Source code for sknano.generators._swnt_generator
# -*- coding: utf-8 -*-
"""
===============================================================================
SWNT structure generator (:mod:`sknano.generators._swnt_generator`)
===============================================================================
.. currentmodule:: sknano.generators._swnt_generator
.. todo::
Add methods to perform fractional translation and cartesian translation
before structure generation.
.. todo::
Handle different units in output coordinates.
"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
#import six
from six.moves import range
__docformat__ = 'restructuredtext en'
import numpy as np
from sknano.core import pluralize
from sknano.core.math import Vector
from sknano.structures import SWNT
from sknano.utils.geometric_shapes import Cuboid
from ._base import Atom, Atoms, GeneratorBase
__all__ = ['SWNTGenerator']
[docs]class SWNTGenerator(SWNT, GeneratorBase):
"""Class for generating nanotube structures.
Parameters
----------
n, m : int
Chiral indices defining the nanotube chiral vector
:math:`\\mathbf{C}_{h} = n\\mathbf{a}_{1} + m\\mathbf{a}_{2} = (n, m)`.
nz : int, optional
Number of repeat unit cells in the :math:`z` direction, along
the *length* of the nanotube.
element1, element2 : {str, int}, optional
Element symbol or atomic number of basis
:class:`~sknano.core.Atom` 1 and 2
bond : float, optional
:math:`\\mathrm{a}_{\\mathrm{CC}} =` distance between
nearest neighbor atoms. Must be in units of **Angstroms**.
Lz : float, optional
Length of nanotube in units of **nanometers**.
Overrides the `nz` value.
.. versionadded:: 0.2.5
tube_length : float, optional
Length of nanotube in units of **nanometers**.
Overrides the `nz` value.
.. deprecated:: 0.2.5
Use `Lz` instead
fix_Lz : bool, optional
Generate the nanotube with length as close to the specified
:math:`L_z` as possible. If `True`, then
non integer :math:`n_z` cells are permitted.
.. versionadded:: 0.2.6
autogen : bool, optional
if `True`, automatically call
:meth:`~SWNTGenerator.generate_unit_cell`,
followed by :meth:`~SWNTGenerator.generate_structure_data`.
verbose : bool, optional
if `True`, show verbose output
Examples
--------
First, load the :class:`~sknano.generators.SWNTGenerator` class.
>>> from sknano.generators import SWNTGenerator
Now let's generate a :math:`\\mathbf{C}_{\\mathrm{h}} = (10, 5)`
SWCNT unit cell.
>>> nt = SWNTGenerator(n=10, m=5)
>>> nt.save_data(fname='10,5_unit_cell.xyz')
The rendered structure looks like (orhographic view):
.. image:: /images/10,5_unit_cell_orthographic_view.png
and the perspective view:
.. image:: /images/10,5_unit_cell_perspective_view.png
"""
def __init__(self, autogen=True, **kwargs):
super(SWNTGenerator, self).__init__(**kwargs)
if autogen:
self.generate_unit_cell()
self.generate_structure_data()
[docs] def generate_unit_cell(self):
"""Generate the nanotube unit cell."""
eps = 0.01
e1 = self.element1
e2 = self.element2
N = self.N
T = self.T
rt = self.rt
psi, tau, dpsi, dtau = self.unit_cell_symmetry_params
if self.verbose:
print('dpsi: {}'.format(dpsi))
print('dtau: {}\n'.format(dtau))
self.unit_cell = Atoms()
for i in range(N):
x1 = rt * np.cos(i * psi)
y1 = rt * np.sin(i * psi)
z1 = i * tau
while z1 > T - eps:
z1 -= T
if z1 < 0:
z1 += T
if self.debug:
print('i={}: x1, y1, z1 = ({:.6f}, {:.6f}, {:.6f})'.format(
i, x1, y1, z1))
atom1 = Atom(element=e1, x=x1, y=y1, z=z1)
atom1.rezero()
if self.verbose:
print('Basis Atom 1:\n{}'.format(atom1))
self.unit_cell.append(atom1)
x2 = rt * np.cos(i * psi + dpsi)
y2 = rt * np.sin(i * psi + dpsi)
z2 = i * tau - dtau
while z2 > T - eps:
z2 -= T
if z2 < 0:
z2 += T
if self.debug:
print('i={}: x2, y2, z2 = ({:.6f}, {:.6f}, {:.6f})'.format(
i, x2, y2, z2))
atom2 = Atom(element=e2, x=x2, y=y2, z=z2)
atom2.rezero()
if self.verbose:
print('Basis Atom 2:\n{}'.format(atom2))
self.unit_cell.append(atom2)
[docs] def generate_structure_data(self):
"""Generate structure data."""
#self.atoms = Atoms()
self.structure_data.clear()
for nz in range(int(np.ceil(self.nz))):
dr = Vector([0.0, 0.0, nz * self.T])
for uc_atom in self.unit_cell:
nt_atom = Atom(element=uc_atom.symbol)
nt_atom.r = uc_atom.r + dr
self.atoms.append(nt_atom)
[docs] def save_data(self, fname=None, outpath=None, structure_format=None,
rotation_angle=None, rot_axis=None, anchor_point=None,
deg2rad=True, center_CM=True, savecopy=True, **kwargs):
"""Save structure data.
See :meth:`~sknano.generators.GeneratorBase.save_data` method
for documentation.
"""
if fname is None:
chirality = '{}{}'.format('{}'.format(self.n).zfill(2),
'{}'.format(self.m).zfill(2))
nz = '{}' if self._assert_integer_nz else '{:.2f}'
nz = ''.join((nz.format(self.nz), pluralize('cell', self.nz)))
fname_wordlist = (chirality, nz)
fname = '_'.join(fname_wordlist)
if self.L0 is not None and self.fix_Lz:
Lz_cutoff = 10 * self.L0 + 1
pmin = [-np.inf, -np.inf, -Lz_cutoff]
pmax = [np.inf, np.inf, Lz_cutoff]
region_bounds = Cuboid(pmin=pmin, pmax=pmax)
region_bounds.update_region_limits()
self.atoms.clip_bounds(region_bounds, center_before_clipping=True)
if center_CM:
self.atoms.center_CM()
super(SWNTGenerator, self).save_data(
fname=fname, outpath=outpath, structure_format=structure_format,
rotation_angle=rotation_angle, rot_axis=rot_axis,
anchor_point=anchor_point, deg2rad=deg2rad, center_CM=False,
savecopy=savecopy, **kwargs)