2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2015,2016,2017,2018,2019, 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.
39 * Declares and defines the PointState class.
41 * Since nearly all operations on PointState objects occur in loops over
42 * (parts of) the grid of an AWH bias, all these methods should be inlined.
43 * Only samplePmf() is called only once per step and is thus not inlined.
45 * \author Viveca Lindahl
46 * \author Berk Hess <hess@kth.se>
50 #ifndef GMX_AWH_POINTSTATE_H
51 #define GMX_AWH_POINTSTATE_H
55 #include "gromacs/mdtypes/awh_history.h"
56 #include "gromacs/mdtypes/awh_params.h"
57 #include "gromacs/utility/gmxassert.h"
59 #include "biasparams.h"
67 //! A value that can be passed to exp() with result 0, also with SIMD
68 constexpr double c_largeNegativeExponent
= -10000.0;
70 //! The largest acceptable positive exponent for variables that are passed to exp().
71 constexpr double c_largePositiveExponent
= 700.0;
76 * \brief The state of a coordinate point.
78 * This class contains all the state variables of a coordinate point
79 * (on the bias grid) and methods to update the state of a point.
84 /*! \brief Constructs a point state with default values. */
85 PointState() : bias_(0),
88 targetConstantWeight_(1),
89 weightSumIteration_(0),
94 numVisitsIteration_(0),
100 * Set all values in the state to those from a history.
102 * \param[in] psh Coordinate point history to copy from.
104 void setFromHistory(const AwhPointStateHistory
&psh
)
106 target_
= psh
.target
;
107 freeEnergy_
= psh
.free_energy
;
109 weightSumIteration_
= psh
.weightsum_iteration
;
110 weightSumTot_
= psh
.weightsum_tot
;
111 weightSumRef_
= psh
.weightsum_ref
;
112 lastUpdateIndex_
= psh
.last_update_index
;
113 logPmfSum_
= psh
.log_pmfsum
;
114 numVisitsIteration_
= psh
.visits_iteration
;
115 numVisitsTot_
= psh
.visits_tot
;
119 * Store the state of a point in a history struct.
121 * \param[in,out] psh Coordinate point history to copy to.
123 void storeState(AwhPointStateHistory
*psh
) const
125 psh
->target
= target_
;
126 psh
->free_energy
= freeEnergy_
;
128 psh
->weightsum_iteration
= weightSumIteration_
;
129 psh
->weightsum_tot
= weightSumTot_
;
130 psh
->weightsum_ref
= weightSumRef_
;
131 psh
->last_update_index
= lastUpdateIndex_
;
132 psh
->log_pmfsum
= logPmfSum_
;
133 psh
->visits_iteration
= numVisitsIteration_
;
134 psh
->visits_tot
= numVisitsTot_
;
138 * Query if the point is in the target region.
140 * \returns true if the point is in the target region.
142 bool inTargetRegion() const
147 /*! \brief Return the bias function estimate. */
153 /*! \brief Set the target to zero and the bias to minus infinity. */
154 void setTargetToZero()
157 /* the bias = log(target) + const = -infty */
158 bias_
= detail::c_largeNegativeExponent
;
161 /*! \brief Return the free energy. */
162 double freeEnergy() const
167 /*! \brief Set the free energy, only to be used at initialization.
169 * \param[in] freeEnergy The free energy.
171 void setFreeEnergy(double freeEnergy
)
173 freeEnergy_
= freeEnergy
;
176 /*! \brief Return the target distribution value. */
177 double target() const
182 /*! \brief Return the weight accumulated since the last update. */
183 double weightSumIteration() const
185 return weightSumIteration_
;
188 /*! \brief Increases the weight accumulated since the last update.
190 * \param[in] weight The amount to add to the weight
192 void increaseWeightSumIteration(double weight
)
194 weightSumIteration_
+= weight
;
197 /*! \brief Returns the accumulated weight */
198 double weightSumTot() const
200 return weightSumTot_
;
203 /*! \brief Return the reference weight histogram. */
204 double weightSumRef() const
206 return weightSumRef_
;
209 /*! \brief Return log(PmfSum). */
210 double logPmfSum() const
215 /*! \brief Set log(PmfSum).
217 * TODO: Replace this setter function with a more elegant solution.
219 * \param[in] logPmfSum The log(PmfSum).
221 void setLogPmfSum(double logPmfSum
)
223 logPmfSum_
= logPmfSum
;
226 /*! \brief Return the number of visits since the last update */
227 double numVisitsIteration() const
229 return numVisitsIteration_
;
232 /*! \brief Return the total number of visits */
233 double numVisitsTot() const
235 return numVisitsTot_
;
238 /*! \brief Set the constant target weight factor.
240 * \param[in] targetConstantWeight The target weight factor.
242 void setTargetConstantWeight(double targetConstantWeight
)
244 targetConstantWeight_
= targetConstantWeight
;
247 /*! \brief Updates the bias of a point. */
250 GMX_ASSERT(target_
> 0, "AWH target distribution must be > 0 to calculate the point bias.");
252 bias_
= freeEnergy() + std::log(target_
);
255 /*! \brief Set the initial reference weighthistogram.
257 * \param[in] histogramSize The weight histogram size.
259 void setInitialReferenceWeightHistogram(double histogramSize
)
261 weightSumRef_
= histogramSize
*target_
;
264 /*! \brief Correct free energy and PMF sum for the change in minimum.
266 * \param[in] minimumFreeEnergy The free energy at the minimum;
268 void normalizeFreeEnergyAndPmfSum(double minimumFreeEnergy
)
270 if (inTargetRegion())
272 /* The sign of the free energy and PMF constants are opposite
273 * because the PMF samples are reweighted with the negative
274 * bias e^(-bias) ~ e^(-free energy).
276 freeEnergy_
-= minimumFreeEnergy
;
277 logPmfSum_
+= minimumFreeEnergy
;
281 /*! \brief Apply previous updates that were skipped.
283 * An update can only be skipped if the parameters needed for the update are constant or
284 * deterministic so that the same update can be performed at a later time.
285 * Here, the necessary parameters are the sampled weight and scaling factors for the
286 * histograms. The scaling factors are provided as arguments only to avoid recalculating
287 * them for each point
289 * The last update index is also updated here.
291 * \param[in] params The AWH bias parameters.
292 * \param[in] numUpdates The global number of updates.
293 * \param[in] weighthistScaling Scale factor for the reference weight histogram.
294 * \param[in] logPmfSumScaling Scale factor for the reference PMF histogram.
295 * \returns true if at least one update was applied.
297 bool performPreviouslySkippedUpdates(const BiasParams
¶ms
,
299 double weighthistScaling
,
300 double logPmfSumScaling
)
302 GMX_ASSERT(params
.skipUpdates(), "Calling function for skipped updates when skipping updates is not allowed");
304 if (!inTargetRegion())
309 /* The most current past update */
310 int64_t lastUpdateIndex
= numUpdates
;
311 int64_t numUpdatesSkipped
= lastUpdateIndex
- lastUpdateIndex_
;
313 if (numUpdatesSkipped
== 0)
315 /* Was not updated */
319 for (int i
= 0; i
< numUpdatesSkipped
; i
++)
321 /* This point was non-local at the time of the update meaning no weight */
322 updateFreeEnergyAndWeight(params
, 0, weighthistScaling
, logPmfSumScaling
);
325 /* Only past updates are applied here. */
326 lastUpdateIndex_
= lastUpdateIndex
;
331 /*! \brief Apply a point update with new sampling.
333 * \note The last update index is also updated here.
334 * \note The new sampling containers are cleared here.
336 * \param[in] params The AWH bias parameters.
337 * \param[in] numUpdates The global number of updates.
338 * \param[in] weighthistScaling Scaling factor for the reference weight histogram.
339 * \param[in] logPmfSumScaling Log of the scaling factor for the PMF histogram.
341 void updateWithNewSampling(const BiasParams
¶ms
,
343 double weighthistScaling
,
344 double logPmfSumScaling
)
346 GMX_RELEASE_ASSERT(lastUpdateIndex_
== numUpdates
, "When doing a normal update, the point update index should match the global index, otherwise we lost (skipped?) updates.");
348 updateFreeEnergyAndWeight(params
, weightSumIteration_
, weighthistScaling
, logPmfSumScaling
);
349 lastUpdateIndex_
+= 1;
351 /* Clear the iteration collection data */
352 weightSumIteration_
= 0;
353 numVisitsIteration_
= 0;
357 /*! \brief Update the PMF histogram with the current coordinate value.
359 * \param[in] convolvedBias The convolved bias.
361 void samplePmf(double convolvedBias
);
364 /*! \brief Update the free energy estimate of a point.
366 * The free energy update here is inherently local, i.e. it just depends on local sampling and on constant
367 * AWH parameters. This assumes that the variables used here are kept constant, at least in between
370 * \param[in] params The AWH bias parameters.
371 * \param[in] weightAtPoint Sampled probability weight at this point.
373 void updateFreeEnergy(const BiasParams
¶ms
,
374 double weightAtPoint
)
376 double weighthistSampled
= weightSumRef() + weightAtPoint
;
377 double weighthistTarget
= weightSumRef() + params
.updateWeight
*target_
;
379 double df
= -std::log(weighthistSampled
/weighthistTarget
);
382 GMX_RELEASE_ASSERT(std::abs(freeEnergy_
) < detail::c_largePositiveExponent
,
383 "Very large free energy differences or badly normalized free energy in AWH update.");
386 /*! \brief Update the reference weight histogram of a point.
388 * \param[in] params The AWH bias parameters.
389 * \param[in] weightAtPoint Sampled probability weight at this point.
390 * \param[in] scaleFactor Factor to rescale the histogram with.
392 void updateWeightHistogram(const BiasParams
¶ms
,
393 double weightAtPoint
,
396 if (params
.idealWeighthistUpdate
)
398 /* Grow histogram using the target distribution. */
399 weightSumRef_
+= target_
*params
.updateWeight
*params
.localWeightScaling
;
403 /* Grow using the actual samples (which are distributed ~ as target). */
404 weightSumRef_
+= weightAtPoint
*params
.localWeightScaling
;
407 weightSumRef_
*= scaleFactor
;
410 /*! \brief Apply a point update.
412 * This updates local properties that can be updated without
413 * accessing or affecting all points.
414 * This excludes updating the size of reference weight histogram and
415 * the target distribution. The bias update is excluded only because
416 * if updates have been skipped this function will be called multiple
417 * times, while the bias only needs to be updated once (last).
419 * Since this function only performs the update with the given
420 * arguments and does not know anything about the time of the update,
421 * the last update index is not updated here. The caller should take
422 * care of updating the update index.
424 * \param[in] params The AWH bias parameters.
425 * \param[in] weightAtPoint Sampled probability weight at this point.
426 * \param[in] weighthistScaling Scaling factor for the reference weight histogram.
427 * \param[in] logPmfSumScaling Log of the scaling factor for the PMF histogram.
429 void updateFreeEnergyAndWeight(const BiasParams
¶ms
,
430 double weightAtPoint
,
431 double weighthistScaling
,
432 double logPmfSumScaling
)
434 updateFreeEnergy(params
, weightAtPoint
);
435 updateWeightHistogram(params
, weightAtPoint
, weighthistScaling
);
436 logPmfSum_
+= logPmfSumScaling
;
441 /*! \brief Update the target weight of a point.
443 * Note that renormalization over all points is needed after the update.
445 * \param[in] params The AWH bias parameters.
446 * \param[in] freeEnergyCutoff The cut-off for the free energy for target type "cutoff".
447 * \returns the updated value of the target.
449 double updateTargetWeight(const BiasParams
¶ms
,
450 double freeEnergyCutoff
)
452 switch (params
.eTarget
)
454 case eawhtargetCONSTANT
:
457 case eawhtargetCUTOFF
:
459 double df
= freeEnergy_
- freeEnergyCutoff
;
460 target_
= 1/(1 + std::exp(df
));
463 case eawhtargetBOLTZMANN
:
464 target_
= std::exp(-params
.temperatureScaleFactor
*freeEnergy_
);
466 case eawhtargetLOCALBOLTZMANN
:
467 target_
= weightSumRef_
;
471 /* All target types can be modulated by a constant factor. */
472 target_
*= targetConstantWeight_
;
477 /*! \brief Set the weight and count accumulated since the last update.
479 * \param[in] weightSum The weight-sum value
480 * \param[in] numVisits The number of visits
482 void setPartialWeightAndCount(double weightSum
,
485 weightSumIteration_
= weightSum
;
486 numVisitsIteration_
= numVisits
;
489 /*! \brief Add the weights and counts accumulated between updates. */
490 void addPartialWeightAndCount()
492 weightSumTot_
+= weightSumIteration_
;
493 numVisitsTot_
+= numVisitsIteration_
;
496 /*! \brief Scale the target weight of the point.
498 * \param[in] scaleFactor Factor to scale with.
500 void scaleTarget(double scaleFactor
)
502 target_
*= scaleFactor
;
506 double bias_
; /**< Current biasing function estimate */
507 double freeEnergy_
; /**< Current estimate of the convolved free energy/PMF. */
508 double target_
; /**< Current target distribution, normalized to 1 */
509 double targetConstantWeight_
; /**< Constant target weight, from user data. */
510 double weightSumIteration_
; /**< Accumulated weight this iteration; note: only contains data for this Bias, even when sharing biases. */
511 double weightSumTot_
; /**< Accumulated weights, never reset */
512 double weightSumRef_
; /**< The reference weight histogram determining the free energy updates */
513 int64_t lastUpdateIndex_
; /**< The last update that was performed at this point, in units of number of updates. */
514 double logPmfSum_
; /**< Logarithm of the PMF histogram */
515 double numVisitsIteration_
; /**< Visits to this bin this iteration; note: only contains data for this Bias, even when sharing biases. */
516 double numVisitsTot_
; /**< Accumulated visits to this bin */
521 #endif /* GMX_AWH_POINTSTATE_H */