WARNING: this may break things, a bunch of stuff changed

class-solution
Daniel Pozsar 2 months ago
parent 46f83ff07c
commit 8af7757c87

@ -1,16 +1,20 @@
# Relativistic magnetic interactions from non-orthogonal basis sets # Relativistic magnetic interactions from non-orthogonal basis sets
More on the theoretical background can be seen on [arXiv](https://arxiv.org/abs/2309.02558). More on the theoretical background can be seen on [arXiv](https://arxiv.org/abs/2309.02558).
# TODO ## TODO
## Testing
### Testing
- Test on lat3_791 - Test on lat3_791
- Test on varcell - Test on `varcell`
- Test on varcell_myrun - Test on `varcell_myrun`
- Test on varcell_myrun_2 - Test on `varcell_myrun_2`
- Test scaling - Test scaling
- Test rotations to x-y 30 and 60 - Test rotations to x-y 30 and 60
## Developing ### Developing
- Magnetic entities cannot handle orbitals, only shells - Magnetic entities cannot handle orbitals, only shells
- Use ReadThe Docs [addons](https://docs.readthedocs.io/en/stable/addons.html) - Use ReadThe Docs [addons](https://docs.readthedocs.io/en/stable/addons.html)
- Check the symmetrization of the Hamiltonian and overlap matrix to make them hermitian - Check the symmetrization of the Hamiltonian and overlap matrix to make them hermitian
@ -21,58 +25,70 @@ More on the theoretical background can be seen on [arXiv](https://arxiv.org/abs/
- fdf atom input - fdf atom input
- orbital indexing must be correct - orbital indexing must be correct
# Building wheel ## Building wheel
See detailed documentation on [PYPI](https://packaging.python.org/en/latest/tutorials/packaging-projects/). See detailed documentation on [PYPI](https://packaging.python.org/en/latest/tutorials/packaging-projects/).
- First you need some API Tokens for Test PYPI ,to be able to upload. You can read about it [here](https://test.pypi.org/help/#apitoken). I own the current project, so you have to contact me. - First you need some API Tokens for Test PYPI ,to be able to upload. You can read about it [here](https://test.pypi.org/help/#apitoken). I own the current project, so you have to contact me.
Use the following commands for a quick setup: Use the following commands for a quick setup:
- Build wheel - Build wheel
```
``` bash
python -m build python -m build
``` ```
- Push to PYPI test repository - Push to PYPI test repository
```
``` bash
python -m twine upload --repository testpypi dist/* python -m twine upload --repository testpypi dist/*
``` ```
# Usage ## Usage
## For end users
### For end users
Download and install from [PYPI](https://test.pypi.org/project/grogu-magn/) test repository. Be aware that this is not up to date yet!!! Download and install from [PYPI](https://test.pypi.org/project/grogu-magn/) test repository. Be aware that this is not up to date yet!!!
``` bash
python3 -m pip install --index-url https://test.pypi.org/simple/ grogupy
``` ```
python3 -m pip install --index-url https://test.pypi.org/simple/ grogu_magn
```
## For developers ### For developers
- Clone repository from Gitea - Clone repository from Gitea
```
``` bash
git clone https://gitea.vo.elte.hu/et209d/grogu.git git clone https://gitea.vo.elte.hu/et209d/grogu.git
``` ```
- Create a virtual environment (.venv) (for example with VsCode) - Create a virtual environment (.venv) (for example with VsCode)
* Use python 3.9.6 - Use python 3.9.6
* install dependencies from: - install dependencies from:
* requirements.txt - requirements.txt
* requirements-dev.txt - requirements-dev.txt
* /docs/requirements.txt - /docs/requirements.txt
- Install and run pre-commit - Install and run pre-commit
```
``` bash
pre-commit install pre-commit install
pre-commit run --all-files pre-commit run --all-files
``` ```
To build the documentation navigate to the `docs/source` folder. Then autogenerate the documentation and build. After this the html page can be found in `docs/source/_build/html`. Follow the commands below. To build the documentation navigate to the `docs/source` folder. Then autogenerate the documentation and build. After this the html page can be found in `docs/source/_build/html`. Follow the commands below.
```
``` bash
cd docs/source cd docs/source
sphinx-apidoc -o ./implementation/ ../../src/ sphinx-apidoc -o ./implementation/ ../../src/
make clean make clean
make html make html
``` ```
To build a pdf containing the documentation instead of make, first navigate to the `docs/source` folde, then use the rst2pdf extension.
``` To build a pdf containing the documentation instead of make, first navigate to the `docs/source` folder, then use the rst2pdf extension.
``` bash
cd docs/source cd docs/source
sphinx-apidoc -o ./implementation/ ../../src/ sphinx-apidoc -o ./implementation/ ../../src/
sphinx-build -b pdf . _build/pdf sphinx-build -b pdf . _build/pdf

@ -21,8 +21,8 @@
"""Docstring in init. """Docstring in init.
""" """
from grogupy.constants import *
from grogupy.core import * from grogupy.core import *
from grogupy.globals import *
from grogupy.io import * from grogupy.io import *
from grogupy.magnetism import * from grogupy.magnetism import *
from grogupy.utilities import * from grogupy.utilities import *

@ -18,17 +18,19 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from typing import Final
import numpy as np import numpy as np
# Pauli matrices # Pauli matrices
TAU_X = np.array([[0, 1], [1, 0]]) TAU_X: Final[np.array] = np.array([[0, 1], [1, 0]])
TAU_Y = np.array([[0, -1j], [1j, 0]]) TAU_Y: Final[np.array] = np.array([[0, -1j], [1j, 0]])
TAU_Z = np.array([[1, 0], [0, -1]]) TAU_Z: Final[np.array] = np.array([[1, 0], [0, -1]])
TAU_0 = np.array([[1, 0], [0, 1]]) TAU_0: Final[np.array] = np.array([[1, 0], [0, 1]])
# list of accepted input parameters # list of accepted input parameters
ACCEPTED_INPUTS = [ ACCEPTED_INPUTS: Final[list] = [
"infile", "infile",
"outfile", "outfile",
"scf_xcf_orientation", "scf_xcf_orientation",
@ -42,7 +44,7 @@ ACCEPTED_INPUTS = [
"padawan_mode", "padawan_mode",
] ]
DEFAULT_ARGUMENTS = dict( DEFAULT_ARGUMENTS: Final[dict] = dict(
infile=None, infile=None,
outfile=None, outfile=None,
scf_xcf_orientation=np.array([0, 0, 1]), scf_xcf_orientation=np.array([0, 0, 1]),

@ -23,12 +23,13 @@
import numpy as np import numpy as np
from numpy.linalg import inv from numpy.linalg import inv
from sisl.physics import Hamiltonian
from grogupy.magnetism import blow_up_orbindx, parse_magnetic_entity from grogupy.magnetism import blow_up_orbindx, parse_magnetic_entity
from grogupy.utilities import commutator from grogupy.utilities import commutator
def onsite_projection(matrix, idx1, idx2): def onsite_projection(matrix: np.array, idx1: np.array, idx2: np.array) -> np.array:
"""It produces the slices of a matrix for the on site projection. """It produces the slices of a matrix for the on site projection.
The slicing is along the last two axes as these contains the orbital indexing. The slicing is along the last two axes as these contains the orbital indexing.
@ -47,7 +48,7 @@ def onsite_projection(matrix, idx1, idx2):
return matrix[..., idx1, :][..., idx2] return matrix[..., idx1, :][..., idx2]
def calc_Vu(H, Tu): def calc_Vu(H: np.array, Tu: np.array) -> np.array:
"""Calculates the local perturbation in case of a spin rotation. """Calculates the local perturbation in case of a spin rotation.
Args: Args:
@ -69,7 +70,7 @@ def calc_Vu(H, Tu):
return Vu1, Vu2 return Vu1, Vu2
def build_hh_ss(dh): def build_hh_ss(dh: Hamiltonian) -> tuple[np.array, np.array]:
"""It builds the Hamiltonian and Overlap matrix from the sisl.dh class. """It builds the Hamiltonian and Overlap matrix from the sisl.dh class.
It restructures the data in the SPIN BOX representation, where NS is It restructures the data in the SPIN BOX representation, where NS is
@ -145,8 +146,8 @@ def build_hh_ss(dh):
def setup_pairs_and_magnetic_entities( def setup_pairs_and_magnetic_entities(
magnetic_entities, pairs, dh, simulation_parameters magnetic_entities: list, pairs: list, dh, simulation_parameters: dict
): ) -> tuple[list, list]:
"""It creates the complete structure of the dictionaries and fills some basic data. """It creates the complete structure of the dictionaries and fills some basic data.
It creates orbital indexes, spin box indexes, coordinates and tags for magnetic entities. It creates orbital indexes, spin box indexes, coordinates and tags for magnetic entities.
@ -297,7 +298,7 @@ def setup_pairs_and_magnetic_entities(
return pairs, magnetic_entities return pairs, magnetic_entities
def parallel_Gk(HK, SK, eran, eset): def parallel_Gk(HK: np.array, SK: np.array, eran: np.array, eset: int) -> np.array:
"""Calculates the Greens function by inversion. """Calculates the Greens function by inversion.
It calculates the Greens function on all the energy levels at the same time. It calculates the Greens function on all the energy levels at the same time.
@ -321,7 +322,7 @@ def parallel_Gk(HK, SK, eran, eset):
return inv(SK * eran.reshape(eset, 1, 1) - HK) return inv(SK * eran.reshape(eset, 1, 1) - HK)
def sequential_GK(HK, SK, eran, eset): def sequential_GK(HK: np.array, SK: np.array, eran: np.array, eset: int) -> np.array:
"""Calculates the Greens function by inversion. """Calculates the Greens function by inversion.
It calculates sequentially over the energy levels. It calculates sequentially over the energy levels.
@ -350,7 +351,7 @@ def sequential_GK(HK, SK, eran, eset):
return Gk return Gk
def remove_clutter_for_save(pairs, magnetic_entities): def remove_clutter_for_save(pairs: list, magnetic_entities: list) -> tuple[list, list]:
"""Removes unimportant data from the dictionaries. """Removes unimportant data from the dictionaries.
It is used before saving to throw away data that It is used before saving to throw away data that

@ -42,16 +42,16 @@ from mpi4py import MPI
try: try:
from tqdm import tqdm from tqdm import tqdm
tqdm_imported = True tqdm_imported: bool = True
except: except:
print("Please install tqdm for nice progress bar.") print("Please install tqdm for nice progress bar.")
tqdm_imported = False tqdm_imported: bool = False
from grogupy import * from grogupy import *
def parse_command_line(): def parse_command_line() -> dict:
"""This function can read input from the command line.""" """This function can read input from the command line."""
parser = ArgumentParser() parser = ArgumentParser()
@ -59,12 +59,19 @@ def parse_command_line():
parser.add_argument( parser.add_argument(
"-i", "-i",
"--input", "--input",
dest="infile", dest="grogupy_infile",
default=None, default=None,
type=str, type=str,
help="Input file name", help="Input file name for the Grogupy fdf file",
required=True, required=True,
) )
parser.add_argument(
"--siesta-input",
dest="infile",
default=None,
type=str,
help="Input file name for the Siesta fdf file",
)
parser.add_argument( parser.add_argument(
"-o", "-o",
"--output", "--output",
@ -129,16 +136,16 @@ def parse_command_line():
return cmd_line_args return cmd_line_args
def main(simulation_parameters, magnetic_entities, pairs): def main(simulation_parameters: dict, magnetic_entities: list, pairs: list) -> None:
# runtime information # runtime information
times = dict() times: dict = dict()
times["start_time"] = timer() times["start_time"] = timer()
# MPI parameters # MPI parameters
comm = MPI.COMM_WORLD comm = MPI.COMM_WORLD
size = comm.Get_size() size: int = comm.Get_size()
rank = comm.Get_rank() rank: int = comm.Get_rank()
root_node = 0 root_node: int = 0
if rank == root_node: if rank == root_node:
# include parallel size in simulation parameters # include parallel size in simulation parameters
@ -172,8 +179,8 @@ def main(simulation_parameters, magnetic_entities, pairs):
# add third direction for off-diagonal anisotropy # add third direction for off-diagonal anisotropy
for orientation in simulation_parameters["ref_xcf_orientations"]: for orientation in simulation_parameters["ref_xcf_orientations"]:
o1 = orientation["vw"][0] o1: np.array = orientation["vw"][0]
o2 = orientation["vw"][1] o2: np.array = orientation["vw"][1]
orientation["vw"].append((o1 + o2) / np.sqrt(2)) orientation["vw"].append((o1 + o2) / np.sqrt(2))
# read sile # read sile
@ -186,7 +193,7 @@ def main(simulation_parameters, magnetic_entities, pairs):
simulation_parameters["cell"] = fdf.read_geometry().cell simulation_parameters["cell"] = fdf.read_geometry().cell
# unit cell index # unit cell index
uc_in_sc_idx = dh.lattice.sc_index([0, 0, 0]) uc_in_sc_idx: int = dh.lattice.sc_index([0, 0, 0])
if rank == root_node: if rank == root_node:
print("\n\n\n\n\n") print("\n\n\n\n\n")
@ -205,9 +212,9 @@ def main(simulation_parameters, magnetic_entities, pairs):
"================================================================================================================================================================" "================================================================================================================================================================"
) )
NO = dh.no # shorthand for number of orbitals in the unit cell NO: int = dh.no # shorthand for number of orbitals in the unit cell
# reformat Hamltonian and Overlap matrix for manipulations # reformat Hamiltonian and Overlap matrix for manipulations
hh, ss = build_hh_ss(dh) hh, ss = build_hh_ss(dh)
# symmetrizing Hamiltonian and Overlap matrix to make them hermitian # symmetrizing Hamiltonian and Overlap matrix to make them hermitian
@ -219,14 +226,18 @@ def main(simulation_parameters, magnetic_entities, pairs):
ss[i], ss[j] = (s1 + s1d.T.conj()) / 2, (s1d + s1.T.conj()) / 2 ss[i], ss[j] = (s1 + s1d.T.conj()) / 2, (s1d + s1.T.conj()) / 2
# identifying TRS and TRB parts of the Hamiltonian # identifying TRS and TRB parts of the Hamiltonian
TAUY = np.kron(np.eye(NO), TAU_Y) TAUY: np.array = np.kron(np.eye(NO), TAU_Y)
hTR = np.array([TAUY @ hh[i].conj() @ TAUY for i in range(dh.lattice.nsc.prod())]) hTR: np.array = np.array(
hTRS = (hh + hTR) / 2 [TAUY @ hh[i].conj() @ TAUY for i in range(dh.lattice.nsc.prod())]
hTRB = (hh - hTR) / 2 )
hTRS: np.array = (hh + hTR) / 2
hTRB: np.array = (hh - hTR) / 2
# extracting the exchange field # extracting the exchange field
traced = [spin_tracer(hTRB[i]) for i in range(dh.lattice.nsc.prod())] # equation 77 traced: np.array = [
XCF = np.array( spin_tracer(hTRB[i]) for i in range(dh.lattice.nsc.prod())
] # equation 77
XCF: np.array = np.array(
[ [
np.array([f["x"] / 2 for f in traced]), np.array([f["x"] / 2 for f in traced]),
np.array([f["y"] / 2 for f in traced]), np.array([f["y"] / 2 for f in traced]),
@ -235,7 +246,7 @@ def main(simulation_parameters, magnetic_entities, pairs):
) )
# check if exchange field has scalar part # check if exchange field has scalar part
max_xcfs = abs(np.array(np.array([f["c"] / 2 for f in traced]))).max() max_xcfs: float = abs(np.array(np.array([f["c"] / 2 for f in traced]))).max()
if max_xcfs > 1e-12: if max_xcfs > 1e-12:
warnings.warn( warnings.warn(
f"Exchange field has non negligible scalar part. Largest value is {max_xcfs}" f"Exchange field has non negligible scalar part. Largest value is {max_xcfs}"
@ -270,10 +281,10 @@ def main(simulation_parameters, magnetic_entities, pairs):
) )
# generate weights for k points # generate weights for k points
wkset = np.ones(len(kset)) / len(kset) wkset: np.array = np.ones(len(kset)) / len(kset)
# split the k points based on MPI size # split the k points based on MPI size
kpcs = np.array_split(kset, size) kpcs: np.array = np.array_split(kset, size)
# use progress bar if available # use progress bar if available
if rank == root_node and tqdm_imported: if rank == root_node and tqdm_imported:
@ -289,20 +300,20 @@ def main(simulation_parameters, magnetic_entities, pairs):
# this will contain the three Hamiltonian in the # this will contain the three Hamiltonian in the
# reference directions needed to calculate the energy # reference directions needed to calculate the energy
# variations upon rotation # variations upon rotation
hamiltonians = [] hamiltonians: list = []
# iterate over the reference directions (quantization axes) # iterate over the reference directions (quantization axes)
for i, orient in enumerate(simulation_parameters["ref_xcf_orientations"]): for i, orient in enumerate(simulation_parameters["ref_xcf_orientations"]):
# obtain rotated exchange field and Hamiltonian # obtain rotated exchange field and Hamiltonian
R = RotMa2b(simulation_parameters["scf_xcf_orientation"], orient["o"]) R: np.array = RotMa2b(simulation_parameters["scf_xcf_orientation"], orient["o"])
rot_XCF = np.einsum("ij,jklm->iklm", R, XCF) rot_XCF: np.array = np.einsum("ij,jklm->iklm", R, XCF)
rot_H_XCF = sum( rot_H_XCF: np.array = sum(
[np.kron(rot_XCF[i], tau) for i, tau in enumerate([TAU_X, TAU_Y, TAU_Z])] [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] rot_H_XCF_uc: np.array = rot_H_XCF[uc_in_sc_idx]
# obtain total Hamiltonian with the rotated exchange field # obtain total Hamiltonian with the rotated exchange field
rot_H = hTRS + rot_H_XCF # equation 76 rot_H: np.array = hTRS + rot_H_XCF # equation 76
# store the relevant information of the Hamiltonian # store the relevant information of the Hamiltonian
hamiltonians.append(dict(orient=orient["o"], H=rot_H)) hamiltonians.append(dict(orient=orient["o"], H=rot_H))
@ -310,11 +321,11 @@ def main(simulation_parameters, magnetic_entities, pairs):
# these are the rotations (for now) perpendicular to the quantization axis # these are the rotations (for now) perpendicular to the quantization axis
for u in orient["vw"]: for u in orient["vw"]:
# section 2.H # section 2.H
Tu = np.kron(np.eye(NO, dtype=int), tau_u(u)) Tu: np.array = np.kron(np.eye(NO, dtype=int), tau_u(u))
Vu1, Vu2 = calc_Vu(rot_H_XCF_uc, Tu) Vu1, Vu2 = calc_Vu(rot_H_XCF_uc, Tu)
for mag_ent in magnetic_entities: for mag_ent in magnetic_entities:
idx = mag_ent["spin_box_indices"] idx: int = mag_ent["spin_box_indices"]
# fill up the perturbed potentials (for now) based on the on-site projections # 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["Vu1"][i].append(onsite_projection(Vu1, idx, idx))
mag_ent["Vu2"][i].append(onsite_projection(Vu2, idx, idx)) mag_ent["Vu2"][i].append(onsite_projection(Vu2, idx, idx))
@ -347,7 +358,7 @@ def main(simulation_parameters, magnetic_entities, pairs):
) )
# https://stackoverflow.com/questions/70746660/how-to-predict-memory-requirement-for-np-linalg-inv # https://stackoverflow.com/questions/70746660/how-to-predict-memory-requirement-for-np-linalg-inv
# memory is O(64 n**2) for complex matrices # memory is O(64 n**2) for complex matrices
memory_size = getsizeof(hamiltonians[0]["H"].base) / 1024 memory_size: int = getsizeof(hamiltonians[0]["H"].base) / 1024
print( print(
f"Memory taken by a single Hamiltonian is: {getsizeof(hamiltonians[0]['H'].base) / 1024} KB" f"Memory taken by a single Hamiltonian is: {getsizeof(hamiltonians[0]['H'].base) / 1024} KB"
) )
@ -376,12 +387,12 @@ def main(simulation_parameters, magnetic_entities, pairs):
# sampling the integrand on the contour and the BZ # sampling the integrand on the contour and the BZ
for k in kpcs[rank]: for k in kpcs[rank]:
# weight of k point in BZ integral # weight of k point in BZ integral
wk = wkset[rank] wk: float = wkset[rank]
# iterate over reference directions # iterate over reference directions
for i, hamiltonian_orientation in enumerate(hamiltonians): for i, hamiltonian_orientation in enumerate(hamiltonians):
# calculate Hamiltonian and Overlap matrix in a given k point # calculate Hamiltonian and Overlap matrix in a given k point
H = hamiltonian_orientation["H"] H: np.array = hamiltonian_orientation["H"]
HK, SK = hsk(H, ss, dh.sc_off, k) HK, SK = hsk(H, ss, dh.sc_off, k)
if simulation_parameters["parallel_solver_for_Gk"]: if simulation_parameters["parallel_solver_for_Gk"]:
@ -392,22 +403,22 @@ def main(simulation_parameters, magnetic_entities, pairs):
# store the Greens function slice of the magnetic entities # store the Greens function slice of the magnetic entities
for mag_ent in magnetic_entities: for mag_ent in magnetic_entities:
idx = mag_ent["spin_box_indices"] idx: int = mag_ent["spin_box_indices"]
mag_ent["Gii_tmp"][i] += onsite_projection(Gk, idx, idx) * wk mag_ent["Gii_tmp"][i] += onsite_projection(Gk, idx, idx) * wk
for pair in pairs: for pair in pairs:
# add phase shift based on the cell difference # add phase shift based on the cell difference
phase = np.exp(1j * 2 * np.pi * k @ pair["Ruc"].T) phase: np.array = np.exp(1j * 2 * np.pi * k @ pair["Ruc"].T)
# get the pair orbital sizes from the magnetic entities # get the pair orbital sizes from the magnetic entities
ai = magnetic_entities[pair["ai"]]["spin_box_indices"] ai: int = magnetic_entities[pair["ai"]]["spin_box_indices"]
aj = magnetic_entities[pair["aj"]]["spin_box_indices"] aj: int = magnetic_entities[pair["aj"]]["spin_box_indices"]
# 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 pair["Gij_tmp"][i] += onsite_projection(Gk, ai, aj) * phase * wk
pair["Gji_tmp"][i] += onsite_projection(Gk, aj, ai) / phase * wk pair["Gji_tmp"][i] += onsite_projection(Gk, aj, ai) / phase * wk
# summ reduce partial results of mpi nodes # sum reduce partial results of mpi nodes
for i in range(len(hamiltonians)): for i in range(len(hamiltonians)):
for mag_ent in magnetic_entities: for mag_ent in magnetic_entities:
comm.Reduce(mag_ent["Gii_tmp"][i], mag_ent["Gii"][i], root=root_node) comm.Reduce(mag_ent["Gii_tmp"][i], mag_ent["Gii"][i], root=root_node)
@ -430,11 +441,11 @@ def main(simulation_parameters, magnetic_entities, pairs):
for tracker, mag_ent in enumerate(magnetic_entities): for tracker, mag_ent in enumerate(magnetic_entities):
# iterate over the quantization axes # iterate over the quantization axes
for i, Gii in enumerate(mag_ent["Gii"]): for i, Gii in enumerate(mag_ent["Gii"]):
storage = [] storage: list = []
# iterate over the first and second order local perturbations # iterate over the first and second order local perturbations
for Vu1, Vu2 in zip(mag_ent["Vu1"][i], mag_ent["Vu2"][i]): for Vu1, Vu2 in zip(mag_ent["Vu1"][i], mag_ent["Vu2"][i]):
# The Szunyogh-Lichtenstein formula # The Szunyogh-Lichtenstein formula
traced = np.trace( traced: np.array = np.trace(
(Vu2 @ Gii + 0.5 * Gii @ Vu1 @ Gii), axis1=1, axis2=2 (Vu2 @ Gii + 0.5 * Gii @ Vu1 @ Gii), 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
@ -450,16 +461,16 @@ def main(simulation_parameters, magnetic_entities, pairs):
for tracker, pair in enumerate(pairs): for tracker, pair in enumerate(pairs):
# iterate over the quantization axes # iterate over the quantization axes
for i, (Gij, Gji) in enumerate(zip(pair["Gij"], pair["Gji"])): for i, (Gij, Gji) in enumerate(zip(pair["Gij"], pair["Gji"])):
site_i = magnetic_entities[pair["ai"]] site_i: int = magnetic_entities[pair["ai"]]
site_j = magnetic_entities[pair["aj"]] site_j: int = magnetic_entities[pair["aj"]]
storage = [] storage: list = []
# iterate over the first order local perturbations in all possible orientations for the two sites # iterate over the first order local perturbations in all possible orientations for the two sites
# actually all possible orientations without the orientation for the off-diagonal anisotropy # actually all possible orientations without the orientation for the off-diagonal anisotropy
# that is why we only take the first two of each Vu1 # that is why we only take the first two of each Vu1
for Vui in site_i["Vu1"][i][:2]: for Vui in site_i["Vu1"][i][:2]:
for Vuj in site_j["Vu1"][i][:2]: for Vuj in site_j["Vu1"][i][:2]:
# The Szunyogh-Lichtenstein formula # The Szunyogh-Lichtenstein formula
traced = np.trace( traced: np.array = np.trace(
(Vui @ Gij @ Vuj @ Gji), axis1=1, axis2=2 (Vui @ Gij @ Vuj @ Gji), 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
@ -499,7 +510,7 @@ def main(simulation_parameters, magnetic_entities, pairs):
# remove unwanted stuff before saving # remove unwanted stuff before saving
pairs, magnetic_entities = remove_clutter_for_save(pairs, magnetic_entities) pairs, magnetic_entities = remove_clutter_for_save(pairs, magnetic_entities)
# create output dictionary with all the relevant data # create output dictionary with all the relevant data
results = dict( results: dict = dict(
parameters=simulation_parameters, parameters=simulation_parameters,
magnetic_entities=magnetic_entities, magnetic_entities=magnetic_entities,
pairs=pairs, pairs=pairs,
@ -514,28 +525,25 @@ def main(simulation_parameters, magnetic_entities, pairs):
if __name__ == "__main__": if __name__ == "__main__":
# loading parameters # loading parameters
# it is not clear how to give grogu.fdf path... command_line_arguments = parse_command_line()
# command_line_arguments = parse_command_line() fdf_arguments, magnetic_entities, pairs = read_grogupy_fdf(
# fdf_arguments, magnetic_entities, pairs = read_fdf(command_line_arguments["infile"]) command_line_arguments["grogupy_infile"]
)
# right now we do not use any of these input, but it shows
# the order of priority when processing arguments # combine the inputs to a single dictionary
default_arguments = False simulation_parameters: Final[dict] = process_input_args(
fdf_arguments = False DEFAULT_ARGUMENTS, fdf_arguments, command_line_arguments, ACCEPTED_INPUTS
command_line_arguments = False )
# simulation_parameters = process_input_args(
# default_arguments, fdf_arguments, command_line_arguments, ACCEPTED_INPUTS
# )
#################################################################################################### ####################################################################################################
# This is the input file for now # # This is the input file for now #
#################################################################################################### ####################################################################################################
magnetic_entities = [ magnetic_entities: list = [
dict(atom=3, l=2), dict(atom=3, l=2),
dict(atom=4, l=2), dict(atom=4, l=2),
dict(atom=5, l=2), dict(atom=5, l=2),
] ]
pairs = [ pairs: list = [
dict(ai=0, aj=1, Ruc=np.array([0, 0, 0])), dict(ai=0, aj=1, Ruc=np.array([0, 0, 0])),
dict(ai=0, aj=2, 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=1, aj=2, Ruc=np.array([0, 0, 0])),
@ -546,7 +554,7 @@ if __name__ == "__main__":
dict(ai=1, aj=2, Ruc=np.array([-2, 0, 0])), dict(ai=1, aj=2, Ruc=np.array([-2, 0, 0])),
dict(ai=1, aj=2, Ruc=np.array([-3, 0, 0])), dict(ai=1, aj=2, Ruc=np.array([-3, 0, 0])),
] ]
simulation_parameters = dict() simulation_parameters: dict = dict()
simulation_parameters["infile"] = ( simulation_parameters["infile"] = (
"/Users/danielpozsar/Downloads/nojij/Fe3GeTe2/monolayer/soc/lat3_791/Fe3GeTe2.fdf" "/Users/danielpozsar/Downloads/nojij/Fe3GeTe2/monolayer/soc/lat3_791/Fe3GeTe2.fdf"
) )

@ -22,13 +22,15 @@
""" """
from pickle import dump, load from pickle import dump, load
from typing import Final
import numpy as np import numpy as np
from globals import ACCEPTED_INPUTS, DEFAULT_ARGUMENTS
from sisl.io import fdfSileSiesta from sisl.io import fdfSileSiesta
from grogupy.constants import ACCEPTED_INPUTS
def read_fdf(path):
def read_grogupy_fdf(path: str) -> tuple[dict, list, list]:
"""It reads the simulation parameters, magnetic entities and pairs from the fdf. """It reads the simulation parameters, magnetic entities and pairs from the fdf.
Args: Args:
@ -113,26 +115,39 @@ def read_fdf(path):
MagneticEntities = fdf.get("MagneticEntities") MagneticEntities = fdf.get("MagneticEntities")
if MagneticEntities is not None: if MagneticEntities is not None:
magnetic_entities = [] magnetic_entities = []
# iterate over magnetic entities
for mag_ent in MagneticEntities: for mag_ent in MagneticEntities:
# drop comments from data
row = mag_ent.split() row = mag_ent.split()
dat = [] dat = []
for string in row: for string in row:
if string.find("#") != -1: if string.find("#") != -1:
break break
dat.append(string) dat.append(string)
# cluster input
if dat[0] in {"Cluster", "cluster"}: if dat[0] in {"Cluster", "cluster"}:
magnetic_entities.append(dict(atom=[int(_) for _ in dat[1:]])) magnetic_entities.append(dict(atom=[int(_) for _ in dat[1:]]))
continue continue
# atom input, same as cluster, but raises
# error when multiple atoms are given
if dat[0] in {"Atom", "atom"}:
if len(dat) > 2:
raise Exception("Atom input must be a single integer")
magnetic_entities.append(dict(atom=int(dat[1])))
continue
# atom and shell information
elif dat[0] in {"AtomShell", "Atomshell", "atomShell", "atomshell"}: elif dat[0] in {"AtomShell", "Atomshell", "atomShell", "atomshell"}:
magnetic_entities.append( magnetic_entities.append(
dict(atom=int(dat[1]), l=[int(_) for _ in dat[2:]]) dict(atom=int(dat[1]), l=[int(_) for _ in dat[2:]])
) )
continue continue
# atom and orbital information
elif dat[0] in {"AtomOrbital", "Atomorbital", "tomOrbital", "atomorbital"}: elif dat[0] in {"AtomOrbital", "Atomorbital", "tomOrbital", "atomorbital"}:
magnetic_entities.append( magnetic_entities.append(
dict(atom=int(dat[1]), orb=[int(_) for _ in dat[2:]]) dict(atom=int(dat[1]), orb=[int(_) for _ in dat[2:]])
) )
continue continue
# orbital information
elif dat[0] in {"Orbitals", "orbitals"}: elif dat[0] in {"Orbitals", "orbitals"}:
magnetic_entities.append(dict(orb=[int(_) for _ in dat[1:]])) magnetic_entities.append(dict(orb=[int(_) for _ in dat[1:]]))
continue continue
@ -143,11 +158,11 @@ def read_fdf(path):
def process_input_args( def process_input_args(
default_arguments, DEFAULT_ARGUMENTS: dict,
fdf_arguments, fdf_arguments: dict,
command_line_arguments, command_line_arguments: dict,
accepted_inputs=ACCEPTED_INPUTS, accepted_inputs: dict = ACCEPTED_INPUTS,
): ) -> dict:
"""It returns the final simulation parameters based on the inputs. """It returns the final simulation parameters based on the inputs.
The merging is done in the order of priority: The merging is done in the order of priority:
@ -168,6 +183,9 @@ def process_input_args(
The final simulation parameters The final simulation parameters
""" """
# copy input so it does not get changed
default_arguments = DEFAULT_ARGUMENTS.copy()
# iterate over fdf_arguments and update default arguments # iterate over fdf_arguments and update default arguments
for key, value in fdf_arguments.values(): for key, value in fdf_arguments.values():
if value is not None and key in accepted_inputs: if value is not None and key in accepted_inputs:
@ -181,7 +199,7 @@ def process_input_args(
return default_arguments return default_arguments
def save_pickle(outfile, data): def save_pickle(outfile: str, data: dict) -> None:
"""Saves the data in the outfile with pickle. """Saves the data in the outfile with pickle.
Args: Args:
@ -196,7 +214,7 @@ def save_pickle(outfile, data):
dump(data, output_file) dump(data, output_file)
def load_pickle(infile): def load_pickle(infile: str) -> dict:
"""Loads the data from the infile with pickle. """Loads the data from the infile with pickle.
Args: Args:
@ -215,7 +233,7 @@ def load_pickle(infile):
return data return data
def print_job_description(simulation_parameters): def print_job_description(simulation_parameters: dict) -> None:
"""It prints the parameters and the description of the job. """It prints the parameters and the description of the job.
@ -273,7 +291,7 @@ def print_job_description(simulation_parameters):
) )
def print_parameters(simulation_parameters): def print_parameters(simulation_parameters: dict) -> None:
"""It prints the simulation parameters for the grogu out. """It prints the simulation parameters for the grogu out.
Args: Args:
@ -319,7 +337,7 @@ def print_parameters(simulation_parameters):
) )
def print_atoms_and_pairs(magnetic_entities, pairs): def print_atoms_and_pairs(magnetic_entities: list, pairs: list) -> None:
"""It prints the pair and magnetic entity information for the grogu out. """It prints the pair and magnetic entity information for the grogu out.
Args: Args:
@ -408,7 +426,7 @@ def print_atoms_and_pairs(magnetic_entities, pairs):
) )
def print_runtime_information(times): def print_runtime_information(times: dict) -> None:
"""It prints the runtime information for the grogu out. """It prints the runtime information for the grogu out.
Args: Args:
@ -426,10 +444,10 @@ def print_runtime_information(times):
f"Hamiltonian conversion and XC field extraction: {times['H_and_XCF_time'] - times['setup_time']:.3f} s" f"Hamiltonian conversion and XC field extraction: {times['H_and_XCF_time'] - times['setup_time']:.3f} s"
) )
print( print(
f"Pair and site datastructure creatrions: {times['site_and_pair_dictionaries_time'] - times['H_and_XCF_time']:.3f} s" f"Pair and site datastructures creations: {times['site_and_pair_dictionaries_time'] - times['H_and_XCF_time']:.3f} s"
) )
print( print(
f"k set cration and distribution: {times['k_set_time'] - times['site_and_pair_dictionaries_time']:.3f} s" f"k set creation and distribution: {times['k_set_time'] - times['site_and_pair_dictionaries_time']:.3f} s"
) )
print( print(
f"Rotating XC potential: {times['reference_rotations_time'] - times['k_set_time']:.3f} s" f"Rotating XC potential: {times['reference_rotations_time'] - times['k_set_time']:.3f} s"

@ -21,10 +21,13 @@
"""Docstring in magnetism. """Docstring in magnetism.
""" """
from typing import Union
import numpy as np import numpy as np
from sisl.physics import Hamiltonian
def blow_up_orbindx(orb_indices): def blow_up_orbindx(orb_indices: np.array) -> np.array:
"""Function to blow up orbital indices to make SPIN BOX indices. """Function to blow up orbital indices to make SPIN BOX indices.
Args: Args:
@ -41,7 +44,7 @@ def blow_up_orbindx(orb_indices):
return orb_indices return orb_indices
def spin_tracer(M): def spin_tracer(M: np.array) -> dict:
"""Spin tracer utility. """Spin tracer utility.
This takes an operator with the orbital-spin sequence: This takes an operator with the orbital-spin sequence:
@ -75,7 +78,12 @@ def spin_tracer(M):
return M_o return M_o
def parse_magnetic_entity(dh, atom=None, l=None, **kwargs): def parse_magnetic_entity(
dh: Hamiltonian,
atom: Union[None, int, list] = None,
l: Union[None, int, list] = None,
orb: Union[None, int, list] = None,
) -> np.array:
"""Function to define orbital indexes of a given magnetic entity. """Function to define orbital indexes of a given magnetic entity.
Args: Args:
@ -83,13 +91,19 @@ def parse_magnetic_entity(dh, atom=None, l=None, **kwargs):
Hamiltonian from sisl Hamiltonian from sisl
atom : integer or list of integers, optional atom : integer or list of integers, optional
Defining atom (or atoms) in the unit cell forming the magnetic entity. Defaults to None Defining atom (or atoms) in the unit cell forming the magnetic entity. Defaults to None
l : integer, optional l : integer or list of integers, optional
Defining the angular momentum channel. Defaults to None Defining the angular momentum channel. Defaults to None
orb : integer or list of integers, optional
Defining the orbital index in the Hamiltonian or on the atom. Defaults to None
Returns: Returns:
list list
The orbital indexes of the given magnetic entity The orbital indexes of the given magnetic entity
""" """
# the case for the Orbitals keyword
if atom is None:
return orb
# case where we deal with more than one atom defining the magnetic entity # case where we deal with more than one atom defining the magnetic entity
if type(atom) == list: if type(atom) == list:
dat = [] dat = []
@ -100,21 +114,21 @@ def parse_magnetic_entity(dh, atom=None, l=None, **kwargs):
): # if specified we restrict to given l angular momentum channel inside each atom ): # if specified we restrict to given l angular momentum channel inside each atom
a_orb_idx = a_orb_idx[[o.l == l for o in dh.geometry.atoms[a].orbitals]] a_orb_idx = a_orb_idx[[o.l == l for o in dh.geometry.atoms[a].orbitals]]
dat.append(a_orb_idx) dat.append(a_orb_idx)
orbital_indeces = np.hstack(dat) orbital_indexes = np.hstack(dat)
# case where we deal with a singel atom magnetic entity # case where we deal with a single atom magnetic entity
elif type(atom) == int: elif type(atom) == int:
orbital_indeces = dh.geometry.a2o(atom, all=True) orbital_indexes = dh.geometry.a2o(atom, all=True)
if ( if (
type(l) == int type(l) == int
): # if specified we restrict to given l angular momentum channel ): # if specified we restrict to given l angular momentum channel
orbital_indeces = orbital_indeces[ orbital_indexes = orbital_indexes[
[o.l == l for o in dh.geometry.atoms[atom].orbitals] [o.l == l for o in dh.geometry.atoms[atom].orbitals]
] ]
return orbital_indeces # numpy array containing integers labeling orbitals associated to a magnetic entity. return orbital_indexes # numpy array containing integers labeling orbitals associated to a magnetic entity.
def calculate_anisotropy_tensor(mag_ent): def calculate_anisotropy_tensor(mag_ent: dict) -> tuple[np.array, float]:
"""Calculates the renormalized anisotropy tensor from the energies. """Calculates the renormalized anisotropy tensor from the energies.
Args: Args:
@ -154,7 +168,7 @@ def calculate_anisotropy_tensor(mag_ent):
return K, consistency_check return K, consistency_check
def calculate_exchange_tensor(pair): def calculate_exchange_tensor(pair: dict) -> tuple[float, np.array, np.array, np.array]:
"""Calculates the exchange tensor from the energies. """Calculates the exchange tensor from the energies.
It produces the isotropic exchange, the relevant elements It produces the isotropic exchange, the relevant elements

@ -21,13 +21,16 @@
"""Docstring in utilities. """Docstring in utilities.
""" """
from typing import Union
import numpy as np import numpy as np
from globals import TAU_0, TAU_X, TAU_Y, TAU_Z
from scipy.special import roots_legendre from scipy.special import roots_legendre
from sisl.io.siesta import eigSileSiesta from sisl.io.siesta import eigSileSiesta
from grogupy.constants import TAU_0, TAU_X, TAU_Y, TAU_Z
def commutator(a, b): def commutator(a: np.array, b: np.array) -> np.array:
"""Shorthand for commutator. """Shorthand for commutator.
Commutator of two matrices in the mathematical sense. Commutator of two matrices in the mathematical sense.
@ -47,7 +50,9 @@ def commutator(a, b):
# define some useful functions # define some useful functions
def hsk(H, ss, sc_off, k=(0, 0, 0)): def hsk(
H: np.array, ss: np.array, sc_off: list, k: tuple = (0, 0, 0)
) -> tuple[np.array, np.array]:
"""Speed up Hk and Sk generation. """Speed up Hk and Sk generation.
Calculates the Hamiltonian and the Overlap matrix at a given k point. It is faster that the sisl version. Calculates the Hamiltonian and the Overlap matrix at a given k point. It is faster that the sisl version.
@ -83,7 +88,7 @@ def hsk(H, ss, sc_off, k=(0, 0, 0)):
return HK, SK return HK, SK
def make_kset(dirs="xyz", NUMK=20): def make_kset(dirs: str = "xyz", NUMK: int = 20) -> np.array:
"""Simple k-grid generator to sample the Brillouin zone. """Simple k-grid generator to sample the Brillouin zone.
Depending on the value of the dirs Depending on the value of the dirs
@ -109,19 +114,26 @@ def make_kset(dirs="xyz", NUMK=20):
kran = len(dirs) * [np.linspace(0, 1, NUMK, endpoint=False)] kran = len(dirs) * [np.linspace(0, 1, NUMK, endpoint=False)]
mg = np.meshgrid(*kran) mg = np.meshgrid(*kran)
dirsdict = dict() directions = dict()
for d in enumerate(dirs): for d in enumerate(dirs):
dirsdict[d[1]] = mg[d[0]].flatten() directions[d[1]] = mg[d[0]].flatten()
for d in "xyz": for d in "xyz":
if not (d in dirs): if not (d in dirs):
dirsdict[d] = 0 * dirsdict[dirs[0]] directions[d] = 0 * directions[dirs[0]]
kset = np.array([dirsdict[d] for d in "xyz"]).T kset = np.array([directions[d] for d in "xyz"]).T
return kset return kset
def make_contour(emin=-20, emax=0.0, enum=42, p=150): # just an empty container class
class Container:
pass
def make_contour(
emin: float = -20, emax: float = 0.0, enum: int = 42, p: float = 150
) -> Container:
"""A more sophisticated contour generator. """A more sophisticated contour generator.
Calculates the parameters for the complex contour integral. It uses the Calculates the parameters for the complex contour integral. It uses the
@ -139,7 +151,7 @@ def make_contour(emin=-20, emax=0.0, enum=42, p=150):
Shape parameter that describes the distribution of the sample points. Defaults to 150 Shape parameter that describes the distribution of the sample points. Defaults to 150
Returns: Returns:
ccont Container
Contains all the information for the contour integral Contains all the information for the contour integral
""" """
x, wl = roots_legendre(enum) x, wl = roots_legendre(enum)
@ -153,11 +165,7 @@ def make_contour(emin=-20, emax=0.0, enum=42, p=150):
ze = z0 + R * np.exp(1j * phi) # complex points for path ze = z0 + R * np.exp(1j * phi) # complex points for path
we = -(y2 - y1) / 2 * np.exp(-y) / p * 1j * (ze - z0) * wl we = -(y2 - y1) / 2 * np.exp(-y) / p * 1j * (ze - z0) * wl
# just an empty container class cont = Container()
class ccont:
pass
cont = ccont()
cont.R = R cont.R = R
cont.z0 = z0 cont.z0 = z0
cont.ze = ze cont.ze = ze
@ -167,7 +175,7 @@ def make_contour(emin=-20, emax=0.0, enum=42, p=150):
return cont return cont
def tau_u(u): def tau_u(u: Union[list, np.array]) -> np.array:
"""Pauli matrix in direction u. """Pauli matrix in direction u.
Returns the vector u in the basis of the Pauli matrices. Returns the vector u in the basis of the Pauli matrices.
@ -188,7 +196,7 @@ def tau_u(u):
# #
def crossM(u): def crossM(u: Union[list, np.array]) -> np.array:
"""Definition for the cross-product matrix. """Definition for the cross-product matrix.
It acts as a cross product with vector u. It acts as a cross product with vector u.
@ -204,7 +212,7 @@ def crossM(u):
return np.array([[0, -u[2], u[1]], [u[2], 0, -u[0]], [-u[1], u[0], 0]]) return np.array([[0, -u[2], u[1]], [u[2], 0, -u[0]], [-u[1], u[0], 0]])
def RotM(theta, u, eps=1e-10): def RotM(theta: float, u: np.array, eps: float = 1e-10) -> np.array:
"""Definition of rotation matrix with angle theta around direction u. """Definition of rotation matrix with angle theta around direction u.
@ -234,7 +242,7 @@ def RotM(theta, u, eps=1e-10):
return M return M
def RotMa2b(a, b, eps=1e-10): def RotMa2b(a: np.array, b: np.array, eps: float = 1e-10) -> np.array:
"""Definition of rotation matrix rotating unit vector a to unit vector b. """Definition of rotation matrix rotating unit vector a to unit vector b.
Function returns array R such that R @ a = b holds. Function returns array R such that R @ a = b holds.
@ -261,7 +269,7 @@ def RotMa2b(a, b, eps=1e-10):
return M return M
def read_siesta_emin(eigfile): def read_siesta_emin(eigfile: str) -> float:
"""It reads the lowest energy level from the siesta run. """It reads the lowest energy level from the siesta run.
It uses the .EIG file from siesta that contains the eigenvalues. It uses the .EIG file from siesta that contains the eigenvalues.
@ -276,12 +284,12 @@ def read_siesta_emin(eigfile):
""" """
# read the file # read the file
eigs = eigSileSiesta(eigfile).read_data() eigenvalues = eigSileSiesta(eigfile).read_data()
return eigs.min() return eigenvalues.min()
def int_de_ke(traced, we): def int_de_ke(traced: np.array, we: float) -> np.array:
"""It numerically integrates the traced matrix. """It numerically integrates the traced matrix.
It is a wrapper from numpy.trapz and it contains the It is a wrapper from numpy.trapz and it contains the

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 3,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -16,7 +16,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 4,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@ -24,14 +24,14 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"0.14.3\n", "0.14.3\n",
"numpy version unknown.\n" "1.24.4\n"
] ]
}, },
{ {
"name": "stderr", "name": "stderr",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[Daniels-MacBook-Air.local:40959] shmem: mmap: an error occurred while determining whether or not /var/folders/yh/dx7xl94n3g52ts3td8qcxjcc0000gn/T//ompi.Daniels-MacBook-Air.501/jf.0/3756457984/sm_segment.Daniels-MacBook-Air.501.dfe70000.0 could be created.\n" "[Daniels-MacBook-Air.local:67208] shmem: mmap: an error occurred while determining whether or not /var/folders/yh/dx7xl94n3g52ts3td8qcxjcc0000gn/T//ompi.Daniels-MacBook-Air.501/jf.0/2623209472/sm_segment.Daniels-MacBook-Air.501.9c5b0000.0 could be created.\n"
] ]
} }
], ],
@ -63,6 +63,60 @@
" print(\"numpy version unknown.\")" " print(\"numpy version unknown.\")"
] ]
}, },
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"({'infile': '/Users/danielpozsar/Downloads/nojij/Fe3GeTe2/monolayer/soc/lat3_791/Fe3GeTe2.fdf',\n",
" 'outfile': './Fe3GeTe2_notebook',\n",
" 'scf_xcf_orientation': array('[ 0 0 1 ]', dtype='<U9'),\n",
" 'ref_xcf_orientations': [{'o': array([1., 0., 0.]),\n",
" 'vw': array([[0., 1., 0.],\n",
" [0., 0., 1.]])},\n",
" {'o': array([0., 1., 0.]),\n",
" 'vw': array([[1., 0., 0.],\n",
" [0., 0., 1.]])},\n",
" {'o': array([0., 0., 1.]),\n",
" 'vw': array([[1., 0., 0.],\n",
" [0., 1., 0.]])}],\n",
" 'kset': 3,\n",
" 'kdirs': 'xy',\n",
" 'ebot': -13,\n",
" 'eset': 300,\n",
" 'esetp': 1000,\n",
" 'parallel_solver_for_Gk': False,\n",
" 'padawan_mode': True},\n",
" [{'atom': [4, 5]},\n",
" {'atom': 3},\n",
" {'atom': 3, 'l': [2]},\n",
" {'atom': 4, 'l': [2, 3]},\n",
" {'atom': 5, 'l': [2]},\n",
" {'atom': 3, 'orb': [7, 2, 4]},\n",
" {'orb': [2, 1, 4, 9]}],\n",
" [{'ai': 0, 'aj': 1, 'Ruc': array([0, 0, 0])},\n",
" {'ai': 0, 'aj': 2, 'Ruc': array([0, 0, 0])},\n",
" {'ai': 1, 'aj': 2, 'Ruc': array([0, 0, 0])},\n",
" {'ai': 0, 'aj': 2, 'Ruc': array([-1, -1, 0])},\n",
" {'ai': 1, 'aj': 2, 'Ruc': array([-1, -1, 0])},\n",
" {'ai': 0, 'aj': 2, 'Ruc': array([-1, 0, 0])},\n",
" {'ai': 1, 'aj': 2, 'Ruc': array([-1, 0, 0])},\n",
" {'ai': 1, 'aj': 2, 'Ruc': array([-2, 0, 0])},\n",
" {'ai': 1, 'aj': 2, 'Ruc': array([-3, 0, 0])}])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"read_grogupy_fdf(\"input.fdf\")"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
@ -120,52 +174,7 @@
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [],
{
"name": "stdout",
"output_type": "stream",
"text": [
"================================================================================================================================================================\n",
"Input file: \n",
"/Users/danielpozsar/Downloads/nojij/Fe3GeTe2/monolayer/soc/lat3_791/Fe3GeTe2.fdf\n",
"Output file: \n",
"./Fe3GeTe2_notebook.pickle\n",
"Number of nodes in the parallel cluster: 1\n",
"================================================================================================================================================================\n",
"Cell [Ang]: \n",
"[[ 3.79100000e+00 0.00000000e+00 0.00000000e+00]\n",
" [-1.89550000e+00 3.28310231e+00 0.00000000e+00]\n",
" [ 1.25954923e-15 2.18160327e-15 2.05700000e+01]]\n",
"================================================================================================================================================================\n",
"DFT axis: \n",
"[0 0 1]\n",
"Quantization axis and perpendicular rotation directions:\n",
"[1 0 0] --» [array([0, 1, 0]), array([0, 0, 1])]\n",
"[0 1 0] --» [array([1, 0, 0]), array([0, 0, 1])]\n",
"[0 0 1] --» [array([1, 0, 0]), array([0, 1, 0])]\n",
"================================================================================================================================================================\n",
"Parameters for the contour integral:\n",
"Number of k points: 3\n",
"k point directions: xy\n",
"Ebot: -13\n",
"Eset: 300\n",
"Esetp: 1000\n",
"================================================================================================================================================================\n"
]
},
{
"ename": "KeyError",
"evalue": "'calculate_charge'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[5], line 43\u001b[0m\n\u001b[1;32m 40\u001b[0m uc_in_sc_idx \u001b[38;5;241m=\u001b[39m dh\u001b[38;5;241m.\u001b[39mlattice\u001b[38;5;241m.\u001b[39msc_index([\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m0\u001b[39m])\n\u001b[1;32m 42\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m rank \u001b[38;5;241m==\u001b[39m root_node:\n\u001b[0;32m---> 43\u001b[0m \u001b[43mprint_parameters\u001b[49m\u001b[43m(\u001b[49m\u001b[43msimulation_parameters\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 44\u001b[0m times[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msetup_time\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m timer()\n\u001b[1;32m 45\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mSetup done. Elapsed time: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimes[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msetup_time\u001b[39m\u001b[38;5;124m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m s\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
"File \u001b[0;32m~/Documents/oktatás/elte/phd/grogu_project/.venv/lib/python3.9/site-packages/grogupy/io.py:132\u001b[0m, in \u001b[0;36mprint_parameters\u001b[0;34m(simulation_parameters)\u001b[0m\n\u001b[1;32m 128\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mEsetp: \u001b[39m\u001b[38;5;124m\"\u001b[39m, simulation_parameters[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mesetp\u001b[39m\u001b[38;5;124m\"\u001b[39m])\n\u001b[1;32m 129\u001b[0m \u001b[38;5;28mprint\u001b[39m(\n\u001b[1;32m 130\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m================================================================================================================================================================\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 131\u001b[0m )\n\u001b[0;32m--> 132\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[43msimulation_parameters\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcalculate_charge\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m:\n\u001b[1;32m 133\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe calculated charge of the Hamiltonian in the quantization axes: \u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 134\u001b[0m \u001b[38;5;28mprint\u001b[39m(simulation_parameters[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcharges\u001b[39m\u001b[38;5;124m\"\u001b[39m])\n",
"\u001b[0;31mKeyError\u001b[0m: 'calculate_charge'"
]
}
],
"source": [ "source": [
"# MPI parameters\n", "# MPI parameters\n",
"comm = MPI.COMM_WORLD\n", "comm = MPI.COMM_WORLD\n",

@ -27,7 +27,7 @@ from pathlib import Path
import numpy as np import numpy as np
import pytest import pytest
from grogupy.globals import DEFAULT_ARGUMENTS from grogupy.constants import DEFAULT_ARGUMENTS
from grogupy.io import ( from grogupy.io import (
load_pickle, load_pickle,
print_atoms_and_pairs, print_atoms_and_pairs,

@ -24,7 +24,7 @@ from hypothesis import given
from hypothesis import strategies as st from hypothesis import strategies as st
from numpy.testing import assert_allclose, assert_array_almost_equal from numpy.testing import assert_allclose, assert_array_almost_equal
from grogupy.globals import TAU_0, TAU_X, TAU_Y, TAU_Z from grogupy.constants import TAU_0, TAU_X, TAU_Y, TAU_Z
from grogupy.utilities import ( from grogupy.utilities import (
RotM, RotM,
RotMa2b, RotMa2b,

Loading…
Cancel
Save