Skip to content

Commit

Permalink
Some tests updates
Browse files Browse the repository at this point in the history
  • Loading branch information
kavanase committed Aug 16, 2024
1 parent b37f46e commit 9d3a7cc
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 146 deletions.
4 changes: 3 additions & 1 deletion doped/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1394,7 +1394,9 @@ def _no_chempots_warning(property="Formation energies (and concentrations)"):
)


def _get_dft_chempots(chempots, el_refs, limit):
def _get_dft_chempots(
chempots: Optional[dict], el_refs: Optional[dict] = None, limit: Optional[str] = None
):
"""
Parse the DFT chempots from the input chempots and limit.
"""
Expand Down
35 changes: 27 additions & 8 deletions doped/interface/fermi_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import numpy as np
import pandas as pd
from monty.json import MSONable
from pymatgen.core.periodic_table import Element
from pymatgen.electronic_structure.dos import FermiDos, Spin
from pymatgen.io.vasp import Vasprun
from scipy.interpolate import griddata
Expand Down Expand Up @@ -1605,7 +1606,9 @@ def scan_chemical_potential_grid(
return pd.concat(
[
self.pseudo_equilibrium_solve(
single_chempot_dict=chempot_series.to_dict(),
single_chempot_dict={
k.replace("μ_", ""): v for k, v in chempot_series.to_dict().items()
},
el_refs=el_refs,
annealing_temperature=annealing_temperature,
quenched_temperature=quenched_temperature,
Expand All @@ -1620,7 +1623,9 @@ def scan_chemical_potential_grid(
return pd.concat(
[
self.equilibrium_solve(
single_chempot_dict=chempot_series.to_dict(),
single_chempot_dict={
k.replace("μ_", ""): v for k, v in chempot_series.to_dict().items()
},
el_refs=el_refs,
temperature=temperature,
effective_dopant_concentration=effective_dopant_concentration,
Expand Down Expand Up @@ -1786,14 +1791,17 @@ def min_max_X(
starting_grid = ChemicalPotentialGrid(chempots)
current_vertices = starting_grid.vertices
chempots_labels = list(current_vertices.columns)
print(current_vertices, chempots_labels)
previous_value = None

while True:
if annealing_temperature is not None:
results_df = pd.concat(
[
self.pseudo_equilibrium_solve(
single_chempot_dict=chempot_series.to_dict(),
single_chempot_dict={
k.replace("μ_", ""): v for k, v in chempot_series.to_dict().items()
},
el_refs=el_refs,
annealing_temperature=annealing_temperature,
quenched_temperature=quenched_temperature,
Expand All @@ -1808,7 +1816,9 @@ def min_max_X(
results_df = pd.concat(
[
self.equilibrium_solve(
single_chempot_dict=chempot_series.to_dict(),
single_chempot_dict={
k.replace("μ_", ""): v for k, v in chempot_series.to_dict().items()
},
el_refs=el_refs,
temperature=temperature,
effective_dopant_concentration=effective_dopant_concentration,
Expand Down Expand Up @@ -2151,10 +2161,17 @@ def __init__(self, chempots: dict[str, Any]):
chemical potentials `with respect to the elemental reference
energies` will be used (i.e. ``chempots["limits_wrt_el_refs"]``)!
"""
if "limits_wrt_el_refs" in chempots:
self.vertices = pd.DataFrame.from_dict(chempots["limits_wrt_el_refs"], orient="index")
else:
self.vertices = pd.DataFrame.from_dict(chempots, orient="index")
unformatted_chempots_dict = chempots.get("limits_wrt_el_refs", chempots)
test_elt = Element("H")
formatted_chempots_dict = {
limit: {
f"μ_{k}" if test_elt.is_valid_symbol(k) else k: v
for (k, v) in unformatted_chempots_subdict.items()
}
for limit, unformatted_chempots_subdict in unformatted_chempots_dict.items()
}

self.vertices = pd.DataFrame.from_dict(formatted_chempots_dict, orient="index")

def get_grid(self, n_points: int = 100) -> pd.DataFrame:
"""
Expand Down Expand Up @@ -2222,6 +2239,8 @@ def grid_from_dataframe(mu_dataframe: pd.DataFrame, n_points: int = 100) -> pd.D
complex_num = complex(0, n_points)

# Get the convex hull of the vertices
print(independent_vars)
print(independent_vars.values)
hull = ConvexHull(independent_vars.values)

# Create a dense grid that covers the entire range of the vertices
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ Repository = "https://github.com/SMTG-Bham/doped"
[project.optional-dependencies]
tests = [
"pytest<8.2", # with pytest==8.2.0, seemed to cause memory issue on GH Actions mpl tests, python=3.10
"pytest-mpl>=0.16.1"
"pytest-mpl>=0.16.1",
"py-sc-fermi"
]
docs = ["sphinx", "sphinx-book-theme", "sphinx_design"]
analysis = [
Expand Down
190 changes: 54 additions & 136 deletions tests/test_interface_fermi_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@
from monty.serialization import loadfn
from pymatgen.electronic_structure.dos import FermiDos

from doped.interface.fermi_solver import (
ChemicalPotentialGrid,
FermiSolver,
FermiSolverDoped,
FermiSolverPyScFermi,
)
from doped.interface.fermi_solver import ChemicalPotentialGrid, FermiSolver

py_sc_fermi_installed = bool(importlib.util.find_spec("py_sc_fermi"))


# TODO: Implement double tests for each (applicable) case with doped and py-sc-fermi backends
# as with new and legacy MP API tests in test_chemical_potentials.py (`develop` branch)


class FermiSolverTestCase(unittest.TestCase):
def setUp(self):
self.thermo_path = "../examples/CdTe/CdTe_LZ_thermo_wout_meta.json.gz"
Expand Down Expand Up @@ -64,7 +63,7 @@ def test_assert_scan_temperature_raises(self):
chempots={},
temperature_range=[1, 2, 3],
annealing_temperature_range=[1, 2, 3],
quenching_temperature_range=None,
quenched_temperature_range=None,
)
print(exc.value) # for debugging

Expand All @@ -73,7 +72,7 @@ def test_assert_scan_temperature_raises(self):
chempots={},
temperature_range=[1, 2, 3],
annealing_temperature_range=None,
quenching_temperature_range=[1, 2, 3],
quenched_temperature_range=[1, 2, 3],
)
print(exc.value) # for debugging

Expand All @@ -82,7 +81,7 @@ def test_assert_scan_temperature_raises(self):
chempots={},
temperature_range=[],
annealing_temperature_range=None,
quenching_temperature_range=None,
quenched_temperature_range=None,
)
print(exc.value) # for debugging

Expand All @@ -92,7 +91,7 @@ def test_assert_scan_temperature_raises(self):
chempots=None,
temperature_range=None,
annealing_temperature_range=[],
quenching_temperature_range=None,
quenched_temperature_range=None,
)
print(exc.value)

Expand Down Expand Up @@ -152,9 +151,7 @@ def test__add_effective_dopant_concentration_and_solve(self):
"Temperature": [300],
},
):
results = self.fs._add_effective_dopant_concentration_and_solve(
{}, effective_dopant_concentration=-1, temperature=1
)
results = self.fs.equilibrium_solve({}, effective_dopant_concentration=-1, temperature=1)
assert results["Dopant (cm^-3)"] == 1

def test__add_effective_dopant_concentration_and_solve_raises(self):
Expand Down Expand Up @@ -210,7 +207,7 @@ def setUp(self):
self.thermo_path = "../examples/CdTe/CdTe_LZ_thermo_wout_meta.json.gz"
self.bulk_dos_vr_path = "../examples/CdTe/CdTe_prim_k181818_NKRED_2_vasprun.xml.gz"
self.thermo = loadfn(self.thermo_path)
self.fs = FermiSolverDoped(self.thermo, self.bulk_dos_vr_path)
self.fs = FermiSolver(self.thermo, self.bulk_dos_vr_path, backend="doped") # default

def test__init__(self):
assert self.fs.defect_thermodynamics == self.thermo
Expand Down Expand Up @@ -260,7 +257,7 @@ def setUp(self):
self.thermo_path = "../examples/CdTe/CdTe_LZ_thermo_wout_meta.json.gz"
self.bulk_dos_vr_path = "../examples/CdTe/CdTe_prim_k181818_NKRED_2_vasprun.xml.gz"
self.thermo = loadfn(self.thermo_path)
self.fs = FermiSolverPyScFermi(self.thermo, self.bulk_dos_vr_path, multiplicity_scaling=32)
self.fs = FermiSolver(self.thermo, self.bulk_dos_vr_path, backend="py-sc-fermi")

def test__init__(self):
assert self.fs.defect_thermodynamics == self.thermo
Expand Down Expand Up @@ -343,13 +340,13 @@ class FermiSolver3DTestCase(unittest.TestCase):
def setUp(self):
self.thermo_path = loadfn("../examples/Cu2SiSe3/Cu2SiSe3_thermo.json")
self.bulk_dos_path = "../examples/Cu2SiSe3/vasprun.xml.gz"
self.fs = FermiSolverDoped(self.thermo_path, self.bulk_dos_path)
self.py_fs = FermiSolverPyScFermi(self.thermo_path, self.bulk_dos_path)
self.fs = FermiSolver(self.thermo_path, self.bulk_dos_path) # doped is default backend
self.py_fs = FermiSolver(self.thermo_path, self.bulk_dos_path, backend="py-sc-fermi")

def test_scan_chemical_potential_grid(self):

results = self.fs.scan_chemical_potential_grid(
n_points=5, annealing_temperature=1000, quenching_temperature=300
n_points=5, annealing_temperature=1000, quenched_temperature=300
)
assert len(results) == 156
assert np.isclose(max(results["Cu"]), 0.0)
Expand All @@ -362,132 +359,53 @@ def test_scan_chemical_potential_grid(self):
assert np.isclose(min(results["Fermi Level"]), -0.074598, rtol=1e-4)

def test_min_max_X(self):

results = self.fs.min_max_X(
target="Electrons (cm^-3)",
min_or_max="max",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], 0.0)

results = self.fs.min_max_X(
target="Electrons (cm^-3)",
min_or_max="min",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], -0.46355805460937427)

results = self.fs.min_max_X(
target="Holes (cm^-3)",
min_or_max="max",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], -0.46355805460937427)

results = self.fs.min_max_X(
target="Holes (cm^-3)",
min_or_max="min",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], 0)

results = self.py_fs.min_max_X(
target="v_Se",
min_or_max="max",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Se"][0], -0.758105, rtol=1e-4)
for target, min_or_max, element, expected in [
("Electrons (cm^-3)", "max", "μ_Cu", 0.0),
("Electrons (cm^-3)", "min", "μ_Cu", -0.46355805460937427),
("Holes (cm^-3)", "max", "μ_Cu", -0.46355805460937427),
("Holes (cm^-3)", "min", "μ_Cu", 0),
("v_Se", "max", "μ_Se", -0.758105),
]:
results = self.fs.min_max_X(
target=target,
min_or_max=min_or_max,
tolerance=0.001,
annealing_temperature=1000,
quenched_temperature=300,
n_points=5,
)
assert np.isclose(results[element][0], expected, rtol=1e-4)

@unittest.skipIf(not py_sc_fermi_installed, "py_sc_fermi is not installed")
def test_min_max_X_pyscf(self):

results = self.py_fs.min_max_X(
target="Electrons (cm^-3)",
min_or_max="max",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], 0.0)

results = self.py_fs.min_max_X(
target="Electrons (cm^-3)",
min_or_max="min",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], -0.46355805460937427, rtol=1e-5)

results = self.py_fs.min_max_X(
target="Holes (cm^-3)",
min_or_max="max",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], -0.46355805460937427)

results = self.py_fs.min_max_X(
target="Holes (cm^-3)",
min_or_max="min",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Cu"][0], 0)

results = self.py_fs.min_max_X(
target="v_Se",
min_or_max="max",
tolerance=0.001,
annealing_temperature=1000,
quenching_temperature=300,
n_points=5,
processes=1,
)
assert np.isclose(results["Se"][0], -0.758105, rtol=1e-4)
for target, min_or_max, element, expected in [
("Electrons (cm^-3)", "max", "μ_Cu", 0.0),
("Electrons (cm^-3)", "min", "μ_Cu", -0.46355805460937427),
("Holes (cm^-3)", "max", "μ_Cu", -0.46355805460937427),
("Holes (cm^-3)", "min", "μ_Cu", 0),
("v_Se", "max", "μ_Se", -0.758105),
]:
results = self.py_fs.min_max_X(
target=target,
min_or_max=min_or_max,
tolerance=0.001,
annealing_temperature=1000,
quenched_temperature=300,
n_points=5,
)
assert np.isclose(results[element][0], expected, rtol=1e-4)

@unittest.skipIf(not py_sc_fermi_installed, "py_sc_fermi is not installed")
def test_scan_chemical_potential_grid_pyscf(self):

results = self.py_fs.scan_chemical_potential_grid(
n_points=5, annealing_temperature=1000, quenching_temperature=300
n_points=5, annealing_temperature=1000, quenched_temperature=300
)
assert len(results) == 156
assert np.isclose(max(results["Cu"]), 0.0)
assert np.isclose(max(results["Si"]), -0.077858, rtol=1e-5)
assert np.isclose(max(results["Se"]), 0.0)
assert np.isclose(min(results["Cu"]), -0.463558, rtol=1e-5)
assert np.isclose(min(results["Si"]), -1.708951, rtol=1e-5)
assert np.isclose(min(results["Se"]), -0.758105, rtol=1e-5)
assert np.isclose(max(results["μ_Cu"]), 0.0)
assert np.isclose(max(results["μ_Si"]), -0.077858, rtol=1e-5)
assert np.isclose(max(results["μ_Se"]), 0.0)
assert np.isclose(min(results["μ_Cu"]), -0.463558, rtol=1e-5)
assert np.isclose(min(results["μ_Si"]), -1.708951, rtol=1e-5)
assert np.isclose(min(results["μ_Se"]), -0.758105, rtol=1e-5)
assert np.isclose(max(results["Fermi Level"]), 0.0155690, rtol=1e-4)
assert np.isclose(min(results["Fermi Level"]), -0.07285, rtol=1e-4)

0 comments on commit 9d3a7cc

Please sign in to comment.