Source code for multipie.util.util_response_tensor

"""
Response tensors up to 4th rank.
"""

import re
import numpy as np
import sympy as sp
from sympy.functions.special.tensor_functions import KroneckerDelta
from sympy import LeviCivita
from itertools import product


# ==================================================
[docs] def delta(i1, i2): """ Kronecker delta. Args: i1 (int): index 1, 1-3. i2 (int): index 2. 1-3. Returns: - (sympy) -- delta(i1,i2). """ return KroneckerDelta(i1, i2)
# ==================================================
[docs] def epsilon(i1, i2, i3): """ Levi-Civita epsilon. Args: i1 (int): index 1, 1-3. i2 (int): index 2. 1-3. i3 (int): index 3, 1-3. Returns: - (sympy) -- epsilon(i1,i2,i3). """ return LeviCivita(i1, i2, i3)
# ==================================================
[docs] def d1234(i1, i2, i3, i4): return delta(i1, i3) * delta(i2, i4) + delta(i1, i4) * delta(i2, i3)
# ==================================================
[docs] def d12345(i1, i2, i3, i4, i5): return ( delta(i1, i3) * epsilon(i2, i4, i5) + delta(i2, i3) * epsilon(i1, i4, i5) + delta(i1, i4) * epsilon(i2, i3, i5) + delta(i2, i4) * epsilon(i1, i3, i5) )
# ==================================================
[docs] def d123456(i1, i2, i3, i4, i5, i6): return sp.S(delta(i1, i2) * d1234(i3, i4, i5, i6) + delta(i3, i4) * d1234(i1, i2, i5, i6)) / 2
# ==================================================
[docs] def d123456p(i1, i2, i3, i4, i5, i6): return ( sp.S( delta(i1, i3) * d1234(i2, i4, i5, i6) + delta(i2, i3) * d1234(i1, i4, i5, i6) + delta(i1, i4) * d1234(i2, i3, i5, i6) + delta(i2, i4) * d1234(i1, i3, i5, i6) ) / 2 )
# ==================================================
[docs] def d123456pp(i1, i2, i3, i4, i5, i6): return sp.S(delta(i1, i2) * d1234(i3, i4, i5, i6) - delta(i3, i4) * d1234(i1, i2, i5, i6)) / 2
# ==================================================
[docs] def d1234567(i1, i2, i3, i4, i5, i6, i7): return ( sp.S( epsilon(i1, i3, i7) * d1234(i2, i4, i5, i6) + epsilon(i2, i3, i7) * d1234(i1, i4, i5, i6) + epsilon(i2, i4, i7) * d1234(i1, i3, i5, i6) + epsilon(i1, i4, i7) * d1234(i2, i3, i5, i6) ) / 2 )
# ==================================================
[docs] def e1234(i1, i2, i3, i4): return delta(i1, i3) * delta(i2, i4) - delta(i1, i4) * delta(i2, i3)
# ==================================================
[docs] def e51234(i1, i2, i3, i4, i5): return ( sp.S( delta(i1, i5) * epsilon(i2, i3, i4) - delta(i2, i5) * epsilon(i1, i3, i4) - delta(i3, i5) * epsilon(i1, i2, i4) + delta(i4, i5) * epsilon(i1, i2, i3) ) / 2 )
# ==================================================
[docs] def e561234(i1, i2, i3, i4, i5, i6): return epsilon(i1, i2, i5) * epsilon(i3, i4, i6) + epsilon(i1, i2, i6) * epsilon(i3, i4, i5)
# ==================================================
[docs] def g12534(i1, i2, i3, i4, i5): return delta(i1, i5) * epsilon(i2, i3, i4) + delta(i2, i5) * epsilon(i1, i3, i4)
# ==================================================
[docs] def g125634(i1, i2, i3, i4, i5, i6): return ( sp.S( delta(i3, i5) * d1234(i1, i2, i4, i6) + delta(i3, i6) * d1234(i1, i2, i4, i5) - delta(i4, i5) * d1234(i1, i2, i3, i6) - delta(i4, i6) * d1234(i1, i2, i3, i5) ) / 2 )
# ==================================================
[docs] def mp_string(lst, head, sort=True): """ Multipole string. Args: head (str): head of multipole. sort (bool, optional): sort subscript ? Returns: - (str) -- multipole string. """ _dv = {1: "x", 2: "y", 3: "z"} lst = [_dv[i] for i in lst] if sort: s = head + "_{" + "".join(sorted("".join(lst))) + "}" else: s = head + "_{" + "".join("".join(lst)) + "}" return s
# ==================================================
[docs] def S0(): """ Rank 0 tensor component. Returns: - (list) -- expression list, (coeff, multipole). """ return [(1, "Q^{(1)}")]
# ==================================================
[docs] def S1(i1): """ Rank 1 tensor component. Args: i1 (int): index 1, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ return [(1, mp_string([i1], "Q^{(1)}"))]
# ==================================================
[docs] def S12(i1, i2): """ Symmetric part of rank 2 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ if i1 == i2: lst = [(1, mp_string([i1, i2], "Q^{(1)}")), (1, "Q^{(1)}")] else: lst = [(1, mp_string([i1, i2], "Q^{(1)}"))] return lst
# ==================================================
[docs] def A12(i1, i2): """ Anti-symmetric part of rank 2 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ lst = [] for i3 in range(1, 4): e = epsilon(i1, i2, i3) if e != 0: lst.append((e, mp_string([i3], "G^{(1)}"))) return lst
# ==================================================
[docs] def S123(i1, i2, i3): """ Symmetric part of rank 3 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ if i1 == i2: l1 = [(1, mp_string([i3], "Q^{(1)}"))] else: l1 = [] l2 = [] for i4 in range(1, 4): d = d1234(i1, i2, i3, i4) if d != 0: l2.append((d, mp_string([i4], "Q^{(2)}"))) l3 = [] for i4, i5 in product(range(1, 4), range(1, 4)): g = g12534(i1, i2, i3, i4, i5) if g != 0: l3.append((g, mp_string([i4, i5], "G^{(1)}"))) l4 = [(1, mp_string([i1, i2, i3], "Q^{(1)}"))] return l1 + l2 + l3 + l4
# ==================================================
[docs] def A123(i1, i2, i3): """ Anti-symmetric part of rank 3 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ e = epsilon(i1, i2, i3) if e != 0: l1 = [(e, "G^{(1)}")] else: l1 = [] l2 = [] for i4 in range(1, 4): e = e1234(i1, i2, i3, i4) if e != 0: l2.append((e, mp_string([i4], "Q^{(3)}"))) l3 = [] for i4 in range(1, 4): e = epsilon(i1, i2, i4) if e != 0: l3.append((e, mp_string([i3, i4], "G^{(2)}"))) return l1 + l2 + l3
# ==================================================
[docs] def S1234(i1, i2, i3, i4): """ SSS part of rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ if i1 == i2 and i3 == i4: l1 = [(1, "Q^{(1)}")] else: l1 = [] d = d1234(i1, i2, i3, i4) if d != 0: l2 = [(d, "Q^{(2)}")] else: l2 = [] l3 = [] for i5, i6 in product(range(1, 4), range(1, 4)): d = d123456(i1, i2, i3, i4, i5, i6) if d != 0: l3.append((d, mp_string([i5, i6], "Q^{(1)}"))) l4 = [] for i5, i6 in product(range(1, 4), range(1, 4)): d = d123456p(i1, i2, i3, i4, i5, i6) if d != 0: l4.append((d, mp_string([i5, i6], "Q^{(2)}"))) l5 = [(1, mp_string([i1, i2, i3, i4], "Q^{(1)}"))] return l1 + l2 + l3 + l4 + l5
# ==================================================
[docs] def Sb1234(i1, i2, i3, i4): """ SSA part of rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ l1 = [] for i5 in range(1, 4): d = d12345(i1, i2, i3, i4, i5) if d != 0: l1.append((d, mp_string([i5], "G^{(1)}"))) l2 = [] for i5, i6 in product(range(1, 4), range(1, 4)): d = d123456pp(i1, i2, i3, i4, i5, i6) if d != 0: l2.append((d, mp_string([i5, i6], "Q^{(3)}"))) l3 = [] for i5, i6, i7 in product(range(1, 4), range(1, 4), range(1, 4)): d = d1234567(i1, i2, i3, i4, i5, i6, i7) if d != 0: l3.append((d, mp_string([i5, i6, i7], "G^{(1)}"))) return l1 + l2 + l3
# ==================================================
[docs] def A1234(i1, i2, i3, i4): """ AAS part of rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ e = e1234(i1, i2, i3, i4) if e != 0: l1 = [(e, "Q^{(3)}")] else: l1 = [] l2 = [] for i5, i6 in product(range(1, 4), range(1, 4)): e = e561234(i1, i2, i3, i4, i5, i6) if e != 0: l2.append((e, mp_string([i5, i6], "Q^{(4)}"))) return l1 + l2
# ==================================================
[docs] def Ab1234(i1, i2, i3, i4): """ AAA part of rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ l1 = [] for i5 in range(1, 4): e = e51234(i1, i2, i3, i4, i5) if e != 0: l1.append((e, mp_string([i5], "G^{(2)}"))) return l1
# ==================================================
[docs] def M1234(i1, i2, i3, i4): """ SA part of rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ l1 = [] for i5 in range(1, 4): de = delta(i1, i2) * epsilon(i3, i4, i5) if de != 0: l1.append((de, mp_string([i5], "G^{(3)}"))) l2 = [] for i5 in range(1, 4): g = g12534(i1, i2, i3, i4, i5) if g != 0: l2.append((g, mp_string([i5], "G^{(4)}"))) l3 = [] for i5, i6 in product(range(1, 4), range(1, 4)): g = g125634(i1, i2, i3, i4, i5, i6) if g != 0: l3.append((g, mp_string([i5, i6], "Q^{(5)}"))) l4 = [] for i5 in range(1, 4): e = epsilon(i3, i4, i5) if e != 0: l4.append((e, mp_string([i1, i2, i5], "G^{(2)}"))) return l1 + l2 + l3 + l4
# ==================================================
[docs] def Mb1234(i1, i2, i3, i4): """ AS part of rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ l1 = [] for i5 in range(1, 4): de = delta(i3, i4) * epsilon(i1, i2, i5) if de != 0: l1.append((de, mp_string([i5], "G^{(5)}"))) l2 = [] for i5 in range(1, 4): g = g12534(i3, i4, i1, i2, i5) if g != 0: l2.append((g, mp_string([i5], "G^{(6)}"))) l3 = [] for i5, i6 in product(range(1, 4), range(1, 4)): g = g125634(i3, i4, i1, i2, i5, i6) if g != 0: l3.append((g, mp_string([i5, i6], "Q^{(6)}"))) l4 = [] for i5 in range(1, 4): e = epsilon(i1, i2, i5) if e != 0: l4.append((e, mp_string([i3, i4, i5], "G^{(3)}"))) return l1 + l2 + l3 + l4
# ==================================================
[docs] def T1234(i1, i2, i3, i4): """ S part of rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ if i1 == i2 and i3 == i4: d1 = 1 else: d1 = 0 d2 = d1234(i1, i2, i3, i4) if d1 + d2 != 0: l1 = [(d1 + d2, "Q^{(1)}")] else: l1 = [] l2 = [] for i5, i6 in product(range(1, 4), range(1, 4)): d = d123456(i1, i2, i3, i4, i5, i6) if d != 0: l2.append((d, mp_string([i5, i6], "Q^{(1)}"))) l3 = [] for i5, i6 in product(range(1, 4), range(1, 4)): d = d123456p(i1, i2, i3, i4, i5, i6) if d != 0: l3.append((d, mp_string([i5, i6], "Q^{(2)}"))) l4 = [] for i5, i6 in product(range(1, 4), range(1, 4)): d = d123456pp(i1, i2, i3, i4, i5, i6) if d != 0: l4.append((d, mp_string([i5, i6], "Q^{(3)}"))) l5 = [] for i5, i6 in product(range(1, 4), range(1, 4)): g = g125634(i1, i2, i3, i4, i5, i6) if g != 0: l5.append((g, mp_string([i5, i6], "Q^{(5)}"))) l6 = [(1, mp_string([i1, i2, i3, i4], "Q^{(1)}"))] return l1 + l2 + l3 + l4 + l5 + l6
# ==================================================
[docs] def P0(): """ Rank 0 tensor component. Returns: - (list) -- expression list, (coeff, multipole). """ return S0()
# ==================================================
[docs] def P1(i1): """ Rank 1 tensor component. Args: i1 (int): index 1, 1-3. Returns: - (list) -- expression list, (coeff, multipole). """ return S1(i1)
# ==================================================
[docs] def P2(i1, i2, opt=None): """ Rank 2 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. opt (str, optional): part, s/a. Returns: - (list) -- expression list, (coeff, multipole). """ if opt is None: return S12(i1, i2) + A12(i1, i2) elif opt == "s": return S12(i1, i2) elif opt == "a": return A12(i1, i2) else: raise ValueError(f"invalid option, {opt}")
# ==================================================
[docs] def P3(i1, i2, i3, opt=None): """ Rank 3 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. opt (str, optional): part, s/a. Returns: - (list) -- expression list, (coeff, multipole). """ if opt is None: return S123(i1, i2, i3) + A123(i1, i2, i3) elif opt == "s": return S123(i1, i2, i3) elif opt == "a": return A123(i1, i2, i3) else: raise ValueError(f"invalid option, {opt}")
# ==================================================
[docs] def P4(i1, i2, i3, i4, opt=None): # sss/ssa/aas/aaa/sa/as/s/a/t. """ Rank 4 tensor component. Args: i1 (int): index 1, 1-3. i2 (int): index 2, 1-3. i3 (int): index 3, 1-3. i4 (int): index 4, 1-3. opt (str, optional): part, sss/ssa/aas/aaa/sa/as/s/a/t. Returns: - (list) -- expression list, (coeff, multipole). """ if opt is None: return ( S1234(i1, i2, i3, i4) + Sb1234(i1, i2, i3, i4) + A1234(i1, i2, i3, i4) + Ab1234(i1, i2, i3, i4) + M1234(i1, i2, i3, i4) + Mb1234(i1, i2, i3, i4) ) elif opt == "sss": return S1234(i1, i2, i3, i4) elif opt == "ssa": return Sb1234(i1, i2, i3, i4) elif opt == "aas": return A1234(i1, i2, i3, i4) elif opt == "aaa": return Ab1234(i1, i2, i3, i4) elif opt == "sa": return M1234(i1, i2, i3, i4) elif opt == "as": return Mb1234(i1, i2, i3, i4) elif opt == "s": return S1234(i1, i2, i3, i4) + Sb1234(i1, i2, i3, i4) + M1234(i1, i2, i3, i4) elif opt == "a": return A1234(i1, i2, i3, i4) + Ab1234(i1, i2, i3, i4) + Mb1234(i1, i2, i3, i4) elif opt == "t": return T1234(i1, i2, i3, i4) else: raise ValueError(f"invalid option, {opt}")
# ==================================================
[docs] def create_active_dict(active, cartesian_mp): d = {} for cc, lst in cartesian_mp.items(): for X in ["Q", "G", "T", "M"]: ex = [] for c, v in lst: Xv = X + v if Xv in active: ex.append((c, X + "_{" + v + "}")) if ex: d[X + cc] = ex return d
# ==================================================
[docs] def split_symbol(s): m = re.fullmatch(r"([A-Za-z]+)(?:\^\{\(([^)]*)\)\})?(?:_\{([^}]*)\})?", s) if m: base = m.group(1) sup = f"({m.group(2)})" if m.group(2) else "" sub = m.group(3) if m.group(3) else "s" return base, sup, sub else: return s, "", "s"
# ==================================================
[docs] def get_response_tensor_mp(rt, active_dict, axial_tensor, magnetic_tensor): to_axial_dict = {"Q": "G", "G": "Q", "T": "M", "M": "T"} to_magnetic_dict = {"Q": "T", "G": "M", "T": "Q", "M": "G"} lst = [(c, *split_symbol(v)) for c, v in rt] ex_lst = [] for c, X, ss, comp in lst: if axial_tensor: X = to_axial_dict[X] if magnetic_tensor: X = to_magnetic_dict[X] if X + comp in active_dict.keys(): mp = active_dict[X + comp] for mc, m in mp: ex_lst.append((c * mc, ss, m)) s = sp.S(0) for c, ss, m in ex_lst: s += c * sp.Symbol(m + "^{" + ss + "}") return s
# ==================================================
[docs] def simplify_tensor(M): """ Simplify tensor. Args: M (ndarray): tensor, [[(symbol, expression)]]. Returns: - (ndarray): simplified tensor. - (dict): expression dict. """ M = [[(sp.Symbol(c), m) for c, m in lst] for lst in M] Xs = [x for lst in M for _, m in lst for x in m.atoms(sp.Symbol)] Xs = list(set(Xs)) Cs = list(reversed([c for lst in M for c, m in lst if m != sp.S(0)])) args = Xs + Cs eqs = [sp.Eq(c, m) for lst in M for c, m in lst] tensor_map = sp.solve(eqs, args) Ms = [[None for _ in lst] for lst in M] d = {} for i, lst in enumerate(M): for j, (c, m) in enumerate(lst): if c in tensor_map: c_ = tensor_map[c] if c_ != sp.S(0): if all([i in Cs for i in c_.atoms(sp.Symbol)]): c = c_ if m != 0: Ms[i][j] = c sym = c.free_symbols if len(sym) > 1: for s in sym: if s not in d.keys(): raise Exception(f"fail to solve.") else: if c.could_extract_minus_sign(): c = -c m = -m d[c] = m else: Ms[i][j] = sp.S(0) Ms = np.asarray(Ms) return Ms, d