def resample_templates(args, logger):
    '\n    Resample a spectrum library of templates onto a fixed logarithmic stride, representing each of the 4MOST arms in\n    turn. We use 4FS to down-sample the templates to the resolution of 4MOST observations, and automatically detect\n    the list of arms contained within each 4FS mock observation. We then resample the 4FS output onto a new raster\n    with fixed logarithmic stride.\n\n    :param args:\n        Object containing arguments supplied by the used, for example the name of the spectrum libraries we use for\n        input and output. The required fields are defined by the user interface above.\n    :param logger:\n        A python logging object.\n    :return:\n        None.\n    '
    workspace = (args.workspace if args.workspace else os_path.join(args.our_path, '../../../workspace'))
    spectra = SpectrumLibrarySqlite.open_and_search(library_spec=args.templates_in, workspace=workspace, extra_constraints={'continuum_normalised': 0})
    (templates_library, templates_library_items, templates_spectra_constraints) = [spectra[i] for i in ('library', 'items', 'constraints')]
    library_path = os_path.join(workspace, args.templates_out)
    output_library = SpectrumLibrarySqlite(path=library_path, create=True)
    etc_wrapper = FourFS(path_to_4fs=os_path.join(args.binary_path, 'OpSys/ETC'), snr_list=[250.0], magnitude=13, snr_per_pixel=True)
    for input_spectrum_id in templates_library_items:
        logger.info('Working on <{}>'.format(input_spectrum_id['filename']))
        input_spectrum_array = templates_library.open(ids=input_spectrum_id['specId'])
        template_flux_normalised = input_spectrum_array.extract_item(0)
        spectrum_matching_field = ('uid' if ('uid' in template_flux_normalised.metadata) else 'Starname')
        object_name = template_flux_normalised.metadata[spectrum_matching_field]
        search_criteria = {spectrum_matching_field: object_name, 'continuum_normalised': 1}
        continuum_normalised_spectrum_id = templates_library.search(**search_criteria)
        assert (len(continuum_normalised_spectrum_id) == 1), 'Could not find continuum-normalised spectrum.'
        template_continuum_normalised_arr = templates_library.open(ids=continuum_normalised_spectrum_id[0]['specId'])
        template_continuum_normalised = template_continuum_normalised_arr.extract_item(0)
        logger.info('Passing template through 4FS')
        mock_observed_template = etc_wrapper.process_spectra(spectra_list=((template_flux_normalised, template_continuum_normalised),))
        for mode in mock_observed_template:
            for index in mock_observed_template[mode]:
                for snr in mock_observed_template[mode][index]:
                    unique_id = hashlib.md5(os.urandom(32)).hexdigest()[:16]
                    for spectrum_type in mock_observed_template[mode][index][snr]:
                        logger.info('Resampling {} spectrum'.format(mode))
                        mock_observed = mock_observed_template[mode][index][snr][spectrum_type]
                        mock_observed.value_errors[np.isnan(mock_observed.value_errors)] = 1000.0
                        if (not np.all(np.isfinite(mock_observed.values))):
                            print('Warning: NaN values in template <{}>'.format(template_flux_normalised.metadata['Starname']))
                            mock_observed.value_errors[np.isnan(mock_observed.values)] = 1000.0
                            mock_observed.values[np.isnan(mock_observed.values)] = 1.0
                        resampler = SpectrumResampler(mock_observed)
                        wavelength_arms = SpectrumProperties(mock_observed.wavelengths).wavelength_arms()
                        for (arm_count, arm) in enumerate(wavelength_arms['wavelength_arms']):
                            (arm_raster, mean_pixel_width) = arm
                            name = '{}_{}'.format(mode, arm_count)
                            arm_info = {'lambda_min': arm_raster[0], 'lambda_max': arm_raster[(- 1)], 'lambda_step': mean_pixel_width}
                            arm_raster = logarithmic_raster(lambda_min=arm_info['lambda_min'], lambda_max=arm_info['lambda_max'], lambda_step=arm_info['lambda_step'])
                            mock_observed_arm = resampler.onto_raster(arm_raster)
                            output_library.insert(spectra=mock_observed_arm, filenames=input_spectrum_id['filename'], metadata_list={'uid': unique_id, 'template_id': object_name, 'mode': mode, 'arm_name': '{}_{}'.format(mode, arm_count), 'lambda_min': arm_raster[0], 'lambda_max': arm_raster[(- 1)], 'lambda_step': mean_pixel_width})
Resample a spectrum library of templates onto a fixed logarithmic stride, representing each of the 4MOST arms in
turn. We use 4FS to down-sample the templates to the resolution of 4MOST observations, and automatically detect
the list of arms contained within each 4FS mock observation. We then resample the 4FS output onto a new raster
with fixed logarithmic stride.

