# -*- coding: utf-8 -*-
"""
===============================================================================
Structure generator base module (:mod:`sknano.generators.base`)
===============================================================================
.. currentmodule:: sknano.generators.base
"""
from __future__ import absolute_import, division, print_function
from __future__ import unicode_literals
__docformat__ = 'restructuredtext en'
from abc import ABCMeta, abstractmethod
import os
import numpy as np
# import copy
from sknano.core.atoms import StructureAtom as Atom
from sknano.core.structures import StructureBase
from sknano.io import StructureWriterMixin, supported_structure_formats
__all__ = ['GeneratorBase', 'GeneratorMixin',
'CrystalStructureGenerator', 'NanoStructureGenerator',
'STRUCTURE_GENERATORS']
#: Tuple of structure generator classes.
STRUCTURE_GENERATORS = ('FullereneGenerator',
'GrapheneGenerator',
'PrimitiveCellGrapheneGenerator',
'ConventionalCellGrapheneGenerator',
'BilayerGrapheneGenerator',
'UnrolledSWNTGenerator',
'SWNTGenerator',
'MWNTGenerator',
'AlphaQuartzGenerator',
'DiamondStructureGenerator',
'FCCStructureGenerator',
'CaesiumChlorideStructureGenerator',
'RocksaltStructureGenerator',
'ZincblendeStructureGenerator',
'MoS2Generator')
[docs]class GeneratorBase(StructureWriterMixin, StructureBase, metaclass=ABCMeta):
"""Base structure generator class.
Parameters
----------
autogen : :class:`~python:bool`
finalize : :class:`~python:bool`
"""
def __init__(self, *args, autogen=True, finalize=True, **kwargs):
super().__init__(*args, **kwargs)
if autogen:
self.generate(finalize=finalize)
# def __getattr__(self, name):
# print('getting attribute: {}'.format(name))
# if name != 'atoms' and len(self.atoms) > 0:
# attr = getattr(self.atoms, name, None)
# if attr:
# return attr
# super().__getattr__(name)
@property
def Natoms(self):
"""N atoms."""
try:
Natoms = self._atoms.Natoms
if Natoms:
return Natoms
raise AttributeError
except AttributeError:
return super().Natoms
@property
def mass(self):
"""Total mass of atoms."""
try:
mass = self._atoms.mass
if mass:
return mass
raise AttributeError
except AttributeError:
return super().mass
@abstractmethod
[docs] def generate(self, finalize=True):
"""Generate structure data."""
return NotImplementedError
[docs] def finalize(self):
"""Finalize structure data by assigning unique ids and types to \
structure atoms."""
atoms = self._atoms
atoms.assign_unique_ids()
atoms.assign_unique_types()
self.structure.translate(self.lattice_shift)
# atoms.lattice = self.crystal_cell.lattice
[docs] def save(self, *args, **kwargs):
"""An alias for :meth:`~sknano.io.StructureWriterMixin.write`."""
super().write(*args, **kwargs)
[docs]class GeneratorMixin:
"""Mixin class with concrete implementation of \
:meth:`~GeneratorBase.generate` method."""
[docs] def generate(self, finalize=True):
"""Concrete implementation of :meth:`~GeneratorBase.generate` \
method."""
self.structure.clear()
for atom in self.crystal_cell:
self.atoms.append(Atom(**atom.todict()))
if finalize:
self.finalize()
[docs]class CrystalStructureGenerator(GeneratorMixin, GeneratorBase):
""":class:`GeneratorBase` sub-class for \
:class:`~sknano.core.structures.CrystalStructureBase`\ s"""
[docs] def save(self, fname=None, scaling_matrix=None, **kwargs):
"""Save structure data."""
if fname is None:
fname = self.__class__.__name__[:-len('Generator')]
if fname.endswith('CC'):
fname = '_'.join((fname, '-'.join(set(self.basis.symbols))))
if scaling_matrix is None:
scaling_matrix = self.scaling_matrix.A
elif isinstance(scaling_matrix, np.matrix):
scaling_matrix = scaling_matrix.A
if fname is not None and scaling_matrix is not None:
ext = None
if fname.endswith(supported_structure_formats):
fname, ext = os.path.splitext(fname)
if isinstance(scaling_matrix, np.ndarray):
if scaling_matrix.ndim == 2:
if scaling_matrix.shape == (1, 3):
scaling_matrix = scaling_matrix.flatten()
elif scaling_matrix.shape == (3, 3) and \
np.all(scaling_matrix -
np.diag(np.diag(scaling_matrix)) == 0):
scaling_matrix = scaling_matrix.diagonal()
else:
scaling_matrix = scaling_matrix.flatten()
fname = '_'.join((fname, 'x'.join(map(str, scaling_matrix))))
if ext is not None:
fname = fname + ext
super().save(fname=fname, **kwargs)
[docs]class NanoStructureGenerator(GeneratorBase):
""":class:`GeneratorBase` sub-class for \
:class:`~sknano.core.structures.NanoStructureBase` class."""
pass