diff --git a/src/nomad_simulations/schema_packages/outputs.py b/src/nomad_simulations/schema_packages/outputs.py index 93b985a4..adbb6710 100644 --- a/src/nomad_simulations/schema_packages/outputs.py +++ b/src/nomad_simulations/schema_packages/outputs.py @@ -305,6 +305,7 @@ def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: logger=logger, ) + class WorkflowOutputs(Outputs): """ This section contains output properties that depend on a single system, but were @@ -345,4 +346,4 @@ class TrajectoryOutputs(WorkflowOutputs): ) def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) \ No newline at end of file + super().normalize(archive, logger) diff --git a/src/nomad_simulations/schema_packages/properties/__init__.py b/src/nomad_simulations/schema_packages/properties/__init__.py index 5eaeb97e..90b001f7 100644 --- a/src/nomad_simulations/schema_packages/properties/__init__.py +++ b/src/nomad_simulations/schema_packages/properties/__init__.py @@ -37,4 +37,4 @@ ElectronicDensityOfStates, SpectralProfile, XASSpectrum, -) \ No newline at end of file +) diff --git a/src/nomad_simulations/schema_packages/properties/energies.py b/src/nomad_simulations/schema_packages/properties/energies.py index 5627967d..93f4eed1 100644 --- a/src/nomad_simulations/schema_packages/properties/energies.py +++ b/src/nomad_simulations/schema_packages/properties/energies.py @@ -85,10 +85,12 @@ 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. @@ -122,6 +124,7 @@ class Energy(PhysicalProperty): 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. @@ -133,9 +136,8 @@ def normalize(self, archive, logger) -> None: if not self.type: self.type == 'classical' elif self.type != 'classical': - logger.error( - f"Misidentified type for classical energy." - ) + logger.error(f'Misidentified type for classical energy.') + class QuantumEnergy(Energy): """ @@ -148,27 +150,26 @@ def normalize(self, archive, logger) -> None: if not self.type: self.type == 'quantum' elif self.type != 'quantum': - logger.error( - f"Misidentified type for quantum energy." - ) + 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): """ Physical property section describing the total energy of a (sub)system. """ - contributions = SubSection( - sub_section=Energy.m_def, repeats=True - ) + contributions = SubSection(sub_section=Energy.m_def, repeats=True) def normalize(self, archive, logger) -> None: super().normalize(archive, logger) + class KineticEnergy(Energy): """ Physical property section describing the kinetic energy of a (sub)system. @@ -196,10 +197,12 @@ class KineticEnergy(Energy): def normalize(self, archive, logger) -> None: super().normalize(archive, logger) + #################################################### # List of classical energy contribuions #################################################### + class PotentialEnergy(ClassicalEnergy): """ Physical property section describing the potential energy of a (sub)system. @@ -208,6 +211,7 @@ class PotentialEnergy(ClassicalEnergy): 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. @@ -216,6 +220,7 @@ class IntermolecularEnergy(ClassicalEnergy): 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. @@ -224,6 +229,7 @@ class VDWEnergy(ClassicalEnergy): 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. @@ -232,6 +238,7 @@ class ElectrostaticEnergy(ClassicalEnergy): 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. @@ -240,6 +247,7 @@ class ElectrostaticShortRangeEnergy(ClassicalEnergy): 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. @@ -302,10 +310,12 @@ class ExternalEnergy(ClassicalEnergy): 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. @@ -313,6 +323,8 @@ class ElectronicEnergy(QuantumEnergy): 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 @@ -330,6 +342,7 @@ 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? @@ -345,6 +358,7 @@ class XCPotentialEnergy(QuantumEnergy): 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? @@ -380,6 +394,7 @@ 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? @@ -391,6 +406,7 @@ 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? @@ -403,6 +419,7 @@ 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? @@ -433,153 +450,152 @@ def normalize(self, archive, logger) -> None: ########################## - - # madelung = SubSection( - # sub_section=EnergyEntry.m_def, - # description=""" - # Contains the value and information regarding the Madelung energy. - # """, - # ) - - # # 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=""" - # Contains the value and information regarding the free energy (nuclei + electrons) - # (whose minimum gives the smeared occupation density calculated with - # smearing_kind). - # """, - # ) - - # sum_eigenvalues = SubSection( - # sub_section=EnergyEntry.m_def, - # description=""" - # Contains the value and information regarding the sum of the eigenvalues of the - # 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 - # """, - # ) \ No newline at end of file +# madelung = SubSection( +# sub_section=EnergyEntry.m_def, +# description=""" +# Contains the value and information regarding the Madelung energy. +# """, +# ) + +# # 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=""" +# Contains the value and information regarding the free energy (nuclei + electrons) +# (whose minimum gives the smeared occupation density calculated with +# smearing_kind). +# """, +# ) + +# sum_eigenvalues = SubSection( +# sub_section=EnergyEntry.m_def, +# description=""" +# Contains the value and information regarding the sum of the eigenvalues of the +# 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 8e56bbb5..54a1fe17 100644 --- a/src/nomad_simulations/schema_packages/properties/forces.py +++ b/src/nomad_simulations/schema_packages/properties/forces.py @@ -45,6 +45,7 @@ # Abstract force classes #################################################### + class Force(PhysicalProperty): """ Abstract physical property section describing some energy of a (sub)system. @@ -67,11 +68,13 @@ class Force(PhysicalProperty): def normalize(self, archive, logger) -> None: super().normalize(archive, logger) + ###################################################### # List of general force properties/contributions that # can have both classical and quantum interpretations ###################################################### + class TotalForce(Force): """ Section containing the total force of a (sub)system. @@ -79,11 +82,10 @@ class TotalForce(Force): Contains the value and information regarding the total forces on the atoms calculated as minus gradient of energy_total. """ + # ! 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 - ) + contributions = SubSection(sub_section=Force.m_def, repeats=True) def normalize(self, archive, logger) -> None: super().normalize(archive, logger) @@ -128,6 +130,7 @@ class RawForce(Force): Value of the forces acting on the atoms **not including** such as fixed atoms, distances, angles, dihedrals, etc. """ + # ? This is VERY imprecise, is this used regularly? def normalize(self, archive, logger) -> None: @@ -160,4 +163,3 @@ def normalize(self, archive, logger) -> None: # 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). -