Skip to content

Events

The Event class (v0.3.0) allows researchers to schedule discrete management actions — irrigation, fertiliser application, and custom interventions — that fire on specific days or at repeating intervals.


Execution Contract

Events fire at the end of each day, after all physics hooks and @farm.step functions have run. State modifications made by an event are visible to model logic from day+1 onwards.

Day N execution order:
  1. Physics hooks  (phase=-2, -1)
  2. @farm.step     (phase=0, 1, 2, …)
  3. Events fire    ← here
  4. Logger records the completed day

API

from cropforge import Farm, Event

farm = Farm(name="Irrigation Trial")

# Interval-based irrigation (fires every 15 days)
farm.add_event(Event.irrigation(
    field="Plot_A",
    interval_days=15,
    amount_mm=30,
    start_day=1,
    end_day=90,
))

# One-time fertiliser
farm.add_event(Event.fertiliser(
    field="Plot_A",
    day=20,
    n_kg_ha=40.0,
    apply_to_layer=0,
))

# Fertiliser on multiple days (split application)
farm.add_event(Event.fertiliser(
    field="Plot_B",
    days=[20, 45],
    n_kg_ha=25.0,
    apply_to_layer=0,
))

# Custom event — arbitrary function called on a specific day
@farm.add_event(Event.custom(field="Plot_A", day=50))
def stress_test(field_state, env_state):
    for plant in field_state.plants:
        plant.custom["drought_stressed"] = True

farm.run(days=90)

Event.irrigation()

Parameter Type Default Description
field str Target field name.
interval_days int Days between irrigations. Must be ≥ 1.
amount_mm float Water added to layer 0 moisture (mm).
start_day int 1 First day on which the event fires.
end_day int \| None None Last day (inclusive). None = end of simulation.

Moisture is capped at the soil's saturation percentage. Irrigation does not affect other fields.


Event.fertiliser()

Parameter Type Default Description
field str Target field name.
day int Single day on which to fire. Mutually exclusive with days.
days List[int] List of days on which to fire. Mutually exclusive with day.
n_kg_ha float Nitrogen added per hectare.
apply_to_layer int 0 Soil layer index to receive nitrogen.

Event.custom()

Parameter Type Description
field str Target field name.
day int Day on which to fire.

The decorated function receives (field_state: FieldState, env_state: EnvironmentState). It may return None or a modified field_state.


Event Log

Every fired event writes one entry to the Event Log panel in the dashboard and to FieldState.events_fired. Format:

Day 15 | Plot_A | irrigation | +30mm (layer 0)
Day 20 | Plot_A | fertiliser | +40 kg/ha N (layer 0)
Day 50 | Plot_A | custom | stress_test()

Error Handling

Error When raised
CropForgeEventError interval_days=0 or other invalid configuration. Raised at farm.run() time.
Custom event exception Caught, logged to Event Log as an error entry. Simulation continues.