ComputeGlobalsElement for the modular simulator
authorPascal Merz <pascal.merz@me.com>
Tue, 9 Jul 2019 13:14:35 +0000 (07:14 -0600)
committerPascal Merz <pascal.merz@colorado.edu>
Fri, 6 Sep 2019 17:41:47 +0000 (19:41 +0200)
This element encapsulates the calls to `compute_globals`. A new
approach to fit the global computation calls into the client approach has
been proposed in I44a7193c, but a complete rewriting is currently outside
the scope of this effort. This element therefore aims at offering an
interface to the legacy implementation which is compatible with the new
simulator approach.

The element comes in 3 (templated) flavors: the leap-frog case, the first
call during a velocity-verlet integrator, and the second call during a
velocity-verlet integrator.

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: I35f310daed6355dc9ea6b574d855929ec2fee6fe

docs/doxygen/lib/modularsimulator.md
src/gromacs/modularsimulator/computeglobalselement.cpp [new file with mode: 0644]
src/gromacs/modularsimulator/computeglobalselement.h [new file with mode: 0644]

index c923a1ca79317214590e8690e223505bef8ce774..0127478634b04eb4b88849c0acf043208bddb389 100644 (file)
@@ -381,6 +381,19 @@ responsibility of the simulator builder to ensure that the
 `EnergyElement` is called at a point of the simulator run
 at which it has access to a valid energy state.
 
+#### `ComputeGlobalsElement`
+The `ComputeGlobalsElement` encapsulates the legacy calls to
+`compute_globals`. While a new approach to the global reduction
+operations has been discussed, it is currently not part of this
+effort. This element therefore aims at offering an interface
+to the legacy implementation which is compatible with the new
+simulator approach.
+
+The element currently comes in 3 (templated) flavors: the leap-frog case,
+the first call during a velocity-verlet integrator, and the second call
+during a velocity-verlet integrator. It is the responsibility of the
+simulator builder to place them at the right place of the
+integration algorithm.
 
 ## Data structures
 
