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,260 @@
|
|
|
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 itertools import combinations
|
|
20
|
+
import numpy as np
|
|
21
|
+
import re
|
|
22
|
+
from typing import Any, Optional
|
|
23
|
+
from fractions import Fraction
|
|
24
|
+
|
|
25
|
+
from ase import lattice as aselattice
|
|
26
|
+
from ase.cell import Cell
|
|
27
|
+
from ase.dft.kpoints import (
|
|
28
|
+
special_paths,
|
|
29
|
+
parse_path_string,
|
|
30
|
+
get_special_points,
|
|
31
|
+
sc_special_points,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
from phonopy.phonon.band_structure import BandStructure
|
|
35
|
+
from phonopy.units import EvTokJmol, VaspToTHz
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def generate_kpath_parameters(
|
|
39
|
+
points: dict[str, np.ndarray], paths: list[list[str]], npoints: int
|
|
40
|
+
) -> list[dict[str, Any]]:
|
|
41
|
+
k_points: list[list[np.ndarray]] = []
|
|
42
|
+
for p in paths:
|
|
43
|
+
k_points.append([points[k] for k in p])
|
|
44
|
+
for index in range(len(p)):
|
|
45
|
+
if p[index] == 'G':
|
|
46
|
+
p[index] = 'Γ'
|
|
47
|
+
parameters: list[dict[str, Any]] = []
|
|
48
|
+
for h, seg in enumerate(k_points):
|
|
49
|
+
for i, path in enumerate(seg):
|
|
50
|
+
parameter: dict[str, Any] = {}
|
|
51
|
+
parameter['npoints'] = npoints
|
|
52
|
+
parameter['startname'] = paths[h][i]
|
|
53
|
+
if i == 0 and len(seg) > 2:
|
|
54
|
+
parameter['kstart'] = path
|
|
55
|
+
parameter['kend'] = seg[i + 1]
|
|
56
|
+
parameter['endname'] = paths[h][i + 1]
|
|
57
|
+
parameters.append(parameter)
|
|
58
|
+
elif i == (len(seg) - 2):
|
|
59
|
+
parameter['kstart'] = path
|
|
60
|
+
parameter['kend'] = seg[i + 1]
|
|
61
|
+
parameter['endname'] = paths[h][i + 1]
|
|
62
|
+
parameters.append(parameter)
|
|
63
|
+
break
|
|
64
|
+
else:
|
|
65
|
+
parameter['kstart'] = path
|
|
66
|
+
parameter['kend'] = seg[i + 1]
|
|
67
|
+
parameter['endname'] = paths[h][i + 1]
|
|
68
|
+
parameters.append(parameter)
|
|
69
|
+
return parameters
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def read_kpath(filename: str) -> list[dict[str, Any]]:
|
|
73
|
+
with open(filename) as f:
|
|
74
|
+
string = f.read()
|
|
75
|
+
|
|
76
|
+
labels_extracted = re.search(r'BAND_LABELS\s*=\s*(.+)', string)
|
|
77
|
+
try:
|
|
78
|
+
labels = labels_extracted.group(1).strip().split()
|
|
79
|
+
except Exception:
|
|
80
|
+
return []
|
|
81
|
+
|
|
82
|
+
points_extracted = re.search(r'BAND\s*=\s*(.+)', string)
|
|
83
|
+
try:
|
|
84
|
+
points = points_extracted.group(1)
|
|
85
|
+
points = [float(Fraction(p)) for p in points.split()]
|
|
86
|
+
points = np.reshape(points, (len(labels), 3))
|
|
87
|
+
points = {labels[i]: points[i] for i in range(len(labels))}
|
|
88
|
+
except Exception:
|
|
89
|
+
return []
|
|
90
|
+
|
|
91
|
+
npoints_extracted = re.search(r'BAND_POINTS\s*\=\s*(\d+)', string)
|
|
92
|
+
npoints = 100 if npoints_extracted is None else int(npoints_extracted.group(1))
|
|
93
|
+
|
|
94
|
+
return generate_kpath_parameters(points, [labels], npoints)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_non_canonical_hexagonal(cell: Cell, symprec: float) -> Optional[int]:
|
|
98
|
+
"""
|
|
99
|
+
Tests if the cell is a non-canonical hexagonal cell
|
|
100
|
+
and returns the index of the ~ 60 degree angle (error range controlled by `symprec`).
|
|
101
|
+
"""
|
|
102
|
+
try:
|
|
103
|
+
target = 60
|
|
104
|
+
angles = cell.angles()
|
|
105
|
+
lattices = cell.lengths()
|
|
106
|
+
except AttributeError:
|
|
107
|
+
raise ValueError('Cell is not ase.cell.Cell')
|
|
108
|
+
|
|
109
|
+
# 2 tests:
|
|
110
|
+
## 1. if there is only one angle close to 60 degrees
|
|
111
|
+
## 2. if there is only one pair of lattice vectors with the same length
|
|
112
|
+
condition_angles = (angles > target - symprec) & (angles < target + symprec)
|
|
113
|
+
lattice_pairs = list(combinations(lattices, 2))
|
|
114
|
+
if (len(match_id := np.where(condition_angles)[0]) == 1) and (
|
|
115
|
+
sum([lat[1] - symprec <= lat[0] <= lat[1] + symprec for lat in lattice_pairs])
|
|
116
|
+
== 1
|
|
117
|
+
):
|
|
118
|
+
return int(match_id[0])
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def generate_kpath_ase(cell: Cell, symprec: float, logger=None) -> list[dict[str, Any]]:
|
|
123
|
+
try:
|
|
124
|
+
if not isinstance(cell, Cell):
|
|
125
|
+
cell = Cell(cell)
|
|
126
|
+
if isinstance(
|
|
127
|
+
rot_axis_id := test_non_canonical_hexagonal(cell, 1e2 * symprec), int
|
|
128
|
+
): # be more lenient with the angle
|
|
129
|
+
logger.warning(
|
|
130
|
+
'Non-canonical hexagonal cell detected. Will correct the orientation.'
|
|
131
|
+
)
|
|
132
|
+
target_axis_id = list(set(range(3)) - {rot_axis_id})[0]
|
|
133
|
+
mirror_matrix = np.eye(3)
|
|
134
|
+
mirror_matrix[target_axis_id, target_axis_id] *= -1
|
|
135
|
+
cell = Cell(mirror_matrix @ cell)
|
|
136
|
+
lattice = aselattice.get_lattice_from_canonical_cell(cell, eps=symprec)
|
|
137
|
+
paths = parse_path_string(lattice.special_path)
|
|
138
|
+
points = lattice.get_special_points()
|
|
139
|
+
except Exception:
|
|
140
|
+
logger.warning('Cannot resolve lattice paths.')
|
|
141
|
+
paths = special_paths['orthorombic'] # TODO: remove reliance on `ase`
|
|
142
|
+
points = sc_special_points['orthorombic'] # TODO: remove reliance on `ase`
|
|
143
|
+
if points is None:
|
|
144
|
+
try:
|
|
145
|
+
points = get_special_points(cell)
|
|
146
|
+
except Exception:
|
|
147
|
+
return []
|
|
148
|
+
|
|
149
|
+
if isinstance(paths, str):
|
|
150
|
+
paths = [list(path) for path in paths.split(',')]
|
|
151
|
+
return generate_kpath_parameters(points, paths, 100)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class PhononProperties:
|
|
155
|
+
def __init__(self, phonopy_obj, logger, **kwargs):
|
|
156
|
+
self.logger = logger
|
|
157
|
+
self.phonopy_obj = phonopy_obj
|
|
158
|
+
self.t_max = kwargs.get('t_max', 1000)
|
|
159
|
+
self.t_min = kwargs.get('t_min', 0)
|
|
160
|
+
self.t_step = kwargs.get('t_step', 100)
|
|
161
|
+
self.band_conf = kwargs.get('band_conf')
|
|
162
|
+
|
|
163
|
+
self.n_atoms = len(phonopy_obj.unitcell)
|
|
164
|
+
|
|
165
|
+
k_mesh = kwargs.get('k_mesh', 30)
|
|
166
|
+
mesh_density = (2 * k_mesh**3) / self.n_atoms
|
|
167
|
+
mesh_number = np.round(mesh_density ** (1.0 / 3.0))
|
|
168
|
+
self.mesh = [mesh_number, mesh_number, mesh_number]
|
|
169
|
+
|
|
170
|
+
self.n_atoms_supercell = len(phonopy_obj.supercell)
|
|
171
|
+
|
|
172
|
+
def get_bandstructure(self):
|
|
173
|
+
phonopy_obj = self.phonopy_obj
|
|
174
|
+
|
|
175
|
+
frequency_unit_factor = VaspToTHz
|
|
176
|
+
is_eigenvectors = False
|
|
177
|
+
|
|
178
|
+
unit_cell = phonopy_obj.unitcell.get_cell()
|
|
179
|
+
sym_tol = phonopy_obj.symmetry.tolerance
|
|
180
|
+
if self.band_conf is not None:
|
|
181
|
+
parameters = read_kpath(self.band_conf)
|
|
182
|
+
else:
|
|
183
|
+
parameters = generate_kpath_ase(unit_cell, sym_tol, self.logger)
|
|
184
|
+
if not parameters:
|
|
185
|
+
return None, None, None
|
|
186
|
+
|
|
187
|
+
# Distances calculated in phonopy.band_structure.BandStructure object
|
|
188
|
+
# are based on absolute positions of q-points in reciprocal space
|
|
189
|
+
# as calculated by using the cell which is handed over during instantiation.
|
|
190
|
+
# Fooling that object by handing over a "unit cell" diag(1,1,1) instead clashes
|
|
191
|
+
# with calculation of non-analytical terms.
|
|
192
|
+
# Hence generate appropriate distances and special k-points list based on fractional
|
|
193
|
+
# coordinates in reciprocal space (to keep backwards compatibility with previous
|
|
194
|
+
# FHI-aims phonon implementation).
|
|
195
|
+
bands = []
|
|
196
|
+
bands_distances = []
|
|
197
|
+
distance = 0.0
|
|
198
|
+
bands_special_points = [distance]
|
|
199
|
+
bands_labels = []
|
|
200
|
+
label = parameters[0]['startname']
|
|
201
|
+
for b in parameters:
|
|
202
|
+
kstart = np.array(b['kstart'])
|
|
203
|
+
kend = np.array(b['kend'])
|
|
204
|
+
npoints = b['npoints']
|
|
205
|
+
dk = (kend - kstart) / (npoints - 1)
|
|
206
|
+
bands.append([(kstart + dk * n) for n in range(npoints)])
|
|
207
|
+
dk_length = np.linalg.norm(dk)
|
|
208
|
+
|
|
209
|
+
for n in range(npoints):
|
|
210
|
+
bands_distances.append(distance + dk_length * n)
|
|
211
|
+
|
|
212
|
+
distance += dk_length * (npoints - 1)
|
|
213
|
+
bands_special_points.append(distance)
|
|
214
|
+
label = [b['startname'], b['endname']]
|
|
215
|
+
bands_labels.append(label)
|
|
216
|
+
|
|
217
|
+
bs_obj = BandStructure(
|
|
218
|
+
bands,
|
|
219
|
+
phonopy_obj.dynamical_matrix,
|
|
220
|
+
with_eigenvectors=is_eigenvectors,
|
|
221
|
+
factor=frequency_unit_factor,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
freqs = bs_obj.get_frequencies()
|
|
225
|
+
|
|
226
|
+
return np.array(freqs), np.array(bands), np.array(bands_labels)
|
|
227
|
+
|
|
228
|
+
def get_dos(self):
|
|
229
|
+
phonopy_obj = self.phonopy_obj
|
|
230
|
+
mesh = self.mesh
|
|
231
|
+
|
|
232
|
+
phonopy_obj.set_mesh(mesh, is_gamma_center=True)
|
|
233
|
+
q_points = phonopy_obj.get_mesh()[0]
|
|
234
|
+
phonopy_obj.set_qpoints_phonon(q_points, is_eigenvectors=False)
|
|
235
|
+
|
|
236
|
+
frequencies = phonopy_obj.get_qpoints_phonon()[0]
|
|
237
|
+
self.frequencies = np.array(frequencies)
|
|
238
|
+
min_freq = min(np.ravel(frequencies))
|
|
239
|
+
max_freq = max(np.ravel(frequencies)) + max(np.ravel(frequencies)) * 0.05
|
|
240
|
+
|
|
241
|
+
phonopy_obj.set_total_DOS(
|
|
242
|
+
freq_min=min_freq, freq_max=max_freq, tetrahedron_method=True
|
|
243
|
+
)
|
|
244
|
+
f, dos = phonopy_obj.get_total_DOS()
|
|
245
|
+
|
|
246
|
+
return f, dos
|
|
247
|
+
|
|
248
|
+
def get_thermodynamical_properties(self):
|
|
249
|
+
phonopy_obj = self.phonopy_obj
|
|
250
|
+
|
|
251
|
+
phonopy_obj.set_mesh(self.mesh, is_gamma_center=True)
|
|
252
|
+
phonopy_obj.set_thermal_properties(
|
|
253
|
+
t_step=self.t_step, t_max=self.t_max, t_min=self.t_min
|
|
254
|
+
)
|
|
255
|
+
T, fe, entropy, cv = phonopy_obj.get_thermal_properties()
|
|
256
|
+
kJmolToEv = 1.0 / EvTokJmol
|
|
257
|
+
fe = fe * kJmolToEv
|
|
258
|
+
JmolToEv = kJmolToEv / 1000
|
|
259
|
+
cv = JmolToEv * cv
|
|
260
|
+
return T, fe, entropy, cv
|
|
@@ -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 phonopy
|
|
@@ -0,0 +1,83 @@
|
|
|
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 numpy as np # pylint: disable=unused-import
|
|
20
|
+
import typing # pylint: disable=unused-import
|
|
21
|
+
from nomad.metainfo import ( # pylint: disable=unused-import
|
|
22
|
+
MSection,
|
|
23
|
+
MCategory,
|
|
24
|
+
Category,
|
|
25
|
+
Package,
|
|
26
|
+
Quantity,
|
|
27
|
+
Section,
|
|
28
|
+
SubSection,
|
|
29
|
+
SectionProxy,
|
|
30
|
+
Reference,
|
|
31
|
+
)
|
|
32
|
+
import runschema.run # pylint: disable=unused-import
|
|
33
|
+
import runschema.calculation # pylint: disable=unused-import
|
|
34
|
+
import runschema.method # pylint: disable=unused-import
|
|
35
|
+
import runschema.system # pylint: disable=unused-import
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
m_package = Package()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class x_phonopy_input(MCategory):
|
|
42
|
+
"""
|
|
43
|
+
Information about properties that concern phonopy calculations.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
m_def = Category()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Method(runschema.method.Method):
|
|
50
|
+
m_def = Section(validate=False, extends_base_section=True)
|
|
51
|
+
|
|
52
|
+
x_phonopy_displacement = Quantity(
|
|
53
|
+
type=np.float64,
|
|
54
|
+
shape=[],
|
|
55
|
+
unit='meter',
|
|
56
|
+
description="""
|
|
57
|
+
Amplitude of the atom diplacement for the phonopy supercell
|
|
58
|
+
""",
|
|
59
|
+
categories=[x_phonopy_input],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
x_phonopy_symprec = Quantity(
|
|
63
|
+
type=np.float64,
|
|
64
|
+
shape=[],
|
|
65
|
+
unit='meter',
|
|
66
|
+
description="""
|
|
67
|
+
Symmetry threshold for the space group identification of the crystal for which the
|
|
68
|
+
vibrational properties are to be calculated
|
|
69
|
+
""",
|
|
70
|
+
categories=[x_phonopy_input],
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class System(runschema.system.System):
|
|
75
|
+
m_def = Section(validate=False, extends_base_section=True)
|
|
76
|
+
|
|
77
|
+
x_phonopy_original_system_ref = Quantity(
|
|
78
|
+
type=runschema.system.System,
|
|
79
|
+
shape=[],
|
|
80
|
+
description="""
|
|
81
|
+
Original cell from which the supercell for the DFT calculations was constructed
|
|
82
|
+
""",
|
|
83
|
+
)
|