2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019,2020,2021, 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.
36 * \brief Declares the signallers for the modular simulator
38 * \author Pascal Merz <pascal.merz@me.com>
39 * \ingroup module_modularsimulator
41 * This header is only used within the modular simulator module
44 #ifndef GMX_MODULARSIMULATOR_SIGNALLERS_H
45 #define GMX_MODULARSIMULATOR_SIGNALLERS_H
49 #include "gromacs/compat/pointers.h"
51 #include "modularsimulatorinterfaces.h"
56 class TrajectoryElement;
57 enum class StartingBehavior;
60 * \ingroup module_modularsimulator
61 * \brief Builder for signallers
63 * This builder allows clients to register, and then builds the signaller
64 * passing on the list of clients.
66 * \tparam Signaller The signaller to be built
68 template<typename Signaller>
69 class SignallerBuilder final
72 //! Allows clients to register to the signaller
73 void registerSignallerClient(typename Signaller::Client* client);
75 //! Build the signaller
76 template<typename... Args>
77 std::unique_ptr<Signaller> build(Args&&... args);
80 //! List of signaller clients
81 std::vector<typename Signaller::Client*> signallerClients_;
82 //! The state of the builder
83 ModularSimulatorBuilderState state_ = ModularSimulatorBuilderState::AcceptingClientRegistrations;
85 //! Helper function to get the callbacks from the clients
86 template<typename... Args>
87 std::vector<SignallerCallback> buildCallbackVector(Args&&... args);
89 /*! \brief Get a callback from a single client
91 * This is in a separate function, as the exact call depends on the
92 * specific signaller / client.
94 template<typename... Args>
95 std::optional<SignallerCallback> getSignallerCallback(typename Signaller::Client* client,
100 * \ingroup module_modularsimulator
101 * \brief Element signalling a neighbor search step
103 * This element informs its clients via callbacks
104 * when a neighbor-searching step is happening.
106 class NeighborSearchSignaller final : public ISignaller
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 setup() override{};
121 //! Allow builder to construct
122 friend class SignallerBuilder<NeighborSearchSignaller>;
123 //! Define client type
124 typedef INeighborSearchSignallerClient Client;
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(std::vector<SignallerCallback> callbacks, Step nstlist, Step initStep, Time initTime);
137 std::vector<SignallerCallback> callbacks_;
141 //! The initial step of the simulation
142 const Step initStep_;
143 //! The initial time of the simulation
144 const Time initTime_;
148 * \ingroup module_modularsimulator
149 * \brief Element signalling the last step
151 * This element informs its clients via callbacks
152 * when the last step is happening.
154 class LastStepSignaller final : public ISignaller, public INeighborSearchSignallerClient
157 /*! \brief Run the signaller at a specific step / time
159 * Informs callbacks if this is the last step
161 * \param step The current time step
162 * \param time The current time
164 void signal(Step step, Time time) override;
166 //! Check that necessary registration was done
167 void setup() override;
169 //! Allow builder to construct
170 friend class SignallerBuilder<LastStepSignaller>;
171 //! Define client type
172 typedef ILastStepSignallerClient Client;
175 /*! \brief Constructor
177 * \param callbacks A vector of pointers to callbacks
178 * \param nsteps The total number of steps for the simulation
179 * \param initStep The first step of the simulation
180 * \param stopHandler A pointer to the stop handler (LastStepSignaller takes ownership)
182 LastStepSignaller(std::vector<SignallerCallback> callbacks, Step nsteps, Step initStep, StopHandler* stopHandler);
185 std::vector<SignallerCallback> callbacks_;
187 //! The last step of the simulation
188 const Step stopStep_;
189 //! Whether we signalled last step due to stop condition
190 bool signalledStopCondition_;
191 //! A pointer to the stop handler communicating signal and time-related stops
192 StopHandler* stopHandler_;
194 //! INeighborSearchSignallerClient implementation
195 std::optional<SignallerCallback> registerNSCallback() override;
196 //! The next NS step (notified by NS signaller)
198 //! Whether we registered to the NS signaller
199 bool nsStepRegistrationDone_;
203 * \ingroup module_modularsimulator
204 * \brief Element signalling a logging step
206 * This element informs its clients via callbacks
207 * when a logging step is happening.
209 class LoggingSignaller final : public ISignaller, public ILastStepSignallerClient
212 /*! \brief Run the signaller at a specific step / time
214 * Informs callbacks if step % nstlog_ == 0
216 * \param step The current time step
217 * \param time The current time
219 void signal(Step step, Time time) override;
221 //! Check that necessary registration was done
222 void setup() override;
224 //! Allow builder to construct
225 friend class SignallerBuilder<LoggingSignaller>;
226 //! Define client type
227 typedef ILoggingSignallerClient Client;
230 /*! \brief Constructor
232 * \param callbacks A vector of pointers to callbacks
233 * \param nstlog The logging frequency
234 * \param initStep The first step of the simulation
235 * \param startingBehavior Whether this is a new simulation or restarting from checkpoint
237 LoggingSignaller(std::vector<SignallerCallback> callbacks,
240 StartingBehavior startingBehavior);
243 std::vector<SignallerCallback> callbacks_;
245 //! The logging frequency
247 //! The initial step of the simulation
248 const Step initStep_;
249 //! How we are starting the simulation
250 const StartingBehavior startingBehavior_;
252 //! ILastStepSignallerClient implementation
253 std::optional<SignallerCallback> registerLastStepCallback() override;
254 //! The last step (notified by signaller)
256 //! Whether we registered to the last step signaller
257 bool lastStepRegistrationDone_;
261 * \ingroup module_modularsimulator
262 * \brief Element signalling trajectory writing
264 * During signalling phase, it checks whether the current step is a writing
265 * step for either the energy or the state (position, velocity, forces)
266 * trajectory. It then notifies the signaller clients of the upcoming step.
268 * The TrajectorySignaller works in close collaboration with the TrajectoryElement
269 * which does the actual trajectory writing during the simulation step.
271 class TrajectorySignaller final : public ISignaller, public ILastStepSignallerClient
274 /*! \brief Prepare signaller
276 * Check that necessary registration was done
278 void setup() override;
280 /*! \brief Run the signaller at a specific step / time
282 * Informs clients when energy or state will be written.
284 * \param step The current time step
285 * \param time The current time
287 void signal(Step step, Time time) override;
289 //! Allow builder to construct
290 friend class SignallerBuilder<TrajectorySignaller>;
291 //! Define client type
292 typedef ITrajectorySignallerClient Client;
296 TrajectorySignaller(std::vector<SignallerCallback> signalEnergyCallbacks,
297 std::vector<SignallerCallback> signalStateCallbacks,
301 int nstxoutCompressed,
304 int tngBoxOutCompressed,
305 int tngLambdaOutCompressed,
308 //! Output frequencies
313 const int nstxoutCompressed_;
314 const int tngBoxOut_;
315 const int tngLambdaOut_;
316 const int tngBoxOutCompressed_;
317 const int tngLambdaOutCompressed_;
318 const int nstenergy_;
321 //! Callbacks to signal events
323 std::vector<SignallerCallback> signalEnergyCallbacks_;
324 std::vector<SignallerCallback> signalStateCallbacks_;
331 bool lastStepRegistrationDone_;
332 //! ILastStepSignallerClient implementation
333 std::optional<SignallerCallback> registerLastStepCallback() override;
337 * \ingroup module_modularsimulator
338 * \brief Element signalling energy related special steps
340 * This element informs its clients via callbacks
341 * of the following events:
342 * - energy calculation step
343 * - virial calculation step
344 * - free energy calculation step
346 class EnergySignaller final : public ISignaller, public ITrajectorySignallerClient, public ILoggingSignallerClient
349 /*! \brief Run the signaller at a specific step / time
351 * Informs callbacks of energy / virial / free energy special steps
353 * \param step The current time step
354 * \param time The current time
356 void signal(Step step, Time time) override;
358 //! Check that necessary registration was done
359 void setup() override;
361 //! Allow builder to construct
362 friend class SignallerBuilder<EnergySignaller>;
363 //! Define client type
364 typedef IEnergySignallerClient Client;
367 /*! \brief Constructor
369 * \param calculateEnergyCallbacks A vector of pointers to callbacks (energy steps)
370 * \param calculateVirialCallbacks A vector of pointers to callbacks (virial steps)
371 * \param calculateFreeEnergyCallbacks A vector of pointers to callbacks (free energy steps)
372 * \param nstcalcenergy The energy calculation frequency
373 * \param nstcalcfreeenergy The free energy calculation frequency
374 * \param nstcalcvirial The free energy calculation frequency
376 EnergySignaller(std::vector<SignallerCallback> calculateEnergyCallbacks,
377 std::vector<SignallerCallback> calculateVirialCallbacks,
378 std::vector<SignallerCallback> calculateFreeEnergyCallbacks,
380 int nstcalcfreeenergy,
385 std::vector<SignallerCallback> calculateEnergyCallbacks_;
386 std::vector<SignallerCallback> calculateVirialCallbacks_;
387 std::vector<SignallerCallback> calculateFreeEnergyCallbacks_;
390 //! The energy calculation frequency
391 const int nstcalcenergy_;
392 //! The free energy calculation frequency
393 const int nstcalcfreeenergy_;
394 //! The virial calculation frequency
395 const int nstcalcvirial_;
397 //! ITrajectorySignallerClient implementation
398 std::optional<SignallerCallback> registerTrajectorySignallerCallback(TrajectoryEvent event) override;
399 //! The energy writing step (notified by signaller)
400 Step energyWritingStep_;
401 //! Whether we registered to the trajectory signaller
402 bool trajectoryRegistrationDone_;
404 //! ILoggingSignallerClient implementation
405 std::optional<SignallerCallback> registerLoggingCallback() override;
406 //! The next logging step (notified by signaller)
408 //! Whether we registered to the logging signaller
409 bool loggingRegistrationDone_;
412 //! Allows clients to register to the signaller
413 template<class Signaller>
414 void SignallerBuilder<Signaller>::registerSignallerClient(typename Signaller::Client* client)
418 if (state_ == ModularSimulatorBuilderState::NotAcceptingClientRegistrations)
420 throw SimulationAlgorithmSetupError(
421 "Tried to register to signaller after it was built.");
423 signallerClients_.emplace_back(client);
427 /*! \brief Build the signaller
429 * General version - for NeighborSearchSignaller, LastStepSignaller, LoggingSignaller
431 template<class Signaller>
432 template<typename... Args>
433 std::unique_ptr<Signaller> SignallerBuilder<Signaller>::build(Args&&... args)
435 state_ = ModularSimulatorBuilderState::NotAcceptingClientRegistrations;
436 auto callbacks = buildCallbackVector();
437 // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
438 return std::unique_ptr<Signaller>(new Signaller(std::move(callbacks), std::forward<Args>(args)...));
441 /*! \brief Build the signaller
443 * Specialized version - TrajectorySignaller has a different build process
446 template<typename... Args>
447 std::unique_ptr<TrajectorySignaller> SignallerBuilder<TrajectorySignaller>::build(Args&&... args)
449 state_ = ModularSimulatorBuilderState::NotAcceptingClientRegistrations;
450 auto signalEnergyCallbacks = buildCallbackVector(TrajectoryEvent::EnergyWritingStep);
451 auto signalStateCallbacks = buildCallbackVector(TrajectoryEvent::StateWritingStep);
452 // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
453 return std::unique_ptr<TrajectorySignaller>(new TrajectorySignaller(
454 std::move(signalEnergyCallbacks), std::move(signalStateCallbacks), std::forward<Args>(args)...));
457 /*! \brief Build the signaller
459 * Specialized version - EnergySignaller has a significantly different build process
462 template<typename... Args>
463 std::unique_ptr<EnergySignaller> SignallerBuilder<EnergySignaller>::build(Args&&... args)
465 state_ = ModularSimulatorBuilderState::NotAcceptingClientRegistrations;
466 auto calculateEnergyCallbacks = buildCallbackVector(EnergySignallerEvent::EnergyCalculationStep);
467 auto calculateVirialCallbacks = buildCallbackVector(EnergySignallerEvent::VirialCalculationStep);
468 auto calculateFreeEnergyCallbacks =
469 buildCallbackVector(EnergySignallerEvent::FreeEnergyCalculationStep);
470 // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
471 return std::unique_ptr<EnergySignaller>(new EnergySignaller(std::move(calculateEnergyCallbacks),
472 std::move(calculateVirialCallbacks),
473 std::move(calculateFreeEnergyCallbacks),
474 std::forward<Args>(args)...));
477 //! Helper function to get the callbacks from the clients
478 template<typename Signaller>
479 template<typename... Args>
480 std::vector<SignallerCallback> SignallerBuilder<Signaller>::buildCallbackVector(Args&&... args)
482 std::vector<SignallerCallback> callbacks;
483 // Allow clients to register their callbacks
484 for (auto& client : signallerClients_)
486 if (auto callback = getSignallerCallback(client, std::forward<Args>(args)...)) // don't register nullptr
488 callbacks.emplace_back(std::move(*callback));
494 //! Get a callback from a single client - NeighborSearchSignaller
496 template<typename... Args>
497 std::optional<SignallerCallback> SignallerBuilder<NeighborSearchSignaller>::getSignallerCallback(
498 typename NeighborSearchSignaller::Client* client,
501 return client->registerNSCallback(std::forward<Args>(args)...);
504 //! Get a callback from a single client - LastStepSignaller
506 template<typename... Args>
507 std::optional<SignallerCallback>
508 SignallerBuilder<LastStepSignaller>::getSignallerCallback(typename LastStepSignaller::Client* client,
511 return client->registerLastStepCallback(std::forward<Args>(args)...);
514 //! Get a callback from a single client - LoggingSignaller
516 template<typename... Args>
517 std::optional<SignallerCallback>
518 SignallerBuilder<LoggingSignaller>::getSignallerCallback(typename LoggingSignaller::Client* client,
521 return client->registerLoggingCallback(std::forward<Args>(args)...);
524 //! Get a callback from a single client - TrajectorySignaller
526 template<typename... Args>
527 std::optional<SignallerCallback>
528 SignallerBuilder<TrajectorySignaller>::getSignallerCallback(typename TrajectorySignaller::Client* client,
531 return client->registerTrajectorySignallerCallback(std::forward<Args>(args)...);
534 //! Get a callback from a single client - EnergySignaller
536 template<typename... Args>
537 std::optional<SignallerCallback>
538 SignallerBuilder<EnergySignaller>::getSignallerCallback(typename EnergySignaller::Client* client,
541 return client->registerEnergyCallback(std::forward<Args>(args)...);
546 #endif // GMX_MODULARSIMULATOR_SIGNALLERS_H