Source code for sknano.core.structures.compositions

# -*- coding: utf-8 -*-
"""
==============================================================================
Base composition classes (:mod:`sknano.core.structures.compositions`)
==============================================================================

.. currentmodule:: sknano.core.structures.compositions

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

from functools import total_ordering
from operator import attrgetter

import numpy as np

from sknano.core import BaseClass, UserList
from sknano.core.math import convert_condition_str, rotation_matrix

__all__ = ['Composition', 'Compositions']


@total_ordering
[docs]class Composition(BaseClass): """Base class for abstract representation of a composition. Parameters ---------- components : {None, sequence, `Atoms`}, optional if not `None`, then a list of `Atom` instances or an `Atoms` instance. """ def __init__(self, components=None, **kwargs): super().__init__(**kwargs) self.components = components self.fmtstr = "components={components!r}" def __eq__(self, other): """Test equality of two `Composition` object instances.""" return self is other or self.components == other.components def __lt__(self, other): """Test if `self` is *less than* `other`.""" return self.components < other.components
[docs] def rezero(self, *args, **kwargs): assert not hasattr(super(), 'rezero')
[docs] def rotate(self, **kwargs): assert not hasattr(super(), 'rotate')
[docs] def translate(self, *args, **kwargs): assert not hasattr(super(), 'translate')
[docs] def todict(self): """Return :class:`~python:dict` of `Composition` constructor \ parameters.""" return dict(components=self.components)
[docs]class Compositions(UserList): """Base class for collection of `Composition` objects. Parameters ---------- compositions : {None, sequence, `Compositions`}, optional if not `None`, then a list of `Composition` instance objects or an existing `Compositions` instance object. """ def __init__(self, compositions=None, update_item_class=True, **kwargs): super().__init__(initlist=compositions) self.fmtstr = "{compositions!r}" @property def __item_class__(self): return Composition def sort(self, key=attrgetter('id'), reverse=False): super().sort(key=key, reverse=reverse) @property def Ncompositions(self): """Number of compositions in `Compositions`.""" return len(self) @property def masses(self): """Return list of `Composition` masses.""" return np.asarray([composition.mass for composition in self]) def filter(self, condition, invert=False): """Filter `Compositions` by `condition`. Parameters ---------- condition : array_like, bool invert : bool, optional Returns ------- filtered_compositions : `Compositions` """ if isinstance(condition, str): condition = convert_condition_str(self, condition) if invert: condition = ~condition try: self.data = np.asarray(self)[condition].tolist() except AttributeError: self.data = np.asarray(self)[condition] def filtered(self, condition, invert=False): if isinstance(condition, str): condition = convert_condition_str(self, condition) if invert: condition = ~condition try: return self.__class__(components=np.asarray(self)[condition].tolist(), **self.kwargs) except AttributeError: return self.__class__(components=np.asarray(self)[condition], **self.kwargs) def get_compositions(self, asarray=False): """Return list of `Compositions`. Parameters ---------- asarray : bool, optional Returns ------- sequence or ndarray """ if asarray: return np.asarray(self.data) else: return self.data def rezero(self, epsilon=1.0e-10): """Set really really small coordinates to zero. Set all coordinates with absolute value less than epsilon to zero. Parameters ---------- epsilon : float smallest allowed absolute value of any :math:`x,y,z` component. """ [composition.rezero(epsilon=epsilon) for composition in self] def rotate(self, **kwargs): """Rotate `Composition` position vectors. Parameters ---------- angle : float axis : :class:`~sknano.core.math.Vector`, optional anchor_point : :class:`~sknano.core.math.Point`, optional rot_point : :class:`~sknano.core.math.Point`, optional from_vector, to_vector : :class:`~sknano.core.math.Vector`, optional degrees : bool, optional transform_matrix : :class:`~numpy:numpy.ndarray` """ if kwargs.get('transform_matrix', None) is None: kwargs['transform_matrix'] = rotation_matrix(**kwargs) [composition.rotate(**kwargs) for composition in self] def translate(self, t, fix_anchor_points=True): """Translate `Composition` position vectors by :class:`Vector` `t`. Parameters ---------- t : :class:`Vector` fix_anchor_points : bool, optional """ [composition.translate(t, fix_anchor_point=fix_anchor_points) for composition in self] def todict(self): return dict(compositions=self.data)