---------------------
Each module implements a factory that returns an instance of gmx::IMDModule.
-This interface has methods that in turn return instances of other interfaces:
-gmx::IMdpOptionProvider, gmx::IMDOutputProvider, and IForceProvider.
+This interface has methods that in turn refer to other interfaces:
+gmx::IMdpOptionProvider, gmx::IMDOutputProvider, and gmx::IForceProvider.
The module also implements these interfaces (or a subset of them), and code
outside the module only calls methods in these interfaces.
// From IMDModule
IMdpOptionProvider *mdpOptionProvider() override { return this; }
IMDOutputProvider *outputProvider() override { return this; }
- IForceProvider *forceProvider() override { return this; }
+ void initForceProviders(ForceProviders *forceProviders) override
+ {
+ if (isActive())
+ {
+ forceProviders->addForceProviderWithoutVirialContribution(this);
+ }
+ }
// From IMdpOptionProvider
void initMdpTransform(IKeyValueTreeTransformRules *transform) override;
void finishOutput() override;
// From IForceProvider
- void initForcerec(t_forcerec *fr) override;
//! \copydoc IForceProvider::calculateForces()
void calculateForces(const t_commrec *cr,
const t_mdatoms *mdatoms,
- PaddedRVecVector *force,
- double t) override;
+ const matrix box,
+ double t,
+ const rvec *x,
+ ArrayRef<RVec> force) override;
private:
//! Return whether or not to apply a field
}
}
-void ElectricField::initForcerec(t_forcerec *fr)
-{
- if (isActive())
- {
- fr->bF_NoVirSum = TRUE;
- fr->efield = this;
- }
-}
-
real ElectricField::field(int dim, real t) const
{
return efield_[dim].evaluate(t);
void ElectricField::calculateForces(const t_commrec *cr,
const t_mdatoms *mdatoms,
- PaddedRVecVector *force,
- double t)
+ const matrix /* box */,
+ double t,
+ const rvec * /* x */,
+ ArrayRef<RVec> force)
{
if (isActive())
{
- rvec *f = as_rvec_array(force->data());
+ rvec *f = as_rvec_array(force.data());
for (int m = 0; (m < DIM); m++)
{
#include "gromacs/mdtypes/iforceprovider.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/utility/arrayref.h"
#include "gromacs/utility/keyvaluetreebuilder.h"
#include "gromacs/utility/keyvaluetreetransform.h"
#include "gromacs/utility/real.h"
class ElectricFieldTest : public ::testing::Test
{
public:
- ElectricFieldTest() {}
-
void test(int dim,
real E0,
real omega,
snew(md.chargeA, md.homenr);
md.chargeA[0] = 1;
- t_commrec *cr = init_commrec();
- t_forcerec *forcerec = mk_forcerec();
- module.forceProvider()->initForcerec(forcerec);
- forcerec->efield->calculateForces(cr, &md, &f, 0);
+ t_commrec *cr = init_commrec();
+ module.initForceProviders()->calculateForces(cr, &md, nullptr, 0, nullptr,
+ gmx::EmptyArrayRef(), f);
done_commrec(cr);
EXPECT_REAL_EQ_TOL(f[0][dim], expectedValue, tolerance);
- sfree(forcerec);
sfree(md.chargeA);
}
};
const gmx::MDLogger &mdlog,
t_forcerec *fr,
t_fcdata *fcd,
- IForceProvider *forceProviders,
const t_inputrec *ir,
const gmx_mtop_t *mtop,
const t_commrec *cr,
}
fr->bF_NoVirSum = (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype) ||
+ fr->forceProviders->hasForcesWithoutVirialContribution() ||
gmx_mtop_ftype_count(mtop, F_POSRES) > 0 ||
gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0);
- /* Initialization call after setting bF_NoVirSum,
- * since it efield->initForcerec also sets this to true.
- */
- forceProviders->initForcerec(fr);
-
if (fr->bF_NoVirSum)
{
fr->forceBufferNoVirialSummation = new PaddedRVecVector;
#include "gromacs/mdtypes/forcerec.h"
#include "gromacs/timing/wallcycle.h"
-struct IForceProvider;
struct t_commrec;
struct t_fcdata;
struct t_filenm;
* \param[in] mdlog File for printing
* \param[out] fr The forcerec
* \param[in] fcd Force constant data
- * \param[in] forceProviders Handle to modules providing forces
* \param[in] ir Inputrec structure
* \param[in] mtop Molecular topology
* \param[in] cr Communication structures
const gmx::MDLogger &mdlog,
t_forcerec *fr,
t_fcdata *fcd,
- IForceProvider *forceProviders,
const t_inputrec *ir,
const gmx_mtop_t *mtop,
const t_commrec *cr,
if (bDoForces)
{
- /* Compute forces due to electric field */
- if (fr->efield != nullptr)
+ /* Collect forces from modules */
+ gmx::ArrayRef<gmx::RVec> fNoVirSum;
+ if (fr->bF_NoVirSum)
{
- fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
+ fNoVirSum = *fr->f_novirsum;
}
+ fr->forceProviders->calculateForces(cr, mdatoms, box, t, x, *force, fNoVirSum);
/* If we have NoVirSum forces, but we do not calculate the virial,
* we sum fr->f_novirsum=f later.
if (bDoForces)
{
- /* Compute forces due to electric field */
- if (fr->efield != nullptr)
+ /* Collect forces from modules */
+ gmx::ArrayRef<gmx::RVec> fNoVirSum;
+ if (fr->bF_NoVirSum)
{
- fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
+ fNoVirSum = *fr->f_novirsum;
}
+ fr->forceProviders->calculateForces(cr, mdatoms, box, t, x, *force, fNoVirSum);
/* Communicate the forces */
if (DOMAINDECOMP(cr))
namespace gmx
{
-class MDModules::Impl : public IMDOutputProvider, public IForceProvider
+class MDModules::Impl : public IMDOutputProvider
{
public:
field_->outputProvider()->finishOutput();
}
- // From IForceProvider
- virtual void initForcerec(t_forcerec *fr)
- {
- field_->forceProvider()->initForcerec(fr);
- }
- virtual void calculateForces(const t_commrec * /*cr*/,
- const t_mdatoms * /*mdatoms*/,
- PaddedRVecVector * /*force*/,
- double /*t*/)
- {
- // not called currently
- }
-
- std::unique_ptr<IMDModule> field_;
+ std::unique_ptr<IMDModule> field_;
+ std::unique_ptr<ForceProviders> forceProviders_;
};
MDModules::MDModules() : impl_(new Impl)
return impl_.get();
}
-IForceProvider *MDModules::forceProvider()
+ForceProviders *MDModules::initForceProviders()
{
- return impl_.get();
+ GMX_RELEASE_ASSERT(impl_->forceProviders_ == nullptr,
+ "Force providers initialized multiple times");
+ impl_->forceProviders_.reset(new ForceProviders);
+ impl_->field_->initForceProviders(impl_->forceProviders_.get());
+ return impl_->forceProviders_.get();
}
} // namespace gmx
#include "gromacs/utility/classhelpers.h"
-struct IForceProvider;
+struct ForceProviders;
+
struct t_inputrec;
namespace gmx
*
* Currently, where the set of modules needs to be accessed, either a pointer
* to MDModules is passed around, or an instance of IMDOutputProvider or
- * IForceProvider returned from MDModules. The implementation of these
- * interfaces in MDModules calls the corresponding methods in the relevant
- * modules. In the future, some additional logic may need to be introduced at
- * the call sites that can also influence the signature of the methods. In
- * this case, a separate object may need to be introduced (e.g.,
- * ForceProvidersManager or similar) that can be passed around without
- * knowledge of the full MDModules. t_forcerec also currently directly calls
- * individual modules through pointers to their interfaces, which should be
- * generalized in the future.
+ * ForceProviders returned from MDModules. These objects returned from
+ * MDModules call the corresponding methods in the relevant modules.
+ * In the future, some additional logic may need to be introduced at
+ * the call sites that can also influence the signature of the methods,
+ * similar to what ForceProviders already does for force computation.
*
* The assignOptionsToModules() and adjustInputrecBasedOnModules() methods of
* this class also take responsibility for wiring up the options (and their
*/
IMDOutputProvider *outputProvider();
/*! \brief
- * Returns an interface for initializing modules providing forces.
+ * Returns an object for computing forces from the modules.
*/
- IForceProvider *forceProvider();
+ ForceProviders *initForceProviders();
private:
class Impl;
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
-struct IForceProvider;
+struct ForceProviders;
/* Abstract type for PME that is defined only in the routine that use them. */
struct gmx_genborn_t;
int nthread_ewc;
struct ewald_corr_thread_t *ewc_t;
- struct IForceProvider *efield;
+ struct ForceProviders *forceProviders;
};
/* Important: Starting with Gromacs-4.6, the values of c6 and c12 in the nbfp array have
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2017, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes from iforceprovider.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_mdtypes
+ */
+#include "gmxpre.h"
+
+#include "iforceprovider.h"
+
+#include <vector>
+
+#include "gromacs/utility/arrayref.h"
+
+using namespace gmx;
+
+class ForceProviders::Impl
+{
+ public:
+ std::vector<IForceProvider *> withVirialContribution_;
+ std::vector<IForceProvider *> withoutVirialContribution_;
+};
+
+ForceProviders::ForceProviders()
+ : impl_(new Impl)
+{
+}
+
+ForceProviders::~ForceProviders()
+{
+}
+
+void ForceProviders::addForceProvider(gmx::IForceProvider *provider)
+{
+ impl_->withVirialContribution_.push_back(provider);
+}
+
+void ForceProviders::addForceProviderWithoutVirialContribution(gmx::IForceProvider *provider)
+{
+ impl_->withoutVirialContribution_.push_back(provider);
+}
+
+bool ForceProviders::hasForcesWithoutVirialContribution() const
+{
+ return !impl_->withoutVirialContribution_.empty();
+}
+
+void ForceProviders::calculateForces(const t_commrec *cr,
+ const t_mdatoms *mdatoms,
+ const matrix box,
+ double t,
+ const rvec *x,
+ gmx::ArrayRef<gmx::RVec> force,
+ gmx::ArrayRef<gmx::RVec> f_novirsum) const
+{
+ for (auto provider : impl_->withVirialContribution_)
+ {
+ provider->calculateForces(cr, mdatoms, box, t, x, force);
+ }
+ for (auto provider : impl_->withoutVirialContribution_)
+ {
+ provider->calculateForces(cr, mdatoms, box, t, x, f_novirsum);
+ }
+}
*/
/*! \libinternal \file
* \brief
- * Declares gmx::IForceProvider.
+ * Declares gmx::IForceProvider and ForceProviders.
*
* See \ref page_mdmodules for an overview of this and associated interfaces.
*
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
* \inlibraryapi
* \ingroup module_mdtypes
*/
#ifndef GMX_MDTYPES_IFORCEPROVIDER_H
#define GMX_MDTYPES_IFORCEPROVIDER_H
-#include "gromacs/math/paddedvector.h"
+#include "gromacs/math/vectypes.h"
+#include "gromacs/utility/classhelpers.h"
struct t_commrec;
struct t_forcerec;
struct t_mdatoms;
+namespace gmx
+{
+
+template <typename T>
+class ArrayRef;
+
/*! \libinternal \brief
* Interface for a component that provides forces during MD.
*
- * This is typically part of a larger structure/class managing its own
- * data, such that it has the information on what to do stored locally.
+ * Modules implementing IMDModule generally implement this internally, and use
+ * IMDModule::initForceProviders() to register their implementation in
+ * ForceProviders.
*
- * The interface is not very generic, as it has been written purely based on
- * extraction of existing functions related to electric field handling.
- * This needs to be generalized when more modules are moved to use the
- * interface.
+ * The interface most likely requires additional generalization for use in
+ * other modules than the current electric field implementation.
*
* \inlibraryapi
* \ingroup module_mdtypes
*/
-struct IForceProvider
+class IForceProvider
{
public:
- /*! \brief
- * Sets relevant options in the forcerec structure.
- *
- * \param[inout] fr The forcerec structure
- *
- * \todo
- * This should be replaced by a method that returns a set of
- * flags/other options (either here, or where the IForceProvider
- * instance is returned), and forcerec should be initialized based on
- * that.
- */
- virtual void initForcerec(t_forcerec *fr) = 0;
-
/*! \brief
* Computes forces.
*
* \param[in] cr Communication record for parallel operations
* \param[in] mdatoms Atom information
- * \param[inout] force The forces
+ * \param[in] box The box
* \param[in] t The actual time in the simulation (ps)
+ * \param[in] x The coordinates
+ * \param[inout] force The forces
*/
- virtual void calculateForces(const t_commrec *cr,
- const t_mdatoms *mdatoms,
- PaddedRVecVector *force,
- double t) = 0;
+ virtual void calculateForces(const t_commrec *cr,
+ const t_mdatoms *mdatoms,
+ const matrix box,
+ double t,
+ const rvec *x,
+ gmx::ArrayRef<gmx::RVec> force) = 0;
protected:
~IForceProvider() {}
};
+} // namespace gmx
+
+/*! \libinternal \brief
+ * Evaluates forces from a collection of gmx::IForceProvider.
+ *
+ * This class is a `struct` outside the `gmx` namespace to make it possible to
+ * forward-declare it in forcerec.h, which still needs to compile when included
+ * from the C group kernels.
+ *
+ * \inlibraryapi
+ * \ingroup module_mdtypes
+ */
+struct ForceProviders
+{
+ public:
+ ForceProviders();
+ ~ForceProviders();
+
+ /*! \brief
+ * Adds a provider.
+ */
+ void addForceProvider(gmx::IForceProvider *provider);
+ /*! \brief
+ * Adds a provider whose forces should not contribute to the virial.
+ */
+ void addForceProviderWithoutVirialContribution(gmx::IForceProvider *provider);
+
+ //! Whether there are modules that do not contribute to the virial.
+ bool hasForcesWithoutVirialContribution() const;
+
+ //! Computes forces.
+ void calculateForces(const t_commrec *cr,
+ const t_mdatoms *mdatoms,
+ const matrix box,
+ double t,
+ const rvec *x,
+ gmx::ArrayRef<gmx::RVec> force,
+ gmx::ArrayRef<gmx::RVec> f_novirsum) const;
+
+ private:
+ class Impl;
+
+ gmx::PrivateImplPointer<Impl> impl_;
+};
+
#endif
#ifndef GMX_MDTYPES_IMDMODULE_H
#define GMX_MDTYPES_IMDMODULE_H
-struct IForceProvider;
+struct ForceProviders;
namespace gmx
{
virtual IMdpOptionProvider *mdpOptionProvider() = 0;
//! Returns an interface for handling output files during simulation.
virtual IMDOutputProvider *outputProvider() = 0;
- //! Returns an interface for computing forces during simulation.
- virtual IForceProvider *forceProvider() = 0;
+ //! Initializes force providers from this module.
+ virtual void initForceProviders(ForceProviders *forceProviders) = 0;
};
} // namespace gmx
bcast_state(cr, state);
/* Initiate forcerecord */
- fr = mk_forcerec();
- fr->hwinfo = hwinfo;
- fr->gpu_opt = &hw_opt->gpu_opt;
- init_forcerec(fplog, mdlog, fr, fcd, mdModules.forceProvider(),
+ fr = mk_forcerec();
+ fr->hwinfo = hwinfo;
+ fr->gpu_opt = &hw_opt->gpu_opt;
+ fr->forceProviders = mdModules.initForceProviders();
+ init_forcerec(fplog, mdlog, fr, fcd,
inputrec, mtop, cr, box,
opt2fn("-table", nfile, fnm),
opt2fn("-tablep", nfile, fnm),