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 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 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 0 elif (EM == b'M'): return 1 else: return None def loadScuffTMatrices(fileName, normalisation = 1): """ TODO doc """ μm = 1e-6 table = np.genfromtxt(fileName, converters={1: _scuffTMatrixConvert_EM_01, 4: _scuffTMatrixConvert_EM_01}, dtype=[('freq', '