rsspolymlp 0.4.1__tar.gz → 0.4.3__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 (84) hide show
  1. {rsspolymlp-0.4.1/src/rsspolymlp.egg-info → rsspolymlp-0.4.3}/PKG-INFO +28 -22
  2. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/README.md +28 -22
  3. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/pyproject.toml +1 -1
  4. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/rss_summarize.py +27 -28
  5. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/assignment_algo.py +181 -0
  6. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/gen_struct_rep.py +371 -0
  7. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/identify_uniqstr.py +232 -0
  8. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/redrep_lattice.py +144 -0
  9. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/redrep_position.py +371 -0
  10. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/struct_match.py +290 -0
  11. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/test/gen_lattice.py +53 -0
  12. rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/test/time_measure.py +0 -0
  13. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp_utils.py +52 -40
  14. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/rsspolymlp.py +2 -1
  15. rsspolymlp-0.4.3/src/rsspolymlp/api/rsspolymlp_utils.py +238 -0
  16. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/eliminate_duplicates.py +9 -6
  17. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/random_struct.py +32 -7
  18. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3/src/rsspolymlp.egg-info}/PKG-INFO +28 -22
  19. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/SOURCES.txt +7 -3
  20. rsspolymlp-0.4.1/src/rsspolymlp/analysis/struct_matcher/gen_redrep.py +0 -338
  21. rsspolymlp-0.4.1/src/rsspolymlp/analysis/struct_matcher/invert_and_swap.py +0 -457
  22. rsspolymlp-0.4.1/src/rsspolymlp/analysis/struct_matcher/reduced_position.py +0 -366
  23. rsspolymlp-0.4.1/src/rsspolymlp/analysis/struct_matcher/struct_match.py +0 -331
  24. rsspolymlp-0.4.1/src/rsspolymlp/api/rsspolymlp_utils.py +0 -175
  25. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/LICENSE +0 -0
  26. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/setup.cfg +0 -0
  27. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/__init__.py +0 -0
  28. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/__init__.py +0 -0
  29. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/eos.py +0 -0
  30. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/ghost_minima.py +0 -0
  31. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/phase_analysis.py +0 -0
  32. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/struct_matcher/__init__.py +0 -0
  33. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/struct_matcher/chiral_spg.py +0 -0
  34. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/__init__.py +0 -0
  35. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp.py +0 -0
  36. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp_devkit.py +0 -0
  37. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp_plot.py +0 -0
  38. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/rsspolymlp_devkit.py +0 -0
  39. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/api/rsspolymlp_plot.py +0 -0
  40. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/common/__init__.py +0 -0
  41. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/common/atomic_energy.py +0 -0
  42. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/common/composition.py +0 -0
  43. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/common/convert_dict.py +0 -0
  44. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/common/interface_vasp.py +0 -0
  45. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/common/property.py +0 -0
  46. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/dataset/compress_vasprun.py +0 -0
  47. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/dataset/gen_mlp_dataset.py +0 -0
  48. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/dataset/split_dataset.py +0 -0
  49. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/estimate_cost.py +0 -0
  50. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/binary/gen_single_model.py +0 -0
  51. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/elemental/gen_hybrid_model.py +0 -0
  52. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/elemental/gen_single_model.py +0 -0
  53. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/n_feature.py +0 -0
  54. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/pypolymlp_gridsearch.py +0 -0
  55. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/reduce_grid.py +0 -0
  56. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/pareto_opt_mlp.py +0 -0
  57. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/polymlp_dev.py +0 -0
  58. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/__init__.py +0 -0
  59. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/load_logfile.py +0 -0
  60. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/optimization_mlp.py +0 -0
  61. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/__init__.py +0 -0
  62. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/lammps_utils.py +0 -0
  63. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/__init__.py +0 -0
  64. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/custom_plt.py +0 -0
  65. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/examples/__init__.py +0 -0
  66. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/examples/example.py +0 -0
  67. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/examples/template.py +0 -0
  68. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/make_plot.py +0 -0
  69. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/opt_geometry_sscha.py +0 -0
  70. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/opt_position_sscha.py +0 -0
  71. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/run_opt_sscha.py +0 -0
  72. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/sscha_property.py +0 -0
  73. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/pymatgen_utils.py +0 -0
  74. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/spglib_utils.py +0 -0
  75. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/__init__.py +0 -0
  76. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/api.py +0 -0
  77. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/gen_incar.py +0 -0
  78. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/gen_script.py +0 -0
  79. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/write_poscar.py +0 -0
  80. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/dependency_links.txt +0 -0
  81. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/entry_points.txt +0 -0
  82. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/requires.txt +0 -0
  83. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/top_level.txt +0 -0
  84. {rsspolymlp-0.4.1 → rsspolymlp-0.4.3}/tests/test_cli_help.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rsspolymlp
