vitrum 1.0.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.
- vitrum-1.0.0/LICENSE +21 -0
- vitrum-1.0.0/MANIFEST.in +1 -0
- vitrum-1.0.0/PKG-INFO +101 -0
- vitrum-1.0.0/README.md +60 -0
- vitrum-1.0.0/pyproject.toml +57 -0
- vitrum-1.0.0/setup.cfg +4 -0
- vitrum-1.0.0/src/vitrum/__init__.py +15 -0
- vitrum-1.0.0/src/vitrum/batch_active/__init__.py +0 -0
- vitrum-1.0.0/src/vitrum/batch_active/database.py +72 -0
- vitrum-1.0.0/src/vitrum/batch_active/flows.py +118 -0
- vitrum-1.0.0/src/vitrum/batch_active/get_structures.py +160 -0
- vitrum-1.0.0/src/vitrum/batch_active/input_writer.py +166 -0
- vitrum-1.0.0/src/vitrum/batch_active/learning.py +339 -0
- vitrum-1.0.0/src/vitrum/batch_active/structure_gen.py +96 -0
- vitrum-1.0.0/src/vitrum/batch_active/workflow.py +147 -0
- vitrum-1.0.0/src/vitrum/comparison.py +39 -0
- vitrum-1.0.0/src/vitrum/coordination.py +148 -0
- vitrum-1.0.0/src/vitrum/diffusion.py +122 -0
- vitrum-1.0.0/src/vitrum/geometry.py +107 -0
- vitrum-1.0.0/src/vitrum/glass_atoms.py +291 -0
- vitrum-1.0.0/src/vitrum/io_helpers.py +46 -0
- vitrum-1.0.0/src/vitrum/mlip_functions.py +103 -0
- vitrum-1.0.0/src/vitrum/packing.py +153 -0
- vitrum-1.0.0/src/vitrum/persistent_homology.py +201 -0
- vitrum-1.0.0/src/vitrum/rings.py +273 -0
- vitrum-1.0.0/src/vitrum/scattering.py +462 -0
- vitrum-1.0.0/src/vitrum/scattering_lengths.csv +84 -0
- vitrum-1.0.0/src/vitrum/structure_gen.py +193 -0
- vitrum-1.0.0/src/vitrum/structure_validation.py +124 -0
- vitrum-1.0.0/src/vitrum/trajectory.py +55 -0
- vitrum-1.0.0/src/vitrum/volume_estimation.py +110 -0
- vitrum-1.0.0/src/vitrum/x_ray_scattering_factor_coefficients.csv +99 -0
- vitrum-1.0.0/src/vitrum.egg-info/PKG-INFO +101 -0
- vitrum-1.0.0/src/vitrum.egg-info/SOURCES.txt +35 -0
- vitrum-1.0.0/src/vitrum.egg-info/dependency_links.txt +1 -0
- vitrum-1.0.0/src/vitrum.egg-info/requires.txt +21 -0
- vitrum-1.0.0/src/vitrum.egg-info/top_level.txt +1 -0
vitrum-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 R-Chr
|
|
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.
|
vitrum-1.0.0/MANIFEST.in
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include src/vitrum *.csv
|
vitrum-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vitrum
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: vitrum is a package for generating input data and analyzing simulation data of glass structures
|
|
5
|
+
Author-email: Rasmus Christensen <rasmus.christensen.a1@tohoku.ac.jp>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/R-Chr/vitrum
|
|
8
|
+
Project-URL: Repository, https://github.com/R-Chr/vitrum
|
|
9
|
+
Project-URL: Documentation, https://vitrum.readthedocs.io/en/latest/
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: ase
|
|
24
|
+
Requires-Dist: pandas
|
|
25
|
+
Requires-Dist: scikit-learn
|
|
26
|
+
Requires-Dist: scipy
|
|
27
|
+
Requires-Dist: pymatgen
|
|
28
|
+
Requires-Dist: ruamel-yaml==0.17.9
|
|
29
|
+
Requires-Dist: numba
|
|
30
|
+
Requires-Dist: matplotlib
|
|
31
|
+
Provides-Extra: workflows
|
|
32
|
+
Requires-Dist: fireworks; extra == "workflows"
|
|
33
|
+
Requires-Dist: jobflow; extra == "workflows"
|
|
34
|
+
Requires-Dist: atomate2; extra == "workflows"
|
|
35
|
+
Provides-Extra: volume-estimation
|
|
36
|
+
Requires-Dist: atomate2; extra == "volume-estimation"
|
|
37
|
+
Requires-Dist: mp_api; extra == "volume-estimation"
|
|
38
|
+
Provides-Extra: persistent-homology
|
|
39
|
+
Requires-Dist: dionysus; extra == "persistent-homology"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# ⚗️ vitrum
|
|
43
|
+
|
|
44
|
+
**vitrum** is a Python package designed for the generation, analysis, and simulation of disordered and glassy atomic structures. It provides a comprehensive suite of tools for structural characterization, diffusion analysis, and tools for machine learning-driven potential development.
|
|
45
|
+
|
|
46
|
+
## 🚧 Active development
|
|
47
|
+
vitrum is under active development. As of 1.0, the public API follows [semantic versioning](https://semver.org/) — breaking changes will be reflected in a major version bump and noted in the [changelog](CHANGELOG.md).
|
|
48
|
+
|
|
49
|
+
## 📖 Documentation
|
|
50
|
+
Please see the `docs` folder for detailed documentation or check the [online documentation](https://vitrum.readthedocs.io/en/latest/).
|
|
51
|
+
|
|
52
|
+
## 📦 Installation
|
|
53
|
+
|
|
54
|
+
To install `vitrum`, you can clone the repository and install it in editable mode:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git clone https://github.com/R-Chr/vitrum.git
|
|
58
|
+
cd vitrum
|
|
59
|
+
pip install -e .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
To install dependencies for simulation workflows (atomate2, fireworks, jobflow):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install -e .[workflows]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 🚀 Examples
|
|
69
|
+
See the [`examples`](examples/) folder for runnable Jupyter notebooks demonstrating scattering/RDF analysis, Qn speciation, and random structure generation, among others.
|
|
70
|
+
|
|
71
|
+
## 🎯 Scope and Functionality
|
|
72
|
+
|
|
73
|
+
`vitrum` offers:
|
|
74
|
+
|
|
75
|
+
### 1. Structural Characterization
|
|
76
|
+
* **Scattering Functions**: Calculate partial and total Radial Distribution Functions (RDF) and Structure Factors ($S(q)$) for both Neutron and X-ray scattering (`vitrum.scattering`).
|
|
77
|
+
* **Ring Analysis**: Analyze ring size distributions and statistics in network glasses (`vitrum.rings`).
|
|
78
|
+
* **Topological Analysis**: Compute persistent homology to identify medium-range order and topological features (`vitrum.persistent_homology`).
|
|
79
|
+
* **Coordination & Angles**: Analyze bond angle distributions and coordination environments (`vitrum.coordination`).
|
|
80
|
+
|
|
81
|
+
### 2. Dynamics & Diffusion
|
|
82
|
+
* **Diffusion Analysis**: Calculate Mean Squared Displacement (MSD), diffusion coefficients, and Van Hove correlation functions (`vitrum.diffusion`).
|
|
83
|
+
|
|
84
|
+
### 3. Machine Learning & Workflows
|
|
85
|
+
* **BALACE Framework**: A Batch Active Learning framework for Atomistic Simulations (`vitrum.batch_active`) (requires `workflows` dependencies).
|
|
86
|
+
* Automated workflow for training Machine Learning Interatomic Potentials (MLIPs) based on ACE .
|
|
87
|
+
* Integration with VASP and LAMMPS for data generation and active learning loops.
|
|
88
|
+
* Job management via Fireworks and Jobflow.
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## 👥 Author
|
|
92
|
+
Rasmus Christensen (rasmusc@bio.aau.dk)
|
|
93
|
+
|
|
94
|
+
## ⭐ Acknowledgements
|
|
95
|
+
`vitrum` relies on several powerful open-source packages:
|
|
96
|
+
* [ASE](https://wiki.fysik.dtu.dk/ase/)
|
|
97
|
+
* [Pymatgen](https://pymatgen.org/)
|
|
98
|
+
* [NumPy](https://numpy.org/) / [SciPy](https://scipy.org/) / [pandas](https://pandas.pydata.org/)
|
|
99
|
+
* [scikit-learn](https://scikit-learn.org/)
|
|
100
|
+
* [Dionysus](https://mrzv.org/software/dionysus2/) / [DioDe](https://github.com/mrzv/diode)
|
|
101
|
+
* [Atomate2](https://github.com/materialsproject/atomate2) / [Jobflow](https://materialsproject.github.io/jobflow/) / [Fireworks](https://materialsproject.github.io/fireworks/)
|
vitrum-1.0.0/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# ⚗️ vitrum
|
|
2
|
+
|
|
3
|
+
**vitrum** is a Python package designed for the generation, analysis, and simulation of disordered and glassy atomic structures. It provides a comprehensive suite of tools for structural characterization, diffusion analysis, and tools for machine learning-driven potential development.
|
|
4
|
+
|
|
5
|
+
## 🚧 Active development
|
|
6
|
+
vitrum is under active development. As of 1.0, the public API follows [semantic versioning](https://semver.org/) — breaking changes will be reflected in a major version bump and noted in the [changelog](CHANGELOG.md).
|
|
7
|
+
|
|
8
|
+
## 📖 Documentation
|
|
9
|
+
Please see the `docs` folder for detailed documentation or check the [online documentation](https://vitrum.readthedocs.io/en/latest/).
|
|
10
|
+
|
|
11
|
+
## 📦 Installation
|
|
12
|
+
|
|
13
|
+
To install `vitrum`, you can clone the repository and install it in editable mode:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/R-Chr/vitrum.git
|
|
17
|
+
cd vitrum
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
To install dependencies for simulation workflows (atomate2, fireworks, jobflow):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install -e .[workflows]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 🚀 Examples
|
|
28
|
+
See the [`examples`](examples/) folder for runnable Jupyter notebooks demonstrating scattering/RDF analysis, Qn speciation, and random structure generation, among others.
|
|
29
|
+
|
|
30
|
+
## 🎯 Scope and Functionality
|
|
31
|
+
|
|
32
|
+
`vitrum` offers:
|
|
33
|
+
|
|
34
|
+
### 1. Structural Characterization
|
|
35
|
+
* **Scattering Functions**: Calculate partial and total Radial Distribution Functions (RDF) and Structure Factors ($S(q)$) for both Neutron and X-ray scattering (`vitrum.scattering`).
|
|
36
|
+
* **Ring Analysis**: Analyze ring size distributions and statistics in network glasses (`vitrum.rings`).
|
|
37
|
+
* **Topological Analysis**: Compute persistent homology to identify medium-range order and topological features (`vitrum.persistent_homology`).
|
|
38
|
+
* **Coordination & Angles**: Analyze bond angle distributions and coordination environments (`vitrum.coordination`).
|
|
39
|
+
|
|
40
|
+
### 2. Dynamics & Diffusion
|
|
41
|
+
* **Diffusion Analysis**: Calculate Mean Squared Displacement (MSD), diffusion coefficients, and Van Hove correlation functions (`vitrum.diffusion`).
|
|
42
|
+
|
|
43
|
+
### 3. Machine Learning & Workflows
|
|
44
|
+
* **BALACE Framework**: A Batch Active Learning framework for Atomistic Simulations (`vitrum.batch_active`) (requires `workflows` dependencies).
|
|
45
|
+
* Automated workflow for training Machine Learning Interatomic Potentials (MLIPs) based on ACE .
|
|
46
|
+
* Integration with VASP and LAMMPS for data generation and active learning loops.
|
|
47
|
+
* Job management via Fireworks and Jobflow.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## 👥 Author
|
|
51
|
+
Rasmus Christensen (rasmusc@bio.aau.dk)
|
|
52
|
+
|
|
53
|
+
## ⭐ Acknowledgements
|
|
54
|
+
`vitrum` relies on several powerful open-source packages:
|
|
55
|
+
* [ASE](https://wiki.fysik.dtu.dk/ase/)
|
|
56
|
+
* [Pymatgen](https://pymatgen.org/)
|
|
57
|
+
* [NumPy](https://numpy.org/) / [SciPy](https://scipy.org/) / [pandas](https://pandas.pydata.org/)
|
|
58
|
+
* [scikit-learn](https://scikit-learn.org/)
|
|
59
|
+
* [Dionysus](https://mrzv.org/software/dionysus2/) / [DioDe](https://github.com/mrzv/diode)
|
|
60
|
+
* [Atomate2](https://github.com/materialsproject/atomate2) / [Jobflow](https://materialsproject.github.io/jobflow/) / [Fireworks](https://materialsproject.github.io/fireworks/)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vitrum"
|
|
7
|
+
description = "vitrum is a package for generating input data and analyzing simulation data of glass structures"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = { text = "MIT" }
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Rasmus Christensen", email = "rasmus.christensen.a1@tohoku.ac.jp" },
|
|
12
|
+
]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dynamic = ["version"]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy",
|
|
17
|
+
"ase",
|
|
18
|
+
"pandas",
|
|
19
|
+
"scikit-learn",
|
|
20
|
+
"scipy",
|
|
21
|
+
"pymatgen",
|
|
22
|
+
"ruamel-yaml==0.17.9",
|
|
23
|
+
"numba",
|
|
24
|
+
"matplotlib",
|
|
25
|
+
]
|
|
26
|
+
classifiers = [
|
|
27
|
+
"Development Status :: 5 - Production/Stable",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3.10",
|
|
30
|
+
"Programming Language :: Python :: 3.11",
|
|
31
|
+
"Programming Language :: Python :: 3.12",
|
|
32
|
+
"Programming Language :: Python :: 3.13",
|
|
33
|
+
"License :: OSI Approved :: MIT License",
|
|
34
|
+
"Operating System :: OS Independent",
|
|
35
|
+
"Topic :: Scientific/Engineering :: Chemistry",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/R-Chr/vitrum"
|
|
40
|
+
Repository = "https://github.com/R-Chr/vitrum"
|
|
41
|
+
Documentation = "https://vitrum.readthedocs.io/en/latest/"
|
|
42
|
+
|
|
43
|
+
[project.optional-dependencies]
|
|
44
|
+
workflows = ["fireworks", "jobflow", "atomate2"]
|
|
45
|
+
volume_estimation = ["atomate2", "mp_api"]
|
|
46
|
+
# diode (used by persistent_homology.py) is not a normal PyPI package;
|
|
47
|
+
# see docs/vitrum/install.md for its manual install instructions.
|
|
48
|
+
persistent_homology = ["dionysus"]
|
|
49
|
+
|
|
50
|
+
[tool.setuptools.dynamic]
|
|
51
|
+
version = { attr = "vitrum.__version__" }
|
|
52
|
+
|
|
53
|
+
[tool.setuptools.packages.find]
|
|
54
|
+
where = ["src"]
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.package-data]
|
|
57
|
+
vitrum = ["scattering_lengths.csv", "x_ray_scattering_factor_coefficients.csv"]
|
vitrum-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from vitrum.glass_atoms import GlassAtoms
|
|
2
|
+
from vitrum.coordination import Coordination
|
|
3
|
+
from vitrum.diffusion import Diffusion
|
|
4
|
+
from vitrum.rings import RingAnalysis
|
|
5
|
+
from vitrum.scattering import Scattering
|
|
6
|
+
|
|
7
|
+
__version__ = "1.0.0"
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"GlassAtoms",
|
|
11
|
+
"Coordination",
|
|
12
|
+
"Diffusion",
|
|
13
|
+
"RingAnalysis",
|
|
14
|
+
"Scattering",
|
|
15
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from sklearn.model_selection import train_test_split
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def update_ace_database(
|
|
7
|
+
wd: str,
|
|
8
|
+
atoms: list,
|
|
9
|
+
iteration: int,
|
|
10
|
+
force_threshold: int = 100,
|
|
11
|
+
train_test_method: str = "composition",
|
|
12
|
+
train_test_fraction: float = 0.2,
|
|
13
|
+
database_paths=None,
|
|
14
|
+
metadata=None,
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
Update the ACE database with new structures.
|
|
18
|
+
|
|
19
|
+
Parameters:
|
|
20
|
+
wd (str): Working directory.
|
|
21
|
+
atoms (list): List of ASE atoms objects.
|
|
22
|
+
iteration (int): Current iteration number.
|
|
23
|
+
force_threshold (int): Force threshold for filtering structures.
|
|
24
|
+
train_test_method (str): Method for splitting data into train and test sets.
|
|
25
|
+
train_test_split (float): Fraction of data to be used for testing.
|
|
26
|
+
database_paths (dict): Paths to the existing train and test databases.
|
|
27
|
+
metadata (str): Metadata for the structures.
|
|
28
|
+
"""
|
|
29
|
+
energy = [i.get_total_energy() for i in atoms]
|
|
30
|
+
force = [i.get_forces().tolist() for i in atoms]
|
|
31
|
+
stress = [i.get_stress() for i in atoms]
|
|
32
|
+
data = {"energy": energy, "forces": force, "stress": stress, "ase_atoms": atoms, "iteration": iteration}
|
|
33
|
+
if metadata:
|
|
34
|
+
data["sample_type"] = metadata
|
|
35
|
+
# create a DataFrame
|
|
36
|
+
df = pd.DataFrame(data)
|
|
37
|
+
df["stress"] = df["stress"].apply(np.array)
|
|
38
|
+
print(f"Iteration {iteration} has {len(df)} structures")
|
|
39
|
+
df = df[~df["forces"].apply(lambda x: np.max(x) > force_threshold)]
|
|
40
|
+
df = df[~df["forces"].apply(lambda x: np.min(x) < -force_threshold)]
|
|
41
|
+
print(f"{len(df)} structures remain after force threshold filter")
|
|
42
|
+
|
|
43
|
+
if train_test_method == "random":
|
|
44
|
+
# Randomly split the data into train and test sets
|
|
45
|
+
df_new = train_test_split(df, test_size=train_test_fraction, random_state=42)
|
|
46
|
+
|
|
47
|
+
elif train_test_method == "composition":
|
|
48
|
+
# determine train/test split
|
|
49
|
+
composition_set = set()
|
|
50
|
+
for atoms in df["ase_atoms"]:
|
|
51
|
+
composition_set.add(atoms.get_chemical_formula())
|
|
52
|
+
|
|
53
|
+
# Choose a random sample of the unique compositions
|
|
54
|
+
composition_list = list(composition_set)
|
|
55
|
+
np.random.shuffle(composition_list)
|
|
56
|
+
test_comps = composition_list[: int(len(composition_list) * train_test_fraction)]
|
|
57
|
+
# Create a mask to filter the DataFrame
|
|
58
|
+
mask = df["ase_atoms"].apply(lambda atoms: atoms.get_chemical_formula() in test_comps)
|
|
59
|
+
# Filter the DataFrame
|
|
60
|
+
df_new = [df[~mask], df[mask]]
|
|
61
|
+
|
|
62
|
+
print(f"{len(df_new[0])} structures added to train set and {len(df_new[1])} structures added to test set")
|
|
63
|
+
|
|
64
|
+
if database_paths:
|
|
65
|
+
for ind, file in enumerate([database_paths["train"], database_paths["test"]]):
|
|
66
|
+
df_old = pd.read_pickle(file, compression="gzip")
|
|
67
|
+
df_concat = pd.concat([df_old] + [df_new[ind]])
|
|
68
|
+
df_concat.to_pickle(file, compression="gzip", protocol=4)
|
|
69
|
+
else:
|
|
70
|
+
df_new[0].to_pickle(f"{wd}/train_data.pckl.gzip", compression="gzip", protocol=4)
|
|
71
|
+
df_new[1].to_pickle(f"{wd}/test_data.pckl.gzip", compression="gzip", protocol=4)
|
|
72
|
+
return {"train": f"{wd}/train_data.pckl.gzip", "test": f"{wd}/test_data.pckl.gzip"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
try:
|
|
2
|
+
from atomate2.vasp.jobs.core import StaticMaker
|
|
3
|
+
from atomate2.vasp.jobs.md import MDMaker
|
|
4
|
+
from atomate2.vasp.sets.core import StaticSetGenerator
|
|
5
|
+
from atomate2.vasp.sets.core import MDSetGenerator
|
|
6
|
+
except ImportError:
|
|
7
|
+
raise ImportError("atomate2 is required for flows. Please install vitrum[batch_active].")
|
|
8
|
+
from pymatgen.io.vasp import Kpoints
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def static_flow(structure, name=False, incar_settings={}, kpoint=False, potcar_functional="PBE_54"):
|
|
12
|
+
if not name:
|
|
13
|
+
name = structure.reduced_formula
|
|
14
|
+
num_atoms = len(structure)
|
|
15
|
+
incar_set = {
|
|
16
|
+
"EDIFF": (10**-5) * num_atoms,
|
|
17
|
+
"ENAUG": None,
|
|
18
|
+
"EDIFFG": None,
|
|
19
|
+
"ALGO": "Normal",
|
|
20
|
+
"ENCUT": 520,
|
|
21
|
+
"ISMEAR": 0,
|
|
22
|
+
"ISPIN": 1, # Do not consider magnetism in AIMD simulations
|
|
23
|
+
"LREAL": "Auto",
|
|
24
|
+
"LAECHG": False,
|
|
25
|
+
"LASPH": True,
|
|
26
|
+
"LCHARG": False,
|
|
27
|
+
"GGA": None, # Just let VASP decide based on POTCAR - the default PE
|
|
28
|
+
"LPLANE": False, # LPLANE is recommended to be False on Cray machines
|
|
29
|
+
"LDAUPRINT": 0,
|
|
30
|
+
"ISIF": 2,
|
|
31
|
+
"SIGMA": 0.05,
|
|
32
|
+
"LVTOT": None,
|
|
33
|
+
"LMIXTAU": None,
|
|
34
|
+
"NELM": 200,
|
|
35
|
+
"PREC": "Normal",
|
|
36
|
+
"NCORE": 16,
|
|
37
|
+
"NSIM": 32,
|
|
38
|
+
}
|
|
39
|
+
incar_set.update(incar_settings)
|
|
40
|
+
if not kpoint:
|
|
41
|
+
kpoint = Kpoints() # Gamma centered, 1x1x1 KPOINTS with no shift
|
|
42
|
+
|
|
43
|
+
run_vasp_kwargs = {"job_type": "direct"}
|
|
44
|
+
|
|
45
|
+
static_maker = StaticMaker(
|
|
46
|
+
name=name,
|
|
47
|
+
input_set_generator=StaticSetGenerator(
|
|
48
|
+
user_incar_settings=incar_set, user_kpoints_settings=kpoint, user_potcar_functional=potcar_functional
|
|
49
|
+
),
|
|
50
|
+
run_vasp_kwargs=run_vasp_kwargs,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return static_maker.make(structure)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def md_flow(
|
|
57
|
+
structure,
|
|
58
|
+
temperature=5000,
|
|
59
|
+
steps=100,
|
|
60
|
+
name=False,
|
|
61
|
+
timestep=1,
|
|
62
|
+
incar_settings={},
|
|
63
|
+
kpoint=False,
|
|
64
|
+
potcar_functional="PBE_54",
|
|
65
|
+
):
|
|
66
|
+
if not name:
|
|
67
|
+
name = structure.reduced_formula
|
|
68
|
+
num_atoms = len(structure)
|
|
69
|
+
|
|
70
|
+
incar_set = {
|
|
71
|
+
"EDIFF": (10**-5) * num_atoms,
|
|
72
|
+
"ENAUG": None,
|
|
73
|
+
"EDIFFG": None,
|
|
74
|
+
"ALGO": "Normal",
|
|
75
|
+
"ENCUT": 520,
|
|
76
|
+
"ISMEAR": 0,
|
|
77
|
+
"ISPIN": 1, # Do not consider magnetism in AIMD simulations
|
|
78
|
+
"LREAL": "Auto",
|
|
79
|
+
"LAECHG": False,
|
|
80
|
+
"LASPH": True,
|
|
81
|
+
"LCHARG": False,
|
|
82
|
+
"GGA": None, # Just let VASP decide based on POTCAR - the default PE
|
|
83
|
+
"LPLANE": False, # LPLANE is recommended to be False on Cray machines
|
|
84
|
+
"LDAUPRINT": 0,
|
|
85
|
+
"ISIF": 2,
|
|
86
|
+
"SIGMA": 0.05,
|
|
87
|
+
"LVTOT": None,
|
|
88
|
+
"LMIXTAU": None,
|
|
89
|
+
"NELM": 200,
|
|
90
|
+
"PREC": "Normal",
|
|
91
|
+
"NCORE": 16,
|
|
92
|
+
"NSIM": 32,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
incar_set.update(incar_settings)
|
|
96
|
+
|
|
97
|
+
if not kpoint:
|
|
98
|
+
kpoint = Kpoints() # Gamma centered, 1x1x1 KPOINTS with no shift
|
|
99
|
+
|
|
100
|
+
run_vasp_kwargs = {"job_type": "direct"}
|
|
101
|
+
|
|
102
|
+
aimd_maker = MDMaker(
|
|
103
|
+
name=name,
|
|
104
|
+
input_set_generator=MDSetGenerator(
|
|
105
|
+
ensemble="nvt",
|
|
106
|
+
start_temp=temperature,
|
|
107
|
+
end_temp=temperature,
|
|
108
|
+
nsteps=steps,
|
|
109
|
+
time_step=timestep,
|
|
110
|
+
# adapted from MPMorph settings
|
|
111
|
+
user_incar_settings=incar_set,
|
|
112
|
+
user_kpoints_settings=kpoint,
|
|
113
|
+
user_potcar_functional=potcar_functional,
|
|
114
|
+
),
|
|
115
|
+
run_vasp_kwargs=run_vasp_kwargs,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return aimd_maker.make(structure)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import subprocess
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from ase.io import read
|
|
8
|
+
from pymatgen.io.ase import AseAtomsAdaptor
|
|
9
|
+
|
|
10
|
+
from vitrum.io_helpers import correct_atom_types, get_LAMMPS_dump_timesteps
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_wflow_id_from_run_uuid(lp, run_uuid):
|
|
14
|
+
wf_ids = [
|
|
15
|
+
i
|
|
16
|
+
for i in lp.get_wf_ids()
|
|
17
|
+
if lp.workflows.find_one({"nodes": i}, projection=["metadata"]).get("metadata", {}).get("uuid") == run_uuid
|
|
18
|
+
]
|
|
19
|
+
return wf_ids
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_atoms_from_wfs(lp, run_uuids, high_temp_params, sampling=":", state=None):
|
|
23
|
+
"""
|
|
24
|
+
Reads all atoms from a workflow given by uuid and returns them.
|
|
25
|
+
|
|
26
|
+
Parameters:
|
|
27
|
+
run_uuids : list
|
|
28
|
+
list of uuids of the workflows to read from.
|
|
29
|
+
sampling : str or list or int, optional
|
|
30
|
+
If sampling is a string, it is interpreted as a slice string for numpy.
|
|
31
|
+
If it is an integer, it is interpreted as the number of samples to take.
|
|
32
|
+
If it is a list, it is interpreted as a list of indices to sample.
|
|
33
|
+
Defaults to ":".
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
atoms: list
|
|
37
|
+
A list of ase atoms objects.
|
|
38
|
+
"""
|
|
39
|
+
wf_ids = sum([get_wflow_id_from_run_uuid(lp, id) for id in run_uuids], [])
|
|
40
|
+
atoms = []
|
|
41
|
+
metadata = []
|
|
42
|
+
|
|
43
|
+
if state == "train_ace_high_temp":
|
|
44
|
+
sampling = high_temp_params["sampling"]
|
|
45
|
+
else:
|
|
46
|
+
sampling = sampling
|
|
47
|
+
|
|
48
|
+
for wf_id in wf_ids:
|
|
49
|
+
wf = lp.get_wf_by_fw_id(wf_id)
|
|
50
|
+
launch_dirs = [fw.launches[0].launch_dir if fw.launches else None for fw in wf.fws]
|
|
51
|
+
for dirs, fw in zip(launch_dirs, wf.fws):
|
|
52
|
+
if fw.state == "COMPLETED":
|
|
53
|
+
atoms_fw = read(f"{dirs}/OUTCAR.gz", format="vasp-out", index=":")
|
|
54
|
+
num_samples = len(atoms_fw)
|
|
55
|
+
if sampling == ":":
|
|
56
|
+
atoms = atoms + atoms_fw
|
|
57
|
+
num_samples = len(atoms_fw)
|
|
58
|
+
elif isinstance(sampling, int):
|
|
59
|
+
sample_index = np.linspace(0, num_samples - 1, sampling, dtype=int)
|
|
60
|
+
atoms = atoms + [atoms_fw[i] for i in sample_index]
|
|
61
|
+
num_samples = len(sample_index)
|
|
62
|
+
elif isinstance(sampling, list):
|
|
63
|
+
atoms = atoms + [atoms_fw[i] for i in sampling]
|
|
64
|
+
num_samples = len(sampling)
|
|
65
|
+
metadata = metadata + [fw.spec["sample_type"]] * num_samples
|
|
66
|
+
|
|
67
|
+
return atoms, metadata
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_structures_from_lammps(
|
|
71
|
+
folder,
|
|
72
|
+
potential_folder,
|
|
73
|
+
atom_types,
|
|
74
|
+
potential,
|
|
75
|
+
pace_select=True,
|
|
76
|
+
force_glass_structures=True,
|
|
77
|
+
use_spaced_timesteps=False,
|
|
78
|
+
max_gamma_structures=500,
|
|
79
|
+
):
|
|
80
|
+
select_files = []
|
|
81
|
+
forced_files = []
|
|
82
|
+
|
|
83
|
+
folder_path = Path(folder)
|
|
84
|
+
for dirpath in folder_path.rglob("*"): # Recursively iterate over all directories/files
|
|
85
|
+
if dirpath.is_dir(): # Ensure it's a directory
|
|
86
|
+
for file in ["glass.dump", "gamma.dump"]:
|
|
87
|
+
file_path = dirpath / file # Use pathlib's `/` operator to join paths
|
|
88
|
+
if file_path.exists(): # Check if file exists
|
|
89
|
+
file_path_str = str(file_path) # .replace(")", r"\)").replace("(", r"\(")
|
|
90
|
+
|
|
91
|
+
if pace_select:
|
|
92
|
+
if force_glass_structures:
|
|
93
|
+
if file == "glass.dump":
|
|
94
|
+
forced_files.append(file_path_str)
|
|
95
|
+
else:
|
|
96
|
+
select_files.append(file_path_str)
|
|
97
|
+
else:
|
|
98
|
+
select_files.append(file_path_str)
|
|
99
|
+
else:
|
|
100
|
+
forced_files.append(file_path_str)
|
|
101
|
+
|
|
102
|
+
gamma_file = f"{folder}/gamma_structures.dat"
|
|
103
|
+
with open(gamma_file, "wb") as wfd:
|
|
104
|
+
for f in select_files:
|
|
105
|
+
with open(f, "rb") as fd:
|
|
106
|
+
shutil.copyfileobj(fd, wfd)
|
|
107
|
+
|
|
108
|
+
atoms_selected = []
|
|
109
|
+
atoms_forced = []
|
|
110
|
+
|
|
111
|
+
if pace_select is True:
|
|
112
|
+
print("Running PACE select")
|
|
113
|
+
atoms_selected += select_structures(
|
|
114
|
+
potential_folder, atom_types, gamma_file, potential, num_select_structures=max_gamma_structures
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
for file_path in forced_files:
|
|
118
|
+
atoms = read(file_path, format="lammps-dump-text", index=":")
|
|
119
|
+
if len(atoms) == 0:
|
|
120
|
+
continue
|
|
121
|
+
symbol_change_map = {i + 1: x for i, x in enumerate(atom_types)}
|
|
122
|
+
atoms = correct_atom_types(atoms, symbol_change_map)
|
|
123
|
+
|
|
124
|
+
if use_spaced_timesteps is True:
|
|
125
|
+
timesteps = get_LAMMPS_dump_timesteps(file_path)
|
|
126
|
+
spaced_timesteps = [0]
|
|
127
|
+
for ind, time in enumerate(timesteps):
|
|
128
|
+
if time > timesteps[spaced_timesteps[-1]] + 100:
|
|
129
|
+
spaced_timesteps.append(ind)
|
|
130
|
+
atoms_forced += [atoms[t] for t in spaced_timesteps]
|
|
131
|
+
else:
|
|
132
|
+
atoms_forced += atoms
|
|
133
|
+
|
|
134
|
+
print(f"Included {len(atoms_selected)} selected structures and {len(atoms_forced)} forced structures.")
|
|
135
|
+
metadata = ["gamma"] * len(atoms_selected) + ["manual"] * len(atoms_forced)
|
|
136
|
+
structures = [AseAtomsAdaptor().get_structure(atom) for atom in atoms_selected] + [
|
|
137
|
+
AseAtomsAdaptor().get_structure(atom) for atom in atoms_forced
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
return structures, metadata
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def select_structures(folder, atom_types, gamma_file, potential, num_select_structures=500):
|
|
144
|
+
atom_string = " ".join([str(atom) for atom in atom_types])
|
|
145
|
+
if potential == "pace":
|
|
146
|
+
subprocess.run(
|
|
147
|
+
f"pace_select -p {folder}/output_potential.yaml -a "
|
|
148
|
+
f'{folder}/output_potential.asi -e "{atom_string}"'
|
|
149
|
+
f" -m {num_select_structures} {gamma_file}",
|
|
150
|
+
shell=True,
|
|
151
|
+
)
|
|
152
|
+
elif potential == "grace":
|
|
153
|
+
subprocess.run(
|
|
154
|
+
f"pace_select -p {folder}/FS_model.yaml"
|
|
155
|
+
f' -a {folder}/FS_model.asi -e "{atom_string}"'
|
|
156
|
+
f" -m {num_select_structures} {gamma_file}",
|
|
157
|
+
shell=True,
|
|
158
|
+
)
|
|
159
|
+
atoms = pd.read_pickle("selected.pkl.gz", compression="gzip")
|
|
160
|
+
return [structure for structure in atoms["ase_atoms"]]
|