Skip to content

Commit

Permalink
Added energies.py and FermiLevel and ChemicalPotential
Browse files Browse the repository at this point in the history
Added SpectralProfile, ElectronicDensityOfStates, XASSpectra in spectral_profile.py

Check iri assignement in __init__ in PhysicalProperty

Fixed ElectronicBandGap
  • Loading branch information
JosePizarro3 committed Apr 12, 2024
1 parent 52558f1 commit b0e93d0
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 70 deletions.
20 changes: 19 additions & 1 deletion src/nomad_simulations/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@
from .model_system import ModelSystem
from .physical_property import PhysicalProperty
from .numerical_settings import SelfConsistency
from .properties import ElectronicBandGap
from .properties import (
ElectronicBandGap,
FermiLevel,
ChemicalPotential,
ElectronicDensityOfStates,
XASSpectra,
)


class Outputs(ArchiveSection):
Expand Down Expand Up @@ -64,6 +70,18 @@ class Outputs(ArchiveSection):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
electronic_band_gap = SubSection(sub_section=ElectronicBandGap.m_def, repeats=True)

fermi_level = SubSection(sub_section=FermiLevel.m_def, repeats=True)

chemical_potential = SubSection(sub_section=ChemicalPotential.m_def, repeats=True)

electronic_dos = SubSection(
sub_section=ElectronicDensityOfStates.m_def, repeats=True
)

xas_spectra = SubSection(sub_section=XASSpectra.m_def, repeats=True)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

def set_model_system_ref(self) -> Optional[ModelSystem]:
if self.m_parent is not None:
model_systems = self.m_parent.model_system
Expand Down
5 changes: 4 additions & 1 deletion src/nomad_simulations/physical_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,10 @@ def _new_value(self) -> Quantity:

def __init__(self, m_def: Section = None, m_context: Context = None, **kwargs):
super().__init__(m_def, m_context, **kwargs)
# self._new_value = self._new_value
if self.iri is None:
logger.warning(
'The used property is not defined in the FAIRmat taxonomy (https://fairmat-nfdi.github.io/fairmat-taxonomy/). You can contribute there if you want to extend the list of available materials properties.'
)

def __setattr__(self, name: str, val: Any) -> None:
# For the special case of `value`, its `shape` needs to be defined from `_full_shape`
Expand Down
3 changes: 2 additions & 1 deletion src/nomad_simulations/properties/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from .energies import FermiLevel, ChemicalPotential
from .band_gap import ElectronicBandGap
from .spectral_profile import SpectralProfile
from .spectral_profile import SpectralProfile, ElectronicDensityOfStates, XASSpectra
5 changes: 2 additions & 3 deletions src/nomad_simulations/properties/band_gap.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import pint
from typing import Optional

from nomad.units import ureg
from nomad.metainfo import Quantity, MEnum, Section, Context

from ..physical_property import PhysicalProperty
Expand All @@ -32,7 +31,7 @@ class ElectronicBandGap(PhysicalProperty):
Energy difference between the highest occupied electronic state and the lowest unoccupied electronic state.
"""

iri = 'https://fairmat-nfdi.github.io/fairmat-taxonomy/#/ElectronicBandGap'
iri = 'https://fairmat-nfdi.github.io/fairmat-taxonomy/ElectronicBandGap'

# ? can `type` change character depending on the `variables`?
type = Quantity(
Expand Down Expand Up @@ -69,7 +68,7 @@ class ElectronicBandGap(PhysicalProperty):

value = Quantity(
type=np.float64,
unit='joule',
unit='joule', # ! this units need to be fixed when we have dynamical units
description="""
The value of the `ElectronicBandGap`.
""",
Expand Down
69 changes: 69 additions & 0 deletions src/nomad_simulations/properties/energies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#
# Copyright The NOMAD Authors.
#
# This file is part of NOMAD. See https://nomad-lab.eu for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import numpy as np

from nomad.metainfo import Quantity, Section, Context

from ..physical_property import PhysicalProperty


class FermiLevel(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.
"""

iri = 'https://fairmat-nfdi.github.io/fairmat-taxonomy/FermiLevel'

value = Quantity(
type=np.float64,
unit='joule', # ! this units need to be fixed when we have dynamical units
description="""
Value of the Fermi level.
""",
)

def __init__(self, m_def: Section = None, m_context: Context = None, **kwargs):
super().__init__(m_def, m_context, **kwargs)
self.rank = [] # ? Is this here or in the attrs instantiation better?

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


class ChemicalPotential(PhysicalProperty):
"""
Free energy cost of adding or extracting a particle from a thermodynamic system.
"""

iri = 'https://fairmat-nfdi.github.io/fairmat-taxonomy/ChemicalPotential'

value = Quantity(
type=np.float64,
unit='joule', # ! this units need to be fixed when we have dynamical units
description="""
Value of the chemical potential.
""",
)

def __init__(self, m_def: Section = None, m_context: Context = None, **kwargs):
super().__init__(m_def, m_context, **kwargs)
self.rank = [] # ? Is this here or in the attrs instantiation better?

def normalize(self, archive, logger) -> None:
super().normalize(archive, logger)
99 changes: 35 additions & 64 deletions src/nomad_simulations/properties/spectral_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import pint

from nomad.units import ureg
from nomad.datamodel.data import ArchiveSection
from nomad.metainfo import (
Quantity,
SubSection,
Expand All @@ -32,38 +31,42 @@
JSON,
)

from ..outputs import resolve_output_value, Outputs, PhysicalProperty, FermiLevel
from ..physical_property import PhysicalProperty


