# The include directory should be mostly empty so that we can use it internally as
# the public interface include directory during build and testing.
configure_file(include/gmxapiversion.h.in include/gmxapi/version.h)
-configure_file(include/multiprocessingresources.cmakein.h include/gmxapi/mpi/multiprocessingresources.h)
+configure_file(include/resourceassignment.cmakein.h include/gmxapi/mpi/resourceassignment.h)
target_include_directories(gmxapi PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
# Install "configured" files from the build tree.
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/gmxapi/version.h
DESTINATION include/gmxapi)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/gmxapi/mpi/multiprocessingresources.h
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/gmxapi/mpi/resourceassignment.h
DESTINATION include/gmxapi/mpi)
# This list file provides the Gromacs::gmxapi cmake target.
target_sources(gmxapi PRIVATE
- multiprocessingresources.cpp
+ resourceassignment.cpp
context.cpp
exceptions.cpp
gmxapi.cpp
#include "gromacs/utility/init.h"
#include "gromacs/utility/smalloc.h"
-#include "gmxapi/mpi/multiprocessingresources.h"
+#include "gmxapi/mpi/resourceassignment.h"
#include "gmxapi/exceptions.h"
#include "gmxapi/session.h"
#include "gmxapi/status.h"
*/
template<bool Value>
using hasLibraryMpi = std::bool_constant<Value>;
-using gmxThreadMpi = hasLibraryMpi<false>;
-using gmxLibMpi = hasLibraryMpi<true>;
-using MpiType = std::conditional_t<GMX_LIB_MPI, gmxLibMpi, gmxThreadMpi>;
+/* Note that a no-MPI build still uses the tMPI headers to define MPI_Comm for the
+ * gmx::SimulationContext definition. The dispatching in this file accounts for
+ * these two definitions of SimulationContext. gmxThreadMpi here does not imply
+ * that the library was necessarily compiled with thread-MPI enabled.
+ */
+using gmxThreadMpi = hasLibraryMpi<false>;
+using gmxLibMpi = hasLibraryMpi<true>;
+using MpiType = std::conditional_t<GMX_LIB_MPI, gmxLibMpi, gmxThreadMpi>;
using MpiContextInitializationError = BasicException<struct MpiContextInitialization>;
{
// Confirm our understanding of the MpiContextManager invariant.
GMX_ASSERT(mpi_.communicator() == MPI_COMM_NULL ? !GMX_LIB_MPI : GMX_LIB_MPI,
- "Precondition is an appropriate communicator for the library environment.");
+ "Precondition violated: inappropriate communicator for the library environment.");
// Make sure we didn't change the data members and overlook implementation details.
GMX_ASSERT(session_.expired(),
"This implementation assumes an expired weak_ptr at initialization.");
* Construct a valid instance with an appropriate default value for the
* base communicator. (Note that appropriate default value depends on whether
* the library was compiled with an external MPI library.)
+ *
+ * \throws BasicException if library cannot be initialized.
*/
MpiContextManager();
/*!
- * \brief Borrow a communicator and ensure that MPI is initialized, if applicable.
- *
- * \param communicator Optional communicator representing a client-managed MPI environment.
+ * \brief Allow the communicator to be specified.
*
+ * Supports use cases in which a client provides a non-default communicator.
+ * Ensures that library environment is properly initialized and finalized,
+ * whether or not an externally managed communicator has been provided.
*
+ * \param communicator Optional communicator representing a client-managed MPI environment.
*
* Note that the communicator must be MPI_COMM_NULL if and only if GROMACS was built without an
* external MPI library.
*
+ * \throws BasicException if library cannot be initialized.
+ *
* \todo (#3650?) Decide whether to exclude this from tMPI environments or find a sensible invariant.
*/
explicit MpiContextManager(MPI_Comm communicator);
explicit ContextImpl(MpiContextManager&& mpi) noexcept(std::is_nothrow_constructible_v<gmx::LegacyMdrunOptions>);
};
-
+/*!
+ * \brief Allow client code to hold a library communicator.
+ *
+ * MPI-enabled client code and thread-MPI GROMACS libraries cannot share headers
+ * in which MPI symbols (such as MPI_Comm) are defined. This class allows a
+ * client to refer to a library communicator opaquely. See gmxapi::offerComm().
+ *
+ * In the initial gmxapi::ResourceAssignment implementation, CommHandle objects
+ * are the only possible recipients of assigned resources. If future implementations
+ * allow richer resource assignment, CommHandle may be superseded by a more
+ * elaborate interface. Otherwise, all we need is this simple type proxy.
+ */
class CommHandle
{
public:
* \author "M. Eric Irrgang <ericirrgang@gmail.com"
*/
-#include "gmxapi/mpi/multiprocessingresources.h"
+#include "gmxapi/mpi/resourceassignment.h"
#include "config.h"
#include "gmxapi/context.h"
#include "gmxapi/exceptions.h"
-#include "gmxapi/mpi/multiprocessingresources.h"
+#include "gmxapi/mpi/resourceassignment.h"
/*! \file
* \brief Provide details of any MPI implementation used when building the library.
* Create an abstract wrapper for client-provided values with which to initialize
* simulation resources. When this wrapper is used, the client is responsible for providing
* a valid communicator that will remain valid for the life of the consumer.
+ *
+ * \throws UsageError if client has not provided a valid communicator.
*/
explicit ResourceAssignmentImpl(const CommT& communicator) : communicator_{ communicator }
{
if (communicator_ == MPI_COMM_NULL)
{
- throw UsageError("Null communicator cannot be lent.");
+ throw UsageError("Cannot assign a Null communicator.");
}
int flag = 0;
MPI_Initialized(&flag);
[[nodiscard]] int size() const override
{
- assert(communicator_ != MPI_COMM_NULL && "Resource invariant implies a valid communicator.");
+ assert(communicator_ != MPI_COMM_NULL && "Class invariant broken: invalid communicator.");
int size = 0;
MPI_Comm_size(communicator_, &size);
return size;
[[nodiscard]] int rank() const override
{
- assert(communicator_ != MPI_COMM_NULL && "Resource invariant implies a valid communicator.");
+ assert(communicator_ != MPI_COMM_NULL && "Class invariant broken: invalid communicator.");
// This default value will never be read, but the compiler can't tell
// that it is initialized by the MPI call.
int rank = -1;
void applyCommunicator(CommHandle* dst) const override
{
- assert(communicator_ != MPI_COMM_NULL && "Resource invariant implies a valid communicator.");
+ assert(communicator_ != MPI_COMM_NULL && "Class invariant broken: invalid communicator.");
offerComm(communicator_, dst);
}
/*!
* \brief Template header utility for connecting to MPI implementations.
*
+ * The client provides a communicator for work executed within the scope of the Context.
+ * Client remains responsible for freeing the communicator and finalizing the MPI environment.
+ *
* To use this helper function, the client software build environment must be
* configured for an MPI implementation compatible with the target GROMACS library.
*
*
* \see createContext(std::unique_ptr<ResourceAssignment> resources)
*
- * The client provides a communicator for work executed within the scope of the Context.
- * Client remains responsible for freeing the communicator and finalizing the MPI environment.
- *
* The communicator resource type is a template parameter because MPI_Comm is commonly a C
* typedef that varies between implementations, so we do not want to couple our
* API to it, but we cannot forward-declare it.
*
* See also https://gitlab.com/gromacs/gromacs/-/issues/3650
+ *
+ * \throws UsageError if the provided resource is not usable.
*/
template<typename CommT>
std::unique_ptr<ResourceAssignment> assignResource(CommT communicator)
* the research papers on the package. Check out http://www.gromacs.org.
*/
-#ifndef GMXAPI_MULTIPROCESSINGRESOURCES_H
-#define GMXAPI_MULTIPROCESSINGRESOURCES_H
+#ifndef GMXAPI_RESOURCEASSIGNMENT_H
+#define GMXAPI_RESOURCEASSIGNMENT_H
/*! \file
* \brief Provide build-specific overloads for client-MPI-dependent stuff.
} // end namespace gmxapi
-#endif // GMXAPI_MULTIPROCESSINGRESOURCES_H
+#endif // GMXAPI_RESOURCEASSIGNMENT_H