Source code for sknano.utils.analysis.funcs

# -*- coding: utf-8 -*-
"""
========================================================================
Structure analysis functions (:mod:`sknano.utils.analysis.funcs`)
========================================================================

.. currentmodule:: sknano.utils.analysis.funcs

"""
from __future__ import absolute_import, division, print_function
from __future__ import unicode_literals

from collections import deque

import numpy as np

from sknano.core.atoms import Atoms


__all__ = ['find_defect_chains', 'find_target_atom']


[docs]def find_defect_chains(atoms, defect_condition, max_length=None, exclude=None, include_root=True, **kwargs): """Analyze atoms for chains of defects.""" if not isinstance(atoms, Atoms): raise TypeError('Expected an `Atoms` object') if max_length is None: max_length = len(atoms) if exclude is None: exclude = [] chains = [] seen = [] for atom in atoms: chain = [] queue = deque([natom for natom in atom.neighbors]) while queue and len(chain) <= max_length: natom = queue.popleft() if defect_condition(natom) and \ all([natom not in atoms_ for atoms_ in (atoms, chain, chains, seen, exclude)]): chain.append(natom) queue.extend([nnatom for nnatom in natom.neighbors if all([nnatom not in atoms_ for atoms_ in (atoms, chain, chains, seen, exclude)])]) seen.append(natom) if len(chain) > 0: if include_root: chain.insert(0, atom) defect_atoms = \ atoms.__class__(chain, update_item_class=False, **atoms.kwargs) chains.append(defect_atoms) return chains
[docs]def find_target_atom(atoms, target_coords=None, search_radius=1.0, nearest_target=False, max_search_radius=None): """Search for atom closest to target location. Parameters ---------- atoms : :class:`~sknano.core.atoms.Atoms` An :class:`~sknano.core.atoms.Atoms` instance. target_coords : array_like An array or list of :math:`x,y,z` coordinates search_radius : :class:`~python:float`, optional Search radius nearest_target : :class:`~python:bool`, optional max_search_radius : :class:`~python:float`, optional Returns ------- target_atom : :class:`~sknano.core.atoms.Atom` An :class:`~sknano.core.atoms.Atom` instance. """ print('Starting search radius: {}'.format(search_radius)) target_atom = None if max_search_radius is None: max_search_radius = 100. * search_radius atom_tree = atoms.atom_tree while search_radius <= max_search_radius: try: target_index = None if nearest_target: target_index = \ atom_tree.query(target_coords, distance_upper_bound=search_radius)[-1] else: target_index = \ np.random.choice( atom_tree.query_ball_point(target_coords, search_radius)) target_atom = atoms[target_index] except (IndexError, ValueError): search_radius += 1 print('No target atom within search radius.\n' 'Increasing radius by 1 unit to {}'.format(search_radius)) else: print('Found target atom.') return target_atom else: print('Maximum search radius exceeded. No target atom found.') return None