diff --git a/modules/mol/mm/pymod/export_topology.cc b/modules/mol/mm/pymod/export_topology.cc
index c104fbf8c7de6fbe8f85fd6b259193c7bb2f8a58..2469e7610d024cde70f8db6d45a7cbae0567affc 100644
--- a/modules/mol/mm/pymod/export_topology.cc
+++ b/modules/mol/mm/pymod/export_topology.cc
@@ -388,6 +388,7 @@ void export_Topology()
     .def("AddExclusion",&ost::mol::mm::Topology::AddExclusion,(arg("idx_one"),arg("idx_two")))
     .def("AddPositionConstraint",&ost::mol::mm::Topology::AddPositionConstraint,(arg("idx")))
     .def("ResetPositionConstraints",&ost::mol::mm::Topology::ResetPositionConstraints)
+    .def("SetDensity",&ost::mol::mm::Topology::SetDensity,(arg("density"),arg("resolution"),arg("scaling")=1.0))
     .def("ResetExclusions",&ost::mol::mm::Topology::ResetExclusions)
     .def("AddHarmonicPositionRestraint",&ost::mol::mm::Topology::AddHarmonicPositionRestraint,(arg("idx"),arg("ref_position"),arg("k"),arg("x_scale")=1.0,arg("y_scale")=1.0,arg("z_scale")=1.0))
     .def("AddHarmonicDistanceRestraint",&ost::mol::mm::Topology::AddHarmonicDistanceRestraint,(arg("idx_one"),arg("idx_two"),arg("length"),arg("force_constant")))
@@ -438,6 +439,9 @@ void export_Topology()
     .def("GetHarmonicDistanceRestraintParameters",&WrapGetHarmonicDistanceRestraintParam,(arg("interaction_idx")))
     .def("GetFGMDHBondDonorParameters",&WrapGetFGMDHBondDonorParam,(arg("interaction_idx")))
     .def("GetFGMDHBondAcceptorParameters",&WrapGetFGMDHBondAcceptorParam,(arg("interaction_idx")))
+    .def("GetDensity",&ost::mol::mm::Topology::GetDensity)
+    .def("GetDensityResolution",&ost::mol::mm::Topology::GetDensityResolution)
+    .def("GetDensityScaling",&ost::mol::mm::Topology::GetDensityResolution)
 
     //setter functions for interaction parameters
     .def("SetHarmonicBondParameters",&ost::mol::mm::Topology::SetHarmonicBondParameters,(arg("interaction_idx"),arg("bond_length"),arg("force_constant")))
