Skip to content

Commit

Permalink
- Make PhysicalProperty initialize self.name
Browse files Browse the repository at this point in the history
- Remove wasteful `__init__` and `normalize`
  • Loading branch information
ndaelman committed Nov 12, 2024
1 parent 9e6f9a5 commit 1e671c8
Show file tree
Hide file tree
Showing 12 changed files with 14 additions and 315 deletions.
3 changes: 2 additions & 1 deletion src/nomad_simulations/schema_packages/physical_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
logger = utils.get_logger(__name__)


def validate_quantity_wrt_value(name: str = ''):
def validate_quantity_wrt_value(name: str = ''): # ! tone down to `quantity_present`
"""
Decorator to validate the existence of a quantity and its shape with respect to the `PhysicalProperty.value`
before calling a method. An example can be found in the module `properties/band_structure.py` for the method
Expand Down Expand Up @@ -238,6 +238,7 @@ 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

# Checking if IRI is defined
if not self.iri:
Expand Down
75 changes: 11 additions & 64 deletions src/nomad_simulations/schema_packages/properties/band_gap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class ElectronicBandGap(PhysicalProperty):

type = Quantity(
type=MEnum('direct', 'indirect'),
shape=['*'],
description="""
Type categorization of the electronic band gap. This quantity is directly related with `momentum_transfer` as by
definition, the electronic band gap is `'direct'` for zero momentum transfer (or if `momentum_transfer` is `None`) and `'indirect'`
Expand All @@ -34,15 +35,13 @@ class ElectronicBandGap(PhysicalProperty):

momentum_transfer = Quantity(
type=np.float64,
shape=[2, 3],
shape=['*', 2, 3],
description="""
If the electronic band gap is `'indirect'`, the reciprocal momentum transfer for which the band gap is defined
in units of the `reciprocal_lattice_vectors`. The initial and final momentum 3D vectors are given in the first
and second element. Example, the momentum transfer in bulk Si2 happens between the Γ and the (approximately)
X points in the Brillouin zone; thus:
`momentum_transfer = [[0, 0, 0], [0.5, 0.5, 0]]`.
Note: this quantity only refers to scalar `value`, not to arrays of `value`.
`momentum_transfer = [[[0, 0, 0], [0.5, 0.5, 0]]]`.
""",
)

Expand All @@ -53,7 +52,7 @@ class ElectronicBandGap(PhysicalProperty):
""",
)

value = Quantity(
_base_value = Quantity(
type=np.float64,
unit='joule',
description="""
Expand All @@ -62,35 +61,7 @@ class ElectronicBandGap(PhysicalProperty):
""",
)

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 validate_values(self, logger: 'BoundLogger') -> Optional[pint.Quantity]:
"""
Validate the electronic band gap `value` by checking if they are negative and sets them to None if they are.
Args:
logger (BoundLogger): The logger to log messages.
"""
value = self.value.magnitude
if not isinstance(self.value.magnitude, np.ndarray): # for scalars
value = np.array(
[value]
) # ! check this when talking with Lauri and Theodore

# Set the value to 0 when it is negative
if (value < 0).any():
logger.error('The electronic band gap cannot be defined negative.')
return None

if not isinstance(self.value.magnitude, np.ndarray): # for scalars
value = value[0]
return value * self.value.u

def resolve_type(self, logger: 'BoundLogger') -> Optional[str]:
def momentum_to_type(self, mtr, logger: 'BoundLogger') -> Optional[str]:
"""
Resolves the `type` of the electronic band gap based on the stored `momentum_transfer` values.
Expand All @@ -100,23 +71,7 @@ def resolve_type(self, logger: 'BoundLogger') -> Optional[str]:
Returns:
(Optional[str]): The resolved `type` of the electronic band gap.
"""
mtr = self.momentum_transfer if self.momentum_transfer is not None else []

# Check if the `momentum_transfer` is [], and return the type and a warning in the log for `indirect` band gaps
if len(mtr) == 0:
if self.type == 'indirect':
logger.warning(
'The `momentum_transfer` is not stored for an `indirect` band gap.'
)
return self.type

# Check if the `momentum_transfer` has at least two elements, and return None if it does not
if len(mtr) == 1:
logger.warning(
'The `momentum_transfer` should have at least two elements so that the difference can be calculated and the type of electronic band gap can be resolved.'
)
return None


# Resolve `type` from the difference between the initial and final momentum transfer
momentum_difference = np.diff(mtr, axis=0)
if (np.isclose(momentum_difference, np.zeros(3))).all():
Expand All @@ -127,17 +82,9 @@ def resolve_type(self, logger: 'BoundLogger') -> Optional[str]:
def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)

# Checks if the `value` is negative and sets it to None if it is.
self.value = self.validate_values(logger)
if self.value is None:
if self.value is not None and np.any(self.value < 0.):
logger.warning('The electronic band gap cannot be defined negative.')
# ? What about deleting the class if `value` is None?
logger.error('The `value` of the electronic band gap is not stored.')
return

# Resolve the `type` of the electronic band gap from `momentum_transfer`, ONLY for scalar `value`
if isinstance(self.value.magnitude, np.ndarray):
logger.info(
'We do not support `type` which describe individual elements in an array `value`.'
)
else:
self.type = self.resolve_type(logger)

if self.momentum_transfer:
self.type = self.momentum_to_type(self.momentum_transfer, logger)
32 changes: 0 additions & 32 deletions src/nomad_simulations/schema_packages/properties/band_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,6 @@ class BaseElectronicEigenvalues(PhysicalProperty):
""",
)

