Source code for HTMACat.catkit.gen.utils.connectivity

import HTMACat.catkit
from . import coordinates
import numpy as np
import scipy
import warnings


[docs]def get_voronoi_neighbors(atoms, cutoff=5.0, return_distances=False): """Return the connectivity matrix from the Voronoi method. Multi-bonding occurs through periodic boundary conditions. Parameters ---------- atoms : atoms object Atoms object with the periodic boundary conditions and unit cell information to use. cutoff : float Radius of maximum atomic bond distance to consider. Returns ------- connectivity : ndarray (n, n) Number of edges formed between atoms in a system. """ index, coords, offsets = coordinates.expand_cell(atoms, cutoff=cutoff) xm, ym, zm = np.max(coords, axis=0) - np.min(coords, axis=0) L = int(len(offsets) / 2) origional_indices = np.arange(L * len(atoms), (L + 1) * len(atoms)) voronoi = scipy.spatial.Voronoi(coords, qhull_options="QbB Qc Qs") points = voronoi.ridge_points connectivity = np.zeros((len(atoms), len(atoms))) distances = [] distance_indices = [] for i, n in enumerate(origional_indices): ridge_indices = np.where(points == n)[0] p = points[ridge_indices] dist = np.linalg.norm(np.diff(coords[p], axis=1), axis=-1)[:, 0] edges = np.sort(index[p]) if not edges.size: warnings.warn( "scipy.spatial.Voronoi returned an atom which has " "no neighbors. This may result in incorrect connectivity." ) continue unique_edge = np.unique(edges, axis=0) for j, edge in enumerate(unique_edge): indices = np.where(np.all(edge == edges, axis=1))[0] d = dist[indices][np.where(dist[indices] < cutoff)[0]] count = len(d) if count == 0: continue u, v = edge distance_indices += [sorted([u, v])] distances += [sorted(d)] connectivity[u][v] += count connectivity[v][u] += count connectivity /= 2 if not return_distances: return connectivity.astype(int) if len(distances) > 0: distance_indices, unique_idx_idx = np.unique(distance_indices, axis=0, return_index=True) distance_indices = distance_indices.tolist() distances = [distances[i] for i in unique_idx_idx] pair_distances = {"indices": distance_indices, "distances": distances} return connectivity.astype(int), pair_distances
[docs]def get_cutoff_neighbors(atoms, cutoff=None, scale_cov_radii=1.2, atol=1e-8): """Return the connectivity matrix from a simple radial cutoff. Multi-bonding occurs through periodic boundary conditions. Parameters ---------- atoms : atoms object Atoms object with the periodic boundary conditions and unit cell information to use. cutoff : float Cutoff radius to use when determining neighbors. scale_cov_radii : float Value close to 1 to scale the covalent radii used for automated cutoff values. atol: float Absolute tolerance to use when computing distances. Returns ------- connectivity : ndarray (n, n) Number of edges formed between atoms in a system. """ cov_radii = HTMACat.catkit.gen.defaults.get("radii") * scale_cov_radii numbers = atoms.numbers index, coords = coordinates.expand_cell(atoms)[:2] if cutoff is None: radii = cov_radii[numbers] radii = np.repeat(radii[:, None], len(index) / len(radii), axis=1) radii = radii.T.flatten() else: radii = np.ones_like(index) * cutoff connectivity = np.zeros((len(atoms), len(atoms)), dtype=int) for i, center in enumerate(atoms.positions): norm = np.linalg.norm(coords - center, axis=1) boundry_distance = norm - radii if cutoff is None: boundry_distance -= cov_radii[numbers[i]] neighbors = index[np.where(boundry_distance < atol)] unique, counts = np.unique(neighbors, return_counts=True) connectivity[i, unique] = counts # Remove self-interaction connectivity[i, i] -= 1 return connectivity