Change use of t_inpfile to std::vector
[gromacs.git] / src / gromacs / awh / read-params.cpp
blobb9b33f933540d21b7f0737ff2e96f31e5fb5a377
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "gmxpre.h"
39 #include "read-params.h"
41 #include "gromacs/awh/awh.h"
42 #include "gromacs/fileio/readinp.h"
43 #include "gromacs/fileio/warninp.h"
44 #include "gromacs/math/units.h"
45 #include "gromacs/math/utilities.h"
46 #include "gromacs/math/vec.h"
47 #include "gromacs/mdtypes/awh-params.h"
48 #include "gromacs/mdtypes/inputrec.h"
49 #include "gromacs/mdtypes/md_enums.h"
50 #include "gromacs/mdtypes/pull-params.h"
51 #include "gromacs/pbcutil/pbc.h"
52 #include "gromacs/pulling/pull.h"
53 #include "gromacs/random/seed.h"
54 #include "gromacs/utility/cstringutil.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/smalloc.h"
58 #include "biasparams.h"
59 #include "biassharing.h"
61 namespace gmx
64 const char *eawhtarget_names[eawhtargetNR+1] = {
65 "constant", "cutoff", "boltzmann", "local-boltzmann", nullptr
68 const char *eawhgrowth_names[eawhgrowthNR+1] = {
69 "exp-linear", "linear", nullptr
72 const char *eawhpotential_names[eawhpotentialNR+1] = {
73 "convolved", "umbrella", nullptr
76 const char *eawhcoordprovider_names[eawhcoordproviderNR+1] = {
77 "pull", nullptr
80 /*! \brief
81 * Read parameters of an AWH bias dimension.
83 * \param[in,out] inp Input file entries.
84 * \param[in] prefix Prefix for dimension parameters.
85 * \param[in,out] dimParams AWH dimensional parameters.
86 * \param[in] pull_params Pull parameters.
87 * \param[in,out] wi Struct for bookeeping warnings.
88 * \param[in] bComment True if comments should be printed.
90 static void readDimParams(std::vector<t_inpfile> *inp, const char *prefix,
91 AwhDimParams *dimParams, const pull_params_t *pull_params,
92 warninp_t wi, bool bComment)
94 char warningmsg[STRLEN];
96 if (bComment)
98 printStringNoNewline(inp, "The provider of the reaction coordinate, currently only pull is supported");
100 char opt[STRLEN];
101 sprintf(opt, "%s-coord-provider", prefix);
102 dimParams->eCoordProvider = get_eeenum(inp, opt, eawhcoordprovider_names, wi);
104 if (bComment)
106 printStringNoNewline(inp, "The coordinate index for this dimension");
108 sprintf(opt, "%s-coord-index", prefix);
109 int coordIndexInput;
110 coordIndexInput = get_eint(inp, opt, 1, wi);
111 if (coordIndexInput < 1)
113 gmx_fatal(FARGS, "Failed to read a valid coordinate index for %s. "
114 "Note that the pull coordinate indexing starts at 1.", opt);
117 /* The pull coordinate indices start at 1 in the input file, at 0 internally */
118 dimParams->coordIndex = coordIndexInput - 1;
120 /* The pull settings need to be consistent with the AWH settings */
121 if (!(pull_params->coord[dimParams->coordIndex].eType == epullEXTERNAL) )
123 gmx_fatal(FARGS, "AWH biasing can only be applied to pull type %s",
124 EPULLTYPE(epullEXTERNAL));
127 if (dimParams->coordIndex >= pull_params->ncoord)
129 gmx_fatal(FARGS, "The given AWH coordinate index (%d) is larger than the number of pull coordinates (%d)",
130 coordIndexInput, pull_params->ncoord);
132 if (pull_params->coord[dimParams->coordIndex].rate != 0)
134 sprintf(warningmsg, "Setting pull-coord%d-rate (%g) is incompatible with AWH biasing this coordinate", coordIndexInput, pull_params->coord[dimParams->coordIndex].rate);
135 warning_error(wi, warningmsg);
138 /* Grid params for each axis */
139 int eGeom = pull_params->coord[dimParams->coordIndex].eGeom;
141 if (bComment)
143 printStringNoNewline(inp, "Start and end values for each coordinate dimension");
146 sprintf(opt, "%s-start", prefix);
147 dimParams->origin = get_ereal(inp, opt, 0., wi);
149 sprintf(opt, "%s-end", prefix);
150 dimParams->end = get_ereal(inp, opt, 0., wi);
152 if (gmx_within_tol(dimParams->end - dimParams->origin, 0, GMX_REAL_EPS))
154 sprintf(warningmsg, "The given interval length given by %s-start (%g) and %s-end (%g) is zero. "
155 "This will result in only one point along this axis in the coordinate value grid.",
156 prefix, dimParams->origin, prefix, dimParams->end);
157 warning(wi, warningmsg);
159 /* Check that the requested interval is in allowed range */
160 if (eGeom == epullgDIST)
162 if (dimParams->origin < 0 || dimParams->end < 0)
164 gmx_fatal(FARGS, "%s-start (%g) or %s-end (%g) set to a negative value. With pull geometry distance coordinate values are non-negative. "
165 "Perhaps you want to use geometry %s instead?",
166 prefix, dimParams->origin, prefix, dimParams->end, EPULLGEOM(epullgDIR));
169 else if (eGeom == epullgANGLE || eGeom == epullgANGLEAXIS)
171 if (dimParams->origin < 0 || dimParams->end > 180)
173 gmx_fatal(FARGS, "%s-start (%g) and %s-end (%g) are outside of the allowed range 0 to 180 deg for pull geometries %s and %s ",
174 prefix, dimParams->origin, prefix, dimParams->end, EPULLGEOM(epullgANGLE), EPULLGEOM(epullgANGLEAXIS));
177 else if (eGeom == epullgDIHEDRAL)
179 if (dimParams->origin < -180 || dimParams->end > 180)
181 gmx_fatal(FARGS, "%s-start (%g) and %s-end (%g) are outside of the allowed range -180 to 180 deg for pull geometry %s. ",
182 prefix, dimParams->origin, prefix, dimParams->end, EPULLGEOM(epullgDIHEDRAL));
186 if (bComment)
188 printStringNoNewline(inp, "The force constant for this coordinate (kJ/mol/nm^2 or kJ/mol/rad^2)");
190 sprintf(opt, "%s-force-constant", prefix);
191 dimParams->forceConstant = get_ereal(inp, opt, 0, wi);
192 if (dimParams->forceConstant <= 0)
194 warning_error(wi, "The force AWH bias force constant should be > 0");
197 if (bComment)
199 printStringNoNewline(inp, "Estimated diffusion constant (nm^2/ps or rad^2/ps)");
201 sprintf(opt, "%s-diffusion", prefix);
202 dimParams->diffusion = get_ereal(inp, opt, 0, wi);
204 if (dimParams->diffusion <= 0)
206 const double diffusion_default = 1e-5;
207 sprintf(warningmsg, "%s not explicitly set by user."
208 " You can choose to use a default value (%g nm^2/ps or rad^2/ps) but this may very well be non-optimal for your system!",
209 opt, diffusion_default);
210 warning(wi, warningmsg);
211 dimParams->diffusion = diffusion_default;
214 if (bComment)
216 printStringNoNewline(inp, "Diameter that needs to be sampled around a point before it is considered covered.");
218 sprintf(opt, "%s-cover-diameter", prefix);
219 dimParams->coverDiameter = get_ereal(inp, opt, 0, wi);
221 if (dimParams->coverDiameter < 0)
223 gmx_fatal(FARGS, "%s (%g) cannot be negative.",
224 opt, dimParams->coverDiameter);
228 /*! \brief
229 * Check consistency of input at the AWH bias level.
231 * \param[in] awhBiasParams AWH bias parameters.
232 * \param[in,out] wi Struct for bookkeeping warnings.
234 static void checkInputConsistencyAwhBias(const AwhBiasParams &awhBiasParams,
235 warninp_t wi)
237 /* Covering diameter and sharing warning. */
238 for (int d = 0; d < awhBiasParams.ndim; d++)
240 double coverDiameter = awhBiasParams.dimParams[d].coverDiameter;
241 if (awhBiasParams.shareGroup <= 0 && coverDiameter > 0)
243 warning(wi, "The covering diameter is only relevant to set for bias sharing simulations.");
248 /*! \brief
249 * Read parameters of an AWH bias.
251 * \param[in,out] inp Input file entries.
252 * \param[in,out] awhBiasParams AWH dimensional parameters.
253 * \param[in] prefix Prefix for bias parameters.
254 * \param[in] ir Input parameter struct.
255 * \param[in,out] wi Struct for bookeeping warnings.
256 * \param[in] bComment True if comments should be printed.
258 static void read_bias_params(std::vector<t_inpfile> *inp, AwhBiasParams *awhBiasParams, const char *prefix,
259 const t_inputrec *ir, warninp_t wi, bool bComment)
261 char opt[STRLEN], prefixdim[STRLEN];
262 char warningmsg[STRLEN];
264 if (bComment)
266 printStringNoNewline(inp, "Estimated initial PMF error (kJ/mol)");
268 sprintf(opt, "%s-error-init", prefix);
270 /* We allow using a default value here without warning (but warn the user if the diffusion constant is not set). */
271 awhBiasParams->errorInitial = get_ereal(inp, opt, 10, wi);
272 if (awhBiasParams->errorInitial <= 0)
274 gmx_fatal(FARGS, "%s (%d) needs to be > 0.", opt);
277 if (bComment)
279 printStringNoNewline(inp, "Growth rate of the reference histogram determining the bias update size: exp-linear or linear");
281 sprintf(opt, "%s-growth", prefix);
282 awhBiasParams->eGrowth = get_eeenum(inp, opt, eawhgrowth_names, wi);
284 if (bComment)
286 printStringNoNewline(inp, "Start the simulation by equilibrating histogram towards the target distribution: no or yes");
288 sprintf(opt, "%s-equilibrate-histogram", prefix);
289 awhBiasParams->equilibrateHistogram = get_eeenum(inp, opt, yesno_names, wi);
290 if (awhBiasParams->equilibrateHistogram && awhBiasParams->eGrowth != eawhgrowthEXP_LINEAR)
292 sprintf(warningmsg, "Option %s will only have an effect for histogram growth type '%s'.",
293 opt, EAWHGROWTH(eawhgrowthEXP_LINEAR));
294 warning(wi, warningmsg);
297 if (bComment)
299 printStringNoNewline(inp, "Target distribution type: constant, cutoff, boltzmann or local-boltzmann");
301 sprintf(opt, "%s-target", prefix);
302 awhBiasParams->eTarget = get_eeenum(inp, opt, eawhtarget_names, wi);
304 if ((awhBiasParams->eTarget == eawhtargetLOCALBOLTZMANN) &&
305 (awhBiasParams->eGrowth == eawhgrowthEXP_LINEAR))
307 sprintf(warningmsg, "Target type '%s' combined with histogram growth type '%s' is not "
308 "expected to give stable bias updates. You probably want to use growth type "
309 "'%s' instead.",
310 EAWHTARGET(eawhtargetLOCALBOLTZMANN), EAWHGROWTH(eawhgrowthEXP_LINEAR),
311 EAWHGROWTH(eawhgrowthLINEAR));
312 warning(wi, warningmsg);
315 if (bComment)
317 printStringNoNewline(inp, "Boltzmann beta scaling factor for target distribution types 'boltzmann' and 'boltzmann-local'");
319 sprintf(opt, "%s-target-beta-scaling", prefix);
320 awhBiasParams->targetBetaScaling = get_ereal(inp, opt, 0, wi);
322 switch (awhBiasParams->eTarget)
324 case eawhtargetBOLTZMANN:
325 case eawhtargetLOCALBOLTZMANN:
326 if (awhBiasParams->targetBetaScaling < 0 || awhBiasParams->targetBetaScaling > 1)
328 gmx_fatal(FARGS, "%s = %g is not useful for target type %s.",
329 opt, awhBiasParams->targetBetaScaling, EAWHTARGET(awhBiasParams->eTarget));
331 break;
332 default:
333 if (awhBiasParams->targetBetaScaling != 0)
335 gmx_fatal(FARGS, "Value for %s (%g) set explicitly but will not be used for target type %s.",
336 opt, awhBiasParams->targetBetaScaling, EAWHTARGET(awhBiasParams->eTarget));
338 break;
341 if (bComment)
343 printStringNoNewline(inp, "Free energy cutoff value for target distribution type 'cutoff'");
345 sprintf(opt, "%s-target-cutoff", prefix);
346 awhBiasParams->targetCutoff = get_ereal(inp, opt, 0, wi);
348 switch (awhBiasParams->eTarget)
350 case eawhtargetCUTOFF:
351 if (awhBiasParams->targetCutoff <= 0)
353 gmx_fatal(FARGS, "%s = %g is not useful for target type %s.",
354 opt, awhBiasParams->targetCutoff, EAWHTARGET(awhBiasParams->eTarget));
356 break;
357 default:
358 if (awhBiasParams->targetCutoff != 0)
360 gmx_fatal(FARGS, "Value for %s (%g) set explicitly but will not be used for target type %s.",
361 opt, awhBiasParams->targetCutoff, EAWHTARGET(awhBiasParams->eTarget));
363 break;
366 if (bComment)
368 printStringNoNewline(inp, "Initialize PMF and target with user data: no or yes");
370 sprintf(opt, "%s-user-data", prefix);
371 awhBiasParams->bUserData = get_eeenum(inp, opt, yesno_names, wi);
373 if (bComment)
375 printStringNoNewline(inp, "Group index to share the bias with, 0 means not shared");
377 sprintf(opt, "%s-share-group", prefix);
378 awhBiasParams->shareGroup = get_eint(inp, opt, 0, wi);
379 if (awhBiasParams->shareGroup < 0)
381 warning_error(wi, "AWH bias share-group should be >= 0");
384 if (bComment)
386 printStringNoNewline(inp, "Dimensionality of the coordinate");
388 sprintf(opt, "%s-ndim", prefix);
389 awhBiasParams->ndim = get_eint(inp, opt, 0, wi);
391 if (awhBiasParams->ndim <= 0 ||
392 awhBiasParams->ndim > c_biasMaxNumDim)
394 gmx_fatal(FARGS, "%s-ndim (%d) needs to be > 0 and at most %d\n", prefix, awhBiasParams->ndim, c_biasMaxNumDim);
396 if (awhBiasParams->ndim > 2)
398 warning_note(wi, "For awh-dim > 2 the estimate based on the diffusion and the initial error is currently only a rough guideline."
399 " You should verify its usefulness for your system before production runs!");
401 snew(awhBiasParams->dimParams, awhBiasParams->ndim);
402 for (int d = 0; d < awhBiasParams->ndim; d++)
404 bComment = bComment && d == 0;
405 sprintf(prefixdim, "%s-dim%d", prefix, d + 1);
406 readDimParams(inp, prefixdim, &awhBiasParams->dimParams[d], ir->pull, wi, bComment);
409 /* Check consistencies here that cannot be checked at read time at a lower level. */
410 checkInputConsistencyAwhBias(*awhBiasParams, wi);
413 /*! \brief
414 * Check consistency of input at the AWH level.
416 * \param[in] awhParams AWH parameters.
417 * \param[in,out] wi Struct for bookkeeping warnings.
419 static void checkInputConsistencyAwh(const AwhParams &awhParams,
420 warninp_t wi)
422 /* Each pull coord can map to at most 1 AWH coord.
423 * Check that we have a shared bias when requesting multisim sharing.
425 bool haveSharedBias = false;
426 for (int k1 = 0; k1 < awhParams.numBias; k1++)
428 const AwhBiasParams &awhBiasParams1 = awhParams.awhBiasParams[k1];
430 if (awhBiasParams1.shareGroup > 0)
432 haveSharedBias = true;
435 /* k1 is the reference AWH, k2 is the AWH we compare with (can be equal to k1) */
436 for (int k2 = k1; k2 < awhParams.numBias; k2++)
438 for (int d1 = 0; d1 < awhBiasParams1.ndim; d1++)
440 const AwhBiasParams &awhBiasParams2 = awhParams.awhBiasParams[k2];
442 /* d1 is the reference dimension of the reference AWH. d2 is the dim index of the AWH to compare with. */
443 for (int d2 = 0; d2 < awhBiasParams2.ndim; d2++)
445 /* Give an error if (d1, k1) is different from (d2, k2) but the pull coordinate is the same */
446 if ( (d1 != d2 || k1 != k2) && (awhBiasParams1.dimParams[d1].coordIndex == awhBiasParams2.dimParams[d2].coordIndex) )
448 char errormsg[STRLEN];
449 sprintf(errormsg, "One pull coordinate (%d) cannot be mapped to two separate AWH dimensions (awh%d-dim%d and awh%d-dim%d). "
450 "If this is really what you want to do you will have to duplicate this pull coordinate.",
451 awhBiasParams1.dimParams[d1].coordIndex + 1, k1 + 1, d1 + 1, k2 + 1, d2 + 1);
452 gmx_fatal(FARGS, errormsg);
459 if (awhParams.shareBiasMultisim && !haveSharedBias)
461 warning(wi, "Sharing of biases over multiple simulations is requested, but no bias is marked as shared (share-group > 0)");
464 /* mdrun does not support this (yet), but will check again */
465 if (haveBiasSharingWithinSimulation(awhParams))
467 warning(wi, "You have shared biases within a single simulation, but mdrun does not support this (yet)");
471 AwhParams *readAndCheckAwhParams(std::vector<t_inpfile> *inp, const t_inputrec *ir, warninp_t wi)
473 char opt[STRLEN], prefix[STRLEN], prefixawh[STRLEN];
475 AwhParams *awhParams;
476 snew(awhParams, 1);
478 sprintf(prefix, "%s", "awh");
480 /* Parameters common for all biases */
482 printStringNoNewline(inp, "The way to apply the biasing potential: convolved or umbrella");
483 sprintf(opt, "%s-potential", prefix);
484 awhParams->ePotential = get_eeenum(inp, opt, eawhpotential_names, wi);
486 printStringNoNewline(inp, "The random seed used for sampling the umbrella center in the case of umbrella type potential");
487 sprintf(opt, "%s-seed", prefix);
488 awhParams->seed = get_eint(inp, opt, -1, wi);
489 if (awhParams->seed == -1)
491 awhParams->seed = static_cast<int>(gmx::makeRandomSeed());
492 fprintf(stderr, "Setting the AWH bias MC random seed to %" GMX_PRId64 "\n", awhParams->seed);
495 printStringNoNewline(inp, "Data output interval in number of steps");
496 sprintf(opt, "%s-nstout", prefix);
497 awhParams->nstOut = get_eint(inp, opt, 100000, wi);
498 if (awhParams->nstOut <= 0)
500 char buf[STRLEN];
501 sprintf(buf, "Not writing AWH output with AWH (%s = %d) does not make sense",
502 opt, awhParams->nstOut);
503 warning_error(wi, buf);
505 /* This restriction can be removed by changing a flag of print_ebin() */
506 if (ir->nstenergy == 0 || awhParams->nstOut % ir->nstenergy != 0)
508 char buf[STRLEN];
509 sprintf(buf, "%s (%d) should be a multiple of nstenergy (%d)",
510 opt, awhParams->nstOut, ir->nstenergy);
511 warning_error(wi, buf);
514 printStringNoNewline(inp, "Coordinate sampling interval in number of steps");
515 sprintf(opt, "%s-nstsample", prefix);
516 awhParams->nstSampleCoord = get_eint(inp, opt, 10, wi);
518 printStringNoNewline(inp, "Free energy and bias update interval in number of samples");
519 sprintf(opt, "%s-nsamples-update", prefix);
520 awhParams->numSamplesUpdateFreeEnergy = get_eint(inp, opt, 10, wi);
522 printStringNoNewline(inp, "When true, biases with share-group>0 are shared between multiple simulations");
523 sprintf(opt, "%s-share-multisim", prefix);
524 awhParams->shareBiasMultisim = get_eeenum(inp, opt, yesno_names, wi);
526 printStringNoNewline(inp, "The number of independent AWH biases");
527 sprintf(opt, "%s-nbias", prefix);
528 awhParams->numBias = get_eint(inp, opt, 1, wi);
529 if (awhParams->numBias <= 0)
531 gmx_fatal(FARGS, "%s needs to be an integer > 0", opt);
534 /* Read the parameters specific to each AWH bias */
535 snew(awhParams->awhBiasParams, awhParams->numBias);
537 for (int k = 0; k < awhParams->numBias; k++)
539 bool bComment = (k == 0);
540 sprintf(prefixawh, "%s%d", prefix, k + 1);
541 read_bias_params(inp, &awhParams->awhBiasParams[k], prefixawh, ir, wi, bComment);
544 /* Do a final consistency check before returning */
545 checkInputConsistencyAwh(*awhParams, wi);
547 if (ir->init_step != 0)
549 warning_error(wi, "With AWH init-step should be 0");
552 return awhParams;
555 /*! \brief
556 * Gets the period of a pull coordinate.
558 * \param[in] pull_params Pull parameters.
559 * \param[in] coord_ind Pull coordinate index.
560 * \param[in] box Box vectors.
561 * \returns the period (or 0 if not periodic).
563 static double get_pull_coord_period(const pull_params_t *pull_params,
564 int coord_ind,
565 const matrix box)
567 double period;
568 t_pull_coord *pcrd_params = &pull_params->coord[coord_ind];
570 if (pcrd_params->eGeom == epullgDIRPBC)
572 /* For direction periodic, we need the pull vector to be one of the box vectors
573 (or more generally I guess it could be an integer combination of boxvectors).
574 This boxvector should to be orthogonal to the (periodic) plane spanned by the other two box vectors.
575 Here we assume that the pull vector is either x, y or z.
576 * E.g. for pull vec = (1, 0, 0) the box vector tensor should look like:
577 * | x 0 0 |
578 * | 0 a c |
579 * | 0 b d |
581 The period is then given by the box length x.
583 Note: we make these checks here for AWH and not in pull because we allow pull to be more general.
585 int m_pullvec = -1, count_nonzeros = 0;
587 /* Check that pull vec has only one component and which component it is. This component gives the relevant box vector */
588 for (int m = 0; m < DIM; m++)
590 if (pcrd_params->vec[m] != 0)
592 m_pullvec = m;
593 count_nonzeros++;
596 if (count_nonzeros != 1)
598 gmx_fatal(FARGS, "For AWH biasing pull coordinate %d with pull geometry %s, the pull vector needs to be parallel to "
599 "a box vector that is parallel to either the x, y or z axis and is orthogonal to the other box vectors.",
600 coord_ind + 1, EPULLGEOM(epullgDIRPBC));
603 /* Check that there is a box vec parallel to pull vec and that this boxvec is orthogonal to the other box vectors */
604 for (int m = 0; m < DIM; m++)
606 for (int n = 0; n < DIM; n++)
608 if ((n != m) && (n == m_pullvec || m == m_pullvec) && box[m][n] > 0)
610 gmx_fatal(FARGS, "For AWH biasing pull coordinate %d with pull geometry %s, there needs to be a box vector parallel to the pull vector that is "
611 "orthogonal to the other box vectors.",
612 coord_ind + 1, EPULLGEOM(epullgDIRPBC));
617 /* If this box vector only has one component as we assumed the norm should be equal to the absolute value of that component */
618 period = static_cast<double>(norm(box[m_pullvec]));
620 else if (pcrd_params->eGeom == epullgDIHEDRAL)
622 /* The dihedral angle is periodic in -180 to 180 deg */
623 period = 360;
625 else
627 period = 0;
630 return period;
633 /*! \brief
634 * Checks if the given interval is defined in the correct periodic interval.
636 * \param[in] origin Start value of interval.
637 * \param[in] end End value of interval.
638 * \param[in] period Period (or 0 if not periodic).
639 * \returns true if the end point values are in the correct periodic interval.
641 static bool intervalIsInPeriodicInterval(double origin, double end, double period)
643 return (period == 0) || (std::fabs(origin) <= 0.5*period && std::fabs(end) <= 0.5*period);
646 /*! \brief
647 * Checks if a value is within an interval.
649 * \param[in] origin Start value of interval.
650 * \param[in] end End value of interval.
651 * \param[in] period Period (or 0 if not periodic).
652 * \param[in] value Value to check.
653 * \returns true if the value is within the interval.
655 static bool valueIsInInterval(double origin, double end, double period, double value)
657 bool bIn_interval;
659 if (period > 0)
661 if (origin < end)
663 /* The interval closes within the periodic interval */
664 bIn_interval = (value >= origin) && (value <= end);
666 else
668 /* The interval wraps around the periodic boundary */
669 bIn_interval = ((value >= origin) && (value <= 0.5*period)) || ((value >= -0.5*period) && (value <= end));
672 else
674 bIn_interval = (value >= origin) && (value <= end);
677 return bIn_interval;
680 /*! \brief
681 * Check if the starting configuration is consistent with the given interval.
683 * \param[in] awhParams AWH parameters.
684 * \param[in,out] wi Struct for bookeeping warnings.
686 static void checkInputConsistencyInterval(const AwhParams *awhParams, warninp_t wi)
688 for (int k = 0; k < awhParams->numBias; k++)
690 AwhBiasParams *awhBiasParams = &awhParams->awhBiasParams[k];
691 for (int d = 0; d < awhBiasParams->ndim; d++)
693 AwhDimParams *dimParams = &awhBiasParams->dimParams[d];
694 int coordIndex = dimParams->coordIndex;
695 double origin = dimParams->origin, end = dimParams->end, period = dimParams->period;
696 double coordValueInit = dimParams->coordValueInit;
698 if ((period == 0) && (origin > end))
700 gmx_fatal(FARGS, "For the non-periodic pull coordinates awh%d-dim%d-start cannot be larger than awh%d-dim%d-end",
701 k + 1, d + 1, origin, k + 1, d + 1, end);
704 /* Currently we assume symmetric periodic intervals, meaning we use [-period/2, period/2] as the reference interval.
705 Make sure the AWH interval is within this reference interval.
707 Note: we could fairly simply allow using a more general interval (e.g. [x, x + period]) but it complicates
708 things slightly and I don't see that there is a great need for it. It would also mean that the interval would
709 depend on AWH input. Also, for dihedral angles you would always want the reference interval to be -180, +180,
710 independent of AWH parameters.
712 if (!intervalIsInPeriodicInterval(origin, end, period))
714 gmx_fatal(FARGS, "When using AWH with periodic pull coordinate geometries awh%d-dim%d-start (%.8g) and "
715 "awh%d-dim%d-end (%.8g) should cover at most one period (%.8g) and take values in between "
716 "minus half a period and plus half a period, i.e. in the interval [%.8g, %.8g].",
717 k + 1, d + 1, origin, k + 1, d + 1, end,
718 period, -0.5*period, 0.5*period);
722 /* Warn if the pull initial coordinate value is not in the grid */
723 if (!valueIsInInterval(origin, end, period, coordValueInit))
725 char warningmsg[STRLEN];
726 sprintf(warningmsg, "The initial coordinate value (%.8g) for pull coordinate index %d falls outside "
727 "of the sampling nterval awh%d-dim%d-start (%.8g) to awh%d-dim%d-end (%.8g). "
728 "This can lead to large initial forces pulling the coordinate towards the sampling interval.",
729 coordValueInit, coordIndex + 1,
730 k + 1, d + 1, origin, k + 1, d + 1, end);
731 warning(wi, warningmsg);
737 void setStateDependentAwhParams(AwhParams *awhParams,
738 const pull_params_t *pull_params, pull_t *pull_work,
739 const matrix box, int ePBC,
740 const t_grpopts *inputrecGroupOptions, warninp_t wi)
742 /* The temperature is not really state depenendent but is not known
743 * when read_awhParams is called (in get ir).
744 * It is known first after do_index has been called in grompp.cpp.
746 if (inputrecGroupOptions->ref_t == NULL ||
747 inputrecGroupOptions->ref_t[0] <= 0)
749 gmx_fatal(FARGS, "AWH biasing is only supported for temperatures > 0");
751 for (int i = 1; i < inputrecGroupOptions->ngtc; i++)
753 if (inputrecGroupOptions->ref_t[i] != inputrecGroupOptions->ref_t[0])
755 gmx_fatal(FARGS, "AWH biasing is currently only supported for identical temperatures for all temperature coupling groups");
759 t_pbc pbc;
760 set_pbc(&pbc, ePBC, box);
762 for (int k = 0; k < awhParams->numBias; k++)
764 AwhBiasParams *awhBiasParams = &awhParams->awhBiasParams[k];
765 for (int d = 0; d < awhBiasParams->ndim; d++)
767 AwhDimParams *dimParams = &awhBiasParams->dimParams[d];
769 /* The periodiciy of the AWH grid in certain cases depends on the simulation box */
770 dimParams->period = get_pull_coord_period(pull_params, dimParams->coordIndex, box);
772 /* The initial coordinate value, converted to external user units. */
773 dimParams->coordValueInit =
774 get_pull_coord_value(pull_work, dimParams->coordIndex, &pbc);
776 t_pull_coord *pullCoord = &pull_params->coord[dimParams->coordIndex];
777 dimParams->coordValueInit *= pull_conversion_factor_internal2userinput(pullCoord);
780 checkInputConsistencyInterval(awhParams, wi);
782 /* Register AWH as external potential with pull to check consistency. */
783 Awh::registerAwhWithPull(*awhParams, pull_work);
786 } // namespace gmx