00. Configuring SCOPE: options, defaults, and common errors
t00-scope-options.RmdEvery SCOPEinR tutorial from here on opens with the same line:
scope_options <- read.table(system.file("input", "setoptions.csv", package = "SCOPEinR"),
header = TRUE, sep = ",")scope_options is a 17-row switchboard controlling which
physics SCOPE actually runs – not tuning parameters (those live in the
LUT), but structural choices: which sub-models execute, which files get
read, which approximations apply. This tutorial is a configuration and
troubleshooting reference, not a lab report: every option’s default,
what changing it does, when you’d actually want to, and – for the ones
this port doesn’t fully support yet – exactly what error you’ll see and
what to do about it.
1. What should I normally use?
The shipped defaults, unmodified, work:
scope_options <- read.table(system.file("input", "setoptions.csv", package = "SCOPEinR"),
header = TRUE, sep = ",")
knitr::kable(scope_options)| Order | Options | Value | Info |
|---|---|---|---|
| 1 | lite | 1 | Value 1 indicates the SCOPE will use the lite SCOPEversion |
| 2 | calc_fluorescence | 1 | Value 1 indicates that SCOPE will calculate thechlorophyll fluorescence in observation direction |
| 3 | calc_spectrum_planck | 1 | Value 1 SCOPE will calculate the spectrum of thermal radiation |
| 4 | calc_xanthophyllabs | 1 | Value 1 indicates the SCOPE includes simulation of reflectance dependence on de-epoxydation state |
| 5 | soilspectrum | 0 | Value 0 use a soil reflectance file and Value 1 SCOPE will calculate the soil spectrum using BSM model |
| 6 | Fluorescence_model | 0 | Value 0 empirical with sustained NPQ from Flexas data and Value 1 empirical with sigmoid for Kn and Value 2 uses Magnani 2012 model |
| 7 | applTcorr | 1 | Value 1 indicates that SCOPE will correct the Vcmax and rate constants for temperature in biochemical.m |
| 8 | verify | 1 | Value 1 indicates that SCOPE will check with field data |
| 9 | mSCOPE | 0 | Value 1 indicates that SCOPE wil use the mSCOPE considering vertical variations in the vegetation canopies |
| 10 | simulation | 0 | Value 0 the SCOPE will execute by individual runs based on LUT table and Value 1 for time series (uses text files with meteo input as time series) |
| 11 | calc_directional | 0 | Value 1 calculate full BRDF for many angles |
| 12 | calc_vert_profiles | 0 | Value 1 indicates that SCOPE will estimate vertical profiles |
| 13 | soil_heat_method | 2 | Value 0 will estimate the GAM parameters with Soil_Inertia0(lambdas) and Value 1 will estimate the GAM with Soil_Inertia1(SMC) and Value 2 will estimate G by 0.35*Rn where always in no TS |
| 14 | calc_rss_rbs | 0 | Value 0 is fixed and Value 1 is calculated |
| 15 | MoninObukhov | 1 | Value 1 indicates that SCOPE wil use the MoninObukhov correction |
| 16 | LIDF | 0 | Value 1 SCOPE wil estimate LIDF from angles file and Value 0 will use LIDFa and LIDFb from LUT table for estimating LIDF |
| 17 | irradiance | 0 | Value 0 use a the irradiance file from SCOPE model Value 1 use irradiance measurements WithE and Value 2 use irradiance from MODTRAN atmospheric.file |
2. The options at a glance
Important: these are not generic on/off flags. Most
are 0/1 toggles, but soilspectrum selects between two
different soil data sources, Fluorescence_model
and soil_heat_method select between three different
methods each, and irradiance selects between three
different irradiance sources – in every one of those cases, “0”
and “1” (and “2”) name specific alternatives, not a universal
false/true. Check the “Alternatives” column below before assuming a
value’s meaning.
| Option | Default | Alternatives | What does it do? | When should I change it? | Status |
|---|---|---|---|---|---|
lite |
1 | 0 | SCOPE-lite (per-layer) vs. full (per-layer-and-leaf-angle) integration | Use 0 when you need the full angular resolution; 1 is faster | ✅ Both work |
calc_fluorescence |
1 | 0 | Simulate chlorophyll fluorescence (SIF) | Set 0 if you only need reflectance and want a faster run | ✅ Both work |
calc_spectrum_planck |
1 | 0 | Full per-wavelength Planck thermal spectrum vs. simplified thermal | Usually keep default | ✅ Both work |
calc_xanthophyllabs |
1 | 0 | Include xanthophyll/PRI reflectance effects | Disable (0) if not needed, small speedup | ✅ Both work |
soilspectrum |
0 | 1 | Soil reflectance from a file vs. computed by BSM | Use 1 to simulate soil physically (brightness/moisture) rather than from a fixed file | ✅ Both work |
Fluorescence_model |
0 | 1, 2 | Which NPQ/fluorescence-yield submodel | Use 2 for the Magnani 2012 model; 1 has no separate implementation yet | ✅ 0 and 2 work; ⚠️ 1 uses the same model as 0 |
applTcorr |
1 | 0 | Temperature-correct Vcmax/biochemical rate constants | Normally keep on | ✅ Both work |
verify |
1 | 0 | Whether SCOPE checks output against field data | Application-dependent | ✅ No effect on the simulation itself (by design – a validation step, not a physics option) |
mSCOPE |
0 | 1 | Vertically heterogeneous canopy (multiple leaf-property layers) | Only for mSCOPE-style applications | ✅ Works |
simulation |
0 | 1 | One run per LUT row vs. time-series mode | Only if you have meteo time-series input files, not a LUT | ❌ Needs a different input format this page doesn’t provide (see below) |
calc_directional |
0 | 1 | Full BRDF over many view angles | Use 1 for directional/BRDF studies | ✅ Both work |
calc_vert_profiles |
0 | 1 | Return vertical (per-layer) canopy profiles | When per-layer profiles are needed | ✅ Works |
soil_heat_method |
2 | 0, 1 | How soil heat flux (G) is estimated | Application-dependent | ✅ All three work |
calc_rss_rbs |
0 | 1 | Fixed vs. computed soil surface/boundary-layer resistances | Use 1 to compute from conditions instead of fixing from the LUT | ✅ Works |
MoninObukhov |
1 | 0 | Atmospheric-stability correction | Application-dependent | ✅ Both work |
LIDF |
0 | 1 | Leaf angle distribution from LUT
(LIDFa/LIDFb) vs. an external angles file |
Use 1 only if you have a real angles file | ✅ Both run and produce different output |
irradiance |
0 | 1, 2 | Irradiance source: SCOPE’s own file, user measurements (“WithE”), or a MODTRAN atmospheric file | 1 if you have real measured irradiance; 2 for a real MODTRAN atmosphere file | ✅ 0 and 2 work; ⚠️ 1 works, see the note below |
3. What can I change for my application?
- Need SIF output?
calc_fluorescence = 1(the default). - Need the full angular (non-lite) energy balance and thermal
emission?
lite = 0. - Need per-layer vertical profiles of net radiation?
calc_vert_profiles = 1. - Need the Magnani 2012 fluorescence/NPQ model instead of the default
empirical fit?
Fluorescence_model = 2. - Need a physically-simulated (BSM) soil instead of a fixed file?
soilspectrum = 1. - Need multi-angular BRDF?
calc_directional = 1. - Have real measured irradiance instead of SCOPE’s bundled default?
irradiance = 1(see the caution in Section 5) or a real MODTRAN atmosphere file (irradiance = 2). - Want a faster run and don’t need fluorescence or PRI effects?
calc_fluorescence = 0,calc_xanthophyllabs = 0. - Everything else: leave at the shipped default – either it has no
effect worth changing (
verify,applTcorrrarely needs to move), or it needs different input this page doesn’t provide (simulation = 1, Section 5.3).
4. If it errors: troubleshooting
| Error you see | Likely cause | What to do |
|---|---|---|
non-numeric matrix extent |
simulation = 1 |
Needs time-series meteo input files, not a single LUT row – this page’s examples don’t provide that input (Section 5.3) |
Fluorescence_model = 1 doesn’t look different from the
default |
Fluorescence_model = 1 |
Expected: this port doesn’t have a separate “sigmoid Kn”
implementation, so it uses the same model as 0 (Section
5.4) |
Direct/diffuse irradiance (Esun_/Esky_)
look swapped |
irradiance = 1 |
Known caveat – see the note in Section 5.5 |
5. Per-option detail: everything not a plain “it works”
5.1 lite = 0 – Full SCOPE (13x36 angular
resolution)
Purpose: activates the full per-leaf-angle-class
(13x36xnl) integration instead of SCOPE-lite’s per-layer aggregation,
for the thermal-emission and net-radiation calculations. What to
expect: lite = 0 returns a physically sane result
– Actot = 6.76 umol/m2/s, close to but distinct from the
lite = 1 baseline (6.95), consistent with the full angular
integration being a more detailed (not wildly different) representation
of the same physics. Note for Python users:
scopeinpython (this package’s Python sibling) only
implements SCOPE-lite; the full per-leaf-angle branches aren’t ported
there.
5.2 calc_vert_profiles = 1 – Vertical canopy
profiles
Purpose: return per-layer (vertical) profiles of net
radiation/ photosynthesis instead of only canopy-integrated totals, in
both lite = 0 and lite = 1 mode. What
to expect: a real per-layer Pn1d profile (one
value per canopy layer, decreasing with depth as light attenuates
through the canopy), with Actot unchanged from the baseline
– this option only adds diagnostic profile output, it doesn’t change the
canopy-integrated flux.
5.3 simulation = 1 – Time-series mode
Purpose: run SCOPE driven by a time series of
meteorological observations (a sequence of dates/conditions) instead of
one LUT row per independent run. Current status in
SCOPEinR: needs input this page doesn’t provide.
Typical error: non-numeric matrix extent.
Why: this mode expects meteorological time-series input
files in a different structure than LUT_input.csv’s
one-row-per-run layout; the error is a direct consequence of feeding it
a single LUT row instead. What should I do? Keep
simulation = 0 unless you have real time-series meteo files
formatted for that mode. Is my input wrong? For this
tutorial’s LUT-based examples, yes – this option needs a fundamentally
different input, not a bug fix.
5.4 Fluorescence_model – which submodel each value
selects
-
Fluorescence_model = 0(default): the empirical (Flexas-fit) model. -
Fluorescence_model = 2: the Magnani et al. (2012) model (get.biochemical.MD12(), authored by Federico Magnani) – gives a numerically distinct result from the default (Actotdiffers meaningfully fromFluorescence_model = 0). -
Fluorescence_model = 1(documented as “sigmoid for Kn”): this port doesn’t have a separate implementation for this value, so it uses the same model asValue = 0. What should I do? TreatFluorescence_model = 1as equivalent to0for now.
5.5 irradiance – source selection, and a note on
irradiance = 1
irradiance = 0 (default): SCOPE’s own
bundled irradiance file.
irradiance = 2 (MODTRAN atmospheric
file): usable end-to-end, returning a physically sane result –
Actot = 7.11 umol/m2/s, distinct from but comparable to the
default (6.95), consistent with using a genuinely different
(MODTRAN-derived) irradiance spectrum. If you have a real MODTRAN
.atm file for your own site/date, drop it into
inst/input/radiationdata/ in place of the bundled example
(FLEX-S3_std.atm).
irradiance = 1 (user-supplied “WithE”
measurements): runs without error. Note: relative to
the default, the mean direct (Esun_) and diffuse
(Esky_) irradiance values come out swapped –
Esun_ matches the default’s Esky_ value and
vice versa. Confirming the correct column order requires a real
reference “WithE” measurement file to check against, which this package
doesn’t bundle. What should I do? Treat
irradiance = 1 output’s direct/diffuse split with caution –
the overall magnitude is not in question, only which of the two columns
is direct vs. diffuse.
5.6 mSCOPE = 1 – vertically heterogeneous canopy
Purpose: simulate a canopy with vertically varying
leaf properties (multiple biochemistry layers) instead of one uniform
layer, following the mSCOPE multi-layer
parameterization (3 layers, LAI fractions c(0.5, 1, 1.5)).
What to expect: mSCOPE = 1 runs and
produces real, substantially different canopy-optical output from the
single-layer default (189 fields differ).
5.7 calc_rss_rbs = 1 – computed soil resistances
Purpose: compute soil surface (rss) and
boundary-layer (rbs) resistances from conditions (soil
moisture, LAI) instead of using fixed values from the LUT. What
to expect: calc_rss_rbs = 1 runs and produces
real, substantially different energy-balance output from the
fixed-resistance default (121 fields differ).
What’s next
- Tutorial 01 – run one full simulation end to end with the (near-)default options from this tutorial.
-
Tutorial 02 – the soil and canopy BRDF machinery
soilspectrumfeeds into. -
Tutorial 04 – fluorescence in depth, including
where
calc_fluorescence/Fluorescence_modelplug in.
Appendix: how these options were verified
Everything above is backed by actually running
get.SCOPE() at each option’s documented alternative values
and diffing the result against a baseline, field by field – not read off
the Info column alone. This appendix has the actual
verification code, kept here rather than in the main teaching flow
above.
A structural diff helper
get.SCOPE()’s return value is a deeply nested list
(data.rad, data.fluxes,
data.canopy, … – see Tutorial 01).
flatten_scope() walks the whole nested result down to
scalars (summarizing longer numeric vectors by their mean and length),
and compare_runs() reports which fields appeared,
disappeared, or changed value beyond floating-point noise.
flatten_scope <- function(x, prefix = "") {
out <- list()
if (is.list(x)) {
nms <- names(x)
if (is.null(nms)) nms <- seq_along(x)
for (i in seq_along(x)) {
nm <- if (is.character(nms)) nms[i] else paste0("[[", nms[i], "]]")
key <- if (nzchar(prefix)) paste0(prefix, "$", nm) else nm
out <- c(out, flatten_scope(x[[i]], key))
}
} else if (is.numeric(x) || is.logical(x) || is.character(x)) {
if (length(x) == 1) {
out[[prefix]] <- x
} else if (length(x) > 1 && is.numeric(x)) {
out[[paste0(prefix, "[mean]")]] <- mean(x, na.rm = TRUE)
}
}
out
}
compare_runs <- function(base_flat, alt_flat, tol = 1e-6) {
added <- setdiff(names(alt_flat), names(base_flat))
removed <- setdiff(names(base_flat), names(alt_flat))
changed <- character(0)
for (nm in intersect(names(base_flat), names(alt_flat))) {
a <- base_flat[[nm]]; b <- alt_flat[[nm]]
if (is.numeric(a) && is.numeric(b)) {
if (is.na(a) != is.na(b) || (!is.na(a) && abs(a - b) > tol * max(1, abs(a)))) {
changed <- c(changed, nm)
}
} else if (!identical(a, b)) {
changed <- c(changed, nm)
}
}
list(added = added, removed = removed, changed = changed)
}Testing every option for real
One baseline run, then every option flipped to each of its other documented values, one option at a time, against the same LUT row. Runs that error are caught rather than allowed to fail the whole comparison – an error is itself a real, reportable result here.
lut <- read.table(system.file("input", "LUT_input.csv", package = "SCOPEinR"), header = TRUE, sep = ",")
run_scope <- function(opts) {
tryCatch({
invisible(capture.output(
res <- SCOPEinR::get.SCOPE(LUT = lut[1, ], options.SCOPE = opts,
optipar = SCOPEinR::optipar2021.Pro.CX,
leaf.model = "fluspect-CX", canopy.model = "fourSAIL",
get.outputs = "ALL", get.plots = FALSE)
))
list(ok = TRUE, res = res[[1]])
}, error = function(e) list(ok = FALSE, err = conditionMessage(e)))
}
base_run <- run_scope(scope_options)
base_flat <- flatten_scope(base_run$res)
# 'simulation' isn't included: value 1 fundamentally changes the input format
# (time-series meteo files instead of a LUT row), so it isn't a same-input
# toggle the way the other 16 options are -- not tested here for that reason,
# not because it errors.
alt_values <- list(
lite = 0, calc_spectrum_planck = 0, calc_xanthophyllabs = 0, soilspectrum = 1,
Fluorescence_model = c(1, 2), applTcorr = 0, verify = 0, mSCOPE = 1,
calc_directional = 1, calc_vert_profiles = 1, soil_heat_method = c(0, 1),
calc_rss_rbs = 1, MoninObukhov = 0, LIDF = 1, irradiance = c(1, 2),
calc_fluorescence = 0
)
results <- list()
for (opt in names(alt_values)) {
for (v in alt_values[[opt]]) {
opts <- scope_options
opts$Value[opts$Options == opt] <- v
r <- run_scope(opts)
if (r$ok) {
cmp <- compare_runs(base_flat, flatten_scope(r$res))
status <- "OK"
n_changed <- length(cmp$added) + length(cmp$removed) + length(cmp$changed)
headline <- if (n_changed == 0) "no measurable effect" else paste(n_changed, "fields differ")
} else {
status <- "ERROR"; n_changed <- NA; headline <- r$err
}
results[[length(results) + 1]] <- data.frame(
option = opt, value = v, status = status, n_changed = n_changed, headline = headline
)
}
}
results_df <- do.call(rbind, results)
knitr::kable(results_df, row.names = FALSE)| option | value | status | n_changed | headline |
|---|---|---|---|---|
| lite | 0 | OK | 146 | 146 fields differ |
| calc_spectrum_planck | 0 | OK | 8 | 8 fields differ |
| calc_xanthophyllabs | 0 | OK | 12 | 12 fields differ |
| soilspectrum | 1 | OK | 175 | 175 fields differ |
| Fluorescence_model | 1 | OK | 1 | 1 fields differ |
| Fluorescence_model | 2 | OK | 134 | 134 fields differ |
| applTcorr | 0 | OK | 119 | 119 fields differ |
| verify | 0 | OK | 1 | 1 fields differ |
| mSCOPE | 1 | OK | 189 | 189 fields differ |
| calc_directional | 1 | OK | 12 | 12 fields differ |
| calc_vert_profiles | 1 | OK | 4 | 4 fields differ |
| soil_heat_method | 0 | OK | 2 | 2 fields differ |
| soil_heat_method | 1 | OK | 2 | 2 fields differ |
| calc_rss_rbs | 1 | OK | 121 | 121 fields differ |
| MoninObukhov | 0 | OK | 122 | 122 fields differ |
| LIDF | 1 | OK | 193 | 193 fields differ |
| irradiance | 1 | OK | 175 | 175 fields differ |
| irradiance | 2 | OK | 196 | 196 fields differ |
| calc_fluorescence | 0 | OK | 23 | 23 fields differ |
This is the raw evidence behind every status/finding in Sections 2 and 5 above.