gridmlip 0.1__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.
- gridmlip-0.1/LICENSE +20 -0
- gridmlip-0.1/MANIFEST.in +3 -0
- gridmlip-0.1/PKG-INFO +94 -0
- gridmlip-0.1/README.md +76 -0
- gridmlip-0.1/gridmlip/__init__.py +1 -0
- gridmlip-0.1/gridmlip/_neighborhood.py +34 -0
- gridmlip-0.1/gridmlip/_percolation_analysis.py +247 -0
- gridmlip-0.1/gridmlip/cli.py +1 -0
- gridmlip-0.1/gridmlip/core.py +274 -0
- gridmlip-0.1/gridmlip/utils.py +146 -0
- gridmlip-0.1/gridmlip.egg-info/PKG-INFO +94 -0
- gridmlip-0.1/gridmlip.egg-info/SOURCES.txt +18 -0
- gridmlip-0.1/gridmlip.egg-info/dependency_links.txt +1 -0
- gridmlip-0.1/gridmlip.egg-info/requires.txt +6 -0
- gridmlip-0.1/gridmlip.egg-info/top_level.txt +1 -0
- gridmlip-0.1/gridmlip.egg-info/zip-safe +1 -0
- gridmlip-0.1/pyproject.toml +3 -0
- gridmlip-0.1/setup.cfg +31 -0
- gridmlip-0.1/setup.py +35 -0
gridmlip-0.1/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
Copyright (c) 2025 Artem Dembitskiy
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
gridmlip-0.1/MANIFEST.in
ADDED
gridmlip-0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: gridmlip
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: Grid-based method for calculating the percolation barrier of mobile species using machine learning interatomic potentials
|
|
5
|
+
Home-page: https://github.com/dembart/gridmlip
|
|
6
|
+
Author: Artem Dembitskiy
|
|
7
|
+
Author-email: art.dembitskiy@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: MLIP,percolation barrier
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
|
|
17
|
+
## gridmlip
|
|
18
|
+
<p align="left">
|
|
19
|
+
<a href="https://github.com/dembart/gridmlip/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-darkred"></a>
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Contents
|
|
23
|
+
- [About](#about)
|
|
24
|
+
- [Installation](#installation)
|
|
25
|
+
- [How to use](#how-to-use)
|
|
26
|
+
- [Notebooks](#notebooks)
|
|
27
|
+
- [How to cite](#how-to-cite)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## About
|
|
31
|
+
|
|
32
|
+
**gridmlip** is a library for calculating percolation barriers of mobile species in solids using grid-based method with machine learning interatomic potentials (MLIPs).
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
pip install gridmlip
|
|
39
|
+
```
|
|
40
|
+
or
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
git clone https://github.com/dembart/gridmlip
|
|
44
|
+
cd gridmlip
|
|
45
|
+
pip install .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## How to use
|
|
49
|
+
Here we describe the pipeline in general. For a specific example, see [Notebooks](#notebooks).
|
|
50
|
+
|
|
51
|
+
#### Step #1: Construct configurations for processing with your favorite MLIP
|
|
52
|
+
```python
|
|
53
|
+
from gridmlip import Grid
|
|
54
|
+
|
|
55
|
+
atomic_types_mapper = {3:0, 31:1, 17:2}
|
|
56
|
+
grig = Grid.from_file('your.cif', specie = 3, r_min = 1.8,
|
|
57
|
+
atomic_types_mapper=atomic_types_mapper # optional
|
|
58
|
+
)
|
|
59
|
+
cfgs = grid.construct_configurations('data.cfg')
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Step #2: Evaluate the configurations with your favorite MLIP
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
mlp calculate_efs p.mtp data.cfg --output_filename=processed_data.cfg'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### Step #3: Read processed configrations and calculate the percolation barriers
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from gridmlip import Grid
|
|
72
|
+
|
|
73
|
+
grid = Grid.from_file('your.cif', specie = 3, r_min = 1.8)
|
|
74
|
+
grid.read_processed_configurations('processed_data.cfg', format = 'cfg')
|
|
75
|
+
grid.percolation_barriers()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Step #4: Write .grd or .cube file for visualization in VESTA 3.0
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
g.write_grd('test.grd')
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Notebooks
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
- [Using TensorNet model pre-trained on MatPES](notebooks/TensorNet_MatPES.ipynb)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
### How to cite
|
|
91
|
+
If you use the gridmlip library, please, consider citing this repository.
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
gridmlip-0.1/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
## gridmlip
|
|
2
|
+
<p align="left">
|
|
3
|
+
<a href="https://github.com/dembart/gridmlip/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-darkred"></a>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Contents
|
|
7
|
+
- [About](#about)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [How to use](#how-to-use)
|
|
10
|
+
- [Notebooks](#notebooks)
|
|
11
|
+
- [How to cite](#how-to-cite)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## About
|
|
15
|
+
|
|
16
|
+
**gridmlip** is a library for calculating percolation barriers of mobile species in solids using grid-based method with machine learning interatomic potentials (MLIPs).
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
pip install gridmlip
|
|
23
|
+
```
|
|
24
|
+
or
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
git clone https://github.com/dembart/gridmlip
|
|
28
|
+
cd gridmlip
|
|
29
|
+
pip install .
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## How to use
|
|
33
|
+
Here we describe the pipeline in general. For a specific example, see [Notebooks](#notebooks).
|
|
34
|
+
|
|
35
|
+
#### Step #1: Construct configurations for processing with your favorite MLIP
|
|
36
|
+
```python
|
|
37
|
+
from gridmlip import Grid
|
|
38
|
+
|
|
39
|
+
atomic_types_mapper = {3:0, 31:1, 17:2}
|
|
40
|
+
grig = Grid.from_file('your.cif', specie = 3, r_min = 1.8,
|
|
41
|
+
atomic_types_mapper=atomic_types_mapper # optional
|
|
42
|
+
)
|
|
43
|
+
cfgs = grid.construct_configurations('data.cfg')
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Step #2: Evaluate the configurations with your favorite MLIP
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
mlp calculate_efs p.mtp data.cfg --output_filename=processed_data.cfg'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Step #3: Read processed configrations and calculate the percolation barriers
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from gridmlip import Grid
|
|
56
|
+
|
|
57
|
+
grid = Grid.from_file('your.cif', specie = 3, r_min = 1.8)
|
|
58
|
+
grid.read_processed_configurations('processed_data.cfg', format = 'cfg')
|
|
59
|
+
grid.percolation_barriers()
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Step #4: Write .grd or .cube file for visualization in VESTA 3.0
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
g.write_grd('test.grd')
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Notebooks
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
- [Using TensorNet model pre-trained on MatPES](notebooks/TensorNet_MatPES.ipynb)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### How to cite
|
|
75
|
+
If you use the gridmlip library, please, consider citing this repository.
|
|
76
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .core import Grid
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import numpy as np
|
|
3
|
+
from scipy.spatial import cKDTree
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _scale_cell(cell, r_cut):
|
|
8
|
+
volume = cell.volume
|
|
9
|
+
scale_a = 2 * np.ceil(r_cut/(volume/np.linalg.norm(np.cross(cell[2, :], cell[1, :])))) + 1
|
|
10
|
+
scale_b = 2 * np.ceil(r_cut/(volume/np.linalg.norm(np.cross(cell[0, :], cell[2, :])))) + 1
|
|
11
|
+
scale_c = 2 * np.ceil(r_cut/(volume/np.linalg.norm(np.cross(cell[0, :], cell[1, :])))) + 1
|
|
12
|
+
return scale_a, scale_b, scale_c
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def nn_list(atoms_pos, mesh_pos, r_cut, cell = None):
|
|
17
|
+
|
|
18
|
+
if np.any(cell):
|
|
19
|
+
scale = _scale_cell(cell, r_cut)
|
|
20
|
+
scales = []
|
|
21
|
+
for s in scale:
|
|
22
|
+
scales.append(np.arange(-(s // 2), s // 2 + 1))
|
|
23
|
+
translations = tuple(list(itertools.product(
|
|
24
|
+
scales[0],
|
|
25
|
+
scales[1],
|
|
26
|
+
scales[2])))
|
|
27
|
+
|
|
28
|
+
buffer = (atoms_pos[:, None, :] + np.dot(translations, cell)).reshape(-1, 3, order = 'F')
|
|
29
|
+
else:
|
|
30
|
+
buffer = atoms_pos
|
|
31
|
+
|
|
32
|
+
tree = cKDTree(buffer)
|
|
33
|
+
distances, indexes = tree.query(mesh_pos, workers=-1, k=1, distance_upper_bound = r_cut)
|
|
34
|
+
return distances, indexes
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import numpy as np
|
|
3
|
+
from scipy.ndimage import measurements, generate_binary_structure
|
|
4
|
+
from joblib import Parallel, delayed
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Percolyze:
|
|
8
|
+
|
|
9
|
+
def __init__(self, data):
|
|
10
|
+
self.data = data
|
|
11
|
+
self.size = data.shape
|
|
12
|
+
|
|
13
|
+
def _cross_boundary(self, coords, data_shape):
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
Check if connected component crosses the boundary of unit cell
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
|
|
21
|
+
coords: np.array
|
|
22
|
+
coordinates of points in connected component
|
|
23
|
+
|
|
24
|
+
data_shape: list
|
|
25
|
+
shape of the mesh constructed over supercell
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
----------
|
|
29
|
+
|
|
30
|
+
d: int
|
|
31
|
+
number of unit cells within a supercell that contains connected component
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
probe = coords[0, :]
|
|
35
|
+
cell_location = np.floor(probe / data_shape)
|
|
36
|
+
translations = np.array(list(itertools.product([0, 1],
|
|
37
|
+
[0, 1],
|
|
38
|
+
[0, 1])))
|
|
39
|
+
translations = translations - cell_location
|
|
40
|
+
test = probe + translations * data_shape
|
|
41
|
+
d = np.argwhere(abs(coords[:, None] - test).sum(axis = 2) == 0).shape[0]
|
|
42
|
+
return d
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _connected_components(self, data, tr):
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
Find connected components
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
|
|
54
|
+
data: np.array
|
|
55
|
+
BVSE distribution data
|
|
56
|
+
|
|
57
|
+
tr: float
|
|
58
|
+
energy threshold to find components
|
|
59
|
+
|
|
60
|
+
task: str, either "bvse" or "void"
|
|
61
|
+
select type of calculation
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
----------
|
|
65
|
+
|
|
66
|
+
labels, features: np.array, number of components
|
|
67
|
+
labels are data points colored to features values
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
n = 2
|
|
71
|
+
lx, ly, lz = data.shape
|
|
72
|
+
superdata = np.zeros((n * lx, n * ly, n * lz))
|
|
73
|
+
for i in range(n):
|
|
74
|
+
for j in range(n):
|
|
75
|
+
for k in range(n):
|
|
76
|
+
superdata[i*lx:(i+1)*lx, j*ly:(j+1)*ly, k*lz:(k+1)*lz] = data
|
|
77
|
+
|
|
78
|
+
region = superdata - superdata.min()
|
|
79
|
+
structure = generate_binary_structure(3,3)
|
|
80
|
+
|
|
81
|
+
labels, features = measurements.label(region < tr, structure = structure)
|
|
82
|
+
|
|
83
|
+
labels_with_pbc = self._apply_pbc(labels)
|
|
84
|
+
return labels_with_pbc, np.unique(labels_with_pbc) # labels, features
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _apply_pbc(self, labels):
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
Apply periodic boundary conditions to the NxMxL np.array of labeled points.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
|
|
96
|
+
labels: np.array of NxMxL size
|
|
97
|
+
array of labeles (connected components)
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
----------
|
|
101
|
+
|
|
102
|
+
labels, features: np.array of NxMxL size and np.array of its unique labels
|
|
103
|
+
the array returned implies pbc conditions
|
|
104
|
+
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
faces_left = [labels[-1, :, :],
|
|
108
|
+
labels[:, -1, :],
|
|
109
|
+
labels[:, :, -1]
|
|
110
|
+
]
|
|
111
|
+
faces_right = [labels[0, :, :],
|
|
112
|
+
labels[:, 0, :],
|
|
113
|
+
labels[:, :, 0]
|
|
114
|
+
]
|
|
115
|
+
for f1, f2 in zip(faces_left, faces_right):
|
|
116
|
+
for s in np.unique(f1):
|
|
117
|
+
if s == 0:
|
|
118
|
+
continue
|
|
119
|
+
else:
|
|
120
|
+
connect = np.unique(f2[f1 == s])
|
|
121
|
+
for c in connect:
|
|
122
|
+
if c == 0:
|
|
123
|
+
continue
|
|
124
|
+
else:
|
|
125
|
+
labels[labels == c] = s
|
|
126
|
+
return labels
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _percolation_dimension(self, labels, features):
|
|
131
|
+
|
|
132
|
+
"""
|
|
133
|
+
Check percolation dimensionality
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
|
|
138
|
+
labels: np.array
|
|
139
|
+
label from _connected_components method
|
|
140
|
+
|
|
141
|
+
features: np.array
|
|
142
|
+
label from _connected_components method
|
|
143
|
+
|
|
144
|
+
Returns
|
|
145
|
+
----------
|
|
146
|
+
d: dimensionality of percolation
|
|
147
|
+
Note: can be from 2 to 8, which is the number of neighboring unit cells within 3x3x3 supercell
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
if len(features) < 1:
|
|
151
|
+
d = 0
|
|
152
|
+
else:
|
|
153
|
+
d = max(Parallel(n_jobs=self.n_jobs,
|
|
154
|
+
backend = self.backend)(delayed(self._percolation_dimension_parallel)(feature, labels) for feature in features))
|
|
155
|
+
return d
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _percolation_dimension_parallel(self, feature, labels):
|
|
160
|
+
|
|
161
|
+
if feature == 0:
|
|
162
|
+
d = 0
|
|
163
|
+
else:
|
|
164
|
+
coords = np.argwhere(labels == feature)
|
|
165
|
+
d = self._cross_boundary(coords, np.array(labels.shape)/2)
|
|
166
|
+
return d
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _percolation_energy(self, dim, encut = 10.0):
|
|
171
|
+
|
|
172
|
+
"""
|
|
173
|
+
Get percolation energy fofr a given dimensionality of percolation
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
|
|
178
|
+
dim: int
|
|
179
|
+
dimensionality of percolation. 2 -> 1D, 4 -> 2D, 8 - 3D percolation
|
|
180
|
+
|
|
181
|
+
encut: float, 10.0 by default
|
|
182
|
+
stop criterion for the search of percolation energy
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
----------
|
|
186
|
+
barrier: float
|
|
187
|
+
percolation energy or np.inf if no percolation found
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
data = self.data.reshape(self.size)
|
|
191
|
+
data = data - data.min()
|
|
192
|
+
emin = data.min()
|
|
193
|
+
emax = emin + encut
|
|
194
|
+
count = 0
|
|
195
|
+
barrier = np.inf
|
|
196
|
+
while (emax - emin) > 0.01:
|
|
197
|
+
count = count + 1
|
|
198
|
+
probe = (emin + emax) / 2
|
|
199
|
+
labels, features = self._connected_components(data, probe)
|
|
200
|
+
if len(features) > 0:
|
|
201
|
+
d = self._percolation_dimension(labels, features)
|
|
202
|
+
if d >= dim:
|
|
203
|
+
emax = probe
|
|
204
|
+
barrier = round(emax,4)
|
|
205
|
+
else:
|
|
206
|
+
emin = probe
|
|
207
|
+
else:
|
|
208
|
+
emin = probe
|
|
209
|
+
return barrier
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def percolation_barriers(self, encut = 10.0, n_jobs = 1, backend = 'threading'):
|
|
214
|
+
|
|
215
|
+
"""
|
|
216
|
+
Find percolation energy and dimensionality of a migration network.
|
|
217
|
+
|
|
218
|
+
Parameters
|
|
219
|
+
----------
|
|
220
|
+
|
|
221
|
+
encut: float, 5.0 by default
|
|
222
|
+
cutoff energy above which barriers supposed to be np.inf
|
|
223
|
+
|
|
224
|
+
n_jobs: int, 1 by default
|
|
225
|
+
number of jobs to run for percolation energy search
|
|
226
|
+
|
|
227
|
+
backend: str, 'threading' by default
|
|
228
|
+
see joblib's documentations for more details
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
----------
|
|
232
|
+
|
|
233
|
+
energies: dict
|
|
234
|
+
infromation about percolation {'E_1D': float, 'E_2D': float, 'E_3D': float}
|
|
235
|
+
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
self.n_jobs = n_jobs
|
|
239
|
+
self.backend = backend
|
|
240
|
+
|
|
241
|
+
energies = {}
|
|
242
|
+
for i, dim in enumerate([2, 4, 8]):
|
|
243
|
+
|
|
244
|
+
energy = self._percolation_energy(encut = encut, dim = dim)
|
|
245
|
+
energies.update({f'E_{i+1}D': energy})
|
|
246
|
+
return energies
|
|
247
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# in progress
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from tqdm import tqdm
|
|
3
|
+
from ase.io import read, write, cube
|
|
4
|
+
from .utils import read_cfg, write_cfg
|
|
5
|
+
from ._neighborhood import nn_list
|
|
6
|
+
from ._percolation_analysis import Percolyze
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__version__ = "0.1"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Grid:
|
|
15
|
+
|
|
16
|
+
def __init__(self, atoms, specie = None, resolution = 0.25,
|
|
17
|
+
r_cut = 5.0, r_min = 1.5, atomic_types_mapper = None):
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
Initialization.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
|
|
25
|
+
atoms: ASE's Atoms object
|
|
26
|
+
atomic structure
|
|
27
|
+
|
|
28
|
+
specie: int
|
|
29
|
+
atomic number of the mobile specie
|
|
30
|
+
|
|
31
|
+
resolution: float, 0.2 by default
|
|
32
|
+
spacing between points (in Angstroms)
|
|
33
|
+
|
|
34
|
+
r_cut: float
|
|
35
|
+
cutoff radius to find the first nearest neighbor for each grid point
|
|
36
|
+
|
|
37
|
+
r_min: float
|
|
38
|
+
blocking sphere radius
|
|
39
|
+
|
|
40
|
+
atomic_types_mapper: dict, optional
|
|
41
|
+
mapper of atomic numbers into species used by MLIP
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
if atomic_types_mapper:
|
|
45
|
+
numbers = self._map_atomic_types(atomic_types_mapper, atoms.numbers)
|
|
46
|
+
atoms = atoms.copy()
|
|
47
|
+
atoms.numbers = numbers
|
|
48
|
+
specie = atomic_types_mapper[specie]
|
|
49
|
+
self.atoms = atoms.copy()
|
|
50
|
+
self.specie = specie
|
|
51
|
+
self.resolution = resolution
|
|
52
|
+
self.cell = self.atoms.cell
|
|
53
|
+
self._mesh(resolution)
|
|
54
|
+
self.base = self.atoms[self.atoms.numbers != self.specie]
|
|
55
|
+
self.min_dists, _ = nn_list(self.base.positions, self.mesh_cart, r_cut, self.cell)
|
|
56
|
+
self.r_cut = r_cut
|
|
57
|
+
self.r_min = r_min
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _map_atomic_types(self, atomic_types_mapper, numbers):
|
|
62
|
+
u,inv = np.unique(numbers,return_inverse = True)
|
|
63
|
+
return np.array([atomic_types_mapper[x] for x in u])[inv].reshape(numbers.shape)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _mesh(self, resolution):
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
This method creates grid of equidistant points in 3D
|
|
71
|
+
with respect to the input resolution.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
resolution: float, 0.2 by default
|
|
76
|
+
spacing between points (in Angstroms)
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
mesh_cart: np.array
|
|
81
|
+
cartesian coordinates of meshgrid
|
|
82
|
+
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
a, b, c, _, _, _ = self.cell.cellpar()
|
|
86
|
+
nx, ny, nz = int(a // resolution), int(b // resolution), int(c // resolution)
|
|
87
|
+
x = np.linspace(0, 1, nx)
|
|
88
|
+
y = np.linspace(0, 1, ny)
|
|
89
|
+
z = np.linspace(0, 1, nz)
|
|
90
|
+
self.mesh_frac = np.stack(np.meshgrid(x, y, z, indexing='ij'), axis=-1).reshape(-1, 3)
|
|
91
|
+
self.mesh_cart = self.cell.cartesian_positions(self.mesh_frac)
|
|
92
|
+
self.size = (nx, ny, nz)
|
|
93
|
+
return self.mesh_cart
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def from_file(cls, file, specie = None, resolution = 0.25,
|
|
99
|
+
r_cut = 5.0, r_min = 1.5, atomic_types_mapper = None):
|
|
100
|
+
"""
|
|
101
|
+
Create Grid object from the file.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
|
|
106
|
+
file: string
|
|
107
|
+
.xyz of .cfg file representing atomic structure
|
|
108
|
+
|
|
109
|
+
specie: int
|
|
110
|
+
atomic number of the mobile specie
|
|
111
|
+
|
|
112
|
+
resolution: float, 0.2 by default
|
|
113
|
+
spacing between points (in Angstroms)
|
|
114
|
+
|
|
115
|
+
r_cut: float
|
|
116
|
+
cutoff radius to find the first nearest neighbor for each grid point
|
|
117
|
+
|
|
118
|
+
r_min: float
|
|
119
|
+
blocking sphere radius
|
|
120
|
+
|
|
121
|
+
atomic_types_mapper: dict, optional
|
|
122
|
+
mapper of the species into atomic numbers
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
Grid object
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
if file.split('.')[-1] == 'cfg':
|
|
130
|
+
atoms = read_cfg(file)[0]
|
|
131
|
+
else:
|
|
132
|
+
atoms = read(file)
|
|
133
|
+
return cls(atoms, specie, resolution=resolution,
|
|
134
|
+
r_cut = r_cut, r_min = r_min, atomic_types_mapper = atomic_types_mapper)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def construct_configurations(self, filename = None):
|
|
139
|
+
"""
|
|
140
|
+
Construct atomic configurations for further calculations.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
|
|
145
|
+
filename: string (Optional)
|
|
146
|
+
path to save .xyz of .cfg file with atomic configurations
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
configurations: list of ASE's atoms object
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
configurations = []
|
|
154
|
+
for p, d in tqdm(zip(self.mesh_cart, self.min_dists), desc = 'creating configurations'):
|
|
155
|
+
if d > self.r_min:
|
|
156
|
+
framework = self.base.copy()
|
|
157
|
+
framework.append(self.specie)
|
|
158
|
+
framework.positions[-1] = p
|
|
159
|
+
configurations.append(framework)
|
|
160
|
+
|
|
161
|
+
if filename:
|
|
162
|
+
if filename.split('.')[-1] == 'cfg':
|
|
163
|
+
write_cfg(filename, configurations)
|
|
164
|
+
else:
|
|
165
|
+
write(filename, configurations)
|
|
166
|
+
return configurations
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def load_energies(self, energies):
|
|
171
|
+
|
|
172
|
+
"""
|
|
173
|
+
Load energies obtained by any MLIP or structure-to-property model.
|
|
174
|
+
Should match order in created configurations.
|
|
175
|
+
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
|
|
179
|
+
energies: np.array
|
|
180
|
+
calculated energies for the created configurations
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
self.energies = energies
|
|
184
|
+
self.distribution = np.ones_like(self.min_dists) * np.inf
|
|
185
|
+
self.distribution[self.min_dists > self.r_min] = self.energies
|
|
186
|
+
self.distribution = np.nan_to_num(self.distribution, copy = False, nan = np.inf)
|
|
187
|
+
self.data = self.distribution.reshape(self.size)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def read_processed_configurations(self, filename, format = 'xyz'):
|
|
191
|
+
|
|
192
|
+
"""
|
|
193
|
+
Read processed (by any MLIP) atomic configurations
|
|
194
|
+
with calculated energies.
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
|
|
199
|
+
filename: string
|
|
200
|
+
path to the processed .xyz of .cfg file
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
if format == 'cfg':
|
|
204
|
+
atoms_list = read_cfg(filename)
|
|
205
|
+
else:
|
|
206
|
+
atoms_list = read(filename, index = ':')
|
|
207
|
+
self.energies = np.array([atoms.get_potential_energy() for atoms in atoms_list])
|
|
208
|
+
del atoms_list
|
|
209
|
+
self.distribution = np.ones_like(self.min_dists) * np.inf
|
|
210
|
+
self.distribution[self.min_dists > self.r_min] = self.energies
|
|
211
|
+
self.distribution = np.nan_to_num(self.distribution, copy = False, nan = np.inf)
|
|
212
|
+
self.data = self.distribution.reshape(self.size)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def write_cube(self, filename):
|
|
217
|
+
|
|
218
|
+
"""
|
|
219
|
+
Write .cube file containing structural and MLIP distribution data.
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
|
|
224
|
+
filename: str
|
|
225
|
+
file name to write .cube
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
data = self.data
|
|
229
|
+
nx, ny, nz = data.shape
|
|
230
|
+
with open(f'{filename}.cube', 'w') as f:
|
|
231
|
+
cube.write_cube(f, self.atoms, data = data[:nx-1, :ny-1, :nz-1])
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def write_grd(self, filename):
|
|
236
|
+
|
|
237
|
+
"""
|
|
238
|
+
Write MLIP distribution volumetric file for VESTA 3.0.
|
|
239
|
+
|
|
240
|
+
Parameters
|
|
241
|
+
----------
|
|
242
|
+
|
|
243
|
+
filename: str
|
|
244
|
+
file name to write .grd
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
data = self.data
|
|
249
|
+
voxels = data.shape[0] - 1, data.shape[1] - 1, data.shape[2] - 1
|
|
250
|
+
cellpars = self.cell.cellpar()
|
|
251
|
+
with open(f'{filename}.grd' , 'w') as report:
|
|
252
|
+
comment = '# MLIP data made with gridmlip package: https://github.com/dembart/gridmlip'
|
|
253
|
+
report.write(comment + '\n')
|
|
254
|
+
report.write(''.join(str(p) + ' ' for p in cellpars).strip() + '\n')
|
|
255
|
+
report.write(''.join(str(v) + ' ' for v in voxels).strip() + '\n')
|
|
256
|
+
for i in range(voxels[0]):
|
|
257
|
+
for j in range(voxels[1]):
|
|
258
|
+
for k in range(voxels[2]):
|
|
259
|
+
val = data[i, j, k]
|
|
260
|
+
report.write(str(val) + '\n')
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def percolation_barriers(self, encut = 10.0):
|
|
265
|
+
"""
|
|
266
|
+
Calculate percolation barriers.
|
|
267
|
+
|
|
268
|
+
Parameters
|
|
269
|
+
----------
|
|
270
|
+
encut: float, 10.0 by default
|
|
271
|
+
upper bound for searching the barrier
|
|
272
|
+
"""
|
|
273
|
+
pl = Percolyze(self.data)
|
|
274
|
+
return pl.percolation_barriers(encut = encut)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from tqdm import tqdm
|
|
3
|
+
from ase import Atoms
|
|
4
|
+
from ase.calculators.singlepoint import SinglePointCalculator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def read_cfg(filename):
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Read .cfg file format used in MLIP package
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
file: str
|
|
16
|
+
path to the file
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
----------
|
|
20
|
+
list of ase's Atoms object with a SinglePointCalculator
|
|
21
|
+
"""
|
|
22
|
+
with open(filename, 'r') as f:
|
|
23
|
+
text = f.readlines()
|
|
24
|
+
configurations = []
|
|
25
|
+
for i_s, i_e in tqdm(zip(np.where(np.array(text) == 'BEGIN_CFG\n')[0], np.where(np.array(text) == 'END_CFG\n')[0])):
|
|
26
|
+
subtext = text[i_s:i_e]
|
|
27
|
+
grade = None
|
|
28
|
+
results = {}
|
|
29
|
+
for i, line in enumerate(subtext):
|
|
30
|
+
if 'Size' in line:
|
|
31
|
+
size = int(subtext[i+1])
|
|
32
|
+
if 'Supercell' in line:
|
|
33
|
+
x = subtext[i+1]
|
|
34
|
+
y = subtext[i+2]
|
|
35
|
+
z = subtext[i+3]
|
|
36
|
+
cell = np.array([x.split(), y.split(), z.split()], dtype = float)
|
|
37
|
+
if 'AtomData' in line:
|
|
38
|
+
pos, forces, numbers = [], [], []
|
|
39
|
+
for n in range(size):
|
|
40
|
+
if len(subtext[i+n+1].split()) == 8:
|
|
41
|
+
id_, num, pos_x, pos_y, pos_z, f_x, f_y, f_z = subtext[i+n+1].split()
|
|
42
|
+
pos.append(np.array([pos_x, pos_y, pos_z], dtype = float))
|
|
43
|
+
forces.append(np.array([f_x, f_y, f_z], dtype = float))
|
|
44
|
+
numbers.append(num)
|
|
45
|
+
elif len(subtext[i+n+1].split()) == 5:
|
|
46
|
+
id_, num, pos_x, pos_y, pos_z = subtext[i+n+1].split()
|
|
47
|
+
pos.append(np.array([pos_x, pos_y, pos_z], dtype = float))
|
|
48
|
+
forces.append(np.array([None, None, None], dtype = float))
|
|
49
|
+
numbers.append(num)
|
|
50
|
+
results.update({'forces': forces})
|
|
51
|
+
if 'MV' in line:
|
|
52
|
+
grade = float(line.split()[-1])
|
|
53
|
+
if 'Energy' in line:
|
|
54
|
+
energy = float(subtext[i+1].split()[-1])
|
|
55
|
+
results.update({'energy': energy})
|
|
56
|
+
if 'PlusStress' in line:
|
|
57
|
+
stress = np.array(subtext[i+1].split(), dtype = float)
|
|
58
|
+
results.update({'stress': stress})
|
|
59
|
+
atoms = Atoms(cell = cell, positions = np.array(pos), numbers = numbers, pbc = True)
|
|
60
|
+
calc = SinglePointCalculator(atoms, **results)
|
|
61
|
+
atoms.calc = calc
|
|
62
|
+
configurations.append(atoms)
|
|
63
|
+
return configurations
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def write_cfg(filename, atoms_list):
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
Write list of atoms into .cfg file used in MLIP package
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
filename: str
|
|
74
|
+
path to the file
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
with open(filename, 'w') as text:
|
|
78
|
+
for atoms in tqdm(atoms_list):
|
|
79
|
+
|
|
80
|
+
text.write('BEGIN_CFG\n')
|
|
81
|
+
|
|
82
|
+
# Size
|
|
83
|
+
text.write(' Size\n')
|
|
84
|
+
text.write('{:6}'.format(len(atoms)) + '\n')
|
|
85
|
+
|
|
86
|
+
# Supercell
|
|
87
|
+
box = np.array(atoms.cell)
|
|
88
|
+
text.write(' Supercell\n')
|
|
89
|
+
text.write(''.join(map('{:16.6f}'.format, box[0, :])) + '\n')
|
|
90
|
+
text.write(''.join(map('{:16.6f}'.format, box[1, :])) + '\n')
|
|
91
|
+
text.write(''.join(map('{:16.6f}'.format, box[2, :])) + '\n')
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
keys = []
|
|
95
|
+
keys.append('ids')
|
|
96
|
+
ids = np.arange(1, len(atoms) + 1)
|
|
97
|
+
|
|
98
|
+
keys.append('type')
|
|
99
|
+
types = atoms.numbers
|
|
100
|
+
|
|
101
|
+
keys.append('cartes_x')
|
|
102
|
+
cartes_x = atoms.positions[:, 0]
|
|
103
|
+
keys.append('cartes_y')
|
|
104
|
+
cartes_y = atoms.positions[:, 1]
|
|
105
|
+
keys.append('cartes_z')
|
|
106
|
+
cartes_z = atoms.positions[:, 2]
|
|
107
|
+
|
|
108
|
+
# forces
|
|
109
|
+
try:
|
|
110
|
+
forces = atoms.get_forces()
|
|
111
|
+
keys.append('fx')
|
|
112
|
+
fx = forces[:, 0]
|
|
113
|
+
keys.append('fy')
|
|
114
|
+
fy = forces[:, 1]
|
|
115
|
+
keys.append('fz')
|
|
116
|
+
fz = forces[:, 2]
|
|
117
|
+
text.write(' AtomData: id type cartes_x cartes_y cartes_z fx fy fz\n')
|
|
118
|
+
data = np.vstack([ids, types, cartes_x, cartes_y, cartes_z, fx, fy, fz]).T
|
|
119
|
+
except:
|
|
120
|
+
text.write(' AtomData: id type cartes_x cartes_y cartes_z\n')
|
|
121
|
+
data = np.vstack([ids, types, cartes_x, cartes_y, cartes_z]).T
|
|
122
|
+
|
|
123
|
+
for i in range(len(data)):
|
|
124
|
+
row = list(data[i, :])
|
|
125
|
+
row[0] = int(row[0])
|
|
126
|
+
row[1] = int(row[1])
|
|
127
|
+
if len(row) == 5:
|
|
128
|
+
text.write('{:13} {:2} {:>13.6f} {:>6.6f} {:>9.6f}'.format(*row) + '\n')
|
|
129
|
+
elif len(row) == 8:
|
|
130
|
+
text.write('{:13} {:2} {:>13.6f} {:>6.6f} {:>9.6f} {:>9.6f} {:>9.6f} {:>9.6f}\n'.format(*row))
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
energy = atoms.get_potential_energy()
|
|
134
|
+
text.write(' Energy\n')
|
|
135
|
+
text.write('{:>13.6f}'.format(energy) + '\n')
|
|
136
|
+
except:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
stress = atoms.get_stress()
|
|
141
|
+
text.write(' PlusStress: xx yy zz yz xz xy\n')
|
|
142
|
+
text.write(' {:>15.6f} {:>4.6f} {:>4.6f} {:>4.6f} {:>4.6f} {:>4.6f}'.format(*stress) + '\n')
|
|
143
|
+
except:
|
|
144
|
+
pass
|
|
145
|
+
text.write(' Feature EFS_by no_info\n')
|
|
146
|
+
text.write('END_CFG\n\n')
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: gridmlip
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: Grid-based method for calculating the percolation barrier of mobile species using machine learning interatomic potentials
|
|
5
|
+
Home-page: https://github.com/dembart/gridmlip
|
|
6
|
+
Author: Artem Dembitskiy
|
|
7
|
+
Author-email: art.dembitskiy@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: MLIP,percolation barrier
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
|
|
17
|
+
## gridmlip
|
|
18
|
+
<p align="left">
|
|
19
|
+
<a href="https://github.com/dembart/gridmlip/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-darkred"></a>
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Contents
|
|
23
|
+
- [About](#about)
|
|
24
|
+
- [Installation](#installation)
|
|
25
|
+
- [How to use](#how-to-use)
|
|
26
|
+
- [Notebooks](#notebooks)
|
|
27
|
+
- [How to cite](#how-to-cite)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## About
|
|
31
|
+
|
|
32
|
+
**gridmlip** is a library for calculating percolation barriers of mobile species in solids using grid-based method with machine learning interatomic potentials (MLIPs).
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
pip install gridmlip
|
|
39
|
+
```
|
|
40
|
+
or
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
git clone https://github.com/dembart/gridmlip
|
|
44
|
+
cd gridmlip
|
|
45
|
+
pip install .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## How to use
|
|
49
|
+
Here we describe the pipeline in general. For a specific example, see [Notebooks](#notebooks).
|
|
50
|
+
|
|
51
|
+
#### Step #1: Construct configurations for processing with your favorite MLIP
|
|
52
|
+
```python
|
|
53
|
+
from gridmlip import Grid
|
|
54
|
+
|
|
55
|
+
atomic_types_mapper = {3:0, 31:1, 17:2}
|
|
56
|
+
grig = Grid.from_file('your.cif', specie = 3, r_min = 1.8,
|
|
57
|
+
atomic_types_mapper=atomic_types_mapper # optional
|
|
58
|
+
)
|
|
59
|
+
cfgs = grid.construct_configurations('data.cfg')
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Step #2: Evaluate the configurations with your favorite MLIP
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
mlp calculate_efs p.mtp data.cfg --output_filename=processed_data.cfg'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### Step #3: Read processed configrations and calculate the percolation barriers
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from gridmlip import Grid
|
|
72
|
+
|
|
73
|
+
grid = Grid.from_file('your.cif', specie = 3, r_min = 1.8)
|
|
74
|
+
grid.read_processed_configurations('processed_data.cfg', format = 'cfg')
|
|
75
|
+
grid.percolation_barriers()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Step #4: Write .grd or .cube file for visualization in VESTA 3.0
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
g.write_grd('test.grd')
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Notebooks
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
- [Using TensorNet model pre-trained on MatPES](notebooks/TensorNet_MatPES.ipynb)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
### How to cite
|
|
91
|
+
If you use the gridmlip library, please, consider citing this repository.
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.cfg
|
|
6
|
+
setup.py
|
|
7
|
+
gridmlip/__init__.py
|
|
8
|
+
gridmlip/_neighborhood.py
|
|
9
|
+
gridmlip/_percolation_analysis.py
|
|
10
|
+
gridmlip/cli.py
|
|
11
|
+
gridmlip/core.py
|
|
12
|
+
gridmlip/utils.py
|
|
13
|
+
gridmlip.egg-info/PKG-INFO
|
|
14
|
+
gridmlip.egg-info/SOURCES.txt
|
|
15
|
+
gridmlip.egg-info/dependency_links.txt
|
|
16
|
+
gridmlip.egg-info/requires.txt
|
|
17
|
+
gridmlip.egg-info/top_level.txt
|
|
18
|
+
gridmlip.egg-info/zip-safe
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gridmlip
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
gridmlip-0.1/setup.cfg
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = gridmlip
|
|
3
|
+
version = attr: gridmlip.core.__version__
|
|
4
|
+
author = Artem Dembitskiy and Alexey Maltsev
|
|
5
|
+
author_email = art.dembitskiy@gmail.com
|
|
6
|
+
url = https://github.com/dembart/gridmlip
|
|
7
|
+
description = gridmlip
|
|
8
|
+
long_description = file: README.md
|
|
9
|
+
long_description_content_type = text/markdown
|
|
10
|
+
keywords = MLIP, percolation barrier
|
|
11
|
+
license = MIT
|
|
12
|
+
classifiers =
|
|
13
|
+
License :: OSI Approved :: BSD License
|
|
14
|
+
Programming Language :: Python :: 3
|
|
15
|
+
|
|
16
|
+
[options]
|
|
17
|
+
packages = find:
|
|
18
|
+
zip_safe = True
|
|
19
|
+
include_package_data = True
|
|
20
|
+
install_requires =
|
|
21
|
+
pandas
|
|
22
|
+
numpy
|
|
23
|
+
ase
|
|
24
|
+
tqdm
|
|
25
|
+
scipy
|
|
26
|
+
joblib
|
|
27
|
+
|
|
28
|
+
[egg_info]
|
|
29
|
+
tag_build =
|
|
30
|
+
tag_date = 0
|
|
31
|
+
|
gridmlip-0.1/setup.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import setuptools
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setuptools.setup(
|
|
7
|
+
name='gridmlip',
|
|
8
|
+
version='0.1',
|
|
9
|
+
py_modules = ["gridmlip"],
|
|
10
|
+
install_requires = [
|
|
11
|
+
"pandas",
|
|
12
|
+
"numpy",
|
|
13
|
+
"scipy",
|
|
14
|
+
"ase",
|
|
15
|
+
"tqdm",
|
|
16
|
+
"joblib",
|
|
17
|
+
],
|
|
18
|
+
author="Artem Dembitskiy",
|
|
19
|
+
author_email="art.dembitskiy@gmail.com",
|
|
20
|
+
description="Grid-based method for calculating the percolation barrier of mobile species using machine learning interatomic potentials",
|
|
21
|
+
key_words = ['percolation-barrier', 'umlip', 'conductivity', 'diffusion'],
|
|
22
|
+
long_description=long_description,
|
|
23
|
+
long_description_content_type="text/markdown",
|
|
24
|
+
url="https://github.com/dembart/gridmlip",
|
|
25
|
+
package_data={"gridmlip": ["*.rst", '*.md'],
|
|
26
|
+
#'tests':['*'],
|
|
27
|
+
},
|
|
28
|
+
classifiers=[
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"License :: OSI Approved :: MIT License",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
],
|
|
33
|
+
include_package_data=True,
|
|
34
|
+
packages=setuptools.find_packages(),
|
|
35
|
+
)
|