Exemple #1
0
    def load_rt(self, fn, resample=True):
        """Load the results of a SixS run."""

        with open(os.path.join(self.lut_dir, fn), 'r') as l:
            lines = l.readlines()

        with open(os.path.join(self.lut_dir, 'LUT_' + fn + '.inp'), 'r') as l:
            inlines = l.readlines()
            solzen = float(inlines[1].strip().split()[0])
        self.coszen = np.cos(solzen / 360 * 2.0 * np.pi)

        # Strip header
        for i, ln in enumerate(lines):
            if ln.startswith('*        trans  down   up'):
                lines = lines[(i + 1):(i + 1 + self.sixs_ngrid_init)]
                break

        solzens = np.zeros(len(lines))
        sphalbs = np.zeros(len(lines))
        transups = np.zeros(len(lines))
        transms = np.zeros(len(lines))
        rhoatms = np.zeros(len(lines))
        self.grid = np.zeros(len(lines))

        for i, ln in enumerate(lines):
            ln = ln.replace('*', ' ').strip()
            w, gt, scad, scau, salb, rhoa, swl, step, sbor, dsol, toar = \
                ln.split()

            self.grid[i] = float(w) * 1000.0  # convert to nm
            solzens[i] = float(solzen)
            sphalbs[i] = float(salb)
            transups[i] = 0.0  # float(scau)
            transms[i] = float(scau) * float(scad) * float(gt)
            rhoatms[i] = float(rhoa)

        if resample:
            solzens = resample_spectrum(solzens, self.grid, self.wl, self.fwhm)
            rhoatms = resample_spectrum(rhoatms, self.grid, self.wl, self.fwhm)
            transms = resample_spectrum(transms, self.grid, self.wl, self.fwhm)
            sphalbs = resample_spectrum(sphalbs, self.grid, self.wl, self.fwhm)
            transups = resample_spectrum(transups, self.grid, self.wl,
                                         self.fwhm)

        results = {
            "solzen": solzens,
            "rhoatm": rhoatms,
            "transm": transms,
            "sphalb": sphalbs,
            "transup": transups
        }
        return results
Exemple #2
0
    def __init__(self, engine_config: RadiativeTransferEngineConfig,
                 full_config: Config):

        self.angular_lut_keys_degrees = [
            'OBSZEN', 'TRUEAZ', 'viewzen', 'viewaz', 'solzen', 'solaz'
        ]
        self.angular_lut_keys_radians = []

        super().__init__(engine_config, full_config)

        self.treat_as_emissive = False

        self.sixs_dir = self.find_basedir(engine_config)
        self.sixs_grid_init = s.arange(self.wl[0], self.wl[-1] + 2.5, 2.5)
        self.sixs_ngrid_init = len(self.sixs_grid_init)
        self.params = {
            'aermodel': 1,
            'AOT550': 0.01,
            'H2OSTR': 0,
            'O3': 0.40,
            'day': engine_config.day,
            'month': engine_config.month,
            'elev': engine_config.elev,
            'alt': engine_config.alt,
            'atm_file': None,
            'abscf_data_directory': None,
            'wlinf': self.sixs_grid_init[0] / 1000.0,  # convert to nm
            'wlsup': self.sixs_grid_init[-1] / 1000.0
        }

        if engine_config.obs_file is not None:
            # A special case where we load the observation geometry
            # from a custom-crafted text file
            g = Geometry(obs=engine_config.obs_file)
            self.params['solzen'] = g.solar_zenith
            self.params['solaz'] = g.solar_azimuth
            self.params['viewzen'] = g.observer_zenith
            self.params['viewaz'] = g.observer_azimuth
        else:
            # We have to get geometry from somewhere, so we presume it is
            # in the configuration file.
            self.params['solzen'] = engine_config.solzen
            self.params['viewzen'] = engine_config.viewzen
            self.params['solaz'] = engine_config.solaz
            self.params['viewaz'] = engine_config.viewaz

        self.esd = s.loadtxt(engine_config.earth_sun_distance_file)
        dt = datetime(2000, self.params['month'], self.params['day'])
        self.day_of_year = dt.timetuple().tm_yday
        self.irr_factor = self.esd[self.day_of_year - 1, 1]

        irr = s.loadtxt(engine_config.irradiance_file, comments='#')
        iwl, irr = irr.T
        irr = irr / 10.0  # convert, uW/nm/cm2
        irr = irr / self.irr_factor**2  # consider solar distance
        self.solar_irr = resample_spectrum(irr, iwl, self.wl, self.fwhm)

        self.lut_quantities = ['rhoatm', 'transm', 'sphalb', 'transup']
        self.build_lut()
