Clarify connection of temperature / pressure coupling and propagators
authorPascal Merz <pascal.merz@me.com>
Fri, 2 Apr 2021 00:53:32 +0000 (00:53 +0000)
committerPascal Merz <pascal.merz@me.com>
Fri, 2 Apr 2021 00:53:32 +0000 (00:53 +0000)
Temperature and pressure coupling and propagators are linked, as most
thermostats and barostats apply some type of scaling to positions and
/ or velocities. The temperature and pressure coupling objects must
therefore be linked to the propagators to properly function.

The current implementation did not allow for much flexibility, as it
only allowed propagators to decide whether to connect to a thermostat
or barostat or not. To allow for more complex algorithms, more
flexibility is required. To that end, this change introduces a
PropagatorTag object, which tags the propagators, and allows the
temperature and pressure coupling objects to pick which propagator to
act on. Additionally, this moves the responsibility of connecting to
the coupling algorithm rather than the propagator, which makes more
sense conceptually.

Refs #3423

docs/doxygen/lib/modularsimulator.md
src/gromacs/modularsimulator/modularsimulator.cpp
src/gromacs/modularsimulator/modularsimulatorinterfaces.h
src/gromacs/modularsimulator/parrinellorahmanbarostat.cpp
src/gromacs/modularsimulator/parrinellorahmanbarostat.h
src/gromacs/modularsimulator/propagator.cpp
src/gromacs/modularsimulator/propagator.h
src/gromacs/modularsimulator/velocityscalingtemperaturecoupling.cpp
src/gromacs/modularsimulator/velocityscalingtemperaturecoupling.h

index 108e127feaa904432d897cfc0121b3acabe2c11a..d4776d3ec43b17ba3fb6fb167dbc751df60f8a9a 100644 (file)
@@ -202,11 +202,12 @@ the simulator algorithm.
             builder->add<StatePropagatorData::Element>();
             if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale)
             {
-                builder->add<VRescaleThermostat>(-1, VRescaleThermostatUseFullStepKE::No);
+                builder->add<VRescaleThermostat>(-1,
+                                                 VRescaleThermostatUseFullStepKE::No,
+                                                 PropagatorTag("LeapFrogPropagator"));
             }
-            builder->add<Propagator<IntegrationStep::LeapFrog>>(legacySimulatorData_->inputrec->delta_t,
-                                                                RegisterWithThermostat::True,
-                                                                RegisterWithBarostat::True);
+            builder->add<Propagator<IntegrationStep::LeapFrog>>(PropagatorTag("LeapFrogPropagator"),
+                                                                legacySimulatorData_->inputrec->delta_t);
             if (legacySimulatorData_->constr)
             {
                 builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
@@ -216,7 +217,7 @@ the simulator algorithm.
             builder->add<EnergyData::Element>();
             if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
             {
-                builder->add<ParrinelloRahmanBarostat>(-1);
+                builder->add<ParrinelloRahmanBarostat>(-1, PropagatorTag("LeapFrogPropagator"));
             }
         }
     }
@@ -545,7 +546,15 @@ Currently, the (templated) implementation covers four cases:
     time step of PositionsOnly.
 
 The propagators also allow to implement temperature and pressure coupling
-schemes by offering (templated) scaling of the velocities.
+schemes by offering (templated) scaling of the velocities. In order to
+link temperature / pressure coupling objects to the propagators, the
+propagator objects have a tag (of strong type `PropagatorTag`). The
+temperature and pressure coupling objects can then connect to the
+matching propagator by comparing their target tag to the different
+propagators. Giving the propagators their tags and informing the
+temperature and pressure coupling algorithms which propagator they are
+connecting to is in the responsibility of the simulation algorithm
+builder.
 
 #### `CompositeSimulatorElement`
 The composite simulator element takes a list of elements and implements
index 5bb98e9afa0da9e49858fe53554bdb80e5c039c9..0f079dc1ce9b856a669661f7d649bbe5e7cfa5ac 100644 (file)
@@ -114,12 +114,13 @@ void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder*
         if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale
             || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen)
         {
-            builder->add<VelocityScalingTemperatureCoupling>(
-                    -1, UseFullStepKE::No, ReportPreviousStepConservedEnergy::No);
+            builder->add<VelocityScalingTemperatureCoupling>(-1,
+                                                             UseFullStepKE::No,
+                                                             ReportPreviousStepConservedEnergy::No,
+                                                             PropagatorTag("LeapFrogPropagator"));
         }
