Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sanity check all pickled non-interacting Hamiltonians in h0 directory #52

Merged
merged 37 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
cd98d68
sanity check all non-interacting Hamiltonians in pickled files in the…
JohanSchott Mar 25, 2024
99eae10
projected angular momentum should be between -L and L
JohanSchott Mar 26, 2024
84bb9cd
use pickle.load
JohanSchott Mar 26, 2024
279ec77
Use default values for stdout and stderr. Want to see where the unit-…
JohanSchott Mar 26, 2024
c17494f
another attempt to see the error traceback from the subprocess
JohanSchott Mar 27, 2024
a41d0db
debug printing and removing mpirun. Do not understand why python comm…
JohanSchott Mar 27, 2024
ceb574b
try mpiexec
JohanSchott Mar 27, 2024
78dd4a1
edit github action script
JohanSchott Mar 27, 2024
e164afb
install python3-mpi4py. Remove openmpi-bin and libopenmpi-dev
JohanSchott Mar 31, 2024
fd120a1
correctly remove libs in requirements-ubuntu.txt
JohanSchott Mar 31, 2024
32621f2
add back openmpi-bin and libopenmpi-dev
JohanSchott Mar 31, 2024
812f632
try echo in parallel
JohanSchott Mar 31, 2024
90fcb49
can not reproduce mpi issue locally. Another commit to investigate fa…
JohanSchott Mar 31, 2024
a733919
install some more stuff
JohanSchott Mar 31, 2024
0fce41d
run mpiexec not in subprocess
JohanSchott Apr 1, 2024
93f07d0
narrow down what is causing the MPI problem.
JohanSchott Apr 1, 2024
be2e228
skip comparison
JohanSchott Apr 1, 2024
efdb6ca
black fix.
JohanSchott Apr 1, 2024
da733ba
ruff fix.
JohanSchott Apr 1, 2024
d58bd68
try also pytest
JohanSchott Apr 1, 2024
7c426dc
try to run real script again.
JohanSchott Apr 1, 2024
4b04f57
add back comparison
JohanSchott Apr 1, 2024
d1f7e9f
ruff fix.
JohanSchott Apr 1, 2024
e52300b
use $ranks processes
JohanSchott Apr 1, 2024
3ec341e
only pytest
JohanSchott Apr 1, 2024
e794715
run all pytests
JohanSchott Apr 1, 2024
80e2bdd
do not treat warnings as errors
JohanSchott Apr 1, 2024
bc383c1
remove mpi stuff and checks
JohanSchott Apr 2, 2024
eaac5bf
use mpiexec when run all unit-tests
JohanSchott Apr 2, 2024
8b8109f
ignore test_comparison_with_reference.py in pytest.ini since it start…
Apr 2, 2024
fcda47f
run subprocess as a separate pytest job.
Apr 2, 2024
fcd732d
add documentation
Apr 2, 2024
185cd51
clean up scripts/run_Ni_NiO_Xbath.sh
Apr 2, 2024
114a836
remove mpi libs in requirements-ubuntu.txt
Apr 2, 2024
86d2d2f
use subprocess.run with check=True
JohanSchott Apr 8, 2024
0d5b4d6
remove extra white spacing
JohanSchott Apr 8, 2024
9ef052d
remove unneccecary print statement and unused variable.
JohanSchott Apr 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/buildci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
Expand All @@ -38,5 +38,7 @@ jobs:
run: |
# Activate virtual environment, and set PYTHONPATH
source env.sh
pytest
# test_comparison_with_reference.py is ignored in pytest.ini
# Test it separatly since it starts MPI processes in a subprocess.run.
pytest
pytest impurityModel/test/test_comparison_with_reference.py
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ Type
```bash
pytest
```
and
```bash
pytest impurityModel/test/test_comparison_with_reference.py
```
to run all python unit tests in the repository.

