Skill Tracer
Skills › Scientific Agent Skills › fluidsim › simulation_workflow.md

simulation_workflow.md

357 lines · skills/fluidsim/references/simulation_workflow.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Bounded simulation, pilot, and restart workflow
2

Bounded simulation, pilot, and restart workflow

Raw lines 1 to 2
3## 1. Define the scientific contract
4
5Before code, record:
6
7- Equations, dependent variables, approximations, and solver key.
8- Units for every dimensional quantity, or reference scales and a complete
9 nondimensionalization map.
10- Domain lengths, geometry, periodic boundary conditions, and symmetries.
11- Initial-condition construction, constraints, amplitude/spectrum, and seed.
12- Forcing field, band, normalization, correlation, and expected/measured input.
13- Dissipation and any hypo-/hyper-viscosity.
14- Observables and acceptance thresholds.
15- Conservation/budget identities and expected numerical residual behavior.
16- Grid, dealiasing, timestep/CFL, and refinement plan.
17- Independent benchmark or verification target.
19Do not proceed from a prompt that only says “simulate turbulence” or supplies a
20Reynolds number without its definition and scaling.

1. Define the scientific contract

Before code, record:

  • Equations, dependent variables, approximations, and solver key.
  • Units for every dimensional quantity, or reference scales and a complete nondimensionalization map.
  • Domain lengths, geometry, periodic boundary conditions, and symmetries.
  • Initial-condition construction, constraints, amplitude/spectrum, and seed.
  • Forcing field, band, normalization, correlation, and expected/measured input.
  • Dissipation and any hypo-/hyper-viscosity.
  • Observables and acceptance thresholds.
  • Conservation/budget identities and expected numerical residual behavior.
  • Grid, dealiasing, timestep/CFL, and refinement plan.
  • Independent benchmark or verification target.

Do not proceed from a prompt that only says “simulate turbulence” or supplies a Reynolds number without its definition and scaling.

Raw lines 3 to 21
22## 2. Declare operational bounds
24Every plan must explicitly bound:
26- CPU cores.
27- MPI ranks and threads/rank.
28- Total and per-rank RAM envelope.
29- Disk bytes and file/inode count.
30- Wall time and FluidSim `max_elapsed`.
31- Grid dimensions and total points.
32- State snapshot and diagnostic save periods.
33- Safe output root and subdirectory.
35The bundled JSON schema requires these fields. Start from:
37```bash
38python3 scripts/solver_config_validator.py --example
39```
41Save the reviewed JSON locally, then:
43```bash
44python3 scripts/solver_config_validator.py --config config.json
45python3 scripts/grid_resource_estimator.py --config config.json
46python3 scripts/simulation_dry_run.py --config config.json --output run.py
47```
49The resource estimator reports an approximate allocation/storage model, not
50measured peaks or enforced quotas. Save records are counted independently of
51the declared file limit; exceeding a limit is a failure, never a truncated
52estimate. Enabled diagnostics outside physical fields, spectra, spectral budget,
53and spatial means require a separate estimate. Iteration-only termination does
54not provide the time horizon this storage model needs.
56The generator does not import FluidSim or run anything. The generated script
57prints a JSON dry run by default. Execution requires both `--execute` and the
58exact reviewed config ID. An MPI plan is only a command preview; the tool never
59invokes a launcher or scheduler.

2. Declare operational bounds

Every plan must explicitly bound:

  • CPU cores.
  • MPI ranks and threads/rank.
  • Total and per-rank RAM envelope.
  • Disk bytes and file/inode count.
  • Wall time and FluidSim max_elapsed.
  • Grid dimensions and total points.
  • State snapshot and diagnostic save periods.
  • Safe output root and subdirectory.

The bundled JSON schema requires these fields. Start from:

python3 scripts/solver_config_validator.py --example

Save the reviewed JSON locally, then:

python3 scripts/solver_config_validator.py --config config.json
python3 scripts/grid_resource_estimator.py --config config.json
python3 scripts/simulation_dry_run.py --config config.json --output run.py

