forked from materialsproject/pymatgen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathregen_libxcfunc.py
executable file
·121 lines (94 loc) · 3.46 KB
/
regen_libxcfunc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python
"""
This script regenerates the enum values in pymatgen.core.libxc_func.py.
It requires in input the path of the `libxc_docs.txt` file contained in libxc/src
The script parses this file, creates a new JSON file inside pymatgen.core
and update the enum values declared in LibxcFunc.
The script must be executed inside pymatgen/dev_scripts.
"""
from __future__ import annotations
import json
import os
import sys
from copy import deepcopy
def parse_libxc_docs(path):
"""Parse libxc_docs.txt file, return dictionary {libxc_id: info_dict}."""
def parse_section(section):
dct = {}
for line in section:
key, value = line.split(":")
dct[key.strip()] = value.strip()
return int(dct["Number"]), dct
dct = {}
with open(path) as file:
section = []
for line in file:
if not line.startswith("-"):
section += [line]
else:
num, entry = parse_section(section)
assert num not in dct
dct[num] = entry
section = []
assert section == []
return dct
def write_libxc_docs_json(xc_funcs, json_path):
"""Write JSON file with libxc metadata to path jpath."""
xc_funcs = deepcopy(xc_funcs)
# Remove XC_FAMILY from Family and XC_ from Kind to make strings more human-readable.
for dct in xc_funcs.values():
dct["Family"] = dct["Family"].replace("XC_FAMILY_", "", 1)
dct["Kind"] = dct["Kind"].replace("XC_", "", 1)
# Build lightweight version with a subset of keys.
for num, dct in xc_funcs.items():
xc_funcs[num] = {key: dct[key] for key in ("Family", "Kind", "References")}
# Descriptions are optional
for opt in ("Description 1", "Description 2"):
desc = dct.get(opt)
if desc is not None:
xc_funcs[num][opt] = desc
with open(json_path, "w") as fh:
json.dump(xc_funcs, fh)
return xc_funcs
def main():
"""Main function."""
if "-h" in sys.argv or "--help" in sys.argv:
print(__doc__)
print("Usage: regen_libxcfunc.py path_to_libxc_docs.txt")
return 0
try:
path = sys.argv[1]
except IndexError:
print(__doc__)
print("Usage: regen_libxcfunc.py path_to_libxc_docs.txt")
return 1
xc_funcs = parse_libxc_docs(path)
# Generate new JSON file in pycore
pmg_core = os.path.abspath("../pymatgen/core/")
json_path = f"{pmg_core}/libxc_docs.json"
write_libxc_docs_json(xc_funcs, json_path)
# Build new enum list.
enum_list = []
for num, d in xc_funcs.items():
# Remove XC_ from codename
codename = d["Codename"][3:]
enum_list += [f" {codename} = {num}"]
enum_list = "\n".join(enum_list) + "\n"
# Re-generate enumerations.
# [0] read py module.
xc_funcpy_path = f"{pmg_core}/libxcfunc.py"
with open(xc_funcpy_path) as file:
lines = file.readlines()
# [1] insert new enum values in list
start = lines.index("#begin_include_dont_touch\n")
stop = lines.index("#end_include_dont_touch\n")
lines.insert(stop, enum_list)
del lines[start + 1 : stop]
# [2] write new py module
with open(xc_funcpy_path, mode="w", encoding="utf-8") as file:
file.writelines(lines)
print("Files have been regenerated")
print("Remember to update __version__ in libxcfuncs.py!")
return 0
if __name__ == "__main__":
raise SystemExit(main())