PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
The Conductor Script: picurv

picurv is the workflow orchestrator for PICurv. It validates YAML inputs, generates C runtime artifacts, and runs or schedules solver/postprocessing stages. It is also the primary user-facing contract layer: many defaults, aliases, and translation rules are enforced here before the C solver starts.

1. General Usage

picurv [COMMAND] [ARGS...]

After make all, bin/picurv is a launcher for the stable picurv_cli/picurv source-tree entrypoint. The implementation lives in picurv_cli/. The launcher uses .picurv-venv/bin/python when bootstrap created a managed environment, then a bootstrap-recorded or user-provided PICURV_PYTHON, and finally python3. Source etc/picurv.sh to add bin/ to your PATH and expose picurv_cli/ as a fallback so picurv works from any directory even if bin/picurv is temporarily absent before make conductor recreates the launcher. If bin/picurv does not exist yet, run ./picurv_cli/picurv build or make conductor.

Primary commands:

  • init
  • build
  • version, versions, and source
  • inputs
  • sync-config
  • run
  • precompute
  • storage
  • summarize
  • submit
  • cancel
  • sweep
  • validate

Core idea:

  • case.yml, solver.yml, monitor.yml, and post.yml are modular profiles.
  • You do not need to rewrite all four every time.
  • In normal use, you mix and match a case definition with reusable solver, monitor, and post profiles as long as the combination is contract-compatible.
  • Example: the same case.yml can be paired with a quieter monitor.yml, a different solver strategy, or a different post recipe without changing the physical setup file.

Help:

./bin/picurv --help
./bin/picurv init --help
./picurv_cli/picurv build --help
./bin/picurv version --help
./bin/picurv versions --help
./bin/picurv source --help
./bin/picurv inputs --help
./bin/picurv sync-config --help
./bin/picurv run --help
./bin/picurv precompute --help
./bin/picurv summarize --help
./bin/picurv submit --help
./bin/picurv cancel --help
./bin/picurv sweep --help
./bin/picurv validate --help

2. init: Create A New Case Directory

picurv init <template_name> [--dest <new_dir>] [--pin-binaries]

Behavior:

  • copies examples/<template_name>/ into a new working directory,
  • creates the uniform <workspace>/config/, <workspace>/inputs/, <workspace>/assets/, <workspace>/runs/, and <workspace>/studies/ tree,
  • classifies and relocates template YAML to canonical roles under <workspace>/config/, preserving colliding variants below <workspace>/config/variants/,
  • writes .picurv-workspace.yml; software.picurv is empty by default and therefore means the latest active installation,
  • optionally renames the destination via --dest,
  • writes .picurv-origin.json with the source repo path and template name,
  • writes .picurv-execution.yml for optional site-specific launcher overrides,
  • seeds that file from a repo-root .picurv-execution.yml when the source clone already has one, otherwise from inert defaults,
  • does not copy binaries by default; runtime executables are resolved from the project bin/ directory via PATH.

Binary pinning (--pin-binaries, superseded by run-time pinning):

  • when --pin-binaries is passed, simulator and postprocessor are copied into the case directory,
  • resolve_runtime_executable uses a copy only when it is a sibling of the picurv script that was invoked. init places no launcher in the case, so the picurv on PATH ignores these copies and launches the installation's bin/,
  • to keep a queued job on the build it was staged with, rely on run-time pinning instead (12. Binary Resolution and Rebuild Safety). The flag remains until the next release,
  • picurv itself is never copied — it is always used from PATH and is safe to update mid-run since it only launches the C binaries.

Examples:

picurv init flat_channel --dest my_first_case

3. build: Build Project Executables

./picurv_cli/picurv build [--source-root <repo>] [--case-dir <case>] [MAKE_ARGS...]

Behavior:

  • calls the top-level Makefile via make,
  • defaults to make all when you do not provide an explicit make target,
  • resolves the source repo from .picurv-origin.json when run from an initialized case,
  • passes any trailing arguments directly through to the Make/build layer,
  • can rebuild or clean the source repo without leaving a copied case directory,
  • writes the streamed build output to <repo>/logs/build.log in the source repo,
  • is the recommended command for normal users instead of invoking make manually.

Direct make all keeps the traditional stdout-only behavior. When you want the same source-repo build plus a warnings-only artifact, use:

make audit-build

This writes:

  • <repo>/logs/build.log
  • <repo>/logs/build.warnings.log

Examples:

./picurv_cli/picurv build
./picurv_cli/picurv build clean-project
./picurv_cli/picurv build SYSTEM=cluster
./picurv_cli/picurv build postprocessor
make audit-build

3b. Source, Version, And Legacy Maintenance Commands

picurv version prints the release, Git commit, and dirty-tree build identity of the Python conductor, then reads back what simulator --version and postprocessor --version actually report. Those two identities are not the same fact: the conductor's says which source staged a run, the binaries' says which build produced its checkpoints, and an edited C tree that was never rebuilt makes them disagree. The run manifest records both, and run warns at staging when a binary is stale.

Each executable's --version has a second line naming the PETSc it was compiled against, petsc <version> <debug|optimized> <arch> <dir>, taken from PETSc's own headers. The same text is stamped into the binary, so picurv version still shows it when the executable cannot start - for example undefined symbol: petscstack, a debug-PETSc build launched with an optimized PETSc on the library path. Where ldd exists, it also shows the libpetsc the current shell would load and marks it when that library lies outside the PETSc the binary was built against. Binaries built before the stamp show PETSc: not recorded.

picurv version status reports the same thing and then validates it, exiting 1 when the conductor, either executable, or the workspace's software.picurv requirement disagree, and naming each disagreement. Bare picurv version always exits 0: it is an informational surface, and a job script that must refuse an incoherent build should ask for the validating form explicitly. Both accept --format json, which adds coherent and problems to the payload.

make delivers the identity through a generated include/picurv_build_identity.h rather than command-line defines, so ordinary header-dependency tracking rebuilds the two translation units that stamp it whenever the commit or dirty state changes. A binary reporting release 0.0.0 was built outside make and carries no identity.

picurv source update fetches branches and tags without changing the active checkout. picurv versions list reports tags; versions install <version> or versions activate [version] requires a clean source checkout, selects the exact Git version, and rebuilds. A bare release such as 0.1.0 resolves to its v0.1.0 tag when no ref carries the bare name. With no argument, activate reads the workspace's exact software.picurv value and refuses ranges.

Make variables and options after the version reach make exactly as they do for picurv build, so a cluster install names its build configuration:

picurv versions install 0.1.0 SYSTEM=cluster
picurv versions activate SYSTEM=cluster # version from the workspace pin
picurv versions activate -- -j8 # version from the pin, options to make

With no version, the first word after activate may be a make assignment or, after --, a make option; neither is a tag or commit, so it goes to make rather than to Git.

A make target is refused, because the install verifies the default build. Success is reported only after simulator and postprocessor report the identity of the commit just checked out; the conductor re-reads that identity rather than using the one it computed at startup, which still names the previous commit.

Note
One installation, activated in place. PICurv installs as a single source checkout that versions activate rewrites by git checkout --detach <tag> followed by the default make build. It does not install side-by-side versioned prefixes such as /software/picurv/0.2.0/, and picurv is not a version multiplexer.

