gridmlip 0.2__tar.gz → 0.2.3__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 (35) hide show
  1. {gridmlip-0.2 → gridmlip-0.2.3}/LICENSE +1 -2
  2. {gridmlip-0.2 → gridmlip-0.2.3}/MANIFEST.in +0 -1
  3. gridmlip-0.2.3/PKG-INFO +131 -0
  4. gridmlip-0.2.3/README.md +112 -0
  5. gridmlip-0.2.3/gridmlip/_distortion.py +44 -0
  6. gridmlip-0.2.3/gridmlip/_generate.py +251 -0
  7. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip/_mesh.py +0 -1
  8. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip/_neighborhood.py +9 -14
  9. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip/_percolation_analysis.py +8 -8
  10. gridmlip-0.2.3/gridmlip/_version.py +1 -0
  11. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip/core.py +177 -104
  12. gridmlip-0.2.3/gridmlip/integrations/__init__.py +0 -0
  13. gridmlip-0.2.3/gridmlip/integrations/gnn_lib.py +107 -0
  14. gridmlip-0.2.3/gridmlip/integrations/mace.py +93 -0
  15. gridmlip-0.2.3/gridmlip/integrations/sevennet.py +87 -0
  16. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip/utils.py +2 -1
  17. gridmlip-0.2.3/gridmlip.egg-info/PKG-INFO +131 -0
  18. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip.egg-info/SOURCES.txt +12 -1
  19. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip.egg-info/requires.txt +2 -2
  20. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip.egg-info/top_level.txt +1 -0
  21. gridmlip-0.2.3/scripts/__init__.py +0 -0
  22. gridmlip-0.2.3/scripts/_nebtools.py +0 -0
  23. gridmlip-0.2.3/scripts/_void_search.py +60 -0
  24. gridmlip-0.2.3/scripts/estimate_bvel13k_dataset_size.py +446 -0
  25. {gridmlip-0.2 → gridmlip-0.2.3}/setup.cfg +9 -4
  26. gridmlip-0.2.3/setup.py +2 -0
  27. gridmlip-0.2/PKG-INFO +0 -94
  28. gridmlip-0.2/README.md +0 -76
  29. gridmlip-0.2/gridmlip.egg-info/PKG-INFO +0 -94
  30. gridmlip-0.2/setup.py +0 -35
  31. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip/__init__.py +0 -0
  32. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip/cli.py +0 -0
  33. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip.egg-info/dependency_links.txt +0 -0
  34. {gridmlip-0.2 → gridmlip-0.2.3}/gridmlip.egg-info/zip-safe +0 -0
  35. {gridmlip-0.2 → gridmlip-0.2.3}/pyproject.toml +0 -0
@@ -1,5 +1,4 @@
1
-
2
- Copyright (c) 2025 Artem Dembitskiy
1
+ Copyright (c) 2025-2026 Artem D. Dembitskiy
3
2
 
4
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
4
  of this software and associated documentation files (the "Software"), to deal
@@ -1,3 +1,2 @@
1
1
  include LICENSE
2
2
  include README.md
