Auto-citations: from .out to manuscript bibliography

You finished a hybrid-DFT/dispersion calculation, the energies look right, and now the journal wants a bibliography. In most QC codes that’s the moment you fire up Google Scholar and start cross-referencing your input file against the manuals. vibe-qc writes the bibliography for you. This tutorial walks through the workflow from input to ready-to-paste BibTeX.

We’ll use a single small system — the water dimer with PBE0/D3(BJ) on def2-TZVP — because it exercises a representative slice of the citation database: a hybrid functional (two papers), a dispersion correction (two papers), an Ahlrichs basis, libint, libxc, and DIIS.

The input

Save the script and geometry side by side:

~/vibeqc-runs/water-dimer/
    input-water-dimer.py
    water-dimer.xyz

water-dimer.xyz:

6
H2O dimer — Cs symmetric, R(O...O) ≈ 2.91 Å
O   0.00000   0.00000  -1.45500
H   0.00000   0.75700  -2.06200
H   0.00000  -0.75700  -2.06200
O   0.00000   0.00000   1.45500
H   0.00000   0.57100   2.02900
H   0.00000  -0.57100   2.02900

input-water-dimer.py:

from pathlib import Path

from vibeqc import Molecule, run_job

HERE = Path(__file__).parent

mol = Molecule.from_xyz(HERE / "water-dimer.xyz")

run_job(
    mol,
    basis="def2-tzvp",
    method="rks",
    functional="PBE0",
    dispersion="d3bj",
    output=HERE / "output-water-dimer-pbe0",
)

Run it from a venv-activated shell:

python input-water-dimer.py

What lands in the directory

After ~5 s on a modern laptop:

output-water-dimer-pbe0.out
output-water-dimer-pbe0.system
output-water-dimer-pbe0.molden
output-water-dimer-pbe0.xyz
output-water-dimer-pbe0.bibtex          # ← new in v0.8.x
output-water-dimer-pbe0.references      # ← new in v0.8.x

The .out file ends with a ## References block; the .bibtex sibling carries the BibTeX entries; the .references sibling has a numbered Chicago-style plain-text version. We’ll look at each in turn.

Reading the .out reference block

Open output-water-dimer-pbe0.out and scroll to the bottom:

## References

Please cite the references below when reporting results
from this run. The corresponding BibTeX entries are
written to the .bibtex sibling.

  [1] Peintinger, Michael F. (2026). vibe-qc: a quantum-chemistry code for
     molecules and solids. [Software v0.8.0, MPL-2.0]. <https://vibe-qc.com/>

  [2] Valeev, Edward F. Libint: A library for the evaluation of molecular
     integrals of many-body operators over Gaussian functions. [Software].
     <https://github.com/evaleev/libint>

  [3] Weigend, Florian and Ahlrichs, Reinhart (2005). Balanced basis sets of
     split valence, triple zeta valence and quadruple zeta valence quality for
     H to Rn: design and assessment of accuracy. Physical Chemistry Chemical
     Physics, 7(18), 3297--3305. doi:10.1039/B508541A

  [4] Lehtola, Susi, Steigemann, Conrad, et al. (2018). Recent developments in
     libxc - A comprehensive library of functionals for density functional
     theory. SoftwareX, 7, 1--5. doi:10.1016/j.softx.2017.11.002

  [5] Perdew, John P., Burke, Kieron, and Ernzerhof, Matthias (1996).
     Generalized Gradient Approximation Made Simple. Physical Review Letters,
     77(18), 3865--3868. doi:10.1103/PhysRevLett.77.3865

  [6] Adamo, Carlo and Barone, Vincenzo (1999). Toward reliable density
     functional methods without adjustable parameters: The PBE0 model. Journal
     of Chemical Physics, 110(13), 6158--6170. doi:10.1063/1.478522

  [7] Pulay, Péter (1980). Convergence acceleration of iterative sequences.
     The case of SCF iteration. Chemical Physics Letters, 73(2), 393--398.
     doi:10.1016/0009-2614(80)80396-4

  [8] Pulay, Péter (1982). Improved SCF convergence acceleration. Journal of
     Computational Chemistry, 3(4), 556--560. doi:10.1002/jcc.540030413

  [9] Grimme, Stefan, Antony, Jens, et al. (2010). A consistent and accurate
     ab initio parametrization of density functional dispersion correction
     (DFT-D) for the 94 elements H-Pu. Journal of Chemical Physics, 132(15),
     154104. doi:10.1063/1.3382344

  [10] Grimme, Stefan, Ehrlich, Stephan, and Goerigk, Lars (2011). Effect of
     the damping function in dispersion corrected density functional theory.
     Journal of Computational Chemistry, 32(7), 1456--1465.
     doi:10.1002/jcc.21759

Each entry is independently justified by what the job did:

#

Why it fired

[1]

Software citation — always first

[2]

libint — used for every two-electron integral

[3]

def2-TZVP — the basis set

[4]

libxc — fires whenever a functional is set

[5]

PBE component of PBE0 (Perdew-Burke-Ernzerhof 1996)

[6]

PBE0-specific hybrid mixing (Adamo-Barone 1999)

[7]

Pulay’s original DIIS paper (default SCF accelerator)

[8]

Pulay’s DIIS follow-up

[9]

Grimme’s D3 base parametrisation

[10]

D3(BJ) damping-function extension

The runtime walks the same routes every time. Swap PBE0 for B3LYP and entries [5]/[6] are replaced by Becke 1993 + LYP 1988 + Stephens 1994 + VWN 1980. Drop the dispersion keyword and [9]/[10] disappear. Make it a periodic job and Togo-Tanaka 2018 (spglib) joins the list.

