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

Generated by: LCOV version 1.16