Checkpoints: state, accessors, save & load#
The checkpoint is the central object of qc-rs — every calculation is a checkpoint you build, extend, run, and query. Core concepts introduced the model; this page is the reference for what a checkpoint holds and the API to read and persist it.
What a checkpoint holds#
A checkpoint bundles:
the molecular input — geometry, basis (
ao),charge,spin,ao_rep, and the resolvediopmap;the current electronic state —
current_mo(row-MO coefficients) +current_density, updated by the guess, SCF, and CASSCF;materialized results — the SCF/LCT/opt/property records;
workflow metadata — the pending graph, trace/restart metadata, and cache metadata.
The current MO/density is a single current set (guess, SCF, and CASSCF update it in place, not per-stage copies). Coordinates are stored in bohr.
Building and inspecting#
import qc
m = qc.chk.new(atom="O 0 0 0.117; H 0 0.757 -0.469; H 0 -0.757 -0.469",
ao="cc-pvdz", unit="angstrom")
# molecular accessors (some are properties, some methods — note the ())
m.natom # 3 (property)
m.symbols # ['O','H','H']
m.charge, m.spin # (0, 1)
m.nelectron() # 10 (method)
m.coordinates() # (natom, 3) array, bohr
m.nuclear_energy() # scalar, hartree
m.dummy_atoms(), m.translation_vectors() # special atoms
Adding steps: functional and method forms#
Every workflow verb exists both ways — identical behavior:
qc.scf(m, ref="r") # functional
m.scf(ref="r") # method-chain — the same pending step
The verbs: guess, ints, scf, casscf, fci, dmrg, lct, td, .opt(), plus qc.grad. Adding a
step does no heavy computation — it returns a new checkpoint with a pending node. .run() materializes
the results.
Reading results#
After .run(), the step accessors expose the materialized records:
m = m.scf(ref="r").run()
m.scf.energy # -76.026794
m.scf.converged # True
m.scf.ncycle # 9
m.scf.energy_components # {'core':..., 'coulomb':..., 'exchange':...}
m.scf.gradient # forces (after a gradient/opt)
m.lct.energy, m.lct.e_corr # after lct(method="mp2")
m.opt.converged, m.opt.energy # after .opt()
m.prop.chrg.hirshfeld() # properties (the qc.prop namespace)
Before .run(), m.scf is a pending node; after, it is the result accessor.
Logging and display#
m.run(log="stdout") # stream the live transcript
m.log(format="text") # replay the stored transcript ("text"/"markdown"/"jsonl")
m.show("result") # rendered state/result snapshot
m.run_events() # raw event stream: list of JSON strings
See the logging chapter.
Save and load#
A checkpoint persists to an HDF5 .qch5 file and reloads into a queryable/extendable checkpoint:
m.save("water.qch5") # persist state + results + pending metadata + transcript
r = qc.chk.load("water.qch5") # restore
r.scf.energy # -76.026794 results survive the round-trip
r.scf(xc="b3lyp").run() # add more steps to the loaded checkpoint
save/load is how you stop and resume: run an expensive step once, save, and later load to compute
properties, optimize, or restart — no recomputation. (Session-sticky parallelism from run(nthread=/nmpi=)
is not saved.)
Importing orbitals: guess("read")#
guess("read", source="other.qch5", irreps=...) imports and projects the MOs from another checkpoint into
the current basis — for restart or cheap-basis → big-basis stepping (initial-guess chapter).
irreps is "auto" (preserve labels only when symmetry matches), "preserve" (mismatch is an error), or
"ignore" (drop labels). qc.chk.load(path) already restores the whole checkpoint, so
qc.chk.load(path).guess("read") is usually redundant.
Reference: common accessors#
accessor |
form |
returns |
|---|---|---|
|
property |
int |
|
property |
list of element symbols |
|
method |
int / float |
|
method |
|
|
property |
|
|
property |
one-electron matrices (after |
|
property |
orbital table / MO coefficients |
|
step accessor |
the materialized result fields |