Programmatic API

Starting with v4.2, GoodVibes exposes a clean kwargs-based Python API in addition to the CLI. The same parser and thermochemistry engine power both — the API just wraps calc_bbe in a friendlier signature and returns a structured result.

Quick start

from goodvibes import compute_thermo

r = compute_thermo("structure.log")
print(f"qh-G(T) = {r.qh_gibbs_free_energy:.6f} Hartree")
print(f"level   = {r.level_of_theory}")

compute_thermo returns a frozen ThermoResult dataclass with every attribute calc_bbe produces (energies in Hartree, entropies in Hartree/K, frequencies in cm⁻¹), plus references to the underlying bbe and qcdata for advanced use.

@dataclass(frozen=True)
class ThermoResult:
    file: str                       # absolute path
    name: str                       # basename without extension
    scf_energy: float
    sp_energy: float | None         # None unless --spc was used
    zpe: float
    enthalpy: float
    qh_enthalpy: float | None       # None when QH=False
    entropy: float
    qh_entropy: float
    gibbs_free_energy: float
    qh_gibbs_free_energy: float
    frequency_wn: list[float] | None
    im_frequency_wn: list[float] | None
    inverted_freqs: list[float] | None
    point_group: str | None
    symmno: int | None
    linear_mol: bool
    multiplicity: int | None
    job_type: str | None
    level_of_theory: str | None
    program: str | None             # 'Gaussian', 'Orca', ...
    bbe: Any                        # original calc_bbe instance
    qcdata: Any                     # parsed QCData
    spc_applied: bool               # a single-point energy replaced E in H and G
    # provenance
    temperature: float              # K
    options: ThermoOptions          # every option, with the scale factors resolved
    freq_scale_factor: float
    zpe_scale_factor: float
    scale_factor_source: str | None # 'user' | 'truhlar' | 'mlip-unscaled' | 'none-found'
    symmetry_source: str            # 'output' | 'pymsym' | 'assumed' (sigma = 1)
    n_imag: int | None              # imaginary modes in the output

scale_factor_source says where the vibrational scale factors came from: passed in (user), the Truhlar database for the level of theory (truhlar), unscaled by design for an MLIP input (mlip-unscaled: from ASE, with a level of theory that names no basis set, e.g. MACE-OFF23), or not found (none-found: the frequencies are used unscaled, and a goodvibes.thermo.ScaleFactorWarning says so instead of a silent 1.0). It is None, like n_imag, for an input without frequencies. to_dataframe has a column for each (not options).

Common options

r = compute_thermo(
    "structure.log",
    QS="grimme",            # default — Grimme quasi-RRHO entropy
    s_freq_cutoff=50,       # cm⁻¹ — soften vibrational modes below this
    spc="TZ",               # use 'structure_TZ.log' for the single point
    temperature=313.15,     # K
    concentration=1.0,      # mol/L; defaults to gas-phase 1 atm
    freq_scale_factor=None, # None → auto-lookup from level of theory
)

All keyword names match the CLI flags. Defaults match what the CLI does when those flags aren’t passed.

Batch and parallel processing

from goodvibes import compute_batch
import glob

paths = glob.glob("conformers/*.log")

# Sequential (default).
results = compute_batch(paths)

# Parallel: spawn 8 worker processes.
results = compute_batch(paths, jobs=8)

# Use all available CPU cores.
results = compute_batch(paths, jobs=0)

compute_batch preserves input order. With jobs > 1, parsing and thermochemistry run in a ProcessPoolExecutor; on a typical laptop this gives 2–3× speedup at 8 cores once the file count is large enough to amortise process startup (~50 files).

Pandas DataFrame export

from goodvibes import compute_batch, to_dataframe

results = compute_batch(glob.glob("*.log"))
df = to_dataframe(results)
df.to_csv("thermo.csv", index=False)
df.sort_values("qh_gibbs_free_energy").head()

to_dataframe requires pandas; install with pip install goodvibes[full] (includes pandas, pyarrow, matplotlib, ase and pyyaml).

The CLI flag --csv PATH does the same thing without leaving the shell:

goodvibes *.log --csv thermo.csv

Supporting Information tables

