You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
### Using `TimeStepModel`to manage multi-rate coupling
98
98
99
99
The second example shows the complementary case. Here we explicitly ask one model
100
100
to run hourly, even though its source data arrives every 30 minutes. Once we do
@@ -110,6 +110,8 @@ reduction policy on the source model itself with `output_policy(...)`. Since `A`
110
110
has a unique producer on the same scale, PlantSimEngine can infer the source
111
111
automatically and reuse that policy.
112
112
113
+
Let's define a simple 30-minute source model that produces a constant value `A=1.0` every time it runs, and declare that its output should be integrated when consumed by a slower model:
Note that `output_policy(...)` says that when a slower model consumes `A`, the default is to integrate it over the coarser time window, using the duration of each source row as weights.
125
130
131
+
Now we define a simple hourly model that consumes `A` and also reads hourly mean temperature from the meteo:
@@ -131,7 +139,16 @@ function PlantSimEngine.run!(::TutorialHourlyIntegratorModel, models, status, me
131
139
status.A_hourly = status.A
132
140
status.T_hourly = meteo.T
133
141
end
142
+
```
143
+
144
+
!!! note
145
+
We make two deliberate simplifications here to keep the example compact:
146
+
1. The hourly model simply copies the integrated `A` value into a new variable called `A_hourly`. This is bad design in a real model because it creates unnecessary variables and makes the data flow less transparent. In a real model, you would typically consume `A` directly and let the integrated value be called `A` as well. However, here we create a separate variable to make it obvious that the hourly model is receiving an aggregated version of the original `A`.
147
+
2. We don't define an `output_policy(...)` for the hourly model, because it is not consumed by any slower model. Usually, developers are encouraged to define `output_policy(...)` for all models, but here we omit it for the hourly model to keep the example compact.
148
+
149
+
Now we can declare a mapping that says the hourly model runs every hour, even though its source data arrives every 30 minutes. We also declare how to reduce the meteorological inputs to match the hourly cadence:
Setting the `TimeStepModel(Hour(1))` forces the second model to run hourly. Since it consumes `A` from the first model, PlantSimEngine looks at the source model's `output_policy(...)` and sees that it should integrate `A` over the hour using the duration of each 30-minute row as weights.
163
+
164
+
!!! note
165
+
If we had omitted `TimeStepModel(Hour(1))`, the hourly model would have simply run on each 30-minute row, and the `output_policy(...)` on the source model would not have been triggered. The hourly model would have received the original 30-minute `A` values instead of an hourly aggregate. This illustrates the key point: `TimeStepModel(...)` is what triggers the multi-rate coupling and the use of reduction policies.
166
+
167
+
In our example, the hourly model does not declare a `timestep_hint`, so it can run at any cadence. By declaring `TimeStepModel(Hour(1))`, we explicitly force it to run hourly, which means it will receive aggregated inputs and meteo.
168
+
169
+
!!! note
170
+
Because our hourly model does not declare a `timestep_hint`, it is flexible and can run at any cadence. However, if we had declared a `timestep_hint` that did not include hourly as an acceptable cadence, then PlantSimEngine would have raised an error when we tried to force it to run hourly. Consequently, it is usually a good practice to declare a `timestep_hint` when writing a model, because it helps to ensure that the model is used in a way that is consistent with its design and intended use.
0 commit comments