def test_transmittance_prospect5(datadir): # runs prospect and compares to online prospect run fname = datadir("prospect5_spectrum.txt") w, true_refl, true_trans = np.loadtxt(fname, unpack=True) w, refl, trans = prosail.run_prospect(2.1, 40, 10., 0.1, 0.015, 0.009, prospect_version="5") assert np.allclose( true_trans, trans, atol=1e-4)
def call_prospect_5(n, cab, car, cbrown, cw, cm): """A wrapper for PROSPECT that does away with some numerical instabilities by interpolating over spectrally.""" x, r, t = prosail.run_prospect(n, cab, car, cbrown, cw, cm, prospect_version="5") rpass = np.isfinite(r) tpass = np.isfinite(t) ri = np.interp(x, x[rpass], r[rpass]) ti = np.interp(x, x[tpass], t[tpass]) return np.c_[ri, ti]
def test_reflectance_prospectpro(datadir): fname = datadir("prospect_pro_test.txt") w, refl_mtlab, trans_mtlab = np.loadtxt(fname, unpack=True) w, refl, trans = prosail.run_prospect( n=1.2, cab=30, car=10.0, cbrown=0.0, cw=0.015, cm=0.009, ant=1.0, prot=0.001, cbc=0.009, prospect_version="PRO", ) assert np.allclose(refl_mtlab, refl, atol=1.0e-4)
def test_transmittance_prospectpro(datadir): fname = datadir("prospect_pro_test.txt") w, refl_mtlab, trans_mtlab = np.loadtxt(fname, unpack=True) w, refl, trans = prosail.run_prospect( 1.2, 30, 10.0, 0.0, 0.015, 0.009, ant=1.0, prot=0.001, cbc=0.009, prospect_version="PRO", ) assert np.allclose(trans_mtlab, trans, atol=1.0e-4)
def fwd_model(x, rho_std, leaf, do_plot=True): wv, rho_pred, _ = prosail.run_prospect(x[0], x[1], x[2], x[3], x[4], x[5], ant=x[6]) rho_noise = np.random.randn(len(wv)) * rho_std rho_meas = rho_pred + rho_noise rho_std *= np.ones(2101) if do_plot: plot_spectra(rho_pred, rho_std, leaf) return rho_pred
def prospect_lklhood(x, wl, rho, rho_unc): """Calculates the log-likelihood of leaf reflectance measurements assuming Gaussian additive noise. Can either use reflectance or transmittance or both.""" wv, rho_pred, _ = prosail.run_prospect(x[0], x[1], x[2], x[3], x[4], x[5], ant=x[6]) rho_unc_ndim = rho_unc.ndim if rho_unc_ndim == 1: cov_obs_rho_inv = 1.0 / (rho_unc * rho_unc) elif rho_unc_ndim == 2: cov_obs_rho_inv = 1. / rho_unc.diagonal() refl_lklhood = np.sum(0.5 * cov_obs_rho_inv * (rho_pred[([150, 260, 335, 390])] - rho)**2) return refl_lklhood
def leaf_ps5(n=1.2, cab=30.0, car=10.0, cbr=1.0, ewt=0.015, lma=0.009): """Run PROSPECT-5 from Python package ``prosail`` (source `on GitHub <https://github.com/jgomezdans/prosail>`_) to generate leaf spectra. Default values are the same as those on the `online PROSPECT page <http://opticleaf.ipgp.fr/index.php?page=prospect>`_. Parameters ---------- n : float Leaf structure parameter (number of effective layers of leaf?; dimensionless). Typical range: [0.8, 3.0]. cab : float Chlorophyll a+b concentration (μg cm-2). Typical range: [0, 100]. car : float Carotenoid concentration (μg cm-2). Typical range: [0, 25]. cbr : float Brown pigment fraction/factor in [0, 1]. ewt : float Equivalent leaf water thickness (cm). Typical range: [0, 0.05]. lma : float Leaf dry mass per unit area (g cm-2). Typical range: [0, 0.02]. Returns ------- xr.Dataset Dataset of the leaf reflectance and transmittance spectra, and PROSPECT input parameters as dimensionless variables. Notes ----- Quoted typical ranges are based on the PROSPECT page and Python PROSAIL readme linked above. """ import prosail wl_nm, r, t = prosail.run_prospect(n, cab, car, cbr, ewt, lma, prospect_version="5") wl = wl_nm / 1000 # nm -> um attrs = {} ds = xr.Dataset( coords=_wl_coord_dict(wl), data_vars={ "rl": _tup("leaf_r", r), "tl": _tup("leaf_t", t), "n": ((), n, { "long_name": "Leaf structure parameter", "units": "" }), "cab": ((), cab, { "long_name": "Chlorophyll a+b", "units": "μg cm-2" }), "car": ((), car, { "long_name": "Carotenoid", "units": "μg cm-2" }), "cbr": ((), cbr, { "long_name": "Brown pigment", "units": "" }), "ewt": ((), ewt, { "long_name": "Equivalent leaf water thickness", "units": "cm" }), "lma": ((), lma, { "long_name": "Leaf dry mass density", "units": "g cm-2" }), }, attrs=attrs, ) return ds
def test_transmittance_prospectd(datadir): fname = datadir("prospect_d_test.mat") trans_mtlab = loadmat(fname)['LRT'][:,2] w, refl, trans = prosail.run_prospect(1.2, 30, 10., 0.0, 0.015, 0.009, ant=1., prospect_version="D") assert np.allclose(trans_mtlab, trans, atol=1.e-4)
def run_prosail(n, cab, car, cbrown, cw, cm, lai, lidfa, hspot, tts, tto, psi, ant=0.0, alpha=40., prospect_version="5", typelidf=2, lidfb=0., factor="SDR", rsoil0=None, rsoil=None, psoil=None, soil_spectrum1=None, soil_spectrum2=None): """Run the PROSPECT_5B and SAILh radiative transfer models. The soil model is a linear mixture model, where two spectra are combined together as rho_soil = rsoil*(psoil*soil_spectrum1+(1-psoil)*soil_spectrum2) By default, ``soil_spectrum1`` is a dry soil, and ``soil_spectrum2`` is a wet soil, so in that case, ``psoil`` is a surface soil moisture parameter. ``rsoil`` is a soil brightness term. You can provide one or the two soil spectra if you want. The soil spectra must be defined between 400 and 2500 nm with 1nm spacing. Parameters ---------- n: float Leaf layers cab: float leaf chlorophyll concentration car: float leaf carotenoid concentration cbrown: float senescent pigment cw: float equivalent leaf water cm: float leaf dry matter lai: float leaf area index lidfa: float a parameter for leaf angle distribution. If ``typliedf``=2, average leaf inclination angle. tts: float Solar zenith angle tto: float Sensor zenith angle psi: float Relative sensor-solar azimuth angle ( saa - vaa ) ant: float leaf anthocyanin concentration (default set to 0) alpha: float The alpha angle (in degrees) used in the surface scattering calculations. By default it's set to 40 degrees. prospect_version: str Which PROSPECT version to use. We have "5" and "D" typelidf: int, optional The type of leaf angle distribution function to use. By default, is set to 2. lidfb: float, optional b parameter for leaf angle distribution. If ``typelidf``=2, ignored factor: str, optional What reflectance factor to return: * "SDR": directional reflectance factor (default) * "BHR": bi-hemispherical r. f. * "DHR": Directional-Hemispherical r. f. (directional illumination) * "HDR": Hemispherical-Directional r. f. (directional view) * "ALL": All of them rsoil0: float, optional The soil reflectance spectrum rsoil: float, optional Soil scalar 1 (brightness) psoil: float, optional Soil scalar 2 (moisture) soil_spectrum1: 2101-element array First component of the soil spectrum soil_spectrum2: 2101-element array Second component of the soil spectrum Returns -------- A reflectance factor between 400 and 2500 nm """ factor = factor.upper() if factor not in ["SDR", "BHR", "DHR", "HDR", "ALL"]: raise ValueError("'factor' must be one of SDR, BHR, DHR, HDR or ALL") if soil_spectrum1 is not None: assert (len(soil_spectrum1) == 2101) else: soil_spectrum1 = prosail.spectral_lib.soil.rsoil1 if soil_spectrum2 is not None: assert (len(soil_spectrum1) == 2101) else: soil_spectrum2 = prosail.spectral_lib.soil.rsoil2 if rsoil0 is None: if (rsoil is None) or (psoil is None): raise ValueError("If rsoil0 isn't define, then rsoil and psoil" + \ " need to be defined!") rsoil0 = rsoil * (psoil * soil_spectrum1 + (1. - psoil) * soil_spectrum2) wv, refl, trans = run_prospect(n, cab, car, cbrown, cw, cm, ant=ant, prospect_version=prospect_version, alpha=alpha) [ tss, too, tsstoo, rdd, tdd, rsd, tsd, rdo, tdo, rso, rsos, rsod, rddt, rsdt, rdot, rsodt, rsost, rsot, gammasdf, gammasdb, gammaso ] = foursail(refl, trans, lidfa, lidfb, typelidf, lai, hspot, tts, tto, psi, rsoil0) if factor == "SDR": return rsot elif factor == "BHR": return rddt elif factor == "DHR": return rsdt elif factor == "HDR": return rdot elif factor == "ALL": return [rsot, rddt, rsdt, rdot]