qpms/qpms/symmetries.py

701 lines
32 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
import re
ň = None
s3long = np.sqrt(np.longdouble(3.))
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
def group_dps_try(elemlist, elem, gens):
'''Deterministic group depth-first search'''
elemlist.append(elem)
for i in range(len(gens)):
newelem = elem * gens[i]
if newelem not in elemlist:
group_dps_try(elemlist, newelem, gens)
return
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
rep3d_gens = None, # 3d (quaternion) representation generators of a point group: sequence of qpms.irep3 instances
):
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,float,complex))
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
)
self.rep3d_gens = rep3d_gens
self.rep3d = None if rep3d_gens is None else generate_grouprep(
self.permgroup,
qpms.IRot3(),
permgroupgens, rep3d_gens,
immultop = None, imcmp = (lambda x, y: x.isclose(y))
)
def deterministic_elemlist(self):
thelist = list()
group_dps_try(thelist, self.permgroup.identity, self.permgroupgens)
return thelist
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))
# alternative, for comparison and testing; should give the same results
def svwf_irrep_projectors2(self, lMax, *rep_gen_func_args, **rep_gen_func_kwargs):
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))
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 = self.deterministic_elemlist()
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
s += ' (qpms_gmi_t[]) { // mt\n'
for i in range(order):
ss = ', '.join([str(permindices[permlist[i]*permlist[j]]) for j in range(order)])
s += ' ' + ss + ',\n'
s += ' },\n'
# qpms_gmi_t *invi
s += ' (qpms_gmi_t[]) { // invi\n'
s += ' ' + ', '.join([str(permindices[permlist[j]**-1]) for j in range(order)])
s += '\n },\n'
# qpms_gmi_t *gens
s += ' (qpms_gmi_t[]) {' + ', '.join([str(permindices[g]) for g in self.permgroupgens]) + '}, // gens\n'
# int ngens
s += ' %d, // ngens\n' % len(self.permgroupgens)
# qpms_permutation_t permrep[]
s += ' (qpms_permutation_t[]){ // permrep\n'
for i in range(order):
s += ' "%s",\n' % str(permlist[i])
s += ' },\n'
# char **elemlabels
s += ' NULL, // elemlabels\n'
# int permrep_nelem
s += ' %d, // permrep_nelem\n' % self.permgroup.degree
# qpms_irot3_t rep3d[]
if self.rep3d is None:
s += ' NULL, // rep3d TODO!!!\n'
else:
s += ' (qpms_irot3_t[]) { // rep3d\n'
for i in range(order):
s += ' ' + self.rep3d[permlist[i]].crepr() + ',\n'
s += ' },\n'
# int nirreps
s += ' %d, // nirreps\n' % len(self.irreps)
# struct qpms_finite_grep_irrep_t irreps[]
s += ' (struct qpms_finite_group_irrep_t[]) { // irreps\n'
for irname in sorted(self.irreps.keys()):
irrep = self.irreps[irname]
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):
s += ' (complex double []) {' + ', '.join([str(irrep[permlist[i]]) for i in range(order)]) + '} // m\n'
else:
s += ' (complex double []) {\n'
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
# 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
# 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)
epsilon = np.eye(2)
alif = np.array(((-1/2,-s3long/2),(s3long/2,-1/2)))
bih = np.array(((-1/2,s3long/2),(-s3long/2,-1/2)))
kaf = np.array(((0,1),(1,0)))
lam = np.array(((1,0),(0,-1)))
ra = np.array(((0,-1),(1,0)))
mim = np.array(((-1/2,-s3long/2),(-s3long/2,1/2)))
nun = np.array(((-1/2,s3long/2),(s3long/2,1/2)))
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)))
def gen_point_group_svwfrep_irreps(permgroup, matrix_irreps_dict, sphrep_full):
'''
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.5j, -0.5j]:
sphrep[np.isclose(sphrep,x)]=x
sphreps[repkey] = sphrep
return sphreps
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
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)
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():
nelem = W.shape[-1] # however, this should change between iterations
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)
theprojector = np.zeros((2,nelem, 2, nelem), dtype = float)
if do_bases:
thebasis = np.zeros((len(tmplist), 2, nelem), dtype=complex)
for i, v in enumerate(tmplist):
thebasis[i] = v
bases[repi] = thebasis
for v in tmplist:
theprojector += (v[:,:,ň,ň] * v.conjugate()[ň,ň,:,:]).real
for x in [0, 1, -1, sqrt(.5), -sqrt(.5), .5, -.5]:
theprojector[np.isclose(theprojector,x)] = x
projectors[repi] = theprojector
if do_bases:
return projectors, bases
else:
return projectors
# Group D3h; mostly legacy code (kept because of the the honeycomb lattice K-point code, whose generalised version not yet implemented)
# 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]
D3h_permgroup = PermutationGroup(*D3h_srcgens) # D3h
D3h_irreps = {
# Bradley, Cracknell p. 61
"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]),
}
#TODO lepší název fce; legacy, use group_info['D3h'].generate_grouprep() instead
def gen_point_D3h_svwf_rep(lMax, vflip = 'x'):
'''
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]
'''
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)
#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)
I_tyty = np.moveaxis(np.eye(2)[:,:,ň,ň] * np.eye(nelem), 2,1)
order = D3h_permgroup.order()
sphrep_full = generate_grouprep(D3h_permgroup, I_tyty, D3h_srcgens, [C3_tyty, vfl_tyty, zfl_tyty],
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.5j, -0.5j]:
sphrep[np.isclose(sphrep,x)]=x
sphreps[repkey] = sphrep
return sphreps
def gen_hexlattice_Kpoint_svwf_rep(lMax, psi, vflip = 'x'):
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)
#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)
I_tyty = np.moveaxis(np.eye(2)[:,:,ň,ň] * np.eye(nelem), 2,1)
hex_C3_K_ptypty = np.diag([exp(-psi*1j*2*pi/3),exp(+psi*1j*2*pi/3)])[:,ň,ň,:,ň,ň] * C3_tyty[ň,:,:,ň,:,:]
hex_zfl_ptypty = np.eye(2)[:,ň,ň,:,ň,ň] * zfl_tyty[ň,:,:,ň,:,:]
#hex_xfl_ptypty = np.array([[0,1],[1,0]])[:,ň,ň,:,ň,ň] * xfl_tyty[ň,:,:,ň,:,:]
hex_vfl_ptypty = np.array([[0,1],[1,0]])[:,ň,ň,:,ň,ň] * vfl_tyty[ň,:,:,ň,:,:]
hex_I_ptypty = np.eye((2*2*nelem)).reshape((2,2,nelem,2,2,nelem))
order = D3h_permgroup.order()
hex_K_sphrep_full = generate_grouprep(D3h_permgroup, hex_I_ptypty, D3h_srcgens, [hex_C3_K_ptypty, hex_vfl_ptypty, hex_zfl_ptypty],
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.5j, -0.5j]:
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
def gen_hexlattice_Kpoint_svwf_rep_projectors(lMax, psi, vflip='x', do_bases=False):
nelem = lMax * (lMax+2)
projectors = dict()
if do_bases:
bases = dict()
for repi, W in gen_hexlattice_Kpoint_svwf_rep(lMax,psi,vflip=vflip).items():
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)
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
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
if do_bases:
return projectors, bases
else:
return projectors
point_group_info = { # representation info of some useful point groups
# 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(),
)
),
'C2' : SVWFPointGroupInfo('C2',
# permutation group generators
(Permutation(0,1), # 180 deg rotation around z axis
),
# dictionary with irrep generators
{
# Bradley, Cracknell p. 57;
'A': (1,),
'B': (-1,),
},
# function that generates a tuple with svwf representation generators
lambda lMax : (qpms.zrotN_tyty(2, lMax),),
# quaternion rep generators
rep3d_gens = (
qpms.IRot3.zrotN(2),
)
),
'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
lambda lMax : (qpms.xflip_tyty(lMax), qpms.yflip_tyty(lMax)),
# quaternion rep generators
rep3d_gens = (
qpms.IRot3.xflip(),
qpms.IRot3.yflip(),
)
),
'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)
# ^^^ btw, I guess that Permutation(0,1, size=6) and Permutation(2,3, size=6) would
# do exactly the same job (they should; CHECK)
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
lambda lMax : (qpms.xflip_tyty(lMax), qpms.yflip_tyty(lMax), qpms.zflip_tyty(lMax)),
# quaternion rep generators
rep3d_gens = (
qpms.IRot3.xflip(),
qpms.IRot3.yflip(),
qpms.IRot3.zflip(),
)
),
'C4' : SVWFPointGroupInfo('C4',
# permutation group generators
(Permutation(0,1,2,3, size=4),), #C4 rotation
# dictionary with irrep generators
{
# Bradley, Cracknell p. 58
'A': (1,),
'B': (-1,),
'1E': (-1j,),
'2E': (1j,),
},
# function that generates a tuple with svwf representation generators
lambda lMax : (qpms.zrotN_tyty(4, lMax), ),
# quaternion rep generators
rep3d_gens = (
qpms.IRot3.zrotN(4),
)
),
'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
lambda lMax : (qpms.zrotN_tyty(4, lMax), qpms.xflip_tyty(lMax)),
# quaternion rep generators
rep3d_gens = (
qpms.IRot3.zrotN(4),
qpms.IRot3.xflip(),
)
),
'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
lambda lMax : (qpms.zrotN_tyty(4, lMax), qpms.xflip_tyty(lMax), qpms.zflip_tyty(lMax)),
# quaternion rep generators
rep3d_gens = (
qpms.IRot3.zrotN(4),
qpms.IRot3.xflip(),
qpms.IRot3.zflip(),
)
),
'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
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 = (
qpms.IRot3.zrotN(3),
qpms.IRot3.xflip(), # if vflip == 'y' else qpms.IRot3.xflip(), # FIXME enable to choose
qpms.IRot3.zflip(),
)
),
'x_and_z_flip': SVWFPointGroupInfo(
'x_and_z_flip',
(
Permutation(0,1, size=4), # x -> -x mirror op
Permutation(2,3, size=4), # z -> -z mirror op
),
{
"P'": (1, 1),
"R'": (-1, 1),
"P''": (-1,-1),
"R''": (1, -1),
},
lambda lMax : (qpms.xflip_tyty(lMax), qpms.zflip_tyty(lMax)),
rep3d_gens = (
qpms.IRot3.xflip(),
qpms.IRot3.zflip(),
)
),
'y_and_z_flip': SVWFPointGroupInfo(
'y_and_z_flip',
(
Permutation(0,1, size=4), # y -> -y mirror op
Permutation(2,3, size=4), # z -> -z mirror op
),
{
"P'": (1, 1),
"R'": (-1, 1),
"P''": (-1,-1),
"R''": (1, -1),
},
lambda lMax : (qpms.yflip_tyty(lMax), qpms.zflip_tyty(lMax)),
rep3d_gens = (
qpms.IRot3.yflip(),
qpms.IRot3.zflip(),
)
),
}