density-guided simulation forces only every :math:`N` steps. The applied force
is scaled by :math:`N` to approximate the same effective Hamiltonian as when
applying the forces every step, while maintaining time-reversibility and energy
-conservation. Note that for this setting, the energy output frequency should
-be a multiple of :math:`N`.
+conservation. Note that for this setting, the energy output frequency must be a
+multiple of :math:`N`.
The maximal time-step should not exceed the fastest oscillation period of any
atom within the map potential divided by :math:`\pi`. This oscillation period
};
notifier->notifier_.subscribe(readInternalParametersFunction);
+ // Checking for consistency with all .mdp options
+ const auto checkEnergyCaluclationFrequencyFunction = [this](EnergyCalculationFrequencyErrors * energyCalculationFrequencyErrors) {
+ densityFittingOptions_.checkEnergyCaluclationFrequency(energyCalculationFrequencyErrors);
+ };
+ notifier->notifier_.subscribe(checkEnergyCaluclationFrequencyFunction);
+
// constructing local atom sets during simulation setup
const auto setLocalAtomSetFunction = [this](LocalAtomSetManager *localAtomSetManager) {
this->constructLocalAtomSet(localAtomSetManager);
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/keyvaluetreebuilder.h"
#include "gromacs/utility/keyvaluetreetransform.h"
+#include "gromacs/utility/mdmodulenotification.h"
#include "gromacs/utility/strconvert.h"
#include "densityfittingamplitudelookup.h"
[](const KeyValueTreeValue &val) { return val.cast<std::int64_t>(); });
}
+void DensityFittingOptions::checkEnergyCaluclationFrequency(EnergyCalculationFrequencyErrors * energyCalculationFrequencyErrors) const
+{
+ if (energyCalculationFrequencyErrors->energyCalculationIntervalInSteps() % parameters_.calculationIntervalInSteps_ != 0)
+ {
+ energyCalculationFrequencyErrors->addError("nstcalcenergy (" +
+ toString(energyCalculationFrequencyErrors->energyCalculationIntervalInSteps())
+ + ") is not a multiple of " + DensityFittingModuleInfo::name_ + "-" + c_everyNStepsTag_
+ + " (" + toString(parameters_.calculationIntervalInSteps_) + ") .");
+ }
+}
+
const std::string &DensityFittingOptions::referenceDensityFileName() const
{
return referenceDensityFileName_;
namespace gmx
{
+class EnergyCalculationFrequencyErrors;
class IndexGroupsAndNames;
class KeyValueTreeObject;
class KeyValueTreeBuilder;
//! Return the file name of the reference density
const std::string &referenceDensityFileName() const;
+ //! Check if input parameters are consistent with other simulation parameters
+ void checkEnergyCaluclationFrequency(EnergyCalculationFrequencyErrors * energyCalculationFrequencyErrors) const;
+
private:
const std::string c_activeTag_ = "active";
{
fprintf(stderr, "checking input for internal consistency...\n");
}
- check_ir(mdparin, ir, opts, wi);
+ check_ir(mdparin, mdModules.notifier(), ir, opts, wi);
if (ir->ld_seed == -1)
{
}
}
-void check_ir(const char *mdparin, t_inputrec *ir, t_gromppopts *opts,
- warninp_t wi)
+void check_ir(const char *mdparin, const gmx::MdModulesNotifier &mdModulesNotifier,
+ t_inputrec *ir, t_gromppopts *opts, warninp_t wi)
/* Check internal consistency.
* NOTE: index groups are not set here yet, don't check things
* like temperature coupling group options here, but in triple_check
check_nst("nstcalcenergy", ir->nstcalcenergy,
"nstenergy", &ir->nstenergy, wi);
}
+
+ // Inquire all MdModules, if their parameters match with the energy
+ // calculation frequency
+ gmx::EnergyCalculationFrequencyErrors energyCalculationFrequencyErrors(ir->nstcalcenergy);
+ mdModulesNotifier.notifier_.notify(&energyCalculationFrequencyErrors);
+
+ // Emit all errors from the energy calculation frequency checks
+ for (const std::string &energyFrequencyErrorMessage : energyCalculationFrequencyErrors.errorMessages())
+ {
+ warning_error(wi, energyFrequencyErrorMessage);
+ }
}
if (ir->nsteps == 0 && !ir->bContinuation)
/*! \brief Clean up object that holds strings parsed from an .mdp file */
void done_inputrec_strings();
-void check_ir(const char *mdparin, t_inputrec *ir, t_gromppopts *opts,
- warninp_t wi);
+void check_ir(const char *mdparin, const gmx::MdModulesNotifier &mdModulesNotifier,
+ t_inputrec *ir, t_gromppopts *opts, warninp_t wi);
/* Validate inputrec data.
* Fatal errors will be added to nerror.
*/
get_ir(inputMdpFilename.c_str(), outputMdpFilename.c_str(),
&mdModules_, &ir_, &opts_, WriteMdpHeader::no, wi_);
- check_ir(inputMdpFilename.c_str(), &ir_, &opts_, wi_);
+ check_ir(inputMdpFilename.c_str(), mdModules_.notifier(), &ir_, &opts_, wi_);
// Now check
bool failure = warning_errors_exist(wi_);
TestReferenceData data;
#define GMX_MDRUNUTILITY_MDMODULENOTIFICATION_H
#include <functional>
+#include <string>
#include <vector>
struct t_commrec;
bool energyOutputToDensityFitting_ = false;
};
+/*! \libinternal
+ * \brief Collect errors for the energy calculation frequency.
+ *
+ * Collect errors regarding energy calculation frequencies as strings that then
+ * may be used to issue errors.
+ *
+ * \note The mdp option "nstcalcenergy" is altered after reading the .mdp input
+ * and only used in certain integrators, thus this class is to be used
+ * only after all these operations are done.
+ */
+class EnergyCalculationFrequencyErrors
+{
+ public:
+ //! Construct by setting the energy calculation frequency
+ EnergyCalculationFrequencyErrors(int64_t energyCalculationIntervalInSteps) :
+ energyCalculationIntervalInSteps_(energyCalculationIntervalInSteps){}
+ //! Return the number of steps of an energy calculation interval
+ std::int64_t energyCalculationIntervalInSteps() const
+ {
+ return energyCalculationIntervalInSteps_;
+ }
+ //! Collect error messages
+ void addError(const std::string &errorMessage)
+ {
+ errorMessages_.push_back(errorMessage);
+ }
+ //! Return error messages
+ const std::vector<std::string> &errorMessages() const
+ {
+ return errorMessages_;
+ }
+ private:
+ //! The frequency of energy calculations
+ const std::int64_t energyCalculationIntervalInSteps_;
+ //! The error messages
+ std::vector<std::string> errorMessages_;
+};
+
struct MdModulesNotifier
{
//! Register callback function types for MdModule
registerMdModuleNotification<
const t_commrec &,
+ EnergyCalculationFrequencyErrors *,
IndexGroupsAndNames,
KeyValueTreeObjectBuilder,
const KeyValueTreeObject &,
#include <string>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
#include "gromacs/topology/ifunc.h"
#include "gromacs/utility/stringutil.h"
"density-guided-simulation-reference-density-filename = %s\n",
TestFileManager::getInputFilePath("ellipsoid-density.mrc").c_str() );
+ //! Mdp values for md integrator with default density fitting parameters.
+ const std::string mdpMdDensfitYesUnsetValues = formatString(
+ "integrator = md\n"
+ "nsteps = 2\n"
+ "cutoff-scheme = verlet\n"
+ "density-guided-simulation-active = yes\n"
+ "density-guided-simulation-group = FirstThreeOfTwelve\n"
+ "density-guided-simulation-reference-density-filename = %s\n",
+ TestFileManager::getInputFilePath("ellipsoid-density.mrc").c_str() );
+
//! Mdp values for steepest-decent energy minimization with density fitting values set to non-defaults.
const std::string mdpDensiftAllDefaultsChanged_ = formatString(
"density-guided-simulation-similarity-measure = relative-entropy\n"
"density-guided-simulation-gaussian-transform-spreading-range-in-multiples-of-width = 6\n"
"density-guided-simulation-normalize-densities = false\n"
);
-
+ //! Set mdp values so that energy calculation interval and density guided simulation interval mismatch.
+ const std::string mdpEnergyAndDensityfittingIntervalMismatch_ = formatString(
+ "nstcalcenergy = 7\n"
+ "density-guided-simulation-nst = 3\n"
+ );
//! The command line to call mdrun
CommandLine commandLineForMdrun_;
};
checkMdrun(expectedEnergyTermMagnitude);
}
+/* Test that grompp exits with error message if energy evaluation frequencies
+ * do not match.
+ */
+TEST_F(DensityFittingTest, GromppErrorWhenEnergyEvaluationFrequencyMismatch)
+{
+ runner_.useStringAsMdpFile(mdpMdDensfitYesUnsetValues + mdpEnergyAndDensityfittingIntervalMismatch_);
+
+ EXPECT_DEATH_IF_SUPPORTED(runner_.callGrompp(), ".*is not a multiple of density-guided-simulation-nst.*");
+}
} // namespace test
} // namespace gmx