import sys
import numpy as np
import pyscf
from pyscf import gto
CASES = [
dict(
name="h2_sto3g",
basis="sto-3g",
geometry="H 0.0 0.0 0.0\nH 0.0 0.0 0.7408",
threshold_pq=1.0e-14,
),
dict(
name="h2o_def2svp",
basis="def2-svp",
geometry="O 0.0 0.0 0.0\nH 0.0 0.757 0.587\nH 0.0 -0.757 0.587",
threshold_pq=1.0e-14,
),
]
def dump_shells(mol):
shells = []
for atom in range(mol.natm):
symbol = mol.atom_symbol(atom)
for entry in mol._basis[symbol]:
l = int(entry[0])
rows = [[float(value) for value in row] for row in entry[1:]]
ncolumn = len(rows[0]) - 1
assert all(len(row) == ncolumn + 1 for row in rows), entry
exponents = [row[0] for row in rows]
for column in range(ncolumn):
shells.append(
dict(
atom=atom,
l=l,
exponents=exponents,
coefficients=[row[1 + column] for row in rows],
)
)
return shells
def internal_shells(mol):
return [(int(row[1]), int(row[2])) for row in mol._bas]
PYSCF_TO_CUEST_ORDER = {0: [0], 1: [2, 0, 1], 2: [2, 3, 1, 4, 0]}
def cuest_ao_order(shells):
order = []
offset = 0
for shell in shells:
l = shell["l"]
if l not in PYSCF_TO_CUEST_ORDER:
raise RuntimeError(f"no pyscf/cuEST AO mapping for l = {l}")
order.extend(offset + i for i in PYSCF_TO_CUEST_ORDER[l])
offset += 2 * l + 1
return order
def fmt(value):
if isinstance(value, float):
return repr(value)
if isinstance(value, (list, tuple)):
return "[" + ", ".join(fmt(v) for v in value) + "]"
return repr(value)
def dump_case(case):
mol = gto.M(
atom=case["geometry"],
basis=case["basis"],
unit="Angstrom",
cart=False,
verbose=0,
)
shells = dump_shells(mol)
dumped = [(shell["l"], len(shell["exponents"])) for shell in shells]
internal = internal_shells(mol)
assert dumped == internal, (case["name"], dumped, internal)
assert sum(2 * shell["l"] + 1 for shell in shells) == mol.nao_nr()
nao = mol.nao_nr()
order = cuest_ao_order(shells)
assert sorted(order) == list(range(nao))
s = mol.intor("int1e_ovlp")[np.ix_(order, order)]
t = mol.intor("int1e_kin")[np.ix_(order, order)]
v = mol.intor("int1e_nuc")[np.ix_(order, order)]
symbols = [mol.atom_symbol(i) for i in range(mol.natm)]
xyz = np.array([mol.atom_coord(i, unit="Angstrom") for i in range(mol.natm)])
assert s.shape == (nao, nao)
lines = []
lines.append("[[cases]]")
lines.append(f"name = {fmt(case['name'])}")
lines.append(f"basis = {fmt(case['basis'])}")
lines.append("pure = true")
lines.append(f"threshold_pq = {fmt(case['threshold_pq'])}")
lines.append(f"symbols = {fmt(symbols)}")
lines.append(f"xyz_angstrom = {fmt([float(x) for x in xyz.ravel()])}")
lines.append(f"nao = {nao}")
for key, matrix in (("s", s), ("t", t), ("v", v)):
lines.append(f"{key} = {fmt([float(x) for x in matrix.ravel()])}")
for shell in shells:
lines.append("")
lines.append("[[cases.shells]]")
lines.append(f"atom = {shell['atom']}")
lines.append(f"l = {shell['l']}")
lines.append(f"exponents = {fmt(shell['exponents'])}")
lines.append(f"coefficients = {fmt(shell['coefficients'])}")
lines.append("")
return lines
def main():
output = sys.argv[1] if len(sys.argv) > 1 else "reference.toml"
lines = [
"# Auto-generated by gen_reference.py; do not edit manually.",
f"# pyscf {pyscf.__version__}",
"",
]
for case in CASES:
lines.extend(dump_case(case))
lines.append("")
with open(output, "w") as fh:
fh.write("\n".join(lines))
print(f"wrote {output}")
if __name__ == "__main__":
main()