Numerical Solvers¶
GreenFlux currently has two solver layers:
simulate_fixed_step: deterministic fixed-step integration for dataclass models that exposestep(state, inputs, dt_s, time_s).simulate_ivp: SciPysolve_ivpadapter for vector ODE models.simulate_greenhouse_unit_climate_ivp: adaptive SciPy integration for the fastGreenhouseUnitclimate state vector.simulate_greenhouse_unit_ivp: adaptive SciPy integration for climate plus staged tomato crop states.
Project Runner Path¶
IVP is now the recommended default. greenflux project-run defaults to
--solver ivp (adaptive full-state SciPy solve_ivp, RK45, rtol 1e-6,
atol 1e-9). The promotion (CAL-04) is justified by the drift gate (CAL-02),
the IVP recalibration (CAL-01) and the 14-window adaptive-accuracy audit
(CAL-03) summarised in the benchmark below.
# adaptive full-state integration (default)
uv run greenflux project-run projects/greenlight_hps_bleiswijk/project.json
The explicit fixed-step path is retained and remains fully functional and
byte-stable — it is selected explicitly with --solver fixed:
The default flip is a CLI-default change only. run_project_greenhouse_unit_case
takes solver explicitly, so dataset-generation call sites that pass
solver="fixed" are unaffected; deterministic dataset generation is unchanged.
The fixed-step path remains the correct choice for:
- deterministic dataset generation (byte-stable; the dataset pipeline depends on it)
- reproducible project runs at exactly the declared project timesteps
- low-overhead smoke tests
- state/flux reporting at declared project timesteps
The adaptive IVP path is preferred for accuracy-sensitive replay because it removes the coarse-step venting needle and condensation ringing (see the audit below) while tracking the explicit path's level accuracy within drift tolerance.
SciPy Adapter¶
greenflux.simulators.scipy.simulate_ivp wraps scipy.integrate.solve_ivp.
It now validates:
- allowed methods:
RK23,RK45,DOP853,Radau,BDF,LSODA - positive tolerances and step sizes
- one-dimensional, finite initial states
- derivative output shape and finite values
- strictly increasing
t_eval_s
The result exposes solver diagnostics:
evaluation_countjacobian_evaluation_countlu_decomposition_countstatusevent_times
Recommended methods:
RK45orDOP853for smooth non-stiff studies.BDForRadaufor condensation, humidity-control or local-mixing studies onceGreenhouseUnitexposes vector derivatives.LSODAwhen automatic stiffness switching is useful and SciPy support is available in the environment.
Greenhouse Unit ODE Contracts¶
GreenhouseUnit now exposes two vector derivative contracts.
The climate contract covers:
air_temperature_kvapour_pressure_paco2_mg_m3local_co2_mg_m3cover_temperature_kscreen_temperature_kfloor_temperature_k
This is available through greenhouse_unit_climate_derivatives,
pack_greenhouse_unit_climate_state and
simulate_greenhouse_unit_climate_ivp.
The full-state contract adds the staged tomato crop:
- crop buffer, leaf, stem and harvested biomass
- crop temperature-sum and 24 h temperature-memory states
- fruit potential-stage-one mass
- all fruit count stages
- all fruit biomass stages
This is available through greenhouse_unit_state_derivatives,
pack_greenhouse_unit_state, greenhouse_unit_state_names and
simulate_greenhouse_unit_ivp.
Both routes reconstruct the same physical tendencies used by
GreenhouseUnit.step for smooth, non-clipped windows. The full-state route is
now suitable for controlled solver experiments that include crop dynamics.
Final IVP-Vs-Explicit Benchmark (CAL-02/03/04)¶
This benchmark is the promotion evidence for the IVP default. All numbers are sourced directly from committed Phase-5 artifacts (no hand-entered guesses):
outputs/calibration/ivp_drift_check.json(CAL-02 drift gate)outputs/calibration/ivp_explicit_degradation.json(CAL-01 recalibration)outputs/calibration/ivp_audit_14window.{json,md}(CAL-03 audit)
The recalibrated IVP-specific parameter sets live in
outputs/calibration/ivp_params_{hps,led}.json. They are stored separately
from the project measured_replay profiles in projects/<id>/project.json —
the project files are intentionally untouched by the recalibration, so the
explicit baseline parameters and deterministic dataset generation are unchanged.
Drift gate — IVP tracks the explicit path (CAL-02)¶
Out-of-sample RMSE over the 14-window OOS split, recalibrated IVP vs the
explicit baseline. The gate is within_115pct (IVP RMSE ≤ 1.15× explicit RMSE
per variable). IVP tracks the explicit path within 0.994–1.003× — no
systematic derivative bias.
| Installation | Variable | Explicit OOS RMSE | IVP OOS RMSE | IVP/explicit ratio |
|---|---|---|---|---|
| HPS | air temperature | 2.423 C | 2.411 C | 0.995 |
| HPS | relative humidity | 9.543 pp | 9.517 pp | 0.997 |
| HPS | vapour pressure | 290.3 Pa | 289.5 Pa | 0.997 |
| HPS | CO2 | 424.7 ppm | 422.2 ppm | 0.994 |
| LED | air temperature | 2.016 C | 2.007 C | 0.995 |
| LED | relative humidity | 7.205 pp | 7.224 pp | 1.003 |
| LED | vapour pressure | 256.2 Pa | 255.8 Pa | 0.998 |
| LED | CO2 | 275.1 ppm | 274.6 ppm | 0.998 |
Both installations pass (within_115pct: true).
Recalibration explicit-degradation gate (CAL-01)¶
The IVP-fit parameter sets must not degrade the explicit path by more than
15% on any variable (within_15pct). Applying the IVP-fit params on the
explicit path:
| Installation | Variable | Baseline RMSE | IVP-fit RMSE | ratio |
|---|---|---|---|---|
| HPS | air temperature | 2.387 C | 2.095 C | 0.878 |
| HPS | relative humidity | 9.135 pp | 7.554 pp | 0.827 |
| HPS | vapour pressure | 293.8 Pa | 287.0 Pa | 0.977 |
| HPS | CO2 | 423.6 ppm | 403.2 ppm | 0.952 |
| LED | air temperature | 1.991 C | 2.076 C | 1.043 |
| LED | relative humidity | 7.177 pp | 7.227 pp | 1.007 |
| LED | vapour pressure | 252.3 Pa | 261.2 Pa | 1.035 |
| LED | CO2 | 271.6 ppm | 264.9 ppm | 0.975 |
Both pass (within_15pct: true). On HPS the IVP-fit params improve the
explicit path on all four variables (ratios 0.83–0.98); on LED the worst case
is air temperature at +4.3%, well inside the 15% bound.
Reliability caveat (honest): the recalibration ran under a tight budget
(3 trials, 25-minute cap, sized from a measured ~53 s/trial). Its internal
reliability_accepted flag is false for both installations — Optuna kept
the baseline in several stages. CAL-01's success criterion (converged + IVP
param set + ≤15% explicit degradation) is met regardless; earning reliability
acceptance would require a larger trial budget. This caveat is recorded here so
the documented numbers are not over-claimed.
14-window adaptive-accuracy audit (CAL-03)¶
Coarse 300 s explicit (integration_substeps=1) vs IVP (RK45, rtol 1e-6,
atol 1e-9) over a 14-window strided OOS audit. Reductions are IVP-vs-coarse
relative reductions (positive = IVP reduces the artifact).
Venting-needle reduction (increment RMSE — the fast roof-venting transient):
| Installation | Variable | coarse incr-RMSE | IVP incr-RMSE | rel. reduction |
|---|---|---|---|---|
| HPS | air temperature | 0.5462 | 0.3871 | 28.5% |
| HPS | relative humidity | 8.598 | 1.646 | 60.4% |
| HPS | vapour pressure | 173.3 | 50.28 | 50.6% |
| HPS | CO2 | 44.81 | 37.55 | 22.0% |
| LED | air temperature | 0.5165 | 0.4503 | 18.6% |
| LED | relative humidity | 2.456 | 1.249 | 42.4% |
| LED | vapour pressure | 74.23 | 48.65 | 31.5% |
| LED | CO2 | 25.04 | 24.49 | 4.1% |
IVP reduces the venting needle on every variable, both installations (HPS 22–60%, LED 4–42%).
Condensation-ringing reduction (supersaturation produced):
| Installation | coarse supersat (Pa) | IVP supersat (Pa) | rel. reduction |
|---|---|---|---|
| HPS | 3403 | 82.35 | 68.4% |
| LED | 486.2 | 78.54 | 39.3% |
Honesty note: this is a diagnostic reduction, not a sink/clip equivalence
claim. The coarse arm's value is the explicit hard-clip magnitude removed (a
reported *_clipping_* diagnostic, no new clamp); the IVP value is the residual
excess above saturation from the smooth relaxation sink (no hard clip). The
metric is symmetric by construction (it compares accumulated supersaturation the
two paths produced), so it avoids the hard-clip-masking pitfall.
Interpretation: adaptive integration does not change the underlying physics, but it tracks the explicit level accuracy within drift tolerance while materially removing the coarse-step venting needle and condensation ringing — which is why IVP is promoted to the recommended default.
High-Humidity Clipping Stress Check¶
The clipping guard was also checked on automatically selected measured high-humidity windows:
uv run python examples/diagnose_project_clipping_stress.py \
projects/greenlight_hps_bleiswijk/project.json \
--installation HPS \
--top-n 3 \
--ivp-method RK45 \
--ivp-method BDF \
--ivp-method Radau \
--output-dir outputs/diagnostics/clipping_stress_hps
uv run python examples/diagnose_project_clipping_stress.py \
projects/greenlight_led_bleiswijk/project.json \
--installation LED \
--top-n 3 \
--ivp-method RK45 \
--output-dir outputs/diagnostics/clipping_stress_led
Results:
| Installation | Windows | Mean RH range | Max RH range | Solver paths | Vapour clips | CO2 clips |
|---|---|---|---|---|---|---|
| HPS | 3 | 84.2-85.2% | 87.8-91.7% | fixed, RK45, BDF, Radau | 0 | 0 |
| LED | 3 | 87.7-88.4% | 92.6-94.3% | fixed, RK45 | 0 | 0 |
Interpretation: the non-negative vapour and CO2 state guards did not activate on the measured high-humidity stress windows. This lowers the priority of state reparameterization for current calibrated GreenLight replay windows. The diagnostic now forces and records the initial fast climate state from the first measured indoor temperature, RH and CO2 value in each selected window. The large humidity and vapour-pressure RMSE that remain after this alignment should not be used as an acceptance score for the project as a whole: crop biomass, root-zone, surface and other slow states are still initialized from project defaults unless separate measured/warm-start states are available. They are useful as stress-window evidence for model-structure/calibration work: boundary storage, screen/floor condensation, sensor alignment, undocumented humidity equipment or latent weather/control offsets. The exported GreenLight projects currently have zero fogging capacity, so the new evaporative cooling coupling does not change these measured replay runs unless fogging is explicitly enabled in a project.
The stiff methods were stable on HPS but did not materially improve the metrics. BDF used 6.3k-8.3k function evaluations per 24 h window with non-zero Jacobian/LU work; Radau used 20.8k-29.1k evaluations. RK45 remains the reasonable default for project IVP replay until condensation events or sharper actuator switching justify stiff solvers.
Remaining Gap¶
IVP is the recommended default and is the route exercised by project-run out
of the box; IVP project summaries report solver evaluation counts, Jacobian
evaluations, LU decompositions, status, message and event times when events are
registered. The remaining gap is event-aware validation and targeted
stiff-method use (deferred to v2: condensation-onset events and an analytical
Jacobian).
Project greenhouse-unit outputs now report non-negative state-guard corrections
as first-class numerical diagnostics. The timeseries CSV includes
vapour_pressure_clipping_pa and co2_clipping_mg_m3, and the summary JSON
aggregates event counts, total correction and maximum correction for each
state guard. These fields are diagnostic for both fixed-step output and IVP
project output where fluxes are reconstructed over the reported trajectory.
The required refactor is:
- Compare fixed-step, RK and stiff methods on CO2-dosing and condensation onset windows.
- Add events for condensation onset, saturation approach and actuator switching when useful.
- Keep
simulate_fixed_step(selected with--solver fixed) as the deterministic dataset-generation mode even though IVP is now the default.
Conservation Policy¶
State clamping such as max(0.0, value) must not remain silent in reliability
claims. GreenhouseUnitFluxes reports:
air_temperature_tendency_k_svapour_pressure_tendency_pa_svapour_pressure_clipping_pavapour_pressure_supersaturation_clipping_paco2_tendency_mg_m3_sco2_clipping_mg_m3
The air vapour state is bounded on both sides: the non-negative floor reports
into vapour_pressure_clipping_pa, and a saturation cap at the post-step air
temperature (relative humidity cannot exceed 100% in bulk air) reports the
condensed excess into vapour_pressure_supersaturation_clipping_pa. The
saturation cap removes a stiff explicit-Euler oscillation in the condensation
sink, which at the 300 s replay step otherwise let the vapour state ring across
the saturation line (relative humidity swinging between 0% and >300%) and sit
persistently supersaturated. It activates only in those non-physical regimes, so
calibrated sub-saturated trajectories are unchanged.
A few brief downward vapour and temperature transients during fast roof-venting
steps were a separate fixed-step artifact. simulate_greenlight_open_loop now
sub-steps each record interval (integration_substeps, default 4 → 75 s
sub-steps), re-evaluating the state-dependent condensation and pipe-heating
terms against the evolving state instead of holding them at the start-of-interval
value for the full 300 s. Measured across a 14-window strided audit of the whole
dataset this barely moves the out-of-sample metrics (it slightly improves them
and removes the venting needles), so the calibration stays valid; substeps=1
reproduces the original single-step behaviour exactly.
These fields let validation code reconstruct the explicit update and flag cases
where non-negative guards introduce a physically meaningful correction.
Project outputs carry the same clipping fields in the timeseries CSV and a
numerical_diagnostics block in the summary JSON so reliability reports can
fail or warn on non-zero corrections instead of discovering them post hoc.
Adaptive project outputs also carry solver_diagnostics in the summary JSON,
including evaluation_count, jacobian_evaluation_count,
lu_decomposition_count, status, message and event_times_s.
Acceptance Rule¶
- adaptive IVP (the default) is the recommended path for measured replay and accuracy-sensitive project runs: it tracks the explicit level accuracy within the drift gate (0.994–1.003× OOS RMSE) while removing the coarse-step venting needle and condensation ringing (CAL-02/03);
- the explicit fixed-step path (
--solver fixed) remains accepted and is the required mode for deterministic, byte-stable dataset generation and exact declared-timestep reporting; - adaptive climate-only results are acceptable for short climate subsystem experiments where crop-state drift is intentionally held external;
- adaptive full-state results are acceptable for controlled solver experiments that include crop dynamics;
- project-run IVP interval fluxes in CSV/resource reports are diagnostic reconstructions over the IVP state trajectory;
- reliability claims must include increment, drift and residual diagnostics, and
the recalibration reliability caveat above (CAL-01
reliability_accepted: falseunder the tight trial budget) must be cited alongside the recalibrated numbers; - full stiff/adaptive (BDF/Radau/event) claims should wait until those method comparisons are exercised against measured replay data.