scopeinpython.scope
The end-to-end SCOPE simulation wrapper: one LUT input row in, leaf optics
(Fluspect-Cx) → soil (BSM or the bundled reference spectra) → optical BRDF
(run_rtmo) → thermal energy balance (ebal) → fluorescence
(rtmf, optional) → zeaxanthin (rtmz, optional) out. Direct,
partial port of SCOPEinR::get.SCOPE.
Note
Verified against a real, unmodified SCOPEinR::get.SCOPE() call
using the R package’s own bundled example inputs
(SCOPEinR/inst/input/LUT_input.csv + setoptions.csv) – see
python/scratch/scratch_scope_export.R. The exact-formula outputs
(LAIsunlit/Pnsun_Cab/Pnsha_Cab/Pntot_Cab, the TOC
reflectance spectrum) match to floating-point noise; the
iterative-convergence outputs (temperatures, energy-balance totals)
match at the same ~1-2% tolerance established for scopeinpython.ebal.ebal()
itself, for the same reason (small floating-point divergence compounding
over ~7-10 nonlinear iterations along a per-layer-loop biochemistry
path – not a functional bug).
See the module docstring below, and Known limitations, for the full
list of options.SCOPE branches this wrapper does not expose at all
(directional BRDF, RTMt_planck, multi-layer mSCOPE, time-series
mode, angle-file LIDF, measurement-file/MODTRAN irradiance) and which
canopy-level “derived data products” beyond ScopeResult
aren’t computed yet.
End-to-end SCOPE simulation wrapper: leaf optics -> soil -> optical BRDF -> thermal energy balance -> [fluorescence] -> [zeaxanthin], driven by a single LUT input row.
Direct, partial port of SCOPEinR::get.SCOPE (SCOPEinR/R/get.SCOPE.R),
“SCOPE-lite” only (matches every other module in this port). Ties together
fluspect_mscope(),
get_bsm() (or the bundled reference soil spectra,
SCOPEinR’s own default), run_rtmo(),
ebal(), rtmf() and
rtmz().
Not ported (same scope as documented for their own modules, or newly scoped out here):
get.SCOPE.parallel– R’s parallel-backend variant (foreach/doParallel) of the same per-row loop below. Not a separate function here: parallelizeget_scope()yourself (multiprocessing,joblib, a plain loop, …) – R’s parallel backend has no 1:1 Python equivalent worth porting.options.calc_directional(full BRDF over many angles,get.brdf),options.calc_spectrum_planck(RTMt_planck.R, the per-wavelength thermal RTM),options.mSCOPEwith more than one profile layer (run_rtmoonly ever sees one leaf-optics spectrum per canopy layer – see its own docstring),options.simulationtime-series mode,options.LIDFfrom an angle file (only LIDFa/LIDFb-derived LIDF is supported), andoptions.irradiancemeasurement-file / MODTRAN-atmosphere-file modes (only the bundled default spectrum, or a caller-suppliedEsun_/Esky_) – none of these are exposed as parameters here at all, matching how e.g.scopeinpython.rtmt_sb.rtmt_sb()simply omits its own unportedobsdirbranch rather than accepting and silently ignoring the argument.The canopy-level “derived data products” section of
get.SCOPE.Rbeyond what’s listed onScopeResult–Pnsun_Car/Rnsun_Cab/Rnsun_PAR/LST/etc all need net-radiation or radiance breakdowns (Rnuc_Car, the directional-brightness-temperatureLote, …) thatscopeinpython.rtmo.net_radiation_lite()andscopeinpython.rtmt_sb.rtmt_sb()don’t compute yet – see their own module docstrings for exactly what’s missing and why.options.soil_heat_method0/1 andoptions.calc_rss_rbs == 1(recomputingrss/rbsfromSMC/LAIviacalc_rssrbs– not ported) –get_scope()always uses the LUT’s ownrss/rbscolumns directly (R’scalc.rss_rbs == 0default) and the simpleG = 0.35*Rnsoil-heat method (R’ssoil_heat_method == 2default), matchingscopeinpython.ebal.ebal()’s own scope.
- scopeinpython.scope.TDP_DEFAULT: dict = {'Q10': 2.0, 'delHaJ': 43540.0, 'delHaKc': 79430.0, 'delHaKo': 36380.0, 'delHaP': 53100.0, 'delHaR': 46390.0, 'delHaT': 37830.0, 'delHaV': 65330.0, 'delHdJ': 152040.0, 'delHdP': 150650.0, 'delHdR': 150650.0, 'delHdV': 149250.0, 'delSJ': 495.0, 'delSP': 490.0, 'delSR': 490.0, 'delSV': 485.0, 's1': 0.3, 's2': 313.15, 's3': 0.2, 's4': 288.15, 's5': 1.3, 's6': 328.15}
Fixed temperature-response coefficients for
get_biochemical()(leafbio.TDP). Direct port ofSCOPEinR::define_temp_response_biochem– always these exact constants, nothing here is derived from caller input.
- scopeinpython.scope.get_zo_and_d(CR, CSSOIL, CD1, Psicor, LAI, hc, kappa)[source]
Roughness length for momentum (
zom) and zero-plane displacement height (d), from vegetation height and LAI (Verhoef, McNaughton & Jacobs 1997). Direct port ofSCOPEinR::get.zo_and_d(against the fixed R source: an undefined-variable bug in its degenerate-canopy branch,zo_and_d$d <- dwith nodever assigned on that branch – errors, or silently picks up a staledleft over from a previous call in the same R session – is fixed inSCOPEinR/R/zo_and_d.Rto the evidently-intendedd <- 0).- Returns:
(zom, d)
- Return type:
tuple[float, float]
- Parameters:
CR (float)
CSSOIL (float)
CD1 (float)
Psicor (float)
LAI (float)
hc (float)
kappa (float)
- class scopeinpython.scope.ScopeOptions(calc_fluor=True, calc_xanthophyllabs=True, apply_t_corr=True, use_monin_obukhov=True, use_bsm_soil=False, k_maxit=100, maxEBer=1.0)[source]
Bases:
objectSubset of R’s
options.SCOPEthis port actually implements (see module docstring for what isn’t exposed at all).- Parameters:
calc_fluor (bool)
calc_xanthophyllabs (bool)
apply_t_corr (bool)
use_monin_obukhov (bool)
use_bsm_soil (bool)
k_maxit (int)
maxEBer (float)
- calc_fluor: bool = True
- calc_xanthophyllabs: bool = True
- apply_t_corr: bool = True
- use_monin_obukhov: bool = True
- use_bsm_soil: bool = False
- k_maxit: int = 100
- maxEBer: float = 1.0
- class scopeinpython.scope.ScopeResult(rtmo: 'RTMoResult', ebal: 'EbalResult', rtmf: 'RTMfResult | None', rtmz: 'RTMzResult | None', nlayers: 'int', LAIsunlit: 'float', LAIshaded: 'float', Pnsun_Cab: 'float', Pnsha_Cab: 'float', Pntot_Cab: 'float', Ja: 'float', PNPQ: 'float', fqe: 'float | None')[source]
Bases:
object- Parameters:
rtmo (RTMoResult)
ebal (EbalResult)
rtmf (RTMfResult | None)
rtmz (RTMzResult | None)
nlayers (int)
LAIsunlit (float)
LAIshaded (float)
Pnsun_Cab (float)
Pnsha_Cab (float)
Pntot_Cab (float)
Ja (float)
PNPQ (float)
fqe (float | None)
- rtmo: RTMoResult
- ebal: EbalResult
- rtmf: RTMfResult | None
- rtmz: RTMzResult | None
- nlayers: int
- LAIsunlit: float
- LAIshaded: float
- Pnsun_Cab: float
- Pnsha_Cab: float
- Pntot_Cab: float
- Ja: float
- PNPQ: float
- fqe: float | None
- scopeinpython.scope.get_scope(lut, options=None, spectral=None, Esun_=None, Esky_=None, rsoil=None)[source]
Run one full SCOPE simulation for a single LUT row. Direct port of the per-row body of
SCOPEinR::get.SCOPE(see module docstring for exact scope).- Parameters:
lut (Mapping) – One row of SCOPE’s
LUT_input.csvlayout (adictorpandas.Serieswith at least the columns used below – seeSCOPEinR/inst/input/LUT_input.csvfor the full reference set).options (ScopeOptions)
spectral (SpectralConfig, optional) – Defaults to
scopeinpython.spectral.get_spectra_scope().Esun (array_like, shape (2162,), optional) – Top-of-atmosphere direct/diffuse irradiance, on
spectral.wlS. Defaults to SCOPE’s own bundled example spectrum (R’soptions.irradiance == 0path).Esky (array_like, shape (2162,), optional) – Top-of-atmosphere direct/diffuse irradiance, on
spectral.wlS. Defaults to SCOPE’s own bundled example spectrum (R’soptions.irradiance == 0path).rsoil (array_like, shape (2001,), optional) – Soil reflectance, 400-2400nm. If omitted, computed from
options.use_bsm_soiland the LUT’s soil columns.Esun_ (ndarray | None)
Esky_ (ndarray | None)
- Return type: