diff --git a/express/properties/non_scalar/formation_energy_references.py b/express/properties/non_scalar/formation_energy_references.py new file mode 100644 index 00000000..ad2e4793 --- /dev/null +++ b/express/properties/non_scalar/formation_energy_references.py @@ -0,0 +1,15 @@ +from typing import Any + +from express.properties.non_scalar import NonScalarProperty + + +class FormationEnergyReferencesFromContext(NonScalarProperty): + def __init__(self, name, parser, value: Any, *args, **kwargs): + super().__init__(name, parser, *args, **kwargs) + self.value = value + + def _serialize(self): + return { + "name": self.name, + "value": self.value, + } diff --git a/express/settings.py b/express/settings.py index 7b12344c..6b5a845e 100644 --- a/express/settings.py +++ b/express/settings.py @@ -19,6 +19,7 @@ "reference": "express.properties.scalar.thermal_correction_to_enthalpy.ThermalCorrectionToEnthalpy" }, "surface_energy": {"reference": "express.properties.scalar.scalar_property_context.ScalarPropertyFromContext"}, + "formation_energy": {"reference": "express.properties.scalar.scalar_property_context.ScalarPropertyFromContext"}, "reaction_energy_barrier": {"reference": "express.properties.scalar.reaction_energy_barrier.ReactionEnergyBarrier"}, "valence_band_offset": {"reference": "express.properties.scalar.scalar_property_context.ScalarPropertyFromContext"}, } @@ -60,6 +61,9 @@ "reference": "express.properties.non_scalar.two_dimensional_plot.average_potential_profile.AveragePotentialProfile" # noqa: E501 }, "dielectric_tensor": {"reference": "express.properties.non_scalar.dielectric_tensor.DielectricTensor"}, + "formation_energy_references": { + "reference": "express.properties.non_scalar.formation_energy_references.FormationEnergyReferencesFromContext" + }, "hubbard_u": {"reference": "express.properties.non_scalar.hubbard_u.HubbardU"}, "hubbard_v": {"reference": "express.properties.non_scalar.hubbard_v.HubbardV"}, "hubbard_v_nn": {"reference": "express.properties.non_scalar.hubbard_v_nn.HubbardV_NN"}, diff --git a/pyproject.toml b/pyproject.toml index cd333d3b..5831df8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ classifiers = [ dependencies = [ "pymatgen>=2023.8.10", "ase>=3.17.0", - "mat3ra-esse>=2026.3.25.post0", + "mat3ra-esse @ git+https://github.com/Exabyte-io/esse.git@9d9ab4b9e3b62c44270dc390bc339052d973696e", "jarvis-tools>=2023.12.12", # To avoid module 'numpy.linalg._umath_linalg' has no attribute '_ilp64' in Colab "numpy>=1.24.4,<2", diff --git a/tests/unit/properties/non_scalar/test_formation_energy_references.py b/tests/unit/properties/non_scalar/test_formation_energy_references.py new file mode 100644 index 00000000..0791c4db --- /dev/null +++ b/tests/unit/properties/non_scalar/test_formation_energy_references.py @@ -0,0 +1,29 @@ +from tests.unit import UnitTestBase +from express.properties.non_scalar.formation_energy_references import FormationEnergyReferencesFromContext + +COMPOUND_TOTAL_ENERGY = -522.232 +COMPOUND_N_ATOMS = 4 +ROWS = [ + { + "label": "SiC", + "total_energy": COMPOUND_TOTAL_ENERGY, + "n_atoms": COMPOUND_N_ATOMS, + "total_energy_per_atom": COMPOUND_TOTAL_ENERGY / COMPOUND_N_ATOMS, + "precision_value": 10, + "precision_metric": "KPPRA", + } +] +EXPECTED = { + "name": "formation_energy_references", + "value": {"rows": ROWS}, +} + + +class FormationEnergyReferencesTest(UnitTestBase): + def test_formation_energy_references(self): + property_ = FormationEnergyReferencesFromContext( + "formation_energy_references", + None, + value={"rows": ROWS}, + ) + self.assertDeepAlmostEqual(property_.serialize_and_validate(), EXPECTED) diff --git a/tests/unit/properties/scalar/test_formation_energy.py b/tests/unit/properties/scalar/test_formation_energy.py new file mode 100644 index 00000000..f7f97b75 --- /dev/null +++ b/tests/unit/properties/scalar/test_formation_energy.py @@ -0,0 +1,27 @@ +import unittest + +from mat3ra.esse import ESSE + +from tests.unit import UnitTestBase +from express.properties.scalar.scalar_property_context import ScalarPropertyFromContext + +FORMATION_ENERGY = {"units": "eV/atom", "name": "formation_energy", "value": -0.123} +FORMATION_ENERGY_VALUE = -0.123 +FORMATION_ENERGY_MANIFEST = ESSE().get_property_manifest("formation_energy") + + +@unittest.skipUnless( + FORMATION_ENERGY_MANIFEST.get("defaults", {}).get("units"), + "formation_energy manifest defaults require a newer mat3ra-esse release", +) +class FormationEnergyTest(UnitTestBase): + def setUp(self): + super().setUp() + + def tearDown(self): + super().tearDown() + + def test_formation_energy(self): + parser = self.get_mocked_parser("formation_energy", FORMATION_ENERGY_VALUE) # noqa : F841 + property_ = ScalarPropertyFromContext("formation_energy", None, value=FORMATION_ENERGY_VALUE) + self.assertDeepAlmostEqual(property_.serialize_and_validate(), FORMATION_ENERGY)