Source code for gyroid.grid

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

"""

import numpy as np
from numpy.linalg import inv

from .common import BRAVAIS,CARTESIAN
from .common import EPS,SMALL,LARGE

__all__ = ["Grid","wave_norm"]

[docs]class Grid(object): ''' A :class:`Grid` object represents a Discretized unit cell in reciprocal space. ''' def __init__(self,ngrid,g,lowBZ=-1,highBZ=1): ''' Initiator of :class:`Grid` :param ngrid: contains number of grids in each dimension :type ngrid: `numpy.array` with integers :param g: a :class:`Group` object :param lowBZ: low bound to find G in BZ, default to -1 :param highBZ: high bound to find G in BZ, default to 1 ''' self.dim = g.dim if np.size(ngrid) != g.dim: raise ValueError('Space dimension and the length of `ngrid` ' 'not match.') self.N = ngrid self.shape = g.shape self.lowBZ = lowBZ self.highBZ = highBZ self.__create_waves(g)
[docs] def to_BZ(self,G): ''' Shift a wave vector to the first Brillouin Zone (BZ). :param G: a wave vector :type G: `numpy.array` :returns: wave vector in BZ and its square magnitude. ''' if np.size(G) != self.dim: raise ValueError('The wave vector and Dimension of ' 'the grid not match in to_BZ.') if self.dim == 1: (i,) = G key = (i,) if not self.BZmap.has_key(key): ivec,ivec2 = self.__find_G_in_BZ(G) self.BZmap[key] = (ivec,ivec2) return self.BZmap[key] if self.dim == 2: (i,j) = G key = (i,j) if not self.BZmap.has_key(key): ivec,ivec2 = self.__find_G_in_BZ(G) self.BZmap[key] = (ivec,ivec2) return self.BZmap[key] if self.dim == 3: (i,j,k) = G key = (i,j,k) if not self.BZmap.has_key(key): ivec,ivec2 = self.__find_G_in_BZ(G) self.BZmap[key] = (ivec,ivec2) return self.BZmap[key]
[docs] def is_wave_cancel(self,G,g): ''' Check whether the wave vector is canceled. A wave is canceled if and only if following conditions are met: 1. Leaves **G** invariant (i.e. **G** . **R** == **G**) 2. Produces a non-zero phase, such that **G** . **t** % 1.0 != 0 :param G: a wave vector :type G: `numpy.array` :param g: a :class:`Group` object :rtype: True or False ''' for i in np.arange(g.order): Gp = np.dot(G,g.symm[i].R) # Pseudo-Spetral method Gp,Gp2 = self.to_BZ(Gp) if np.all(np.abs(Gp-G) < EPS): phase = np.dot(G,g.symm[i].t) % 1.0 # for cases phase=-1.0 - SMALL # (-1.0 - SMALL) % 1.0 ~ (1.0 - SMALL) if np.abs(phase-1.0) < EPS: phase -= 1.0 # wave canceled if phase not equal 0 if np.abs(phase) > EPS: return True return False
@property
[docs] def max_Gsq(self): ''' The maximun square of wave vector in the grid.''' length = SMALL if self.dim == 1: for (i,) in np.ndindex(self.N[0]): G = np.array([i]) G,G2 = self.to_BZ(G) if G2 > length: length = G2 if self.dim == 2: for (i,j) in np.ndindex(self.N[0],self.N[1]): G = np.array([i,j]) G,G2 = self.to_BZ(G) if G2 > length: length = G2 if self.dim == 3: for (i,j,k) in np.ndindex(self.N[0],self.N[1],self.N[2]): G = np.array([i,j,k]) G,G2 = self.to_BZ(G) if G2 > length: length = G2 return length
def __find_G_in_BZ(self,G): low = self.lowBZ high = self.highBZ G_try = G G_min = G Gsq_min = LARGE if self.dim == 1: for i in np.arange(high,low-1,-1): G_try = G + np.array([i]) * self.N Gsq = wave_norm(G_try,self.shape) if Gsq < Gsq_min: Gsq_min, G_min = Gsq, G_try if self.dim == 2: for i in np.arange(high,low-1,-1): for j in np.arange(high,low-1,-1): G_try = G + np.array([i,j]) * self.N Gsq = wave_norm(G_try,self.shape) if Gsq < Gsq_min: Gsq_min, G_min = Gsq, G_try if self.dim == 3: for i in np.arange(high,low-1,-1): for j in np.arange(high,low-1,-1): for k in np.arange(high,low-1,-1): G_try = G + np.array([i,j,k]) * self.N Gsq = wave_norm(G_try,self.shape) if Gsq < Gsq_min: Gsq_min, G_min = Gsq, G_try return G_min,Gsq_min def __create_waves(self,g): #Gsq_max = self.max_Gabs * self.max_Gabs #G_max = np.zeros(self.dim) #for i in np.arange(self.dim): # aa = np.sqrt(np.dot(self.shape.h[i],self.shape.h[i])) # G_max[i] = int(self.max_Gabs * aa / (2.0 * np.pi)) + 1 # Calculate number of effective waves # Pseudo-Spectral method w,G2 = None,None self.BZmap = {} if self.dim == 1: for i in np.arange(self.N[0]): ivec,ivec2 = self.__find_G_in_BZ(np.array([i])) self.BZmap[(i,)] = (ivec,ivec2) if not self.is_wave_cancel(ivec,g): if w is None: w = np.array([ivec]) G2 = np.array([ivec2]) else: w = np.append(w,[ivec],axis=0) G2 = np.append(G2,[ivec2],axis=0) if self.dim == 2: for (i,j) in np.ndindex(self.N[0],self.N[1]): ivec,ivec2 = self.__find_G_in_BZ(np.array([i,j])) self.BZmap[(i,j)] = (ivec,ivec2) if not self.is_wave_cancel(ivec,g): if w is None: w = np.array([ivec]) G2 = np.array([ivec2]) else: w = np.append(w,[ivec],axis=0) G2 = np.append(G2,[ivec2],axis=0) if self.dim == 3: for (i,j,k) in np.ndindex(self.N[0],self.N[1],self.N[2]): ivec,ivec2 = self.__find_G_in_BZ(np.array([i,j,k])) self.BZmap[(i,j,k)] = (ivec,ivec2) if not self.is_wave_cancel(ivec,g): if w is None: w = np.array([ivec]) G2 = np.array([ivec2]) else: w = np.append(w,[ivec],axis=0) G2 = np.append(G2,[ivec2],axis=0) # Sort G2 in ascending order, returned the corresponding indices w = w.T self.Nw = np.size(w,1) ind = np.argsort(G2) self.waves = w[:,ind] self.Gsq = G2[ind]
[docs]def wave_norm(G,shape): ''' Calculate the square magnitude of a wave vector **G** ^2. :param G: a wave vector with 1, 2, or 3 elements :type G: 1D `numpy.array` :param shape: a :class:`Shape` object :return: **G** ^2 :rtype: double ''' v = np.dot(G,shape.g) return np.dot(v,v)

Related Topics