diff --git a/src/gromacs/modularsimulator/computeglobalselement.cpp b/src/gromacs/modularsimulator/computeglobalselement.cpp
new file mode 100644 (file)
index 0000000..f26bd45
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal
+ * \brief Defines the global reduction element for the modular simulator
+ *
+ * \author Pascal Merz <pascal.merz@me.com>
+ * \ingroup module_modularsimulator
+ */
+
+#include "gmxpre.h"
+
+#include "computeglobalselement.h"
+
+#include "gromacs/domdec/partition.h"
+#include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/md_support.h"
+#include "gromacs/mdlib/mdatoms.h"
+#include "gromacs/mdlib/stat.h"
+#include "gromacs/mdtypes/group.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/topology/topology.h"
+
+namespace gmx
+{
+template <ComputeGlobalsAlgorithm algorithm>
+ComputeGlobalsElement<algorithm>::ComputeGlobalsElement(
+        StatePropagatorData *statePropagatorData,
+        EnergyElement       *energyElement,
+        int                  nstglobalcomm,
+        FILE                *fplog,
+        const MDLogger      &mdlog,
+        t_commrec           *cr,
+        t_inputrec          *inputrec,
+        const MDAtoms       *mdAtoms,
+        t_nrnb              *nrnb,
+        gmx_wallcycle       *wcycle,
+        t_forcerec          *fr,
+        const gmx_mtop_t    *global_top,
+        Constraints         *constr) :
+    energyReductionStep_(-1),
+    virialReductionStep_(-1),
+    doStopCM_(inputrec->comm_mode != ecmNO),
+    nstcomm_(inputrec->nstcomm),
+    nstglobalcomm_(nstglobalcomm),
+    initStep_(inputrec->init_step),
+    nullSignaller_(std::make_unique<SimulationSignaller>(nullptr, nullptr, nullptr, false, false)),
+    totalNumberOfBondedInteractions_(0),
+    shouldCheckNumberOfBondedInteractions_(false),
+    needToSumEkinhOld_(false),
+    statePropagatorData_(statePropagatorData),
+    energyElement_(energyElement),
+    localTopology_(nullptr),
+    vcm_(global_top->groups, *inputrec),
+    signals_(),
+    fplog_(fplog),
+    mdlog_(mdlog),
+    cr_(cr),
+    inputrec_(inputrec),
+    top_global_(global_top),
+    mdAtoms_(mdAtoms),
+    constr_(constr),
+    nrnb_(nrnb),
+    wcycle_(wcycle),
+    fr_(fr)
+{
+    reportComRemovalInfo(fplog, vcm_);
+    gstat_ = global_stat_init(inputrec_);
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+ComputeGlobalsElement<algorithm>::~ComputeGlobalsElement()
+{
+    global_stat_destroy(gstat_);
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+void ComputeGlobalsElement<algorithm>::elementSetup()
+{
+    GMX_ASSERT(localTopology_, "Setup called before local topology was set.");
+
+    // Only do initial communication step for one of the velocity-verlet stages
+    if (algorithm == ComputeGlobalsAlgorithm::LeapFrog ||
+        algorithm == ComputeGlobalsAlgorithm::VelocityVerletAtFullTimeStep)
+    {
+        // TODO: When reintroducing checkpointing:
+        //      * add CGLO_READEKIN if we read ekin
+        //      * don't remove com motion if we read from checkpoint
+        unsigned int        cglo_flags =
+            (CGLO_TEMPERATURE | CGLO_GSTAT
+             | (shouldCheckNumberOfBondedInteractions_ ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0));
+
+        if (algorithm == ComputeGlobalsAlgorithm::VelocityVerletAtFullTimeStep)
+        {
+            cglo_flags |= CGLO_PRESSURE | CGLO_CONSTRAINT;
+        }
+
+        // To minimize communication, compute_globals computes the COM velocity
+        // and the kinetic energy for the velocities without COM motion removed.
+        // Thus to get the kinetic energy without the COM contribution, we need
+        // to call compute_globals twice.
+        for (int cgloIteration = 0; cgloIteration < (doStopCM_ ? 2 : 1); cgloIteration++)
+        {
+            unsigned int cglo_flags_iteration = cglo_flags;
+            if (doStopCM_ && cgloIteration == 0)
+            {
+                cglo_flags_iteration |= CGLO_STOPCM;
+                cglo_flags_iteration &= ~CGLO_TEMPERATURE;
+            }
+
+            compute(-1, cglo_flags_iteration, nullSignaller_.get(), false, true);
+
+            if (cglo_flags_iteration & CGLO_STOPCM)
+            {
+                auto v = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
+                // At initialization, do not pass x with acceleration-correction mode
+                // to avoid (incorrect) correction of the initial coordinates.
+                rvec *xPtr = nullptr;
+                if (vcm_.mode != ecmLINEAR_ACCELERATION_CORRECTION)
+                {
+                    xPtr = as_rvec_array(statePropagatorData_->positionsView().paddedArrayRef().data());
+                }
+                process_and_stopcm_grp(fplog_, &vcm_, *mdAtoms_->mdatoms(), xPtr, v);
+                inc_nrnb(nrnb_, eNR_STOPCM, mdAtoms_->mdatoms()->homenr);
+            }
+        }
+
+        // Calculate the initial half step temperature, and save the ekinh_old
+        for (int i = 0; (i < inputrec_->opts.ngtc); i++)
+        {
+            copy_mat(energyElement_->ekindata()->tcstat[i].ekinh,
+                     energyElement_->ekindata()->tcstat[i].ekinh_old);
+        }
+    }
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+void ComputeGlobalsElement<algorithm>::scheduleTask(
+        Step step, Time gmx_unused time,
+        const RegisterRunFunctionPtr &registerRunFunction)
+{
+    const bool needComReduction    = doStopCM_ && do_per_step(step, nstcomm_);
+    const bool needGlobalReduction =
+        step == energyReductionStep_ || step == virialReductionStep_ ||
+        needComReduction || do_per_step(step, nstglobalcomm_);
+
+    // TODO: CGLO_GSTAT is only used for needToSumEkinhOld_, i.e. to signal that we do or do not
+    //       sum the previous kinetic energy. We should simplify / clarify this.
+
+    if (algorithm == ComputeGlobalsAlgorithm::LeapFrog)
+    {
+        // With Leap-Frog we can skip compute_globals at
+        // non-communication steps, but we need to calculate
+        // the kinetic energy one step before communication.
+        if (!needGlobalReduction && !do_per_step(step+1, nstglobalcomm_))
+        {
+            return;
+        }
+
+        const bool doEnergy = step == energyReductionStep_;
+        int        flags    =
+            (needGlobalReduction ? CGLO_GSTAT : 0)
+            | (doEnergy ? CGLO_ENERGY : 0)
+            | (needComReduction ? CGLO_STOPCM : 0)
+            | CGLO_TEMPERATURE
+            | CGLO_PRESSURE
+            | CGLO_CONSTRAINT
+            | (shouldCheckNumberOfBondedInteractions_ ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0);
+
+        // Since we're already communicating at this step, we
+        // can propagate intra-simulation signals. Note that
+        // check_nstglobalcomm has the responsibility for
+        // choosing the value of nstglobalcomm which satisfies
+        // the need of the different signallers.
+        const bool  doIntraSimSignal = true;
+        // Disable functionality
+        const bool  doInterSimSignal = false;
+
+        // Make signaller to signal stop / reset / checkpointing signals
+        auto signaller = std::make_shared<SimulationSignaller>(
+                    &signals_, cr_, nullptr, doInterSimSignal, doIntraSimSignal);
+
+        (*registerRunFunction)(
+                std::make_unique<SimulatorRunFunction>(
+                        [this, step, flags, signaller = std::move(signaller)]()
+                        {compute(step, flags, signaller.get(), true); }));
+    }
+    else if (algorithm == ComputeGlobalsAlgorithm::VelocityVerletAtFullTimeStep)
+    {
+        // For vv, the state at the beginning of the step is positions at time t, velocities at time t - dt/2
+        // The first velocity propagation (+dt/2) therefore actually corresponds to the previous step.
+        // So we need information from the last step in the first half of the integration
+        if (!needGlobalReduction && !do_per_step(step - 1, nstglobalcomm_))
+        {
+            return;
+        }
+
+        const bool doTemperature = step != initStep_;
+        const bool doEnergy      = step == energyReductionStep_;
+
+        int        flags =
+            (needGlobalReduction ? CGLO_GSTAT : 0)
+            | (doEnergy ? CGLO_ENERGY : 0)
+            | (doTemperature ? CGLO_TEMPERATURE : 0)
+            | CGLO_PRESSURE
+            | CGLO_CONSTRAINT
+            | (needComReduction ? CGLO_STOPCM : 0)
+            | (shouldCheckNumberOfBondedInteractions_ ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0)
+            | CGLO_SCALEEKIN;
+
+        (*registerRunFunction)(
+                std::make_unique<SimulatorRunFunction>(
+                        [this, step, flags]() { compute(step, flags, nullSignaller_.get(), false); }));
+    }
+    else if (algorithm == ComputeGlobalsAlgorithm::VelocityVerletAfterCoordinateUpdate)
+    {
+        // second call to compute_globals for this step
+        if (!needGlobalReduction)
+        {
+            return;
+        }
+        int flags =
+            CGLO_GSTAT | CGLO_CONSTRAINT
+            | (shouldCheckNumberOfBondedInteractions_ ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0);
+
+        // Since we're already communicating at this step, we
+        // can propagate intra-simulation signals. Note that
+        // check_nstglobalcomm has the responsibility for
+        // choosing the value of nstglobalcomm which satisfies
+        // the need of the different signallers.
+        const bool doIntraSimSignal = true;
+        // Disable functionality
+        const bool doInterSimSignal = false;
+
+        auto       signaller = std::make_shared<SimulationSignaller>(
+                    &signals_, cr_, nullptr, doInterSimSignal, doIntraSimSignal);
+
+        (*registerRunFunction)(
+                std::make_unique<SimulatorRunFunction>(
+                        [this, step, flags, signaller = std::move(signaller)]() {
+                            compute(step, flags, signaller.get(), true);
+                        }));
+    }
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+void ComputeGlobalsElement<algorithm>::compute(
+        gmx::Step step, unsigned int flags,
+        SimulationSignaller *signaller,
+        bool useLastBox, bool isInit)
+{
+    auto x       = as_rvec_array(statePropagatorData_->positionsView().paddedArrayRef().data());
+    auto v       = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
+    auto box     = statePropagatorData_->box();
+    auto lastbox = useLastBox ? statePropagatorData_->previousBox() : statePropagatorData_->box();
+    real lambda  = 0;
+
+    compute_globals(gstat_, cr_, inputrec_, fr_,
+                    energyElement_->ekindata(),
+                    x, v, box, lambda,
+                    mdAtoms_->mdatoms(), nrnb_, &vcm_,
+                    step != -1 ? wcycle_ : nullptr,
+                    energyElement_->enerdata(),
+                    energyElement_->forceVirial(step),
+                    energyElement_->constraintVirial(step),
+                    energyElement_->totalVirial(step),
+                    energyElement_->pressure(step),
+                    energyElement_->muTot(),
+                    constr_, signaller, lastbox,
+                    &totalNumberOfBondedInteractions_, &needToSumEkinhOld_, flags);
+    checkNumberOfBondedInteractions(mdlog_, cr_, totalNumberOfBondedInteractions_,
+                                    top_global_, localTopology_, x, box,
+                                    &shouldCheckNumberOfBondedInteractions_);
+    if (flags & CGLO_STOPCM && !isInit)
+    {
+        process_and_stopcm_grp(fplog_, &vcm_, *mdAtoms_->mdatoms(), x, v);
+        inc_nrnb(nrnb_, eNR_STOPCM, mdAtoms_->mdatoms()->homenr);
+    }
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+CheckBondedInteractionsCallbackPtr
+ComputeGlobalsElement<algorithm>::getCheckNumberOfBondedInteractionsCallback()
+{
+    return std::make_unique<CheckBondedInteractionsCallback>(
+            [this](){needToCheckNumberOfBondedInteractions(); });
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+void ComputeGlobalsElement<algorithm>::needToCheckNumberOfBondedInteractions()
+{
+    shouldCheckNumberOfBondedInteractions_ = true;
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+void ComputeGlobalsElement<algorithm>::setTopology(const gmx_localtop_t *top)
+{
+    localTopology_ = top;
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+SignallerCallbackPtr ComputeGlobalsElement<algorithm>::
+    registerEnergyCallback(EnergySignallerEvent event)
+{
+    if (event == EnergySignallerEvent::energyCalculationStep)
+    {
+        return std::make_unique<SignallerCallback>(
+                [this](Step step, Time)
+                {energyReductionStep_ = step; });
+    }
+    if (event == EnergySignallerEvent::virialCalculationStep)
+    {
+        return std::make_unique<SignallerCallback>(
+                [this](Step step, Time){virialReductionStep_ = step; });
+    }
+    return nullptr;
+
+}
+
+template <ComputeGlobalsAlgorithm algorithm>
+SignallerCallbackPtr ComputeGlobalsElement<algorithm>::
+    registerTrajectorySignallerCallback(TrajectoryEvent event)
+{
+    if (event == TrajectoryEvent::energyWritingStep)
+    {
+        return std::make_unique<SignallerCallback>(
+                [this](Step step, Time)
+                {energyReductionStep_ = step; });
+    }
+    return nullptr;
+}
+
+//! Explicit template instantiation
+//! @{
+template class ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>;
+template class ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerletAtFullTimeStep>;
+template class ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerletAfterCoordinateUpdate>;
+//! @}
+}  // namespace gmx
diff --git a/src/gromacs/modularsimulator/computeglobalselement.h b/src/gromacs/modularsimulator/computeglobalselement.h
new file mode 100644 (file)
index 0000000..afd8e90
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal
+ * \brief Declares the global reduction element for the modular simulator
+ *
+ * \author Pascal Merz <pascal.merz@me.com>
+ * \ingroup module_modularsimulator
+ */
+
+#ifndef GMX_MODULARSIMULATOR_COMPUTEGLOBALSELEMENT_H
+#define GMX_MODULARSIMULATOR_COMPUTEGLOBALSELEMENT_H
+
+#include "gromacs/mdlib/simulationsignal.h"
+#include "gromacs/mdlib/vcm.h"
+
+#include "energyelement.h"
+#include "modularsimulatorinterfaces.h"
+#include "statepropagatordata.h"
+#include "topologyholder.h"
+
+struct gmx_global_stat;
+struct gmx_wallcycle;
+struct t_nrnb;
+
+namespace gmx
+{
+class MDAtoms;
+class MDLogger;
+
+//! \addtogroup module_modularsimulator
+//! \{
+
+//! The different global reduction schemes we know about
+enum class ComputeGlobalsAlgorithm
+{
+    LeapFrog,
+    VelocityVerletAtFullTimeStep,
+    VelocityVerletAfterCoordinateUpdate
+};
+
+//! The function type allowing to request a check of the number of bonded interactions
+typedef std::function<void()> CheckBondedInteractionsCallback;
+//! Pointer to the function type allowing to request a check of the number of bonded interactions
+typedef std::unique_ptr<CheckBondedInteractionsCallback> CheckBondedInteractionsCallbackPtr;
+
+/*! \libinternal
+ * \brief Encapsulate the calls to `compute_globals`
+ *
+ * This element aims at offering an interface to the legacy
+ * implementation which is compatible with the new simulator approach.
+ *
+ * The element comes in 3 (templated) flavors: the leap-frog case, the first
+ * call during a velocity-verlet integrator, and the second call during a
+ * velocity-verlet integrator. In velocity verlet, the state at the beginning
+ * of the step corresponds to
+ *     positions at time t
+ *     velocities at time t - dt/2
+ * The first velocity propagation (+dt/2) therefore actually corresponds to the
+ * previous step, bringing the state to the full timestep at time t. Most global
+ * reductions are made at this point. The second call is needed to correct the
+ * constraint virial after the second propagation of velocities (+dt/2) and of
+ * the positions (+dt).
+ *
+ * @tparam algorithm  The global reduction scheme
+ */
+template <ComputeGlobalsAlgorithm algorithm>
+class ComputeGlobalsElement final :
+    public                  ISimulatorElement,
+    public                  IEnergySignallerClient,
+    public                  ITrajectorySignallerClient,
+    public                  ITopologyHolderClient
+{
+    public:
+        //! Constructor
+        ComputeGlobalsElement(
+            StatePropagatorData *statePropagatorData,
+            EnergyElement       *energyElement,
+            int                  nstglobalcomm,
+            FILE                *fplog,
+            const MDLogger      &mdlog,
+            t_commrec           *cr,
+            t_inputrec          *inputrec,
+            const MDAtoms       *mdAtoms,
+            t_nrnb              *nrnb,
+            gmx_wallcycle       *wcycle,
+            t_forcerec          *fr,
+            const gmx_mtop_t    *global_top,
+            Constraints         *constr);
+
+        //! Destructor
+        ~ComputeGlobalsElement() override;
+
+        /*! \brief Element setup - first call to compute_globals
+         *
+         */
+        void elementSetup() override;
+
+        /*! \brief Register run function for step / time
+         *
+         * This registers the call to compute_globals when needed.
+         *
+         * @param step                 The step number
+         * @param time                 The time
+         * @param registerRunFunction  Function allowing to register a run function
+         */
+        void scheduleTask(
+            Step step, Time time,
+            const RegisterRunFunctionPtr &registerRunFunction) override;
+
+        //! Get callback to request checking of bonded interactions
+        CheckBondedInteractionsCallbackPtr getCheckNumberOfBondedInteractionsCallback();
+
+        //! No element teardown needed
+        void elementTeardown() override {}
+
+    private:
+        //! ITopologyClient implementation
+        void setTopology(const gmx_localtop_t *top) override;
+        //! IEnergySignallerClient implementation
+        SignallerCallbackPtr registerEnergyCallback(EnergySignallerEvent event) override;
+        //! ITrajectorySignallerClient implementation
+        SignallerCallbackPtr registerTrajectorySignallerCallback(TrajectoryEvent event) override;
+        //! The compute_globals call
+        void compute(
+            Step step, unsigned int flags,
+            SimulationSignaller *signaller, bool useLastBox,
+            bool isInit = false);
+
+        //! Next step at which energy needs to be reduced
+        Step energyReductionStep_;
+        //! Next step at which virial needs to be reduced
+        Step virialReductionStep_;
+
+        //! Whether center of mass motion stopping is enabled
+        const bool                           doStopCM_;
+        //! Number of steps after which center of mass motion is removed
+        int                                  nstcomm_;
+        //! Compute globals communication period
+        int                                  nstglobalcomm_;
+        //! The initial step (only used for VV)
+        const Step                           initStep_;
+        //! A dummy signaller (used for setup and VV)
+        std::unique_ptr<SimulationSignaller> nullSignaller_;
+
+        /*! \brief Check that DD doesn't miss bonded interactions
+         *
+         * Domain decomposition could incorrectly miss a bonded
+         * interaction, but checking for that requires a global
+         * communication stage, which does not otherwise happen in DD
+         * code. So we do that alongside the first global energy reduction
+         * after a new DD is made. These variables handle whether the
+         * check happens, and the result it returns.
+         */
+        //! @{
+        int  totalNumberOfBondedInteractions_;
+        bool shouldCheckNumberOfBondedInteractions_;
+        //! @}
+
+        /*! \brief Signal to ComputeGlobalsElement that it should check for DD errors
+         *
+         * Note that this should really be the responsibility of the DD element.
+         * MDLogger, global and local topology are only needed due to the call to
+         * checkNumberOfBondedInteractions(...).
+         *
+         * The DD element should have a single variable which gets reduced, and then
+         * be responsible for the checking after a global reduction has happened.
+         * This would, however, require a new approach for the compute_globals calls,
+         * which is not yet implemented. So for now, we're leaving this here.
+         */
+        void needToCheckNumberOfBondedInteractions();
+
+        //! Whether we need to sum ekinh_old at a later run
+        bool needToSumEkinhOld_;
+
+        //! Global reduction struct
+        gmx_global_stat *gstat_;
+
+        //! Pointer to the microstate
+        StatePropagatorData  *statePropagatorData_;
+        //! Pointer to the energy element (needed for the tensors and mu_tot)
+        EnergyElement        *energyElement_;
+        //! Pointer to the local topology (only needed for checkNumberOfBondedInteractions)
+        const gmx_localtop_t *localTopology_;
+
+        //! Center of mass motion removal
+        t_vcm             vcm_;
+        //! Signals
+        SimulationSignals signals_;
+
+        // Access to ISimulator data
+        //! Handles logging.
+        FILE             *fplog_;
+        //! Handles logging.
+        const MDLogger   &mdlog_;
+        //! Handles communication.
+        t_commrec        *cr_;
+        //! Contains user input mdp options.
+        t_inputrec       *inputrec_;
+        //! Full system topology - only needed for checkNumberOfBondedInteractions.
+        const gmx_mtop_t *top_global_;
+        //! Atom parameters for this domain.
+        const MDAtoms    *mdAtoms_;
+        //! Handles constraints.
+        Constraints      *constr_;
+        //! Manages flop accounting.
+        t_nrnb           *nrnb_;
+        //! Manages wall cycle accounting.
+        gmx_wallcycle    *wcycle_;
+        //! Parameters for force calculations.
+        t_forcerec       *fr_;
+};
+
+//! \}
+}      // namespace gmx
+
+#endif // GMX_MODULARSIMULATOR_COMPUTEGLOBALSELEMENT_H