rsspolymlp 0.3.4__tar.gz → 0.4.0__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 (81) hide show
  1. {rsspolymlp-0.3.4/src/rsspolymlp.egg-info → rsspolymlp-0.4.0}/PKG-INFO +16 -12
  2. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/README.md +15 -11
  3. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/pyproject.toml +1 -1
  4. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/eos.py +1 -1
  5. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/ghost_minima.py +9 -13
  6. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/phase_analysis.py +7 -10
  7. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/rss_summarize.py +48 -31
  8. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/struct_matcher/struct_match.py +63 -32
  9. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/unique_struct.py +5 -5
  10. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/cli_rsspolymlp.py +16 -6
  11. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/cli_rsspolymlp_devkit.py +23 -31
  12. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/cli_rsspolymlp_utils.py +13 -0
  13. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/rsspolymlp.py +20 -16
  14. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/rsspolymlp_devkit.py +24 -31
  15. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/rsspolymlp_plot.py +7 -10
  16. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/rsspolymlp_utils.py +47 -12
  17. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/common/atomic_energy.py +1 -1
  18. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/common/composition.py +2 -3
  19. rsspolymlp-0.4.0/src/rsspolymlp/common/interface_vasp.py +318 -0
  20. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/dataset/gen_mlp_dataset.py +9 -8
  21. rsspolymlp-0.3.4/src/rsspolymlp/mlp_dev/dataset/divide_dataset.py → rsspolymlp-0.4.0/src/rsspolymlp/mlp_dev/dataset/split_dataset.py +63 -89
  22. rsspolymlp-0.4.0/src/rsspolymlp/mlp_dev/model_selection/binary/gen_single_model.py +74 -0
  23. {rsspolymlp-0.3.4/src/rsspolymlp/mlp_dev/model_selection → rsspolymlp-0.4.0/src/rsspolymlp/mlp_dev/model_selection/elemental}/gen_single_model.py +3 -3
  24. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/model_selection/n_feature.py +16 -4
  25. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/model_selection/pypolymlp_gridsearch.py +3 -3
  26. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/model_selection/reduce_grid.py +7 -1
  27. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/polymlp_dev.py +2 -1
  28. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/rss/eliminate_duplicates.py +3 -3
  29. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/rss/optimization_mlp.py +10 -6
  30. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/matplot_util/examples/template.py +2 -2
  31. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/opt_sscha/opt_geometry_sscha.py +4 -5
  32. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/opt_sscha/sscha_property.py +10 -2
  33. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/spglib_utils.py +1 -1
  34. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/vasp_util/gen_script.py +3 -2
  35. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/vasp_util/write_poscar.py +12 -1
  36. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0/src/rsspolymlp.egg-info}/PKG-INFO +16 -12
  37. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp.egg-info/SOURCES.txt +5 -9
  38. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/tests/test_cli_help.py +0 -1
  39. rsspolymlp-0.3.4/src/rsspolymlp/analysis/struct_matcher/deprecated/invert_and_swap.py +0 -106
  40. rsspolymlp-0.3.4/src/rsspolymlp/analysis/struct_matcher/deprecated/irrep_position.py +0 -379
  41. rsspolymlp-0.3.4/src/rsspolymlp/analysis/struct_matcher/deprecated/niggli.py +0 -10
  42. rsspolymlp-0.3.4/src/rsspolymlp/analysis/struct_matcher/deprecated/struct_match.py +0 -264
  43. rsspolymlp-0.3.4/src/rsspolymlp/analysis/struct_matcher/deprecated/utils.py +0 -83
  44. rsspolymlp-0.3.4/src/rsspolymlp/utils/opt_sscha/harmonic_real.py +0 -379
  45. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/LICENSE +0 -0
  46. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/setup.cfg +0 -0
  47. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/__init__.py +0 -0
  48. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/__init__.py +0 -0
  49. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/struct_matcher/__init__.py +0 -0
  50. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/struct_matcher/chiral_spg.py +0 -0
  51. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/struct_matcher/invert_and_swap.py +0 -0
  52. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/analysis/struct_matcher/reduced_position.py +0 -0
  53. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/__init__.py +0 -0
  54. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/api/cli_rsspolymlp_plot.py +0 -0
  55. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/common/__init__.py +0 -0
  56. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/common/convert_dict.py +0 -0
  57. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/common/property.py +0 -0
  58. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/dataset/compress_vasprun.py +0 -0
  59. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/estimate_cost.py +0 -0
  60. {rsspolymlp-0.3.4/src/rsspolymlp/mlp_dev/model_selection → rsspolymlp-0.4.0/src/rsspolymlp/mlp_dev/model_selection/elemental}/gen_hybrid_model.py +0 -0
  61. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/mlp_dev/pareto_opt_mlp.py +0 -0
  62. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/rss/__init__.py +0 -0
  63. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/rss/load_logfile.py +0 -0
  64. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/rss/random_struct.py +0 -0
  65. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/__init__.py +0 -0
  66. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/lammps_utils.py +0 -0
  67. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/matplot_util/__init__.py +0 -0
  68. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/matplot_util/custom_plt.py +0 -0
  69. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/matplot_util/examples/__init__.py +0 -0
  70. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/matplot_util/examples/example.py +0 -0
  71. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/matplot_util/make_plot.py +0 -0
  72. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/opt_sscha/opt_position_sscha.py +0 -0
  73. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/opt_sscha/run_opt_sscha.py +0 -0
  74. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/pymatgen_utils.py +0 -0
  75. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/vasp_util/__init__.py +0 -0
  76. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/vasp_util/api.py +0 -0
  77. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp/utils/vasp_util/gen_incar.py +0 -0
  78. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp.egg-info/dependency_links.txt +0 -0
  79. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp.egg-info/entry_points.txt +0 -0
  80. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/src/rsspolymlp.egg-info/requires.txt +0 -0
  81. {rsspolymlp-0.3.4 → rsspolymlp-0.4.0}/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.4
