LCOV - code coverage report
Current view: top level - gridtools - KDE.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 204 233 87.6 %
Date: 2026-11-05 10:19:04 Functions: 99 112 88.4 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2017 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_KDE_h
      23             : #define __PLUMED_gridtools_KDE_h
      24             : 
      25             : #include "ActionWithGrid.h"
      26             : #include "SumOfKernels.h"
      27             : #include "core/PlumedMain.h"
      28             : #include "core/ActionSet.h"
      29             : #include "core/PbcAction.h"
      30             : #include "tools/HistogramBead.h"
      31             : #include "core/ParallelTaskManager.h"
      32             : #include "tools/SwitchingFunction.h"
      33             : #include "tools/Matrix.h"
      34             : 
      35             : namespace PLMD {
      36             : namespace gridtools {
      37             : 
      38             : template <class K, class P, class G>
      39          13 : class KDEHelper {
      40             : public:
      41             :   G g;
      42             :   bool fixed_width;
      43             :   std::size_t maxkernels;
      44             :   std::size_t ndim{0};
      45             :   SumOfKernels<K, P> kernelsum;
      46             :   std::vector<unsigned> nneigh;
      47             :   std::vector<std::size_t> nkernels_per_point_v;
      48             :   std::size_t *nkernels_per_point{nullptr};
      49             :   std::vector<std::size_t> kernels_for_gridpoint_v;
      50             :   std::size_t *kernels_for_gridpoint{nullptr};
      51             :   static void registerKeywords( Keywords& keys );
      52             :   static void read( KDEHelper<K,P,G>& func,
      53             :                     ActionWithArguments* action,
      54             :                     const std::vector<Value*>& args,
      55             :                     GridCoordinatesObject& gridobject,
      56             :                     std::vector<std::size_t>& shape,
      57             :                     function::FunctionOptions& options );
      58             :   static void readKernelParameters( std::string& value, ActionWithArguments* action, const std::string& outlab, bool rerequestargs );
      59             :   static void addArgument( const std::string& value, ActionWithArguments* action );
      60             :   static void setupGridBounds( KDEHelper<K,P,G>& func, const Tensor& box, GridCoordinatesObject& gridobject, const std::vector<Value*>& args, Value* myval );
      61             :   static void transferParamsToKernel( const std::vector<double>& argval, KDEHelper<K,P,G>& func, GridCoordinatesObject& gridobject, bool updateNeighborsOnEachKernel, std::size_t nkernels, unsigned kval, View<double>& params );
      62             :   static void transferKernels( KDEHelper<K,P,G>& func, const std::vector<Value*>& args, GridCoordinatesObject& gridobject );
      63             :   void update() {
      64        2599 :     ndim = nneigh.size();
      65        2599 :     nkernels_per_point = nkernels_per_point_v.data();
      66        2599 :     kernels_for_gridpoint = kernels_for_gridpoint_v.data();
      67             :     kernelsum.update();
      68             :   }
      69             :   void toACCDevice() const {
      70             : #pragma acc enter data copyin(this[0:1],fixed_width,maxkernels,ndim, \
      71             :                               nkernels_per_point[0:nkernels_per_point_v.size()], \
      72             :                               kernels_for_gridpoint[0:kernels_for_gridpoint_v.size()])
      73             :     kernelsum.toACCDevice();
      74             :   }
      75             :   void removeFromACCDevice() const  {
      76             :     kernelsum.removeFromACCDevice();
      77             : #pragma acc exit data delete(kernels_for_gridpoint[0:kernels_for_gridpoint_v.size()], \
      78             :                              nkernels_per_point[0:nkernels_per_point_v.size()], \
      79             :                              ndim,maxkernels,fixed_width,this[0:1])
      80             :   }
      81             : };
      82             : 
      83             : template <class K, class P, class G>
      84         443 : void KDEHelper<K,P,G>::registerKeywords( Keywords& keys ) {
      85         362 :   SumOfKernels<K,P>::registerKeywords( keys );
      86         443 :   G::registerKeywords( keys );
      87         443 : }
      88             : 
      89             : template <class K, class P, class G>
      90         112 : void KDEHelper<K,P,G>::read( KDEHelper<K,P,G>& func,
      91             :                              ActionWithArguments* action,
      92             :                              const std::vector<Value*>& args,
      93             :                              GridCoordinatesObject& gridobject,
      94             :                              std::vector<std::size_t>& shape,
      95             :                              function::FunctionOptions& options ) {
      96         112 :   func.nneigh.resize( args.size() );
      97          84 :   SumOfKernels<K,P>::read( func.kernelsum, action, args, options );
      98         112 :   G::readBandwidthAndHeight( func.kernelsum.params, action );
      99         413 :   for(unsigned i=1; i<action->getNumberOfArguments(); ++i) {
     100         302 :     if( (action->getPntrToArgument(0))->getNumberOfValues()==0 && (action->getPntrToArgument(i))->isConstant() ) {
     101           1 :       continue;
     102             :     }
     103             : 
     104         301 :     if( (action->getPntrToArgument(0))->getNumberOfValues()!=1 || (action->getPntrToArgument(0))->getNumberOfValues()!=1 ) {
     105         201 :       if( (action->getPntrToArgument(0))->getRank()!=(action->getPntrToArgument(i))->getRank() ) {
     106           0 :         action->error("mismatch between ranks of input actions");
     107             :       }
     108         443 :       for(unsigned j=0; j<(action->getPntrToArgument(0))->getRank(); ++j) {
     109         242 :         if( (action->getPntrToArgument(0))->getShape()[j]!=(action->getPntrToArgument(i))->getShape()[j] ) {
     110           0 :           action->error("mismatch between shapes of input actions");
     111             :         }
     112             :       }
     113             :     }
     114             :   }
     115         111 :   G::readGridParameters( func.g, action, gridobject, shape );
     116         110 : }
     117             : 
     118             : template <class K, class P, class G>
     119         105 : void KDEHelper<K,P,G>::setupGridBounds( KDEHelper<K,P,G>& func, const Tensor& box, GridCoordinatesObject& gridobject, const std::vector<Value*>& args, Value* myval ) {
     120             :   // Setup the grid boundaries on first step
     121          94 :   G::setupGridBounds( func.g, box, gridobject, args, myval );
     122         102 :   if( gridobject.getGridType()!="fibonacci" ) {
     123             :     // Set the periodicity of the parameters
     124         212 :     for(unsigned i=0; i<gridobject.getDimension(); ++i) {
     125         121 :       P::setArgumentDomain( i, func.kernelsum.params, gridobject.getGridSpacing()[i], gridobject.isPeriodic(i), gridobject.getMin()[i], gridobject.getMax()[i] );
     126             :     }
     127             :   }
     128             :   func.kernelsum.params.update();
     129             :   // Check if the bandwidth changes during the simulation
     130         102 :   func.fixed_width = false;
     131         102 :   std::size_t ndim = gridobject.getDimension();
     132         102 :   if( K::bandwidthIsConstant( ndim, args ) && K::bandwidthsAllSame( ndim, args ) ) {
     133         102 :     std::vector<double> myargs( args.size() );
     134         477 :     for(unsigned j=0; j<args.size(); ++j) {
     135         375 :       myargs[j] = args[j]->get(0);
     136             :     }
     137             :     // Convert the input into kernel parameters, so that the support is computed from the same
     138             :     // quantities used in transferParamsToKernel when it is recomputed for each kernel
     139             :     // (NonDiagonalKernelParams stores the inverse of the covariance matrix, not the covariance)
     140         102 :     std::vector<double> kparams( K::getNumberOfParameters(ndim), 0.0 );
     141             :     View<double> kpview( kparams.data(), kparams.size() );
     142         102 :     K::setKernelAndCheckHeight( kpview, ndim, myargs );
     143         102 :     G::getDiscreteSupport( func.g, func.kernelsum.params, View<const double>( kparams.data() + ndim, K::getNumberOfShapeParameters(ndim)), func.nneigh, gridobject );
     144         102 :     func.fixed_width = true;
     145             :   }
     146         102 : }
     147             : 
     148             : template <class K, class P, class G>
     149         181 : void KDEHelper<K,P,G>::readKernelParameters( std::string& value, ActionWithArguments* action, const std::string& outlab, bool rerequestargs ) {
     150             :   std::size_t dot = value.find_first_of('.');
     151         181 :   ActionWithValue* av = action->plumed.getActionSet().selectWithLabel<ActionWithValue*>( value.substr(0,dot) );
     152         181 :   if( !av ) {
     153         133 :     std::string matstr, vals = "VALUES=" + value;
     154         133 :     if( (action->getPntrToArgument(0))->getRank()==2 ) {
     155             :       std::string nr, nc;
     156          14 :       Tools::convert( (action->getPntrToArgument(0))->getShape()[0], nr );
     157          14 :       Tools::convert( (action->getPntrToArgument(0))->getShape()[1], nc );
     158          42 :       matstr = " NROWS=" + nr + " NCOLS=" + nc;
     159             :     }
     160     1446501 :     for(unsigned i=1; i<(action->getPntrToArgument(0))->getNumberOfValues(); ++i) {
     161     2892736 :       vals += "," + value;
     162             :     }
     163         266 :     action->plumed.readInputWords( Tools::getWords(action->getLabel() + outlab + ": CONSTANT NOLOG " + vals + matstr ), false );
     164         266 :     value = action->getLabel() + outlab;
     165             :   } else {
     166             :     Value* myval;
     167          48 :     if( dot!=std::string::npos ) {
     168           2 :       myval = av->copyOutput( value );
     169             :     } else {
     170          46 :       if( av->getNumberOfComponents()>1 ) {
     171           0 :         action->error("problem reading argument " + value );
     172             :       }
     173          46 :       myval = av->copyOutput(0);
     174             :     }
     175          48 :     if( myval->getRank()==0 ) {
     176             :       std::string nvals;
     177           0 :       if( (action->getPntrToArgument(0))->getRank()==2 ) {
     178             :         std::string nr, nc;
     179           0 :         Tools::convert( (action->getPntrToArgument(0))->getShape()[0], nr );
     180           0 :         Tools::convert( (action->getPntrToArgument(0))->getShape()[1], nc );
     181           0 :         nvals = nr + "," + nc;
     182             :       } else {
     183           0 :         Tools::convert( (action->getPntrToArgument(0))->getNumberOfValues(), nvals );
     184             :       }
     185           0 :       action->plumed.readInputWords( Tools::getWords(action->getLabel() + outlab + "_ones: ONES SIZE=" + nvals ), false );
     186           0 :       action->plumed.readInputWords( Tools::getWords(action->getLabel() + outlab + ": CUSTOM ARG=" + action->getLabel() + outlab + "_ones," + value ), false );
     187           0 :       value = action->getLabel() + outlab;
     188             :     }
     189             :   }
     190         181 :   if( !rerequestargs ) {
     191             :     return;
     192             :   }
     193         150 :   KDEHelper<K,P,G>::addArgument( value, action );
     194           0 : }
     195             : 
     196             : template <class K, class P, class G>
     197         242 : void KDEHelper<K,P,G>::addArgument( const std::string& value, ActionWithArguments* action ) {
     198         242 :   std::size_t dot = value.find_first_of(".");
     199         242 :   ActionWithValue* av = action->plumed.getActionSet().selectWithLabel<ActionWithValue*>( value.substr(0,dot) );
     200         242 :   plumed_assert( av );
     201         242 :   std::vector<Value*> args( action->getArguments() );
     202         242 :   args.push_back( av->copyOutput(0) );
     203         242 :   action->requestArguments( args );
     204         242 : }
     205             : 
     206             : template <class K, class P, class G>
     207      600634 : void KDEHelper<K,P,G>::transferParamsToKernel( const std::vector<double>& argval, KDEHelper<K,P,G>& func, GridCoordinatesObject& gridobject, bool updateNeighborsOnEachKernel, std::size_t nkernels, unsigned kval, View<double>& params ) {
     208             :   // This sets the kernel parameters for the Kth kernel and checks that we want
     209             :   // to consider it
     210      600634 :   std::size_t ndim = gridobject.getDimension();
     211      600634 :   if( !K::setKernelAndCheckHeight( params, ndim, argval ) ) {
     212      224647 :     return;
     213             :   }
     214             :   // If the widths of each kernel are not all the same then get the discrete support
     215      375987 :   if( updateNeighborsOnEachKernel ) {
     216           0 :     G::getDiscreteSupport( func.g, func.kernelsum.params, View<const double>(params.data()+ndim,K::getNumberOfShapeParameters(ndim)), func.nneigh, gridobject );
     217             :   }
     218             : 
     219             :   // Now get the grid points for this particular kernel
     220             :   unsigned num_neigh;
     221      375987 :   std::vector<unsigned> neighbors;
     222      375987 :   G::getNeighbors( func.kernelsum.params, View<double>(params.data(),ndim), gridobject, func.nneigh, num_neigh, neighbors );
     223             : 
     224             :   // And transfer the neighbor information to the holders
     225    57114839 :   for(unsigned j=0; j<num_neigh; ++j) {
     226    56738853 :     plumed_assert( neighbors[j]*nkernels + func.nkernels_per_point_v[neighbors[j]] < func.kernels_for_gridpoint_v.size() );
     227    56738853 :     func.kernels_for_gridpoint_v[ neighbors[j]*nkernels + func.nkernels_per_point_v[neighbors[j]] ] = kval;
     228    56738853 :     func.nkernels_per_point_v[ neighbors[j] ]++;
     229             :   }
     230             : }
     231             : 
     232             : template <class K, class P, class G>
     233        2600 : void KDEHelper<K,P,G>::transferKernels( KDEHelper<K,P,G>& func, const std::vector<Value*>& args, GridCoordinatesObject& gridobject ) {
     234             :   // Resize the kernel sum if we need to
     235             :   // Number of kernels is determined based on sparsity pattern of matrix input as matrix of heights
     236        2600 :   std::size_t nkernels = args[args.size()-1]->getNumberOfStoredValues();
     237             :   // And resize the grid counters if we need to
     238        2600 :   std::size_t ngp = gridobject.getNumberOfPoints();
     239        2600 :   if( func.nkernels_per_point_v.size()!=ngp ) {
     240         102 :     func.nkernels_per_point_v.resize( ngp );
     241             :   }
     242        2600 :   std::size_t ndim = gridobject.getDimension();
     243             :   std::size_t nparams_per_kernel = K::getNumberOfParameters(ndim);
     244             :   std::fill( func.nkernels_per_point_v.begin(), func.nkernels_per_point_v.end(), 0 );
     245        2600 :   if( func.kernelsum.kernelParams_v.size()!=nkernels*nparams_per_kernel ) {
     246         109 :     func.kernelsum.kernelParams_v.resize( nkernels*nparams_per_kernel );
     247         109 :     func.kernels_for_gridpoint_v.resize( ngp*nkernels );
     248             :   }
     249             : 
     250        2600 :   std::vector<double> argval( args.size() );
     251        2600 :   bool bandwidthsAllSame = false, updateNeighborsOnEachKernel = !func.fixed_width;
     252        2600 :   if( updateNeighborsOnEachKernel ) {
     253           0 :     bandwidthsAllSame = K::bandwidthsAllSame( ndim, args );
     254             :   }
     255        2600 :   if( args[args.size()-1]->getRank()==2 ) {
     256          53 :     const unsigned nc    = args[args.size()-1]->getShape()[1];
     257          53 :     const unsigned nrows = args[args.size()-1]->getShape()[0];
     258          53 :     const unsigned ncs   = args[args.size()-1]->getNumberOfColumns();
     259       11237 :     for(unsigned i=0; i<nrows; ++i) {
     260       11184 :       unsigned ncols = args[args.size()-1]->getRowLength(i);
     261       60646 :       for(unsigned k=0; k<args.size(); ++k) {
     262       87640 :         plumed_massert( args[k]->isConstant() || ncols==args[k]->getRowLength(i), "all input matrices must have same sparsity pattern" );
     263             :       }
     264      448275 :       for(unsigned j=0; j<ncols; ++j) {
     265      437091 :         unsigned jind = args[args.size()-1]->getRowIndex( i, j );
     266     1990664 :         for(unsigned k=0; k<args.size(); ++k) {
     267     1553573 :           if( jind==args[k]->getRowIndex( i, j ) ) {
     268     1138794 :             argval[k] = args[k]->get( i*ncs+ j, false );
     269             :           } else {
     270      414779 :             argval[k] = args[k]->get( i*nc + jind );
     271             :           }
     272             :         }
     273      437091 :         View<double> myparams( func.kernelsum.kernelParams_v.data() + nparams_per_kernel*(i*ncs+j), nparams_per_kernel );
     274      437091 :         KDEHelper<K,P,G>::transferParamsToKernel( argval, func, gridobject, updateNeighborsOnEachKernel, nkernels, i*ncs+j, myparams );
     275      437091 :         if( bandwidthsAllSame ) {
     276             :           updateNeighborsOnEachKernel = false;
     277             :         }
     278             :       }
     279             :     }
     280             :   } else {
     281      166089 :     for(unsigned i=0; i<nkernels; ++i) {
     282             :       // Transfer the kernel parameters to local vector of doubles
     283      873139 :       for(unsigned j=0; j<args.size(); ++j) {
     284      709596 :         argval[j] = args[j]->get(i,false);
     285             :       }
     286      163543 :       View<double> myparams( func.kernelsum.kernelParams_v.data() + nparams_per_kernel*i, nparams_per_kernel );
     287      163543 :       KDEHelper<K,P,G>::transferParamsToKernel( argval, func, gridobject, updateNeighborsOnEachKernel, nkernels, i, myparams );
     288      163542 :       if( bandwidthsAllSame ) {
     289             :         updateNeighborsOnEachKernel = false;
     290             :       }
     291             :     }
     292             :   }
     293             :   // Get the maximum number of kernels for any given grid point (used for resizing derivatives)
     294        2599 :   func.maxkernels = 0;
     295      586780 :   for(unsigned i=0; i<ngp; ++i) {
     296      584181 :     if( func.nkernels_per_point_v[i]>func.maxkernels ) {
     297        3919 :       func.maxkernels = func.nkernels_per_point_v[i];
     298             :     }
     299             :   }
     300             :   func.update();
     301        2599 : }
     302             : 
     303             : template <class K, class P, class G, typename myPTM=defaultPTM>
     304             : class KDE : public ActionWithGrid {
     305             : public:
     306             :   using input_type = KDEHelper<K, P, G>;
     307             :   using mytype=KDE<K, P, G, myPTM>;
     308             :   using PTM = typename myPTM::template PTM<mytype>;
     309             :   typedef typename PTM::ParallelActionsInput ParallelActionsInput;
     310             :   typedef typename PTM::ParallelActionsOutput ParallelActionsOutput;
     311             : private:
     312             :   bool firststep;
     313             : /// The parallel task manager
     314             :   PTM taskmanager;
     315             :   GridCoordinatesObject gridobject;
     316             : public:
     317             :   static void registerKeywords( Keywords& keys );
     318             :   explicit KDE(const ActionOptions&ao);
     319             :   std::vector<std::string> getGridCoordinateNames() const override ;
     320             :   const GridCoordinatesObject& getGridCoordinatesObject() const override ;
     321             :   unsigned getNumberOfDerivatives() override;
     322             :   int checkTaskIsActive( const unsigned& itask ) const override ;
     323             :   void turnOnDerivatives() override ;
     324             :   void prepare() override ;
     325             :   void calculate() override ;
     326             :   void getArgumentInputData( std::vector<double>& inputdata ) const override ;
     327             :   void getArgumentInputData( std::vector<float>& inputdata ) const override ;
     328             :   static void performTask( std::size_t task_index,
     329             :                            const KDEHelper<K, P, G>& actiondata,
     330             :                            ParallelActionsInput& input,
     331             :                            ParallelActionsOutput& output );
     332             :   void applyNonZeroRankForces( std::vector<double>& outforces ) override ;
     333             :   static int getNumberOfValuesPerTask( std::size_t task_index,
     334             :                                        const KDEHelper<K, P, G>& actiondata );
     335             :   static void getForceIndices( std::size_t task_index,
     336             :                                std::size_t colno,
     337             :                                std::size_t ntotal_force,
     338             :                                const KDEHelper<K, P, G>& actiondata,
     339             :                                const ParallelActionsInput& input,
     340             :                                ForceIndexHolder force_indices );
     341             : };
     342             : 
     343             : template <class K, class P, class G, typename myPTM>
     344         443 : void KDE<K,P,G,myPTM>::registerKeywords( Keywords& keys ) {
     345         443 :   ActionWithGrid::registerKeywords( keys );
     346         886 :   keys.addInputKeyword("compulsory","ARG","scalar/vector/matrix","the label for the value that should be used to construct the histogram");
     347         443 :   KDEHelper<K,P,G>::registerKeywords( keys );
     348             :   // Keywords for spherical KDE
     349         443 :   keys.add("hidden","MASKED_INPUT_ALLOWED","turns on that you are allowed to use masked inputs ");
     350         886 :   keys.setValueDescription("grid","a function on a grid that was obtained by doing a Kernel Density Estimation using the input arguments");
     351         443 :   if( keys.getDisplayName()!="SPHERICAL_KDE" ) {
     352         852 :     keys.setDisplayName("KDE");
     353             :   }
     354         443 :   PTM::registerKeywords( keys );
     355         443 : }
     356             : 
     357             : template <class K, class P, class G, typename myPTM>
     358         112 : KDE<K,P,G,myPTM>::KDE(const ActionOptions&ao):
     359             :   Action(ao),
     360             :   ActionWithGrid(ao),
     361         112 :   firststep(true),
     362         112 :   taskmanager(this) {
     363             : 
     364         112 :   std::vector<std::size_t> shape( getNumberOfArguments() );
     365         112 :   unsigned numberOfKernels=getPntrToArgument(0)->getNumberOfValues();
     366         172 :   for(unsigned i=1; i<shape.size(); ++i) {
     367          60 :     if( numberOfKernels!=getPntrToArgument(i)->getNumberOfValues() ) {
     368           0 :       error("mismatch between numbers of values in input arguments");
     369             :     }
     370             :   }
     371             : 
     372         112 :   function::FunctionOptions foptions;
     373         112 :   KDEHelper<K,P,G>::read( taskmanager.getActionInput(), this, getArguments(), gridobject, shape, foptions );
     374         110 :   addValueWithDerivatives( shape );
     375         110 :   setNotPeriodic();
     376         110 :   getPntrToComponent(0)->setDerivativeIsZeroWhenValueIsZero();
     377         120 : }
     378             : 
     379             : template <class K, class P, class G, typename myPTM>
     380        8063 : unsigned KDE<K,P,G,myPTM>::getNumberOfDerivatives() {
     381        8063 :   return gridobject.getDimension();
     382             : }
     383             : 
     384             : template <class K, class P, class G, typename myPTM>
     385         155 : std::vector<std::string> KDE<K,P,G,myPTM>::getGridCoordinateNames() const {
     386         155 :   std::vector<std::string> names( gridobject.getDimension() );
     387         386 :   for(unsigned i=0; i<names.size(); ++i) {
     388             :     names[i] = getPntrToArgument(i)->getName();
     389             :   }
     390         155 :   return names;
     391           0 : }
     392             : 
     393             : template <class K, class P, class G, typename myPTM>
     394      280185 : const GridCoordinatesObject& KDE<K,P,G,myPTM>::getGridCoordinatesObject() const {
     395      280185 :   return gridobject;
     396             : }
     397             : 
     398             : template <class K, class P, class G, typename myPTM>
     399      584181 : int KDE<K,P,G,myPTM>::checkTaskIsActive( const unsigned& itask ) const {
     400      584181 :   if( taskmanager.getActionInput().nkernels_per_point_v[itask]>0 ) {
     401      183368 :     return 1;
     402             :   }
     403             :   return -1;
     404             : }
     405             : 
     406             : template <class K, class P, class G, typename myPTM>
     407          64 : void KDE<K,P,G,myPTM>::turnOnDerivatives() {
     408          64 :   if( getName().find("DISCRETE")!=std::string::npos ) {
     409           0 :     error("KDE with discrete kernels is not differentiable");
     410             :   }
     411          64 :   ActionWithValue::turnOnDerivatives();
     412          64 : }
     413             : 
     414             : template <class K, class P, class G, typename myPTM>
     415        2603 : void KDE<K,P,G,myPTM>::prepare() {
     416        2603 :   ActionWithVector::prepare();
     417        2603 :   std::size_t nkernels = getPntrToArgument(0)->getNumberOfValues();
     418        8101 :   for(unsigned i=1; i<getNumberOfArguments(); ++i) {
     419             :     Value* myarg = getPntrToArgument(i);
     420        5498 :     if( myarg->getNumberOfValues()!=nkernels ) {
     421           1 :       if( myarg->isConstant() && myarg->getNumberOfValues()==1 ) {
     422           1 :         myarg->reshapeConstantValue( getPntrToArgument(0)->getShape() );
     423             :       } else {
     424           0 :         plumed_merror("found mismatched numbers of arguments in input");
     425             :       }
     426             :     }
     427             :   }
     428        2603 : }
     429             : 
     430             : template <class K, class P, class G, typename myPTM>
     431        2603 : void KDE<K,P,G,myPTM>::calculate() {
     432        2603 :   if( firststep ) {
     433         105 :     Tensor box;
     434         105 :     PbcAction* bv = plumed.getActionSet().template selectWithLabel<PbcAction*>("Box");
     435         105 :     if( bv ) {
     436         104 :       box = bv->getPbc().getBox();
     437             :     }
     438         105 :     KDEHelper<K,P,G>::setupGridBounds( taskmanager.getActionInput(), box, gridobject, getArguments(), getPntrToComponent(0) );
     439         102 :     firststep=false;
     440             :   }
     441        2600 :   KDEHelper<K,P,G>::transferKernels( taskmanager.getActionInput(), getArguments(), gridobject );
     442        2599 :   taskmanager.setupParallelTaskManager( getNumberOfArguments()*taskmanager.getActionInput().maxkernels, getNumberOfForceDerivatives() );
     443        2599 :   taskmanager.runAllTasks();
     444        2599 : }
     445             : 
     446             : template <class K, class P, class G, typename myPTM>
     447        2599 : void KDE<K,P,G,myPTM>::getArgumentInputData( std::vector<double>& inputdata ) const {
     448        2599 :   std::size_t ndim = gridobject.getDimension();
     449        2599 :   std::size_t nstored = getConstPntrToComponent(0)->getNumberOfStoredValues();
     450        2599 :   std::vector<double> pos( ndim );
     451        2599 :   if( inputdata.size()!=nstored*ndim ) {
     452         101 :     inputdata.resize( ndim*nstored );
     453             :   }
     454             : 
     455      586780 :   for(unsigned i=0; i<nstored; ++i) {
     456      584181 :     gridobject.getGridPointCoordinates( i, pos );
     457     1939989 :     for(unsigned j=0; j<ndim; ++j) {
     458     1355808 :       inputdata[ i*ndim + j ] = pos[j];
     459             :     }
     460             :   }
     461        2599 : }
     462             : 
     463             : template <class K, class P, class G, typename myPTM>
     464           0 : void KDE<K,P,G,myPTM>::getArgumentInputData( std::vector<float>& inputdata ) const {
     465           0 :   std::size_t ndim = gridobject.getDimension();
     466           0 :   std::size_t nstored = getConstPntrToComponent(0)->getNumberOfStoredValues();
     467           0 :   std::vector<double> pos( ndim );
     468           0 :   if( inputdata.size()!=nstored*ndim ) {
     469           0 :     inputdata.resize( ndim*nstored );
     470             :   }
     471             : 
     472           0 :   for(unsigned i=0; i<nstored; ++i) {
     473           0 :     gridobject.getGridPointCoordinates( i, pos );
     474           0 :     for(unsigned j=0; j<ndim; ++j) {
     475           0 :       inputdata[ i*ndim + j ] = pos[j];
     476             :     }
     477             :   }
     478           0 : }
     479             : 
     480             : template <class K, class P, class G, typename myPTM>
     481      190619 : void KDE<K,P,G,myPTM>::performTask( std::size_t task_index,
     482             :                                     const KDEHelper<K, P, G>& actiondata,
     483             :                                     ParallelActionsInput& input,
     484             :                                     ParallelActionsOutput& output ) {
     485      190619 :   std::size_t ndim = actiondata.ndim;
     486      381238 :   SumOfKernels<K,P>::calc( View<const std::size_t>( actiondata.kernels_for_gridpoint + task_index*input.argstarts[1], actiondata.nkernels_per_point[task_index] ),
     487      190619 :                            actiondata.kernelsum,
     488      190619 :                            View<const double>(input.inputdata + task_index*ndim,ndim),
     489             :                            View<double>(output.values.data(), 1),
     490             :                            View<double>(output.values.data()+1, ndim),
     491      190619 :                            View<double>(output.derivatives.data(),actiondata.maxkernels*input.nargs) );
     492             : 
     493      190619 : }
     494             : 
     495             : template <class K, class P, class G, typename myPTM>
     496         617 : void KDE<K,P,G,myPTM>::applyNonZeroRankForces( std::vector<double>& outforces ) {
     497         617 :   taskmanager.applyForces( outforces );
     498         617 : }
     499             : 
     500             : template <class K, class P, class G, typename myPTM>
     501        7329 : int KDE<K,P,G,myPTM>::getNumberOfValuesPerTask( std::size_t task_index,
     502             :     const KDEHelper<K, P, G>& actiondata ) {
     503        7329 :   return 1;
     504             : }
     505             : 
     506             : template <class K, class P, class G, typename myPTM>
     507        7239 : void KDE<K,P,G,myPTM>::getForceIndices( std::size_t task_index,
     508             :                                         std::size_t colno,
     509             :                                         std::size_t ntotal_force,
     510             :                                         const KDEHelper<K, P, G>& actiondata,
     511             :                                         const ParallelActionsInput& input,
     512             :                                         ForceIndexHolder force_indices ) {
     513        7239 :   force_indices.threadsafe_derivatives_end[0] = 0;
     514             :   std::size_t nparams = K::getNumberOfParameters( actiondata.ndim );
     515        7239 :   View<const std::size_t> kernellist( actiondata.kernels_for_gridpoint + task_index*input.argstarts[1], actiondata.nkernels_per_point[task_index] );
     516     1051320 :   for(unsigned i=0; i<kernellist.size(); ++i) {
     517     5555892 :     for(unsigned j=0; j<nparams; ++j) {
     518     4511811 :       force_indices.indices[0][i*nparams+j] = input.argstarts[j] + kernellist[i];
     519             :     }
     520             :   }
     521        7239 :   force_indices.tot_indices[0] = kernellist.size()*nparams;
     522        7239 : }
     523             : 
     524             : }
     525             : }
     526             : #endif

Generated by: LCOV version 1.16