LCOV - code coverage report
Current view: top level - tools - Grid.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 567 805 70.4 %
Date: 2026-11-05 10:19:04 Functions: 69 172 40.1 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed 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
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : 
      23             : #include "Grid.h"
      24             : #include "Tools.h"
      25             : #include "core/Value.h"
      26             : #include "File.h"
      27             : #include "Exception.h"
      28             : #include "KernelFunctions.h"
      29             : #include "RootFindingBase.h"
      30             : #include "Communicator.h"
      31             : #include "small_vector/small_vector.h"
      32             : 
      33             : #include <vector>
      34             : #include <limits>
      35             : #include <cstdlib>
      36             : #include <cmath>
      37             : #include <iostream>
      38             : #include <sstream>
      39             : #include <cstdio>
      40             : #include <cfloat>
      41             : #include <array>
      42             : 
      43             : namespace PLMD {
      44             : 
      45             : constexpr std::size_t GridBase::maxdim;
      46             : 
      47             : template<unsigned dimension_>
      48        3242 : class Accelerator final:
      49             :   public Grid::AcceleratorBase {
      50             : 
      51             : public:
      52             : 
      53        1654 :   unsigned getDimension() const override {
      54        1654 :     return dimension_;
      55             :   }
      56             : 
      57       61864 :   std::vector<GridBase::index_t> getNeighbors(const GridBase& grid, const std::vector<unsigned> & nbin_,const std::vector<bool> & pbc_,const unsigned* indices,std::size_t indices_size,const std::vector<unsigned> &nneigh)const override {
      58             :     plumed_dbg_assert(indices_size==dimension_ && nneigh.size()==dimension_);
      59             : 
      60       61864 :     std::vector<Grid::index_t> neighbors;
      61             :     std::array<unsigned,dimension_> small_bin;
      62             :     std::array<unsigned,dimension_> small_indices;
      63             :     std::array<unsigned,dimension_> tmp_indices;
      64             : 
      65             :     unsigned small_nbin=1;
      66      184870 :     for(unsigned j=0; j<dimension_; ++j) {
      67      123006 :       small_bin[j]=(2*nneigh[j]+1);
      68             :       // along a periodic direction a neighborhood larger than the grid would visit
      69             :       // some points more than once: visit each point of the grid exactly once instead
      70      123006 :       if(pbc_[j] && small_bin[j]>nbin_[j]) {
      71           0 :         small_bin[j]=nbin_[j];
      72             :       }
      73      123006 :       small_nbin*=small_bin[j];
      74             :     }
      75       61864 :     neighbors.reserve(small_nbin);
      76             : 
      77      184870 :     for(unsigned j=0; j<dimension_; j++) {
      78      123006 :       small_indices[j]=0;
      79             :     }
      80             : 
      81     1373282 :     for(unsigned index=0; index<small_nbin; ++index) {
      82             :       unsigned ll=0;
      83     3768576 :       for(unsigned i=0; i<dimension_; ++i) {
      84     2457158 :         int i0=small_indices[i]-nneigh[i]+indices[i];
      85     2457158 :         if(!pbc_[i] && i0<0) {
      86       46880 :           continue;
      87             :         }
      88     2410278 :         if(!pbc_[i] && i0>=static_cast<int>(nbin_[i])) {
      89       35216 :           continue;
      90             :         }
      91     2375062 :         if( pbc_[i] ) {
      92     2116244 :           const int n=nbin_[i];
      93     2116244 :           i0=((i0%n)+n)%n;
      94             :         }
      95     2375062 :         tmp_indices[ll]=static_cast<unsigned>(i0);
      96     2375062 :         ll++;
      97             :       }
      98     1311418 :       if(ll==dimension_) {
      99     1229322 :         neighbors.push_back(getIndex(grid,nbin_,&tmp_indices[0],dimension_));
     100             :       }
     101             : 
     102     1311418 :       small_indices[0]++;
     103     2291480 :       for(unsigned j=0; j<dimension_-1; j++)
     104     1145740 :         if(small_indices[j]==small_bin[j]) {
     105      162562 :           small_indices[j]=0;
     106      162562 :           small_indices[j+1]++;
     107             :         }
     108             :     }
     109       61864 :     return neighbors;
     110             :   }
     111             : 
     112             :   // we are flattening arrays using a column-major order
     113     7293498 :   GridBase::index_t getIndex(const GridBase& grid, const std::vector<unsigned> & nbin_,const unsigned* indices,std::size_t indices_size) const override {
     114    19634249 :     for(unsigned int i=0; i<dimension_; i++)
     115    12340751 :       if(indices[i]>=nbin_[i]) {
     116           0 :         plumed_error() << "Looking for a value outside the grid along the " << i << " dimension (arg name: "<<grid.getArgNames()[i]<<")";
     117             :       }
     118     7293498 :     auto index=indices[dimension_-1];
     119     9658156 :     for(unsigned int i=dimension_-1; i>0; --i) {
     120     5047253 :       index=index*nbin_[i-1]+indices[i-1];
     121             :     }
     122     7293498 :     return index;
     123             :   }
     124             : 
     125    33313934 :   void getPoint(const std::vector<double> & min_,const std::vector<double> & dx_, const unsigned* indices,std::size_t indices_size,double* point,std::size_t point_size) const override {
     126   113361970 :     for(unsigned int i=0; i<dimension_; ++i) {
     127    80048036 :       point[i]=min_[i]+(double)(indices[i])*dx_[i];
     128             :     }
     129    33313934 :   }
     130             : 
     131     1203510 :   void getIndices(const std::vector<double> & min_,const std::vector<double> & dx_, const std::vector<double> & x, unsigned* rindex_data,std::size_t rindex_size) const override {
     132             :     plumed_dbg_assert(x.size()==dimension_);
     133             :     plumed_dbg_assert(rindex_size==dimension_);
     134     3566946 :     for(unsigned int i=0; i<dimension_; ++i) {
     135     2363436 :       const double f=std::floor((x[i]-min_[i])/dx_[i]);
     136             :       // converting a negative (or too large) double to unsigned is undefined behavior:
     137             :       // on x86 it gave a huge index (and getIndex raised an error), on arm64 it gives 0
     138             :       // (i.e. the value of the first bin). Map it explicitly to an invalid index.
     139     2363436 :       rindex_data[i] = (f>=0.0 && f<double(std::numeric_limits<unsigned>::max())) ?
     140             :                        static_cast<unsigned>(f) : std::numeric_limits<unsigned>::max();
     141             :     }
     142     1203510 :   }
     143             : 
     144             : 
     145             :   // we are flattening arrays using a column-major order
     146    38013328 :   void getIndices(const std::vector<unsigned> & nbin_, GridBase::index_t index, unsigned* indices, std::size_t indices_size) const override {
     147    38013328 :     plumed_assert(indices_size==dimension_)<<indices_size;
     148    91039369 :     for(unsigned int i=0; i<dimension_-1; ++i) {
     149    53994039 :       indices[i]=index%nbin_[i];
     150    53994039 :       index/=nbin_[i];
     151             :     }
     152    38013328 :     indices[dimension_-1]=index;
     153    38013328 :   }
     154             : 
     155             : };
     156             : 
     157        3242 : std::unique_ptr<Grid::AcceleratorBase> Grid::AcceleratorBase::create(unsigned dim) {
     158             : // I do this by enumeration.
     159             : // Maybe can be simplified using the preprocessor, but I am not sure it's worth it
     160             :   if(dim==1) {
     161        2573 :     return std::make_unique<Accelerator<1>>();
     162             :   }
     163             :   if(dim==2) {
     164         661 :     return std::make_unique<Accelerator<2>>();
     165             :   }
     166             :   if(dim==3) {
     167           8 :     return std::make_unique<Accelerator<3>>();
     168             :   }
     169             :   if(dim==4) {
     170           0 :     return std::make_unique<Accelerator<4>>();
     171             :   }
     172             :   if(dim==5) {
     173           0 :     return std::make_unique<Accelerator<5>>();
     174             :   }
     175             :   if(dim==6) {
     176           0 :     return std::make_unique<Accelerator<6>>();
     177             :   }
     178             :   if(dim==7) {
     179           0 :     return std::make_unique<Accelerator<7>>();
     180             :   }
     181             :   if(dim==8) {
     182           0 :     return std::make_unique<Accelerator<8>>();
     183             :   }
     184             :   if(dim==9) {
     185           0 :     return std::make_unique<Accelerator<9>>();
     186             :   }
     187             :   if(dim==10) {
     188           0 :     return std::make_unique<Accelerator<10>>();
     189             :   }
     190             :   if(dim==11) {
     191           0 :     return std::make_unique<Accelerator<11>>();
     192             :   }
     193             :   if(dim==12) {
     194           0 :     return std::make_unique<Accelerator<12>>();
     195             :   }
     196             :   if(dim==13) {
     197           0 :     return std::make_unique<Accelerator<13>>();
     198             :   }
     199             :   if(dim==14) {
     200           0 :     return std::make_unique<Accelerator<14>>();
     201             :   }
     202             :   if(dim==15) {
     203           0 :     return std::make_unique<Accelerator<15>>();
     204             :   }
     205             :   if(dim==16) {
     206           0 :     return std::make_unique<Accelerator<16>>();
     207             :   }
     208             : // no need to go beyond this
     209           0 :   plumed_error();
     210             : }
     211             : 
     212        1460 : GridBase::GridBase(const std::string& funcl, const std::vector<Value*> & args, const std::vector<std::string> & gmin,
     213        1460 :                    const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv) {
     214             : // various checks
     215        1460 :   plumed_assert(args.size()<=maxdim) << "grid dim cannot exceed "<<maxdim;
     216        1460 :   plumed_massert(args.size()==gmin.size(),"grid min dimensions in input do not match number of arguments");
     217        1460 :   plumed_massert(args.size()==nbin.size(),"number of bins on input do not match number of arguments");
     218        1460 :   plumed_massert(args.size()==gmax.size(),"grid max dimensions in input do not match number of arguments");
     219        1460 :   unsigned dim=gmax.size();
     220        1460 :   std::vector<std::string> names;
     221        1460 :   std::vector<bool> isperiodic;
     222        1460 :   std::vector<std::string> pmin,pmax;
     223        1460 :   names.resize( dim );
     224        1460 :   isperiodic.resize( dim );
     225        1460 :   pmin.resize( dim );
     226        1460 :   pmax.resize( dim );
     227        3248 :   for(unsigned int i=0; i<dim; ++i) {
     228        1788 :     names[i]=args[i]->getName();
     229        1788 :     if( args[i]->isPeriodic() ) {
     230             :       isperiodic[i]=true;
     231         595 :       args[i]->getDomain( pmin[i], pmax[i] );
     232             :     } else {
     233             :       isperiodic[i]=false;
     234             :       pmin[i]="0.";
     235             :       pmax[i]="0.";
     236             :     }
     237             :   }
     238             : // this is a value-independent initializator
     239        1460 :   Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,isperiodic,pmin,pmax);
     240        2920 : }
     241             : 
     242         128 : GridBase::GridBase(const std::string& funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin,
     243             :                    const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv,
     244         128 :                    const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ) {
     245             : // this calls the initializator
     246         128 :   Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,isperiodic,pmin,pmax);
     247         128 : }
     248             : 
     249        1588 : void GridBase::Init(const std::string& funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin,
     250             :                     const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv,
     251             :                     const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ) {
     252        1588 :   fmt_="%14.9f";
     253             : // various checks
     254        1588 :   plumed_assert(names.size()<=maxdim) << "grid size cannot exceed "<<maxdim;
     255        1588 :   plumed_massert(names.size()==gmin.size(),"grid dimensions in input do not match number of arguments");
     256        1588 :   plumed_massert(names.size()==nbin.size(),"grid dimensions in input do not match number of arguments");
     257        1588 :   plumed_massert(names.size()==gmax.size(),"grid dimensions in input do not match number of arguments");
     258        1588 :   dimension_=gmax.size();
     259        1588 :   accelerator=AcceleratorHandler(dimension_);
     260        1588 :   str_min_=gmin;
     261        1588 :   str_max_=gmax;
     262        1588 :   argnames.resize( dimension_ );
     263        1588 :   min_.resize( dimension_ );
     264        1588 :   max_.resize( dimension_ );
     265        1588 :   pbc_.resize( dimension_ );
     266        3504 :   for(unsigned int i=0; i<dimension_; ++i) {
     267        1916 :     argnames[i]=names[i];
     268        1916 :     if( isperiodic[i] ) {
     269             :       pbc_[i]=true;
     270             :       str_min_[i]=pmin[i];
     271             :       str_max_[i]=pmax[i];
     272             :     } else {
     273             :       pbc_[i]=false;
     274             :     }
     275        1916 :     Tools::convert(str_min_[i],min_[i]);
     276        1916 :     Tools::convert(str_max_[i],max_[i]);
     277        1916 :     funcname=funcl;
     278        1916 :     plumed_massert(max_[i]>min_[i],"maximum in grid must be larger than minimum");
     279        1916 :     plumed_massert(nbin[i]>0,"number of grid points must be greater than zero");
     280             :   }
     281        1588 :   nbin_=nbin;
     282        1588 :   dospline_=dospline;
     283        1588 :   usederiv_=usederiv;
     284        1588 :   if(dospline_) {
     285         216 :     plumed_assert(dospline_==usederiv_);
     286             :   }
     287        1588 :   maxsize_=1;
     288        3504 :   for(unsigned int i=0; i<dimension_; ++i) {
     289        1916 :     dx_.push_back( (max_[i]-min_[i])/static_cast<double>( nbin_[i] ) );
     290        1916 :     if( !pbc_[i] ) {
     291        1257 :       max_[i] += dx_[i];
     292        1257 :       nbin_[i] += 1;
     293             :     }
     294        1916 :     maxsize_*=nbin_[i];
     295             :   }
     296        1588 : }
     297             : 
     298       45997 : bool GridBase::isInside(const std::vector<double> & x) const {
     299             :   plumed_dbg_assert(x.size()==dimension_);
     300      110272 :   for(unsigned i=0; i<dimension_; ++i) {
     301       64603 :     if(!pbc_[i]) {
     302             :       // same arithmetic as getIndices (false also for a NaN)
     303       30043 :       const double k=std::floor((x[i]-min_[i])/dx_[i]);
     304       30043 :       if(!(k>=0.0 && k<static_cast<double>(nbin_[i]))) {
     305             :         return false;
     306             :       }
     307             :     }
     308             :   }
     309             :   return true;
     310             : }
     311             : 
     312             : namespace {
     313             : /// bound of a resized grid as a string: 12 significant digits, so that the files do not depend on the last digits of
     314             : /// the bounds, which can differ between platforms (e.g. with fused multiply-add); when a grid is read from a file
     315             : /// its lattice is compared with a tolerance
     316         266 : std::string boundString(double x) {
     317             :   char buffer[64];
     318             :   std::snprintf(buffer,sizeof(buffer),"%.12g",x);
     319         266 :   return buffer;
     320             : }
     321             : }
     322             : 
     323         132 : void GridBase::resize(const std::vector<long long> & lower, const std::vector<long long> & upper) {
     324         132 :   plumed_assert(lower.size()==dimension_ && upper.size()==dimension_);
     325         132 :   const std::vector<unsigned> oldnbin(nbin_);
     326         132 :   std::vector<unsigned> newnbin(nbin_);
     327             :   double newsize=1.0;
     328         318 :   for(unsigned i=0; i<dimension_; ++i) {
     329         186 :     if(lower[i]!=0 || upper[i]!=0) {
     330         133 :       plumed_massert(!pbc_[i],"periodic directions of a grid cannot be resized");
     331         133 :       const long long n=static_cast<long long>(nbin_[i])+lower[i]+upper[i];
     332         133 :       plumed_massert(n>=2 && n<=static_cast<long long>(std::numeric_limits<unsigned>::max()),"invalid number of grid points after resizing");
     333         133 :       newnbin[i]=static_cast<unsigned>(n);
     334             :     }
     335         186 :     newsize*=newnbin[i];
     336             :   }
     337         132 :   plumed_massert(newsize<static_cast<double>(std::numeric_limits<index_t>::max()),"too many grid points after resizing");
     338         318 :   for(unsigned i=0; i<dimension_; ++i) {
     339         186 :     if(lower[i]!=0 || upper[i]!=0) {
     340         133 :       min_[i]-=static_cast<double>(lower[i])*dx_[i];
     341         133 :       max_[i]+=static_cast<double>(upper[i])*dx_[i];
     342         133 :       nbin_[i]=newnbin[i];
     343             :       // as in the input of a non-periodic grid, the maximum is the last point
     344         266 :       str_min_[i]=boundString(min_[i]);
     345         266 :       str_max_[i]=boundString(max_[i]-dx_[i]);
     346             :     }
     347             :   }
     348         132 :   maxsize_=1;
     349         318 :   for(unsigned i=0; i<dimension_; ++i) {
     350         186 :     maxsize_*=nbin_[i];
     351             :   }
     352         132 :   resizeData(oldnbin,lower);
     353         132 : }
     354             : 
     355         567 : void GridBase::forEachStoredPoint(const std::function<void(index_t,double)> & f) const {
     356         567 :   const index_t n=getSize();
     357     9412884 :   for(index_t i=0; i<n; ++i) {
     358     9412317 :     f(i,getValue(i));
     359             :   }
     360         567 : }
     361             : 
     362         436 : void SparseGrid::forEachStoredPoint(const std::function<void(index_t,double)> & f) const {
     363     1095308 :   for(const auto & it : map_) {
     364     1094872 :     f(it.first,it.second);
     365             :   }
     366         436 : }
     367             : 
     368           0 : void GridBase::resizeData(const std::vector<unsigned> & oldnbin, const std::vector<long long> & shift) {
     369           0 :   plumed_merror("this kind of grid cannot be resized");
     370             : }
     371             : 
     372     1360671 : std::vector<std::string> GridBase::getMin() const {
     373     1360671 :   return str_min_;
     374             : }
     375             : 
     376         559 : std::vector<std::string> GridBase::getMax() const {
     377         559 :   return str_max_;
     378             : }
     379             : 
     380     1330206 : std::vector<double> GridBase::getDx() const {
     381     1330206 :   return dx_;
     382             : }
     383             : 
     384      213050 : double GridBase::getDx(index_t j) const {
     385      213050 :   return dx_[j];
     386             : }
     387             : 
     388          37 : double GridBase::getBinVolume() const {
     389             :   double vol=1.;
     390         102 :   for(unsigned i=0; i<dx_.size(); ++i) {
     391          65 :     vol*=dx_[i];
     392             :   }
     393          37 :   return vol;
     394             : }
     395             : 
     396       26440 : std::vector<bool> GridBase::getIsPeriodic() const {
     397       26440 :   return pbc_;
     398             : }
     399             : 
     400     1050474 : std::vector<unsigned> GridBase::getNbin() const {
     401     1050474 :   return nbin_;
     402             : }
     403             : 
     404        9436 : std::vector<std::string> GridBase::getArgNames() const {
     405        9436 :   return argnames;
     406             : }
     407             : 
     408    18384374 : unsigned GridBase::getDimension() const {
     409    18384374 :   return dimension_;
     410             : }
     411             : 
     412       48272 : unsigned GridBase::getSplineNeighbors(const unsigned* indices, std::size_t indices_size, index_t* neighbors, std::size_t neighbors_size)const {
     413       48272 :   plumed_assert(indices_size==dimension_);
     414       48272 :   unsigned nneigh=1<<dimension_; // same as unsigned(pow(2.0,dimension_));
     415       48272 :   plumed_assert(neighbors_size==nneigh);
     416             : 
     417             :   unsigned nneighbors = 0;
     418             : 
     419             :   std::array<unsigned,maxdim> nindices;
     420             :   unsigned inind;
     421      180804 :   for(unsigned int i=0; i<nneigh; ++i) {
     422             :     unsigned tmp=i;
     423             :     inind=0;
     424      337040 :     for(unsigned int j=0; j<dimension_; ++j) {
     425      204508 :       unsigned i0=tmp%2+indices[j];
     426      204508 :       tmp/=2;
     427      204508 :       if(!pbc_[j] && i0==nbin_[j]) {
     428           4 :         continue;
     429             :       }
     430      204504 :       if( pbc_[j] && i0==nbin_[j]) {
     431             :         i0=0;
     432             :       }
     433      204504 :       nindices[inind++]=i0;
     434             :     }
     435      132532 :     if(inind==dimension_) {
     436      132528 :       neighbors[nneighbors++]=getIndex(nindices.data(),dimension_);
     437             :     }
     438             :   }
     439       48272 :   return nneighbors;
     440             : }
     441             : 
     442       29207 : std::vector<GridBase::index_t> GridBase::getNearestNeighbors(const index_t index) const {
     443       29207 :   std::vector<index_t> nearest_neighs = std::vector<index_t>();
     444       87620 :   for (unsigned i = 0; i < dimension_; i++) {
     445       58413 :     std::vector<unsigned> neighsneeded = std::vector<unsigned>(dimension_, 0);
     446       58413 :     neighsneeded[i] = 1;
     447       58413 :     std::vector<index_t> singledim_nearest_neighs = getNeighbors(index, neighsneeded);
     448      232018 :     for (unsigned j = 0; j < singledim_nearest_neighs.size(); j++) {
     449      173605 :       index_t neigh = singledim_nearest_neighs[j];
     450      173605 :       if (neigh != index) {
     451      115192 :         nearest_neighs.push_back(neigh);
     452             :       }
     453             :     }
     454             :   }
     455       29207 :   return nearest_neighs;
     456             : }
     457             : 
     458           0 : std::vector<GridBase::index_t> GridBase::getNearestNeighbors(const std::vector<unsigned> &indices) const {
     459             :   plumed_dbg_assert(indices.size() == dimension_);
     460           0 :   return getNearestNeighbors(getIndex(indices));
     461             : }
     462             : 
     463           0 : void GridBase::addKernel( const KernelFunctions& kernel ) {
     464             :   plumed_dbg_assert( kernel.ndim()==dimension_ );
     465           0 :   std::vector<unsigned> nneighb=kernel.getSupport( dx_ );
     466           0 :   std::vector<index_t> neighbors=getNeighbors( kernel.getCenter(), nneighb );
     467           0 :   std::vector<double> xx( dimension_ );
     468           0 :   std::vector<std::unique_ptr<Value>> vv( dimension_ );
     469             :   std::string str_min, str_max;
     470           0 :   for(unsigned i=0; i<dimension_; ++i) {
     471           0 :     vv[i]=Tools::make_unique<Value>();
     472           0 :     if( pbc_[i] ) {
     473           0 :       Tools::convert(min_[i],str_min);
     474           0 :       Tools::convert(max_[i],str_max);
     475           0 :       vv[i]->setDomain( str_min, str_max );
     476             :     } else {
     477           0 :       vv[i]->setNotPeriodic();
     478             :     }
     479             :   }
     480             : 
     481             : // vv_ptr contains plain pointers obtained from vv.
     482             : // this is the simplest way to replace a unique_ptr here.
     483             : // perhaps the interface of kernel.evaluate() should be changed
     484             : // in order to accept a std::vector<std::unique_ptr<Value>>
     485           0 :   auto vv_ptr=Tools::unique2raw(vv);
     486             : 
     487           0 :   std::vector<double> der( dimension_ );
     488           0 :   for(unsigned i=0; i<neighbors.size(); ++i) {
     489           0 :     index_t ineigh=neighbors[i];
     490           0 :     getPoint( ineigh, xx );
     491           0 :     for(unsigned j=0; j<dimension_; ++j) {
     492           0 :       vv[j]->set(xx[j]);
     493             :     }
     494           0 :     double newval = kernel.evaluate( vv_ptr, der, usederiv_ );
     495           0 :     if( usederiv_ ) {
     496           0 :       addValueAndDerivatives( ineigh, newval, der );
     497             :     } else {
     498           0 :       addValue( ineigh, newval );
     499             :     }
     500             :   }
     501           0 : }
     502             : 
     503     1193613 : double GridBase::getValue(const std::vector<unsigned> & indices) const {
     504     1193613 :   return getValue(getIndex(indices));
     505             : }
     506             : 
     507       10645 : double GridBase::getValue(const std::vector<double> & x) const {
     508       10645 :   if(!dospline_) {
     509         127 :     return getValue(getIndex(x));
     510             :   } else {
     511       10518 :     std::vector<double> der(dimension_);
     512       10518 :     return getValueAndDerivatives(x,der);
     513             :   }
     514             : }
     515             : 
     516     3100944 : double GridBase::getValueAndDerivatives(index_t index, std::vector<double>& der) const {
     517             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     518     3100944 :   der.resize(dimension_);
     519     3100944 :   return getValueAndDerivatives(index,der.data(),der.size());
     520             : }
     521             : 
     522     2527708 : double GridBase::getValueAndDerivatives(const std::vector<unsigned> & indices, std::vector<double>& der) const {
     523     2527708 :   return getValueAndDerivatives(getIndex(indices),der);
     524             : }
     525             : 
     526       48818 : double GridBase::getValueAndDerivatives(const std::vector<double> & x, std::vector<double>& der) const {
     527             :   plumed_dbg_assert(der.size()==dimension_ && usederiv_);
     528             : 
     529       48818 :   if(dospline_) {
     530             :     double X,X2,X3,value;
     531             :     std::array<double,maxdim> fd, C, D;
     532             :     std::array<double,maxdim> dder;
     533             : // reset
     534             :     value=0.0;
     535      114538 :     for(unsigned int i=0; i<dimension_; ++i) {
     536       66266 :       der[i]=0.0;
     537             :     }
     538             : 
     539             :     std::array<unsigned,maxdim> indices;
     540       48272 :     getIndices(x, indices.data(),dimension_);
     541             :     std::array<double,maxdim> xfloor;
     542       48272 :     getPoint(indices.data(), dimension_, xfloor.data(),dimension_);
     543       48272 :     gch::small_vector<index_t,16> neigh(1<<dimension_); // pow(2,dimension_); up to dimension 4 will stay on stack
     544       48272 :     auto nneigh = getSplineNeighbors(indices.data(),dimension_, neigh.data(), neigh.size());
     545             : 
     546             : // loop over neighbors
     547             :     std::array<unsigned,maxdim> nindices;
     548      180800 :     for(unsigned int ipoint=0; ipoint<nneigh; ++ipoint) {
     549      132528 :       double grid=getValueAndDerivatives(neigh[ipoint],dder.data(),dimension_);
     550      132528 :       getIndices(neigh[ipoint], nindices.data(), dimension_);
     551             :       double ff=1.0;
     552             : 
     553      337032 :       for(unsigned j=0; j<dimension_; ++j) {
     554             :         int x0=1;
     555      204504 :         if(nindices[j]==indices[j]) {
     556             :           x0=0;
     557             :         }
     558      204504 :         double dx=getDx(j);
     559      204504 :         X=std::abs((x[j]-xfloor[j])/dx-(double)x0);
     560      204504 :         X2=X*X;
     561      204504 :         X3=X2*X;
     562             :         double yy;
     563      204504 :         if(std::abs(grid)<0.0000001) {
     564             :           yy=0.0;
     565             :         } else {
     566      200190 :           yy=-dder[j]/grid;
     567             :         }
     568      204504 :         C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*dx;
     569      204504 :         D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*dx;
     570      204504 :         D[j]*=(x0?-1.0:1.0)/dx;
     571      204504 :         ff*=C[j];
     572             :       }
     573      337032 :       for(unsigned j=0; j<dimension_; ++j) {
     574      204504 :         fd[j]=D[j];
     575      552960 :         for(unsigned i=0; i<dimension_; ++i)
     576      348456 :           if(i!=j) {
     577      143952 :             fd[j]*=C[i];
     578             :           }
     579             :       }
     580      132528 :       value+=grid*ff;
     581      337032 :       for(unsigned j=0; j<dimension_; ++j) {
     582      204504 :         der[j]+=grid*fd[j];
     583             :       }
     584             :     }
     585             :     return value;
     586             :   } else {
     587         546 :     return getValueAndDerivatives(getIndex(x),der);
     588             :   }
     589             : }
     590             : 
     591           0 : void GridBase::setValue(const std::vector<unsigned> & indices, double value) {
     592           0 :   setValue(getIndex(indices),value);
     593           0 : }
     594             : 
     595           0 : void GridBase::setValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der) {
     596           0 :   setValueAndDerivatives(getIndex(indices),value,der);
     597           0 : }
     598             : 
     599           0 : void GridBase::addValue(const std::vector<unsigned> & indices, double value) {
     600           0 :   addValue(getIndex(indices),value);
     601           0 : }
     602             : 
     603           0 : void GridBase::addValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der) {
     604           0 :   addValueAndDerivatives(getIndex(indices),value,der);
     605           0 : }
     606             : 
     607           0 : void GridBase::addValueAndDerivatives(index_t index, double value, const double* der, std::size_t der_size) {
     608           0 :   std::vector<double> d(der,der+der_size);
     609           0 :   addValueAndDerivatives(index,value,d);
     610           0 : }
     611             : 
     612        1180 : void GridBase::writeHeader(OFile& ofile) {
     613        2685 :   for(unsigned i=0; i<dimension_; ++i) {
     614        3010 :     ofile.addConstantField("min_" + argnames[i]);
     615        3010 :     ofile.addConstantField("max_" + argnames[i]);
     616        3010 :     ofile.addConstantField("nbins_" + argnames[i]);
     617        3010 :     ofile.addConstantField("periodic_" + argnames[i]);
     618             :   }
     619        1180 : }
     620             : 
     621           1 : void Grid::clear() {
     622           1 :   grid_.assign(maxsize_,0.0);
     623           1 :   if(usederiv_) {
     624           0 :     der_.assign(maxsize_*dimension_,0.0);
     625             :   }
     626           1 : }
     627             : 
     628        1180 : void Grid::writeToFile(OFile& ofile) {
     629        1180 :   std::vector<double> xx(dimension_);
     630        1180 :   std::vector<double> der(dimension_);
     631             :   double f;
     632        1180 :   writeHeader(ofile);
     633     2562753 :   for(index_t i=0; i<getSize(); ++i) {
     634     2561573 :     xx=getPoint(i);
     635     2561573 :     if(usederiv_) {
     636      571866 :       f=getValueAndDerivatives(i,der);
     637             :     } else {
     638     1989707 :       f=getValue(i);
     639             :     }
     640     4971197 :     if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) {
     641       25000 :       ofile.printf("\n");
     642             :     }
     643     7570135 :     for(unsigned j=0; j<dimension_; ++j) {
     644    10017124 :       ofile.printField("min_" + argnames[j], str_min_[j] );
     645    10017124 :       ofile.printField("max_" + argnames[j], str_max_[j] );
     646    10017124 :       ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) );
     647     5008562 :       if( pbc_[j] ) {
     648     4101894 :         ofile.printField("periodic_" + argnames[j], "true" );
     649             :       } else {
     650     5915230 :         ofile.printField("periodic_" + argnames[j], "false" );
     651             :       }
     652             :     }
     653     7570135 :     for(unsigned j=0; j<dimension_; ++j) {
     654     5008562 :       ofile.fmtField(" "+fmt_);
     655     5008562 :       ofile.printField(argnames[j],xx[j]);
     656             :     }
     657     2561573 :     ofile.fmtField(" "+fmt_);
     658     2561573 :     ofile.printField(funcname,f);
     659     2561573 :     if(usederiv_)
     660     1687906 :       for(unsigned j=0; j<dimension_; ++j) {
     661     1116040 :         ofile.fmtField(" "+fmt_);
     662     2232080 :         ofile.printField("der_" + argnames[j],der[j]);
     663             :       }
     664     2561573 :     ofile.printField();
     665             :   }
     666        1180 : }
     667             : 
     668           0 : void GridBase::writeCubeFile(OFile& ofile, const double& lunit) {
     669           0 :   plumed_assert( dimension_==3 );
     670           0 :   ofile.printf("PLUMED CUBE FILE\n");
     671           0 :   ofile.printf("OUTER LOOP: X, MIDDLE LOOP: Y, INNER LOOP: Z\n");
     672             :   // Number of atoms followed by position of origin (origin set so that center of grid is in center of cell)
     673           0 :   ofile.printf("%d %f %f %f\n",1,-0.5*lunit*(max_[0]-min_[0]),-0.5*lunit*(max_[1]-min_[1]),-0.5*lunit*(max_[2]-min_[2]));
     674           0 :   ofile.printf("%u %f %f %f\n",nbin_[0],lunit*dx_[0],0.0,0.0);  // Number of bins in each direction followed by
     675           0 :   ofile.printf("%u %f %f %f\n",nbin_[1],0.0,lunit*dx_[1],0.0);  // shape of voxel
     676           0 :   ofile.printf("%u %f %f %f\n",nbin_[2],0.0,0.0,lunit*dx_[2]);
     677           0 :   ofile.printf("%d %f %f %f\n",1,0.0,0.0,0.0); // Fake atom otherwise VMD doesn't work
     678           0 :   std::vector<unsigned> pp(3);
     679           0 :   for(pp[0]=0; pp[0]<nbin_[0]; ++pp[0]) {
     680           0 :     for(pp[1]=0; pp[1]<nbin_[1]; ++pp[1]) {
     681           0 :       for(pp[2]=0; pp[2]<nbin_[2]; ++pp[2]) {
     682           0 :         ofile.printf("%f ",getValue(pp) );
     683           0 :         if(pp[2]%6==5) {
     684           0 :           ofile.printf("\n");
     685             :         }
     686             :       }
     687           0 :       ofile.printf("\n");
     688             :     }
     689             :   }
     690           0 : }
     691             : 
     692           0 : std::unique_ptr<GridBase> GridBase::create(const std::string& funcl, const std::vector<Value*> & args, IFile& ifile,
     693             :     const std::vector<std::string> & gmin,const std::vector<std::string> & gmax,
     694             :     const std::vector<unsigned> & nbin,bool dosparse, bool dospline, bool doder) {
     695           0 :   std::unique_ptr<GridBase> grid=GridBase::create(funcl,args,ifile,dosparse,dospline,doder);
     696           0 :   std::vector<unsigned> cbin( grid->getNbin() );
     697           0 :   std::vector<std::string> cmin( grid->getMin() ), cmax( grid->getMax() );
     698           0 :   for(unsigned i=0; i<args.size(); ++i) {
     699           0 :     plumed_massert( cmin[i]==gmin[i], "mismatched grid min" );
     700           0 :     plumed_massert( cmax[i]==gmax[i], "mismatched grid max" );
     701           0 :     if( args[i]->isPeriodic() ) {
     702           0 :       plumed_massert( cbin[i]==nbin[i], "mismatched grid nbins" );
     703             :     } else {
     704           0 :       plumed_massert( (cbin[i]-1)==nbin[i], "mismatched grid nbins");
     705             :     }
     706             :   }
     707           0 :   return grid;
     708           0 : }
     709             : 
     710          93 : std::unique_ptr<GridBase> GridBase::create(const std::string& funcl, const std::vector<Value*> & args, IFile& ifile, bool dosparse, bool dospline, bool doder) {
     711          93 :   std::unique_ptr<GridBase> grid;
     712          93 :   unsigned nvar=args.size();
     713             :   bool hasder=false;
     714             :   std::string pstring;
     715          94 :   std::vector<int> gbin1(nvar);
     716          94 :   std::vector<unsigned> gbin(nvar);
     717          94 :   std::vector<std::string> labels(nvar),gmin(nvar),gmax(nvar);
     718          93 :   std::vector<std::string> fieldnames;
     719          93 :   ifile.scanFieldList( fieldnames );
     720             : 
     721             : // Retrieve names for fields
     722         214 :   for(unsigned i=0; i<args.size(); ++i) {
     723         121 :     labels[i]=args[i]->getName();
     724             :     bool found=false;
     725         149 :     for(unsigned j=0; j<fieldnames.size(); ++j) {
     726         149 :       if( labels[i]==fieldnames[j] ) {
     727             :         found=true;
     728             :         break;
     729             :       }
     730             :     }
     731             :     // This is a change to ensure that we can deal with old style names for multicolvars
     732         121 :     std::size_t und = labels[i].find_first_of("_");
     733         121 :     if( !found && und!=std::string::npos ) {
     734           0 :       labels[i] = labels[i].substr(0,und) + "." + labels[i].substr(und+1);
     735           0 :       for(unsigned j=0; j<fieldnames.size(); ++j) {
     736           0 :         if( labels[i]==fieldnames[j] ) {
     737             :           found=true;
     738             :           break;
     739             :         }
     740             :       }
     741             :     }
     742             :   }
     743             : // And read the stuff from the header
     744          93 :   if( !ifile.FieldExist( funcl ) ) {
     745             :     std::string fields;
     746           8 :     for(const auto & f : fieldnames) {
     747          15 :       fields += " " + f;
     748             :     }
     749           5 :     plumed_merror("there is no column labelled " + funcl + " in the grid file " + ifile.getPath() + " (its columns are:" + fields + "). "
     750             :                   "The column is named after the label of the action that wrote the grid: check that the action has the same label");
     751             :   }
     752         212 :   for(unsigned i=0; i<args.size(); ++i) {
     753         240 :     ifile.scanField( "min_" + labels[i], gmin[i]);
     754         240 :     ifile.scanField( "max_" + labels[i], gmax[i]);
     755         240 :     ifile.scanField( "periodic_" + labels[i], pstring );
     756         240 :     ifile.scanField( "nbins_" + labels[i], gbin1[i]);
     757         120 :     plumed_assert( gbin1[i]>0 );
     758         120 :     if( args[i]->isPeriodic() ) {
     759          45 :       plumed_massert( pstring=="true", "input value is periodic but grid is not");
     760             :       std::string pmin, pmax;
     761          45 :       args[i]->getDomain( pmin, pmax );
     762          45 :       gbin[i]=gbin1[i];
     763          45 :       if( pmin!=gmin[i] || pmax!=gmax[i] ) {
     764           0 :         plumed_merror("mismatch between grid boundaries and periods of values");
     765             :       }
     766             :     } else {
     767          75 :       gbin[i]=gbin1[i]-1;  // Note header in grid file indicates one more bin that there should be when data is not periodic
     768          75 :       plumed_massert( pstring=="false", "input value is not periodic but grid is");
     769             :     }
     770         120 :     hasder=ifile.FieldExist( "der_" + labels[i] );
     771         120 :     if( doder && !hasder ) {
     772           0 :       plumed_merror("missing derivatives from grid file");
     773             :     }
     774         148 :     for(unsigned j=0; j<fieldnames.size(); ++j) {
     775         176 :       for(unsigned k=i+1; k<args.size(); ++k) {
     776          28 :         if( fieldnames[j]==labels[k] ) {
     777           0 :           plumed_merror("arguments in input are not in same order as in grid file");
     778             :         }
     779             :       }
     780         148 :       if( fieldnames[j]==labels[i] ) {
     781             :         break;
     782             :       }
     783             :     }
     784             :   }
     785             : 
     786          92 :   if(!dosparse) {
     787          91 :     grid=Tools::make_unique<Grid>(funcl,args,gmin,gmax,gbin,dospline,doder);
     788             :   } else {
     789           1 :     grid=Tools::make_unique<SparseGrid>(funcl,args,gmin,gmax,gbin,dospline,doder);
     790             :   }
     791             : 
     792          92 :   std::vector<double> xx(nvar),dder(nvar);
     793          92 :   std::vector<double> dx=grid->getDx();
     794             :   double f,x;
     795     1138531 :   while( ifile.scanField(funcl,f) ) {
     796     3410248 :     for(unsigned i=0; i<nvar; ++i) {
     797     2271809 :       ifile.scanField(labels[i],x);
     798     2271809 :       xx[i]=x+dx[i]/2.0;
     799     4543618 :       ifile.scanField( "min_" + labels[i], gmin[i]);
     800     4543618 :       ifile.scanField( "max_" + labels[i], gmax[i]);
     801     4543618 :       ifile.scanField( "nbins_" + labels[i], gbin1[i]);
     802     4543618 :       ifile.scanField( "periodic_" + labels[i], pstring );
     803             :     }
     804     1138439 :     if(hasder) {
     805     3284226 :       for(unsigned i=0; i<nvar; ++i) {
     806     4376792 :         ifile.scanField( "der_" + labels[i], dder[i] );
     807             :       }
     808             :     }
     809     1138439 :     index_t index=grid->getIndex(xx);
     810     1138439 :     if(doder) {
     811     1095722 :       grid->setValueAndDerivatives(index,f,dder);
     812             :     } else {
     813       42717 :       grid->setValue(index,f);
     814             :     }
     815     1138439 :     ifile.scanField();
     816             :   }
     817          92 :   return grid;
     818          97 : }
     819             : 
     820         861 : double Grid::getMinValue() const {
     821             :   double minval;
     822             :   minval=DBL_MAX;
     823     2258311 :   for(index_t i=0; i<grid_.size(); ++i) {
     824     2257450 :     if(grid_[i]<minval) {
     825             :       minval=grid_[i];
     826             :     }
     827             :   }
     828         861 :   return minval;
     829             : }
     830             : 
     831        1202 : double Grid::getMaxValue() const {
     832             :   double maxval;
     833             :   maxval=DBL_MIN;
     834    11595330 :   for(index_t i=0; i<grid_.size(); ++i) {
     835    11594128 :     if(grid_[i]>maxval) {
     836             :       maxval=grid_[i];
     837             :     }
     838             :   }
     839        1202 :   return maxval;
     840             : }
     841             : 
     842         607 : void Grid::scaleAllValuesAndDerivatives( const double& scalef ) {
     843         607 :   if(usederiv_) {
     844       33548 :     for(index_t i=0; i<grid_.size(); ++i) {
     845       33524 :       grid_[i]*=scalef;
     846       99570 :       for(unsigned j=0; j<dimension_; ++j) {
     847       66046 :         der_[i*dimension_+j]*=scalef;
     848             :       }
     849             :     }
     850             :   } else {
     851     1572834 :     for(index_t i=0; i<grid_.size(); ++i) {
     852     1572251 :       grid_[i]*=scalef;
     853             :     }
     854             :   }
     855         607 : }
     856             : 
     857           0 : void Grid::logAllValuesAndDerivatives( const double& scalef ) {
     858           0 :   if(usederiv_) {
     859           0 :     for(index_t i=0; i<grid_.size(); ++i) {
     860           0 :       grid_[i] = scalef*std::log(grid_[i]);
     861           0 :       for(unsigned j=0; j<dimension_; ++j) {
     862           0 :         der_[i*dimension_+j] = scalef/der_[i*dimension_+j];
     863             :       }
     864             :     }
     865             :   } else {
     866           0 :     for(index_t i=0; i<grid_.size(); ++i) {
     867           0 :       grid_[i] = scalef*std::log(grid_[i]);
     868             :     }
     869             :   }
     870           0 : }
     871             : 
     872        1329 : void Grid::setMinToZero() {
     873        1329 :   double min=grid_[0];
     874     3518541 :   for(index_t i=1; i<grid_.size(); ++i)
     875     3517212 :     if(grid_[i]<min) {
     876             :       min=grid_[i];
     877             :     }
     878     3519870 :   for(index_t i=0; i<grid_.size(); ++i) {
     879     3518541 :     grid_[i] -= min;
     880             :   }
     881        1329 : }
     882             : 
     883           1 : void Grid::applyFunctionAllValuesAndDerivatives( double (*func)(double val), double (*funcder)(double valder) ) {
     884           1 :   if(usederiv_) {
     885         901 :     for(index_t i=0; i<grid_.size(); ++i) {
     886         900 :       grid_[i]=func(grid_[i]);
     887        2700 :       for(unsigned j=0; j<dimension_; ++j) {
     888        1800 :         der_[i*dimension_+j]=funcder(der_[i*dimension_+j]);
     889             :       }
     890             :     }
     891             :   } else {
     892           0 :     for(index_t i=0; i<grid_.size(); ++i) {
     893           0 :       grid_[i]=func(grid_[i]);
     894             :     }
     895             :   }
     896           1 : }
     897             : 
     898           0 : double Grid::getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ) const {
     899           0 :   return getValueAndDerivatives( x, der ) - contour_location;
     900             : }
     901             : 
     902           0 : void Grid::findSetOfPointsOnContour(const double& target, const std::vector<bool>& nosearch,
     903             :                                     unsigned& npoints, std::vector<std::vector<double> >& points ) {
     904             : // Set contour location for function
     905           0 :   contour_location=target;
     906             : // Resize points to maximum possible value
     907           0 :   points.resize( dimension_*maxsize_ );
     908             : 
     909             : // Two points for search
     910           0 :   std::vector<unsigned> ind(dimension_);
     911           0 :   std::vector<double> direction( dimension_, 0 );
     912             : 
     913             : // Run over whole grid
     914           0 :   npoints=0;
     915             :   RootFindingBase<Grid> mymin( this );
     916           0 :   for(unsigned i=0; i<maxsize_; ++i) {
     917           0 :     for(unsigned j=0; j<dimension_; ++j) {
     918           0 :       ind[j]=getIndices(i)[j];
     919             :     }
     920             : 
     921             :     // Get the value of a point on the grid
     922           0 :     double val1=getValue(i) - target;
     923             : 
     924             :     // Now search for contour in each direction
     925             :     bool edge=false;
     926           0 :     for(unsigned j=0; j<dimension_; ++j) {
     927           0 :       if( nosearch[j] ) {
     928           0 :         continue ;
     929             :       }
     930             :       // Make sure we don't search at the edge of the grid
     931           0 :       if( !pbc_[j] && (ind[j]+1)==nbin_[j] ) {
     932           0 :         continue;
     933           0 :       } else if( (ind[j]+1)==nbin_[j] ) {
     934             :         edge=true;
     935           0 :         ind[j]=0;
     936             :       } else {
     937           0 :         ind[j]+=1;
     938             :       }
     939           0 :       double val2=getValue(ind) - target;
     940           0 :       if( val1*val2<0 ) {
     941             :         // Use initial point location as first guess for search
     942           0 :         points[npoints].resize(dimension_);
     943           0 :         for(unsigned k=0; k<dimension_; ++k) {
     944           0 :           points[npoints][k]=getPoint(i)[k];
     945             :         }
     946             :         // Setup direction vector
     947           0 :         direction[j]=0.999999999*dx_[j];
     948             :         // And do proper search for contour point
     949           0 :         mymin.linesearch( direction, points[npoints], &Grid::getDifferenceFromContour );
     950           0 :         direction[j]=0.0;
     951           0 :         npoints++;
     952             :       }
     953           0 :       if( pbc_[j] && edge ) {
     954             :         edge=false;
     955           0 :         ind[j]=nbin_[j]-1;
     956             :       } else {
     957           0 :         ind[j]-=1;
     958             :       }
     959             :     }
     960             :   }
     961           0 : }
     962             : 
     963             : /// OVERRIDES ARE BELOW
     964             : 
     965    27984931 : Grid::index_t Grid::getSize() const {
     966    27984931 :   return maxsize_;
     967             : }
     968             : 
     969    35819167 : double Grid::getValue(index_t index) const {
     970             :   plumed_dbg_assert(index<maxsize_);
     971    35819167 :   return grid_[index];
     972             : }
     973             : 
     974     3215376 : double Grid::getValueAndDerivatives(index_t index, double* der,std::size_t der_size) const {
     975             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der_size==dimension_);
     976     7034252 :   for(unsigned i=0; i<dimension_; i++) {
     977     3818876 :     der[i]=der_[dimension_*index+i];
     978             :   }
     979     3215376 :   return grid_[index];
     980             : }
     981             : 
     982     6444104 : void Grid::setValue(index_t index, double value) {
     983             :   plumed_dbg_assert(index<maxsize_ && !usederiv_);
     984     6444104 :   grid_[index]=value;
     985     6444104 : }
     986             : 
     987     2592840 : void Grid::setValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
     988             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     989     2592840 :   grid_[index]=value;
     990     7727932 :   for(unsigned i=0; i<dimension_; i++) {
     991     5135092 :     der_[dimension_*index+i]=der[i];
     992             :   }
     993     2592840 : }
     994             : 
     995           1 : void Grid::addValue(index_t index, double value) {
     996             :   plumed_dbg_assert(index<maxsize_ && !usederiv_);
     997           1 :   grid_[index]+=value;
     998           1 : }
     999             : 
    1000     1058017 : void Grid::addValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
    1001             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
    1002     1058017 :   grid_[index]+=value;
    1003     3086538 :   for(unsigned int i=0; i<dimension_; ++i) {
    1004     2028521 :     der_[index*dimension_+i]+=der[i];
    1005             :   }
    1006     1058017 : }
    1007             : 
    1008     4453920 : void Grid::addValueAndDerivatives(index_t index, double value, const double* der, std::size_t der_size) {
    1009             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der_size==dimension_);
    1010     4453920 :   grid_[index]+=value;
    1011    13095620 :   for(unsigned int i=0; i<dimension_; ++i) {
    1012     8641700 :     der_[index*dimension_+i]+=der[i];
    1013             :   }
    1014     4453920 : }
    1015             : 
    1016         123 : void Grid::resizeData(const std::vector<unsigned> & oldnbin, const std::vector<long long> & shift) {
    1017         123 :   std::vector<double> newgrid(maxsize_,0.0);
    1018         123 :   std::vector<double> newder;
    1019         123 :   if(usederiv_) {
    1020         123 :     newder.assign(maxsize_*dimension_,0.0);
    1021             :   }
    1022             :   index_t oldsize=1;
    1023         291 :   for(unsigned i=0; i<dimension_; ++i) {
    1024         168 :     oldsize*=oldnbin[i];
    1025             :   }
    1026             :   // loop over the old points in column-major order
    1027         123 :   std::vector<unsigned> k(dimension_,0);
    1028      152290 :   for(index_t old=0; old<oldsize; ++old) {
    1029             :     bool kept=true;
    1030             :     index_t index=0;
    1031      446599 :     for(unsigned i=dimension_; i-->0;) {
    1032      295714 :       const long long knew=static_cast<long long>(k[i])+shift[i];
    1033      295714 :       if(knew<0 || knew>=static_cast<long long>(nbin_[i])) {
    1034             :         kept=false;
    1035             :         break;
    1036             :       }
    1037      294432 :       index=index*nbin_[i]+static_cast<index_t>(knew);
    1038             :     }
    1039      152167 :     if(kept) {
    1040      150885 :       newgrid[index]=grid_[old];
    1041      150885 :       if(usederiv_) {
    1042      445317 :         for(unsigned i=0; i<dimension_; ++i) {
    1043      294432 :           newder[index*dimension_+i]=der_[old*dimension_+i];
    1044             :         }
    1045             :       }
    1046             :     }
    1047      153572 :     for(unsigned i=0; i<dimension_; ++i) {
    1048      153449 :       if(++k[i]<oldnbin[i]) {
    1049             :         break;
    1050             :       }
    1051        1405 :       k[i]=0;
    1052             :     }
    1053             :   }
    1054             :   grid_.swap(newgrid);
    1055             :   der_.swap(newder);
    1056         123 : }
    1057             : 
    1058           9 : void SparseGrid::resizeData(const std::vector<unsigned> & oldnbin, const std::vector<long long> & shift) {
    1059             :   // new index of the point with index old before resizing, false if it was removed
    1060       17190 :   auto newIndex=[&](index_t old, index_t & index) {
    1061       17190 :     std::vector<long long> k(dimension_);
    1062       51570 :     for(unsigned i=0; i<dimension_; ++i) {
    1063       34380 :       k[i]=static_cast<long long>(old%oldnbin[i])+shift[i];
    1064       34380 :       old/=oldnbin[i];
    1065       34380 :       if(k[i]<0 || k[i]>=static_cast<long long>(nbin_[i])) {
    1066             :         return false;
    1067             :       }
    1068             :     }
    1069       17190 :     index=0;
    1070       51570 :     for(unsigned i=dimension_; i-->0;) {
    1071       34380 :       index=index*nbin_[i]+static_cast<index_t>(k[i]);
    1072             :     }
    1073             :     return true;
    1074           9 :   };
    1075             :   std::map<index_t,double> newmap;
    1076        8604 :   for(const auto & it : map_) {
    1077             :     index_t index;
    1078        8595 :     if(newIndex(it.first,index)) {
    1079        8595 :       newmap[index]=it.second;
    1080             :     }
    1081             :   }
    1082             :   std::map<index_t,std::vector<double>> newder;
    1083        8604 :   for(auto & it : der_) {
    1084             :     index_t index;
    1085        8595 :     if(newIndex(it.first,index)) {
    1086        8595 :       newder[index].swap(it.second);
    1087             :     }
    1088             :   }
    1089             :   map_.swap(newmap);
    1090             :   der_.swap(newder);
    1091           9 : }
    1092             : 
    1093           0 : Grid::index_t SparseGrid::getSize() const {
    1094           0 :   return map_.size();
    1095             : }
    1096             : 
    1097           0 : Grid::index_t SparseGrid::getMaxSize() const {
    1098           0 :   return maxsize_;
    1099             : }
    1100             : 
    1101           0 : double SparseGrid::getValue(index_t index)const {
    1102           0 :   plumed_assert(index<maxsize_);
    1103             :   double value=0.0;
    1104             :   const auto it=map_.find(index);
    1105           0 :   if(it!=map_.end()) {
    1106           0 :     value=it->second;
    1107             :   }
    1108           0 :   return value;
    1109             : }
    1110             : 
    1111       18456 : double SparseGrid::getValueAndDerivatives(index_t index, double* der, std::size_t der_size)const {
    1112       18456 :   plumed_assert(index<maxsize_ && usederiv_ && der_size==dimension_);
    1113             :   double value=0.0;
    1114       50108 :   for(unsigned int i=0; i<dimension_; ++i) {
    1115       31652 :     der[i]=0.0;
    1116             :   }
    1117             :   const auto it=map_.find(index);
    1118       18456 :   if(it!=map_.end()) {
    1119       18290 :     value=it->second;
    1120             :   }
    1121             :   const auto itder=der_.find(index);
    1122       18456 :   if(itder!=der_.end()) {
    1123             :     const auto & second(itder->second);
    1124       49660 :     for(unsigned i=0; i<second.size(); i++) {
    1125       31370 :       der[i]=itder->second[i];
    1126             :     }
    1127             :   }
    1128       18456 :   return value;
    1129             : }
    1130             : 
    1131           0 : void SparseGrid::setValue(index_t index, double value) {
    1132           0 :   plumed_assert(index<maxsize_ && !usederiv_);
    1133           0 :   map_[index]=value;
    1134           0 : }
    1135             : 
    1136          37 : void SparseGrid::setValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
    1137          37 :   plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
    1138          37 :   map_[index]=value;
    1139          37 :   der_[index]=der;
    1140          37 : }
    1141             : 
    1142           0 : void SparseGrid::addValue(index_t index, double value) {
    1143           0 :   plumed_assert(index<maxsize_ && !usederiv_);
    1144           0 :   map_[index]+=value;
    1145           0 : }
    1146             : 
    1147           0 : void SparseGrid::addValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
    1148           0 :   plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
    1149           0 :   map_[index]+=value;
    1150           0 :   der_[index].resize(dimension_);
    1151           0 :   for(unsigned int i=0; i<dimension_; ++i) {
    1152           0 :     der_[index][i]+=der[i];
    1153             :   }
    1154           0 : }
    1155             : 
    1156      796842 : void SparseGrid::addValueAndDerivatives(index_t index, double value, const double* der, std::size_t der_size) {
    1157      796842 :   plumed_assert(index<maxsize_ && usederiv_ && der_size==dimension_);
    1158      796842 :   map_[index]+=value;
    1159      796842 :   der_[index].resize(dimension_);
    1160     2373643 :   for(unsigned int i=0; i<dimension_; ++i) {
    1161     1576801 :     der_[index][i]+=der[i];
    1162             :   }
    1163      796842 : }
    1164             : 
    1165           0 : void SparseGrid::writeToFile(OFile& ofile) {
    1166           0 :   std::vector<double> xx(dimension_);
    1167           0 :   std::vector<double> der(dimension_);
    1168             :   double f;
    1169           0 :   writeHeader(ofile);
    1170           0 :   ofile.fmtField(" "+fmt_);
    1171           0 :   for(const auto & it : map_) {
    1172           0 :     index_t i=it.first;
    1173           0 :     xx=getPoint(i);
    1174           0 :     if(usederiv_) {
    1175           0 :       f=getValueAndDerivatives(i,der);
    1176             :     } else {
    1177           0 :       f=getValue(i);
    1178             :     }
    1179           0 :     if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) {
    1180           0 :       ofile.printf("\n");
    1181             :     }
    1182           0 :     for(unsigned j=0; j<dimension_; ++j) {
    1183           0 :       ofile.printField("min_" + argnames[j], str_min_[j] );
    1184           0 :       ofile.printField("max_" + argnames[j], str_max_[j] );
    1185           0 :       ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) );
    1186           0 :       if( pbc_[j] ) {
    1187           0 :         ofile.printField("periodic_" + argnames[j], "true" );
    1188             :       } else {
    1189           0 :         ofile.printField("periodic_" + argnames[j], "false" );
    1190             :       }
    1191             :     }
    1192           0 :     for(unsigned j=0; j<dimension_; ++j) {
    1193           0 :       ofile.printField(argnames[j],xx[j]);
    1194             :     }
    1195           0 :     ofile.printField(funcname, f);
    1196           0 :     if(usederiv_) {
    1197           0 :       for(unsigned j=0; j<dimension_; ++j) {
    1198           0 :         ofile.printField("der_" + argnames[j],der[j]);
    1199             :       }
    1200             :     }
    1201           0 :     ofile.printField();
    1202             :   }
    1203           0 : }
    1204             : 
    1205           0 : double SparseGrid::getMinValue() const {
    1206             :   double minval;
    1207             :   minval=0.0;
    1208           0 :   for(auto const & i : map_) {
    1209           0 :     if(i.second<minval) {
    1210             :       minval=i.second;
    1211             :     }
    1212             :   }
    1213           0 :   return minval;
    1214             : }
    1215             : 
    1216         445 : double SparseGrid::getMaxValue() const {
    1217             :   double maxval;
    1218             :   maxval=0.0;
    1219     1095898 :   for(auto const & i : map_) {
    1220     1095453 :     if(i.second>maxval) {
    1221             :       maxval=i.second;
    1222             :     }
    1223             :   }
    1224         445 :   return maxval;
    1225             : }
    1226             : 
    1227     1010062 : void Grid::projectOnLowDimension(double &val, std::vector<int> &vHigh, WeightBase * ptr2obj ) {
    1228             :   unsigned i=0;
    1229     3016945 :   for(i=0; i<vHigh.size(); i++) {
    1230     2015726 :     if(vHigh[i]<0) { // this bin needs to be integrated out
    1231             :       // parallelize here???
    1232     1010062 :       for(unsigned j=0; j<(getNbin())[i]; j++) {
    1233     1001219 :         vHigh[i]=int(j);
    1234     1001219 :         projectOnLowDimension(val,vHigh,ptr2obj); // recursive function: this is the core of the mechanism
    1235     1001219 :         vHigh[i]=-1;
    1236             :       }
    1237             :       return; //
    1238             :     }
    1239             :   }
    1240             :   // when there are no more bin to dig in then retrieve the value
    1241     1001219 :   if(i==vHigh.size()) {
    1242     1001219 :     std::vector<unsigned> vv(vHigh.size());
    1243     3003657 :     for(unsigned j=0; j<vHigh.size(); j++) {
    1244     2002438 :       vv[j]=unsigned(vHigh[j]);
    1245             :     }
    1246             :     //
    1247             :     // this is the real assignment !!!!! (hack this to have bias or other stuff)
    1248             :     //
    1249             : 
    1250             :     // this case: produce fes
    1251             :     //val+=exp(beta*getValue(vv)) ;
    1252     1001219 :     double myv=getValue(vv);
    1253     1001219 :     val=ptr2obj->projectInnerLoop(val,myv) ;
    1254             :     // to be added: bias (same as before without negative sign)
    1255             :     //std::cerr<<" VAL: "<<val <<endl;
    1256             :   }
    1257             : }
    1258             : 
    1259          81 : Grid Grid::project(const std::vector<std::string> & proj, WeightBase *ptr2obj ) {
    1260             :   // find extrema only for the projection
    1261          81 :   std::vector<std::string>   smallMin,smallMax;
    1262          81 :   std::vector<unsigned> smallBin;
    1263          81 :   std::vector<unsigned> dimMapping;
    1264          81 :   std::vector<bool> smallIsPeriodic;
    1265          81 :   std::vector<std::string> smallName;
    1266             : 
    1267             :   // check if the two key methods are there
    1268             :   WeightBase* pp = dynamic_cast<WeightBase*>(ptr2obj);
    1269          81 :   if (!pp) {
    1270           0 :     plumed_merror("This WeightBase is not complete: you need a projectInnerLoop and projectOuterLoop ");
    1271             :   }
    1272             : 
    1273         162 :   for(unsigned j=0; j<proj.size(); j++) {
    1274         120 :     for(unsigned i=0; i<getArgNames().size(); i++) {
    1275         120 :       if(proj[j]==getArgNames()[i]) {
    1276             :         unsigned offset;
    1277             :         // note that at sizetime the non periodic dimension get a bin more
    1278         162 :         if(getIsPeriodic()[i]) {
    1279             :           offset=0;
    1280             :         } else {
    1281             :           offset=1;
    1282             :         }
    1283          81 :         smallMax.push_back(getMax()[i]);
    1284          81 :         smallMin.push_back(getMin()[i]);
    1285          81 :         smallBin.push_back(getNbin()[i]-offset);
    1286          81 :         smallIsPeriodic.push_back(getIsPeriodic()[i]);
    1287          81 :         dimMapping.push_back(i);
    1288          81 :         smallName.push_back(getArgNames()[i]);
    1289          81 :         break;
    1290             :       }
    1291             :     }
    1292             :   }
    1293          81 :   Grid smallgrid("projection",smallName,smallMin,smallMax,smallBin,false,false,smallIsPeriodic,smallMin,smallMax);
    1294             :   // check that the two grids are commensurate
    1295         162 :   for(unsigned i=0; i<dimMapping.size(); i++) {
    1296          81 :     plumed_massert(  (smallgrid.getMax())[i] == (getMax())[dimMapping[i]],  "the two input grids are not compatible in max"   );
    1297          81 :     plumed_massert(  (smallgrid.getMin())[i] == (getMin())[dimMapping[i]],  "the two input grids are not compatible in min"   );
    1298          81 :     plumed_massert(  (smallgrid.getNbin())[i]== (getNbin())[dimMapping[i]], "the two input grids are not compatible in bin"   );
    1299             :   }
    1300          81 :   std::vector<unsigned> toBeIntegrated;
    1301         243 :   for(unsigned i=0; i<getArgNames().size(); i++) {
    1302             :     bool doappend=true;
    1303         243 :     for(unsigned j=0; j<dimMapping.size(); j++) {
    1304         162 :       if(dimMapping[j]==i) {
    1305             :         doappend=false;
    1306             :         break;
    1307             :       }
    1308             :     }
    1309         162 :     if(doappend) {
    1310          81 :       toBeIntegrated.push_back(i);
    1311             :     }
    1312             :   }
    1313             : 
    1314             :   // loop over all the points in the Grid, find the corresponding fixed index, rotate over all the other ones
    1315        8924 :   for(unsigned i=0; i<smallgrid.getSize(); i++) {
    1316        8843 :     std::vector<unsigned> v;
    1317        8843 :     v=smallgrid.getIndices(i);
    1318        8843 :     std::vector<int> vHigh((getArgNames()).size(),-1);
    1319       17686 :     for(unsigned j=0; j<dimMapping.size(); j++) {
    1320        8843 :       vHigh[dimMapping[j]]=int(v[j]);
    1321             :     }
    1322             :     // the vector vhigh now contains at the beginning the index of the low dimension and -1 for the values that need to be integrated
    1323        8843 :     double initval=0.;
    1324        8843 :     projectOnLowDimension(initval,vHigh, ptr2obj);
    1325        8843 :     smallgrid.setValue(i,ptr2obj->projectOuterLoop(initval));
    1326             :   }
    1327             : 
    1328          81 :   return smallgrid;
    1329         162 : }
    1330             : 
    1331           0 : double Grid::integrate( std::vector<unsigned>& npoints ) {
    1332             :   plumed_dbg_assert( npoints.size()==dimension_ );
    1333           0 :   plumed_assert( dospline_ );
    1334             : 
    1335             :   unsigned ntotgrid=1;
    1336             :   double box_vol=1.0;
    1337           0 :   std::vector<double> ispacing( npoints.size() );
    1338           0 :   for(unsigned j=0; j<dimension_; ++j) {
    1339           0 :     if( !pbc_[j] ) {
    1340           0 :       ispacing[j] = ( max_[j] - dx_[j] - min_[j] ) / static_cast<double>( npoints[j] );
    1341           0 :       npoints[j]+=1;
    1342             :     } else {
    1343           0 :       ispacing[j] = ( max_[j] - min_[j] ) / static_cast<double>( npoints[j] );
    1344             :     }
    1345           0 :     ntotgrid*=npoints[j];
    1346           0 :     box_vol*=ispacing[j];
    1347             :   }
    1348             : 
    1349           0 :   std::vector<double> vals( dimension_ );
    1350           0 :   std::vector<unsigned> t_index( dimension_ );
    1351             :   double integral=0.0;
    1352           0 :   for(unsigned i=0; i<ntotgrid; ++i) {
    1353           0 :     t_index[0]=(i%npoints[0]);
    1354             :     unsigned kk=i;
    1355           0 :     for(unsigned j=1; j<dimension_-1; ++j) {
    1356           0 :       kk=(kk-t_index[j-1])/npoints[j-1];
    1357           0 :       t_index[j]=(kk%npoints[j]);
    1358             :     }
    1359           0 :     if( dimension_>=2 ) {
    1360           0 :       t_index[dimension_-1]=((kk-t_index[dimension_-2])/npoints[dimension_-2]);
    1361             :     }
    1362             : 
    1363           0 :     for(unsigned j=0; j<dimension_; ++j) {
    1364           0 :       vals[j]=min_[j] + t_index[j]*ispacing[j];
    1365             :     }
    1366             : 
    1367           0 :     integral += getValue( vals );
    1368             :   }
    1369             : 
    1370           0 :   return box_vol*integral;
    1371             : }
    1372             : 
    1373           0 : void Grid::mpiSumValuesAndDerivatives( Communicator& comm ) {
    1374           0 :   comm.Sum( grid_ );
    1375           0 :   for(unsigned i=0; i<der_.size(); ++i) {
    1376           0 :     comm.Sum( der_[i] );
    1377             :   }
    1378           0 : }
    1379             : 
    1380             : 
    1381      213811 : bool indexed_lt(std::pair<Grid::index_t, double> const &x, std::pair<Grid::index_t, double> const   &y) {
    1382      213811 :   return x.second < y.second;
    1383             : }
    1384             : 
    1385         491 : double GridBase::findMaximalPathMinimum(const std::vector<double> &source, const std::vector<double> &sink) {
    1386             :   plumed_dbg_assert(source.size() == dimension_);
    1387             :   plumed_dbg_assert(sink.size() == dimension_);
    1388             :   // Start and end indices
    1389         491 :   index_t source_idx = getIndex(source);
    1390         491 :   index_t sink_idx = getIndex(sink);
    1391             :   // Path cost
    1392             :   double maximal_minimum = 0;
    1393             :   // In one dimension, path searching is very easy--either go one way if it's not periodic,
    1394             :   // or go both ways if it is periodic. There's no reason to pay the cost of Dijkstra.
    1395         491 :   if (dimension_ == 1) {
    1396             :     // Do a search from the grid source to grid sink that does not
    1397             :     // cross the grid boundary.
    1398         147 :     double curr_min_bias = getValue(source_idx);
    1399             :     // Either search from a high source to a low sink.
    1400         147 :     if (source_idx > sink_idx) {
    1401         735 :       for (index_t i = source_idx; i >= sink_idx; i--) {
    1402         588 :         if (curr_min_bias == 0.0) {
    1403             :           break;
    1404             :         }
    1405         588 :         curr_min_bias = fmin(curr_min_bias, getValue(i));
    1406             :       }
    1407             :       // Or search from a low source to a high sink.
    1408           0 :     } else if (source_idx < sink_idx) {
    1409           0 :       for (index_t i = source_idx; i <= sink_idx; i++) {
    1410           0 :         if (curr_min_bias == 0.0) {
    1411             :           break;
    1412             :         }
    1413           0 :         curr_min_bias = fmin(curr_min_bias, getValue(i));
    1414             :       }
    1415             :     }
    1416             :     maximal_minimum = curr_min_bias;
    1417             :     // If the grid is periodic, also do the search that crosses
    1418             :     // the grid boundary.
    1419         147 :     if (pbc_[0]) {
    1420          42 :       double c_min_bias = getValue(source_idx);
    1421             :       // Either go from a high source to the upper boundary and
    1422             :       // then from the bottom boundary to the sink
    1423          42 :       if (source_idx > sink_idx) {
    1424         210 :         for (index_t i = source_idx; i < maxsize_; i++) {
    1425         168 :           if (c_min_bias == 0.0) {
    1426             :             break;
    1427             :           }
    1428         168 :           c_min_bias = fmin(c_min_bias, getValue(i));
    1429             :         }
    1430         210 :         for (index_t i = 0; i <= sink_idx; i++) {
    1431         168 :           if (c_min_bias == 0.0) {
    1432             :             break;
    1433             :           }
    1434         168 :           c_min_bias = fmin(c_min_bias, getValue(i));
    1435             :         }
    1436             :         // Or go from a low source to the bottom boundary and
    1437             :         // then from the high boundary to the sink
    1438           0 :       } else if (source_idx < sink_idx) {
    1439           0 :         for (index_t i = source_idx; i > 0; i--) {
    1440           0 :           if (c_min_bias == 0.0) {
    1441             :             break;
    1442             :           }
    1443           0 :           c_min_bias = fmin(c_min_bias, getValue(i));
    1444             :         }
    1445           0 :         c_min_bias = fmin(c_min_bias, getValue(0));
    1446           0 :         for (index_t i = maxsize_ - 1; i <= sink_idx; i--) {
    1447           0 :           if (c_min_bias == 0.0) {
    1448             :             break;
    1449             :           }
    1450           0 :           c_min_bias = fmin(c_min_bias, getValue(i));
    1451             :         }
    1452             :       }
    1453             :       // If the boundary crossing paths was more biased, it's
    1454             :       // minimal bias replaces the non-boundary-crossing path's
    1455             :       // minimum.
    1456          42 :       maximal_minimum = fmax(maximal_minimum, c_min_bias);
    1457             :     }
    1458             :     // The one dimensional path search is complete.
    1459         147 :     return maximal_minimum;
    1460             :     // In two or more dimensions, path searching isn't trivial and we really
    1461             :     // do need to use a path search algorithm. Dijkstra is the simplest decent
    1462             :     // one. Using it we've never found the path search to be performance
    1463             :     // limiting in any solvated biomolecule test system, but faster options are
    1464             :     // easy to imagine if they become necessary. NB-In this case, we're actually
    1465             :     // using a greedy variant of Dijkstra's algorithm where the first possible
    1466             :     // path to a point always controls the path cost to that point. The structure
    1467             :     // of the cost function in this case guarantees that the calculated costs will
    1468             :     // be correct using this variant even though fine details of the paths may not
    1469             :     // match a normal Dijkstra search.
    1470         344 :   } else if (dimension_ > 1) {
    1471             :     // Prepare calculation temporaries for Dijkstra's algorithm.
    1472             :     // Minimal path costs from source to a given grid point
    1473         344 :     std::vector<double> mins_from_source = std::vector<double>(maxsize_, -1.0);
    1474             :     // Heap for tracking available steps, steps are recorded as std::pairs of
    1475             :     // an index and a value.
    1476         344 :     std::vector< std::pair<index_t, double> > next_steps;
    1477             :     std::pair<index_t, double> curr_indexed_val;
    1478         344 :     std::make_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1479             :     // The search begins at the source index.
    1480         688 :     next_steps.push_back(std::pair<index_t, double>(source_idx, getValue(source_idx)));
    1481         344 :     std::push_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1482             :     // At first no points have been examined and the optimal path has not been found.
    1483             :     bool path_not_found = true;
    1484             :     // Until a path is found,
    1485             :     while (path_not_found) {
    1486             :       // Examine the grid point currently most accessible from
    1487             :       // the set of all previously explored grid points by popping
    1488             :       // it from the top of the heap.
    1489       29550 :       std::pop_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1490             :       curr_indexed_val = next_steps.back();
    1491             :       next_steps.pop_back();
    1492             :       // Check if this point is the sink point, and if so
    1493             :       // finish the loop.
    1494       29550 :       if (curr_indexed_val.first == sink_idx) {
    1495             :         path_not_found = false;
    1496             :         maximal_minimum = curr_indexed_val.second;
    1497         344 :         break;
    1498             :         // Check if this point has reached the worst possible
    1499             :         // value, and if so stop looking for paths.
    1500       29206 :       } else if (curr_indexed_val.second == 0.0) {
    1501             :         maximal_minimum = 0.0;
    1502             :         break;
    1503             :       }
    1504             :       // If the search is not over, add this grid point's neighbors to the
    1505             :       // possible next points to search for the sink.
    1506       29206 :       std::vector<index_t> neighs = getNearestNeighbors(curr_indexed_val.first);
    1507      144396 :       for (unsigned k = 0; k < neighs.size(); k++) {
    1508      115190 :         index_t i = neighs[k];
    1509             :         // If the neighbor has not already been added to the list of possible next steps,
    1510      115190 :         if (mins_from_source[i] == -1.0) {
    1511             :           // Set the cost to reach it via a path through the current point being examined.
    1512       43978 :           mins_from_source[i] = fmin(curr_indexed_val.second, getValue(i));
    1513             :           // Add the neighboring point to the heap of potential next steps.
    1514       43978 :           next_steps.push_back(std::pair<index_t, double>(i, mins_from_source[i]));
    1515       43978 :           std::push_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1516             :         }
    1517             :       }
    1518             :       // Move on to the next best looking step along any of the paths
    1519             :       // growing from the source.
    1520             :     }
    1521             :     // The multidimensional path search is now complete.
    1522             :     return maximal_minimum;
    1523         344 :   }
    1524             :   return 0.0;
    1525             : }
    1526             : 
    1527             : }

Generated by: LCOV version 1.16