Source code for gyroid.unitcell

# -*- coding: utf-8 -*-
"""
gyroid.unitcell
===============

:copyright: (c) 2012 by Yi-Xin Liu
:license: BSD, see LICENSE for more details.

"""

import numpy as np
from numpy.linalg import inv

from .common import BRAVAIS,CARTESIAN
from .common import CRYSTAL_SYSTEM1,CRYSTAL_SYSTEM2,CRYSTAL_SYSTEM3
from .common import LAMELLAR
from .common import SQUARE,RECTANGULAR,HEXAGONAL,OBLIQUE
from .common import CUBIC,TETRAGONAL,ORTHORHOMBIC,TRIGONAL,MONOCLINIC
from .common import TRICLINIC,DEFAULT

__all__ = ["UnitCell","Shape"]

[docs]class UnitCell(object): """ """ def __init__(self,dim,cell_type=DEFAULT,cell_param=None): """ if cell_type is missing, cell_param has no effect! """ self.dim = dim if dim == 1: if cell_type in CRYSTAL_SYSTEM1: self.type = cell_type self.__standard_cell_1D(cell_type,cell_param) else: raise ValueError("Unkonw crystal system for 1D space.") if dim == 2: if cell_type in CRYSTAL_SYSTEM2: self.type = cell_type self.__standard_cell_2D(cell_type,cell_param) else: raise ValueError("Unkonw crystal system for 2D space.") if dim == 3: if cell_type in CRYSTAL_SYSTEM3: self.type = cell_type self.__standard_cell_3D(cell_type,cell_param) else: raise ValueError("Unkonw crystal system for 3D space.") self.shape = self.__create_shape() def __create_shape(self): """ a,b,c - length of Bravais unit vector alpha, beta, gamma - angle between vectors b and c, c and a, and a and b, respectively. """ if self.dim == 1: return Shape(1,np.array([self.a])) if self.dim == 2: a = np.array([self.a, 0.0]) b = np.array([self.b*np.cos(self.gamma), self.b*np.sin(self.gamma)]) return Shape(2,a,b) if self.dim == 3: a = np.array([self.a, 0.0, 0.0]) b = np.array([self.b*np.cos(self.gamma), self.b*np.sin(self.gamma), 0.0]) cx = self.c*np.cos(self.beta) cy = self.c*(np.cos(self.alpha)- np.cos(self.beta)*np.cos(self.gamma)) cz = np.sqrt(self.c*self.c - cx*cx - cy*cy) c = np.array([cx,cy,cz]) return Shape(3,a,b,c) def __standard_cell_1D(self,cell_type,cp): if cell_type == LAMELLAR: if np.size(cp) < 1: raise ValueError("Lamellar crystal requires 1 parameters.") self.a = cp[0] elif cell_type == DEFAULT: self.a = 1.0 else: raise ValueError("Unknow 1D crystal system.") def __standard_cell_2D(self,cell_type,cp): pi2 = np.pi / 2.0 pi3 = 2.0 * np.pi / 3.0 if cell_type == SQUARE: if np.size(cp) < 1: raise ValueError("Square crystal requires 1 parameters.") self.a, self.b = cp[0] self.gamma = pi2 elif cell_type == RECTANGULAR: if np.size(cp) < 2: raise ValueError( "Rectangular crystal requires 2 parameters.") self.a, self.b = cp[0], cp[1] self.gamma = pi2 elif cell_type == HEXAGONAL: if np.size(cp) < 1: raise ValueError( "Hexagonal crystal requires 1 parameters.") self.a, self.b = cp[0], cp[0] self.gamma = pi3 elif cell_type == OBLIQUE: if np.size(cp) < 3: raise ValueError( "Oblique crystal requires 3 parameters.") self.a, self.b = cp[0], cp[1] self.gamma = cp[2] elif cell_type == DEFAULT: self.a, self.b = 1.0, 1.0 self.gamma = pi2 else: raise ValueError("Unknow 2D crystal system.") def __standard_cell_3D(self,cell_type,cp): pi2 = np.pi / 2.0 pi3 = 2.0 * np.pi / 3.0 if cell_type == CUBIC: if np.size(cp) < 1: raise ValueError("Cubic crystal requires 1 parameters.") self.a, self.b, self.c = cp[0], cp[0], cp[0] self.alpha, self.beta, self.gamma = pi2, pi2, pi2 elif cell_type == TETRAGONAL: if np.size(cp) < 2: raise ValueError( "Tetragonal crystal requires 2 parameters.") self.a, self.b, self.c = cp[0], cp[0], cp[1] self.alpha, self.beta, self.gamma = pi2, pi2, pi2 elif cell_type == ORTHORHOMBIC: if np.size(cp) < 3: raise ValueError( "Orthorhombic crystal requires 3 parameters.") self.a, self.b, self.c = cp[0], cp[1], cp[2] self.alpha, self.beta, self.gamma = pi2, pi2, pi2 elif cell_type == HEXAGONAL: if np.size(cp) < 2: raise ValueError( "Hexagonal crystal requires 3 parameters.") self.a, self.b, self.c = cp[0], cp[0], cp[1] self.alpha, self.beta, self.gamma = pi2, pi2, pi3 elif cell_type == TRIGONAL: if np.size(cp) < 2: raise ValueError( "Trigonal crystal requires 3 parameters.") self.a, self.b, self.c = cp[0], cp[0], cp[0] self.alpha, self.beta, self.gamma = cp[1], cp[1], cp[1] elif cell_type == MONOCLINIC: if np.size(cp) < 4: raise ValueError( "Monoclinic crystal requires 3 parameters.") self.a, self.b, self.c = cp[0], cp[1], cp[2] self.alpha, self.beta, self.gamma = pi2, cp[3], pi2 elif cell_type == TRICLINIC: if np.size(cp) < 6: raise ValueError( "Triclinic crystal requires 6 parameters.") self.a, self.b, self.c = cp[0], cp[1], cp[2] self.alpha, self.beta, self.gamma = cp[3], cp[4], cp[5] elif cell_type == DEFAULT: self.a, self.b, self.c = 1.0, 1.0, 1.0 self.alpha, self.beta, self.gamma = pi2, pi2, pi2 else: raise ValueError("Unknown 3D crystal system.")
[docs]class Shape(object): """ Shape matrix constructed from unit vectors in Cartesian Coordinate. The Morse convention is used. That is each row in the shape matrix represents a unit vector, e.g. h = (a1,a2,a3) where a_i = (x_i,y_i,z_i) is the unit vector of the Bravis lattice in Cartesian Coordinate. """ def __init__(self,dim,a1,a2=None,a3=None): self.dim = dim if dim==3 and np.size(a1)==3 and np.size(a2)==3 and np.size(a3)==3: self.m = np.array([a1,a2,a3]) elif dim==2 and np.size(a1)==2 and np.size(a2)==2: self.m = np.array([a1,a2]) elif dim==1 and np.size(a1)==1: self.m = np.array([a1]) else: raise ValueError( "Dimension and the number of unit vector not match")
[docs] def shift(self,t,basis_type): """ Shift position or translation vector so as to lie in the first unit cell. """ if basis_type == BRAVAIS: return t % 1.0 elif basis_type == CARTESIAN: cc = np.dot(self.g,t) / (2.0 * np.pi) return np.dot(self.h, cc % 1.0) else: raise ValueError("Unrecognized basis type when shift a vector.")
@property
[docs] def l(self): """ return (|a1|,|a2|,|a3|), the length vector. """ return np.sqrt(np.sum(self.m**2,axis=1))
@property
[docs] def h(self): """ The shape matrix in Real Space. """ return self.m
@property
[docs] def g(self): """ The shape matrix in Reciprocal Space. """ return 2.0 * np.pi * inv(self.m).T