Add function calls to MdModules to sign up for notifications
authorChristian Blau <cblau@gwdg.de>
Tue, 21 Jan 2020 10:05:03 +0000 (11:05 +0100)
committerChristian Blau <cblau@gwdg.de>
Thu, 5 Mar 2020 10:00:21 +0000 (11:00 +0100)
Allow MdModules to sign up to notifications after they know their own
options. This makes it possible that modules only get called back when
they need to and not by default and skips the if(active) logic in
functions that are called back in favour of not subscribing to the
notifications to begin with.

refs #3076

Change-Id: Ib95c1f734f919805c661ac6f6451af5da8187eec

13 files changed:
src/gromacs/applied_forces/densityfitting.cpp
src/gromacs/applied_forces/densityfitting.h
src/gromacs/applied_forces/electricfield.cpp
src/gromacs/applied_forces/tests/densityfitting.cpp
src/gromacs/gmxpreprocess/grompp.cpp
src/gromacs/imd/imd.cpp
src/gromacs/mdrun/mdmodules.cpp
src/gromacs/mdrun/mdmodules.h
src/gromacs/mdrun/runner.cpp
src/gromacs/mdtypes/imdmodule.h
src/gromacs/restraint/restraintmdmodule.cpp
src/gromacs/restraint/restraintmdmodule.h
src/gromacs/swap/swapcoords.cpp

