Tutorial 45: vibe-view end-to-end walkthrough

You will learn: how to produce a .qvf archive from a routine vibe-qc job, launch vibe-view, and inspect every section the calculation wrote: structure, electron density, the HOMO / LUMO orbitals, the optimisation trajectory, the IR spectrum, and the per-job citation bundle.

Prerequisites:

  • vibeqc installed and a working SCF setup (any tutorial under Fundamentals shows this).

  • vibe-view installed: from the vibe-qc checkout root either pip install -e '.[viewer-gpu]' (with vibe-qc) or pip install -e vibe-view/ (standalone). VTK is ~200 MB so the first install is slow.

  • A working modern browser (Chrome, Firefox, Safari, Edge). vibe-view uses Trame + WebSocket; very strict ad-blockers can interfere.

Time to complete: about 5 minutes.

1. Produce a .qvf

Anything in vibe-qc that runs through run_job or run_periodic_job can emit a .qvf by passing output_qvf=True. Here is a small RKS / PBE / 6-31G* water calculation with everything that vibe-view knows how to render:

# input-water-vibe-view.py
from vibeqc import Atom, Molecule, run_job

mol = Molecule([
    Atom(8, [0.0,  0.00,  0.00]),
    Atom(1, [0.0,  1.43, -0.98]),
    Atom(1, [0.0, -1.43, -0.98]),
])

run_job(
    mol,
    basis="6-31g*",
    method="rks",
    functional="PBE",
    optimize=True,                 # writes a trajectory section
    hessian=True,                  # writes vibrations + IR spectrum
    output="water",
    output_qvf=True,               # produces water.qvf
    write_density=True,            # embeds the SCF density isosurface
    write_molden_file=True,        # embeds wavefunction.gto + MO blobs
)

Run it (a few seconds on any modern laptop):

~/path/to/vibeqc/.venv/bin/python input-water-vibe-view.py

Output:

water.out          .  banner + SCF trace + geometry opt log
water.molden       .  MO coefficients (Avogadro / Jmol)
water.traj         .  ASE trajectory (ase gui water.traj)
water.bibtex       .  auto-assembled BibTeX entries
water.references   .  Chicago-style reference list
water.system       .  TOML manifest with hardware + library versions
water.qvf          .  what we will open in vibe-view in a second

Have a peek at the manifest to confirm the sections vibe-view will render:

import zipfile, json
manifest = json.loads(zipfile.ZipFile("water.qvf").read("manifest.json"))
for s in manifest["sections"]:
    print(f"  {s['id']:<15s} {s['kind']}")

Typical output:

  structure       structure
  density         volume.density
  homo            volume.orbital
  lumo            volume.orbital
  wavefunction    wavefunction.gto
  traj0           trajectory
  vib             vibrations
  ir              spectra.ir
  citations       citations
  scf_history     scf_history

2. Launch vibe-view

vibe-view open water.qvf

Two things happen:

  1. Startup banner prints to stdout (the same table you printed from the manifest above, with per-section render status):

    ╔══════════════════════════════════════════════════════════════════════════════╗
    ║  QVF file: water.qvf                                                         ║
    ║  Source:   vibe-qc 0.9.0 - water                                             ║
    ╠══════════════════════════════════════════════════════════════════════════════╣
    ║  structure          structure                    rendered                    ║
    ║  density            volume.density               rendered                    ║
    ║  homo               volume.orbital               rendered                    ║
    ║  lumo               volume.orbital               rendered                    ║
    ║  wavefunction       wavefunction.gto             rendered                    ║
    ║  traj0              trajectory                   rendered                    ║
    ║  vib                vibrations                   rendered                    ║
    ║  ir                 spectra.ir                   rendered                    ║
    ║  citations          citations                    rendered                    ║
    ║  scf_history        scf_history                  rendered                    ║
    ╚══════════════════════════════════════════════════════════════════════════════╝
    
  2. The default browser opens at http://127.0.0.1:8080 with the 3D viewport. The server stays in the foreground; press Ctrl+C in the terminal to stop it.

Tips:

vibe-view open water.qvf --port 9876        # different port
vibe-view open water.qvf --no-browser       # do not auto-open the browser
vibe-view open water.qvf --host 0.0.0.0     # bind to all interfaces (remote use)

3. Walk through what each panel does

The browser window has three regions:

  • Top bar: source banner (program + version + calculation name) and the active-section pill.

  • Sidebar (left): every section from the manifest, classified as rendered / skipped / error. Click any section to make it active.

  • Viewport (centre): 3D scene for structure / volume / trajectory / vibrations, interactive Plotly for bands / spectra, table for atom_properties / scf_history / citations.

Structure

The first section that auto-activates is structure. You see the H2O molecule with CPK-coloured atoms (red oxygen, white hydrogens) and bonds drawn from covalent radii. Rotate with left-drag, pan with middle-drag, zoom with the scroll wheel.

Electron density

Click density in the sidebar. vibe-view marches the cubes at the default isovalue of 0.05 e/bohr^3 and renders the resulting isosurface translucent over the structure. A sidebar control lets you change the isovalue (lower values give a larger lobe; higher values squeeze in toward the nuclei).

This is the right place to see what the SCF actually converged on. For water the lone-pair region behind the oxygen should be the largest pocket of density.

Molecular orbitals (HOMO + LUMO)

Click homo. vibe-view marches the cubes on the orbital .dat payload (real-valued for closed-shell molecular MOs). Because MOs have signed lobes the viewer uses a divergent colormap by default, so you can see the + and - regions. Set the isovalue to ~0.04 bohr^(-3/2) for the standard “balloon” view of an HF-style HOMO.

Click lumo to see the LUMO instead. Both stay loaded; the viewport always shows the active section’s volume.