3
- Version: 0.4.1
3
+ Version: 0.4.3
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>
@@ -31,27 +31,9 @@ Dynamic: license-file
31
31
 
32
32
  # Framework for random structure search using polynomial machine learning potentials
33
33
 
34
- ## Citation of rsspolymlp
35
-
36
- If you use `rsspolymlp` in your study, please cite the following articles.
37
-
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
- ```
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}
53
- }
54
- ```
34
+ `rsspolymlp` is a Python code designed to conduct random structure searches (RSS) using polynomial machine learning potentials (MLPs).
35
+ The code provides functionalities for generating initial random structures, performing geometry optimization using polynomial MLPs, and eliminating duplicate structures.
36
+ The formulation and development of polynomial MLPs are detailed in [`pypolymlp`](https://github.com/sekocha/pypolymlp).
55
37
 
56
38
  ## Installation
57
39
 
@@ -89,6 +71,7 @@ conda install -c conda-forge scikit-learn joblib pypolymlp spglib symfc
89
71
  pip install rsspolymlp
90
72
  ```
91
73
 
74
+
92
75
  ## How to use rsspolymlp
93
76
 
94
77
  - [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
@@ -107,3 +90,26 @@ pip install rsspolymlp
107
90
  - Single-point calculation
108
91
  - Local geometry optimization
109
92
  - [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
93
+
94
+
95
+ ## Citation of rsspolymlp
96
+
97
+ If you use `rsspolymlp` in your study, please cite the following articles.
98
+
99
+ “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)
100
+ ```
101
+ @article{Phys.Rev.Mater.10.093801,
102
+ title = {Systematic global structure search of bismuth-based binary systems under pressure using machine learning potentials},
103
+ author = {Wakai, Hayato and Ishiwata, Shintaro and Seko, Atsuto},
104
+ journal = {Phys. Rev. Mater.},
105
+ volume = {10},
106
+ issue = {9},
107
+ pages = {093801},
108
+ numpages = {28},
109
+ year = {2026},
110
+ month = {Sep},
111
+ publisher = {American Physical Society},
112
+ doi = {10.1103/k9sg-v7hl},
113
+ url = {https://link.aps.org/doi/10.1103/k9sg-v7hl}
114
+ }
115
+ ```
@@ -1,26 +1,8 @@
1
1
  # Framework for random structure search using polynomial machine learning potentials
2
2
 
3
- ## Citation of rsspolymlp
4
-
5
- If you use `rsspolymlp` in your study, please cite the following articles.
6
-
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
- ```
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}
22
- }
23
- ```
3
+ `rsspolymlp` is a Python code designed to conduct random structure searches (RSS) using polynomial machine learning potentials (MLPs).
4
+ The code provides functionalities for generating initial random structures, performing geometry optimization using polynomial MLPs, and eliminating duplicate structures.
5
+ The formulation and development of polynomial MLPs are detailed in [`pypolymlp`](https://github.com/sekocha/pypolymlp).
24
6
 
25
7
  ## Installation
26
8
 
@@ -58,6 +40,7 @@ conda install -c conda-forge scikit-learn joblib pypolymlp spglib symfc
58
40
  pip install rsspolymlp
59
41
  ```
60
42
 
43
+
61
44
  ## How to use rsspolymlp
62
45
 