index 5a134e4327ab0a1d9c929d5511a895cb07dae96f..2889e61a5072eabe85e1f4a13fa11f2c8a34ec45 100644 (file)
@@ -223,8 +223,12 @@ private:
  */
 class DensityFitting final : public IMDModule
 {
+
 public:
-    /*! \brief Construct the density fitting module.
+    //! Construct the density fitting module.
+    explicit DensityFitting() = default;
+
+    /*! \brief Request to be notified during pre-processing.
      *
      * \param[in] notifier allows the module to subscribe to notifications from MdModules.
      *
@@ -234,25 +238,18 @@ public:
      *   - storing its internal parameters in a tpr file by writing to a
      *     key-value-tree during pre-processing by a function taking a
      *     KeyValueTreeObjectBuilder as parameter
-     *   - reading its internal parameters from a key-value-tree during
-     *     simulation setup by taking a const KeyValueTreeObject & parameter
-     *   - constructing local atom sets in the simulation parameter setup
-     *     by taking a LocalAtomSetManager * as parameter
-     *   - the type of periodic boundary conditions that are used
-     *     by taking a PeriodicBoundaryConditionType as parameter
-     *   - the writing of checkpoint data
-     *     by taking a MdModulesWriteCheckpointData as parameter
-     *   - the reading of checkpoint data
-     *     by taking a MdModulesCheckpointReadingDataOnMaster as parameter
-     *   - the broadcasting of checkpoint data
-     *     by taking MdModulesCheckpointReadingBroadcast as parameter
      */
-    explicit DensityFitting(MdModulesNotifier* notifier)
+    void subscribeToPreProcessingNotifications(MdModulesNotifier* notifier) override
     {
         // Callbacks for several kinds of MdModuleNotification are created
         // and subscribed, and will be dispatched correctly at run time
         // based on the type of the parameter required by the lambda.
 
+        if (!densityFittingOptions_.active())
+        {
+            return;
+        }
+
         // Setting the atom group indices from index group string
         const auto setFitGroupIndicesFunction = [this](const IndexGroupsAndNames& indexGroupsAndNames) {
             densityFittingOptions_.setFitGroupIndices(indexGroupsAndNames);
@@ -265,18 +262,41 @@ public:
         };
         notifier->preProcessingNotifications_.subscribe(writeInternalParametersFunction);
 
-        // Reading internal parameters during simulation setup
-        const auto readInternalParametersFunction = [this](const KeyValueTreeObject& tree) {
-            densityFittingOptions_.readInternalParametersFromKvt(tree);
-        };
-        notifier->simulationSetupNotifications_.subscribe(readInternalParametersFunction);
-
         // Checking for consistency with all .mdp options
         const auto checkEnergyCaluclationFrequencyFunction =
                 [this](EnergyCalculationFrequencyErrors* energyCalculationFrequencyErrors) {
                     densityFittingOptions_.checkEnergyCaluclationFrequency(energyCalculationFrequencyErrors);
                 };
         notifier->preProcessingNotifications_.subscribe(checkEnergyCaluclationFrequencyFunction);
+    }
+
+    /*! \brief Request to be notified.
+     * The density fitting code subscribes to these notifications:
+     *   - reading its internal parameters from a key-value-tree during
+     *     simulation setup by taking a const KeyValueTreeObject & parameter
+     *   - constructing local atom sets in the simulation parameter setup
+     *     by taking a LocalAtomSetManager * as parameter
+     *   - the type of periodic boundary conditions that are used
+     *     by taking a PeriodicBoundaryConditionType as parameter
+     *   - the writing of checkpoint data
+     *     by taking a MdModulesWriteCheckpointData as parameter
+     *   - the reading of checkpoint data
+     *     by taking a MdModulesCheckpointReadingDataOnMaster as parameter
+     *   - the broadcasting of checkpoint data
+     *     by taking MdModulesCheckpointReadingBroadcast as parameter
+     */
+    void subscribeToSimulationSetupNotifications(MdModulesNotifier* notifier) override
+    {
+        if (!densityFittingOptions_.active())
+        {
+            return;
+        }
+
+        // Reading internal parameters during simulation setup
+        const auto readInternalParametersFunction = [this](const KeyValueTreeObject& tree) {
+            densityFittingOptions_.readInternalParametersFromKvt(tree);
+        };
+        notifier->simulationSetupNotifications_.subscribe(readInternalParametersFunction);
 
         // constructing local atom sets during simulation setup
         const auto setLocalAtomSetFunction = [this](LocalAtomSetManager* localAtomSetManager) {
@@ -359,12 +379,8 @@ public:
      */
     void constructLocalAtomSet(LocalAtomSetManager* localAtomSetManager)
     {
-        if (densityFittingOptions_.active())
-        {
-            LocalAtomSet atomSet =
-                    localAtomSetManager->add(densityFittingOptions_.buildParameters().indices_);
-            densityFittingSimulationParameters_.setLocalAtomSet(atomSet);
-        }
+        LocalAtomSet atomSet = localAtomSetManager->add(densityFittingOptions_.buildParameters().indices_);
+        densityFittingSimulationParameters_.setLocalAtomSet(atomSet);
     }
 
     /*! \brief Request energy output to energy file during simulation.
@@ -384,21 +400,17 @@ public:
      */
     void writeCheckpointData(MdModulesWriteCheckpointData checkpointWriting)
     {
-        if (densityFittingOptions_.active())
-        {
-            const DensityFittingForceProviderState& state = forceProvider_->stateToCheckpoint();
-            checkpointWriting.builder_.addValue<std::int64_t>(
-                    DensityFittingModuleInfo::name_ + "-stepsSinceLastCalculation",
-                    state.stepsSinceLastCalculation_);
-            checkpointWriting.builder_.addValue<real>(
-                    DensityFittingModuleInfo::name_ + "-adaptiveForceConstantScale",
-                    state.adaptiveForceConstantScale_);
-            KeyValueTreeObjectBuilder exponentialMovingAverageKvtEntry =
-                    checkpointWriting.builder_.addObject(DensityFittingModuleInfo::name_
-                                                         + "-exponentialMovingAverageState");
-            exponentialMovingAverageStateAsKeyValueTree(exponentialMovingAverageKvtEntry,
-                                                        state.exponentialMovingAverageState_);
-        }
+        const DensityFittingForceProviderState& state = forceProvider_->stateToCheckpoint();
+        checkpointWriting.builder_.addValue<std::int64_t>(
+                DensityFittingModuleInfo::name_ + "-stepsSinceLastCalculation",
+                state.stepsSinceLastCalculation_);
+        checkpointWriting.builder_.addValue<real>(
+                DensityFittingModuleInfo::name_ + "-adaptiveForceConstantScale",
+                state.adaptiveForceConstantScale_);
+        KeyValueTreeObjectBuilder exponentialMovingAverageKvtEntry = checkpointWriting.builder_.addObject(
+                DensityFittingModuleInfo::name_ + "-exponentialMovingAverageState");
+        exponentialMovingAverageStateAsKeyValueTree(exponentialMovingAverageKvtEntry,
+                                                    state.exponentialMovingAverageState_);
     }
 
     /*! \brief Read the internal parameters from the checkpoint file on master
@@ -406,34 +418,31 @@ public:
      */
     void readCheckpointDataOnMaster(MdModulesCheckpointReadingDataOnMaster checkpointReading)
     {
-        if (densityFittingOptions_.active())
+        if (checkpointReading.checkpointedData_.keyExists(DensityFittingModuleInfo::name_
+                                                          + "-stepsSinceLastCalculation"))
         {
-            if (checkpointReading.checkpointedData_.keyExists(DensityFittingModuleInfo::name_
-                                                              + "-stepsSinceLastCalculation"))
-            {
-                densityFittingState_.stepsSinceLastCalculation_ =
-                        checkpointReading
-                                .checkpointedData_[DensityFittingModuleInfo::name_
-                                                   + "-stepsSinceLastCalculation"]
-                                .cast<std::int64_t>();
-            }
-            if (checkpointReading.checkpointedData_.keyExists(DensityFittingModuleInfo::name_
-                                                              + "-adaptiveForceConstantScale"))
-            {
-                densityFittingState_.adaptiveForceConstantScale_ =
-                        checkpointReading
-                                .checkpointedData_[DensityFittingModuleInfo::name_
-                                                   + "-adaptiveForceConstantScale"]
-                                .cast<real>();
-            }
-            if (checkpointReading.checkpointedData_.keyExists(DensityFittingModuleInfo::name_
-                                                              + "-exponentialMovingAverageState"))
-            {
-                densityFittingState_.exponentialMovingAverageState_ = exponentialMovingAverageStateFromKeyValueTree(
-                        checkpointReading
-                                .checkpointedData_[DensityFittingModuleInfo::name_ + "-exponentialMovingAverageState"]
-                                .asObject());
-            }
+            densityFittingState_.stepsSinceLastCalculation_ =
+                    checkpointReading
+                            .checkpointedData_[DensityFittingModuleInfo::name_
+                                               + "-stepsSinceLastCalculation"]
+                            .cast<std::int64_t>();
+        }
+        if (checkpointReading.checkpointedData_.keyExists(DensityFittingModuleInfo::name_
+                                                          + "-adaptiveForceConstantScale"))
+        {
+            densityFittingState_.adaptiveForceConstantScale_ =
+                    checkpointReading
+                            .checkpointedData_[DensityFittingModuleInfo::name_
+                                               + "-adaptiveForceConstantScale"]
+                            .cast<real>();
+        }
+        if (checkpointReading.checkpointedData_.keyExists(DensityFittingModuleInfo::name_
+                                                          + "-exponentialMovingAverageState"))
+        {
+            densityFittingState_.exponentialMovingAverageState_ = exponentialMovingAverageStateFromKeyValueTree(
+                    checkpointReading
+                            .checkpointedData_[DensityFittingModuleInfo::name_ + "-exponentialMovingAverageState"]
+                            .asObject());
         }
     }
 
@@ -443,14 +452,11 @@ public:
      */
     void broadcastCheckpointData(MdModulesCheckpointReadingBroadcast checkpointBroadcast)
     {
-        if (densityFittingOptions_.active())
+        if (PAR(&(checkpointBroadcast.cr_)))
         {
-            if (PAR(&(checkpointBroadcast.cr_)))
-            {
-                block_bc(&(checkpointBroadcast.cr_), densityFittingState_.stepsSinceLastCalculation_);
-                block_bc(&(checkpointBroadcast.cr_), densityFittingState_.adaptiveForceConstantScale_);
-                block_bc(&(checkpointBroadcast.cr_), densityFittingState_.exponentialMovingAverageState_);
-            }
+            block_bc(&(checkpointBroadcast.cr_), densityFittingState_.stepsSinceLastCalculation_);
+            block_bc(&(checkpointBroadcast.cr_), densityFittingState_.adaptiveForceConstantScale_);
+            block_bc(&(checkpointBroadcast.cr_), densityFittingState_.exponentialMovingAverageState_);
         }
     }
 
@@ -473,9 +479,9 @@ private:
 
 } // namespace
 
-std::unique_ptr<IMDModule> DensityFittingModuleInfo::create(MdModulesNotifier* notifier)
+std::unique_ptr<IMDModule> DensityFittingModuleInfo::create()
 {
-    return std::make_unique<DensityFitting>(notifier);
+    return std::make_unique<DensityFitting>();
 }
 
 const std::string DensityFittingModuleInfo::name_ = "density-guided-simulation";
index 389e4144c5149f1317b3b9eb23f082e9b94b48fd..6e29a7faa3e4d575f44bd8ae89de2b0d4f811ff0 100644 (file)
@@ -58,7 +58,7 @@ struct DensityFittingModuleInfo
      * Fitting an all-atom structure into an experimental cryo-EM density map is a
      * typical application.
      */
-    static std::unique_ptr<IMDModule> create(MdModulesNotifier* notifier);
+    static std::unique_ptr<IMDModule> create();
     //! The name of the module
     static const std::string name_;
 };
index 5bc278142d330498555d45d9a2f2e26e8992a80d..08c414f5d42c973e06f32387c75079250ef0e397 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020, 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.
@@ -171,6 +171,9 @@ public:
     void calculateForces(const ForceProviderInput& forceProviderInput,
                          ForceProviderOutput*      forceProviderOutput) override;
 
+    void subscribeToSimulationSetupNotifications(MdModulesNotifier* /* notifier */) override {}
+    void subscribeToPreProcessingNotifications(MdModulesNotifier* /* notifier */) override {}
+
 private:
     //! Return whether or not to apply a field
     bool isActive() const;
index 38f3cb0d4c2c4e379fced7ced966b5130abb4fda..bc5ae180d944313633f83cd4b28a8f1b75972757 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, 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.
@@ -94,7 +94,7 @@ public:
     {
         KeyValueTreeObject mdpOptionsTree = mdpValueBuilder_.build();
 
-        densityFittingModule_ = DensityFittingModuleInfo::create(&notifier_);
+        densityFittingModule_ = DensityFittingModuleInfo::create();
 
         // set up options
         Options densityFittingModuleOptions;
@@ -117,7 +117,6 @@ public:
 
 protected:
     KeyValueTreeBuilder        mdpValueBuilder_;
-    MdModulesNotifier          notifier_;
     ForceProviders             densityFittingForces_;
     std::unique_ptr<IMDModule> densityFittingModule_;
 };
index 66d9dbaea8794cd3f54854ea4a1223e26d52b379..f95384d1f818a9dc8f43428aab24462b175295b2 100644 (file)
@@ -1856,6 +1856,11 @@ int gmx_grompp(int argc, char* argv[])
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
 
+    // Now that the MdModules have their options assigned from get_ir, subscribe
+    // to eventual notifications during pre-processing their data
+    mdModules.subscribeToPreProcessingNotifications();
+
+
     if (bVerbose)
     {
         GMX_LOG(logger.info)
index 6126e65fee3b1a9a6780b72b5278a62d52733822..4f54a989d3247e7bb01d664e1aa3007a6623b694 100644 (file)
@@ -325,6 +325,8 @@ class InteractiveMolecularDynamics final : public IMDModule
     IMdpOptionProvider* mdpOptionProvider() override { return nullptr; }
     IMDOutputProvider*  outputProvider() override { return nullptr; }
     void                initForceProviders(ForceProviders* /* forceProviders */) override {}
+    void subscribeToSimulationSetupNotifications(MdModulesNotifier* /* notifier */) override {}
+    void subscribeToPreProcessingNotifications(MdModulesNotifier* /* notifier */) override {}
 };
 
 std::unique_ptr<IMDModule> createInteractiveMolecularDynamicsModule()
index 19dfd2869a55c3227867f3e4e8d4f556b25a47d1..a8ff0a0352a6711a847c4d5e8e4e3b05c018a22a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, 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.
@@ -63,7 +63,7 @@ class MDModules::Impl : public IMDOutputProvider
 {
 public:
     Impl() :
-        densityFitting_(DensityFittingModuleInfo::create(&notifier_)),
+        densityFitting_(DensityFittingModuleInfo::create()),
         field_(createElectricFieldModule()),
         imd_(createInteractiveMolecularDynamicsModule()),
         swapCoordinates_(createSwapCoordinatesModule())
@@ -174,6 +174,16 @@ ForceProviders* MDModules::initForceProviders()
     return impl_->forceProviders_.get();
 }
 
+void MDModules::subscribeToPreProcessingNotifications()
+{
+    impl_->densityFitting_->subscribeToPreProcessingNotifications(&impl_->notifier_);
+}
+
+void MDModules::subscribeToSimulationSetupNotifications()
+{
+    impl_->densityFitting_->subscribeToSimulationSetupNotifications(&impl_->notifier_);
+}
+
 void MDModules::add(std::shared_ptr<gmx::IMDModule> module)
 {
     impl_->modules_.emplace_back(std::move(module));
index 3f956431e5b6048e07e6d1a0039d7053a46ab31e..6fabb761cd3854fb41bbfcd35548cb2b559ce9fa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, 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.
@@ -144,6 +144,22 @@ public:
      */
     ForceProviders* initForceProviders();
 
+    /*! \brief Subscribe MdModules to simulation setup notifications.
+     *
+     * Allows MdModules to subscribe to notifications that are called back
+     * during the set up of an MD simulation, after the options were
+     * assigned to the modules.
+     */
+    void subscribeToSimulationSetupNotifications();
+
+    /*! \brief Subscribe MdModules to notifications during pre-processing.
+     *
+     * Allows MdModules to subscribe to notifications that are called back
+     * during pre processing an MD simulation, after the options were
+     * assigned to the modules.
+     */
+    void subscribeToPreProcessingNotifications();
+
     /*!
      * \brief Add a module to the container.
      *
index 6827e7e9de8ca19bb8b710788e2b79a406e8df3c..d15f2933d3d17ac658564dafef0c8a08623e9122 100644 (file)
@@ -910,6 +910,8 @@ int Mdrunner::mdrunner()
 
     // TODO: Error handling
     mdModules_->assignOptionsToModules(*inputrec->params, nullptr);
+    // now that the MdModules know their options, they know which callbacks to sign up to
+    mdModules_->subscribeToSimulationSetupNotifications();
     const auto& mdModulesNotifier = mdModules_->notifier().simulationSetupNotifications_;
 
     if (inputrec->internalParameters != nullptr)
index c9b1f594024c9b7d761bc2b45f215f7b32f44549..83283417b4873cfa1b0ef9d52d0c47db6725c25b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020, 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.
@@ -51,6 +51,7 @@ namespace gmx
 class ForceProviders;
 class IMDOutputProvider;
 class IMdpOptionProvider;
+struct MdModulesNotifier;
 
 /*! \libinternal \brief
  * Extension module for \Gromacs simulations.
@@ -73,6 +74,10 @@ public:
     virtual IMDOutputProvider* outputProvider() = 0;
     //! Initializes force providers from this module.
     virtual void initForceProviders(ForceProviders* forceProviders) = 0;
+    //! Subscribe to simulation setup notifications
+    virtual void subscribeToSimulationSetupNotifications(MdModulesNotifier* notifier) = 0;
+    //! Subscribe to pre processing notifications
+    virtual void subscribeToPreProcessingNotifications(MdModulesNotifier* notifier) = 0;
 };
 
 } // namespace gmx
index a6ba84eeee54eddb1d16d3d3bf38d1a416058771..cb8091aac40b45aed8b90926b3e15df26b4c34b8 100644 (file)
@@ -204,6 +204,10 @@ std::unique_ptr<RestraintMDModule> RestraintMDModule::create(std::shared_ptr<IRe
     return newModule;
 }
 
+void RestraintMDModule::subscribeToSimulationSetupNotifications(MdModulesNotifier* /*notifier*/) {}
+
+void RestraintMDModule::subscribeToPreProcessingNotifications(MdModulesNotifier* /*notifier*/) {}
+
 // private constructor to implement static create() method.
 RestraintMDModule::RestraintMDModule(std::unique_ptr<RestraintMDModuleImpl> restraint) :
     impl_{ std::move(restraint) }
index c6ec4b56153a883d0f0107a34ec9079ebfd60320..2a0c75784a93de6f2f8580a1ea7983829fb3a57c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, 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.
@@ -53,6 +53,7 @@ namespace gmx
 
 // Forward declaration to allow opaque pointer to library internal class.
 class RestraintMDModuleImpl;
+struct MdModulesNotifier;
 
 /*! \libinternal \ingroup module_restraint
  * \brief MDModule wrapper for Restraint implementations.
@@ -115,6 +116,11 @@ public:
      */
     void initForceProviders(ForceProviders* forceProviders) override;
 
+    //! Subscribe to simulation setup notifications
+    void subscribeToSimulationSetupNotifications(MdModulesNotifier* notifier) override;
+    //! Subscribe to pre processing notifications
+    void subscribeToPreProcessingNotifications(MdModulesNotifier* notifier) override;
+
 private:
     /*!
      * \brief Private implementation opaque pointer.
index a9290efe6504f9eff0a331f35fb9a0ecac49b1ed..37df287b80a5d7e370bddf4d83065de8d51a2669 100644 (file)
@@ -126,6 +126,8 @@ class SwapCoordinates final : public IMDModule
     IMdpOptionProvider* mdpOptionProvider() override { return nullptr; }
     IMDOutputProvider*  outputProvider() override { return nullptr; }
     void                initForceProviders(ForceProviders* /* forceProviders */) override {}
+    void subscribeToSimulationSetupNotifications(MdModulesNotifier* /* notifier */) override {}
+    void subscribeToPreProcessingNotifications(MdModulesNotifier* /* notifier */) override {}
 };
 
 std::unique_ptr<IMDModule> createSwapCoordinatesModule()