Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

RustiQ is an experimental Rust quantum chemistry application and reusable rustiq-chem-core library. This manual serves scientific users, Rust contributors, and theoretical chemists.

Do not use RustiQ results for research conclusions without independent validation against established quantum chemistry packages.

Choose TOML for a single calculation or optional Nickel for parameterized studies. Both formats share the same defaults and validation; see calculation inputs and execution for how an input becomes a result.

Where should I start?

The glossary explains unfamiliar scientific and software terms. Existing workflow notes preserve useful operational guidance alongside the user guides and CLI reference.

Implemented capabilities include RHF, UHF, MP2, XYZ geometries, Gaussian basis sets, TOML and native Nickel input, sequential studies, and versioned JSON. The practical user guides now cover these capabilities, including HF/MP2 calculations, Nickel studies, JSON output, and portable calculation bundles. The command-line reference describes the shipped commands and options.

Portable .rustiq bundles can be written, reused, and inspected from the CLI as well as through Rust APIs. Start with the portable bundle guide for a runnable CLI workflow, then see the persistence specification for the archive contract. The authoritative references page links to the roadmap for plans and to the files that define existing contracts.

Installation

Install with Nix

See installing with Nix for the supported platforms, profile installation, and CPU-specific builds.

Install a prebuilt release binary

When a release is available, ordinary users can download the archive for their operating system and CPU from the GitHub Releases page. Archives are named rustiq-chem-<target>.tar.gz on Unix and rustiq-chem-<target>.zip on Windows. Supported targets are x86_64-unknown-linux-gnu (Linux Intel/AMD), aarch64-unknown-linux-gnu (Linux ARM64), x86_64-apple-darwin (Intel macOS), aarch64-apple-darwin (Apple Silicon), x86_64-pc-windows-msvc (Windows Intel/AMD), and aarch64-pc-windows-msvc (Windows ARM64). Linux GNU archives require a compatible glibc runtime.

RustiQ-authored code is MIT OR Apache-2.0. Executables include LGPL libraries, third-party notices and a matching corresponding-source archive on the same release page. See licenses and redistribution for source access, rebuilding and package redistribution requirements.

Verify and run the executable

Download the release’s sha256.sum beside the archive chosen for your platform. You do not need the archives for other platforms. Copy only the matching line from sha256.sum into a new text file named selected.sha256, preserving both the hash and filename. On Linux or macOS, verify it before extracting:

sha256sum --check selected.sha256  # Linux
shasum -a 256 --check selected.sha256  # macOS

On Windows, use PowerShell to compare the downloaded archive’s computed hash with its matching entry in sha256.sum:

$archive = "rustiq-chem-x86_64-pc-windows-msvc.zip"
$entries = @(Select-String -Path .\sha256.sum -SimpleMatch $archive)
if ($entries.Count -ne 1) { throw "Expected one checksum entry for $archive" }
$expected = ($entries[0].Line -split '\s+')[0]
$actual = (Get-FileHash ".\$archive" -Algorithm SHA256).Hash
if ($actual -ine $expected) { throw "SHA-256 mismatch for $archive" }
Write-Host "SHA-256 verified: $archive"

The release guide has the full platform-specific verification instructions. For Windows ARM64, replace the archive filename with rustiq-chem-aarch64-pc-windows-msvc.zip. Extract the archive only after the checksum comparison succeeds, then run ./rustiq --help from its directory on Linux or macOS, or .\rustiq.exe --help from that directory in PowerShell. To use rustiq from any directory, add the directory containing rustiq or rustiq.exe to PATH and open a new terminal.

The Cargo package is named rustiq-chem; the executable is named rustiq (or rustiq.exe on Windows).

Consult the manual

Release archives contain an offline HTML manual in manual/html/ beside the executable. Keep that directory with the executable when moving the extracted installation. The Nix package installs the same offline manual under share/doc/rustiq/manual/html. Navigation, styling, equations, and diagrams use local resources; external reference links require network access.

rustiq docs
rustiq docs --web
rustiq docs --print-path

rustiq docs opens the installed manual in the default browser using a browser-specific launcher, independently of HTML file associations. --web forces the online manual for the compiled release version; development builds use the development manual. The choice is made from the Cargo package version without a network lookup. Versions with a complete dev prerelease identifier, such as 0.1.0-alpha.1.dev, select /dev/. Other versions, including alpha and beta releases, select /vVERSION/. This applies equally to Cargo, Nix, and release archives, without packaging flags. A release-version source build selects its versioned manual even before publication. --print-path prints the absolute local index path without starting a browser; combine it with --web to print the online URL instead. On headless machines, copy the manual tree to another machine and open its index.html, or use the printed URL in a browser with network access.

Cargo-only installations have no bundled manual: rustiq docs opens the online manual and --print-path prints its URL. RustiQ does not download the manual. An existing manual directory with a missing index produces an error; restore the complete installation or use --web. If the whole manual directory has been removed, RustiQ cannot distinguish the installation from a Cargo install and uses the online manual.

If browser launching fails, the diagnostic includes the target and the --print-path route. RustiQ uses the operating system’s default browser opener. PDF export is future work and --pdf is not supported.

Make basis sets available

The archive contains neither sample inputs nor basis data. With network access, download a basis using rustiq basis download sto-3g. This command is available in online builds and requires network access. To work offline, import a local Basis Set Exchange JSON file with rustiq basis import /path/to/basis.json; import does not access the network. See the basis-set guide and the first calculation for a complete binary-only example.

Build and install from source

Contributors and users building from a checkout need Git, Rust through rustup, a C/C++ build toolchain, and CMake. Clone from a parent directory, then run Cargo commands from the checkout root. For complete prerequisite and platform details, see the manual setup.

git clone https://github.com/mveril/RustiQ.git
cd RustiQ
cargo build --locked

cargo build does not add the executable to PATH. To run without installing, prefix commands with cargo run --locked --, for example cargo run --locked -- --help. To install the package executable into Cargo’s binary directory:

cargo install --locked --path .
rustiq --help

The registry package is also named rustiq-chem; install from crates.io only when the relevant version has been published. See the development environments page for Nix, Docker, and other supported contributor setups.

Installing with Nix

Install Nix and enable the nix-command and flakes experimental features. The flake supports x86-64 Linux, ARM64 Linux, and Apple Silicon macOS. On Windows, use Nix inside WSL2 to run the Linux package. See Nix setup for enabling flakes and platform prerequisites. The first install needs network access and may compile dependencies. Install the standard package from any directory with:

nix profile install github:mveril/RustiQ
rustiq --version

Home Manager without a configuration flake

If your Home Manager configuration uses home.nix directly, create a rustiq.nix file beside it:

{ pkgs, ... }:
let
  rustiq = builtins.getFlake "github:mveril/RustiQ";
in
{
  home.packages = [
    (rustiq.legacyPackages.${pkgs.stdenv.hostPlatform.system}.cpuTarget "native")
  ];
}

Add the module to the imports in home.nix, keeping any existing imports:

imports = [ ./rustiq.nix ];

Apply the configuration using your usual command. For Home Manager integrated as a NixOS module, run sudo nixos-rebuild switch --impure; for standalone Home Manager, run home-manager switch --impure. The unlocked GitHub reference requires impure evaluation. Check rustiq --version afterward. The reference tracks the default branch and is not pinned by a configuration flake.lock; use a revision in the URL for a fixed version. See the CPU-specific build caveats before using native. To use the standard package, replace the entry in home.packages with rustiq.packages.${pkgs.stdenv.hostPlatform.system}.default.

Home Manager and NixOS

The following snippets extend an existing flake-based configuration. Add RustiQ as an input to your configuration’s flake.nix:

inputs.rustiq.url = "github:mveril/RustiQ";

The configuration’s flake.lock pins that input. To update it later, run nix flake update rustiq in the configuration directory, then apply the configuration again. Keep your existing inputs, modules, and state version. If the configuration is a Git flake, add any newly created module files to Git before applying it so that Nix can see them.

Home Manager

In the existing outputs function, bind the inputs as inputs@{ ... }, and pass them to your existing home-manager.lib.homeManagerConfiguration:

extraSpecialArgs = { inherit inputs; };

Merge this with any existing extraSpecialArgs. In your home.nix, add inputs to the module arguments and add RustiQ to home.packages:

{ pkgs, inputs, ... }:
{
  home.packages = [
    inputs.rustiq.packages.${pkgs.stdenv.hostPlatform.system}.default
  ];
}

Merge the list with your existing packages. From your configuration directory, apply it with home-manager switch --flake .#YOUR_USER and check rustiq --version. Replace YOUR_USER with your Home Manager configuration name. See the Home Manager flake guide. For Home Manager as a NixOS module, pass the inputs through home-manager.extraSpecialArgs instead.

NixOS configuration.nix

In the existing outputs function, bind the inputs as inputs@{ ... }, and pass them to your existing nixpkgs.lib.nixosSystem:

specialArgs = { inherit inputs; };

Merge this with any existing specialArgs. Create rustiq.nix beside your configuration.nix. This complete NixOS module installs a RustiQ build optimized for the build machine’s CPU:

# NixOS module: provide the RustiQ flake through specialArgs.inputs.
{ pkgs, inputs, ... }:
{
  environment.systemPackages = [
    (inputs.rustiq.legacyPackages.${pkgs.stdenv.hostPlatform.system}.cpuTarget "native")
  ];
}

Then import it in the existing configuration.nix, preserving any other imports:

{ ... }:
{
  imports = [ ./rustiq.nix ];
}

Alternatively, add ./rustiq.nix to the modules list in nixosSystem. See the CPU caveats below before using native. To use the standard package, replace the expression inside the list with:

inputs.rustiq.packages.${pkgs.stdenv.hostPlatform.system}.default

From the configuration directory, apply it with sudo nixos-rebuild switch --flake .#YOUR_HOST and check rustiq --version. Replace YOUR_HOST with your NixOS configuration name. See the NixOS package management guide.

Optional CPU-specific build

The NixOS module above uses this expression. For Home Manager, you can also replace the standard package entry in home.packages with it:

(inputs.rustiq.legacyPackages.${pkgs.stdenv.hostPlatform.system}.cpuTarget "native")

For a profile installation from any directory, use one command instead:

nix profile install --impure --expr '(builtins.getFlake "github:mveril/RustiQ").legacyPackages.${builtins.currentSystem}.cpuTarget "native"'

List compiler CPU names with rustc --print target-cpus (for example inside nix develop github:mveril/RustiQ#rust). native selects the build machine’s CPU, which may differ from the machine running RustiQ when using remote builders. Its detected CPU is not recorded in the Nix build identity: cached results may have been built for a different CPU. For reproducible builds or deployment across machines, replace native with a compatible explicit CPU name such as znver3. A binary may fail on machines with fewer processor features. This setting applies to Rust-compiled code and does not promise optimization of every native dependency. The --impure flag allows the command-line expression to obtain the current system and resolve the unlocked GitHub reference.

Build from a checkout

From the root of a RustiQ checkout, build the default package and run it without adding it to your profile:

nix build
./result/bin/rustiq --version

The package includes the offline manual and shell completions. Run rustiq docs after installing, or ./result/bin/rustiq docs from the checkout. See the manual instructions and the Nix package guide.

The package enables online basis downloads but does not bundle sample inputs or basis sets. Download or import a basis before running a calculation; see make basis sets available and the first calculation. For development shells, see Nix setup.

First H₂ calculation

Using only the release binary

Copy the following geometry into a file named h2.xyz in your working directory. It is the same geometry used by the checked-in sample:

2
Hydrogen molecule
H 0.0 0.0 -0.37
H 0.0 0.0  0.37

The explicit download is needed because run does not fetch missing bases unless --auto-download or RUSTIQ_AUTO_DOWNLOAD enables downloading. Use --no-auto-download to explicitly prevent it. The release archive contains neither sample inputs nor basis files. To use an existing local basis file without network access, import it with rustiq basis import /path/to/basis.json.

Create an input, download STO-3G, and run the calculation:

rustiq init h2.xyz -o calculation.toml
rustiq basis download sto-3g
rustiq run calculation.toml

Tip

With an online-enabled build and network access, you can replace the separate download and run commands with rustiq run calculation.toml --auto-download to fetch a missing basis.

Reproducing the sample configuration without a checkout

The checked-in configuration is included directly:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf.guess]
type = "CoreHamiltonian"

You can also copy this configuration without a checkout: save the geometry shown above as molecule.xyz in a new working directory, create an inputs directory with mkdir inputs, and save the TOML as inputs/h2.toml. After obtaining STO-3G as described above, run rustiq run inputs/h2.toml. The ../molecule.xyz path resolves relative to the runfile directory. This is an alternative to the init workflow; keep using calculation.toml from that workflow in subsequent guides.

Using the checked-in sample

From a source checkout, run these commands from the repository root to import the checked-in fixture and run the example without installing RustiQ:

cargo run --locked -- basis import tests/data/sto-3g.json
cargo run --locked -- run samples/h2/sto-3g/calculation.toml

CLI tests import the same fixture into an isolated store.

Verifying the calculation

Default input units are Angstrom; resolved coordinates are Bohr. The neutral singlet defaults resolve HF Auto to RHF. The core-Hamiltonian guess makes this example deterministic.

The following verification commands are for users working from a source checkout; they are optional when using only the release binary. The existing CLI regression test checks this input, RHF resolution, units, two SCF iterations, and these selected output lines. Its reproducible command is below; the test source is linked for readers who want to inspect its assertions.

CLI test source on GitHub

SCF converged after 2 iterations.
Total Energy (including nuclear repulsion): -1.116759 Hartree

Run that verification with:

cargo test --locked --test cli_samples test_cli_h2_sample_converges_and_prints_reference_energy

For independent numerical verification, the h2-sto-3g-rhf case compares full precision JSON energies against PySCF with a 2e-10 Hartree energy tolerance. The rounded terminal value above is not that tolerance. See the book’s scientific scope and reference comparisons for the coverage boundary. The comparison implementation and full reference instructions are linked below.

Comparison source on GitHub

Reference test instructions on GitHub

Reproducing this comparison requires the cloned repository and its Nix development environment (or the documented uv/PySCF setup); the binary archive alone does not include the reference harness.

nix run .#pyscf-check -- -k 'h2-sto-3g-rhf and not mp2'

These checks validate this case, not arbitrary chemistry. Results remain experimental and require independent validation before research use. Continue with output interpretation. To save and reuse the calculation’s AO ERIs, continue with the portable bundle guide.

Explore more calculations and workflows in the examples index.

Interpreting output

The standard run report has three visible parts:

  • Requested options: a canonical TOML representation of the requested calculation and a canonical XYZ representation of its input geometry. These show the options after parsing and normalization; they do not reproduce the original source text or comments.

  • Resolved settings: a concise summary of the scientific setup used for the calculation, including atom count, charge, multiplicity, coordinate units, resolved HF method, and basis name and size.

  • Numerical results: SCF convergence information, energy values, overlap rank, energy components, and timings. The H₂ sample’s total HF energy is reported as -1.116759 Hartree. The first sample resolves to neutral singlet H₂, RHF, STO-3G, and two basis functions. Input coordinates are Angstrom; resolved coordinates are Bohr. Energies are in Hartree.

  • Electronic energy: electronic kinetic energy, electron–nuclear attraction, and electron–electron interaction at the HF level.

  • Nuclear repulsion energy: repulsion between the fixed nuclei.

  • Total HF energy: electronic energy plus nuclear repulsion.

  • SCF convergence: the iterative solution met its configured criterion. This does not establish basis completeness or accuracy against experiment.

With colors enabled, section titles are cyan, successful SCF convergence is green, and displayed energy values are yellow. The same energy-value styling is used for HF iteration values, energy components, and MP2 energies; residuals and other diagnostics remain uncolored. The Calculation heading follows the same title styling. TOML and XYZ use syntax highlighting.

The original TOML and XYZ source text, along with full canonical views of the resolved configuration and geometry, are retained as internal representations; the standard CLI report does not display them.

Portable bundles can retain the scientific input snapshots and AO ERIs for later inspection and compatible reuse. They do not save the energies or the HF wavefunction; see portable calculation bundles.

Convergence and overlap diagnostics

Both RHF and UHF require delta_energy and residual_norm to be below method.hf.convergence_threshold (default 1e-8). delta_energy is the absolute change in electronic energy between successive iterations, in Hartree. residual_norm is the Frobenius norm of the AO matrix residual \(FPS - SPF\), where \(F\), \(P\), and \(S\) are the Fock, density, and overlap matrices. UHF combines the alpha and beta norms as \(\sqrt{r_\alpha^2 + r_\beta^2}\). The same numerical threshold is applied to both diagnostics; it is not an error bound on the final energy.

Final canonicalization also checks that orbitals obtained from the final Fock matrix reproduce the occupied density within that threshold. Further density updates consume the remaining SCF iteration budget; failure to obtain consistent orbitals is a numerical error. RHF additionally requires an unmixed orbital density before accepting convergence.

Overlap effective rank is the number of retained independent basis directions. With method.hf.orthogonalization.linear_dependency_threshold = t, eigenvectors of the overlap matrix are retained only when their eigenvalue exceeds \(t\lambda_{\max}\). The default is 1e-8. A report of 9/10 means one direction was discarded, reducing the orbital space used by HF and MP2. Increasing this threshold can change energies. Setting it to zero retains all directions only if the overlap matrix is strictly positive definite.

Inspect both convergence diagnostics and the retained rank when comparing calculations. See the Nickel schema for input defaults and the scientific limitations for the interpretation of a converged solution.

The first-calculation test checks the rounded total energy of -1.116759 Hartree. The independent comparison uses full precision.

MP2 adds a correlation energy to a converged HF reference. This first sample does not request MP2. The checked-in MP2 sample is included here so the manual shows the exact runnable input:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf]
method = "Rhf"

[method.hf.guess]
type = "CoreHamiltonian"

[method.mp2]
frozen_orbitals = 0

MP2 sample source on GitHub

Its h2-sto-3g-rhf-mp2 PySCF comparison provides executable evidence for the MP2 guide; see the book’s reference comparison coverage.

A successful small-basis H₂ test does not validate every molecule, basis, open-shell state, or chemical prediction. Review the book’s scientific limitations. The full reference-test instructions remain available on GitHub.

Examples

This curated selection introduces introductory and representative workflows; it is not an exhaustive catalog. See the repository’s samples directory for additional molecules and advanced configurations. Those files require a source checkout and are not bundled with release archives.

These guides use the installed rustiq executable. Basis sets are not distributed with RustiQ: download them explicitly, or import independently obtained JSON files with rustiq basis import /path/to/basis.json when offline. Automatic downloads must be enabled explicitly with --auto-download or RUSTIQ_AUTO_DOWNLOAD; --no-auto-download prevents them. See basis availability for offline and online builds.

Example and objectiveBasisGuide and prerequisites
H₂ / RHF: first calculationSTO-3GFirst calculation; create the XYZ file and obtain the basis.
OH / UHF: open-shell calculationSTO-3GHartree–Fock; create the OH geometry and obtain the basis.
H₂ / RHF-MP2: electron correlationSTO-3GMP2; first create H₂ as in the first calculation.
OH / UHF-MP2: open-shell correlationSTO-3GOpen-shell MP2; create OH as in the HF guide.
Inspect and transform XYZ geometryNoneGeometry; create an XYZ file.
Parameterized and batch studiesSTO-3G and 6-31GNickel studies; obtain both bases. No separate Nickel executable is needed.
Create, inspect, verify and rerun bundles; reuse AO ERIsSTO-3GPortable bundles; first prepare the H₂ input and basis.

Calculation inputs and execution

RustiQ offers two complementary input formats. TOML is the simple choice for one calculation: a small, readable file is enough, and users do not need to learn Nickel.

Nickel is optional for calculation studies. Its imports, functions, and list operations can generate related configurations—for example, varying basis sets or numerical settings without duplicating full input files. Nickel can also describe one calculation.

Both formats pass through the same embedded Nickel contracts for defaults, validation, and normalization. The normalized configurations then enter the same Rust scientific core, which has no dependency on TOML or Nickel. Users do not need to install the Nickel executable: RustiQ embeds the configuration evaluator.

---
config:
  flowchart:
    htmlLabels: false