3
+ Version: 0.4.0
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>
@@ -35,17 +35,21 @@ Dynamic: license-file
35
35
 
36
36
  If you use `rsspolymlp` in your study, please cite the following articles.
37
37
 
38
- “Efficient global crystal structure prediction using polynomial machine learning potential in the binary Al–Cu alloy system”, [J. Ceram. Soc. Jpn. 131, 762 (2023)](https://www.jstage.jst.go.jp/article/jcersj2/131/10/131_23053/_article/-char/ja/)
38
+ “Systematic global structure search of bismuth-based binary systems under pressure using machine learning potentials”, [Phys. Rev. Materials 10, 093801 (2026)](https://doi.org/10.1103/k9sg-v7hl)
39
39
  ```
40
- @article{HayatoWakai202323053,
41
- title="{Efficient global crystal structure prediction using polynomial machine learning potential in the binary Al–Cu alloy system}",
42
- author={Hayato Wakai and Atsuto Seko and Isao Tanaka},
43
- journal={J. Ceram. Soc. Jpn.},
44
- volume={131},
45
- number={10},
46
- pages={762-766},
47
- year={2023},
48
- doi={10.2109/jcersj2.23053}
40
+ @article{Phys.Rev.Mater.10.093801,
41
+ title = {Systematic global structure search of bismuth-based binary systems under pressure using machine learning potentials},
42
+ author = {Wakai, Hayato and Ishiwata, Shintaro and Seko, Atsuto},
43
+ journal = {Phys. Rev. Mater.},
44
+ volume = {10},
45
+ issue = {9},
46
+ pages = {093801},
47
+ numpages = {28},
48
+ year = {2026},
49
+ month = {Sep},
50
+ publisher = {American Physical Society},
51
+ doi = {10.1103/k9sg-v7hl},
52
+ url = {https://link.aps.org/doi/10.1103/k9sg-v7hl}
49
53
  }
50
54
  ```
51
55
 
@@ -93,7 +97,7 @@ pip install rsspolymlp
93
97
  - Unique structure identification and RSS result summarization
94
98
  - Ghost minimum structure elimination
95
99
  - Phase stability analysis
96
- - [Development kit for polynomial MLPs](docs/rsspolymlp_devkit.md)
100
+ - [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
97
101
  - MLP dataset generation
98
102
  - DFT dataset division
99
103
  - Polynomial MLP development
@@ -4,17 +4,21 @@
4
4
 
5
5
  If you use `rsspolymlp` in your study, please cite the following articles.
6
6
 
7
- “Efficient global crystal structure prediction using polynomial machine learning potential in the binary Al–Cu alloy system”, [J. Ceram. Soc. Jpn. 131, 762 (2023)](https://www.jstage.jst.go.jp/article/jcersj2/131/10/131_23053/_article/-char/ja/)
7
+ “Systematic global structure search of bismuth-based binary systems under pressure using machine learning potentials”, [Phys. Rev. Materials 10, 093801 (2026)](https://doi.org/10.1103/k9sg-v7hl)
8
8
  ```
9
- @article{HayatoWakai202323053,
10
- title="{Efficient global crystal structure prediction using polynomial machine learning potential in the binary Al–Cu alloy system}",
11
- author={Hayato Wakai and Atsuto Seko and Isao Tanaka},
12
- journal={J. Ceram. Soc. Jpn.},
13
- volume={131},
14
- number={10},
15
- pages={762-766},
16
- year={2023},
17
- doi={10.2109/jcersj2.23053}
9
+ @article{Phys.Rev.Mater.10.093801,
10
+ title = {Systematic global structure search of bismuth-based binary systems under pressure using machine learning potentials},
11
+ author = {Wakai, Hayato and Ishiwata, Shintaro and Seko, Atsuto},
12
+ journal = {Phys. Rev. Mater.},
13
+ volume = {10},
14
+ issue = {9},
15
+ pages = {093801},
16
+ numpages = {28},
17
+ year = {2026},
18
+ month = {Sep},
19
+ publisher = {American Physical Society},
20
+ doi = {10.1103/k9sg-v7hl},
21
+ url = {https://link.aps.org/doi/10.1103/k9sg-v7hl}
18
22
  }
19
23
  ```
20
24
 
@@ -62,7 +66,7 @@ pip install rsspolymlp
62
66
  - Unique structure identification and RSS result summarization
63
67
  - Ghost minimum structure elimination
64
68
  - Phase stability analysis
65
- - [Development kit for polynomial MLPs](docs/rsspolymlp_devkit.md)
69
+ - [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
66
70
  - MLP dataset generation
67
71
  - DFT dataset division
68
72
  - Polynomial MLP development
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rsspolymlp"
7
- version = "0.3.4"
7
+ version = "0.4.0"
8
8
  description = "A framework for random structure search using polynomial MLPs"
9
9
  license = "MIT"
10
10
  authors = [
@@ -90,7 +90,7 @@ class EOSFit:
90
90
  else:
91
91
  self.parameters = result[0]
92
92
 
93
- print(f"RMSE of EOS fit (energy): {self.rmse*1000:.6f} meV")
93
+ print(f"RMSE of EOS fit (energy): {self.rmse * 1000:.6f} meV")
94
94
 
95
95
  @property
96
96
  def rmse(self) -> float:
@@ -8,9 +8,8 @@ import shutil
8
8
  import numpy as np
9
9
  from sklearn.cluster import KMeans
10
10
 
11
- from pypolymlp.core.interface_vasp import Vasprun
12
11
  from pypolymlp.core.units import EVtoGPa
13
- from rsspolymlp.common.atomic_energy import atomic_energy
12
+ from rsspolymlp.common.interface_vasp import parse_properties_from_vasprun
14
13
 
15
14
 
16
15
  def detect_ghost_minima(energies: np.array, distances: np.array):
@@ -165,7 +164,9 @@ def detect_actual_ghost_minima(dft_path):
165
164
  vasprun_get = False
166
165
  for vasprun in vasprun_paths:
167
166
  try:
168
- vaspobj = Vasprun(vasprun)
167
+ structure, (energy_dft, _, stress_dft) = parse_properties_from_vasprun(
168
+ vasprun, units="GPa"
169
+ )
169
170
  vasprun_get = True
170
171
  except Exception:
171
172
  continue
@@ -182,22 +183,17 @@ def detect_actual_ghost_minima(dft_path):
182
183
  )
183
184
  continue
184
185
 
185
- energy_dft = vaspobj.energy
186
- structure = vaspobj.structure
187
- for element in structure.elements:
188
- energy_dft -= atomic_energy(element)
189
- energy_dft /= len(structure.elements)
190
186
  vol_per_atom = structure.volume / len(structure.elements)
191
187
 
192
- # Subtract pressure term from MLP enthalpy
193
188
  mlp_energy = res["energy"]
194
189
  mlp_energy -= pressure * vol_per_atom / EVtoGPa
190
+ energy_dft /= len(structure.elements)
191
+ e_diff = mlp_energy - energy_dft
195
192
 
196
- stress_dft = [(vaspobj.stress / 10).tolist()[i][i] for i in range(3)]
193
+ stress_dft = [stress_dft[i][i] for i in range(3)]
197
194
  press_diff = [pressure - stress_dft[i] for i in range(3)]
198
195
  stress_diff = np.max(np.abs(press_diff)) * vol_per_atom / EVtoGPa
199
196
 
200
- e_diff = mlp_energy - energy_dft
201
197
  diff_all.append(
202
198
  {
203
199
  "energy_diff": e_diff,
@@ -221,8 +217,8 @@ def detect_actual_ghost_minima(dft_path):
221
217
 
222
218
  print(f" - structure: {poscar}", file=f)
223
219
  if not delta_e == "null":
224
- print(f" energy_diff_meV_per_atom: {delta_e*1000:.3f}", file=f)
225
- print(f" stress_diff_meV_per_atom: {delta_s*1000:.3f}", file=f)
220
+ print(f" energy_diff_meV_per_atom: {delta_e * 1000:.3f}", file=f)
221
+ print(f" stress_diff_meV_per_atom: {delta_s * 1000:.3f}", file=f)
226
222
  e_threshold = -0.1 # unit: eV/atom
227
223
  s_threshold = 0.5
228
224
  if delta_e < e_threshold or delta_s > s_threshold:
@@ -7,9 +7,8 @@ import numpy as np
7
7
  import yaml
8
8
  from scipy.spatial import ConvexHull
9
9
 
10
- from pypolymlp.core.interface_vasp import Vasprun
11
- from rsspolymlp.common.atomic_energy import atomic_energy
12
10
  from rsspolymlp.common.composition import compute_composition
11
+ from rsspolymlp.common.interface_vasp import parse_properties_from_vasprun
13
12
 
14
13
 
15
14
  class ConvexHullAnalyzer:
@@ -247,9 +246,9 @@ class ConvexHullAnalyzer:
247
246
  def parse_results(self, input_paths, ghost_minima_file=None, parse_vasp=False):
248
247
  """
249
248
  Populate composition_data by parsing RSS JSON or VASP vasprun.xml outputs.
250
- :param input_paths: List of RSS JSON files or VASP directories.
251
- :param ghost_minima_file: YAML file listing ghost minima to exclude (RSS only).
252
- :param parse_vasp: If True, parse VASP outputs; otherwise parse RSS JSON.
249
+ input_paths: List of RSS JSON files or VASP directories.
250
+ ghost_minima_file: YAML file listing ghost minima to exclude (RSS only).
251
+ parse_vasp: If True, parse VASP outputs; otherwise parse RSS JSON.
253
252
  """
254
253
  if parse_vasp:
255
254
  self._parse_vasp_results(input_paths)
@@ -319,15 +318,13 @@ class ConvexHullAnalyzer:
319
318
  for dft_path in input_paths:
320
319
  vasprun_path = f"{dft_path}/vasprun.xml"
321
320
  try:
322
- vaspobj = Vasprun(vasprun_path)
321
+ structure, (energy_dft, _, _) = parse_properties_from_vasprun(
322
+ vasprun_path
323
+ )
323
324
  except Exception:
324
325
  print(vasprun_path, "failed")
325
326
  continue
326
327
 
327
- energy_dft = vaspobj.energy
328
- structure = vaspobj.structure
329
- for element in structure.elements:
330
- energy_dft -= atomic_energy(element)
331
328
  energy_dft /= len(structure.elements)
332
329
  if energy_dft < -15:
333
330
  print(vasprun_path, "exhibits very low energy:", energy_dft, "eV/atom")
@@ -9,7 +9,6 @@ from time import time
9
9
 
10
10
  import numpy as np
11
11
 
12
- from pypolymlp.core.interface_vasp import Vasprun
13
12
  from pypolymlp.utils.vasp_utils import write_poscar_file
14
13
  from rsspolymlp.analysis.ghost_minima import detect_ghost_minima
15
14
  from rsspolymlp.analysis.unique_struct import (
@@ -18,9 +17,9 @@ from rsspolymlp.analysis.unique_struct import (
18
17
  log_all_unique_structures,
19
18
  log_unique_structures,
20
19
  )
21
- from rsspolymlp.common.atomic_energy import atomic_energy
22
20
  from rsspolymlp.common.composition import compute_composition
23
21
  from rsspolymlp.common.convert_dict import polymlp_struct_from_dict
22
+ from rsspolymlp.common.interface_vasp import Vasprun, parse_properties_from_vasprun
24
23
  from rsspolymlp.common.property import PropUtil
25
24
 
26
25
 
@@ -132,19 +131,22 @@ class RSSResultSummarizer:
132
131
  for ustr in unique_structs:
133
132
  num_opt_str += len(list(ustr.dupstr_paths))
134
133
 
135
- with open(composition_tag + ".yaml", "w") as f:
136
- print("general_information:", file=f)
137
- print(f" sorting_time_sec: {round(time_finish, 2)}", file=f)
138
- print(f" pressure_GPa: {self.pressure}", file=f)
139
- print(f" num_optimized_structs: {num_opt_str}", file=f)
140
- print(f" num_unique_structs: {len(unique_structs)}", file=f)
141
- print("", file=f)
142
-
143
134
  energies = np.array([s.energy for s in unique_structs])
144
135
  distances = np.array([s.least_distance for s in unique_structs])
145
136
 
146
137
  sort_idx = np.argsort(energies)
147
138
  unique_str_sorted = [unique_structs[i] for i in sort_idx]
139
+ if self.thresholds is not None:
140
+ e_min = None
141
+ for idx, u in enumerate(unique_str_sorted):
142
+ if e_min is None:
143
+ e_min = u.energy
144
+ if u.energy - e_min > self.thresholds[0] * 0.001:
145
+ unique_str_sorted = unique_str_sorted[:idx]
146
+ break
147
+ output_file = f"{composition_tag}_{self.thresholds[0]}"
148
+ else:
149
+ output_file = composition_tag
148
150
 
149
151
  if not self.parse_vasp:
150
152
  os.makedirs("ghost_minima", exist_ok=True)
@@ -160,19 +162,27 @@ class RSSResultSummarizer:
160
162
  else:
161
163
  is_ghost_minima = None
162
164
 
165
+ with open(output_file + ".yaml", "w") as f:
166
+ print("general_information:", file=f)
167
+ print(f" sorting_time_sec: {round(time_finish, 2)}", file=f)
168
+ print(f" pressure_GPa: {self.pressure}", file=f)
169
+ print(f" num_optimized_structs: {num_opt_str}", file=f)
170
+ print(f" num_unique_structs: {len(unique_structs)}", file=f)
171
+ print("", file=f)
172
+
163
173
  rss_result_all = log_unique_structures(
164
- composition_tag + ".yaml",
174
+ output_file + ".yaml",
165
175
  unique_str_sorted,
166
176
  is_ghost_minima,
167
177
  pressure=self.pressure,
168
178
  )
169
179
 
170
- with open(f"json/{composition_tag}.json", "w") as f:
180
+ with open(f"json/{output_file}.json", "w") as f:
171
181
  json.dump(rss_result_all, f)
172
182
 
173
183
  if self.thresholds is not None or self.output_poscar is not False:
174
184
  self.generate_poscars(
175
- f"json/{composition_tag}.json",
185
+ f"json/{output_file}.json",
176
186
  thresholds=self.thresholds,
177
187
  output_poscar=self.output_poscar,
178
188
  )
@@ -188,6 +198,13 @@ class RSSResultSummarizer:
188
198
  print(f"Composition {composition_tag}: summarizing...")
189
199
  self.analyzer = UniqueStructureAnalyzer()
190
200
 
201
+ if not self.parse_vasp:
202
+ axis_tol = 0.03
203
+ pos_tol = 0.03
204
+ else:
205
+ axis_tol = 0.1
206
+ pos_tol = 0.1
207
+
191
208
  time_start = time()
192
209
  for res_path in res_paths:
193
210
  print(f" - Processing result file (parent): {res_path}")
@@ -195,8 +212,8 @@ class RSSResultSummarizer:
195
212
  results_same_comp[composition_tag][res_path],
196
213
  standardize_axis=True,
197
214
  keep_unique=True,
198
- axis_tol=0.03,
199
- pos_tol=0.03,
215
+ axis_tol=axis_tol,
216
+ pos_tol=pos_tol,
200
217
  )
201
218
  time_finish = time() - time_start
202
219
 
@@ -333,7 +350,7 @@ class RSSResultSummarizer:
333
350
 
334
351
  for res in rss_results:
335
352
  if threshold is not None:
336
- diff = abs(e_min - res["energy"])
353
+ diff = res["energy"] - e_min
337
354
  if diff * 1000 > threshold:
338
355
  continue
339
356
 
@@ -348,11 +365,10 @@ class RSSResultSummarizer:
348
365
  shutil.copy(poscar_path, dest)
349
366
  else:
350
367
  try:
351
- vaspobj = Vasprun(res["struct_path"])
368
+ polymlp_st = Vasprun(res["struct_path"]).structure
352
369
  except Exception:
353
370
  print(res["struct_path"], "failed")
354
371
  continue
355
- polymlp_st = vaspobj.structure
356
372
  write_poscar_file(polymlp_st, filename=dest)
357
373
  shutil.copy(res["struct_path"], dest_vasp)
358
374
  else:
@@ -368,12 +384,16 @@ class RSSResultSummarizer:
368
384
 
369
385
  def resolve_path(base: Path, p):
370
386
  cwd = Path.cwd()
387
+ target = Path(p)
371
388
  if p is None:
372
389
  return None
373
- p = Path(p)
374
- target = (
375
- base / p if "opt_struct" in p.parts else base / "opt_struct" / p.name
376
- )
390
+ if not self.parse_vasp:
391
+ p = Path(p)
392
+ target = (
393
+ base / p
394
+ if "opt_struct" in p.parts
395
+ else base / "opt_struct" / p.name
396
+ )
377
397
  return os.path.relpath(target, start=cwd)
378
398
 
379
399
  paths_same_comp = defaultdict(list)
@@ -418,24 +438,21 @@ class RSSResultSummarizer:
418
438
  "dupstr_paths": None,
419
439
  }
420
440
  try:
421
- vaspobj = Vasprun(path_name + "/vasprun.xml")
441
+ polymlp_st, (energy_dft, _, _) = parse_properties_from_vasprun(
442
+ path_name + "/vasprun.xml",
443
+ )
422
444
  except Exception:
423
445
  print("ParseError:", path_name + "/vasprun.xml")
424
446
  continue
425
447
 
426
- polymlp_st = vaspobj.structure
427
- objprop = PropUtil(polymlp_st.axis.T, polymlp_st.positions.T)
428
- spg_list = objprop.analyze_space_group(polymlp_st.elements)
429
-
430
- energy_dft = vaspobj.energy
431
- for element in polymlp_st.elements:
432
- energy_dft -= atomic_energy(element)
433
448
  energy_dft /= len(polymlp_st.elements)
434
-
435
449
  if energy_dft < -10:
436
450
  print(path_name, "exhibits an unphysically low energy. Skipping.")
437
451
  continue
438
452
 
453
+ objprop = PropUtil(polymlp_st.axis.T, polymlp_st.positions.T)
454
+ spg_list = objprop.analyze_space_group(polymlp_st.elements)
455
+
439
456
  res_dict["struct_path"] = os.path.relpath(
440
457
  path_name + "/vasprun.xml", os.getcwd()
441
458
  )
@@ -1,15 +1,17 @@
1
+ import math
1
2
  import re
2
3
  from collections import Counter
4
+ from contextlib import redirect_stdout
3
5
  from dataclasses import dataclass
4
6
  from typing import Optional
5
7
 
6
8
  import numpy as np
7
9
 
8
10
  from pypolymlp.core.data_format import PolymlpStructure
9
- from pypolymlp.core.interface_vasp import Poscar
10
11
  from pypolymlp.utils.vasp_utils import write_poscar_file
11
12
  from rsspolymlp.analysis.struct_matcher.reduced_position import StructRepReducer
12
13
  from rsspolymlp.common.composition import compute_composition
14
+ from rsspolymlp.common.interface_vasp import Poscar
13
15
  from rsspolymlp.utils.spglib_utils import SymCell
14
16
 
15
17
 
@@ -30,6 +32,7 @@ def struct_match(
30
32
  pos_tol: float = 0.01,
31
33
  spg_match: bool = True,
32
34
  verbose: bool = False,
35
+ output_file: str = "struct_matcher.yaml",
33
36
  ) -> bool:
34
37
  """
35
38
  Determine whether two sets of ReducedStructRep objects are structurally
@@ -111,40 +114,64 @@ def struct_match(
111
114
 
112
115
  if verbose:
113
116
 
114
- def log_axis_positions(symprec, axis, positions):
117
+ def log_axis_positions(symprec, axis, positions, round_axis=4, round_pos=3):
115
118
  print(" - symprec:", np.round(symprec, 5).tolist())
116
- print(" metric_tensor:", np.round(axis, 4).tolist())
119
+ print(" metric_tensor:", np.round(axis, round_axis).tolist())
117
120
  print(" positions:")
118
- for axis_tag, p in zip(
119
- ["a", "b", "c"], np.round(positions.reshape(3, -1), 3).tolist()
120
- ):
121
- formatted = ",".join(f"{val:6.3f}" for val in p)
121
+ for p in positions.reshape(3, -1).tolist():
122
+ formatted = ",".join(f"{val:{round_pos + 3}.{round_pos}f}" for val in p)
122
123
  print(f" - [{formatted}]")
123
124
 
124
- print("--- results of rsspolymlp.analysis.struct_matcher ---")
125
- print("tolerance:")
126
- print(" axis_tol:", axis_tol)
127
- print(" pos_tol:", pos_tol)
128
- print("structures:")
129
- for i, st_set in enumerate([st_1_set, st_2_set]):
130
- print(f" - struct_No: {i+1}")
131
- for st in st_set:
132
- print(" spg_number:", st.spg_number)
133
- print(" representations:")
134
- for h, pos in enumerate(st.positions):
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))
137
- if axis_d_min is not None:
138
- print("difference_log:")
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:")
142
- log_axis_positions(pos_d_min[1][0], axis_d_min[1][0], pos_d_min[1][1])
143
- print(" structure_2:")
144
- log_axis_positions(pos_d_min[1][2], axis_d_min[1][1], pos_d_min[1][3])
145
- print(" diffs:")
146
- log_axis_positions([], axis_d_min[1][2], pos_d_min[1][4])
147
- print("Match:", struct_match)
125
+ with open(output_file, "w") as f, redirect_stdout(f):
126
+ print("tolerance:")
127
+ print(" axis_tol:", axis_tol)
128
+ print(" pos_tol:", pos_tol)
129
+ print("structures:")
130
+ for i, st_set in enumerate([st_1_set, st_2_set]):
131
+ print(f" - struct_No: {i + 1}")
132
+ for st in st_set:
133
+ print(" spg_number:", st.spg_number)
134
+ print(" representations:")
135
+ for h, pos in enumerate(st.positions):
136
+ log_axis_positions(st.symprec_set[h], st.axis[h], pos)
137
+ print("min_axis_l2_norm:", np.round(min_axis_l2_norm, 3))
138
+ if axis_d_min is not None:
139
+ x_axis = abs(float(axis_d_min[0]))
140
+ if x_axis <= 1e-12:
141
+ round_axis = 6
142
+ else:
143
+ round_axis = min(-math.floor(math.log10(x_axis)) + 1, 6)
144
+ x_pos = abs(float(pos_d_min[0]))
145
+ if x_pos <= 1e-12:
146
+ round_pos = 6
147
+ else:
148
+ round_pos = min(-math.floor(math.log10(x_pos)) + 1, 6)
149
+
150
+ print("difference_log:")
151
+ print(" - axis_l2_norm:", np.round(axis_d_min[0], round_axis))
152
+ print(" pos_max_abs:", np.round(pos_d_min[0], round_pos))
153
+ print(" structure_1:")
154
+ log_axis_positions(
155
+ pos_d_min[1][0],
156
+ axis_d_min[1][0],
157
+ pos_d_min[1][1],
158
+ round_axis,
159
+ round_pos,
160
+ )
161
+ print(" structure_2:")
162
+ log_axis_positions(
163
+ pos_d_min[1][2],
164
+ axis_d_min[1][1],
165
+ pos_d_min[1][3],
166
+ round_axis,
167
+ round_pos,
168
+ )
169
+ print(" diffs:")
170
+ log_axis_positions(
171
+ [], axis_d_min[1][2], pos_d_min[1][4], round_axis, round_pos
172
+ )
173
+ print("Match:", struct_match)
174
+ print(f"{output_file} is generated.")
148
175
 
149
176
  return struct_match
150
177
 
@@ -153,6 +180,7 @@ def generate_primitive_cells(
153
180
  poscar_name: Optional[str] = None,
154
181
  polymlp_st: Optional[PolymlpStructure] = None,
155
182
  symprec_set: list[float] = [1e-5, 1e-4, 1e-3, 1e-2],
183
+ refine_cell: bool = False,
156
184
  ) -> tuple[list[PolymlpStructure], list[int]]:
157
185
  """
158
186
  Generate primitive cells of a given structure under different symmetry tolerances.
@@ -189,7 +217,10 @@ def generate_primitive_cells(
189
217
  continue
190
218
  else:
191
219
  try:
192
- primitive_st = symutil.primitive_cell()
220
+ if not refine_cell:
221
+ primitive_st = symutil.primitive_cell()
222
+ else:
223
+ primitive_st = symutil.refine_cell()
193
224
  except TypeError:
194
225
  continue
195
226
  primitive_st_set.append(primitive_st)
@@ -6,7 +6,7 @@ import joblib
6
6
  import numpy as np
7
7
 
8
8
  from pypolymlp.core.data_format import PolymlpStructure
9
- from pypolymlp.core.interface_vasp import Poscar
9
+ from rsspolymlp.common.interface_vasp import Poscar
10
10
  from rsspolymlp.analysis.struct_matcher.struct_match import (
11
11
  ReducedStructRep,
12
12
  generate_primitive_cells,
@@ -430,11 +430,11 @@ def log_all_unique_structures(
430
430
  with open(file_name, "a") as f:
431
431
  print("unique_structures:", file=f)
432
432
  for idx1, _str in enumerate(unique_structs):
433
- print(f" - struct_No: {idx1+1}", file=f)
433
+ print(f" - struct_No: {idx1 + 1}", file=f)
434
434
  print(" structures:", file=f)
435
435
  for idx2, _str in enumerate(unique_structs[idx1]):
436
- print(f" - sub_struct_No: '{idx1+1}_{idx2+1}'", file=f)
437
- print(f" poscar_name: {_str.struct_path}", file=f)
436
+ print(f" - sub_struct_No: '{idx1 + 1}_{idx2 + 1}'", file=f)
437
+ print(f" struct_path: {_str.struct_path}", file=f)
438
438
  print(f" pressure: {_str.pressure}", file=f)
439
439
  print(f" enthalpy: {_str.energy}", file=f)
440
440
  print(f" axis: {_str.axis_abc}", file=f)
@@ -460,7 +460,7 @@ def log_all_unique_structures(
460
460
  _res["energy"] = _str.energy
461
461
  _res["pressure"] = None
462
462
  _res["spg_list"] = _str.spg_list
463
- _res["struct_no"] = f"{idx1 + 1}_{idx2+1}"
463
+ _res["struct_no"] = f"{idx1 + 1}_{idx2 + 1}"
464
464
  _res["is_ghost_minima"] = False
465
465
  rss_results.append(_res)
466
466
  if unique_structs_prop is not None:
@@ -4,9 +4,9 @@ from rsspolymlp.api.rsspolymlp import (
4
4
  rss_ghost_minima_cands,
5
5
  rss_ghost_minima_validate,
6
6
  rss_init_struct,
7
+ rss_opt,
7
8
  rss_phase_analysis,
8
9
  rss_polymlp,
9
- rss_run_parallel,
10
10
  rss_summarize,
11
11
  rss_uniq_struct,
12
12
  )
@@ -21,9 +21,9 @@ def run():
21
21
  help="Mode: Initial random structure generation",
22
22
  )
23
23
  parser.add_argument(
24
- "--rss_parallel",
24
+ "--rss_opt",
25
25
  action="store_true",
26
- help="Mode: RSS using the polynomial MLP in parallel",
26
+ help="Mode: RSS using the polynomial MLP",
27
27
  )
28
28
  parser.add_argument(
29
29
  "--rss_single",
@@ -100,7 +100,7 @@ def run():
100
100
  help="Minimum interatomic distance in initial structure (angstrom)",
101
101
  )
102
102
 
103
- # --rss_parallel mode
103
+ # --rss_opt mode
104
104
  parser.add_argument(
105
105
  "--pot",
106
106
  nargs="*",
@@ -108,6 +108,12 @@ def run():
108
108
  default=["polymlp.yaml"],
109
109
  help="Potential file for polynomial MLP",
110
110
  )
111
+ parser.add_argument(
112
+ "--init_poscars_dir",
113
+ type=str,
114
+ default="initial_struct",
115
+ help="Directory containing POSCARs describing initial structures",
116
+ )
111
117
  parser.add_argument(
112
118
  "--n_opt_str",
113
119
  type=int,
@@ -131,6 +137,7 @@ def run():
131
137
  parser.add_argument(
132
138
  "--solver_method", type=str, default="CG", help="Type of solver"
133
139
  )
140
+ parser.add_argument("--gtol", type=float, default=1e-6, help="")
134
141
  parser.add_argument(
135
142
  "--c_maxiter",
136
143
  type=int,
@@ -260,12 +267,14 @@ def run():
260
267
  max_volume=args.max_volume,
261
268
  )
262
269
 
263
- if args.rss_parallel:
264
- rss_run_parallel(
270
+ if args.rss_opt:
271
+ rss_opt(
265
272
  pot=args.pot,
273
+ init_poscars_dir=args.init_poscars_dir,
266
274
  pressure=args.pressure,
267
275
  with_symmetry=args.symmetry,
268
276
  solver_method=args.solver_method,
277
+ gtol=args.gtol,
269
278
  c_maxiter=args.c_maxiter,
270
279
  n_opt_str=args.n_opt_str,
271
280
  not_stop_rss=args.not_stop_rss,
@@ -292,6 +301,7 @@ def run():
292
301
  max_volume=args.max_volume,
293
302
  least_distance=args.least_distance,
294
303
  solver_method=args.solver_method,
304
+ gtol=args.gtol,
295
305
  not_stop_rss=args.not_stop_rss,
296
306
  num_process=args.num_process,
297
307
  backend=args.backend,