예제 #1
0
def parse_metadata(metafile, pan=False):
    import os, sys, fnmatch, dateutil.parser
    from xml.dom import minidom
    from acolite import distance_se
    from numpy import pi, tan, arctan2, mod
    dtor = pi / 180.

    if not os.path.isfile(metafile):
        print('Metadata file {} not found.'.format(metafile))
        sys.exit()

    try:
        xmldoc = minidom.parse(metafile)
    except:
        print('Error opening metadata file.')
        sys.exit()

    metadata = {}
    metadata['SATELLITE'] = 'Pléiades'

    ## get image information
    metadata_tags = [
        'NROWS', 'NCOLS', 'NBANDS', 'RESAMPLING_SPACING', 'MISSION',
        'MISSION_INDEX', 'INSTRUMENT', 'INSTRUMENT_INDEX', 'IMAGING_DATE',
        'IMAGING_TIME', 'BAND_MODE', 'RED_CHANNEL', 'GREEN_CHANNEL',
        'BLUE_CHANNEL', 'ALPHA_CHANNEL', 'EXTENT_TYPE'
    ]
    for tag in metadata_tags:
        node = xmldoc.getElementsByTagName(tag)
        if len(node) > 0: metadata[tag] = node[0].firstChild.nodeValue
    metadata['SENSOR'] = '{}{}'.format(metadata['MISSION'],
                                       metadata['MISSION_INDEX'])
    if 'SPOT' in metadata['SENSOR']: metadata['SATELLITE'] = 'SPOT'

    ## get acquisition time
    #time_s = xmldoc.getElementsByTagName('Time_Range')[0].getElementsByTagName("START")[0].firstChild.nodeValue
    #time_e =  xmldoc.getElementsByTagName('Time_Range')[0].getElementsByTagName("END")[0].firstChild.nodeValue
    #metadata["TIME_START"] = dateutil.parser.parse(time_s)
    #metadata["TIME_END"] = dateutil.parser.parse(time_e)
    #metadata["DOY"] = metadata["TIME_END"].strftime('%j')
    metadata["TIME"] = dateutil.parser.parse(''.join(
        [metadata["IMAGING_DATE"], 'T', metadata["IMAGING_TIME"]]))
    metadata["DOY"] = metadata["TIME"].strftime('%j')
    metadata["SE_DISTANCE"] = distance_se(metadata['DOY'])

    ###
    node = xmldoc.getElementsByTagName("RADIOMETRIC_PROCESSING")
    metadata['RADIOMETRIC_PROCESSING'] = node[0].firstChild.nodeValue if len(
        node) > 0 else 'RADIANCE'

    ## get 'special' values
    for t in xmldoc.getElementsByTagName('Special_Value'):
        name = (t.getElementsByTagName("SPECIAL_VALUE_TEXT")
                [0].firstChild.nodeValue)
        value = (t.getElementsByTagName("SPECIAL_VALUE_COUNT")
                 [0].firstChild.nodeValue)
        metadata[name] = value

    ## get view and sun geometry
    geometric_tags = [
        'LOCATION_TYPE', 'TIME', 'SUN_AZIMUTH', 'SUN_ELEVATION',
        'AZIMUTH_ANGLE', 'VIEWING_ANGLE_ACROSS_TRACK',
        'VIEWING_ANGLE_ALONG_TRACK', 'VIEWING_ANGLE',
        'INCIDENCE_ANGLE_ALONG_TRACK', 'INCIDENCE_ANGLE_ACROSS_TRACK',
        'INCIDENCE_ANGLE'
    ]
    geometric_values = []
    for t in xmldoc.getElementsByTagName('Located_Geometric_Values'):
        geom = {}
        for tag in geometric_tags:
            node = t.getElementsByTagName(tag)
            if len(node) > 0:
                if tag in ['LOCATION_TYPE', 'TIME']:
                    geom[tag] = node[0].firstChild.nodeValue
                else:
                    geom[tag] = float(node[0].firstChild.nodeValue)

        ## compute viewing azimuth
        orientation_angle = geom['AZIMUTH_ANGLE']
        #incidence_across = geom['INCIDENCE_ANGLE_ACROSS_TRACK']
        #incidence_along = geom['INCIDENCE_ANGLE_ALONG_TRACK']
        #geom['VIEWING_AZIMUTH'] = mod(orientation_angle - arctan2(tan(incidence_across*dtor), tan(incidence_along*dtor))/dtor,360)

        #ang_across = geom['VIEWING_ANGLE_ACROSS_TRACK']
        #ang_along = geom['VIEWING_ANGLE_ALONG_TRACK']

        ang_across = geom['INCIDENCE_ANGLE_ACROSS_TRACK']
        ang_along = geom['INCIDENCE_ANGLE_ALONG_TRACK']
        geom['VIEWING_AZIMUTH'] = mod(
            orientation_angle -
            arctan2(tan(ang_across * dtor), tan(ang_along * dtor)) / dtor, 360)

        #geom['VIEWING_AZIMUTH'] = geom['AZIMUTH_ANGLE']

        geometric_values.append(geom)

    metadata['GEOMETRY'] = geometric_values

    ## get band info such as F0 and calibration
    band_info = {}
    bands = ['B0', 'B1', 'B2', 'B3']
    default_F0 = [1915., 1830., 1594., 1060.]

    if pan is True:
        bands = ['P']
        default_F0 = [1548.]

    for band in bands:
        band_data = {}
        for t in xmldoc.getElementsByTagName('BAND_ID'):
            if (t.firstChild.nodeValue) == band:
                parent = t.parentNode.nodeName
                if parent == 'Band_Solar_Irradiance':
                    unit = t.parentNode.getElementsByTagName(
                        'MEASURE_UNIT')[0].firstChild.nodeValue
                    F0 = float(
                        t.parentNode.getElementsByTagName('VALUE')
                        [0].firstChild.nodeValue)
                    if F0 == 999.:
                        idx = [i for i, j in enumerate(bands) if j == band]
                        F0 = default_F0[idx[0]]
                    band_data['F0'] = F0
                if parent == 'Band_Radiance':
                    unit = t.parentNode.getElementsByTagName(
                        'MEASURE_UNIT')[0].firstChild.nodeValue
                    band_data['radiance_gain'] = float(
                        t.parentNode.getElementsByTagName('GAIN')
                        [0].firstChild.nodeValue)
                    band_data['radiance_bias'] = float(
                        t.parentNode.getElementsByTagName('BIAS')
                        [0].firstChild.nodeValue)

                if parent == 'Band_Reflectance':
                    band_data['reflectance_gain'] = float(
                        t.parentNode.getElementsByTagName('GAIN')
                        [0].firstChild.nodeValue)
                    band_data['reflectance_bias'] = float(
                        t.parentNode.getElementsByTagName('BIAS')
                        [0].firstChild.nodeValue)

                if parent == 'Band_Digital_Number':
                    band_data['radiance_to_dn_gain'] = float(
                        t.parentNode.getElementsByTagName('GAIN')
                        [0].firstChild.nodeValue)
                    band_data['radiance_to_dn_bias'] = float(
                        t.parentNode.getElementsByTagName('BIAS')
                        [0].firstChild.nodeValue)

                if parent == 'Band_Spectral_Range':
                    unit = t.parentNode.getElementsByTagName(
                        'MEASURE_UNIT')[0].firstChild.nodeValue
                    wave_start = float(
                        t.parentNode.getElementsByTagName('MIN')
                        [0].firstChild.nodeValue)
                    wave_end = float(
                        t.parentNode.getElementsByTagName('MAX')
                        [0].firstChild.nodeValue)
                    if wave_start > 100.: wave_start /= 1000.
                    if wave_end > 100.: wave_end /= 1000.

                    band_data['wave_start'] = wave_start
                    band_data['wave_end'] = wave_end

                    band_data['wave'] = (band_data['wave_end'] +
                                         band_data['wave_start']) / 2.
                    #if band_data['wave_start'] > 100.: band_data['wave_start']=band_data['wave_start']/1000.
                    #if band_data['wave_end'] > 100.: band_data['wave_start']=band_data['wave_start']/1000.
                    #if band_data['wave'] > 100.: band_data['wave_start']=band_data['wave_start']/1000.
                    band_data['wave_name'] = str(
                        round(int(band_data['wave'] * 1000.), 2))
                if pan is False:
                    if band == metadata['RED_CHANNEL']:
                        band_data['band_index'] = 0
                    if band == metadata['GREEN_CHANNEL']:
                        band_data['band_index'] = 1
                    if band == metadata['BLUE_CHANNEL']:
                        band_data['band_index'] = 2
                    if band == metadata['ALPHA_CHANNEL']:
                        band_data['band_index'] = 3
        band_info[band] = band_data
    metadata['BAND_INFO'] = band_info

    ## read vertices of spatial extent
    vertex_tags = ['LON', 'LAT', 'X', 'Y', 'COL', 'ROW']
    vertex_values = []
    for t in xmldoc.getElementsByTagName('Vertex'):
        vertex = {}
        for tag in vertex_tags:
            node = t.getElementsByTagName(tag)
            if len(node) > 0:
                vertex[tag] = float(node[0].firstChild.nodeValue)
        vertex_values.append(vertex)

    vertices = {}
    for t in xmldoc.getElementsByTagName('Center'):
        vertex = {}
        for tag in vertex_tags:
            node = t.getElementsByTagName(tag)
            if len(node) > 0:
                vertex[tag] = float(node[0].firstChild.nodeValue)
        vertices['C'] = vertex

    ncols = float(metadata['NCOLS'])
    nrows = float(metadata['NROWS'])
    for i, v in enumerate(vertex_values):
        col = float(v['COL'])
        row = float(v['ROW'])

        if (col == 1) & (row == 1):
            vertices['UL'] = v
            continue
        if (col == ncols) & (row == 1):
            vertices['UR'] = v
            continue
        if (col == ncols) & (row == nrows):
            vertices['LR'] = v
            continue
        if (col == 1) & (row == nrows):
            vertices['LL'] = v
            continue
        vertices['V{}'.format(i)] = v

    metadata['VERTICES'] = vertices

    ## get tile information
    try:
        metadata['ntiles'] = int(
            xmldoc.getElementsByTagName("NTILES")[0].firstChild.nodeValue)
        metadata['ntiles_R'] = int(
            xmldoc.getElementsByTagName("NTILES_COUNT")
            [0]._attrs['ntiles_R'].nodeValue)
        metadata['ntiles_C'] = int(
            xmldoc.getElementsByTagName("NTILES_COUNT")
            [0]._attrs['ntiles_C'].nodeValue)
        metadata['tiles_nrows'] = int(
            xmldoc.getElementsByTagName("NTILES_SIZE")
            [0]._attrs['nrows'].nodeValue)
        metadata['tiles_ncols'] = int(
            xmldoc.getElementsByTagName("NTILES_SIZE")
            [0]._attrs['ncols'].nodeValue)
    except:
        metadata['ntiles'] = 1
        metadata['ntiles_R'] = 1
        metadata['ntiles_C'] = 1
        metadata['tiles_nrows'] = int(metadata['NROWS'])
        metadata['tiles_ncols'] = int(metadata['NROWS'])

    ## set some defaults
    metadata['THS'] = 90. - metadata['GEOMETRY'][1]['SUN_ELEVATION']
    metadata['THV'] = metadata['GEOMETRY'][1]['VIEWING_ANGLE']
    azi = abs(metadata['GEOMETRY'][1]['SUN_AZIMUTH'] -
              metadata['GEOMETRY'][1]['VIEWING_AZIMUTH'])
    if azi > 180: azi -= 180
    metadata['AZI'] = azi
    metadata['SENSOR'] = metadata['INSTRUMENT'] + metadata['MISSION_INDEX']

    bands = sorted({band for band in metadata['BAND_INFO']})
    wavelengths = sorted({
        metadata['BAND_INFO'][band]['wave']
        for band in metadata['BAND_INFO']
    })
    band_wavelengths = sorted({
        metadata['BAND_INFO'][band]['wave_name']
        for band in metadata['BAND_INFO']
    })

    #band_indices = [metadata['BAND_INFO'][band]['band_index'] for band in bands]
    band_indices = []
    for bi, band in enumerate(bands):
        if 'band_index' in metadata['BAND_INFO'][band].keys():
            band_indices.append(metadata['BAND_INFO'][band]['band_index'])
        else:
            band_indices.append(bi)

    metadata['BANDS'] = bands
    metadata['WAVELENGTHS'] = wavelengths
    metadata['BAND_WAVELENGTHS'] = band_wavelengths
    metadata['BAND_INDICES'] = band_indices

    band_names = []
    for band in bands:
        if band == 'B0': band_names.append('Blue')
        if band == 'B1': band_names.append('Green')
        if band == 'B2': band_names.append('Red')
        if band == 'B3': band_names.append('NIR')

    metadata['BAND_NAMES'] = band_names
    metadata['BANDS_ALL'] = ['Blue', 'Green', 'Red', 'NIR']
    metadata['BANDS_REDNIR'] = ['Red', 'NIR']
    metadata['BANDS_VIS'] = ['Blue', 'Green', 'Red']
    metadata['BANDS_NIR'] = ['NIR']
    metadata['BANDS_BESTFIT'] = ['Red', 'NIR']

    return metadata