---
flowchart TD
    TOML["`TOML (.toml)
One calculation`"]
    NICKEL["`Nickel (.ncl)
One or more calculations`"]
    CONTRACTS["`Shared Nickel contracts
Defaults, validation, normalization`"]
    INPUTS["Resolved scientific configurations"]
    CORE["`rustiq-chem-core
Runs scientific calculations`"]
    RESULTS["Single result or ordered batch results"]

    TOML --> CONTRACTS
    NICKEL --> CONTRACTS
    CONTRACTS --> INPUTS
    INPUTS --> CORE
    CORE --> RESULTS

Choose the TOML calculation guide for one calculation or Nickel studies for a parameterized campaign. Studies execute sequentially, not as a parallel job scheduler.

Geometry files

Examples in this chapter that use samples/ or tests/data/ require a cloned repository and should be run from its root. Release binaries do not include those files; the first-calculation guide shows how to create local inputs and obtain a basis.

RustiQ reads molecular coordinates from XYZ files. Each file starts with the number of atoms, then a comment line, then one line per atom containing an element symbol or atomic number and three Cartesian coordinates. See the checked-in H₂ example:

2
Hydrogen molecule
H 0.0 0.0 -0.37
H 0.0 0.0  0.37

Tip

Element symbols and atomic numbers are interchangeable. Each atom line may use either an element symbol, such as H, or its atomic number, such as 1. Both forms identify hydrogen; this book uses symbols consistently for readability.

The atom count must not exceed the number of atom lines present in the file. RustiQ reports a geometry parse error when the count and available lines do not match, including when the count is too large to represent the supplied geometry.

RustiQ treats the coordinates as Angstrom by default; TOML can specify Bohr. The coordinates in XYZ do not specify molecular charge, spin multiplicity, or units. Those are calculation settings. A charge changes the electron count; multiplicity specifies the intended spin state. RustiQ checks that the electron count and multiplicity have compatible parity, but this check does not identify the physical ground state. See the configuration guide.

Calculations convert between Bohr and Angstrom using the 2018 CODATA Bohr radius published by NIST: 5.29177210903e-11 m, multiplied by 1e10 to obtain Angstrom per Bohr. RustiQ keeps this edition to preserve existing numerical results. The conversion regression can be run with cargo test -p rustiq-chem-core conversion_preserves_the_2018_codata_factor; it checks the exact floating-point result for one Bohr.

geometry info reports atom and center information, including a nuclear repulsion value. The calculation returns an error if any two atoms have exactly identical coordinates, because their nuclear repulsion is undefined.

Warning

Nuclear repulsion: beware of XYZ coordinate units.

geometry info does not convert coordinates from Angstrom to Bohr. XYZ files have no unit metadata, so this command evaluates nuclear repulsion directly from the supplied numbers, effectively treating them as Bohr. For an XYZ file written in Angstrom (including the H₂ sample below), its reported nuclear-repulsion value is not a physically meaningful energy in Hartree. Do not interpret or compare it with energies from a molecular calculation.

Unlike geometry info, rustiq run converts input coordinates using [molecule].units (default: "Angstrom") before computing energies. This setting does not apply to the standalone geometry command.

With only the release binary, save this geometry as h2.xyz as shown in the first-calculation guide. After reading the units warning above, inspect or transform the local file with:

rustiq geometry info h2.xyz
rustiq geometry translate h2.xyz --dz 1 -o h2-shifted.xyz

From the repository root, inspect a geometry with:

rustiq geometry info samples/h2/molecule.xyz

The geometry tools can rotate, translate, center, or orient XYZ coordinates. For example, transformations read and write XYZ and can use standard input/output:

rustiq geometry translate samples/h2/molecule.xyz --dz 1

These are coordinate transformations. They do not change coordinates to minimize molecular energy and are not geometry optimization. Standalone XYZ tools do not convert coordinate units; they have no unit metadata. Transformations change coordinate values, and written XYZ coordinates are rounded to six decimal places. Use the runfile’s units setting to tell a calculation how to interpret its coordinates.

Mass centering and principal-axis orientation use atomic weights from mendeleev: interval-valued weights use the conventional value, uncertain weights use the central value, and elements without a standard weight use the mass number of the most stable isotope. Consequently, these transformations can produce slightly different coordinates than versions that used a different periodic table dataset. In the Rust core API, Atom stores mendeleev::Element by value. The core crate re-exports this type as rustiq_core::Element, so a downstream crate can construct hydrogen atoms with rustiq_core::Element::H without declaring its own direct mendeleev dependency. The same element type supplies atomic numbers for electronic-structure calculations and atomic weights for geometry operations. The core methods for mass centering, inertia tensors, and principal-axis orientation return their values directly without an atomic-weight error.

For a TOML calculation, the geometry path is relative to the TOML file’s directory. init can create a TOML file that refers to an XYZ file without copying it:

rustiq init samples/h2/molecule.xyz -o calculation.toml

Run commands from the repository root. The relevant executable checks are in tests/cli_samples.rs and tests/init_cli.rs. Geometry parsing and the transformations themselves are implemented in crates/rustiq-core/src/molecules/geometry.rs and src/cli/commands/geometry_command/.

The core Geometry::nucl_repulsion API returns a dedicated NuclearRepulsionError::CoincidentAtoms for coincident nuclei. It traverses atom pairs without allocating an intermediate collection.

Continue with basis sets, then configuration.

Gaussian basis sets

A basis set is a finite collection of functions used to represent molecular orbitals. RustiQ’s Gaussian basis functions are built from Gaussian functions centered on atoms. The chosen basis affects the size of the orbital space and the numerical result. A small basis such as STO-3G is useful for examples but does not guarantee accurate energies or properties.

Import or download a basis

basis import reads a Basis Set Exchange JSON file from the path you provide. It works with the release binary and does not require Cargo or a source checkout. For example, if sto-3g.json is in the current directory:

rustiq basis import sto-3g.json
rustiq basis list

The import itself is local and needs no network access; you must obtain the JSON file separately. On a connected computer, choose a basis and JSON format from the Basis Set Exchange, download the file, and transfer it to the calculation computer if needed. Then import it with the executable command above. In a source checkout, the checked-in STO-3G fixture is available at tests/data/sto-3g.json, and the sample calculation is at samples/h2/sto-3g/calculation.toml:

rustiq basis import tests/data/sto-3g.json
rustiq run samples/h2/sto-3g/calculation.toml

The test suite exercises the fixture using an isolated store in tests/cli_samples.rs and basis import/storage behavior in crates/rustiq-core/src/basis/basis_store.rs.

List, import, or remove locally stored bases with:

rustiq basis list
rustiq basis import /path/to/basis.json
rustiq basis remove sto-3g

The default store is in the platform’s application data directory. Set RUSTIQ_DATA_BASIS to choose its exact path, or RUSTIQ_DATA_HOME to choose the data root. The CLI guide in existing workflows lists platform paths and migration notes.

Online workflow

The default CLI build enables the online feature. Use it to list or download bases:

rustiq basis list --online
rustiq basis download sto-3g

Online commands require network access. A normal run uses the local basis store; automatic downloading can be enabled with --auto-download, disabled with --no-auto-download, or set using RUSTIQ_AUTO_DOWNLOAD. Builds without the online feature can import, list local files, and remove bases but cannot download or query online listings. The commands reflect the CLI tests in tests/cli_samples.rs.

Supported input features

Basis files are imported in the Basis Set Exchange JSON form. A shell groups functions with the same center and angular momentum: \(l=0,1,2\) denote s, p, and d functions. Cartesian and spherical describe two function forms that differ in how angular dependence is represented. For elements used by a molecule, the current loader accepts Gaussian-type and Cartesian Gaussian shells through angular momentum \(l=15\), and spherical Gaussian shells through \(l=2\). It rejects Slater-type shells and effective core potentials (ECPs). Higher angular momentum or other basis-file features should not be assumed to work just because a basis is downloadable. This describes loader support, not numerical validation of all those cases. The checks are in basis.rs.

During basis construction, RustiQ normalizes each Cartesian primitive using its three angular momentum components, then normalizes the contraction for its shell. Spherical functions are formed from normalized Cartesian components. The imported contraction coefficients therefore set the relative primitive weights; their overall scale does not set the resulting function norm. A coefficient group that cancels to the zero function, or whose computed norm is not finite and positive, is rejected with a shell and coefficient-group diagnostic. Contractions that cannot be normalized reliably and unrepresentable normalized primitive coefficients are also rejected. The contraction norm is checked again after normalization; an absolute deviation from unity of \(10^{-6}\) or greater causes rejection. These safeguards do not establish support for arbitrary extreme exponents throughout the integral engine.

Basis choice is one part of a calculation’s accuracy. Convergence, independent agreement, basis quality, and physical validity are distinct checks; see scientific scope. See the glossary for shared basis vocabulary.

Next: TOML configuration.

TOML calculation configuration

Examples in this chapter that use samples/ or tests/data/ require a cloned repository and should be run from its root. Release binaries do not include those files; the first-calculation guide shows how to create equivalent local inputs and obtain a basis.

A TOML input describes one calculation. TOML is the simplest choice: you do not need to learn Nickel or install its executable. RustiQ embeds Nickel internally to supply the same defaults and validation as optional Nickel studies. For a standalone input, reuse calculation.toml generated by rustiq init in the first-calculation guide, keep its geometry and downloaded or imported STO-3G basis available, and run rustiq run calculation.toml.

The checked-in neutral H₂ example below is for a source checkout:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf.guess]
type = "CoreHamiltonian"

From the repository root, import the basis if needed and run the input:

rustiq basis import tests/data/sto-3g.json
rustiq run samples/h2/sto-3g/calculation.toml

The [molecule] section points to an XYZ geometry and can set charge, multiplicity, and coordinate units. [basis] names a locally available basis. [method.hf] controls Hartree–Fock, and [method.mp2] requests a correlation calculation after HF. See the HF and MP2 guides for interpreting those methods.

For example, the existing MP2 sample adds an MP2 section:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf]
method = "Rhf"

[method.hf.guess]
type = "CoreHamiltonian"

[method.mp2]
frozen_orbitals = 0

Defaults such as neutral charge, Angstrom coordinates, automatic HF selection, 100 SCF iterations, and a \(10^{-8}\) convergence threshold are filled by the embedded Nickel contracts. The same contracts reject unknown fields and validate values; TOML parsing alone does not describe the full input rules. See calculation inputs and execution for how TOML and Nickel inputs pass through the shared contracts. See the authoritative Nickel input contracts.

Important HF numerical controls include convergence_threshold, max_iterations, diis.enabled, diis.max_history, and orthogonalization.linear_dependency_threshold. MP2 has frozen_orbitals and memory_limit; the latter is a workspace budget, not a process memory limit. The defaults and detailed validation rules belong to the Nickel source, not a second specification in this guide.

Optional local AO ERI cache

The directory-backed AO ERI cache is local, disposable storage. It is disabled by default; enable it in the runfile to allow reuse across runs. The checked-in cache sample below is a complete calculation input; its geometry path is relative to the sample file and points to samples/h2/molecule.xyz:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf.guess]
type = "CoreHamiltonian"

[cache]
enabled = true

With only the release binary, follow the first-calculation workflow to create calculation.toml, then add this section to that file and rerun it:

[cache]
enabled = true

The short block is a fragment to append to the existing input, not a complete runfile. Then run the local input and inspect its cache entries with:

rustiq run calculation.toml --cache-dir ./rustiq-cache
rustiq cache list --cache-dir ./rustiq-cache

--cache-dir DIR selects the directory for this run but does not enable the cache. The cache can be used as a fallback when a portable bundle has no compatible AO ERI; it is not itself a portable .rustiq bundle. See the portable bundle guide for that reuse order.

The geometry path is resolved relative to the TOML file. If the input is read from standard input, its geometry path is resolved from the current working directory. Geometry file structure and coordinate units are explained in the geometry guide.

The CLI reports diagnostics for malformed TOML, unknown or invalid fields, unavailable bases, and invalid molecular states. Tests cover valid examples and grouped diagnostics in tests/cli_samples.rs and tests/nickel_cli.rs. Successful validation means the requested input is internally acceptable; it does not validate the scientific choice of state or method. See the glossary for shared configuration and scientific terms.

Hartree–Fock calculations

Examples in this chapter that use samples/ or tests/data/ require a cloned repository and should be run from its root. Release binaries do not include those files; the first-calculation guide shows how to create local inputs and obtain a basis.

Hartree–Fock (HF) is RustiQ’s reference method for its calculations. It approximates each electron as moving in an average field from the others. The result is found iteratively by updating the electron density and solving the effective one-electron equations until the density and energy are consistent.

RHF (restricted HF) uses shared spatial orbitals for paired alpha- and beta-spin electrons. It is appropriate for a closed-shell state. UHF (unrestricted HF) allows alpha and beta electrons to use different spatial orbitals, which supports open-shell states. UHF is more flexible but its wavefunction need not have a pure total spin.

Select a method and starting guess

With method = "Auto", RustiQ selects RHF for an even electron count and singlet multiplicity, and UHF otherwise. In Nickel/TOML values these methods are spelled "Rhf" and "Uhf". Explicit RHF requires an even-electron singlet; explicit UHF can also describe a singlet. This rule uses the requested charge and multiplicity; it is not a ground-state search. The user remains responsible for choosing the molecular state. Explicit Rhf or Uhf can also be requested when compatible with the electron count.

This open-shell OH example uses neutral charge and doublet multiplicity, so Auto resolves to UHF:

[basis]
name = "sto-3g"

[molecule]
geometry = "../oh.xyz"
charge = 0
multiplicity = 2

[method.hf]
method = "Auto"
convergence_threshold = 1e-5

[method.hf.guess]
type = "CoreHamiltonian"

[method.hf.diis]
enabled = true
max_history = 6

To run this same example with only the release binary, save the following geometry as oh.xyz in your working directory. Create an inputs directory with mkdir inputs if it does not already exist, and save the TOML above as inputs/oh.toml. Its ../oh.xyz path then resolves without editing the sample. Download STO-3G and run (offline, instead import an independently obtained STO-3G JSON file with rustiq basis import /path/to/sto-3g.json):

2
Hydroxyl radical
O 0.0 0.0 0.000
H 0.0 0.0 0.970
rustiq basis download sto-3g
rustiq run inputs/oh.toml

Tip

With an online-enabled build and network access, rustiq run inputs/oh.toml --auto-download downloads STO-3G if it is missing, then runs the calculation. You can use this instead of the separate download and run commands above.

For a source checkout, run it after importing STO-3G:

rustiq basis import tests/data/sto-3g.json
rustiq run samples/oh/sto-3g/calculation.toml

The converged total HF energy is approximately -74.362669 Hartree. The open-shell CLI test and PySCF comparison are linked in scientific scope.

The checked-in H₂ input uses a core-Hamiltonian guess and resolves to RHF:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf.guess]
type = "CoreHamiltonian"

An initial density guess starts the self-consistent iterations. Available choices include core-Hamiltonian, one-electron, random, and zero guesses; the default is core-Hamiltonian. A guess affects the starting path, not the definition of the converged equations. Different guesses can lead to different solutions in difficult cases.

Iterations and convergence

SCF means self-consistent field, the repeated process of building a Fock matrix (the effective one-electron operator) from the current density matrix, solving for orbitals, then rebuilding the density. The atomic-orbital (AO) basis consists of functions centered on atoms; molecular orbitals are combinations of these functions. DIIS (direct inversion in the iterative subspace) can extrapolate Fock matrices from previous iterations to accelerate convergence. It is disabled by default; it changes the numerical route, not the HF model. The DIIS method is associated with Pulay’s extrapolation approach (Pulay, 1982).

The default maximum is 100 iterations. The default convergence_threshold is \(10^{-8}\). Both the absolute change in electronic energy between iterations and the Frobenius norm of the AO commutator residual must fall below this threshold. The energy change is in Hartree; the residual is \(FPS-SPF\). For UHF, alpha and beta residual norms combine as \(\sqrt{r_\alpha^2+r_\beta^2}\). This threshold is not a bound on final energy error.

If SCF reaches its iteration limit, inspect the energy and residual history, then try enabling DIIS or a different initial guess. First confirm geometry units, charge, multiplicity, and basis. Treat numerical errors separately from iteration-limit outcomes, and do not interpret an unconverged result as a valid solution.

Enabling DIIS also enables an energy safeguard in RHF and UHF. Once the density has the required electron populations, a step that raises the electronic energy beyond a roundoff allowance clears the DIIS history and triggers optimal damping. This includes ordinary SCF steps when DIIS has too little usable history to extrapolate: diagonalizing the physical Fock matrix minimizes a linearized energy, and can still raise the full HF energy. For a rejected DIIS extrapolation, the candidate is first recomputed from the physical Fock operator. An ordinary step already supplies that candidate. The Zero guess is a startup sentinel without the required electrons, so its first step is not damped; occupied orbitals establish the electron populations.

Optimal damping minimizes the HF energy along a density segment. For spin channel \(\sigma\), let \(P_\sigma^{(0)}\) be the density before the step and \(P_\sigma^{(1)}\) the density obtained by diagonalizing the physical Fock operator. The damped density is

\[ P_\sigma(t) = (1-t)P_\sigma^{(0)} + tP_\sigma^{(1)}, \qquad 0 \le t \le 1. \]

Because each Hartree-Fock Fock matrix is affine in the densities, the energy along this segment is quadratic:

\[ E(t) - E(0) = \mathrm{slope}\, t + \mathrm{curvature}\, t^2. \]

\[ \mathrm{slope} = \sum_\sigma \operatorname{Tr} [\Delta P_\sigma F_\sigma^{(0)}], \qquad \mathrm{curvature} = \frac{1}{2}\sum_\sigma \operatorname{Tr} [\Delta P_\sigma \Delta F_\sigma], \]

Here \(F_\sigma^{(k)}\) is the physical Fock operator built from the endpoint densities; each UHF Fock operator depends on both spin channels. Also, \(\Delta P_\sigma=P_\sigma^{(1)}-P_\sigma^{(0)}\) and \(\Delta F_\sigma=F_\sigma^{(1)}-F_\sigma^{(0)}\). For RHF, the sum has one spin-summed density and its Fock matrix; for UHF, it runs over \(\sigma\in\{\alpha,\beta\}\). The UHF terms use one shared \(t\), so \(\mathrm{curvature}\) includes the Coulomb coupling between the spin channels. The implementation chooses \(t\) that minimizes \(E(t)\) on this common segment, \([0,1]\), rather than varying the two spin fractions independently. Electron populations in the AO basis are \(N_\sigma=\operatorname{Tr}(P_\sigma S)\), or \(N=\operatorname{Tr}(PS)\) for the RHF spin-summed density. When both endpoint densities have the required electron populations, their mixture preserves those populations, though it need not represent a single determinant. Convergence and determinant spin diagnostics require the stored density to be represented by the current orbitals. An interior mixture generally does not represent the candidate determinant. If damping retains the previous endpoint (\(t=0\)), its density also need not match the newly computed orbitals; spin diagnostics are omitted in that case too. The undamped candidate (\(t=1\)) retains its orbital representation. These safeguards do not guarantee the global HF minimum or stability against spin symmetry breaking. For background on UHF damping, see Yamamoto and Mochizuki (2014).

The AO basis functions overlap. RustiQ diagonalizes their overlap matrix and discards directions whose eigenvalues are at or below the configured relative cutoff (default \(10^{-8}\) times the largest eigenvalue). The retained rank reports the effective dimension used by HF. Rank reduction can change results; inspect it when comparing calculations.

Read the result carefully

The electronic HF energy includes electronic kinetic, electron–nuclear, and electron–electron terms. Total HF energy adds nuclear repulsion. Energies are in Hartree; input Angstrom coordinates are converted to Bohr internally. Terminal energies are rounded for display. The H₂/STO-3G example is checked against a PySCF 2.15.0 reference in the project comparison suite with an absolute energy tolerance of \(2\times10^{-10}\) Hartree; the CLI test checks the rounded value. See reference comparison coverage and the output guide.

When determinant spin diagnostics are available, UHF output includes \(\langle S^2\rangle\) and its deviation from the requested spin state’s ideal value. A nonzero deviation is called spin contamination. For a requested spin \(S=(M-1)/2\), where \(M\) is multiplicity, the ideal expectation is \(S(S+1)\) in units of \(\hbar^2\). For a doublet this is 0.75. Contamination is a diagnostic, not a correction and not proof that UHF found the right state. A converged SCF solution can still be a poor physical model or a local solution. HF uses one Slater determinant and omits electron correlation beyond exchange; small bases and strongly correlated systems need particular care. Read the scientific limitations before interpreting results. See the glossary for shared terms.

The SCF criteria, overlap rank, and spin diagnostics are implemented in scf.rs, orthogonalization.rs, and uhf.rs. The checked-in H₂ and OH CLI/reference cases provide reproducible examples.

Next: MP2.

MP2 calculations

Examples in this chapter that use samples/ or tests/data/ require a cloned repository and should be run from its root. Release binaries do not include those files; the first-calculation guide shows how to create local inputs and obtain a basis. Commands using rustiq assume the executable is installed or available on PATH. From a source checkout without installation, use the cargo run --locked -- prefix described in the CLI reference.

Second-order Møller–Plesset perturbation theory (MP2) estimates an electron correlation correction using molecular orbitals from a converged HF reference. It does not replace HF: RustiQ first solves HF, then evaluates MP2. MP2 is available with both RHF and UHF references. An unconverged HF result cannot be used as an MP2 reference.

The checked-in H₂ input requests RHF-MP2 with no frozen orbitals:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf]
method = "Rhf"

[method.hf.guess]
type = "CoreHamiltonian"

[method.mp2]
frozen_orbitals = 0

With only the release binary, follow the first-calculation guide to create h2.xyz. STO-3G must be available: run rustiq basis download sto-3g with network access, or import an independently obtained local file with rustiq basis import /path/to/sto-3g.json when offline. If you already ran that first calculation, its imported or downloaded basis is still available. Generate and run an MP2 input with:

rustiq init h2.xyz --mp2 -o h2-mp2.toml
rustiq run h2-mp2.toml

Tip

With an online-enabled build and network access, use rustiq run h2-mp2.toml --auto-download to fetch STO-3G if it is missing instead of downloading it separately.

For a source checkout, run the checked-in sample from the repository root after importing STO-3G:

cargo run --locked -- basis import tests/data/sto-3g.json
cargo run --locked -- run samples/h2/sto-3g/mp2_calculation.toml

On successful completion, H₂ reports an MP2 correlation energy of approximately -0.013138 Hartree, in addition to its converged HF energy and total MP2 energy. This is rounded output for the STO-3G case, not a general accuracy claim; the reference tolerances are given below.

The MP2 correlation energy is the correction added to HF electronic energy. Total MP2 energy is HF electronic energy plus MP2 correlation energy plus nuclear repulsion. For the implemented canonical RHF/UHF references with occupied orbitals below virtual orbitals and finite denominators, the second-order correction is nonpositive. A positive value should prompt investigation of orbital ordering, the reference, or numerical inputs.

Open-shell UHF-MP2 example

OH is an open-shell doublet (multiplicity 2). For this input, Auto selects UHF, and MP2 uses the converged UHF reference. The existing OH/STO-3G input is:

[basis]
name = "sto-3g"

[molecule]
geometry = "../oh.xyz"
charge = 0
multiplicity = 2

[method.hf]
method = "Auto"
convergence_threshold = 1e-10

[method.hf.guess]
type = "CoreHamiltonian"

[method.mp2]
frozen_orbitals = 0

[method.hf.diis]
enabled = true
max_history = 6

With only the release binary, save the following geometry as oh.xyz in your working directory:

2
Hydroxyl radical
O 0.0 0.0 0.000
H 0.0 0.0 0.970

Create an inputs directory with mkdir inputs if it does not already exist. Save the TOML above as inputs/oh-mp2.toml; its ../oh.xyz path resolves to that geometry. Preserve the threshold and DIIS settings. STO-3G must be available before running: download it as below, or, when offline, replace the download command with rustiq basis import /path/to/sto-3g.json using an independently obtained local file.

rustiq basis download sto-3g
rustiq run inputs/oh-mp2.toml

Tip

With an online-enabled build and network access, rustiq run inputs/oh-mp2.toml --auto-download fetches STO-3G if it is missing, then runs the calculation. Use this instead of the separate download and run commands above.

Run it from the repository root after making STO-3G available, as described in the basis-set guide:

cargo run --locked -- run samples/oh/sto-3g/mp2_calculation.toml

The calculation reports a UHF-MP2 correlation energy. Existing PySCF comparisons cover this specific example within the tolerances documented below; they do not establish general chemical accuracy.

Frozen occupied orbitals

Occupied orbitals contain electrons in the HF reference; virtual orbitals are unoccupied orbitals available as excitation destinations. The frozen_orbitals setting excludes the lowest occupied orbitals from the MP2 correlation treatment. Its default is zero, so all occupied orbitals are included. RHF requires at least one occupied orbital to remain correlated and at least one virtual orbital; the frozen count must be smaller than the occupied count. For UHF, the count cannot exceed either spin’s occupied-orbital count, though one spin sector may be fully frozen.

For RHF, the count refers to spatial orbitals; freezing one excludes one doubly occupied orbital. For UHF, the same count is applied separately to the alpha and beta occupied spaces. The excluded orbitals can have different spatial shapes. The setting does not choose chemically defined core orbitals automatically. Select it explicitly when comparing calculations.

Memory use

MP2 transforms integrals from the atomic-orbital basis into molecular-orbital blocks. RustiQ processes these blocks to avoid storing the full transformed four-index tensor at once. memory_limit configures the estimated additional workspace used for these transformations. "auto" selects a budget based on available memory; explicit byte sizes such as "500 MB" can also be set.

This workspace budget is not a limit on total process memory. It excludes already resident HF data and atomic-orbital integrals, allocator overhead, and other numerical-library scratch space. If one required block cannot fit within the budget, the calculation returns an error; it does not exceed the budget to allocate that block. See the source for Mp2MemoryPlan and the authoritative Nickel defaults in the input contract.

For example, the existing Nickel default is auto. To set an explicit byte-size budget, add this field inside [method.mp2] if that table already exists:

memory_limit = "500 MB"

If the table does not exist, create it with the field:

[method.mp2]
memory_limit = "500 MB"

These are configuration fragments, not complete runfiles. Do not add a second [method.mp2] table or redefine an existing memory_limit key.

If the budget is below the minimum workspace needed for one occupied block, that sector cannot be transformed and the MP2 calculation errors. Automatic budget resolution follows the shared resource policy.

The H₂/STO-3G RHF-MP2 comparison checks the HF energy within \(2\times10^{-10}\) Hartree and MP2 correlation energy within \(10^{-10}\) Hartree against PySCF 2.15.0. The OH/STO-3G UHF-MP2 case checks HF energy within \(5\times10^{-8}\), correlation energy within \(5\times10^{-9}\) Hartree, and spin expectation within \(2\times10^{-5}\). These are agreement tolerances for those inputs, not a measure of general chemical accuracy. See the reference coverage and the reference test source. Reproduce both selected cases from a cloned repository with Nix, or use the documented uv/PySCF setup. These reference commands are optional and are not included in the release binary:

nix run .#pyscf-check -- -k 'h2-sto-3g-rhf-mp2 or oh-sto-3g-uhf-mp2'

Small energy denominators can make MP2 corrections unreliable, especially in strongly correlated or near-degenerate systems. Numerical safeguards and agreement on a few examples do not establish physical validity. The method’s perturbative basis is described in Møller and Plesset (1934); see also this discussion of problematic MP2 denominators (Lee and Head-Gordon, 2018).

Nickel studies

Examples in this chapter that use samples/ or tests/data/ require a cloned repository and should be run from its root. Release binaries do not include those files; the first-calculation guide shows how to create local inputs and obtain a basis.

For a single calculation, TOML is sufficient. Nickel is an optional interface for parameterized studies that vary basis sets or numerical settings without duplicating input files. You do not need Nickel to run TOML calculations.

Nickel is a configuration language that RustiQ embeds. A .ncl file can import other Nickel files and compute a list of related calculation records. The checked-in single-calculation .ncl input is a small starting point:

{
  molecule.geometry = "../molecule.xyz",
  basis.name = "sto-3g",
  method.hf = {},
}

For the release binary, copy the H₂ geometry from the study section below to molecule.xyz in your working directory. Create an inputs directory with mkdir inputs and save this input as inputs/calculation.ncl. Its ../molecule.xyz path resolves without editing. Download STO-3G with rustiq basis download sto-3g, or import an independently obtained local JSON file with rustiq basis import /path/to/sto-3g.json when offline. Then run rustiq run inputs/calculation.ncl.

Tip

With an online-enabled build and network access, rustiq run inputs/calculation.ncl --auto-download fetches STO-3G if it is missing before running the calculation.

For a source checkout, make sure STO-3G is in the local basis store, then run this checked-in input:

rustiq basis import tests/data/sto-3g.json
rustiq run samples/h2/sto-3g/calculation.ncl

The checked-in H₂ study maps over two basis names to produce two inputs:

let bases = ["sto-3g", "6-31g"] in
std.array.map
  (fun basis_name => {
    molecule.geometry = "molecule.xyz",
    basis.name = basis_name,
    method.hf.diis = { enabled = true, max_history = 2 },
  })
  bases

To run this study with only the release binary, save the H₂ geometry below as molecule.xyz and save the study above as study.ncl in the same working directory. The study’s molecule.geometry = "molecule.xyz" path is relative to that file. Both STO-3G and 6-31G must be available. Download them as shown below, or import independently obtained local files when offline with rustiq basis import /path/to/sto-3g.json /path/to/6-31g.json.

2
Hydrogen molecule
H 0.0 0.0 -0.37
H 0.0 0.0  0.37
rustiq basis download sto-3g
rustiq basis download 6-31g
rustiq run study.ncl

Tip

With an online-enabled build and network access, rustiq run study.ncl --auto-download fetches any missing bases required by the study instead of downloading them separately.

This study is sequential. For a source checkout, run it from the repository root after making both bases available:

rustiq basis import tests/data/sto-3g.json
rustiq basis import tests/data/reference/RustiQ/basis_sets/6-31g.json
rustiq run samples/h2/study.ncl

When both calculations succeed, selected output excerpts are:

Calculation 1/2
Calculation 2/2
2 succeeded, 0 non-converged, 0 failed

The example runs two calculations sequentially, using STO-3G and 6-31G. Both must succeed for this success summary to appear. These are selected lines, not the complete terminal output.

The Nickel file uses molecule.geometry, basis.name, and an HF DIIS setting to create one calculation for each list item. Geometry paths resolve relative to the top-level .ncl file; Nickel imports resolve relative to the file that imports them. No external Nickel executable is needed.

TOML inputs describe one calculation. A .ncl file with one calculation behaves as a single calculation; an array with multiple entries produces a batch. This is useful for studies that vary inputs while keeping the remaining settings shared. Nickel is validated using the same authoritative input contracts as TOML; it does not define a second scientific configuration schema. See calculation inputs and execution for the shared input flow. The project integration test constructs a native import fixture and checks resolution from a different working directory; see tests/nickel_cli.rs. See configuration and the Nickel contract source.

RustiQ validates all study entries before it starts running them. Calculations then run in source order. A calculation that has a recoverable runtime error or does not converge is recorded for that entry, and later entries are still attempted. Fatal infrastructure errors stop the batch. The batch returns an unsuccessful process status if any entry fails or does not converge, while retaining per-calculation results: 4 for partial success, 3 when every entry stops because HF did not converge, or 1 when no entry succeeds and at least one has another error. Fatal infrastructure errors return 1 regardless of earlier successes. A configuration error prevents execution of the batch and returns 1. See the CLI exit-code contract.

The integration coverage is in tests/nickel_cli.rs and tests/json_output_cli.rs. For structured outcomes, see JSON output. To save a study’s calculation entries and reusable AO ERIs in one portable bundle, see portable calculation bundles. See the glossary for Nickel and calculation terminology.

JSON output

Examples in this chapter that use samples/ or tests/data/ require a cloned repository and should be run from its root. Release binaries do not include those files; the first-calculation guide shows how to create local inputs and obtain a basis.

Use JSON when another program needs calculation results. run writes only the machine-readable result to standard output. After following the release- binary path in the first-calculation guide, use the locally created input:

This writes a JSON file without terminal color:

rustiq run calculation.toml --format json --color never > result.json

For a source checkout, run commands from the repository root and make the named basis available first. To save machine-readable output, redirect standard output and disable color explicitly:

rustiq run samples/h2/sto-3g/calculation.toml --format json
rustiq run samples/h2/sto-3g/calculation.toml --format json --color never > result.json

For readable terminal inspection, add --pretty:

rustiq run samples/h2/sto-3g/calculation.toml --format json --pretty

--pretty requires --format json. Compact JSON is unstyled; when saving pretty output for another tool, use --color never to disable syntax colors.

A TOML input produces one calculation result. A one-entry Nickel array also uses the single-result schema. A multi-entry Nickel study produces a batch document with one outcome per input, in source order. Each entry can be success, non_converged, or error. Later calculations continue after a recoverable per-calculation error, but fatal infrastructure errors stop the batch. A valid JSON document can accompany a nonzero exit code. A single HF-only calculation that does not converge still produces the single result with converged: false; its energy and diagnostics describe the final iterate, and the command returns 3. If MP2 was requested, non-converged HF prevents MP2 execution and the run reports a diagnostic with code 3 instead of a single-result JSON document. Other input, preparation, or runtime errors for a single calculation return 1 without result JSON.

A completed batch returns 0 when all entries succeed, 4 when some succeed and others do not, 3 when none succeed and all stop because HF did not converge, and 1 when none succeed and any entry has another error. Fatal infrastructure errors always return 1. See the CLI exit-code contract and Nickel studies guide for details.

Results include schema_version, which lets consuming software select the matching contract. The single-calculation contract is calculation-output-v1.schema.json; batch output uses batch-output-v1.schema.json. These versioned schemas are authoritative; this guide does not repeat their field definitions. See also the reference index.

When run uses --reuse or --artifact, calculation results add an optional artifacts field describing AO ERI selection and its origin. For example, a bundle hit appears as:

{
  "artifacts": [
    { "name": "ao_eri", "decision": "reused", "origin": "archive", "source_index": 0 }
  ]
}

decision describes whether the archive supplied a compatible AO ERI; origin identifies the archive, enabled local cache, or fresh computation that supplied the ERIs actually used. A bundle hit also includes its zero-based source_index. The field is omitted when neither option is used, and batch results report it on each calculation entry. See the portable bundle guide for the full workflow and the CLI reference for details.

Nickel batch JSON

The checked-in Nickel study runs two calculations. Follow that guide’s basis-set setup first, especially when running offline, then produce pretty JSON with colors disabled:

rustiq run samples/h2/study.ncl --format json --pretty --color never

For the release-binary path, save the local study as described in the Nickel guide and use its filename instead, for example rustiq run study.ncl --format json --pretty --color never.

The output follows the versioned batch schema. Each successful calculation contains a result following the single-calculation schema linked above. Inspect the status of every calculation; a batch can include non-converged or failed entries even when it produces valid JSON. --color never prevents ANSI escape sequences in redirected output.

Energies are in Hartree. JSON preserves full floating-point values for comparison and downstream processing, while terminal tables round energies for readability. Do not compare a rounded terminal value against a tight numerical tolerance. Existing JSON CLI tests validate both schemas and full-precision H₂ output in tests/json_output_cli.rs. The checked-in reference tests compare JSON values against PySCF 2.15.0 for selected systems; see scientific scope. For terminology used in result fields, see the glossary.

Portable calculation bundles

Examples in this chapter that use samples/ or tests/data/ require a cloned repository and should be run from its root. Release binaries do not include those files; the first-calculation guide shows how to create local inputs and obtain a basis. Commands using rustiq assume the executable is installed or available on PATH. From a source checkout without installation, use the cargo run --locked -- prefix described in the CLI reference.

A .rustiq bundle is a portable snapshot of RustiQ calculation inputs and optional reusable atomic-orbital electron-repulsion integrals (AO ERIs). It lets users rerun saved calculations or reuse compatible AO ERIs in new ones without carrying a machine-local cache. The bundle does not save a Hartree–Fock wavefunction or skip a new SCF run.

Create and inspect a bundle

Release binary

First follow the local-input workflow in the first-calculation guide. Use the calculation.toml generated by rustiq init and its downloaded or imported STO-3G basis; no additional basis setup is needed. Choose a destination that does not already exist.

rustiq run calculation.toml --artifact h2.rustiq
rustiq artifact inspect h2.rustiq
rustiq artifact verify h2.rustiq
rustiq run h2.rustiq

Tip

With an online-enabled build and network access, rustiq run calculation.toml --artifact h2.rustiq --auto-download fetches STO-3G if it is missing during bundle creation. Direct reruns of an existing bundle need no basis download.

Source checkout

Alternatively, from a cloned repository, make the checked-in STO-3G basis available, then run the H₂ sample and write a bundle to the current directory:

The runfile used here is the checked-in H₂ sample. Run these commands from the repository root:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf.guess]
type = "CoreHamiltonian"
cargo run --locked -- basis import tests/data/sto-3g.json
cargo run --locked -- run samples/h2/sto-3g/calculation.toml --artifact h2.rustiq

--artifact writes the current calculation collection as a new bundle, independently of text or JSON result output. For a Nickel study, the bundle contains one entry for each requested calculation.

Inspect a bundle without the original runfile, geometry file, or basis store:

rustiq artifact inspect h2.rustiq
rustiq artifact inspect h2.rustiq --format json

Inspection displays canonical requested and resolved calculation snapshots, producer information, artifact representations, and captured source names and sizes. Requested values may differ from resolved values: for example, an Auto HF method can resolve to RHF, and requested Angstrom coordinates appear as resolved Bohr coordinates. Text output syntax-highlights the canonical TOML and XYZ when color is enabled by --color or RUSTIQ_COLOR; use --color never for plain text. The optional JSON payloads_verified field is false: inspection validates the archive index, provenance, scientific snapshots and declared artifact sizes, but does not hash or decode numerical payloads. Use artifact verify to check supported payloads eagerly; otherwise, execution checks a payload when its scientific stage selects and reads it. Inspection is structural, not a calculation or an independent scientific validation.

Use artifact verify to eagerly read and validate every supported numerical payload in the bundle:

rustiq artifact verify h2.rustiq

The command checks compact AO ERI payload hashes, NPY encoding, array dimensions, and consistency with the declared AO basis. It reports the number of verified payloads and calculations on standard output, and exits unsuccessfully if a payload is invalid or has an unsupported representation. A bundle with no numerical payloads can successfully report zero verified payloads. Verification does not execute the calculation or establish that the scientific method or result is valid. For the H₂ bundle created above, the output is:

Verified 1 payload(s) across 1 calculation(s).

Rerun a saved calculation

Run a .rustiq bundle directly to reconstruct and execute its archived calculation settings, without the original runfile, geometry file, or basis store:

rustiq run h2.rustiq
rustiq run h2.rustiq --format json --pretty --color never

For a multi-calculation bundle, RustiQ reruns every entry in manifest order and reports a batch, like a multi-entry Nickel study. This is a fresh calculation: RustiQ restores the resolved scientific inputs and reuses compatible AO ERIs when present; otherwise it recomputes them. A corrupt compatible AO ERI payload causes an execution error. It then runs HF again and MP2 again when requested. It does not restore orbitals, density matrices, DIIS history, or prior results, so this command does not resume an SCF trajectory. A saved random seed is restored as an input; it does not guarantee bitwise-identical results across software versions or platforms.

To use different settings, supply a TOML or Nickel input and use --reuse instead. A direct archive rerun cannot be combined with --reuse, --artifact, --cache-dir, --auto-download, or --no-auto-download. With --format json, the rerun uses the normal single-calculation or batch result schema and omits the artifacts reuse-decision array because the bundle is the implicit artifact source. The source bundle remains unchanged; direct reruns do not use the local AO ERI cache or download basis sets.

Reuse AO ERIs in a new calculation

This workflow needs a TOML or Nickel input, its geometry, and an available basis. --reuse does not run the calculation saved in the bundle or restore its captured source files. Instead, RustiQ prepares the supplied input, checks the bundle for compatible AO ERIs, and runs HF again; it also runs MP2 again if the new input requests MP2. The archive itself supplies reusable artifacts and remains read-only.

For the release-binary workflow, use the local calculation.toml created in the first-calculation guide. Keep its downloaded basis available for this new run; its geometry path resolves beside calculation.toml:

rustiq run calculation.toml --reuse h2.rustiq --format json --pretty --color never

From a source checkout, the equivalent command uses the checked-in sample:

cargo run --locked -- run samples/h2/sto-3g/calculation.toml --reuse h2.rustiq --format json --pretty --color never

When a runfile is executed with --reuse or --artifact, its JSON result includes an artifacts entry. A reused AO ERI is reported like this:

{
  "artifacts": [
    {
      "name": "ao_eri",
      "decision": "reused",
      "origin": "archive",
      "source_index": 0
    }
  ]
}

decision says whether the bundle supplied a compatible artifact; the CLI reports reused, missing, or incompatible. origin says where the ERIs actually came from: archive, an enabled local cache, or fresh computation. For example, decision: incompatible with origin: cache means no bundle entry matched but an enabled local cache supplied the ERIs. When an archive entry is selected, source_index is its zero-based position in that bundle. In a batch, each result reports its own selection.

The reuse order is:

  1. First compatible AO ERI in the archive’s manifest order.
  2. Matching entry in the enabled local AO ERI cache.
  3. Recompute the AO ERIs.

The local-cache step is used only when [cache].enabled = true in the runfile. --cache-dir selects the cache location but does not enable caching; see the configuration guide for the input setting.

The archive remains read-only during reuse. To publish a new snapshot from the calculation, provide a new destination. For the release-binary workflow:

rustiq run calculation.toml --reuse h2.rustiq --artifact h2-updated.rustiq

For a source checkout, use the sample path:

cargo run --locked -- run samples/h2/sto-3g/calculation.toml --reuse h2.rustiq --artifact h2-updated.rustiq

What can be reused?

AO ERIs are reusable when the effective integral inputs match. RustiQ checks the ordered atomic numbers and nuclear coordinates in Bohr, effective AO basis functions, Schwarz screening setting, and integral representation and computation versions. A matching basis-set label or atom count alone is not enough. HF method and convergence settings, and whether MP2 is requested, do not change AO ERI compatibility. The persistence specification defines the complete identity.

Change to the new inputAO ERI compatibility
HF method, initial guess, or SCF convergence limitCan remain compatible; HF runs again with the new settings.
Add or change MP2 settingsCan remain compatible; MP2 runs again from the new HF result.
Geometry, effective AO basis, or Schwarz screeningIncompatible; RustiQ checks the local cache, then recomputes if needed.

The bundle stores scientific input snapshots and optional AO ERIs. It does not store HF energies, convergence status, orbitals, density matrices, DIIS history, or MP2 results. Save the result JSON separately when those outputs matter. Captured input and geometry bytes are provenance for inspection; they do not affect compatibility, and Nickel imports are not captured recursively. The same reconstruction is available to Rust callers; see the Rust API examples in the persistence specification.

Publication and failures

--artifact publishes the current requested collection; it does not append to the source bundle. A new destination must not exist. An existing destination is accepted only when it resolves to the explicit --reuse source, in which case RustiQ replaces that bundle after producing a complete validated snapshot. Other existing destinations are left untouched.

Run outcomeBundle behavior
Every requested calculation produces a resultPublish the current collection.
A preparation or execution error occursDo not publish; preserve any prior destination.
HF-only run reaches its iteration limitIts result can still publish the AO ERIs. A single HF run returns exit code 3; a batch with non-converged results and no execution errors publishes, then returns 3 if none converged or 4 if some succeeded. See the CLI exit-code contract.
MP2 was requested but HF did not convergeMP2 execution fails, so the collection is not published.

JSON for a completed calculation or batch may already have been written when a later publication error is reported. See the CLI reference for exact exit and publication behavior and the persistence V1 specification for the archive contract and the EZFIO comparison.

Scientific scope and limitations

RustiQ is experimental software for molecular electronic energies at a fixed geometry. The implemented model uses the nonrelativistic, clamped point-nucleus electronic Hamiltonian: nuclei do not move, and relativistic corrections are not included. A successful run or reference comparison does not establish research-grade correctness. Independently validate the method, basis, molecular state, convergence, and quantities relevant to your research against established packages before drawing chemical conclusions.

Implemented scope

Hartree–Fock (HF) is available as restricted HF (RHF) for closed shells and unrestricted HF (UHF) with separate alpha and beta orbitals for open shells. Automatic selection resolves the method from the molecular state. DIIS accelerates the iterative SCF solution; core-Hamiltonian and randomized density guesses are available. MP2 adds a correlation correction to converged RHF or UHF orbitals, with optional frozen occupied orbitals and a blocked transformation governed by a workspace budget.

Calculations use XYZ geometries with Angstrom or Bohr input, charge and spin multiplicity, Gaussian basis functions, one-electron integrals, and compact stored electron-repulsion integrals (ERIs). Schwarz screening can skip small ERIs, and overlap orthogonalization removes near-dependent directions according to a configured threshold. These thresholds can affect energies and convergence; convergence alone does not establish their suitability for a particular system. Increasing integrals.schwarz_threshold skips more small integrals at a potential accuracy cost; setting it to zero disables Schwarz screening. The authoritative default is in the Nickel schema.

Gaussian Cartesian and spherical functions are implemented, including spherical d functions. Spherical angular momentum above d and effective core potentials (ECPs) are rejected by the current basis loader. The relevant implementation is linked below for inspection.

Basis loader source on GitHub Downloading a basis file does not guarantee that its contents are supported or numerically validated. Geometry inspection and coordinate transformations are available; these operations do not optimize the geometry’s energy. See the glossary for terminology and the workflow notes for preserved usage guidance.

Reference comparisons

The book’s first H₂ calculation provides a reproducible entry point to independent PySCF comparisons with explicit tolerances. The comparison instructions and case definitions are linked below. The release binary user can inspect these checked-in comparisons and their tolerances, but reproducing them requires a source checkout plus the Nix development shell or the documented uv/PySCF setup. They cover H₂ and water in STO-3G, 6-31G, and cc-pVDZ, open-shell H₂⁺ and OH, and selected RHF/UHF MP2 cases. The expanded independent energy matrix adds LiH/6-31G RHF, CO/STO-3G RHF and RHF-MP2, H₂O/cc-pVDZ RHF-MP2 with spherical d functions, and OH/6-31G UHF and UHF-MP2. Geometry provenance and reuse notes are in Molecular and basis-set data sources. The new cases independently interpret the checked-in raw BSE coefficients; primary MP2 references correlate all occupied orbitals. New HF tolerances are 1e-11–2e-11 Hartree and MP2 correlation tolerances 1e-11–2e-11 Hartree, with measured errors and per-case justifications in the reference instructions. OH/6-31G uses an explicit seeded random guess to reach the lower-energy pi-hole solution: a core-Hamiltonian guess can converge to a distinct sigma-hole state. The comparisons check HF spin diagnostics as well as energy, without claiming global HF stability. The report records available SCF iteration counts, provenance hashes, and derived total MP2 energies. Additional cases exercise frozen occupied orbitals and small versus larger MP2 workspace budgets. For OH/STO-3G, the UHF-only sample uses a numerical SCF threshold of 1e-5 in both RustiQ and PySCF, while the UHF-MP2 sample uses 1e-10 in both. Matching the numerical thresholds does not make the two codes’ SCF stopping criteria identical: RustiQ checks an energy change and an AO commutator residual, while PySCF uses its own convergence tests. Compare converged energies and spin diagnostics rather than assuming equivalent accuracy from a matching input number. The first H₂ calculation identifies its CLI test and full-precision independent comparison.

This is a useful, limited reference suite. Its tolerances are case-specific; the H₂/STO-3G tolerance is not a universal accuracy guarantee. It does not systematically span elements, contraction conventions, angular momenta, charges, spin states, difficult SCF solutions, or large systems. Agreement in selected energies can leave errors in untested quantities or shared assumptions undetected. It also does not prove basis completeness, adequacy of HF/MP2 for a chemical problem, or agreement with experiment. UHF spin contamination is an additional physical concern even for converged solutions.

Physical limits of HF and MP2

HF represents the state with a single Slater determinant and omits electron correlation beyond exchange. Convergence establishes a self-consistent solution within the selected orbital space; it does not establish that the solution is the lowest-energy HF state. Different initial guesses can find different solutions. UHF can lower its energy by breaking spin symmetry, so inspect \(\langle S^2\rangle\) and spin contamination as well as the energy.

Bond stretching, dissociation, and near-degenerate states can require several important electronic configurations. A converged single-determinant reference can then be physically inadequate. MP2 is a perturbative correction to that reference, not a general remedy for strong correlation. Its energy terms contain denominators \(\epsilon_i + \epsilon_j - \epsilon_a - \epsilon_b\), with occupied indices \(i,j\) and virtual indices \(a,b\). Small denominators can produce excessively large corrections. Lee and Head-Gordon discuss these denominator problems and bond-breaking examples in their study of regularized MP2.

RustiQ rejects non-finite denominators and absolute denominator values at or below 1e-12 Hartree. This numerical guard is not a physical suitability test: passing it does not establish that the perturbation expansion is reliable. Agreement with another HF/MP2 implementation tests numerical consistency under matched conventions; judging a chemical prediction also requires an appropriate method, basis, and molecular state.

Major limitations

The current calculation methods do not provide DFT, analytic gradients, geometry optimization, vibrational frequencies, or post-HF methods beyond MP2. The molecular input workflow uses XYZ rather than a broad set of chemistry formats. General research use needs broader independent numerical validation, scientific convention documentation, and performance evidence.

Memory management and screening already exist, but compact ERI storage can still grow rapidly with basis size. The MP2 workspace budget is not a bound on total process memory. Larger checked-in molecules are examples, not evidence of robust or competitive performance at scale.

The authoritative references page links to the roadmap and issues, which own future plans. Detailed method derivations and broader validation methodology belong to later scientific documentation; this page describes current boundaries.

Reference comparison instructions on GitHub

Reference case definitions on GitHub

Project roadmap on GitHub

Glossary

This short glossary connects the scientific and software vocabulary used in this manual. It is an orientation aid; method definitions and API contracts remain in their authoritative references.

TermMeaning in this manual
AO / MOAtomic orbital / molecular orbital. Basis functions centered on atoms represent the molecular orbitals used by HF and MP2.
Basis setA finite collection of functions used to represent electronic orbitals. STO-3G is a small basis suitable for the first example, not a general accuracy guarantee.
Bohr / AngstromLength units. Bohr is the atomic unit of length; Angstrom is commonly used for molecular coordinates. RustiQ converts input coordinates to Bohr for calculations.
HartreeThe atomic unit of energy used in RustiQ’s reported energies.
HF / RHF / UHFHartree–Fock / restricted HF / unrestricted HF. RHF pairs electrons in shared spatial orbitals; UHF permits different spatial orbitals for alpha and beta spins.
SCFSelf-consistent field: the iterative procedure for solving the HF equations. Meeting its convergence criterion does not prove chemical accuracy.
DIISDirect inversion in the iterative subspace: an acceleration technique for SCF iterations.
MP2Second-order Møller–Plesset perturbation theory: a correlation correction built from an HF reference.
Multiplicity2S + 1 for spin quantum number S. Singlet and doublet mean multiplicities one and two. Charge and multiplicity specify the intended molecular state.
Spin contaminationDeviation of UHF’s spin expectation value from the value for the intended pure spin state.
ERIElectron-repulsion integral: a contribution describing the Coulomb interaction between electrons in the chosen basis.
AO ERIAtomic-orbital electron-repulsion integral. RustiQ’s optional local cache stores these deterministic integrals, not HF or MP2 results.
OrthogonalizationConstruction of an orthonormal orbital space from overlapping basis functions. Near-dependent directions may be removed.
Frozen orbitalsOccupied orbitals excluded from the MP2 correlation calculation.
ECPEffective core potential: a model replacing core electrons and their nuclear interaction; currently unsupported by RustiQ’s basis loader.
Rust / CargoRust is the implementation language; Cargo builds Rust packages and runs their tests and examples. Users can run an installed CLI without writing Rust.
Crate / workspaceA Rust package’s library or executable unit / a group of packages built together. RustiQ separates its CLI and scientific library.
CLI / APICommand-line interface for terminal users / application programming interface for code using the library.
rustdoc / mdBookRust’s API documentation generator / the tool that builds this user and developer manual.
TOML / NickelCalculation input languages. TOML provides declarative settings; Nickel also supports imports and computed studies and owns input defaults and validation.
JSON / schemaA structured data format / the contract describing valid data. Existing versioned schemas define RustiQ’s machine-readable results.
Nix / flakeA tool for reproducible packages and environments / this repository’s project definition, with dependencies locked by flake.lock. Nix does not require NixOS.
Dev ContainerA prepared Linux development environment running through Docker, with editor integration.
Cache / portable artifactDisposable local data used to avoid repeated work / an intentional scientific snapshot. .rustiq bundles can be written, reused, and inspected through the CLI or Rust APIs.
Validation / toleranceComparison against independent evidence / the allowed difference in a particular numerical check. Passing selected checks does not validate every calculation.
Contracted GaussianA basis function formed by a weighted sum of primitive Gaussian functions that share a center and angular momentum.
Primitive GaussianA Gaussian function used as a component of a contracted basis function.
Occupied / virtual orbitalAn orbital assigned electrons in the reference determinant / an unoccupied orbital available as an excitation destination.
Fock matrixThe effective one-electron matrix built from the current electron density in Hartree–Fock.
Density matrixA matrix encoding which molecular orbitals are occupied and their contributions in the atomic-orbital basis.
Overlap matrixThe matrix of pairwise integrals between basis functions; its off-diagonal values reflect that these functions need not be orthogonal.
Cartesian / spherical GaussianTwo ways to represent the angular part of Gaussian basis functions. Their function counts differ for d and higher angular momentum.
Correlation energyThe energy correction beyond the chosen HF reference; RustiQ reports MP2 correlation separately from the HF and total energies.
Linear dependenceNear-redundancy among basis functions, which can make the overlap matrix numerically singular. RustiQ may discard the affected directions.

Command-line reference

Run these commands from any working directory with the installed rustiq binary. In a source checkout without an installed executable, replace the rustiq command prefix with cargo run --locked --. rustiq --help and rustiq <command> --help show the options supported by the installed build.

Manual

rustiq docs opens the offline HTML manual bundled with a release archive or Nix package. Cargo-only installations open the online manual. Use --web to force the online version, or --print-path to print the local index path or online URL without launching a browser. See installation for relocation, headless use, browser selection, and incomplete-installation errors. PDF export is not implemented.

Binary version and build details

rustiq --version (or rustiq -V) prints the package version on one line. Use rustiq --version --verbose (or rustiq -V -v) for grouped build details; the two flags can also appear in reverse order. These requests return exit code zero and write plain text to standard output. The top-level --verbose flag requires --version; basis list --verbose retains its existing meaning.

The detailed output groups source, compiler, CPU target, and build configuration metadata. It includes the full Git commit and status, compilation target, Rust compiler and LLVM versions, Cargo optimization level, exact profile when supplied by the build, declared debug-information, LTO, codegen-unit, debug-assertion, and integer overflow-check settings, target architecture and explicitly requested target CPU when available, enabled target features, and enabled Cargo features. The architecture is displayed whenever Cargo provides it, independently of whether a target CPU was explicitly requested. No named ISA classification is inferred from the features. Cargo’s synthetic default feature marker is omitted. Values that Cargo or the build system cannot establish are generally omitted from text output. The integer overflow-check row explicitly shows unknown when unavailable; without a declared value, debug assertions are read from the CLI’s compiled cfg(debug_assertions). Cargo’s PROFILE variable does not identify custom profiles reliably, so the profile is shown only when the build supplies its exact name. Release artifacts built by cargo-dist declare dist in their workflow; Nix package builds declare release.

Configuration declared in the selected package profile in Cargo.toml is labeled as declared. Profile inheritance is followed. Cargo does not expose effective LTO, codegen-unit, overflow-check, debug-assertion, or debug-information settings to build scripts. Declared values are reported when the selected profile declares them; debug assertions otherwise use the compiled cfg value and integer overflow checks show unknown. Cargo’s optimization value is supplied to build scripts; a separate compiler flag can override it. Target CPU is populated only from an explicit RustiQ build override or a recognized target-cpu option in Cargo’s encoded rustflags or RUSTFLAGS. The target feature list comes from Cargo’s target cfg for the final target; it does not describe runtime CPU support. Observed rustflags are not a complete record of compiler arguments or Cargo configuration.

LTO and codegen units are labeled as declared because Cargo does not expose their effective compiler values to build scripts. Target features describe compile-time target settings, not instructions supported by the machine at runtime. The architecture and globally enabled features come from Cargo’s final compilation target, including during cross-compilation. The display does not hard-code CPU families, instruction sets, ISA levels, or reference feature lists. This allows the same code to report targets supported by different compiler toolchains without assuming their naming conventions. Rust’s target cfg does not establish the minimum compatible processor for the entire linked executable, particularly if native dependencies or specialized kernels use additional instructions. RustiQ does not guess the concrete build-host CPU.

For example, the grouped output has this shape (unknown optional fields are omitted and the values depend on the build):

rustiq 0.1.0-alpha.1

SOURCE
  Git commit          <full commit hash>
  Status              dirty

COMPILER
  Rust                <compiler version>
  Channel             <stable, beta, nightly, or dev>
  Rust commit         <full hash, only for nightly when available>
  LLVM                <LLVM version>
  Target              <target triple>

CPU TARGET
  Architecture        <target architecture, when available>
  Target CPU          <explicit CPU request, when available>
  Target features     <features enabled for the compilation target, when available>

BUILD CONFIGURATION
  Profile             <exact profile, if supplied>
  Optimization        <Cargo value>
  Debug information   <profile value, if declared>
  LTO                 <profile value (declared)>
  Codegen units       <profile value (declared)>
  Debug assertions    <profile value (declared), or compiled cfg value>
  Integer overflow checks <profile value (declared), or unknown>
  Cargo features      <enabled features, excluding the default marker>

NUMERICAL LIBRARIES
  Linear algebra      nalgebra <version>
  Parallelism         rayon <version>
  Special functions   special <version>

CHEMICAL DATA
  Periodic table      mendeleev <version>
  Bohr radius         CODATA 2018

The numerical libraries section identifies nalgebra for linear algebra, Rayon for parallelism, and special for special functions used by the Boys function implementation. Their versions are read at build time from Cargo.lock when it contains a single distinct version of each crate; otherwise the corresponding version is shown as version unknown. When terminal hyperlinks are enabled, each backend name and version links to that exact version on crates.io. Unknown versions have no link. The parallelism row does not report the active thread count.

The chemical data section identifies the mendeleev crate used for chemical element properties; its resolved version is read from Cargo.lock during the build, using the same fallback and crates.io hyperlink behavior as the numerical libraries. The Bohr-to-ångström conversion factor in the core uses the CODATA 2018 Bohr radius from NIST. Its revision and NIST reference URL are defined alongside the conversion constant in rustiq-core, not duplicated in the CLI. With terminal hyperlinks enabled, the revision links to the NIST CODATA 2018 table. This does not claim that all chemical constants, atomic masses, or basis sets use CODATA 2018. Basis sets and their own revisions are specific to individual calculations and are not reported in this binary-version output.

Integer overflow checks concern integer arithmetic, not floating-point NaN, infinity, or SCF convergence.

Text calculation banners show a 12-character commit abbreviation and its source state. When Git provenance is unknown, they show Build: unknown. OSC 8 links, when enabled, target the complete commit hash. JSON calculation output remains free of banners and retains its existing schema.

All fields are embedded during compilation and remain available when the executable is copied elsewhere, without Git or Rust installed. The source state is clean or dirty according to changes to tracked files at build time; untracked files do not affect this Git dirty flag. The Status row displays clean, dirty, or unknown; a missing commit is displayed as unknown, as can happen when compiling an unpacked source archive without Git metadata. When stdout is a terminal that supports hyperlinks, the Git commit hash links to that commit in the RustiQ repository. The target feature list links to the Rust Reference’s explanation and tables of processor features. Redirected output stays plain text unless FORCE_HYPERLINK explicitly enables links. These fields describe build provenance, not a cryptographic identity of the executable or proof that two builds are identical. The compiler commit is shown only for nightly toolchains, when available; stable, beta, and dev builds still show their compiler channel.

Packagers may set RUSTIQ_BUILD_GIT_COMMIT to a full Git hash (or unknown) and RUSTIQ_BUILD_GIT_STATE to clean, dirty, or unknown at compilation time to override Git discovery. An injected commit without an injected state uses state unknown. RUSTIQ_BUILD_PROFILE, RUSTIQ_BUILD_SYSTEM, and RUSTIQ_BUILD_TARGET_CPU can supply exact build-system metadata when known; the profile, system name, and CPU values are validated before embedding. Nix supplies its profile, build-system name, and flake revision, while the cargo-dist release workflow supplies its profile and build-system name. The Nix source revision is the Git revision passed by the flake, not a Nix store path. Setting these variables when running an already built binary has no effect.

Commands

Manual pages and shell completions

Cargo builds enable the independent manpages and completions features by default. They provide these commands:

rustiq manpages ./manpages
rustiq completions > current-shell-completion
rustiq completions bash > rustiq.bash
rustiq completions zsh > _rustiq
rustiq completions fish > rustiq.fish
rustiq completions elvish > rustiq.elv
rustiq completions powershell > rustiq.ps1
rustiq completions nushell > rustiq.nu

manpages creates its destination directory and replaces existing generated pages. When switching between standalone and packaging modes in the same directory, obsolete rustiq-manpages.1 and rustiq-completions.1 pages are removed. Use a fresh directory for a completely clean generated set if other commands have changed between RustiQ versions. It writes rustiq.1 and pages for the subcommands, including nested commands such as rustiq-artifact-inspect.1. Each page includes the online manual in its SEE ALSO section. completions writes only the script to standard output; generation errors go to standard error and return a failing exit status. Its shell argument is optional: RustiQ recognizes the calling process’s shell first, then falls back to the SHELL environment variable. This includes nu for Nushell and pwsh or powershell for PowerShell. If neither identifies a supported shell, the command asks you to provide one explicitly. Supply the argument when running through a launcher that obscures the calling shell. Both generators reflect the commands and options enabled in the current build. For example, offline builds omit online-only basis commands. By default, generated files also include manpages and completions when those features are enabled. Set RUSTIQ_PACKAGING=true (or 1) to omit manpages and completions from both manuals and shell completion scripts; false, 0, or an unset variable keeps them. Other packagers can use this setting when installing generated files alongside a binary built without the generator features. Values other than true, false, 1, and 0 produce an error.

Load the generated file in the matching shell: source ./rustiq.bash in Bash, source ./rustiq.fish in Fish, or source ./rustiq.elv in Elvish. For Zsh, place _rustiq in a directory on $fpath before running autoload -Uz compinit; compinit. In PowerShell, dot-source the script with . ./rustiq.ps1; it registers native argument completion without adding a command wrapper or Get-Help integration. In Nushell, load it with use ./rustiq.nu *. Add the appropriate loading command to your shell configuration to retain it in future sessions.

To select features explicitly from a checkout, use, for example:

cargo run --locked --no-default-features --features manpages -- manpages ./manpages
cargo run --locked --no-default-features --features completions -- completions nushell

These examples omit online; add it to the feature list if needed. A build without a generator’s feature omits that command and its dependency. The Nix package installs the generated assets but disables both generators in its executable.

Application commands

CommandPurpose
rustiq init <XYZ>Create a TOML calculation input that refers to an XYZ geometry.
rustiq run [INPUT]Run TOML or Nickel input, or rerun calculations from a .rustiq bundle. With no path, read TOML from standard input. Multi-entry inputs run as batches.
rustiq basis import <PATH>...Import basis JSON files into the local basis store.
rustiq basis list [--online] [--verbose]List locally stored bases; online listing is available in builds with the online feature.
rustiq basis download <NAME>Download a basis in builds with the online feature.
rustiq basis remove <NAME>... / --allRemove selected bases or the local basis store contents.
rustiq cache list [--cache-dir DIR]Inspect AO ERI cache entries and their validation status.
rustiq cache remove <NAME-OR-FINGERPRINT> [--cache-dir DIR] / --allRemove selected or all AO ERI cache entries.
rustiq artifact inspect <PATH> [--format FORMAT]Inspect portable .rustiq calculation snapshots and artifact metadata.
rustiq artifact verify <PATH>Check hashes and decode supported numerical payloads in a portable .rustiq bundle.
rustiq geometry info [XYZ]Print basic geometry information; read XYZ from standard input when no path is given.
rustiq geometry rotate, translate, center, oriente, isometryTransform a geometry and write the result; each subcommand has its own help.

The geometry tools and basis storage are utilities around a calculation; they do not create a .rustiq portable artifact. See the geometry guide and existing workflows for examples of geometry, init, and basis management commands.

init options include --output (calculation.toml by default), --force, --basis (sto-3g), --charge (zero), --multiplicity, --units (angstrom by default, or bohr), --hf (auto, rhf, or uhf), and --mp2. Without an explicit multiplicity, it selects singlet for an even electron count and doublet for an odd count. This is a starting convention; choose the physical state appropriate to the molecule. The existing workflows documents path and overwrite behavior.

run options and input selection

The input filename extension selects TOML, Nickel (.ncl), or a portable .rustiq bundle. TOML describes a single calculation. Nickel can describe one calculation or an ordered array; an array of one uses the single-calculation output contract, while a larger array uses the batch contract. A .rustiq input reconstructs and reruns its archived resolved calculation(s); multi-entry bundles use the batch contract. Nickel imports resolve relative to the importing file. Geometry paths resolve relative to the top-level input file; for TOML read from standard input, they resolve from the current working directory. Direct archive reruns cannot be combined with --reuse, --artifact, --cache-dir, --auto-download, or --no-auto-download; the source bundle is read-only and provides its resolved basis and inputs. Archive reruns do not use the local ERI cache or basis-download settings. Text output shows SCF progress; JSON output suppresses progress and writes only the result document.

Important options:

OptionBehavior
--format FORMAT (text or json)Select text output (default) or versioned JSON. JSON result data is written to standard output.
--prettyPretty-print single-calculation or batch JSON, optionally with syntax highlighting. Requires --format json.
--color MODE (auto, always, or never)Control ANSI colors globally; also accepts RUSTIQ_COLOR. Use --color never when redirecting pretty JSON.
--auto-download / --no-auto-downloadIn online builds, allow or disable fetching a missing basis for this run. These override RUSTIQ_AUTO_DOWNLOAD; without either flag, 1 or true (case-insensitive) enables it and other or missing values disable it. Offline builds always use local bases.
--cache-dir DIRChoose the AO ERI cache root for this run. The input must also set [cache].enabled = true; this option does not enable caching.
--reuse PATHRead a portable .rustiq bundle and reuse the first compatible AO ERI for each calculation.
--artifact PATHWrite the current calculation or batch as a portable .rustiq bundle, independently of text or JSON output.

Output presentation is selected exclusively by the CLI --format text|json option. The TOML and Nickel calculation contracts do not accept an output section. Scientific execution emits a completion event after all requested stages complete. An HF-only result can be unconverged and still be a completed execution. The CLI consumes it to retain a lightweight summary, then selects text or JSON presentation after execution. JSON retains its single versioned result document (including the existing batch envelope), without streaming intermediate events. The campaign runner returns ordered outcomes directly; recoverable failures remain in that result and fatal orchestration failures stop the campaign before rendering.

The cache directory path is resolved from the caller’s current working directory. Pass the same --cache-dir to cache list or cache remove to manage entries from a run that used a custom cache root.

The CLI reports input, basis, preparation, and calculation errors as diagnostics. Exit codes follow the Unix convention: zero means complete success; any nonzero code means the command did not fully succeed. Codes 3 and 4 are RustiQ-specific.

CodeMeaning
0All requested calculations succeeded. Help and version requests also return zero.
1General error, a batch with no successful calculations and at least one error unrelated to HF non-convergence, or a fatal infrastructure error.
2Invalid command-line arguments.
3No requested calculation succeeded, and every unsuccessful calculation stopped because HF did not converge.
4A completed batch contains both successful and unsuccessful calculations, including non-convergence or recoverable errors.

These codes apply to TOML, Nickel, and .rustiq inputs, with text or JSON output. A calculation succeeds only when the complete requested method succeeds: converged HF followed by an MP2 error is not a successful calculation. MP2 blocked by HF non-convergence counts as non-convergence, so a single such run returns 3. Input validation before execution returns 1; CLI argument validation returns 2. Fatal infrastructure errors during execution or output writing return 1 and can prevent result JSON from being produced. Artifact publication happens after successful scientific execution. If publication then fails, the CLI still writes the completed calculation or campaign JSON before returning 1; this behavior is covered by publication_error_keeps_complete_calculation_and_batch_json.

A single HF-only calculation that reaches its iteration limit still returns its final-iteration result, with converged: false in JSON, but exits with 3. MP2 requires converged HF; a single MP2 run blocked by non-convergence reports a diagnostic without result JSON. Recoverable per-entry errors in a batch do not prevent later entries from running. The batch JSON records each outcome, and a valid JSON document can accompany a nonzero exit code. Output fields remain defined by the versioned schemas. Convergence alone does not establish the physical validity of a result.

From the repository root, capture the status even when the calculation fails (the conditional also works in shells using set -e):

status=0
cargo run -- run samples/h2/sto-3g/calculation.toml --format json > result.json || status=$?
printf 'Exit code: %s\n' "$status"

When using the installed binary, replace cargo run -- with rustiq. In scripts, inspect the exit code and, when available, individual JSON outcomes; see the JSON guide.

Feature availability

CapabilityAvailable behavior
TOMLOne calculation per input; see the checked-in H₂ input.
NickelOne calculation or an ordered study/batch; see the checked-in study example.
JSONVersioned single-calculation and batch results, selected with run --format json; schemas are linked below.
AO ERI cacheOptional local reuse through [cache].enabled and --cache-dir; entries can be listed or removed. AO ERI means atomic-orbital electron-repulsion integral.
Portable .rustiq bundleCreate with run --artifact, rerun with run FILE.rustiq, reuse artifacts with run INPUT --reuse FILE.rustiq, inspect with artifact inspect, and validate stored AO ERIs with artifact verify. Reruns start a fresh HF calculation. See the portable bundle guide.
Scientific statusExperimental; selected checks do not establish research-grade correctness. See scientific scope and limitations.

Basis downloads and online basis listing require a build with the online feature. The standard CLI enables it; offline builds provide import, local listing, and removal. Geometry transformations are CLI utilities, not calculation input transformations unless their output file is then used as an input.

These examples use files shipped in the repository and must be run from its root after checkout. The release archive contains neither fixtures nor sample inputs. With only the binary, use rustiq basis import /path/to/basis.json for a separately obtained basis file, or rustiq basis download sto-3g in an online build; provide your own input file to rustiq run.

From the repository root, import the checked-in STO-3G and 6-31G basis fixtures before running these examples:

rustiq basis import tests/data/sto-3g.json tests/data/reference/RustiQ/basis_sets/6-31g.json
rustiq run samples/h2/sto-3g/calculation.toml
rustiq run samples/h2/study.ncl --format json --pretty --color never
rustiq run samples/h2/sto-3g/calculation-cache.toml --cache-dir ./rustiq-cache
rustiq cache list --cache-dir ./rustiq-cache

The Nickel study uses both STO-3G and 6-31G; importing only STO-3G is insufficient unless basis auto-download is enabled in an online build. The TOML and cache examples require only STO-3G. See the Nickel studies guide for the individual import commands. The relative ./rustiq-cache directory is resolved from the caller’s working directory on Windows, Linux, and macOS.

The H₂ TOML and Nickel examples are exercised by tests/cli_samples.rs, tests/nickel_cli.rs, and tests/json_output_cli.rs. The JSON tests also check pretty-printing of Nickel batches. The cache-enabled input is samples/h2/sto-3g/calculation-cache.toml; its store-then-hit behavior is covered by test_cli_h2_sample_uses_eri_cache_when_enabled_in_runfile in tests/cli_samples.rs, in addition to the Rust core persistence tests.

Calculation input contracts

TOML and Nickel inputs use the same calculation settings. The embedded Nickel contracts are authoritative for defaults, allowed fields, types, and validation; the CLI does not define a separate TOML-only set of defaults. Consult the TOML guide for sections and checked-in examples, then the geometry, Hartree–Fock, and MP2 guides for the corresponding scientific settings. The Nickel contracts and their validation are linked from the reference index.

The following settings are accepted by both TOML and Nickel. This is a navigation aid, not a second schema: exact defaults, value constraints, and cross-field validation remain defined by the linked Nickel contract.

SectionSupported settings
[molecule]geometry, charge, multiplicity, units (Angstrom or Bohr)
[basis]name
[method.hf]method (Auto, Rhf, Uhf), max_iterations, convergence_threshold, guess, diis.enabled, diis.max_history, orthogonalization.linear_dependency_threshold
[method.mp2]frozen_orbitals, memory_limit
[integrals]schwarz_threshold for integral screening
[cache]enabled for the disposable local AO ERI cache

The accepted density guesses and their fields are defined in the Nickel contract; see the HF guide for their use. The cache stores AO ERI data only; it does not store Hartree–Fock or MP2 results, and a cache hit does not guarantee that every calculation will run faster.

Cache and portable bundles

The local AO ERI cache (atomic-orbital electron-repulsion integrals) is a disposable optimization for deterministic two-electron integrals. It is disabled by default in the calculation input; --cache-dir only selects where enabled cache entries are stored. Use cache list and cache remove to inspect or remove entries. Missing, invalid, or incompatible entries are recomputed. The local cache is not a deliverable or a portable calculation file.

Portable .rustiq bundles use the V1 ZIP/ZIP64 format described by the authoritative persistence specification. The format is conceptually inspired by EZFIO in Quantum Package 2 (qp2), but uses an independent archive structure and APIs; see the comparison. For a guided create, inspect, and reuse workflow, see the portable bundle guide. Bundles are separate from the disposable local AO ERI cache. Reuse opens its source read-only. For each requested calculation, RustiQ selects the first compatible, supported AO ERI in bundle order; when none is available, an enabled local cache is checked before recomputation. A corrupt selected payload is an error. A source entry can supply data to multiple calculations in a Nickel batch.

rustiq run samples/h2/sto-3g/calculation.toml --artifact h2.rustiq
rustiq run samples/h2/sto-3g/calculation.toml --reuse h2.rustiq --artifact next.rustiq --format json
rustiq artifact inspect h2.rustiq --format json
rustiq artifact verify h2.rustiq
rustiq run h2.rustiq
# Replace the source bundle after all requested calculations produce results:
rustiq run samples/h2/sto-3g/calculation.toml --reuse h2.rustiq --artifact h2.rustiq

Publication captures the current requested calculation collection and its compatible known artifacts. It does not append history. An existing destination is accepted only when it resolves to the explicit --reuse source; otherwise the command fails without replacing it. Publication happens after every requested calculation produces a result. Preparation or execution errors prevent publication of the collection and leave the destination unchanged. An HF-only non-converged result can contribute its AO ERI. A Nickel batch containing only non-converged HF-only results can publish its bundle even though the command exits unsuccessfully. If MP2 was requested but HF does not converge, execution fails and the bundle is not published. HF orbitals, SCF restart state, DIIS history, and MP2 results are not persisted.

When --reuse or --artifact is used, JSON calculation results include an optional artifacts array. decision reports archive selection (reused, missing, or incompatible); origin reports the ERI actually used (archive, cache, or computation). A reused item includes its zero-based source_index. Without these options the existing JSON result shape is retained. run FILE.rustiq --format json uses the regular single-calculation or batch result schema but does not include this reuse-decision array: the bundle is the implicit artifact source for that mode. Publication failures are reported on stderr and return a failing exit status. Since publication follows scientific execution, JSON for the completed calculation or campaign is written before that publication error is returned.

artifact inspect PATH displays requested and resolved scientific snapshots, producer details, artifact representations, and captured source names and sizes. In text mode, canonical TOML and XYZ are syntax-highlighted when color is enabled by --color or RUSTIQ_COLOR; JSON output remains structured JSON. It validates the archive index, provenance, snapshots, and declared artifact sizes, but does not hash or decode numeric payloads. Use artifact verify to check supported payloads eagerly; otherwise, execution checks a payload when its scientific stage selects and reads it. Inspection does not execute calculations or establish scientific validity. JSON output follows the artifact inspection V1 schema. artifact verify PATH eagerly reads and validates supported numerical payloads. It currently checks compact AO ERI payload hashes, NPY encoding, array dimensions, and consistency with the declared AO basis. It reports an error for an invalid payload or unsupported representation. Verification does not run a calculation or establish scientific validity. The archive captures exact bytes of the main input and geometry files as shared provenance; it does not capture Nickel’s full import graph. See the persistence specification for the archive contract and API details.

Output contracts

run --format json selects one of two versioned contracts: the single calculation schema or the batch schema. schema_version identifies the contract; schemas, rather than this manual, define the complete field sets. The JSON guide describes output selection, standard output behavior, failure cases, and the existing automated checks.

Existing calculation workflows

For a concise catalog of shipped commands, input settings, JSON behavior, and feature availability, see the command-line reference. This page keeps the longer workflow examples.

This page preserves operational details from the former README. For the progressive workflows, start with the geometry, basis set, configuration, Nickel, MP2, and JSON guides. Commands below use checked-in sample files and run from the repository root after cloning. The Cargo package is rustiq-chem, and the installed executable is rustiq. Users with only the release binary can run equivalent commands with their own geometry, input, and basis JSON files; see the first calculation and basis-set guide. Commands below use an installed rustiq; when working from the checkout without installing it, prepend cargo run --locked -- to the command arguments, for example cargo run --locked -- run samples/h2/sto-3g/calculation.toml. See the glossary for scientific and development terms.

Create input from an XYZ geometry

rustiq init samples/h2/molecule.xyz -o calculation.toml
rustiq init samples/h2/molecule.xyz --hf uhf --multiplicity 3 --mp2 -o triplet.toml

init references the geometry; it does not copy it. The output defaults to calculation.toml in the current directory. Its parent directory must exist. Use --force to replace an existing regular file; the source geometry, directories, and symbolic links are protected from replacement.

Defaults are STO-3G, neutral charge, Angstrom coordinates, and automatic HF selection. Without --multiplicity, the electron count (including charge) selects a singlet for an even count and a doublet for an odd count. This is a starting convention, not a prediction of the ground state. Specify the physical state yourself. --hf accepts auto, rhf, or uhf; --units accepts angstrom or bohr. Incompatible molecular states are rejected. --basis and --charge select another basis and charge. --mp2 adds MP2 with no frozen orbitals. Default-valued settings are omitted from generated TOML and restored by the authoritative Nickel configuration.

Initialization needs neither a cached basis nor network access. Running the calculation checks basis availability and numerical requirements. tests/init_cli.rs checks that generated HF and MP2 inputs run; unit tests in init_command.rs check options, paths, defaults, and overwrite protection.

Geometry paths resolve from the top-level calculation file’s directory, including geometry values supplied by Nickel imports. Nickel imports themselves resolve from the importing file. With no input filename, run reads TOML from standard input and resolves geometry from the caller’s current directory. CLI paths such as --cache-dir also resolve from the caller’s directory.

Basis management and storage

A basis set supplies the functions used to represent electronic orbitals. Import the checked-in fixture for the first calculation, or manage the local store with:

rustiq basis list
rustiq basis import tests/data/sto-3g.json
rustiq basis list --online
rustiq basis download sto-3g

basis import reads a local file and works offline. Online listing and basis download require the online Cargo feature, enabled by default for the CLI, and network access. Offline builds retain local listing and removal. run --auto-download permits downloading a missing basis; --no-auto-download disables it. These flags override RUSTIQ_AUTO_DOWNLOAD, which enables downloading for 1 or true (case-insensitive); otherwise it is disabled. Import and store behavior are tested in basis_store.rs.

The CLI uses the platform’s local application data directory, then appends basis_sets:

PlatformDefault basis directory
Linux~/.local/share/rustiq/basis_sets
Windows%LOCALAPPDATA%\rustiq\data\basis_sets
macOS~/Library/Application Support/rustiq/basis_sets

An absolute XDG_DATA_HOME replaces ~/.local/share on Linux. RUSTIQ_DATA_BASIS overrides the entire basis directory and takes precedence over RUSTIQ_DATA_HOME, which selects <root>/rustiq/basis_sets. Prefer absolute paths for these overrides. If the platform directory cannot be determined, the fallback is <system temporary directory>/rustiq/basis_sets; the operating system may remove its contents.

Older alpha installations used ~/.local/share/RustiQ/basis_sets on Linux, %LOCALAPPDATA%\RustiQ\basis_sets on Windows, and ~/Library/Application Support/RustiQ/basis_sets on macOS. There is no automatic migration or lookup there. Copy existing bases to the current location or set RUSTIQ_DATA_BASIS to the old directory. The policy and override tests live in directories.rs. The basis store is separate from the disposable integral cache and portable scientific bundles described under authoritative references.

JSON results and Nickel studies

rustiq run samples/h2/sto-3g/calculation.toml --format json
rustiq run samples/h2/sto-3g/calculation.ncl
rustiq run samples/h2/study.ncl --format json

The study runs STO-3G and 6-31G calculations sequentially. Import both fixtures from tests/data/reference/RustiQ/basis_sets/, or permit automatic download. The input extension selects TOML or Nickel; no external Nickel executable is needed. TOML and init describe single calculations.

JSON is suitable for automated analysis because energies retain floating-point precision rather than terminal display rounding. Use the existing single and batch schemas as the field contracts; check schema_version. UHF results include spin expectation and contamination relative to the requested spin state; RHF results omit that spin object. Unconverged results describe the final iteration, not a converged wavefunction.

One calculation, including an array of length one, produces the single-result contract. Larger arrays produce the batch contract in source order, with success, non_converged, or error outcomes. Configuration is validated before execution. Recoverable runtime failures allow later entries to run; fatal execution or output errors can stop the campaign before a complete document is rendered. Completed campaign JSON records ordered per-entry outcomes, and a nonzero exit code can accompany that document. Artifact publication occurs after successful execution, so a publication failure preserves the completed JSON but still makes the command fail. Empty arrays are rejected.

Compact JSON has no ANSI styling even with forced color. --pretty requires --format json and can add syntax highlighting when colors are enabled; use --color never when saving pretty JSON for another program. JSON tests and Nickel tests verify these contracts and study execution.

MP2 and its memory budget

MP2 estimates a correlation correction using converged HF orbitals; RustiQ supports both RHF and UHF references. It refuses MP2 on unconverged HF. The existing H₂ input is:

[basis]
name = "sto-3g"

[molecule]
geometry = "../molecule.xyz"

[method.hf]
method = "Rhf"

[method.hf.guess]
type = "CoreHamiltonian"

[method.mp2]
frozen_orbitals = 0

After importing STO-3G, run:

rustiq run samples/h2/sto-3g/mp2_calculation.toml

frozen_orbitals excludes the lowest occupied orbitals from correlation; zero correlates all occupied orbitals. For RHF, it counts spatial orbitals: frozen_orbitals = 1 freezes one doubly occupied orbital (two electrons). For UHF, the same count applies separately to the alpha and beta occupied spaces: 1 freezes the lowest occupied alpha orbital and the lowest occupied beta orbital, also excluding two electrons. These spin orbitals can have different spatial shapes. This configuration setting does not specify separate spin counts or arbitrary orbital indices.

RHF requires the count to be smaller than the occupied-orbital count. UHF requires it not to exceed either spin’s occupied count; a spin channel may have no active occupied orbitals left. Choose the frozen space explicitly when comparing packages. Defaults and input validation belong to Nickel; the core also checks the reference-specific orbital partition during MP2. The PySCF comparisons include RHF/UHF MP2, frozen orbitals, and different workspace budgets.

memory_limit = "auto" resolves once before MP2 to half the available memory. On Linux, the process’s cgroup free-memory limit caps the host value when available. If memory information is unavailable, the fallback is 512 MiB. Explicit sizes such as "500 MB" (decimal units) and "1.5 GiB" (binary units) are accepted. The budget covers additional matrix payloads for the blocked transformation from atomic to molecular orbitals, including panels and coefficient copies. The transformation stages the left virtual coefficient transpose once per spin sector and borrows contiguous right occupied and virtual coefficient columns across occupied blocks. Each AO panel is expanded using its first-pair symmetry, and the transformed panel is reused for the swapped second AO pair. Panels are still expanded again for each occupied block. The workspace estimate remains a conservative bound on these temporary payloads. HF data and compact atomic-orbital integrals are separate. It does not cap total process memory, allocator overhead, or matrix-kernel scratch storage. A budget too small for one occupied block fails before the transformation buffers are allocated. The text report shows block size and workspace estimates. See the tested resource policy and blocked implementation.

Terminal colors

--color and RUSTIQ_COLOR accept auto, always, and never, in order of precedence: CLI flag, environment setting, automatic detection. In automatic mode, NO_COLOR disables styling; otherwise terminal detection is independent for standard output (reports) and standard error (diagnostics and progress). Explicit always or never overrides NO_COLOR.

rustiq --color never run samples/h2/sto-3g/calculation.toml

Windows output uses adaptive terminal support, including legacy consoles. The implementation and focused checks are in color.rs and the JSON integration tests. See the JSON section above for pretty output.

Authoritative references

These documents remain the sources of truth:

The directory-backed local AO ERI cache is disposable, machine-local storage. A portable .rustiq bundle is a deliberate scientific snapshot accessed by the CLI and Rust APIs. A cache directory is not a portable bundle.

Molecular and basis-set data sources

The repository-root DATA_SOURCES.md is the authoritative record. Its contents are included below so the source notes are available in the published manual as well.

Molecular and basis-set data sources

This file records the provenance of molecular geometries and basis-set data currently checked into RustiQ. Coordinates in the XYZ files are in ångströms. For geometries without an external citation, no external provenance is recorded in the repository; do not cite them as experimental or independently optimized reference data.

Molecular geometries

MoleculeRepository filesProvenance and reuse notes
Hydrogen, H₂samples/h2/molecule.xyz; crates/rustiq-core/tests/data/samples/h2/molecule.xyzProject sample/test geometry, with atoms 0.74 Å apart. No external geometry source is recorded. The core fixture duplicates the sample.
Water, H₂Osamples/h2o/h2o.xyz; crates/rustiq-core/tests/data/samples/h2o/h2o.xyzProject sample/test geometry. No external geometry source is recorded. The core fixture duplicates the sample.
Hydroxyl radical, OHsamples/oh/oh.xyz; crates/rustiq-core/tests/data/samples/oh/oh.xyzProject sample/test geometry, with an O–H distance of 0.970 Å. No external geometry source is recorded. The core fixture duplicates the sample.
Lithium hydride, LiHsamples/lih/lih.xyzProject-authored, fixed test geometry: Li at the origin and H at z = 1.60 Å. Chosen as a rounded equilibrium-like distance, consistent with the 1.5957 Å spectroscopic distance discussed in Gottlieb and Weishäupl, Comput. Theor. Chem. 1007, 82–89 (2013), author manuscript. It is not an experimental coordinate file or an optimization result. Neutral singlet; reused by the 6-31G RHF reference.
Carbon monoxide, COsamples/co/co.xyzProject-authored, fixed test geometry: C at the origin and O at z = 1.13 Å. A deliberately rounded equilibrium-like test distance; not an experimental coordinate file or an optimization result. Neutral singlet; the STO-3G RHF and RHF-MP2 references use this identical file.
Ethanolsamples/ethanol/ethanol.xyzThe file describes this as an approximate gas-phase geometry. No external source or calculation provenance is recorded; treat it as an illustrative project geometry, not as a sourced equilibrium structure.
Benzenesamples/benzene/benzene.xyz3D conformer identified by the file as PubChem CID 241 and retrieved through PubChem PUG REST. PubChem record; PUG REST documentation. PubChem’s policy states that PubChem-generated information and participant-provided information are made available without cost and restriction, while warning that some contributed information may be copyrighted. The record labels this as a PubChem 3D conformer.
Cholesterolsamples/cholesterol/cholesterol.xyz3D conformer identified by the file as PubChem CID 5997. PubChem record. PubChem’s policy states that PubChem-generated information and participant-provided information are made available without cost and restriction, while warning that some contributed information may be copyrighted. The record labels this as a PubChem 3D conformer.
Anthracenesamples/anthracene/anthracene.xyzPubChem 3D conformer for CID 8418, obtained as an SDF record through the PubChem PUG REST 3D SDF endpoint; PubChem compound record. The XYZ stores the 24 atom coordinates from that conformer in ångströms. PubChem policy says PubChem-generated and participant-provided information is made available without cost and restriction, but warns that some contributed information may be copyrighted; verify provenance-specific notices when present.

PubChem’s data submission policy also places responsibility on users to respect restrictions that apply to third-party contributed content. The PubChem attribution here describes the geometry provenance recorded by the files; it is not a blanket clearance for every item associated with a PubChem record.

Geometry reuse review for the HF/MP2 extension

Reviewed on 2026-10-21. The new XYZ files are constructed by the project; no third-party coordinate file, database table, spectrum, image, or article text is redistributed. LiH uses a rounded test distance with literature attribution; CO uses a project-selected rounded test distance. Existing water and OH geometries are reused byte-for-byte, with their original unsourced status preserved above. A new reference calculation does not establish external provenance for an old geometry.

The U.S. Copyright Office distinguishes facts from protected expression. This is not a blanket license for database compilations or a determination of rights in every jurisdiction. In particular, the NIST SRD policy reserves compilation copyright under the Standard Reference Data Act, and the NIST Chemistry WebBook is SRD 69. Its government origin must not be treated as automatic public-domain status. The WebBook was consulted to check physical plausibility; its coordinate exports and tables are not imported. The test geometries above intentionally use project-selected rounded distances instead of copied database records. No NIST license is claimed or granted by this repository.

Locally stored basis sets

These are the basis-set datasets present in the repository’s versioned reference store. No other basis-set dataset is listed here. The reference store README identifies them as unmodified files downloaded from the Basis Set Exchange (BSE) using RustiQ. Their embedded revision metadata is reproduced below.

Basis setLocal source fileEmbedded BSE revision metadataFoundational reference
STO-3Gtests/data/reference/RustiQ/basis_sets/sto-3g.jsonData from Gaussian09, revision date 2018-06-19, version 1Hehre, Stewart, and Pople, “Self-consistent molecular-orbital methods. I. Use of Gaussian expansions of Slater-type atomic orbitals,” J. Chem. Phys. 51, 2657 (1969), DOI 10.1063/1.1672392.
6-31Gtests/data/reference/RustiQ/basis_sets/6-31g.jsonData from Gaussian 09/GAMESS, revision date 2018-06-19, version 1Hehre, Ditchfield, and Pople, “Self-Consistent Molecular Orbital Methods. XII. Further Extensions of Gaussian-Type Basis Sets for Use in Molecular Orbital Studies of Organic Molecules,” J. Chem. Phys. 56, 2257 (1972), DOI 10.1063/1.1677527.
cc-pVDZtests/data/reference/RustiQ/basis_sets/cc-pvdz.jsonData from ccRepo/Grant Hill, revision date 2018-10-03, version 1Dunning, “Gaussian basis sets for use in correlated molecular calculations. I. The atoms boron through neon and hydrogen,” J. Chem. Phys. 90, 1007 (1989), DOI 10.1063/1.456153.

The BSE recommends citing its database papers when publishing work that uses the exchange: Pritchard et al., “A New Basis Set Exchange: An Open, Up-to-date Resource for the Molecular Sciences Community” (2019), and, for the earlier database, Schuchardt et al., “Basis Set Exchange: A Community Database for Computational Sciences” (2007). The BSE documentation identifies the software code as BSD-3-Clause; that statement alone does not establish a license for all contributed basis data. The local JSON records do not state a separate data license. Retain their attribution and review the applicable source terms before republishing these datasets beyond the repository.

The HF/MP2 extension reuses the existing 6-31G lithium (elements["3"]) and STO-3G carbon (elements["6"]) records. No BSE data was added, modified, or downloaded for this extension. The reference environment copies the existing versioned files into an isolated store. PySCF independently normalizes their raw coefficients for the new cases. The upstream BSE software license was checked on 2026-10-21; its BSD redistribution conditions concern software and do not resolve separate contributed-data rights. The attribution and existing data-license limitation above continue to apply.

The repository also contains byte-identical copies of STO-3G at tests/data/sto-3g.json and crates/rustiq-core/tests/data/sto-3g.json. Their SHA-256 is db3478afbe34866ed9ee8720e1bf8513d4de16dea22e568e7c1e838fd1231e40. They are project fixtures, distinct from the BSE snapshot above (SHA-256 6e9edeb7ae5ee1c4155dbc84b8bad9b74f07077f8136c7531f86d7f0d358b638); they have no separate provenance metadata and are not described as a BSE download.

The project uses NIST’s Computational Chemistry Comparison and Benchmark Database (CCCBDB, SRD 101) as a possible reference resource only when its terms permit. It is not the provenance of any geometry listed above, and no CCCBDB geometry is bundled here. NIST identifies CCCBDB as SRD 101; consult the NIST license and terms before any reuse.

Development environments

Choose an environment according to the operating system on which you want RustiQ to run, the tools you want prepared, and your compute site’s policies. Docker is an optional development convenience; it is not a universal recommendation for scientific calculations.

SetupWhere Rust and RustiQ runAdvantagesLimitations
Docker / Dev ContainerLinux inside a container on every hostPrepared workspace and VS Code integrationLinux target only; Desktop uses a VM; resource and file-sharing settings need attention
NixNative Linux or Apple Silicon macOS; Linux in WSL2 on WindowsPinned tools without requiring DockerLimited flake platforms; store and installation requirements; WSL2 uses a VM
Manual / CargoNative Linux, macOS, or WindowsDirect host execution and control over installed toolsNative dependencies and optional scientific tools must be installed separately

For native execution on Windows or Intel macOS, choose manual installation. On Linux or Apple Silicon macOS, Nix prepares tools while retaining native execution. Choose Docker when a shared Linux development workspace is useful and its host integration suits your needs.

For HPC workloads, consider the compute node’s operating system, available memory and CPUs, filesystem, and scheduler policies. A native setup avoids adding a VM on Windows or macOS; Docker Engine directly on Linux shares the host kernel. These distinctions do not establish a performance ranking: measure representative calculations with release builds on the intended execution environment. The Docker page explains resource limits and platform boundaries in more detail.

Each setup page contains its prerequisites, commands, advantages, and limits. See known supported platforms for compatibility evidence and Nix packages and shells for the pinned tool inventory.

Terms used in the setup guides

A host is the machine running your environment. A container isolates processes and their installed tools while using a Linux kernel. A virtual machine (VM) runs a guest operating system with its own kernel. WSL2 runs Linux in a VM on Windows. A terminal lets you type commands; a shell interprets them. A Nix development shell makes selected tools available in that session. Cargo builds Rust programs, and rustup installs Rust toolchains.

Docker and VS Code Dev Container

Visual Studio Code (usually called VS Code) is a free application for editing and managing software projects. You can think of it as a text editor with a project file browser, a built-in terminal, and optional extensions that add features such as Rust error highlighting, debugging, or Nickel support. For this project, it gives you one place to edit files, run commands, and see errors.

A Dev Container is a prepared Linux environment for the project. VS Code shows the files and editor on your computer, while Rust, Nix, and the other development tools run inside the container. This avoids installing and configuring those tools individually on your computer. The repository includes the container configuration, so contributors can use the same setup.

Choose this setup when you want a prepared Linux workspace with VS Code integration. Compare it with native Nix and manual installation before choosing a calculation environment.

Advantages and limitations for scientific computing

  • Advantages: the repository supplies a consistent Linux workspace, pinned tools through Nix, and editor integration. Development dependencies stay in the container; the host needs Docker, Git, and VS Code.
  • Platform: Rust, Cargo, and RustiQ run under Linux regardless of the host operating system. The resulting executable targets the container’s Linux architecture; it is not a native Windows or macOS executable.
  • Virtualization: Docker Engine directly on Linux shares the host kernel and does not require a virtual machine. Docker Desktop runs Linux containers in a Linux VM, including on Linux hosts. On Windows, its Linux backend uses WSL2 or Hyper-V. See the official Docker Desktop VM documentation.
  • Resources and files: the VM’s CPU and memory allocation can restrict a calculation independently of the physical machine’s capacity. Host file sharing can also affect I/O. Review Desktop resource settings and any container resource limits before large calculations. Images and the persistent Nix store consume disk space, and initial setup needs downloads.
  • HPC use: this is a development workspace. Cluster policy may prohibit Docker or require another runtime; the supplied Dev Container does not configure a batch scheduler. Check the site’s supported environment before choosing it for compute nodes.

There is no measured universal performance penalty documented for this setup. For performance comparisons, use release builds and record the actual CPU, available memory, architecture, filesystem, and any VM or container limits. Matching the container architecture to the processor avoids introducing cross-architecture emulation into the comparison.

Prepare your computer

  1. Install Visual Studio Code.
  2. Install and start Docker Desktop, or Docker Engine on Linux. Follow its instructions for your operating system. On Windows, its WSL2 backend requires WSL2; the official setup guide explains that requirement. Docker must be configured to run Linux containers.
  3. In VS Code, open the Extensions view from the left sidebar, search for Dev Containers, and install the extension published by Microsoft.
  4. Install Git to download the project.

Open RustiQ in its prepared environment

Open a terminal on your computer and download the project:

git clone https://github.com/mveril/RustiQ.git
cd RustiQ

In VS Code, choose File > Open Folder and select the downloaded RustiQ folder. Open View > Command Palette, search for Dev Containers: Reopen in Container, and select it. The command palette lets you find VS Code actions by name. The first creation can take several minutes while Docker builds the image and Nix downloads the toolchain pinned by flake.lock. Subsequent starts reuse the Docker image and Nix store.

The container is based on Debian Bookworm and installs only Nix and direnv at the system level. The FlakeEnv extension loads devShells.default directly and propagates its environment to terminals, tasks, debuggers, and language servers. Rust, Nix, TOML, Nickel, dependency, Python, Jupyter, and LLDB support is installed as a small explicit extension list rather than through extension packs with overlapping behavior.

The Rust toolchain, rust-analyzer, nixd, nixfmt, Nickel, its language server, Ruff, scientific Python stack, and development utilities are provided by the Nix shell. The Dev Container also installs these VS Code extensions:

  • FlakeEnv loads the flake environment into editor processes.
  • rust-analyzer provides Rust language support; CodeLLDB provides debugging.
  • Nix IDE and Nickel provide Nix and Nickel language support.
  • Even Better TOML supports TOML, while Prettier formats JSON, YAML, and Markdown.
  • Dependi helps inspect dependencies; Python, Jupyter, and Ruff support the Python reference tools.
  • NPY Viewer provides tables, heatmaps, and statistics for .npy files, including the integral fixtures in crates/rustiq-core/tests/data/integrals/. Python is optional. Use the reference tools for numerical verification.

The first activation can take several minutes; later starts reuse the persistent Nix store. Because .envrc execution requires explicit trust, run direnv allow once in the container if FlakeEnv reports that it is blocked, then run FlakeEnv: Reload Environment.

When the workspace is ready, choose Terminal > New Terminal in VS Code. Commands in this terminal run inside the prepared Linux environment. Verify that the tools are available:

cargo --version
rustc --version
rust-analyzer --version
cargo test

After changing .devcontainer/devcontainer.json, rebuild the container. After changing flake.nix or flake.lock, run FlakeEnv: Reload Environment; a container rebuild is only needed when the Dev Container configuration changes.

Dev Container Troubleshooting On Windows

  • If Docker reports that dockerDesktopLinuxEngine cannot be found, start Docker Desktop and wait until docker info succeeds before reopening the repository.
  • If container creation fails while mounting a path such as \\wsl.localhost\<distribution>\mnt\wslg\runtime-dir\wayland-0, disable Dev Containers: Mount Wayland Socket in the VS Code user settings. The equivalent JSON setting is "dev.containers.mountWaylandSocket": false. This only disables Linux GUI forwarding; it does not affect Docker, Rust, Nix, or terminal access.
  • Nix inside the container is installed by the Dev Container feature. It is independent of any Nix or NixOS installation in WSL.
  • If a flake change is not visible in the editor, run FlakeEnv: Reload Environment and restart the affected language server if necessary.

Nix setup

Nix supplies the project’s pinned toolchain without requiring Docker or VS Code. A development shell makes tools available to processes on the current operating system; it is not a virtual machine. See Nix packages and shells for the individual tools provided by the flake.

Advantages and limitations

  • Advantages: flake.lock pins the environment dependencies. Linux and Apple Silicon macOS users compile and run RustiQ natively with prepared Rust and optional PySCF tools. Any editor or terminal can be used.
  • Platforms: this flake supports Linux x86_64 and AArch64 and Apple Silicon macOS. It does not declare native Windows or Intel macOS support.
  • Windows: WSL2 adds a Linux VM and produces Linux executables. Nix inside WSL2 does not remove that virtualization layer.
  • Maintenance: Nix installation, flakes, and the store introduce concepts to learn. Initial downloads or local dependency builds can take time; the store requires disk space. direnv is optional.
  • HPC use: native Nix avoids a container runtime on supported hosts, but installation and access to /nix/store depend on cluster policy. Build on a suitable build node and follow the site’s scheduler and resource rules. Copying a Nix executable alone does not carry its store dependencies to another machine.

If Nix is new to you, start with the official introduction to Nix and learning resources. Nix is a package manager and development-environment tool; NixOS is a complete Linux distribution built around it. You do not need to replace your operating system with NixOS to use this repository’s flake.

Useful references include the official Nix flakes guide, nix develop reference, NixOS-WSL documentation, direnv installation guide, and nix-direnv. For tools used outside the flake, see Rustup and the uv documentation.

The flake supports the following platforms:

  • Linux on x86_64 and AArch64;
  • macOS on Apple Silicon.

The pinned nixpkgs revision no longer supports Intel macOS (x86_64-darwin). Use the native Cargo workflow on that platform.

On Windows, use the Linux flake through WSL2, with either NixOS-WSL or another Linux distribution with Nix installed. This builds and runs Linux executables. For a native Windows executable, use manual installation.

Getting Nix

Choose the case that matches your machine:

  • On NixOS, including NixOS-WSL: Nix is already installed as part of the operating system. NixOS-WSL installation instructions are available for users who want to run NixOS directly under WSL2. Make sure the modern Nix command and flakes are enabled in your NixOS configuration:

    nix.settings.experimental-features = [ "nix-command" "flakes" ];
    

    Apply the configuration with sudo nixos-rebuild switch, then continue with nix develop or the direnv workflow below.

  • On another Linux distribution, macOS, or a non-NixOS WSL2 distribution: install Nix separately as an additional package manager. It works alongside tools such as apt, dnf, pacman, or Homebrew and does not replace them. Follow the official Nix download and installation instructions for your platform, restart the shell if requested, and verify the installation with nix --version. The official page recommends a multi-user installation when the platform supports it. To enable the commands used here, add the following line to your user configuration file, ~/.config/nix/nix.conf (create the directory and file if needed):

    experimental-features = nix-command flakes
    

    Merge these features with any existing experimental-features setting.

In either case, Nix reads flake.nix and flake.lock from this repository to create the same project-specific toolchain without installing those development tools globally. The first invocation may take some time because Nix must download the pinned dependencies; later invocations reuse its local store.

Nix Without direnv

Install Nix with flakes enabled, clone the repository, and enter the development shell manually:

git clone https://github.com/mveril/RustiQ.git
cd RustiQ
nix develop

The default full shell provides the Rust toolchain selected by rust-toolchain.toml, the development utilities, and a Python environment built from the checked-in uv.lock. PySCF and the scientific Python dependencies are available on every platform declared by the flake. Nix places that environment directly on PATH, so no virtual environment needs to be created or activated:

python -c "import pyscf; print(pyscf.__version__)"

Platform-specific profiling and debugging tools are included where available. Run the usual Cargo commands inside the shell:

cargo build
cargo test
cargo run --locked -- basis import tests/data/sto-3g.json
cargo run --locked -- run samples/h2/sto-3g/calculation.toml

Four shells are available so that contributors only load the tools needed for their current task:

ShellContentsCommand
mini-rustRust toolchain and native build dependenciesnix develop .#mini-rust
rustComplete Rust development, debugging, and profiling tools without Pythonnix develop .#rust
mini-pyscfMinimal Rust build environment plus Python and PySCFnix develop .#mini-pyscf
fullComplete Rust and scientific Python environmentnix develop .#full

Running nix develop without a shell name selects full.

Leave the environment with exit or Ctrl-D. You can also build the default Nix package without entering the development shell:

nix build

Nix With direnv

Install both Nix and direnv, enable the direnv hook for your shell, then run:

git clone https://github.com/mveril/RustiQ.git
cd RustiQ
direnv allow

The tracked .envrc loads the full shell automatically whenever you enter the repository and unloads it when you leave. To select a lighter shell for one checkout, create an ignored .envrc.local, then allow the updated environment:

printf '%s\n' 'export RUSTIQ_DEV_SHELL=rust' > .envrc.local
direnv allow

Valid values are mini-rust, rust, mini-pyscf, and full. The tracked .envrc rejects other values before passing the selection to Nix. direnv allow is deliberately required the first time, and again after either envrc file changes, so that shell code is not executed without review. Use direnv deny to revoke permission.

Inside the Dev Container, FlakeEnv performs this integration for VS Code. The tracked .envrc remains useful for developers who use direnv in another editor or terminal.

If use flake is unknown, install or configure nix-direnv, or use nix develop directly. Some direnv/Nix installations already provide this integration.

Manual setup with Rust and Cargo

Advantages and limitations

  • Advantages: builds and calculations run directly on Linux, macOS, or Windows. No container or VM is required. This is suitable when native host execution, local profiling, or existing cluster build tools matter.
  • Maintenance: you install native build dependencies and optional tools yourself. The repository selects Rust through rust-toolchain.toml and Cargo dependencies through Cargo.lock, but does not pin the entire host environment.
  • Platforms: native Cargo supports the platforms in the compatibility table, including Windows and Intel macOS. Python development tools run natively on Windows; PySCF comparisons also run on Windows x86-64.
  • HPC use: this route can use the site’s existing compiler environment without Docker or Nix. Build and run according to cluster policy, using the scheduler’s assigned resources. A locally built binary still needs a compatible target OS, architecture, and runtime dependencies.

Install and build

Install a C/C++ build toolchain and CMake for native dependencies. On Linux, use your distribution’s development packages; on macOS, install the Xcode Command Line Tools and CMake. On Windows, install Visual Studio C++ Build Tools with the Windows SDK, CMake, and the Rust MSVC toolchain.

Install Git and Rust through rustup, then use Cargo directly on Linux, macOS, or Windows:

git clone https://github.com/mveril/RustiQ.git
cd RustiQ
rustup show
cargo build --locked
cargo test
cargo run --locked -- basis import tests/data/sto-3g.json
cargo run --locked -- run samples/h2/sto-3g/calculation.toml

rustup show causes rustup to notice rust-toolchain.toml and install the requested stable toolchain and components if necessary. This route is enough to build and run RustiQ, but the extra tools and the PySCF reference environment from the Nix development shell must be installed separately if you need them. The repository uses uv for that environment on Linux, macOS, WSL2, and native Windows:

uv sync --locked
uv run --locked ruff --version
uv run --locked pytest tools/test_book_links.py tools/test_release_smoke.py tools/benchmarks

The project supports Python 3.12 through 3.14. The default groups install JupyterLab, ipykernel, Matplotlib, SciPy, NumPy, pytest, and Ruff. The lock also includes PySCF 2.15.0 on Linux, macOS, and Windows x86-64. Windows ARM64 remains excluded. Binary wheels are required; source builds remain disabled. Run the reference suite with:

uv run --locked pytest tools/reference

On Windows x86-64, the same command runs PySCF calculations, AO integral comparisons, helper tests, and persistence interoperability tests. Use WSL2 for PySCF on Windows ARM64. These Python tools support development and validation; building the RustiQ executable still requires the Rust toolchain and the Cargo commands above.

Build for calculations and install the executable

From the repository root, use an optimized build for substantial calculations or timing comparisons:

cargo build --release --locked
cargo run --locked -- basis import tests/data/sto-3g.json
cargo run --release --locked -- run samples/h2/sto-3g/calculation.toml

To install into Cargo’s binary directory:

cargo install --locked --path .
rustiq --help

The executable is named rustiq (or rustiq.exe on Windows); use lowercase on case-sensitive systems. Ensure Cargo’s binary directory is on PATH. Keep the checkout for the tutorial’s sample files.

Nix packages and shells

The flake also exposes legacyPackages.<system>.cpuTarget, a function accepting an LLVM CPU name and returning a CPU-specific RustiQ package. See the installation guide for commands and portability considerations. The default package remains portable.

The packages below are declared in flake.nix. All four shells share Rust build essentials. rust adds Rust development tools; mini-pyscf adds the Python reference-test environment to the minimal Rust shell; full combines both extensions. nix develop selects full by default.

Use nix develop .#<shell> to enter a named shell. The direnv setup can select the same names with RUSTIQ_DEV_SHELL; see Development environments.

Rust build essentials

PackagePurposeShells
Rust toolchain from rust-toolchain.tomlrustc, Cargo, Clippy, rustfmt, and Rust source components pinned to the project toolchainAll
cmakeBuilds native dependencies that use CMakeAll
pkg-configHelps native builds find installed librariesAll
libiconv (macOS only)Provides character conversion support needed by native builds on macOSAll on macOS

Rust development tools

The flake pins a NixOS 26.05 nixpkgs revision and uses its development tools directly, without local package overrides. Its cargo-dist package is version 0.31.0; before regenerating release workflows, install the version required by dist-workspace.toml as described in Releasing.

PackagePurposeShells
rust-analyzerRust language server for editor completion, diagnostics, and navigationrust, full
cargo-nextestRuns Rust tests with improved reporting and test isolationrust, full
cargo-denyChecks dependency licenses, advisories, sources, and duplicate cratesrust, full
cargo-aboutGenerates the third-party license notices used in distributionsrust, full
cargo-llvm-covMeasures Rust test code coverage using LLVM instrumentationrust, full
cargo-criterionRuns Criterion benchmarks through Cargorust, full
cargo-expandDisplays macro-expanded Rust coderust, full
cargo-editAdds, removes, and upgrades dependencies from the command linerust, full
cargo-dist (dist)Builds release archives, installers, and checksumsrust, full
cargo-info (cargo info)Displays crate metadata from registriesrust, full
baconWatches files and reruns selected Cargo checksrust, full
cargo-watchRuns Cargo commands when files changerust, full
gitSource control commandsrust, full
hyperfineRepeats and compares command-line benchmarksrust, full
jqReads and transforms JSON from the command linerust, full
mdbookBuilds and previews this manualrust, full
mdbook-mermaidPreprocesses Mermaid diagrams in the manualrust, full
nixdNix language server for editor supportrust, full
nixfmtFormats Nix expressionsrust, full
nickelParses and evaluates Nickel configuration filesrust, full
nlsNickel language server for editor diagnostics and completionrust, full
ripgrep (rg)Fast recursive text searchrust, full
timeReports elapsed time and resource usage for commandsrust, full
clang (Linux only)C/C++ compiler used by profiling and native development toolsrust, full on Linux
cargo-flamegraph (Linux only)Profiles Rust programs and creates flamegraphsrust, full on Linux
gdb (Linux only)Command-line debuggerrust, full on Linux
inferno (Linux only)Converts profiler output into flamegraphsrust, full on Linux
perf (Linux only)Linux performance-counter profilerrust, full on Linux
samply (macOS only)Sampling profiler for macOSrust, full on macOS

Python and scientific packages

Python dependencies are described by pyproject.toml and pinned in uv.lock. Nix builds the Python environments from those files. Python is 3.14 in this flake.

Package or groupPurposeShells
uvPython project and dependency manager for workflows outside the prebuilt shell environmentfull
pyscfIndependent quantum-chemistry implementation used for reference calculationsmini-pyscf, full
numpyArray and numerical operations used in tests and scientific Python toolsmini-pyscf, full
pytestRuns the PySCF reference test suitemini-pyscf, full
scipyScientific algorithms used by optional analysis and development toolsfull
matplotlibCreates plots for scientific analysisfull
ipykernelConnects Python environments to Jupyter kernelsfull
jupyterlabInteractive notebook environmentfull
ruffLints and formats Python codefull

mini-pyscf uses the Python test dependency group; full includes the default group, which combines dev, test, and linting. The helper nix run .#pyscf-check -- ... runs the reference tests against the packaged RustiQ binary. For example:

nix run .#pyscf-check -- -q

Other flake outputs

The flake also exposes nix build .#book to build this manual, nix build .#cargo-artifacts for cached Cargo dependency artifacts, and nix build .#pyscf-environment for the base PySCF environment. These are build outputs rather than development shells. The default package is the RustiQ CLI binary, available through nix build. Its online manual follows the Cargo version: a dev prerelease identifier selects development documentation; other versions select the matching versioned manual. No release flag is needed. See releasing.

Installed manual and completions

The default package includes manual pages for man rustiq and its subcommands, such as man rustiq-artifact-inspect. Every page links to the online book. The package also includes the complete offline HTML manual under share/doc/rustiq/manual/html, including local equation and diagram resources. From the repository root:

nix build
./result/bin/rustiq docs
./result/bin/rustiq docs --print-path

Use --web to open the online manual. Cargo-only installations use the online manual by default; see installation.

The package also installs Bash, Zsh, and Fish completions in the standard Nix locations. Shell discovery depends on your Nix profile and shell setup.

Nushell also loads the completion automatically at interactive startup when the profile exposes share/nushell/vendor/autoload through its data directories. On NixOS, enabling programs.nushell exposes share/nushell from the system profile. Other profiles may need their share directory in XDG_DATA_DIRS.

Nushell, PowerShell, and Elvish scripts are also provided under share/rustiq/completions/ for manual loading. From the repository root, build the package with nix build, then load the script in the matching shell:

use ./result/share/rustiq/completions/rustiq.nu *
. ./result/share/rustiq/completions/rustiq.ps1
source ./result/share/rustiq/completions/rustiq.elv

For persistent configuration, use the corresponding installed profile path instead of a checkout’s result link. PowerShell support registers native argument completion only.

Nix generates the files with a separate build tool and sets RUSTIQ_PACKAGING=true so both generators omit themselves from manuals and completions. The installed executable retains online but disables the Cargo features manpages and completions, so it does not offer generation commands or link their dependencies. Other packagers can set the same variable when generating assets for a binary built without those features. Nix checks build and test all features separately; package installation checks verify the installed assets and the absence of generator commands.

Useful references

Known supported platforms

RustiQ is written almost entirely in Rust, which makes it portable across a wide range of operating systems and processor architectures. The CLI and the rustiq-chem-core library are known to work on the platforms below. Automated build and test checks help maintain that compatibility as the project evolves.

Operating systemProcessor architectureAvailable setup
Linuxx86_64Cargo, Nix, or the Dev Container
LinuxAArch64 (ARM64)Cargo, Nix, or the Dev Container
Windowsx86_64Native Cargo, or a Linux environment through WSL2 or the Dev Container
WindowsAArch64 (ARM64)Native Cargo, or a Linux environment through WSL2 or the Dev Container
macOSApple Silicon (AArch64)Cargo, Nix, or the Dev Container
macOSIntel (x86_64)Cargo or the Dev Container

Other Rust targets may also work. This table describes known compatibility; it is not an exhaustive list of every platform on which RustiQ could run. Native dependencies and optional tools can impose additional requirements.

Choosing an environment

The Cargo workflow builds RustiQ directly on your operating system. It is available on all the platforms listed above. The Nix flake provides a prepared Rust and scientific Python environment for these systems:

  • x86_64-linux;
  • aarch64-linux;
  • aarch64-darwin (Apple Silicon).

The pinned nixpkgs revision no longer supports Intel macOS, so use native Cargo or the Linux Dev Container on that platform. Native Windows users can also use Cargo; Nix requires a Linux environment such as WSL2.

The optional VS Code Dev Container provides a Linux environment through Docker. It is an option on all the host platforms in the table, including Linux and Windows ARM64, provided Docker can run Linux containers on the host. Inside the container, Nix uses x86_64-linux or aarch64-linux according to the container architecture, even when the host runs Windows or macOS. See Development environments for installation instructions, Windows troubleshooting, and the configured VS Code extensions.

The optional scientific Python tools have their own platform requirements. The project configures uv for Linux, macOS, and native Windows. The locked PySCF 2.15.0 release includes native Windows x86-64 wheels; Windows ARM64 remains excluded. The Nix environment provides PySCF on every declared Nix system. For PySCF comparisons on Windows ARM64, use WSL2 or the Linux Dev Container.

How compatibility is checked

The regular CI workflow provides ongoing evidence for this support:

  • Native Cargo checks cover Linux x86_64, Windows x86_64 and ARM64, and macOS Apple Silicon and Intel. They run formatting, Clippy, workspace tests with and without the online feature, and standalone core checks.
  • Nix checks cover Linux x86_64 and AArch64 and macOS Apple Silicon. They build RustiQ, exercise the development shells, and compare reference energies against PySCF.
  • The Dev Container is built and tested on Linux x86_64, including Cargo tests and PySCF comparisons. Separate Windows and macOS host integrations are not exercised by these checks.
  • The standalone uv environment is checked on Linux and Windows x86_64 with Python 3.12 and 3.14. A native PySCF job runs the reference suite on Linux x86-64 and ARM64, macOS Intel and Apple Silicon, and Windows x86-64. Windows also checks Rust/NumPy persistence interoperability with Python 3.12.

The scheduled full Nix workflow also runs all native flake checks on the three declared Nix systems. These checks validate known configurations; they do not limit the possible platforms for the Rust application.

Releasing RustiQ

RustiQ uses dist to build and publish binary archives to GitHub Releases. crates.io publication runs in a separate workflow. Registry lookup or dry-run failures block promotion; once promoted, a registry publishing failure does not block the binary workflow. Neither workflow creates a release from a GitHub Release event; both are explicitly dispatched by promotion after a merge into main, and crates.io publication can also be started manually for an existing tag.

Binary releases

The repository-root dist-workspace.toml pins dist 0.34.0, selects only the rustiq-chem CLI package, and lists the six supported targets. Pull requests run dist plan; this checks the release plan without building or publishing artifacts. The generated workflow also runs on non-main pull requests because dist 0.34.0 does not expose a pull-request base-branch filter. A pull request cannot enter the publishing jobs.

All six target builds use native GitHub-hosted runners: Linux x64 on ubuntu-22.04, Linux ARM64 on ubuntu-24.04-arm, macOS Intel on macos-15-intel, Apple Silicon on macos-latest, Windows x64 on windows-2025, and Windows ARM64 on windows-11-arm. The configuration explicitly selects the ARM runners and preserves the native Windows runners.

The rustiq-chem-core library remains a build dependency and is not packaged as an application. The generated workflow is .github/workflows/release.yml. It pins actions/upload-artifact to an exact version. Because cargo-dist emits a major version reference for that action, dist-workspace.toml sets allow-dirty = ["ci"] so dist plan does not reject the exact pin as an out-of-date generated workflow. Keep the pin synchronized with the intended upload-artifact release when updating the workflow or cargo-dist. Preserve the custom build-manual job, the local-build dependency on it, and the download into manual/html/ when regenerating the release workflow; generated defaults do not contain this offline-manual integration.

Release rehearsal

Run Actions → Release artifact smoke test → Run workflow and select the commit, branch, or tag to rehearse. The manually triggered workflow builds the configured target archive with the pinned dist version on each target’s native GitHub-hosted runner. It extracts that archive, verifies its dist-generated SHA-256 checksum, starts the packaged rustiq executable, checks --help, and runs the checked-in H2/STO-3G regression with a copied local basis fixture and JSON output. Per-target results appear in the job summary; archives, dist manifests, and command logs are uploaded as workflow artifacts. Successful targets also publish a separate rustiq-packages-<target> artifact containing the distributable archive and checksums. Follow the download link in the run summary, then unzip the GitHub Actions artifact to obtain the original release archive. Downloads require a GitHub login and remain available until the workflow artifacts expire. After all six native builds pass, a global job runs dist build --artifacts=global, just as publication does. This builds the corresponding source archive and combined checksums. Download rustiq-release-packages from its summary link to obtain all native archives and global assets together. Only after this upload do the six native smoke jobs download that same artifact and test their target archive against its combined sha256.sum. Thus the downloadable final packages are the packages exercised by the smoke tests. The source archive requires a clean committed checkout; commit local changes before rehearsing them in CI. The Apple Silicon smoke job uses the native macos-latest runner.

This checks archive integrity and basic executable operation for the six configured targets. The H2 energy comparison reuses the regression reference and is a packaging smoke test, not broad scientific validation, independent platform validation, or proof of compatibility with every supported operating system. The runs use GitHub-hosted runners, which are not pristine operating system installations. The rehearsal requires the combined sha256.sum generated by the global dist build and verifies each tested archive against it. A checksum made during a rehearsal does not independently validate a published release.

The rehearsal has read-only repository permissions and only a workflow_dispatch trigger. It does not run dist’s host command, upload release assets, create a GitHub Release, create tags, or publish crates. It complements .github/workflows/release.yml, whose dispatched release path builds and publishes the release assets; ordinary pull requests continue to use the generated plan-only check.

Each executable archive includes rustiq (named rustiq.exe on Windows), the README, LICENSE-MIT, LICENSE-APACHE, COPYING, DISTRIBUTION.md, and THIRD-PARTY-NOTICES.txt, and the complete offline manual in manual/html/. The release workflow builds the validated Nix book once and downloads that artifact into every native archive build. Archive rehearsals check the manual after relocating the extracted tree. See documentation checks for local archive preparation and the offline build process. RustiQ-authored source retains MIT OR Apache-2.0; Malachite and ansi_colours retain their LGPL terms. COPYING supplies the GPLv3 text referenced by LGPLv3, rather than imposing GPLv3 on all RustiQ code. Unix archives use .tar.gz and Windows archives use .zip. Dist adds a .sha256 file for each archive and a sha256.sum manifest. Installers are disabled. Archives do not include calculation samples or basis data.

Each release also includes rustiq-corresponding-source.tar.gz, generated by the dist extra-artifact command python3 tools/distribution.py source before publication. This supplies the committed repository tree and all locked dependency sources. The generated Cargo configuration allows registry-free rebuilding. Dist’s repository-only source tarball is disabled because it would omit the dependency sources. Dist treats this file as an extra artifact; it does not emit a separate checksum for it in the release plan. Before publishing, verify that the source archive is actually present in the release assets and corresponds to the tagged commit. Its checksum can be calculated separately when verifying distribution integrity. See licenses and redistribution for rebuild instructions and the requirements for package maintainers. The Nix package installs the same notice documents into share/doc/rustiq/manual/html; its metadata describes RustiQ’s MIT/Apache terms and the bundled LGPL/MPL components.

To verify the assets listed in sha256.sum on Linux, download it and all listed assets into one directory, then run:

sha256sum --check sha256.sum

On macOS, use the built-in shasum command:

shasum -a 256 --check sha256.sum

On Windows PowerShell, use the explicit manifest comparison in the installation guide, replacing its example archive filename with the archive for your target.

The archive target identifies the operating system and CPU architecture; it does not guarantee compatibility with every Linux distribution or older system library. The Linux GNU archives require a compatible glibc runtime.

Maintaining the changelog

Maintain the repository-root CHANGELOG.md by hand using Keep a Changelog categories and concise, user-facing entries.

  1. Add notable implemented changes under Unreleased during development.
  2. Review and edit the entries before each release, checking capabilities and limitations against the current code, tests, and documentation.
  3. During release preparation, move the relevant entries into a versioned section, such as ## [0.1.0-beta.1] - YYYY-MM-DD.
  4. Replace YYYY-MM-DD with the actual release date and update the changelog’s version and comparison links.
  5. Leave an empty ## [Unreleased] section for future changes, omitting empty categories.
  6. After updating package versions as described below, run dist plan --tag v0.1.0-beta.1 --output-format=json (substitute the intended tag). Check that announcement_github_body contains the intended version’s changelog entries and limitations, rather than only artifact download notes.
  7. Finalize and commit the changelog with the release preparation changes before creating the release tag.

The first public beta should document the capabilities available at launch. For subsequent beta releases, describe incremental changes instead of repeating the complete feature inventory.

Before the first release, preserve the existing Unreleased link to the develop branch’s commit history: no beta release tag exists yet. When preparing v0.1.0-beta.1, finalize the entries under a dated version heading and leave Unreleased ready for future changes:

## [Unreleased]

## [0.1.0-beta.1] - YYYY-MM-DD

Replace YYYY-MM-DD with the actual publication date. As part of that release preparation, set the reference links to the following convention, which applies after the first release:

[Unreleased]: https://github.com/mveril/RustiQ/compare/v0.1.0-beta.1...HEAD
[0.1.0-beta.1]: https://github.com/mveril/RustiQ/releases/tag/v0.1.0-beta.1

For each subsequent release, add its version link and update the Unreleased comparison to start from the latest published version. Until release preparation begins, do not finalize the beta section or add links to an unpublished release.

Dist 0.34.0 has built-in changelog support. It discovers the root changelog and selects the matching version section for release notes. It can also use Unreleased for prereleases, but release preparation should still finalize a dated version section. The existing workflow passes dist’s announcement_github_body to gh release create; no separate release-note generator or workflow change is needed.

Preparing a release

Start from develop on a task branch:

git switch -c chore/prepare-version develop

From the repository root, update the version in both package manifests and update the CLI’s rustiq-chem-core dependency requirement to that same version:

  • Cargo.toml (rustiq-chem)
  • crates/rustiq-core/Cargo.toml (rustiq-chem-core)
  • Cargo.toml’s rustiq-core dependency

After editing the manifests, regenerate Cargo.lock and the corresponding notices. The distribution script needs Python with tarfile extraction filters: Python 3.12 or later, or the backported filters in Python 3.10.12+/3.11.4+. This is independent of the optional PySCF environment. Enter the Nix rust or full shell for the pinned notice generator, or install cargo-about 0.9.2 outside Nix, then run:

cargo check --workspace
cargo install cargo-about --version 0.9.2 --locked
python3 tools/distribution.py notices
python3 tools/distribution.py check
cargo deny --locked --workspace --all-features check
git add CHANGELOG.md Cargo.toml crates/rustiq-core/Cargo.toml Cargo.lock THIRD-PARTY-NOTICES.txt THIRD-PARTY-NOTICES.sha256
git commit -m "Prepare release X.Y.Z"

The publishing workflow checks both package versions and the CLI dependency requirement against the tag using Cargo metadata. After committing the version change, build the workspace:

cargo check --workspace --locked

Promotion requires registry availability and a successful workspace publication dry run. There is currently no local Nickel patch or corresponding crates.io publication block. Before publishing crates, review the acknowledged upstream advisories described in crates.io publication and run cargo publish --dry-run --workspace --locked.

Regenerate and commit notices after changing dependencies, license configuration, the notice template or generator. Review supplemental upstream notices when updating crates whose published packages omit their licenses. CI checks their package inventory, input hashes and generated-file integrity. This catches stale or accidentally edited output; it does not independently verify every license clause or certify legal compliance. Review generated notices and supplemental attribution when changing dependencies. To rehearse the complete source delivery from a clean committed checkout:

python3 tools/distribution.py source

The command rejects source changes and untracked files, except the dist workflow’s generated JSON manifests. It verifies offline Cargo resolution from the archive staging tree. Before a release, also extract the source artifact and run the reconstruction command documented in licensing.

Review the dist release plan and regenerate the workflow after changing the dist configuration or updating dist. The allow-dirty = ["ci"] setting means the generator does not check whether the checked-in release workflow matches its current template. Preserve the exact upload-artifact pin if you regenerate the workflow:

dist plan
dist generate --mode ci
dist generate --mode ci --check

The Rust development shell includes the Nixpkgs cargo-dist package. The generated workflow installs the exact dist version recorded in dist-workspace.toml. Before regenerating locally, install that same version if the Nixpkgs package differs:

cargo install cargo-dist --version 0.34.0 --locked

Development takes place on the default develop branch. Use a version ending in .dev, keeping both crate versions and the internal dependency synchronized. Prepare a release on a chore/* task branch from develop: remove the development identifier, finalize the dated changelog, and update Cargo.lock.

Push the task branch and open a pull request targeting main:

git push -u origin chore/prepare-version
gh pr create --base main --head chore/prepare-version

The required Release eligibility check rejects development versions, mismatched package versions, and versions already present as a tag, GitHub Release, crates.io package, or published manual. Lookup failures block release eligibility. The check also runs:

cargo publish --workspace --locked --dry-run

Cargo packages and compiles both crates, including the unpublished core dependency. Keep package verification enabled. A failure blocks the merge. Update the branch with main before merging so checks apply to the prospective merged result. Every merge into main, including documentation changes, requires a fresh version. Alpha and beta versions are allowed; a complete dev prerelease identifier is not.

After merging, Promote release repeats validation and the publication dry run, creates vVERSION at the merged commit, and explicitly dispatches the binary, crates.io, and documentation workflows at that tag. Do not create or push tags manually. Tag creation with the Actions token does not itself start push workflows. The three publications run independently; inspect each workflow for completion. The registry publication still requires CARGO_REGISTRY_TOKEN.

Resume development with the next intended version ending in .dev on develop. No release/* branches are used. Check the matching /RustiQ/vVERSION/ manual and versions.json after publication. Versioned manuals remain immutable. The documentation homepage opens the latest stable version, otherwise the latest prerelease, otherwise /dev/. Pushes to develop update only /dev/.

crates.io publication

Nickel 0.19’s published dependency graph currently includes imbl-sized-chunks 0.1.3, affected by the unfixed security advisory RUSTSEC-2026-0292, and the unmaintained bitmaps 3.2.1 (RUSTSEC-2026-0247). RustiQ intentionally uses Nickel’s published releases: it does not fork Nickel or backport its transitive dependencies. deny.toml records explicit exceptions for these advisories. Passing cargo deny check does not indicate that the vulnerability is fixed. Review these exceptions and upstream fixes before each release; see dependency review.

The crates.io workflow is not blocked by these exceptions. A merge into main can trigger publication of both crates while the upstream vulnerability remains present. Decide whether to publish that version with the documented risk or hold the release pull request until Nickel publishes a compatible fix.

.github/workflows/publish-crates.yml publishes both workspace crates when a release is promoted from main. Cargo publishes workspace members in dependency order, so rustiq-chem-core is available before rustiq-chem. Before publishing, the workflow uses the crates.io API to exclude package versions that already exist. If a run publishes the core crate and then fails while publishing the CLI, rerunning the same tag skips the existing core version and retries the CLI. For a retry, open Actions → Publish crates.io packages → Run workflow, enter the existing v… tag, and start the workflow. This workflow remains separate from the dist binary release workflow and can also be run manually for an existing tag.

The workflow currently authenticates with the Actions secret CARGO_REGISTRY_TOKEN. Create it from a crates.io API token with only package publishing permissions, then add it under the repository’s Actions secrets before the first release. Keep the token out of repository files and do not grant permissions to yank crates.

Crates.io Trusted Publishing uses GitHub OIDC and avoids a long-lived token, but crates.io requires each crate to have an initial token-authenticated publication before a Trusted Publisher can be configured. For RustiQ’s first publication, use CARGO_REGISTRY_TOKEN to publish both packages through the tag workflow or its manual execution for an existing tag. After both crates exist, configure a Trusted Publisher for each crate in crates.io to trust this repository and the publishing workflow. A follow-up change can then replace the token authentication with OIDC; the binary release workflow does not use or depend on the crates.io token.

Cargo may time out while waiting for a published version to appear in the registry index even when the upload succeeded. Check the version on crates.io before retrying; the workflow’s existence check will skip a version already published.

All package formats derive their online documentation channel from the Cargo version. Build a tagged release with nix build github:mveril/RustiQ/vX.Y.Z; no package selector or release flag is required.

If tag creation succeeds but a dispatch fails, run the missing publication workflow manually at that existing tag. Do not rerun promotion to create the tag again. Rerun failed publication jobs for the same tag; never move the tag. Cargo skips already published crates, and the documentation publisher checks immutable content. For binaries, inspect an existing GitHub Release and its assets before retrying.

Resume development through a task pull request to develop. Port any release-only fixes or changelog changes, then synchronize both crate versions, the internal dependency, and Cargo.lock with the next version ending in .dev. Do not merge release versions back without restoring the development suffix.

For an existing release tag, explicitly select that tag when retrying:

gh workflow run release.yml --ref vVERSION
gh workflow run docs-publish.yml --ref vVERSION
gh workflow run publish-crates.yml --ref vVERSION -f tag=vVERSION

Dispatch only the missing publication. A default-branch dispatch does not select the release revision. Rerun failed jobs in the original binary workflow when some assets already exist; do not create a competing GitHub Release.

RustiQ distribution terms and source access

RustiQ-authored source files are available under MIT OR Apache-2.0. Third-party files keep their upstream licenses and copyrights. The package manifests describe the RustiQ-authored source; they do not relicense dependencies.

The executable uses Malachite under LGPL-3.0-only through Nickel and ansi_colours under LGPL-3.0-or-later through bat. These libraries and their use are covered by the LGPL. RustiQ’s own code remains MIT OR Apache-2.0; the libraries are not relicensed. The GPLv3 text in COPYING accompanies the LGPL terms, which supplement GPLv3; it does not declare RustiQ as a whole GPL. THIRD-PARTY-NOTICES.txt supplies the LGPL, MPL, data-license and other texts and upstream notices. The BSD alternative is selected for bounded-vec-deque. This policy also applies to binaries built without the online feature.

Sources for a distributed executable

Each tagged GitHub release supplies rustiq-corresponding-source.tar.gz alongside its binary archives, at no additional charge. The version-specific download URL is recorded at the top of THIRD-PARTY-NOTICES.txt. Obtain the source artifact from the same release as the binary. It contains the repository sources, Cargo.lock, build scripts, assets, vendored dependencies, and Cargo configuration for using them without accessing a registry. Vendored dependencies are the bundled third-party source code in vendor. GitHub’s automatic repository source downloads do not contain the vendor tree.

Extract and enter the archive using tar on Unix or recent Windows systems:

tar -xzf rustiq-corresponding-source.tar.gz
cd rustiq-source

Install Rust, a native C/C++ toolchain and CMake as described in the manual’s Cargo setup guide. Build the executable using:

cargo build --offline --locked --profile dist --bin rustiq

The result is target/dist/rustiq (target/dist/rustiq.exe on Windows). This rebuild enables the default online feature. An offline application build adds --no-default-features; the build itself stays offline in both cases. This is a reconstruction procedure, not a guarantee of byte-identical binaries. SOURCE-INFO.txt identifies the repository commit and lockfile.

To replace an LGPL component, copy its directory from vendor to an editable directory. For example, copy vendor/malachite-base-0.9.2 to modified/malachite-base and make your changes there. Create a [patch.crates-io] section in the extracted source archive’s root Cargo.toml (or add an entry to that section if it already exists):

[patch.crates-io]
malachite-base = { path = "modified/malachite-base" }

Then rebuild with cargo build --offline --profile dist --bin rustiq. Omit --locked because Cargo may need to update the lockfile for the local replacement. The replacement must satisfy the required package version and API, or you must adjust its dependents too. Keep the upstream license and document your modifications. Vendored files have integrity checks, so use a path patch rather than editing them in place. This changes only the local reconstruction: RustiQ does not modify or fork Nickel upstream.

Redistributing or packaging RustiQ

Include COPYING, LICENSE-MIT, LICENSE-APACHE, DISTRIBUTION.md and THIRD-PARTY-NOTICES.txt with each executable archive or installed package. Preserve the upstream notices, including bundled native code and assets. Package metadata may describe RustiQ-authored code as MIT OR Apache-2.0. It must also preserve the notices and terms for the bundled LGPL, MPL and other components; the application license does not replace those terms.

When serving binaries for download, give recipients equally convenient, no-charge access to the exact corresponding sources on the same download page. If the sources are on another server, put clear directions next to the binary and keep that source access available for as long as needed to meet LGPLv3 section 4(d)(0), which refers to GPLv3 section 6. Preserve the source link in the installed documentation. If you rebuild or patch the application, supply corresponding sources for your own build, including packaging scripts and modifications. Media, devices and other distribution methods require the applicable GPLv3 section 6 arrangements, including installation information when required.

The upstream LGPL and MPL sources and any modifications must remain available under their applicable licenses. Do not add terms that prevent modification, replacement of LGPL components, or reverse engineering to debug those modifications. Normal command execution does not require a credits banner; the accompanying documents carry the notices.

Dependency review

cargo-deny restricts additional license approvals to reviewed crate versions. cargo-about generates license texts; tools/distribution.py adds separate upstream notices and records the lockfile and input hashes. Identical upstream texts are included once and referenced by each package that supplies them. cargo vendor gathers dependency sources; git archive supplies the committed project tree; cargo-dist publishes the resulting archive. CI checks the package inventory and generated-file integrity, not every license clause. Supplemental upstream notices and their provenance are retained in licenses/extra-notices.txt, including notices missing from published crate archives. Review these when updating the affected crates. cargo-about and cargo-deny only cover the Cargo dependency graph; review the license terms and attribution of checked-in scientific data, fixtures, assets, and other third-party content separately before redistribution.

RustiQ retains transitive dependencies with informational maintenance advisories for bincode, unsafe-libyaml and yaml-rust. Their specific advisory IDs and reasons are recorded in deny.toml. Rustls has been updated to its fixed patch release.

Nickel 0.19 depends on imbl-sized-chunks 0.1.3, affected by RUSTSEC-2026-0292: a memory-safety vulnerability involving double free / use-after-free if an element’s destructor panics during certain removal operations. The fix is in imbl-sized-chunks 0.2.0 or later, but RustiQ deliberately keeps Nickel’s published dependency graph rather than carrying a local backport or forking Nickel. deny.toml explicitly acknowledges this unfixed security advisory; a passing cargo deny check does not mean this risk has been mitigated.

The same dependency graph includes the unmaintained bitmaps 3.2.1 crate (RUSTSEC-2026-0247), which is a maintenance advisory, not the same vulnerability. Reassess both exceptions before releases and adopt a compatible upstream Nickel update when one becomes available. There is no automatic crates.io publication block associated with these acknowledged advisories; the publishing workflow still runs on version tags.

Authoritative terms: GPLv3, LGPLv3, MPL 2.0, and CDLA-Permissive-2.0.

For build prerequisites, see Manual / Cargo setup. For release maintenance commands, see Releasing RustiQ.

Contributing and the Rust API

CONTRIBUTING.md owns branch naming, lint policy, and verification commands. See development environments for setup.

Run cargo deny check from the workspace root to check dependency advisories, licenses, duplicate versions, and dependency sources. The same check runs in a dedicated GitHub Actions job; its policy is defined in deny.toml.

The distribution script requires Python with tarfile extraction filters (Python 3.12+, or patched 3.10.12+/3.11.4+). The rust and full Nix shells provide cargo-about. Outside Nix, install cargo-about 0.9.2. After dependency or notice-generation changes, run python3 tools/distribution.py notices, then python3 tools/distribution.py check. Commit the generated notice text and its checksum with the change. See licenses and redistribution for the distribution policy and Nickel’s dependency advisories.

The workspace keeps CLI parsing and presentation in the root package and scientific configuration and calculations in rustiq-chem-core. The core’s calculation module orchestrates work in molecules, basis, eri, hf, and mp2.

Rustdoc remains the canonical public API reference. Generate and open it with MathJax support:

tools/generate-rustdoc.sh --open

On Windows:

.\tools\generate-rustdoc.ps1 -Open

The generated entry point is target/doc/rustiq_core/index.html. MathJax equations require browser access to the CDN. The Pages site publishes the manual; rustdoc is generated separately.

For book equations, use MathJax delimiters \\( ... \\) inline and \\[ ... \\] for display math. Markdown consumes one backslash, so write TeX commands with doubled backslashes as well. Avoid starting a continuation line with Markdown syntax such as +, which can split an equation into a list. Build the book and inspect the generated HTML and a browser-rendered equation, including multiline equations. MathJax requires JavaScript in the browser.

Runnable API examples and public API tests provide executable workflows and verification. Link to these sources instead of duplicating item-level documentation in the book.

Public API imports

Use rustiq_core::prelude::* for direct calculations. It includes CalculationExecution, the trait providing execute() and execute_with_events() for builders and prepared calculations. With explicit imports, bring rustiq_core::calculation::CalculationExecution into scope to call those methods. The builder supports mutable setters such as hf(...), accessors such as get_hf(), and consuming with_hf(...) variants.

Explicit imports use molecules for molecular inputs, config for options, random distributions and validated scalars, basis for basis data, and calculation for execution and results. Located<T> remains available from config and the prelude for optional frontend source positions.

Extensible option structs, including HF, DIIS, orthogonalization, molecular, integral, MP2, random-guess, and guess-perturbation configurations, are #[non_exhaustive]. Create them with Default::default() and then assign the public fields you want to customize. External Rust callers cannot use struct literals or ..Default::default() to construct these types. See the core config module’s Rustdoc for executable examples.

RandomConfig is also non-exhaustive, but has no Default implementation because no distribution is appropriate for every calculation. Start with RandomConfig::new(distribution) and assign seed when reproducible sampling is required. An absent seed continues to initialize sampling from system randomness.

New options must have defaults that preserve the previous behavior when the option is omitted. Maintain this contract in both the core’s Default implementations and the input frontend’s defaults. Non-exhaustiveness protects Rust source compatibility when fields are added; preserving default behavior also requires checking the existing calculation and input regression tests.

The core produces ScfResult, ScfIteration, SCF timings, HfCalculationResult, and Mp2MemoryPlan; these are non-exhaustive inspection records, not extension points for constructing scientific output. Public fields remain readable, while new diagnostics can be added without requiring downstream struct literals to change. Mp2Result remains constructible because the public Mp2Calculation trait lets downstream implementations return the same result type.

Enums are non-exhaustive when callers select among evolving configurations or consume results that may gain another variant, such as HfMethod, ResolvedHfMethod, density guesses, random distributions, and MP2 sectors. HfOutcome remains exhaustive because a completed HF run has exactly two convergence states; setup and calculation failures are returned as errors. RestrictedMethod and UnrestrictedMethod also remain exhaustive and name only the currently implemented method for each reference. Adding a supported method is an explicit API change, rather than an open-ended configuration choice.

For portable archives and raw AO ERIs, import RustiQData, RustiQBundle, and CompactEri explicitly from rustiq_core::persistence. Import ArtifactReuseDecision and ArtifactReuseEvent from rustiq_core::calculation; these advanced types require explicit imports. The portable examples linked above demonstrate the persistence imports, and the portable prelude test shows how to combine them with the calculation prelude.

Architecture and calculation lifecycle

The root CLI package owns terminal reports, application directories, and src/runfile/, which resolves TOML/Nickel through the embedded Nickel schema. The library owns scientific configuration and calculations without a Nickel dependency. This boundary lets a different frontend supply scientific options without embedding its input syntax or terminal behavior into numerical code.

Within the core, molecules owns geometry, units, charge and electron counts; basis constructs Gaussian functions; eri computes and stores electron repulsion integrals; hf solves RHF/UHF; and mp2 consumes HF orbitals. Rust makes ownership and mutation explicit for matrices, integral storage, and shared results. Enums model choices such as the HF method, while Cargo brings dependency locking, feature selection, and tests into one workflow. These engineering tools help make assumptions inspectable; they do not establish numerical correctness or a performance advantage over other languages.

UHF builds the alpha and beta Fock matrices in one pass over AO pairs. Each pair shares the Coulomb contribution from the total density and the integral loads, while retaining a separate exchange contribution for each spin density. The independent scalar contraction regression covers unequal spin densities, equal spin densities, and an empty beta density across different Rayon pools: cargo test -p rustiq-chem-core spin_fock_matrices_match_independent_contractions.

Typed errors distinguish invalid input from numerical failures. Optional source locations let the CLI attach diagnostics to input text without making the library own that text or its presentation.

CalculationBuilder accepts geometry, basis data, and scientific options. prepare() validates the state, converts coordinates to Bohr, constructs the basis, and resolves RHF/UHF. A prepared calculation can execute repeatedly. run_hf() distinguishes converged and unconverged outcomes; only the converged solution exposes mp2(). This type boundary prevents accidental MP2 execution on unconverged orbitals. Cloned solutions share immutable scientific data; execution errors retain completed HF outcomes when available.

The core emits CalculationCompleted once after all requested stages complete. An HF-only run emits it even when the returned HF outcome is unconverged; execution completion and convergence are separate facts. A failing requested MP2 stage leaves the earlier HF notification available but emits no calculation completion. Callbacks borrow results synchronously; retaining them requires copying. The CLI copies only numerical summaries and artifact reports for batch presentation, so collecting a campaign does not retain orbital matrices or AO integrals. Campaign execution returns one ordered CampaignResult directly, including recoverable errors. Fatal errors stop execution before presentation. The CLI then derives the campaign summary, publishes artifacts when allowed, and renders the complete text or versioned JSON document. Publication failure after successful scientific execution still leaves the completed JSON on stdout while returning a failing process status. Portable bundle reruns use the same result presentation.

The normalized CalculationRequest records scientific input without geometry paths or frontend source spans. Canonical TOML/XYZ rendering belongs to CLI adapters. Core consumers supply explicit paths to BasisStore::new; application storage environment variables are CLI policy. The core has no default features; its optional online feature enables online basis support. See the runnable examples and public API tests above for complete construction and error handling.

Data preparation, execution, and reuse

The lifecycle is:

CLI TOML/Nickel adapter or another frontend
    -> geometry + basis data + scientific options
    -> CalculationBuilder::prepare()
       molecule in Bohr, Gaussian basis, resolved HF method and random seeds
    -> PreparedCalculation::run_hf()
       one-electron integrals, overlap orthogonalization, AO ERI acquisition
       -> iterative SCF; final canonicalization if converged
       -> HfOutcome::Converged or HfOutcome::Unconverged
    -> extract the typed converged RHF/UHF solution
    -> Mp2Calculation::mp2()
       blocked AO-to-MO integral transformation and MP2 correlation-energy evaluation

HfOutcome records whether HF converged and contains an AnyHfSolution<State> whose Restricted or Unrestricted variant retains the reference-specific solution. HfSolution<R, State> carries both the reference and convergence state in its type; the RhfSolution and UhfSolution aliases name the common profiles. AnyHfSolution does not expose MP2. For HF followed by MP2, call prepared.run_hf()?.into_converged()?, match the runtime variant, then call mp2(config) on the resulting typed RHF or UHF solution. Both typed solutions implement the Mp2Calculation capability trait, exported in the prelude; unconverged and generic runtime solutions do not. The conversion returns an execution error retaining the unconverged outcome, recoverable with into_hf(). Typed/runtime conversions preserve state and return a typed HfReferenceMismatch error that retains the original solution when the requested reference does not match.

The owned-output implementation lives in crates/rustiq-core/src/calculation/solution/, with separate modules for generic results, HF adaptation, runtime dispatch, outcomes and execution errors. The calculation/solution.rs facade preserves the existing public exports through rustiq_core::calculation and the prelude. Convergence markers stay together, and private shared storage stays with the result that owns it.

HfSolution<R, State> wraps ScfSolution<HfMethodDescriptor<R>, State>. The following conversions preserve the physical method, reference, convergence state and shared scientific allocation:

SourceTargetConversion
HfSolution<R, State>ScfSolution<HfMethodDescriptor<R>, State>From / Into, or into_scf()
ScfSolution<HfMethodDescriptor<R>, State>HfSolution<R, State>From / Into, or from_scf()
&HfSolution<R, State>&ScfSolution<HfMethodDescriptor<R>, State>AsRef, or as_scf()
Restricted or unrestricted generic HF outputAnyHfSolution<State>From / Into
AnyHfSolution<State>Restricted or unrestricted generic HF outputTryFrom / TryInto

The checked runtime extraction returns HfReferenceMismatch<State> on a reference mismatch. It reports the expected and actual HF references and retains the original AnyHfSolution<State>, recoverable with into_solution(). These conversions transfer or borrow existing ownership; they do not clone scientific data or allocate another result. The named methods delegate to the standard traits. The HF wrapper keeps its explicit interface, including occupied_orbitals(); existing HF callers need no migration.

ScfSolution<M, State> owns scientific output; ScfResult contains numerical metrics. The public ScfMethod trait associates independent coefficient, energy, occupation, summary and RetainedData types. It describes output rather than an executable SCF algorithm. The implementing descriptor type identifies the physical method separately from those representations. The generic occupations() accessor borrows method-specific occupations, which need not be integer orbital counts. retained_data() borrows scientific artifacts retained after execution; the generic contract requires neither an HF summary nor AO ERIs.

Implementing this trait does not provide an SCF engine or a public solution constructor: the library establishes the method-specific convergence state. For HF, HfMethodDescriptor<R> identifies the compatible method, with an HfCalculationResult summary and retained AO ERIs. Its ScfSolution specialization exposes scf_result() to borrow metrics from the summary. Only compatible converged HF wrappers implement Mp2Calculation; generic HF output can be restored through Into or from_scf(). AnyHfSolution itself does not imply that MP2 is available for every contained or future HF reference. Supported converged HF implementations also guarantee final canonicalization; this is an HF guarantee, rather than a universal requirement on every SCF method.

The sealed HfReference contract associates a compatible HF method, coefficient representation, orbital energies, and occupations. Generic code converts the associated method into ResolvedHfMethod; conversion into the input selector HfMethod is not required by the trait. RHF has one shared coefficient matrix and energy vector with one doubly occupied spatial-orbital count. UHF has separate alpha and beta coefficients, energies, and electron counts, represented by Spin<T>. Read-only accessors expose these values; energies are in Hartree, and each occupation count selects a prefix of its coefficient columns. Cloning a solution shares retained scientific data. An unconverged solution keeps diagnostic orbitals, while final canonical orbitals are guaranteed only after convergence.

Initial guesses use the same reference markers through DensityGuess<R> and OrbitalGuess<R>. Reference-specific Fock-like inputs contain one matrix for Restricted and a Spin pair for Unrestricted, using the same HfReference component contract as HfSolution. The zero startup sentinel is available for both. Unperturbed guesses retain one core matrix for RHF or duplicate it for UHF. Random and perturbed guesses generate one matrix for RHF or two ordered alpha/beta matrices for UHF without constructing a discarded beta matrix; the seeded alpha sequence is preserved across references.

Only converged solutions expose MP2. Method dispatch is exhaustive, so each supported reference has an explicit correlation implementation. An MP2 error retains the completed HF result for inspection or retry. See the hf_solution example and API tests for executable workflows.

The complete offline example in crates/rustiq-core/examples/hf_solution.rs is also included directly in the HfOutcome API documentation. Run it from the repository root:

cargo run -p rustiq-chem-core --example hf_solution --no-default-features

It embeds the checked-in STO-3G basis and the H2 singlet and OH doublet geometries, with coordinates interpreted in Angstrom. It prints reference-specific occupied counts, total HF energies and MP2 correlation energies in Hartree. A deliberately invalid frozen-orbital count demonstrates error recovery: the example drops the original HF handle, extracts the retained output from the error using the standard conversion traits, and retries MP2 without rerunning HF. Unexpected failures propagate as errors. The example illustrates API ownership and error handling; the independent scientific comparisons remain separate verification procedures.

prepare() constructs reusable input data; it does not compute integrals or solve HF. Each normal run_hf() call builds a new HF execution state, including one-electron integrals and the orthogonalizer. Without an explicit reuse source, AO ERIs are recomputed too. Repeated execution of a prepared calculation does not itself memoize these numerical arrays. Random seeds resolved at preparation are retained for repeated executions.

An optional EriCache can load compatible AO ERIs from a directory or store newly computed ones. It is disposable local storage. A supplied CompactEri through run_hf_with_eri() bypasses AO ERI computation and cache lookup, but the raw tensor API checks its expected element count rather than proving its scientific provenance. The caller must supply ERIs for the prepared geometry, AO ordering, and screening policy. Use the persistence APIs’ compatibility checks when reusing an archive. HF solutions retain their AO ERIs, and cloned solutions share immutable result data; these retained results are distinct from the prepared input data.

Portable .rustiq bundles can be read and written through the core persistence APIs and through the CLI’s run --reuse, run --artifact, artifact inspect, and artifact verify commands. run INPUT --reuse BUNDLE resolves the supplied runfile’s geometry and basis as usual, then uses bundle compatibility to select AO ERIs. run BUNDLE.rustiq reconstructs the archived resolved calculations without the original inputs or local basis store. The Rust API can also reconstruct a calculation from those scientific snapshots. These workflows start fresh HF executions; HF solutions and SCF restart state are not persisted. Neither workflow turns a local cache directory into a portable artifact. See the portable bundle guide, the persistence contract, and the runnable API examples for details. Portable NPY ERI payloads stream directly into the final shared compact storage through an exact-size iterator, avoiding a temporary full-size Vec<f64>.

This distinction matters for performance: compact AO ERI storage still grows as the fourth power of basis dimension, and the MP2 workspace budget covers additional transformation buffers rather than the full HF data or process memory. See MP2 memory policy.

Build profiles and performance investigation

Cargo’s default development and test builds favor development speed. Release builds optimize execution using thin link-time optimization and one codegen unit, and strip symbols. The custom profiling profile retains release optimizations with debug information and symbols:

cargo build --locked --release
cargo build --locked --profile profiling

The profiling executable is under target/profiling/. For optimization specific to the build machine’s CPU, use RUSTFLAGS="-C target-cpu=native" cargo build --locked --release; that binary may require instructions absent on another CPU. In PowerShell, set $env:RUSTFLAGS = "-C target-cpu=native", build, then remove it with Remove-Item Env:RUSTFLAGS. There is no separate native Cargo profile.

Coulomb integrals cache Boys function values by order. When the requested maximum order is nonzero, positive arguments up to 20 use a positive-term series to seed the highest order, followed by downward recurrence; larger arguments retain the gamma-function seed. An order-zero cache uses the error-function expression. This changes numerical evaluation rather than the integral definition or screening policy. The unit tests in boys.rs compare the cache against independent quadrature, including the series boundary. Run cargo test -p rustiq-chem-core math_utils::boys and the affected PySCF comparisons after changing this path.

The eri_timings and mp2_timings benchmarks use Criterion and require bench:

cargo bench --bench mp2_timings --features bench
cargo bench --bench eri_timings --features bench
cargo bench --bench eri_storage_allocation --features bench
cargo bench --bench eri_storage_memory --features bench

The MP2 benchmark compares the dense AO-to-MO transformation and correlation energy evaluation with the production memory-blocked path on deterministic synthetic RHF inputs. Each blocked case is constrained to process occupied orbitals in at least two blocks, even when the requested memory budget could fit one block. RUSTIQ_MP2_MEMORY sets an upper cap; each case may use a smaller budget to force multiple blocks. AO dimensions must be at least 6. It checks that both paths produce matching energies before timing them, and records the selected block size, block count, workspace budget, and estimated temporary workspace. Input and ERI construction remain outside the measured iterations. These synthetic inputs benchmark the contraction code; they are not molecular calculations or scientific accuracy validation. RUSTIQ_MP2_MEMORY, RUSTIQ_MP2_SIZES (comma-separated AO dimensions), and RAYON_NUM_THREADS select the memory budget, AO dimensions, and thread count. The ERI benchmark times repeated integral construction for the checked-in molecular cases. By default it skips the larger ethanol and cholesterol cases; set RUSTIQ_BENCH_HEAVY=1 to include them. RUSTIQ_BENCH_FILTER selects cases by name or geometry path, and RUSTIQ_BENCH_BASIS_STORE selects a basis store. It reports compact ERI storage elements processed per second. This count is the size of the compact representation; Schwarz screening may skip evaluations or leave stored elements zero, so it is not a count of integrals evaluated per second.

The eri_storage_allocation benchmark compares Vec-then-Arc construction with the exact-size-iterator Arc initialization path for identical compact tensor sizes. It measures storage allocation and initialization only, not ERI evaluation. Compare the same Criterion benchmark and compiler settings on both revisions. The Miri workflow targets a sequential unit test for the shared in-place initialization helper, checking its initialization safety independently of Rayon scheduling. Run the same check locally with nightly Rust:

rustup +nightly component add miri rust-src
cargo +nightly miri setup
cargo +nightly miri test -p rustiq-chem-core --lib test_in_place_storage_initialization_miri

The eri_storage_memory benchmark uses a counting global allocator in a separate executable to report peak live heap bytes attributable to each construction. It includes requested allocation sizes, not allocator overhead or process RSS. It compares the same Vec-then-Arc and in-place storage paths.

The standard cases use 30 samples, a 2-second warm-up, and a 5-second measurement target. Heavy ERI cases and MP2 cases with 48 or more AOs use Criterion’s minimum of 10 samples, a 1-second warm-up, and a 2-second target. These are targets: Criterion may take longer to collect the requested samples, especially when each calculation is expensive. Heavy ERI cases remain disabled unless RUSTIQ_BENCH_HEAVY=1 is set. Measurements are saved under target/criterion.

Criterion baselines can be compared only between revisions that both use Criterion and the same benchmark workload. The multiblock MP2 workload has a new Criterion identifier, so its first run establishes a new starting point; do not compare it with the previous single-block mp2/blocked measurements. Legacy timing results also cannot be compared directly with Criterion measurements. MP2 input construction is excluded from measured iterations. Keep CPU architecture, Rayon thread count, build flags, enabled features, MP2 memory budget, power settings, and benchmark environment variables consistent. Save a baseline on the reference revision with the same workload, then compare from the revision under test:

cargo bench --bench mp2_timings --features bench -- --save-baseline before
cargo bench --bench mp2_timings --features bench -- --baseline before

See the MP2 benchmark source and ERI benchmark source. Benchmarks provide performance measurements, not scientific validation.

Generate reproducible reports

From the repository root, the scientific report reuses the canonical PySCF reference cases and their absolute tolerances:

uv run --locked python tools/reference/report.py --output-dir target/scientific-report

It writes full precision results to validation.json and readable tables to validation.md. In addition to the cases run by pytest tools/reference, it includes the frozen-core MP2 variants exercised by those tests at 32 KiB and 512 MiB workspace budgets. Total HF energies and MP2 correlation energies are reported separately. A case fails if either implementation does not converge, an energy comparison exceeds its existing tolerance, or the UHF spin expectation value misses its tolerance. Failed cases remain in the report, and the command returns a nonzero status. The report records software versions, commit and platform metadata so results can be compared across revisions.

Generate Criterion measurements and their report with:

cargo bench --features bench --bench eri_timings
cargo bench --features bench --bench mp2_timings
uv run --locked python tools/benchmarks/report.py

The report is written to target/performance-report/benchmarks.json and benchmarks.md. To produce both reports on GitHub, open Actions → Scientific and performance report → Run workflow on the selected branch or commit. The workflow uploads rustiq-scientific-performance-reports; download that artifact from the completed workflow run to inspect the Markdown and JSON files.

Criterion stores structured estimates in target/criterion; the benchmark executables also write the case dimensions and configuration used by the report generator there. The default runs include the small ERI cases and MP2 AO sizes 12, 24, and 48. To select a smaller local run or opt into the expensive ERI cases, set RUSTIQ_BENCH_FILTER, RUSTIQ_MP2_SIZES, RUSTIQ_MP2_MEMORY, and RUSTIQ_BENCH_HEAVY as described above. The report includes Criterion means and confidence intervals. Its configured MP2 workspace is not measured peak RSS, and synthetic MP2 cases do not model complete molecular calculations. Results are machine-dependent; the on-demand GitHub Actions workflow starts with one small ERI case and AO sizes 12 and 24. To run heavy ERI cases, select Include the heavy ERI cases and choose an ERI filter that matches those cases. The checkbox enables RUSTIQ_BENCH_HEAVY=1; it is disabled by default.

These reports provide numerical regression checks for selected cases. They do not establish general chemical accuracy; see the scientific scope for the limits of HF, MP2, and numerical agreement. Equal numeric convergence thresholds do not mean that RustiQ and PySCF use identical convergence tests.

Independent AO integral validation

The parameterized Cargo tests integral_reference_tests::export_integral_validation::case_N compare production overlap (S), kinetic (T), nuclear attraction (V), and Hcore = T + V matrices with versioned PySCF 2.14.0 fixtures. It compares every matrix entry and every unique unscreened electron-repulsion integral (ERI), in chemists’ notation. No Python installation is needed for Cargo tests. The cases are H2/STO-3G (2 AOs), H2O/STO-3G (7), H2O/6-31G (13), and H2O/cc-pVDZ with spherical 5D (24) and Cartesian 6D (25) functions. The Cartesian cc-pVDZ water case is also rotated by 0.37 radians around the normalized (1, 2, 3) axis with RustiQ’s Geometry::rotate; its independently generated PySCF reference uses the same Rodrigues rotation. This checks the Cartesian integrals with coordinates spanning all three Cartesian axes.

All families use an absolute tolerance of 1e-10 in each family’s units, with no relative acceptance criterion. Measured maxima on these cases are below 9e-14; the threshold leaves margin for floating-point accumulation and platform differences in contracted Hermite/Boys evaluation while remaining below the 1e-8 scale that would require investigation. Relative errors are diagnostic only and are reported for reference magnitudes at least 1e-8. Reports include dimensions, counts, RMS and maximum absolute error, exceedance counts, and the five largest discrepancies with zero-based AO indices and full precision values. For S the units are dimensionless; T, V, Hcore, and ERIs are in atomic units of energy.

The fixtures are generated independently by PySCF/libcint from the same raw checked-in Basis Set Exchange (BSE) JSON exponents and contraction coefficients, not from RustiQ’s normalized primitives. PySCF interprets and normalizes those coefficients independently. This avoids differences in rounded packaged basis sets. Geometry is converted from the checked-in Angstrom XYZ files to Bohr using 0.529177210903 Angstrom/Bohr (CODATA 2018), then supplied explicitly in Bohr. The JSON metadata records source hashes, PySCF version, AO permutation, units, layout, and each numerical array hash. Cargo rejects changed source inputs or array contents; pytest also regenerates every reference array and checks it within 1e-13 absolute units. Regeneration never reads RustiQ integral values.

RustiQ retains atom, BSE shell, and contraction order; PySCF stably sorts shells by angular momentum. Within each p shell RustiQ uses z,y,x versus PySCF x,y,z. The real spherical d order and phases agree: xy, yz, (2zz−xx−yy), xz, (xx−yy), with normalized polynomial combinations. Cartesian order is reversed: RustiQ zz,yz,yy,xz,xy,xx versus PySCF xx,xy,xz,yy,yz,zz. The mapping is constructed from these conventions, never fitted to integral values. PySCF’s Cartesian d functions have radial normalization: multiply its xx,yy,zz functions by sqrt(5/(4π)) and xy,xz,yz by sqrt(15/(4π)) to obtain unit-normalized monomials. These factors follow from angular integrals of squared monomials, 4π/5 and 4π/15, respectively. The reference generator checks the resulting unit overlap diagonals. A separate analytic coefficient test compares the spherical d polynomials with PySCF’s Cartesian-to-spherical transformation, checking phases that the planar water geometry alone cannot distinguish. This positive diagonal scaling has condition number sqrt(3); there is no fitted rotation or phase adjustment. The Cartesian extension changes only the in-memory shell representation, preserving every source exponent and coefficient and leaving fixtures and production defaults unchanged. See the authoritative PySCF basis construction source and integral interface.

Reproduce the independent comparisons and verify the fixtures:

cargo test -p rustiq-chem-core --lib integral_reference_tests
nix develop .#mini-pyscf --command pytest tools/reference
# Equivalent non-Nix workflow:
uv run --locked pytest tools/reference
# Intentionally regenerate versioned NumPy arrays and provenance:
uv run --locked python tools/reference/integrals.py --regenerate
# Write the detailed integral-only machine-readable report:
uv run --locked python tools/reference/integrals.py --report target/integrals.json

NumPy writes individual .npy fixtures; Rust reads them directly through the existing persistence readers backed by npyz. Matrices have two-dimensional shapes and Fortran (column-major) storage. ERIs use lower triangular AO pairs i≥j, followed by lower triangular pairs of pairs p≥q, with pair index i(i+1)/2+j. No full four-index tensor is allocated. The scientific report above includes an independent AO integral section and full precision JSON diagnostics. Harness failures are reported as failures, not omitted.

Three forms of evidence remain distinct: independent integral comparisons check agreement with libcint; internal eightfold compact reconstruction checks validate storage symmetry; end-to-end HF/MP2 comparisons validate selected calculations. The compact reconstruction check is algebraic and does not independently recompute eight permutations. Existing Schwarz screening tests remain separate; this accuracy test passes None to the production threshold interface and does not change default screening. Successful checks establish agreement only for these geometries, contractions, s/p functions, and spherical and Cartesian d functions. They do not establish correctness for higher angular momenta, extreme exponents, arbitrary geometries, or basis completeness.

Documentation checks

The manual uses mdBook, MathJax for equations, and mdbook-mermaid for diagrams. Nix is optional. Run the commands below from the repository root.

Build the offline manual

The complete documentation build and checks are:

nix build .#book

Open result/index.html. The derivation builds the book, bundles pinned MathJax resources and Mermaid assets, tests supported Rust snippets, and checks local links and HTML fragments. Its build runs without networking once Nix has fetched its declared inputs.

Without Nix, install mdbook and mdbook-mermaid using Cargo or equivalent packages, and provide Python 3.12 or later with pytest installed (see the Python tooling setup):

cargo install mdbook --version 0.5.2 --locked
cargo install mdbook-mermaid --version 0.17.1 --locked
python tools/build-manual.py
mdbook test docs
pytest tools/test_book_links.py tools/test_release_smoke.py
python tools/check-book-links.py docs/book --config docs/book.toml --offline
git diff --check

Open docs/book/index.html. The builder downloads the pinned MathJax 2.7.9 npm archive, verifies its SHA-256 digest, installs Mermaid resources, and builds the HTML. It replaces mdBook’s CDN loader with relative local MathJax paths, using SVG equations so reading local files does not require web fonts. MathJax’s license is preserved in mathjax/LICENSE in the output. Use mdbook-mermaid 0.17.1 with mdBook 0.5: it fixes the theme button identifiers used by the diagram initializer. The browser check also exercises light and dark theme changes with networking disabled. The local installation follows MathJax’s installation guidance.

To build with networking disabled, supply the already downloaded, matching MathJax 2.7.9 npm archive; the documentation tools must also be installed:

python tools/build-manual.py --mathjax-archive /path/to/mathjax-2.7.9.tgz

Both routes produce the same relocatable manual. Readers need a browser, but no checkout, Python, Rust, mdBook, or network connection. External reference links, repository links, and edit links still require networking. Generated docs/book/, docs/mermaid.min.js, and docs/mermaid-init.js are ignored by Git and must not be committed.

Preview while editing

The Nix rust and full shells include mdBook and mdbook-mermaid. For a live preview, enter nix develop .#rust if using Nix, then run:

mdbook-mermaid install docs
mdbook serve docs --open

This direct mdBook preview uses its CDN MathJax loader. To inspect the offline result, stop the server, rerun the offline builder above, and open the generated index.html. Running mdbook build or mdbook serve directly regenerates the unmodified CDN loader; it does not produce the distributable offline manual.

Release integration and coverage

The release and six-target rehearsal workflows build the Nix book once and supply it as manual/html/ to every archive build. For a local dist build, first prepare that directory:

nix build .#book
mkdir -p manual/html
cp -R result/. manual/html/
dist build --artifacts=local --target x86_64-unknown-linux-gnu

Use the target for the native operating system and architecture. The generated manual/html/ directory is ignored by Git. The Nix package installs the same book under share/doc/rustiq/manual/html and checks rustiq docs --print-path against its installed index. Cargo builds and published crates do not bundle the book.

Verification coverage is explicit:

  • The book build checks chapter structure, sample includes, and Mermaid assets.
  • The link checker validates local links, assets, and HTML fragments. Its --offline mode also rejects remote HTML runtime resources; external reference links remain allowed. It does not execute JavaScript or fetch URLs.
  • Documentation CI also runs tools/check-manual-browser.py against the built book in Chromium with networking disabled, checking file navigation, styles, rendered SVG equations, and Mermaid diagrams. To reproduce, install playwright==1.64.1 and its Chromium browser in a separate Python environment, then run python tools/check-manual-browser.py docs/book (or result).
  • mdbook test validates supported Rust blocks; this edition has no Rust snippets. It does not execute shell, TOML, XYZ, or Nickel examples.
  • CLI integration tests exercise relocated archive and Nix layouts, an incomplete manual, browser failures, explicit web selection, and Cargo’s online-only behavior. Archive rehearsals verify the packaged manual path and required MathJax/Mermaid assets after relocation.
  • Main CI validates CLI samples, configuration, batches, and PySCF comparisons. Documentation CI does not repeat that scientific suite. The first-calculation chapter identifies its numerical reference, tolerance, and reproduction command.

The Documentation workflow validates pull requests and supports manual runs. Publish documentation runs on pushes to develop and explicit release dispatches and deploys the validated book to GitHub Pages. Set the repository’s Pages source to GitHub Actions. PR builds have no Pages write permission.

Published versions

Pushes to develop publish the current book at /RustiQ/dev/. Release workflow dispatches at version tags publish immutable snapshots at /RustiQ/vX.Y.Z/, for example /RustiQ/v0.1.0-beta.1/; a retry fails if the stored commit or generated content differs. The gh-pages branch stores the complete assembled site, including earlier snapshots. GitHub Pages must remain configured to deploy using GitHub Actions, not from that branch. Publication is serialized, and pull requests only validate the book.

/RustiQ/beta/ points to the highest published beta and /RustiQ/stable/ to the highest stable release; the stable alias appears only when a stable release exists. The root redirects to the highest stable release, otherwise the highest prerelease, otherwise development. Release tags must match the package version and point to an ancestor of main; publication fetches main and rejects tags outside its history.

The root 404.html uses the same release preference as the homepage, with an absolute site path independent of the missing URL’s nesting depth. Versioned 404 pages retain their version-specific asset base. These changes apply only to the published website; the offline manual remains relocatable.

Initial migration

Before enabling the first publication, choose one of these procedures. Keep Pages configured for GitHub Actions in both cases. In the repository’s Actions tab, select Publish documentation and disable the workflow using its menu; wait for any active run to finish before preparing the branch so a run cannot migrate an incomplete seed. Re-enable it after seeding. Re-enabling alone does not publish: the next push to develop or a valid release dispatch triggers publication.

Existing populated gh-pages branch: inspect its root tree and confirm that it contains the old published HTML paths, including pages removed from the current book. If it does, leave those files in place and enable publication. The first run inventories their HTML paths, replaces them with redirects to the corresponding dev/ paths, removes old root assets, and records "legacy_source": "existing-root" in versions.json. A removed development page ultimately reaches the site-wide 404 fallback.

Fresh or empty gh-pages branch: previous Actions deployments do not automatically populate this branch. To preserve their paths, obtain the complete HTML tree from the last successful deployment’s retained Pages artifact or an archived copy before migration. Extract the artifact so index.html and the chapter directories are directly in a local directory, for example /tmp/previous-manual. If the downloaded artifact is a ZIP containing artifact.tar, unpack both layers:

mkdir -p /tmp/previous-pages-artifact /tmp/previous-manual
unzip /path/to/github-pages.zip -d /tmp/previous-pages-artifact
tar -xf /tmp/previous-pages-artifact/artifact.tar -C /tmp/previous-manual
test -f /tmp/previous-manual/index.html

Inspect the extracted paths and contents before proceeding. In a separate clone, seed the branch as follows:

git clone https://github.com/mveril/RustiQ.git /tmp/rustiq-pages-seed
cd /tmp/rustiq-pages-seed
git switch --orphan gh-pages
git rm -rf --ignore-unmatch .
cp -R /tmp/previous-manual/. .
git add -A
git commit -m "Seed previously published manual for migration"
git push origin gh-pages

Use this orphan procedure only when the remote branch does not exist. If an empty branch already exists, use the following in the separate clone instead of the orphan sequence:

git switch --track origin/gh-pages
cp -R /tmp/previous-manual/. .
git add -A
git commit -m "Seed previously published manual for migration"
git push origin gh-pages

Inspect the seeded tree before enabling publication; then follow the populated-branch procedure above. Do not replace an already versioned site or delete its versions.json or snapshots.

If no archive is available, publication can start from the fresh branch, but only paths in the current book receive legacy redirects. The script emits a warning and records "legacy_source": "current-book-only"; it cannot recover removed historical paths. No live website is downloaded or scraped. The legacy_redirects flag records completion of redirect generation, not proof that all historical paths were available.

Migration runs once. Subsequent runs retain its provenance and legacy redirects, refresh the root 404 fallback, and leave existing release snapshots immutable. Identical release retries succeed; conflicting content or source commits fail before modifying the site.

/RustiQ/versions.json lists releases in descending SemVer order, their URLs, channels and source commit IDs, along with the latest aliases and development URL. URLs in the index are relative to the site root. The index is static and does not require an API. The offline book remains separate.

For a local assembly test, run python tools/publish-docs.py result SITE COMMIT --development, or replace --development with --version v0.1.0-beta.1. COMMIT is the full source commit ID and SITE is a writable directory. For example, the index contains entries of this form (the commit is abbreviated here for readability):

{
  "legacy_redirects": true,
  "legacy_source": "existing-root",
  "development": "dev/",
  "latest_beta": "v0.1.0-beta.1",
  "latest_stable": null,
  "versions": [{"version": "v0.1.0-beta.1", "url": "v0.1.0-beta.1/", "channel": "beta", "commit": "..."}]
}

Repository rename

The current public Pages base remains https://mveril.github.io/RustiQ/. After renaming the repository to mveril/rustiq, configure Pages to deploy via GitHub Actions, update the documentation base URL and the site-specific 404 base, then publish and verify the new site and release links. GitHub repository redirects do not guarantee redirects for the old Pages URL: arrange and verify a separate redirect for the old Pages site before relying on existing links. Previously published binary URLs cannot be changed.