{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Conformational sampling\n", "\n", "> ### In this tutorial we will cover:\n", "> - how we may use BuildAMol to obtain multiple conformations for a molecule" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We sometimes want to test out different conformations of a molecule. To achieve this we can use molecular dynamics (MD) simulations. BuildAMol does not perform MD, however. We can nontheless use BuildAMol's optimization algorithms to obtain multiple conformations for a molecule. The algorithms:\n", "\n", "- `swarm_optimize`, \n", "- `anneal_optimize`,\n", "- `genetic_optimize`\n", " \n", "offer the functionality of returning multiple solutions using the argument `n_best`. We can make use of this to obtain multiple conformations for one molecule during optimization by simply passing this argument to the optimization function or the `optimize` wrapper. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's start by loading some molecule from a file" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "application/3dmoljs_load.v0": "
\n

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n jupyter labextension install jupyterlab_3dmol

\n
\n", "text/html": [ "
\n", "

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n", " jupyter labextension install jupyterlab_3dmol

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import buildamol as bam\n", "bam.visual.set_backend(\"py3dmol\")\n", "\n", "mol = bam.read_pdb(\"files/x_wing.pdb\")\n", "mol.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Preparing the environment\n", "\n", "If you have already checked out the other tutorials on conformational optimization then you know that we first have to export our molecule into a _graph_ object and set up an optimization environment. If all of that is news to you, go check out the other tutorials to learn more. For now, let's just make an environment and subsample some bonds to optimize:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# make a graph (standard optimization procedure)\n", "graph = mol.get_atom_graph()\n", "\n", "# get some edges to rotate \n", "# (here we take a random subset of edges)\n", "# all edges are directed to be pointing \"outward\" from the central node\n", "edges = graph.find_rotatable_edges(graph.central_node)\n", "edges = graph.sample_edges(edges, n=2, m=5) # two clusters with 5 sampled edges each\n", "\n", "# make an environment to optimize\n", "env = bam.optimizers.DistanceRotatron(graph, edges, pushback=1.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sampling with `n_best`\n", "\n", "Now we can optimize the molecule in order to obtain multiple conformer samples by passing `n_best` as an argument to the `optimize` wrapper function like so:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[Molecule(x_wing), Molecule(x_wing), Molecule(x_wing), Molecule(x_wing), Molecule(x_wing)]\n" ] } ], "source": [ "# optimize and get the conformer samples\n", "# we pass n_best=10 to get the 10 best solutions back\n", "conformers = bam.optimizers.optimize(mol, env, algorithm=\"swarm\", n_best=10, n_particles=100)\n", "print(conformers)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we have a list of ten conformers for the X-Wing molecule. We can look at them in one 3D plot using the code below" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/3dmoljs_load.v0": "
\n

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n jupyter labextension install jupyterlab_3dmol

\n
\n", "text/html": [ "
\n", "

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n", " jupyter labextension install jupyterlab_3dmol

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# make a 3D molecule representation of the original\n", "view = mol.draw(color=\"gray\")\n", "\n", "# now draw all conformers\n", "for c in conformers:\n", " view.add(c.draw(color=\"cyan\"))\n", "\n", "view.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each of the generated conformers is a `Molecule` in its own right so we can do with these now whatever. Of course, since they are all products of the same optimization they look very much alike. That is not quite what \"sampling\" is supposed to be, though." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sampling with independent optimizations\n", "\n", "To diversify the conformers that are sampled, we could either extend the optimization scope (e.g. more particles for particle-swarm optimization) or we simply use multiple independent optimizations like so:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/3dmoljs_load.v0": "
\n

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n jupyter labextension install jupyterlab_3dmol

\n
\n", "text/html": [ "
\n", "

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n", " jupyter labextension install jupyterlab_3dmol

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# make some conformers from individual optimizations\n", "conformers = [bam.optimizers.optimize(mol.copy(), env, algorithm=\"swarm\", n_particles=5) for i in range(5)]\n", "\n", "view = mol.draw(color=\"gray\")\n", "for c in conformers:\n", " view.add(c.draw(color=\"orange\"))\n", "view.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That looks much more like what we are hoping to see. However, notice how we reduced the scale of the optimization markedly so as not to wait too long. When doing separate optimizations we can leverage the power of _parallel computation_, however, to get a significant speedup! \n", "For convenience BuildAMol has a `parallel_optimize` function that we can use to run multiple optimizations, well, in parallel! Here's how to use it:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/3dmoljs_load.v0": "
\n

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n jupyter labextension install jupyterlab_3dmol

\n
\n", "text/html": [ "
\n", "

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n", " jupyter labextension install jupyterlab_3dmol

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# run twenty optimizations in parallel\n", "# by passing a list of environments\n", "# since we want to do sampling we set unify_final=False\n", "conformers = bam.optimizers.parallel_optimize(mol, [env] * 20, algorithm=\"swarm\", n_particles=5, unify_final=False)\n", "\n", "view = mol.draw(color=\"gray\")\n", "for c in conformers:\n", " view.add(c.draw(color=\"limegreen\"))\n", "view.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And there we have some more conformers. Of course if we want to do it a little more rigorous, we should repeat the procedure multiple times while sampling different edges to get more diversity. Hopefully you feel like you could already do this on your own at this point, but let's demonstrate it anyways:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/3dmoljs_load.v0": "
\n

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n jupyter labextension install jupyterlab_3dmol

\n
\n", "text/html": [ "
\n", "

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n", " jupyter labextension install jupyterlab_3dmol

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "conformers = []\n", "for i in range(5):\n", " # make a new graph each time \n", " edges = graph.sample_edges(graph.find_rotatable_edges(graph.central_node), n=2, m=5)\n", " env = bam.optimizers.DistanceRotatron(graph, edges, pushback=1.5)\n", "\n", " # optimize and get the conformer samples\n", " incoming = bam.optimizers.parallel_optimize(mol, [env] * 10, algorithm=\"swarm\", n_particles=5, unify_final=False)\n", " conformers.extend(incoming)\n", " \n", "view = mol.draw(color=\"gray\")\n", "for c in conformers:\n", " view.add(c.draw(color=\"purple\"))\n", "view.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And there we have a total of 50 conformations overlaid! Out of interest, let's also check how many of our conformers have clashes in them:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "application/3dmoljs_load.v0": "
\n

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n jupyter labextension install jupyterlab_3dmol

\n
\n", "text/html": [ "
\n", "

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
\n", " jupyter labextension install jupyterlab_3dmol

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "v = mol.draw(color=\"gray\")\n", "for c in conformers:\n", " if c.count_clashes() == 0:\n", " color = \"limegreen\"\n", " else:\n", " color = \"red\"\n", " \n", " v.add(c.draw(color=color))\n", "\n", "v.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we want to use these conformers in a deep-learning dataset for instance? Well, most of the available deep-learning tools work with RDKit so let's simply generate a \"dataset\" in the form of a pickled list of dictionaries that contain RDKit molecules and some other data. We can then use this to maybe retrain an existing tool to better accomodate our needs, or do whatever else our research may entail..." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "import pickle\n", "\n", "dataset = []\n", "\n", "for idx, c in enumerate(conformers):\n", " if c.count_clashes() > 0:\n", " continue\n", " new = {\n", " \"conformer_id\" : c.id + str(idx),\n", " # any additional features that would be of interest\n", " # ...\n", " \"mol\" : c.to_rdkit()\n", " }\n", " dataset.append(new)\n", "\n", "with open(\"./files/x_wing_conformers.pkl\", \"wb\") as f:\n", " pickle.dump(dataset, f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With this we have reached the end of this tutorial. Hopefully you found it useful for your search for conformers!" ] } ], "metadata": { "kernelspec": { "display_name": "glyco2", "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.11.0" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }