Fix stop condition handling (modular simulator)
[gromacs.git] / src / gromacs / modularsimulator / signallers.h
blob109031347ec7deeeb74611b236ae0a842d2125bc
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019, 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 /*! \libinternal
36 * \brief Declares the signallers for the modular simulator
38 * \author Pascal Merz <pascal.merz@me.com>
39 * \ingroup module_modularsimulator
42 #ifndef GMX_MODULARSIMULATOR_SIGNALLERS_H
43 #define GMX_MODULARSIMULATOR_SIGNALLERS_H
45 #include <vector>
47 #include "gromacs/compat/pointers.h"
49 #include "modularsimulatorinterfaces.h"
51 namespace gmx
53 class StopHandler;
54 class TrajectoryElement;
56 //! \addtogroup module_modularsimulator
57 //! \{
59 /*! \libinternal
60 * \brief Builder for signallers
62 * This builder allows clients to register, and then builds the signaller
63 * passing on the list of clients.
65 * @tparam Signaller The signaller to be built
67 template <typename Signaller>
68 class SignallerBuilder final
70 public:
71 //! Allows clients to register to the signaller
72 void registerSignallerClient(
73 compat::not_null<typename Signaller::Client*> client);
75 //! Build the signaller
76 template <typename ... Args>
77 std::unique_ptr<Signaller> build(Args && ... args);
79 private:
80 //! List of signaller clients
81 std::vector<typename Signaller::Client*> signallerClients_;
83 //! Helper function to get the callbacks from the clients
84 template <typename ... Args>
85 std::vector<SignallerCallbackPtr> buildCallbackVector(Args && ... args);
87 /*! \brief Get a callback from a single client
89 * This is in a separate function, as the exact call depends on the
90 * specific signaller / client.
92 template <typename ... Args>
93 SignallerCallbackPtr getSignallerCallback(
94 typename Signaller::Client *client,
95 Args && ... args);
99 /*! \libinternal
100 * \brief Element signalling a neighbor search step
102 * This element informs its clients via callbacks
103 * when a neighbor-searching step is happening.
105 class NeighborSearchSignaller final :
106 public ISignaller
108 public:
109 /*! \brief Run the signaller at a specific step / time
111 * Informs callbacks if step % nstlist_ == 0
113 * @param step The current time step
114 * @param time The current time
116 void signal(Step step, Time time) override;
118 //! Do nothing at setup time
119 void signallerSetup() override {};
121 //! Allow builder to construct
122 friend class SignallerBuilder<NeighborSearchSignaller>;
123 //! Define client type
124 typedef INeighborSearchSignallerClient Client;
126 private:
127 /*! \brief Constructor
129 * @param callbacks A vector of pointers to callbacks
130 * @param nstlist The frequency at which neighbor search is performed
131 * @param initStep The first step of the simulation
132 * @param initTime The start time of the simulation
134 NeighborSearchSignaller(
135 std::vector<SignallerCallbackPtr> callbacks,
136 Step nstlist, Step initStep, Time initTime);
138 //! Client callbacks
139 std::vector<SignallerCallbackPtr> callbacks_;
141 //! The NS frequency
142 const Step nstlist_;
143 //! The initial step of the simulation
144 const Step initStep_;
145 //! The initial time of the simulation
146 const Time initTime_;
149 /*! \libinternal
150 * \brief Element signalling the last step
152 * This element informs its clients via callbacks
153 * when the last step is happening.
155 class LastStepSignaller final :
156 public ISignaller,
157 public INeighborSearchSignallerClient
159 public:
160 /*! \brief Run the signaller at a specific step / time
162 * Informs callbacks if this is the last step
164 * @param step The current time step
165 * @param time The current time
167 void signal(Step step, Time time) override;
169 //! Check that necessary registration was done
170 void signallerSetup() override;
172 //! Allow builder to construct
173 friend class SignallerBuilder<LastStepSignaller>;
174 //! Define client type
175 typedef ILastStepSignallerClient Client;
177 private:
178 /*! \brief Constructor
180 * @param callbacks A vector of pointers to callbacks
181 * @param nsteps The total number of steps for the simulation
182 * @param initStep The first step of the simulation
183 * @param stopHandler A pointer to the stop handler (LastStepSignaller takes ownership)
185 LastStepSignaller(
186 std::vector<SignallerCallbackPtr> callbacks,
187 Step nsteps, Step initStep,
188 StopHandler* stopHandler);
190 //! Client callbacks
191 std::vector<SignallerCallbackPtr> callbacks_;
193 //! The last step of the simulation
194 const Step stopStep_;
195 //! Whether we signalled last step due to stop condition
196 bool signalledStopCondition_;
197 //! A pointer to the stop handler communicating signal and time-related stops
198 StopHandler *stopHandler_;
200 //! INeighborSearchSignallerClient implementation
201 SignallerCallbackPtr registerNSCallback() override;
202 //! The next NS step (notified by NS signaller)
203 Step nextNSStep_;
204 //! Whether we registered to the NS signaller
205 bool nsStepRegistrationDone_;
208 /*! \libinternal
209 * \brief Element signalling a logging step
211 * This element informs its clients via callbacks
212 * when a logging step is happening.
214 class LoggingSignaller final :
215 public ISignaller,
216 public ILastStepSignallerClient
218 public:
219 /*! \brief Run the signaller at a specific step / time
221 * Informs callbacks if step % nstlog_ == 0
223 * @param step The current time step
224 * @param time The current time
226 void signal(Step step, Time time) override;
228 //! Check that necessary registration was done
229 void signallerSetup() override;
231 //! Allow builder to construct
232 friend class SignallerBuilder<LoggingSignaller>;
233 //! Define client type
234 typedef ILoggingSignallerClient Client;
236 private:
237 /*! \brief Constructor
239 * @param callbacks A vector of pointers to callbacks
240 * @param nstlog The logging frequency
241 * @param initStep The first step of the simulation
242 * @param initTime The start time of the simulation
244 LoggingSignaller(
245 std::vector<SignallerCallbackPtr> callbacks,
246 Step nstlog,
247 Step initStep,
248 Time initTime);
250 //! Client callbacks
251 std::vector<SignallerCallbackPtr> callbacks_;
253 //! The logging frequency
254 const Step nstlog_;
255 //! The initial step of the simulation
256 const Step initStep_;
257 //! The initial time of the simulation
258 const Time initTime_;
260 //! ILastStepSignallerClient implementation
261 SignallerCallbackPtr registerLastStepCallback() override;
262 //! The last step (notified by signaller)
263 Step lastStep_;
264 //! Whether we registered to the last step signaller
265 bool lastStepRegistrationDone_;
268 /*! \libinternal
269 * \brief Element signalling energy related special steps
271 * This element informs its clients via callbacks
272 * of the following events:
273 * - energy calculation step
274 * - virial calculation step
275 * - free energy calculation step
277 class EnergySignaller final :
278 public ISignaller,
279 public ITrajectorySignallerClient,
280 public ILoggingSignallerClient
282 public:
283 /*! \brief Run the signaller at a specific step / time
285 * Informs callbacks of energy / virial / free energy special steps
287 * @param step The current time step
288 * @param time The current time
290 void signal(Step step, Time time) override;
292 //! Check that necessary registration was done
293 void signallerSetup() override;
295 //! Allow builder to construct
296 friend class SignallerBuilder<EnergySignaller>;
297 //! Define client type
298 typedef IEnergySignallerClient Client;
300 private:
301 /*! \brief Constructor
303 * @param calculateEnergyCallbacks A vector of pointers to callbacks (energy steps)
304 * @param calculateVirialCallbacks A vector of pointers to callbacks (virial steps)
305 * @param calculateFreeEnergyCallbacks A vector of pointers to callbacks (free energy steps)
306 * @param nstcalcenergy The energy calculation frequency
307 * @param nstcalcfreeenergy The free energy calculation frequency
308 * @param nstcalcvirial The free energy calculation frequency
310 EnergySignaller(
311 std::vector<SignallerCallbackPtr> calculateEnergyCallbacks,
312 std::vector<SignallerCallbackPtr> calculateVirialCallbacks,
313 std::vector<SignallerCallbackPtr> calculateFreeEnergyCallbacks,
314 int nstcalcenergy,
315 int nstcalcfreeenergy,
316 int nstcalcvirial);
318 //! Client callbacks
319 //! {
320 std::vector<SignallerCallbackPtr> calculateEnergyCallbacks_;
321 std::vector<SignallerCallbackPtr> calculateVirialCallbacks_;
322 std::vector<SignallerCallbackPtr> calculateFreeEnergyCallbacks_;
323 //! }
325 //! The energy calculation frequency
326 const int nstcalcenergy_;
327 //! The free energy calculation frequency
328 const int nstcalcfreeenergy_;
329 //! The virial calculation frequency
330 const int nstcalcvirial_;
332 //! ITrajectorySignallerClient implementation
333 SignallerCallbackPtr registerTrajectorySignallerCallback(TrajectoryEvent event) override;
334 //! The energy writing step (notified by signaller)
335 Step energyWritingStep_;
336 //! Whether we registered to the trajectory signaller
337 bool trajectoryRegistrationDone_;
339 //! ILoggingSignallerClient implementation
340 SignallerCallbackPtr registerLoggingCallback() override;
341 //! The next logging step (notified by signaller)
342 Step loggingStep_;
343 //! Whether we registered to the logging signaller
344 bool loggingRegistrationDone_;
347 //! /}
349 //! Allows clients to register to the signaller
350 template <class Signaller>
351 void SignallerBuilder<Signaller>::registerSignallerClient(
352 compat::not_null<typename Signaller::Client*> client)
354 signallerClients_.emplace_back(client);
357 /*! \brief Build the signaller
359 * General version - for NeighborSearchSignaller, LastStepSignaller, LoggingSignaller
361 template <class Signaller>
362 template <typename ... Args>
363 std::unique_ptr<Signaller> SignallerBuilder<Signaller>::build(Args && ... args)
365 auto callbacks = buildCallbackVector();
366 // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
367 return std::unique_ptr<Signaller>(
368 new Signaller(
369 std::move(callbacks),
370 std::forward<Args>(args) ...));
373 /*! \brief Build the signaller
375 * Specialized version - EnergySignaller has a significantly different build process
377 template <>
378 template <typename ... Args>
379 std::unique_ptr<EnergySignaller> SignallerBuilder<EnergySignaller>::build(Args && ... args)
381 auto calculateEnergyCallbacks = buildCallbackVector(EnergySignallerEvent::energyCalculationStep);
382 auto calculateVirialCallbacks = buildCallbackVector(EnergySignallerEvent::virialCalculationStep);
383 auto calculateFreeEnergyCallbacks = buildCallbackVector(EnergySignallerEvent::freeEnergyCalculationStep);
384 // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
385 return std::unique_ptr<EnergySignaller>(
386 new EnergySignaller(
387 std::move(calculateEnergyCallbacks),
388 std::move(calculateVirialCallbacks),
389 std::move(calculateFreeEnergyCallbacks),
390 std::forward<Args>(args) ...));
393 //! Helper function to get the callbacks from the clients
394 template <typename Signaller>
395 template <typename ... Args>
396 std::vector<SignallerCallbackPtr> SignallerBuilder<Signaller>::buildCallbackVector(Args && ... args)
398 std::vector<SignallerCallbackPtr> callbacks;
399 // Allow clients to register their callbacks
400 for (auto &client : signallerClients_)
402 if (auto callback = getSignallerCallback(client, std::forward<Args>(args) ...)) // don't register nullptr
404 callbacks.emplace_back(std::move(callback));
407 return callbacks;
410 //! Get a callback from a single client - NeighborSearchSignaller
411 template <>
412 template <typename ... Args>
413 SignallerCallbackPtr SignallerBuilder<NeighborSearchSignaller>::getSignallerCallback(
414 typename NeighborSearchSignaller::Client *client, Args && ... args)
416 return client->registerNSCallback(std::forward<Args>(args) ...);
419 //! Get a callback from a single client - LastStepSignaller
420 template <>
421 template <typename ... Args>
422 SignallerCallbackPtr SignallerBuilder<LastStepSignaller>::getSignallerCallback(
423 typename LastStepSignaller::Client *client, Args && ... args)
425 return client->registerLastStepCallback(std::forward<Args>(args) ...);
428 //! Get a callback from a single client - LoggingSignaller
429 template <>
430 template <typename ... Args>
431 SignallerCallbackPtr SignallerBuilder<LoggingSignaller>::getSignallerCallback(
432 typename LoggingSignaller::Client *client, Args && ... args)
434 return client->registerLoggingCallback(std::forward<Args>(args) ...);
437 //! Get a callback from a single client - EnergySignaller
438 template <>
439 template <typename ... Args>
440 SignallerCallbackPtr SignallerBuilder<EnergySignaller>::getSignallerCallback(
441 typename EnergySignaller::Client *client, Args && ... args)
443 return client->registerEnergyCallback(std::forward<Args>(args) ...);
446 } // namespace gmx
448 #endif // GMX_MODULARSIMULATOR_SIGNALLERS_H