This page is the practical companion to the reference docs. Use it when you already understand the config roles and want proven patterns for combining them cleanly.
PICurv is designed around modular config roles:
case.yml: physics, grid, BCs, run durationsolver.yml: numerical strategymonitor.yml: logging, diagnostics, output cadence, directoriespost.yml: analysis recipecluster.yml: scheduler policystudy.yml: parameter sweep definitionThe intended UX is:
Pattern A: same case, different monitoring
case.ymlmonitor.yml for fast iterationmonitor.yml for production outputPattern B: same case, different analysis
post.yml recipesPattern C: same solver profile reused across many cases
solver.yml for a known momentum strategyPattern D: same cluster profile across many jobs
cluster.yml for site policyPattern E: same case, different local launch environment
mpiexec on ordinary workstations.picurv-execution.yml when a cluster login node or cluster batch job needs site-specific launcher flagsFirst-time local workflow:
Solver-only run:
Solver-only run on a cluster login node with a persistent site launcher config:
Cluster run that reuses the same site launcher defaults unless cluster.yml overrides them:
Post-process an existing run with a different recipe:
Catch up the same recipe in batches while the solver is still producing new source steps:
Operational notes:
post.yml; each run processes only the steps whose output is missing or stale.For restart-lineage visualization, merge this into the recipe's io mapping:
Postprocess ancestors with the same recipe first, then catch up the child using the command above and the full desired window. Open the child's .pvd in <run.visualization>/<recipe_id>/. Checkpoint times supply the time axis even when solver dt changes. The post stride and fields must retain the same recipe ID; otherwise ancestor results need to be generated for the new recipe. Catch-up refreshes the PVD atomically; reopen it in ParaView to see newly added frames. Use scope: run when ancestry should not be included. Full rules are in Configuration Reference: Postprocessor YAML.
Dry-run planning:
Stage artifacts without starting execution:
Add --cluster cluster.yml to stage Slurm scripts instead of local command metadata.
Delayed submit from existing staged artifacts:
Cancel a submitted run by directory:
Request a solver final-output shutdown before exiting:
Use plain cancel if the solver is wedged or not reaching runtime checkpoints.
Generated Slurm solver jobs already enable the runtime walltime guard by default. Override it only when needed:
Keep an early signal as fallback protection for preemption/manual termination:
For direct mpirun batch launches, use signal: "B:USR1@300" and prefer exec mpirun ....
Run naming note:
cluster.yml does not provide a run-name field.picurv creates runs/<case_basename>_<timestamp>/ automatically.Programmatic baseline:
examples/flat_channel/flat_channel.ymlexamples/flat_channel/Imp-MG-Standard.ymlexamples/flat_channel/Standard_Output.ymlexamples/flat_channel/standard_analysis.ymlFile-grid baseline:
examples/bent_channel/bent_channel.ymlexamples/bent_channel/Imp-MG-Standard.ymlexamples/bent_channel/Standard_Output.ymlexamples/bent_channel/standard_analysis.ymlAnalytical zero-flow Brownian verification:
examples/brownian_motion/brownian_motion.ymlexamples/brownian_motion/Analytical-Zero.ymlexamples/brownian_motion/Standard_Output.ymlexamples/brownian_motion/brownian_analysis.ymlAnalytical uniform-flow deterministic drift verification:
examples/drift_uniform_flow/drift_uniform_flow.ymlexamples/drift_uniform_flow/Analytical-UniformFlow.ymlexamples/drift_uniform_flow/Standard_Output.ymlexamples/drift_uniform_flow/uniform_flow_analysis.ymlAnalytical zero-flow plus verification-source diffusivity drift verification:
examples/drift_diffusivity_gradient/drift_diffusivity_gradient.ymlexamples/drift_diffusivity_gradient/Analytical-Zero-Verification-LinearDiffusivity.ymlexamples/drift_diffusivity_gradient/Standard_Output.ymlexamples/drift_diffusivity_gradient/drift_diffusivity_gradient_analysis.ymlThese are examples, not fixed bundles. You can intentionally swap roles when the contract makes sense.
Use the drift examples as separate, end-to-end checks for the two deterministic particle-position terms:
examples/drift_uniform_flow/ isolates the carrier-velocity term in X_new = X_old + (vel + diffusivitygradient) * dt + Brownian.examples/drift_diffusivity_gradient/ isolates the diffusivity-gradient term while keeping the carrier flow at zero.The intended policy is:
verification.* overrides when there is no cleaner end-to-end way to prescribe the field needed for verification.For the current diffusivity-drift case, the curated source override lives behind:
Contributor note:
include/verification_sources.h and src/verification_sources.cMinimal zero-flow startup:
Constant cartesian velocity (channel with explicit components):
Constant streamwise velocity for a periodic box (no INLET face):
Poiseuille with a clear scalar input (INLET face present — no flow_direction needed):
Poiseuille for a periodic domain (no INLET face):
Generated grid workflow:
Generate once, inspect, then reuse as a file grid:
The staged run contains the generated dimensional grid at <run.inputs>/grid/grid.generated.picgrid - physically <workspace>/runs/<run_id>/inputs/grid/grid.generated.picgrid.
After checking that file, a later case can reuse it without running grid.gen:
PICurv will validate and non-dimensionalize that source file into the new run's own <run.config>/grid.run.
Generated square-duct Poiseuille inlet profile:
picurv run --solve writes the dimensional generated profile and profile.info under <run.config>/, stages the solver-scale .picslice, and writes that staged path into bcs.run. For square_duct_poiseuille, bulk_velocity is the target inlet bulk speed. When a target PICGRID is available, generated profiles are sampled at inlet face centers and normalized by geometric quad face areas; profile.info reports the area-weighted mean before and after normalization, total area, face-area range, discrete sampled mean, and Umax/Ubulk.
File-backed prescribed inlet profile:
For 64 x 64 x 1024 cells, a -Zeta or +Zeta profile is 64 x 64. The first file value maps to tangential solver index (j=1, i=1).
Field-sliced prescribed inlet profile from an old run:
This extracts Cartesian Ucat normal speeds from the old slice, validates the old and new face normals, writes *.sliced.picslice, then stages it through the same file-backed C path. V1 requires matching source and target slice sizes.
Precompute deterministic artifacts without launching the solver:
This mirrors the <run.config>/ layout, so inspected generated artifacts can later be reused through grid.mode: file and source.type: file.
Restart with explicit particle re-initialization:
Continue a run that ended at step 500 for 1000 more steps:
solver.yml keeps operation_mode.eulerian_field_source: "solve": with start_step > 0 the solver loads the step-500 state and advances it. (load would instead replay stored fields and needs a checkpoint at every step.)
Optional particle choice:
Expected step range:
5005011500Choose flat_channel when:
programmatic_c,Choose bent_channel when:
grid.mode: file,grid_gen later.Choose brownian_motion when:
ZERO_FLOW analytical mode.Use solver.yml -> verification.sources.scalar when you need a known particle scalar truth field and there is no ordinary production workflow that can create that truth end-to-end.
Recommended pattern:
operation_mode.eulerian_field_source: analyticalanalytical_type: ZERO_FLOW for pure deposition checksverification.sources.scalar<run.analysis.metrics>/scatter_metrics.csvSeparation rules:
verification.sources.scalar is absent, ordinary production runs are unchangedPsi update is bypassed in verification modeUNIFORM_FLOW or TGV3DThis pathway is useful for more than one study. It enables:
scatter_metrics.csvA complete runnable example is provided in examples/scatter_verification/.
The dynamic model's defaults are the ones that are safe on any geometry, not the ones that are best for yours. Two settings usually want changing, and both follow from the flow rather than from taste.
Pick the averaging set from the flow's homogeneous directions. averaging.mode defaults to local, which assumes nothing and is correspondingly noisy: the denominator of the coefficient collapses wherever the resolved strain is briefly small. Where the flow has a homogeneous direction, say so:
Both read the same because homogeneous derives its directions from the case's periodicity. Name them explicitly only when the flow is homogeneous along an axis the boundary conditions do not declare periodic.
Match the filter width to the cell aspect ratio. filter_width defaults to cube_root_volume, which is exact for a cube and progressively optimistic as a cell is stretched. On a wall-resolved mesh with moderately stretched cells, scotti corrects that optimism without inflating the width at the wall; max_edge suits wall-modelled or hybrid runs, where near-wall cells are meant to be coarse.
Turn the diagnostics on before trusting anything.
Then read <run.analysis.metrics>/les_coefficient.csv, or plot it directly:
What to look for:
cs_effective should settle; for decaying isotropic turbulence at 64^3 with the box test filter it settled at 0.18-0.19 on the HOM02 benchmark (Lilly's 0.16-0.17 assumes a spectral cutoff). A curve that drifts or oscillates is the signal to stop.limited_fraction near zero means the max_cs ceiling is not shaping the result. A large value means the clip is doing the modelling.backscatter_fraction is what the clipping modes discard. Under local averaging it is routinely large, which is the argument for averaging rather than clipping.nu_t_over_nu_mean far above one means the model, not the molecular viscosity, is setting the dissipation; far below one means it is doing nothing.Judging resolution. Compare k_sgs_mean against the resolved turbulent kinetic energy from monitor.yml -> field_statistics. Pope's criterion asks the resolved share to exceed roughly 80%. The two halves come from different pipelines deliberately: resolved turbulent energy needs the mean subtracted correctly, which the statistics windows do and the closure does not attempt.
Full option reference at Configuration Reference: Case YAML; the formulation is derived in LES Turbulence Closure.