vibeview.qvf

QVF reader — the core file-open lifecycle (§2.4 of the design doc).

Responsibilities: - Open .qvf zip archive, extract + validate manifest.json - Parse sections into pydantic models - Verify sha256 of every binary member before use (Rule 4) - Lazy extraction of volumetric .dat blobs

Module Attributes

QVFSource

a filesystem path, raw zip bytes, or a seekable binary file-like object (BytesIO, an opened file, etc.).

Functions

clamp_replication(replication, pbc)

Force the replication count to 1 on every non-periodic axis.

Classes

Atom(symbol, position, atomic_number[, ...])

One atom.

AtomPropertiesData(mulliken_charges, ...[, ...])

BandsData(kpath, eigenvalues, fermi)

BasisShell(center, l, exponents, coefficients)

One contracted shell of the GTO basis (§ 1.5).

BondOrdersData(method, pairs)

Bond-order analysis section.

CitationsData(bibtex)

BibTeX bibliography embedded in the QVF.

DOSCOOPData(energies, projections, ...)

COOP/COHP bonding analysis section (dos.coop or dos.cohp).

EPRData(raw)

EPR section payload.

EquationOfStateData(volumes, energies, fit)

GridData(origin, voxel_vectors, shape)

JobSpecData(job_type, method, basis, ...)

job.spec section payload — the declarative specification of the calculation the archive requests (spec § 5.9).

Manifest(*, qvf_version, source, sections[, ...])

MemberSpec(*, path, format, sha256[, dtype, ...])

One member of a section (a file inside the zip).

NMRData(raw)

NMR section payload.

PhononBandsData(qpath, frequencies)

PhononDOSData(frequencies, dos, meta)

QTAIMData(points, bond_paths)

QTAIM topological analysis section.

QVFReader(source)

Read a .qvf archive and provide lazy access to sections.

ReactionPathData(atoms, coords, energies, ...)

Self-contained reaction path (reaction.path).

ReactionWaypoint(frame_index, label, kind[, ...])

One reaction-path waypoint annotation.

ReactionWaypointsData(trajectory_ref, ...)

Waypoint annotations layered on a referenced trajectory.

RunRecordData(program, program_version, ...)

run.record section payload — the self-contained record of one program invocation (verbatim input + full log, spec § 5.8).

SCFHistoryData(iterations)

Per-iteration SCF trail.

ScanSurfaceData(axis_a, axis_b, energies[, ...])

2D relaxed-scan energy surface (scan.surface).

Section(*, id, kind[, members, component, ...])

One section from the manifest.

Source(*, program, version, calculation)

SpectraData(frequencies, intensities)

StructureData(atoms, pbc, lattice_vectors, bonds)

A unit cell, or a molecule when pbc is all-False.

SymmetryData(raw)

spglib-style symmetry analysis embedded in the QVF.

TrajectoryData(atoms, coords, energies)

VibrationsData(atoms, frequencies, displacements)

ViewerDefaults(*[, auto_open])

Viewer defaults from manifest.json.

WavefunctionGTOData(structure_ref, pure, ...)

wavefunction.gto payload.

Exceptions

CriticalSectionUnsupportedError

A section (or root extension) flagged critical: true has a kind the viewer cannot render.

ManifestValidationError

manifest.json failed JSON Schema validation.

QVFError

Base for all QVF reader errors.

QVFOpenError

Cannot open or read the .qvf file.

SHA256MismatchError

sha256 of a member does not match the manifest.

SectionNotFoundError

Requested section id not found in manifest.

class vibeview.qvf.Source(*, program, version, calculation)[source]

Bases: BaseModel

Parameters:
  • program (str)

  • version (str)

  • calculation (str)

program: str
version: str
calculation: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class vibeview.qvf.MemberSpec(*, path, format, sha256, dtype=None, shape=None)[source]

Bases: BaseModel

One member of a section (a file inside the zip).

Parameters:
path: str
format: str
sha256: str
dtype: str | None
shape: list[int] | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class vibeview.qvf.Section(*, id, kind, members=<factory>, component=None, trajectory_ref=None, **extra_data)[source]

Bases: BaseModel

One section from the manifest.

