nomad-schema-plugin-simulation-workflow 1.0.1__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_schema_plugin_simulation_workflow-1.0.1.dist-info/LICENSE +202 -0
- nomad_schema_plugin_simulation_workflow-1.0.1.dist-info/METADATA +17 -0
- nomad_schema_plugin_simulation_workflow-1.0.1.dist-info/RECORD +22 -0
- nomad_schema_plugin_simulation_workflow-1.0.1.dist-info/WHEEL +5 -0
- nomad_schema_plugin_simulation_workflow-1.0.1.dist-info/entry_points.txt +2 -0
- nomad_schema_plugin_simulation_workflow-1.0.1.dist-info/top_level.txt +1 -0
- simulationworkflowschema/__init__.py +118 -0
- simulationworkflowschema/chemical_reaction.py +167 -0
- simulationworkflowschema/dmft.py +84 -0
- simulationworkflowschema/elastic.py +494 -0
- simulationworkflowschema/equation_of_state.py +213 -0
- simulationworkflowschema/general.py +505 -0
- simulationworkflowschema/geometry_optimization.py +349 -0
- simulationworkflowschema/gw.py +69 -0
- simulationworkflowschema/max_ent.py +80 -0
- simulationworkflowschema/molecular_dynamics.py +2601 -0
- simulationworkflowschema/phonon.py +196 -0
- simulationworkflowschema/photon_polarization.py +75 -0
- simulationworkflowschema/single_point.py +273 -0
- simulationworkflowschema/tb.py +77 -0
- simulationworkflowschema/thermodynamics.py +375 -0
- simulationworkflowschema/xs.py +100 -0
|
@@ -0,0 +1,375 @@
|
|
|
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
|
+
import numpy as np
|
|
19
|
+
from nptyping import NDArray
|
|
20
|
+
|
|
21
|
+
from nomad.datamodel.data import ArchiveSection
|
|
22
|
+
from nomad.metainfo import SubSection, Section, Quantity, Reference, derived
|
|
23
|
+
from nomad.datamodel.metainfo.workflow import Link
|
|
24
|
+
from runschema.system import System
|
|
25
|
+
from .general import (
|
|
26
|
+
SimulationWorkflowResults,
|
|
27
|
+
SimulationWorkflowMethod,
|
|
28
|
+
SerialSimulation,
|
|
29
|
+
WORKFLOW_METHOD_NAME,
|
|
30
|
+
WORKFLOW_RESULTS_NAME,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Decomposition(ArchiveSection):
|
|
35
|
+
"""
|
|
36
|
+
Section containing information about the system to which an unstable compound will
|
|
37
|
+
decompose to.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
m_def = Section(validate=False)
|
|
41
|
+
|
|
42
|
+
fraction = Quantity(
|
|
43
|
+
type=np.float64,
|
|
44
|
+
shape=[],
|
|
45
|
+
description="""
|
|
46
|
+
Amount of the resulting system.
|
|
47
|
+
""",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
system_ref = Quantity(
|
|
51
|
+
type=Reference(System.m_def),
|
|
52
|
+
shape=[],
|
|
53
|
+
description="""
|
|
54
|
+
Reference to the resulting system.
|
|
55
|
+
""",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
formula = Quantity(
|
|
59
|
+
type=str,
|
|
60
|
+
shape=[],
|
|
61
|
+
description="""
|
|
62
|
+
Chemical formula of the resulting system.
|
|
63
|
+
""",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Stability(ArchiveSection):
|
|
68
|
+
"""
|
|
69
|
+
Section containing information regarding the stability of the system.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
m_def = Section(validate=False)
|
|
73
|
+
|
|
74
|
+
n_references = Quantity(
|
|
75
|
+
type=int,
|
|
76
|
+
shape=[],
|
|
77
|
+
description="""
|
|
78
|
+
Number of reference systems.
|
|
79
|
+
""",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
systems_ref = Quantity(
|
|
83
|
+
type=Reference(System.m_def),
|
|
84
|
+
shape=['n_references'],
|
|
85
|
+
description="""
|
|
86
|
+
References to the reference systems.
|
|
87
|
+
""",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
formation_energy = Quantity(
|
|
91
|
+
type=np.float64,
|
|
92
|
+
shape=[],
|
|
93
|
+
unit='joule',
|
|
94
|
+
description="""
|
|
95
|
+
Calculated value of the formation energy of the compound.
|
|
96
|
+
""",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
delta_formation_energy = Quantity(
|
|
100
|
+
type=np.float64,
|
|
101
|
+
shape=[],
|
|
102
|
+
unit='joule',
|
|
103
|
+
description="""
|
|
104
|
+
Energy with respect to the convex hull.
|
|
105
|
+
""",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
n_references = Quantity(
|
|
109
|
+
type=int,
|
|
110
|
+
shape=[],
|
|
111
|
+
description="""
|
|
112
|
+
Number of reference systems.
|
|
113
|
+
""",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
is_stable = Quantity(
|
|
117
|
+
type=bool,
|
|
118
|
+
shape=[],
|
|
119
|
+
description="""
|
|
120
|
+
Indicates if a compound is stable.
|
|
121
|
+
""",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
decomposition = SubSection(sub_section=Decomposition.m_def, repeats=True)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class ThermodynamicsResults(SimulationWorkflowResults):
|
|
128
|
+
n_values = Quantity(
|
|
129
|
+
type=int,
|
|
130
|
+
shape=[],
|
|
131
|
+
description="""
|
|
132
|
+
Number of thermodynamics property evaluations.
|
|
133
|
+
""",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
temperature = Quantity(
|
|
137
|
+
type=np.float64,
|
|
138
|
+
shape=['n_values'],
|
|
139
|
+
unit='kelvin',
|
|
140
|
+
description="""
|
|
141
|
+
Specifies the temperatures at which properties such as the Helmholtz free energy
|
|
142
|
+
are calculated.
|
|
143
|
+
""",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
pressure = Quantity(
|
|
147
|
+
type=np.float64,
|
|
148
|
+
shape=['n_values'],
|
|
149
|
+
unit='pascal',
|
|
150
|
+
description="""
|
|
151
|
+
Array containing the values of the pressure (one third of the trace of the stress
|
|
152
|
+
tensor) corresponding to each property evaluation.
|
|
153
|
+
""",
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
helmholtz_free_energy = Quantity(
|
|
157
|
+
type=np.float64,
|
|
158
|
+
shape=['n_values'],
|
|
159
|
+
unit='joule',
|
|
160
|
+
description="""
|
|
161
|
+
Helmholtz free energy per unit cell at constant volume.
|
|
162
|
+
""",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
heat_capacity_c_p = Quantity(
|
|
166
|
+
type=np.float64,
|
|
167
|
+
shape=['n_values'],
|
|
168
|
+
unit='joule / kelvin',
|
|
169
|
+
description="""
|
|
170
|
+
Heat capacity per cell unit at constant pressure.
|
|
171
|
+
""",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
heat_capacity_c_v = Quantity(
|
|
175
|
+
type=np.float64,
|
|
176
|
+
shape=['n_values'],
|
|
177
|
+
unit='joule / kelvin',
|
|
178
|
+
description="""
|
|
179
|
+
Heat capacity per cell unit at constant volume.
|
|
180
|
+
""",
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
@derived(
|
|
184
|
+
type=np.float64,
|
|
185
|
+
shape=['n_values'],
|
|
186
|
+
unit='joule / (kelvin * kilogram)',
|
|
187
|
+
description="""
|
|
188
|
+
Specific heat capacity at constant volume.
|
|
189
|
+
""",
|
|
190
|
+
cached=True,
|
|
191
|
+
)
|
|
192
|
+
def heat_capacity_c_v_specific(self) -> NDArray:
|
|
193
|
+
"""Returns the specific heat capacity by dividing the heat capacity per
|
|
194
|
+
cell with the mass of the atoms in the cell.
|
|
195
|
+
"""
|
|
196
|
+
import nomad.atomutils
|
|
197
|
+
|
|
198
|
+
workflow = self.m_parent
|
|
199
|
+
if not workflow._systems or not workflow._systems[0].atoms:
|
|
200
|
+
return
|
|
201
|
+
atomic_numbers = workflow._systems[0].atoms.species
|
|
202
|
+
mass_per_unit_cell = nomad.atomutils.get_summed_atomic_mass(atomic_numbers)
|
|
203
|
+
heat_capacity = self.heat_capacity_c_v
|
|
204
|
+
specific_heat_capacity = heat_capacity / mass_per_unit_cell
|
|
205
|
+
|
|
206
|
+
return specific_heat_capacity.magnitude
|
|
207
|
+
|
|
208
|
+
vibrational_free_energy_at_constant_volume = Quantity(
|
|
209
|
+
type=np.float64,
|
|
210
|
+
shape=['n_values'],
|
|
211
|
+
unit='joule',
|
|
212
|
+
description="""
|
|
213
|
+
Holds the vibrational free energy per cell unit at constant volume.
|
|
214
|
+
""",
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
@derived(
|
|
218
|
+
type=np.float64,
|
|
219
|
+
shape=['n_values'],
|
|
220
|
+
unit='joule / kilogram',
|
|
221
|
+
description="""
|
|
222
|
+
Stores the specific vibrational free energy at constant volume.
|
|
223
|
+
""",
|
|
224
|
+
cached=True,
|
|
225
|
+
)
|
|
226
|
+
def vibrational_free_energy_at_constant_volume_specific(self) -> NDArray:
|
|
227
|
+
import nomad.atomutils
|
|
228
|
+
|
|
229
|
+
workflow = self.m_parent
|
|
230
|
+
if not workflow._systems or not workflow._systems[0].atoms:
|
|
231
|
+
return
|
|
232
|
+
atomic_numbers = workflow._systems[0].atoms.species
|
|
233
|
+
mass_per_unit_cell = nomad.atomutils.get_summed_atomic_mass(atomic_numbers)
|
|
234
|
+
free_energy = self.vibrational_free_energy_at_constant_volume
|
|
235
|
+
specific_free_energy = free_energy / mass_per_unit_cell
|
|
236
|
+
|
|
237
|
+
return specific_free_energy.magnitude
|
|
238
|
+
|
|
239
|
+
vibrational_free_energy = Quantity(
|
|
240
|
+
type=np.float64,
|
|
241
|
+
shape=['n_values'],
|
|
242
|
+
unit='joule',
|
|
243
|
+
description="""
|
|
244
|
+
Calculated value of the vibrational free energy, F_vib.
|
|
245
|
+
""",
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
vibrational_internal_energy = Quantity(
|
|
249
|
+
type=np.float64,
|
|
250
|
+
shape=['n_values'],
|
|
251
|
+
unit='joule',
|
|
252
|
+
description="""
|
|
253
|
+
Calculated value of the vibrational internal energy, U_vib.
|
|
254
|
+
""",
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
vibrational_entropy = Quantity(
|
|
258
|
+
type=np.float64,
|
|
259
|
+
shape=['n_values'],
|
|
260
|
+
unit='joule / kelvin',
|
|
261
|
+
description="""
|
|
262
|
+
Calculated value of the vibrational entropy, S.
|
|
263
|
+
""",
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
gibbs_free_energy = Quantity(
|
|
267
|
+
type=np.float64,
|
|
268
|
+
shape=['n_values'],
|
|
269
|
+
unit='joule',
|
|
270
|
+
description="""
|
|
271
|
+
Calculated value of the Gibbs free energy, G.
|
|
272
|
+
""",
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
entropy = Quantity(
|
|
276
|
+
type=np.float64,
|
|
277
|
+
shape=['n_values'],
|
|
278
|
+
unit='joule / kelvin',
|
|
279
|
+
description="""
|
|
280
|
+
Calculated value of the entropy.
|
|
281
|
+
""",
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
enthalpy = Quantity(
|
|
285
|
+
type=np.float64,
|
|
286
|
+
shape=['n_values'],
|
|
287
|
+
unit='joule',
|
|
288
|
+
description="""
|
|
289
|
+
Calculated value of enthalpy.
|
|
290
|
+
""",
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
internal_energy = Quantity(
|
|
294
|
+
type=np.float64,
|
|
295
|
+
shape=['n_values'],
|
|
296
|
+
unit='joule',
|
|
297
|
+
description="""
|
|
298
|
+
Calculated value of the internal energy, U.
|
|
299
|
+
""",
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
stability = SubSection(sub_section=Stability.m_def, repeats=False)
|
|
303
|
+
|
|
304
|
+
def normalize(self, archive, logger):
|
|
305
|
+
super().normalize(archive, logger)
|
|
306
|
+
|
|
307
|
+
try:
|
|
308
|
+
calculations = archive.run[-1].calculation
|
|
309
|
+
except Exception:
|
|
310
|
+
calculations = []
|
|
311
|
+
|
|
312
|
+
def set_thermo_property(name):
|
|
313
|
+
values = []
|
|
314
|
+
quantity = None
|
|
315
|
+
for calc in calculations:
|
|
316
|
+
if hasattr(calc, name):
|
|
317
|
+
try:
|
|
318
|
+
quantity = calc[name]
|
|
319
|
+
values.append(
|
|
320
|
+
quantity.magnitude
|
|
321
|
+
if hasattr(quantity, 'magnitude')
|
|
322
|
+
else quantity
|
|
323
|
+
)
|
|
324
|
+
continue
|
|
325
|
+
except Exception:
|
|
326
|
+
pass
|
|
327
|
+
# TODO section thermodynamics should be removed
|
|
328
|
+
for thermo in calc.thermodynamics:
|
|
329
|
+
try:
|
|
330
|
+
quantity = thermo[name]
|
|
331
|
+
values.append(
|
|
332
|
+
quantity.magnitude
|
|
333
|
+
if hasattr(quantity, 'magnitude')
|
|
334
|
+
else quantity
|
|
335
|
+
)
|
|
336
|
+
except Exception:
|
|
337
|
+
pass
|
|
338
|
+
if len(values) == 0:
|
|
339
|
+
return
|
|
340
|
+
|
|
341
|
+
unit = quantity.units if hasattr(quantity, 'units') else 1.0
|
|
342
|
+
setattr(self, name, np.array(values) * unit)
|
|
343
|
+
|
|
344
|
+
if self.temperature is None:
|
|
345
|
+
set_thermo_property('temperature')
|
|
346
|
+
|
|
347
|
+
if self.helmholtz_free_energy is None:
|
|
348
|
+
set_thermo_property('helmholtz_free_energy')
|
|
349
|
+
|
|
350
|
+
if self.vibrational_free_energy_at_constant_volume is None:
|
|
351
|
+
set_thermo_property('vibrational_free_energy_at_constant_volume')
|
|
352
|
+
|
|
353
|
+
if self.heat_capacity_c_v is None:
|
|
354
|
+
set_thermo_property('heat_capacity_c_v')
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class ThermodynamicsMethod(SimulationWorkflowMethod):
|
|
358
|
+
pass
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class Thermodynamics(SerialSimulation):
|
|
362
|
+
method = SubSection(sub_section=ThermodynamicsMethod)
|
|
363
|
+
|
|
364
|
+
results = SubSection(sub_section=ThermodynamicsResults)
|
|
365
|
+
|
|
366
|
+
def normalize(self, archive, logger):
|
|
367
|
+
super().normalize(archive, logger)
|
|
368
|
+
|
|
369
|
+
if not self.method:
|
|
370
|
+
self.method = ThermodynamicsMethod()
|
|
371
|
+
self.inputs.append(Link(name=WORKFLOW_METHOD_NAME, section=self.method))
|
|
372
|
+
|
|
373
|
+
if not self.results:
|
|
374
|
+
self.results = ThermodynamicsResults()
|
|
375
|
+
self.outputs.append(Link(name=WORKFLOW_RESULTS_NAME, section=self.results))
|
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
from nomad.metainfo import SubSection
|
|
19
|
+
from runschema.calculation import (
|
|
20
|
+
Spectra,
|
|
21
|
+
ElectronicStructureProvenance,
|
|
22
|
+
)
|
|
23
|
+
from .general import (
|
|
24
|
+
SimulationWorkflowResults,
|
|
25
|
+
ElectronicStructureOutputs,
|
|
26
|
+
SimulationWorkflowMethod,
|
|
27
|
+
BeyondDFT,
|
|
28
|
+
)
|
|
29
|
+
from .photon_polarization import PhotonPolarizationResults
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class XSResults(SimulationWorkflowResults):
|
|
33
|
+
"""
|
|
34
|
+
Groups DFT, GW and PhotonPolarization outputs: band gaps (DFT, GW), DOS (DFT, GW),
|
|
35
|
+
band structures (DFT, GW), spectra (PhotonPolarization). The ResultsNormalizer takes
|
|
36
|
+
care of adding a label 'DFT' or 'GW' in the method `get_xs_workflow_properties`.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
dft_outputs = SubSection(
|
|
40
|
+
sub_section=ElectronicStructureOutputs.m_def, repeats=False
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
gw_outputs = SubSection(sub_section=ElectronicStructureOutputs.m_def, repeats=False)
|
|
44
|
+
|
|
45
|
+
spectra = SubSection(sub_section=PhotonPolarizationResults, repeats=True)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class XSMethod(SimulationWorkflowMethod):
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class XS(BeyondDFT):
|
|
53
|
+
"""
|
|
54
|
+
The XS workflow is generated in an extra EntryArchive IF both the DFT SinglePoint
|
|
55
|
+
and the PhotonPolarization EntryArchives are present in the upload.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
# TODO extend to reference a GW SinglePoint.
|
|
59
|
+
|
|
60
|
+
method = SubSection(sub_section=XSMethod)
|
|
61
|
+
|
|
62
|
+
results = SubSection(sub_section=XSResults)
|
|
63
|
+
|
|
64
|
+
def normalize(self, archive, logger):
|
|
65
|
+
if len(self.tasks) < 2:
|
|
66
|
+
logger.error(
|
|
67
|
+
'Expected more than one task: DFT+PhotonPolarization or DFT+GW+PhotonPolarization.'
|
|
68
|
+
)
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
dft_task = self.tasks[0]
|
|
72
|
+
xs_tasks = [self.tasks[i] for i in range(1, len(self.tasks))]
|
|
73
|
+
gw_task = None
|
|
74
|
+
# Check if the xs_tasks contain GW SinglePoint or a list of PhotonPolarizations
|
|
75
|
+
if xs_tasks[0].task.m_def.name != 'PhotonPolarization':
|
|
76
|
+
gw_task = xs_tasks[0]
|
|
77
|
+
xs_tasks.pop(
|
|
78
|
+
0
|
|
79
|
+
) # we delete the [0] element associated with GW in case DFT+GW+PhotonPolarization workflow
|
|
80
|
+
|
|
81
|
+
if not self.results:
|
|
82
|
+
self.results = XSResults()
|
|
83
|
+
|
|
84
|
+
task_map = {
|
|
85
|
+
'dft': dft_task,
|
|
86
|
+
'gw': gw_task,
|
|
87
|
+
}
|
|
88
|
+
self.get_electronic_structure_workflow_results(task_map)
|
|
89
|
+
|
|
90
|
+
for xs in xs_tasks:
|
|
91
|
+
if xs.m_xpath('task.results'):
|
|
92
|
+
photon_results = xs.task.results
|
|
93
|
+
# Adding provenance to BSE method section, in addition to the existent 'photon' provenance
|
|
94
|
+
if xs.task.m_xpath('inputs[1].section'):
|
|
95
|
+
for spectra in photon_results.spectrum_polarization:
|
|
96
|
+
provenance = ElectronicStructureProvenance(
|
|
97
|
+
methodology=xs.task.inputs[1].section, label='bse'
|
|
98
|
+
)
|
|
99
|
+
spectra.m_add_sub_section(Spectra.provenance, provenance)
|
|
100
|
+
self.results.m_add_sub_section(XSResults.spectra, photon_results)
|