LCOV - code coverage report
Current view: top level - gridtools - SumOfKernels.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 80 81 98.8 %
Date: 2026-11-05 10:19:04 Functions: 24 24 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             : #ifndef __PLUMED_gridtools_SumOfKernels_h
      23             : #define __PLUMED_gridtools_SumOfKernels_h
      24             : 
      25             : #include "function/FunctionSetup.h"
      26             : #include "tools/SwitchingFunction.h"
      27             : #include "tools/HistogramBead.h"
      28             : #include "tools/Matrix.h"
      29             : 
      30             : namespace PLMD {
      31             : namespace gridtools {
      32             : 
      33             : template <class K>
      34             : class RegularKernel;
      35             : 
      36             : class DiagonalKernelParams {
      37             : public:
      38             :   View<const double> at;
      39             :   View<const double> sigma;
      40             :   View<const double,1> height;
      41             :   DiagonalKernelParams( const View<const double>& params, const std::size_t ndim ):
      42             :     at(params.data(),ndim),
      43    38921925 :     sigma(params.data()+ndim,ndim),
      44    38921925 :     height(params.data()+2*ndim) {
      45             :   }
      46             :   static bool bandwidthIsConstant( std::size_t ndim, const std::vector<Value*>& args );
      47             :   static bool bandwidthsAllSame( std::size_t ndim, const std::vector<Value*>& args );
      48             :   static bool setKernelAndCheckHeight( View<double>& params, std::size_t ndim, const std::vector<double>& args );
      49             :   static std::size_t getNumberOfParameters( const std::size_t& nargs );
      50             :   static std::size_t getNumberOfShapeParameters( const std::size_t& nargs );
      51             :   static void getSigmaProjections( const View<const double>& shape, std::vector<double>& support );
      52             : #pragma acc routine seq
      53             :   static double evaluateR2( const RegularKernel<DiagonalKernelParams>& p, const DiagonalKernelParams& kp, View<const double> x, View<double> paramderivs );
      54             : };
      55             : 
      56             : inline
      57             : std::size_t DiagonalKernelParams::getNumberOfParameters( const std::size_t& nargs ) {
      58        7568 :   return 2*nargs + 1;
      59             : }
      60             : 
      61             : class NonDiagonalKernelParams {
      62             : public:
      63             :   View<const double> at;
      64             :   View2D<const double> metric;
      65             :   View<const double,1> height;
      66        3762 :   NonDiagonalKernelParams( const View<const double>& params, const std::size_t ndim ):
      67             :     at(params.data(),ndim),
      68        3762 :     metric(params.data()+ndim,ndim,ndim),
      69        3762 :     height(params.data()+ndim*(1+ndim)) {
      70        3762 :   }
      71             :   static bool bandwidthIsConstant( std::size_t ndim, const std::vector<Value*>& args );
      72             :   static bool bandwidthsAllSame( std::size_t ndim, const std::vector<Value*>& args );
      73             :   static bool setKernelAndCheckHeight( View<double>& params, std::size_t ndim, const std::vector<double>& args );
      74             :   static std::size_t getNumberOfParameters( const std::size_t& nargs );
      75             :   static std::size_t getNumberOfShapeParameters( const std::size_t& nargs );
      76             :   static void getSigmaProjections( const View<const double>& shape, std::vector<double>& support );
      77             : #pragma acc routine seq
      78             :   static double evaluateR2( const RegularKernel<NonDiagonalKernelParams>& p, const NonDiagonalKernelParams& kp, View<const double> x, View<double> paramderivs );
      79             : };
      80             : 
      81             : inline
      82             : std::size_t NonDiagonalKernelParams::getNumberOfParameters( const std::size_t& nargs ) {
      83        1321 :   return nargs + nargs*nargs + 1;
      84             : }
      85             : 
      86             : class DiscreteKernel {
      87             : public:
      88             :   static void registerKeywords( Keywords& keys ) {}
      89             :   static void read( DiscreteKernel& p, ActionWithArguments* action, const std::vector<Value*>& args ) {}
      90             :   static void setArgumentDomain( const unsigned& i, DiscreteKernel& params, const double& spacing, const bool isp, const std::string& min1, const std::string& max1 ) {}
      91             :   static void getSupport( DiscreteKernel& params, const View<const double>& shape, std::vector<double>& support ) {}
      92             : #pragma acc routine seq
      93             :   static double calc( const DiscreteKernel& params, const DiagonalKernelParams& kp, View<const double> x, View<double> der, View<double> paramderivs );
      94             :   void update() {}
      95             :   void toACCDevice() const {}
      96             :   void removeFromACCDevice() const  {}
      97             : };
      98             : 
      99             : class HistogramBeadKernel {
     100             : public:
     101             :   HistogramBead::KernelType kerneltype;
     102             :   std::vector<std::size_t> periodic_v;
     103             :   std::size_t* periodic{nullptr};
     104             :   std::vector<double> domainmin_v;
     105             :   double* domainmin{nullptr};
     106             :   std::vector<double> domainmax_v;
     107             :   double* domainmax{nullptr};
     108             :   std::vector<double> gridspacing_v;
     109             :   double* gridspacing{nullptr};
     110             :   static void registerKeywords( Keywords& keys );
     111             :   static void read( HistogramBeadKernel& p, ActionWithArguments* action, const std::vector<Value*>& args );
     112             :   static void setArgumentDomain( const unsigned& i, HistogramBeadKernel& params, const double& spacing, const bool isp, const std::string& min1, const std::string& max1 );
     113             :   static void getSupport( HistogramBeadKernel& params, const View<const double>& shape, std::vector<double>& support );
     114             : #pragma acc routine seq
     115             :   static double calc( const HistogramBeadKernel& params, const DiagonalKernelParams& kp, View<const double> x, View<double> der, View<double> paramderivs );
     116             :   void update() {
     117          18 :     periodic = periodic_v.data();
     118          18 :     domainmin = domainmin_v.data();
     119          18 :     domainmax = domainmax_v.data();
     120          18 :     gridspacing = gridspacing_v.data();
     121             :   }
     122             :   void toACCDevice() const {
     123             : #pragma acc enter data copyin(this[0:1],kerneltype,periodic[0:periodic_v.size()],domainmin[0:domainmin_v.size()],domainmax[0:domainmax_v.size()],gridspacing[0:gridspacing_v.size()])
     124             :   }
     125             :   void removeFromACCDevice() const  {
     126             : #pragma acc exit data delete(gridspacing[0:gridspacing_v.size()],domainmax[0:domainmax_v.size()],domainmin[0:domainmin_v.size()],periodic[0:periodic_v.size()],kerneltype,this[0:1])
     127             :   }
     128             : };
     129             : 
     130             : template <class K>
     131             : class RegularKernel {
     132             : public:
     133             :   bool canusevol;
     134             :   double cutoff;
     135             : #ifdef __PLUMED_HAS_OPENACC
     136             :   SwitchingFunctionAccelerable switchingFunction;
     137             : #else
     138             :   SwitchingFunction switchingFunction;
     139             : #endif //__PLUMED_HAS_OPENACC
     140             :   std::vector<int> periodic_v;
     141             :   int* periodic{nullptr};
     142             :   std::vector<double> max_minus_min_v;
     143             :   double* max_minus_min{nullptr};
     144             :   std::vector<double> inv_max_minus_min_v;
     145             :   double* inv_max_minus_min{nullptr};
     146             :   static void registerKeywords( Keywords& keys );
     147             :   static void read( RegularKernel& p, ActionWithArguments* action, const std::vector<Value*>& args );
     148             :   static void setArgumentDomain( const unsigned& i, RegularKernel& params, const double& spacing, const bool isp, const std::string& min1, const std::string& max1 );
     149             :   static double difference( const RegularKernel& params, unsigned i, const double& val1, const double& val2 );
     150             :   static void getSupport( const RegularKernel& params, const View<const double>& shape, std::vector<double>& support );
     151             :   static double calc( const RegularKernel& params, const K& kp, View<const double> x, View<double> der, View<double> paramderivs );
     152             :   void update() {
     153          59 :     periodic = periodic_v.data();
     154          59 :     max_minus_min = max_minus_min_v.data();
     155          59 :     inv_max_minus_min = inv_max_minus_min_v.data();
     156             :   }
     157             : #ifdef __PLUMED_HAS_OPENACC
     158             :   void toACCDevice() const {
     159             : #pragma acc enter data copyin(this[0:1],periodic[0:periodic_v.size()],max_minus_min[0:max_minus_min_v.size()],inv_max_minus_min[0:inv_max_minus_min_v.size()])
     160             :     switchingFunction.toACCDevice();
     161             :   }
     162             :   void removeFromACCDevice() const  {
     163             :     switchingFunction.removeFromACCDevice();
     164             : #pragma acc exit data delete(inv_max_minus_min[0:inv_max_minus_min_v.size()],max_minus_min[0:max_minus_min_v.size()],periodic[0:periodic_v.size()],this[0:1])
     165             :   }
     166             : #endif //__PLUMED_HAS_OPENACC
     167             : };
     168             : 
     169             : template <class K>
     170         322 : void RegularKernel<K>::registerKeywords( Keywords& keys ) {
     171             :   std::string strcut;
     172         322 :   Tools::convert( sqrt(2*dp2cutoff), strcut );
     173         322 :   keys.add("compulsory","KERNEL","GAUSSIAN D_MAX=" + strcut,"the kernel function you are using.");
     174         322 : }
     175             : 
     176             : template <class K>
     177          66 : void RegularKernel<K>::read( RegularKernel& p, ActionWithArguments* action, const std::vector<Value*>& args ) {
     178             :   std::string kerneltype;
     179         132 :   action->parse("KERNEL",kerneltype);
     180             :   std::string errors;
     181         815 :   for(auto & c: kerneltype) {
     182         749 :     c = std::toupper(c);
     183             :   }
     184          66 :   p.canusevol = (kerneltype.find("GAUSSIAN")!=std::string::npos );
     185          66 :   p.switchingFunction.set( kerneltype + " R_0=1.0", errors );
     186          66 :   if( p.switchingFunction.get_dmax()<std::numeric_limits<double>::max() ) {
     187          15 :     p.cutoff = p.switchingFunction.get_dmax();
     188          30 :     action->log<<"  using switching function for kernel with r0="<<p.switchingFunction.description()<<" and cutoff "<<p.cutoff<<"\n";
     189             :   } else {
     190          51 :     p.cutoff = sqrt(2*dp2cutoff);
     191         102 :     action->warning("using a switching function without a D_MAX parameter for the kernel is not recommended. As discussed in the manual, "
     192             :                     "when D_MAX is unset the cutoff is set equal to sqrt(2*6.25). However, density from any given kernel "
     193             :                     "will be accumulated at points that are more than this D_MAX from the center of the kernel. The reason why "
     194             :                     "is explained on the manual pages for KDE in the section on selecting kernels.");
     195             :   }
     196          66 :   if( errors.length()!=0 ) {
     197           0 :     action->error("problem reading switching function description " + errors);
     198             :   }
     199          66 :   p.periodic_v.resize( args.size(), 0 );
     200          66 :   p.max_minus_min_v.resize( args.size() );
     201          66 :   p.inv_max_minus_min_v.resize( args.size() );
     202          66 : }
     203             : 
     204             : template <class K>
     205          88 : void RegularKernel<K>::setArgumentDomain( const unsigned& i, RegularKernel& params, const double& spacing, const bool isp, const std::string& min1, const std::string& max1 ) {
     206          88 :   if( isp ) {
     207             :     double min, max;
     208          36 :     Tools::convert( min1, min );
     209          36 :     Tools::convert( max1, max );
     210          36 :     params.periodic_v[i] = 1;
     211          36 :     params.max_minus_min_v[i]=max-min;
     212          36 :     params.inv_max_minus_min_v[i]=1.0/params.max_minus_min_v[i];
     213             :   }
     214          88 : }
     215             : 
     216             : template <class K>
     217   113638449 : double RegularKernel<K>::difference( const RegularKernel<K>& params, unsigned i, const double& val1, const double& val2 ) {
     218   113638449 :   if( params.periodic[i]==0 ) {
     219    22670935 :     return val1 - val2;
     220             :   }
     221    90967514 :   return params.max_minus_min[i]*Tools::pbc( params.inv_max_minus_min[i]*( val1 - val2 ) );
     222             : }
     223             : 
     224             : template <class K>
     225          59 : void RegularKernel<K>::getSupport( const RegularKernel<K>& params, const View<const double>& shape, std::vector<double>& support ) {
     226          59 :   K::getSigmaProjections( shape, support );
     227         147 :   for(unsigned i=0; i<support.size(); ++i) {
     228          88 :     support[i] = params.cutoff*support[i];
     229             :   }
     230          59 : }
     231             : 
     232             : template <class K>
     233    38359793 : double RegularKernel<K>::calc( const RegularKernel<K>& params, const K& kp, View<const double> x, View<double> der, View<double> paramderivs ) {
     234             :   // Not all the parameter derivatives are set below (e.g. those with respect to the bandwidths)
     235             :   // and evaluateR2 for non-diagonal kernels accumulates into them, so they must start from zero:
     236             :   // the derivative buffers of the task managers are reused between tasks (and are not initialised on the GPU)
     237   303988960 :   for(unsigned i=0; i<paramderivs.size(); ++i) {
     238   265629167 :     paramderivs[i] = 0;
     239             :   }
     240    38359793 :   double r2 = K::evaluateR2( params, kp, x, paramderivs );
     241    38359793 :   double dval, val = kp.height[0]*params.switchingFunction.calculateSqr( r2, dval );
     242    38359793 :   dval *= kp.height[0];
     243   151990718 :   for(unsigned i=0; i<der.size(); ++i) {
     244   113630925 :     der[i] += dval*paramderivs[i];
     245   113630925 :     paramderivs[i] = -dval*paramderivs[i];
     246             :   }
     247             :   // The height is always the last parameter of the kernel (DiagonalKernelParams: 2*ndim, NonDiagonalKernelParams: ndim*(1+ndim))
     248    38359793 :   paramderivs[paramderivs.size()-1] = val / kp.height[0];
     249    38359793 :   return val;
     250             : }
     251             : 
     252             : class VonMissesKernelParams {
     253             : public:
     254             :   View<const double,3> at;
     255             :   View<const double,1> concentration;
     256             :   View<const double,1> height;
     257             :   VonMissesKernelParams( const View<const double>& params, const std::size_t ndim ):
     258             :     at(params.data()),
     259    18858417 :     concentration(params.data()+3),
     260    18858417 :     height(params.data()+4) {
     261             :   }
     262             :   static bool bandwidthIsConstant( std::size_t ndim, const std::vector<Value*>& args );
     263             :   static bool bandwidthsAllSame( std::size_t ndim, const std::vector<Value*>& args );
     264             :   static bool setKernelAndCheckHeight( View<double>& params, std::size_t ndim, const std::vector<double>& argval );
     265             :   static std::size_t getNumberOfParameters( const std::size_t& nargs );
     266             :   static std::size_t getNumberOfShapeParameters( const std::size_t& nargs );
     267             : };
     268             : 
     269             : inline
     270             : std::size_t VonMissesKernelParams::getNumberOfParameters( const std::size_t& nargs ) {
     271             :   return 5;
     272             : }
     273             : 
     274             : class UniversalVonMisses {
     275             : public:
     276             :   static void registerKeywords( Keywords& keys ) {}
     277             :   static void read( UniversalVonMisses& p, ActionWithArguments* action, const std::vector<Value*>& args ) {}
     278             :   static void setArgumentDomain( const unsigned& i, UniversalVonMisses& params, const double& spacing, const bool isp, const std::string& min1, const std::string& max1 ) {}
     279             : #pragma acc routine seq
     280             :   static double calc( const UniversalVonMisses& params, const VonMissesKernelParams& kp, View<const double> x, View<double> der, View<double> paramderivs );
     281             :   void update() {}
     282             :   void toACCDevice() const {}
     283             :   void removeFromACCDevice() const  {}
     284             : };
     285             : 
     286             : template <class K, class P>
     287          13 : class SumOfKernels {
     288             : public:
     289             :   P params;
     290             :   std::vector<double> kernelParams_v;
     291             :   double* kernelParams{nullptr};
     292             : /// This is used to setup the input gridobject's bounds with the grid data from values
     293             :   static void registerKeywords( Keywords& keys );
     294             :   static void read( SumOfKernels<K,P>& func, ActionWithArguments* action, const std::vector<Value*>& args, function::FunctionOptions& options );
     295             :   static void calc( View<const std::size_t> klist, const SumOfKernels<K,P>& func, View<const double> args, View<double> values, View<double> der, View<double> paramderivs );
     296             :   void update() {
     297        2599 :     kernelParams=kernelParams_v.data();
     298             :   }
     299             :   void toACCDevice() const {
     300             : #pragma acc enter data copyin(this[0:1],kernelParams[0:kernelParams_v.size()])
     301             :     params.toACCDevice();
     302             :   }
     303             :   void removeFromACCDevice() const  {
     304             :     params.removeFromACCDevice();
     305             : #pragma acc exit data delete(kernelParams[0:kernelParams_v.size()],this[0:1])
     306             :   }
     307             : };
     308             : 
     309             : template <class K, class P>
     310         362 : void SumOfKernels<K,P>::registerKeywords( Keywords& keys ) {
     311         362 :   P::registerKeywords( keys );
     312         362 : }
     313             : 
     314             : template <class K, class P>
     315          84 : void SumOfKernels<K,P>::read( SumOfKernels<K,P>& func, ActionWithArguments* action, const std::vector<Value*>& args, function::FunctionOptions& options ) {
     316             : // Read the universal parameters for the kernel
     317          84 :   P::read( func.params, action, args );
     318          84 : }
     319             : 
     320             : template <class K, class P>
     321      190619 : void SumOfKernels<K,P>::calc( View<const std::size_t> klist, const SumOfKernels<K,P>& func, View<const double> args, View<double> values, View<double> der, View<double> paramderivs ) {
     322      190619 :   values[0] = 0;
     323      675784 :   for(unsigned i=0; i<der.size(); ++i) {
     324      485165 :     der[i] = 0;
     325             :   }
     326             :   std::size_t ndim = args.size();
     327             :   std::size_t nparams = K::getNumberOfParameters( ndim );
     328    57974723 :   for(unsigned i=0; i<klist.size(); ++i) {
     329    57784104 :     values[0] += P::calc( func.params, K(View<const double>(func.kernelParams + nparams*klist[i],nparams),ndim), args, der, View<double>( paramderivs.data() + i*nparams, nparams ) );
     330             :   }
     331      190619 : }
     332             : 
     333             : }
     334             : }
     335             : #endif

Generated by: LCOV version 1.16