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 suiteMultiwfn-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

chrg

atomic charges (Mulliken, Löwdin, Hirshfeld, NPA, CM5, ADCH, MBIS, …)

bond

bond orders & valence (Mayer, Wiberg, IBSI, fuzzy, multicenter)

mpol

electric moments (dipole, quadrupole) and atomic polarizabilities

qtaim

QTAIM (Bader) topology, critical points, and basin integration

elf

ELF/LOL basins and domains

arom

aromaticity indices (HOMA, BIRD, FLU, PDI, MCI, …)

cdft

conceptual-DFT reactivity and Fukui functions

orb

orbital composition, localization, indices

nbo

NBO / IAO / IBO analysis

spin

spin density and ⟨S²⟩

esp

electrostatic potential on a surface / at nuclei

spec

orbital DOS, HOMO–LUMO gap, band centers

mesh

real-space fields on a grid (NCI, IGM, cube export)

geom

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?