Skip to content

Commit

Permalink
Added testing for Permittivity
Browse files Browse the repository at this point in the history
  • Loading branch information
JosePizarro3 committed May 22, 2024
1 parent 201e25c commit 70c03e9
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 11 deletions.
24 changes: 14 additions & 10 deletions src/nomad_simulations/properties/permittivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import numpy as np
from structlog.stdlib import BoundLogger
from typing import Optional
from typing import Optional, List

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

Expand Down Expand Up @@ -49,7 +49,7 @@ class Permittivity(PhysicalProperty):

value = Quantity(
type=np.complex128,
# unit='joule',
# unit='joule', # TODO check units (they have to match `SpectralProfile.value`)
description="""
Value of the permittivity tensor. If the value does not depend on the scattering vector `q`, then we
can extract the optical absorption spectrum from the imaginary part of the permittivity tensor (this is also called
Expand All @@ -75,7 +75,7 @@ def resolve_type(self) -> str:

def extract_absorption_spectra(
self, logger: BoundLogger
) -> Optional[AbsorptionSpectrum]:
) -> Optional[List[AbsorptionSpectrum]]:
"""
Extract the absorption spectrum from the imaginary part of the permittivity tensor.
"""
Expand All @@ -93,10 +93,14 @@ def extract_absorption_spectra(
'The `permittivity` does not have a `Frequency` variable to extract the absorption spectrum.'
)
return None
# Extract the absorption spectrum from the imaginary part of the permittivity tensor
absorption_spectrum = AbsorptionSpectrum(variables=frequencies)
absorption_spectrum.value = self.value.imag
return absorption_spectrum
# Define the `absorption_spectra` for each principal direction along the diagonal of the `Permittivity.value` as the imaginary part
spectra = []
for i in range(3):
val = self.value[:, i, i].imag
absorption_spectrum = AbsorptionSpectrum(variables=frequencies)
absorption_spectrum.value = val
spectra.append(absorption_spectrum)
return spectra

def normalize(self, archive, logger) -> None:
super().normalize(archive, logger)
Expand All @@ -105,6 +109,6 @@ def normalize(self, archive, logger) -> None:
self.type = self.resolve_type()

# `AbsorptionSpectrum` extraction
absorption_spectrum = self.extract_absorption_spectra(logger)
if absorption_spectrum is not None:
self.m_parent.absorption_spectrum.append(absorption_spectrum)
absorption_spectra = self.extract_absorption_spectra(logger)
if absorption_spectra is not None:
self.m_parent.absorption_spectrum = absorption_spectra
4 changes: 3 additions & 1 deletion src/nomad_simulations/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def is_not_representative(model_system, logger: BoundLogger):

# cannot define typing with `Variables` due to circular import issue
def get_variables(
variables: List[ArchiveSection], variable_cls: ArchiveSection
variables: Optional[List[ArchiveSection]], variable_cls: ArchiveSection
) -> List[ArchiveSection]:
"""
Get the list of variables which are of type `variable_cls` and appear under `variables`.
Expand All @@ -145,6 +145,8 @@ def get_variables(
Returns:
(List[Variables]): The list of variables which are of type `variable_cls`.
"""
if variables is None:
return []
result = []
for var in variables:
if isinstance(var, variable_cls):
Expand Down
128 changes: 128 additions & 0 deletions tests/test_permittivity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#
# 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 typing import List, Optional

from nomad.units import ureg
from nomad.datamodel import EntryArchive

from . import logger

from nomad_simulations import Simulation
from nomad_simulations.model_system import ModelSystem, AtomicCell
from nomad_simulations.atoms_state import AtomsState
from nomad_simulations.outputs import Outputs
from nomad_simulations.properties import Permittivity
from nomad_simulations.variables import Variables, KMesh, Frequency


class TestPermittivity:
"""
Test the `Permittivity` class defined in `properties/permittivity.py`.
"""

# ! Include this initial `test_default_quantities` method when testing your PhysicalProperty classes
def test_default_quantities(self):
"""
Test the default quantities assigned when creating an instance of the `Permittivity` class.
"""
permittivity = Permittivity()
assert permittivity.iri == 'http://fairmat-nfdi.eu/taxonomy/Permittivity'
assert permittivity.name == 'Permittivity'
assert permittivity.rank == [3, 3]

@pytest.mark.parametrize(
'variables, result',
[
(None, 'static'),
([], 'static'),
([KMesh()], 'static'),
([KMesh(), Frequency()], 'dynamic'),
],
)
def test_resolve_type(self, variables: Optional[List[Variables]], result: str):
"""
Test the `resolve_type` method.
"""
permittivity = Permittivity()
if variables is not None:
permittivity.variables = [var for var in variables]
assert permittivity.resolve_type() == result

@pytest.mark.parametrize(
'variables, value, result',
[
# Empty case
(None, None, None),
# No `variables`
([], np.eye(3) * (1 + 1j), None),
# If `variables` contain `KMesh`, we cannot extract absorption spectra
(
[KMesh(points=[[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]])],
np.array([np.eye(3) * k_point * (1 + 1j) for k_point in range(1, 5)]),
None,
),
# Even if `variables` contain `Frequency`, we cannot extract absorption spectra if `value` depends on `KMesh`
(
[
Frequency(points=[0, 1, 2, 3, 4]),
KMesh(points=[[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]),
],
np.array(
[
[
np.eye(3) * k_point * (1 + 1j)
+ np.eye(3) * freq_point * 0.5j
for k_point in range(1, 5)
]
for freq_point in range(5)
]
),
None,
),
# Valid case: `value` does not depend on `KMesh` and we can extract absorption spectra
(
[
Frequency(points=[0, 1, 2, 3, 4]),
],
np.array([np.eye(3) * freq_point * 0.5j for freq_point in range(5)]),
[0.0, 0.5, 1.0, 1.5, 2.0],
),
],
)
def test_extract_absorption_spectra(
self, variables: Optional[List[Variables]], value: Optional[np.array], result
):
"""
Test the `extract_absorption_spectra` method. The `result` in the last valid case corresponds to the imaginary part of
the diagonal of the `Permittivity.value` for each frequency point.
"""
permittivity = Permittivity()
if variables is not None:
permittivity.variables = [var for var in variables]
permittivity.value = value
absorption_spectra = permittivity.extract_absorption_spectra(logger)
if absorption_spectra is not None:
assert len(absorption_spectra) == 3
assert absorption_spectra[0].rank == []
assert len(absorption_spectra[0].value) == len(variables[0].points)
assert np.allclose(absorption_spectra[0].value, result)
else:
assert absorption_spectra == result

0 comments on commit 70c03e9

Please sign in to comment.