diff --git a/src/nomad_simulations/common.py b/src/nomad_simulations/common.py deleted file mode 100644 index 90c58425..00000000 --- a/src/nomad_simulations/common.py +++ /dev/null @@ -1,74 +0,0 @@ -# -# 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 typing -# from structlog.stdlib import BoundLogger -import numpy as np - -from nomad.datamodel.data import ArchiveSection -from nomad.metainfo import Quantity - - -# TODO check this once outputs.py is defined -class HoppingMatrix(ArchiveSection): - """ - Section containing the hopping/overlap matrix elements between N projected orbitals. This - is also the output of a TB calculation. - """ - - n_orbitals = Quantity( - type=np.int32, - description=""" - Number of projected orbitals. - """, - ) - - n_wigner_seitz_points = Quantity( - type=np.int32, - description=""" - Number of Wigner-Seitz real points. - """, - ) - - # TODO check with SlaterKoster and OrbitalsState.degeneracy - degeneracy_factors = Quantity( - type=np.int32, - shape=['n_wigner_seitz_points'], - description=""" - Degeneracy of each Wigner-Seitz grid point. - """, - ) - - value = Quantity( - type=np.float64, - shape=['n_wigner_seitz_points', 'n_orbitals * n_orbitals', 7], - unit='joule', - description=""" - Real space hopping matrix for each Wigner-Seitz grid point. The elements are - defined as follows: - - n_x n_y n_z orb_1 orb_2 real_part + j * imag_part - - where (n_x, n_y, n_z) define the Wigner-Seitz cell vector in fractional coordinates, - (orb_1, orb_2) indicates the hopping amplitude between orb_1 and orb_2, and the - real and imaginary parts of the hopping. - """, - ) - - def normalize(self, archive, logger) -> None: - super().normalize(archive, logger) diff --git a/src/nomad_simulations/outputs.py b/src/nomad_simulations/outputs.py index 7d4bfec1..ac1ca674 100644 --- a/src/nomad_simulations/outputs.py +++ b/src/nomad_simulations/outputs.py @@ -27,9 +27,11 @@ from .physical_property import PhysicalProperty from .numerical_settings import SelfConsistency from .properties import ( - ElectronicBandGap, FermiLevel, ChemicalPotential, + CrystalFieldSplitting, + HoppingMatrix, + ElectronicBandGap, ElectronicDensityOfStates, XASSpectra, ) @@ -65,6 +67,12 @@ class Outputs(ArchiveSection): chemical_potential = SubSection(sub_section=ChemicalPotential.m_def, repeats=True) + crystal_field_splitting = SubSection( + sub_section=CrystalFieldSplitting.m_def, repeats=True + ) + + hopping_matrix = SubSection(sub_section=HoppingMatrix.m_def, repeats=True) + electronic_band_gap = SubSection(sub_section=ElectronicBandGap.m_def, repeats=True) electronic_dos = SubSection( diff --git a/src/nomad_simulations/properties/__init__.py b/src/nomad_simulations/properties/__init__.py index c84a0fc8..e529ed38 100644 --- a/src/nomad_simulations/properties/__init__.py +++ b/src/nomad_simulations/properties/__init__.py @@ -24,3 +24,4 @@ ElectronicDensityOfStates, XASSpectra, ) +from .hopping_matrix import HoppingMatrix, CrystalFieldSplitting diff --git a/src/nomad_simulations/properties/hopping_matrix.py b/src/nomad_simulations/properties/hopping_matrix.py new file mode 100644 index 00000000..8f163776 --- /dev/null +++ b/src/nomad_simulations/properties/hopping_matrix.py @@ -0,0 +1,106 @@ +# +# 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 HoppingMatrix(PhysicalProperty): + """ + Transition probability between two atomic orbitals in a tight-binding model. + """ + + iri = 'http://fairmat-nfdi.eu/taxonomy/HoppingMatrix' + + n_orbitals = Quantity( + type=np.int32, + description=""" + Number of orbitals in the tight-binding model. + """, + ) + + degeneracy_factors = Quantity( + type=np.int32, + shape=['*'], + description=""" + Degeneracy of each Wigner-Seitz point. + """, + ) + + value = Quantity( + type=np.complex128, + unit='joule', + description=""" + Value of the hopping matrix in joules. The elements are complex numbers defined for each Wigner-Seitz point and + each pair of orbitals; thus, `rank = [n_orbitals, n_orbitals]`. Note this contains also the onsite values, i.e., + it includes the Wigner-Seitz point (0, 0, 0), hence the `CrystalFieldSplitting` values. + """, + ) + + def __init__( + self, m_def: Section = None, m_context: Context = None, **kwargs + ) -> None: + super().__init__(m_def, m_context, **kwargs) + # ! n_orbitals need to be set up during initialization of the class + self.rank = ( + [] if self.n_orbitals is None else [self.n_orbitals, self.n_orbitals] + ) + self.name = self.m_def.name + + # TODO add normalization to extract DOS, band structure, etc, properties from `HoppingMatrix` + + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) + + +class CrystalFieldSplitting(PhysicalProperty): + """ + Energy difference between the degenerated orbitals of an ion in a crystal field environment. + """ + + iri = 'http://fairmat-nfdi.eu/taxonomy/CrystalFieldSplitting' + + n_orbitals = Quantity( + type=np.int32, + description=""" + Number of orbitals in the tight-binding model. + """, + ) + + value = Quantity( + type=np.float64, + unit='joule', + description=""" + Value of the crystal field splittings in joules. This is the intra-orbital local contribution, i.e., the same orbital + at the same Wigner-Seitz point (0, 0, 0). + """, + ) + + def __init__( + self, m_def: Section = None, m_context: Context = None, **kwargs + ) -> None: + super().__init__(m_def, m_context, **kwargs) + # ! n_orbitals need to be set up during initialization of the class + self.rank = [] if self.n_orbitals is None else [self.n_orbitals] + self.name = self.m_def.name + + def normalize(self, archive, logger) -> None: + super().normalize(archive, logger) diff --git a/src/nomad_simulations/variables.py b/src/nomad_simulations/variables.py index d5202d4a..7c713b15 100644 --- a/src/nomad_simulations/variables.py +++ b/src/nomad_simulations/variables.py @@ -129,3 +129,27 @@ def __init__( def normalize(self, archive, logger) -> None: super().normalize(archive, logger) + + +class WignerSeitz(Variables): + """ + Wigner-Seitz points in which the real space is discretized. This variable is used to define `HoppingMatrix(PhysicalProperty)` and + other inter-cell properties. See, e.g., https://en.wikipedia.org/wiki/Wigner–Seitz_cell. + """ + + grid_points = Quantity( + type=np.float64, + shape=['n_grid_points', 3], + description=""" + Wigner-Seitz points with respect to the origin cell, (0, 0, 0). These are 3D arrays stored in fractional coordinates. + """, + ) + + 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, logger) -> None: + super().normalize(archive, logger) diff --git a/tests/test_hopping_matrix.py b/tests/test_hopping_matrix.py new file mode 100644 index 00000000..d5d6d8af --- /dev/null +++ b/tests/test_hopping_matrix.py @@ -0,0 +1,70 @@ +# +# 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 pytest +import numpy as np + +from nomad_simulations.properties import HoppingMatrix, CrystalFieldSplitting + + +class TestHoppingMatrix: + """ + Test the `HoppingMatrix` class defined in `properties/hopping_matrix.py`. + """ + + # ! Include this initial `test_default_quantities` method when testing your PhysicalProperty classes + @pytest.mark.parametrize( + 'n_orbitals, rank', + [ + (None, []), + (3, [3, 3]), + ], + ) + def test_default_quantities(self, n_orbitals: int, rank: list): + """ + Test the default quantities assigned when creating an instance of the `HoppingMatrix` class. + """ + hopping_matrix = HoppingMatrix(n_orbitals=n_orbitals) + assert hopping_matrix.iri == 'http://fairmat-nfdi.eu/taxonomy/HoppingMatrix' + assert hopping_matrix.name == 'HoppingMatrix' + assert hopping_matrix.rank == rank + + +class TestCrystalFieldSplitting: + """ + Test the `CrystalFieldSplitting` class defined in `properties/hopping_matrix.py`. + """ + + # ! Include this initial `test_default_quantities` method when testing your PhysicalProperty classes + @pytest.mark.parametrize( + 'n_orbitals, rank', + [ + (None, []), + (3, [3]), + ], + ) + def test_default_quantities(self, n_orbitals: int, rank: list): + """ + Test the default quantities assigned when creating an instance of the `CrystalFieldSplitting` class. + """ + crystal_field = CrystalFieldSplitting(n_orbitals=n_orbitals) + assert ( + crystal_field.iri == 'http://fairmat-nfdi.eu/taxonomy/CrystalFieldSplitting' + ) + assert crystal_field.name == 'CrystalFieldSplitting' + assert crystal_field.rank == rank