"""Class for intepolated entries."""
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy as np
from pymatgen.analysis.phase_diagram import GrandPotPDEntry
from pymatgen.entries.computed_entries import ComputedEntry
from rxn_network.core import Composition
from rxn_network.utils.funcs import get_logger
logger = get_logger(__name__)
if TYPE_CHECKING:
from pymatgen.core.periodic_table import Element
[docs]
class InterpolatedEntry(ComputedEntry):
"""Lightweight Entry object for computed data. Contains facilities
for applying corrections to the energy attribute and for storing
calculation parameters.
"""
def __init__(
self,
composition: Composition,
energy: float,
correction: float = 0.0,
energy_adjustments: list | None = None,
parameters: dict | None = None,
data: dict | None = None,
entry_id: object | None = None,
):
"""
Args:
composition: Composition of the entry. For flexibility, this can take the form of all the typical input
taken by a Composition, including a {symbol: amt} dict, a string formula, and others.
energy: Energy of the entry. Usually the final calculated
energy from VASP or other electronic structure codes.
correction: Manually set an energy correction, will ignore
energy_adjustments if specified. Defaults to 0.
energy_adjustments: An optional list of EnergyAdjustment to
be applied to the energy. This is used to modify the energy for certain
analyses. Defaults to None.
parameters: An optional dict of parameters associated with
the entry. Defaults to None.
data: An optional dict of any additional data associated
with the entry. Defaults to None.
entry_id: An optional id to uniquely identify the entry.
"""
composition = Composition(composition)
if entry_id is None:
entry_id = f"{self.__class__.__name__}-{composition.formula}"
super().__init__(
composition,
energy,
correction=correction,
energy_adjustments=energy_adjustments,
parameters=parameters,
data=data,
entry_id=entry_id,
)
[docs]
def to_grand_entry(self, chempots: dict[Element, float]) -> GrandPotPDEntry:
"""Convert a GibbsComputedEntry to a GrandComputedEntry.
Args:
chempots: A dictionary of {element: chempot} pairs.
Returns:
A GrandComputedEntry.
"""
return GrandPotPDEntry(self, chempots)
[docs]
def get_new_temperature(self, new_temperature: float) -> InterpolatedEntry:
"""Return a copy of the InterpolatedEntry at the new specified temperature.
WARNING: This is not possible for interpolated entries. Instead, this returns a copy of the original entry.
Args:
new_temperature: The new temperature to use [K]
Returns:
A copy of the entry.
"""
_ = new_temperature
logger.warning(
"It is not possible to get a new temperature for interpolated entries"
"(one must recalculate from the phase diagram). Instead, this returns a copy of the opriginal entry."
)
return self.copy()
@property
def unique_id(self) -> str:
"""Returns a unique ID for the entry."""
return self.entry_id
@property
def is_experimental(self) -> bool:
"""Returns True by default."""
return False
def __repr__(self):
output = [
(f"InterpolatedEntry | {self.composition.formula} ({self.composition.reduced_formula})"),
f"Energy = {self.energy:.4f}",
]
return "\n".join(output)
def __eq__(self, other) -> bool:
if type(other) is not type(self):
return False
if not np.isclose(self.energy, other.energy):
return False
if getattr(self, "entry_id", None) and getattr(other, "entry_id", None):
return self.entry_id == other.entry_id
if self.composition != other.composition:
return False
return True
def __hash__(self):
return hash(
(
self.composition,
self.energy,
self.entry_id,
)
)