-        builder->add<Propagator<IntegrationStep::LeapFrog>>(legacySimulatorData_->inputrec->delta_t,
-                                                            RegisterWithThermostat::True,
-                                                            RegisterWithBarostat::True);
+        builder->add<Propagator<IntegrationStep::LeapFrog>>(
+                PropagatorTag("LeapFrogPropagator"), legacySimulatorData_->inputrec->delta_t);
         if (legacySimulatorData_->constr)
         {
             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
@@ -128,7 +129,7 @@ void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder*
         builder->add<EnergyData::Element>();
         if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
         {
-            builder->add<ParrinelloRahmanBarostat>(-1);
+            builder->add<ParrinelloRahmanBarostat>(-1, PropagatorTag("LeapFrogPropagator"));
         }
     }
     else if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::VV)
@@ -136,9 +137,7 @@ void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder*
         // The velocity verlet integration algorithm
         builder->add<ForceElement>();
         builder->add<Propagator<IntegrationStep::VelocitiesOnly>>(
-                0.5 * legacySimulatorData_->inputrec->delta_t,
-                RegisterWithThermostat::False,
-                RegisterWithBarostat::True);
+                PropagatorTag("VelocityHalfStep"), 0.5 * legacySimulatorData_->inputrec->delta_t);
         if (legacySimulatorData_->constr)
         {
             builder->add<ConstraintsElement<ConstraintVariable::Velocities>>();
@@ -149,12 +148,13 @@ void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder*
             || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen)
         {
             builder->add<VelocityScalingTemperatureCoupling>(
-                    0, UseFullStepKE::Yes, ReportPreviousStepConservedEnergy::Yes);
+                    0,
+                    UseFullStepKE::Yes,
+                    ReportPreviousStepConservedEnergy::Yes,
+                    PropagatorTag("VelocityHalfAndPositionFullStep"));
         }
         builder->add<Propagator<IntegrationStep::VelocityVerletPositionsAndVelocities>>(
-                legacySimulatorData_->inputrec->delta_t,
-                RegisterWithThermostat::True,
-                RegisterWithBarostat::False);
+                PropagatorTag("VelocityHalfAndPositionFullStep"), legacySimulatorData_->inputrec->delta_t);
         if (legacySimulatorData_->constr)
         {
             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
@@ -163,7 +163,7 @@ void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder*
         builder->add<EnergyData::Element>();
         if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
         {
-            builder->add<ParrinelloRahmanBarostat>(-1);
+            builder->add<ParrinelloRahmanBarostat>(-1, PropagatorTag("VelocityHalfStep"));
         }
     }
     else
index 0ed26a68fbad13478689d7c650a75d439f9b2a14..2e8c79f1df6fed09a04b47dafe443a9855d0ed52 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, 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.
@@ -454,6 +454,25 @@ enum class ModularSimulatorBuilderState
 //! Generic callback to the propagator
 typedef std::function<void(Step)> PropagatorCallback;
 
+/*! \internal
+ * \brief Strong type used to name propagators
+ */
+struct PropagatorTag
+{
+    //! Explicit constructor
+    explicit PropagatorTag(std::string_view name) : name_(name) {}
+    //! Can be used as string
+    operator const std::string&() const { return name_; }
+    //! Equality operator
+    bool operator==(const PropagatorTag& other) const { return name_ == other.name_; }
+    //! Inequality operator
+    bool operator!=(const PropagatorTag& other) const { return name_ != other.name_; }
+
+private:
+    //! The name of the propagator
+    const std::string name_;
+};
+
 /*! \internal
  * \brief Information needed to connect a propagator to a thermostat
  */
@@ -465,6 +484,8 @@ struct PropagatorThermostatConnection
     std::function<ArrayRef<real>()> getViewOnVelocityScaling;
     //! Function variable for callback.
     std::function<PropagatorCallback()> getVelocityScalingCallback;
