Skip to content

Commit

Permalink
Extend to band structures
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Daelman committed Dec 18, 2024
1 parent 6f8a7ea commit ba97b08
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 60 deletions.
6 changes: 3 additions & 3 deletions src/nomad_simulations/schema_packages/properties/band_gap.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from nomad.units import ureg
from nomad.datamodel.data import ArchiveSection
from nomad.metainfo import MEnum, Quantity
from nomad.metainfo.physical_properties import DatasetTemplate, Energy
from nomad.metainfo.datasets import DatasetTemplate, Energy
from ..variables import (
SpinChannel,
MomentumTransfer,
Expand All @@ -29,8 +29,8 @@ class HomoLumoGap(ArchiveSection): # ? class description

def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
self.m_all_validate() # ensure constraints
if np.any(self.values.fields < 0):
logger.warning(f'Negative band gap detected: {self.values.fields} J')
if np.any((energies := self.get_variable(Energy).get_values()) < 0): # ? failure handling
logger.warning(f'Negative band gap detected: {energies.to('J').magnitude} J')


class ElectronicBandGap(HomoLumoGap): # ! TODO: add optical band gap
Expand Down
118 changes: 68 additions & 50 deletions src/nomad_simulations/schema_packages/properties/band_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import numpy as np
import pint
import plotly.express as px

from nomad.datamodel.data import ArchiveSection
from nomad.metainfo import MEnum, Quantity
from nomad.metainfo.physical_properties import MaterialProperty, Count
from nomad.metainfo.physical_properties import DatasetTemplate, Count, Energy
from ..variables import SpinChannel, KMesh

if TYPE_CHECKING:
Expand Down Expand Up @@ -33,38 +35,21 @@


class ElectronicEigenstates(ArchiveSection):
values = MaterialProperty(
values = DatasetTemplate(
name='ElectronicEigenstates',
fields=[Energy, Occupancy], # shape defined by variables
variables=[SpinChannel, KMesh], # ? enforce spanned dimension at metainfo level
mandatory_fields=[Energy, Occupancy],
mandatory_variables=[SpinChannel],
iri='http://fairmat-nfdi.eu/taxonomy/ElectronicEigenvalues',
description="""A base section used to define basic quantities for the `ElectronicEigenvalues` and `ElectronicEigenstates` properties.""",
)

kind = Quantity(
type=MEnum('KS', 'KSxc', 'SigX', 'SigC', 'Zk'),
description="""
Contributions to the electronic eigenvalues. Example, in the case of a DFT+GW calculation, the GW eigenvalues
are stored under `value`, and each contribution is identified by `label`:
- `'KS'`: Kohn-Sham contribution. This is also stored in the DFT entry under `ElectronicEigenvalues.value`.
- `'KSxc'`: Diagonal matrix elements of the expectation value of the Kohn-Sahm exchange-correlation potential.
- `'SigX'`: Diagonal matrix elements of the exchange self-energy. This is also stored in the GW entry under `ElectronicSelfEnergy.value`.
- `'SigC'`: Diagonal matrix elements of the correlation self-energy. This is also stored in the GW entry under `ElectronicSelfEnergy.value`.
- `'Zk'`: Quasiparticle renormalization factors contribution. This is also stored in the GW entry under `QuasiparticleWeights.value`.
A base section used to define basic quantities for
the `ElectronicEigenvalues` and `ElectronicEigenstates` properties.
""",
)

# ? Should we add functionalities to handle min/max of the `value` in some specific cases, e.g. bands around the Fermi level,
# ? core bands separated by gaps, and equivalently, higher-energy valence bands separated by gaps?

# references
reciprocal_cell = Quantity(
type=KSpace.reciprocal_lattice_vectors,
description="""
Reference to the reciprocal lattice vectors stored under `KSpace`.
""",
) # !

atoms_state_ref = Quantity(
type=AtomsState,
description="""
Expand All @@ -80,30 +65,11 @@ class ElectronicEigenstates(ArchiveSection):
) # ! TODO: unify with `atoms_state_ref`

# derived properties
n_bands = Quantity(
type=np.int32,
description="""
Number of bands / eigenvalues.
""",
) # ? remove
n_eigenvalues = Count # ? remove

highest_occupied = Quantity(
type=np.float64, # ! energy, k-point
unit='joule',
description="""
Highest occupied electronic eigenvalue. Together with `lowest_unoccupied`, it defines the
electronic band gap.
""",
)
highest_occupied = Energy # ? property

lowest_unoccupied = Quantity(
type=np.float64, # ! energy, k-point
unit='joule',
description="""
Lowest unoccupied electronic eigenvalue. Together with `highest_occupied`, it defines the
electronic band gap.
""",
)
lowest_unoccupied = Energy # ? property

def order_eigenvalues(self) -> Union[bool, tuple['pint.Quantity', np.ndarray]]:
"""
Expand Down Expand Up @@ -214,9 +180,61 @@ def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
self.reciprocal_cell = self.resolve_reciprocal_cell()


# TODO: consider matching different k-channels for indirect bandgaps
def bandstructure_to_dos(bs: ElectronicEigenstates) -> ElectronicDOS:
pass
class DensityOfStates(ElectronicEigenstates):
# fermi_level

# band_gap

partial_dos = DatasetTemplate(
mandatory_fields=[Energy, Count], # ! relax
mandatory_variables=[SpinChannel, AtomsState], # to be interpreted as the symbol, i.e. p_x
) # ? instead of subsection

def plot(self):
self.m_all_validate()
energy_axes = self.values.get_values(Energy).by(SpinChannel)
figure_main = px.line(
x=np.sort(np.array(set(*energy_axes))), # overlay along spin dim
y=self.values.get_values(Count).by(SpinChannel),
color=self.values.get_variable(SpinChannel),
)


class BandStructure(ArchiveSection):
values = DatasetTemplate(
name='BandStructure',
fields=[ElectronicEigenstates.values],
variables=[KMesh], # ? at what level will `SpinChannel` exist
)

kind = Quantity(
type=MEnum('KS', 'KSxc', 'SigX', 'SigC', 'Zk'),
description="""
Contributions to the electronic eigenvalues. Example, in the case of a DFT+GW calculation, the GW eigenvalues
are stored under `value`, and each contribution is identified by `label`:
- `'KS'`: Kohn-Sham contribution. This is also stored in the DFT entry under `ElectronicEigenvalues.value`.
- `'KSxc'`: Diagonal matrix elements of the expectation value of the Kohn-Sahm exchange-correlation potential.
- `'SigX'`: Diagonal matrix elements of the exchange self-energy. This is also stored in the GW entry under `ElectronicSelfEnergy.value`.
- `'SigC'`: Diagonal matrix elements of the correlation self-energy. This is also stored in the GW entry under `ElectronicSelfEnergy.value`.
- `'Zk'`: Quasiparticle renormalization factors contribution. This is also stored in the GW entry under `QuasiparticleWeights.value`.
""",
) # ? move to `ElectronicEigenstates`

reciprocal_cell = Quantity(
type=KSpace.reciprocal_lattice_vectors,
description="""
Reference to the reciprocal lattice vectors stored under `KSpace`.
""",
) # !

highest_occupied = DatasetTemplate(
name='HighestOccupied',
mandatory_fields=[Energy, KMesh],
) # ? property

lowest_unoccupied = ighest_occupied = DatasetTemplate(
name='LowestUnoccupied',
mandatory_fields=[Energy, KMesh],
) # ? property

def dos_to_bandgap(dos: ElectronicDOS) -> ElectronicBandGap:
pass
# ! plot
14 changes: 7 additions & 7 deletions src/nomad_simulations/schema_packages/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import numpy as np
from nomad.datamodel.data import ArchiveSection
from nomad.metainfo import MEnum, Quantity
from nomadmetainfo.physical_properties import (
PhysicalProperty,
MaterialProperty,
from nomad.metainfo.datasets import (
ValuesTemplate,
DatasetTemplate,
)

if TYPE_CHECKING:
Expand All @@ -22,14 +22,14 @@
)


SpinChannel = PhysicalProperty(
SpinChannel = ValuesTemplate(
name='SpinChannel',
type=MEnum('alpha', 'beta', 'both'),
# ! iri
)


KMesh = PhysicalProperty(
KMesh = ValuesTemplate(
type=np.float64, # ? KMeshSettings.points,
shape=[3],
unit='1/m',
Expand All @@ -41,7 +41,7 @@
)


MomentumTransfer = PhysicalProperty(
MomentumTransfer = ValuesTemplate(
type=np.float64,
shape=[2, 3],
unit='1/meter',
Expand All @@ -57,7 +57,7 @@
)


class Variables(ArchiveSection):
class Variables(ArchiveSection): # ! TODO: deprecate
"""
Variables over which the physical property varies, and they are defined as grid points, i.e., discretized
values by `n_points` and `points`. These are used to calculate the `shape` of the physical property.
Expand Down

0 comments on commit ba97b08

Please sign in to comment.