import numpy as np import quaternion, spherical_functions as sf # because of the Wigner matrices. These imports are SLOW. import re from scipy import interpolate from scipy.constants import hbar, e as eV, pi, c from qpms_c import get_mn_y, get_nelem ň = np.newaxis from .types import NormalizationT, TMatrixSpec # Transformations of spherical bases def WignerD_mm(l, quat): """ Calculates Wigner D matrix (as an numpy (2*l+1,2*l+1)-shaped array) for order l, and a rotation given by quaternion quat. This represents the rotation of spherical vector basis TODO doc """ indices = np.array([ [l,i,j] for i in range(-l,l+1) for j in range(-l,l+1)]) Delems = sf.Wigner_D_element(quat, indices).reshape(2*l+1,2*l+1) return Delems def WignerD_mm_fromvector(l, vect): """ TODO doc """ return WignerD_mm(l, quaternion.from_rotation_vector(vect)) def WignerD_yy(lmax, quat): """ TODO doc """ my, ny = get_mn_y(lmax) Delems = np.zeros((len(my),len(my)),dtype=complex) b_in = 0 e_in = None for l in range(1,lmax+1): e_in = b_in + 2*l+1 Delems[b_in:e_in,b_in:e_in] = WignerD_mm(l, quat) b_in = e_in return Delems def WignerD_yy_fromvector(lmax, vect): """ TODO doc """ return WignerD_yy(lmax, quaternion.from_rotation_vector(vect)) def identity_yy(lmax): """ TODO doc """ return np.eye(lMax2nelem(lMax)) def identity_tyty(lmax): """ TODO doc """ nelem = lMax2nelem(lmax) return np.eye(2*nelem).reshape((2,nelem,2,nelem)) def xflip_yy(lmax): """ TODO doc xflip = δ(m + m') δ(l - l') (i.e. ones on the (m' m) antidiagonal """ my, ny = get_mn_y(lmax) elems = np.zeros((len(my),len(my)),dtype=int) b_in = 0 e_in = None for l in range(1,lmax+1): e_in = b_in + 2*l+1 elems[b_in:e_in,b_in:e_in] = np.eye(2*l+1)[::-1,:] b_in = e_in return elems def xflip_tyy(lmax): fl_yy = xflip_yy(lmax) return np.array([fl_yy,-fl_yy]) def xflip_tyty(lmax): fl_yy = xflip_yy(lmax) nelem = fl_yy.shape[0] fl_tyty = np.zeros((2,nelem,2,nelem),dtype=int) fl_tyty[0,:,0,:] = fl_yy fl_tyty[1,:,1,:] = -fl_yy return fl_tyty def yflip_yy(lmax): """ TODO doc yflip = rot(z,pi/2) * xflip * rot(z,-pi/2) = δ(m + m') δ(l - l') * (-1)**m """ my, ny = get_mn_y(lmax) elems = xflip_yy(lmax) elems[(my % 2)==1] = elems[(my % 2)==1] * -1 # Obvious sign of tiredness (this is correct but ugly; FIXME) return elems def yflip_tyy(lmax): fl_yy = yflip_yy(lmax) return np.array([fl_yy,-fl_yy]) def yflip_tyty(lmax): fl_yy = yflip_yy(lmax) nelem = fl_yy.shape[0] fl_tyty = np.zeros((2,nelem,2,nelem),dtype=int) fl_tyty[0,:,0,:] = fl_yy fl_tyty[1,:,1,:] = -fl_yy return fl_tyty def zflip_yy(lmax): """ TODO doc zflip = (-1)^(l+m) """ my, ny = get_mn_y(lmax) elems = np.zeros((len(my), len(my)), dtype=int) b_in = 0 e_in = None for l in range(1,lmax+1): e_in = b_in + 2*l+1 elems[b_in:e_in,b_in:e_in] = np.diag([(-1)**i for i in range(e_in-b_in)]) b_in = e_in return elems def zflip_tyy(lmax): fl_yy = zflip_yy(lmax) return np.array([fl_yy,-fl_yy]) def zflip_tyty(lmax): fl_yy = zflip_yy(lmax) nelem = fl_yy.shape[0] fl_tyty = np.zeros((2,nelem,2,nelem),dtype=int) fl_tyty[0,:,0,:] = fl_yy fl_tyty[1,:,1,:] = -fl_yy return fl_tyty def zrotN_yy(N, lMax): return WignerD_yy_fromvector(lMax, np.array([0,0,pi * (2/N)])) def op_yy2tyty(yyop): ''' Broadcasts an yy operator to tyty operator without considering mirroring effects. Good (maybe only) for rotations. ''' return np.moveaxis(np.eye(2)[:,:,ň,ň] * yyop, 2,1) def zrotN_tyty(N, lMax): return op_yy2tyty(zrotN_yy(N, lMax)) def parity_yy(lmax): """ Parity operator (flip in x,y,z) parity = (-1)**l """ my, ny = get_mn_y(lmax) return np.diag((-1)**ny) # BTW parity (xyz-flip) is simply (-1)**ny #----------------------------------------------------# # Loading T-matrices from scuff-tmatrix output files # #----------------------------------------------------# # We don't really need this particular function anymore, but... def _scuffTMatrixConvert_EM_01(EM): #print(EM) if (EM == b'E'): return 1 elif (EM == b'M'): return 0 else: return None def loadScuffTMatrices(fileName, normalisation = 1, version = 'old', freqscale = None, order = None): """ TODO doc version describes version of scuff-em. It is either 'old' or 'new'. default order is ('N','M') with 'old' version, ('M','N') with 'new' """ oldversion = (version == 'old') μm = 1e-6 table = np.genfromtxt(fileName, converters={1: _scuffTMatrixConvert_EM_01, 4: _scuffTMatrixConvert_EM_01} if oldversion else None, skip_header = 0 if oldversion else 5, usecols = None if oldversion else (0, 2, 3, 4, 6, 7, 8, 9, 10), dtype=[('freq', '