3
-
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.1
2
+ Name: gridmlip
3
+ Version: 0.2.3
4
+ Summary: gridmlip
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,irreducible mesh
10
+ Classifier: License :: OSI Approved :: BSD License
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: 3.15
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+
20
+ ## gridmlip
21
+ <p align="left">
22
+ <a href="https://github.com/dembart/gridmlip/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-darkred"></a>
23
+
24
+
25
+ ## Contents
26
+ - [About](#about)
27
+ - [Installation](#installation)
28
+ - [How to use](#how-to-use)
29
+ - [Notebooks](#notebooks)
30
+ - [How to cite](#how-to-cite)
31
+
32
+
33
+ ## About
34
+
35
+ **gridmlip** is a library for the symmetry-aware grid-based sampling of the energy landscape of mobile species in solids using machine learning interatomic potentials (MLIPs).
36
+
37
+ > (!) Note: The API and functionality may change. Errors are expected. The library is under development.
38
+
39
+ ## Installation
40
+
41
+ ```
42
+ pip install gridmlip
43
+ ```
44
+ or
45
+
46
+ ```python
47
+ git clone https://github.com/dembart/gridmlip
48
+ cd gridmlip
49
+ pip install .
50
+ ```
51
+
52
+ ## How to use
53
+ Here we describe the pipeline in general. For a specific example, see [Notebooks](#notebooks).
54
+
55
+ ### Percolation analysis
56
+
57
+ ```python
58
+ from gridmlip import Grid
59
+ from gridmlip.integrations.sevennet import evaluate_atoms_list # sevenn must be installed
60
+
61
+ file = './data/Li10Ge(PS6)2_mp.cif'
62
+ specie = 3
63
+
64
+ ### Create grid
65
+ g = Grid.from_file(
66
+ file,
67
+ specie,
68
+ r_min=0.8,
69
+ r_cut=5.0,
70
+ resolution=0.2,
71
+ symprec=0.1,
72
+ empty_framework=True,
73
+ verbose=True
74
+ )
75
+
76
+ ### Prepare inequivalent atomic configurations
77
+ atoms_list = g.construct_configurations(config_format='ase')
78
+
79
+ ### Predict energies
80
+ energy_list, forces_list = evaluate_atoms_list(
81
+ atoms_list,
82
+ model_path='./data/checkpoint_sevennet_0.pth',
83
+ device='cuda',
84
+ compute_force=False,
85
+ batch_size=256
86
+ )
87
+
88
+ ### Load energies
89
+ g.load_energies(energy_list)
90
+
91
+ ### Determine percolation barriers
92
+ barriers = g.percolation_barriers(n_jobs=-1)
93
+
94
+ ### Save .grd file for visualization in VESTA 3.0
95
+ g.write_grd('test.grd')
96
+ ```
97
+ ### Generate defected configurations for MLIP pre-training
98
+
99
+ ```python
100
+ from ase.io import read
101
+ from gridmlip._generate import DefectGenerator
102
+
103
+ GENERATOR_PARAMS = {
104
+ 'specie': 3,
105
+ 'resolution': 0.25,
106
+ 'r_min': 1.3,
107
+ 'r_cut': 7.5,
108
+ 'symprec': 0.1,
109
+ 'max_sep_dist': 'auto',
110
+ 'upper_bound': 6.0,
111
+ }
112
+
113
+ gen = DefectGenerator(atoms, **GENERATOR_PARAMS)
114
+
115
+ ### Symmetrically distinct defect configurations
116
+ cfgs_int = gen.generate_dataset(defect_type='int')
117
+ cfgs_vac= gen.generate_dataset(defect_type='vac')
118
+ cfgs_frk = gen.generate_dataset(defect_type='frenkel')
119
+ ```
120
+
121
+ ## Notebooks
122
+
123
+
124
+ - [Using SevenNet for calculating percolation barriers](notebooks/integrations.ipynb)
125
+
126
+ - [Using moment tensor potentials (as implemented in MLIP 2.0) for calculating percolation barriers](notebooks/mtp.ipynb)
127
+
128
+
129
+ ### How to cite
130
+ If you use the gridmlip library, please, consider citing this repository.
131
+
@@ -0,0 +1,112 @@
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 the symmetry-aware grid-based sampling of the energy landscape of mobile species in solids using machine learning interatomic potentials (MLIPs).
17
+
18
+ > (!) Note: The API and functionality may change. Errors are expected. The library is under development.
19
+
20
+ ## Installation
21
+
22
+ ```
23
+ pip install gridmlip
24
+ ```
25
+ or
26
+
27
+ ```python
28
+ git clone https://github.com/dembart/gridmlip
29
+ cd gridmlip
30
+ pip install .
31
+ ```
32
+
33
+ ## How to use
34
+ Here we describe the pipeline in general. For a specific example, see [Notebooks](#notebooks).
35
+
36
+ ### Percolation analysis
37
+
38
+ ```python
39
+ from gridmlip import Grid
40
+ from gridmlip.integrations.sevennet import evaluate_atoms_list # sevenn must be installed
41
+
42
+ file = './data/Li10Ge(PS6)2_mp.cif'
43
+ specie = 3
44
+
45
+ ### Create grid
46
+ g = Grid.from_file(
47
+ file,
48
+ specie,
49
+ r_min=0.8,
50
+ r_cut=5.0,
51
+ resolution=0.2,
52
+ symprec=0.1,
53
+ empty_framework=True,
54
+ verbose=True
55
+ )
56
+
57
+ ### Prepare inequivalent atomic configurations
58
+ atoms_list = g.construct_configurations(config_format='ase')
59
+
60
+ ### Predict energies
61
+ energy_list, forces_list = evaluate_atoms_list(
62
+ atoms_list,
63
+ model_path='./data/checkpoint_sevennet_0.pth',
64
+ device='cuda',
65
+ compute_force=False,
66
+ batch_size=256
67
+ )
68
+
69
+ ### Load energies
70
+ g.load_energies(energy_list)
71
+
72
+ ### Determine percolation barriers
73
+ barriers = g.percolation_barriers(n_jobs=-1)
74
+
75
+ ### Save .grd file for visualization in VESTA 3.0
76
+ g.write_grd('test.grd')
77
+ ```
78
+ ### Generate defected configurations for MLIP pre-training
79
+
80
+ ```python
81
+ from ase.io import read
82
+ from gridmlip._generate import DefectGenerator
83
+
84
+ GENERATOR_PARAMS = {
85
+ 'specie': 3,
86
+ 'resolution': 0.25,
87
+ 'r_min': 1.3,
88
+ 'r_cut': 7.5,
89
+ 'symprec': 0.1,
90
+ 'max_sep_dist': 'auto',
91
+ 'upper_bound': 6.0,
92
+ }
93
+
94
+ gen = DefectGenerator(atoms, **GENERATOR_PARAMS)
95
+
96
+ ### Symmetrically distinct defect configurations
97
+ cfgs_int = gen.generate_dataset(defect_type='int')
98
+ cfgs_vac= gen.generate_dataset(defect_type='vac')
99
+ cfgs_frk = gen.generate_dataset(defect_type='frenkel')
100
+ ```
101
+
102
+ ## Notebooks
103
+
104
+
105
+ - [Using SevenNet for calculating percolation barriers](notebooks/integrations.ipynb)
106
+
107
+ - [Using moment tensor potentials (as implemented in MLIP 2.0) for calculating percolation barriers](notebooks/mtp.ipynb)
108
+
109
+
110
+ ### How to cite
111
+ If you use the gridmlip library, please, consider citing this repository.
112
+
@@ -0,0 +1,44 @@
1
+ import numpy as np
2
+
3
+
4
+ def _get_rng(rng=None):
5
+ if isinstance(rng, np.random.Generator):
6
+ return rng
7
+ return np.random.default_rng(rng)
8
+
9
+
10
+ def distort_lattice(atoms, std=0.03, rng=None):
11
+ """Randomly apply independent strain to the three lattice vectors."""
12
+ rng = _get_rng(rng)
13
+
14
+ cell = atoms.cell.array.copy()
15
+ lengths = np.linalg.norm(cell, axis=1)
16
+
17
+ scale = rng.uniform(
18
+ 1 - std,
19
+ 1 + std,
20
+ size=3,
21
+ )
22
+
23
+ new_lengths = lengths * scale
24
+ new_cell = cell * (new_lengths / lengths)[:, None]
25
+
26
+ distorted = atoms.copy()
27
+ distorted.info["original_cell"] = atoms.cell.array.copy()
28
+ distorted.set_cell(new_cell, scale_atoms=True)
29
+
30
+ return distorted
31
+
32
+
33
+ def rattle_positions(atoms, std=0.05, rng=None):
34
+ """Randomly rattle atomic positions."""
35
+ rng = _get_rng(rng)
36
+
37
+ rattled = atoms.copy()
38
+ rattled.arrays["original_positions"] = (
39
+ rattled.positions.copy()
40
+ )
41
+
42
+ rattled.rattle(stdev=std, rng=rng)
43
+
44
+ return rattled
@@ -0,0 +1,251 @@
1
+ import numpy as np
2
+ from tqdm import tqdm
3
+
4
+ from spglib import get_symmetry_dataset
5
+ from ions import Percolator, Edge
6
+
7
+ from .core import Grid
8
+ from ._neighborhood import nn_list
9
+ from ._distortion import rattle_positions, distort_lattice
10
+
11
+
12
+
13
+ class DefectGenerator:
14
+
15
+ def __init__(
16
+ self,
17
+ atoms,
18
+ specie: int,
19
+ resolution: float = 0.25,
20
+ r_cut: float = 6.0,
21
+ r_min: float = 1.0,
22
+ symprec: float | None = 0.1,
23
+ max_sep_dist: float | str = 'auto',
24
+ upper_bound: float = 6.0,
25
+ verbose: bool = False,
26
+ seed: int | np.random.Generator | None = None,
27
+ ):
28
+ if specie is None:
29
+ raise ValueError("specie is required (atomic number of the mobile species)")
30
+
31
+ self.atoms = atoms.copy()
32
+ self.specie = specie
33
+ self.resolution = resolution
34
+ self.r_cut = r_cut
35
+ self.r_min = r_min
36
+ self.symprec = symprec
37
+ self.max_sep_dist = max_sep_dist
38
+ self.verbose = verbose
39
+ self.upper_bound = upper_bound
40
+ self._specie_symbol = atoms[atoms.numbers == specie].symbols[0]
41
+ self.rng = np.random.default_rng(seed)
42
+ self._percolator = None # placeholder
43
+ self._mincut_maxdim = None # placeholder
44
+
45
+
46
+ def _make_grid(self, atoms):
47
+ grid = Grid(
48
+ atoms,
49
+ specie=self.specie,
50
+ resolution=self.resolution,
51
+ symprec=self.symprec,
52
+ empty_framework=False,
53
+ r_cut=self.r_cut,
54
+ r_min=self.r_min,
55
+ verbose=self.verbose,
56
+ )
57
+ grid.generate_mesh()
58
+ return grid
59
+
60
+ @staticmethod
61
+ def _valid_positions(mesh_pos, framework, r_min):
62
+ """Filter candidate positions using the actual framework."""
63
+ if r_min <= 0:
64
+ return mesh_pos
65
+
66
+ distances, _ = nn_list(framework.positions, mesh_pos, r_cut=r_min, cell=framework.cell)
67
+
68
+ return mesh_pos[distances >= r_min]
69
+
70
+
71
+ @staticmethod
72
+ def _remove_atoms(atoms, indices):
73
+ mask = np.ones(len(atoms), dtype=bool)
74
+ mask[indices] = False
75
+ return atoms[mask].copy()
76
+
77
+
78
+ @staticmethod
79
+ def _filter_by_distance(mesh_pos, center, r_cut, cell):
80
+ """Keep points within cutoff of center."""
81
+ distances, _ = nn_list(center.reshape(1, 3), mesh_pos, r_cut=r_cut, cell=cell)
82
+ return mesh_pos[distances <= r_cut]
83
+
84
+
85
+ def _get_percolator(self):
86
+ """Note: bottleneck_radius is hardcoded to 0.0 here."""
87
+ if self._percolator is None:
88
+ pl = Percolator(self.atoms, mobile_specie=self._specie_symbol, upper_bound=self.upper_bound)
89
+ mincut, maxdim = pl.mincut_maxdim(bottleneck_radius=0.0)
90
+ self._percolator = pl
91
+ self._mincut_maxdim = (mincut, maxdim)
92
+ return (self._percolator, *self._mincut_maxdim)
93
+
94
+
95
+ def _prepare_site(self, atoms, base, remove_ids, center, max_sep):
96
+ grid = self._make_grid(self._remove_atoms(atoms, remove_ids))
97
+ ir_mesh_cart = grid.mesh_cart[grid.ir_grid_points]
98
+ filtered_pos = ir_mesh_cart[grid.min_dists >= grid.r_min]
99
+ filtered_pos = self._filter_by_distance(filtered_pos, center, max_sep, atoms.cell)
100
+
101
+ # filtering due to the lower defect concentration in a supercell
102
+ defect_base = self._remove_atoms(base, remove_ids)
103
+
104
+ filtered_pos = self._valid_positions(
105
+ filtered_pos,
106
+ defect_base[defect_base.numbers == self.specie],
107
+ self.r_min,
108
+ )
109
+
110
+ return filtered_pos, defect_base
111
+
112
+
113
+ def _prepare_interstitials(self):
114
+
115
+ atoms = self.atoms.copy()
116
+ grid = self._make_grid(atoms)
117
+ base = grid._repeat_atoms(atoms, grid.r_cut)
118
+ ir_mesh_cart = grid.mesh_cart[grid.ir_grid_points]
119
+ filtered_pos = ir_mesh_cart[grid.min_dists >= grid.r_min]
120
+ return [(filtered_pos, base)]
121
+
122
+
123
+
124
+ def _prepare_vacancies(self):
125
+
126
+ atoms = self.atoms.copy()
127
+ pl, mincut, maxdim = self._get_percolator()
128
+ edges = pl.unique_edges(cutoff=mincut, bottleneck_radius=0.0)
129
+
130
+ base = Grid._repeat_atoms(atoms, self.r_cut)
131
+
132
+ sites_and_base = []
133
+ for edge_data in edges:
134
+
135
+ source, target, offset = (edge_data[0], edge_data[1], edge_data[2:])
136
+ scale = (atoms.cell.cellpar()[:3] / base.cell.cellpar()[:3])
137
+ edge = Edge(base, source, target, offset * scale)
138
+
139
+ local_max_sep = self.max_sep_dist
140
+ if local_max_sep == "auto":
141
+ local_max_sep = edge.length / 2 + self.resolution
142
+
143
+ filtered_pos, defect_base = self._prepare_site(
144
+ atoms, base, [source, target], edge.centroid, local_max_sep
145
+ )
146
+ sites_and_base.append((filtered_pos, defect_base))
147
+
148
+ return sites_and_base
149
+
150
+
151
+
152
+ def _prepare_frenkels(self):
153
+
154
+ atoms = self.atoms.copy()
155
+
156
+ equivalent_atoms = np.arange(len(atoms))
157
+ if self.symprec is not None:
158
+ dataset = get_symmetry_dataset(
159
+ (
160
+ atoms.cell,
161
+ atoms.get_scaled_positions(),
162
+ atoms.numbers,
163
+ ),
164
+ symprec=self.symprec,
165
+ )
166
+ equivalent_atoms = dataset.equivalent_atoms
167
+
168
+ ineq_sites = np.unique(equivalent_atoms)
169
+ vac_ids = ineq_sites[atoms.numbers[ineq_sites] == self.specie]
170
+
171
+ if self.max_sep_dist == "auto":
172
+ _, mincut, _ = self._get_percolator()
173
+ global_max_sep = mincut
174
+ else:
175
+ global_max_sep = self.max_sep_dist
176
+
177
+ base = Grid._repeat_atoms(atoms, self.r_cut)
178
+
179
+ sites_and_base = []
180
+ for vac_id in vac_ids:
181
+ filtered_pos, defect_base = self._prepare_site(
182
+ atoms, base, [vac_id], atoms.positions[vac_id], global_max_sep
183
+ )
184
+ sites_and_base.append((filtered_pos, defect_base))
185
+ return sites_and_base
186
+
187
+
188
+ @staticmethod
189
+ def _statistics(sites_and_base):
190
+ summary = {
191
+ 'points': sum([d[0].shape[0] for d in sites_and_base]),
192
+ 'bases': len(sites_and_base),
193
+ }
194
+ return summary
195
+
196
+
197
+ def _append_configurations(self, base, mesh_pos, pos_std=None, strain_std=None, verbose=False):
198
+ """Construct configurations"""
199
+ configs = []
200
+
201
+ for p in tqdm(mesh_pos, desc="creating configurations", disable=not verbose):
202
+ framework = base.copy()
203
+
204
+ if pos_std is not None:
205
+ framework = rattle_positions(framework, std=pos_std, rng=self.rng) # rng added
206
+
207
+ framework.append(self.specie)
208
+ framework.positions[-1] = p
209
+
210
+ if strain_std is not None:
211
+ framework = distort_lattice(framework, std=strain_std, rng=self.rng) # rng added
212
+
213
+ configs.append(framework)
214
+
215
+ return configs
216
+
217
+
218
+ def generate_dataset(
219
+ self,
220
+ defect_type: str,
221
+ pos_std: float | None = None,
222
+ strain_std: float | None = None,
223
+ verbose: bool = False,
224
+ dry_run: bool = False,
225
+ ):
226
+ if defect_type == 'int':
227
+ sites_and_base = self._prepare_interstitials()
228
+ elif defect_type == 'vac':
229
+ sites_and_base = self._prepare_vacancies()
230
+ elif defect_type == 'frenkel':
231
+ sites_and_base = self._prepare_frenkels()
232
+ else:
233
+ raise ValueError(
234
+ f"defect_type must be 'int', 'vac', or 'frenkel', got {defect_type!r}"
235
+ )
236
+
237
+ if dry_run:
238
+ return self._statistics(sites_and_base)
239
+
240
+ cfgs = []
241
+ for (mesh_pos, base) in sites_and_base:
242
+ cfgs.extend(
243
+ self._append_configurations(
244
+ base,
245
+ mesh_pos,
246
+ pos_std=pos_std,
247
+ strain_std=strain_std,
248
+ verbose=verbose,
249
+ )
250
+ )
251
+ return cfgs
@@ -123,7 +123,6 @@ class Mesh:
123
123
  npoints = len(self.mesh)
124
124
  nsym = len(self.rotations)
125
125
 
126
- lin_indices = self._index_to_linear(self.mesh)
127
126
  index_map = np.arange(npoints, dtype=int)
128
127
 
129
128
  all_images = self._apply_sym_ops()
@@ -3,32 +3,27 @@ import numpy as np
3
3
  from scipy.spatial import cKDTree
4
4
 
5
5
 
6
+ def nn_list(atoms_pos, mesh_pos, r_cut, cell=None):
6
7
 
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
8
  if np.any(cell):
19
- scale = _scale_cell(cell, r_cut)
9
+ volume = np.linalg.det(cell)
10
+ h1 = volume/np.linalg.norm(np.cross(cell[2, :], cell[1, :]))
11
+ h2 = volume/np.linalg.norm(np.cross(cell[0, :], cell[2, :]))
12
+ h3 = volume/np.linalg.norm(np.cross(cell[0, :], cell[1, :]))
13
+ scale = 2 * np.array(np.ceil(r_cut/np.array([h1, h2, h3])), dtype=int) + 1
20
14
  scales = []
21
15
  for s in scale:
22
16
  scales.append(np.arange(-(s // 2), s // 2 + 1))
17
+
23
18
  translations = tuple(list(itertools.product(
24
19
  scales[0],
25
20
  scales[1],
26
21
  scales[2])))
27
22
 
28
- buffer = (atoms_pos[:, None, :] + np.dot(translations, cell)).reshape(-1, 3, order = 'F')
23
+ buffer = (atoms_pos[:, None, :] + np.dot(translations, cell)).reshape(-1, 3, order='F')
29
24
  else:
30
25
  buffer = atoms_pos
31
26
 
32
27
  tree = cKDTree(buffer)
33
- distances, indexes = tree.query(mesh_pos, workers=-1, k=1, distance_upper_bound = r_cut)
28
+ distances, indexes = tree.query(mesh_pos, workers=-1, k=1, distance_upper_bound=r_cut)
34
29
  return distances, indexes
@@ -167,7 +167,7 @@ class Percolyze:
167
167
 
168
168
 
169
169
 
170
- def _percolation_energy(self, dim, encut = 10.0):
170
+ def _percolation_energy(self, dim, upper_limit=10.0):
171
171
 
172
172
  """
173
173
  Get percolation energy fofr a given dimensionality of percolation
@@ -178,7 +178,7 @@ class Percolyze:
178
178
  dim: int
179
179
  dimensionality of percolation. 2 -> 1D, 4 -> 2D, 8 - 3D percolation
180
180
 
181
- encut: float, 10.0 by default
181
+ upper_limit: float, 10.0 by default
182
182
  stop criterion for the search of percolation energy
183
183
 
184
184
  Returns
@@ -190,7 +190,7 @@ class Percolyze:
190
190
  data = self.data.reshape(self.size)
191
191
  data = data - data.min()
192
192
  emin = data.min()
193
- emax = emin + encut
193
+ emax = emin + upper_limit
194
194
  count = 0
195
195
  barrier = np.inf
196
196
  while (emax - emin) > 0.01:
@@ -210,7 +210,7 @@ class Percolyze:
210
210
 
211
211
 
212
212
 
213
- def percolation_barriers(self, encut = 10.0, n_jobs = 1, backend = 'threading'):
213
+ def percolation_barriers(self, upper_limit=10.0, n_jobs=1, backend='threading'):
214
214
 
215
215
  """
216
216
  Find percolation energy and dimensionality of a migration network.
@@ -218,7 +218,7 @@ class Percolyze:
218
218
  Parameters
219
219
  ----------
220
220
 
221
- encut: float, 5.0 by default
221
+ upper_limit: float, 5.0 by default
222
222
  cutoff energy above which barriers supposed to be np.inf
223
223
 
224
224
  n_jobs: int, 1 by default
@@ -231,7 +231,7 @@ class Percolyze:
231
231
  ----------
232
232
 
233
233
  energies: dict
234
- infromation about percolation {'E_1D': float, 'E_2D': float, 'E_3D': float}
234
+ infromation about percolation {'e1d': float, 'e2d': float, 'e3d': float}
235
235
 
236
236
  """
237
237
 
@@ -241,7 +241,7 @@ class Percolyze:
241
241
  energies = {}
242
242
  for i, dim in enumerate([2, 4, 8]):
243
243
 
244
- energy = self._percolation_energy(encut = encut, dim = dim)
245
- energies.update({f'E_{i+1}D': energy})
244
+ energy = self._percolation_energy(upper_limit = upper_limit, dim = dim)
245
+ energies.update({f'e{i+1}d': energy})
246
246
  return energies
247
247
 
@@ -0,0 +1 @@
1
+ __version__ = "0.2.3"