def test_rsdt_prosail5(datadir): fname = datadir("REFL_CAN.txt") w, resv, rdot, rsot, rddt, rsdt = np.loadtxt(fname, unpack=True) rr = prosail.run_prosail(1.5, 40., 8., 0.0, 0.01, 0.009, 3., -0.35, 0.01, 30., 10., 0., typelidf=1, lidfb=-0.15, rsoil = 1., psoil=1., factor="DHR") assert np.allclose(rsdt, rr, atol=0.01)
def call_prosail ( n, cab, car, cbrown, cw, cm, lai, lidf, rsoil, psoil, hspot, sza, vza, vaa ): """Helper function""" r = prosail.run_prosail ( n, cab, car, cbrown, cw, cm, lai, lidf, 0, rsoil, psoil, hspot, sza, vza, vaa, 2 ) rpass = np.isfinite ( r ) x = np.arange(400, 2501 ) ri = np.interp ( x, x[rpass], r[rpass]) return ri
def brdfModel(s,vza,sza,raa): ''' Run the full BRDF model for parameters in s ''' try: brdf = [] for i in xrange(len(s['n'])): brdf.append(run_prosail(s['n'][i],s['cab'][i],s['car'][i],s['cbrown'][i],s['cw'][i],s['cm'][i],\ s['lai'][i],s['ala'][i],0.0,s['bsoil'][i],s['psoil'][i],s['hspot'][i],\ vza[i],sza[i],raa[i],2)) except: brdf = [] for i in xrange(len(s['n'])): brdf.append(run_prosail(s['n'][i],s['cab'][i],s['car'][i],s['cbrown'][i],s['cw'][i],s['cm'][i],\ s['lai'][i],s['ala'][i],0.0,s['bsoil'][i],s['psoil'][i],s['hspot'][i],\ vza,sza,raa,2)) return (vza,sza,raa),transform(s),fixnan(np.array(brdf))
def prosail8d(N, CAB, CW, CM, LAI, LAD, PSOIL, SZA): """Generates Prosail Data Parameters ---------- N : float Leaf Structure Parameter CAB : float Leaf Chlorophyll Concentration CW : float Equivalent Leaf Water CM : float Leaf Dry Matter LAI : float Leaf Area Index LAD : float Leaf angle distribution PSOIL : float Solar Scalar 2 (Moisture) SZA : float Solar Zenith Angle Returns ------- spectrum : np.ndarray (2101, ) The generated spectrum for prosail """ return prosail.run_prosail( n=N, # Leaf Structure Parameter cab=CAB, # Chlorophyll a + b car=0, # Leaf Cartenoid Concentration cbrown=0, # Senescent Pigment cw=CW, # Equivalent Leaf Water cm=CM, # Leaf Dry Matter lai=LAI, # Leaf Area Index lidfa=LAD, # Leaf Angle Distribution (a) hspot=0.01, # HotSpot tts=SZA, # Sun Zenith Angle tto=0, # Sensor zenith angle psi=0.0, # Relative Sensor-Solar Azimuth angle ant=0, # leaf antho. concen. alpha=40, # psoil=PSOIL, rsoil=1.0, )
def cpled_model(x, wavebands, sza, saa, vza, vaa, day, month, do_trans=True): """A coupled land surface/atmospheric model, predicting TOA refl from land surface parameters and atmospheric composition parameters. This function provides estimates of TOA refl for * A particular date * A particular illumination geometry The underlying land surface reflectance spectra is simulated using PROSAIL, and the atmospheric calculations are done with 6S. The coupling assumes a Lambertian land surface The input parameter ``x`` is a vector with the following components: * ``n`` * ``cab`` * ``car`` * ``cbrown`` * ``cw`` * ``cm`` * ``lai`` * ``ala`` * ``bsoil`` * ``psoil`` * ``aot_550`` * ``o3_conc`` * ``cwc`` """ from prosail import run_prosail # Invert parameter LAI if do_trans: x = inverse_transform(x) ################# surface refl with prosail ##################### surf_refl = np.c_[ np.arange(400, 2501)/1000., \ run_prosail(x[0], x[1], x[2], x[3], \ x[4], x[5], x[6], x[7], 0, x[8], x[9], 0.01, sza, vza, vaa, 2 )] ################# Atmospheric modelling with 6s ################## o3 = x[-2] cwc = x[-1] aot = x[-3] s, retvals = atcorr ( wavebands, o3, cwc, aot, surf_refl, sza, saa, vza, \ vaa, day, month ) ################ Per band coupling ############################### refl_toa = [] for i, sixs_output in enumerate(retvals): rho_surf = np.interp( wavebands[i], \ surf_refl[:,0], surf_refl[:,1]) refl_toa.append(to_refltoa(sixs_output, rho_surf)) return np.array(refl_toa)
def optical_forward_operator(x, sza, vza, raa, version="PROSAIL_D", hspot=0.01): """A generic wrapper to the PROSPECT+SAIL operators. Uses either PROSPECT D or PROSPECT 5. The state vector is given as a 1D vector, with parameters in order: 1. N (leaf layers) 2. Ant (if using PROSPECT-D, Anthocyanins, ug/cm2) 3. Cab (leaf chlorophyll conc, ug/cm2) 4. Car (leaf carotenoids conc, ug/cm2) 5. Cbrown (senescent pigment-like concentration, -) 6. Cw (equivalent leaf water thickness, cm) 7. Cm (dry matter, g/cm2) 8. LAI (leaf area index, m2/m2) 9. ALA (average leaf angle, deg) 10. rsoil (dry soil scalar) 11. psoil (wet soil scalar) Additionally, one needs to pass the different view/illumination angles, and optionally the value of the hotspot parameter. The function returns the top of canopy reflectance between 400 and 2500 nm every 1 nm. """ if not version.upper() in ["PROSAIL_D", "PROSAIL_5"]: raise ValueError("Can only deal with SAIL + PROSPECT D or 5!") if version.upper() == "PROSAIL_D": # Using prospect D n, ant, cab, car, cbrown, cw, cm, lai, ala, rsoil, psoil = x rho_canopy = run_prosail(n, cab, car, cbrown, cw, cm, lai, ala, hspot, sza, vza, raa, ant=ant, prospect_version="D", rsoil=rsoil, psoil=psoil) elif version.upper() == "PROSAIL_5": n, cab, car, cbrown, cw, cm, lai, ala, rsoil, psoil = x rho_canopy = run_prosail(n, cab, car, cbrown, cw, cm, lai, ala, hspot, sza, vza, raa, prospect_version="5", rsoil=rsoil, psoil=psoil) return rho_canopy
def generate_spectrum(p): return ps.run_prosail(n=p[0], cab=p[1], cw=p[2], car=p[3], cbrown=p[4], cm=p[5], lai=p[6], lidfa=p[7], psoil=p[8], rsoil=p[9], hspot=p[10], tts=p[11], tto=p[12], psi=p[13], ant=p[14], prospect_version="D")
def gen_samp_noise_angle_withsoil(nsamples, parameters,p_mins, p_maxs, tts, tto, psi): samples, distributions = gp_emulator.create_training_set(parameters, p_mins, p_maxs, n_train=nsamples) simu_ref = np.zeros((nsamples, 2101)) for i in range (nsamples) : noise = np.random.normal(0,1,2101)/500. simu_ref[i,:] = prosail.run_prosail(samples[i,0], samples[i,1], samples[i,2], samples[i,3], samples[i,4], samples[i,5], samples[i,6], samples[i,7], 0.01, tts=tts, tto=tto, psi=psi, prospect_version='D',typelidf = 2, rsoil = samples[i,8], psoil = samples[i,9])+noise for i in range(len(samples)): "n", "exp(-cab/100)", "exp(-car/100)", "cbrown", "exp(-50*cw)", "exp(-50*cm)", "exp(-lai/2)", "ala/90.", "bsoil", "psoil" samples[:,1] = np.exp(-samples[:,1]/100.) samples[:,2] = np.exp(-samples[:,2]/100.) samples[:,4] = np.exp(-50.*samples[:,4]) samples[:,5] = np.exp(-50.*samples[:,5]) samples[:,6] = np.exp(-samples[:,6]/2.) samples[:,7] = samples[:,7]/90. return simu_ref, samples
def trans_prosail ( N, cab, car, cbrown, cw, cm, lai, lidfa, lidfb, bsoil, psoil, \ hspot, tts, tto, psi ,lidfType): """A version of PROSAIL that uses transformed parameters to quasi-linearise the model. See http://dx.doi.org/10.1016/j.rse.2011.12.027""" # Define the constants slai = -2.0 skab = -100.0 skar = -100.0 skw = -1./50. skm = -1./100. # Transform the parameters to real units xlai = slai * np.log ( lai ) xkab = skab * np.log ( cab ) xkar = skar * np.log ( car ) xkw = skw * np.log ( cw ) xdm = skm * np.log ( cm ) # Run the PROSAIL model retval = run_prosail ( N, xkab, xkar, cbrown, xkw, xdm, xlai, \ lidfa, lidfb,bsoil, psoil, hspot, tts, tto, psi ,lidfType) return retval
def call_prosail(n, cab, car, ant, cbrown, cw, cm, lai, lidf, rsoil, psoil, hspot, sza, vza, vaa): """Helper function""" r = prosail.run_prosail(n, cab, car, cbrown, cw, cm, lai, lidf, hspot, sza, vza, vaa, ant=ant, rsoil=rsoil, psoil=psoil, prospect_version="D") rpass = np.isfinite(r) x = np.arange(400, 2501) ri = np.interp(x, x[rpass], r[rpass]) return ri
def test_rddt_prosail5(datadir): fname = datadir("REFL_CAN.txt") w, resv, rdot, rsot, rddt, rsdt = np.loadtxt(fname, unpack=True) rr = prosail.run_prosail( 1.5, 40.0, 8.0, 0.0, 0.01, 0.009, 3.0, -0.35, 0.01, 30.0, 10.0, 0.0, typelidf=1, lidfb=-0.15, rsoil=1.0, psoil=1.0, factor="BHR", ) assert np.allclose(rddt, rr, atol=0.01)
import prosail import numpy as np import matplotlib.pyplot as plt from prosail import run_prosail rr = run_prosail(1.5, 40., 8., 0.0, 0.01, 0.009, 3., -0.35, 0.01, 30., 10., 0., typelidf=1, lidfb=-0.15, rsoil=1., psoil=1., factor="SDR") plt.plot(np.arange(400, 2501), rr, 'r-') plt.show()
def do_fwd_model ( x, sza, vza, raa ): x = inverse_transform ( x ) ################# surface refl with prosail ##################### surf_refl = prosail.run_prosail(x[0], x[1], x[2], x[3], \ x[4], x[5], x[6], x[7], 0, x[8], x[9], 0.01, sza, vza, raa, 2 ) return surf_refl
def create_observations2 ( state, parameter_grid, latitude, longitude, the_time="10:30",\ b_min = np.array( [ 620., 841, 459, 545, 1230, 1628, 2105] ), \ b_max = np.array( [ 670., 876, 479, 565, 1250, 1652, 2155] ), \ every=5, prop=0.4, WINDOW=3, noise_scalar=1, vza_var=7., emu_dir="./"): """This function creates the observations for a given temporal evolution of parameters, loation, and bands. By default, we take only MODIS bands. The function does a number of other things: 1.- Calculate missing observations due to simulated cloud 2.- Add noise TODO: There's a problem with pyephem, gives silly solar altitudes!!!""" wv = np.arange ( 400, 2501 ) n_bands = b_min.shape[0] band_pass = np.zeros(( n_bands,2101), dtype=np.bool) bw = np.zeros( n_bands ) bh = np.zeros( n_bands ) for i in xrange( n_bands ): band_pass[i,:] = np.logical_and ( wv >= b_min[i], \ wv <= b_max[i] ) bw[i] = b_max[i] - b_min[i] bh[i] = ( b_max[i] + b_min[i] )/2. import ephem o = ephem.Observer() o.lat, o.long, o.date = latitude, longitude, "2011/1/1 %s" % the_time dd = o.date t = np.arange ( np.random.randint(1,every), 366 ) obs_doys = np.array ( [ i for i in t if i % every == 0 ] ) #prop = 0.4 #WINDOW = 3 weightings = np.repeat(1.0, WINDOW) / WINDOW xx = np.convolve(np.random.rand(len(t)*100),weightings,'valid')[WINDOW:WINDOW+len(t)] maxx = sorted(xx)[:int(len(xx)*prop)] mask = np.in1d(xx,maxx) doys_nocloud = t[mask] x = np.in1d ( obs_doys, doys_nocloud ) obs_doys = obs_doys[x] vza = np.zeros_like ( obs_doys, dtype=np.float) sza = np.zeros_like ( obs_doys, dtype=np.float) raa = np.zeros_like ( obs_doys, dtype=np.float) rho = np.zeros (( len(bw), obs_doys.shape[0] )) sigma_obs = (0.05-0.01)*(bh-bh.min())/(bh.max()-bh.min()) sigma_obs += 0.01 sigma_obs = sigma_obs * noise_scalar S = np.array([22, 37, 52, 70]) for i,doy in enumerate(obs_doys): j = doy - 1 # location in parameter_grid... vza[i] = np.random.rand(1)*vza_var # 15 degs o.date = dd + doy sun = ephem.Sun ( o ) sza[i] = 90. - float(sun.alt )*180./np.pi ##sza[i] = S[np.argmin ( np.abs ( xx-S))] ##sza[i] = 37 vaa = np.random.rand(1)*360. saa = np.random.rand(1)*360. raa[i] = 0.0#vaa - saa p = np.r_[parameter_grid[:8,j],0,parameter_grid[8:, j], 0.01,sza[i], vza[i], raa[i], 2 ] r = fixnan( np.atleast_2d ( prosail.run_prosail ( *p )) ).squeeze() rho[:, i] = np.array ( [r[ band_pass[ii,:]].sum()/bw[ii] \ for ii in xrange(n_bands) ] ) rho[:, i] = np.clip (rho[:, i] + np.random.randn ( n_bands )*sigma_obs, 1e-4, 0.999) srza = float(int(sza[i]) - (int(sza[i])%5)) vrza = float(int(vza[i]) - (int(vza[i])%5)) emulator_name = os.path.join ( emu_dir, "%03.1f_%03.1f_%03.1f_prosail.npz" % ( srza, vrza, raa[i] ) ) if not os.path.exists ( emulator_name ): print "Creating emulator for %s" % emulator_name gp = create_prosail_emulators ( sza, vza, raa ) gp.dump_emulator ( emulator_name ) return obs_doys, vza, sza, raa, rho, sigma_obs
def gen_lut(self, inv_mapping_table, inv_table, landcover_config_path=None, prosail_config_path=None, soil_path=None): """ Generates the lookup table and stores it in the DB must be run seperately from the inversion part Parameters ---------- inv_mapping_table : String name of the table storing the inversion mapping required for performing the inversion inv_table : String Name of the table the lookup-table should be written to (<schema.table>) landcover_config_path : String file-path to landcover config file (opt.; per default the OBIA4RTM delivered file will be used) prosail_config_path : String file-path to landcover config file (opt.; per default the OBIA4RTM delivered file will be used) soil_path : String file-path to file with soil reflectance values (opt.; per default the OBIA4RTM delivered file will be used) Returns: -------- None """ # get scene metadata first self.get_scene_metadata() # basic setup first # get S2 sensor-response function resampler = get_resampler(self.conn, self.cursor, self.__sensor, self.__logger) # params that could be inverted list_of_params = ['n', 'cab', 'car', 'cbrown', 'cw', 'cm', 'lai', 'lidfa', 'lidfb', 'rsoil', 'psoil', 'hspot', 'typelidf'] # firstly, create the LUT from the params config file for the # defined land cover classes if prosail_config_path is None: prosail_config = self.set_ProSAIL_config() else: prosail_config = self.set_ProSAIL_config(prosail_config_path) if landcover_config_path is None: landcover_config = self.set_landcover_config() else: landcover_config = self.set_landcover_config(landcover_config_path) # default soil-spectra -> use soil_reflectance from ProSAIL package if soil_path is None: soils = self.set_soilrefl() else: soils = self.set_soilrefl(soil_path) # read in the landcover class information and the corresponding # prosail parameter setup params_container = read_params_per_class(prosail_config, landcover_config, self.__logger) # extract the land cover classes lc_keys = list(params_container.keys()) # loop over the land cover classes and generate the LUT per class for lc in lc_keys: # extract the land cover code and semantics lc_code = lc[0] # code lc_sema = lc[1] # meaning # get the ProSAIL parameters # if a land cover class is not found skip try: params = params_container.get(lc) except (ValueError, KeyError): self.__logger.warning("Land cover class '{}' specified in config "\ "file but not found in ProSAIL config - " " skipping".format(lc_code)) continue param_lut = lut.lookup_table() param_lut.generate_param_lut(params) print("INFO: Start to generate ProSAIL-LUT for class '{0}' with "\ "{1} simulations ('{2}')\n".format( lc_sema, param_lut.lut_size, self.scene_id)) params_inv = dict() for ii in range(param_lut.to_be_inv[0].shape[0]): params_inv[str(ii)] = list_of_params[param_lut.to_be_inv[0][ii]] # convert to json params_inv_json = json.dumps(params_inv) # write the metadata into the inversion_mapping table insert = "INSERT INTO {0} (acquisition_date, " \ "params_to_be_inverted, landuse, sensor, scene_id) " \ "VALUES('{1}', '{2}', {3}, '{4}', '{5}') "\ "ON CONFLICT(scene_id, landuse) DO NOTHING;".format( inv_mapping_table, self.acquisition_date, params_inv_json, lc_code, self.__sensor, self.scene_id) try: self.cursor.execute(insert) self.conn.commit() except DatabaseError: self.__logger.error("Failed to insert metadata of inversion process!", exc_info=True) close_logger(self.__logger) sys.exit(error_message) # loop over the parameters stored in the LUT and generate the # according synthetic spectra for ii in range(param_lut.lut_size): # run ProSAIL for each combination in the LUT try: n = param_lut.lut[0,ii] cab = param_lut.lut[1,ii] car = param_lut.lut[2,ii] cbrown = param_lut.lut[3,ii] cw = param_lut.lut[4,ii] cm = param_lut.lut[5,ii] lai = param_lut.lut[6,ii] lidfa = param_lut.lut[7,ii] lidfb = param_lut.lut[8,ii] rsoil = param_lut.lut[9,ii] psoil = param_lut.lut[10,ii] hspot = param_lut.lut[11,ii] typelidf = param_lut.lut[12,ii] except IndexError: self.__logger.error("No data available for land cover class "\ "'{}'".format(lc_code)) close_logger(self.__logger) return # run prosail in forward mode -> resulting spectrum is from # 400 to 2500 nm in 1nm steps # use Python ProSAIL bindings spectrum = prosail.run_prosail(n, cab, car, cbrown, cw, cm, lai, lidfa, hspot, self.__tts, self.__tto, self.__psi, ant=0.0, alpha=40., prospect_version="5", typelidf=typelidf, lidfb=lidfb, rsoil0=soils[:,0], rsoil=rsoil, psoil=psoil, factor="SDR") # resample to SRF of sensor # perform resampling from 1nm to S2-bands sensor_spectrum = resampler(spectrum) # convert to % reflectance sensor_spectrum *= 100. # store the results in DB insert_statement = "INSERT INTO {0} (id, n, cab, car, cbrown, "\ "cw, cm, lai, lidfa, lidfb, rsoil, psoil, "\ "hspot, tts, tto, psi, typelidf, "\ "b2, b3, b4, b5, b6, b7, b8a, b11, b12, "\ "acquisition_date, landuse, scene_id) "\ "VALUES ({1}, {2}, {3}, {4}, {5}, {6}, {7}, "\ "{8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, {17}, " \ "{18}, {19}, {20}, {21}, {22}, {23}, {24}, {25}, {26}, '{27}', " \ "{28}, '{29}') ON CONFLICT (id, scene_id, landuse) "\ "DO NOTHING;".format( inv_table, ii, np.round(n, 4), np.round(cab, 4), np.round(car, 4), np.round(cbrown, 4), np.round(cw, 4), np.round(cm, 4), np.round(lai, 4), np.round(lidfa, 4), np.round(lidfb, 4), np.round(rsoil, 4), np.round(psoil, 4), np.round(hspot, 4), np.round(self.__tts, 4), np.round(self.__tto, 4), np.round(self.__psi, 4), np.round(typelidf, 2), np.round(sensor_spectrum[0], 4), np.round(sensor_spectrum[1], 4), np.round(sensor_spectrum[2], 4), np.round(sensor_spectrum[3], 4), np.round(sensor_spectrum[4], 4), np.round(sensor_spectrum[5], 4), np.round(sensor_spectrum[6], 4), np.round(sensor_spectrum[7], 4), np.round(sensor_spectrum[8], 4), self.acquisition_date, lc_code, self.scene_id ) try: self.cursor.execute(insert_statement) self.conn.commit() except DatabaseError: self.__logger.error("INSERT of synthetic spectra failed!", exc_info=True) continue