From 1e67592727b7f453069ce36121783e9dcf00c18e Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Thu, 31 Oct 2024 01:29:52 -0500 Subject: [PATCH] Update OpenMM Colab notebooks --- .trunk/trunk.yaml | 4 +- examples/README.md | 2 +- examples/openmm/Harmonic_Bias.ipynb | 459 ------------------ examples/openmm/Harmonic_Bias.md | 224 --------- examples/openmm/metad/Metadynamics-ADP.ipynb | 127 ++--- examples/openmm/metad/Metadynamics-ADP.md | 100 ++-- .../openmm/metad/nacl/Metadynamics_NaCl.ipynb | 123 ++--- .../openmm/metad/nacl/Metadynamics_NaCl.md | 96 ++-- .../openmm/spectral_abf/ADP_SpectralABF.ipynb | 114 ++--- .../openmm/spectral_abf/ADP_SpectralABF.md | 88 +--- 10 files changed, 183 insertions(+), 1154 deletions(-) delete mode 100644 examples/openmm/Harmonic_Bias.ipynb delete mode 100644 examples/openmm/Harmonic_Bias.md diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 53c261b5..e57df145 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -41,7 +41,7 @@ lint: paths: - examples/Advanced_Sampling_Introduction.md - examples/Installing_a_PySAGES_Environment.md - - examples/openmm/Harmonic_Bias.md + - examples/openmm/harmonic_bias/Harmonic_Bias.md - examples/hoomd-blue/ann/Butane_ANN.md - examples/hoomd-blue/harmonic_bias/Harmonic_Bias.md - examples/openmm/metad/Metadynamics-ADP.md @@ -55,7 +55,7 @@ lint: paths: - examples/Advanced_Sampling_Introduction.ipynb - examples/Installing_a_PySAGES_Environment.ipynb - - examples/openmm/Harmonic_Bias.ipynb + - examples/openmm/harmonic_bias/Harmonic_Bias.ipynb - examples/hoomd-blue/ann/Butane_ANN.ipynb - examples/hoomd-blue/harmonic_bias/Harmonic_Bias.ipynb - examples/openmm/metad/Metadynamics-ADP.ipynb diff --git a/examples/README.md b/examples/README.md index d61dfaf4..4e524ebb 100644 --- a/examples/README.md +++ b/examples/README.md @@ -45,7 +45,7 @@ Examples for Methods using OpenMM can be found in the subfolder [openmm](openmm) ### OpenMM notebooks -- Harmonic bias for the dihedral angle of Alanine Dipeptide: [![Harmonic Bias](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SSAGESLabs/PySAGES/blob/main/examples/openmm/Harmonic_Bias.ipynb) +- Harmonic bias for the dihedral angle of Alanine Dipeptide: [![Harmonic Bias](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SSAGESLabs/PySAGES/blob/main/examples/openmm/harmonic_bias/Harmonic_Bias.ipynb) - Metadynamics sampling with Alanine Dipeptide: [![Metadynamics](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SSAGESLabs/PySAGES/blob/main/examples/openmm/metad/Metadynamics-ADP.ipynb) - Metadynamics sampling with NaCL [![MetadynamicsNaCl](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SSAGESLabs/PySAGES/blob/main/examples/openmm/metad/nacl/Metadynamics_NaCl.ipynb) - Spectral ABF sampling with Alanine Dipeptide: [![SpectralABF](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SSAGESLabs/PySAGES/blob/main/examples/openmm/spectral_abf/ADP_SpectralABF.ipynb) diff --git a/examples/openmm/Harmonic_Bias.ipynb b/examples/openmm/Harmonic_Bias.ipynb deleted file mode 100644 index 678a321f..00000000 --- a/examples/openmm/Harmonic_Bias.ipynb +++ /dev/null @@ -1,459 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "_UgEohXC8n0g" - }, - "source": [ - "\n", - "# Setting up the environment\n", - "\n", - "First, we are setting up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin. We copy it from Google Drive and install PySAGES for it. We also have a Google Colab that performs this installation for reference, but that requires permissions that we do not want on our Google Drive.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "id": "nMThqa-DjVcb" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "BASE_URL=\"https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7\"\n", - "wget -q --load-cookies /tmp/cookies.txt \"$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\\w+).*/\\1\\n/p')\" -O pysages-env.zip\n", - "rm -rf /tmp/cookies.txt" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "25H3kl03wzJe", - "outputId": "528d12be-8cc4-42d9-d460-692d46a0e662" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "env: PYSAGES_ENV=/env/pysages\n" - ] - } - ], - "source": [ - "%env PYSAGES_ENV=/env/pysages" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "id": "CPkgxfj6w4te" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "mkdir -p $PYSAGES_ENV .\n", - "unzip -qquo pysages-env.zip -d $PYSAGES_ENV" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "id": "JMO5fiRTxAWB" - }, - "outputs": [], - "source": [ - "import os\n", - "import sys\n", - "\n", - "ver = sys.version_info\n", - "\n", - "sys.path.append(os.environ[\"PYSAGES_ENV\"] + \"/lib/python\" + str(ver.major) + \".\" + str(ver.minor) + \"/site-packages/\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "lf2KeHt5_eFv" - }, - "source": [ - "\n", - "## PySAGES\n", - "\n", - "The next step is to install PySAGES.\n", - "First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "mx0IRythaTyG" - }, - "source": [ - "\n", - "We test the jax installation and check the versions.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "Z4E914qBHbZS", - "outputId": "56c47936-19c1-4de8-fbc7-1cace7282498" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0.2.27\n", - "0.1.75\n" - ] - } - ], - "source": [ - "import jax\n", - "import jaxlib\n", - "print(jax.__version__)\n", - "print(jaxlib.__version__)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "vtAmA51IAYxn" - }, - "source": [ - "\n", - "Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "id": "xYRGOcFJjEE6" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "rm -rf PySAGES\n", - "git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null\n", - "cd PySAGES\n", - "pip install -q . &> /dev/null" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "h5xD1zfj-J2z" - }, - "source": [ - "\n", - "# Harmonic Bias simulations\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "id": "OIyRfOU9_cEJ" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "mkdir /content/harmonic-bias\n", - "cd /content/harmonic-bias" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Uh2y2RXDDZub" - }, - "source": [ - "\n", - "A harmonic bias simulation constraints a collective variable with a harmonic potential. This is useful for a variety of advanced sampling methods, in particular, umbrella sampling.\n", - "\n", - "For this Colab, we are using alanine dipeptide as the example molecule, a system widely-used for benchmarking enhanced sampling methods. So first, we fetch the molecule from the examples of PySAGES.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "id": "5fxJMNyE-RdA" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "cp /content/PySAGES/examples/inputs/alanine-dipeptide/adp-explicit.pdb ./" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "SqaG8YdK__FU" - }, - "source": [ - "\n", - "Next we load the PySAGES/OpenMM environment.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "P6kPLtGI_-66", - "outputId": "98e496cb-b78d-47bf-8b96-f2af942b10fc" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n" - ] - } - ], - "source": [ - "from pysages.colvars import DihedralAngle\n", - "from pysages.methods import HarmonicBias, HistogramLogger\n", - "import numpy as np\n", - "from pysages.utils import try_import\n", - "\n", - "import pysages\n", - "\n", - "openmm = try_import(\"openmm\", \"simtk.openmm\")\n", - "unit = try_import(\"openmm.unit\", \"simtk.unit\")\n", - "app = try_import(\"openmm.app\", \"simtk.openmm.app\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "3TV4h_WEAdSm" - }, - "source": [ - "\n", - "Next, we write a function that can generate an execution context for OpenMM. This is everything you would normally write in an OpenMM script, just wrapped as a function that returns the context of the simulation.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "id": "GAGw0s_cAcgP" - }, - "outputs": [], - "source": [ - "\"\"\"\n", - "Generates a simulation context, we pass this function to the attribute `run` of our sampling method.\n", - "\"\"\"\n", - "def generate_simulation(**kwargs):\n", - " pdb_filename = \"adp-explicit.pdb\"\n", - " T = 298.15 * unit.kelvin\n", - " dt = 2.0 * unit.femtoseconds\n", - " pdb = app.PDBFile(pdb_filename)\n", - "\n", - " ff = app.ForceField(\"amber99sb.xml\", \"tip3p.xml\")\n", - " cutoff_distance = 1.0 * unit.nanometer\n", - " topology = pdb.topology\n", - " system = ff.createSystem(\n", - " topology, constraints = app.HBonds, nonbondedMethod = app.NoCutoff,\n", - " nonbondedCutoff = cutoff_distance\n", - " )\n", - "\n", - " positions = pdb.getPositions(asNumpy = True)\n", - "\n", - " integrator = openmm.LangevinIntegrator(T, 1 / unit.picosecond, dt)\n", - "\n", - " simulation = app.Simulation(topology, system, integrator)\n", - " simulation.context.setPositions(positions)\n", - " simulation.minimizeEnergy()\n", - "\n", - " return simulation" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "YtUoUMEdKtH8" - }, - "source": [ - "\n", - "The next step is to define the collective variable (CV). In this case, we choose the two dihedral angles on the molecule as defined by the atom positions. We also choose an equilibrium value to constrain the dihedrals and the corresponding spring constant.\n", - "The `HarmonicBias` class is responsible for introducing the bias into the simulation run.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "id": "zEH5jrRoKszT" - }, - "outputs": [], - "source": [ - "cvs = (DihedralAngle((4, 6, 8, 14)), DihedralAngle((6, 8, 14, 16)))\n", - "center =[ -0.33*np.pi, -0.4*np.pi]\n", - "k = 100\n", - "method = HarmonicBias(cvs, k, center)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "sqKuZo92K9n9" - }, - "source": [ - "\n", - "We now define a Histogram callback to log the measured values of the CVs and run the simulation for $10^4$ time steps. The `HistogramLogger` collects the state of the collective variable during the run.\n", - "Make sure to run with GPU support. Using the CPU platform with OpenMM is possible and supported, but can take a very long time.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "id": "-XKSe3os_-Rg" - }, - "outputs": [], - "source": [ - "callback = HistogramLogger(50)\n", - "pysages.run(method, generate_simulation, int(1e4), callback)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "z8V0iX70RF1m" - }, - "source": [ - "\n", - "Next, we want to plot the histogram as recorded from the simulations.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "id": "Mvq9CWdg_qxl" - }, - "outputs": [], - "source": [ - "bins = 25\n", - "lim = (-np.pi/2, -np.pi/4)\n", - "lims = [lim for i in range(2)]\n", - "hist, edges = callback.get_histograms(bins=bins, range=lims)\n", - "hist_list = [np.sum(hist, axis=(0)), np.sum(hist, axis=(1))]" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 301 - }, - "id": "mxZVBr2FR5FJ", - "outputId": "2d0d189b-a1b8-400d-92cd-0fbbeaa783e8" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "fig, ax = plt.subplots()\n", - "\n", - "ax.set_xlabel(r\"CV $\\xi_i$\")\n", - "ax.set_ylabel(r\"$p(\\xi_i)$\")\n", - "\n", - "x = np.linspace(lim[0], lim[1], hist_list[0].shape[0])\n", - "\n", - "for i in range(len(hist_list)):\n", - " (line,) = ax.plot(x, hist_list[i], label=\"i= {0}\".format(i))\n", - "\n", - "ax.legend(loc=\"best\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "m9JjGXq_ha-6" - }, - "source": [ - "\n", - "We see how the dihedral angles are distributed. The histograms are not perfect in this example because we ran the simulation only for a few time steps and hence sampling is quite limited.\n" - ] - } - ], - "metadata": { - "accelerator": "GPU", - "colab": { - "name": "Harmonic-Bias-PySAGES-OpenMM.ipynb", - "provenance": [] - }, - "jupytext": { - "formats": "ipynb,md" - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.2" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/openmm/Harmonic_Bias.md b/examples/openmm/Harmonic_Bias.md deleted file mode 100644 index 160717c7..00000000 --- a/examples/openmm/Harmonic_Bias.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -jupyter: - jupytext: - formats: ipynb,md - text_representation: - extension: .md - format_name: markdown - format_version: '1.3' - jupytext_version: 1.16.4 - kernelspec: - display_name: Python 3 - language: python - name: python3 ---- - - - -# Setting up the environment - -First, we are setting up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin. We copy it from Google Drive and install PySAGES for it. We also have a Google Colab that performs this installation for reference, but that requires permissions that we do not want on our Google Drive. - - - -```bash id="nMThqa-DjVcb" - -BASE_URL="https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7" -wget -q --load-cookies /tmp/cookies.txt "$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\w+).*/\1\n/p')" -O pysages-env.zip -rm -rf /tmp/cookies.txt -``` - -```python colab={"base_uri": "https://localhost:8080/"} id="25H3kl03wzJe" outputId="528d12be-8cc4-42d9-d460-692d46a0e662" -%env PYSAGES_ENV=/env/pysages -``` - -```bash id="CPkgxfj6w4te" - -mkdir -p $PYSAGES_ENV . -unzip -qquo pysages-env.zip -d $PYSAGES_ENV -``` - -```python id="JMO5fiRTxAWB" -import os -import sys - -ver = sys.version_info - -sys.path.append(os.environ["PYSAGES_ENV"] + "/lib/python" + str(ver.major) + "." + str(ver.minor) + "/site-packages/") -``` - - - -## PySAGES - -The next step is to install PySAGES. -First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details. - - - - - -We test the jax installation and check the versions. - - - -```python colab={"base_uri": "https://localhost:8080/"} id="Z4E914qBHbZS" outputId="56c47936-19c1-4de8-fbc7-1cace7282498" -import jax -import jaxlib -print(jax.__version__) -print(jaxlib.__version__) -``` - - - -Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself. - - - -```bash id="xYRGOcFJjEE6" - -rm -rf PySAGES -git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null -cd PySAGES -pip install -q . &> /dev/null -``` - - - -# Harmonic Bias simulations - - - -```bash id="OIyRfOU9_cEJ" - -mkdir /content/harmonic-bias -cd /content/harmonic-bias -``` - - - -A harmonic bias simulation constraints a collective variable with a harmonic potential. This is useful for a variety of advanced sampling methods, in particular, umbrella sampling. - -For this Colab, we are using alanine dipeptide as the example molecule, a system widely-used for benchmarking enhanced sampling methods. So first, we fetch the molecule from the examples of PySAGES. - - - -```bash id="5fxJMNyE-RdA" - -cp /content/PySAGES/examples/inputs/alanine-dipeptide/adp-explicit.pdb ./ -``` - - - -Next we load the PySAGES/OpenMM environment. - - - -```python colab={"base_uri": "https://localhost:8080/"} id="P6kPLtGI_-66" outputId="98e496cb-b78d-47bf-8b96-f2af942b10fc" -from pysages.colvars import DihedralAngle -from pysages.methods import HarmonicBias, HistogramLogger -import numpy as np -from pysages.utils import try_import - -import pysages - -openmm = try_import("openmm", "simtk.openmm") -unit = try_import("openmm.unit", "simtk.unit") -app = try_import("openmm.app", "simtk.openmm.app") -``` - - - -Next, we write a function that can generate an execution context for OpenMM. This is everything you would normally write in an OpenMM script, just wrapped as a function that returns the context of the simulation. - - - -```python id="GAGw0s_cAcgP" -""" -Generates a simulation context, we pass this function to the attribute `run` of our sampling method. -""" -def generate_simulation(**kwargs): - pdb_filename = "adp-explicit.pdb" - T = 298.15 * unit.kelvin - dt = 2.0 * unit.femtoseconds - pdb = app.PDBFile(pdb_filename) - - ff = app.ForceField("amber99sb.xml", "tip3p.xml") - cutoff_distance = 1.0 * unit.nanometer - topology = pdb.topology - system = ff.createSystem( - topology, constraints = app.HBonds, nonbondedMethod = app.NoCutoff, - nonbondedCutoff = cutoff_distance - ) - - positions = pdb.getPositions(asNumpy = True) - - integrator = openmm.LangevinIntegrator(T, 1 / unit.picosecond, dt) - - simulation = app.Simulation(topology, system, integrator) - simulation.context.setPositions(positions) - simulation.minimizeEnergy() - - return simulation -``` - - - -The next step is to define the collective variable (CV). In this case, we choose the two dihedral angles on the molecule as defined by the atom positions. We also choose an equilibrium value to constrain the dihedrals and the corresponding spring constant. -The `HarmonicBias` class is responsible for introducing the bias into the simulation run. - - - -```python id="zEH5jrRoKszT" -cvs = (DihedralAngle((4, 6, 8, 14)), DihedralAngle((6, 8, 14, 16))) -center =[ -0.33*np.pi, -0.4*np.pi] -k = 100 -method = HarmonicBias(cvs, k, center) -``` - - - -We now define a Histogram callback to log the measured values of the CVs and run the simulation for $10^4$ time steps. The `HistogramLogger` collects the state of the collective variable during the run. -Make sure to run with GPU support. Using the CPU platform with OpenMM is possible and supported, but can take a very long time. - - - -```python id="-XKSe3os_-Rg" -callback = HistogramLogger(50) -pysages.run(method, generate_simulation, int(1e4), callback) -``` - - - -Next, we want to plot the histogram as recorded from the simulations. - - - -```python id="Mvq9CWdg_qxl" -bins = 25 -lim = (-np.pi/2, -np.pi/4) -lims = [lim for i in range(2)] -hist, edges = callback.get_histograms(bins=bins, range=lims) -hist_list = [np.sum(hist, axis=(0)), np.sum(hist, axis=(1))] -``` - -```python colab={"base_uri": "https://localhost:8080/", "height": 301} id="mxZVBr2FR5FJ" outputId="2d0d189b-a1b8-400d-92cd-0fbbeaa783e8" -import matplotlib.pyplot as plt -fig, ax = plt.subplots() - -ax.set_xlabel(r"CV $\xi_i$") -ax.set_ylabel(r"$p(\xi_i)$") - -x = np.linspace(lim[0], lim[1], hist_list[0].shape[0]) - -for i in range(len(hist_list)): - (line,) = ax.plot(x, hist_list[i], label="i= {0}".format(i)) - -ax.legend(loc="best") -``` - - - -We see how the dihedral angles are distributed. The histograms are not perfect in this example because we ran the simulation only for a few time steps and hence sampling is quite limited. - - diff --git a/examples/openmm/metad/Metadynamics-ADP.ipynb b/examples/openmm/metad/Metadynamics-ADP.ipynb index 671c4b89..9779b12f 100644 --- a/examples/openmm/metad/Metadynamics-ADP.ipynb +++ b/examples/openmm/metad/Metadynamics-ADP.ipynb @@ -3,14 +3,13 @@ { "cell_type": "markdown", "metadata": { - "id": "T-Qkg9C9n7Cc" + "id": "_UgEohXC8n0g" }, "source": [ - "\n", "# Setting up the environment\n", "\n", - "First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin.\n", - "We copy it from Google Drive and install PySAGES for it.\n" + "First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the openmm-dlext plugin.\n", + "We download it from Google Drive and make it visible to the running python process in this Colab instance." ] }, { @@ -24,8 +23,11 @@ "%%bash\n", "\n", "BASE_URL=\"https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7\"\n", - "wget -q --load-cookies /tmp/cookies.txt \"$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\\w+).*/\\1\\n/p')\" -O pysages-env.zip\n", - "rm -rf /tmp/cookies.txt" + "COOKIES=\"/tmp/cookies.txt\"\n", + "CONFIRMATION=\"$(wget -q --save-cookies $COOKIES --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\\w+).*/\\1\\n/p')\"\n", + "\n", + "wget -q --load-cookies $COOKIES \"$BASE_URL&confirm=$CONFIRMATION\" -O pysages-env.zip\n", + "rm -rf $COOKIES" ] }, { @@ -35,8 +37,8 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "id": "KRPmkpd9n_NG", - "outputId": "5e474d51-1c66-4d16-bab9-29747fd9d466" + "id": "25H3kl03wzJe", + "outputId": "528d12be-8cc4-42d9-d460-692d46a0e662" }, "outputs": [ { @@ -55,7 +57,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "id": "J7OY5K9VoBBh" + "id": "CPkgxfj6w4te" }, "outputs": [], "source": [ @@ -69,7 +71,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "id": "EMAWp8VloIk4" + "id": "JMO5fiRTxAWB" }, "outputs": [], "source": [ @@ -79,46 +81,18 @@ "ver = sys.version_info\n", "sys.path.append(os.environ[\"PYSAGES_ENV\"] + \"/lib/python\" + str(ver.major) + \".\" + str(ver.minor) + \"/site-packages/\")\n", "\n", - "os.environ[\"XLA_FLAGS\"] = \"--xla_gpu_strict_conv_algorithm_picker=false\"\n", "os.environ[\"LD_LIBRARY_PATH\"] = \"/usr/lib/x86_64-linux-gnu:\" + os.environ[\"LD_LIBRARY_PATH\"]" ] }, { "cell_type": "markdown", "metadata": { - "id": "we_mTkFioS6R" + "id": "lf2KeHt5_eFv" }, "source": [ - "\n", "## PySAGES\n", "\n", - "The next step is to install PySAGES.\n", - "First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "vK0RZtbroQWe" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "pip install -q --upgrade pip\n", - "# Installs the wheel compatible with CUDA.\n", - "pip install -q --upgrade \"jax[cuda]\" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html &> /dev/null" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "wAtjM-IroYX8" - }, - "source": [ - "\n", - "Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself.\n" + "The next step is to install PySAGES. We retrieve the latest version from GitHub and add its dependecies via `pip`." ] }, { @@ -129,12 +103,7 @@ }, "outputs": [], "source": [ - "%%bash\n", - "\n", - "rm -rf PySAGES\n", - "git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null\n", - "cd PySAGES\n", - "pip install -q . &> /dev/null" + "!pip install -qq git+https://github.com/SSAGESLabs/PySAGES.git > /dev/null" ] }, { @@ -143,8 +112,7 @@ "id": "KBFVcG1FoeMq" }, "source": [ - "\n", - "# Metadynamics-biased simulations\n" + "# Metadynamics-biased simulations" ] }, { @@ -171,8 +139,7 @@ "%%bash\n", "\n", "# Download pdb file with the initial configuration of our system\n", - "PDB_URL=\"https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb\"\n", - "wget -q $PDB_URL" + "wget -q https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb" ] }, { @@ -183,23 +150,19 @@ }, "outputs": [], "source": [ - "import numpy\n", - "\n", - "from pysages.utils import try_import\n", + "import numpy as np\n", + "import openmm\n", + "import openmm.app as app\n", + "import openmm.unit as unit\n", "\n", - "openmm = try_import(\"openmm\", \"simtk.openmm\")\n", - "unit = try_import(\"openmm.unit\", \"simtk.unit\")\n", - "app = try_import(\"openmm.app\", \"simtk.openmm.app\")\n", - "\n", - "\n", - "pi = numpy.pi\n", "\n", + "pi = np.pi\n", "T = 298.15 * unit.kelvin\n", "dt = 2.0 * unit.femtoseconds\n", "adp_pdb = \"adp-vacuum.pdb\"\n", "\n", "\n", - "def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt):\n", + "def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt, **kwargs):\n", " pdb = app.PDBFile(pdb_filename)\n", "\n", " ff = app.ForceField(\"amber99sb.xml\")\n", @@ -249,11 +212,11 @@ }, "outputs": [], "source": [ + "import pysages\n", + "\n", "from pysages.grids import Grid\n", "from pysages.colvars import DihedralAngle\n", - "from pysages.methods import Metadynamics\n", - "\n", - "import pysages" + "from pysages.methods import Metadynamics" ] }, { @@ -262,7 +225,6 @@ "id": "LknkRvo1o4av" }, "source": [ - "\n", "The next step is to define the collective variable (CV). In this case, we choose the so called $\\phi$ and $\\psi$ dihedral angles of alanine dipeptide.\n", "\n", "For this example we will use the well-tempered version without grids. But these options can be configured.\n", @@ -271,7 +233,7 @@ "\n", "We also define a grid, which can be used as optional parameter to accelerate Metadynamics by approximating the biasing potential and its gradient by the closest value at the centers of the grid cells.\n", "\n", - "_Note:_ when setting $\\Delta T$ we need to also provide a value for $k_B$ that matches the internal units used by the backend.\n" + "_Note:_ when setting $\\Delta T$ we need to also provide a value for $k_B$ that matches the internal units used by the backend." ] }, { @@ -310,10 +272,9 @@ "id": "Fz8BfU34pA_N" }, "source": [ - "\n", "We now simulate the number of time steps set above.\n", "Make sure to run with GPU support, otherwise, it can take a very long time.\n", - "On the GPU this should run in around half an hour.\n" + "On the GPU this should run in around half an hour." ] }, { @@ -333,10 +294,9 @@ "id": "PXBKUfK0p9T2" }, "source": [ - "\n", "## Analysis\n", "\n", - "Let's plot the negative of the sum of gaussians accumulated. This will get close to the free energy surface for long enough simulations (larger than what is practical to run on Colab, but we should get close enough for illustration purposes here).\n" + "Let's plot the negative of the sum of gaussians accumulated. This will get close to the free energy surface for long enough simulations (larger than what is practical to run on Colab, but we should get close enough for illustration purposes here)." ] }, { @@ -357,8 +317,7 @@ "id": "6mrlIOfoszBJ" }, "source": [ - "\n", - "We are now going to gather the information for the heights, standard deviations and centers of the accumulated gaussians and build a function to evaluate their sum at any point of the collective variable space.\n" + "We are now going to gather the information for the heights, standard deviations and centers of the accumulated gaussians and build a function to evaluate their sum at any point of the collective variable space." ] }, { @@ -370,7 +329,7 @@ "outputs": [], "source": [ "fe_result = pysages.analyze(run_result)\n", - "metapotential = fe_result['metapotential']" + "metapotential = fe_result[\"metapotential\"]" ] }, { @@ -408,8 +367,7 @@ "id": "Kf_CMdih90Cd" }, "source": [ - "\n", - "And plot it.\n" + "And plot it." ] }, { @@ -461,8 +419,7 @@ "id": "a-LGmeZ_3_m-" }, "source": [ - "\n", - "Lastly, we plot the height of the gaussians as a function of time and observe that their height decreases at an exponential rate as expected for well-tempered metadynamics.\n" + "Lastly, we plot the height of the gaussians as a function of time and observe that their height decreases at an exponential rate as expected for well-tempered metadynamics." ] }, { @@ -491,24 +448,16 @@ } ], "source": [ - "_dt = dt #method.context[0].sampler.snapshot.dt\n", - "ts = _dt * 1e-3 * numpy.arange(0, fe_result['heights'].size) * run_result.method.stride\n", + "ts = dt * 1e-3 * np.arange(0, fe_result[\"heights\"].size) * run_result.method.stride\n", "\n", "fig, ax = plt.subplots(dpi=120)\n", - "ax.plot(ts, fe_result['heights'], \"o\", mfc=\"none\", ms=4)\n", + "\n", "ax.set_xlabel(\"time [ns]\")\n", "ax.set_ylabel(\"height [kJ/mol]\")\n", - "plt.show()" + "ax.plot(ts, fe_result[\"heights\"], \"o\", mfc=\"none\", ms=4)\n", + "\n", + "fig.show()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "R6rEuwWAZ8Qp" - }, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/examples/openmm/metad/Metadynamics-ADP.md b/examples/openmm/metad/Metadynamics-ADP.md index fb430387..b30b119a 100644 --- a/examples/openmm/metad/Metadynamics-ADP.md +++ b/examples/openmm/metad/Metadynamics-ADP.md @@ -13,77 +13,55 @@ jupyter: name: python3 --- - - + # Setting up the environment -First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin. -We copy it from Google Drive and install PySAGES for it. - +First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the openmm-dlext plugin. +We download it from Google Drive and make it visible to the running python process in this Colab instance. ```bash id="3eTbKklCnyd_" BASE_URL="https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7" -wget -q --load-cookies /tmp/cookies.txt "$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\w+).*/\1\n/p')" -O pysages-env.zip -rm -rf /tmp/cookies.txt +COOKIES="/tmp/cookies.txt" +CONFIRMATION="$(wget -q --save-cookies $COOKIES --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\w+).*/\1\n/p')" + +wget -q --load-cookies $COOKIES "$BASE_URL&confirm=$CONFIRMATION" -O pysages-env.zip +rm -rf $COOKIES ``` -```python colab={"base_uri": "https://localhost:8080/"} id="KRPmkpd9n_NG" outputId="5e474d51-1c66-4d16-bab9-29747fd9d466" +```python colab={"base_uri": "https://localhost:8080/"} id="25H3kl03wzJe" outputId="528d12be-8cc4-42d9-d460-692d46a0e662" %env PYSAGES_ENV=/env/pysages ``` -```bash id="J7OY5K9VoBBh" +```bash id="CPkgxfj6w4te" mkdir -p $PYSAGES_ENV . unzip -qquo pysages-env.zip -d $PYSAGES_ENV ``` -```python id="EMAWp8VloIk4" +```python id="JMO5fiRTxAWB" import os import sys ver = sys.version_info sys.path.append(os.environ["PYSAGES_ENV"] + "/lib/python" + str(ver.major) + "." + str(ver.minor) + "/site-packages/") -os.environ["XLA_FLAGS"] = "--xla_gpu_strict_conv_algorithm_picker=false" os.environ["LD_LIBRARY_PATH"] = "/usr/lib/x86_64-linux-gnu:" + os.environ["LD_LIBRARY_PATH"] ``` - - + ## PySAGES -The next step is to install PySAGES. -First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details. - +The next step is to install PySAGES. We retrieve the latest version from GitHub and add its dependecies via `pip`. -```bash id="vK0RZtbroQWe" - -pip install -q --upgrade pip -# Installs the wheel compatible with CUDA. -pip install -q --upgrade "jax[cuda]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html &> /dev/null -``` - - - -Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself. - - - -```bash id="B-HB9CzioV5j" - -rm -rf PySAGES -git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null -cd PySAGES -pip install -q . &> /dev/null +```python id="B-HB9CzioV5j" +!pip install -qq git+https://github.com/SSAGESLabs/PySAGES.git > /dev/null ``` - # Metadynamics-biased simulations - @@ -98,28 +76,23 @@ For this Colab, we are using alanine peptide in vacuum as example system. ```bash id="fre3-LYso1hh" # Download pdb file with the initial configuration of our system -PDB_URL="https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb" -wget -q $PDB_URL +wget -q https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb ``` ```python id="BBvC7Spoog82" -import numpy +import numpy as np +import openmm +import openmm.app as app +import openmm.unit as unit -from pysages.utils import try_import - -openmm = try_import("openmm", "simtk.openmm") -unit = try_import("openmm.unit", "simtk.unit") -app = try_import("openmm.app", "simtk.openmm.app") - - -pi = numpy.pi +pi = np.pi T = 298.15 * unit.kelvin dt = 2.0 * unit.femtoseconds adp_pdb = "adp-vacuum.pdb" -def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt): +def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt, **kwargs): pdb = app.PDBFile(pdb_filename) ff = app.ForceField("amber99sb.xml") @@ -158,15 +131,14 @@ Next, we load PySAGES and the relevant classes and methods for our problem ```python id="fpMg-o8WomAA" +import pysages + from pysages.grids import Grid from pysages.colvars import DihedralAngle from pysages.methods import Metadynamics - -import pysages ``` - The next step is to define the collective variable (CV). In this case, we choose the so called $\phi$ and $\psi$ dihedral angles of alanine dipeptide. For this example we will use the well-tempered version without grids. But these options can be configured. @@ -176,7 +148,6 @@ We set the initial height, standard deviation and deposition frequency `stride` We also define a grid, which can be used as optional parameter to accelerate Metadynamics by approximating the biasing potential and its gradient by the closest value at the centers of the grid cells. _Note:_ when setting $\Delta T$ we need to also provide a value for $k_B$ that matches the internal units used by the backend. - ```python id="B1Z8FWz0o7u_" @@ -203,11 +174,9 @@ method = Metadynamics(cvs, height, sigma, stride, ngauss, deltaT=deltaT, kB=kB, ``` - We now simulate the number of time steps set above. Make sure to run with GPU support, otherwise, it can take a very long time. On the GPU this should run in around half an hour. - ```python id="K951m4BbpUar" @@ -215,11 +184,9 @@ run_result = pysages.run(method, generate_simulation, timesteps) ``` - ## Analysis Let's plot the negative of the sum of gaussians accumulated. This will get close to the free energy surface for long enough simulations (larger than what is practical to run on Colab, but we should get close enough for illustration purposes here). - ```python id="X69d1R7OpW4P" @@ -228,14 +195,12 @@ from pysages.approxfun import compute_mesh ``` - We are now going to gather the information for the heights, standard deviations and centers of the accumulated gaussians and build a function to evaluate their sum at any point of the collective variable space. - ```python id="zJqvpbw8szxR" fe_result = pysages.analyze(run_result) -metapotential = fe_result['metapotential'] +metapotential = fe_result["metapotential"] ``` @@ -257,9 +222,7 @@ A = A.reshape(plot_grid.shape) ``` - And plot it. - ```python colab={"base_uri": "https://localhost:8080/", "height": 461} id="3s9LL9apBMVb" outputId="55abf4e5-fef0-4faa-bf01-9719cbe8aa2b" @@ -281,22 +244,17 @@ plt.show() ``` - Lastly, we plot the height of the gaussians as a function of time and observe that their height decreases at an exponential rate as expected for well-tempered metadynamics. - ```python colab={"base_uri": "https://localhost:8080/", "height": 457} id="SI_fhUW9CGlP" outputId="5d32f99d-4911-44bb-9d89-69c3e6212cb7" -_dt = dt #method.context[0].sampler.snapshot.dt -ts = _dt * 1e-3 * numpy.arange(0, fe_result['heights'].size) * run_result.method.stride +ts = dt * 1e-3 * np.arange(0, fe_result["heights"].size) * run_result.method.stride fig, ax = plt.subplots(dpi=120) -ax.plot(ts, fe_result['heights'], "o", mfc="none", ms=4) + ax.set_xlabel("time [ns]") ax.set_ylabel("height [kJ/mol]") -plt.show() -``` - -```python id="R6rEuwWAZ8Qp" +ax.plot(ts, fe_result["heights"], "o", mfc="none", ms=4) +fig.show() ``` diff --git a/examples/openmm/metad/nacl/Metadynamics_NaCl.ipynb b/examples/openmm/metad/nacl/Metadynamics_NaCl.ipynb index d7c8f5d6..ee946588 100644 --- a/examples/openmm/metad/nacl/Metadynamics_NaCl.ipynb +++ b/examples/openmm/metad/nacl/Metadynamics_NaCl.ipynb @@ -3,14 +3,13 @@ { "cell_type": "markdown", "metadata": { - "id": "T-Qkg9C9n7Cc" + "id": "_UgEohXC8n0g" }, "source": [ - "\n", "# Setting up the environment\n", "\n", - "First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin.\n", - "We copy it from Google Drive and install PySAGES for it.\n" + "First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the openmm-dlext plugin.\n", + "We download it from Google Drive and make it visible to the running python process in this Colab instance." ] }, { @@ -24,19 +23,18 @@ "%%bash\n", "\n", "BASE_URL=\"https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7\"\n", - "wget -q --load-cookies /tmp/cookies.txt \"$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\\w+).*/\\1\\n/p')\" -O pysages-env.zip\n", - "rm -rf /tmp/cookies.txt" + "COOKIES=\"/tmp/cookies.txt\"\n", + "CONFIRMATION=\"$(wget -q --save-cookies $COOKIES --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\\w+).*/\\1\\n/p')\"\n", + "\n", + "wget -q --load-cookies $COOKIES \"$BASE_URL&confirm=$CONFIRMATION\" -O pysages-env.zip\n", + "rm -rf $COOKIES" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "KRPmkpd9n_NG", - "outputId": "d1929eaa-42df-4a7d-afed-6094eab16e72" + "id": "25H3kl03wzJe" }, "outputs": [ { @@ -55,7 +53,7 @@ "cell_type": "code", "execution_count": 3, "metadata": { - "id": "J7OY5K9VoBBh" + "id": "CPkgxfj6w4te" }, "outputs": [], "source": [ @@ -69,7 +67,7 @@ "cell_type": "code", "execution_count": 5, "metadata": { - "id": "EMAWp8VloIk4" + "id": "JMO5fiRTxAWB" }, "outputs": [], "source": [ @@ -79,62 +77,29 @@ "ver = sys.version_info\n", "sys.path.append(os.environ[\"PYSAGES_ENV\"] + \"/lib/python\" + str(ver.major) + \".\" + str(ver.minor) + \"/site-packages/\")\n", "\n", - "os.environ[\"XLA_FLAGS\"] = \"--xla_gpu_strict_conv_algorithm_picker=false\"\n", "os.environ[\"LD_LIBRARY_PATH\"] = \"/usr/lib/x86_64-linux-gnu:\" + os.environ[\"LD_LIBRARY_PATH\"]" ] }, { "cell_type": "markdown", "metadata": { - "id": "we_mTkFioS6R" + "id": "lf2KeHt5_eFv" }, "source": [ - "\n", "## PySAGES\n", "\n", - "The next step is to install PySAGES.\n", - "First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details.\n" + "The next step is to install PySAGES. We retrieve the latest version from GitHub and add its dependecies via `pip`." ] }, { "cell_type": "code", "execution_count": 6, - "metadata": { - "id": "vK0RZtbroQWe" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "pip install -q --upgrade pip\n", - "# Installs the wheel compatible with CUDA.\n", - "pip install -q --upgrade \"jax[cuda]\" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html &> /dev/null" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "wAtjM-IroYX8" - }, - "source": [ - "\n", - "Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, "metadata": { "id": "B-HB9CzioV5j" }, "outputs": [], "source": [ - "%%bash\n", - "\n", - "rm -rf PySAGES\n", - "git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null\n", - "cd PySAGES\n", - "pip install -q . &> /dev/null" + "!pip install -qq git+https://github.com/SSAGESLabs/PySAGES.git > /dev/null" ] }, { @@ -143,8 +108,7 @@ "id": "KBFVcG1FoeMq" }, "source": [ - "\n", - "# Metadynamics-biased simulations\n" + "# Metadynamics-biased simulations" ] }, { @@ -153,11 +117,10 @@ "id": "0W2ukJuuojAl" }, "source": [ - "\n", "Metadynamics gradually builds a biasing potential from a sum of gaussians that are deposited one at a time every certain number of (user defined) time steps.\n", "There are two flavors of the algorithm, _Standard Metadynamics_ in which the heights of the gaussians is time independent, and _Well-tempered Metadynamics_ for which the heights of the deposited gaussians decreases depending on how frequently are visited the explored regions of collective variable space.\n", "\n", - "For this Colab, we are estimating the free energy along the distance between Na and Cl in water as example system.\n" + "For this Colab, we are estimating the free energy along the distance between Na and Cl in water as example system." ] }, { @@ -171,11 +134,10 @@ "%%bash\n", "\n", "# Download pdb file with the initial configuration of our system\n", - "cp PySAGES/examples/inputs/nacl/nacl-explicit.pdb .\n", + "wget -q https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/nacl/nacl-explicit.pdb\n", "\n", "# Download force field file\n", - "ff_URL=\"https://raw.githubusercontent.com/openmm/openmmforcefields/main/openmmforcefields/ffxml/amber/tip3p_standard.xml\"\n", - "wget -q $ff_URL" + "wget -q https://raw.githubusercontent.com/openmm/openmmforcefields/main/openmmforcefields/ffxml/amber/tip3p_standard.xml" ] }, { @@ -186,21 +148,17 @@ }, "outputs": [], "source": [ - "import numpy\n", - "\n", - "from pysages.utils import try_import\n", + "import numpy as np\n", + "import openmm\n", + "import openmm.app as app\n", + "import openmm.unit as unit\n", "\n", - "openmm = try_import(\"openmm\", \"simtk.openmm\")\n", - "unit = try_import(\"openmm.unit\", \"simtk.unit\")\n", - "app = try_import(\"openmm.app\", \"simtk.openmm.app\")\n", - "\n", - "\n", - "pi = numpy.pi\n", "\n", + "pi = np.pi\n", "T = 298.15 * unit.kelvin\n", "dt = 2.0 * unit.femtoseconds\n", "nacl_pdb = \"nacl-explicit.pdb\"\n", - "nacl_ff = 'tip3p_standard.xml'\n", + "nacl_ff = \"tip3p_standard.xml\"\n", "\n", "\n", "def generate_simulation(pdb_filename=nacl_pdb, T=T, dt=dt):\n", @@ -321,10 +279,9 @@ "id": "Fz8BfU34pA_N" }, "source": [ - "\n", "We now simulate the number of time steps set above.\n", "Make sure to run with GPU support, otherwise, it can take a very long time.\n", - "On the GPU this should run in around half an hour.\n" + "On the GPU this should run in around half an hour." ] }, { @@ -344,10 +301,9 @@ "id": "PXBKUfK0p9T2" }, "source": [ - "\n", "## Analysis\n", "\n", - "Let's plot the negative of the sum of gaussians accumulated. This will get close to the free energy surface for long enough simulations (larger than what is practical to run on Colab, but we should get close enough for illustration purposes here).\n" + "Let's plot the negative of the sum of gaussians accumulated. This will get close to the free energy surface for long enough simulations (larger than what is practical to run on Colab, but we should get close enough for illustration purposes here)." ] }, { @@ -368,8 +324,7 @@ "id": "6mrlIOfoszBJ" }, "source": [ - "\n", - "We are now going to gather the information for the heights, standard deviations and centers of the accumulated gaussians and build a function to evaluate their sum at any point of the collective variable space.\n" + "We are now going to gather the information for the heights, standard deviations and centers of the accumulated gaussians and build a function to evaluate their sum at any point of the collective variable space." ] }, { @@ -390,8 +345,7 @@ "id": "VfTQ5yeyxt8e" }, "source": [ - "\n", - "Next we use the biasing potential to estimate the free energy surface. For well-tempered metadynamics this is equal to the sum of accumulated gaussians scaled by the factor $-(T + \\Delta T)\\, / \\,\\Delta T$.\n" + "Next we use the biasing potential to estimate the free energy surface. For well-tempered metadynamics this is equal to the sum of accumulated gaussians scaled by the factor $-(T + \\Delta T)\\, / \\,\\Delta T$." ] }, { @@ -421,8 +375,7 @@ "id": "Kf_CMdih90Cd" }, "source": [ - "\n", - "And plot it.\n" + "And plot it." ] }, { @@ -460,7 +413,7 @@ "ax.set_ylim(0.1,10)\n", "\n", "#fig.savefig(\"nacl-fe.png\", dpi=fig.dpi)\n", - "plt.show()" + "fig.show()" ] }, { @@ -499,24 +452,16 @@ } ], "source": [ - "_dt = dt #method.context[0].sampler.snapshot.dt\n", - "ts = _dt * 1e-3 * numpy.arange(0, fe_result['heights'].size) * run_result.method.stride\n", + "ts = dt * 1e-3 * np.arange(0, fe_result['heights'].size) * run_result.method.stride\n", "\n", "fig, ax = plt.subplots(dpi=120)\n", + "\n", "ax.plot(ts, fe_result['heights'], \"o\", mfc=\"none\", ms=4)\n", "ax.set_xlabel(\"time [ns]\")\n", "ax.set_ylabel(\"height [kJ/mol]\")\n", - "plt.show()" + "\n", + "fig.show()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "R6rEuwWAZ8Qp" - }, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/examples/openmm/metad/nacl/Metadynamics_NaCl.md b/examples/openmm/metad/nacl/Metadynamics_NaCl.md index 97506380..06fc28e6 100644 --- a/examples/openmm/metad/nacl/Metadynamics_NaCl.md +++ b/examples/openmm/metad/nacl/Metadynamics_NaCl.md @@ -13,114 +13,85 @@ jupyter: name: python3 --- - - + # Setting up the environment -First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin. -We copy it from Google Drive and install PySAGES for it. - +First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the openmm-dlext plugin. +We download it from Google Drive and make it visible to the running python process in this Colab instance. ```bash id="3eTbKklCnyd_" BASE_URL="https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7" -wget -q --load-cookies /tmp/cookies.txt "$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\w+).*/\1\n/p')" -O pysages-env.zip -rm -rf /tmp/cookies.txt +COOKIES="/tmp/cookies.txt" +CONFIRMATION="$(wget -q --save-cookies $COOKIES --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\w+).*/\1\n/p')" + +wget -q --load-cookies $COOKIES "$BASE_URL&confirm=$CONFIRMATION" -O pysages-env.zip +rm -rf $COOKIES ``` -```python colab={"base_uri": "https://localhost:8080/"} id="KRPmkpd9n_NG" outputId="d1929eaa-42df-4a7d-afed-6094eab16e72" +```python id="25H3kl03wzJe" %env PYSAGES_ENV=/env/pysages ``` -```bash id="J7OY5K9VoBBh" +```bash id="CPkgxfj6w4te" mkdir -p $PYSAGES_ENV . unzip -qquo pysages-env.zip -d $PYSAGES_ENV ``` -```python id="EMAWp8VloIk4" +```python id="JMO5fiRTxAWB" import os import sys ver = sys.version_info sys.path.append(os.environ["PYSAGES_ENV"] + "/lib/python" + str(ver.major) + "." + str(ver.minor) + "/site-packages/") -os.environ["XLA_FLAGS"] = "--xla_gpu_strict_conv_algorithm_picker=false" os.environ["LD_LIBRARY_PATH"] = "/usr/lib/x86_64-linux-gnu:" + os.environ["LD_LIBRARY_PATH"] ``` - - + ## PySAGES -The next step is to install PySAGES. -First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details. - +The next step is to install PySAGES. We retrieve the latest version from GitHub and add its dependecies via `pip`. -```bash id="vK0RZtbroQWe" - -pip install -q --upgrade pip -# Installs the wheel compatible with CUDA. -pip install -q --upgrade "jax[cuda]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html &> /dev/null -``` - - - -Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself. - - - -```bash id="B-HB9CzioV5j" - -rm -rf PySAGES -git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null -cd PySAGES -pip install -q . &> /dev/null +```python id="B-HB9CzioV5j" +!pip install -qq git+https://github.com/SSAGESLabs/PySAGES.git > /dev/null ``` - # Metadynamics-biased simulations - - Metadynamics gradually builds a biasing potential from a sum of gaussians that are deposited one at a time every certain number of (user defined) time steps. There are two flavors of the algorithm, _Standard Metadynamics_ in which the heights of the gaussians is time independent, and _Well-tempered Metadynamics_ for which the heights of the deposited gaussians decreases depending on how frequently are visited the explored regions of collective variable space. For this Colab, we are estimating the free energy along the distance between Na and Cl in water as example system. - ```bash id="fre3-LYso1hh" # Download pdb file with the initial configuration of our system -cp PySAGES/examples/inputs/nacl/nacl-explicit.pdb . +wget -q https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/nacl/nacl-explicit.pdb # Download force field file -ff_URL="https://raw.githubusercontent.com/openmm/openmmforcefields/main/openmmforcefields/ffxml/amber/tip3p_standard.xml" -wget -q $ff_URL +wget -q https://raw.githubusercontent.com/openmm/openmmforcefields/main/openmmforcefields/ffxml/amber/tip3p_standard.xml ``` ```python id="BBvC7Spoog82" -import numpy +import numpy as np +import openmm +import openmm.app as app +import openmm.unit as unit -from pysages.utils import try_import - -openmm = try_import("openmm", "simtk.openmm") -unit = try_import("openmm.unit", "simtk.unit") -app = try_import("openmm.app", "simtk.openmm.app") - - -pi = numpy.pi +pi = np.pi T = 298.15 * unit.kelvin dt = 2.0 * unit.femtoseconds nacl_pdb = "nacl-explicit.pdb" -nacl_ff = 'tip3p_standard.xml' +nacl_ff = "tip3p_standard.xml" def generate_simulation(pdb_filename=nacl_pdb, T=T, dt=dt): @@ -214,11 +185,9 @@ method = Metadynamics(cvs, height, sigma, stride, ngauss, deltaT=deltaT, kB=kB, ``` - We now simulate the number of time steps set above. Make sure to run with GPU support, otherwise, it can take a very long time. On the GPU this should run in around half an hour. - ```python id="K951m4BbpUar" @@ -226,11 +195,9 @@ run_result = pysages.run(method, generate_simulation, timesteps) ``` - ## Analysis Let's plot the negative of the sum of gaussians accumulated. This will get close to the free energy surface for long enough simulations (larger than what is practical to run on Colab, but we should get close enough for illustration purposes here). - ```python id="X69d1R7OpW4P" @@ -239,9 +206,7 @@ from pysages.approxfun import compute_mesh ``` - We are now going to gather the information for the heights, standard deviations and centers of the accumulated gaussians and build a function to evaluate their sum at any point of the collective variable space. - ```python id="zJqvpbw8szxR" @@ -250,9 +215,7 @@ metapotential = fe_result['metapotential'] ``` - Next we use the biasing potential to estimate the free energy surface. For well-tempered metadynamics this is equal to the sum of accumulated gaussians scaled by the factor $-(T + \Delta T)\, / \,\Delta T$. - ```python id="6W7Xf0ilqAcm" @@ -270,9 +233,7 @@ A = A.reshape(plot_grid.shape) ``` - And plot it. - ```python colab={"base_uri": "https://localhost:8080/", "height": 466} id="3s9LL9apBMVb" outputId="6384612f-d75a-4541-b988-c4660ab2e570" @@ -285,7 +246,7 @@ ax.set_xlim(0.1,1.25) ax.set_ylim(0.1,10) #fig.savefig("nacl-fe.png", dpi=fig.dpi) -plt.show() +fig.show() ``` @@ -295,16 +256,13 @@ Lastly, we plot the height of the gaussians as a function of time and observe th ```python colab={"base_uri": "https://localhost:8080/", "height": 457} id="SI_fhUW9CGlP" outputId="82a23a39-2cd9-46ab-df80-fe6ac9a7cbf6" -_dt = dt #method.context[0].sampler.snapshot.dt -ts = _dt * 1e-3 * numpy.arange(0, fe_result['heights'].size) * run_result.method.stride +ts = dt * 1e-3 * np.arange(0, fe_result['heights'].size) * run_result.method.stride fig, ax = plt.subplots(dpi=120) + ax.plot(ts, fe_result['heights'], "o", mfc="none", ms=4) ax.set_xlabel("time [ns]") ax.set_ylabel("height [kJ/mol]") -plt.show() -``` - -```python id="R6rEuwWAZ8Qp" +fig.show() ``` diff --git a/examples/openmm/spectral_abf/ADP_SpectralABF.ipynb b/examples/openmm/spectral_abf/ADP_SpectralABF.ipynb index b0b67f25..c1c3e304 100644 --- a/examples/openmm/spectral_abf/ADP_SpectralABF.ipynb +++ b/examples/openmm/spectral_abf/ADP_SpectralABF.ipynb @@ -3,14 +3,13 @@ { "cell_type": "markdown", "metadata": { - "id": "T-Qkg9C9n7Cc" + "id": "_UgEohXC8n0g" }, "source": [ - "\n", "# Setting up the environment\n", "\n", - "First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin.\n", - "We copy it from Google Drive and install PySAGES for it.\n" + "First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the openmm-dlext plugin.\n", + "We download it from Google Drive and make it visible to the running python process in this Colab instance." ] }, { @@ -24,19 +23,18 @@ "%%bash\n", "\n", "BASE_URL=\"https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7\"\n", - "wget -q --load-cookies /tmp/cookies.txt \"$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\\w+).*/\\1\\n/p')\" -O pysages-env.zip\n", - "rm -rf /tmp/cookies.txt" + "COOKIES=\"/tmp/cookies.txt\"\n", + "CONFIRMATION=\"$(wget -q --save-cookies $COOKIES --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\\w+).*/\\1\\n/p')\"\n", + "\n", + "wget -q --load-cookies $COOKIES \"$BASE_URL&confirm=$CONFIRMATION\" -O pysages-env.zip\n", + "rm -rf $COOKIES" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "KRPmkpd9n_NG", - "outputId": "e577ce0d-0a62-4f48-fb05-fde3a39c2ccc" + "id": "25H3kl03wzJe" }, "outputs": [ { @@ -55,7 +53,7 @@ "cell_type": "code", "execution_count": 3, "metadata": { - "id": "J7OY5K9VoBBh" + "id": "CPkgxfj6w4te" }, "outputs": [], "source": [ @@ -69,7 +67,7 @@ "cell_type": "code", "execution_count": 5, "metadata": { - "id": "EMAWp8VloIk4" + "id": "JMO5fiRTxAWB" }, "outputs": [], "source": [ @@ -79,62 +77,29 @@ "ver = sys.version_info\n", "sys.path.append(os.environ[\"PYSAGES_ENV\"] + \"/lib/python\" + str(ver.major) + \".\" + str(ver.minor) + \"/site-packages/\")\n", "\n", - "os.environ[\"XLA_FLAGS\"] = \"--xla_gpu_strict_conv_algorithm_picker=false\"\n", "os.environ[\"LD_LIBRARY_PATH\"] = \"/usr/lib/x86_64-linux-gnu:\" + os.environ[\"LD_LIBRARY_PATH\"]" ] }, { "cell_type": "markdown", "metadata": { - "id": "we_mTkFioS6R" + "id": "lf2KeHt5_eFv" }, "source": [ - "\n", "## PySAGES\n", "\n", - "The next step is to install PySAGES.\n", - "First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details.\n" + "The next step is to install PySAGES. We retrieve the latest version from GitHub and add its dependecies via `pip`." ] }, { "cell_type": "code", "execution_count": 6, - "metadata": { - "id": "vK0RZtbroQWe" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "pip install -q --upgrade pip\n", - "# Installs the wheel compatible with CUDA.\n", - "pip install -q --upgrade \"jax[cuda]\" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html &> /dev/null" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "wAtjM-IroYX8" - }, - "source": [ - "\n", - "Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, "metadata": { "id": "B-HB9CzioV5j" }, "outputs": [], "source": [ - "%%bash\n", - "\n", - "rm -rf PySAGES\n", - "git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null\n", - "cd PySAGES\n", - "pip install -q . &> /dev/null" + "!pip install -qq git+https://github.com/SSAGESLabs/PySAGES.git > /dev/null" ] }, { @@ -143,8 +108,7 @@ "id": "KBFVcG1FoeMq" }, "source": [ - "\n", - "# SpectralABF-biased simulations\n" + "# SpectralABF-biased simulations" ] }, { @@ -153,10 +117,9 @@ "id": "0W2ukJuuojAl" }, "source": [ - "\n", "SpectralABF gradually learns a better approximation to the coefficients of a basis functions expansion of the free energy of a system, from the generalized mean forces in a similar fashion to the ABF sampling method.\n", "\n", - "For this Colab, we are using alanine peptide in vacuum as example system.\n" + "For this Colab, we are using alanine peptide in vacuum as example system." ] }, { @@ -170,8 +133,7 @@ "%%bash\n", "\n", "# Download pdb file with the initial configuration of our system\n", - "PDB_URL=\"https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb\"\n", - "wget -q $PDB_URL" + "wget -q https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb" ] }, { @@ -182,23 +144,19 @@ }, "outputs": [], "source": [ - "import numpy\n", - "\n", - "from pysages.utils import try_import\n", - "\n", - "openmm = try_import(\"openmm\", \"simtk.openmm\")\n", - "unit = try_import(\"openmm.unit\", \"simtk.unit\")\n", - "app = try_import(\"openmm.app\", \"simtk.openmm.app\")\n", - "\n", + "import numpy as np\n", + "import openmm\n", + "import openmm.app as app\n", + "import openmm.unit as unit\n", "\n", - "pi = numpy.pi\n", "\n", + "pi = np.pi\n", "T = 298.15 * unit.kelvin\n", "dt = 2.0 * unit.femtoseconds\n", "adp_pdb = \"adp-vacuum.pdb\"\n", "\n", "\n", - "def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt):\n", + "def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt, **kwargs):\n", " pdb = app.PDBFile(pdb_filename)\n", "\n", " ff = app.ForceField(\"amber99sb.xml\")\n", @@ -236,8 +194,7 @@ "id": "3UrzENm_oo6U" }, "source": [ - "\n", - "Next, we load PySAGES and the relevant classes and methods for our problem\n" + "Next, we load PySAGES and the relevant classes and methods for our problem" ] }, { @@ -261,10 +218,9 @@ "id": "LknkRvo1o4av" }, "source": [ - "\n", "The next step is to define the collective variable (CV). In this case, we choose the so called $\\phi$ and $\\psi$ dihedral angles of alanine dipeptide.\n", "\n", - "We define a grid, which will be used to indicate how we want to bin the forces that will be used to approximate the biasing potential and its gradient.\n" + "We define a grid, which will be used to indicate how we want to bin the forces that will be used to approximate the biasing potential and its gradient." ] }, { @@ -288,9 +244,8 @@ "id": "Fz8BfU34pA_N" }, "source": [ - "\n", "We now simulate the number of time steps set above.\n", - "Make sure to run with GPU support, otherwise, it can take a very long time.\n" + "Make sure to run with GPU support, otherwise, it can take a very long time." ] }, { @@ -310,10 +265,9 @@ "id": "PXBKUfK0p9T2" }, "source": [ - "\n", "## Analysis\n", "\n", - "Let's plot the free energy!\n" + "Let's plot the free energy!" ] }, { @@ -324,8 +278,7 @@ }, "outputs": [], "source": [ - "import matplotlib.pyplot as plt\n", - "from pysages.approxfun import compute_mesh" + "import matplotlib.pyplot as plt" ] }, { @@ -385,17 +338,8 @@ "cbar = plt.colorbar(im)\n", "cbar.ax.set_ylabel(r\"$A~[kJ/mol]$\", rotation=270, labelpad=20)\n", "\n", - "plt.show()" + "fig.show()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "R6rEuwWAZ8Qp" - }, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/examples/openmm/spectral_abf/ADP_SpectralABF.md b/examples/openmm/spectral_abf/ADP_SpectralABF.md index 714e33e4..adeb2fd8 100644 --- a/examples/openmm/spectral_abf/ADP_SpectralABF.md +++ b/examples/openmm/spectral_abf/ADP_SpectralABF.md @@ -13,112 +13,83 @@ jupyter: name: python3 --- - - + # Setting up the environment -First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the DLExt plugin. -We copy it from Google Drive and install PySAGES for it. - +First, we set up our environment. We use an already compiled and packaged installation of OpenMM and the openmm-dlext plugin. +We download it from Google Drive and make it visible to the running python process in this Colab instance. ```bash id="3eTbKklCnyd_" BASE_URL="https://drive.usercontent.google.com/download?id=1hsKkKtdxZTVfHKgqVF6qV2e-4SShmhr7" -wget -q --load-cookies /tmp/cookies.txt "$BASE_URL&confirm=$(wget -q --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\w+).*/\1\n/p')" -O pysages-env.zip -rm -rf /tmp/cookies.txt +COOKIES="/tmp/cookies.txt" +CONFIRMATION="$(wget -q --save-cookies $COOKIES --keep-session-cookies --no-check-certificate $BASE_URL -O- | sed -rn 's/.*confirm=(\w+).*/\1\n/p')" + +wget -q --load-cookies $COOKIES "$BASE_URL&confirm=$CONFIRMATION" -O pysages-env.zip +rm -rf $COOKIES ``` -```python colab={"base_uri": "https://localhost:8080/"} id="KRPmkpd9n_NG" outputId="e577ce0d-0a62-4f48-fb05-fde3a39c2ccc" +```python id="25H3kl03wzJe" %env PYSAGES_ENV=/env/pysages ``` -```bash id="J7OY5K9VoBBh" +```bash id="CPkgxfj6w4te" mkdir -p $PYSAGES_ENV . unzip -qquo pysages-env.zip -d $PYSAGES_ENV ``` -```python id="EMAWp8VloIk4" +```python id="JMO5fiRTxAWB" import os import sys ver = sys.version_info sys.path.append(os.environ["PYSAGES_ENV"] + "/lib/python" + str(ver.major) + "." + str(ver.minor) + "/site-packages/") -os.environ["XLA_FLAGS"] = "--xla_gpu_strict_conv_algorithm_picker=false" os.environ["LD_LIBRARY_PATH"] = "/usr/lib/x86_64-linux-gnu:" + os.environ["LD_LIBRARY_PATH"] ``` - - + ## PySAGES -The next step is to install PySAGES. -First, we install the jaxlib version that matches the CUDA installation of this Colab setup. See the JAX documentation [here](https://github.com/google/jax) for more details. - - - -```bash id="vK0RZtbroQWe" - -pip install -q --upgrade pip -# Installs the wheel compatible with CUDA. -pip install -q --upgrade "jax[cuda]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html &> /dev/null -``` - - - -Now we can finally install PySAGES. We clone the newest version from [here](https://github.com/SSAGESLabs/PySAGES) and build the remaining pure python dependencies and PySAGES itself. - +The next step is to install PySAGES. We retrieve the latest version from GitHub and add its dependecies via `pip`. -```bash id="B-HB9CzioV5j" - -rm -rf PySAGES -git clone https://github.com/SSAGESLabs/PySAGES.git &> /dev/null -cd PySAGES -pip install -q . &> /dev/null +```python id="B-HB9CzioV5j" +!pip install -qq git+https://github.com/SSAGESLabs/PySAGES.git > /dev/null ``` - # SpectralABF-biased simulations - - SpectralABF gradually learns a better approximation to the coefficients of a basis functions expansion of the free energy of a system, from the generalized mean forces in a similar fashion to the ABF sampling method. For this Colab, we are using alanine peptide in vacuum as example system. - ```bash id="fre3-LYso1hh" # Download pdb file with the initial configuration of our system -PDB_URL="https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb" -wget -q $PDB_URL +wget -q https://raw.githubusercontent.com/SSAGESLabs/PySAGES/main/examples/inputs/alanine-dipeptide/adp-vacuum.pdb ``` ```python id="BBvC7Spoog82" -import numpy - -from pysages.utils import try_import - -openmm = try_import("openmm", "simtk.openmm") -unit = try_import("openmm.unit", "simtk.unit") -app = try_import("openmm.app", "simtk.openmm.app") - +import numpy as np +import openmm +import openmm.app as app +import openmm.unit as unit -pi = numpy.pi +pi = np.pi T = 298.15 * unit.kelvin dt = 2.0 * unit.femtoseconds adp_pdb = "adp-vacuum.pdb" -def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt): +def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt, **kwargs): pdb = app.PDBFile(pdb_filename) ff = app.ForceField("amber99sb.xml") @@ -151,9 +122,7 @@ def generate_simulation(pdb_filename=adp_pdb, T=T, dt=dt): ``` - Next, we load PySAGES and the relevant classes and methods for our problem - ```python id="fpMg-o8WomAA" @@ -165,11 +134,9 @@ import pysages ``` - The next step is to define the collective variable (CV). In this case, we choose the so called $\phi$ and $\psi$ dihedral angles of alanine dipeptide. We define a grid, which will be used to indicate how we want to bin the forces that will be used to approximate the biasing potential and its gradient. - ```python id="B1Z8FWz0o7u_" @@ -181,10 +148,8 @@ method = SpectralABF(cvs, grid) ``` - We now simulate the number of time steps set above. Make sure to run with GPU support, otherwise, it can take a very long time. - ```python id="K951m4BbpUar" @@ -192,16 +157,13 @@ run_result = pysages.run(method, generate_simulation, timesteps) ``` - ## Analysis Let's plot the free energy! - ```python id="X69d1R7OpW4P" import matplotlib.pyplot as plt -from pysages.approxfun import compute_mesh ``` ```python id="zJqvpbw8szxR" @@ -229,9 +191,5 @@ ax.set_ylabel(r"$\psi$") cbar = plt.colorbar(im) cbar.ax.set_ylabel(r"$A~[kJ/mol]$", rotation=270, labelpad=20) -plt.show() -``` - -```python id="R6rEuwWAZ8Qp" - +fig.show() ```