@ -19,45 +19,44 @@
# SOFTWARE.
import os
os . environ [ " OMP_NUM_THREADS " ] = " 1 " # export OMP_NUM_THREADS=1
os . environ [ " OPENBLAS_NUM_THREADS " ] = " 1 " # export OPENBLAS_NUM_THREADS=1
os . environ [ " MKL_NUM_THREADS " ] = " 1 " # export MKL_NUM_THREADS=1
os . environ [ " VECLIB_MAXIMUM_THREADS " ] = " 1 " # export VECLIB_MAXIMUM_THREADS=1
os . environ [ " NUMEXPR_NUM_THREADS " ] = " 1 " # export NUMEXPR_NUM_THREADS=1
from timeit import default_timer as timer
# runtime information
times = dict ( )
times [ " start_time " ] = timer ( )
import warnings
from sys import getsizeof
from timeit import default_timer as timer
import numpy as np
import sisl
from mpi4py import MPI
from src. grogupy import *
from grogupy import *
# input output stuff
######################################################################
######################################################################
######################################################################
infile = (
" /Users/danielpozsar/Downloads/nojij/Fe3GeTe2/monolayer/soc/lat3_791/Fe3GeTe2.fdf "
)
outfile = " ./Fe3GeTe2_notebook "
def main ( ) :
magnetic_entities = [
# constrain numpy in parallel run
os . environ [ " OMP_NUM_THREADS " ] = " 1 " # export OMP_NUM_THREADS=1
os . environ [ " OPENBLAS_NUM_THREADS " ] = " 1 " # export OPENBLAS_NUM_THREADS=1
os . environ [ " MKL_NUM_THREADS " ] = " 1 " # export MKL_NUM_THREADS=1
os . environ [ " VECLIB_MAXIMUM_THREADS " ] = " 1 " # export VECLIB_MAXIMUM_THREADS=1
os . environ [ " NUMEXPR_NUM_THREADS " ] = " 1 " # export NUMEXPR_NUM_THREADS=1
# runtime information
times = dict ( )
times [ " start_time " ] = timer ( )
# input output stuff
######################################################################
######################################################################
######################################################################
infile = " /Users/danielpozsar/Downloads/nojij/Fe3GeTe2/monolayer/soc/lat3_791/Fe3GeTe2.fdf "
outfile = " ./Fe3GeTe2_notebook "
magnetic_entities = [
dict ( atom = 3 , l = 2 ) ,
dict ( atom = 4 , l = 2 ) ,
dict ( atom = 5 , l = 2 ) ,
]
pairs = [
]
pairs = [
dict ( ai = 0 , aj = 1 , Ruc = np . array ( [ 0 , 0 , 0 ] ) ) ,
dict ( ai = 0 , aj = 2 , Ruc = np . array ( [ 0 , 0 , 0 ] ) ) ,
dict ( ai = 1 , aj = 2 , Ruc = np . array ( [ 0 , 0 , 0 ] ) ) ,
@ -67,34 +66,30 @@ pairs = [
dict ( ai = 1 , aj = 2 , Ruc = np . array ( [ - 1 , 0 , 0 ] ) ) ,
dict ( ai = 1 , aj = 2 , Ruc = np . array ( [ - 2 , 0 , 0 ] ) ) ,
dict ( ai = 1 , aj = 2 , Ruc = np . array ( [ - 3 , 0 , 0 ] ) ) ,
]
simulation_parameters = default_args
simulation_parameters [ " infile " ] = infile
simulation_parameters [ " outfile " ] = outfile
simulation_parameters [ " kset " ] = 20
simulation_parameters [ " kdirs " ] = " xy "
simulation_parameters [ " eset " ] = 600
simulation_parameters [ " esetp " ] = 10000
fdf = sisl . io . fdfSileSiesta ( " input.fdf " )
fdf . get ( " XCF_Rotation " )
######################################################################
######################################################################
######################################################################
# MPI parameters
comm = MPI . COMM_WORLD
size = comm . Get_size ( )
rank = comm . Get_rank ( )
root_node = 0
# include parallel size in simulation parameters
simulation_parameters [ " parallel_size " ] = size
# check versions for debugging
if rank == root_node :
]
simulation_parameters = default_args
simulation_parameters [ " infile " ] = infile
simulation_parameters [ " outfile " ] = outfile
simulation_parameters [ " kset " ] = 20
simulation_parameters [ " kdirs " ] = " xy "
simulation_parameters [ " eset " ] = 600
simulation_parameters [ " esetp " ] = 10000
######################################################################
######################################################################
######################################################################
# MPI parameters
comm = MPI . COMM_WORLD
size = comm . Get_size ( )
rank = comm . Get_rank ( )
root_node = 0
if rank == root_node :
# include parallel size in simulation parameters
simulation_parameters [ " parallel_size " ] = size
# check versions for debugging
try :
print ( " sisl version: " , sisl . __version__ )
except :
@ -104,12 +99,12 @@ if rank == root_node:
except :
print ( " numpy version unknown. " )
# rename outfile
if not simulation_parameters [ " outfile " ] . endswith ( " .pickle " ) :
# rename outfile
if not simulation_parameters [ " outfile " ] . endswith ( " .pickle " ) :
simulation_parameters [ " outfile " ] + = " .pickle "
# if ebot is not given put it 0.1 eV under the smallest energy
if simulation_parameters [ " ebot " ] is None :
# if ebot is not given put it 0.1 eV under the smallest energy
if simulation_parameters [ " ebot " ] is None :
try :
eigfile = simulation_parameters [ " infile " ] [ : - 3 ] + " EIG "
simulation_parameters [ " ebot " ] = read_siesta_emin ( eigfile ) - 0.1
@ -117,20 +112,22 @@ if simulation_parameters["ebot"] is None:
except :
print ( " Could not determine ebot. " )
print ( " Parameter was not given and .EIG file was not found. " )
else :
simulation_parameters [ " automatic_ebot " ] = False
# read sile
fdf = sisl . get_sile ( simulation_parameters [ " infile " ] )
# read sile
fdf = sisl . get_sile ( simulation_parameters [ " infile " ] )
# read in hamiltonian
dh = fdf . read_hamiltonian ( )
# read in hamiltonian
dh = fdf . read_hamiltonian ( )
# read unit cell vectors
simulation_parameters [ " cell " ] = fdf . read_geometry ( ) . cell
# read unit cell vectors
simulation_parameters [ " cell " ] = fdf . read_geometry ( ) . cell
# unit cell index
uc_in_sc_idx = dh . lattice . sc_index ( [ 0 , 0 , 0 ] )
# unit cell index
uc_in_sc_idx = dh . lattice . sc_index ( [ 0 , 0 , 0 ] )
if rank == root_node :
if rank == root_node :
print ( " \n \n \n \n \n " )
print (
" #################################################################### JOB INFORMATION ########################################################################### "
@ -147,42 +144,43 @@ if rank == root_node:
" ================================================================================================================================================================ "
)
NO = dh . no # shorthand for number of orbitals in the unit cell
# reformat Hamltonian and Overlap matrix for manipulations
hh , ss , NO = build_hh_ss ( dh )
# reformat Hamltonian and Overlap matrix for manipulations
hh , ss = build_hh_ss ( dh )
# symmetrizing Hamiltonian and Overlap matrix to make them hermitian
for i in range ( dh . lattice . sc_off . shape [ 0 ] ) :
# symmetrizing Hamiltonian and Overlap matrix to make them hermitian
for i in range ( dh . lattice . sc_off . shape [ 0 ] ) :
j = dh . lattice . sc_index ( - dh . lattice . sc_off [ i ] )
h1 , h1d = hh [ i ] , hh [ j ]
hh [ i ] , hh [ j ] = ( h1 + h1d . T . conj ( ) ) / 2 , ( h1d + h1 . T . conj ( ) ) / 2
s1 , s1d = ss [ i ] , ss [ j ]
ss [ i ] , ss [ j ] = ( s1 + s1d . T . conj ( ) ) / 2 , ( s1d + s1 . T . conj ( ) ) / 2
# identifying TRS and TRB parts of the Hamiltonian
TAUY = np . kron ( np . eye ( NO ) , tau_y )
hTR = np . array ( [ TAUY @ hh [ i ] . conj ( ) @ TAUY for i in range ( dh . lattice . nsc . prod ( ) ) ] )
hTRS = ( hh + hTR ) / 2
hTRB = ( hh - hTR ) / 2
# identifying TRS and TRB parts of the Hamiltonian
TAUY = np . kron ( np . eye ( NO ) , tau_y )
hTR = np . array ( [ TAUY @ hh [ i ] . conj ( ) @ TAUY for i in range ( dh . lattice . nsc . prod ( ) ) ] )
hTRS = ( hh + hTR ) / 2
hTRB = ( hh - hTR ) / 2
# extracting the exchange field
traced = [ spin_tracer ( hTRB [ i ] ) for i in range ( dh . lattice . nsc . prod ( ) ) ] # equation 77
XCF = np . array (
# extracting the exchange field
traced = [ spin_tracer ( hTRB [ i ] ) for i in range ( dh . lattice . nsc . prod ( ) ) ] # equation 77
XCF = np . array (
[
np . array ( [ f [ " x " ] / 2 for f in traced ] ) ,
np . array ( [ f [ " y " ] / 2 for f in traced ] ) ,
np . array ( [ f [ " z " ] / 2 for f in traced ] ) ,
]
)
)
# check if exchange field has scalar part
max_xcfs = abs ( np . array ( np . array ( [ f [ " c " ] / 2 for f in traced ] ) ) ) . max ( )
if max_xcfs > 1e-12 :
# check if exchange field has scalar part
max_xcfs = abs ( np . array ( np . array ( [ f [ " c " ] / 2 for f in traced ] ) ) ) . max ( )
if max_xcfs > 1e-12 :
warnings . warn (
f " Exchange field has non negligible scalar part. Largest value is { max_xcfs } "
)
if rank == root_node :
if rank == root_node :
times [ " H_and_XCF_time " ] = timer ( )
print (
f " Hamiltonian and exchange field rotated. Elapsed time: { times [ ' H_and_XCF_time ' ] } s "
@ -191,12 +189,12 @@ if rank == root_node:
" ================================================================================================================================================================ "
)
# initialize pairs and magnetic entities based on input information
pairs , magnetic_entities = setup_pairs_and_magnetic_entities (
# initialize pairs and magnetic entities based on input information
pairs , magnetic_entities = setup_pairs_and_magnetic_entities (
magnetic_entities , pairs , dh , simulation_parameters
)
)
if rank == root_node :
if rank == root_node :
times [ " site_and_pair_dictionaries_time " ] = timer ( )
print (
f " Site and pair dictionaries created. Elapsed time: { times [ ' site_and_pair_dictionaries_time ' ] } s "
@ -205,35 +203,35 @@ if rank == root_node:
" ================================================================================================================================================================ "
)
# generate k space sampling
kset = make_kset (
# generate k space sampling
kset = make_kset (
dirs = simulation_parameters [ " kdirs " ] , NUMK = simulation_parameters [ " kset " ]
)
)
# generate weights for k points
wkset = np . ones ( len ( kset ) ) / len ( kset )
# generate weights for k points
wkset = np . ones ( len ( kset ) ) / len ( kset )
# split the k points based on MPI size
kpcs = np . array_split ( kset , size )
# split the k points based on MPI size
kpcs = np . array_split ( kset , size )
# use progress bar if available
if rank == root_node and tqdm_imported :
# use progress bar if available
if rank == root_node and tqdm_imported :
kpcs [ root_node ] = tqdm ( kpcs [ root_node ] , desc = " k loop " )
if rank == root_node :
if rank == root_node :
times [ " k_set_time " ] = timer ( )
print ( f " k set created. Elapsed time: { times [ ' k_set_time ' ] } s " )
print (
" ================================================================================================================================================================ "
)
# this will contain the three Hamiltonian in the
# reference directions needed to calculate the energy
# variations upon rotation
hamiltonians = [ ]
# this will contain the three Hamiltonian in the
# reference directions needed to calculate the energy
# variations upon rotation
hamiltonians = [ ]
# iterate over the reference directions (quantization axes)
for i , orient in enumerate ( simulation_parameters [ " ref_xcf_orientations " ] ) :
# iterate over the reference directions (quantization axes)
for i , orient in enumerate ( simulation_parameters [ " ref_xcf_orientations " ] ) :
# obtain rotated exchange field and Hamiltonian
R = RotMa2b ( simulation_parameters [ " scf_xcf_orientation " ] , orient [ " o " ] )
rot_XCF = np . einsum ( " ij,jklm->iklm " , R , XCF )
@ -248,16 +246,6 @@ for i, orient in enumerate(simulation_parameters["ref_xcf_orientations"]):
# store the relevant information of the Hamiltonian
hamiltonians . append ( dict ( orient = orient [ " o " ] , H = rot_H ) )
if simulation_parameters [ " calculate_charge " ] :
hamiltonians [ - 1 ] [ " GS " ] = np . zeros (
( simulation_parameters [ " eset " ] , rot_H . shape [ 1 ] , rot_H . shape [ 2 ] ) ,
dtype = " complex128 " ,
)
hamiltonians [ - 1 ] [ " GS_tmp " ] = np . zeros (
( simulation_parameters [ " eset " ] , rot_H . shape [ 1 ] , rot_H . shape [ 2 ] ) ,
dtype = " complex128 " ,
)
# these are the rotations (for now) perpendicular to the quantization axis
for u in orient [ " vw " ] :
# section 2.H
@ -270,7 +258,7 @@ for i, orient in enumerate(simulation_parameters["ref_xcf_orientations"]):
mag_ent [ " Vu1 " ] [ i ] . append ( onsite_projection ( Vu1 , idx , idx ) )
mag_ent [ " Vu2 " ] [ i ] . append ( onsite_projection ( Vu2 , idx , idx ) )
if rank == root_node :
if rank == root_node :
times [ " reference_rotations_time " ] = timer ( )
print (
f " Rotations done perpendicular to quantization axis. Elapsed time: { times [ ' reference_rotations_time ' ] } s "
@ -279,14 +267,16 @@ if rank == root_node:
" ================================================================================================================================================================ "
)
# provide helpful information to estimate the runtime and memory
# requirements of the Greens function calculations
if rank == root_node :
# provide helpful information to estimate the runtime and memory
# requirements of the Greens function calculations
if rank == root_node :
print ( " Starting matrix inversions. " )
if simulation_parameters [ " padawan_mode " ] :
print ( " Padawan mode: " )
print ( f " Total number of k points: { kset . shape [ 0 ] } " )
print ( f " Number of energy samples per k point: { simulation_parameters [ ' eset ' ] } " )
print (
f " Number of energy samples per k point: { simulation_parameters [ ' eset ' ] } "
)
print ( f " Total number of directions: { len ( hamiltonians ) } " )
print (
f " Total number of matrix inversions: { kset . shape [ 0 ] * len ( hamiltonians ) * simulation_parameters [ ' eset ' ] } "
@ -311,19 +301,19 @@ if rank == root_node:
" ================================================================================================================================================================ "
)
# MPI barrier
comm . Barrier ( )
# MPI barrier
comm . Barrier ( )
# make energy contour
cont = make_contour (
# make energy contour
cont = make_contour (
emin = simulation_parameters [ " ebot " ] ,
enum = simulation_parameters [ " eset " ] ,
p = simulation_parameters [ " esetp " ] ,
)
eran = cont . ze
)
eran = cont . ze
# sampling the integrand on the contour and the BZ
for k in kpcs [ rank ] :
# sampling the integrand on the contour and the BZ
for k in kpcs [ rank ] :
# weight of k point in BZ integral
wk = wkset [ rank ]
@ -339,10 +329,6 @@ for k in kpcs[rank]:
# solve Greens function sequentially for the energies, because of memory bound
Gk = sequential_GK ( HK , SK , eran , simulation_parameters [ " eset " ] )
# saving this for total charge
if simulation_parameters [ " calculate_charge " ] :
hamiltonian_orientation [ " GS_tmp " ] + = Gk @ SK * wk
# store the Greens function slice of the magnetic entities
for mag_ent in magnetic_entities :
idx = mag_ent [ " spin_box_indices " ]
@ -360,12 +346,8 @@ for k in kpcs[rank]:
pair [ " Gij_tmp " ] [ i ] + = onsite_projection ( Gk , ai , aj ) * phase * wk
pair [ " Gji_tmp " ] [ i ] + = onsite_projection ( Gk , aj , ai ) / phase * wk
# summ reduce partial results of mpi nodes
for i in range ( len ( hamiltonians ) ) :
# for total charge calculation
if simulation_parameters [ " calculate_charge " ] :
comm . Reduce ( hamiltonians [ i ] [ " GS_tmp " ] , hamiltonians [ i ] [ " GS " ] , root = root_node )
# summ reduce partial results of mpi nodes
for i in range ( len ( hamiltonians ) ) :
for mag_ent in magnetic_entities :
comm . Reduce ( mag_ent [ " Gii_tmp " ] [ i ] , mag_ent [ " Gii " ] [ i ] , root = root_node )
@ -373,7 +355,7 @@ for i in range(len(hamiltonians)):
comm . Reduce ( pair [ " Gij_tmp " ] [ i ] , pair [ " Gij " ] [ i ] , root = root_node )
comm . Reduce ( pair [ " Gji_tmp " ] [ i ] , pair [ " Gji " ] [ i ] , root = root_node )
if rank == root_node :
if rank == root_node :
times [ " green_function_inversion_time " ] = timer ( )
print (
f " Calculated Greens functions. Elapsed time: { times [ ' green_function_inversion_time ' ] } s "
@ -382,15 +364,7 @@ if rank == root_node:
" ================================================================================================================================================================ "
)
if rank == root_node :
# Calculate total charge
if simulation_parameters [ " calculate_charge " ] :
for hamiltonian in hamiltonians :
GS = hamiltonian [ " GS " ]
traced = np . trace ( ( GS ) , axis1 = 1 , axis2 = 2 )
simulation_parameters [ " charges " ] . append ( int_de_ke ( traced , cont . we ) )
if rank == root_node :
# iterate over the magnetic entities
for tracker , mag_ent in enumerate ( magnetic_entities ) :
# iterate over the quantization axes
@ -473,3 +447,7 @@ if rank == root_node:
save_pickle ( simulation_parameters [ " outfile " ] , results )
print ( " \n \n \n \n \n " )
if __name__ == " __main__ " :
main ( )