LCOV - code coverage report
Current view: top level - function - FunctionSetup.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 60 67 89.6 %
Date: 2026-11-05 10:19:04 Functions: 25 27 92.6 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-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             : #ifndef __PLUMED_function_FunctionSetup_h
      23             : #define __PLUMED_function_FunctionSetup_h
      24             : 
      25             : #include "core/ActionWithValue.h"
      26             : #include "core/ActionWithArguments.h"
      27             : #include "core/ActionWithVector.h"
      28             : 
      29             : #include <cmath>
      30             : 
      31             : namespace PLMD {
      32             : namespace function {
      33             : 
      34        4527 : struct FunctionOptions {
      35             :   /// Is the derivative zero if the value is zero
      36             :   bool derivativeZeroIfValueIsZero = false;
      37             : /// Are multiple components registered with a single name as in SphericalHarmonic and Moments
      38             :   std::vector<std::string> multipleValuesForEachRegisteredComponent;
      39             : };
      40             : 
      41             : template <class T>
      42        2232 : struct FunctionData {
      43             :   /// Set equal to one if we are doing EvaluateGridFunction
      44             :   unsigned argstart = 0;
      45             :   // Number of scalars that appear in input
      46             :   unsigned nscalars = 0;
      47             :   T f;
      48             :   // This is for setting up the functions
      49             :   static void setup( T& myfunc,
      50             :                      const std::vector<std::string>& components,
      51             :                      const std::vector<std::size_t>& shape,
      52             :                      bool hasderiv,
      53             :                      ActionWithValue* action );
      54             : #ifdef __PLUMED_HAS_OPENACC
      55             :   void toACCDevice() const {
      56             : #pragma acc enter data copyin(this[0:1], argstart, nscalars)
      57             :     f.toACCDevice();
      58             :   }
      59             :   void removeFromACCDevice() const {
      60             :     f.removeFromACCDevice();
      61             : #pragma acc exit data delete(nscalars, argstart, this[0:1])
      62             :   }
      63             : #endif //__PLUMED_HAS_OPENACC
      64             : };
      65             : 
      66             : template <class T>
      67        4395 : void FunctionData<T>::setup( T& myfunc,
      68             :                              const std::vector<std::string>& components,
      69             :                              const std::vector<std::size_t>& shape,
      70             :                              bool hasderiv,
      71             :                              ActionWithValue* action ) {
      72        4395 :   ActionWithArguments* aarg = action->castToActionWithArguments();
      73        4395 :   plumed_assert( aarg );
      74        4395 :   FunctionOptions options;
      75        4395 :   T::read( myfunc, aarg, options );
      76             : 
      77        4388 :   if( action->keywords.getDisplayName()=="SORT" ) {
      78          41 :     for(unsigned j=0; j<aarg->getNumberOfArguments(); ++j) {
      79             :       std::string num;
      80          28 :       Tools::convert( j+1, num );
      81          28 :       if( hasderiv ) {
      82          26 :         action->addComponentWithDerivatives( num, shape );
      83             :       } else {
      84           2 :         action->addComponent( num, shape );
      85             :       }
      86             :     }
      87             :   } else {
      88        8796 :     for(unsigned i=0; i<components.size(); ++i) {
      89        4421 :       if( options.multipleValuesForEachRegisteredComponent.size()>0 ) {
      90         840 :         for(unsigned j=0; j<options.multipleValuesForEachRegisteredComponent.size(); ++j) {
      91         743 :           if( hasderiv ) {
      92          30 :             action->addComponentWithDerivatives( components[i] + options.multipleValuesForEachRegisteredComponent[j], shape );
      93             :           } else {
      94        1456 :             action->addComponent( components[i] + options.multipleValuesForEachRegisteredComponent[j], shape );
      95             :           }
      96             :         }
      97        4324 :       } else if( components[i]==".#!value" ) {
      98        4318 :         if( hasderiv ) {
      99        2300 :           action->addValueWithDerivatives( shape );
     100             :         } else {
     101        2018 :           action->addValue( shape );
     102             :         }
     103           6 :       } else if( components[i].find_first_of("_")!=std::string::npos ) {
     104           2 :         if( aarg->getNumberOfArguments()==1 && hasderiv ) {
     105           1 :           action->addValueWithDerivatives( shape );
     106           1 :         } else if( aarg->getNumberOfArguments()==1 ) {
     107           0 :           action->addValue( shape );
     108             :         } else {
     109           3 :           for(unsigned j=0; j<aarg->getNumberOfArguments(); ++j) {
     110           2 :             if( hasderiv ) {
     111           4 :               action->addComponentWithDerivatives( (aarg->getPntrToArgument(j))->getName() + components[i], shape );
     112             :             } else {
     113           0 :               action->addComponent( (aarg->getPntrToArgument(j))->getName() + components[i], shape );
     114             :             }
     115             :           }
     116             :         }
     117             :       } else {
     118           4 :         if( hasderiv ) {
     119           0 :           action->addComponentWithDerivatives( components[i], shape );
     120             :         } else {
     121           4 :           action->addComponent( components[i], shape );
     122             :         }
     123             :       }
     124             :     }
     125             :   }
     126        4388 :   if( options.derivativeZeroIfValueIsZero ) {
     127        3143 :     for(unsigned i=0; i<action->getNumberOfComponents(); ++i) {
     128        1914 :       (action->copyOutput(i))->setDerivativeIsZeroWhenValueIsZero();
     129             :     }
     130             :   }
     131        4388 :   if( action->keywords.exists("PERIODIC") ) {
     132        3766 :     plumed_assert( action->keywords.getDisplayName()!="DIFFERENCE" );
     133        3766 :     std::vector<std::string> period;
     134        7532 :     action->parseVector("PERIODIC",period);
     135        3766 :     if( period.size()==1 ) {
     136        3758 :       if( period[0]!="NO") {
     137           0 :         action->error("input to PERIODIC keyword does not make sense");
     138             :       }
     139        7516 :       for(unsigned i=0; i<action->getNumberOfComponents(); ++i) {
     140        3758 :         (action->copyOutput(i))->setNotPeriodic();
     141             :       }
     142             :       return;
     143           8 :     } else if( period.size()!=2 ) {
     144           0 :       action->error("input to PERIODIC keyword does not make sense");
     145             :     }
     146          16 :     for(unsigned i=0; i<action->getNumberOfComponents(); ++i) {
     147           8 :       (action->copyOutput(i))->setDomain( period[0], period[1] );
     148             :     }
     149        4395 :   } else if( action->keywords.getDisplayName()=="DIFFERENCE" ) {
     150         184 :     if( aarg->getPntrToArgument(0)->isPeriodic() ) {
     151             :       std::string min, max;
     152          42 :       aarg->getPntrToArgument(0)->getDomain( min, max );
     153          42 :       action->setPeriodic(min,max);
     154         142 :     } else if( aarg->getPntrToArgument(1)->isPeriodic() ) {
     155             :       std::string min, max;
     156           0 :       aarg->getPntrToArgument(1)->getDomain( min, max );
     157           0 :       action->setPeriodic( min, max );
     158             :     } else {
     159         142 :       action->setNotPeriodic();
     160             :     }
     161             :   } else {
     162        1584 :     for(unsigned i=0; i<action->getNumberOfComponents(); ++i) {
     163        1146 :       (action->copyOutput(i))->setNotPeriodic();
     164             :     }
     165             :   }
     166             : }
     167             : 
     168             : struct FunctionOutput {
     169             :   View<double> values;
     170             :   View2D<double> derivs;
     171             :   static FunctionOutput create( unsigned nvals,
     172             :                                 double* vals,
     173             :                                 unsigned ndev,
     174             :                                 double* devs ) {
     175             :     return FunctionOutput{
     176             :       View<double>(vals,nvals),
     177             :       View2D<double>(devs,nvals,ndev)
     178      124668 :     };
     179             :   }
     180             : };
     181             : 
     182             : /// Check if all the values returned by the function are zero when all the arguments are zero.
     183             : /// When this is not the case an element of a vector cannot be skipped because its arguments are zero.
     184             : /// A value that is not finite (e.g. 0/0) is treated as zero, as that element is not meaningful.
     185             : template <class T>
     186        1290 : bool functionIsZeroWhenArgumentsAreZero( const T& f, std::size_t nargs, std::size_t ncomponents ) {
     187        1290 :   std::vector<double> zeros( nargs, 0.0 ), vals( ncomponents, 0.0 ), derivs( ncomponents*nargs, 0.0 );
     188             :   auto funcout = FunctionOutput::create( ncomponents, vals.data(), nargs, derivs.data() );
     189        1290 :   T::calc( f, true, View<const double>( zeros.data(), nargs ), funcout );
     190        2369 :   for(const auto & v : vals) {
     191        1291 :     if( std::isfinite(v) && std::fabs(v)>epsilon ) {
     192             :       return false;
     193             :     }
     194             :   }
     195             :   return true;
     196             : }
     197             : 
     198             : } // namespace function
     199             : } // namespace PLMD
     200             : #endif

Generated by: LCOV version 1.16