|
8 | 8 | 2. Then, models that have a dependency on other models are run. The first ones are the ones that depend on an independent model. Then the ones that are children of the second ones, and then their children ... until no children are found anymore. There are two types of children models (*i.e.* dependencies): hard and soft dependencies: |
9 | 9 | 1. Hard dependencies are always run before soft dependencies. A hard dependency is a model that is directly called by another model. It is declared as such by its parent that lists its hard-dependencies as `dep`. See [this example](https://github.com/VirtualPlantLab/PlantSimEngine.jl/blob/3d91bb053ddbd087d38dcffcedd33a9db35a0fcc/examples/dummy.jl#L39) that shows `Process2Model` defining a hard dependency on any model that simulates `process1`. |
10 | 10 | 2. Soft dependencies are then run sequentially. A model has a soft dependency on another model if one or more of its inputs is computed by another model. If a soft dependency has several parent nodes (*e.g.* two different models compute two inputs of the model), it is run only if all its parent nodes have been run already. In practice, when we visit a node that has one of its parent that did not run already, we stop the visit of this branch. The node will eventually be visited from the branch of the last parent that was run. |
| 11 | + |
| 12 | +## Multi-rate model configuration (experimental) |
| 13 | + |
| 14 | +For multiscale simulations, model usage is configured in the mapping through `ModelSpec` transforms: |
| 15 | + |
| 16 | +- `TimeStepModel(...)`: sets model execution clock. |
| 17 | +- `InputBindings(...)`: sets producer, source variable, optional source scale, and policy for each consumer input. |
| 18 | +- `OutputRouting(...)`: sets whether an output is canonical (`:canonical`) or stream-only (`:stream_only`). |
| 19 | + |
| 20 | +Typical pipeline form: |
| 21 | + |
| 22 | +```julia |
| 23 | +ModelSpec(MyModel()) |> |
| 24 | +TimeStepModel(ClockSpec(24.0, 1.0)) |> |
| 25 | +InputBindings(; x=(process=:producer, var=:y, policy=HoldLast())) |> |
| 26 | +OutputRouting(; z=:stream_only) |
| 27 | +``` |
| 28 | + |
| 29 | +### Hold-last coupling (default policy) |
| 30 | + |
| 31 | +```julia |
| 32 | +mapping = Dict( |
| 33 | + "Leaf" => ( |
| 34 | + ModelSpec(LeafSourceModel()) |> TimeStepModel(1.0), |
| 35 | + ModelSpec(LeafConsumerModel()) |> |
| 36 | + TimeStepModel(ClockSpec(2.0, 1.0)) |> |
| 37 | + InputBindings(; C=(process=:leafsource, var=:S)), |
| 38 | + ), |
| 39 | +) |
| 40 | +``` |
| 41 | + |
| 42 | +### Daily integration from hourly stream |
| 43 | + |
| 44 | +```julia |
| 45 | +mapping = Dict( |
| 46 | + "Leaf" => ( |
| 47 | + ModelSpec(HourlyAssimModel()) |> TimeStepModel(1.0), |
| 48 | + ), |
| 49 | + "Plant" => ( |
| 50 | + ModelSpec(DailyCarbonOfferModel()) |> |
| 51 | + TimeStepModel(ClockSpec(24.0, 1.0)) |> |
| 52 | + InputBindings(; A=(process=:hourlyassim, var=:A, scale="Leaf", policy=Integrate())), |
| 53 | + ), |
| 54 | +) |
| 55 | +``` |
| 56 | + |
| 57 | +### Interpolate slow producer to fast consumer |
| 58 | + |
| 59 | +```julia |
| 60 | +mapping = Dict( |
| 61 | + "Leaf" => ( |
| 62 | + ModelSpec(SlowSourceModel()) |> TimeStepModel(ClockSpec(2.0, 1.0)), |
| 63 | + ModelSpec(FastConsumerModel()) |> |
| 64 | + TimeStepModel(1.0) |> |
| 65 | + InputBindings(; X=(process=:slowsource, var=:X, policy=Interpolate())), |
| 66 | + ), |
| 67 | +) |
| 68 | +``` |
| 69 | + |
| 70 | +When `multirate=true` is passed to `run!`, the runtime resolves inputs from producer temporal streams according to these policies. |
0 commit comments