Skip to content

GreenFlux — Models, Equipment & Controls Overview

A single reference for what the simulator currently models: the physics, the equipment library, and the control layer. It reflects the state after the equipment-realism milestone (closed-loop forward heating + ventilation + CO2, runnable from project-run --mode forward).

The package is layered strictly (each layer only depends on those below it):

equations  ->  flows  ->  equipment / control  ->  systems / simulators  ->  projects / analysis

1. Physics models

Climate state (the greenhouse "unit")

systems/greenhouse_unit.py::GreenhouseUnit is the assembly point. Its immutable GreenhouseUnitState carries up to nine climate + node states:

State Meaning
air_temperature_k greenhouse air temperature
vapour_pressure_pa air humidity (vapour pressure)
co2_mg_m3 air CO2 concentration
local_co2_mg_m3 near-canopy CO2 (local-mixing sensor blend)
cover_temperature_k cover/glazing surface (condensation)
screen_temperature_k thermal-screen surface (condensation)
floor_temperature_k floor/soil surface
thermal_mass_temperature_k lumped thermal-mass node
moisture_buffer_vapour_pressure_pa moisture-buffer node

Every step returns a rich GreenhouseUnitFluxes record — each physical term (heating, ventilation, envelope loss, condensation, transpiration, CO2 exchange, …) is a named field, enabling per-term balance decomposition and calibration.

Crop

crop/ models a staged tomato crop (photosynthesis, respiration, partitioning, fruit development). In the climate loop the canopy is treated as a coupled node (transpiration, CO2 exchange, sensible/latent split). Crop pools (buffer/leaf/stem/fruit/harvested) are explicit states.

Scalar physics (equations/, flows/)

  • equations/: psychrometrics (saturated vapour pressure, RH, dew point; pluggable psychrolib/CoolProp backends), fluid flow, fluid heat transfer.
  • flows/: coupled transfer wrappers composing the scalars — heat_and_vapour, mass_transfer (condensation/evaporation), canopy_transpiration, ventilation (Boulard-Baille natural-vent law + forced-fan rate), heat_transfer.

Integration paths (all share the same physics)

Path Entry point Use
Explicit fixed-step (Euler) simulators/core.py::simulate_fixed_step deterministic, dataset generation
Adaptive IVP (SciPy solve_ivp) systems/greenhouse_unit_ode.py::simulate_greenhouse_unit_ivp recommended default; stiff/accurate
Forward (closed-loop) simulators/forward.py::simulate_forward actuator-driven design studies

The fixed-step and IVP paths reproduce the same physics (parity-verified). The forward path wraps either integrator with a control loop (below).


2. Equipment library (equipment/)

Each device is a frozen dataclass with a capacity-aware output(...)/step(...)/dose(...) method returning a result record. Present-vs-absent realism constraints are noted.

Device Class(es) Models Capacity / limits
Boiler Boiler, PipeCircuit, PipeHeatingNetwork, HeatingPipeSegment pipe heat delivery; boiler fuel→heat rated nominal_heat_power_w, efficiency, reports unmet load; ε-NTU pipe effectiveness; free-convection pipe correlation
Ventilation RoofVent, FanVentilator, InfiltrationLeakage natural roof buoyancy+wind exchange; forced-fan flow; envelope leakage fan max_flow_m3_s + specific_power_w_per_m3_s (electric); discharge/wind/resistance coefficients
CO2 supply CO2Tank, FlueGasCO2Source, CO2LocalMixing, CO2DosingMemory pure-gas dosing; flue-gas capture; near-canopy mixing; pulse memory tank capacity_mg_m2_s+purity; flue max_fuel_power_w_m2, co2_yield, capture eff., contaminant split
Humidity Dehumidifier, FoggingSystem, CondensationSurface condensing dehumidifier; fogging humidifier; cover/screen/floor condensation removal capped at capacity_kg_m2_s and available excess; electric/pump power; first-order surface lag
Envelope EnvelopeBoundary, EnvelopeAssembly per-boundary U·A·exposure conductance validated U/exposure; screen-insulation credit
Lighting LampFixture (HPS/LED presets) PAR/NIR/FIR/convective spectral split dimming clamp; installed_power_w_m2
Screens MovableScreen, ScreenMaterial shortwave transmission, heat-loss reduction, light pollution closure clamp; material presets (thermal/blackout/shade)
Irrigation DripperLine, FertigationSolution, IrrigationEvent emitter flow, EC/pH/nutrients, drain fraction emitter max_flow_kg_m2_s, uniformity
Heat pump consoclim_heat_pump, ConsoClimHeatPumpParameters temperature-dependent COP (EIRFT/CAPFT), part-load, cycling full-load cap, COP map — available but not yet wired into the greenhouse loop
Sizing FloorAreaSizingBasis, capacity_per_floor_area rated-capacity ↔ per-area conversions

Runtime wiring status. The measured-replay path drives climate from measured actuator logs (pipe-temperature heating proxy, measured roof %, CO2 injection signal) and the passive elements (envelope, condensation, local mixing). The forward path (below) wires the capacity-aware Boiler, RoofVent+FanVentilator, and CO2Tank/FlueGasCO2Source through closed-loop actuators. The heat pump and the lamp spectral split remain available but are not yet consumed by either run path.


3. Control layer (control/) — the forward mode

New with the equipment-realism milestone. Actuators follow one pattern: setpoint → PI controller → capacity-limited equipment → flux + consumption + saturation.

Generic PI controller

