Periodic systems¶
vibe-qc supports 1D, 2D, and 3D periodicity through a single
PeriodicSystem type. Dimensionality is specified by dim ∈ {1, 2, 3};
the lattice matrix is always a full-rank 3×3.
See also
periodic_methods.md- comparative tour of vibe-qc’s periodic-SCF kernels (BIPOLE, GDF, GPW/GAPW), a bonding-organised example gallery, and the end-to-end surface-reactions workflow.crystal_lattices.md— the 14 Bravais lattices, with visualisations + worked examples for each common lattice (rocksalt, diamond, perovskite, HCP, wurtzite, rutile, corundum, α-quartz, graphene).k_points.md— Monkhorst-Pack mesh generation and Brillouin-zone sampling.multi_k_scf.md— multi-k SCF: current ship state (Γ-only native GDF), parity target, scope caveats.ewald.md— Ewald summation for periodic Coulomb.
Born-von Karman PBC contract¶
The periodic stack follows the same lattice-general Born-von Karman boundary-condition model used by CRYSTAL-style Gaussian crystal codes:
The input lattice is an arbitrary full-rank matrix whose columns are the Cartesian direct-lattice vectors in bohr. There are no cubic-, hexagonal-, or orthorhombic-only branches in the public periodic method interfaces.
sysp.reciprocal_lattice()is generated automatically as \(2\pi A^{-T}\), so \(a_i \cdot b_j = 2\pi\delta_{ij}\) for triclinic cells just as for cubic cells.Monkhorst-Pack, Gamma-centred, and explicit k-lists are stored in fractional reciprocal coordinates and converted through that reciprocal matrix.
Real-space lattice sums enumerate integer Born-von Karman image vectors and then apply Cartesian cutoff / screening tolerances. Tight production crystals should use the GDF/FFTDF track; direct truncated sums remain a debug/reference path.
Bravais centering is represented either by primitive vectors or by additional basis atoms in a conventional cell. The Coulomb, k-point, GDF, FFT, and SCF interfaces should not special-case
P,I,F,C, orRcentering labels.
Regression coverage pins this contract on representative triclinic, monoclinic, orthorhombic, tetragonal, trigonal, hexagonal, and cubic metrics, plus CRYSTAL-style target structures: FCC diamond, BCC Fe, hexagonal graphene, and Al2O3 stoichiometry in a skew hexagonal cell. The native Γ-GDF RHF/RKS path is also smoke-tested on those 3D crystal metrics and on non-orthogonal 1D / 2D embedding cells.
import numpy as np
from vibeqc import Atom, PeriodicSystem
# 1D chain — column 0 of lattice is the lattice vector, the other two
# columns are implicit vacuum axes with enough separation to decouple
# images.
sysp_1d = PeriodicSystem(
dim=1,
lattice=np.diag([4.0, 30.0, 30.0]),
unit_cell=[Atom(1, [0, 0, 0]), Atom(1, [0, 0, 1.4])],
)
# 2D slab. Prefer vq.slab_2d: give only the two in-plane lattice
# vectors and the atoms at their real z. The third lattice column is
# synthesized for you and is NOT a vacuum gap; the SCF is invariant to
# it. Building a dim=2 PeriodicSystem by hand works too, but then the
# third column is still only bookkeeping.
sysp_2d = vq.slab_2d(
[2.5, 0.0, 0.0],
[0.0, 2.5, 0.0],
[Atom(6, [0, 0, 0])],
)
# 3D bulk — all three columns are lattice vectors.
sysp_3d = PeriodicSystem(
dim=3,
lattice=np.diag([5.4, 5.4, 5.4]), # Si conventional cubic, bohr
unit_cell=[Atom(14, [0, 0, 0]), Atom(14, [0.25, 0.25, 0.25])],
)
Accessors¶
sysp.reciprocal_lattice() # 3×3 matrix, columns = b_i with a_i · b_j = 2π δ_ij
sysp.n_electrons() # total electrons per unit cell (Z - charge)
sysp.unit_cell_molecule() # Molecule view for BasisSet() construction
Space-group analysis¶
from vibeqc import attach_symmetry
attach_symmetry(sysp) # populates sysp.symmetry via spglib
print(sysp.symmetry)
# SpaceGroup(number=227, symbol='Fd-3m', order=48)
SpaceGroup carries number (International Tables), international_symbol,
hall_number, point_group, and the full list of symmetry operations.
POSCAR I/O¶
from vibeqc import read_poscar, write_poscar
sysp = read_poscar("tests/data/NaCl.poscar") # returns Crystal
# To convert between Crystal and PeriodicSystem, see the next section.
standard = read_poscar(
"tests/data/NaCl.poscar",
symmetrise=True,
to_primitive=True,
)
sysp_clean = standard.system # returns PeriodicSystem
CIF I/O¶
from vibeqc import read_cif
crystal = read_cif("MgO.cif") # returns Crystal
standard = read_cif(
"MgO.cif",
symmetrise=True,
to_primitive=True,
)
sysp_clean = standard.system # returns PeriodicSystem
The CIF reader handles cell lengths/angles, fractional
_atom_site_* loops, uncertainty suffixes such as 4.210(1), and
standard CIF symmetry-operation loops. When symmetry operations are
present, asymmetric-unit sites are expanded to the full unit cell
before Crystal construction.
Extended-XYZ I/O¶
Periodic Extended-XYZ stores the lattice in the comment line using the
ASE convention: Lattice="a_x a_y a_z b_x ... c_z" with lattice
vectors as rows in Ångström. vibe-qc converts that to the internal
column-vector bohr convention when periodic mode is requested:
from vibeqc import from_xyz
sysp = from_xyz("MgO.xyz", periodic=True) # returns PeriodicSystem
standard = from_xyz(
"MgO.xyz",
symmetrise=True,
to_primitive=True,
)
sysp_clean = standard.system # returns PeriodicSystem
Plain molecular from_xyz(path) is unchanged and still returns a
Molecule. For plain XYZ files that carry no Lattice="..." tag,
pass an explicit 3×3 lattice= matrix in Ångström and, if needed,
dim=1, dim=2, or dim=3.