Source code for sknano.core.analysis.ring_analysis

# -*- coding: utf-8 -*-
"""
===============================================================================
Ring analysis (:mod:`sknano.core.analysis.ring_analysis`)
===============================================================================

.. currentmodule:: sknano.core.analysis.ring_analysis

"""
from __future__ import absolute_import, division, print_function
from __future__ import unicode_literals
__docformat__ = 'restructuredtext en'

from collections import deque

import numpy as np

# from sknano.core import timethis
# from sknano.core.math import Vector

try:
    from . import _ring_finder
except ImportError:
    _ring_finder = None

__all__ = ['find_rings', 'py_find_rings']


# @timethis
[docs]def find_rings(Natoms, NNN, nn_idx, nn_seed, nn_amat, nn_vecs, max_ring_size=None, eps=0.0001, pyversion=False): """Find rings. Parameters ---------- Natoms : :class:`~python:int` NNN : :class:`~python:int` nn_idx : :class:`~numpy:numpy.ndarray` nn_seed : :class:`~numpy:numpy.ndarray` nn_amat : :class:`~numpy:numpy.ndarray` nn_vecs : :class:`~numpy:numpy.ndarray` max_ring_size : :class:`~python:int`, optional eps : :class:`~python:float`, optional """ if max_ring_size is None: max_ring_size = -1 if _ring_finder is None or pyversion: return py_find_rings(Natoms, NNN, nn_idx, nn_seed, nn_amat, nn_vecs, max_ring_size, eps) nn_idx = np.asarray(nn_idx, dtype=np.intc) nn_seed = np.asarray(nn_seed, dtype=np.intc) nn_amat = np.asarray(nn_amat, dtype=np.intc) try: nn_vecs = np.asarray([v.__array__() for v in nn_vecs], dtype=np.double) except AttributeError: nn_vecs = np.asarray(nn_vecs, dtype=np.double) return _ring_finder.find_rings(Natoms, NNN, nn_idx, nn_seed, nn_amat, nn_vecs, max_ring_size, eps)
# @timethis
[docs]def py_find_rings(Natoms, NNN, nn_idx, nn_seed, nn_amat, nn_vecs, max_ring_size=None, eps=0.0001): """Find rings. Parameters ---------- Natoms : :class:`~python:int` NNN : :class:`~python:int` nn_idx : :class:`~numpy:numpy.ndarray` nn_seed : :class:`~numpy:numpy.ndarray` nn_amat : :class:`~numpy:numpy.ndarray` nn_vecs : :class:`~numpy:numpy.ndarray` max_ring_size : :class:`~python:int`, optional eps : :class:`~python:float`, optional """ if max_ring_size is None: max_ring_size = -1 visited = np.zeros(NNN, dtype=bool) # ring_counter = Counter() ring_counts = [] nodes_list = [] def search_paths(root=None, node=None, d=None): """Search for closed paths starting from `root` atom. Parameters ---------- root, node : :class:`~python:int` d : array_like """ q = deque([(root, [node], d)]) while q: prev, nodes, d = q.popleft() node = nodes[-1] if node > 0: i = node for si in range(nn_seed[i], nn_seed[i+1]): ni = nn_idx[si] if not visited[si] and ni != prev: di = nn_amat[root][i] dni = nn_amat[root][ni] if (dni == di + 1): if (len(nodes) < (max_ring_size - 1) // 2 or max_ring_size < 0): q.append((node, nodes + [ni], d + nn_vecs[si])) else: continue elif ((dni == di) or (dni == di - 1)): q.append((node, nodes + [-ni], d + nn_vecs[si])) else: raise ValueError('bad adjacency matrix') else: i = -node for si in range(nn_seed[i], nn_seed[i + 1]): ni = nn_idx[si] if not visited[si] and ni != prev: di = nn_amat[root][i] dni = nn_amat[root][ni] if ni == root: dr = nn_vecs[si] + d # For a closed ring, the vector sum of the # ring bond vectors will have zero length. if dr.norm < eps: found_ring = True nodes.append(root) ring_size = len(nodes) for n in range(ring_size): for m in range(n + 1, ring_size): s = m - n if s > ring_size // 2: s = ring_size - s if nn_amat[abs(nodes[m])][ abs(nodes[n])] != s: found_ring = False if found_ring: nodes_list.append(nodes) while len(ring_counts) < ring_size + 1: ring_counts.append(0) ring_counts[ring_size] += 1 elif dni == di - 1: q.append((node, nodes + [-ni], d + nn_vecs[si])) for i in range(Natoms): for si in range(nn_seed[i], nn_seed[i+1]): ni = nn_idx[si] if i < ni: visited[si] = True for nsi in range(nn_seed[ni], nn_seed[ni+1]): nni = nn_idx[nsi] if nni == i: visited[nsi] = True search_paths(root=i, node=ni, d=nn_vecs[si]) return ring_counts, nodes_list