def beckman_rdn(simulated_modtran, wl, n_bands=424):

    refl_file = "../isofit/examples/20171108_Pasadena/insitu/BeckmanLawn.txt"
    solar_irr = np.load('../isofit/examples/20171108_Pasadena/solar_irr.npy')[:-1]
    coszen = 0.6155647578988601
    rfl = np.genfromtxt(refl_file)
    rfl = resample_spectrum(rfl[:,1],rfl[:,0],wl,rfl[:,2]*1000)

    rho = simulated_modtran[:,n_bands:2*n_bands]
    rdn_atm = rho / np.pi*(solar_irr * coszen)

    transm = simulated_modtran[:,:n_bands]
    rdn_down = (solar_irr * coszen) / np.pi * transm

    sphalb = simulated_modtran[:,n_bands*2:n_bands*3]

    rdn = rdn_atm + rdn_down * rfl / (1.0 - sphalb * rfl)

    return rdn, rdn_atm
Exemple #4
0
    def __init__(self, engine_config: RadiativeTransferEngineConfig,
                 full_config: Config):

        # Specify which of the potential MODTRAN LUT parameters are angular, which will be handled differently
        self.angular_lut_keys_degrees = [
            'OBSZEN', 'TRUEAZ', 'viewzen', 'viewaz', 'solzen', 'solaz'
        ]
        self.angular_lut_keys_radians = []

        super().__init__(engine_config, full_config)

        self.lut_quantities = ['rhoatm', 'transm', 'sphalb', 'transup']
        self.treat_as_emissive = False

        # Load in the emulator aux - hold off on emulator till last
        # second, as the model is large, and we don't want to load in
        # parallel if possible
        emulator_aux = np.load(engine_config.emulator_aux_file)

        simulator_wavelengths = emulator_aux['simulator_wavelengths']
        simulator_wavelengths = np.arange(350, 2500 + 2.5, 2.5)
        emulator_wavelengths = emulator_aux['emulator_wavelengths']
        n_simulator_chan = len(simulator_wavelengths)
        n_emulator_chan = len(emulator_wavelengths)

        for lq in self.lut_quantities:
            if lq not in emulator_aux['rt_quantities'].tolist(
            ) and lq != 'transup':
                raise AttributeError(
                    'lut_quantities: {} do not match emulator_aux rt_quantities: {}'
                    .format(self.lut_quantities,
                            emulator_aux['rt_quantities']))

        interpolator_disk_paths = [
            engine_config.interpolator_base_path + '_' + rtq + '.pkl'
            for rtq in self.lut_quantities
        ]

        # Build a new config for sixs simulation runs using existing config
        sixs_config: RadiativeTransferEngineConfig = deepcopy(engine_config)
        sixs_config.aerosol_model_file = None
        sixs_config.aerosol_template_file = None
        sixs_config.emulator_file = None

        # Populate the sixs-values from the modtran template file
        with open(sixs_config.template_file, 'r') as infile:
            modtran_input = yaml.safe_load(
                infile)['MODTRAN'][0]['MODTRANINPUT']

        # Do a quickk conversion to put things in solar azimuth/zenith terms for 6s
        dt = datetime.datetime(2000, 1, 1) + datetime.timedelta(days=modtran_input['GEOMETRY']['IDAY'] - 1)  + \
             datetime.timedelta(hours = modtran_input['GEOMETRY']['GMTIME'])

        solar_azimuth, solar_zenith, ra, dec, h = sunpos(
            dt, modtran_input['GEOMETRY']['PARM1'],
            -modtran_input['GEOMETRY']['PARM2'],
            modtran_input['SURFACE']['GNDALT'] * 1000.0)

        sixs_config.day = dt.day
        sixs_config.month = dt.month
        sixs_config.elev = modtran_input['SURFACE']['GNDALT']
        sixs_config.alt = modtran_input['GEOMETRY']['H1ALT']
        sixs_config.solzen = solar_zenith
        sixs_config.solaz = solar_azimuth
        sixs_config.viewzen = 180 - modtran_input['GEOMETRY']['OBSZEN']
        sixs_config.viewaz = modtran_input['GEOMETRY']['TRUEAZ']
        sixs_config.wlinf = 0.35
        sixs_config.wlsup = 2.5

        # Build the simulator
        logging.debug('Create RTE simulator')
        sixs_rte = SixSRT(sixs_config,
                          full_config,
                          build_lut_only=False,
                          wavelength_override=simulator_wavelengths,
                          fwhm_override=np.ones(n_simulator_chan) * 2.,
                          modtran_emulation=True)
        self.solar_irr = sixs_rte.solar_irr
        self.esd = sixs_rte.esd
        self.coszen = sixs_rte.coszen

        emulator_irr = emulator_aux['solar_irr']
        irr_factor_ref = sixs_rte.esd[200, 1]
        irr_factor_current = sixs_rte.esd[sixs_rte.day_of_year - 1, 1]

        # First, convert our irr to date 0, then back to current date
        self.solar_irr = resample_spectrum(
            emulator_irr * irr_factor_ref**2 / irr_factor_current**2,
            emulator_wavelengths, self.wl, self.fwhm)

        # First, check if we've already got the vector interpolators built on disk:
        prebuilt = np.all([os.path.isfile(x) for x in interpolator_disk_paths])
        if prebuilt == False:
            # Load the emulator
            emulator = keras.models.load_model(engine_config.emulator_file)

            # Couple emulator-simulator
            emulator_inputs = np.zeros(
                (sixs_rte.points.shape[0],
                 n_simulator_chan * len(emulator_aux['rt_quantities'])),
                dtype=float)

            logging.info('loading 6s results for emulator')
            for ind, (point, fn) in enumerate(zip(self.points,
                                                  sixs_rte.files)):
                simulator_output = sixs_rte.load_rt(fn, resample=False)
                for keyind, key in enumerate(emulator_aux['rt_quantities']):
                    emulator_inputs[ind,
                                    keyind * n_simulator_chan:(keyind + 1) *
                                    n_simulator_chan] = simulator_output[key]
            emulator_inputs[np.isnan(emulator_inputs)] = 0
            emulator_inputs_match_output = np.zeros(
                (emulator_inputs.shape[0],
                 n_emulator_chan * len(emulator_aux['rt_quantities'])))
            for key_ind, key in enumerate(emulator_aux['rt_quantities']):
                band_range_o = np.arange(n_emulator_chan * key_ind,
                                         n_emulator_chan * (key_ind + 1))
                band_range_i = np.arange(n_simulator_chan * key_ind,
                                         n_simulator_chan * (key_ind + 1))

                finterp = interpolate.interp1d(
                    simulator_wavelengths, emulator_inputs[:, band_range_i])
                emulator_inputs_match_output[:, band_range_o] = finterp(
                    emulator_wavelengths)

            if 'response_scaler' in emulator_aux.keys():
                response_scaler = emulator_aux['response_scaler']
            else:
                response_scaler = 100.

            logging.debug('Emulating')
            emulator_outputs = emulator.predict(
                emulator_inputs) / response_scaler
            emulator_outputs = emulator_outputs + emulator_inputs_match_output

            dims_aug = self.lut_dims + [self.n_chan]
            for key_ind, key in enumerate(emulator_aux['rt_quantities']):
                interpolator_inputs = np.zeros(dims_aug, dtype=float)
                for point_ind, point in enumerate(self.points):
                    ind = [
                        np.where(g == p)[0]
                        for g, p in zip(self.lut_grids, point)
                    ]
                    ind = tuple(ind)
                    interpolator_inputs[ind] = resample_spectrum(
                        emulator_outputs[point_ind, key_ind *
                                         n_emulator_chan:(key_ind + 1) *
                                         n_emulator_chan],
                        emulator_wavelengths, self.wl, self.fwhm)

                if key == 'transup':
                    interpolator_inputs[...] = 0

                self.luts[key] = VectorInterpolator(self.lut_grids,
                                                    interpolator_inputs,
                                                    self.lut_interp_types)

            self.luts['transup'] = VectorInterpolator(self.lut_grids,
                                                      interpolator_inputs * 0,
                                                      self.lut_interp_types)

            for key_ind, key in enumerate(self.lut_quantities):
                with open(interpolator_disk_paths[key_ind], 'wb') as fi:
                    pickle.dump(self.luts[key], fi, protocol=4)

        else:
            logging.info('Prebuilt LUT interpolators found, loading from disk')
            for key_ind, key in enumerate(self.lut_quantities):
                with open(interpolator_disk_paths[key_ind], 'rb') as fi:
                    self.luts[key] = pickle.load(fi)
