diff --git a/src/nomad_simulations/schema_packages/physical_property.py b/src/nomad_simulations/schema_packages/physical_property.py index 92841b97..038ac820 100644 --- a/src/nomad_simulations/schema_packages/physical_property.py +++ b/src/nomad_simulations/schema_packages/physical_property.py @@ -24,6 +24,7 @@ from nomad import utils from nomad.datamodel.data import ArchiveSection from nomad.datamodel.metainfo.basesections import Entity +from nomad.datamodel.metainfo.annotations import ELNAnnotation from nomad.metainfo import ( URL, MEnum, @@ -41,6 +42,7 @@ from nomad_simulations.schema_packages.numerical_settings import SelfConsistency from nomad_simulations.schema_packages.variables import Variables +from nomad_simulations.schema_packages.model_method import ModelMethod # We add `logger` for the `validate_quantity_wrt_value` decorator logger = utils.get_logger(__name__) @@ -324,3 +326,21 @@ def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: # Resolve if the physical property `is_derived` or not from another physical property. self.is_derived = self._is_derived() + +class PropertyContribution(PhysicalProperty): + """ + Abstract physical property section linking a property contribution to a contribution + from some method. + """ + model_method_ref = Quantity( + type=ModelMethod, + description=""" + Reference to the `ModelMethod` section to which the property is linked to. + """, + a_eln=ELNAnnotation(component='ReferenceEditQuantity'), + ) + + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) + if not self.name: + self.name = self.get('model_method_ref').get('name') diff --git a/src/nomad_simulations/schema_packages/properties/__init__.py b/src/nomad_simulations/schema_packages/properties/__init__.py index 90b001f7..b5a9f2e9 100644 --- a/src/nomad_simulations/schema_packages/properties/__init__.py +++ b/src/nomad_simulations/schema_packages/properties/__init__.py @@ -20,14 +20,13 @@ from .band_structure import ElectronicBandStructure, ElectronicEigenvalues from .energies import ( FermiLevel, - ChemicalPotential, TotalEnergy, Energy, ClassicalEnergy, QuantumEnergy, ) from .forces import TotalForce, Force -from .thermodynamics import Temperature +from .thermodynamics import Temperature, ChemicalPotential from .fermi_surface import FermiSurface from .hopping_matrix import CrystalFieldSplitting, HoppingMatrix from .permittivity import Permittivity diff --git a/src/nomad_simulations/schema_packages/properties/energies.py b/src/nomad_simulations/schema_packages/properties/energies.py index 93f4eed1..162d02ce 100644 --- a/src/nomad_simulations/schema_packages/properties/energies.py +++ b/src/nomad_simulations/schema_packages/properties/energies.py @@ -20,60 +20,57 @@ import numpy as np -from nomad.metainfo import Quantity, Section, Context, SubSection, MEnum +from nomad.metainfo import Quantity, Section, Context, SubSection if TYPE_CHECKING: from nomad.metainfo import Section, Context from nomad.datamodel.datamodel import EntryArchive from structlog.stdlib import BoundLogger -from nomad_simulations.schema_packages.physical_property import PhysicalProperty +from nomad_simulations.schema_packages.physical_property import PhysicalProperty, PropertyContribution +################## +# Abstract classes +################## -class FermiLevel(PhysicalProperty): +class BaseEnergy(PhysicalProperty): """ - Energy required to add or extract a charge from a material at zero temperature. It can be also defined as the chemical potential at zero temperature. + Abstract physical property section describing some energy of a (sub)system. """ - # ! implement `iri` and `rank` as part of `m_def = Section()` - - iri = 'http://fairmat-nfdi.eu/taxonomy/FermiLevel' - value = Quantity( type=np.float64, unit='joule', description=""" - The value of the Fermi level. + The value of the energy. """, ) - def __init__( - self, m_def: 'Section' = None, m_context: 'Context' = None, **kwargs - ) -> None: - super().__init__(m_def, m_context, **kwargs) - self.rank = [] - self.name = self.m_def.name - def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: super().normalize(archive, logger) +class EnergyContribution(BaseEnergy, PropertyContribution): + """ + Abstract physical property section linking a property contribution to a contribution + from some method. + """ + + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) + +#################################### +# List of specific energy properties +#################################### -class ChemicalPotential(PhysicalProperty): +class FermiLevel(BaseEnergy): """ - Free energy cost of adding or extracting a particle from a thermodynamic system. + Physical property section describing the Fermi level, i.e., the energy required to add or extract a charge from a material at zero temperature. + It can be also defined as the chemical potential at zero temperature. """ # ! implement `iri` and `rank` as part of `m_def = Section()` - iri = 'http://fairmat-nfdi.eu/taxonomy/ChemicalPotential' - - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the chemical potential. - """, - ) + iri = 'http://fairmat-nfdi.eu/taxonomy/FermiLevel' def __init__( self, m_def: 'Section' = None, m_context: 'Context' = None, **kwargs @@ -85,125 +82,34 @@ def __init__( def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: super().normalize(archive, logger) - -#################################################### -# Abstract energy classes -#################################################### - - -class Energy(PhysicalProperty): - """ - Abstract physical property section describing some energy of a (sub)system. - """ - - type = Quantity( - type=MEnum('classical', 'quantum'), - description=""" - Refers to the method used for calculating the energy. - - Allowed values are: - - | Energy Type | Description | - - | ---------------------- | ----------------------------------------- | - - | `"classical"` | The energy is determined via a classical mechanics formalism. | - - | `"quantum"` | The energy is determined via a quantum mechanics formalism. | - """, - ) - - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the energy. - """, - ) - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ClassicalEnergy(Energy): - """ - Abstract physical property section describing some classical energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - if not self.type: - self.type == 'classical' - elif self.type != 'classical': - logger.error(f'Misidentified type for classical energy.') - - -class QuantumEnergy(Energy): - """ - Abstract physical property section describing some quantum energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - if not self.type: - self.type == 'quantum' - elif self.type != 'quantum': - logger.error(f'Misidentified type for quantum energy.') - - -###################################################### -# List of general energy properties/contributions that -# can have both classical and quantum interpretations -###################################################### - - -class TotalEnergy(Energy): +#! The only issue with this structure is that total energy will never be a sum of its contributions, +#! since kinetic energy lives separately, but I think maybe this is ok? +class TotalEnergy(BaseEnergy): """ Physical property section describing the total energy of a (sub)system. """ - contributions = SubSection(sub_section=Energy.m_def, repeats=True) + contributions = SubSection(sub_section=EnergyContribution.m_def, repeats=True) + + def __init__( + self, m_def: 'Section' = None, m_context: 'Context' = None, **kwargs + ) -> None: + super().__init__(m_def, m_context, **kwargs) + self.name = self.m_def.name def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -class KineticEnergy(Energy): +#? Separate quantities for nuclear and electronic KEs? +class KineticEnergy(BaseEnergy): """ Physical property section describing the kinetic energy of a (sub)system. """ - type = Quantity( - type=MEnum('classical', 'quantum'), - description=""" - Refers to the method used for calculating the kinetic energy. - - Allowed values are: - - | Energy Type | Description | - - | ---------------------- | ----------------------------------------- | - - | `"classical"` | The kinetic energy is calculated directly from - the velocities of particles as KE = /sum_i 1/2 m_i v_i^2, where the sum runs over the number of particles in the system, - m_i is the mass of particle i, and v_i is the velocity of particle i. | - - | `"quantum"` | ... | - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -#################################################### -# List of classical energy contribuions -#################################################### - - -class PotentialEnergy(ClassicalEnergy): +class PotentialEnergy(BaseEnergy): """ Physical property section describing the potential energy of a (sub)system. """ @@ -212,242 +118,27 @@ def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class IntermolecularEnergy(ClassicalEnergy): - """ - Physical property section describing all intramolecular contributions to the potential energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class VDWEnergy(ClassicalEnergy): - """ - Physical property section describing the van der Waals contributions to the potential energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ElectrostaticEnergy(ClassicalEnergy): - """ - Physical property section describing all electrostatic contributions to the potential energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ElectrostaticShortRangeEnergy(ClassicalEnergy): - """ - Physical property section describing short-range electrostatic contributions to the potential energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ElectrostaticLongRangeEnergy(ClassicalEnergy): - """ - Physical property section describing long-range electrostatic contributions to the potential energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class IntramolecularEnergy(ClassicalEnergy): - """ - Physical property section describing all intramolecular contributions to the potential energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class BondEnergy(ClassicalEnergy): - """ - Physical property section describing contributions to the potential energy from bond interactions of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class AngleEnergy(ClassicalEnergy): - """ - Physical property section describing contributions to the potential energy from angle interactions of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class DihedralEnergy(ClassicalEnergy): - """ - Physical property section describing contributions to the potential energy from dihedral interactions of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ImproperDihedralEnergy(ClassicalEnergy): - """ - Physical property section describing contributions to the potential energy from improper dihedral interactions of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ExternalEnergy(ClassicalEnergy): - """ - Physical property section describing contributions to the potential energy from external interactions of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -###################################### -# List of quantum energy contributions -###################################### - - -class ElectronicEnergy(QuantumEnergy): - """ - Physical property section describing the electronic energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -#! allowed_contributions = ['PotKin'] Not sure how to deal with sub-contributions... - I lean towards keeping a flat list but I am not sure of all the usages - - -class ElectronicKineticEnergy(QuantumEnergy): - """ - Physical property section describing the electronic kinetic energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class XCEnergy(QuantumEnergy): - """ - Physical property section describing the exchange-correlation (XC) energy of a (sub)system, - calculated using the functional stored in XC_functional. - """ - - # ! Someone check this description! - # ? Do we really want to specify the method here? This can't be user-defined? - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - +#! I removed all previous contributions associated in some way with terms in the Hamiltonian. +#? Should the remaining contributions below be incorporated into some sort of workflow results if still relevant? -class XCPotentialEnergy(QuantumEnergy): - """ - Physical property section describing the potential energy contribution to the exchange-correlation (XC) energy, - i.e., the integral of the first order derivative of the functional - stored in XC_functional (integral of v_xc*electron_density), i.e., the component - of XC that is in the sum of the eigenvalues. Value associated with the - configuration, should be the most converged value. | - """ - - # ! Someone check this description! - # ? Do we really want to specify the method here? This can't be user-defined? - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -# ? XCCorrelationEnergy? -class CorrelationEnergy(QuantumEnergy): - """ - Physical property section describing the correlation energy of a (sub)system, - calculated using the method described in XC_functional. - """ - # ! Someone check this description! - # ? Do we really want to specify the method here? This can't be user-defined? +# class ZeroTemperatureEnergy(QuantumEnergy): +# """ +# Physical property section describing the total energy of a (sub)system extrapolated to $T=0$, based on a free-electron gas argument. +# """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the correlation energy. - """, - ) +# def normalize(self, archive, logger) -> None: +# super().normalize(archive, logger) - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) +# class ZeroPointEnergy(QuantumEnergy): +# """ +# Physical property section describing the zero-point vibrational energy of a (sub)system, +# calculated using the method described in zero_point_method. +# """ -# ? XCExchangeEnergy? -class ExchangeEnergy(QuantumEnergy): - """ - Physical property section describing the exchange energy of a (sub)system, - calculated using the method described in XC_functional. - """ - - # ! Someone check this description! - # ? Do we really want to specify the method here? This can't be user-defined? - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ZeroTemperatureEnergy(QuantumEnergy): - """ - Physical property section describing the total energy of a (sub)system extrapolated to $T=0$, based on a free-electron gas argument. - """ - - # ! Someone check this description! - # ? Do we really want to specify the method here? This can't be user-defined? - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ZeroPointEnergy(QuantumEnergy): - """ - Physical property section describing the zero-point vibrational energy of a (sub)system, - calculated using the method described in zero_point_method. - """ - - # ! Someone check this description! - # ? Do we really want to specify the method here? This can't be user-defined? - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ElectrostaticEnergy(QuantumEnergy): - """ - Physical property section describing the electrostatic energy (nuclei + electrons) of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class NuclearRepulsionEnergy(QuantumEnergy): - """ - Physical property section describing the nuclear-nuclear repulsion energy of a (sub)system. - """ - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -########################## -# Other / General energies -########################## +# def normalize(self, archive, logger) -> None: +# super().normalize(archive, logger) # madelung = SubSection( @@ -457,14 +148,6 @@ def normalize(self, archive, logger) -> None: # """, # ) -# # TODO I suggest ewald is moved to "long range" under electrostatic->energyentry, unless there is some other usage I am misunderstanding -# ewald = SubSection( -# sub_section=EnergyEntry.m_def, -# description=""" -# Contains the value and information regarding the Ewald energy. -# """, -# ) - # free = SubSection( # sub_section=EnergyEntry.m_def, # description=""" @@ -481,121 +164,3 @@ def normalize(self, archive, logger) -> None: # Hamiltonian matrix. # """, # ) - -# van_der_waals = SubSection( -# sub_section=EnergyEntry.m_def, -# description=""" -# Contains the value and information regarding the Van der Waals energy. A multiple -# occurence is expected when more than one van der Waals methods are defined. The -# van der Waals kind should be specified in Energy.kind -# """, -# ) - -# hartree_fock_x_scaled = SubSection( -# sub_section=EnergyEntry.m_def, -# description=""" -# Scaled exact-exchange energy that depends on the mixing parameter of the -# functional. For example in hybrid functionals, the exchange energy is given as a -# linear combination of exact-energy and exchange energy of an approximate DFT -# functional; the exact exchange energy multiplied by the mixing coefficient of the -# hybrid functional would be stored in this metadata. Defined consistently with -# XC_method. -# """, -# ) - -# ? This is technically NOT redundant with total energy, but I fear that people will use them interchangeably, so we need to be clear about the definitions in any case -# internal = Quantity( -# type=np.dtype(np.float64), -# shape=[], -# unit='joule', -# description=""" -# Value of the internal energy. -# """, -# ) - -# double_counting = SubSection( -# sub_section=EnergyEntry.m_def, -# categories=[FastAccess], -# description=""" -# Double counting correction when performing Hubbard model calculations. -# """, -# ) - -# # TODO remove this should be be entropy.correction -# correction_entropy = SubSection( -# sub_section=EnergyEntry.m_def, -# description=""" -# Entropy correction to the potential energy to compensate for the change in -# occupation so that forces at finite T do not need to keep the change of occupation -# in account. Defined consistently with XC_method. -# """, -# ) - -# # TODO remove this should be in electrostatic.correction -# correction_hartree = SubSection( -# sub_section=EnergyEntry.m_def, -# description=""" -# Correction to the density-density electrostatic energy in the sum of eigenvalues -# (that uses the mixed density on one side), and the fully consistent density- -# density electrostatic energy. Defined consistently with XC_method. -# """, -# ) - -# # TODO remove this should be in xc.correction -# correction_xc = SubSection( -# sub_section=EnergyEntry.m_def, -# description=""" -# Correction to energy_XC. -# """, -# ) - -# # ? Is it ok to store this in outputs and not in workflow? I guess we can ensure in normalization that this is a WorkflowOutput, etc...? -# change = Quantity( -# type=np.dtype(np.float64), -# shape=[], -# unit='joule', -# description=""" -# Stores the change of total energy with respect to the previous step. -# """, -# categories=[ErrorEstimateContribution, EnergyValue], -# ) - -# fermi = Quantity( -# type=np.dtype(np.float64), -# shape=[], -# unit='joule', -# description=""" -# Fermi energy (separates occupied from unoccupied single-particle states) -# """, -# categories=[EnergyTypeReference, EnergyValue], -# ) - -# highest_occupied = Quantity( -# type=np.dtype(np.float64), -# unit='joule', -# shape=[], -# description=""" -# The highest occupied energy. -# """, -# ) - -# lowest_unoccupied = Quantity( -# type=np.dtype(np.float64), -# unit='joule', -# shape=[], -# description=""" -# The lowest unoccupied energy. -# """, -# ) - -# # TODO this should be removed and replaced by correction in EnergyEntry -# current = SubSection( -# sub_section=EnergyEntry.m_def, -# description=""" -# Contains the value and information regarding the energy calculated with -# calculation_method_current. energy_current is equal to energy_total for -# non-perturbative methods. For perturbative methods, energy_current is equal to the -# correction: energy_total minus energy_total of the calculation_to_calculation_ref -# with calculation_to_calculation_kind = starting_point -# """, -# ) diff --git a/src/nomad_simulations/schema_packages/properties/forces.py b/src/nomad_simulations/schema_packages/properties/forces.py index 54a1fe17..4ecf10b7 100644 --- a/src/nomad_simulations/schema_packages/properties/forces.py +++ b/src/nomad_simulations/schema_packages/properties/forces.py @@ -36,27 +36,22 @@ import numpy as np -from nomad.metainfo import Quantity, Section, Context, SubSection, MEnum -from nomad.datamodel.data import ArchiveSection - -from nomad_simulations.physical_property import PhysicalProperty +from nomad.metainfo import Quantity, Section, Context, SubSection +from nomad_simulations.schema_packages.physical_property import PhysicalProperty, PropertyContribution #################################################### # Abstract force classes #################################################### +################## +# Abstract classes +################## -class Force(PhysicalProperty): +class BaseForce(PhysicalProperty): """ - Abstract physical property section describing some energy of a (sub)system. + Abstract physical property section describing some force of a (sub)system. """ - type = Quantity( - type=MEnum('classical', 'quantum'), - description=""" - """, - ) - value = Quantity( type=np.dtype(np.float64), unit='newton', @@ -65,101 +60,62 @@ class Force(PhysicalProperty): """, ) - def normalize(self, archive, logger) -> None: + def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: super().normalize(archive, logger) - -###################################################### -# List of general force properties/contributions that -# can have both classical and quantum interpretations -###################################################### - - -class TotalForce(Force): +class ForceContribution(BaseForce, PropertyContribution): """ - Section containing the total force of a (sub)system. - - Contains the value and information regarding the total forces on the atoms - calculated as minus gradient of energy_total. + Abstract physical property section linking a property contribution to a contribution + from some method. """ - # ! We need to avoid giving the precise method of calculation without also providing context, this is not necessarily true in general! - - contributions = SubSection(sub_section=Force.m_def, repeats=True) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -################################ -# List of Forces Contributions # -################################ +################################### +# List of specific force properties +################################### - -class FreeForce(Force): +class TotalForce(BaseForce): """ - Physical property section describing... - - Contains the value and information regarding the forces on the atoms - corresponding to the minus gradient of energy_free. The (electronic) energy_free - contains the information on the change in (fractional) occupation of the - electronic eigenstates, which are accounted for in the derivatives, yielding a - truly energy-conserved quantity. + Physical property section describing the total force of a (sub)system. """ - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class ZeroTemperatureForce(Force): - """ - Physical property section describing... + contributions = SubSection(sub_section=ForceContribution.m_def, repeats=True) - Contains the value and information regarding the forces on the atoms - corresponding to the minus gradient of energy_T0. - """ + def __init__( + self, m_def: 'Section' = None, m_context: 'Context' = None, **kwargs + ) -> None: + super().__init__(m_def, m_context, **kwargs) + self.name = self.m_def.name def normalize(self, archive, logger) -> None: super().normalize(archive, logger) +#? See questions about corresponding energies +# class FreeForce(Force): +# """ +# Physical property section describing... -class RawForce(Force): - """ - Physical property section describing... +# Contains the value and information regarding the forces on the atoms +# corresponding to the minus gradient of energy_free. The (electronic) energy_free +# contains the information on the change in (fractional) occupation of the +# electronic eigenstates, which are accounted for in the derivatives, yielding a +# truly energy-conserved quantity. +# """ - Value of the forces acting on the atoms **not including** such as fixed atoms, - distances, angles, dihedrals, etc. - """ +# def normalize(self, archive, logger) -> None: +# super().normalize(archive, logger) - # ? This is VERY imprecise, is this used regularly? - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) +# class ZeroTemperatureForce(Force): +# """ +# Physical property section describing... +# Contains the value and information regarding the forces on the atoms +# corresponding to the minus gradient of energy_T0. +# """ -# ? Do we want to support custom contributions? -# contributions = SubSection( -# sub_section=ForcesEntry.m_def, -# description=""" -# Contains other forces contributions to the total atomic forces not already -# defined. -# """, -# repeats=True, -# ) - -# types = SubSection( -# sub_section=ForcesEntry.m_def, -# description=""" -# Contains other types of forces not already defined. -# """, -# repeats=True, -# ) - - -# Old version of the Forces description -# Value of the forces acting on the atoms. This is calculated as minus gradient of -# the corresponding energy type or contribution **including** constraints, if -# present. The derivatives with respect to displacements of nuclei are evaluated in -# Cartesian coordinates. In addition, these are obtained by filtering out the -# unitary transformations (center-of-mass translations and rigid rotations for -# non-periodic systems, see value_raw for the unfiltered counterpart). +# def normalize(self, archive, logger) -> None: +# super().normalize(archive, logger) diff --git a/src/nomad_simulations/schema_packages/properties/thermodynamics.py b/src/nomad_simulations/schema_packages/properties/thermodynamics.py index 7ac8a38b..8275f71a 100644 --- a/src/nomad_simulations/schema_packages/properties/thermodynamics.py +++ b/src/nomad_simulations/schema_packages/properties/thermodynamics.py @@ -36,22 +36,15 @@ import numpy as np from nomad.metainfo import Quantity, SubSection, MEnum -from nomad_simulations.physical_property import PhysicalProperty +from nomad_simulations.schema_packages.physical_property import PhysicalProperty +from nomad_simulations.schema_packages.properties import Energy -class Enthalpy(PhysicalProperty): +class Enthalpy(Energy): """ Physical property section describing the enthalpy (i.e. energy_total + pressure * volume.) of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the enthalpy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) @@ -73,20 +66,23 @@ def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class ChemicalPotential(PhysicalProperty): +class ChemicalPotential(Energy): """ - Physical property section describing the chemical potential of a (sub)system. + Free energy cost of adding or extracting a particle from a thermodynamic system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the chemical potential. - """, - ) + # ! implement `iri` and `rank` as part of `m_def = Section()` - def normalize(self, archive, logger) -> None: + iri = 'http://fairmat-nfdi.eu/taxonomy/ChemicalPotential' + + def __init__( + self, m_def: 'Section' = None, m_context: 'Context' = None, **kwargs + ) -> None: + super().__init__(m_def, m_context, **kwargs) + self.rank = [] + self.name = self.m_def.name + + def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: super().normalize(archive, logger) @@ -107,19 +103,11 @@ def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class Virial(PhysicalProperty): +class Virial(Energy): """ Physical property section describing the virial (cross product between positions and forces) of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the virial. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger)