Installation

vibe-qc is a Python package with a C++ core. The C++ core links against libint (Gaussian integrals), libxc (XC functionals), spglib (crystal symmetry), FFTW3 (Ewald long-range Hartree), libecpint (effective-core potentials), plus a pinned snapshot of pugixml + libcerf inside libecpint’s tree.

See also

Once installation is done, good practices covers the working conventions for actually using vibe-qc — where to put your calculations (hint: not inside the source tree), naming, reproducibility, performance hygiene, and what to try when SCF diverges. Worth a five-minute read before your first production run.

All native dependencies are vendored. scripts/setup_native_deps.sh fetches each one from upstream, configures it the way vibe-qc needs (e.g. libint with max_am=5 + 1st derivatives), builds, and installs into third_party/<name>/install/. Vendoring eliminates the “which version of libxc / spglib / FFTW does this distro happen to ship?” failure mode — every checkout produces an identical native ABI.

Requirements

System tools the build needs:

  • Python ≥ 3.11 (3.11–3.13 are tested; 3.14 works but ymmv on bleeding-edge wheels)

  • C++17 compiler — AppleClang 13+, GCC 10+, Clang 13+

  • CMake ≥ 3.20 and Ninja

  • git, make, curl, tar

Plus three small system libraries that libint’s code generator uses during its own build (we deliberately don’t vendor these — GMP has arch-specific assembly, and Boost / Eigen are header-only and on every distro):

  • Eigen 3 (3.4+) — header-only

  • Boost — header-only

  • GMP with C++ bindings (gmpxx)

OpenMP comes with the C++ compiler on Linux; on macOS it’s libomp from Homebrew.

Python deps (pybind11, scikit-build-core, numpy, pytest, pyscf, ase) come in through pip from pyproject.toml automatically.

One-shot bootstrap

After installing the system tools below, the install is the same on every platform:

git clone https://gitlab.peintinger.com/mpei/vibeqc.git
cd vibeqc
./scripts/setup_native_deps.sh       # 15–40 min one-time, idempotent
python3 -m venv .venv
.venv/bin/pip install -e '.[test]'

git clone lands you on release (the project’s default branch), which is the latest tagged release. The banner reads Release vX.Y.Z to match the tag. For active development on main instead, add git checkout main after the clone — main is the higher X.Y.dev0 development version and rebuilds with every push. Pin to a specific tag (git checkout v0.4.6) for fully reproducible calculations.

setup_native_deps.sh calls (in order):

  1. build_libint.sh — libint 2.13.1

  2. build_libxc.sh — libxc 7.0.0

  3. build_spglib.sh — spglib 2.7.0

  4. build_fftw.sh — FFTW3 3.3.10

  5. build_libecpint.sh — libecpint + pugixml + libcerf

  6. setup_basis_library.sh — populate python/vibeqc/basis_library/basis/ from libint’s standard set plus our custom additions

Each per-dep script is idempotent — re-running after an interrupted build, or after a git pull that changes only one of them, only rebuilds what’s needed.

Per-platform: install the system tools

macOS (Homebrew)

brew install cmake ninja libomp boost eigen gmp git

Apple Silicon note. Homebrew lives at /opt/homebrew on ARM Macs. vibe-qc’s CMake configuration runs brew --prefix and adds that to CMAKE_PREFIX_PATH automatically, so no manual path setup is needed.

libomp is not optional on macOS. AppleClang ships without OpenMP support, and several vendored deps (spglib in particular) hard-require it. brew install libomp puts the headers + library at $(brew --prefix libomp); vibe-qc’s setup_native_deps.sh auto-detects this on main (commit 973c8f3 and later). On older release branches that pre-date the auto-detect, also export the hint env var before running setup_native_deps.sh / scripts/update.sh:

export OpenMP_ROOT=$(brew --prefix libomp)

Add it to ~/.zshrc if you want it to persist across sessions. Without it, CMake’s FindOpenMP errors out with Could NOT find OpenMP_C (missing: OpenMP_C_FLAGS OpenMP_C_LIB_NAMES) and the spglib configure stops there.

