Source code for symmetr.symmetrize_exp

from __future__ import print_function
from __future__ import absolute_import
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from builtins import str
from builtins import range
import re
import copy
import sys
import math
import time

import sympy
import numpy as np

from .tensors import matrix, mat2ten, Tensor
from .fslib import transform_position
from .symmetrize import symmetr,params_trans
from .symT import convert_vec

__all__ = ['create_rank2', 'sub_m', 'print_tensor', 'simplify_tensor', 'index_from_1', 'is_collinear', 'convert_mags',
           'get_L_trans', 'def_syms_L']

[docs] def create_rank2(ten,n_op=2,xyz=False): """ Creates a rank 2 tensor that includes magnetic moment explicitely. """ X = matrix(0,3) X.x = ten.x X.v = ten.v if ten.dim2 > 2: m = {} for i in range(3): if xyz: names = ['m_x','m_y','m_z'] name = names[i] else: name = 'm%s' % i m[i] = sympy.symbols(name) for ind in ten: M = 1 for i in range(2,len(ind)): M *= m[ind[i]] X[ind[0],ind[1]] += ten[ind]*M else: for ind in ten: X[ind] = ten[ind] return X
[docs] def sub_m(ten,n_op,xyz=False): X = Tensor(0, 3, n_op) if ten.dim2 > n_op: m = {} for i in range(3): if xyz: names = ['m_x','m_y','m_z'] name = names[i] else: name = 'm%s' % i m[i] = sympy.symbols(name) for ind in ten: M = 1 for i in range(n_op,len(ind)): M *= m[ind[i]] ind_m = [] for i in range(n_op): ind_m.append(ind[i]) ind_m = tuple(ind_m) X[ind_m] += ten[ind]*M else: for ind in ten: X[ind] = ten[ind] return X
[docs] def simplify_tensor(ten,xyz=False,index_from_1=False): """ Renames the variables of the tensor and simplifies it. """ X = create_rank2(ten,xyz=xyz) xinds = list(set(re.findall(r'x[0-9]+',sympy.srepr(X)))) #contains the new indices xn = {} if not index_from_1: for i in range(len(xinds)): xn[i] = sympy.symbols('x'+str(i)) else: for i in range(len(xinds)): xn[i] = sympy.symbols('x'+str(i+1)) for ind in X: for i in range(len(xinds)): X[ind] = X[ind].subs(xinds[i],xn[i]) X[ind] = sympy.simplify(X[ind]) return X
[docs] def index_from_1(X,rank=2): """ Takes a rank 3 tensor and rename the indeces so that the numbering starts from 1 and not 0. """ if rank == 2: xinds = list(set(re.findall(r'x[0-9]+',sympy.srepr(X)))) xn = {} xnz = {} for i in range(3): for j in range(3): xnz[(i,j)] = sympy.symbols('z'+str(i+1)+str(j+1)) for i in range(3): for j in range(3): xn[(i,j)] = sympy.symbols('x'+str(i+1)+str(j+1)) for ind in X: for i in range(3): for j in range(3): X[ind] = X[ind].subs(X.x[i,j],xnz[(i,j)]) for ind in X: for i in range(3): for j in range(3): X[ind] = X[ind].subs(xnz[(i,j)],xn[(i,j)]) return X if rank == 3: xinds = list(set(re.findall(r'x[0-9]+',sympy.srepr(X)))) xn = {} xnz = {} for i in range(3): for j in range(3): for k in range(3): xnz[(i,j,k)] = sympy.symbols('z'+str(i+1)+str(j+1)+str(k+1)) for i in range(3): for j in range(3): for k in range(3): xn[(i,j,k)] = sympy.symbols('x'+str(i+1)+str(j+1)+str(k+1)) for ind in X: for i in range(3): for j in range(3): for k in range(3): X[ind] = X[ind].subs(X.x[i,j,k],xnz[(i,j,k)]) for ind in X: for i in range(3): for j in range(3): for k in range(3): X[ind] = X[ind].subs(xnz[(i,j,k)],xn[(i,j,k)]) return X
[docs] def is_collinear(mags,prec=1e-5): res = True first = sorted(list(mags.keys()))[0] for i in mags: if abs(mags[first].dot(mags[i]))/mags[first].norm()/mags[i].norm() < 1-prec: res = False break return res
[docs] def convert_mags(mags,sym): mags_R = {} for atom in mags: mags_R[atom] = convert_vec(mags[atom],sym.get_R('s')) mags_Rp = {} perms = sym.permutations for atom in mags: mags_Rp[perms[atom]] = mags_R[atom] return mags_Rp
[docs] def get_L_trans(mags,sym,debug=False): initial_signs = [] atoms = sorted(list(mags.keys())) first = atoms[0] initial_signs = {} for atom in atoms: if mags[first].dot(mags[atom]) > 0: initial_signs[atom] = 1 else: initial_signs[atom] = -1 permuted_signs = {} for atom in atoms: permuted_signs[atom] = initial_signs[sym.permutations[atom]] if debug: print(initial_signs) print(permuted_signs) if all(initial_signs[atom] == permuted_signs[atom] for atom in atoms): return sym.Rs elif all(initial_signs[atom] == -permuted_signs[atom] for atom in atoms): return -sym.Rs else: return None #the code bellow is old and should be deleted mags_R = convert_mags(mags,sym) signs = [] for atom in atoms: if mags_R[first].dot(mags_R[atom]) > 0: signs.append(1) else: signs.append(-1) if debug: print('') print('transformed magnetic moments:') for atom in sorted(list(mags_R.keys())): print(atom, ":") sympy.pprint(mags_R[atom]) print('initial signs of magnetic moments') print(initial_signs) print('signs of the trasnformed moments') print(signs) if initial_signs != signs: return None else: mag_0_R = convert_vec(mags[first],sym.get_R('s')) sign_0 = mag_0_R.dot(mags_R[first]) if sign_0 > 0: sign = 1 else: sign = -1 if debug: print('sign: {}'.format(sign)) return sym.get_R('s')
#if signs == initial_signs: # return sym.get_R('s') #elif signs == [-s for s in initial_signs]: # return -sym.get_R('s') #else: # return None
[docs] def def_syms_L(mags,syms,prec=1e-5,debug=False): #select nonzero magnetic moments mags_dict = {} for i,mag in enumerate(mags): if mag.norm() > prec: mags_dict[i+1] = mag if debug: print('Starting defining L transformation') print('Nonzero magnetic moments') print(mags,mags_dict) for atom in sorted(list(mags_dict.keys())): print(atom, ":") sympy.pprint(mags_dict[atom]) if len(mags_dict) == 0: print("!!!Warning!!!: no magnetic moments defined in the input. Assuming a ferromagnetic system.") for sym in syms: sym.def_custom_R('N',sym.get_R('s')) syms_L = syms else: if not is_collinear(mags_dict,prec): raise Exception("Expansions only work for collinear magnetic systems") syms_L = [] for sym in syms: if debug: print('') print('Taking symmetry:') print(sym) L_trans = get_L_trans(mags_dict,sym,debug=debug) if debug: print('L_trans:') print(L_trans) if L_trans is not None: sym.def_custom_R('N',L_trans) syms_L.append(sym) return syms_L