+    //! The tag of the creating propagator
+    PropagatorTag tag;
 };
 
 /*! \internal
@@ -476,6 +497,8 @@ struct PropagatorBarostatConnection
     std::function<ArrayRef<rvec>()> getViewOnPRScalingMatrix;
     //! Function variable for callback.
     std::function<PropagatorCallback()> getPRScalingCallback;
+    //! The tag of the creating propagator
+    PropagatorTag tag;
 };
 
 //! /}
index 9b35825a6041451f1902f486d3ae8383ab85c6ac..d01e6fd4d82e2d5355329fa59c306edc8763de6b 100644 (file)
@@ -88,10 +88,14 @@ ParrinelloRahmanBarostat::ParrinelloRahmanBarostat(int                  nstpcoup
     energyData->setParrinelloRahamnBarostat(this);
 }
 
-void ParrinelloRahmanBarostat::connectWithPropagator(const PropagatorBarostatConnection& connectionData)
+void ParrinelloRahmanBarostat::connectWithMatchingPropagator(const PropagatorBarostatConnection& connectionData,
+                                                             const PropagatorTag& propagatorTag)
 {
-    scalingTensor_      = connectionData.getViewOnPRScalingMatrix();
-    propagatorCallback_ = connectionData.getPRScalingCallback();
+    if (connectionData.tag == propagatorTag)
+    {
+        scalingTensor_      = connectionData.getViewOnPRScalingMatrix();
+        propagatorCallback_ = connectionData.getPRScalingCallback();
+    }
 }
 
 void ParrinelloRahmanBarostat::scheduleTask(Step step,
@@ -161,7 +165,8 @@ void ParrinelloRahmanBarostat::elementSetup()
         throw MissingElementConnectionError(
                 "Parrinello-Rahman barostat was not connected to a propagator.\n"
                 "Connection to a propagator element is needed to scale the velocities.\n"
-                "Use connectWithPropagator(...) before building the ModularSimulatorAlgorithm "
+                "Use connectWithMatchingPropagator(...) before building the "
+                "ModularSimulatorAlgorithm "
                 "object.");
     }
 
@@ -300,7 +305,8 @@ ISimulatorElement* ParrinelloRahmanBarostat::getElementPointerImpl(
         EnergyData*                             energyData,
         FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
         GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
-        int                                   offset)
+        int                                   offset,
+        const PropagatorTag&                  propagatorTag)
 {
     auto* element  = builderHelper->storeElement(std::make_unique<ParrinelloRahmanBarostat>(
             legacySimulatorData->inputrec->nstpcouple,
@@ -313,8 +319,8 @@ ISimulatorElement* ParrinelloRahmanBarostat::getElementPointerImpl(
             legacySimulatorData->inputrec,
             legacySimulatorData->mdAtoms));
     auto* barostat = static_cast<ParrinelloRahmanBarostat*>(element);
-    builderHelper->registerBarostat([barostat](const PropagatorBarostatConnection& connection) {
-        barostat->connectWithPropagator(connection);
+    builderHelper->registerBarostat([barostat, propagatorTag](const PropagatorBarostatConnection& connection) {
+        barostat->connectWithMatchingPropagator(connection, propagatorTag);
     });
     return element;
 }
index 77ede5316557e06407ec222c53b6426d77e99aef..ee11ececf122107112c145dcf7850548af60f408 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, 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.
@@ -103,7 +103,8 @@ public:
     [[nodiscard]] real conservedEnergyContribution() const;
 
     //! Connect this to propagator
-    void connectWithPropagator(const PropagatorBarostatConnection& connectionData);
+    void connectWithMatchingPropagator(const PropagatorBarostatConnection& connectionData,
+                                       const PropagatorTag&                propagatorTag);
 
     //! ICheckpointHelperClient write checkpoint implementation
     void saveCheckpointState(std::optional<WriteCheckpointData> checkpointData, const t_commrec* cr) override;
@@ -120,17 +121,20 @@ public:
      * \param energyData  Pointer to the \c EnergyData object
      * \param freeEnergyPerturbationData  Pointer to the \c FreeEnergyPerturbationData object
      * \param globalCommunicationHelper  Pointer to the \c GlobalCommunicationHelper object
+     * \param propagatorTag  Tag of the propagator to connect to
      * \param offset  The step offset at which the barostat is applied
      *
      * \return  Pointer to the element to be added. Element needs to have been stored using \c storeElement
      */
-    static ISimulatorElement* getElementPointerImpl(LegacySimulatorData* legacySimulatorData,
-                                                    ModularSimulatorAlgorithmBuilderHelper* builderHelper,
-                                                    StatePropagatorData*        statePropagatorData,
-                                                    EnergyData*                 energyData,
-                                                    FreeEnergyPerturbationData* freeEnergyPerturbationData,
-                                                    GlobalCommunicationHelper* globalCommunicationHelper,
-                                                    int                        offset);
+    static ISimulatorElement*
+    getElementPointerImpl(LegacySimulatorData*                    legacySimulatorData,
+                          ModularSimulatorAlgorithmBuilderHelper* builderHelper,
+                          StatePropagatorData*                    statePropagatorData,
+                          EnergyData*                             energyData,
+                          FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
+                          GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
+                          int                                   offset,
+                          const PropagatorTag&                  propagatorTag);
 
 private:
     //! The frequency at which the barostat is applied
