Input scripts and output files

A classic quantum-chemistry workflow means running a job and getting back a text log, plus files a viewer can open. vibeqc.run_job bundles that up so you don’t have to wire it together by hand: one call writes the formatted output, the molden orbital file, and — for optimisation runs — a trajectory animation.

Writing an input script

An input “script” in vibe-qc is just a Python file. The conventional shape:

# input-h2o.py
from pathlib import Path
from vibeqc import Molecule, run_job

HERE = Path(__file__).parent

mol = Molecule.from_xyz(HERE / "h2o.xyz")

run_job(
    mol,
    basis="6-31g*",
    method="rhf",
    output=HERE / "output-h2o",
)

Run it like any Python file:

python3 input-h2o.py

Four ready-to-run examples live under examples/ — single-point RHF, DFT, open-shell UHF, and BFGS geometry optimisation.

Output files

Given output="output-h2o", run_job writes three file families named by the same stem:

output-h2o.out — the text log

Plain ASCII, readable in any editor. Sections, in order:

  1. Banner — vibe-qc + libint + libxc + spglib versions, for provenance. Identical to vibeqc.print_banner().

  2. Job header — method + basis.

  3. Initial atom table — Z + Cartesian bohr + charge + multiplicity

    • electron count.

  4. Optimisation block (only when optimize=True) — target convergence, final optimised geometry.

  5. SCF trace — iteration-by-iteration energy, ΔE, commutator norm, DIIS history length. Flags converged / NOT converged.

  6. Energy components (DFT only) — nuclear repulsion, electronic, Coulomb J, HF-exchange K, XC, total.

  7. Orbital-energy table — all occupied MOs and up to n_virtual=5 virtual MOs (override via n_virtual=...), with HOMO/LUMO markers and the HOMO-LUMO gap in Ha and eV. For UHF/UKS, separate Alpha and Beta blocks with per-spin HOSMO / LUSMO markers and per-spin gaps.

The same content is available programmatically as vibeqc.format_scf_trace(result, molecule=...) — pass it a file handle and a molecule to get a string you can log, print, or splice into your own output layout.

output-h2o.molden — molecular orbitals

Molden-format file carrying:

  • The geometry in atomic units.

  • The full basis set (per-atom, per-shell exponents and contraction coefficients, raw — primitive normalisation is reapplied by the reader).

  • Every molecular orbital: symmetry label (A for now, vibe-qc is not yet symmetry-adapted), orbital energy in Hartree, spin, occupancy (2 for occupied restricted, 1 for each alpha/beta spin-occupied, 0 otherwise), then the AO coefficients reordered from libint’s m = -L..+L convention to Molden’s (m=0, +1, -1, +2, -2, ...) ordering so the file is drop-in for any molden-aware viewer (Jmol, Avogadro, Molden itself, IQmol, MolView).

For unrestricted (UHF/UKS) results the file contains two MO blocks — first the Alpha spin, then the Beta spin — as the Molden format requires.

Open any .molden file via:

# Jmol (cross-platform, Java):
jmol output-h2o.molden

# Avogadro 2 (cross-platform):
avogadro output-h2o.molden

output-h2o.traj — optimisation trajectory

Emitted only when optimize=True. It’s an ASE binary trajectory — one frame per optimiser step, containing atomic positions + energy + forces. View it as an animation with:

ase gui output-h2o.traj

Convert to XYZ for tools that prefer that format:

ase convert output-h2o.traj output-h2o-frames.xyz

Or iterate frames programmatically:

from ase.io import read
frames = read("output-h2o.traj", index=":")
for step, atoms in enumerate(frames):
    print(step, atoms.get_potential_energy())

run_job parameters

Parameter

Default

Purpose

molecule

required

Molecule in bohr coordinates

basis=

required

libint-recognised basis name

method=

"auto"

"rhf" / "uhf" / "rks" / "uks" / "auto"

functional=

None

XC functional name for RKS/UKS (e.g. "PBE", "B3LYP")

output=

"output"

path stem; files become {output}.out, {output}.molden, {output}.traj

optimize=

False

run BFGS (via ASE) before the final SCF

fmax=

0.05

optimiser convergence in eV/Å (ASE convention)

max_opt_steps=

200

optimiser iteration limit

write_molden_file=

True

emit the .molden file

rhf_options= / uhf_options= / rks_options= / uks_options=

None

fine SCF control — override the relevant options struct

method="auto" resolves to:

  • functional set + multiplicity 1 → RKS

  • functional set + multiplicity ≥ 2 → UKS

  • no functional + multiplicity 1 → RHF

  • no functional + multiplicity ≥ 2 → UHF

The return value is the underlying SCF result object (RHFResult, UHFResult, RKSResult, or UKSResult) — so you can continue in Python after the call to inspect MO coefficients, density matrices, or feed the result to downstream post-SCF analysis.

When to use run_job vs the low-level drivers

run_job optimises for the 80% case: one method on one geometry, producing a log and an orbital file. If you want to

  • sweep over basis sets / functionals in one script,

  • compose your own output format,

  • run periodic systems (not yet wired into run_job),

  • or call the SCF drivers with non-default numerical integration grids,

reach for the low-level API (run_rhf, run_rks, etc.) and format_scf_trace directly. Everything run_job does internally is re-usable via the same public API.