rsspolymlp 0.3.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.
- rsspolymlp-0.3.0/LICENSE +21 -0
- rsspolymlp-0.3.0/PKG-INFO +106 -0
- rsspolymlp-0.3.0/README.md +75 -0
- rsspolymlp-0.3.0/pyproject.toml +51 -0
- rsspolymlp-0.3.0/setup.cfg +4 -0
- rsspolymlp-0.3.0/src/rsspolymlp/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/eos.py +238 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/ghost_minima.py +247 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/load_plot_data.py +36 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/phase_analysis.py +340 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/rss_summarize.py +458 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/chiral_spg.py +85 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/deprecated/invert_and_swap.py +106 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/deprecated/irrep_position.py +379 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/deprecated/niggli.py +10 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/deprecated/struct_match.py +264 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/deprecated/utils.py +83 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/invert_and_swap.py +457 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/reduced_position.py +433 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/struct_matcher/struct_match.py +294 -0
- rsspolymlp-0.3.0/src/rsspolymlp/analysis/unique_struct.py +478 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/cli_rsspolymlp.py +338 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/cli_rsspolymlp_devkit.py +321 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/cli_rsspolymlp_plot.py +127 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/cli_rsspolymlp_utils.py +58 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/rsspolymlp.py +250 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/rsspolymlp_devkit.py +237 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/rsspolymlp_plot.py +363 -0
- rsspolymlp-0.3.0/src/rsspolymlp/api/rsspolymlp_utils.py +46 -0
- rsspolymlp-0.3.0/src/rsspolymlp/common/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/common/atomic_energy.py +38 -0
- rsspolymlp-0.3.0/src/rsspolymlp/common/composition.py +65 -0
- rsspolymlp-0.3.0/src/rsspolymlp/common/convert_dict.py +60 -0
- rsspolymlp-0.3.0/src/rsspolymlp/common/property.py +116 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/dataset/compress_vasprun.py +77 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/dataset/divide_dataset.py +130 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/dataset/gen_mlp_dataset.py +77 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/estimate_cost.py +57 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/model_selection/gen_hybrid_model.py +139 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/model_selection/gen_single_model.py +74 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/model_selection/n_feature.py +57 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/model_selection/pypolymlp_gridsearch.py +385 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/model_selection/reduce_grid.py +25 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/pareto_opt_mlp.py +214 -0
- rsspolymlp-0.3.0/src/rsspolymlp/mlp_dev/polymlp_dev.py +125 -0
- rsspolymlp-0.3.0/src/rsspolymlp/rss/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/rss/eliminate_duplicates.py +345 -0
- rsspolymlp-0.3.0/src/rsspolymlp/rss/load_logfile.py +176 -0
- rsspolymlp-0.3.0/src/rsspolymlp/rss/optimization_mlp.py +325 -0
- rsspolymlp-0.3.0/src/rsspolymlp/rss/random_struct.py +135 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/lammps_utils.py +240 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/matplot_util/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/matplot_util/custom_plt.py +103 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/matplot_util/examples/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/matplot_util/examples/example.py +122 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/matplot_util/examples/template.py +72 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/matplot_util/make_plot.py +349 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/pymatgen_utils.py +165 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/spglib_utils.py +232 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/vasp_util/__init__.py +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/vasp_util/api.py +154 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/vasp_util/gen_incar.py +164 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/vasp_util/gen_script.py +208 -0
- rsspolymlp-0.3.0/src/rsspolymlp/utils/vasp_util/write_poscar.py +38 -0
- rsspolymlp-0.3.0/src/rsspolymlp.egg-info/PKG-INFO +106 -0
- rsspolymlp-0.3.0/src/rsspolymlp.egg-info/SOURCES.txt +72 -0
- rsspolymlp-0.3.0/src/rsspolymlp.egg-info/dependency_links.txt +1 -0
- rsspolymlp-0.3.0/src/rsspolymlp.egg-info/entry_points.txt +5 -0
- rsspolymlp-0.3.0/src/rsspolymlp.egg-info/requires.txt +21 -0
- rsspolymlp-0.3.0/src/rsspolymlp.egg-info/top_level.txt +1 -0
rsspolymlp-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Hayato Wakai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rsspolymlp
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A framework for random structure search using polynomial MLPs
|
|
5
|
+
Author-email: Hayato Wakai <wakai@cms.mtl.kyoto-u.ac.jp>
|
|
6
|
+
Maintainer-email: Hayato Wakai <wakai@cms.mtl.kyoto-u.ac.jp>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: homepage, https://github.com/hytwakai/rsspolymlp
|
|
9
|
+
Project-URL: repository, https://github.com/hytwakai/rsspolymlp
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: numpy
|
|
14
|
+
Requires-Dist: scipy
|
|
15
|
+
Requires-Dist: scikit-learn
|
|
16
|
+
Requires-Dist: joblib
|
|
17
|
+
Requires-Dist: pypolymlp
|
|
18
|
+
Requires-Dist: spglib
|
|
19
|
+
Requires-Dist: symfc
|
|
20
|
+
Provides-Extra: pymatgen
|
|
21
|
+
Requires-Dist: pymatgen; extra == "pymatgen"
|
|
22
|
+
Provides-Extra: matplotlib
|
|
23
|
+
Requires-Dist: matplotlib; extra == "matplotlib"
|
|
24
|
+
Provides-Extra: seaborn
|
|
25
|
+
Requires-Dist: seaborn; extra == "seaborn"
|
|
26
|
+
Provides-Extra: tools
|
|
27
|
+
Requires-Dist: pymatgen; extra == "tools"
|
|
28
|
+
Requires-Dist: matplotlib; extra == "tools"
|
|
29
|
+
Requires-Dist: seaborn; extra == "tools"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# A framework for random structure search (RSS) using polynomial MLPs
|
|
33
|
+
|
|
34
|
+
## Citation of rsspolymlp
|
|
35
|
+
|
|
36
|
+
If you use `rsspolymlp` in your study, please cite the following articles.
|
|
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/)
|
|
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}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
### Required libraries and python modules
|
|
55
|
+
|
|
56
|
+
- python >= 3.10
|
|
57
|
+
- scikit-learn
|
|
58
|
+
- joblib
|
|
59
|
+
- pypolymlp
|
|
60
|
+
- spglib
|
|
61
|
+
- symfc
|
|
62
|
+
|
|
63
|
+
[Optional]
|
|
64
|
+
- matplotlib (if plotting RSS results)
|
|
65
|
+
- seaborn (if plotting RSS results)
|
|
66
|
+
|
|
67
|
+
### How to install
|
|
68
|
+
- Install from conda-forge
|
|
69
|
+
|
|
70
|
+
| Name | Downloads | Version | Platforms |
|
|
71
|
+
| --- | --- | --- | --- |
|
|
72
|
+
| [](https://anaconda.org/conda-forge/rsspolymlp) | [](https://anaconda.org/conda-forge/rsspolymlp) | [](https://anaconda.org/conda-forge/rsspolymlp) | [](https://anaconda.org/conda-forge/rsspolymlp) |
|
|
73
|
+
|
|
74
|
+
```shell
|
|
75
|
+
conda create -n rsspolymlp
|
|
76
|
+
conda activate rsspolymlp
|
|
77
|
+
conda install -c conda-forge rsspolymlp
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- Install from PyPI
|
|
81
|
+
```shell
|
|
82
|
+
conda create -n rsspolymlp
|
|
83
|
+
conda activate rsspolymlp
|
|
84
|
+
conda install -c conda-forge scikit-learn joblib pypolymlp spglib symfc
|
|
85
|
+
pip install rsspolymlp
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## How to use rsspolymlp
|
|
89
|
+
|
|
90
|
+
- [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
|
|
91
|
+
- Initial structure generation
|
|
92
|
+
- Global RSS with polynomial MLPs
|
|
93
|
+
- Unique structure identification and RSS result summarization
|
|
94
|
+
- Ghost minimum structure elimination
|
|
95
|
+
- Phase stability analysis
|
|
96
|
+
- [Development kit for polynomial MLPs](docs/rsspolymlp_devkit.md)
|
|
97
|
+
- MLP dataset generation
|
|
98
|
+
- DFT dataset division
|
|
99
|
+
- Polynomial MLP development
|
|
100
|
+
- Pareto-optimal MLP selection
|
|
101
|
+
- Python API
|
|
102
|
+
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
103
|
+
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
104
|
+
- Single-point calculation
|
|
105
|
+
- Local geometry optimization
|
|
106
|
+
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# A framework for random structure search (RSS) using polynomial MLPs
|
|
2
|
+
|
|
3
|
+
## Citation of rsspolymlp
|
|
4
|
+
|
|
5
|
+
If you use `rsspolymlp` in your study, please cite the following articles.
|
|
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/)
|
|
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}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### Required libraries and python modules
|
|
24
|
+
|
|
25
|
+
- python >= 3.10
|
|
26
|
+
- scikit-learn
|
|
27
|
+
- joblib
|
|
28
|
+
- pypolymlp
|
|
29
|
+
- spglib
|
|
30
|
+
- symfc
|
|
31
|
+
|
|
32
|
+
[Optional]
|
|
33
|
+
- matplotlib (if plotting RSS results)
|
|
34
|
+
- seaborn (if plotting RSS results)
|
|
35
|
+
|
|
36
|
+
### How to install
|
|
37
|
+
- Install from conda-forge
|
|
38
|
+
|
|
39
|
+
| Name | Downloads | Version | Platforms |
|
|
40
|
+
| --- | --- | --- | --- |
|
|
41
|
+
| [](https://anaconda.org/conda-forge/rsspolymlp) | [](https://anaconda.org/conda-forge/rsspolymlp) | [](https://anaconda.org/conda-forge/rsspolymlp) | [](https://anaconda.org/conda-forge/rsspolymlp) |
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
conda create -n rsspolymlp
|
|
45
|
+
conda activate rsspolymlp
|
|
46
|
+
conda install -c conda-forge rsspolymlp
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- Install from PyPI
|
|
50
|
+
```shell
|
|
51
|
+
conda create -n rsspolymlp
|
|
52
|
+
conda activate rsspolymlp
|
|
53
|
+
conda install -c conda-forge scikit-learn joblib pypolymlp spglib symfc
|
|
54
|
+
pip install rsspolymlp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## How to use rsspolymlp
|
|
58
|
+
|
|
59
|
+
- [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
|
|
60
|
+
- Initial structure generation
|
|
61
|
+
- Global RSS with polynomial MLPs
|
|
62
|
+
- Unique structure identification and RSS result summarization
|
|
63
|
+
- Ghost minimum structure elimination
|
|
64
|
+
- Phase stability analysis
|
|
65
|
+
- [Development kit for polynomial MLPs](docs/rsspolymlp_devkit.md)
|
|
66
|
+
- MLP dataset generation
|
|
67
|
+
- DFT dataset division
|
|
68
|
+
- Polynomial MLP development
|
|
69
|
+
- Pareto-optimal MLP selection
|
|
70
|
+
- Python API
|
|
71
|
+
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
72
|
+
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
73
|
+
- Single-point calculation
|
|
74
|
+
- Local geometry optimization
|
|
75
|
+
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rsspolymlp"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "A framework for random structure search using polynomial MLPs"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "Hayato Wakai", email = "wakai@cms.mtl.kyoto-u.ac.jp"},
|
|
12
|
+
]
|
|
13
|
+
maintainers = [
|
|
14
|
+
{name = "Hayato Wakai", email = "wakai@cms.mtl.kyoto-u.ac.jp"},
|
|
15
|
+
]
|
|
16
|
+
readme = {file = "README.md", content-type = "text/markdown"}
|
|
17
|
+
requires-python = ">=3.10"
|
|
18
|
+
dependencies = [
|
|
19
|
+
"numpy",
|
|
20
|
+
"scipy",
|
|
21
|
+
"scikit-learn",
|
|
22
|
+
"joblib",
|
|
23
|
+
"pypolymlp",
|
|
24
|
+
"spglib",
|
|
25
|
+
"symfc",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
pymatgen = ["pymatgen"]
|
|
30
|
+
matplotlib = ["matplotlib"]
|
|
31
|
+
seaborn = ["seaborn"]
|
|
32
|
+
tools = ["pymatgen", "matplotlib", "seaborn"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
homepage = "https://github.com/hytwakai/rsspolymlp"
|
|
36
|
+
repository = "https://github.com/hytwakai/rsspolymlp"
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
rsspolymlp = "rsspolymlp.api.cli_rsspolymlp:run"
|
|
40
|
+
rsspolymlp-devkit = "rsspolymlp.api.cli_rsspolymlp_devkit:run"
|
|
41
|
+
rsspolymlp-plot = "rsspolymlp.api.cli_rsspolymlp_plot:run"
|
|
42
|
+
rsspolymlp-utils = "rsspolymlp.api.cli_rsspolymlp_utils:run"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools]
|
|
45
|
+
package-dir = {"" = "src"}
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
where = ["src"]
|
|
49
|
+
|
|
50
|
+
[tool.setuptools.package-data]
|
|
51
|
+
rsspolymlp = ["py.typed"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# src/rss_polymlp/__init__.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# src/rss_polymlp/analysis/__init__.py
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import scipy
|
|
6
|
+
from scipy.interpolate import interp1d
|
|
7
|
+
from scipy.optimize import leastsq
|
|
8
|
+
|
|
9
|
+
from pypolymlp.core.units import EVtoGPa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def vinet(v, *p):
|
|
13
|
+
"""Return Vinet EOS.
|
|
14
|
+
p[0] = E_0
|
|
15
|
+
p[1] = B_0
|
|
16
|
+
p[2] = B'_0
|
|
17
|
+
p[3] = V_0
|
|
18
|
+
"""
|
|
19
|
+
x = (v / p[3]) ** (1.0 / 3)
|
|
20
|
+
xi = 3.0 / 2 * (p[2] - 1)
|
|
21
|
+
return p[0] + (
|
|
22
|
+
9 * p[1] * p[3] / (xi**2) * (1 + (xi * (1 - x) - 1) * np.exp(xi * (1 - x)))
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EOSFit:
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
energies: np.ndarray,
|
|
31
|
+
volumes: np.ndarray,
|
|
32
|
+
init_parameter: list[float] = None,
|
|
33
|
+
pressure: float = None,
|
|
34
|
+
volume_range: list[float] = None,
|
|
35
|
+
):
|
|
36
|
+
"""
|
|
37
|
+
Fit an equation of state (EOS) to energy-volume data and
|
|
38
|
+
enable Gibbs energy interpolation at arbitrary pressures.
|
|
39
|
+
"""
|
|
40
|
+
sort_idx = np.argsort(-np.array(volumes))
|
|
41
|
+
self._energies = np.array(energies)[sort_idx]
|
|
42
|
+
self._volumes = np.array(volumes)[sort_idx]
|
|
43
|
+
|
|
44
|
+
self._eos = vinet
|
|
45
|
+
self.parameters = None
|
|
46
|
+
self._volume_range = (
|
|
47
|
+
volume_range
|
|
48
|
+
if volume_range is not None
|
|
49
|
+
else [np.min(self._volumes) * 0.99, np.max(self._volumes) * 1.01]
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if init_parameter is None:
|
|
53
|
+
# Default initial parameters: [E0, B0, B0', V0]
|
|
54
|
+
self._init_parameter = [
|
|
55
|
+
energies[len(energies) // 2],
|
|
56
|
+
0.6,
|
|
57
|
+
4.0,
|
|
58
|
+
volumes[len(volumes) // 2],
|
|
59
|
+
]
|
|
60
|
+
else:
|
|
61
|
+
self._init_parameter = init_parameter
|
|
62
|
+
|
|
63
|
+
if pressure is not None:
|
|
64
|
+
self._energies += pressure * self._volumes / EVtoGPa
|
|
65
|
+
|
|
66
|
+
self.fit()
|
|
67
|
+
self.interpolate_gibbs_from_pressure(self._volume_range)
|
|
68
|
+
|
|
69
|
+
def fit(self):
|
|
70
|
+
"""Fit EOS parameters to energy-volume data using least squares."""
|
|
71
|
+
warnings.filterwarnings("error")
|
|
72
|
+
|
|
73
|
+
def residuals(p, eos, v, e):
|
|
74
|
+
return eos(v, *p) - e
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
result = leastsq(
|
|
78
|
+
residuals,
|
|
79
|
+
self._init_parameter,
|
|
80
|
+
args=(self._eos, self._volumes, self._energies),
|
|
81
|
+
full_output=1,
|
|
82
|
+
)
|
|
83
|
+
except RuntimeError:
|
|
84
|
+
logging.exception("Fitting to EOS failed.")
|
|
85
|
+
raise
|
|
86
|
+
except (RuntimeWarning, scipy.optimize.optimize.OptimizeWarning):
|
|
87
|
+
logging.exception("Difficulty in fitting to EOS.")
|
|
88
|
+
raise
|
|
89
|
+
else:
|
|
90
|
+
self.parameters = result[0]
|
|
91
|
+
|
|
92
|
+
print(f"RMSE of EOS fit (energy): {self.rmse*1000:.6f} meV")
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def rmse(self) -> float:
|
|
96
|
+
"""Return RMSE between fitted EOS and input energy data."""
|
|
97
|
+
if self.parameters is None:
|
|
98
|
+
raise ValueError("Fit must be performed before calculating RMSE.")
|
|
99
|
+
predicted = self._eos(self._volumes, *self.parameters)
|
|
100
|
+
error = predicted - self._energies
|
|
101
|
+
return np.sqrt(np.mean(error**2))
|
|
102
|
+
|
|
103
|
+
def interpolate_gibbs_from_pressure(
|
|
104
|
+
self, volume_range: list[float], n_grid: int = None
|
|
105
|
+
):
|
|
106
|
+
"""
|
|
107
|
+
Precompute interpolation function for G(P) using volume range.
|
|
108
|
+
Stores:
|
|
109
|
+
self.g_interp: interpolator
|
|
110
|
+
self.pressure_lb / pressure_ub: pressure bounds
|
|
111
|
+
"""
|
|
112
|
+
if n_grid is None:
|
|
113
|
+
# Pressure grid is set with ~0.01 GPa resolution.
|
|
114
|
+
pressures, _ = self._get_pressure_and_gibbs_from_volumes(
|
|
115
|
+
[min(volume_range), max(volume_range)]
|
|
116
|
+
)
|
|
117
|
+
pressure_range = abs(pressures[1] - pressures[0])
|
|
118
|
+
n_grid = int(round(pressure_range * 100))
|
|
119
|
+
|
|
120
|
+
volumes = np.linspace(min(volume_range), max(volume_range), n_grid)
|
|
121
|
+
pressures, gibbs_energies = self._get_pressure_and_gibbs_from_volumes(volumes)
|
|
122
|
+
|
|
123
|
+
sort_idx = np.argsort(pressures)
|
|
124
|
+
sorted_pressures = pressures[sort_idx]
|
|
125
|
+
sorted_gibbs = gibbs_energies[sort_idx]
|
|
126
|
+
|
|
127
|
+
self.pressure_lb = sorted_pressures[0]
|
|
128
|
+
self.pressure_ub = sorted_pressures[-1]
|
|
129
|
+
|
|
130
|
+
self.g_interp = interp1d(
|
|
131
|
+
sorted_pressures,
|
|
132
|
+
sorted_gibbs,
|
|
133
|
+
kind="linear",
|
|
134
|
+
bounds_error=True,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def _get_pressure_and_gibbs_from_volumes(
|
|
138
|
+
self, volumes: np.ndarray, eps: float = 1e-4
|
|
139
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
140
|
+
"""Calculate pressure and Gibbs energy for each volume using numerical derivatives."""
|
|
141
|
+
gibbs_list = []
|
|
142
|
+
pressure_list = []
|
|
143
|
+
energies = self.get_energy(volumes)
|
|
144
|
+
|
|
145
|
+
for vol, e in zip(volumes, energies):
|
|
146
|
+
e_forward, e_backward = self.get_energy([vol + eps, vol - eps])
|
|
147
|
+
dE_dV = (e_forward - e_backward) / (2 * eps)
|
|
148
|
+
pressure_eVA3 = -dE_dV
|
|
149
|
+
gibbs = e + pressure_eVA3 * vol
|
|
150
|
+
pressure_GPa = pressure_eVA3 * EVtoGPa
|
|
151
|
+
gibbs_list.append(gibbs)
|
|
152
|
+
pressure_list.append(pressure_GPa)
|
|
153
|
+
|
|
154
|
+
return np.array(pressure_list), np.array(gibbs_list)
|
|
155
|
+
|
|
156
|
+
def get_energy(self, volumes: np.ndarray) -> np.ndarray:
|
|
157
|
+
"""Return predicted energy values for given volumes using fitted EOS."""
|
|
158
|
+
return vinet(np.array(volumes), *self.parameters)
|
|
159
|
+
|
|
160
|
+
def get_gibbs(self, pressures: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
|
|
161
|
+
"""Return interpolated Gibbs free energy values at given pressures in GPa."""
|
|
162
|
+
pressures = np.asarray(pressures)
|
|
163
|
+
in_range_mask = (self.pressure_lb <= pressures) & (
|
|
164
|
+
pressures <= self.pressure_ub
|
|
165
|
+
)
|
|
166
|
+
if not np.any(in_range_mask):
|
|
167
|
+
raise ValueError(
|
|
168
|
+
"All provided pressures are outside the interpolation range "
|
|
169
|
+
f"[{self.pressure_lb:.3f}, {self.pressure_ub:.3f}] GPa."
|
|
170
|
+
)
|
|
171
|
+
valid_pressures = pressures[in_range_mask]
|
|
172
|
+
return valid_pressures, self.g_interp(valid_pressures)
|
|
173
|
+
|
|
174
|
+
def rmse_from_enthalpy_data(
|
|
175
|
+
self,
|
|
176
|
+
pressures: np.ndarray,
|
|
177
|
+
reference_gibbs: np.ndarray,
|
|
178
|
+
) -> float:
|
|
179
|
+
"""
|
|
180
|
+
Compute RMSE between interpolated Gibbs free energies and reference values."""
|
|
181
|
+
_, predicted_gibbs = self.get_gibbs(pressures)
|
|
182
|
+
error = np.array(predicted_gibbs) - np.array(reference_gibbs)
|
|
183
|
+
return np.sqrt(np.mean(error**2))
|
|
184
|
+
|
|
185
|
+
def eos_plot(self, fig_name="EV_plot.png"):
|
|
186
|
+
from rsspolymlp.utils.matplot_util.custom_plt import CustomPlt
|
|
187
|
+
from rsspolymlp.utils.matplot_util.make_plot import MakePlot
|
|
188
|
+
|
|
189
|
+
custom_template = CustomPlt(
|
|
190
|
+
label_size=8,
|
|
191
|
+
label_pad=3.0,
|
|
192
|
+
xtick_size=7,
|
|
193
|
+
ytick_size=7,
|
|
194
|
+
xtick_pad=3.0,
|
|
195
|
+
ytick_pad=3.0,
|
|
196
|
+
)
|
|
197
|
+
plt = custom_template.get_custom_plt()
|
|
198
|
+
plotter = MakePlot(
|
|
199
|
+
plt=plt,
|
|
200
|
+
column_size=0.85,
|
|
201
|
+
height_ratio=0.95,
|
|
202
|
+
)
|
|
203
|
+
plotter.initialize_ax()
|
|
204
|
+
plotter.set_visuality(n_color=4, n_line=4, n_marker=0, color_type="grad")
|
|
205
|
+
|
|
206
|
+
volumes = np.linspace(min(self._volume_range), max(self._volume_range), 200)
|
|
207
|
+
energies = self.get_energy(volumes)
|
|
208
|
+
|
|
209
|
+
plotter.ax_plot(
|
|
210
|
+
volumes,
|
|
211
|
+
energies,
|
|
212
|
+
plot_type="closed",
|
|
213
|
+
label=None,
|
|
214
|
+
plot_size=0.0,
|
|
215
|
+
line_size=0.7,
|
|
216
|
+
zorder=1,
|
|
217
|
+
)
|
|
218
|
+
plotter.ax_scatter(
|
|
219
|
+
self._volumes,
|
|
220
|
+
self._energies,
|
|
221
|
+
plot_type="open",
|
|
222
|
+
label=None,
|
|
223
|
+
plot_size=0.7,
|
|
224
|
+
zorder=2,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
plotter.finalize_ax(
|
|
228
|
+
xlabel=r"Volume ($\rm{\AA}^3$/atom)",
|
|
229
|
+
ylabel="Energy (eV/atom)",
|
|
230
|
+
)
|
|
231
|
+
plt.tight_layout()
|
|
232
|
+
plt.savefig(
|
|
233
|
+
fig_name,
|
|
234
|
+
bbox_inches="tight",
|
|
235
|
+
pad_inches=0.01,
|
|
236
|
+
dpi=400,
|
|
237
|
+
)
|
|
238
|
+
plt.close()
|