Skip to content

Commit 1b7bb62

Browse files
feat: add support for flexible multiplicity in CP2K inputs (#1785)
1 parent ed971ae commit 1b7bb62

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed

dpgen/generator/lib/cp2k.py

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,127 @@
11
import numpy as np
22

3+
atomic_numbers = {
4+
"H": 1,
5+
"He": 2,
6+
"Li": 3,
7+
"Be": 4,
8+
"B": 5,
9+
"C": 6,
10+
"N": 7,
11+
"O": 8,
12+
"F": 9,
13+
"Ne": 10,
14+
"Na": 11,
15+
"Mg": 12,
16+
"Al": 13,
17+
"Si": 14,
18+
"P": 15,
19+
"S": 16,
20+
"Cl": 17,
21+
"Ar": 18,
22+
"K": 19,
23+
"Ca": 20,
24+
"Sc": 21,
25+
"Ti": 22,
26+
"V": 23,
27+
"Cr": 24,
28+
"Mn": 25,
29+
"Fe": 26,
30+
"Co": 27,
31+
"Ni": 28,
32+
"Cu": 29,
33+
"Zn": 30,
34+
"Ga": 31,
35+
"Ge": 32,
36+
"As": 33,
37+
"Se": 34,
38+
"Br": 35,
39+
"Kr": 36,
40+
"Rb": 37,
41+
"Sr": 38,
42+
"Y": 39,
43+
"Zr": 40,
44+
"Nb": 41,
45+
"Mo": 42,
46+
"Tc": 43,
47+
"Ru": 44,
48+
"Rh": 45,
49+
"Pd": 46,
50+
"Ag": 47,
51+
"Cd": 48,
52+
"In": 49,
53+
"Sn": 50,
54+
"Sb": 51,
55+
"Te": 52,
56+
"I": 53,
57+
"Xe": 54,
58+
"Cs": 55,
59+
"Ba": 56,
60+
"La": 57,
61+
"Ce": 58,
62+
"Pr": 59,
63+
"Nd": 60,
64+
"Pm": 61,
65+
"Sm": 62,
66+
"Eu": 63,
67+
"Gd": 64,
68+
"Tb": 65,
69+
"Dy": 66,
70+
"Ho": 67,
71+
"Er": 68,
72+
"Tm": 69,
73+
"Yb": 70,
74+
"Lu": 71,
75+
"Hf": 72,
76+
"Ta": 73,
77+
"W": 74,
78+
"Re": 75,
79+
"Os": 76,
80+
"Ir": 77,
81+
"Pt": 78,
82+
"Au": 79,
83+
"Hg": 80,
84+
"Tl": 81,
85+
"Pb": 82,
86+
"Bi": 83,
87+
"Po": 84,
88+
"At": 85,
89+
"Rn": 86,
90+
"Fr": 87,
91+
"Ra": 88,
92+
"Ac": 89,
93+
"Th": 90,
94+
"Pa": 91,
95+
"U": 92,
96+
"Np": 93,
97+
"Pu": 94,
98+
"Am": 95,
99+
"Cm": 96,
100+
"Bk": 97,
101+
"Cf": 98,
102+
"Es": 99,
103+
"Fm": 100,
104+
"Md": 101,
105+
"No": 102,
106+
"Lr": 103,
107+
"Rf": 104,
108+
"Db": 105,
109+
"Sg": 106,
110+
"Bh": 107,
111+
"Hs": 108,
112+
"Mt": 109,
113+
"Ds": 110,
114+
"Rg": 111,
115+
"Cn": 112,
116+
"Nh": 113,
117+
"Fl": 114,
118+
"Mc": 115,
119+
"Lv": 116,
120+
"Ts": 117,
121+
"Og": 118,
122+
}
123+
124+
3125
default_config = {
4126
"GLOBAL": {"PROJECT": "DPGEN"},
5127
"FORCE_EVAL": {
@@ -121,6 +243,46 @@ def iterdict(d, out_list, flag=None, indent=0):
121243
out_list.insert(index, " " * indent + k + " " + v)
122244

123245

246+
def calculate_multiplicity(atom_names, atom_types, charge=0):
247+
"""
248+
Calculate the multiplicity based on atom species, quantities, and system charge.
249+
250+
This function provides a basic heuristic for determining multiplicity:
251+
- Even number of electrons -> singlet (multiplicity = 1)
252+
- Odd number of electrons -> doublet (multiplicity = 2)
253+
254+
Note: This approach assumes that an odd electron count always results in a doublet state.
255+
It does not account for systems with multiple unpaired electrons, which can have higher
256+
multiplicities (e.g., triplet, quartet, etc.). Users should be aware of this limitation
257+
and use the function accordingly.
258+
259+
:param atom_names: List of element symbols.
260+
:param atom_types: List of atom type indices.
261+
:param charge: System charge (default: 0).
262+
:return: Multiplicity.
263+
"""
264+
# Calculate the total number of electrons
265+
total_electrons = 0
266+
for idx in atom_types:
267+
element = atom_names[idx]
268+
try:
269+
total_electrons += atomic_numbers[element]
270+
except KeyError:
271+
raise ValueError(f"Unknown element '{element}' encountered in atom_names.")
272+
273+
# Subtract/add electrons based on system charge
274+
# Positive charge means we remove electrons, negative charge means we add electrons
275+
total_electrons -= charge
276+
277+
# Determine multiplicity based on the total number of electrons
278+
# Even number of electrons -> singlet (multiplicity = 1)
279+
# Odd number of electrons -> doublet (multiplicity = 2)
280+
if total_electrons % 2 == 0:
281+
return 1
282+
else:
283+
return 2
284+
285+
124286
def make_cp2k_input(sys_data, fp_params):
125287
# covert cell to cell string
126288
cell = sys_data["cells"][0]
@@ -132,14 +294,27 @@ def make_cp2k_input(sys_data, fp_params):
132294
cell_c = np.array2string(cell[2, :])
133295
cell_c = cell_c[1:-1]
134296

297+
atom_names = sys_data["atom_names"]
298+
atom_types = sys_data["atom_types"]
299+
# Get system charge if provided, default to 0
300+
charge = sys_data.get("charge", 0)
301+
dft_params = fp_params.get("FORCE_EVAL", {}).get("DFT", {})
302+
if "MULTIPLICITY" in dft_params:
303+
multiplicity = dft_params["MULTIPLICITY"]
304+
else:
305+
multiplicity = calculate_multiplicity(atom_names, atom_types, charge)
306+
135307
# get update from user
136308
user_config = fp_params
137309
# get update from cell
138310
cell_config = {
139311
"FORCE_EVAL": {"SUBSYS": {"CELL": {"A": cell_a, "B": cell_b, "C": cell_c}}}
140312
}
313+
# get update for multiplicity
314+
multiplicity_config = {"FORCE_EVAL": {"DFT": {"MULTIPLICITY": multiplicity}}}
141315
update_dict(default_config, user_config)
142316
update_dict(default_config, cell_config)
317+
update_dict(default_config, multiplicity_config)
143318
# output list
144319
input_str = []
145320
iterdict(default_config, input_str)

0 commit comments

Comments
 (0)