Source code for buildamol.extensions.polymers.nanotubes

"""
The main function to make simple nanotubes.
"""

# This code directly uses the stuff from the nanotube tutorial notebook
# (see documentation)

import numpy as np
import buildamol.core as core

from . import polycarbons

__all__ = ["nanotube"]


[docs] def nanotube(n: int, k: int) -> core.Molecule: """ Make a graphene nanotube with n carbon atoms per ring layer Parameters ---------- n : int The number of carbon atoms per ring layer k : int The number of ring layers Returns ------- Molecule The nanotube """ angle = np.radians(32) # we can approximate the ring radius by the length and number of carbon atoms # given the formula: u = 2 * r * pi , where the circumference u is roughly # length * ring_size * cos(angle) (otherwise the bond lengths would be off) radius = (np.cos(angle) * polycarbons._length_C_C) * (n + 1) / (2 * np.pi) # now we can calculate the coordinates for the carbon and hydrogen atoms # in the ring theta = np.linspace(0, 2 * np.pi, n, endpoint=False) carbon_x = radius * np.cos(theta) carbon_y = radius * np.sin(theta) z = np.zeros(n) z[1::2] = np.sin(angle) * polycarbons._length_C_H # assembly half the unit ring ring = core.Molecule.new(id="RING", resname="RNG") Cs, cbonds = polycarbons._make_carbons(carbon_x, carbon_y, z) cbonds.append((f"C1", f"C{n}")) ring.add_atoms(*Cs) ring.add_bonds(*cbonds) # add the rest of the ring by copying and flipping the first half ring2 = ring.copy().move([0, 0, polycarbons._length_C_C]).flip("xy") ring.add_residues(ring2.get_residue(1)) ring.add_bonds(*ring2.get_bonds()) for i in range(0, n, 2): c = f"C{i+1}" a = ring.get_atom(c, residue=1) b = ring.get_atom(c, residue=2) ring.add_bond(a, b, 2) _min = min(i.coord[2] for i in ring.atoms) ring.move([0, 0, -_min]) height = max(i.coord[2] for i in ring.atoms) dz = polycarbons._length_C_C + height # the distance between the rings # ================================= # now we can stack the rings to form the nanotube nanotube = ring.copy() for i in range(k - 1): # get a new ring and move it to the correct position # (we move downward by the length of the ring...) other = ring.copy().move([0, 0, -dz * (i + 1)]) # add it to the nanotube nanotube.add_residues(*other.get_residues()) nanotube.add_bonds(*other.get_bonds()) # and add bonds between the incoming and the previous ring # (careful, here we use a shifted index, compared to the previous cell) for j in range(1, n + 1, 2): c = f"C{j+1}" a = nanotube.get_atom(c, residue=-2) b = nanotube.get_atom(c, residue=-3) nanotube.add_bond(a, b, 2) return nanotube
if __name__ == "__main__": nanotube(10)