LCOV - code coverage report
Current view: top level - gridtools - HistogramOnGrid.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 119 121 98.3 %
Date: 2024-10-11 08:09:47 Functions: 12 12 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             : #include "HistogramOnGrid.h"
      23             : #include "tools/KernelFunctions.h"
      24             : 
      25             : namespace PLMD {
      26             : namespace gridtools {
      27             : 
      28          65 : void HistogramOnGrid::registerKeywords( Keywords& keys ) {
      29          65 :   GridVessel::registerKeywords( keys );
      30         130 :   keys.add("compulsory","KERNEL","the type of kernel to use");
      31         130 :   keys.add("compulsory","BANDWIDTH","the bandwidths");
      32         130 :   keys.add("compulsory","CONCENTRATION","the concentration parameter for Von Mises-Fisher distributions");
      33          65 : }
      34             : 
      35          45 : HistogramOnGrid::HistogramOnGrid( const vesselbase::VesselOptions& da ):
      36             :   GridVessel(da),
      37          45 :   neigh_tot(0),
      38          45 :   addOneKernelAtATime(false),
      39          45 :   bandwidths(dimension),
      40          45 :   discrete(false)
      41             : {
      42          90 :   if( getType()=="flat" ) {
      43          86 :     parse("KERNEL",kerneltype);
      44          86 :     if( kerneltype=="discrete" || kerneltype=="DISCRETE" ) {
      45          10 :       discrete=true; setNoDerivatives();
      46             :     } else {
      47          66 :       parseVector("BANDWIDTH",bandwidths);
      48             :     }
      49             :   } else {
      50           2 :     parse("CONCENTRATION",von_misses_concentration);
      51           2 :     von_misses_norm = von_misses_concentration / ( 4*pi*sinh( von_misses_concentration ) );
      52             :   }
      53          45 : }
      54             : 
      55           3 : double HistogramOnGrid::getFibonacciCutoff() const {
      56           3 :   return std::log( epsilon / von_misses_norm ) / von_misses_concentration;
      57             : }
      58             : 
      59          19 : bool HistogramOnGrid::noDiscreteKernels() const {
      60          19 :   return !discrete;
      61             : }
      62             : 
      63          50 : void HistogramOnGrid::setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax,
      64             :                                  const std::vector<unsigned>& nbins, const std::vector<double>& spacing ) {
      65          50 :   GridVessel::setBounds( smin, smax, nbins, spacing );
      66          50 :   if( !discrete ) {
      67          40 :     std::vector<double> point(dimension,0);
      68          40 :     KernelFunctions kernel( point, bandwidths, kerneltype, "DIAGONAL", 1.0 ); neigh_tot=1;
      69          80 :     nneigh=kernel.getSupport( dx ); std::vector<double> support( kernel.getContinuousSupport() );
      70         103 :     for(unsigned i=0; i<dimension; ++i) {
      71          63 :       if( pbc[i] && 2*support[i]>getGridExtent(i) ) error("bandwidth is too large for periodic grid");
      72          63 :       neigh_tot *= (2*nneigh[i]+1);
      73             :     }
      74          40 :   }
      75          50 : }
      76             : 
      77       23625 : std::unique_ptr<KernelFunctions> HistogramOnGrid::getKernelAndNeighbors( std::vector<double>& point, unsigned& num_neigh, std::vector<unsigned>& neighbors ) const {
      78       23625 :   if( discrete ) {
      79        4222 :     plumed_assert( getType()=="flat" );
      80        4222 :     num_neigh=1; for(unsigned i=0; i<dimension; ++i) point[i] += 0.5*dx[i];
      81        2111 :     neighbors[0] = getIndex( point ); return NULL;
      82       43028 :   } else if( getType()=="flat" ) {
      83       21457 :     auto kernel=Tools::make_unique<KernelFunctions>( point, bandwidths, kerneltype, "DIAGONAL", 1.0 );
      84             : // GB: Now values is destroyed when exiting this function.
      85             : // I think before there was a leak
      86       21457 :     std::vector<std::unique_ptr<Value>> values=getVectorOfValues();
      87       64371 :     kernel->normalize( Tools::unique2raw(values) ); getNeighbors( kernel->getCenter(), nneigh, num_neigh, neighbors );
      88             :     return kernel;
      89       21571 :   } else if( getType()=="fibonacci" ) {
      90          57 :     getNeighbors( point, nneigh, num_neigh, neighbors );
      91             :     return NULL;
      92             :   } else {
      93           0 :     plumed_error();
      94             :   }
      95             :   return NULL;
      96             : }
      97             : 
      98      115624 : std::vector<std::unique_ptr<Value>> HistogramOnGrid::getVectorOfValues() const {
      99             :   std::vector<std::unique_ptr<Value>> vv;
     100      225230 :   for(unsigned i=0; i<dimension; ++i) {
     101      167418 :     vv.emplace_back(Tools::make_unique<Value>());
     102      167418 :     if( pbc[i] ) vv[i]->setDomain( str_min[i], str_max[i] );
     103       64454 :     else vv[i]->setNotPeriodic();
     104             :   }
     105       57812 :   return vv;
     106           0 : }
     107             : 
     108       38461 : void HistogramOnGrid::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const {
     109       38461 :   if( addOneKernelAtATime ) {
     110             :     plumed_dbg_assert( myvals.getNumberOfValues()==2 && !wasforced );
     111       14908 :     std::vector<double> der( dimension );
     112       54492 :     for(unsigned i=0; i<dimension; ++i) der[i]=myvals.getDerivative( 1, i );
     113       14908 :     accumulate( getAction()->getPositionInCurrentTaskList(current), myvals.get(0), myvals.get(1), der, buffer );
     114             :   } else {
     115             :     plumed_dbg_assert( myvals.getNumberOfValues()==dimension+2 );
     116       23553 :     std::vector<double> point( dimension ); double weight=myvals.get(0)*myvals.get( 1+dimension );
     117       89610 :     for(unsigned i=0; i<dimension; ++i) point[i]=myvals.get( 1+i );
     118             :     // Get the kernel
     119       23553 :     unsigned num_neigh; std::vector<unsigned> neighbors(1);
     120       23553 :     std::vector<double> der( dimension );
     121       23553 :     std::unique_ptr<KernelFunctions> kernel=getKernelAndNeighbors( point, num_neigh, neighbors );
     122             : 
     123       27879 :     if( !kernel && getType()=="flat" ) {
     124        2106 :       plumed_dbg_assert( num_neigh==1 ); der.resize(0);
     125        2106 :       accumulate( neighbors[0], weight, 1.0, der, buffer );
     126             :     } else {
     127             :       double totwforce=0.0;
     128       21447 :       std::vector<double> intforce( 2*dimension, 0.0 );
     129       21447 :       std::vector<std::unique_ptr<Value>> vv( getVectorOfValues() );
     130             : 
     131       21447 :       double newval; std::vector<unsigned> tindices( dimension ); std::vector<double> xx( dimension );
     132    20582512 :       for(unsigned i=0; i<num_neigh; ++i) {
     133    20561065 :         unsigned ineigh=neighbors[i];
     134    20561065 :         if( inactive( ineigh ) ) continue ;
     135    11848693 :         getGridPointCoordinates( ineigh, tindices, xx );
     136    11848693 :         if( kernel ) {
     137    47354528 :           for(unsigned j=0; j<dimension; ++j) vv[j]->set(xx[j]);
     138    23687840 :           newval = kernel->evaluate( Tools::unique2raw(vv), der, true );
     139             :         } else {
     140             :           // Evalulate dot product
     141       19092 :           double dot=0; for(unsigned j=0; j<dimension; ++j) { dot+=xx[j]*point[j]; der[j]=xx[j]; }
     142             :           // Von misses distribution for concentration parameter
     143        4773 :           newval = von_misses_norm*exp( von_misses_concentration*dot );
     144             :           // And final derivatives
     145       19092 :           for(unsigned j=0; j<dimension; ++j) der[j] *= von_misses_concentration*newval;
     146             :         }
     147    11848693 :         accumulate( ineigh, weight, newval, der, buffer );
     148    11848693 :         if( wasForced() ) {
     149        5744 :           accumulateForce( ineigh, weight, der, intforce );
     150        5744 :           totwforce += myvals.get( 1+dimension )*newval*forces[ineigh];
     151             :         }
     152             :       }
     153       21447 :       if( wasForced() ) {
     154             :         // Minus sign for kernel here as we are taking derivative with respect to position of center of
     155             :         // kernel NOT derivative wrt to grid point
     156         110 :         double pref = 1; if( kernel ) pref = -1;
     157         110 :         unsigned nder = getAction()->getNumberOfDerivatives();
     158         110 :         unsigned gridbuf = getNumberOfBufferPoints()*getNumberOfQuantities();
     159         300 :         for(unsigned j=0; j<dimension; ++j) {
     160       33940 :           for(unsigned k=0; k<myvals.getNumberActive(); ++k) {
     161             :             unsigned kder=myvals.getActiveIndex(k);
     162       33750 :             buffer[ bufstart + gridbuf + kder ] += pref*intforce[j]*myvals.getDerivative( j+1, kder );
     163             :           }
     164             :         }
     165             :         // Accumulate the sum of all the weights
     166         110 :         buffer[ bufstart + gridbuf + nder ] += myvals.get(0);
     167             :         // Add the derivatives of the weights into the force -- this is separate loop as weights of all parts are considered together
     168       32060 :         for(unsigned k=0; k<myvals.getNumberActive(); ++k) {
     169             :           unsigned kder=myvals.getActiveIndex(k);
     170       31950 :           buffer[ bufstart + gridbuf + kder ] += totwforce*myvals.getDerivative( 0, kder );
     171       31950 :           buffer[ bufstart + gridbuf + nder + 1 + kder ] += myvals.getDerivative( 0, kder );
     172             :         }
     173             :       }
     174       21447 :     }
     175       23553 :   }
     176       38461 : }
     177             : 
     178       40596 : void HistogramOnGrid::accumulate( const unsigned& ipoint, const double& weight, const double& dens, const std::vector<double>& der, std::vector<double>& buffer ) const {
     179       40596 :   buffer[bufstart+nper*ipoint] += weight*dens;
     180      168672 :   if( der.size()>0 ) for(unsigned j=0; j<dimension; ++j) buffer[bufstart+nper*ipoint + 1 + j] += weight*der[j];
     181       40596 : }
     182             : 
     183        5744 : void HistogramOnGrid::accumulateForce( const unsigned& ipoint, const double& weight, const std::vector<double>& der, std::vector<double>& intforce ) const {
     184       18414 :   for(unsigned j=0; j<der.size(); ++j) intforce[j] += forces[ipoint]*weight*der[j];
     185        5744 : }
     186             : 
     187          20 : void HistogramOnGrid::getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ) {
     188          20 :   if( finalForces.size()!=getAction()->getNumberOfDerivatives() ) finalForces.resize( getAction()->getNumberOfDerivatives() );
     189             :   // And the final force
     190          20 :   unsigned nder = getAction()->getNumberOfDerivatives();
     191             :   // Derivatives due to normalization
     192          20 :   unsigned gridbuf = getNumberOfBufferPoints()*getNumberOfQuantities();
     193        3815 :   for(unsigned i=0; i<finalForces.size(); ++i) finalForces[i] = buffer[ bufstart + gridbuf + i ];
     194             :   // Derivatives due to normalization
     195          20 :   if( !noAverage() ) {
     196          15 :     unsigned wderstart = bufstart + gridbuf + nder; double pref=0;
     197        3620 :     for(unsigned ipoint=0; ipoint<getNumberOfPoints(); ++ipoint) {
     198        3605 :       pref += forces[ipoint]*buffer[ bufstart + ipoint*nper ] / buffer[wderstart];
     199             :     }
     200        3570 :     for(unsigned j=0; j<finalForces.size(); ++j) finalForces[j] -= pref*buffer[ wderstart + 1 + j ];
     201             :   }
     202          20 : }
     203             : 
     204         156 : void HistogramOnGrid::finish( const std::vector<double>& buffer ) {
     205         156 :   if( addOneKernelAtATime ) {
     206       14975 :     for(unsigned i=0; i<getAction()->getCurrentNumberOfActiveTasks(); ++i) {
     207       69400 :       for(unsigned j=0; j<nper; ++j) addDataElement( nper*getAction()->getActiveTask(i)+j, buffer[bufstart+i*nper+j] );
     208             :     }
     209             :   } else {
     210          89 :     GridVessel::finish( buffer );
     211             :   }
     212         156 : }
     213             : 
     214             : }
     215             : }

Generated by: LCOV version 1.15