From 324398548d867b91d8e637cf6cf4be539b9deb77 Mon Sep 17 00:00:00 2001 From: JosePizarro3 Date: Mon, 3 Jun 2024 15:25:35 +0200 Subject: [PATCH] Deleting all tests to debug --- tests/conftest.py | 320 ---------------------- tests/test.py | 2 + tests/test_atoms_state.py | 367 ------------------------- tests/test_band_gap.py | 131 --------- tests/test_energies.py | 54 ---- tests/test_hopping_matrix.py | 73 ----- tests/test_model_system.py | 441 ------------------------------ tests/test_numerical_settings.py | 398 --------------------------- tests/test_outputs.py | 92 ------- tests/test_permittivity.py | 167 ----------- tests/test_physical_properties.py | 160 ----------- tests/test_spectral_profile.py | 306 --------------------- tests/test_utils.py | 97 ------- tests/test_variables.py | 54 ---- 14 files changed, 2 insertions(+), 2660 deletions(-) delete mode 100644 tests/conftest.py create mode 100644 tests/test.py delete mode 100644 tests/test_atoms_state.py delete mode 100644 tests/test_band_gap.py delete mode 100644 tests/test_energies.py delete mode 100644 tests/test_hopping_matrix.py delete mode 100644 tests/test_model_system.py delete mode 100644 tests/test_numerical_settings.py delete mode 100644 tests/test_outputs.py delete mode 100644 tests/test_permittivity.py delete mode 100644 tests/test_physical_properties.py delete mode 100644 tests/test_spectral_profile.py delete mode 100644 tests/test_utils.py delete mode 100644 tests/test_variables.py diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 20b9011e..00000000 --- a/tests/conftest.py +++ /dev/null @@ -1,320 +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 os -import numpy as np -import pytest -from typing import List, Optional, Dict - -from nomad.units import ureg -from nomad.datamodel import EntryArchive - -from . import logger - -from nomad_simulations.schema import Simulation -from nomad_simulations.schema_sections.model_system import ModelSystem, AtomicCell -from nomad_simulations.schema_sections.atoms_state import AtomsState, OrbitalsState -from nomad_simulations.schema_sections.model_method import ModelMethod -from nomad_simulations.schema_sections.numerical_settings import ( - SelfConsistency, - KSpace, - KMesh as KMeshSettings, - KLinePath as KLinePathSettings, -) -from nomad_simulations.schema_sections.outputs import Outputs, SCFOutputs -from nomad_simulations.schema_sections.variables import Energy2 as Energy -from nomad_simulations.schema_sections.properties import ( - ElectronicBandGap, - DOSProfile, - ElectronicDensityOfStates, -) - -if os.getenv('_PYTEST_RAISE', '0') != '0': - - @pytest.hookimpl(tryfirst=True) - def pytest_exception_interact(call): - raise call.excinfo.value - - @pytest.hookimpl(tryfirst=True) - def pytest_internalerror(excinfo): - raise excinfo.value - - -def generate_simulation( - model_system: Optional[ModelSystem] = None, - model_method: Optional[ModelMethod] = None, - outputs: Optional[Outputs] = None, -) -> Simulation: - """ - Generate a `Simulation` section with the main sub-sections, `ModelSystem`, `ModelMethod`, and `Outputs`. If `ModelSystem` - and `Outputs` are set, then it adds `ModelSystem` as a reference in `Outputs`. - """ - simulation = Simulation() - if model_method is not None: - simulation.model_method.append(model_method) - if model_system is not None: - simulation.model_system.append(model_system) - if outputs is not None: - simulation.outputs.append(outputs) - outputs.model_system_ref = model_system - return simulation - - -def generate_model_system( - type: str = 'original', - system_type: str = 'bulk', - positions: List[List[float]] = [[0, 0, 0], [0.5, 0.5, 0.5]], - lattice_vectors: List[List[float]] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - chemical_symbols: List[str] = ['Ga', 'As'], - orbitals_symbols: List[List[str]] = [['s'], ['px', 'py']], - is_representative: bool = True, - pbc: List[bool] = [False, False, False], -) -> Optional[ModelSystem]: - """ - Generate a `ModelSystem` section with the given parameters. - """ - if len(chemical_symbols) != len(orbitals_symbols): - return None - - model_system = ModelSystem(type=system_type, is_representative=is_representative) - atomic_cell = AtomicCell( - type=type, - positions=positions * ureg.angstrom, - lattice_vectors=lattice_vectors * ureg.angstrom, - periodic_boundary_conditions=pbc, - ) - model_system.cell.append(atomic_cell) - - # Add atoms_state to the model_system - atoms_state = [] - for element, orbitals in zip(chemical_symbols, orbitals_symbols): - orbitals_state = [] - for orbital in orbitals: - orbitals_state.append( - OrbitalsState( - l_quantum_symbol=orbital[0], ml_quantum_symbol=orbital[1:] - ) - ) # TODO add this split setter as part of the `OrbitalsState` methods - atom_state = AtomsState(chemical_symbol=element, orbitals_state=orbitals_state) - # and obtain the atomic number for each AtomsState - atom_state.normalize(EntryArchive(), logger) - atoms_state.append(atom_state) - atomic_cell.atoms_state = atoms_state - return model_system - - -def generate_atomic_cell( - lattice_vectors: List = [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - positions=None, - periodic_boundary_conditions=None, - chemical_symbols: List = ['H', 'H', 'O'], - atomic_numbers: List = [1, 1, 8], -) -> AtomicCell: - """ - Generate an `AtomicCell` section with the given parameters. - """ - # Define positions if not provided - if positions is None and chemical_symbols is not None: - n_atoms = len(chemical_symbols) - positions = [[i / n_atoms, i / n_atoms, i / n_atoms] for i in range(n_atoms)] - # Define periodic boundary conditions if not provided - if periodic_boundary_conditions is None: - periodic_boundary_conditions = [False, False, False] - - # Define the atomic cell - atomic_cell = AtomicCell() - if lattice_vectors: - atomic_cell.lattice_vectors = lattice_vectors * ureg('angstrom') - if positions: - atomic_cell.positions = positions * ureg('angstrom') - if periodic_boundary_conditions: - atomic_cell.periodic_boundary_conditions = periodic_boundary_conditions - - # Add the elements information - for index, atom in enumerate(chemical_symbols): - atom_state = AtomsState() - setattr(atom_state, 'chemical_symbol', atom) - atomic_number = atom_state.resolve_atomic_number(logger) - assert atomic_number == atomic_numbers[index] - atom_state.atomic_number = atomic_number - atomic_cell.atoms_state.append(atom_state) - - return atomic_cell - - -def generate_scf_electronic_band_gap_template( - threshold_change: float = 1e-3, -) -> SCFOutputs: - """ - Generate a `SCFOutputs` section with a template for the electronic_band_gap property. - """ - scf_outputs = SCFOutputs() - # Define a list of scf_steps with values of the total energy like [1, 1.1, 1.11, 1.111, etc], - # such that the difference between one step and the next one decreases a factor of 10. - n_scf_steps = 5 - for i in range(1, n_scf_steps): - value = 1 + sum([1 / (10**j) for j in range(1, i + 1)]) - scf_step = Outputs( - electronic_band_gaps=[ElectronicBandGap(value=value * ureg.joule)] - ) - scf_outputs.scf_steps.append(scf_step) - # Add a SCF calculated PhysicalProperty - scf_outputs.electronic_band_gaps.append(ElectronicBandGap(value=value * ureg.joule)) - # and a `SelfConsistency` ref section - scf_params = SelfConsistency( - threshold_change=threshold_change, threshold_change_unit='joule' - ) - scf_outputs.electronic_band_gaps[0].self_consistency_ref = scf_params - return scf_outputs - - -def generate_simulation_electronic_dos( - energy_points: List[int] = [-3, -2, -1, 0, 1, 2, 3], -) -> Simulation: - """ - Generate a `Simulation` section with an `ElectronicDensityOfStates` section under `Outputs`. It uses - the template of the model_system created with the `generate_model_system` function. - """ - # Create the `Simulation` section to make refs work - model_system = generate_model_system() - outputs = Outputs() - simulation = generate_simulation(model_system=model_system, outputs=outputs) - - # Populating the `ElectronicDensityOfStates` section - variables_energy = [Energy(points=energy_points * ureg.joule)] - electronic_dos = ElectronicDensityOfStates(variables=variables_energy) - outputs.electronic_dos.append(electronic_dos) - # electronic_dos.value = total_dos * ureg('1/joule') - orbital_s_Ga_pdos = DOSProfile( - variables=variables_energy, - entity_ref=model_system.cell[0].atoms_state[0].orbitals_state[0], - ) - orbital_px_As_pdos = DOSProfile( - variables=variables_energy, - entity_ref=model_system.cell[0].atoms_state[1].orbitals_state[0], - ) - orbital_py_As_pdos = DOSProfile( - variables=variables_energy, - entity_ref=model_system.cell[0].atoms_state[1].orbitals_state[1], - ) - orbital_s_Ga_pdos.value = [0.2, 0.5, 0, 0, 0, 0.0, 0.0] * ureg('1/joule') - orbital_px_As_pdos.value = [1.0, 0.2, 0, 0, 0, 0.3, 0.0] * ureg('1/joule') - orbital_py_As_pdos.value = [0.3, 0.5, 0, 0, 0, 0.5, 1.3] * ureg('1/joule') - electronic_dos.projected_dos = [ - orbital_s_Ga_pdos, - orbital_px_As_pdos, - orbital_py_As_pdos, - ] - return simulation - - -def generate_k_line_path( - high_symmetry_path_names: List[str] = ['Gamma', 'X', 'Y', 'Gamma'], - high_symmetry_path_values: List[List[float]] = [ - [0, 0, 0], - [0.5, 0, 0], - [0, 0.5, 0], - [0, 0, 0], - ], -) -> KLinePathSettings: - return KLinePathSettings( - high_symmetry_path_names=high_symmetry_path_names, - high_symmetry_path_values=high_symmetry_path_values, - ) - - -def generate_k_space_simulation( - system_type: str = 'bulk', - is_representative: bool = True, - positions: List[List[float]] = [[0, 0, 0], [0.5, 0.5, 0.5]], - lattice_vectors: List[List[float]] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - chemical_symbols: List[str] = ['Ga', 'As'], - orbitals_symbols: List[List[str]] = [['s'], ['px', 'py']], - pbc: List[bool] = [False, False, False], - reciprocal_lattice_vectors: Optional[List[List[float]]] = [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1], - ], - high_symmetry_path_names: List[str] = ['Gamma', 'X', 'Y', 'Gamma'], - high_symmetry_path_values: List[List[float]] = [ - [0, 0, 0], - [0.5, 0, 0], - [0, 0.5, 0], - [0, 0, 0], - ], - grid=[6, 6, 6], -) -> Simulation: - model_system = generate_model_system( - system_type=system_type, - is_representative=is_representative, - positions=positions, - lattice_vectors=lattice_vectors, - chemical_symbols=chemical_symbols, - orbitals_symbols=orbitals_symbols, - pbc=pbc, - ) - k_space = KSpace() - # adding `reciprocal_lattice_vectors` - if reciprocal_lattice_vectors is not None: - k_space.reciprocal_lattice_vectors = ( - 2 * np.pi * np.array(reciprocal_lattice_vectors) / ureg.angstrom - ) - # adding `KMeshSettings - k_mesh = KMeshSettings(grid=grid) - k_space.k_mesh.append(k_mesh) - # adding `KLinePathSettings` - k_line_path = KLinePathSettings( - high_symmetry_path_names=high_symmetry_path_names, - high_symmetry_path_values=high_symmetry_path_values, - ) - k_space.k_line_path = k_line_path - # appending `KSpace` to `ModelMethod.numerical_settings` - model_method = ModelMethod() - model_method.numerical_settings.append(k_space) - return generate_simulation(model_method=model_method, model_system=model_system) - - -@pytest.fixture(scope='session') -def model_system() -> ModelSystem: - return generate_model_system() - - -@pytest.fixture(scope='session') -def atomic_cell() -> AtomicCell: - return generate_atomic_cell() - - -@pytest.fixture(scope='session') -def scf_electronic_band_gap() -> SCFOutputs: - return generate_scf_electronic_band_gap_template() - - -@pytest.fixture(scope='session') -def simulation_electronic_dos() -> Simulation: - return generate_simulation_electronic_dos() - - -@pytest.fixture(scope='session') -def k_line_path() -> KLinePathSettings: - return generate_k_line_path() - - -@pytest.fixture(scope='session') -def k_space_simulation() -> Simulation: - return generate_k_space_simulation() diff --git a/tests/test.py b/tests/test.py new file mode 100644 index 00000000..d9866b9e --- /dev/null +++ b/tests/test.py @@ -0,0 +1,2 @@ +def dummy_test(): + assert True diff --git a/tests/test_atoms_state.py b/tests/test_atoms_state.py deleted file mode 100644 index 33fcea38..00000000 --- a/tests/test_atoms_state.py +++ /dev/null @@ -1,367 +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 pytest -import numpy as np -from typing import List, Union, Optional, Tuple - -from nomad.units import ureg -from nomad.datamodel import EntryArchive - -from . import logger - -from nomad_simulations.schema_sections.atoms_state import ( - OrbitalsState, - CoreHole, - HubbardInteractions, - AtomsState, -) - - -class TestOrbitalsState: - """ - Test the `OrbitalsState` class defined in atoms_state.py. - """ - - @staticmethod - def add_state( - orbital_state: OrbitalsState, - l_number: int, - ml_number: Optional[int], - ms_number: Optional[float], - j_number: Optional[List[float]], - mj_number: Optional[List[float]], - ) -> None: - """Adds l and ml quantum numbers to the `OrbitalsState` section.""" - orbital_state.l_quantum_number = l_number - orbital_state.ml_quantum_number = ml_number - orbital_state.ms_quantum_number = ms_number - orbital_state.j_quantum_number = j_number - orbital_state.mj_quantum_number = mj_number - - @pytest.mark.parametrize( - 'number_label, values, results', - [ - ('n_quantum_number', [-1, 0, 1, 2], [False, False, True, True]), - ('l_quantum_number', [-2, 0, 1, 2], [False, False, True, True]), - # l_quantum_number == 2 when testing 'ml_quantum_number' - ('ml_quantum_number', [-3, 5, -2, 1], [False, False, True, True]), - ('ms_quantum_number', [0, 10, -0.5, 0.5], [False, False, True, True]), - ], - ) - def test_check_quantum_numbers( - self, number_label: str, values: List[int], results: List[bool] - ): - """ - Test the quantum number check for the `OrbitalsState` section. - """ - orbital_state = OrbitalsState(n_quantum_number=2) - for val, res in zip(values, results): - if number_label == 'ml_quantum_number': - orbital_state.l_quantum_number = 2 - setattr(orbital_state, number_label, val) - assert orbital_state._check_quantum_numbers(logger) == res - - @pytest.mark.parametrize( - 'quantum_name, value, expected_result', - [ - ('l', 0, 's'), - ('l', 1, 'p'), - ('l', 2, 'd'), - ('l', 3, 'f'), - ('l', 4, None), - ('ml', -1, 'x'), - ('ml', 0, 'z'), - ('ml', 1, 'y'), - ('ml', -2, None), - ('ms', -0.5, 'down'), - ('ms', 0.5, 'up'), - ('ms', -0.75, None), - ('no_attribute', None, None), - ], - ) - def test_number_and_symbol( - self, - quantum_name: str, - value: Union[int, float], - expected_result: Optional[str], - ): - """ - Test the number and symbol resolution for each of the quantum numbers defined in the parametrization. - """ - # Adding quantum numbers to the `OrbitalsState` section - orbital_state = OrbitalsState(n_quantum_number=2) - if quantum_name == 'ml': # l_quantum_number must be specified - orbital_state.l_quantum_number = 1 - setattr(orbital_state, f'{quantum_name}_quantum_number', value) - - # Making sure that the `'number'` is assigned - resolved_type = orbital_state.resolve_number_and_symbol( - quantum_name, 'number', logger - ) - assert resolved_type == value - - # Resolving if the counter-type is assigned - resolved_countertype = orbital_state.resolve_number_and_symbol( - quantum_name, 'symbol', logger - ) - assert resolved_countertype == expected_result - - @pytest.mark.parametrize( - 'l_quantum_number, ml_quantum_number, j_quantum_number, mj_quantum_number, ms_quantum_number, degeneracy', - [ - (1, None, None, None, 0.5, 3), - (1, None, None, None, None, 6), - (1, -1, None, None, 0.5, 1), - (1, -1, None, None, None, 2), - # ! `RusselSanders` uses the electronic state, but here we are defining single orbitals. We need new methodology to treat these cases separately - # ! and these tests for j_quantum_number and mj_quantum_number need to be updated. - (1, -1, [1 / 2, 3 / 2], None, None, 6), - (1, -1, [1 / 2, 3 / 2], [-3 / 2, 1 / 2, 1 / 2, 3 / 2], None, 2), - ], - ) - def test_degeneracy( - self, - l_quantum_number: int, - ml_quantum_number: Optional[int], - j_quantum_number: Optional[List[float]], - mj_quantum_number: Optional[List[float]], - ms_quantum_number: Optional[float], - degeneracy: int, - ): - """ - Test the degeneracy of each orbital states defined in the parametrization. - """ - orbital_state = OrbitalsState(n_quantum_number=2) - self.add_state( - orbital_state, - l_quantum_number, - ml_quantum_number, - ms_quantum_number, - j_quantum_number, - mj_quantum_number, - ) - assert orbital_state.resolve_degeneracy() == degeneracy - - def test_normalize(self): - """ - Test the normalization of the `OrbitalsState`. Inputs are defined as the quantities of the `OrbitalsState` section. - """ - orbital_state = OrbitalsState(n_quantum_number=2) - self.add_state(orbital_state, 2, -2, None, None, None) - orbital_state.normalize(EntryArchive(), logger) - assert orbital_state.n_quantum_number == 2 - assert orbital_state.l_quantum_number == 2 - assert orbital_state.l_quantum_symbol == 'd' - assert orbital_state.ml_quantum_number == -2 - assert orbital_state.ml_quantum_symbol == 'xy' - assert orbital_state.degeneracy == 2 - - -class TestCoreHole: - """ - Test the `CoreHole` class defined in atoms_state.py. - """ - - @pytest.mark.parametrize( - 'orbital_ref, degeneracy, n_excited_electrons, occupation', - [ - (OrbitalsState(l_quantum_number=1), 6, 0.5, 5.5), - (OrbitalsState(l_quantum_number=1, ml_quantum_number=-1), 2, 0.5, 1.5), - (None, None, 0.5, None), - ], - ) - def test_occupation( - self, - orbital_ref: Optional[OrbitalsState], - degeneracy: Optional[int], - n_excited_electrons: float, - occupation: Optional[float], - ): - """ - Test the occupation of a core hole for a given set of orbital reference and degeneracy. - """ - core_hole = CoreHole( - orbital_ref=orbital_ref, n_excited_electrons=n_excited_electrons - ) - if orbital_ref is not None: - assert orbital_ref.resolve_degeneracy() == degeneracy - resolved_occupation = core_hole.resolve_occupation(logger) - if resolved_occupation is not None: - assert np.isclose(resolved_occupation, occupation) - else: - assert resolved_occupation == occupation - - @pytest.mark.parametrize( - 'orbital_ref, n_excited_electrons, dscf_state, results', - [ - (OrbitalsState(l_quantum_number=1), -0.5, None, (-0.5, None, None)), - (OrbitalsState(l_quantum_number=1), 0.5, None, (0.5, None, 5.5)), - ( - OrbitalsState(l_quantum_number=1, ml_quantum_number=-1), - 0.5, - None, - (0.5, None, 1.5), - ), - (OrbitalsState(l_quantum_number=1), 0.5, 'initial', (None, 1, None)), - (OrbitalsState(l_quantum_number=1), 0.5, 'final', (0.5, None, 5.5)), - (None, 0.5, None, (0.5, None, None)), - ], - ) - def test_normalize( - self, - orbital_ref: Optional[OrbitalsState], - n_excited_electrons: Optional[float], - dscf_state: Optional[str], - results: Tuple[Optional[float], Optional[float], Optional[float]], - ): - """ - Test the normalization of the `CoreHole`. Inputs are defined as the quantities of the `CoreHole` section. - """ - core_hole = CoreHole( - orbital_ref=orbital_ref, - n_excited_electrons=n_excited_electrons, - dscf_state=dscf_state, - ) - core_hole.normalize(EntryArchive(), logger) - assert core_hole.n_excited_electrons == results[0] - if core_hole.orbital_ref: - assert core_hole.orbital_ref.degeneracy == results[1] - assert core_hole.orbital_ref.occupation == results[2] - - -class TestHubbardInteractions: - """ - Test the `HubbardInteractions` class defined in atoms_state.py. - """ - - @pytest.mark.parametrize( - 'slater_integrals, results', - [ - ([3.0, 2.0, 1.0], (0.1429146, -0.0357286, 0.0893216)), - (None, (None, None, None)), - ([3.0, 2.0, 1.0, 0.5], (None, None, None)), - ], - ) - def test_u_interactions( - self, - slater_integrals: Optional[List[float]], - results: Tuple[Optional[float], Optional[float], Optional[float]], - ): - """ - Test the Hubbard interactions `U`, `U'`, and `J` for a given set of Slater integrals. - """ - # Adding `slater_integrals` to the `HubbardInteractions` section - hubbard_interactions = HubbardInteractions() - if slater_integrals is not None: - hubbard_interactions.slater_integrals = slater_integrals * ureg.eV - - # Resolving U, U', and J from class method - ( - u_interaction, - u_interorbital_interaction, - j_hunds_coupling, - ) = hubbard_interactions.resolve_u_interactions(logger) - - if None not in (u_interaction, u_interorbital_interaction, j_hunds_coupling): - assert np.isclose(u_interaction.to('eV').magnitude, results[0]) - assert np.isclose(u_interorbital_interaction.to('eV').magnitude, results[1]) - assert np.isclose(j_hunds_coupling.to('eV').magnitude, results[2]) - else: - assert ( - u_interaction, - u_interorbital_interaction, - j_hunds_coupling, - ) == results - - @pytest.mark.parametrize( - 'u_interaction, j_local_exchange_interaction, u_effective', - [ - (3.0, 1.0, 2.0), - (-3.0, 1.0, None), - (3.0, None, 3.0), - (None, 1.0, None), - ], - ) - def test_u_effective( - self, - u_interaction: Optional[float], - j_local_exchange_interaction: Optional[float], - u_effective: Optional[float], - ): - """ - Test the effective Hubbard interaction `U_eff` for a given set of Hubbard interactions `U` and `J`. - """ - # Adding `u_interaction` and `j_local_exchange_interaction` to the `HubbardInteractions` section - hubbard_interactions = HubbardInteractions() - if u_interaction is not None: - hubbard_interactions.u_interaction = u_interaction * ureg.eV - if j_local_exchange_interaction is not None: - hubbard_interactions.j_local_exchange_interaction = ( - j_local_exchange_interaction * ureg.eV - ) - - # Resolving Ueff from class method - resolved_u_effective = hubbard_interactions.resolve_u_effective(logger) - if resolved_u_effective is not None: - assert np.isclose(resolved_u_effective.to('eV').magnitude, u_effective) - else: - assert resolved_u_effective == u_effective - - def test_normalize(self): - """ - Test the normalization of the `HubbardInteractions`. Inputs are defined as the quantities of the `HubbardInteractions` section. - """ - # ? Is this enough for testing? Can we do more? - hubbard_interactions = HubbardInteractions( - u_interaction=3.0 * ureg.eV, - u_interorbital_interaction=1.0 * ureg.eV, - j_hunds_coupling=2.0 * ureg.eV, - j_local_exchange_interaction=2.0 * ureg.eV, - ) - hubbard_interactions.normalize(EntryArchive(), logger) - assert np.isclose(hubbard_interactions.u_effective.to('eV').magnitude, 1.0) - assert np.isclose(hubbard_interactions.u_interaction.to('eV').magnitude, 3.0) - - -class TestAtomsState: - """ - Tests the `AtomsState` class defined in atoms_state.py. - """ - - @pytest.mark.parametrize( - 'chemical_symbol, atomic_number', - [ - ('Fe', 26), - ('H', 1), - ('Cu', 29), - ('O', 8), - ], - ) - def test_chemical_symbol_and_atomic_number( - self, chemical_symbol: str, atomic_number: int - ): - """ - Test the `chemical_symbol` and `atomic_number` resolution for the `AtomsState` section. - """ - # Testing `chemical_symbol` - atom_state = AtomsState(chemical_symbol=chemical_symbol) - assert atom_state.resolve_atomic_number(logger) == atomic_number - # Testing `atomic_number` - atom_state.atomic_number = atomic_number - assert atom_state.resolve_chemical_symbol(logger) == chemical_symbol diff --git a/tests/test_band_gap.py b/tests/test_band_gap.py deleted file mode 100644 index 9a0cbc8f..00000000 --- a/tests/test_band_gap.py +++ /dev/null @@ -1,131 +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 pytest -import numpy as np -from typing import Optional, List, Union - -from nomad.units import ureg -from nomad.datamodel import EntryArchive - -from . import logger - -from nomad_simulations.schema_sections.properties import ElectronicBandGap -from nomad_simulations.schema_sections.variables import Temperature - - -class TestElectronicBandGap: - """ - Test the `ElectronicBandGap` class defined in `properties/band_gap.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 `ElectronicBandGap` class. - """ - electronic_band_gap = ElectronicBandGap() - assert ( - electronic_band_gap.iri - == 'http://fairmat-nfdi.eu/taxonomy/ElectronicBandGap' - ) - assert electronic_band_gap.name == 'ElectronicBandGap' - assert electronic_band_gap.rank == [] - - @pytest.mark.parametrize( - 'value, result', - [ - (0.0, 0.0), - (1.0, 1.0), - (-1.0, None), - ([1.0, 2.0, -1.0], None), - ], - ) - def test_check_negative_values( - self, value: Union[List[float], float], result: float - ): - """ - Test the `_check_negative_values` method. - """ - if isinstance(value, list): - electronic_band_gap = ElectronicBandGap( - variables=[Temperature(points=[1, 2, 3] * ureg.kelvin)] - ) - else: - electronic_band_gap = ElectronicBandGap() - electronic_band_gap.value = value * ureg.joule - checked_value = electronic_band_gap._check_negative_values(logger) - if checked_value is not None: - assert np.isclose(checked_value.magnitude, result) - else: - assert checked_value == result - - @pytest.mark.parametrize( - 'momentum_transfer, type, result', - [ - (None, None, None), - (None, 'direct', 'direct'), - (None, 'indirect', 'indirect'), - ([], None, None), - ([], 'direct', 'direct'), - ([], 'indirect', 'indirect'), - ([[0, 0, 0]], None, None), - ([[0, 0, 0]], 'direct', None), - ([[0, 0, 0]], 'indirect', None), - ([[0, 0, 0], [0, 0, 0]], None, 'direct'), - ([[0, 0, 0], [0, 0, 0]], 'direct', 'direct'), - ([[0, 0, 0], [0, 0, 0]], 'indirect', 'direct'), - ([[0, 0, 0], [0.5, 0.5, 0.5]], None, 'indirect'), - ([[0, 0, 0], [0.5, 0.5, 0.5]], 'direct', 'indirect'), - ([[0, 0, 0], [0.5, 0.5, 0.5]], 'indirect', 'indirect'), - ], - ) - def test_resolve_type( - self, momentum_transfer: Optional[List[float]], type: str, result: Optional[str] - ): - """ - Test the `resolve_type` method. - """ - electronic_band_gap = ElectronicBandGap( - variables=[], - momentum_transfer=momentum_transfer, - type=type, - ) - assert electronic_band_gap.resolve_type(logger) == result - - def test_normalize(self): - """ - Test the `normalize` method for two different ElectronicBandGap instantiations, one with a scalar - `value` and another with a temperature-dependent `value` - """ - scalar_band_gap = ElectronicBandGap(variables=[], type='direct') - scalar_band_gap.value = 1.0 * ureg.joule - scalar_band_gap.normalize(EntryArchive(), logger) - assert scalar_band_gap.type == 'direct' - assert np.isclose(scalar_band_gap.value.magnitude, 1.0) - - t_dependent_band_gap = ElectronicBandGap( - variables=[Temperature(points=[0, 10, 20, 30] * ureg.kelvin)], - type='direct', - ) - t_dependent_band_gap.value = [1.0, 2.0, 3.0, 4.0] * ureg.joule - t_dependent_band_gap.normalize(EntryArchive(), logger) - assert t_dependent_band_gap.type == 'direct' - assert ( - np.isclose(t_dependent_band_gap.value.magnitude, [1.0, 2.0, 3.0, 4.0]) - ).all() diff --git a/tests/test_energies.py b/tests/test_energies.py deleted file mode 100644 index 8d5ea540..00000000 --- a/tests/test_energies.py +++ /dev/null @@ -1,54 +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. -# - -from nomad_simulations.schema_sections.properties import FermiLevel, ChemicalPotential - - -class TestFermiLevel: - """ - Test the `FermiLevel` class defined in `properties/energies.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 `FermiLevel` class. - """ - fermi_level = FermiLevel() - assert fermi_level.iri == 'http://fairmat-nfdi.eu/taxonomy/FermiLevel' - assert fermi_level.name == 'FermiLevel' - assert fermi_level.rank == [] - - -class TestChemicalPotential: - """ - Test the `ChemicalPotential` class defined in `properties/energies.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 `ChemicalPotential` class. - """ - chemical_potential = ChemicalPotential() - assert ( - chemical_potential.iri - == 'http://fairmat-nfdi.eu/taxonomy/ChemicalPotential' - ) - assert chemical_potential.name == 'ChemicalPotential' - assert chemical_potential.rank == [] diff --git a/tests/test_hopping_matrix.py b/tests/test_hopping_matrix.py deleted file mode 100644 index b6c1bdbb..00000000 --- a/tests/test_hopping_matrix.py +++ /dev/null @@ -1,73 +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 pytest -import numpy as np - -from nomad_simulations.schema_sections.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 diff --git a/tests/test_model_system.py b/tests/test_model_system.py deleted file mode 100644 index 698a3ce3..00000000 --- a/tests/test_model_system.py +++ /dev/null @@ -1,441 +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 pytest -import numpy as np -from typing import List, Optional - -from nomad.datamodel import EntryArchive - -from . import logger -from .conftest import generate_atomic_cell - -from nomad_simulations.schema_sections.model_system import ( - Symmetry, - ChemicalFormula, - ModelSystem, -) - - -class TestAtomicCell: - """ - Test the `AtomicCell`, `Cell` and `GeometricSpace` classes defined in model_system.py - """ - - @pytest.mark.parametrize( - 'chemical_symbols, atomic_numbers, formula, lattice_vectors, positions, periodic_boundary_conditions', - [ - ( - ['H', 'H', 'O'], - [1, 1, 8], - 'H2O', - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [False, False, False], - ), # full atomic cell - ( - [], - [1, 1, 8], - 'H2O', - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [False, False, False], - ), # missing chemical_symbols - ( - ['H', 'H', 'O'], - [1, 1, 8], - 'H2O', - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [], - [False, False, False], - ), # missing positions - ( - ['H', 'H', 'O'], - [1, 1, 8], - 'H2O', - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1], [2, 2, 2]], - [False, False, False], - ), # chemical_symbols and positions with different lengths - ( - ['H', 'H', 'O'], - [1, 1, 8], - 'H2O', - [], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [False, False, False], - ), # missing lattice_vectors - ], - ) - def test_generate_ase_atoms( - self, - chemical_symbols: List[str], - atomic_numbers: List[int], - formula: str, - lattice_vectors: List[List[float]], - positions: List[List[float]], - periodic_boundary_conditions: List[bool], - ): - """ - Test the creation of `ase.Atoms` from `AtomicCell`. - """ - atomic_cell = generate_atomic_cell( - lattice_vectors, - positions, - periodic_boundary_conditions, - chemical_symbols, - atomic_numbers, - ) - - # Test `to_ase_atoms` function - ase_atoms = atomic_cell.to_ase_atoms(logger) - if not chemical_symbols or len(chemical_symbols) != len(positions): - assert ase_atoms is None - else: - if lattice_vectors: - assert (ase_atoms.cell == lattice_vectors).all() - else: - assert (ase_atoms.cell == [0, 0, 0]).all() - assert (ase_atoms.positions == positions).all() - assert (ase_atoms.pbc == periodic_boundary_conditions).all() - assert (ase_atoms.symbols.numbers == atomic_numbers).all() - assert ase_atoms.symbols.get_chemical_formula() == formula - - @pytest.mark.parametrize( - 'chemical_symbols, atomic_numbers, lattice_vectors, positions, vectors_results, angles_results, volume', - [ - ( - ['H', 'H', 'O'], - [1, 1, 8], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [1.0, 1.0, 1.0], - [90.0, 90.0, 90.0], - 1.0, - ), # full atomic cell - ( - ['H', 'H', 'O'], - [1, 1, 8], - [[1.2, 2.3, 0], [1.2, -2.3, 0], [0, 0, 1]], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [2.59422435, 2.59422435, 1.0], - [90.0, 90.0, 124.8943768], - 5.52, - ), # full atomic cell with different lattice_vectors - ( - [], - [1, 1, 8], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [None, None, None], - [None, None, None], - None, - ), # missing chemical_symbols - ( - ['H', 'H', 'O'], - [1, 1, 8], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [], - [None, None, None], - [None, None, None], - None, - ), # missing positions - ( - ['H', 'H', 'O'], - [1, 1, 8], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1], [2, 2, 2]], - [None, None, None], - [None, None, None], - None, - ), # chemical_symbols and positions with different lengths - ( - ['H', 'H', 'O'], - [1, 1, 8], - [], - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [0.0, 0.0, 0.0], - [90.0, 90.0, 90.0], - 0.0, - ), # missing lattice_vectors - ], - ) - def test_geometric_space( - self, - chemical_symbols: List[str], - atomic_numbers: List[int], - lattice_vectors: List[List[float]], - positions: List[List[float]], - vectors_results: List[Optional[float]], - angles_results: List[Optional[float]], - volume: Optional[float], - ): - """ - Test the `GeometricSpace` quantities normalization from `AtomicCell`. - """ - pbc = [False, False, False] - atomic_cell = generate_atomic_cell( - lattice_vectors, - positions, - pbc, - chemical_symbols, - atomic_numbers, - ) - - # Get `GeometricSpace` quantities via normalization of `AtomicCell` - atomic_cell.normalize(EntryArchive(), logger) - # Testing lengths of cell vectors - for index, name in enumerate( - ['length_vector_a', 'length_vector_b', 'length_vector_c'] - ): - quantity = getattr(atomic_cell, name) - if quantity is not None: - assert np.isclose( - quantity.to('angstrom').magnitude, - vectors_results[index], - ) - else: - assert quantity == vectors_results[index] - # Testing angles between cell vectors - for index, name in enumerate( - ['angle_vectors_b_c', 'angle_vectors_a_c', 'angle_vectors_a_b'] - ): - quantity = getattr(atomic_cell, name) - if quantity is not None: - assert np.isclose( - quantity.to('degree').magnitude, - angles_results[index], - ) - else: - assert quantity == angles_results[index] - # Testing volume - if atomic_cell.volume is not None: - assert np.isclose(atomic_cell.volume.to('angstrom^3').magnitude, volume) - else: - assert atomic_cell.volume == volume - - -class TestModelSystem: - """ - Test the `ModelSystem`, `Symmetry` and `ChemicalFormula` classes defined in model_system.py - """ - - def test_empty_chemical_formula(self): - """ - Test the empty `ChemicalFormula` normalization if a sibling `AtomicCell` is not provided. - """ - chemical_formula = ChemicalFormula() - chemical_formula.normalize(EntryArchive(), logger) - for name in ['descriptive', 'reduced', 'iupac', 'hill', 'anonymous']: - assert getattr(chemical_formula, name) is None - - @pytest.mark.parametrize( - 'chemical_symbols, atomic_numbers, formulas', - [ - ( - ['H', 'H', 'O'], - [1, 1, 8], - ['H2O', 'H2O', 'H2O', 'H2O', 'A2B'], - ), - ( - ['O', 'O', 'O', 'O', 'La', 'Cu', 'Cu'], - [8, 8, 8, 8, 57, 29, 29], - ['LaCu2O4', 'Cu2LaO4', 'LaCu2O4', 'Cu2LaO4', 'A4B2C'], - ), - ( - ['O', 'La', 'As', 'Fe', 'C'], - [8, 57, 33, 26, 6], - ['CAsFeLaO', 'AsCFeLaO', 'LaFeCAsO', 'CAsFeLaO', 'ABCDE'], - ), - ], - ) - def test_chemical_formula( - self, - chemical_symbols: List[str], - atomic_numbers: List[int], - formulas: List[str], - ): - """ - Test the `ChemicalFormula` normalization if a sibling `AtomicCell` is created, and thus the `Formula` class can be used. - """ - atomic_cell = generate_atomic_cell( - chemical_symbols=chemical_symbols, atomic_numbers=atomic_numbers - ) - chemical_formula = ChemicalFormula() - model_system = ModelSystem(chemical_formula=chemical_formula) - model_system.cell.append(atomic_cell) - chemical_formula.normalize(EntryArchive(), logger) - for index, name in enumerate( - ['descriptive', 'reduced', 'iupac', 'hill', 'anonymous'] - ): - assert getattr(chemical_formula, name) == formulas[index] - - @pytest.mark.parametrize( - 'positions, pbc, system_type, dimensionality', - [ - ( - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - None, - 'molecule / cluster', - 0, - ), - ( - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [False, False, False], - 'molecule / cluster', - 0, - ), - ( - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [True, False, False], - '1D', - 1, - ), - ( - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [True, True, False], - '2D', - 2, - ), - ( - [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]], - [True, True, True], - 'bulk', - 3, - ), - ], - ) - def test_system_type_and_dimensionality( - self, - positions: List[List[float]], - pbc: Optional[List[bool]], - system_type: str, - dimensionality: int, - ): - """ - Test the `ModelSystem` normalization of `type` and `dimensionality` from `AtomicCell`. - """ - atomic_cell = generate_atomic_cell( - positions=positions, periodic_boundary_conditions=pbc - ) - ase_atoms = atomic_cell.to_ase_atoms(logger) - model_system = ModelSystem() - model_system.cell.append(atomic_cell) - ( - resolved_system_type, - resolved_dimensionality, - ) = model_system.resolve_system_type_and_dimensionality(ase_atoms, logger) - assert resolved_system_type == system_type - assert resolved_dimensionality == dimensionality - - def test_symmetry(self): - """ - Test the `Symmetry` normalization from a sibling `AtomicCell` section. - """ - atomic_cell = generate_atomic_cell( - periodic_boundary_conditions=[True, True, True] - ) - assert ( - np.isclose( - atomic_cell.lattice_vectors.to('angstrom').magnitude, - np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), - ) - ).all() - symmetry = Symmetry() - primitive, conventional = symmetry.resolve_bulk_symmetry(atomic_cell, logger) - assert symmetry.bravais_lattice == 'hR' - assert symmetry.hall_symbol == '-R 3 2"' - assert symmetry.point_group_symbol == '-3m' - assert symmetry.space_group_number == 166 - assert symmetry.space_group_symbol == 'R-3m' - assert primitive.type == 'primitive' - assert primitive.periodic_boundary_conditions == [False, False, False] - assert ( - np.isclose( - primitive.lattice_vectors.to('angstrom').magnitude, - np.array( - [ - [7.07106781e-01, 4.08248290e-01, 5.77350269e-01], - [-7.07106781e-01, 4.08248290e-01, 5.77350269e-01], - [1.08392265e-17, -8.16496581e-01, 5.77350269e-01], - ] - ), - ) - ).all() - assert conventional.type == 'conventional' - assert ( - np.isclose( - conventional.lattice_vectors.to('angstrom').magnitude, - np.array( - [ - [1.41421356, 0.0, 0.0], - [-0.70710678, 1.22474487, 0.0], - [0.0, 0.0, 1.73205081], - ] - ), - ) - ).all() - - def test_no_representative(self): - """ - Test the normalization of a `ModelSystem` is not run if it is not representative. - """ - model_system = ModelSystem(is_representative=False) - model_system.normalize(EntryArchive(), logger) - assert model_system.type is None - assert model_system.dimensionality is None - - def test_empty_atomic_cell(self): - """ - Test the normalization of a `ModelSystem` is not run if it has no `AtomicCell` child section. - """ - model_system = ModelSystem(is_representative=True) - model_system.normalize(EntryArchive(), logger) - assert model_system.type is None - assert model_system.dimensionality is None - - def test_normalize(self): - """ - Test the full normalization of a representative `ModelSystem`. - """ - atomic_cell = generate_atomic_cell( - periodic_boundary_conditions=[True, True, True] - ) - model_system = ModelSystem(is_representative=True) - model_system.cell.append(atomic_cell) - model_system.normalize(EntryArchive(), logger) - # Basic quantities assertions - assert model_system.type == 'bulk' - assert model_system.dimensionality == 3 - # AtomicCell - assert len(model_system.cell) == 3 - assert model_system.cell[0].type == 'original' - assert model_system.cell[1].type == 'primitive' - assert model_system.cell[2].type == 'conventional' - # Symmetry - assert len(model_system.symmetry) == 1 - assert model_system.symmetry[0].bravais_lattice == 'hR' - assert model_system.symmetry[0].atomic_cell_ref == model_system.cell[2] - # ChemicalFormula - assert model_system.chemical_formula.descriptive == 'H2O' - # ElementalComposition - assert len(model_system.elemental_composition) == 2 - assert model_system.elemental_composition[0].element == 'H' - assert np.isclose(model_system.elemental_composition[0].atomic_fraction, 2 / 3) - assert model_system.elemental_composition[1].element == 'O' - assert np.isclose(model_system.elemental_composition[1].atomic_fraction, 1 / 3) diff --git a/tests/test_numerical_settings.py b/tests/test_numerical_settings.py deleted file mode 100644 index 00fbf060..00000000 --- a/tests/test_numerical_settings.py +++ /dev/null @@ -1,398 +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 pytest -import numpy as np -from typing import Optional, List - -from nomad.units import ureg -from nomad.datamodel import EntryArchive - -from nomad_simulations.schema_sections.numerical_settings import ( - KMesh, - KLinePath, - KSpaceFunctionalities, -) - -from . import logger -from .conftest import generate_k_line_path, generate_k_space_simulation - - -class TestKSpace: - """ - Test the `KSpace` class defined in `numerical_settings.py`. - """ - - @pytest.mark.parametrize( - 'system_type, is_representative, reciprocal_lattice_vectors, result', - [ - ('bulk', False, None, None), - ('atom', True, None, None), - ('bulk', True, None, [[1, 0, 0], [0, 1, 0], [0, 0, 1]]), - ( - 'bulk', - True, - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - ), - ], - ) - def test_normalize( - self, - system_type: Optional[str], - is_representative: bool, - reciprocal_lattice_vectors: Optional[List[List[float]]], - result: List[List[float]], - ): - """ - Test the `normalize` method. This also test the `resolve_reciprocal_lattice_vectors` method. - """ - simulation = generate_k_space_simulation( - system_type=system_type, - is_representative=is_representative, - reciprocal_lattice_vectors=reciprocal_lattice_vectors, - ) - k_space = simulation.model_method[0].numerical_settings[0] - assert k_space.name == 'KSpace' - k_space.normalize(EntryArchive(), logger) - if k_space.reciprocal_lattice_vectors is not None: - value = k_space.reciprocal_lattice_vectors.to('1/angstrom').magnitude / ( - 2 * np.pi - ) - assert np.allclose(value, result) - else: - assert k_space.reciprocal_lattice_vectors == result - - -class TestKSpaceFunctionalities: - """ - Test the `KSpaceFunctionalities` class defined in `numerical_settings.py`. - """ - - @pytest.mark.parametrize( - 'reciprocal_lattice_vectors, check_grid, grid, result', - [ - (None, None, None, False), - ([[1, 0, 0], [0, 1, 0], [0, 0, 1]], False, None, True), - ([[1, 0, 0], [0, 1, 0], [0, 0, 1]], True, None, False), - ([[1, 0, 0], [0, 1, 0], [0, 0, 1]], True, [6, 6, 6, 4], False), - ([[1, 0, 0], [0, 1, 0], [0, 0, 1]], True, [6, 6, 6], True), - ], - ) - def test_check_reciprocal_lattice_vectors( - self, - reciprocal_lattice_vectors: Optional[List[List[float]]], - check_grid: bool, - grid: Optional[List[int]], - result: bool, - ): - """ - Test the `_check_reciprocal_lattice_vectors` private method. - """ - check = KSpaceFunctionalities()._check_reciprocal_lattice_vectors( - reciprocal_lattice_vectors=reciprocal_lattice_vectors, - logger=logger, - check_grid=check_grid, - grid=grid, - ) - assert check == result - - def test_resolve_high_symmetry_points(self): - """ - Test the `resolve_high_symmetry_points` method. Only testing the valid situation in which the `ModelSystem` normalization worked. - """ - # `ModelSystem.normalize()` need to extract `bulk` as a type. - simulation = generate_k_space_simulation( - pbc=[True, True, True], - ) - model_systems = simulation.model_system - # normalize to extract symmetry - simulation.model_system[0].normalize(EntryArchive(), logger) - - # Testing the functionality method - high_symmetry_points = KSpaceFunctionalities().resolve_high_symmetry_points( - model_systems=model_systems, logger=logger - ) - assert len(high_symmetry_points) == 4 - assert high_symmetry_points == { - 'Gamma': [0, 0, 0], - 'M': [0.5, 0.5, 0], - 'R': [0.5, 0.5, 0.5], - 'X': [0, 0.5, 0], - } - - -class TestKMesh: - """ - Test the `KMesh` class defined in `numerical_settings.py`. - """ - - @pytest.mark.parametrize( - 'center, grid, result_points, result_offset', - [ - # No `center` and `grid` - (None, None, None, None), - # No `grid` - ('Gamma-centered', None, None, None), - ('Monkhorst-Pack', None, None, None), - # `center` is `'Gamma-centered'` - ( - 'Gamma-centered', - [2, 2, 2], - [[0.0, 1.0, 0.0, 1.0, 0.0, 1.0]], # ! this result is weird @ndaelman-hu - [0.0, 0.0, 0.0], - ), - # `center` is `'Monkhorst-Pack'` - ( - 'Monkhorst-Pack', - [2, 2, 2], - [ - [-0.25, -0.25, -0.25], - [-0.25, -0.25, 0.25], - [-0.25, 0.25, -0.25], - [-0.25, 0.25, 0.25], - [0.25, -0.25, -0.25], - [0.25, -0.25, 0.25], - [0.25, 0.25, -0.25], - [0.25, 0.25, 0.25], - ], - [0.0, 0.0, 0.0], - ), - # Invalid `grid` - ('Monkhorst-Pack', [-2, 2, 2], None, None), - ], - ) - def test_resolve_points_and_offset( - self, center, grid, result_points, result_offset - ): - """ - Test the `resolve_points_and_offset` method. - """ - k_mesh = KMesh(center=center) - if grid is not None: - k_mesh.grid = grid - points, offset = k_mesh.resolve_points_and_offset(logger) - if points is not None: - assert np.allclose(points, result_points) - else: - assert points == result_points - if offset is not None: - assert np.allclose(offset, result_offset) - else: - assert offset == result_offset - - @pytest.mark.parametrize( - 'system_type, is_representative, grid, reciprocal_lattice_vectors, result_get_k_line_density, result_k_line_density', - [ - # No `grid` and `reciprocal_lattice_vectors` - ('bulk', False, None, None, None, None), - # No `reciprocal_lattice_vectors` - ('bulk', False, [6, 6, 6], None, None, None), - # No `grid` - ('bulk', False, None, [[1, 0, 0], [0, 1, 0], [0, 0, 1]], None, None), - # `is_representative` set to False - ( - 'bulk', - False, - [6, 6, 6], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - 0.954929658, - None, - ), - # `system_type` is not 'bulk' - ( - 'atom', - True, - [6, 6, 6], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - 0.954929658, - None, - ), - # All parameters are set - ( - 'bulk', - True, - [6, 6, 6], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - 0.954929658, - 0.954929658, - ), - ], - ) - def test_resolve_k_line_density( - self, - system_type: Optional[str], - is_representative: bool, - grid: Optional[List[int]], - reciprocal_lattice_vectors: Optional[List[List[float]]], - result_get_k_line_density: Optional[float], - result_k_line_density: Optional[float], - ): - """ - Test the `resolve_k_line_density` and `get_k_line_density` methods - """ - simulation = generate_k_space_simulation( - system_type=system_type, - is_representative=is_representative, - reciprocal_lattice_vectors=reciprocal_lattice_vectors, - grid=grid, - ) - k_space = simulation.model_method[0].numerical_settings[0] - reciprocal_lattice_vectors = k_space.reciprocal_lattice_vectors - k_mesh = k_space.k_mesh[0] - model_systems = simulation.model_system - # Applying method `get_k_line_density` - get_k_line_density_value = k_mesh.get_k_line_density( - reciprocal_lattice_vectors=reciprocal_lattice_vectors, logger=logger - ) - if get_k_line_density_value is not None: - assert np.isclose( - get_k_line_density_value.to('angstrom').magnitude, - result_get_k_line_density, - ) - else: - assert get_k_line_density_value == result_get_k_line_density - # Applying method `resolve_k_line_density` - k_line_density = k_mesh.resolve_k_line_density( - model_systems=model_systems, - reciprocal_lattice_vectors=reciprocal_lattice_vectors, - logger=logger, - ) - if k_line_density is not None: - assert np.isclose( - k_line_density.to('angstrom').magnitude, result_k_line_density - ) - else: - assert k_line_density == result_k_line_density - - -class TestKLinePath: - """ - Test the `KLinePath` class defined in `numerical_settings.py`. - """ - - @pytest.mark.parametrize( - 'high_symmetry_path_names, high_symmetry_path_values, result', - [ - (None, None, False), - ([], [], False), - (['Gamma', 'X', 'Y'], None, False), - ([], [[0, 0, 0], [0.5, 0, 0], [0, 0.5, 0]], False), - (['Gamma', 'X', 'Y'], [[0, 0, 0], [0.5, 0, 0], [0, 0.5, 0]], True), - ], - ) - def test_check_high_symmetry_path( - self, - high_symmetry_path_names: List[str], - high_symmetry_path_values: List[List[float]], - result: bool, - ): - """ - Test the `_check_high_symmetry_path` private method. - """ - k_line_path = generate_k_line_path( - high_symmetry_path_names=high_symmetry_path_names, - high_symmetry_path_values=high_symmetry_path_values, - ) - assert k_line_path._check_high_symmetry_path(logger) == result - - @pytest.mark.parametrize( - 'reciprocal_lattice_vectors, high_symmetry_path_names, result', - [ - (None, None, []), - ([[1, 0, 0], [0, 1, 0], [0, 0, 1]], None, []), - ( - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - ['Gamma', 'X', 'R'], - [[0, 0, 0], [0, 0.5, 0], [0.5, 0.5, 0.5]], - ), - ], - ) - def test_resolve_high_symmetry_path_values( - self, - reciprocal_lattice_vectors: Optional[List[List[float]]], - high_symmetry_path_names: List[str], - result: List[float], - ): - """ - Test the `resolve_high_symmetry_path_values` method. Only testing the valid situation in which the `ModelSystem` normalization worked. - """ - # `ModelSystem.normalize()` need to extract `bulk` as a type. - simulation = generate_k_space_simulation( - pbc=[True, True, True], - reciprocal_lattice_vectors=reciprocal_lattice_vectors, - high_symmetry_path_names=high_symmetry_path_names, - high_symmetry_path_values=None, - ) - model_system = simulation.model_system[0] - model_system.normalize(EntryArchive(), logger) # normalize to extract symmetry - - # `KLinePath` can be understood as a `KMeshBase` section - k_line_path = simulation.model_method[0].numerical_settings[0].k_line_path - high_symmetry_points_values = k_line_path.resolve_high_symmetry_path_values( - simulation.model_system, reciprocal_lattice_vectors, logger - ) - assert high_symmetry_points_values == result - - def test_get_high_symmetry_path_norm(self, k_line_path: KLinePath): - """ - Test the `get_high_symmetry_path_norm` method. - """ - rlv = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) * ureg('1/meter') - high_symmetry_path_norms = k_line_path.get_high_symmetry_path_norms( - reciprocal_lattice_vectors=rlv, logger=logger - ) - hs_points = [0, 0.5, 0.5 + 1 / np.sqrt(2), 1 + 1 / np.sqrt(2)] - for i, val in enumerate(hs_points): - assert np.isclose(high_symmetry_path_norms[i].magnitude, val) - - def test_resolve_points(self, k_line_path: KLinePath): - """ - Test the `resolve_points` method. - """ - rlv = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) * ureg('1/meter') - hs_points = [0, 0.5, 0.5 + 1 / np.sqrt(2), 1 + 1 / np.sqrt(2)] - # Define paths - gamma_x = np.linspace(hs_points[0], hs_points[1], num=5) - x_y = np.linspace(hs_points[1], hs_points[2], num=5) - y_gamma = np.linspace(hs_points[2], hs_points[3], num=5) - points_norm = np.concatenate((gamma_x, x_y, y_gamma)) - k_line_path.resolve_points( - points_norm=points_norm, reciprocal_lattice_vectors=rlv, logger=logger - ) - assert len(points_norm) == len(k_line_path.points) - points = np.array( - [ - [0.0, 0.0, 0.0], # 'Gamma' - [0.125, 0.0, 0.0], - [0.25, 0.0, 0.0], - [0.375, 0.0, 0.0], - [0.5, 0.0, 0.0], # 'X' - [0.4, 0.1, 0.0], - [0.3, 0.2, 0.0], - [0.2, 0.3, 0.0], - [0.1, 0.4, 0.0], - [0.0, 0.5, 0.0], # 'Y' - [0.0, 0.4, 0.0], - [0.0, 0.3, 0.0], - [0.0, 0.2, 0.0], - [0.0, 0.1, 0.0], - [0.0, 0.0, 0.0], # 'Gamma' - ] - ) - assert np.allclose(k_line_path.points, points) diff --git a/tests/test_outputs.py b/tests/test_outputs.py deleted file mode 100644 index cdf6ed46..00000000 --- a/tests/test_outputs.py +++ /dev/null @@ -1,92 +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 pytest - -from nomad.units import ureg -from nomad.datamodel import EntryArchive - -from . import logger -from .conftest import generate_scf_electronic_band_gap_template - -from nomad_simulations.schema_sections.outputs import Outputs, ElectronicBandGap - - -class TestOutputs: - """ - Test the `Outputs` class defined in `outputs.py`. - """ - - @pytest.mark.parametrize( - 'threshold_change, result', - [(1e-3, True), (1e-5, False)], - ) - def test_is_scf_converged(self, threshold_change: float, result: bool): - """ - Test the `resolve_is_scf_converged` method. - """ - scf_outputs = generate_scf_electronic_band_gap_template( - threshold_change=threshold_change - ) - is_scf_converged = scf_outputs.resolve_is_scf_converged( - property_name='electronic_band_gaps', - i_property=0, - phys_property=scf_outputs.electronic_band_gaps[0], - logger=logger, - ) - assert is_scf_converged == result - - def test_extract_spin_polarized_properties(self): - """ - Test the `extract_spin_polarized_property` method. - """ - outputs = Outputs() - - # No spin-polarized band gap - band_gap_non_spin_polarized = ElectronicBandGap(variables=[]) - band_gap_non_spin_polarized.value = 2.0 * ureg.joule - outputs.electronic_band_gaps.append(band_gap_non_spin_polarized) - band_gaps = outputs.extract_spin_polarized_property('electronic_band_gaps') - assert band_gaps == [] - - # Spin-polarized band gaps - band_gap_spin_1 = ElectronicBandGap(variables=[], spin_channel=0) - band_gap_spin_1.value = 1.0 * ureg.joule - outputs.electronic_band_gaps.append(band_gap_spin_1) - band_gap_spin_2 = ElectronicBandGap(variables=[], spin_channel=1) - band_gap_spin_2.value = 1.5 * ureg.joule - outputs.electronic_band_gaps.append(band_gap_spin_2) - band_gaps = outputs.extract_spin_polarized_property('electronic_band_gaps') - assert len(band_gaps) == 2 - assert band_gaps[0].value.magnitude == 1.0 - assert band_gaps[1].value.magnitude == 1.5 - - @pytest.mark.parametrize( - 'threshold_change, result', - [(1e-3, True), (1e-5, False)], - ) - def test_normalize(self, threshold_change: float, result: bool): - """ - Test the `normalize` method. - """ - scf_outputs = generate_scf_electronic_band_gap_template( - threshold_change=threshold_change - ) - - scf_outputs.normalize(EntryArchive(), logger) - assert scf_outputs.electronic_band_gaps[0].is_scf_converged == result diff --git a/tests/test_permittivity.py b/tests/test_permittivity.py deleted file mode 100644 index 8f91703e..00000000 --- a/tests/test_permittivity.py +++ /dev/null @@ -1,167 +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 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.schema import Simulation -from nomad_simulations.schema_sections.model_system import ModelSystem, AtomicCell -from nomad_simulations.schema_sections.atoms_state import AtomsState -from nomad_simulations.schema_sections.outputs import Outputs -from nomad_simulations.schema_sections.properties import Permittivity -from nomad_simulations.schema_sections.variables import Variables, KMesh, Frequency - -from .conftest import generate_k_space_simulation - - -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( - 'kmesh_grid, variables, result', - [ - (None, None, 'static'), - ([], None, 'static'), - ([3, 3, 3], None, 'static'), - ([3, 3, 3], Frequency(), 'dynamic'), - ], - ) - def test_resolve_type( - self, - kmesh_grid: Optional[List[int]], - variables: Optional[Variables], - result: str, - ): - """ - Test the `resolve_type` method. - """ - permittivity = Permittivity() - - # Generating `KMesh` numerical settings section - simulation = generate_k_space_simulation(grid=kmesh_grid) - k_mesh_settings = simulation.model_method[0].numerical_settings[0].k_mesh[0] - k_mesh_settings.label = 'q-mesh' - k_mesh_settings.center = 'Monkhorst-Pack' - k_mesh_settings.points, _ = k_mesh_settings.resolve_points_and_offset(logger) - if kmesh_grid is not None and len(kmesh_grid) > 0: - kmesh_variables = KMesh(points=k_mesh_settings) - permittivity.variables.append(kmesh_variables) - - # Adding variables to `permittivity` property - if variables is not None and len(variables) > 0: - permittivity.variables.append(variables) - assert permittivity.resolve_type() == result - - @pytest.mark.parametrize( - 'kmesh_grid, frequencies_points, value, result', - [ - # Empty case - (None, None, None, None), - # No `variables` - ([], [], np.eye(3) * (1 + 1j), None), - # If `KMesh` is defined we cannot extract absorption spectra - ( - [4, 1, 1], - [], - np.array([np.eye(3) * k_point * (1 + 1j) for k_point in range(1, 5)]), - None, - ), - # Even if we define `Frequency`, we cannot extract absorption spectra if `value` depends on `KMesh` - ( - [4, 1, 1], - [0, 1, 2, 3, 4], - np.array( - [ - [ - np.eye(3) * k_point * (1 + 1j) - + np.eye(3) * freq_point * 0.5j - for freq_point in range(5) - ] - for k_point in range(1, 5) - ] - ), - None, - ), - # Valid case: `value` does not depend on `KMesh` and we can extract absorption spectra - ( - [], - [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, - kmesh_grid: Optional[List[int]], - frequencies_points: Optional[List[float]], - value: Optional[np.ndarray], - result: Optional[List[float]], - ): - """ - 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() - - # Generating `KMesh` numerical settings section - simulation = generate_k_space_simulation(grid=kmesh_grid) - k_mesh_settings = simulation.model_method[0].numerical_settings[0].k_mesh[0] - k_mesh_settings.label = 'q-mesh' - k_mesh_settings.center = 'Monkhorst-Pack' - k_mesh_settings.points, _ = k_mesh_settings.resolve_points_and_offset(logger) - if kmesh_grid is not None and len(kmesh_grid) > 0: - kmesh_variables = KMesh(points=k_mesh_settings) - permittivity.variables.append(kmesh_variables) - - # Adding `Frequency` if defined - if frequencies_points is not None and len(frequencies_points) > 0: - frequencies = Frequency(points=frequencies_points) - permittivity.variables.append(frequencies) - - if permittivity.variables is not None and len(permittivity.variables) > 0: - permittivity.value = value - - absorption_spectra = permittivity.extract_absorption_spectra(logger) - if absorption_spectra is not None: - assert len(absorption_spectra) == 3 - spectrum = absorption_spectra[1] - assert spectrum.rank == [] - assert spectrum.axis == 'yy' - assert len(spectrum.value) == len(permittivity.variables[0].points) - assert np.allclose(spectrum.value, result) - else: - assert absorption_spectra == result diff --git a/tests/test_physical_properties.py b/tests/test_physical_properties.py deleted file mode 100644 index fd7f8893..00000000 --- a/tests/test_physical_properties.py +++ /dev/null @@ -1,160 +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 numpy as np -import pytest - -from nomad.units import ureg -from nomad.datamodel import EntryArchive -from nomad.metainfo import Quantity - -from . import logger - -from nomad_simulations.schema_sections.variables import Variables -from nomad_simulations.schema_sections.physical_property import PhysicalProperty - - -class DummyPhysicalProperty(PhysicalProperty): - value = Quantity( - type=np.float64, - unit='eV', - description=""" - This value is defined in order to test the `__setattr__` method in `PhysicalProperty`. - """, - ) - - -class TestPhysicalProperty: - """ - Test the `PhysicalProperty` class defined in `physical_property.py`. - """ - - @pytest.mark.parametrize( - 'rank, variables, result_variables_shape, result_full_shape', - [ - ([], [], [], []), - ([3], [], [], [3]), - ([3, 3], [], [], [3, 3]), - ([], [Variables(n_points=4)], [4], [4]), - ([3], [Variables(n_points=4)], [4], [4, 3]), - ([3, 3], [Variables(n_points=4)], [4], [4, 3, 3]), - ( - [], - [Variables(n_points=4), Variables(n_points=10)], - [4, 10], - [4, 10], - ), - ( - [3], - [Variables(n_points=4), Variables(n_points=10)], - [4, 10], - [4, 10, 3], - ), - ( - [3, 3], - [Variables(n_points=4), Variables(n_points=10)], - [4, 10], - [4, 10, 3, 3], - ), - ], - ) - def test_static_properties( - self, - rank: list, - variables: list, - result_variables_shape: list, - result_full_shape: list, - ): - """ - Test the static properties of the `PhysicalProperty` class, `variables_shape` and `full_shape`. - """ - physical_property = PhysicalProperty( - source='simulation', - rank=rank, - variables=variables, - ) - assert physical_property.variables_shape == result_variables_shape - assert physical_property.full_shape == result_full_shape - - def test_setattr_value(self): - """ - Test the `__setattr__` method when setting the `value` quantity of a physical property. - """ - physical_property = DummyPhysicalProperty( - source='simulation', - rank=[3, 3], - variables=[Variables(n_points=4), Variables(n_points=10)], - ) - # `physical_property.value` must have full_shape=[4, 10, 3, 3] - value = np.ones((4, 10, 3, 3)) * ureg.eV - assert physical_property.full_shape == list(value.shape) - physical_property.value = value - assert np.all(physical_property.value == value) - - def test_setattr_value_wrong_shape(self): - """ - Test the `__setattr__` method when the `value` has a wrong shape. - """ - physical_property = PhysicalProperty( - source='simulation', - rank=[], - variables=[], - ) - # `physical_property.value` must have shape=[] - value = np.ones((3, 3)) - wrong_shape = list(value.shape) - with pytest.raises(ValueError) as exc_info: - physical_property.value = value - assert ( - str(exc_info.value) - == f'The shape of the stored `value` {wrong_shape} does not match the full shape {physical_property.full_shape} extracted from the variables `n_points` and the `shape` defined in `PhysicalProperty`.' - ) - - def test_setattr_none(self): - """ - Test the `__setattr__` method when setting the `value` to `None`. - """ - physical_property = PhysicalProperty( - source='simulation', - rank=[], - variables=[], - ) - with pytest.raises(ValueError) as exc_info: - physical_property.value = None - assert ( - str(exc_info.value) - == f'The value of the physical property {physical_property.name} is None. Please provide a finite valid value.' - ) - - def test_is_derived(self): - """ - Test the `normalize` and `_is_derived` methods. - """ - # Testing a directly parsed physical property - not_derived_physical_property = PhysicalProperty(source='simulation') - assert not_derived_physical_property._is_derived() is False - not_derived_physical_property.normalize(EntryArchive(), logger) - assert not_derived_physical_property.is_derived is False - # Testing a derived physical property - derived_physical_property = PhysicalProperty( - source='analysis', - physical_property_ref=not_derived_physical_property, - ) - assert derived_physical_property._is_derived() is True - derived_physical_property.normalize(EntryArchive(), logger) - assert derived_physical_property.is_derived is True diff --git a/tests/test_spectral_profile.py b/tests/test_spectral_profile.py deleted file mode 100644 index ae0e1e16..00000000 --- a/tests/test_spectral_profile.py +++ /dev/null @@ -1,306 +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 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.schema import Simulation -from nomad_simulations.schema_sections.model_system import ModelSystem, AtomicCell -from nomad_simulations.schema_sections.atoms_state import AtomsState -from nomad_simulations.schema_sections.outputs import Outputs -from nomad_simulations.schema_sections.properties import ( - SpectralProfile, - ElectronicDensityOfStates, - AbsorptionSpectrum, - XASSpectrum, -) -from nomad_simulations.schema_sections.variables import Energy2 as Energy - - -class TestSpectralProfile: - """ - Test the `SpectralProfile` class defined in `properties/spectral_profile.py`. - """ - - def test_is_valid_spectral_profile(self): - """ - Test the `is_valid_spectral_profile` method. - """ - spectral_profile = SpectralProfile( - variables=[Energy(points=[-1, 0, 1] * ureg.joule)] - ) - spectral_profile.value = [1.5, 0, 0.8] - assert spectral_profile.is_valid_spectral_profile() - spectral_profile.value = [2, 0, -4] - assert not spectral_profile.is_valid_spectral_profile() - - -class TestElectronicDensityOfStates: - """ - Test the `ElectronicDensityOfStates` class defined in `properties/spectral_profile.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 `ElectronicDensityOfStates` class. - """ - electronic_dos = ElectronicDensityOfStates() - assert ( - electronic_dos.iri - == 'http://fairmat-nfdi.eu/taxonomy/ElectronicDensityOfStates' - ) - assert electronic_dos.name == 'ElectronicDensityOfStates' - assert electronic_dos.rank == [] - - def test_resolve_energies_origin(self): - """ - Test the `resolve_energies_origin` method. - """ - # ! add test when `ElectronicEigenvalues` is implemented - pass - - def test_resolve_normalization_factor(self, simulation_electronic_dos: Simulation): - """ - Test the `resolve_normalization_factor` method. - """ - simulation = Simulation() - outputs = Outputs() - # We only used the `simulation_electronic_dos` fixture to get the `ElectronicDensityOfStates` to test missing refs - electronic_dos = simulation_electronic_dos.outputs[0].electronic_dos[0] - electronic_dos.energies_origin = 0.5 * ureg.joule - outputs.electronic_dos.append(electronic_dos) - simulation.outputs.append(outputs) - - # No `model_system_ref` - assert electronic_dos.resolve_normalization_factor(logger) is None - - # No `model_system_ref.cell` - model_system = ModelSystem() - simulation.model_system.append(model_system) - outputs.model_system_ref = simulation.model_system[0] - assert electronic_dos.resolve_normalization_factor(logger) is None - - # No `model_system_ref.cell.atoms_state` - atomic_cell = AtomicCell( - type='original', positions=[[0, 0, 0], [0.5, 0.5, 0.5]] * ureg.meter - ) - model_system.cell.append(atomic_cell) - assert electronic_dos.resolve_normalization_factor(logger) is None - - # Adding the required `model_system_ref` sections and quantities - atoms_state = [ - AtomsState(chemical_symbol='Ga'), - AtomsState(chemical_symbol='As'), - ] - for atom in atoms_state: - atom.normalize(EntryArchive(), logger) - atomic_cell.atoms_state = atoms_state - # Non spin-polarized - normalization_factor = electronic_dos.resolve_normalization_factor(logger) - assert np.isclose(normalization_factor, 0.015625) - # Spin-polarized - electronic_dos.spin_channel = 0 - normalization_factor_spin_polarized = ( - electronic_dos.resolve_normalization_factor(logger) - ) - assert np.isclose( - normalization_factor_spin_polarized, 0.5 * normalization_factor - ) - - def test_extract_band_gap(self): - """ - Test the `extract_band_gap` method. - """ - # ! add test when `ElectronicEigenvalues` is implemented - pass - - def test_resolve_pdos_name(self, simulation_electronic_dos: Simulation): - """ - Test the `resolve_pdos_name` method. - """ - # Get projected DOSProfile from the simulation fixture - projected_dos = ( - simulation_electronic_dos.outputs[0].electronic_dos[0].projected_dos - ) - assert len(projected_dos) == 3 - pdos_names = ['orbital s Ga', 'orbital px As', 'orbital py As'] - for i, pdos in enumerate(projected_dos): - name = pdos.resolve_pdos_name(logger) - assert name == pdos_names[i] - - def test_extract_projected_dos(self, simulation_electronic_dos: Simulation): - """ - Test the `extract_projected_dos` method. - """ - # Get Outputs and ElectronicDensityOfStates from the simulation fixture - outputs = simulation_electronic_dos.outputs[0] - electronic_dos = outputs.electronic_dos[0] - - # Initial tests for the passed `projected_dos` (only orbital PDOS) - assert len(electronic_dos.projected_dos) == 3 # only orbital projected DOS - orbital_projected = electronic_dos.extract_projected_dos('orbital', logger) - atom_projected = electronic_dos.extract_projected_dos('atom', logger) - assert len(orbital_projected) == 3 and len(atom_projected) == 0 - orbital_projected_names = [orb_pdos.name for orb_pdos in orbital_projected] - assert orbital_projected_names == [ - 'orbital s Ga', - 'orbital px As', - 'orbital py As', - ] - assert ( - orbital_projected[0].entity_ref - == outputs.model_system_ref.cell[0].atoms_state[0].orbitals_state[0] - ) # orbital `s` in `Ga` atom - assert ( - orbital_projected[1].entity_ref - == outputs.model_system_ref.cell[0].atoms_state[1].orbitals_state[0] - ) # orbital `px` in `As` atom - assert ( - orbital_projected[2].entity_ref - == outputs.model_system_ref.cell[0].atoms_state[1].orbitals_state[1] - ) # orbital `py` in `As` atom - - orbital_projected = electronic_dos.extract_projected_dos('orbital', logger) - atom_projected = electronic_dos.extract_projected_dos('atom', logger) - assert len(orbital_projected) == 3 and len(atom_projected) == 0 - - @pytest.mark.parametrize( - 'value, result', - [ - (None, [1.5, 1.2, 0, 0, 0, 0.8, 1.3]), - ([30.5, 1.2, 0, 0, 0, 0.8, 1.3], [30.5, 1.2, 0, 0, 0, 0.8, 1.3]), - ], - ) - def test_generate_from_pdos( - self, - simulation_electronic_dos: Simulation, - value: Optional[List[float]], - result: List[float], - ): - """ - Test the `generate_from_projected_dos` method. - """ - # Get Outputs and ElectronicDensityOfStates from the simulation fixture - outputs = simulation_electronic_dos.outputs[0] - electronic_dos = outputs.electronic_dos[0] - - # Add `value` - if value is not None: - electronic_dos.value = value * ureg('1/joule') - - val = electronic_dos.generate_from_projected_dos(logger) - assert (val.magnitude == result).all() - - # Testing orbital + atom projected DOS (3 orbitals + 2 atoms PDOS) - assert len(electronic_dos.projected_dos) == 5 - orbital_projected = electronic_dos.extract_projected_dos('orbital', logger) - atom_projected = electronic_dos.extract_projected_dos('atom', logger) - assert len(orbital_projected) == 3 and len(atom_projected) == 2 - atom_projected_names = [atom_pdos.name for atom_pdos in atom_projected] - assert atom_projected_names == ['atom Ga', 'atom As'] - assert ( - atom_projected[0].entity_ref - == outputs.model_system_ref.cell[0].atoms_state[0] - ) # `Ga` atom - assert ( - atom_projected[1].entity_ref - == outputs.model_system_ref.cell[0].atoms_state[1] - ) # `As` atom - - def test_normalize(self): - """ - Test the `normalize` method. - """ - # ! add test when `ElectronicEigenvalues` is implemented - pass - - -class TestAbsorptionSpectrum: - """ - Test the `AbsorptionSpectrum` class defined in `properties/spectral_profile.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 `AbsorptionSpectrum` class. - """ - absorption_spectrum = AbsorptionSpectrum() - assert absorption_spectrum.iri is None # Add iri when available - assert absorption_spectrum.name == 'AbsorptionSpectrum' - assert absorption_spectrum.rank == [] - - -class TestXASSpectrum: - """ - Test the `XASSpectrum` class defined in `properties/spectral_profile.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 `XASSpectrum` class. - """ - xas_spectrum = XASSpectrum() - assert xas_spectrum.iri is None # Add iri when available - assert xas_spectrum.name == 'XASSpectrum' - assert xas_spectrum.rank == [] - - @pytest.mark.parametrize( - 'xanes_energies, exafs_energies, xas_values', - [ - (None, None, None), - ([0, 1, 2], None, None), - (None, [3, 4, 5], None), - ([0, 1, 2], [3, 4, 5], [0.5, 0.1, 0.3, 0.2, 0.4, 0.6]), - ([0, 1, 4], [3, 4, 5], None), - ([0, 1, 2], [0, 4, 5], None), - ], - ) - def test_generate_from_contributions( - self, - xanes_energies: Optional[List[float]], - exafs_energies: Optional[List[float]], - xas_values: Optional[List[float]], - ): - """ - Test the `generate_from_contributions` method. - """ - xas_spectrum = XASSpectrum() - if xanes_energies is not None: - xanes_spectrum = AbsorptionSpectrum() - xanes_spectrum.variables = [Energy(points=xanes_energies * ureg.joule)] - xanes_spectrum.value = [0.5, 0.1, 0.3] - xas_spectrum.xanes_spectrum = xanes_spectrum - if exafs_energies is not None: - exafs_spectrum = AbsorptionSpectrum() - exafs_spectrum.variables = [Energy(points=exafs_energies * ureg.joule)] - exafs_spectrum.value = [0.2, 0.4, 0.6] - xas_spectrum.exafs_spectrum = exafs_spectrum - xas_spectrum.generate_from_contributions(logger) - if xas_spectrum.value is not None: - assert (xas_spectrum.value == xas_values).all() - else: - assert xas_spectrum.value == xas_values diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index cfd4df71..00000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,97 +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 pytest -import numpy as np - -from nomad.units import ureg - -from nomad_simulations.schema_sections.utils import ( - get_sibling_section, - is_not_representative, - get_variables, -) -from nomad_simulations.schema_sections.model_system import ( - ModelSystem, - AtomicCell, - Symmetry, -) -from nomad_simulations.schema_sections.variables import Temperature, Energy2 as Energy - -from . import logger - - -def test_get_sibling_section(): - """ - Test the `get_sibling_section` utility function. - """ - parent_section = ModelSystem() - section = AtomicCell(type='original') - parent_section.cell.append(section) - sibling_section = Symmetry() - parent_section.symmetry.append(sibling_section) - assert get_sibling_section(section, '', logger) is None - assert get_sibling_section(section, 'symmetry', logger) == sibling_section - assert get_sibling_section(sibling_section, 'cell', logger) == section - assert get_sibling_section(section, 'symmetry', logger, index_sibling=2) is None - section2 = AtomicCell(type='primitive') - parent_section.cell.append(section2) - assert ( - get_sibling_section(sibling_section, 'cell', logger, index_sibling=0) == section - ) - assert ( - get_sibling_section(sibling_section, 'cell', logger, index_sibling=1) - == section2 - ) - - -def test_is_not_representative(): - """ - Test the `is_not_representative` utility function. - """ - assert is_not_representative(None, logger) is None - assert is_not_representative(ModelSystem(), logger) - assert not is_not_representative(ModelSystem(is_representative=True), logger) - - -# ! Missing test for RusselSandersState (but this class will probably be deprecated) - - -@pytest.mark.parametrize( - 'variables, result, result_length', - [ - (None, [], 0), - ([], [], 0), - ([Temperature()], [], 0), - ([Temperature(), Energy(n_points=4)], [Energy(n_points=4)], 1), - ( - [Temperature(), Energy(n_points=2), Energy(n_points=10)], - [Energy(n_points=2), Energy(n_points=10)], - 2, - ), - # TODO add testing when we have variables which inherit from another variable - ], -) -def test_get_variables(variables: list, result: list, result_length: int): - """ - Test the `get_variables` utility function - """ - energies = get_variables(variables, Energy) - assert len(energies) == result_length - for i, energy in enumerate(energies): # asserting energies == result does not work - assert energy.n_points == result[i].n_points diff --git a/tests/test_variables.py b/tests/test_variables.py deleted file mode 100644 index 82bd49b8..00000000 --- a/tests/test_variables.py +++ /dev/null @@ -1,54 +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 pytest - -from nomad.datamodel import EntryArchive - -from . import logger - -from nomad_simulations.schema_sections.variables import Variables - - -class TestVariables: - """ - Test the `Variables` class defined in `variables.py`. - """ - - @pytest.mark.parametrize( - 'n_points, points, result', - [ - (3, [-1, 0, 1], 3), - (5, [-1, 0, 1], 3), - (None, [-1, 0, 1], 3), - (4, None, 4), - (4, [], 4), - ], - ) - def test_normalize(self, n_points: int, points: list, result: int): - """ - Test the `normalize` and `get_n_points` methods. - """ - variable = Variables( - name='variable_1', - n_points=n_points, - points=points, - ) - assert variable.get_n_points(logger) == result - variable.normalize(EntryArchive(), logger) - assert variable.n_points == result