diff --git a/modules/mol/mm/src/CMakeLists.txt b/modules/mol/mm/src/CMakeLists.txt
index f5d7ba62c87a26d480e10cd969fa0ac896f14c79..58cd9883c1518e6dacca772825999151e860b1d3 100644
--- a/modules/mol/mm/src/CMakeLists.txt
+++ b/modules/mol/mm/src/CMakeLists.txt
@@ -16,7 +16,11 @@ set(OST_MOL_MM_HEADERS
   index.hh
   topology.hh
   steep.hh
-
+  openmm_plugins/density_plugin/openmmapi/density_force.hh
+  openmm_plugins/density_plugin/openmmapi/density_kernels.hh
+  openmm_plugins/density_plugin/openmmapi/density_force_impl.hh
+  openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.hh
+  openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.hh
 )
 
 set(OST_MOL_MM_SOURCES
@@ -34,6 +38,8 @@ set(OST_MOL_MM_SOURCES
   topology_creator.cc
   topology.cc
   steep.cc
+  openmm_plugins/density_plugin/openmmapi/density_force.cc
+  openmm_plugins/density_plugin/openmmapi/density_force_impl.cc
 )
 
 # create settings.hh as configurational header, needed to set the plugins path
@@ -42,7 +48,7 @@ set(SETTINGS_HH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/settings.hh")
 configure_file(settings.hh.in ${SETTINGS_HH_FILE})
 
 
-set(MOL_MM_DEPS ost_mol ost_io)
+set(MOL_MM_DEPS ost_mol ost_io ost_img)
 
 
 module(NAME mol_mm SOURCES ${OST_MOL_MM_SOURCES}
@@ -62,3 +68,41 @@ copy_if_different("${CMAKE_CURRENT_SOURCE_DIR}" "${STAGE_DIR}/share/openstructur
                   "CHARMM27.dat" "CHARMM_27_FORCEFIELD"
                   "ost_mol_mm")
 install(FILES "CHARMM27.dat" DESTINATION "share/openstructure/forcefields/")
+
+#The plugins that get loaded by OpenMM have to be built seperately
+
+##########################
+#build the density plugin#
+##########################
+
+#define the sources (headers are already handled above)
+SET(DENSITY_PLUGIN_REFERENCE_SOURCES
+  openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.cc
+  openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.cc
+)
+
+# Set the library name
+SET(OPENMM_DENSITY_REFERENCE_LIBRARY_NAME density_plugin_reference)
+SET(SHARED_TARGET_DENSITY_PLUGIN ${OPENMM_DENSITY_REFERENCE_LIBRARY_NAME})
+
+ADD_LIBRARY(${SHARED_TARGET_DENSITY_PLUGIN} SHARED ${DENSITY_PLUGIN_REFERENCE_SOURCES})
+ADD_DEPENDENCIES(${SHARED_TARGET_DENSITY_PLUGIN} ost_mol_mm ost_img ost_mol_mm)
+
+SET_TARGET_PROPERTIES(${SHARED_TARGET_DENSITY_PLUGIN} PROPERTIES
+                      LIBRARY_OUTPUT_DIRECTORY ${STAGE_DIR}/share/openstructure/openmm_plugins/
+                      ARCHIVE_OUTPUT_DIRECTORY ${STAGE_DIR}/share/openstructure/openmm_plugins/
+                      RUNTIME_OUTPUT_DIRECTORY ${STAGE_DIR}/share/openstructure/openmm_plugins/)
+
+foreach(_DEPENDENCY ${_MOL_MM_DEPS})
+  TARGET_LINK_LIBRARIES(${SHARED_TARGET_DENSITY_PLUGIN} ${_DEPENDENCY})
+endforeach()
+#also link against OpenMM and the mm module
+TARGET_LINK_LIBRARIES(${SHARED_TARGET_DENSITY_PLUGIN} ${OPEN_MM_LIBRARIES})
+TARGET_LINK_LIBRARIES(${SHARED_TARGET_DENSITY_PLUGIN} ost_mol_mm)
+
+file(MAKE_DIRECTORY ${STAGE_DIR}/share/openstructure/openmm_plugins/)
+INSTALL(TARGETS ${SHARED_TARGET_DENSITY_PLUGIN} LIBRARY DESTINATION "${STAGE_DIR}/share/openstructure/openmm_plugins/")
+
+
+
+
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force.cc b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8ff809d9a768edb8efd64acbde96fe2e51bcae31
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force.cc
@@ -0,0 +1,97 @@
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <ost/mol/mm/density_force.hh>
+#include <ost/mol/mm/density_force_impl.hh>
+#include <openmm/OpenMMException.h>
+#include <openmm/internal/AssertionUtilities.h>
+#include <string.h>
+
+namespace ost{ namespace mol{ namespace mm{
+
+OpenMM::ForceImpl* DensityForce::createImpl() const {
+    return new DensityForceImpl(*this);
+}
+
+void DensityForce::updateParametersInContext(OpenMM::Context& context) {
+    dynamic_cast<DensityForceImpl&>(getImplInContext(context)).updateParametersInContext(getContextImpl(context));
+}
+
+void DensityForce::addParticle(Real mass){
+  masses_.push_back(mass);
+  in_body_.push_back(false);
+}
+
+Real DensityForce::getParticleMass(int idx) const{
+  if(idx >= this->getNumParticles() || idx < 0){
+    throw OpenMM::OpenMMException("Invalid index provided!");
+  }
+  return masses_[idx];
+}
+
+bool DensityForce::isInBody(int idx) const{
+  if(idx >= this->getNumParticles() || idx < 0){
+    throw OpenMM::OpenMMException("Invalid index provided!");
+  }
+  return in_body_[idx];
+}
+
+void DensityForce::defineBody(const std::vector<int>& indices){
+  //first check, whether any of the indices is invalid or already part of a body
+  int num_particles = this->getNumParticles();
+  for(std::vector<int>::const_iterator i = indices.begin();
+      i != indices.end(); ++i){
+    if(*i >= num_particles || *i < 0){
+      throw OpenMM::OpenMMException("Invalid index provided!");
+    }
+    if(in_body_[*i]){
+      throw OpenMM::OpenMMException("Particle can be part of only one body!");
+    }
+  }
+
+  //let's change the state of the according particles
+  for(std::vector<int>::const_iterator i = indices.begin();
+      i != indices.end(); ++i){
+    in_body_[*i] = true;
+  }
+
+  //and finally define the body
+  bodies_.push_back(indices);
+}
+
+const std::vector<int>& DensityForce::getBody(int idx) const{
+  if(idx >= this->getNumBodies() || idx < 0){
+    throw OpenMM::OpenMMException("Invalid index provided!");
+  }
+  return bodies_[idx];
+}
+
+}}} //ns
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force.hh b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f932ff797b978cd54ebe8be72c03935f587f73af
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force.hh
@@ -0,0 +1,94 @@
+#ifndef OPENMM_DENSITYFORCE_H_
+#define OPENMM_DENSITYFORCE_H_
+
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <openmm/Context.h>
+#include <openmm/Force.h>
+#include <ost/img/image.hh>
+
+namespace ost { namespace mol{ namespace mm{
+
+
+class DensityForce : public OpenMM::Force {
+public:
+    /**
+     * Create an DensityForce. The density force only makes sense for simulation boxes
+     * with orthogonal base vectors.
+     */
+
+    //since the density is scaled in Angstrom, the resolution is also in Angstrom
+    DensityForce(const ost::img::ImageHandle& d, Real r, Real s): density_(d),
+                                                                   resolution_(r),
+                                                                   scaling_(s) { }
+
+    void addParticle(Real mass);
+
+    int getNumParticles() const { return masses_.size(); }
+
+    int getNumBodies() const { return bodies_.size(); }
+
+    Real getParticleMass(int idx) const;
+
+    bool isInBody(int idx) const;
+
+    void defineBody(const std::vector<int>& indices);
+
+    const std::vector<int>& getBody(int idx) const;
+
+    void setScaling(Real scaling) { scaling_ = scaling; }
+
+    Real getScaling() const { return scaling_; }
+
+    ost::img::ImageHandle getDensity() const { return density_; }
+
+    Real getResolution() const { return resolution_; }
+
+    void updateParametersInContext(OpenMM::Context& context);
+
+    bool usesPeriodicBoundaryConditions() const { return false; }
+      
+protected:
+    OpenMM::ForceImpl* createImpl() const;
+private:
+
+    ost::img::ImageHandle density_;
+    std::vector<Real> masses_;
+    std::vector<bool> in_body_;
+    std::vector<std::vector<int> > bodies_;
+    Real resolution_;
+    Real scaling_;
+};
+
+}}} // ns
+
+#endif /*OPENMM_DENSITYFORCE_H_*/
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force_impl.cc b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1d2b859a0eb006fe13c389a9818d2958bc69a801
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force_impl.cc
@@ -0,0 +1,71 @@
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <ost/mol/mm/density_force_impl.hh>
+#include <ost/mol/mm/density_kernels.hh>
+#include <openmm/OpenMMException.h>
+#include <openmm/internal/ContextImpl.h>
+#include <cmath>
+#include <map>
+#include <set>
+#include <sstream>
+
+namespace ost{ namespace mol{ namespace mm{
+
+DensityForceImpl::DensityForceImpl(const DensityForce& owner) : owner(owner) {
+}
+
+DensityForceImpl::~DensityForceImpl() {
+}
+
+void DensityForceImpl::initialize(OpenMM::ContextImpl& context) {
+    kernel = context.getPlatform().createKernel(CalcDensityForceKernel::Name(), context);
+    kernel.getAs<CalcDensityForceKernel>().initialize(context.getSystem(), owner);
+}
+
+double DensityForceImpl::calcForcesAndEnergy(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
+    if ((groups&(1<<owner.getForceGroup())) != 0)
+        return kernel.getAs<CalcDensityForceKernel>().execute(context, includeForces, includeEnergy);
+    return 0.0;
+}
+
+std::vector<std::string> DensityForceImpl::getKernelNames() {
+    std::vector<std::string> names;
+    names.push_back(CalcDensityForceKernel::Name());
+    return names;
+}
+
+void DensityForceImpl::updateParametersInContext(OpenMM::ContextImpl& context) {
+    kernel.getAs<CalcDensityForceKernel>().copyParametersToContext(context, owner);
+}
+
+}}} //ns
+
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force_impl.hh b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force_impl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..850b2c5c23a33b48773bcc29b5001f1ad904353b
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_force_impl.hh
@@ -0,0 +1,74 @@
+#ifndef OPENMM_DENSITYFORCEIMPL_H_
+#define OPENMM_DENSITYFORCEIMPL_H_
+
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <ost/mol/mm/density_force.hh>
+#include <openmm/internal/ForceImpl.h>
+#include <openmm/Kernel.h>
+#include <utility>
+#include <set>
+#include <string>
+
+namespace ost{ namespace mol{ namespace mm{
+
+/**
+ * This is the internal implementation of DensityForce.
+ */
+
+class DensityForceImpl : public OpenMM::ForceImpl {
+public:
+    DensityForceImpl(const DensityForce& owner);
+    ~DensityForceImpl();
+    void initialize(OpenMM::ContextImpl& context);
+    const DensityForce& getOwner() const {
+        return owner;
+    }
+    void updateContextState(OpenMM::ContextImpl& context) {
+        // This force field doesn't update the state directly.
+    }
+    double calcForcesAndEnergy(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
+    std::map<std::string, double> getDefaultParameters() {
+        return std::map<std::string, double>(); // This force field doesn't define any parameters.
+    }
+    std::vector<std::string> getKernelNames();
+
+    void updateParametersInContext(OpenMM::ContextImpl& context);
+private:
+    const DensityForce& owner;
+    OpenMM::Kernel kernel;
+};
+
+}}} //ns
+
+#endif /*OPENMM_DENSITYFORCEIMPL_H_*/
+
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_kernels.hh b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_kernels.hh
new file mode 100644
index 0000000000000000000000000000000000000000..78e16cfa795519c82252b7edce168329ea404e97
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/openmmapi/density_kernels.hh
@@ -0,0 +1,80 @@
+#ifndef DENSITY_KERNELS_H_
+#define DENSITY_KERNELS_H_
+
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <ost/mol/mm/density_force.hh>
+#include <openmm/KernelImpl.h>
+#include <openmm/Platform.h>
+#include <openmm/System.h>
+#include <string>
+
+namespace ost{ namespace mol{ namespace mm{
+
+/**
+ * This kernel is invoked by DensityForce to calculate the forces acting on the system and the energy of the system.
+ */
+class CalcDensityForceKernel : public OpenMM::KernelImpl {
+public:
+    static std::string Name() {
+        return "CalcDensityForce";
+    }
+    CalcDensityForceKernel(std::string name, const OpenMM::Platform& platform) : OpenMM::KernelImpl(name, platform) {
+    }
+    /**
+     * Initialize the kernel.
+     * 
+     * @param system     the System this kernel will be applied to
+     * @param force      the DensityForce this kernel will be used for
+     */
+    virtual void initialize(const OpenMM::System& system, const DensityForce& force) = 0;
+    /**
+     * Execute the kernel to calculate the forces and/or energy.
+     *
+     * @param context        the context in which to execute this kernel
+     * @param includeForces  true if forces should be calculated
+     * @param includeEnergy  true if the energy should be calculated
+     * @return the potential energy due to the force
+     */
+    virtual double execute(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy) = 0;
+    /**
+     * Copy changed parameters over to a context.
+     *
+     * @param context    the context to copy parameters to
+     * @param force      the DensityForce to copy the parameters from
+     */
+    virtual void copyParametersToContext(OpenMM::ContextImpl& context, const DensityForce& force) = 0;
+};
+
+}}} //ns
+
+#endif /*DENSITY_KERNELS_H_*/
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.cc b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8df88868d90895b7b48b89e436799fd3bde97956
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.cc
@@ -0,0 +1,62 @@
+/* -------------------------------------------------------------------------- *
+ *                              OpenMMExample                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <ost/mol/mm/reference_density_kernel_factory.hh>
+#include <ost/mol/mm/reference_density_kernels.hh>
+#include <openmm/reference/ReferencePlatform.h>
+#include <openmm/internal/ContextImpl.h>
+#include <openmm/OpenMMException.h>
+
+using namespace ost::mol::mm;
+
+extern "C" void registerPlatforms() {
+}
+
+extern "C" void registerKernelFactories() {
+    for (int i = 0; i < OpenMM::Platform::getNumPlatforms(); i++) {
+        OpenMM::Platform& platform = OpenMM::Platform::getPlatform(i);
+        if (dynamic_cast<OpenMM::ReferencePlatform*>(&platform) != NULL) {
+            ReferenceDensityKernelFactory* factory = new ReferenceDensityKernelFactory();
+            platform.registerKernelFactory(CalcDensityForceKernel::Name(), factory);
+        }
+    }
+}
+
+extern "C" void registerDensityReferenceKernelFactories() {
+    registerKernelFactories();
+}
+
+OpenMM::KernelImpl* ReferenceDensityKernelFactory::createKernelImpl(std::string name, const OpenMM::Platform& platform, OpenMM::ContextImpl& context) const {
+    OpenMM::ReferencePlatform::PlatformData& data = *static_cast<OpenMM::ReferencePlatform::PlatformData*>(context.getPlatformData());
+    if (name == CalcDensityForceKernel::Name())
+        return new ReferenceCalcDensityForceKernel(name, platform);
+    throw OpenMM::OpenMMException((std::string("Tried to create kernel with illegal kernel name '")+name+"'").c_str());
+}
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.hh b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.hh
new file mode 100644
index 0000000000000000000000000000000000000000..14dfdf44c23060f65f12c3939815b8bd27664608
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernel_factory.hh
@@ -0,0 +1,53 @@
+#ifndef OPENMM_REFERENCEDensityKERNELFACTORY_H_
+#define OPENMM_REFERENCEDensityKERNELFACTORY_H_
+
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <openmm/KernelFactory.h>
+
+/**
+ * This KernelFactory creates kernels for the reference implementation of the Density plugin.
+ */
+
+namespace ost{ namespace mol{ namespace mm{
+
+class ReferenceDensityKernelFactory : public OpenMM::KernelFactory {
+public:
+    OpenMM::KernelImpl* createKernelImpl(std::string name, 
+                                         const OpenMM::Platform& platform, 
+                                         OpenMM::ContextImpl& context) const;
+};
+
+
+}}} //ns
+
+#endif /*OPENMM_REFERENCEDENSITYKERNELFACTORY_H_*/
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.cc b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.cc
new file mode 100644
index 0000000000000000000000000000000000000000..aeefb13871dd53b16c97501df1917fa31cf51e4b
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.cc
@@ -0,0 +1,342 @@
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <ost/mol/mm/reference_density_kernels.hh>
+#include <ost/mol/mm/density_force.hh>
+#include <openmm/OpenMMException.h>
+#include <openmm/internal/ContextImpl.h>
+#include <openmm/reference/RealVec.h>
+#include <openmm/reference/ReferencePlatform.h>
+
+using namespace OpenMM;
+using namespace std;
+
+namespace{
+
+static vector<RealVec>& extractPositions(ContextImpl& context) {
+  ReferencePlatform::PlatformData* data = 
+  reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
+  return *((vector<RealVec>*) data->positions);
+}
+
+static vector<RealVec>& extractForces(ContextImpl& context) {
+    ReferencePlatform::PlatformData* data = 
+    reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
+    return *((vector<RealVec>*) data->forces);
+}
+
+} //anon ns
+
+
+namespace ost{ namespace mol { namespace mm{
+
+ReferenceCalcDensityForceKernel::~ReferenceCalcDensityForceKernel(){
+  if(data_ != NULL) delete [] data_;
+}
+
+void ReferenceCalcDensityForceKernel::initialize(const System& system, const DensityForce& force) {
+
+  if(system.getNumParticles() != force.getNumParticles()){
+    std::string err = "DensityForce must contain same number of";
+    err += " particles as system!";
+    throw OpenMM::OpenMMException(err);
+  }
+
+  if(data_ != NULL) delete [] data_;
+
+  ost::img::ImageHandle density = force.getDensity();
+
+  x_sampling_ = density.GetSpatialSampling()[0] * 0.1;
+  y_sampling_ = density.GetSpatialSampling()[1] * 0.1;
+  z_sampling_ = density.GetSpatialSampling()[2] * 0.1;
+  one_over_x_sampling_ = Real(1.0) / x_sampling_;
+  one_over_y_sampling_ = Real(1.0) / y_sampling_;
+  one_over_z_sampling_ = Real(1.0) / z_sampling_;
+  half_x_sampling_ = Real(0.5) * x_sampling_;
+  half_y_sampling_ = Real(0.5) * y_sampling_;
+  half_z_sampling_ = Real(0.5) * z_sampling_;
+  x_origin_ = density.GetAbsoluteOrigin()[0] * 0.1;
+  y_origin_ = density.GetAbsoluteOrigin()[1] * 0.1;
+  z_origin_ = density.GetAbsoluteOrigin()[2] * 0.1;
+  x_extent_ = density.GetSize()[0];
+  y_extent_ = density.GetSize()[1];
+  z_extent_ = density.GetSize()[2];
+
+  data_ = new Real[x_extent_ * y_extent_ * z_extent_];
+  int current_idx = 0;
+  for(int i = 0; i < x_extent_; ++i){
+    for(int j = 0; j < y_extent_; ++j){
+      for(int k = 0; k < z_extent_; ++k){
+        data_[current_idx] = density.GetReal(ost::img::Point(i,j,k));
+        ++current_idx;
+      }
+    }
+  }
+
+  idx_helper_one_ = y_extent_ * z_extent_;
+  idx_helper_two_ = z_extent_;
+
+  //sigma for gaussian like representations of the atoms
+  resolution_ = force.getResolution() * 0.1;
+  s_ = resolution_ * 0.425;
+  one_s_ = Real(1.0) / s_;
+  square_one_s_ = Real(1.0) / (s_ * s_);
+  one_sqrt_2_pi_s_ = Real(1.0) / std::sqrt(Real(2.0) * Real(M_PI) * s_);
+  padding_dist_ = s_ * Real(2.0);
+  scaling_ = 10000 * force.getScaling();
+
+  //let's get body and particle info...
+
+  num_particles_ = system.getNumParticles();
+  num_bodies_ = force.getNumBodies();
+
+  particle_masses_.resize(num_particles_);
+
+  for(int i = 0; i < num_particles_; ++i){
+    particle_masses_[i] = force.getParticleMass(i);
+  }
+
+  bodies_.clear();
+  //let's set every particle not belonging to a body to its own body
+  for(int i = 0; i < num_particles_; ++i){
+    if(force.isInBody(i)) continue;
+      std::vector<int> body(1,i);
+      bodies_.push_back(body);
+  }
+
+  //let's fill the defined bodies!
+  for(int i = 0; i < num_bodies_; ++i){
+    const std::vector<int>& current_body = force.getBody(i);
+    bodies_.push_back(current_body);
+  }
+
+  //let's update the num_bodies_ !!!
+  num_bodies_ = bodies_.size();
+}
+
+double ReferenceCalcDensityForceKernel::execute(ContextImpl& context, 
+                                                bool includeForces, 
+                                                bool includeEnergy) {
+
+
+
+  vector<RealVec>& pos = extractPositions(context);
+  vector<RealVec>& force = extractForces(context);
+
+  //distance of a density position towards a particle
+  Real x_d;
+  Real y_d;
+  Real z_d;
+
+  //derivative of a full body
+  Real body_dx;
+  Real body_dy;
+  Real body_dz;
+
+  //return value for the full energy, will be updated when iterating over
+  //all bodies
+  Real overall_energy = 0.0;
+
+  //some helper variables
+  Real dd;
+  Real e_term;
+  Real density;
+  Real p_density;
+  std::vector<Real> p_dx;
+  std::vector<Real> p_dy;
+  std::vector<Real> p_dz;
+  std::vector<Real> p_m;
+  Real denominator;
+  Real nominator;
+  Real a, b;
+  Real temp_one, temp_two;
+  Real prefac;
+  Real min_x_pos, max_x_pos;
+  Real min_y_pos, max_y_pos;
+  Real min_z_pos, max_z_pos;
+  Real body_x_origin, body_y_origin, body_z_origin;
+  int body_x_extent, body_y_extent, body_z_extent;
+  int num_voxels;
+
+  for(int body_idx = 0; body_idx < num_bodies_; ++body_idx){
+        
+    int body_size = bodies_[body_idx].size();
+
+    //set derivatives for every particle in each direction to zero
+    //and extract the required masses
+    p_dx.assign(body_size,0.0);
+    p_dy.assign(body_size,0.0);
+    p_dz.assign(body_size,0.0);
+    p_m.resize(body_size);
+
+    for(int p_idx = 0; p_idx < body_size; ++p_idx){
+      p_m[p_idx] = particle_masses_[bodies_[body_idx][p_idx]];
+    }
+
+    min_x_pos = std::numeric_limits<Real>::max();
+    max_x_pos = -std::numeric_limits<Real>::max();
+    min_y_pos = std::numeric_limits<Real>::max();
+    max_y_pos = -std::numeric_limits<Real>::max();
+    min_z_pos = std::numeric_limits<Real>::max();
+    max_z_pos = -std::numeric_limits<Real>::max();
+
+    //let's find out how big this thing is...
+    for(int p_idx = 0; p_idx < body_size; ++p_idx){
+      RealVec& p = pos[bodies_[body_idx][p_idx]];
+      min_x_pos = (p[0] < min_x_pos) ? p[0]: min_x_pos;
+      max_x_pos = (p[0] > max_x_pos) ? p[0]: max_x_pos;
+      min_y_pos = (p[1] < min_y_pos) ? p[1]: min_y_pos;
+      max_y_pos = (p[1] > max_y_pos) ? p[1]: max_y_pos;
+      min_z_pos = (p[2] < min_z_pos) ? p[2]: min_z_pos;
+      max_z_pos = (p[2] > max_z_pos) ? p[2]: max_z_pos;
+    }
+
+    //we add some padding
+    min_x_pos -= padding_dist_;
+    max_x_pos += padding_dist_;
+    min_y_pos -= padding_dist_;
+    max_y_pos += padding_dist_;
+    min_z_pos -= padding_dist_;
+    max_z_pos += padding_dist_;
+
+    body_x_extent = std::max(3, 
+      static_cast<int>(std::ceil((max_x_pos - min_x_pos)*one_over_x_sampling_)));
+    body_y_extent = std::max(3, 
+      static_cast<int>(std::ceil((max_y_pos - min_y_pos)*one_over_y_sampling_)));
+    body_z_extent = std::max(3, 
+      static_cast<int>(std::ceil((max_z_pos - min_z_pos)*one_over_z_sampling_)));
+    num_voxels = body_x_extent * body_y_extent * body_z_extent;
+
+    Real overlap = min_x_pos + body_x_extent * x_sampling_ - max_x_pos;
+    body_x_origin = min_x_pos - 0.5 * overlap;
+    overlap = min_y_pos + body_y_extent * y_sampling_ - max_y_pos;
+    body_y_origin = min_y_pos - 0.5 * overlap;
+    overlap = min_z_pos + body_z_extent * z_sampling_ - max_z_pos;
+    body_z_origin = min_z_pos - 0.5 * overlap;
+
+
+    density_values_.resize(num_voxels);
+    body_values_.assign(num_voxels,0.0);
+
+    //let's fill the density values
+    int current_idx = 0;
+    for(int i = 0; i < body_x_extent; ++i){
+        for(int j = 0; j < body_y_extent; ++j){
+            for(int k = 0; k < body_z_extent; ++k){
+                density_values_[current_idx] = 
+                this->GetIntpolValue(body_x_origin + i * x_sampling_ + half_x_sampling_,
+                                     body_y_origin + j * y_sampling_ + half_y_sampling_,
+                                     body_z_origin + k * z_sampling_ + half_z_sampling_);
+                ++current_idx;
+            }
+        }
+    }
+
+    for(int p_idx = 0; p_idx < body_size; ++p_idx){
+
+      //the actual position of the particle
+      RealVec& p = pos[bodies_[body_idx][p_idx]];
+      current_idx = 0;
+
+      for(int i = 0; i < body_x_extent; ++i){
+
+        x_d = p[0] - (body_x_origin + i * x_sampling_ + half_x_sampling_);
+
+        for(int j = 0; j < body_y_extent; ++j){
+
+          y_d = p[1] - (body_y_origin + j * y_sampling_ + half_y_sampling_);
+
+          for(int k = 0; k < body_z_extent; ++k){
+
+            z_d = p[2] - (body_z_origin + k * z_sampling_ + half_z_sampling_);
+                        
+            dd = x_d * x_d + y_d * y_d + z_d * z_d;
+
+            e_term = std::exp(Real(-0.5) * dd * square_one_s_);
+            density = density_values_[current_idx];
+            p_dx[p_idx] += (density * (x_d * one_s_) * e_term);
+            p_dy[p_idx] += (density * (y_d * one_s_) * e_term);
+            p_dz[p_idx] += (density * (z_d * one_s_) * e_term);
+            p_density = p_m[p_idx] * one_sqrt_2_pi_s_ * e_term;
+            body_values_[current_idx] += p_density;
+            ++current_idx;
+
+          }
+        }
+      }
+    }
+
+    nominator = 0.0;
+    denominator = 0.0;
+    temp_one = 0.0;
+    temp_two = 0.0;
+
+    for(int i = 0; i < num_voxels; ++i){
+      a = density_values_[i];
+      b = body_values_[i];
+      nominator += (a * b);
+      temp_one += (a * a);
+      temp_two += (b * b);
+    }        
+
+    if(temp_one == 0.0 || temp_two == 0.0) continue;
+
+    denominator = std::sqrt(temp_one * temp_two);
+    prefac = scaling_ / denominator * one_sqrt_2_pi_s_; 
+
+    body_dx = 0.0;
+    body_dy = 0.0;
+    body_dz = 0.0;
+
+    for(int p_idx = 0; p_idx < body_size; ++p_idx){
+      body_dx -= prefac * p_m[p_idx] * p_dx[p_idx];
+      body_dy -= prefac * p_m[p_idx] * p_dy[p_idx];
+      body_dz -= prefac * p_m[p_idx] * p_dz[p_idx];
+    }
+
+    //finally update the forces accordingly
+    for(int p_idx = 0; p_idx < body_size; ++p_idx){
+      force[bodies_[body_idx][p_idx]][0] += body_dx;
+      force[bodies_[body_idx][p_idx]][1] += body_dy;
+      force[bodies_[body_idx][p_idx]][2] += body_dz;
+    }
+
+    overall_energy -= (scaling_ * nominator/denominator);
+  }
+
+  return overall_energy;
+}
+
+void ReferenceCalcDensityForceKernel::copyParametersToContext(ContextImpl& context, const DensityForce& force) {
+  //ToDo
+}
+
+}}} //ns
diff --git a/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.hh b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.hh
new file mode 100644
index 0000000000000000000000000000000000000000..7a06088ee572d7d91e606601d2fe9eb0b41725a2
--- /dev/null
+++ b/modules/mol/mm/src/openmm_plugins/density_plugin/platforms/reference/reference_density_kernels.hh
@@ -0,0 +1,164 @@
+#ifndef REFERENCE_DENSITY_KERNELS_H_
+#define REFERENCE_DENSITY_KERNELS_H_
+
+/* -------------------------------------------------------------------------- *
+ *                                   OpenMM                                   *
+ * -------------------------------------------------------------------------- *
+ * This is part of the OpenMM molecular simulation toolkit originating from   *
+ * Simbios, the NIH National Center for Physics-Based Simulation of           *
+ * Biological Structures at Stanford, funded under the NIH Roadmap for        *
+ * Medical Research, grant U54 GM072970. See https://simtk.org.               *
+ *                                                                            *
+ * Portions copyright (c) 2014 Stanford University and the Authors.           *
+ * Authors: Peter Eastman                                                     *
+ * Contributors:                                                              *
+ *                                                                            *
+ * Permission is hereby granted, free of charge, to any person obtaining a    *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation  *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
+ * and/or sell copies of the Software, and to permit persons to whom the      *
+ * Software is furnished to do so, subject to the following conditions:       *
+ *                                                                            *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software.                        *
+ *                                                                            *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
+ * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
+ * -------------------------------------------------------------------------- */
+
+#include <ost/mol/mm/density_kernels.hh>
+#include <openmm/Platform.h>
+#include <vector>
+#include <set>
+#include <limits> 
+
+namespace ost{ namespace mol{ namespace mm{
+
+/**
+ * This kernel is invoked by DensityForce to calculate the forces acting on the system and the energy of the system.
+ */
+class ReferenceCalcDensityForceKernel : public CalcDensityForceKernel {
+public:
+    ReferenceCalcDensityForceKernel(std::string name, const OpenMM::Platform& platform) : CalcDensityForceKernel(name, platform), data_(NULL) {
+    }
+
+    ~ReferenceCalcDensityForceKernel();
+
+    /**
+     * Initialize the kernel.
+     * 
+     * @param system     the System this kernel will be applied to
+     * @param force      the DensityForce this kernel will be used for
+     */
+    void initialize(const OpenMM::System& system, const DensityForce& force);
+    /**
+     * Execute the kernel to calculate the forces and/or energy.
+     *
+     * @param context        the context in which to execute this kernel
+     * @param includeForces  true if forces should be calculated
+     * @param includeEnergy  true if the energy should be calculated
+     * @return the potential energy due to the force
+     */
+    double execute(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy);
+    /**
+     * Copy changed parameters over to a context.
+     *
+     * @param context    the context to copy parameters to
+     * @param force      the DensityForce to copy the parameters from
+     */
+    void copyParametersToContext(OpenMM::ContextImpl& context, const DensityForce& force);
+private:
+
+    inline Real GetValue(int a, int b, int c){
+      return data_[a * idx_helper_one_ + b * idx_helper_two_ + c];
+    }
+
+    inline Real GetIntpolValue(Real x, Real y, Real z){
+
+      //distances to origin
+      Real dx = x - x_origin_;
+      Real dy = y - y_origin_;
+      Real dz = z - z_origin_;
+
+      int x_bin = std::floor(dx * one_over_x_sampling_);
+      int y_bin = std::floor(dy * one_over_y_sampling_);
+      int z_bin = std::floor(dz * one_over_z_sampling_);
+
+      if(x_bin < 0 || x_bin >= (x_extent_-1) || 
+         y_bin < 0 || y_bin >= (y_extent_-1) ||
+         z_bin < 0 || z_bin >= (z_extent_-1)) return 0.0;
+
+      //distances in fraction of bin towards base bin
+      dx = (dx - x_bin * x_sampling_) * one_over_x_sampling_;
+      dy = (dy - y_bin * y_sampling_) * one_over_y_sampling_;
+      dz = (dz - z_bin * z_sampling_) * one_over_z_sampling_;
+
+      intpol_values_[0] = this->GetValue(x_bin,y_bin,z_bin);
+      intpol_values_[1] = this->GetValue(x_bin+1,y_bin,z_bin);
+      intpol_values_[2] = this->GetValue(x_bin,y_bin+1,z_bin);
+      intpol_values_[3] = this->GetValue(x_bin+1,y_bin+1,z_bin);
+      intpol_values_[4] = this->GetValue(x_bin,y_bin,z_bin+1);
+      intpol_values_[5] = this->GetValue(x_bin+1,y_bin,z_bin+1);
+      intpol_values_[6] = this->GetValue(x_bin,y_bin+1,z_bin+1);
+      intpol_values_[7] = this->GetValue(x_bin+1,y_bin+1,z_bin+1);
+
+      //do first bilinear interpolation
+      Real f11 = (1.0 - dx) * intpol_values_[0] + dx * intpol_values_[1];
+      Real f12 = (1.0 - dx) * intpol_values_[2] + dx * intpol_values_[3];
+      Real f21 = (1.0 - dx) * intpol_values_[4] + dx * intpol_values_[5];
+      Real f22 = (1.0 - dx) * intpol_values_[6] + dx * intpol_values_[7];
+
+      Real f1 = (1.0 - dy) * f11 + dy * f12;
+      Real f2 = (1.0 - dy) * f21 + dy * f22;
+
+      return (1.0 - dz) * f1 + dz * f2;
+    }
+
+    //this stuff is required to store and extract the internal density values
+    Real* data_;
+    Real intpol_values_[8];
+    int idx_helper_one_;
+    int idx_helper_two_;
+    Real x_sampling_;
+    Real y_sampling_;
+    Real z_sampling_;
+    Real one_over_x_sampling_;
+    Real one_over_y_sampling_;
+    Real one_over_z_sampling_;
+    Real half_x_sampling_;
+    Real half_y_sampling_;
+    Real half_z_sampling_;
+    Real x_origin_;
+    Real y_origin_;
+    Real z_origin_;
+    int x_extent_;
+    int y_extent_;
+    int z_extent_;
+
+    //this is stuff used in the actual force calculation
+    Real resolution_;
+    Real s_;
+    Real one_s_;
+    Real square_one_s_;
+    Real one_sqrt_2_pi_s_;
+    Real padding_dist_;
+    Real scaling_;
+    std::vector<Real> density_values_;
+    std::vector<Real> body_values_;
+
+    //this is stuff containing information of the simulated system
+    int num_bodies_;
+    int num_particles_;
+    std::vector<float> particle_masses_;
+    std::vector<std::vector<int> > bodies_;
+};
+
+}}} // ns
+
+#endif /*REFERENCE_DENSITY_KERNELS_H_*/
diff --git a/modules/mol/mm/src/settings.hh.in b/modules/mol/mm/src/settings.hh.in
index b3f5511a1d65f35e3f54bd8f4559549f3fdda4ba..50dd9b71abcbd4eb2e9f9229642f40a4843585a1 100644
--- a/modules/mol/mm/src/settings.hh.in
+++ b/modules/mol/mm/src/settings.hh.in
@@ -135,7 +135,7 @@ struct Settings{
                 use_dispersion_correction(true),
                 keep_ff_specific_naming(true),
                 openmm_plugin_directory("@OPEN_MM_PLUGIN_DIR@"),
-                custom_plugin_directory("@OPEN_MM_PLUGIN_DIR@")
+                custom_plugin_directory("@STAGE_DIR@/share/openstructure/openmm_plugins")
 
                   {   }
 
diff --git a/modules/mol/mm/src/simulation.cc b/modules/mol/mm/src/simulation.cc
index 830b9bd5b6a1b14f92fdaf99248c95c279158dbb..d4e411becfbd9c25737c024cd5e3ca1793dd0f45 100644
--- a/modules/mol/mm/src/simulation.cc
+++ b/modules/mol/mm/src/simulation.cc
@@ -161,6 +161,7 @@ SimulationPtr Simulation::Load(const String& filename, SettingsPtr settings){
   sim_ptr->integrator_ = settings->integrator;
 
   OpenMM::Platform::loadPluginsFromDirectory (settings->openmm_plugin_directory);
+  OpenMM::Platform::loadPluginsFromDirectory (settings->custom_plugin_directory);
   OpenMM::Platform* platform;
 
   switch(settings->platform){
@@ -285,6 +286,7 @@ void Simulation::Init(const TopologyPtr top,
   //to proceed in time, but first we have to load the proper platform
 
   OpenMM::Platform::loadPluginsFromDirectory (settings->openmm_plugin_directory);
+  OpenMM::Platform::loadPluginsFromDirectory (settings->custom_plugin_directory);
   OpenMM::Platform* platform;
   std::map<String,String> context_properties;
 
diff --git a/modules/mol/mm/src/system_creator.cc b/modules/mol/mm/src/system_creator.cc
index 2912a5dcab88240f5d0c254bcc4659aa3ba922af..223f7ea9e540df0b56941f4cd25141622156297f 100644
--- a/modules/mol/mm/src/system_creator.cc
+++ b/modules/mol/mm/src/system_creator.cc
@@ -18,6 +18,7 @@
 //------------------------------------------------------------------------------
 
 #include <ost/mol/mm/system_creator.hh>
+#include <ost/mol/mm/density_force.hh>
 #include <OpenMM.h>
 
 namespace ost{ namespace mol{ namespace mm{
@@ -437,6 +438,27 @@ SystemPtr SystemCreator::Create(const TopologyPtr top,
                                                                            settings->barostat_frequency);
     sys->addForce(&barostat);
   }
+
+  //add density if valid
+  ost::img::ImageHandle density = top->GetDensity();
+  if(density.IsValid()){
+    Real r = top->GetDensityResolution();
+    Real s = top->GetDensityScaling();
+    DensityForce* density_force_ptr = new DensityForce(density,r,s);
+    for(std::vector<Real>::iterator i = masses.begin(); 
+        i != masses.end(); ++i){
+      density_force_ptr->addParticle(*i);
+    }
+    const std::vector<std::vector<int> >& density_bodies = top->GetDensityBodies();
+    for(std::vector<std::vector<int> >::const_iterator i = density_bodies.begin();
+        i != density_bodies.end(); ++i){
+      density_force_ptr->defineBody(*i);
+    }
+    sys->addForce(density_force_ptr);
+  }
+
+
+
   return sys;
 }
 }}} //ns
diff --git a/modules/mol/mm/src/topology.cc b/modules/mol/mm/src/topology.cc
index 448e25490f6b8486b60f44b1e34bb55750d2fbcc..819d2d500c12de758ec13436909c1645f01d52f3 100644
--- a/modules/mol/mm/src/topology.cc
+++ b/modules/mol/mm/src/topology.cc
@@ -255,6 +255,41 @@ void Topology::AddPositionConstraint(uint index){
   position_constraints_.push_back(index);
 }
 
+void Topology::SetDensity(const ost::img::ImageHandle& d, Real r, Real s){
+  density_ = d;
+  density_resolution_ = r;
+  density_scaling_ = s;
+  in_density_body_.assign(num_particles_,false);
+  density_bodies_.clear();
+}
+
+void Topology::DefineDensityBody(const std::vector<int>& indices){
+
+  if(!density_.IsValid()){
+    throw ost::Error("Must set valid density before you can define density bodies");
+  }
+
+  //first check, whether any of the indices is invalid or already part of a body
+  for(std::vector<int>::const_iterator i = indices.begin();
+      i != indices.end(); ++i){
+    if(*i >= static_cast<int>(num_particles_) || *i < 0){
+      throw ost::Error("Invalid index provided!");
+    }
+    if(in_density_body_[*i]){
+      throw ost::Error("Particle can be part of only one body!");
+    }
+  }
+
+  //let's change the state of the according particles
+  for(std::vector<int>::const_iterator i = indices.begin();
+      i != indices.end(); ++i){
+    in_density_body_[*i] = true;
+  }
+
+  //and finally define the body
+  density_bodies_.push_back(indices);
+}
+
 uint Topology::AddHarmonicPositionRestraint(uint ind, const geom::Vec3& ref_position, Real k, 
                                             Real x_scale, Real y_scale, Real z_scale){
   if(ind >= num_particles_){
diff --git a/modules/mol/mm/src/topology.hh b/modules/mol/mm/src/topology.hh
index e578e42001b8c7e56a9eef1a0aa0571b097ac8fc..486accf1eb55c6ba1fe0db5fea040a445d6bb182 100644
--- a/modules/mol/mm/src/topology.hh
+++ b/modules/mol/mm/src/topology.hh
@@ -38,6 +38,7 @@
 #include <ost/mol/xcs_editor.hh>
 #include <ost/mol/bond_handle.hh>
 #include <ost/mol/residue_prop.hh>
+#include <ost/img/image_handle.hh>
 
 #include <time.h>
 
@@ -127,6 +128,12 @@ public:
 
   void AddPositionConstraint(uint index);
 
+  void SetDensity(const ost::img::ImageHandle& d, Real r, Real s = 1.0);
+
+  void DefineDensityBody(const std::vector<int>& indices);
+
+  int GetNumDensityBodies() const { return density_bodies_.size(); }
+
   void ResetPositionConstraints() { position_constraints_.clear(); }
 
   void ResetExclusions() { exclusions_.clear(); }
@@ -212,6 +219,12 @@ public:
 
   void GetFGMDHBondAcceptorParameters(uint index, uint& index_one, uint& index_two) const;
 
+  ost::img::ImageHandle GetDensity() { return density_; }
+
+  Real GetDensityResolution() { return density_resolution_; }
+
+  Real GetDensityScaling() { return density_scaling_; }
+
   void SetHarmonicBondParameters(uint index, const Real bond_length, const Real force_constant);
 
   void SetHarmonicAngleParameters(uint index, const Real angle, const Real force_constant);
@@ -272,6 +285,9 @@ public:
 
   const std::vector<Index<2> >& GetFGMDHBondAcceptors() const { return fgmd_hbond_acceptors_; }
 
+  const std::vector<std::vector<int> >& GetDensityBodies() const { return density_bodies_; }
+
+
   std::vector<Real> GetSigmas() const { return sigmas_; }
 
   std::vector<Real> GetEpsilons() const { return epsilons_; }
@@ -796,6 +812,12 @@ private:
   std::set<Index<2> > added_distance_constraints_;
   std::set<Index<2> > added_exclusions_;
 
+  //density map
+  ost::img::ImageHandle density_;
+  Real density_resolution_;
+  Real density_scaling_;
+  std::vector<std::vector<int> > density_bodies_;
+  std::vector<bool> in_density_body_;
 };