That is a deliberate trade, and it has three consequences worth knowing before you rely on a version pin:

  • Two workspaces pinned to different releases cannot both be satisfied. Activating for one makes the other's software.picurv requirement fail. There is one active release per installation, not one per workspace.
  • Activating changes unpinned jobs. A job that launches the installation's bin/ runs whatever was built last when it starts. Every generated job script refuses to launch an executable whose identity differs from the one read at staging, and a run staged with --pin-executables keeps its own copies (12. Binary Resolution and Rebuild Safety).
  • Development and version-switching share one tree. activate refuses a dirty checkout, so uncommitted work must be committed or stashed first.

These commands are tested in tests/test_workspace_lifecycle.py against real Git repositories and stubbed builds: source update against a live origin and an unreachable remote, versions list ordering, install and activate argument routing, and the refusal of a build that does not carry the new identity. Rebuilding a real release is not part of the suite.

Both versions activate and a failed workspace version check name the installation they would change, so the effect is stated rather than discovered. If you need concurrent releases — several people on one filesystem, or reproducing a published result while developing against a newer tree — install PICurv more than once and select between them with your shell or your site's module system.

pull-source and status-source remain legacy maintenance surfaces. New workspaces normally use the active installation and the version commands instead of copying executables into every case.

sync-config refreshes files from examples/<template_name>/ into the case directory. It compares against the template as init lays it out - canonical <workspace>/config/ names, variants under <workspace>/config/variants/, rewritten paths - so each case file is matched with the template file it was made from. By default it preserves user-modified files and only copies missing files:

picurv sync-config --case-dir my_case
picurv sync-config --case-dir my_case --overwrite
picurv sync-config --case-dir my_case --prune

Run from inside the workspace, --case-dir can be omitted.

--prune is conservative: it removes only files previously recorded as template-managed that no longer exist in the source template. User-created case files are not pruned. sync-config does not copy execution.example.yml into a case; instead it creates .picurv-execution.yml only when the case does not already have one.

pull-source refreshes every local branch with a configured upstream, then restores the branch you started on, so you can update code without leaving the case directory. It refuses a checkout detached by versions install or versions activate: restoring that commit after the pull would leave the code that runs unchanged while the branches moved.

picurv pull-source --case-dir my_case
picurv pull-source --case-dir my_case --current-branch-only
picurv pull-source --case-dir my_case --no-rebase
picurv pull-source --case-dir my_case --remote origin --branch main

status-source inspects source commit drift, copied binary drift, and template-file drift before you decide what to sync. Template files are compared the same way sync-config compares them, so a file reported modified is one sync-config would skip:

picurv status-source --case-dir my_case
picurv status-source --case-dir my_case --format json

For older cases that do not yet have .picurv-origin.json, pass --source-root /path/to/PICurv. For sync-config, also pass --template-name <example_name> if the template cannot be inferred.

init, sync-config and status-source are tested in tests/test_case_maintenance.py, and make smoke initializes, validates and dry-runs every shipped template. On a fresh flat_channel workspace with one edited <workspace>/config/solver.yml, status-source reported exactly that file modified and none missing, sync-config skipped it and left the case root unchanged, and sync-config --overwrite restored it in place.

status-source --format json payload highlights:

  • source_repo_root, case_dir
  • last_known_source_git_commit, current_source_git_commit, source_commit_changed
  • binaries:
    • case_bin_current, case_bin_different, case_bin_missing
  • config:
    • case_current_files, case_modified_files, case_missing_files
    • template_removed_since_last_sync (when template-managed tracking is available)

4. run: Single-Case Workflow

./bin/picurv run [STAGES] [INPUTS] [OPTIONS]

Stages:

  • --solve
  • --post-process

Inputs for --solve:

  • --case <case.yml>
  • --solver <solver.yml>
  • --monitor <monitor.yml> (logging, diagnostics, profiling, output cadence, directories)

Inputs for --post-process:

  • --post <post.yml>
  • either same invocation with --solve, or --run-dir <existing_run_dir>

MPI/local options:

  • -n, --num-procs
    • applies to solver and field postprocessor launch sizing.
    • PICurv strips conflicting MPI size flags from post launches and rewrites them to the requested rank count.
    • local multi-rank runs resolve launcher overrides in this order: PICURV_MPI_LAUNCHER, MPI_LAUNCHER, nearest .picurv-execution.yml, nearest legacy .picurv-local.yml, then default mpiexec.

Staging/execution options:

  • --cluster <cluster.yml>
  • --scheduler slurm (optional explicit selector)
  • --no-submit (stage run artifacts without starting the local or Slurm backend)

Preflight options:

  • --dry-run (resolve and print launch/artifact plan only, including PETSc diagnostic flags and log paths)
  • --format json (machine-readable output for --dry-run)

Local example:

./bin/picurv run --solve --post-process -n 8 \
--case my_case/case.yml \
--solver my_case/solver.yml \
--monitor my_case/monitor.yml \
--post my_case/post.yml

In this command, the solver and field postprocessor both run with 8 ranks.

Slurm example (generate + submit):

./bin/picurv run --solve --post-process \
--case my_case/case.yml \
--solver my_case/solver.yml \
--monitor my_case/monitor.yml \
--post my_case/post.yml \
--cluster my_case/cluster.yml

Stage artifacts without starting execution:

./bin/picurv run --solve --post-process \
--case my_case/case.yml \
--solver my_case/solver.yml \
--monitor my_case/monitor.yml \
--post my_case/post.yml \
--no-submit

Add --cluster my_case/cluster.yml to stage Slurm scripts instead of local commands.

Follow-up execution/submission from existing artifacts:

./bin/picurv submit --run-dir runs/<run_id>

Post-only continuation examples:

post.yml -> io.paraview_series optionally adds physical-time .pvd collections to this workflow. With enabled: true, scope: lineage, the conductor follows the existing manifest ancestry and indexes matching ancestor VTK recipes together with the current run's frames. Prepare ancestor output first. Post catch-up refreshes the collection even when the field window is already complete; solve-only and spectra-only invocations do not refresh it. See Configuration Reference: Postprocessor YAML for recipe compatibility and Tutorial: A Guide to Visualizing Your Results for opening the result.

  • Post-processing is incremental. Keep the full analysis window in post.yml; each run processes only the steps whose output is missing or stale, and launches nothing when every step is up to date:
./bin/picurv run --post-process \
--run-dir runs/search_robustness_20260322-073415 \
--post search_robustness_analysis.yml
  • Every step the postprocessor produces is recorded in the recipe's state.json with the recipe fingerprint and its checkpoint's commit marker. A step is processed again when any of its output files is missing, when the recipe changed, or when its checkpoint changed. Output written before these records existed is kept when it is newer than its checkpoint. Steps need not be contiguous: a single deleted file is reprocessed alone.
  • Rebuilding the postprocessor does not make output stale. PICurv reports how many up-to-date steps another or an unrecorded build made; --recompute regenerates every requested step that has a committed checkpoint, for every selected stage.
  • A step whose checkpoint is not committed yet waits. If the solver has written source data only through step 420, a run over 0..1000 processes the committed steps; a later run picks up the rest once the solver writes them.
  • The steps are decided when the post job starts, under the post lock. A Slurm post job staged before the solver ran, or resubmitted later, processes only what is missing when it starts. A job that fails or is interrupted part-way keeps the steps it finished.
  • A field-statistics window's output is expected only at steps where that window had accumulated a sample, so a window that opens late (or has not opened yet) does not make earlier steps incomplete.
  • --continue belongs to --solve; on a post-only command it is ignored with a warning.
  • A recipe that differs from another recipe in the same run is a separate recipe with its own outputs; fields and statistics windows the two share are recomputed, not reused, because a recipe writes one file per step holding all its fields. PICurv warns when another recipe already produced them for the steps about to be processed. To compute only what is new, put the new outputs in a recipe of their own.
  • If you change the recipe itself, for example by adding Qcrit_nodal, changing the statistics output prefix, or changing step_interval, PICurv treats it as a new recipe with its own output directory and processes its whole window.
  • PICurv allows only one post writer per run directory. If a second post job targets the same run, it is refused immediately instead of racing on <run.visualization>/ or <run.analysis.statistics>/.

