wmaee.utils.geometry

 1import operator
 2import itertools
 3import numpy as np
 4from ase import Atoms
 5from typing import Union, Tuple, Dict, Any
 6
 7from wmaee.core.requirements import test_pmg
 8if test_pmg():
 9    from pymatgen.core import Structure
10    from pymatgen.io.ase import AseAtomsAdaptor
11
12def find_neighbors(atoms: Union[Atoms, Any],
13                   rcut: float = 3.0,
14                   mindist: float = 0.1,
15                   properties: Tuple[str, ...] = ('indices', 'distances', 'images', 'vecs')
16                   ) -> Dict[int, Tuple[np.ndarray, ...]]:
17    """
18    Find neighbors for each atom within a specified cutoff distance and minimum distance.
19    
20    This function applies the minimum image convention to consider periodic boundary conditions.
21
22    Parameters
23    ----------
24    atoms : Union[Atoms, Any]
25        The atoms object to query. It can be an Atoms object or any other compatible type.
26    rcut : float, optional
27        The cutoff distance for neighbor search, by default 3.0.
28    mindist : float, optional
29        The minimum distance for neighbor search, by default 0.1.
30    properties : Tuple[str, ...], optional
31        An iterable of properties to return for each atom. 
32        Available options are 'indices', 'distances', 'images', 'vecs', by default ('indices', 'distances', 'images', 'vecs').
33
34    Returns
35    -------
36    Dict[int, Tuple[np.ndarray, ...]]
37        A dictionary where the keys represent the atom ids, and the values are tuples containing the desired properties.
38        - 'indices': Indices of neighboring atoms.
39        - 'distances': Distances to neighboring atoms.
40        - 'images': Indices of periodic images of neighboring atoms.
41        - 'vecs': Vectors pointing from the central atom to its neighbors.
42    """
43    if test_pmg() and isinstance(atoms, Structure):
44        atoms = AseAtomsAdaptor.get_atoms(atoms)
45
46    a, b, c = atoms.cell
47    stride = len(atoms)
48    image_vector = np.zeros((stride * 27, 3), dtype=float)
49    indices = np.hstack([np.arange(len(atoms))] * 27)
50    image_indices = np.zeros_like(image_vector, dtype=int)
51
52    for i, (ta, tb, tc) in enumerate(itertools.product(*[[-1, 0, 1]] * 3)):
53        start, end = (i * stride), ((i + 1) * stride)
54        image_vector[start:end] = a * ta + b * tb + c * tc
55        image_vector[start:end] += atoms.positions
56        image_indices[start:end] = [ta, tb, tc]
57
58    result = dict()
59    position_vector = np.zeros_like(image_vector)
60
61    for i, pos in enumerate(atoms.positions):
62        position_vector[:] = pos
63        distance_vectors = position_vector - image_vector
64        distances = np.linalg.norm(distance_vectors, axis=1)
65        mask = np.logical_and(distances >= mindist, distances < rcut)
66        result[i] = dict(indices=indices[mask], distances=distances[mask], images=image_indices[mask], vecs=distance_vectors[mask, :])
67
68    mapper = operator.itemgetter(*properties)
69    return {i: mapper(d) for i, d in result.items()}
def find_neighbors( atoms: Union[ase.atoms.Atoms, Any], rcut: float = 3.0, mindist: float = 0.1, properties: Tuple[str, ...] = ('indices', 'distances', 'images', 'vecs')) -> Dict[int, Tuple[numpy.ndarray, ...]]:
13def find_neighbors(atoms: Union[Atoms, Any],
14                   rcut: float = 3.0,
15                   mindist: float = 0.1,
16                   properties: Tuple[str, ...] = ('indices', 'distances', 'images', 'vecs')
17                   ) -> Dict[int, Tuple[np.ndarray, ...]]:
18    """
19    Find neighbors for each atom within a specified cutoff distance and minimum distance.
20    
21    This function applies the minimum image convention to consider periodic boundary conditions.
22
23    Parameters
24    ----------
25    atoms : Union[Atoms, Any]
26        The atoms object to query. It can be an Atoms object or any other compatible type.
27    rcut : float, optional
28        The cutoff distance for neighbor search, by default 3.0.
29    mindist : float, optional
30        The minimum distance for neighbor search, by default 0.1.
31    properties : Tuple[str, ...], optional
32        An iterable of properties to return for each atom. 
33        Available options are 'indices', 'distances', 'images', 'vecs', by default ('indices', 'distances', 'images', 'vecs').
34
35    Returns
36    -------
37    Dict[int, Tuple[np.ndarray, ...]]
38        A dictionary where the keys represent the atom ids, and the values are tuples containing the desired properties.
39        - 'indices': Indices of neighboring atoms.
40        - 'distances': Distances to neighboring atoms.
41        - 'images': Indices of periodic images of neighboring atoms.
42        - 'vecs': Vectors pointing from the central atom to its neighbors.
43    """
44    if test_pmg() and isinstance(atoms, Structure):
45        atoms = AseAtomsAdaptor.get_atoms(atoms)
46
47    a, b, c = atoms.cell
48    stride = len(atoms)
49    image_vector = np.zeros((stride * 27, 3), dtype=float)
50    indices = np.hstack([np.arange(len(atoms))] * 27)
51    image_indices = np.zeros_like(image_vector, dtype=int)
52
53    for i, (ta, tb, tc) in enumerate(itertools.product(*[[-1, 0, 1]] * 3)):
54        start, end = (i * stride), ((i + 1) * stride)
55        image_vector[start:end] = a * ta + b * tb + c * tc
56        image_vector[start:end] += atoms.positions
57        image_indices[start:end] = [ta, tb, tc]
58
59    result = dict()
60    position_vector = np.zeros_like(image_vector)
61
62    for i, pos in enumerate(atoms.positions):
63        position_vector[:] = pos
64        distance_vectors = position_vector - image_vector
65        distances = np.linalg.norm(distance_vectors, axis=1)
66        mask = np.logical_and(distances >= mindist, distances < rcut)
67        result[i] = dict(indices=indices[mask], distances=distances[mask], images=image_indices[mask], vecs=distance_vectors[mask, :])
68
69    mapper = operator.itemgetter(*properties)
70    return {i: mapper(d) for i, d in result.items()}

Find neighbors for each atom within a specified cutoff distance and minimum distance.

This function applies the minimum image convention to consider periodic boundary conditions.

Parameters
  • atoms (Union[Atoms, Any]): The atoms object to query. It can be an Atoms object or any other compatible type.
  • rcut (float, optional): The cutoff distance for neighbor search, by default 3.0.
  • mindist (float, optional): The minimum distance for neighbor search, by default 0.1.
  • properties (Tuple[str, ...], optional): An iterable of properties to return for each atom. Available options are 'indices', 'distances', 'images', 'vecs', by default ('indices', 'distances', 'images', 'vecs').
Returns
  • Dict[int, Tuple[np.ndarray, ...]]: A dictionary where the keys represent the atom ids, and the values are tuples containing the desired properties.
    • 'indices': Indices of neighboring atoms.
    • 'distances': Distances to neighboring atoms.
    • 'images': Indices of periodic images of neighboring atoms.
    • 'vecs': Vectors pointing from the central atom to its neighbors.