Quickstart: your first calculation#

This chapter gets you from a blank Python prompt to a real quantum-chemistry result in a few lines. We will compute the energy of a water molecule, switch the method to DFT, and read out an atomic-charge property — enough to see the whole shape of a qc-rs calculation.

Note

Before you start You need qc-rs installed and importable (import qc works). If not, do Installation & the build first.

Run your first calculation#

Type this into a Python session (or a script, or a Jupyter notebook cell):

import qc

# 1. Build a checkpoint: water, in the cc-pVDZ basis, coordinates in ångström.
mychk = qc.chk.new(
    atom="O 0.0000 0.0000 0.1173; H 0.0000 0.7572 -0.4692; H 0.0000 -0.7572 -0.4692",
    ao="cc-pvdz",
    unit="angstrom",
)

# 2. Add a restricted Hartree–Fock (RHF) step, and run it.
mychk = mychk.scf(ref="r").run()

# 3. Read the result.
print(f"energy    = {mychk.scf.energy:.6f} hartree")
print(f"converged = {mychk.scf.converged}")

You should see:

energy    = -76.026772 hartree
converged = True

That is a complete Hartree–Fock calculation. Congratulations — you just solved the electronic Schrödinger equation (approximately!) for water.

What just happened?#

Three ideas, one per line:

  1. qc.chk.new(...) builds a checkpoint — the object that holds your molecule and, later, all results. Here we gave it the geometry (atom=), the basis set (ao="cc-pvdz"), and the unit of the coordinates (unit="angstrom").

  2. .scf(ref="r") adds a step — a self-consistent-field calculation. ref="r" means restricted (closed-shell) Hartree–Fock. Adding a step does no heavy computation yet; it just records what you want.

  3. .run() does the work, and afterwards mychk.scf.energy reads the result back out.

This build-then-run pattern is the heart of qc-rs. We look at it properly in Core concepts.

Tip

Watch it run: run(log=...) By default .run() is silent — it just computes. Pass run(log="stdout") to stream a live, quantum-chemistry-style transcript instead: the system summary, the SCF cycle-by-cycle energy table, and the convergence check. A few options you will reach for early — log_style="modern"/"orca" picks the visual style, and plot=True draws the SCF convergence curve inline (in a notebook with %matplotlib inline). After a run, mychk.log() replays the transcript without recomputing. The full set is shown in Editor setup and the Logging & output chapter.

Tip

Make it faster: nthread= By default a calculation uses a single CPU core. Pass run(nthread=8) to spread the work across 8 cores of your machine — shared-memory thread parallelism that speeds up almost every run on a laptop or a single node, with no extra setup. (Running across many machines with MPI process parallelism, nmpi=, is more advanced — we introduce it later in Parallel computing & HPC. For now, nthread= is all you need.)

The result carries much more than the energy. For instance mychk.scf.ncycle is how many SCF iterations it took to converge, and mychk.scf.energy_components breaks the total energy into its physical pieces (kinetic, nuclear attraction, Coulomb, exchange, …). You will meet these as you need them.

Tip

A Python note f"...{mychk.scf.energy:.6f}..." is an f-string — Python substitutes the value of the expression in {...} into the text, and :.6f formats it with six digits after the decimal point.

Switch to DFT#

Want density-functional theory instead of Hartree–Fock? Change one thing — add a functional with xc=:

mydft = qc.chk.new(
    atom="O 0.0000 0.0000 0.1173; H 0.0000 0.7572 -0.4692; H 0.0000 -0.7572 -0.4692",
    ao="cc-pvdz", unit="angstrom",
).scf(ref="r", xc="b3lyp").run()

print(f"{mydft.scf.energy:.6f} hartree")   # -76.420369

The B3LYP energy (-76.420369) is lower than the Hartree–Fock one because it includes electron correlation — a concept we develop in Foundations.

Your first property#

An energy is only the beginning. From the same converged calculation you can ask for hundreds of properties. Here are the Mulliken atomic charges:

q = qc.prop.chrg.mulliken(mychk)
print(q["charges"])       # [-0.3060, 0.1530, 0.1530]
print(q["atom_labels"])   # ['O', 'H', 'H']

Oxygen carries a partial negative charge and each hydrogen a partial positive charge — exactly the polarity you expect for water. The whole property suite lives in Molecular properties.

Open-shell molecules (radicals)#

Not every molecule is a closed shell. For a radical — an odd number of electrons, or unpaired spins — use unrestricted Hartree–Fock (ref="u") and set the spin. Here is the methyl radical (CH₃•), a doublet:

ch3 = qc.chk.new(
    atom="C 0 0 0; H 0 1.079 0; H 0.934 -0.539 0; H -0.934 -0.539 0",
    ao="cc-pvdz", unit="angstrom",
    spin=2,                       # spin multiplicity 2S+1: 2 = doublet (one unpaired electron)
).scf(ref="u").run()              # ref="u" = unrestricted

print(f"{ch3.scf.energy:.6f} hartree")     # -39.563802
print(qc.prop.spin.s_squared(ch3))         # 0.7612   (ideal doublet: 0.75)

Tip

A note on spin spin is the multiplicity 2S+1: 1 = singlet (all electrons paired), 2 = doublet (one unpaired), 3 = triplet (two unpaired). Use ref="r" for closed shells, ref="u" (unrestricted) or ref="ro" (restricted-open) for open shells.

The ⟨S²⟩ 0.76 here is close to the ideal 0.75 of a pure doublet; small excesses measure a little spin contamination, which the SCF chapter explains.

Where to next#