Skip to content

aeolus1d run, end to end

What the command line does between aeolus1d run case.toml and the exit code: argument parsing, the pre-flight refusals, the optional resume, the run, the result file with its manifest, and which exit code each failure becomes. The chart is the command's seams. What happens inside the stages has charts of its own: the load, the pre-flight, the choice of driver and the write are in Case load, build, run, write; the resume in Resume from a checkpoint. The contract of every function below is in its docstring (the standard is Function contracts and flow charts).

What enters: argv. What leaves: an exit code, log lines (INFO and below on stdout, warnings and errors on stderr), and with --out an HDF5 result plus <out stem>.manifest.json, with --cgns a CGNS file.

flowchart TD
    A["argv: [-q | -v] run CASE flags"] --> P{"build_parser().parse_args"}
    P -- "bad type, bad choice, -q with -v, missing CASE" --> E2["SystemExit 2, usage on stderr"]
    P --> V["_apply_global_verbosity: -q WARNING, -v DEBUG"]
    V --> R["_cmd_run"]
    R --> UC{"--allow-user-code?"}
    UC -- yes --> ENV1["AEOLUS_ALLOW_USER_CODE = 1, never cleared"]
    UC -- no --> LG
    ENV1 --> LG["_configure_run_logging: level, run id, case digest; --log-json also sets AEOLUS_QUIET_SETTINGS, never cleared"]
    LG --> LP{"_load_and_preflight: load_case"}
    LP -- "missing file, bad TOML, unknown key, invalid case" --> M2["main prints the curated message: exit 2"]
    LP --> OV["--chem-every-n / -rtol / -atol written into the case"]
    OV --> PF{"validate_case_pre_run, then _refuse_bad_run_args"}
    PF -- "ValueError" --> X2["ERROR: aeolus1d: refusing to run - reason; exit 2, nothing written"]
    PF --> RS{"_read_resume (only with --resume)"}
    RS -- "ResumeError, naming the file" --> X1["ERROR: resume failed: ...; exit 1"]
    RS --> SG["_build_live_control, _install_stop_signal_handlers: SIGINT / SIGTERM ask for a clean stop"]
    SG --> EG{"--trace-dt, a resume or controllers?"}
    EG -- yes --> AE["_advance_eager: _build_eager_network (resume seeds), _build_tracer, dispatch_advance"]
    EG -- no --> AP["_advance_plain: run_case"]
    AE --> ADV{"advance"}
    AP --> ADV
    ADV -- "max_steps watchdog, NonAdvancingStepError" --> M1["main prints one line: exit 1, no result file"]
    ADV -- "any other exception" --> TB["traceback"]
    ADV -- "t_end reached, or a stop was requested" --> FR["_finish_run: stop note, flush-failure count, _print_run_summary"]
    FR --> WO{"_write_run_outputs"}
    WO -- "--out" --> H5["write_hdf5, then the manifest (resume_sha256 from _read_resume)"]
    WO -- "--cgns" --> CG["write_cgns"]
    WO -- "a write fails" --> M3["missing directory: main prints it, exit 2; any other OSError: traceback"]
    H5 --> OK["exit 0"]
    CG --> OK
    WO -- "neither" --> OK

The signal handlers are put back in a finally whichever way the advance and the write end.

Exit codes

Code When Message
0 the run finished, or stopped cleanly on SIGINT / SIGTERM, and the outputs were written the summary on stdout
1 --resume file unreadable or not a checkpoint resume failed: <file>: ... (stderr)
1 the --max-steps cap was reached; a driver assembled a non-advancing dt one line from main; no result file is written
2 a flag the pre-flight refuses aeolus1d: refusing to run - <reason> (stderr)
2 the case file is missing, unparsable or invalid the curated message of load_case, naming the file
2 a write hits a missing directory (FileNotFoundError) error: <message>
2 argparse refuses the arguments usage and the reason (stderr)
traceback any other exception (KeyError, another RuntimeError, a permission error) not mapped

What the pre-flight refuses

_refuse_bad_run_args (after validate_case_pre_run), each with the flag and the value in the message, before anything is built or written:

  • --info-every-n below 1; --trace-dt not above 0 (NaN included).
  • --progress-dt or --live-flush-interval negative or NaN (0 keeps its meaning: the default cadence, flush at every new sample).
  • --trace-max-snapshots negative or 1 (0 means unbounded, 2 and up is a cap).
  • --cgns with --live-flush-interval, --out and --trace-dt (the CGNS file would get no time series).
  • _refuse_bad_output_paths: an --out or --cgns whose directory does not exist (it used to fail after the whole run), an output that is the case file, and --cgns equal to --out.

--out equal to --resume is not refused. It is the documented way to extend a result in place; the manifest keeps the digest of the file that was read, and a failed write loses the checkpoint (write_hdf5 truncates its target first).

State the command leaves behind

aeolus1d run is a one-shot process, so none of this matters from the shell. It does when main is called in-process (the test suite, an embedding):

  • AEOLUS_ALLOW_USER_CODE=1 after --allow-user-code, never cleared (a maintainer decision, BACKLOG.md: "Two security-relevant findings in the user-code loader").
  • AEOLUS_QUIET_SETTINGS=1 after --log-json (and after warmup, which sets it when unset), never cleared.
  • The aeolus1d logger's handlers, level and run id (-q / -v and --log-level set the level).
  • Matplotlib's backend after turbo-map (not run).

Functions

  • src/aeolus1d/cli/main.py::build_parser
  • src/aeolus1d/cli/main.py::_apply_global_verbosity
  • src/aeolus1d/cli/main.py::main
  • src/aeolus1d/cli/commands/run.py::_add_run_args
  • src/aeolus1d/cli/commands/run.py::_cmd_run
  • src/aeolus1d/cli/commands/run.py::_configure_run_logging
  • src/aeolus1d/cli/commands/run.py::_case_file_hash
  • src/aeolus1d/cli/commands/run.py::_load_and_preflight
  • src/aeolus1d/cli/commands/run.py::_refuse_bad_run_args
  • src/aeolus1d/cli/commands/run.py::_refuse_bad_output_paths
  • src/aeolus1d/cli/commands/run.py::_read_resume
  • src/aeolus1d/cli/commands/run.py::_build_live_control
  • src/aeolus1d/cli/commands/run.py::_install_stop_signal_handlers
  • src/aeolus1d/cli/commands/run.py::_advance_eager
  • src/aeolus1d/cli/commands/run.py::_advance_plain
  • src/aeolus1d/cli/commands/run.py::_build_eager_network
  • src/aeolus1d/cli/commands/run.py::_build_tracer
  • src/aeolus1d/cli/commands/run.py::_StepHooks._maybe_live_flush
  • src/aeolus1d/cli/commands/run.py::_finish_run
  • src/aeolus1d/cli/commands/run.py::_print_run_summary
  • src/aeolus1d/cli/commands/run.py::_write_run_outputs
  • src/aeolus1d/cli/commands/run.py::_manifest_overrides
  • src/aeolus1d/cli/_shared.py::_max_steps_message
  • src/aeolus1d/cli/_shared.py::_same_file
  • src/aeolus1d/io/case.py::validate_case_pre_run
  • src/aeolus1d/io/case.py::run_case
  • src/aeolus1d/io/case.py::dispatch_advance
  • src/aeolus1d/io/writer.py::write_hdf5
  • src/aeolus1d/io/manifest.py::write_manifest