From 1a0fc7bb5c536b197a1dff327aa0bccd8c47ee6a Mon Sep 17 00:00:00 2001 From: jrudz Date: Fri, 21 Jun 2024 08:40:11 +0200 Subject: [PATCH] reorganized energy inheritance --- src/nomad_simulations/properties/energies.py | 457 +++++-------------- 1 file changed, 121 insertions(+), 336 deletions(-) diff --git a/src/nomad_simulations/properties/energies.py b/src/nomad_simulations/properties/energies.py index 9b7f2fe0..3b441f54 100644 --- a/src/nomad_simulations/properties/energies.py +++ b/src/nomad_simulations/properties/energies.py @@ -79,367 +79,277 @@ def __init__( def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - #################################################### -# List of classical energy contribuions +# Abstract energy classes #################################################### - -class PotentialEnergy(PhysicalProperty): +class Energy(PhysicalProperty): """ - Section containing the potential energy of a (sub)system. - """ - - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the potential energy. - """, - ) - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - - -class KineticEnergy(PhysicalProperty): - """ - Section containing the kinetic energy of a (sub)system. + 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 kinetic energy. + Refers to the method used for calculating the energy. Allowed values are: - | Thermostat Name | Description | + | 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. | + | `"classical"` | The energy is determined via a classical mechanics formalism. | - | `"quantum"` | ... | + | `"quantum"` | The energy is determined via a quantum mechanics formalism. | """, ) - # ? Just an idea, not sure if this is necessary since we will be referencing the method, I guess maybe it's overkill in general - # ? If we do this, maybe we should have a general Energy(PP) class which is inherited from in case there are multiple interpretations/calculation methods value = Quantity( type=np.float64, unit='joule', description=""" - The value of the kinetic energy. + The value of the energy. """, ) def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -class VDWEnergy(PhysicalProperty): +class ClassicalEnergy(Energy): """ - Section containing the van der Waals contributions to the potential energy of a (sub)system. + Abstract physical property section describing some classical energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of the van der Waals contributions to the potential energy. - """, - ) - 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 ElectrostaticEnergy(PhysicalProperty): +class QuamtumEnergy(Energy): """ - Section containing all electrostatic contributions to the potential energy of a (sub)system. + Abstract physical property section describing some quantum energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of all electrostatic contributions to the potential energy. - """, - ) - 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." + ) -class ElectrostaticShortRangeEnergy(PhysicalProperty): +###################################################### +# List of general energy properties/contributions that +# can have both classical and quantum interpretations +###################################################### + +class TotalEnergy(Energy): """ - Section containing short-range electrostatic contributions to the potential energy of a (sub)system. + Physical property section describing the total energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of the short-range electrostatic contributions to the potential energy. - """, + contributions = SubSection( + sub_section=Energy.m_def, repeats=True ) def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -class ElectrostaticLongRangeEnergy(PhysicalProperty): +class KineticEnergy(Energy): """ - Section containing long-range electrostatic contributions to the potential energy of a (sub)system. + Physical property section describing the kinetic energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', + type = Quantity( + type=MEnum('classical', 'quantum'), description=""" - Value of the long-range electrostatic contributions to the potential energy. + 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 BondedEnergy(PhysicalProperty): +class PotentialEnergy(ClassicalEnergy): """ - Section containing all bonded (i.e., intramolecular) contributions to the potential energy of a (sub)system. + Physical property section describing the potential energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of all bonded (i.e., intramolecular) contributions to the potential energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -class BondEnergy(PhysicalProperty): +class IntermolecularEnergy(ClassicalEnergy): """ - Section containing contributions to the potential energy from bond interactions of a (sub)system. + Physical property section describing all intramolecular contributions to the potential energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of contributions to the potential energy from bond interactions. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -class AngleEnergy(PhysicalProperty): +class VDWEnergy(ClassicalEnergy): """ - Section containing contributions to the potential energy from angle interactions of a (sub)system. + Physical property section describing the van der Waals contributions to the potential energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of contributions to the potential energy from angle interactions. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -class DihedralEnergy(PhysicalProperty): +class ElectrostaticEnergy(ClassicalEnergy): """ - Section containing contributions to the potential energy from dihedral interactions of a (sub)system. + Physical property section describing all electrostatic contributions to the potential energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of contributions to the potential energy from dihedral interactions. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - -class ImproperDihedralEnergy(PhysicalProperty): +class ElectrostaticShortRangeEnergy(ClassicalEnergy): """ - Section containing contributions to the potential energy from improper dihedral interactions of a (sub)system. + Physical property section describing short-range electrostatic contributions to the potential energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of contributions to the potential energy from improper dihedral interactions. - """, - ) + 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 ExternalEnergy(PhysicalProperty): +class IntramolecularEnergy(ClassicalEnergy): """ - Section containing contributions to the potential energy from external interactions of a (sub)system. + Physical property section describing all intramolecular contributions to the potential energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - Value of contributions to the potential energy from external interactions. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class ClassicalEnergyContributions(ArchiveSection): +class BondEnergy(ClassicalEnergy): """ - Section containing contributions to the potential energy from a classical force field. + Physical property section describing contributions to the potential energy from bond interactions of a (sub)system. """ - potential = SubSection(sub_section=PotentialEnergy.m_def, repeats=False) + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) - kinetic = SubSection(sub_section=KineticEnergy.m_def, repeats=False) - vdw = SubSection(sub_section=VDWEnergy.m_def, repeats=False) +class AngleEnergy(ClassicalEnergy): + """ + Physical property section describing contributions to the potential energy from angle interactions of a (sub)system. + """ - electrostatic = SubSection(sub_section=ElectrostaticEnergy.m_def, repeats=False) + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) - electrostatic_short_range = SubSection( - sub_section=ElectrostaticShortRangeEnergy.m_def, repeats=False - ) - electrostatic_long_range = SubSection( - sub_section=ElectrostaticLongRangeEnergy.m_def, repeats=False - ) +class DihedralEnergy(ClassicalEnergy): + """ + Physical property section describing contributions to the potential energy from dihedral interactions of a (sub)system. + """ - bonded = SubSection(sub_section=BondedEnergy.m_def, repeats=False) + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) - bond = SubSection(sub_section=BondEnergy.m_def, repeats=False) - angle = SubSection(sub_section=AngleEnergy.m_def, repeats=False) +class ImproperDihedralEnergy(ClassicalEnergy): + """ + Physical property section describing contributions to the potential energy from improper dihedral interactions of a (sub)system. + """ - dihedral = SubSection(sub_section=DihedralEnergy.m_def, repeats=False) + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) - improper_dihedral = SubSection( - sub_section=ImproperDihedralEnergy.m_def, repeats=False - ) - external = SubSection(sub_section=ExternalEnergy.m_def, repeats=False) +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) - # Set the name of the section - self.name = self.m_def.name - ###################################### # List of quantum energy contributions ###################################### - -class ElectronicEnergy(PhysicalProperty): +class ElectronicEnergy(QuamtumEnergy): """ - Section containing the electronic energy of a (sub)system. + Physical property section describing the electronic energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the electronic energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) - allowed_contributions = ['PotKin'] +#! 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(PhysicalProperty): +class ElectronicKineticEnergy(QuamtumEnergy): """ - Section containing the electronic kinetic energy of a (sub)system. + Physical property section describing the electronic kinetic energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the electronic kinetic energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class XCEnergy(PhysicalProperty): +class XCEnergy(QuamtumEnergy): """ - Section containing the exchange-correlation (XC) energy of a (sub)system, + 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? - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the exchange-correlation energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class XCPotentialEnergy(PhysicalProperty): +class XCPotentialEnergy(QuamtumEnergy): """ - Section containing the potential energy contribution to the exchange-correlation (XC) energy, + 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? - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the potential energy contribution of the exchange-correlation energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) # ? XCCorrelationEnergy? -class CorrelationEnergy(PhysicalProperty): +class CorrelationEnergy(QuamtumEnergy): """ - Section containing the correlation energy of a (sub)system, + Physical property section describing the correlation energy of a (sub)system, calculated using the method described in XC_functional. """ @@ -459,164 +369,64 @@ def normalize(self, archive, logger) -> None: # ? XCExchangeEnergy? -class ExchangeEnergy(PhysicalProperty): +class ExchangeEnergy(QuamtumEnergy): """ - Section containing the exchange energy of a (sub)system, + 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? - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the exchange energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class ZeroTemperatureEnergy(PhysicalProperty): +class ZeroTemperatureEnergy(QuamtumEnergy): """ - Section containing the total energy of a (sub)system extrapolated to $T=0$. + 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 total energy 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(PhysicalProperty): +class ZeroPointEnergy(QuamtumEnergy): """ - Section containing the zero-point vibrational energy of a (sub)system, + 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? - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the zero-point energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class ElectrostaticEnergy(PhysicalProperty): +class ElectrostaticEnergy(QuamtumEnergy): """ - Section containing the electrostatic energy (nuclei + electrons) of a (sub)system. + Physical property section describing the electrostatic energy (nuclei + electrons) of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the electrostatic energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class NuclearRepulsionEnergy(PhysicalProperty): +class NuclearRepulsionEnergy(QuamtumEnergy): """ - Section containing the nuclear-nuclear repulsion energy of a (sub)system. + Physical property section describing the nuclear-nuclear repulsion energy of a (sub)system. """ - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the nuclear-nuclear repulsion energy. - """, - ) - def normalize(self, archive, logger) -> None: super().normalize(archive, logger) -class QuantumEnergyContributions(ArchiveSection): - """ - Section containing contributions to the potential energy from a DFT calculation. - """ - - ... - - electronic = SubSection(sub_section=ElectronicEnergy.m_def, repeats=False) - - electronic_kinetic = SubSection( - sub_section=ElectronicKineticEnergy.m_def, repeats=False - ) - - xc = SubSection(sub_section=XCEnergy.m_def, repeats=False) - - xc_potential = SubSection(sub_section=XCPotentialEnergy.m_def, repeats=False) - - correlation = SubSection(sub_section=CorrelationEnergy.m_def, repeats=False) - - exchange = SubSection(sub_section=ExchangeEnergy.m_def, repeats=False) - - zero_temperature = SubSection( - sub_section=ZeroTemperatureEnergy.m_def, repeats=False - ) - - zero_point = SubSection(sub_section=ZeroPointEnergy.m_def, repeats=False) - - electrostatic = SubSection(sub_section=ElectrostaticEnergy.m_def, repeats=False) - - nuclear_repulsion = SubSection( - sub_section=NuclearRepulsionEnergy.m_def, repeats=False - ) - - ########################## # Other / General energies ########################## -class TotalEnergy(PhysicalProperty): - """ - Section containing the total energy of a (sub)system. - """ - - value = Quantity( - type=np.float64, - unit='joule', - description=""" - The value of the total energy. - """, - ) - # ? Do we need these descriptions under value? It ends up simply duplicating the section info to some extent. - - classical_contributions = SubSection( - sub_section=ClassicalEnergyContributions.m_def, repeats=False - ) - - quantum_contributions = SubSection( - sub_section=QuantumEnergyContributions.m_def, repeats=False - ) - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) - #? Should we set total energy value as sum of all contributions if not set explicitly? # madelung = SubSection( # sub_section=EnergyEntry.m_def, @@ -767,28 +577,3 @@ def normalize(self, archive, logger) -> None: # with calculation_to_calculation_kind = starting_point # """, # ) - - -# # ? Do we want to allow this? -# class EnergyCustom(PhysicalProperty): -# """ -# Section containing the total energy of a (sub)system. -# """ - -# name = Quantity( -# type=str, -# description=""" -# The name of this custom energy. -# """, -# ) - -# value = Quantity( -# type=np.float64, -# unit='joule', -# description=""" -# The value of this custom energy type. -# """, -# ) - -# def normalize(self, archive, logger) -> None: -# super().normalize(archive, logger)