Example #1
0
def main():
    # Parse arguments
    parser = argparse.ArgumentParser(description="Apply OE to a block of data.")
    parser.add_argument('input_radiance', type=str)
    parser.add_argument('input_loc', type=str)
    parser.add_argument('input_obs', type=str)
    parser.add_argument('working_directory', type=str)
    parser.add_argument('sensor', type=str, choices=['ang', 'avcl', 'neon', 'prism'])
    parser.add_argument('--copy_input_files', type=int, choices=[0,1], default=0)
    parser.add_argument('--h2o', action='store_true')
    parser.add_argument('--modtran_path', type=str)
    parser.add_argument('--wavelength_path', type=str)
    parser.add_argument('--surface_category', type=str, default="multicomponent_surface")
    parser.add_argument('--aerosol_climatology_path', type=str, default=None)
    parser.add_argument('--rdn_factors_path', type=str)
    parser.add_argument('--surface_path', type=str)
    parser.add_argument('--channelized_uncertainty_path', type=str)
    parser.add_argument('--lut_config_file', type=str)
    parser.add_argument('--logging_level', type=str, default="INFO")
    parser.add_argument('--log_file', type=str, default=None)
    parser.add_argument('--n_cores', type=int, default=-1)
    parser.add_argument('--presolve', choices=[0,1], type=int, default=0)
    parser.add_argument('--empirical_line', choices=[0,1], type=int, default=0)

    args = parser.parse_args()

    if args.copy_input_files == 1:
        args.copy_input_files = True
    else:
        args.copy_input_files = False

    if args.log_file is None:
        logging.basicConfig(format='%(message)s', level=args.logging_level)
    else:
        logging.basicConfig(format='%(message)s', level=args.logging_level, filename=args.log_file)

    lut_params = LUTConfig(args.lut_config_file)

    paths = Pathnames(args)
    paths.make_directories()
    paths.stage_files()

    # Based on the sensor type, get appropriate year/month/day info fro intial condition.
    # We'll adjust for line length and UTC day overrun later
    if args.sensor == 'ang':
        # parse flightline ID (AVIRIS-NG assumptions)
        dt = datetime.strptime(paths.fid[3:], '%Y%m%dt%H%M%S')
        dayofyear = dt.timetuple().tm_yday
    elif args.sensor == 'avcl':
        # parse flightline ID (AVIRIS-CL assumptions)
        dt = datetime.strptime('20{}t000000'.format(paths.fid[1:7]), '%Y%m%dt%H%M%S')
        dayofyear = dt.timetuple().tm_yday
    elif args.sensor == 'neon':
        dt = datetime.strptime(paths.fid, 'NIS01_%Y%m%d_%H%M%S')
        dayofyear = dt.timetuple().tm_yday
    elif args.sensor == 'prism':
        dt = datetime.strptime(paths.fid[3:], '%Y%m%dt%H%M%S')
        dayofyear = dt.timetuple().tm_yday

    h_m_s, day_increment, mean_path_km, mean_to_sensor_azimuth, mean_to_sensor_zenith, valid, \
    to_sensor_azimuth_lut_grid, to_sensor_zenith_lut_grid = get_metadata_from_obs(paths.obs_working_path, lut_params)

    if day_increment:
        dayofyear += 1

    gmtime = float(h_m_s[0] + h_m_s[1] / 60.)

    # get radiance file, wavelengths
    if args.wavelength_path:
        chn, wl, fwhm = np.loadtxt(args.wavelength_path).T
    else:
        radiance_dataset = envi.open(paths.radiance_working_path + '.hdr')
        wl = np.array([float(w) for w in radiance_dataset.metadata['wavelength']])
        if 'fwhm' in radiance_dataset.metadata:
            fwhm = np.array([float(f) for f in radiance_dataset.metadata['fwhm']])
        elif 'FWHM' in radiance_dataset.metadata:
            fwhm = np.array([float(f) for f in radiance_dataset.metadata['FWHM']])
        else:
            fwhm = np.ones(wl.shape) * (wl[1] - wl[0])

        # Close out radiance dataset to avoid potential confusion
        del radiance_dataset

    # Convert to microns if needed
    if wl[0] > 100:
        wl = wl / 1000.0
        fwhm = fwhm / 1000.0

    # write wavelength file
    wl_data = np.concatenate([np.arange(len(wl))[:, np.newaxis], wl[:, np.newaxis],
                              fwhm[:, np.newaxis]], axis=1)
    np.savetxt(paths.wavelength_path, wl_data, delimiter=' ')

    mean_latitude, mean_longitude, mean_elevation_km, elevation_lut_grid = get_metadata_from_loc(paths.loc_working_path, lut_params)

    # Need a 180 - here, as this is already in MODTRAN convention
    mean_altitude_km = mean_elevation_km + np.cos(np.deg2rad(180 - mean_to_sensor_zenith)) * mean_path_km

    logging.info('Path (km): %f, 180 - To-sensor Zenith (deg): %f, To-sensor Azimuth (deg) : %f, Altitude: %6.2f km' %
                 (mean_path_km, mean_to_sensor_zenith, mean_to_sensor_azimuth, mean_altitude_km))



    # Superpixel segmentation
    if args.empirical_line == 1:
        if not exists(paths.lbl_working_path) or not exists(paths.radiance_working_path):
            logging.info('Segmenting...')
            segment(spectra=(paths.radiance_working_path, paths.lbl_working_path),
                    flag=-9999, npca=5, segsize=SEGMENTATION_SIZE, nchunk=CHUNKSIZE)

        # Extract input data per segment
        for inp, outp in [(paths.radiance_working_path, paths.rdn_subs_path),
                          (paths.obs_working_path, paths.obs_subs_path),
                          (paths.loc_working_path, paths.loc_subs_path)]:
            if not exists(outp):
                logging.info('Extracting ' + outp)
                extractions(inputfile=inp, labels=paths.lbl_working_path,
                            output=outp, chunksize=CHUNKSIZE, flag=-9999)


    if args.presolve == 1 and (not exists(paths.h2o_subs_path + '.hdr') or not exists(paths.h2o_subs_path)):
        write_modtran_template(atmosphere_type='ATM_MIDLAT_SUMMER', fid=paths.fid, altitude_km=mean_altitude_km,
                               dayofyear=dayofyear, latitude=mean_latitude, longitude=mean_longitude,
                               to_sensor_azimuth=mean_to_sensor_azimuth, to_sensor_zenith=mean_to_sensor_zenith,
                               gmtime=gmtime, elevation_km=mean_elevation_km,
                               output_file=paths.h2o_template_path, ihaze_type='AER_NONE')

        # TODO: this is effectively redundant from the radiative_transfer->modtran. Either devise a way
        # to port in from there, or put in utils to reduce redundancy.
        xdir = {
            'linux': 'linux',
            'darwin': 'macos',
            'windows': 'windows'
        }
        name = 'H2O_bound_test'
        filebase = os.path.join(paths.lut_h2o_directory, name)
        with open(paths.h2o_template_path, 'r') as f:
            bound_test_config = json.load(f)

        bound_test_config['MODTRAN'][0]['MODTRANINPUT']['NAME'] = name
        bound_test_config['MODTRAN'][0]['MODTRANINPUT']['ATMOSPHERE']['H2OSTR'] = 50
        with open(filebase + '.json', 'w') as fout:
            fout.write(json.dumps(bound_test_config, cls=SerialEncoder, indent=4, sort_keys=True))

        cwd = os.getcwd()
        os.chdir(paths.lut_h2o_directory)
        cmd = os.path.join(paths.modtran_path, 'bin', xdir[platform], 'mod6c_cons ' + filebase + '.json')
        try:
            subprocess.call(cmd, shell=True, timeout=10)
        except:
            pass
        os.chdir(cwd)

        max_water = None
        with open(filebase + '.tp6') as tp6file:
            for count, line in enumerate(tp6file):
                if 'The water column is being set to the maximum' in line:
                    max_water = line.split(',')[1].strip()
                    max_water = float(max_water.split(' ')[0])
                    break

        if max_water is None:
            logging.error('Could not find MODTRAN H2O upper bound in file {}'.format(filebase + '.tp6'))
            raise KeyError('Could not find MODTRAN H2O upper bound')

        # Write the presolve connfiguration file
        h2o_grid = np.linspace(0.01, max_water - 0.01, 10).round(2)
        logging.info('Pre-solve H2O grid: {}'.format(h2o_grid))
        logging.info('Writing H2O pre-solve configuration file.')
        build_presolve_config(paths, h2o_grid, args.n_cores, args.surface_category)

        # Run modtran retrieval
        logging.info('Run ISOFIT initial guess')
        retrieval_h2o = isofit.Isofit(paths.h2o_config_path, level='DEBUG')
        retrieval_h2o.run()

        # clean up unneeded storage
        for to_rm in ['*r_k', '*t_k', '*tp7', '*wrn', '*psc', '*plt', '*7sc', '*acd']:
            cmd = 'rm ' + join(paths.lut_h2o_directory, to_rm)
            logging.info(cmd)
            os.system(cmd)

    # Define h2o grid, either from presolve or LUTConfig
    if args.presolve == 1:
        h2o = envi.open(paths.h2o_subs_path + '.hdr')
        h2o_est = h2o.read_band(-1)[:].flatten()

        h2o_lut_grid = np.linspace(np.percentile(h2o_est[h2o_est > lut_params.h2o_min], 5),
                                   np.percentile(h2o_est[h2o_est > lut_params.h2o_min], 95),
                                   lut_params.num_h2o_lut_elements)

        if (np.abs(h2o_lut_grid[-1] - h2o_lut_grid[0]) < 0.03):
            new_h2o_lut_grid = np.linspace(h2o_lut_grid[0] - 0.1* np.ceil(lut_params.num_h2o_lut_elements/2.), 
                                           h2o_lut_grid[0] + 0.1*np.ceil(lut_params.num_h2o_lut_elements/2.), 
                                           lut_params.num_h2o_lut_elements)
            logging.warning('Warning: h2o lut grid from presolve detected as {}-{}, which is very narrow.  Expanding to {}-{}.  Advised to check presolve solutions thoroughly.'.format(h2o_lut_grid[0],h2o_lut_grid[-1], new_h2o_lut_grid[0], new_h2o_lut_grid[-1]))
            h2o_lut_grid = new_h2o_lut_grid
    else:
        h2o_lut_grid = np.linspace(lut_params.default_h2o_lut_range[0], lut_params.default_h2o_lut_range[1],
                                   lut_params.num_h2o_lut_elements)


    logging.info('Full (non-aerosol) LUTs:\nElevation: {}\nTo-sensor azimuth: {}\nTo-sensor zenith: {}\nh2o-vis: {}:'.format(elevation_lut_grid, to_sensor_azimuth_lut_grid, to_sensor_zenith_lut_grid, h2o_lut_grid))

    logging.info(paths.state_subs_path)
    if not exists(paths.state_subs_path) or \
            not exists(paths.uncert_subs_path) or \
            not exists(paths.rfl_subs_path):

        write_modtran_template(atmosphere_type='ATM_MIDLAT_SUMMER', fid=paths.fid, altitude_km=mean_altitude_km,
                               dayofyear=dayofyear, latitude=mean_latitude, longitude=mean_longitude,
                               to_sensor_azimuth=mean_to_sensor_azimuth, to_sensor_zenith=mean_to_sensor_zenith,
                               gmtime=gmtime, elevation_km=mean_elevation_km, output_file=paths.modtran_template_path)

        logging.info('Writing main configuration file.')
        build_main_config(paths, lut_params, h2o_lut_grid, elevation_lut_grid, to_sensor_azimuth_lut_grid,
                          to_sensor_zenith_lut_grid, mean_latitude, mean_longitude, dt, 
                          args.empirical_line == 1, args.n_cores, args.surface_category)

        # Run modtran retrieval
        logging.info('Running ISOFIT with full LUT')
        retrieval_full = isofit.Isofit(paths.modtran_config_path, level='DEBUG')
        retrieval_full.run()

        # clean up unneeded storage
        for to_rm in ['*r_k', '*t_k', '*tp7', '*wrn', '*psc', '*plt', '*7sc', '*acd']:
            cmd = 'rm ' + join(paths.lut_modtran_directory, to_rm)
            logging.info(cmd)
            os.system(cmd)

    if not exists(paths.rfl_working_path) or not exists(paths.uncert_working_path):
        # Empirical line
        logging.info('Empirical line inference')
        empirical_line(reference_radiance_file=paths.rdn_subs_path,
                       reference_reflectance_file=paths.rfl_subs_path,
                       reference_uncertainty_file=paths.uncert_subs_path,
                       reference_locations_file=paths.loc_subs_path,
                       segmentation_file=paths.lbl_working_path,
                       input_radiance_file=paths.radiance_working_path,
                       input_locations_file=paths.loc_working_path,
                       output_reflectance_file=paths.rfl_working_path,
                       output_uncertainty_file=paths.uncert_working_path,
                       isofit_config=paths.modtran_config_path)

    logging.info('Done.')
