Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,21 @@ export(add_strategies)
export(build_scenario)
export(check_driver_interpolation)
export(classify_scm_run)
export(climate_extreme)
export(control)
export(control_accurate)
export(environment_type)
export(evaluate_scenario)
export(events)
export(events_default)
export(expand_parameters)
export(expand_state)
export(export_patch_state)
export(generate_strategy)
export(grow_individual_to_height)
export(grow_individual_to_size)
export(grow_individual_to_time)
export(harvest)
export(hyperpar)
export(integrate_over_size_distribution)
export(interpolate_to_heights)
Expand All @@ -70,15 +74,18 @@ export(make_initial_state)
export(model_id)
export(model_version)
export(mutant_parameters)
export(node_introductions)
export(node_schedule_times_default)
export(optimise_individual_rate_at_height_by_trait)
export(optimise_individual_rate_at_size_by_trait)
export(param_hyperpar)
export(plant_log_console)
export(plot_size_distribution)
export(rainfall_pulse)
export(read_scenario_mapping)
export(read_scenario_table)
export(resource_compensation_point)
export(resource_pulse)
export(run_plant_benchmarks)
export(run_scenarios)
export(run_scm)
Expand Down
54 changes: 54 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,60 @@ were not previously recorded here:
flux the plant has moves establishment and every plant near its compensation
point, so it wants its own change and its own re-blessing rather than being
folded in here where one census movement would have two causes.
* **Discrete events (#628).** `run_scm()` takes an `events` argument: a queue of
`(time, action)` items applied between solver legs, the way node introductions
always have been. Build one with `events()` and the typed constructors —
`node_introductions()`, `resource_pulse()`, `harvest()`, `climate_extreme()`.

The vocabulary is deliberately taxa- and model-agnostic, because the machinery
is shared by every strategy and environment: a resource pulse is water in TF24
and could be anything countable in a size-structured animal model, and a
climate extreme is heat in one model and could be cold or salinity in another.
Names that are only true of one model live with that model — `rainfall_pulse()`
is a resource pulse of water into TF24's surface soil layer, and
`TF24_Environment$add_water_pulse()` is the same action on the C++ side.

```r
ev <- events(
node_introductions(p),
rainfall_pulse(time = c(1.5, 3.2), depth = c(0.013, 0.050)),
harvest(time = 20, fraction = 0.5, size_min = 10)
)
res <- run_scm(p, env = env, ctrl = ctrl, events = ev)
```

Each event carries when it happens, its type, its target (`"environment"`,
`"patch"` or one `"species"`) and the values it needs. What each one actually
did — as against what was asked of it — is readable as `scm$event_log`; the two
differ routinely, because a pulse is capped at what the pool can hold and the
excess is shed.

Two things worth knowing. An event is also a **stop time** for the integrator,
so adding one changes the adaptive step sequence: a run with events legitimately
differs from one without, at solver tolerance, even away from the events. And
events are instantaneous *to the solver* only — an action may sub-integrate its
own fast model over a nominal duration with demography frozen, which is what
`climate_extreme()` does. Design notes in `notes/plan-events.md`.

`collect = TRUE` returns `events` and `event_log` alongside the tidied output,
since events are supplied separately from `p` and a collected result would
otherwise record neither what was asked for nor what was done.

Events are validated before the run rather than during it: an event past
`max_patch_lifetime`, a type aimed at a target it cannot act on, and
parameters an action cannot use (a non-finite intensity, a negative
sensitivity, an inverted size band) are all refused at construction.

Runs that supply no events are unaffected, and verified so: FF16, K93 and TF24
are `identical()` on ODE step times, fitness and state.

Also adopts odelia 0.3.1's opt-in domain checks. Two conditions that used to
kill a run outright are now rejected steps: a non-finite environment state
(measured in #608 to be integrator overshoot, which a smaller step recovers),
and an infeasible leaf probe out of phylloptim's collar root-find. Both are
inert when nothing goes wrong -- the three reference runs stay `identical()`.
A runaway cohort density stays fatal, because that divergence is in the
equations rather than the stepper and shrinking cannot recover it.

* **`Control$node_density_in_birth_date`** (default `FALSE`) carries the SCM's
size distribution as a density in birth date instead of in height.
Expand Down
96 changes: 84 additions & 12 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -761,12 +761,12 @@ NodeScheduleEvent__ctor <- function(introduction, species_index) {
.Call('_plant_NodeScheduleEvent__ctor', PACKAGE = 'plant', introduction, species_index)
}

NodeScheduleEvent__species_index__get <- function(obj_) {
.Call('_plant_NodeScheduleEvent__species_index__get', PACKAGE = 'plant', obj_)
NodeScheduleEvent__target_index__get <- function(obj_) {
.Call('_plant_NodeScheduleEvent__target_index__get', PACKAGE = 'plant', obj_)
}

NodeScheduleEvent__species_index__set <- function(obj_, value) {
invisible(.Call('_plant_NodeScheduleEvent__species_index__set', PACKAGE = 'plant', obj_, value))
NodeScheduleEvent__target_index__set <- function(obj_, value) {
invisible(.Call('_plant_NodeScheduleEvent__target_index__set', PACKAGE = 'plant', obj_, value))
}

NodeScheduleEvent__times__get <- function(obj_) {
Expand All @@ -785,6 +785,22 @@ NodeScheduleEvent__species_index_raw__get <- function(obj_) {
.Call('_plant_NodeScheduleEvent__species_index_raw__get', PACKAGE = 'plant', obj_)
}

Events__ctor <- function() {
.Call('_plant_Events__ctor', PACKAGE = 'plant')
}

Events__vdor <- function(obj) {
.Call('_plant_Events__vdor', PACKAGE = 'plant', obj)
}

EventLog__ctor <- function() {
.Call('_plant_EventLog__ctor', PACKAGE = 'plant')
}

EventLog__vdor <- function(obj) {
.Call('_plant_EventLog__vdor', PACKAGE = 'plant', obj)
}

NodeSchedule__ctor <- function(n_species) {
.Call('_plant_NodeSchedule__ctor', PACKAGE = 'plant', n_species)
}
Expand Down Expand Up @@ -2157,6 +2173,10 @@ Patch___FF16__FF16_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_Patch___FF16__FF16_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
}

Patch___FF16__FF16_Env__ode_state_valid <- function(obj_, y) {
.Call('_plant_Patch___FF16__FF16_Env__ode_state_valid', PACKAGE = 'plant', obj_, y)
}

Patch___FF16__FF16_Env__introduce_new_node <- function(obj_, species_index) {
invisible(.Call('_plant_Patch___FF16__FF16_Env__introduce_new_node', PACKAGE = 'plant', obj_, species_index))
}
Expand Down Expand Up @@ -2269,6 +2289,10 @@ Patch___TF24__TF24_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_Patch___TF24__TF24_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
}

Patch___TF24__TF24_Env__ode_state_valid <- function(obj_, y) {
.Call('_plant_Patch___TF24__TF24_Env__ode_state_valid', PACKAGE = 'plant', obj_, y)
}

Patch___TF24__TF24_Env__introduce_new_node <- function(obj_, species_index) {
invisible(.Call('_plant_Patch___TF24__TF24_Env__introduce_new_node', PACKAGE = 'plant', obj_, species_index))
}
Expand Down Expand Up @@ -2381,6 +2405,10 @@ Patch___TF24f__TF24_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_Patch___TF24f__TF24_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
}

Patch___TF24f__TF24_Env__ode_state_valid <- function(obj_, y) {
.Call('_plant_Patch___TF24f__TF24_Env__ode_state_valid', PACKAGE = 'plant', obj_, y)
}

Patch___TF24f__TF24_Env__introduce_new_node <- function(obj_, species_index) {
invisible(.Call('_plant_Patch___TF24f__TF24_Env__introduce_new_node', PACKAGE = 'plant', obj_, species_index))
}
Expand Down Expand Up @@ -2493,6 +2521,10 @@ Patch___K93__K93_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_Patch___K93__K93_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
}

Patch___K93__K93_Env__ode_state_valid <- function(obj_, y) {
.Call('_plant_Patch___K93__K93_Env__ode_state_valid', PACKAGE = 'plant', obj_, y)
}

Patch___K93__K93_Env__introduce_new_node <- function(obj_, species_index) {
invisible(.Call('_plant_Patch___K93__K93_Env__introduce_new_node', PACKAGE = 'plant', obj_, species_index))
}
Expand Down Expand Up @@ -2601,8 +2633,8 @@ Patch___K93__K93_Env__state__get <- function(obj_) {
.Call('_plant_Patch___K93__K93_Env__state__get', PACKAGE = 'plant', obj_)
}

SCM___FF16__FF16_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_SCM___FF16__FF16_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
SCM___FF16__FF16_Env__ctor <- function(parameters, environment, events, control) {
.Call('_plant_SCM___FF16__FF16_Env__ctor', PACKAGE = 'plant', parameters, environment, events, control)
}

SCM___FF16__FF16_Env__run <- function(obj_) {
Expand Down Expand Up @@ -2673,6 +2705,14 @@ SCM___FF16__FF16_Env__node_schedule__set <- function(obj_, value) {
invisible(.Call('_plant_SCM___FF16__FF16_Env__node_schedule__set', PACKAGE = 'plant', obj_, value))
}

SCM___FF16__FF16_Env__events__get <- function(obj_) {
.Call('_plant_SCM___FF16__FF16_Env__events__get', PACKAGE = 'plant', obj_)
}

SCM___FF16__FF16_Env__event_log__get <- function(obj_) {
.Call('_plant_SCM___FF16__FF16_Env__event_log__get', PACKAGE = 'plant', obj_)
}

SCM___FF16__FF16_Env__ode_times__get <- function(obj_) {
.Call('_plant_SCM___FF16__FF16_Env__ode_times__get', PACKAGE = 'plant', obj_)
}
Expand All @@ -2693,8 +2733,8 @@ SCM___FF16__FF16_Env__collect_refinement_errors__set <- function(obj_, value) {
invisible(.Call('_plant_SCM___FF16__FF16_Env__collect_refinement_errors__set', PACKAGE = 'plant', obj_, value))
}

SCM___TF24__TF24_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_SCM___TF24__TF24_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
SCM___TF24__TF24_Env__ctor <- function(parameters, environment, events, control) {
.Call('_plant_SCM___TF24__TF24_Env__ctor', PACKAGE = 'plant', parameters, environment, events, control)
}

SCM___TF24__TF24_Env__run <- function(obj_) {
Expand Down Expand Up @@ -2765,6 +2805,14 @@ SCM___TF24__TF24_Env__node_schedule__set <- function(obj_, value) {
invisible(.Call('_plant_SCM___TF24__TF24_Env__node_schedule__set', PACKAGE = 'plant', obj_, value))
}

SCM___TF24__TF24_Env__events__get <- function(obj_) {
.Call('_plant_SCM___TF24__TF24_Env__events__get', PACKAGE = 'plant', obj_)
}

SCM___TF24__TF24_Env__event_log__get <- function(obj_) {
.Call('_plant_SCM___TF24__TF24_Env__event_log__get', PACKAGE = 'plant', obj_)
}

SCM___TF24__TF24_Env__ode_times__get <- function(obj_) {
.Call('_plant_SCM___TF24__TF24_Env__ode_times__get', PACKAGE = 'plant', obj_)
}
Expand All @@ -2785,8 +2833,8 @@ SCM___TF24__TF24_Env__collect_refinement_errors__set <- function(obj_, value) {
invisible(.Call('_plant_SCM___TF24__TF24_Env__collect_refinement_errors__set', PACKAGE = 'plant', obj_, value))
}

SCM___TF24f__TF24_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_SCM___TF24f__TF24_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
SCM___TF24f__TF24_Env__ctor <- function(parameters, environment, events, control) {
.Call('_plant_SCM___TF24f__TF24_Env__ctor', PACKAGE = 'plant', parameters, environment, events, control)
}

SCM___TF24f__TF24_Env__run <- function(obj_) {
Expand Down Expand Up @@ -2857,6 +2905,14 @@ SCM___TF24f__TF24_Env__node_schedule__set <- function(obj_, value) {
invisible(.Call('_plant_SCM___TF24f__TF24_Env__node_schedule__set', PACKAGE = 'plant', obj_, value))
}

SCM___TF24f__TF24_Env__events__get <- function(obj_) {
.Call('_plant_SCM___TF24f__TF24_Env__events__get', PACKAGE = 'plant', obj_)
}

SCM___TF24f__TF24_Env__event_log__get <- function(obj_) {
.Call('_plant_SCM___TF24f__TF24_Env__event_log__get', PACKAGE = 'plant', obj_)
}

SCM___TF24f__TF24_Env__ode_times__get <- function(obj_) {
.Call('_plant_SCM___TF24f__TF24_Env__ode_times__get', PACKAGE = 'plant', obj_)
}
Expand All @@ -2877,8 +2933,8 @@ SCM___TF24f__TF24_Env__collect_refinement_errors__set <- function(obj_, value) {
invisible(.Call('_plant_SCM___TF24f__TF24_Env__collect_refinement_errors__set', PACKAGE = 'plant', obj_, value))
}

SCM___K93__K93_Env__ctor <- function(parameters, environment, control) {
.Call('_plant_SCM___K93__K93_Env__ctor', PACKAGE = 'plant', parameters, environment, control)
SCM___K93__K93_Env__ctor <- function(parameters, environment, events, control) {
.Call('_plant_SCM___K93__K93_Env__ctor', PACKAGE = 'plant', parameters, environment, events, control)
}

SCM___K93__K93_Env__run <- function(obj_) {
Expand Down Expand Up @@ -2949,6 +3005,14 @@ SCM___K93__K93_Env__node_schedule__set <- function(obj_, value) {
invisible(.Call('_plant_SCM___K93__K93_Env__node_schedule__set', PACKAGE = 'plant', obj_, value))
}

SCM___K93__K93_Env__events__get <- function(obj_) {
.Call('_plant_SCM___K93__K93_Env__events__get', PACKAGE = 'plant', obj_)
}

SCM___K93__K93_Env__event_log__get <- function(obj_) {
.Call('_plant_SCM___K93__K93_Env__event_log__get', PACKAGE = 'plant', obj_)
}

SCM___K93__K93_Env__ode_times__get <- function(obj_) {
.Call('_plant_SCM___K93__K93_Env__ode_times__get', PACKAGE = 'plant', obj_)
}
Expand Down Expand Up @@ -4157,6 +4221,14 @@ TF24_Environment__get_soil_number_of_depths <- function(obj_) {
.Call('_plant_TF24_Environment__get_soil_number_of_depths', PACKAGE = 'plant', obj_)
}

TF24_Environment__add_resource_pulse <- function(obj_, layer, amount) {
.Call('_plant_TF24_Environment__add_resource_pulse', PACKAGE = 'plant', obj_, layer, amount)
}

TF24_Environment__add_water_pulse <- function(obj_, depth) {
.Call('_plant_TF24_Environment__add_water_pulse', PACKAGE = 'plant', obj_, depth)
}

TF24_Environment__set_soil_water_state <- function(obj_, state) {
invisible(.Call('_plant_TF24_Environment__set_soil_water_state', PACKAGE = 'plant', obj_, state))
}
Expand Down
Loading
Loading