"""
ResponseTensorPG manages physical response tensors upto rank 4.
"""
import sympy as sp
from gcoreutils.nsarray import NSArray
from multipie.tag.tag_group import TagGroup
from multipie.tag.tag_list import TagList
from multipie.response_tensor.util.response_tensor_util import simplify_tensor, create_tensor
from multipie.tag.tag_response_tensor import TagResponseTensor
from multipie.const import __def_dict__
# ==================================================
[docs]
class ResponseTensorPG(dict): # dict of (response tag, matrix), { TagResponseTensor: NSArray }.
"""
a set of response tensors upto rank 4.
Attributes:
tag (TagGroup): point-group tag.
definition ({TagResponseTensor:{sympy:sympy}}): definition in terms of multipoles for each component.
"""
# ==================================================
def __init__(self, pg_tag):
"""
initialize the class.
Args:
pg_tag (TagGroup or str): point group tag.
"""
if pg_tag is None:
self.tag = None
"""point-group tag."""
self.definition = {}
else:
self.tag = TagGroup(str(pg_tag))
self._initialize()
# ==================================================
def __str__(self):
return str(self.tag)
# ==================================================
def __repr__(self):
return repr(self.tag)
# ==================================================
def latex(self):
return self.tag.latex()
# ==================================================
def _initialize(self):
"""
create response tensors.
"""
# create response tensor data, { tag: [[(tensor symbol, component)]] }.
d = {}
for head in __def_dict__["head"]:
for rank, comp in __def_dict__["response_head"].keys():
tag = TagResponseTensor.create(head, rank, comp)
d[tag] = create_tensor(self.tag, tag)
# create active tensor, { tag: Matrix }.
mat = {}
for tag, M in d.items():
M = simplify_tensor(M)
zero = sp.zeros(len(M), len(M[0]))
x = zero.copy()
for i, lst in enumerate(M):
for j, (c, m) in enumerate(lst):
if m == sp.S(0):
x[i, j] = sp.S(0)
else:
x[i, j] = c
if not x.equals(zero):
mat[tag] = x
# create definition of each element, { tag: {tensor_symbol: definition} }.
de = {}
for tag, M1 in mat.items():
de[tag] = []
M2 = sp.Matrix([[m for _, m in lst] for lst in d[tag]])
Cs = []
for i in range(M1.rows):
for j in range(M1.cols):
m = M1[i, j]
if m != sp.S(0):
Cs += [i for i in m.atoms(sp.Symbol)]
Cs = list(set(Cs))
for m1, m2 in zip(M1, M2):
c_lst = [i for i in m1.atoms(sp.Symbol)]
if all([c in Cs for c in c_lst]) and m1 != sp.S(0):
de[tag].append((m1, m2))
for c in c_lst:
Cs.remove(c)
for k, v in mat.items():
self[k] = NSArray(v.tolist(), "matrix")
self.definition = {k: dict(v) for k, v in de.items()}
"""definition in terms of multipoles for each component."""
# ==================================================
[docs]
def select(self, **kwargs):
"""
select response tensors with given keywords.
Args:
kwargs (dict): select conditions for response tensors, (head/rank/comp).
Returns:
ResponseTensorPG: selected response tensors.
"""
c_rt = ResponseTensorPG(None)
for t in self.key_list().select(**kwargs):
c_rt[t] = self[t]
c_rt.definition[t] = self.definition[t]
c_rt.tag = self.tag
return c_rt
# ==================================================
def _dump(self):
"""
dump response tensors.
"""
for tag in self.keys():
print(f"=== rank {tag.rank} {tag.i_type} {tag.t_type} tensor '{tag.comp}' component ===")
print(tag.symbol(), "=", self[tag])
def_mul = self.definition[tag]
for t, d in def_mul.items():
print(" ", t, ":=", d)
# ==================================================
def _info(self):
"""
get information of the response tensors.
"""
s = "* -------------------------------------------------------------------------------------------------------- *" + "\n"
s += " The symmetry properties of the response tensors 'C' of the 0-th to 4-th orders are summarized" + "\n"
s += " in terms of the electric, electric toroidal, magnetic, and magnetic toroidal multipoles, Q, G, M, and T." + "\n"
s += " The basis of the matrices is represented by using the Voigt notation (1=xx, 2=yy, 3=zz, 4=yz, 5=zx, 6=xy)." + "\n"
s += "* -------------------------------------------------------------------------------------------------------- *" + "\n"
s += "- rank 0 tensor" + "\n"
s += " C = Q_{0}" + "\n"
s += " C = (Q_{0})" + "\n"
s += "- rank 1 tensor" + "\n"
s += " C = Q_{1}" + "\n"
s += " C = (Q_{x}, Q_{y}, Q_{z})" + "\n"
s += "- rank 2 tensor" + "\n"
s += " C12 = S12 + A12" + "\n"
s += " S12 = S21" + "\n"
s += " A12 = -A21" + "\n"
s += "- rank 3 tensor" + "\n"
s += " C123 = S12;3 + A12;3" + "\n"
s += " S12;3 = S21;3" + "\n"
s += " A12;3 = -A21;3" + "\n"
s += "- rank 4 tensor" + "\n"
s += " C1234 = S12;34 + Sb12;34 + A12;34 + Ab12;34 + M12;34 + Mb12;34" + "\n"
s += " S12;34 = S21;34 = S12;43 = S34;12" + "\n"
s += " Sb12;34 = Sb21;34 = Sb12;43 = -Sb34;12" + "\n"
s += " A12;34 = -A21;34 = -A12;43 = A34;12" + "\n"
s += " Ab12;34 = -Ab21;34 = -Ab12;43 = -Ab34;12" + "\n"
s += " M12;34 = M21;34 = -M12;43" + "\n"
s += " Mb12;34 = -Mb21;34 = Mb12;43" + "\n"
print(s)
# ==================================================
def __getitem__(self, tag):
if type(tag) == str:
return self.get(TagResponseTensor(tag))
else:
return self.get(tag)
# ==================================================
def key_list(self):
return TagList(self.keys())