rsspolymlp 0.3.3__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.
Files changed (82) hide show
  1. {rsspolymlp-0.3.3/src/rsspolymlp.egg-info → rsspolymlp-0.3.4}/PKG-INFO +1 -1
  2. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/pyproject.toml +1 -1
  3. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/phase_analysis.py +88 -33
  4. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/rss_summarize.py +10 -13
  5. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/struct_match.py +13 -12
  6. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/cli_rsspolymlp.py +0 -9
  7. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/cli_rsspolymlp_devkit.py +13 -0
  8. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/cli_rsspolymlp_utils.py +55 -8
  9. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/rsspolymlp.py +8 -32
  10. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/rsspolymlp_devkit.py +20 -2
  11. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/rsspolymlp_plot.py +2 -2
  12. rsspolymlp-0.3.4/src/rsspolymlp/api/rsspolymlp_utils.py +150 -0
  13. rsspolymlp-0.3.4/src/rsspolymlp/mlp_dev/dataset/divide_dataset.py +212 -0
  14. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/dataset/gen_mlp_dataset.py +30 -19
  15. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/eliminate_duplicates.py +50 -4
  16. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/optimization_mlp.py +3 -1
  17. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/examples/example.py +2 -2
  18. rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/harmonic_real.py +379 -0
  19. rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/opt_geometry_sscha.py +471 -0
  20. rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/opt_position_sscha.py +179 -0
  21. rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/run_opt_sscha.py +415 -0
  22. rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/sscha_property.py +271 -0
  23. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4/src/rsspolymlp.egg-info}/PKG-INFO +1 -1
  24. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/SOURCES.txt +5 -1
  25. rsspolymlp-0.3.3/src/rsspolymlp/analysis/load_plot_data.py +0 -36
  26. rsspolymlp-0.3.3/src/rsspolymlp/api/rsspolymlp_utils.py +0 -87
  27. rsspolymlp-0.3.3/src/rsspolymlp/mlp_dev/dataset/divide_dataset.py +0 -130
  28. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/LICENSE +0 -0
  29. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/README.md +0 -0
  30. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/setup.cfg +0 -0
  31. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/__init__.py +0 -0
  32. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/__init__.py +0 -0
  33. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/eos.py +0 -0
  34. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/ghost_minima.py +0 -0
  35. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/__init__.py +0 -0
  36. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/chiral_spg.py +0 -0
  37. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/invert_and_swap.py +0 -0
  38. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/irrep_position.py +0 -0
  39. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/niggli.py +0 -0
  40. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/struct_match.py +0 -0
  41. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/deprecated/utils.py +0 -0
  42. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/invert_and_swap.py +0 -0
  43. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/struct_matcher/reduced_position.py +0 -0
  44. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/analysis/unique_struct.py +0 -0
  45. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/__init__.py +0 -0
  46. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/api/cli_rsspolymlp_plot.py +0 -0
  47. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/common/__init__.py +0 -0
  48. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/common/atomic_energy.py +0 -0
  49. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/common/composition.py +0 -0
  50. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/common/convert_dict.py +0 -0
  51. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/common/property.py +0 -0
  52. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/dataset/compress_vasprun.py +0 -0
  53. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/estimate_cost.py +0 -0
  54. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/gen_hybrid_model.py +0 -0
  55. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/gen_single_model.py +0 -0
  56. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/n_feature.py +0 -0
  57. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/pypolymlp_gridsearch.py +0 -0
  58. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/model_selection/reduce_grid.py +0 -0
  59. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/pareto_opt_mlp.py +0 -0
  60. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/mlp_dev/polymlp_dev.py +0 -0
  61. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/__init__.py +0 -0
  62. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/load_logfile.py +0 -0
  63. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/rss/random_struct.py +0 -0
  64. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/__init__.py +0 -0
  65. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/lammps_utils.py +0 -0
  66. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/__init__.py +0 -0
  67. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/custom_plt.py +0 -0
  68. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/examples/__init__.py +0 -0
  69. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/examples/template.py +0 -0
  70. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/matplot_util/make_plot.py +0 -0
  71. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/pymatgen_utils.py +0 -0
  72. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/spglib_utils.py +0 -0
  73. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/__init__.py +0 -0
  74. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/api.py +0 -0
  75. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/gen_incar.py +0 -0
  76. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/gen_script.py +0 -0
  77. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp/utils/vasp_util/write_poscar.py +0 -0
  78. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/dependency_links.txt +0 -0
  79. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/entry_points.txt +0 -0
  80. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/requires.txt +0 -0
  81. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/src/rsspolymlp.egg-info/top_level.txt +0 -0
  82. {rsspolymlp-0.3.3 → rsspolymlp-0.3.4}/tests/test_cli_help.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rsspolymlp
3
- Version: 0.3.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>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rsspolymlp"
7
- version = "0.3.3"
7
+ version = "0.3.4"
8
8
  description = "A framework for random structure search using polynomial MLPs"
9
9
  license = "MIT"