The resource estimator reports an approximate allocation/storage model, not measured peaks or enforced quotas. Save records are counted independently of the declared file limit; exceeding a limit is a failure, never a truncated estimate. Enabled diagnostics outside physical fields, spectra, spectral budget, and spatial means require a separate estimate. Iteration-only termination does not provide the time horizon this storage model needs.

The generator does not import FluidSim or run anything. The generated script prints a JSON dry run by default. Execution requires both --execute and the exact reviewed config ID. An MPI plan is only a command preview; the tool never invokes a launcher or scheduler.

Raw lines 22 to 60
Runs code python3 scripts/solver_config_validator.py :38
Runs code python3 scripts/grid_resource_estimator.py :45
Runs code python3 scripts/simulation_dry_run.py :46
61## 3. Verify the locked environment
63In an isolated exact environment:
65```python
66from importlib.metadata import version
67from fluidfft import get_methods
69assert version("fluidsim") == "0.9.0"
70assert version("fluidfft") == "0.4.5"
71print(sorted(get_methods()))
72```
74Record registered FFT methods, then load and exercise the chosen method.
75`get_methods()` lists entry points even when an optional dependency is absent
76(for example Dask). Importing a package is not enough: construct the selected
77solver's defaults and run its tiny transform/solver smoke.

3. Verify the locked environment

In an isolated exact environment:

from importlib.metadata import version
from fluidfft import get_methods

assert version("fluidsim") == "0.9.0"
assert version("fluidfft") == "0.4.5"
print(sorted(get_methods()))

Record registered FFT methods, then load and exercise the chosen method. get_methods() lists entry points even when an optional dependency is absent (for example Dask). Importing a package is not enough: construct the selected solver's defaults and run its tiny transform/solver smoke.

Raw lines 61 to 78
79## 4. Tiny no-output serial smoke
81After approval, use a trivial, bounded state:
83```python
84from fluidsim.solvers.ns2d.solver import Simul
86params = Simul.create_default_params()
87params.oper.nx = params.oper.ny = 8
88params.oper.Lx = params.oper.Ly = 2.0
89params.oper.coef_dealiasing = 2 / 3
90params.time_stepping.USE_CFL = False
91params.time_stepping.deltat0 = 0.001
92params.time_stepping.deltat_max = 0.001
93params.time_stepping.t_end = 0.001
94params.time_stepping.max_elapsed = "00:01:00"
95params.init_fields.type = "constant"
96params.init_fields.constant.value = 0.0
97params.output.HAS_TO_SAVE = False
98params.output.ONLINE_PLOT_OK = False
100sim = Simul(params)
101sim.time_stepping.start()
102```
104This checks import, FFT construction, initialization, and one bounded step. It
105does not test the intended physics, forcing, conservation, convergence,
106performance, output, or restart.

4. Tiny no-output serial smoke

After approval, use a trivial, bounded state:

from fluidsim.solvers.ns2d.solver import Simul

params = Simul.create_default_params()
params.oper.nx = params.oper.ny = 8
params.oper.Lx = params.oper.Ly = 2.0
params.oper.coef_dealiasing = 2 / 3
params.time_stepping.USE_CFL = False
params.time_stepping.deltat0 = 0.001
params.time_stepping.deltat_max = 0.001
params.time_stepping.t_end = 0.001
params.time_stepping.max_elapsed = "00:01:00"
params.init_fields.type = "constant"
params.init_fields.constant.value = 0.0
params.output.HAS_TO_SAVE = False
params.output.ONLINE_PLOT_OK = False

sim = Simul(params)
sim.time_stepping.start()

This checks import, FFT construction, initialization, and one bounded step. It does not test the intended physics, forcing, conservation, convergence, performance, output, or restart.

Raw lines 79 to 107
108## 5. Tiny output/restart smoke
110Use a dedicated empty output root under a quota. Keep:
112- `params.output.sub_directory` a safe one-component study identifier.
113- `ONLINE_PLOT_OK = False` for unattended runs.
114- Short `t_end`, short `max_elapsed`, and low resolution.
115- One or two physical-state saves and a bounded scalar diagnostic.
116- Spectra/budget outputs disabled unless they are the feature being tested.
118Inspect before analysis:
120```bash
121python3 scripts/output_inventory.py --path fluidsim-runs
122python3 scripts/budget_summary.py --path fluidsim-runs
123```
125Confirm exact filenames and growth. FluidSim 0.9 defaults to
126`state_phys_t*.nc` for physical states; spectra remain HDF5.