:param args:
    Object containing arguments supplied by the used, for example the name of the spectrum libraries we use for
    input and output. The required fields are defined by the user interface above.
:param logger:
    A python logging object.
:return:
    None.
def resample_templates(args, logger):
    '\n    Resample a spectrum library of templates onto a fixed logarithmic stride, representing each of the 4MOST arms in\n    turn. We use 4FS to down-sample the templates to the resolution of 4MOST observations, and automatically detect\n    the list of arms contained within each 4FS mock observation. We then resample the 4FS output onto a new raster\n    with fixed logarithmic stride.\n\n    :param args:\n        Object containing arguments supplied by the used, for example the name of the spectrum libraries we use for\n        input and output. The required fields are defined by the user interface above.\n    :param logger:\n        A python logging object.\n    :return:\n        None.\n    '
    workspace = (args.workspace if args.workspace else os_path.join(args.our_path, '../../../workspace'))
    spectra = SpectrumLibrarySqlite.open_and_search(library_spec=args.templates_in, workspace=workspace, extra_constraints={'continuum_normalised': 0})
    (templates_library, templates_library_items, templates_spectra_constraints) = [spectra[i] for i in ('library', 'items', 'constraints')]
    library_path = os_path.join(workspace, args.templates_out)
    output_library = SpectrumLibrarySqlite(path=library_path, create=True)
    etc_wrapper = FourFS(path_to_4fs=os_path.join(args.binary_path, 'OpSys/ETC'), snr_list=[250.0], magnitude=13, snr_per_pixel=True)
    for input_spectrum_id in templates_library_items:
        logger.info('Working on <{}>'.format(input_spectrum_id['filename']))
        input_spectrum_array = templates_library.open(ids=input_spectrum_id['specId'])
        template_flux_normalised = input_spectrum_array.extract_item(0)
        spectrum_matching_field = ('uid' if ('uid' in template_flux_normalised.metadata) else 'Starname')
        object_name = template_flux_normalised.metadata[spectrum_matching_field]
        search_criteria = {spectrum_matching_field: object_name, 'continuum_normalised': 1}
        continuum_normalised_spectrum_id = templates_library.search(**search_criteria)
        assert (len(continuum_normalised_spectrum_id) == 1), 'Could not find continuum-normalised spectrum.'
        template_continuum_normalised_arr = templates_library.open(ids=continuum_normalised_spectrum_id[0]['specId'])
        template_continuum_normalised = template_continuum_normalised_arr.extract_item(0)
        logger.info('Passing template through 4FS')
        mock_observed_template = etc_wrapper.process_spectra(spectra_list=((template_flux_normalised, template_continuum_normalised),))
        for mode in mock_observed_template:
            for index in mock_observed_template[mode]:
                for snr in mock_observed_template[mode][index]:
                    unique_id = hashlib.md5(os.urandom(32)).hexdigest()[:16]
                    for spectrum_type in mock_observed_template[mode][index][snr]:
                        logger.info('Resampling {} spectrum'.format(mode))
                        mock_observed = mock_observed_template[mode][index][snr][spectrum_type]
                        mock_observed.value_errors[np.isnan(mock_observed.value_errors)] = 1000.0
                        if (not np.all(np.isfinite(mock_observed.values))):
                            print('Warning: NaN values in template <{}>'.format(template_flux_normalised.metadata['Starname']))
                            mock_observed.value_errors[np.isnan(mock_observed.values)] = 1000.0
                            mock_observed.values[np.isnan(mock_observed.values)] = 1.0
                        resampler = SpectrumResampler(mock_observed)
                        wavelength_arms = SpectrumProperties(mock_observed.wavelengths).wavelength_arms()
                        for (arm_count, arm) in enumerate(wavelength_arms['wavelength_arms']):
                            (arm_raster, mean_pixel_width) = arm
                            name = '{}_{}'.format(mode, arm_count)
                            arm_info = {'lambda_min': arm_raster[0], 'lambda_max': arm_raster[(- 1)], 'lambda_step': mean_pixel_width}
                            arm_raster = logarithmic_raster(lambda_min=arm_info['lambda_min'], lambda_max=arm_info['lambda_max'], lambda_step=arm_info['lambda_step'])
                            mock_observed_arm = resampler.onto_raster(arm_raster)
                            output_library.insert(spectra=mock_observed_arm, filenames=input_spectrum_id['filename'], metadata_list={'uid': unique_id, 'template_id': object_name, 'mode': mode, 'arm_name': '{}_{}'.format(mode, arm_count), 'lambda_min': arm_raster[0], 'lambda_max': arm_raster[(- 1)], 'lambda_step': mean_pixel_width})