Exemple #5
0
    def __init__(self, config, statevector_names):

        TabularRT.__init__(self, config)
        self.sixs_dir = self.find_basedir(config)
        self.wl, self.fwhm = load_wavelen(config['wavelength_file'])
        self.sixs_grid_init = s.arange(self.wl[0], self.wl[-1]+2.5, 2.5)
        self.sixs_ngrid_init = len(self.sixs_grid_init)
        self.sixs_dir = self.find_basedir(config)
        self.params = {'aermodel': 1,
                       'AOT550': 0.01,
                       'H2OSTR': 0,
                       'O3': 0.40,
                       'day':   config['day'],
                       'month': config['month'],
                       'elev':  config['elev'],
                       'alt':   config['alt'],
                       'atm_file': None,
                       'abscf_data_directory': None,
                       'wlinf': self.sixs_grid_init[0]/1000.0,  # convert to nm
                       'wlsup': self.sixs_grid_init[-1]/1000.0}

        if 'obs_file' in config:
            # A special case where we load the observation geometry
            # from a custom-crafted text file
            g = Geometry(obs=config['obs_file'])
            self.params['solzen'] = g.solar_zenith
            self.params['solaz'] = g.solar_azimuth
            self.params['viewzen'] = g.observer_zenith
            self.params['viewaz'] = g.observer_azimuth
        else:
            # We have to get geometry from somewhere, so we presume it is
            # in the configuration file.
            for f in ['solzen', 'viewzen', 'solaz', 'viewaz']:
                self.params[f] = config[f]

        self.esd = s.loadtxt(config['earth_sun_distance_file'])
        dt = datetime(2000, self.params['month'], self.params['day'])
        self.day_of_year = dt.timetuple().tm_yday
        self.irr_factor = self.esd[self.day_of_year-1, 1]

        irr = s.loadtxt(config['irradiance_file'], comments='#')
        iwl, irr = irr.T
        irr = irr / 10.0  # convert, uW/nm/cm2
        irr = irr / self.irr_factor**2  # consider solar distance
        self.solar_irr = resample_spectrum(irr, iwl,  self.wl, self.fwhm)

        self.angular_lut_keys_degrees = ['OBSZEN','TRUEAZ','viewzen','viewaz',
            'solzen','solaz']

        self.lut_quantities = ['rhoatm', 'transm', 'sphalb', 'transup']
        self.build_lut()

        # This array is used to handle the potential indexing mismatch between
        # the 'global statevector' (which may couple multiple radiative 
        # transform models) and this statevector. It should never be modified
        full_to_local_statevector_position_mapping = []
        for sn in self.statevec:
            ix = statevector_names.index(sn)
            full_to_local_statevector_position_mapping.append(ix)
        self._full_to_local_statevector_position_mapping = \
            s.array(full_to_local_statevector_position_mapping)