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,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)
|