Skip to content

Commit fefa64a

Browse files
committed
Extend ams parser
1 parent 350a53f commit fefa64a

File tree

3 files changed

+189
-9
lines changed

3 files changed

+189
-9
lines changed

src/nomad_simulation_parsers/parsers/ams/file_parser.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ def str_to_labels_positions(val_in):
2424
unit = val.pop(0)[0].lower()
2525
unit = ureg.bohr if unit.startswith('bohr') else ureg.angstrom
2626
val = np.transpose(val)
27-
return val[1], np.array(val[2:5].T, dtype=np.dtype(np.float64)) * unit
27+
return [
28+
list(val[1]),
29+
np.array(val[2:5].T, dtype=np.dtype(np.float64)) * unit,
30+
]
2831

2932
def str_to_lattice_vectors(val_in):
3033
val = [v.split()[-3:] for v in val_in.strip().splitlines()]
@@ -697,8 +700,8 @@ def to_band_energy_ranges(val_in):
697700
Quantity(
698701
'forces_total',
699702
rf'Gradients \(hartree/bohr\)\s+'
700-
rf'Index.+\s+((?:\d+ +[A-Z][a-z]*'
701-
rf' +{RE_FLOAT} +{RE_FLOAT} +{RE_FLOAT}\s+)+)',
703+
rf'Index.+\s+'
704+
rf'((?:\d+ +[A-Z][a-z]* +{RE_FLOAT} +{RE_FLOAT} +{RE_FLOAT}\s+)+)',
702705
str_operation=str_to_forces,
703706
),
704707
Quantity(
@@ -1253,8 +1256,7 @@ def parse_results(self) -> None:
12531256
)
12541257

12551258
def parse_properties(self) -> None:
1256-
if properties := self.data.get('Properties'):
1257-
return
1259+
properties = self.data.get('Properties', {})
12581260

12591261
nspin = self.data.get('General', {}).get('nspin', 1)
12601262

@@ -1342,7 +1344,9 @@ def parse_properties(self) -> None:
13421344
)
13431345
bottom_conduction_band = band_structure.get('BottomConductionBand')
13441346
band_gap['energy_lowest_unoccupied'] = (
1345-
(bottom_conduction_band * ureg.hartree) if not None else None
1347+
(bottom_conduction_band * ureg.hartree)
1348+
if bottom_conduction_band is not None
1349+
else None
13461350
)
13471351
self._results['band_gap'] = band_gap
13481352

src/nomad_simulation_parsers/parsers/ams/parser.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import os
12
from importlib import reload
3+
from typing import Any
24

5+
import numpy as np
36
from nomad.datamodel import EntryArchive
47
from nomad.parsing.file_parser import ArchiveWriter
58
from nomad.parsing.file_parser.mapping_parser import MetainfoParser, TextParser
@@ -8,9 +11,11 @@
811
from nomad_simulations.schema_packages.general import Program, Simulation
912
from structlog.stdlib import BoundLogger
1013

14+
from nomad_simulation_parsers.parsers.utils.general import search_files
1115
from nomad_simulation_parsers.schema_packages import ams
1216

1317
from .file_parser import OutParser
18+
from .file_parser import RKFParser as RKFTextParser
1419

1520
LOGGER = get_logger(__name__)
1621

@@ -21,6 +26,44 @@ class MainfileParser(TextParser):
2126
def logger(self):
2227
return LOGGER
2328

29+
def get_xc_functionals(self, source: dict[str, Any]) -> list[str]:
30+
xc_functionals = []
31+
for xc_type in ['LDA', 'GGA', 'MGGA']:
32+
functionals = source.get(xc_type, '').split()
33+
kind = ['XC'] if len(functionals) == 1 else ['X', 'C']
34+
for n, functional in enumerate(functionals):
35+
xc_functionals.append(
36+
f'{xc_type}_{kind[n]}_{functional.rstrip("x").rstrip("c").upper()}'
37+
)
38+
return xc_functionals
39+
40+
def get_contributions(self, source: dict[str, Any]) -> list[dict[str, Any]]:
41+
return [
42+
dict(name=key, value=val) for key, val in source.items() if val is not None
43+
]
44+
45+
def get_eigenvalues(
46+
self, source: dict[str, Any] | list[np.ndarray]
47+
) -> list[dict[str, np.ndarray]]:
48+
energies = source.get('energies', []) if isinstance(source, dict) else []
49+
occupations = (
50+
source.get('occupations', []) if isinstance(source, dict) else source[2]
51+
)
52+
nspin = max(len(energies), len(occupations))
53+
eigenvalues = [dict() for _ in range(nspin)]
54+
for n, energy in enumerate(energies):
55+
eigenvalues[n]['eigenvalues'] = energy
56+
for n, occupations in enumerate(occupations):
57+
eigenvalues[n]['occupations'] = occupations
58+
return [eig for eig in eigenvalues if eig]
59+
60+
61+
class RKFParser(MainfileParser):
62+
# TODO temporary fix for structlog unable to propagate logger
63+
@property
64+
def logger(self):
65+
return LOGGER
66+
2467

