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.
- atomisticparsers/__init__.py +400 -0
- atomisticparsers/amber/__init__.py +19 -0
- atomisticparsers/amber/__main__.py +31 -0
- atomisticparsers/amber/metainfo/__init__.py +19 -0
- atomisticparsers/amber/metainfo/amber.py +495 -0
- atomisticparsers/amber/parser.py +42 -0
- atomisticparsers/asap/__init__.py +19 -0
- atomisticparsers/asap/__main__.py +31 -0
- atomisticparsers/asap/metainfo/__init__.py +19 -0
- atomisticparsers/asap/metainfo/asap.py +75 -0
- atomisticparsers/asap/parser.py +197 -0
- atomisticparsers/bopfox/__init__.py +19 -0
- atomisticparsers/bopfox/__main__.py +31 -0
- atomisticparsers/bopfox/metainfo/__init__.py +19 -0
- atomisticparsers/bopfox/metainfo/bopfox.py +225 -0
- atomisticparsers/bopfox/parser.py +808 -0
- atomisticparsers/dftbplus/__init__.py +19 -0
- atomisticparsers/dftbplus/__main__.py +31 -0
- atomisticparsers/dftbplus/metainfo/__init__.py +19 -0
- atomisticparsers/dftbplus/metainfo/dftbplus.py +217 -0
- atomisticparsers/dftbplus/parser.py +500 -0
- atomisticparsers/dlpoly/__init__.py +19 -0
- atomisticparsers/dlpoly/__main__.py +31 -0
- atomisticparsers/dlpoly/metainfo/__init__.py +19 -0
- atomisticparsers/dlpoly/metainfo/dl_poly.py +312 -0
- atomisticparsers/dlpoly/parser.py +798 -0
- atomisticparsers/gromacs/__init__.py +19 -0
- atomisticparsers/gromacs/__main__.py +31 -0
- atomisticparsers/gromacs/metainfo/__init__.py +19 -0
- atomisticparsers/gromacs/metainfo/gromacs.py +2388 -0
- atomisticparsers/gromacs/parser.py +1581 -0
- atomisticparsers/gromos/__init__.py +19 -0
- atomisticparsers/gromos/__main__.py +31 -0
- atomisticparsers/gromos/metainfo/__init__.py +19 -0
- atomisticparsers/gromos/metainfo/gromos.py +1995 -0
- atomisticparsers/gromos/parser.py +58 -0
- atomisticparsers/gulp/__init__.py +19 -0
- atomisticparsers/gulp/__main__.py +31 -0
- atomisticparsers/gulp/metainfo/__init__.py +19 -0
- atomisticparsers/gulp/metainfo/gulp.py +1117 -0
- atomisticparsers/gulp/parser.py +1316 -0
- atomisticparsers/h5md/__init__.py +19 -0
- atomisticparsers/h5md/__main__.py +31 -0
- atomisticparsers/h5md/metainfo/__init__.py +19 -0
- atomisticparsers/h5md/metainfo/h5md.py +239 -0
- atomisticparsers/h5md/parser.py +901 -0
- atomisticparsers/lammps/__init__.py +19 -0
- atomisticparsers/lammps/__main__.py +31 -0
- atomisticparsers/lammps/metainfo/__init__.py +19 -0
- atomisticparsers/lammps/metainfo/lammps.py +1417 -0
- atomisticparsers/lammps/parser.py +1753 -0
- atomisticparsers/libatoms/__init__.py +19 -0
- atomisticparsers/libatoms/__main__.py +31 -0
- atomisticparsers/libatoms/metainfo/__init__.py +19 -0
- atomisticparsers/libatoms/metainfo/lib_atoms.py +251 -0
- atomisticparsers/libatoms/parser.py +38 -0
- atomisticparsers/namd/__init__.py +19 -0
- atomisticparsers/namd/__main__.py +31 -0
- atomisticparsers/namd/metainfo/__init__.py +19 -0
- atomisticparsers/namd/metainfo/namd.py +1605 -0
- atomisticparsers/namd/parser.py +312 -0
- atomisticparsers/tinker/__init__.py +19 -0
- atomisticparsers/tinker/__main__.py +31 -0
- atomisticparsers/tinker/metainfo/__init__.py +18 -0
- atomisticparsers/tinker/metainfo/tinker.py +1363 -0
- atomisticparsers/tinker/parser.py +685 -0
- atomisticparsers/utils/__init__.py +22 -0
- atomisticparsers/utils/mdanalysis.py +662 -0
- atomisticparsers/utils/parsers.py +226 -0
- atomisticparsers/xtb/__init__.py +19 -0
- atomisticparsers/xtb/__main__.py +32 -0
- atomisticparsers/xtb/metainfo/__init__.py +19 -0
- atomisticparsers/xtb/metainfo/xtb.py +256 -0
- atomisticparsers/xtb/parser.py +979 -0
- nomad_parser_plugins_atomistic-1.0.dist-info/LICENSE +202 -0
- nomad_parser_plugins_atomistic-1.0.dist-info/METADATA +327 -0
- nomad_parser_plugins_atomistic-1.0.dist-info/RECORD +80 -0
- nomad_parser_plugins_atomistic-1.0.dist-info/WHEEL +5 -0
- nomad_parser_plugins_atomistic-1.0.dist-info/entry_points.txt +15 -0
- nomad_parser_plugins_atomistic-1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1581 @@
|
|
|
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 numpy as np
|
|
21
|
+
import logging
|
|
22
|
+
import re
|
|
23
|
+
import datetime
|
|
24
|
+
|
|
25
|
+
import panedr
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
import MDAnalysis
|
|
29
|
+
from MDAnalysis.topology.tpr import utils as tpr_utils, setting as tpr_setting
|
|
30
|
+
except Exception:
|
|
31
|
+
logging.warning('Required module MDAnalysis not found.')
|
|
32
|
+
MDAnalysis = False
|
|
33
|
+
from ase.symbols import symbols2numbers
|
|
34
|
+
from nomad.units import ureg
|
|
35
|
+
from nomad.parsing.file_parser import TextParser, Quantity, FileParser
|
|
36
|
+
from runschema.run import Run, Program, TimeRun
|
|
37
|
+
from runschema.method import (
|
|
38
|
+
NeighborSearching,
|
|
39
|
+
ForceCalculations,
|
|
40
|
+
Method,
|
|
41
|
+
ForceField,
|
|
42
|
+
Model,
|
|
43
|
+
AtomParameters,
|
|
44
|
+
)
|
|
45
|
+
from runschema.system import AtomsGroup
|
|
46
|
+
from simulationworkflowschema import (
|
|
47
|
+
GeometryOptimization,
|
|
48
|
+
GeometryOptimizationMethod,
|
|
49
|
+
GeometryOptimizationResults,
|
|
50
|
+
)
|
|
51
|
+
from .metainfo.gromacs import (
|
|
52
|
+
x_gromacs_section_control_parameters,
|
|
53
|
+
x_gromacs_section_input_output_files,
|
|
54
|
+
)
|
|
55
|
+
from atomisticparsers.utils import MDAnalysisParser, MDParser
|
|
56
|
+
from simulationworkflowschema.molecular_dynamics import get_bond_list_from_model_contributions
|
|
57
|
+
|
|
58
|
+
re_float = r'[-+]?\d+\.*\d*(?:[Ee][-+]\d+)?'
|
|
59
|
+
re_n = r'[\n\r]'
|
|
60
|
+
|
|
61
|
+
MOL = 6.022140857e23
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def to_float(string):
|
|
65
|
+
try:
|
|
66
|
+
value = float(string)
|
|
67
|
+
except ValueError:
|
|
68
|
+
value = None
|
|
69
|
+
return value
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class GromacsLogParser(TextParser):
|
|
73
|
+
def __init__(self):
|
|
74
|
+
super().__init__(None)
|
|
75
|
+
|
|
76
|
+
def init_quantities(self):
|
|
77
|
+
def str_to_header(val_in):
|
|
78
|
+
val = [v.split(':', 1) for v in val_in.strip().splitlines()]
|
|
79
|
+
return {v[0].strip(): v[1].strip() for v in val if len(v) == 2}
|
|
80
|
+
|
|
81
|
+
def str_to_input_parameters(val_in):
|
|
82
|
+
re_array = re.compile(r'\s*([\w\-]+)\[[\d ]+\]\s*=\s*\{*(.+)')
|
|
83
|
+
re_scalar = re.compile(r'\s*([\w\-]+)\s*[=:]\s*(.+)')
|
|
84
|
+
parameters = dict()
|
|
85
|
+
val = val_in.strip().splitlines()
|
|
86
|
+
for val_n in val:
|
|
87
|
+
val_scalar = re_scalar.match(val_n)
|
|
88
|
+
if val_scalar:
|
|
89
|
+
parameters[val_scalar.group(1)] = val_scalar.group(2)
|
|
90
|
+
continue
|
|
91
|
+
val_array = re_array.match(val_n)
|
|
92
|
+
if val_array:
|
|
93
|
+
parameters.setdefault(val_array.group(1), [])
|
|
94
|
+
value = [
|
|
95
|
+
float(v) for v in val_array.group(2).rstrip('}').split(',')
|
|
96
|
+
]
|
|
97
|
+
parameters[val_array.group(1)].append(
|
|
98
|
+
value[0] if len(value) == 1 else value
|
|
99
|
+
)
|
|
100
|
+
return parameters
|
|
101
|
+
|
|
102
|
+
def str_to_energies(val_in):
|
|
103
|
+
thermo_common = [
|
|
104
|
+
r'Total Energy',
|
|
105
|
+
r'Potential',
|
|
106
|
+
r'Kinetic En.',
|
|
107
|
+
r'Temperature',
|
|
108
|
+
r'Pressure \(bar\)',
|
|
109
|
+
r'LJ \(SR\)',
|
|
110
|
+
r'Coulomb \(SR\)',
|
|
111
|
+
r'Proper Dih.',
|
|
112
|
+
]
|
|
113
|
+
n_chars_val = re.search(rf'( +{"| +".join(thermo_common)})', val_in)
|
|
114
|
+
n_chars_val = len(n_chars_val.group(1)) if n_chars_val is not None else None
|
|
115
|
+
if n_chars_val is None:
|
|
116
|
+
n_chars_val = 15
|
|
117
|
+
energies = {}
|
|
118
|
+
rows = [v for v in val_in.splitlines() if v]
|
|
119
|
+
for n in range(0, len(rows), 2):
|
|
120
|
+
pointer = 0
|
|
121
|
+
while pointer < len(rows[n]):
|
|
122
|
+
key = rows[n][pointer : pointer + n_chars_val].strip()
|
|
123
|
+
value = rows[n + 1][pointer : pointer + n_chars_val]
|
|
124
|
+
energies[key] = to_float(value)
|
|
125
|
+
pointer += n_chars_val
|
|
126
|
+
return energies
|
|
127
|
+
|
|
128
|
+
def str_to_step_info(val_in):
|
|
129
|
+
val = val_in.strip().splitlines()
|
|
130
|
+
keys = val[0].split()
|
|
131
|
+
values = [to_float(v) for v in val[1].split()]
|
|
132
|
+
return {key: values[n] for n, key in enumerate(keys)}
|
|
133
|
+
|
|
134
|
+
thermo_quantities = [
|
|
135
|
+
Quantity(
|
|
136
|
+
'energies',
|
|
137
|
+
r'Energies \(kJ/mol\).*\n(\s*[\s\S]+?)(?:\n.*step.* load imb.*|\n\n)',
|
|
138
|
+
str_operation=str_to_energies,
|
|
139
|
+
convert=False,
|
|
140
|
+
),
|
|
141
|
+
Quantity(
|
|
142
|
+
'step_info',
|
|
143
|
+
rf'{re_n}\s*(Step.+\n[\d\.\- ]+)',
|
|
144
|
+
str_operation=str_to_step_info,
|
|
145
|
+
convert=False,
|
|
146
|
+
),
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
self._quantities = [
|
|
150
|
+
Quantity('time_start', r'Log file opened on (.+)', flatten=False),
|
|
151
|
+
Quantity(
|
|
152
|
+
'host_info',
|
|
153
|
+
r'Host:\s*(\S+)\s*pid:\s*(\d+)\s*rank ID:\s*(\d+)\s*number of ranks:\s*(\d*)',
|
|
154
|
+
),
|
|
155
|
+
Quantity(
|
|
156
|
+
'module_version', r'GROMACS:\s*(.+?),\s*VERSION\s*(\S+)', flatten=False
|
|
157
|
+
),
|
|
158
|
+
Quantity('execution_path', r'Executable:\s*(.+)'),
|
|
159
|
+
Quantity('working_path', r'Data prefix:\s*(.+)'),
|
|
160
|
+
# TODO cannot understand treatment of the command line in the old parser
|
|
161
|
+
Quantity(
|
|
162
|
+
'header',
|
|
163
|
+
r'(?:GROMACS|Gromacs) (20[\s\S]+?)\n\n',
|
|
164
|
+
str_operation=str_to_header,
|
|
165
|
+
),
|
|
166
|
+
Quantity(
|
|
167
|
+
'header',
|
|
168
|
+
r'(?:GROMACS|Gromacs) (version:[\s\S]+?)\n\n',
|
|
169
|
+
str_operation=str_to_header,
|
|
170
|
+
),
|
|
171
|
+
Quantity(
|
|
172
|
+
'input_parameters',
|
|
173
|
+
r'Input Parameters:\s*([\s\S]+?)\n\n',
|
|
174
|
+
str_operation=str_to_input_parameters,
|
|
175
|
+
),
|
|
176
|
+
Quantity('maximum_force', r'Norm of force\s*([\s\S]+?)\n\n', flatten=False),
|
|
177
|
+
Quantity(
|
|
178
|
+
'step',
|
|
179
|
+
r'(Step\s*Time[\s\S]+?Energies[\s\S]+?\n\n)',
|
|
180
|
+
repeats=True,
|
|
181
|
+
sub_parser=TextParser(quantities=thermo_quantities),
|
|
182
|
+
),
|
|
183
|
+
Quantity(
|
|
184
|
+
'averages',
|
|
185
|
+
r'A V E R A G E S ====>([\s\S]+?\n\n\n)',
|
|
186
|
+
sub_parser=TextParser(quantities=thermo_quantities),
|
|
187
|
+
),
|
|
188
|
+
Quantity('time_end', r'Finished \S+ on rank \d+ (.+)', flatten=False),
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class GromacsMdpParser(TextParser):
|
|
193
|
+
def __init__(self):
|
|
194
|
+
super().__init__(None)
|
|
195
|
+
|
|
196
|
+
def init_quantities(self):
|
|
197
|
+
def str_to_input_parameters(val_in):
|
|
198
|
+
re_array = re.compile(r'\s*([\w\-]+)\[[\d ]+\]\s*=\s*\{*(.+)')
|
|
199
|
+
re_scalar = re.compile(r'\s*([\w\-]+)\s*[=:]\s*(.+)')
|
|
200
|
+
parameters = dict()
|
|
201
|
+
val = [line.strip() for line in val_in.splitlines()]
|
|
202
|
+
for val_n in val:
|
|
203
|
+
val_scalar = re_scalar.match(val_n)
|
|
204
|
+
if val_scalar:
|
|
205
|
+
parameters[val_scalar.group(1)] = val_scalar.group(2)
|
|
206
|
+
continue
|
|
207
|
+
val_array = re_array.match(val_n)
|
|
208
|
+
if val_array:
|
|
209
|
+
parameters.setdefault(val_array.group(1), [])
|
|
210
|
+
value = [
|
|
211
|
+
to_float(v) for v in val_array.group(2).rstrip('}').split(',')
|
|
212
|
+
]
|
|
213
|
+
parameters[val_array.group(1)].append(
|
|
214
|
+
value[0] if len(value) == 1 else value
|
|
215
|
+
)
|
|
216
|
+
return parameters
|
|
217
|
+
|
|
218
|
+
self._quantities = [
|
|
219
|
+
Quantity(
|
|
220
|
+
'input_parameters',
|
|
221
|
+
r'([\s\S]+)',
|
|
222
|
+
str_operation=str_to_input_parameters,
|
|
223
|
+
),
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class GromacsXvgParser(TextParser):
|
|
228
|
+
def __init__(self):
|
|
229
|
+
super().__init__(None)
|
|
230
|
+
self.re_columns = re.compile(r'@\s*s\d{1,2}\s*legend\s*\".*\"')
|
|
231
|
+
self.re_comment = re.compile(r'^[@#]')
|
|
232
|
+
self.re_quotes = re.compile(r'\"(.*)\"')
|
|
233
|
+
self.re_label = re.compile(r'@\s*(title|xaxis|yaxis)\s*(?: label)?\s*"(.*)"')
|
|
234
|
+
|
|
235
|
+
def str_to_results(val_in):
|
|
236
|
+
results = {
|
|
237
|
+
'column_vals': None,
|
|
238
|
+
'title': '',
|
|
239
|
+
'xaxis': '',
|
|
240
|
+
'yaxis': '',
|
|
241
|
+
'column_headers': [],
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
val = val_in.strip().splitlines()
|
|
245
|
+
val = [line.strip() for line in val]
|
|
246
|
+
for val_n in val:
|
|
247
|
+
val_label = self.re_label.match(val_n)
|
|
248
|
+
val_legend = self.re_columns.match(val_n)
|
|
249
|
+
val_comment = self.re_comment.match(val_n)
|
|
250
|
+
if val_label:
|
|
251
|
+
key, label = val_label.groups()
|
|
252
|
+
results[key] = label
|
|
253
|
+
elif val_legend: # TODO convert out of xmgrace notation
|
|
254
|
+
column = val_legend.group()
|
|
255
|
+
column = self.re_quotes.findall(column)
|
|
256
|
+
column = column[0] if column else None
|
|
257
|
+
results['column_headers'].append(column)
|
|
258
|
+
elif not val_comment:
|
|
259
|
+
results['column_vals'] = (
|
|
260
|
+
np.vstack((results['column_vals'], [val_n.split()]))
|
|
261
|
+
if results['column_vals'] is not None
|
|
262
|
+
else [val_n.split()]
|
|
263
|
+
)
|
|
264
|
+
return results
|
|
265
|
+
|
|
266
|
+
self._quantities = [
|
|
267
|
+
Quantity(
|
|
268
|
+
'results',
|
|
269
|
+
r'([\s\S]+)',
|
|
270
|
+
str_operation=str_to_results,
|
|
271
|
+
),
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class GromacsEDRParser(FileParser):
|
|
276
|
+
def __init__(self):
|
|
277
|
+
super().__init__(None)
|
|
278
|
+
|
|
279
|
+
@property
|
|
280
|
+
def fileedr(self):
|
|
281
|
+
if self._file_handler is None:
|
|
282
|
+
try:
|
|
283
|
+
self._file_handler = panedr.edr_to_df(self.mainfile)
|
|
284
|
+
except Exception:
|
|
285
|
+
self.logger.error('Error reading edr file.')
|
|
286
|
+
|
|
287
|
+
return self._file_handler
|
|
288
|
+
|
|
289
|
+
def parse(self, key):
|
|
290
|
+
if self.fileedr is None:
|
|
291
|
+
return
|
|
292
|
+
|
|
293
|
+
val = self.fileedr.get(key, None)
|
|
294
|
+
if self._results is None:
|
|
295
|
+
self._results = dict()
|
|
296
|
+
|
|
297
|
+
if val is not None:
|
|
298
|
+
val = np.asarray(val)
|
|
299
|
+
|
|
300
|
+
self._results[key] = val
|
|
301
|
+
|
|
302
|
+
def keys(self):
|
|
303
|
+
return list(self.fileedr.keys())
|
|
304
|
+
|
|
305
|
+
@property
|
|
306
|
+
def length(self):
|
|
307
|
+
return self.fileedr.shape[0]
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class GromacsMDAnalysisParser(MDAnalysisParser):
|
|
311
|
+
def __init__(self):
|
|
312
|
+
super().__init__(None)
|
|
313
|
+
|
|
314
|
+
def get_interactions(self):
|
|
315
|
+
interactions = super().get_interactions()
|
|
316
|
+
|
|
317
|
+
# add force field parameters
|
|
318
|
+
try:
|
|
319
|
+
interactions.extend(self.get_force_field_parameters())
|
|
320
|
+
except Exception:
|
|
321
|
+
self.logger.error('Error parsing force field parameters.')
|
|
322
|
+
|
|
323
|
+
self._results['interactions'] = interactions
|
|
324
|
+
|
|
325
|
+
return interactions
|
|
326
|
+
|
|
327
|
+
def get_force_field_parameters(self):
|
|
328
|
+
# read force field parameters not saved by MDAnalysis
|
|
329
|
+
# copied from MDAnalysis.topology.tpr.utils
|
|
330
|
+
# TODO maybe a better implementation exists
|
|
331
|
+
if MDAnalysis.__version__ != '2.0.0':
|
|
332
|
+
self.logger.warning('Incompatible version of MDAnalysis.')
|
|
333
|
+
|
|
334
|
+
with open(self.mainfile, 'rb') as f:
|
|
335
|
+
data = tpr_utils.TPXUnpacker(f.read())
|
|
336
|
+
|
|
337
|
+
interactions = []
|
|
338
|
+
|
|
339
|
+
# read header
|
|
340
|
+
header = tpr_utils.read_tpxheader(data)
|
|
341
|
+
# address compatibility issue
|
|
342
|
+
if header.fver >= tpr_setting.tpxv_AddSizeField and header.fgen >= 27:
|
|
343
|
+
actual_body_size = len(data.get_buffer()) - data.get_position()
|
|
344
|
+
if actual_body_size == 4 * header.sizeOfTprBody:
|
|
345
|
+
self.logger.error('Unsupported tpr format.')
|
|
346
|
+
return interactions
|
|
347
|
+
data = tpr_utils.TPXUnpacker2020.from_unpacker(data)
|
|
348
|
+
|
|
349
|
+
# read other unimportant parts
|
|
350
|
+
if header.bBox:
|
|
351
|
+
tpr_utils.extract_box_info(data, header.fver)
|
|
352
|
+
if header.ngtc > 0:
|
|
353
|
+
if header.fver < 69:
|
|
354
|
+
tpr_utils.ndo_real(data, header.ngtc)
|
|
355
|
+
tpr_utils.ndo_real(data, header.ngtc)
|
|
356
|
+
if not header.bTop:
|
|
357
|
+
return interactions
|
|
358
|
+
|
|
359
|
+
tpr_utils.do_symstr(data, tpr_utils.do_symtab(data))
|
|
360
|
+
data.unpack_int()
|
|
361
|
+
ntypes = data.unpack_int()
|
|
362
|
+
# functional types
|
|
363
|
+
functypes = tpr_utils.ndo_int(data, ntypes)
|
|
364
|
+
data.unpack_double() if header.fver >= 66 else 12.0
|
|
365
|
+
data.unpack_real()
|
|
366
|
+
# read the ffparams
|
|
367
|
+
for i in functypes:
|
|
368
|
+
parameters = []
|
|
369
|
+
if i in [
|
|
370
|
+
tpr_setting.F_ANGLES,
|
|
371
|
+
tpr_setting.F_G96ANGLES,
|
|
372
|
+
tpr_setting.F_BONDS,
|
|
373
|
+
tpr_setting.F_G96BONDS,
|
|
374
|
+
tpr_setting.F_HARMONIC,
|
|
375
|
+
tpr_setting.F_IDIHS,
|
|
376
|
+
]:
|
|
377
|
+
parameters.append(data.unpack_real()) # rA
|
|
378
|
+
parameters.append(data.unpack_real()) # krA
|
|
379
|
+
parameters.append(data.unpack_real()) # rB
|
|
380
|
+
parameters.append(data.unpack_real()) # krB
|
|
381
|
+
|
|
382
|
+
elif i in [tpr_setting.F_RESTRANGLES]:
|
|
383
|
+
parameters.append(data.unpack_real()) # harmonic.rA
|
|
384
|
+
parameters.append(data.unpack_real()) # harmonic.krA
|
|
385
|
+
elif i in [tpr_setting.F_LINEAR_ANGLES]:
|
|
386
|
+
parameters.append(data.unpack_real()) # linangle.klinA
|
|
387
|
+
parameters.append(data.unpack_real()) # linangle.aA
|
|
388
|
+
parameters.append(data.unpack_real()) # linangle.klinB
|
|
389
|
+
parameters.append(data.unpack_real()) # linangle.aB);
|
|
390
|
+
elif i in [tpr_setting.F_FENEBONDS]:
|
|
391
|
+
parameters.append(data.unpack_real()) # fene.bm
|
|
392
|
+
parameters.append(data.unpack_real()) # fene.kb
|
|
393
|
+
elif i in [tpr_setting.F_RESTRBONDS]:
|
|
394
|
+
parameters.append(data.unpack_real()) # restraint.lowA
|
|
395
|
+
parameters.append(data.unpack_real()) # restraint.up1A
|
|
396
|
+
parameters.append(data.unpack_real()) # restraint.up2A
|
|
397
|
+
parameters.append(data.unpack_real()) # restraint.kA
|
|
398
|
+
parameters.append(data.unpack_real()) # restraint.lowB
|
|
399
|
+
parameters.append(data.unpack_real()) # restraint.up1B
|
|
400
|
+
parameters.append(data.unpack_real()) # restraint.up2B
|
|
401
|
+
parameters.append(data.unpack_real()) # restraint.kB
|
|
402
|
+
elif i in [
|
|
403
|
+
tpr_setting.F_TABBONDS,
|
|
404
|
+
tpr_setting.F_TABBONDSNC,
|
|
405
|
+
tpr_setting.F_TABANGLES,
|
|
406
|
+
tpr_setting.F_TABDIHS,
|
|
407
|
+
]:
|
|
408
|
+
parameters.append(data.unpack_real()) # tab.kA
|
|
409
|
+
parameters.append(data.unpack_int()) # tab.table
|
|
410
|
+
parameters.append(data.unpack_real()) # tab.kB
|
|
411
|
+
elif i in [tpr_setting.F_CROSS_BOND_BONDS]:
|
|
412
|
+
parameters.append(data.unpack_real()) # cross_bb.r1e
|
|
413
|
+
parameters.append(data.unpack_real()) # cross_bb.r2e
|
|
414
|
+
parameters.append(data.unpack_real()) # cross_bb.krr
|
|
415
|
+
elif i in [tpr_setting.F_CROSS_BOND_ANGLES]:
|
|
416
|
+
parameters.append(data.unpack_real()) # cross_ba.r1e
|
|
417
|
+
parameters.append(data.unpack_real()) # cross_ba.r2e
|
|
418
|
+
parameters.append(data.unpack_real()) # cross_ba.r3e
|
|
419
|
+
parameters.append(data.unpack_real()) # cross_ba.krt
|
|
420
|
+
elif i in [tpr_setting.F_UREY_BRADLEY]:
|
|
421
|
+
parameters.append(data.unpack_real()) # u_b.theta
|
|
422
|
+
parameters.append(data.unpack_real()) # u_b.ktheta
|
|
423
|
+
parameters.append(data.unpack_real()) # u_b.r13
|
|
424
|
+
parameters.append(data.unpack_real()) # u_b.kUB
|
|
425
|
+
if header.fver >= 79:
|
|
426
|
+
parameters.append(data.unpack_real()) # u_b.thetaB
|
|
427
|
+
parameters.append(data.unpack_real()) # u_b.kthetaB
|
|
428
|
+
parameters.append(data.unpack_real()) # u_b.r13B
|
|
429
|
+
parameters.append(data.unpack_real()) # u_b.kUBB
|
|
430
|
+
elif i in [tpr_setting.F_QUARTIC_ANGLES]:
|
|
431
|
+
parameters.append(data.unpack_real()) # qangle.theta
|
|
432
|
+
parameters.append(tpr_utils.ndo_real(data, 5)) # qangle.c
|
|
433
|
+
elif i in [tpr_setting.F_BHAM]:
|
|
434
|
+
parameters.append(data.unpack_real()) # bham.a
|
|
435
|
+
parameters.append(data.unpack_real()) # bham.b
|
|
436
|
+
parameters.append(data.unpack_real()) # bham.c
|
|
437
|
+
elif i in [tpr_setting.F_MORSE]:
|
|
438
|
+
parameters.append(data.unpack_real()) # morse.b0
|
|
439
|
+
parameters.append(data.unpack_real()) # morse.cb
|
|
440
|
+
parameters.append(data.unpack_real()) # morse.beta
|
|
441
|
+
if header.fver >= 79:
|
|
442
|
+
parameters.append(data.unpack_real()) # morse.b0B
|
|
443
|
+
parameters.append(data.unpack_real()) # morse.cbB
|
|
444
|
+
parameters.append(data.unpack_real()) # morse.betaB
|
|
445
|
+
elif i in [tpr_setting.F_CUBICBONDS]:
|
|
446
|
+
parameters.append(data.unpack_real()) # cubic.b0g
|
|
447
|
+
parameters.append(data.unpack_real()) # cubic.kb
|
|
448
|
+
parameters.append(data.unpack_real()) # cubic.kcub
|
|
449
|
+
elif i in [tpr_setting.F_CONNBONDS]:
|
|
450
|
+
pass
|
|
451
|
+
elif i in [tpr_setting.F_POLARIZATION]:
|
|
452
|
+
parameters.append(data.unpack_real()) # polarize.alpha
|
|
453
|
+
elif i in [tpr_setting.F_ANHARM_POL]:
|
|
454
|
+
parameters.append(data.unpack_real()) # anharm_polarize.alpha
|
|
455
|
+
parameters.append(data.unpack_real()) # anharm_polarize.drcut
|
|
456
|
+
parameters.append(data.unpack_real()) # anharm_polarize.khyp
|
|
457
|
+
elif i in [tpr_setting.F_WATER_POL]:
|
|
458
|
+
parameters.append(data.unpack_real()) # wpol.al_x
|
|
459
|
+
parameters.append(data.unpack_real()) # wpol.al_y
|
|
460
|
+
parameters.append(data.unpack_real()) # wpol.al_z
|
|
461
|
+
parameters.append(data.unpack_real()) # wpol.rOH
|
|
462
|
+
parameters.append(data.unpack_real()) # wpol.rHH
|
|
463
|
+
parameters.append(data.unpack_real()) # wpol.rOD
|
|
464
|
+
elif i in [tpr_setting.F_THOLE_POL]:
|
|
465
|
+
parameters.append(data.unpack_real()) # thole.a
|
|
466
|
+
parameters.append(data.unpack_real()) # thole.alpha1
|
|
467
|
+
parameters.append(data.unpack_real()) # thole.alpha2
|
|
468
|
+
parameters.append(data.unpack_real()) # thole.rfac
|
|
469
|
+
|
|
470
|
+
elif i in [tpr_setting.F_LJ]:
|
|
471
|
+
parameters.append(data.unpack_real()) # lj_c6
|
|
472
|
+
parameters.append(data.unpack_real()) # lj_c9
|
|
473
|
+
elif i in [tpr_setting.F_LJ14]:
|
|
474
|
+
parameters.append(data.unpack_real()) # lj14_c6A
|
|
475
|
+
parameters.append(data.unpack_real()) # lj14_c12A
|
|
476
|
+
parameters.append(data.unpack_real()) # lj14_c6B
|
|
477
|
+
parameters.append(data.unpack_real()) # lj14_c12B
|
|
478
|
+
elif i in [tpr_setting.F_LJC14_Q]:
|
|
479
|
+
parameters.append(data.unpack_real()) # ljc14.fqq
|
|
480
|
+
parameters.append(data.unpack_real()) # ljc14.qi
|
|
481
|
+
parameters.append(data.unpack_real()) # ljc14.qj
|
|
482
|
+
parameters.append(data.unpack_real()) # ljc14.c6
|
|
483
|
+
parameters.append(data.unpack_real()) # ljc14.c12
|
|
484
|
+
elif i in [tpr_setting.F_LJC_PAIRS_NB]:
|
|
485
|
+
parameters.append(data.unpack_real()) # ljcnb.qi
|
|
486
|
+
parameters.append(data.unpack_real()) # ljcnb.qj
|
|
487
|
+
parameters.append(data.unpack_real()) # ljcnb.c6
|
|
488
|
+
parameters.append(data.unpack_real()) # ljcnb.c12
|
|
489
|
+
|
|
490
|
+
elif i in [
|
|
491
|
+
tpr_setting.F_PIDIHS,
|
|
492
|
+
tpr_setting.F_ANGRES,
|
|
493
|
+
tpr_setting.F_ANGRESZ,
|
|
494
|
+
tpr_setting.F_PDIHS,
|
|
495
|
+
]:
|
|
496
|
+
parameters.append(data.unpack_real()) # pdihs_phiA
|
|
497
|
+
parameters.append(data.unpack_real()) # pdihs_cpA
|
|
498
|
+
parameters.append(data.unpack_real()) # pdihs_phiB
|
|
499
|
+
parameters.append(data.unpack_real()) # pdihs_cpB
|
|
500
|
+
parameters.append(data.unpack_int()) # pdihs_mult
|
|
501
|
+
|
|
502
|
+
elif i in [tpr_setting.F_RESTRDIHS]:
|
|
503
|
+
parameters.append(data.unpack_real()) # pdihs.phiA
|
|
504
|
+
parameters.append(data.unpack_real()) # pdihs.cpA
|
|
505
|
+
elif i in [tpr_setting.F_DISRES]:
|
|
506
|
+
parameters.append(data.unpack_int()) # disres.label
|
|
507
|
+
parameters.append(data.unpack_int()) # disres.type
|
|
508
|
+
parameters.append(data.unpack_real()) # disres.low
|
|
509
|
+
parameters.append(data.unpack_real()) # disres.up1
|
|
510
|
+
parameters.append(data.unpack_real()) # disres.up2
|
|
511
|
+
parameters.append(data.unpack_real()) # disres.kfac
|
|
512
|
+
|
|
513
|
+
elif i in [tpr_setting.F_ORIRES]:
|
|
514
|
+
parameters.append(data.unpack_int()) # orires.ex
|
|
515
|
+
parameters.append(data.unpack_int()) # orires.label
|
|
516
|
+
parameters.append(data.unpack_int()) # orires.power
|
|
517
|
+
parameters.append(data.unpack_real()) # orires.c
|
|
518
|
+
parameters.append(data.unpack_real()) # orires.obs
|
|
519
|
+
parameters.append(data.unpack_real()) # orires.kfac
|
|
520
|
+
|
|
521
|
+
elif i in [tpr_setting.F_DIHRES]:
|
|
522
|
+
if header.fver < 72:
|
|
523
|
+
parameters.append(data.unpack_int()) # idum
|
|
524
|
+
parameters.append(data.unpack_int()) # idum
|
|
525
|
+
parameters.append(data.unpack_real()) # dihres.phiA
|
|
526
|
+
parameters.append(data.unpack_real()) # dihres.dphiA
|
|
527
|
+
parameters.append(data.unpack_real()) # dihres.kfacA
|
|
528
|
+
if header.fver >= 72:
|
|
529
|
+
parameters.append(data.unpack_real()) # dihres.phiB
|
|
530
|
+
parameters.append(data.unpack_real()) # dihres.dphiB
|
|
531
|
+
parameters.append(data.unpack_real()) # dihres.kfacB
|
|
532
|
+
|
|
533
|
+
elif i in [tpr_setting.F_POSRES]:
|
|
534
|
+
parameters.append(tpr_utils.do_rvec(data)) # posres.pos0A
|
|
535
|
+
parameters.append(tpr_utils.do_rvec(data)) # posres.fcA
|
|
536
|
+
parameters.append(tpr_utils.do_rvec(data)) # posres.pos0B
|
|
537
|
+
parameters.append(tpr_utils.do_rvec(data)) # posres.fcB
|
|
538
|
+
|
|
539
|
+
elif i in [tpr_setting.F_FBPOSRES]:
|
|
540
|
+
parameters.append(data.unpack_int()) # fbposres.geom
|
|
541
|
+
parameters.append(tpr_utils.do_rvec(data)) # fbposres.pos0
|
|
542
|
+
parameters.append(data.unpack_real()) # fbposres.r
|
|
543
|
+
parameters.append(data.unpack_real()) # fbposres.k
|
|
544
|
+
|
|
545
|
+
elif i in [tpr_setting.F_CBTDIHS]:
|
|
546
|
+
parameters.append(
|
|
547
|
+
tpr_utils.ndo_real(data, tpr_setting.NR_CBTDIHS)
|
|
548
|
+
) # cbtdihs.cbtcA
|
|
549
|
+
|
|
550
|
+
elif i in [tpr_setting.F_RBDIHS]:
|
|
551
|
+
parameters.append(
|
|
552
|
+
tpr_utils.ndo_real(data, tpr_setting.NR_RBDIHS)
|
|
553
|
+
) # iparams_rbdihs_rbcA
|
|
554
|
+
parameters.append(
|
|
555
|
+
tpr_utils.ndo_real(data, tpr_setting.NR_RBDIHS)
|
|
556
|
+
) # iparams_rbdihs_rbcB
|
|
557
|
+
|
|
558
|
+
elif i in [tpr_setting.F_FOURDIHS]:
|
|
559
|
+
# Fourier dihedrals
|
|
560
|
+
parameters.append(
|
|
561
|
+
tpr_utils.ndo_real(data, tpr_setting.NR_RBDIHS)
|
|
562
|
+
) # rbdihs.rbcA
|
|
563
|
+
parameters.append(
|
|
564
|
+
tpr_utils.ndo_real(data, tpr_setting.NR_RBDIHS)
|
|
565
|
+
) # rbdihs.rbcB
|
|
566
|
+
|
|
567
|
+
elif i in [tpr_setting.F_CONSTR, tpr_setting.F_CONSTRNC]:
|
|
568
|
+
parameters.append(data.unpack_real()) # dA
|
|
569
|
+
parameters.append(data.unpack_real()) # dB
|
|
570
|
+
|
|
571
|
+
elif i in [tpr_setting.F_SETTLE]:
|
|
572
|
+
parameters.append(data.unpack_real()) # settle.doh
|
|
573
|
+
parameters.append(data.unpack_real()) # settle.dhh
|
|
574
|
+
|
|
575
|
+
elif i in [tpr_setting.F_VSITE1]:
|
|
576
|
+
pass
|
|
577
|
+
|
|
578
|
+
elif i in [tpr_setting.F_VSITE2, tpr_setting.F_VSITE2FD]:
|
|
579
|
+
parameters.append(data.unpack_real()) # vsite.a
|
|
580
|
+
|
|
581
|
+
elif i in [
|
|
582
|
+
tpr_setting.F_VSITE3,
|
|
583
|
+
tpr_setting.F_VSITE3FD,
|
|
584
|
+
tpr_setting.F_VSITE3FAD,
|
|
585
|
+
]:
|
|
586
|
+
parameters.append(data.unpack_real()) # vsite.a
|
|
587
|
+
|
|
588
|
+
elif i in [
|
|
589
|
+
tpr_setting.F_VSITE3OUT,
|
|
590
|
+
tpr_setting.F_VSITE4FD,
|
|
591
|
+
tpr_setting.F_VSITE4FDN,
|
|
592
|
+
]:
|
|
593
|
+
parameters.append(data.unpack_real()) # vsite.a
|
|
594
|
+
parameters.append(data.unpack_real()) # vsite.b
|
|
595
|
+
parameters.append(data.unpack_real()) # vsite.c
|
|
596
|
+
|
|
597
|
+
elif i in [tpr_setting.F_VSITEN]:
|
|
598
|
+
parameters.append(data.unpack_int()) # vsiten.n
|
|
599
|
+
parameters.append(data.unpack_real()) # vsiten.a
|
|
600
|
+
|
|
601
|
+
elif i in [tpr_setting.F_GB12, tpr_setting.F_GB13, tpr_setting.F_GB14]:
|
|
602
|
+
# /* We got rid of some parameters in version 68 */
|
|
603
|
+
if header.fver < 68:
|
|
604
|
+
parameters.append(data.unpack_real()) # rdum
|
|
605
|
+
parameters.append(data.unpack_real()) # rdum
|
|
606
|
+
parameters.append(data.unpack_real()) # rdum
|
|
607
|
+
parameters.append(data.unpack_real()) # rdum
|
|
608
|
+
parameters.append(data.unpack_real()) # gb.sar
|
|
609
|
+
parameters.append(data.unpack_real()) # gb.st
|
|
610
|
+
parameters.append(data.unpack_real()) # gb.pi
|
|
611
|
+
parameters.append(data.unpack_real()) # gb.gbr
|
|
612
|
+
parameters.append(data.unpack_real()) # gb.bmlt
|
|
613
|
+
|
|
614
|
+
elif i in [tpr_setting.F_CMAP]:
|
|
615
|
+
parameters.append(data.unpack_int()) # cmap.cmapA
|
|
616
|
+
parameters.append(data.unpack_int()) # cmap.cmapB
|
|
617
|
+
else:
|
|
618
|
+
raise NotImplementedError(f'unknown functype: {i}')
|
|
619
|
+
interactions.append(
|
|
620
|
+
dict(type=tpr_setting.interaction_types[i][1], parameters=parameters)
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
return interactions
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
class GromacsParser(MDParser):
|
|
627
|
+
def __init__(self):
|
|
628
|
+
self.log_parser = GromacsLogParser()
|
|
629
|
+
self.traj_parser = GromacsMDAnalysisParser()
|
|
630
|
+
self.energy_parser = GromacsEDRParser()
|
|
631
|
+
self.mdp_parser = GromacsMdpParser()
|
|
632
|
+
self.mdp_ext = 'mdp'
|
|
633
|
+
self.mdp_std_filename = 'mdout'
|
|
634
|
+
self.xvg_parser = GromacsXvgParser()
|
|
635
|
+
self.input_parameters = {}
|
|
636
|
+
self._gro_energy_units = ureg.kilojoule / MOL
|
|
637
|
+
self._thermo_ignore_list = ['Time', 'Box-X', 'Box-Y', 'Box-Z']
|
|
638
|
+
self._base_calc_map = {
|
|
639
|
+
'Temperature': ('temperature', ureg.kelvin),
|
|
640
|
+
'Volume': ('volume', ureg.nm**3),
|
|
641
|
+
'Density': ('density', ureg.kilogram / ureg.m**3),
|
|
642
|
+
'Pressure (bar)': ('pressure', ureg.bar),
|
|
643
|
+
'Pressure': ('pressure', ureg.bar),
|
|
644
|
+
'Enthalpy': ('enthalpy', self._gro_energy_units),
|
|
645
|
+
}
|
|
646
|
+
self._energy_map = {
|
|
647
|
+
'Potential': 'potential',
|
|
648
|
+
'Kinetic En.': 'kinetic',
|
|
649
|
+
'Total Energy': 'total',
|
|
650
|
+
'pV': 'pressure_volume_work',
|
|
651
|
+
}
|
|
652
|
+
self._vdw_map = {
|
|
653
|
+
'LJ (SR)': 'short_range',
|
|
654
|
+
'LJ (LR)': 'long_range',
|
|
655
|
+
'Disper. corr.': 'correction',
|
|
656
|
+
}
|
|
657
|
+
self._electrostatic_map = {
|
|
658
|
+
'Coulomb (SR)': 'short_range',
|
|
659
|
+
'Coul. recip.': 'long_range',
|
|
660
|
+
}
|
|
661
|
+
self._energy_keys_contain = [
|
|
662
|
+
'bond',
|
|
663
|
+
'angle',
|
|
664
|
+
'dih.',
|
|
665
|
+
'coul-',
|
|
666
|
+
'coulomb-',
|
|
667
|
+
'lj-',
|
|
668
|
+
'en.',
|
|
669
|
+
]
|
|
670
|
+
super().__init__()
|
|
671
|
+
|
|
672
|
+
def get_pbc(self):
|
|
673
|
+
pbc = self.input_parameters.get('pbc', 'xyz')
|
|
674
|
+
return ['x' in pbc, 'y' in pbc, 'z' in pbc]
|
|
675
|
+
|
|
676
|
+
def get_mdp_file(self):
|
|
677
|
+
"""
|
|
678
|
+
Tries to find the mdp input parameters (ext = mdp) that match the mainfile calculation.
|
|
679
|
+
Priority is as follows:
|
|
680
|
+
1. output mdp file containing both the matching mainfile name and the standard
|
|
681
|
+
gromacs name `mdout`
|
|
682
|
+
2. file containing the standard gromacs name `mdout`
|
|
683
|
+
3. input mdp file matching the mainfile name (as usual)
|
|
684
|
+
4. any `.mdp` file within the directory (as usual)
|
|
685
|
+
"""
|
|
686
|
+
files = [d for d in self._gromacs_files if d.endswith(self.mdp_ext)]
|
|
687
|
+
|
|
688
|
+
if len(files) == 0:
|
|
689
|
+
return ''
|
|
690
|
+
|
|
691
|
+
if len(files) == 1:
|
|
692
|
+
return os.path.join(self._maindir, files[0])
|
|
693
|
+
|
|
694
|
+
for f in files:
|
|
695
|
+
filename = f.rsplit('.', 1)[0]
|
|
696
|
+
if self._basename in filename and self.mdp_std_filename in filename:
|
|
697
|
+
return os.path.join(self._maindir, f)
|
|
698
|
+
|
|
699
|
+
for f in files:
|
|
700
|
+
filename = f.rsplit('.', 1)[0]
|
|
701
|
+
if self.mdp_std_filename in filename:
|
|
702
|
+
return os.path.join(self._maindir, f)
|
|
703
|
+
|
|
704
|
+
return self.get_gromacs_file(self.mdp_ext)
|
|
705
|
+
|
|
706
|
+
def get_gromacs_file(self, ext):
|
|
707
|
+
files = [d for d in self._gromacs_files if d.endswith(ext)]
|
|
708
|
+
|
|
709
|
+
if len(files) == 0:
|
|
710
|
+
return ''
|
|
711
|
+
|
|
712
|
+
if len(files) == 1:
|
|
713
|
+
return os.path.join(self._maindir, files[0])
|
|
714
|
+
|
|
715
|
+
# we assume that the file has the same basename as the log file e.g.
|
|
716
|
+
# out.log would correspond to out.tpr and out.trr and out.edr
|
|
717
|
+
for f in files:
|
|
718
|
+
if f.rsplit('.', 1)[0] == self._basename:
|
|
719
|
+
return os.path.join(self._maindir, f)
|
|
720
|
+
|
|
721
|
+
for f in files:
|
|
722
|
+
if f.rsplit('.', 1)[0].startswith(self._basename):
|
|
723
|
+
return os.path.join(self._maindir, f)
|
|
724
|
+
|
|
725
|
+
# if the files are all named differently, we guess that the one that does not
|
|
726
|
+
# share the same basename would be file we are interested in
|
|
727
|
+
# e.g. in a list of files out.log someout.log out.tpr out.trr another.tpr file.trr
|
|
728
|
+
# we guess that the out.* files belong together and the rest that does not share
|
|
729
|
+
# a basename would be grouped together
|
|
730
|
+
counts = []
|
|
731
|
+
for f in files:
|
|
732
|
+
count = 0
|
|
733
|
+
for reff in self._gromacs_files:
|
|
734
|
+
if f.rsplit('.', 1)[0] == reff.rsplit('.', 1)[0]:
|
|
735
|
+
count += 1
|
|
736
|
+
if count == 1:
|
|
737
|
+
return os.path.join(self._maindir, f)
|
|
738
|
+
counts.append(count)
|
|
739
|
+
|
|
740
|
+
return os.path.join(self._maindir, files[counts.index(min(counts))])
|
|
741
|
+
|
|
742
|
+
def parse_thermodynamic_data(self):
|
|
743
|
+
sec_run = self.archive.run[-1]
|
|
744
|
+
|
|
745
|
+
n_frames = self.traj_parser.get('n_frames')
|
|
746
|
+
|
|
747
|
+
# # TODO read also from ene
|
|
748
|
+
edr_file = self.get_gromacs_file('edr')
|
|
749
|
+
self.energy_parser.mainfile = edr_file
|
|
750
|
+
|
|
751
|
+
# get it from edr file
|
|
752
|
+
if self.energy_parser.keys():
|
|
753
|
+
thermo_data = self.energy_parser
|
|
754
|
+
else:
|
|
755
|
+
# try to get it from log file
|
|
756
|
+
steps = self.input_parameters.get('step', [])
|
|
757
|
+
thermo_data = dict()
|
|
758
|
+
for n, step in enumerate(steps):
|
|
759
|
+
n = int(step.get('step_info', {}).get('Step', n))
|
|
760
|
+
if step.energies is None:
|
|
761
|
+
continue
|
|
762
|
+
keys = step.energies.keys()
|
|
763
|
+
for key in keys:
|
|
764
|
+
thermo_data.setdefault(key, [None] * n_frames)
|
|
765
|
+
thermo_data[key][n] = step.energies.get(key)
|
|
766
|
+
info = step.get('step_info', {})
|
|
767
|
+
thermo_data.setdefault('Time', [None] * n_frames)
|
|
768
|
+
thermo_data['Time'][n] = info.get('Time', None)
|
|
769
|
+
|
|
770
|
+
if not thermo_data:
|
|
771
|
+
# get it from edr file
|
|
772
|
+
thermo_data = self.energy_parser
|
|
773
|
+
|
|
774
|
+
calculation_times = thermo_data.get('Time', [])
|
|
775
|
+
time_step = self.input_parameters.get('dt')
|
|
776
|
+
if time_step is None and len(calculation_times) > 1:
|
|
777
|
+
time_step = calculation_times[1] - calculation_times[0]
|
|
778
|
+
self.thermodynamics_steps = [
|
|
779
|
+
int(time / time_step if time_step else 1) for time in calculation_times
|
|
780
|
+
]
|
|
781
|
+
|
|
782
|
+
for n, step in enumerate(self.thermodynamics_steps):
|
|
783
|
+
data = {
|
|
784
|
+
'step': step,
|
|
785
|
+
'time': calculation_times[n] * ureg.picosecond,
|
|
786
|
+
'method_ref': sec_run.method[-1] if sec_run.method else None,
|
|
787
|
+
'energy': {},
|
|
788
|
+
}
|
|
789
|
+
if step in self._trajectory_steps:
|
|
790
|
+
data['forces'] = dict(
|
|
791
|
+
total=dict(
|
|
792
|
+
value=self.traj_parser.get_forces(
|
|
793
|
+
self._trajectory_steps.index(step)
|
|
794
|
+
)
|
|
795
|
+
)
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
pressure_tensor, virial_tensor = None, None
|
|
799
|
+
for key in thermo_data.keys():
|
|
800
|
+
if (
|
|
801
|
+
key in self._thermo_ignore_list
|
|
802
|
+
or (val := thermo_data.get(key)[n]) is None
|
|
803
|
+
):
|
|
804
|
+
continue
|
|
805
|
+
|
|
806
|
+
# Attributes of BaseCalculation
|
|
807
|
+
if key in self._base_calc_map:
|
|
808
|
+
data[self._base_calc_map[key][0]] = (
|
|
809
|
+
val * self._base_calc_map[key][1]
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
# pressure tensor
|
|
813
|
+
elif match := re.match(r'Pres-([XYZ]{2})', key):
|
|
814
|
+
if pressure_tensor is None:
|
|
815
|
+
pressure_tensor = np.zeros(shape=(3, 3))
|
|
816
|
+
pressure_tensor[tuple('XYZ'.index(n) for n in match.group(1))] = val
|
|
817
|
+
|
|
818
|
+
# virial tensor
|
|
819
|
+
elif match := re.match(r'Vir-([XYZ]{2})', key):
|
|
820
|
+
if virial_tensor is None:
|
|
821
|
+
virial_tensor = np.zeros(shape=(3, 3))
|
|
822
|
+
virial_tensor[tuple('XYZ'.index(n) for n in match.group(1))] = val
|
|
823
|
+
|
|
824
|
+
# well-defined, single Energy quantities
|
|
825
|
+
elif (nomad_key := self._energy_map.get(key)) is not None:
|
|
826
|
+
data['energy'][nomad_key] = dict(value=val * self._gro_energy_units)
|
|
827
|
+
# well-defined, piecewise energy quantities
|
|
828
|
+
elif (nomad_key := self._vdw_map.get(key)) is not None:
|
|
829
|
+
data['energy'].setdefault(
|
|
830
|
+
'van_der_waals', {'value': 0.0 * self._gro_energy_units}
|
|
831
|
+
)
|
|
832
|
+
data['energy']['van_der_waals'][nomad_key] = (
|
|
833
|
+
val * self._gro_energy_units
|
|
834
|
+
)
|
|
835
|
+
data['energy']['van_der_waals']['value'] += (
|
|
836
|
+
val * self._gro_energy_units
|
|
837
|
+
)
|
|
838
|
+
elif (nomad_key := self._electrostatic_map.get(key)) is not None:
|
|
839
|
+
data['energy'].setdefault(
|
|
840
|
+
'electrostatic', {'value': 0.0 * self._gro_energy_units}
|
|
841
|
+
)
|
|
842
|
+
data['energy']['electrostatic'][nomad_key] = (
|
|
843
|
+
val * self._gro_energy_units
|
|
844
|
+
)
|
|
845
|
+
data['energy']['electrostatic']['value'] += (
|
|
846
|
+
val * self._gro_energy_units
|
|
847
|
+
)
|
|
848
|
+
# try to identify other known energy keys to be stored as gromacs-specific
|
|
849
|
+
elif any(
|
|
850
|
+
keyword in key.lower() for keyword in self._energy_keys_contain
|
|
851
|
+
):
|
|
852
|
+
data['energy'].setdefault('x_gromacs_energy_contributions', [])
|
|
853
|
+
data['energy']['x_gromacs_energy_contributions'].append(
|
|
854
|
+
dict(kind=key, value=val * self._gro_energy_units)
|
|
855
|
+
)
|
|
856
|
+
else: # store all other quantities as gromacs-specific under BaseCalculation
|
|
857
|
+
data.setdefault('x_gromacs_thermodynamics_contributions', [])
|
|
858
|
+
data['x_gromacs_thermodynamics_contributions'].append(
|
|
859
|
+
dict(kind=key, value=val)
|
|
860
|
+
)
|
|
861
|
+
|
|
862
|
+
if pressure_tensor is not None:
|
|
863
|
+
data['pressure_tensor'] = pressure_tensor * ureg.bar
|
|
864
|
+
|
|
865
|
+
if virial_tensor is not None:
|
|
866
|
+
data['virial_tensor'] = virial_tensor * (ureg.bar * ureg.nm**3)
|
|
867
|
+
|
|
868
|
+
self.parse_thermodynamics_step(data)
|
|
869
|
+
|
|
870
|
+
def parse_system(self):
|
|
871
|
+
sec_run = self.archive.run[-1]
|
|
872
|
+
|
|
873
|
+
def get_composition(children_names):
|
|
874
|
+
children_count_tup = np.unique(children_names, return_counts=True)
|
|
875
|
+
formula = ''.join(
|
|
876
|
+
[f'{name}({count})' for name, count in zip(*children_count_tup)]
|
|
877
|
+
)
|
|
878
|
+
return formula
|
|
879
|
+
|
|
880
|
+
n_frames = self.traj_parser.get('n_frames', 0)
|
|
881
|
+
traj_sampling_rate = self.input_parameters.get('nstxout', 1)
|
|
882
|
+
self.n_atoms = [self.traj_parser.get_n_atoms(n) for n in range(n_frames)]
|
|
883
|
+
traj_steps = [n * traj_sampling_rate for n in range(n_frames)]
|
|
884
|
+
self.trajectory_steps = traj_steps
|
|
885
|
+
|
|
886
|
+
pbc = self.get_pbc()
|
|
887
|
+
self._system_time_map = {}
|
|
888
|
+
for step in self.trajectory_steps:
|
|
889
|
+
n = traj_steps.index(step)
|
|
890
|
+
positions = self.traj_parser.get_positions(n)
|
|
891
|
+
if positions is None:
|
|
892
|
+
continue
|
|
893
|
+
|
|
894
|
+
bond_list = []
|
|
895
|
+
if n == 0: # TODO add references to the bond list for other steps
|
|
896
|
+
bond_list = get_bond_list_from_model_contributions(
|
|
897
|
+
sec_run, method_index=-1, model_index=-1
|
|
898
|
+
)
|
|
899
|
+
|
|
900
|
+
atom_labels = self.traj_parser.get_atom_labels(n)
|
|
901
|
+
if atom_labels is not None:
|
|
902
|
+
try:
|
|
903
|
+
symbols2numbers(atom_labels)
|
|
904
|
+
except KeyError:
|
|
905
|
+
atom_labels = ['X'] * len(atom_labels)
|
|
906
|
+
|
|
907
|
+
self.parse_trajectory_step(
|
|
908
|
+
{
|
|
909
|
+
'atoms': {
|
|
910
|
+
'n_atoms': self.traj_parser.get_n_atoms(n),
|
|
911
|
+
'periodic': pbc,
|
|
912
|
+
'lattice_vectors': self.traj_parser.get_lattice_vectors(n),
|
|
913
|
+
'labels': atom_labels,
|
|
914
|
+
'positions': positions,
|
|
915
|
+
'velocities': self.traj_parser.get_velocities(n),
|
|
916
|
+
'bond_list': bond_list if bond_list else None,
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
)
|
|
920
|
+
|
|
921
|
+
if not sec_run.system:
|
|
922
|
+
return
|
|
923
|
+
|
|
924
|
+
# parse atomsgroup (segments --> molecules --> residues)
|
|
925
|
+
atoms_info = self.traj_parser._results['atoms_info']
|
|
926
|
+
atoms_moltypes = np.array(atoms_info['moltypes'])
|
|
927
|
+
atoms_molnums = np.array(atoms_info['molnums'])
|
|
928
|
+
atoms_resids = np.array(atoms_info['resids'])
|
|
929
|
+
atoms_elements = np.array(atoms_info['elements'])
|
|
930
|
+
atoms_resnames = np.array(atoms_info['resnames'])
|
|
931
|
+
for segment in self.traj_parser.universe.segments:
|
|
932
|
+
# we only create atomsgroup in the initial system
|
|
933
|
+
sec_segment = AtomsGroup()
|
|
934
|
+
sec_run.system[0].atoms_group.append(sec_segment)
|
|
935
|
+
sec_segment.type = 'molecule_group'
|
|
936
|
+
sec_segment.index = int(segment.segindex)
|
|
937
|
+
sec_segment.atom_indices = segment.atoms.ix
|
|
938
|
+
sec_segment.n_atoms = len(sec_segment.atom_indices)
|
|
939
|
+
sec_segment.is_molecule = False
|
|
940
|
+
|
|
941
|
+
moltypes = np.unique(atoms_moltypes[sec_segment.atom_indices])
|
|
942
|
+
moltypes_count = {}
|
|
943
|
+
for moltype in moltypes:
|
|
944
|
+
atom_indices = np.where(atoms_moltypes == moltype)[0]
|
|
945
|
+
# mol_nums is the molecule identifier for each atom
|
|
946
|
+
mol_nums = atoms_molnums[atom_indices]
|
|
947
|
+
moltypes_count[moltype] = np.unique(mol_nums).shape[0]
|
|
948
|
+
formula = ''.join(
|
|
949
|
+
[f'{moltype}({moltypes_count[moltype]})' for moltype in moltypes_count]
|
|
950
|
+
)
|
|
951
|
+
sec_segment.composition_formula = formula
|
|
952
|
+
sec_segment.label = f'group_{moltypes[0]}'
|
|
953
|
+
|
|
954
|
+
for i_molecule, molecule in enumerate(
|
|
955
|
+
np.unique(atoms_molnums[sec_segment.atom_indices])
|
|
956
|
+
):
|
|
957
|
+
sec_molecule = AtomsGroup()
|
|
958
|
+
sec_segment.atoms_group.append(sec_molecule)
|
|
959
|
+
sec_molecule.index = i_molecule
|
|
960
|
+
sec_molecule.atom_indices = np.where(atoms_molnums == molecule)[0]
|
|
961
|
+
sec_molecule.n_atoms = len(sec_molecule.atom_indices)
|
|
962
|
+
# use first particle to get the moltype
|
|
963
|
+
# not sure why but this value is being cast to int, cast back to str
|
|
964
|
+
sec_molecule.label = str(atoms_moltypes[sec_molecule.atom_indices[0]])
|
|
965
|
+
sec_molecule.type = 'molecule'
|
|
966
|
+
sec_molecule.is_molecule = True
|
|
967
|
+
|
|
968
|
+
mol_resids = np.unique(atoms_resids[sec_molecule.atom_indices])
|
|
969
|
+
n_res = mol_resids.shape[0]
|
|
970
|
+
if n_res == 1:
|
|
971
|
+
elements = atoms_elements[sec_molecule.atom_indices]
|
|
972
|
+
sec_molecule.composition_formula = get_composition(elements)
|
|
973
|
+
else:
|
|
974
|
+
mol_resnames = atoms_resnames[sec_molecule.atom_indices]
|
|
975
|
+
restypes = np.unique(mol_resnames)
|
|
976
|
+
for i_restype, restype in enumerate(restypes):
|
|
977
|
+
sec_monomer_group = AtomsGroup()
|
|
978
|
+
sec_molecule.atoms_group.append(sec_monomer_group)
|
|
979
|
+
restype_indices = np.where(atoms_resnames == restype)[0]
|
|
980
|
+
sec_monomer_group.label = f'group_{restype}'
|
|
981
|
+
sec_monomer_group.type = 'monomer_group'
|
|
982
|
+
sec_monomer_group.index = i_restype
|
|
983
|
+
sec_monomer_group.atom_indices = np.intersect1d(
|
|
984
|
+
restype_indices, sec_molecule.atom_indices
|
|
985
|
+
)
|
|
986
|
+
sec_monomer_group.n_atoms = len(sec_monomer_group.atom_indices)
|
|
987
|
+
sec_monomer_group.is_molecule = False
|
|
988
|
+
|
|
989
|
+
restype_resids = np.unique(
|
|
990
|
+
atoms_resids[sec_monomer_group.atom_indices]
|
|
991
|
+
)
|
|
992
|
+
restype_count = restype_resids.shape[0]
|
|
993
|
+
sec_monomer_group.composition_formula = (
|
|
994
|
+
f'{restype}({restype_count})'
|
|
995
|
+
)
|
|
996
|
+
for i_res, res_id in enumerate(restype_resids):
|
|
997
|
+
sec_residue = AtomsGroup()
|
|
998
|
+
sec_monomer_group.atoms_group.append(sec_residue)
|
|
999
|
+
sec_residue.index = i_res
|
|
1000
|
+
atom_indices = np.where(atoms_resids == res_id)[0]
|
|
1001
|
+
sec_residue.atom_indices = np.intersect1d(
|
|
1002
|
+
atom_indices, sec_monomer_group.atom_indices
|
|
1003
|
+
)
|
|
1004
|
+
sec_residue.n_atoms = len(sec_residue.atom_indices)
|
|
1005
|
+
sec_residue.label = str(restype)
|
|
1006
|
+
sec_residue.type = 'monomer'
|
|
1007
|
+
sec_residue.is_molecule = False
|
|
1008
|
+
elements = atoms_elements[sec_residue.atom_indices]
|
|
1009
|
+
sec_residue.composition_formula = get_composition(elements)
|
|
1010
|
+
|
|
1011
|
+
names = atoms_resnames[sec_molecule.atom_indices]
|
|
1012
|
+
ids = atoms_resids[sec_molecule.atom_indices]
|
|
1013
|
+
# filter for the first instance of each residue, as to not overcount
|
|
1014
|
+
__, ids_count = np.unique(ids, return_counts=True)
|
|
1015
|
+
# get the index of the first atom of each residue
|
|
1016
|
+
ids_firstatom = np.cumsum(ids_count)[:-1]
|
|
1017
|
+
# add the 0th index manually
|
|
1018
|
+
ids_firstatom = np.insert(ids_firstatom, 0, 0)
|
|
1019
|
+
names_firstatom = names[ids_firstatom]
|
|
1020
|
+
sec_molecule.composition_formula = get_composition(names_firstatom)
|
|
1021
|
+
|
|
1022
|
+
def parse_method(self):
|
|
1023
|
+
sec_method = Method()
|
|
1024
|
+
self.archive.run[-1].method.append(sec_method)
|
|
1025
|
+
sec_force_field = ForceField()
|
|
1026
|
+
sec_method.force_field = sec_force_field
|
|
1027
|
+
sec_model = Model()
|
|
1028
|
+
sec_force_field.model.append(sec_model)
|
|
1029
|
+
try:
|
|
1030
|
+
n_atoms = self.traj_parser.get('n_atoms', 0)
|
|
1031
|
+
except Exception:
|
|
1032
|
+
gro_file = self.get_gromacs_file('gro')
|
|
1033
|
+
self.traj_parser.mainfile = gro_file
|
|
1034
|
+
n_atoms = self.traj_parser.get('n_atoms', 0)
|
|
1035
|
+
|
|
1036
|
+
atoms_info = self.traj_parser.get('atoms_info', {})
|
|
1037
|
+
for n in range(n_atoms):
|
|
1038
|
+
sec_atom = AtomParameters()
|
|
1039
|
+
sec_method.atom_parameters.append(sec_atom)
|
|
1040
|
+
sec_atom.charge = atoms_info.get('charges', [None] * (n + 1))[n]
|
|
1041
|
+
sec_atom.mass = atoms_info.get('masses', [None] * (n + 1))[n]
|
|
1042
|
+
sec_atom.label = atoms_info.get('names', [None] * (n + 1))[n]
|
|
1043
|
+
sec_atom.x_gromacs_atom_name = atoms_info.get(
|
|
1044
|
+
'atom_names', [None] * (n + 1)
|
|
1045
|
+
)[n]
|
|
1046
|
+
sec_atom.x_gromacs_atom_resid = atoms_info.get('resids', [None] * (n + 1))[
|
|
1047
|
+
n
|
|
1048
|
+
]
|
|
1049
|
+
sec_atom.x_gromacs_atom_resname = atoms_info.get(
|
|
1050
|
+
'resnames', [None] * (n + 1)
|
|
1051
|
+
)[n]
|
|
1052
|
+
sec_atom.x_gromacs_atom_molnum = atoms_info.get(
|
|
1053
|
+
'molnums', [None] * (n + 1)
|
|
1054
|
+
)[n]
|
|
1055
|
+
sec_atom.x_gromacs_atom_moltype = atoms_info.get(
|
|
1056
|
+
'moltypes', [None] * (n + 1)
|
|
1057
|
+
)[n]
|
|
1058
|
+
|
|
1059
|
+
if n_atoms == 0:
|
|
1060
|
+
self.logger.error('Error parsing interactions.')
|
|
1061
|
+
|
|
1062
|
+
interactions = self.traj_parser.get_interactions()
|
|
1063
|
+
self.parse_interactions(interactions, sec_model)
|
|
1064
|
+
|
|
1065
|
+
input_parameters = self.input_parameters
|
|
1066
|
+
sec_force_calculations = ForceCalculations()
|
|
1067
|
+
sec_force_field.force_calculations = sec_force_calculations
|
|
1068
|
+
sec_neighbor_searching = NeighborSearching()
|
|
1069
|
+
sec_force_calculations.neighbor_searching = sec_neighbor_searching
|
|
1070
|
+
|
|
1071
|
+
nstlist = input_parameters.get('nstlist', None)
|
|
1072
|
+
sec_neighbor_searching.neighbor_update_frequency = (
|
|
1073
|
+
int(nstlist) if nstlist else None
|
|
1074
|
+
)
|
|
1075
|
+
rlist = to_float(input_parameters.get('rlist', None))
|
|
1076
|
+
sec_neighbor_searching.neighbor_update_cutoff = (
|
|
1077
|
+
rlist * ureg.nanometer if rlist else None
|
|
1078
|
+
)
|
|
1079
|
+
rvdw = to_float(input_parameters.get('rvdw', None))
|
|
1080
|
+
sec_force_calculations.vdw_cutoff = rvdw * ureg.nanometer if rvdw else None
|
|
1081
|
+
coulombtype = input_parameters.get('coulombtype', 'no').lower()
|
|
1082
|
+
coulombtype_map = {
|
|
1083
|
+
'cut-off': 'cutoff',
|
|
1084
|
+
'ewald': 'ewald',
|
|
1085
|
+
'pme': 'particle_mesh_ewald',
|
|
1086
|
+
'p3m-ad': 'particle_particle_particle_mesh',
|
|
1087
|
+
'reaction-field': 'reaction_field',
|
|
1088
|
+
'shift': 'cutoff',
|
|
1089
|
+
'switch': 'cutoff',
|
|
1090
|
+
'user': 'cutoff',
|
|
1091
|
+
}
|
|
1092
|
+
value = coulombtype_map.get(
|
|
1093
|
+
coulombtype,
|
|
1094
|
+
[val for key, val in coulombtype_map.items() if key in coulombtype],
|
|
1095
|
+
)
|
|
1096
|
+
value = (
|
|
1097
|
+
value
|
|
1098
|
+
if not isinstance(value, list)
|
|
1099
|
+
else value[0]
|
|
1100
|
+
if len(value) != 0
|
|
1101
|
+
else None
|
|
1102
|
+
)
|
|
1103
|
+
sec_force_calculations.coulomb_type = value
|
|
1104
|
+
rcoulomb = input_parameters.get('rcoulomb', None)
|
|
1105
|
+
sec_force_calculations.coulomb_cutoff = to_float(rcoulomb)
|
|
1106
|
+
|
|
1107
|
+
def get_thermostat_parameters(self, integrator: str = ''):
|
|
1108
|
+
thermostat = self.input_parameters.get('tcoupl', 'no').lower()
|
|
1109
|
+
thermostat_map = {
|
|
1110
|
+
'berendsen': 'berendsen',
|
|
1111
|
+
'v-rescale': 'velocity_rescaling',
|
|
1112
|
+
'nose-hoover': 'nose_hoover',
|
|
1113
|
+
'andersen': 'andersen',
|
|
1114
|
+
}
|
|
1115
|
+
value = thermostat_map.get(
|
|
1116
|
+
thermostat,
|
|
1117
|
+
[val for key, val in thermostat_map.items() if key in thermostat],
|
|
1118
|
+
)
|
|
1119
|
+
value = (
|
|
1120
|
+
value
|
|
1121
|
+
if not isinstance(value, list)
|
|
1122
|
+
else value[0]
|
|
1123
|
+
if len(value) != 0
|
|
1124
|
+
else None
|
|
1125
|
+
)
|
|
1126
|
+
thermostat_parameters = {}
|
|
1127
|
+
thermostat_parameters['thermostat_type'] = value
|
|
1128
|
+
if 'sd' in integrator:
|
|
1129
|
+
thermostat_parameters['thermostat_type'] = 'langevin_goga'
|
|
1130
|
+
if thermostat_parameters['thermostat_type']:
|
|
1131
|
+
reference_temperature = self.input_parameters.get('ref-t', None)
|
|
1132
|
+
if isinstance(reference_temperature, str):
|
|
1133
|
+
reference_temperature = to_float(
|
|
1134
|
+
reference_temperature.split()[0]
|
|
1135
|
+
) # ! simulated annealing protocols not supported
|
|
1136
|
+
reference_temperature *= ureg.kelvin if reference_temperature else None
|
|
1137
|
+
thermostat_parameters['reference_temperature'] = reference_temperature
|
|
1138
|
+
coupling_constant = self.input_parameters.get('tau-t', None)
|
|
1139
|
+
if isinstance(coupling_constant, str):
|
|
1140
|
+
coupling_constant = to_float(
|
|
1141
|
+
coupling_constant.split()[0]
|
|
1142
|
+
) # ! simulated annealing protocols not supported
|
|
1143
|
+
coupling_constant *= ureg.picosecond if coupling_constant else None
|
|
1144
|
+
thermostat_parameters['coupling_constant'] = coupling_constant
|
|
1145
|
+
|
|
1146
|
+
return thermostat_parameters
|
|
1147
|
+
|
|
1148
|
+
def get_barostat_parameters(self):
|
|
1149
|
+
barostat_parameters = {}
|
|
1150
|
+
barostat_map = {
|
|
1151
|
+
'berendsen': 'berendsen',
|
|
1152
|
+
'parrinello-rahman': 'parrinello_rahman',
|
|
1153
|
+
'mttk': 'martyna_tuckerman_tobias_klein',
|
|
1154
|
+
'c-rescale': 'stochastic_cell_rescaling',
|
|
1155
|
+
}
|
|
1156
|
+
barostat = self.input_parameters.get('pcoupl', 'no').lower()
|
|
1157
|
+
value = barostat_map.get(
|
|
1158
|
+
barostat, [val for key, val in barostat_map.items() if key in barostat]
|
|
1159
|
+
)
|
|
1160
|
+
value = (
|
|
1161
|
+
value
|
|
1162
|
+
if not isinstance(value, list)
|
|
1163
|
+
else value[0]
|
|
1164
|
+
if len(value) != 0
|
|
1165
|
+
else None
|
|
1166
|
+
)
|
|
1167
|
+
barostat_parameters['barostat_type'] = value
|
|
1168
|
+
if barostat_parameters['barostat_type']:
|
|
1169
|
+
couplingtype = self.input_parameters.get('pcoupltype', None).lower()
|
|
1170
|
+
couplingtype_map = {
|
|
1171
|
+
'isotropic': 'isotropic',
|
|
1172
|
+
'semiisotropic': 'semi_isotropic',
|
|
1173
|
+
'anisotropic': 'anisotropic',
|
|
1174
|
+
}
|
|
1175
|
+
value = couplingtype_map.get(
|
|
1176
|
+
couplingtype,
|
|
1177
|
+
[val for key, val in couplingtype_map.items() if key in couplingtype],
|
|
1178
|
+
)
|
|
1179
|
+
barostat_parameters['coupling_type'] = (
|
|
1180
|
+
value[0] if isinstance(value, list) else value
|
|
1181
|
+
)
|
|
1182
|
+
taup = to_float(self.input_parameters.get('tau-p', None))
|
|
1183
|
+
barostat_parameters['coupling_constant'] = (
|
|
1184
|
+
np.ones(shape=(3, 3)) * taup * ureg.picosecond if taup else None
|
|
1185
|
+
)
|
|
1186
|
+
refp = self.input_parameters.get('ref-p', None)
|
|
1187
|
+
barostat_parameters['reference_pressure'] = (
|
|
1188
|
+
refp * ureg.bar if refp is not None else None
|
|
1189
|
+
)
|
|
1190
|
+
compressibility = self.input_parameters.get('compressibility', None)
|
|
1191
|
+
barostat_parameters['compressibility'] = (
|
|
1192
|
+
compressibility * (1.0 / ureg.bar)
|
|
1193
|
+
if compressibility is not None
|
|
1194
|
+
else None
|
|
1195
|
+
)
|
|
1196
|
+
return barostat_parameters
|
|
1197
|
+
|
|
1198
|
+
def get_free_energy_calculation_parameters(self):
|
|
1199
|
+
free_energy_parameters = {}
|
|
1200
|
+
free_energy = self.input_parameters.get('free-energy', '')
|
|
1201
|
+
free_energy = free_energy.lower() if free_energy else ''
|
|
1202
|
+
expanded = self.input_parameters.get('expanded', '')
|
|
1203
|
+
expanded = expanded.lower() if expanded else ''
|
|
1204
|
+
delta_lambda = int(self.input_parameters.get('delta-lamda', -1))
|
|
1205
|
+
if free_energy == 'yes' and expanded == 'yes':
|
|
1206
|
+
self.logger.warning(
|
|
1207
|
+
'storage of expanded ensemble simulation data not supported, skipping storage of free energy calculation parameters'
|
|
1208
|
+
)
|
|
1209
|
+
elif free_energy == 'yes' and delta_lambda == 'no':
|
|
1210
|
+
self.logger.warning(
|
|
1211
|
+
'Only fixed state free energy calculation calculations are explicitly supported, skipping storage of free energy calculation parameters.'
|
|
1212
|
+
)
|
|
1213
|
+
elif free_energy == 'yes':
|
|
1214
|
+
free_energy_parameters['type'] = 'alchemical'
|
|
1215
|
+
lambda_key_map = {
|
|
1216
|
+
'fep': 'output',
|
|
1217
|
+
'coul': 'coulomb',
|
|
1218
|
+
'vdw': 'vdw',
|
|
1219
|
+
'bonded': 'bonded',
|
|
1220
|
+
'restraint': 'restraint',
|
|
1221
|
+
'mass': 'mass',
|
|
1222
|
+
'temperature': 'temperature',
|
|
1223
|
+
}
|
|
1224
|
+
lambdas = {
|
|
1225
|
+
key: self.input_parameters.get(f'{key}-lambdas', '')
|
|
1226
|
+
for key in lambda_key_map.keys()
|
|
1227
|
+
}
|
|
1228
|
+
lambdas = {
|
|
1229
|
+
key: [to_float(i) for i in val.split()] for key, val in lambdas.items()
|
|
1230
|
+
}
|
|
1231
|
+
free_energy_parameters['lambdas'] = [
|
|
1232
|
+
{'type': nomad_key, 'value': lambdas[gromacs_key]}
|
|
1233
|
+
for gromacs_key, nomad_key in lambda_key_map.items()
|
|
1234
|
+
if lambdas[gromacs_key]
|
|
1235
|
+
]
|
|
1236
|
+
free_energy_parameters['lambda_index'] = self.input_parameters.get(
|
|
1237
|
+
'init-lambda-state', ''
|
|
1238
|
+
)
|
|
1239
|
+
|
|
1240
|
+
atoms_info = self.traj_parser._results['atoms_info']
|
|
1241
|
+
atoms_moltypes = np.array(atoms_info['moltypes'])
|
|
1242
|
+
couple_moltype = self.input_parameters.get('couple-moltype', '').split()
|
|
1243
|
+
n_atoms = len(atoms_moltypes)
|
|
1244
|
+
indices = []
|
|
1245
|
+
if len(couple_moltype) == 1 and couple_moltype[0].lower() == 'system':
|
|
1246
|
+
indices.extend(range(n_atoms))
|
|
1247
|
+
else:
|
|
1248
|
+
for moltype in couple_moltype:
|
|
1249
|
+
indices.extend(
|
|
1250
|
+
[
|
|
1251
|
+
index
|
|
1252
|
+
for index in range(n_atoms)
|
|
1253
|
+
if atoms_moltypes[index].lower() == moltype
|
|
1254
|
+
]
|
|
1255
|
+
)
|
|
1256
|
+
free_energy_parameters['atom_indices'] = indices
|
|
1257
|
+
|
|
1258
|
+
couple_vdw_map = {'vdw-q': True, 'vdw': True, 'q': False, 'none': False}
|
|
1259
|
+
couple_coloumb_map = {
|
|
1260
|
+
'vdw-q': True,
|
|
1261
|
+
'vdw': False,
|
|
1262
|
+
'q': True,
|
|
1263
|
+
'none': False,
|
|
1264
|
+
}
|
|
1265
|
+
couple_initial = self.input_parameters.get('couple-lambda0', 'none').lower()
|
|
1266
|
+
couple_final = self.input_parameters.get('couple-lambda1', 'vdw-q').lower()
|
|
1267
|
+
|
|
1268
|
+
free_energy_parameters['initial_state_vdw'] = couple_vdw_map[couple_initial]
|
|
1269
|
+
free_energy_parameters['final_state_vdw'] = couple_vdw_map[couple_final]
|
|
1270
|
+
free_energy_parameters['initial_state_coloumb'] = couple_coloumb_map[
|
|
1271
|
+
couple_initial
|
|
1272
|
+
]
|
|
1273
|
+
free_energy_parameters['final_state_coloumb'] = couple_coloumb_map[
|
|
1274
|
+
couple_final
|
|
1275
|
+
]
|
|
1276
|
+
|
|
1277
|
+
couple_intramolecular = self.input_parameters.get(
|
|
1278
|
+
'couple-intramol', 'on'
|
|
1279
|
+
).lower()
|
|
1280
|
+
free_energy_parameters['final_state_bonded'] = True
|
|
1281
|
+
free_energy_parameters['initial_state_bonded'] = (
|
|
1282
|
+
couple_intramolecular != 'yes'
|
|
1283
|
+
)
|
|
1284
|
+
return free_energy_parameters
|
|
1285
|
+
|
|
1286
|
+
def parse_workflow(self):
|
|
1287
|
+
sec_run = self.archive.run[-1]
|
|
1288
|
+
sec_calc = sec_run.get('calculation')
|
|
1289
|
+
input_parameters = self.input_parameters
|
|
1290
|
+
|
|
1291
|
+
workflow = None
|
|
1292
|
+
integrator = input_parameters.get('integrator', 'md').lower()
|
|
1293
|
+
if integrator in ['l-bfgs', 'cg', 'steep']:
|
|
1294
|
+
workflow = GeometryOptimization(
|
|
1295
|
+
method=GeometryOptimizationMethod(),
|
|
1296
|
+
results=GeometryOptimizationResults(),
|
|
1297
|
+
)
|
|
1298
|
+
workflow.method.type = 'atomic'
|
|
1299
|
+
integrator_map = {
|
|
1300
|
+
'steep': 'steepest_descent',
|
|
1301
|
+
'cg': 'conjugant_gradient',
|
|
1302
|
+
'l-bfgs': 'low_memory_broyden_fletcher_goldfarb_shanno',
|
|
1303
|
+
}
|
|
1304
|
+
value = integrator_map.get(
|
|
1305
|
+
integrator,
|
|
1306
|
+
[val for key, val in integrator_map.items() if key in integrator],
|
|
1307
|
+
)
|
|
1308
|
+
value = (
|
|
1309
|
+
value
|
|
1310
|
+
if not isinstance(value, list)
|
|
1311
|
+
else value[0]
|
|
1312
|
+
if len(value) != 0
|
|
1313
|
+
else None
|
|
1314
|
+
)
|
|
1315
|
+
workflow.method.method = value
|
|
1316
|
+
nsteps = input_parameters.get('nsteps', None)
|
|
1317
|
+
workflow.method.optimization_steps_maximum = int(nsteps) if nsteps else None
|
|
1318
|
+
nstenergy = input_parameters.get('nstenergy', None)
|
|
1319
|
+
workflow.method.save_frequency = int(nstenergy) if nstenergy else None
|
|
1320
|
+
|
|
1321
|
+
force_maximum = to_float(input_parameters.get('emtol', None))
|
|
1322
|
+
force_conversion = ureg.convert(
|
|
1323
|
+
1.0, ureg.kilojoule * ureg.avogadro_number / ureg.nanometer, ureg.newton
|
|
1324
|
+
)
|
|
1325
|
+
workflow.method.convergence_tolerance_force_maximum = (
|
|
1326
|
+
force_maximum * force_conversion if force_maximum else None
|
|
1327
|
+
)
|
|
1328
|
+
|
|
1329
|
+
energies = []
|
|
1330
|
+
steps = []
|
|
1331
|
+
for calc in sec_calc:
|
|
1332
|
+
val = calc.get('energy')
|
|
1333
|
+
energy = val.get('potential') if val else None
|
|
1334
|
+
if energy:
|
|
1335
|
+
energies.append(energy.value.magnitude)
|
|
1336
|
+
step = calc.get('step')
|
|
1337
|
+
steps.append(step)
|
|
1338
|
+
workflow.results.energies = energies
|
|
1339
|
+
workflow.results.steps = steps
|
|
1340
|
+
workflow.results.optimization_steps = len(energies) + 1
|
|
1341
|
+
|
|
1342
|
+
final_force_maximum = self.log_parser.get('maximum_force')
|
|
1343
|
+
final_force_maximum = to_float(
|
|
1344
|
+
re.split('=|\n', final_force_maximum)[1]
|
|
1345
|
+
if final_force_maximum
|
|
1346
|
+
else None
|
|
1347
|
+
)
|
|
1348
|
+
workflow.results.final_force_maximum = (
|
|
1349
|
+
final_force_maximum * force_conversion if final_force_maximum else None
|
|
1350
|
+
)
|
|
1351
|
+
self.archive.workflow2 = workflow
|
|
1352
|
+
else:
|
|
1353
|
+
method, results = {}, {}
|
|
1354
|
+
nsteps = input_parameters.get('nsteps', None)
|
|
1355
|
+
method['n_steps'] = int(nsteps) if nsteps else None
|
|
1356
|
+
nstxout = input_parameters.get('nstxout', None)
|
|
1357
|
+
method['coordinate_save_frequency'] = int(nstxout) if nstxout else None
|
|
1358
|
+
nstvout = input_parameters.get('nstvout', None)
|
|
1359
|
+
method['velocity_save_frequency'] = int(nstvout) if nstvout else None
|
|
1360
|
+
nstfout = input_parameters.get('nstfout', None)
|
|
1361
|
+
method['force_save_frequency'] = int(nstfout) if nstfout else None
|
|
1362
|
+
nstenergy = input_parameters.get('nstenergy', None)
|
|
1363
|
+
method['thermodynamics_save_frequency'] = (
|
|
1364
|
+
int(nstenergy) if nstenergy else None
|
|
1365
|
+
)
|
|
1366
|
+
|
|
1367
|
+
integrator_map = {
|
|
1368
|
+
'md': 'leap_frog',
|
|
1369
|
+
'md-vv': 'velocity_verlet',
|
|
1370
|
+
'sd': 'langevin_goga',
|
|
1371
|
+
'bd': 'brownian',
|
|
1372
|
+
}
|
|
1373
|
+
value = integrator_map.get(
|
|
1374
|
+
integrator,
|
|
1375
|
+
[val for key, val in integrator_map.items() if key in integrator],
|
|
1376
|
+
)
|
|
1377
|
+
value = (
|
|
1378
|
+
value
|
|
1379
|
+
if not isinstance(value, list)
|
|
1380
|
+
else value[0]
|
|
1381
|
+
if len(value) != 0
|
|
1382
|
+
else None
|
|
1383
|
+
)
|
|
1384
|
+
method['integrator_type'] = value
|
|
1385
|
+
timestep = to_float(input_parameters.get('dt', None))
|
|
1386
|
+
method['integration_timestep'] = (
|
|
1387
|
+
timestep * ureg.picosecond if timestep else None
|
|
1388
|
+
)
|
|
1389
|
+
|
|
1390
|
+
thermostat_parameters = self.get_thermostat_parameters(integrator)
|
|
1391
|
+
method['thermostat_parameters'] = [thermostat_parameters]
|
|
1392
|
+
barostat_parameters = self.get_barostat_parameters()
|
|
1393
|
+
method['barostat_parameters'] = [barostat_parameters]
|
|
1394
|
+
|
|
1395
|
+
if thermostat_parameters.get('thermostat_type'):
|
|
1396
|
+
method['thermodynamic_ensemble'] = (
|
|
1397
|
+
'NPT' if barostat_parameters.get('barostat_type') else 'NVT'
|
|
1398
|
+
)
|
|
1399
|
+
elif barostat_parameters.get('barostat_type'):
|
|
1400
|
+
method['thermodynamic_ensemble'] = 'NPH'
|
|
1401
|
+
else:
|
|
1402
|
+
method['thermodynamic_ensemble'] = 'NVE'
|
|
1403
|
+
|
|
1404
|
+
params_key = 'free_energy_calculation_parameters'
|
|
1405
|
+
method[params_key] = self.get_free_energy_calculation_parameters()
|
|
1406
|
+
|
|
1407
|
+
self.xvg_parser.mainfile = self.get_gromacs_file('xvg')
|
|
1408
|
+
free_energies = self.xvg_parser.get('results')
|
|
1409
|
+
|
|
1410
|
+
title = free_energies.get('title', '') if free_energies is not None else ''
|
|
1411
|
+
flag_fe = False
|
|
1412
|
+
if (
|
|
1413
|
+
r'dH/d\xl\f{}' in title and r'\xD\f{}H' in title
|
|
1414
|
+
): # TODO incorporate x and y axis labels into the checks
|
|
1415
|
+
flag_fe = True
|
|
1416
|
+
results_key = 'free_energy_calculations'
|
|
1417
|
+
results[results_key] = {}
|
|
1418
|
+
columns = free_energies.get('column_vals')
|
|
1419
|
+
results[results_key]['n_frames'] = len(columns)
|
|
1420
|
+
lambdas = method[params_key].get('lambdas', None)
|
|
1421
|
+
results[results_key]['n_states'] = (
|
|
1422
|
+
len(lambdas[0].get('value', [])) if lambdas is not None else None
|
|
1423
|
+
)
|
|
1424
|
+
results[results_key]['lambda_index'] = method[params_key].get(
|
|
1425
|
+
'lambda_index', None
|
|
1426
|
+
)
|
|
1427
|
+
results[results_key]['value_unit'] = str(self._gro_energy_units.units)
|
|
1428
|
+
xaxis = free_energies.get('xaxis', '').lower()
|
|
1429
|
+
# The expected columns of the xvg file are:
|
|
1430
|
+
# Total Energy
|
|
1431
|
+
# dH/dlambda current lambda
|
|
1432
|
+
# Delta H between each lambda and current lambda (n_lambda columns)
|
|
1433
|
+
# PV Energy
|
|
1434
|
+
if (
|
|
1435
|
+
'time' in xaxis
|
|
1436
|
+
and columns[:, 3:-1].shape[1] == results[results_key]['n_states']
|
|
1437
|
+
):
|
|
1438
|
+
results[results_key]['times'] = columns[:, 0] * ureg.ps
|
|
1439
|
+
columns = columns[:, 1:] * self._gro_energy_units.magnitude
|
|
1440
|
+
else:
|
|
1441
|
+
self.logger.warning(
|
|
1442
|
+
'Unexpected format of xvg file. Not storing free energy calculation results.'
|
|
1443
|
+
)
|
|
1444
|
+
flag_fe = False
|
|
1445
|
+
|
|
1446
|
+
self.parse_md_workflow(dict(method=method, results=results))
|
|
1447
|
+
|
|
1448
|
+
if flag_fe and self.archive.m_context:
|
|
1449
|
+
sec_fe_parameters = (
|
|
1450
|
+
self.archive.workflow2.method.free_energy_calculation_parameters[0]
|
|
1451
|
+
)
|
|
1452
|
+
sec_fe = self.archive.workflow2.results.free_energy_calculations[0]
|
|
1453
|
+
sec_fe.method_ref = sec_fe_parameters
|
|
1454
|
+
sec_fe.value_total_energy_magnitude = columns[:, 0]
|
|
1455
|
+
sec_fe.value_total_energy_derivative_magnitude = columns[:, 1]
|
|
1456
|
+
sec_fe.value_total_energy_differences_magnitude = columns[:, 2:-1]
|
|
1457
|
+
sec_fe.value_PV_energy_magnitude = columns[:, -1]
|
|
1458
|
+
|
|
1459
|
+
def parse_input(self):
|
|
1460
|
+
sec_run = self.archive.run[-1]
|
|
1461
|
+
sec_input_output_files = x_gromacs_section_input_output_files()
|
|
1462
|
+
sec_run.x_gromacs_section_input_output_files = sec_input_output_files
|
|
1463
|
+
|
|
1464
|
+
topology_file = os.path.basename(self.traj_parser.mainfile)
|
|
1465
|
+
if topology_file.endswith('tpr'):
|
|
1466
|
+
sec_input_output_files.x_gromacs_inout_file_topoltpr = topology_file
|
|
1467
|
+
elif topology_file.endswith('gro'):
|
|
1468
|
+
sec_input_output_files.x_gromacs_inout_file_confoutgro = topology_file
|
|
1469
|
+
|
|
1470
|
+
trajectory_file = os.path.basename(self.traj_parser.auxilliary_files[0])
|
|
1471
|
+
sec_input_output_files.x_gromacs_inout_file_trajtrr = trajectory_file
|
|
1472
|
+
|
|
1473
|
+
edr_file = os.path.basename(self.energy_parser.mainfile)
|
|
1474
|
+
sec_input_output_files.x_gromacs_inout_file_eneredr = edr_file
|
|
1475
|
+
|
|
1476
|
+
sec_control_parameters = x_gromacs_section_control_parameters()
|
|
1477
|
+
sec_run.x_gromacs_section_control_parameters = sec_control_parameters
|
|
1478
|
+
input_parameters = self.input_parameters
|
|
1479
|
+
input_parameters.update(self.info.get('header', {}))
|
|
1480
|
+
for key, val in input_parameters.items():
|
|
1481
|
+
key = (
|
|
1482
|
+
'x_gromacs_inout_control_%s'
|
|
1483
|
+
% key.replace('-', '').replace(' ', '_').lower()
|
|
1484
|
+
)
|
|
1485
|
+
quantity_def = sec_control_parameters.m_def.all_quantities.get(key)
|
|
1486
|
+
if quantity_def:
|
|
1487
|
+
try:
|
|
1488
|
+
val = str(val) if not isinstance(val, np.ndarray) else val
|
|
1489
|
+
sec_control_parameters.m_set(quantity_def, val)
|
|
1490
|
+
except Exception:
|
|
1491
|
+
self.logger.error('Error setting metainfo.', data={'key': key})
|
|
1492
|
+
|
|
1493
|
+
def write_to_archive(self):
|
|
1494
|
+
self._maindir = os.path.dirname(self.mainfile)
|
|
1495
|
+
self._gromacs_files = os.listdir(self._maindir)
|
|
1496
|
+
self._basename = os.path.basename(self.mainfile).rsplit('.', 1)[0]
|
|
1497
|
+
self.log_parser.mainfile = self.mainfile
|
|
1498
|
+
self.log_parser.logger = self.logger
|
|
1499
|
+
self.traj_parser.logger = self.logger
|
|
1500
|
+
self.energy_parser.logger = self.logger
|
|
1501
|
+
self._frame_rate = None
|
|
1502
|
+
|
|
1503
|
+
sec_run = Run()
|
|
1504
|
+
self.archive.run.append(sec_run)
|
|
1505
|
+
|
|
1506
|
+
header = self.log_parser.get('header', {})
|
|
1507
|
+
|
|
1508
|
+
sec_run.program = Program(
|
|
1509
|
+
name='GROMACS',
|
|
1510
|
+
version=str(header.get('version', 'unknown')).lstrip('VERSION '),
|
|
1511
|
+
)
|
|
1512
|
+
|
|
1513
|
+
sec_time_run = TimeRun()
|
|
1514
|
+
sec_run.time_run = sec_time_run
|
|
1515
|
+
for key in ['start', 'end']:
|
|
1516
|
+
time = self.log_parser.get('time_%s' % key)
|
|
1517
|
+
if time is None:
|
|
1518
|
+
continue
|
|
1519
|
+
setattr(
|
|
1520
|
+
sec_time_run,
|
|
1521
|
+
'date_%s' % key,
|
|
1522
|
+
datetime.datetime.strptime(time, '%a %b %d %H:%M:%S %Y').timestamp(),
|
|
1523
|
+
)
|
|
1524
|
+
|
|
1525
|
+
host_info = self.log_parser.get('host_info')
|
|
1526
|
+
if host_info is not None:
|
|
1527
|
+
sec_run.x_gromacs_program_execution_host = host_info[0]
|
|
1528
|
+
sec_run.x_gromacs_parallel_task_nr = host_info[1]
|
|
1529
|
+
sec_run.x_gromacs_number_of_tasks = host_info[2]
|
|
1530
|
+
|
|
1531
|
+
# parse the input parameters using log file as default and mdp output or input as supplementary
|
|
1532
|
+
self.input_parameters = {
|
|
1533
|
+
key.replace('_', '-'): val.lower() if isinstance(val, str) else val
|
|
1534
|
+
for key, val in self.log_parser.get('input_parameters', {}).items()
|
|
1535
|
+
}
|
|
1536
|
+
self.mdp_parser.mainfile = self.get_mdp_file()
|
|
1537
|
+
for key, param in self.mdp_parser.get('input_parameters', {}).items():
|
|
1538
|
+
new_key = key.replace('_', '-')
|
|
1539
|
+
if new_key not in self.input_parameters:
|
|
1540
|
+
self.input_parameters[new_key] = (
|
|
1541
|
+
param.lower() if isinstance(param, str) else param
|
|
1542
|
+
)
|
|
1543
|
+
|
|
1544
|
+
topology_file = self.get_gromacs_file('tpr')
|
|
1545
|
+
# I have no idea if output trajectory file can be specified in input
|
|
1546
|
+
trr_file = self.get_gromacs_file('trr')
|
|
1547
|
+
trr_file_nopath = trr_file.rsplit('.', 1)[0]
|
|
1548
|
+
trr_file_nopath = trr_file_nopath.rsplit('/')[-1]
|
|
1549
|
+
xtc_file = self.get_gromacs_file('xtc')
|
|
1550
|
+
xtc_file_nopath = xtc_file.rsplit('.', 1)[0]
|
|
1551
|
+
xtc_file_nopath = xtc_file_nopath.rsplit('/')[-1]
|
|
1552
|
+
if not trr_file_nopath.startswith(self._basename):
|
|
1553
|
+
trajectory_file = (
|
|
1554
|
+
xtc_file if xtc_file_nopath.startswith(self._basename) else trr_file
|
|
1555
|
+
)
|
|
1556
|
+
else:
|
|
1557
|
+
trajectory_file = trr_file
|
|
1558
|
+
|
|
1559
|
+
self.traj_parser.mainfile = topology_file
|
|
1560
|
+
self.traj_parser.auxilliary_files = [trajectory_file]
|
|
1561
|
+
# check to see if the trr file can be read properly (and has positions), otherwise try xtc file instead
|
|
1562
|
+
positions = None
|
|
1563
|
+
if (universe := self.traj_parser.universe) is not None:
|
|
1564
|
+
atoms = getattr(universe, 'atoms', None)
|
|
1565
|
+
positions = getattr(atoms, 'positions', None)
|
|
1566
|
+
if positions is None:
|
|
1567
|
+
self.traj_parser.auxilliary_files = [xtc_file] if xtc_file else [trr_file]
|
|
1568
|
+
|
|
1569
|
+
self.parse_method()
|
|
1570
|
+
|
|
1571
|
+
self.parse_system()
|
|
1572
|
+
|
|
1573
|
+
self.parse_thermodynamic_data()
|
|
1574
|
+
|
|
1575
|
+
self.parse_input()
|
|
1576
|
+
|
|
1577
|
+
self.parse_workflow()
|
|
1578
|
+
|
|
1579
|
+
self.traj_parser.clean()
|
|
1580
|
+
self.traj_parser.close()
|
|
1581
|
+
self.energy_parser.close()
|