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,618 @@
1
+ #
2
+ # Copyright The NOMAD Authors.
3
+ #
4
+ # This file is part of NOMAD. See https://nomad-lab.eu for further info.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ import datetime
20
+ import numpy as np
21
+ import ase.io
22
+ import os
23
+
24
+ from nomad.datamodel import EntryArchive
25
+ from nomad.units import ureg as units
26
+ from nomad.parsing.parsers import _compressions
27
+ from runschema.run import Run, Program, TimeRun
28
+ from runschema.system import System, Atoms
29
+ from runschema.method import (
30
+ Method,
31
+ Electronic,
32
+ BasisSet,
33
+ BasisSetContainer,
34
+ )
35
+ from runschema.calculation import Calculation, Dos, DosValues, Charges
36
+
37
+ from nomad.parsing.file_parser import TextParser, Quantity
38
+
39
+ from .metainfo.lobster import x_lobster_section_cohp, x_lobster_section_coop
40
+
41
+ """
42
+ This is a LOBSTER code parser.
43
+ """
44
+
45
+ e = (1 * units.e).to_base_units().magnitude
46
+ eV = (1 * units.eV).to_base_units().magnitude
47
+
48
+
49
+ def get_lobster_file(filename):
50
+ compressions = [''] + [v[0] for v in _compressions.values()]
51
+ for compression in compressions:
52
+ name = f'{filename}.{compression}'
53
+ if os.path.isfile(name):
54
+ return name
55
+ return filename
56
+
57
+
58
+ def parse_ICOXPLIST(fname, scc, method):
59
+ def icoxp_line_split(string):
60
+ tmp = string.split()
61
+ # LOBSTER version 3 and above
62
+ if len(tmp) == 8:
63
+ return [
64
+ tmp[1],
65
+ tmp[2],
66
+ float(tmp[3]),
67
+ [int(tmp[4]), int(tmp[5]), int(tmp[6])],
68
+ float(tmp[7]),
69
+ ]
70
+ # LOBSTER versions below 3
71
+ elif len(tmp) == 6:
72
+ return [tmp[1], tmp[2], float(tmp[3]), float(tmp[4]), int(tmp[5])]
73
+
74
+ icoxplist_parser = TextParser(
75
+ quantities=[
76
+ Quantity(
77
+ 'icoxpslist_for_spin',
78
+ r'\s*CO[OH]P.*spin\s*\d\s*([^#]+[-\d\.]+)',
79
+ repeats=True,
80
+ sub_parser=TextParser(
81
+ quantities=[
82
+ Quantity(
83
+ 'line',
84
+ # LOBSTER version 3 and above
85
+ r'(\s*\d+\s+\w+\s+\w+\s+[\.\d]+\s+[-\d]+\s+[-\d]+\s+[-\d]+\s+[-\.\d]+\s*)|'
86
+ # LOBSTER versions below 3
87
+ r'(\s*\d+\s+\w+\s+\w+\s+[\.\d]+\s+[-\.\d]+\s+[\d]+\s*)',
88
+ repeats=True,
89
+ str_operation=icoxp_line_split,
90
+ )
91
+ ]
92
+ ),
93
+ )
94
+ ]
95
+ )
96
+
97
+ if not os.path.isfile(fname):
98
+ return
99
+ icoxplist_parser.mainfile = fname
100
+ icoxplist_parser.parse()
101
+
102
+ icoxp = []
103
+ for spin, icoxplist in enumerate(icoxplist_parser.get('icoxpslist_for_spin')):
104
+ lines = icoxplist.get('line')
105
+ if lines is None:
106
+ break
107
+ if isinstance(lines[0][4], int):
108
+ a1, a2, distances, tmp, bonds = zip(*lines)
109
+ else:
110
+ a1, a2, distances, v, tmp = zip(*lines)
111
+ icoxp.append(0)
112
+ icoxp[-1] = list(tmp)
113
+ if spin == 0:
114
+ if method == 'o':
115
+ section = x_lobster_section_coop()
116
+ scc.x_lobster_section_coop = section
117
+ elif method == 'h':
118
+ section = x_lobster_section_cohp()
119
+ scc.x_lobster_section_cohp = section
120
+
121
+ setattr(
122
+ section, 'x_lobster_number_of_co{}p_pairs'.format(method), len(list(a1))
123
+ )
124
+ setattr(section, 'x_lobster_co{}p_atom1_labels'.format(method), list(a1))
125
+ setattr(section, 'x_lobster_co{}p_atom2_labels'.format(method), list(a2))
126
+ setattr(
127
+ section,
128
+ 'x_lobster_co{}p_distances'.format(method),
129
+ np.array(distances) * units.angstrom,
130
+ )
131
+
132
+ # version specific entries
133
+ if 'v' in locals():
134
+ setattr(section, 'x_lobster_co{}p_translations'.format(method), list(v))
135
+ if 'bonds' in locals():
136
+ setattr(
137
+ section,
138
+ 'x_lobster_co{}p_number_of_bonds'.format(method),
139
+ list(bonds),
140
+ )
141
+
142
+ if len(icoxp) > 0:
143
+ setattr(
144
+ section,
145
+ 'x_lobster_integrated_co{}p_at_fermi_level'.format(method),
146
+ np.array(icoxp) * units.eV,
147
+ )
148
+
149
+
150
+ def parse_COXPCAR(fname, scc, method, logger):
151
+ coxpcar_parser = TextParser(
152
+ quantities=[
153
+ Quantity(
154
+ 'coxp_pairs',
155
+ r'No\.\d+:(\w{1,2}\d+)->(\w{1,2}\d+)\(([\d\.]+)\)\s*?',
156
+ repeats=True,
157
+ ),
158
+ Quantity(
159
+ 'coxp_lines', r'\n\s*(-*\d+\.\d+(?:[ \t]+-*\d+\.\d+)+)', repeats=True
160
+ ),
161
+ ]
162
+ )
163
+
164
+ if not os.path.isfile(fname):
165
+ return
166
+ coxpcar_parser.mainfile = fname
167
+ coxpcar_parser.parse()
168
+
169
+ if method == 'o':
170
+ if not scc.x_lobster_section_coop:
171
+ section = x_lobster_section_coop()
172
+ section.x_lobster_section_coop = section
173
+ else:
174
+ section = scc.x_lobster_section_coop
175
+ elif method == 'h':
176
+ if not scc.x_lobster_section_cohp:
177
+ section = x_lobster_section_cohp()
178
+ scc.x_lobster_section_cohp = section
179
+ else:
180
+ section = scc.x_lobster_section_cohp
181
+
182
+ pairs = coxpcar_parser.get('coxp_pairs')
183
+ if pairs is None:
184
+ logger.warning(
185
+ 'No CO{}P values detected in CO{}PCAR.lobster.'.format(
186
+ method.upper(), method.upper()
187
+ )
188
+ )
189
+ return
190
+ a1, a2, distances = zip(*pairs)
191
+ number_of_pairs = len(list(a1))
192
+
193
+ setattr(section, 'x_lobster_number_of_co{}p_pairs'.format(method), number_of_pairs)
194
+ setattr(section, 'x_lobster_co{}p_atom1_labels'.format(method), list(a1))
195
+ setattr(section, 'x_lobster_co{}p_atom2_labels'.format(method), list(a2))
196
+ setattr(
197
+ section,
198
+ 'x_lobster_co{}p_distances'.format(method),
199
+ np.array(distances) * units.angstrom,
200
+ )
201
+
202
+ coxp_lines = coxpcar_parser.get('coxp_lines')
203
+ if coxp_lines is None:
204
+ logger.warning(
205
+ 'No CO{}P values detected in CO{}PCAR.lobster.'
206
+ 'The file is likely incomplete'.format(method.upper(), method.upper())
207
+ )
208
+ return
209
+ coxp_lines = list(zip(*coxp_lines))
210
+
211
+ setattr(
212
+ section, 'x_lobster_number_of_co{}p_values'.format(method), len(coxp_lines[0])
213
+ )
214
+ setattr(
215
+ section,
216
+ 'x_lobster_co{}p_energies'.format(method),
217
+ np.array(coxp_lines[0]) * units.eV,
218
+ )
219
+
220
+ if len(coxp_lines) == 2 * number_of_pairs + 3:
221
+ coxp = [[x] for x in coxp_lines[3::2]]
222
+ icoxp = [[x] for x in coxp_lines[4::2]]
223
+ acoxp = [coxp_lines[1]]
224
+ aicoxp = [coxp_lines[2]]
225
+ elif len(coxp_lines) == 4 * number_of_pairs + 5:
226
+ coxp = [
227
+ x
228
+ for x in zip(
229
+ coxp_lines[5 : number_of_pairs * 2 + 4 : 2],
230
+ coxp_lines[number_of_pairs * 2 + 5 : 4 * number_of_pairs + 4 : 2],
231
+ )
232
+ ]
233
+ icoxp = [
234
+ x
235
+ for x in zip(
236
+ coxp_lines[6 : number_of_pairs * 2 + 5 : 2],
237
+ coxp_lines[number_of_pairs * 2 + 6 : 4 * number_of_pairs + 5 : 2],
238
+ )
239
+ ]
240
+ acoxp = [coxp_lines[1], coxp_lines[3]]
241
+ aicoxp = [coxp_lines[2], coxp_lines[4]]
242
+ else:
243
+ logger.warning(
244
+ 'Unexpected number of columns {} ' 'in CO{}PCAR.lobster.'.format(
245
+ len(coxp_lines), method.upper()
246
+ )
247
+ )
248
+ return
249
+
250
+ # FIXME: correct magnitude?
251
+ setattr(section, 'x_lobster_co{}p_values'.format(method), np.array(coxp))
252
+ setattr(section, 'x_lobster_average_co{}p_values'.format(method), np.array(acoxp))
253
+ setattr(
254
+ section,
255
+ 'x_lobster_integrated_co{}p_values'.format(method),
256
+ np.array(icoxp) * units.eV,
257
+ )
258
+ setattr(
259
+ section,
260
+ 'x_lobster_average_integrated_co{}p_values'.format(method),
261
+ np.array(aicoxp) * units.eV,
262
+ )
263
+ setattr(
264
+ section,
265
+ 'x_lobster_integrated_co{}p_values'.format(method),
266
+ np.array(icoxp) * units.eV,
267
+ )
268
+
269
+
270
+ def parse_CHARGE(fname, scc):
271
+ charge_parser = TextParser(
272
+ quantities=[
273
+ Quantity(
274
+ 'charges',
275
+ r'\s*\d+\s+[A-Za-z]{1,2}\s+([-\d\.]+)\s+([-\d\.]+)\s*',
276
+ repeats=True,
277
+ )
278
+ ]
279
+ )
280
+
281
+ if not os.path.isfile(fname):
282
+ return
283
+ charge_parser.mainfile = fname
284
+ charge_parser.parse()
285
+
286
+ charges = charge_parser.get('charges')
287
+ if charges is not None:
288
+ sec_charges = Charges()
289
+ scc.charges.append(sec_charges)
290
+ sec_charges.analysis_method = 'mulliken'
291
+ sec_charges.kind = 'integrated'
292
+ sec_charges.value = np.array(list(zip(*charges))[0]) * units.elementary_charge
293
+ sec_charges = Charges()
294
+ scc.charges.append(sec_charges)
295
+ sec_charges.analysis_method = 'loewdin'
296
+ sec_charges.kind = 'integrated'
297
+ sec_charges.value = np.array(list(zip(*charges))[1]) * units.elementary_charge
298
+
299
+
300
+ def parse_DOSCAR(fname, run, logger):
301
+ def parse_species(run, atomic_numbers):
302
+ """
303
+ If we don't have any structure from the underlying DFT code, we can
304
+ at least figure out what atoms we have in the structure. The best place
305
+ to get this info from is the DOSCAR.lobster
306
+ """
307
+
308
+ if not run.system:
309
+ system = System()
310
+ run.system.append(system)
311
+ system.atoms = Atoms(species=atomic_numbers, periodic=[True, True, True])
312
+
313
+ def translate_lm(lm):
314
+ lm_dictionary = {
315
+ 's': [0, 0],
316
+ 'p_z': [1, 0],
317
+ 'p_x': [1, 1],
318
+ 'p_y': [1, 2],
319
+ 'd_z^2': [2, 0],
320
+ 'd_xz': [2, 1],
321
+ 'd_yz': [2, 2],
322
+ 'd_xy': [2, 3],
323
+ 'd_x^2-y^2': [2, 4],
324
+ 'z^3': [3, 0],
325
+ 'xz^2': [3, 1],
326
+ 'yz^2': [3, 2],
327
+ 'xyz': [3, 3],
328
+ 'z(x^2-y^2)': [3, 4],
329
+ 'x(x^2-3y^2)': [3, 5],
330
+ 'y(3x^2-y^2)': [3, 6],
331
+ }
332
+ return lm_dictionary.get(lm[1:])
333
+
334
+ if not os.path.isfile(fname):
335
+ return
336
+
337
+ energies = []
338
+ dos_values = []
339
+ integral_dos = []
340
+ atom_projected_dos_values = []
341
+ atom_index = 0
342
+ n_atoms = 0
343
+ n_dos = 0
344
+ atomic_numbers = []
345
+ lms = []
346
+ with open(fname, 'rb') as f:
347
+ compression, open_compressed = _compressions.get(f.read(3), (None, open))
348
+
349
+ with open_compressed(fname) as f:
350
+ for i, line in enumerate(f):
351
+ if i == 0:
352
+ n_atoms = int(line.split()[0])
353
+ if i == 1:
354
+ _ = float(line.split()[0]) * units.angstrom**3
355
+ if i == 5:
356
+ n_dos = int(line.split()[2])
357
+ if compression:
358
+ try:
359
+ line = line.decode('utf-8')
360
+ except Exception:
361
+ break
362
+
363
+ if 'Z=' in line:
364
+ atom_index += 1
365
+ atom_projected_dos_values.append([])
366
+ lms.append((line.split(';')[-1]).split())
367
+ atomic_numbers.append(int(line.split(';')[-2].split('=')[1]))
368
+ continue
369
+ if i > 5:
370
+ line = [float(x) for x in line.split()]
371
+ if atom_index == 0:
372
+ energies.append(line[0])
373
+ if len(line) == 3:
374
+ dos_values.append([line[1]])
375
+ integral_dos.append([line[2]])
376
+ elif len(line) == 5:
377
+ dos_values.append([line[1], line[2]])
378
+ integral_dos.append([line[3], line[4]])
379
+ else:
380
+ atom_projected_dos_values[-1].append(line[1:])
381
+
382
+ if len(atomic_numbers) > 0 and len(atomic_numbers) == n_atoms:
383
+ parse_species(run, atomic_numbers)
384
+
385
+ if n_dos == 0:
386
+ return
387
+
388
+ if len(dos_values) == n_dos:
389
+ value = list(zip(*dos_values))
390
+ n_spin_channels = len(value)
391
+ n_electrons = sum(atomic_numbers)
392
+ index = (np.abs(energies)).argmin()
393
+ # integrated dos at the Fermi level should be the number of electrons
394
+ n_valence_electrons = int(round(sum(integral_dos[index])))
395
+ n_core_electrons = n_electrons - n_valence_electrons
396
+ value_integrated = np.array(list(zip(*integral_dos))) + n_core_electrons / len(
397
+ integral_dos[0]
398
+ )
399
+ for spin_i in range(n_spin_channels):
400
+ dos = Dos()
401
+ run.calculation[0].dos_electronic.append(dos)
402
+ dos.n_energies = n_dos
403
+ dos.energies = energies * units.eV
404
+ dos.spin_channel = spin_i if n_spin_channels == 2 else None
405
+ dos_total = DosValues()
406
+ dos.total.append(dos_total)
407
+ dos_total.value = value[spin_i] * (1 / units.eV)
408
+ dos_total.value_integrated = value_integrated[spin_i]
409
+ else:
410
+ logger.warning(
411
+ "Unable to parse total dos from DOSCAR.lobster, \
412
+ it doesn't contain enough dos values"
413
+ )
414
+ return
415
+
416
+ for atom_i, pdos in enumerate(atom_projected_dos_values):
417
+ if len(pdos) != n_dos:
418
+ logger.warning(
419
+ "Unable to parse atom lm-projected dos from DOSCAR.lobster, \
420
+ it doesn't contain enough dos values"
421
+ )
422
+ continue
423
+
424
+ if len(lms[atom_i]) == len(pdos[0]):
425
+ # we have the same lm-projections for spin up and dn
426
+ dos_values = np.array([[lmdos] for lmdos in zip(*pdos)]) / eV
427
+ elif len(lms[atom_i]) * 2 == len(pdos[0]):
428
+ pdos_up = list(zip(*pdos))[0::2]
429
+ pdos_dn = list(zip(*pdos))[1::2]
430
+ dos_values = np.array([[a, b] for a, b in zip(pdos_up, pdos_dn)]) / eV
431
+ else:
432
+ logger.warning('Unexpected number of columns in DOSCAR.lobster')
433
+ return
434
+ for lm_i, lm in enumerate(lms[atom_i]):
435
+ for spin_i in range(len(dos_values[lm_i])):
436
+ dos = run.calculation[0].dos_electronic[spin_i]
437
+ section_pdos = DosValues()
438
+ dos.atom_projected.append(section_pdos)
439
+ section_pdos.atom_index = atom_i
440
+ section_pdos.m_kind = 'real_orbital'
441
+ section_pdos.lm = translate_lm(lm)
442
+ section_pdos.value = dos_values[lm_i][spin_i]
443
+
444
+
445
+ mainfile_parser = TextParser(
446
+ quantities=[
447
+ Quantity('program_version', r'^LOBSTER\s*v([\d\.]+)\s*', repeats=False),
448
+ Quantity(
449
+ 'datetime',
450
+ r'starting on host \S* on (\d{4}-\d\d-\d\d\sat\s\d\d:\d\d:\d\d)\s[A-Z]{3,4}',
451
+ repeats=False,
452
+ ),
453
+ Quantity(
454
+ 'x_lobster_code',
455
+ r'detecting used PAW program... (.*)',
456
+ repeats=False,
457
+ flatten=False,
458
+ ),
459
+ Quantity(
460
+ 'x_lobster_basis',
461
+ r'setting up local basis functions\.\.\.\s*(?:WARNING.*\s*)*\s*((?:[a-zA-Z]{1,2}\s+\(.+\)(?:\s+\d\S+)+\s+)+)',
462
+ repeats=False,
463
+ sub_parser=TextParser(
464
+ quantities=[
465
+ Quantity(
466
+ 'x_lobster_basis_species',
467
+ r'([a-zA-Z]+){1,2}\s+\((.+)\)((?:\s+\d\S+)+)\s+',
468
+ repeats=True,
469
+ )
470
+ ]
471
+ ),
472
+ ),
473
+ Quantity(
474
+ 'spilling',
475
+ r'((?:spillings|abs. tot)[\s\S]*?charge\s*spilling:\s*\d+\.\d+%)',
476
+ repeats=True,
477
+ sub_parser=TextParser(
478
+ quantities=[
479
+ Quantity(
480
+ 'abs_total_spilling',
481
+ r'abs.\s*total\s*spilling:\s*(\d+\.\d+)%',
482
+ repeats=False,
483
+ ),
484
+ Quantity(
485
+ 'abs_charge_spilling',
486
+ r'abs.\s*charge\s*spilling:\s*(\d+\.\d+)%',
487
+ repeats=False,
488
+ ),
489
+ ]
490
+ ),
491
+ ),
492
+ Quantity('finished', r'finished in (\d)', repeats=False),
493
+ ]
494
+ )
495
+
496
+
497
+ class LobsterParser:
498
+ def __init__(self):
499
+ pass
500
+
501
+ def parse(self, mainfile: str, archive: EntryArchive, logger=None):
502
+ mainfile_parser.mainfile = mainfile
503
+ mainfile_path = os.path.dirname(mainfile)
504
+ mainfile_parser.parse()
505
+
506
+ run = Run()
507
+ archive.run.append(run)
508
+
509
+ run.program = Program(
510
+ name='LOBSTER', version=str(mainfile_parser.get('program_version'))
511
+ )
512
+ # FIXME: There is a timezone info present as well, but datetime support for timezones
513
+ # is bad and it doesn't support some timezones (for example CEST).
514
+ # That leads to test failures, so ignore it for now.
515
+ date = datetime.datetime.strptime(
516
+ ' '.join(mainfile_parser.get('datetime')), '%Y-%m-%d at %H:%M:%S'
517
+ ) - datetime.datetime(1970, 1, 1)
518
+ run.time_run = TimeRun(wall_start=date.total_seconds())
519
+ code = mainfile_parser.get('x_lobster_code')
520
+
521
+ # parse structure
522
+ if code is not None:
523
+ if code == 'VASP':
524
+ try:
525
+ contcar_path = get_lobster_file(
526
+ os.path.join(mainfile_path, 'CONTCAR')
527
+ )
528
+ structure = ase.io.read(contcar_path, format='vasp')
529
+ except FileNotFoundError:
530
+ logger.warning(
531
+ 'Unable to parse structure info, no CONTCAR detected'
532
+ )
533
+ elif code == 'Quantum Espresso':
534
+ for file in os.listdir(mainfile_path):
535
+ # lobster requires the QE input to have *.scf.in suffix
536
+ if file.endswith('.scf.in'):
537
+ qe_input_file = os.path.join(mainfile_path, file)
538
+ structure = ase.io.read(qe_input_file, format='espresso-in')
539
+ if 'structure' not in locals():
540
+ logger.warning(
541
+ 'Unable to parse structure info, no Quantum Espresso input detected'
542
+ )
543
+ else:
544
+ logger.warning('Parsing of {} structure is not supported'.format(code))
545
+
546
+ if 'structure' in locals():
547
+ system = System()
548
+ run.system.append(system)
549
+ system.atoms = Atoms(
550
+ lattice_vectors=structure.get_cell() * units.angstrom,
551
+ labels=structure.get_chemical_symbols(),
552
+ periodic=structure.get_pbc(),
553
+ positions=structure.get_positions() * units.angstrom,
554
+ )
555
+
556
+ if mainfile_parser.get('finished') is not None:
557
+ run.clean_end = True
558
+ else:
559
+ run.clean_end = False
560
+
561
+ scc = Calculation()
562
+ run.calculation.append(scc)
563
+ method = Method()
564
+ run.method.append(method)
565
+ scc.method_ref = method
566
+
567
+ spilling = mainfile_parser.get('spilling')
568
+ if spilling is not None:
569
+ method.electronic = Electronic(n_spin_channels=len(spilling))
570
+ total_spilling = []
571
+ charge_spilling = []
572
+ for s in spilling:
573
+ total_spilling.append(s.get('abs_total_spilling'))
574
+ charge_spilling.append(s.get('abs_charge_spilling'))
575
+ scc.x_lobster_abs_total_spilling = np.array(total_spilling)
576
+ scc.x_lobster_abs_charge_spilling = np.array(charge_spilling)
577
+
578
+ method.x_lobster_code = code
579
+
580
+ if (basis := mainfile_parser.get('x_lobster_basis')) is not None:
581
+ if (species := basis.get('x_lobster_basis_species')) is not None:
582
+ method.electrons_representation = [
583
+ BasisSetContainer(
584
+ type='atom-centered orbitals', # https://pubs.acs.org/doi/pdf/10.1021/j100135a014
585
+ scope=[
586
+ 'wavefunction'
587
+ ], # https://pubs.acs.org/doi/pdf/10.1021/jp202489s
588
+ basis_set=[
589
+ BasisSet(
590
+ type=species[0][
591
+ 1
592
+ ], # https://www.nature.com/articles/s41524-019-0208-x
593
+ scope=['full-electron'],
594
+ )
595
+ ],
596
+ )
597
+ ]
598
+
599
+ parse_ICOXPLIST(
600
+ get_lobster_file(mainfile_path + '/ICOHPLIST.lobster'), scc, 'h'
601
+ )
602
+ parse_ICOXPLIST(
603
+ get_lobster_file(mainfile_path + '/ICOOPLIST.lobster'), scc, 'o'
604
+ )
605
+
606
+ parse_COXPCAR(
607
+ get_lobster_file(mainfile_path + '/COHPCAR.lobster'), scc, 'h', logger
608
+ )
609
+ parse_COXPCAR(
610
+ get_lobster_file(mainfile_path + '/COOPCAR.lobster'), scc, 'o', logger
611
+ )
612
+
613
+ parse_CHARGE(get_lobster_file(mainfile_path + '/CHARGE.lobster'), scc)
614
+
615
+ parse_DOSCAR(get_lobster_file(mainfile_path + '/DOSCAR.lobster'), run, logger)
616
+
617
+ if run.system:
618
+ scc.system_ref = run.system[0]
@@ -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 PhonopyParser
@@ -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.phonopy import PhonopyParser
26
+
27
+ if __name__ == '__main__':
28
+ configure_logging(console_log_level=logging.DEBUG)
29
+ archive = EntryArchive()
30
+ PhonopyParser().parse(sys.argv[1], archive, logging)
31
+ json.dump(archive.m_to_dict(), sys.stdout, indent=2)