vibeqc.basis_crystal¶
CRYSTAL-format basis-set parser and NWChem/.g94 emitter.
Targets the per-element CRYSTAL basis-set files distributed by the
Bredow group (Peintinger–Vilela Oliveira–Bredow, pob-*): one file
per element, named ZZ_Sym (e.g. 06_C), plain-text CRYSTAL input.
Supported today¶
All-electron shells (S, SP, P, D, F, G) and explicit INPUT effective
core potentials (the 200+Z atoms of the Rb-I and Cs-Po pob-*
archives). emit_g94() writes the shells as a .g94 libint loads,
emit_ecp_sidecar() the ECPs as the .ecp sidecar every SCF route
reads beside it, and emit_crystal() both back as CRYSTAL input.
Not supported¶
CRYSTAL’s library pseudopotentials (HAYWSC, STUTSC, …) and the
spin-orbit INPSOC form: their parameters are not in the text.
CRYSTAL per-element format summary¶
- Line 1::
Z NSHELL
- or for ECP-using atoms::
(200 + Z) NSHELL
- Each shell starts with::
ITYPE LAT NG CHE SCAL
where
ITYPE– 0 = user-defined (the only case the Bredow files use).LAT– shell angular-momentum code:0=S, 1=SP, 2=P, 3=D, 4=F, 5=G.
NG– number of primitive Gaussians.CHE– formal occupancy (electrons) assigned to this shell.SCAL– scale factor s on the exponents: CRYSTAL usesexponent * s**2(the Pople zeta-scaling convention), and for this general-basis type both 1.0 and 0.0 mean as-written. Seecrystal_exponent_factor().
Followed by NG lines of exponent coefficient (or exponent
s_coef p_coef for SP shells).
Functions
|
Build ECP data for a PeriodicSystem from parsed CRYSTAL atom bases. |
Flatten a |
|
|
Factor CRYSTAL multiplies a shell's exponents by for |
|
Convert per-element basis specs into CRYSTAL inline-basis format. |
|
Write the ECP blocks of CRYSTAL atom records as a |
|
Convert a list of per-element basis specs into a single .g94 (Gaussian / NWChem format) string that libint can load. |
|
Download the Bredow group all-electron basis sets, parse them, and optionally convert them to .g94 files loadable by libint. |
|
Parse a single CRYSTAL per-element basis file. |
Convenience wrapper: parse a CRYSTAL per-element file from disk. |
|
|
Split a multi-element CRYSTAL inline basis block into per-element specs. |
|
The element-Z block of a CRYSTAL inline basis text. |
|
The shell's effective exponents, with its |
Classes
|
Parsed per-atom basis set (one Bredow file). |
|
Parsed CRYSTAL effective-core-potential block. |
|
One Gaussian term inside a CRYSTAL ECP angular-momentum block. |
|
One contracted Gaussian shell in CRYSTAL format. |
|
Flat primitive arrays in the exact shape |
- vibeqc.basis_crystal.crystal_exponent_factor(scal)[source]¶
Factor CRYSTAL multiplies a shell’s exponents by for
SCAL.CRYSTAL scales a general (
ITYB=0) shell’s exponents bySCAL**2, the Pople convention in whichSCALis the Slater zeta andalpha(zeta) = zeta**2 * alpha(1)(Hehre, Stewart & Pople, J. Chem. Phys. 51, 2657 (1969)). Both 1.0 and 0.0 leave the exponents as written; 0.0 selects the standard Pople factor only for the built-inITYB=1STO-nG sets (CRYSTAL23 manual, section 2.2.1, note 2).The manual (section 2.2.1, p. 25) calls
SCALonly a “scale factor”, so the square was settled by calculation: CRYSTAL23 1.0.1 RHF on H2 with a shell written as (a, SCAL s) gives the same energy, to every printed digit, as (a*s**2, SCAL 1) and as (a*s**2, SCAL 0), and prints the exponents a*s**2 in its basis-set table; (a*s, SCAL 1) is 0.8 mEh away.tests/test_basis_crystal.pypins those energies.vibe_basis.io.exportcarries a copy of this rule, because vibe-basis does not import vibe-qc; keep the two in step.
- class vibeqc.basis_crystal.CrystalShell(shell_type, occupancy, scale_factor, exponents=<factory>, coefficients=<factory>, coefficients_p=<factory>)[source]¶
Bases:
objectOne contracted Gaussian shell in CRYSTAL format.
The shell’s effective exponents are
exponentstimescrystal_exponent_factor()ofscale_factor, exactly as CRYSTAL reads anITYB LAT NG CHE SCALshell. The parser applies that factor on the way in and returnsscale_factor=1.0, so a parsed shell’sexponentsare already effective. A shell built by hand may carry unscaled exponents and aSCAL; every emitter applies the factor (scaled_exponents()).- Parameters:
- vibeqc.basis_crystal.scaled_exponents(shell)[source]¶
The shell’s effective exponents, with its
SCALapplied.- Parameters:
shell (CrystalShell)
- Return type:
- class vibeqc.basis_crystal.CrystalECPTerm(ell, alpha, coefficient, n_pow)[source]¶
Bases:
objectOne Gaussian term inside a CRYSTAL ECP angular-momentum block.
Encodes the contribution
V_ℓ_term(r) = C . r^n . exp(-a . r^2)
in the standard Stuttgart-Köln / Hay-Wadt convention.
ellis the angular momentum (0=s, 1=p, …, 4=g) – or the special label"local"for the M-counted local-potential terms in CRYSTAL’s eq. 3.18.
- class vibeqc.basis_crystal.CrystalECP(znuc, m_local, m_per_ell=(), terms=<factory>)[source]¶
Bases:
objectParsed CRYSTAL effective-core-potential block.
Built from the
INPUT-keyword block that follows a200+Zatom header in CRYSTAL-format basis files. Carries everything libecpint needs to build the V_ECP operator: the effective nuclear charge (Z_eff = Z - ncore), and the per-ℓ Gaussian expansion of the local + ℓ-projected potentials.The CRYSTAL ECP convention has up to five ℓ-projected components (ℓ = 0..4) plus a “local” group counted by
Min the header.termscollects them all in source order; group them byterm.ellto match a specific potential expansion.- terms: list[CrystalECPTerm]¶
- class vibeqc.basis_crystal.CrystalAtomBasis(Z, has_ecp, shells=<factory>, ecp=None)[source]¶
Bases:
objectParsed per-atom basis set (one Bredow file).
- Parameters:
Z (int)
has_ecp (bool)
shells (list[CrystalShell])
ecp (CrystalECP | None)
- shells: list[CrystalShell]¶
- ecp: CrystalECP | None = None¶
- vibeqc.basis_crystal.parse_crystal_atom_basis(text, source='<string>')[source]¶
Parse a single CRYSTAL per-element basis file.
sourceis used only in error messages.- Parameters:
- Return type:
- vibeqc.basis_crystal.parse_crystal_atom_basis_file(path)[source]¶
Convenience wrapper: parse a CRYSTAL per-element file from disk.
- Parameters:
- Return type:
- vibeqc.basis_crystal.parse_crystal_inline_basis(text, source='<string>')[source]¶
Split a multi-element CRYSTAL inline basis block into per-element specs.
The inverse of
emit_crystal(). Whereparse_crystal_atom_basis()reads one element’s file, this reads the concatenated block that goes into a.d12deck afterENDGEOM:12 5 <- Mg 0 0 8 2.0 0.0 ... 8 4 <- O 0 0 8 2.0 0.0 ... 99 0 <- terminator
Why it exists: the basis-optimization engines exchange candidate bases as exactly this text (
EnergyEngine.crystal_energy’sbasis_text). An engine that computes a crystal needs every element’s block, and an engine computing an isolated atom needs the right one. Reading only the first block and relabelling it with the requestedZ– which is what the vibe-qc engine used to do – silently gives O the Mg basis, which converges and is wrong.Splitting is line-structural (the CRYSTAL inline format is one record per line), then each per-element slice is handed to
parse_crystal_atom_basis()so all the token-level quirks it handles – theSCALtypo, the exponent-scale convention, the positive-exponent guard – apply identically here.An ECP
INPUTblock after a200+Zheader is framed by its ownZNUC M M0 M1 M2 M3 M4record (M + M0 + ... + M4term records follow), which is whatemit_crystal()writes. CRYSTAL’s library pseudopotentials (HAYWSC,STUTSC, …) and the spin-orbitINPSOCform carry no parameters vibe-qc reads, so they are refused.- Parameters:
- Returns:
One entry per element, in source order.
- Return type:
- Raises:
ValueError – On a malformed block, a CRYSTAL built-in shell (
ITYPE != 0), a pseudopotential other thanINPUT, or a duplicated element.
- vibeqc.basis_crystal.parse_crystal_inline_element(text, Z, source='<string>')[source]¶
The element-Z block of a CRYSTAL inline basis text.
Picks by the block’s own atomic number. A reader that takes the first block and stamps Z on it gives O the Mg basis for MgO, which converges and is wrong; two optimizer readers did that until 2026-10.
- Raises:
KeyError – If no block is for Z.
- Parameters:
- Return type:
- class vibeqc.basis_crystal.LibecpintInlineArrays(exponents, coefficients, ams, ns, local_ell, max_proj_ell)[source]¶
Bases:
objectFlat primitive arrays in the exact shape
libecpint::ECPIntegrator:: set_ecp_basis(...)expects for one ECP center.Mapping convention (per CRYSTAL23 Sec.”Effective core pseudo-potentials” p. 84, eqs. 3.18 + 3.19, against libecpint’s XML convention where the local channel sits at
lval = max_proj_ell + 1):- CRYSTAL
M(ell="local"term group) -> libecpint
ams[i] = local_ell = max_proj_ell + 1. This is the U_L channel that acts on all angular momenta (no projector applied), matching the local-potential semantics in CRYSTAL eq. 3.18.
- CRYSTAL
- CRYSTAL
M_ℓ(ell in {0..4}term groups, with non-zero count) -> libecpint
ams[i] = ℓ. Projected channels; libecpint applies P_ℓ during integration.
- CRYSTAL
- CRYSTAL
NKL(the literal power of r in eqs. 3.18 + 3.19) -> libecpint
ns[i] = NKL + 2. libecpint takes the Gaussian-format power and subtracts two, so a Stuttgart r^0 term is NKL = 0 here andns[i] = 2there.
- CRYSTAL
Both conventions yield the same V_ECP matrix elements when summed against the basis. Verified against ecp10mdf.xml (K, Z=19) shell layout: local at lval=4 with placeholder zero, projectors at lval= 0..3 for s/p/d/f, max projector ell = 3.
- Parameters:
- vibeqc.basis_crystal.crystal_ecp_to_libecpint_arrays(ecp)[source]¶
Flatten a
CrystalECPinto libecpint primitive arrays.The conversion is bookkeeping – no algebraic rewrite of the ECP. Each
CrystalECPTermbecomes one primitive with its (alpha, coefficient) carried over verbatim; theelllabel is re-keyed onto libecpint’s per-primitiveamconvention and the radial power is converted between the two conventions (seeLibecpintInlineArraysfor both mappings).Phase 14g pairs this with a C++
compute_ecp_matrix_inlinethat calls libecpint’sset_ecp_basis(...)(the inline- primitive form) instead ofset_ecp_basis_from_library(...)(the XML form used today). That unblocks the 5th-period pob basis sets (Rb-I, Cs-Po) and any future inline-ECP archives (vDZP, mixed-row dhf-*).- Parameters:
ecp (CrystalECP) – Parsed CRYSTAL ECP block from
parse_crystal_atom_basis().- Returns:
Bundle ready to feed libecpint’s inline-primitive API.
- Return type:
- Raises:
ValueError – If a term carries an unrecognised
elllabel (not"local"and not in 0..4).
- vibeqc.basis_crystal.emit_ecp_sidecar(atoms, header_comment='')[source]¶
Write the ECP blocks of CRYSTAL atom records as a
.ecpsidecar.The layout is the one
vibeqc.basis_toolkit.exporter_g94renders next to every ECP-bearing orbital file andvibeqc.ecp_metadata.parse_inline_ecp_sidecar()reads back:Ag 0 Ag-ECP 4 28 g potential 1 2 1.0 0.0 s-g potential ...
Channels come straight from
crystal_ecp_to_libecpint_arrays(), so the sidecar round-trips to the exact primitive arrays the periodic driver feeds libecpint; the headerlmaxis that bridge’s local channel andncore = Z - Z_eff. A record without local terms gets the conventional zero placeholder so the local channel is present. Atoms without an ECP are skipped.- Parameters:
atoms (Sequence[CrystalAtomBasis])
header_comment (str)
- Return type:
- vibeqc.basis_crystal.build_periodic_ecp_data(system, atoms)[source]¶
Build ECP data for a PeriodicSystem from parsed CRYSTAL atom bases.
- Parameters:
system (PeriodicSystem)
atoms (list[CrystalAtomBasis])
- Return type:
- vibeqc.basis_crystal.emit_g94(atoms, header_comment='')[source]¶
Convert a list of per-element basis specs into a single .g94 (Gaussian / NWChem format) string that libint can load.
Every exponent and coefficient is written with shortest round-trip precision (
_exact_number()), so the file carries exactly the doubles ofatoms. Each shell’s CRYSTALSCALis applied to its exponents (scaled_exponents()); a parsed shell hasscale_factor1.0, so its exponents pass through unchanged.- Parameters:
atoms (Sequence[CrystalAtomBasis])
header_comment (str)
- Return type:
- vibeqc.basis_crystal.emit_crystal(atoms)[source]¶
Convert per-element basis specs into CRYSTAL inline-basis format.
Produces text suitable for pasting into a CRYSTAL
.d12input deck after the geometry block (ENDGEOM). The format is:Z NSHELL 0 LAT NPG OCC SCALE exp1 coeff1 exp2 coeff2 ... 99 0 END
where LAT = 0(S), 1(SP), 2(P), 3(D), 4(F), 5(G). For SP shells each primitive line carries both s and p coefficients. Every number is written with shortest round-trip precision (
_exact_number()), so CRYSTAL andparse_crystal_inline_basis()read back the doubles ofatoms.ECP-bearing atoms (
has_ecp=True) are emitted with200+Zas the header number, followed by theirINPUTpseudopotential block (_crystal_ecp_lines()). All-electron atoms emit the raw Z.- Parameters:
atoms (Sequence[CrystalAtomBasis]) – Sequence of
CrystalAtomBasisobjects, typically parsed from the Bredow-group per-element CRYSTAL files viaparse_crystal_atom_basis()orparse_crystal_atom_basis_file().- Returns:
Multi-line CRYSTAL basis-set block ready for insertion into a
.d12deck.- Return type:
- Raises:
ValueError – On an atomic number outside 1-98, a shell type CRYSTAL has no LAT code for, a
200+Zatom without its ECP, or an ECP term projecting l > 4.
- vibeqc.basis_crystal.fetch_bredow_basis_sets(dest_dir=None, names=None, *, verbose=True, return_atoms=False)[source]¶
Download the Bredow group all-electron basis sets, parse them, and optionally convert them to .g94 files loadable by libint.
- Parameters:
dest_dir (str | Path | None) – Directory for the .g94 output files. There is no default destination: with
dest_dir=Nonenothing is written and the call only parses, which is useful only withreturn_atoms=True(a call that would do neither raisesValueError). The default used to be a directory inside the installed package, so any caller that only wanted the records – the runtime ECP fallback, the ECP tests – rewrote a tracked file of whatever tree it ran in (#393). A maintainer refreshing the committed copy passes that directory explicitly.names (Iterable[str] | None) – Subset of basis-set keys to fetch (from
_BREDOW_ARCHIVES).Nonefetches all supported light-element archives.verbose (bool) – Print progress + citation info.
return_atoms (bool)
- Returns:
dict mapping basis name -> path of the generated .g94 file (empty when
dest_dirisNone); withreturn_atoms=True, a tuple of thatdict and the parsed records per basis name.
- Return type:
dict[str, Path] | tuple[dict[str, Path], dict[str, list[CrystalAtomBasis]]]