Parameters:
model_config = {'extra': 'allow'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

id: str
kind: str
members: dict[str, MemberSpec]
component: str | None
trajectory_ref: str | None
class vibeview.qvf.ViewerDefaults(*, auto_open=<factory>, **extra_data)[source]

Bases: BaseModel

Viewer defaults from manifest.json.

Known fields (auto_open) are explicit. All other keys are per-section hints (e.g. "density": {"isovalue": 0.05, ...}) and are captured via Pydantic’s extra=”allow” in model_extra.

Parameters:
model_config = {'extra': 'allow'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

auto_open: list[str]
class vibeview.qvf.Manifest(*, qvf_version, source, sections, viewer_defaults=None, **extra_data)[source]

Bases: BaseModel

Parameters:
model_config = {'extra': 'allow'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

qvf_version: int
source: Source
sections: list[Section]
viewer_defaults: ViewerDefaults | None
exception vibeview.qvf.QVFError[source]

Bases: Exception

Base for all QVF reader errors.

exception vibeview.qvf.QVFOpenError[source]

Bases: QVFError

Cannot open or read the .qvf file.

exception vibeview.qvf.ManifestValidationError[source]

Bases: QVFError

manifest.json failed JSON Schema validation.

exception vibeview.qvf.SHA256MismatchError[source]

Bases: QVFError

sha256 of a member does not match the manifest. Hard error for that section.

exception vibeview.qvf.SectionNotFoundError[source]

Bases: QVFError

Requested section id not found in manifest.

exception vibeview.qvf.CriticalSectionUnsupportedError[source]

Bases: QVFError

A section (or root extension) flagged critical: true has a kind the viewer cannot render. Per the QVF spec (§2.2 / §5.5 / §7) the consumer MUST refuse to open such a file rather than silently render a partial, misleading view.

class vibeview.qvf.Atom(symbol, position, atomic_number, atom_name=None, residue_name=None, residue_seq=None, chain_id=None, b_factor=None)[source]

Bases: object

One atom. The biomolecular fields are optional and default to None.

Chemistry files (XYZ, a computed structure) carry none of them; a PDB carries all five, and the cartoon/ribbon work (roadmap workstream D) is built on them — atom_name identifies the backbone trace, chain_id + residue_seq order it, residue_name colours it, b_factor carries the temperature factor (or, for a predicted structure, the per-residue confidence a predictor writes into that column). Optional rather than required so every existing archive, and every non-biomolecular producer, keeps working untouched.

Parameters:
  • symbol (str)

  • position (ndarray)

  • atomic_number (int)

  • atom_name (str | None)

  • residue_name (str | None)

  • residue_seq (int | None)

  • chain_id (str | None)

  • b_factor (float | None)

symbol: str
position: ndarray
atomic_number: int
atom_name: str | None = None
residue_name: str | None = None
residue_seq: int | None = None
chain_id: str | None = None
b_factor: float | None = None
vibeview.qvf.clamp_replication(replication, pbc)[source]

Force the replication count to 1 on every non-periodic axis.

Replicating along a non-periodic axis would tile the structure along a synthesized, non-physical lattice column — for a 2D slab that fabricates a stack of sheets that the calculation never contained.

Parameters:
Return type:

tuple[int, int, int]

class vibeview.qvf.StructureData(atoms, pbc, lattice_vectors, bonds, dim=3, supplied_residues=None, supplied_chains=None, supplied_secondary_structure=None)[source]

Bases: object

A unit cell, or a molecule when pbc is all-False.

For dim < 3 the lattice columns dim..2 are non-physical: vibe-qc synthesizes them so AO integrals and spglib always see a full-rank 3x3 matrix, and the SCF energy is provably invariant to their length. They are NOT cell edges and must never be drawn, replicated along, or used as a geometric extent. pbc is the only signal that separates a synthesized column from a real lattice vector — a synthesized 30-bohr normal and a real 30-bohr vacuum gap are numerically identical in lattice_vectors.

Parameters:
atoms: list[Atom]
pbc: tuple[bool, bool, bool]
lattice_vectors: ndarray | None
bonds: list[tuple[int, int, float, tuple[int, int, int]]] | None
dim: int = 3
supplied_residues: list[dict[str, Any]] | None = None
supplied_chains: list[str] | None = None
supplied_secondary_structure: list[dict[str, Any]] | None = None
property has_residues: bool

True when this structure carries biomolecular identity.

Either carrier counts: per-atom residue numbers, or a producer-supplied residues list on the section object. A producer may legitimately supply the second without the first.

chain_ids()[source]

Chain ids, in presentation order.

The producer-supplied chains list when the archive has one (it may order chains for presentation, and may name a chain that contributes no residue), otherwise the chains chains() derived.

Return type:

list[str]

chains()[source]

{chain_id: [(residue_seq, [atom indices]), ...]}.

A producer-supplied residues list wins over the derivation below (spec § 5.1 precedence). Everything after this paragraph describes that derivation, which is what runs for a PDB import and for every archive whose producer supplied nothing.

Residues appear in the order the file lists them, which for a PDB is the order along the chain — the ribbon must follow the actual connectivity, and sorting by residue number would silently reorder insertion codes or non-monotonic numbering. Atoms with no residue identity are skipped rather than lumped into a fake chain; a file with none simply yields {}.

Grouping is by contiguous run of (chain, sequence, name), not by a global key. PDB residue numbers are only four columns wide and wrap at 9999, so a solvated system reuses them: keying globally merged a lipid and a water that happened to share number 1001 into one 80-atom “residue” (measured: 1,256 such collisions on a 150k-atom membrane protein, 9,999 buckets where the file holds 12,010 residues). Contiguity is also what makes insertion codes behave, since those too are listed in order.

Return type:

dict[str, list[tuple[int, list[int]]]]

ca_residues(chain_id=None)[source]

(chain, residue_seq, CA atom index) for each CA-bearing residue.

The single ordering used by backbone_trace() and by the supplied-assignment branch of secondary_structure(), so the two cannot drift apart: a per-CA label list that did not line up with the trace it is zipped against would mislabel a whole chain.

Public because renderers need it. Anything building a per-CA array to zip against backbone_trace() — a selection mask, a colour array — must walk this exact ordering rather than re-deriving it, since a second copy of the walk can drift. It was private until 2026-07-26, which forced the cartoon renderer to reach in through getattr and carry a duplicated fallback.

Parameters:

chain_id (str | None)

Return type:

list[tuple[str, int, int]]

backbone_trace(chain_id=None)[source]

Alpha-carbon coordinates, in chain order — the ribbon spine.

[N, 3]; empty when the structure has no CA atoms. Pass chain_id for a single chain, or leave it None to concatenate every chain (callers drawing one ribbon per chain should ask per chain, so the spline does not jump between them).

Parameters:

chain_id (str | None)

Return type:

ndarray

secondary_structure(chain_id=None, *, detailed=False)[source]

Per-alpha-carbon secondary structure, aligned with backbone_trace().

One character per CA: "H" helix, "E" extended strand, "C" coil. The list is always the same length as the trace for the same chain_id, so a renderer can zip the two.

With detailed=True, supplied subtype annotations additionally return G (3-10 helix), I (pi helix) and B (beta bridge). Geometric assignment always returns the coarse H/E/C labels.

A producer-supplied secondary_structure range list wins, per chain, over the geometric assignment described below (spec § 5.1 precedence). That is not a preference for tidiness: the CA-only assignment below genuinely cannot tell an alpha- from a pi- from a 3-10 helix, or a beta-bridge from a sheet, and a producer can.

Assignment is from the CA trace alone. Real DSSP (Kabsch & Sander, Biopolymers 22, 2577 (1983)) reads backbone N/CA/C/O and assigns from hydrogen-bond energies; a QVF is not guaranteed to carry O at all, and vibe-view needs this only to decide ribbon geometry. CA-only assignment is an established family of approximations to it, the reference implementation being P-SEA (Labesse, Colloc’h, Pothier & Mornon, Comput. Appl. Biosci. 13, 291 (1997)), which discriminates on CA(i)-CA(i+k) distances plus the virtual CA angle and dihedral. This uses those same descriptors.

The numeric windows below are this implementation’s, chosen to bracket ideal geometry rather than transcribed from the paper. tests/test_secondary_structure.py constructs an ideal right-handed alpha-helix (1.5 A rise, 100 deg/residue, CA on a 2.3 A radius) and an ideal extended strand (3.34 A rise) and measures, under this module’s dihedral sign convention:

helix d2 5.43 d3 5.05 d4 6.20 tau 90.4 alpha 50.0 strand d2 6.68 d3 10.20 d4 13.36 tau 120.7 alpha 180.0

A left-handed helix measures alpha -50.0, so the dihedral sign is what keeps one from being read as the other.

Assignment is per chain even when chain_id is None: running the window across a chain boundary would invent structure out of two unrelated termini that happen to be adjacent in the file.

Parameters:
  • chain_id (str | None)

  • detailed (bool)

Return type:

list[str]

class vibeview.qvf.GridData(origin: 'np.ndarray', voxel_vectors: 'np.ndarray', shape: 'tuple[int, int, int]')[source]

Bases: object

Parameters:
origin: ndarray
voxel_vectors: ndarray
shape: tuple[int, int, int]
class vibeview.qvf.BandsData(kpath: 'dict[str, Any]', eigenvalues: 'np.ndarray', fermi: 'float | None')[source]

Bases: object

Parameters:
kpath: dict[str, Any]
eigenvalues: ndarray
fermi: float | None
class vibeview.qvf.PhononBandsData(qpath: 'dict[str, Any]', frequencies: 'np.ndarray')[source]

Bases: object

Parameters:
qpath: dict[str, Any]
frequencies: ndarray
class vibeview.qvf.PhononDOSData(frequencies: 'np.ndarray', dos: 'np.ndarray', meta: 'dict[str, Any]')[source]

Bases: object

Parameters:
frequencies: ndarray
dos: ndarray
meta: dict[str, Any]
class vibeview.qvf.EquationOfStateData(volumes: 'np.ndarray', energies: 'np.ndarray', fit: 'dict[str, Any]')[source]

Bases: object

Parameters:
volumes: ndarray
energies: ndarray
fit: dict[str, Any]
class vibeview.qvf.SpectraData(frequencies: 'np.ndarray', intensities: 'np.ndarray')[source]

Bases: object

Parameters:
frequencies: ndarray
intensities: ndarray
class vibeview.qvf.TrajectoryData(atoms: 'list[Atom]', coords: 'np.ndarray', energies: 'list[float] | None')[source]

Bases: object

Parameters:
atoms: list[Atom]
coords: ndarray
energies: list[float] | None
class vibeview.qvf.VibrationsData(atoms: 'list[Atom]', frequencies: 'np.ndarray', displacements: 'np.ndarray')[source]

Bases: object

Parameters:
atoms: list[Atom]
frequencies: ndarray
displacements: ndarray
class vibeview.qvf.AtomPropertiesData(mulliken_charges: 'np.ndarray | None', loewdin_charges: 'np.ndarray | None', spin_populations: 'np.ndarray | None' = None, hirshfeld_charges: 'np.ndarray | None' = None, iao_charges: 'np.ndarray | None' = None)[source]

Bases: object

Parameters:
mulliken_charges: ndarray | None
loewdin_charges: ndarray | None
spin_populations: ndarray | None = None
hirshfeld_charges: ndarray | None = None
iao_charges: ndarray | None = None
class vibeview.qvf.CitationsData(bibtex)[source]

Bases: object

BibTeX bibliography embedded in the QVF.

The writer stores references.bib as a binary member (utf-8 bytes + sha256). We decode here so renderers see a string.

Parameters:

bibtex (str)

bibtex: str
class vibeview.qvf.RunRecordData(program, program_version, command, exit_status, started_utc, finished_utc, sequence, input_text, input_size, log_text, log_size, files, attachment_roles)[source]

Bases: object

run.record section payload — the self-contained record of one program invocation (verbatim input + full log, spec § 5.8).

input_text / log_text are decoded UTF-8 (None when the member is absent); input_size / log_size are the uncompressed byte counts from the ZIP central directory so a renderer can size-gate what it pushes to the DOM. files is the optional filename index; attachment_roles lists attachment members present (their bytes are not read here).

Parameters:
  • program (str)

  • program_version (str | None)

  • command (str | None)

  • exit_status (int | None)

  • started_utc (str | None)

  • finished_utc (str | None)

  • sequence (int | None)

  • input_text (str | None)

  • input_size (int)

  • log_text (str | None)

  • log_size (int)

  • files (dict)

  • attachment_roles (list[str])

program: str
program_version: str | None
command: str | None
exit_status: int | None
started_utc: str | None
finished_utc: str | None
sequence: int | None
input_text: str | None
input_size: int
log_text: str | None
log_size: int
files: dict
attachment_roles: list[str]
class vibeview.qvf.JobSpecData(job_type, method, basis, functional, charge, multiplicity, kpoints, tasks, options, raw)[source]

Bases: object

job.spec section payload — the declarative specification of the calculation the archive requests (spec § 5.9). raw keeps the full JobSpecPayload (open for forward growth); the typed fields mirror its portable top level.

Parameters:
  • job_type (str)

  • method (str | None)

  • basis (str | None)

  • functional (str | None)

  • charge (int | None)

  • multiplicity (int | None)

  • kpoints (list | None)

  • tasks (list)

  • options (dict)

  • raw (dict)

job_type: str
method: str | None
basis: str | None
functional: str | None
charge: int | None
multiplicity: int | None
kpoints: list | None
tasks: list
options: dict
raw: dict
class vibeview.qvf.NMRData(raw)[source]

Bases: object

NMR section payload.

Writer (qvf.py::_write_spectra_nmr_section) pass-through of a dict with conventional keys: chemical_shifts, shielding_tensors, j_couplings, isotope, reference, solvent. Shape of each field is not schema-enforced, so we keep the raw dict and let the renderer decide what to surface.

Parameters:

raw (dict)

raw: dict
class vibeview.qvf.EPRData(raw)[source]

Bases: object

EPR section payload.

Writer (qvf.py::_write_spectra_epr_section) pass-through of a dict with conventional keys: g_tensor, hyperfine, zero_field_splitting. Shape of each field is not schema-enforced, so we keep the raw dict and let the renderer decide what to surface.

Parameters:

raw (dict)

raw: dict
class vibeview.qvf.SymmetryData(raw)[source]

Bases: object

spglib-style symmetry analysis embedded in the QVF.

Writer (qvf.py::_write_symmetry_section) passes through whatever dict the producer hands it (space group number, symbol, point group, Hall symbol, …). Keys are conventional, not enforced by schema. The renderer surfaces every key it finds.

Parameters:

raw (dict)

raw: dict
class vibeview.qvf.SCFHistoryData(iterations)[source]

Bases: object

Per-iteration SCF trail.

Writer (qvf.py::_write_scf_history_section) stores a JSON document {“iterations”: [{“iter”, “energy_eh”, “delta_e”, “diis_error”}, …]}. Field set is conventional, not enforced by schema — keep them as plain dicts so the renderer can degrade gracefully when a key is missing (e.g. non-DIIS solvers have no diis_error).

Parameters:

iterations (list[dict[str, float | int]])

iterations: list[dict[str, float | int]]
class vibeview.qvf.BondOrdersData(method, pairs)[source]

Bases: object

Bond-order analysis section.

Parameters:
method: str
pairs: list[dict[str, object]]
class vibeview.qvf.QTAIMData(points, bond_paths)[source]

Bases: object

QTAIM topological analysis section.

Parameters:
points: list[dict[str, object]]
bond_paths: list[dict[str, object]] | None
class vibeview.qvf.DOSCOOPData(energies, projections, integrated, meta)[source]

Bases: object

COOP/COHP bonding analysis section (dos.coop or dos.cohp).

Parameters:
energies: ndarray
projections: ndarray
integrated: ndarray
meta: dict[str, object]
class vibeview.qvf.BasisShell(center, l, exponents, coefficients, pure=True)[source]

Bases: object

One contracted shell of the GTO basis (§ 1.5).

Parameters:
center: int
l: int
exponents: ndarray
coefficients: ndarray
pure: bool = True
class vibeview.qvf.WavefunctionGTOData(structure_ref, pure, n_ao, shells, spin, orbital_kind, energies, occupations, symmetry_labels, alpha_energies, alpha_occupations, beta_energies, beta_occupations, mo_coefficients, mo_coefficients_alpha, mo_coefficients_beta, symmetry_labels_beta=None, atom_populations=None, centroids_bohr=None, n_centres=None, localization_method=None, occupation_semantics=None, k_point=None, relocalization=None)[source]

Bases: object

wavefunction.gto payload.

For restricted: mo_coefficients is set, mo_coefficients_alpha and mo_coefficients_beta are None.

For unrestricted: the per-spin variants are set, and mo_coefficients is None.

Each coefficient matrix is row-major [n_mo, n_ao].

Parameters:
structure_ref: str
pure: bool
n_ao: int
shells: list[BasisShell]
spin: str
orbital_kind: str
energies: ndarray | None
occupations: ndarray | None
symmetry_labels: list[str] | None
alpha_energies: ndarray | None
alpha_occupations: ndarray | None
beta_energies: ndarray | None
beta_occupations: ndarray | None
mo_coefficients: ndarray | None
mo_coefficients_alpha: ndarray | None
mo_coefficients_beta: ndarray | None
symmetry_labels_beta: list[str] | None = None
atom_populations: ndarray | None = None
centroids_bohr: ndarray | None = None
n_centres: ndarray | None = None
localization_method: str | None = None
occupation_semantics: str | None = None
k_point: ndarray | None = None
relocalization: dict[str, Any] | None = None
class vibeview.qvf.ReactionWaypoint(frame_index, label, kind, energy_eh=None)[source]

Bases: object

One reaction-path waypoint annotation.

Parameters:
frame_index: int
label: str
kind: str
energy_eh: float | None = None
class vibeview.qvf.ReactionPathData(atoms, coords, energies, reaction_coordinate, waypoints, lattice=None, dim=None, dim_per_frame=None, reaction_coordinate_label=None, reaction_coordinate_unit=None, frame_volumes=None, volume_grid=None, volume_frame_index=None, volume_label=None, volume_isovalue=None)[source]

Bases: object

Self-contained reaction path (reaction.path).

Binary layout matches trajectory: coords[n_frames, n_atoms, 3] in Å.

Periodic reaction paths (qvf_version >= 2) additionally carry the per-frame lattice + dimensionality so the renderer can draw the cell and wrap atoms across periodic boundaries:

  • lattice is None for molecular paths. Otherwise a float64 array of shape (3, 3) when every frame shares the same lattice (the fixed-cell common case) or (n_frames, 3, 3) for variable- cell paths. Columns are a, b, c, in bohr — matching vibeqc.PeriodicSystem.lattice. The renderer is responsible for the bohr→Å conversion (coords are already Å).

  • dim is None for molecular paths. Otherwise an int in {1, 2, 3}; dim_per_frame is set instead when frames carry different dimensionalities.

Parameters:
atoms: list[Atom]
coords: ndarray
energies: list[float] | None
reaction_coordinate: list[float] | None
waypoints: list[ReactionWaypoint]
lattice: ndarray | None = None
dim: int | None = None
dim_per_frame: list[int] | None = None
reaction_coordinate_label: str | None = None
reaction_coordinate_unit: str | None = None
frame_volumes: ndarray | None = None
volume_grid: GridData | None = None
volume_frame_index: list[int] | None = None
volume_label: str | None = None
volume_isovalue: float | None = None
class vibeview.qvf.ReactionWaypointsData(trajectory_ref, waypoints, reaction_coordinate)[source]

Bases: object

Waypoint annotations layered on a referenced trajectory.

Parameters:
trajectory_ref: str
waypoints: list[ReactionWaypoint]
reaction_coordinate: list[float] | None
class vibeview.qvf.ScanSurfaceData(axis_a, axis_b, energies, coordinate_a_label=None, coordinate_a_unit=None, coordinate_b_label=None, coordinate_b_unit=None, atoms=None, geometries=None)[source]

Bases: object

2D relaxed-scan energy surface (scan.surface).

energies is [nA, nB] (Hartree); axis_a / axis_b are the 1D driven-coordinate values. Optional geometries is the relaxed structure at each node, flattened [nA*nB, n_atoms, 3] in Å (row-major over (a, b)); atoms carries the element symbols.

Parameters:
axis_a: ndarray
axis_b: ndarray
energies: ndarray
coordinate_a_label: str | None = None
coordinate_a_unit: str | None = None
coordinate_b_label: str | None = None
coordinate_b_unit: str | None = None
atoms: list[Atom] | None = None
geometries: ndarray | None = None
vibeview.qvf.QVFSource

a filesystem path, raw zip bytes, or a seekable binary file-like object (BytesIO, an opened file, etc.).

Used by vibe-qc to hand a freshly built QVF over to the viewer without touching disk.

Type:

Anything QVFReader can open

alias of str | Path | bytes | bytearray | memoryview | IO[bytes]

class vibeview.qvf.QVFReader(source)[source]

Bases: object

Read a .qvf archive and provide lazy access to sections.

The archive can come from any of:

  • a filesystem path (str / pathlib.Path ending in .qvf)

  • raw zip bytes (bytes / bytearray / memoryview) — vibe-qc can build a QVF in memory via qvf_bytes(...) and pass them in

  • a seekable binary file-like object (BytesIO, opened binary file, …)

The zip handle is kept open for the lifetime of the reader so lazy binary blobs can be read on demand. close() (or use as a context manager) releases it; if the reader owns an in-memory buffer that is released too.

Parameters:

source (QVFSource)

property manifest: Manifest
property path: Path | None

Path to the .qvf file on disk, or None for in-memory archives.

property source: Source
property sections: list[Section]
property viewer_defaults: ViewerDefaults | None
property provenance: dict[str, Any]

The manifest’s open provenance block ({} when absent).

property dipole_moment: dict[str, Any]

The manifest’s root dipole_moment block ({} when absent).

Root, not ``provenance`` – QVF spec § 4.7 puts it there and the schema declares it as a root property. Reading it off provenance silently yields None for every file ever written, which is what left the dipole arrow and the dipole readout dead.

Keys: total_debye, vector_debye (3), origin (3).

property thermochemistry: dict[str, Any]

The manifest’s root thermochemistry block ({} when absent).

Root, for the same reason as dipole_moment. Producer keys (python/vibeqc/runner.py) are zpve_eh, enthalpy_eh, entropy_cal_mol_k, gibbs_free_energy_eh, temperature_k and pressure_atm.

Note the entropy is cal/mol/K, not Eh/K – the one field here whose unit is not atomic.

property run_status: str | None

The archive’s place in a calculation lifecycle (spec § 3.2): "pending" for a job container that has not yet run, "running" while the job is in flight (live checkpoint), then "converged" or "failed". None when not stated (an ordinary results archive).

property checkpoint_info: dict[str, Any]

seq (monotonic), wall_time_s, written_at, optionally scf_iteration / energy_eh on mid-SCF snapshots.

Type:

provenance.checkpoint ({} when absent)

run_record_sections()[source]

All run.record sections in run-history order.

Ordered by their sequence field (spec § 5.8; a record without one sorts before sequenced records, keeping manifest order among themselves). The last entry is the latest run — the one whose results the archive’s other sections describe.

Return type:

list[Section]

run_record_position(section_id)[source]

(1-based position, total) of a run.record in run history.

Position total is the latest run. (0, 0) when the section is not a run.record of this archive.

Parameters:

section_id (str)

Return type:

tuple[int, int]

lifecycle_warnings()[source]

Container-lifecycle consistency warnings (spec § 3.2, § 5.9).

“Done” means a terminal run_status (converged / failed) plus a complete latest run.record — one that carries both its input and log members (an empty log is complete: a run that failed before output began legitimately logged zero bytes). Returns human-readable warnings, empty when the archive is consistent. Non-terminal and unstated statuses never warn.

Return type:

list[str]

section_is_partial(section_id)[source]

True when the producer marked this section partial — still growing in a live checkpoint (e.g. an optimization trajectory).

Parameters:

section_id (str)

Return type:

bool

has_section(section_id)[source]
Parameters:

section_id (str)

Return type:

bool

get_section(section_id)[source]
Parameters:

section_id (str)

Return type:

Section

section_error(section_id)[source]

Return error string if this section had a sha256 mismatch, or None.

Parameters:

section_id (str)

Return type:

str | None

set_edit_overlay(positions, symbols, *, lattice_vectors=None)[source]

Record viewer-side edited geometry (see _edit_overlay).

positions is an (n, 3) sequence in angstroms, symbols the matching element symbols. Subsequent read_structure() calls return this geometry (with explicit bonds dropped — atom indices from the file no longer apply) instead of the archive’s.

lattice_vectors replaces the current edit-overlay lattice when supplied. Omitting it preserves the current lattice, which lets ordinary atom edits made after a supercell build keep that expanded cell. The lattice is reset together with the atoms by clear_edit_overlay().

Return type:

None

clear_edit_overlay()[source]

Drop viewer-side edits; read_structure() returns the file again.

Return type:

None

property has_edit_overlay: bool
set_wavefunction_overlay(section_id, wavefunction)[source]

Register a viewer-computed wavefunction under section_id.

The id also gets a synthetic Section so the sidebar and every reader.sections consumer see it exactly like an archived one. The section carries no members: nothing will read them, because read_wavefunction_gto() short-circuits on the overlay first.

Registering the same id twice replaces the payload and leaves the single synthetic section in place, so re-running a criterion does not accumulate sidebar rows.

Parameters:
Return type:

None

clear_wavefunction_overlays(section_ids=None)[source]

Drop selected (or all) viewer-computed wavefunctions and their sections.

Parameters:

section_ids (list[str] | None)

Return type:

None

property wavefunction_overlay_ids: list[str]

Section ids currently backed by a viewer-computed wavefunction.

read_structure(section_id='structure')[source]

Read + verify a structure section. Always eager.

section_id defaults to the primary "structure" section. Wavefunctions may reference a different structure, which callers can request explicitly so the displayed atoms, cell, and AO centres stay registered.

When an edit overlay is set (set_edit_overlay()), it applies only to the primary structure. Its returned atoms are the edited geometry and bonds is None (auto-bonding applies). PBC/dimensionality still come from the file; the lattice comes from the overlay when an edit replaced it.

Parameters:

section_id (str)

Return type:

StructureData

read_bonds(section_id)[source]

Read a canonical bonds section as (i, j, order, image).

Parameters:

section_id (str)

Return type:

list[tuple[int, int, float]]

infer_bonds(structure)[source]

Infer bonds from covalent radii when no explicit bonds section.

Inferred bonds carry order 1.0 (covalent-radius inference cannot recover multiplicity); explicit bonds keep the producer’s order.

When a bond_orders section is present in the same file, its per-pair order values are used to override the bond orders — Mayer/Wiberg bond orders are more accurate than the simple single/double/triple from the bonds section.

Parameters:

structure (StructureData)

Return type:

list[tuple[int, int, float]]

read_volume_grid(section_id)[source]

Read the grid descriptor for a volume section (always eager — tiny).

Parameters:

section_id (str)

Return type:

GridData

read_volume_data(section_id)[source]

Read + verify the volumetric .dat blob (lazy — call on UI activation).

Parameters:

section_id (str)

Return type:

ndarray

read_bands(section_id)[source]
Parameters:

section_id (str)

Return type:

BandsData

read_phonon_bands(section_id)[source]

Read a phonon_bands section (QVF spec §4.13).

qpath mirrors the electronic kpath (labeled segments with n_points); frequencies is [n_qpoints, n_modes] in cm^-1.

Parameters:

section_id (str)

Return type:

PhononBandsData

read_phonon_dos(section_id)[source]

Read a phonon_dos section (QVF spec §4.13).

frequencies and dos are [n_points]; meta is optional producer metadata (smearing, n_atoms, …) and absent on minimal files.

Parameters:

section_id (str)

Return type:

PhononDOSData

read_equation_of_state(section_id)[source]

Read an equation_of_state section (QVF spec §4.14).

volumes / energies are the sampled V-E points (Angstrom^3 / eV); fit carries the producer’s fitted EOS params (model, V0, E0, B0 in GPa, B0_prime, optional unit strings).

Parameters:

section_id (str)

Return type:

EquationOfStateData

read_spectra(section_id)[source]
Parameters:

section_id (str)

Return type:

SpectraData

read_trajectory(section_id)[source]
Parameters:

section_id (str)

Return type:

TrajectoryData

read_vibrations(section_id)[source]
Parameters:

section_id (str)

Return type:

VibrationsData

read_wavefunction_gto(section_id)[source]

Read a wavefunction.gto section (basis + MO coefficients).

Parameters:

section_id (str)

Return type:

WavefunctionGTOData

read_reaction_path(section_id)[source]

Read a reaction.path section (self-contained: frames + waypoints).

v2 archives may carry a lattice binary member + a dim integer in the metadata JSON; both surface on the returned ReactionPathData (None on v1 / molecular).

Parameters:

section_id (str)

Return type:

ReactionPathData

read_reaction_waypoints(section_id)[source]

Read a reaction.waypoints annotation that points at a trajectory.

Parameters:

section_id (str)

Return type:

ReactionWaypointsData

read_scan_surface(section_id)[source]

Read a scan.surface section (2D relaxed energy grid).

Parameters:

section_id (str)

Return type:

ScanSurfaceData

read_atom_properties(section_id)[source]

Read population-analysis charges and spin populations.

Parameters:

section_id (str)

Return type:

AtomPropertiesData

read_nmr(section_id)[source]

Read the NMR spectrum payload from a spectra.nmr section.

The producer hands the writer an opaque dict with conventional keys (chemical_shifts, shielding_tensors, j_couplings, isotope, reference, solvent); we surface the dict as-is.

Parameters:

section_id (str)

Return type:

NMRData

read_epr(section_id)[source]

Read the EPR parameter payload from a spectra.epr section.

The producer hands the writer an opaque dict with conventional keys (g_tensor, hyperfine, zero_field_splitting); we surface it as-is.

Parameters:

section_id (str)

Return type:

EPRData

read_symmetry(section_id)[source]

Read the spglib-style symmetry summary from a structure.symmetry section.

Parameters:

section_id (str)

Return type:

SymmetryData

read_scf_history(section_id)[source]

Read the per-iteration SCF history from a scf_history section.

Iteration record keys are conventional (see SCFHistoryData); the renderer tolerates missing keys.

Parameters:

section_id (str)

Return type:

SCFHistoryData

read_citations(section_id)[source]

Read the BibTeX bytes from a citations section.

The writer stores them as a binary member (utf-8) per design § 1.4 / qvf.py::_write_citations_section. We decode to str here so renderers don’t need to know the on-disk encoding.

Parameters:

section_id (str)

Return type:

CitationsData

read_run_record(section_id)[source]

Read a run.record section — verbatim input + full log of one program invocation (spec § 5.8).

Text members are decoded UTF-8 with errors="replace" (the format requires UTF-8; a lenient decode keeps a slightly broken producer viewable). Attachment members are listed but not read — they can be arbitrary bytes and are only surfaced by name.

Parameters:

section_id (str)

Return type:

RunRecordData

read_run_record_attachment(section_id, role, *, max_bytes=4194304)[source]

Decode a run.record attachment.* member as UTF-8 text.

Attachments are arbitrary bytes; this returns None (rather than raising) when the member is absent, larger than max_bytes (uncompressed, checked from the ZIP central directory before reading), or not valid UTF-8 — the renderer then falls back to listing the attachment by name.

Parameters:
  • section_id (str)

  • role (str)

  • max_bytes (int)

Return type:

str | None

ATTACHMENT_DOWNLOAD_MAX_BYTES = 67108864

Hard ceiling on a single attachment download. The bytes are base64-encoded into a state value and pushed over the websocket, so this bounds memory and socket pressure, not disk.

run_record_attachments(section_id)[source]

Describe a run.record’s attachment.* members for listing.

Metadata only — no payload is read. Each entry carries role, a filename (sanitised to a bare basename; the files index is producer-supplied and must never steer a write), size in bytes, and too_large against ATTACHMENT_DOWNLOAD_MAX_BYTES.

Parameters:

section_id (str)

Return type:

list[dict[str, Any]]

read_run_record_attachment_bytes(section_id, role)[source]

Raw bytes of one attachment.* member, for download only.

Deliberately separate from read_run_record_attachment(), which decodes text for rendering: attachments are arbitrary bytes by spec and callers must not be tempted to put these in the DOM. Returns None when the member is absent or exceeds ATTACHMENT_DOWNLOAD_MAX_BYTES (checked from the ZIP central directory before reading, so a zip bomb cannot be expanded into memory first).

Parameters:
Return type:

bytes | None

read_job_spec(section_id)[source]

Read a job.spec section — the declarative request the archive carries (spec § 5.9). Pair with run_status to tell a pending container from a settled one.

Parameters:

section_id (str)

Return type:

JobSpecData

read_bond_orders(section_id)[source]

Read a bond_orders section (Mayer/Wiberg bond-order analysis).

Parameters:

section_id (str)

Return type:

BondOrdersData

read_topology_qtaim(section_id)[source]

Read a topology.qtaim section (critical points + bond paths).

Parameters:

section_id (str)

Return type:

QTAIMData

read_dos_coop(section_id)[source]

Read a dos.coop or dos.cohp section.

Parameters:

section_id (str)

Return type:

DOSCOOPData

close()[source]
Return type:

None