Add class ListedForces
[alexxy/gromacs.git] / src / gromacs / modularsimulator / modularsimulator.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 /*! \libinternal \file
36  * \brief Provides the modular simulator.
37  *
38  * Defines the ModularSimulator class. Provides checkUseModularSimulator() utility function
39  * to determine whether the ModularSimulator should be used.
40  *
41  * \author Pascal Merz <pascal.merz@me.com>
42  * \ingroup module_modularsimulator
43  */
44 #ifndef GROMACS_MODULARSIMULATOR_MODULARSIMULATOR_H
45 #define GROMACS_MODULARSIMULATOR_MODULARSIMULATOR_H
46
47 #include <queue>
48
49 #include "gromacs/mdlib/md_support.h"
50 #include "gromacs/mdlib/resethandler.h"
51 #include "gromacs/mdrun/isimulator.h"
52
53 #include "checkpointhelper.h"
54 #include "domdechelper.h"
55 #include "modularsimulatorinterfaces.h"
56 #include "pmeloadbalancehelper.h"
57 #include "topologyholder.h"
58
59 struct t_fcdata;
60
61 namespace gmx
62 {
63 class DomDecHelper;
64 class EnergyElement;
65 class EnergySignaller;
66 class FreeEnergyPerturbationElement;
67 class LoggingSignaller;
68 class StatePropagatorData;
69 class NeighborSearchSignaller;
70 class PmeLoadBalanceHelper;
71 class TrajectoryElementBuilder;
72
73 /*! \libinternal
74  * \ingroup module_modularsimulator
75  * \brief The modular simulator
76  *
77  * Based on the input given, this simulator builds independent elements and
78  * signallers and stores them in a respective vector. The run function
79  * runs the simulation by, in turn, building a task list from the elements
80  * for a predefined number of steps, then running the task list, and repeating
81  * until the stop criterion is fulfilled.
82  */
83 class ModularSimulator final : public ISimulator
84 {
85 public:
86     //! Run the simulator
87     void run() override;
88
89     //! Check for disabled functionality
90     static bool isInputCompatible(bool                             exitOnFailure,
91                                   const t_inputrec*                inputrec,
92                                   bool                             doRerun,
93                                   const gmx_mtop_t&                globalTopology,
94                                   const gmx_multisim_t*            ms,
95                                   const ReplicaExchangeParameters& replExParams,
96                                   const t_fcdata*                  fcd,
97                                   bool                             doEssentialDynamics,
98                                   bool                             doMembed);
99
100     // Only builder can construct
101     friend class SimulatorBuilder;
102
103 private:
104     //! Constructor
105     template<typename... Args>
106     explicit ModularSimulator(Args&&... args);
107
108     /*! \brief The initialisation
109      *
110      * This builds all signallers and elements, and is responsible to put
111      * them in the correct order.
112      */
113     void constructElementsAndSignallers();
114
115     /*! \brief A function called once before the simulation run
116      *
117      * This function collects calls which need to be made once at the
118      * beginning of the simulation run. These are mainly printing information
119      * to the user and starting the wall time.
120      */
121     void simulatorSetup();
122
123     /*! \brief A function called once after the simulation run
124      *
125      * This function collects calls which need to be made once at the
126      * end of the simulation run.
127      */
128     void simulatorTeardown();
129
130     /*! \brief A function called before every step
131      *
132      * This function collects calls which need to be made before every
133      * simulation step. The need for this function could likely be
134      * eliminated by rewriting the stop and reset handler to fit the
135      * modular simulator approach.
136      */
137     void preStep(Step step, Time time, bool isNeighborSearchingStep);
138
139     /*! \brief A function called after every step
140      *
141      * This function collects calls which need to be made after every
142      * simulation step.
143      */
144     void postStep(Step step, Time time);
145
146     /*! \brief Build the integrator part of the simulator
147      *
148      * This includes the force calculation, state propagation, constraints,
149      * global computation, and the points during the process at which valid
150      * micro state / energy states are found. Currently, buildIntegrator
151      * knows about NVE md and md-vv algorithms.
152      */
153     std::unique_ptr<ISimulatorElement>
154     buildIntegrator(SignallerBuilder<NeighborSearchSignaller>* neighborSearchSignallerBuilder,
155                     SignallerBuilder<EnergySignaller>*         energySignallerBuilder,
156                     SignallerBuilder<LoggingSignaller>*        loggingSignallerBuilder,
157                     SignallerBuilder<TrajectorySignaller>*     trajectorySignallerBuilder,
158                     std::vector<ICheckpointHelperClient*>*     checkpointClients,
159                     CheckBondedInteractionsCallbackPtr*        checkBondedInteractionsCallback,
160                     compat::not_null<StatePropagatorData*>     statePropagatorDataPtr,
161                     compat::not_null<EnergyElement*>           energyElementPtr,
162                     FreeEnergyPerturbationElement*             freeEnergyPerturbationElementPtr,
163                     bool                                       hasReadEkinState);
164
165     //! Build the force element - can be normal forces or shell / flex constraints
166     std::unique_ptr<ISimulatorElement>
167     buildForces(SignallerBuilder<NeighborSearchSignaller>* neighborSearchSignallerBuilder,
168                 SignallerBuilder<EnergySignaller>*         energySignallerBuilder,
169                 StatePropagatorData*                       statePropagatorDataPtr,
170                 EnergyElement*                             energyElementPtr,
171                 FreeEnergyPerturbationElement*             freeEnergyPerturbationElement);
172
173     /*! \brief Add run functions to the task queue
174      *
175      * This function calls PME load balancing and domain decomposition first,
176      * and then queries the elements for all steps of the life time of the
177      * current neighbor list for their run functions. When the next step
178      * would be a neighbor-searching step, this function returns, such that
179      * the simulator can run the pre-computed task list before updating the
180      * neighbor list and re-filling the task list.
181      *
182      * TODO: In the current approach, unique pointers to tasks are created
183      *       repeatedly. While preliminary measures do not seem to indicate
184      *       performance problems, a pool allocator would be an obvious
185      *       optimization possibility, as would reusing the task queue if
186      *       the task queue is periodic around the rebuild point (i.e. the
187      *       task queue is identical between rebuilds).
188      */
189     void populateTaskQueue();
190
191     //! Check for disabled functionality (during construction time)
192     void checkInputForDisabledFunctionality();
193
194     //! The run queue
195     std::queue<SimulatorRunFunctionPtr> taskQueue_;
196
197     /* Note that the Simulator is owning the signallers and elements.
198      * The ownership list and the call list of the elements are kept
199      * separate, to allow to have elements more than once in the call
200      * lists - for example, using velocity verlet, the compute globals
201      * element needs to be scheduled more than once per step. For the
202      * signallers, no distinction between ownership and call list is
203      * made, all signallers are called exactly once per scheduling step.
204      *
205      * Objects being both a signaller and an element are not supported.
206      */
207     //! List of signalers (ownership and calling sequence)
208     std::vector<std::unique_ptr<ISignaller>> signallerList_;
209     //! List of schedulerElements (ownership)
210     std::vector<std::unique_ptr<ISimulatorElement>> elementsOwnershipList_;
211     //! List of schedulerElements (calling sequence)
212     std::vector<compat::not_null<ISimulatorElement*>> elementCallList_;
213
214     //! \cond
215     //! Helper function to add elements or signallers to the call list via raw pointer
216     template<typename T, typename U>
217     static void addToCallList(U* element, std::vector<compat::not_null<T*>>& callList);
218     //! Helper function to add elements or signallers to the call list via non-null raw pointer
219     template<typename T, typename U>
220     static void addToCallList(compat::not_null<U*> element, std::vector<compat::not_null<T*>>& callList);
221     //! Helper function to add elements or signallers to the call list via smart pointer
222     template<typename T, typename U>
223     static void addToCallList(std::unique_ptr<U>& element, std::vector<compat::not_null<T*>>& callList);
224     /*! \brief Helper function to add elements or signallers to the call list
225      *         and move the ownership to the ownership list
226      */
227     template<typename T, typename U>
228     static void addToCallListAndMove(std::unique_ptr<U>                 element,
229                                      std::vector<compat::not_null<T*>>& callList,
230                                      std::vector<std::unique_ptr<T>>&   elementList);
231     //! \endcond
232
233     // Infrastructure elements
234     //! The domain decomposition element
235     std::unique_ptr<DomDecHelper> domDecHelper_;
236     //! The PME load balancing element
237     std::unique_ptr<PmeLoadBalanceHelper> pmeLoadBalanceHelper_;
238     //! The checkpoint helper
239     std::unique_ptr<CheckpointHelper> checkpointHelper_;
240     //! The stop handler
241     std::unique_ptr<StopHandler> stopHandler_;
242     //! The reset handler
243     std::unique_ptr<ResetHandler> resetHandler_;
244     //! Signal vector (used by stop / reset / checkpointing signaller)
245     SimulationSignals signals_;
246     //! Compute globals communication period
247     int nstglobalcomm_;
248
249     //! The topology
250     std::unique_ptr<TopologyHolder> topologyHolder_;
251
252     //! The current step
253     Step step_ = -1;
254
255     /*! \internal
256      * \brief Signal helper
257      *
258      * The simulator needs to know about the last step and the
259      * neighbor searching step, which are determined in signallers.
260      * This object can be registered to the signals and accessed by
261      * the methods of the simulator.
262      */
263     class SignalHelper : public ILastStepSignallerClient, public INeighborSearchSignallerClient
264     {
265     public:
266         //! The last step
267         Step lastStep_ = std::numeric_limits<Step>::max();
268         //! The next NS step
269         Step nextNSStep_ = -1;
270         //! ILastStepSignallerClient implementation
271         SignallerCallbackPtr registerLastStepCallback() override;
272         //! INeighborSearchSignallerClient implementation
273         SignallerCallbackPtr registerNSCallback() override;
274     };
275     //! The signal helper object
276     std::unique_ptr<SignalHelper> signalHelper_;
277
278     // TODO: This is a hack for stop handler - needs to go once StopHandler
279     //       is adapted to the modular simulator
280     //! Whether this is a neighbor-searching step
281     bool stophandlerIsNSStep_ = false;
282     //! The current step
283     Step stophandlerCurrentStep_ = -1;
284 };
285
286 //! Constructor implementation (here to avoid template-related linker problems)
287 template<typename... Args>
288 ModularSimulator::ModularSimulator(Args&&... args) : ISimulator(std::forward<Args>(args)...)
289 {
290     nstglobalcomm_ = computeGlobalCommunicationPeriod(mdlog, inputrec, cr);
291     signalHelper_  = std::make_unique<SignalHelper>();
292     checkInputForDisabledFunctionality();
293 }
294
295 //! \cond
296 template<typename T, typename U>
297 void ModularSimulator::addToCallList(U* element, std::vector<compat::not_null<T*>>& callList)
298 {
299     if (element)
300     {
301         callList.emplace_back(element);
302     }
303 }
304
305 template<typename T, typename U>
306 void ModularSimulator::addToCallList(gmx::compat::not_null<U*>          element,
307                                      std::vector<compat::not_null<T*>>& callList)
308 {
309     callList.emplace_back(element);
310 }
311
312 template<typename T, typename U>
313 void ModularSimulator::addToCallList(std::unique_ptr<U>& element, std::vector<compat::not_null<T*>>& callList)
314 {
315     if (element)
316     {
317         callList.emplace_back(compat::make_not_null(element.get()));
318     }
319 }
320
321 template<typename T, typename U>
322 void ModularSimulator::addToCallListAndMove(std::unique_ptr<U>                 element,
323                                             std::vector<compat::not_null<T*>>& callList,
324                                             std::vector<std::unique_ptr<T>>&   elementList)
325 {
326     if (element)
327     {
328         callList.emplace_back(compat::make_not_null(element.get()));
329         elementList.emplace_back(std::move(element));
330     }
331 }
332 //! \endcond
333
334 /*!
335  * \brief Whether or not to use the ModularSimulator
336  *
337  * GMX_DISABLE_MODULAR_SIMULATOR environment variable allows to disable modular simulator for
338  * all uses.
339  *
340  * See ModularSimulator::isInputCompatible() for function signature.
341  *
342  * \ingroup module_modularsimulator
343  */
344 template<typename... Ts>
345 auto checkUseModularSimulator(Ts&&... args)
346         -> decltype(ModularSimulator::isInputCompatible(std::forward<Ts>(args)...))
347 {
348     return ModularSimulator::isInputCompatible(std::forward<Ts>(args)...)
349            && getenv("GMX_DISABLE_MODULAR_SIMULATOR") == nullptr;
350 }
351
352 } // namespace gmx
353
354 #endif // GROMACS_MODULARSIMULATOR_MODULARSIMULATOR_H