Numerical verification against R
Every function in toolsrtm and scopeinpython has been ported
from, and verified directly against, the corresponding ToolsRTM/
SCOPEinR R function. Each has a pytest regression test comparing
its output against reference values generated by running the R package
itself (python/scratch/scratch_export.R) and saving the results to
CSV. Reference CSVs are bundled under each package’s tests/refdata/.
cd python/toolsrtm && python -m pytest tests -q # 32 tests
cd python/scopeinpython && python -m pytest tests -q # 18 tests
All 50 tests pass, and every ported function matches its R counterpart to floating-point precision or better:
Function |
Reference call |
Max relative diff (Python vs R) |
|---|---|---|
|
|
0 (exact) |
|
|
5.8e-14 |
|
|
~1e-14 |
|
|
0 (exact) |
|
|
3.4e-14 |
|
|
~1e-15 |
|
|
~1e-15 |
|
|
~1e-15 |
|
|
< 1e-6 |
|
|
< 1e-6 |
|
|
~5e-7 (E1 exponential-integral: R integrates numerically, |
|
|
~5e-10 (worst: |
|
|
~1e-15 (refl/tran), ~1e-19 (fluorescence matrices) |
|
|
~1e-15 (refl/tran), ~1e-19 (fluorescence matrices) |
|
|
6.9e-12 |
|
same R functions with those |
~5e-12 (Liberty), ~1e-15 (Fluspect) |
|
|
4.2e-15 |
|
|
2.7e-14 |
|
|
~1e-13 (worst field |
|
|
~1e-15 (refl/tran/kChlrel/kCarrel), ~1e-19 (Mb/Mf) |
|
|
~1e-15 (refl/tran/kChlrel/kCarrel/phiI/phiII), ~1e-19 (Mb/Mf) |
|
|
~1e-6 (loop-accumulated over 30 layers) |
|
|
~1.5e-3 absolute worst case (documented spline approximation, see scopeinpython.rtmf) |
|
|
~1e-5 |
|
|
~1e-9 to ~1e-13 |
|
|
~1-2% (~5% worst case, |
Two things worth knowing about, not discrepancies:
run_rtmo’srso/refllegitimately produceNaN/infat far-thermal wavelengths whereEsun_underflows to ~0 – this reproduces R’s own behaviour at the same wavelengths.soilwat’s use ofscipy.stats.poisson.pmf(round(mu), k)mirrors the original R callstats::dpois(round(mu), k)exactly, and is covered by the BSM regression test.
See python/README.md at the repo root for the full narrative version
of this table.