예제 #2
0
def fixed_model(metadata,
                tau550,
                rsr_file=None,
                lutdir=None,
                lut='PONDER-LUT-201607-MOD2-1013mb',
                pressure=None):
    import acolite as pp
    import os

    ## get scene geometry and default bands from metadata
    try:
        if 'SE_DISTANCE' in metadata.keys():
            se_distance = metadata['SE_DISTANCE']
        else:
            se_distance = pp.distance_se(metadata['DOY'])

        ths = metadata['THS']
        thv = metadata['THV']
        azi = metadata['AZI']

        if 'SATELLITE_SENSOR' in metadata.keys():
            sensor = metadata['SATELLITE_SENSOR']
        else:
            sensor = metadata['SENSOR']

        #rednir_bands = metadata['BANDS_REDNIR']
        #vis_bands = metadata['BANDS_VIS']
        #nir_bands = metadata['BANDS_NIR']

        #bestfit_bands_defaults = metadata['BANDS_BESTFIT']

        bands_sorted = metadata['BANDS_ALL']
    except:
        print(
            'Could not get appropriate metadata for model selection for satellite {}'
            .format(metadata['SATELLITE']))
        print(metadata.keys())
        return (1)

#    ## get scene geometry
#    if metadata['SATELLITE']=='Pléiades':
#        se_distance = pp.distance_se(metadata['DOY'])
#        ths = 90. - metadata['GEOMETRY'][1]['SUN_ELEVATION']
#        thv = metadata['GEOMETRY'][1]['VIEWING_ANGLE']
#        azi = abs(metadata['GEOMETRY'][1]['SUN_AZIMUTH'] - metadata['GEOMETRY'][1]['AZIMUTH_ANGLE'])
#        if azi > 180: azi -= 180
#        sensor = metadata['INSTRUMENT']+metadata['MISSION_INDEX']
#        rednir_bands = ['Red','NIR']
#        vis_bands = ['Blue','Green','Red']
#    if metadata['SATELLITE']=='WorldView2':
#        se_distance = pp.distance_se(metadata['DOY'])
#        ths = metadata['THS']
#        thv = metadata['THV']
#        azi = metadata['AZI']
#        sensor = 'WorldView2'
#        rednir_bands = ['RED','NIR1','NIR2']
#        vis_bands = ['COASTAL','BLUE','GREEN','YELLOW','RED']

