rsspolymlp 0.4.2__tar.gz → 0.4.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.4.2/src/rsspolymlp.egg-info → rsspolymlp-0.4.4}/PKG-INFO +19 -20
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/README.md +18 -19
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/pyproject.toml +1 -1
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/rss_summarize.py +31 -14
- rsspolymlp-0.4.4/src/rsspolymlp/analysis/struct_matcher/assignment_algo.py +181 -0
- rsspolymlp-0.4.4/src/rsspolymlp/analysis/struct_matcher/gen_struct_rep.py +371 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/struct_matcher/identify_uniqstr.py +88 -39
- rsspolymlp-0.4.4/src/rsspolymlp/analysis/struct_matcher/redrep_lattice.py +144 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/struct_matcher/redrep_position.py +174 -115
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/struct_matcher/struct_match.py +25 -10
- rsspolymlp-0.4.4/src/rsspolymlp/analysis/struct_matcher/test/gen_lattice.py +53 -0
- rsspolymlp-0.4.4/src/rsspolymlp/analysis/struct_matcher/test/time_measure.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/cli_rsspolymlp.py +8 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/cli_rsspolymlp_utils.py +35 -29
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/rsspolymlp.py +3 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/rsspolymlp_utils.py +70 -40
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/common/atomic_energy.py +2 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/common/property.py +1 -1
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/dataset/split_dataset.py +4 -3
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/rss/eliminate_duplicates.py +5 -4
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/matplot_util/make_plot.py +14 -3
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/spglib_utils.py +5 -1
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4/src/rsspolymlp.egg-info}/PKG-INFO +19 -20
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp.egg-info/SOURCES.txt +2 -0
- rsspolymlp-0.4.2/src/rsspolymlp/analysis/struct_matcher/assignment_algo.py +0 -112
- rsspolymlp-0.4.2/src/rsspolymlp/analysis/struct_matcher/gen_struct_rep.py +0 -325
- rsspolymlp-0.4.2/src/rsspolymlp/analysis/struct_matcher/redrep_lattice.py +0 -541
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/LICENSE +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/setup.cfg +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/eos.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/ghost_minima.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/phase_analysis.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/struct_matcher/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/analysis/struct_matcher/chiral_spg.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/cli_rsspolymlp_devkit.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/cli_rsspolymlp_plot.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/rsspolymlp_devkit.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/api/rsspolymlp_plot.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/common/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/common/composition.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/common/convert_dict.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/common/interface_vasp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/dataset/compress_vasprun.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/dataset/gen_mlp_dataset.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/estimate_cost.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/model_selection/binary/gen_single_model.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/model_selection/elemental/gen_hybrid_model.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/model_selection/elemental/gen_single_model.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/model_selection/n_feature.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/model_selection/pypolymlp_gridsearch.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/model_selection/reduce_grid.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/pareto_opt_mlp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/mlp_dev/polymlp_dev.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/rss/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/rss/load_logfile.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/rss/optimization_mlp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/rss/random_struct.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/lammps_utils.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/matplot_util/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/matplot_util/custom_plt.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/matplot_util/examples/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/matplot_util/examples/example.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/matplot_util/examples/template.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/opt_sscha/opt_geometry_sscha.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/opt_sscha/opt_position_sscha.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/opt_sscha/run_opt_sscha.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/opt_sscha/sscha_property.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/pymatgen_utils.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/vasp_util/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/vasp_util/api.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/vasp_util/gen_incar.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/vasp_util/gen_script.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp/utils/vasp_util/write_poscar.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp.egg-info/dependency_links.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp.egg-info/entry_points.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp.egg-info/requires.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.4}/src/rsspolymlp.egg-info/top_level.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.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.4.
|
|
3
|
+
Version: 0.4.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>
|
|
@@ -31,25 +31,9 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# Framework for random structure search using polynomial machine learning potentials
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- Initial structure generation
|
|
38
|
-
- Global RSS with polynomial MLPs
|
|
39
|
-
- Unique structure identification and RSS result summarization
|
|
40
|
-
- Phase stability analysis
|
|
41
|
-
- [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
|
|
42
|
-
- MLP dataset generation
|
|
43
|
-
- DFT dataset division
|
|
44
|
-
- Polynomial MLP development
|
|
45
|
-
- Pareto-optimal MLP selection
|
|
46
|
-
- Python API
|
|
47
|
-
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
48
|
-
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
49
|
-
- Single-point calculation
|
|
50
|
-
- Local geometry optimization
|
|
51
|
-
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
52
|
-
|
|
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).
|
|
53
37
|
|
|
54
38
|
## Installation
|
|
55
39
|
|
|
@@ -88,6 +72,21 @@ pip install rsspolymlp
|
|
|
88
72
|
```
|
|
89
73
|
|
|
90
74
|
|
|
75
|
+
## How to use rsspolymlp
|
|
76
|
+
|
|
77
|
+
- [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
|
|
78
|
+
- Initial structure generation
|
|
79
|
+
- Global RSS with polynomial MLPs
|
|
80
|
+
- Unique structure identification and RSS result summarization
|
|
81
|
+
- Phase stability analysis
|
|
82
|
+
- Python API
|
|
83
|
+
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
84
|
+
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
85
|
+
- Single-point calculation
|
|
86
|
+
- Local geometry optimization
|
|
87
|
+
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
88
|
+
|
|
89
|
+
|
|
91
90
|
## Citation of rsspolymlp
|
|
92
91
|
|
|
93
92
|
If you use `rsspolymlp` in your study, please cite the following articles.
|
|
@@ -1,24 +1,8 @@
|
|
|
1
1
|
# Framework for random structure search using polynomial machine learning potentials
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
- Initial structure generation
|
|
7
|
-
- Global RSS with polynomial MLPs
|
|
8
|
-
- Unique structure identification and RSS result summarization
|
|
9
|
-
- Phase stability analysis
|
|
10
|
-
- [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
|
|
11
|
-
- MLP dataset generation
|
|
12
|
-
- DFT dataset division
|
|
13
|
-
- Polynomial MLP development
|
|
14
|
-
- Pareto-optimal MLP selection
|
|
15
|
-
- Python API
|
|
16
|
-
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
17
|
-
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
18
|
-
- Single-point calculation
|
|
19
|
-
- Local geometry optimization
|
|
20
|
-
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
21
|
-
|
|
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).
|
|
22
6
|
|
|
23
7
|
## Installation
|
|
24
8
|
|
|
@@ -57,6 +41,21 @@ pip install rsspolymlp
|
|
|
57
41
|
```
|
|
58
42
|
|
|
59
43
|
|
|
44
|
+
## How to use rsspolymlp
|
|
45
|
+
|
|
46
|
+
- [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
|
|
47
|
+
- Initial structure generation
|
|
48
|
+
- Global RSS with polynomial MLPs
|
|
49
|
+
- Unique structure identification and RSS result summarization
|
|
50
|
+
- Phase stability analysis
|
|
51
|
+
- Python API
|
|
52
|
+
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
53
|
+
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
54
|
+
- Single-point calculation
|
|
55
|
+
- Local geometry optimization
|
|
56
|
+
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
57
|
+
|
|
58
|
+
|
|
60
59
|
## Citation of rsspolymlp
|
|
61
60
|
|
|
62
61
|
If you use `rsspolymlp` in your study, please cite the following articles.
|
|
@@ -6,15 +6,15 @@ import xml.etree.ElementTree as ET
|
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from time import time
|
|
9
|
-
from typing import Optional
|
|
9
|
+
from typing import Literal, Optional
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
|
|
13
13
|
from pypolymlp.utils.vasp_utils import write_poscar_file
|
|
14
14
|
from rsspolymlp.analysis.ghost_minima import detect_ghost_minima
|
|
15
15
|
from rsspolymlp.analysis.struct_matcher.gen_struct_rep import (
|
|
16
|
+
StructRepGenerator,
|
|
16
17
|
StructReps,
|
|
17
|
-
generate_struct_reps_parallel,
|
|
18
18
|
)
|
|
19
19
|
from rsspolymlp.analysis.struct_matcher.identify_uniqstr import (
|
|
20
20
|
UniqueStructIdentifier,
|
|
@@ -38,6 +38,7 @@ class RSSResultSummarizer:
|
|
|
38
38
|
element_order: list = None,
|
|
39
39
|
num_process: int = -1,
|
|
40
40
|
backend: str = "loky",
|
|
41
|
+
assign_method: Literal["redrep", "greedy", "HK", "pymatgen"] = "redrep",
|
|
41
42
|
primitive_symprecs: list[float] = [1e-5, 1e-4, 1e-3, 1e-2],
|
|
42
43
|
output_poscar: bool = False,
|
|
43
44
|
thresholds: list[float] = None,
|
|
@@ -51,6 +52,7 @@ class RSSResultSummarizer:
|
|
|
51
52
|
self.element_order = element_order
|
|
52
53
|
self.num_process = num_process
|
|
53
54
|
self.backend = backend
|
|
55
|
+
self.assign_method = assign_method
|
|
54
56
|
self.primitive_symprecs = primitive_symprecs
|
|
55
57
|
self.output_poscar = output_poscar
|
|
56
58
|
self.thresholds = thresholds
|
|
@@ -58,7 +60,7 @@ class RSSResultSummarizer:
|
|
|
58
60
|
self.update_parent = update_parent
|
|
59
61
|
|
|
60
62
|
self.pressure = None
|
|
61
|
-
self.analyzer =
|
|
63
|
+
self.analyzer = None
|
|
62
64
|
|
|
63
65
|
def run_summarize(self):
|
|
64
66
|
os.makedirs("json", exist_ok=True)
|
|
@@ -90,10 +92,13 @@ class RSSResultSummarizer:
|
|
|
90
92
|
axis_tol = 0.1
|
|
91
93
|
pos_tol = 0.1
|
|
92
94
|
|
|
95
|
+
self.analyzer = UniqueStructIdentifier(
|
|
96
|
+
axis_tol=axis_tol,
|
|
97
|
+
pos_tol=pos_tol,
|
|
98
|
+
assign_method=self.assign_method,
|
|
99
|
+
)
|
|
93
100
|
for comp_tag, res_paths in json_paths_c.items():
|
|
94
101
|
print(f"Composition {comp_tag}: summarizing...")
|
|
95
|
-
self.analyzer = UniqueStructIdentifier()
|
|
96
|
-
|
|
97
102
|
time_start = time()
|
|
98
103
|
|
|
99
104
|
processed_paths = set()
|
|
@@ -119,6 +124,7 @@ class RSSResultSummarizer:
|
|
|
119
124
|
rss_results_c[comp_tag][res_path],
|
|
120
125
|
axis_tol=axis_tol,
|
|
121
126
|
pos_tol=pos_tol,
|
|
127
|
+
assign_method=self.assign_method,
|
|
122
128
|
pre_analyzer=self.analyzer,
|
|
123
129
|
)
|
|
124
130
|
|
|
@@ -127,11 +133,11 @@ class RSSResultSummarizer:
|
|
|
127
133
|
unique_structs = self.analyzer.unique_str
|
|
128
134
|
unique_str_prop = self.analyzer.unique_str_prop
|
|
129
135
|
enthalpies = np.array([s["energy"] for s in unique_str_prop])
|
|
130
|
-
distances = np.array([s["least_distance"] for s in unique_str_prop])
|
|
131
136
|
sort_idx = np.argsort(enthalpies)
|
|
132
137
|
|
|
133
138
|
if not self.parse_vasp:
|
|
134
139
|
os.makedirs("ghost_minima", exist_ok=True)
|
|
140
|
+
distances = np.array([s["least_distance"] for s in unique_str_prop])
|
|
135
141
|
is_ghost_minima, ghost_minima_info = detect_ghost_minima(
|
|
136
142
|
enthalpies[sort_idx], distances[sort_idx]
|
|
137
143
|
)
|
|
@@ -196,8 +202,6 @@ class RSSResultSummarizer:
|
|
|
196
202
|
|
|
197
203
|
for comp_tag, res_paths in json_paths_c.items():
|
|
198
204
|
print(f"Composition {comp_tag}: summarizing...")
|
|
199
|
-
self.analyzer = UniqueStructIdentifier()
|
|
200
|
-
|
|
201
205
|
if not self.parse_vasp:
|
|
202
206
|
axis_tol = 0.03
|
|
203
207
|
pos_tol = 0.03
|
|
@@ -210,10 +214,11 @@ class RSSResultSummarizer:
|
|
|
210
214
|
print(f" - Processing result file (parent): {res_path}")
|
|
211
215
|
self.analyzer = identify_unique_structure(
|
|
212
216
|
rss_results_c[comp_tag][res_path],
|
|
213
|
-
|
|
217
|
+
normalize_axis=True,
|
|
214
218
|
keep_unique=True,
|
|
215
219
|
axis_tol=axis_tol,
|
|
216
220
|
pos_tol=pos_tol,
|
|
221
|
+
assign_method=self.assign_method,
|
|
217
222
|
pre_analyzer=self.analyzer,
|
|
218
223
|
)
|
|
219
224
|
time_finish = time() - time_start
|
|
@@ -225,7 +230,7 @@ class RSSResultSummarizer:
|
|
|
225
230
|
sort_idx = np.argsort(enthalpies)
|
|
226
231
|
sort_idx = sorted(
|
|
227
232
|
sort_idx,
|
|
228
|
-
key=lambda i: len(
|
|
233
|
+
key=lambda i: len(unique_structs[i]),
|
|
229
234
|
reverse=True,
|
|
230
235
|
)
|
|
231
236
|
unique_str_sorted = [unique_structs[i] for i in sort_idx]
|
|
@@ -264,11 +269,13 @@ class RSSResultSummarizer:
|
|
|
264
269
|
r["dupstr_paths"] = set(r["dupstr_paths"])
|
|
265
270
|
|
|
266
271
|
print(" - Converting reduced crystal structure representation...")
|
|
267
|
-
|
|
272
|
+
generator = StructRepGenerator(
|
|
273
|
+
primitive_symprecs=self.primitive_symprecs,
|
|
274
|
+
)
|
|
275
|
+
struct_reps_list = generator.generate_struct_reps_parallel(
|
|
268
276
|
rss_results,
|
|
269
277
|
num_process=self.num_process,
|
|
270
278
|
backend=self.backend,
|
|
271
|
-
symprec_set1=self.symprec_set,
|
|
272
279
|
)
|
|
273
280
|
if self.update_parent:
|
|
274
281
|
print(" - Eliminating duplicate structures...")
|
|
@@ -589,6 +596,14 @@ def log_all_unique_structures(
|
|
|
589
596
|
with open(file_name, "a") as f:
|
|
590
597
|
print("unique_structures:", file=f)
|
|
591
598
|
for idx1, _str in enumerate(unique_structs):
|
|
599
|
+
if unique_str_prop is not None:
|
|
600
|
+
sorted_data = sorted(
|
|
601
|
+
zip(unique_structs[idx1], unique_str_prop[idx1]),
|
|
602
|
+
key=lambda x: x[1]["energy"],
|
|
603
|
+
)
|
|
604
|
+
unique_structs[idx1], unique_str_prop[idx1] = map(
|
|
605
|
+
list, zip(*sorted_data)
|
|
606
|
+
)
|
|
592
607
|
print(f" - struct_No: {idx1 + 1}", file=f)
|
|
593
608
|
print(" structures:", file=f)
|
|
594
609
|
for idx2, _str in enumerate(unique_structs[idx1]):
|
|
@@ -600,7 +615,9 @@ def log_all_unique_structures(
|
|
|
600
615
|
objprop = PropUtil(polymlp_st.axis.T, polymlp_st.positions.T)
|
|
601
616
|
print(f" - sub_struct_No: '{idx1 + 1}_{idx2 + 1}'", file=f)
|
|
602
617
|
print(f" struct_path: {_str.struct_path}", file=f)
|
|
603
|
-
print(
|
|
618
|
+
print(
|
|
619
|
+
f" pressure: {unique_str_prop[idx1][idx2]['pressure']}", file=f
|
|
620
|
+
)
|
|
604
621
|
print(f" enthalpy: {e}", file=f)
|
|
605
622
|
print(f" axis: {objprop.abc}", file=f)
|
|
606
623
|
print(
|
|
@@ -630,7 +647,7 @@ def log_all_unique_structures(
|
|
|
630
647
|
if unique_other_prop is not None:
|
|
631
648
|
print(" properties:", unique_other_prop[idx1], file=f)
|
|
632
649
|
|
|
633
|
-
comp_res = compute_composition(unique_structs[0][0].
|
|
650
|
+
comp_res = compute_composition(unique_structs[0][0].original_polymlp_st.elements)
|
|
634
651
|
|
|
635
652
|
rss_result_all = {
|
|
636
653
|
"elements": comp_res.unique_elements.tolist(),
|
|
@@ -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
|