QVF format specification (v1)¶
Status: Normative. This document specifies the QVF v1 container format and its producer/consumer contract. The machine-readable contract is the JSON Schema
qvf_manifest.schema.json(shipped alongside this file); where prose and schema disagree, the schema wins. This is a self-contained copy of the specification maintained by the vibe-qc project, distributed under Apache-2.0 so that any code can implement a conforming producer or consumer.
QVF (.qvf, “Quantum Visualization Format”) is a ZIP-based container for
quantum-chemistry visualization and analysis data. It keeps one calculation’s
structure, scalar fields, spectra, bands, trajectories, wavefunctions,
provenance, and viewer hints in a single random-access file, instead of
scattering them across Cube, XYZ, Molden, XSF, log, and program-specific
sidecar files. It is also a document format for the steps before a
calculation: the species of a reaction scheme with their chemical identity
(§ 5.1), the scheme that relates them (§ 5.14), the jobs to run on them
(§ 5.9) and a picture of the whole (§ 5.15) travel in one file that the
calculation’s results later join.
The format is intended for the whole quantum-chemistry ecosystem. A QVF producer may be any quantum-chemistry code. A QVF consumer may be a structure viewer, a band plotter, a spectrum tool, a validator, a notebook script, or a GPU viewer.
QVF v1 is deliberately not a restart format. It does not encode integral
caches, SCF internal state, engine-internal grids, or every possible
wavefunction representation. The optional wavefunction.gto section is a
visualization-oriented, Molden-like molecular-orbital carrier, not a universal
restart record.
The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY are used as in RFC 2119.
1. Design goals¶
One shareable artifact. A calculation’s visualization data travels as one
.qvffile.Random access. A consumer reads only the members it needs.
Typed payloads. Every member declares format, dtype, shape, and a sha256 checksum where applicable.
Stable common vocabulary. Common data types use canonical section kinds.
Partial support. A consumer can support a subset of kinds and still open the file. Unsupported vendor sections are reported, not misinterpreted.
Producer neutrality.
source.programcan name any code; core kinds are not producer-specific.
2. Archive model¶
A QVF file is a ZIP archive. The only mandatory member is manifest.json at
the archive root. Every other member is named from the manifest — member paths
are part of the manifest contract, not hard-coded by the container.
A typical archive:
example.qvf
├── manifest.json (REQUIRED — the only member read by name)
├── structure/
│ └── structure.json
├── wavefunction/
│ ├── basis.json
│ ├── mo_metadata.json
│ └── mo_coefficients.dat
├── volumes/
│ ├── density.dat
│ └── density_grid.json
├── spectra/
│ └── ir.json
└── citations/
└── references.bib
Path layout is not semantic. Consumers MUST follow the path fields in
manifest.json and MUST NOT assume ZIP entry order or directory names.
Producers SHOULD use stable, readable directory names for debuggability.
2.1 Byte-level container requirements¶
The archive MUST be a valid ZIP (PKZIP APPNOTE, deflate/store methods).
manifest.jsonMUST be present at the archive root (path exactlymanifest.json, no leading directory). In an archive updated in place, which holds more than one entry of that name, the manifest is the entry whose central-directory record comes last (§ 2.3).Producers SHOULD store
manifest.jsonuncompressed (STORE method) so a consumer can read the table of contents cheaply; other members SHOULD be DEFLATE-compressed. Neither is mandatory — a consumer decompresses via the ZIP method recorded in the central directory regardless.Producers SHOULD write
manifest.jsonlast (or ensure its recorded checksums match the already-written member bytes). Because each member’s sha256 is embedded in the manifest, all member bytes must be finalized before the manifest is serialized.Member paths — every
pathin the manifest and every ZIP entry name — MUST be relative and use/as the only separator: a path MUST NOT contain a backslash (\) or a NUL character, MUST NOT begin with/or with a drive-letter prefix (^[A-Za-z]:), and MUST NOT contain any..path segment. (Schema:ZipPathexpresses the leading-/, NUL, and..rules; validators enforce all of them, § 6.)Each ZIP entry name MUST occur only once in the archive, with one exception: an archive updated in place holds its superseded
manifest.jsonentries until it is repacked (§ 2.3). The ZIP format permits duplicate names and readers disagree on which entry wins, so an archive that duplicates any other name is ambiguous; a consumer SHOULD refuse to open it.Every ZIP entry other than the current
manifest.jsonand directory entries (names ending in/) SHOULD be referenced by a memberpath. An unreferenced (“orphan”) entry, a supersededmanifest.jsonincluded, does not make the archive invalid — it is the expected by-product of updating an archive in place (§ 2.3) — and consumers never read it, because members are reached only through the manifest (§ 2). Validators report it as a warning (§ 6).A consumer SHOULD enforce resource caps before decompressing or parsing anything — per-member and total uncompressed size, compression ratio, and JSON size and nesting depth — to guard against zip-bomb and parser-exhaustion inputs. The sizes are recorded in the ZIP central directory, so they can be checked without decompressing; a reader MUST NOT inflate an entry past the uncompressed size recorded for it. § 6.1 lists the reference values; the reference tools cap each member at 8 GiB (1 gigavoxel of float64).
2.2 Endianness¶
All binary members are stored in little-endian byte order. QVF v1 dtype names (§ 4.2) do not carry a byte-order mark. Producers on big-endian platforms MUST byte-swap to little-endian before writing.
The optional root field byte_order (§ 3.1) states this explicitly. Its
only valid value in v1 is "little", and it documents what every v1 archive
already is: an archive without the field is little-endian too, and a consumer
MUST NOT read its absence as an unknown byte order. Any other value is
invalid — the JSON Schema rejects it, so a validator reports E_SCHEMA (§ 6)
— and a consumer SHOULD refuse an archive that carries one rather than
guess how to read its binary members. Producers MAY write the field; the
reference writers write it in every archive.
The tag belongs in the dtype names themselves (<f8 rather than float64),
where it would describe each binary member. That changes the dtype vocabulary
every consumer validates, so it cannot happen within v1; it is recorded as a
candidate for the next major version (V2-01 in docs/format_review.md), and
byte_order is the v1 declaration until then.
2.3 Updating an archive in place¶
A producer may change an existing archive without rewriting it: a runner that
executes a pending job.spec archive and writes its results back (§ 5.9), a
program that saves live checkpoints of a running calculation (§ 3.2), a tool
that adds an analysis to a finished archive. The ZIP format allows this by
appending. This section fixes how a QVF archive is appended to, so that every
consumer reads an updated archive the same way.
An update:
MAY append new ZIP entries. The producer leaves the bytes of the existing entries where they are, writes the new entries after the last of them (where the old central directory began), and then writes a new central directory that lists every entry of the archive, old and new, in the order of their data.
MUST write a new
manifest.jsonas the last entry of the archive, after every member it references; like any manifest it SHOULD be stored uncompressed (§ 2.1). The new manifest is complete: it lists every section of the updated archive, and its member specs reference the entries the update appended as well as the earlier entries it keeps, whose bytes,sha256andsize(§ 4.2) are unchanged.MUST NOT give a new entry the name of an existing entry, other than
manifest.json. A member whose content changes is written under a new path, and the new manifest references that path.
The previous manifest.json, and every entry the new manifest no longer
references (a replaced member, the members of a removed section), are
superseded. They stay in the archive as orphans (§ 2.1): a consumer
MUST ignore them, and a validator reports each one as the warning
W_ORPHAN_MEMBER. They still count towards the total-size cap of § 6.1.
A consumer that reads manifest.json by name MUST use the entry whose
central-directory record comes last when the archive holds more than one
entry of that name. This is the one exception to the rule that entry names are
unique (§ 2.1): a validator reports E_ZIP_DUPLICATE_ENTRY for any duplicated
name except manifest.json, and for a duplicated manifest.json it reports
W_ORPHAN_MEMBER for each superseded copy. Because an update writes its
manifest last, a reader that walks the local headers in data order instead of
reading the central directory also meets the current manifest last.
Repacking writes the archive anew from its current manifest: every entry
the manifest references, then the manifest, and nothing else. It removes every
orphan and every superseded manifest and changes no member’s bytes, so the
sha256 and size values of the manifest stay valid. The reference toolkit
provides it as the repack operation (informative).
The updated manifest records what changed:
metadata.modified_utc(§ 3.5) SHOULD be set to the time of the update;metadata.created_utcandmetadata.uuidMAY be kept, because the archive is the same archive, changed.provenance.run_status(§ 3.2) follows the calculation’s lifecycle: apendingarchive becomesrunningwhile a runner writes checkpoints, andconvergedorfailedwhen it settles.Each program run an update records is a
run.recordsection (§ 5.8). When an archive carries several, theirsequencefields order them: an update adds its run record with the nextsequenceand keeps the earlier ones unchanged.A
job.specsection is kept verbatim (§ 5.9), so a settled archive still records what was asked.
Appending overwrites the old central directory, so an update interrupted before it writes the new one leaves an archive that cannot be opened. A producer that must not lose the previous state writes the updated archive to a copy and renames it over the original (informative).
2.4 File identification¶
A QVF archive is identified to operating systems, file managers and web
servers by the names below. Every program that reads or writes QVF files
SHOULD declare them exactly as given, so that the desktop associates
.qvf files with one type whichever program installed it last.
Identifier |
Value |
|---|---|
File name extension |
|
Media type |
|
macOS Uniform Type Identifier |
|
Type description |
|
QVF uses a proposed vendor-tree media type with the registered +zip
structured-syntax suffix (RFC 6838, RFC 6839). Its
registration draft awaits maintainer
approval for submission; the QVF media type remains unregistered until IANA
accepts it. A generic ZIP tool may open the archive, and a program that knows
the type reads it as QVF. It is the type a
web server sends for a .qvf file and the one a desktop entry or file
association names. A QVF archive has no magic number of its own beyond the ZIP
signature, and the manifest is written last (§ 2.1), so content sniffing cannot
tell it from other ZIP files; programs identify it by the extension, or by
finding manifest.json with a qvf_version.
registry.json carries the same values under file_type, and
spec/file-type/ carries the declarations ready to copy (informative):
qvf-uti.plist— the macOS type declaration, the dictionary that goes into an application’sUTImportedTypeDeclarations(orUTExportedTypeDeclarations) array inInfo.plist, with the type’s description, conformance, the extension and the media type. One program of a family of applications exports the type and the others import it; the declarations are identical, so macOS resolves the type the same way whichever of them is installed.qvf-mime.xml— the freedesktop.org shared-mime-info definition, a subclass ofapplication/zipmatched by the glob*.qvf, for Linux desktops (installed into$XDG_DATA_HOME/mime/packages/or/usr/share/mime/packages/and activated withupdate-mime-database).
On Windows, the file association’s Content Type value is the media type.
A picture of the archive, for a file manager’s thumbnail or a quick-look
preview, is the thumbnail member of its first preview section (§ 5.15).
3. The manifest¶
3.1 Root object¶
{
"qvf_version": 1,
"schema_uri": "https://vibe-qc.org/spec/qvf/1/manifest.schema.json",
"byte_order": "little",
"source": {
"program": "my-code",
"version": "1.2.3",
"calculation": "h2o_rhf_sto3g"
},
"sections": [ /* … */ ]
}
Root field |
Required |
Meaning |
|---|---|---|
|
yes |
Integer format version. v1 = |
|
yes |
|
|
yes |
Array of section objects (§ 4). |
|
no |
Canonical URI of the JSON Schema. Informational. |
|
no |
Byte order of every binary member. The only valid value is |
|
no |
Calculation-level metadata (§ 3.2). |
|
no |
Descriptive metadata of the archive itself: title, authors, licence, identifiers, time stamps (§ 3.5). |
|
no |
Viewer hints: |
|
no |
Root thermochemistry block (§ 3.3). |
|
no |
Root dipole block (§ 3.3). |
|
no |
Root geometry-constraint block (§ 3.3). |
|
no |
Root energies block: the energy of the primary result, its components, and energies by method (§ 3.6). |
|
no |
Extension governance block (§ 7). |
Producers MUST emit qvf_version: 1. A consumer that only understands v1
MUST refuse to open a file whose qvf_version is an unrecognized major
version — with the one historical exception below.
Historical note — archives stamped
qvf_version: 2. vibe-qc v0.10.0 – v0.15.x stampedqvf_version: 2on archives containing a periodicreaction.path. That bump was a mistake: the only difference from v1 is a single optional member (latticeonreaction.path, § 5.5), which is the additive case that the versioning policy says must not bump the version. The bump was withdrawn by a governance ruling on 2026-07-10 (seeGOVERNANCE.md§ Version history).Such archives are v1-compatible. Consumers SHOULD accept
qvf_version: 2and treat it as1. Producers MUST NOT emit it. A periodic reaction path is detected by the presence of thelatticemember, never by the manifest version.A validator treats such an archive as
qvf_version: 1for every check, the JSON Schema check included, and reports the warningW_VERSION_WITHDRAWN(§ 6): the archive is valid, and the warning records that its producer wrote a version producers must not write. A tool that updates such an archive in place (§ 2.3) writesqvf_version: 1and the v1schema_uriinto its new manifest. Every other value ofqvf_versionis the errorE_VERSION.
3.2 provenance¶
Optional and open (additionalProperties: true): a key that is not in the
table below is allowed, and a consumer ignores one it does not know. A
producer emits only what it knows. The recognised fields are typed by the
schema’s root provenance property:
Field |
Type |
Unit |
Meaning |
|---|---|---|---|
|
string |
— |
Method of the calculation, e.g. |
|
string |
— |
Exchange–correlation functional of a DFT method. |
|
string |
— |
Basis-set name. |
|
integer |
e |
Net charge. |
|
integer |
— |
Spin multiplicity 2S+1. |
|
integer ≥ 0 |
— |
Number of electrons the calculation treats explicitly, the same quantity as |
|
integer ≥ 0 |
— |
Number of SCF iterations. |
|
boolean |
— |
Whether the SCF converged. |
|
|
|
Energy of the SCF method that |
|
|
|
Fermi energy. |
|
number ≥ 0 |
s |
Wall-clock time of the calculation. |
|
integer, 0–3 |
— |
Echo of the structure’s periodic-axis count (§ 5.1): informational here, and never a substitute for reading |
|
enum |
— |
The archive’s place in a calculation’s lifecycle; see below. |
|
object |
— |
Informative bookkeeping of a |
|
array of software objects |
— |
The programs and libraries that produced the results; see below. |
|
string, 7–64 hexadecimal characters |
— |
The producer’s own source revision: a git commit hash, abbreviated or full (40 characters for SHA-1, 64 for SHA-256). Git prints lowercase. |
|
integer ≥ 1 |
— |
Threads the calculation ran with, per process. |
|
integer ≥ 1 |
— |
MPI ranks (processes); 1 for a serial run. |
|
integer ≥ 0 |
— |
GPUs the calculation used; 0 for none. |
|
string |
UTC |
When the calculation started, in the form below. |
|
string |
UTC |
When the calculation finished, in the same form. |
|
string |
— |
Deprecated; see below. |
scf_energy and fermi_energy carry the unit names of § 4.3; the legacy
spellings Eh, eV and Hartree are accepted there but deprecated.
started_utc and finished_utc take the form of the time stamps of the root
metadata block (§ 3.5): an ISO 8601 date and time in UTC,
YYYY-MM-DDThh:mm:ssZ, optionally with a fractional second, the trailing Z
required. A validator checks the form (§ 6), not the truth or the order of the
two. n_threads, n_mpi_ranks and n_gpus record what the run used; the
resources a job.spec asks for are hints (§ 5.9), and the two need not agree.
A pending archive has not run, so these fields and the time stamps, when it
carries them, describe the step that prepared it.
Agreement with the sections. provenance.n_electrons, when present,
MUST agree with basis.n_electrons of a wavefunction.gto section (§ 5.3)
that states one.
software is an array of objects, one per program or library, each
$defs/ProvenanceSoftware (strict: only the fields below and vendor keys
beginning x_). The root source names the QVF producer (§ 3.1) and
run.record.program the code that ran (§ 5.8); software lists every
component that shaped the numbers, such as an integral library or an
exchange–correlation library.
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
string, non-empty |
yes |
Name of the program or library, e.g. |
|
string |
no |
Version, as the component reports it. |
|
string |
no |
Where the component is published, e.g. its home page. A public address only: machine names and internal addresses are private operational detail, like |
"provenance": {
"method": "rks", "functional": "pbe",
"software": [{"name": "my-code", "version": "1.2.3"},
{"name": "integral-lib", "version": "2.9.0",
"url": "https://example.org/integral-lib"}],
"git_commit": "9f2b6c1d4e7a",
"n_threads": 8, "n_mpi_ranks": 4, "n_gpus": 0,
"started_utc": "2026-10-07T12:00:00Z", "finished_utc": "2026-10-07T12:07:31Z",
"wall_seconds": 451.0
}
One provenance field has normative lifecycle semantics:
run_status— one of"pending","running","converged","failed"; the archive’s place in a calculation’s lifecycle.pendingdescribes a job that has not yet run — typically a container carrying astructure(§ 5.1) plus ajob.spec(§ 5.9) and no result sections.runningmarks a live mid-run checkpoint snapshot (such snapshots may also carry an informativecheckpointbookkeeping object with a monotonicseq).convergedandfailedmark a settled terminal archive; a terminal archive whose producer embeds its own input/log also carries arun.record(§ 5.8). An absentrun_statusmeans “not stated” — a consumer MUST NOT infer a status, and in particular MUST NOT treat absence asconverged. An archive moves from one status to the next by being updated in place (§ 2.3) or written anew. An archive that carries severaljob.specsections (a job set, § 5.9) states the status of the set:pendinguntil one of its jobs starts,runningfrom then until every job has settled, thenconvergedwhen every job converged andfailedwhen at least one failed; the status of each job is therun_statusof therun.recordthat names it (§ 5.8).
One provenance field is deprecated:
hostname— the name of the machine the calculation ran on. Producers SHOULD NOT emit it. Consumers MUST ignore it for any purpose other than display and MUST NOT rely on it. It may be removed in a future major version. Archives are meant to be shared, and machine names are private operational detail rather than part of a calculation’s result. The field stays listed so that archives which already carry it remain interpretable; its presence never makes an archive invalid. See also “Sharing and sanitisation” in § 5.8.
3.3 Root metadata blocks¶
These describe the calculation as a whole (not binary payloads), so they live at the manifest root rather than as sections.
thermochemistry—zpve_eh,enthalpy_eh,entropy_cal_mol_k,gibbs_free_energy_eh(Hartree / cal·mol⁻¹·K⁻¹),temperature_k,pressure_atm. All optional.dipole_moment—total_debye,vector_debye(3-vector, Debye),origin: either a conventional name ("center_of_mass","center_of_nuclear_charge","origin") or an explicit 3-vector in bohr. This block stays the canonical place for a bare dipole. Aproperties.electricsection (§ 5.13) may restate it beside the higher multipoles, and the two statements MUST then agree.constraints—frozen_atoms(0-based indices),distance_constraints(each{atoms: [i, j], target_angstrom}).energies— the energies of the calculation, specified in § 3.6.
3.4 viewer_defaults¶
An optional root object carrying hints for consumers that render the archive:
which sections to show first, camera bookmarks and the initial camera, a
cross-fade between two volumes, and how to draw each section.
Hints are suggestions, not data. A consumer MAY ignore any hint, MUST
ignore a hint it does not understand, and MUST NOT refuse to open a file
because a hint is malformed: it ignores that hint and opens the file as if the
hint were absent. A consumer that validates the manifest against the schema
before opening therefore does not refuse a file over a finding in
viewer_defaults. Producers SHOULD emit hints in the shapes and the
lowercase spellings given here.
Member |
Value |
|---|---|
|
Array of section ids to show first. The first |
|
Ordered camera bookmarks ( |
|
The camera a consumer starts with, an object in the shape of a bookmark’s |
|
Two volume sections to cross-fade between and where the blend starts, |
any other key |
A section id; the value is that section’s hint object (§ 3.4.1). A key that names no section is ignored. |
auto_open, bookmarks, camera and crossfade are reserved: a section
MUST NOT use one as its id, because its hint object could not be told
apart from the reserved member. A validator reports a section that does
(§ 6).
camera. The view a consumer opens the archive with: position,
focal_point and view_up, Cartesian 3-vectors in Å, and exactly one of
view_angle (perspective, in degrees, between 0 and 180 exclusive) and
parallel_scale (orthographic, in Å, positive), the shape of
$defs/Camera. A consumer that cannot use the camera, because it is not
such an object or because the consumer draws no 3-D scene, ignores it. A
consumer MAY open an archive without a camera hint at the camera of its
first bookmark.
crossfade. An object that asks a consumer to show two volume sections
(volume.*, § 5.2) blended into each other, for example two orbitals or two
densities on one grid:
Key |
Required |
Type |
Meaning |
|---|---|---|---|
|
yes |
string |
|
|
yes |
string |
|
|
no |
number, 0 to 1 |
Where the blend starts: |
A consumer ignores a crossfade that is not an object or lacks a or b,
and one whose a or b does not name a section it can draw. It reads a
blend that is absent, not a finite number, or outside 0 to 1 as 0.5 and
still applies the pair.
camera, crossfade and the per-section key energy_window (§ 3.4.1) are
specified here only, like render and transfer_function: the schema
reserves camera and crossfade but does not check their values, a
validator MAY report a value that does not match this section as a
warning, and it MUST NOT fail an archive because of one.
3.4.1 Section hint object¶
A section hint object ($defs/ViewerHint) suggests how one section is drawn.
It is defined independently of where it is stored: v1 keys it by section id
directly inside viewer_defaults, and the keys below keep their meaning
wherever a later version places the object. Every key is optional. The object
is open, so a consumer ignores keys it does not know.
Key |
Type |
Meaning |
|---|---|---|
|
number |
Contour level, in the section’s data units (§ 4.3). |
|
string |
Name of the colour map to draw with. Names are not standardised; a consumer uses its default for a name it does not know. |
|
number, 0 to 1 |
Opacity of the drawn surface; in volume mode, the peak of the consumer’s default opacity ramp. |
|
three integers ≥ 1 |
Cells to draw along each lattice vector of a periodic structure. |
|
string |
How a scalar-field section is first drawn: |
|
object |
The function a scalar-field section is drawn with as a volume. |
|
|
The energy range a |
A scalar-field section is one a consumer draws from a 3-D grid: volume.* and
basis.ao. The schema types the first four keys, so a malformed value of one
of them fails schema conformance (§ 6). render, transfer_function and
energy_window are specified here only: a validator MAY report one that
does not match this section as a warning, and MUST NOT fail an archive
because of it.
render. "isosurface" contours the field at isovalue; "volume" draws
the field itself through a transfer function. A consumer MAY accept other
capitalisations and surrounding whitespace, and treats any value it does not
recognise as "isosurface". A consumer that cannot draw the section as a
volume (it has no volume renderer, does not draw that kind as one, or the
field has no finite samples) ignores render and draws the section as it
otherwise would. In volume mode isovalue is unused. Without a
transfer_function the consumer builds its own default function for the kind,
with colormap as the palette and opacity as the peak of its opacity ramp;
with one, the function’s opacity nodes decide the opacity and opacity is not
applied.
transfer_function. A JSON object, used whenever the section is drawn as a
volume, whether render or the user chose that mode:
Key |
Required |
Shape |
Meaning |
|---|---|---|---|
|
yes |
|
Two finite numbers, |
|
yes |
array of |
Colour nodes, at least one: |
|
yes |
array of |
Opacity nodes, at least one: |
|
no |
string |
Name of the opacity ramp the nodes were derived from, for a consumer’s editor. Names are not standardised; the nodes, not the name, define the function. |
|
no |
string |
|
Between nodes, colour and opacity vary linearly with x; beyond the outermost
node they keep its value, and a node position outside range clamps to the
nearer end. A consumer drops a node that is not an array of the right length,
has a non-finite member, or has a colour or opacity outside 0 to 1, and sorts
the remaining nodes by x. It ignores the whole function, drawing with its
default as if none were given, when range is not two finite numbers with
high > low or when no colour node or no opacity node remains. Other keys are
ignored. A producer that wants its colour nodes drawn as given sets colormap
to "custom".
A spin density that opens as a volume, with a diverging palette and both lobes
visible (spin is the section’s id):
"viewer_defaults": {
"spin": {
"render": "volume",
"transfer_function": {
"range": [-0.02, 0.02],
"color": [[-0.02, 0.23, 0.30, 0.75], [0.0, 0.95, 0.95, 0.95], [0.02, 0.71, 0.02, 0.15]],
"opacity": [[-0.02, 0.5], [-0.002, 0.0], [0.002, 0.0], [0.02, 0.5]],
"colormap": "custom"
}
}
}
energy_window. The energy range a consumer first plots a bands
section or a dos.* section (§ 5.6) over, so that a producer can open an
all-electron spectrum, whose core states lie hundreds of eV below the Fermi
level, on its valence region. The value is [min, max]: two finite numbers,
max > min, in eV relative to the Fermi level (the band energies minus
kpath.fermi, and the DOS energy grid as stored, which is referenced to it).
A consumer MAY also accept the objects {"min": …, "max": …} and
{"emin": …, "emax": …}, which a producer SHOULD NOT write. It ignores
any other value, a non-finite number or a window with max ≤ min, and plots
as if no window were given. A consumer that draws a bands and a dos.*
section on one energy axis may apply the window of either. The user’s own
choice of range overrides it, like any hint.
A periodic archive that opens at a saved view, with its band structure and
DOS on the valence region and two densities half cross-faded (bands,
dos, rho_a and rho_b are section ids):
"viewer_defaults": {
"camera": {"position": [0.0, -12.0, 4.0], "focal_point": [0.0, 0.0, 0.0],
"view_up": [0.0, 0.0, 1.0], "view_angle": 30.0},
"crossfade": {"a": "rho_a", "b": "rho_b", "blend": 0.5},
"bands": {"energy_window": [-15.0, 10.0]},
"dos": {"energy_window": [-15.0, 10.0]}
}
3.5 Root metadata¶
An optional root object ($defs/Metadata) that describes the archive itself,
so that it can be cited, found, and traced: what it is, who made it, under
which licence it may be used, and which identifiers name it and its sources.
The blocks of § 3.2 and § 3.3 describe the calculation; this one describes the
archive. Every field is optional. None of them changes how the rest of the
archive is read, and a consumer MAY ignore the block. The block is
strict: a key not listed below is an error unless it begins with x_,
which a producer may use for its own additions.
"metadata": {
"title": "Water: RHF/STO-3G density and orbitals",
"created_utc": "2026-10-07T12:00:00Z",
"uuid": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"authors": [{"name": "A. Researcher", "orcid": "0000-0002-1825-0097"}],
"license": "CC-BY-4.0",
"keywords": ["water", "electron density"]
}
Field |
Type |
Meaning |
|---|---|---|
|
string |
Short human-readable title. |
|
string |
Free-text description of the contents. |
|
string |
When the archive was first written: an ISO 8601 date and time in UTC, |
|
string |
When the archive was last changed, in the same form. Absent means not changed since |
|
string |
Identifier of this archive: an RFC 4122 UUID in lowercase hexadecimal 8-4-4-4-12 form, with a version digit from 1 to 8 and the RFC 4122 variant (the first digit of the fourth group is |
|
array of author objects |
People or groups responsible for the contents, in citation order. |
|
string |
Licence of the contents. An SPDX identifier or expression (e.g. |
|
string |
DOI under which the archive is published, without a resolver prefix (e.g. |
|
array of strings |
Subject keywords for search and cataloguing. |
|
array of strings |
Archives or publications this archive was derived from, each a |
|
array of strings |
Free labels for a user’s own organisation of archives; unlike |
An author object ($defs/MetadataAuthor, strict like the block):
Field |
Required |
Meaning |
|---|---|---|
|
yes |
Name as it should be cited. |
|
no |
ORCID iD, e.g. |
|
no |
Institution. |
|
no |
Contact address. |
email and affiliation are personal data. Archives are meant to be shared,
so a producer SHOULD NOT emit either by default, but only when the person
concerned asks for it; a tool that sanitises an archive for sharing treats
them like the personal content of a run.record (“Sharing and sanitisation”,
§ 5.8).
Identity and time. A producer SHOULD set created_utc and uuid in
every archive it writes, generating a random (version 4) uuid for each one;
the reference writers do so by default and let the caller turn it off, for
example to keep test vectors reproducible. An archive that its producer updates
in place (§ 2.3), such as a job.spec archive that moves from pending to
converged (§ 3.2), MAY keep its uuid and then SHOULD set
modified_utc. A tool that writes a new archive from an existing one (a
converter, a sanitiser, a subset) SHOULD give the new archive its own
uuid and list the source’s uuid or DOI in derived_from. A validator checks
the form of the two time stamps and of uuid (§ 6), not their truth.
3.6 Root energies¶
An optional root object ($defs/Energies) stating the energies of the
calculation: the energy of the archive’s primary result, a decomposition of
it into components, and the energies of the same system by further methods,
for example the SCF reference and the correlated energy of an MP2
calculation. Every energy is a {value, units} object
($defs/ValueWithUnits), and producers SHOULD write hartree. The object
is strict: it carries only the fields below and vendor keys beginning x_.
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
|
yes |
Energy of the archive’s primary result: the calculation its result sections ( |
|
string |
no |
Method of the primary result, e.g. |
|
object ( |
no |
Named contributions to |
|
array of objects ( |
no |
The energy of the same system by each further method: |
|
string |
no |
Free-text note on the units, for people; it declares nothing. |
components ($defs/EnergyComponents, strict) names each contribution
by one of the keys below; every key is optional and its value is a
{value, units} object. A key beginning x_ names a further,
producer-defined component and is a {value, units} object as well.
Component |
Meaning |
|---|---|
|
Nuclear–nuclear repulsion energy. |
|
Electronic energy: everything but |
|
One-electron energy: kinetic energy plus electron–nuclear attraction. |
|
Two-electron energy: Coulomb plus exchange (Hartree–Fock), or Coulomb plus exchange–correlation (Kohn–Sham). |
|
Exchange–correlation energy of a density functional. |
|
Exchange energy: Hartree–Fock exchange, or the exchange part of |
|
Correlation energy: a correlated energy minus its reference energy, or the correlation part of |
|
Dispersion correction, e.g. DFT-D3. |
|
Contribution of a solvent model. |
|
Zero-point vibrational energy. |
|
Thermal correction to the energy at |
|
Interaction with an embedding environment, e.g. QM/MM or an embedding potential. |
Components may overlap (exchange_correlation contains exchange and
correlation) and need not be exhaustive, so a consumer MUST NOT add
them up to obtain total.
Consistency with the other root blocks. Where the manifest states one energy twice, the two statements MUST agree within 1e-8 hartree:
provenance.scf_energy(§ 3.2) is the energy of the method thatprovenance.methodnames. Every energy thatenergiesstates for that same method — eachby_methodentry whosemethodis that name, andtotalwhenenergies.methodis that name — MUST agree with it. Method names are compared case-insensitively in ASCII, so"RHF"and"rhf"are one method. For a calculation beyond SCF,provenance.methodaccordingly names the SCF method whose energyscf_energyis, andenergies.methodthe method of the final result. An energy ofenergieswhose method is not named, or is another method, is not compared.components.zpveMUST agree withthermochemistry.zpve_eh(§ 3.3).
A validator converts both values to hartree before comparing them
(1 hartree = 27.211386245988 eV = 627.5094740631 kcal/mol =
2625.4996394799 kJ/mol, CODATA 2018), reports a disagreement as
E_ROOT_INCONSISTENT (§ 6), and skips a comparison when it does not
recognise a unit. The unit strings it recognises, case-insensitively, are
hartree (and its older spellings Eh and Ha), ev, kcal_per_mol and
kj_per_mol.
An MP2 calculation on an RHF reference:
"provenance": {"method": "rhf", "scf_energy": {"value": -74.9629, "units": "hartree"}},
"energies": {
"total": {"value": -75.0124, "units": "hartree"},
"method": "mp2",
"components": {"correlation": {"value": -0.0495, "units": "hartree"}},
"by_method": [
{"method": "rhf", "total": {"value": -74.9629, "units": "hartree"}},
{"method": "mp2", "total": {"value": -75.0124, "units": "hartree"}}
]
}
The rhf entry restates provenance.scf_energy and must agree with it. The
MP2 total and the mp2 entry are not compared with it, because their
method is not the one provenance.method names.
4. Sections and members¶
4.1 Section object¶
{
"id": "vol_dens_0",
"kind": "volume.density",
"label": "Electron density",
"members": { /* role -> member spec */ }
}
Field |
Required |
Meaning |
|---|---|---|
|
yes |
Unique within the archive. |
|
yes |
Canonical kind (§ 5) or |
|
yes |
Map from member role to a JSON or binary member spec. |
|
no |
Human-readable display label. |
|
no |
Component hint (e.g. for |
|
no |
If |
|
no |
URI of a JSON Schema for a vendor section’s members. |
|
no |
Id of the |
|
no |
Id of the |
|
no |
Free-text label that groups related sections for display, e.g. |
Some kinds add kind-specific peer fields on the section object (e.g.
volume.difference carries operand_a/operand_b; reaction.waypoints
carries trajectory_ref). These are documented per kind in § 5.
Section references and grouping. Any section, of any kind including a
vendor kind, MAY carry structure_ref, run_ref, and group. They make
an archive that holds several structures or several steps of a calculation
unambiguous: a consumer learns which geometry a volume, wavefunction, or
spectrum belongs to and which program run produced it, instead of guessing
from section order or ids. structure_ref MUST name a section of kind
structure, and run_ref a section of kind run.record, in the same archive;
a validator reports one that does not (§ 6). A section without them makes no
statement, and a consumer keeps its usual behaviour, for example using the
archive’s only structure, or the first structure of an archive with several
(below). group carries no meaning beyond grouping:
sections with equal group values belong together, and a consumer MAY
present them together, for instance as one node of a tree.
Section ids carry no meaning. An id names a section so that other
sections and viewer_defaults can refer to it; nothing else may be read
into it. structure is a conventional id that the reference writers use by
default, not a role: an archive may hold structures with any ids, such as
structure_m1 and structure_m2 for the species of a scheme, and none named
structure. A consumer MUST find sections by their kind and by the
references of § 4.1 and § 5, and MUST NOT depend on a conventional id.
The first structure. A consumer that shows one structure at a time, or
needs one structure for an operation that names none, uses the first
structure: the first structure section that viewer_defaults.auto_open
lists (§ 3.4), else the first section of kind structure in sections
order. It SHOULD also offer the archive’s other structures, for example
by showing a structure when its section is selected. A producer that wants a
particular structure shown first lists it in auto_open. The rule chooses
what to show and changes no reference: a section without structure_ref in
an archive with several structures still makes no statement about which one
it describes. A standalone bonds section is the one exception: its atom
indices need a structure, and without structure_ref they address the first
structure (§ 5.1).
The kind-specific references stay as they are: operand_a and operand_b of
volume.difference (§ 5.2), trajectory_ref of reaction.waypoints (§ 5.5),
and the structure_ref inside the basis payload of wavefunction.gto
(§ 5.3) and wavefunction.bloch (§ 5.3.1). When a section carries a structure_ref and one of its payloads
carries one too, the section’s takes precedence: a consumer reads the
payload’s atom indices, such as the shell center indices of a basis,
against the atoms of the structure that the section names. Producers
SHOULD keep the two equal.
4.2 Member specs¶
JSON member:
{ "path": "structure/structure.json", "format": "json", "sha256": "<64 hex>",
"size": 1834 }
Binary member:
{
"path": "volumes/density.dat",
"format": "binary",
"dtype": "float32",
"shape": [80, 80, 80],
"sha256": "<64 hex>",
"size": 2048000
}
formatis"json"or"binary".sha256is the lowercase hex sha256 of the exact bytes stored for that member (the uncompressed payload). Consumers MUST verify it before use.size(optional, on every member spec: JSON, binary and opaque) is the uncompressed byte count of the stored member, an integer ≥ 0. It MUST equal the uncompressed size that the ZIP central directory records for the member’s entry, so for a binary member with adtypeit isitemsize(dtype) × ∏(shape). Producers SHOULD write it; the reference writers write it for every member. A validator checks it against the central directory before reading the member, and reports a disagreement asE_BINARY_SIZE(§ 6). A consumer that relies onsize— to allocate a buffer before inflating, or to size-gate rendering (§ 5.8) — MUST first check that it equals the size the central directory records, and treat a member whosesizedisagrees as invalid. Archives written beforesizeexisted omit it and remain valid.JSON members MUST parse as UTF-8 JSON.
Binary members are raw, C-contiguous, little-endian arrays.
dtypeis one of:int8,int16,int32,int64,uint8,uint16,uint32,uint64,float32,float64. The stored byte length MUST equalitemsize(dtype) × ∏(shape).A small set of opaque binary members carry no
dtype/shape:citations.references(UTF-8 BibTeX bytes), therun.recordmembersinput/log(UTF-8 text) andattachment.*(arbitrary bytes, § 5.8), thepreviewmembersthumbnailandimage(§ 5.15), and any member of a vendor section (§ 7.3) that its producer writes without them. Consumers skip the byte-length check for these and decode per the owning kind’s contract.media_type(optional, on every member spec) is the IANA media type of the member’s bytes, such asimage/png,text/plainorapplication/json: a type and a subtype, without parameters (RFC 6838). It describes the bytes and changes nothing in how they are read: a JSON member is UTF-8 JSON and a binary member with adtypeis a little-endian array whatever itsmedia_typesays. A kind may require it, aspreviewdoes (§ 5.15); elsewhere it is a hint for programs that hand a member to another program, most usefully on opaque members.
4.3 Units and numeric conventions¶
Producers convert to these units at write time. Consumers MUST treat on-disk units as the contract (they may convert for display).
Field |
Unit / convention |
|---|---|
|
Ångström |
|
Ångström, row vectors |
|
Ångström, row vectors (the structure convention); see Lattice conventions below |
|
bohr, column matrix (columns = a, b, c); see Lattice conventions below |
|
bohr |
|
bohr per grid step |
|
e / bohr³ (electron density) |
|
orbital amplitude on a bohr grid |
|
hartree / e (atomic units of potential) |
|
dimensionless, s(r) = |∇ρ| / (2(3π²)^⅓ ρ^⅔) |
|
e / bohr³ (the transition density of one excitation, § 5.2) |
|
e / bohr⁵ (∇²ρ); the vocabulary has no unit name for it, so |
|
the unit of the sampled field, declared as |
|
|
periodic |
|
|
Ångström |
|
Hartree |
|
Å / fs |
|
hartree / bohr; the energy gradient, so the forces are its negative (§ 5.5) |
|
fs |
|
ų |
|
kelvin |
|
eV |
|
cm⁻¹ / km·mol⁻¹ |
|
eV |
|
cm⁻¹ |
|
bohr⁻² |
|
Hartree |
|
|
|
dimensionless; AOs as Appendix A.1 defines them |
|
electrons: tr(P · S) is the electron count (§ 5.3) |
|
hartree (§ 5.3.1) |
|
fractional reciprocal-lattice coordinates, k = k₁b₁ + k₂b₂ + k₃b₃ with a_i · b_j = 2π δ_ij (§ 5.3.1) |
|
eV (referenced to E_F at 0.0) |
|
eV (signed: E(k) − E_F) |
|
Ångström, row vectors / Å⁻¹, row vectors, 2π included |
|
cm⁻¹ |
|
ų / eV |
|
ų / eV / GPa |
|
hartree / bohr; the energy gradient ∂E/∂R, so the forces are its negative (§ 5.10) |
|
hartree / bohr³ |
|
hartree / bohr²; hartree / (bohr² · amu) when |
|
|
|
dimensionless |
|
10⁻⁴⁰ esu²·cm² (the “10⁻⁴⁰ cgs” unit), signed |
|
atomic units: e·bohr / e·ħ/mₑ (= 2 μ_B) |
root |
|
|
debye (§ 5.13) |
|
debye · Å / debye · Ų; |
|
atomic units, e² a₀² / E_h and e³ a₀³ / E_h² (§ 5.13) |
|
GPa; |
|
dimensionless (relative permittivity) (§ 5.13) |
|
e / C · m⁻² (§ 5.13) |
When adding fields, prefer unit-bearing names (energy_eh, energy_ev,
frequency_cm) or a {value, units} object.
Unit names¶
A unit is named by one of the unit names below, a controlled vocabulary.
The JSON Schema carries the same list in the same order as $defs/UnitName,
and the two are kept identical. Names are case-sensitive. The list names
units; it changes none: every unit of the table above keeps its meaning.
Unit name |
Quantity |
Definition or note |
|---|---|---|
|
length |
1 Å = 10⁻¹⁰ m |
|
length |
a₀ = 0.529177210903 Å (CODATA 2018) |
|
energy |
E_h = 27.211386245988 eV (CODATA 2018) |
|
energy |
1 eV = 1.602176634 × 10⁻¹⁹ J (exact) |
|
molar energy |
thermochemical kcal·mol⁻¹, 4.184 kJ·mol⁻¹ (exact); E_h N_A = 627.5094740631 kcal·mol⁻¹ |
|
molar energy |
kJ·mol⁻¹; E_h N_A = 2625.4996394799 kJ·mol⁻¹ (CODATA 2018) |
|
wavenumber |
1 cm⁻¹ = 100 m⁻¹; as an energy E = h c ν̃, with E_h / (h c) = 219474.6313632 cm⁻¹ (CODATA 2018) |
|
length (wavelength) |
1 nm = 10⁻⁹ m; as a photon energy E = h c / λ, with h c = 1239.841984332 eV·nm (exact) |
|
electric dipole moment |
1 D = 10⁻²¹ / c C·m ≈ 3.335641 × 10⁻³⁰ C·m |
|
frequency |
1 MHz = 10⁶ s⁻¹ |
|
frequency |
1 Hz = 1 s⁻¹ |
|
dimensionless ratio |
10⁻⁶; chemical shifts and shieldings |
|
IR intensity |
km·mol⁻¹, the integrated molar absorption coefficient |
|
volume |
1 ų = 10⁻³⁰ m³ |
|
volume |
a₀³ |
|
pressure |
1 GPa = 10⁹ Pa |
|
time |
1 fs = 10⁻¹⁵ s |
|
time |
1 ps = 10⁻¹² s |
|
temperature |
the SI kelvin |
|
pressure |
standard atmosphere, 101 325 Pa (exact) |
|
electric charge |
elementary charge, 1.602176634 × 10⁻¹⁹ C (exact) |
|
mass |
unified atomic mass unit (dalton), 1.66053906660 × 10⁻²⁷ kg (CODATA 2018) |
|
plane angle |
the SI radian |
|
plane angle |
π / 180 rad |
|
— |
a pure number, such as a normalized intensity |
Legacy spellings. Archives written before this vocabulary carry three
other spellings in the units of a {value, units} object (scf_energy,
fermi_energy, § 3.2). They remain valid there, and only there, and are
deprecated: producers SHOULD write the unit name, and consumers
MUST read a legacy spelling as the unit name it stands for. The schema
lists them as $defs/LegacyUnitName.
Legacy spelling |
Unit name |
|---|---|
|
|
|
|
|
|
Declared units¶
A payload can say which unit its values are in. The units object of the
volume grid (§ 5.2), of the trajectory, reaction-path and scan metadata
(§ 5.5), of the kpath, DOS meta, Fermi-surface mesh, qpath and phonon
meta payloads (§ 5.6), of the QTAIM payload (§ 5.7) and the meta.units
object of the excited_states payload (§ 5.12) maps a key to a unit name.
The key is the name of a field of the payload (for excited_states, of a
state), or the role of a binary member of the same section, such as coords
or eigenvalues. A
one-dimensional spectrum declares the units of its axes in x_units and
y_units, and the unit of its line width in broadening.units (§ 5.4). The
axis of a volume.series declares the unit of its values in units, a
single unit name (§ 5.2).
Producers MAY declare units. A declaration is not a conversion: the values are stored in the declared unit.
Consumers MUST honour a declared unit: they read the values in it, and convert from it when they need another.
Where the table above fixes the unit of a field or member, a declaration only restates it, and a declared unit that contradicts it is an error: a grid
units.originother thanbohr, a trajectoryunits.coordsother thanangstrom, or a trajectoryunits.latticeother thanangstrom(a reaction path’s isbohr). The payload definitions encode these fixed units, so a validator that runs the JSON Schema check reports the contradiction asE_PAYLOAD_SCHEMA(§ 6).Where a payload leaves the unit open (a spectrum’s x axis, QTAIM positions, the scan axes), a declaration chooses it, within the quantity the field holds: a position takes a length.
A declared unit is a unit name. So is the
unitsof a{value, units}object, except that it may also be a legacy spelling. A validator reports any other string in these places as the warningW_UNIT_UNKNOWN(§ 6). The schema types these strings as well, so a validator that runs the JSON Schema check also reportsE_SCHEMAorE_PAYLOAD_SCHEMAfor an unknown unit, and the archive does not validate there.
The older unit-bearing keys (unit of a scan axis, reaction_coordinate_unit,
energy_unit, coordinate_a_unit and the like) stay free text in v1, because
archives already carry spellings outside the vocabulary, such as "rad".
Producers SHOULD use unit names in them as well. When a scan’s
units.energies and energy_unit, or a units entry and an axis unit,
are both present they MUST name the same unit.
Lattice conventions¶
QVF v1 carries the same physical object, a periodic cell, in three members
that follow two conventions, which differ in layout and in unit.
structure.lattice_vectors and trajectory.lattice use the structure
convention (rows, Å); reaction.path.lattice uses the reaction-path
convention (columns, bohr). Both conventions are normative and frozen for the
whole of v1; neither will change within it. This subsection is the one place
that states both, and the member descriptions in § 5.1 and § 5.5 refer to it.
|
|
|
|
|---|---|---|---|
Convention |
structure |
structure |
reaction path |
Where |
JSON payload of a |
binary member |
binary member |
Shape |
|
|
|
Layout |
rows: row |
rows: row |
columns: column |
Unit |
Ångström |
Ångström |
bohr |
Storage |
JSON numbers |
float64, little-endian, C order (element |
float64, little-endian, C order (element |
Periodicity is signalled by |
|
|
presence of the member |
A [3, 3] slice of trajectory.lattice is laid out and scaled exactly as
structure.lattice_vectors: the frame-0 cell of a trajectory equals the
lattice_vectors of its structure, element for element, with no conversion.
The two conventions differ deliberately: reaction.path.lattice predates the
structure-convention carriers and stays columns in bohr for the whole of v1,
and trajectory.lattice, added later, adopts the structure convention so that
new carriers converge on one layout.
Write R for a matrix in the structure convention (structure.lattice_vectors
or one [3, 3] slice of trajectory.lattice; Å, rows) and L for one
[3, 3] slice of reaction.path.lattice (bohr, columns), and
f = 1.8897261246 bohr per Å (the reciprocal of 1 bohr = 0.529177210903 Å,
CODATA 2018, rounded to ten decimals). Then
L[i][j] = f · R[j][i] i.e. L = f · Rᵀ (structure → reaction.path)
R[i][j] = L[j][i] / f i.e. R = Lᵀ / f (reaction.path → structure)
so the columns of L are the rows of R scaled by f. For a per-frame
[n_frames, 3, 3] member, apply the conversion to each frame’s slice.
Worked example. A hexagonal cell with a = 2.46 Å and a 15.875 Å normal (the
2-D graphene slab of the conformance corpus). As structure.lattice_vectors
(Å, rows):
[[2.46, 0.0, 0.0 ], // a
[1.23, 2.1304, 0.0 ], // b
[0.0, 0.0, 15.875]] // c
and as the equivalent reaction.path.lattice (bohr, columns, 4 decimals):
[[ 4.6487, 2.3244, 0.0000 ], column 0 = a = (4.6487, 0.0000, 0.0000)
[ 0.0000, 4.0259, 0.0000 ], column 1 = b = (2.3244, 4.0259, 0.0000)
[ 0.0000, 0.0000, 29.9994 ]] column 2 = c = (0.0000, 0.0000, 29.9994)
The second matrix is the transpose of the first times f: row a of the Å
matrix, (2.46, 0, 0), becomes column 0 of the bohr matrix, (4.6487, 0, 0)ᵀ,
and row b, (1.23, 2.1304, 0), becomes column 1, (2.3244, 4.0259, 0)ᵀ.
Reading the bohr matrix by rows would give a = (4.6487, 2.3244, 0) and
b = (0, 4.0259, 0), which is a different cell. For an axis-aligned cubic or
orthorhombic cell the matrix is diagonal and the transpose is invisible,
leaving only the unit factor, so a diagonal test case does not show that the
two conventions agree.
A consumer MUST NOT assume the convention of one member for another: it
MUST read structure.lattice_vectors and trajectory.lattice as rows in Å
and reaction.path.lattice as columns in bohr, and convert explicitly when it
combines a reaction path with either of the others (for example to overlay a
path on the cell of its structure). A producer that writes several MUST
write each in its own convention. A validator reads each member in its own
convention and never mixes them: it checks the shape of each lattice against
the frames of its own section (§ 6), and never compares one carrier with
another.
Note (informative). New carriers of a cell adopt the structure convention.
Unifying reaction.path.lattice with it is a v2 ledger item (V2-05).
5. Canonical section kinds¶
Every kind below is a oneOf branch in the schema. A section’s kind selects
its required member set. The table lists each kind and its required members;
subsections give the payload shapes that matter for interoperability.
Kind |
Required members (roles) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
≥1 of the scalar roles |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
≥1 of |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
any mix of valid JSON/binary members |
Payload definitions. A JSON member whose section kind and role have a
payload definition, the $defs entry of the JSON Schema named in the table
above and in the subsections below, MUST conform to it, and a validator
checks that it does (§ 6). A payload definition describes an archive member,
not manifest content, so nothing in the manifest refers to it. Each payload
table below names the strictness level of its definition:
strict — the payload carries only the keys its table lists. Any other key is an error, except a key that begins with
x_: a producer may use such keys for its own additions, and a consumer that does not understand one ignores it.typed-open — the keys its table lists are typed, and any other key is accepted; a consumer that does not understand one ignores it.
5.1 structure and bonds¶
structure.json — schema’d as $defs/StructurePayload:
{
"atoms": [
{"symbol": "O", "position": [0.0, 0.0, 0.1173], "atomic_number": 8},
{"symbol": "H", "position": [0.0, 0.7572, -0.4692], "atomic_number": 1}
],
"pbc": [false, false, false],
"lattice_vectors": null
}
Each atom carries symbol, position (Cartesian Å, never fractional), and
atomic_number; producers may add further per-atom fields.
Periodicity¶
pbc is an array of three booleans and is the normative carrier of
periodicity: axis i is periodic iff pbc[i]. It is REQUIRED whenever
lattice_vectors is a non-null array. When absent the structure is a molecule,
exactly as if [false, false, false] had been written.
All eight patterns are legal. The periodic axes need NOT be the leading
ones: a slab whose surface normal lies along y is [true, false, true], and a
producer MUST NOT be required to permute its lattice to satisfy a consumer.
lattice_vectors is a [3,3] array of row vectors in Å — row i is the
lattice vector of axis i, paired with pbc[i]. It is REQUIRED (non-null)
when any pbc[i] is true, and SHOULD be null or absent otherwise.
trajectory.lattice (§ 5.5) uses the same layout and unit; the other lattice
carrier in v1, reaction.path.lattice, uses a different layout and unit; see
Lattice conventions in § 4.3.
For every axis i where pbc[i] is false, row i is non-physical
bookkeeping. Producers keep the matrix full-rank 3×3 so that integral codes
and symmetry finders always see a 3-D lattice, but such a row spans no
periodicity and encodes no geometry. A consumer MUST NOT draw it as a cell
edge, replicate the structure along it, or read it as a vacuum extent. This is
not a hypothetical: a synthesized 30-bohr normal and a real 30-bohr vacuum gap
are numerically identical in lattice_vectors, so pbc is the only signal
that tells them apart. Any heuristic of the form “is this row long and
orthogonal? then it is vacuum” silently renders 2-D slabs inside empty boxes.
dimensionality (0–3) is OPTIONAL and derived, with the invariant
dimensionality == the number of true entries in pbc
A producer that emits it MUST satisfy that invariant; a validator MUST
reject a payload that violates it. It is a convenience scalar and carries no
axis identity: a consumer MUST take per-axis periodicity from pbc, and
MUST NOT infer which axes are periodic from dimensionality.
dimensionality lives in the payload, alongside the pbc it is derived
from — not on the section object. An earlier revision of this section placed it
on the section object; a consumer MUST NOT read it from there. Archives that
carry it in the old position remain fully interpretable, because pbc is what a
consumer reads.
Note (informative). Some producers — vibe-qc among them — order their lattice so the periodic axes come first, emitting
pbcas[true] * dim + [false] * (3 - dim). A consumer reading a pre-conformance archive that hasdimensionalitybut nopbcmay assume that ordering as a fallback. This is a legacy accommodation, not part of the contract, and it is unnecessary for any archive conforming to this section, wherepbcis always present when it matters.
Connectivity¶
Explicit connectivity is a separate bonds section
({"pairs": [{"i": 0, "j": 1, "order": 1.0}, …]}), or the optional bonds
member of the structure section itself. If neither is present, a viewer may
infer bonds from covalent radii. The payload, of a bonds section and of a
structure section’s optional bonds member alike, is $defs/BondsPayload
(§ 5.7).
The atom indices of a bonds member of a structure section address that
structure’s atoms. A standalone bonds section names its structure with the
generic section field structure_ref (§ 4.1):
Present: the bonds belong to the
structuresection it names, and their indices address its atoms. A validator reports astructure_refthat does not name astructuresection (E_REF_UNRESOLVED), and an atom indexiorjthat is not below the atom count of that structure (E_MEMBER_MALFORMED, § 6).Absent: the bonds belong to the archive’s first structure (§ 4.1), in an archive with one structure that structure, as before this field was specified.
A producer that writes several structure sections SHOULD set
structure_ref on every standalone bonds section, or, simpler, write each
structure’s bonds as that section’s own bonds member.
{"id": "bonds_product", "kind": "bonds", "structure_ref": "structure_product",
"members": {"bonds": {"path": "bonds_product/connectivity.json", "format": "json",
"sha256": "…"}}}
Biomolecule metadata¶
The structure section object (peer to id/kind/members, not inside
the payload) MAY carry optional biomolecule metadata for cartoon/ribbon
rendering. All four fields are OPTIONAL and independent; a structure
carrying none of them is a valid plain structure, and a consumer that does not
understand them MUST ignore them.
Field |
Type |
Schema |
|---|---|---|
|
array of chain-id strings, in presentation order |
— |
|
array of |
|
|
array of |
|
|
array of number, one per atom, parallel to the payload’s |
— |
atom_indices are 0-based into the structure member payload’s atoms
array. residues are listed in chain order — the order a ribbon is drawn
in — not sorted by seq: insertion codes and non-monotonic numbering are both
legal, and sorting would silently reorder them. seq is not a global key:
PDB residue numbers are four columns wide and wrap at 9999, so a solvated
system reuses them.
Precedence. Many consumers can derive residues, chains, and secondary structure themselves — from the per-atom fields below, and from CA geometry. Where a producer supplies these fields, a consumer MUST prefer the supplied values over its own inference. A producer knows what geometry cannot reveal: an α- from a π- from a 3-10 helix, a β-bridge from a sheet.
A payload’s atoms MAY additionally carry the per-atom biomolecular fields
atom_name (PDB cols 13-16, e.g. "CA"), residue_name (cols 18-20),
residue_seq (cols 23-26), chain_id (col 22) and b_factor (cols 61-66).
Where both carriers are present, the per-atom b_factor wins over the
section-level b_factors array: it cannot desynchronize from its own atom. A
consumer MUST ignore a b_factors array whose length differs from the atom
count rather than applying a partial mapping.
These fields were added under v1: an optional member is the additive case
and does not bump qvf_version (see GOVERNANCE.md).
Chemical identity¶
The structure section object MAY also say which chemical species the
structure is: its net charge and spin multiplicity, a name, and line notations.
Like the biomolecule metadata they are peers of id and members, so a
consumer reads them from the manifest without opening a member, and a program
that lists the molecules of an archive, or searches archives for one, needs
nothing else. All are OPTIONAL and independent.
Field |
Type |
Meaning |
|---|---|---|
|
integer |
Net charge of the species, in units of the elementary charge. |
|
integer ≥ 1 |
Spin multiplicity 2S+1 of the species. |
|
string, non-empty |
Name of the species, e.g. |
|
string, no whitespace |
SMILES of the species. |
|
string beginning |
InChI of the species, standard ( |
|
string, |
InChIKey of the species: 14 and 10 uppercase letters and one more, joined by hyphens. |
The generic section field label (§ 4.1) is the short label a scheme or a
viewer shows for the species, such as its compound number ("1", "3a");
name is its chemical name.
The fields describe the species whose atoms the structure payload holds:
all of them, hydrogens included, with the stated charge. The line notations
name the species as a whole and imply no atom order, so a consumer
MUST NOT map a SMILES atom to a payload atom by position. A producer
writes only identifiers that it derived from these atoms or knows to describe
them; when it writes several they name the same species. The validators
cannot compare a SMILES or an InChI with the atoms and do not try.
A field that is absent states nothing: in particular a structure without
charge is not declared neutral. A consumer that needs the charge or the
multiplicity of such a structure takes it from provenance (§ 3.2) when the
archive has exactly one structure section, and otherwise from its own
default. The charge and multiplicity of a calculation are those of its
job.spec (§ 5.9), which is authoritative for the job and may differ on
purpose, for a vertical ionization for example.
Two rules relate the fields to the rest of the archive, and a validator checks both (§ 6):
Electron count. When
chargeis present the species has N = Σ Z −chargeelectrons, Σ Z being the sum of the payload’satomic_numbervalues: N MUST NOT be negative, and whenmultiplicityis present too, the unpaired electrons,multiplicity− 1, MUST NOT exceed N and MUST have the parity of N. A violation isE_CHARGE_MULTIPLICITY.Agreement with
provenance. In an archive with exactly onestructuresection, itschargeandmultiplicityMUST equalprovenance.chargeandprovenance.multiplicitywhere both are present: there they state the same thing twice. A disagreement isE_ROOT_INCONSISTENT.
A methane molecule labelled as compound 2 of a scheme:
{
"id": "structure_methane", "kind": "structure", "label": "2",
"name": "methane", "charge": 0, "multiplicity": 1,
"smiles": "C", "inchi": "InChI=1S/CH4/h1H4",
"inchikey": "VNWKTOKETHGBQD-UHFFFAOYSA-N",
"members": {"structure": {"path": "structure_methane/structure.json",
"format": "json", "sha256": "…"}}
}
These fields were added under v1, like the biomolecule metadata. An
archive that holds several molecules, such as the species of a reaction
scheme (§ 5.14), gives each its own structure section and identity, and
every reader then knows which molecule is which and what its charge and spin
are.
5.2 volume.*¶
A volume section samples a field on a regular grid. Every volume kind has a
JSON grid member (the payload below) and a binary data member, float32 by
default and float64 by opt-in. The kind fixes what data holds and its shape;
the grid always describes the three spatial axes of data.
Kind |
|
Holds |
Unit of |
|---|---|---|---|
|
|
electron density |
e / bohr³ |
|
|
orbital amplitude |
amplitude on a bohr grid |
|
|
spin density |
— |
|
|
electron localization function |
— |
|
|
difference of two fields (below) |
that of the operands |
|
|
electrostatic potential |
hartree / e |
|
|
reduced density gradient |
dimensionless |
|
|
any other scalar field, named by the section |
— |
|
|
Laplacian of the electron density, ∇²ρ |
e / bohr⁵ |
|
|
a Cartesian vector field (below) |
— |
|
|
a complex scalar field (below) |
— |
|
|
|
— |
The units are those of § 4.3. A dash means that § 4.3 fixes none: the unit is
that of the field, and a producer declares it as grid.units.data when the
vocabulary of § 4.3 names it.
The grid shape is the [nx, ny, nz] of this table: the shape of a 3-D
data member, the leading three extents of a volume.vector or
volume.complex member, and the trailing three of a volume.series member.
The grid payload¶
// the CHGCAR-style grid of the conformance archive volume_periodic.qvf
// (a hexagonal cell; voxel vectors shown to 4 decimals)
{
"origin": [0.0, 0.0, 0.0],
"voxel_vectors": [[0.7748, 0.0, 0.0], [-0.3874, 0.6710, 0.0], [0.0, 0.0, 0.7913]],
"shape": [6, 6, 8],
"periodic": [true, true, true],
"includes_endpoint": false,
"structure_ref": "structure"
}
The grid payload is schema’d as $defs/VolumeGridPayload (strict). The same
definition governs the grid member of basis.ao (§ 5.7) and the
volume_grid member of reaction.path (§ 5.5).
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
3 numbers |
yes |
Cartesian position of grid point |
bohr |
|
3 × 3 numbers |
yes |
The step vectors |
bohr per step |
|
3 integers ≥ 1 |
yes |
Number of points |
— |
|
object |
no |
Declared units (§ 4.3, Declared units), keyed by a field of this payload or a member role of the section; |
— |
|
3 booleans |
no |
|
— |
|
boolean |
no |
Whether the points along a periodic axis include the endpoint of the period (below). Absent means |
— |
|
string |
no |
|
— |
Point positions. For data index (i, j, k), with 0 ≤ i < shape[0],
0 ≤ j < shape[1] and 0 ≤ k < shape[2], the point position is
r(i, j, k) = origin + i·v_0 + j·v_1 + k·v_2
This is point-centred data: the grid has exactly shape points, at these
positions, whatever the other fields say. For the 4-D kinds the extra axis is
not a spatial axis: the point of data[i][j][k][c] (vector, complex) and of
data[s][i][j][k] (series) is r(i, j, k).
Periodic grids. The grid’s structure is the structure section the
section-level structure_ref names, else the one the grid’s structure_ref
names; when neither is given, it is the archive’s structure section if the
archive has exactly one. Along an axis a with periodic[a] true, the field
is periodic with the lattice vector L_a of that structure, which is row a
of its lattice_vectors converted to bohr (L_a = f · R[a], § 4.3, Lattice
conventions), and the grid samples exactly one period. includes_endpoint
says how:
includes_endpoint: true(the default; the convention of cube files): the points span the closed period. The last plane is the image of the first, soshape[a] − 1steps span one period:v_a · (shape[a] − 1) = L_a, and planeshape[a] − 1repeats plane0. The grid holdsshape[a] − 1distinct planes per period.includes_endpoint: false(the convention of VASP CHGCAR files): the points span the period exclusive of its endpoint, soshape[a]steps span one period:v_a · shape[a] = L_a. Indexshape[a]would be plane0of the next cell; every plane is distinct.
A consumer that tiles a periodic grid along axis a (replicates it to draw a
supercell), or that wraps an index or interpolates across the cell boundary,
MUST drop the duplicated plane when includes_endpoint is true: the period
in index space is shape[a] − 1, and plane shape[a] − 1 is not repeated
before plane 0 of the next cell. When includes_endpoint is false the period
is shape[a] and no plane is dropped. A producer MUST write the
includes_endpoint value that matches its points, and SHOULD write
structure_ref when the archive has more than one structure.
Worked example. One axis of a cell with L = 4.0 bohr, sampled by four
points in each convention:
includes_endpoint: false (CHGCAR style) v = L / 4 = 1.0 bohr
index 0 1 2 3 | 4 = index 0 of the next cell
position 0.0 1.0 2.0 3.0 | 4.0
distinct planes per period: 4
tiled: f0 f1 f2 f3 | f0 f1 f2 f3 | f0 …
includes_endpoint: true (cube style) v = L / 3 = 1.3333 bohr
index 0 1 2 3
position 0.0 1.3333 2.6667 4.0 index 3 is index 0 shifted by L
distinct planes per period: 3
tiled: f0 f1 f2 | f0 f1 f2 | f0 … plane 3 dropped
A consumer that tiles the cube-style grid without dropping plane 3 draws
f0 f1 f2 f3 f0 … with f3 = f0: a doubled plane at every cell boundary,
and a period of four steps where the cell has three, so the field drifts by
one step per cell. A consumer that drops the last plane of the CHGCAR-style
grid loses a quarter of the period. Producers of both conventions exist, and
the numbers alone do not say which one an archive holds; includes_endpoint
does. The conformance archive volume_periodic.qvf holds one periodic
density in both conventions.
A validator checks, for every grid payload whose periodic[a] is true and
whose structure resolves, that the structure’s pbc[a] is true and that
v_a · (shape[a] − 1) (when includes_endpoint is true) or v_a · shape[a]
(when it is false) equals L_a within a relative tolerance of 10⁻⁶,
|span − L_a| ≤ 10⁻⁶ |L_a|, comparing the vectors component by component
rather than their lengths (§ 6). An axis that periodic does not mark is not
checked, so a grid may sample a box that is finite along an axis the structure
is periodic in, such as the vacuum direction of a slab. A grid structure_ref
that names no structure section is an unresolved reference.
volume.difference may add operand_a and operand_b (section ids); if one is
present both MUST be. Sign convention: data = operand_a − operand_b.
volume.transition_density holds the transition density of one electronic
excitation, ρ₀ₙ(r): the one-particle transition density between the
reference state 0 and the excited state n, summed over spin, in e / bohr³.
It integrates to zero, and its first moment ∫ r ρ₀ₙ(r) d³r is the
transition dipole up to its sign. Its overall sign is arbitrary, as is the
phase of the excited state. The density of the excited state minus that of
the reference state is a difference density and is written as
volume.difference. Two optional section fields (peers of members) name the
state:
Field |
Type |
Meaning |
|---|---|---|
|
string |
|
|
integer ≥ 1 |
The |
A validator checks that excited_states_ref names an excited_states section
and that state_index is the index of one of its states (§ 6).
volume.laplacian¶
data[i][j][k] is ∇²ρ at r(i, j, k) in e / bohr⁵: negative where the
density concentrates charge and positive where it depletes it, the map
QTAIM reads valence-shell charge concentrations from. The vocabulary of § 4.3
has no unit name for e / bohr⁵, so a producer does not declare
grid.units.data for it (§ 9).
volume.vector and volume.complex¶
A volume.vector section holds a Cartesian vector at every grid point, such
as the gradient of a density, an electric field or a current density:
data[i][j][k][c] is component c (0 = x, 1 = y, 2 = z) of the vector
at r(i, j, k), in the Cartesian frame of origin. The member is
$defs/Volume4DVectorBinary, whose trailing extent is 3. Its unit is that of
the field; a producer declares it as grid.units.data when the vocabulary
of § 4.3 names it. The section field component is not used.
A volume.complex section holds a complex scalar field, such as a complex
molecular orbital or a Bloch function at one k-point:
data[i][j][k][0] is the real part and data[i][j][k][1] the imaginary part
at r(i, j, k), the [re, im] layout of complex phonon eigenvectors (§ 5.6).
The member is $defs/Volume4DComplexBinary, whose trailing extent is 2.
volume.series¶
A volume.series section holds n scalar fields on one grid, such as the
density along a trajectory, a time-dependent density or the densities of
several electronic states: data[s], the slab s, is the field at
the axis value axis.values[s]. The members are grid, data
($defs/Volume4DBinary, [n, nx, ny, nz]) and axis, a JSON member that says
what indexes the slabs.
Payload axis ($defs/VolumeSeriesAxisPayload, strict):
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
|
yes |
What indexes the slabs: a time; a frame of the trajectory or reaction path that |
— |
|
array of numbers |
yes |
The axis value of each slab, in slab order: |
|
|
unit name |
no |
Unit of |
— |
|
array of strings |
no |
Display label of each slab, |
— |
|
string |
no |
|
— |
A validator checks that data has rank 4, that values and, when present,
labels have one entry per slab (n, the leading extent of data), and
that trajectory_ref names a trajectory or reaction.path section (§ 6).
volume.series is the general form of the per-frame volumes that a
reaction.path carries as frame_volumes and volume_grid (§ 5.5); a
producer SHOULD write new per-frame volumes as a volume.series.
5.3 wavefunction.gto¶
Carries an atom-centered Gaussian basis and MO coefficient matrices for
molecular wavefunctions and the Γ-point (k = 0) crystalline orbitals of
periodic systems. Crystalline orbitals at other k-points, or at several, are
carried by wavefunction.bloch (§ 5.3.1), which shares the basis payload
defined here. See Appendix A for the AO-ordering and
primitive-normalization contract — this is the single most error-prone part of
implementing a producer, and getting it wrong silently corrupts every rendered
orbital. A producer that also writes the AO overlap member makes the contract
checkable: validators compare its diagonal with Appendix A.1.
{
"kind": "wavefunction.gto",
"members": {
"basis": {"path": "wavefunction/basis.json", "format": "json", "sha256": "…"},
"mo_metadata": {"path": "wavefunction/mo_metadata.json", "format": "json", "sha256": "…"},
"mo_coefficients": {
"path": "wavefunction/mo_coefficients.dat", "format": "binary",
"dtype": "float64", "shape": [41, 41], "sha256": "…"
}
}
}
mo_coefficients shape is [n_mo, n_ao] (rows are MOs). Unrestricted
wavefunctions replace it with mo_coefficients_alpha + mo_coefficients_beta.
Complex coefficients add a trailing axis of length 2, and a two-component
wavefunction doubles the AO axis (Spin and complex coefficients below).
Role |
Format |
Required |
Meaning |
|---|---|---|---|
|
JSON, |
yes |
The basis set (below). |
|
JSON, |
yes |
Orbital energies, occupations and labels (below). |
|
float64 |
yes, single set |
The MO coefficients, one row per MO, columns in the AO order of |
|
as |
yes, |
The α and the β coefficients, replacing |
|
float64 |
no, SHOULD |
The AO overlap matrix (AO overlap and density matrices below). |
|
float64 |
no; only with |
The spin-summed one-particle density matrix. |
|
float64 |
no; both or neither, only with the α and β coefficients |
The α and the β one-particle density matrices. |
n_ao is the number of AOs of the basis payload: the sum over its shells of
2l+1 (spherical) or (l+1)(l+2)/2 (Cartesian).
basis payload — schema’d as $defs/BasisPayload (strict). The AO order
is the concatenation of the shells in array order, each in the in-shell order
of Appendix A.2.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
string |
yes |
Id of the |
— |
|
array of shells (below) |
yes |
The contracted shells, in AO order. |
— |
|
boolean |
no |
Angular type of every shell without its own |
— |
|
integer ≥ 0 |
no |
Number of AOs: the sum over the shells of |
— |
|
array of ECP entries (below) |
no |
Effective core potentials, at most one per atom. |
— |
|
integer ≥ 0 |
no |
Number of electrons the wavefunction describes: |
electrons |
Each shell ($defs/BasisShell, strict):
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
integer ≥ 0 |
yes |
0-based index into the atoms of the |
— |
|
integer, 0–7 |
yes |
Shell angular momentum. |
— |
|
≥ 1 numbers, each > 0 |
yes |
Primitive exponents. |
bohr⁻² |
|
≥ 1 numbers |
yes |
Contraction coefficients on |
— |
|
boolean |
no |
Overrides the payload-level |
— |
exponents and coefficients MUST have the same length. JSON Schema
cannot express that rule, so the schema does not check it.
n_electrons, when present, MUST equal the sum of the mo_metadata
occupations over both spin channels, within 1e-6, unless
occupation_semantics is transition_weight; and when root
provenance.n_electrons (§ 3.2) is present as well, the two MUST be equal.
Effective core potentials¶
An ecp entry ($defs/BasisEcpCentre, strict) replaces the
n_core_electrons innermost electrons of one atom by a potential. The
wavefunction describes the other Z − n_core_electrons electrons of that
atom, which is why n_electrons subtracts the core counts. A consumer that
computes a property from the wavefunction, such as the electrostatic
potential, a population or an electron count, gives an ECP atom the effective
nuclear charge Z − n_core_electrons.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
integer ≥ 0 |
yes |
The atom, a 0-based index as for a shell’s |
— |
|
integer ≥ 0 |
yes |
Number of electrons the potential replaces on this atom. |
electrons |
|
string |
no |
Name of the potential, e.g. |
— |
|
array of radial functions (below) |
no |
The local part and the semi-local channels. Absent, the potential is named by |
— |
Each radial function ($defs/BasisEcpProjector, strict) is a sum of terms in
the conventional semi-local form,
U(r) = Σ_i c_i · r^(n_i − 2) · exp(−α_i r²) r in bohr, U in hartree
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
integer ≥ 0 |
yes |
Angular momentum of a semi-local channel; for the local part, its conventional label |
— |
|
≥ 1 numbers, each > 0 |
yes |
The |
bohr⁻² |
|
≥ 1 numbers |
yes |
The |
hartree · bohr^(2 − n_i) |
|
≥ 1 integers |
yes |
The radial powers |
— |
|
boolean |
no |
|
— |
The three arrays are parallel and MUST have the same length. The potential of the centre is
V(r) = U_L(r) + Σ_channels Σ_{m=−l..l} |l m⟩ U_l(r) ⟨l m|
where U_L is the radial function with local: true (zero when there is
none), which acts on every angular momentum, and each semi-local channel
multiplies the projector |l m⟩⟨l m| onto angular momentum l about the
centre. A centre has at most one local part, and its l is the highest l
of the centre: the local part of a potential with s, p and d channels is
labelled l = 3. As in the tabulations of Gaussian, Molpro and NWChem, a
semi-local channel of a centre with a local part holds the difference
U_l(r) − U_L(r): QVF stores the function that multiplies the projector, so a
producer copies such a table without converting it.
mo_metadata payload — schema’d as $defs/MoMetadataPayload (strict).
spin selects one of two shapes. "unrestricted" carries its orbitals in an
alpha and a beta object, matching mo_coefficients_alpha and
mo_coefficients_beta, and no top-level n_mo, energies, occupations or
symmetry_labels. Every other spin value carries one set of orbitals at the
top level, matching mo_coefficients, and no alpha or beta. Per-MO arrays
are in the row order of the coefficient member.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
|
yes |
|
— |
|
|
no |
What the orbitals are: eigenfunctions of the converged Fock or Kohn–Sham operator ( |
— |
|
integer ≥ 0 |
no |
Number of AOs; equals the |
— |
|
integer ≥ 0 |
no; single set only |
Number of MOs; equals the row count of |
— |
|
array of numbers |
yes, single set only |
Orbital energy of each MO. |
Hartree |
|
array of numbers |
yes, single set only |
Occupation of each MO: electrons per orbital, or a transition weight (see |
electrons |
|
array of strings |
no; single set only |
Irreducible-representation label of each MO, one per entry of |
— |
|
spin channels (below) |
yes, |
The α and the β orbitals. |
— |
|
|
no |
Meaning of |
— |
|
3 numbers |
no |
Crystal momentum of the orbitals, in fractional coordinates of the reciprocal lattice; absent or |
— |
|
boolean |
no; yes for |
|
— |
|
|
no |
Alternative spelling of |
— |
|
|
no |
Order of the last axis of complex coefficients. |
— |
|
string |
no |
Reference to the electronic state the orbitals describe, for state-specific orbitals. For natural transition orbitals it is the |
— |
|
integer ≥ 1 |
no |
The |
— |
|
|
no |
Which half of a state’s natural transition orbitals the section holds (below). |
— |
|
string |
no |
Name of the method that localized the orbitals. |
— |
|
string, non-empty |
no |
Name of the minimal reference basis of free-atom AOs from which the producer constructed intrinsic atomic orbitals (IAOs), for IAO-based localization and IAO charges, e.g. |
— |
|
|
no |
Fraction of each localized orbital on each atom; each row sums to 1. |
— |
|
|
no |
Centroid of each localized orbital. |
bohr |
|
array of integers ≥ 0 |
no |
Number of atoms each localized orbital is centred on. |
— |
A spin channel ($defs/MoSpinChannel, strict) carries energies (Hartree)
and occupations (electrons, 0 to 1), both required, and optionally n_mo
(the row count of its coefficient member) and symmetry_labels (one per
entry of its energies). What state_ref refers to for orbitals other
than natural transition orbitals is not yet specified.
The IAO reference basis. Intrinsic atomic orbitals (IAOs) are built from
the occupied orbitals of the calculation and a minimal basis of free-atom
AOs, and intrinsic bond orbitals (IBOs) by localizing the occupied orbitals on
them (G. Knizia, J. Chem. Theory Comput. 2013, 9, 4834–4843,
doi:10.1021/ct400687b). The construction takes the minimal basis as an input:
the IAOs, the IAO charges and the IBOs change slightly with it (that paper
uses free-atom AOs from cc-pVTZ, MINAO, and compares them with Huzinaga’s
MINI and with ANO-RCC functions). A producer that localizes on IAOs
SHOULD therefore name that basis in localization_reference_basis, by the
name its program uses ("minao", "mini", …), beside localization_method.
Deprecated fields. Three keys that producers wrote before the canonical
carriers existed remain valid, so that archives which carry them keep
validating. The schema annotates them "deprecated": true; producers
SHOULD NOT write them, consumers SHOULD prefer the canonical carrier
when both are present, and they may be removed in a future major version.
Field |
Type |
Meaning |
Canonical carrier |
|---|---|---|---|
|
array of numbers, one per atom |
IAO partial charges, in e. |
The |
|
integer ≥ 0 |
The excited state natural transition orbitals describe, in the producer’s numbering. |
|
|
number |
That state’s excitation energy, in eV. |
The state’s |
Natural transition orbitals. The natural transition orbitals (NTOs) of an
excited state (§ 5.12) are written as two wavefunction.gto sections with
the basis of the reference wavefunction: one holds the hole orbitals, which
span the occupied space of the reference, and one the particle orbitals,
which span its virtual space. Both mo_metadata payloads carry
orbital_kind: "nto", occupation_semantics: "transition_weight", the same
state_ref (the id of the excited_states section) and state_index (the
index of the state there), and nto_role: "hole" in one section,
"particle" in the other. Row k of the hole section and row k of the particle
section are the k-th hole–particle pair, so the two sections have the same
number of rows, in order of decreasing weight, and the same occupations:
the weight λₖ of each pair. λₖ is the k-th eigenvalue of T Tᵀ for the
transition density matrix T in the orbital basis, the square of its k-th
singular value, and the weights of a normalized state sum to 1. energies,
which the payload requires, has no meaning for NTOs: producers SHOULD
write zeros, and consumers ignore it. The state’s nto_ref names the hole
section; a consumer finds the particle section as the wavefunction.gto
section whose mo_metadata has the same state_ref and state_index and
nto_role: "particle".
For an unrestricted reference, there are still two sections per state,
not four. Both payloads use spin: "unrestricted", with alpha and beta
objects and mo_coefficients_alpha / mo_coefficients_beta members. Each
spin channel has its own corresponding-orbital transformation and its own
hole–particle pairs. Row k of the hole’s α channel pairs with row k of the
particle’s α channel, and likewise for β. Hole and particle MUST have
the same row count and the same occupations in each spin channel. The α
and β row counts may differ, including an empty channel. Each channel’s
occupations MUST be nonnegative, in non-increasing order, with one
weight per coefficient row; its energies and optional n_mo have that
same length/count. The weights are squared singular values λₖ = σₖ², not
singular values. For a normalized state, both spins together sum to 1;
neither spin is separately normalized. The hole and particle each carry
the same weights, so this sum counts each pair once. nto_ref still names
the hole section and the particle lookup above is unchanged and unique.
The state identified by state_ref and state_index MUST exist.
For compatibility, deprecated NTO metadata without nto_role remains
accepted as in toolkit v0.3.0 and is exempt from the new unrestricted
channel/pair checks. Consumers MUST NOT infer a missing role from section
order. New writers use the complete canonical fields described above.
The normalization statement is conditional: full TDDFT/RPA transition densities can have a non-unit weight sum because of de-excitation terms. QVF does not label a transition density as normalized, and validators do not impose a unit sum. See R. L. Martin, J. Chem. Phys. 118, 4775 (2003), doi:10.1063/1.1558471, equations 4–9 and the spin-unrestricted extension. This clarification does not specify NTOs of restricted-open references.
Spin and complex coefficients¶
restrictedandrestricted_openuse the single-set shape: onemo_coefficientsmember and top-levelenergiesandoccupations. Occupations run from 0 to 2 electrons per spatial orbital. Arestricted_openwavefunction has singly occupied orbitals (fractional occupations are allowed, for natural or ensemble orbitals); by the usual high-spin convention a singly occupied orbital carries an α electron.unrestricteduses the two-set shape:mo_coefficients_alphaandmo_coefficients_beta, described by thealphaandbetaspin channels, with occupations from 0 to 1.generalizedis a two-component (spinor) wavefunction in the single-set shape. Each MO is a spin orbitalψ_i = Σ_μ (C[i, μ] χ_μ α + C[i, n_ao + μ] χ_μ β): the AO axis ofmo_coefficientshas 2 n_ao entries in the spinor layout[α AOs…, β AOs…], the α components on then_aoAOs ofbasisin their Appendix A.2 order, then the β components on the same AOs in the same order.n_aoinbasisandmo_metadatastays the number of spatial AOs. Occupations run from 0 to 1. Ageneralizedwavefunction MUST carrycomplex: true; a real one is written with a zero imaginary part.complex: truemeans that every coefficient member has a trailing axis of length 2,[re, im]:[n_mo, n_ao, 2], or[n_mo, 2 n_ao, 2]forgeneralized. Withcomplexabsent orfalseevery coefficient member is real and has no such axis.coefficient_encoding: "complex_split_last_axis"is the same statement ascomplex: true(and"real"asfalse) and is read the same way whencomplexis absent.
AO overlap and density matrices¶
The optional members overlap, density_matrix, density_matrix_alpha and
density_matrix_beta are float64 [n_ao, n_ao] matrices whose rows and
columns follow the AO order of basis (Appendix A.2), real in every case,
including a complex or generalized wavefunction.
overlapis the AO overlap matrixS[μ, ν] = ⟨χ_μ | χ_ν⟩of the contracted AOs exactly asbasisdefines them: primitives normalized with theN_iof Appendix A.1 and contracted with the stored coefficients. Producers SHOULD write it. Its diagonal lets any consumer check that the stored coefficients and AO order mean what the producer’s own integral code meant (Appendix A.1, Verifying withoverlap), and validators do: a diagonal that disagrees with the basis is the errorE_NORMALIZATION.density_matrixis the spin-summed (total) one-particle density matrixPin the AO basis of a single-set wavefunction, so that the electron density isρ(r) = Σ_μν P[μ, ν] χ_μ(r) χ_ν(r)andtr(P S)is the number of electrons it describes. For orbitals that define it, such as an SCF wavefunction,P[μ, ν] = Σ_i n_i C[i, μ] C[i, ν]with the occupationsn_i; a correlated method may store its own density, which its orbitals do not reproduce. For complex coefficientsPis the real part of the Hermitian density matrix, all thatρneeds because the AOs are real; forgeneralizedit is the spin-summed spatial density,P[μ, ν] = Re Σ_i n_i (C̄[i, μ] C[i, ν] + C̄[i, n_ao + μ] C[i, n_ao + ν]).density_matrix_alphaanddensity_matrix_betaare the α and the β density matrices of an unrestricted wavefunction; the total density is their sum and the spin density their difference.
The density members follow the coefficient members: density_matrix appears
only with mo_coefficients, and density_matrix_alpha and
density_matrix_beta appear only together and only with
mo_coefficients_alpha and mo_coefficients_beta.
Checks¶
Besides the payload definitions, validators check (§ 6): the rank of every
coefficient member against complex; the length of every symmetry_labels
against its energies; the [n_ao, n_ao] shape of overlap and of the
density members, and their pairing with the coefficient members; n_electrons
against the occupations (all E_MEMBER_MALFORMED) and against
provenance.n_electrons (E_ROOT_INCONSISTENT); and the diagonal of
overlap against Appendix A.1 (E_NORMALIZATION).
5.3.1 wavefunction.bloch — k-resolved Bloch orbitals, provisional¶
Provisional. This kind was promoted from the vendor section
x_vibeqc.bloch_wavefunctionby maintainer decision before a second independent producer shipped it (GOVERNANCE.md, “Vendor → canonical promotion”); itsregistry.jsonpromotionsentry carries"status": "provisional". It is canonical in every other respect: the schema and the validators check it, and the conformance corpus exercises it. It becomes final when a second producer ships it, and any revision needed before then is additive (§ 7.2).
Carries the k-resolved crystalline orbitals of a periodic system: complex MO
coefficients at every k-point of a set, for one or two spin channels, over the
atom-centred Gaussian basis of the cell, with their energies and occupations.
A producer whose orbitals live at Γ alone may keep using wavefunction.gto
(§ 5.3); a producer with orbitals at several k-points, or at one k-point other
than Γ, writes this kind.
{
"id": "wf_bloch",
"kind": "wavefunction.bloch",
"members": {
"basis": {"path": "wf_bloch/basis.json", "format": "json", "sha256": "…"},
"kpoints": {"path": "wf_bloch/kpoints.json", "format": "json", "sha256": "…"},
"mo_metadata": {"path": "wf_bloch/mo_metadata.json", "format": "json", "sha256": "…"},
"mo_coefficients": {"path": "wf_bloch/mo_coefficients.bin", "format": "binary",
"dtype": "float64", "shape": [2, 2, 2, 2, 2], "sha256": "…"},
"energies": {"path": "wf_bloch/energies.bin", "format": "binary",
"dtype": "float64", "shape": [2, 2, 2], "sha256": "…"},
"occupations": {"path": "wf_bloch/occupations.bin", "format": "binary",
"dtype": "float64", "shape": [2, 2, 2], "sha256": "…"}
}
}
Bloch sum. The basis payload is the one of § 5.3, with the AO order and
the primitive normalization of Appendix A; its shell center indices refer to
the atoms of one cell. For each AO χ_μ the Bloch function at crystal momentum
k is
φ_μk(r) = N^(−1/2) · Σ_T e^{+i k·T} · χ_μ(r − T)
where T runs over the lattice translations T = n₁a₁ + n₂a₂ + n₃a₃ along the
periodic axes (n_i = 0 for an axis whose pbc entry is false) and N is the
number of cells in the Born–von Kármán supercell. k is given in fractional
coordinates of the reciprocal lattice, k = k₁b₁ + k₂b₂ + k₃b₃ with
a_i · b_j = 2π δ_ij, so k·T = 2π (k₁n₁ + k₂n₂ + k₃n₃). The phase is
e^{+ik·T}, and the AO’s position inside the cell is not part of it. Orbital m
of spin channel s at k-point k is
ψ_msk(r) = Σ_μ C_ksmμ · φ_μk(r), C_ksmμ = c[k, s, m, μ, 0] + i · c[k, s, m, μ, 1]
with c the mo_coefficients array. In this convention the overlap of two
Bloch functions is S_μν(k) = Σ_T e^{ik·T} ⟨χ_μ(r) | χ_ν(r − T)⟩, and the
orbitals of a converged calculation are orthonormal in that metric, C†S(k)C
= 1. The electron density of the cell is
ρ(r) = Σ_k w_k Σ_s Σ_m n_ksm |ψ_msk(r)|², with the weights w of the
kpoints payload and the occupations n. An orbital multiplied by a phase
e^{iθ} is the same state; consumers MUST NOT assume a particular gauge.
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
JSON, |
yes |
The contracted shells of the cell, as for |
— |
|
JSON, |
yes |
The k-points, in the order of axis 0 of the binary members; table below. |
— |
|
JSON, |
yes |
The orbital set; table below. |
— |
|
float64 |
yes |
|
— |
|
float64 |
yes |
|
hartree |
|
float64 |
yes |
|
electrons |
Spin channel 0 is α and 1 is β. Unlike the arrays of § 5.6, whose spin axis leads, the orbital members keep the k-point axis first, so that the orbitals of one k-point are contiguous.
Payload kpoints ($defs/BlochKpointsPayload, strict; kpoints is
required):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
≥ 1 arrays of 3 numbers |
Every k-point, in fractional reciprocal-lattice coordinates (see above). n_k is their number. |
— |
|
array of numbers ≥ 0 |
Integration weight of each k-point, one per k-point, summing to 1 within 1e-6. Absent when the k-points are not an integration set, such as points along a path. |
— |
|
array of strings |
One label per k-point, such as a high-symmetry name; |
— |
|
3 integers ≥ 1 |
Dimensions of the uniform mesh the k-points were taken from, when they were: the k-points are its points, or the irreducible subset of them that the weights account for. |
— |
|
3 numbers |
Fractional reciprocal-lattice position of mesh point (0, 0, 0); absent means a Γ-centred mesh. |
— |
|
boolean |
|
— |
|
object |
Optional declaration (§ 4.3, Declared units) restating that |
— |
Payload mo_metadata ($defs/BlochMoMetadataPayload, strict). Per-orbital
energies and occupations are the binary members above, not fields of this
payload.
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
|
yes |
One set of spatial orbitals for both spins ( |
|
1 or 2 |
yes |
Axis 1 of the binary members; 1 for |
|
integer ≥ 0 |
yes |
Axis 2 of the binary members: the orbitals at each k-point and spin. |
|
integer ≥ 0 |
yes |
Axis 3 of |
|
|
yes |
The coefficients are complex; always |
|
|
yes |
|
|
as in § 5.3 |
no |
What the orbitals are; absent means |
|
array of integers ≥ 0 |
no |
The number of orbitals that are defined at each k-point, one entry per k-point, each at most |
|
|
no |
Fermi level, on the absolute scale of |
|
object |
no |
Optional declaration restating that |
Structure. The section’s structure is the one its section-level
structure_ref names, else the one basis.structure_ref names (§ 4.1). It
MUST be a structure section with at least one periodic axis (§ 5.1).
Rules a validator checks (§ 6): mo_coefficients is
[n_k, n_spin, n_mo, n_ao, 2] with n_spin 1 or 2; energies and
occupations have its [n_k, n_spin, n_mo]; the kpoints payload lists n_k
k-points and, when present, n_k labels and n_k weights that sum to 1
within 1e-6; mo_metadata states the n_spin that spin implies and the
n_spin, n_mo and n_ao of the binary members, and n_mo_per_k has n_k
entries of at most n_mo; basis.n_ao equals n_ao. A disagreement, or a
structure with no periodic axis, is E_MEMBER_MALFORMED; a
basis.structure_ref that does not name a structure section (when the
section names none itself) is E_REF_UNRESOLVED.
With bands. When an archive carries both a wavefunction.bloch section
and a bands section (§ 5.6) whose k-points include some of the Bloch
section’s, the band energies at those k-points SHOULD agree with
energies once converted from hartree to eV (mind the axis orders,
[n_spin, n_k, n_bands] against [n_k, n_spin, n_mo]). Validators do not
check this.
5.4 Spectra¶
Every spectra.* section carries exactly one JSON member, spectrum. The six
one-dimensional kinds share one payload, $defs/SpectrumPayload;
spectra.nmr and spectra.epr carry object-shaped parameter sets,
$defs/NmrSpectrumPayload and $defs/EprSpectrumPayload.
Each payload definition in § 5 has one of three strictness levels:
strict — no keys other than the listed ones, at the root and in every listed object, except extension keys whose names begin with
x_;typed-open — the listed fields are typed; the root stays open for forward growth;
permissive — the listed fields are typed and every object stays open; a later revision may tighten the definition once producer conventions settle.
A consumer ignores keys it does not know in an open object.
One-dimensional spectra¶
spectra.ir, spectra.raman, spectra.uvvis, spectra.ecd, spectra.vcd
and spectra.generic. Payload: $defs/SpectrumPayload, typed-open.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
number[] |
yes |
The x value of every point or line. |
the kind’s § 4.3 unit, or |
|
number[] |
yes |
The y value of each |
the kind’s § 4.3 unit, or |
|
number[] |
no |
Alias of |
as |
|
unit name (§ 4.3) |
no |
Unit of |
— |
|
unit name (§ 4.3) |
no |
Unit of |
— |
|
object[] |
no |
Annotated peaks: |
|
|
object |
no |
The line shape the producer applied, or recommends: |
|
|
number > 0 |
no |
Temperature the spectrum refers to. |
K |
|
object |
no |
|
nm; dimensionless |
|
object |
no |
|
— |
|
string |
no |
|
— |
The x axis. frequencies carries the x axis in the unit § 4.3 gives the
kind — cm⁻¹ for spectra.ir, eV for spectra.uvvis — unless x_units
declares another unit. The name is historical and is kept for every kind,
including those whose x values are energies (UV-Vis, ECD); x is an optional
quantity-neutral alias, and a rename is left to a future major version. For a
kind § 4.3 gives no unit (spectra.raman, spectra.ecd, spectra.vcd,
spectra.generic) producers SHOULD declare x_units and y_units;
consumers conventionally assume cm⁻¹ for Raman and VCD and eV for ECD. A
declared unit is a declaration, not a conversion: the values are stored in it,
and a consumer MUST NOT read them in the kind’s default unit. x_units,
y_units and broadening.units are unit names of § 4.3 (Declared units).
One length. frequencies, intensities and, when present, x MUST
have the same length. JSON Schema cannot express this rule, so a validator
checks it separately (§ 6).
peaks[].assignment.mode_index is a 0-based index into the modes of the
archive’s vibrations section (§ 5.5); state_index identifies the
electronic state a transition reaches. When the payload carries states_ref,
every state_index is the index of a state of the excited_states section
that states_ref names (§ 5.12), and a validator checks both (§ 6); without
states_ref, states are numbered as the producer numbers them.
The raman and uvvis blocks are meaningful only in the kind they name.
spectra.nmr¶
Payload: $defs/NmrSpectrumPayload, permissive. Atom indices (atom_index,
i, j) are 0-based indices into the atoms of the archive’s structure.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
string |
no |
Observed nucleus, e.g. |
— |
|
string |
no |
Shift reference, e.g. |
— |
|
string |
no |
Solvent or solvation model, when one was used. |
— |
|
object[] |
no |
One entry per nucleus: |
ppm; |
|
object[] |
no |
One entry per nucleus: |
ppm |
|
object[] |
no |
One entry per atom pair: |
Hz |
spectra.epr¶
Payload: $defs/EprSpectrumPayload, permissive. Units are fixed: g-values
are dimensionless; hyperfine and zero-field-splitting parameters are in MHz.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
object |
no |
|
dimensionless |
|
object[] |
no |
One entry per magnetic nucleus: |
MHz |
|
object |
no |
|
MHz |
A 3 × 3 tensor of either payload is written as three rows in the Cartesian frame of the structure.
5.5 Trajectories, reactions, vibrations¶
trajectory: JSON metadata (atom identities, per-frame metadata) + coords
[n_frames, n_atoms, 3] in Å, plus optional per-frame members (the cell,
velocities, gradients, times, energies, cell volumes, temperatures; below).
reaction.path uses the same layout and adds waypoint records
({frame_index, label, kind, energy_eh?}, kind ∈
reactant/transition_state/intermediate/product/point). reaction.waypoints
carries only annotations and references an existing trajectory section via the
section-level trajectory_ref. vibrations: JSON metadata (frequencies in
cm⁻¹) + displacements float64 [n_modes, n_atoms, 3]. scan.surface: JSON
metadata + the 1-D coordinate values axis_a and axis_b + energies
[nA, nB], with optional relaxed geometries.
trajectory members. Every binary member is little-endian and C-ordered
(§ 4.2), in the frame order and atom order of coords. The per-frame members
are optional and independent: an optimization may carry only energies, a
molecular-dynamics run all of them.
Role |
dtype |
Shape |
Required |
Meaning |
Unit |
|---|---|---|---|---|---|
|
JSON |
— |
yes |
Atom identities and per-frame metadata ( |
— |
|
float64, or float32 |
|
yes |
Cartesian position of every atom in every frame. float32 only when |
Å |
|
float64 |
|
no |
The cell, in the structure convention: rows, row |
Å |
|
float64 |
|
no |
Velocity of every atom in every frame. |
Å / fs |
|
float64 |
|
no |
The energy gradient dE/dR of every atom in every frame, as the |
hartree / bohr |
|
float64 |
|
no |
Time of each frame. |
fs |
|
float64 |
|
no |
Energy of each frame: the binary form of |
hartree |
|
float64 |
|
no |
Volume of the cell of each frame. |
ų |
|
float64 |
|
no |
Instantaneous temperature of each frame. |
kelvin |
The schema types these members as $defs/TrajectoryCoords,
$defs/TrajectoryLattice, $defs/TrajectoryFrameVectors (velocities,
gradient) and $defs/TrajectoryFrameScalars (the [n_frames] members).
The rules that relate the members to each other are semantic, and a validator
checks them (§ 6):
Extents.
n_framesandn_atomsare the first two extents ofcoords. Every per-frame member hasn_framesas its leading extent, andvelocitiesandgradienthaven_atomsas their second; a[n_frames, 3, 3]latticehas one cell per frame.Precision.
coordsMAY be float32 whenmetadata.precisionis"float32", which halves the size of a long run;precision, when present, MUST name the dtype ofcoords, and float32coordswithout it are an error. Every other member is float64.Periodicity. A
trajectorythat carrieslatticeMUST carrymetadata.pbc, and atrueentry ofmetadata.pbcMUST be accompanied bylattice, mirroring thestructurecontract of § 5.1:pbcis the normative carrier of periodicity, and a row of an aperiodic axis is bookkeeping, not a cell edge. A trajectory withoutlatticeis molecular.Energies. When both the binary
energiesandmetadata.energiesare present they MUST agree within 1e-10 hartree, frame by frame. Producers SHOULD prefer the binary member for long runs and MAY then omit the JSON array.Times. When
timesis absent andmetadata.timestep_fsis present, framek(0-based) is atk × timestep_fs. Whentimesis present it is the time of each frame, whatevertimestep_fssays.
trajectory.lattice is not the convention of reaction.path.lattice
(columns, bohr); Lattice conventions in § 4.3 states both. A validator reads
each in its own convention and never mixes them.
reaction.path members. A reaction.path has the metadata and coords
of a trajectory, with the same rules, and may carry the per-frame members
velocities, gradient, times and energies of the table above, with the
same shapes, units and rules. It carries neither cell_volumes nor
temperatures, and its cell is its own lattice member, below. The
frame_volumes and volume_grid members carry per-frame volumetric data
($defs/Volume4DBinary, $defs/VolumeGridPayload).
Periodic reaction paths. reaction.path may carry an optional lattice
binary member: float64 with shape [3, 3] (fixed cell — the common case) or
[n_frames, 3, 3] (variable cell), columns = a, b, c in bohr. Its
presence is what marks the path periodic — a reaction.path without
lattice is unambiguously molecular and renderers must draw no cell. This is
capability detection by member presence, per § 7.1; it does not involve a
qvf_version bump.
This is not the layout or unit of structure.lattice_vectors or of
trajectory.lattice (rows, Å); see Lattice conventions in § 4.3 for the
side-by-side comparison and the conversion.
trajectory metadata payload — schema’d as
$defs/TrajectoryMetadataPayload (typed-open), which extends
$defs/TrajectoryMetadataCommon, the keys it shares with the reaction.path
metadata. It names the atoms, in the atom order of coords, through at least
one of symbols, atomic_numbers and atoms; when more than one is present
they MUST describe the same atoms. Per-frame arrays are in frame order.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
array of strings |
one of three |
Element symbol of each atom. |
— |
|
array of integers ≥ 0 |
one of three |
Atomic number of each atom. |
— |
|
array of |
one of three |
Atom identities as objects. |
— |
|
array of numbers |
no |
Energy of each frame; equal to the binary |
Hartree |
|
integer ≥ 0 |
no |
Number of frames; equals the leading dimension of |
— |
|
|
no |
What produced the frames: |
— |
|
3 booleans |
for a |
Per-axis periodicity of the frames, as in the |
— |
|
|
no |
Thermodynamic ensemble of a molecular-dynamics run. |
— |
|
number > 0 |
no |
Time between consecutive frames; frame |
fs |
|
|
no |
Precision of |
— |
|
object |
no |
Declared units (§ 4.3, Declared units), keyed by a field of this payload or a member role of the section. The units of this section remain the contract, so a declaration restates them: |
— |
reaction.path metadata payload — schema’d as
$defs/ReactionPathMetadataPayload (typed-open), which also extends
$defs/TrajectoryMetadataCommon: every field of the trajectory table above,
with the same rules except the pbc requirement, which belongs to a
trajectory’s lattice (a reaction path is periodic when it carries its own
lattice member), plus:
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
array of waypoint records (below) |
no |
Annotated frames of the path. |
— |
|
array of numbers |
no |
Value of the reaction coordinate at each frame: the abscissa of an energy profile. |
|
|
string |
no |
Display label of the reaction coordinate. |
— |
|
string |
no |
Unit of |
— |
|
integer, 0–3 |
no |
Number of periodic dimensions, shared by every frame of a periodic path. |
— |
|
array of integers, 0–3 |
no |
Number of periodic dimensions of each frame, for a path whose frames differ; used instead of |
— |
|
array of integers ≥ 0 |
no |
For each slab of |
— |
|
string |
no |
Display label of the per-frame volumes. |
— |
|
number |
no |
Suggested isovalue for the per-frame volumes. |
that of the volume data |
The volume_grid member that accompanies frame_volumes is a grid payload
(§ 5.2, $defs/VolumeGridPayload).
Per-frame volumes and volume.series. The frame_volumes and
volume_grid members of a reaction.path are the older form of a
volume.series section (§ 5.2) whose axis has kind: "frame", values
equal to the path’s volume_frame_index (or 0, 1, …, n − 1 when it is
absent) and trajectory_ref naming the path; volume_label corresponds to
the section label of the series, and volume_isovalue to the isovalue
of a section hint (§ 3.4.1). The two forms carry
the same data, [n, nx, ny, nz] slabs on one grid. Producers SHOULD write
per-frame volumes as a volume.series section, which any trajectory or
reaction path can name; both forms remain valid in v1 and neither is
deprecated, so a consumer that reads per-frame volumes SHOULD read both.
Waypoint record — $defs/ReactionWaypoint (strict), used by reaction.path
metadata and by reaction.waypoints:
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
integer ≥ 0 |
yes |
0-based index of the annotated frame: of the section’s own |
— |
|
string |
yes |
Display label, e.g. |
— |
|
|
yes |
Role of the frame on the path; |
— |
|
number |
no |
Energy of the frame. |
Hartree |
reaction.waypoints waypoints payload — schema’d as
$defs/ReactionWaypointsPayload (strict):
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
array of waypoint records |
yes |
Annotated frames of the referenced trajectory. |
— |
|
array of numbers |
no |
Value of the reaction coordinate at each frame of that trajectory, in frame order. |
— |
scan.surface metadata payload — schema’d as
$defs/ScanSurfaceMetadataPayload (typed-open). The axis objects axis_a and
axis_b are the preferred form. The flat label and unit keys are recognised
alternatives that producers already write; when both forms are present, the
objects take precedence.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
axis objects (below) |
no |
The first driven coordinate (along the rows of |
— |
|
string |
no |
Flat alternatives to |
— |
|
string |
no |
Flat alternatives to |
— |
|
string |
no |
Flat alternatives to |
— |
|
array of |
no |
Atom identities, in the atom order of |
— |
|
string |
no |
Unit of the |
— |
|
object |
no |
Declared units, as for |
— |
An axis object ($defs/ScanSurfaceAxis, typed-open) carries label (string,
required), unit (string: the unit of the values in the matching axis_a or
axis_b binary member, e.g. "bohr" or "rad") and atoms (the 0-based
indices of the atoms that define the coordinate: two for a distance, three for
an angle, four for a dihedral).
vibrations metadata payload — schema’d as
$defs/VibrationsMetadataPayload (typed-open). Per-mode arrays hold one entry
per mode, in the mode order of displacements. An imaginary mode is
written as a negative frequency whose magnitude is the imaginary wavenumber:
a mode at 512i cm⁻¹ is written -512.0. imaginary, when present, MUST
agree with the sign of frequencies.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
array of numbers |
yes |
Harmonic wavenumber of each mode; negative for an imaginary mode. |
cm⁻¹ |
|
array of numbers |
no |
IR intensity of each mode. |
km·mol⁻¹ |
|
array of numbers |
no |
Raman scattering activity of each mode. |
Å⁴·amu⁻¹ |
|
array of numbers |
no |
Reduced mass of each mode. |
amu |
|
array of numbers |
no |
Force constant of each mode. |
mdyn·Å⁻¹ |
|
array of strings |
no |
Irreducible-representation label of each mode. |
— |
|
array of booleans |
no |
|
— |
|
integer ≥ 0 |
no |
Number of modes; equals the leading dimension of |
— |
|
array of strings |
no |
Element symbol of each atom, in the atom order of |
— |
|
array of atoms as in the |
no |
Reference geometry: one atom per atom of |
Å |
vibrations hessian_ref. A vibrations section MAY carry the
section field hessian_ref (a peer of members), the id of the hessian
section (§ 5.11) its modes were derived from. A validator checks that it
names a hessian section (§ 6).
5.6 Bands, DOS, and periodic kinds¶
Each kind below lists its members; each JSON member names the schema
definition its payload conforms to ($defs/…), and a validator checks it
against that definition. A payload is strict when it allows only the
fields of its table plus vendor keys beginning x_, and typed-open when the
fields of its table are typed and further keys are allowed. Units are those of
§ 4.3; the Unit columns restate them. All indices are 0-based.
Spin axis¶
An array that resolves spin carries it as its leading axis, of length
n_spin (1 or 2; index 0 is α, 1 is β), as bands.eigenvalues
[n_spin, n_k, n_bands] always has. Several members also have an older,
lower-rank form without that axis:
Member |
With the spin axis |
Lower-rank form (means |
|---|---|---|
|
|
|
|
|
— |
|
|
|
|
|
|
|
|
|
|
|
|
Both forms are legal, and a consumer reads the lower-rank form as n_spin = 1.
In a bands section a rank-4 projections and an occupations MUST have
the [n_spin, n_k, n_bands] extents of eigenvalues, and a rank-3
projections its [n_k, n_bands]; a validator reports a disagreement as
E_MEMBER_MALFORMED (§ 6). A producer whose eigenvalues have two spin
channels SHOULD write projections with the spin axis; a rank-3
projections beside two spin channels carries one set of weights, which a
consumer MAY apply to both. A DOS section with a spin axis also states
n_spin (a section field of dos.total and dos.projected, a field of the
meta payload of dos.coop and dos.cohp), and it MUST equal the length
of that axis. For two-component (spinor) bands n_spin is 1.
bands¶
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
JSON, |
yes |
The path, the Fermi level and the fat-band channels; table below. |
— |
|
float64 |
yes |
|
eV |
|
float64, |
no |
Fat-band weights, |
— |
|
float64, |
no |
|
electrons |
Payload kpath ($defs/KpathPayload, strict; no field is required):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
array of |
Every k-point of the path in the order of |
— |
|
array of strings |
One label per k-point, parallel to |
— |
|
array of segment objects |
The straight segments of the path, in path order; table below. |
— |
|
number |
Fermi level, on the scale of |
eV |
|
number |
The same Fermi level under the name the DOS kinds use; equal to |
eV |
|
boolean |
|
— |
|
integer, 1 or 2 |
Equal to |
— |
|
integer ≥ 1 |
Equal to |
— |
|
integer ≥ 1 |
Equal to |
— |
|
array of channel objects or strings |
One per last-axis slice of |
— |
|
string |
Display title. |
— |
|
object |
Optional declaration, field name or member role → unit name, restating the units of this table (§ 4.3, Declared units): |
— |
|
|
Informational keys that existing producers write; a consumer needs none of them. |
— |
Segment object ($defs/KpathSegment, strict; also used by qpath):
Field |
Type |
Meaning |
|---|---|---|
|
integer ≥ 0 |
Index of the segment’s first point along the path axis. Absent: the previous segment’s |
|
integer ≥ 0 |
Index of its last point, inclusive. Absent: |
|
integer ≥ 1 |
Number of points on the segment, both ends included. |
|
string |
High-symmetry labels of the two end points; may be empty. |
|
|
Fractional reciprocal-lattice coordinates of the two end points. |
Consecutive segments therefore share their boundary point, unless the later
one gives an explicit start; that is how a path with a jump (X|U) is
written.
Channel object ($defs/DosChannel, typed-open; also used by the DOS and
phonon payloads below):
Field |
Type |
Meaning |
|---|---|---|
|
string, required |
Display label, e.g. |
|
integer ≥ 0 |
Atom index into the |
|
integer ≥ 0 |
Shell angular momentum. Absent: summed over shells. |
|
integer |
Component of a spherical shell, −l to l, as in Appendix A.2. Absent: summed over the shell. |
|
0 or 1 |
For a channel that is itself spin-resolved, which arises only in a projection without a spin axis. |
Further keys, such as an element symbol, are allowed.
dos.total and dos.projected¶
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
float64 |
yes |
|
eV |
|
float64 |
yes |
|
states / eV |
|
|
yes |
|
states / eV |
dos.coop and dos.cohp¶
Crystal orbital overlap (COOP) and Hamilton (COHP) populations of atom pairs.
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
float64 |
yes |
|
eV |
|
float64 |
yes |
|
— |
|
float64 |
yes |
|
— |
|
JSON, |
yes |
What the pair axis means; table below. |
— |
Payload meta ($defs/DosMetaPayload, typed-open):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
string |
|
— |
|
integer, 1 or 2 |
Number of spin channels: the length of the spin axis, or 1 without one. |
— |
|
number |
Absolute Fermi level that |
eV |
|
number ≥ 0 |
Broadening width. |
eV |
|
string |
Broadening function, e.g. |
— |
|
array |
One entry per pair: |
Å ( |
|
array of strings |
Display labels, one per pair. |
— |
|
array of channel objects |
One per pair, naming its two atoms as |
— |
|
object |
Optional declaration, field name or member role → unit name (§ 4.3, Declared units): |
— |
fermi_surface¶
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
JSON, |
yes |
The k-point mesh and the cell; table below. |
— |
|
float32 or float64 |
yes |
|
eV |
Grid point (i1, i2, i3) of a uniform mesh lies at the fractional
reciprocal-lattice coordinates (i1/nk1 + shift[0], i2/nk2 + shift[1], i3/nk3 + shift[2]), modulo the reciprocal lattice; without a shift, index 0
on every axis is Γ. A producer SHOULD write lattice_vectors or
reciprocal_lattice: without either, a consumer can place the surface only in
fractional coordinates. When both are present they MUST agree.
Payload mesh ($defs/FermiMeshPayload, strict; no field is required):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
|
|
— |
|
integers ≥ 1 |
The same three numbers as separate keys, the form existing producers write; equal to |
— |
|
|
Position of grid point |
— |
|
boolean |
|
— |
|
array of |
For a mesh that is not uniform: the fractional coordinates of every grid point, entry |
— |
|
number |
Absolute Fermi level that |
eV |
|
integer, 1 or 2 |
Number of spin channels of the underlying calculation. |
— |
|
array of integers ≥ 0 |
Index, in the producer’s full band list, of each band along the last axis of |
— |
|
|
Real-space cell, rows, in the convention of |
Å |
|
|
b1, b2, b3 as rows, including the 2π factor: a_i · b_j = 2π δ_ij. |
Å⁻¹ |
|
object |
Optional declaration, field name or member role → unit name (§ 4.3, Declared units): |
— |
phonon_bands¶
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
JSON, |
yes |
The q-point path; table below. |
— |
|
float64 |
yes |
|
cm⁻¹ |
Payload qpath ($defs/QpathPayload, strict; no field is required) is laid
out like kpath: kpoints, labels, segments (segment objects counting
q-points along frequencies axis 0), channels (channel objects), title
and units mean what they mean there, without the electronic fields fermi,
fermi_energy_ev, spinor and n_spin; a declared units.frequencies is
cm-1. It adds:
Field |
Type |
Meaning |
|---|---|---|
|
integer ≥ 1 |
Number of q-points along the path, equal to |
|
integer ≥ 1 |
Number of atoms in the cell. |
|
integer ≥ 1 |
Number of phonon branches, 3 · |
|
boolean |
Whether the section carries mode eigenvectors. |
phonon_dos¶
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
JSON, |
yes |
Counts, broadening and channels; table below. An empty object is valid. |
— |
|
float64 |
yes |
|
cm⁻¹ |
|
float64 |
yes |
|
states / cm⁻¹ |
Payload meta ($defs/PhononMetaPayload, typed-open):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
integer ≥ 1 |
Number of atoms in the cell. |
— |
|
integer ≥ 1 |
Number of phonon branches, 3 · |
— |
|
number ≥ 0 |
Broadening width. |
cm⁻¹ |
|
string |
Broadening function, e.g. |
— |
|
array of channel objects |
Channels of a projected phonon DOS, one per projection row. |
— |
|
object |
Optional declaration, field name or member role → unit name (§ 4.3, Declared units): |
— |
equation_of_state¶
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
float64 |
yes |
|
ų |
|
float64 |
yes |
|
eV |
|
JSON, |
yes |
The fitted model; table below. |
— |
Payload fit ($defs/EosFitPayload, strict):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
string, required |
|
— |
|
number |
Equilibrium volume. |
ų |
|
number |
Energy at |
eV |
|
number |
Bulk modulus at |
GPa |
|
number |
Pressure derivative of the bulk modulus at |
dimensionless |
|
number ≥ 0 |
Root-mean-square residual of the fit over the points. |
eV |
|
integer ≥ 0 |
Number of points the fit used. |
— |
|
array of numbers |
Pressure of the fitted model at each volume, parallel to |
GPa |
|
string |
Informational restatements of eV, ų and GPa. |
— |
Model-specific values, such as polynomial coefficients, go under x_ keys.
DOS section fields. dos.total and dos.projected carry their metadata
as optional fields on the section object (§ 4.1), not as members:
Field |
Type |
Meaning |
|---|---|---|
|
integer, |
Number of spin channels: |
|
number ≥ 0, eV |
Width of the broadening applied to the DOS. |
|
string |
Name of the broadening function, e.g. |
|
number, eV |
Fermi energy. |
|
number ≥ 0 |
Number of electrons; may be fractional. |
|
array of objects ( |
One label object per row of |
A channels item may carry atom (integer ≥ 0, the 0-based index of the
projected atom in the structure section), l (integer ≥ 0), m (integer),
spin (0 = α/up, 1 = β/down), and label (a display string such as
"O-2p"). Every item field is optional. An item may carry further fields;
a consumer ignores those it does not understand.
Phonon eigenvectors and projected phonon DOS. phonon_bands may carry an
optional binary member eigenvectors, float64 with shape
[n_q, n_modes, n_atoms, 3] when the eigenvectors are real or
[n_q, n_modes, n_atoms, 3, 2] when they are complex. The last axis of the
complex form holds [re, im], as for complex wavefunction.gto
coefficients. The first two axes index the same q-points and modes as
frequencies, and the axis of length 3 holds the Cartesian x, y, z
components. The member stores the eigenvectors as the producer computed
them; v1 does not fix their normalization or mass weighting.
phonon_dos may carry an optional binary member projected, float64
[n_channels, n_points]: row c is the phonon DOS projected on channel c,
sampled on the n_points values of frequencies. The meta member then
SHOULD carry a channels array with one object per row, in row order.
An item has the shape of a dos.projected channel, typically
{"atom": 0, "label": "Mg"}, with every field optional.
5.7 Analysis kinds¶
atom_properties: per-atom scalar and vector results, one binary member per
role; the role list, units and conventions are in the atom_properties
subsection below. bond_orders: JSON
{method, pairs: [{i, j, order, distance_ang?, symbol_i?, symbol_j?}]}.
citations: one binary references member of UTF-8 BibTeX bytes. basis.ao:
a per-AO grid + ao_metadata (quantum numbers + provenance) — see
Appendix A.3 for how a spherical and a Cartesian component are each named.
The JSON payloads of bonds (§ 5.1), bond_orders, scf_history,
topology.qtaim and structure.symmetry are specified by the $defs entries
named below, at the strictness levels defined in § 5.4. Atom indices are
0-based indices into the atoms of the archive’s structure; those of bonds
address the structure § 5.1 assigns (the structure that holds a bonds
member, or the one a bonds section’s structure_ref names, else the first
structure).
bonds¶
Payload of a bonds section’s bonds member and of a structure section’s
optional bonds member: $defs/BondsPayload, strict.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
object[] |
yes |
One entry per bond. |
— |
|
integer ≥ 0 |
yes |
The two atoms. |
— |
|
number ≥ 0 |
no |
Bond order; absent means 1. |
— |
bond_orders¶
Payload of the bond_orders member: $defs/BondOrdersPayload, strict.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
string |
yes |
Bond-order definition. Lowercase names are recommended: |
— |
|
object[] |
yes |
One entry per atom pair. |
— |
|
integer ≥ 0 |
yes |
The two atoms. |
— |
|
number |
yes |
Bond order under |
— |
|
number ≥ 0 |
no |
Interatomic distance. |
Å |
|
string |
no |
Element symbols of the two atoms. |
— |
scf_history¶
Payload of the iterations member: $defs/ScfHistoryPayload, strict.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
object[] |
yes |
One record per SCF iteration, in order. |
— |
|
integer ≥ 0 |
yes |
Iteration number, as the producer counts them. |
— |
|
number |
yes |
Total energy after the iteration. |
Hartree |
|
number |
no |
Energy change from the previous iteration. |
Hartree |
|
number |
no |
DIIS error norm. |
atomic units |
|
number |
no |
Root-mean-square change of the density matrix from the previous iteration. |
atomic units |
|
boolean |
no |
Whether the SCF met its convergence criteria; absent means not stated. |
— |
topology.qtaim¶
Payload of the critical_points member: $defs/QtaimPayload, permissive
at the root, with typed points.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
object[] |
yes |
Critical points of the electron density. |
— |
|
string |
yes |
|
— |
|
3 numbers |
yes |
Cartesian position. |
|
|
number |
no |
Electron density at the point. |
not fixed |
|
number |
no |
Laplacian of the electron density at the point. |
not fixed |
|
number |
no |
Ellipticity; meaningful for a |
dimensionless |
|
2 integers ≥ 0 |
no |
For a |
— |
|
integer[] ≥ 0 |
no |
Atoms the point belongs to, e.g. the nucleus of an |
— |
|
object[] |
no |
Gradient paths joining two nuclei through a |
— |
|
2 integers ≥ 0 |
no |
The two atoms the path joins. |
— |
|
array of 3-vectors |
no |
Vertices of the path as a polyline. |
|
|
object |
no |
|
— |
Position unit. Every position — a point’s position and every vertex of
a bond_paths[].path — is Cartesian, in the unit units.position declares.
When units or units.position is absent, the unit is ångström
("angstrom"). This default was chosen to match the structure section
(§ 5.1, Å) whose atoms the points overlay. It is provisional: it is
subject to maintainer decision 2 (“QTAIM position unit”) in
docs/format_review.md, and a later revision of this section will record
that decision. Producers SHOULD therefore declare units.position
explicitly, and a consumer MUST read positions in a declared unit. rho
and laplacian have no fixed unit in v1, and the unit names of § 4.3 do not
yet include a unit of electron density or of its Laplacian, so a producer
cannot declare them; a consumer that does not know the producer’s
convention presents them as written.
structure.symmetry¶
Payload of the data member: $defs/SymmetryPayload, permissive.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
integer 1–230 |
no |
Space-group number of the International Tables for Crystallography. |
— |
|
string |
no |
Short international (Hermann–Mauguin) space-group symbol, e.g. |
— |
|
string |
no |
Hall symbol of the space group. |
— |
|
string |
no |
Point-group symbol; Schoenflies notation recommended, e.g. |
— |
|
string |
no |
The point group in Hermann–Mauguin notation, e.g. |
— |
|
object[] |
no |
Symmetry operations x′ = R x + t: |
fractional coordinates of the structure’s lattice when periodic; Cartesian for a molecule, t zero or absent |
|
string[] |
no |
Wyckoff letter of each atom, in the order of the structure’s |
— |
|
integer[] ≥ 0 |
no |
For each atom, the index of the representative atom of its symmetry-equivalence class. |
— |
|
number > 0 |
no |
Distance tolerance of the symmetry search. |
Å |
|
integer 1–230, string |
no |
The same quantities as |
— |
atom_properties¶
An atom_properties section holds per-atom results as binary members, one per
role. Row i of every member belongs to atom i of the structure the
section describes, and all roles of one section have the same n_atoms. A
section carries one or more roles. A scalar role is float64 [n_atoms]
($defs/AtomChargeBinary); a vector role is float64 [n_atoms, 3]
($defs/AtomVectorBinary), whose last axis holds the Cartesian components
x, y, z in the frame of the structure. The table is the one role list: the
schema, the § 5 table, this table and both reference writers carry the same
names in the same order.
Role |
Shape |
Quantity |
Unit |
Convention |
|---|---|---|---|---|
|
|
Mulliken net atomic charge |
|
Net charge (see below). |
|
|
Löwdin net atomic charge |
|
Net charge. |
|
|
Hirshfeld (stockholder) net atomic charge |
|
Net charge. |
|
|
Net atomic charge from the intrinsic atomic orbital (IAO) partition |
|
Net charge. |
|
|
Spin population, α minus β electrons on the atom |
electrons |
Positive for an excess of α electrons. |
|
|
Charge Model 5 (CM5) net atomic charge |
|
Net charge. |
|
|
Net atomic charge fitted to the molecular electrostatic potential on the CHELPG grid |
|
Net charge. |
|
|
Net atomic charge from the restrained electrostatic potential (RESP) fit |
|
Net charge. |
|
|
Net atomic charge from an unrestrained fit to the electrostatic potential |
|
Net charge. |
|
|
Natural population analysis (NPA) net atomic charge of the NBO analysis |
|
Net charge. |
|
|
Minimal basis iterative stockholder (MBIS) net atomic charge |
|
Net charge. |
|
|
Net atomic charge from integrating the electron density over the QTAIM (Bader) basin |
|
Net charge. |
|
|
Density-derived electrostatic and chemical (DDEC) net atomic charge |
|
Net charge. |
|
|
Total valence of the atom |
dimensionless |
Under the producer’s bond-order scheme; |
|
|
Bonded valence: the sum of the bond orders between the atom and every other atom |
dimensionless |
Under the producer’s bond-order scheme. |
|
|
Condensed Fukui function f⁺ (nucleophilic attack) |
dimensionless |
f⁺ = p(N+1) − p(N) (see below). |
|
|
Condensed Fukui function f⁻ (electrophilic attack) |
dimensionless |
f⁻ = p(N) − p(N−1). |
|
|
Condensed Fukui function f⁰ (radical attack) |
dimensionless |
f⁰ = (f⁺ + f⁻) / 2. |
|
|
Condensed dual descriptor Δf |
dimensionless |
Δf = |
|
|
Energy assigned to the atom by the producer’s energy partition |
|
The partition scheme is the producer’s. |
|
|
Volume assigned to the atom by the producer’s partition |
|
The partition scheme is the producer’s. |
|
|
Isotropic NMR shielding σ of the atom’s nucleus |
|
A shielding, not a chemical shift: no reference compound is subtracted. |
|
|
Atomic magnetic moment, Cartesian components |
μB (Bohr magneton) |
A collinear producer puts the moment on the quantisation axis (see below). |
|
|
Energy gradient on the atom, ∂E/∂R, Cartesian components |
|
A gradient, not a force: force = −gradient (see below). |
Charges. Every *_charge role is a net atomic charge in units of the
elementary charge e: the atom’s nuclear charge (its effective core charge
where an effective core potential replaces core electrons) minus its electron
population, so a positive value means electron loss. The role name is the
partition scheme. The schemes give different numbers for the same density,
and a consumer MUST NOT treat two charge roles as interchangeable.
spin_population counts electrons, α minus β, and is positive for an excess
of α electrons.
Fukui functions. The condensed Fukui functions are differences of atomic
electron populations. With p_A(M) the electron population of atom A in the
system of M electrons and N the electron count of the system, f⁺_A =
p_A(N+1) − p_A(N), f⁻_A = p_A(N) − p_A(N−1), f⁰_A = (f⁺_A + f⁻_A) / 2, and the
dual descriptor Δf_A = f⁺_A − f⁻_A. All are dimensionless. A producer that
writes dual_descriptor together with fukui_plus and fukui_minus SHOULD
write values that satisfy the identity to numerical precision. The population
scheme behind the populations is the producer’s and is not named by the role.
magnetic_moment. The three components are the Cartesian components of
the atomic moment in μB, in the frame of the structure. A collinear
calculation has no spatial spin direction: its producer puts the signed
moment on the quantisation axis, [0, 0, m] for the usual z axis, with the
sign convention of spin_population (positive for an excess of α electrons).
A non-collinear producer writes the full vector.
force_eh_bohr. The row of atom i is the gradient ∂E/∂R_i of the
energy with respect to the position of atom i, in hartree/bohr, the sign
convention of the gradient member of the forces kind (force = −gradient),
despite the role’s name. The role lets a section show per-atom gradients next
to charges; it is a display alias. When a forces section for the same
structure is present and its gradient differs from this role, the forces
section is authoritative.
Custom roles. A producer may add a quantity the list does not provide as
a role named custom.<name>, where <name> is one or more characters of
A–Z, a–z, 0–9 and _. A custom role is a scalar (float64 [n_atoms]) or
a vector (float64 [n_atoms, 3]) member, like the listed roles. A section that
has a custom.* member MUST also have a JSON member meta
($defs/AtomPropertiesMetaPayload, strict) with one entry per custom role,
keyed by the role name. A validator reports E_MEMBER_MALFORMED for a
custom.* member that meta does not describe, including when the section
has no meta member (§ 6). Entries for roles the section does not carry are
ignored. A consumer that does not know a custom role presents its
description and units, or ignores it. Use a listed role when one fits, and
a vendor kind (§ 7.3) for data that is not per-atom.
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
object |
yes, one per custom role |
Description of the role of that name. |
— |
|
string |
yes |
Unit of the values, spelled as in § 4.3 where it gives a spelling (for example |
— |
|
string |
yes |
What the quantity is, with any sign convention. |
— |
|
|
yes |
|
— |
{
"custom.born_charge_mean": {
"units": "e",
"description": "Trace of the Born effective-charge tensor divided by three.",
"kind": "scalar"
}
}
5.8 run.record — self-contained run records¶
A run.record section carries the verbatim artefacts of one program
invocation: the input handed to a quantum-chemistry code, the full log/output
it produced, and any auxiliary files. With it, a QVF archive is a
self-contained record of a calculation — input, results, and log travel in
one file.
Section fields (peers of members, like volume.difference’s operands):
Field |
Required |
Meaning |
|---|---|---|
|
yes |
The code the input/log belong to ( |
|
no |
Version string of that code. |
|
no |
Launch command line, as one string. |
|
no |
Integer process exit status. |
|
no |
ISO 8601 UTC timestamps. |
|
no |
Ordering index (≥ 0) when an archive carries multiple run records (multi-step workflows: opt → freq → …). |
|
no |
Id of the |
|
no |
Outcome of this run: |
job_ref and run_status make the runs of a job set (§ 5.9) unambiguous: a
job is pending until a run.record names it, and that run’s run_status is
the job’s. In an archive with one job.spec, a run record without job_ref
executed that job, as before.
program is deliberately distinct from the root source.program (§ 3.1): the
root identifies the QVF producer, which may be a converter or packing tool;
run.record.program identifies the code that actually ran. For a code
writing its own archives the two coincide.
Members — at least one of input / log is REQUIRED:
input— the verbatim main input, opaque binary bytes that MUST decode as UTF-8 text. Producers converting from another encoding transcode at write time.log— the full log/output of the program, opaque UTF-8 binary bytes. A producer that finalizes the archive before its own process ends SHOULD embed the log as complete as it can be at write time and note any truncation in thefilesindex ("truncated": trueon thelogentry); a packing tool working from finished files embeds them whole.files— optional JSON index describing the stored members, schema’d as$defs/RunRecordFilesPayload: a map from member role to an entry that records the member’s original file. Every key MUST name a member that exists in the section (input,log, or anattachment.<suffix>), so the index has no vendor keys of its own. An entry is strict: only the fields below and vendor keys beginningx_.Field
Type
Meaning
filenamestring
Original file name, without directories.
descriptionstring
What the file is, for display.
media_typestring
IANA media type of the bytes, e.g.
text/plainorchemical/x-xyz.truncatedboolean
truewhen the stored bytes are not the complete file, e.g. a log embedded before the run ended.No field of an entry is required; producers SHOULD give
filenamewhenever the member was read from a file.attachment.<suffix>— optional auxiliary files (structure includes, restart data, …), opaque binary bytes with no encoding requirement.<suffix>matches[A-Za-z0-9_.-]+. Describe each in thefilesindex.
Producers SHOULD NOT duplicate large binary result files (wavefunctions, volumetric grids) as attachments when a canonical section kind exists for the data — attachments are for run artefacts, not a bypass of § 5.
A consumer renders input and log as plain text. Logs can reach tens of MB;
consumers SHOULD size-gate rendering (the uncompressed size is available
from the ZIP central directory without reading the member, and from the
member’s size, § 4.2) and offer the full text on demand.
5.9 job.spec — declarative job specification¶
A job.spec section describes the calculation an archive requests —
before, and independent of, any results it carries. Together with a
structure section (§ 5.1) it makes a QVF archive an executable input: a
runner opens the container, reconstructs the job from the declarative
payload, executes it, and writes the results — and a run.record (§ 5.8) —
back into the same container. An archive whose provenance.run_status
(§ 3.2) is "pending" carries at least one job.spec section and the
structure sections they run on.
Members:
spec— REQUIRED JSON member, schema’d as$defs/JobSpecPayload.
The payload:
Field |
Required |
Meaning |
|---|---|---|
|
yes |
|
|
no |
Method identifier (e.g. |
|
no |
Basis-set name (e.g. |
|
no |
Exchange-correlation functional name, for DFT methods, or |
|
no |
Net charge, integer. Absent means |
|
no |
Spin multiplicity 2S+1, integer ≥ 1. Absent means |
|
no |
|
|
no |
Ordered list of task identifiers, e.g. |
|
no |
String: id of the |
|
no |
Object: implicit solvation, below. Absent means none. |
|
no |
String: the dispersion correction by its conventional lowercase name, e.g. |
|
no |
String: the scalar-relativistic treatment by its conventional lowercase name, e.g. |
|
no |
Object: SCF settings, below. Absent means the engine’s defaults. |
|
no |
Object: geometry-optimisation settings, below. Absent means the engine’s defaults. |
|
no |
Object: the resources the job would like, below. Hints, not requirements. |
|
no |
Object of additional engine-specific keywords (JSON-safe values). A runner that does not recognize an option MUST refuse the job rather than silently drop the option. |
null and absent differ. null states that the method takes no such
input, and a runner MUST NOT supply one; an absent key leaves the choice
to the engine, as for method. The empty string "" is a deprecated
spelling of null, which earlier producers wrote for a semiempirical job’s
basis: it remains valid, a consumer reads it as null, and producers
SHOULD NOT write it.
The payload root is open (additionalProperties: true) for forward growth,
but producers SHOULD put engine-specific keywords under options,
keeping the typed top level portable across codes. The four objects below are
strict, each a $defs entry of the schema: they carry only the fields listed
and vendor keys beginning x_, so an engine keyword has no place in them and
goes under options. Every field of them is optional, and an absent field
means the engine’s default.
solvation ($defs/JobSpecSolvation):
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
string, non-empty |
yes |
The solvation model by its conventional lowercase name, e.g. |
|
string, non-empty |
no |
The solvent by name, e.g. |
|
number > 0 |
no |
Static dielectric constant, dimensionless. When given it is the constant the model uses, and |
scf ($defs/JobSpecScf):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
number > 0 |
Convergence threshold of the SCF energy change. An engine that converges on another measure maps it to its nearest criterion. |
hartree |
|
integer ≥ 1 |
Maximum number of SCF iterations. |
— |
|
string, non-empty |
The initial guess by its conventional lowercase name, e.g. |
— |
|
number |
Damping factor of the density or Fock update. |
— |
geometry ($defs/JobSpecGeometry):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
number > 0 |
Convergence threshold of the optimisation: the largest Cartesian gradient component. An engine with several criteria applies it to its gradient criterion and keeps its defaults for the others. |
hartree/bohr |
|
integer ≥ 1 |
Maximum number of optimisation steps. |
— |
|
|
The coordinate system the optimiser steps in. |
— |
resources ($defs/JobSpecResources) are hints, not requirements: a
runner uses what it has and may use less, and a run that used other resources
has not failed to honour the spec. What a run actually used is recorded in provenance (n_threads, n_mpi_ranks,
n_gpus, wall_seconds; § 3.2).
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
integer ≥ 1 |
Number of CPU cores to use. |
— |
|
integer ≥ 1 |
Memory to use. |
megabytes |
|
number > 0 |
Wall-clock time to allow. |
s |
A periodic job on a given structure:
{
"job_type": "periodic",
"method": "rks", "functional": "pbe", "basis": "pob-tzvp-rev2",
"structure_ref": "structure",
"kpoints": [4, 4, 1],
"tasks": ["optimize"],
"dispersion": "d3bj",
"scf": {"convergence": 1e-8, "max_iterations": 100, "guess": "sad"},
"geometry": {"convergence": 4.5e-4, "max_steps": 50, "coordinates": "redundant"},
"resources": {"n_cores": 16, "memory_mb": 32000, "walltime_s": 86400}
}
A job.spec is declarative data, never code. Executing it involves no
evaluation of an embedded program — deliberately distinct from
run.record.input, which may be an arbitrary script and is a record of
what ran, not a request. A runner MUST NOT execute run.record.input as
a side effect of opening or running an archive.
Lifecycle: a runner that executes a pending archive updates the same
container (§ 2.3) — result sections are added, a run.record is embedded, and
provenance.run_status moves to "converged" or "failed". The runner also
records what ran, with which resources and when, in provenance (software,
git_commit, n_threads, n_mpi_ranks, n_gpus, started_utc,
finished_utc; § 3.2). The job.spec section is preserved verbatim through
this update, so a settled archive still records what was asked. Multi-step
workflows append further run.record sections ordered by their sequence
field.
Job sets¶
An archive MAY carry several job.spec sections, a job set: for
example one calculation for each species of a reaction scheme (§ 5.14), or the
same species at several levels of theory. Each job.spec section is one job,
independent of the others.
Each job names its structure. In an archive with more than one
structuresection, a job without astructure_refis ambiguous, and a runner MUST refuse it, as above. The section-levelstructure_ref(§ 4.1) is the preferred carrier, because a consumer reads it from the manifest without opening the payload; astructure_refinside thespecpayload remains valid, the section’s takes precedence, and producers SHOULD keep the two equal.Runs name their job. A runner executes any subset of the jobs, in any order or in parallel. For each job it runs it adds a
run.recordwhosejob_refnames the job’s section and whoserun_statusgives the job’s outcome (§ 5.8), and the result sections of that run SHOULD carryrun_refnaming the run record andstructure_refnaming the structure (§ 4.1), so that a reader attributes every result to its job. A job that norun.recordnames has not run.The set has one status.
provenance.run_statussummarises the set:pending,running, thenconvergedorfailed(§ 3.2).One refusal does not stop the set. A runner that refuses or fails one job still runs the others it was asked to run, and records the failed one with
run_status: "failed".
Jobs of a set do not depend on each other. A sequence within one job, such as
an optimisation followed by a frequency calculation on the optimised
geometry, is that job’s tasks list.
A pending job set with two species, each job naming its structure on the section object:
"provenance": {"run_status": "pending"},
"sections": [
{"id": "structure_s1", "kind": "structure", "label": "1", "charge": 0,
"multiplicity": 1, "members": {"structure": {"path": "…", "format": "json", "sha256": "…"}}},
{"id": "structure_s2", "kind": "structure", "label": "2", "charge": 0,
"multiplicity": 2, "members": {"structure": {"path": "…", "format": "json", "sha256": "…"}}},
{"id": "job_s1_opt", "kind": "job.spec", "structure_ref": "structure_s1",
"members": {"spec": {"path": "…", "format": "json", "sha256": "…"}}},
{"id": "job_s2_opt", "kind": "job.spec", "structure_ref": "structure_s2",
"members": {"spec": {"path": "…", "format": "json", "sha256": "…"}}}
]
5.10 forces — nuclear gradient and stress¶
A forces section carries the first derivatives of the energy at one
geometry: the derivatives with respect to the nuclear positions and, for a
periodic system, the stress. The stored quantity is the energy gradient,
not the force: gradient[a][c] is ∂E/∂R, the derivative of the energy with
respect to Cartesian coordinate c (0 = x, 1 = y, 2 = z) of atom a. The force
on atom a is the negative of row a, F = −∇E. A consumer that draws forces
MUST negate the stored values.
The rows follow the atoms of one structure section (§ 5.1), in the order of
its atoms, and the Cartesian axes are that structure’s. The structure is
the one the section-level structure_ref names when the section carries one
(§ 4.1), else the one meta.structure_ref names; when neither is given, it
is the archive’s structure section if the archive has exactly one.
Producers SHOULD name the structure whenever the archive has more than
one.
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
float64 |
yes |
|
hartree / bohr |
|
float64 |
no |
|
hartree / bohr³ |
|
JSON, |
no |
Table below. |
— |
Payload meta ($defs/ForcesMetaPayload, strict; no field is required):
Field |
Type |
Meaning |
|---|---|---|
|
string |
|
|
string |
Method of the energy that was differentiated, e.g. |
|
|
What |
|
object ( |
Declared units: |
A validator checks that gradient is [n_atoms, 3] and stress [3, 3];
when it can resolve the structure, it checks that n_atoms is that
structure’s atom count, and a meta.structure_ref that names no structure
section is an unresolved reference (§ 6).
5.11 hessian — Cartesian second derivatives¶
A hessian section carries the matrix of second derivatives of the energy
with respect to the nuclear Cartesian coordinates at one geometry, from which
harmonic frequencies and normal modes follow; a vibrations section names
the Hessian its modes come from through hessian_ref (§ 5.5).
matrix[i][j] is ∂²E/∂x_i∂x_j, where index i = 3a + c belongs to Cartesian
coordinate c (0 = x, 1 = y, 2 = z) of atom a: the order is x₀, y₀, z₀, x₁,
y₁, z₁, … for N atoms. The atoms and axes are those of the section’s
structure, resolved as for forces (§ 5.10). The matrix is symmetric; a
producer whose Hessian is not exactly symmetric, as a finite-difference one
is, SHOULD write (H + Hᵀ)/2.
Member |
Format |
Required |
Shape and meaning |
Unit |
|---|---|---|---|---|
|
float64 |
yes |
|
hartree / bohr²; hartree / (bohr² · amu) when |
|
JSON, |
no |
Table below. |
— |
Payload meta ($defs/HessianMetaPayload, strict; no field is required, but
a mass-weighted matrix requires atom_masses_amu):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
string |
|
— |
|
boolean |
|
— |
|
boolean |
|
— |
|
array of numbers > 0 |
Mass of each atom in atom order, N entries: the masses of the mass weighting, or the masses frequencies derived from the matrix are to use. |
amu (unified atomic mass unit) |
|
object ( |
Declared units, as for |
— |
A validator checks that matrix is square with an extent divisible by 3,
that atom_masses_amu has N entries, and, when it can resolve the structure,
that N is that structure’s atom count (§ 6).
5.12 excited_states — excited states and transition properties¶
An excited_states section carries the electronically excited states of one
calculation, from TD-DFT, CIS, ADC, EOM-CC or any other method that yields a
table of states: their energies, transition properties and dominant orbital
excitations. Every state is a vertical excitation from one reference
state, usually the ground state that the archive’s wavefunction.gto and
provenance describe. The section has one member:
Member |
Format |
Required |
Meaning |
|---|---|---|---|
|
JSON, |
yes |
The states and a description of the calculation (tables below). |
Besides the generic fields of § 4.1 (its structure_ref names the structure
whose axes the transition dipoles use), the section may carry one field of its
own, a peer of members:
Section field |
Type |
Meaning |
|---|---|---|
|
string |
|
Payload states ($defs/ExcitedStatesPayload, strict):
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
array of states (below) |
yes |
The states, in ascending order of |
|
object (below) |
no |
The calculation the states come from. |
Each state ($defs/ExcitedState, strict):
Field |
Type |
Required |
Meaning |
Unit |
|---|---|---|---|---|
|
integer ≥ 1 |
yes |
Number of the state, unique within the payload, counted from 1 in the producer’s order (normally by increasing energy); the reference state has no entry. Spectrum peaks (§ 5.4), natural transition orbitals (§ 5.3) and transition densities (§ 5.2) name a state by this number. |
— |
|
|
yes |
Vertical excitation energy: the energy of the state minus that of the reference state. |
producers SHOULD write |
|
|
no |
Total energy of the state. |
producers SHOULD write |
|
integer ≥ 1 |
no |
Spin multiplicity 2S + 1. |
— |
|
string |
no |
Irreducible representation of the state, e.g. |
— |
|
number ≥ 0 |
no |
Oscillator strength f of the transition from the reference state. |
dimensionless |
|
number |
no |
Rotatory strength R of the transition, signed. |
10⁻⁴⁰ esu²·cm² |
|
3 numbers |
no |
Electric transition dipole moment ⟨0|μ̂|n⟩. |
e·bohr (atomic units) |
|
3 numbers |
no |
Magnetic transition dipole moment ⟨0|m̂|n⟩. |
e·ħ/mₑ (atomic units, = 2 μ_B) |
|
array (below) |
no |
The dominant orbital excitations of the state. |
— |
|
string |
no |
|
— |
|
string |
no |
|
— |
The two dipoles are Cartesian vectors in the axes of the section’s structure.
The sign of a transition dipole is arbitrary, as is the phase of the state;
f and R are not. In the length gauge f = (2/3) ΔE |μ|², with the excitation
energy ΔE in hartree and the transition dipole μ in atomic units. The
rotatory strength unit is the one quantum-chemistry programs print as
“10⁻⁴⁰ cgs”; the vocabulary of § 4.3 has no name for it, nor for the atomic
units of the dipoles, so this table fixes the units of these three fields and
meta.units does not declare them.
Each contribution ($defs/ExcitedStateContribution, strict):
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
integer ≥ 0 |
yes |
The orbital the electron leaves: a 0-based row of the coefficient member of the reference wavefunction. |
|
integer ≥ 0 |
yes |
The orbital the electron enters, indexed the same way. |
|
|
no |
For an unrestricted reference, the spin channel: |
|
number |
yes |
Weight of the excitation in the state: the squared amplitude X² (CIS, TDA) or X² − Y² (full TD-DFT, RPA), normalized so that the weights of all excitations of the state sum to 1. A list of the dominant ones sums to a little less. |
Without wavefunction_ref the orbital rows refer to the reference calculation
as the producer numbers its orbitals, which a consumer cannot check; producers
SHOULD set wavefunction_ref whenever they write contributions, and give
spin for every contribution of an unrestricted reference. A contribution
without spin in an unrestricted reference indexes a row that both
coefficient members have.
Payload meta ($defs/ExcitedStatesMeta, strict; no field is required):
Field |
Type |
Meaning |
|---|---|---|
|
string |
The excited-state method, e.g. |
|
string |
Label of the reference state, e.g. |
|
integer ≥ 0 |
Number of states; when present it MUST equal the length of |
|
boolean |
|
|
boolean |
|
|
object |
Declared units (§ 4.3), keyed by a field of the states, each value a unit name: |
Linked sections. The table of states is the hub of an excited-state calculation:
wavefunction_refnames the referencewavefunction.gto(§ 5.3).A state’s
nto_refnames thewavefunction.gtosection of its hole NTOs; that section and its particle partner carry this section’sidasstate_refand the state’sindexasstate_index(§ 5.3).A state’s
density_refnames itsvolume.transition_density, which carries this section’sidasexcited_states_refand the state’sindexasstate_index(§ 5.2), or avolume.difference.A one-dimensional spectrum names this section with
states_ref, and its peaks name states byassignment.state_index(§ 5.4). A stick UV-Vis spectrum derived from the table has one line per state at its excitation energy, with the oscillator strength as intensity (y_units"dimensionless"); an ECD stick spectrum uses the rotatory strengths.
A validator checks that the index values are unique and ascending, that
meta.n_states, when present, equals the number of states, that
wavefunction_ref and every nto_ref name wavefunction.gto sections and
every density_ref a volume.transition_density or volume.difference
section, and, when wavefunction_ref names a wavefunction.gto section,
that every from_mo and to_mo is a row of its coefficient member (§ 6).
5.13 Property kinds¶
Three kinds carry properties of the system as a single JSON payload each:
properties.electric (electric multipole moments and polarizabilities),
properties.elastic (the elastic constants of a periodic system) and
properties.dielectric (the dielectric tensors, Born charges and
piezoelectric tensor of a periodic system). A section of one of these kinds has
exactly one member, properties, a JSON member whose payload is strict
(§ 5): the keys of its table, and keys that begin with x_, are allowed, and
the same holds for every object inside it. No field is required unless its
table says so; a field that is absent was not computed.
Conventions common to the three kinds:
Axes. Cartesian components
x, y, zare those of thestructurethe section describes: the one the section-levelstructure_refnames when the section carries one (§ 4.1), else the archive’sstructuresection if it has exactly one. Producers SHOULD name the structure whenever the archive has more than one.Matrices are nested arrays of rows: entry
[i][j]is rowi, columnj, with the Cartesian orderx, y, zfor a 3 × 3 matrix. In Voigt notation the six indices are, in this order,xx, yy, zz, yz, xz, xy.Units are fixed; the tables give them (§ 4.3). The optional
unitsobject of each payload maps a field name to a unit name and may only restate the unit that is fixed, as for the other payloads (§ 4.3, Declared units). It can name only the fields whose unit is in the vocabulary: a compound unit such as debye · Å or GPa⁻¹ has no name there (§ 9), so those fields are fixed by their table alone.One section, one state. A section holds the properties of one geometry and, for an electric field response, one frequency. A producer with several (a static and a dynamic polarizability, say) writes several sections with distinct ids and MAY tie them together with
group(§ 4.1).
properties.electric¶
Payload properties ($defs/ElectricPropertiesPayload, strict; at least one
of dipole, quadrupole, octupole, polarizability and
hyperpolarizability is required):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
string or |
Reference point of the multipole moments, with the meaning of |
bohr, for a vector |
|
object |
|
debye |
|
object |
|
debye · Å |
|
object |
|
debye · Ų |
|
object |
|
atomic units, e² a₀² / E_h; |
|
object |
|
atomic units, e³ a₀³ / E_h²; |
|
object |
Declared units: |
— |
With the charges q_i of the nuclei and of the electrons (the electron’s is −e)
at the positions r_i, taken relative to origin, the multipole moments are:
the dipole μ_a = Σ q_i r_a;
the Buckingham quadrupole Θ_ab = ½ Σ q_i (3 r_a r_b − r² δ_ab), which is traceless, and the Cartesian quadrupole Q_ab = Σ q_i r_a r_b, whose trace is Σ q_i r².
tracelesssays whether the stored matrix has zero trace: it is alwaystruefor"buckingham", and for"cartesian"it says that the trace has been removed, Q_ab − ⅓ δ_ab Σ_c Q_cc;the Buckingham octupole Ω_abc = ½ Σ q_i (5 r_a r_b r_c − r² (r_a δ_bc + r_b δ_ac + r_c δ_ab)) and the Cartesian octupole Σ q_i r_a r_b r_c.
For a charged system the moments depend on origin; for a neutral one the
dipole does not, but the quadrupole does as long as the dipole is non-zero.
The polarizability and hyperpolarizability are the responses of the dipole to a
uniform electric field F: μ_a(F) = μ_a + α_ab F_b + ½ β_abc F_b F_c + …, with
the dynamic versions at the stated frequencies; α is symmetric for a static
field.
Consistency with the root dipole. The root block dipole_moment (§ 3.3)
stays the canonical place for a bare dipole. When both it and a
properties.electric dipole are present, the two state one dipole: vector
MUST equal vector_debye, and total MUST equal total_debye, each
within 1e-6 debye, for every field both state. A producer that restates the
dipole SHOULD also give the same origin; the check compares the dipole
values only. A validator reports a disagreement as E_ROOT_INCONSISTENT
(§ 6), located at the section’s properties member.
properties.elastic¶
Payload properties ($defs/ElasticPropertiesPayload, strict; stiffness is
required):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
6 × 6 numbers, required |
The stiffness matrix C_IJ = ∂σ_I/∂ε_J in Voigt notation, with the engineering shear strains 2ε_yz, 2ε_xz, 2ε_xy. Symmetric. |
GPa |
|
6 × 6 numbers |
The compliance matrix S, the inverse of |
GPa⁻¹ |
|
number |
Bulk modulus K. |
GPa |
|
number |
Shear modulus G. |
GPa |
|
number |
Young’s modulus E. |
GPa |
|
number |
Poisson’s ratio ν. |
— |
|
|
The averaging scheme the four isotropic numbers come from: Voigt (uniform strain, from the stiffness), Reuss (uniform stress, from the compliance) or Hill (the arithmetic mean of the two). Absent means that the scheme is not stated; a producer SHOULD state it whenever it writes a modulus, because the schemes differ for an anisotropic crystal. |
— |
|
object |
Declared units: |
— |
A validator checks that stiffness and, when present, compliance are
symmetric: entries [I][J] and [J][I] differ by at most 1e-6 times the
largest absolute entry of the matrix. A violation is E_MEMBER_MALFORMED
(§ 6). The payload carries no positive-definiteness rule: the stiffness of a
mechanically unstable structure is legitimate data.
properties.dielectric¶
Payload properties ($defs/DielectricPropertiesPayload, strict;
electronic is required):
Field |
Type |
Meaning |
Unit |
|---|---|---|---|
|
3 × 3 numbers, required |
The electronic dielectric tensor ε∞, the high-frequency response with the ions held fixed. |
— (relative permittivity) |
|
3 × 3 numbers |
The ionic (lattice) contribution to the static dielectric tensor. |
— |
|
3 × 3 numbers |
The static dielectric tensor ε₀. |
— |
|
array of 3 × 3 numbers |
The Born effective charge tensor Z* of each atom, one per atom in the atom order of the structure: Z*[i][j] is the polarization along |
e |
|
3 × 6 numbers |
The piezoelectric stress tensor e_iα = ∂P_i/∂ε_α, row |
C / m² |
|
object |
Declared units: |
— |
Two rules need the payload as a whole, so a validator checks them (§ 6):
when
electronic,ionicandstaticare all present,staticMUST equalelectronic+ionic, entry by entry, within 1e-6;when the section’s structure resolves (the section-level
structure_ref, else the archive’s onlystructure),born_chargesMUST have exactly one tensor per atom of it.
A violation of either is E_MEMBER_MALFORMED.
5.14 reaction.scheme — reaction schemes¶
A reaction.scheme section relates structure sections (§ 5.1) as the
reactants, reagents and products of one or more reaction steps, the way a
scheme in a paper does: which species react, what is drawn at the arrow, the
kind of arrow, the conditions written beside it and the yield. It carries the
chemistry of a drawn scheme, not its drawing; the species are the archive’s
structure sections, with their chemical identity (§ 5.1, Chemical
identity), so every reader knows the molecules and their roles without the
program that drew them.
Members:
scheme— REQUIRED JSON member, schema’d as$defs/ReactionSchemePayload(strict).
The section has no kind-specific fields; its generic label (§ 4.1) titles
the scheme. An archive MAY carry several schemes.
Payload scheme ($defs/ReactionSchemePayload, strict):
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
array of step objects, at least one |
yes |
The steps of the scheme, in reading order. Steps that share a species form a sequence: the product of one step is a reactant of the next. |
A step ($defs/ReactionStep, strict):
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
string, |
yes |
Identifier of the step, unique within the payload. |
|
string |
no |
Display label of the step, e.g. |
|
array of participants, at least one |
yes |
The species the step consumes. |
|
array of participants, at least one |
yes |
The species the step forms. |
|
array of participants |
no |
Species drawn at the arrow rather than on either side: reagents, catalysts, solvents drawn as structures. |
|
|
no |
The kind of arrow; absent means |
|
array of strings |
no |
The text written at the arrow, one entry per line, in reading order, e.g. |
|
number, 0 to 100 |
no |
Yield of the step’s products, in percent. |
|
string |
no |
The yield as printed, e.g. |
A participant ($defs/ReactionParticipant, strict):
Field |
Type |
Required |
Meaning |
|---|---|---|---|
|
string |
yes |
Id of the |
|
number > 0 |
no |
Stoichiometric coefficient of the species in the step; absent means 1. |
Every object of the payload may carry vendor keys beginning x_.
Roles are chemical, the arrow is how the step is drawn. reactants are
consumed and products formed in the step’s forward direction whatever the
arrow, so a quantity of the step such as a reaction energy is always products
minus reactants:
forward— reactants → products.equilibrium— reactants ⇌ products; the forward direction is the one written.retrosynthetic— products ⇒ reactants: the target, the step’sproducts, sits at the tail of the arrow and the precursors, itsreactants, at the head. A producer whose drawing records the species by their place at the arrow swaps them when it writes a retrosynthetic step.resonance— reactants ↔ products: two resonance structures of one species, at the tail and the head. No reaction takes place; producers SHOULD NOT writereagents,conditionsor a yield for it.
A species that appears in several steps is one structure section named by
each of them. A species without a three-dimensional structure cannot be a
participant, because every participant names a structure section; a
producer writes such a reagent into conditions instead.
A validator checks (§ 6), reporting E_REF_UNRESOLVED for the first rule and
E_MEMBER_MALFORMED for the others:
every
structure_refnames astructuresection;the step
idvalues are unique within the payload;within one role of one step, no
structure_refoccurs twice (a coefficient says how many).
Reaction energies (reserved). A later revision will add the energies of
each step, computed from energies of its participants and their coefficients;
the key energies of a step is reserved for it, and the strict payload rejects
it until then. A producer that has such numbers now writes them under an x_
key.
A two-step synthesis, the second step an equilibrium with a reagent drawn at the arrow (the structures are sections of the same archive):
{
"steps": [
{"id": "r1", "label": "a",
"reactants": [{"structure_ref": "structure_s1"},
{"structure_ref": "structure_s2", "coefficient": 2}],
"products": [{"structure_ref": "structure_s3"}],
"conditions": ["THF, −78 °C", "2 h"],
"yield_percent": 87, "yield_text": "87%"},
{"id": "r2", "label": "b", "arrow": "equilibrium",
"reactants": [{"structure_ref": "structure_s3"}],
"reagents": [{"structure_ref": "structure_s4"}],
"products": [{"structure_ref": "structure_s5"}]}
]
}
5.15 preview — a picture of the archive¶
A preview section carries a picture of the archive’s contents, so that a
file manager, a quick-look panel or a catalogue can show the archive without
understanding any other section.
Role |
Format |
Required |
Meaning |
|---|---|---|---|
|
opaque binary with |
yes |
A raster image, the picture a file manager shows. |
|
opaque binary with |
no |
A larger or vector rendering of the same picture, for a preview pane. |
Both members are opaque binary members (§ 4.2) and MUST carry their
media_type ($defs/PreviewThumbnail, $defs/PreviewImage): a reader learns
the image type from the manifest and does not sniff the bytes.
Which picture. The picture of the archive is the
thumbnailof the firstpreviewsection insectionsorder. Furtherpreviewsections MAY show parts of the archive and say which withstructure_reforgroup(§ 4.1).Size. The longest side of a thumbnail SHOULD be between 256 and 1024 pixels, and the member SHOULD be at most 1 MiB, so that a file manager reads it cheaply. An already compressed image gains nothing from DEFLATE, so a producer MAY store both members uncompressed.
The bytes are what the type says. A PNG member begins with the PNG signature (bytes
89 50 4E 47 0D 0A 1A 0A), a JPEG member withFF D8 FF, and an SVG member is a UTF-8 SVG document.SVG is inert. An SVG member MUST be self-contained: it references no external resource (no remote
href, image, font or style sheet) and contains no script or event-handler attribute. A consumer that renders it MUST NOT run scripts or fetch external resources, whatever the document contains.
The picture describes the archive and is not data: a consumer MUST NOT
read chemistry from it, and a producer that updates an archive (§ 2.3) so that
the picture no longer matches SHOULD replace or remove the preview
section.
A validator checks that each member’s bytes begin with the signature of its
raster media_type, and that an image/svg+xml member decodes as UTF-8 and
contains an <svg element (§ 6). The media_type values themselves are
checked by the JSON Schema.
6. Validation semantics¶
A validator treats every archive as untrusted input. A conforming validator
performs the checks below and reports each problem as a finding with a
severity: an error makes the archive invalid; a warning does not.
Every check is an error except the orphan rule, the unit-name rule and the
withdrawn version 2, which are warnings. The JSON Schema check is structural; the other checks are
semantic rules that a validator performs whether or not it can run a JSON
Schema engine.
Container — checked from the ZIP central directory before any member is decompressed:
The archive is a readable ZIP, and every entry the validator reads decompresses to exactly the uncompressed size recorded for it and matches its ZIP CRC-32.
ZIP entry names are unique (§ 2.1), except
manifest.json: any other duplicated name is an error. Of severalmanifest.jsonentries the one whose central-directory record comes last is the manifest, and each earlier copy is superseded and reported as the warningW_ORPHAN_MEMBER(§ 2.3).Every ZIP entry name follows the path rules of § 2.1.
No entry exceeds the per-member uncompressed-size cap; the uncompressed sizes of all entries together do not exceed the total cap (§ 6.1). A validator MUST NOT decompress an entry that exceeds a cap, nor any member payload once the total cap is exceeded.
Warning: every entry other than the current
manifest.jsonand directory entries is referenced by a memberpath(orphans, § 2.1, § 2.3).
Manifest:
manifest.jsonexists (the last entry of that name, § 2.3), is within the JSON size and depth caps, and parses as UTF-8 JSON to an object; it conforms to the JSON Schema. Among other things the schema check rejects a rootbyte_orderother than"little"(§ 2.2).qvf_versionis1, or the withdrawn2, which a validator reads as1for every check, the JSON Schema check included, and reports as the warningW_VERSION_WITHDRAWN(§ 3.1);sourcecarriesprogram,version, andcalculation, withprogramandversionnon-empty.sectionsis an array of objects, each with a stringid, a stringkind, and amembersobject.Section
idvalues are unique, and none isauto_open,bookmarks,cameraorcrossfade(reservedviewer_defaultskeys, § 3.1, § 3.4).Every
kindis canonical (§ 5) or a vendor kindx_<vendor>.*(§ 7.3).Extension governance (§ 7): a
critical: truesection whose kind is neither canonical nor a declared vendor namespace is an error.Root blocks agree (§ 3.6): every energy of
energiesstated for the method thatprovenance.methodnames agrees withprovenance.scf_energy, andenergies.components.zpvewiththermochemistry.zpve_eh, within 1e-8 hartree. In an archive with exactly onestructuresection, itschargeandmultiplicityequalprovenance.chargeandprovenance.multiplicitywhere both are present (§ 5.1).
Members and kind-specific rules:
Every member spec is an object with a string
paththat follows § 2.1.Every declared member
pathexists in the archive.Every member
size, when present, is a non-negative integer equal to the uncompressed size the ZIP central directory records for the member’s entry (§ 4.2). The check needs no decompression and is made before the member is read.Every declared member
sha256matches the stored bytes.Every JSON member is within the JSON size and depth caps and parses as UTF-8 JSON.
Every binary member that declares a
dtypeuses a § 4.2 dtype name, and its byte length equalsitemsize × ∏(shape).Every JSON member whose section kind and role have a payload definition (§ 5) conforms to that
$defsentry of the JSON Schema. This is part of the JSON Schema check.A
structurepayload’s periodicity contract (§ 5.1) holds:pbcis present wheneverlattice_vectorsis non-null;lattice_vectorsis non-null whenever anypbc[i]is true; anddimensionality, when present, equals the number of true entries inpbc.A
structuresection’schargeandmultiplicityare possible for the atoms of its payload (§ 5.1, Chemical identity): withcharge, the electron count N = Σatomic_number−chargeis not negative, and withmultiplicitytoo,multiplicity− 1 is at most N and has the parity of N.volume.difference.operand_a/operand_bresolve when present.reaction.waypoints.trajectory_refresolves to atrajectorysection.A section’s
structure_ref, when present, resolves to astructuresection, and itsrun_refto arun.recordsection (§ 4.1).A standalone
bondssection whosestructure_refnames astructuresection: every pair’siandjis an atom of that structure, from 0 to its atom count − 1 (§ 5.1). Abondssection withoutstructure_ref, and thebondsmember of astructuresection, are not checked against an atom count.bands: a rank-4projectionsand anoccupationshave the[n_spin, n_k, n_bands]extents ofeigenvalues, and a rank-3projectionshas its[n_k, n_bands](§ 5.6).trajectoryandreaction.path(§ 5.5):coordsare float32 only whenmetadata.precisionis"float32", andprecision, when present, names the dtype ofcoords. Against acoordsof shape[n_frames, n_atoms, 3],velocitiesandgradientare[n_frames, n_atoms, 3],times,energiesand, for a trajectory,cell_volumesandtemperaturesare[n_frames], andlatticeis[3, 3]or[n_frames, 3, 3]. The binaryenergiesagree withmetadata.energieswithin 1e-10 hartree. A trajectory that carrieslatticehasmetadata.pbc, and one whosemetadata.pbchas atrueentry carrieslattice. Eachlatticeis read in its own convention (§ 4.3); a validator never compares or converts one carrier against another.forcesandhessian(§ 5.10, § 5.11):gradientis[n_atoms, 3],stressis[3, 3],matrixis square with an extent 3N divisible by 3, andhessianmeta.atom_masses_amu, when present, has N entries. When the section’s structure resolves (the section-levelstructure_ref, elsemeta.structure_ref, else the archive’s onlystructuresection),n_atomsand N equal its number of atoms. Ameta.structure_refnames astructuresection.vibrations.hessian_ref, when present, names ahessiansection (§ 5.5).excited_states(§ 5.12): theindexvalues ofstatesare unique and ascending, andmeta.n_states, when present, equals the number of states. The section’swavefunction_refand every state’snto_refnamewavefunction.gtosections, and everydensity_refavolume.transition_densityorvolume.differencesection. Whenwavefunction_refnames awavefunction.gtosection, every contribution’sfrom_moandto_mois a row of its coefficient member: ofmo_coefficients, else ofmo_coefficients_alphaormo_coefficients_betaasspinselects, and of both whenspinis absent. The rows are read from the manifestshapeof the member.Unrestricted NTOs (
wavefunction.gto, § 5.3): each alpha/beta metadata channel has one nonnegative, non-increasing weight and one energy per coefficient row; optionaln_moagrees. The state reference resolves, and exactly one opposite-role section exists for the same state, with the same spin layout and equal row counts and weights per spin. Findings useE_MEMBER_MALFORMEDfor channel/pair inconsistencies andE_REF_UNRESOLVEDfor missing/ambiguous partners or state references, located at the affected section’smembers/mo_metadata. A unit weight sum is not imposed because normalization is conditional.A one-dimensional spectrum’s
states_ref, when present, names anexcited_statessection, and everypeaks[].assignment.state_indexis theindexof one of its states (§ 5.4).A
volume.transition_densitysection’sexcited_states_ref, when present, names anexcited_statessection, and itsstate_indexis theindexof one of its states (§ 5.2).job.spec: thestructure_refof thespecpayload, when present, names astructuresection (§ 5.9). The payload’ssolvation,scf,geometryandresourcesobjects are checked by the JSON Schema check like the rest of the payload. Arun.recordjob_ref, when present, names ajob.specsection (§ 5.8).reaction.scheme(§ 5.14): every participant’sstructure_refnames astructuresection; the stepidvalues are unique within the payload; and nostructure_refoccurs twice within one role of one step.preview(§ 5.15): a member whosemedia_typeisimage/pngbegins with the PNG signature and one whosemedia_typeisimage/jpegwithFF D8 FF; animage/svg+xmlmember decodes as UTF-8 and contains<svg.wavefunction.gto(§ 5.3): every coefficient member has rank 3 with a last extent of 2 whenmo_metadatasayscomplex: true(orcoefficient_encoding: "complex_split_last_axis"), and rank 2 otherwise; everysymmetry_labelsarray, at the top level or in a spin channel, has one entry per entry of itsenergies;overlapand the density members are[n_ao, n_ao], with n_ao counted from thebasisshells (itsn_aowhen the shells cannot be read);density_matrixappears only withmo_coefficients, anddensity_matrix_alphaanddensity_matrix_betaonly together and only with the α and β coefficients; andbasis.n_electrons, when present, equals the sum of the occupations over both spin channels within 1e-6, unlessoccupation_semanticsistransition_weight.A
basis.n_electronsand a rootprovenance.n_electronsthat are both present are equal (§ 3.2, § 5.3).When a
wavefunction.gtosection carriesoverlap, its diagonal agrees with the self-overlaps that Appendix A.1 gives for thebasispayload, to a relative tolerance of 1e-6 (Appendix A.1, Verifying withoverlap).Volumes (§ 5.2): the
dataofvolume.laplacianis[nx, ny, nz], ofvolume.vector[nx, ny, nz, 3], ofvolume.complex[nx, ny, nz, 2]and ofvolume.series[n, nx, ny, nz]; avolume.seriesaxishas onevaluesentry, and onelabelsentry when it has labels, per slab, and itstrajectory_ref, when present, names atrajectoryorreaction.pathsection.Grids (§ 5.2): a grid payload’s
structure_ref, when present, names astructuresection. Whenperiodic[a]is true and the grid’s structure resolves (the section-levelstructure_ref, else the grid’sstructure_ref, else the archive’s onlystructuresection), that structure’spbc[a]is true, andvoxel_vectors[a] × (shape[a] − 1)whenincludes_endpointis true or absent, orvoxel_vectors[a] × shape[a]when it is false, equals lattice rowaof the structure converted to bohr within 10⁻⁶ relative.The property kinds (§ 5.13): a
properties.elasticstiffnessandcomplianceare symmetric to within 1e-6 of their largest entry; in aproperties.dielectricpayload,staticequalselectronic+ionicwithin 1e-6 when all three are present, andborn_chargeshas one tensor per atom of the section’s structure when that resolves (the section-levelstructure_ref, else the archive’s onlystructuresection); each violation isE_MEMBER_MALFORMED. Aproperties.electricdipoleagrees with the rootdipole_momentwithin 1e-6 debye (vectoragainstvector_debye,totalagainsttotal_debye), or the finding isE_ROOT_INCONSISTENT. The payloadsproperties.electric,properties.elasticandproperties.dielectricconform to the$defsdefinitions of § 5.13.wavefunction.bloch(§ 5.3.1):mo_coefficientsis[n_k, n_spin, n_mo, n_ao, 2]withn_spin1 or 2, andenergiesandoccupationshave its[n_k, n_spin, n_mo]; thekpointspayload lists n_k k-points and, when present, n_klabelsand n_kweightsthat sum to 1 within 1e-6;mo_metadatan_spin(1 forrestricted, 2 forunrestricted),n_moandn_ao, andbasis.n_ao, agree with those axes, andmo_metadata.n_mo_per_khas n_k entries of at mostn_mo. The section’s structure (the section-levelstructure_ref, elsebasis.structure_ref) is astructuresection with at least one periodic axis.The JSON members
bands.kpath,dos.coop.meta,dos.cohp.meta,fermi_surface.mesh,phonon_bands.qpath,phonon_dos.meta,equation_of_state.fitandrun.record.filesconform to the$defspayload definitions their tables name (§ 5.6, § 5.8).run.record:inputandlogmembers decode as UTF-8; every key of thefilesindex names a member that exists in the section.atom_properties: everycustom.<name>member has an entry namedcustom.<name>, a JSON object, in the section’smetamember (§ 5.7); a missingmetamember, or one without that entry, is an error for that member. Themetapayload itself is checked against$defs/AtomPropertiesMetaPayloadlike any payload definition.A one-dimensional spectrum’s
frequencies,intensitiesand, when present,xhave the same length — a part ofSpectrumPayloadthat JSON Schema cannot express (§ 5.4).Warning: every declared unit is a unit name of § 4.3 (Declared units): each value of the
unitsobject of a JSON member of a canonical kind, and of themeta.unitsobject of anexcited_statespayload; a one-dimensional spectrum’sx_units,y_unitsandbroadening.units; theunitsof avolume.seriesaxis; and theunitsof every{value, units}object directly underprovenance, which may also be a legacy spelling. This rule needs no JSON Schema engine. The schema types the same strings, so a validator that runs it also reports the schema finding.
6.1 Resource limits¶
A validator reports an error when an archive exceeds one of the caps below. Validators SHOULD use the reference values, which are the defaults of the reference validators; producers SHOULD stay within them so that their archives validate everywhere.
Quantity |
Reference value |
|---|---|
Uncompressed size of one ZIP entry |
8 GiB |
Total uncompressed size of all ZIP entries |
64 GiB |
Size of |
256 MiB |
Nesting depth of JSON arrays and objects |
64 — a top-level |
Compression ratio is not a format validity limit: valid constant arrays can
compress by more than 1000:1. The size caps above and the requirement never to
inflate past the declared uncompressed size bound decompression independently
of compression ratio. Readers MUST reject a mismatch between actual and
declared size or a CRC-32 mismatch as E_ZIP_UNREADABLE.
The reference APIs retain max_ratio as an optional, stricter application
policy for compatibility, with 0 disabling it by default. A positive value
applies to compressed entries of at least ratio_exempt_bytes (default 1 MiB);
STORE entries remain exempt. E_COMPRESSION_RATIO identifies rejection by this
explicit policy, not a malformed QVF archive.
6.2 Finding codes¶
Conforming validators SHOULD report each finding with the stable code
listed in Appendix B (“Validation finding codes”), so that tools, bindings,
and test suites match findings by code rather than by message text. A finding
carries exactly one code: E_… codes are errors, W_… codes are warnings.
The conformance suite’s negative corpus (conformance/negative/) holds a
must-fail archive for each rule, naming the code it must produce.
7. Extension and versioning model¶
7.1 qvf_version¶
Integer. v1 = 1. A value > 1 signals breaking changes; a v1-only consumer
MUST refuse such files, except the withdrawn 2, which it SHOULD read
as 1 (§ 3.1). Minor, backward-compatible growth (new optional
kinds, new optional members) does not bump the integer — capability is
detected via supported-kind checking and the extensions block.
7.2 Canonical kinds¶
Canonical kinds appear in the schema and § 5. They may grow in minor revisions; no canonical kind may be removed or have its required members changed without a major version bump.
7.3 Vendor namespace x_<vendor>.*¶
Any kind matching x_<vendor>.<specific> is a vendor extension. <vendor>
SHOULD be a DNS-like identifier (x_orca, x_pyscf, x_vasp). Vendor
members must be valid JSON, binary or opaque binary member specs (§ 4.2);
an opaque member, such as an image, SHOULD carry its media_type.
Registering the namespace in registry.json (vendor_namespaces) records
who uses it and is advisory (GOVERNANCE.md). A consumer MUST list vendor
sections as present-but-unsupported unless the extension is critical: true.
Unknown non-vendor kinds are not valid QVF.
For example, ASCENT’s advisory x_ascent registration carries non-critical
x_ascent.dataset records beside canonical structure sections. Registering
that prefix does not make its private dataset payload a canonical QVF kind.
7.4 Root extensions block and per-section critical¶
The manifest root may declare vendor extensions:
{ "extensions": { "x_orca": { "version": "1.0", "schema_uri": "…", "critical": false } } }
Each section may carry critical (default false). If critical: true and the
consumer does not support the kind, the consumer MUST refuse to open the
file rather than silently drop the section. Use critical: true only when the
section changes correct interpretation of the rest of the file (e.g. an ECP that
alters the effective electron count).
7.5 Promoting a vendor kind to canonical¶
The kind is used in production by ≥ 2 independent producers for ≥ 1 minor cycle.
A spec PR adds it to § 5, the schema
oneOfbranches, and the validator.Its member contract is stable across the two producers.
At least one reference consumer renders it.
The maintainer may promote a kind before the first criterion is met, as a
maintainer decision recorded in GOVERNANCE.md and registry.json;
spectra.epr and wavefunction.bloch (§ 5.3.1) were promoted that way. A
kind promoted before a second independent producer ships it carries
"status": "provisional" in its registry.json promotions entry. A
provisional kind is canonical in every respect (§ 7.2): producers may emit it,
consumers may rely on it, and any revision it needs is additive. It becomes
final, and loses the status, when a second producer ships it.
8. Conformance¶
8.1 Producer conformance¶
A conforming producer MUST:
write a valid ZIP with
manifest.jsonat the root;set
qvf_versionto1;include
source.program,source.version,source.calculation;use unique section ids matching
^[A-Za-z0-9_.-]+$, other than the reservedauto_open,bookmarks,cameraandcrossfade(§ 3.4);use canonical kinds or
x_<vendor>.*;include only member paths that exist in the ZIP and follow § 2.1 (relative,
/-separated, no..segments), and write each ZIP entry name once — exceptmanifest.jsonwhen updating an archive in place, whose new manifest is the last entry (§ 2.3);compute sha256 over the exact stored bytes of each member, and write a member’s
size, when it writes one, as the uncompressed byte count of the member’s entry (§ 4.2);write
byte_order, when it writes it, as"little"(§ 2.2);write numeric fields in the units of § 4.3, and name every declared unit with a unit name of § 4.3;
write binary payloads matching the declared dtype and shape, little-endian;
ensure JSON members parse as UTF-8 JSON, and that every JSON member with a payload definition (§ 5) conforms to it;
write
pbcin everystructurepayload that carrieslattice_vectors, and keepdimensionality— if emitted at all — equal tosum(pbc)(§ 5.1);point every
structure_ref,run_refandtrajectory_refon a section at a section of the kind it names (§ 4.1, § 5.5), and likewise every reference of an excited-state calculation:wavefunction_ref,nto_ref,density_ref,states_refandexcited_states_ref(§ 5.12), every participant of areaction.scheme(§ 5.14) and everyrun.recordjob_ref(§ 5.8);write a structure’s
chargeandmultiplicityonly as values possible for its atoms, and equal to those ofprovenancein an archive with onestructuresection (§ 5.1);write the atom indices of a standalone
bondssection that carries astructure_refas atoms of the structure it names (§ 5.1);give every
previewmember itsmedia_type, and write an SVGimagethat references no external resource and contains no script (§ 5.15);declare each
x_<vendor>namespace in rootextensionswhen any section in that namespace iscritical: true;set
critical: trueonly when consumer support is truly required.
A conforming producer SHOULD include provenance when known; include
citations when results depend on citable methods/bases/functionals; prefer a
specific volume.* kind over volume.generic; use a vendor namespace for
experimental payloads; set structure_ref on every standalone bonds section
of an archive with several structures (§ 5.1); stay within the reference
resource limits of § 6.1; and run a validator on its own output in tests.
8.2 Consumer conformance¶
A conforming consumer MUST:
read
manifest.jsonby name, not by ZIP entry order, and use the entry whose central-directory record comes last when there are several (§ 2.3);ignore every ZIP entry the manifest does not reference: orphans and superseded manifests (§ 2.1, § 2.3);
sanity-check
qvf_version,source, andsections;verify sha256 before using a member’s bytes;
interpret only kinds it supports;
report unsupported vendor sections without corrupting or misinterpreting them;
respect declared dtype, shape, and units, reading a legacy unit spelling as the unit name it stands for (§ 4.3);
take per-axis periodicity from
pbc, and never draw, replicate along, or measure an extent from a lattice row whose axis is non-periodic (§ 5.1);read a payload’s atom indices against the structure named by the section’s
structure_refwhen the section has one, in preference to astructure_refinside the payload (§ 4.1), and the bonds of a standalonebondssection without one against the first structure (§ 5.1);find sections by kind and reference, never by a conventional id such as
structure, and open an archive with several structures, none of them namedstructure, showing its first structure (§ 4.1);open a file whose
viewer_defaultscarries a malformed or unknown hint, ignoring that hint (§ 3.4);render an SVG
previewmember, if at all, without running scripts or fetching external resources (§ 5.15);honor the per-section
criticalflag and the rootextensionscriticalflags, refusing to open when an unsupported extension is critical.
A conforming consumer SHOULD read an archive stamped qvf_version: 2 as
1 (§ 3.1), refuse an archive with duplicate ZIP entry
names other than manifest.json, refuse an archive whose byte_order is not
"little" (§ 2.2), and apply the § 6.1 resource limits before decompressing or parsing a
member (§ 2.1).
A consumer MAY require specific kinds for a given operation (a band plotter
may refuse a file without bands; a structure viewer may open it and ignore all
scalar fields).
9. Known open items (informative)¶
These are acknowledged limitations of v1, not defects:
Endianness tag. dtype names do not carry byte order. v1 archives are little-endian and may say so once, with the root
byte_order(§ 2.2); a per-dtype prefix such as<f8changes the dtype vocabulary and is a candidate for the next major version.k-resolved Bloch wavefunctions.
wavefunction.gtocovers molecular systems and the Γ-point; k-resolved orbitals over an atom-centred Gaussian basis are carried bywavefunction.bloch(§ 5.3.1), which is provisional until a second producer ships it. Not yet covered: k-resolved density matrices (the spin-density restart payload ofx_vibeqc.bloch_wavefunctionstays in that vendor section), two-component (spinor) Bloch orbitals, and Bloch orbitals over other bases such as plane waves or numeric atomic orbitals; producers may usex_<vendor>.*for those meanwhile.NMR and EPR schema tightening. The
spectra.nmrandspectra.eprpayloads are typed but permissive in v1 (§ 5.4): their known fields are checked and every object stays open until producer conventions settle.Fermi-surface meshes. v1 assumes a Γ-centered uniform Monkhorst-Pack grid.
Cartesian
wavefunction.gtoshells have little mileage. The convention is fully specified (Appendix A.1: oneN_iper shell, from the totall), butpure: falsehas far less cross-consumer mileage thanpure: true, and the per-component normalization trap described there has already been hit in practice — by the reference producer’s own two readers, which is how it was found. A producer can now make its archives checkable: with theoverlapmember (§ 5.3) every reference validator compares the stored diagonal with Appendix A.1 and reports ad_xyself-overlap of 1 rather than 1/3 asE_NORMALIZATION. The check covers producers only; a consumer that evaluates AOs still has to test its own evaluator on a Cartesian d shell (the corpus archiveswavefunction_cartesian.qvfandwavefunction_overlap.qvfcarry the numbers), because a spherical-only test will not catch the trap.QTAIM position unit. The ångström default for
topology.qtaimpositions (§ 5.7) is provisional pending a maintainer decision; producers should declareunits.position.Unit names of compound quantities. The unit vocabulary of § 4.3 names the units that QVF payloads declare today. It has no name yet for compound units such as an electron density (e·bohr⁻³), its Laplacian (e·bohr⁻⁵,
volume.laplacian), a reciprocal length (Å⁻¹) or a density of states (states·eV⁻¹), so such fields cannot be declared; their units are those of § 4.3 and the payload tables. A later revision may add names, which is an additive change.Two-dimensional drawings. v1 has no canonical kind for an editable drawing of molecules or of a scheme: the drawing formats in use (Ketcher’s KET, ChemDraw’s CDXML, the 2-D coordinates of an MDL molfile) are program-specific, and one producer writes drawings into QVF today. Such a drawing travels in its producer’s vendor section, as vibe-sketch’s
x_vibesketch.documentdoes. What a drawing means has canonical carriers: the identity of each species on itsstructuresection (§ 5.1), the scheme asreaction.scheme(§ 5.14) and the picture aspreview(§ 5.15).Reaction energies.
reaction.scheme(§ 5.14) reserves the step keyenergiesfor the energies of a step, to be specified when a producer computes them from the energies of the participants.
10. Governance and stewardship¶
QVF is an open standard. It was created by and is stewarded by the
vibe-qc project — that origin is explicit — but the format
is producer-neutral by design (§ 1) and its specification and reference
implementations are Apache-2.0, so any code may implement a conforming producer
or consumer, including a proprietary one, with no obligation back to vibe-qc.
vibe-qc’s own non-standard data lives under the x_vibeqc.* vendor namespace,
exactly like any other adopter’s.
The governance model, versioning policy, change process, and the
vendor→canonical promotion process are described in GOVERNANCE.md; the
machine-readable list of canonical kinds and registered vendor namespaces is in
registry.json (kept in lock-step with the schema). Stewardship is intended to
broaden as independent producers adopt the format.
Appendix A. AO ordering, primitive normalization, and component naming¶
A wavefunction.gto or wavefunction.bloch section is only correct if the
MO coefficients, the AO ordering, and the primitive normalization all agree with A.1–A.2 of this
appendix. This is the part most producers get subtly wrong. A.3 applies to
basis.ao, which names a single AO rather than ordering a whole matrix, and
depends on the same in-shell ordering.
A.1 Contraction and the normalization convention¶
Each contracted basis function is reconstructed as
χ(r) = Σ_i c_i · φ_i(r)
where each primitive φ_i is normalized as:
φ_i(r) = N_i · (x−A_x)^{l_x} (y−A_y)^{l_y} (z−A_z)^{l_z} · exp(−α_i r²)
N_i = (2 α_i / π)^{3/4} · (4 α_i)^{l/2} / √((2l − 1)!!), l = l_x + l_y + l_z
The coefficients c_i written into basis.json MUST apply to primitives
normalized exactly this way.
N_idepends only onl, not on(l_x, l_y, l_z). This matters for Cartesian shells, and it is deliberate:N_iis the normalization of the axial component(l, 0, 0)and is applied uniformly to the whole shell. It is what libint and libcint store, so a producer divides by one factor per primitive and is done.The consequence is that for
pure: falseshells the primitives are not individually unit-normalized. Only the axial components (x^l,y^l,z^l) have unit norm; a mixed component such asd_xydoes not. Concretely, for a single Cartesian d shell the overlap diagonal in this convention is⟨xx|xx⟩ = 1but⟨xy|xy⟩ = 1/3. A genuinely unit-normalized Cartesian Gaussian would divide by√((2l_x−1)!!(2l_y−1)!!(2l_z−1)!!)instead of√((2l−1)!!), which ford_xydiffers by a factor of√3.Consumers MUST NOT apply a per-component correction on top of
N_i. Doing so scales every mixed Cartesian AO by that factor and the resulting density is wrong by its square — a factor of 3 ford_xy. This is a real, observed failure mode, not a hypothetical one. Forpure: trueshells the question does not arise: the solid-harmonic transform absorbs it and the two conventions coincide, which is why the discrepancy can sit unnoticed in a spherical-only pipeline.
This is not a hypothetical warning. Both of vibe-qc’s AO evaluators shipped that per-component correction — its own
evaluate_aoand the vibe-view reader — while its writer divided byN_iexactly as specified. Writer and readers therefore disagreed by that factor onpure: falseshells, and nothing failed loudly, because spherical shells (everything a named basis produces) are unaffected. Both readers were corrected on 2026-08-05. If you are implementing a consumer, this is the single easiest thing here to get wrong, and a spherical-only test will not catch it.
The trap. Integral libraries such as libint and libcint (used by PySCF, and by many other codes including patterns ORCA developers will recognize from GBW-style storage) store contraction coefficients already pre-multiplied by
N_i— i.e. the stored coefficient isc_i · N_i, so it multiplies an un-normalized primitive. If your engine stores coefficients that way, you MUST divide each stored coefficient byN_ibefore writing it intobasis.json. Writing the engine-native (pre-scaled) coefficients produces orbitals that look plausible but are quantitatively wrong, especially for high-land tightly contracted shells.
Reference implementation of N_i (Python; the C++ toolkit has the identical
routine as qvf::primitive_norm):
import math
def primitive_norm(alpha: float, l: int) -> float:
radial = (2.0 * alpha / math.pi) ** 0.75
angular = (4.0 * alpha) ** (l / 2.0)
df = 1.0
for k in range(1, 2 * l, 2): # (2l-1)!!
df *= k
return radial * angular / math.sqrt(df)
Both reference writers expose a flag: pass your coefficients as-is if they are
already on N_i-normalized primitives, or ask the writer to divide by N_i
if they are libint/libcint-style. When in doubt, verify against a known orbital: the
HOMO of H₂O/STO-3G evaluated on a grid should integrate to ~1 electron per spin.
Better still, write the overlap member and let a validator check it, as
described next.
Verifying with overlap¶
The self-overlap of every AO follows from basis.json alone. For a shell of
angular momentum l with exponents α_i and coefficients c_i, the
self-overlap of its axial component (l, 0, 0) is
S_axial = Σ_i Σ_j c_i c_j · ( 2 √(α_i α_j) / (α_i + α_j) )^(l + 3/2)
which is Σ_ij c_i c_j N_i N_j ⟨x^l e^(−α_i r²) | x^l e^(−α_j r²)⟩ with the
N_i above folded in. The diagonal of the AO overlap matrix, at the AO index
of each component of the shell (A.2), is then:
spherical shell:
S_axialfor everym, because a real solid harmonic built onN_i-normalized primitives is normalized like the axial component;Cartesian shell:
S_axial · (2l_x−1)!! (2l_y−1)!! (2l_z−1)!! / (2l−1)!!for the component(l_x, l_y, l_z):S_axialfor an axial component,S_axial / 3ford_xy,S_axial / 5forf_xxy,S_axial / 15forf_xyz.
A contraction normalized in the usual way has S_axial = 1, so the diagonal
is 1 for every spherical AO and every axial Cartesian AO, and 1/3 for d_xy.
A wavefunction.gto section may carry the overlap matrix its producer
computed with its own integral code (the overlap member, § 5.3), and
producers SHOULD write it. A validator then computes the values above from
basis.json and compares each with the stored diagonal at that AO’s index,
to a relative tolerance of 1e-6. A disagreement is the error
E_NORMALIZATION (Appendix B): the coefficients in basis.json are not
on N_i-normalized primitives (the libint/libcint trap above), a
per-component correction has been applied to a Cartesian shell (a d_xy
diagonal of 1 rather than 1/3), or the AO order disagrees with A.2. The check
sees the diagonal only, so it cannot tell apart the components of a spherical
shell, whose diagonal entries are all equal: a permutation of m within a
spherical shell passes it.
This is the most valuable interoperability check the format has. The
normalization trap produces orbitals that look plausible and are wrong; with
overlap in the archive it fails validation at write time instead.
A.2 AO ordering within a shell¶
AO order is part of the contract and MUST match the pure flag:
Spherical (
pure: true): functions are orderedm = −l, −l+1, …, +l.Cartesian (
pure: false): libint lexicographic ordering of(l_x, l_y, l_z)withl_x + l_y + l_z = l, decreasingl_xfirst, thenl_y.
The row/column index of an AO in mo_coefficients is its position in the
concatenation of all shells (shell order = shells array order), each shell
contributing 2l+1 (spherical) or (l+1)(l+2)/2 (Cartesian) functions.
If your engine uses a different in-shell order (common differences: p as
x,y,z vs m = −1,0,+1; d as xx,yy,zz,xy,xz,yz vs m = −2…+2), you
MUST permute the coefficient rows into QVF order before writing.
A.3 Naming a single component (basis.ao)¶
A basis.ao section carries one component of one shell, so its
ao_metadata has to name which — and the two shell kinds above are named
differently:
Spherical (
pure: true):angular_momentumis[l, m]withm ∈ [−l, +l], the harmonic’s own index under the A.2 ordering.Cartesian (
pure: false): there is no magnetic quantum number. The component is named bycartesian_powers, the[l_x, l_y, l_z]of the monomial, so a d shell’s six components are[2,0,0] … [0,0,2]in the A.2 order.angular_momentum[1]is then0by convention and carries no meaning.
cartesian_powers is present if and only if the component is Cartesian,
and l_x + l_y + l_z MUST equal angular_momentum[0]. A consumer
therefore reads l from angular_momentum[0] for either kind, but MUST
NOT read angular_momentum[1] as an m when cartesian_powers is
present — [2, 0] on a Cartesian d component does not mean d_z².
The trap. Deriving
mas component index −lis correct for a spherical shell and wrong for a Cartesian one, where it runs past+l: a Cartesian d shell comes out asm = −2 … +3over its six components. A producer that emitsbasis.aofor Cartesian shells MUST branch on the shell’spureflag.
cartesian_powers is an optional member added under v1 — the additive case
per GOVERNANCE.md, so there is no qvf_version bump, and a spherical-only
producer is unaffected.
Appendix B. Validation finding codes (informative)¶
Stable identifiers for the findings of § 6. A code is never renamed or
reused; a new check gets a new code. Messages are free text for people; tools
match on the code. The Python reference validator (python/qvf_reader.py),
the C++ reference validator (qvf::QvfReader::validate_findings) and the
JavaScript validator (@qvf/core) emit these codes. All three run the JSON
Schema check: Python through jsonschema, C++ and JavaScript through the
checker generated from the schema (scripts/gen_kinds.py). A validator that
runs without the check (jsonschema missing, or the check disabled) reports
W_SCHEMA_SKIPPED instead of E_SCHEMA / E_PAYLOAD_SCHEMA.
A finding is {severity, code, where, message}. where locates it:
archive (the ZIP as a whole), entry:<name> (one ZIP entry),
manifest.json (the manifest document as a whole), or a JSON Pointer
(RFC 6901) into manifest.json, such as /sections/2/members/data. A
finding about a member’s payload points at the member spec that declares it.
Code |
Severity |
Rule |
Meaning |
|---|---|---|---|
|
error |
§ 2.1 |
The archive is not a readable ZIP, or an entry cannot be decompressed (corrupt data, CRC mismatch, unsupported method, data that does not inflate to its recorded size). |
|
error |
§ 2.1, § 2.3 |
Two or more ZIP entries share a name other than |
|
error |
§ 2.1 |
A ZIP entry name or a member |
|
error |
§ 6.1 |
An entry’s uncompressed size exceeds the per-member cap; it is not decompressed. |
|
error |
§ 6.1 |
The entries’ total uncompressed size exceeds the total cap; no member payload is decompressed. |
|
error |
§ 6.1 |
An explicitly enabled application ratio policy rejects a compressed entry; it is not decompressed. Disabled by default; not a format validity rule. |
|
warning |
§ 2.1, § 2.3 |
A ZIP entry, other than the current |
|
error |
§ 2.1 |
There is no |
|
error |
§ 3 |
|
|
error |
§ 6.1 |
|
|
error |
§ 6.1 |
|
|
error |
§ 6 |
|
|
warning |
§ 6 |
The validator could not run the JSON Schema check; the semantic checks still ran. |
|
error |
§ 3.1 |
|
|
warning |
§ 3.1 |
|
|
error |
§ 3.1 |
|
|
error |
§ 4.1 |
|
|
error |
§ 4.1 |
Two sections share an |
|
error |
§ 3.1, § 3.4 |
A section |
|
error |
§ 7.3 |
A |
|
error |
§ 7.4 |
A |
|
error |
§ 4.2, § 5.1, § 5.2, § 5.3, § 5.3.1, § 5.5, § 5.6, § 5.7, § 5.10, § 5.11, § 5.12, § 5.13, § 5.14, § 5.15 |
A member spec is not an object or has no string |
|
error |
§ 4.2 |
A declared member |
|
error |
§ 4.2 |
A member’s bytes do not match its |
|
error |
§ 4.2 |
A JSON member is not UTF-8 JSON. |
|
error |
§ 4.2 |
A binary member’s |
|
error |
§ 4.2 |
A binary member’s byte length differs from |
|
error |
§ 5.8, § 5.15 |
A |
|
error |
§ 6 |
A JSON member violates the payload definition (§ 5) of its section kind and role (one finding per schema error), or a one-dimensional spectrum’s arrays differ in length (§ 5.4). |
|
error |
§ 5.1 |
A |
|
error |
§ 5.1 |
A |
|
error |
§ 4.1, § 5.2, § 5.3.1, § 5.4, § 5.5, § 5.8, § 5.9, § 5.10, § 5.11, § 5.12, § 5.14 |
A |
|
error |
§ 5.8 |
A |
|
warning |
§ 4.3 |
A declared unit is not a unit name: a value of a payload’s |
|
error |
§ 3.6, § 5.1, § 5.3, § 5.13 |
Two statements of the same quantity differ: an energy of |
|
error |
§ 5.3, Appendix A.1 |
The diagonal of a |