10
10
  authors = [
@@ -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
- """Compute formation energies, build convex hull, and evaluate energies above hull."""
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
- self.compute_formation_energies()
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 compute_formation_energies(self):
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
- ref_energies = [
91
+ self.endmember_energies = [
84
92
  np.min(self._composition_data[tuple(r)]["energy"]) for r in pure_sorted
85
93
  ]
86
- ref_energies = np.array(ref_energies)
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["formation_e"])
109
- min_e.append(data["formation_e"][idx])
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, parse_rss_result=False):
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
- if parse_rss_result:
386
- base = Path(path_name).parents[1]
387
- for r in loaded_dict["rss_results"]:
388
- r["struct_path"] = resolve_path(base, r["struct_path"])
389
- r["dupstr_paths"] = {
390
- resolve_path(base, p) for p in r["dupstr_paths"]
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"])
@@ -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" - [{formatted}]")
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" - struct_No: {i+1}")
130
+ print(f" - struct_No: {i+1}")
129
131
  for st in st_set:
130
- print(" spg_number:", st.spg_number)
131
- print(" representations:")
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(" - axis_l2_norm:", np.round(axis_d_min[0], 3))
138
- print(" pos_max_abs:", np.round(pos_d_min[0], 3))
139
- print(" structure_1:")
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(" structure_2:")
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(" diffs:")
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,
@@ -1,6 +1,6 @@
1
1
  import argparse
2
2
 
3
- from rsspolymlp.api.rsspolymlp_utils import geometry_opt, struct_matcher
3
+ from rsspolymlp.api.rsspolymlp_utils import geometry_opt, struct_compare, struct_matcher
4
4
 
5
5
 
6
6
  def run():
@@ -10,6 +10,11 @@ def run():
10
10
  action="store_true",
11
11
  help="Mode: struct_matcher",
12
12
  )
13
+ parser.add_argument(
14
+ "--struct_compare",
15
+ action="store_true",
16
+ help="Mode: struct_compare",
17
+ )
13
18
  parser.add_argument(
14
19
  "--geometry_opt",
15
20
  action="store_true",
@@ -18,7 +23,7 @@ def run():
18
23
 
19
24
  # --struct_matcher mode
20
25
  parser.add_argument(
21
- "--poscar",
26
+ "--poscars",
22
27
  type=str,
23
28
  nargs="+",
24
29
  default=None,
@@ -38,7 +43,7 @@ def run():
38
43
  help="Backend for joblib parallelization",
39
44
  )
40
45
  parser.add_argument(
41
- "--symprec_set",
46
+ "--primitive_symprecs",
42
47
  nargs="*",
43
48
  type=float,
44
49
  default=[1e-5, 1e-4, 1e-3, 1e-2],
@@ -51,6 +56,37 @@ def run():
51
56
  help="Output file name (default: unique_struct.yaml).",
52
57
  )
53
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
+
54
90
  # --geometry_opt mode
55
91
  parser.add_argument(
56
92
  "--pot",
@@ -81,21 +117,32 @@ def run():
81
117
 
82
118
  if args.struct_matcher:
83
119
  struct_matcher(
84
- poscar_paths=args.poscar,
120
+ poscar_paths=args.poscars,
85
121
  num_process=args.num_process,
86
122
  backend=args.backend,
87
- symprec_set=args.symprec_set,
123
+ primitive_symprecs=args.primitive_symprecs,
88
124
  output_file=args.output_file,
89
125
  )
90
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
+
91
140
  if args.geometry_opt:
92
141
  geometry_opt(
93
- poscar_paths=args.poscar,
142
+ poscar_paths=args.poscars,
94
143
  pot=args.pot,
95
144
  pressure=args.pressure,
96
145
  with_symmetry=args.symmetry,
97
146
  solver_method=args.solver_method,
98
147
  c_maxiter=args.c_maxiter,
99
- num_process=args.num_process,
100
- backend=args.backend,
101
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
- if num_process == 1:
93
- for poscar in poscar_path_all:
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/parallel_time.log", "a") as f:
106
- print("Number of CPU cores:", num_process, file=f)
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], output_dir: str = "compress_dft_data", num_process: int = 4
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
- valid_paths, vasprun_status = check_convergence(vasp_paths=vasp_paths)
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)
@@ -6,7 +6,7 @@ import numpy as np
6
6
 
7
7
  from pypolymlp.core.interface_vasp import Vasprun
8
8
  from pypolymlp.core.units import EVtoGPa
9
- from rsspolymlp.analysis.load_plot_data import load_plot_data
9
+ from rsspolymlp.analysis.phase_analysis import load_convexhull_data
10
10
  from rsspolymlp.common.atomic_energy import atomic_energy
11
11
  from rsspolymlp.mlp_dev.pareto_opt_mlp import pareto_front, parse_mlp_property
12
12
  from rsspolymlp.utils.matplot_util.custom_plt import CustomPlt
@@ -33,7 +33,7 @@ def plot_binary(threshold=None):
33
33
 
34
34
  plotter.set_visuality(n_color=4, n_line=4, n_marker=1, color_type="grad")
35
35
 
36
- phase_res = load_plot_data(threshold=threshold)
36
+ phase_res = load_convexhull_data(threshold=threshold)
37
37
  plotter.ax_plot(
38
38
  phase_res["hull_comp"][:, 1],
39
39
  phase_res["hull_e"],