5. Tiny output/restart smoke

Use a dedicated empty output root under a quota. Keep:

  • params.output.sub_directory a safe one-component study identifier.
  • ONLINE_PLOT_OK = False for unattended runs.
  • Short t_end, short max_elapsed, and low resolution.
  • One or two physical-state saves and a bounded scalar diagnostic.
  • Spectra/budget outputs disabled unless they are the feature being tested.

Inspect before analysis:

python3 scripts/output_inventory.py --path fluidsim-runs
python3 scripts/budget_summary.py --path fluidsim-runs

Confirm exact filenames and growth. FluidSim 0.9 defaults to state_phys_t*.nc for physical states; spectra remain HDF5.

Raw lines 108 to 127
Runs code python3 scripts/output_inventory.py :121
Runs code python3 scripts/budget_summary.py :122
128## 6. Representative scientific pilot
130Increase only enough to exercise the intended:
132- Initial-condition path.
133- Forcing type and injection normalization.
134- Solver-specific state and outputs.
135- FFT backend.
136- Checkpoint and restart.
137- Analysis code.
139During and after the pilot, check:
141- CFL and `deltat` history against all relevant wave/advection/diffusion limits.
142- Divergence or other constraints.
143- Energy/enstrophy/scalar/potential-energy budgets as appropriate.
144- Measured forcing input and dissipation.
145- Spectral tails and dealiasing contamination.
146- Runtime, peak RSS, per-rank imbalance, file count, and disk growth.
147- NaN/Inf, stalled advancement, unexpected truncation, and incomplete files.
149A passing pilot permits planning a refinement study; it does not validate a
150production run.

6. Representative scientific pilot

Increase only enough to exercise the intended:

  • Initial-condition path.
  • Forcing type and injection normalization.
  • Solver-specific state and outputs.
  • FFT backend.
  • Checkpoint and restart.
  • Analysis code.

During and after the pilot, check:

  • CFL and deltat history against all relevant wave/advection/diffusion limits.
  • Divergence or other constraints.
  • Energy/enstrophy/scalar/potential-energy budgets as appropriate.
  • Measured forcing input and dissipation.
  • Spectral tails and dealiasing contamination.
  • Runtime, peak RSS, per-rank imbalance, file count, and disk growth.
  • NaN/Inf, stalled advancement, unexpected truncation, and incomplete files.

A passing pilot permits planning a refinement study; it does not validate a production run.

Raw lines 128 to 151
152## 7. Running a reviewed serial plan
154The generated script is deliberately gated:
156```bash
157python3 run.py
158python3 run.py --execute --acknowledge-config-id REVIEWED_CONFIG_ID
159```
161At execution, it verifies the installed FluidSim/FluidFFT versions, assigns
162reviewed thread limits before NumPy import, and checks the actual MPI size.
163Restart paths are anchored to the script directory and rehashed before loading;
164use a matching `provenance.restart.path` and `init_fields.from_file.path`.
165These are preflight checks, not RAM/disk/CPU quota enforcement.
167The first command is dry-run only. The second is a real simulation and must be
168issued by the user or approved operator after reviewing limits and output
169destination.
171Never silently increase resolution, duration, save frequency, rank count, or
172wall time after approval.

7. Running a reviewed serial plan

The generated script is deliberately gated:

python3 run.py
python3 run.py --execute --acknowledge-config-id REVIEWED_CONFIG_ID

At execution, it verifies the installed FluidSim/FluidFFT versions, assigns reviewed thread limits before NumPy import, and checks the actual MPI size. Restart paths are anchored to the script directory and rehashed before loading; use a matching provenance.restart.path and init_fields.from_file.path. These are preflight checks, not RAM/disk/CPU quota enforcement.

The first command is dry-run only. The second is a real simulation and must be issued by the user or approved operator after reviewing limits and output destination.

Never silently increase resolution, duration, save frequency, rank count, or wall time after approval.