Graceful shutdown note:

  • generated Slurm solver jobs enable a runtime walltime guard by default; after 10 completed warmup steps, PICurv estimates timestep cost and requests the same graceful final-write path before remaining walltime gets too tight.
  • if cluster.yml -> execution.extra_sbatch.signal requests an early warning signal, PICurv also traps SIGUSR1, SIGTERM, and SIGINT, then writes one last snapshot at the next safe checkpoint even when the normal recording interval has not been reached.
  • tune the automatic estimator in cluster.yml -> execution.walltime_guard; keep execution.extra_sbatch.signal as fallback protection for preemption/manual termination or jobs that may not reach the warmup window.
  • use signal: "USR1@300" for srun-launched jobs, or signal: "B:USR1@300" plus exec mpirun ... for direct mpirun batch launches.

Runtime stream logs:

  • C-managed logs remain under <run.runtime_logs>/.
  • wrapper stdout/stderr stream logs now live under <run.scheduler>/ for both local and Slurm launches.
  • this avoids collisions with solver startup, which recreates the C log directory.

5. summarize: Read-Only Run Configuration and Health Summary

./bin/picurv summarize --run-dir <run_dir> \
[--overview] [--case] [--solver] [--monitor] \
[--list-plot-series | --plot <qualified-series>] [--last <n>] \
[--latest | --max-step | --step <n>] [--format json]

Behavior:

  • --overview reports run metadata plus curated case, solver, and monitor summaries,
  • --case, --solver, and --monitor are additive selectors for individual copied configs,
  • config-only selectors work before runtime logs exist,
  • timestep selectors read existing runtime artifacts and still require summary-capable logs,
  • plain summarize --run-dir ... preserves the implicit latest-step health behavior,
  • --list-plot-series discovers numeric scalar histories available to --plot,
  • --plot <qualified-series> delegates time-history rendering to generators/plot.gen,
  • plotting requires matplotlib, which bootstrap installs in the managed PICurv environment by default,
  • continued runs write # Continuation from step <N> separators into append-only logs,
  • plots use the latest continuation segment by default; --last <n> keeps its last N chronological records per line,
  • --plot-output <path> saves without opening a window; headless interactive requests save under <run.analysis>/plots/,
  • builds a best-effort step summary without changing solver output,
  • works for active runs and completed runs,
  • reports unavailable sections when a source log is missing or disabled.

Examples:

./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --overview
./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --case --solver
./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --latest
./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --monitor --step 500
./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --list-plot-series
./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --plot momentum.residual_norm --last 100
./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --plot memory.process_peak_mb_max --plot-output peak.png
./bin/picurv summarize --run-dir runs/my_case_20260310-120000 --latest --format json

Configuration summaries include configured values plus useful normalized and derived values such as Reynolds number, nondimensional timestep, normalized solver selections, effective monitoring cadence, and enabled diagnostics. Text output uses glanceable dashboards with aligned field groups and compact tables; use --format json for structured automation output.

Plotting supports numeric scalar histories from continuity, particle metrics, momentum, Poisson, profiling, runtime memory, and solution-convergence logs. Block-based histories render one line per block and profiling histories render one line per function. Residual/norm series use logarithmic scaling when all values are positive; --linear-y forces linear scaling. Plot mode is standalone and does not combine with overview/config/selected-step selectors.

generators/plot.gen is the standalone rendering layer. It accepts the versioned, normalized JSON request produced by picurv through stdin, and can also render a saved request directly:

python3 generators/plot.gen --input request.json
cat request.json | python3 generators/plot.gen --input -
python3 generators/plot.gen --input request.json --output history.png

The normalized request contains plot labels, scale selection, window metadata, and ordered labeled lines of numeric [timestep, value] points. plot.gen does not parse PICurv run directories or logs.

