diff --git a/pyproject.toml b/pyproject.toml index 0fda2989..eaf3c396 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,8 +22,8 @@ authors = [{ name = "Matthew McDermott", email = "mcdermott@berkeley.edu" }] dynamic = ["version"] classifiers = [ "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", @@ -32,9 +32,9 @@ classifiers = [ "Topic :: Scientific/Engineering :: Chemistry", "Topic :: Software Development :: Libraries :: Python Modules", ] -requires-python = ">=3.10" +requires-python = ">=3.11" dependencies = [ - "pymatgen>=2024.11.13", + "pymatgen>=2026.5.4", "numba>=0.60.0", "jobflow>=0.1.18", "ray>=2.36.0", @@ -53,13 +53,13 @@ docs = [ "sphinx==7.2.6", ] tests = [ - "mp-api==0.45.0", # required for testing get_entry_set job + "mp-api>=0.45.0", "pytest==8.3.3", "pytest-cov==5.0.0", "pytest-xdist==3.6.1", ] strict = [ - "pymatgen==2024.11.13", + "pymatgen==2026.5.4", "numba==0.60.0", "jobflow==0.1.18", "ray==2.36.0", @@ -97,7 +97,7 @@ omit = [ ] [tool.ruff] -target-version = "py310" +target-version = "py311" line-length = 120 extend-exclude = ["*.ipynb", "tests/**"] diff --git a/src/rxn_network/entries/entry_set.py b/src/rxn_network/entries/entry_set.py index 1e680e0e..b4528191 100644 --- a/src/rxn_network/entries/entry_set.py +++ b/src/rxn_network/entries/entry_set.py @@ -299,8 +299,12 @@ def get_entries_with_jitter(self) -> GibbsEntrySet: for idx, entry in enumerate(entries): if entry.is_element: continue + # Handle nan uncertainty (pymatgen returns nan when there are no energy adjustments) + uncertainty = entry.correction_uncertainty + if np.isnan(uncertainty): + uncertainty = 0.0 adj = ConstantEnergyAdjustment( - value=jitter[idx] * entry.correction_uncertainty, + value=jitter[idx] * uncertainty, name="Random jitter", description=("Randomly sampled (Gaussian) noise to account for uncertainty in data"), ) diff --git a/src/rxn_network/network/network.py b/src/rxn_network/network/network.py index 73a6833c..a4e7ffac 100644 --- a/src/rxn_network/network/network.py +++ b/src/rxn_network/network/network.py @@ -384,17 +384,17 @@ def get_edge_weight_with_cf(edge_obj): g = g.copy() - path = rx.dijkstra_shortest_paths( # type: ignore + shortest_paths = rx.dijkstra_shortest_paths( g, precursors_node, target_node, weight_fn=get_edge_weight_with_cf ) - if not path: + if not shortest_paths: return [] - path = list(path[target_node]) + first_path: list[int] = list(shortest_paths[target_node]) - a = [path] - a_costs = [path_cost(path)] + a: list[list[int]] = [first_path] + a_costs = [path_cost(first_path)] b = PriorityQueue() # type: ignore diff --git a/src/rxn_network/reactions/computed.py b/src/rxn_network/reactions/computed.py index 6c5df92e..0b2a2a16 100644 --- a/src/rxn_network/reactions/computed.py +++ b/src/rxn_network/reactions/computed.py @@ -137,7 +137,11 @@ def energy_uncertainty(self) -> float: for entry in self._entries: (comp, factor) = entry.composition.get_reduced_composition_and_factor() - energy_ufloat = ufloat(entry.energy, entry.correction_uncertainty) + # Handle nan uncertainty (pymatgen returns nan when there are no energy adjustments) + uncertainty = entry.correction_uncertainty + if np.isnan(uncertainty): + uncertainty = 0.0 + energy_ufloat = ufloat(entry.energy, uncertainty) calc_energies[comp] = min(calc_energies.get(comp, float("inf")), energy_ufloat / factor) energy_with_uncertainty = sum( diff --git a/tests/entries/test_entry_set.py b/tests/entries/test_entry_set.py index f1f3d722..bb9b1947 100644 --- a/tests/entries/test_entry_set.py +++ b/tests/entries/test_entry_set.py @@ -2,6 +2,7 @@ from copy import deepcopy +import numpy as np import pytest from pymatgen.analysis.phase_diagram import PhaseDiagram from pymatgen.entries.computed_entries import ConstantEnergyAdjustment @@ -120,6 +121,35 @@ def test_get_entries_with_jitter(gibbs_entries): assert new_ent.energy != pytest.approx(old_ent.energy) +def test_get_entries_with_jitter_nan_uncertainty(gibbs_entries): + """Test that get_entries_with_jitter handles entries with nan correction_uncertainty. + + pymatgen returns nan for correction_uncertainty when there are no energy adjustments. + This test ensures the jitter calculation doesn't produce nan values. + """ + # Create a copy of entries and clear their energy adjustments to trigger nan uncertainty + entries_no_adjustments = [] + for entry in gibbs_entries: + entry_copy = entry.copy() + entry_copy.energy_adjustments.clear() + entries_no_adjustments.append(entry_copy) + + entry_set = GibbsEntrySet(entries_no_adjustments) + + # Verify that entries now have nan correction_uncertainty + for entry in entry_set: + if not entry.is_element: + assert np.isnan(entry.correction_uncertainty), ( + f"Expected nan correction_uncertainty for {entry.composition}" + ) + + new_entries = entry_set.get_entries_with_jitter() + + # Ensure no nan energies were produced + for entry in new_entries: + assert not np.isnan(entry.energy), f"Got nan energy for {entry.composition}" + + def test_get_adjusted_entry(interpolated_entry): entry_copy = deepcopy(interpolated_entry) entry_copy.energy_adjustments.append(ConstantEnergyAdjustment(0.1)) diff --git a/tests/entries/test_nist.py b/tests/entries/test_nist.py index 81ba2bb7..28f3a032 100644 --- a/tests/entries/test_nist.py +++ b/tests/entries/test_nist.py @@ -60,14 +60,6 @@ def test_energy_per_atom(entries): assert actual_energies == pytest.approx(expected_energies) -def test_correction_uncertainty(entries): - assert all(e.correction_uncertainty == 0 for e in entries.values()) - - -def test_correction_uncertainty_per_atom(entries): - assert all(e.correction_uncertainty_per_atom == 0 for e in entries.values()) - - def test_is_experimental(entries): assert all(e.is_experimental for e in entries.values())