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.
Files changed (37) hide show
  1. vitrum-1.0.0/LICENSE +21 -0
  2. vitrum-1.0.0/MANIFEST.in +1 -0
  3. vitrum-1.0.0/PKG-INFO +101 -0
  4. vitrum-1.0.0/README.md +60 -0
  5. vitrum-1.0.0/pyproject.toml +57 -0
  6. vitrum-1.0.0/setup.cfg +4 -0
  7. vitrum-1.0.0/src/vitrum/__init__.py +15 -0
  8. vitrum-1.0.0/src/vitrum/batch_active/__init__.py +0 -0
  9. vitrum-1.0.0/src/vitrum/batch_active/database.py +72 -0
  10. vitrum-1.0.0/src/vitrum/batch_active/flows.py +118 -0
  11. vitrum-1.0.0/src/vitrum/batch_active/get_structures.py +160 -0
  12. vitrum-1.0.0/src/vitrum/batch_active/input_writer.py +166 -0
  13. vitrum-1.0.0/src/vitrum/batch_active/learning.py +339 -0
  14. vitrum-1.0.0/src/vitrum/batch_active/structure_gen.py +96 -0
  15. vitrum-1.0.0/src/vitrum/batch_active/workflow.py +147 -0
  16. vitrum-1.0.0/src/vitrum/comparison.py +39 -0
  17. vitrum-1.0.0/src/vitrum/coordination.py +148 -0
  18. vitrum-1.0.0/src/vitrum/diffusion.py +122 -0
  19. vitrum-1.0.0/src/vitrum/geometry.py +107 -0
  20. vitrum-1.0.0/src/vitrum/glass_atoms.py +291 -0
  21. vitrum-1.0.0/src/vitrum/io_helpers.py +46 -0
  22. vitrum-1.0.0/src/vitrum/mlip_functions.py +103 -0
  23. vitrum-1.0.0/src/vitrum/packing.py +153 -0
  24. vitrum-1.0.0/src/vitrum/persistent_homology.py +201 -0
  25. vitrum-1.0.0/src/vitrum/rings.py +273 -0
  26. vitrum-1.0.0/src/vitrum/scattering.py +462 -0
  27. vitrum-1.0.0/src/vitrum/scattering_lengths.csv +84 -0
  28. vitrum-1.0.0/src/vitrum/structure_gen.py +193 -0
  29. vitrum-1.0.0/src/vitrum/structure_validation.py +124 -0
  30. vitrum-1.0.0/src/vitrum/trajectory.py +55 -0
  31. vitrum-1.0.0/src/vitrum/volume_estimation.py +110 -0
  32. vitrum-1.0.0/src/vitrum/x_ray_scattering_factor_coefficients.csv +99 -0
  33. vitrum-1.0.0/src/vitrum.egg-info/PKG-INFO +101 -0
  34. vitrum-1.0.0/src/vitrum.egg-info/SOURCES.txt +35 -0
  35. vitrum-1.0.0/src/vitrum.egg-info/dependency_links.txt +1 -0
  36. vitrum-1.0.0/src/vitrum.egg-info/requires.txt +21 -0
  37. 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.
@@ -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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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"]]