Refactored next_neighbors and added type hints

This commit is contained in:
Sebastian Kloth 2023-12-26 11:05:16 +01:00
parent fd60cae3b8
commit 97e29e6de3

View File

@ -10,7 +10,7 @@ from .checksum import checksum
from .coordinates import CoordinateFrame from .coordinates import CoordinateFrame
def compare_regex(str_list: list[str], exp: str): def compare_regex(str_list: list[str], exp: str) -> np.ndarray:
""" """
Compare a list of strings with a regular expression. Compare a list of strings with a regular expression.
""" """
@ -79,10 +79,10 @@ class AtomSubset:
the keyworss below. Names are matched as a regular expression with `re.match`. the keyworss below. Names are matched as a regular expression with `re.match`.
Args: Args:
atom_name: Specification of the atom name atom_name: Specification of the atom name
residue_name: Specification of the resiude name residue_name: Specification of the resiude name
residue_id: Residue ID or list of IDs residue_id: Residue ID or list of IDs
indices: List of atom indices indices: List of atom indices
""" """
new_subset = self new_subset = self
if atom_name is not None: if atom_name is not None:
@ -176,7 +176,7 @@ class AtomSubset:
return checksum(self.description) return checksum(self.description)
def gyration_radius(position: CoordinateFrame): def gyration_radius(position: CoordinateFrame) -> np.ndarray:
r""" r"""
Calculates a list of all radii of gyration of all molecules given in the coordinate Calculates a list of all radii of gyration of all molecules given in the coordinate
frame, weighted with the masses of the individual atoms. frame, weighted with the masses of the individual atoms.
@ -185,7 +185,8 @@ def gyration_radius(position: CoordinateFrame):
position: Coordinate frame object position: Coordinate frame object
..math:: ..math::
R_G = \left(\frac{\sum_{i=1}^{n} m_i |\vec{r_i} - \vec{r_{COM}}|^2 }{\sum_{i=1}^{n} m_i } R_G = \left(\frac{\sum_{i=1}^{n} m_i |\vec{r_i}
- \vec{r_{COM}}|^2 }{\sum_{i=1}^{n} m_i }
\rigth)^{\frac{1}{2}} \rigth)^{\frac{1}{2}}
""" """
gyration_radii = np.array([]) gyration_radii = np.array([])
@ -207,7 +208,7 @@ def layer_of_atoms(
thickness: float, thickness: float,
plane_normal: npt.ArrayLike, plane_normal: npt.ArrayLike,
plane_offset: Optional[npt.ArrayLike] = np.array([0, 0, 0]), plane_offset: Optional[npt.ArrayLike] = np.array([0, 0, 0]),
): ) -> np.array:
if plane_offset is None: if plane_offset is None:
np.array([0, 0, 0]) np.array([0, 0, 0])
atoms = atoms - plane_offset atoms = atoms - plane_offset
@ -215,45 +216,14 @@ def layer_of_atoms(
return np.abs(distance) <= thickness return np.abs(distance) <= thickness
def distance_to_atoms(ref, atoms, box=None):
"""Get the minimal distance from atoms to ref.
The result is an array of with length == len(atoms)
"""
out = np.empty(atoms.shape[0])
for i, atom in enumerate(atoms):
diff = (pbc_diff(atom, ref, box) ** 2).sum(axis=1).min()
out[i] = np.sqrt(diff)
return out
def distance_to_atoms_KDtree(ref, atoms, box=None, thickness=None):
"""
Get the minimal distance from atoms to ref.
The result is an array of with length == len(atoms)
Can be faster than distance_to_atoms.
Thickness defaults to box/5. If this is too small results may be wrong.
If box is not given then periodic boundary conditions are not applied!
"""
if thickness == None:
thickness = box / 5
if box is not None:
start_coords = np.copy(atoms) % box
all_frame_coords = pbc_points(ref, box, thickness=thickness)
else:
start_coords = atoms
all_frame_coords = ref
tree = KDTree(all_frame_coords)
return tree.query(start_coords)[0]
def next_neighbors( def next_neighbors(
atoms, atoms: CoordinateFrame,
query_atoms=None, query_atoms: Optional[CoordinateFrame] = None,
number_of_neighbors=1, number_of_neighbors: int = 1,
distance_upper_bound=np.inf, distance_upper_bound: float = np.inf,
distinct=False, distinct: bool = False,
): **kwargs
) -> (np.ndarray, np.ndarray):
""" """
Find the N next neighbors of a set of atoms. Find the N next neighbors of a set of atoms.
@ -269,15 +239,29 @@ def next_neighbors(
If this is true, the atoms and query atoms are taken as distinct sets of If this is true, the atoms and query atoms are taken as distinct sets of
atoms atoms
""" """
tree = KDTree(atoms)
dnn = 0 dnn = 0
if query_atoms is None: if query_atoms is None:
query_atoms = atoms query_atoms = atoms
dnn = 1
elif not distinct: elif not distinct:
dnn = 1 dnn = 1
dist, indices = tree.query(
query_atoms, box = atoms.box
number_of_neighbors + dnn, if np.all(np.diag(np.diag(box)) == box):
distance_upper_bound=distance_upper_bound, atoms = atoms % np.diag(box)
) tree = KDTree(atoms, boxsize=np.diag(box))
return indices[:, dnn:] distances, indices = tree.query(
query_atoms, number_of_neighbors, distance_upper_bound=distance_upper_bound
)
else:
atoms_pbc, atoms_pbc_index = pbc_points(
query_atoms, box, thickness=distance_upper_bound+0.1, index=True, **kwargs
)
tree = KDTree(atoms_pbc)
distances, indices = tree.query(
query_atoms, number_of_neighbors, distance_upper_bound=distance_upper_bound
)
indices = atoms_pbc_index[indices]
return distances[:, dnn:], indices[:, dnn:]