Python bindings for mdrun.
authorM. Eric Irrgang <ericirrgang@gmail.com>
Thu, 23 May 2019 21:44:00 +0000 (16:44 -0500)
committerMark Abraham <mark.j.abraham@gmail.com>
Fri, 5 Jul 2019 06:52:03 +0000 (08:52 +0200)
This change makes a near-exact copy of the mdrun Python
bindings from gmxapi 0.0.7.
Reference https://github.com/kassonlab/gmxapi/releases/tag/v0.0.7.3

This establishes a base from which to transition Python bindings
development from GitHub to the GROMACS repository, so Python wrappers,
interface updates, and other changes are deferred to separate commits.

The provided interface largely opaque except for arguments passed the
same way as mdrun command line flags.

GROMACS must be built with GMXAPI=ON.

Fixes #2912

Change-Id: I2f51ae8f2369334d06a7ceaa8a4abf3ed9fc444a

13 files changed:
python_packaging/README.md
python_packaging/src/.gitignore [new file with mode: 0644]
python_packaging/src/CMakeLists.txt
python_packaging/src/gmxapi/__init__.py
python_packaging/src/gmxapi/export_context.cpp [new file with mode: 0644]
python_packaging/src/gmxapi/export_system.cpp [new file with mode: 0644]
python_packaging/src/gmxapi/module.cpp
python_packaging/src/gmxapi/module.h [new file with mode: 0644]
python_packaging/src/gmxapi/pycontext.cpp [new file with mode: 0644]
python_packaging/src/gmxapi/pycontext.h [new file with mode: 0644]
python_packaging/src/gmxapi/pysystem.cpp [new file with mode: 0644]
python_packaging/src/gmxapi/pysystem.h [new file with mode: 0644]
python_packaging/src/test/test_mdrun.py [new file with mode: 0644]

index e534214b8edae795ebb5a5e84b7206cb95f69445..d22f8fed9f97e0b6aaa6e884be037d2b45ad3c8b 100644 (file)
@@ -132,3 +132,10 @@ Note: scikit-build can use CMake Toolchains to properly handle `pip` builds.
 
 The `pip install` options `--no-index` and `--find-links` allow for an offline stash of package archives so that
 satisfying dependencies for a new virtualenv does not require network access or lengthy build times.