Example #2
0
def do_inverse(isofit_inv: dict, radfile: pathlib.Path,
               est_refl_file: pathlib.Path, est_state_file: pathlib.Path,
               atm_coef_file: pathlib.Path, post_unc_file: pathlib.Path,
               overwrite: bool, use_empirical_line: bool):
    if use_empirical_line:
        # Segment first, then run on segmented file
        SEGMENTATION_SIZE = 40
        CHUNKSIZE = 256
        lbl_working_path = radfile.parent / str(radfile).replace(
            "toa-radiance", "segmentation")
        rdn_subs_path = radfile.with_suffix("-subs")
        rfl_subs_path = est_refl_file.with_suffix("-subs")
        state_subs_path = est_state_file.with_suffix("-subs")
        atm_subs_path = atm_coef_file.with_suffix("-subs")
        unc_subs_path = post_unc_file.with_suffix("-subs")
        isofit_inv["input"]["measured_radiance_file"] = str(rdn_subs_path)
        isofit_inv["output"] = {
            "estimated_reflectance_file": str(rfl_subs_path),
            "estimated_state_file": str(state_subs_path),
            "atmospheric_coefficients_file": str(atm_subs_path),
            "posterior_uncertainty_file": str(unc_subs_path)
        }
        if not overwrite and lbl_working_path.exists(
        ) and rdn_subs_path.exists():
            logger.info(
                "Skipping segmentation and extraction because files exist.")
        else:
            logger.info(
                "Fixing any radiance values slightly less than zero...")
            rad_img = sp.open_image(str(radfile) + ".hdr")
            rad_m = rad_img.open_memmap(writable=True)
            nearzero = np.logical_and(rad_m < 0, rad_m > -2)
            rad_m[nearzero] = 0.0001
            del rad_m
            del rad_img
            logger.info("Segmenting...")
            segment(spectra=(str(radfile), str(lbl_working_path)),
                    flag=-9999,
                    npca=5,
                    segsize=SEGMENTATION_SIZE,
                    nchunk=CHUNKSIZE)
            logger.info("Extracting...")
            extractions(inputfile=str(radfile),
                        labels=str(lbl_working_path),
                        output=str(rdn_subs_path),
                        chunksize=CHUNKSIZE,
                        flag=-9999)

    else:
        # Run Isofit directly
        isofit_inv["input"]["measured_radiance_file"] = str(radfile)
        isofit_inv["output"] = {
            "estimated_reflectance_file": str(est_refl_file),
            "estimated_state_file": str(est_state_file),
            "atmospheric_coefficients_file": str(atm_coef_file),
            "posterior_uncertainty_file": str(post_unc_file)
        }

    if not overwrite and pathlib.Path(
            isofit_inv["output"]["estimated_reflectance_file"]).exists():
        logger.info("Skipping inversion because output file exists.")
    else:
        invfile = radfile.parent / (
            str(radfile).replace("toa-radiance", "inverse") + ".json")
        json.dump(isofit_inv, open(invfile, "w"), indent=2)
        Isofit(invfile).run()

    if use_empirical_line:
        if not overwrite and est_refl_file.exists():
            logger.info("Skipping empirical line because output exists.")
        else:
            logger.info("Applying empirical line...")
            empirical_line(reference_radiance_file=str(rdn_subs_path),
                           reference_reflectance_file=str(rfl_subs_path),
                           reference_uncertainty_file=str(unc_subs_path),
                           reference_locations_file=None,
                           segmentation_file=str(lbl_working_path),
                           input_radiance_file=str(radfile),
                           input_locations_file=None,
                           output_reflectance_file=str(est_refl_file),
                           output_uncertainty_file=str(post_unc_file),
                           isofit_config=str(invfile))