from goodvibes import compute_batch, si_rows, write_si

results = compute_batch(glob.glob("*.log"))
write_si(results, "si.md", units="kcal/mol")    # also .tex, .csv, .tsv, .xyz
rows = si_rows(results)                         # one dict per structure

The CLI flag --si PATH (with --si-units) does the same; see cookbook recipe 4d.

Rates and the energy span

from goodvibes import energy_span, eyring_rate, rate_ratio, step_table

eyring_rate(20.0, 298.15)                        # s⁻¹; kcal/mol unless units= says otherwise
rate_ratio(15.0, 16.0)                           # k(15.0) / k(16.0)
levels = {"I0": 0.0, "TS1": 15.0, "I1": -10.0, "TS2": 8.0, "P": -5.0}
es = energy_span(levels, ["TS1", "TS2"])         # the last point closes the cycle
print(es.span, es.tdts, es.tdi, es.tof)
step_table(levels, ["TS1", "TS2"])               # barrier, k and half-life per step

A reaction-profile document has the same as Profile.energy_span(), Profile.step_table() and Profile.write_mikimo(), at the series’ temperature and in the document’s units.

Skipping a re-parse

If you’ve already parsed an output file (e.g. via :py:func:goodvibes.io.parse_qcdata), pass it in to avoid re-reading:

from goodvibes.io import parse_qcdata
from goodvibes import compute_thermo

qc = parse_qcdata("structure.log")
r = compute_thermo(qcdata=qc)

A QCData can also be built without any file, from an ASE Atoms and a vibrational analysis (QCData.from_atoms, QCData.from_vibrations); see cookbook recipe 4b.

What’s new in v4.x at a glance

  • v4.1 — Selectivity redesign. N-way --label NAME=PATTERN (or --selectivity FILE.yaml) replaces the 2-only --ee a:b. Outputs Boltzmann-averaged AND lowest-conformer-only tables. Structured SelectivityResult exposed on the JSON output.

  • v4.1 — --json PATH. Structured output (schema v1.0) with per-file thermochemistry, parsed metadata, options, plus optional selectivity and pes blocks.

  • v4.2 — PES rewrite. New 3-layer model (ConformerSet/Point/Pathway); true-YAML input format alongside the legacy line-based format (auto-detected, deprecated); stoichiometric sums (2*A + B); --lowest-only mode for “lowest qh-G conformer per species” PES tables.

  • v4.2 — Programmatic API. This page.

  • v4.6 — Profile model. ConformerSet.from_results with public ensemble rollups (populations, ensemble_free_energy, s_conf, dedup) that re-evaluate each structure at any temperature (ComputedEntry); point roles and display labels; pathway edges; Series (a quantity at a temperature, computed or declared); plot_profile with a merged x axis, temperature / quantity / literature overlays and layout="panels"; QCData.from_atoms / from_vibrations for file-free ASE and MLIP inputs; every class importable from goodvibes. See the cookbook, recipes 4 and 4b.

  • 5.1 — Selectivity on the profile. SelectivityResult v2 (major, signed ee_signed, ratio, ensemble_energies); the reaction-profile 1.1 selectivity block with Curtin–Hammett checks (Profile.evaluate_selectivity, goodvibes-profile selectivity); compute_selectivity_batch / summarize_selectivity for sweeps over temperatures, entropy cutoffs and conformer windows; plot_boltzmann_histogram, plot_temperature_scan; Profile.diff and goodvibes-profile diff. See cookbook recipe 3b.

  • Reaction-profile documents. load_profile / Profile read, validate, evaluate, write, tabulate and plot reaction-profile/1.0 documents; goodvibes --profile writes one and goodvibes-profile works with them without output files. See the reaction-profile format.

  • v4.2 — --jobs N parallel parsing. ~3× speedup at 8 cores.

  • v4.2 — --csv PATH. Per-structure DataFrame export.

  • v4.2 — ORCA CPU-time scaling. ORCA prints wall time only; GoodVibes now multiplies by the parsed MPI process count to give an effective CPU time, matching the Gaussian/NWChem/xTB convention. Footnoted on the TOTAL CPU line.

See the project ROADMAP for what is planned next and CHANGELOG.md for what has shipped.