2568
# TODO temporary fix for structlog unable to propagate logger
2669
class AMSMetainfoParser(MetainfoParser):
@@ -32,6 +75,7 @@ def logger(self):
3275
class AMSArchiveWriter(ArchiveWriter):
3376
mainfile_parser = MainfileParser(text_parser=OutParser())
3477
metainfo_parser = AMSMetainfoParser()
78+
rkf_parser = RKFParser(text_parser=RKFTextParser())
3579

3680
def write_to_archive(self):
3781
# reload schema package to use correct annotations
@@ -41,8 +85,17 @@ def write_to_archive(self):
4185
self.archive.data = Simulation(program=Program(name='AMS'))
4286
self.metainfo_parser.data_object = self.archive.data
4387

44-
self.mainfile_parser.filepath = self.mainfile
45-
self.mainfile_parser.convert(self.metainfo_parser)
88+
rkf_files = search_files('ams.rkf', os.path.dirname(self.mainfile))
89+
self.parser = self.mainfile_parser
90+
self.parser.filepath = self.mainfile
91+
if rkf_files:
92+
if len(rkf_files) > 1:
93+
self.logger.warning('Multiple ams.rkf files found.')
94+
self.parser = self.rkf_parser
95+
self.parser.filepath = rkf_files[0]
96+
self.parser.data_object.parse()
97+
98+
self.parser.convert(self.metainfo_parser)
4699

47100

48101
class AMSParser(MatchingParser):

src/nomad_simulation_parsers/schema_packages/ams.py

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
from nomad.datamodel.metainfo.annotations import Mapper
22
from nomad.metainfo import SchemaPackage
33
from nomad.parsing.file_parser.mapping_parser import MAPPING_ANNOTATION_KEY
4-
from nomad_simulations.schema_packages import general
4+
from nomad_simulations.schema_packages import (
5+
general,
6+
model_method,
7+
model_system,
8+
outputs,
9+
)
510

611
m_package = SchemaPackage()
712

@@ -12,10 +17,128 @@ class Program(general.Program):
1217
)
1318

1419

