Skip to content

Commit fe4bc07

Browse files
millores
1 parent 640ee37 commit fe4bc07

1 file changed

Lines changed: 23 additions & 241 deletions

File tree

docs/episodes/04-muestreo-avanzado.md

Lines changed: 23 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,33 @@ permalink: /episodes/04-muestreo-avanzado/
1212

1313
<!-- toc:start -->
1414
## Table of contents
15+
- [Table of contents](#table-of-contents)
1516
- [Duration](#duration)
1617
- [Objectives](#objectives)
1718
- [Content](#content)
1819
- [Thermodynamic foundations](#thermodynamic-foundations)
1920
- [Official OpenMM tutorials](#official-openmm-tutorials)
2021
- [Simulated annealing](#simulated-annealing)
22+
- [Guided demo](#guided-demo)
23+
- [Exercise](#exercise)
24+
- [Notebooks](#notebooks)
25+
- [Replica exchange (REMD)](#replica-exchange-remd)
26+
- [REMD for alanine dipeptide](#remd-for-alanine-dipeptide)
27+
- [Exercise](#exercise-1)
28+
- [Notebooks](#notebooks-1)
2129
- [Gaussian accelerated MD (GaMD) with OpenMM](#gaussian-accelerated-md-gamd-with-openmm)
30+
- [Guided demo: GaMD on alanine dipeptide](#guided-demo-gamd-on-alanine-dipeptide)
31+
- [Exercise](#exercise-2)
32+
- [Notebooks](#notebooks-2)
2233
- [Martini coarse-graining with OpenMM](#martini-coarse-graining-with-openmm)
34+
- [Guided demo: Martini coarse-graining for the complex system](#guided-demo-martini-coarse-graining-for-the-complex-system)
35+
- [Exercise](#exercise-3)
36+
- [Notebooks](#notebooks-3)
2337
- [Umbrella sampling](#umbrella-sampling)
2438
- [SBMOpenMM resources](#sbmopenmm-resources)
2539
- [Guide scripts (OpenMM Application Layer)](#guide-scripts-openmm-application-layer)
26-
- [Alanine dipeptide](#alanine-dipeptide)
27-
- [Protein-ligand complex](#protein-ligand-complex)
40+
- [Alanine dipeptide](#alanine-dipeptide)
41+
- [Protein-ligand complex](#protein-ligand-complex)
2842
- [References](#references)
2943
<!-- toc:end -->
3044

@@ -103,7 +117,7 @@ Script source: <a href="{{ site.baseurl }}/episodes/scripts/openmm_advanced_anne
103117

104118
The accompanying explanation notes that the loop simply updates the `LangevinMiddleIntegrator` temperature before each batch of 1,000 steps, which mirrors the ramping schedules we describe here. Keep that block as a quick reference when tuning integrator parameters or defining temperature sequences for your exercises so the practical code stays aligned with the theory in this episode.
105119

106-
### Replica exchange (REMD) context
120+
## Replica exchange (REMD)
107121

108122
The same temperature-ramping intuition underpins replica-exchange (REMD) methods. Instead of moving a single trajectory between high and low temperatures, REMD maintains multiple replicas at different thermodynamic states and swaps them through Metropolis trials to jump across barriers. `OpenMMTools` exposes `ReplicaExchangeSampler` (see https://openmmtools.readthedocs.io/en/stable/multistate.html#replicaexchangesampler-replica-exchange-among-thermodynamic-states)
109123
to manage state definitions, collect swap statistics, and maintain detailed balance for arbitrary Hamiltonians.
@@ -211,256 +225,24 @@ To feed the analysis, we rely on the official scripts described in the OpenMM gu
211225

212226
In each case, the outputs (DCD, CSV, and energy reports) are used in this episode's exercises.
213227

214-
## Alanine dipeptide
228+
### Alanine dipeptide
215229

216-
### Guided demo
217-
218-
<!-- sync-from: docs/episodes/scripts/05-muestreo-avanzado_simple.py -->
219-
```python
220-
#!/usr/bin/env python3
221-
import os
222-
from pathlib import Path
223-
224-
from openmm import unit, app
225-
import openmm as mm
226-
from openmm.app import PDBFile, ForceField, Simulation
227-
228-
COURSE_DIR = Path(os.environ.get("COURSE_DIR", str(Path.home() / "Concepcion26"))).expanduser()
229-
DATA_DIR = COURSE_DIR / "data"
230-
PDB_IN = DATA_DIR / "alanine-dipeptide.pdb"
231-
OUT_DIR = COURSE_DIR / "results" / "05-muestreo-avanzado" / "simple"
232-
OUT_DIR.mkdir(parents=True, exist_ok=True)
233-
234-
pdb = PDBFile(str(PDB_IN))
235-
forcefield = ForceField("amber14-all.xml", "amber14/tip3pfb.xml")
236-
237-
system = forcefield.createSystem(
238-
pdb.topology,
239-
nonbondedMethod=app.NoCutoff,
240-
constraints=app.HBonds,
241-
)
242-
243-
# Constrain the distance between two atoms as a simple example.
244-
force = mm.CustomBondForce("0.5*k*(r-r0)^2")
245-
force.addPerBondParameter("k")
246-
force.addPerBondParameter("r0")
247-
force.addBond(0, 1, [500.0 * unit.kilojoule_per_mole / unit.nanometer**2, 0.25 * unit.nanometer])
248-
system.addForce(force)
249-
250-
integrator = mm.LangevinIntegrator(300 * unit.kelvin, 1 / unit.picosecond, 2 * unit.femtoseconds)
251-
252-
simulation = Simulation(pdb.topology, system, integrator)
253-
simulation.context.setPositions(pdb.positions)
254-
255-
simulation.minimizeEnergy(maxIterations=200)
256-
simulation.step(2000)
257-
258-
print("Simulation with restraint finished. Output dir:", OUT_DIR)
259-
```
260-
261-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py">05-muestreo-avanzado_simple.py</a>
262-
263-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py">05-muestreo-avanzado_simple.py</a>
264-
265-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py">05-muestreo-avanzado_simple.py</a>
266-
267-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py">05-muestreo-avanzado_simple.py</a>
268-
269-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py">05-muestreo-avanzado_simple.py</a>
270230

271231
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py">05-muestreo-avanzado_simple.py</a>
272232

273-
### Exercise
274-
275-
- Run the simple workflow with spherical restraints and record the value of $\langle \|\mathbf{g}\|^2 \rangle$ before and after annealing.
276-
- Compare the average potential energy with and without CustomExternalForce.
277-
278-
### Key points
279-
280-
- Keep reports every 10 steps to monitor integrator drift.
281-
- Adjust $\beta$ to preserve numerical stability in small systems.
282-
283-
### Notebooks and scripts
233+
<!-- sync-from: docs/episodes/notebooks/04-muestreo-avanzado_simple.ipynb -->
234+
<div class="notebook-embed"><iframe src="{{ site.baseurl }}/episodes/notebooks/rendered/04-muestreo-avanzado_simple.html" loading="lazy"></iframe><div class="notebook-links"><a href="{{ site.baseurl }}/episodes/notebooks/04-muestreo-avanzado_simple.ipynb" download>Download notebook</a> | <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py" download>Download script (.py)</a></div></div>
284235

285236
- This notebook executes the advanced sampling routine for alanine (restraints, custom forces, reporting energies) and tracks gradient norms. (<a href="{{ site.baseurl }}/episodes/notebooks/04-muestreo-avanzado_simple.ipynb">notebook</a> | <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado_simple.py">script</a>)
286237

287-
## Protein-ligand complex
288-
289-
### Guided demo
290-
291-
<!-- sync-from: docs/episodes/scripts/05-muestreo-avanzado.py -->
292-
```python
293-
#!/usr/bin/env python3
294-
import argparse
295-
import os
296-
import sys
297-
import time
298-
from pathlib import Path
299-
300-
from openff.toolkit import Molecule
301-
from openmmforcefields.generators import SystemGenerator
302-
import openmm
303-
from openmm import app, unit, LangevinIntegrator
304-
from openmm.app import PDBFile, Simulation, Modeller, StateDataReporter, DCDReporter
305-
306-
COURSE_DIR = Path(os.environ.get("COURSE_DIR", str(Path.home() / "Concepcion26"))).expanduser()
307-
DATA_DIR = COURSE_DIR / "data" / "complex"
308-
DEFAULT_PROTEIN = DATA_DIR / "protein.pdb"
309-
DEFAULT_LIGAND = DATA_DIR / "ligand1.mol"
310-
311-
312-
def get_platform():
313-
speed = 0
314-
platform = None
315-
for i in range(openmm.Platform.getNumPlatforms()):
316-
candidate = openmm.Platform.getPlatform(i)
317-
if candidate.getSpeed() > speed:
318-
platform = candidate
319-
speed = candidate.getSpeed()
320-
print("Using platform", platform.getName())
321-
if platform.getName() in {"CUDA", "OpenCL"}:
322-
platform.setPropertyDefaultValue("Precision", "mixed")
323-
print("Set precision for platform", platform.getName(), "to mixed")
324-
return platform
325-
326-
327-
def main() -> None:
328-
parser = argparse.ArgumentParser(description="Simulate protein-ligand complex with optional solvation")
329-
parser.add_argument("-p", "--protein", default=str(DEFAULT_PROTEIN), help="Protein PDB file")
330-
parser.add_argument("-l", "--ligand", default=str(DEFAULT_LIGAND), help="Ligand MOL file")
331-
parser.add_argument("-o", "--output", default="solvated", help="Base name for output files")
332-
parser.add_argument("-s", "--steps", type=int, default=5000, help="Number of steps")
333-
parser.add_argument("-z", "--step-size", type=float, default=0.002, help="Step size (ps)")
334-
parser.add_argument("-f", "--friction-coeff", type=float, default=1.0, help="Friction coefficient (ps)")
335-
parser.add_argument("-i", "--interval", type=int, default=1000, help="Reporting interval")
336-
parser.add_argument("-t", "--temperature", type=int, default=300, help="Temperature (K)")
337-
parser.add_argument("--solvate", action="store_true", help="Add solvent box")
338-
parser.add_argument("--padding", type=float, default=10.0, help="Padding for solvent box (A)")
339-
parser.add_argument("--water-model", default="tip3p", choices=["tip3p", "spce", "tip4pew", "tip5p", "swm4ndp"], help="Water model")
340-
parser.add_argument("--positive-ion", default="Na+", help="Positive ion for solvation")
341-
parser.add_argument("--negative-ion", default="Cl-", help="Negative ion for solvation")
342-
parser.add_argument("--ionic-strength", type=float, default=0.0, help="Ionic strength (M)")
343-
parser.add_argument("--no-neutralize", action="store_true", help="Don't neutralize")
344-
parser.add_argument("-e", "--equilibration-steps", type=int, default=200, help="Equilibration steps")
345-
args = parser.parse_args()
346-
347-
t0 = time.time()
348-
out_dir = COURSE_DIR / "results" / "05-muestreo-avanzado" / "complex"
349-
out_dir.mkdir(parents=True, exist_ok=True)
350-
output_base = str(out_dir / args.output)
351-
output_complex = output_base + "_complex.pdb"
352-
output_min = output_base + "_minimised.pdb"
353-
output_traj = output_base + "_traj.dcd"
354-
355-
print("Reading ligand")
356-
ligand_mol = Molecule.from_file(args.ligand)
357-
358-
print("Preparing system")
359-
forcefield_kwargs = {
360-
"constraints": app.HBonds,
361-
"rigidWater": True,
362-
"removeCMMotion": False,
363-
"hydrogenMass": 4 * unit.amu,
364-
}
365-
system_generator = SystemGenerator(
366-
forcefields=["amber/ff14SB.xml", "amber/tip3p_standard.xml"],
367-
small_molecule_forcefield="gaff-2.11",
368-
molecules=[ligand_mol],
369-
forcefield_kwargs=forcefield_kwargs,
370-
)
371-
372-
print("Reading protein")
373-
protein_pdb = PDBFile(args.protein)
374-
375-
print("Preparing complex")
376-
modeller = Modeller(protein_pdb.topology, protein_pdb.positions)
377-
lig_top = ligand_mol.to_topology()
378-
modeller.add(lig_top.to_openmm(), lig_top.get_positions().to_openmm())
379-
380-
if args.solvate:
381-
print("Adding solvent")
382-
modeller.addSolvent(
383-
system_generator.forcefield,
384-
model=args.water_model,
385-
padding=args.padding * unit.angstroms,
386-
positiveIon=args.positive_ion,
387-
negativeIon=args.negative_ion,
388-
ionicStrength=args.ionic_strength * unit.molar,
389-
neutralize=not args.no_neutralize,
390-
)
391-
392-
with open(output_complex, "w") as outfile:
393-
PDBFile.writeFile(modeller.topology, modeller.positions, outfile)
394-
395-
system = system_generator.create_system(modeller.topology, molecules=ligand_mol)
396-
step_size = args.step_size * unit.picoseconds
397-
friction = args.friction_coeff / unit.picosecond
398-
temperature = args.temperature * unit.kelvin
399-
duration = (step_size * args.steps).value_in_unit(unit.nanoseconds)
400-
401-
if system.usesPeriodicBoundaryConditions():
402-
system.addForce(openmm.MonteCarloBarostat(1 * unit.atmospheres, temperature, 25))
403-
404-
integrator = LangevinIntegrator(temperature, friction, step_size)
405-
platform = get_platform()
406-
407-
simulation = Simulation(modeller.topology, system, integrator, platform=platform)
408-
simulation.context.setPositions(modeller.positions)
409-
410-
print("Minimising ...")
411-
simulation.minimizeEnergy()
412-
413-
with open(output_min, "w") as outfile:
414-
PDBFile.writeFile(
415-
modeller.topology,
416-
simulation.context.getState(getPositions=True, enforcePeriodicBox=True).getPositions(),
417-
file=outfile,
418-
keepIds=True,
419-
)
420-
421-
simulation.context.setVelocitiesToTemperature(temperature)
422-
print("Equilibrating ...")
423-
simulation.step(args.equilibration_steps)
424-
425-
simulation.reporters.append(DCDReporter(output_traj, args.interval, enforcePeriodicBox=True))
426-
simulation.reporters.append(StateDataReporter(sys.stdout, args.interval * 5, step=True, potentialEnergy=True, temperature=True))
427-
428-
print("Starting simulation with", args.steps, "steps ...")
429-
t1 = time.time()
430-
simulation.step(args.steps)
431-
t2 = time.time()
432-
print("Simulation complete in", round((t2 - t1) / 60, 3), "mins")
433-
print("Simulation time was", round(duration, 3), "ns")
434-
print("Total wall clock time was", round((t2 - t0) / 60, 3), "mins")
435-
436-
437-
if __name__ == "__main__":
438-
main()
439-
```
440-
441-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py">05-muestreo-avanzado.py</a>
442-
443-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py">05-muestreo-avanzado.py</a>
444-
445-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py">05-muestreo-avanzado.py</a>
238+
### Protein-ligand complex
446239

447-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py">05-muestreo-avanzado.py</a>
448240

449241
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py">05-muestreo-avanzado.py</a>
450242

451-
Script source: <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py">05-muestreo-avanzado.py</a>
452-
453-
### Exercise
454-
455-
- Run with `--solvate` and `--padding 12`, recording solvent density and Coulomb energy.
456-
- Try another water model and analyze the variation in $\Delta G$ estimated from partition differences.
457-
458-
### Key points
459-
460-
- Periodic solvation stabilizes $\Delta G$ on long time scales and improves annealing convergence.
461-
- Compare energy distributions to validate extended sampling.
243+
<!-- sync-from: docs/episodes/notebooks/04-muestreo-avanzado.ipynb -->
244+
<div class="notebook-embed"><iframe src="{{ site.baseurl }}/episodes/notebooks/rendered/04-muestreo-avanzado.html" loading="lazy"></iframe><div class="notebook-links"><a href="{{ site.baseurl }}/episodes/notebooks/04-muestreo-avanzado.ipynb" download>Download notebook</a> | <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py" download>Download script (.py)</a></div></div>
462245

463-
### Notebooks and scripts
464246

465247
- This notebook covers the complex system with solvation options, barostat control, and energy/force logging to validate enhanced sampling workflows. (<a href="{{ site.baseurl }}/episodes/notebooks/04-muestreo-avanzado.ipynb">notebook</a> | <a href="{{ site.baseurl }}/episodes/scripts/05-muestreo-avanzado.py">script</a>)
466248

0 commit comments

Comments
 (0)