Runtime
The CropForge runtime engine (cropforge/runtime.py) drives the time-stepping loop and defines the error-handling contract.
Execution Order (per day)
For each simulation day, for each field, the engine executes in this exact order:
| Order | Phase | What runs |
|---|---|---|
| 1 | phase=-2 |
ET0 physics hook (if use_physics(et0=True)) |
| 2 | phase=-1 |
Root impedance hook (if use_physics(root_impedance=True)) |
| 3 | phase=0 |
Researcher @farm.step functions (sorted by phase) |
| 4 | End of day | Registered Event objects that fire on this day |
| 5 | — | Parquet logger records the completed timestep |
Key principle: Events fire after all step functions. State modifications made by an event are visible to model logic from day+1 onwards. This mirrors real farming: the crop responds to today's environment, then the farmer acts.
Error Handling
When a @farm.step function raises an unhandled exception:
- The simulation halts immediately.
- A crash log is written to
cropforge_crash.login the working directory. - All completed timesteps are flushed to the partial Parquet log so data is not lost.
- A
CropForgeStepErroris raised.
CropForgeStepError
| Attribute | Type | Description |
|---|---|---|
day |
int |
Day on which the failure occurred. |
step_name |
str |
Name of the step function that raised. |
crash_log_path |
str |
Absolute path to the crash log file. |
original_exception |
BaseException |
The original exception. |
CropForgeVisualizeError
Raised by farm.visualize() if the pre-flight check fails (e.g. no Parquet log found, port already in use).
CropForgeEventError
Raised when an Event is configured with invalid parameters (e.g. interval_days=0). Raised at farm.run() time, not at event registration time.