Molecular properties (qc.prop)#
A converged wavefunction is not the end — it is the starting point for analysis. What are the atomic charges? Where are the bonds, and how strong? Is a ring aromatic? Where will an electrophile attack? qc-rs answers these with a large, built-in molecular-properties suite — Multiwfn-class wavefunction analysis you reach without ever leaving Python. This short page explains how the suite is organized; the following chapters cover each family.
The qc.prop.<group>.<leaf> namespace#
Every property lives at qc.prop.<group>.<leaf>, organized into 14 thematic groups:
group |
what it covers |
|---|---|
|
atomic charges (Mulliken, Löwdin, Hirshfeld, NPA, CM5, ADCH, MBIS, …) |
|
bond orders & valence (Mayer, Wiberg, IBSI, fuzzy, multicenter) |
|
electric moments (dipole, quadrupole) and atomic polarizabilities |
|
QTAIM (Bader) topology, critical points, and basin integration |
|
ELF/LOL basins and domains |
|
aromaticity indices (HOMA, BIRD, FLU, PDI, MCI, …) |
|
conceptual-DFT reactivity and Fukui functions |
|
orbital composition, localization, indices |
|
NBO / IAO / IBO analysis |
|
spin density and ⟨S²⟩ |
|
electrostatic potential on a surface / at nuclei |
|
orbital DOS, HOMO–LUMO gap, band centers |
|
real-space fields on a grid (NCI, IGM, cube export) |
|
geometric analysis (RDF, rotational constants, surface area) |
The next six chapters walk through the most-used families: charges & bond orders, QTAIM & ELF, weak interactions, aromaticity, conceptual-DFT reactivity, and spectra & DOS.
Two equivalent forms#
Every property has a functional form and a method form — they are identical, so use whichever reads better in your code:
import qc
water = "O 0 0 0.117; H 0 0.757 -0.469; H 0 -0.757 -0.469"
m = qc.chk.new(atom=water, ao="cc-pvdz", unit="angstrom").scf(ref="r").run()
qc.prop.chrg.hirshfeld(m) # functional form
m.prop.chrg.hirshfeld() # method form — the same result
They return the same value (verified: both give the O charge −0.32191159).
Lazy, cached, and eager bundles#
Properties are computed on demand and cached by a content hash of the wavefunction — ask for the same property twice and the second call is free; re-run an SCF that changes the density and the cache invalidates automatically. You do not manage any of this.
When you know up front that you want a batch of properties, ask the SCF to compute them eagerly with
scf(prop=...):
m = qc.chk.new(atom=water, ao="cc-pvdz", unit="angstrom").scf(ref="r", prop=True).run()
# prop=True computes a standard bundle; prop=<preset name> or prop=[<refs>] select what to compute
What you need first#
Almost every property needs a converged SCF (a density and orbitals) — so the pattern is always
“.scf(...).run(), then ask for properties.” A few grid-based analyses (QTAIM, ELF, the real-space fields)
are heavier than the charges; they are still one call, just slower. With that, let’s start with the most
common question of all: where is the charge?