Introduce signallers for modular integrator
authorPascal Merz <pascal.merz@me.com>
Wed, 19 Jun 2019 02:35:42 +0000 (20:35 -0600)
committerMark Abraham <mark.j.abraham@gmail.com>
Wed, 28 Aug 2019 16:40:34 +0000 (18:40 +0200)
commitc1e6bbf947fbdc25dde8a662d4281143545281fd
treeb479b092c258632617afcb03088e3945592555dc
parent9618ec8185cbddb8c6a6b070a57bf00a31fa0200
Introduce signallers for modular integrator

In the current do_md() function, code flow is governed by booleans
set on every iteration of the simulator loop (e.g. bNS, do_ene,
bCalcEner, etc). In a modular simulator, we want to avoid common,
quasi-global variables. This change proposes an approach to replace
these booleans by a signaller-client system. An object ("signaller")
is thereby responsible to decide when specific events are happening,
and is informing its clients about it. This approach is implemented
for five types of events, namely neighbor-searching steps, logging
steps, energy-calculation steps (energy, free energy and virial
calculation), the last step, and trajectory (x/v/f and energy)
writing steps.

These signallers are designed to run at the beginning of scheduling
for a specific step.

If signallers depend on each others, they need to be ran in their
order of dependency. To illustrate this, consider the case of energy
calculation. This signaller can run by itself, checking if the
current step is an energy-calculation step. It can also be triggered
by the trajectory signaller, since the energy signaller is a client -
another way to say that we should calculate energies if we want to
write to the energy trajectory in this step. While we could imagine
that the trajectory signaller triggers a callback which in turn
informs the energy clients about the next step, this becomes shaky
when a signaller depends on more than one other signaller. Running
the signallers in their order of dependence, on the other hand, is
stable as long as there are no cyclic dependencies (which should
never happen). In our example, we therefore require the trajectory
signaller to run before the energy signaller. The builder, which
also registers signallers which each others, is responsible to keep
the signallers in order. This is trivially done by adding the
signallers to a vector right after building them.

The TrajectoryElement is both a simulator element (as it needs to run
periodically to output state or energy information to file) and a
signaller (as it needs to warn the state / energy objects that a
writing step is coming up). The TrajectoryElement is built around the
gmx_mdoutf object, which it owns. It can therefore not easily be
split into a element and a signaller part, or into a state writing and a
energy writing part. During the simulator run phase, it is
calling its trajectory clients (which do not necessarily need
to be identical with the signaller clients), passing them a valid
output pointer and letting them write to trajectory. Unlike the
legacy implementation, the trajectory element itself knows nothing
about the data that is written to file - it is only responsible
to inform clients about trajectory steps, and providing a valid
file pointer to the objects that need to write to trajectory.

This commit is part of the commit chain introducing the new modular
simulator. Please see docs/doxygen/lib/modularsimulator.md for details
on the chosen approach. As the elements of the new simulator cannot all
be introduced in one commit, it might be worth to view Iaae1e205 to see
a working prototype of the approach.

Change-Id: Ic58a18a374ff0ec5a47d0853c514e439ba1a45a3
docs/doxygen/lib/modularsimulator.md
docs/doxygen/suppressions.txt
src/gromacs/modularsimulator/CMakeLists.txt
src/gromacs/modularsimulator/modularsimulatorinterfaces.h
src/gromacs/modularsimulator/signallers.cpp [new file with mode: 0644]
src/gromacs/modularsimulator/signallers.h [new file with mode: 0644]
src/gromacs/modularsimulator/trajectoryelement.cpp [new file with mode: 0644]
src/gromacs/modularsimulator/trajectoryelement.h [new file with mode: 0644]