Linux — Arch / Manjaro

sudo pacman -S base-devel cmake ninja git curl gmp eigen boost python

base-devel is the meta-group that carries gcc/g++/make/binutils. python on Arch is 3.13+ as of mid-2026 and bundles pip and the venv module out of the box — no separate python-pip /

Note

Arch’s eigen package is currently version 5.0.1. This works fine — libint 2.13.1 (which we vendor in third_party/libint/) shipped a CMake module that handles both the Eigen 3 and Eigen 5 header layouts. Arch keeps Eigen 5’s headers under /usr/include/eigen3/ for backward compatibility with dependent packages, so no path-mangling is needed on your end.

If you previously installed the AUR eigen3 (3.4.x) package as a workaround, you can safely switch back to the standard eigenyay -S eigen and accept the conflict prompt.

python-virtualenv needed. curl is used by setup_native_deps.sh to fetch libint / libxc / spglib / FFTW / libecpint tarballs.

If you’d rather not install anything system-wide, an AUR helper like yay or paru works the same way:

yay -S base-devel cmake ninja git curl gmp eigen boost python

If you need a specific Python version that differs from Arch’s rolling-release default, pyenv (yay -S pyenv) builds an isolated interpreter under ~/.pyenv without touching the system Python.

Linux — Debian / Ubuntu

sudo apt update
sudo apt install \
    build-essential cmake ninja-build git curl \
    libeigen3-dev libboost-dev libgmp-dev libgmpxx4ldbl \
    python3 python3-dev python3-venv

What each step does

Step

Purpose

OS-package install

C++ compiler, CMake/Ninja, plus the headers libint’s code generator needs at build time (Boost, Eigen, GMP).

setup_native_deps.sh

Fetches and builds libint, libxc, spglib, FFTW3, libecpint into third_party/<dep>/install/. Each dep short-circuits silently if already built.

setup_basis_library.sh

Copies libint’s 90 standard .g94 basis files plus anything in basis_library/custom/ into python/vibeqc/basis_library/basis/. The bundled basis library ships inside the Python package so a stock pip install gets every basis set without the user setting LIBINT_DATA_PATH.

python3 -m venv .venv

Isolates vibe-qc from your system Python.

pip install -e '.[test]'

Drives CMake via scikit-build-core, picks up the vendored libs from third_party/, compiles the pybind11 module, installs in editable mode plus test deps (pyscf, ase, dftd3).

Verifying

.venv/bin/python -c "import vibeqc; vibeqc.print_banner()"

Should print a labeled box with vibe-qc’s version, the build’s git provenance, and every linked native library:

╔══════════════════════════════════════════════════════════════════════════════════════╗
║ Release v0.4.0  —  Quantum chemistry for molecules and solids                        ║
║ © Michael F. Peintinger · MPL 2.0  ·  https://vibe-qc.com                            ║
║ linked: libint 2.13.1 · libxc 7.0.0 · spglib 2.7.0                                   ║
╚══════════════════════════════════════════════════════════════════════════════════════╝

If you cloned from main instead of release, the first line reads dev 0.5.0.dev0 (main @ <sha>) (with a dirty flag if the working tree has uncommitted changes). The exact libint / libxc / spglib versions match what setup_native_deps.sh vendored — currently 2.13.1 / 7.0.0 / 2.7.0 for v0.4.0. The banner exercises the C++ extension under the hood (each linked library reports its own version through the pybind11 module), so seeing it is proof both that the Python side imports and that the native side loaded.

If even that crashes, fall back to the minimal smoke test that isolates the C++ extension load from anything else:

.venv/bin/python -c "import vibeqc; print(vibeqc.hello())"
# vibeqc core alive

Then run the regression suite:

.venv/bin/python -m pytest tests/

855+ tests should pass in about two minutes on a recent machine (the count grows with each phase).

Optional terminal viewer (MolTUI)

