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

Generated by: LCOV version 1.15