Skip to content

Commit 3ae1847

Browse files
committed
Make better tutorials for multirate
1 parent 7eb1c28 commit 3ae1847

6 files changed

Lines changed: 553 additions & 285 deletions

File tree

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,12 @@ An example output of a multiscale simulation is shown in the documentation of Pl
350350

351351
PlantSimEngine also supports multi-rate MTG simulations, where different models run at different cadences inside the same execution. A typical use case is to run leaf-scale processes hourly, aggregate them into daily plant-scale balances, and then export weekly summary series from the same simulation.
352352

353-
The dedicated tutorial covers the main pieces of the API, including `TimeStepModel`, `InputBindings`, `MeteoBindings`, `ScopeModel`, and `OutputRequest`:
353+
The dedicated documentation now has three pages: a short introduction to the
354+
core ideas, a fuller step-by-step tutorial, and an advanced configuration page:
354355

355-
- [Multi-rate tutorial](https://VirtualPlantLab.github.io/PlantSimEngine.jl/stable/multirate/multirate_tutorial/)
356+
- [Introduction to multi-rate execution](https://VirtualPlantLab.github.io/PlantSimEngine.jl/stable/multirate/introduction/)
357+
- [Step-by-step hourly, daily, weekly simulation](https://VirtualPlantLab.github.io/PlantSimEngine.jl/stable/multirate/multirate_tutorial/)
358+
- [Advanced multi-rate configuration](https://VirtualPlantLab.github.io/PlantSimEngine.jl/stable/multirate/advanced_configuration/)
356359

357360
## Projects that use PlantSimEngine
358361

docs/make.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ makedocs(;
6464
"Visualizing our toy plant with PlantGeom" => "./multiscale/multiscale_example_4.md",
6565
],
6666
"Multi-rate tutorials" => [
67-
"Hourly, daily, weekly simulation" => "./multirate/multirate_tutorial.md",
67+
"Introduction to multi-rate execution" => "./multirate/introduction.md",
68+
"Step-by-step hourly/daily/weekly simulation" => "./multirate/multirate_tutorial.md",
69+
"Advanced multi-rate configuration" => "./multirate/advanced_configuration.md",
6870
],
6971
"Troubleshooting and testing" => [
7072
"Troubleshooting" => "./troubleshooting_and_testing/plantsimengine_and_julia_troubleshooting.md",

docs/src/index.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,12 @@ An example output of a multiscale simulation is shown in the documentation of Pl
318318

319319
PlantSimEngine also supports multi-rate MTG simulations, where different models run at different cadences inside the same execution. A typical use case is to run leaf-scale processes hourly, aggregate them into daily plant-scale balances, and then export weekly summary series from the same simulation.
320320

321-
The dedicated tutorial covers the main pieces of the API, including `TimeStepModel`, `InputBindings`, `MeteoBindings`, `ScopeModel`, and `OutputRequest`:
321+
The dedicated documentation now has three pages: a short introduction to the
322+
core ideas, a fuller step-by-step tutorial, and an advanced configuration page:
322323

323-
- [Hourly, daily, weekly simulation](./multirate/multirate_tutorial.md)
324+
- [Introduction to multi-rate execution](./multirate/introduction.md)
325+
- [Step-by-step hourly, daily, weekly simulation](./multirate/multirate_tutorial.md)
326+
- [Advanced multi-rate configuration](./multirate/advanced_configuration.md)
324327

325328
## State of the field
326329

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# Advanced multi-rate configuration
2+
3+
This page collects the multi-rate features that were intentionally kept in the
4+
background on the first two pages:
5+
6+
- [Introduction to multi-rate execution](introduction.md) explains the core
7+
scheduling rules;
8+
- [Step-by-step multi-rate tutorial](multirate_tutorial.md) shows a complete
9+
hourly/daily/weekly MTG example with minimal configuration;
10+
- this page covers the explicit configuration tools you reach for when defaults
11+
are no longer enough.
12+
13+
The goal here is not to build another full simulation from scratch. Instead, the
14+
objective is to explain when and why you should add more explicit multi-rate
15+
declarations to a mapping.
16+
17+
## 1. When the defaults are enough
18+
19+
PlantSimEngine tries to keep simple mappings concise:
20+
21+
- if a model does not declare `TimeStepModel(...)`, it follows the meteo
22+
cadence;
23+
- if an input has a unique producer, `InputBindings(...)` can often be omitted;
24+
- if a model consumes common `Atmosphere` variables at a coarser cadence,
25+
PlantMeteo default transforms can often replace explicit `MeteoBindings(...)`;
26+
- if an exported variable has a unique canonical publisher, `OutputRequest(...)`
27+
can often omit `process=`.
28+
29+
The sections below focus on the cases where that implicit behavior becomes too
30+
ambiguous or too limiting.
31+
32+
## 2. Explicit model-to-model bindings with `InputBindings(...)`
33+
34+
The tutorial pages rely on unique-producer inference plus `output_policy(...)`
35+
declared on the source models. That is the simplest setup, but it stops being
36+
enough as soon as several candidate producers exist or when you want to override
37+
the default resampling rule.
38+
39+
Use explicit `InputBindings(...)` when:
40+
41+
- several models can produce the same input variable;
42+
- the same process exists at several reachable scales;
43+
- the source variable has a different name than the consumer input;
44+
- the producer default policy is not the policy you want for this particular
45+
connection.
46+
47+
For example, a daily plant model may need to say explicitly that it consumes the
48+
hourly leaf assimilation stream from the `:Leaf` scale and integrates it over
49+
the day:
50+
51+
```julia
52+
plant_daily_spec = ModelSpec(TutorialPlantDailyModel()) |>
53+
TimeStepModel(ClockSpec(24.0, 0.0)) |>
54+
InputBindings(;
55+
leaf_assim_h=(
56+
process=:tutorialleafhourly,
57+
scale=:Leaf,
58+
var=:leaf_assim_h,
59+
policy=Integrate(),
60+
),
61+
)
62+
```
63+
64+
This is more verbose than inference, but the resulting mapping is also more
65+
explicit: anyone reading it can see exactly where the data comes from and how it
66+
is reduced.
67+
68+
## 3. Explicit meteorological aggregation with `MeteoBindings(...)`
69+
70+
For common `Atmosphere` variables, PlantSimEngine delegates weather sampling to
71+
PlantMeteo, and PlantMeteo already defines default transforms. In practice, this
72+
means you often do not need `MeteoBindings(...)` for variables such as `T`,
73+
`Rh`, or aliases like `Ri_SW_q`.
74+
75+
Add explicit `MeteoBindings(...)` when:
76+
77+
- you want a non-default reducer;
78+
- the target variable should come from a differently named source variable;
79+
- the variable is not covered by PlantMeteo defaults;
80+
- you want the mapping itself to document the intended weather aggregation rule.
81+
82+
For example, this daily model makes the defaults explicit for temperature and
83+
shortwave radiation energy:
84+
85+
```julia
86+
plant_daily_spec = ModelSpec(TutorialPlantDailyModel()) |>
87+
TimeStepModel(ClockSpec(24.0, 0.0)) |>
88+
MeteoBindings(
89+
;
90+
T=MeanWeighted(),
91+
Ri_SW_q=(source=:Ri_SW_f, reducer=RadiationEnergy()),
92+
)
93+
```
94+
95+
And this variant shows a more genuinely custom rule:
96+
97+
```julia
98+
plant_daily_spec = ModelSpec(TutorialPlantDailyModel()) |>
99+
TimeStepModel(ClockSpec(24.0, 0.0)) |>
100+
MeteoBindings(
101+
;
102+
T=(source=:T, reducer=MaxReducer()),
103+
rad_peak=(source=:Ri_SW_f, reducer=MaxReducer()),
104+
)
105+
```
106+
107+
The important point is that `MeteoBindings(...)` is not only about reducing
108+
weather from fast to slow. It is also a way to state the semantics of that
109+
reduction explicitly.
110+
111+
## 4. Calendar-aligned windows with `MeteoWindow(...)`
112+
113+
By default, coarser meteo sampling uses rolling windows that follow the model
114+
clock. That is often sufficient, but some models are tied to civil periods such
115+
as "the current day" or "the current week".
116+
117+
In those cases, use `MeteoWindow(...)` to replace the default trailing window
118+
with a calendar-aligned one:
119+
120+
```julia
121+
plant_daily_spec = ModelSpec(TutorialPlantDailyModel()) |>
122+
TimeStepModel(ClockSpec(24.0, 0.0)) |>
123+
MeteoWindow(
124+
CalendarWindow(
125+
:day;
126+
anchor=:current_period,
127+
week_start=1,
128+
completeness=:strict,
129+
),
130+
)
131+
```
132+
133+
This becomes important when a daily or weekly model should aggregate over civil
134+
days or weeks rather than over "the last 24 hours" or "the last 168 hours".
135+
136+
## 5. Exporting streams with `OutputRequest(...)`
137+
138+
The second tutorial page uses `OutputRequest(...)` to materialize clean
139+
hourly/daily/weekly tables from the simulation streams. The simple form works
140+
well when the requested variable has a unique canonical publisher:
141+
142+
```julia
143+
req_plant_daily = OutputRequest(:Plant, :plant_assim_d;
144+
name=:plant_assim_daily,
145+
clock=ClockSpec(24.0, 0.0),
146+
)
147+
```
148+
149+
More complex mappings often need more explicit requests. In particular, add
150+
`process=` when several models can publish the same variable, and add `policy=`
151+
when you need a specific export-time resampling behavior:
152+
153+
```julia
154+
req_daily_energy = OutputRequest(:Leaf, :leaf_assim_h;
155+
name=:leaf_energy_daily,
156+
process=:tutorialleafhourly,
157+
policy=Integrate(),
158+
clock=ClockSpec(24.0, 0.0),
159+
)
160+
161+
req_hourly_hold = OutputRequest(:Plant, :plant_assim_d;
162+
name=:plant_assim_hold_hourly,
163+
process=:tutorialplantdaily,
164+
policy=HoldLast(),
165+
clock=ClockSpec(1.0, 0.0),
166+
)
167+
```
168+
169+
So `OutputRequest(...)` is not just a way to rename a column. It is also a
170+
declaration of which stream you want, at which cadence, and with which
171+
resampling policy.
172+
173+
## 6. Scopes in larger MTGs
174+
175+
The first two pages use a minimal MTG with one plant, so `ScopeModel(...)` is
176+
not needed there. In a larger scene, however, several plants may contain the
177+
same scales and the same processes. In that case, scopes control how streams are
178+
partitioned across the MTG.
179+
180+
Typical choices are:
181+
182+
- `ScopeModel(:global)` to share a stream across the whole simulation;
183+
- `ScopeModel(:plant)` to isolate streams within each plant subtree;
184+
- `ScopeModel(:scene)` to isolate them within each scene;
185+
- `ScopeModel(:self)` to keep a stream attached to each individual node.
186+
187+
Once a mapping contains repeated scales and repeated processes, adding the right
188+
scope is often just as important as choosing the right timestep.
189+
190+
## 7. Inspect resolved configuration
191+
192+
When a mapping mixes inferred bindings, explicit bindings, custom meteo
193+
aggregation, scopes, and export requests, it becomes difficult to reason about
194+
the final resolved configuration by inspection alone.
195+
196+
That is where `explain_model_specs(...)` and `resolved_model_specs(...)` become
197+
useful:
198+
199+
```julia
200+
explain_model_specs(mapping)
201+
202+
resolved = resolved_model_specs(mapping)
203+
resolved[:Plant]
204+
```
205+
206+
These helpers let you confirm:
207+
208+
- the effective timestep of each model;
209+
- the resolved input bindings;
210+
- the resolved meteo bindings;
211+
- the active meteo window.
212+
213+
In practice, this is often the fastest way to debug a multi-rate mapping before
214+
running a larger simulation.
215+
216+
## 8. How to choose between the three pages
217+
218+
Use the pages in this order:
219+
220+
1. start with [Introduction to multi-rate execution](introduction.md) if you
221+
want to understand the scheduling rules;
222+
2. continue with [Step-by-step multi-rate tutorial](multirate_tutorial.md) for
223+
a complete but compact MTG example;
224+
3. come back to this page when you need explicit bindings, explicit meteo
225+
aggregation, custom export requests, scopes, or debugging helpers.

0 commit comments

Comments
 (0)