From 8e3da355a251de1201c662c05730924da4171215 Mon Sep 17 00:00:00 2001 From: Christian Blau Date: Thu, 8 Aug 2019 16:18:35 +0200 Subject: [PATCH] Internal parameter storage for IMDModules It is currently not possible for MdModules to store data in a tpr file that is non-mdp input, e.g., the result of some computation during setup level. Atom indices of index groups are one example: evaluated from strings during grompp time, they are stored as list of integers in the run input file. During the mdrun setup the information to evaluate the index groups is no longer available. This patch introduces a storage for internal MdModule parameters. The parameters are stored in a seperate key-value-tree in the input record that is then serialized into the tpr file. In contrast to the ir->params, this key-value-tree does not match the options given in an input file. Change-Id: I207d8c837c39f1afb196507fe228306700e46a49 --- docs/doxygen/lib/mdmodules.md | 16 ++++++++++++++++ src/gromacs/fileio/tpxio.cpp | 20 ++++++++++++++++++-- src/gromacs/gmxpreprocess/grompp.cpp | 10 ++++++++++ src/gromacs/mdlib/broadcaststructs.cpp | 17 ++++++++++++++++- src/gromacs/mdrun/mdmodules.h | 3 +++ src/gromacs/mdrun/runner.cpp | 5 +++++ src/gromacs/mdtypes/inputrec.h | 3 +++ 7 files changed, 71 insertions(+), 3 deletions(-) diff --git a/docs/doxygen/lib/mdmodules.md b/docs/doxygen/lib/mdmodules.md index 3da16c19b3..a531b5a1b5 100644 --- a/docs/doxygen/lib/mdmodules.md +++ b/docs/doxygen/lib/mdmodules.md @@ -191,3 +191,19 @@ To include a notification for your module, YourCallbackSignature argument(); mdModules_.notifier().notify(argument); ``` + +Storing non-mdp option module parameters +---------------------------------------- + +Some mdrun modules want to store data that is non-mdp input, e.g., the result of +computation during setup. Atom indices of index groups are one example: +they are evaluated from strings during grompp time and stored as list of +integers in the run input file. During the mdrun setup the information to +evaluate the index groups is no longer available. + +To store parameters, subscribe to the `KeyValueTreeBuilder*` notification that +provides a handle to a KeyValueTreeBuilder that allows adding own information to +that tree. + +To restore parameters, subscribe to the `const KeyValueTreeObject &` +notification that returns the tree that is build by the KeyValueTreeBuilder*. diff --git a/src/gromacs/fileio/tpxio.cpp b/src/gromacs/fileio/tpxio.cpp index 0d26379c75..409ec59fb3 100644 --- a/src/gromacs/fileio/tpxio.cpp +++ b/src/gromacs/fileio/tpxio.cpp @@ -101,7 +101,8 @@ static const char *tpx_tag = TPX_TAG_RELEASE; * in this enumeration, and write code below that does the right thing * according to the value of file_version. */ -enum tpxv { +enum tpxv +{ tpxv_ComputationalElectrophysiology = 96, /**< support for ion/water position swaps (computational electrophysiology) */ tpxv_Use64BitRandomSeed, /**< change ld_seed from int to int64_t */ tpxv_RestrictedBendingAndCombinedAngleTorsionPotentials, /**< potentials for supporting coarse-grained force fields */ @@ -121,8 +122,9 @@ enum tpxv { tpxv_AcceleratedWeightHistogram, /**< sampling with accelerated weight histogram method (AWH) */ tpxv_RemoveImplicitSolvation, /**< removed support for implicit solvation */ tpxv_PullPrevStepCOMAsReference, /**< Enabled using the COM of the pull group of the last frame as reference for PBC */ - tpxv_MimicQMMM, /**< Inroduced support for MiMiC QM/MM interface */ + tpxv_MimicQMMM, /**< Introduced support for MiMiC QM/MM interface */ tpxv_PullAverage, /**< Added possibility to output average pull force and position */ + tpxv_GenericInternalParameters, /**< Added internal parameters for mdrun modules*/ tpxv_Count /**< the total number of tpxv versions */ }; @@ -1684,6 +1686,20 @@ static void do_inputrec(gmx::ISerializer *serializer, { ir->params = new gmx::KeyValueTreeObject(paramsBuilder.build()); } + + if (file_version >= tpxv_GenericInternalParameters) + { + if (serializer->reading()) + { + ir->internalParameters = std::make_unique(gmx::deserializeKeyValueTree(serializer)); + } + else + { + GMX_RELEASE_ASSERT(ir->internalParameters != nullptr, + "Parameters should be present when writing inputrec"); + gmx::serializeKeyValueTree(*ir->internalParameters, serializer); + } + } } diff --git a/src/gromacs/gmxpreprocess/grompp.cpp b/src/gromacs/gmxpreprocess/grompp.cpp index 43a317cc21..10cb4d9875 100644 --- a/src/gromacs/gmxpreprocess/grompp.cpp +++ b/src/gromacs/gmxpreprocess/grompp.cpp @@ -101,6 +101,7 @@ #include "gromacs/utility/fatalerror.h" #include "gromacs/utility/futil.h" #include "gromacs/utility/gmxassert.h" +#include "gromacs/utility/keyvaluetreebuilder.h" #include "gromacs/utility/smalloc.h" #include "gromacs/utility/snprintf.h" @@ -2418,6 +2419,15 @@ int gmx_grompp(int argc, char *argv[]) } } + // Add the md modules internal parameters that are not mdp options + // e.g., atom indices + + { + gmx::KeyValueTreeBuilder internalParameterBuilder; + mdModules.notifier().notify(&internalParameterBuilder); + ir->internalParameters = std::make_unique(internalParameterBuilder.build()); + } + if (bVerbose) { fprintf(stderr, "writing run input file...\n"); diff --git a/src/gromacs/mdlib/broadcaststructs.cpp b/src/gromacs/mdlib/broadcaststructs.cpp index 6eb325684e..7d67cf00ff 100644 --- a/src/gromacs/mdlib/broadcaststructs.cpp +++ b/src/gromacs/mdlib/broadcaststructs.cpp @@ -677,6 +677,15 @@ static void bc_swapions(const t_commrec *cr, t_swapcoords *swap) static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec) { + // Make sure to destruct all previously set internal parameters properly + // before the block_bc on the inputrec overwrites them. + // They are expected to be null anyway, but we can't guarantee this here. + if (!SIMMASTER(cr)) + { + // will call destructor on previously set parameters upon leaving this block + std::unique_ptr previouslySetInternalParametersOnNonMaster; + inputrec->internalParameters.swap(previouslySetInternalParametersOnNonMaster); + } // Note that this overwrites pointers in inputrec, so all pointer fields // Must be initialized separately below. block_bc(cr, *inputrec); @@ -684,6 +693,7 @@ static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec) { gmx::InMemorySerializer serializer; gmx::serializeKeyValueTree(*inputrec->params, &serializer); + gmx::serializeKeyValueTree(*inputrec->internalParameters, &serializer); std::vector buffer = serializer.finishAndGetBuffer(); size_t size = buffer.size(); block_bc(cr, size); @@ -691,7 +701,7 @@ static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec) } else { - // block_bc() above overwrites the old pointer, so set it to a + // block_bc() of inputrec above overwrites the old pointer, so set it to a // reasonable value in case code below throws. inputrec->params = nullptr; std::vector buffer; @@ -701,6 +711,11 @@ static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec) gmx::InMemoryDeserializer serializer(buffer, false); inputrec->params = new gmx::KeyValueTreeObject( gmx::deserializeKeyValueTree(&serializer)); + // release is required because internalParameters' destructor will fail + // if block_bc() of inputrec overwrites the internalParameters pointer with garbage + auto gmx_unused releasedGarbagePointer = inputrec->internalParameters.release(); + inputrec->internalParameters = std::make_unique( + gmx::deserializeKeyValueTree(&serializer)); } bc_grpopts(cr, &(inputrec->opts)); diff --git a/src/gromacs/mdrun/mdmodules.h b/src/gromacs/mdrun/mdmodules.h index e3c816f8ab..21ca0ba5a7 100644 --- a/src/gromacs/mdrun/mdmodules.h +++ b/src/gromacs/mdrun/mdmodules.h @@ -59,6 +59,7 @@ class IKeyValueTreeErrorHandler; class IKeyValueTreeTransformRules; class IMDOutputProvider; class KeyValueTreeObject; +class KeyValueTreeBuilder; class IMDModule; class LocalAtomSetManager; @@ -110,6 +111,8 @@ class MDModules //! Register callback function types for MDModules using notifier_type = registerMdModuleNotification< CommunicationIsSetup, + KeyValueTreeBuilder*, + const KeyValueTreeObject &, LocalAtomSetManager * >::type; diff --git a/src/gromacs/mdrun/runner.cpp b/src/gromacs/mdrun/runner.cpp index 6e01ac3c47..bc1a4bbc6e 100644 --- a/src/gromacs/mdrun/runner.cpp +++ b/src/gromacs/mdrun/runner.cpp @@ -142,6 +142,7 @@ #include "gromacs/utility/filestream.h" #include "gromacs/utility/gmxassert.h" #include "gromacs/utility/gmxmpi.h" +#include "gromacs/utility/keyvaluetree.h" #include "gromacs/utility/logger.h" #include "gromacs/utility/loggerbuilder.h" #include "gromacs/utility/physicalnodecommunicator.h" @@ -798,6 +799,10 @@ int Mdrunner::mdrunner() // TODO: Error handling mdModules_->assignOptionsToModules(*inputrec->params, nullptr); + if (inputrec->internalParameters != nullptr) + { + mdModules_->notifier().notify(*inputrec->internalParameters); + } if (fplog != nullptr) { diff --git a/src/gromacs/mdtypes/inputrec.h b/src/gromacs/mdtypes/inputrec.h index 48b3fda5de..dc24fc035b 100644 --- a/src/gromacs/mdtypes/inputrec.h +++ b/src/gromacs/mdtypes/inputrec.h @@ -587,6 +587,9 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding) //! KVT object that contains input parameters converted to the new style. gmx::KeyValueTreeObject *params; + + //! KVT for storing simulation parameters that are not part of the mdp file. + std::unique_ptr internalParameters; }; int ir_optimal_nstcalcenergy(const t_inputrec *ir); -- 2.22.0