LCOV - code coverage report
Current view: top level - gridtools - FunctionOfGrid.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 138 147 93.9 %
Date: 2025-04-08 21:11:17 Functions: 16 20 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2020 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             : #ifndef __PLUMED_gridtools_FunctionOfGrid_h
      23             : #define __PLUMED_gridtools_FunctionOfGrid_h
      24             : 
      25             : #include "ActionWithGrid.h"
      26             : #include "function/Custom.h"
      27             : #include "tools/Matrix.h"
      28             : 
      29             : namespace PLMD {
      30             : namespace gridtools {
      31             : 
      32             : template <class T>
      33             : class FunctionOfGrid : public ActionWithGrid {
      34             : private:
      35             : /// The function that is being computed
      36             :   T myfunc;
      37             : public:
      38             :   static void registerKeywords(Keywords&);
      39             :   explicit FunctionOfGrid(const ActionOptions&);
      40             : /// This does setup required on first step
      41             :   void setupOnFirstStep( const bool incalc ) override ;
      42             : /// Get the number of derivatives for this action
      43             :   unsigned getNumberOfDerivatives() override ;
      44             : /// Get the label to write in the graph
      45           0 :   std::string writeInGraph() const override {
      46           0 :     return myfunc.getGraphInfo( getName() );
      47             :   }
      48             : /// Get the underlying names
      49             :   std::vector<std::string> getGridCoordinateNames() const override ;
      50             : /// Get the underlying grid coordinates object
      51             :   const GridCoordinatesObject& getGridCoordinatesObject() const override ;
      52             : /// Calculate the function
      53             :   void performTask( const unsigned& current, MultiValue& myvals ) const override ;
      54             : ///
      55             :   void gatherStoredValue( const unsigned& valindex, const unsigned& code, const MultiValue& myvals,
      56             :                           const unsigned& bufstart, std::vector<double>& buffer ) const override ;
      57             : /// Add the forces
      58             :   void apply() override;
      59             : };
      60             : 
      61             : template <class T>
      62        1047 : void FunctionOfGrid<T>::registerKeywords(Keywords& keys ) {
      63        1047 :   ActionWithGrid::registerKeywords(keys);
      64        1047 :   std::string name = keys.getDisplayName();
      65        1047 :   std::size_t und=name.find("_GRID");
      66        2094 :   keys.setDisplayName( name.substr(0,und) );
      67        1047 :   keys.reserve("compulsory","PERIODIC","if the output of your function is periodic then you should specify the periodicity of the function.  If the output is not periodic you must state this using PERIODIC=NO");
      68         871 :   T tfunc;
      69        1047 :   tfunc.registerKeywords( keys );
      70        1047 :   if( typeid(tfunc)==typeid(function::Custom()) ) {
      71           0 :     keys.add("hidden","NO_ACTION_LOG","suppresses printing from action on the log");
      72             :   }
      73        2094 :   if( keys.getDisplayName()=="INTEGRATE") {
      74         294 :     keys.setValueDescription("scalar","the numerical integral of the input function over its whole domain");
      75         294 :     keys.addInputKeyword("compulsory","ARG","grid","the label of the function on a grid that is being integrated");
      76        1800 :   } else if( keys.getDisplayName()=="SUM") {
      77          58 :     keys.setValueDescription("scalar","the sum of the value of the function over all the grid points where it has been evaluated");
      78          58 :     keys.addInputKeyword("compulsory","ARG","grid","the label of the function on a grid from which we are computing a sum");
      79        1742 :   } else if( keys.outputComponentExists(".#!value") ) {
      80        1742 :     keys.setValueDescription("grid","the grid obtained by doing an element-wise application of " + keys.getOutputComponentDescription(".#!value") + " to the input grid");
      81        1742 :     keys.addInputKeyword("compulsory","ARG","scalar/grid","the labels of the scalars and functions on a grid that we are using to compute the required function");
      82             :   }
      83        1918 : }
      84             : 
      85             : template <class T>
      86         523 : FunctionOfGrid<T>::FunctionOfGrid(const ActionOptions&ao):
      87             :   Action(ao),
      88         523 :   ActionWithGrid(ao) {
      89         523 :   if( getNumberOfArguments()==0 ) {
      90           0 :     error("found no arguments");
      91             :   }
      92             :   // This will require a fix
      93         523 :   if( getPntrToArgument(0)->getRank()==0 || !getPntrToArgument(0)->hasDerivatives() ) {
      94           0 :     error("first input to this action must be a grid");
      95             :   }
      96             :   // Get the shape of the input grid
      97         523 :   std::vector<unsigned> shape( getPntrToArgument(0)->getShape() );
      98         937 :   for(unsigned i=1; i<getNumberOfArguments(); ++i ) {
      99         414 :     if( getPntrToArgument(i)->getRank()==0 ) {
     100         122 :       continue;
     101             :     }
     102         292 :     std::vector<unsigned> s( getPntrToArgument(i)->getShape() );
     103         292 :     if( s.size()!=shape.size() ) {
     104           0 :       error("mismatch between dimensionalities of input grids");
     105             :     }
     106             :   }
     107             :   // Read the input and do some checks
     108         523 :   myfunc.read( this );
     109             :   // Check we are not calculating an integral
     110         523 :   if( myfunc.zeroRank() ) {
     111          90 :     shape.resize(0);
     112             :   }
     113             :   // Check that derivatives are available
     114          90 :   if( !myfunc.derivativesImplemented() ) {
     115             :     error("derivatives have not been implemended for " + getName() );
     116             :   }
     117             :   // Get the names of the components
     118         523 :   std::vector<std::string> components( keywords.getOutputComponents() );
     119             :   // Create the values to hold the output
     120        1046 :   if( components.size()!=1 || components[0]!=".#!value" ) {
     121           0 :     error("functions of grid should only output one grid");
     122             :   }
     123         523 :   addValueWithDerivatives( shape );
     124             :   // Set the periodicities of the output components
     125         523 :   myfunc.setPeriodicityForOutputs( this );
     126             :   // Check if we can turn off the derivatives when they are zero
     127         433 :   if( myfunc.getDerivativeZeroIfValueIsZero() )  {
     128         492 :     for(int i=0; i<getNumberOfComponents(); ++i) {
     129         246 :       getPntrToComponent(i)->setDerivativeIsZeroWhenValueIsZero();
     130             :     }
     131             :   }
     132         523 :   setupOnFirstStep( false );
     133        1046 : }
     134             : 
     135             : template <class T>
     136        1045 : void FunctionOfGrid<T>::setupOnFirstStep( const bool incalc ) {
     137             :   double volume = 1.0;
     138        1045 :   const GridCoordinatesObject& mygrid = getGridCoordinatesObject();
     139        1045 :   unsigned npoints = getPntrToArgument(0)->getNumberOfValues();
     140        2090 :   if( mygrid.getGridType()=="flat" ) {
     141         999 :     std::vector<unsigned> shape( getGridCoordinatesObject().getNbin(true) );
     142        1794 :     for(unsigned i=1; i<getNumberOfArguments(); ++i ) {
     143         795 :       if( getPntrToArgument(i)->getRank()==0 ) {
     144         222 :         continue;
     145             :       }
     146         573 :       std::vector<unsigned> s( getPntrToArgument(i)->getShape() );
     147        1160 :       for(unsigned j=0; j<shape.size(); ++j) {
     148         587 :         if( shape[j]!=s[j] ) {
     149           0 :           error("mismatch between sizes of input grids");
     150             :         }
     151             :       }
     152             :     }
     153        1998 :     for(int i=0; i<getNumberOfComponents(); ++i) {
     154         999 :       if( getPntrToComponent(i)->getRank()>0 ) {
     155         833 :         getPntrToComponent(i)->setShape(shape);
     156             :       }
     157             :     }
     158         999 :     std::vector<double> vv( getGridCoordinatesObject().getGridSpacing() );
     159         166 :     volume=vv[0];
     160        1081 :     for(unsigned i=1; i<vv.size(); ++i) {
     161           4 :       volume *=vv[i];
     162             :     }
     163             :   } else {
     164          14 :     volume=4*pi / static_cast<double>( npoints );
     165             :   }
     166             :   // This resizes the scalars
     167        2090 :   for(int i=0; i<getNumberOfComponents(); ++i) {
     168        1045 :     if( getPntrToComponent(i)->getRank()==0 ) {
     169         180 :       getPntrToComponent(i)->resizeDerivatives( npoints );
     170             :     }
     171             :   }
     172        1045 :   if( getName()=="SUM_GRID" ) {
     173             :     volume = 1.0;
     174             :   }
     175             :   // This sets the prefactor to the volume which converts integrals to sums
     176        1045 :   myfunc.setup( this );
     177         180 :   myfunc.setPrefactor( this, volume );
     178        1045 : }
     179             : 
     180             : template <class T>
     181       15460 : const GridCoordinatesObject& FunctionOfGrid<T>::getGridCoordinatesObject() const {
     182       15460 :   ActionWithGrid* ag=ActionWithGrid::getInputActionWithGrid( getPntrToArgument(0)->getPntrToAction() );
     183       15460 :   plumed_assert( ag );
     184       15460 :   return ag->getGridCoordinatesObject();
     185             : }
     186             : 
     187             : template <class T>
     188         198 : std::vector<std::string> FunctionOfGrid<T>::getGridCoordinateNames() const {
     189         198 :   ActionWithGrid* ag=ActionWithGrid::getInputActionWithGrid( getPntrToArgument(0)->getPntrToAction() );
     190         198 :   plumed_assert( ag );
     191         198 :   return ag->getGridCoordinateNames();
     192             : }
     193             : 
     194             : template <class T>
     195        1814 : unsigned FunctionOfGrid<T>::getNumberOfDerivatives() {
     196         514 :   if( myfunc.zeroRank() ) {
     197         514 :     return getPntrToArgument(0)->getNumberOfValues();
     198             :   }
     199        1300 :   unsigned nder = getGridCoordinatesObject().getDimension();
     200        1300 :   return getGridCoordinatesObject().getDimension() + getNumberOfArguments() - myfunc.getArgStart();
     201             : }
     202             : 
     203             : template <class T>
     204      974814 : void FunctionOfGrid<T>::performTask( const unsigned& current, MultiValue& myvals ) const {
     205             :   unsigned argstart=myfunc.getArgStart();
     206      974814 :   std::vector<double> args( getNumberOfArguments() - argstart );
     207     2629182 :   for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     208     1654368 :     if( getPntrToArgument(i)->getRank()==0 ) {
     209      544232 :       args[i-argstart]=getPntrToArgument(i)->get();
     210             :     } else {
     211     1110136 :       args[i-argstart] = getPntrToArgument(i)->get(current);
     212             :     }
     213             :   }
     214             :   // Calculate the function and its derivatives
     215      974814 :   std::vector<double> vals(1);
     216      974814 :   Matrix<double> derivatives( 1, getNumberOfArguments()-argstart );
     217      974814 :   myfunc.calc( this, args, vals, derivatives );
     218      974814 :   unsigned np = myvals.getTaskIndex();
     219             :   // And set the values and derivatives
     220      974814 :   unsigned ostrn = getConstPntrToComponent(0)->getPositionInStream();
     221      974814 :   myvals.addValue( ostrn, vals[0] );
     222       23665 :   if( !myfunc.zeroRank() ) {
     223             :     // Add the derivatives for a grid
     224     2581852 :     for(unsigned j=argstart; j<getNumberOfArguments(); ++j) {
     225             :       // We store all the derivatives of all the input values - i.e. the grid points these are used in apply
     226     1630703 :       myvals.addDerivative( ostrn, getConstPntrToComponent(0)->getRank()+j-argstart, derivatives(0,j-argstart) );
     227             :       // And now we calculate the derivatives of the value that is stored on the grid correctly so that we can interpolate functions
     228     1630703 :       if( getPntrToArgument(j)->getRank()!=0 ) {
     229     3413677 :         for(unsigned k=0; k<getPntrToArgument(j)->getRank(); ++k) {
     230     2327206 :           myvals.addDerivative( ostrn, k, derivatives(0,j-argstart)*getPntrToArgument(j)->getGridDerivative( np, k ) );
     231             :         }
     232             :       }
     233             :     }
     234      951149 :     unsigned nderivatives = getConstPntrToComponent(0)->getNumberOfGridDerivatives();
     235     4575808 :     for(unsigned j=0; j<nderivatives; ++j) {
     236     3624659 :       myvals.updateIndex( ostrn, j );
     237             :     }
     238       23665 :   } else if( !doNotCalculateDerivatives() ) {
     239             :     // These are the derivatives of the integral
     240        8161 :     myvals.addDerivative( ostrn, current, derivatives(0,0) );
     241        8161 :     myvals.updateIndex( ostrn, current );
     242             :   }
     243      974814 : }
     244             : 
     245             : template <class T>
     246      951149 : void FunctionOfGrid<T>::gatherStoredValue( const unsigned& valindex, const unsigned& code, const MultiValue& myvals,
     247             :     const unsigned& bufstart, std::vector<double>& buffer ) const {
     248      951149 :   if( getConstPntrToComponent(0)->getRank()>0 && getConstPntrToComponent(0)->hasDerivatives() ) {
     249             :     plumed_dbg_assert( getNumberOfComponents()==1 && valindex==0 );
     250      951149 :     unsigned nder = getConstPntrToComponent(0)->getNumberOfGridDerivatives();
     251      951149 :     unsigned ostr = getConstPntrToComponent(0)->getPositionInStream();
     252      951149 :     unsigned kp = bufstart + code*(1+nder);
     253      951149 :     buffer[kp] += myvals.get( ostr );
     254     4575808 :     for(unsigned i=0; i<nder; ++i) {
     255     3624659 :       buffer[kp + 1 + i] += myvals.getDerivative( ostr, i );
     256             :     }
     257             :   } else {
     258           0 :     ActionWithVector::gatherStoredValue( valindex, code, myvals, bufstart, buffer );
     259             :   }
     260      951149 : }
     261             : 
     262             : template <class T>
     263        6067 : void FunctionOfGrid<T>::apply() {
     264        6067 :   if( doNotCalculateDerivatives() || !getPntrToComponent(0)->forcesWereAdded() ) {
     265        5442 :     return;
     266             :   }
     267             : 
     268             :   // This applies forces for the integral
     269         494 :   if( myfunc.zeroRank() ) {
     270         494 :     ActionWithVector::apply();
     271         494 :     return;
     272             :   }
     273             : 
     274             :   // Work out how to deal with arguments
     275             :   unsigned nscalars=0, argstart=myfunc.getArgStart();
     276        1870 :   for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     277        1245 :     if( getPntrToArgument(i)->getRank()==0 ) {
     278          20 :       nscalars++;
     279             :     }
     280             :   }
     281             : 
     282         625 :   std::vector<double> totv(nscalars,0);
     283         625 :   Value* outval=getPntrToComponent(0);
     284        7575 :   for(unsigned i=0; i<outval->getNumberOfValues(); ++i) {
     285             :     nscalars=0;
     286       19845 :     for(unsigned j=argstart; j<getNumberOfArguments(); ++j) {
     287       12895 :       double fforce = outval->getForce(i);
     288       12895 :       if( getPntrToArgument(j)->getRank()==0 ) {
     289        3205 :         totv[nscalars] += fforce*outval->getGridDerivative( i, outval->getRank()+j );
     290        3205 :         nscalars++;
     291             :       } else {
     292        9690 :         double vval = outval->getGridDerivative( i, outval->getRank()+j  );
     293        9690 :         getPntrToArgument(j)->addForce( i, fforce*vval );
     294             :       }
     295             :     }
     296             :   }
     297             :   nscalars=0;
     298        1870 :   for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     299        1245 :     if( getPntrToArgument(i)->getRank()==0 ) {
     300          20 :       getPntrToArgument(i)->addForce( 0, totv[nscalars] );
     301          20 :       nscalars++;
     302             :     }
     303             :   }
     304             : 
     305             : }
     306             : 
     307             : }
     308             : }
     309             : #endif

Generated by: LCOV version 1.16