Commit a05a1c44 authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Added optimade tools, continued to work on optimade and metainfo.

parent f2ff5b86
......@@ -155,4 +155,4 @@
branch = nomad-fair
[submodule "dependencies/optimade-python-tools"]
path = dependencies/optimade-python-tools
url = git@github.com:markus1978/optimade-python-tools.git
url = https://github.com/markus1978/optimade-python-tools.git
......@@ -6,6 +6,7 @@ git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
while read path_key path
do
echo $path
[ -f $path/requirements.txt ] && pip install -r $path/requirements.txt
[ -f $path/setup.py ] && pip install $1 $path
(echo "$path" | grep -vEq ^dependencies/optimade-python-tools$) \
&& [ -f $path/requirements.txt ] && pip install -r $path/requirements.txt
[ -f $path/setup.py ] && pip install --ignore-requires-python $1 $path
done
Subproject commit 72e341104fdb50c5d9b93a7ffc120edd6b203506
Subproject commit 3c2874e4cedae2e8743984b11a0d9b0375a008af
......@@ -96,6 +96,12 @@ class DFTCalcWithMetadata(CalcWithMetadata):
super().__init__(**kwargs)
def update(self, **kwargs):
super().update(**kwargs)
if self.optimade is not None and isinstance(self.optimade, dict):
self.optimade = optimade.OptimadeStructureEntry.m_from_dict(self.optimade)
def apply_domain_metadata(self, backend):
from nomad.normalizing.system import normalized_atom_labels
......
......@@ -436,8 +436,8 @@ class MObject(metaclass=MObjectMeta):
else:
if parent_index != -1:
raise IndexError('Not a repeatable sub section.')
else:
return m_data_value
return m_data_value
def m_add_sub_section(self, sub_section: MObjectBound) -> MObjectBound:
"""Adds the given section instance as a sub section to this section."""
......@@ -535,7 +535,7 @@ class MObject(metaclass=MObjectMeta):
def items() -> Iterable[Tuple[str, Any]]:
yield 'm_section', self.m_section.name
if self.m_parent_index != -1:
yield 'm_parnet_index', self.m_parent_index
yield 'm_parent_index', self.m_parent_index
for name, sub_section in self.m_section.sub_sections.items():
if name not in self.m_data:
......@@ -555,6 +555,33 @@ class MObject(metaclass=MObjectMeta):
return {key: value for key, value in items()}
@classmethod
def m_from_dict(cls: Type[MObjectBound], dct: Dict[str, Any]) -> MObjectBound:
section_def = cls.m_section
# remove m_section and m_parent_index, they set themselves automatically
assert section_def.name == dct.pop('m_section', None)
dct.pop('m_parent_index', -1)
def items():
for name, sub_section_def in section_def.sub_sections.items():
if name in dct:
sub_section_value = dct.pop(name)
if sub_section_def.repeats:
yield name, [
sub_section_def.section_cls.m_from_dict(sub_section_dct)
for sub_section_dct in sub_section_value]
else:
yield name, sub_section_def.section_cls.m_from_dict(sub_section_value)
for key, value in dct.items():
yield key, value
dct = {key: value for key, value in items()}
section_instance = cast(MObjectBound, section_def.section_cls())
section_instance.m_update(**dct)
return section_instance
def m_to_json(self):
"""Returns the data of this section as a json string. """
pass
......
......@@ -54,8 +54,7 @@ class Quantity(Property):
if derive_method is None:
raise KeyError('Derived quantity %s is not implemented' % self.name)
else:
return derive_method()
return derive_method()
elif self.synonym is not None:
return getattr(obj, self.synonym)
......@@ -158,7 +157,8 @@ class MetainfoObject(metaclass=MetainfoObjectMeta):
descriptor = getattr(type(self), name)
if descriptor is None:
raise KeyError
elif not isinstance(descriptor, Property):
if not isinstance(descriptor, Property):
raise KeyError
return descriptor
......
......@@ -248,6 +248,8 @@ def elastic_obj(source: MObject, target_cls: type):
if source is None:
return None
assert isinstance(source, MObject)
target = target_cls()
for name, quantity in source.m_section.quantities.items():
......
......@@ -12,11 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any, Dict, cast
from typing import Any, Dict
import numpy as np
from nomad import config
from nomad.parsing import LocalBackend
from nomad.normalizing.normalizer import SystemBasedNormalizer
from nomad.metainfo import units
from nomad.metainfo.optimade import OptimadeStructureEntry
......@@ -97,6 +96,4 @@ class OptimadeNormalizer(SystemBasedNormalizer):
optimade = self.get_optimade_data(index)
self._backend.add_mi2_section(optimade)
except Exception as e:
import traceback
traceback.print_exc()
self.logger.warn('could not acquire optimade data', exc_info=e)
import json
from optimade.filterparser import LarkParser
from lark import Transformer
from nomad.processing import Upload
from nomad.search import SearchRequest
from nomad.metainfo.optimade import OptimadeStructureEntry
def test_get_entry(published: Upload):
......@@ -13,3 +16,82 @@ def test_get_entry(published: Upload):
assert 'OptimadeStructureEntry' in data
search_result = SearchRequest().search_parameter('calc_id', calc_id).execute_paginated()['results'][0]
assert 'optimade' in search_result
class ESTransformer(Transformer):
def __default__(self, tree, children, *args, **kwargs):
return children[0]
def and_expr(self, args):
if len(args) == 1:
return args[0]
return dict(op='AND', ops=list(args))
def or_expr(self, args):
if len(args) == 1:
return args[0]
return dict(op='OR', ops=list(args))
def not_expr(self, args):
if len(args) == 1:
return args[0]
return dict(op='NOT', ops=list(args))
def cmp_op(self, args):
return dict(op=args[1], ops=[args[0], args[2]])
def list_op(self, args):
if len(args) == 3:
return dict(op='HAS', qualifier=args[1], ops=[args[0], args[2]])
else:
return dict(op='HAS', ops=[args[0], args[1]])
def known_op(self, args):
return dict(op='KNOWN', qualifier=args[1], ops=[args[0]])
def list(self, args):
return list(args)
def tuple(self, args):
return list(args)
def predicate(self, args):
if len(args) == 1:
return args[0]
return dict(pred=args[0], op=args[1])
def quantity(self, args):
quantity_name = args[0]
quantity_def = OptimadeStructureEntry.m_section.quantities.get(quantity_name, None)
if quantity_def is None:
raise Exception('%s is not a known quantity' % quantity_name)
return quantity_def.name
def literal(self, args):
literal = args[0]
try:
int(literal)
except Exception:
pass
try:
float(literal)
except Exception:
pass
return literal.strip('"')
def test_optimade_parser():
p = LarkParser(version=(0, 10, 0))
tree = p.parse('nelements < 3.4e-10 OR elements:elements_ratios HAS ALL "H":>1, "O":>2 AND (elements CONTAINS "H")')
transformer = ESTransformer()
result = transformer.transform(tree)
print(json.dumps(result, indent=2))
......@@ -156,7 +156,9 @@
"C", "O", "H", "H", "C", "O", "H", "H",
"C", "O", "H", "H", "C", "O", "H", "H",
"C", "O", "H", "H", "C", "O", "H", "H"
]
],
"lattice_vectors": [
[0, 0.5, 0.5],[0.5, 0 , 0.5],[0.5, 0.5, 0]]
}
],
"section_single_configuration_calculation": [
......
......@@ -57,7 +57,9 @@
"K",
"Si",
"Si"
]
],
"lattice_vectors": [
[0, 0.5, 0.5],[0.5, 0 , 0.5],[0.5, 0.5, 0]]
}
],
"section_single_configuration_calculation": [
......
......@@ -54,7 +54,9 @@
],
"atom_labels": [
"Br1SiSiK"
]
],
"lattice_vectors": [
[0, 0.5, 0.5],[0.5, 0 , 0.5],[0.5, 0.5, 0]]
}
],
"section_single_configuration_calculation": [
......
......@@ -52,7 +52,9 @@
3.0
]
],
"atom_labels": ["Br", "Si", "Si", "Za"]
"atom_labels": ["Br", "Si", "Si", "Za"],
"lattice_vectors": [
[0, 0.5, 0.5],[0.5, 0 , 0.5],[0.5, 0.5, 0]]
}
],
"section_single_configuration_calculation": [
......
......@@ -11,6 +11,8 @@
# 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.metainfo.metainfo import MObject, Section, Quantity, Definition, sub_section
......@@ -258,3 +260,31 @@ class TestM1:
system = System()
system.atom_positions = [[1, 2, 3]]
assert type(system.atom_positions) == np.ndarray
@pytest.fixture(scope='function')
def example_data(self):
run = Run()
run.code_name = 'test code name'
system: System = run.m_create(System)
system.n_atoms = 3
system.atom_label = ['H', 'H', 'O']
system.atom_positions = np.array([[1.2e-10, 0, 0], [0, 1.2e-10, 0], [0, 0, 1.2e-10]])
return run
def assert_example_data(self, data: Run):
assert_section_instance(data)
assert data.m_section == Run.m_section
assert data.code_name == 'test code name'
system: System = data.m_sub_section(System, 0)
assert_section_instance(system)
assert system.m_section == System.m_section
assert system.n_atoms == 3
assert system.atom_label == ['H', 'H', 'O']
assert type(system.atom_positions) == np.ndarray
def test_to_dict(self, example_data):
dct = example_data.m_to_dict()
new_example_data = Run.m_from_dict(dct)
self.assert_example_data(new_example_data)
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