## set LUT dir and rsr_file
#pypath='/storage/Python/' ## to improve!
#pp_path = os.path.dirname(pp.__file__)
#if lutdir is None:
#    lutdir=pp_path+'/data/LUT/'
#if rsr_file is None:
#    rsr_file = pp_path+'/data/RSR/'+sensor+'.txt'

## set LUT dir and rsr_file
    from acolite import config
    pp_path = config['pp_data_dir']
    if lutdir is None:
        lutdir = pp_path + '/LUT/'
    if rsr_file is None:
        rsr_file = pp_path + '/RSR/' + sensor + '.txt'

    rsr, rsr_bands = pp.rsr_read(file=rsr_file)

    ## get sensor LUT
    #lut_sensor, meta_sensor = pp.aerlut.get_sensor_lut(sensor, rsr_file, lutdir=lutdir, lutid=lut, override=0)
    #(ratm, rorayl, dtotr, utotr, dtott, utott, astot) = pp.aerlut.lut_get_ac_parameters_fixed_tau_sensor(lut_sensor,meta_sensor,azi,thv,ths,tau550)

    ## get sensor LUT
    lut_sensor, meta_sensor = pp.aerlut.get_sensor_lut(sensor,
                                                       rsr_file,
                                                       lutdir=lutdir,
                                                       lutid=lut,
                                                       override=0)

    ## read luts at other pressures if needed
    if pressure is not None:
        lut_data_dict = {}
        lut_data_dict[lut] = {'lut': lut_sensor, 'meta': meta_sensor}
        lut_split = lut.split('-')
        lut0 = '-'.join(lut_split[0:-1] + ['0500mb'])
        lut_sensor, meta_sensor = pp.aerlut.get_sensor_lut(sensor,
                                                           rsr_file,
                                                           lutdir=lutdir,
                                                           lutid=lut0,
                                                           override=0)
        lut_data_dict[lut0] = {'lut': lut_sensor, 'meta': meta_sensor}

        lut1 = '-'.join(lut_split[0:-1] + ['1100mb'])
        lut_sensor, meta_sensor = pp.aerlut.get_sensor_lut(sensor,
                                                           rsr_file,
                                                           lutdir=lutdir,
                                                           lutid=lut1,
                                                           override=0)
        lut_data_dict[lut1] = {'lut': lut_sensor, 'meta': meta_sensor}

        lut_sensor, meta_sensor = pp.aerlut.aerlut_pressure(
            lut,
            lutdir,
            pressure,
            sensor,
            rsr_file,
            lut_data_dict=lut_data_dict)

    (ratm, rorayl, dtotr, utotr, dtott, utott,
     astot) = pp.aerlut.lut_get_ac_parameters_fixed_tau_sensor(
         lut_sensor, meta_sensor, azi, thv, ths, tau550)

    return (ratm, rorayl, dtotr, utotr, dtott, utott, astot,
            tau550), lut_sensor, meta_sensor
