Add AWH biasing module + tests
[gromacs.git] / src / gromacs / awh / awh.cpp
blob02ff69114f4f2b49091aef6f5401d7a9c598be4f
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2015,2016,2017, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
36 /*! \internal \file
37 * \brief
38 * Implements the Awh class.
40 * \author Viveca Lindahl
41 * \author Berk Hess <hess@kth.se>
42 * \ingroup module_awh
45 #include "gmxpre.h"
47 #include "awh.h"
49 #include <assert.h>
51 #include <cmath>
52 #include <cstdio>
53 #include <cstdlib>
54 #include <cstring>
56 #include <algorithm>
58 #include "gromacs/gmxlib/network.h"
59 #include "gromacs/math/units.h"
60 #include "gromacs/mdtypes/awh-history.h"
61 #include "gromacs/mdtypes/awh-params.h"
62 #include "gromacs/mdtypes/commrec.h"
63 #include "gromacs/mdtypes/forceoutput.h"
64 #include "gromacs/mdtypes/inputrec.h"
65 #include "gromacs/mdtypes/pull-params.h"
66 #include "gromacs/mdtypes/state.h"
67 #include "gromacs/pbcutil/pbc.h"
68 #include "gromacs/pulling/pull.h"
69 #include "gromacs/timing/wallcycle.h"
70 #include "gromacs/utility/exceptions.h"
71 #include "gromacs/utility/gmxassert.h"
72 #include "gromacs/utility/pleasecite.h"
74 #include "bias.h"
75 #include "biassharing.h"
76 #include "pointstate.h"
78 namespace gmx
81 /*! \internal
82 * \brief A bias and its coupling to the system.
84 * This struct is used to separate the bias machinery in the Bias class,
85 * which should be independent from the reaction coordinate, from the
86 * obtaining of the reaction coordinate values and passing the computed forces.
87 * Currently the AWH method couples to the system by mapping each
88 * AWH bias to a pull coordinate. This can easily be generalized here.
90 struct BiasCoupledToSystem
92 /*! \brief Constructor, couple a bias to a set of pull coordinates.
94 * \param[in] bias The bias.
95 * \param[in] pullCoordIndex The pull coordinate indices.
97 BiasCoupledToSystem(Bias bias,
98 const std::vector<int> &pullCoordIndex);
100 Bias bias; /**< The bias. */
101 const std::vector<int> pullCoordIndex; /**< The pull coordinates this bias acts on. */
103 /* Here AWH can be extended to work on other coordinates than pull. */
106 BiasCoupledToSystem::BiasCoupledToSystem(Bias bias,
107 const std::vector<int> &pullCoordIndex) :
108 bias(bias),
109 pullCoordIndex(pullCoordIndex)
111 /* We already checked for this in grompp, but check again here. */
112 GMX_RELEASE_ASSERT(static_cast<size_t>(bias.ndim()) == pullCoordIndex.size(), "The bias dimensionality should match the number of pull coordinates.");
115 Awh::Awh(FILE *fplog,
116 const t_inputrec &inputRecord,
117 const t_commrec *commRecord,
118 const AwhParams &awhParams,
119 const std::string &biasInitFilename,
120 pull_t *pull_work) :
121 seed_(awhParams.seed),
122 commRecord_(commRecord),
123 pull_(pull_work),
124 potentialOffset_(0)
126 /* We already checked for this in grompp, but check again here. */
127 GMX_RELEASE_ASSERT(inputRecord.pull != nullptr, "With AWH we should have pull parameters");
128 GMX_RELEASE_ASSERT(pull_work != nullptr, "With AWH pull should be initialized before initializing AWH");
130 if (fplog != nullptr)
132 please_cite(fplog, "Lindahl2014");
135 if (haveBiasSharingWithinSimulation(awhParams))
137 /* This has likely been checked by grompp, but throw anyhow. */
138 GMX_THROW(InvalidInputError("Biases within a simulation are shared, currently sharing of biases is only supported between simulations"));
141 int numSharingSimulations = 1;
142 if (awhParams.shareBiasMultisim && MULTISIM(commRecord_))
144 numSharingSimulations = commRecord_->ms->nsim;
147 /* Initialize all the biases */
148 const double beta = 1/(BOLTZ*inputRecord.opts.ref_t[0]);
149 for (int k = 0; k < awhParams.numBias; k++)
151 const AwhBiasParams &awhBiasParams = awhParams.awhBiasParams[k];
153 std::vector<int> pullCoordIndex;
154 std::vector<DimParams> dimParams;
155 for (int d = 0; d < awhBiasParams.ndim; d++)
157 const AwhDimParams &awhDimParams = awhBiasParams.dimParams[d];
158 GMX_RELEASE_ASSERT(awhDimParams.eCoordProvider == eawhcoordproviderPULL, "Currently only the pull code is supported as coordinate provider");
159 const t_pull_coord &pullCoord = inputRecord.pull->coord[awhDimParams.coordIndex];
160 double conversionFactor = pull_coordinate_is_angletype(&pullCoord) ? DEG2RAD : 1;
161 dimParams.push_back(DimParams(conversionFactor, awhDimParams.forceConstant, beta));
163 pullCoordIndex.push_back(awhDimParams.coordIndex);
166 /* Construct the bias and couple it to the system. */
167 Bias::ThisRankWillDoIO thisRankWillDoIO = (MASTER(commRecord_) ? Bias::ThisRankWillDoIO::Yes : Bias::ThisRankWillDoIO::No);
168 biasCoupledToSystem_.emplace_back(Bias(k, awhParams, awhParams.awhBiasParams[k], dimParams, beta, inputRecord.delta_t, numSharingSimulations, biasInitFilename, thisRankWillDoIO),
169 pullCoordIndex);
172 /* Need to register the AWH coordinates to be allowed to apply forces to the pull coordinates. */
173 registerAwhWithPull(awhParams, pull_);
175 if (numSharingSimulations > 1 && MASTER(commRecord_))
177 std::vector<size_t> pointSize;
178 for (auto const &biasCts : biasCoupledToSystem_)
180 pointSize.push_back(biasCts.bias.state().points().size());
182 /* Ensure that the shared biased are compatible between simulations */
183 biasesAreCompatibleForSharingBetweenSimulations(awhParams, pointSize, commRecord_->ms);
187 Awh::~Awh() = default;
189 real Awh::applyBiasForcesAndUpdateBias(int ePBC,
190 const t_mdatoms &mdatoms,
191 const matrix box,
192 gmx::ForceWithVirial *forceWithVirial,
193 double t,
194 gmx_int64_t step,
195 gmx_wallcycle *wallcycle,
196 FILE *fplog)
198 GMX_ASSERT(forceWithVirial, "Need a valid ForceWithVirial object");
200 wallcycle_start(wallcycle, ewcAWH);
202 t_pbc pbc;
203 set_pbc(&pbc, ePBC, box);
205 /* During the AWH update the potential can instantaneously jump due to either
206 an bias update or moving the umbrella. The jumps are kept track of and
207 subtracted from the potential in order to get a useful conserved energy quantity. */
208 double awhPotential = potentialOffset_;
210 for (auto &biasCts : biasCoupledToSystem_)
212 /* Update the AWH coordinate values with those of the corresponding
213 * pull coordinates.
215 awh_dvec coordValue = { 0, 0, 0, 0 };
216 for (int d = 0; d < biasCts.bias.ndim(); d++)
218 coordValue[d] = get_pull_coord_value(pull_, biasCts.pullCoordIndex[d], &pbc);
221 /* Perform an AWH biasing step: this means, at regular intervals,
222 * sampling observables based on the input pull coordinate value,
223 * setting the bias force and/or updating the AWH bias state.
225 awh_dvec biasForce;
226 double biasPotential;
227 double biasPotentialJump;
228 /* Note: In the near future this call will be split in calls
229 * to supports bias sharing within a single simulation.
231 biasCts.bias.calcForceAndUpdateBias(coordValue, biasForce,
232 &biasPotential, &biasPotentialJump,
233 commRecord_->ms,
234 t, step, seed_, fplog);
236 awhPotential += biasPotential;
238 /* Keep track of the total potential shift needed to remove the potential jumps. */
239 potentialOffset_ -= biasPotentialJump;
241 /* Communicate the bias force to the pull struct.
242 * The bias potential is returned at the end of this function,
243 * so that it can be added externally to the correct energy data block.
245 for (int d = 0; d < biasCts.bias.ndim(); d++)
247 apply_external_pull_coord_force(pull_, biasCts.pullCoordIndex[d],
248 biasForce[d], &mdatoms,
249 forceWithVirial);
253 wallcycle_stop(wallcycle, ewcAWH);
255 return MASTER(commRecord_) ? static_cast<real>(awhPotential) : 0;
258 std::shared_ptr<AwhHistory> Awh::initHistoryFromState() const
260 if (MASTER(commRecord_))
262 std::shared_ptr<AwhHistory> awhHistory(new AwhHistory);
263 awhHistory->bias.clear();
264 awhHistory->bias.resize(biasCoupledToSystem_.size());
266 for (size_t k = 0; k < awhHistory->bias.size(); k++)
268 biasCoupledToSystem_[k].bias.initHistoryFromState(&awhHistory->bias[k]);
271 return awhHistory;
273 else
275 /* Return an empty pointer */
276 return std::shared_ptr<AwhHistory>();
280 void Awh::restoreStateFromHistory(const AwhHistory *awhHistory)
282 /* Restore the history to the current state */
283 if (MASTER(commRecord_))
285 GMX_RELEASE_ASSERT(awhHistory != nullptr, "The master rank should have a valid awhHistory when restoring the state from history.");
287 if (awhHistory->bias.size() != biasCoupledToSystem_.size())
289 GMX_THROW(InvalidInputError("AWH state and history contain different numbers of biases. Likely you provided a checkpoint from a different simulation."));
292 potentialOffset_ = awhHistory->potentialOffset;
294 if (PAR(commRecord_))
296 gmx_bcast(sizeof(potentialOffset_), &potentialOffset_, commRecord_);
299 for (size_t k = 0; k < biasCoupledToSystem_.size(); k++)
301 biasCoupledToSystem_[k].bias.restoreStateFromHistory(awhHistory ? &awhHistory->bias[k] : nullptr, commRecord_);
305 void Awh::updateHistory(AwhHistory *awhHistory) const
307 if (!MASTER(commRecord_))
309 return;
312 /* This assert will also catch a non-master rank calling this function. */
313 GMX_RELEASE_ASSERT(awhHistory->bias.size() == biasCoupledToSystem_.size(), "AWH state and history bias count should match");
315 awhHistory->potentialOffset = potentialOffset_;
317 for (size_t k = 0; k < awhHistory->bias.size(); k++)
319 biasCoupledToSystem_[k].bias.updateHistory(&awhHistory->bias[k]);
323 const char * Awh::externalPotentialString()
325 return "AWH";
328 void Awh::registerAwhWithPull(const AwhParams &awhParams,
329 pull_t *pull_work)
331 GMX_RELEASE_ASSERT(pull_work, "Need a valid pull object");
333 for (int k = 0; k < awhParams.numBias; k++)
335 const AwhBiasParams &biasParams = awhParams.awhBiasParams[k];
337 for (int d = 0; d < biasParams.ndim; d++)
339 register_external_pull_potential(pull_work, biasParams.dimParams[d].coordIndex, Awh::externalPotentialString());
344 } // namespace gmx