Pulling the BibTeX into your manuscript

output-water-dimer-pbe0.bibtex carries the same entries in BibTeX form. Excerpt:

@software{peintinger_vibeqc,
  author      = {Peintinger, Michael F.},
  title       = {vibe-qc: a quantum-chemistry code for molecules and solids},
  year        = 2026,
  url         = {https://vibe-qc.com/},
  version     = {0.8.0},
  license     = {MPL-2.0},
  note        = {Always cite. A peer-reviewed publication is forthcoming; this software citation is the canonical reference until then.}
}

@article{weigend_ahlrichs_def2_2005,
  author      = {Weigend, Florian and Ahlrichs, Reinhart},
  title       = {Balanced basis sets of split valence, triple zeta valence and quadruple zeta valence quality for H to Rn: design and assessment of accuracy},
  journal     = {Physical Chemistry Chemical Physics},
  volume      = 7,
  number      = 18,
  pages       = {3297--3305},
  year        = 2005,
  doi         = {10.1039/B508541A}
}

@article{adamo_barone_1999,
  author      = {Adamo, Carlo and Barone, Vincenzo},
  title       = {Toward reliable density functional methods without adjustable parameters: The PBE0 model},
  journal     = {Journal of Chemical Physics},
  volume      = 110,
  number      = 13,
  pages       = {6158--6170},
  year        = 1999,
  doi         = {10.1063/1.478522}
}

@article{grimme_d3bj_2011,
  author      = {Grimme, Stefan and Ehrlich, Stephan and Goerigk, Lars},
  title       = {Effect of the damping function in dispersion corrected density functional theory},
  journal     = {Journal of Computational Chemistry},
  volume      = 32,
  number      = 7,
  pages       = {1456--1465},
  year        = 2011,
  doi         = {10.1002/jcc.21759}
}

Drop the file into your LaTeX project’s bibliography sources and reference each entry by its bibtex_key:

% main.tex
\usepackage[backend=biber, style=chem-acs]{biblatex}
\addbibresource{output-water-dimer-pbe0.bibtex}

\begin{document}
Single-point energies were computed at the PBE0~\cite{adamo_barone_1999}
level with the D3(BJ)~\cite{grimme_d3_2010,grimme_d3bj_2011} dispersion
correction and the def2-TZVP~\cite{weigend_ahlrichs_def2_2005} basis set,
as implemented in vibe-qc~\cite{peintinger_vibeqc}.
\end{document}

That’s the whole loop. biber main resolves every key against the auto-generated .bibtex file. No hand-copying, no Google Scholar.

Regenerating citations after the fact

If you lost the .bibtex / .references files (a cluster transfer dropped them, the run predates the citation surface, …) the vibeqc-cite console script reads the .system manifest and re-emits them:

# Print the plain-text refs to stdout:
vibeqc-cite output-water-dimer-pbe0

# Or rewrite the sibling files:
vibeqc-cite output-water-dimer-pbe0 --write

# BibTeX only, to stdout (handy for grep / piping):
vibeqc-cite output-water-dimer-pbe0 --bibtex-only

The CLI loads the same database the SCF would have walked at run time, so the output is bit-identical to what run_job would have written. Useful for pre-v0.8.x runs whose manifests predate the auto-citation work and for porting a paper draft to a different machine without re-running every SCF.

Combining bibliographies across runs

If your manuscript involves several runs (HF reference + PBE + PBE0, say), append the .bibtex files into one source. biber is deduplicating-aware as long as the keys match — and bibtex_key values are deliberately stable across runs:

cat output-*.bibtex > manuscript-references.bibtex

Each file starts with the same peintinger_vibeqc + valeev_libint preamble, but biber merges them. The same applies to anyone combining a vibe-qc bibliography with their existing manuscript references — keys never clash because the database uses <first_author>_<subject>_<year> and the standard chemistry literature naming convention picks the same authors.

When a route is missing

If you use a feature that isn’t in the bundled database yet — say you pin a custom libxc id by passing functional="xc_id_502" — the runtime emits a warning rather than a crash:

# --- citation routing warnings ---
# no citation route for functional 'xc_id_502'

This block is appended to .references. The fix is in two layers:

  1. For your manuscript right now: look up the specific functional in the libxc references list (xc_func_info on the libxc CLI, or the libxc documentation) and add the matching citation to your .bibtex by hand.

  2. For everyone else: extend the database. The contract is spelled out in AGENTS.md § “Citation database ownership” and the schema in the citations user guide; patches welcome. If you added a functional to vibe-qc and forgot the database entry, CI will catch it via tests/test_citations.py::test_required_functional_has_a_route.

Inspecting the bibliography without running SCF

For tutorial writing or manuscript drafting it’s often useful to see the bibliography for a planned calculation before running it. The same machinery is exposed as a Python API:

from vibeqc.output import OutputPlan
from vibeqc.output.citations import load_default_database

plan = OutputPlan.from_run_job_kwargs(
    output="preview",
    method="RKS",
    basis="def2-tzvp",
    functional="PBE0",
)

db = load_default_database()
cits = db.assemble_from_plan(plan, dispersion="d3bj")

for i, c in enumerate(cits, 1):
    print(f"[{i}] ({c.bibtex_key}) {c.title}")

prints the same ordered key list the SCF would have emitted. The citations user guide has the full API reference, including the per-call flags for periodic / ECP / FFTW / ASE.

Resources

This tutorial completes in under 10 seconds on a modern laptop; peak memory is <200 MB. The bibliography assembly itself is O(routes) and runs in microseconds — it adds no measurable overhead on top of the SCF.

References

The papers above are themselves the references for this tutorial. The auto-citation surface itself rests on:

Next