2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, 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.
38 * Implements functions in grid.h.
40 * \author Viveca Lindahl
41 * \author Berk Hess <hess@kth.se>
56 #include "gromacs/math/functions.h"
57 #include "gromacs/math/utilities.h"
58 #include "gromacs/mdtypes/awh_params.h"
59 #include "gromacs/utility/cstringutil.h"
60 #include "gromacs/utility/exceptions.h"
61 #include "gromacs/utility/gmxassert.h"
62 #include "gromacs/utility/smalloc.h"
63 #include "gromacs/utility/stringutil.h"
72 * Return x so that it is periodic in [-period/2, +period/2).
74 * x is modified by shifting its value by a +/- a period if
75 * needed. Thus, it is assumed that x is at most one period
76 * away from this interval. For period = 0, x is not modified.
78 * \param[in] x Pointer to the value to modify.
79 * \param[in] period The period, or 0 if not periodic.
80 * \returns Value that is within the period.
82 double centerPeriodicValueAroundZero(const double x, double period)
84 GMX_ASSERT(period >= 0, "Periodic should not be negative");
86 const double halfPeriod = period * 0.5;
88 double valueInPeriod = x;
90 if (valueInPeriod >= halfPeriod)
92 valueInPeriod -= period;
94 else if (valueInPeriod < -halfPeriod)
96 valueInPeriod += period;
102 * If period>0, retrun x so that it is periodic in [0, period), else return x.
104 * Return x is shifted its value by a +/- a period, if
105 * needed. Thus, it is assumed that x is at most one period
106 * away from this interval. For this domain and period > 0
107 * this is equivalent to x = x % period. For period = 0,
110 * \param[in,out] x Pointer to the value to modify, should be >= 0.
111 * \param[in] period The period, or 0 if not periodic.
112 * \returns for period>0: index value witin [0, period), otherwise: \p x.
114 int indexWithinPeriod(int x, int period)
116 GMX_ASSERT(period >= 0, "Periodic should not be negative");
123 GMX_ASSERT(x > -period && x < 2 * period,
124 "x should not be more shifted by more than one period");
141 * Get the length of the interval (origin, end).
143 * This returns the distance obtained by connecting the origin point to
144 * the end point in the positive direction. Note that this is generally
145 * not the shortest distance. For period > 0, both origin and
146 * end are expected to take values in the same periodic interval,
147 * ie. |origin - end| < period.
149 * \param[in] origin Start value of the interval.
150 * \param[in] end End value of the interval.
151 * \param[in] period The period, or 0 if not periodic.
152 * \returns the interval length from origin to end.
154 double getIntervalLengthPeriodic(double origin, double end, double period)
156 double length = end - origin;
159 /* The interval wraps around the +/- boundary which has a discontinuous jump of -period. */
163 GMX_RELEASE_ASSERT(length >= 0, "Negative AWH grid axis length.");
164 GMX_RELEASE_ASSERT(period == 0 || length <= period, "Interval length longer than period.");
170 * Get the deviation x - x0.
172 * For period > 0, the deviation with minimum absolute value is returned,
173 * i.e. with a value in the interval [-period/2, +period/2).
174 * Also for period > 0, it is assumed that |x - x0| < period.
176 * \param[in] x From value.
177 * \param[in] x0 To value.
178 * \param[in] period The period, or 0 if not periodic.
179 * \returns the deviation from x to x0.
181 double getDeviationPeriodic(double x, double x0, double period)
187 dev = centerPeriodicValueAroundZero(dev, period);
195 double getDeviationFromPointAlongGridAxis(const BiasGrid& grid, int dimIndex, int pointIndex, double value)
197 double coordValue = grid.point(pointIndex).coordValue[dimIndex];
199 return getDeviationPeriodic(value, coordValue, grid.axis(dimIndex).period());
202 double getDeviationFromPointAlongGridAxis(const BiasGrid& grid, int dimIndex, int pointIndex1, int pointIndex2)
204 double coordValue1 = grid.point(pointIndex1).coordValue[dimIndex];
205 double coordValue2 = grid.point(pointIndex2).coordValue[dimIndex];
207 return getDeviationPeriodic(coordValue1, coordValue2, grid.axis(dimIndex).period());
210 bool pointsAlongLambdaAxis(const BiasGrid& grid, int pointIndex1, int pointIndex2)
212 if (!grid.hasLambdaAxis())
216 if (pointIndex1 == pointIndex2)
220 const int numDimensions = grid.numDimensions();
221 for (int d = 0; d < numDimensions; d++)
223 if (grid.axis(d).isFepLambdaAxis())
225 if (getDeviationFromPointAlongGridAxis(grid, d, pointIndex1, pointIndex2) == 0)
232 if (getDeviationFromPointAlongGridAxis(grid, d, pointIndex1, pointIndex2) != 0)
241 bool pointsHaveDifferentLambda(const BiasGrid& grid, int pointIndex1, int pointIndex2)
243 if (!grid.hasLambdaAxis())
247 if (pointIndex1 == pointIndex2)
251 const int numDimensions = grid.numDimensions();
252 for (int d = 0; d < numDimensions; d++)
254 if (grid.axis(d).isFepLambdaAxis())
256 if (getDeviationFromPointAlongGridAxis(grid, d, pointIndex1, pointIndex2) != 0)
265 void linearArrayIndexToMultiDim(int indexLinear, int numDimensions, const awh_ivec numPointsDim, awh_ivec indexMulti)
267 for (int d = 0; d < numDimensions; d++)
271 for (int k = d + 1; k < numDimensions; k++)
273 stride *= numPointsDim[k];
276 indexMulti[d] = indexLinear / stride;
277 indexLinear -= indexMulti[d] * stride;
281 void linearGridindexToMultiDim(const BiasGrid& grid, int indexLinear, awh_ivec indexMulti)
283 awh_ivec numPointsDim;
284 const int numDimensions = grid.numDimensions();
285 for (int d = 0; d < numDimensions; d++)
287 numPointsDim[d] = grid.axis(d).numPoints();
290 linearArrayIndexToMultiDim(indexLinear, numDimensions, numPointsDim, indexMulti);
294 int multiDimArrayIndexToLinear(const awh_ivec indexMulti, int numDimensions, const awh_ivec numPointsDim)
298 for (int d = numDimensions - 1; d >= 0; d--)
300 indexLinear += stride * indexMulti[d];
301 stride *= numPointsDim[d];
310 /*! \brief Convert a multidimensional grid point index to a linear one.
312 * \param[in] axis The grid axes.
313 * \param[in] indexMulti Multidimensional grid point index to convert to a linear one.
314 * \returns the linear index.
316 int multiDimGridIndexToLinear(ArrayRef<const GridAxis> axis, const awh_ivec indexMulti)
318 awh_ivec numPointsDim = { 0 };
320 for (size_t d = 0; d < axis.size(); d++)
322 numPointsDim[d] = axis[d].numPoints();
325 return multiDimArrayIndexToLinear(indexMulti, axis.size(), numPointsDim);
330 int multiDimGridIndexToLinear(const BiasGrid& grid, const awh_ivec indexMulti)
332 return multiDimGridIndexToLinear(grid.axis(), indexMulti);
339 * Take a step in a multidimensional array.
341 * The multidimensional index gives the starting point to step from. Dimensions are
342 * stepped through in order of decreasing dimensional index such that the index is
343 * incremented in the highest dimension possible. If the starting point is the end
344 * of the array, a step cannot be taken and the index is not modified.
346 * \param[in] numDim Number of dimensions of the array.
347 * \param[in] numPoints Vector with the number of points along each dimension.
348 * \param[in,out] indexDim Multidimensional index, each with values in [0, numPoints[d] - 1].
349 * \returns true if a step was taken, false if not.
351 bool stepInMultiDimArray(int numDim, const awh_ivec numPoints, awh_ivec indexDim)
353 bool haveStepped = false;
355 for (int d = numDim - 1; d >= 0 && !haveStepped; d--)
357 if (indexDim[d] < numPoints[d] - 1)
359 /* Not at a boundary, just increase by 1. */
365 /* At a boundary. If we are not at the end of the array,
366 reset the index and check if we can step in higher dimensions */
378 * Transforms a grid point index to to the multidimensional index of a subgrid.
380 * The subgrid is defined by the location of its origin and the number of points
381 * along each dimension. The index transformation thus consists of a projection
382 * of the linear index onto each dimension, followed by a translation of the origin.
383 * The subgrid may have parts that don't overlap with the grid. E.g. the origin
384 * vector can have negative components meaning the origin lies outside of the grid.
385 * However, the given point needs to be both a grid and subgrid point.
387 * Periodic boundaries are taken care of by wrapping the subgrid around the grid.
388 * Thus, for periodic dimensions the number of subgrid points need to be less than
389 * the number of points in a period to prevent problems of wrapping around.
391 * \param[in] grid The grid.
392 * \param[in] subgridOrigin Vector locating the subgrid origin relative to the grid origin.
393 * \param[in] subgridNpoints The number of subgrid points in each dimension.
394 * \param[in] point BiasGrid point to get subgrid index for.
395 * \param[in,out] subgridIndex Subgrid multidimensional index.
397 void gridToSubgridIndex(const BiasGrid& grid,
398 const awh_ivec subgridOrigin,
399 const awh_ivec subgridNpoints,
401 awh_ivec subgridIndex)
403 /* Get the subgrid index of the given grid point, for each dimension. */
404 for (int d = 0; d < grid.numDimensions(); d++)
406 /* The multidimensional grid point index relative to the subgrid origin. */
407 subgridIndex[d] = indexWithinPeriod(grid.point(point).index[d] - subgridOrigin[d],
408 grid.axis(d).numPointsInPeriod());
410 /* The given point should be in the subgrid. */
411 GMX_RELEASE_ASSERT((subgridIndex[d] >= 0) && (subgridIndex[d] < subgridNpoints[d]),
412 "Attempted to convert an AWH grid point index not in subgrid to out of "
413 "bounds subgrid index");
418 * Transform a multidimensional subgrid index to a grid point index.
420 * If the given subgrid point is not a grid point the transformation will not be successful
421 * and the grid point index will not be set. Periodic boundaries are taken care of by
422 * wrapping the subgrid around the grid.
424 * \param[in] grid The grid.
425 * \param[in] subgridOrigin Vector locating the subgrid origin relative to the grid origin.
426 * \param[in] subgridIndex Subgrid multidimensional index to get grid point index for.
427 * \param[in,out] gridIndex BiasGrid point index.
428 * \returns true if the transformation was successful.
430 bool subgridToGridIndex(const BiasGrid& grid, const awh_ivec subgridOrigin, const awh_ivec subgridIndex, int* gridIndex)
432 awh_ivec globalIndexDim;
434 /* Check and apply boundary conditions for each dimension */
435 for (int d = 0; d < grid.numDimensions(); d++)
437 /* Transform to global multidimensional indexing by adding the origin */
438 globalIndexDim[d] = subgridOrigin[d] + subgridIndex[d];
440 /* The local grid is allowed to stick out on the edges of the global grid. Here the boundary conditions are applied.*/
441 if (globalIndexDim[d] < 0 || globalIndexDim[d] > grid.axis(d).numPoints() - 1)
443 /* Try to wrap around if periodic. Otherwise, the transformation failed so return. */
444 if (!grid.axis(d).isPeriodic())
449 /* The grid might not contain a whole period. Can only wrap around if this gap is not too large. */
450 int gap = grid.axis(d).numPointsInPeriod() - grid.axis(d).numPoints();
454 if (globalIndexDim[d] < 0)
456 bridge = -globalIndexDim[d];
457 numWrapped = bridge - gap;
460 globalIndexDim[d] = grid.axis(d).numPoints() - numWrapped;
465 bridge = globalIndexDim[d] - (grid.axis(d).numPoints() - 1);
466 numWrapped = bridge - gap;
469 globalIndexDim[d] = numWrapped - 1;
480 /* Translate from multidimensional to linear indexing and set the return value */
481 (*gridIndex) = multiDimGridIndexToLinear(grid, globalIndexDim);
488 bool advancePointInSubgrid(const BiasGrid& grid,
489 const awh_ivec subgridOrigin,
490 const awh_ivec subgridNumPoints,
493 /* Initialize the subgrid index to the subgrid origin. */
494 awh_ivec subgridIndex = { 0 };
496 /* Get the subgrid index of the given grid point index. */
497 if (*gridPointIndex >= 0)
499 gridToSubgridIndex(grid, subgridOrigin, subgridNumPoints, *gridPointIndex, subgridIndex);
503 /* If no grid point is given we start at the subgrid origin (which subgridIndex is initialized to).
504 If this is a valid grid point then we're done, otherwise keep looking below. */
505 /* TODO: separate into a separate function (?) */
506 if (subgridToGridIndex(grid, subgridOrigin, subgridIndex, gridPointIndex))
512 /* Traverse the subgrid and look for the first point that is also in the grid. */
513 while (stepInMultiDimArray(grid.numDimensions(), subgridNumPoints, subgridIndex))
515 /* If this is a valid grid point, the grid point index is updated.*/
516 if (subgridToGridIndex(grid, subgridOrigin, subgridIndex, gridPointIndex))
526 * Returns the point distance between from value x to value x0 along the given axis.
528 * Note that the returned distance may be negative or larger than the
529 * number of points in the axis. For a periodic axis, the distance is chosen
530 * to be in [0, period), i.e. always positive but not the shortest one.
532 * \param[in] axis BiasGrid axis.
533 * \param[in] x From value.
534 * \param[in] x0 To value.
535 * \returns (x - x0) in number of points.
537 static int pointDistanceAlongAxis(const GridAxis& axis, double x, double x0)
541 if (axis.spacing() > 0)
543 /* Get the real-valued distance. For a periodic axis, the shortest one. */
544 double period = axis.period();
545 double dx = getDeviationPeriodic(x, x0, period);
547 /* Transform the distance into a point distance by rounding. */
548 distance = gmx::roundToInt(dx / axis.spacing());
550 /* If periodic, shift the point distance to be in [0, period) */
551 distance = indexWithinPeriod(distance, axis.numPointsInPeriod());
558 * Query if a value is in range of the grid.
560 * \param[in] value Value to check.
561 * \param[in] axis The grid axes.
562 * \returns true if the value is in the grid.
564 static bool valueIsInGrid(const awh_dvec value, ArrayRef<const GridAxis> axis)
566 /* For each dimension get the one-dimensional index and check if it is in range. */
567 for (size_t d = 0; d < axis.size(); d++)
569 /* The index is computed as the point distance from the origin. */
570 int index = pointDistanceAlongAxis(axis[d], value[d], axis[d].origin());
572 if (!(index >= 0 && index < axis[d].numPoints()))
581 bool BiasGrid::covers(const awh_dvec value) const
583 return valueIsInGrid(value, axis());
586 std::optional<int> BiasGrid::lambdaAxisIndex() const
588 for (size_t i = 0; i < axis_.size(); i++)
590 if (axis_[i].isFepLambdaAxis())
598 int BiasGrid::numFepLambdaStates() const
600 for (size_t i = 0; i < axis_.size(); i++)
602 if (axis_[i].isFepLambdaAxis())
604 return axis_[i].numPoints();
610 int GridAxis::nearestIndex(double value) const
612 /* Get the point distance to the origin. This may by an out of index range for the axis. */
613 int index = pointDistanceAlongAxis(*this, value, origin_);
615 if (index < 0 || index >= numPoints_)
619 GMX_RELEASE_ASSERT(index >= 0 && index < numPointsInPeriod_,
620 "Index not in periodic interval 0 for AWH periodic axis");
621 int endDistance = (index - (numPoints_ - 1));
622 int originDistance = (numPointsInPeriod_ - index);
623 index = originDistance < endDistance ? 0 : numPoints_ - 1;
627 index = (index < 0) ? 0 : (numPoints_ - 1);
635 * Map a value to the nearest point in the grid.
637 * \param[in] value Value.
638 * \param[in] axis The grid axes.
639 * \returns the point index nearest to the value.
641 static int getNearestIndexInGrid(const awh_dvec value, ArrayRef<const GridAxis> axis)
645 /* If the index is out of range, modify it so that it is in range by choosing the nearest point on the edge. */
646 for (size_t d = 0; d < axis.size(); d++)
648 indexMulti[d] = axis[d].nearestIndex(value[d]);
651 return multiDimGridIndexToLinear(axis, indexMulti);
654 int BiasGrid::nearestIndex(const awh_dvec value) const
656 return getNearestIndexInGrid(value, axis());
663 * Find and set the neighbors of a grid point.
665 * The search space for neighbors is a subgrid with size set by a scope cutoff.
666 * In general not all point within scope will be valid grid points.
668 * \param[in] pointIndex BiasGrid point index.
669 * \param[in] grid The grid.
670 * \param[in,out] neighborIndexArray Array to fill with neighbor indices.
672 void setNeighborsOfGridPoint(int pointIndex, const BiasGrid& grid, std::vector<int>* neighborIndexArray)
674 const int c_maxNeighborsAlongAxis =
675 1 + 2 * static_cast<int>(BiasGrid::c_numPointsPerSigma * BiasGrid::c_scopeCutoff);
677 awh_ivec numCandidates = { 0 };
678 awh_ivec subgridOrigin = { 0 };
679 for (int d = 0; d < grid.numDimensions(); d++)
681 if (grid.axis(d).isFepLambdaAxis())
683 /* Use all points along an axis linked to FEP */
684 numCandidates[d] = grid.axis(d).numPoints();
685 subgridOrigin[d] = 0;
689 /* The number of candidate points along this dimension is given by the scope cutoff. */
690 numCandidates[d] = std::min(c_maxNeighborsAlongAxis, grid.axis(d).numPoints());
692 /* The origin of the subgrid to search */
693 int centerIndex = grid.point(pointIndex).index[d];
694 subgridOrigin[d] = centerIndex - numCandidates[d] / 2;
698 /* Find and set the neighbors */
699 int neighborIndex = -1;
700 bool aPointExists = true;
702 /* Keep looking for grid points while traversing the subgrid. */
705 /* The point index is updated if a grid point was found. */
706 aPointExists = advancePointInSubgrid(grid, subgridOrigin, numCandidates, &neighborIndex);
710 neighborIndexArray->push_back(neighborIndex);
717 void BiasGrid::initPoints()
719 awh_ivec numPointsDimWork = { 0 };
720 awh_ivec indexWork = { 0 };
722 for (size_t d = 0; d < axis_.size(); d++)
724 /* Temporarily gather the number of points in each dimension in one array */
725 numPointsDimWork[d] = axis_[d].numPoints();
728 for (auto& point : point_)
730 for (size_t d = 0; d < axis_.size(); d++)
732 if (axis_[d].isFepLambdaAxis())
734 point.coordValue[d] = indexWork[d];
738 point.coordValue[d] = axis_[d].origin() + indexWork[d] * axis_[d].spacing();
741 if (axis_[d].period() > 0)
743 /* Do we always want the values to be centered around 0 ? */
744 point.coordValue[d] =
745 centerPeriodicValueAroundZero(point.coordValue[d], axis_[d].period());
748 point.index[d] = indexWork[d];
751 stepInMultiDimArray(axis_.size(), numPointsDimWork, indexWork);
755 GridAxis::GridAxis(double origin, double end, double period, double pointDensity) :
756 origin_(origin), period_(period), isFepLambdaAxis_(false)
758 length_ = getIntervalLengthPeriodic(origin_, end, period_);
760 /* Automatically determine number of points based on the user given endpoints
761 and the expected fluctuations in the umbrella. */
766 else if (pointDensity == 0)
772 /* An extra point is added here to account for the endpoints. The
773 minimum number of points for a non-zero interval is 2. */
774 numPoints_ = 1 + static_cast<int>(std::ceil(length_ * pointDensity));
777 /* Set point spacing based on the number of points */
780 /* Set the grid spacing so that a period is matched exactly by an integer number of points.
781 The number of points in a period is equal to the number of grid spacings in a period
782 since the endpoints are connected. */
784 length_ > 0 ? static_cast<int>(std::ceil(period / length_ * (numPoints_ - 1))) : 1;
785 spacing_ = period_ / numPointsInPeriod_;
787 /* Modify the number of grid axis points to be compatible with the period dependent spacing. */
788 numPoints_ = std::min(static_cast<int>(round(length_ / spacing_)) + 1, numPointsInPeriod_);
792 numPointsInPeriod_ = 0;
793 spacing_ = numPoints_ > 1 ? length_ / (numPoints_ - 1) : 0;
797 GridAxis::GridAxis(double origin, double end, double period, int numPoints, bool isFepLambdaAxis) :
798 origin_(origin), period_(period), numPoints_(numPoints), isFepLambdaAxis_(isFepLambdaAxis)
802 length_ = end - origin_;
804 numPointsInPeriod_ = numPoints;
808 length_ = getIntervalLengthPeriodic(origin_, end, period_);
809 spacing_ = numPoints_ > 1 ? length_ / (numPoints_ - 1) : period_;
810 numPointsInPeriod_ = static_cast<int>(std::round(period_ / spacing_));
814 BiasGrid::BiasGrid(ArrayRef<const DimParams> dimParams, ArrayRef<const AwhDimParams> awhDimParams)
816 GMX_RELEASE_ASSERT(dimParams.size() == awhDimParams.size(), "Dimensions needs to be equal");
817 /* Define the discretization along each dimension */
820 for (int d = 0; d < gmx::ssize(awhDimParams); d++)
822 double origin = dimParams[d].scaleUserInputToInternal(awhDimParams[d].origin());
823 double end = dimParams[d].scaleUserInputToInternal(awhDimParams[d].end());
824 if (awhDimParams[d].coordinateProvider() == AwhCoordinateProviderType::Pull)
826 period[d] = dimParams[d].scaleUserInputToInternal(awhDimParams[d].period());
828 c_numPointsPerSigma >= 1.0,
829 "The number of points per sigma should be at least 1.0 to get a uniformly "
830 "covering the reaction using Gaussians");
831 double pointDensity = std::sqrt(dimParams[d].pullDimParams().betak) * c_numPointsPerSigma;
832 axis_.emplace_back(origin, end, period[d], pointDensity);
836 axis_.emplace_back(origin, end, 0, dimParams[d].fepDimParams().numFepLambdaStates, true);
838 numPoints *= axis_[d].numPoints();
841 point_.resize(numPoints);
843 /* Set their values */
846 /* Keep a neighbor list for each point.
847 * Note: could also generate neighbor list only when needed
848 * instead of storing them for each point.
850 for (size_t m = 0; m < point_.size(); m++)
852 std::vector<int>* neighbor = &point_[m].neighbor;
854 setNeighborsOfGridPoint(m, *this, neighbor);
858 void mapGridToDataGrid(std::vector<int>* gridpointToDatapoint,
859 const double* const* data,
861 const std::string& dataFilename,
862 const BiasGrid& grid,
863 const std::string& correctFormatMessage)
865 /* Transform the data into a grid in order to map each grid point to a data point
866 using the grid functions. */
868 /* Count the number of points for each dimension. Each dimension
869 has its own stride. */
871 int numPointsCounted = 0;
872 std::vector<int> numPoints(grid.numDimensions());
873 std::vector<bool> isFepLambdaAxis(grid.numDimensions());
874 for (int d = grid.numDimensions() - 1; d >= 0; d--)
876 int numPointsInDim = 0;
878 double firstValue = data[d][pointIndex];
882 pointIndex += stride;
883 } while (pointIndex < numDataPoints
884 && !gmx_within_tol(firstValue, data[d][pointIndex], GMX_REAL_EPS));
886 /* The stride in dimension dimension d - 1 equals the number of points
888 stride = numPointsInDim;
890 numPointsCounted = (numPointsCounted == 0) ? numPointsInDim : numPointsCounted * numPointsInDim;
892 numPoints[d] = numPointsInDim;
893 isFepLambdaAxis[d] = grid.axis(d).isFepLambdaAxis();
896 if (numPointsCounted != numDataPoints)
898 std::string mesg = gmx::formatString(
899 "Could not extract data properly from %s. Wrong data format?"
901 dataFilename.c_str(),
902 correctFormatMessage.c_str());
903 GMX_THROW(InvalidInputError(mesg));
906 std::vector<GridAxis> axis_;
907 axis_.reserve(grid.numDimensions());
908 /* The data grid has the data that was read and the properties of the AWH grid */
909 for (int d = 0; d < grid.numDimensions(); d++)
911 if (isFepLambdaAxis[d])
913 axis_.emplace_back(data[d][0], data[d][numDataPoints - 1], 0, numPoints[d], true);
918 data[d][0], data[d][numDataPoints - 1], grid.axis(d).period(), numPoints[d], false);
922 /* Map each grid point to a data point. No interpolation, just pick the nearest one.
923 * It is assumed that the given data is uniformly spaced for each dimension.
925 for (size_t m = 0; m < grid.numPoints(); m++)
927 /* We only define what we need for the datagrid since it's not needed here which is a bit ugly */
929 if (!valueIsInGrid(grid.point(m).coordValue, axis_))
931 std::string mesg = gmx::formatString(
932 "%s does not contain data for all coordinate values. "
933 "Make sure your input data covers the whole sampling domain "
934 "and is correctly formatted. \n\n%s",
935 dataFilename.c_str(),
936 correctFormatMessage.c_str());
937 GMX_THROW(InvalidInputError(mesg));
939 (*gridpointToDatapoint)[m] = getNearestIndexInGrid(grid.point(m).coordValue, axis_);