Skip to content

Commit

Permalink
gmxapi-30 Tutorial / working Jupyter notebook examples
Browse files Browse the repository at this point in the history
* Add a bunch of clarifying documentation to the source code.
* Remove stale comments, dead code, and other cruft.
* Expand the description of how the plugins work.
  • Loading branch information
eirrgang committed Jun 6, 2018
1 parent 6fb1b7f commit 782daee
Show file tree
Hide file tree
Showing 6 changed files with 420 additions and 113 deletions.
29 changes: 28 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This repository uses CMake to build and install a Python C++ extension package.

* ``CMakeLists.txt``, ``cmake/FindGROMACS.cmake``, and ``src/CMakeLists.txt`` provide necessary CMake infrastructure. You should not need to edit these.
* ``src/cpp`` contains a header and ``cpp`` file for each restraint potential built with this module. When adding new potentials, you will update ``CMakeLists.txt`` to create build targets. Use the existing potentials as examples.
* ``src/pythonmodule/`` contains ``CMakeLists.txt``, ``export_plugin.h``, and ``export_plugin.cpp``. When you have written a new potential, you can add it to ``CMakeLists.txt`` and ``export_plugin.cpp``. This is the code that produces the C++ extension for Python.
* ``src/pythonmodule/`` contains ``CMakeLists.txt``, ``export_plugin.h``, and ``export_plugin.cpp``. When you have written a new potential, you can add it to ``CMakeLists.txt`` and ``export_plugin.cpp``. This is the code that produces the C++ extension for Python. ``HarmonicRestraint`` is a simple example that applies a Hooke's Law spring between two atoms. ``EnsembleHarmonic`` applies a more complicated potential and uses additional facilities provided by gmxapi.
* ``src/pybind11`` is just a copy of the Python bindings framework from the Pybind project (ref https://github.com/pybind/pybind11 ). It is used to wrap the C++ restraint code and give it a Python interface.
* ``tests/`` contains C++ and Python tests for the provided code. Update ``CMakeLists.txt`` to add your own, based on these examples. C++ unit tests use `googletest<https://github.com/google/googletest>`_. Python tests use the `pytest <https://docs.pytest.org/en/latest/>`_. Refer to those respective projects for more about how they make test-writing easier.
* ``examples`` contains a sample SLURM job script and ``restrained-ensemble.py`` gmxapi script that have been used to do restrained ensemble simulations. ``example.py`` and ``example.ipynb`` explore a toy alanine dipeptide system. ``strip_notebook.py`` is a helper script to remove extra output and state data from an iPython notebook before checking updates back into the repository.
Expand Down Expand Up @@ -141,6 +141,33 @@ The actual filename will be something like ``libharmonicpotential.so`` or ``harm
or something depending on your operating system.
These libraries are used to build a Python module named ``myplugin``.

When setting up a workflow, a Python script provides gmxapi with parameters and a factory function
for a plugin restraint potential. This Python interface is defined in ``src/pythonmodule/export_plugin.cpp``.
When a Session is launched, an C++ object that performs restraint force calculations is created and
given to the GROMACS library. During each MD step, part of the MD force evaluation includes a call
to the calculations performed by the restraint. For the pair restraints demonstrated here, GROMACS
provides relative coordinates of two atomic sites to the calculation code in the plugin. If multiple
restrained pairs are needed, multiple restraints are attached to the simulation. Coordination across
an ensemble of simulations is possible using resources provided by the Session.

Fundamentally, a new restraint potential is implemented by creating a class that provides a
``calculate()`` method and using wrappers to give it interfaces to GROMACS and to Python.
C++ wrappers allow the basic class implementing the potential to be presented to the GROMACS
library in a way that can be used to evaluate forces during a simulation. Other C++ template
code wraps the potential in a portable way so that it can be passed to GROMACS through a Python
interface and to receive parameters from the Python interpreter. Pybind11 syntax in
``export_plugin.cpp`` provides the code to actually expose the plugin as a class in a Python module
that is compatible with the ``gmx`` package provided in the ``gmxapi`` project.

By version
0.1.0, additional wrappers and boilerplate code will be migrated out of the files that
define the ``calculate()`` methods. Until then, some amount of copy-and-paste or editing is
necessary to implement a new potential. Refer to ``src/cpp/harmonicpotential.h`` and to
``src/cpp/harmonicpotential.cpp`` for a documented example of a simple pair restraint. A more
complex example is found in the ``ensemblepotential`` files. The code in ``src/cpp`` is sufficient
to produce testable object code, but the Python module is exported in ``src/pythonmodule/export_plugin.cpp``. If you add additional source files for a new potential,
you will need to update ``src/cpp/CMakeLists.txt`` as well.

Python tests
============

Expand Down
35 changes: 25 additions & 10 deletions src/cpp/ensemblepotential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
// Created by Eric Irrgang on 2/26/18.
//

/*! \file
* \brief Code to implement the potential declared in ensemblepotential.h
*
* This file currently contains boilerplate that will not be necessary in future gmxapi releases, as
* well as additional code used in implementing the restrained ensemble example workflow.
*
* A simpler restraint potential would only update the calculate() function. If a callback function is
* not needed or desired, remove the callback() code from this file and from ensemblepotential.h
*/

#include "ensemblepotential.h"

#include <cmath>
Expand All @@ -21,14 +31,6 @@ void EnsembleResourceHandle::reduce(const Matrix<double> &send,
(*_reduce)(send, receive);
}

template<typename T_I, typename T_O>
void EnsembleResourceHandle::map_reduce(const T_I &iterable,
T_O *output,
void (*function)(double, const PairHist & input,
PairHist * output)
)
{}

/*!
* \brief Apply a Gaussian blur when building a density grid for a list of values.
*
Expand Down Expand Up @@ -154,7 +156,13 @@ EnsembleHarmonic::EnsembleHarmonic(const input_param_type &params) :
{
}

// Todo: reference coordinate for PBC problems.
//
//
// HERE is the (optional) function that updates the state of the restraint periodically.
// It is called before calculate() once per timestep per simulation (on the master rank of
// a parallelized simulation).
//
//
void EnsembleHarmonic::callback(gmx::Vector v,
gmx::Vector v0,
double t,
Expand Down Expand Up @@ -255,6 +263,12 @@ void EnsembleHarmonic::callback(gmx::Vector v,

}


//
//
// HERE is the function that does the calculation of the restraint force.
//
//
gmx::PotentialPointData EnsembleHarmonic::calculate(gmx::Vector v,
gmx::Vector v0,
double t)
Expand Down Expand Up @@ -316,7 +330,8 @@ EnsembleResourceHandle EnsembleResources::getHandle() const
return handle;
}

// Explicitly instantiate a definition.
// Important: Explicitly instantiate a definition for the templated class declared in ensemblepotential.h.
// Failing to do this will cause a linker error.
template class ::plugin::RestraintModule<EnsembleRestraint>;

} // end namespace plugin
Loading

0 comments on commit 782daee

Please sign in to comment.