Skip to contents
library(ToolsRTM)
library(SCOPEinR)

Every 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, applTcorr rarely 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 (Actot differs meaningfully from Fluorescence_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 as Value = 0. What should I do? Treat Fluorescence_model = 1 as equivalent to 0 for 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 soilspectrum feeds into.
  • Tutorial 04 – fluorescence in depth, including where calc_fluorescence/Fluorescence_model plug 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.