Update instructions in containers.rst
[gromacs.git] / python_packaging / sample_restraint / src / cpp / sessionresources.h
blob44dbb8f6393e7152012231838a65f5b32c73b714
1 /*! \file
2 * \brief Provide some useful types and templates for GROMACS restraints.
4 * \todo This should be part of a template library installed with GROMACS.
6 * \author M. Eric Irrgang <ericirrgang@gmail.com>
7 */
9 #ifndef RESTRAINT_SESSIONRESOURCES_H
10 #define RESTRAINT_SESSIONRESOURCES_H
12 #include <functional>
13 #include <memory>
14 #include <mutex>
15 #include <vector>
17 #include "gmxapi/gromacsfwd.h"
18 #include "gmxapi/session.h"
19 #include "gmxapi/session/resources.h"
20 #include "gmxapi/md/mdmodule.h"
22 #include "gromacs/restraint/restraintpotential.h"
23 #include "gromacs/utility/real.h"
25 namespace plugin
28 // Stop-gap for cross-language data exchange pending SharedData implementation and inclusion of Eigen.
29 // Adapted from pybind docs.
30 template<class T>
31 class Matrix
33 public:
34 Matrix(size_t rows,
35 size_t cols) :
36 rows_(rows),
37 cols_(cols),
38 data_(rows_ * cols_,
43 explicit Matrix(std::vector<T>&& captured_data) :
44 rows_{1},
45 cols_{captured_data.size()},
46 data_{std::move(captured_data)}
50 std::vector<T>* vector()
51 { return &data_; }
53 T* data()
54 { return data_.data(); };
56 size_t rows() const
57 { return rows_; }
59 size_t cols() const
60 { return cols_; }
62 private:
63 size_t rows_;
64 size_t cols_;
65 std::vector<T> data_;
68 // Defer implicit instantiation to ensemblepotential.cpp
69 extern template
70 class Matrix<double>;
72 /*!
73 * \brief An active handle to ensemble resources provided by the Context.
75 * The semantics of holding this handle aren't determined yet, but it should be held as briefly as possible since it
76 * may involve locking global resources or preventing the simulation from advancing. Basically, though, it allows the
77 * Context implementation flexibility in how or where it provides services.
79 * Resources may be incoming input data or functors to trigger output data events.
81 * \internal
82 * It is not yet clear whether we want to assume that default behavior is for an operation to be called for each edge
83 * on every iterative graph execution, leaving less frequent calls as an optimization, or to fully support occasional
84 * data events issued by nodes during their execution.
86 * In this example, assume the plugin has specified that it provides a `.ostream.stop` port that provides asynchronous
87 * boolean events. We can provide a template member function that will handle either execution mode.
89 * ResourceHandle::ostream() will return access to a gmxapi::session::OutputStream object, which will provide
90 * set("stop", true), to give access to a function pointer from a member vector of function pointers.
92 * In the case that we are triggering asynchronous data events, the function will make the appropriate call. In the case
93 * that we have output at regular intervals, the function will update internal state for the next time the edge is
94 * evaluated.
96 * In an alternative implementation, we could maintain a data object that could be queried by subscribers, but a publish
97 * and subscribe model seems much more useful, optimizeable, and robust. We can issue the calls to the subscribers and
98 * then be done with it.
100 * If we need to optimize for reuse of memory locations, we can do one of two things: require that
101 * the subscribing object not return until it has done what it needed with the data (including deep copy) or use
102 * managed handles for the data, possibly with a custom allocator, that prevents rewriting while there are read handles
103 * still open. One way that came up in conversation with Mark to allow some optimization is to allow the recipient of
104 * the handle to make either an `open` that gets a potentially blocking read-lock or an `open` that requests ownership.
105 * If no other consumers of the data request ownership, the ownership can be transferred without a copy. Otherwise, a
106 * copy is made.
108 class ResourcesHandle
110 public:
112 * \brief Ensemble reduce.
114 * \param send Matrices to be summed across the ensemble using Context resources.
115 * \param receive destination of reduced data instead of updating internal Matrix.
117 void reduce(const Matrix<double>& send,
118 Matrix<double>* receive) const;
121 * \brief Issue a stop condition event.
123 * Can be called on any or all ranks. Sets a condition that will cause the current simulation to shut down
124 * after the current step.
126 void stop();
128 // to be abstracted and hidden...
129 const std::function<void(const Matrix<double>&,
130 Matrix<double>*)>* reduce_;
132 gmxapi::SessionResources* session_;
136 * \brief Reference to workflow-level resources managed by the Context.
138 * Provides a connection to the higher-level workflow management with which to access resources and operations. The
139 * reference provides no resources directly and we may find that it should not extend the life of a Session or Context.
140 * Resources are accessed through Handle objects returned by member functions.
142 * gmxapi version 0.1.0 will provide this functionality through SessionResources.
144 class Resources
146 public:
148 * \brief Create a new resources object.
150 * This constructor is called by the framework during Session launch to provide the plugin
151 * potential with external resources.
153 * \note If getHandle() is going to be used, setSession() must be called first.
155 * \param reduce ownership of a function object providing ensemble averaging of a 2D matrix.
157 explicit Resources(std::function<void(const Matrix<double>&,
158 Matrix<double>*)>&& reduce) :
159 reduce_(reduce),
160 session_(nullptr)
164 * \brief Grant the caller an active handle for the currently executing block of code.
166 * Objects should not keep resource handles open for longer than a single block of code.
167 * calculate() and callback() functions get a handle to the resources for the current time step
168 * by calling getHandle().
170 * \note setSession() must be called before this function can be used.
171 * This clumsy protocol requires other infrastructure before it can be
172 * cleaned up for gmxapi 0.1
174 * \return resource handle
176 * In this release, the only facility provided by the resources is a function object for
177 * the ensemble averaging function provided by the Context.
179 ResourcesHandle getHandle() const;
182 * \brief Acquires a pointer to a Session managing these resources.
184 * \param session non-owning pointer to Session resources.
186 void setSession(gmxapi::SessionResources* session);
188 private:
189 //! bound function object to provide ensemble reduce facility.
190 std::function<void(const Matrix<double>&,
191 Matrix<double>*)> reduce_;
193 // Raw pointer to the session in which these resources live.
194 gmxapi::SessionResources* session_;
198 * \brief Template for MDModules from restraints.
200 * Allows a GROMACS module to be produced easily from the provided class. Refer to
201 * src/pythonmodule/export_plugin.cpp for how this template is used.
203 * \tparam R a class implementing the gmx::IRestraintPotential interface.
205 * The template type parameter should define a ``input_param_type`` member type.
207 * \todo move this to a template header in gmxapi */
208 template<class R>
209 class RestraintModule : public gmxapi::MDModule // consider names
211 public:
212 using param_t = typename R::input_param_type;
215 * \brief Construct a named restraint module.
217 * Objects of this type are created during Session launch, so this code really doesn't belong
218 * here. The Director / Builder for the restraint uses a generic interface to pass standard
219 * parameters for pair restraints: a list of sites, a (custom) parameters structure, and
220 * resources provided by the Session.
222 * \param name
223 * \param sites
224 * \param params
225 * \param resources
227 RestraintModule(std::string name,
228 std::vector<int> sites,
229 const typename R::input_param_type& params,
230 std::shared_ptr<Resources> resources) :
231 sites_{std::move(sites)},
232 params_{params},
233 resources_{std::move(resources)},
234 name_{std::move(name)}
239 ~RestraintModule() override = default;
242 * \brief Implement gmxapi::MDModule interface to get module name.
244 * name is provided during the building stage.
245 * \return
247 // \todo make member function const
248 const char* name() const override
250 return name_.c_str();
254 * \brief Implement gmxapi::MDModule interface to create a restraint for libgromacs.
256 * \return (Possibly shared) Ownership of a restraint instance
258 * Creates the restraint instance if it does not already exist. Only creates one restraint
259 * instance in the lifetime of the RestraintModule.
261 * Note this interface is not stable but requires other GROMACS and gmxapi infrastructure
262 * to mature before it is clear whether we will be creating a new instance or sharing ownership
263 * of the object. A future version may use a std::unique_ptr.
265 std::shared_ptr<gmx::IRestraintPotential> getRestraint() override
267 std::lock_guard<std::mutex> lock(restraintInstantiation_);
268 if (!restraint_)
270 restraint_ = std::make_shared<R>(sites_,
271 params_,
272 resources_);
274 return restraint_;
277 private:
278 std::vector<int> sites_;
279 param_t params_;
281 // Need to figure out if this is copyable or who owns it.
282 std::shared_ptr<Resources> resources_;
284 const std::string name_;
285 std::shared_ptr<R> restraint_{nullptr};
286 std::mutex restraintInstantiation_;
290 * \brief Filehandle management helper class.
292 * Use the RAII pattern to make sure that a (newly) constructed object has an open filehandle and that
293 * a the filehandle for a destructed object is closed. Closing a file is not guaranteed to be error-free,
294 * so the programmer should explicitly call close() and check for errors (see the C library docs
295 * for fclose()).
297 * RAIIFile makes sure that fclose() is called exactly once, whether client code issues close()
298 * or not.
300 class RAIIFile
302 public:
305 * \brief Open a file in the chosen access mode.
307 * \param filename Name of file to be opened.
308 * \param mode access mode as described for the fopen C library call.
310 RAIIFile(const char* filename,
311 const char* mode) :
312 fh_{fopen(filename,
313 mode)}
317 * \brief Open a file for writing.
319 * \param filename Name of file to be opened.
321 * File is opened in mode "w", which truncates data if the file already exists.
322 * For other file access modes, use RAIIFile(const char* filename, const char* mode)
324 explicit RAIIFile(const char* filename) :
325 RAIIFile(filename,
326 "w")
330 * \brief Explicitly close the associated filehandle.
332 * It is good practice to explicitly close the file at a known point in the client code, though
333 * it is not strictly necessary. If the filehandle is still open when the RAIIFile object is
334 * destroyed, the fclose will be called then.
336 * Calling close() additional times on the same RAIIFile object is fine and has no effect in
337 * single-threaded code. However, the destructor and close() routines are not thread-safe, so
338 * the client code should make sure that close() is not called at the same time by multiple threads.
339 * Standard reference-counting constructs, like std::shared_ptr, can be used to make sure the
340 * object destructor is called exactly once if it needs to be shared.
342 * Refer to documentation on fclose() on checking for and interpreting `errno`.
344 void close()
346 if (fh_ != nullptr)
348 fclose(fh_);
350 fh_ = nullptr;
354 * \brief RAII destructor.
356 * Make sure the filehandle gets closed exactly once.
358 ~RAIIFile()
360 if (fh_ != nullptr)
362 fclose(fh_);
366 RAIIFile(const RAIIFile&) = delete;
368 RAIIFile& operator=(const RAIIFile&) = delete;
370 RAIIFile(RAIIFile&&) = default;
372 RAIIFile& operator=(RAIIFile&&) = default;
375 * \brief Get the managed filehandle.
377 * \return raw pointer to the underlying filehandle.
379 FILE* fh() const noexcept
381 return fh_;
384 private:
385 /// file handle
386 FILE* fh_{nullptr};
389 } // end namespace plugin
391 #endif //RESTRAINT_SESSIONRESOURCES_H