packmol-memgen-minimal 1.1.16__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.
- packmol_memgen/__init__.py +2 -0
- packmol_memgen/__version__.py +34 -0
- packmol_memgen/data/LICENSE.Apache-2.0 +201 -0
- packmol_memgen/data/extra_solvents.lib +789 -0
- packmol_memgen/data/frcmod.lipid_ext +97 -0
- packmol_memgen/data/frcmod.solvents +129 -0
- packmol_memgen/data/insane_lipids.txt +138 -0
- packmol_memgen/data/insane_solvents.txt +45 -0
- packmol_memgen/data/leaprc.extra_solvents +42 -0
- packmol_memgen/data/leaprc.lipid_ext +48 -0
- packmol_memgen/data/lipid_ext.lib +12312 -0
- packmol_memgen/data/martini_v3.0.0.itp +356605 -0
- packmol_memgen/data/memgen.parm +4082 -0
- packmol_memgen/data/pdbs.tar.gz +0 -0
- packmol_memgen/data/solvent.parm +14 -0
- packmol_memgen/example/example.sh +31 -0
- packmol_memgen/lib/__init__.py +0 -0
- packmol_memgen/lib/amber.py +77 -0
- packmol_memgen/lib/charmmlipid2amber/__init__.py +0 -0
- packmol_memgen/lib/charmmlipid2amber/charmmlipid2amber.csv +7164 -0
- packmol_memgen/lib/charmmlipid2amber/charmmlipid2amber.py +225 -0
- packmol_memgen/lib/pdbremix/LICENSE +21 -0
- packmol_memgen/lib/pdbremix/__init__.py +0 -0
- packmol_memgen/lib/pdbremix/_version.py +1 -0
- packmol_memgen/lib/pdbremix/amber.py +1103 -0
- packmol_memgen/lib/pdbremix/asa.py +227 -0
- packmol_memgen/lib/pdbremix/data/aminoacid.pdb +334 -0
- packmol_memgen/lib/pdbremix/data/binaries.json +26 -0
- packmol_memgen/lib/pdbremix/data/charmm22.parameter +2250 -0
- packmol_memgen/lib/pdbremix/data/charmm22.topology +1635 -0
- packmol_memgen/lib/pdbremix/data/color_b.py +682 -0
- packmol_memgen/lib/pdbremix/data/hin.lib +130 -0
- packmol_memgen/lib/pdbremix/data/hydroxide.lib +88 -0
- packmol_memgen/lib/pdbremix/data/make_chi.py +92 -0
- packmol_memgen/lib/pdbremix/data/opls.parameter +1108 -0
- packmol_memgen/lib/pdbremix/data/opls.topology +1869 -0
- packmol_memgen/lib/pdbremix/data/phd.frcmod +82 -0
- packmol_memgen/lib/pdbremix/data/phd.leaprc +4 -0
- packmol_memgen/lib/pdbremix/data/phd.prepin +35 -0
- packmol_memgen/lib/pdbremix/data/template.pdb +334 -0
- packmol_memgen/lib/pdbremix/data/znb.frcmod +24 -0
- packmol_memgen/lib/pdbremix/data/znb.leaprc +7 -0
- packmol_memgen/lib/pdbremix/data/znb.lib +69 -0
- packmol_memgen/lib/pdbremix/data.py +264 -0
- packmol_memgen/lib/pdbremix/fetch.py +102 -0
- packmol_memgen/lib/pdbremix/force.py +627 -0
- packmol_memgen/lib/pdbremix/gromacs.py +978 -0
- packmol_memgen/lib/pdbremix/lib/__init__.py +0 -0
- packmol_memgen/lib/pdbremix/lib/docopt.py +579 -0
- packmol_memgen/lib/pdbremix/lib/pyqcprot.py +305 -0
- packmol_memgen/lib/pdbremix/namd.py +1078 -0
- packmol_memgen/lib/pdbremix/pdbatoms.py +543 -0
- packmol_memgen/lib/pdbremix/pdbtext.py +120 -0
- packmol_memgen/lib/pdbremix/protein.py +311 -0
- packmol_memgen/lib/pdbremix/pymol.py +480 -0
- packmol_memgen/lib/pdbremix/rmsd.py +203 -0
- packmol_memgen/lib/pdbremix/simulate.py +420 -0
- packmol_memgen/lib/pdbremix/spacehash.py +73 -0
- packmol_memgen/lib/pdbremix/trajectory.py +286 -0
- packmol_memgen/lib/pdbremix/util.py +273 -0
- packmol_memgen/lib/pdbremix/v3.py +16 -0
- packmol_memgen/lib/pdbremix/v3array.py +482 -0
- packmol_memgen/lib/pdbremix/v3numpy.py +350 -0
- packmol_memgen/lib/pdbremix/volume.py +155 -0
- packmol_memgen/lib/utils.py +1017 -0
- packmol_memgen/main.py +2827 -0
- packmol_memgen_minimal-1.1.16.dist-info/METADATA +664 -0
- packmol_memgen_minimal-1.1.16.dist-info/RECORD +71 -0
- packmol_memgen_minimal-1.1.16.dist-info/WHEEL +4 -0
- packmol_memgen_minimal-1.1.16.dist-info/entry_points.txt +2 -0
- packmol_memgen_minimal-1.1.16.dist-info/licenses/LICENSE +338 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
__doc__ = """
|
|
4
|
+
|
|
5
|
+
Common Interface for molecular dynamics packages.
|
|
6
|
+
|
|
7
|
+
It provides a common API to 3 modules that wrap standard
|
|
8
|
+
relatively-free molecular-dynamics packages:
|
|
9
|
+
|
|
10
|
+
- amber.py
|
|
11
|
+
- gromacs.py
|
|
12
|
+
- namd.py
|
|
13
|
+
|
|
14
|
+
The routines are divided into roughly three sections:
|
|
15
|
+
|
|
16
|
+
1. Read and write restart files
|
|
17
|
+
2. Generate restart files from PDB
|
|
18
|
+
3. Run simulations from restart files
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import shutil
|
|
24
|
+
import copy
|
|
25
|
+
|
|
26
|
+
from . import util
|
|
27
|
+
|
|
28
|
+
from . import amber
|
|
29
|
+
from . import namd
|
|
30
|
+
from . import gromacs
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ##########################################################
|
|
35
|
+
|
|
36
|
+
# 0. Housekeeping function to figure out simulation package
|
|
37
|
+
|
|
38
|
+
def get_md_module(force_field):
|
|
39
|
+
"""
|
|
40
|
+
Returns the specific interface module that is referenced by
|
|
41
|
+
force_field.
|
|
42
|
+
"""
|
|
43
|
+
if force_field.startswith('GROMACS'):
|
|
44
|
+
return gromacs
|
|
45
|
+
elif force_field.startswith('AMBER'):
|
|
46
|
+
return amber
|
|
47
|
+
elif force_field.startswith('NAMD'):
|
|
48
|
+
return namd
|
|
49
|
+
else:
|
|
50
|
+
raise ValueError("unrecognized force-field" + force_field)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# ##########################################################
|
|
55
|
+
|
|
56
|
+
# 1. Reading and writing restart files
|
|
57
|
+
|
|
58
|
+
# In PDBREMIX, all simulations require restart files to run.
|
|
59
|
+
|
|
60
|
+
# 1. topology file (top)
|
|
61
|
+
# 2. coordinates file (crds)
|
|
62
|
+
# 3. velocities file (vels)
|
|
63
|
+
|
|
64
|
+
# When read into a Soup object, it is assumed that the units
|
|
65
|
+
# in the atom.pos and atom.vel vectors are:
|
|
66
|
+
|
|
67
|
+
# - positions: angstroms
|
|
68
|
+
# - velocities: angstroms/picosecond
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def expand_restart_files(force_field, basename):
|
|
72
|
+
"""
|
|
73
|
+
Returns expanded restart files (top, crds, vels) with basename
|
|
74
|
+
for the package implied by force_field. No file checking.
|
|
75
|
+
"""
|
|
76
|
+
md_module = get_md_module(force_field)
|
|
77
|
+
return md_module.expand_restart_files(basename)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_restart_files(basename):
|
|
81
|
+
"""
|
|
82
|
+
Returns restart files (top, crds, vels) only if they exist,
|
|
83
|
+
otherwise raises Exception. Will deduce package by
|
|
84
|
+
file extensions attached to the basename.
|
|
85
|
+
"""
|
|
86
|
+
for module in [amber, gromacs, namd]:
|
|
87
|
+
try:
|
|
88
|
+
return module.get_restart_files(basename)
|
|
89
|
+
except util.FileException:
|
|
90
|
+
pass
|
|
91
|
+
raise util.FileException("Couldn't find restart files for " + basename)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def soup_from_restart_files(basename, skip_solvent=True):
|
|
95
|
+
"""
|
|
96
|
+
Reads a Soup from the restart files.
|
|
97
|
+
"""
|
|
98
|
+
for module in [amber, gromacs, namd]:
|
|
99
|
+
try:
|
|
100
|
+
top, crds, vels = module.get_restart_files(basename)
|
|
101
|
+
return module.soup_from_restart_files(
|
|
102
|
+
top, crds, vels, skip_solvent)
|
|
103
|
+
except util.FileException:
|
|
104
|
+
pass
|
|
105
|
+
raise util.FileException("Couldn't find restart files for " + basename)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def write_soup_to_crds_and_vels(force_field, soup, basename):
|
|
109
|
+
"""
|
|
110
|
+
From soup, writes out the coordinate/velocities for a given
|
|
111
|
+
packaged that is deduced from the force_field.
|
|
112
|
+
"""
|
|
113
|
+
md_module = get_md_module(force_field)
|
|
114
|
+
return md_module.write_soup_to_crds_and_vels(soup, basename)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def convert_restart_to_pdb(basename, pdb):
|
|
118
|
+
"""
|
|
119
|
+
Converts restart files with basename into PDB file.
|
|
120
|
+
"""
|
|
121
|
+
# Will now try to guess restart files by trying each module in
|
|
122
|
+
# turn. Since the functions throws a FileException if any
|
|
123
|
+
# expected files are missing, catching these will determine
|
|
124
|
+
# failure
|
|
125
|
+
for module in [amber, gromacs, namd]:
|
|
126
|
+
try:
|
|
127
|
+
return module.convert_restart_to_pdb(basename, pdb)
|
|
128
|
+
except util.FileException:
|
|
129
|
+
pass
|
|
130
|
+
raise util.FileException("Couldn't find restart files for " + basename)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# # 2. Generate restart files from PDB
|
|
134
|
+
|
|
135
|
+
# The restart files used for PDBREMIX assumes a consistent file
|
|
136
|
+
# naming.
|
|
137
|
+
|
|
138
|
+
# To generate a topology file from the PDB file:
|
|
139
|
+
# - handles multiple protein chains
|
|
140
|
+
# - hydrogens are removed and then regenerated
|
|
141
|
+
# - disulfide bonds are identified
|
|
142
|
+
# - charged residue protonation states are auto-detected
|
|
143
|
+
# - explicit water in cubic box with 10.0 angstrom buffer
|
|
144
|
+
# - counterions to neutralize the system
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def pdb_to_top_and_crds(
|
|
148
|
+
force_field, raw_pdb, basename, solvent_buffer=10.0):
|
|
149
|
+
"""
|
|
150
|
+
Creates and returns the absolute pathnames to topology and
|
|
151
|
+
coordinate files required to start an MD simulation using the
|
|
152
|
+
package implied in the force_field.
|
|
153
|
+
"""
|
|
154
|
+
md_module = get_md_module(force_field)
|
|
155
|
+
top, crd = md_module.pdb_to_top_and_crds(
|
|
156
|
+
force_field, raw_pdb, basename, solvent_buffer)
|
|
157
|
+
return os.path.abspath(top), os.path.abspath(crd)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# ##########################################################
|
|
161
|
+
|
|
162
|
+
# # 3. Run simulations from restart files
|
|
163
|
+
|
|
164
|
+
# Simulation approach for implicit solvent:
|
|
165
|
+
# - optional positional constraints: 100 kcal/mol/angs**2
|
|
166
|
+
# - Langevin thermostat for constant temperature
|
|
167
|
+
|
|
168
|
+
# Simulation approach for explict water:
|
|
169
|
+
# - optional positional restraints: 100 kcal/mol/angs**2
|
|
170
|
+
# - periodic box with PME electrostatics
|
|
171
|
+
# - Langevin thermostat for constant temperature
|
|
172
|
+
# - Nose-Hoover barometer with flexible box size
|
|
173
|
+
|
|
174
|
+
# Each package maintains its own files, but all required
|
|
175
|
+
# will share a common basename with standard extensions
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def fetch_simulation_parameters(
|
|
179
|
+
force_field, top, crds, restraint_pdb,
|
|
180
|
+
simulation_type, basename, restraint_force=None):
|
|
181
|
+
"""
|
|
182
|
+
Returns a dictionary that contains all the high level
|
|
183
|
+
parameters needed to run an MD simulation using the package
|
|
184
|
+
implied in force_field.
|
|
185
|
+
|
|
186
|
+
Options for simulation_type:
|
|
187
|
+
1. 'minimization'
|
|
188
|
+
2. 'constant_energy'
|
|
189
|
+
3. 'langevin_thermometer'
|
|
190
|
+
"""
|
|
191
|
+
# use a bit of magic to get the dictionary. Pesumably the
|
|
192
|
+
# dictionary with the correct name is present in each
|
|
193
|
+
# simulation module
|
|
194
|
+
md_module = get_md_module(force_field)
|
|
195
|
+
parms_dict_name = '%s_parms' % simulation_type
|
|
196
|
+
parms = getattr(md_module, parms_dict_name).copy()
|
|
197
|
+
# Several fields in parms is common across all packages, these
|
|
198
|
+
# are taken from the parameters of this function:
|
|
199
|
+
parms.update({
|
|
200
|
+
'force_field': force_field,
|
|
201
|
+
'topology': top,
|
|
202
|
+
'input_crds': crds,
|
|
203
|
+
'output_basename': basename,
|
|
204
|
+
})
|
|
205
|
+
if restraint_pdb:
|
|
206
|
+
parms['restraint_pdb'] = restraint_pdb
|
|
207
|
+
if restraint_force is not None:
|
|
208
|
+
parms['restraint_force'] = restraint_force
|
|
209
|
+
return parms
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def run_simulation_with_parameters(parms):
|
|
213
|
+
"""
|
|
214
|
+
Carries out simulations based on parms
|
|
215
|
+
"""
|
|
216
|
+
# For housekeeping, the parms dictionary is written to a
|
|
217
|
+
# .config file. As an Exception is thrown if simulation failed,
|
|
218
|
+
# the existence of an equivalent .config file is an indicator
|
|
219
|
+
# that the simulation has already successfully run.
|
|
220
|
+
config = parms['output_basename'] + ".config"
|
|
221
|
+
if util.is_same_dict_in_file(parms, config):
|
|
222
|
+
print("Skipping: simulation already run.")
|
|
223
|
+
return
|
|
224
|
+
md_module = get_md_module(parms['force_field'])
|
|
225
|
+
md_module.run(parms)
|
|
226
|
+
# No exceptions were thrown - write .config file.
|
|
227
|
+
util.write_dict(config, parms)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def minimize(
|
|
231
|
+
force_field, in_basename, basename,
|
|
232
|
+
restraint_pdb="", restraint_force=None, n_step=200):
|
|
233
|
+
"""
|
|
234
|
+
Runs an energy minimization on the restart files top & crd.
|
|
235
|
+
|
|
236
|
+
This is a crucial step as minimization is more robust than
|
|
237
|
+
dynamics calculations. An initial minimization will find a good
|
|
238
|
+
local energy minimum conformation for a dynamics simulation to
|
|
239
|
+
start. This will avoid spurious initial energy fluctuations for
|
|
240
|
+
future dynamics.
|
|
241
|
+
"""
|
|
242
|
+
md_module = get_md_module(force_field)
|
|
243
|
+
top, crds, vels = md_module.get_restart_files(in_basename)
|
|
244
|
+
parms = fetch_simulation_parameters(
|
|
245
|
+
force_field, top, crds, restraint_pdb,
|
|
246
|
+
'minimization', basename, restraint_force)
|
|
247
|
+
parms['n_step_minimization'] = n_step
|
|
248
|
+
run_simulation_with_parameters(parms)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def langevin_thermometer(
|
|
252
|
+
force_field, in_basename, n_step, temp, basename,
|
|
253
|
+
n_step_per_snapshot=50, restraint_pdb="", restraint_force=None,
|
|
254
|
+
random_seed=2343):
|
|
255
|
+
"""
|
|
256
|
+
Runs a constant temperature simulation using a Langevin
|
|
257
|
+
thermometer.
|
|
258
|
+
|
|
259
|
+
There are two basic thermometers in most packages. Anderson
|
|
260
|
+
and Langevin. Anderson simply rescales the energy to satisfy
|
|
261
|
+
the average kinetic energy equation wheras Langevin adds a
|
|
262
|
+
little random force. Langevin thus avoids getting trapped in
|
|
263
|
+
unintended energy minima for the cost of a bit of stochasity.
|
|
264
|
+
"""
|
|
265
|
+
md_module = get_md_module(force_field)
|
|
266
|
+
top, crds, vels = md_module.get_restart_files(in_basename)
|
|
267
|
+
parms = fetch_simulation_parameters(
|
|
268
|
+
force_field, top, crds, restraint_pdb,
|
|
269
|
+
'langevin_thermometer', basename, restraint_force)
|
|
270
|
+
parms['input_vels'] = vels
|
|
271
|
+
parms['random_seed'] = random_seed
|
|
272
|
+
parms['n_step_dynamics'] = n_step
|
|
273
|
+
parms['n_step_per_snapshot'] = n_step_per_snapshot
|
|
274
|
+
parms['temperature_thermometer'] = "%.1f" % temp
|
|
275
|
+
parms['temperature_initial_velocities'] = "%.1f" % temp
|
|
276
|
+
run_simulation_with_parameters(parms)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def constant_energy(
|
|
280
|
+
force_field, in_basename, n_step, basename,
|
|
281
|
+
n_step_per_snapshot=50, restraint_pdb="", restraint_force=None):
|
|
282
|
+
"""
|
|
283
|
+
Runs a constant energy simulation.
|
|
284
|
+
|
|
285
|
+
Constant energy simulation are useful if you want to capture
|
|
286
|
+
energy transfers exactly. Normally such simulations are
|
|
287
|
+
preceeded by a period of thermal regulation using a Langevin
|
|
288
|
+
thermometer.
|
|
289
|
+
"""
|
|
290
|
+
md_module = get_md_module(force_field)
|
|
291
|
+
top, crds, vels = md_module.get_restart_files(in_basename)
|
|
292
|
+
parms = fetch_simulation_parameters(
|
|
293
|
+
force_field, top, crds, restraint_pdb,
|
|
294
|
+
'constant_energy', basename, restraint_force)
|
|
295
|
+
parms['input_vels'] = vels
|
|
296
|
+
parms['n_step_dynamics'] = n_step
|
|
297
|
+
parms['n_step_per_snapshot'] = n_step_per_snapshot
|
|
298
|
+
assert 'temperature_thermometer' not in parms
|
|
299
|
+
assert 'temp_init' not in parms
|
|
300
|
+
run_simulation_with_parameters(parms)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def merge_trajectories(force_field, basename, src_basenames):
|
|
304
|
+
md_module = get_md_module(force_field)
|
|
305
|
+
md_module.merge_trajectories(basename, src_basenames)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def merge_simulations(force_field, basename, sim_dirs):
|
|
309
|
+
"""
|
|
310
|
+
Splices together a bunch of simulations, all with the same
|
|
311
|
+
basename, into one large simulation in the current directory.
|
|
312
|
+
"""
|
|
313
|
+
if not sim_dirs:
|
|
314
|
+
return
|
|
315
|
+
src_basenames = [os.path.join(s, basename) for s in sim_dirs]
|
|
316
|
+
merge_trajectories(force_field, basename, src_basenames)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def pulse(
|
|
320
|
+
force_field, in_basename, basename, n_step, pulse_fn,
|
|
321
|
+
n_step_per_pulse=100, restraint_pdb="", restraint_force=None):
|
|
322
|
+
"""
|
|
323
|
+
Runs a pulse simulation that uses the restart-file modification
|
|
324
|
+
strategy to manage a steered-molecular dynamics simulation.
|
|
325
|
+
|
|
326
|
+
The pulsed approacha pplies external forces in pulses, which is
|
|
327
|
+
practically carried out be running short constant-energy
|
|
328
|
+
simulations and directly modifying the restart velocities
|
|
329
|
+
between each simulation.
|
|
330
|
+
|
|
331
|
+
Pulse simulations has certain advantages: for instance, the
|
|
332
|
+
system can respond to the forces between pulses, and the
|
|
333
|
+
incredibly flexibility in applying forces. The disadvantage is
|
|
334
|
+
the costly setup which is hopefully, mitigated by this library.
|
|
335
|
+
|
|
336
|
+
Reference: Bosco K. Ho and David A. Agard (2010) "An improved
|
|
337
|
+
strategy for generating forces in steered molecular dynamics:
|
|
338
|
+
the mechanical unfolding of titin, e2lip3 and ubiquitin" PLoS
|
|
339
|
+
ONE 5(9):e13068.
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
# Grab the simulation prameters for a constant energy
|
|
343
|
+
# simulation. Constant energy is preferred as we want to ensure
|
|
344
|
+
# energy changes come only from our velocity modification.
|
|
345
|
+
top, crds, vels = get_restart_files(in_basename)
|
|
346
|
+
# use dummy top and crds, which will be overriden
|
|
347
|
+
overall_config_parms = fetch_simulation_parameters(
|
|
348
|
+
force_field, top, crds, restraint_pdb,
|
|
349
|
+
'constant_energy', basename, restraint_force)
|
|
350
|
+
overall_config_parms.update({
|
|
351
|
+
'input_md_name': in_basename,
|
|
352
|
+
'input_vels': vels,
|
|
353
|
+
'n_step_dynamics': n_step,
|
|
354
|
+
'n_step_per_snapshot': n_step_per_pulse // 2,
|
|
355
|
+
'n_step_per_pulse': n_step_per_pulse
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
# Check if the simulation has already run as the config
|
|
359
|
+
# file is not written until the very end
|
|
360
|
+
config = basename + ".config"
|
|
361
|
+
if util.is_same_dict_in_file(overall_config_parms, config):
|
|
362
|
+
print("Skipping: pulsing simulation already run.")
|
|
363
|
+
return
|
|
364
|
+
|
|
365
|
+
# The overall_config_parms will be written out at the end.
|
|
366
|
+
# We make a copy for internal use
|
|
367
|
+
pulse_parms = copy.deepcopy(overall_config_parms)
|
|
368
|
+
|
|
369
|
+
# Calculate steps for each pulse, esp for last step
|
|
370
|
+
n_pulse = pulse_parms['n_step_dynamics'] / n_step_per_pulse
|
|
371
|
+
n_step_list = [n_step_per_pulse for i in range(n_pulse)]
|
|
372
|
+
n_excess_step = pulse_parms['n_step_dynamics'] % n_step_per_pulse
|
|
373
|
+
if n_excess_step > 0:
|
|
374
|
+
n_pulse += 1
|
|
375
|
+
n_step_list.append(n_excess_step)
|
|
376
|
+
|
|
377
|
+
# Prepare restart files for first step
|
|
378
|
+
pulse_parms['topology'] = os.path.abspath(pulse_parms['topology'])
|
|
379
|
+
in_basename = pulse_parms['input_md_name']
|
|
380
|
+
pulse_parms['input_md_name'] = os.path.abspath(in_basename)
|
|
381
|
+
|
|
382
|
+
# Now loop through pulses
|
|
383
|
+
timer = util.Timer()
|
|
384
|
+
save_dir = os.getcwd()
|
|
385
|
+
pulses = ["pulse%d" % i for i in range(n_pulse)]
|
|
386
|
+
for pulse, n_step in zip(pulses, n_step_list):
|
|
387
|
+
print("Pulse: %s/%d" % (pulse, n_pulse))
|
|
388
|
+
|
|
389
|
+
os.chdir(save_dir)
|
|
390
|
+
util.goto_dir(pulse)
|
|
391
|
+
|
|
392
|
+
pulse_parms['n_step_dynamics'] = n_step
|
|
393
|
+
|
|
394
|
+
soup = soup_from_restart_files(pulse_parms['input_md_name'])
|
|
395
|
+
|
|
396
|
+
# Apply forces by modifying the velocities directly
|
|
397
|
+
pulse_fn(soup)
|
|
398
|
+
|
|
399
|
+
crds, vels = write_soup_to_crds_and_vels(
|
|
400
|
+
force_field, soup, basename + '.pulse.in')
|
|
401
|
+
pulse_parms['input_crds'] = crds
|
|
402
|
+
pulse_parms['input_vels'] = vels
|
|
403
|
+
|
|
404
|
+
run_simulation_with_parameters(pulse_parms)
|
|
405
|
+
|
|
406
|
+
# Setup new restart files based on just-finished pulse
|
|
407
|
+
pulse_parms['input_md_name'] = os.path.abspath(basename)
|
|
408
|
+
|
|
409
|
+
os.chdir(save_dir)
|
|
410
|
+
|
|
411
|
+
merge_simulations(force_field, basename, pulses)
|
|
412
|
+
|
|
413
|
+
# cleanup pulses after merging
|
|
414
|
+
util.clean_fname(*pulses)
|
|
415
|
+
|
|
416
|
+
# everything worked, no exceptions thrown
|
|
417
|
+
open(basename+'.time', 'w').write(timer.str()+'\n')
|
|
418
|
+
util.write_dict(config, overall_config_parms)
|
|
419
|
+
|
|
420
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import array
|
|
2
|
+
import math
|
|
3
|
+
from . import v3
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SpaceHash(object):
|
|
7
|
+
"""
|
|
8
|
+
A geometrical object to sort a set of vertices into disjoint
|
|
9
|
+
boxes to optimize pair sorting by distance.
|
|
10
|
+
|
|
11
|
+
The boxes are defined by div, and close pairs generates listing
|
|
12
|
+
of indices of the vertices that are within div apart.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, vertices, div=5.3, padding=0.05):
|
|
16
|
+
self.vertices = vertices
|
|
17
|
+
self.div = div
|
|
18
|
+
self.inv_div = 1.0 / self.div
|
|
19
|
+
self.padding = padding
|
|
20
|
+
|
|
21
|
+
zero3 = lambda: [0.0] * 3
|
|
22
|
+
self.minima = zero3()
|
|
23
|
+
self.maxima = zero3()
|
|
24
|
+
self.spans = zero3()
|
|
25
|
+
self.sizes = zero3()
|
|
26
|
+
|
|
27
|
+
for i in range(3):
|
|
28
|
+
self.minima[i] = min([v[i] for v in self.vertices])
|
|
29
|
+
self.maxima[i] = max([v[i] for v in self.vertices])
|
|
30
|
+
self.minima[i] -= self.padding
|
|
31
|
+
self.maxima[i] += self.padding
|
|
32
|
+
self.spans[i] = self.maxima[i] - self.minima[i]
|
|
33
|
+
self.sizes[i] = int(math.ceil(self.spans[i] * self.inv_div))
|
|
34
|
+
|
|
35
|
+
self.size1_size2 = self.sizes[1] * self.sizes[2]
|
|
36
|
+
self.size2 = self.sizes[2]
|
|
37
|
+
|
|
38
|
+
self.cells = {}
|
|
39
|
+
self.spaces = []
|
|
40
|
+
for i_vertex, vertex in enumerate(self.vertices):
|
|
41
|
+
space = self.vertex_to_space(vertex)
|
|
42
|
+
self.spaces.append(space)
|
|
43
|
+
space_hash = self.space_to_hash(space)
|
|
44
|
+
cell = self.cells.setdefault(space_hash, array.array('L'))
|
|
45
|
+
cell.append(i_vertex)
|
|
46
|
+
|
|
47
|
+
def vertex_to_space(self, v):
|
|
48
|
+
return [int((v[i] - self.minima[i]) * self.inv_div) for i in range(3)]
|
|
49
|
+
|
|
50
|
+
def space_to_hash(self, s):
|
|
51
|
+
return s[0] * self.size1_size2 + s[1] * self.size2 + s[2]
|
|
52
|
+
|
|
53
|
+
def neighbourhood(self, space):
|
|
54
|
+
def neighbourhood_in_dim(space, i_dim):
|
|
55
|
+
i = max(0, space[i_dim] - 1)
|
|
56
|
+
j = min(self.sizes[i_dim], space[i_dim] + 2)
|
|
57
|
+
return list(range(i, j))
|
|
58
|
+
for s0 in neighbourhood_in_dim(space, 0):
|
|
59
|
+
for s1 in neighbourhood_in_dim(space, 1):
|
|
60
|
+
for s2 in neighbourhood_in_dim(space, 2):
|
|
61
|
+
yield [s0, s1, s2]
|
|
62
|
+
|
|
63
|
+
def close_pairs(self):
|
|
64
|
+
n_vertex = len(self.vertices)
|
|
65
|
+
for i_vertex0 in range(n_vertex):
|
|
66
|
+
space0 = self.spaces[i_vertex0]
|
|
67
|
+
for space1 in self.neighbourhood(space0):
|
|
68
|
+
hash1 = self.space_to_hash(space1)
|
|
69
|
+
for i_vertex1 in self.cells.get(hash1, []):
|
|
70
|
+
if i_vertex0 < i_vertex1:
|
|
71
|
+
yield i_vertex0, i_vertex1
|
|
72
|
+
|
|
73
|
+
|