nomad-parser-plugins-atomistic 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 (80) hide show
  1. atomisticparsers/__init__.py +400 -0
  2. atomisticparsers/amber/__init__.py +19 -0
  3. atomisticparsers/amber/__main__.py +31 -0
  4. atomisticparsers/amber/metainfo/__init__.py +19 -0
  5. atomisticparsers/amber/metainfo/amber.py +495 -0
  6. atomisticparsers/amber/parser.py +42 -0
  7. atomisticparsers/asap/__init__.py +19 -0
  8. atomisticparsers/asap/__main__.py +31 -0
  9. atomisticparsers/asap/metainfo/__init__.py +19 -0
  10. atomisticparsers/asap/metainfo/asap.py +75 -0
  11. atomisticparsers/asap/parser.py +197 -0
  12. atomisticparsers/bopfox/__init__.py +19 -0
  13. atomisticparsers/bopfox/__main__.py +31 -0
  14. atomisticparsers/bopfox/metainfo/__init__.py +19 -0
  15. atomisticparsers/bopfox/metainfo/bopfox.py +225 -0
  16. atomisticparsers/bopfox/parser.py +808 -0
  17. atomisticparsers/dftbplus/__init__.py +19 -0
  18. atomisticparsers/dftbplus/__main__.py +31 -0
  19. atomisticparsers/dftbplus/metainfo/__init__.py +19 -0
  20. atomisticparsers/dftbplus/metainfo/dftbplus.py +217 -0
  21. atomisticparsers/dftbplus/parser.py +500 -0
  22. atomisticparsers/dlpoly/__init__.py +19 -0
  23. atomisticparsers/dlpoly/__main__.py +31 -0
  24. atomisticparsers/dlpoly/metainfo/__init__.py +19 -0
  25. atomisticparsers/dlpoly/metainfo/dl_poly.py +312 -0
  26. atomisticparsers/dlpoly/parser.py +798 -0
  27. atomisticparsers/gromacs/__init__.py +19 -0
  28. atomisticparsers/gromacs/__main__.py +31 -0
  29. atomisticparsers/gromacs/metainfo/__init__.py +19 -0
  30. atomisticparsers/gromacs/metainfo/gromacs.py +2388 -0
  31. atomisticparsers/gromacs/parser.py +1581 -0
  32. atomisticparsers/gromos/__init__.py +19 -0
  33. atomisticparsers/gromos/__main__.py +31 -0
  34. atomisticparsers/gromos/metainfo/__init__.py +19 -0
  35. atomisticparsers/gromos/metainfo/gromos.py +1995 -0
  36. atomisticparsers/gromos/parser.py +58 -0
  37. atomisticparsers/gulp/__init__.py +19 -0
  38. atomisticparsers/gulp/__main__.py +31 -0
  39. atomisticparsers/gulp/metainfo/__init__.py +19 -0
  40. atomisticparsers/gulp/metainfo/gulp.py +1117 -0
  41. atomisticparsers/gulp/parser.py +1316 -0
  42. atomisticparsers/h5md/__init__.py +19 -0
  43. atomisticparsers/h5md/__main__.py +31 -0
  44. atomisticparsers/h5md/metainfo/__init__.py +19 -0
  45. atomisticparsers/h5md/metainfo/h5md.py +239 -0
  46. atomisticparsers/h5md/parser.py +901 -0
  47. atomisticparsers/lammps/__init__.py +19 -0
  48. atomisticparsers/lammps/__main__.py +31 -0
  49. atomisticparsers/lammps/metainfo/__init__.py +19 -0
  50. atomisticparsers/lammps/metainfo/lammps.py +1417 -0
  51. atomisticparsers/lammps/parser.py +1753 -0
  52. atomisticparsers/libatoms/__init__.py +19 -0
  53. atomisticparsers/libatoms/__main__.py +31 -0
  54. atomisticparsers/libatoms/metainfo/__init__.py +19 -0
  55. atomisticparsers/libatoms/metainfo/lib_atoms.py +251 -0
  56. atomisticparsers/libatoms/parser.py +38 -0
  57. atomisticparsers/namd/__init__.py +19 -0
  58. atomisticparsers/namd/__main__.py +31 -0
  59. atomisticparsers/namd/metainfo/__init__.py +19 -0
  60. atomisticparsers/namd/metainfo/namd.py +1605 -0
  61. atomisticparsers/namd/parser.py +312 -0
  62. atomisticparsers/tinker/__init__.py +19 -0
  63. atomisticparsers/tinker/__main__.py +31 -0
  64. atomisticparsers/tinker/metainfo/__init__.py +18 -0
  65. atomisticparsers/tinker/metainfo/tinker.py +1363 -0
  66. atomisticparsers/tinker/parser.py +685 -0
  67. atomisticparsers/utils/__init__.py +22 -0
  68. atomisticparsers/utils/mdanalysis.py +662 -0
  69. atomisticparsers/utils/parsers.py +226 -0
  70. atomisticparsers/xtb/__init__.py +19 -0
  71. atomisticparsers/xtb/__main__.py +32 -0
  72. atomisticparsers/xtb/metainfo/__init__.py +19 -0
  73. atomisticparsers/xtb/metainfo/xtb.py +256 -0
  74. atomisticparsers/xtb/parser.py +979 -0
  75. nomad_parser_plugins_atomistic-1.0.dist-info/LICENSE +202 -0
  76. nomad_parser_plugins_atomistic-1.0.dist-info/METADATA +327 -0
  77. nomad_parser_plugins_atomistic-1.0.dist-info/RECORD +80 -0
  78. nomad_parser_plugins_atomistic-1.0.dist-info/WHEEL +5 -0
  79. nomad_parser_plugins_atomistic-1.0.dist-info/entry_points.txt +15 -0
  80. nomad_parser_plugins_atomistic-1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1316 @@
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 logging
21
+ import numpy as np
22
+ from datetime import datetime
23
+ from ase.atoms import Atoms as ase_Atoms
24
+ from ase.spacegroup import crystal as ase_crystal
25
+
26
+ from nomad.units import ureg
27
+ from nomad.parsing.file_parser import TextParser, Quantity, Parser
28
+ from runschema.run import Run, Program, TimeRun
29
+ from runschema.method import Method, ForceField, Model, Interaction, AtomParameters
30
+ from runschema.system import System, Atoms
31
+ from runschema.calculation import Calculation, Energy, EnergyEntry
32
+ from simulationworkflowschema import (
33
+ Elastic,
34
+ ElasticMethod,
35
+ ElasticResults,
36
+ MolecularDynamics,
37
+ MolecularDynamicsMethod,
38
+ )
39
+ from atomisticparsers.gulp.metainfo.gulp import (
40
+ x_gulp_bulk_optimisation,
41
+ x_gulp_bulk_optimisation_cycle,
42
+ )
43
+
44
+
45
+ re_f = r'[-+]?\d+\.\d*(?:[Ee][-+]\d+)?'
46
+ re_n = r'[\n\r]'
47
+
48
+
49
+ class MainfileParser(TextParser):
50
+ def init_quantities(self):
51
+ def to_species(val_in):
52
+ data = dict(
53
+ label=[],
54
+ x_gulp_type=[],
55
+ atom_number=[],
56
+ mass=[],
57
+ charge=[],
58
+ x_gulp_covalent_radius=[],
59
+ x_gulp_ionic_radius=[],
60
+ x_gulp_vdw_radius=[],
61
+ )
62
+ for val in val_in.strip().splitlines():
63
+ val = val.strip().split()
64
+ data['label'].append(val[0])
65
+ data['x_gulp_type'].append(val[1].lower())
66
+ data['atom_number'].append(int(val[2]))
67
+ data['mass'].append(float(val[3]) * ureg.amu)
68
+ data['charge'].append(float(val[4]) * ureg.elementary_charge)
69
+ data['x_gulp_covalent_radius'].append(float(val[5]) * ureg.angstrom)
70
+ data['x_gulp_ionic_radius'].append(float(val[6]) * ureg.angstrom)
71
+ data['x_gulp_vdw_radius'].append(float(val[7]) * ureg.angstrom)
72
+ return data
73
+
74
+ def to_cell_parameters(val_in):
75
+ val = val_in.strip().split()
76
+ return np.array(
77
+ [val[0], val[2], val[4], val[1], val[3], val[5]], np.dtype(np.float64)
78
+ )
79
+
80
+ coordinates_quantities = [
81
+ Quantity('unit', r'Label +\((\w+)\)', dtype=str),
82
+ Quantity(
83
+ 'auxilliary_keys', r'x +y +z +(.+)', str_operation=lambda x: x.split()
84
+ ),
85
+ Quantity(
86
+ 'atom',
87
+ rf'\d+ +([A-Z][a-z]*)\S* +(\w+ +{re_f}.+)',
88
+ repeats=True,
89
+ str_operation=lambda x: x.strip().replace('*', '').split(),
90
+ ),
91
+ ]
92
+
93
+ calc_quantities = [
94
+ Quantity(
95
+ 'energy_components',
96
+ rf'Components of .*energy \:\s+([\s\S]+?){re_n} *{re_n}',
97
+ sub_parser=TextParser(
98
+ quantities=[
99
+ Quantity(
100
+ 'key_val',
101
+ rf'(.+) *= +({re_f}) eV',
102
+ repeats=True,
103
+ str_operation=lambda x: [
104
+ v.strip() for v in x.rsplit(' ', 1)
105
+ ],
106
+ )
107
+ ]
108
+ ),
109
+ ),
110
+ Quantity(
111
+ 'bulk_optimisation',
112
+ rf'(Number of variables += +\d+[\s\S]+?Start of bulk optimisation \:\s+[\s\S]+?){re_n} *{re_n}',
113
+ sub_parser=TextParser(
114
+ quantities=[
115
+ Quantity(
116
+ 'x_gulp_n_variables',
117
+ r'Number of variables += +(\d+)',
118
+ dtype=np.int32,
119
+ ),
120
+ Quantity(
121
+ 'x_gulp_max_n_calculations',
122
+ r'Maximum number of calculations += +(\d+)',
123
+ dtype=np.int32,
124
+ ),
125
+ Quantity(
126
+ 'x_gulp_max_hessian_update_interval',
127
+ r'Maximum Hessian update interval += +(\d+)',
128
+ dtype=np.int32,
129
+ ),
130
+ Quantity(
131
+ 'x_gulp_max_step_size',
132
+ rf'Maximum step size += +({re_f})',
133
+ dtype=np.float64,
134
+ ),
135
+ Quantity(
136
+ 'x_gulp_max_parameter_tolerance',
137
+ rf'Maximum parameter tolerance += +({re_f})',
138
+ dtype=np.float64,
139
+ ),
140
+ Quantity(
141
+ 'x_gulp_max_function_tolerance',
142
+ rf'Maximum function +tolerance += +({re_f})',
143
+ dtype=np.float64,
144
+ ),
145
+ Quantity(
146
+ 'x_gulp_max_gradient_tolerance',
147
+ rf'Maximum gradient +tolerance += +({re_f})',
148
+ dtype=np.float64,
149
+ ),
150
+ Quantity(
151
+ 'x_gulp_max_gradient_component',
152
+ rf'Maximum gradient +component += +({re_f})',
153
+ dtype=np.float64,
154
+ ),
155
+ Quantity(
156
+ 'cycle',
157
+ rf'Cycle\: +\d+ +Energy\: +({re_f}) +Gnorm\: +({re_f}) +CPU\: +({re_f})',
158
+ repeats=True,
159
+ dtype=np.dtype(np.float64),
160
+ ),
161
+ ]
162
+ ),
163
+ ),
164
+ Quantity(
165
+ 'coordinates',
166
+ r'Final.+coordinates.+\:\s+\-+\s+'
167
+ r'No\. +Atomic +(x +y +z +.+\s+Label .+)\s*\-+\s*([\s\S]+?)\-{50}',
168
+ sub_parser=TextParser(quantities=coordinates_quantities),
169
+ ),
170
+ Quantity(
171
+ 'lattice_vectors',
172
+ rf'Final Cartesian lattice vectors \(Angstroms\) \:\s+((?:{re_f}\s+)+)',
173
+ dtype=np.dtype(np.float64),
174
+ shape=(3, 3),
175
+ ),
176
+ Quantity(
177
+ 'cell_parameters_primitive',
178
+ rf'Final cell parameters and derivatives \:\s+\-+\s+'
179
+ rf'((?:\w+ +{re_f}.+\s+)+)',
180
+ str_operation=lambda x: np.array(
181
+ [v.split()[1] for v in x.strip().splitlines()], np.dtype(np.float64)
182
+ ),
183
+ ),
184
+ Quantity(
185
+ 'cell_parameters',
186
+ r'Non\-primitive lattice parameters \:\s+'
187
+ rf'a += +({re_f}) +b += +({re_f}) +c += +({re_f})\s+'
188
+ rf'alpha *= +({re_f}) +beta *= +({re_f}) +gamma *= +({re_f})\s+',
189
+ dtype=np.dtype(np.float64),
190
+ ),
191
+ Quantity(
192
+ 'elastic_constants',
193
+ r'Elastic Constant Matrix.+\s+\-+\s+Indices.+\s+\-+\s+'
194
+ rf'((?:\d+ +{re_f} +{re_f} +{re_f} +{re_f} +{re_f} +{re_f}\s+)+)',
195
+ str_operation=lambda x: np.array(
196
+ [v.split()[1:7] for v in x.strip().splitlines()],
197
+ np.dtype(np.float64),
198
+ )
199
+ * ureg.GPa,
200
+ ),
201
+ Quantity(
202
+ 'elastic_compliance',
203
+ r'Elastic Compliance Matrix.+\s+\-+\s+Indices.+\s+\-+\s+'
204
+ rf'((?:\d+ +{re_f} +{re_f} +{re_f} +{re_f} +{re_f} +{re_f}\s+)+)',
205
+ str_operation=lambda x: np.array(
206
+ [v.split()[1:7] for v in x.strip().splitlines()],
207
+ np.dtype(np.float64),
208
+ )
209
+ * 1
210
+ / ureg.GPa,
211
+ ),
212
+ Quantity(
213
+ 'mechanical_properties',
214
+ rf'Mechanical properties \:\s+([\s\S]+?){re_n} *{re_n}',
215
+ sub_parser=TextParser(
216
+ quantities=[
217
+ Quantity(
218
+ 'bulk_modulus',
219
+ rf'Bulk +Modulus \(GPa\) += +({re_f} +{re_f} +{re_f})',
220
+ dtype=np.dtype(np.float64),
221
+ unit=ureg.GPa,
222
+ ),
223
+ Quantity(
224
+ 'shear_modulus',
225
+ rf'Shear +Modulus \(GPa\) += +({re_f} +{re_f} +{re_f})',
226
+ dtype=np.dtype(np.float64),
227
+ unit=ureg.GPa,
228
+ ),
229
+ Quantity(
230
+ 'x_gulp_velocity_s_wave',
231
+ rf'Velocity S\-wave \(km/s\) += +({re_f} +{re_f} +{re_f})',
232
+ dtype=np.dtype(np.float64),
233
+ unit=ureg.km / ureg.s,
234
+ ),
235
+ Quantity(
236
+ 'x_gulp_velocity_p_wave',
237
+ rf'Velocity P\-wave \(km/s\) += +({re_f} +{re_f} +{re_f})',
238
+ dtype=np.dtype(np.float64),
239
+ unit=ureg.km / ureg.s,
240
+ ),
241
+ Quantity(
242
+ 'compressibility',
243
+ rf'Compressibility \(1/GPa\) += +({re_f})',
244
+ dtype=np.float64,
245
+ unit=1 / ureg.GPa,
246
+ ),
247
+ Quantity(
248
+ 'x_gulp_youngs_modulus',
249
+ rf'Youngs Moduli \(GPa\) += +({re_f} +{re_f} +{re_f})',
250
+ dtype=np.dtype(np.float64),
251
+ unit=ureg.GPa,
252
+ ),
253
+ Quantity(
254
+ 'poissons_ratio',
255
+ rf'Poissons Ratio \((?:x|y|z)\) += +(.+)',
256
+ dtype=np.dtype(np.float64),
257
+ repeats=True,
258
+ ),
259
+ ]
260
+ ),
261
+ ),
262
+ Quantity(
263
+ 'x_gulp_piezoelectric_strain_matrix',
264
+ rf'Piezoelectric Strain Matrix\: \(Units=C/m\*\*2\)\s+\-+\s+'
265
+ rf'Indices.+\s*\-+\s+((?:\w +{re_f}.+\s+)+)',
266
+ dtype=np.dtype(np.float64),
267
+ str_operation=lambda x: np.array(
268
+ [v.strip().split()[1:7] for v in x.strip().splitlines()],
269
+ np.dtype(np.float64),
270
+ )
271
+ * ureg.C
272
+ / ureg.m**2,
273
+ ),
274
+ Quantity(
275
+ 'x_gulp_piezoelectric_stress_matrix',
276
+ rf'Piezoelectric Stress Matrix\: \(Units=10\*\*\-11 C/N\)\s+\-+\s+'
277
+ rf'Indices.+\s*\-+\s+((?:\w +{re_f}.+\s+)+)',
278
+ dtype=np.dtype(np.float64),
279
+ str_operation=lambda x: np.array(
280
+ [v.strip().split()[1:7] for v in x.strip().splitlines()],
281
+ np.dtype(np.float64),
282
+ )
283
+ * 10**-11
284
+ * ureg.C
285
+ / ureg.N,
286
+ ),
287
+ Quantity(
288
+ 'x_gulp_static_dielectric_constant_tensor',
289
+ r'Static dielectric constant tensor \:\s+\-+\s+x +y +z\s+\-+\s+'
290
+ rf'((?:\w +{re_f} +{re_f} +{re_f}\s+)+)',
291
+ str_operation=lambda x: np.array(
292
+ [v.strip().split()[1:4] for v in x.strip().splitlines()],
293
+ np.dtype(np.float64),
294
+ ),
295
+ ),
296
+ Quantity(
297
+ 'x_gulp_high_frequency_dielectric_constant_tensor',
298
+ r'High frequency dielectric constant tensor \:\s+\-+\s+x +y +z\s+\-+\s+'
299
+ rf'((?:\w +{re_f} +{re_f} +{re_f}\s+)+)',
300
+ str_operation=lambda x: np.array(
301
+ [v.strip().split()[1:4] for v in x.strip().splitlines()],
302
+ np.dtype(np.float64),
303
+ ),
304
+ ),
305
+ Quantity(
306
+ 'x_gulp_static_refractive_indices',
307
+ r'Static refractive indices \:\s+\-+\s+([\s\S]+?)\-{50}',
308
+ sub_parser=TextParser(
309
+ quantities=[
310
+ Quantity(
311
+ 'value',
312
+ rf'\d+ += +({re_f})',
313
+ repeats=True,
314
+ dtype=np.float64,
315
+ )
316
+ ]
317
+ ),
318
+ ),
319
+ Quantity(
320
+ 'x_gulp_high_frequency_refractive_indices',
321
+ r'High frequency refractive indices \:\s+\-+\s+([\s\S]+?)\-{50}',
322
+ sub_parser=TextParser(
323
+ quantities=[
324
+ Quantity(
325
+ 'value',
326
+ rf'\d+ += +({re_f})',
327
+ repeats=True,
328
+ dtype=np.float64,
329
+ )
330
+ ]
331
+ ),
332
+ ),
333
+ ]
334
+
335
+ interaction_quantities = [
336
+ Quantity('atom_type', r'([A-Z]\S* +(?:core|shell|c|s))\s', repeats=True),
337
+ Quantity(
338
+ 'functional_form',
339
+ r'([A-Z].{12})',
340
+ dtype=str,
341
+ flatten=False,
342
+ str_operation=lambda x: x.strip(),
343
+ ),
344
+ ]
345
+
346
+ self._quantities = [
347
+ Quantity(
348
+ 'header',
349
+ rf'(Version[\s\S]+?){re_n} *{re_n}',
350
+ sub_parser=TextParser(
351
+ quantities=[
352
+ Quantity('program_version', r'Version = (\S+)', dtype=str),
353
+ Quantity('task', r'\* +(\w+) +\- .+', repeats=True, dtype=str),
354
+ Quantity(
355
+ 'title',
356
+ r'\*\*\*\s+\* +(.+?) +\*\s+\*\*\*',
357
+ dtype=str,
358
+ flatten=False,
359
+ ),
360
+ ]
361
+ ),
362
+ ),
363
+ Quantity(
364
+ 'date_start',
365
+ r'Job Started +at (\d+\:\d+\.\d+) (\d+)\w+ (\w+) +(\d+)',
366
+ dtype=str,
367
+ flatten=False,
368
+ ),
369
+ Quantity(
370
+ 'date_end',
371
+ r'Job Started +at (\d+\:\d+\.\d+) (\d+)\w+ (\w+) +(\d+)',
372
+ dtype=str,
373
+ flatten=False,
374
+ ),
375
+ Quantity('x_gulp_n_cpu', r'Number of CPUs += +(\d+)', dtype=np.int32),
376
+ Quantity(
377
+ 'x_gulp_host_name', r'Host name += +(\S+)', dtype=str, flatten=False
378
+ ),
379
+ Quantity(
380
+ 'x_gulp_total_n_configurations_input',
381
+ r'Total number of configurations input += +(\d+)',
382
+ dtype=np.int32,
383
+ ),
384
+ Quantity(
385
+ 'input_configuration',
386
+ r'(Input for Configuration.+\s*\*+[\s\S]+?)\*{80}',
387
+ sub_parser=TextParser(
388
+ quantities=[
389
+ Quantity('x_gulp_formula', r'Formula = (\S+)', dtype=str),
390
+ Quantity(
391
+ 'x_gulp_pbc', r'Dimensionality = (\d+)', dtype=np.int32
392
+ ),
393
+ Quantity(
394
+ 'x_gulp_space_group',
395
+ rf'Space group \S+ +\: +(.+?) +{re_n}',
396
+ dtype=str,
397
+ flatten=False,
398
+ ),
399
+ Quantity(
400
+ 'x_gulp_patterson_group',
401
+ rf'Patterson group +\: +(.+?) +{re_n}',
402
+ dtype=str,
403
+ flatten=False,
404
+ ),
405
+ Quantity(
406
+ 'lattice_vectors',
407
+ rf'Cartesian lattice vectors \(Angstroms\) \:\s+'
408
+ rf'((?:{re_f} +{re_f} +{re_f}\s+)+)',
409
+ dtype=np.dtype(np.float64),
410
+ shape=[3, 3],
411
+ ),
412
+ Quantity(
413
+ 'cell_parameters',
414
+ rf'Primitive cell parameters.+\s+a.+?a += +({re_f}) +alpha += +({re_f})\s+'
415
+ rf'b.+?b += +({re_f}) +beta += +({re_f})\s+'
416
+ rf'c.+?c += +({re_f}) +gamma += +({re_f})\s+',
417
+ str_operation=to_cell_parameters,
418
+ ),
419
+ Quantity(
420
+ 'cell_parameters',
421
+ rf'Cell parameters.+\s+a += +({re_f}) +alpha += +({re_f})\s+'
422
+ rf'b += +({re_f}) +beta += +({re_f})\s+'
423
+ rf'c += +({re_f}) +gamma += +({re_f})\s+',
424
+ str_operation=to_cell_parameters,
425
+ ),
426
+ Quantity(
427
+ 'coordinates',
428
+ r'No\. +Atomic +(x +y +z +.+\s+Label .+)\s*\-+\s*([\s\S]+?)\-{50}',
429
+ sub_parser=TextParser(quantities=coordinates_quantities),
430
+ ),
431
+ ]
432
+ ),
433
+ ),
434
+ Quantity(
435
+ 'input_information',
436
+ r'(General input information\s+\*\s*\*+[\s\S]+?)\*{80}',
437
+ sub_parser=TextParser(
438
+ quantities=[
439
+ Quantity(
440
+ 'species',
441
+ rf'Species +Type.+\s+Number.+\s*\-+\s+'
442
+ rf'((?:[A-Z]\w* +\w+ +\d+.+\s+)+)',
443
+ str_operation=to_species,
444
+ convert=False,
445
+ ),
446
+ Quantity(
447
+ 'pgfnff',
448
+ r'(pGFNFF forcefield to be used[\s\S]+pGFNFF.+)',
449
+ sub_parser=TextParser(
450
+ quantities=[
451
+ Quantity(
452
+ 'key_parameter',
453
+ rf'pGFNFF (.+? += +{re_f})',
454
+ repeats=True,
455
+ str_operation=lambda x: [
456
+ v.strip() for v in x.split('=')
457
+ ],
458
+ )
459
+ ]
460
+ ),
461
+ ),
462
+ # old format
463
+ Quantity(
464
+ 'pair_potential',
465
+ r'(Atom +Types +Potential +A +B +C +D +.*\s+)'
466
+ r'(.+\s*\-+\s*[\s\S]+?)\-{80}',
467
+ repeats=True,
468
+ sub_parser=TextParser(
469
+ quantities=[
470
+ Quantity(
471
+ 'interaction',
472
+ r'([A-Z]\S* +(?:core|shell|c|s) +[A-Z]\S* +(?:core|shell|c|s) +.+)',
473
+ repeats=True,
474
+ sub_parser=TextParser(
475
+ quantities=interaction_quantities
476
+ + [
477
+ Quantity(
478
+ 'key_parameter',
479
+ rf'({re_f}) +({re_f}) +({re_f}) +({re_f}) +({re_f}) +({re_f})',
480
+ str_operation=lambda x: list(
481
+ zip(
482
+ [
483
+ 'A',
484
+ 'B',
485
+ 'C',
486
+ 'D',
487
+ 'cutoff_min',
488
+ 'cutoff_max',
489
+ ],
490
+ np.array(
491
+ x.strip().split(),
492
+ np.dtype(np.float64),
493
+ ),
494
+ )
495
+ ),
496
+ )
497
+ ]
498
+ ),
499
+ )
500
+ ]
501
+ ),
502
+ ),
503
+ # TODO verify this no example
504
+ Quantity(
505
+ 'three_body_potential',
506
+ r'(Atom +Atom +Atom +Force Constants +Theta.*\s+)'
507
+ r'(.+\s*\-+\s*[\s\S]+?)\-{80}',
508
+ repeats=True,
509
+ sub_parser=TextParser(
510
+ quantities=[
511
+ Quantity(
512
+ 'interaction',
513
+ r'([A-Z]\S* +(?:core|shell|c|s) +[A-Z]\S* +(?:core|shell|c|s) +.+)',
514
+ repeats=True,
515
+ sub_parser=TextParser(
516
+ quantities=interaction_quantities
517
+ + [
518
+ Quantity(
519
+ 'key_parameter',
520
+ rf'({re_f}) +({re_f}) +({re_f}) +({re_f})',
521
+ str_operation=lambda x: list(
522
+ zip(
523
+ [
524
+ 'force_constant_1',
525
+ 'force_constant_2',
526
+ 'force_constant_3',
527
+ 'Theta',
528
+ ],
529
+ np.array(
530
+ x.strip().split(),
531
+ np.dtype(np.float64),
532
+ ),
533
+ )
534
+ ),
535
+ )
536
+ ]
537
+ ),
538
+ )
539
+ ]
540
+ ),
541
+ ),
542
+ # TODO verify this no example
543
+ Quantity(
544
+ 'four_body_potential',
545
+ r'(Atom Types +Force cst\s*Sign\s*Phase\s*Phi0.*\s+)'
546
+ r'(.+\s*\-+\s*[\s\S]+?)\-{80}',
547
+ repeats=True,
548
+ sub_parser=TextParser(
549
+ quantities=[
550
+ Quantity(
551
+ 'interaction',
552
+ r'([A-Z]\S* +(?:core|shell|c|s) +[A-Z]\S* +(?:core|shell|c|s) +.+)',
553
+ repeats=True,
554
+ sub_parser=TextParser(
555
+ quantities=interaction_quantities
556
+ + [
557
+ Quantity(
558
+ 'key_parameter',
559
+ rf'({re_f}) +({re_f}) +({re_f}) +({re_f})',
560
+ str_operation=lambda x: list(
561
+ zip(
562
+ [
563
+ 'force_constant',
564
+ 'sign',
565
+ 'phase',
566
+ 'phi0',
567
+ ],
568
+ np.array(
569
+ x.strip().split(),
570
+ np.dtype(np.float64),
571
+ ),
572
+ )
573
+ ),
574
+ )
575
+ ]
576
+ ),
577
+ )
578
+ ]
579
+ ),
580
+ ),
581
+ # new format
582
+ Quantity(
583
+ 'interatomic_potential',
584
+ rf'.+? potentials +\:\s+\-+\s+'
585
+ rf'Atom.+?Potential +Parameter([\s\S]+?){re_n} *{re_n}',
586
+ repeats=True,
587
+ sub_parser=TextParser(
588
+ quantities=[
589
+ Quantity(
590
+ 'interaction',
591
+ # r'([A-Z]\S* +(?:core|shell|c|s) +[A-Z]\S* +(?:core|shell|c|s) +[\s\S]+?\-{80})',
592
+ r'([A-Z]\S* +(?:core|shell|c|s) +[\s\S]+?\-{80})',
593
+ repeats=True,
594
+ sub_parser=TextParser(
595
+ quantities=interaction_quantities
596
+ + [
597
+ Quantity(
598
+ 'key_parameter',
599
+ r'([A-Z].{14}) {1,4}(\-*\d+\S*)',
600
+ repeats=True,
601
+ str_operation=lambda x: [
602
+ v.strip()
603
+ for v in x.rsplit(' ', 1)
604
+ ],
605
+ )
606
+ ]
607
+ ),
608
+ )
609
+ ]
610
+ ),
611
+ ),
612
+ ]
613
+ ),
614
+ ),
615
+ Quantity(
616
+ 'single_point',
617
+ r'Output for configuration.+\s+\*+([\s\S]+?)(?:\*{80}|\Z)',
618
+ repeats=True,
619
+ sub_parser=TextParser(
620
+ quantities=[
621
+ Quantity(
622
+ 'calculation',
623
+ r'(Components of.+energy \:[\s\S]+?(?:Time to end of|Optimisation achieved|\Z).*)',
624
+ repeats=True,
625
+ sub_parser=TextParser(quantities=calc_quantities),
626
+ )
627
+ ]
628
+ ),
629
+ ),
630
+ Quantity(
631
+ 'molecular_dynamics',
632
+ r'Molecular Dynamics.+\s+\*+([\s\S]+?)(?:\*{80}|\Z)',
633
+ repeats=True,
634
+ sub_parser=TextParser(
635
+ quantities=[
636
+ Quantity(
637
+ 'ensemble_type', r'ensemble \((\S+)\) to be used', dtype=str
638
+ ),
639
+ Quantity(
640
+ 'x_gulp_friction_temperature_bath',
641
+ rf'Friction for temperature bath += +({re_f})',
642
+ dtype=np.float64,
643
+ ),
644
+ Quantity(
645
+ 'x_gulp_n_mobile_ions',
646
+ r'No\. of mobile ions += +(\d+)',
647
+ dtype=np.int32,
648
+ ),
649
+ Quantity(
650
+ 'x_gulp_n_degrees_of_freedom',
651
+ r'No\. of degrees of freedom += +(\d+)',
652
+ dtype=np.int32,
653
+ ),
654
+ Quantity(
655
+ 'timestep',
656
+ rf'Time step += +({re_f})',
657
+ dtype=np.float64,
658
+ unit=ureg.ps,
659
+ ),
660
+ Quantity(
661
+ 'x_gulp_equilibration_time',
662
+ rf'Equilibration time += +({re_f})',
663
+ dtype=np.float64,
664
+ unit=ureg.ps,
665
+ ),
666
+ Quantity(
667
+ 'x_gulp_production_time',
668
+ rf'Production time += +({re_f})',
669
+ dtype=np.float64,
670
+ unit=ureg.ps,
671
+ ),
672
+ Quantity(
673
+ 'x_gulp_scaling_time',
674
+ rf'Scaling time += +({re_f})',
675
+ dtype=np.float64,
676
+ unit=ureg.ps,
677
+ ),
678
+ Quantity(
679
+ 'x_gulp_scaling_frequency',
680
+ rf'Scaling frequency += +({re_f})',
681
+ dtype=np.float64,
682
+ unit=ureg.ps,
683
+ ),
684
+ Quantity(
685
+ 'x_gulp_sampling_frequency',
686
+ rf'Sampling frequency += +({re_f})',
687
+ dtype=np.float64,
688
+ unit=ureg.ps,
689
+ ),
690
+ Quantity(
691
+ 'x_gulp_write_frequency',
692
+ rf'Write frequency += +({re_f})',
693
+ dtype=np.float64,
694
+ unit=ureg.ps,
695
+ ),
696
+ Quantity(
697
+ 'x_gulp_td_force_start_time',
698
+ rf'TD\-Force start time += +({re_f})',
699
+ dtype=np.float64,
700
+ unit=ureg.ps,
701
+ ),
702
+ Quantity(
703
+ 'x_gulp_td_field_start_time',
704
+ rf'TD\-Field start time += +({re_f})',
705
+ dtype=np.float64,
706
+ unit=ureg.ps,
707
+ ),
708
+ Quantity(
709
+ 'step',
710
+ rf'(Time \: +[\s\S]+?)(?:\*\*|{re_n} *{re_n})',
711
+ repeats=True,
712
+ sub_parser=TextParser(
713
+ quantities=[
714
+ Quantity(
715
+ 'time',
716
+ rf'Time \: +({re_f})',
717
+ dtype=np.float64,
718
+ unit=ureg.ps,
719
+ ),
720
+ Quantity(
721
+ 'energy_kinetic',
722
+ rf'Kinetic energy +\(eV\) += +({re_f}) +({re_f})',
723
+ dtype=np.dtype(np.float64),
724
+ unit=ureg.eV,
725
+ ),
726
+ Quantity(
727
+ 'energy_potential',
728
+ rf'Potential energy +\(eV\) += +({re_f}) +({re_f})',
729
+ dtype=np.dtype(np.float64),
730
+ unit=ureg.eV,
731
+ ),
732
+ Quantity(
733
+ 'energy_total',
734
+ rf'Total energy +\(eV\) += +({re_f}) +({re_f})',
735
+ dtype=np.dtype(np.float64),
736
+ unit=ureg.eV,
737
+ ),
738
+ Quantity(
739
+ 'temperature',
740
+ rf'Temperature +\(K\) += +({re_f}) +({re_f})',
741
+ dtype=np.dtype(np.float64),
742
+ unit=ureg.kelvin,
743
+ ),
744
+ Quantity(
745
+ 'pressure',
746
+ rf'Pressure +\(GPa\) += +({re_f}) +({re_f})',
747
+ dtype=np.dtype(np.float64),
748
+ unit=ureg.GPa,
749
+ ),
750
+ ]
751
+ ),
752
+ ),
753
+ ]
754
+ ),
755
+ ),
756
+ Quantity(
757
+ 'defect',
758
+ r'Defect calculation for configuration.+\s+\*+([\s\S]+?)(?:\*{80}|\Z)',
759
+ repeats=True,
760
+ sub_parser=TextParser(
761
+ quantities=[
762
+ Quantity(
763
+ 'calculation',
764
+ r'(Components of.+energy \:[\s\S]+?(?:Time to end of|Optimisation achieved).+)',
765
+ repeats=True,
766
+ sub_parser=TextParser(quantities=calc_quantities),
767
+ )
768
+ ]
769
+ ),
770
+ ),
771
+ ]
772
+
773
+
774
+ class GulpParser(Parser):
775
+ def __init__(self):
776
+ self.mainfile_parser = MainfileParser()
777
+ self._metainfo_map = {
778
+ 'Attachment energy': 'x_gulp_attachment',
779
+ 'Attachment energy/unit': 'x_gulp_attachment_unit',
780
+ 'Bond-order potentials': 'x_gulp_bond_order_potentials',
781
+ 'Brenner potentials': 'x_gulp_brenner_potentials',
782
+ 'Bulk energy': 'x_gulp_bulk',
783
+ 'Dispersion (real+recip)': 'x_gulp_dispersion',
784
+ 'Electric_field*distance': 'x_gulp_electric_field_distance',
785
+ 'Energy shift': 'x_gulp_shift',
786
+ 'Four-body potentials': 'x_gulp_four_body_potentials',
787
+ 'Improper torsions': 'x_gulp_improper_torsions',
788
+ 'Interatomic potentials': 'x_gulp_interatomic_potentials',
789
+ 'Many-body potentials': 'x_gulp_many_body_potentials',
790
+ 'Monopole - monopole (real)': 'x_gulp_monopole_monopole_real',
791
+ 'Monopole - monopole (recip)': 'x_gulp_monopole_monopole_recip',
792
+ 'Monopole - monopole (total)': 'x_gulp_monopole_monopole_total',
793
+ 'Neutralising energy': 'x_gulp_neutralising',
794
+ 'Non-primitive unit cell': 'x_gulp_non_primitive_unit_cell',
795
+ 'Out of plane potentials': 'x_gulp_out_of_plane_potentials',
796
+ 'Primitive unit cell': 'x_gulp_primitive_unit_cell',
797
+ 'ReaxFF force field': 'x_gulp_reaxff_force_field',
798
+ 'Region 1-2 interaction': 'x_gulp_region_1_2_interaction',
799
+ 'Region 2-2 interaction': 'x_gulp_region_2_2_interaction',
800
+ 'Self energy (EEM/QEq/SM)': 'x_gulp_self_eem_qeq_sm',
801
+ 'SM Coulomb correction': 'x_gulp_sm_coulomb_correction',
802
+ 'Solvation energy': 'x_gulp_solvation',
803
+ 'Three-body potentials': 'x_gulp_three_body_potentials',
804
+ 'Total lattice energy': 'total',
805
+ 'Total defect energy': 'total',
806
+ }
807
+ self._sg_map = {
808
+ 'P 1': 1,
809
+ 'P -1': 2,
810
+ 'P 2': 3,
811
+ 'P 21': 4,
812
+ 'C 2': 5,
813
+ 'P M': 6,
814
+ 'P C': 7,
815
+ 'C M': 8,
816
+ 'C C': 9,
817
+ 'P 2/M': 10,
818
+ 'P 21/M': 11,
819
+ 'C 2/M': 12,
820
+ 'P 2/C': 13,
821
+ 'P 21/C': 14,
822
+ 'C 2/C': 15,
823
+ 'P 2 2 2': 16,
824
+ 'P 2 2 21': 17,
825
+ 'P 21 21 2': 18,
826
+ 'P 21 21 21': 19,
827
+ 'C 2 2 21': 20,
828
+ 'C 2 2 2': 21,
829
+ 'F 2 2 2': 22,
830
+ 'I 2 2 2': 23,
831
+ 'I 21 21 21': 24,
832
+ 'P M M 2': 25,
833
+ 'P M C 21': 26,
834
+ 'P C C 2': 27,
835
+ 'P M A 2': 28,
836
+ 'P C A 21': 29,
837
+ 'P N C 2': 30,
838
+ 'P M N 21': 31,
839
+ 'P B A 2': 32,
840
+ 'P N A 21': 33,
841
+ 'P N N 2': 34,
842
+ 'C M M 2': 35,
843
+ 'C M C 21': 36,
844
+ 'C C C 2': 37,
845
+ 'A M M 2': 38,
846
+ 'A B M 2': 39,
847
+ 'A M A 2': 40,
848
+ 'A B A 2': 41,
849
+ 'F M M 2': 42,
850
+ 'F D D 2': 43,
851
+ 'I M M 2': 44,
852
+ 'I B A 2': 45,
853
+ 'I M A 2': 46,
854
+ 'P M M M': 47,
855
+ 'P N N N': 48,
856
+ 'P C C M': 49,
857
+ 'P B A N': 50,
858
+ 'P M M A': 51,
859
+ 'P N N A': 52,
860
+ 'P M N A': 53,
861
+ 'P C C A': 54,
862
+ 'P B A M': 55,
863
+ 'P C C N': 56,
864
+ 'P B C M': 57,
865
+ 'P N N M': 58,
866
+ 'P M M N': 59,
867
+ 'P B C N': 60,
868
+ 'P B C A': 61,
869
+ 'P N M A': 62,
870
+ 'C M C M': 63,
871
+ 'C M C A': 64,
872
+ 'C M M M': 65,
873
+ 'C C C M': 66,
874
+ 'C M M A': 67,
875
+ 'C C C A': 68,
876
+ 'F M M M': 69,
877
+ 'F D D D': 70,
878
+ 'I M M M': 71,
879
+ 'I B A M': 72,
880
+ 'I B C A': 73,
881
+ 'I M M A': 74,
882
+ 'P 4': 75,
883
+ 'P 41': 76,
884
+ 'P 42': 77,
885
+ 'P 43': 78,
886
+ 'I 4': 79,
887
+ 'I 41': 80,
888
+ 'P -4': 81,
889
+ 'I -4': 82,
890
+ 'P 4/M': 83,
891
+ 'P 42/M': 84,
892
+ 'P 4/N': 85,
893
+ 'P 42/N': 86,
894
+ 'I 4/M': 87,
895
+ 'I 41/A': 88,
896
+ 'P 4 2 2': 89,
897
+ 'P 4 21 2': 90,
898
+ 'P 41 2 2': 91,
899
+ 'P 41 21 2': 92,
900
+ 'P 42 2 2': 93,
901
+ 'P 42 21 2': 94,
902
+ 'P 43 2 2': 95,
903
+ 'P 43 21 2': 96,
904
+ 'I 4 2 2': 97,
905
+ 'I 41 2 2': 98,
906
+ 'P 4 M M': 99,
907
+ 'P 4 B M': 100,
908
+ 'P 42 C M': 101,
909
+ 'P 42 N M': 102,
910
+ 'P 4 C C': 103,
911
+ 'P 4 N C': 104,
912
+ 'P 42 M C': 105,
913
+ 'P 42 B C': 106,
914
+ 'I 4 M M': 107,
915
+ 'I 4 C M': 108,
916
+ 'I 41 M D': 109,
917
+ 'I 41 C D': 110,
918
+ 'P -4 2 M': 111,
919
+ 'P -4 2 C': 112,
920
+ 'P -4 21 M': 113,
921
+ 'P -4 21 C': 114,
922
+ 'P -4 M 2': 115,
923
+ 'P -4 C 2': 116,
924
+ 'P -4 B 2': 117,
925
+ 'P -4 N 2': 118,
926
+ 'I -4 M 2': 119,
927
+ 'I -4 C 2': 120,
928
+ 'I -4 2 M': 121,
929
+ 'I -4 2 D': 122,
930
+ 'P 4/M M M': 123,
931
+ 'P 4/M C C': 124,
932
+ 'P 4/N B M': 125,
933
+ 'P 4/N N C': 126,
934
+ 'P 4/M B M': 127,
935
+ 'P 4/M N C': 128,
936
+ 'P 4/N M M': 129,
937
+ 'P 4/N C C': 130,
938
+ 'P 42/M M C': 131,
939
+ 'P 42/M C M': 132,
940
+ 'P 42/N B C': 133,
941
+ 'P 42/N N M': 134,
942
+ 'P 42/M B C': 135,
943
+ 'P 42/M N M': 136,
944
+ 'P 42/N M C': 137,
945
+ 'P 42/N C M': 138,
946
+ 'I 4/M M M': 139,
947
+ 'I 4/M C M': 140,
948
+ 'I 41/A M D': 141,
949
+ 'I 41/A C D': 142,
950
+ 'P 3': 143,
951
+ 'P 31': 144,
952
+ 'P 32': 145,
953
+ 'R 3': 146,
954
+ 'P -3': 147,
955
+ 'R -3': 148,
956
+ 'P 3 1 2': 149,
957
+ 'P 3 2 1': 150,
958
+ 'P 31 1 2': 151,
959
+ 'P 31 2 1': 152,
960
+ 'P 32 1 2': 153,
961
+ 'P 32 2 1': 154,
962
+ 'R 3 2': 155,
963
+ 'P 3 M 1': 156,
964
+ 'P 3 1 M': 157,
965
+ 'P 3 C 1': 158,
966
+ 'P 3 1 C': 159,
967
+ 'R 3 M': 160,
968
+ 'R 3 C': 161,
969
+ 'P -3 1 M': 162,
970
+ 'P -3 1 C': 163,
971
+ 'P -3 M 1': 164,
972
+ 'P -3 C 1': 165,
973
+ 'R -3 M': 166,
974
+ 'R -3 C': 167,
975
+ 'P 6': 168,
976
+ 'P 61': 169,
977
+ 'P 65': 170,
978
+ 'P 62': 171,
979
+ 'P 64': 172,
980
+ 'P 63': 173,
981
+ 'P -6': 174,
982
+ 'P 6/M': 175,
983
+ 'P 63/M': 176,
984
+ 'P 6 2 2': 177,
985
+ 'P 61 2 2': 178,
986
+ 'P 65 2 2': 179,
987
+ 'P 62 2 2': 180,
988
+ 'P 64 2 2': 181,
989
+ 'P 63 2 2': 182,
990
+ 'P 6 M M': 183,
991
+ 'P 6 C C': 184,
992
+ 'P 63 C M': 185,
993
+ 'P 63 M C': 186,
994
+ 'P -6 M 2': 187,
995
+ 'P -6 C 2': 188,
996
+ 'P -6 2 M': 189,
997
+ 'P -6 2 C': 190,
998
+ 'P 6/M M M': 191,
999
+ 'P 6/M C C': 192,
1000
+ 'P 63/M C M': 193,
1001
+ 'P 63/M M C': 194,
1002
+ 'P 2 3': 195,
1003
+ 'F 2 3': 196,
1004
+ 'I 2 3': 197,
1005
+ 'P 21 3': 198,
1006
+ 'I 21 3': 199,
1007
+ 'P M 3': 200,
1008
+ 'P M -3': 200,
1009
+ 'P N 3': 201,
1010
+ 'P N -3': 201,
1011
+ 'F M 3': 202,
1012
+ 'F M -3': 202,
1013
+ 'F D 3': 203,
1014
+ 'F D -3': 203,
1015
+ 'I M 3': 204,
1016
+ 'I M -3': 204,
1017
+ 'P A 3': 205,
1018
+ 'P A -3': 205,
1019
+ 'I A 3': 206,
1020
+ 'I A -3': 206,
1021
+ 'P 4 3 2': 207,
1022
+ 'P 42 3 2': 208,
1023
+ 'F 4 3 2': 209,
1024
+ 'F 41 3 2': 210,
1025
+ 'I 4 3 2': 211,
1026
+ 'P 43 3 2': 212,
1027
+ 'P 41 3 2': 213,
1028
+ 'I 41 3 2': 214,
1029
+ 'P -4 3 M': 215,
1030
+ 'F -4 3 M': 216,
1031
+ 'I -4 3 M': 217,
1032
+ 'P -4 3 N': 218,
1033
+ 'F -4 3 C': 219,
1034
+ 'I -4 3 D': 220,
1035
+ 'P M 3 M': 221,
1036
+ 'P N 3 N': 222,
1037
+ 'P M 3 N': 223,
1038
+ 'P N 3 M': 224,
1039
+ 'F M 3 M': 225,
1040
+ 'F M 3 C': 226,
1041
+ 'F D 3 M': 227,
1042
+ 'F D 3 C': 228,
1043
+ 'I M 3 M': 229,
1044
+ 'I A 3 D': 230,
1045
+ 'C 1': 231,
1046
+ 'C -1': 232,
1047
+ }
1048
+
1049
+ def write_to_archive(self) -> None:
1050
+ self.mainfile_parser.logger = self.logger
1051
+ self.mainfile_parser.mainfile = self.mainfile
1052
+ self.maindir = os.path.dirname(self.mainfile)
1053
+
1054
+ sec_run = Run()
1055
+ self.archive.run.append(sec_run)
1056
+ # general run parameters
1057
+ header = self.mainfile_parser.get('header', {})
1058
+ sec_run.program = Program(version=header.get('program_version'))
1059
+ sec_run.x_gulp_title = header.get('title')
1060
+ for key, val in self.mainfile_parser.items():
1061
+ if key.startswith('x_gulp_'):
1062
+ setattr(sec_run, key, val)
1063
+ if self.mainfile_parser.date_start is not None:
1064
+ sec_run.time_run = TimeRun(
1065
+ date_start=datetime.strptime(
1066
+ self.mainfile_parser.date_start, '%H:%M.%S %d %B %Y'
1067
+ ).timestamp()
1068
+ )
1069
+ if self.mainfile_parser.date_end is not None:
1070
+ sec_run.time_run.date_end = datetime.strptime(
1071
+ self.mainfile_parser.date_end, '%H:%M.%S %d %B %Y'
1072
+ ).timestamp()
1073
+
1074
+ input_info = self.mainfile_parser.get('input_information', {})
1075
+ sec_method = Method()
1076
+ sec_run.method.append(sec_method)
1077
+ # add force field interaction models
1078
+ force_field = ForceField()
1079
+ sec_method.force_field = force_field
1080
+ # for the new format, all potentials are in potentials while in old, needs to add
1081
+ # pair, three- and four-body interactions
1082
+ for potential_type in [
1083
+ 'interatomic_potential',
1084
+ 'pair_potential',
1085
+ 'three_body_potential',
1086
+ 'four_body_potential',
1087
+ ]:
1088
+ for potential in input_info.get(potential_type, []):
1089
+ sec_model = Model()
1090
+ force_field.model.append(sec_model)
1091
+ for interaction in potential.get('interaction', []):
1092
+ sec_model.contributions.append(
1093
+ Interaction(
1094
+ functional_form=interaction.functional_form,
1095
+ atom_labels=[[v[0] for v in interaction.get('atom_type')]],
1096
+ parameters={
1097
+ key: float(val) if isinstance(val, np.float64) else val
1098
+ for key, val in interaction.get('key_parameter', [])
1099
+ },
1100
+ )
1101
+ )
1102
+
1103
+ if (pgfnff := input_info.get('pgfnff')) is not None:
1104
+ sec_model = Model()
1105
+ force_field.model.append(sec_model)
1106
+ sec_model.name = 'pGFNFF'
1107
+ sec_model.contributions.append(
1108
+ Interaction(
1109
+ parameters={
1110
+ key: float(val) for key, val in pgfnff.get('key_parameter', [])
1111
+ }
1112
+ )
1113
+ )
1114
+ # atom parameters
1115
+ for n in range(len(input_info.get('species', {}).get('label', []))):
1116
+ sec_atom_parameter = AtomParameters()
1117
+ sec_method.atom_parameters.append(sec_atom_parameter)
1118
+ for key, val in input_info.species.items():
1119
+ setattr(sec_atom_parameter, key, val[n])
1120
+
1121
+ input_config = self.mainfile_parser.get('input_configuration', {})
1122
+
1123
+ def parse_system(source):
1124
+ # read from input configuration if section does not have structure information
1125
+ source = (
1126
+ self.mainfile_parser.input_configuration
1127
+ if source.coordinates is None
1128
+ else source
1129
+ )
1130
+ if source.coordinates is None:
1131
+ return
1132
+
1133
+ sec_system = System()
1134
+ sec_run.system.append(sec_system)
1135
+ positions = []
1136
+ labels = []
1137
+ for atom in source.coordinates.get('atom', []):
1138
+ # include only core atoms
1139
+ if atom[1].lower().startswith('c'):
1140
+ positions.append(atom[2:5])
1141
+ labels.append(atom[0])
1142
+ lattice_vectors = source.get(
1143
+ 'lattice_vectors', input_config.lattice_vectors
1144
+ )
1145
+ unit = source.coordinates.get('unit', '')
1146
+ if unit.lower().startswith('frac') and lattice_vectors is not None:
1147
+ positions = np.dot(positions, lattice_vectors)
1148
+ # get periodicity
1149
+ periodic = np.array([False] * 3)
1150
+ periodic[0 : input_config.get('x_gulp_pbc', 3)] = True
1151
+ # build the basis atoms
1152
+ atoms = ase_Atoms(symbols=labels, cell=lattice_vectors, positions=positions)
1153
+ # build the full crystal
1154
+ space_group = self._sg_map.get(input_config.x_gulp_space_group)
1155
+ # cellpar from source or primitive cellpar or from input_config
1156
+ cellpar = source.get(
1157
+ 'cell_parameters',
1158
+ source.get('cell_parameters_primitive', input_config.cell_parameters),
1159
+ )
1160
+ if space_group is not None and cellpar is not None:
1161
+ atoms = ase_crystal(
1162
+ atoms,
1163
+ spacegroup=space_group,
1164
+ pbc=periodic,
1165
+ primitive_cell=True,
1166
+ cellpar=cellpar,
1167
+ onduplicates='replace',
1168
+ )
1169
+ # TODO take fractional occupancies into consideration
1170
+ sec_system.atoms = Atoms(
1171
+ positions=atoms.get_positions() * ureg.angstrom,
1172
+ labels=atoms.get_chemical_symbols(),
1173
+ lattice_vectors=atoms.get_cell().array * ureg.angstrom,
1174
+ periodic=periodic,
1175
+ )
1176
+ return sec_system
1177
+
1178
+ def parse_mechanical_property(name, source, target):
1179
+ values = source.get(name, [None] * 3)
1180
+ types = (
1181
+ ['x', 'y', 'z']
1182
+ if 'youngs_modulus' in name
1183
+ else ['reuss', 'voigt', 'hill']
1184
+ )
1185
+ for n, type_n in enumerate(types):
1186
+ setattr(target, f'{name}_{type_n}', values[n])
1187
+
1188
+ def parse_calculation(source):
1189
+ sec_calc = Calculation()
1190
+ sec_run.calculation.append(sec_calc)
1191
+
1192
+ if source.energy_components is not None:
1193
+ sec_energy = Energy()
1194
+ sec_calc.energy = sec_energy
1195
+ for key, val in source.energy_components.get('key_val', []):
1196
+ name = self._metainfo_map.get(key)
1197
+ if name is None:
1198
+ continue
1199
+ val = (
1200
+ val * ureg.eV
1201
+ if name.startswith('x_gulp_')
1202
+ else EnergyEntry(value=val * ureg.eV)
1203
+ )
1204
+ setattr(sec_energy, name, val)
1205
+ # assign primitive unit cell energy to energy total
1206
+ sec_energy.total = EnergyEntry(
1207
+ value=sec_energy.x_gulp_primitive_unit_cell
1208
+ )
1209
+
1210
+ if source.bulk_optimisation is not None:
1211
+ sec_opt = x_gulp_bulk_optimisation()
1212
+ sec_calc.x_gulp_bulk_optimisation = sec_opt
1213
+ for cycle in source.bulk_optimisation.get('cycle', []):
1214
+ sec_opt.x_gulp_bulk_optimisation_cycle.append(
1215
+ x_gulp_bulk_optimisation_cycle(
1216
+ x_gulp_energy=cycle[0] * ureg.eV,
1217
+ x_gulp_gnorm=cycle[1],
1218
+ x_gulp_cpu_time=cycle[2],
1219
+ )
1220
+ )
1221
+ for key, val in source.bulk_optimisation.items():
1222
+ if key.startswith('x_gulp_'):
1223
+ setattr(sec_opt, key, val)
1224
+
1225
+ if source.elastic_constants is not None:
1226
+ workflow = Elastic(method=ElasticMethod(), results=ElasticResults())
1227
+ workflow.method.energy_stress_calculator = 'gulp'
1228
+ workflow.results.elastic_constants_matrix_second_order = (
1229
+ source.elastic_constants
1230
+ )
1231
+ workflow.results.compliance_matrix_second_order = (
1232
+ source.elastic_compliance
1233
+ )
1234
+ mechanical_properties = source.get('mechanical_properties', {})
1235
+ parse_mechanical_property(
1236
+ 'bulk_modulus', mechanical_properties, workflow.results
1237
+ )
1238
+ parse_mechanical_property(
1239
+ 'shear_modulus', mechanical_properties, workflow.results
1240
+ )
1241
+ parse_mechanical_property(
1242
+ 'x_gulp_velocity_s_wave', mechanical_properties, workflow.results
1243
+ )
1244
+ parse_mechanical_property(
1245
+ 'x_gulp_velocity_p_wave', mechanical_properties, workflow.results
1246
+ )
1247
+ parse_mechanical_property(
1248
+ 'x_gulp_youngs_modulus', mechanical_properties, workflow.results
1249
+ )
1250
+ workflow.results.x_gulp_compressibility = mechanical_properties.get(
1251
+ 'compressibility'
1252
+ )
1253
+ poissons = mechanical_properties.get('poissons_ratio', np.zeros((3, 3)))
1254
+ # insert zeros for diagonal elements
1255
+ for n in range(3):
1256
+ poissons[n] = np.insert(poissons[n], n, 0.0)
1257
+ workflow.results.x_gulp_poissons_ratio = poissons
1258
+ self.archive.workflow2 = workflow
1259
+
1260
+ # md properties
1261
+ if source.energy_total is not None:
1262
+ sec_calc.energy = Energy(
1263
+ total=EnergyEntry(
1264
+ value=source.energy_total[0],
1265
+ kinetic=source.energy_kinetic[0],
1266
+ potential=source.energy_potential[0],
1267
+ )
1268
+ )
1269
+ sec_calc.energy.x_gulp_total_averaged = EnergyEntry(
1270
+ value=source.energy_total[1],
1271
+ kinetic=source.energy_kinetic[1],
1272
+ potential=source.energy_potential[1],
1273
+ )
1274
+ sec_calc.time = source.time
1275
+ sec_calc.temperature = source.get('temperature', [None, None])[0]
1276
+ sec_calc.pressure = source.get('pressure', [None, None])[0]
1277
+ sec_calc.x_gulp_temperature_averaged = source.get(
1278
+ 'temperature', [None, None]
1279
+ )[1]
1280
+ sec_calc.x_gulp_pressure_averaged = source.get('pressure', [None, None])[1]
1281
+
1282
+ # other properties
1283
+ for key, val in source.items():
1284
+ if key.startswith('x_gulp_'):
1285
+ if key.endswith('refractive_indices') and val is not None:
1286
+ val = val.value
1287
+ setattr(sec_calc, key, val)
1288
+
1289
+ return sec_calc
1290
+
1291
+ for output in self.mainfile_parser.get('single_point', []):
1292
+ for calculation in output.get('calculation', []):
1293
+ sec_system = parse_system(calculation)
1294
+ sec_calc = parse_calculation(calculation)
1295
+ sec_calc.system_ref = sec_system
1296
+
1297
+ for output in self.mainfile_parser.get('defect', []):
1298
+ for calculation in output.get('calculation', []):
1299
+ sec_system = parse_system(calculation)
1300
+ sec_calc = parse_calculation(calculation)
1301
+ sec_calc.system_ref = sec_system
1302
+
1303
+ for output in self.mainfile_parser.get('molecular_dynamics', []):
1304
+ workflow = MolecularDynamics(method=MolecularDynamicsMethod())
1305
+ workflow.method.thermodynamic_ensemble = output.get(
1306
+ 'ensemble_type', ''
1307
+ ).upper()
1308
+ workflow.method.integration_timestep = output.timestep
1309
+ for key, val in output.items():
1310
+ if key.startswith('x_gulp_'):
1311
+ setattr(workflow, key, val)
1312
+ # parse md steps
1313
+ for step in output.get('step', []):
1314
+ parse_calculation(step)
1315
+ # TODO where are the trajectory data saved
1316
+ self.archive.workflow2 = workflow