Raw lines 152 to 173
Runs code python3 run.py :157
174## 8. Read-only loading
176Use the lightweight loader:
178```python
179from fluidsim import load_sim_for_plot
181sim = load_sim_for_plot(
182 "run-directory",
183 merge_missing_params=False,
184 hide_stdout=True,
186```
188Use native loaders only on trusted run metadata: they import the recorded
189solver/extension modules. For untrusted files, start with the bounded metadata
190helpers instead.
192Official 0.9 source shows that it:
194- Loads solver and parameters from the result directory.
195- Sets a constant initialization and coarse operator.
196- Sets `NEW_DIR_RESULTS = False`.
197- Sets `output.HAS_TO_SAVE = False` and `ONLINE_PLOT_OK = False`.
198- Selects default/sequential FFT for plotting.
199- Can merge missing defaults for older runs when explicitly requested.
201`merge_missing_params=True` helps load old metadata but does not prove that an
202old result is scientifically or numerically equivalent under the new version.

8. Read-only loading

Use the lightweight loader:

from fluidsim import load_sim_for_plot

sim = load_sim_for_plot(
    "run-directory",
    merge_missing_params=False,
    hide_stdout=True,
)

Use native loaders only on trusted run metadata: they import the recorded solver/extension modules. For untrusted files, start with the bounded metadata helpers instead.

Official 0.9 source shows that it:

  • Loads solver and parameters from the result directory.
  • Sets a constant initialization and coarse operator.
  • Sets NEW_DIR_RESULTS = False.
  • Sets output.HAS_TO_SAVE = False and ONLINE_PLOT_OK = False.
  • Selects default/sequential FFT for plotting.
  • Can merge missing defaults for older runs when explicitly requested.

merge_missing_params=True helps load old metadata but does not prove that an old result is scientifically or numerically equivalent under the new version.

Raw lines 174 to 203
204## 9. State-bearing loading
206```python
207from fluidsim import load_state_phys_file
209sim = load_state_phys_file(
210 "run-directory",
211 t_approx="last",
212 modif_save_params=True,
213 merge_missing_params=False,
214 init_with_initialized_state=True,
215 hide_stdout=True,
217```
219This constructs a full-resolution operator and loads state; it can be expensive.
220With the default `modif_save_params=True`, saving and online plotting are
221disabled. Loading a state object is not the same as approving a restart.

9. State-bearing loading

from fluidsim import load_state_phys_file

sim = load_state_phys_file(
    "run-directory",
    t_approx="last",
    modif_save_params=True,
    merge_missing_params=False,
    init_with_initialized_state=True,
    hide_stdout=True,
)

This constructs a full-resolution operator and loads state; it can be expensive. With the default modif_save_params=True, saving and online plotting are disabled. Loading a state object is not the same as approving a restart.

Raw lines 204 to 222
223## 10. Reviewed Python restart
225First compare metadata:
227```bash
228python3 scripts/restart_compatibility.py \
229 --source state_phys_t001.000.nc \
230 --target-config restart-config.json
231```
233The checker uses required state keys and dataset shapes/dtypes, not just a
234nonempty `/state_phys` group. It requires grid/domain metadata and finite state
235time. For a directory it examines at most 256 entries in that run, selecting by
236stored time/iteration rather than filename ordering; ambiguous latest states
237require an explicit file. Soft/external links are rejected. For time-correlated
238forcing, `/state_params/forcing` must contain `seed0`, `seed1`, and
239`t_last_change`. A JSON manifest must provide `state.dataset_metadata` entries
240with `shape` and `numeric: true` for each required field; its digest is a
241declaration, unlike a digest computed from the checkpoint.
243Then, after approval:
245```python
246from fluidsim import load_for_restart
248params, Simul = load_for_restart(
249 "run-directory",
250 t_approx="last",
251 merge_missing_params=False,
253params.time_stepping.t_end = 2.0
254params.time_stepping.max_elapsed = "00:10:00"
255params.NEW_DIR_RESULTS = True
257sim = Simul(params)
258sim.time_stepping.start()
259```
261`load_for_restart` reads parameters from `/info_simul/params`, sets
262`init_fields.type = "from_file"`, points it to the selected state file, and by
263default sets `NEW_DIR_RESULTS = False`. Explicitly choose append versus new
264directory. Never append to an irreplaceable run without a backup and checksum.
266Record:
268- Parent run ID/path and state SHA-256.
269- Selected state time/iteration.
270- Parent and child package/backend/platform versions.
271- Every changed parameter and justification.
272- Append/new-directory decision.
273- Forcing state continuity.
274- Child output inventory and lock/script/config hashes.
276FluidSim 0.9.0 stores “state parameters” in restarting files. FluidSim 0.8.6
277fixed incorrect restart of time-correlated forcing; old checkpoints need extra
278review.

