Source code for graphdot.graph.adjacency.atomic

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
import copy
import functools
import numpy as np
from mendeleev.fetch import fetch_table
from graphdot.graph.adjacency.euclidean import Tent, Gaussian, CompactBell


[docs]def copying_lru_cache(*args, **kwargs): def decorator(f): cached_func = functools.lru_cache(*args, **kwargs)(f) def wrapper(*args, **kwargs): return copy.deepcopy(cached_func(*args, **kwargs)) return wrapper return decorator
[docs]@copying_lru_cache(maxsize=32) def get_ptable(): return fetch_table('elements')
[docs]@copying_lru_cache(maxsize=128) def get_length_scales(name): ptable = get_ptable() length = np.zeros(ptable.atomic_number.max() + 1) length[ptable.atomic_number] = ptable[name] * 0.01 # pm to A return length
[docs]class AtomicAdjacency: r"""Converts interatomic distances into edge weights using the equation :math:`a(i, j) = w(\frac{\lVert\mathbf{r}_{ij}\rVert}{\sigma_{ij}})`, where :math:`w` is a weight function that generally decays with distance, and :math:`\sigma_{ij}` is a length scale parameter betweens atom :math:`i` and :math:`j` and loosely corresponds to the typically distance of interatomic interactions between the atoms. Parameters ---------- shape: str or callable If string, must match one of the following patterns: - ``tent[n]``: e.g. ``tent1``, ``teng2``, etc. :py:class:`Tent`. - ``gaussian``: :py:class:`Gaussian`. - ``compactbell[a,b]``: e.g. ``compactbell4,2``, :py:class:`CompactBell`. length_scale: str The atomic property to be used to determine the range and strength of edges to be constructed between pairs of atoms. The strength will generally fall to zero at roughly a distance 3 times the length scale. Possible values are: - **atomic_radius** - atomic_radius_rahm - **vdw_radius** (default) - vdw_radius_bondi - vdw_radius_truhlar - vdw_radius_rt - vdw_radius_batsanov - vdw_radius_dreiding - vdw_radius_uff - vdw_radius_mm3 - vdw_radius_alvarez - covalent_radius_cordero - covalent_radius_pyykko - covalent_radius_bragg - covalent_radius_pyykko_double - covalent_radius_pyykko_triple - metallic_radius - metallic_radius_c12 zoom: float A zooming factor to be multiplied with the length scales to extend the range of interactions. """ def __init__(self, shape='tent1', length_scale='vdw_radius', zoom=1.0): if isinstance(shape, str): self.shape = self._parse_shape(shape) if isinstance(length_scale, str): self.ltable = get_length_scales(length_scale) else: ptbl = get_ptable() self.ltable = length_scale * np.ones(ptbl.atomic_number.max() + 1) self.ltable *= zoom @staticmethod def _parse_shape(shape): if shape == 'gaussian': return Gaussian() m = re.match(r'tent(\d+)', shape) if m: return Tent(ord=int(m.group(1))) m = re.match(r'compactbell(\d+),(\d+)', shape) if m: return CompactBell(a=int(m.group(1)), b=int(m.group(2))) raise ValueError(f'Unrecognizable adjacency shape: {shape}')
[docs] def __call__(self, n1, n2, r): """compute adjacency between atoms Parameters ---------- n1: int Atomic number of the element n2: int Same as n1 r: float Distance between the two atoms Returns ------- float: A non-negative weight """ r1 = self.ltable[n1] r2 = self.ltable[n2] weight = self.shape(r, np.sqrt(r1 * r2)) return weight
[docs] def cutoff(self, elements): max_length_scale = self.ltable[elements].max() return self.shape.cutoff(max_length_scale)