class SpectralProfile(Outputs):
class SpectralProfile(PhysicalProperty):
"""
A base section used to define the spectral profile.
"""

intensities = Quantity(
value = Quantity(
type=np.float64,
shape=['*'],
description="""
Intensities in arbitrary units.
Value of the intensities of a spectral profile in arbitrary units.
""",
)

intensities_units = Quantity(
type=str,
description="""
Unit using the pint UnitRegistry() notation for the `intensities`. Example, if the spectra `is_derived`
from the imaginary part of the dielectric function, `intensities_units` are `'F/m'`.
""",
)
# TODO implement this in PhysicalProperty (similar to shape)
# value_units = Quantity(
# type=str,
# description="""
# Unit using the pint UnitRegistry() notation for the `value`. Example, if the spectra `is_derived`
# from the imaginary part of the dielectric function, `value` are `'F/m'`.
# """,
# )

def __init__(self, m_def: Section = None, m_context: Context = None, **kwargs):
super().__init__(m_def, m_context, **kwargs)
self.rank = [] # ? Is this here or in the attrs instantiation better?

def is_valid_spectral_profile(self) -> bool:
"""
Check if the spectral profile is valid, i.e., if the `intensities` are defined positive.
Check if the spectral profile is valid, i.e., if all `value` are defined positive.
Returns:
(bool): True if the spectral profile is valid, False otherwise.
"""
if (self.intensities < 0.0).any():
if (self.value < 0.0).any():
return False
return True

Expand All @@ -77,45 +80,21 @@ def normalize(self, archive, logger) -> None:
return


class ElectronicSpectralProfile(SpectralProfile):
class ElectronicDensityOfStates(SpectralProfile):
"""
A base section used to define the electronic spectral profile variables. These are defined as the excitation energies.
Electronic Density of States (DOS).
"""

n_energies = Quantity(
type=np.int32,
shape=[],
description="""
Number of energies.
""",
)

energies = Quantity(
type=np.float64,
shape=['n_energies'],
unit='joule',
description="""
Energies.
""",
)
iri = 'http://fairmat-nfdi.eu/taxonomy/ElectronicDensityOfStates'

energies_origin = Quantity(
type=np.float64,
unit='joule',
spin_channel = Quantity(
type=np.int32,
description="""
Origin of reference for the energies.
Spin channel of the corresponding DOS. It can take values of 0 or 1. This quantity is set only if
`ModelMethod.is_spin_polarized` is `True`.
""",
)

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


class ElectronicDOS(ElectronicSpectralProfile):
"""
Electronic Density of States (DOS).
"""

fermi_level = Quantity(
type=np.float64,
unit='joule',
Expand All @@ -129,14 +108,6 @@ class ElectronicDOS(ElectronicSpectralProfile):
""",
)

spin_channel = Quantity(
type=np.int32,
description="""
Spin channel of the corresponding DOS. It can take values of 0 or 1. This quantity is set only if
`ModelMethod.is_spin_polarized` is `True`.
""",
)

normalization_factor = Quantity(
type=np.float64,
description="""
Expand All @@ -146,16 +117,15 @@ class ElectronicDOS(ElectronicSpectralProfile):
""",
)

intensities_integrated = Quantity(
value_integrated = Quantity(
type=np.float64,
shape=['n_energies'],
description="""
The cumulative intensities integrated from from the lowest (most negative) energy to the `fermi_level`.
""",
)

projected_dos = SubSection(
sub_section=ElectronicSpectralProfile.m_def,
sub_section=SpectralProfile.m_def,
repeats=True,
description="""
Projected DOS. It can be species- (same elements in the unit cell), atom- (different elements in the unit cell),
Expand All @@ -170,7 +140,6 @@ class ElectronicDOS(ElectronicSpectralProfile):

def __init__(self, m_def: Section = None, m_context: Context = None, **kwargs):
super().__init__(m_def, m_context, **kwargs)
# Set the name of the section
self.name = self.m_def.name

def resolve_fermi_level(self) -> Optional[np.float64]:
Expand All @@ -181,9 +150,9 @@ def resolve_fermi_level(self) -> Optional[np.float64]:
(Optional[np.float64]): The resolved Fermi level.
"""
fermi_level = self.fermi_level
if fermi_level is None:
fermi_level = resolve_output_value(self, FermiLevel)
return fermi_level
# if fermi_level is None:
# fermi_level = resolve_output_value(self, FermiLevel)
# return fermi_level

def check_spin_polarized(self) -> bool:
"""
Expand Down Expand Up @@ -234,23 +203,25 @@ def normalize(self, archive, logger) -> None:
self.energies_origin = self.resolve_energies_origin()


class XASSpectra(ElectronicSpectralProfile):
class XASSpectra(SpectralProfile):
"""
X-ray Absorption Spectra (XAS).
"""

xanes_spectra = SubSection(
sub_section=ElectronicSpectralProfile.m_def,
sub_section=SpectralProfile.m_def,
description="""
X-ray Absorption Near Edge Structure (XANES) spectra.
""",
repeats=False,
)

exafs_spectra = SubSection(
sub_section=ElectronicSpectralProfile.m_def,
sub_section=SpectralProfile.m_def,
description="""
Extended X-ray Absorption Fine Structure (EXAFS) spectra.
""",
repeats=False,
)

def __init__(self, m_def: Section = None, m_context: Context = None, **kwargs):
Expand Down

0 comments on commit b0e93d0

Please sign in to comment.