10. Reviewed Python restart

First compare metadata:

python3 scripts/restart_compatibility.py \
  --source state_phys_t001.000.nc \
  --target-config restart-config.json

The checker uses required state keys and dataset shapes/dtypes, not just a nonempty /state_phys group. It requires grid/domain metadata and finite state time. For a directory it examines at most 256 entries in that run, selecting by stored time/iteration rather than filename ordering; ambiguous latest states require an explicit file. Soft/external links are rejected. For time-correlated forcing, /state_params/forcing must contain seed0, seed1, and t_last_change. A JSON manifest must provide state.dataset_metadata entries with shape and numeric: true for each required field; its digest is a declaration, unlike a digest computed from the checkpoint.

Then, after approval:

from fluidsim import load_for_restart

params, Simul = load_for_restart(
    "run-directory",
    t_approx="last",
    merge_missing_params=False,
)
params.time_stepping.t_end = 2.0
params.time_stepping.max_elapsed = "00:10:00"
params.NEW_DIR_RESULTS = True

sim = Simul(params)
sim.time_stepping.start()

load_for_restart reads parameters from /info_simul/params, sets init_fields.type = "from_file", points it to the selected state file, and by default sets NEW_DIR_RESULTS = False. Explicitly choose append versus new directory. Never append to an irreplaceable run without a backup and checksum.

Record:

  • Parent run ID/path and state SHA-256.
  • Selected state time/iteration.
  • Parent and child package/backend/platform versions.
  • Every changed parameter and justification.
  • Append/new-directory decision.
  • Forcing state continuity.
  • Child output inventory and lock/script/config hashes.

FluidSim 0.9.0 stores “state parameters” in restarting files. FluidSim 0.8.6 fixed incorrect restart of time-correlated forcing; old checkpoints need extra review.

Raw lines 223 to 279
Runs code python3 scripts/restart_compatibility.py :228
Runs code script/config :274
280## 11. Upstream restart CLI
282Safe first action:
284```bash
285fluidsim-restart --only-check run-directory --t_end 2.0
286```
288Current options include `--only-check`, `--only-init`, `--new-dir-results`,
289`--t_approx`, target/additive time or iteration bounds,
290`--merge-missing-params`, and `--max-elapsed`.
292Avoid `--modify-params` with any untrusted or generated text. Official source
293passes that string to Python code execution. The bundled generator never emits
294this option.
296The CLI does not supply scheduler resource limits. Running it under MPI or a
297scheduler remains a separate, explicit operational action.

11. Upstream restart CLI

Safe first action:

fluidsim-restart --only-check run-directory --t_end 2.0

Current options include --only-check, --only-init, --new-dir-results, --t_approx, target/additive time or iteration bounds, --merge-missing-params, and --max-elapsed.

Avoid --modify-params with any untrusted or generated text. Official source passes that string to Python code execution. The bundled generator never emits this option.

The CLI does not supply scheduler resource limits. Running it under MPI or a scheduler remains a separate, explicit operational action.

Raw lines 280 to 298
299## 12. Resolution changes
301Do not change `oper.nx/ny/nz` and treat an old state file as directly compatible.
302FluidSim provides:
304```bash
305fluidsim-modif-resolution run-directory 5/4
306```
308This creates a new state at modified resolution. Before use:
310- Inventory free memory and disk; interpolation/FFT can be expensive.
311- Preserve the original state.
312- Record coefficient, source/output hashes, and implementation version.
313- Check domain, state keys, normalization, and constraints.
314- Treat the child as a new numerical experiment.
315- Re-run transient, budget, spectral, and refinement checks.
317Do not run this automatically or on a large state by default.

