QVF job containers: one file, whole lifecycle¶
A QVF archive can describe a calculation before it has run. Such a
job container carries the structure, a declarative job.spec
section (method, basis, functional, charge, multiplicity, k-mesh,
tasks, engine options), and provenance.run_status = "pending".
Running it updates the same file in place: results sections are
added, a complete run.record (the executed spec, the full log, and
the .system / .perf / structured-event sidecars) is embedded, and
the status settles to converged or failed. The one file is then a
complete, portable record of the calculation - no sidecar needed to
understand it.
The job.spec payload is declarative data, never code: running a
container never executes an embedded script (QVF spec § 5.9).
A single job may name its input geometry with structure_ref on the section
or in its payload; the section reference takes precedence. The input geometry,
drawing members, metadata and extension declarations remain in the archive.
Results receive their own structure and section references, and the result
geometry is the default view. The original job.spec section and payload stay
unchanged, including when execution is forced again.
A legacy job without either reference must have exactly one structure. It keeps
that structure’s id for the latest result and stores the submitted geometry as
attachment.input_structure_* members of the run record. It is not silently
converted into an ambiguous job with several structures. Prior canonical result
sections are replaced in this legacy mode; their old bytes and run history remain
in the archive, without associating old properties with the new geometry.
Colliding result paths and understood references are relocated; conflicting
extension declarations or
opaque vendor references that cannot be relocated safely cause an atomic
rollback to the submitted archive.
basis and functional follow QVF spec § 5.9. A name is a nonempty string.
null states that the method takes no such input: semiempirical,
tight-binding (xTB, DFTB) and MACE jobs record "basis": null and
"functional": null, and Hartree-Fock and correlated wavefunction jobs record
"functional": null. An absent key leaves the choice to the engine. The
runners and write_pending_qvf write these spellings and never the empty
string. Reading a container, vibeqc run treats null, an absent key and the
deprecated "" that earlier versions wrote alike: it supplies no basis set or
functional of its own. A container stamped with the withdrawn qvf_version: 2
is read as version 1 with a W_VERSION_WITHDRAWN warning and is rewritten as
version 1 when it is updated in place; any other version is refused. Explicit
job specs passed to the low-level writer are preserved verbatim, except that
an empty basis or functional is written as null.
Build a pending container¶
import vibeqc as vq
mol = vq.Molecule([vq.Atom(1, [0, 0, 0]), vq.Atom(1, [0, 0, 1.4])], 0, 1)
vq.write_pending_qvf(
mol, "job",
method="rhf", basis="sto-3g",
tasks=["single_point"], # or ["optimize", "hessian"]
options={"perf_log": True}, # supported JSON engine options
)
# -> job.qvf, run_status "pending"
Periodic systems work the same way - pass a PeriodicSystem (its
charge/multiplicity are recorded) plus kpoints=[n1, n2, n3].
options uses the target runner’s keyword names. Values must have a supported
JSON representation; keyword recognition alone does not make arbitrary Python
runtime objects portable. Unknown keys and unsupported representations are
refused at run time rather than silently dropped.
Structured engine options¶
Supply option-class arguments as JSON objects, for example:
options={"rhf_options": {
"use_diis": True, "damping": 0.0,
"max_iter": 120, "conv_tol_energy": 1e-8,
}}
The engine reconstructs its options object before calling the runner. Omitted
fields retain that class’s defaults; explicit zero, false and null values are
not replaced by defaults. Supported records are rhf_options, uhf_options,
rks_options, uks_options, rohf_options, roks_options, mp2_options,
ump2_options, ccsd_options, cisd_options, cc3_options, ccsdt_options,
selected_ci_options, dmrg_options, v2rdm_options,
transcorrelated_options, casci_options, caspt2_options, nevpt2_options,
casscf_options, dlpno_options, dlpno_ccsd_options, mlip_options,
ccm_options, thermo_options, periodic smearing, and
opentrustregion_options when that constructor is available in the installed
runtime.
dlpno_ccsd_options is the LocalCCSDOptions of the local DLPNO-CCSD and
DLPNO-CCSD(T) solver that run_job uses (the O(N^6) correctness pilot stays a
Python-API option). A container states its local triples algorithm with
"triples_mode": "local" (DLPNO-(T0)), "t1" (the default) or "exact".
Its enumerated text fields accept only the values the molecular route
implements, so a misspelling is refused at its path rather than read as some
other choice: triples_mode, localise ("boys" or "none"),
residual_domain, domain_criterion and pno_norm (canonical names). Because
run_job refuses the top-level dlpno_thresholds beside an options object,
dlpno_options and dlpno_ccsd_options records may name their preset in a
reserved "dlpno_thresholds" key, the JSON form of
options_from_dlpno_thresholds: the preset is applied first and the record’s
own fields after it, so an explicit threshold labels the result custom.
options={"dlpno_ccsd_options": {"dlpno_thresholds": "tight",
"triples_mode": "t1"},
"frozen_core": "chemical"}
The run record’s system attachment then carries dlpno_triples_mode and
dlpno_triples_algorithm, the algorithm that ran.
Native enum fields use their public member names as strings (case insensitive),
for example "initial_guess": "SAD" or "scf_accelerator": "DIIS".
Nested option objects such as "grid": {"n_radial": 75} and
"davidson": {"max_iter": 50} are reconstructed recursively. Typed numeric
arrays, including level-shift schedules, are validated element by element.
Python option records retain their constructor validation, including smearing
aliases and CCSD frozen-core explicitness. Boolean values are not numbers here;
"max_iter": true, unknown fields and non-finite numbers are errors that name
the full option path.
This is an engine-specific encoding inside QVF’s existing open options
object, not a new QVF schema version. It does not deserialize arbitrary classes.
Native matrices, nonempty native object arrays (such as explicit ECP objects),
callbacks, CASSCF pt2 objects, and structured band_structure,
dft_plus_u, read_from, dispersion, citype, triples or
dlpno_thresholds objects currently receive an explicit refusal.
Use the Python runner API for those runtime objects. Scalar shorthand forms
remain available where the runner supports them. Existing mapping APIs such as
geom_opt_options and solvent, and fragment atom-index lists, keep their
normal consumer semantics (fragments must contain lists of integer atom
indices; dft_plus_u=[] remains a no-site request). Local Python run_container(..., **overrides)
values remain ordinary runner objects, outside the serialized spec.
An option-conversion refusal occurs before SCF and settles an attempted
in-place execution as failed, preserving the original job.spec bytes.
Run it locally¶
vibeqc run job.qvf
(python -m vibeqc run job.qvf is equivalent.) The runner
reconstructs the job from the spec, streams the ordinary .out and
sidecar files to the output stem (default: the container’s own stem),
and finishes by atomically rewriting job.qvf itself: during
execution the archive reads running; afterwards it is converged or
failed with a complete, sequenced run.record. A run that fails
before producing output settles with an empty embedded log - that is
a complete record of that invocation, not a defect.
A settled container is a record; re-running it must be explicit:
vibeqc run job.qvf --force
appends another sequenced run.record, preserving the earlier runs as
history. --output STEM redirects the sidecar files without moving
the container.
Ship it through vq¶
The container is the whole payload and the updated container is the whole result. With a managed runtime (fleet hosts):
vq submit HOST job.qvf --program vibeqc-dev
vq fetch HOST JOBID --name job.qvf -o results/
The daemon resolves the managed runtime, snapshots its full Git SHA,
runs python -m vibeqc._cli run job.qvf, and rejects any runtime drift
before chemistry starts. vq fetch --name retrieves just the settled
container. vq status --json reports the container’s qvf_lifecycle
(status, sequence, terminal completeness). Routine submissions do not
need a version or SHA argument. Add --expected-sha FULL_40_HEX_SHA
only when reproducing a historical run and you want an extra assertion.
On a host without a managed program entry, the directory form works with any interpreter:
vq submit HOST -d jobdir/ -- vibeqc run job.qvf
See Queue and docs/agent_interaction.md in vibe-queue for
queue mechanics.
Submit it from vibe-view¶
Open any structure, choose Submit to vq cluster, and leave Submit as QVF container enabled. The Job Manager writes a pending container from the structure on screen plus the method and basis fields, submits that one file, and opens the settled artifact with its Job Spec and Run Record panels when it returns.
Writing a pending archive is a producer action. If vibeqc is not installed
next to vibe-view, the switch is disabled and the viewer keeps using its
generated-script submission path.
Open it in vibe-view¶
vibe-view renders the whole lifecycle: a pending
container opens with an amber “pending” chip and a Job Spec panel
stating the job has not yet run; with auto-reload enabled the chip
follows the file through running to its terminal state. A settled
container shows the results plus a Run Record panel per run - the
executed spec, the complete log, the rendered system manifest,
performance log, and structured event table - labeled
“Run #k of N - latest” when the container has been re-run. A terminal
container whose latest record is missing its input or log is flagged
with an explicit warning rather than silently reading as done.
The same archive can also be inspected without a display server:
vibe-view show job.qvf --info # lifecycle and archive summary
vibe-view show job.qvf --plain # one terminal-rendered structure frame
vibe-view tui job.qvf # interactive terminal viewer
Use vibe-view open job.qvf for the graphical viewer. show is useful
in logs and CI; tui is useful over SSH without X forwarding.
What lives where¶
Content |
In the container |
Sidecar file |
|---|---|---|
Structure + |
always, preserved verbatim |
none |
Results (energies, wavefunction, …) |
canonical sections |
assorted ( |
Full log |
|
|
References |
|
|
System manifest |
|
|
Performance / structured logs |
|
|
Sidecar files still land at the output stem - the container makes them
redundant, it does not suppress them. Individual writers are switched
off with the usual runner keywords (write_xyz_file=False, …), which a
container can carry in its options.
Learn by running one¶
The tutorial Running a calculation as a QVF container walks through a pending molecular container, local execution, inspection, terminal and graphical viewing, a deliberate re-run, a periodic container, and the first-class vq submit/fetch path.
Runnable companions live under the checkout path
examples/qvf_containers/:
build_h2_job.pycreates a molecular H2/STO-3G container.build_periodic_he_job.pycreates a tiny periodic He/SCC-DFTB container.inspect_job.pyvalidates either file and prints its spec, status, section kinds, and run history.
Format details: QVF design and the QVF specification (published QVF spec, § 3.2 and § 5.9).
Explicit molecular symmetry source¶
Experimental molecular RHF/UHF single points can request the source-qualified
fixed-orbit path through the symmetry_reduction option. It carries explicit
operations, screening tolerance, omission cap, budget and execution policy.
The shared symmetry reference
describes the strict record and its constructor helper. Every execution
qualifies a fresh integral producer; a saved audit or source hash cannot
replace that check. Keep convergence/guess controls in the existing method
option record. Correlation, derivatives, fitting and periodic calculations
require their own source admission.
With hierarchical screening, executor="ordered" uses native omission bounds
to qualify the fixed mask without integral audit reads. It evaluates all
retained ordered tiles during SCF. executor="auto" with expected_builds
1 or 2 also takes this path and skips unprofitable calibration; larger
estimates keep measured routing and the retained-source audit. This is an
experimental molecular execution choice, not a new symmetry assumption
about the electronic state or a guaranteed speedup. Version 2 source hashes
separate the actual integral mask from qualification and cost evidence.