Merge branch release-2016 into release-2018
[gromacs.git] / src / gromacs / awh / awh.cpp
blob6c3671bdbbd8989dc9e0318624993ba7b5b20c5c
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/fileio/enxio.h"
59 #include "gromacs/gmxlib/network.h"
60 #include "gromacs/math/units.h"
61 #include "gromacs/mdtypes/awh-history.h"
62 #include "gromacs/mdtypes/awh-params.h"
63 #include "gromacs/mdtypes/commrec.h"
64 #include "gromacs/mdtypes/forceoutput.h"
65 #include "gromacs/mdtypes/inputrec.h"
66 #include "gromacs/mdtypes/pull-params.h"
67 #include "gromacs/mdtypes/state.h"
68 #include "gromacs/pbcutil/pbc.h"
69 #include "gromacs/pulling/pull.h"
70 #include "gromacs/timing/wallcycle.h"
71 #include "gromacs/utility/exceptions.h"
72 #include "gromacs/utility/gmxassert.h"
73 #include "gromacs/utility/pleasecite.h"
75 #include "bias.h"
76 #include "biassharing.h"
77 #include "correlationgrid.h"
78 #include "pointstate.h"
80 namespace gmx
83 /*! \internal
84 * \brief A bias and its coupling to the system.
86 * This struct is used to separate the bias machinery in the Bias class,
87 * which should be independent from the reaction coordinate, from the
88 * obtaining of the reaction coordinate values and passing the computed forces.
89 * Currently the AWH method couples to the system by mapping each
90 * AWH bias to a pull coordinate. This can easily be generalized here.
92 struct BiasCoupledToSystem
94 /*! \brief Constructor, couple a bias to a set of pull coordinates.
96 * \param[in] bias The bias.
97 * \param[in] pullCoordIndex The pull coordinate indices.
99 BiasCoupledToSystem(Bias bias,
100 const std::vector<int> &pullCoordIndex);
102 Bias bias; /**< The bias. */
103 const std::vector<int> pullCoordIndex; /**< The pull coordinates this bias acts on. */
105 /* Here AWH can be extended to work on other coordinates than pull. */
108 BiasCoupledToSystem::BiasCoupledToSystem(Bias bias,
109 const std::vector<int> &pullCoordIndex) :
110 bias(std::move(bias)),
111 pullCoordIndex(pullCoordIndex)
113 /* We already checked for this in grompp, but check again here. */
114 GMX_RELEASE_ASSERT(static_cast<size_t>(bias.ndim()) == pullCoordIndex.size(), "The bias dimensionality should match the number of pull coordinates.");
117 Awh::Awh(FILE *fplog,
118 const t_inputrec &inputRecord,
119 const t_commrec *commRecord,
120 const AwhParams &awhParams,
121 const std::string &biasInitFilename,
122 pull_t *pull_work) :
123 seed_(awhParams.seed),
124 nstout_(awhParams.nstOut),
125 commRecord_(commRecord),
126 pull_(pull_work),
127 potentialOffset_(0)
129 /* We already checked for this in grompp, but check again here. */
130 GMX_RELEASE_ASSERT(inputRecord.pull != nullptr, "With AWH we should have pull parameters");
131 GMX_RELEASE_ASSERT(pull_work != nullptr, "With AWH pull should be initialized before initializing AWH");
133 if (fplog != nullptr)
135 please_cite(fplog, "Lindahl2014");
138 if (haveBiasSharingWithinSimulation(awhParams))
140 /* This has likely been checked by grompp, but throw anyhow. */
141 GMX_THROW(InvalidInputError("Biases within a simulation are shared, currently sharing of biases is only supported between simulations"));
144 int numSharingSimulations = 1;
145 if (awhParams.shareBiasMultisim && MULTISIM(commRecord_))
147 numSharingSimulations = commRecord_->ms->nsim;
150 /* Initialize all the biases */
151 const double beta = 1/(BOLTZ*inputRecord.opts.ref_t[0]);
152 for (int k = 0; k < awhParams.numBias; k++)
154 const AwhBiasParams &awhBiasParams = awhParams.awhBiasParams[k];
156 std::vector<int> pullCoordIndex;
157 std::vector<DimParams> dimParams;
158 for (int d = 0; d < awhBiasParams.ndim; d++)
160 const AwhDimParams &awhDimParams = awhBiasParams.dimParams[d];
161 GMX_RELEASE_ASSERT(awhDimParams.eCoordProvider == eawhcoordproviderPULL, "Currently only the pull code is supported as coordinate provider");
162 const t_pull_coord &pullCoord = inputRecord.pull->coord[awhDimParams.coordIndex];
163 double conversionFactor = pull_coordinate_is_angletype(&pullCoord) ? DEG2RAD : 1;
164 dimParams.push_back(DimParams(conversionFactor, awhDimParams.forceConstant, beta));
166 pullCoordIndex.push_back(awhDimParams.coordIndex);
169 /* Construct the bias and couple it to the system. */
170 Bias::ThisRankWillDoIO thisRankWillDoIO = (MASTER(commRecord_) ? Bias::ThisRankWillDoIO::Yes : Bias::ThisRankWillDoIO::No);
171 biasCoupledToSystem_.emplace_back(Bias(k, awhParams, awhParams.awhBiasParams[k], dimParams, beta, inputRecord.delta_t, numSharingSimulations, biasInitFilename, thisRankWillDoIO),
172 pullCoordIndex);
174 biasCoupledToSystem_.back().bias.printInitializationToLog(fplog);
177 /* Need to register the AWH coordinates to be allowed to apply forces to the pull coordinates. */
178 registerAwhWithPull(awhParams, pull_);
180 if (numSharingSimulations > 1 && MASTER(commRecord_))
182 std::vector<size_t> pointSize;
183 for (auto const &biasCts : biasCoupledToSystem_)
185 pointSize.push_back(biasCts.bias.state().points().size());
187 /* Ensure that the shared biased are compatible between simulations */
188 biasesAreCompatibleForSharingBetweenSimulations(awhParams, pointSize, commRecord_->ms);
192 Awh::~Awh() = default;
194 bool Awh::isOutputStep(gmx_int64_t step) const
196 return (nstout_ > 0 && step % nstout_ == 0);
199 real Awh::applyBiasForcesAndUpdateBias(int ePBC,
200 const t_mdatoms &mdatoms,
201 const matrix box,
202 gmx::ForceWithVirial *forceWithVirial,
203 double t,
204 gmx_int64_t step,
205 gmx_wallcycle *wallcycle,
206 FILE *fplog)
208 GMX_ASSERT(forceWithVirial, "Need a valid ForceWithVirial object");
210 wallcycle_start(wallcycle, ewcAWH);
212 t_pbc pbc;
213 set_pbc(&pbc, ePBC, box);
215 /* During the AWH update the potential can instantaneously jump due to either
216 an bias update or moving the umbrella. The jumps are kept track of and
217 subtracted from the potential in order to get a useful conserved energy quantity. */
218 double awhPotential = potentialOffset_;
220 for (auto &biasCts : biasCoupledToSystem_)
222 /* Update the AWH coordinate values with those of the corresponding
223 * pull coordinates.
225 awh_dvec coordValue = { 0, 0, 0, 0 };
226 for (int d = 0; d < biasCts.bias.ndim(); d++)
228 coordValue[d] = get_pull_coord_value(pull_, biasCts.pullCoordIndex[d], &pbc);
231 /* Perform an AWH biasing step: this means, at regular intervals,
232 * sampling observables based on the input pull coordinate value,
233 * setting the bias force and/or updating the AWH bias state.
235 double biasPotential;
236 double biasPotentialJump;
237 /* Note: In the near future this call will be split in calls
238 * to supports bias sharing within a single simulation.
240 gmx::ArrayRef<const double> biasForce =
241 biasCts.bias.calcForceAndUpdateBias(coordValue,
242 &biasPotential, &biasPotentialJump,
243 commRecord_->ms,
244 t, step, seed_, fplog);
246 awhPotential += biasPotential;
248 /* Keep track of the total potential shift needed to remove the potential jumps. */
249 potentialOffset_ -= biasPotentialJump;
251 /* Communicate the bias force to the pull struct.
252 * The bias potential is returned at the end of this function,
253 * so that it can be added externally to the correct energy data block.
255 for (int d = 0; d < biasCts.bias.ndim(); d++)
257 apply_external_pull_coord_force(pull_, biasCts.pullCoordIndex[d],
258 biasForce[d], &mdatoms,
259 forceWithVirial);
262 if (isOutputStep(step))
264 /* We might have skipped updates for part of the grid points.
265 * Ensure all points are updated before writing out their data.
267 biasCts.bias.doSkippedUpdatesForAllPoints();
271 wallcycle_stop(wallcycle, ewcAWH);
273 return MASTER(commRecord_) ? static_cast<real>(awhPotential) : 0;
276 std::shared_ptr<AwhHistory> Awh::initHistoryFromState() const
278 if (MASTER(commRecord_))
280 std::shared_ptr<AwhHistory> awhHistory(new AwhHistory);
281 awhHistory->bias.clear();
282 awhHistory->bias.resize(biasCoupledToSystem_.size());
284 for (size_t k = 0; k < awhHistory->bias.size(); k++)
286 biasCoupledToSystem_[k].bias.initHistoryFromState(&awhHistory->bias[k]);
289 return awhHistory;
291 else
293 /* Return an empty pointer */
294 return std::shared_ptr<AwhHistory>();
298 void Awh::restoreStateFromHistory(const AwhHistory *awhHistory)
300 /* Restore the history to the current state */
301 if (MASTER(commRecord_))
303 GMX_RELEASE_ASSERT(awhHistory != nullptr, "The master rank should have a valid awhHistory when restoring the state from history.");
305 if (awhHistory->bias.size() != biasCoupledToSystem_.size())
307 GMX_THROW(InvalidInputError("AWH state and history contain different numbers of biases. Likely you provided a checkpoint from a different simulation."));
310 potentialOffset_ = awhHistory->potentialOffset;
312 if (PAR(commRecord_))
314 gmx_bcast(sizeof(potentialOffset_), &potentialOffset_, commRecord_);
317 for (size_t k = 0; k < biasCoupledToSystem_.size(); k++)
319 biasCoupledToSystem_[k].bias.restoreStateFromHistory(awhHistory ? &awhHistory->bias[k] : nullptr, commRecord_);
323 void Awh::updateHistory(AwhHistory *awhHistory) const
325 if (!MASTER(commRecord_))
327 return;
330 /* This assert will also catch a non-master rank calling this function. */
331 GMX_RELEASE_ASSERT(awhHistory->bias.size() == biasCoupledToSystem_.size(), "AWH state and history bias count should match");
333 awhHistory->potentialOffset = potentialOffset_;
335 for (size_t k = 0; k < awhHistory->bias.size(); k++)
337 biasCoupledToSystem_[k].bias.updateHistory(&awhHistory->bias[k]);
341 const char * Awh::externalPotentialString()
343 return "AWH";
346 void Awh::registerAwhWithPull(const AwhParams &awhParams,
347 pull_t *pull_work)
349 GMX_RELEASE_ASSERT(pull_work, "Need a valid pull object");
351 for (int k = 0; k < awhParams.numBias; k++)
353 const AwhBiasParams &biasParams = awhParams.awhBiasParams[k];
355 for (int d = 0; d < biasParams.ndim; d++)
357 register_external_pull_potential(pull_work, biasParams.dimParams[d].coordIndex, Awh::externalPotentialString());
362 /* Fill the AWH data block of an energy frame with data (if there is any). */
363 void Awh::writeToEnergyFrame(gmx_int64_t step,
364 t_enxframe *frame) const
366 GMX_ASSERT(MASTER(commRecord_), "writeToEnergyFrame should only be called on the master rank");
367 GMX_ASSERT(frame != nullptr, "Need a valid energy frame");
369 if (!isOutputStep(step))
371 /* This is not an AWH output step, don't write any AWH data */
372 return;
375 /* Get the total number of energy subblocks that AWH needs */
376 int numSubblocks = 0;
377 for (auto &biasCoupledToSystem : biasCoupledToSystem_)
379 numSubblocks += biasCoupledToSystem.bias.numEnergySubblocksToWrite();
381 GMX_ASSERT(numSubblocks > 0, "We should always have data to write");
383 /* Add 1 energy block */
384 add_blocks_enxframe(frame, frame->nblock + 1);
386 /* Take the block that was just added and set the number of subblocks. */
387 t_enxblock *awhEnergyBlock = &(frame->block[frame->nblock - 1]);
388 add_subblocks_enxblock(awhEnergyBlock, numSubblocks);
390 /* Claim it as an AWH block. */
391 awhEnergyBlock->id = enxAWH;
393 /* Transfer AWH data blocks to energy sub blocks */
394 int energySubblockCount = 0;
395 for (auto &biasCoupledToSystem : biasCoupledToSystem_)
397 energySubblockCount += biasCoupledToSystem.bias.writeToEnergySubblocks(&(awhEnergyBlock->sub[energySubblockCount]));
401 } // namespace gmx