LCOV - code coverage report
Current view: top level - tools - Grid.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 439 624 70.4 %
Date: 2019-08-13 10:15:31 Functions: 55 79 69.6 %

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

Generated by: LCOV version 1.14