gridmlip 0.2.3__tar.gz → 0.2.5__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 (36) hide show
  1. {gridmlip-0.2.3/gridmlip.egg-info → gridmlip-0.2.5}/PKG-INFO +54 -1
  2. {gridmlip-0.2.3 → gridmlip-0.2.5}/README.md +53 -0
  3. gridmlip-0.2.5/gridmlip/_neighborhood.py +77 -0
  4. gridmlip-0.2.5/gridmlip/_version.py +1 -0
  5. gridmlip-0.2.5/gridmlip/_void_search.py +114 -0
  6. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/core.py +6 -1
  7. gridmlip-0.2.5/gridmlip/integrations/bvse.py +142 -0
  8. gridmlip-0.2.5/gridmlip/select.py +1 -0
  9. {gridmlip-0.2.3 → gridmlip-0.2.5/gridmlip.egg-info}/PKG-INFO +54 -1
  10. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip.egg-info/SOURCES.txt +3 -0
  11. {gridmlip-0.2.3 → gridmlip-0.2.5}/scripts/_void_search.py +20 -4
  12. gridmlip-0.2.3/gridmlip/_neighborhood.py +0 -29
  13. gridmlip-0.2.3/gridmlip/_version.py +0 -1
  14. {gridmlip-0.2.3 → gridmlip-0.2.5}/LICENSE +0 -0
  15. {gridmlip-0.2.3 → gridmlip-0.2.5}/MANIFEST.in +0 -0
  16. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/__init__.py +0 -0
  17. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/_distortion.py +0 -0
  18. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/_generate.py +0 -0
  19. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/_mesh.py +0 -0
  20. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/_percolation_analysis.py +0 -0
  21. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/cli.py +0 -0
  22. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/integrations/__init__.py +0 -0
  23. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/integrations/gnn_lib.py +0 -0
  24. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/integrations/mace.py +0 -0
  25. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/integrations/sevennet.py +0 -0
  26. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip/utils.py +0 -0
  27. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip.egg-info/dependency_links.txt +0 -0
  28. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip.egg-info/requires.txt +0 -0
  29. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip.egg-info/top_level.txt +0 -0
  30. {gridmlip-0.2.3 → gridmlip-0.2.5}/gridmlip.egg-info/zip-safe +0 -0
  31. {gridmlip-0.2.3 → gridmlip-0.2.5}/pyproject.toml +0 -0
  32. {gridmlip-0.2.3 → gridmlip-0.2.5}/scripts/__init__.py +0 -0
  33. {gridmlip-0.2.3 → gridmlip-0.2.5}/scripts/_nebtools.py +0 -0
  34. {gridmlip-0.2.3 → gridmlip-0.2.5}/scripts/estimate_bvel13k_dataset_size.py +0 -0
  35. {gridmlip-0.2.3 → gridmlip-0.2.5}/setup.cfg +0 -0
  36. {gridmlip-0.2.3 → gridmlip-0.2.5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gridmlip
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: gridmlip
5
5
  Home-page: https://github.com/dembart/gridmlip
6
6
  Author: Artem Dembitskiy
@@ -118,6 +118,59 @@ cfgs_vac= gen.generate_dataset(defect_type='vac')
118
118
  cfgs_frk = gen.generate_dataset(defect_type='frenkel')
119
119
  ```
120
120
 
121
+ ### Find voids
122
+
123
+ ```python
124
+ from ase.io import read
125
+ from gridmlip._void_search import clustered_local_minima
126
+
127
+ atoms = read('file.cif')
128
+
129
+ g = Grid(atoms, specie=3, empty_framework=False)
130
+ g.generate_mesh()
131
+
132
+ clusters = clustered_local_minima(
133
+ -g.min_distances_data, # can be any data computed for the generated grid
134
+ min_distance=2.0,
135
+ relative_max_value=0.5,
136
+ cell=g.atoms.cell,
137
+ coord_type='cart'
138
+ )
139
+
140
+ for (pos, energy, n) in clusters:
141
+ print('Site', pos)
142
+ print('Site energy', energy) # here, energy is the minimal distances
143
+ print('Number of points in a cluster', n)
144
+
145
+ ```
146
+
147
+ ### Bond valence site energy calculations
148
+
149
+ ```python
150
+ from ase.io import read
151
+ from ions.decorate import assign_oxidation_states
152
+ from gridmlip.integrations.bvse import bvse_distribution
153
+
154
+ atoms = read('LiFePO4.cif')
155
+ atoms = assign_oxidation_states(atoms)
156
+
157
+ PARAMS = {
158
+ "mobile_ion": "Li+",
159
+ "resolution": 0.2,
160
+ "r_min": 0.8,
161
+ "r_cut": 10.0,
162
+ "empty_framework": True,
163
+ "k": 100,
164
+ "f": 0.74,
165
+ }
166
+
167
+ grid, energies = bvse_distribution(atoms, **PARAMS)
168
+ grid.percolation_barriers() # energies already loaded via grid.load_energies(energies)
169
+
170
+ ```
171
+
172
+
173
+
121
174
  ## Notebooks
122
175
 
123
176
 
@@ -99,6 +99,59 @@ cfgs_vac= gen.generate_dataset(defect_type='vac')
99
99
  cfgs_frk = gen.generate_dataset(defect_type='frenkel')
100
100
  ```
101
101
 
102
+ ### Find voids
103
+
104
+ ```python
105
+ from ase.io import read
106
+ from gridmlip._void_search import clustered_local_minima
107
+
108
+ atoms = read('file.cif')
109
+
110
+ g = Grid(atoms, specie=3, empty_framework=False)
111
+ g.generate_mesh()
112
+
113
+ clusters = clustered_local_minima(
114
+ -g.min_distances_data, # can be any data computed for the generated grid
115
+ min_distance=2.0,
116
+ relative_max_value=0.5,
117
+ cell=g.atoms.cell,
118
+ coord_type='cart'
119
+ )
120
+
121
+ for (pos, energy, n) in clusters:
122
+ print('Site', pos)
123
+ print('Site energy', energy) # here, energy is the minimal distances
124
+ print('Number of points in a cluster', n)
125
+
126
+ ```
127
+
128
+ ### Bond valence site energy calculations
129
+
130
+ ```python
131
+ from ase.io import read
132
+ from ions.decorate import assign_oxidation_states
133
+ from gridmlip.integrations.bvse import bvse_distribution
134
+
135
+ atoms = read('LiFePO4.cif')
136
+ atoms = assign_oxidation_states(atoms)
137
+
138
+ PARAMS = {
139
+ "mobile_ion": "Li+",
140
+ "resolution": 0.2,
141
+ "r_min": 0.8,
142
+ "r_cut": 10.0,
143
+ "empty_framework": True,
144
+ "k": 100,
145
+ "f": 0.74,
146
+ }
147
+
148
+ grid, energies = bvse_distribution(atoms, **PARAMS)
149
+ grid.percolation_barriers() # energies already loaded via grid.load_energies(energies)
150
+
151
+ ```
152
+
153
+
154
+
102
155
  ## Notebooks
103
156
 
104
157
 
@@ -0,0 +1,77 @@
1
+ import itertools
2
+ import numpy as np
3
+ from scipy.spatial import cKDTree
4
+
5
+
6
+ def nn_list(atoms_pos, mesh_pos, r_cut, cell=None, k=1, return_orig_ids=False):
7
+ """
8
+ k nearest neighbors for each query point in `mesh_pos`.
9
+
10
+ Parameters
11
+ ----------
12
+ atoms_pos : (N, 3) ndarray
13
+ Atom positions.
14
+
15
+ mesh_pos : (M, 3) ndarray
16
+ Query points.
17
+
18
+ r_cut : float
19
+ Cutoff
20
+
21
+ cell : (3, 3) ndarray or None
22
+ Periodic cell. If given, periodic images within `r_cut` are added.
23
+
24
+ k : int
25
+ Number of neighbors.
26
+
27
+ Returns
28
+ -------
29
+ distances : (M, k) ndarray
30
+ Distances. `inf` where no neighbor was found within `r_cut`.
31
+
32
+ indexes : (M, k) ndarray
33
+ Indices into the buffered array
34
+
35
+ orig_indexes : (M, k) ndarray
36
+ Indices into the original `atoms_pos`
37
+ """
38
+ atoms_pos = np.asarray(atoms_pos)
39
+ n_atoms = len(atoms_pos)
40
+
41
+ if cell is not None and np.any(cell):
42
+ cell = np.asarray(cell)
43
+ volume = np.linalg.det(cell)
44
+ h1 = volume / np.linalg.norm(np.cross(cell[2, :], cell[1, :]))
45
+ h2 = volume / np.linalg.norm(np.cross(cell[0, :], cell[2, :]))
46
+ h3 = volume / np.linalg.norm(np.cross(cell[0, :], cell[1, :]))
47
+ scale = 2 * np.array(np.ceil(r_cut / np.array([h1, h2, h3])), dtype=int) + 1
48
+ scales = [np.arange(-(s // 2), s // 2 + 1) for s in scale]
49
+
50
+ translations = np.array(list(itertools.product(*scales))) # (T, 3)
51
+ n_trans = len(translations)
52
+
53
+ # (n_atoms, n_trans, 3) -> (n_atoms * n_trans, 3), C-order:
54
+ # buffer row k = i * n_trans + t
55
+ buffer = (atoms_pos[:, None, :] + translations @ cell).reshape(-1, 3)
56
+
57
+ # Consistent with the C-order reshape above.
58
+ buffer_to_orig = np.repeat(np.arange(n_atoms), n_trans)
59
+ else:
60
+ buffer = atoms_pos
61
+ buffer_to_orig = np.arange(n_atoms)
62
+
63
+ tree = cKDTree(buffer)
64
+ distances, indexes = tree.query(
65
+ mesh_pos, workers=-1, k=k, distance_upper_bound=r_cut
66
+ )
67
+
68
+ if not return_orig_ids:
69
+ return distances, indexes
70
+
71
+ # cKDTree returns len(buffer) for "not found". Map valid entries back
72
+ # to original atom indices; leave "not found" as -1.
73
+ orig_indexes = np.full_like(indexes, -1)
74
+ valid = indexes < len(buffer)
75
+ orig_indexes[valid] = buffer_to_orig[indexes[valid]]
76
+
77
+ return distances, indexes, orig_indexes
@@ -0,0 +1 @@
1
+ __version__ = "0.2.5"
@@ -0,0 +1,114 @@
1
+ import numpy as np
2
+ from scipy import ndimage
3
+ from scipy.spatial import cKDTree
4
+ from ase.cell import Cell
5
+
6
+
7
+ def _find_local_minima(distribution, size=3):
8
+ E = distribution[:-1, :-1, :-1]
9
+ minf = ndimage.minimum_filter(E, size=size, mode='wrap')
10
+ mask = E == minf
11
+
12
+ padded = np.pad(mask, 1, mode='wrap')
13
+ labeled, _ = ndimage.label(padded, structure=np.ones((3, 3, 3), bool))
14
+ labeled = labeled[1:-1, 1:-1, 1:-1]
15
+
16
+ labels = np.unique(labeled)
17
+ labels = labels[labels != 0]
18
+ idx = np.array([np.argwhere(labeled == l)[0] for l in labels])
19
+ val = E[tuple(idx.T)]
20
+ return idx, val
21
+
22
+
23
+ def _cluster_minima(idx, val, shape, cell, min_distance, max_value=None):
24
+ if max_value is not None:
25
+ m = val < max_value
26
+ idx, val = idx[m], val[m]
27
+
28
+ cell = np.asarray(cell, dtype=float)
29
+ frac = idx / np.array(shape, dtype=float)
30
+ cart = frac @ cell
31
+
32
+ shifts = np.array(np.meshgrid([-1, 0, 1], [-1, 0, 1], [-1, 0, 1], indexing='ij')).reshape(3, -1).T
33
+ n = len(idx)
34
+ rep_cart = ((shifts[:, None, :] + frac[None, :, :]).reshape(-1, 3)) @ cell
35
+ owner = np.tile(np.arange(n), len(shifts))
36
+ tree = cKDTree(rep_cart)
37
+
38
+ order = np.argsort(val)
39
+ alive = np.ones(n, bool)
40
+
41
+ clusters = []
42
+ for i in order:
43
+ if not alive[i]:
44
+ continue
45
+ neighbors = np.unique(owner[tree.query_ball_point(cart[i], min_distance)])
46
+ clusters.append((idx[i], val[i], len(neighbors)))
47
+ for j in neighbors:
48
+ alive[j] = False
49
+
50
+ return clusters
51
+
52
+
53
+ def clustered_local_minima(
54
+ data: np.ndarray,
55
+ min_distance: float,
56
+ relative_max_value: float,
57
+ cell: np.ndarray,
58
+ coord_type : str = 'cart',
59
+ ):
60
+ """
61
+ Find local minima for calculated data on a grid.
62
+
63
+ Parameters
64
+ ----------
65
+ data : np.ndarray of shape (N, M, K)
66
+ data calculated for the generated grid
67
+
68
+ min_distance : float
69
+ minimal distance between voids
70
+
71
+ relative_max_value : float
72
+ relative maximum value of the data to search for minima
73
+ `data.min() + relative_max_value`
74
+
75
+ cell : np.ndarray of size (3,3)
76
+ lattice matrix
77
+
78
+ coord_type : str, "cart" by default
79
+ in what format minima coordinates will be return
80
+ allowed values are "cart", "frac", mesh"
81
+ "cart" - cartesian coordinates
82
+ "frac" - fractional coordinates
83
+ "mesh" - mesh posititions
84
+
85
+ Returns
86
+ -------
87
+ clusters : list of lists,
88
+ each list contains position of a minimum,
89
+ energy value, and number of points clustered
90
+
91
+ """
92
+ assert coord_type in ("cart", "frac", "mesh")
93
+
94
+ idx, val = _find_local_minima(data)
95
+ core_shape = tuple(s - 1 for s in data.shape)
96
+ clusters = _cluster_minima(idx, val, core_shape,
97
+ min_distance=min_distance,
98
+ max_value=data.min() + relative_max_value,
99
+ cell=cell,
100
+ )
101
+
102
+ if coord_type == "mesh":
103
+ return clusters
104
+ else:
105
+ cell_ase = Cell(cell)
106
+ clusters_new = []
107
+ for i, v, n in clusters:
108
+ scaled_site = i/(np.array(data.shape) - 1)
109
+ if coord_type == "cart":
110
+ cart_site = cell_ase.cartesian_positions(scaled_site)
111
+ clusters_new.append([cart_site, v, n])
112
+ else:
113
+ clusters_new.append([scaled_site, v, n])
114
+ return clusters_new
@@ -132,7 +132,12 @@ class Grid:
132
132
  h3 = cell.volume/np.linalg.norm(np.cross(cell[0, :], cell[1, :]))
133
133
  scale = np.array(np.ceil(r_cut/np.array([h1, h2, h3])), dtype=int)
134
134
  return atoms.repeat(scale)
135
-
135
+
136
+ @property
137
+ def min_distances_data(self):
138
+ return self.min_dists[self.mapping].reshape(self.mesh_shape)
139
+
140
+
136
141
  @classmethod
137
142
  def from_file(
138
143
  cls,
@@ -0,0 +1,142 @@
1
+ import re
2
+ import numpy as np
3
+
4
+ from ase.data import covalent_radii, atomic_numbers
5
+ from ions.data import principle_number
6
+ from ions.decorate import assign_bvse_params, assign_oxidation_states
7
+ from ions.calculators.potential import BVFF
8
+
9
+ from ..core import Grid
10
+ from .._neighborhood import nn_list
11
+
12
+
13
+
14
+ def _decompose(mobile_ion):
15
+
16
+ """ Decompose input string into chemical element and oxidation state"""
17
+
18
+ element = re.sub('\d', '', mobile_ion).replace("+","").replace("-","")
19
+ oxi_state = re.sub('\D', '', mobile_ion)
20
+
21
+ if '-' in mobile_ion:
22
+ sign = -1
23
+ else:
24
+ sign = 1
25
+ if len(oxi_state) > 0:
26
+ if sign > 0:
27
+ oxi_state = float(oxi_state)
28
+ else:
29
+ oxi_state = -float(oxi_state)
30
+ else:
31
+ oxi_state = sign
32
+
33
+ return element, atomic_numbers[element], int(oxi_state)
34
+
35
+
36
+ def _get_array(atoms, name):
37
+ """ Helper function"""
38
+ arr = atoms.get_array(name)
39
+ arr = np.concatenate([arr, [np.nan]]) # np.nan is added to deal with kDTree upper bound
40
+ return arr
41
+
42
+
43
+
44
+ def bvse_distribution(
45
+ atoms: object,
46
+ mobile_ion: str = None,
47
+ resolution: float = 0.25,
48
+ r_cut: float = 10.0,
49
+ r_min: float = 0.8,
50
+ empty_framework: bool = True,
51
+ k: int = 100,
52
+ f: float = 0.74,
53
+ verbose: bool = False,
54
+ ):
55
+
56
+ """
57
+ Compute the bond valence site energy (BVSE) distribution for a mobile ion.
58
+
59
+ Parameters
60
+ ----------
61
+ atoms : ase.Atoms
62
+ Structure containing the framework and mobile-ion species.
63
+
64
+ mobile_ion : str
65
+ Chemical symbol of the mobile ion (e.g., "Li", "Na").
66
+
67
+ resolution : float
68
+ Grid spacing in Å for the energy landscape. Default 0.25.
69
+
70
+ r_cut : float
71
+ Cutoff radius in Å for bond-valence interactions. Default 10.0.
72
+
73
+ r_min : float
74
+ Minimum interatomic distance in Å. Default 0.8.
75
+
76
+ empty_framework : bool
77
+ If True, remove mobile ions before computing the landscape. Default True.
78
+
79
+ k : int
80
+ Number of bins / grid points along each axis. Default 100.
81
+
82
+ f : float
83
+ Screening factor (e.g., for the BVSE prefactor). Default 0.74.
84
+
85
+ verbose : bool
86
+ print out some info
87
+
88
+ Returns
89
+ -------
90
+ gridmlip.Grid, energies
91
+ grid with generated mesh and an array of calculated energies for irreducible mesh points
92
+ """
93
+
94
+ symbol, specie, q1 = _decompose(mobile_ion)
95
+ n1, rc1 = principle_number[specie], covalent_radii[specie]
96
+
97
+ atoms_decorated = assign_bvse_params(atoms, symbol, q1, self_interaction=True)
98
+ base = atoms_decorated.copy()
99
+
100
+ if empty_framework:
101
+ base = atoms_decorated[atoms_decorated.numbers != specie]
102
+
103
+ grid = Grid(atoms, specie=specie, resolution=resolution,
104
+ r_cut=r_cut, r_min=r_min, empty_framework=empty_framework,
105
+ verbose=verbose)
106
+ grid.generate_mesh()
107
+ mesh_cart = grid.mesh_cart[grid.ir_grid_points]
108
+ mesh_cart = mesh_cart[grid.min_dists > grid.r_min]
109
+
110
+ distances, _, ids = nn_list(base.positions, mesh_cart, r_cut=r_cut,
111
+ cell=base.cell, k=k, return_orig_ids=True)
112
+
113
+ r_min = np.take(_get_array(base, 'r_min'), ids, axis = -1)
114
+ alpha = np.take(_get_array(base, 'alpha'), ids, axis = -1)
115
+ rc2 = np.take(_get_array(base, 'rc2'), ids, axis = -1)
116
+ d0 = np.take(_get_array(base, 'd0'), ids, axis = -1)
117
+ q2 = np.take(_get_array(base, 'oxi_states'), ids, axis = -1)
118
+ q2 = np.where(q2 * q1 > 0, q2, 0)
119
+ n2 = np.take(_get_array(base, 'n2'), ids, axis = -1)
120
+
121
+ morse = np.nan_to_num(BVFF.Morse(distances, r_min, d0, alpha),
122
+ copy=False,
123
+ nan=0.0,
124
+ ).sum(axis=1)
125
+
126
+ coulomb = np.nan_to_num(BVFF.Coulomb(
127
+ q1,
128
+ q2,
129
+ distances,
130
+ rc1,
131
+ rc2,
132
+ n1,
133
+ n2,
134
+ f=f),
135
+ copy=False,
136
+ nan=0.0,
137
+ ).sum(axis=1)
138
+
139
+ energies = morse + coulomb
140
+ grid.load_energies(energies)
141
+
142
+ return grid, energies
@@ -0,0 +1 @@
1
+ # FPS sampling with/without relative distance
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gridmlip
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: gridmlip
5
5
  Home-page: https://github.com/dembart/gridmlip
6
6
  Author: Artem Dembitskiy
@@ -118,6 +118,59 @@ cfgs_vac= gen.generate_dataset(defect_type='vac')
118
118
  cfgs_frk = gen.generate_dataset(defect_type='frenkel')
119
119
  ```
120
120
 
121
+ ### Find voids
122
+
123
+ ```python
124
+ from ase.io import read
125
+ from gridmlip._void_search import clustered_local_minima
126
+
127
+ atoms = read('file.cif')
128
+
129
+ g = Grid(atoms, specie=3, empty_framework=False)
130
+ g.generate_mesh()
131
+
132
+ clusters = clustered_local_minima(
133
+ -g.min_distances_data, # can be any data computed for the generated grid
134
+ min_distance=2.0,
135
+ relative_max_value=0.5,
136
+ cell=g.atoms.cell,
137
+ coord_type='cart'
138
+ )
139
+
140
+ for (pos, energy, n) in clusters:
141
+ print('Site', pos)
142
+ print('Site energy', energy) # here, energy is the minimal distances
143
+ print('Number of points in a cluster', n)
144
+
145
+ ```
146
+
147
+ ### Bond valence site energy calculations
148
+
149
+ ```python
150
+ from ase.io import read
151
+ from ions.decorate import assign_oxidation_states
152
+ from gridmlip.integrations.bvse import bvse_distribution
153
+
154
+ atoms = read('LiFePO4.cif')
155
+ atoms = assign_oxidation_states(atoms)
156
+
157
+ PARAMS = {
158
+ "mobile_ion": "Li+",
159
+ "resolution": 0.2,
160
+ "r_min": 0.8,
161
+ "r_cut": 10.0,
162
+ "empty_framework": True,
163
+ "k": 100,
164
+ "f": 0.74,
165
+ }
166
+
167
+ grid, energies = bvse_distribution(atoms, **PARAMS)
168
+ grid.percolation_barriers() # energies already loaded via grid.load_energies(energies)
169
+
170
+ ```
171
+
172
+
173
+
121
174
  ## Notebooks
122
175
 
123
176
 
@@ -11,8 +11,10 @@ gridmlip/_mesh.py
11
11
  gridmlip/_neighborhood.py
12
12
  gridmlip/_percolation_analysis.py
13
13
  gridmlip/_version.py
14
+ gridmlip/_void_search.py
14
15
  gridmlip/cli.py
15
16
  gridmlip/core.py
17
+ gridmlip/select.py
16
18
  gridmlip/utils.py
17
19
  gridmlip.egg-info/PKG-INFO
18
20
  gridmlip.egg-info/SOURCES.txt
@@ -21,6 +23,7 @@ gridmlip.egg-info/requires.txt
21
23
  gridmlip.egg-info/top_level.txt
22
24
  gridmlip.egg-info/zip-safe
23
25
  gridmlip/integrations/__init__.py
26
+ gridmlip/integrations/bvse.py
24
27
  gridmlip/integrations/gnn_lib.py
25
28
  gridmlip/integrations/mace.py
26
29
  gridmlip/integrations/sevennet.py
@@ -3,7 +3,7 @@ from scipy import ndimage
3
3
  from scipy.spatial import cKDTree
4
4
 
5
5
 
6
- def find_local_minima(distribution, size=3):
6
+ def _find_local_minima(distribution, size=3):
7
7
  E = distribution[:-1, :-1, :-1]
8
8
  minf = ndimage.minimum_filter(E, size=size, mode='wrap')
9
9
  mask = E == minf
@@ -19,7 +19,7 @@ def find_local_minima(distribution, size=3):
19
19
  return idx, val
20
20
 
21
21
 
22
- def cluster_minima(idx, val, shape, cell, min_distance, max_value=None):
22
+ def _cluster_minima(idx, val, shape, cell, min_distance, max_value=None):
23
23
  if max_value is not None:
24
24
  m = val < max_value
25
25
  idx, val = idx[m], val[m]
@@ -50,9 +50,25 @@ def cluster_minima(idx, val, shape, cell, min_distance, max_value=None):
50
50
 
51
51
 
52
52
  def clustered_local_minima(data, min_distance, relative_max_value, cell):
53
- idx, val = find_local_minima(data)
53
+ """
54
+ Find local minima on a calculated grid distribution.
55
+
56
+ Parameters
57
+ ----------
58
+
59
+ data : np.ndarray of shape (N, M, K)
60
+ data calculated for the generated grid
61
+
62
+ min_distance : float
63
+ minimal distance between clusters
64
+
65
+ relative_max_value : float
66
+ relative maximum value of the data to search for minima
67
+ `data.min() + relative_max_value`
68
+ """
69
+ idx, val = _find_local_minima(data)
54
70
  core_shape = tuple(s - 1 for s in data.shape)
55
- clusters = cluster_minima(idx, val, core_shape,
71
+ clusters = _cluster_minima(idx, val, core_shape,
56
72
  min_distance=min_distance,
57
73
  max_value=data.min() + relative_max_value,
58
74
  cell = cell
@@ -1,29 +0,0 @@
1
- import itertools
2
- import numpy as np
3
- from scipy.spatial import cKDTree
4
-
5
-
6
- def nn_list(atoms_pos, mesh_pos, r_cut, cell=None):
7
-
8
- if np.any(cell):
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
14
- scales = []
15
- for s in scale:
16
- scales.append(np.arange(-(s // 2), s // 2 + 1))
17
-
18
- translations = tuple(list(itertools.product(
19
- scales[0],
20
- scales[1],
21
- scales[2])))
22
-
23
- buffer = (atoms_pos[:, None, :] + np.dot(translations, cell)).reshape(-1, 3, order='F')
24
- else:
25
- buffer = atoms_pos
26
-
27
- tree = cKDTree(buffer)
28
- distances, indexes = tree.query(mesh_pos, workers=-1, k=1, distance_upper_bound=r_cut)
29
- return distances, indexes
@@ -1 +0,0 @@
1
- __version__ = "0.2.3"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes