LCOV - code coverage report
Current view: top level - tools - Grid.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 490 703 69.7 %
Date: 2026-03-30 13:16:06 Functions: 55 77 71.4 %

          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             : 
      32             : #include <vector>
      33             : #include <cmath>
      34             : #include <iostream>
      35             : #include <sstream>
      36             : #include <cstdio>
      37             : #include <cfloat>
      38             : #include <array>
      39             : 
      40             : namespace PLMD {
      41             : 
      42             : constexpr std::size_t GridBase::maxdim;
      43             : 
      44        1329 : GridBase::GridBase(const std::string& funcl, const std::vector<Value*> & args, const std::vector<std::string> & gmin,
      45        1329 :                    const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv) {
      46             : // various checks
      47        1329 :   plumed_assert(args.size()<=maxdim) << "grid dim cannot exceed "<<maxdim;
      48        1329 :   plumed_massert(args.size()==gmin.size(),"grid min dimensions in input do not match number of arguments");
      49        1329 :   plumed_massert(args.size()==nbin.size(),"number of bins on input do not match number of arguments");
      50        1329 :   plumed_massert(args.size()==gmax.size(),"grid max dimensions in input do not match number of arguments");
      51        1329 :   unsigned dim=gmax.size();
      52             :   std::vector<std::string> names;
      53             :   std::vector<bool> isperiodic;
      54             :   std::vector<std::string> pmin,pmax;
      55        1329 :   names.resize( dim );
      56        1329 :   isperiodic.resize( dim );
      57        1329 :   pmin.resize( dim );
      58        1329 :   pmax.resize( dim );
      59        2937 :   for(unsigned int i=0; i<dim; ++i) {
      60        1608 :     names[i]=args[i]->getName();
      61        1608 :     if( args[i]->isPeriodic() ) {
      62             :       isperiodic[i]=true;
      63         502 :       args[i]->getDomain( pmin[i], pmax[i] );
      64             :     } else {
      65             :       isperiodic[i]=false;
      66             :       pmin[i]="0.";
      67             :       pmax[i]="0.";
      68             :     }
      69             :   }
      70             : // this is a value-independent initializator
      71        1329 :   Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,isperiodic,pmin,pmax);
      72        2658 : }
      73             : 
      74         128 : GridBase::GridBase(const std::string& funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin,
      75             :                    const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv,
      76         128 :                    const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ) {
      77             : // this calls the initializator
      78         128 :   Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,isperiodic,pmin,pmax);
      79         128 : }
      80             : 
      81        1457 : void GridBase::Init(const std::string& funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin,
      82             :                     const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv,
      83             :                     const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ) {
      84        1457 :   fmt_="%14.9f";
      85             : // various checks
      86        1457 :   plumed_assert(names.size()<=maxdim) << "grid size cannot exceed "<<maxdim;
      87        1457 :   plumed_massert(names.size()==gmin.size(),"grid dimensions in input do not match number of arguments");
      88        1457 :   plumed_massert(names.size()==nbin.size(),"grid dimensions in input do not match number of arguments");
      89        1457 :   plumed_massert(names.size()==gmax.size(),"grid dimensions in input do not match number of arguments");
      90        1457 :   dimension_=gmax.size();
      91        1457 :   str_min_=gmin;
      92        1457 :   str_max_=gmax;
      93        1457 :   argnames.resize( dimension_ );
      94        1457 :   min_.resize( dimension_ );
      95        1457 :   max_.resize( dimension_ );
      96        1457 :   pbc_.resize( dimension_ );
      97        3193 :   for(unsigned int i=0; i<dimension_; ++i) {
      98        1736 :     argnames[i]=names[i];
      99        1736 :     if( isperiodic[i] ) {
     100             :       pbc_[i]=true;
     101             :       str_min_[i]=pmin[i];
     102             :       str_max_[i]=pmax[i];
     103             :     } else {
     104             :       pbc_[i]=false;
     105             :     }
     106        1736 :     Tools::convert(str_min_[i],min_[i]);
     107        1736 :     Tools::convert(str_max_[i],max_[i]);
     108        1736 :     funcname=funcl;
     109        1736 :     plumed_massert(max_[i]>min_[i],"maximum in grid must be larger than minimum");
     110        1736 :     plumed_massert(nbin[i]>0,"number of grid points must be greater than zero");
     111             :   }
     112        1457 :   nbin_=nbin;
     113        1457 :   dospline_=dospline;
     114        1457 :   usederiv_=usederiv;
     115        1457 :   if(dospline_) {
     116          93 :     plumed_assert(dospline_==usederiv_);
     117             :   }
     118        1457 :   maxsize_=1;
     119        3193 :   for(unsigned int i=0; i<dimension_; ++i) {
     120        1736 :     dx_.push_back( (max_[i]-min_[i])/static_cast<double>( nbin_[i] ) );
     121        1736 :     if( !pbc_[i] ) {
     122        1170 :       max_[i] += dx_[i];
     123        1170 :       nbin_[i] += 1;
     124             :     }
     125        1736 :     maxsize_*=nbin_[i];
     126             :   }
     127        1457 : }
     128             : 
     129     1360396 : std::vector<std::string> GridBase::getMin() const {
     130     1360396 :   return str_min_;
     131             : }
     132             : 
     133         345 : std::vector<std::string> GridBase::getMax() const {
     134         345 :   return str_max_;
     135             : }
     136             : 
     137     1319585 : std::vector<double> GridBase::getDx() const {
     138     1319585 :   return dx_;
     139             : }
     140             : 
     141       11944 : double GridBase::getDx(index_t j) const {
     142       11944 :   return dx_[j];
     143             : }
     144             : 
     145          37 : double GridBase::getBinVolume() const {
     146             :   double vol=1.;
     147         102 :   for(unsigned i=0; i<dx_.size(); ++i) {
     148          65 :     vol*=dx_[i];
     149             :   }
     150          37 :   return vol;
     151             : }
     152             : 
     153        2240 : std::vector<bool> GridBase::getIsPeriodic() const {
     154        2240 :   return pbc_;
     155             : }
     156             : 
     157     1012510 : std::vector<unsigned> GridBase::getNbin() const {
     158     1012510 :   return nbin_;
     159             : }
     160             : 
     161        9436 : std::vector<std::string> GridBase::getArgNames() const {
     162        9436 :   return argnames;
     163             : }
     164             : 
     165    18321217 : unsigned GridBase::getDimension() const {
     166    18321217 :   return dimension_;
     167             : }
     168             : 
     169             : // we are flattening arrays using a column-major order
     170     7146297 : GridBase::index_t GridBase::getIndex(const std::vector<unsigned> & indices) const {
     171             :   plumed_dbg_assert(indices.size()==dimension_);
     172    19320328 :   for(unsigned int i=0; i<dimension_; i++)
     173    12174031 :     if(indices[i]>=nbin_[i]) {
     174             :       std::string is;
     175           0 :       Tools::convert(i,is);
     176           0 :       plumed_error() << "Looking for a value outside the grid along the " << is << " dimension (arg name: "<<getArgNames()[i]<<")";
     177             :     }
     178     7146297 :   index_t index=indices[dimension_-1];
     179    12174031 :   for(unsigned int i=dimension_-1; i>0; --i) {
     180     5027734 :     index=index*nbin_[i-1]+indices[i-1];
     181             :   }
     182     7146297 :   return index;
     183             : }
     184             : 
     185     1100069 : GridBase::index_t GridBase::getIndex(const std::vector<double> & x) const {
     186             :   plumed_dbg_assert(x.size()==dimension_);
     187     2200138 :   return getIndex(getIndices(x));
     188             : }
     189             : 
     190             : // we are flattening arrays using a column-major order
     191    37829929 : std::vector<unsigned> GridBase::getIndices(index_t index) const {
     192    37829929 :   std::vector<unsigned> indices(dimension_);
     193             :   index_t kk=index;
     194    37829929 :   indices[0]=(index%nbin_[0]);
     195    54778638 :   for(unsigned int i=1; i<dimension_-1; ++i) {
     196    16948709 :     kk=(kk-indices[i-1])/nbin_[i-1];
     197    16948709 :     indices[i]=(kk%nbin_[i]);
     198             :   }
     199    37829929 :   if(dimension_>=2) {
     200    36999987 :     indices[dimension_-1]=((kk-indices[dimension_-2])/nbin_[dimension_-2]);
     201             :   }
     202    37829929 :   return indices;
     203             : }
     204             : 
     205        8964 : void GridBase::getIndices(index_t index, std::vector<unsigned>& indices) const {
     206        8964 :   if (indices.size()!=dimension_) {
     207        3738 :     indices.resize(dimension_);
     208             :   }
     209             :   index_t kk=index;
     210        8964 :   indices[0]=(index%nbin_[0]);
     211        8964 :   for(unsigned int i=1; i<dimension_-1; ++i) {
     212           0 :     kk=(kk-indices[i-1])/nbin_[i-1];
     213           0 :     indices[i]=(kk%nbin_[i]);
     214             :   }
     215        8964 :   if(dimension_>=2) {
     216        2980 :     indices[dimension_-1]=((kk-indices[dimension_-2])/nbin_[dimension_-2]);
     217             :   }
     218        8964 : }
     219             : 
     220     1104293 : std::vector<unsigned> GridBase::getIndices(const std::vector<double> & x) const {
     221             :   plumed_dbg_assert(x.size()==dimension_);
     222     1104293 :   std::vector<unsigned> indices(dimension_);
     223     3308093 :   for(unsigned int i=0; i<dimension_; ++i) {
     224     2203800 :     indices[i] = unsigned(std::floor((x[i]-min_[i])/dx_[i]));
     225             :   }
     226     1104293 :   return indices;
     227             : }
     228             : 
     229        3738 : void GridBase::getIndices(const std::vector<double> & x, std::vector<unsigned>& indices) const {
     230             :   plumed_dbg_assert(x.size()==dimension_);
     231        3738 :   if (indices.size()!=dimension_) {
     232           0 :     indices.resize(dimension_);
     233             :   }
     234        8221 :   for(unsigned int i=0; i<dimension_; ++i) {
     235        4483 :     indices[i] = unsigned(std::floor((x[i]-min_[i])/dx_[i]));
     236             :   }
     237        3738 : }
     238             : 
     239    31542440 : std::vector<double> GridBase::getPoint(const std::vector<unsigned> & indices) const {
     240             :   plumed_dbg_assert(indices.size()==dimension_);
     241    31542440 :   std::vector<double> x(dimension_);
     242   108460905 :   for(unsigned int i=0; i<dimension_; ++i) {
     243    76918465 :     x[i]=min_[i]+(double)(indices[i])*dx_[i];
     244             :   }
     245    31542440 :   return x;
     246             : }
     247             : 
     248    28822338 : std::vector<double> GridBase::getPoint(index_t index) const {
     249             :   plumed_dbg_assert(index<maxsize_);
     250    57644676 :   return getPoint(getIndices(index));
     251             : }
     252             : 
     253           0 : std::vector<double> GridBase::getPoint(const std::vector<double> & x) const {
     254             :   plumed_dbg_assert(x.size()==dimension_);
     255           0 :   return getPoint(getIndices(x));
     256             : }
     257             : 
     258     1110725 : void GridBase::getPoint(index_t index,std::vector<double> & point) const {
     259             :   plumed_dbg_assert(index<maxsize_);
     260     1110725 :   getPoint(getIndices(index),point);
     261     1110725 : }
     262             : 
     263     1114463 : void GridBase::getPoint(const std::vector<unsigned> & indices,std::vector<double> & point) const {
     264             :   plumed_dbg_assert(indices.size()==dimension_);
     265             :   plumed_dbg_assert(point.size()==dimension_);
     266     3330298 :   for(unsigned int i=0; i<dimension_; ++i) {
     267     2215835 :     point[i]=min_[i]+(double)(indices[i])*dx_[i];
     268             :   }
     269     1114463 : }
     270             : 
     271           0 : void GridBase::getPoint(const std::vector<double> & x,std::vector<double> & point) const {
     272             :   plumed_dbg_assert(x.size()==dimension_);
     273           0 :   getPoint(getIndices(x),point);
     274           0 : }
     275             : 
     276       23376 : std::vector<GridBase::index_t> GridBase::getNeighbors(const std::vector<unsigned> &indices,const std::vector<unsigned> &nneigh)const {
     277             :   plumed_dbg_assert(indices.size()==dimension_ && nneigh.size()==dimension_);
     278             : 
     279             :   std::vector<index_t> neighbors;
     280       23376 :   std::vector<unsigned> small_bin(dimension_);
     281             : 
     282             :   unsigned small_nbin=1;
     283       69616 :   for(unsigned j=0; j<dimension_; ++j) {
     284       46240 :     small_bin[j]=(2*nneigh[j]+1);
     285       46240 :     small_nbin*=small_bin[j];
     286             :   }
     287             : 
     288       23376 :   std::vector<unsigned> small_indices(dimension_);
     289             :   std::vector<unsigned> tmp_indices;
     290     1292414 :   for(unsigned index=0; index<small_nbin; ++index) {
     291     1269038 :     tmp_indices.resize(dimension_);
     292             :     unsigned kk=index;
     293     1269038 :     small_indices[0]=(index%small_bin[0]);
     294     1269038 :     for(unsigned i=1; i<dimension_-1; ++i) {
     295           0 :       kk=(kk-small_indices[i-1])/small_bin[i-1];
     296           0 :       small_indices[i]=(kk%small_bin[i]);
     297             :     }
     298     1269038 :     if(dimension_>=2) {
     299     1255566 :       small_indices[dimension_-1]=((kk-small_indices[dimension_-2])/small_bin[dimension_-2]);
     300             :     }
     301             :     unsigned ll=0;
     302     3793642 :     for(unsigned i=0; i<dimension_; ++i) {
     303     2524604 :       int i0=small_indices[i]-nneigh[i]+indices[i];
     304     2524604 :       if(!pbc_[i] && i0<0) {
     305       19722 :         continue;
     306             :       }
     307     2504882 :       if(!pbc_[i] && i0>=static_cast<int>(nbin_[i])) {
     308       20972 :         continue;
     309             :       }
     310     2483910 :       if( pbc_[i] && i0<0) {
     311        5947 :         i0=nbin_[i]-(-i0)%nbin_[i];
     312             :       }
     313     2483910 :       if( pbc_[i] && i0>=static_cast<int>(nbin_[i])) {
     314        9978 :         i0%=nbin_[i];
     315             :       }
     316     2483910 :       tmp_indices[ll]=static_cast<unsigned>(i0);
     317     2483910 :       ll++;
     318             :     }
     319     1269038 :     tmp_indices.resize(ll);
     320     1269038 :     if(tmp_indices.size()==dimension_) {
     321     1245710 :       neighbors.push_back(getIndex(tmp_indices));
     322             :     }
     323             :   }
     324       23376 :   return neighbors;
     325             : }
     326             : 
     327        4223 : std::vector<GridBase::index_t> GridBase::getNeighbors(const std::vector<double> & x,const std::vector<unsigned> & nneigh)const {
     328             :   plumed_dbg_assert(x.size()==dimension_ && nneigh.size()==dimension_);
     329        8446 :   return getNeighbors(getIndices(x),nneigh);
     330             : }
     331             : 
     332       19153 : std::vector<GridBase::index_t> GridBase::getNeighbors(index_t index,const std::vector<unsigned> & nneigh)const {
     333             :   plumed_dbg_assert(index<maxsize_ && nneigh.size()==dimension_);
     334       38306 :   return getNeighbors(getIndices(index),nneigh);
     335             : }
     336             : 
     337        3738 : void GridBase::getSplineNeighbors(const std::vector<unsigned> & indices, std::vector<GridBase::index_t>& neighbors, unsigned& nneighbors)const {
     338             :   plumed_dbg_assert(indices.size()==dimension_);
     339        3738 :   unsigned nneigh=unsigned(std::pow(2.0,int(dimension_)));
     340        3738 :   if (neighbors.size()!=nneigh) {
     341        3738 :     neighbors.resize(nneigh);
     342             :   }
     343             : 
     344        3738 :   std::vector<unsigned> nindices(dimension_);
     345             :   unsigned inind;
     346        3738 :   nneighbors = 0;
     347       12704 :   for(unsigned int i=0; i<nneigh; ++i) {
     348             :     unsigned tmp=i;
     349             :     inind=0;
     350       20912 :     for(unsigned int j=0; j<dimension_; ++j) {
     351       11946 :       unsigned i0=tmp%2+indices[j];
     352       11946 :       tmp/=2;
     353       11946 :       if(!pbc_[j] && i0==nbin_[j]) {
     354           2 :         continue;
     355             :       }
     356       11944 :       if( pbc_[j] && i0==nbin_[j]) {
     357             :         i0=0;
     358             :       }
     359       11944 :       nindices[inind++]=i0;
     360             :     }
     361        8966 :     if(inind==dimension_) {
     362        8964 :       neighbors[nneighbors++]=getIndex(nindices);
     363             :     }
     364             :   }
     365        3738 : }
     366             : 
     367        9577 : std::vector<GridBase::index_t> GridBase::getNearestNeighbors(const index_t index) const {
     368        9577 :   std::vector<index_t> nearest_neighs = std::vector<index_t>();
     369       28730 :   for (unsigned i = 0; i < dimension_; i++) {
     370       19153 :     std::vector<unsigned> neighsneeded = std::vector<unsigned>(dimension_, 0);
     371       19153 :     neighsneeded[i] = 1;
     372       19153 :     std::vector<index_t> singledim_nearest_neighs = getNeighbors(index, neighsneeded);
     373       74978 :     for (unsigned j = 0; j < singledim_nearest_neighs.size(); j++) {
     374       55825 :       index_t neigh = singledim_nearest_neighs[j];
     375       55825 :       if (neigh != index) {
     376       36672 :         nearest_neighs.push_back(neigh);
     377             :       }
     378             :     }
     379             :   }
     380        9577 :   return nearest_neighs;
     381             : }
     382             : 
     383           0 : std::vector<GridBase::index_t> GridBase::getNearestNeighbors(const std::vector<unsigned> &indices) const {
     384             :   plumed_dbg_assert(indices.size() == dimension_);
     385           0 :   return getNearestNeighbors(getIndex(indices));
     386             : }
     387             : 
     388           0 : void GridBase::addKernel( const KernelFunctions& kernel ) {
     389             :   plumed_dbg_assert( kernel.ndim()==dimension_ );
     390           0 :   std::vector<unsigned> nneighb=kernel.getSupport( dx_ );
     391           0 :   std::vector<index_t> neighbors=getNeighbors( kernel.getCenter(), nneighb );
     392           0 :   std::vector<double> xx( dimension_ );
     393           0 :   std::vector<std::unique_ptr<Value>> vv( dimension_ );
     394             :   std::string str_min, str_max;
     395           0 :   for(unsigned i=0; i<dimension_; ++i) {
     396           0 :     vv[i]=Tools::make_unique<Value>();
     397           0 :     if( pbc_[i] ) {
     398           0 :       Tools::convert(min_[i],str_min);
     399           0 :       Tools::convert(max_[i],str_max);
     400           0 :       vv[i]->setDomain( str_min, str_max );
     401             :     } else {
     402           0 :       vv[i]->setNotPeriodic();
     403             :     }
     404             :   }
     405             : 
     406             : // vv_ptr contains plain pointers obtained from vv.
     407             : // this is the simplest way to replace a unique_ptr here.
     408             : // perhaps the interface of kernel.evaluate() should be changed
     409             : // in order to accept a std::vector<std::unique_ptr<Value>>
     410           0 :   auto vv_ptr=Tools::unique2raw(vv);
     411             : 
     412           0 :   std::vector<double> der( dimension_ );
     413           0 :   for(unsigned i=0; i<neighbors.size(); ++i) {
     414           0 :     index_t ineigh=neighbors[i];
     415           0 :     getPoint( ineigh, xx );
     416           0 :     for(unsigned j=0; j<dimension_; ++j) {
     417           0 :       vv[j]->set(xx[j]);
     418             :     }
     419           0 :     double newval = kernel.evaluate( vv_ptr, der, usederiv_ );
     420           0 :     if( usederiv_ ) {
     421           0 :       addValueAndDerivatives( ineigh, newval, der );
     422             :     } else {
     423           0 :       addValue( ineigh, newval );
     424             :     }
     425             :   }
     426           0 : }
     427             : 
     428     1193613 : double GridBase::getValue(const std::vector<unsigned> & indices) const {
     429     1193613 :   return getValue(getIndex(indices));
     430             : }
     431             : 
     432         357 : double GridBase::getValue(const std::vector<double> & x) const {
     433         357 :   if(!dospline_) {
     434          18 :     return getValue(getIndex(x));
     435             :   } else {
     436         339 :     std::vector<double> der(dimension_);
     437         339 :     return getValueAndDerivatives(x,der);
     438             :   }
     439             : }
     440             : 
     441     2527708 : double GridBase::getValueAndDerivatives(const std::vector<unsigned> & indices, std::vector<double>& der) const {
     442     2527708 :   return getValueAndDerivatives(getIndex(indices),der);
     443             : }
     444             : 
     445        3738 : double GridBase::getValueAndDerivatives(const std::vector<double> & x, std::vector<double>& der) const {
     446             :   plumed_dbg_assert(der.size()==dimension_ && usederiv_);
     447             : 
     448        3738 :   if(dospline_) {
     449             :     double X,X2,X3,value;
     450             :     std::array<double,maxdim> fd, C, D;
     451        3738 :     std::vector<double> dder(dimension_);
     452             : // reset
     453             :     value=0.0;
     454        8221 :     for(unsigned int i=0; i<dimension_; ++i) {
     455        4483 :       der[i]=0.0;
     456             :     }
     457             : 
     458        3738 :     std::vector<unsigned> indices(dimension_);
     459        3738 :     getIndices(x, indices);
     460        3738 :     std::vector<double> xfloor(dimension_);
     461        3738 :     getPoint(indices, xfloor);
     462             :     std::vector<index_t> neigh;
     463             :     unsigned nneigh;
     464        3738 :     getSplineNeighbors(indices, neigh, nneigh);
     465             : 
     466             : // loop over neighbors
     467             :     std::vector<unsigned> nindices;
     468       12702 :     for(unsigned int ipoint=0; ipoint<nneigh; ++ipoint) {
     469        8964 :       double grid=getValueAndDerivatives(neigh[ipoint],dder);
     470        8964 :       getIndices(neigh[ipoint], nindices);
     471             :       double ff=1.0;
     472             : 
     473       20908 :       for(unsigned j=0; j<dimension_; ++j) {
     474             :         int x0=1;
     475       11944 :         if(nindices[j]==indices[j]) {
     476             :           x0=0;
     477             :         }
     478       11944 :         double dx=getDx(j);
     479       11944 :         X=std::abs((x[j]-xfloor[j])/dx-(double)x0);
     480       11944 :         X2=X*X;
     481       11944 :         X3=X2*X;
     482             :         double yy;
     483       11944 :         if(std::abs(grid)<0.0000001) {
     484             :           yy=0.0;
     485             :         } else {
     486        9032 :           yy=-dder[j]/grid;
     487             :         }
     488       11944 :         C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*dx;
     489       11944 :         D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*dx;
     490       11944 :         D[j]*=(x0?-1.0:1.0)/dx;
     491       11944 :         ff*=C[j];
     492             :       }
     493       20908 :       for(unsigned j=0; j<dimension_; ++j) {
     494       11944 :         fd[j]=D[j];
     495       29848 :         for(unsigned i=0; i<dimension_; ++i)
     496       17904 :           if(i!=j) {
     497        5960 :             fd[j]*=C[i];
     498             :           }
     499             :       }
     500        8964 :       value+=grid*ff;
     501       20908 :       for(unsigned j=0; j<dimension_; ++j) {
     502       11944 :         der[j]+=grid*fd[j];
     503             :       }
     504             :     }
     505             :     return value;
     506             :   } else {
     507           0 :     return getValueAndDerivatives(getIndex(x),der);
     508             :   }
     509             : }
     510             : 
     511           0 : void GridBase::setValue(const std::vector<unsigned> & indices, double value) {
     512           0 :   setValue(getIndex(indices),value);
     513           0 : }
     514             : 
     515           0 : void GridBase::setValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der) {
     516           0 :   setValueAndDerivatives(getIndex(indices),value,der);
     517           0 : }
     518             : 
     519           0 : void GridBase::addValue(const std::vector<unsigned> & indices, double value) {
     520           0 :   addValue(getIndex(indices),value);
     521           0 : }
     522             : 
     523           0 : void GridBase::addValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der) {
     524           0 :   addValueAndDerivatives(getIndex(indices),value,der);
     525           0 : }
     526             : 
     527        1147 : void GridBase::writeHeader(OFile& ofile) {
     528        2611 :   for(unsigned i=0; i<dimension_; ++i) {
     529        2928 :     ofile.addConstantField("min_" + argnames[i]);
     530        2928 :     ofile.addConstantField("max_" + argnames[i]);
     531        2928 :     ofile.addConstantField("nbins_" + argnames[i]);
     532        2928 :     ofile.addConstantField("periodic_" + argnames[i]);
     533             :   }
     534        1147 : }
     535             : 
     536           1 : void Grid::clear() {
     537           1 :   grid_.assign(maxsize_,0.0);
     538           1 :   if(usederiv_) {
     539           0 :     der_.assign(maxsize_*dimension_,0.0);
     540             :   }
     541           1 : }
     542             : 
     543        1147 : void Grid::writeToFile(OFile& ofile) {
     544        1147 :   std::vector<double> xx(dimension_);
     545        1147 :   std::vector<double> der(dimension_);
     546             :   double f;
     547        1147 :   writeHeader(ofile);
     548     2533412 :   for(index_t i=0; i<getSize(); ++i) {
     549     2532265 :     xx=getPoint(i);
     550     2532265 :     if(usederiv_) {
     551      542558 :       f=getValueAndDerivatives(i,der);
     552             :     } else {
     553     1989707 :       f=getValue(i);
     554             :     }
     555     4914902 :     if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) {
     556       24551 :       ofile.printf("\n");
     557             :     }
     558     7484524 :     for(unsigned j=0; j<dimension_; ++j) {
     559     9904518 :       ofile.printField("min_" + argnames[j], str_min_[j] );
     560     9904518 :       ofile.printField("max_" + argnames[j], str_max_[j] );
     561     9904518 :       ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) );
     562     4952259 :       if( pbc_[j] ) {
     563     4068696 :         ofile.printField("periodic_" + argnames[j], "true" );
     564             :       } else {
     565     5835822 :         ofile.printField("periodic_" + argnames[j], "false" );
     566             :       }
     567             :     }
     568     7484524 :     for(unsigned j=0; j<dimension_; ++j) {
     569     4952259 :       ofile.fmtField(" "+fmt_);
     570     4952259 :       ofile.printField(argnames[j],xx[j]);
     571             :     }
     572     2532265 :     ofile.fmtField(" "+fmt_);
     573     2532265 :     ofile.printField(funcname,f);
     574     2532265 :     if(usederiv_)
     575     1602295 :       for(unsigned j=0; j<dimension_; ++j) {
     576     1059737 :         ofile.fmtField(" "+fmt_);
     577     2119474 :         ofile.printField("der_" + argnames[j],der[j]);
     578             :       }
     579     2532265 :     ofile.printField();
     580             :   }
     581        1147 : }
     582             : 
     583           0 : void GridBase::writeCubeFile(OFile& ofile, const double& lunit) {
     584           0 :   plumed_assert( dimension_==3 );
     585           0 :   ofile.printf("PLUMED CUBE FILE\n");
     586           0 :   ofile.printf("OUTER LOOP: X, MIDDLE LOOP: Y, INNER LOOP: Z\n");
     587             :   // Number of atoms followed by position of origin (origin set so that center of grid is in center of cell)
     588           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]));
     589           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
     590           0 :   ofile.printf("%u %f %f %f\n",nbin_[1],0.0,lunit*dx_[1],0.0);  // shape of voxel
     591           0 :   ofile.printf("%u %f %f %f\n",nbin_[2],0.0,0.0,lunit*dx_[2]);
     592           0 :   ofile.printf("%d %f %f %f\n",1,0.0,0.0,0.0); // Fake atom otherwise VMD doesn't work
     593           0 :   std::vector<unsigned> pp(3);
     594           0 :   for(pp[0]=0; pp[0]<nbin_[0]; ++pp[0]) {
     595           0 :     for(pp[1]=0; pp[1]<nbin_[1]; ++pp[1]) {
     596           0 :       for(pp[2]=0; pp[2]<nbin_[2]; ++pp[2]) {
     597           0 :         ofile.printf("%f ",getValue(pp) );
     598           0 :         if(pp[2]%6==5) {
     599           0 :           ofile.printf("\n");
     600             :         }
     601             :       }
     602           0 :       ofile.printf("\n");
     603             :     }
     604             :   }
     605           0 : }
     606             : 
     607          20 : std::unique_ptr<GridBase> GridBase::create(const std::string& funcl, const std::vector<Value*> & args, IFile& ifile,
     608             :     const std::vector<std::string> & gmin,const std::vector<std::string> & gmax,
     609             :     const std::vector<unsigned> & nbin,bool dosparse, bool dospline, bool doder) {
     610          20 :   std::unique_ptr<GridBase> grid=GridBase::create(funcl,args,ifile,dosparse,dospline,doder);
     611          20 :   std::vector<unsigned> cbin( grid->getNbin() );
     612          20 :   std::vector<std::string> cmin( grid->getMin() ), cmax( grid->getMax() );
     613          49 :   for(unsigned i=0; i<args.size(); ++i) {
     614          29 :     plumed_massert( cmin[i]==gmin[i], "mismatched grid min" );
     615          29 :     plumed_massert( cmax[i]==gmax[i], "mismatched grid max" );
     616          29 :     if( args[i]->isPeriodic() ) {
     617           8 :       plumed_massert( cbin[i]==nbin[i], "mismatched grid nbins" );
     618             :     } else {
     619          21 :       plumed_massert( (cbin[i]-1)==nbin[i], "mismatched grid nbins");
     620             :     }
     621             :   }
     622          20 :   return grid;
     623          20 : }
     624             : 
     625          70 : std::unique_ptr<GridBase> GridBase::create(const std::string& funcl, const std::vector<Value*> & args, IFile& ifile, bool dosparse, bool dospline, bool doder) {
     626          70 :   std::unique_ptr<GridBase> grid;
     627          70 :   unsigned nvar=args.size();
     628             :   bool hasder=false;
     629             :   std::string pstring;
     630          70 :   std::vector<int> gbin1(nvar);
     631          70 :   std::vector<unsigned> gbin(nvar);
     632          70 :   std::vector<std::string> labels(nvar),gmin(nvar),gmax(nvar);
     633             :   std::vector<std::string> fieldnames;
     634          70 :   ifile.scanFieldList( fieldnames );
     635             : // Retrieve names for fields
     636         158 :   for(unsigned i=0; i<args.size(); ++i) {
     637          88 :     labels[i]=args[i]->getName();
     638             :   }
     639             : // And read the stuff from the header
     640          70 :   plumed_massert( ifile.FieldExist( funcl ), "no column labelled " + funcl + " in in grid input");
     641         158 :   for(unsigned i=0; i<args.size(); ++i) {
     642         176 :     ifile.scanField( "min_" + labels[i], gmin[i]);
     643         176 :     ifile.scanField( "max_" + labels[i], gmax[i]);
     644         176 :     ifile.scanField( "periodic_" + labels[i], pstring );
     645         176 :     ifile.scanField( "nbins_" + labels[i], gbin1[i]);
     646          88 :     plumed_assert( gbin1[i]>0 );
     647          88 :     if( args[i]->isPeriodic() ) {
     648          26 :       plumed_massert( pstring=="true", "input value is periodic but grid is not");
     649             :       std::string pmin, pmax;
     650          26 :       args[i]->getDomain( pmin, pmax );
     651          26 :       gbin[i]=gbin1[i];
     652          26 :       if( pmin!=gmin[i] || pmax!=gmax[i] ) {
     653           0 :         plumed_merror("mismatch between grid boundaries and periods of values");
     654             :       }
     655             :     } else {
     656          62 :       gbin[i]=gbin1[i]-1;  // Note header in grid file indicates one more bin that there should be when data is not periodic
     657          62 :       plumed_massert( pstring=="false", "input value is not periodic but grid is");
     658             :     }
     659          88 :     hasder=ifile.FieldExist( "der_" + args[i]->getName() );
     660          88 :     if( doder && !hasder ) {
     661           0 :       plumed_merror("missing derivatives from grid file");
     662             :     }
     663         106 :     for(unsigned j=0; j<fieldnames.size(); ++j) {
     664         124 :       for(unsigned k=i+1; k<args.size(); ++k) {
     665          18 :         if( fieldnames[j]==labels[k] ) {
     666           0 :           plumed_merror("arguments in input are not in same order as in grid file");
     667             :         }
     668             :       }
     669         106 :       if( fieldnames[j]==labels[i] ) {
     670             :         break;
     671             :       }
     672             :     }
     673             :   }
     674             : 
     675          70 :   if(!dosparse) {
     676          70 :     grid=Tools::make_unique<Grid>(funcl,args,gmin,gmax,gbin,dospline,doder);
     677             :   } else {
     678           0 :     grid=Tools::make_unique<SparseGrid>(funcl,args,gmin,gmax,gbin,dospline,doder);
     679             :   }
     680             : 
     681          70 :   std::vector<double> xx(nvar),dder(nvar);
     682          70 :   std::vector<double> dx=grid->getDx();
     683             :   double f,x;
     684     1099575 :   while( ifile.scanField(funcl,f) ) {
     685     3294553 :     for(unsigned i=0; i<nvar; ++i) {
     686     2195048 :       ifile.scanField(labels[i],x);
     687     2195048 :       xx[i]=x+dx[i]/2.0;
     688     4390096 :       ifile.scanField( "min_" + labels[i], gmin[i]);
     689     4390096 :       ifile.scanField( "max_" + labels[i], gmax[i]);
     690     4390096 :       ifile.scanField( "nbins_" + labels[i], gbin1[i]);
     691     4390096 :       ifile.scanField( "periodic_" + labels[i], pstring );
     692             :     }
     693     1099505 :     if(hasder) {
     694     3168531 :       for(unsigned i=0; i<nvar; ++i) {
     695     4223270 :         ifile.scanField( "der_" + args[i]->getName(), dder[i] );
     696             :       }
     697             :     }
     698     1099505 :     index_t index=grid->getIndex(xx);
     699     1099505 :     if(doder) {
     700     1056788 :       grid->setValueAndDerivatives(index,f,dder);
     701             :     } else {
     702       42717 :       grid->setValue(index,f);
     703             :     }
     704     1099505 :     ifile.scanField();
     705             :   }
     706          70 :   return grid;
     707          70 : }
     708             : 
     709         861 : double Grid::getMinValue() const {
     710             :   double minval;
     711             :   minval=DBL_MAX;
     712     2258311 :   for(index_t i=0; i<grid_.size(); ++i) {
     713     2257450 :     if(grid_[i]<minval) {
     714             :       minval=grid_[i];
     715             :     }
     716             :   }
     717         861 :   return minval;
     718             : }
     719             : 
     720         629 : double Grid::getMaxValue() const {
     721             :   double maxval;
     722             :   maxval=DBL_MIN;
     723     3755246 :   for(index_t i=0; i<grid_.size(); ++i) {
     724     3754617 :     if(grid_[i]>maxval) {
     725             :       maxval=grid_[i];
     726             :     }
     727             :   }
     728         629 :   return maxval;
     729             : }
     730             : 
     731         594 : void Grid::scaleAllValuesAndDerivatives( const double& scalef ) {
     732         594 :   if(usederiv_) {
     733       21474 :     for(index_t i=0; i<grid_.size(); ++i) {
     734       21463 :       grid_[i]*=scalef;
     735       63888 :       for(unsigned j=0; j<dimension_; ++j) {
     736       42425 :         der_[i*dimension_+j]*=scalef;
     737             :       }
     738             :     }
     739             :   } else {
     740     1572834 :     for(index_t i=0; i<grid_.size(); ++i) {
     741     1572251 :       grid_[i]*=scalef;
     742             :     }
     743             :   }
     744         594 : }
     745             : 
     746           0 : void Grid::logAllValuesAndDerivatives( const double& scalef ) {
     747           0 :   if(usederiv_) {
     748           0 :     for(index_t i=0; i<grid_.size(); ++i) {
     749           0 :       grid_[i] = scalef*std::log(grid_[i]);
     750           0 :       for(unsigned j=0; j<dimension_; ++j) {
     751           0 :         der_[i*dimension_+j] = scalef/der_[i*dimension_+j];
     752             :       }
     753             :     }
     754             :   } else {
     755           0 :     for(index_t i=0; i<grid_.size(); ++i) {
     756           0 :       grid_[i] = scalef*std::log(grid_[i]);
     757             :     }
     758             :   }
     759           0 : }
     760             : 
     761        1329 : void Grid::setMinToZero() {
     762        1329 :   double min=grid_[0];
     763     3518541 :   for(index_t i=1; i<grid_.size(); ++i)
     764     3517212 :     if(grid_[i]<min) {
     765             :       min=grid_[i];
     766             :     }
     767     3519870 :   for(index_t i=0; i<grid_.size(); ++i) {
     768     3518541 :     grid_[i] -= min;
     769             :   }
     770        1329 : }
     771             : 
     772           1 : void Grid::applyFunctionAllValuesAndDerivatives( double (*func)(double val), double (*funcder)(double valder) ) {
     773           1 :   if(usederiv_) {
     774         901 :     for(index_t i=0; i<grid_.size(); ++i) {
     775         900 :       grid_[i]=func(grid_[i]);
     776        2700 :       for(unsigned j=0; j<dimension_; ++j) {
     777        1800 :         der_[i*dimension_+j]=funcder(der_[i*dimension_+j]);
     778             :       }
     779             :     }
     780             :   } else {
     781           0 :     for(index_t i=0; i<grid_.size(); ++i) {
     782           0 :       grid_[i]=func(grid_[i]);
     783             :     }
     784             :   }
     785           1 : }
     786             : 
     787           0 : double Grid::getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ) const {
     788           0 :   return getValueAndDerivatives( x, der ) - contour_location;
     789             : }
     790             : 
     791           0 : void Grid::findSetOfPointsOnContour(const double& target, const std::vector<bool>& nosearch,
     792             :                                     unsigned& npoints, std::vector<std::vector<double> >& points ) {
     793             : // Set contour location for function
     794           0 :   contour_location=target;
     795             : // Resize points to maximum possible value
     796           0 :   points.resize( dimension_*maxsize_ );
     797             : 
     798             : // Two points for search
     799           0 :   std::vector<unsigned> ind(dimension_);
     800           0 :   std::vector<double> direction( dimension_, 0 );
     801             : 
     802             : // Run over whole grid
     803           0 :   npoints=0;
     804             :   RootFindingBase<Grid> mymin( this );
     805           0 :   for(unsigned i=0; i<maxsize_; ++i) {
     806           0 :     for(unsigned j=0; j<dimension_; ++j) {
     807           0 :       ind[j]=getIndices(i)[j];
     808             :     }
     809             : 
     810             :     // Get the value of a point on the grid
     811           0 :     double val1=getValue(i) - target;
     812             : 
     813             :     // Now search for contour in each direction
     814             :     bool edge=false;
     815           0 :     for(unsigned j=0; j<dimension_; ++j) {
     816           0 :       if( nosearch[j] ) {
     817           0 :         continue ;
     818             :       }
     819             :       // Make sure we don't search at the edge of the grid
     820           0 :       if( !pbc_[j] && (ind[j]+1)==nbin_[j] ) {
     821           0 :         continue;
     822           0 :       } else if( (ind[j]+1)==nbin_[j] ) {
     823             :         edge=true;
     824           0 :         ind[j]=0;
     825             :       } else {
     826           0 :         ind[j]+=1;
     827             :       }
     828           0 :       double val2=getValue(ind) - target;
     829           0 :       if( val1*val2<0 ) {
     830             :         // Use initial point location as first guess for search
     831           0 :         points[npoints].resize(dimension_);
     832           0 :         for(unsigned k=0; k<dimension_; ++k) {
     833           0 :           points[npoints][k]=getPoint(i)[k];
     834             :         }
     835             :         // Setup direction vector
     836           0 :         direction[j]=0.999999999*dx_[j];
     837             :         // And do proper search for contour point
     838           0 :         mymin.linesearch( direction, points[npoints], &Grid::getDifferenceFromContour );
     839           0 :         direction[j]=0.0;
     840           0 :         npoints++;
     841             :       }
     842           0 :       if( pbc_[j] && edge ) {
     843             :         edge=false;
     844           0 :         ind[j]=nbin_[j]-1;
     845             :       } else {
     846           0 :         ind[j]-=1;
     847             :       }
     848             :     }
     849             :   }
     850           0 : }
     851             : 
     852             : /// OVERRIDES ARE BELOW
     853             : 
     854    28865222 : Grid::index_t Grid::getSize() const {
     855    28865222 :   return maxsize_;
     856             : }
     857             : 
     858    27284983 : double Grid::getValue(index_t index) const {
     859             :   plumed_dbg_assert(index<maxsize_);
     860    27284983 :   return grid_[index];
     861             : }
     862             : 
     863     3079830 : double Grid::getValueAndDerivatives(index_t index, std::vector<double>& der) const {
     864             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     865     3079830 :   der.resize(dimension_);
     866     6679639 :   for(unsigned i=0; i<dimension_; i++) {
     867     3599809 :     der[i]=der_[dimension_*index+i];
     868             :   }
     869     3079830 :   return grid_[index];
     870             : }
     871             : 
     872     6444104 : void Grid::setValue(index_t index, double value) {
     873             :   plumed_dbg_assert(index<maxsize_ && !usederiv_);
     874     6444104 :   grid_[index]=value;
     875     6444104 : }
     876             : 
     877     2552369 : void Grid::setValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
     878             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     879     2552369 :   grid_[index]=value;
     880     7609163 :   for(unsigned i=0; i<dimension_; i++) {
     881     5056794 :     der_[dimension_*index+i]=der[i];
     882             :   }
     883     2552369 : }
     884             : 
     885           1 : void Grid::addValue(index_t index, double value) {
     886             :   plumed_dbg_assert(index<maxsize_ && !usederiv_);
     887           1 :   grid_[index]+=value;
     888           1 : }
     889             : 
     890     1172186 : void Grid::addValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
     891             :   plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     892     1172186 :   grid_[index]+=value;
     893     3501367 :   for(unsigned int i=0; i<dimension_; ++i) {
     894     2329181 :     der_[index*dimension_+i]+=der[i];
     895             :   }
     896     1172186 : }
     897             : 
     898           0 : Grid::index_t SparseGrid::getSize() const {
     899           0 :   return map_.size();
     900             : }
     901             : 
     902           0 : Grid::index_t SparseGrid::getMaxSize() const {
     903           0 :   return maxsize_;
     904             : }
     905             : 
     906           0 : double SparseGrid::getValue(index_t index)const {
     907           0 :   plumed_assert(index<maxsize_);
     908             :   double value=0.0;
     909             :   const auto it=map_.find(index);
     910           0 :   if(it!=map_.end()) {
     911           0 :     value=it->second;
     912             :   }
     913           0 :   return value;
     914             : }
     915             : 
     916         200 : double SparseGrid::getValueAndDerivatives(index_t index, std::vector<double>& der)const {
     917         200 :   plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     918             :   double value=0.0;
     919         580 :   for(unsigned int i=0; i<dimension_; ++i) {
     920         380 :     der[i]=0.0;
     921             :   }
     922             :   const auto it=map_.find(index);
     923         200 :   if(it!=map_.end()) {
     924         132 :     value=it->second;
     925             :   }
     926             :   const auto itder=der_.find(index);
     927         200 :   if(itder!=der_.end()) {
     928         132 :     der=itder->second;
     929             :   }
     930         200 :   return value;
     931             : }
     932             : 
     933           0 : void SparseGrid::setValue(index_t index, double value) {
     934           0 :   plumed_assert(index<maxsize_ && !usederiv_);
     935           0 :   map_[index]=value;
     936           0 : }
     937             : 
     938           0 : void SparseGrid::setValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
     939           0 :   plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     940           0 :   map_[index]=value;
     941           0 :   der_[index]=der;
     942           0 : }
     943             : 
     944           0 : void SparseGrid::addValue(index_t index, double value) {
     945           0 :   plumed_assert(index<maxsize_ && !usederiv_);
     946           0 :   map_[index]+=value;
     947           0 : }
     948             : 
     949       19999 : void SparseGrid::addValueAndDerivatives(index_t index, double value, std::vector<double>& der) {
     950       19999 :   plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_);
     951       19999 :   map_[index]+=value;
     952       19999 :   der_[index].resize(dimension_);
     953       59682 :   for(unsigned int i=0; i<dimension_; ++i) {
     954       39683 :     der_[index][i]+=der[i];
     955             :   }
     956       19999 : }
     957             : 
     958           0 : void SparseGrid::writeToFile(OFile& ofile) {
     959           0 :   std::vector<double> xx(dimension_);
     960           0 :   std::vector<double> der(dimension_);
     961             :   double f;
     962           0 :   writeHeader(ofile);
     963           0 :   ofile.fmtField(" "+fmt_);
     964           0 :   for(const auto & it : map_) {
     965           0 :     index_t i=it.first;
     966           0 :     xx=getPoint(i);
     967           0 :     if(usederiv_) {
     968           0 :       f=getValueAndDerivatives(i,der);
     969             :     } else {
     970           0 :       f=getValue(i);
     971             :     }
     972           0 :     if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) {
     973           0 :       ofile.printf("\n");
     974             :     }
     975           0 :     for(unsigned j=0; j<dimension_; ++j) {
     976           0 :       ofile.printField("min_" + argnames[j], str_min_[j] );
     977           0 :       ofile.printField("max_" + argnames[j], str_max_[j] );
     978           0 :       ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) );
     979           0 :       if( pbc_[j] ) {
     980           0 :         ofile.printField("periodic_" + argnames[j], "true" );
     981             :       } else {
     982           0 :         ofile.printField("periodic_" + argnames[j], "false" );
     983             :       }
     984             :     }
     985           0 :     for(unsigned j=0; j<dimension_; ++j) {
     986           0 :       ofile.printField(argnames[j],xx[j]);
     987             :     }
     988           0 :     ofile.printField(funcname, f);
     989           0 :     if(usederiv_) {
     990           0 :       for(unsigned j=0; j<dimension_; ++j) {
     991           0 :         ofile.printField("der_" + argnames[j],der[j]);
     992             :       }
     993             :     }
     994           0 :     ofile.printField();
     995             :   }
     996           0 : }
     997             : 
     998           0 : double SparseGrid::getMinValue() const {
     999             :   double minval;
    1000             :   minval=0.0;
    1001           0 :   for(auto const & i : map_) {
    1002           0 :     if(i.second<minval) {
    1003             :       minval=i.second;
    1004             :     }
    1005             :   }
    1006           0 :   return minval;
    1007             : }
    1008             : 
    1009           9 : double SparseGrid::getMaxValue() const {
    1010             :   double maxval;
    1011             :   maxval=0.0;
    1012         590 :   for(auto const & i : map_) {
    1013         581 :     if(i.second>maxval) {
    1014             :       maxval=i.second;
    1015             :     }
    1016             :   }
    1017           9 :   return maxval;
    1018             : }
    1019             : 
    1020     1010062 : void Grid::projectOnLowDimension(double &val, std::vector<int> &vHigh, WeightBase * ptr2obj ) {
    1021             :   unsigned i=0;
    1022     3016945 :   for(i=0; i<vHigh.size(); i++) {
    1023     2015726 :     if(vHigh[i]<0) { // this bin needs to be integrated out
    1024             :       // parallelize here???
    1025     1010062 :       for(unsigned j=0; j<(getNbin())[i]; j++) {
    1026     1001219 :         vHigh[i]=int(j);
    1027     1001219 :         projectOnLowDimension(val,vHigh,ptr2obj); // recursive function: this is the core of the mechanism
    1028     1001219 :         vHigh[i]=-1;
    1029             :       }
    1030             :       return; //
    1031             :     }
    1032             :   }
    1033             :   // when there are no more bin to dig in then retrieve the value
    1034     1001219 :   if(i==vHigh.size()) {
    1035             :     //std::cerr<<"POINT: ";
    1036             :     //for(unsigned j=0;j<vHigh.size();j++){
    1037             :     //   std::cerr<<vHigh[j]<<" ";
    1038             :     //}
    1039     1001219 :     std::vector<unsigned> vv(vHigh.size());
    1040     3003657 :     for(unsigned j=0; j<vHigh.size(); j++) {
    1041     2002438 :       vv[j]=unsigned(vHigh[j]);
    1042             :     }
    1043             :     //
    1044             :     // this is the real assignment !!!!! (hack this to have bias or other stuff)
    1045             :     //
    1046             : 
    1047             :     // this case: produce fes
    1048             :     //val+=exp(beta*getValue(vv)) ;
    1049     1001219 :     double myv=getValue(vv);
    1050     1001219 :     val=ptr2obj->projectInnerLoop(val,myv) ;
    1051             :     // to be added: bias (same as before without negative sign)
    1052             :     //std::cerr<<" VAL: "<<val <<endl;
    1053             :   }
    1054             : }
    1055             : 
    1056          81 : Grid Grid::project(const std::vector<std::string> & proj, WeightBase *ptr2obj ) {
    1057             :   // find extrema only for the projection
    1058             :   std::vector<std::string>   smallMin,smallMax;
    1059             :   std::vector<unsigned> smallBin;
    1060             :   std::vector<unsigned> dimMapping;
    1061             :   std::vector<bool> smallIsPeriodic;
    1062             :   std::vector<std::string> smallName;
    1063             : 
    1064             :   // check if the two key methods are there
    1065             :   WeightBase* pp = dynamic_cast<WeightBase*>(ptr2obj);
    1066          81 :   if (!pp) {
    1067           0 :     plumed_merror("This WeightBase is not complete: you need a projectInnerLoop and projectOuterLoop ");
    1068             :   }
    1069             : 
    1070         162 :   for(unsigned j=0; j<proj.size(); j++) {
    1071         120 :     for(unsigned i=0; i<getArgNames().size(); i++) {
    1072         120 :       if(proj[j]==getArgNames()[i]) {
    1073             :         unsigned offset;
    1074             :         // note that at sizetime the non periodic dimension get a bin more
    1075         162 :         if(getIsPeriodic()[i]) {
    1076             :           offset=0;
    1077             :         } else {
    1078             :           offset=1;
    1079             :         }
    1080          81 :         smallMax.push_back(getMax()[i]);
    1081          81 :         smallMin.push_back(getMin()[i]);
    1082          81 :         smallBin.push_back(getNbin()[i]-offset);
    1083         162 :         smallIsPeriodic.push_back(getIsPeriodic()[i]);
    1084          81 :         dimMapping.push_back(i);
    1085          81 :         smallName.push_back(getArgNames()[i]);
    1086          81 :         break;
    1087             :       }
    1088             :     }
    1089             :   }
    1090          81 :   Grid smallgrid("projection",smallName,smallMin,smallMax,smallBin,false,false,smallIsPeriodic,smallMin,smallMax);
    1091             :   // check that the two grids are commensurate
    1092         162 :   for(unsigned i=0; i<dimMapping.size(); i++) {
    1093          81 :     plumed_massert(  (smallgrid.getMax())[i] == (getMax())[dimMapping[i]],  "the two input grids are not compatible in max"   );
    1094          81 :     plumed_massert(  (smallgrid.getMin())[i] == (getMin())[dimMapping[i]],  "the two input grids are not compatible in min"   );
    1095          81 :     plumed_massert(  (smallgrid.getNbin())[i]== (getNbin())[dimMapping[i]], "the two input grids are not compatible in bin"   );
    1096             :   }
    1097             :   std::vector<unsigned> toBeIntegrated;
    1098         243 :   for(unsigned i=0; i<getArgNames().size(); i++) {
    1099             :     bool doappend=true;
    1100         243 :     for(unsigned j=0; j<dimMapping.size(); j++) {
    1101         162 :       if(dimMapping[j]==i) {
    1102             :         doappend=false;
    1103             :         break;
    1104             :       }
    1105             :     }
    1106         162 :     if(doappend) {
    1107          81 :       toBeIntegrated.push_back(i);
    1108             :     }
    1109             :   }
    1110             : 
    1111             :   // loop over all the points in the Grid, find the corresponding fixed index, rotate over all the other ones
    1112        8924 :   for(unsigned i=0; i<smallgrid.getSize(); i++) {
    1113             :     std::vector<unsigned> v;
    1114        8843 :     v=smallgrid.getIndices(i);
    1115        8843 :     std::vector<int> vHigh((getArgNames()).size(),-1);
    1116       17686 :     for(unsigned j=0; j<dimMapping.size(); j++) {
    1117        8843 :       vHigh[dimMapping[j]]=int(v[j]);
    1118             :     }
    1119             :     // the vector vhigh now contains at the beginning the index of the low dimension and -1 for the values that need to be integrated
    1120        8843 :     double initval=0.;
    1121        8843 :     projectOnLowDimension(initval,vHigh, ptr2obj);
    1122        8843 :     smallgrid.setValue(i,ptr2obj->projectOuterLoop(initval));
    1123             :   }
    1124             : 
    1125          81 :   return smallgrid;
    1126         162 : }
    1127             : 
    1128           0 : double Grid::integrate( std::vector<unsigned>& npoints ) {
    1129             :   plumed_dbg_assert( npoints.size()==dimension_ );
    1130           0 :   plumed_assert( dospline_ );
    1131             : 
    1132             :   unsigned ntotgrid=1;
    1133             :   double box_vol=1.0;
    1134           0 :   std::vector<double> ispacing( npoints.size() );
    1135           0 :   for(unsigned j=0; j<dimension_; ++j) {
    1136           0 :     if( !pbc_[j] ) {
    1137           0 :       ispacing[j] = ( max_[j] - dx_[j] - min_[j] ) / static_cast<double>( npoints[j] );
    1138           0 :       npoints[j]+=1;
    1139             :     } else {
    1140           0 :       ispacing[j] = ( max_[j] - min_[j] ) / static_cast<double>( npoints[j] );
    1141             :     }
    1142           0 :     ntotgrid*=npoints[j];
    1143           0 :     box_vol*=ispacing[j];
    1144             :   }
    1145             : 
    1146           0 :   std::vector<double> vals( dimension_ );
    1147           0 :   std::vector<unsigned> t_index( dimension_ );
    1148             :   double integral=0.0;
    1149           0 :   for(unsigned i=0; i<ntotgrid; ++i) {
    1150           0 :     t_index[0]=(i%npoints[0]);
    1151             :     unsigned kk=i;
    1152           0 :     for(unsigned j=1; j<dimension_-1; ++j) {
    1153           0 :       kk=(kk-t_index[j-1])/npoints[j-1];
    1154           0 :       t_index[j]=(kk%npoints[j]);
    1155             :     }
    1156           0 :     if( dimension_>=2 ) {
    1157           0 :       t_index[dimension_-1]=((kk-t_index[dimension_-2])/npoints[dimension_-2]);
    1158             :     }
    1159             : 
    1160           0 :     for(unsigned j=0; j<dimension_; ++j) {
    1161           0 :       vals[j]=min_[j] + t_index[j]*ispacing[j];
    1162             :     }
    1163             : 
    1164           0 :     integral += getValue( vals );
    1165             :   }
    1166             : 
    1167           0 :   return box_vol*integral;
    1168             : }
    1169             : 
    1170           0 : void Grid::mpiSumValuesAndDerivatives( Communicator& comm ) {
    1171           0 :   comm.Sum( grid_ );
    1172           0 :   for(unsigned i=0; i<der_.size(); ++i) {
    1173           0 :     comm.Sum( der_[i] );
    1174             :   }
    1175           0 : }
    1176             : 
    1177             : 
    1178       59573 : bool indexed_lt(std::pair<Grid::index_t, double> const &x, std::pair<Grid::index_t, double> const   &y) {
    1179       59573 :   return x.second < y.second;
    1180             : }
    1181             : 
    1182         273 : double GridBase::findMaximalPathMinimum(const std::vector<double> &source, const std::vector<double> &sink) {
    1183             :   plumed_dbg_assert(source.size() == dimension_);
    1184             :   plumed_dbg_assert(sink.size() == dimension_);
    1185             :   // Start and end indices
    1186         273 :   index_t source_idx = getIndex(source);
    1187         273 :   index_t sink_idx = getIndex(sink);
    1188             :   // Path cost
    1189             :   double maximal_minimum = 0;
    1190             :   // In one dimension, path searching is very easy--either go one way if it's not periodic,
    1191             :   // or go both ways if it is periodic. There's no reason to pay the cost of Dijkstra.
    1192         273 :   if (dimension_ == 1) {
    1193             :     // Do a search from the grid source to grid sink that does not
    1194             :     // cross the grid boundary.
    1195         147 :     double curr_min_bias = getValue(source_idx);
    1196             :     // Either search from a high source to a low sink.
    1197         147 :     if (source_idx > sink_idx) {
    1198         735 :       for (index_t i = source_idx; i >= sink_idx; i--) {
    1199         588 :         if (curr_min_bias == 0.0) {
    1200             :           break;
    1201             :         }
    1202         588 :         curr_min_bias = fmin(curr_min_bias, getValue(i));
    1203             :       }
    1204             :       // Or search from a low source to a high sink.
    1205           0 :     } else if (source_idx < sink_idx) {
    1206           0 :       for (index_t i = source_idx; i <= sink_idx; i++) {
    1207           0 :         if (curr_min_bias == 0.0) {
    1208             :           break;
    1209             :         }
    1210           0 :         curr_min_bias = fmin(curr_min_bias, getValue(i));
    1211             :       }
    1212             :     }
    1213             :     maximal_minimum = curr_min_bias;
    1214             :     // If the grid is periodic, also do the search that crosses
    1215             :     // the grid boundary.
    1216         147 :     if (pbc_[0]) {
    1217          42 :       double curr_min_bias = getValue(source_idx);
    1218             :       // Either go from a high source to the upper boundary and
    1219             :       // then from the bottom boundary to the sink
    1220          42 :       if (source_idx > sink_idx) {
    1221         210 :         for (index_t i = source_idx; i < maxsize_; i++) {
    1222         168 :           if (curr_min_bias == 0.0) {
    1223             :             break;
    1224             :           }
    1225         168 :           curr_min_bias = fmin(curr_min_bias, getValue(i));
    1226             :         }
    1227         210 :         for (index_t i = 0; i <= sink_idx; i++) {
    1228         168 :           if (curr_min_bias == 0.0) {
    1229             :             break;
    1230             :           }
    1231         168 :           curr_min_bias = fmin(curr_min_bias, getValue(i));
    1232             :         }
    1233             :         // Or go from a low source to the bottom boundary and
    1234             :         // then from the high boundary to the sink
    1235           0 :       } else if (source_idx < sink_idx) {
    1236           0 :         for (index_t i = source_idx; i > 0; i--) {
    1237           0 :           if (curr_min_bias == 0.0) {
    1238             :             break;
    1239             :           }
    1240           0 :           curr_min_bias = fmin(curr_min_bias, getValue(i));
    1241             :         }
    1242           0 :         curr_min_bias = fmin(curr_min_bias, getValue(0));
    1243           0 :         for (index_t i = maxsize_ - 1; i <= sink_idx; i--) {
    1244           0 :           if (curr_min_bias == 0.0) {
    1245             :             break;
    1246             :           }
    1247           0 :           curr_min_bias = fmin(curr_min_bias, getValue(i));
    1248             :         }
    1249             :       }
    1250             :       // If the boundary crossing paths was more biased, it's
    1251             :       // minimal bias replaces the non-boundary-crossing path's
    1252             :       // minimum.
    1253          42 :       maximal_minimum = fmax(maximal_minimum, curr_min_bias);
    1254             :     }
    1255             :     // The one dimensional path search is complete.
    1256         147 :     return maximal_minimum;
    1257             :     // In two or more dimensions, path searching isn't trivial and we really
    1258             :     // do need to use a path search algorithm. Dijkstra is the simplest decent
    1259             :     // one. Using it we've never found the path search to be performance
    1260             :     // limiting in any solvated biomolecule test system, but faster options are
    1261             :     // easy to imagine if they become necessary. NB-In this case, we're actually
    1262             :     // using a greedy variant of Dijkstra's algorithm where the first possible
    1263             :     // path to a point always controls the path cost to that point. The structure
    1264             :     // of the cost function in this case guarantees that the calculated costs will
    1265             :     // be correct using this variant even though fine details of the paths may not
    1266             :     // match a normal Dijkstra search.
    1267         126 :   } else if (dimension_ > 1) {
    1268             :     // Prepare calculation temporaries for Dijkstra's algorithm.
    1269             :     // Minimal path costs from source to a given grid point
    1270         126 :     std::vector<double> mins_from_source = std::vector<double>(maxsize_, -1.0);
    1271             :     // Heap for tracking available steps, steps are recorded as std::pairs of
    1272             :     // an index and a value.
    1273             :     std::vector< std::pair<index_t, double> > next_steps;
    1274             :     std::pair<index_t, double> curr_indexed_val;
    1275         126 :     std::make_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1276             :     // The search begins at the source index.
    1277         252 :     next_steps.push_back(std::pair<index_t, double>(source_idx, getValue(source_idx)));
    1278         126 :     std::push_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1279             :     // At first no points have been examined and the optimal path has not been found.
    1280             :     index_t n_examined = 0;
    1281             :     bool path_not_found = true;
    1282             :     // Until a path is found,
    1283             :     while (path_not_found) {
    1284             :       // Examine the grid point currently most accessible from
    1285             :       // the set of all previously explored grid points by popping
    1286             :       // it from the top of the heap.
    1287        9702 :       std::pop_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1288             :       curr_indexed_val = next_steps.back();
    1289             :       next_steps.pop_back();
    1290             :       n_examined++;
    1291             :       // Check if this point is the sink point, and if so
    1292             :       // finish the loop.
    1293        9702 :       if (curr_indexed_val.first == sink_idx) {
    1294             :         path_not_found = false;
    1295             :         maximal_minimum = curr_indexed_val.second;
    1296         126 :         break;
    1297             :         // Check if this point has reached the worst possible
    1298             :         // value, and if so stop looking for paths.
    1299        9576 :       } else if (curr_indexed_val.second == 0.0) {
    1300             :         maximal_minimum = 0.0;
    1301             :         break;
    1302             :       }
    1303             :       // If the search is not over, add this grid point's neighbors to the
    1304             :       // possible next points to search for the sink.
    1305        9576 :       std::vector<index_t> neighs = getNearestNeighbors(curr_indexed_val.first);
    1306       46246 :       for (unsigned k = 0; k < neighs.size(); k++) {
    1307       36670 :         index_t i = neighs[k];
    1308             :         // If the neighbor has not already been added to the list of possible next steps,
    1309       36670 :         if (mins_from_source[i] == -1.0) {
    1310             :           // Set the cost to reach it via a path through the current point being examined.
    1311       12284 :           mins_from_source[i] = fmin(curr_indexed_val.second, getValue(i));
    1312             :           // Add the neighboring point to the heap of potential next steps.
    1313       12284 :           next_steps.push_back(std::pair<index_t, double>(i, mins_from_source[i]));
    1314       12284 :           std::push_heap(next_steps.begin(), next_steps.end(), indexed_lt);
    1315             :         }
    1316             :       }
    1317             :       // Move on to the next best looking step along any of the paths
    1318             :       // growing from the source.
    1319             :     }
    1320             :     // The multidimensional path search is now complete.
    1321             :     return maximal_minimum;
    1322             :   }
    1323             :   return 0.0;
    1324             : }
    1325             : 
    1326             : }

Generated by: LCOV version 1.16