Typical sources:

  • <run.runtime_logs>/Continuity_Metrics.log
  • <run.runtime_logs>/Particle_Metrics.log (per-step Lost plus run-local Lost Total when available)
  • <run.runtime_logs>/Momentum_Solver_Convergence_History_Block_*.log
  • <run.runtime_logs>/Poisson_Solver_Convergence_History_Block_*.log
  • <run.runtime_logs>/solution_convergence.log (mode-specific speed/KE drift and L2 norms)
  • <run.runtime_logs>/Profiling_Timestep_Summary.csv when enabled
  • <run.runtime_logs>/Runtime_Memory.log when monitor.diagnostics.runtime_memory_log.enabled is true
  • <run.analysis.metrics>/les_coefficient.csv when case.yml -> models.physics.turbulence.les.diagnostics.enabled is true; the les.* series carry the effective coefficient, its spread, eddy-viscosity levels, the modelled subgrid energy, and the pre-clipping backscattering and limited fractions
  • <run.runtime_logs>/PETSc_*_Solver.log / <run.runtime_logs>/PETSc_*_PostProcessor.log when file-backed PETSc diagnostics are enabled
  • <run.scheduler>/*_solver.log or <run.scheduler>/solver_*.out for sampled particle snapshot previews

When particle snapshots are available, summarize reports sampled diagnostics such as:

  • speed min/mean/max/std and stagnant-count
  • sampled position bounds and centroid
  • sampled rank counts and duplicate sampled cells
  • sampled weight min/max by component
  • sanity checks for duplicate PIDs and non-finite/zero/negative weights
  • top sampled speeds and sampled deltas versus the previous snapshot when matching PIDs exist

Dry-run example (no file writes):

./bin/picurv run --solve --post-process \
--case my_case/case.yml \
--solver my_case/solver.yml \
--monitor my_case/monitor.yml \
--post my_case/post.yml \
--dry-run --format json

Common run use cases:

  • first full local run: --solve --post-process
  • solver-only run: --solve
  • post-only rerun on an existing run directory: --post-process --run-dir ...
  • staged local/cluster run without execution: --no-submit
  • delayed submission of an already-staged run: submit --run-dir ...
  • planning and CI-style checks: --dry-run

5a. precompute: Generate Deterministic Artifacts

picurv precompute --case config/case.yml [--only grid,initial-condition,inlet-profiles]

precompute creates immutable, content-addressed workspace assets without launching the solver. It uses exactly the same provider graph as run --solve: grids build before any Python initial condition or inlet slice that consumes them. Provider settings, referenced-file checksums, and software identity determine reuse.

The build occurs under assets/.precompute-* and publishes to assets/objects/ only after the whole requested dependency closure succeeds. The mutable pointer in assets/sets/ records which objects match the current case file. A normal run reuses those objects automatically and writes the exact selection to inputs/assets.lock.yml. When the case file's set has no match - a new, copied, or renamed case file - the run looks for a published object with the same provider identity before building, adopts it, and records it in that case file's set. Generated payloads are byte-reproducible (their summaries record paths relative to themselves), so rebuilding an unchanged provider publishes the same object rather than a duplicate.

Providers owned by the C runtime are reported but never approximated by Python. A selected C-only provider makes precompute fail before publication. See Run Artifact Lifecycle Contract for the directory and dependency contracts.

5b. submit: Execute Existing Staged Artifacts

./bin/picurv submit [--run-dir <run_dir> | --study-dir <study_dir>] \
[--stage {all,solve,post-process}] [--force] [--dry-run]

Behavior:

  • consumes existing --no-submit artifacts without regenerating configs or scripts,
  • reads <run.scheduler>/submission.json to locate staged Slurm scripts or local command tokens,
  • executes/submits solve, post-process, or both,
  • wires the post stage dependency automatically for Slurm when all is selected,
  • executes local staged stages in order when launch_mode: local,
  • refuses re-submission unless --force is explicitly provided,
  • refuses a local post-process stage while a solve staged in the same set has not run; a post staged on its own is accepted,
  • a resubmitted post-process stage decides at start which steps need work, so it skips output that is already up to date,
  • for a study, submits the set staged last: the original arrays, or the ones sweep --continue --no-submit staged; the metrics aggregation job follows the post array (afterany), as sweep chains it,
  • first points a run or study that was moved at its new location (see 1.3 Moving Or Copying A Run Or Study).

Examples:

./bin/picurv submit --run-dir runs/my_case_20260310-120000
./bin/picurv submit --run-dir runs/my_case_20260310-120000 --stage solve
./bin/picurv submit --study-dir studies/my_study_20260310-120000 --dry-run

Notes:

  • --run-dir supports local and Slurm staged runs,
  • --study-dir remains Slurm-only,
  • --dry-run prints the exact local command or sbatch plan,
  • --force is the opt-in path for deliberate resubmission.

5c. cancel: Stop A Slurm Run By Run Directory

./bin/picurv cancel --run-dir <run_dir> [--stage {all,solve,post-process}] [--graceful] [--dry-run]

Behavior:

  • reads <run.scheduler>/submission.json from an existing run directory,
  • resolves the recorded Slurm job IDs for solve and/or post-process,
  • runs hard scancel <job_id> for the selected stage set by default,
  • with --graceful, sends scancel --signal=USR1 --full <job_id> for solver jobs, reaching the batch process and MPI children so the runtime can write the latest safe off-cadence step at the next checkpoint,
  • post-process jobs still use hard cancellation, even when --graceful is present,
  • avoids manual job-id lookup when the run directory is already known.

Examples:

./bin/picurv cancel --run-dir runs/my_case_20260310-120000
./bin/picurv cancel --run-dir runs/my_case_20260310-120000 --stage solve
./bin/picurv cancel --run-dir runs/my_case_20260310-120000 --stage solve --graceful
./bin/picurv cancel --run-dir runs/my_case_20260310-120000 --dry-run

Notes:

  • works only for Slurm-submitted runs that have <run.scheduler>/submission.json,
  • does not apply to local runs,
  • --graceful requests solver shutdown and final output; if a job is wedged or not reaching runtime checkpoints, rerun without --graceful to hard-cancel it,
  • --dry-run is useful when you want to confirm the recorded stage/job mapping first.

6. sweep: Parameter Study via Slurm Arrays

# Launch new study
./bin/picurv sweep \
--study my_study/study.yml \
--cluster my_study/cluster.yml [--no-submit]
# Continue a partially-completed study
./bin/picurv sweep --continue --study-dir studies/<study_id> \
[--cluster cluster_more_time.yml]
# Re-aggregate metrics manually
./bin/picurv sweep --reaggregate --study-dir studies/<study_id>

Behavior (new study):

  • expands parameter matrix from study.yml
  • materializes case directories under studies/<study_id>/cases/
  • generates solver_array.sbatch, post_array.sbatch, and metrics_aggregate.sbatch
  • renders post_array.sbatch with the same cluster allocation as the solver array
  • submits solver → post (afterok) → metrics (afterany) chain (unless --no-submit)

Behavior (--continue):

  • detects per-case completion status (complete / partial / empty)
  • if all cases complete, auto-aggregates metrics and exits
  • otherwise prepares continuation for incomplete cases (checkpoint restart via resolve_restart_source)
  • submits sparse solver array (incomplete cases only) → full post array → metrics aggregation

Behavior (--reaggregate):

  • re-runs metrics collection and plot generation on existing study outputs

7. validate: Config-Only Checks

./bin/picurv validate \
--case my_case/case.yml \
--solver my_case/solver.yml \
--monitor my_case/monitor.yml \
--post my_case/post.yml

validate does not launch solver/post and does not create run/study artifacts.

What validate is for:

  • check a new profile combination before running,
  • confirm a modified template still satisfies the current schema,
  • catch mode-dependent contract errors before the C runtime,
  • inspect warnings where picurv preserves a C-side default intentionally.

8. Full Command and Option Matrix

The table below is generated by introspecting the assembled argparse parser - build_main_parser() in picurv_cli/cli.py together with the registrars delegated from other modules, such as add_storage_parser() in picurv_cli/storage/. Reading cli.py alone understates the command set, which is why the generator exercises the built parser rather than pattern-matching the source.

It is regenerated by make docs-cli-reference and checked by make audit-cli-reference, so a parser change makes it stale and fails CI. The narrative guidance in the sections above is hand-written and complements it; this section is the exhaustive reference.

17 top-level commands.

picurv build

Calls the project's Makefile directly through `make`.

positional arguments

FlagRequiredChoicesDefaultDescription
make_args (positional)yes——Arguments to pass directly to the make command (e.g., 'clean-project').

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--source-rootno——Optional override for the PICurv source repository root.
--case-dirno——Optional case directory used to resolve .picurv-origin.json when not running from that case.

picurv cancel

Look up scheduler/submission.json inside an existing run directory and cancel

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--run-diryes——Path to the run directory whose Slurm job(s) should be canceled.
--stagenoall, post-process, solveallWhich recorded stage job(s) to cancel (default: all).
--dry-runno—FalseShow which `scancel` command(s) would run without actually canceling anything.
--gracefulno—FalseFor solver jobs, request a clean runtime shutdown by sending SIGUSR1 to the process tree instead of hard-canceling immediately. The solver writes the latest safe off-cadence step at the next checkpoint. Non-solver stages still use ordinary scancel.

picurv init

Create a case workspace from examples/<template_name>.

positional arguments

FlagRequiredChoicesDefaultDescription
template_name (positional)yes——Name of the case template directory to copy (e.g., 'flat_channel').

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--destno——Optional name for the new directory. Defaults to the template name. Path is relative to your current working directory.
--source-rootno——Optional override for the PICurv source repository root. Useful when running from a copied case without metadata.
--pin-binariesno—FalseCopy simulator and postprocessor into the case directory. Use this to freeze specific binary versions for reproducibility or to protect running jobs from concurrent rebuilds.

picurv inputs

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit

picurv inputs import

positional arguments

FlagRequiredChoicesDefaultDescription
kind (positional)yesgrid, initial-condition, inlet-profile, reference-field—
source (positional)yes——Existing source file.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--nameno——Destination name; defaults to the source basename.
--modenocopy, hardlink, reference, reflinkcopyHow to retain the input. Reference mode records but does not copy an external path.
--workspaceno——Workspace root; defaults to discovery from the current directory.

picurv precompute

Generate configured deterministic artifacts, such as grid_gen grids,

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--caseyes——Path to case.yml containing grid/profile/IC generator settings.
--onlyno—allComma-separated asset kinds (grid, initial-condition, inlet-profiles), or all.

picurv pull-source

Legacy maintenance command; new workspaces use `picurv source update` and

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--case-dirno——Optional case directory used to resolve .picurv-origin.json.
--source-rootno——Optional override for the PICurv source repository root.
--remoteno——Optional git remote name (e.g., origin).
--branchno——Optional branch name. If provided without --remote, origin is assumed.
--current-branch-onlyno—FalseOnly pull the currently checked out branch instead of iterating across all local tracking branches.
--no-rebaseno—FalseUse plain git pull instead of git pull --rebase.

picurv run

Execute solver and/or post-processing stages.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
-n, --num-procsno—1Number of MPI processes for solver and post-processing stages.
--clusterno——Path to cluster.yml for Slurm execution mode.
--schedulerno——Explicit scheduler selector (currently 'slurm').
--no-submitno—FalseStage run artifacts without starting local execution or Slurm submission.
--pin-executablesno——Copy simulator and postprocessor into the run's config/bin/ at staging, so a later rebuild of the installation cannot change what the job runs. On a pinned run, re-pins it to the current build.
--no-pin-executablesno——Launch the installation's executables even when the workspace sets reproducibility.pin_executables. Slurm jobs still check at start that they report the build identity read at staging.
--dry-runno—FalseResolve and print planned commands/artifacts, including diagnostic flags and log paths, without writing files.
--formatnojson, texttextOutput format for --dry-run (default: text).

stages

FlagRequiredChoicesDefaultDescription
--solveno—FalseExecute the solver stage (creates a new run directory).
--post-processno—FalseExecute the post-processing stage on a run directory.
--continueno—FalseExtend an existing run's solve in place. Requires --solve and --run-dir, and start_step > 0; appends to existing solver output/logs. Post-processing needs no flag: it always skips up-to-date steps.

solver inputs (required for --solve)

FlagRequiredChoicesDefaultDescription
--caseno——Path to the case definition file (e.g., case.yml).
--solverno——Path to the solver settings profile (e.g., solver.yml).
--monitorno——Path to the monitoring, diagnostics, and I/O profile (e.g., monitor.yml).
--restart-from, --fromno——Path to an existing run directory to restart from. Use 'latest' to select the newest compatible local workspace run.
--statistics-statenocarry, reset—For a branched restart with field statistics enabled, this is required: 'reset' discards the parent's accumulated windows, 'carry' resumes compatible saved window state. Ignored when field statistics are disabled.
--require-precomputedno—FalseRefuse to build missing or stale deterministic assets while staging the run.
--fetch-missingno—FalseTry the configured storage profile before rebuilding a missing workspace asset.

post-processor inputs (required for --post-process)

FlagRequiredChoicesDefaultDescription
--run-dirno——Path to an existing run directory. (Used with --post-process or --solve --continue).
--postno——Path to the post-processing recipe file (e.g., post.yml).
--onlyno——Comma-separated post stages to run: 'fields' (the field post-processor) and/or 'spectra'. Defaults to every stage. Use --only spectra to measure spectra without running the field stage.
--recomputeno—FalseRegenerate every requested step that has a committed checkpoint, including steps whose output is up to date (for example, after rebuilding the postprocessor). Applies to every selected stage.

picurv source

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit

picurv source update

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--remoteno—origin

picurv status-source

Legacy maintenance command; `picurv version status` reports build coherence for

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--case-dirno——Optional case directory used to resolve .picurv-origin.json.
--source-rootno——Optional override for the PICurv source repository root.
--template-nameno——Optional template name override when metadata is absent.
--formatnojson, texttextOutput format (default: text).

picurv storage

Manage PICurv run and study data through a configured rclone remote.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit

picurv storage list

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.
--searchno——Case-insensitive search across IDs, labels, identities, and tags.
--workspace-labelno——Show only archives belonging to this workspace identity.
--formatnojson, texttext

picurv storage offload

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--run-dirno——Standalone run directory.
--study-dirno——Sweep study directory.
--workspaceno——Workspace root: its configuration, catalog, and assets, not its runs and studies, which are their own artifacts.
--case-idno——One numbered study member, such as case_0003; repeat to select several.
--completedno—FalseWith --study-dir, select every finished member and skip the rest.
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.
--include-inputsno—FalseWith --workspace, also archive user-supplied files under inputs/.
--labelno——Human-readable searchable label.
--notesno——Free-text note recorded with the archive and shown by `show`.
--tagno——Repeatable KEY=VALUE catalog tag.
--compressionnoauto, balanced, fast, maximum, none—
--policynoanalysis-ready, metadata-only, restart-ready—
--retainno——Keep this component local regardless of --policy; repeatable and comma-separated. One of: checkpoints, logs, analysis, visualization, inputs, raw-output.
--dropno——Prune this component locally regardless of --policy; same names as --retain.
--workersno——
--keep-latest-checkpointno——
--drop-all-checkpointsno——
--dry-runno—False

picurv storage plan

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--run-dirno——Standalone run directory.
--study-dirno——Sweep study directory.
--workspaceno——Workspace root: its configuration, catalog, and assets, not its runs and studies, which are their own artifacts.
--case-idno——One numbered study member, such as case_0003; repeat to select several.
--completedno—FalseWith --study-dir, select every finished member and skip the rest.
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.
--compressionnoauto, balanced, fast, maximum, none—
--policynoanalysis-ready, metadata-only, restart-ready—
--retainno——Keep this component local regardless of --policy; repeatable and comma-separated. One of: checkpoints, logs, analysis, visualization, inputs, raw-output.
--dropno——Prune this component locally regardless of --policy; same names as --retain.
--workersno——
--keep-latest-checkpointno——
--drop-all-checkpointsno——

picurv storage protect

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--run-dirno——Standalone run directory.
--study-dirno——Sweep study directory.
--workspaceno——Workspace root: its configuration, catalog, and assets, not its runs and studies, which are their own artifacts.
--case-idno——One numbered study member, such as case_0003; repeat to select several.
--completedno—FalseWith --study-dir, select every finished member and skip the rest.
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.
--include-inputsno—FalseWith --workspace, also archive user-supplied files under inputs/.
--labelno——Human-readable searchable label.
--notesno——Free-text note recorded with the archive and shown by `show`.
--tagno——Repeatable KEY=VALUE catalog tag.
--compressionnoauto, balanced, fast, maximum, none—
--policynoanalysis-ready, metadata-only, restart-ready—
--retainno——Keep this component local regardless of --policy; repeatable and comma-separated. One of: checkpoints, logs, analysis, visualization, inputs, raw-output.
--dropno——Prune this component locally regardless of --policy; same names as --retain.
--workersno——
--keep-latest-checkpointno——
--drop-all-checkpointsno——
--dry-runno—False

picurv storage prune

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--workspaceno——Workspace root; defaults to discovery from the cwd.
--assetsyes—FalseSelect the workspace asset store. Required: prune removes nothing else.
--unused-locallyyes—FalseConfirm that only objects with no active local run are removed.
--dry-runno—FalseReport the decision only.
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.

picurv storage restore

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--archive-idno——Globally unique remote archive ID.
--workspace-idno——Restore a workspace archive by its recorded workspace identity.
--run-dirno——Cold run containing a local storage marker.
--study-dirno——Cold study containing a local storage marker.
--case-idno——
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.
--tono——Optional alternate restore destination.
--checkpointno——One committed step; repeat to select several.
--checkpointsno——An inclusive step range as START:END or START:END:STRIDE; repeatable.
--componentnoanalysis, assets, inputs, logs, raw-output, unclassified, visualization, workspace-config, workspace-inputs—Restore one semantic component; repeat as needed.
--forceno—FalseAllow merge into a non-matching existing destination.
--workersno——Parallel download/extraction workers.

picurv storage setup

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--remoteyes——Rclone remote and base path, such as labstore:picurv-data.
--profileno—archiveProfile name (default: archive).
--storage-configno——Storage YAML path (default: ./.picurv-storage.yml).
--compressionnoauto, balanced, fast, maximum, noneauto
--chunk-size-gibno—8.0
--workersno—<local CPU count, capped 1-8>CPU workers for compression and restoration.
--offload-policynoanalysis-ready, metadata-only, restart-readymetadata-only
--keep-latest-checkpointno—FalseRetain the newest committed checkpoint after offload.
--staging-directoryno——Optional local directory for one archive chunk at a time.
--dry-runno—False

picurv storage show

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--archive-idyes——
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.

picurv storage status

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--run-dirno——Standalone run directory.
--study-dirno——Sweep study directory.
--workspaceno——Workspace root: its configuration, catalog, and assets, not its runs and studies, which are their own artifacts.
--case-idno——One numbered study member, such as case_0003; repeat to select several.
--completedno—FalseWith --study-dir, select every finished member and skip the rest.
--formatnojson, texttext

picurv storage verify

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--archive-idno——
--run-dirno——
--study-dirno——
--workspaceno——Workspace whose own archive to verify.
--case-idno——
--profileno——Configured storage profile name.
--storage-configno——Explicit storage YAML path.

picurv submit

Consume an existing artifact set created by picurv --no-submit and

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--run-dirno——Path to a staged run directory created by `picurv run ... --no-submit`.
--study-dirno——Path to a staged study directory created by `picurv sweep --cluster ... --no-submit`.
--stagenoall, post-process, solveallWhich staged job(s) to submit (default: all).
--forceno—FalseAllow re-submitting a stage already marked as submitted in scheduler/submission.json.
--dry-runno—FalseShow which local command(s) or `sbatch` command(s) would run without starting anything.

picurv summarize

Build read-only configuration overviews, run-health summaries, and scalar time-history plots.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--run-diryes——Path to the run directory to inspect.
--overviewno—FalseSummarize run metadata plus copied case, solver, and monitor configs without implicitly requesting health.
--caseno—FalseSummarize the copied run-local case.yml.
--solverno—FalseSummarize the copied run-local solver.yml.
--monitorno—FalseSummarize the copied run-local monitor.yml.
--list-plot-seriesno—FalseList scalar histories available to --plot.
--list-seriesno—False==SUPPRESS==
--plotno——Plot one qualified scalar history, such as momentum.residual_norm (requires matplotlib).
--plot-spectrumno——Plot up to six representative measured energy spectra, including the first and last states, overlaid on the initial-condition spectrum. Takes an optional task-name substring when the recipe measured more than one spectrum (requires matplotlib).
--lastno——Plot only the last N chronological records per line.
--plot-outputno——Save the plot to this path instead of opening an interactive window.
--linear-yno—FalseForce linear y-axis scaling instead of automatic residual/norm log scaling.
--stepno——Specific completed timestep to summarize.
--latestno—FalseSummarize the most recently appended completed step found in available artifacts (default behavior).
--max-stepno—FalseSummarize the numerically largest timestep found in available artifacts.
--snapshot-rowsno—5Number of sampled particle snapshot rows to preview when solver stream output contains them.
--formatnojson, texttextOutput format (default: text).

picurv sweep

Launch studies from study.yml + cluster.yml, whether the study uses

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--studyno——Path to study.yml defining either a `parameters` cross-product expansion or explicit parameter_sets, plus metrics.
--clusterno——Path to cluster.yml defining Slurm resources.
--no-submitno—FalseGenerate all study artifacts without submitting jobs.
--pin-executablesno——Copy simulator and postprocessor into the run's config/bin/ at staging, so a later rebuild of the installation cannot change what the job runs. On a pinned run, re-pins it to the current build.
--no-pin-executablesno——Launch the installation's executables even when the workspace sets reproducibility.pin_executables. Slurm jobs still check at start that they report the build identity read at staging.
--study-dirno——Path to an existing study directory (for --continue/--reaggregate).
--continueno—FalseContinue a partially-completed study. Requires --study-dir.
--reaggregateno—FalseRe-run metrics aggregation on a completed study. Requires --study-dir.
--auto-fetchno—FalseRestore cold-storage study members automatically instead of refusing. Requires a configured storage profile.

picurv sync-config

Copy updated example template files into an existing case directory.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--case-dirno——Optional case directory to refresh. Defaults to the current case.
--source-rootno——Optional override for the PICurv source repository root.
--template-nameno——Optional template name override (e.g., flat_channel). Required when metadata is absent.
--overwriteno—FalseOverwrite case files even when they differ from the template.
--pruneno—FalseRemove stale files that were previously tracked as template-managed but no longer exist in the source template.

picurv validate

Validate one or more config roles. No solver/post execution and no run/study artifact writes.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--caseno——Path to case.yml
--solverno——Path to solver.yml
--monitorno——Path to monitor.yml (logging, diagnostics, profiling, and I/O)
--restart-fromno——Path to a run directory to validate restart from.
--continueno—FalseValidate continue-in-place mode. Requires --run-dir.
--run-dirno——Path to an existing run directory (for --continue validation).
--postno——Path to post.yml
--clusterno——Path to cluster.yml
--studyno——Path to study.yml
--strictno—FalseEnable additional strict checks for selected roles.

picurv version

Report the build identity shared by the Python conductor and the native

positional arguments

FlagRequiredChoicesDefaultDescription
version_action (positional)nostatus—'status' validates conductor/executable/workspace coherence and exits 1 on disagreement.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--formatnojson, texttext

picurv versions

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit

picurv versions activate

positional arguments

FlagRequiredChoicesDefaultDescription
version (positional)no——Version/tag; defaults to the workspace requirement.
make_args (positional)yes——Make variables and options passed to the build, as with 'picurv build' (for example SYSTEM=cluster). Place them after every picurv option.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit
--workspaceno——Workspace root; defaults to discovery from the current directory.

picurv versions install

positional arguments

FlagRequiredChoicesDefaultDescription
version (positional)yes——Tag, bare release (resolved to v<release>), or commit.
make_args (positional)yes——Make variables and options passed to the build, as with 'picurv build' (for example SYSTEM=cluster). Place them after every picurv option.

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit

picurv versions list

options

FlagRequiredChoicesDefaultDescription
-h, --helpno——show this help message and exit

run:

  • stages:
    • --solve (requires --case, --solver, --monitor)
    • --post-process (requires --post; requires --run-dir when --solve is not selected)
  • solver inputs:
    • --case <path>
    • --solver <path>
    • --monitor <path> (logging, diagnostics, profiling, output cadence)
  • post inputs:
    • --post <path>
    • --run-dir <path>
  • restart and asset selection:
    • --restart-from <run-dir|latest> (alias --from; latest picks the newest compatible workspace run)
    • --statistics-state {reset,carry} (branched restart only; entries at 8.6 Restart Statistics State Entries)
    • --require-precomputed (refuse to build a missing or stale workspace asset)
    • --fetch-missing (try the configured storage profile before rebuilding one)
  • launch controls:
    • -n, --num-procs <int> (solver and field postprocessor stages)
    • --cluster <cluster.yml> (enables Slurm mode)
    • --scheduler <name> (must be used with --cluster; must match cluster.yml:scheduler.type)
    • --no-submit (stage files and submission metadata without starting execution)
    • --dry-run (no file writes; plan only, including diagnostic artifacts)
    • --format {text,json} (dry-run output format)

validate:

  • role selectors:
    • --case <path>
    • --solver <path>
    • --monitor <path>
    • --post <path>
    • --cluster <path>
    • --study <path>
  • stricter policy:
    • --strict (adds additional checks for selected roles; documented below)

precompute:

  • required:
    • --case <path>
  • optional:
    • --only <grid,initial-condition,inlet-profiles> (defaults to all configured providers)

summarize:

  • required:
    • --run-dir <path>
  • <run.config>/run views:
    • --overview
    • --case
    • --solver
    • --monitor
  • selected-step health:
    • mutually exclusive --step <n>, --latest, or --max-step
    • --snapshot-rows <positive-int>
  • standalone time-history discovery/plotting:
    • mutually exclusive --list-plot-series or --plot <qualified-series>
    • --last <positive-int> (requires --plot)
    • --plot-output <path> (requires --plot)
    • --linear-y (requires --plot)
    • plot/list modes cannot combine with <run.config>/run views or selected-step health
  • output:
    • --format {text,json} (--list-plot-series supports JSON; --plot rejects JSON)

submit:

  • required:
    • exactly one of --run-dir <path> or --study-dir <path>
  • optional:
    • --stage {all,solve,post-process}
    • --force
    • --dry-run

cancel:

  • required:
    • --run-dir <path>
  • optional:
    • --stage {all,solve,post-process}
    • --dry-run

sweep:

  • new study mode (default):
    • --study <study.yml> (required)
    • --cluster <cluster.yml> (required)
    • --no-submit (optional)
  • continuation mode:
    • --continue (required)
    • --study-dir <path> (required)
    • --cluster <cluster.yml> (optional; overrides original cluster resources)
  • reaggregation mode:
    • --reaggregate (required)
    • --study-dir <path> (required)

init:

  • positional:
    • <template_name>
  • optional:
    • --dest <dir>
    • --source-root <repo>
    • --pin-binaries (legacy; copies simulator/postprocessor into the case, used only when that directory's own picurv is invoked)

build:

  • optional:
    • --source-root <repo>
    • --case-dir <case_dir>
  • passthrough:
    • trailing MAKE_ARGS... are passed directly to make

sync-config:

  • --case-dir <case_dir>
  • --source-root <repo>
  • --template-name <template>
  • --overwrite
  • --prune

pull-source:

  • --case-dir <case_dir>
  • --source-root <repo>
  • --remote <git_remote>
  • --branch <git_branch>
  • --no-rebase

status-source:

  • --case-dir <case_dir>
  • --source-root <repo>
  • --template-name <template>
  • --format {text,json}

8. <tt>validate --strict</tt>: Additional Checks

--strict does not change baseline schema validation, but it adds file-system consistency checks for selected roles:

  • with --study:
    • base configs listed in study.base_configs are loaded and revalidated as real case/solver/monitor/post bundles.
    • this catches study files that are syntactically valid but point to invalid base configurations.

Use --strict in CI/pre-submit checks when validating reusable profile libraries or study manifests.

9. Dry-Run JSON Plan Schema

picurv run --dry-run --format json emits a deterministic plan payload with these top-level keys:

  • mode ("dry-run")
  • created_at (ISO timestamp)
  • launch_mode (local or slurm)
  • warnings (list)
  • inputs (resolved absolute paths)
  • stages (stage-specific launch plans)
  • artifacts (predicted files/directories, deduplicated)
  • run_id_preview / run_dir_preview (when known)
  • solver_num_procs_effective
  • post_num_procs_effective
  • num_procs_effective (currently mirrors solver count)

For file-backed grid modes, artifacts includes the planned staged grid path (<run.inputs>/grid/grid.run). For grid.mode: grid_gen, it also includes the generated PICGRID path (<run.inputs>/grid/grid.generated.picgrid), its quality report (<run.analysis.metrics>/grid.info), and its .vts preview (<run.visualization>/precompute/grid.vts) - all three unconditionally, since picurv chooses the destination rather than accepting stats_file/vts_file config keys. Dry-run still does not run generators/grid.gen or write these files. For generated prescribed-flow profiles, artifacts includes the dimensional generated .picslice, the solver-scale staged .picslice, and profile.info.

Stage entries under stages.solve and stages.post-process include:

  • mode (local or slurm)
  • num_procs_effective
  • launch_command (tokenized command list)
  • launch_command_string (shell-ready display string)

Additional stage fields:

  • script (Slurm script path in cluster mode)
  • command / command_string (local staged command tokens/display string)
  • source_data_directory (post stage source directory resolution)
  • restart_source_directory (solve stage, when restart source is resolved)

Dry-run guarantees:

  • no run directory creation,
  • no control/post recipe writes,
  • no scheduler script writes,
  • no job submission.

10. Structured Error Output Contract

Validation and CLI usage errors are emitted as one-line, machine-parseable records:

ERROR <CODE> | key=<yaml_or_cli_key> | file=<path_or_dash> | message=<summary> | hint=<actionable_hint>

Current normalized error code set:

  • CLI_USAGE_INVALID
  • CFG_MISSING_SECTION
  • CFG_MISSING_KEY
  • CFG_INVALID_TYPE
  • CFG_INVALID_VALUE
  • CFG_FILE_NOT_FOUND
  • CFG_GRID_PARSE
  • CFG_INCONSISTENT_COMBO

This contract is exercised by Python tests and should remain stable for wrappers and CI parsers.

11. Modular Profile Strategy

PICurv is intended to be used with reusable profile libraries.

Typical pattern:

  1. keep case.yml focused on physics, grid, BCs, and run duration,
  2. keep solver.yml focused on numerical strategy,
  3. keep monitor.yml focused on logging, diagnostics, profiling, and I/O cadence,
  4. keep post.yml focused on analysis outputs,
  5. recombine them as needed for different studies.

Examples:

  • same case.yml + a lighter monitor.yml for fast debug runs,
  • same case.yml + a stricter solver.yml for convergence checks,
  • same case.yml + multiple post.yml recipes for different analysis outputs,
  • same solver.yml reused across many cases when the discretization strategy is stable.

This is why picurv treats these roles as separate inputs instead of one monolithic file.

For prebuilt reusable profiles, also see the local guides under:

  • config/solvers/
  • config/monitors/
  • config/postprocessors/
  • config/schedulers/
  • examples/master_template/

12. Binary Resolution and Rebuild Safety

picurv resolves simulator and postprocessor for a run using this precedence:

  1. The run's pinned copies — when the run's <run.config>/active.json records executables, every stage of that run launches those copies.
  2. Invocation directory — if the binary exists as a sibling of the invoked picurv script (e.g. case-local copies from --pin-binaries), it is used next.
  3. Project bin/ directory — the default location after make all.

Run-time pinning (opt-in). Staging a solve with --pin-executables copies both executables into <run.config.bin> and records each copy's path, SHA-256, and build identity in active.json. The run manifest and software lock then describe those copies, not the installation. Without the switch a run launches the installation's bin/.

Setting Pins
neither switch, no workspace setting no
--pin-executables on run or sweep yes
reproducibility.pin_executables: true in the workspace yes, for every staging in it
--no-pin-executables no, even when the workspace sets it
  • A continuation keeps the run's pin. --pin-executables on a pinned run re-pins it to the current build under that continuation's revision in <run.config.history>; --no-pin-executables on a pinned run is refused, so the run's records never name a build it did not launch.
  • Post-processing launches the postprocessor the run is pinned to. The switches apply only when a solve is staged.
  • Each member of a sweep is pinned in its own run directory, and the array scripts launch $RUN_DIR's copy. A study whose members disagree about pinning is refused.
  • An executable that is not built is left unpinned with a warning.

Job-start identity check. Every generated Slurm script, pinned or not, runs the executable's --version after module setup and before the launcher, and exits before any rank starts when the reported identity, including the PETSc line, differs from the one read at staging. When staging could not read an identity, the job logs the one it finds and launches.

bin/picurv is a launcher for picurv_cli/picurv. This means:

  • there is one stable executable entrypoint backed by the picurv_cli/ package,
  • make conductor recreates the launcher (idempotent),
  • bootstrap-managed installs run with the repo-local .picurv-venv Python,
  • etc/picurv.sh adds bin/ to PATH so picurv works from any directory.

Rebuilding while jobs are running:

  • Updating picurv (the Python script) mid-run is always safe — it is only used to launch jobs, not during solver execution.
  • Rebuilding simulator/postprocessor (make all) overwrites the binaries in bin/. A pinned run is unaffected. An unpinned Slurm job that has not started fails its job-start identity check instead of running the new build, and has to be restaged.
  • The run manifest records the build identity of the executables the run launches; picurv version checks the currently active identity.

Recommended workflow for concurrent development and production:

picurv run --solve --cluster cluster.yml --pin-executables ... # copies bin/ into the run
make all # safe: the run keeps its copies

12.1 Workspace Input Import Mode Entries

Value Maps to
copycopy
hardlinkhardlink
referencereference
reflinkreflink

Every mode below is supported. They were exercised locally (asset-store-local-2026-09-21) and on the cluster's Lustre scratch (asset-lifecycle-grace-2026-10-01), where copy, hardlink and reference imports each fed a precompute that a second precompute reused, and reflink was refused with the filesystem's reason. Object accumulation at campaign scale and remote-backed pruning have not been exercised.

copy

Identity. picurv inputs import <kind> <source> --mode copy.

What it does. Copies the source into its canonical workspace inputs/ home and catalogues the source checksum, size, and new relative path.

When to choose it. Default to copy when portability and independent ownership matter more than local disk duplication. Unlike links, the workspace remains valid if the source is moved or deleted.

Parameters it owns. Optional --name supplies the destination basename.

Interactions. Storage includes the copied file when a run locks and materializes an asset derived from it.

Diagnostics. Success prints the catalog ID and relative path; an existing target or missing source fails before the catalog changes.

Evidence. Unit verified — tests/test_workspace_lifecycle.py checks the copied bytes and catalog entry. Integration verified - asset-store-local-2026-09-21: a copied field became an initial-condition object that a second precompute reused unchanged. Production verified - asset-lifecycle-grace-2026-10-01: on Lustre a copied grid got its own inode, and a precompute from it was reused by the next precompute.

Limitations. Uses additional disk space equal to the imported file.

reflink

Identity. picurv inputs import <kind> <source> --mode reflink.

What it does. Requests a copy-on-write clone through cp --reflink=always, then catalogues it like a copy.

When to choose it. Prefer it for very large local inputs on a filesystem that supports reflinks: it begins space-efficiently but remains independently writable, unlike hardlink.

Parameters it owns. Optional --name supplies the destination basename.

Interactions. Failure does not fall back silently; choose copy explicitly when the filesystem reports that reflinks are unsupported.

Diagnostics. The import fails with the native copy error if reflink creation is unavailable and writes no catalog record.

Evidence. Integration verified - asset-store-local-2026-09-21: on a filesystem without reflink support the import failed with cp's "Operation not supported", left no temporary file, and wrote no catalog record. A successful reflink import has not been exercised; that needs a filesystem that supports it. Production verified - asset-lifecycle-grace-2026-10-01: Lustre scratch refused it the same way. Supported on the owner's decision, since the refusal path is the one most users meet.

Limitations. A successful clone needs a copy-on-write filesystem with reflink support, such as Btrfs or XFS; none has been tested.

hardlink

Identity. picurv inputs import <kind> <source> --mode hardlink.

What it does. Creates a second directory entry for the same inode and catalogues the imported path.

When to choose it. Use it only for immutable, same-filesystem inputs when avoiding a full copy matters and every owner agrees not to modify the bytes.

Parameters it owns. Optional --name supplies the destination basename.

Interactions. Source and destination share mutations. Asset checksums detect a changed provider input and prevent stale object reuse, but cannot undo the mutation.

Diagnostics. Cross-filesystem or permission failures are reported before the catalog changes.

Evidence. Integration verified - asset-store-local-2026-09-21: the imported path shares the source's inode, the catalog records the source checksum, and after one byte of the shared file changed the next precompute built a new object rather than reusing the old one. Production verified - asset-lifecycle-grace-2026-10-01: on Lustre the imported grid shared the source's inode (2 links), and its precompute was reused.

Limitations. Shared-inode ownership is easy to misuse, and it cannot cross filesystems.

reference

Identity. picurv inputs import <kind> <source> --mode reference.

What it does. Writes a small .reference.yml containing the absolute target, registration checksum, and byte count; it does not copy the target.

When to choose it. Use it for an authoritative shared dataset that should remain externally owned. Choose copy when the workspace or storage archive must be portable.

Parameters it owns. Optional --name names the reference record.

Interactions. Resolution fails loudly when the target is missing. A target whose bytes changed since registration is used as it now is: its current checksum selects a new asset object, so nothing stale is reused, but no warning is printed and the registration checksum is not compared. Storage records the dependency but neither archives nor prunes the external file.

Diagnostics. Registration prints an external-reference warning; missing targets fail when registered or consumed.

Evidence. Unit verified — tests/test_workspace_lifecycle.py checks reference content and catalog identity. Integration verified - asset-store-local-2026-09-21: a reference import fed a solver run, and changing one byte of its target built a new object. Production verified - asset-lifecycle-grace-2026-10-01: on Lustre a 280-byte reference record fed a precompute that the next precompute reused.

Limitations. Restoring the workspace cannot restore an external target; its owner must make the same path available or the reference must be replaced.

13. Generated Runtime Artifacts

Single run (run):

  • <run.config>/*.control, bcs*.run, immutable YAML snapshots, plus optional whitelist.run / profile.run sidecars when enabled
  • <run.config.history>/<revision>/ (new active config snapshots for continuation)
  • <run.post_recipes>/<recipe-id>/{post.yml,post.run,state.json}
  • <run.inputs>/{grid,initial_condition,inlet_profiles,restart}/ and <run.asset_lock>
  • <run.checkpoints>/, <run.analysis>/, and <run.visualization>/
  • <run.runtime_logs>/ and <run.scheduler>/ (scripts, stream logs, and submission state)
  • runs/<run_id>/manifest.json

Sweep (sweep):

  • studies/<study_id>/cases/<case_i>/...
  • studies/<study_id>/scheduler/case_index.tsv
  • studies/<study_id>/scheduler/solver_array.sbatch
  • studies/<study_id>/scheduler/post_array.sbatch
  • studies/<study_id>/scheduler/solver_<array_jobid>_<taskid>.out/.err, post_<array_jobid>_<taskid>.out/.err
  • studies/<study_id>/scheduler/submission.json
  • studies/<study_id>/output/analysis/metrics_table.csv
  • studies/<study_id>/output/analysis/plots/*.png (if plotting enabled and matplotlib available)
  • studies/<study_id>/study_manifest.json

14. <tt>storage</tt>

storage is a top-level command registered from picurv_cli/storage/, and is the one command family this page does not detail. Subcommands: setup, plan, protect, offload, restore, verify, list, show, status.

Full semantics, retention model, and rclone configuration are documented in Storage Management Guide.

15. Next Steps