dcebdc5ba928b9f6e03b21461186de7e8c67518c
[alexxy/gromacs.git] / src / gromacs / modularsimulator / checkpointhelper.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief Declares the checkpoint helper for the modular simulator
37  *
38  * \author Pascal Merz <pascal.merz@me.com>
39  * \ingroup module_modularsimulator
40  *
41  * This header is only used within the modular simulator module
42  */
43
44 #ifndef GMX_MODULARSIMULATOR_CHECKPOINTHELPER_H
45 #define GMX_MODULARSIMULATOR_CHECKPOINTHELPER_H
46
47 #include <map>
48 #include <vector>
49
50 #include "gromacs/mdlib/checkpointhandler.h"
51 #include "gromacs/mdrunutility/handlerestart.h"
52
53 #include "modularsimulatorinterfaces.h"
54
55 struct gmx_walltime_accounting;
56 struct ObservablesHistory;
57
58 namespace gmx
59 {
60 class KeyValueTreeObject;
61 class MDLogger;
62 class TrajectoryElement;
63
64 /*! \internal
65  * \ingroup module_modularsimulator
66  * \brief Checkpoint helper
67  *
68  * The `CheckpointHelper` is responsible to write checkpoints. In the
69  * longer term, it will also be responsible to read checkpoints, but this
70  * is not yet implemented.
71  *
72  * Writing checkpoints is done just before neighbor-searching (NS) steps,
73  * or after the last step. Checkpointing occurs periodically (by default,
74  * every 15 minutes), and needs two NS steps to take effect - on the first
75  * NS step, the checkpoint helper on master rank signals to all other ranks
76  * that checkpointing is about to occur. At the next NS step, the checkpoint
77  * is written. On the last step, checkpointing happens immediately after the
78  * step (no signalling). To be able to react to last step being signalled,
79  * the CheckpointHelper does also implement the `ISimulatorElement` interface,
80  * but does only register a function if the last step has been called. It
81  * should be placed on top of the simulator loop.
82  *
83  * Checkpointing happens at the end of a simulation step, which gives a
84  * straightforward re-entry point at the top of the simulator loop.
85  *
86  * Checkpoint writing is done by passing sub-objects of a
87  * WriteCheckpointDataHolder object to the clients. Checkpoint reading is
88  * done by passing sub-objects of a ReadCheckpointDataHolder object (passed
89  * in from runner level) do the clients.
90  *
91  * \see ReadCheckpointDataHolder
92  * \see WriteCheckpointDataHolder
93  * \see CheckpointData
94  */
95 class CheckpointHelper final : public ILastStepSignallerClient, public ISimulatorElement
96 {
97 public:
98     //! Constructor
99     CheckpointHelper(std::vector<std::tuple<std::string, ICheckpointHelperClient*>>&& clients,
100                      std::unique_ptr<CheckpointHandler> checkpointHandler,
101                      int                                initStep,
102                      TrajectoryElement*                 trajectoryElement,
103                      FILE*                              fplog,
104                      t_commrec*                         cr,
105                      ObservablesHistory*                observablesHistory,
106                      gmx_walltime_accounting*           walltime_accounting,
107                      t_state*                           state_global,
108                      bool                               writeFinalCheckpoint);
109
110     /*! \brief Run checkpointing
111      *
112      * Sets signal and / or performs checkpointing at neighbor searching steps
113      *
114      * \param step  The step number
115      * \param time  The time
116      */
117     void run(Step step, Time time);
118
119     /*! \brief Register run function for step / time
120      *
121      * Performs checkpointing at the last step. This is part of the element call
122      * list, as the checkpoint helper need to be able to react to the last step
123      * being signalled.
124      *
125      * \param step                 The step number
126      * \param time                 The time
127      * \param registerRunFunction  Function allowing to register a run function
128      */
129     void scheduleTask(Step step, Time time, const RegisterRunFunction& registerRunFunction) override;
130
131     //! No element setup needed
132     void elementSetup() override {}
133     //! No element teardown needed
134     void elementTeardown() override {}
135
136 private:
137     //! List of checkpoint clients
138     std::vector<std::tuple<std::string, ICheckpointHelperClient*>> clients_;
139
140     //! The checkpoint handler
141     std::unique_ptr<CheckpointHandler> checkpointHandler_;
142
143     //! The first step of the simulation
144     const Step initStep_;
145     //! The last step of the simulation
146     Step lastStep_;
147     //! Whether a checkpoint is written on the last step
148     const bool writeFinalCheckpoint_;
149
150     //! ILastStepSignallerClient implementation
151     std::optional<SignallerCallback> registerLastStepCallback() override;
152
153     //! The actual checkpoint writing function
154     void writeCheckpoint(Step step, Time time);
155
156     //! Pointer to the trajectory element - to use file pointer
157     TrajectoryElement* trajectoryElement_;
158
159     // Access to ISimulator data
160     //! Handles logging.
161     FILE* fplog_;
162     //! Handles communication.
163     t_commrec* cr_;
164     //! History of simulation observables.
165     ObservablesHistory* observablesHistory_;
166     //! Manages wall time accounting.
167     gmx_walltime_accounting* walltime_accounting_;
168     //! Full simulation state (only non-nullptr on master rank).
169     t_state* state_global_;
170 };
171
172 /*! \internal
173  * \ingroup module_modularsimulator
174  * \brief Builder for the checkpoint helper
175  */
176 class CheckpointHelperBuilder
177 {
178 public:
179     //! Constructor
180     CheckpointHelperBuilder(std::unique_ptr<ReadCheckpointDataHolder> checkpointDataHolder,
181                             StartingBehavior                          startingBehavior,
182                             t_commrec*                                cr);
183
184     //! Register checkpointing client
185     void registerClient(ICheckpointHelperClient* client);
186
187     //! Set CheckpointHandler
188     void setCheckpointHandler(std::unique_ptr<CheckpointHandler> checkpointHandler);
189
190     //! Return CheckpointHelper
191     template<typename... Args>
192     std::unique_ptr<CheckpointHelper> build(Args&&... args);
193
194 private:
195     //! Map of checkpoint clients
196     std::map<std::string, ICheckpointHelperClient*> clientsMap_;
197     //! Whether we are resetting from checkpoint
198     const bool resetFromCheckpoint_;
199     //! The input checkpoint data
200     std::unique_ptr<ReadCheckpointDataHolder> checkpointDataHolder_;
201     //! The checkpoint handler
202     std::unique_ptr<CheckpointHandler> checkpointHandler_;
203     //! Handles communication.
204     t_commrec* cr_;
205     //! Whether the builder accepts registrations.
206     ModularSimulatorBuilderState state_;
207 };
208
209 template<typename... Args>
210 std::unique_ptr<CheckpointHelper> CheckpointHelperBuilder::build(Args&&... args)
211 {
212     state_ = ModularSimulatorBuilderState::NotAcceptingClientRegistrations;
213     // Make sure that we don't have unused entries in checkpoint
214     if (resetFromCheckpoint_)
215     {
216         for (const auto& key : checkpointDataHolder_->keys())
217         {
218             if (clientsMap_.count(key) == 0)
219             {
220                 // We have an entry in checkpointDataHolder_ which has no matching client
221                 throw CheckpointError("Checkpoint entry " + key + " was not read. This "
222                                       "likely means that you are not using the same algorithm "
223                                       "that was used to create the checkpoint file.");
224             }
225         }
226     }
227
228     std::vector<std::tuple<std::string, ICheckpointHelperClient*>>&& clients = { clientsMap_.begin(),
229                                                                                  clientsMap_.end() };
230     return std::make_unique<CheckpointHelper>(std::move(clients), std::move(checkpointHandler_),
231                                               std::forward<Args>(args)...);
232 }
233
234 } // namespace gmx
235
236 #endif // GMX_MODULARSIMULATOR_CHECKPOINTHELPER_H