@ -19,457 +19,435 @@
# SOFTWARE.
# SOFTWARE.
import os
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
import warnings
from sys import getsizeof
from sys import getsizeof
from timeit import default_timer as timer
import numpy as np
import sisl
import sisl
from mpi4py import MPI
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 "
magnetic_entities = [
dict ( atom = 3 , l = 2 ) ,
dict ( atom = 4 , l = 2 ) ,
dict ( atom = 5 , l = 2 ) ,
]
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 ] ) ) ,
dict ( ai = 0 , aj = 2 , Ruc = np . array ( [ - 1 , - 1 , 0 ] ) ) ,
dict ( ai = 1 , aj = 2 , Ruc = np . array ( [ - 1 , - 1 , 0 ] ) ) ,
dict ( ai = 0 , aj = 2 , Ruc = np . array ( [ - 1 , 0 , 0 ] ) ) ,
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 :
try :
print ( " sisl version: " , sisl . __version__ )
except :
print ( " sisl version unknown. " )
try :
print ( " numpy version: " , np . __version__ )
except :
print ( " numpy version unknown. " )
# 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 :
try :
eigfile = simulation_parameters [ " infile " ] [ : - 3 ] + " EIG "
simulation_parameters [ " ebot " ] = read_siesta_emin ( eigfile ) - 0.1
simulation_parameters [ " automatic_ebot " ] = True
except :
print ( " Could not determine ebot. " )
print ( " Parameter was not given and .EIG file was not found. " )
# read sile
fdf = sisl . get_sile ( simulation_parameters [ " infile " ] )
# read in hamiltonian
dh = fdf . read_hamiltonian ( )
# 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 ] )
if rank == root_node :
print ( " \n \n \n \n \n " )
print (
" #################################################################### JOB INFORMATION ########################################################################### "
)
print_job_description ( simulation_parameters )
print (
" ################################################################################################################################################################ "
)
print ( " \n \n \n \n \n " )
times [ " setup_time " ] = timer ( )
print ( f " Setup done. Elapsed time: { times [ ' setup_time ' ] } s " )
print (
" ================================================================================================================================================================ "
)
def main ( ) :
# reformat Hamltonian and Overlap matrix for manipulations
# constrain numpy in parallel run
hh , ss , NO = build_hh_ss ( dh )
os . environ [ " OMP_NUM_THREADS " ] = " 1 " # export OMP_NUM_THREADS=1
os . environ [ " OPENBLAS_NUM_THREADS " ] = " 1 " # export OPENBLAS_NUM_THREADS=1
# symmetrizing Hamiltonian and Overlap matrix to make them hermitian
os . environ [ " MKL_NUM_THREADS " ] = " 1 " # export MKL_NUM_THREADS=1
for i in range ( dh . lattice . sc_off . shape [ 0 ] ) :
os . environ [ " VECLIB_MAXIMUM_THREADS " ] = " 1 " # export VECLIB_MAXIMUM_THREADS=1
j = dh . lattice . sc_index ( - dh . lattice . sc_off [ i ] )
os . environ [ " NUMEXPR_NUM_THREADS " ] = " 1 " # export NUMEXPR_NUM_THREADS=1
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
# 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
# runtime information
max_xcfs = abs ( np . array ( np . array ( [ f [ " c " ] / 2 for f in traced ] ) ) ) . max ( )
times = dict ( )
if max_xcfs > 1e-12 :
times [ " start_time " ] = timer ( )
warnings . warn (
f " Exchange field has non negligible scalar part. Largest value is { max_xcfs } "
)
if rank == root_node :
# input output stuff
times [ " H_and_XCF_time " ] = timer ( )
######################################################################
print (
######################################################################
f " Hamiltonian and exchange field rotated. Elapsed time: { times [ ' H_and_XCF_time ' ] } s "
######################################################################
)
print (
" ================================================================================================================================================================ "
)
# initialize pairs and magnetic entities based on input information
infile = " /Users/danielpozsar/Downloads/nojij/Fe3GeTe2/monolayer/soc/lat3_791/Fe3GeTe2.fdf "
pairs , magnetic_entities = setup_pairs_and_magnetic_entities (
outfile = " ./Fe3GeTe2_notebook "
magnetic_entities , pairs , dh , simulation_parameters
)
if rank == root_node :
magnetic_entities = [
times [ " site_and_pair_dictionaries_time " ] = timer ( )
dict ( atom = 3 , l = 2 ) ,
print (
dict ( atom = 4 , l = 2 ) ,
f " Site and pair dictionaries created. Elapsed time: { times [ ' site_and_pair_dictionaries_time ' ] } s "
dict ( atom = 5 , l = 2 ) ,
)
]
print (
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 ] ) ) ,
dict ( ai = 0 , aj = 2 , Ruc = np . array ( [ - 1 , - 1 , 0 ] ) ) ,
dict ( ai = 1 , aj = 2 , Ruc = np . array ( [ - 1 , - 1 , 0 ] ) ) ,
dict ( ai = 0 , aj = 2 , Ruc = np . array ( [ - 1 , 0 , 0 ] ) ) ,
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
######################################################################
######################################################################
######################################################################
# 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 :
print ( " sisl version unknown. " )
try :
print ( " numpy version: " , np . __version__ )
except :
print ( " numpy version unknown. " )
# 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 :
try :
eigfile = simulation_parameters [ " infile " ] [ : - 3 ] + " EIG "
simulation_parameters [ " ebot " ] = read_siesta_emin ( eigfile ) - 0.1
simulation_parameters [ " automatic_ebot " ] = True
except :
print ( " Could not determine ebot. " )
print ( " Parameter was not given and .EIG file was not found. " )
else :
simulation_parameters [ " automatic_ebot " ] = False
# generate k space sampling
# read sile
kset = make_kset (
fdf = sisl . get_sile ( simulation_parameters [ " infile " ] )
dirs = simulation_parameters [ " kdirs " ] , NUMK = simulation_parameters [ " kset " ]
)
# generate weights for k points
# read in hamiltonian
wkset = np . ones ( len ( kset ) ) / len ( kset )
dh = fdf . read_hamiltonian ( )
# split the k points based on MPI size
# read unit cell vectors
kpcs = np . array_split ( kset , size )
simulation_parameters [ " cell " ] = fdf . read_geometry ( ) . cell
# use progress bar if available
# unit cell index
if rank == root_node and tqdm_imported :
uc_in_sc_idx = dh . lattice . sc_index ( [ 0 , 0 , 0 ] )
kpcs [ root_node ] = tqdm ( kpcs [ root_node ] , desc = " k loop " )
if rank == root_node :
if rank == root_node :
times [ " k_set_time " ] = timer ( )
print ( " \n \n \n \n \n " )
print ( f " k set created. Elapsed time: { times [ ' k_set_time ' ] } s " )
print (
print (
" #################################################################### JOB INFORMATION ########################################################################### "
" ================================================================================================================================================================ "
)
)
print_job_description ( simulation_parameters )
print (
" ################################################################################################################################################################ "
)
print ( " \n \n \n \n \n " )
# this will contain the three Hamiltonian in the
times [ " setup_time " ] = timer ( )
# reference directions needed to calculate the energy
print ( f " Setup done. Elapsed time: { times [ ' setup_time ' ] } s " )
# variations upon rotation
print (
hamiltonians = [ ]
" ================================================================================================================================================================ "
)
# 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 )
rot_H_XCF = sum (
[ np . kron ( rot_XCF [ i ] , tau ) for i , tau in enumerate ( [ tau_x , tau_y , tau_z ] ) ]
)
rot_H_XCF_uc = rot_H_XCF [ uc_in_sc_idx ]
# obtain total Hamiltonian with the rotated exchange field
NO = dh . no # shorthand for number of orbitals in the unit cell
rot_H = hTRS + rot_H_XCF # equation 76
# 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 ] ) :
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
# 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 ] ) ,
]
)
# store the relevant information of the Hamiltonian
# check if exchange field has scalar part
hamiltonians . append ( dict ( orient = orient [ " o " ] , H = rot_H ) )
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 simulation_parameters [ " calculate_charge " ] :
if rank == root_node :
hamiltonians [ - 1 ] [ " GS " ] = np . zeros (
times[ " H_and_XCF_time " ] = timer ( )
( simulation_parameters [ " eset " ] , rot_H . shape [ 1 ] , rot_H . shape [ 2 ] ) ,
print (
dtype = " complex128 " ,
f " Hamiltonian and exchange field rotated. Elapsed time: { times [ ' H_and_XCF_time ' ] } s "
)
)
hamiltonians [ - 1 ] [ " GS_tmp " ] = np . zeros (
print (
( simulation_parameters [ " eset " ] , rot_H . shape [ 1 ] , rot_H . shape [ 2 ] ) ,
" ================================================================================================================================================================ "
dtype = " complex128 " ,
)
)
# these are the rotations (for now) perpendicular to the quantization axis
# initialize pairs and magnetic entities based on input information
for u in orient [ " vw " ] :
pairs , magnetic_entities = setup_pairs_and_magnetic_entities (
# section 2.H
magnetic_entities , pairs , dh , simulation_parameters
Tu = np . kron ( np . eye ( NO , dtype = int ) , tau_u ( u ) )
Vu1 , Vu2 = calc_Vu ( rot_H_XCF_uc , Tu )
for mag_ent in magnetic_entities :
idx = mag_ent [ " spin_box_indices " ]
# fill up the perturbed potentials (for now) based on the on-site projections
mag_ent [ " Vu1 " ] [ i ] . append ( onsite_projection ( Vu1 , idx , idx ) )
mag_ent [ " Vu2 " ] [ i ] . append ( onsite_projection ( Vu2 , idx , idx ) )
if rank == root_node :
times [ " reference_rotations_time " ] = timer ( )
print (
f " Rotations done perpendicular to quantization axis. Elapsed time: { times [ ' reference_rotations_time ' ] } s "
)
print (
" ================================================================================================================================================================ "
)
)
# provide helpful information to estimate the runtime and memory
if rank == root_node :
# requirements of the Greens function calculations
times [ " site_and_pair_dictionaries_time " ] = timer ( )
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 " Total number of directions: { len ( hamiltonians ) } " )
print (
print (
f " Total number of matrix inversions: { kset . shape [ 0 ] * len ( hamiltonians ) * simulation_parameters [ ' eset ' ] } "
f " Site and pair dictionaries created. Elapsed time: { times [ ' site_and_pair_dictionaries_time ' ] } s "
)
)
print (
print (
f " The shape of the Hamiltonian and the Greens function is { NO } x { NO } = { NO * NO } "
" ================================================================================================================================================================ "
)
# 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 )
# 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 :
kpcs [ root_node ] = tqdm ( kpcs [ root_node ] , desc = " k loop " )
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 = [ ]
# 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 )
rot_H_XCF = sum (
[ np . kron ( rot_XCF [ i ] , tau ) for i , tau in enumerate ( [ tau_x , tau_y , tau_z ] ) ]
)
)
# https://stackoverflow.com/questions/70746660/how-to-predict-memory-requirement-for-np-linalg-inv
rot_H_XCF_uc = rot_H_XCF [ uc_in_sc_idx ]
# memory is O(64 n**2) for complex matrices
memory_size = getsizeof ( hamiltonians [ 0 ] [ " H " ] . base ) / 1024
# obtain total Hamiltonian with the rotated exchange field
rot_H = hTRS + rot_H_XCF # equation 76
# store the relevant information of the Hamiltonian
hamiltonians . append ( dict ( orient = orient [ " o " ] , H = rot_H ) )
# these are the rotations (for now) perpendicular to the quantization axis
for u in orient [ " vw " ] :
# section 2.H
Tu = np . kron ( np . eye ( NO , dtype = int ) , tau_u ( u ) )
Vu1 , Vu2 = calc_Vu ( rot_H_XCF_uc , Tu )
for mag_ent in magnetic_entities :
idx = mag_ent [ " spin_box_indices " ]
# fill up the perturbed potentials (for now) based on the on-site projections
mag_ent [ " Vu1 " ] [ i ] . append ( onsite_projection ( Vu1 , idx , idx ) )
mag_ent [ " Vu2 " ] [ i ] . append ( onsite_projection ( Vu2 , idx , idx ) )
if rank == root_node :
times [ " reference_rotations_time " ] = timer ( )
print (
print (
f " Memory taken by a single Hamiltonian is: { getsizeof ( hamiltonians [ 0 ] [ ' H ' ] . base ) / 1024 } KB "
f " Rotations done perpendicular to quantization axis. Elapsed time: { times [ ' reference_rotations_time ' ] } s "
)
)
print ( f " Expected memory usage per matrix inversion: { memory_size * 32 } KB " )
print (
print (
f " Expected memory usage per k point for parallel inversion: { memory_size * len ( hamiltonians ) * simulation_parameters [ ' eset ' ] * 32 } KB "
" ================================================================================================================================================================ "
)
)
# 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 " Total number of directions: { len ( hamiltonians ) } " )
print (
f " Total number of matrix inversions: { kset . shape [ 0 ] * len ( hamiltonians ) * simulation_parameters [ ' eset ' ] } "
)
print (
f " The shape of the Hamiltonian and the Greens function is { NO } x { NO } = { NO * NO } "
)
# https://stackoverflow.com/questions/70746660/how-to-predict-memory-requirement-for-np-linalg-inv
# memory is O(64 n**2) for complex matrices
memory_size = getsizeof ( hamiltonians [ 0 ] [ " H " ] . base ) / 1024
print (
f " Memory taken by a single Hamiltonian is: { getsizeof ( hamiltonians [ 0 ] [ ' H ' ] . base ) / 1024 } KB "
)
print ( f " Expected memory usage per matrix inversion: { memory_size * 32 } KB " )
print (
f " Expected memory usage per k point for parallel inversion: { memory_size * len ( hamiltonians ) * simulation_parameters [ ' eset ' ] * 32 } KB "
)
print (
f " Expected memory usage on root node: { len ( np . array_split ( kset , size ) [ 0 ] ) * memory_size * len ( hamiltonians ) * simulation_parameters [ ' eset ' ] * 32 / 1024 } MB "
)
print (
print (
f " Expected memory usage on root node: { len ( np . array_split ( kset , size ) [ 0 ] ) * memory_size * len ( hamiltonians ) * simulation_parameters [ ' eset ' ] * 32 / 1024 } MB "
" ================================================================================================================================================================ "
)
)
print (
" ================================================================================================================================================================ "
)
# MPI barrier
# MPI barrier
comm . Barrier ( )
comm . Barrier ( )
# make energy contour
cont = make_contour (
emin = simulation_parameters [ " ebot " ] ,
enum = simulation_parameters [ " eset " ] ,
p = simulation_parameters [ " esetp " ] ,
)
eran = cont . ze
# sampling the integrand on the contour and the BZ
for k in kpcs [ rank ] :
# weight of k point in BZ integral
wk = wkset [ rank ]
# iterate over reference directions
for i , hamiltonian_orientation in enumerate ( hamiltonians ) :
# calculate Hamiltonian and Overlap matrix in a given k point
H = hamiltonian_orientation [ " H " ]
HK , SK = hsk ( H , ss , dh . sc_off , k )
if simulation_parameters [ " parallel_solver_for_Gk " ] :
Gk = parallel_Gk ( HK , SK , eran , simulation_parameters [ " eset " ] )
else :
# 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
# make energy contour
if simulation_parameters [ " calculate_charge " ] :
cont = make_contour (
hamiltonian_orientation [ " GS_tmp " ] + = Gk @ SK * wk
emin = simulation_parameters [ " ebot " ] ,
enum = simulation_parameters [ " eset " ] ,
p = simulation_parameters [ " esetp " ] ,
)
eran = cont . ze
# store the Greens function slice of the magnetic entities
# sampling the integrand on the contour and the BZ
for mag_ent in magnetic_entities :
for k in kpcs [ rank ] :
idx = mag_ent [ " spin_box_indices " ]
# weight of k point in BZ integral
mag_ent [ " Gii_tmp " ] [ i ] + = onsite_projection ( Gk , idx , idx ) * wk
wk = wkset [ rank ]
for pair in pairs :
# iterate over reference directions
# add phase shift based on the cell difference
for i , hamiltonian_orientation in enumerate ( hamiltonians ) :
phase = np . exp ( 1 j * 2 * np . pi * k @ pair [ " Ruc " ] . T )
# calculate Hamiltonian and Overlap matrix in a given k point
H = hamiltonian_orientation [ " H " ]
HK , SK = hsk ( H , ss , dh . sc_off , k )
# get the pair orbital sizes from the magnetic entities
if simulation_parameters [ " parallel_solver_for_Gk " ] :
ai = magnetic_entities [ pair [ " ai " ] ] [ " spin_box_indices " ]
Gk = parallel_Gk ( HK , SK , eran , simulation_parameters [ " eset " ] )
aj = magnetic_entities [ pair [ " aj " ] ] [ " spin_box_indices " ]
else :
# solve Greens function sequentially for the energies, because of memory bound
Gk = sequential_GK ( HK , SK , eran , simulation_parameters [ " eset " ] )
# store the Greens function slice of the magnetic entities
# store the Greens function slice of the magnetic entities
pair [ " Gij_tmp " ] [ i ] + = onsite_projection ( Gk , ai , aj ) * phase * wk
for mag_ent in magnetic_entities :
pair [ " Gji_tmp " ] [ i ] + = onsite_projection ( Gk , aj , ai ) / phase * wk
idx = mag_ent [ " spin_box_indices " ]
mag_ent [ " Gii_tmp " ] [ i ] + = onsite_projection ( Gk , idx , idx ) * wk
# summ reduce partial results of mpi nodes
for i in range ( len ( hamiltonians ) ) :
for pair in pairs :
# for total charge calculation
# add phase shift based on the cell difference
if simulation_parameters [ " calculate_charge " ] :
phase = np . exp ( 1 j * 2 * np . pi * k @ pair [ " Ruc " ] . T )
comm . Reduce ( hamiltonians [ i ] [ " GS_tmp " ] , hamiltonians [ i ] [ " GS " ] , root = root_node )
# get the pair orbital sizes from the magnetic entities
for mag_ent in magnetic_entities :
ai = magnetic_entities [ pair [ " ai " ] ] [ " spin_box_indices " ]
comm . Reduce ( mag_ent [ " Gii_tmp " ] [ i ] , mag_ent [ " Gii " ] [ i ] , root = root_node )
aj = magnetic_entities [ pair [ " aj " ] ] [ " spin_box_indices " ]
for pair in pairs :
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 :
times [ " green_function_inversion_time " ] = timer ( )
print (
f " Calculated Greens functions. Elapsed time: { times [ ' green_function_inversion_time ' ] } s "
)
print (
" ================================================================================================================================================================ "
)
# store the Greens function slice of the magnetic entities
pair [ " Gij_tmp " ] [ i ] + = onsite_projection ( Gk , ai , aj ) * phase * wk
pair [ " Gji_tmp " ] [ i ] + = onsite_projection ( Gk , aj , ai ) / phase * wk
if rank == root_node :
# summ reduce partial results of mpi nodes
# Calculate total charge
for i in range ( len ( hamiltonians ) ) :
if simulation_parameters [ " calculate_charge " ] :
for mag_ent in magnetic_entities :
for hamiltonian in hamiltonians :
comm . Reduce ( mag_ent [ " Gii_tmp " ] [ i ] , mag_ent [ " Gii " ] [ i ] , root = root_node )
GS = hamiltonian [ " GS " ]
traced = np . trace ( ( GS ) , axis1 = 1 , axis2 = 2 )
for pair in pairs :
simulation_parameters [ " charges " ] . append ( int_de_ke ( traced , cont . we ) )
comm . Reduce ( pair [ " Gij_tmp " ] [ i ] , pair [ " Gij " ] [ i ] , root = root_node )
comm . Reduce ( pair [ " Gji_tmp " ] [ i ] , pair [ " Gji " ] [ i ] , root = root_node )
# iterate over the magnetic entities
for tracker , mag_ent in enumerate ( magnetic_entities ) :
if rank == root_node :
# iterate over the quantization axes
times [ " green_function_inversion_time " ] = timer ( )
for i , Gii in enumerate ( mag_ent [ " Gii " ] ) :
print (
storage = [ ]
f " Calculated Greens functions. Elapsed time: { times [ ' green_function_inversion_time ' ] } s "
# iterate over the first and second order local perturbations
)
for Vu1 , Vu2 in zip ( mag_ent [ " Vu1 " ] [ i ] , mag_ent [ " Vu2 " ] [ i ] ) :
print (
# The Szunyogh-Lichtenstein formula
" ================================================================================================================================================================ "
traced = np . trace (
( Vu2 @ Gii + 0.5 * Gii @ Vu1 @ Gii ) , axis1 = 1 , axis2 = 2
) # this is the on site projection
# evaluation of the contour integral
storage . append ( int_de_ke ( traced , cont . we ) )
# fill up the magnetic entities dictionary with the energies
magnetic_entities [ tracker ] [ " energies " ] . append ( storage )
# convert to np array
magnetic_entities [ tracker ] [ " energies " ] = np . array (
magnetic_entities [ tracker ] [ " energies " ]
)
)
# iterate over the pairs
if rank == root_node :
for tracker , pair in enumerate ( pairs ) :
# iterate over the magnetic entities
# iterate over the quantization axes
for tracker , mag_ent in enumerate ( magnetic_entities ) :
for i , ( Gij , Gji ) in enumerate ( zip ( pair [ " Gij " ] , pair [ " Gji " ] ) ) :
# iterate over the quantization axes
site_i = magnetic_entities [ pair [ " ai " ] ]
for i , Gii in enumerate ( mag_ent [ " Gii " ] ) :
site_j = magnetic_entities [ pair [ " aj " ] ]
storage = [ ]
storage = [ ]
# iterate over the first and second order local perturbations
# iterate over the first order local perturbations in all possible orientations for the two sites
for Vu1 , Vu2 in zip ( mag_ent [ " Vu1 " ] [ i ] , mag_ent [ " Vu2 " ] [ i ] ) :
for Vui in site_i [ " Vu1 " ] [ i ] :
for Vuj in site_j [ " Vu1 " ] [ i ] :
# The Szunyogh-Lichtenstein formula
# The Szunyogh-Lichtenstein formula
traced = np . trace (
traced = np . trace (
( Vu i @ Gij @ Vuj @ Gj i) , axis1 = 1 , axis2 = 2
( Vu 2 @ Gii + 0.5 * Gii @ Vu1 @ Gi i) , axis1 = 1 , axis2 = 2
) # this is the on site projection
) # this is the on site projection
# evaluation of the contour integral
# evaluation of the contour integral
storage . append ( int_de_ke ( traced , cont . we ) )
storage . append ( int_de_ke ( traced , cont . we ) )
# fill up the pairs dictionary with the energies
# fill up the magnetic entities dictionary with the energies
pairs [ tracker ] [ " energies " ] . append ( storage )
magnetic_entities [ tracker ] [ " energies " ] . append ( storage )
# convert to np array
# convert to np array
pairs [ tracker ] [ " energies " ] = np . array ( pairs [ tracker ] [ " energies " ] )
magnetic_entities [ tracker ] [ " energies " ] = np . array (
magnetic_entities [ tracker ] [ " energies " ]
# calculate magnetic parameters
)
for mag_ent in magnetic_entities :
Kxx , Kyy , Kzz , consistency = calculate_anisotropy_tensor ( mag_ent )
# iterate over the pairs
mag_ent [ " K " ] = np . array ( [ Kxx , Kyy , Kzz ] ) * sisl . unit_convert ( " eV " , " meV " )
for tracker , pair in enumerate ( pairs ) :
mag_ent [ " K_consistency " ] = consistency
# iterate over the quantization axes
for i , ( Gij , Gji ) in enumerate ( zip ( pair [ " Gij " ] , pair [ " Gji " ] ) ) :
for pair in pairs :
site_i = magnetic_entities [ pair [ " ai " ] ]
J_iso , J_S , D , J = calculate_exchange_tensor ( pair )
site_j = magnetic_entities [ pair [ " aj " ] ]
pair [ " J_iso " ] = J_iso * sisl . unit_convert ( " eV " , " meV " )
storage = [ ]
pair [ " J_S " ] = J_S * sisl . unit_convert ( " eV " , " meV " )
# iterate over the first order local perturbations in all possible orientations for the two sites
pair [ " D " ] = D * sisl . unit_convert ( " eV " , " meV " )
for Vui in site_i [ " Vu1 " ] [ i ] :
pair [ " J " ] = J * sisl . unit_convert ( " eV " , " meV " )
for Vuj in site_j [ " Vu1 " ] [ i ] :
# The Szunyogh-Lichtenstein formula
times [ " end_time " ] = timer ( )
traced = np . trace (
print ( " \n \n \n \n \n " )
( Vui @ Gij @ Vuj @ Gji ) , axis1 = 1 , axis2 = 2
print (
) # this is the on site projection
" ##################################################################### GROGU OUTPUT ############################################################################# "
# evaluation of the contour integral
)
storage . append ( int_de_ke ( traced , cont . we ) )
# fill up the pairs dictionary with the energies
pairs [ tracker ] [ " energies " ] . append ( storage )
# convert to np array
pairs [ tracker ] [ " energies " ] = np . array ( pairs [ tracker ] [ " energies " ] )
# calculate magnetic parameters
for mag_ent in magnetic_entities :
Kxx , Kyy , Kzz , consistency = calculate_anisotropy_tensor ( mag_ent )
mag_ent [ " K " ] = np . array ( [ Kxx , Kyy , Kzz ] ) * sisl . unit_convert ( " eV " , " meV " )
mag_ent [ " K_consistency " ] = consistency
print_parameters ( simulation_parameters )
for pair in pairs :
print_atoms_and_pairs ( magnetic_entities , pairs )
J_iso , J_S , D , J = calculate_exchange_tensor ( pair )
print (
pair [ " J_iso " ] = J_iso * sisl . unit_convert ( " eV " , " meV " )
" ################################################################################################################################################################ "
pair [ " J_S " ] = J_S * sisl . unit_convert ( " eV " , " meV " )
)
pair [ " D " ] = D * sisl . unit_convert ( " eV " , " meV " )
print_runtime_information ( times )
pair [ " J " ] = J * sisl . unit_convert ( " eV " , " meV " )
print ( " " )
times [ " end_time " ] = timer ( )
# remove unwanted stuff before saving
print ( " \n \n \n \n \n " )
pairs , magnetic_entities = remove_clutter_for_save ( pairs , magnetic_entities )
print (
# create output dictionary with all the relevant data
" ##################################################################### GROGU OUTPUT ############################################################################# "
results = dict (
)
parameters = simulation_parameters ,
magnetic_entities = magnetic_entities ,
print_parameters ( simulation_parameters )
pairs = pairs ,
print_atoms_and_pairs ( magnetic_entities , pairs )
runtime = times ,
print (
)
" ################################################################################################################################################################ "
)
print_runtime_information ( times )
print ( " " )
# remove unwanted stuff before saving
pairs , magnetic_entities = remove_clutter_for_save ( pairs , magnetic_entities )
# create output dictionary with all the relevant data
results = dict (
parameters = simulation_parameters ,
magnetic_entities = magnetic_entities ,
pairs = pairs ,
runtime = times ,
)
# save results
save_pickle ( simulation_parameters [ " outfile " ] , results )
print ( " \n \n \n \n \n " )
# save results
save_pickle ( simulation_parameters [ " outfile " ] , results )
print ( " \n \n \n \n \n " )
if __name__ == " __main__ " :
main ( )