12. Resolution changes

Do not change oper.nx/ny/nz and treat an old state file as directly compatible. FluidSim provides:

fluidsim-modif-resolution run-directory 5/4

This creates a new state at modified resolution. Before use:

  • Inventory free memory and disk; interpolation/FFT can be expensive.
  • Preserve the original state.
  • Record coefficient, source/output hashes, and implementation version.
  • Check domain, state keys, normalization, and constraints.
  • Treat the child as a new numerical experiment.
  • Re-run transient, budget, spectral, and refinement checks.

Do not run this automatically or on a large state by default.

Raw lines 299 to 318
319## 13. MPI/HPC handoff
321After a serial pilot:
3231. Ask the site scheduler for the intended allocation; never submit from this
324 skill.
3252. Verify the pinned MPI/FluidFFT environment inside that allocation.
3263. Run a manually launched tiny two-rank smoke.
3274. Benchmark candidate FFT methods on representative small shapes.
3285. Confirm decomposition compatibility and local array sizes.
3296. Set explicit process/thread affinity.
3307. Set memory/rank, wall time, scratch, output quota, and signal/checkpoint
331 behavior.
3328. Use a short restartable pilot before scale-up.
334The 2019 FluidSim/FluidFFT performance results are hardware- and shape-specific.
335Do not extrapolate their wall times or fastest backend to another cluster.

13. MPI/HPC handoff

After a serial pilot:

  1. Ask the site scheduler for the intended allocation; never submit from this skill.
  2. Verify the pinned MPI/FluidFFT environment inside that allocation.
  3. Run a manually launched tiny two-rank smoke.
  4. Benchmark candidate FFT methods on representative small shapes.
  5. Confirm decomposition compatibility and local array sizes.
  6. Set explicit process/thread affinity.
  7. Set memory/rank, wall time, scratch, output quota, and signal/checkpoint behavior.
  8. Use a short restartable pilot before scale-up.

The 2019 FluidSim/FluidFFT performance results are hardware- and shape-specific. Do not extrapolate their wall times or fastest backend to another cluster.

Raw lines 319 to 336
337## Failure and interruption handling
339- Preserve logs and last complete checkpoint.
340- Treat a signal-terminated or wall-time-limited run as incomplete until the
341 checkpoint is inventoried and validated.
342- Do not pick the lexically latest file without checking its time, iteration,
343 HDF5 readability, and checksum.
344- Never overwrite the parent state during recovery.
345- Re-run the compatibility checker before every continuation.
346- Explain any budget discontinuity at the restart boundary.

Failure and interruption handling

  • Preserve logs and last complete checkpoint.
  • Treat a signal-terminated or wall-time-limited run as incomplete until the checkpoint is inventoried and validated.
  • Do not pick the lexically latest file without checking its time, iteration, HDF5 readability, and checksum.
  • Never overwrite the parent state during recovery.
  • Re-run the compatibility checker before every continuation.
  • Explain any budget discontinuity at the restart boundary.
Raw lines 337 to 347
348## Sources (verified 2026-10-01)
350- [FluidSim user tutorial](https://fluidsim.readthedocs.io/en/latest/ipynb/tuto_user.html).
351- [Restart and resolution change](https://fluidsim.readthedocs.io/en/latest/ipynb/restart_modif_resol.html).
352- [FluidSim load/restart source](https://github.com/fluiddyn/fluidsim/blob/0.9.0/fluidsim/util/util.py).
353- [Restart CLI source](https://fluidsim.readthedocs.io/en/latest/_modules/fluidsim_core/scripts/restart.html).
354- [FluidSim 0.9 release notes](https://fluidsim.readthedocs.io/en/latest/changes.html).
355- Mohanan et al., [FluidSim primary paper](https://doi.org/10.5334/jors.239),
356 published 2019-04-26; performance claims are limited to its documented
357 benchmark setup.

Sources (verified 2026-10-01)

Raw lines 348 to 357
Runs code scripts/restart.html :353