{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Creating and importing molecular systems in OpenMM" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Preliminaries\n", "\n", "First, we import OpenMM. It's recommended that you always import this way:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from simtk import openmm, unit\n", "from simtk.openmm import app\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## The OpenMM `System` object\n", "\n", "The OpenMM [`System`](http://docs.openmm.org/7.1.0/api-python/library.html#system) object is a container that completely specifies how to compute the forces and energies for all particles in the molecular system. \n", "\n", "Because it is part of the C++ OpenMM API, `System` (and the related `Force` classes) are not true Python objects but instead SWIG-wrapped C++ objects, so you will find their naming and accessor conventions conform to C++ (rather than Pythonic) standards.\n", "\n", "There are many ways to create or import OpenMM `System` objects:\n", "* We can assemble all the particles and define their interactions ourselves programmatically using the OpenMM C++ API\n", "* We could load in a serialized version of the `System` object via the built-in XML serializer\n", "* We can use the various importers in the [`simtk.openmm.app`](http://docs.openmm.org/7.1.0/api-python/app.html) layer to read in a system definition in AMBER, CHARMM, or gromacs format\n", "* We can create our own `System` object from a PDB file using the OpenMM [`ForceField`](http://docs.openmm.org/7.1.0/userguide/application.html#force-fields) facility\n", "* We can use a large variety of pre-built test systems provided by the [`openmmtools.testsystems`](http://openmmtools.readthedocs.io) module for testing code on a battery of different system types with different kinds of forces\n", "\n", "Remember that if you want more information on `openmm.System`, you can use `help(openmm.System)`:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating a periodic Lennard-Jones system\n", "\n", "We'll start by building a simple periodic Lennard-Jones system using the Python wrappers for the main OpenMM C++ API." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Define the parameters of the Lennard-Jones periodic system\n", "nparticles = 512\n", "reduced_density = 0.05\n", "mass = 39.9 * unit.amu\n", "charge = 0.0 * unit.elementary_charge\n", "sigma = 3.4 * unit.angstroms\n", "epsilon = 0.238 * unit.kilocalories_per_mole\n", "\n", "# Create a system and add particles to it\n", "system = openmm.System()\n", "for index in range(nparticles):\n", " # Particles are added one at a time\n", " # Their indices in the System will correspond with their indices in the Force objects we will add later\n", " system.addParticle(mass)\n", " \n", "# Set the periodic box vectors\n", "number_density = reduced_density / sigma**3\n", "volume = nparticles * (number_density ** -1)\n", "box_edge = volume ** (1. / 3.)\n", "box_vectors = np.diag([box_edge/unit.angstrom for i in range(3)]) * unit.angstroms\n", "system.setDefaultPeriodicBoxVectors(*box_vectors)\n", "\n", "# Add Lennard-Jones interactions using a NonbondedForce\n", "force = openmm.NonbondedForce()\n", "force.setNonbondedMethod(openmm.NonbondedForce.CutoffPeriodic)\n", "for index in range(nparticles): # all particles must have parameters assigned for the NonbondedForce\n", " # Particles are assigned properties in the same order as they appear in the System object\n", " force.addParticle(charge, sigma, epsilon)\n", "force.setCutoffDistance(3.0 * sigma) # set cutoff (truncation) distance at 3*sigma\n", "force.setUseSwitchingFunction(True) # use a smooth switching function to avoid force discontinuities at cutoff\n", "force.setSwitchingDistance(2.5 * sigma) # turn on switch at 2.5*sigma\n", "force.setUseDispersionCorrection(True) # use long-range isotropic dispersion correction\n", "force_index = system.addForce(force) # system takes ownership of the NonbondedForce object" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The OpenMM Python API uses units throughout\n", "\n", "Note the use of unit-bearing quantities via [`simtk.unit`](http://docs.openmm.org/7.1.0/userguide/library.html#units-and-dimensional-analysis). OpenMM's Python API uses a powerful units system that prevents many common kinds of mistakes with unit conversion, such as those that caused the loss of the [Mars Polar Lander](http://www.cnn.com/TECH/space/9909/30/mars.metric.02/). We'll examine the units system in more detail later---for now, we simply recognize that best practices dictate we feed OpenMM unit-bearing quantities (though this is not strictly necessary), and that it will return unit-bearing quantities." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.53 nm\n" ] }, { "data": { "text/plain": [ "'Quantity(value=1.53, unit=nanometer)'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# construct a Quantity using the multiply operator\n", "bond_length = 1.53 * unit.nanometer\n", "# equivalently using the explicit Quantity constructor\n", "bond_length = unit.Quantity(1.53, unit.nanometer)\n", "# or more verbosely\n", "bond_length = unit.Quantity(value=1.53, unit=unit.nanometer)\n", "# print a unit in human-readable form\n", "print(bond_length)\n", "# or display it in machine-readable form\n", "repr(bond_length)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Accesssors for System attributes and Forces\n", "\n", "The [`System`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.System.html#simtk.openmm.openmm.System) object has a number of useful accessors for examining the contents of the system and " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The system has 512 particles\n", "Particle 0 has mass 39.900 amu\n", "Particle 1 has mass 39.900 amu\n", "Particle 2 has mass 39.900 amu\n", "Particle 3 has mass 39.900 amu\n", "Particle 4 has mass 39.900 amu\n", "The system has 0 constraints\n", "There are 1 forces\n", "Force 0 : NonbondedForce\n" ] } ], "source": [ "# Get the number of particles in the System\n", "print('The system has %d particles' % system.getNumParticles())\n", "# Print a few particle masses\n", "for index in range(5):\n", " print('Particle %5d has mass %12.3f amu' % (index, system.getParticleMass(index) / unit.amu))\n", "# Print number of constraints\n", "print('The system has %d constraints' % system.getNumConstraints())\n", "# Get the number of forces and iterate through them\n", "print('There are %d forces' % system.getNumForces())\n", "for (index, force) in enumerate(system.getForces()):\n", " print('Force %5d : %s' % (index, force.__class__.__name__))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Define positions for the Lennard-Jones particles\n", "\n", "To compute energies or forces, we will need to define some positions for the system before we can compute energies or forces.\n", "We'll generate some randomly, but as we will see later, there are many more ways to load molecular positions." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 50.06589405 38.74885235 35.33400422]\n", " [ 50.95223274 50.29185888 12.95023497]\n", " [ 28.94210046 34.42082076 60.99670999]\n", " ..., \n", " [ 49.8772534 60.166914 30.42399294]\n", " [ 56.75521618 37.75775794 53.37899838]\n", " [ 60.90425164 10.08568524 43.13366285]] A\n" ] } ], "source": [ "positions = box_edge * np.random.rand(nparticles,3) \n", "print(positions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Computing energies and forces\n", "\n", "To compute energies and forces efficiently, OpenMM requires you create a [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.html#simtk.openmm.openmm.Context) that handles the computation on a particular piece of hardware. This could be a GPU or CPU using a specific set of fast computation kernels.\n", "\n", "OpenMM forces us to explicitly move data (positions, velocities, forces) into and out of the `Context` through specific calls so that we remember that each of these operations carries overhead of moving data across the bus to the GPU, for example. To achieve maximum speed, OpenMM can perform a number of operations---such as integrating many molecular dynamics steps---fully on the GPU without slowing things down by moving data back and forth over the bus. We'll see examples of this soon.\n", "\n", "First, we just want to compute energies and forces and then minimize the energy of our system. To do that, we first need to create an [`Integrator`](http://docs.openmm.org/7.1.0/userguide/application.html#integrators) that will be bound to the [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.html#simtk.openmm.openmm.Context):" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Create an integrator\n", "timestep = 1.0 * unit.femtoseconds\n", "integrator = openmm.VerletIntegrator(timestep)\n", "# Create a Context using the default platform (the fastest abailable one is picked automatically)\n", "# NOTE: The integrator is bound irrevocably to the context, so we can't reuse it\n", "context = openmm.Context(system, integrator)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will look at [`Integrator`](http://docs.openmm.org/7.1.0/userguide/application.html#integrators) objects more in depth in [Module 02 - Integrators and Sampling](https://github.com/choderalab/openmm-tutorials/blob/master/02%20-%20Integrators%20and%20sampling.ipynb)\n", "\n", "We can also optionally specify which platform we want. OpenMM comes with the following [`Platforms:`](http://docs.openmm.org/7.1.0/userguide/application.html#platforms)\n", "* [`Reference`](http://docs.openmm.org/7.1.0/userguide/library.html#platforms) - A slow double-precision single-threaded CPU-only implementation intended for comparing fast implementations with a \"verifiably correct\" one\n", "* [`CPU`](http://docs.openmm.org/7.1.0/userguide/library.html#cpu-platform) - A fast multithreaded mixed-precision CPU-only implementation\n", "* [`OpenCL`](http://docs.openmm.org/7.1.0/userguide/library.html#opencl-platform) - A highly portable OpenCL implementation that can be used with GPU or CPU OpenCL drivers; supports multiple precision models (single, mixed, double)\n", "* [`CUDA`](http://docs.openmm.org/7.1.0/userguide/library.html#cuda-platform) - The fastest implementation that uses [CUDA](https://developer.nvidia.com/cuda-downloads) for NVIDIA GPUs; supports multiple precision models (single, mixed, double)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# We have to create a new integrator for every Context since it takes ownership of the integrator we pass it\n", "integrator = openmm.VerletIntegrator(timestep)\n", "# Create a Context using the multithreaded mixed-precision CPU platform\n", "platform = openmm.Platform.getPlatformByName('CPU')\n", "context = openmm.Context(system, integrator, platform)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `System` object can be used by multiple `Contexts` because the `System` is copied and converted to the efficient `Platform` specific kernels inside the `Context` object. Changing parameters or adding new `Force`'s on the Python `System` itself will not update the representation inside the `Context`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[Quantity(value=(14.766431834276288, 0.0, 0.0), unit=nanometer), Quantity(value=(0.0, 14.766431834276288, 0.0), unit=nanometer), Quantity(value=(0.0, 0.0, 14.766431834276288), unit=nanometer)]\n", "[Quantity(value=(7.383215917138144, 0.0, 0.0), unit=nanometer), Quantity(value=(0.0, 7.383215917138144, 0.0), unit=nanometer), Quantity(value=(0.0, 0.0, 7.383215917138144), unit=nanometer)]\n" ] } ], "source": [ "from copy import deepcopy\n", "# Create a new integrator we can throw away\n", "throwaway_integrator = openmm.VerletIntegrator(timestep)\n", "# Copy the System object for this example\n", "copy_system = deepcopy(system)\n", "throwaway_context = openmm.Context(copy_system, throwaway_integrator)\n", "# Change something in the Python System, e.g. double the box size\n", "copy_system.setDefaultPeriodicBoxVectors(*box_vectors*2)\n", "# Observe how the box size in the Context and Python System are different\n", "print([vector for i, vector in enumerate(copy_system.getDefaultPeriodicBoxVectors())])\n", "print([vector for i, vector in enumerate(throwaway_context.getState().getPeriodicBoxVectors())])\n", "# Cleanup\n", "del throwaway_integrator, throwaway_context" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are ways to update paramters in an existing `Context`, but that topic will be covered in later tutorials.\n", "\n", "Once we have a [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.html#simtk.openmm.openmm.Context), we need to tell OpenMM we want to retrieve the energy and forces for a specific set of particle positions. This is done by retrieving a [`State`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.State.html#simtk.openmm.openmm.State) object from the [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.html#simtk.openmm.openmm.Context) that contains *only* the information we want to retrieve so as to minimize the amount of data that needs to be sent over the bus from a GPU:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Potential energy: 20731546.609353863 kJ/mol\n", "Forces: [(-0.4904191792011261, -2.0151243209838867, 2.990215539932251), (-4.348661422729492, -2.4672372341156006, 3.2111189365386963), (0.010116085410118103, -0.08782704174518585, -0.008425451815128326), (-0.17573882639408112, -0.07705540955066681, 0.25119271874427795), (-1.2817492485046387, 1.4227875471115112, -0.6091694235801697)] kJ/(nm mol)\n" ] } ], "source": [ "# Set the positions\n", "context.setPositions(positions)\n", "# Retrieve the energy and forces\n", "state = context.getState(getEnergy=True, getForces=True)\n", "potential_energy = state.getPotentialEnergy()\n", "print('Potential energy: %s' % potential_energy)\n", "forces = state.getForces()\n", "print('Forces: %s' % forces[0:5])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the forces are returned as a `list` of tuples with units attached. If we want a numpy array instead, we could convert it, but it's much easier just use the `asNumpy=True` argument to [`state.getForces`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.State.html#simtk.openmm.openmm.State.getForces)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Forces: [[ -4.90419179e-01 -2.01512432e+00 2.99021554e+00]\n", " [ -4.34866142e+00 -2.46723723e+00 3.21111894e+00]\n", " [ 1.01160854e-02 -8.78270417e-02 -8.42545182e-03]\n", " ..., \n", " [ -6.53141165e+00 -2.62020969e+00 -3.67551947e+00]\n", " [ 2.32062773e+04 1.06050898e+05 2.38855234e+05]\n", " [ -4.50388193e+00 1.33601656e+01 -1.09453621e+01]] kJ/(nm mol)\n" ] } ], "source": [ "# Get forces as numpy array\n", "forces = state.getForces(asNumpy=True)\n", "print('Forces: %s' % forces)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Minimizing the potential energy\n", "\n", "You'll notice the energy and force magnitude is pretty large:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Potential energy: 20731546.60935385 kJ/mol\n", "Force magnitude: 3064549996.115365 kJ/(nm mol)\n" ] } ], "source": [ "# Compute the energy\n", "state = context.getState(getEnergy=True, getForces=True)\n", "potential_energy = state.getPotentialEnergy()\n", "print('Potential energy: %s' % potential_energy)\n", "# Compute the force magnitude\n", "forces = state.getForces(asNumpy=True)\n", "force_magnitude = (forces**2).sum().sqrt()\n", "print('Force magnitude: %s' % force_magnitude)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we tried to do dynamics at this point, the system will likely explode!\n", "\n", "OpenMM provides a [`LocalEnergyMinimizer`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.LocalEnergyMinimizer.html#simtk.openmm.openmm.LocalEnergyMinimizer) that can be used to bring the force magnitude to be low enough to be able to run a simulation that won't explode." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Potential energy: -202.54488264416048 kJ/mol\n", "Force magnitude: 138.81753123729027 kJ/(nm mol)\n" ] } ], "source": [ "# Minimize the potential energy\n", "openmm.LocalEnergyMinimizer.minimize(context)\n", "\n", "# Compute the energy and force magnitude after minimization\n", "state = context.getState(getEnergy=True, getForces=True)\n", "potential_energy = state.getPotentialEnergy()\n", "print('Potential energy: %s' % potential_energy)\n", "forces = state.getForces(asNumpy=True)\n", "force_magnitude = (forces**2).sum().sqrt()\n", "print('Force magnitude: %s' % force_magnitude)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Serializing the System object to disk or for transport over the network\n", "\n", "You can serialize and restore `System` objects as a string (which can be written to disk) via the [`XmlSerializer`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.XmlSerializer.html#simtk.openmm.openmm.XmlSerializer) class:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Serialize to a string\n", "system_xml = openmm.XmlSerializer.serialize(system)\n", "# Restore from a string\n", "restored_system = openmm.XmlSerializer.deserialize(system_xml)\n", "assert(system.getNumParticles() == restored_system.getNumParticles())" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['',\n", " '',\n", " '\\t',\n", " '\\t\\t',\n", " '\\t\\t',\n", " '\\t\\t',\n", " '\\t',\n", " '\\t',\n", " '\\t\\t',\n", " '\\t\\t',\n", " '\\t\\t',\n", " '\\t\\t',\n", " '\\t\\t',\n", " '\\t\\t',\n", " '\\t\\t']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Peek at the first 15 lines of the XML file\n", "system_xml.split('\\n')[:15]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load a molecular system defined by AMBER, CHARMM, or gromacs\n", "\n", "The OpenMM [`app` layer](http://docs.openmm.org/7.1.0/userguide/application.html#using-amber-files) provides convenience classes that help you load in systems defined in AMBER, CHARMM, or gromacs. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Loading an AMBER system\n", "\n", "We can use [`AmberPrmtopFile`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.app.amberprmtopfile.AmberPrmtopFile.html#simtk.openmm.app.amberprmtopfile.AmberPrmtopFile) to load an Amber `prmtop` file and [`InpcrdFile`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.app.amberinpcrdfile.AmberInpcrdFile.html#simtk.openmm.app.amberinpcrdfile.AmberInpcrdFile) to load an `inpcrd` file:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Potential energy: -137.4395293410778 kJ/mol\n" ] } ], "source": [ "# Load in an AMBER system\n", "from simtk.openmm import app\n", "prmtop = app.AmberPrmtopFile('resources/alanine-dipeptide-implicit.prmtop')\n", "inpcrd = app.AmberInpcrdFile('resources/alanine-dipeptide-implicit.inpcrd')\n", "system = prmtop.createSystem(nonbondedMethod=app.NoCutoff, implicitSolvent=app.OBC2, constraints=app.HBonds)\n", "positions = inpcrd.getPositions(asNumpy=True)\n", "\n", "# Compute the potential energy\n", "def compute_potential(system, positions):\n", " \"\"\"Print the potential energy given a System and positions.\"\"\"\n", " integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds)\n", " context = openmm.Context(system, integrator)\n", " context.setPositions(positions)\n", " print('Potential energy: %s' % context.getState(getEnergy=True).getPotentialEnergy())\n", " # Clean up\n", " del context, integrator\n", " \n", "compute_potential(system, positions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading a CHARMM system\n", "\n", "We can also [load CHARMM files](http://docs.openmm.org/7.1.0/userguide/application.html#using-charmm-files):" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Potential energy: 187615.39653015137 kJ/mol\n" ] } ], "source": [ "# Load in a CHARMM system\n", "from simtk.openmm import app\n", "psf = app.CharmmPsfFile('resources/ala_ala_ala.psf')\n", "pdbfile = app.PDBFile('resources/ala_ala_ala.pdb')\n", "params = app.CharmmParameterSet('resources/charmm22.rtf', 'resources/charmm22.par')\n", "system = psf.createSystem(params, nonbondedMethod=app.NoCutoff, constraints=app.HBonds)\n", "positions = pdbfile.getPositions(asNumpy=True)\n", "compute_potential(system, positions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading a gromacs system\n", "\n", "We can also [load gromacs files](http://docs.openmm.org/7.1.0/userguide/application.html#using-gromacs-files), though you'll want to have the gromacs parameter files installed first.\n", "\n", "You can install a version of gromacs via `conda` with:\n", "```\n", "conda install --yes -c bioconda gromacs\n", "```" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Potential energy: -115290.90428611072 kJ/mol\n" ] } ], "source": [ "# Load in a gromacs system\n", "from simtk.openmm import app\n", "gro = app.GromacsGroFile('resources/input.gro')\n", "# Make sure you change this to your appropriate gromacs include directory!\n", "gromacs_include_filepath = '/Users/choderaj/miniconda3/share/gromacs/top/'\n", "top = app.GromacsTopFile('resources/input.top', periodicBoxVectors=gro.getPeriodicBoxVectors(), includeDir=gromacs_include_filepath)\n", "system = top.createSystem(nonbondedMethod=app.PME, nonbondedCutoff=1*unit.nanometer, constraints=app.HBonds)\n", "positions = gro.getPositions(asNumpy=True)\n", "compute_potential(system, positions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating a `System` using the OpenMM `ForceField` class\n", "\n", "OpenMM also provides a number of [force fields](http://docs.openmm.org/7.1.0/userguide/application.html#force-fields) that have been converted into a [universal XML force field description format](http://docs.openmm.org/7.1.0/userguide/application.html#writing-the-xml-file) that can also be [extended in a modular manner](http://docs.openmm.org/7.1.0/userguide/application.html#extending-forcefield). Several [common AMBER protein force fields are provided](http://docs.openmm.org/7.1.0/userguide/application.html#force-fields) that work well for protein systems in which all atoms are already present." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Potential energy: -115281.71871208795 kJ/mol\n" ] } ], "source": [ "# Create an OpenMM system using the ForceField class\n", "pdb = app.PDBFile('resources/input.pdb')\n", "forcefield = app.ForceField('amber99sb.xml', 'tip3p.xml')\n", "system = forcefield.createSystem(pdb.topology, nonbondedMethod=app.PME, nonbondedCutoff=1*unit.nanometer, constraints=app.HBonds)\n", "positions = pdb.positions\n", "compute_potential(system, positions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualizing the system and using `Topology` objects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "While the `System` objects don't contain any information on the *identities* of the particles or how these are organized into residues or molecules, we can extract a [`Topology`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.app.topology.Topology.html#simtk.openmm.app.topology.Topology) object that provides this information from a PDB file:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Extract the topology from a PDB file\n", "pdbfile = app.PDBFile('resources/alanine-dipeptide-implicit.pdb')\n", "positions = pdbfile.getPositions()\n", "topology = pdbfile.getTopology()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "OpenMM provides a way to write a frame to a PDB file should you want to visualize your initial configuration:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Write out a PDB file\n", "with open('output.pdb', 'w') as outfile:\n", " app.PDBFile.writeFile(topology, positions, outfile)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If working in a Jupyter notebook, we can use [`mdtraj`](http://mdtraj.org) and [`nglview`](https://github.com/arose/nglview) to visualize the system:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1993509e835247aca1b915862731383c" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Create an MDTraj Trajectory object\n", "import mdtraj\n", "mdtraj_topology = mdtraj.Topology.from_openmm(topology)\n", "traj = mdtraj.Trajectory(positions/unit.nanometers, mdtraj_topology)\n", "\n", "# View it in nglview\n", "import nglview\n", "view = nglview.show_mdtraj(traj)\n", "view.add_ball_and_stick('all')\n", "view.center_view(zoom=True)\n", "view" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prebuilt systems with `openmmtools.testsystems`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The [`openmmtools.testsystems`](http://openmmtools.readthedocs.io/en/latest/testsystems.html) module provides a number \n", "of pre-built test systems that are very useful for testing your code or benchmarking your algorithms. The full list of test systems can be found [here](http://openmmtools.readthedocs.io/en/latest/testsystems.html), but we'll highlight a few below." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 0. 0. 0.]] A\n", "Help on HarmonicOscillator in module openmmtools.testsystems object:\n", "\n", "class HarmonicOscillator(TestSystem)\n", " | Create a 3D harmonic oscillator, with a single particle confined in an isotropic harmonic well.\n", " | \n", " | Parameters\n", " | ----------\n", " | K : simtk.unit.Quantity, optional, default=100.0 * unit.kilocalories_per_mole/unit.angstrom**2\n", " | harmonic restraining potential\n", " | mass : simtk.unit.Quantity, optional, default=39.948 * unit.amu\n", " | particle mass\n", " | U0 : simtk.unit.Quantity, optional, default=0.0 * unit.kilocalories_per_mole\n", " | Potential offset for harmonic oscillator\n", " | \n", " | The functional form is given by\n", " | \n", " | U(x) = (K/2) * ( (x-x0)^2 + y^2 + z^2 ) + U0\n", " | \n", " | Attributes\n", " | ----------\n", " | system : simtk.openmm.System\n", " | Openmm system with the harmonic oscillator\n", " | positions : list\n", " | positions of harmonic oscillator\n", " | \n", " | Context parameters\n", " | ------------------\n", " | testsystems_HarmonicOscillator_K\n", " | Spring constant of harmonic oscillator\n", " | testsystems_HarmonicOscillator_x0\n", " | Reference x position for harmonic oscillator\n", " | testsystems_HarmonicOscillator_U0\n", " | Reference potential additive constant for harmonic oscillator\n", " | \n", " | Notes\n", " | -----\n", " | \n", " | The natural period of a harmonic oscillator is T = sqrt(m/K), so you will want to use an\n", " | integration timestep smaller than ~ T/10.\n", " | \n", " | The standard deviation in position in each dimension is sigma = (kT / K)^(1/2)\n", " | \n", " | The expectation and standard deviation of the potential energy of a 3D harmonic oscillator is (3/2)kT.\n", " | \n", " | Examples\n", " | --------\n", " | \n", " | Create a 3D harmonic oscillator with default parameters:\n", " | \n", " | >>> ho = HarmonicOscillator()\n", " | >>> (system, positions) = ho.system, ho.positions\n", " | \n", " | Create a harmonic oscillator with specified mass and spring constant:\n", " | \n", " | >>> mass = 12.0 * unit.amu\n", " | >>> K = 1.0 * unit.kilocalories_per_mole / unit.angstroms**2\n", " | >>> ho = HarmonicOscillator(K=K, mass=mass)\n", " | >>> (system, positions) = ho.system, ho.positions\n", " | \n", " | Get a list of the available analytically-computed properties.\n", " | \n", " | >>> print(ho.analytical_properties)\n", " | ['potential_expectation', 'potential_standard_deviation']\n", " | \n", " | Compute the potential expectation and standard deviation\n", " | \n", " | >>> import simtk.unit as u\n", " | >>> thermodynamic_state = ThermodynamicState(temperature=298.0*u.kelvin, system=system)\n", " | >>> potential_mean = ho.get_potential_expectation(thermodynamic_state)\n", " | >>> potential_stddev = ho.get_potential_standard_deviation(thermodynamic_state)\n", " | \n", " | TODO:\n", " | * Add getters and setters for K, x0, U0 that access current global parameter in system\n", " | * Add method to compute free energy of the harmonic oscillator(s)\n", " | \n", " | Method resolution order:\n", " | HarmonicOscillator\n", " | TestSystem\n", " | builtins.object\n", " | \n", " | Methods defined here:\n", " | \n", " | __init__(self, K=Quantity(value=100.0, unit=kilocalorie/(angstrom**2*mole)), mass=Quantity(value=39.948, unit=dalton), U0=Quantity(value=0.0, unit=kilojoule/mole), **kwargs)\n", " | Abstract base class for test system.\n", " | \n", " | Parameters\n", " | ----------\n", " | \n", " | get_potential_expectation(self, state)\n", " | Return the expectation of the potential energy, computed analytically or numerically.\n", " | \n", " | Arguments\n", " | ---------\n", " | \n", " | state : ThermodynamicState with temperature defined\n", " | The thermodynamic state at which the property is to be computed.\n", " | \n", " | Returns\n", " | -------\n", " | \n", " | potential_mean : simtk.unit.Quantity compatible with simtk.unit.kilojoules_per_mole\n", " | The expectation of the potential energy.\n", " | \n", " | get_potential_standard_deviation(self, state)\n", " | Return the standard deviation of the potential energy, computed analytically or numerically.\n", " | \n", " | Arguments\n", " | ---------\n", " | \n", " | state : ThermodynamicState with temperature defined\n", " | The thermodynamic state at which the property is to be computed.\n", " | \n", " | Returns\n", " | -------\n", " | \n", " | potential_stddev : simtk.unit.Quantity compatible with simtk.unit.kilojoules_per_mole\n", " | potential energy standard deviation if implemented, or else None\n", " | \n", " | ----------------------------------------------------------------------\n", " | Methods inherited from TestSystem:\n", " | \n", " | reduced_potential_expectation(self, state_sampled_from, state_evaluated_in)\n", " | Calculate the expected potential energy in state_sampled_from, divided by kB * T in state_evaluated_in.\n", " | \n", " | Notes\n", " | -----\n", " | \n", " | This is not called get_reduced_potential_expectation because this function\n", " | requires two, not one, inputs.\n", " | \n", " | serialize(self)\n", " | Return the System and positions in serialized XML form.\n", " | \n", " | Returns\n", " | -------\n", " | \n", " | system_xml : str\n", " | Serialized XML form of System object.\n", " | \n", " | state_xml : str\n", " | Serialized XML form of State object containing particle positions.\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors inherited from TestSystem:\n", " | \n", " | __dict__\n", " | dictionary for instance variables (if defined)\n", " | \n", " | __weakref__\n", " | list of weak references to the object (if defined)\n", " | \n", " | analytical_properties\n", " | A list of available analytical properties, accessible via 'get_propertyname(thermodynamic_state)' calls.\n", " | \n", " | name\n", " | The name of the test system.\n", " | \n", " | positions\n", " | The simtk.unit.Quantity object containing the particle positions, with units compatible with simtk.unit.nanometers.\n", " | \n", " | system\n", " | The simtk.openmm.System object corresponding to the test system.\n", " | \n", " | topology\n", " | The simtk.openmm.app.Topology object corresponding to the test system.\n", "\n" ] } ], "source": [ "from openmmtools import testsystems\n", "\n", "t = testsystems.HarmonicOscillator()\n", "system, positions, topology = t.system, t.positions, t.topology\n", "\n", "print(positions)\n", "help(t)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "320755d3d5644808982590fa99c2515e" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Create a Lennard-Jones cluster with a harmonic spherical restraint:\n", "t = testsystems.LennardJonesCluster()\n", "\n", "def visualize(t):\n", " import mdtraj\n", " mdtraj_topology = mdtraj.Topology.from_openmm(t.topology)\n", " traj = mdtraj.Trajectory([t.positions/unit.nanometers], mdtraj_topology)\n", "\n", " # View it in nglview\n", " import nglview\n", " view = nglview.show_mdtraj(traj)\n", " if t.system.getNumParticles() < 2000:\n", " view.add_ball_and_stick('all')\n", " view.center_view(zoom=True)\n", " return view\n", "\n", "visualize(t)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "176b982339cb4ed8a2bf63158ae3eadf" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "t = testsystems.LennardJonesFluid(reduced_density=0.90)\n", "visualize(t)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "6c7fd4d46170412b8578d105b3309884" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "t = testsystems.WaterBox()\n", "visualize(t)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "c43f710328d5448085b6c2ec0cde2df5" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "t = testsystems.AlanineDipeptideVacuum()\n", "visualize(t)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "8db295aeaced41d29ece18f0db7071c5" } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# The Joint AMBER-CHARMM (JAC) DHFR in explicit solvent benchmark system\n", "t = testsystems.DHFRExplicit()\n", "visualize(t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are lots and lots of test systems defined! You can find the complete list and descriptions [here](http://openmmtools.readthedocs.io/en/latest/testsystems.html).\n", "Try some!" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "HarmonicOscillator\n", "MethanolBox\n", "AMOEBAIonBox\n", "ConstraintCoupledHarmonicOscillator\n", "CustomExternalForcesTestSystem\n", "DHFRExplicit\n", "AMOEBAProteinBox\n", "AlanineDipeptideVacuum\n", "AlchemicalAlanineDipeptide\n", "LennardJonesFluid\n", "LennardJonesFluidTruncated\n", "LennardJonesFluidSwitched\n", "LennardJonesGrid\n", "SrcImplicit\n", "WCAFluid\n", "HostGuestImplicit\n", "HostGuestImplicitHCT\n", "HostGuestImplicitOBC1\n", "HostGuestImplicitGBn\n", "HostGuestImplicitGBn2\n", "HostGuestImplicitOBC2\n", "TolueneImplicit\n", "TolueneImplicitHCT\n", "TolueneImplicitOBC1\n", "TolueneImplicitGBn2\n", "TolueneImplicitGBn\n", "TolueneImplicitOBC2\n", "SrcExplicit\n", "SrcExplicitReactionField\n", "LysozymeImplicit\n", "LennardJonesPair\n", "HostGuestExplicit\n", "MolecularIdealGas\n", "DiatomicFluid\n", "UnconstrainedDiatomicFluid\n", "ConstrainedDiatomicFluid\n", "DipolarFluid\n", "UnconstrainedDipolarFluid\n", "ConstrainedDipolarFluid\n", "SodiumChlorideCrystal\n", "WaterBox\n", "FiveSiteWaterBox\n", "FlexibleReactionFieldWaterBox\n", "AlchemicalWaterBox\n", "FlexiblePMEWaterBox\n", "DischargedWaterBoxHsites\n", "FlexibleWaterBox\n", "FlexibleDischargedWaterBox\n", "GiantFlexibleDischargedWaterBox\n", "GiantFlexibleWaterBox\n", "DischargedWaterBox\n", "PMEWaterBox\n", "FourSiteWaterBox\n", "Diatom\n", "IdealGas\n", "HostGuestVacuum\n", "CustomGBForceSystem\n", "TolueneVacuum\n", "DNADodecamerExplicit\n", "PowerOscillator\n", "AlanineDipeptideExplicit\n", "CustomLennardJonesFluidMixture\n", "AlanineDipeptideImplicit\n", "HarmonicOscillatorArray\n", "LennardJonesCluster\n" ] } ], "source": [ "# Get all subclasses of type `TestSystem`\n", "from openmmtools.tests.test_testsystems import get_all_subclasses\n", "for t in get_all_subclasses(testsystems.TestSystem):\n", " print(t.__name__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Wrap-up\n", "\n", "We've reviewed a myriad of ways that you can create OpenMM [`System`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.System.html#simtk.openmm.openmm.System) objects. \n", "\n", "To recap, there are many ways to create or import OpenMM `System` objects:\n", "* We can assemble all the particles and define their interactions ourselves programmatically using the OpenMM C++ API\n", "* We could load in a serialized version of the `System` object via the built-in XML serializer\n", "* We can use the various importers in the [`simtk.openmm.app`](http://docs.openmm.org/7.1.0/api-python/app.html) layer to read in a system definition in AMBER, CHARMM, or gromacs format\n", "* We can create our own `System` object from a PDB file using the OpenMM [`ForceField`](http://docs.openmm.org/7.1.0/userguide/application.html#force-fields) facility\n", "* We can use a large variety of pre-built test systems provided by the [`openmmtools.testsystems`](http://openmmtools.readthedocs.io) module for testing code on a battery of different system types with different kinds of forces" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "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.5.4" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": { "00a80b0fa531413cafdb96f6024bcb9a": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_e4874c9fcce5457ebe368f716486e496", "width": "900.0" } }, "010cf2d56d23430894355065c6fff727": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_380050d3192e4f4b99e2b861c066b3d5", "width": "900.0" } }, "0388565b6dfc4452bc9ff64d7c82da1f": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_f6afd199ec3c456398ca5cd35da333e1", "width": "900.0" } }, "05086198de0840d3ac98c2bd89f7260b": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_c7364480a1644d58a2bebc38a1e0fb4c", "width": "900.0" } }, "063f9430d8424354b09818d5c5f61c75": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "06c06380f7cb43068ffe173cc67b054e": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "146c18a2608e4971a1c8aab11498e012": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "160698ef9d664b8580b9524b40c18121": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "176b982339cb4ed8a2bf63158ae3eadf": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_4a7bcaf30e78428aa3c284d2e36bf9f6", "n_components": 1, "orientation": [], "picked": {} } }, "1993509e835247aca1b915862731383c": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_e09d49d6f5ef43e985725cc4dad2d05c", "n_components": 1, "orientation": [], "picked": {} } }, "29b5e393d10b42858ef0c8a18ea0a172": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_43fc98d89e554849931afe0aba364e8f", "n_components": 0, "orientation": [], "picked": {} } }, "2bbb00b63b094a8ea947d8de206dcbff": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_3081e04806064f9b9c3c1f5f3488571d", "width": "900.0" } }, "2e5074b431684a55b2dafa07f781c28c": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_160698ef9d664b8580b9524b40c18121", "width": "900.0" } }, "3081e04806064f9b9c3c1f5f3488571d": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "320755d3d5644808982590fa99c2515e": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_ecb4a85f6ecc444b8bc86c96571bf41c", "n_components": 1, "orientation": [], "picked": {} } }, "37422d7d24134e2f94bf64e9692f88b8": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "380050d3192e4f4b99e2b861c066b3d5": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "38cff443a63e4d2490149de9fef89a87": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "43fc98d89e554849931afe0aba364e8f": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "46e56d4e292f448bb968ede11a26c456": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "4a7bcaf30e78428aa3c284d2e36bf9f6": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "4bbd94def27645f6bc3dad6713a20dd7": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "57e4ac14c32549f1992d0856989312fd": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "661fefa03644456db2d074b8e9ea1cd3": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_c7a526513dd74325afb7142daefa62c9", "width": "900.0" } }, "67fdde3622614c41b0a801283cf87a6a": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "6c7fd4d46170412b8578d105b3309884": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_78d7738daa4a4bb4935b2dfce97cc469", "n_components": 1, "orientation": [], "picked": {} } }, "78d7738daa4a4bb4935b2dfce97cc469": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "8a462f72cacd4e8c929e3f46002e7152": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_a8fd46f8cb874e79b64b249161712bb7", "n_components": 0, "orientation": [], "picked": {} } }, "8b1906a984c44d4e8b74b3b6a3d2b34e": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_67fdde3622614c41b0a801283cf87a6a", "width": "900.0" } }, "8db295aeaced41d29ece18f0db7071c5": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_37422d7d24134e2f94bf64e9692f88b8", "n_components": 1, "orientation": [], "picked": {} } }, "9b8af3f95c024944bed51d5f1b220f69": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_46e56d4e292f448bb968ede11a26c456", "width": "900.0" } }, "a0fce6906fb74c2581dab694ff6ab98a": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_d3db66d05cfc4e2aadb4a9cc5819e9b2", "n_components": 0, "orientation": [], "picked": {} } }, "a29e37f9ae6e4272a4fade64e2e8e93b": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "a8fd46f8cb874e79b64b249161712bb7": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "ac6f9846473a489f94c8890c316c4a70": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_38cff443a63e4d2490149de9fef89a87", "width": "900.0" } }, "bcd64dee983b4b9eb6560e6f0c9b0946": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_146c18a2608e4971a1c8aab11498e012", "width": "900.0" } }, "bf660ec7d7284db483103370ac2cad2a": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_06c06380f7cb43068ffe173cc67b054e", "n_components": 0, "orientation": [], "picked": {} } }, "c331edb8657d4ad294b17b74b95a6cba": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "ImageModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4", "layout": "IPY_MODEL_a29e37f9ae6e4272a4fade64e2e8e93b", "width": "900.0" } }, "c43f710328d5448085b6c2ec0cde2df5": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_57e4ac14c32549f1992d0856989312fd", "n_components": 1, "orientation": [], "picked": {} } }, "c7364480a1644d58a2bebc38a1e0fb4c": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "c7a526513dd74325afb7142daefa62c9": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "d3db66d05cfc4e2aadb4a9cc5819e9b2": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "e06ec404ede34cc7b7b2e32115e5bd21": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_063f9430d8424354b09818d5c5f61c75", "n_components": 0, "orientation": [], "picked": {} } }, "e09d49d6f5ef43e985725cc4dad2d05c": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "e4874c9fcce5457ebe368f716486e496": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "ec31753dc72041f4bca5736b58371473": { "model_module": "jupyter-js-widgets", "model_module_version": "*", "model_name": "DOMWidgetModel", "state": { "_camera_str": "orthographic", "_full_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_image_data": "", "_model_name": "DOMWidgetModel", "_n_dragged_files": 0, "_original_stage_parameters": { "ambientColor": 14540253, "ambientIntensity": 0.2, "backgroundColor": "white", "cameraFov": 40, "cameraType": "perspective", "clipDist": 10, "clipFar": 100, "clipNear": 0, "fogFar": 100, "fogNear": 50, "hoverTimeout": 500, "impostor": true, "lightColor": 14540253, "lightIntensity": 1, "panSpeed": 0.8, "quality": "medium", "rotateSpeed": 2, "sampleLevel": 0, "zoomSpeed": 1.2 }, "_view_module": "nglview-js-widgets", "_view_name": "NGLView", "background": "white", "count": 1, "frame": 0, "layout": "IPY_MODEL_4bbd94def27645f6bc3dad6713a20dd7", "n_components": 0, "orientation": [], "picked": {} } }, "ecb4a85f6ecc444b8bc86c96571bf41c": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } }, "f6afd199ec3c456398ca5cd35da333e1": { "model_module": "jupyter-js-widgets", "model_module_version": "~2.1.4", "model_name": "LayoutModel", "state": { "_model_module_version": "~2.1.4", "_view_module_version": "~2.1.4" } } }, "version_major": 1, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 2 }