def __init__(
self, m_def: 'Section' = None, m_context: 'Context' = None, **kwargs
) -> None:
super().__init__(m_def, m_context, **kwargs)

def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


class ElectronicEigenvalues(BaseElectronicEigenvalues):
""" """
Expand Down Expand Up @@ -124,12 +116,6 @@ class ElectronicEigenvalues(BaseElectronicEigenvalues):
""",
)

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

@validate_quantity_wrt_value(name='occupation')
def order_eigenvalues(self) -> Union[bool, tuple[pint.Quantity, np.ndarray]]:
"""
Expand Down Expand Up @@ -314,15 +300,6 @@ class ElectronicBandStructure(ElectronicEigenvalues):

iri = 'http://fairmat-nfdi.eu/taxonomy/ElectronicBandStructure'

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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


class Occupancy(PhysicalProperty):
"""
Expand Down Expand Up @@ -365,13 +342,4 @@ class Occupancy(PhysicalProperty):
""",
)

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

# TODO add extraction from `ElectronicEigenvalues.occupation`

def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)
43 changes: 0 additions & 43 deletions src/nomad_simulations/schema_packages/properties/energies.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ class BaseEnergy(PhysicalProperty):
""",
)

def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


class EnergyContribution(BaseEnergy, PropertyContribution):
"""
Expand All @@ -52,10 +49,6 @@ class EnergyContribution(BaseEnergy, PropertyContribution):
relevant atoms or electrons or as a function of them.
"""

# TODO address the dual parent normalization explicity
def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


####################################
# List of specific energy properties
Expand All @@ -69,15 +62,6 @@ class FermiLevel(BaseEnergy):

iri = 'http://fairmat-nfdi.eu/taxonomy/FermiLevel'

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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


#! 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?
Expand All @@ -90,42 +74,15 @@ class TotalEnergy(BaseEnergy):
# ? add a generic contributions quantity to PhysicalProperty
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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


# ? Separate quantities for nuclear and electronic KEs?
class KineticEnergy(BaseEnergy):
"""
Physical property section describing the kinetic energy of a (sub)system.
"""

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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


class PotentialEnergy(BaseEnergy):
"""
Physical property section describing the potential energy of a (sub)system.
"""

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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,4 @@ class FermiSurface(PhysicalProperty):
""",
)

# ! TODO _base_value

def __init__(
self, m_def: 'Section' = None, m_context: 'Context' = None, **kwargs
) -> None:
super().__init__(m_def, m_context, **kwargs)
# ! `n_bands` need to be set up during initialization of the class
self.name = self.m_def.name

