2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 #ifndef GMXAPI_CONTEXT_IMPL_H
36 #define GMXAPI_CONTEXT_IMPL_H
38 * \brief Declare gmxapi::ContextImpl
40 * \author M. Eric Irrgang <ericirrgang@gmail.com>
47 #include "gromacs/mdrun/legacymdrunoptions.h"
48 #include "gromacs/mdtypes/mdrunoptions.h"
49 #include "gromacs/utility/gmxmpi.h"
51 #include "gmxapi/context.h"
52 #include "gmxapi/session.h"
58 * \brief Provide RAII management of library MPI context.
60 * To acquire an MpiContextManager is to have assurance that any external MPI
61 * environment is ready to use. When the MpiContextManager is released or
62 * goes out of scope, the destructor finalizes the resources.
64 * It is plausible that one or more ranks may not participate in an API session,
65 * but we have not historically handled such use cases at this level.
66 * For GROMACS built with an MPI library, the root communicator in the MpiContextManager
67 * must be valid. For other builds (e.g. tMPI), the communicator member must be MPI_COMM_NULL.
69 * If the client provides a communicator, the client promises to maintain the validity
70 * of the communicator for the life of the MpiContextManager.
72 * Note that thread-MPI chooses the number of ranks and constructs its
73 * MPI communicator internally, so does not and is unlikely to ever
76 * \todo Log errors during set up or tear down.
77 * There is no resource for logging or reporting errors during initialization or when misused.
81 class MpiContextManager
85 * \brief Default constructor.
87 * Construct a valid instance with an appropriate default value for the
88 * base communicator. (Note that appropriate default value depends on whether
89 * the library was compiled with an external MPI library.)
96 * \brief Exclusive ownership of a scoped context means copying is impossible.
100 MpiContextManager(const MpiContextManager&) = delete;
101 MpiContextManager& operator=(const MpiContextManager&) = delete;
105 * \brief Transfer ownership of the managed GROMACS MPI context.
109 MpiContextManager(MpiContextManager&& source) noexcept = default;
110 MpiContextManager& operator=(MpiContextManager&& source) noexcept = default;
114 * \brief Get the communicator for this context.
116 * \return Communicator with an appropriate initialized state for the current library
119 * \throws gmxapi::UsageError if MpiContextManager is in an invalid state, such as after
122 [[nodiscard]] MPI_Comm communicator() const;
126 * \brief The resources provided by this manager.
128 * A valid MpiContextManager has a value for communicator_ that is appropriate
129 * for the library configuration.
131 std::unique_ptr<MPI_Comm> communicator_;
135 * \brief Context implementation.
137 * Execution contexts have a uniform interface specified by the API. Implementations for
138 * particular execution environments can specialize / derive from this base.
140 * \todo Separate interface and implementation.
142 * \warning Definition and semantics depend on configure-time details. For example,
143 * MPI-enabled libraries always hold a valid MPI communicator via MpiContextManager,
144 * whereas tMPI and non-MPI builds hold a meaningless MpiContextManager.
146 * \todo Provide functions or traits for introspection.
150 class ContextImpl final : public std::enable_shared_from_this<ContextImpl>
156 * \brief Factory function
158 * Since this class provides `shared_from_this`, we need to make sure
159 * that it never exists without a shared_ptr owning it.
161 * If we can confirm `shared_from_this` is no longer necessary, implementation may change.
162 * \todo: Use registration/deregistration of launched Sessions to log warnings on shutdown
163 * instead of letting Session keep ContextImpl alive.
165 * \return ownership of a new object
167 static std::shared_ptr<ContextImpl> create(MpiContextManager&& mpi);
170 * \brief Copy disallowed because Session state would become ambiguous.
172 * The API implementation needs to unambiguously determine
173 * which Sessions and Contexts are associated with each other.
176 ContextImpl(const ContextImpl&) = delete;
177 ContextImpl& operator=(const ContextImpl&) = delete;
181 * \brief Objects are not trivial to move.
183 * \todo Implement move semantics. Requires a moveable const MpiContextManager and
184 * LegacyMdrunOptions members.
188 ContextImpl(ContextImpl&&) = delete;
189 ContextImpl& operator=(ContextImpl&&) = delete;
193 * \brief Translate the workflow to the execution context and launch.
195 * \param work workflow graph
196 * \return ownership of a new session
198 * \todo This probably makes more sense as a free function, but we need to determine access policies.
200 * Session is returned with shared_ptr ownership so that Context
201 * can hold a weak_ptr and because Session Resources handles
202 * are still evolving.
203 * \todo Hide lifetime management and ownership from handle object.
204 * We can achieve the necessary aspects of this shared_ptr at a lower level of implementation.
205 * Note also that returned value policies can be implemented in higher level wrappers to ensure
206 * correct object lifetime scope. (See pybind, for instance.)
208 std::shared_ptr<Session> launch(const Workflow& work);
211 * \brief Retain the ability to find a launched session while it exists.
213 * The client owns the Session launched by a Context, but it is helpful
214 * for the Context to know if it has an active Session associated with it.
216 * \todo Use registration/deregistration protocol instead.
217 * Requires logging facility.
219 std::weak_ptr<Session> session_;
222 * \brief mdrun command line arguments.
224 * Store arguments provided by the client and pass them when launching
225 * a simulation runner. This allows client code to access the same
226 * options as are available to mdrun on the command line while the API
232 * \brief Legacy option-handling and set up for mdrun.
234 * This object should not exist, but is necessary now to introduce
235 * the API in a way that means CLI and API work similarly and do not
236 * duplicate definitions e.g. of command-line options.
238 gmx::LegacyMdrunOptions options_;
241 * \brief Scoped MPI management.
243 * Part of the ContextImpl invariant establishes a point where MPI initialization status is
246 * Note that the MpiContextManager invariant is dependent on configure-time options to the
247 * GROMACS library. Specifically, MpiContextManager::communicator() is guaranteed to be
248 * MPI_COMM_NULL if and only if the library was built without an external MPI library.
249 * This is confusing and we should split either this class or the
250 * MpiContextManager class. Another alternative would be to use a std::optional here and to
251 * allow the std::unique_ptr<MpiContextManager> provided to ContextImpl::create() to be null,
252 * but that means a slight change of documented behavior protocol. See #3688 and #3650 for
255 * To ensure the MpiContextManager is initialized only once, we use a const member that must
256 * be initialized at construction.
258 const MpiContextManager mpi_;
262 * \brief Basic constructor.
264 * Don't use this. Use create() to get a shared pointer right away.
265 * Otherwise, shared_from_this() is potentially dangerous.
267 explicit ContextImpl(MpiContextManager&& mpi) noexcept(std::is_nothrow_constructible_v<gmx::LegacyMdrunOptions>);
274 using commType = MPI_Comm;
275 MPI_Comm communicator{ MPI_COMM_NULL };
278 } // end namespace gmxapi
279 #endif // GMXAPI_CONTEXT_IMPL_H