Skip to content

Commit b91d4f5

Browse files
Add option to parallelize running each phase (#74)
1 parent ea5a04e commit b91d4f5

File tree

1 file changed

+41
-18
lines changed

1 file changed

+41
-18
lines changed

absolv/runner.py

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Run calculations defined by a config."""
22

3+
import functools
4+
import multiprocessing
35
import pathlib
46
import tempfile
57
import typing
@@ -172,13 +174,26 @@ def _equilibrate(
172174
return simulation.context.getState(getPositions=True)
173175

174176

175-
def _run_phase_hremd(
177+
def _run_eq_phase(
176178
protocol: absolv.config.EquilibriumProtocol,
177-
temperature: openmm.unit.Quantity,
178179
prepared_system: PreparedSystem,
180+
output_dir: pathlib.Path | None,
181+
temperature: openmm.unit.Quantity,
179182
platform: femto.md.constants.OpenMMPlatform,
180-
output_dir: pathlib.Path | None = None,
181183
) -> tuple[dict[str, float], dict[str, numpy.ndarray]]:
184+
"""Run HREMD for one of the solvent phases.
185+
186+
Args:
187+
protocol: The protocol to run.
188+
prepared_system: The prepared system to run.
189+
output_dir: The (optional) directory to save HREMD samples to.
190+
temperature: The temperature to run at.
191+
platform: The OpenMM platform to run using.
192+
193+
Returns:
194+
The free energy estimates and the overlap matrices. See
195+
``femto.fe.ddg.estimate_ddg`` for more details.
196+
"""
182197
platform = (
183198
femto.md.constants.OpenMMPlatform.REFERENCE
184199
if prepared_system.topology.box_vectors is None
@@ -239,6 +254,7 @@ def run_eq(
239254
prepared_system_b: PreparedSystem,
240255
platform: femto.md.constants.OpenMMPlatform = femto.md.constants.OpenMMPlatform.CUDA,
241256
output_dir: pathlib.Path | None = None,
257+
parallel: bool = False,
242258
) -> absolv.config.Result:
243259
"""Perform a simulation at each lambda window and for each solvent.
244260
@@ -248,27 +264,34 @@ def run_eq(
248264
prepared_system_b: The prepared system b. See ``setup`` for more details.
249265
platform: The OpenMM platform to run using.
250266
output_dir: The (optional) directory to save HREMD samples to.
267+
parallel: Whether to run calculations for solvent A and solvent B in
268+
parallel. This is mostly useful when running HFE calculations where
269+
the vacuum phase will typically run on the CPU while the solvent phase
270+
will run on the GPU.
251271
"""
252272

253-
results_a, overlap_a = _run_phase_hremd(
254-
config.alchemical_protocol_a,
255-
config.temperature,
256-
prepared_system_a,
257-
platform,
258-
None if output_dir is None else output_dir / "solvent-a",
273+
output_dir_a = None if output_dir is None else output_dir / "solvent-a"
274+
output_dir_b = None if output_dir is None else output_dir / "solvent-b"
275+
276+
args = [
277+
(config.alchemical_protocol_a, prepared_system_a, output_dir_a),
278+
(config.alchemical_protocol_b, prepared_system_b, output_dir_b),
279+
]
280+
run_fn = functools.partial(
281+
_run_eq_phase, temperature=config.temperature, platform=platform
259282
)
260283

261-
dg_a, dg_a_std = results_a["ddG_kcal_mol"], results_a["ddG_error_kcal_mol"]
262-
# overlap_a = overlap_a["overlap_0"]
284+
if parallel:
285+
with multiprocessing.Pool(2) as pool:
286+
results = list(pool.starmap(run_fn, args))
287+
else:
288+
results = [run_fn(*args[0]), run_fn(*args[1])]
263289

264-
results_b, overlap_b = _run_phase_hremd(
265-
config.alchemical_protocol_b,
266-
config.temperature,
267-
prepared_system_b,
268-
platform,
269-
None if output_dir is None else output_dir / "solvent-b",
270-
)
290+
results_a, overlap_a = results[0]
291+
results_b, overlap_b = results[1]
271292

293+
dg_a, dg_a_std = results_a["ddG_kcal_mol"], results_a["ddG_error_kcal_mol"]
294+
# overlap_a = overlap_a["overlap_0"]
272295
dg_b, dg_b_std = results_b["ddG_kcal_mol"], results_b["ddG_error_kcal_mol"]
273296
# overlap_b = overlap_b["overlap_0"]
274297

0 commit comments

Comments
 (0)