Commit 442919cf authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Removed unnecessary JSON serialization from encyclopedia metainfo, changed...

Removed unnecessary JSON serialization from encyclopedia metainfo, changed periodicity to be a boolean array.
parent b4ebc0f7
Pipeline #69343 failed with stages
in 18 minutes and 4 seconds
......@@ -3,6 +3,53 @@ from elasticsearch_dsl import InnerDoc
from nomad.metainfo import MSection, Section, SubSection, Quantity, MEnum, units
class WyckoffSet(MSection):
m_def = Section(
a_flask=dict(skip_none=True),
a_elastic=dict(type=InnerDoc),
description="""
Section for storing Wyckoff set information.
"""
)
wyckoff_letter = Quantity(
type=str,
description="""
The Wyckoff letter for this set.
"""
)
x = Quantity(
type=float,
description="""
The x variable if present.
"""
)
y = Quantity(
type=float,
description="""
The y variable if present.
"""
)
z = Quantity(
type=float,
description="""
The z variable if present.
"""
)
indices = Quantity(
type=np.dtype('i4'),
shape=["1..*"],
description="""
Indices of the atoms belonging to this group.
"""
)
element = Quantity(
type=str,
description="""
Chemical element at this Wyckoff position.
"""
)
class Material(MSection):
m_def = Section(
a_flask=dict(skip_none=True),
......@@ -102,10 +149,10 @@ class Material(MSection):
"""
)
periodicity = Quantity(
type=np.dtype('i1'),
shape=["1..*"],
type=np.bool,
shape=[3],
description="""
The indices of the periodic dimensions.
Periodicity of each lattice direction.
"""
)
point_group = Quantity(
......@@ -180,28 +227,9 @@ class Material(MSection):
idealized to match the detected symmemtry properties.
"""
)
wyckoff_groups = Quantity(
type=str,
description="""
Returns a list of information about the Wyckoff groups in the JSON format.
An example of the output:
[
{
'wyckoff_letter': 'a',
'variables': {'z': 0.0},
'indices': [0, 6, 12],
'element': 'Bi'
},
{
'wyckoff_letter': 'b',
'variables': {'x': 0.50155295, 'z': 0.87461175999999996},
'indices': [1, 3, 4, 7, 9, 10, 13, 15, 16],
'element': 'Ga'
}, ...
]
"""
)
wyckoff_sets = SubSection(sub_section=WyckoffSet.m_def, repeats=True)
cell_angles_string = Quantity(
type=str,
description="""
......@@ -316,12 +344,6 @@ class Method(MSection):
Basic type of GW calculation.
"""
)
settings_basis_set = Quantity(
type=str,
description="""
Basis set settings in JSON format.
"""
)
smearing_kind = Quantity(
type=MEnum("gaussian", "fermi", "marzari-vanderbilt", "methfessel-paxton", "tetrahedra"),
description="""
......
......@@ -28,9 +28,9 @@ import matid.geometry
from nomad.normalizing.normalizer import Normalizer, s_scc, s_system, s_method, s_frame_sequence, r_frame_sequence_to_sampling, s_sampling_method, r_frame_sequence_local_frames
from nomad.normalizing.settingsbasisset import SettingsBasisSet
from nomad.metainfo.encyclopedia import Encyclopedia, Material, Method, Properties, RunType
from nomad.metainfo.encyclopedia import Encyclopedia, Material, Method, Properties, RunType, WyckoffSet
from nomad.normalizing import structure
from nomad.utils import hash, NumpyEncoder
from nomad.utils import hash
from nomad import config
J_to_Ry = 4.587425e+17
......@@ -508,7 +508,7 @@ class MaterialBulkNormalizer(MaterialNormalizer):
material.material_name = name
def periodicity(self, material: Material) -> None:
material.periodicity = np.array([0, 1, 2], dtype=np.int8)
material.periodicity = np.array([True, True, True], dtype=np.bool)
def point_group(self, material: Material, section_symmetry: Dict) -> None:
point_group = section_symmetry["point_group"]
......@@ -598,21 +598,18 @@ class MaterialBulkNormalizer(MaterialNormalizer):
strukturbericht = re.sub('[$_{}]', '', strukturbericht)
material.strukturbericht_designation = strukturbericht
def wyckoff_groups(self, material: Material, wyckoff_sets: Dict) -> None:
wyckoff_list = []
def wyckoff_sets(self, material: Material, wyckoff_sets: Dict) -> None:
for group in wyckoff_sets:
data = {
"wyckoff_letter": group.wyckoff_letter,
"element": group.element,
"indices": group.indices,
"variables": {
"x": group.x,
"y": group.y,
"z": group.z,
},
}
wyckoff_list.append(data)
material.wyckoff_groups = json.dumps(wyckoff_list, sort_keys=True)
wset = material.m_create(WyckoffSet)
if group.x is not None:
wset.x = group.x
if group.y is not None:
wset.y = group.y
if group.z is not None:
wset.z = group.z
wset.indices = group.indices
wset.element = group.element
wset.wyckoff_letter = group.wyckoff_letter
def normalize(self, ctx: Context) -> None:
# Fetch resources
......@@ -655,7 +652,7 @@ class MaterialBulkNormalizer(MaterialNormalizer):
self.structure_type(material, sec_system)
self.structure_prototype(material, sec_system)
self.strukturbericht_designation(material, sec_system)
self.wyckoff_groups(material, wyckoff_sets)
self.wyckoff_sets(material, wyckoff_sets)
class Material2DNormalizer(MaterialNormalizer):
......@@ -671,8 +668,9 @@ class Material2DNormalizer(MaterialNormalizer):
cell_prim *= 1e-10
material.cell_primitive = cell_prim
def lattice_parameters(self, material: Material, std_atoms: Atoms, periodic_indices: np.array) -> None:
def lattice_parameters(self, material: Material, std_atoms: Atoms, periodicity: np.array) -> None:
# 2D systems only have three lattice parameter: two length and angle between them
periodic_indices = np.where(np.array(periodicity) == True)[0] # noqa: E712
cell = std_atoms.get_cell()
a_vec = cell[periodic_indices[0], :] * 1e-10
b_vec = cell[periodic_indices[1], :] * 1e-10
......@@ -694,8 +692,7 @@ class Material2DNormalizer(MaterialNormalizer):
if sum(vacuum_directions) != 1:
raise ValueError("Could not detect the periodic dimensions in a 2D system.")
periodic_indices = np.where(vacuum_directions == False)[0] # noqa: E712
material.periodicity = np.sort(np.array(periodic_indices, dtype=np.int8))
material.periodicity = np.invert(vacuum_directions)
def get_symmetry_analyzer(self, original_system: Atoms) -> SymmetryAnalyzer:
# Determine the periodicity by examining vacuum gaps
......@@ -731,11 +728,10 @@ class Material2DNormalizer(MaterialNormalizer):
)
return symmetry_analyzer
def normalizer(self, ctx: Context) -> None:
def normalize(self, ctx: Context) -> None:
# Fetch resources
sec_enc = self.backend.get_mi2_section(Encyclopedia.m_def)
material = sec_enc.material
calculation = sec_enc.calculation
repr_atoms = ctx.representative_system.tmp["representative_atoms"] # Temporary value stored by SystemNormalizer
symmetry_analyzer = self.get_symmetry_analyzer(repr_atoms)
std_atoms = symmetry_analyzer.get_conventional_system()
......@@ -743,7 +739,6 @@ class Material2DNormalizer(MaterialNormalizer):
names, counts = structure.get_hill_decomposition(prim_atoms.get_chemical_symbols(), reduced=False)
greatest_common_divisor = reduce(gcd, counts)
reduced_counts = np.array(counts) / greatest_common_divisor
# non_periodic_index_std = self.get_non_periodic_index_std(symmetry_analyzer)
# Fill metainfo
self.periodicity(material, std_atoms)
......@@ -755,7 +750,7 @@ class Material2DNormalizer(MaterialNormalizer):
self.cell_primitive(material, prim_atoms)
self.formula(material, names, counts)
self.formula_reduced(material, names, reduced_counts)
self.lattice_parameters(calculation, std_atoms, material.periodicity)
self.lattice_parameters(material, std_atoms, material.periodicity)
class Material1DNormalizer(MaterialNormalizer):
......@@ -780,8 +775,9 @@ class Material1DNormalizer(MaterialNormalizer):
cell_normalized *= 1e-10
material.cell_normalized = cell_normalized
def lattice_parameters(self, material: Material, std_atoms: Atoms, periodic_indices: np.array) -> None:
def lattice_parameters(self, material: Material, std_atoms: Atoms, periodicity: np.array) -> None:
# 1D systems only have one lattice parameter: length in periodic dimension
periodic_indices = np.where(np.array(periodicity) == True)[0] # noqa: E712
cell = std_atoms.get_cell()
a = np.linalg.norm(cell[periodic_indices[0], :]) * 1e-10
material.lattice_parameters = np.array([a, 0.0, 0.0, 0.0, 0.0, 0.0])
......@@ -798,8 +794,7 @@ class Material1DNormalizer(MaterialNormalizer):
if sum(vacuum_directions) != 2:
raise ValueError("Could not detect the periodic dimensions in a 1D system.")
periodic_indices = np.where(vacuum_directions == False)[0] # noqa: E712
material.periodicity = np.sort(np.array(periodic_indices, dtype=np.int8))
material.periodicity = np.invert(vacuum_directions)
def get_structure_fingerprint(self, prim_atoms: Atoms) -> str:
"""Calculates a numeric fingerprint that coarsely encodes the atomic
......@@ -928,18 +923,16 @@ class Material1DNormalizer(MaterialNormalizer):
std_atoms.wrap()
# Reduce cell size to just fit the system in the non-periodic dimensions.
indices = [0, 1, 2]
for idx in periodicity:
del indices[idx]
pos = std_atoms.get_scaled_positions(wrap=False)
cell = std_atoms.get_cell()
new_cell = np.array(cell)
translation = np.zeros(3)
for index in indices:
imin = np.min(pos[:, index])
imax = np.max(pos[:, index])
translation -= cell[index, :] * imin
new_cell[index] = cell[index, :] * (imax - imin)
for index, periodic in enumerate(periodicity):
if not periodic:
imin = np.min(pos[:, index])
imax = np.max(pos[:, index])
translation -= cell[index, :] * imin
new_cell[index] = cell[index, :] * (imax - imin)
std_atoms.translate(translation)
std_atoms.set_cell(new_cell)
......@@ -1324,8 +1317,7 @@ class MethodDFTNormalizer(MethodNormalizer):
result = settings_basis.to_dict()
# Save as JSON in metainfo
settings_basis_set_json = json.dumps(result, cls=NumpyEncoder, sort_keys=True)
method.settings_basis_set = settings_basis_set_json
# method.settings_basis_set = result
return result
......
......@@ -14,6 +14,7 @@
from collections import OrderedDict
from abc import ABC, abstractmethod
from nomad.parsing.backend import Section
import re
import numpy
......@@ -263,7 +264,7 @@ class SettingsBasisSetCodeDependentFhiAims(
result = None
if data is None:
return None
elif isinstance(data, (dict)):
elif isinstance(data, (Section, dict)):
result = OrderedDict()
for k in sorted(cls._filtered_section_keys(data)):
v = data.get(k, None)
......
......@@ -45,7 +45,6 @@ import json
import uuid
import time
import re
import numpy as np
from werkzeug.exceptions import HTTPException
import hashlib
import sys
......@@ -540,20 +539,3 @@ def common_prefix(paths):
common_prefix = ''
return common_prefix
class NumpyEncoder(json.JSONEncoder):
"""Custom encoder for JSON that transforms numpy datatypes to python data
structures.
"""
def default(self, obj): # pylint: disable=E0202
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.bool_):
return bool(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(NumpyEncoder, self).default(obj)
......@@ -61,31 +61,37 @@ def test_1d_metainfo(one_d: LocalBackend):
"""Tests that metainfo for 1D systems is correctly processed.
"""
enc = one_d.get_mi2_section(Encyclopedia.m_def)
# Material
assert enc.material.system_type == "1D"
assert enc.material.formula == "C6H4"
assert enc.material.formula_reduced == "C3H2"
assert np.array_equal(enc.material.periodicity, [True, False, False])
# Representative system
assert enc.material.number_of_atoms == 10
assert enc.material.atom_labels == ["C", "C", "C", "C", "C", "C", "H", "H", "H", "H"]
assert enc.material.atom_positions is not None
assert enc.material.cell_normalized is not None
assert enc.material.formula == "C6H4"
assert enc.material.formula_reduced == "C3H2"
assert np.allclose(enc.calculation.lattice_parameters, [4.33793652e-10, 0, 0, 0, 0, 0], atol=0)
assert np.array_equal(enc.material.periodicity, [0])
assert np.allclose(enc.material.lattice_parameters, [4.33793652e-10, 0, 0, 0, 0, 0], atol=0)
def test_2d_metainfo(two_d: LocalBackend):
"""Tests that metainfo for 2D systems is correctly processed.
"""
enc = two_d.get_mi2_section(Encyclopedia.m_def)
# Material
assert enc.material.system_type == "2D"
assert enc.material.formula == "C2"
assert enc.material.formula_reduced == "C"
assert np.array_equal(enc.material.periodicity, [True, True, False])
# Representative system
assert enc.material.number_of_atoms == 2
assert enc.material.atom_labels == ["C", "C"]
assert enc.material.atom_positions is not None
assert enc.material.cell_normalized is not None
assert enc.material.cell_primitive is not None
assert enc.material.formula == "C2"
assert enc.material.formula_reduced == "C"
assert np.allclose(enc.calculation.lattice_parameters, [2.46559821e-10, 2.46559821e-10, 0, 120 / 180 * np.pi, 0, 0], atol=0)
assert np.array_equal(enc.material.periodicity, [0, 1])
assert np.allclose(enc.material.lattice_parameters, [2.46559821e-10, 2.46559821e-10, 0, 120 / 180 * np.pi, 0, 0], atol=0)
def test_bulk_metainfo(bulk: LocalBackend):
......@@ -106,7 +112,7 @@ def test_bulk_metainfo(bulk: LocalBackend):
assert enc.material.bravais_lattice == "cF"
assert enc.material.has_free_wyckoff_parameters is False
assert enc.material.point_group == "m-3m"
assert enc.material.wyckoff_groups is not None
assert enc.material.wyckoff_sets is not None
assert enc.material.space_group_number == 227
assert enc.material.space_group_international_short_symbol == "Fd-3m"
......@@ -116,13 +122,13 @@ def test_bulk_metainfo(bulk: LocalBackend):
assert enc.material.atom_positions is not None
assert enc.material.cell_normalized is not None
assert enc.material.cell_primitive is not None
assert np.array_equal(enc.material.periodicity, [0, 1, 2])
assert np.array_equal(enc.material.periodicity, [True, True, True])
assert enc.material.lattice_parameters is not None
assert enc.material.cell_volume == pytest.approx(5.431**3 * 1e-30)
# Calculation
assert enc.calculation.atomic_density == pytest.approx(4.99402346512432e+28)
assert enc.calculation.lattice_parameters is not None
assert enc.calculation.mass_density == pytest.approx(8 * 28.0855 * 1.6605389e-27 / (5.431**3 * 1e-30)) # Atomic mass in kg/m^3
assert enc.calculation.cell_volume == pytest.approx(5.431**3 * 1e-30)
assert enc.properties.atomic_density == pytest.approx(4.99402346512432e+28)
assert enc.properties.mass_density == pytest.approx(8 * 28.0855 * 1.6605389e-27 / (5.431**3 * 1e-30)) # Atomic mass in kg/m^3
def test_1d_material_identification():
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment