Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / awh / grid.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35
36 /*! \internal \file
37  * \brief
38  * Implements functions in grid.h.
39  *
40  * \author Viveca Lindahl
41  * \author Berk Hess <hess@kth.se>
42  * \ingroup module_awh
43  */
44
45 #include "gmxpre.h"
46
47 #include "grid.h"
48
49 #include <cassert>
50 #include <cmath>
51 #include <cstring>
52
53 #include <algorithm>
54
55 #include "gromacs/math/functions.h"
56 #include "gromacs/math/utilities.h"
57 #include "gromacs/mdtypes/awh_params.h"
58 #include "gromacs/utility/cstringutil.h"
59 #include "gromacs/utility/exceptions.h"
60 #include "gromacs/utility/gmxassert.h"
61 #include "gromacs/utility/smalloc.h"
62 #include "gromacs/utility/stringutil.h"
63
64 namespace gmx
65 {
66
67 namespace
68 {
69
70 /*! \brief
71  * Modify x so that it is periodic in [-period/2, +period/2).
72  *
73  * x is modified by shifting its value by a +/- a period if
74  * needed. Thus, it is assumed that x is at most one period
75  * away from this interval. For period = 0, x is not modified.
76  *
77  * \param[in,out] x       Pointer to the value to modify.
78  * \param[in]     period  The period, or 0 if not periodic.
79  */
80 void centerPeriodicValueAroundZero(double* x, double period)
81 {
82     GMX_ASSERT(period >= 0, "Periodic should not be negative");
83
84     const double halfPeriod = period * 0.5;
85
86     if (*x >= halfPeriod)
87     {
88         *x -= period;
89     }
90     else if (*x < -halfPeriod)
91     {
92         *x += period;
93     }
94 }
95
96 /*! \brief
97  * If period>0, retrun x so that it is periodic in [0, period), else return x.
98  *
99  * Return x is shifted its value by a +/- a period, if
100  * needed. Thus, it is assumed that x is at most one period
101  * away from this interval. For this domain and period > 0
102  * this is equivalent to x = x % period. For period = 0,
103  * x is not modified.
104  *
105  * \param[in,out] x       Pointer to the value to modify, should be >= 0.
106  * \param[in]     period  The period, or 0 if not periodic.
107  * \returns for period>0: index value witin [0, period), otherwise: \p x.
108  */
109 int indexWithinPeriod(int x, int period)
110 {
111     GMX_ASSERT(period >= 0, "Periodic should not be negative");
112
113     if (period == 0)
114     {
115         return x;
116     }
117
118     GMX_ASSERT(x > -period && x < 2 * period,
119                "x should not be more shifted by more than one period");
120
121     if (x >= period)
122     {
123         return x - period;
124     }
125     else if (x < 0)
126     {
127         return x + period;
128     }
129     else
130     {
131         return x;
132     }
133 }
134
135 /*! \brief
136  * Get the length of the interval (origin, end).
137  *
138  * This returns the distance obtained by connecting the origin point to
139  * the end point in the positive direction. Note that this is generally
140  * not the shortest distance. For period > 0, both origin and
141  * end are expected to take values in the same periodic interval,
142  * ie. |origin - end| < period.
143  *
144  * \param[in] origin    Start value of the interval.
145  * \param[in] end       End value of the interval.
146  * \param[in] period    The period, or 0 if not periodic.
147  * \returns the interval length from origin to end.
148  */
149 double getIntervalLengthPeriodic(double origin, double end, double period)
150 {
151     double length = end - origin;
152     if (length < 0)
153     {
154         /* The interval wraps around the +/- boundary which has a discontinuous jump of -period. */
155         length += period;
156     }
157
158     GMX_RELEASE_ASSERT(length >= 0, "Negative AWH grid axis length.");
159     GMX_RELEASE_ASSERT(period == 0 || length <= period, "Interval length longer than period.");
160
161     return length;
162 }
163
164 /*! \brief
165  * Get the deviation x - x0.
166  *
167  * For period > 0, the deviation with minimum absolute value is returned,
168  * i.e. with a value in the interval [-period/2, +period/2).
169  * Also for period > 0, it is assumed that |x - x0| < period.
170  *
171  * \param[in] x        From value.
172  * \param[in] x0       To value.
173  * \param[in] period   The period, or 0 if not periodic.
174  * \returns the deviation from x to x0.
175  */
176 double getDeviationPeriodic(double x, double x0, double period)
177 {
178     double dev = x - x0;
179
180     if (period > 0)
181     {
182         centerPeriodicValueAroundZero(&dev, period);
183     }
184
185     return dev;
186 }
187
188 } // namespace
189
190 double getDeviationFromPointAlongGridAxis(const Grid& grid, int dimIndex, int pointIndex, double value)
191 {
192     double coordValue = grid.point(pointIndex).coordValue[dimIndex];
193
194     return getDeviationPeriodic(value, coordValue, grid.axis(dimIndex).period());
195 }
196
197 void linearArrayIndexToMultiDim(int indexLinear, int numDimensions, const awh_ivec numPointsDim, awh_ivec indexMulti)
198 {
199     for (int d = 0; d < numDimensions; d++)
200     {
201         int stride = 1;
202
203         for (int k = d + 1; k < numDimensions; k++)
204         {
205             stride *= numPointsDim[k];
206         }
207
208         indexMulti[d] = indexLinear / stride;
209         indexLinear -= indexMulti[d] * stride;
210     }
211 }
212
213 void linearGridindexToMultiDim(const Grid& grid, int indexLinear, awh_ivec indexMulti)
214 {
215     awh_ivec  numPointsDim;
216     const int numDimensions = grid.numDimensions();
217     for (int d = 0; d < numDimensions; d++)
218     {
219         numPointsDim[d] = grid.axis(d).numPoints();
220     }
221
222     linearArrayIndexToMultiDim(indexLinear, numDimensions, numPointsDim, indexMulti);
223 }
224
225
226 int multiDimArrayIndexToLinear(const awh_ivec indexMulti, int numDimensions, const awh_ivec numPointsDim)
227 {
228     int stride      = 1;
229     int indexLinear = 0;
230     for (int d = numDimensions - 1; d >= 0; d--)
231     {
232         indexLinear += stride * indexMulti[d];
233         stride *= numPointsDim[d];
234     }
235
236     return indexLinear;
237 }
238
239 namespace
240 {
241
242 /*! \brief Convert a multidimensional grid point index to a linear one.
243  *
244  * \param[in] axis       The grid axes.
245  * \param[in] indexMulti Multidimensional grid point index to convert to a linear one.
246  * \returns the linear index.
247  */
248 int multiDimGridIndexToLinear(const std::vector<GridAxis>& axis, const awh_ivec indexMulti)
249 {
250     awh_ivec numPointsDim = { 0 };
251
252     for (size_t d = 0; d < axis.size(); d++)
253     {
254         numPointsDim[d] = axis[d].numPoints();
255     }
256
257     return multiDimArrayIndexToLinear(indexMulti, axis.size(), numPointsDim);
258 }
259
260 } // namespace
261
262 int multiDimGridIndexToLinear(const Grid& grid, const awh_ivec indexMulti)
263 {
264     return multiDimGridIndexToLinear(grid.axis(), indexMulti);
265 }
266
267 namespace
268 {
269
270 /*! \brief
271  * Take a step in a multidimensional array.
272  *
273  * The multidimensional index gives the starting point to step from. Dimensions are
274  * stepped through in order of decreasing dimensional index such that the index is
275  * incremented in the highest dimension possible. If the starting point is the end
276  * of the array, a step cannot be taken and the index is not modified.
277  *
278  * \param[in] numDim        Number of dimensions of the array.
279  * \param[in] numPoints     Vector with the number of points along each dimension.
280  * \param[in,out] indexDim  Multidimensional index, each with values in [0, numPoints[d] - 1].
281  * \returns true if a step was taken, false if not.
282  */
283 bool stepInMultiDimArray(int numDim, const awh_ivec numPoints, awh_ivec indexDim)
284 {
285     bool haveStepped = false;
286
287     for (int d = numDim - 1; d >= 0 && !haveStepped; d--)
288     {
289         if (indexDim[d] < numPoints[d] - 1)
290         {
291             /* Not at a boundary, just increase by 1. */
292             indexDim[d]++;
293             haveStepped = true;
294         }
295         else
296         {
297             /* At a boundary. If we are not at the end of the array,
298                reset the index and check if we can step in higher dimensions */
299             if (d > 0)
300             {
301                 indexDim[d] = 0;
302             }
303         }
304     }
305
306     return haveStepped;
307 }
308
309 /*! \brief
310  * Transforms a grid point index to to the multidimensional index of a subgrid.
311  *
312  * The subgrid is defined by the location of its origin and the number of points
313  * along each dimension. The index transformation thus consists of a projection
314  * of the linear index onto each dimension, followed by a translation of the origin.
315  * The subgrid may have parts that don't overlap with the grid. E.g. the origin
316  * vector can have negative components meaning the origin lies outside of the grid.
317  * However, the given point needs to be both a grid and subgrid point.
318  *
319  * Periodic boundaries are taken care of by wrapping the subgrid around the grid.
320  * Thus, for periodic dimensions the number of subgrid points need to be less than
321  * the number of points in a period to prevent problems of wrapping around.
322  *
323  * \param[in]     grid            The grid.
324  * \param[in]     subgridOrigin   Vector locating the subgrid origin relative to the grid origin.
325  * \param[in]     subgridNpoints  The number of subgrid points in each dimension.
326  * \param[in]     point           Grid point to get subgrid index for.
327  * \param[in,out] subgridIndex    Subgrid multidimensional index.
328  */
329 void gridToSubgridIndex(const Grid&    grid,
330                         const awh_ivec subgridOrigin,
331                         const awh_ivec subgridNpoints,
332                         int            point,
333                         awh_ivec       subgridIndex)
334 {
335     /* Get the subgrid index of the given grid point, for each dimension. */
336     for (int d = 0; d < grid.numDimensions(); d++)
337     {
338         /* The multidimensional grid point index relative to the subgrid origin. */
339         subgridIndex[d] = indexWithinPeriod(grid.point(point).index[d] - subgridOrigin[d],
340                                             grid.axis(d).numPointsInPeriod());
341
342         /* The given point should be in the subgrid. */
343         GMX_RELEASE_ASSERT((subgridIndex[d] >= 0) && (subgridIndex[d] < subgridNpoints[d]),
344                            "Attempted to convert an AWH grid point index not in subgrid to out of "
345                            "bounds subgrid index");
346     }
347 }
348
349 /*! \brief
350  * Transform a multidimensional subgrid index to a grid point index.
351  *
352  * If the given subgrid point is not a grid point the transformation will not be successful
353  * and the grid point index will not be set. Periodic boundaries are taken care of by
354  * wrapping the subgrid around the grid.
355  *
356  * \param[in]     grid           The grid.
357  * \param[in]     subgridOrigin  Vector locating the subgrid origin relative to the grid origin.
358  * \param[in]     subgridIndex   Subgrid multidimensional index to get grid point index for.
359  * \param[in,out] gridIndex      Grid point index.
360  * \returns true if the transformation was successful.
361  */
362 bool subgridToGridIndex(const Grid& grid, const awh_ivec subgridOrigin, const awh_ivec subgridIndex, int* gridIndex)
363 {
364     awh_ivec globalIndexDim;
365
366     /* Check and apply boundary conditions for each dimension */
367     for (int d = 0; d < grid.numDimensions(); d++)
368     {
369         /* Transform to global multidimensional indexing by adding the origin */
370         globalIndexDim[d] = subgridOrigin[d] + subgridIndex[d];
371
372         /* The local grid is allowed to stick out on the edges of the global grid. Here the boundary conditions are applied.*/
373         if (globalIndexDim[d] < 0 || globalIndexDim[d] > grid.axis(d).numPoints() - 1)
374         {
375             /* Try to wrap around if periodic. Otherwise, the transformation failed so return. */
376             if (!grid.axis(d).isPeriodic())
377             {
378                 return false;
379             }
380
381             /* The grid might not contain a whole period. Can only wrap around if this gap is not too large. */
382             int gap = grid.axis(d).numPointsInPeriod() - grid.axis(d).numPoints();
383
384             int bridge;
385             int numWrapped;
386             if (globalIndexDim[d] < 0)
387             {
388                 bridge     = -globalIndexDim[d];
389                 numWrapped = bridge - gap;
390                 if (numWrapped > 0)
391                 {
392                     globalIndexDim[d] = grid.axis(d).numPoints() - numWrapped;
393                 }
394             }
395             else
396             {
397                 bridge     = globalIndexDim[d] - (grid.axis(d).numPoints() - 1);
398                 numWrapped = bridge - gap;
399                 if (numWrapped > 0)
400                 {
401                     globalIndexDim[d] = numWrapped - 1;
402                 }
403             }
404
405             if (numWrapped <= 0)
406             {
407                 return false;
408             }
409         }
410     }
411
412     /* Translate from multidimensional to linear indexing and set the return value */
413     (*gridIndex) = multiDimGridIndexToLinear(grid, globalIndexDim);
414
415     return true;
416 }
417
418 } // namespace
419
420 bool advancePointInSubgrid(const Grid&    grid,
421                            const awh_ivec subgridOrigin,
422                            const awh_ivec subgridNumPoints,
423                            int*           gridPointIndex)
424 {
425     /* Initialize the subgrid index to the subgrid origin. */
426     awh_ivec subgridIndex = { 0 };
427
428     /* Get the subgrid index of the given grid point index. */
429     if (*gridPointIndex >= 0)
430     {
431         gridToSubgridIndex(grid, subgridOrigin, subgridNumPoints, *gridPointIndex, subgridIndex);
432     }
433     else
434     {
435         /* If no grid point is given we start at the subgrid origin (which subgridIndex is initialized to).
436            If this is a valid grid point then we're done, otherwise keep looking below. */
437         /* TODO: separate into a separate function (?) */
438         if (subgridToGridIndex(grid, subgridOrigin, subgridIndex, gridPointIndex))
439         {
440             return true;
441         }
442     }
443
444     /* Traverse the subgrid and look for the first point that is also in the grid. */
445     while (stepInMultiDimArray(grid.numDimensions(), subgridNumPoints, subgridIndex))
446     {
447         /* If this is a valid grid point, the grid point index is updated.*/
448         if (subgridToGridIndex(grid, subgridOrigin, subgridIndex, gridPointIndex))
449         {
450             return true;
451         }
452     }
453
454     return false;
455 }
456
457 /*! \brief
458  * Returns the point distance between from value x to value x0 along the given axis.
459  *
460  * Note that the returned distance may be negative or larger than the
461  * number of points in the axis. For a periodic axis, the distance is chosen
462  * to be in [0, period), i.e. always positive but not the shortest one.
463  *
464  * \param[in]  axis   Grid axis.
465  * \param[in]  x      From value.
466  * \param[in]  x0     To value.
467  * \returns (x - x0) in number of points.
468  */
469 static int pointDistanceAlongAxis(const GridAxis& axis, double x, double x0)
470 {
471     int distance = 0;
472
473     if (axis.spacing() > 0)
474     {
475         /* Get the real-valued distance. For a periodic axis, the shortest one. */
476         double period = axis.period();
477         double dx     = getDeviationPeriodic(x, x0, period);
478
479         /* Transform the distance into a point distance by rounding. */
480         distance = gmx::roundToInt(dx / axis.spacing());
481
482         /* If periodic, shift the point distance to be in [0, period) */
483         distance = indexWithinPeriod(distance, axis.numPointsInPeriod());
484     }
485
486     return distance;
487 }
488
489 /*! \brief
490  * Query if a value is in range of the grid.
491  *
492  * \param[in] value   Value to check.
493  * \param[in] axis    The grid axes.
494  * \returns true if the value is in the grid.
495  */
496 static bool valueIsInGrid(const awh_dvec value, const std::vector<GridAxis>& axis)
497 {
498     /* For each dimension get the one-dimensional index and check if it is in range. */
499     for (size_t d = 0; d < axis.size(); d++)
500     {
501         /* The index is computed as the point distance from the origin. */
502         int index = pointDistanceAlongAxis(axis[d], value[d], axis[d].origin());
503
504         if (!(index >= 0 && index < axis[d].numPoints()))
505         {
506             return false;
507         }
508     }
509
510     return true;
511 }
512
513 bool Grid::covers(const awh_dvec value) const
514 {
515     return valueIsInGrid(value, axis());
516 }
517
518 int GridAxis::nearestIndex(double value) const
519 {
520     /* Get the point distance to the origin. This may by an out of index range for the axis. */
521     int index = pointDistanceAlongAxis(*this, value, origin_);
522
523     if (index < 0 || index >= numPoints_)
524     {
525         if (isPeriodic())
526         {
527             GMX_RELEASE_ASSERT(index >= 0 && index < numPointsInPeriod_,
528                                "Index not in periodic interval 0 for AWH periodic axis");
529             int endDistance    = (index - (numPoints_ - 1));
530             int originDistance = (numPointsInPeriod_ - index);
531             index              = originDistance < endDistance ? 0 : numPoints_ - 1;
532         }
533         else
534         {
535             index = (index < 0) ? 0 : (numPoints_ - 1);
536         }
537     }
538
539     return index;
540 }
541
542 /*! \brief
543  * Map a value to the nearest point in the grid.
544  *
545  * \param[in] value  Value.
546  * \param[in] axis   The grid axes.
547  * \returns the point index nearest to the value.
548  */
549 static int getNearestIndexInGrid(const awh_dvec value, const std::vector<GridAxis>& axis)
550 {
551     awh_ivec indexMulti;
552
553     /* If the index is out of range, modify it so that it is in range by choosing the nearest point on the edge. */
554     for (size_t d = 0; d < axis.size(); d++)
555     {
556         indexMulti[d] = axis[d].nearestIndex(value[d]);
557     }
558
559     return multiDimGridIndexToLinear(axis, indexMulti);
560 }
561
562 int Grid::nearestIndex(const awh_dvec value) const
563 {
564     return getNearestIndexInGrid(value, axis());
565 }
566
567 namespace
568 {
569
570 /*! \brief
571  * Find and set the neighbors of a grid point.
572  *
573  * The search space for neighbors is a subgrid with size set by a scope cutoff.
574  * In general not all point within scope will be valid grid points.
575  *
576  * \param[in]     pointIndex           Grid point index.
577  * \param[in]     grid                 The grid.
578  * \param[in,out] neighborIndexArray   Array to fill with neighbor indices.
579  */
580 void setNeighborsOfGridPoint(int pointIndex, const Grid& grid, std::vector<int>* neighborIndexArray)
581 {
582     const int c_maxNeighborsAlongAxis =
583             1 + 2 * static_cast<int>(Grid::c_numPointsPerSigma * Grid::c_scopeCutoff);
584
585     awh_ivec numCandidates = { 0 };
586     awh_ivec subgridOrigin = { 0 };
587     for (int d = 0; d < grid.numDimensions(); d++)
588     {
589         /* The number of candidate points along this dimension is given by the scope cutoff. */
590         numCandidates[d] = std::min(c_maxNeighborsAlongAxis, grid.axis(d).numPoints());
591
592         /* The origin of the subgrid to search */
593         int centerIndex  = grid.point(pointIndex).index[d];
594         subgridOrigin[d] = centerIndex - numCandidates[d] / 2;
595     }
596
597     /* Find and set the neighbors */
598     int  neighborIndex = -1;
599     bool aPointExists  = true;
600
601     /* Keep looking for grid points while traversing the subgrid. */
602     while (aPointExists)
603     {
604         /* The point index is updated if a grid point was found. */
605         aPointExists = advancePointInSubgrid(grid, subgridOrigin, numCandidates, &neighborIndex);
606
607         if (aPointExists)
608         {
609             neighborIndexArray->push_back(neighborIndex);
610         }
611     }
612 }
613
614 } // namespace
615
616 void Grid::initPoints()
617 {
618     awh_ivec numPointsDimWork = { 0 };
619     awh_ivec indexWork        = { 0 };
620
621     for (size_t d = 0; d < axis_.size(); d++)
622     {
623         /* Temporarily gather the number of points in each dimension in one array */
624         numPointsDimWork[d] = axis_[d].numPoints();
625     }
626
627     for (auto& point : point_)
628     {
629         for (size_t d = 0; d < axis_.size(); d++)
630         {
631             point.coordValue[d] = axis_[d].origin() + indexWork[d] * axis_[d].spacing();
632
633             if (axis_[d].period() > 0)
634             {
635                 /* Do we always want the values to be centered around 0 ? */
636                 centerPeriodicValueAroundZero(&point.coordValue[d], axis_[d].period());
637             }
638
639             point.index[d] = indexWork[d];
640         }
641
642         stepInMultiDimArray(axis_.size(), numPointsDimWork, indexWork);
643     }
644 }
645
646 GridAxis::GridAxis(double origin, double end, double period, double pointDensity) :
647     origin_(origin),
648     period_(period)
649 {
650     length_ = getIntervalLengthPeriodic(origin_, end, period_);
651
652     /* Automatically determine number of points based on the user given endpoints
653        and the expected fluctuations in the umbrella. */
654     if (length_ == 0)
655     {
656         numPoints_ = 1;
657     }
658     else if (pointDensity == 0)
659     {
660         numPoints_ = 2;
661     }
662     else
663     {
664         /* An extra point is added here to account for the endpoints. The
665            minimum number of points for a non-zero interval is 2. */
666         numPoints_ = 1 + static_cast<int>(std::ceil(length_ * pointDensity));
667     }
668
669     /* Set point spacing based on the number of points */
670     if (isPeriodic())
671     {
672         /* Set the grid spacing so that a period is matched exactly by an integer number of points.
673            The number of points in a period is equal to the number of grid spacings in a period
674            since the endpoints are connected.  */
675         numPointsInPeriod_ =
676                 length_ > 0 ? static_cast<int>(std::ceil(period / length_ * (numPoints_ - 1))) : 1;
677         spacing_ = period_ / numPointsInPeriod_;
678
679         /* Modify the number of grid axis points to be compatible with the period dependent spacing. */
680         numPoints_ = std::min(static_cast<int>(round(length_ / spacing_)) + 1, numPointsInPeriod_);
681     }
682     else
683     {
684         numPointsInPeriod_ = 0;
685         spacing_           = numPoints_ > 1 ? length_ / (numPoints_ - 1) : 0;
686     }
687 }
688
689 GridAxis::GridAxis(double origin, double end, double period, int numPoints) :
690     origin_(origin),
691     period_(period),
692     numPoints_(numPoints)
693 {
694     length_            = getIntervalLengthPeriodic(origin_, end, period_);
695     spacing_           = numPoints_ > 1 ? length_ / (numPoints_ - 1) : period_;
696     numPointsInPeriod_ = static_cast<int>(std::round(period_ / spacing_));
697 }
698
699 Grid::Grid(const std::vector<DimParams>& dimParams, const AwhDimParams* awhDimParams)
700 {
701     /* Define the discretization along each dimension */
702     awh_dvec period;
703     int      numPoints = 1;
704     for (size_t d = 0; d < dimParams.size(); d++)
705     {
706         double origin = dimParams[d].scaleUserInputToInternal(awhDimParams[d].origin);
707         double end    = dimParams[d].scaleUserInputToInternal(awhDimParams[d].end);
708         period[d]     = dimParams[d].scaleUserInputToInternal(awhDimParams[d].period);
709         static_assert(c_numPointsPerSigma >= 1.0,
710                       "The number of points per sigma should be at least 1.0 to get a uniformly "
711                       "covering the reaction using Gaussians");
712         double pointDensity = std::sqrt(dimParams[d].betak) * c_numPointsPerSigma;
713         axis_.emplace_back(origin, end, period[d], pointDensity);
714         numPoints *= axis_[d].numPoints();
715     }
716
717     point_.resize(numPoints);
718
719     /* Set their values */
720     initPoints();
721
722     /* Keep a neighbor list for each point.
723      * Note: could also generate neighbor list only when needed
724      * instead of storing them for each point.
725      */
726     for (size_t m = 0; m < point_.size(); m++)
727     {
728         std::vector<int>* neighbor = &point_[m].neighbor;
729
730         setNeighborsOfGridPoint(m, *this, neighbor);
731     }
732 }
733
734 void mapGridToDataGrid(std::vector<int>*    gridpointToDatapoint,
735                        const double* const* data,
736                        int                  numDataPoints,
737                        const std::string&   dataFilename,
738                        const Grid&          grid,
739                        const std::string&   correctFormatMessage)
740 {
741     /* Transform the data into a grid in order to map each grid point to a data point
742        using the grid functions. */
743
744     /* Count the number of points for each dimension. Each dimension
745        has its own stride. */
746     int              stride           = 1;
747     int              numPointsCounted = 0;
748     std::vector<int> numPoints(grid.numDimensions());
749     for (int d = grid.numDimensions() - 1; d >= 0; d--)
750     {
751         int    numPointsInDim = 0;
752         int    pointIndex     = 0;
753         double firstValue     = data[d][pointIndex];
754         do
755         {
756             numPointsInDim++;
757             pointIndex += stride;
758         } while (pointIndex < numDataPoints
759                  && !gmx_within_tol(firstValue, data[d][pointIndex], GMX_REAL_EPS));
760
761         /* The stride in dimension dimension d - 1 equals the number of points
762            dimension d. */
763         stride = numPointsInDim;
764
765         numPointsCounted = (numPointsCounted == 0) ? numPointsInDim : numPointsCounted * numPointsInDim;
766
767         numPoints[d] = numPointsInDim;
768     }
769
770     if (numPointsCounted != numDataPoints)
771     {
772         std::string mesg = gmx::formatString(
773                 "Could not extract data properly from %s. Wrong data format?"
774                 "\n\n%s",
775                 dataFilename.c_str(), correctFormatMessage.c_str());
776         GMX_THROW(InvalidInputError(mesg));
777     }
778
779     std::vector<GridAxis> axis_;
780     axis_.reserve(grid.numDimensions());
781     /* The data grid has the data that was read and the properties of the AWH grid */
782     for (int d = 0; d < grid.numDimensions(); d++)
783     {
784         axis_.emplace_back(data[d][0], data[d][numDataPoints - 1], grid.axis(d).period(), numPoints[d]);
785     }
786
787     /* Map each grid point to a data point. No interpolation, just pick the nearest one.
788      * It is assumed that the given data is uniformly spaced for each dimension.
789      */
790     for (size_t m = 0; m < grid.numPoints(); m++)
791     {
792         /* We only define what we need for the datagrid since it's not needed here which is a bit ugly */
793
794         if (!valueIsInGrid(grid.point(m).coordValue, axis_))
795         {
796             std::string mesg = gmx::formatString(
797                     "%s does not contain data for all coordinate values. "
798                     "Make sure your input data covers the whole sampling domain "
799                     "and is correctly formatted. \n\n%s",
800                     dataFilename.c_str(), correctFormatMessage.c_str());
801             GMX_THROW(InvalidInputError(mesg));
802         }
803         (*gridpointToDatapoint)[m] = getNearestIndexInGrid(grid.point(m).coordValue, axis_);
804     }
805 }
806
807 } // namespace gmx