예제 #3
0
def select_model(metadata,
                 rdark,
                 rsr_file=None,
                 lutdir=None,
                 bestfit='bands',
                 bestfit_bands=None,
                 force_band=None,
                 pressure=None,
                 model_selection='min_tau',
                 rdark_list_selection='intercept',
                 lowess_frac=0.5,
                 lut_data_dict=None,
                 luts=[
                     'PONDER-LUT-201704-MOD1-1013mb',
                     'PONDER-LUT-201704-MOD2-1013mb',
                     'PONDER-LUT-201704-MOD3-1013mb'
                 ]):

    import acolite as pp
    import os
    from numpy import float64, ndarray, arange, nanmin, where, nan, isnan, min
    from numpy.ma import MaskedArray, is_masked
    from statsmodels.nonparametric.smoothers_lowess import lowess

    ## get scene geometry and default bands from metadata
    try:
        if 'SE_DISTANCE' in metadata.keys():
            se_distance = metadata['SE_DISTANCE']
        else:
            se_distance = pp.distance_se(metadata['DOY'])
        ths = metadata['THS']
        thv = metadata['THV']
        azi = metadata['AZI']
        if 'LUT_SENSOR' in metadata.keys():
            sensor = metadata['LUT_SENSOR']
        elif 'SATELLITE_SENSOR' in metadata.keys():
            sensor = metadata['SATELLITE_SENSOR']
        else:
            sensor = metadata['SENSOR']
        bestfit_bands_defaults = metadata['BANDS_BESTFIT']
        bands_sorted = metadata['BANDS_ALL']
    except:
        print(
            'Could not get appropriate metadata for model selection for satellite {}'
            .format(metadata['SATELLITE']))
        print(metadata.keys())
        return (1)

    bestfit_bands_all = rdark.keys()
    if bestfit_bands is None: bestfit_bands = bestfit_bands_defaults
    if bestfit_bands == 'default': bestfit_bands = bestfit_bands_defaults
    if bestfit_bands == 'all': bestfit_bands = bestfit_bands_all

    ## set LUT dir and rsr_file
    pp_path = pp.config['pp_data_dir']
    if lutdir is None:
        lutdir = pp_path + '/LUT/'
    if rsr_file is None:
        rsr_file = pp_path + '/RSR/' + sensor + '.txt'
    rsr, rsr_bands = pp.shared.rsr_read(file=rsr_file)

    ## make lut data dictionary that can be reused in next runs
    if lut_data_dict is None:
        lut_data_dict = {}
        for li, lut in enumerate(luts):
            ## get sensor LUT
            lut_sensor, meta_sensor = pp.aerlut.get_sensor_lut(sensor,
                                                               rsr_file,
                                                               lutdir=lutdir,
                                                               lutid=lut,
                                                               override=0)
            lut_data_dict[lut] = {'lut': lut_sensor, 'meta': meta_sensor}

            ## read luts at other pressures if needed
            if pressure is not None:
                lut_split = lut.split('-')
                lut0 = '-'.join(lut_split[0:-1] + ['0500mb'])
                lut_sensor, meta_sensor = pp.aerlut.get_sensor_lut(
                    sensor, rsr_file, lutdir=lutdir, lutid=lut0, override=0)
                lut_data_dict[lut0] = {'lut': lut_sensor, 'meta': meta_sensor}

                lut1 = '-'.join(lut_split[0:-1] + ['1100mb'])
                lut_sensor, meta_sensor = pp.aerlut.get_sensor_lut(
                    sensor, rsr_file, lutdir=lutdir, lutid=lut1, override=0)
                lut_data_dict[lut1] = {'lut': lut_sensor, 'meta': meta_sensor}

    ## empty dicts
    rdark_smooth = {}
    rdark_selected = {}

    ## default is not to use the 'list' type model/rdark selection
    ## will only be used if the rdark is a list and the rdark_list_selection=="list"
    rdark_list = False

    ## find out what kind of rdark is given and which selection to use
    for band in rdark.keys():
        ## given rdark is a single spectrum
        if (type(rdark[band]) == float64):
            rdark_selected[band] = rdark[band]

        ## given rdark is a list of spectra
        elif (type(rdark[band]) == ndarray) or (type(rdark[band])
                                                == MaskedArray):
            #pixel_range = range(0, len(rdark[band]))
            pixel_range = [float(i) for i in range(0, len(rdark[band]))]
            #print(pixel_range)
            rdark_list = True

            ## select rdark by lowess smoothing the given spectra
            if rdark_list_selection == 'smooth':
                rdark_smooth[band] = lowess(rdark[band],
                                            pixel_range,
                                            frac=lowess_frac)[:, 1]
                rdark_selected[band] = rdark_smooth[band][0]
                rdark_list = False

            ## select rdark by OLS intercept
            elif rdark_list_selection == 'intercept':
                for band in rdark.keys():
                    reg = pp.shared.regression.lsqfity(
                        pixel_range, rdark[band])  # m, b, r, sm, sb
                    rdark_selected[band] = reg[1]
                    rdark_list = False

            ## select rdark from all given pixels according to min rmsd
            elif rdark_list_selection == 'list':
                rdark_selected[band] = rdark[band]
                rdark_list = True

            ## select rdark from all given pixels according to min rmsd, but first smooth the given rdark
            elif rdark_list_selection == 'list_smooth':
                rdark_selected[band] = lowess(rdark[band],
                                              pixel_range,
                                              frac=lowess_frac)[:, 1]
                rdark_list = True

            ## fallback selection is darkest pixel in each band
            else:
                rdark_list_selection = 'darkest'
                rdark_selected[band] = nanmin(rdark[band])

        ## given dark is something else
        else:
            print('rdark type not recognised')
            rdark_selected = (rdark)

    if rdark_list:
        from numpy import min, max
        rdark_len = [len(rdark[b]) for b in rdark]
        max_len = max(rdark_len)
        min_len = min(rdark_len)
        rdark = {b: rdark[b][0:min_len] for b in rdark}

    ## find best fitting model
    sel_rmsd = 1.
    sel_tau = 5.
    taufits = []

    daot_minimum = 5

    ## run through luts
    for li, lut in enumerate(luts):

        ## get current sensor LUT
        if pressure is not None:  ## interpolate LUTs to given pressure
            lut_sensor, meta_sensor = pp.aerlut.aerlut_pressure(
                lut,
                lutdir,
                pressure,
                sensor,
                rsr_file,
                lut_data_dict=lut_data_dict)
        else:  ## just the default LUTs
            lut_sensor, meta_sensor = (lut_data_dict[lut]["lut"],
                                       lut_data_dict[lut]["meta"])

        ## get tau for selected dark spectrum
        tau_550, tau_rmsd, tau_band = pp.aerlut.lut_get_taufit_sensor(
            lut_sensor,
            meta_sensor,
            azi,
            thv,
            ths,
            rdark_selected,
            bestfit_bands=bestfit_bands,
            force_band=force_band)

        ## if rdark list method do not select tau and model here, just append to 'taufits' list for later processing
        if (rdark_list):
            taufits.append((tau_550, tau_rmsd, tau_band))

        ## if single spectra selected before, select tau and model here
        else:
            ## get tau and ac parameters for this model
            tmp = pp.aerlut.lut_get_ac_parameters_sensor(lut_sensor,
                                                         meta_sensor,
                                                         azi,
                                                         thv,
                                                         ths,
                                                         rdark_selected,
                                                         force_band=force_band)

            ## band index for this model (i.e. band giving lowest tau)
            idx = tmp[8]
            ## selected tau for this model
            tau550_cur = tmp[7][idx]

            ## probably obsolete
            if bestfit == 'bands':
                rmsd_y = [rdark_selected[band] for band in bestfit_bands]
                rmsd_x = [tmp[0][band] for band in bestfit_bands]
                rmsd = pp.rmsd(rmsd_x, rmsd_y)
            else:
                rmsd = tmp[9][idx]

            ## find best spectral fit
            if model_selection == 'min_rmsd':
                if is_masked(rmsd):
                    rmsd = 1.0

                if (rmsd <= sel_rmsd) | (li == 0):
                    sel_rmsd = rmsd
                    sel_idx = idx
                    sel_ac_par = tmp
                    sel_model_lut, sel_model_lut_meta = (lut_sensor,
                                                         meta_sensor)
                    pixel_idx = -1

            ## find lowest tau fit
            if model_selection == 'min_tau':
                if (tau550_cur <= sel_tau) | (li == 0):
                    sel_tau = tau550_cur
                    sel_rmsd = rmsd
                    sel_idx = idx
                    sel_ac_par = tmp
                    sel_model_lut, sel_model_lut_meta = (lut_sensor,
                                                         meta_sensor)
                    pixel_idx = -1

            ## find lowest tau and second band with most similar tau
            if model_selection == 'min_dtau':
                allt = [tmp[7][b] for i, b in enumerate(tmp[7].keys())]
                min_tau = min([t for t in allt if t > 0.001])
                allt_diff_sorted = [t - min_tau for t in allt if t > min_tau]
                allt_diff_sorted.sort()
                if allt_diff_sorted[0] < daot_minimum:
                    daot_minimum = allt_diff_sorted[0]
                    daot_second_band = [b for i,b in enumerate(tmp[7].keys()) \
                                        if allt[i] == allt_diff_sorted[0] + min_tau][0]

                    sel_tau = tau550_cur
                    sel_rmsd = rmsd
                    sel_idx = (idx, daot_second_band)
                    sel_ac_par = tmp
                    sel_model_lut, sel_model_lut_meta = (lut_sensor,
                                                         meta_sensor)
                    pixel_idx = -1

            ## find lowest tau and minimum rmsd with any other band
            if model_selection == 'min_drmsd':
                rmsdi = {}
                rmsdi_band = ''
                rmsdi_min = 5
                for i, b in enumerate(tmp[7].keys()):
                    if b == idx: continue

                    rmsd_yi = [rdark_selected[b], rdark_selected[idx]]
                    rmsd_xi = [tmp[0][b], tmp[0][idx]]
                    rmsdi[b] = pp.rmsd(rmsd_xi, rmsd_yi)
                    if is_masked(rmsdi[b]): rmsdi[b] = 5
                    if (rmsdi[b] < rmsdi_min) & (b != idx):
                        rmsdi_band = b
                        rmsdi_min = rmsdi[b]

                # this happens if no band fits better (e.g. for rhopath==rhorayleigh)
                if rmsdi_band == '':
                    rmsdi_band = b
                    sel_rmsd = -1
                    sel_idx = (idx, idx)
                    sel_ac_par = tmp
                    sel_model_lut, sel_model_lut_meta = (lut_sensor,
                                                         meta_sensor)
                    pixel_idx = -1
                elif (rmsdi[rmsdi_band] <= sel_rmsd) | (li == 0):
                    sel_rmsd = rmsdi[rmsdi_band]
                    sel_idx = (idx, rmsdi_band)
                    sel_ac_par = tmp
                    sel_model_lut, sel_model_lut_meta = (lut_sensor,
                                                         meta_sensor)
                    pixel_idx = -1

    ## get rdark/tau+model according to min rmsd/tau in the given pixel lists
    ## when rdark_list_selection did not select a single spectrum
    if (rdark_list):
        ## choose best lut for each pixel
        tau_550_sel = []
        tau_rmsd_sel = []
        tau_band_sel = []
        tau_model_sel = []

        ## get for each pixel the minimum rmsd [1] according to the models
        ## default select on min tau
        list_min_idx = 0

        if model_selection == "min_tau":
            list_min_idx = 0
        elif model_selection == "min_rmsd":
            list_min_idx = 1

        for i in pixel_range:
            val_c = [
                taufits[j][list_min_idx][i] for j in range(0, len(taufits))
            ]  ## selected tau/rmsd per model for this pixel
            idx = [i for i, t in enumerate(val_c) if (t == nanmin(val_c))]
            if len(idx) == 0:
                tau_550_sel.append(nan)
                tau_rmsd_sel.append(nan)
                tau_band_sel.append(nan)
                tau_model_sel.append(nan)
            else:
                idx = idx[0]
                tau_550_sel.append(taufits[idx][0][i])
                tau_rmsd_sel.append(taufits[idx][1][i])
                tau_band_sel.append(taufits[idx][2][i])
                tau_model_sel.append(idx + 1)

        ## select pixel with min rmsd
        pixel_idx = where(tau_rmsd_sel == nanmin(tau_rmsd_sel))[0][0]

        ## select lut and band
        lut_sel = luts[tau_model_sel[pixel_idx] - 1]
        sel_idx = tau_band_sel[pixel_idx]
        sel_rmsd = tau_rmsd_sel[pixel_idx]

        ## construct the selected dark pixel
        for band in rdark_selected.keys():
            rdark_selected[band] = rdark_selected[band][pixel_idx]

        ## get selected LUT
        if pressure is not None:
            sel_model_lut, sel_model_lut_meta = pp.aerlut.aerlut_pressure(
                lut_sel,
                lutdir,
                pressure,
                sensor,
                rsr_file,
                lut_data_dict=lut_data_dict)
        else:
            sel_model_lut, sel_model_lut_meta = (
                lut_data_dict[lut_sel]["lut"], lut_data_dict[lut_sel]["meta"])

        ## get ac parameters for the selected rdark  - probably better to use the TAU to retrieve parameters ?
        sel_ac_par = pp.aerlut.lut_get_ac_parameters_sensor(
            sel_model_lut,
            sel_model_lut_meta,
            azi,
            thv,
            ths,
            rdark_selected,
            force_band=force_band)

    ## get ac parameters from previously selected model
    (ratm_s, rorayl_s, dtotr_s, utotr_s, dtott_s, utott_s,
     astot_s) = sel_ac_par[0:7]
    tau550_all_bands = sel_ac_par[7]
    if type(sel_idx) == str:
        tau550 = tau550_all_bands[sel_idx]
    else:
        tau550 = tau550_all_bands[sel_idx[0]]
    dark_idx = sel_idx

    ## if tau is the minimum in the model ratm may be nans
    ## in that case replace by Rayleigh reflectance
    from numpy import isnan
    for band in ratm_s.keys():
        if isnan(ratm_s[band]): ratm_s[band] = rorayl_s[band]

    return (ratm_s,rorayl_s,dtotr_s,utotr_s,dtott_s,utott_s,astot_s, tau550),\
           (bands_sorted, tau550_all_bands, dark_idx, sel_rmsd, rdark_selected, pixel_idx), (sel_model_lut, sel_model_lut_meta)