63
46
  - [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
@@ -75,4 +58,27 @@ pip install rsspolymlp
75
58
  - [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
76
59
  - Single-point calculation
77
60
  - Local geometry optimization
78
- - [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
61
+ - [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
62
+
63
+
64
+ ## Citation of rsspolymlp
65
+
66
+ If you use `rsspolymlp` in your study, please cite the following articles.
67
+
68
+ “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)
69
+ ```
70
+ @article{Phys.Rev.Mater.10.093801,
71
+ title = {Systematic global structure search of bismuth-based binary systems under pressure using machine learning potentials},
72
+ author = {Wakai, Hayato and Ishiwata, Shintaro and Seko, Atsuto},
73
+ journal = {Phys. Rev. Mater.},
74
+ volume = {10},
75
+ issue = {9},
76
+ pages = {093801},
77
+ numpages = {28},
78
+ year = {2026},
79
+ month = {Sep},
80
+ publisher = {American Physical Society},
81
+ doi = {10.1103/k9sg-v7hl},
82
+ url = {https://link.aps.org/doi/10.1103/k9sg-v7hl}
83
+ }
84
+ ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rsspolymlp"
7
- version = "0.4.1"
7
+ version = "0.4.3"
8
8
  description = "A framework for random structure search using polynomial MLPs"
9
9
  license = "MIT"
10
10
  authors = [
@@ -9,15 +9,14 @@ from time import time
9
9
  from typing import Optional
10
10
 
11
11
  import numpy as np
12
-
13
12
  from pypolymlp.utils.vasp_utils import write_poscar_file
13
+
14
14
  from rsspolymlp.analysis.ghost_minima import detect_ghost_minima
15
- from rsspolymlp.analysis.struct_matcher.gen_redrep import (
16
- ReducedStructReps,
17
- generate_redreps_parallel,
15
+ from rsspolymlp.analysis.struct_matcher.gen_struct_rep import (
16
+ StructRepGenerator,
17
+ StructReps,
18
18
  )
19
- from rsspolymlp.analysis.struct_matcher.struct_match import (
20
- UniqueStructIdentifier,
19
+ from rsspolymlp.analysis.struct_matcher.identify_uniqstr import (
21
20
  identify_unique_structure,
22
21
  )
23
22
  from rsspolymlp.common.composition import compute_composition
@@ -58,7 +57,7 @@ class RSSResultSummarizer:
58
57
  self.update_parent = update_parent
59
58
 
60
59
  self.pressure = None
61
- self.analyzer = UniqueStructIdentifier()
60
+ self.analyzer = None
62
61
 
63
62
  def run_summarize(self):
64
63
  os.makedirs("json", exist_ok=True)
@@ -92,8 +91,6 @@ class RSSResultSummarizer:
92
91
 
93
92
  for comp_tag, res_paths in json_paths_c.items():
94
93
  print(f"Composition {comp_tag}: summarizing...")
95
- self.analyzer = UniqueStructIdentifier()
96
-
97
94
  time_start = time()
98
95
 
99
96
  processed_paths = set()
@@ -196,8 +193,6 @@ class RSSResultSummarizer:
196
193
 
197
194
  for comp_tag, res_paths in json_paths_c.items():
198
195
  print(f"Composition {comp_tag}: summarizing...")
199
- self.analyzer = UniqueStructIdentifier()
200
-
201
196
  if not self.parse_vasp:
202
197
  axis_tol = 0.03
203
198
  pos_tol = 0.03
@@ -210,7 +205,7 @@ class RSSResultSummarizer:
210
205
  print(f" - Processing result file (parent): {res_path}")
211
206
  self.analyzer = identify_unique_structure(
212
207
  rss_results_c[comp_tag][res_path],
213
- standardize_axis=True,
208
+ normalize_axis=True,
214
209
  keep_unique=True,
215
210
  axis_tol=axis_tol,
216
211
  pos_tol=pos_tol,
@@ -264,15 +259,17 @@ class RSSResultSummarizer:
264
259
  r["dupstr_paths"] = set(r["dupstr_paths"])
265
260
 
266
261
  print(" - Converting reduced crystal structure representation...")
267
- redreps_list = generate_redreps_parallel(
268
- rss_results,
262
+ generator = StructRepGenerator(
269
263
  num_process=self.num_process,
270
264
  backend=self.backend,
271
- symprec_set1=self.symprec_set,
265
+ primitive_symprecs=self.primitive_symprecs,
266
+ )
267
+ struct_reps_list = generator.generate_struct_reps_parallel(
268
+ rss_results,
272
269
  )
273
270
  if self.update_parent:
274
271
  print(" - Eliminating duplicate structures...")
275
- for idx, redreps in enumerate(redreps_list):
272
+ for idx, redreps in enumerate(struct_reps_list):
276
273
  self.analyzer.identify_duplicate_struct(
277
274
  unique_struct=redreps,
278
275
  other_properties=rss_results[idx],
@@ -280,7 +277,7 @@ class RSSResultSummarizer:
280
277
  pos_tol=0.03,
281
278
  )
282
279
  else:
283
- self.analyzer._initialize_unique_structs(redreps_list, rss_results)
280
+ self.analyzer._initialize_unique_structs(struct_reps_list, rss_results)
284
281
 
285
282
  return set(processed_paths)
286
283
 
@@ -461,21 +458,22 @@ class RSSResultSummarizer:
461
458
 
462
459
  def dump_json_rss_results(
463
460
  file_name: str,
464
- redreps_list: list[ReducedStructReps],
461
+ struct_reps_list: list[StructReps],
465
462
  enthalpy_lists: list[float],
466
463
  is_ghost_minima=None,
467
464
  pressure=None,
468
465
  ):
469
466
  if is_ghost_minima is None:
470
- is_ghost_minima = np.full_like(redreps_list, False, dtype=bool)
467
+ is_ghost_minima = np.full_like(struct_reps_list, False, dtype=bool)
471
468
 
472
469
  rss_results = []
473
- for idx, _str in enumerate(redreps_list):
470
+ for idx, _str in enumerate(struct_reps_list):
474
471
  polymlp_st = _str.original_polymlp_st
475
472
  objprop = PropUtil(polymlp_st.axis.T, polymlp_st.positions.T)
476
473
  rss_results.append(
477
474
  {
478
475
  "struct_path": _str.struct_path,
476
+ "poscar_path": _str.struct_path,
479
477
  "structure": polymlp_struct_to_dict(polymlp_st),
480
478
  "energy": enthalpy_lists[idx],
481
479
  "axis_abc": objprop.abc,
@@ -487,8 +485,8 @@ def dump_json_rss_results(
487
485
  "is_ghost_minima": bool(is_ghost_minima[idx]),
488
486
  }
489
487
  )
490
- if len(redreps_list) > 0:
491
- comp_res = compute_composition(redreps_list[0].original_polymlp_st.elements)
488
+ if len(struct_reps_list) > 0:
489
+ comp_res = compute_composition(struct_reps_list[0].original_polymlp_st.elements)
492
490
  rss_result_all = {
493
491
  "elements": comp_res.unique_elements.tolist(),
494
492
  "comp_ratio": comp_res.comp_ratio,
@@ -507,13 +505,13 @@ def dump_json_rss_results(
507
505
 
508
506
  def log_unique_structures(
509
507
  file_name: str,
510
- redreps_list: list[ReducedStructReps],
508
+ struct_reps_list: list[StructReps],
511
509
  enthalpy_lists: Optional[list[float]] = None,
512
510
  is_ghost_minima=None,
513
511
  unique_struct_iters=None,
514
512
  ):
515
513
  if is_ghost_minima is None:
516
- is_ghost_minima = np.full_like(redreps_list, False, dtype=bool)
514
+ is_ghost_minima = np.full_like(struct_reps_list, False, dtype=bool)
517
515
  energy_min = None
518
516
  if enthalpy_lists is not None:
519
517
  for i in range(len(enthalpy_lists)):
@@ -522,9 +520,10 @@ def log_unique_structures(
522
520
  break
523
521
 
524
522
  struct_num_max = max(
525
- (_s.struct_tag for _s in redreps_list if _s.struct_tag is not None), default=0
523
+ (_s.struct_tag for _s in struct_reps_list if _s.struct_tag is not None),
524
+ default=0,
526
525
  )
527
- for _s in redreps_list:
526
+ for _s in struct_reps_list:
528
527
  if _s.struct_tag is None:
529
528
  struct_num_max += 1
530
529
  _s.struct_tag = struct_num_max
@@ -532,7 +531,7 @@ def log_unique_structures(
532
531
  with open(file_name, "a") as f:
533
532
  print("unique_structures:", file=f)
534
533
  for is_ghost in [False, True]:
535
- for idx, _str in enumerate(redreps_list):
534
+ for idx, _str in enumerate(struct_reps_list):
536
535
  if energy_min is not None:
537
536
  e_diff = round((enthalpy_lists[idx] - energy_min) * 1000, 2)
538
537
  if (not is_ghost and e_diff < -300) or (
@@ -579,7 +578,7 @@ def log_unique_structures(
579
578
 
580
579
  def log_all_unique_structures(
581
580
  file_name,
582
- unique_structs: list[list[ReducedStructReps]],
581
+ unique_structs: list[list[StructReps]],
583
582
  unique_str_prop: Optional[list[list[dict]]] = None,
584
583
  unique_other_prop=None,
585
584
  ):
@@ -0,0 +1,181 @@
1
+ import time
2
+
3
+ import numpy as np
4
+ from scipy.sparse import csr_array
5
+ from scipy.sparse.csgraph import maximum_bipartite_matching
6
+
7
+
8
+ def sort_match_screen(
9
+ pos_reps1: np.ndarray,
10
+ pos_reps2: np.ndarray,
11
+ elements1: np.ndarray,
12
+ elements2: np.ndarray,
13
+ axis_abc: np.ndarray,
14
+ pos_tol: float,
15
+ verbose: bool = False,
16
+ ):
17
+ # pos1: (N1, n_atoms, 3)
18
+ # pos2: (N2, n_atoms, 3)
19
+ if len(elements1) != len(elements2):
20
+ return np.zeros((len(pos_reps1), len(pos_reps2)), dtype=bool)
21
+ unique_elements = np.unique(elements1)
22
+
23
+ def sort_positions_axis(pos_reps, elements, axis):
24
+ pos_reps = np.asarray(pos_reps)
25
+ sorted_reps = np.empty_like(pos_reps[:, :, axis])
26
+ start = 0
27
+ for el in unique_elements:
28
+ idx = np.flatnonzero(elements == el)
29
+ n = len(idx)
30
+ sorted_reps[:, start : start + n] = np.sort(
31
+ pos_reps[:, idx, axis],
32
+ axis=1,
33
+ )
34
+ start += n
35
+ return sorted_reps
36
+
37
+ matched = np.ones(
38
+ (len(pos_reps1), len(pos_reps2)),
39
+ dtype=bool,
40
+ )
41
+ for axis in range(3):
42
+ rows, cols = np.where(matched)
43
+ if len(rows) == 0:
44
+ break
45
+
46
+ t_start_s = time.time()
47
+ pos1_axis = sort_positions_axis(pos_reps1, elements1, axis)
48
+ pos2_axis = sort_positions_axis(pos_reps2, elements2, axis)
49
+ if verbose:
50
+ print(f"code: sort_match_screen (axis {axis})")
51
+ print(f" Sorting: {round((time.time() - t_start_s) * 1000, 2)} ms")
52
+
53
+ t_start_m = time.time()
54
+ diff = pos1_axis[rows] - pos2_axis[cols]
55
+ diff -= axis_abc[axis] * np.round(diff / axis_abc[axis])
56
+ matched[rows, cols] = np.all(np.abs(diff) <= pos_tol, axis=1)
57
+ if verbose:
58
+ print(f" Matching: {round((time.time() - t_start_m) * 1000, 2)} ms")
59
+ print(f" Candidate matches: {np.count_nonzero(matched)}")
60
+ return matched
61
+
62
+
63
+ def greedy_match(
64
+ pos1: np.ndarray,
65
+ pos2: np.ndarray,
66
+ elements1: np.ndarray,
67
+ elements2: np.ndarray,
68
+ axis_abc: np.ndarray,
69
+ pos_tol: float,
70
+ verbose: bool = False,
71
+ ):
72
+ judge = True
73
+ inv_axis_abc = 1 / axis_abc
74
+
75
+ t_start_g = time.time()
76
+ for el in np.unique(elements1):
77
+ if not judge:
78
+ break
79
+ targets1 = np.where(elements1 == el)[0]
80
+ targets2 = np.where(elements2 == el)[0]
81
+ used = np.zeros(len(targets1), dtype=bool)
82
+ for i in targets1:
83
+ diff = np.abs(pos2[targets2] - pos1[i])
84
+ diff -= axis_abc * np.round(inv_axis_abc * diff)
85
+ diff_max = np.max(np.abs(diff), axis=1)
86
+ diff[used] = np.inf
87
+ j = np.argmin(diff_max)
88
+ if diff_max[j] >= pos_tol:
89
+ judge = False
90
+ break
91
+ used[j] = True
92
+ if verbose:
93
+ print("code: greedy_match")
94
+ print(f" Matching: {round((time.time() - t_start_g) * 1000, 2)} ms")
95
+
96
+ if judge:
97
+ return True
98
+ else:
99
+ return False
100
+
101
+
102
+ def bottleneck_assignment(
103
+ pos1: np.ndarray,
104
+ pos2: np.ndarray,
105
+ elements1: np.ndarray,
106
+ elements2: np.ndarray,
107
+ axis_abc: np.ndarray,
108
+ pos_tol: float,
109
+ best_matching: bool = False,
110
+ verbose: bool = False,
111
+ ):
112
+ inv_axis_abc = 1 / axis_abc
113
+ for el in np.unique(elements1):
114
+ targets1 = np.where(elements1 == el)[0]
115
+ targets2 = np.where(elements2 == el)[0]
116
+ pos1_sub = pos1[targets1]
117
+ pos2_sub = pos2[targets2]
118
+
119
+ t_start_d = time.time()
120
+ diff = pos1_sub[:, None, :] - pos2_sub[None, :, :]
121
+ diff -= axis_abc * np.round(diff * inv_axis_abc)
122
+ pos_d = np.max(np.abs(diff), axis=2)
123
+ n = pos_d.shape[0]
124
+ if verbose:
125
+ print("code: bottleneck_assignment")
126
+ print(
127
+ f" Difference Calc.: {round((time.time() - t_start_d) * 1000, 2)} ms"
128
+ )
129
+
130
+ t_start_m = time.time()
131
+ if best_matching:
132
+ # Sort distinct candidate distances
133
+ values = np.unique(pos_d)
134
+ left, right = 0, len(values) - 1
135
+ while left < right:
136
+ mid = (left + right) // 2
137
+ rows, cols = np.where(pos_d <= values[mid])
138
+ graph = csr_array(
139
+ (
140
+ np.ones(len(rows), dtype=np.int8),
141
+ (rows, cols),
142
+ ),
143
+ shape=pos_d.shape,
144
+ )
145
+ matching = maximum_bipartite_matching(graph, perm_type="column")
146
+ if np.all(matching >= 0):
147
+ right = mid
148
+ else:
149
+ left = mid + 1
150
+
151
+ threshold = values[left]
152
+ rows, cols = np.where(pos_d <= threshold)
153
+ graph = csr_array(
154
+ (
155
+ np.ones(len(rows), dtype=np.int8),
156
+ (rows, cols),
157
+ ),
158
+ shape=pos_d.shape,
159
+ )
160
+ matching = maximum_bipartite_matching(graph, perm_type="column")
161
+ pos_max_diffs = pos_d[np.arange(n), matching].tolist()
162
+ if verbose:
163
+ print(f" Matching: {round((time.time() - t_start_m) * 1000, 2)} ms")
164
+ if max(pos_max_diffs) > pos_tol:
165
+ return False
166
+ else:
167
+ t_start_m = time.time()
168
+ rows, cols = np.where(pos_d <= pos_tol)
169
+ graph = csr_array(
170
+ (
171
+ np.ones(len(rows), dtype=np.int8),
172
+ (rows, cols),
173
+ ),
174
+ shape=pos_d.shape,
175
+ )
176
+ matching = maximum_bipartite_matching(graph, perm_type="column")
177
+ if verbose:
178
+ print(f" Matching: {round((time.time() - t_start_m) * 1000, 2)} ms")
179
+ if not np.all(matching >= 0):
180
+ return False
181
+ return True