Vibe-qc writes Molden files by default for any calculation that calls run_job(...). Those files render in any of Avogadro, Jmol, VMD, PyMOL, Molden, or ChimeraX — but if you’d rather inspect orbitals inline in the terminal (handy on a remote SSH session, or when you’re iterating fast), MolTUI is the right tool. Pure Python; renders geometries, orbitals, and normal modes via Unicode block characters.

Two ways to install it alongside vibe-qc:

1. As a vibe-qc extra — single command, captures the dependency in your install record:

.venv/bin/pip install '.[viewer]'           # from the repo
# or
.venv/bin/pip install 'vibe-qc[viewer]'     # once vibe-qc is on PyPI

2. Interactive script — run any time after the venv is set up; re-runnable, asks before installing each tool:

./scripts/install_optional_tools.sh
# → "Install moltui? [Y/n]"

Pass --yes for non-interactive (CI / Docker) use, or a tool name to install just that one (./scripts/install_optional_tools.sh moltui).

After install:

.venv/bin/python water.py                       # produces water.molden
.venv/bin/moltui water.molden                   # render in the terminal

MolTUI also supports .cube (vibe-qc’s grid output), .fchk, .xyz, .gbw (ORCA), and .hess (ORCA normal modes), so the same install lets you view files from external codes too.

Common issues

./scripts/build_libint.sh: line N: brew: command not found You’re on Linux but the script tried the macOS path. This was fixed in 0.1.0+; pull main and re-run. The script now sniffs uname -s and uses the right toolchain per platform.

“Could not find Libint2 / Libxc / Spglib / FFTW3” CMake didn’t find one of the vendored installs. The most common cause is that setup_native_deps.sh was interrupted partway through. Re-running it is safe — finished deps short-circuit, only the unfinished one rebuilds.

If you genuinely want to point at a system install instead of the vendored one, simply don’t run that dep’s build script. CMake silently falls through to system discovery if third_party/<dep>/install/ is absent.

“error: externally-managed-environment” on macOS You’re trying to pip install against Homebrew’s system Python. PEP 668 blocks this; always use a virtualenv:

python3 -m venv .venv && .venv/bin/pip install -e '.[test]'

libint build is slow The libint code generator produces a large amount of source for max_am=5 plus first derivatives (several thousand files). The compile phase uses Ninja which parallelizes; expect 10–30 min on a modern 8-core machine, longer on Mac minis / small VMs. Set CMAKE_BUILD_PARALLEL_LEVEL to restrict parallelism if you’re running out of RAM.

Python 3.14 + some dependency refuses to build Most scientific packages have wheels for 3.11–3.13; 3.14 is bleeding edge and occasionally missing binary wheels (numpy, pyscf, scipy typically catch up within a few weeks). Stick to 3.12 or 3.13 if you hit this.

rm -rf + rebuild If everything goes sideways:

rm -rf third_party .venv build python/vibeqc/basis_library/basis
./scripts/setup_native_deps.sh
python3 -m venv .venv
.venv/bin/pip install -e '.[test]'

Updating

git pull
./scripts/setup_native_deps.sh     # rebuilds anything whose pinned version moved
.venv/bin/pip install -e '.[test]' --force-reinstall --no-deps

The vendored deps rarely need rebuilding — only if a build_*.sh script bumps its pinned version, which we do as a deliberate commit (visible in git log scripts/).

Picking a build to test against

vibe-qc’s runtime banner records which git revision produced any output (see docs/release_process.md). When you want to run calculations against a specific build for testing — comparing against release, validating a topic-branch fix, etc. — check out that ref before running setup_native_deps.sh:

git fetch origin
git checkout release        # or v0.1.0, or some-topic-branch
./scripts/setup_native_deps.sh
.venv/bin/pip install -e '.[test]' --force-reinstall --no-deps

The banner on the next run will then read e.g. Release v0.1.0 or dev 0.1.0 (some-topic-branch @ abc1234), which is what you’ll see prepended to every persisted SCF log.