The full MO set via wavefunction.gto

For more orbitals than just HOMO / LUMO, click wavefunction. vibe-view shows a list of every MO (with energy and occupation) and re-samples each MO from the basis + coefficients when you click it. This is cheaper to produce than writing every MO as a separate volume.orbital section.

Geometry-optimisation trajectory

Click traj0. The viewport switches to a frame-by-frame animation of the geometry-optimisation steps. A play / pause / step strip below the viewport drives the timeline; a small energy chart above it plots the per-frame energies (in Hartree) so you can see the SCF energy decrease monotonically.

For our water optimisation there are only a few frames because the input geometry was already near the minimum; the energy chart drops by a fraction of a mHa and the structure barely moves.

Vibrational modes

Click vib. The viewport renders the equilibrium geometry; a dropdown selector lets you pick a normal mode by frequency (in cm^-1). The atoms oscillate along the displacement vector with the mode’s amplitude.

For water at HF/6-31G* you should see three modes near 1700, 3900, and 4000 cm^-1: the symmetric bend, the symmetric stretch, and the antisymmetric stretch. The stretches mostly move the hydrogens; the bend mostly moves the oxygen.

IR spectrum

Click ir. The viewport switches to an interactive Plotly stem chart of intensities vs frequency. Hover any peak to see the exact frequency and intensity (in km / mol). The chart respects the viewer-defaults x-axis range if the producer set one.

Citations

Click citations at the bottom of the sidebar. The viewport shows the embedded BibTeX bundle as a copy-paste block: every paper the run cites (vibe-qc itself, libint, libxc, PBE, the basis set, plus any dispersion / SCF-accelerator references). This is the same bundle written to water.bibtex on disk; see the citations user guide for the format spec.

SCF history

Click scf_history. Two stacked Plotly panes:

  • Top: SCF energy vs iteration (Hartree).

  • Bottom: |DIIS error| vs iteration (log scale).

Hover any iteration to see the exact numbers. This is the same information vibe-qc writes to water.out as a text table, presented as a chart you can zoom and pan.

4. Periodic example: MgO bands

Periodic systems work the same way. For an MgO rocksalt RHF calculation with an embedded band structure:

# input-mgo-vibe-view.py
import numpy as np
import vibeqc as vq

a = 4.21 / 0.529177                                       # Angstrom to bohr
mgo = vq.PeriodicSystem(
    3,
    np.eye(3) * a,
    [vq.Atom(12, [0.0, 0.0, 0.0]),
     vq.Atom(8,  [a/2, a/2, a/2])],
)
basis = vq.BasisSet(mgo.unit_cell_molecule(), "sto-3g")

# Compute a band structure along a high-symmetry path. Each segment
# is (start_frac, start_label, end_frac, end_label).
kpath = vq.kpath_from_segments(
    mgo,
    segments=[
        ([0.0, 0.0, 0.0], "G", [0.5, 0.0, 0.5], "X"),
        ([0.5, 0.0, 0.5], "X", [0.5, 0.5, 0.5], "L"),
        ([0.5, 0.5, 0.5], "L", [0.0, 0.0, 0.0], "G"),
    ],
    points_per_segment=20,
)

vq.run_periodic_job(
    mgo,
    basis=basis,
    method="RHF",
    output="mgo",
    output_qvf=True,
    write_density=True,
    band_structure=vq.band_structure_hcore(mgo, basis, kpath),
)
vibe-view open mgo.qvf

Two extra sidebar entries appear compared to the molecular case:

  • structure now shows a unit-cell wireframe. Sidebar gains a replication control (Nx, Ny, Nz) to extend the cell along the lattice vectors. Atoms, the cell box, and any active isosurface all expand together.

  • bands opens the Plotly band plot: every band’s eigenvalue along the k-path, with a horizontal line at the Fermi energy. Hover any band to see the energy in eV.

5. Tips and gotchas

Producer-side hints with viewer_defaults

To make a .qvf open with the right defaults (which section to activate, isovalue, colormap, camera bookmarks), pass viewer_defaults= to the QVF writer or build it inside run_job via the output-plan API. vibe-view picks up the hints on load. See the viewer_defaults section of the user guide.

In-memory QVF (skip the disk round-trip)

If you’re scripting vibe-view from a notebook and do not want a .qvf on disk:

import io
from vibeview import launch_qvf

# Build the archive in memory.
buf = io.BytesIO()
# ... use the QVF writer with `buf` as the path ...

buf.seek(0)
launch_qvf(buf, open_browser=False)

launch_qvf accepts any seekable binary file-like, not just paths.

Remote viewing over SSH

For runs on a remote box you can either:

  1. Forward the port: ssh -L 8080:127.0.0.1:8080 remote, then run vibe-view open run.qvf on the remote and open http://127.0.0.1:8080 in your local browser.

  2. Bind vibe-view to the public interface: vibe-view open run.qvf --host 0.0.0.0 --no-browser. Only do this on a trusted network; the Trame server has no authentication.

The cheap alternative for SSH-only access is moltui, which renders to the terminal directly.

vibe-view says “skipped, unsupported” on a section I care about

The kind is not yet in vibe-view/src/vibeview/kinds.py::SUPPORTED_KINDS. Either:

  • The producer wrote a kind under the x_<vendor>.* namespace, which the viewer never tries to render by design (the namespace is reserved for producer-specific extensions).

  • The kind is implemented on the writer but not yet on the viewer. The full matrix is in the QVF design doc § 1.4. Adding a renderer is a three-step contribution: add the kind to SUPPORTED_KINDS, drop a renderer module in vibe-view/src/vibeview/renderers/, and wire the activation branch in vibe-view/src/vibeview/app.py. The existing renderers are short (~100 to ~200 lines each) and serve as templates.

What next