LCOV - code coverage report
Current view: top level - gridtools - EvaluateGridFunction.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 105 127 82.7 %
Date: 2025-04-08 21:11:17 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-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             : #include "EvaluateGridFunction.h"
      23             : #include "ActionWithGrid.h"
      24             : #include "core/PlumedMain.h"
      25             : #include "core/ActionSet.h"
      26             : 
      27             : namespace PLMD {
      28             : namespace gridtools {
      29             : 
      30         184 : void EvaluateGridFunction::registerKeywords( Keywords& keys ) {
      31         184 :   keys.add("compulsory","INTERPOLATION_TYPE","spline","the method to use for interpolation.  Can be spline, linear, ceiling or floor.");
      32         184 :   keys.addFlag("ZERO_OUTSIDE_GRID_RANGE",false,"if we are asked to evaluate the function for a number that is outside the range of the grid set it to zero");
      33         368 :   keys.setValueDescription("scalar","interpolation of the input grid to get the value of the function at the input arguments");
      34         184 : }
      35             : 
      36         242 : std::vector<bool> EvaluateGridFunction::getPbc() const {
      37         242 :   std::vector<bool> ipbc( gridobject.getDimension() );
      38         484 :   for(unsigned i=0; i<ipbc.size(); ++i) {
      39         242 :     ipbc[i] = gridobject.isPeriodic(i);
      40             :   }
      41         242 :   return ipbc;
      42             : }
      43             : 
      44          88 : void EvaluateGridFunction::read( ActionWithArguments* action ) {
      45          88 :   if( action->getPntrToArgument(0)->getRank()==0 || !action->getPntrToArgument(0)->hasDerivatives() ) {
      46           0 :     action->error("should have one grid as input to this action");
      47             :   }
      48             :   // Get the input grid
      49          88 :   ActionWithGrid* ag = ActionWithGrid::getInputActionWithGrid( (action->getPntrToArgument(0))->getPntrToAction() );
      50         176 :   if( ag->getGridCoordinatesObject().getGridType()!="flat" ) {
      51           0 :     action->error("cannot interpolate on fibonacci sphere");
      52             :   }
      53          88 :   std::vector<bool> ipbc( ag->getGridCoordinatesObject().getDimension() );
      54         184 :   for(unsigned i=0; i<ipbc.size(); ++i) {
      55         192 :     ipbc[i] = ag->getGridCoordinatesObject().isPeriodic(i);
      56             :   }
      57         176 :   gridobject.setup( "flat", ipbc, 0, 0.0 );
      58             :   // Now use this information to create a gridobject
      59             :   std::vector<std::string> argn;
      60          88 :   parseFlag(action,"ZERO_OUTSIDE_GRID_RANGE",set_zero_outside_range);
      61          88 :   if( set_zero_outside_range ) {
      62           0 :     action->log.printf("  function is zero outside grid range \n");
      63             :   }
      64             :   // Get the type of interpolation that we are doing
      65             :   std::string itype;
      66         176 :   parse(action,"INTERPOLATION_TYPE",itype);
      67          88 :   if( itype=="spline" ) {
      68           8 :     interpolation_type=spline;
      69           8 :     spline_interpolator=Tools::make_unique<Interpolator>( action->getPntrToArgument(0), gridobject );
      70          80 :   } else if( itype=="linear" ) {
      71          65 :     interpolation_type=linear;
      72          15 :   } else if( itype=="floor" ) {
      73           0 :     interpolation_type=floor;
      74          15 :   } else if( itype=="ceiling" ) {
      75          15 :     interpolation_type=ceiling;
      76             :   } else {
      77           0 :     action->error("type " + itype + " of interpolation is not defined");
      78             :   }
      79          88 :   action->log.printf("  generating off grid points using %s interpolation \n", itype.c_str() );
      80         176 : }
      81             : 
      82         170 : void EvaluateGridFunction::setup( ActionWithValue* action ) {
      83         170 :   FunctionTemplateBase::setup( action );
      84         170 :   ActionWithArguments* aarg = dynamic_cast<ActionWithArguments*>( action );
      85         170 :   ActionWithGrid* ag = ActionWithGrid::getInputActionWithGrid( (aarg->getPntrToArgument(0))->getPntrToAction() );
      86         170 :   const GridCoordinatesObject & ingrid = ag->getGridCoordinatesObject();
      87         170 :   std::vector<double> sp( ingrid.getGridSpacing() );
      88         170 :   gridobject.setBounds( ingrid.getMin(), ingrid.getMax(), ingrid.getNbin(false), sp );
      89         170 : }
      90             : 
      91       39145 : void EvaluateGridFunction::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const {
      92       39145 :   if( set_zero_outside_range && !gridobject.inbounds( args ) ) {
      93           0 :     vals[0]=0.0;
      94           0 :     return;
      95             :   }
      96             :   unsigned dimension = gridobject.getDimension();
      97             :   plumed_dbg_assert( args.size()==dimension && vals.size()==1 );
      98       39145 :   if( interpolation_type==spline ) {
      99       23729 :     std::vector<double> der( dimension );
     100       23729 :     vals[0] =  spline_interpolator->splineInterpolation( args, der );
     101       74416 :     for(unsigned j=0; j<dimension; ++j) {
     102       50687 :       derivatives(0,j) = der[j];
     103             :     }
     104       15416 :   } else if( interpolation_type==linear ) {
     105             :     Value* values=action->getPntrToArgument(0);
     106        6600 :     std::vector<double> xfloor(dimension);
     107        6600 :     std::vector<unsigned> indices(dimension), nindices(dimension), ind(dimension);
     108        6600 :     gridobject.getIndices( args, indices );
     109        6600 :     unsigned nn=gridobject.getIndex(args);
     110        6600 :     gridobject.getGridPointCoordinates( nn, nindices, xfloor );
     111        6600 :     double y1 = values->get(nn);
     112        6600 :     vals[0] = y1;
     113       13200 :     for(unsigned i=0; i<args.size(); ++i) {
     114             :       int x0=1;
     115        6600 :       if(nindices[i]==indices[i]) {
     116             :         x0=0;
     117             :       }
     118        6600 :       double ddx=gridobject.getGridSpacing()[i];
     119        6600 :       double X = fabs((args[i]-xfloor[i])/ddx-(double)x0);
     120       13200 :       for(unsigned j=0; j<args.size(); ++j) {
     121        6600 :         ind[j] = indices[j];
     122             :       }
     123        6600 :       if( gridobject.isPeriodic(i) && (ind[i]+1)==gridobject.getNbin(false)[i] ) {
     124           0 :         ind[i]=0;
     125             :       } else {
     126        6600 :         ind[i] = ind[i] + 1;
     127             :       }
     128        6600 :       vals[0] += ( values->get( gridobject.getIndex(ind) ) - y1 )*X;
     129        6600 :       derivatives(0,i) = ( values->get( gridobject.getIndex(ind) ) - y1 ) / ddx;
     130             :     }
     131        8816 :   } else if( interpolation_type==floor ) {
     132             :     Value* values=action->getPntrToArgument(0);
     133           0 :     std::vector<unsigned> indices(dimension);
     134           0 :     gridobject.getIndices( args, indices );
     135           0 :     unsigned nn = gridobject.getIndex(indices);
     136             :     plumed_dbg_assert( nn<values->getNumberOfValues() );
     137           0 :     vals[0] = values->get( nn );
     138           0 :     for(unsigned j=0; j<dimension; ++j) {
     139           0 :       derivatives(0,j) = values->getGridDerivative( nn, j );
     140             :     }
     141        8816 :   } else if( interpolation_type==ceiling ) {
     142             :     Value* values=action->getPntrToArgument(0);
     143        8816 :     std::vector<unsigned> indices(dimension);
     144        8816 :     gridobject.getIndices( args, indices );
     145       17632 :     for(unsigned i=0; i<indices.size(); ++i) {
     146       17632 :       if( gridobject.isPeriodic(i) && (indices[i]+1)==gridobject.getNbin(false)[i] ) {
     147        2204 :         indices[i]=0;
     148             :       } else {
     149        6612 :         indices[i] = indices[i] + 1;
     150             :       }
     151             :     }
     152        8816 :     unsigned nn = gridobject.getIndex(indices);
     153        8816 :     vals[0] = values->get( nn );
     154       17632 :     for(unsigned j=0; j<dimension; ++j) {
     155        8816 :       derivatives(0,j) = values->getGridDerivative( nn, j );
     156             :     }
     157             :   } else {
     158           0 :     plumed_error();
     159             :   }
     160             : }
     161             : 
     162        1956 : void EvaluateGridFunction::applyForce( const ActionWithArguments* action, const std::vector<double>& args, const double& force, std::vector<double>& forcesToApply ) const {
     163             :   unsigned dimension = gridobject.getDimension();
     164        1956 :   if( interpolation_type==spline ) {
     165           0 :     action->error("can't apply forces on values interpolated using splines");
     166        1956 :   } else if( interpolation_type==linear ) {
     167             :     Value* values=action->getPntrToArgument(0);
     168         100 :     std::vector<double> xfloor(dimension);
     169         100 :     std::vector<unsigned> indices(dimension), nindices(dimension), ind(dimension);
     170         100 :     gridobject.getIndices( args, indices );
     171         100 :     unsigned nn=gridobject.getIndex(args);
     172         100 :     gridobject.getGridPointCoordinates( nn, nindices, xfloor );
     173         200 :     for(unsigned i=0; i<args.size(); ++i) {
     174             :       int x0=1;
     175         100 :       if(nindices[i]==indices[i]) {
     176             :         x0=0;
     177             :       }
     178         100 :       double ddx=gridobject.getGridSpacing()[i];
     179         100 :       double X = fabs((args[i]-xfloor[i])/ddx-(double)x0);
     180         200 :       for(unsigned j=0; j<args.size(); ++j) {
     181         100 :         ind[j] = indices[j];
     182             :       }
     183         100 :       if( gridobject.isPeriodic(i) && (ind[i]+1)==gridobject.getNbin(false)[i] ) {
     184           0 :         ind[i]=0;
     185             :       } else {
     186         100 :         ind[i] = ind[i] + 1;
     187             :       }
     188         100 :       forcesToApply[nn] += force*(1-X);
     189         100 :       forcesToApply[gridobject.getIndex(ind)] += X*force;
     190             :     }
     191        1856 :   } else if( interpolation_type==floor ) {
     192             :     Value* values=action->getPntrToArgument(0);
     193           0 :     std::vector<unsigned> indices(dimension);
     194           0 :     gridobject.getIndices( args, indices );
     195           0 :     unsigned nn = gridobject.getIndex(indices);
     196           0 :     forcesToApply[nn] += force;
     197        1856 :   } else if( interpolation_type==ceiling ) {
     198             :     Value* values=action->getPntrToArgument(0);
     199        1856 :     std::vector<unsigned> indices(dimension);
     200        1856 :     gridobject.getIndices( args, indices );
     201        3712 :     for(unsigned i=0; i<indices.size(); ++i) {
     202        3712 :       if( gridobject.isPeriodic(i) && (indices[i]+1)==gridobject.getNbin(false)[i] ) {
     203         464 :         indices[i]=0;
     204             :       } else {
     205        1392 :         indices[i] = indices[i] + 1;
     206             :       }
     207             :     }
     208        1856 :     unsigned nn = gridobject.getIndex(indices);
     209        1856 :     forcesToApply[nn] += force;
     210             :   } else {
     211           0 :     plumed_error();
     212             :   }
     213        1956 : }
     214             : 
     215             : }
     216             : }

Generated by: LCOV version 1.16