# -*- coding: utf-8 -*-
"""
===============================================================================
Compute functions (:mod:`sknano.structures._compute_funcs`)
===============================================================================
.. currentmodule:: sknano.structures._compute_funcs
"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
from six.moves import range
__docformat__ = 'restructuredtext en'
from fractions import gcd
import numbers
import numpy as np
from sknano.core.atoms import Atom
from sknano.core.refdata import CCbond, grams_per_Da
__all__ = ['compute_d', 'compute_dR', 'compute_N', 'compute_t1', 'compute_t2',
'compute_Ch', 'compute_chiral_angle', 'compute_T', 'compute_dt',
'compute_rt', 'compute_M', 'compute_R', 'compute_R_chiral_angle',
'compute_symmetry_operation', 'compute_psi', 'compute_tau',
'compute_Lz', 'compute_electronic_type', 'compute_Natoms',
'compute_Natoms_per_tube', 'compute_Natoms_per_unit_cell',
'compute_unit_cell_mass', 'compute_linear_mass_density',
'compute_bundle_density', 'compute_symmetry_chiral_angle',
'compute_tube_diameter', 'compute_tube_radius',
'compute_tube_length', 'compute_tube_mass']
[docs]def compute_d(n, m):
"""Compute :math:`d=\\gcd{(n, m)}`
:math:`d` is the **G**\ reatest **C**\ ommon **D**\ ivisor of
:math:`n` and :math:`m`.
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)`.
Returns
-------
int
Greatest Common Divisor of :math:`n` and :math:`m`
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
return gcd(n, m)
[docs]def compute_dR(n, m):
"""Compute :math:`d_R=\\gcd{(2n + m, 2m + n)}`
:math:`d_R` is the **G**\ reatest **C**\ ommon **D**\ ivisor of
:math:`2n + m` and :math:`2m + n`.
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)`.
Returns
-------
int
greatest common divisor of :math:`2n+m` and :math:`2m+n`
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
return gcd(2 * m + n, 2 * n + m)
[docs]def compute_N(n, m):
"""Compute :math:`N = \\frac{2(n^2+m^2+nm)}{d_R}`.
:math:`N` is the number of graphene hexagons mapped to a nanotube
*unit cell*.
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)`.
Returns
-------
int
Number of hexagons per nanotube unit cell:
:math:`N = \\frac{2(n^2+m^2+nm)}{d_R}`.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
dR = compute_dR(n, m)
try:
return int(2 * (n**2 + m**2 + n * m) / dR)
except ZeroDivisionError:
return 0
[docs]def compute_t1(n, m):
"""Compute :math:`t_1 = \\frac{2m + n}{d_R}`
where :math:`d_R = \\gcd{(2n + m, 2m + n)}`.
The component of the translation vector :math:`\\mathbf{T}`
along :math:`\\mathbf{a}_1`:
.. math::
\\mathbf{T} = t_1\\mathbf{a}_{1} + t_2\\mathbf{a}_2
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)`.
Returns
-------
int
:math:`t_1`
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
dR = compute_dR(n, m)
try:
return int((2 * m + n) / dR)
except ZeroDivisionError:
return 0
[docs]def compute_t2(n, m):
"""Compute :math:`t_2 = -\\frac{2n + m}{d_R}`
where :math:`d_R = \\gcd{(2n + m, 2m + n)}`.
The component of the translation vector :math:`\\mathbf{T}`
along :math:`\\mathbf{a}_2`:
.. math::
\\mathbf{T} = t_1\\mathbf{a}_1 + t_2\\mathbf{a}_2
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)`.
Returns
-------
int
:math:`t_2`
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
dR = compute_dR(n, m)
try:
return -int((2 * n + m) / dR)
except ZeroDivisionError:
return 0
[docs]def compute_Ch(n, m, bond=None, **kwargs):
"""Compute nanotube circumference :math:`|\\mathbf{C}_{h}|` in \
**\u212b**.
.. math::
|\\mathbf{C}_h| = a\\sqrt{n^2 + m^2 + nm} =
\\sqrt{3}a_{\\mathrm{CC}}\\sqrt{n^2 + m^2 + nm}
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)`.
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
Returns
-------
float
Nanotube circumference :math:`|\\mathbf{C}_h|` in \u212b.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
if bond is None:
bond = CCbond
return bond * np.sqrt(3 * (n**2 + m**2 + n * m))
[docs]def compute_chiral_angle(n, m, rad2deg=True):
"""Compute chiral angle :math:`\\theta_c`.
.. math::
\\theta_c = \\tan^{-1}\\left(\\frac{\\sqrt{3} m}{2n + m}\\right)
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)`.
rad2deg : bool, optional
If `True`, return angle in degrees.
Returns
-------
float
Chiral angle :math:`\\theta_{c}` in
degrees (default) or radians (if `rad2deg=False`).
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
theta = np.arctan(np.sqrt(3) * m / (2 * n + m))
#return np.arccos((2*n + m) / (2 * np.sqrt(n**2 + m**2 + n*m)))
if rad2deg:
return np.degrees(theta)
else:
return theta
[docs]def compute_T(n, m, bond=None, length=True, **kwargs):
"""Compute length of nanotube unit cell :math:`|\\mathbf{T}|` in \
\u212b.
.. math::
|\\mathbf{T}| = \\frac{\\sqrt{3} |\\mathbf{C}_{h}|}{d_{R}}
= \\frac{\\sqrt{3}a\\sqrt{n^2 + m^2 + nm}}{d_{R}}
= \\frac{3a_{\\mathrm{CC}}\\sqrt{n^2 + m^2 + nm}}{d_{R}}
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)`.
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
length : bool, optional
Compute the magnitude (i.e., length) of the translation vector.
Returns
-------
float or 2-tuple of ints
If `length` is `True`, then
return the length of unit cell in \u212b.
If `length` is `False`, return the componets of the
translation vector as a 2-tuple of ints
(:math:`t_1`, :math:`t_2`).
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
if length:
if bond is None:
bond = CCbond
Ch = compute_Ch(n, m, bond=bond, **kwargs)
dR = compute_dR(n, m)
try:
return np.sqrt(3) * Ch / dR
except (FloatingPointError, ZeroDivisionError):
return 0
else:
t1 = compute_t1(n, m)
t2 = compute_t2(n, m)
return (t1, t2)
[docs]def compute_dt(n, m, bond=None, **kwargs):
"""Compute nanotube diameter :math:`d_t` in \u212b.
.. math::
d_t = \\frac{|\\mathbf{C}_h|}{\\pi}
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)`.
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
Returns
-------
float
Nanotube diameter :math:`d_t` in \u212b.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
Ch = compute_Ch(n, m, bond=bond)
return Ch / np.pi
[docs]def compute_rt(n, m, bond=None, **kwargs):
"""Compute nanotube radius :math:`r_t` in \u212b.
.. math::
r_t = \\frac{|\\mathbf{C}_h|}{2\\pi}
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)`.
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
Returns
-------
float
Nanotube radius :math:`r_t` in \u212b.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
Ch = compute_Ch(n, m, bond=bond, **kwargs)
return Ch / (2 * np.pi)
[docs]def compute_M(n, m):
"""Compute :math:`M = mp - nq`
:math:`M` is the number of multiples of the translation vector
:math:`\\mathbf{T}` in the vector :math:`N\\mathbf{R}`.
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)`.
Returns
-------
int
:math:`M = mp - nq`
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
p, q = compute_R(n, m)
return m * p - n * q
[docs]def compute_R(n, m, bond=None, length=False, **kwargs):
"""Compute symmetry vector :math:`\\mathbf{R} = (p, q)`.
The *symmetry vector* is any lattice vector of the unfolded graphene
layer that represents a *symmetry operation* of the nanotube. The
symmetry vector :math:`\\mathbf{R}` can be written as:
.. math::
\\mathbf{R} = p\\mathbf{a}_1 + q\\mathbf{a}_2
where :math:`p` and :math:`q` are integers.
The *symmetry vector* represents a *symmetry operation* of the nanotube
which arises as a *screw translation*, which is a combination of
a rotation :math:`\\psi` and translation :math:`\\tau`. The symmetry
operation of the nanotube can be written as:
.. math::
R = (\\psi|\\tau)
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)`.
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
length : bool, optional
If `True`, return :math:`|\\mathbf{R}|`.
Returns
-------
(p, q) : tuple
2-tuple of ints -- components of :math:`\\mathbf{R}`.
float
Length of :math:`\\mathbf{R}` (:math:`|\\mathbf{R}|`) if `length`
is `True` in units of **\u212b**.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
N = compute_N(n, m)
t1 = compute_t1(n, m)
t2 = compute_t2(n, m)
p = q = 0
for i in range(0, t1 + n + 1):
for j in range(t2, m + 1):
R = t1 * j - t2 * i
if R == 1:
M = m * i - n * j
if M > 0 and M <= N:
p = i
q = j
if length:
if bond is None:
bond = CCbond
return bond * np.sqrt(3 * (p**2 + q**2 + p * q))
else:
return (p, q)
[docs]def compute_R_chiral_angle(n, m, rad2deg=True):
"""Compute "chiral angle" of symmetry vector :math:`\\theta_R`.
.. math::
\\theta_R = \\tan^{-1}\\left(\\frac{\\sqrt{3}q}{2p + q}\\right)
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)`.
rad2deg : bool, optional
If `True`, return angle in degrees
Returns
-------
float
Chiral angle of *symmetry vector* :math:`\\theta_R` in
degrees (default) or radians (if `rad2deg=False`).
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
p, q = compute_R(n, m)
theta = np.arctan((np.sqrt(3) * q) / (2 * p + q))
if rad2deg:
return np.degrees(theta)
else:
return theta
[docs]def compute_symmetry_operation(n, m, bond=None):
"""Compute symmetry operation :math:`(\\psi|\\tau)`.
The *symmetry vector* `R` represents a *symmetry
operation* of the nanotube which arises as a *screw translation*, which
is a combination of a rotation :math:`\\psi` and translation
:math:`\\tau`.
The symmetry operation of the nanotube can be written as:
.. math::
R = (\\psi|\\tau)
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)`.
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
Returns
-------
(psi, tau) : tuple
2-tuple of floats -- :math:`\\psi` in radians and
:math:`\\tau` in \u212b.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
psi = compute_psi(n, m)
tau = compute_tau(n, m, bond=bond)
return (psi, tau)
[docs]def compute_psi(n, m):
"""Compute rotation component of symmetry operation \
:math:`\\psi` in **radians**.
.. math::
\\psi = \\frac{2\\pi}{N}
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)`.
Returns
-------
float
Rotation component of symmetry operation :math:`\\psi`
in **radians**.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
N = compute_N(n, m)
try:
return 2 * np.pi / N
except (FloatingPointError, ZeroDivisionError):
return 0
[docs]def compute_tau(n, m, bond=None, **kwargs):
"""Compute translation component of symmetry operation \
:math:`\\tau` in **\u212b**.
.. math::
\\tau = \\frac{M|\\mathbf{T}|}{N}
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)`.
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
Returns
-------
float
Translation component of symmetry operation :math:`\\tau`
in **\u212b**.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
M = compute_M(n, m)
N = compute_N(n, m)
T = compute_T(n, m, bond=bond, **kwargs)
try:
return M * T / N
except ZeroDivisionError:
return 0
[docs]def compute_electronic_type(n, m):
"""Compute nanotube electronic type.
.. versionadded:: 0.2.7
The electronic type is determined as follows:
if :math:`(2n + m)\\,\\mathrm{mod}\\,3=0`, the nanotube is
**metallic**.
if :math:`(2n + m)\\,\\mathrm{mod}\\,3=1`, the nanotube is
**semiconducting, type 1**.
if :math:`(2n + m)\\,\\mathrm{mod}\\,3=2`, the nanotube is
**semiconducting, type 2**.
The :math:`x\\,\\mathrm{mod}\\,y` notation is mathematical
shorthand for the *modulo* operation, which computes the
**remainder** of the division of :math:`x` by :math:`y`.
So, for example, all *armchair* nanotubes must be metallic
since the chiral indices satisfy: :math:`2n + m = 2n + n = 3n` and
therefore :math:`3n\\,\\mathrm{mod}\\,3` i.e. the remainder of the
division of :math:`3n/3=n` is always zero.
.. note::
Mathematically, :math:`(2n + m)\\,\\mathrm{mod}\\,3` is equivalent
to :math:`(n - m)\\,\\mathrm{mod}\\,3` when distinguishing
between metallic and semiconducting. However, when
distinguishing between semiconducting types,
one must be careful to observe the following convention:
* Semiconducting, **type 1** means:
* :math:`(2n + m)\\,\\mathrm{mod}\\,3=1`
* :math:`(n - m)\\,\\mathrm{mod}\\,3=2`
* Semiconducting, **type 2** means:
* :math:`(2n + m)\\,\\mathrm{mod}\\,3=2`
* :math:`(n - m)\\,\\mathrm{mod}\\,3=1`
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)`.
Returns
-------
str
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
if (2 * n + m) % 3 == 1:
return 'semiconducting, type 1'
elif (2 * n + m) % 3 == 2:
return 'semiconducting, type 2'
else:
return 'metallic'
[docs]def compute_Natoms(n, m, nz):
"""Compute :math:`N_{\\mathrm{atoms/tube}}`
.. math::
N_{\\mathrm{atoms/tube}} = N_{\\mathrm{atoms/cell}} \\times
n_{z-\\mathrm{cells}}
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, float}
Number of nanotube unit cells
Returns
-------
int
:math:`N_{\\mathrm{atoms/tube}}`
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
Natoms_per_unit_cell = compute_Natoms_per_unit_cell(n, m)
return int(Natoms_per_unit_cell * nz)
[docs]def compute_Natoms_per_tube(n, m, nz):
"""Compute :math:`N_{\\mathrm{atoms/tube}}`
.. math::
N_{\\mathrm{atoms/tube}} = N_{\\mathrm{atoms/cell}} \\times
n_{z-\\mathrm{cells}}
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, float}
Number of nanotube unit cells
Returns
-------
int
:math:`N_{\\mathrm{atoms/tube}}`
"""
return compute_Natoms(n, m, nz)
[docs]def compute_Natoms_per_unit_cell(n, m):
"""Compute :math:`N_{\mathrm{atoms/cell}} = 2N`.
.. math::
N_{\\mathrm{atoms}} = 2N = \\frac{4(n^2 + m^2 + nm)}{d_R}
where :math:`N` is the number of graphene hexagons mapped to the
nanotube unit cell.
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)`.
Returns
-------
`2N` : int
Number of atoms in nanotube *unit cell*:
N_{\\mathrm{atoms}} = 2N = \\frac{4(n^2 + m^2 + nm)}{d_R}
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
N = compute_N(n, m)
return 2 * N
[docs]def compute_unit_cell_mass(n, m, element1=None, element2=None, **kwargs):
"""Compute nanotube unit cell mass in *Daltons*/*atomic mass units* (amu) \
units.
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)`.
element1, element2 : {str, int}, optional
Element symbol or atomic number of basis
:class:`~sknano.core.atoms.Atom` 1 and 2
Returns
-------
float
Unit cell mass in **Daltons**.
Notes
-----
.. todo::
Handle different elements and perform accurate calculation by
determining number of atoms of each element.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
N = compute_N(n, m)
if element1 is None:
element1 = 'C'
if element2 is None:
element2 = 'C'
mass = N * (Atom(element1).m + Atom(element2).m)
return mass
[docs]def compute_linear_mass_density(n, m, bond=None, element1=None, element2=None,
**kwargs):
"""Compute nanotube linear mass density (mass per unit length) in \
**grams/nm**.
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)`.
element1, element2 : {str, int}, optional
Element symbol or atomic number of basis
:class:`~sknano.core.atoms.Atom` 1 and 2
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
Returns
-------
float
Linear mass density in units of **g/nm**.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
mass = compute_unit_cell_mass(n, m, element1=element1, element2=element2,
**kwargs)
T = compute_T(n, m, bond=bond, length=True, **kwargs)
try:
linear_mass_density = mass / T
# there are 1.6605e-24 grams / Da and 10 angstroms / nm
linear_mass_density *= 10 * grams_per_Da
return linear_mass_density
except ZeroDivisionError:
return 0
[docs]def compute_bundle_density(n, m, d_vdw=None, bond=None,
element1=None, element2=None):
"""Compute nanotube bundle mass density \
:math:`\\rho_{\\mathrm{bundle}}(n, m)` in :math:`\\mathrm{g/cm^3}`.
.. math::
\\rho_{\\mathrm{bundle}}(n, m) = \\frac{8\\pi^2 m_{\\mathrm{C}}
\\sqrt{n^2 + m^2 + nm}}{9\\sqrt{3}a_{\\mathrm{CC}}^3 \\times
\\left(\\sqrt{n^2 + m^2 + nm} +
\\frac{\\pi d_{\\mathrm{vdW}}}{\\sqrt{3}a_{\\mathrm{CC}}}\\right)^2}
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)`.
d_vdw : int
van der Waals distance between nearest-neighbor tubes
bond : float, optional
Bond length.
Returns
-------
float
:math:`\\rho_{\\mathrm{bundle}}` in units of
:math:`\\mathrm{\\frac{g}{cm^3}}`
"""
if bond is None:
bond = CCbond
if d_vdw is None:
if n == m:
d_vdw = 3.38
elif (m == 0) or (n == 0):
d_vdw = 3.41
else:
d_vdw = 3.39
if element1 is None:
element1 = 'C'
if element2 is None:
element2 = 'C'
if element1 == element2:
bundle_density = 8 * np.pi**2 * Atom(element1).m * \
np.sqrt(n**2 + m**2 + n*m) / \
(9 * np.sqrt(3) * bond**3 *
(np.sqrt(n**2 + m**2 + n*m) +
np.pi * d_vdw / (np.sqrt(3) * bond))**2)
else:
bundle_density = 0
# there are 1.6605e-24 grams / Da and 1e-8 cm / angstrom
bundle_density *= grams_per_Da / (1e-8)**3
return bundle_density
[docs]def compute_Lz(n, m, nz, bond=None, **kwargs):
"""Compute :math:`L_z = L_{\\mathrm{tube}}` in **nanometers**.
.. math::
L_z = n_z |\\mathbf{T}|
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, float}
Number of nanotube unit cells
bond : float, optional
Distance between nearest neighbor atoms (i.e., bond length).
Must be in units of **\u212b**. Default value is
the carbon-carbon bond length in graphite, approximately
:math:`\\mathrm{a}_{\\mathrm{CC}} = 1.42` \u212b
Returns
-------
float
:math:`L_z = L_{\\mathrm{tube}}` in **nanometers**
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
if not (isinstance(nz, numbers.Real) or nz > 0):
raise TypeError('Expected a real, positive number')
T = compute_T(n, m, bond=bond, **kwargs)
return nz * T / 10
def compute_symmetry_chiral_angle(n, m, rad2deg=True):
"""Alias for :func:`compute_R_chiral_angle`."""
return compute_R_chiral_angle(n, m, rad2deg=rad2deg)
def compute_tube_diameter(n, m, bond=None, **kwargs):
"""Alias for :func:`compute_dt`"""
return compute_dt(n, m, bond=bond, **kwargs)
def compute_tube_radius(n, m, bond=None, **kwargs):
"""Alias for :func:`compute_rt`"""
return compute_rt(n, m, bond=bond, **kwargs)
def compute_tube_length(n, m, nz, bond=None, **kwargs):
"""Alias for :func:`compute_Lz`"""
return compute_Lz(n, m, nz, bond=bond, **kwargs)
[docs]def compute_tube_mass(n, m, nz, element1=None, element2=None, **kwargs):
"""Compute nanotube mass in **grams**.
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, float}
Number of nanotube unit cells
element1, element2 : {str, int}, optional
Element symbol or atomic number of basis
:class:`~sknano.core.atoms.Atom` 1 and 2
Returns
-------
float
Nanotube mass in **grams**.
Notes
-----
.. todo::
Handle different elements and perform accurate calculation by
determining number of atoms of each element.
"""
if not (isinstance(n, numbers.Real) or n >= 0):
raise TypeError('Expected an integer')
if not (isinstance(m, numbers.Real) or m >= 0):
raise TypeError('Expected an integer')
if not (isinstance(nz, numbers.Real) or nz > 0):
raise TypeError('Expected a real, positive number')
Natoms = compute_Natoms(n, m, nz)
if element1 is None:
element1 = 'C'
if element2 is None:
element2 = 'C'
atom1 = Atom(element1)
atom2 = Atom(element2)
mass = Natoms * (atom1.m + atom2.m) / 2
# there are 1.6605e-24 grams / Da
mass *= grams_per_Da
return mass