LCOV - code coverage report
Current view: top level - gridtools - GridVessel.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 218 229 95.2 %
Date: 2018-12-19 07:49:13 Functions: 28 31 90.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-2018 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             : #include "GridVessel.h"
      23             : #include "vesselbase/ActionWithVessel.h"
      24             : #include "tools/Tools.h"
      25             : 
      26             : namespace PLMD {
      27             : namespace gridtools {
      28             : 
      29          36 : void GridVessel::registerKeywords( Keywords& keys ) {
      30          36 :   AveragingVessel::registerKeywords( keys );
      31          36 :   keys.add("compulsory","COMPONENTS","the names of the components in the vector");
      32          36 :   keys.add("compulsory","COORDINATES","the names of the coordinates of the grid");
      33          36 :   keys.add("compulsory","PBC","is the grid periodic in each direction or not");
      34          36 : }
      35             : 
      36          36 : GridVessel::GridVessel( const vesselbase::VesselOptions& da ):
      37             :   AveragingVessel(da),
      38             :   bounds_set(false),
      39             :   cube_units(1.0),
      40             :   noderiv(false),
      41          36 :   npoints(0)
      42             : {
      43          36 :   std::vector<std::string> compnames; parseVector("COMPONENTS",compnames);
      44          72 :   std::vector<std::string> coordnames; parseVector("COORDINATES",coordnames);
      45          36 :   dimension=coordnames.size();
      46          72 :   std::vector<std::string> spbc( dimension ); parseVector("PBC",spbc);
      47          36 :   str_min.resize( dimension);  str_max.resize( dimension ); stride.resize( dimension );
      48          36 :   max.resize( dimension ); dx.resize( dimension ); nbin.resize( dimension ); min.resize( dimension );
      49             : 
      50             : 
      51          36 :   unsigned n=0; nper=compnames.size()*( 1 + coordnames.size() );
      52          36 :   arg_names.resize( coordnames.size() + compnames.size()*( 1 + coordnames.size() ) );
      53          36 :   for(unsigned i=0; i<coordnames.size(); ++i) { arg_names[n] = coordnames[i]; n++; }
      54          72 :   for(unsigned i=0; i<compnames.size(); ++i) {
      55          36 :     arg_names[n]=compnames[i]; n++;
      56          36 :     for(unsigned j=0; j<coordnames.size(); ++j) { arg_names[n] = "d" + compnames[i] + "_" + coordnames[j]; n++; }
      57             :   }
      58             : 
      59          36 :   pbc.resize( dimension );
      60          91 :   for(unsigned i=0; i<dimension; ++i) {
      61          55 :     if( spbc[i]=="F" ) pbc[i]=false;
      62          20 :     else if( spbc[i]=="T" ) pbc[i]=true;
      63           0 :     else plumed_error();
      64          36 :   }
      65          36 : }
      66             : 
      67           6 : void GridVessel::setNoDerivatives() {
      68           6 :   nper = ( nper/(1+dimension) ); noderiv=true;
      69          12 :   std::vector<std::string> tnames( dimension ), cnames(nper);
      70           6 :   for(unsigned i=0; i<dimension; ++i) tnames[i]=arg_names[i];
      71           6 :   unsigned k=dimension; for(unsigned i=0; i<nper; ++i) { cnames[i]=arg_names[k]; k+=(1+dimension); }
      72           6 :   arg_names.resize( dimension + nper );
      73           6 :   for(unsigned i=0; i<dimension; ++i) arg_names[i]=tnames[i];
      74          12 :   for(unsigned i=0; i<nper; ++i) arg_names[dimension+i]=cnames[i];
      75           6 : }
      76             : 
      77          56 : void GridVessel::setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax,
      78             :                             const std::vector<unsigned>& binsin, const std::vector<double>& spacing ) {
      79             :   plumed_dbg_assert( smin.size()==dimension && smax.size()==dimension );
      80          56 :   plumed_assert( (spacing.size()==dimension || binsin.size()==dimension) );
      81             : 
      82          56 :   npoints=1; bounds_set=true;
      83         146 :   for(unsigned i=0; i<dimension; ++i) {
      84          90 :     str_min[i]=smin[i]; str_max[i]=smax[i];
      85          90 :     Tools::convert( str_min[i], min[i] );
      86          90 :     Tools::convert( str_max[i], max[i] );
      87          90 :     if( spacing.size()==dimension && binsin.size()==dimension ) {
      88          27 :       double range = max[i] - min[i]; unsigned spc = std::floor( range / spacing[i]);
      89             :       // This check ensures that nbins is set correctly if spacing is set the same as the number of bins
      90          27 :       if( fabs( binsin[i]*spacing[i]-range )>epsilon ) spc += 1;
      91          27 :       if( spc>binsin[i] ) nbin[i]=spc; else nbin[i]=binsin[i];
      92          63 :     } else if( binsin.size()==dimension ) nbin[i]=binsin[i];
      93           0 :     else if( spacing.size()==dimension ) nbin[i] = std::floor(( max[i] - min[i] ) / spacing[i]) + 1;
      94           0 :     else plumed_error();
      95          90 :     dx[i] = ( max[i] - min[i] ) / static_cast<double>( nbin[i] );
      96          90 :     if( !pbc[i] ) { max[i] +=dx[i]; nbin[i]+=1; }
      97          90 :     stride[i]=npoints;
      98          90 :     npoints*=nbin[i];
      99             :   }
     100          56 :   resize();  // Always resize after setting new bounds as grid size may have have changed
     101          56 : }
     102             : 
     103          36 : std::string GridVessel::description() {
     104          36 :   if( !bounds_set ) return "";
     105             : 
     106          48 :   std::string des="grid of "; std::string num;
     107          36 :   for(unsigned i=0; i<dimension-1; ++i) {
     108          12 :     Tools::convert( nbin[i], num );
     109          12 :     des += num + " X ";
     110             :   }
     111          24 :   Tools::convert( nbin[dimension-1], num );
     112          24 :   des += num + " equally spaced points between (";
     113          24 :   for(unsigned i=0; i<dimension-1; ++i) des += str_min[i] + ",";
     114          24 :   Tools::convert( nbin[dimension-1], num );
     115          24 :   des += str_min[dimension-1] + ") and (";
     116          24 :   for(unsigned i=0; i<dimension-1; ++i) des += str_max[i] + ",";
     117          24 :   des += str_max[dimension-1] + ")";
     118          48 :   return des;
     119             : }
     120             : 
     121         109 : void GridVessel::resize() {
     122         109 :   plumed_massert( nper>0, "Number of datapoints at each grid point has not been set");
     123         109 :   resizeBuffer( getNumberOfBufferPoints()*nper ); setDataSize( npoints*nper );
     124         109 :   if( active.size()!=npoints) active.resize( npoints, true );
     125         109 : }
     126             : 
     127    15637495 : unsigned GridVessel::getIndex( const std::vector<unsigned>& indices ) const {
     128             :   plumed_dbg_assert( bounds_set && indices.size()==dimension );
     129             :   // indices are flattended using a column-major order
     130    15637495 :   unsigned index=indices[dimension-1];
     131    46883540 :   for(unsigned i=dimension-1; i>0; --i) {
     132    31250000 :     index=index*nbin[i-1]+indices[i-1];
     133             :   }
     134    15633540 :   return index;
     135             : }
     136             : 
     137       15398 : void GridVessel::getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const {
     138             :   plumed_dbg_assert( bounds_set && point.size()==dimension && indices.size()==dimension );
     139       60844 :   for(unsigned i=0; i<dimension; ++i) {
     140       45425 :     indices[i]=std::floor( (point[i] - min[i])/dx[i] );
     141       45442 :     if( pbc[i] ) indices[i]=indices[i]%nbin[i];
     142        4881 :     else if( indices[i]>nbin[i] ) plumed_merror("point is outside grid range");
     143             :   }
     144       15419 : }
     145             : 
     146        7516 : unsigned GridVessel::getIndex( const std::vector<double>& point ) const {
     147             :   plumed_dbg_assert( bounds_set && point.size()==dimension );
     148        7516 :   std::vector<unsigned> indices(dimension); getIndices( point, indices );
     149        7516 :   return getIndex( indices );
     150             : }
     151             : 
     152    76468697 : void GridVessel::convertIndexToIndices( const unsigned& index, const std::vector<unsigned>& nnbin, std::vector<unsigned>& indices ) const {
     153    76468697 :   unsigned kk=index;
     154    76468697 :   indices[0]=index%nnbin[0];
     155   152648942 :   for(unsigned i=1; i<dimension-1; ++i) {
     156    76231686 :     kk=(kk-indices[i-1])/nnbin[i-1];
     157    76510743 :     indices[i]=kk%nnbin[i];
     158             :   }
     159    76417256 :   if(dimension>=2) { // I think this is wrong
     160    76436052 :     indices[dimension-1]=(kk-indices[dimension-2])/nnbin[dimension-2];
     161             :   }
     162             : 
     163    76331280 : }
     164             : 
     165    10765265 : void GridVessel::getIndices( const unsigned& index, std::vector<unsigned>& indices ) const {
     166    10765265 :   convertIndexToIndices( index, nbin, indices );
     167    10764566 : }
     168             : 
     169    10664906 : void GridVessel::getGridPointCoordinates( const unsigned& ipoint, std::vector<double>& x ) const {
     170             :   plumed_dbg_assert( x.size()==dimension && ipoint<npoints );
     171    10664906 :   std::vector<unsigned> tindices( dimension ); getIndices( ipoint, tindices );
     172    10667313 :   for(unsigned i=0; i<dimension; ++i) x[i] = min[i] + dx[i]*tindices[i];
     173    10665087 : }
     174             : 
     175        7510 : void GridVessel::getSplineNeighbors( const unsigned& mybox, std::vector<unsigned>& mysneigh ) const {
     176        7510 :   mysneigh.resize( static_cast<unsigned>(pow(2.,dimension)) );
     177             : 
     178        7511 :   std::vector<unsigned> tmp_indices( dimension );
     179       15022 :   std::vector<unsigned> my_indices( dimension );
     180        7511 :   getIndices( mybox, my_indices );
     181       66389 :   for(unsigned i=0; i<mysneigh.size(); ++i) {
     182       58868 :     unsigned tmp=i;
     183      234657 :     for(unsigned j=0; j<dimension; ++j) {
     184      175774 :       unsigned i0=tmp%2+my_indices[j]; tmp/=2;
     185      175807 :       if(!pbc[j] && i0==nbin[j]) getAction()->error("Extrapolating function on grid");
     186      175804 :       if( pbc[j] && i0==nbin[j]) i0=0;
     187      175791 :       tmp_indices[j]=i0;
     188             :     }
     189       58883 :     mysneigh[i]=getIndex( tmp_indices );
     190       58880 :     plumed_massert( active[mysneigh[i]], "inactive grid point required for splines");
     191        7511 :   }
     192        7511 : }
     193             : 
     194       46612 : double GridVessel::getGridElement( const unsigned& ipoint, const unsigned& jelement ) const {
     195       46612 :   plumed_assert( bounds_set && ipoint<npoints && jelement<nper && active[ipoint] );
     196       46583 :   return getDataElement( nper*ipoint + jelement  );
     197             : }
     198             : 
     199           0 : void GridVessel::setGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ) {
     200             :   plumed_dbg_assert( bounds_set && ipoint<npoints && jelement<nper );
     201           0 :   setDataElement( nper*ipoint + jelement, value );
     202           0 : }
     203             : 
     204           5 : void GridVessel::addToGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ) {
     205             :   plumed_dbg_assert( bounds_set && ipoint<npoints && jelement<nper );
     206           5 :   addDataElement( nper*ipoint + jelement, value );
     207           5 : }
     208             : 
     209        9204 : void GridVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const {
     210             :   plumed_dbg_assert( myvals.getNumberOfValues()==(nper+1) );
     211        9204 :   for(unsigned i=0; i<nper; ++i) buffer[bufstart + nper*current + i] += myvals.get(i+1);
     212        9279 : }
     213             : 
     214           0 : double GridVessel::getGridElement( const std::vector<unsigned>& indices, const unsigned& jelement ) const {
     215           0 :   return getGridElement( getIndex( indices ), jelement );
     216             : }
     217             : 
     218           0 : void GridVessel::setGridElement( const std::vector<unsigned>& indices, const unsigned& jelement, const double& value ) {
     219           0 :   setGridElement( getIndex( indices ), jelement, value );
     220           0 : }
     221             : 
     222        4837 : std::vector<std::string> GridVessel::getMin() const {
     223        4837 :   return str_min;
     224             : }
     225             : 
     226        4866 : std::vector<std::string> GridVessel::getMax() const {
     227        4866 :   return str_max;
     228             : }
     229             : 
     230        5259 : std::vector<unsigned> GridVessel::getNbin() const {
     231             :   plumed_dbg_assert( bounds_set );
     232        5259 :   std::vector<unsigned> ngrid( dimension );
     233       12182 :   for(unsigned i=0; i<dimension; ++i) {
     234        6921 :     if( !pbc[i] ) ngrid[i]=nbin[i] - 1;
     235        3492 :     else ngrid[i]=nbin[i];
     236             :   }
     237        5261 :   return ngrid;
     238             : }
     239             : 
     240       15996 : void GridVessel::getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh,
     241             :                                unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const {
     242             :   plumed_dbg_assert( bounds_set && nneigh.size()==dimension );
     243             : 
     244       15996 :   std::vector<unsigned> indices( dimension );
     245       16000 :   for(unsigned i=0; i<dimension; ++i) indices[i] = std::floor( (pp[i]-min[i])/dx[i] );
     246       15997 :   getNeighbors( indices, nneigh, num_neighbors, neighbors );
     247       15998 : }
     248             : 
     249       34083 : void GridVessel::getNeighbors( const std::vector<unsigned>& indices, const std::vector<unsigned>& nneigh,
     250             :                                unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const {
     251             :   plumed_dbg_assert( bounds_set && nneigh.size()==dimension );
     252             : 
     253       34083 :   unsigned num_neigh=1; std::vector<unsigned> small_bin( dimension );
     254      136256 :   for(unsigned i=0; i<dimension; ++i) {
     255      102170 :     small_bin[i]=(2*nneigh[i]+1);
     256      102170 :     num_neigh *=small_bin[i];
     257             :   }
     258       34086 :   if( neighbors.size()!=num_neigh ) neighbors.resize( num_neigh );
     259             : 
     260       34086 :   num_neighbors=0;
     261       68172 :   std::vector<unsigned> s_indices(dimension), t_indices(dimension);
     262    65813929 :   for(unsigned index=0; index<num_neigh; ++index) {
     263    65779843 :     bool found=true;
     264    65779843 :     convertIndexToIndices( index, small_bin, s_indices );
     265   262809041 :     for(unsigned i=0; i<dimension; ++i) {
     266   197053097 :       int i0=s_indices[i]-nneigh[i]+indices[i];
     267   197097486 :       if(!pbc[i] && i0<0)        found=false;
     268   197368259 :       if(!pbc[i] && i0>=nbin[i]) found=false;
     269   197149502 :       if( pbc[i] && i0<0)        i0=nbin[i]-(-i0)%nbin[i];
     270   197142968 :       if( pbc[i] && i0>=nbin[i]) i0%=nbin[i];
     271   197044415 :       t_indices[i]=static_cast<unsigned>(i0);
     272             :     }
     273    65755944 :     if( found ) {
     274    15491747 :       neighbors[num_neighbors]=getIndex( t_indices );
     275    15490356 :       num_neighbors++;
     276             :     }
     277       34086 :   }
     278       34086 : }
     279             : 
     280          11 : void GridVessel::setCubeUnits( const double& units ) {
     281          11 :   cube_units=units;
     282          11 : }
     283             : 
     284           8 : double GridVessel::getCubeUnits() const {
     285           8 :   return cube_units;
     286             : }
     287             : 
     288           7 : std::string GridVessel::getInputString() const {
     289           7 :   std::string mstring="COORDINATES="+arg_names[0];
     290           7 :   for(unsigned i=1; i<dimension; ++i) mstring+="," + arg_names[i];
     291           7 :   mstring += " PBC=";
     292           7 :   if( pbc[0] ) mstring +="T";
     293           5 :   else mstring +="F";
     294          11 :   for(unsigned i=1; i<dimension; ++i) {
     295           4 :     if( pbc[i] ) mstring +=",T";
     296           4 :     else mstring +=",F";
     297             :   }
     298           7 :   return mstring;
     299             : }
     300             : 
     301        7510 : double GridVessel::getValueAndDerivatives( const std::vector<double>& x, const unsigned& ind, std::vector<double>& der ) const {
     302             :   plumed_dbg_assert( der.size()==dimension && !noderiv && ind<getNumberOfComponents() );
     303             : 
     304        7510 :   double X,X2,X3,value=0; der.assign(der.size(),0.0);
     305        7511 :   std::vector<double> fd(dimension);
     306       15022 :   std::vector<double> C(dimension);
     307       15022 :   std::vector<double> D(dimension);
     308       15021 :   std::vector<double> dder(dimension);
     309             : 
     310       15022 :   std::vector<unsigned> nindices(dimension);
     311       15022 :   std::vector<unsigned> indices(dimension); getIndices( x, indices );
     312       15022 :   std::vector<unsigned> neigh; getSplineNeighbors( getIndex(indices), neigh );
     313       15021 :   std::vector<double> xfloor(dimension); getGridPointCoordinates( getIndex(x), xfloor );
     314             : 
     315             : // loop over neighbors
     316       66390 :   for(unsigned int ipoint=0; ipoint<neigh.size(); ++ipoint) {
     317       58871 :     double grid=getGridElement(neigh[ipoint], ind*(1+dimension) );
     318       58913 :     for(unsigned j=0; j<dimension; ++j) dder[j] = getGridElement( neigh[ipoint], ind*(1+dimension) + 1 + j );
     319             : 
     320       58879 :     getIndices( neigh[ipoint], nindices );
     321       58823 :     double ff=1.0;
     322             : 
     323      234607 :     for(unsigned j=0; j<dimension; ++j) {
     324      175742 :       int x0=1;
     325      175742 :       if(nindices[j]==indices[j]) x0=0;
     326      175801 :       double ddx=dx[j];
     327      175787 :       X=fabs((x[j]-xfloor[j])/ddx-(double)x0);
     328      175613 :       X2=X*X;
     329      175613 :       X3=X2*X;
     330             :       double yy;
     331      175613 :       if(fabs(grid)<0.0000001) yy=0.0;
     332      161521 :       else yy=-dder[j]/grid;
     333      175823 :       C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*ddx;
     334      175857 :       D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*ddx;
     335      175837 :       D[j]*=(x0?-1.0:1.0)/ddx;
     336      175849 :       ff*=C[j];
     337             :     }
     338      234650 :     for(unsigned j=0; j<dimension; ++j) {
     339      175794 :       fd[j]=D[j];
     340      175901 :       for(unsigned i=0; i<dimension; ++i) if(i!=j) fd[j]*=C[i];
     341             :     }
     342       58856 :     value+=grid*ff;
     343       58856 :     for(unsigned j=0; j<dimension; ++j) der[j]+=grid*fd[j];
     344             :   }
     345       15021 :   return value;
     346             : }
     347             : 
     348           2 : void GridVessel::activateThesePoints( const std::vector<bool>& to_activate ) {
     349             :   plumed_dbg_assert( to_activate.size()==npoints );
     350           2 :   for(unsigned i=0; i<npoints; ++i) active[i]=to_activate[i];
     351           2 : }
     352             : 
     353             : }
     354        2523 : }
     355             : 

Generated by: LCOV version 1.13