20+
class AtomsState(model_system.AtomsState):
21+
model_system.AtomsState.chemical_symbol.m_annotations.setdefault(
22+
MAPPING_ANNOTATION_KEY, {}
23+
).update(dict(out=Mapper(mapper='.@')))
24+
25+
26+
class AtomicCell(model_system.AtomicCell):
27+
model_system.AtomicCell.lattice_vectors.m_annotations.setdefault(
28+
MAPPING_ANNOTATION_KEY, {}
29+
).update(dict(out=Mapper(mapper='.@')))
30+
31+
32+
class ModelSystem(model_system.ModelSystem):
33+
model_system.ModelSystem.positions.m_annotations.setdefault(
34+
MAPPING_ANNOTATION_KEY, {}
35+
).update(dict(out=Mapper(mapper='.labels_positions[1]')))
36+
model_system.AtomsState.m_def.m_annotations.setdefault(
37+
MAPPING_ANNOTATION_KEY, {}
38+
).update(dict(out=Mapper(mapper='.labels_positions[0]')))
39+
model_system.AtomicCell.m_def.m_annotations.setdefault(
40+
MAPPING_ANNOTATION_KEY, {}
41+
).update(dict(out=Mapper(mapper='.lattice_vectors')))
42+
43+
44+
class XCFunctional(model_method.XCFunctional):
45+
model_method.XCFunctional.libxc_name.m_annotations.setdefault(
46+
MAPPING_ANNOTATION_KEY, {}
47+
).update(dict(out=Mapper(mapper='.@')))
48+
49+
50+
class DFT(model_method.DFT):
51+
model_method.DFT.xc_functionals.m_annotations.setdefault(
52+
MAPPING_ANNOTATION_KEY, {}
53+
).update(
54+
dict(
55+
out=Mapper(
56+
mapper=('get_xc_functionals', ['.model_parameters.dft_potential'])
57+
)
58+
)
59+
)
60+
61+
62+
class TotalEnergy(outputs.TotalEnergy):
63+
outputs.TotalEnergy.value.m_annotations.setdefault(
64+
MAPPING_ANNOTATION_KEY, {}
65+
).update(dict(out=Mapper(mapper='.value || .energy_total')))
66+
outputs.TotalEnergy.contributions.m_annotations.setdefault(
67+
MAPPING_ANNOTATION_KEY, {}
68+
).update(dict(out=Mapper(mapper=('get_contributions', ['.energies']))))
69+
70+
71+
class TotalForce(outputs.TotalForce):
72+
outputs.TotalForce.value.m_annotations.setdefault(
73+
MAPPING_ANNOTATION_KEY, {}
74+
).update(dict(out=Mapper(mapper='.value || .forces_total')))
75+
outputs.TotalForce.contributions.m_annotations.setdefault(
76+
MAPPING_ANNOTATION_KEY, {}
77+
).update(dict(out=Mapper(mapper=('get_contributions', ['.forces']))))
78+
79+
80+
class ElectronicEigenvalues(outputs.ElectronicEigenvalues):
81+
outputs.ElectronicEigenvalues.value.m_annotations.setdefault(
82+
MAPPING_ANNOTATION_KEY, {}
83+
).update(dict(out=Mapper(mapper='.eigenvalues')))
84+
outputs.ElectronicEigenvalues.occupation.m_annotations.setdefault(
85+
MAPPING_ANNOTATION_KEY, {}
86+
).update(dict(out=Mapper(mapper='.occupations')))
87+
88+
89+
class Outputs(outputs.Outputs):
90+
outputs.Outputs.total_energies.m_annotations.setdefault(
91+
MAPPING_ANNOTATION_KEY, {}
92+
).update(dict(out=Mapper(mapper='.@')))
93+
outputs.Outputs.total_forces.m_annotations.setdefault(
94+
MAPPING_ANNOTATION_KEY, {}
95+
).update(dict(out=Mapper(mapper='.@')))
96+
outputs.Outputs.electronic_eigenvalues.m_annotations.setdefault(
97+
MAPPING_ANNOTATION_KEY, {}
98+
).update(
99+
dict(
100+
out=Mapper(
101+
mapper=('get_eigenvalues', ['.eigenvalues || .band_energy_ranges'])
102+
)
103+
)
104+
)
105+
106+
15107
class Simulation(general.Simulation):
16108
general.Simulation.program.m_annotations.setdefault(
17109
MAPPING_ANNOTATION_KEY, {}
18110
).update(dict(out=Mapper(mapper='.@')))
111+
model_method.DFT.m_def.m_annotations.setdefault(MAPPING_ANNOTATION_KEY, {}).update(
112+
dict(
113+
out=Mapper(
114+
mapper='.geometry_optimization || molecular_dynamics || .single_point'
115+
)
116+
)
117+
)
118+
general.Simulation.model_system.m_annotations.setdefault(
119+
MAPPING_ANNOTATION_KEY, {}
120+
).update(
121+
dict(
122+
out=Mapper(
123+
mapper=
124+
'.geometry_optimization.step '
125+
'|| molecular_dynamics.step '
126+
'|| .single_point'
127+
)
128+
)
129+
)
130+
general.Simulation.outputs.m_annotations.setdefault(
131+
MAPPING_ANNOTATION_KEY, {}
132+
).update(
133+
dict(
134+
out=Mapper(
135+
mapper=
136+
'.geometry_optimization.step '
137+
'|| molecular_dynamics.step '
138+
'|| .single_point'
139+
)
140+
)
141+
)
19142

20143

21144
Simulation.m_def.m_annotations.setdefault(MAPPING_ANNOTATION_KEY, {}).update(

0 commit comments

Comments
 (0)