From c4e2fbeee65fa27e543b67ce3ab09c535dd29067 Mon Sep 17 00:00:00 2001 From: "M. Eric Irrgang" Date: Mon, 14 Sep 2020 15:37:40 +0000 Subject: [PATCH] Create and use SimulationInput module. Allow Mdrunner to accept a handle to SimulationInput from the client. This change adds an input method to the MdRunner builder to provide access to resources provided through the new SimulationInput module. Refs #3374 --- api/gmxapi/cpp/context.cpp | 14 +- src/gromacs/mdrun/CMakeLists.txt | 13 +- src/gromacs/mdrun/runner.cpp | 40 +++- src/gromacs/mdrun/runner.h | 21 ++ src/gromacs/mdrun/simulationinput.cpp | 54 +++-- src/gromacs/mdrun/simulationinput.h | 137 +++++++++---- src/gromacs/mdrun/simulationinput_impl.h | 78 -------- src/gromacs/mdrun/simulationinputhandle.cpp | 199 +++++++++++++++++++ src/gromacs/mdrun/simulationinputhandle.h | 198 ++++++++++++++++++ src/gromacs/mdrun/simulationinpututility.cpp | 78 -------- src/gromacs/mdrun/simulationinpututility.h | 142 ------------- src/programs/mdrun/mdrun.cpp | 3 +- 12 files changed, 598 insertions(+), 379 deletions(-) delete mode 100644 src/gromacs/mdrun/simulationinput_impl.h create mode 100644 src/gromacs/mdrun/simulationinputhandle.cpp create mode 100644 src/gromacs/mdrun/simulationinputhandle.h delete mode 100644 src/gromacs/mdrun/simulationinpututility.cpp delete mode 100644 src/gromacs/mdrun/simulationinpututility.h diff --git a/api/gmxapi/cpp/context.cpp b/api/gmxapi/cpp/context.cpp index b8f4c9a959..436ff90701 100644 --- a/api/gmxapi/cpp/context.cpp +++ b/api/gmxapi/cpp/context.cpp @@ -109,13 +109,18 @@ std::shared_ptr ContextImpl::launch(const Workflow& work) filename = mdNode->params(); } - /* As default behavior, automatically extend trajectories from the checkpoint file. + /* Mock up the argv interface used by option processing infrastructure. + * + * As default behavior, automatically extend trajectories from the checkpoint file. * In the future, our API for objects used to initialize a simulation needs to address the fact that currently a * microstate requires data from both the TPR and checkpoint file to be fully specified. Put another way, * current * GROMACS simulations can take a "configuration" as input that does not constitute a complete microstate in * terms of hidden degrees of freedom (integrator/thermostat/barostat/PRNG state), but we want a clear notion of * a microstate for gmxapi interfaces. + * + * TODO: Remove `-s` and `-cpi` arguments. + * Ref: https://gitlab.com/gromacs/gromacs/-/issues/3652 */ // Set input TPR name @@ -192,8 +197,13 @@ std::shared_ptr ContextImpl::launch(const Workflow& work) builder.addReplicaExchange(options_.replExParams); // Need to establish run-time values from various inputs to provide a resource handle to Mdrunner builder.addHardwareOptions(options_.hw_opt); + // \todo File names are parameters that should be managed modularly through further factoring. builder.addFilenames(options_.filenames); + // TODO: Remove `s` and `-cpi` from LegacyMdrunOptions before launch(). #3652 + auto simulationInput = makeSimulationInput(options_); + builder.addInput(simulationInput); + // Note: The gmx_output_env_t life time is not managed after the call to parse_common_args. // \todo Implement lifetime management for gmx_output_env_t. // \todo Output environment should be configured outside of Mdrunner and provided as a resource. @@ -205,6 +215,8 @@ std::shared_ptr ContextImpl::launch(const Workflow& work) std::move(simulationContext), std::move(logFileGuard)); // Clean up argv once builder is no longer in use + // TODO: Remove long-lived references to argv so this is no longer necessary. + // Ref https://gitlab.com/gromacs/gromacs/-/issues/2877 for (auto&& string : argv) { if (string != nullptr) diff --git a/src/gromacs/mdrun/CMakeLists.txt b/src/gromacs/mdrun/CMakeLists.txt index fac4c8ea9a..cb714aff3d 100644 --- a/src/gromacs/mdrun/CMakeLists.txt +++ b/src/gromacs/mdrun/CMakeLists.txt @@ -46,11 +46,22 @@ gmx_add_libgromacs_sources( shellfc.cpp simulationcontext.cpp simulationinput.cpp - simulationinpututility.cpp + simulationinputhandle.cpp simulatorbuilder.cpp tpi.cpp ) +# TODO: Find a home for this header and a scheme for installation. +# This header straddles the installed libraries and is a transitive interface +# from libgromacs to libgmxapi to libgmxapi clients. Near term efforts are +# planned to consolidate these libraries and refine the public interface. +# In the mean time, this is kept out of the gmxapi to avoid circular dependencies +# between the libraries. It can be moved to a separate interface-only target, +# but that is beyond the scope of issue #3379, which introduces the header. +# Ref #3152 and #3652 +install(FILES simulationinputhandle.h + DESTINATION include/gromacs/mdrun) + if (BUILD_TESTING) # TODO import this from src/programs/mdrun/tests # add_subdirectory(tests) diff --git a/src/gromacs/mdrun/runner.cpp b/src/gromacs/mdrun/runner.cpp index 3d3a1bcf38..9dcfd9cd74 100644 --- a/src/gromacs/mdrun/runner.cpp +++ b/src/gromacs/mdrun/runner.cpp @@ -105,6 +105,8 @@ #include "gromacs/mdlib/vsite.h" #include "gromacs/mdrun/mdmodules.h" #include "gromacs/mdrun/simulationcontext.h" +#include "gromacs/mdrun/simulationinput.h" +#include "gromacs/mdrun/simulationinputhandle.h" #include "gromacs/mdrunutility/handlerestart.h" #include "gromacs/mdrunutility/logging.h" #include "gromacs/mdrunutility/multisim.h" @@ -167,8 +169,6 @@ #include "isimulator.h" #include "membedholder.h" #include "replicaexchange.h" -#include "simulationinput.h" -#include "simulationinpututility.h" #include "simulatorbuilder.h" #if GMX_FAHCORE @@ -356,6 +356,7 @@ Mdrunner Mdrunner::cloneOnSpawnedThread() const newRunner.ms = ms; newRunner.startingBehavior = startingBehavior; newRunner.stopHandlerBuilder_ = std::make_unique(*stopHandlerBuilder_); + newRunner.inputHolder_ = inputHolder_; threadMpiMdrunnerAccessBarrier(); @@ -782,13 +783,6 @@ int Mdrunner::mdrunner() // Print citation requests after all software/hardware printing pleaseCiteGromacs(fplog); - // TODO: Use SimulationInputHolder member to access SimulationInput. Issue #3374. - const auto* const tprFilename = ftp2fn(efTPR, filenames.size(), filenames.data()); - const auto* const cpiFilename = opt2fn("-cpi", filenames.size(), filenames.data()); - // Note that, as of this change, there is no public API for simulationInput or its creation. - // TODO: (#3374) Public API for providing simulationInput from client. - auto simulationInput = detail::makeSimulationInput(tprFilename, cpiFilename); - // Note: legacy program logic relies on checking whether these pointers are assigned. // Objects may or may not be allocated later. std::unique_ptr inputrec; @@ -806,7 +800,7 @@ int Mdrunner::mdrunner() /* Read (nearly) all data required for the simulation * and keep the partly serialized tpr contents to send to other ranks later */ - applyGlobalSimulationState(*simulationInput.object_, partialDeserializedTpr.get(), + applyGlobalSimulationState(*inputHolder_.get(), partialDeserializedTpr.get(), globalState.get(), inputrec.get(), &mtop); } @@ -1098,7 +1092,7 @@ int Mdrunner::mdrunner() // Finish applying initial simulation state information from external sources on all ranks. // Reconcile checkpoint file data with Mdrunner state established up to this point. - applyLocalState(*simulationInput.object_, logFileHandle, cr, domdecOptions.numCells, + applyLocalState(*inputHolder_.get(), logFileHandle, cr, domdecOptions.numCells, inputrec.get(), globalState.get(), &observablesHistory, mdrunOptions.reproducible, mdModules_->notifier(), modularSimulatorCheckpointData.get(), useModularSimulator); @@ -1870,6 +1864,8 @@ public: void addDomdec(const DomdecOptions& options); + void addInput(SimulationInputHandle inputHolder); + void addVerletList(int nstlist); void addReplicaExchange(const ReplicaExchangeParameters& params); @@ -1954,6 +1950,8 @@ private: * \brief Builder for simulation stop signal handler. */ std::unique_ptr stopHandlerBuilder_ = nullptr; + + SimulationInputHandle inputHolder_; }; Mdrunner::BuilderImplementation::BuilderImplementation(std::unique_ptr mdModules, @@ -2016,6 +2014,15 @@ Mdrunner Mdrunner::BuilderImplementation::build() // nullptr is a valid value for the multisim handle newRunner.ms = multiSimulation_; + if (inputHolder_) + { + newRunner.inputHolder_ = std::move(inputHolder_); + } + else + { + GMX_THROW(gmx::APIError("MdrunnerBuilder::addInput() is required before build().")); + } + // \todo Clarify ownership and lifetime management for gmx_output_env_t // \todo Update sanity checking when output environment has clearly specified invariants. // Initialization and default values for oenv are not well specified in the current version. @@ -2131,6 +2138,11 @@ void Mdrunner::BuilderImplementation::addStopHandlerBuilder(std::unique_ptr mdModules, compat::not_null context) : impl_{ std::make_unique(std::move(mdModules), context) } @@ -2235,6 +2247,12 @@ MdrunnerBuilder& MdrunnerBuilder::addStopHandlerBuilder(std::unique_ptraddInput(std::move(input)); + return *this; +} + MdrunnerBuilder::MdrunnerBuilder(MdrunnerBuilder&&) noexcept = default; MdrunnerBuilder& MdrunnerBuilder::operator=(MdrunnerBuilder&&) noexcept = default; diff --git a/src/gromacs/mdrun/runner.h b/src/gromacs/mdrun/runner.h index 268465463b..21f8317c79 100644 --- a/src/gromacs/mdrun/runner.h +++ b/src/gromacs/mdrun/runner.h @@ -53,6 +53,7 @@ #include "gromacs/hardware/hw_info.h" #include "gromacs/math/vec.h" #include "gromacs/mdrun/mdmodules.h" +#include "gromacs/mdrun/simulationinputhandle.h" #include "gromacs/mdrunutility/handlerestart.h" #include "gromacs/mdtypes/mdrunoptions.h" #include "gromacs/utility/arrayref.h" @@ -297,6 +298,14 @@ private: std::unique_ptr stopHandlerBuilder_; //! The modules that comprise mdrun. std::unique_ptr mdModules_; + + /*! + * \brief Holds simulation input specification provided by client, if any. + * + * If present on any instance (rank) of a simulation runner, an identical + * (or compatible) SimulationInput must be held on all cooperating instances. + */ + SimulationInputHandle inputHolder_; }; /*! \libinternal @@ -585,6 +594,18 @@ public: */ MdrunnerBuilder& addStopHandlerBuilder(std::unique_ptr builder); + /*! + * \brief Acquire a handle to the SimulationInput. + * + * Required. SimulationInput will be taking responsibility for some of the + * input provided through other methods, such as addFilenames. + * + * See also issue https://gitlab.com/gromacs/gromacs/-/issues/3374 + * + * \param input Shared ownership of a SimulationInput. + */ + MdrunnerBuilder& addInput(SimulationInputHandle input); + ~MdrunnerBuilder(); private: diff --git a/src/gromacs/mdrun/simulationinput.cpp b/src/gromacs/mdrun/simulationinput.cpp index bdf2f681d3..a29c252103 100644 --- a/src/gromacs/mdrun/simulationinput.cpp +++ b/src/gromacs/mdrun/simulationinput.cpp @@ -37,42 +37,40 @@ #include "simulationinput.h" -#include - -#include "simulationinput_impl.h" +#include "gromacs/fileio/checkpoint.h" +#include "gromacs/fileio/tpxio.h" +#include "gromacs/mdtypes/inputrec.h" +#include "gromacs/mdtypes/observableshistory.h" +#include "gromacs/mdtypes/state.h" namespace gmx { -struct MdModulesNotifier; - -SimulationInput::SimulationInput(const char* tprFilename, const char* cpiFilename) : - tprFilename_(tprFilename), - cpiFilename_(cpiFilename) +void applyGlobalSimulationState(const SimulationInput& simulationInput, + PartialDeserializedTprFile* partialDeserializedTpr, + t_state* globalState, + t_inputrec* inputRecord, + gmx_mtop_t* molecularTopology) { + *partialDeserializedTpr = read_tpx_state(simulationInput.tprFilename_.c_str(), inputRecord, + globalState, molecularTopology); } -SimulationInputHolder::SimulationInputHolder() = default; - -SimulationInputHolder::~SimulationInputHolder() = default; - -namespace detail +void applyLocalState(const SimulationInput& simulationInput, + t_fileio* logfio, + const t_commrec* cr, + int* dd_nc, + t_inputrec* inputRecord, + t_state* state, + ObservablesHistory* observablesHistory, + bool reproducibilityRequested, + const MdModulesNotifier& mdModulesNotifier, + gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData, + const bool useModularSimulator) { - -SimulationInputHolder makeSimulationInput(const char* tprFilename, const char* cpiFilename) -{ - // Note: it seems clear that we will want a SimulationInput to be linked to - // a communications context (whether the SimulationContext or something higher level) - // so that it can encapsulate the data locality details. Otherwise, we have - // to choose whether to read the files everywhere or just to store the - // filenames until a communications context is known. - auto simulationInput = std::make_unique(tprFilename, cpiFilename); - - SimulationInputHolder holder; - holder.object_ = std::move(simulationInput); - return holder; + load_checkpoint(simulationInput.cpiFilename_.c_str(), logfio, cr, dd_nc, inputRecord, state, + observablesHistory, reproducibilityRequested, mdModulesNotifier, + modularSimulatorCheckpointData, useModularSimulator); } -} // end namespace detail - } // end namespace gmx diff --git a/src/gromacs/mdrun/simulationinput.h b/src/gromacs/mdrun/simulationinput.h index 81da8a8ab8..896018219c 100644 --- a/src/gromacs/mdrun/simulationinput.h +++ b/src/gromacs/mdrun/simulationinput.h @@ -32,75 +32,134 @@ * 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 Public interface for SimulationInput facilities. +/*! \libinternal \file + * \brief Utilities for interacting with SimulationInput. * * \author M. Eric Irrgang * \ingroup module_mdrun + * \inlibraryapi */ #ifndef GMX_MDRUN_SIMULATIONINPUT_H #define GMX_MDRUN_SIMULATIONINPUT_H #include +#include -namespace gmx -{ +#include "gromacs/mdrun/simulationinputhandle.h" +#include "gromacs/mdtypes/checkpointdata.h" +#include "gromacs/utility/mdmodulenotification.h" // Forward declarations for types from other modules that are opaque to the public API. -class LegacyMdrunOptions; +// TODO: Document the sources of these symbols or import a (self-documenting) fwd header. +struct gmx_mtop_t; +struct t_commrec; +struct t_fileio; +struct t_inputrec; +class t_state; +struct ObservablesHistory; +struct PartialDeserializedTprFile; -/*! +namespace gmx +{ +/* * \brief Prescription for molecular simulation. * - * Represents the complete and unique information needed to generate a simulation - * trajectory segment. SimulationInput objects are opaque to the public API. - * Clients can acquire SimulationInput objects through makeSimulationInput(). + * In the first implementation, this is a POD struct to allow removal of direct + * references to TPR and CPT files from Mdrunner. The interface for SimulationInput + * should be considered to be *completely unspecified* until resolution of + * https://gitlab.com/gromacs/gromacs/-/issues/3374 * - * See also https://gitlab.com/gromacs/gromacs/-/issues/3379 for design and development road map. - */ -class SimulationInput; - -/*! - * \brief Owning handle to a SimulationInput object. + * Clients should use the utility functions defined in simulationinpututility.h * - * SimulationInput has no public API. Acquire a SimulationInputHolder with makeSimulationInput(). - * See https://gitlab.com/gromacs/gromacs/-/issues/3374 + * Design note: It is probably sufficient for future versions to compose SimulationInput + * through a Builder rather than to subclass an Interface or base class. Outside of this + * translation unit, we should avoid coupling to the class definition until/unless we + * develop a much better understanding of simulation input portability. */ -class SimulationInputHolder +class SimulationInput { public: - SimulationInputHolder(); - ~SimulationInputHolder(); - - SimulationInputHolder(SimulationInputHolder&&) noexcept = default; - SimulationInputHolder& operator=(SimulationInputHolder&&) noexcept = default; + SimulationInput(const char* tprFilename, const char* cpiFilename); - std::unique_ptr object_; + std::string tprFilename_; + std::string cpiFilename_; }; -namespace detail -{ - -/*! \brief Get a SimulationInput. +/*! \brief Get the global simulation input. * - * \internal - * Design notes: SimulationInput creation will warrant a builder protocol, and - * this helper can evolve into a director to apply the contents of LegacyMdrunOptions, - * while such an operation is still relevant. + * Acquire global simulation data structures from the SimulationInput handle. + * Note that global data is returned in the calling thread. In parallel + * computing contexts, the client is responsible for calling only where needed. * * Example: - * // After preparing a LegacyMdrunOptions and calling handleRestart()... - * SimulationInputBuilder builder; - * auto simulationInputHandle = makeSimulationInput(options, &builder); + * if (SIMMASTER(cr)) + * { + * // Only the master rank has the global state + * globalState = globalSimulationState(simulationInput); * - * // In addition to MdrunnerBuilder::addFiles(), - * mdrunnerBuilder.addInput(simulationInputHandle.get()); + * // Read (nearly) all data required for the simulation + * applyGlobalInputRecord(simulationInput, inputrec); + * applyGlobalTopology(simulationInput, &mtop); + * } * + * \todo Factor the logic for global/local and master-rank-checks. + * The SimulationInput utilities should behave properly for the various distributed data scenarios. + * Consider supplying data directly to the consumers rather than exposing the + * implementation details of the legacy aggregate types. + * + * \{ */ -SimulationInputHolder makeSimulationInput(const char* tprFilename, const char* cpiFilename); +// TODO: Remove this monolithic detail as member data can be separately cached and managed. (#3374) +// Note that clients still need tpxio.h for PartialDeserializedTprFile. +void applyGlobalSimulationState(const SimulationInput& simulationInput, + PartialDeserializedTprFile* partialDeserializedTpr, + t_state* globalState, + t_inputrec* inputrec, + gmx_mtop_t* globalTopology); +// TODO: Implement the following, pending further discussion re #3374. +std::unique_ptr globalSimulationState(const SimulationInput&); +void applyGlobalInputRecord(const SimulationInput&, t_inputrec*); +void applyGlobalTopology(const SimulationInput&, gmx_mtop_t*); +//! \} -} // end namespace detail +/*! \brief Initialize local stateful simulation data. + * + * Establish an invariant for the simulator at a trajectory point. + * Call on all ranks (after domain decomposition and task assignments). + * + * After this call, the simulator has all of the information it will + * receive in order to advance a trajectory from the current step. + * Checkpoint information has been applied, if applicable, and stateful + * data has been (re)initialized. + * + * \warning Mdrunner instances do not clearly distinguish between global and local + * versions of t_state. + * + * \todo Factor the distributed data aspects of simulation input data into the + * SimulationInput implementation. + * + * \todo Consider refactoring to decouple the checkpoint facility from its consumers + * (state, observablesHistory, mdModulesNotifier, and parts of ir). + * + * \warning It is the caller’s responsibility to make sure that + * preconditions are satisfied for the parameter objects. + * + * \see globalSimulationState() + * \see applyGlobalInputRecord() + * \see applyGlobalTopology() + */ +void applyLocalState(const SimulationInput& simulationInput, + t_fileio* logfio, + const t_commrec* cr, + int* dd_nc, + t_inputrec* ir, + t_state* state, + ObservablesHistory* observablesHistory, + bool reproducibilityRequested, + const MdModulesNotifier& notifier, + gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData, + bool useModularSimulator); } // end namespace gmx diff --git a/src/gromacs/mdrun/simulationinput_impl.h b/src/gromacs/mdrun/simulationinput_impl.h deleted file mode 100644 index dfa5ab0f73..0000000000 --- a/src/gromacs/mdrun/simulationinput_impl.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the GROMACS molecular simulation package. - * - * Copyright (c) 2020, 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 GROMACS_SIMULATIONINPUT_IMPL_H -#define GROMACS_SIMULATIONINPUT_IMPL_H - -/*! \libinternal \file - * \brief Library interface for SimulationInput. - * - * \ingroup module_mdrun - */ - -#include - -namespace gmx -{ - -struct MdModulesNotifier; - -/* - * \brief Prescription for molecular simulation. - * - * In the first implementation, this is a POD struct to allow removal of direct - * references to TPR and CPT files from Mdrunner. The interface for SimulationInput - * should be considered to be *completely unspecified* until resolution of - * https://gitlab.com/gromacs/gromacs/-/issues/3374 - * - * Clients should use the utility functions defined in simulationinpututility.h - * - * Design note: It is probably sufficient for future versions to compose SimulationInput - * through a Builder rather than to subclass an Interface or base class. Outside of this - * translation unit, we should avoid coupling to the class definition until/unless we - * develop a much better understanding of simulation input portability. - */ -class SimulationInput -{ -public: - SimulationInput(const char* tprFilename, const char* cpiFilename); - - std::string tprFilename_; - std::string cpiFilename_; -}; - -} // end namespace gmx - -#endif // GROMACS_SIMULATIONINPUT_IMPL_H diff --git a/src/gromacs/mdrun/simulationinputhandle.cpp b/src/gromacs/mdrun/simulationinputhandle.cpp new file mode 100644 index 0000000000..ae5e2b81c6 --- /dev/null +++ b/src/gromacs/mdrun/simulationinputhandle.cpp @@ -0,0 +1,199 @@ +/* + * This file is part of the GROMACS molecular simulation package. + * + * Copyright (c) 2020, 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. + */ + +#include "gmxpre.h" + +#include "simulationinputhandle.h" + +#include + +#include "gromacs/mdrun/legacymdrunoptions.h" + +namespace gmx +{ + +/*! \cond + * SimulationInput needs much more discussion and refinement before it should be used directly. + * Use the interface defined in the headers and refer to #3652 for updates. + * + * Design note: It is probably sufficient for future versions to compose SimulationInput + * through a Builder rather than to subclass an Interface or base class. Outside of this + * translation unit, we should avoid coupling to the class definition until/unless we + * develop a much better understanding of simulation input portability. + * + */ +class SimulationInput +{ +public: + SimulationInput(const char* tprFilename, const char* cpiFilename) : + tprFilename_(tprFilename), + cpiFilename_(cpiFilename) + { + } + + std::string tprFilename_; + std::string cpiFilename_; +}; +/*! \endcond */ + +class detail::SimulationInputHandleImpl final +{ +public: + explicit SimulationInputHandleImpl(std::shared_ptr input) : + simulationInput_{ std::move(input) } + { + } + + SimulationInputHandleImpl(const SimulationInputHandleImpl&) = default; + SimulationInputHandleImpl& operator=(const SimulationInputHandleImpl&) = default; + SimulationInputHandleImpl(SimulationInputHandleImpl&&) noexcept = default; + SimulationInputHandleImpl& operator=(SimulationInputHandleImpl&&) noexcept = default; + + [[nodiscard]] SimulationInput* simulationInput() const { return simulationInput_.get(); } + + /*! \brief Boolean interpretation checks for presence of payload. + * + * \return true if handle has a SimulationInput, else false. + */ + operator bool() const { return bool(simulationInput_); } + +private: + // Note that we should not need to worry about managing the SimulationInput + // Deleter as long as we manage the SimulationInputHolderImpl Deleter and + // SimulationInputHolderImpl is the only way to own a SimulationInput. + // BUT these semantics may change, and we should try to be responsible about + // consistent Allocator implementation. + std::shared_ptr simulationInput_; +}; + +/*! \cond + * TODO: Improve doxygen source scoping. + * It seems surprising that doxygen should be looking at this source file, but we + * need to exclude the following definitions to avoid warnings. + * Possibly related to https://gitlab.com/gromacs/gromacs/-/issues/3402 + */ +detail::SimulationInputHandleImplDeleter::SimulationInputHandleImplDeleter() = default; + +detail::SimulationInputHandleImplDeleter::SimulationInputHandleImplDeleter( + const SimulationInputHandleImplDeleter&) noexcept = default; + +detail::SimulationInputHandleImplDeleter::SimulationInputHandleImplDeleter( + SimulationInputHandleImplDeleter&&) noexcept = default; + +detail::SimulationInputHandleImplDeleter& detail::SimulationInputHandleImplDeleter:: + operator=(const SimulationInputHandleImplDeleter&) noexcept = default; + +detail::SimulationInputHandleImplDeleter& detail::SimulationInputHandleImplDeleter:: + operator=(SimulationInputHandleImplDeleter&&) noexcept = default; + +void detail::SimulationInputHandleImplDeleter::operator()(SimulationInputHandleImpl* impl) const +{ + delete impl; +} + +SimulationInputHandle::SimulationInputHandle() = default; + +SimulationInputHandle::~SimulationInputHandle() = default; + +SimulationInputHandle::SimulationInputHandle(std::unique_ptr impl) : + impl_(impl.release()) +{ +} + +SimulationInputHandle::SimulationInputHandle(const SimulationInputHandle& source) +{ + // Dynamically allocate a new holder implementation object using the copy constructor. + // Note that make_unique does not provide for custom deleters, and there is no default + // overload to move construct/assign from basic unique_ptr to one with custom deleter, + // but more elaborate creation functions for SimulationInputHolderImpl seem like + // overkill at this point. Still, we use make_unique to confine constructor errors + // to the following exception-safe line. + auto impl = std::make_unique(*source.impl_); + // Move ownership of the heap object to the handle with a custom deleter. + impl_.reset(impl.release()); +} + +SimulationInputHandle& SimulationInputHandle::operator=(const SimulationInputHandle& source) +{ + if (this != &source) + { + // Dynamically allocate a new holder implementation object using the copy constructor. + // Note that make_unique does not provide for custom deleters, and there is no default + // overload to move construct/assign from basic unique_ptr to one with custom deleter, + // but more elaborate creation functions for SimulationInputHolderImpl seem like + // overkill at this point. Still, we use make_unique to confine constructor errors + // to the following exception-safe line. + auto impl = std::make_unique(*source.impl_); + // Move ownership of the heap object to the handle with a custom deleter. + impl_.reset(impl.release()); + } + return *this; +} +/*! \endcond */ + +SimulationInput* SimulationInputHandle::get() const noexcept +{ + if (!impl_) + { + return nullptr; + } + return impl_->simulationInput(); +} + +SimulationInputHandle::operator bool() const +{ + if (impl_) + { + return bool(*impl_); + } + return false; +} + +SimulationInputHandle makeSimulationInput(const LegacyMdrunOptions& options) +{ + // Note: it seems clear that we will want a SimulationInput to be linked to + // a communications context (whether the SimulationContext or something higher level) + // so that it can encapsulate the data locality details. Otherwise, we have + // to choose whether to read the files everywhere or just to store the + // filenames until a communications context is known. + const auto* const tprFilename = ftp2fn(efTPR, options.filenames.size(), options.filenames.data()); + const auto* const cpiFilename = opt2fn("-cpi", options.filenames.size(), options.filenames.data()); + auto simulationInput = std::make_unique(tprFilename, cpiFilename); + auto impl = std::make_unique(std::move(simulationInput)); + + return SimulationInputHandle(std::move(impl)); +} + +} // end namespace gmx diff --git a/src/gromacs/mdrun/simulationinputhandle.h b/src/gromacs/mdrun/simulationinputhandle.h new file mode 100644 index 0000000000..d5e5bde5dd --- /dev/null +++ b/src/gromacs/mdrun/simulationinputhandle.h @@ -0,0 +1,198 @@ +/* + * This file is part of the GROMACS molecular simulation package. + * + * Copyright (c) 2020, 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 Public interface for SimulationInput facilities. + * + * \author M. Eric Irrgang + * \ingroup module_mdrun + * \inpublicapi + */ + +#ifndef GMX_MDRUN_SIMULATIONINPUTHANDLE_H +#define GMX_MDRUN_SIMULATIONINPUTHANDLE_H + +#include + +namespace gmx +{ + +// Forward declarations for types from other modules that are opaque to the public API. +class LegacyMdrunOptions; + +/*! + * \brief Prescription for molecular simulation. + * + * Represent the complete and unique information needed to generate a simulation + * trajectory segment. SimulationInput objects are opaque to the public API. + * Ownership can be managed with SimulationInputHolder objects. Clients can + * acquire owning references to SimulationInput objects (as SimulationInputHolder) + * through makeSimulationInput() or from other SimulationInputHolders. + * + * A SimulationInput object represents an immutable source of data, and is safe + * to share. A SimulationInput object may have internal state to support + * performance optimizations when shared by multiple SimulationInputHolders. + * The SimulationInput is guaranteed to live at least as long as any associated + * SimulationInputHolders. The API does not specify whether it may persist + * longer internally or be reused for later equivalent requests. + * + * \see SimulationInputHandle + * \see makeSimulationInput() + * + * \internal + * SimulationInput has no public interface yet, but we need a forward declaration for the + * library symbol. Library interface provided through simulationinput.h + * See also https://gitlab.com/gromacs/gromacs/-/issues/3379 for design and development road map. + */ +class SimulationInput; + +/*! \cond internal + * Client software developers do not interact directly with the contents of gmx::detail, + * but some declarations and definitions are necessary in the public headers, such as + * forward declarations of implementation classes and definitions of custom deleters. + */ +namespace detail +{ +/*! + * \brief Private implementation class; + */ +class SimulationInputHandleImpl; + +/*! + * \brief Explicit deleter details for SimulationInputHolderImpl. + * + * SimulationInputHolderImpl objects are created by the GROMACS library, but + * are destroyed when the SimulationInputHolder goes out of scope in the client + * code, which may be linked to a different allocator. + * We want to make sure that objects are allocated and deallocated with the same + * allocator, so we avoid the default deleter in unique_ptrs and compile allocation + * and deallocation code in the same translation unit. + * + * Note that this does not solve potential ABI incompatibilities between the + * unique_ptr implementations themselves, but we need to consider ABI + * compatibility goals and challenges as well as supported use cases and + * ownership semantics. + */ +struct SimulationInputHandleImplDeleter +{ + /*! \cond */ + SimulationInputHandleImplDeleter(); + SimulationInputHandleImplDeleter(const SimulationInputHandleImplDeleter& deleter) noexcept; + SimulationInputHandleImplDeleter(SimulationInputHandleImplDeleter&& deleter) noexcept; + SimulationInputHandleImplDeleter& operator=(const SimulationInputHandleImplDeleter& deleter) noexcept; + SimulationInputHandleImplDeleter& operator=(SimulationInputHandleImplDeleter&& deleter) noexcept; + void operator()(SimulationInputHandleImpl* impl) const; + /*! \endcond */ +}; +} // end namespace detail +/*! \endcond internal */ + +/*! + * \brief Owning handle to a SimulationInput object. + * + * SimulationInput objects are logically immutable, so ownership may be shared + * by multiple SimulationInputHolders. + * + * Acquire a SimulationInputHolder with makeSimulationInput() and pass to (e.g.) + * gmx::MdrunnerBuilder::addInput() + * + * SimulationInput has no public API yet. + * \see https://gitlab.com/gromacs/gromacs/-/issues/3379 + */ +class SimulationInputHandle +{ +public: + /*! \cond internal */ + SimulationInputHandle(); + ~SimulationInputHandle(); + + SimulationInputHandle(const SimulationInputHandle& source); + SimulationInputHandle(SimulationInputHandle&&) noexcept = default; + + SimulationInputHandle& operator=(const SimulationInputHandle& rhs); + SimulationInputHandle& operator=(SimulationInputHandle&&) noexcept = default; + + /*! + * \brief Take ownership of private implementation object to produce a new public holder. + */ + explicit SimulationInputHandle(std::unique_ptr impl); + /*! \endcond */ + + /*! + * \brief Access opaque SimulationInput pointer. + * + * \return Borrowed access to the SimulationInput, if present. + */ + [[nodiscard]] SimulationInput* get() const noexcept; + + /*! + * \brief Boolean context returns true if an input is held, else false. + */ + operator bool() const; + +private: + std::unique_ptr impl_; +}; + +/*! \brief Direct the construction of a SimulationInput. + * + * \warning Creation methods for SimulationInput resources are under rapid development. + * Reference https://gitlab.com/gromacs/gromacs/-/issues/3652 + * + * \param options library-internal container holding partially processed user input. + * + * \ingroup module_mdrun + * + * \internal + * This isn't really a public API function until its arguments are obtainable + * through the public API. + * + * Design notes: SimulationInput creation will warrant a builder protocol, and + * this helper can evolve into a director to apply the contents of LegacyMdrunOptions, + * while such an operation is still relevant. + * + * Example: + * // After preparing a LegacyMdrunOptions and calling handleRestart()... + * SimulationInputBuilder builder; + * auto simulationInputHandle = makeSimulationInput(options, &builder); + * + * // In addition to MdrunnerBuilder::addFiles(), + * mdrunnerBuilder.addInput(simulationInputHandle.get()); + * + */ +SimulationInputHandle makeSimulationInput(const LegacyMdrunOptions& options); + +} // end namespace gmx + +#endif // GMX_MDRUN_SIMULATIONINPUTHANDLE_H diff --git a/src/gromacs/mdrun/simulationinpututility.cpp b/src/gromacs/mdrun/simulationinpututility.cpp deleted file mode 100644 index 74a050b2cd..0000000000 --- a/src/gromacs/mdrun/simulationinpututility.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the GROMACS molecular simulation package. - * - * Copyright (c) 2020, 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. - */ - -#include "gmxpre.h" - -#include "simulationinpututility.h" - -#include "gromacs/fileio/checkpoint.h" -#include "gromacs/fileio/tpxio.h" -#include "gromacs/mdtypes/inputrec.h" -#include "gromacs/mdtypes/observableshistory.h" -#include "gromacs/mdtypes/state.h" - -#include "simulationinput_impl.h" - -namespace gmx -{ - -void applyGlobalSimulationState(const SimulationInput& simulationInput, - PartialDeserializedTprFile* partialDeserializedTpr, - t_state* globalState, - t_inputrec* inputRecord, - gmx_mtop_t* molecularTopology) -{ - *partialDeserializedTpr = read_tpx_state(simulationInput.tprFilename_.c_str(), inputRecord, - globalState, molecularTopology); -} - -void applyLocalState(const SimulationInput& simulationInput, - t_fileio* logfio, - const t_commrec* cr, - int* dd_nc, - t_inputrec* inputRecord, - t_state* state, - ObservablesHistory* observablesHistory, - bool reproducibilityRequested, - const MdModulesNotifier& mdModulesNotifier, - gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData, - const bool useModularSimulator) -{ - load_checkpoint(simulationInput.cpiFilename_.c_str(), logfio, cr, dd_nc, inputRecord, state, - observablesHistory, reproducibilityRequested, mdModulesNotifier, - modularSimulatorCheckpointData, useModularSimulator); -} - -} // end namespace gmx diff --git a/src/gromacs/mdrun/simulationinpututility.h b/src/gromacs/mdrun/simulationinpututility.h deleted file mode 100644 index e65a9cf09e..0000000000 --- a/src/gromacs/mdrun/simulationinpututility.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of the GROMACS molecular simulation package. - * - * Copyright (c) 2020, 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. - */ -/*! \libinternal \file - * \brief Utilities for interacting with SimulationInput. - * - * \author M. Eric Irrgang - * \ingroup module_mdrun - */ - -#ifndef GMX_MDRUN_SIMULATIONINPUTUTILITY_H -#define GMX_MDRUN_SIMULATIONINPUTUTILITY_H - -#include - -#include "gromacs/mdtypes/checkpointdata.h" -#include "gromacs/utility/mdmodulenotification.h" - -#include "simulationinput.h" - -// Forward declarations for types from other modules that are opaque to the public API. -// TODO: Document the sources of these symbols or import a (self-documenting) fwd header. -struct gmx_mtop_t; -struct t_commrec; -struct t_fileio; -struct t_inputrec; -class t_state; -struct ObservablesHistory; -struct PartialDeserializedTprFile; - -namespace gmx -{ - -/*! \brief Get the global simulation input. - * - * Acquire global simulation data structures from the SimulationInput handle. - * Note that global data is returned in the calling thread. In parallel - * computing contexts, the client is responsible for calling only where needed. - * - * Example: - * if (SIMMASTER(cr)) - * { - * // Only the master rank has the global state - * globalState = globalSimulationState(simulationInput); - * - * // Read (nearly) all data required for the simulation - * applyGlobalInputRecord(simulationInput, inputrec); - * applyGlobalTopology(simulationInput, &mtop); - * } - * - * \todo Factor the logic for global/local and master-rank-checks. - * The SimulationInput utilities should behave properly for the various distributed data scenarios. - * Consider supplying data directly to the consumers rather than exposing the - * implementation details of the legacy aggregate types. - * - * \{ - */ -// TODO: Remove this monolithic detail as member data can be separately cached and managed. (#3374) -// Note that clients still need tpxio.h for PartialDeserializedTprFile. -void applyGlobalSimulationState(const SimulationInput& simulationInput, - PartialDeserializedTprFile* partialDeserializedTpr, - t_state* globalState, - t_inputrec* inputrec, - gmx_mtop_t* globalTopology); -// TODO: Implement the following, pending further discussion re #3374. -std::unique_ptr globalSimulationState(const SimulationInput&); -void applyGlobalInputRecord(const SimulationInput&, t_inputrec*); -void applyGlobalTopology(const SimulationInput&, gmx_mtop_t*); -//! \} - -/*! \brief Initialize local stateful simulation data. - * - * Establish an invariant for the simulator at a trajectory point. - * Call on all ranks (after domain decomposition and task assignments). - * - * After this call, the simulator has all of the information it will - * receive in order to advance a trajectory from the current step. - * Checkpoint information has been applied, if applicable, and stateful - * data has been (re)initialized. - * - * \warning Mdrunner instances do not clearly distinguish between global and local - * versions of t_state. - * - * \todo Factor the distributed data aspects of simulation input data into the - * SimulationInput implementation. - * - * \todo Consider refactoring to decouple the checkpoint facility from its consumers - * (state, observablesHistory, mdModulesNotifier, and parts of ir). - * - * \warning It is the caller’s responsibility to make sure that - * preconditions are satisfied for the parameter objects. - * - * \see globalSimulationState() - * \see applyGlobalInputRecord() - * \see applyGlobalTopology() - */ -void applyLocalState(const SimulationInput& simulationInput, - t_fileio* logfio, - const t_commrec* cr, - int* dd_nc, - t_inputrec* ir, - t_state* state, - ObservablesHistory* observablesHistory, - bool reproducibilityRequested, - const MdModulesNotifier& notifier, - gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData, - bool useModularSimulator); - -} // end namespace gmx - -#endif // GMX_MDRUN_SIMULATIONINPUTUTILITY_H diff --git a/src/programs/mdrun/mdrun.cpp b/src/programs/mdrun/mdrun.cpp index 5a4a46d7f4..f85fe26931 100644 --- a/src/programs/mdrun/mdrun.cpp +++ b/src/programs/mdrun/mdrun.cpp @@ -3,7 +3,7 @@ * * Copyright (c) 1991-2000, University of Groningen, The Netherlands. * Copyright (c) 2001-2004, The GROMACS development team. - * Copyright (c) 2011-2019, by the GROMACS development team, led by + * Copyright (c) 2011-2020, 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. @@ -259,6 +259,7 @@ int gmx_mdrun(int argc, char* argv[]) builder.addHardwareOptions(options.hw_opt); // \todo File names are parameters that should be managed modularly through further factoring. builder.addFilenames(options.filenames); + builder.addInput(makeSimulationInput(options)); // Note: The gmx_output_env_t life time is not managed after the call to parse_common_args. // \todo Implement lifetime management for gmx_output_env_t. // \todo Output environment should be configured outside of Mdrunner and provided as a resource. -- 2.22.0