### Documentation
Expand Down
37 changes: 5 additions & 32 deletions impurityModel/ed/get_spectra.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ def get_hamiltonian_operator(nBaths, nValBaths, slaterCondon, SOCs, DCinfo, hFie
hHfieldOperator = finite.gethHfieldop(hx, hy, hz, l=2)

# Read the non-relativistic non-interacting Hamiltonian operator from file.
h0_operator = get_h0_operator(h0_filename, nBaths)
h0_operator = read_pickled_file(h0_filename)

# Add Hamiltonian terms to one operator.
hOperator = finite.addOps(
Expand All @@ -416,37 +416,10 @@ def get_hamiltonian_operator(nBaths, nValBaths, slaterCondon, SOCs, DCinfo, hFie
return hOp


def get_h0_operator(h0_filename, nBaths):
"""
Return h0 operator.
Parameters
----------
h0_filename : str
Filename of non-interacting, non-relativistic operator.
nBaths : dict
Number of bath states for each angular momentum.
Returns
-------
h0_operator : dict
The non-relativistic non-interacting Hamiltonian in operator form.
Hamiltonian describes 3d orbitals and bath orbitals.
tuple : complex,
where each tuple describes a process of two steps (annihilation and then creation).
Each step is described by a tuple of the form:
(spin_orb, 'c') or (spin_orb, 'a'),
where spin_orb is a tuple of the form (l, s, m) or (l, b) or ((l_a, l_b), b).
"""
with open(h0_filename, "rb") as handle:
h0_operator = pickle.loads(handle.read())
# Sanity check
for process in h0_operator.keys():
for event in process:
if len(event[0]) == 2:
assert nBaths[event[0][0]] > event[0][1]
return h0_operator
def read_pickled_file(filename: str):
with open(filename, "rb") as handle:
content = pickle.load(handle)
return content


if __name__ == "__main__":
Expand Down
57 changes: 30 additions & 27 deletions impurityModel/test/test_comparison_with_reference.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""
Module with test comparing new simulations with reference data.

test_comparison_with_reference.py is not allowed to import any MPI stuff, except in the subprocess.run.
Otherwise MPI gets confused, since MPI can't handle that both the parent and the child process use MPI.
"""

import inspect
import math
import os
import subprocess
Expand All @@ -11,50 +13,51 @@
import h5py
import numpy as np

DIR_PATH = os.path.dirname(os.path.realpath(__file__))

SCRIPT_PATH = os.path.join(DIR_PATH, "../../scripts/run_Ni_NiO_Xbath.sh")
REFERENCE_SPECTRA_PATH = os.path.join(DIR_PATH, "referenceOutput/Ni_NiO_50bath/spectra.h5")


def test_comparison():
compare_spectra()


def compare_spectra(
script_file="scripts/run_Ni_NiO_Xbath.sh",
script_path=SCRIPT_PATH,
script_argument=50,
reference_file="referenceOutput/Ni_NiO_50bath/spectra.h5",
reference_spectra_path=REFERENCE_SPECTRA_PATH,
):
print("Start comparison of spectra...")
# Create a temporary directory using the context manager
with tempfile.TemporaryDirectory() as tmpdirname:
print("Created temporary directory", tmpdirname)
os.chdir(tmpdirname)
print("Current working dir:", os.getcwd())
path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
print(f"{path = }")
cmd = os.path.join(path[:-19], script_file)
print("Run command:", cmd)
print("Use command argument:", script_argument)
print(f"{script_path = }")
print(f"{script_argument = }")

subprocess.run(args=[cmd, str(script_argument)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
subprocess.run(args=[script_path, str(script_argument)], check=True)

files_and_dirs = os.listdir()
print("Files and folders in temporary folder:", files_and_dirs)
assert os.path.isfile("spectra.h5")
assert os.path.isfile(reference_spectra_path), reference_spectra_path
# Open spectra file and the reference spectra file
file_handle = h5py.File("spectra.h5", "r")
ref_file_handle = h5py.File(os.path.join(path, reference_file), "r")
# Compare file contents
for key in ref_file_handle:
print("Compare dataset:", key)
x = file_handle[key][()]
x_ref = ref_file_handle[key][()]
abs_diff = np.abs(x - x_ref)
i = np.argmax(abs_diff)
print("Max abs diff:", np.ravel(abs_diff)[i])
print("Reference value at max diff:", np.ravel(x_ref)[i])
np.testing.assert_allclose(x, x_ref, atol=3e-2)
np.testing.assert_allclose(x, x_ref, atol=2e-2, rtol=0.1)
print("Mean abs diff:", np.mean(abs_diff))
assert math.isclose(np.mean(abs_diff), 0, abs_tol=2e-5)
print("Median abs diff:", np.median(abs_diff))
assert math.isclose(np.median(abs_diff), 0, abs_tol=1e-8)
with h5py.File("spectra.h5", "r") as file_handle, h5py.File(reference_spectra_path, "r") as ref_file_handle:
# Compare file contents
for key in ref_file_handle:
print("Compare dataset:", key)
x = file_handle[key][()]
x_ref = ref_file_handle[key][()]
abs_diff = np.abs(x - x_ref)
i = np.argmax(abs_diff)
print("Reference value at max diff:", np.ravel(x_ref)[i])
np.testing.assert_allclose(x, x_ref, atol=3e-2)
np.testing.assert_allclose(x, x_ref, atol=2e-2, rtol=0.1)
print("Mean abs diff:", np.mean(abs_diff))
assert math.isclose(np.mean(abs_diff), 0, abs_tol=2e-5)
print("Median abs diff:", np.median(abs_diff))
assert math.isclose(np.median(abs_diff), 0, abs_tol=1e-8)
print("Comparison successful")


Expand Down
58 changes: 58 additions & 0 deletions impurityModel/test/test_h0.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import os
from glob import glob

from impurityModel.ed.get_spectra import read_pickled_file

DIR_PATH = os.path.dirname(os.path.realpath(__file__))


def test_read_all_h0_pickle_files():
for h0_filename in glob(os.path.join(DIR_PATH, "../../h0/h0*.pickle")):
h0 = read_pickled_file(h0_filename)

string = os.path.basename(h0_filename).split(".")[0].split("_")[-1].split("bath")[0]
nBaths_tot = sum([int(nbath) for nbath in string.split("p")])
# So far, in all the non-interacting Hamiltonians the angular momentum is equal to two
# for the correlated orbitals that are coupled to the bath states.
nBaths = {2: nBaths_tot}

sanity_check_non_interacting_hamiltonian(h0, nBaths)


def sanity_check_non_interacting_hamiltonian(h0: dict[tuple, complex], nBaths: dict[int, int]):
"""
Sanity check non-interacting Hamiltonian operator.

Parameters
-------
h0:
Non-interacting Hamiltonian operator.
Describes impurity orbitals and bath orbitals.
Each tuple key describes a process of two steps: annihilation followed by creation.
Each step is described by a tuple of the form:
(spin_orb, 'c') for creation, and
(spin_orb, 'a') for annihilation,
where spin_orb is a tuple of the form (l, s, m) or (l, b) or ((l_a, l_b), b).
nBaths:
angular momentum: number of bath states coupled to the correlated orbitals with this angular momentum.
"""
for process, value in h0.items():
assert isinstance(value, complex)
assert len(process) == 2 # two events in non-interacting Hamiltonian
assert process[1][1] == "a" # First event is annihilation
assert process[0][1] == "c" # Second event is creation
for event in process[::-1]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to check events in any particular order.

Suggested change
for event in process[::-1]:
for event in process:

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order does not matter in this for-loop. But when a process is used for real, i.e. applied on a product state, the order matters.

The order is chosen such that $c_i^\dagger c_j \ket{\Psi}$ is implemented as process ((i, 'c'), (j, 'a')) operating on the state $\ket{\Psi}$ (with 'c' denoting creation and 'a' annihilation). So the right-most "event" is first applied, and finally the left-most "event", just like the math expression.
Relevant documentation e.g. https://github.com/JohanSchott/impurityModel/blob/master/impurityModel/ed/finite.py#L1320
https://github.com/JohanSchott/impurityModel/blob/master/impurityModel/ed/finite.py#L1395

And in the same way is the Coulomb interaction process between two electrons:
$c_i^\dagger c_j^\dagger c_k c_l$ implemented as ((i, 'c'), (j, 'c'), (k, 'a'), (l, 'a'))
https://github.com/JohanSchott/impurityModel/blob/master/impurityModel/ed/finite.py#L1322

Because of this I think it might be good to consistently loop over events "from right to left" in this repo.

assert len(event) == 2 # spin-orbit and create or remove
spin_orbit_info = event[0]
if len(spin_orbit_info) == 2:
l, bath_index = spin_orbit_info
assert 0 <= l <= 3
assert 0 <= bath_index < nBaths[l]
elif len(spin_orbit_info) == 3:
l, s, m = spin_orbit_info
assert l in nBaths
assert 0 <= l <= 3
assert s in (0, 1)
assert m in range(-l, l + 1)
else:
raise ValueError(f"{spin_orbit_info}")
6 changes: 4 additions & 2 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[pytest]
testpaths = impurityModel

# Test test_comparison_with_reference.py in a separate pytest call since it starts MPI processes in a subprocess.run, and
# MPI can't handle that both the parent and the child process use MPI.
addopts = --ignore impurityModel/test/test_comparison_with_reference.py

filterwarnings =
error
filterwarnings = error
5 changes: 3 additions & 2 deletions requirements-ubuntu.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
build-essential
gfortran
openmpi-bin
libopenmpi-dev
python3
python3-dev
python3-venv
python3-mpi4py
openmpi-bin
libopenmpi-dev
2 changes: 1 addition & 1 deletion scripts/run_Ni_NiO_Xbath.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ echo "Number of bath states: $nBath3d"
echo "H0 filename: $h0_filename"
echo "Radial wavefunction filename: $radial_filename"

mpirun -n $ranks python -m impurityModel.ed.get_spectra $h0_filename $radial_filename --nBaths 0 $nBath3d --nValBaths 0 $nBath3d
mpiexec -n $ranks --verbose python -m impurityModel.ed.get_spectra $h0_filename $radial_filename --nBaths 0 $nBath3d --nValBaths 0 $nBath3d
Loading