mirror of
https://github.com/triqs/dft_tools
synced 2024-10-31 11:13:46 +01:00
239 lines
8.5 KiB
Python
239 lines
8.5 KiB
Python
##########################################################################
|
|
#
|
|
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
|
|
#
|
|
# Copyright (C) 2011 by M. Aichhorn, L. Pourovskii, V. Vildosola
|
|
#
|
|
# TRIQS is free software: you can redistribute it and/or modify it under the
|
|
# terms of the GNU General Public License as published by the Free Software
|
|
# Foundation, either version 3 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# TRIQS. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
##########################################################################
|
|
"""
|
|
Module for orbital basis transformations
|
|
"""
|
|
|
|
|
|
from triqs_dft_tools.sumk_dft import *
|
|
from triqs_dft_tools.converters import Wien2kConverter
|
|
from triqs.gf import *
|
|
from h5 import *
|
|
import triqs.utility.mpi as mpi
|
|
import numpy
|
|
import copy
|
|
|
|
|
|
class TransBasis:
|
|
"""
|
|
Computates rotations into a new basis, using the condition that a given property is diagonal in the new basis.
|
|
"""
|
|
|
|
def __init__(self, SK=None, hdf_datafile=None):
|
|
"""
|
|
Initialization of the class. There are two ways to do so:
|
|
|
|
- existing SumkLDA class : when you have an existing SumkLDA instance
|
|
- from hdf5 archive : when you want to use data from hdf5 archive
|
|
|
|
Giving the class instance overrides giving the string for the hdf5 archive.
|
|
|
|
Parameters
|
|
----------
|
|
SK : class SumkLDA, optional
|
|
Existing instance of SumkLDA class.
|
|
hdf5_datafile : string, optional
|
|
Name of hdf5 archive to be used.
|
|
|
|
"""
|
|
|
|
if SK is None:
|
|
# build our own SK instance
|
|
if hdf_datafile is None:
|
|
mpi.report("trans_basis: give SK instance or HDF filename!")
|
|
return 0
|
|
|
|
Converter = Wien2kConverter(filename=hdf_datafile, repacking=False)
|
|
Converter.convert_dft_input()
|
|
del Converter
|
|
|
|
self.SK = SumkDFT(hdf_file=hdf_datafile +
|
|
'.h5', use_dft_blocks=False)
|
|
else:
|
|
self.SK = SK
|
|
|
|
self.T = copy.deepcopy(self.SK.T[0])
|
|
self.w = numpy.identity(SK.corr_shells[0]['dim'])
|
|
|
|
def calculate_diagonalisation_matrix(self, prop_to_be_diagonal='eal', calc_in_solver_blocks = False):
|
|
"""
|
|
Calculates the diagonalisation matrix w, and stores it as member of the class.
|
|
|
|
Parameters
|
|
----------
|
|
prop_to_be_diagonal : string, optional
|
|
Defines the property to be diagonalized.
|
|
|
|
- 'eal' : local hamiltonian (i.e. crystal field)
|
|
- 'dm' : local density matrix
|
|
|
|
calc_in_solver_blocks : bool, optional
|
|
Whether the property shall be diagonalized in the
|
|
full sumk structure, or just in the solver structure.
|
|
|
|
Returns
|
|
-------
|
|
wsqr : double
|
|
Measure for the degree of rotation done by the diagonalisation. wsqr=1 means no rotation.
|
|
|
|
"""
|
|
|
|
if prop_to_be_diagonal == 'eal':
|
|
prop = self.SK.eff_atomic_levels()[0]
|
|
elif prop_to_be_diagonal == 'dm':
|
|
prop = self.SK.density_matrix(method='using_point_integration')[0]
|
|
else:
|
|
mpi.report(
|
|
"trans_basis: not a valid quantitiy to be diagonal. Choices are 'eal' or 'dm'.")
|
|
return 0
|
|
|
|
if calc_in_solver_blocks:
|
|
trafo = self.SK.block_structure.transformation
|
|
self.SK.block_structure.transformation = None
|
|
|
|
prop_solver = self.SK.block_structure.convert_matrix(prop, space_from='sumk', space_to='solver')
|
|
v= {}
|
|
for name in prop_solver:
|
|
v[name] = numpy.linalg.eigh(prop_solver[name])[1]
|
|
self.w = self.SK.block_structure.convert_matrix(v, space_from='solver', space_to='sumk')['ud' if self.SK.SO else 'up']
|
|
self.T = numpy.dot(self.T.transpose().conjugate(),
|
|
self.w).conjugate().transpose()
|
|
self.SK.block_structure.transformation = trafo
|
|
else:
|
|
if self.SK.SO == 0:
|
|
self.eig, self.w = numpy.linalg.eigh(prop['up'])
|
|
# calculate new Transformation matrix
|
|
self.T = numpy.dot(self.T.transpose().conjugate(),
|
|
self.w).conjugate().transpose()
|
|
else:
|
|
self.eig, self.w = numpy.linalg.eigh(prop['ud'])
|
|
# calculate new Transformation matrix
|
|
self.T = numpy.dot(self.T.transpose().conjugate(),
|
|
self.w).conjugate().transpose()
|
|
|
|
# measure for the 'unity' of the transformation:
|
|
wsqr = sum(abs(self.w.diagonal())**2) / self.w.diagonal().size
|
|
return wsqr
|
|
|
|
def rotate_gf(self, gf_to_rot):
|
|
"""
|
|
Uses the diagonalisation matrix w to rotate a given GF into the new basis.
|
|
|
|
Parameters
|
|
----------
|
|
gf_to_rot : BlockGf
|
|
Green's function block to rotate.
|
|
|
|
Returns
|
|
-------
|
|
gfreturn : BlockGf
|
|
Green's function rotated into the new basis.
|
|
"""
|
|
|
|
# build a full GF
|
|
gfrotated = BlockGf(name_block_generator=[(block, GfImFreq(
|
|
target_shape=(block_dim, block_dim), mesh=gf_to_rot.mesh)) for block, block_dim in self.SK.gf_struct_sumk[0]], make_copies=False)
|
|
|
|
# transform the CTQMC blocks to the full matrix:
|
|
# ish is the index of the inequivalent shell corresponding to icrsh
|
|
ish = self.SK.corr_to_inequiv[0]
|
|
for block, block_dim in self.gf_struct_solver[ish].items():
|
|
for ind1 in range(block_dim):
|
|
for ind2 in range(block_dim):
|
|
gfrotated[self.SK.solver_to_sumk_block[ish][block]][
|
|
ind1, ind2] << gf_to_rot[block][ind1, ind2]
|
|
|
|
# Rotate using the matrix w
|
|
for bname, gf in gfrotated:
|
|
gfrotated[bname].from_L_G_R(
|
|
self.w.transpose().conjugate(), gfrotated[bname], self.w)
|
|
|
|
gfreturn = gf_to_rot.copy()
|
|
# Put back into CTQMC basis:
|
|
for block, block_dim in self.gf_struct_solver[ish].items():
|
|
for ind1 in range(block_dim):
|
|
for ind2 in range(block_dim):
|
|
gfreturn[block][ind1, ind2] << gfrotated[
|
|
self.SK.solver_to_sumk_block[0][block]][ind1, ind2]
|
|
|
|
return gfreturn
|
|
|
|
def write_trans_file(self, filename):
|
|
"""
|
|
Writes the new transformation T into a file readable by dmftproj. By that, the requested quantity is
|
|
diagonal already at input.
|
|
|
|
Parameters
|
|
----------
|
|
filename : string
|
|
Name of the file where the transformation is stored.
|
|
"""
|
|
|
|
f = open(filename, 'w')
|
|
Tnew = self.T.conjugate()
|
|
dim = self.SK.corr_shells[0]['dim']
|
|
|
|
if self.SK.SO == 0:
|
|
|
|
for i in range(dim):
|
|
st = ''
|
|
for k in range(dim):
|
|
st += " %9.6f" % (Tnew[i, k].real)
|
|
st += " %9.6f" % (Tnew[i, k].imag)
|
|
for k in range(2 * dim):
|
|
st += " 0.0"
|
|
|
|
if i < (dim - 1):
|
|
f.write("%s\n" % (st))
|
|
else:
|
|
st1 = st.replace(' ', '*', 1)
|
|
f.write("%s\n" % (st1))
|
|
|
|
for i in range(dim):
|
|
st = ''
|
|
for k in range(2 * dim):
|
|
st += " 0.0"
|
|
for k in range(dim):
|
|
st += " %9.6f" % (Tnew[i, k].real)
|
|
st += " %9.6f" % (Tnew[i, k].imag)
|
|
|
|
if i < (dim - 1):
|
|
f.write("%s\n" % (st))
|
|
else:
|
|
st1 = st.replace(' ', '*', 1)
|
|
f.write("%s\n" % (st1))
|
|
|
|
else:
|
|
|
|
for i in range(dim):
|
|
st = ''
|
|
for k in range(dim):
|
|
st += " %9.6f" % (Tnew[i, k].real)
|
|
st += " %9.6f" % (Tnew[i, k].imag)
|
|
|
|
if i < (dim - 1):
|
|
f.write("%s\n" % (st))
|
|
else:
|
|
st1 = st.replace(' ', '*', 1)
|
|
f.write("%s\n" % (st1))
|
|
|
|
f.close()
|