PIControllerParameters / PIControllerState / pi_control_step — unit-neutral (proportional_gain, integral_gain, output_max, output_min), with conditional-integration anti-windup. Output units are actuator-specific.

Actuators

Actuator Wraps Tracks Notes
HeatingActuator Boiler (per m²) temperature setpoint modulating PI, capacity + efficiency + gas; optional ramp limit; under-capacity → saturated
VentilationActuator RoofVent + FanVentilator max-temperature and max-humidity two gated PI demands (cool only if outside cooler; dehumidify only if outside drier); max of the two; split-range command [0,1] roof → [1,2] fan; fan electricity
CO2Actuator CO2Tank/FlueGasCO2Source CO2 ppm setpoint dose reduced by roof opening (no wasting gas into open vents); CO2/fuel accounting

Setpoint schedules

Per domain: Constant* and DayNight* providers for heating temperature, ventilation temperature, humidity (constant only), and CO2 ppm. "Enrich by day only" falls out of a day/night CO2 setpoint whose night value is ambient.

Composition (simulate_forward)

Each control interval evaluates the actuators in order heating → ventilation → CO2 (CO2 reads the vent's roof opening for its dose reduction), then advances the same GreenhouseUnit physics with the resulting fluxes held constant (zero-order hold) via the fixed or IVP integrator. Separate heating/ventilation setpoints create a natural deadband. The PI integral state lives in the driver, never in the frozen physics state, so the mode composes with both integrators without touching parity.

Consumption ledger (ForwardConsumptionLedger): heat_delivered_kwh_m2, fuel_gas_kwh_m2, fan_electricity_kwh_m2, co2_dosed_kg_m2, co2_source_fuel_kwh_m2, plus utilization/at-capacity hours per actuator.

Note: ventilation cooling is stiff (a fully open roof at large ΔT removes hundreds of W/m²); forward runs with active ventilation should use solver="ivp" (the default) — a 300 s explicit-Euler step overshoots.


4. Run modes

Declarative forward control

A project may declare a project-level forward_control block (projects/schema.py): heating / ventilation / co2 actuator definitions (PI gains, capacities, dose params) + heating_setpoint / ventilation_setpoint / humidity_setpoint / co2_setpoint schedules (constant or day_night). It resolves to the actuators + setpoints simulate_forward consumes. Heating is mandatory; ventilation and CO2 are optional; the CO2 source comes from equipment.co2. The block is optional — projects without it are unaffected.

CLI

greenflux project-run <project.json> --mode replay    # measured forcing (default), validated
greenflux project-run <project.json> --mode forward   # closed-loop actuators from forward_control
  • replay: reproduces measured actuator behaviour; the calibrated, validated path; byte-stable (dataset generation depends on it).
  • forward: runs the closed-loop actuators over weather-only forcing and writes the same outputs (timeseries + recovered fluxes, summary.json with the consumption ledger, ledger-derived resource_statistics). Both GreenLight projects ship a forward_control block, so --mode forward works out of the box.

Solver flags apply to both (--solver ivp|fixed, IVP tolerances). See docs/project_run_forward.md.


5. Calibration & validation

  • Validated against the GreenLight HPS/LED Bleiswijk measured-replay dataset.
  • Calibration profiles per project (measured_replay, measured_replay_physical, measured_replay_ivp). measured_replay_physical is the recommended default for simulation studies: physical parameters (near-unity fudge multipliers), better balance closure, comparable climate accuracy. measured_replay is retained byte-stable.
  • A shared cover-condensation vapour-sink helper makes project-run reproduce the replay's calibrated humidity/latent behaviour (previously the builder path silently dropped it).
  • analysis/resource_statistics.py aggregates macro consumptions (heat/electricity/CO2/water) and assesses them against plausibility bounds.

See docs/usable_physical_models.md, the calibration-forcing reconciliation notes (internal).


6. Realism status & known limitations (honest)

Realistic today - Closed-loop heating / ventilation / CO2 with capacity limits, efficiency/fuel accounting, actuator dynamics (anti-windup, ramp, split-range staging, dose-vs-vent coupling), and a consumption ledger — driven by physical equipment, not replayed signals. - Physical calibration (measured_replay_physical) with balances that close. - Validated forward behaviour: on a warm day the controller holds temperature in the heat/vent deadband ~92 % of the time and daytime CO2 within ±100 ppm of target ~95 %.

Known limitations / follow-ups - Heat pump (COP-vs-temperature) is modelled but not wired into either run path. - Lighting uses a single heat-fraction scalar in the runtime; the LampFixture spectral split (PAR/NIR/FIR) is not consumed there. - CO2 as a diagnostic in replay: the measured injection signal is uninformative (binary, off ~97 % of the time) — forward setpoint dosing is meaningful, replay CO2 is not. - Deferred CO2 signal-shaping reconciliation: the replay's stateful CO2 pulse shaping is not yet reproduced by project-run (needs a stateful builder input schedule). - Irrigation / water balance is an open-loop dosing calculator, not coupled to a root-zone state; the forward resource ledger reports no water. - Fuel/gas totals appear in the forward summary.json ledger but not in the flat ResourceMacroStatistics (which has no fuel field). - On/off-hysteresis control and a declarative case-level forward trigger are not implemented (the --mode forward CLI flag is the trigger).


Pointers

  • Actuator internals: docs/forward_heating_mode.md, docs/forward_ventilation_mode.md, docs/forward_co2_mode.md.
  • Running forward: docs/project_run_forward.md.
  • Calibration: docs/usable_physical_models.md, the calibration-forcing reconciliation notes (internal).