.. _examples-of-openmm-integration:

Examples of OpenMM Integration
###############################


GROMACS
*******

GROMACS is a large, complex application written primarily in C.  The
considerations involved in adapting it to use OpenMM are likely to be similar to
those faced by developers of other existing applications.

The first principle we followed in adapting GROMACS was to keep all OpenMM-related
code isolated to just a few files, while modifying as little of the
existing GROMACS code as possible.  This minimized the risk of breaking existing
parts of the code, while making the OpenMM-related parts as easy to work with as
possible.  It also minimized the need for C code to invoke the C++ API.  (This
would not be an issue if we used the OpenMM C API wrapper, but that is less
convenient than the C++ API, and placing all of the OpenMM calls into separate
C++ files solves the problem equally well.)  Nearly all of the OpenMM-specific
code is contained in a single file, openmm_wrapper.cpp.  It defines four
functions which encapsulate all of the interaction between OpenMM and the rest
of GROMACS:

\ :code:`openmm_init()`\ : As arguments, this function takes pointers to lots of
internal GROMACS data structures that describe the simulation to be run.  It
creates a System, Integrator, and Context based on them, then returns an opaque
reference to an object containing them.  That reference is an input argument to
all of the other functions defined in openmm_wrapper.cpp.  This allows
information to be passed between those functions without exposing it to the rest
of GROMACS.

\ :code:`openmm_take_one_step()`\ : This calls :code:`step(1)` on the
Integrator that was created by :code:`openmm_init()`\ .

\ :code:`openmm_copy_state()`\ : This calls :code:`getState()` on the
Context that was created by :code:`openmm_init()`\ , and then copies
information from the resulting State into various GROMACS data structures.  This
function is how state data generated by OpenMM is passed back to GROMACS for
output, analysis, etc.

\ :code:`openmm_cleanup()`\ : This is called at the end of the simulation.  It
deletes all the objects that were created by :code:`openmm_init()`\ .

This set of functions defines the interactions between GROMACS and OpenMM:
copying information from the application to OpenMM, performing integration,
copying information from OpenMM back to the application, and freeing resources
at the end of the simulation.  While the details of their implementations are
specific to GROMACS, this overall pattern is fairly generic.  A similar set of
functions can be used for many other applications as well.

TINKER-OpenMM
*************

TINKER is written primarily in Fortran, and uses common blocks extensively to
store application-wide parameters.  Rather than modify the TINKER build scripts
to allow C++ code, it was decided to use the OpenMM C API instead.  Despite
these differences, the overall approach used to add OpenMM support was very
similar to that used for GROMACS.

TINKER-OpenMM allows OpenMM to be used to calculate forces and energies and to
perform the integration in the main molecular dynamics loop. The only changes to
the TINKER source code are in the file :code:`dynamic.f` for the setup and
running of a simulation.  An added file, :code:`dynamic_openmm.c`\ , contains
the interface C code between TINKER and OpenMM.

The flow of the molecular dynamics simulation using OpenMM is as follows:

#. The TINKER code is used to read the AMOEBA parameter file,  the
   :code:`*.xyz` and :code:`*.key` files.  It then parses the command-line
   options.

#. The routine :code:`map_common_blocks_to_c_data_structs()` is
   called to map the FORTRAN common blocks to C data structures used in setting the
   parameters used by OpenMM.

#. The routine :code:`openmm_validate()` is called from
   :code:`dynamic.f` before the main loop.  This routine checks that all required
   options and settings obtained from the input in step (1) and common blocks in
   step (2) are available.  If an option or setting is unsupported, the program
   exits with an appropriate message.  The routine :code:`openmm_validate()`
   and the other OpenMM interface methods are in the file
   :code:`dynamic_openmm.c`\ .

#. :code:`openmm_init()` is called to create the OpenMM System,
   Integrator and Context objects..

#. :code:`openmm_take_steps()` is called to take a specified number
   of time steps.

#. :code:`openmm_update()` is then called to retrieve the state
   (energies/positions/velocities) and populate the appropriate TINKER data
   structures.  These values are converted from the OpenMM units of kJ/nm to kcal/Å
   when populating the TINKER arrays.

#. Once the main loop has completed, the routine
   :code:`openmm_cleanup()` is called to delete the OpenMM objects and release
   resources being used on the GPU.