def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)
# ! TODO add `_base_value`
9 changes: 0 additions & 9 deletions src/nomad_simulations/schema_packages/properties/forces.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ class ForceContribution(BaseForce, PropertyContribution):
relevant atoms or electrons or as a function of them.
"""

def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


###################################
# List of specific force properties
Expand All @@ -66,9 +63,3 @@ class TotalForce(BaseForce):
"""

contributions = SubSection(sub_section=ForceContribution.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
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,6 @@ class ElectronicGreensFunction(BaseGreensFunction):
""",
)

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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


class ElectronicSelfEnergy(BaseGreensFunction):
"""
Expand All @@ -221,15 +212,6 @@ class ElectronicSelfEnergy(BaseGreensFunction):
""",
)

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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


class HybridizationFunction(BaseGreensFunction):
"""
Expand All @@ -247,15 +229,6 @@ class HybridizationFunction(BaseGreensFunction):
""",
)

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: 'EntryArchive', logger: 'BoundLogger') -> None:
super().normalize(archive, logger)


class QuasiparticleWeight(PhysicalProperty):
"""
Expand Down Expand Up @@ -337,12 +310,6 @@ class QuasiparticleWeight(PhysicalProperty):
""",
)

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 is_valid_quasiparticle_weight(self) -> bool:
"""
Check if the quasiparticle weight values are valid, i.e., if all `value` are defined between
Expand Down
Loading

1 comment on commit 1e671c8

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/nomad_simulations
   __init__.py4250%3–4
   _version.py11282%5–6
src/nomad_simulations/schema_packages
   __init__.py15287%39–41
   atoms_state.py1902189%13–15, 201–204, 228, 283–284, 352–353, 355, 537, 549–550, 611–615, 630–634, 641
   basis_set.py2402888%8–9, 122–133, 172–185, 208, 391–395, 417–418, 462–465, 584, 615, 617
   general.py89891%4–7, 121, 185, 295–296, 306
   model_method.py2697871%10–12, 171–174, 177–184, 276–277, 297, 318–339, 355–381, 384–401, 587, 780, 791, 833–840, 878, 897, 977, 1034, 1109, 1223
   model_system.py3483789%45–51, 235, 254, 258, 261, 264, 290, 376–377, 454–455, 472–473, 686–689, 736–743, 917–918, 1140–1144, 1150–1151, 1159–1160, 1165, 1188
   numerical_settings.py2596176%12–14, 217, 219–220, 223–226, 230–231, 238–241, 250–253, 257–260, 262–265, 270–273, 279–282, 469–496, 571, 606–609, 633, 636, 681, 683–686, 690, 694, 741, 745–766, 821–822, 889
   outputs.py1202480%9–10, 252–255, 258–259, 279–309, 323, 325, 362, 381
   physical_property.py1081883%22–24, 210, 235, 252–255, 267, 279, 282–283, 298, 304, 326–328
   variables.py861286%8–10, 98, 121, 145, 167, 189, 211, 233, 256, 276
src/nomad_simulations/schema_packages/properties
   band_gap.py261254%8–10, 76–80, 83–90
   band_structure.py1055151%9–11, 129–144, 163–184, 217–250, 259–271, 282–293
   energies.py17382%7–9
   fermi_surface.py11373%7–9
   forces.py13377%7–9
   greens_function.py812569%7–9, 174–179, 322, 324–326, 336, 338–346, 352–365
   hopping_matrix.py17382%7–9
   permittivity.py46883%7–9, 96–104
   spectral_profile.py24413943%9–11, 44, 51–54, 84–87, 92, 180–281, 337–349, 374–377, 397, 402–405, 430–444, 447–483, 533–536, 552–553, 558–564
   thermodynamics.py34391%7–9
src/nomad_simulations/schema_packages/utils
   utils.py791680%8–11, 65–74, 83–84, 89, 92, 169–170
TOTAL242355977% 

Tests Skipped Failures Errors Time
402 0 💤 97 ❌ 0 🔥 17.188s ⏱️

Please sign in to comment.