+
+# Dependencies
+
+## OS X
+Some dependencies (notably, a Python installation itself) may require some fiddling
+with the XCode SDK.
+https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes#3035624
\ No newline at end of file
diff --git a/python_packaging/src/.gitignore b/python_packaging/src/.gitignore
new file mode 100644 (file)
index 0000000..dc10183
--- /dev/null
@@ -0,0 +1,2 @@
+_skbuild
+pip-wheel-metadata
index 28660bcaadf80177ac33399ba333668e6940666a..03d2e8350d36a786c1db6d7b5b4ddb199c2ccaaf 100644 (file)
@@ -85,6 +85,10 @@ add_subdirectory(external/pybind)
 
 set(GMXAPI_PYTHON_EXTENSION_SOURCES
     gmxapi/module.cpp
+    gmxapi/export_context.cpp
+    gmxapi/export_system.cpp
+    gmxapi/pycontext.cpp
+    gmxapi/pysystem.cpp
     )
 
 pybind11_add_module(_gmxapi
index 9aef072c43a51ade0899812faf2b199c0626f08a..a872f802ecfb8fd5d67b26eae94f1b177d82e5d2 100644 (file)
 
 """gmxapi Python package for GROMACS."""
 
-__all__ = ['commandline_operation', 'logger', 'operation']
+__all__ = ['commandline_operation', 'exceptions', 'logger', 'operation']
 
+import os
+
+from gmxapi import exceptions
 from gmxapi import operation
 from gmxapi._logging import logger
 from gmxapi.commandline import commandline_operation
diff --git a/python_packaging/src/gmxapi/export_context.cpp b/python_packaging/src/gmxapi/export_context.cpp
new file mode 100644 (file)
index 0000000..e2e1059
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief Bindings for Context class.
+ *
+ *
+ * \author M. Eric Irrgang <ericirrgang@gmail.com>
+ *
+ * \ingroup module_python
+ */
+#include "module.h"
+
+#include "gmxapi/context.h"
+#include "gmxapi/exceptions.h"
+#include "pycontext.h"
+
+
+namespace gmxpy
+{
+
+namespace detail
+{
+
+namespace py = pybind11;
+
+
+/*! \internal
+ * \brief Update a parameter structure for a simulation execution context.
+ *
+ * \param mdargs [OUT] Container for parameters made available to the MD library context.
+ * \param params Python dictionary mapping parameter names to argument values.
+ *
+ * Note that the current library infrastructure does not provide a way for the
+ * simulation machinery to express human-readable parameter names with rich
+ * descriptions, so a few of the most necessary mdrun command line parameters
+ * are hard coded here. Ref. https://redmine.gromacs.org/issues/2877
+ *
+ * For reference and default values, see
+ * http://manual.gromacs.org/current/onlinehelp/gmx-mdrun.html#options
+ */
+static void setMDArgs(std::vector<std::string>* mdargs,
+                      py::dict                  params)
+{
+    mdargs->clear();
+    if (params.contains("grid"))
+    {
+        if (py::len(params["grid"]) == 0)
+        {
+            throw gmxapi::UsageError("Grid argument must describe domain decomposition grid.");
+        }
+        std::vector<std::string> vals;
+        for (auto && val : params["grid"])
+        {
+            vals.emplace_back(py::cast<std::string>(py::str(val)));
+        }
+        mdargs->emplace_back("-dd");
+        for (auto && val : vals)
+        {
+            mdargs->emplace_back(val);
+        }
+    }
+    if (params.contains("pme_ranks"))
+    {
+        auto val = py::cast<std::string>(py::str(params["pme_ranks"]));
+        mdargs->emplace_back("-npme");
+        mdargs->emplace_back(val);
+    }
+    if (params.contains("threads"))
+    {
+        auto val = py::cast<std::string>(py::str(params["threads"]));
+        mdargs->emplace_back("-nt");
+        mdargs->emplace_back(val);
+    }
+    if (params.contains("tmpi"))
+    {
+        auto val = py::cast<std::string>(py::str(params["tmpi"]));
+        mdargs->emplace_back("-ntmpi");
+        mdargs->emplace_back(val);
+    }
+    if (params.contains("threads_per_rank"))
+    {
+        auto val = py::cast<std::string>(py::str(params["threads_per_rank"]));
+        mdargs->emplace_back("-ntomp");
+        mdargs->emplace_back(val);
+    }
+    if (params.contains("pme_threads_per_rank"))
+    {
+        auto val = py::cast<std::string>(py::str(params["pme_threads_per_rank"]));
+        mdargs->emplace_back("-ntomp_pme");
+        mdargs->emplace_back(val);
+    }
+    if (params.contains("steps"))
+    {
+        auto val = py::cast<std::string>(py::str(params["steps"]));
+        mdargs->emplace_back("-nsteps");
+        mdargs->emplace_back(val);
+    }
+    if (params.contains("max_hours"))
+    {
+        auto val = py::cast<std::string>(py::str(params["max_hours"]));
+        mdargs->emplace_back("-maxh");
+        mdargs->emplace_back(val);
+    }
+    if (params.contains("append_output"))
+    {
+        try
+        {
+            if (!params["append_output"].cast<bool>())
+            {
+                mdargs->emplace_back("-noappend");
+            }
+        }
+        catch (const py::cast_error &e)
+        {
+            // Couldn't cast to bool for some reason.
+            // Convert to gmxapi exception (not implemented)
+            // ref. https://github.com/kassonlab/gmxapi/issues/125
+            throw;
+        }
+    }
+}
+
+void export_context(py::module &m)
+{
+    // Add argument type before it is used for more sensible automatic bindings behavior.
+    py::class_ < MDArgs, std::unique_ptr < MDArgs>> mdargs(m, "MDArgs");
+    mdargs.def(py::init(), "Create an empty MDArgs object.");
+    mdargs.def("set",
+               [](MDArgs* self, py::dict params){ setMDArgs(self, params); },
+               "Assign parameters in MDArgs from Python dict.");
+
+    // Export execution context class
+    py::class_ < PyContext, std::shared_ptr < PyContext>> context(m, "Context");
+    context.def(py::init(), "Create a default execution context.");
+    context.def("setMDArgs", &PyContext::setMDArgs, "Set MD runtime parameters.");
+
+    context.def("add_mdmodule", &PyContext::addMDModule,
+                "Add an MD plugin for the simulation.");
+}
+
+} // end namespace gmxpy::detail
+
+} // end namespace gmxpy
diff --git a/python_packaging/src/gmxapi/export_system.cpp b/python_packaging/src/gmxapi/export_system.cpp
new file mode 100644 (file)
index 0000000..752e6d1
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief Bindings for System and session launch.
+ *
+ * \ingroup module_python
+ * \author M. Eric Irrgang <ericirrgang@gmail.com>
+ */
+
+#include "module.h"
+
+#include <iostream>
+
+#include "gmxapi/md.h"
+#include "gmxapi/session.h"
+#include "gmxapi/status.h"
+#include "gmxapi/system.h"
+
+#include "pycontext.h"
+#include "pysystem.h"
+
+// Note that PyCapsule symbols from Python.h should be imported by way of the pybind headers, so let's not
+// muddy the waters by explicitly including Python.h here unless we want to get more particular about the
+// CMake configuration.
+
+namespace gmxpy
+{
+
+namespace detail
+{
+
+namespace py = pybind11;
+
+
+void export_system(py::module &m)
+{
+    using ::gmxapi::System;
+
+    // The Session is a resource shared by active API operations.
+    // We can't completely surrender ownership to Python because other API objects may refer to it.
+    // We could use our own holder class instead of shared_ptr, but developers would
+    // have to keep in mind that Python may make new references in different scopes
+    // and threads, and pass references into other C++ code. Using shared_ptr
+    // self-documents intent. Future implementations could refactor Session as a
+    // dynamically accessed facet of the Context, which the API client would be
+    // required to maintain and to pass to the API.
+    py::class_ < ::gmxapi::Session, std::shared_ptr < ::gmxapi::Session>> session(m, "MDSession");
+    session.def("run", &::gmxapi::Session::run, "Run the simulation workflow");
+    session.def("close", &::gmxapi::Session::close, "Shut down the execution environment and close the session.");
+
+    // Export system container class
+    py::class_<System, std::shared_ptr<System> > system(m, "MDSystem");
+    system.def("launch",
+               [](System* system, std::shared_ptr<PyContext> context)
+               {
+                   auto newSession = system->launch(context->get());
+                   return newSession;
+               },
+               "Launch the configured workflow in the provided context.");
+
+    // Module-level function
+    m.def("from_tpr", &gmxpy::from_tpr, "Return a system container initialized from the given input record.");
+}
+
+} // end namespace gmxpy::detail
+
+} // end namespace gmxpy
index 5f7b7928324a0ae77acee4281b7c0370c89ed938..36075623a49f8ad5a0c68601f9973196372ff683 100644 (file)
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
+/*! \internal \file
+ * \brief Exports Python bindings for gmxapi._gmxapi module.
+ *
+ * \author M. Eric Irrgang <ericirrgang@gmail.com>
+ *
+ * \ingroup module_python
+ */
+
+#include "module.h"
+
+#include <memory>
+
+#include "gmxapi/status.h"
+#include "gmxapi/version.h"
+
 #include "pybind11/pybind11.h"
 
-PYBIND11_MODULE(_gmxapi, m) {
-}
+namespace py = pybind11;
+
+// Export Python module.
+
+/// used to set __doc__
+/// pybind11 uses const char* objects for docstrings. C++ raw literals can be used.
+const char* const docstring = R"delimeter(
+gmxapi core module
+==================
+
+gmxapi._gmxapi provides Python access to the GROMACS C++ API so that client code can be
+implemented in Python, C++, or a mixture. The classes provided are mirrored on the
+C++ side in the gmxapi namespace as best as possible.
+
+This documentation is generated from C++ extension code. Refer to C++ source
+code and developer documentation for more details.
+
+)delimeter";
+
+/*! \brief Export gmxapi._gmxapi Python module in shared object file.
+ *
+ * \ingroup module_python
+ */
+
+// Instantiate the Python module
+PYBIND11_MODULE(_gmxapi, m){
+    using namespace gmxpy::detail;
+    m.doc() = docstring;
+
+    // Export core bindings
+    m.def("has_feature",
+          &gmxapi::Version::hasFeature,
+          "Check the gmxapi library for a named feature.");
+
+    py::class_< ::gmxapi::Status > gmx_status(m, "Status", "Holds status for API operations.");
+
+    // Get bindings exported by the various components.
+    export_context(m);
+    export_system(m);
+
+} // end pybind11 module
diff --git a/python_packaging/src/gmxapi/module.h b/python_packaging/src/gmxapi/module.h
new file mode 100644 (file)
index 0000000..c5c8e40
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \defgroup module_python Python module for accessing Gromacs library
+ * The Python module ``gmxapi`` consists of a high-level interface implemented in
+ * pure Python and a low-level interface implemented as a C++ extension in the
+ * submodule, gmxapi._gmxapi.
+ */
+/*! \file
+ * \brief Declares symbols to be exported to gmxapi._gmxapi Python module.
+ *
+ * Declares namespace gmxpy, used internally in the C++ extension.
+ * \ingroup module_python
+ */
+#ifndef GMXPY_MODULE_H
+#define GMXPY_MODULE_H
+
+#include "pybind11/pybind11.h"
+
+
+/*! \brief API client code from which to export Python bindings
+ *
+ * gmxpy is not a public interface. It implements bindings for the public
+ * Python API in the C++ Python extension it produces, and it uses the public
+ * C++ Gromacs API, but is itself an API *client* and its C++ interfaces are not
+ * intended to be used in external code.
+ * \ingroup module_python
+ */
+namespace gmxpy
+{
+
+namespace detail
+{
+
+void export_context(pybind11::module &m);
+void export_system(pybind11::module &m);
+
+}      // end namespace gmxpy::detail
+
+}      // end namespace gmxpy
+
+#endif // GMXPY_MODULE_H
diff --git a/python_packaging/src/gmxapi/pycontext.cpp b/python_packaging/src/gmxapi/pycontext.cpp
new file mode 100644 (file)
index 0000000..db6133c
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief Wrapper code for gmxapi::Context.
+ *
+ * \ingroup module_python
+ * \author M. Eric Irrgang <ericirrgang@gmail.com>
+ */
+#include "pycontext.h"
+
+#include "gmxapi/gmxapi.h"
+#include "gmxapi/md.h"
+
+
+namespace py = pybind11;
+
+namespace gmxpy
+{
+
+void PyContext::setMDArgs(const MDArgs &mdArgs)
+{
+    assert(context_);
+    context_->setMDArgs(mdArgs);
+}
+
+std::shared_ptr<gmxapi::Session> PyContext::launch(const gmxapi::Workflow &work)
+{
+    assert(context_);
+    return context_->launch(work);
+}
+
+std::shared_ptr<gmxapi::MDWorkSpec> PyContext::getSpec() const
+{
+    assert(workNodes_);
+    return workNodes_;
+}
+
+std::shared_ptr<gmxapi::Context> PyContext::get() const
+{
+    assert(context_);
+    return context_;
+}
+
+PyContext::PyContext() :
+    context_ {std::make_shared<gmxapi::Context>()},
+workNodes_ {
+    std::make_shared<gmxapi::MDWorkSpec>()
+}
+{
+    assert(context_);
+    assert(workNodes_);
+}
+
+void PyContext::addMDModule(pybind11::object force_object)
+{
+    // If force_object has a bind method, give it a PyCapsule with a pointer
+    // to our C++ object.
+    if (py::hasattr(force_object, "bind"))
+    {
+        auto spec   = getSpec();
+        auto holder = new gmxapi::MDHolder(spec);
+        holder->name_ = "pygmx holder";
+        auto deleter = [](PyObject *o) {
+                if (PyCapsule_IsValid(o, gmxapi::MDHolder_Name))
+                {
+                    auto holder_ptr = (gmxapi::MDHolder *) PyCapsule_GetPointer(o, gmxapi::MDHolder_Name);
+                    delete holder_ptr;
+                    // \todo double-check whether there is something we should do to invalidate a PyCapsule.
+                }
+                ;
+            };
+        auto capsule = py::capsule(holder,
+                                   gmxapi::MDHolder_Name,
+                                   deleter);
+        py::object bind = force_object.attr("bind");
+        // py::capsule does not have bindings and does not implicitly convert to py::object
+        py::object obj = capsule;
+        bind(obj);
+    }
+    else
+    {
+        // Note: Exception behavior is likely to change.
+        // Ref: https://github.com/kassonlab/gmxapi/issues/125
+        throw py::value_error("Argument must provide a `bind` method.");
+    }
+}
+
+} // end namespace gmxpy
diff --git a/python_packaging/src/gmxapi/pycontext.h b/python_packaging/src/gmxapi/pycontext.h
new file mode 100644 (file)
index 0000000..54c7dc0
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief Declarations for Context wrappers.
+ *
+ * \ingroup module_python
+ * \author M. Eric Irrgang <ericirrgang@gmail.com>
+ */
+
+#ifndef GMXPY_PYCONTEXT_H
+#define GMXPY_PYCONTEXT_H
+
+#include "pybind11/pybind11.h"
+
+#include "gmxapi/context.h"
+#include "gmxapi/md.h"
+
+namespace gmxpy
+{
+
+using gmxapi::MDArgs;
+
+
+/*!
+ * \brief Wrapper for gmxapi::Context
+ *
+ * Proxies gmxapi::Context methods and includes additions not yet provided by
+ * by upstream library.
+ */
+class PyContext
+{
+    public:
+        PyContext();
+        void setMDArgs(const MDArgs &mdArgs);
+        std::shared_ptr<gmxapi::Session> launch(const gmxapi::Workflow &work);
+        std::shared_ptr<gmxapi::Context> get() const;
+
+        void addMDModule(pybind11::object forceProvider);
+
+        /*!
+         * \brief Borrow shared ownership of the System's container of associated modules.
+         *
+         * Used with gmxapi::MDHolder to add MD Modules to the simulation to be run.
+         *
+         * \return handle to be passed to gmxapi::MDHolder
+         *
+         */
+        std::shared_ptr<gmxapi::MDWorkSpec> getSpec() const;
+
+    private:
+        std::shared_ptr<gmxapi::Context>    context_;
+        std::shared_ptr<gmxapi::MDWorkSpec> workNodes_;
+};
+
+
+}      // end namespace gmxpy
+
+#endif //GMXPY_PYCONTEXT_H
diff --git a/python_packaging/src/gmxapi/pysystem.cpp b/python_packaging/src/gmxapi/pysystem.cpp
new file mode 100644 (file)
index 0000000..5dfb34f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief Implement System helper code.
+ *
+ * \ingroup module_python
+ * \author M. Eric Irrgang <ericirrgang@gmail.com>
+ */
+
+#include "pysystem.h"
+
+#include <memory>
+
+namespace gmxpy
+{
+
+std::shared_ptr<gmxapi::System> from_tpr(std::string filename)
+{
+    auto system = gmxapi::fromTprFile(filename);
+    return std::make_shared<gmxapi::System>(std::move(system));
+}
+
+} // end namespace gmxpy
diff --git a/python_packaging/src/gmxapi/pysystem.h b/python_packaging/src/gmxapi/pysystem.h
new file mode 100644 (file)
index 0000000..2ae84ec
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#ifndef GMXPY_SYSTEM_H
+#define GMXPY_SYSTEM_H
+
+/*! \file
+ * \brief Declare helpers for gmxapi::System.
+ *
+ * \ingroup module_python
+ * \author M. Eric Irrgang <ericirrgang@gmail.com>
+ */
+
+#include <memory>
+#include <string>
+
+#include "gmxapi/gmxapi.h"
+#include "gmxapi/system.h"
+
+namespace gmxpy
+{
+
+std::shared_ptr<gmxapi::System> from_tpr(std::string filename);
+
+}      // end namespace gmxpy
+
+#endif // header guard
diff --git a/python_packaging/src/test/test_mdrun.py b/python_packaging/src/test/test_mdrun.py
new file mode 100644 (file)
index 0000000..e36b7a1
--- /dev/null
@@ -0,0 +1,71 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2019, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+"""Test gromacs.mdrun operation.
+
+Factory produces deferred execution operation.
+
+TODO: Factory expects input for conformation, topology, simulation parameters, simulation state.
+
+TODO: Factory accepts additional keyword input to indicate binding
+ to the "potential" interface.
+"""
+
+import logging
+import os
+import pytest
+
+# Configure the `logging` module before and non-built-in packages start to use it.
+logging.getLogger().setLevel(logging.DEBUG)
+# create console handler
+ch = logging.StreamHandler()
+ch.setLevel(logging.DEBUG)
+# create formatter and add it to the handler
+formatter = logging.Formatter('%(asctime)s:%(name)s:%(levelname)s: %(message)s')
+ch.setFormatter(formatter)
+# add the handlers to the logger
+logging.getLogger().addHandler(ch)
+
+from gmxapi import _gmxapi
+
+from pytesthelpers import withmpi_only
+
+@pytest.mark.usefixtures('cleandir')
+def test_run_from_tpr(spc_water_box):
+    assert os.path.exists(spc_water_box)
+    filename = os.path.abspath(spc_water_box)
+    system = _gmxapi.from_tpr(filename)
+    context = _gmxapi.Context()
+    md = system.launch(context)
+    md.run()