tmatrices.py: get TMatrix by CL argument specification
Former-commit-id: e28bd7f80f64a810a1f2a22534e3fc1a40341dc9
This commit is contained in:
parent
8bbd199d3a
commit
cff4a2cbf1
|
@ -6,3 +6,5 @@ LMAXVAR - besides to int, the function should support an iterable for the lMax a
|
||||||
to support systems where different nanoparticles have different lMax.
|
to support systems where different nanoparticles have different lMax.
|
||||||
|
|
||||||
VECTORIZE - add support to process more than one element at once, in general.
|
VECTORIZE - add support to process more than one element at once, in general.
|
||||||
|
|
||||||
|
FEATURE - non-urgent general feature to implement
|
||||||
|
|
|
@ -42,6 +42,9 @@ def get_mn_y(int nmax):
|
||||||
i = i + 1
|
i = i + 1
|
||||||
return (m_arr, n_arr)
|
return (m_arr, n_arr)
|
||||||
|
|
||||||
|
def get_nelem(unsigned int lMax):
|
||||||
|
return lMax * (lMax + 2)
|
||||||
|
|
||||||
def get_y_mn_unsigned(int nmax):
|
def get_y_mn_unsigned(int nmax):
|
||||||
"""
|
"""
|
||||||
Auxillary function for mapping 'unsigned m', n indices to the flat y-indexing.
|
Auxillary function for mapping 'unsigned m', n indices to the flat y-indexing.
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
#import argparse # Do I need it when calling just parser methods?
|
|
||||||
import warnings
|
import warnings
|
||||||
|
import argparse
|
||||||
|
#import sys # for debugging purpose, TODO remove in production
|
||||||
|
import os # because of path
|
||||||
|
|
||||||
__TODOs__ = '''
|
__TODOs__ = '''
|
||||||
|
- Checking validity of T-matrix ops (the arguments of --tr, --sym or similar) according to what is implemented
|
||||||
|
in tmatrices.py.
|
||||||
- Implement a more user-friendly way to define the lattice base vectors and positions of the particles.
|
- Implement a more user-friendly way to define the lattice base vectors and positions of the particles.
|
||||||
cf. https://stackoverflow.com/questions/2371436/evaluating-a-mathematical-expression-in-a-string/2371789
|
cf. https://stackoverflow.com/questions/2371436/evaluating-a-mathematical-expression-in-a-string/2371789
|
||||||
- low priority: allow to perform some more custom operations on T-Matrix, using some kind of parsing from the previous point
|
- low priority: allow to perform some more custom operations on T-Matrix, using some kind of parsing from the previous point
|
||||||
|
@ -35,7 +39,7 @@ def add_argparse_unitcell_definitions(parser):
|
||||||
parser.add_argument('--particle', '-p', nargs='+', action=make_action_sharedlist('particle', 'particlespec'), help='Particle label, coordinates x,y, and (optionally) path to the T-Matrix.')
|
parser.add_argument('--particle', '-p', nargs='+', action=make_action_sharedlist('particle', 'particlespec'), help='Particle label, coordinates x,y, and (optionally) path to the T-Matrix.')
|
||||||
parser.add_argument('--TMatrix', '-t', nargs='+', action=make_action_sharedlist('TMatrix_path', 'particlespec'), help='Path to TMatrix file')
|
parser.add_argument('--TMatrix', '-t', nargs='+', action=make_action_sharedlist('TMatrix_path', 'particlespec'), help='Path to TMatrix file')
|
||||||
parser.add_argument('--background_permittivity', action='store', type=float, default=1., help='Background medium relative permittivity (default 1)')
|
parser.add_argument('--background_permittivity', action='store', type=float, default=1., help='Background medium relative permittivity (default 1)')
|
||||||
parser.add_argument('--lMax', action=make_action_sharedlist('lMax', 'particlespec'), nargs=+, help='Override lMax from the TMatrix file')
|
parser.add_argument('--lMax', action=make_action_sharedlist('lMax', 'particlespec'), nargs='+', help='Override lMax from the TMatrix file')
|
||||||
popgrp=parser.add_argument_group(title='Operations')
|
popgrp=parser.add_argument_group(title='Operations')
|
||||||
popgrp.add_argument('--tr', dest='ops', nargs='+', action=make_action_sharedlist('tr', 'ops'), default=list()) # the default value for dest can be set once
|
popgrp.add_argument('--tr', dest='ops', nargs='+', action=make_action_sharedlist('tr', 'ops'), default=list()) # the default value for dest can be set once
|
||||||
popgrp.add_argument('--sym', dest='ops', nargs='+', action=make_action_sharedlist('sym', 'ops'))
|
popgrp.add_argument('--sym', dest='ops', nargs='+', action=make_action_sharedlist('sym', 'ops'))
|
||||||
|
@ -62,7 +66,7 @@ def add_argparse_common_options(parser):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def arg_preprocess_particles(parser, d=None, return_tuple=False):
|
def arg_preprocess_particles(pargs, d=None, return_tuple=False):
|
||||||
'''
|
'''
|
||||||
Nanoparticle position and T-matrix path parsing
|
Nanoparticle position and T-matrix path parsing
|
||||||
|
|
||||||
|
@ -91,20 +95,20 @@ def arg_preprocess_particles(parser, d=None, return_tuple=False):
|
||||||
lMax_overrides = dict()
|
lMax_overrides = dict()
|
||||||
default_TMatrix_path = None
|
default_TMatrix_path = None
|
||||||
default_lMax_override = None
|
default_lMax_override = None
|
||||||
if not any((arg_type == 'particle') in (arg_type, arg_content) for in pargs.particlespec):
|
if not any((arg_type == 'particle') for (arg_type, arg_content) in pargs.particlespec):
|
||||||
# no particles positions given: suppose only one per unit cell, in the cell origin
|
# no particles positions given: suppose only one per unit cell, in the cell origin
|
||||||
positions = {None: (0.0)}
|
positions = {None: (0.0)}
|
||||||
else:
|
else:
|
||||||
positions = dict()
|
positions = dict()
|
||||||
for arg_type, arg_content in pargs.particlespec:
|
for arg_type, arg_content in pargs.particlespec:
|
||||||
if arg_type == 'particle' # --particle option
|
if arg_type == 'particle': # --particle option
|
||||||
if 3 <= len(arg_content) <= 4:
|
if 3 <= len(arg_content) <= 4:
|
||||||
try:
|
try:
|
||||||
positions[arg_content[0]] = (float(arg_content[1]), float(arg_content[2]))
|
positions[arg_content[0]] = (float(arg_content[1]), float(arg_content[2]))
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
e.args += ("second and third argument of --particle must be valid floats, given: ", arg_content)
|
e.args += ("second and third argument of --particle must be valid floats, given: ", arg_content)
|
||||||
raise
|
raise
|
||||||
if len(arg_content == 4):
|
if len(arg_content) == 4:
|
||||||
if arg_content[0] in TMatrix_paths:
|
if arg_content[0] in TMatrix_paths:
|
||||||
warnings.warn('T-matrix path for particle \'%s\' already specified.'
|
warnings.warn('T-matrix path for particle \'%s\' already specified.'
|
||||||
'Overriding with the last value.' % arg_content[0], SyntaxWarning)
|
'Overriding with the last value.' % arg_content[0], SyntaxWarning)
|
||||||
|
@ -145,7 +149,10 @@ def arg_preprocess_particles(parser, d=None, return_tuple=False):
|
||||||
if (set(TMatrix_paths.keys()) != set(positions.keys())) and default_TMatrix_path is None:
|
if (set(TMatrix_paths.keys()) != set(positions.keys())) and default_TMatrix_path is None:
|
||||||
raise ValueError("Position(s) of particles(s) labeled %s was given without their T-matrix"
|
raise ValueError("Position(s) of particles(s) labeled %s was given without their T-matrix"
|
||||||
" and no default T-matrix was specified"
|
" and no default T-matrix was specified"
|
||||||
% str(set(positions.keys()) - set(TMatrix_paths_keys())))
|
% str(set(positions.keys()) - set(TMatrix_paths.keys())))
|
||||||
|
# Fill default_TMatrix_path to those that don't have its own
|
||||||
|
for label in (set(positions.keys()) - set(TMatrix_paths.keys())):
|
||||||
|
TMatrix_paths[label] = default_TMatrix_path
|
||||||
for path in TMatrix_paths.values():
|
for path in TMatrix_paths.values():
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise ValueError("Cannot access T-matrix file %s. Does it exist?" % path)
|
raise ValueError("Cannot access T-matrix file %s. Does it exist?" % path)
|
||||||
|
@ -162,8 +169,6 @@ def arg_preprocess_particles(parser, d=None, return_tuple=False):
|
||||||
e.args += 'Specified operation on undefined particle labeled \'%s\'' % label
|
e.args += 'Specified operation on undefined particle labeled \'%s\'' % label
|
||||||
raise
|
raise
|
||||||
|
|
||||||
print(sys.stderr, "ops: ", ops) #DEBUG
|
|
||||||
|
|
||||||
#### Collect all the info about the particles / their T-matrices into one list ####
|
#### Collect all the info about the particles / their T-matrices into one list ####
|
||||||
# Enumerate and assign all the _different_ T-matrices (without any intelligent group-theory checking, though)
|
# Enumerate and assign all the _different_ T-matrices (without any intelligent group-theory checking, though)
|
||||||
TMatrix_specs = dict((spec, number)
|
TMatrix_specs = dict((spec, number)
|
||||||
|
@ -174,7 +179,7 @@ def arg_preprocess_particles(parser, d=None, return_tuple=False):
|
||||||
for label in positions.keys()
|
for label in positions.keys()
|
||||||
)))
|
)))
|
||||||
# particles_specs contains (label, (xpos, ypos), tmspec_index per element)
|
# particles_specs contains (label, (xpos, ypos), tmspec_index per element)
|
||||||
particles_specs = [(label, positions(label),
|
particles_specs = [(label, positions[label],
|
||||||
TMatrix_specs[(lMax_overrides[label] if label in lMax_overrides.keys() else None,
|
TMatrix_specs[(lMax_overrides[label] if label in lMax_overrides.keys() else None,
|
||||||
TMatrix_paths[label],
|
TMatrix_paths[label],
|
||||||
tuple(ops[label]))]
|
tuple(ops[label]))]
|
||||||
|
@ -186,7 +191,8 @@ def arg_preprocess_particles(parser, d=None, return_tuple=False):
|
||||||
|
|
||||||
if d is None:
|
if d is None:
|
||||||
d = dict()
|
d = dict()
|
||||||
d['particle_specs'] = particle_specs
|
# TODO what if I used classes instead?
|
||||||
|
d['particle_specs'] = particles_specs
|
||||||
d['TMatrix_specs'] = TMatrix_specs
|
d['TMatrix_specs'] = TMatrix_specs
|
||||||
if return_tuple:
|
if return_tuple:
|
||||||
return (particles_specs, TMatrix_specs)
|
return (particles_specs, TMatrix_specs)
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import quaternion, spherical_functions as sf # because of the Wigner matrices. These imports are SLOW.
|
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 # TODO IMPORT get_nelem INTO THE FINAL MODULE
|
||||||
|
ň = np.newaxis
|
||||||
|
|
||||||
# Transformations of spherical bases
|
# Transformations of spherical bases
|
||||||
def WignerD_mm(l, quat):
|
def WignerD_mm(l, quat):
|
||||||
|
@ -239,3 +244,94 @@ def symz_indexarrays(lMax, npart = 1):
|
||||||
TEč = č[(mč+nč+tč) % 2 == 0]
|
TEč = č[(mč+nč+tč) % 2 == 0]
|
||||||
TMč = č[(mč+nč+tč) % 2 == 1]
|
TMč = č[(mč+nč+tč) % 2 == 1]
|
||||||
return (TEč, TMč)
|
return (TEč, TMč)
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Processing T-matrix related operations from scripts
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
see also scripts_common.py
|
||||||
|
|
||||||
|
The unit cell is defined by a dict particle_specs and a list TMatrix_specs.
|
||||||
|
This particular module has to provide the T-matrices according to what is defined
|
||||||
|
in TMatrix_specs
|
||||||
|
|
||||||
|
TMatrix_specs is a list of tuples (lMax_override, TMatrix_path, ops)
|
||||||
|
where
|
||||||
|
- TMatrix_path is path to the file generated by scuff-tmatrix
|
||||||
|
- lMax_override is int or None; if it is int and less than the lMax found from the T-matrix file,
|
||||||
|
lMax_override is used as the order cutoff for the output T-matrix.
|
||||||
|
- ops is an iterable of tuples (optype, opargs) where currently optype can be 'sym' or 'tr'
|
||||||
|
for symmetrization operation or some other transformation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#TODO FEATURE more basic group symmetry operations, cf. http://symmetry.otterbein.edu/tutorial/index.html
|
||||||
|
|
||||||
|
# This is for finite „fractional“ rotations along the z-axis (mCN means rotation of 2π*(m/N))
|
||||||
|
reCN = re.compile('(\d*)C(\d+)') # TODO STYLE make this regexp also accept the 3*C_5-type input, eqiv. to 3C5
|
||||||
|
|
||||||
|
def get_TMatrix_fromspec(tmatrix_spec):
|
||||||
|
''' TODO doc
|
||||||
|
returns (TMatrices, freqs, lMax)
|
||||||
|
'''
|
||||||
|
lMax_override, tmpath, ops = tmatrix_spec
|
||||||
|
TMatrices, freqs, freqs_weirdunits, lMax = loadScuffTMatrices(tmpath)
|
||||||
|
if lMax_override is not None and (lMax_override < lMax_orig):
|
||||||
|
nelem = get_nelem(lMax_override)
|
||||||
|
TMatrices = TMatrices[...,0:nelem,:,0:nelem]
|
||||||
|
lMax = lMax_override
|
||||||
|
|
||||||
|
for (optype, opargs) in ops:
|
||||||
|
if optype == 'sym':
|
||||||
|
mCN = reCN.match(opargs)
|
||||||
|
if opargs == 'C2' or opargs == 'C_2':
|
||||||
|
opmat = apply_matrix_left(yflip_yy(lMax), xflip_yy(lMax), -1)
|
||||||
|
TMatrices = (TMatrices + apply_matrix_left(opmat, apply_matrix_left(opmat, TMatrices, -3), -1))/2
|
||||||
|
elif opargs == 'σ_x' or opargs == 'σx':
|
||||||
|
opmat = xflip_tyty(lMax)
|
||||||
|
TMatrices = (TMatrices + apply_ndmatrix_left(opmat, apply_ndmatrix_left(opmat, TMatrices, (-4,-3)),(-2,-1)))/2
|
||||||
|
elif opargs == 'σ_y' or opargs == 'σy':
|
||||||
|
opmat = yflip_tyty(lMax)
|
||||||
|
TMatrices = (TMatrices + apply_ndmatrix_left(opmat, apply_ndmatrix_left(opmat, TMatrices, (-4,-3)),(-2,-1)))/2
|
||||||
|
elif opargs == 'σ_z' or opargs == 'σz':
|
||||||
|
opmat = zflip_tyty(lMax)
|
||||||
|
TMatrices = (TMatrices + apply_ndmatrix_left(opmat, apply_ndmatrix_left(opmat, TMatrices, (-4,-3)),(-2,-1)))/2
|
||||||
|
elif mCN:
|
||||||
|
rotN = int(mCN.group(2)) # the possible m is ignored
|
||||||
|
TMatrix_contribs = np.empty((rotN,)+TMatrices.shape, dtype=np.complex_)
|
||||||
|
for i in range(rotN):
|
||||||
|
rotangle = 2*np.pi*i / rotN
|
||||||
|
rot = WignerD_yy_fromvector(lMax, np.array([0,0,rotangle]))
|
||||||
|
rotinv = WignerD_yy_fromvector(lMax, np.array([0,0,-rotangle]))
|
||||||
|
TMatrix_contribs[i] = apply_matrix_left(rot, apply_matrix_left(rotinv, TMatrices, -3), -1)
|
||||||
|
TMatrices = np.sum(TMatrix_contribs, axis=0) / rotN
|
||||||
|
elif opargs == 'C_inf' or opargs == 'Cinf' or opargs == 'C_∞' or opargs == 'C∞':
|
||||||
|
raise ValueError('not implemented: ', opargs) # TODO FEATURE
|
||||||
|
else:
|
||||||
|
raise ValueError('not implemented: ', opargs)
|
||||||
|
elif optype == 'tr':
|
||||||
|
mCN = reCN.match(opargs)
|
||||||
|
if opargs == 'C2' or opargs == 'C_2':
|
||||||
|
opmat = apply_matrix_left(yflip_yy(lMax), xflip_yy(lMax), -1)
|
||||||
|
TMatrices = apply_matrix_left(opmat, apply_matrix_left(opmat, TMatrices, -3), -1)/2
|
||||||
|
elif opargs == 'σ_x' or opargs == 'σx':
|
||||||
|
opmat = xflip_tyty(lMax)
|
||||||
|
TMatrices = apply_ndmatrix_left(opmat, apply_ndmatrix_left(opmat, TMatrices, (-4,-3)),(-2,-1))/2
|
||||||
|
elif opargs == 'σ_y' or opargs == 'σy':
|
||||||
|
opmat = yflip_tyty(lMax)
|
||||||
|
TMatrices = apply_ndmatrix_left(opmat, apply_ndmatrix_left(opmat, TMatrices, (-4,-3)),(-2,-1))/2
|
||||||
|
elif opargs == 'σ_z' or opargs == 'σz':
|
||||||
|
opmat = zflip_tyty(lMax)
|
||||||
|
TMatrices = apply_ndmatrix_left(opmat, apply_ndmatrix_left(opmat, TMatrices, (-4,-3)),(-2,-1))/2
|
||||||
|
elif mCN:
|
||||||
|
rotN = int(mCN.group(2))
|
||||||
|
power = int(mCN.group(1)) if mCN.group(1) else 1
|
||||||
|
rotangle = 2*np.pi*power / rotN
|
||||||
|
rot = WignerD_yy_fromvector(lMax, np.array([0,0,rotangle]))
|
||||||
|
rotinv = WignerD_yy_fromvector(lMax, np.array([0,0,-rotangle]))
|
||||||
|
TMatrices = apply_matrix_left(rot, apply_matrix_left(rotinv, TMatrices, -3), -1)
|
||||||
|
else:
|
||||||
|
raise ValueError('not implemented: ', opargs)
|
||||||
|
else:
|
||||||
|
raise ValueError('not implemented: ', optype)
|
||||||
|
return (TMatrices, freqs, lMax)
|
||||||
|
|
Loading…
Reference in New Issue