nomad-parser-plugins-workflow 1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nomad_parser_plugins_workflow-1.0.dist-info/LICENSE +202 -0
- nomad_parser_plugins_workflow-1.0.dist-info/METADATA +319 -0
- nomad_parser_plugins_workflow-1.0.dist-info/RECORD +58 -0
- nomad_parser_plugins_workflow-1.0.dist-info/WHEEL +5 -0
- nomad_parser_plugins_workflow-1.0.dist-info/entry_points.txt +11 -0
- nomad_parser_plugins_workflow-1.0.dist-info/top_level.txt +1 -0
- workflowparsers/__init__.py +314 -0
- workflowparsers/aflow/__init__.py +19 -0
- workflowparsers/aflow/__main__.py +31 -0
- workflowparsers/aflow/metainfo/__init__.py +19 -0
- workflowparsers/aflow/metainfo/aflow.py +1240 -0
- workflowparsers/aflow/parser.py +741 -0
- workflowparsers/asr/__init__.py +19 -0
- workflowparsers/asr/__main__.py +31 -0
- workflowparsers/asr/metainfo/__init__.py +19 -0
- workflowparsers/asr/metainfo/asr.py +306 -0
- workflowparsers/asr/parser.py +266 -0
- workflowparsers/atomate/__init__.py +19 -0
- workflowparsers/atomate/__main__.py +31 -0
- workflowparsers/atomate/metainfo/__init__.py +19 -0
- workflowparsers/atomate/metainfo/atomate.py +395 -0
- workflowparsers/atomate/parser.py +357 -0
- workflowparsers/elastic/__init__.py +19 -0
- workflowparsers/elastic/__main__.py +31 -0
- workflowparsers/elastic/metainfo/__init__.py +19 -0
- workflowparsers/elastic/metainfo/elastic.py +364 -0
- workflowparsers/elastic/parser.py +798 -0
- workflowparsers/fhivibes/__init__.py +19 -0
- workflowparsers/fhivibes/__main__.py +31 -0
- workflowparsers/fhivibes/metainfo/__init__.py +19 -0
- workflowparsers/fhivibes/metainfo/fhi_vibes.py +898 -0
- workflowparsers/fhivibes/parser.py +566 -0
- workflowparsers/lobster/__init__.py +19 -0
- workflowparsers/lobster/__main__.py +31 -0
- workflowparsers/lobster/metainfo/__init__.py +19 -0
- workflowparsers/lobster/metainfo/lobster.py +446 -0
- workflowparsers/lobster/parser.py +618 -0
- workflowparsers/phonopy/__init__.py +19 -0
- workflowparsers/phonopy/__main__.py +31 -0
- workflowparsers/phonopy/calculator.py +260 -0
- workflowparsers/phonopy/metainfo/__init__.py +19 -0
- workflowparsers/phonopy/metainfo/phonopy.py +83 -0
- workflowparsers/phonopy/parser.py +583 -0
- workflowparsers/quantum_espresso_epw/__init__.py +19 -0
- workflowparsers/quantum_espresso_epw/__main__.py +31 -0
- workflowparsers/quantum_espresso_epw/metainfo/__init__.py +19 -0
- workflowparsers/quantum_espresso_epw/metainfo/quantum_espresso_epw.py +579 -0
- workflowparsers/quantum_espresso_epw/parser.py +583 -0
- workflowparsers/quantum_espresso_phonon/__init__.py +19 -0
- workflowparsers/quantum_espresso_phonon/__main__.py +31 -0
- workflowparsers/quantum_espresso_phonon/metainfo/__init__.py +19 -0
- workflowparsers/quantum_espresso_phonon/metainfo/quantum_espresso_phonon.py +389 -0
- workflowparsers/quantum_espresso_phonon/parser.py +483 -0
- workflowparsers/quantum_espresso_xspectra/__init__.py +19 -0
- workflowparsers/quantum_espresso_xspectra/__main__.py +31 -0
- workflowparsers/quantum_espresso_xspectra/metainfo/__init__.py +19 -0
- workflowparsers/quantum_espresso_xspectra/metainfo/quantum_espresso_xspectra.py +290 -0
- workflowparsers/quantum_espresso_xspectra/parser.py +586 -0
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright The NOMAD Authors.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of NOMAD.
|
|
5
|
+
# See https://nomad-lab.eu for further info.
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
import os
|
|
20
|
+
import numpy as np
|
|
21
|
+
import logging
|
|
22
|
+
import xarray
|
|
23
|
+
import json
|
|
24
|
+
import re
|
|
25
|
+
|
|
26
|
+
from nomad.units import ureg
|
|
27
|
+
from nomad.parsing.file_parser import FileParser
|
|
28
|
+
|
|
29
|
+
from runschema.run import Run, Program
|
|
30
|
+
from runschema.method import (
|
|
31
|
+
Method,
|
|
32
|
+
DFT,
|
|
33
|
+
XCFunctional,
|
|
34
|
+
Functional,
|
|
35
|
+
BasisSet,
|
|
36
|
+
BasisSetContainer,
|
|
37
|
+
)
|
|
38
|
+
from runschema.system import System, Atoms
|
|
39
|
+
from runschema.calculation import (
|
|
40
|
+
Calculation,
|
|
41
|
+
Thermodynamics,
|
|
42
|
+
Energy,
|
|
43
|
+
EnergyEntry,
|
|
44
|
+
Stress,
|
|
45
|
+
StressEntry,
|
|
46
|
+
Forces,
|
|
47
|
+
ForcesEntry,
|
|
48
|
+
)
|
|
49
|
+
from simulationworkflowschema import (
|
|
50
|
+
SinglePoint,
|
|
51
|
+
GeometryOptimization,
|
|
52
|
+
MolecularDynamics,
|
|
53
|
+
Phonon,
|
|
54
|
+
)
|
|
55
|
+
from .metainfo.fhi_vibes import (
|
|
56
|
+
x_fhi_vibes_section_attributes,
|
|
57
|
+
x_fhi_vibes_section_metadata,
|
|
58
|
+
x_fhi_vibes_section_atoms,
|
|
59
|
+
x_fhi_vibes_section_MD,
|
|
60
|
+
x_fhi_vibes_section_calculator,
|
|
61
|
+
x_fhi_vibes_section_calculator_parameters,
|
|
62
|
+
x_fhi_vibes_section_vibes,
|
|
63
|
+
x_fhi_vibes_section_relaxation,
|
|
64
|
+
x_fhi_vibes_section_relaxation_kwargs,
|
|
65
|
+
x_fhi_vibes_section_settings,
|
|
66
|
+
x_fhi_vibes_section_phonopy,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class XarrayParser(FileParser):
|
|
71
|
+
def __init__(self):
|
|
72
|
+
super().__init__()
|
|
73
|
+
self.re_index = re.compile(r'(.+?)\[(\d+)\]')
|
|
74
|
+
self._raw_metadata = dict()
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def dataset(self):
|
|
78
|
+
if self._file_handler is None:
|
|
79
|
+
try:
|
|
80
|
+
self._file_handler = xarray.open_dataset(self.mainfile)
|
|
81
|
+
self._raw_metadata = json.loads(
|
|
82
|
+
self._file_handler.attrs.get('raw_metadata', '{}')
|
|
83
|
+
)
|
|
84
|
+
except Exception:
|
|
85
|
+
self.logger.error('Error reading trajectory file.')
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
return self._file_handler
|
|
89
|
+
|
|
90
|
+
def parse(self, key):
|
|
91
|
+
key = key.strip('/')
|
|
92
|
+
val = self.dataset
|
|
93
|
+
for section in key.split('/'):
|
|
94
|
+
indexed = re.match(self.re_index, section)
|
|
95
|
+
if indexed:
|
|
96
|
+
section = indexed.group(1)
|
|
97
|
+
index = indexed.group(2)
|
|
98
|
+
if section == 'raw_metadata':
|
|
99
|
+
val = self._raw_metadata
|
|
100
|
+
elif section == 'attrs':
|
|
101
|
+
val = self.dataset.attrs
|
|
102
|
+
else:
|
|
103
|
+
val = val.get(section)
|
|
104
|
+
try:
|
|
105
|
+
val = val[int(index)] if indexed else val
|
|
106
|
+
except Exception:
|
|
107
|
+
val = None
|
|
108
|
+
if val is None:
|
|
109
|
+
break
|
|
110
|
+
if isinstance(val, xarray.DataArray):
|
|
111
|
+
val = np.array(val, dtype=val.dtype)
|
|
112
|
+
|
|
113
|
+
self._results[key] = val
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class FHIVibesParser:
|
|
117
|
+
def __init__(self):
|
|
118
|
+
self.parser = XarrayParser()
|
|
119
|
+
|
|
120
|
+
self._units = {
|
|
121
|
+
'volume': ureg.angstrom**3,
|
|
122
|
+
'displacements': ureg.angstrom,
|
|
123
|
+
'velocities': ureg.angstrom / ureg.fs,
|
|
124
|
+
'momenta': ureg.eV * ureg.fs / ureg.angstrom,
|
|
125
|
+
'force_constants': ureg.eV / ureg.angstrom**2,
|
|
126
|
+
'forces_harmonic': ureg.eV / ureg.angstrom,
|
|
127
|
+
'forces': ureg.eV / ureg.angstrom,
|
|
128
|
+
'stress': ureg.eV / ureg.angstrom**3,
|
|
129
|
+
'energy_potential_harmonic': ureg.eV,
|
|
130
|
+
'sigma_per_sample': None,
|
|
131
|
+
'pressure': ureg.eV / ureg.angstrom**3,
|
|
132
|
+
'temperature': ureg.K,
|
|
133
|
+
'pressure_kinetic': ureg.eV / ureg.angstrom**3,
|
|
134
|
+
'pressure_potential': ureg.eV / ureg.angstrom**3,
|
|
135
|
+
'aims_uuid': None,
|
|
136
|
+
'energy': ureg.eV,
|
|
137
|
+
'heat_flux': ureg.amu / ureg.fs**3,
|
|
138
|
+
'heat_flux_harmonic': ureg.amu / ureg.fs**3,
|
|
139
|
+
'heat_flux_0_harmonic': ureg.amu / ureg.fs**3,
|
|
140
|
+
'mass': ureg.amu,
|
|
141
|
+
'length': ureg.angstrom,
|
|
142
|
+
'time': ureg.fs,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
self._frame_rate = None
|
|
146
|
+
# max cumulative number of atoms for all parsed trajectories to calculate sampling rate
|
|
147
|
+
self._cum_max_atoms = 1000000
|
|
148
|
+
# mas number of frames takes precedent over maximum number of atoms
|
|
149
|
+
self._max_frames = 100
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def frame_rate(self):
|
|
153
|
+
if self._frame_rate is None:
|
|
154
|
+
n_atoms = len(self.parser.get('attrs').get('symbols', []))
|
|
155
|
+
|
|
156
|
+
if n_atoms == 0 or self.n_frames == 0:
|
|
157
|
+
self._frame_rate = 1
|
|
158
|
+
else:
|
|
159
|
+
cum_atoms = n_atoms * self.n_frames
|
|
160
|
+
self._frame_rate = (
|
|
161
|
+
1
|
|
162
|
+
if cum_atoms <= self._cum_max_atoms
|
|
163
|
+
else cum_atoms // self._cum_max_atoms
|
|
164
|
+
)
|
|
165
|
+
if self.n_frames // self._frame_rate > self._max_frames:
|
|
166
|
+
self._frame_rate = self.n_frames // self._max_frames
|
|
167
|
+
return self._frame_rate
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def n_frames(self):
|
|
171
|
+
if self.calculation_type == 'phonon':
|
|
172
|
+
return 1
|
|
173
|
+
return len(self.parser.get('positions', []))
|
|
174
|
+
|
|
175
|
+
def parse_configurations(self):
|
|
176
|
+
def parse_system(n_frame):
|
|
177
|
+
sec_system = System()
|
|
178
|
+
sec_run.system.append(sec_system)
|
|
179
|
+
sec_atoms = Atoms()
|
|
180
|
+
sec_system.atoms = sec_atoms
|
|
181
|
+
sec_atoms.labels = self.parser.get('attrs').get('symbols')
|
|
182
|
+
sec_atoms.positions = self.parser.get(
|
|
183
|
+
'positions', unit=self._units.get('length')
|
|
184
|
+
)[n_frame]
|
|
185
|
+
sec_atoms.lattice_vectors = self.parser.get(
|
|
186
|
+
'cell', unit=self._units.get('length')
|
|
187
|
+
)[n_frame]
|
|
188
|
+
sec_atoms.periodic = self.parser.get('attrs/raw_metadata/atoms/pbc')
|
|
189
|
+
velocities = self.parser.get(
|
|
190
|
+
'velocities', unit=self._units.get('velocities')
|
|
191
|
+
)
|
|
192
|
+
if velocities is not None:
|
|
193
|
+
sec_atoms.velocities = velocities[n_frame]
|
|
194
|
+
return sec_system
|
|
195
|
+
|
|
196
|
+
def parse_scc(n_frame):
|
|
197
|
+
sec_scc = Calculation()
|
|
198
|
+
sec_run.calculation.append(sec_scc)
|
|
199
|
+
sec_thermo = Thermodynamics()
|
|
200
|
+
sec_scc.thermodynamics.append(sec_thermo)
|
|
201
|
+
|
|
202
|
+
if self.calculation_type == 'molecular_dynamics':
|
|
203
|
+
sec_thermo.time_step = n_frame
|
|
204
|
+
# TODO metainfo should be in common
|
|
205
|
+
sec_scc.x_fhi_vibes_MD_time = n_frame * timestep
|
|
206
|
+
|
|
207
|
+
sec_energy = Energy()
|
|
208
|
+
sec_scc.energy = sec_energy
|
|
209
|
+
sec_forces = Forces()
|
|
210
|
+
sec_scc.forces = sec_forces
|
|
211
|
+
sec_stress = Stress()
|
|
212
|
+
sec_scc.stress = sec_stress
|
|
213
|
+
for key in ['kinetic', 'potential']:
|
|
214
|
+
val = self.parser.get('energy_%s' % key, unit=self._units.get('energy'))
|
|
215
|
+
if val is not None:
|
|
216
|
+
sec_energy.contributions.append(
|
|
217
|
+
EnergyEntry(value=val[n_frame], kind=key)
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
val = self.parser.get('stress_%s' % key, unit=self._units.get('stress'))
|
|
221
|
+
if val is not None:
|
|
222
|
+
sec_stress.contributions.append(
|
|
223
|
+
StressEntry(value=val[n_frame], kind=key)
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
val = self.parser.get(
|
|
227
|
+
'stresses_%s' % key, unit=self._units.get('stress')
|
|
228
|
+
)
|
|
229
|
+
if val is not None:
|
|
230
|
+
sec_stress.contributions[-1].values_per_atom = val[n_frame]
|
|
231
|
+
|
|
232
|
+
calculation_quantities = [
|
|
233
|
+
'volume',
|
|
234
|
+
'displacements',
|
|
235
|
+
'momenta',
|
|
236
|
+
'forces_harmonic',
|
|
237
|
+
'forces',
|
|
238
|
+
'stress',
|
|
239
|
+
'energy_potential_harmonic',
|
|
240
|
+
'sigma_per_sample',
|
|
241
|
+
'pressure',
|
|
242
|
+
'temperature',
|
|
243
|
+
'pressure_kinetic',
|
|
244
|
+
'pressure_potential',
|
|
245
|
+
'aims_uuid',
|
|
246
|
+
'heat_flux',
|
|
247
|
+
'heat_flux_harmonic',
|
|
248
|
+
'heat_flux_0_harmonic',
|
|
249
|
+
]
|
|
250
|
+
for key in calculation_quantities:
|
|
251
|
+
val = self.parser.get(key, unit=self._units.get(key, None))
|
|
252
|
+
if val is None:
|
|
253
|
+
continue
|
|
254
|
+
|
|
255
|
+
# TODO figure out what shape of output fc
|
|
256
|
+
if key.startswith('force_constants'):
|
|
257
|
+
continue
|
|
258
|
+
if key.startswith('forces'):
|
|
259
|
+
key = 'atom_%s' % key
|
|
260
|
+
|
|
261
|
+
if key == 'atom_forces':
|
|
262
|
+
sec_forces.total = ForcesEntry(value=val[n_frame])
|
|
263
|
+
elif key == 'stress':
|
|
264
|
+
sec_stress.total = StressEntry(value=val[n_frame])
|
|
265
|
+
if key in ['temperature', 'pressure', 'volume']:
|
|
266
|
+
setattr(sec_thermo, key, val[n_frame])
|
|
267
|
+
else:
|
|
268
|
+
setattr(sec_scc, 'x_fhi_vibes_%s' % key, val[n_frame])
|
|
269
|
+
|
|
270
|
+
return sec_scc
|
|
271
|
+
|
|
272
|
+
sec_scc = None
|
|
273
|
+
try:
|
|
274
|
+
sec_atrr = (
|
|
275
|
+
self.archive.run[-1].method[-1].x_fhi_vibes_section_attributes[-1]
|
|
276
|
+
)
|
|
277
|
+
timestep = sec_atrr.x_fhi_vibes_attributes_timestep
|
|
278
|
+
except Exception:
|
|
279
|
+
timestep = 0
|
|
280
|
+
|
|
281
|
+
for n_frame in range(self.n_frames):
|
|
282
|
+
if (n_frame % self.frame_rate) > 0:
|
|
283
|
+
continue
|
|
284
|
+
|
|
285
|
+
if self.calculation_type == 'single_point':
|
|
286
|
+
sec_run = self.archive.run[n_frame]
|
|
287
|
+
# we can only do this for single point where we have separate section_runs
|
|
288
|
+
# for each frame
|
|
289
|
+
sec_run.raw_id = self.parser.get('aims_uuid')[n_frame]
|
|
290
|
+
else:
|
|
291
|
+
# TODO aims_uuid is in x_fhi_vibes_aims_uuid, this should be changed
|
|
292
|
+
sec_run = self.archive.run[-1]
|
|
293
|
+
|
|
294
|
+
sec_system = parse_system(n_frame)
|
|
295
|
+
sec_scc = parse_scc(n_frame)
|
|
296
|
+
sec_scc.system_ref = sec_system
|
|
297
|
+
sec_scc.method_ref = sec_run.method[-1]
|
|
298
|
+
|
|
299
|
+
# force constants
|
|
300
|
+
for key in ['force_constants', 'force_constants_remapped']:
|
|
301
|
+
val = self.parser.get(key, unit=self._units.get('force_constants'))
|
|
302
|
+
if val is not None and sec_scc:
|
|
303
|
+
setattr(sec_scc, 'x_fhi_vibes_%s' % key, val)
|
|
304
|
+
|
|
305
|
+
def parse_method(self, n_run):
|
|
306
|
+
def parse_xc_functional():
|
|
307
|
+
# TODO This is a temporary fix to circumvent the normalization tests failure
|
|
308
|
+
# due to missing xc functional information but this should be fetched directly
|
|
309
|
+
# from the underlying calculation
|
|
310
|
+
xc_type_map = {'PW': 'C'}
|
|
311
|
+
calculator_parameters = self.parser.get(
|
|
312
|
+
'attrs/raw_metadata/calculator/calculator_parameters', {}
|
|
313
|
+
)
|
|
314
|
+
xc_functional = calculator_parameters.get('xc', '').upper()
|
|
315
|
+
xc_functional_info = re.match(
|
|
316
|
+
r'(\w+)\S+?((?:LDA|GGA|MGGA|HYB_GGA|HYB_MGGA))', xc_functional
|
|
317
|
+
)
|
|
318
|
+
if xc_functional_info:
|
|
319
|
+
xc_name = xc_functional_info.group(1)
|
|
320
|
+
xc_type = xc_type_map.get(xc_name, None)
|
|
321
|
+
if xc_type is None:
|
|
322
|
+
self.logger.error('Cannot resolve XC functional.')
|
|
323
|
+
return
|
|
324
|
+
name = '%s_%s_%s' % (
|
|
325
|
+
xc_functional_info.group(2),
|
|
326
|
+
xc_type,
|
|
327
|
+
xc_functional_info.group(1),
|
|
328
|
+
)
|
|
329
|
+
sec_xc_functional = XCFunctional()
|
|
330
|
+
sec_dft.xc_functional = sec_xc_functional
|
|
331
|
+
functional = Functional(name=name)
|
|
332
|
+
if 'HYB' in name:
|
|
333
|
+
sec_xc_functional.hybrid.append(functional)
|
|
334
|
+
elif '_X_' in name:
|
|
335
|
+
sec_xc_functional.exchange.append(functional)
|
|
336
|
+
elif '_C_' in name:
|
|
337
|
+
sec_xc_functional.correlation.append(functional)
|
|
338
|
+
else:
|
|
339
|
+
sec_xc_functional.contributions.append(functional)
|
|
340
|
+
|
|
341
|
+
def parse_atoms(section, atoms):
|
|
342
|
+
for key, val in atoms.items():
|
|
343
|
+
# why is the formatting of symbols and masses different for atoms?
|
|
344
|
+
if key in ['symbols', 'masses']:
|
|
345
|
+
if isinstance(val[0], list):
|
|
346
|
+
val_flattened = []
|
|
347
|
+
for val_i in val:
|
|
348
|
+
val_flattened.extend([val_i[1]] * val_i[0])
|
|
349
|
+
val = val_flattened
|
|
350
|
+
if key == 'masses':
|
|
351
|
+
val = val * self._units.get('mass')
|
|
352
|
+
elif key in ['positions', 'cell']:
|
|
353
|
+
val = val * self._units.get('length')
|
|
354
|
+
elif key == 'velocities':
|
|
355
|
+
val = val * self._units.get('length') / self._units.get('time')
|
|
356
|
+
setattr(section, 'x_fhi_vibes_atoms_%s' % key, val)
|
|
357
|
+
|
|
358
|
+
def parse_metadata():
|
|
359
|
+
metadata = self.parser.get('attrs/raw_metadata')
|
|
360
|
+
sec_metadata = x_fhi_vibes_section_metadata()
|
|
361
|
+
sec_attrs.x_fhi_vibes_section_attributes_metadata.append(sec_metadata)
|
|
362
|
+
for key, val in metadata.items():
|
|
363
|
+
if key == 'MD':
|
|
364
|
+
sec_md = x_fhi_vibes_section_MD()
|
|
365
|
+
sec_metadata.x_fhi_vibes_section_metadata_MD.append(sec_md)
|
|
366
|
+
for md_key in val.keys():
|
|
367
|
+
setattr(
|
|
368
|
+
sec_md,
|
|
369
|
+
'x_fhi_vibes_MD_%s' % md_key.replace('-', '_'),
|
|
370
|
+
val[md_key],
|
|
371
|
+
)
|
|
372
|
+
elif key == 'relaxation':
|
|
373
|
+
sec_relaxation = x_fhi_vibes_section_relaxation()
|
|
374
|
+
sec_metadata.x_fhi_vibes_section_relaxation.append(sec_relaxation)
|
|
375
|
+
for relaxation_key in val.keys():
|
|
376
|
+
if relaxation_key == 'kwargs':
|
|
377
|
+
sec_kwargs = x_fhi_vibes_section_relaxation_kwargs()
|
|
378
|
+
sec_relaxation.x_fhi_vibes_section_relaxation_kwargs.append(
|
|
379
|
+
sec_kwargs
|
|
380
|
+
)
|
|
381
|
+
for kwargs_key in val['kwargs']:
|
|
382
|
+
setattr(
|
|
383
|
+
sec_kwargs,
|
|
384
|
+
'x_fhi_vibes_relaxation_kwargs_%s' % kwargs_key,
|
|
385
|
+
val['kwargs'][kwargs_key],
|
|
386
|
+
)
|
|
387
|
+
else:
|
|
388
|
+
setattr(
|
|
389
|
+
sec_relaxation,
|
|
390
|
+
'x_fhi_vibes_relaxation_%s'
|
|
391
|
+
% relaxation_key.replace('-', '_'),
|
|
392
|
+
val[relaxation_key],
|
|
393
|
+
)
|
|
394
|
+
elif key == 'Phonopy':
|
|
395
|
+
sec_phonopy = x_fhi_vibes_section_phonopy()
|
|
396
|
+
sec_metadata.x_fhi_vibes_section_phonopy.append(sec_phonopy)
|
|
397
|
+
for phonopy_key in val.keys():
|
|
398
|
+
if phonopy_key == 'primitive':
|
|
399
|
+
sec_primitive = x_fhi_vibes_section_atoms()
|
|
400
|
+
sec_phonopy.x_fhi_vibes_section_phonopy_primitive.append(
|
|
401
|
+
sec_primitive
|
|
402
|
+
)
|
|
403
|
+
parse_atoms(sec_primitive, val['primitive'])
|
|
404
|
+
else:
|
|
405
|
+
setattr(
|
|
406
|
+
sec_phonopy,
|
|
407
|
+
'x_fhi_vibes_phonopy_%s' % phonopy_key,
|
|
408
|
+
val[phonopy_key],
|
|
409
|
+
)
|
|
410
|
+
elif key == 'calculator':
|
|
411
|
+
sec_calculator = x_fhi_vibes_section_calculator()
|
|
412
|
+
sec_metadata.x_fhi_vibes_section_metadata_calculator.append(
|
|
413
|
+
sec_calculator
|
|
414
|
+
)
|
|
415
|
+
sec_calculator.x_fhi_vibes_calculator = metadata['calculator'][
|
|
416
|
+
'calculator'
|
|
417
|
+
]
|
|
418
|
+
sec_calculator_parameters = (
|
|
419
|
+
x_fhi_vibes_section_calculator_parameters()
|
|
420
|
+
)
|
|
421
|
+
sec_calculator.x_fhi_vibes_section_calculator_parameters.append(
|
|
422
|
+
sec_calculator_parameters
|
|
423
|
+
)
|
|
424
|
+
for calc_key in val['calculator_parameters'].keys():
|
|
425
|
+
if calc_key == 'use_pimd_wrapper':
|
|
426
|
+
val['calculator_parameters'][calc_key] = str(
|
|
427
|
+
val['calculator_parameters'][calc_key]
|
|
428
|
+
)
|
|
429
|
+
setattr(
|
|
430
|
+
sec_calculator_parameters,
|
|
431
|
+
'x_fhi_vibes_calculator_parameters_%s' % calc_key,
|
|
432
|
+
val['calculator_parameters'][calc_key],
|
|
433
|
+
)
|
|
434
|
+
elif key in ['atoms', 'primitive', 'supercell']:
|
|
435
|
+
sec_atoms = x_fhi_vibes_section_atoms()
|
|
436
|
+
sec_metadata.x_fhi_vibes_section_metadata_atoms.append(sec_atoms)
|
|
437
|
+
sec_atoms.x_fhi_vibes_atoms_kind = key
|
|
438
|
+
parse_atoms(sec_atoms, val)
|
|
439
|
+
elif key == 'vibes':
|
|
440
|
+
sec_vibes = x_fhi_vibes_section_vibes()
|
|
441
|
+
sec_metadata.x_fhi_vibes_section_metadata_vibes.append(sec_vibes)
|
|
442
|
+
for vibes_key in val.keys():
|
|
443
|
+
setattr(sec_vibes, 'x_fhi_vibes_%s' % vibes_key, val[vibes_key])
|
|
444
|
+
elif key == 'settings':
|
|
445
|
+
sec_settings = x_fhi_vibes_section_settings()
|
|
446
|
+
sec_metadata.x_fhi_vibes_section_metadata_settings.append(
|
|
447
|
+
sec_settings
|
|
448
|
+
)
|
|
449
|
+
for settings_key in val.keys():
|
|
450
|
+
setattr(
|
|
451
|
+
sec_settings,
|
|
452
|
+
'x_fhi_vibes_settings_%s' % settings_key,
|
|
453
|
+
val[settings_key],
|
|
454
|
+
)
|
|
455
|
+
else:
|
|
456
|
+
setattr(sec_metadata, key, val)
|
|
457
|
+
|
|
458
|
+
sec_method = Method()
|
|
459
|
+
self.archive.run[n_run].method.append(sec_method)
|
|
460
|
+
sec_dft = DFT()
|
|
461
|
+
sec_method.dft = sec_dft
|
|
462
|
+
|
|
463
|
+
parse_xc_functional()
|
|
464
|
+
|
|
465
|
+
sec_attrs = x_fhi_vibes_section_attributes()
|
|
466
|
+
sec_method.x_fhi_vibes_section_attributes.append(sec_attrs)
|
|
467
|
+
|
|
468
|
+
time_units = {'ns': ureg.ns, 'fs': ureg.fs, 'ps': ureg.ps}
|
|
469
|
+
attrs = self.parser.get('attrs')
|
|
470
|
+
for key, val in attrs.items():
|
|
471
|
+
if key == 'raw_metadata':
|
|
472
|
+
parse_metadata()
|
|
473
|
+
elif key.startswith('atoms_'):
|
|
474
|
+
sec_atoms = x_fhi_vibes_section_atoms()
|
|
475
|
+
sec_attrs.x_fhi_vibes_section_attributes_atoms.append(sec_atoms)
|
|
476
|
+
sec_atoms.x_fhi_vibes_atoms_kind = key
|
|
477
|
+
atoms = json.loads(val)
|
|
478
|
+
sec_atoms.x_fhi_vibes_atoms_natoms = len(atoms['positions'])
|
|
479
|
+
parse_atoms(sec_atoms, atoms)
|
|
480
|
+
setattr(
|
|
481
|
+
sec_attrs,
|
|
482
|
+
'x_fhi_vibes_attributes_number_of_%s' % key,
|
|
483
|
+
len(atoms['positions']),
|
|
484
|
+
)
|
|
485
|
+
else:
|
|
486
|
+
if key == 'masses':
|
|
487
|
+
val = val * self._units.get('mass')
|
|
488
|
+
elif key == 'timestep':
|
|
489
|
+
val = val * time_units.get(
|
|
490
|
+
attrs.get('time_unit').lower(), self._units.get('time')
|
|
491
|
+
)
|
|
492
|
+
setattr(sec_attrs, 'x_fhi_vibes_attributes_%s' % key, val)
|
|
493
|
+
|
|
494
|
+
# we need this information for force constants
|
|
495
|
+
n_atoms_supercell = sec_attrs.x_fhi_vibes_attributes_number_of_atoms_supercell
|
|
496
|
+
if n_atoms_supercell:
|
|
497
|
+
sec_attrs.x_fhi_vibes_attributes_force_constants_remapped_size = (
|
|
498
|
+
n_atoms_supercell * 3
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
def init_parser(self):
|
|
502
|
+
self.parser.mainfile = self.filepath
|
|
503
|
+
self.parser.logger = self.logger
|
|
504
|
+
|
|
505
|
+
def parse(self, filepath, archive, logger):
|
|
506
|
+
self.filepath = os.path.abspath(filepath)
|
|
507
|
+
self.archive = archive
|
|
508
|
+
self.logger = logger if logger is not None else logging.getLogger(__name__)
|
|
509
|
+
self.maindir = os.path.dirname(self.filepath)
|
|
510
|
+
|
|
511
|
+
self.init_parser()
|
|
512
|
+
|
|
513
|
+
metadata = self.parser.get('attrs/raw_metadata')
|
|
514
|
+
|
|
515
|
+
if 'MD' in metadata:
|
|
516
|
+
self.calculation_type = 'molecular_dynamics'
|
|
517
|
+
self.archive.workflow2 = MolecularDynamics()
|
|
518
|
+
elif 'relaxation' in metadata:
|
|
519
|
+
self.calculation_type = 'geometry_optimization'
|
|
520
|
+
self.archive.workflow2 = GeometryOptimization()
|
|
521
|
+
elif 'Phonopy' in metadata:
|
|
522
|
+
self.calculation_type = 'phonon'
|
|
523
|
+
self.archive.workflow2 = Phonon()
|
|
524
|
+
else:
|
|
525
|
+
# the single point workflow in vibes means multiple separate calculations on
|
|
526
|
+
# on same material (stoichiometry, number of atoms) but may differ on
|
|
527
|
+
# on structure (lattice, positions). This means we need to create separate
|
|
528
|
+
# section runs
|
|
529
|
+
self.calculation_type = 'single_point'
|
|
530
|
+
self.archive.workflow2 = SinglePoint()
|
|
531
|
+
|
|
532
|
+
if self.calculation_type == 'single_point':
|
|
533
|
+
for n_frame in range(self.n_frames):
|
|
534
|
+
if (n_frame % self.frame_rate) > 0:
|
|
535
|
+
continue
|
|
536
|
+
self.archive.run.append(Run())
|
|
537
|
+
else:
|
|
538
|
+
self.archive.run.append(Run())
|
|
539
|
+
|
|
540
|
+
for n_run, sec_run in enumerate(self.archive.run):
|
|
541
|
+
sec_run.program = Program(
|
|
542
|
+
name='FHI-vibes', version=metadata.get('vibes', dict()).get('version')
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
self.parse_method(n_run)
|
|
546
|
+
if metadata.get('calculator', dict()).get('calculator').lower() == 'aims':
|
|
547
|
+
sec_run.method[-1].electrons_representation = [
|
|
548
|
+
BasisSetContainer(
|
|
549
|
+
type='atom-centered orbitals',
|
|
550
|
+
scope=['wavefunction'],
|
|
551
|
+
basis_set=[
|
|
552
|
+
BasisSet(
|
|
553
|
+
type='numeric AOs',
|
|
554
|
+
scope=['full-electron'],
|
|
555
|
+
)
|
|
556
|
+
],
|
|
557
|
+
)
|
|
558
|
+
]
|
|
559
|
+
|
|
560
|
+
# TODO For single_point, we can only have workflow for one vibes single point frame
|
|
561
|
+
# as workflow is not repeating in metainfo.
|
|
562
|
+
# To resolve this, we can redefine single_point workflow to be consistent with
|
|
563
|
+
# the idea of vibes single point but I do not like it.
|
|
564
|
+
self.parse_configurations()
|
|
565
|
+
|
|
566
|
+
self.parser.close()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright The NOMAD Authors.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of NOMAD.
|
|
5
|
+
# See https://nomad-lab.eu for further info.
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
from .parser import LobsterParser
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright The NOMAD Authors.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of NOMAD.
|
|
5
|
+
# See https://nomad-lab.eu for further info.
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
import sys
|
|
20
|
+
import json
|
|
21
|
+
import logging
|
|
22
|
+
|
|
23
|
+
from nomad.utils import configure_logging
|
|
24
|
+
from nomad.datamodel import EntryArchive
|
|
25
|
+
from workflowparsers.lobster import LobsterParser
|
|
26
|
+
|
|
27
|
+
if __name__ == '__main__':
|
|
28
|
+
configure_logging(console_log_level=logging.DEBUG)
|
|
29
|
+
archive = EntryArchive()
|
|
30
|
+
LobsterParser().parse(sys.argv[1], archive, logging)
|
|
31
|
+
json.dump(archive.m_to_dict(), sys.stdout, indent=2)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright The NOMAD Authors.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of NOMAD.
|
|
5
|
+
# See https://nomad-lab.eu for further info.
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
from . import lobster
|