Example #3
0
def main():
    # Parse arguments
    parser = argparse.ArgumentParser(
        description="Apply OE to a block of data.")
    parser.add_argument('input_radiance', type=str)
    parser.add_argument('input_loc', type=str)
    parser.add_argument('input_obs', type=str)
    parser.add_argument('working_directory', type=str)
    parser.add_argument('sensor', type=str, choices=['ang', 'avcl', 'neon'])
    parser.add_argument('--copy_input_files',
                        type=int,
                        choices=[0, 1],
                        default=0)
    parser.add_argument('--h2o', action='store_true')
    parser.add_argument('--modtran_path', type=str)
    parser.add_argument('--wavelength_path', type=str)
    parser.add_argument('--aerosol_climatology_path', type=str, default=None)
    parser.add_argument('--rdn_factors_path', type=str)
    parser.add_argument('--surface_path', type=str)
    parser.add_argument('--channelized_uncertainty_path', type=str)
    parser.add_argument('--lut_config_file', type=str)
    parser.add_argument('--logging_level', type=str, default="INFO")
    parser.add_argument('--log_file', type=str, default=None)

    args = parser.parse_args()

    if args.copy_input_files == 1:
        args.copy_input_files = True
    else:
        args.copy_input_files = False

    if args.log_file is None:
        logging.basicConfig(format='%(message)s', level=args.logging_level)
    else:
        logging.basicConfig(format='%(message)s',
                            level=args.logging_level,
                            filename=args.log_file)

    lut_params = LUTConfig(args.lut_config_file)

    paths = Pathnames(args)
    paths.make_directories()
    paths.stage_files()

    # Based on the sensor type, get appropriate year/month/day info fro intial condition.
    # We'll adjust for line length and UTC day overrun later
    if args.sensor == 'ang':
        # parse flightline ID (AVIRIS-NG assumptions)
        dt = datetime.strptime(paths.fid[3:], '%Y%m%dt%H%M%S')
        dayofyear = dt.timetuple().tm_yday
    elif args.sensor == 'avcl':
        # parse flightline ID (AVIRIS-CL assumptions)
        dt = datetime.strptime('20{}t000000'.format(paths.fid[1:7]),
                               '%Y%m%dt%H%M%S')
        dayofyear = dt.timetuple().tm_yday
    elif args.sensor == 'neon':
        dt = datetime.strptime(paths.fid, 'NIS01_%Y%m%d_%H%M%S')
        dayofyear = dt.timetuple().tm_yday

    h_m_s, day_increment, mean_path_km, mean_to_sensor_azimuth, mean_to_sensor_zenith, valid, \
    to_sensor_azimuth_lut_grid, to_sensor_zenith_lut_grid = get_metadata_from_obs(paths.obs_working_path, lut_params)

    if day_increment:
        dayofyear += 1

    gmtime = float(h_m_s[0] + h_m_s[1] / 60.)

    # Superpixel segmentation
    if not exists(paths.lbl_working_path) or not exists(
            paths.radiance_working_path):
        logging.info('Segmenting...')
        segment(spectra=(paths.radiance_working_path, paths.lbl_working_path),
                flag=-9999,
                npca=5,
                segsize=SEGMENTATION_SIZE,
                nchunk=CHUNKSIZE)

    # Extract input data per segment
    for inp, outp in [(paths.radiance_working_path, paths.rdn_subs_path),
                      (paths.obs_working_path, paths.obs_subs_path),
                      (paths.loc_working_path, paths.loc_subs_path)]:
        if not exists(outp):
            logging.info('Extracting ' + outp)
            extractions(inputfile=inp,
                        labels=paths.lbl_working_path,
                        output=outp,
                        chunksize=CHUNKSIZE,
                        flag=-9999)

    # get radiance file, wavelengths
    if args.wavelength_path:
        chn, wl, fwhm = np.loadtxt(args.wavelength_path).T
    else:
        radiance_dataset = envi.open(paths.rdn_subs_path + '.hdr')
        wl = np.array(
            [float(w) for w in radiance_dataset.metadata['wavelength']])
        if 'fwhm' in radiance_dataset.metadata:
            fwhm = np.array(
                [float(f) for f in radiance_dataset.metadata['fwhm']])
        if 'FWHM' in radiance_dataset.metadata:
            fwhm = np.array(
                [float(f) for f in radiance_dataset.metadata['FWHM']])
        else:
            fwhm = np.ones(wl.shape) * (wl[1] - wl[0])

    # Convert to microns if needed
    if wl[0] > 100:
        wl = wl / 1000.0
        fwhm = fwhm / 1000.0

    # write wavelength file
    wl_data = np.concatenate([
        np.arange(len(wl))[:, np.newaxis], wl[:, np.newaxis], fwhm[:,
                                                                   np.newaxis]
    ],
                             axis=1)
    np.savetxt(paths.wavelength_path, wl_data, delimiter=' ')

    mean_latitude, mean_longitude, mean_elevation_km, elevation_lut_grid = get_metadata_from_loc(
        paths.loc_working_path, lut_params)

    # Need a 180 - here, as this is already in MODTRAN convention
    mean_altitude_km = mean_elevation_km + np.cos(
        np.deg2rad(180 - mean_to_sensor_zenith)) * mean_path_km

    logging.info(
        'Path (km): %f, 180 - To-sensor Zenith (deg): %f, To-sensor Azimuth (deg) : %f, Altitude: %6.2f km'
        % (mean_path_km, mean_to_sensor_zenith, mean_to_sensor_azimuth,
           mean_altitude_km))

    if not exists(paths.h2o_subs_path + '.hdr') or not exists(
            paths.h2o_subs_path):

        write_modtran_template(atmosphere_type='ATM_MIDLAT_SUMMER',
                               fid=paths.fid,
                               altitude_km=mean_altitude_km,
                               dayofyear=dayofyear,
                               latitude=mean_latitude,
                               longitude=mean_longitude,
                               to_sensor_azimuth=mean_to_sensor_azimuth,
                               to_sensor_zenith=mean_to_sensor_zenith,
                               gmtime=gmtime,
                               elevation_km=mean_elevation_km,
                               output_file=paths.h2o_template_path,
                               ihaze_type='AER_NONE')

        # Write the presolve connfiguration file
        logging.info('Writing H2O pre-solve configuration file.')
        build_presolve_config(paths, np.linspace(0.5, 5, 10))

        # Run modtran retrieval
        logging.info('Run ISOFIT initial guess')
        retrieval_h2o = isofit.Isofit(paths.h2o_config_path, level='DEBUG')
        retrieval_h2o.run()

        # clean up unneeded storage
        for to_rm in [
                '*r_k', '*t_k', '*tp7', '*wrn', '*psc', '*plt', '*7sc', '*acd'
        ]:
            cmd = 'rm ' + join(paths.lut_h2o_directory, to_rm)
            logging.info(cmd)
            os.system(cmd)

    # Extract h2o grid avoiding the zero label (periphery, bad data)
    # and outliers
    h2o = envi.open(paths.h2o_subs_path + '.hdr')
    h2o_est = h2o.read_band(-1)[:].flatten()

    h2o_lut_grid = np.linspace(
        np.percentile(h2o_est[h2o_est > lut_params.h2o_min], 5),
        np.percentile(h2o_est[h2o_est > lut_params.h2o_min], 95),
        lut_params.num_h2o_lut_elements)

    logging.info(
        'Full (non-aerosol) LUTs:\nElevation: {}\nTo-sensor azimuth: {}\nTo-sensor zenith: {}\nh2o-vis: {}:'
        .format(elevation_lut_grid, to_sensor_azimuth_lut_grid,
                to_sensor_zenith_lut_grid, h2o_lut_grid))

    logging.info(paths.state_subs_path)
    if not exists(paths.state_subs_path) or \
            not exists(paths.uncert_subs_path) or \
            not exists(paths.rfl_subs_path):

        write_modtran_template(atmosphere_type='ATM_MIDLAT_SUMMER',
                               fid=paths.fid,
                               altitude_km=mean_altitude_km,
                               dayofyear=dayofyear,
                               latitude=mean_latitude,
                               longitude=mean_longitude,
                               to_sensor_azimuth=mean_to_sensor_azimuth,
                               to_sensor_zenith=mean_to_sensor_zenith,
                               gmtime=gmtime,
                               elevation_km=mean_elevation_km,
                               output_file=paths.modtran_template_path)

        logging.info('Writing main configuration file.')
        build_main_config(paths, lut_params, h2o_lut_grid, elevation_lut_grid,
                          to_sensor_azimuth_lut_grid,
                          to_sensor_zenith_lut_grid, mean_latitude,
                          mean_longitude, dt)

        # Run modtran retrieval
        logging.info('Running ISOFIT with full LUT')
        retrieval_full = isofit.Isofit(paths.modtran_config_path,
                                       level='DEBUG')
        retrieval_full.run()

        # clean up unneeded storage
        for to_rm in [
                '*r_k', '*t_k', '*tp7', '*wrn', '*psc', '*plt', '*7sc', '*acd'
        ]:
            cmd = 'rm ' + join(paths.lut_modtran_directory, to_rm)
            logging.info(cmd)
            os.system(cmd)

    if not exists(paths.rfl_working_path) or not exists(
            paths.uncert_working_path):
        # Empirical line
        logging.info('Empirical line inference')
        empirical_line(reference_radiance=paths.rdn_subs_path,
                       reference_reflectance=paths.rfl_subs_path,
                       reference_uncertainty=paths.uncert_subs_path,
                       reference_locations=paths.loc_subs_path,
                       hashfile=paths.lbl_working_path,
                       input_radiance=paths.radiance_working_path,
                       input_locations=paths.loc_working_path,
                       output_reflectance=paths.rfl_working_path,
                       output_uncertainty=paths.uncert_working_path,
                       isofit_config=paths.modtran_config_path)

    logging.info('Done.')