2018-09-22 04:29:30 +03:00
from sympy . combinatorics import Permutation , PermutationGroup
Permutation . print_cyclic = True
import cmath
from cmath import exp , pi
from math import sqrt
import numpy as np
np . set_printoptions ( linewidth = 200 )
import qpms
import numbers
2019-02-25 14:21:09 +02:00
import re
2018-09-22 04:29:30 +03:00
ň = None
def grouprep_try ( tdict , src , im , srcgens , imgens , immultop = None , imcmp = None ) :
tdict [ src ] = im
for i in range ( len ( srcgens ) ) :
new_src = src * srcgens [ i ]
new_im = ( im * imgens [ i ] ) if ( immultop is None ) else immultop ( im , imgens [ i ] )
if new_src not in tdict . keys ( ) :
grouprep_try ( tdict , new_src , new_im , srcgens , imgens , immultop , imcmp )
elif ( ( new_im != tdict [ new_src ] ) if ( imcmp is None ) else ( not imcmp ( new_im , tdict [ new_src ] ) ) ) : # check consistency
print ( src , ' * ' , srcgens [ i ] , ' --> ' , new_src )
print ( im )
print ( ' * ' )
print ( imgens [ i ] )
print ( ' --> ' )
print ( new_im )
print ( ' != ' )
print ( tdict [ new_src ] )
raise ValueError ( " Homomorphism inconsistency detected " )
return
2018-12-17 12:14:18 +02:00
class SVWFPointGroupInfo : # only for point groups, coz in svwf_rep() I use I_tyty, not I_ptypty or something alike
def __init__ ( self ,
name ,
permgroupgens , # permutation group generators
irrepgens_dict , # dictionary with irrep generators,
svwf_rep_gen_func , # function that generates a tuple with svwf representation generators
2019-02-25 14:21:09 +02:00
rep3d_gens = None , # 3d (quaternion) representation generators of a point group: sequence of qpms.irep3 instances
2018-12-17 12:14:18 +02:00
) :
self . name = name
self . permgroupgens = permgroupgens
self . permgroup = PermutationGroup ( * permgroupgens )
self . irrepgens_dict = irrepgens_dict
self . svwf_rep_gen_func = svwf_rep_gen_func
self . irreps = dict ( )
for irrepname , irrepgens in irrepgens_dict . items ( ) :
is1d = isinstance ( irrepgens [ 0 ] , int )
irrepdim = 1 if is1d else irrepgens [ 0 ] . shape [ 0 ]
self . irreps [ irrepname ] = generate_grouprep ( self . permgroup ,
1 if is1d else np . eye ( irrepdim ) ,
permgroupgens , irrepgens ,
immultop = None if is1d else np . dot ,
imcmp = None if is1d else np . allclose
)
2019-02-21 17:38:43 +02:00
self . rep3d_gens = rep3d_gens
self . rep3d = None if rep3d_gens is None else generate_grouprep (
self . permgroup ,
2019-03-02 20:22:29 +02:00
qpms . IRot3 ( ) ,
2019-02-21 17:38:43 +02:00
permgroupgens , rep3d_gens ,
2019-02-25 14:21:09 +02:00
immultop = None , imcmp = ( lambda x , y : x . isclose ( y ) )
2019-02-21 17:38:43 +02:00
)
2018-12-17 12:14:18 +02:00
def svwf_rep ( self , lMax , * rep_gen_func_args , * * rep_gen_func_kwargs ) :
'''
This method generates full SVWF ( reducible ) representation of the group .
'''
svwfgens = self . svwf_rep_gen_func ( lMax , * rep_gen_func_args , * * rep_gen_func_kwargs )
my , ny = qpms . get_mn_y ( lMax )
nelem = len ( my )
I_tyty = np . moveaxis ( np . eye ( 2 ) [ : , : , ň , ň ] * np . eye ( nelem ) , 2 , 1 )
return generate_grouprep ( self . permgroup , I_tyty , self . permgroupgens , svwfgens , immultop = mmult_tyty , imcmp = np . allclose )
def svwf_irrep_projectors ( self , lMax , * rep_gen_func_args , * * rep_gen_func_kwargs ) :
return gen_point_group_svwfrep_projectors ( self . permgroup , self . irreps , self . svwf_rep ( lMax , * rep_gen_func_args , * * rep_gen_func_kwargs ) )
2018-12-17 16:46:51 +02:00
# alternative, for comparison and testing; should give the same results
def svwf_irrep_projectors2 ( self , lMax , * rep_gen_func_args , * * rep_gen_func_kwargs ) :
2018-12-17 17:27:04 +02:00
return gen_point_group_svwfrep_projectors2 ( self . permgroup , self . irreps , self . svwf_rep ( lMax , * rep_gen_func_args , * * rep_gen_func_kwargs ) )
def svwf_irrep_projectors2_w_bases ( self , lMax , * rep_gen_func_args , * * rep_gen_func_kwargs ) :
return gen_point_group_svwfrep_projectors2_w_bases ( self . permgroup , self . irreps , self . svwf_rep ( lMax , * rep_gen_func_args , * * rep_gen_func_kwargs ) )
2019-02-21 17:38:43 +02:00
def generate_c_source ( self ) :
'''
Generates a string with a chunk of C code with a definition of a qpms_finite_group_t instance .
See also groups . h .
'''
permlist = list ( self . permgroup . elements ) # all elements ordered
order = len ( permlist )
permindices = { perm : i for i , perm in enumerate ( permlist ) } # 'invert' permlist
identity = self . permgroup . identity
s = " { \n "
# char *name
s + = ' " %s " , // name \n ' % self . name
# size_t order;
s + = ' %d , // order \n ' % order
# qpms_gmi_t idi
s + = ' %d , // idi \n ' % permindices [ identity ]
# qpms_gmi_t *mt
2019-03-02 23:26:49 +02:00
s + = ' (qpms_gmi_t[]) { // mt \n '
2019-02-21 17:38:43 +02:00
for i in range ( order ) :
ss = ' , ' . join ( [ str ( permindices [ permlist [ i ] * permlist [ j ] ] ) for j in range ( order ) ] )
s + = ' ' + ss + ' , \n '
s + = ' }, \n '
2019-02-26 08:15:03 +02:00
# qpms_gmi_t *invi
2019-03-02 23:26:49 +02:00
s + = ' (qpms_gmi_t[]) { // invi \n '
2019-02-26 08:15:03 +02:00
s + = ' ' + ' , ' . join ( [ str ( permindices [ permlist [ j ] * * - 1 ] ) for j in range ( order ) ] )
s + = ' \n }, \n '
2019-02-21 17:38:43 +02:00
# qpms_gmi_t *gens
2019-03-02 23:26:49 +02:00
s + = ' (qpms_gmi_t[]) { ' + ' , ' . join ( [ str ( permindices [ g ] ) for g in self . permgroupgens ] ) + ' }, // gens \n '
2019-02-21 17:38:43 +02:00
# int ngens
s + = ' %d , // ngens \n ' % len ( self . permgroupgens )
# qpms_permutation_t permrep[]
2019-03-02 23:26:49 +02:00
s + = ' (qpms_permutation_t[]) { // permrep \n '
2019-02-21 17:38:43 +02:00
for i in range ( order ) :
s + = ' " %s " , \n ' % str ( permlist [ i ] )
2019-02-26 08:15:03 +02:00
s + = ' }, \n '
2019-02-21 17:38:43 +02:00
# char **elemlabels
s + = ' NULL, // elemlabels \n '
# int permrep_nelem
s + = ' %d , // permrep_nelem \n ' % self . permgroup . degree
2019-02-25 14:21:09 +02:00
# qpms_irot3_t rep3d[]
if self . rep3d is None :
2019-02-21 17:38:43 +02:00
s + = ' NULL, // rep3d TODO!!! \n '
else :
2019-03-02 23:26:49 +02:00
s + = ' (qpms_irot3_t[]) { // rep3d \n '
2019-02-21 17:38:43 +02:00
for i in range ( order ) :
2019-02-25 14:21:09 +02:00
s + = ' ' + self . rep3d [ permlist [ i ] ] . crepr ( ) + ' , \n '
2019-02-21 17:38:43 +02:00
s + = ' }, \n '
# int nirreps
s + = ' %d , // nirreps \n ' % len ( self . irreps )
# struct qpms_finite_grep_irrep_t irreps[]
2019-03-02 23:26:49 +02:00
s + = ' (struct qpms_finite_group_irrep_t[]) { // irreps \n '
2019-02-21 17:38:43 +02:00
for irname , irrep in self . irreps . items ( ) :
s + = ' { \n '
is1d = isinstance ( irrep [ identity ] , ( int , float , complex ) )
dim = 1 if is1d else irrep [ identity ] . shape [ 0 ]
# int dim
s + = ' %d , // dim \n ' % dim
# char name[]
s + = ' " %s " , //name \n ' % re . escape ( irname )
# complex double *m
if ( is1d ) :
2019-03-02 23:26:49 +02:00
s + = ' (complex double []) { ' + ' , ' . join ( [ str ( irrep [ permlist [ i ] ] ) for i in range ( order ) ] ) + ' } // m \n '
2019-02-21 17:38:43 +02:00
else :
2019-03-02 23:26:49 +02:00
s + = ' (complex double []) { \n '
2019-02-21 17:38:43 +02:00
for i in range ( order ) :
s + = ' // %s \n ' % str ( permlist [ i ] )
for row in range ( dim ) :
s + = ' '
for col in range ( dim ) :
s + = ' %s , ' % re . sub ( ' j ' , ' *I ' , str ( irrep [ permlist [ i ] ] [ row , col ] ) )
s + = ' \n '
mat = irrep [ permlist [ i ] ]
s + = ' } \n '
#s += ' %d, // dim\n' %
s + = ' }, \n '
s + = ' } // end of irreps \n '
s + = ' } '
return s
2018-12-17 12:14:18 +02:00
2018-09-22 04:29:30 +03:00
# srcgroup is expected to be PermutationGroup and srcgens of the TODO
# imcmp returns True if two elements of the image group are 'equal', otherwise False
def generate_grouprep ( srcgroup , im_identity , srcgens , imgens , immultop = None , imcmp = None ) :
sz = srcgens [ 0 ] . size
for g in srcgens :
if g . size != sz :
raise ValueError ( ' All the generators must have the same " size " ' )
tdict = dict ( )
grouprep_try ( tdict , Permutation ( sz - 1 ) , im_identity , srcgens , imgens , immultop = immultop , imcmp = imcmp )
if ( srcgroup . order ( ) != len ( tdict . keys ( ) ) ) : # basic check
raise ValueError ( ' The supplied " generators " failed to generate the preimage group: ' ,
srcgroup . order ( ) , " != " , len ( tdict . keys ( ) ) )
return tdict
2018-12-17 12:14:18 +02:00
# matrices appearing in 2d representations of common groups as used in Bradley, Cracknell p. 61 (with arabic names instead of greek, because lambda is a keyword)
2018-09-22 04:29:30 +03:00
epsilon = np . eye ( 2 )
alif = np . array ( ( ( - 1 / 2 , - sqrt ( 3 ) / 2 ) , ( sqrt ( 3 ) / 2 , - 1 / 2 ) ) )
bih = np . array ( ( ( - 1 / 2 , sqrt ( 3 ) / 2 ) , ( - sqrt ( 3 ) / 2 , - 1 / 2 ) ) )
2018-12-17 12:14:18 +02:00
kaf = np . array ( ( ( 0 , 1 ) , ( 1 , 0 ) ) )
2018-09-22 04:29:30 +03:00
lam = np . array ( ( ( 1 , 0 ) , ( 0 , - 1 ) ) )
2018-12-17 12:14:18 +02:00
ra = np . array ( ( ( 0 , - 1 ) , ( 1 , 0 ) ) )
2018-09-22 04:29:30 +03:00
mim = np . array ( ( ( - 1 / 2 , - sqrt ( 3 ) / 2 ) , ( - sqrt ( 3 ) / 2 , 1 / 2 ) ) )
nun = np . array ( ( ( - 1 / 2 , sqrt ( 3 ) / 2 ) , ( sqrt ( 3 ) / 2 , 1 / 2 ) ) )
2018-12-17 12:14:18 +02:00
def mmult_tyty ( a , b ) :
return ( qpms . apply_ndmatrix_left ( a , b , ( - 4 , - 3 ) ) )
def mmult_ptypty ( a , b ) :
return ( qpms . apply_ndmatrix_left ( a , b , ( - 6 , - 5 , - 4 ) ) )
2018-12-17 16:46:51 +02:00
def gen_point_group_svwfrep_irreps ( permgroup , matrix_irreps_dict , sphrep_full ) :
2018-12-17 12:14:18 +02:00
'''
Gives the projection operators $ P_kl ( ' \ Gamma ' ) $ from Dresselhaus ( 4.28 )
for all irreps $ \Gamma $ of D3h . ;
as an array with indices [ k , l , t , y , t , y ]
Example of creating last argument :
sphrep_full = generate_grouprep ( D3h_permgroup , I_tyty , D3h_srcgens , [ C3_tyty , vfl_tyty , zfl_tyty ] ,
immultop = mmult_tyty , imcmp = np . allclose )
'''
order = permgroup . order ( )
sphreps = dict ( )
nelem = sphrep_full [ permgroup [ 0 ] ] . shape [ - 1 ] # quite ugly hack
for repkey , matrixrep in matrix_irreps_dict . items ( ) :
arepmatrix = matrixrep [ permgroup [ 0 ] ] # just one of the matrices to get the shape etc
if isinstance ( arepmatrix , numbers . Number ) :
dim = 1 # repre dimension
preprocess = lambda x : np . array ( [ [ x ] ] )
elif isinstance ( arepmatrix , np . ndarray ) :
if ( len ( arepmatrix . shape ) ) != 2 or arepmatrix . shape [ 0 ] != arepmatrix . shape [ 1 ] :
raise ValueError ( " Arrays representing irrep matrices must be of square shape " )
dim = arepmatrix . shape [ 0 ]
preprocess = lambda x : x
else :
raise ValueError ( " Irrep is not a square array or number " )
sphrep = np . zeros ( ( dim , dim , 2 , nelem , 2 , nelem ) , dtype = complex )
for i in permgroup . elements :
sphrep + = preprocess ( matrixrep [ i ] ) . conj ( ) . transpose ( ) [ : , : , ň , ň , ň , ň ] * sphrep_full [ i ]
sphrep * = dim / order
# clean the nonexact values here
for x in [ 0 , 0.5 , - 0.5 , 0.5 j , - 0.5 j ] :
sphrep [ np . isclose ( sphrep , x ) ] = x
sphreps [ repkey ] = sphrep
return sphreps
2018-12-17 16:46:51 +02:00
def gen_point_group_svwfrep_projectors ( permgroup , matrix_irreps_dict , sphrep_full ) :
'''
The same as gen_point_group_svwfrep_irreps , but summed over the kl diagonal , so
one gets single projector onto each irrep space and the arrays have indices
[ t , y , t , y ]
'''
summedprojs = dict ( )
for repi , W in gen_point_group_svwfrep_irreps ( permgroup , matrix_irreps_dict , sphrep_full ) . items ( ) :
irrepd = W . shape [ 0 ]
if irrepd == 1 :
mat = np . reshape ( W , W . shape [ - 4 : ] )
else :
mat = np . zeros ( W . shape [ - 4 : ] , dtype = complex ) # TODO the result should be real — check!
for d in range ( irrepd ) :
mat + = W [ d , d ]
if not np . allclose ( mat . imag , 0 ) :
raise ValueError ( " The imaginary part of the resulting projector should be zero, damn! " )
else :
summedprojs [ repi ] = mat . real
return summedprojs
2018-12-17 17:27:04 +02:00
def gen_point_group_svwfrep_projectors2_w_bases ( permgroup , matrix_irreps_dict , sphrep_full ) :
return gen_point_group_svwfrep_projectors2 ( permgroup , matrix_irreps_dict , sphrep_full , do_bases = True )
2018-12-17 16:46:51 +02:00
def gen_point_group_svwfrep_projectors2 ( permgroup , matrix_irreps_dict , sphrep_full , do_bases = False ) :
'''
an approach as in gen_hexlattice_Kpoint_svwf_rep_projectors ; for comparison and testing
'''
if ( do_bases ) :
bases = dict ( )
projectors = dict ( )
for repi , W in gen_point_group_svwfrep_irreps ( permgroup , matrix_irreps_dict , sphrep_full ) . items ( ) :
2018-12-17 17:27:04 +02:00
nelem = W . shape [ - 1 ] # however, this should change between iterations
2018-12-17 16:46:51 +02:00
totalvecs = 0
tmplist = list ( )
for t in ( 0 , 1 ) :
for y in range ( nelem ) :
for ai in range ( W . shape [ 0 ] ) :
for bi in range ( W . shape [ 1 ] ) :
v = np . zeros ( ( 2 , nelem ) )
v [ t , y ] = 1
v1 = np . tensordot ( W [ ai , bi ] , v , axes = ( [ - 2 , - 1 ] , [ 0 , 1 ] ) )
if not np . allclose ( v1 , 0 ) :
v1 = normalize ( v1 )
for v2 in tmplist :
dot = np . tensordot ( v1 . conjugate ( ) , v2 , axes = ( [ - 2 , - 1 ] , [ 0 , 1 ] ) )
if not ( np . allclose ( dot , 0 ) ) :
if not np . allclose ( np . abs ( dot ) , 1 ) :
raise ValueError ( ' You have to fix this piece of code. ' )
break
else :
totalvecs + = 1
tmplist . append ( v1 )
2018-12-17 17:27:04 +02:00
theprojector = np . zeros ( ( 2 , nelem , 2 , nelem ) , dtype = float )
2018-12-17 16:46:51 +02:00
if do_bases :
thebasis = np . zeros ( ( len ( tmplist ) , 2 , nelem ) , dtype = complex )
for i , v in enumerate ( tmplist ) :
thebasis [ i ] = v
2018-12-17 17:27:04 +02:00
bases [ repi ] = thebasis
2018-12-17 16:46:51 +02:00
for v in tmplist :
2018-12-17 17:27:04 +02:00
theprojector + = ( v [ : , : , ň , ň ] * v . conjugate ( ) [ ň , ň , : , : ] ) . real
2018-12-17 16:46:51 +02:00
for x in [ 0 , 1 , - 1 , sqrt ( .5 ) , - sqrt ( .5 ) , .5 , - .5 ] :
theprojector [ np . isclose ( theprojector , x ) ] = x
2018-12-17 17:27:04 +02:00
projectors [ repi ] = theprojector
2018-12-17 16:46:51 +02:00
if do_bases :
return projectors , bases
else :
return projectors
2018-12-17 12:14:18 +02:00
# Group D3h; mostly legacy code (kept because of the the honeycomb lattice K-point code, whose generalised version not yet implemented)
2018-09-22 04:29:30 +03:00
# Note that the size argument of permutations is necessary, otherwise e.g. c*c and b*b would not be evaluated equal
# N.B. the weird elements as Permutation(N) – it means identity permutation of size N+1.
rot3_perm = Permutation ( 0 , 1 , 2 , size = 5 ) # C3 rotation
xflip_perm = Permutation ( 0 , 2 , size = 5 ) # vertical mirror
zflip_perm = Permutation ( 3 , 4 , size = 5 ) # horizontal mirror
D3h_srcgens = [ rot3_perm , xflip_perm , zflip_perm ]
2018-12-17 12:14:18 +02:00
D3h_permgroup = PermutationGroup ( * D3h_srcgens ) # D3h
2018-09-22 04:29:30 +03:00
D3h_irreps = {
# Bradley, Cracknell p. 61
2018-09-26 04:17:01 +03:00
" E ' " : generate_grouprep ( D3h_permgroup , epsilon , D3h_srcgens , [ alif , lam , epsilon ] , immultop = np . dot , imcmp = np . allclose ) ,
" E ' ' " : generate_grouprep ( D3h_permgroup , epsilon , D3h_srcgens , [ alif , lam , - epsilon ] , immultop = np . dot , imcmp = np . allclose ) ,
# Bradley, Cracknell p. 59, or Dresselhaus, Table A.14 (p. 482)
" A1 ' " : generate_grouprep ( D3h_permgroup , 1 , D3h_srcgens , [ 1 , 1 , 1 ] ) ,
" A2 ' " : generate_grouprep ( D3h_permgroup , 1 , D3h_srcgens , [ 1 , - 1 , 1 ] ) ,
" A1 ' ' " : generate_grouprep ( D3h_permgroup , 1 , D3h_srcgens , [ 1 , - 1 , - 1 ] ) ,
" A2 ' ' " : generate_grouprep ( D3h_permgroup , 1 , D3h_srcgens , [ 1 , 1 , - 1 ] ) ,
2018-09-22 04:29:30 +03:00
}
2018-12-17 12:14:18 +02:00
#TODO lepší název fce; legacy, use group_info['D3h'].generate_grouprep() instead
2018-10-03 09:25:05 +03:00
def gen_point_D3h_svwf_rep ( lMax , vflip = ' x ' ) :
2018-09-26 04:17:01 +03:00
'''
Gives the projection operators $ P_kl ( ' \ Gamma ' ) $ from Dresselhaus ( 4.28 )
for all irreps $ \Gamma $ of D3h . ;
as an array with indices [ k , l , t , y , t , y ]
'''
2018-09-22 04:29:30 +03:00
my , ny = qpms . get_mn_y ( lMax )
nelem = len ( my )
C3_yy = qpms . WignerD_yy_fromvector ( lMax , np . array ( [ 0 , 0 , 2 * pi / 3 ] ) )
C3_tyty = np . moveaxis ( np . eye ( 2 ) [ : , : , ň , ň ] * C3_yy , 2 , 1 )
zfl_tyty = qpms . zflip_tyty ( lMax )
2018-10-03 09:25:05 +03:00
#yfl_tyty = qpms.yflip_tyty(lMax)
#xfl_tyty = qpms.xflip_tyty(lMax)
vfl_tyty = qpms . yflip_tyty ( lMax ) if vflip == ' y ' else qpms . xflip_tyty ( lMax )
2018-09-22 04:29:30 +03:00
I_tyty = np . moveaxis ( np . eye ( 2 ) [ : , : , ň , ň ] * np . eye ( nelem ) , 2 , 1 )
order = D3h_permgroup . order ( )
2018-10-03 09:25:05 +03:00
sphrep_full = generate_grouprep ( D3h_permgroup , I_tyty , D3h_srcgens , [ C3_tyty , vfl_tyty , zfl_tyty ] ,
2018-09-22 04:29:30 +03:00
immultop = mmult_tyty , imcmp = np . allclose )
sphreps = dict ( )
for repkey , matrixrep in D3h_irreps . items ( ) :
arepmatrix = matrixrep [ rot3_perm ] # just one of the matrices to get the shape etc
if isinstance ( arepmatrix , numbers . Number ) :
dim = 1 # repre dimension
preprocess = lambda x : np . array ( [ [ x ] ] )
elif isinstance ( arepmatrix , np . ndarray ) :
if ( len ( arepmatrix . shape ) ) != 2 or arepmatrix . shape [ 0 ] != arepmatrix . shape [ 1 ] :
raise ValueError ( " Arrays representing irrep matrices must be of square shape " )
dim = arepmatrix . shape [ 0 ]
preprocess = lambda x : x
else :
raise ValueError ( " Irrep is not a square array or number " )
sphrep = np . zeros ( ( dim , dim , 2 , nelem , 2 , nelem ) , dtype = complex )
for i in D3h_permgroup . elements :
sphrep + = preprocess ( matrixrep [ i ] ) . conj ( ) . transpose ( ) [ : , : , ň , ň , ň , ň ] * sphrep_full [ i ]
sphrep * = dim / order
# clean the nonexact values here
for x in [ 0 , 0.5 , - 0.5 , 0.5 j , - 0.5 j ] :
sphrep [ np . isclose ( sphrep , x ) ] = x
sphreps [ repkey ] = sphrep
return sphreps
2018-10-03 09:25:05 +03:00
def gen_hexlattice_Kpoint_svwf_rep ( lMax , psi , vflip = ' x ' ) :
2018-09-22 04:29:30 +03:00
my , ny = qpms . get_mn_y ( lMax )
nelem = len ( my )
C3_yy = qpms . WignerD_yy_fromvector ( lMax , np . array ( [ 0 , 0 , 2 * pi / 3 ] ) )
C3_tyty = np . moveaxis ( np . eye ( 2 ) [ : , : , ň , ň ] * C3_yy , 2 , 1 )
zfl_tyty = qpms . zflip_tyty ( lMax )
2018-10-03 09:25:05 +03:00
#yfl_tyty = qpms.yflip_tyty(lMax)
#xfl_tyty = qpms.xflip_tyty(lMax)
vfl_tyty = qpms . yflip_tyty ( lMax ) if vflip == ' y ' else qpms . xflip_tyty ( lMax )
2018-09-22 04:29:30 +03:00
I_tyty = np . moveaxis ( np . eye ( 2 ) [ : , : , ň , ň ] * np . eye ( nelem ) , 2 , 1 )
hex_C3_K_ptypty = np . diag ( [ exp ( - psi * 1 j * 2 * pi / 3 ) , exp ( + psi * 1 j * 2 * pi / 3 ) ] ) [ : , ň , ň , : , ň , ň ] * C3_tyty [ ň , : , : , ň , : , : ]
hex_zfl_ptypty = np . eye ( 2 ) [ : , ň , ň , : , ň , ň ] * zfl_tyty [ ň , : , : , ň , : , : ]
2018-10-03 09:25:05 +03:00
#hex_xfl_ptypty = np.array([[0,1],[1,0]])[:,ň,ň,:,ň,ň] * xfl_tyty[ň,:,:,ň,:,:]
hex_vfl_ptypty = np . array ( [ [ 0 , 1 ] , [ 1 , 0 ] ] ) [ : , ň , ň , : , ň , ň ] * vfl_tyty [ ň , : , : , ň , : , : ]
2018-09-22 04:29:30 +03:00
hex_I_ptypty = np . eye ( ( 2 * 2 * nelem ) ) . reshape ( ( 2 , 2 , nelem , 2 , 2 , nelem ) )
order = D3h_permgroup . order ( )
2018-10-03 09:25:05 +03:00
hex_K_sphrep_full = generate_grouprep ( D3h_permgroup , hex_I_ptypty , D3h_srcgens , [ hex_C3_K_ptypty , hex_vfl_ptypty , hex_zfl_ptypty ] ,
2018-09-22 04:29:30 +03:00
immultop = mmult_ptypty , imcmp = np . allclose )
hex_K_sphreps = dict ( )
for repkey , matrixrep in D3h_irreps . items ( ) :
arepmatrix = matrixrep [ rot3_perm ] # just one of the matrices to get the shape etc
if isinstance ( arepmatrix , numbers . Number ) :
dim = 1 # repre dimension
preprocess = lambda x : np . array ( [ [ x ] ] )
elif isinstance ( arepmatrix , np . ndarray ) :
if ( len ( arepmatrix . shape ) ) != 2 or arepmatrix . shape [ 0 ] != arepmatrix . shape [ 1 ] :
raise ValueError ( " Arrays representing irrep matrices must be of square shape " )
dim = arepmatrix . shape [ 0 ]
preprocess = lambda x : x
else :
raise ValueError ( " Irrep is not a square array or number " )
sphrep = np . zeros ( ( dim , dim , 2 , 2 , nelem , 2 , 2 , nelem ) , dtype = complex )
for i in D3h_permgroup . elements :
sphrep + = preprocess ( matrixrep [ i ] ) . conj ( ) . transpose ( ) [ : , : , ň , ň , ň , ň , ň , ň ] * hex_K_sphrep_full [ i ]
sphrep * = dim / order
# clean the nonexact values here
for x in [ 0 , 0.5 , - 0.5 , 0.5 j , - 0.5 j ] :
sphrep [ np . isclose ( sphrep , x ) ] = x
hex_K_sphreps [ repkey ] = sphrep
return hex_K_sphreps
def normalize ( v ) :
norm = np . linalg . norm ( v . reshape ( ( np . prod ( v . shape ) , ) ) , ord = 2 )
if norm == 0 :
return v * np . nan
return v / norm
2018-10-03 09:25:05 +03:00
def gen_hexlattice_Kpoint_svwf_rep_projectors ( lMax , psi , vflip = ' x ' , do_bases = False ) :
2018-09-22 04:29:30 +03:00
nelem = lMax * ( lMax + 2 )
projectors = dict ( )
2018-09-24 00:21:15 +03:00
if do_bases :
bases = dict ( )
2018-10-03 09:25:05 +03:00
for repi , W in gen_hexlattice_Kpoint_svwf_rep ( lMax , psi , vflip = vflip ) . items ( ) :
2018-09-22 04:29:30 +03:00
totalvecs = 0
tmplist = list ( )
for p in ( 0 , 1 ) :
for t in ( 0 , 1 ) :
for y in range ( nelem ) :
for ai in range ( W . shape [ 0 ] ) :
for bi in range ( W . shape [ 1 ] ) :
v = np . zeros ( ( 2 , 2 , nelem ) )
v [ p , t , y ] = 1
#v = np.ones((2,2,nelem))
v1 = np . tensordot ( W [ ai , bi ] , v , axes = ( [ - 3 , - 2 , - 1 ] , [ 0 , 1 , 2 ] ) )
if not np . allclose ( v1 , 0 ) :
v1 = normalize ( v1 )
for v2 in tmplist :
dot = np . tensordot ( v1 . conjugate ( ) , v2 , axes = ( [ - 3 , - 2 , - 1 ] , [ 0 , 1 , 2 ] ) )
if not np . allclose ( dot , 0 ) :
if not np . allclose ( np . abs ( dot ) , 1 ) :
raise ValueError ( ' You have to fix this piece of code. ' ) # TODO maybe I should make sure that the absolute value is around 1
break
else :
totalvecs + = 1
tmplist . append ( v1 )
#for index, x in np.ndenumerate(v1):
# if x!=0:
# print(index, x)
#print('----------')
theprojector = np . zeros ( ( 2 , 2 , nelem , 2 , 2 , nelem ) , dtype = float )
2018-09-24 00:21:15 +03:00
if do_bases :
thebasis = np . zeros ( ( len ( tmplist ) , 2 , 2 , nelem ) , dtype = complex )
for i , v in enumerate ( tmplist ) :
thebasis [ i ] = v
bases [ repi ] = thebasis
2018-09-22 04:29:30 +03:00
for v in tmplist :
theprojector + = ( v [ : , : , : , ň , ň , ň ] * v . conjugate ( ) [ ň , ň , ň , : , : , : ] ) . real # TODO check is it possible to have imaginary elements?
for x in [ 0 , 1 , - 1 , sqrt ( 0.5 ) , - sqrt ( 0.5 ) , 0.5 , - 0.5 ] :
theprojector [ np . isclose ( theprojector , x ) ] = x
projectors [ repi ] = theprojector
2018-09-24 00:21:15 +03:00
if do_bases :
return projectors , bases
else :
return projectors
2018-09-22 04:29:30 +03:00
2018-12-17 12:14:18 +02:00
point_group_info = { # representation info of some useful point groups
2019-03-02 23:26:49 +02:00
# TODO real trivial without generators
' trivial_g ' : SVWFPointGroupInfo ( ' trivial_g ' ,
# permutation group generators
( # I put here the at least the identity for now (it is reduntant, but some functions are not robust enough to have an empty set of generators
Permutation ( ) ,
) ,
# dictionary with irrep generators
{
" A " : ( 1 , ) ,
} ,
# function that generates a tuple with svwf representation generators
lambda lMax : ( qpms . identity_tyty ( lMax ) , ) ,
# quaternion rep generators
rep3d_gens = (
qpms . IRot3 . identity ( ) ,
)
) ,
2018-12-17 12:14:18 +02:00
' C2v ' : SVWFPointGroupInfo ( ' C2v ' ,
# permutation group generators
( Permutation ( 0 , 1 , size = 4 ) ( 2 , 3 ) , # x -> - x mirror operation (i.e. yz mirror plane)
Permutation ( 0 , 3 , size = 4 ) ( 1 , 2 ) , # y -> - y mirror operation (i.e. xz mirror plane)
) ,
# dictionary with irrep generators
{
# Bradley, Cracknell p. 58; not sure about the labels / axes here
' A1 ' : ( 1 , 1 ) ,
' B2 ' : ( - 1 , 1 ) ,
' A2 ' : ( - 1 , - 1 ) ,
' B1 ' : ( 1 , - 1 ) ,
} ,
# function that generates a tuple with svwf representation generators
2019-02-25 14:21:09 +02:00
lambda lMax : ( qpms . xflip_tyty ( lMax ) , qpms . yflip_tyty ( lMax ) ) ,
# quaternion rep generators
rep3d_gens = (
2019-03-02 20:22:29 +02:00
qpms . IRot3 . xflip ( ) ,
qpms . IRot3 . yflip ( ) ,
2019-02-25 14:21:09 +02:00
)
2018-12-17 12:14:18 +02:00
) ,
' D2h ' : SVWFPointGroupInfo ( ' D2h ' ,
# permutation group generators
( Permutation ( 0 , 1 , size = 6 ) ( 2 , 3 ) , # x -> - x mirror operation (i.e. yz mirror plane)
Permutation ( 0 , 3 , size = 6 ) ( 1 , 2 ) , # y -> - y mirror operation (i.e. xz mirror plane)
2018-12-25 22:34:37 +02:00
# ^^^ btw, I guess that Permutation(0,1, size=6) and Permutation(2,3, size=6) would
# do exactly the same job (they should; CHECK)
2018-12-17 12:14:18 +02:00
Permutation ( 4 , 5 , size = 6 ) # z -> - z mirror operation (i.e. xy mirror plane)
) ,
# dictionary with irrep generators
{
# Product of C2v and zflip; not sure about the labels / axes here
" A1 ' " : ( 1 , 1 , 1 ) ,
" B2 ' " : ( - 1 , 1 , 1 ) ,
" A2 ' " : ( - 1 , - 1 , 1 ) ,
" B1 ' " : ( 1 , - 1 , 1 ) ,
" A1 ' ' " : ( - 1 , - 1 , - 1 ) ,
" B2 ' ' " : ( 1 , - 1 , - 1 ) ,
" A2 ' ' " : ( 1 , 1 , - 1 ) ,
" B1 ' ' " : ( - 1 , 1 , - 1 ) ,
} ,
# function that generates a tuple with svwf representation generators
2019-02-25 14:21:09 +02:00
lambda lMax : ( qpms . xflip_tyty ( lMax ) , qpms . yflip_tyty ( lMax ) , qpms . zflip_tyty ( lMax ) ) ,
# quaternion rep generators
rep3d_gens = (
2019-03-02 20:22:29 +02:00
qpms . IRot3 . xflip ( ) ,
qpms . IRot3 . yflip ( ) ,
qpms . IRot3 . zflip ( ) ,
2019-02-25 14:21:09 +02:00
)
2018-12-17 12:14:18 +02:00
) ,
' C4v ' : SVWFPointGroupInfo ( ' C4v ' ,
# permutation group generators
( Permutation ( 0 , 1 , 2 , 3 , size = 4 ) , #C4 rotation
Permutation ( 0 , 1 , size = 4 ) ( 2 , 3 ) ) , # x -> - x mirror operation (i.e. yz mirror plane)
# dictionary with irrep generators
{
# Bradley, Cracknell p. 62
' E ' : ( ra , - lam ) ,
# Bradley, Cracknell p. 59, or Dresselhaus, Table A.18
' A1 ' : ( 1 , 1 ) ,
' A2 ' : ( 1 , - 1 ) ,
' B1 ' : ( - 1 , 1 ) ,
' B2 ' : ( - 1 , - 1 ) ,
} ,
# function that generates a tuple with svwf representation generators
2019-02-25 14:21:09 +02:00
lambda lMax : ( qpms . zrotN_tyty ( 4 , lMax ) , qpms . xflip_tyty ( lMax ) ) ,
# quaternion rep generators
rep3d_gens = (
2019-03-02 20:22:29 +02:00
qpms . IRot3 . zrotN ( 4 ) ,
qpms . IRot3 . xflip ( ) ,
2019-02-25 14:21:09 +02:00
)
2018-12-17 12:14:18 +02:00
) ,
' D4h ' : SVWFPointGroupInfo ( ' D4h ' ,
# permutation group generators
( Permutation ( 0 , 1 , 2 , 3 , size = 6 ) , # C4 rotation
Permutation ( 0 , 1 , size = 6 ) ( 2 , 3 ) , # x -> - x mirror operation (i.e. yz mirror plane)
Permutation ( 4 , 5 , size = 6 ) , # horizontal mirror operation z -> -z (i.e. xy mirror plane)
) ,
# dictionary with irrep generators
{ # product of C4v and zflip
" E ' " : ( ra , - lam , epsilon ) ,
" E ' ' " : ( ra , - lam , - epsilon ) ,
" A1 ' " : ( 1 , 1 , 1 ) ,
" A2 ' " : ( 1 , - 1 , 1 ) ,
" A1 ' ' " : ( 1 , - 1 , - 1 ) ,
" A2 ' ' " : ( 1 , 1 , - 1 ) ,
" B1 ' " : ( - 1 , 1 , 1 ) ,
" B2 ' " : ( - 1 , - 1 , 1 ) ,
" B1 ' ' " : ( - 1 , - 1 , - 1 ) ,
" B2 ' ' " : ( - 1 , 1 , - 1 ) ,
} ,
# function that generates a tuple with svwf representation generators
2019-02-25 14:21:09 +02:00
lambda lMax : ( qpms . zrotN_tyty ( 4 , lMax ) , qpms . xflip_tyty ( lMax ) , qpms . zflip_tyty ( lMax ) ) ,
# quaternion rep generators
rep3d_gens = (
2019-03-02 20:22:29 +02:00
qpms . IRot3 . zrotN ( 4 ) ,
qpms . IRot3 . xflip ( ) ,
qpms . IRot3 . zflip ( ) ,
2019-02-25 14:21:09 +02:00
)
2018-12-17 12:14:18 +02:00
) ,
' D3h ' : SVWFPointGroupInfo ( ' D3h ' ,
# permutation group generators
( Permutation ( 0 , 1 , 2 , size = 5 ) , # C3 rotation
Permutation ( 0 , 2 , size = 5 ) , # vertical mirror
Permutation ( 3 , 4 , size = 5 ) , # horizontal mirror z -> -z (i.e. xy mirror plane)
) ,
# dictionary with irrep generators
{ # Bradley, Cracknell p. 61
" E ' " : ( alif , lam , epsilon ) ,
" E ' ' " : ( alif , lam , - epsilon ) ,
# Bradley, Cracknell p. 59, or Dresselhaus, Table A.14 (p. 482)
" A1 ' " : ( 1 , 1 , 1 ) ,
" A2 ' " : ( 1 , - 1 , 1 ) ,
" A1 ' ' " : ( 1 , - 1 , - 1 ) ,
" A2 ' ' " : ( 1 , 1 , - 1 ) ,
} ,
# function that generates a tuple with svwf representation generators
2019-02-25 14:21:09 +02:00
lambda lMax , vflip : ( qpms . zrotN_tyty ( 3 , lMax ) , qpms . yflip_tyty ( lMax ) if vflip == ' y ' else qpms . xflip_tyty ( lMax ) , qpms . zflip_tyty ( lMax ) ) ,
# quaternion rep generators
rep3d_gens = (
2019-03-02 20:22:29 +02:00
qpms . IRot3 . zrotN ( 3 ) ,
qpms . IRot3 . xflip ( ) , # if vflip == 'y' else qpms.IRot3.xflip(), # FIXME enable to choose
qpms . IRot3 . zflip ( ) ,
2019-02-25 14:21:09 +02:00
)
2018-12-17 12:14:18 +02:00
) ,
}