index de13bbf1a0dab8451683927922a0d2b81b038e28..406438aedcea4756d81f3aa34af7a43a7922f0ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, 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.
@@ -526,27 +526,21 @@ ISimulatorElement* Propagator<algorithm>::getElementPointerImpl(
         EnergyData gmx_unused*     energyData,
         FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
         GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
-        double                                timestep,
-        RegisterWithThermostat                registerWithThermostat,
-        RegisterWithBarostat                  registerWithBarostat)
+        const PropagatorTag&                  propagatorTag,
+        double                                timestep)
 {
-    auto* element = builderHelper->storeElement(std::make_unique<Propagator<algorithm>>(
+    auto* element    = builderHelper->storeElement(std::make_unique<Propagator<algorithm>>(
             timestep, statePropagatorData, legacySimulatorData->mdAtoms, legacySimulatorData->wcycle));
-    if (registerWithThermostat == RegisterWithThermostat::True)
-    {
-        auto* propagator = static_cast<Propagator<algorithm>*>(element);
-        builderHelper->registerWithThermostat(
-                { [propagator](int num) { propagator->setNumVelocityScalingVariables(num); },
-                  [propagator]() { return propagator->viewOnVelocityScaling(); },
-                  [propagator]() { return propagator->velocityScalingCallback(); } });
-    }
-    if (registerWithBarostat == RegisterWithBarostat::True)
-    {
-        auto* propagator = static_cast<Propagator<algorithm>*>(element);
-        builderHelper->registerWithBarostat(
-                { [propagator]() { return propagator->viewOnPRScalingMatrix(); },
-                  [propagator]() { return propagator->prScalingCallback(); } });
-    }
+    auto* propagator = static_cast<Propagator<algorithm>*>(element);
+    builderHelper->registerWithThermostat(
+            { [propagator](int num) { propagator->setNumVelocityScalingVariables(num); },
+              [propagator]() { return propagator->viewOnVelocityScaling(); },
+              [propagator]() { return propagator->velocityScalingCallback(); },
+              propagatorTag });
+    builderHelper->registerWithBarostat(
+            { [propagator]() { return propagator->viewOnPRScalingMatrix(); },
+              [propagator]() { return propagator->prScalingCallback(); },
+              propagatorTag });
     return element;
 }
 
index df505c5f7fc94aac0b214a9cbe6b7ba45dde8404..ae480513a48e904a084d06e9a85dd0d8717aa535 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, 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.
@@ -67,19 +67,6 @@ class StatePropagatorData;
 //! \addtogroup module_modularsimulator
 //! \{
 
-//! Whether built propagator should be registered with thermostat
-enum class RegisterWithThermostat
-{
-    True,
-    False
-};
-//! Whether built propagator should be registered with barostat
-enum class RegisterWithBarostat
-{
-    True,
-    False
-};
-
 /*! \brief The different integration types we know about
  *
  * PositionsOnly:
@@ -174,9 +161,8 @@ public:
      * \param energyData  Pointer to the \c EnergyData object
      * \param freeEnergyPerturbationData  Pointer to the \c FreeEnergyPerturbationData object
      * \param globalCommunicationHelper  Pointer to the \c GlobalCommunicationHelper object
+     * \param propagatorTag  The name of the propagator to simplify connection
      * \param timestep  The time step the propagator uses
-     * \param registerWithThermostat  Whether this propagator should be registered with the thermostat
-     * \param registerWithBarostat  Whether this propagator should be registered with the barostat
      *
      * \return  Pointer to the element to be added. Element needs to have been stored using \c storeElement
      */
@@ -186,9 +172,8 @@ public:
                                                     EnergyData*                 energyData,
                                                     FreeEnergyPerturbationData* freeEnergyPerturbationData,
                                                     GlobalCommunicationHelper* globalCommunicationHelper,
-                                                    double                     timestep,
-                                                    RegisterWithThermostat registerWithThermostat,
-                                                    RegisterWithBarostat   registerWithBarostat);
+                                                    const PropagatorTag&       propagatorTag,
+                                                    double                     timestep);
 
 private:
     //! The actual propagation
index 402b13a954b1361c83e5d818c57c74a380a6adf3..ac467f2717405709e346b2df18b366f41ed26bf0 100644 (file)
@@ -316,10 +316,14 @@ VelocityScalingTemperatureCoupling::VelocityScalingTemperatureCoupling(
     }
 }
 
