asyncmd 0.3.2__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.
- asyncmd/__init__.py +18 -0
- asyncmd/_config.py +26 -0
- asyncmd/_version.py +75 -0
- asyncmd/config.py +203 -0
- asyncmd/gromacs/__init__.py +16 -0
- asyncmd/gromacs/mdconfig.py +351 -0
- asyncmd/gromacs/mdengine.py +1127 -0
- asyncmd/gromacs/utils.py +197 -0
- asyncmd/mdconfig.py +440 -0
- asyncmd/mdengine.py +100 -0
- asyncmd/slurm.py +1199 -0
- asyncmd/tools.py +86 -0
- asyncmd/trajectory/__init__.py +25 -0
- asyncmd/trajectory/convert.py +577 -0
- asyncmd/trajectory/functionwrapper.py +556 -0
- asyncmd/trajectory/propagate.py +937 -0
- asyncmd/trajectory/trajectory.py +1103 -0
- asyncmd/utils.py +148 -0
- asyncmd-0.3.2.dist-info/LICENSE +232 -0
- asyncmd-0.3.2.dist-info/METADATA +179 -0
- asyncmd-0.3.2.dist-info/RECORD +23 -0
- asyncmd-0.3.2.dist-info/WHEEL +5 -0
- asyncmd-0.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,351 @@
|
|
1
|
+
# This file is part of asyncmd.
|
2
|
+
#
|
3
|
+
# asyncmd is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# asyncmd is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with asyncmd. If not, see <https://www.gnu.org/licenses/>.
|
15
|
+
import shlex
|
16
|
+
import logging
|
17
|
+
from ..mdconfig import LineBasedMDConfig
|
18
|
+
|
19
|
+
logger = logging.getLogger(__name__)
|
20
|
+
|
21
|
+
|
22
|
+
class MDP(LineBasedMDConfig):
|
23
|
+
"""
|
24
|
+
Parse, modify and write gromacs .mdp files.
|
25
|
+
|
26
|
+
Make all options set in a given mdp file available via a dictionary of
|
27
|
+
option, list of values pairs. Includes automatic types for known options
|
28
|
+
and keeps track if any options have been changed compared to the original
|
29
|
+
file.
|
30
|
+
|
31
|
+
Parameters
|
32
|
+
----------
|
33
|
+
original_file : str
|
34
|
+
absolute or relative path to original config file to parse
|
35
|
+
|
36
|
+
Methods
|
37
|
+
-------
|
38
|
+
write(outfile)
|
39
|
+
write the current (modified) configuration state to a given file
|
40
|
+
parse()
|
41
|
+
read the current original_file and update own state with it
|
42
|
+
"""
|
43
|
+
|
44
|
+
_KEY_VALUE_SEPARATOR = " = "
|
45
|
+
_INTER_VALUE_CHAR = " "
|
46
|
+
# MDP param types, sorted into groups/by headings as in the gromacs manual
|
47
|
+
# https://manual.gromacs.org/documentation/current/user-guide/mdp-options.html
|
48
|
+
_FLOAT_PARAMS = []
|
49
|
+
_FLOAT_SINGLETON_PARAMS = []
|
50
|
+
_INT_PARAMS = []
|
51
|
+
_INT_SINGLETON_PARAMS = []
|
52
|
+
_STR_SINGLETON_PARAMS = []
|
53
|
+
# Run control
|
54
|
+
_FLOAT_SINGLETON_PARAMS += ["tinit", "dt"]
|
55
|
+
_INT_SINGLETON_PARAMS += ["nsteps", "init-step", "simulation-part",
|
56
|
+
"nstcomm"]
|
57
|
+
_STR_SINGLETON_PARAMS += ["integrator", "comm-mode"]
|
58
|
+
# Langevin dynamics
|
59
|
+
_FLOAT_SINGLETON_PARAMS += ["bd-fric"]
|
60
|
+
_INT_SINGLETON_PARAMS += ["ld-seed"]
|
61
|
+
# Energy minimization
|
62
|
+
_FLOAT_SINGLETON_PARAMS += ["emtol", "emstep"]
|
63
|
+
_INT_SINGLETON_PARAMS += ["nstcgsteep", "nbfgscorr"]
|
64
|
+
# Shell Molecular Dynamics
|
65
|
+
_FLOAT_SINGLETON_PARAMS += ["fcstep"]
|
66
|
+
_INT_SINGLETON_PARAMS += ["niter"]
|
67
|
+
# Test particle insertion
|
68
|
+
_FLOAT_SINGLETON_PARAMS += ["rtpi"]
|
69
|
+
# Output control
|
70
|
+
# NOTE: 'nstxtcout' and 'xtc-precision' are deprecated since GMX v5.0
|
71
|
+
_FLOAT_SINGLETON_PARAMS += ["compressed-x-precision", "xtc-precision"]
|
72
|
+
_INT_SINGLETON_PARAMS += ["nstxout", "nstvout", "nstfout", "nstlog",
|
73
|
+
"nstcalcenergy", "nstenergy",
|
74
|
+
"nstxout-compressed", "nstxtcout"]
|
75
|
+
# Neighbor searching
|
76
|
+
# NOTE: 'rlistlong' and 'nstcalclr' are used with group cutoff scheme,
|
77
|
+
# i.e. deprecated since GMX v5.0
|
78
|
+
_FLOAT_SINGLETON_PARAMS += ["verlet-buffer-tolerance", "rlist",
|
79
|
+
"rlistlong"]
|
80
|
+
_INT_SINGLETON_PARAMS += ["nstlist", "nstcalclr"]
|
81
|
+
_STR_SINGLETON_PARAMS += ["cutoff-scheme", "ns-type", "pbc",
|
82
|
+
"periodic-molecules"]
|
83
|
+
# Electrostatics
|
84
|
+
_FLOAT_SINGLETON_PARAMS += ["rcoulomb-switch", "rcoulomb", "epsilon-r",
|
85
|
+
"epsilon-rf"]
|
86
|
+
_STR_SINGLETON_PARAMS += ["coulombtype", "coulomb-modifier"]
|
87
|
+
# Van der Waals
|
88
|
+
_FLOAT_SINGLETON_PARAMS += ["rvdw-switch", "rvdw"]
|
89
|
+
_STR_SINGLETON_PARAMS += ["vdwtype", "vdw-modifier", "DispCorr"]
|
90
|
+
# Ewald
|
91
|
+
_FLOAT_SINGLETON_PARAMS += ["fourierspacing", "ewald-rtol",
|
92
|
+
"ewald-rtol-lj"]
|
93
|
+
_INT_SINGLETON_PARAMS += ["fourier-nx", "fourier-ny", "fourier-nz",
|
94
|
+
"pme-order"]
|
95
|
+
_STR_SINGLETON_PARAMS += ["lj-pme-comb-rule", "ewald-geometry"]
|
96
|
+
# Temperature coupling
|
97
|
+
_FLOAT_PARAMS += ["tau-t", "ref-t"]
|
98
|
+
_INT_SINGLETON_PARAMS += ["nsttcouple", "nh-chain-length"]
|
99
|
+
_STR_SINGLETON_PARAMS += ["tcoupl", "Tcoupl"] # GMX accepts both versions
|
100
|
+
# Pressure coupling
|
101
|
+
_FLOAT_SINGLETON_PARAMS += ["tau-p"]
|
102
|
+
_FLOAT_PARAMS += ["compressibility", "ref-p"]
|
103
|
+
_INT_SINGLETON_PARAMS += ["nstpcouple"]
|
104
|
+
_STR_SINGLETON_PARAMS += ["pcoupl", "Pcoupl", # GMX accepts both versions
|
105
|
+
"pcoupltype", "refcoord-scaling"]
|
106
|
+
# Simulated annealing
|
107
|
+
_FLOAT_PARAMS += ["annealing-time", "annealing-temp"]
|
108
|
+
_INT_PARAMS += ["annealing-npoints"]
|
109
|
+
# Velocity generation
|
110
|
+
_FLOAT_SINGLETON_PARAMS += ["gen-temp"]
|
111
|
+
_INT_SINGLETON_PARAMS += ["gen-seed"]
|
112
|
+
_STR_SINGLETON_PARAMS += ["gen-vel"]
|
113
|
+
# Bonds
|
114
|
+
_FLOAT_SINGLETON_PARAMS += ["shake-tol", "lincs-warnangle"]
|
115
|
+
_INT_SINGLETON_PARAMS += ["lincs-order", "lincs-iter"]
|
116
|
+
_STR_SINGLETON_PARAMS += ["constraints", "constraint-algorithm",
|
117
|
+
# the next two are referencing the same option
|
118
|
+
"continuation", "unconstrained-start",
|
119
|
+
"morse"]
|
120
|
+
# Walls
|
121
|
+
_INT_SINGLETON_PARAMS += ["nwall"]
|
122
|
+
_STR_SINGLETON_PARAMS += ["wall-atomtype", "wall-type"]
|
123
|
+
_FLOAT_SINGLETON_PARAMS += ["wall-r-linpot", "wall-density",
|
124
|
+
"wall-ewald-zfac"]
|
125
|
+
# COM Pulling
|
126
|
+
_STR_SINGLETON_PARAMS += ["pull", "pull-print-com", "pull-print-ref-value",
|
127
|
+
"pull-print-components",
|
128
|
+
"pull-pbc-ref-prev-step-com",
|
129
|
+
"pull-xout-average", "pull-fout-average"]
|
130
|
+
_FLOAT_SINGLETON_PARAMS += ["pull-cylinder-r", "pull-constr-tol"]
|
131
|
+
_INT_SINGLETON_PARAMS += ["pull-nstxout", "pull-nstfout", "pull-ngroups",
|
132
|
+
"pull-ncoords"]
|
133
|
+
# Note: gromacs has a maximum of 256 groups, see e.g.
|
134
|
+
# https://manual.gromacs.org/current/reference-manual/algorithms/group-concept.html
|
135
|
+
# I (hejung) did not find a maximum for the number of pull coordinates,
|
136
|
+
# but we go with 512 here for now (assuming at most two coords per group)
|
137
|
+
_STR_SINGLETON_PARAMS += (
|
138
|
+
[f"pull-group{n}-name" for n in range(1, 257)]
|
139
|
+
+ [f"pull-coord{n}-type" for n in range(1, 513)]
|
140
|
+
+ [f"pull-coord{n}-potential-provider" for n in range(1, 513)]
|
141
|
+
+ [f"pull-coord{n}-geometry" for n in range(1, 513)]
|
142
|
+
+ [f" pull-coord{n}-start" for n in range(1, 513)]
|
143
|
+
)
|
144
|
+
_FLOAT_SINGLETON_PARAMS += (
|
145
|
+
[f"pull-coord{n}-init" for n in range(1, 513)]
|
146
|
+
+ [f"pull-coord{n}-rate" for n in range(1, 513)]
|
147
|
+
+ [f"pull-coord{n}-k" for n in range(1, 513)]
|
148
|
+
+ [f"pull-coord{n}-kB" for n in range(1, 513)]
|
149
|
+
)
|
150
|
+
_FLOAT_PARAMS += (
|
151
|
+
[f"pull-group{n}-weights" for n in range(1, 257)]
|
152
|
+
+ [f"pull-coord{n}-origin" for n in range(1, 513)]
|
153
|
+
+ [f"pull-coord{n}-vec" for n in range(1, 513)]
|
154
|
+
)
|
155
|
+
_INT_SINGLETON_PARAMS += [f"pull-group{n}-pbcatom" for n in range(1, 257)]
|
156
|
+
_INT_PARAMS += [f"pull-coord{n}-groups" for n in range(1, 513)]
|
157
|
+
# AWH adaptive biasing
|
158
|
+
# Note we assume a maximum number of 20 awh coordinates, each consisting of
|
159
|
+
# a maximum of 4 (pull coordinate) dimensions
|
160
|
+
_STR_SINGLETON_PARAMS += (
|
161
|
+
["awh", "awh-potential", "awh-share-multisim"]
|
162
|
+
+ [f"awh{n}-growth" for n in range(1, 21)]
|
163
|
+
+ [f"awh{n}-equilibrate-histogram" for n in range(1, 21)]
|
164
|
+
+ [f"awh{n}-target" for n in range(1, 21)]
|
165
|
+
+ [f"awh{n}-user-data" for n in range(1, 21)]
|
166
|
+
+ [f"awh{n}-dim{d}-coord-provider"
|
167
|
+
for n in range(1, 21) for d in range(1, 5)]
|
168
|
+
)
|
169
|
+
_INT_SINGLETON_PARAMS += (
|
170
|
+
["awh-seed", "awh-nstout", "awh-nstsample", "awh-nsamples-update",
|
171
|
+
"awh-nbias"]
|
172
|
+
+ [f"awh{n}-share-group" for n in range(1, 21)]
|
173
|
+
+ [f"awh{n}-ndim" for n in range(1, 21)]
|
174
|
+
+ [f"awh{n}-dim{d}-coord-index"
|
175
|
+
for n in range(1, 21) for d in range(1, 5)]
|
176
|
+
)
|
177
|
+
_FLOAT_SINGLETON_PARAMS += (
|
178
|
+
[f"awh{n}-error-init" for n in range(1, 21)]
|
179
|
+
+ [f"awh{n}-target-beta-scaling" for n in range(1, 21)]
|
180
|
+
+ [f"awh{n}-target-cutoff" for n in range(1, 21)]
|
181
|
+
+ [f"awh{n}-dim{d}-force-constant"
|
182
|
+
for n in range(1, 21) for d in range(1, 5)]
|
183
|
+
+ [f"awh{n}-dim{d}-start"
|
184
|
+
for n in range(1, 21) for d in range(1, 5)]
|
185
|
+
+ [f"awh{n}-dim{d}-end"
|
186
|
+
for n in range(1, 21) for d in range(1, 5)]
|
187
|
+
+ [f"awh{n}-dim{d}-period"
|
188
|
+
for n in range(1, 21) for d in range(1, 5)]
|
189
|
+
+ [f"awh{n}-dim{d}-diffusion"
|
190
|
+
for n in range(1, 21) for d in range(1, 5)]
|
191
|
+
+ [f"awh{n}-dim{d}-cover-diameter"
|
192
|
+
for n in range(1, 21) for d in range(1, 5)]
|
193
|
+
)
|
194
|
+
# Enforced rotation
|
195
|
+
# Note: rotation groups are zero indexed, we assume a maximum of 30
|
196
|
+
_STR_SINGLETON_PARAMS += (["rotation"]
|
197
|
+
+ [f"rot-group{n}" for n in range(30)]
|
198
|
+
+ [f"rot-type{n}" for n in range(30)]
|
199
|
+
+ [f"rot-massw{n}" for n in range(30)]
|
200
|
+
+ [f"rot-fit-method{n}" for n in range(30)]
|
201
|
+
)
|
202
|
+
_INT_SINGLETON_PARAMS += ["rot-ngroups", "rot-nstrout", "rot-nstsout"]
|
203
|
+
_FLOAT_SINGLETON_PARAMS += ([f"rot-rate{n}" for n in range(30)]
|
204
|
+
+ [f"rot-k{n}" for n in range(30)]
|
205
|
+
+ [f"rot-slab-dist{n}" for n in range(30)]
|
206
|
+
+ [f"rot-min-gauss{n}" for n in range(30)]
|
207
|
+
+ [f"rot-eps{n}" for n in range(30)]
|
208
|
+
+ [f"rot-potfit-step{n}" for n in range(30)]
|
209
|
+
)
|
210
|
+
_FLOAT_PARAMS += ([f"rot-vec{n}" for n in range(30)]
|
211
|
+
+ [f"rot-pivot{n}" for n in range(30)]
|
212
|
+
)
|
213
|
+
# NMR refinement
|
214
|
+
_STR_SINGLETON_PARAMS += ["disre", "disre-weighting", "disre-mixed",
|
215
|
+
"orire", "orire-fitgrp"]
|
216
|
+
_FLOAT_SINGLETON_PARAMS += ["disre-fc", "disre-tau", "orire-fc",
|
217
|
+
"orire-tau"]
|
218
|
+
_INT_SINGLETON_PARAMS += ["nstdisreout", "nstorireout"]
|
219
|
+
# Free energy calculations
|
220
|
+
_STR_SINGLETON_PARAMS += ["free-energy", "expanded", "sc-coul",
|
221
|
+
"couple-moltype", "couple-lambda0",
|
222
|
+
"couple-lambda1", "couple-intramol",
|
223
|
+
"dhdl-derivatives", "dhdl-print-energy",
|
224
|
+
"separate-dhdl-file"]
|
225
|
+
_FLOAT_SINGLETON_PARAMS += ["init-lambda", "delta-lambda", "sc-alpha",
|
226
|
+
"sc-sigma", "dh-hist-spacing"]
|
227
|
+
_INT_SINGLETON_PARAMS += ["init-lambda-state", "calc-lambda-neighbors",
|
228
|
+
"sc-r-power", "sc-power", "nstdhdl",
|
229
|
+
"dh-hist-size"]
|
230
|
+
_FLOAT_PARAMS += ["fep-lambdas", "coul-lambdas", "vdw-lambdas",
|
231
|
+
"bonded-lambdas", "restraint-lambdas", "mass-lambdas",
|
232
|
+
"temperature-lambdas"]
|
233
|
+
# Expanded Ensemble calculations
|
234
|
+
_INT_SINGLETON_PARAMS += ["nstexpanded", "lmc-seed", "lmc-repeats",
|
235
|
+
"lmc-gibbsdelta", "lmc-forced-nstart",
|
236
|
+
"nst-transition-matrix", "mininum-var-min"]
|
237
|
+
_STR_SINGLETON_PARAMS += ["lmc-stats", "lmc-mc-move", "wl-oneovert",
|
238
|
+
"symmetrized-transition-matrix",
|
239
|
+
"lmc-weights-equil", "simulated-tempering",
|
240
|
+
"simulated-tempering-scaling"]
|
241
|
+
_FLOAT_SINGLETON_PARAMS += ["mc-temperature", "wl-ratio", "wl-scale",
|
242
|
+
"init-wl-delta", "sim-temp-low",
|
243
|
+
"sim-temp-high"]
|
244
|
+
_FLOAT_PARAMS += ["init-lambda-weights"]
|
245
|
+
# Non-equilibrium MD
|
246
|
+
_FLOAT_SINGLETON_PARAMS += ["accelerate", "cos-acceleration"]
|
247
|
+
_FLOAT_PARAMS += ["deform"]
|
248
|
+
# Electric fields
|
249
|
+
_FLOAT_PARAMS += ["electric-field-x", "electric-field-y",
|
250
|
+
"electric-field-z"]
|
251
|
+
# Mixed quantum/classical molecular dynamics
|
252
|
+
_STR_SINGLETON_PARAMS += ["QMMM", "QMMMscheme", "QMmethod", "QMbasis",
|
253
|
+
"SH"]
|
254
|
+
_INT_SINGLETON_PARAMS += ["QMcharge", "QMmult", "CASorbitals",
|
255
|
+
"CASelectrons"]
|
256
|
+
# Implicit solvent
|
257
|
+
_STR_SINGLETON_PARAMS += ["implicit-solvent", "gb-algorithm",
|
258
|
+
"sa-algorithm"]
|
259
|
+
_INT_SINGLETON_PARAMS += ["nstgbradii"]
|
260
|
+
_FLOAT_SINGLETON_PARAMS += ["rgbradii", "gb-epsilon-solvent",
|
261
|
+
"gb-saltconc", "gb-obc-alpha", "gb-obc-beta",
|
262
|
+
"gb-obc-gamma", "gb-dielectric-offset",
|
263
|
+
"sa-surface-tension"]
|
264
|
+
# Computational Electrophysiology
|
265
|
+
# Note: we assume a maximum of 10 controlled ion types
|
266
|
+
_STR_SINGLETON_PARAMS += (["swapcoords", "split-group0", "split-group1",
|
267
|
+
"massw-split0", "massw-split1", "solvent-group"]
|
268
|
+
+ [f"iontype{n}-name" for n in range(10)]
|
269
|
+
)
|
270
|
+
_INT_SINGLETON_PARAMS += (["swap-frequency", "coupl-steps", "iontypes",
|
271
|
+
"threshold"]
|
272
|
+
+ [f"iontype{n}-in-A" for n in range(10)]
|
273
|
+
+ [f"iontype{n}-in-B" for n in range(10)]
|
274
|
+
)
|
275
|
+
_FLOAT_SINGLETON_PARAMS += ["bulk-offsetA", "bulk-offsetB", "cyl0-r",
|
276
|
+
"cyl0-up", "cyl0-down", "cyl1-r", "cyl1-up",
|
277
|
+
"cyl1-down"]
|
278
|
+
# User defined thingies
|
279
|
+
_INT_SINGLETON_PARAMS += [f"userint{n}" for n in range(1, 5)]
|
280
|
+
_FLOAT_SINGLETON_PARAMS += [f"userreal{n}" for n in range(1, 5)]
|
281
|
+
|
282
|
+
def _parse_line(self, line):
|
283
|
+
# NOTE: we need to do this so complicated, because gmx accepts
|
284
|
+
# "key=value" i.e. without spaces, so we can not use shlex.shlex
|
285
|
+
# for separating the key and value reliably although this will be
|
286
|
+
# a corner case as most mdp files have "key = value" with spaces
|
287
|
+
# split only at first equal sign
|
288
|
+
splits_at_equal = line.split("=", maxsplit=1)
|
289
|
+
# split at first comment sign
|
290
|
+
splits_at_comment = line.split(";", maxsplit=1)
|
291
|
+
# now we have multiple options:
|
292
|
+
# 1. split only at '=' and not at ';' -> key=value line without comment
|
293
|
+
# 2. split only at ';' and not at '=' -> (probably) a comment line,
|
294
|
+
# at least if the comment is the
|
295
|
+
# first char, otherwise we need
|
296
|
+
# an equal sign to be valid (?)
|
297
|
+
# 3. split at ';' and at '=' -> need to find out if the comment is
|
298
|
+
# before or after the equal sign
|
299
|
+
# 4. no splits at '=' and no splits at ';' -> weired line, probably
|
300
|
+
# not a valid line(?)
|
301
|
+
if splits_at_comment[0] == "":
|
302
|
+
# option 2 (and 3 if the comment is before the equal sign)
|
303
|
+
# comment sign is the first letter, so the whole line is
|
304
|
+
# (most probably) a comment line
|
305
|
+
logger.debug(f"mdp line parsed as comment: {line}")
|
306
|
+
return {}
|
307
|
+
if ((len(splits_at_equal) == 2 and len(splits_at_comment) == 1) # option 1
|
308
|
+
# or option 3 with equal sign before comment sign
|
309
|
+
or ((len(splits_at_equal) == 2 and len(splits_at_comment) == 2)
|
310
|
+
and (len(splits_at_comment[0]) > len(splits_at_equal[0])))):
|
311
|
+
key = splits_at_equal[0].strip() # strip of the white space
|
312
|
+
# make sure the key is a single word, i.e. contains no spaces
|
313
|
+
# if it is not we will raise the error below
|
314
|
+
if key.split()[0] == key:
|
315
|
+
value_unparsed = splits_at_equal[1]
|
316
|
+
parser = shlex.shlex(value_unparsed,
|
317
|
+
posix=True, punctuation_chars=True)
|
318
|
+
parser.commenters = ";"
|
319
|
+
# puncutation_chars=True adds "~-./*?=" to wordchars
|
320
|
+
# such that we do not split floats and file paths and similar
|
321
|
+
tokens = list(parser)
|
322
|
+
# gromacs mdp can have 0-N tokens/values to the RHS of the '='
|
323
|
+
if len(tokens) == 0:
|
324
|
+
# line with empty options, e.g. 'define = '
|
325
|
+
return {self._key_char_replace(key): []}
|
326
|
+
# lines with content, we always return a list (and let our
|
327
|
+
# type_dispatch sort out the singleton options and the typing)
|
328
|
+
return {self._key_char_replace(key): tokens}
|
329
|
+
# if we end up here we did not know how to parse properly, e.g.
|
330
|
+
# option 4 and option 3 with comment before equal but not at the
|
331
|
+
# first position of the line (i.e. not a full comment line)
|
332
|
+
# so no idea what happend here: best to let the user have a look :)
|
333
|
+
raise ValueError(f"Could not parse the following mdp line: {line}")
|
334
|
+
|
335
|
+
def _key_char_replace(self, key):
|
336
|
+
# make it possible to use CHARMM-GUI generated mdp-files, because
|
337
|
+
# CHARMM-GUI uses "_" instead of "-" in the option names,
|
338
|
+
# which seems to be an undocumented gromacs feature,
|
339
|
+
# i.e. gromacs reads these mdp-files without complaints :)
|
340
|
+
# we will however stick with "-" all the time to make sure every option
|
341
|
+
# exists only once, i.e. we convert all keys to use "-" instead of "_"
|
342
|
+
return key.replace("_", "-")
|
343
|
+
|
344
|
+
def __getitem__(self, key):
|
345
|
+
return super().__getitem__(self._key_char_replace(key))
|
346
|
+
|
347
|
+
def __setitem__(self, key, value):
|
348
|
+
return super().__setitem__(self._key_char_replace(key), value)
|
349
|
+
|
350
|
+
def __delitem__(self, key):
|
351
|
+
return super().__delitem__(self._key_char_replace(key))
|