rsspolymlp 0.3.2__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rsspolymlp-0.3.2/src/rsspolymlp.egg-info → rsspolymlp-0.3.4}/PKG-INFO +1 -1
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/pyproject.toml +1 -1
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/phase_analysis.py +88 -33
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/rss_summarize.py +10 -13
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/struct_match.py +13 -12
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/api/cli_rsspolymlp.py +0 -9
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/api/cli_rsspolymlp_devkit.py +13 -0
- rsspolymlp-0.3.4/src/rsspolymlp/api/cli_rsspolymlp_utils.py +148 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/api/rsspolymlp.py +8 -32
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/api/rsspolymlp_devkit.py +20 -2
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/api/rsspolymlp_plot.py +2 -2
- rsspolymlp-0.3.4/src/rsspolymlp/api/rsspolymlp_utils.py +150 -0
- rsspolymlp-0.3.4/src/rsspolymlp/mlp_dev/dataset/divide_dataset.py +212 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/dataset/gen_mlp_dataset.py +30 -19
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/eliminate_duplicates.py +50 -4
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/optimization_mlp.py +3 -1
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/examples/example.py +2 -2
- rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/harmonic_real.py +379 -0
- rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/opt_geometry_sscha.py +471 -0
- rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/opt_position_sscha.py +179 -0
- rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/run_opt_sscha.py +415 -0
- rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/sscha_property.py +271 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4/src/rsspolymlp.egg-info}/PKG-INFO +1 -1
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/SOURCES.txt +7 -2
- rsspolymlp-0.3.4/tests/test_cli_help.py +39 -0
- rsspolymlp-0.3.2/src/rsspolymlp/analysis/load_plot_data.py +0 -36
- rsspolymlp-0.3.2/src/rsspolymlp/api/cli_rsspolymlp_utils.py +0 -58
- rsspolymlp-0.3.2/src/rsspolymlp/api/rsspolymlp_utils.py +0 -46
- rsspolymlp-0.3.2/src/rsspolymlp/mlp_dev/dataset/divide_dataset.py +0 -130
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/LICENSE +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/README.md +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/setup.cfg +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/eos.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/ghost_minima.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/chiral_spg.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/invert_and_swap.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/irrep_position.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/niggli.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/struct_match.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/utils.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/invert_and_swap.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/reduced_position.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/unique_struct.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/api/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/api/cli_rsspolymlp_plot.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/common/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/common/atomic_energy.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/common/composition.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/common/convert_dict.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/common/property.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/dataset/compress_vasprun.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/estimate_cost.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/gen_hybrid_model.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/gen_single_model.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/n_feature.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/pypolymlp_gridsearch.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/reduce_grid.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/pareto_opt_mlp.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/polymlp_dev.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/load_logfile.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/random_struct.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/lammps_utils.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/custom_plt.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/examples/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/examples/template.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/make_plot.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/pymatgen_utils.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/spglib_utils.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/__init__.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/api.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/gen_incar.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/gen_script.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/write_poscar.py +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/dependency_links.txt +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/entry_points.txt +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/requires.txt +0 -0
- {rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rsspolymlp
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A framework for random structure search using polynomial MLPs
|
|
5
5
|
Author-email: Hayato Wakai <wakai@cms.mtl.kyoto-u.ac.jp>
|
|
6
6
|
Maintainer-email: Hayato Wakai <wakai@cms.mtl.kyoto-u.ac.jp>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ast
|
|
1
2
|
import json
|
|
2
3
|
import os
|
|
3
4
|
from collections import defaultdict
|
|
@@ -18,6 +19,7 @@ class ConvexHullAnalyzer:
|
|
|
18
19
|
self.elements = np.array(elements)
|
|
19
20
|
# Initialize per-composition storage
|
|
20
21
|
self._composition_data = {}
|
|
22
|
+
self.endmember_energies = None
|
|
21
23
|
# Convex hull object
|
|
22
24
|
self.hull = None
|
|
23
25
|
# Results for global minima on the hull
|
|
@@ -33,9 +35,9 @@ class ConvexHullAnalyzer:
|
|
|
33
35
|
def composition_data(self, data):
|
|
34
36
|
"""
|
|
35
37
|
composition_data maps each composition ratio (tuple) to a dict with keys:
|
|
36
|
-
'energy': np.ndarray of energies,
|
|
37
|
-
'input_path': np.ndarray of file paths,
|
|
38
|
-
'struct_tag': np.ndarray of structure tags.
|
|
38
|
+
- 'energy': np.ndarray of energies,
|
|
39
|
+
- 'input_path': np.ndarray of file paths,
|
|
40
|
+
- 'struct_tag': np.ndarray of structure tags.
|
|
39
41
|
"""
|
|
40
42
|
if not isinstance(data, dict):
|
|
41
43
|
raise TypeError("composition_data must be a dictionary.")
|
|
@@ -60,53 +62,53 @@ class ConvexHullAnalyzer:
|
|
|
60
62
|
self._composition_data = data
|
|
61
63
|
|
|
62
64
|
def run_analysis(self):
|
|
63
|
-
"""
|
|
65
|
+
"""
|
|
66
|
+
Construct the convex hull, compute formation energies, and evaluate energies above the hull.
|
|
67
|
+
The convex-hull results are stored in the following attributes:
|
|
68
|
+
- 'self.hull_energies': formation energies of structures on the hull
|
|
69
|
+
- 'self.hull_compositions': compositions of structures on the hull
|
|
70
|
+
- 'self.hull_paths': paths corresponding to structures on the hull
|
|
71
|
+
self._composition_data maps each composition ratio to a dictionary containing:
|
|
72
|
+
- 'formation_e': np.ndarray of formation energies
|
|
73
|
+
- 'fe_above_ch': np.ndarray of energies above the convex hull
|
|
74
|
+
"""
|
|
64
75
|
if len(self.elements) == 0:
|
|
65
76
|
raise ValueError("elements is none. Please set elements.")
|
|
66
77
|
if not self._composition_data:
|
|
67
78
|
raise ValueError("composition_data is empty. Please set results first.")
|
|
68
|
-
|
|
79
|
+
|
|
80
|
+
self.set_endmember_energies()
|
|
69
81
|
self.compute_convex_hull()
|
|
82
|
+
self.compute_formation_energies()
|
|
70
83
|
self.compute_fe_above_ch()
|
|
71
84
|
|
|
72
|
-
def
|
|
73
|
-
"""Compute formation energy for each structure relative to pure elements."""
|
|
74
|
-
# Sort compositions for reproducible output
|
|
75
|
-
comps = np.array(list(self._composition_data.keys()))
|
|
76
|
-
order = np.lexsort(comps.T)
|
|
77
|
-
sorted_keys = [tuple(comps[i].tolist()) for i in order]
|
|
78
|
-
self._composition_data = {k: self._composition_data[k] for k in sorted_keys}
|
|
79
|
-
|
|
85
|
+
def set_endmember_energies(self):
|
|
80
86
|
# Reference energies from pure elements (where any ratio == 1)
|
|
87
|
+
os.makedirs("phase_analysis/data", exist_ok=True)
|
|
88
|
+
comps = np.array(list(self._composition_data.keys()))
|
|
81
89
|
pure = comps[np.any(comps == 1, axis=1)]
|
|
82
90
|
pure_sorted = sorted(pure, key=lambda x: np.argmax(x))
|
|
83
|
-
|
|
91
|
+
self.endmember_energies = [
|
|
84
92
|
np.min(self._composition_data[tuple(r)]["energy"]) for r in pure_sorted
|
|
85
93
|
]
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
# Calculate and store formation energies
|
|
89
|
-
for ratio, data in self._composition_data.items():
|
|
90
|
-
formation = data["energy"] - np.dot(ref_energies, np.array(ratio))
|
|
91
|
-
data["formation_e"] = formation
|
|
92
|
-
|
|
93
|
-
# Save JSON and elements
|
|
94
|
-
os.makedirs("phase_analysis/data", exist_ok=True)
|
|
95
|
-
serial = {
|
|
96
|
-
str(r): {k: v.tolist() for k, v in d.items()}
|
|
97
|
-
for r, d in self._composition_data.items()
|
|
98
|
-
}
|
|
99
|
-
with open("phase_analysis/data/composition_data.json", "w") as f:
|
|
100
|
-
json.dump(serial, f)
|
|
101
|
-
np.save("phase_analysis/data/elements.npy", self.elements)
|
|
94
|
+
self.endmember_energies = np.array(self.endmember_energies)
|
|
102
95
|
|
|
103
96
|
def compute_convex_hull(self):
|
|
104
97
|
"""Build the convex hull and extract vertex compositions and energies."""
|
|
98
|
+
os.makedirs("phase_analysis/data", exist_ok=True)
|
|
99
|
+
# Sort compositions for reproducible output
|
|
100
|
+
comps = np.array(list(self._composition_data.keys()))
|
|
101
|
+
order = np.lexsort(comps.T)
|
|
102
|
+
sorted_keys = [tuple(comps[i].tolist()) for i in order]
|
|
103
|
+
self._composition_data = {k: self._composition_data[k] for k in sorted_keys}
|
|
104
|
+
|
|
105
105
|
comps, min_e, paths = [], [], []
|
|
106
106
|
for ratio, data in self._composition_data.items():
|
|
107
107
|
comps.append(ratio)
|
|
108
|
-
idx = np.argmin(data["
|
|
109
|
-
min_e.append(
|
|
108
|
+
idx = np.argmin(data["energy"])
|
|
109
|
+
min_e.append(
|
|
110
|
+
data["energy"][idx] - np.dot(self.endmember_energies, np.array(ratio))
|
|
111
|
+
)
|
|
110
112
|
paths.append(data["input_path"][idx])
|
|
111
113
|
|
|
112
114
|
comp_arr = np.array(comps)
|
|
@@ -140,10 +142,28 @@ class ConvexHullAnalyzer:
|
|
|
140
142
|
f.write(f" formation_e: {energy}\n")
|
|
141
143
|
|
|
142
144
|
# Save NumPy arrays
|
|
143
|
-
os.makedirs("phase_analysis/data", exist_ok=True)
|
|
144
145
|
np.save("phase_analysis/data/hull_e.npy", self.hull_energies)
|
|
145
146
|
np.save("phase_analysis/data/hull_comp.npy", self.hull_compositions)
|
|
146
147
|
|
|
148
|
+
def compute_formation_energies(self, json_output=True):
|
|
149
|
+
"""Compute formation energy for each structure relative to pure elements."""
|
|
150
|
+
# Calculate and store formation energies
|
|
151
|
+
for ratio, data in self._composition_data.items():
|
|
152
|
+
formation = data["energy"] - np.dot(
|
|
153
|
+
self.endmember_energies, np.array(ratio)
|
|
154
|
+
)
|
|
155
|
+
data["formation_e"] = formation
|
|
156
|
+
|
|
157
|
+
# Save JSON and elements
|
|
158
|
+
if json_output:
|
|
159
|
+
serial = {
|
|
160
|
+
str(r): {k: v.tolist() for k, v in d.items()}
|
|
161
|
+
for r, d in self._composition_data.items()
|
|
162
|
+
}
|
|
163
|
+
with open("phase_analysis/data/composition_data.json", "w") as f:
|
|
164
|
+
json.dump(serial, f)
|
|
165
|
+
np.save("phase_analysis/data/elements.npy", self.elements)
|
|
166
|
+
|
|
147
167
|
def compute_fe_above_ch(self):
|
|
148
168
|
"""Compute each structure's energy above the convex hull."""
|
|
149
169
|
for ratio, data in self._composition_data.items():
|
|
@@ -309,6 +329,9 @@ class ConvexHullAnalyzer:
|
|
|
309
329
|
for element in structure.elements:
|
|
310
330
|
energy_dft -= atomic_energy(element)
|
|
311
331
|
energy_dft /= len(structure.elements)
|
|
332
|
+
if energy_dft < -15:
|
|
333
|
+
print(vasprun_path, "exhibits very low energy:", energy_dft, "eV/atom")
|
|
334
|
+
continue
|
|
312
335
|
|
|
313
336
|
comp_res = compute_composition(structure.elements, self.elements)
|
|
314
337
|
comp_ratio = tuple(
|
|
@@ -338,3 +361,35 @@ class ConvexHullAnalyzer:
|
|
|
338
361
|
}
|
|
339
362
|
|
|
340
363
|
self._composition_data = dft_dict_array
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def load_convexhull_data(path="./phase_analysis", threshold=None):
|
|
367
|
+
res = {}
|
|
368
|
+
|
|
369
|
+
res["elements"] = np.load(f"{path}/data/elements.npy")
|
|
370
|
+
res["hull_comp"] = np.load(f"{path}/data/hull_comp.npy")
|
|
371
|
+
res["hull_e"] = np.load(f"{path}/data/hull_e.npy")
|
|
372
|
+
with open(f"{path}/data/composition_data.json", "r") as f:
|
|
373
|
+
data = json.load(f)
|
|
374
|
+
res["composition_data"] = convert_json_to_ndarray(data)
|
|
375
|
+
|
|
376
|
+
res["not_near_ch"] = None
|
|
377
|
+
res["near_ch"] = None
|
|
378
|
+
if threshold is not None:
|
|
379
|
+
thre = float(threshold)
|
|
380
|
+
with open(f"{path}/threshold_{thre}meV/not_near_ch.json", "r") as f:
|
|
381
|
+
data1 = json.load(f)
|
|
382
|
+
with open(f"{path}/threshold_{thre}meV/near_ch.json", "r") as f:
|
|
383
|
+
data2 = json.load(f)
|
|
384
|
+
res["not_near_ch"] = convert_json_to_ndarray(data1)
|
|
385
|
+
res["near_ch"] = convert_json_to_ndarray(data2)
|
|
386
|
+
|
|
387
|
+
return res
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def convert_json_to_ndarray(data):
|
|
391
|
+
converted = {
|
|
392
|
+
ast.literal_eval(k): {key: np.array(val) for key, val in v.items()}
|
|
393
|
+
for k, v in data.items()
|
|
394
|
+
}
|
|
395
|
+
return converted
|
|
@@ -80,9 +80,7 @@ class RSSResultSummarizer:
|
|
|
80
80
|
parent_path_ref[composition_tag] = json_path
|
|
81
81
|
|
|
82
82
|
if not self.parse_vasp:
|
|
83
|
-
paths_same_comp, results_same_comp = self._parse_json_result(
|
|
84
|
-
parse_rss_result=True
|
|
85
|
-
)
|
|
83
|
+
paths_same_comp, results_same_comp = self._parse_json_result()
|
|
86
84
|
axis_tol = 0.03
|
|
87
85
|
pos_tol = 0.03
|
|
88
86
|
else:
|
|
@@ -187,10 +185,12 @@ class RSSResultSummarizer:
|
|
|
187
185
|
paths_same_comp, results_same_comp = self._parse_json_result()
|
|
188
186
|
|
|
189
187
|
for composition_tag, res_paths in paths_same_comp.items():
|
|
188
|
+
print(f"Composition {composition_tag}: summarizing...")
|
|
190
189
|
self.analyzer = UniqueStructureAnalyzer()
|
|
191
190
|
|
|
192
191
|
time_start = time()
|
|
193
192
|
for res_path in res_paths:
|
|
193
|
+
print(f" - Processing result file (parent): {res_path}")
|
|
194
194
|
self.remove_duplicates_in_comp(
|
|
195
195
|
results_same_comp[composition_tag][res_path],
|
|
196
196
|
standardize_axis=True,
|
|
@@ -364,7 +364,7 @@ class RSSResultSummarizer:
|
|
|
364
364
|
|
|
365
365
|
return struct_counts
|
|
366
366
|
|
|
367
|
-
def _parse_json_result(self
|
|
367
|
+
def _parse_json_result(self):
|
|
368
368
|
|
|
369
369
|
def resolve_path(base: Path, p):
|
|
370
370
|
cwd = Path.cwd()
|
|
@@ -382,15 +382,12 @@ class RSSResultSummarizer:
|
|
|
382
382
|
with open(path_name) as f:
|
|
383
383
|
loaded_dict = json.load(f)
|
|
384
384
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
r["structure"] = polymlp_struct_from_dict(r["structure"])
|
|
393
|
-
r["struct_no"] = None
|
|
385
|
+
base = Path(path_name).parents[1]
|
|
386
|
+
for r in loaded_dict["rss_results"]:
|
|
387
|
+
r["struct_path"] = resolve_path(base, r["struct_path"])
|
|
388
|
+
r["dupstr_paths"] = {resolve_path(base, p) for p in r["dupstr_paths"]}
|
|
389
|
+
r["structure"] = polymlp_struct_from_dict(r["structure"])
|
|
390
|
+
r["struct_no"] = None
|
|
394
391
|
|
|
395
392
|
target_elements = loaded_dict["elements"]
|
|
396
393
|
comp_ratio = tuple(loaded_dict["comp_ratio"])
|
{rsspolymlp-0.3.2 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/struct_match.py
RENAMED
|
@@ -63,6 +63,7 @@ def struct_match(
|
|
|
63
63
|
struct_match = False
|
|
64
64
|
axis_d_min = None
|
|
65
65
|
pos_d_min = None
|
|
66
|
+
min_axis_l2_norm = 1e8
|
|
66
67
|
for st_1 in st_1_set:
|
|
67
68
|
for st_2 in st_2_set:
|
|
68
69
|
if struct_match or st_1.element_count != st_2.element_count:
|
|
@@ -75,6 +76,7 @@ def struct_match(
|
|
|
75
76
|
) # (N_symp1, N_symp2, 6)
|
|
76
77
|
axis_d_flat = axis_d.reshape(-1, axis_d.shape[2]) # (N_symp1*N_symp2, 6)
|
|
77
78
|
l2_norm = np.linalg.norm(axis_d_flat, axis=1)
|
|
79
|
+
min_axis_l2_norm = min(min_axis_l2_norm, np.min(l2_norm))
|
|
78
80
|
|
|
79
81
|
match_axis = l2_norm < axis_tol
|
|
80
82
|
if not np.any(match_axis):
|
|
@@ -117,32 +119,31 @@ def struct_match(
|
|
|
117
119
|
["a", "b", "c"], np.round(positions.reshape(3, -1), 3).tolist()
|
|
118
120
|
):
|
|
119
121
|
formatted = ",".join(f"{val:6.3f}" for val in p)
|
|
120
|
-
print(f"
|
|
122
|
+
print(f" - [{formatted}]")
|
|
121
123
|
|
|
124
|
+
print("--- results of rsspolymlp.analysis.struct_matcher ---")
|
|
122
125
|
print("tolerance:")
|
|
123
126
|
print(" axis_tol:", axis_tol)
|
|
124
127
|
print(" pos_tol:", pos_tol)
|
|
125
|
-
print("")
|
|
126
128
|
print("structures:")
|
|
127
129
|
for i, st_set in enumerate([st_1_set, st_2_set]):
|
|
128
|
-
print(f"
|
|
130
|
+
print(f" - struct_No: {i+1}")
|
|
129
131
|
for st in st_set:
|
|
130
|
-
print("
|
|
131
|
-
print("
|
|
132
|
+
print(" spg_number:", st.spg_number)
|
|
133
|
+
print(" representations:")
|
|
132
134
|
for h, pos in enumerate(st.positions):
|
|
133
135
|
log_axis_positions(st.symprec_set[h], st.axis[h], pos)
|
|
136
|
+
print("min_axis_l2_norm:", np.round(min_axis_l2_norm, 3))
|
|
134
137
|
if axis_d_min is not None:
|
|
135
|
-
print("")
|
|
136
138
|
print("difference_log:")
|
|
137
|
-
print("
|
|
138
|
-
print("
|
|
139
|
-
print("
|
|
139
|
+
print(" - axis_l2_norm:", np.round(axis_d_min[0], 3))
|
|
140
|
+
print(" pos_max_abs:", np.round(pos_d_min[0], 3))
|
|
141
|
+
print(" structure_1:")
|
|
140
142
|
log_axis_positions(pos_d_min[1][0], axis_d_min[1][0], pos_d_min[1][1])
|
|
141
|
-
print("
|
|
143
|
+
print(" structure_2:")
|
|
142
144
|
log_axis_positions(pos_d_min[1][2], axis_d_min[1][1], pos_d_min[1][3])
|
|
143
|
-
print("
|
|
145
|
+
print(" diffs:")
|
|
144
146
|
log_axis_positions([], axis_d_min[1][2], pos_d_min[1][4])
|
|
145
|
-
print("")
|
|
146
147
|
print("Match:", struct_match)
|
|
147
148
|
|
|
148
149
|
return struct_match
|
|
@@ -165,12 +165,6 @@ def run():
|
|
|
165
165
|
default=-1,
|
|
166
166
|
help="Number of optimized structures to analyze (-1 means all)",
|
|
167
167
|
)
|
|
168
|
-
parser.add_argument(
|
|
169
|
-
"--cutoff",
|
|
170
|
-
type=float,
|
|
171
|
-
default=None,
|
|
172
|
-
help="Cutoff radius used in the MLP model (optional)",
|
|
173
|
-
)
|
|
174
168
|
|
|
175
169
|
# Target paths for rsspolymlp postprocessing
|
|
176
170
|
parser.add_argument(
|
|
@@ -275,14 +269,11 @@ def run():
|
|
|
275
269
|
c_maxiter=args.c_maxiter,
|
|
276
270
|
n_opt_str=args.n_opt_str,
|
|
277
271
|
not_stop_rss=args.not_stop_rss,
|
|
278
|
-
num_process=args.num_process,
|
|
279
|
-
backend=args.backend,
|
|
280
272
|
)
|
|
281
273
|
|
|
282
274
|
if args.uniq_struct:
|
|
283
275
|
rss_uniq_struct(
|
|
284
276
|
num_str=args.num_str,
|
|
285
|
-
cutoff=args.cutoff,
|
|
286
277
|
num_process=args.num_process,
|
|
287
278
|
backend=args.backend,
|
|
288
279
|
)
|
|
@@ -208,8 +208,18 @@ def run():
|
|
|
208
208
|
default=4,
|
|
209
209
|
help="Number of processes to use with joblib.",
|
|
210
210
|
)
|
|
211
|
+
parser.add_argument(
|
|
212
|
+
"--not_check",
|
|
213
|
+
action="store_true",
|
|
214
|
+
)
|
|
211
215
|
|
|
212
216
|
# --divide_data mode
|
|
217
|
+
parser.add_argument(
|
|
218
|
+
"--target_pressure",
|
|
219
|
+
type=float,
|
|
220
|
+
default=0.0,
|
|
221
|
+
help="",
|
|
222
|
+
)
|
|
213
223
|
parser.add_argument(
|
|
214
224
|
"--th_e_high",
|
|
215
225
|
type=float,
|
|
@@ -305,11 +315,14 @@ def run():
|
|
|
305
315
|
vasp_paths=args.paths,
|
|
306
316
|
output_dir=args.output_dir,
|
|
307
317
|
num_process=args.num_process,
|
|
318
|
+
not_check=args.not_check,
|
|
308
319
|
)
|
|
309
320
|
|
|
310
321
|
if args.divide_data:
|
|
311
322
|
divide_dft_dataset(
|
|
323
|
+
elements=args.elements,
|
|
312
324
|
target_dirs=args.paths,
|
|
325
|
+
target_pressure=args.target_pressure,
|
|
313
326
|
threshold_e_high=args.th_e_high,
|
|
314
327
|
threshold_e_low=args.th_e_low,
|
|
315
328
|
threshold_f_small=args.th_f_small,
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from rsspolymlp.api.rsspolymlp_utils import geometry_opt, struct_compare, struct_matcher
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def run():
|
|
7
|
+
parser = argparse.ArgumentParser()
|
|
8
|
+
parser.add_argument(
|
|
9
|
+
"--struct_matcher",
|
|
10
|
+
action="store_true",
|
|
11
|
+
help="Mode: struct_matcher",
|
|
12
|
+
)
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"--struct_compare",
|
|
15
|
+
action="store_true",
|
|
16
|
+
help="Mode: struct_compare",
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--geometry_opt",
|
|
20
|
+
action="store_true",
|
|
21
|
+
help="Mode: geometry_optimizations",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# --struct_matcher mode
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--poscars",
|
|
27
|
+
type=str,
|
|
28
|
+
nargs="+",
|
|
29
|
+
default=None,
|
|
30
|
+
help="Paths of target POSCAR files.",
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--num_process",
|
|
34
|
+
type=int,
|
|
35
|
+
default=-1,
|
|
36
|
+
help="Number of processes to use with joblib. Use -1 to use all available CPU cores.",
|
|
37
|
+
)
|
|
38
|
+
parser.add_argument(
|
|
39
|
+
"--backend",
|
|
40
|
+
type=str,
|
|
41
|
+
choices=["loky", "threading", "multiprocessing"],
|
|
42
|
+
default="loky",
|
|
43
|
+
help="Backend for joblib parallelization",
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"--primitive_symprecs",
|
|
47
|
+
nargs="*",
|
|
48
|
+
type=float,
|
|
49
|
+
default=[1e-5, 1e-4, 1e-3, 1e-2],
|
|
50
|
+
help="List of symmetry tolerances used to identify distinct primitive cells.",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--output_file",
|
|
54
|
+
type=str,
|
|
55
|
+
default="unique_struct.yaml",
|
|
56
|
+
help="Output file name (default: unique_struct.yaml).",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# --struct_compare mode
|
|
60
|
+
parser.add_argument(
|
|
61
|
+
"--refine_symprec",
|
|
62
|
+
type=float,
|
|
63
|
+
default=1e-3,
|
|
64
|
+
help="Symmetry tolerance used to identify refine structure.",
|
|
65
|
+
)
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
"--reduced_symprecs",
|
|
68
|
+
nargs="*",
|
|
69
|
+
type=float,
|
|
70
|
+
default=None,
|
|
71
|
+
help="List of symmetry tolerances used to identify reduced structure representation.",
|
|
72
|
+
)
|
|
73
|
+
parser.add_argument(
|
|
74
|
+
"--axis_tol",
|
|
75
|
+
type=float,
|
|
76
|
+
default=1e-2,
|
|
77
|
+
help="",
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--pos_tol",
|
|
81
|
+
type=float,
|
|
82
|
+
default=1e-2,
|
|
83
|
+
help="",
|
|
84
|
+
)
|
|
85
|
+
parser.add_argument("--standardize_axis", action="store_true", help="")
|
|
86
|
+
parser.add_argument("--original_axis", action="store_true", help="")
|
|
87
|
+
parser.add_argument("--frac_coords", action="store_true", help="")
|
|
88
|
+
parser.add_argument("--not_verbose", action="store_true", help="")
|
|
89
|
+
|
|
90
|
+
# --geometry_opt mode
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--pot",
|
|
93
|
+
nargs="*",
|
|
94
|
+
type=str,
|
|
95
|
+
default=["polymlp.yaml"],
|
|
96
|
+
help="Potential file for polynomial MLP",
|
|
97
|
+
)
|
|
98
|
+
parser.add_argument(
|
|
99
|
+
"--pressure", type=float, default=0.0, help="Pressure term (in GPa)"
|
|
100
|
+
)
|
|
101
|
+
parser.add_argument(
|
|
102
|
+
"--symmetry",
|
|
103
|
+
action="store_true",
|
|
104
|
+
help="If enabled, the optimization is comducted with using symmetry constraints.",
|
|
105
|
+
)
|
|
106
|
+
parser.add_argument(
|
|
107
|
+
"--solver_method", type=str, default="CG", help="Type of solver"
|
|
108
|
+
)
|
|
109
|
+
parser.add_argument(
|
|
110
|
+
"--c_maxiter",
|
|
111
|
+
type=int,
|
|
112
|
+
default=100,
|
|
113
|
+
help="Maximum number of iterations when c1 and c2 values are changed",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
args = parser.parse_args()
|
|
117
|
+
|
|
118
|
+
if args.struct_matcher:
|
|
119
|
+
struct_matcher(
|
|
120
|
+
poscar_paths=args.poscars,
|
|
121
|
+
num_process=args.num_process,
|
|
122
|
+
backend=args.backend,
|
|
123
|
+
primitive_symprecs=args.primitive_symprecs,
|
|
124
|
+
output_file=args.output_file,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if args.struct_compare:
|
|
128
|
+
struct_compare(
|
|
129
|
+
poscar_paths=args.poscars,
|
|
130
|
+
refine_symprec=args.refine_symprec,
|
|
131
|
+
reduced_symprecs=args.reduced_symprecs,
|
|
132
|
+
axis_tol=args.axis_tol,
|
|
133
|
+
pos_tol=args.pos_tol,
|
|
134
|
+
standardize_axis=args.standardize_axis,
|
|
135
|
+
original_axis=args.original_axis,
|
|
136
|
+
frac_coords=args.frac_coords,
|
|
137
|
+
verbose=not args.not_verbose,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if args.geometry_opt:
|
|
141
|
+
geometry_opt(
|
|
142
|
+
poscar_paths=args.poscars,
|
|
143
|
+
pot=args.pot,
|
|
144
|
+
pressure=args.pressure,
|
|
145
|
+
with_symmetry=args.symmetry,
|
|
146
|
+
solver_method=args.solver_method,
|
|
147
|
+
c_maxiter=args.c_maxiter,
|
|
148
|
+
)
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import glob
|
|
2
|
-
import multiprocessing
|
|
3
2
|
import os
|
|
4
3
|
import time
|
|
5
4
|
|
|
6
|
-
from joblib import Parallel, delayed
|
|
7
|
-
from joblib.externals.loky import get_reusable_executor
|
|
8
|
-
|
|
9
5
|
from rsspolymlp.analysis.ghost_minima import (
|
|
10
6
|
detect_actual_ghost_minima,
|
|
11
7
|
ghost_minima_candidates,
|
|
@@ -43,8 +39,6 @@ def rss_run_parallel(
|
|
|
43
39
|
c_maxiter=100,
|
|
44
40
|
n_opt_str=1000,
|
|
45
41
|
not_stop_rss=False,
|
|
46
|
-
num_process=-1,
|
|
47
|
-
backend="loky",
|
|
48
42
|
):
|
|
49
43
|
"""
|
|
50
44
|
Performing Random Structure Search (RSS) on multiple tasks in parallel
|
|
@@ -73,11 +67,6 @@ def rss_run_parallel(
|
|
|
73
67
|
if len(poscar_path_all) == 0:
|
|
74
68
|
return
|
|
75
69
|
|
|
76
|
-
if num_process == 1:
|
|
77
|
-
not_stop_rss = True
|
|
78
|
-
elif num_process == -1:
|
|
79
|
-
num_process = multiprocessing.cpu_count()
|
|
80
|
-
|
|
81
70
|
rssobj = OptimizationMLP(
|
|
82
71
|
pot=pot,
|
|
83
72
|
pressure=pressure,
|
|
@@ -89,36 +78,22 @@ def rss_run_parallel(
|
|
|
89
78
|
)
|
|
90
79
|
|
|
91
80
|
time_start = time.time()
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
rssobj.run_optimization(poscar)
|
|
95
|
-
else:
|
|
96
|
-
# Perform parallel optimization with joblib
|
|
97
|
-
time_start = time.time()
|
|
98
|
-
Parallel(n_jobs=num_process, backend=backend, verbose=100)(
|
|
99
|
-
delayed(rssobj.run_optimization)(poscar) for poscar in poscar_path_all
|
|
100
|
-
)
|
|
101
|
-
executor = get_reusable_executor(max_workers=num_process)
|
|
102
|
-
executor.shutdown(wait=True)
|
|
81
|
+
for poscar in poscar_path_all:
|
|
82
|
+
rssobj.run_optimization(poscar)
|
|
103
83
|
elapsed = time.time() - time_start
|
|
104
84
|
|
|
105
|
-
with open("rss_result/
|
|
106
|
-
print("Number of
|
|
107
|
-
print("Number of the structures:", len(glob.glob("log/*")), file=f)
|
|
85
|
+
with open("rss_result/elapsed_time.log", "a") as f:
|
|
86
|
+
print("Number of structures:", len(glob.glob("log/*")), file=f)
|
|
108
87
|
print("Computational time:", elapsed, file=f)
|
|
109
88
|
print("", file=f)
|
|
110
89
|
|
|
111
90
|
|
|
112
91
|
def rss_uniq_struct(
|
|
113
92
|
num_str=-1,
|
|
114
|
-
cutoff=None,
|
|
115
93
|
num_process=-1,
|
|
116
94
|
backend="loky",
|
|
117
95
|
):
|
|
118
96
|
analyzer = RSSResultAnalyzer()
|
|
119
|
-
if cutoff is not None:
|
|
120
|
-
analyzer.cutoff = cutoff
|
|
121
|
-
|
|
122
97
|
analyzer.run_rss_uniq_struct(
|
|
123
98
|
num_str=num_str,
|
|
124
99
|
num_process=num_process,
|
|
@@ -182,8 +157,6 @@ def rss_polymlp(
|
|
|
182
157
|
c_maxiter=c_maxiter,
|
|
183
158
|
n_opt_str=n_opt_str,
|
|
184
159
|
not_stop_rss=not_stop_rss,
|
|
185
|
-
num_process=num_process,
|
|
186
|
-
backend=backend,
|
|
187
160
|
)
|
|
188
161
|
|
|
189
162
|
with open("rss_result/success.dat") as f:
|
|
@@ -192,7 +165,10 @@ def rss_polymlp(
|
|
|
192
165
|
print("Target number of optimized structures reached. Exiting.")
|
|
193
166
|
break
|
|
194
167
|
|
|
195
|
-
rss_uniq_struct(
|
|
168
|
+
rss_uniq_struct(
|
|
169
|
+
num_process=num_process,
|
|
170
|
+
backend=backend,
|
|
171
|
+
)
|
|
196
172
|
|
|
197
173
|
|
|
198
174
|
def rss_summarize(
|
|
@@ -140,9 +140,21 @@ def mlp_dataset(
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
def compress_vasprun(
|
|
143
|
-
vasp_paths: list[str],
|
|
143
|
+
vasp_paths: list[str],
|
|
144
|
+
output_dir: str = "compress_dft_data",
|
|
145
|
+
num_process: int = 4,
|
|
146
|
+
not_check: bool = False,
|
|
144
147
|
):
|
|
145
|
-
|
|
148
|
+
if not not_check:
|
|
149
|
+
valid_paths, vasprun_status = check_convergence(vasp_paths=vasp_paths)
|
|
150
|
+
else:
|
|
151
|
+
valid_paths = vasp_paths
|
|
152
|
+
vasprun_status = {
|
|
153
|
+
"fail": 0,
|
|
154
|
+
"fail_iteration": 0,
|
|
155
|
+
"parse": 0,
|
|
156
|
+
"success": 0,
|
|
157
|
+
}
|
|
146
158
|
|
|
147
159
|
judge_list = Parallel(n_jobs=num_process)(
|
|
148
160
|
delayed(compress)(vasp_path + "/vasprun.xml", output_dir)
|
|
@@ -168,7 +180,9 @@ def compress_vasprun(
|
|
|
168
180
|
|
|
169
181
|
|
|
170
182
|
def divide_dft_dataset(
|
|
183
|
+
elements: list[str],
|
|
171
184
|
target_dirs: str,
|
|
185
|
+
target_pressure: float = 0.0,
|
|
172
186
|
threshold_e_high: float = 10.0, # in eV/atom
|
|
173
187
|
threshold_e_low: Optional[float] = None,
|
|
174
188
|
threshold_f_small: float = 3.0, # in eV/ang
|
|
@@ -183,7 +197,9 @@ def divide_dft_dataset(
|
|
|
183
197
|
vasprun_paths.extend(sorted(glob.glob(target_dir + "/*")))
|
|
184
198
|
|
|
185
199
|
vasprun_dict = divide_dataset(
|
|
200
|
+
elements=elements,
|
|
186
201
|
vasprun_paths=vasprun_paths,
|
|
202
|
+
target_pressure=target_pressure,
|
|
187
203
|
threshold_e_high=threshold_e_high,
|
|
188
204
|
threshold_e_low=threshold_e_low,
|
|
189
205
|
threshold_f_small=threshold_f_small,
|
|
@@ -198,7 +214,9 @@ def divide_dft_dataset(
|
|
|
198
214
|
|
|
199
215
|
with open(f"{output_dir}/dataset.yaml", "w") as f:
|
|
200
216
|
print("arguments:", file=f)
|
|
217
|
+
print(" elements:", elements, file=f)
|
|
201
218
|
print(" path:", target_dir, file=f)
|
|
219
|
+
print(" target_pressure:", target_pressure, file=f)
|
|
202
220
|
print(" threshold_e_high:", threshold_e_high, file=f)
|
|
203
221
|
print(" threshold_e_low:", threshold_e_low, file=f)
|
|
204
222
|
print(" threshold_f_small:", threshold_f_small, file=f)
|