-void VelocityScalingTemperatureCoupling::connectWithPropagator(const PropagatorThermostatConnection& connectionData)
+void VelocityScalingTemperatureCoupling::connectWithMatchingPropagator(const PropagatorThermostatConnection& connectionData,
+                                                                       const PropagatorTag& propagatorTag)
 {
-    temperatureCouplingImpl_->connectWithPropagator(connectionData, numTemperatureGroups_);
-    propagatorCallback_ = connectionData.getVelocityScalingCallback();
+    if (connectionData.tag == propagatorTag)
+    {
+        temperatureCouplingImpl_->connectWithPropagator(connectionData, numTemperatureGroups_);
+        propagatorCallback_ = connectionData.getVelocityScalingCallback();
+    }
 }
 
 void VelocityScalingTemperatureCoupling::elementSetup()
@@ -329,7 +333,8 @@ void VelocityScalingTemperatureCoupling::elementSetup()
         throw MissingElementConnectionError(
                 "Velocity scaling temperature coupling was not connected to a propagator.\n"
                 "Connection to a propagator element is needed to scale the velocities.\n"
-                "Use connectWithPropagator(...) before building the ModularSimulatorAlgorithm "
+                "Use connectWithMatchingPropagator(...) before building the "
+                "ModularSimulatorAlgorithm "
                 "object.");
     }
 }
@@ -466,12 +471,13 @@ ISimulatorElement* VelocityScalingTemperatureCoupling::getElementPointerImpl(
         LegacySimulatorData*                    legacySimulatorData,
         ModularSimulatorAlgorithmBuilderHelper* builderHelper,
         StatePropagatorData gmx_unused* statePropagatorData,
-        EnergyData gmx_unused*     energyData,
+        EnergyData*                     energyData,
         FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
         GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
         int                                   offset,
         UseFullStepKE                         useFullStepKE,
-        ReportPreviousStepConservedEnergy     reportPreviousStepConservedEnergy)
+        ReportPreviousStepConservedEnergy     reportPreviousStepConservedEnergy,
+        const PropagatorTag&                  propagatorTag)
 {
     // Element is now owned by the caller of this method, who will handle lifetime (see ModularSimulatorAlgorithm)
     auto* element = builderHelper->storeElement(std::make_unique<VelocityScalingTemperatureCoupling>(
@@ -489,9 +495,10 @@ ISimulatorElement* VelocityScalingTemperatureCoupling::getElementPointerImpl(
             legacySimulatorData->inputrec->etc));
     auto* thermostat = static_cast<VelocityScalingTemperatureCoupling*>(element);
     // Capturing pointer is safe because lifetime is handled by caller
-    builderHelper->registerThermostat([thermostat](const PropagatorThermostatConnection& connection) {
-        thermostat->connectWithPropagator(connection);
-    });
+    builderHelper->registerThermostat(
+            [thermostat, propagatorTag](const PropagatorThermostatConnection& connection) {
+                thermostat->connectWithMatchingPropagator(connection, propagatorTag);
+            });
     return element;
 }
 
index 68daad8497596225b332e73e73e9f388acce9581..4b8947c2264507f0368d9a4969f5c0e681f22d81 100644 (file)
@@ -120,7 +120,8 @@ public:
     [[nodiscard]] real conservedEnergyContribution() const;
 
     //! Connect this to propagator
-    void connectWithPropagator(const PropagatorThermostatConnection& connectionData);
+    void connectWithMatchingPropagator(const PropagatorThermostatConnection& connectionData,
+                                       const PropagatorTag&                  propagatorTag);
 
     //! ICheckpointHelperClient write checkpoint implementation
     void saveCheckpointState(std::optional<WriteCheckpointData> checkpointData, const t_commrec* cr) override;
@@ -137,6 +138,7 @@ public:
      * \param energyData  Pointer to the \c EnergyData object
      * \param freeEnergyPerturbationData  Pointer to the \c FreeEnergyPerturbationData object
      * \param globalCommunicationHelper  Pointer to the \c GlobalCommunicationHelper object
+     * \param propagatorTag  Tag of the propagator to connect to
      * \param offset  The step offset at which the thermostat is applied
      * \param useFullStepKE  Whether full step or half step KE is used
      * \param reportPreviousStepConservedEnergy  Report the previous or the current step conserved energy
@@ -152,7 +154,8 @@ public:
                           GlobalCommunicationHelper*              globalCommunicationHelper,
                           int                                     offset,
                           UseFullStepKE                           useFullStepKE,
-                          ReportPreviousStepConservedEnergy reportPreviousStepConservedEnergy);
+                          ReportPreviousStepConservedEnergy       reportPreviousStepConservedEnergy,
+                          const PropagatorTag&                    propagatorTag);
 
 private:
     //! The frequency at which the thermostat is applied