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
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
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)
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)