mirror of
https://github.com/triqs/dft_tools
synced 2024-08-17 01:31:44 +02:00
![AlynJ](/assets/img/avatar_default.png)
updated the Elk interface to fix some minor bugs which arose for certain systems with equivalent atoms. I've also included new tests for this interface and collated all of these interface tests in the "test/python/elk" subdirectory.
650 lines
29 KiB
Python
650 lines
29 KiB
Python
|
|
##########################################################################
|
|
#
|
|
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
|
|
#
|
|
# Copyright (C) 2019 by A. D. N. James, A. Hampel and M. Aichhorn
|
|
#
|
|
# 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/>.
|
|
#
|
|
##########################################################################
|
|
"""
|
|
Elk converter
|
|
"""
|
|
|
|
from types import *
|
|
import numpy
|
|
from .converter_tools import *
|
|
import os.path
|
|
from h5 import *
|
|
from locale import atof
|
|
from triqs_dft_tools.converters.elktools import readElkfiles as read_Elk
|
|
from triqs_dft_tools.converters.elktools import ElkConverterTools as Elk_tools
|
|
|
|
class ElkConverter(ConverterTools,Elk_tools,read_Elk):
|
|
"""
|
|
Conversion from Elk output to an hdf5 file that can be used as input for the SumkDFT class.
|
|
"""
|
|
|
|
def __init__(self, filename, hdf_filename=None,
|
|
dft_subgrp='dft_input', symmcorr_subgrp='dft_symmcorr_input',
|
|
bc_subgrp='dft_bandchar_input', symmpar_subgrp='dft_symmpar_input',
|
|
bands_subgrp='dft_bands_input', misc_subgrp='dft_misc_input',
|
|
transp_subgrp='dft_transp_input',fs_subgrp='dft_fs_input',
|
|
repacking=False):
|
|
"""
|
|
Initialise the class.
|
|
|
|
Parameters
|
|
----------
|
|
filename : string
|
|
Base name of DFT files.
|
|
hdf_filename : string, optional
|
|
Name of hdf5 archive to be created.
|
|
dft_subgrp : string, optional
|
|
Name of subgroup storing necessary DFT data.
|
|
symmcorr_subgrp : string, optional
|
|
Name of subgroup storing correlated-shell symmetry data.
|
|
parproj_subgrp : string, optional
|
|
Name of subgroup storing partial projector data.
|
|
symmpar_subgrp : string, optional
|
|
Name of subgroup storing partial-projector symmetry data.
|
|
bands_subgrp : string, optional
|
|
Name of subgroup storing band data.
|
|
misc_subgrp : string, optional
|
|
Name of subgroup storing miscellaneous DFT data.
|
|
transp_subgrp : string, optional
|
|
Name of subgroup storing transport data.
|
|
repacking : boolean, optional
|
|
Does the hdf5 archive need to be repacked to save space?
|
|
|
|
"""
|
|
|
|
assert isinstance(filename, str), "ElkConverter: Please provide the DFT files' base name as a string."
|
|
if hdf_filename is None:
|
|
hdf_filename = filename + '.h5'
|
|
self.hdf_file = hdf_filename
|
|
self.dft_file = 'PROJ.OUT'
|
|
self.band_file = 'BAND.OUT'
|
|
self.eval_file = 'EIGVAL.OUT'
|
|
self.efermi_file = 'EFERMI.OUT'
|
|
self.kp_file = 'KPOINTS.OUT'
|
|
self.geom_file='GEOMETRY.OUT'
|
|
self.dft_subgrp = dft_subgrp
|
|
self.symmcorr_subgrp = symmcorr_subgrp
|
|
self.bc_subgrp = bc_subgrp
|
|
self.symmpar_subgrp = symmpar_subgrp
|
|
self.bands_subgrp = bands_subgrp
|
|
self.misc_subgrp = misc_subgrp
|
|
self.transp_subgrp = transp_subgrp
|
|
self.fs_subgrp = fs_subgrp
|
|
self.fortran_to_replace = {'D': 'E'}
|
|
|
|
# Checks if h5 file is there and repacks it if wanted:
|
|
if (os.path.exists(self.hdf_file) and repacking):
|
|
ConverterTools.repack(self)
|
|
|
|
def check_dens(self,n_k,nstsv,occ,bz_weights,n_spin_blocs,band_window,SO):
|
|
"""
|
|
Check the charge density below the correlated energy window and up to the Fermi level
|
|
"""
|
|
|
|
density_required=0.0E-7
|
|
charge_below=0.0E-7
|
|
#calculate the valence charge and charge below lower energy window bound
|
|
#Elk does not use the tetrahedron method when calculating these charges
|
|
for ik in range(n_k):
|
|
for ist in range(nstsv):
|
|
#calculate the charge over all the bands
|
|
density_required+=occ[ik][ist]*bz_weights[ik]
|
|
for isp in range(n_spin_blocs):
|
|
#Convert occ list from elk to two index format for spins
|
|
jst=int((isp)*nstsv*0.5)
|
|
#Take lowest index in band_window for SO system
|
|
if(SO==0):
|
|
nst=band_window[isp][ik, 0]-1
|
|
else:
|
|
band=[band_window[0][ik, 0],band_window[1][ik, 0]]
|
|
nst=min(band)-1
|
|
#calculate the charge below energy window
|
|
for ist in range(jst,nst):
|
|
charge_below+=occ[ik][ist]*bz_weights[ik]
|
|
#return charges
|
|
return(density_required,charge_below)
|
|
|
|
def rotsym(self,n_shells,shells,n_symm,ind,basis,T,mat):
|
|
"""
|
|
Rotates the symmetry matrices into basis defined by the T unitary matrix
|
|
the outputted projectors are rotated to the irreducible representation
|
|
and then reduced in size to the orbitals used to construct the projectors.
|
|
"""
|
|
|
|
for ish in range(n_shells):
|
|
#check that the T matrix is not the Identity (i.e. not using spherical
|
|
#harmonics).
|
|
if(basis[ish]!=0):
|
|
#put mat into temporary matrix
|
|
temp=mat
|
|
#index range of lm values used to create the Wannier projectors
|
|
min_ind=numpy.min(ind[ish][:])
|
|
max_ind=numpy.max(ind[ish][:])+1
|
|
#dimension of lm values used to construct the projectors
|
|
dim=shells[ish]['dim']
|
|
#loop over all symmetries
|
|
for isym in range(n_symm):
|
|
#rotate symmetry matrix into basis defined by T
|
|
mat[isym][ish]=numpy.matmul(T[ish],mat[isym][ish])
|
|
mat[isym][ish]=numpy.matmul(mat[isym][ish],T[ish].conjugate().transpose())
|
|
#put desired subset of transformed symmetry matrix into temp matrix for symmetry isym
|
|
for id in range(len(ind[ish])):
|
|
i=ind[ish][id]
|
|
for jd in range(len(ind[ish][:])):
|
|
j=ind[ish][jd]
|
|
temp[isym][ish][id,jd]=mat[isym][ish][i,j]
|
|
#put temp matrix into mat
|
|
mat=temp
|
|
#reduce size of lm arrays in mat lm dim
|
|
for isym in range(n_symm):
|
|
dim=shells[ish]['dim']
|
|
mat[isym][ish]=mat[isym][ish][:dim,:dim]
|
|
return mat
|
|
|
|
def update_so_quatities(self,n_shells,shells,n_corr_shells,corr_shells,n_inequiv_shells,dim_reps,n_k,n_symm,n_orbitals,proj_mat,T,su2,mat,sym=True):
|
|
"""
|
|
Changes the array sizes and elements for arrays used in spin-orbit coupled calculations.
|
|
"""
|
|
|
|
#change dim for each shell
|
|
for ish in range(n_shells):
|
|
shells[ish]['dim'] *= 2
|
|
for ish in range(n_corr_shells):
|
|
corr_shells[ish]['dim'] *= 2
|
|
for ish in range(n_inequiv_shells):
|
|
dim_reps[ish]=[2*dim_reps[ish][i] for i in range(len(dim_reps[ish]))]
|
|
#Make temporary array of original n_orbitals
|
|
n_orbitals_orig=n_orbitals
|
|
#Make SO n_orbitals array
|
|
#loop over k-points
|
|
for ik in range(n_k):
|
|
#new orbital array
|
|
n_orbitals[ik,0]=max(n_orbitals[ik,:])
|
|
#reduce array size
|
|
n_orbitals=n_orbitals[:,:1]
|
|
#Resize proj_mat, mat, T
|
|
#make temporary projector array
|
|
proj_mat_tmp = numpy.zeros([n_k, 1, n_corr_shells, max([crsh['dim'] for crsh in corr_shells]), numpy.max(n_orbitals)], numpy.complex_)
|
|
for ish in range(n_corr_shells):
|
|
#update proj_mat
|
|
for ik in range(n_k):
|
|
#extra array elements in "dim" dimension
|
|
size=int(0.5*corr_shells[ish]['dim'])
|
|
#put each spinor into tmp array and ensure elements are assigned correctly in case of change of max(n_orbitals)
|
|
proj_mat_tmp[ik][0][ish][0:size][0:n_orbitals_orig[ik,0]]=proj_mat[ik][0][ish][0:size][0:n_orbitals_orig[ik,0]]
|
|
#put other spinor projectors into extra "dim" elements
|
|
proj_mat_tmp[ik][0][ish][size:2*size][0:n_orbitals_orig[ik,1]]=proj_mat[ik][1][ish][0:size][0:n_orbitals_orig[ik,1]]
|
|
#update T
|
|
#extra array elements in each dimension
|
|
size=2*corr_shells[ish]['l']+1
|
|
#extend the arrays
|
|
T[ish]=numpy.lib.pad(T[ish],((0,size),(0,size)),'constant',constant_values=(0.0))
|
|
#make block diagonal
|
|
T[ish][size:2*size,size:2*size]=T[ish][0:size,0:size]
|
|
#update the symmetries arrays if needed
|
|
if(sym):
|
|
#update mat - This includes the spin SU(2) matrix for spin-coupled calculations
|
|
#size of each quadrant in the lm symmetry array.
|
|
size=int(0.5*corr_shells[ish]['dim'])
|
|
#temporary spin block array for SU(2) spin operations on mat
|
|
spinmat = numpy.zeros([size,2,size,2],numpy.complex_)
|
|
for isym in range(n_symm):
|
|
#expand size of array
|
|
mat[isym][ish]=numpy.lib.pad(mat[isym][ish],((0,size),(0,size)),'constant',constant_values=(0.0))
|
|
#make arraye block diagonal
|
|
mat[isym][ish][size:2*size,size:2*size]=mat[isym][ish][0:size,0:size]
|
|
#apply SU(2) spin matrices to lm symmetries
|
|
#put mat into array of spin blocks
|
|
for i1,i2 in numpy.ndindex(2,2):
|
|
spinmat[0:size,i1,0:size,i2] = mat[isym][ish][i1*size:(i1+1)*size,i2*size:(i2+1)*size]
|
|
#apply the SU(2) spin matrices
|
|
for ilm,jlm in numpy.ndindex(size,size):
|
|
spinmat[ilm,:,jlm,:] = numpy.dot(su2[isym][:,:],spinmat[ilm,:,jlm,:])
|
|
#put spinmat into back in mat format
|
|
for i1,i2 in numpy.ndindex(2,2):
|
|
mat[isym][ish][i1*size:(i1+1)*size,i2*size:(i2+1)*size] = spinmat[0:size,i1,0:size,i2]
|
|
#assign arrays and delete temporary arrays
|
|
del proj_mat
|
|
proj_mat = proj_mat_tmp
|
|
del proj_mat_tmp, n_orbitals_orig
|
|
return shells,corr_shells,dim_reps,n_orbitals,proj_mat,T,mat
|
|
|
|
def sort_dft_eigvalues(self,n_spin_blocs,SO,n_k,n_orbitals,band_window,en,energy_unit):
|
|
"""
|
|
Rearranges the energy eigenvalue arrays into TRIQS format
|
|
"""
|
|
|
|
hopping = numpy.zeros([n_k, n_spin_blocs, numpy.max(n_orbitals), numpy.max(n_orbitals)], numpy.complex_)
|
|
#loop over spin
|
|
for isp in range(n_spin_blocs):
|
|
#loop over k-points
|
|
for ik in range(n_k):
|
|
#loop over bands
|
|
for ist in range(0,n_orbitals[ik, isp]):
|
|
#converter index for spin polarised Elk indices and take SO into consideration
|
|
if(SO==0):
|
|
jst=int(band_window[isp][ik, 0]-1+ist)
|
|
else:
|
|
band=[band_window[0][ik, 0],band_window[1][ik, 0]]
|
|
jst=int(min(band)-1+ist)
|
|
#correlated window energies
|
|
hopping[ik,isp,ist,ist]=en[ik][jst]*energy_unit
|
|
return hopping
|
|
|
|
def convert_dft_input(self):
|
|
"""
|
|
Reads the appropriate files and stores the data for the
|
|
|
|
- dft_subgrp
|
|
- symmcorr_subgrp
|
|
- misc_subgrp
|
|
|
|
in the hdf5 archive.
|
|
|
|
"""
|
|
# Read and write only on the master node
|
|
if not (mpi.is_master_node()):
|
|
return
|
|
filext='.OUT'
|
|
dft_file='PROJ'+filext
|
|
mpi.report("Reading %s" % dft_file)
|
|
#Energy conversion - Elk uses Hartrees
|
|
energy_unit = 27.2113850560 # Elk uses hartrees
|
|
#The projectors change size per k-point
|
|
k_dep_projection = 1
|
|
#Symmetries are used
|
|
symm_op = 1 # Use symmetry groups for the k-sum
|
|
shells=[]
|
|
#read information about projectors calculated in the Elk calculation
|
|
[gen_info,n_corr_shells,n_inequiv_shells,corr_to_inequiv,inequiv_to_corr,corr_shells,n_reps,dim_reps,ind,basis,T] = read_Elk.read_proj(self,dft_file)
|
|
#get info for HDF5 file from gen_info
|
|
n_k=gen_info['n_k']
|
|
SP=gen_info['spinpol']-1
|
|
#Elk uses spinor wavefunctions. Therefore these two spinor wavefunctions have spin-orbit coupling incorporated in them. Here we read in the spinors
|
|
n_spin_blocs = SP + 1
|
|
SO=gen_info['SO']
|
|
n_atoms=gen_info['natm']
|
|
#Elk only calculates Wannier projectors (no theta projectors generated):
|
|
n_shells=n_corr_shells
|
|
for ish in range(n_shells):
|
|
shells.append(corr_shells[ish].copy())
|
|
#remove last 2 entries from corr_shlls
|
|
del shells[ish]['SO']
|
|
del shells[ish]['irep']
|
|
shells[ish]['dim'] = 2*shells[ish]['l']+1
|
|
#read eigenvalues calculated in the Elk calculation
|
|
mpi.report("Reading %s and EFERMI.OUT" % self.eval_file)
|
|
[en,occ,nstsv]=read_Elk.read_eig(self)
|
|
#read projectors calculated in the Elk calculation
|
|
proj_mat = numpy.zeros([n_k, n_spin_blocs, n_corr_shells, max([crsh['dim'] for crsh in corr_shells]), nstsv], numpy.complex_)
|
|
mpi.report("Reading projector(s)")
|
|
for ish in range(n_corr_shells):
|
|
[n_orbitals,band_window,rep,proj_mat]=read_Elk.read_projector(self,corr_shells,n_spin_blocs,ish,proj_mat,ind,T,basis,filext)
|
|
#read kpoints calculated in the Elk calculation
|
|
mpi.report("Reading %s" % self.kp_file)
|
|
[bz_weights,vkl]=read_Elk.read_kpoints(self)
|
|
#symmetry matrix
|
|
mpi.report("Reading GEOMETRY.OUT")
|
|
#read in atom positions, the symmetry operators (in lattice coordinates) and lattice vectors
|
|
[ns, na, atpos]=read_Elk.read_geometry(self)
|
|
#Read symmetry files
|
|
mpi.report("Reading SYMCRYS.OUT")
|
|
[n_symm,spinmat,symmat,tr] = read_Elk.readsym(self)
|
|
mpi.report("Reading LATTICE.OUT")
|
|
[amat,amatinv,bmat,bmatinv] = read_Elk.readlat(self)
|
|
#calculating atom permutations
|
|
perm = Elk_tools.gen_perm(self,n_symm,ns,na,n_atoms,symmat,tr,atpos)
|
|
#determine the cartesian lattice symmetries and the spin axis rotations
|
|
#required for the spinors (for SO for now)
|
|
su2 = []
|
|
symmatc=[]
|
|
for isym in range(n_symm):
|
|
#convert the lattice symmetry matrices into cartesian coordinates
|
|
tmp = numpy.matmul(amat,symmat[isym])
|
|
symmatc.append(numpy.matmul(tmp,amatinv))
|
|
#convert the spin symmetry matrices into cartesian coordinates
|
|
spinmatc = numpy.matmul(amat,spinmat[isym])
|
|
spinmatc = numpy.matmul(spinmatc,amatinv)
|
|
#calculate the rotation angle and spin axis vector in cartesian coordinates
|
|
[v,th] = self.rotaxang(spinmatc[:,:])
|
|
#calculate the SU(2) matrix from the angle and spin axis vector
|
|
su2.append(self.axangsu2(v,th))
|
|
del tmp
|
|
|
|
#calculating the symmetries in complex harmonics
|
|
mat = Elk_tools.symlat_to_complex_harmonics(self,n_symm,n_corr_shells,symmatc,corr_shells)
|
|
mat = self.rotsym(n_corr_shells,corr_shells,n_symm,ind,basis,T,mat)
|
|
|
|
#The reading is done. Some variables may need to change for TRIQS compatibility.
|
|
#Alter size of some of the arrays if spin orbit coupling is enabled.
|
|
#For SO in Elk, the eigenvalues and eigenvector band indices are in asscending order w.r.t energy
|
|
if(SO==1):
|
|
[shells,corr_shells,dim_reps,n_orbitals,proj_mat,T,mat]=self.update_so_quatities(n_shells,shells,n_corr_shells,corr_shells,n_inequiv_shells,dim_reps,n_k,n_symm,n_orbitals,proj_mat,T,su2,mat)
|
|
#reduce n_spin_blocs
|
|
n_spin_blocs = SP + 1 - SO
|
|
|
|
#put the energy eigenvalues arrays in TRIQS format
|
|
hopping = self.sort_dft_eigvalues(n_spin_blocs,SO,n_k,n_orbitals,band_window,en,energy_unit)
|
|
|
|
#Elk does not use global to local matrix rotation (Rotloc) as is done in Wien2k. However, the projectors
|
|
#require a symmetry matrix to rotate from jatom to iatom. Below finds the non inversion
|
|
#symmetric matrices which were used in calculating the projectors
|
|
use_rotations = 1
|
|
rot_mat = [numpy.identity(corr_shells[icrsh]['dim'], numpy.complex_) for icrsh in range(n_corr_shells)]
|
|
for icrsh in range(n_corr_shells):
|
|
#return inequivalent index
|
|
incrsh = corr_to_inequiv[icrsh]
|
|
#return first inequivalent corr_shell index
|
|
jcrsh = inequiv_to_corr[incrsh]
|
|
#want to rotate atom to first inequivalent atom in list
|
|
iatom = corr_shells[jcrsh]['atom']
|
|
for isym in range(n_symm):
|
|
jatom=perm[isym][corr_shells[icrsh]['atom']-1]
|
|
#determinant determines if crystal symmetry matrix has inversion symmetry (=-1)
|
|
det = numpy.linalg.det(symmat[isym][:,:])
|
|
if((jatom==iatom)&(det>0.0)):
|
|
#local rotation which rotates equivalent atom into its local coordinate system
|
|
#(inverse of the symmetry operator applied to the projectors in Elk)
|
|
rot_mat[icrsh][:,:]=mat[isym][icrsh][:,:].conjugate().transpose()
|
|
#used first desired symmetry in crystal symmetry list
|
|
break
|
|
# Elk does not currently use time inversion symmetry
|
|
rot_mat_time_inv = [0 for i in range(n_corr_shells)]
|
|
|
|
#Check that the charge of all the bands and below the correlated window have been calculated correctly
|
|
[density_required, charge_below] = self.check_dens(n_k,nstsv,occ,bz_weights,n_spin_blocs,band_window,SO)
|
|
#calculate the required charge (density_required) to remain charge neutral
|
|
mpi.report("The total charge of the system = %f" %density_required)
|
|
mpi.report("The charge below the correlated window = %f" %charge_below)
|
|
mpi.report("The charge within the correlated window = %f" %(density_required - charge_below))
|
|
|
|
#Elk interface does not calculate theta projectors, hence orbits are the same as Wannier projectors
|
|
orbits=[]
|
|
#remove the spatom index to avoid errors in the symmetry routines
|
|
for ish in range(n_corr_shells):
|
|
#remove "spatom"
|
|
del corr_shells[ish]['spatom']
|
|
orbits.append(corr_shells[ish].copy())
|
|
for ish in range(n_shells):
|
|
#remove "spatom"
|
|
del shells[ish]['spatom']
|
|
n_orbits=len(orbits)
|
|
|
|
#Note that the T numpy array is defined for all shells.
|
|
|
|
# Save it to the HDF:
|
|
ar = HDFArchive(self.hdf_file, 'a')
|
|
if not (self.dft_subgrp in ar):
|
|
ar.create_group(self.dft_subgrp)
|
|
# The subgroup containing the data. If it does not exist, it is
|
|
# created. If it exists, the data is overwritten!
|
|
things_to_save = ['energy_unit', 'n_k', 'k_dep_projection', 'SP', 'SO', 'charge_below', 'density_required',
|
|
'symm_op', 'n_shells', 'shells', 'n_corr_shells', 'corr_shells', 'use_rotations', 'rot_mat',
|
|
'rot_mat_time_inv', 'n_reps', 'dim_reps', 'T', 'n_orbitals', 'proj_mat', 'bz_weights', 'hopping',
|
|
'n_inequiv_shells', 'corr_to_inequiv', 'inequiv_to_corr']
|
|
for it in things_to_save:
|
|
ar[self.dft_subgrp][it] = locals()[it]
|
|
del ar
|
|
# Save it to the HDF:
|
|
ar = HDFArchive(self.hdf_file, 'a')
|
|
symm_subgrp=self.symmcorr_subgrp
|
|
#Elk does not use time inversion symmetry
|
|
time_inv = [0 for j in range(n_symm)]
|
|
mat_tinv = [numpy.identity(orbits[orb]['dim'], numpy.complex_)
|
|
for orb in range(n_orbits)]
|
|
#Save all the symmetry data
|
|
if not (symm_subgrp in ar):
|
|
ar.create_group(symm_subgrp)
|
|
things_to_save_sym = ['n_symm', 'n_atoms', 'perm',
|
|
'orbits', 'SO', 'SP', 'time_inv', 'mat', 'mat_tinv']
|
|
for it in things_to_save_sym:
|
|
ar[symm_subgrp][it] = locals()[it]
|
|
del ar
|
|
#Save misc info
|
|
things_to_save_misc = ['band_window','vkl','nstsv']
|
|
# Save it to the HDF:
|
|
ar = HDFArchive(self.hdf_file, 'a')
|
|
if not (self.misc_subgrp in ar):
|
|
ar.create_group(self.misc_subgrp)
|
|
for it in things_to_save_misc:
|
|
ar[self.misc_subgrp][it] = locals()[it]
|
|
del ar
|
|
mpi.report('Converted the Elk ground state data')
|
|
|
|
|
|
def convert_bands_input(self):
|
|
"""
|
|
Reads the appropriate files and stores the data for the bands_subgrp in the hdf5 archive.
|
|
|
|
"""
|
|
# Read and write only on the master node
|
|
if not (mpi.is_master_node()):
|
|
return
|
|
filext='_WANBAND.OUT'
|
|
dft_file='PROJ'+filext
|
|
mpi.report("Reading %s" % dft_file)
|
|
#Energy conversion - Elk uses Hartrees
|
|
energy_unit = 27.2113850560 # Elk uses hartrees
|
|
shells=[]
|
|
#read information about projectors calculated in the Elk calculation
|
|
[gen_info,n_corr_shells,n_inequiv_shells,corr_to_inequiv,inequiv_to_corr,corr_shells,n_reps,dim_reps,ind,basis,T] = read_Elk.read_proj(self,dft_file)
|
|
#get info for HDF5 file from gen_info
|
|
n_k=gen_info['n_k']
|
|
SP=gen_info['spinpol']-1
|
|
#Elk uses spinor wavefunctions. Therefore these two spinor wavefunctions have spin-orbit coupling incorporated in them. Here we read in the spinors
|
|
n_spin_blocs = SP + 1
|
|
SO=gen_info['SO']
|
|
#Elk only calculates Wannier projectors (no theta projectors generated):
|
|
n_shells=n_corr_shells
|
|
for ish in range(n_shells):
|
|
shells.append(corr_shells[ish].copy())
|
|
#remove last 2 entries from corr_shlls
|
|
del shells[ish]['SO']
|
|
del shells[ish]['irep']
|
|
shells[ish]['dim'] = 2*shells[ish]['l']+1
|
|
|
|
#read in the band eigenvalues
|
|
mpi.report("Reading BAND.OUT")
|
|
en=numpy.loadtxt('BAND.OUT')
|
|
nstsv=int(len(en[:,1])/n_k)
|
|
#convert the en array into a workable format
|
|
entmp = numpy.zeros([n_k,nstsv], numpy.complex_)
|
|
enj=0
|
|
for ist in range(nstsv):
|
|
for ik in range(n_k):
|
|
entmp[ik,ist]=en[enj,1]
|
|
enj+=1
|
|
del en
|
|
#read projectors
|
|
proj_mat = numpy.zeros([n_k, n_spin_blocs, n_corr_shells, max([crsh['dim'] for crsh in corr_shells]), nstsv], numpy.complex_)
|
|
mpi.report("Reading projector(s)")
|
|
for ish in range(n_corr_shells):
|
|
[n_orbitals,band_window,rep,proj_mat]=read_Elk.read_projector(self,corr_shells,n_spin_blocs,ish,proj_mat,ind,T,basis,filext)
|
|
|
|
#alter arrays for spin-orbit coupling
|
|
if(SO==1):
|
|
mat=[]
|
|
su2=[]
|
|
n_symm=1
|
|
[shells,corr_shells,dim_reps,n_orbitals,proj_mat,T,mat]=self.update_so_quatities(n_shells,shells,n_corr_shells,corr_shells,n_inequiv_shells,dim_reps,n_k,n_symm,n_orbitals,proj_mat,T,su2,mat,sym=False)
|
|
#reduce n_spin_blocs
|
|
n_spin_blocs = SP + 1 - SO
|
|
|
|
#put the energy eigenvalues arrays in TRIQS format
|
|
hopping = self.sort_dft_eigvalues(n_spin_blocs,SO,n_k,n_orbitals,band_window,entmp,energy_unit)
|
|
|
|
# No partial projectors generated here, so set to 0:
|
|
n_parproj = numpy.array([0])
|
|
proj_mat_all = numpy.array([0])
|
|
|
|
# Save it to the HDF:
|
|
ar = HDFArchive(self.hdf_file, 'a')
|
|
if not (self.bands_subgrp in ar):
|
|
ar.create_group(self.bands_subgrp)
|
|
# The subgroup containing the data. If it does not exist, it is
|
|
# created. If it exists, the data is overwritten!
|
|
things_to_save = ['n_k', 'n_orbitals', 'proj_mat',
|
|
'hopping', 'n_parproj', 'proj_mat_all']
|
|
for it in things_to_save:
|
|
ar[self.bands_subgrp][it] = locals()[it]
|
|
del ar
|
|
mpi.report('Converted the band data')
|
|
|
|
def convert_fs_input(self):
|
|
"""
|
|
Reads the appropriate files and stores the data for the FS_subgrp in the hdf5 archive.
|
|
|
|
"""
|
|
# Read and write only on the master node
|
|
if not (mpi.is_master_node()):
|
|
return
|
|
filext='_FS.OUT'
|
|
dft_file='PROJ'+filext
|
|
mpi.report("Reading %s" % dft_file)
|
|
#Energy conversion - Elk uses Hartrees
|
|
energy_unit = 27.2113850560 # Elk uses hartrees
|
|
shells=[]
|
|
#read information about projectors calculated in the Elk calculation
|
|
[gen_info,n_corr_shells,n_inequiv_shells,corr_to_inequiv,inequiv_to_corr,corr_shells,n_reps,dim_reps,ind,basis,T] = read_Elk.read_proj(self,dft_file)
|
|
#get info for HDF5 file from gen_info
|
|
n_k=gen_info['n_k']
|
|
SP=gen_info['spinpol']-1
|
|
#Elk uses spinor wavefunctions. Therefore these two spinor wavefunctions have spin-orbit coupling incorporated in them. Here we read in the spinors
|
|
n_spin_blocs = SP + 1
|
|
SO=gen_info['SO']
|
|
#Elk only calculates Wannier projectors (no theta projectors generated):
|
|
n_shells=n_corr_shells
|
|
for ish in range(n_shells):
|
|
shells.append(corr_shells[ish].copy())
|
|
#remove last 2 entries from corr_shlls
|
|
del shells[ish]['SO']
|
|
del shells[ish]['irep']
|
|
shells[ish]['dim'] = 2*shells[ish]['l']+1
|
|
|
|
#read in the eigenvalues used for the FS calculation
|
|
mpi.report("Reading EIGVAL_FS.OUT and EFERMI.OUT")
|
|
[en,occ,nstsv]=read_Elk.read_eig(self,filext=filext)
|
|
#read kpoints calculated in the Elk FS calculation
|
|
mpi.report("Reading KPOINT_FS.OUT")
|
|
[bz_weights,vkl]=read_Elk.read_kpoints(self,filext=filext)
|
|
|
|
#read projectors
|
|
proj_mat = numpy.zeros([n_k, n_spin_blocs, n_corr_shells, max([crsh['dim'] for crsh in corr_shells]), nstsv], numpy.complex_)
|
|
mpi.report("Reading projector(s)")
|
|
for ish in range(n_corr_shells):
|
|
[n_orbitals,band_window,rep,proj_mat]=read_Elk.read_projector(self,corr_shells,n_spin_blocs,ish,proj_mat,ind,T,basis,filext)
|
|
|
|
#Need lattice symmetries to unfold the irreducible BZ
|
|
#Read symmetry files
|
|
mpi.report("Reading SYMCRYS.OUT")
|
|
[n_symm,spinmat,symlat,tr] = read_Elk.readsym(self)
|
|
mpi.report("Reading LATTICE.OUT")
|
|
[amat,amatinv,bmat,bmatinv] = read_Elk.readlat(self)
|
|
#Put eigenvalues into array of eigenvalues for the correlated window
|
|
#alter arrays for spin-orbit coupling
|
|
if(SO==1):
|
|
mat=[]
|
|
su2=[]
|
|
[shells,corr_shells,dim_reps,n_orbitals,proj_mat,T,mat]=self.update_so_quatities(n_shells,shells,n_corr_shells,corr_shells,n_inequiv_shells,dim_reps,n_k,n_symm,n_orbitals,proj_mat,T,su2,mat,sym=False)
|
|
#reduce n_spin_blocs
|
|
n_spin_blocs = SP + 1 - SO
|
|
|
|
#put the energy eigenvalues arrays in TRIQS format
|
|
hopping = self.sort_dft_eigvalues(n_spin_blocs,SO,n_k,n_orbitals,band_window,en,energy_unit)
|
|
|
|
# Save it to the HDF:
|
|
ar = HDFArchive(self.hdf_file, 'a')
|
|
if not (self.fs_subgrp in ar):
|
|
ar.create_group(self.fs_subgrp)
|
|
# The subgroup containing the data. If it does not exist, it is
|
|
# created. If it exists, the data is overwritten!
|
|
things_to_save = ['n_k', 'n_orbitals', 'proj_mat','bmat',
|
|
'hopping', 'vkl','symlat', 'n_symm']
|
|
for it in things_to_save:
|
|
ar[self.fs_subgrp][it] = locals()[it]
|
|
del ar
|
|
mpi.report('Converted the FS data')
|
|
|
|
def dft_band_characters(self):
|
|
"""
|
|
Reads in the band characters generated in Elk to be used for
|
|
PDOS and band character band structure plots.
|
|
"""
|
|
|
|
if not (mpi.is_master_node()):
|
|
return
|
|
mpi.report("Reading BC.OUT")
|
|
|
|
# get needed data from hdf file
|
|
# from general info
|
|
ar = HDFArchive(self.hdf_file, 'a')
|
|
things_to_read = ['SP', 'SO','n_k','n_orbitals']
|
|
for it in things_to_read:
|
|
if not hasattr(self, it):
|
|
setattr(self, it, ar[self.dft_subgrp][it])
|
|
#from misc info
|
|
things_to_read = ['nstsv','band_window']
|
|
for it in things_to_read:
|
|
if not hasattr(self, it):
|
|
setattr(self, it, ar[self.misc_subgrp][it])
|
|
#from sym info
|
|
things_to_read = ['n_atoms']
|
|
symm_subgrp=self.symmcorr_subgrp
|
|
for it in things_to_read:
|
|
if not hasattr(self, it):
|
|
setattr(self, it, ar[symm_subgrp][it])
|
|
|
|
#read in band characters
|
|
[bc,maxlm] = read_Elk.read_bc(self)
|
|
#set up SO bc array
|
|
if (self.SO):
|
|
tmp = numpy.zeros([2*maxlm,1,self.n_atoms,self.nstsv,self.n_k], numpy.float_)
|
|
#put both spinors into the lm array indices.
|
|
tmp[0:maxlm,0,:,:,:]=bc[0:maxlm,0,:,:,:]
|
|
tmp[maxlm:2*maxlm,0,:,:,:]=bc[0:maxlm,1,:,:,:]
|
|
maxlm=2*maxlm
|
|
del bc
|
|
bc = tmp
|
|
del tmp
|
|
|
|
#reduce bc matrix to band states stored in hdf file
|
|
n_spin_blocs=self.SP+1-self.SO
|
|
tmp = numpy.zeros([maxlm,n_spin_blocs,self.n_atoms,numpy.max(self.n_orbitals),self.n_k], numpy.float_)
|
|
for ik in range(self.n_k):
|
|
for isp in range(n_spin_blocs):
|
|
nst=self.n_orbitals[ik,isp]
|
|
ibot=self.band_window[isp][ik, 0]-1
|
|
itop=ibot+nst
|
|
tmp[:,isp,:,0:nst,ik]=bc[:,isp,:,ibot:itop,ik]
|
|
del bc
|
|
bc = tmp
|
|
del tmp
|
|
|
|
things_to_save = ['maxlm', 'bc']
|
|
if not (self.bc_subgrp in ar):
|
|
ar.create_group(self.bc_subgrp)
|
|
for it in things_to_save:
|
|
ar[self.bc_subgrp][it] = locals()[it]
|
|
del ar
|
|
mpi.report('Converted the band character data')
|
|
|