Skip to content

Commit b30ef2c

Browse files
Harper GrimsleyHarper Grimsley
Harper Grimsley
authored and
Harper Grimsley
committed
carry on my wayward json
1 parent 259f6b0 commit b30ef2c

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

forte/proc/jsondump.py

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import numpy as np
2+
import psi4
3+
import json
4+
5+
def jsondump(wfn, frozen_docc, active_docc, active_socc, active_uocc, int_cutoff = 1e-13, fname="forte_molecule.json"):
6+
"""
7+
Function to build a JSON file compatible with QForte.
8+
Data is extracted from a Psi4 Wavefunction object.
9+
Assumes ROHF, and that unpaired electrons don't exist outside the
10+
active space
11+
"""
12+
13+
print(f"\nSaving system info to {fname}.\n")
14+
15+
mol = wfn.molecule()
16+
mints = psi4.core.MintsHelper(wfn.basisset())
17+
scalars = wfn.scalar_variables()
18+
E_nuc = scalars["NUCLEAR REPULSION ENERGY"]
19+
20+
ao_oeis = mints.ao_kinetic().np + mints.ao_potential().np
21+
ao_teis = mints.ao_eri().np
22+
num_frozen = np.sum(frozen_docc)
23+
num_active = np.sum(active_docc + active_socc + active_uocc)
24+
25+
#Reorder C so that instead of orbital energy, it is sorted core->active->virtual
26+
#Active space is chosen for aufbau ordering (i.e. doccs, soccs, uoccs)
27+
28+
orbitals = []
29+
for irrep, block in enumerate(wfn.epsilon_a_subset("MO", "ACTIVE").nph):
30+
for orbital in block:
31+
orbitals.append([orbital, irrep])
32+
33+
orbitals.sort()
34+
orb_irreps_to_int = []
35+
for [eps, irrep] in orbitals:
36+
orb_irreps_to_int.append(irrep)
37+
38+
categories = {"frozen_docc": [], "active_docc": [], "active_socc": [], "active_uocc": [], "frozen_uocc": []}
39+
40+
irrep_dict = {}
41+
for i, irrep in enumerate(orb_irreps_to_int):
42+
if irrep not in irrep_dict:
43+
irrep_dict[irrep] = []
44+
irrep_dict[irrep].append(i)
45+
46+
# Assign orbitals to categories based on count constraints
47+
for irrep, orbitals in irrep_dict.items():
48+
count_frozen = frozen_docc[irrep]
49+
count_active_docc = active_docc[irrep]
50+
count_active_socc = active_socc[irrep]
51+
count_active_uocc = active_uocc[irrep]
52+
53+
categories["frozen_docc"].extend(orbitals[:count_frozen])
54+
categories["active_docc"].extend(orbitals[count_frozen:count_frozen + count_active_docc])
55+
categories["active_socc"].extend(orbitals[count_frozen + count_active_docc:count_frozen + count_active_docc + count_active_socc])
56+
categories["active_uocc"].extend(orbitals[count_frozen + count_active_docc + count_active_socc:count_frozen + count_active_docc + count_active_socc + count_active_uocc])
57+
categories["frozen_uocc"].extend(orbitals[count_frozen + count_active_docc + count_active_socc + count_active_uocc:])
58+
59+
for key in categories:
60+
categories[key].sort()
61+
62+
new_order = (categories["frozen_docc"] +
63+
categories["active_docc"] +
64+
categories["active_socc"] +
65+
categories["active_uocc"] +
66+
categories["frozen_uocc"])
67+
68+
C = wfn.Ca_subset("AO", "ALL").np[:, new_order]
69+
70+
71+
72+
#Compute frozen core energy and frozen core one electron integral. (E_fc does NOT include nuclear repulsion.)
73+
Pc = np.einsum('pi,si->ps', C[:,:num_frozen], C[:,:num_frozen])
74+
ao_hc = ao_oeis + 2*np.einsum('psuv,ps->uv', ao_teis, Pc) - np.einsum('puvs,ps->uv', ao_teis, Pc)
75+
E_fc = np.trace(Pc.T@(ao_hc + ao_oeis))
76+
77+
mo_oeis = np.einsum("ui,vj,uv->ij", C, C, ao_oeis)[num_frozen:num_active+num_frozen,
78+
num_frozen:num_active+num_frozen]
79+
80+
mo_teis = np.einsum("pi,qj,rk,sl,pqrs->ijkl", C, C, C, C, ao_teis)[num_frozen:num_active+num_frozen,
81+
num_frozen:num_active+num_frozen,
82+
num_frozen:num_active+num_frozen,
83+
num_frozen:num_active+num_frozen]
84+
85+
86+
87+
nalpha = wfn.nalpha() - np.sum(frozen_docc)
88+
nbeta = wfn.nbeta() - np.sum(frozen_docc)
89+
so_irreps = []
90+
for i in new_order:
91+
so_irreps += [orb_irreps_to_int[i],orb_irreps_to_int[i]]
92+
93+
print(f"({nalpha+nbeta}, {num_active}) active space.\n")
94+
print(f"Ms = {(nalpha - nbeta)/2}\n")
95+
print(f"Nuclear repulsion energy: {E_nuc}")
96+
print(f"Frozen core energy: {E_fc}")
97+
print(f"Total scalar energy: {E_fc + E_nuc}")
98+
99+
external_data = {}
100+
external_data["scalar_energy"] = {}
101+
external_data["scalar_energy"]["data"] = E_fc + E_nuc
102+
external_data["oei"] = {}
103+
external_data["oei"]["data"] = []
104+
105+
external_data["tei"] = {}
106+
external_data["tei"]["data"] = []
107+
108+
kept = []
109+
neglected = [0]
110+
for p in range(num_active):
111+
pa = p*2
112+
pb = p*2 + 1
113+
for q in range(num_active):
114+
qa = q*2
115+
qb = q*2 + 1
116+
oei = float(mo_oeis[p,q])
117+
if abs(oei) > int_cutoff:
118+
kept.append(oei)
119+
external_data["oei"]["data"].append((pa, qa, oei))
120+
external_data["oei"]["data"].append((pb, qb, oei))
121+
else:
122+
neglected.append(oei)
123+
for r in range(num_active):
124+
ra = r*2
125+
rb = r*2 + 1
126+
for s in range(num_active):
127+
sa = s*2
128+
sb = s*2 + 1
129+
130+
tei_J = -float(mo_teis[p,s,q,r])
131+
tei_K = -float(mo_teis[p,r,q,s])
132+
133+
if abs(tei_J - tei_K) > int_cutoff:
134+
kept.append(tei_J - tei_K)
135+
external_data["tei"]["data"].append((pa,qa,ra,sa, tei_J - tei_K))
136+
external_data["tei"]["data"].append((pb,qb,rb,sb, tei_J - tei_K))
137+
else:
138+
neglected.append(tei_J - tei_K)
139+
140+
if abs(tei_J) > int_cutoff:
141+
kept.append(tei_J)
142+
external_data["tei"]["data"].append((pa,qa,ra,sa,tei_J))
143+
external_data["tei"]["data"].append((pb,qb,rb,sb,tei_J))
144+
else:
145+
neglected.append(tei_J)
146+
147+
print(f"\nIntegral cutoff: {int_cutoff}\n")
148+
print(f"{len(kept)}/{pow(num_active,2)*2 + pow(num_active,4)*4} integrals stored.")
149+
print(f"Smallest included electron integral: {np.amin(abs(np.array(kept)))}")
150+
print(f"Largest neglected electron integral: {np.amax(abs(np.array(neglected)))}\n")
151+
152+
external_data["nso"] = {}
153+
external_data["nso"]["data"] = 2 * int(num_active)
154+
external_data["na"] = {}
155+
external_data["na"]["data"] = int(nalpha)
156+
external_data["nb"] = {}
157+
external_data["nb"]["data"] = int(nbeta)
158+
external_data["point_group"] = {}
159+
external_data["point_group"]["data"] = mol.symmetry_from_input().lower()
160+
external_data["symmetry"] = {}
161+
external_data["symmetry"]["data"] = so_irreps
162+
163+
with open(fname, "w") as f:
164+
json.dump(external_data, f, indent = 0)
165+
166+
print(f"\nSystem info saved to {fname}.\n")
167+
168+
169+
170+
171+
172+

0 commit comments

Comments
 (0)