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.
Files changed (58) hide show
  1. nomad_parser_plugins_workflow-1.0.dist-info/LICENSE +202 -0
  2. nomad_parser_plugins_workflow-1.0.dist-info/METADATA +319 -0
  3. nomad_parser_plugins_workflow-1.0.dist-info/RECORD +58 -0
  4. nomad_parser_plugins_workflow-1.0.dist-info/WHEEL +5 -0
  5. nomad_parser_plugins_workflow-1.0.dist-info/entry_points.txt +11 -0
  6. nomad_parser_plugins_workflow-1.0.dist-info/top_level.txt +1 -0
  7. workflowparsers/__init__.py +314 -0
  8. workflowparsers/aflow/__init__.py +19 -0
  9. workflowparsers/aflow/__main__.py +31 -0
  10. workflowparsers/aflow/metainfo/__init__.py +19 -0
  11. workflowparsers/aflow/metainfo/aflow.py +1240 -0
  12. workflowparsers/aflow/parser.py +741 -0
  13. workflowparsers/asr/__init__.py +19 -0
  14. workflowparsers/asr/__main__.py +31 -0
  15. workflowparsers/asr/metainfo/__init__.py +19 -0
  16. workflowparsers/asr/metainfo/asr.py +306 -0
  17. workflowparsers/asr/parser.py +266 -0
  18. workflowparsers/atomate/__init__.py +19 -0
  19. workflowparsers/atomate/__main__.py +31 -0
  20. workflowparsers/atomate/metainfo/__init__.py +19 -0
  21. workflowparsers/atomate/metainfo/atomate.py +395 -0
  22. workflowparsers/atomate/parser.py +357 -0
  23. workflowparsers/elastic/__init__.py +19 -0
  24. workflowparsers/elastic/__main__.py +31 -0
  25. workflowparsers/elastic/metainfo/__init__.py +19 -0
  26. workflowparsers/elastic/metainfo/elastic.py +364 -0
  27. workflowparsers/elastic/parser.py +798 -0
  28. workflowparsers/fhivibes/__init__.py +19 -0
  29. workflowparsers/fhivibes/__main__.py +31 -0
  30. workflowparsers/fhivibes/metainfo/__init__.py +19 -0
  31. workflowparsers/fhivibes/metainfo/fhi_vibes.py +898 -0
  32. workflowparsers/fhivibes/parser.py +566 -0
  33. workflowparsers/lobster/__init__.py +19 -0
  34. workflowparsers/lobster/__main__.py +31 -0
  35. workflowparsers/lobster/metainfo/__init__.py +19 -0
  36. workflowparsers/lobster/metainfo/lobster.py +446 -0
  37. workflowparsers/lobster/parser.py +618 -0
  38. workflowparsers/phonopy/__init__.py +19 -0
  39. workflowparsers/phonopy/__main__.py +31 -0
  40. workflowparsers/phonopy/calculator.py +260 -0
  41. workflowparsers/phonopy/metainfo/__init__.py +19 -0
  42. workflowparsers/phonopy/metainfo/phonopy.py +83 -0
  43. workflowparsers/phonopy/parser.py +583 -0
  44. workflowparsers/quantum_espresso_epw/__init__.py +19 -0
  45. workflowparsers/quantum_espresso_epw/__main__.py +31 -0
  46. workflowparsers/quantum_espresso_epw/metainfo/__init__.py +19 -0
  47. workflowparsers/quantum_espresso_epw/metainfo/quantum_espresso_epw.py +579 -0
  48. workflowparsers/quantum_espresso_epw/parser.py +583 -0
  49. workflowparsers/quantum_espresso_phonon/__init__.py +19 -0
  50. workflowparsers/quantum_espresso_phonon/__main__.py +31 -0
  51. workflowparsers/quantum_espresso_phonon/metainfo/__init__.py +19 -0
  52. workflowparsers/quantum_espresso_phonon/metainfo/quantum_espresso_phonon.py +389 -0
  53. workflowparsers/quantum_espresso_phonon/parser.py +483 -0
  54. workflowparsers/quantum_espresso_xspectra/__init__.py +19 -0
  55. workflowparsers/quantum_espresso_xspectra/__main__.py +31 -0
  56. workflowparsers/quantum_espresso_xspectra/metainfo/__init__.py +19 -0
  57. workflowparsers/quantum_espresso_xspectra/metainfo/quantum_espresso_xspectra.py +290 -0
  58. 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