@@ -16,25 +16,24 @@ it exemplifies how to create your own custom monitoring.
1616    sys.path.append(' scripts'  ) 
1717    from  advection_model import  advect_model, advect_model_src 
1818
19-  The following imports are necessary for the examples below.
19+  Let's use the following setup for the examples below. It is based on the
20+ ``advect_model `` created in Section :ref: `create_model `.
2021
2122.. ipython :: python 
2223
2324    import  xsimlab as  xs 
2425
25-  .. ipython :: python 
26-    :suppress: 
27- 
2826    in_ds =  xs.create_setup( 
2927        model = advect_model, 
3028        clocks = { 
31-             ' time'  : np.linspace(0 ., 1 ., 5 ), 
29+             ' time'  : np.linspace(0 ., 1 ., 6 ), 
3230        }, 
3331        input_vars = { 
3432            ' grid'  : {' length'  : 1.5 , ' spacing'  : 0.01 }, 
3533            ' init'  : {' loc'  : 0.3 , ' scale'  : 0.1 }, 
3634            ' advect__v'  : 1 . 
3735        }, 
36+         output_vars = {' profile__u'  : ' time'  } 
3837    ) 
3938
4039
@@ -172,3 +171,41 @@ methods that may share some state:
172171
173172   with  PrintStepTime(): 
174173       in_ds.xsimlab.run(model = advect_model) 
174+ 
175+ 
176+  Control simulation runtime
177+ -------------------------- 
178+ 
179+ Runtime hook functions may return a :class: `~xsimlab.RuntimeSignal ` so that you
180+ can control the simulation workflow (e.g., skip the current stage or process,
181+ break the simulation time steps) based on some condition or some computed value.
182+ 
183+ In the example below, the simulation stops as soon as the gaussian pulse (peak
184+ value) has been advected past ``x = 0.4 ``.
185+ 
186+ .. ipython ::
187+ 
188+    In [2]: @xs.runtime_hook("run_step", "model", "post")
189+       ...: def maybe_stop(model, context, state):
190+       ...:     peak_idx = np.argmax(state[('profile', 'u')])
191+       ...:     peak_x = state[('grid', 'x')][peak_idx]
192+       ...:
193+       ...:     if peak_x > 0.4:
194+       ...:         print("Peak crossed x=0.4, stop simulation!")
195+       ...:         return xs.RuntimeSignal.BREAK
196+       ...:
197+ 
198+    In [3]: out_ds = in_ds.xsimlab.run(
199+       ...:     model=advect_model,
200+       ...:     hooks=[print_step_start, maybe_stop]
201+       ...: )
202+ 
203+ Even when a simulation stops early like in the example above, the resulting
204+ xarray Dataset still contains all time steps defined in the input Dataset.
205+ Output variables have fill (masked) values for the time steps that were not run,
206+ as shown below with the ``nan `` values for ``profile__u `` (fill values are not
207+ stored physically in the Zarr output store).
208+ 
209+ .. ipython :: python 
210+ 
211+    out_ds 
0 commit comments