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

Generated by: LCOV version 1.16