Model traits
This page centralizes the model-level traits that can be defined in PlantSimEngine. It complements:
- Model execution for runtime behavior,
- Parallelization for execution over objects/time-steps.
Trait inventory for models
timespec(::Type{<:MyModel})
Defines the default execution clock of a model.
Default:
PlantSimEngine.timespec(::Type{<:AbstractModel}) = ClockSpec(1.0, 0.0)Use it when your model has a natural native clock (for example daily by default).
output_policy(::Type{<:MyModel})
Defines per-output default schedule policy for produced streams.
Default:
PlantSimEngine.output_policy(::Type{<:AbstractModel}) = NamedTuple()Behavior:
- unspecified outputs fall back to
HoldLast(); - used by runtime when resolving cross-clock reads;
- used as default policy for inferred
InputBindings(...)when users do not provide explicit bindings; - hint-only and lazy: policy is applied only for outputs that are actually consumed/exported. Declaring a policy for an unused output does not trigger integration work.
Example:
PlantSimEngine.output_policy(::Type{<:MyModel}) = (
carbon_assimilation=Integrate(),
leaf_temperature=Aggregate(MeanReducer()),
)Users can always override or complement this trait at mapping level:
ModelSpec(MyConsumerModel()) |>
InputBindings(
;
carbon_assimilation=(process=:myproducer, var=:carbon_assimilation, policy=HoldLast()), # override trait default
carbon_assimilation_max=(process=:myproducer, var=:carbon_assimilation, policy=Aggregate(MaxReducer())), # complement with extra derived input
)timestep_hint(::Type{<:MyModel})
Optional compatibility hint when TimeStepModel(...) is not provided.
Default:
PlantSimEngine.timestep_hint(::Type{<:AbstractModel}) = nothingSupported forms include:
- fixed period:
Dates.Hour(1); - range:
(Dates.Minute(30), Dates.Hour(2)); - named tuple:
(; required=..., preferred=...).
required is enforced when runtime uses meteo-derived timestep. preferred is informational only.
meteo_hint(::Type{<:MyModel})
Optional inference trait for weather sampling configuration.
Default:
PlantSimEngine.meteo_hint(::Type{<:AbstractModel}) = nothingExpected value:
(; bindings=..., window=...)Where:
bindingsis compatible withMeteoBindings(...),windowis compatible withMeteoWindow(...).
TimeStepDependencyTrait(::Type{<:MyModel})
ObjectDependencyTrait(::Type{<:MyModel})
Parallelization traits (single-scale runtime):
TimeStepDependencyTrait: depends or not on other timesteps;ObjectDependencyTrait: depends or not on other objects.
Defaults are conservative (dependent) and can be overridden when safe.
Precedence rules
Runtime precedence is intentionally explicit:
- Input policy: explicit
InputBindings(..., policy=...)> inferred from produceroutput_policy>HoldLast(). - Timestep:
TimeStepModel(...)>timespec(model)when non-default > meteo base step. - Meteo sampling: explicit
MeteoBindings(...)/MeteoWindow(...)>meteo_hint(...)> runtime defaults.
Is everything documented?
For model-level traits, the documented set is now:
timespec,output_policy,timestep_hint,meteo_hint,TimeStepDependencyTrait,ObjectDependencyTrait.
Outside model traits, PlantSimEngine also exposes data-format traits such as DataFormat for input containers (see Input types).
Naming conventions and API consistency
Current API uses two naming styles on purpose:
- snakecase for trait/query functions (
timespec, `outputpolicy,timestephint,meteohint`); - CamelCase for
ModelSpecpipeline transforms (TimeStepModel,InputBindings,MeteoBindings,MeteoWindow,OutputRouting,ScopeModel).
This distinction reflects role:
- snake_case: "what the model declares";
- CamelCase: "what the mapping config applies".
For future unification, a non-breaking path would be:
- keep existing names as stable API,
- avoid plain snakecase aliases that would collide with existing getter names (`inputbindings
,meteobindings,outputrouting,model_scope`), - if needed, add explicit config-oriented aliases with distinct names (for example
*_configforms) and keep current constructors, - evaluate deprecations only after one full release cycle and user feedback.