LCOV - code coverage report
Current view: top level - tools - HistogramBead.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 95 161 59.0 %
Date: 2026-11-05 10:19:04 Functions: 11 20 55.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-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 "HistogramBead.h"
      23             : #include <vector>
      24             : #include "Tools.h"
      25             : #include "Keywords.h"
      26             : 
      27             : #pragma GCC diagnostic error "-Wswitch"
      28             : 
      29             : /*
      30             : IMPORTANT NOTE FOR DEVELOPERS:
      31             : 
      32             : If you add a new type of function in this file please add documentation for your new switching function type in function/Between.cpp
      33             : 
      34             : */
      35             : namespace PLMD {
      36             : 
      37             : constexpr double DP2CUTOFF=6.25;
      38             : //Non periodic constructor
      39      719120 : HistogramBead::HistogramBead(KernelType kt,const  double l,
      40             :                              const double h,
      41      719120 :                              const double w):
      42      719120 :   type(kt),
      43      719120 :   periodicity(Periodicity::notperiodic) {
      44      719120 :   set(l,h,w);
      45      719120 : }
      46             : //periodic constructor
      47           0 : HistogramBead::HistogramBead(KernelType kt,
      48             :                              double mlow,
      49             :                              double mhigh,const  double l,
      50             :                              const double h,
      51           0 :                              const double w):
      52           0 :   type(kt) {
      53             :   isPeriodic(mlow,mhigh);
      54           0 :   set(l,h,w);
      55           0 : }
      56             : 
      57           0 : HistogramBead::HistogramBead(const HistogramBead&)=default;
      58           0 : HistogramBead::HistogramBead(HistogramBead&&)=default;
      59           0 : HistogramBead& HistogramBead::operator=(const HistogramBead&)=default;
      60           0 : HistogramBead& HistogramBead::operator=(HistogramBead&&)=default;
      61             : 
      62           0 : void HistogramBead::registerKeywords( Keywords& keys ) {
      63           0 :   keys.add("compulsory","LOWER","the lower boundary for this particular bin");
      64           0 :   keys.add("compulsory","UPPER","the upper boundary for this particular bin");
      65           0 :   keys.add("compulsory","SMEAR","0.5","the amount to smear the Gaussian for each value in the distribution");
      66           0 : }
      67             : 
      68          58 : std::string HistogramBead::description() const {
      69          58 :   std::ostringstream ostr;
      70          58 :   switch (type) {
      71          58 :   case KernelType::gaussian:
      72          58 :     ostr<<"between "<<lowb<<" and "
      73          58 :         <<highb<<" width of gaussian window equals "<<width;
      74             :     break;
      75           0 :   case KernelType::triangular:
      76           0 :     ostr<<"between "<<lowb<<" and "
      77           0 :         <<highb<<" width of triangular window equals "<<width;
      78             :     break;
      79             :   }
      80          58 :   return ostr.str();
      81          58 : }
      82             : 
      83           0 : void HistogramBead::generateBins( const std::string& params, std::vector<std::string>& bins ) {
      84           0 :   std::vector<std::string> data=Tools::getWords(params);
      85           0 :   plumed_massert(data.size()>=1,"There is no input for this keyword");
      86             : 
      87           0 :   std::string name=data[0];
      88             : 
      89             :   unsigned nbins;
      90           0 :   std::vector<double> range(2);
      91             :   std::string smear;
      92           0 :   bool found_nb=Tools::parse(data,"NBINS",nbins);
      93           0 :   plumed_massert(found_nb,"Number of bins in histogram not found");
      94           0 :   bool found_r=Tools::parse(data,"LOWER",range[0]);
      95           0 :   plumed_massert(found_r,"Lower bound for histogram not specified");
      96           0 :   found_r=Tools::parse(data,"UPPER",range[1]);
      97           0 :   plumed_massert(found_r,"Upper bound for histogram not specified");
      98           0 :   plumed_massert(range[0]<range[1],"Range specification is dubious");
      99           0 :   bool found_b=Tools::parse(data,"SMEAR",smear);
     100           0 :   if(!found_b) {
     101           0 :     Tools::convert(0.5,smear);
     102             :   }
     103             : 
     104             :   std::string lb,ub;
     105           0 :   double delr = ( range[1]-range[0] ) / static_cast<double>( nbins );
     106           0 :   for(unsigned i=0; i<nbins; ++i) {
     107           0 :     Tools::convert( range[0]+i*delr, lb );
     108           0 :     Tools::convert( range[0]+(i+1)*delr, ub );
     109           0 :     bins.push_back( name + " " +  "LOWER=" + lb + " " + "UPPER=" + ub + " " + "SMEAR=" + smear );
     110             :   }
     111           0 :   plumed_assert(bins.size()==nbins);
     112           0 : }
     113             : 
     114          58 : void HistogramBead::set( const std::string& params, std::string& errormsg ) {
     115          58 :   std::vector<std::string> data=Tools::getWords(params);
     116          58 :   if(data.size()<1) {
     117             :     errormsg="No input has been specified";
     118             :     return;
     119             :   }
     120             : 
     121          58 :   std::string name=data[0];
     122             : 
     123          58 :   if(name=="GAUSSIAN") {
     124          58 :     type=KernelType::gaussian;
     125          58 :     cutoff=std::sqrt(2.0*DP2CUTOFF);
     126           0 :   } else if(name=="TRIANGULAR") {
     127           0 :     type=KernelType::triangular;
     128           0 :     cutoff=1.0;
     129             :   } else {
     130           0 :     plumed_merror("cannot understand kernel type " + name );
     131             :   }
     132             : 
     133             :   double smear;
     134          58 :   bool found_r=Tools::parse(data,"LOWER",lowb);
     135          58 :   if( !found_r ) {
     136             :     errormsg="Lower bound has not been specified use LOWER";
     137             :   }
     138          58 :   found_r=Tools::parse(data,"UPPER",highb);
     139          58 :   if( !found_r ) {
     140             :     errormsg="Upper bound has not been specified use UPPER";
     141             :   }
     142          58 :   if( lowb>=highb ) {
     143             :     errormsg="Lower bound is higher than upper bound";
     144             :   }
     145             : 
     146          58 :   smear=0.5;
     147          58 :   Tools::parse(data,"SMEAR",smear);
     148          58 :   width=smear*(highb-lowb);
     149          58 : }
     150             : 
     151     3744806 : void HistogramBead::set(const  double l, const double h, const double w) {
     152     3744806 :   lowb=l;
     153     3744806 :   highb=h;
     154     3744806 :   width=w;
     155     3744806 :   switch (type) {
     156      880958 :   case KernelType::gaussian : {
     157      880958 :     cutoff=std::sqrt(2.0*DP2CUTOFF);
     158             :   }
     159      880958 :   break;
     160     2863848 :   case KernelType::triangular : {
     161     2863848 :     cutoff=1.0;
     162             :   }
     163             :   }
     164     3744806 : }
     165             : 
     166          78 : HistogramBead::KernelType HistogramBead::getKernelType( const std::string& ktype ) {
     167          78 :   if(ktype=="gaussian") {
     168             :     return KernelType::gaussian;
     169           5 :   } else if(ktype=="triangular") {
     170             :     return KernelType::triangular;
     171             :   } else {
     172           0 :     plumed_merror("cannot understand kernel type " + ktype );
     173             :   }
     174             : }
     175             : 
     176           0 : void HistogramBead::setKernelType( const std::string& ktype ) {
     177           0 :   if(ktype=="gaussian") {
     178           0 :     type=KernelType::gaussian;
     179           0 :   } else if(ktype=="triangular") {
     180           0 :     type=KernelType::triangular;
     181             :   } else {
     182           0 :     plumed_merror("cannot understand kernel type " + ktype );
     183             :   }
     184           0 : }
     185             : 
     186           0 : void HistogramBead::setKernelType( KernelType ktype ) {
     187           0 :   type=ktype;
     188           0 : }
     189             : 
     190      397966 : double HistogramBead::calculate(const double x, double& df ) const {
     191             :   double res=0.0;
     192      397966 :   switch (type) {
     193      397966 :   case KernelType::gaussian : {
     194      397966 :     const double lowB = difference( x, lowb ) / ( std::sqrt(2.0) * width );
     195      397966 :     const double upperB = difference( x, highb ) / ( std::sqrt(2.0) * width );
     196      397966 :     df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( std::sqrt(PLMD::twopi)*width );
     197      397966 :     res = 0.5*( erf( upperB ) - erf( lowB ) );
     198             :   }
     199      397966 :   break;
     200           0 :   case KernelType::triangular : {
     201           0 :     const double lowB = ( difference( x, lowb ) / width );
     202           0 :     const double upperB = ( difference( x, highb ) / width );
     203           0 :     df=0.0;
     204           0 :     if( std::fabs(lowB)<1. ) {
     205           0 :       df = (1 - std::fabs(lowB)) / width;
     206             :     }
     207           0 :     if( std::fabs(upperB)<1. ) {
     208           0 :       df -= (1 - std::fabs(upperB)) / width;
     209             :     }
     210           0 :     if (upperB<=-1. || lowB >=1.) {
     211             :       break;
     212             :     }
     213           0 :     const double ia = (lowB>-1.0) ? lowB : -1.0;
     214           0 :     const double ib = (upperB<1.0) ? upperB : 1.0;
     215           0 :     res = (ib*(2.-std::fabs(ib))-ia*(2.-std::fabs(ia)))*0.5;
     216             :   }
     217             :   }
     218      397966 :   return res;
     219             : }
     220             : 
     221      425128 : double HistogramBead::calculateWithCutoff( double x, double& df ) const {
     222      425128 :   return calculateWithCutoff( x, lowb, highb, width, df );
     223             : }
     224             : 
     225      958728 : double HistogramBead::calculateWithCutoff(double x,
     226             :     double l,
     227             :     double u,
     228             :     double s,
     229             :     double& df ) const {
     230      958728 :   double lowB = difference( x, l ) / s;
     231      958728 :   double upperB = difference( x, u ) / s;
     232      958728 :   if( upperB<=-cutoff || lowB>=cutoff ) {
     233       87679 :     df=0.0;
     234       87679 :     return 0.0;
     235             :   }
     236             :   double f=0.0;
     237      871049 :   switch (type) {
     238      446863 :   case KernelType::gaussian : {
     239      446863 :     lowB /= std::sqrt(2.0);
     240      446863 :     upperB /= std::sqrt(2.0);
     241      446863 :     df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( std::sqrt(2*pi)*s );
     242      446863 :     f = 0.5*( erf( upperB ) - erf( lowB ) );
     243             :   }
     244      446863 :   break;
     245      424186 :   case KernelType::triangular : {
     246      424186 :     df=0;
     247      424186 :     if( std::fabs(lowB)<1. ) {
     248      108180 :       df = (1.0 - std::fabs(lowB)) / s;
     249             :     }
     250      424186 :     if( std::fabs(upperB)<1. ) {
     251      108180 :       df -= (1.0 - std::fabs(upperB)) / s;
     252             :     }
     253      424186 :     if (upperB<=-1. || lowB >=1.) {
     254             :       f=0.0;
     255             :     } else {
     256             :       double ia, ib;
     257      424186 :       if( lowB>-1.0 ) {
     258             :         ia=lowB;
     259             :       } else {
     260             :         ia=-1.0;
     261             :       }
     262      424186 :       if( upperB<1.0 ) {
     263             :         ib=upperB;
     264             :       } else {
     265             :         ib=1.0;
     266             :       }
     267      424186 :       f = (ib*(2.-std::fabs(ib))-ia*(2.-std::fabs(ia)))*0.5;
     268             :     }
     269             :   }
     270             :   }
     271             :   return f;
     272             : }
     273             : 
     274        9360 : double HistogramBead::lboundDerivative( const double x ) const {
     275        9360 :   switch (type) {
     276        9360 :   case KernelType::gaussian : {
     277        9360 :     double lowB = difference( x, lowb ) / ( std::sqrt(2.0) * width );
     278        9360 :     return exp( -lowB*lowB ) / ( std::sqrt(2*pi)*width );
     279             :   }
     280             :   break;
     281             :   case  KernelType::triangular : {
     282             :     assert(false);
     283             :     //TODO: something about this:
     284             :     // double lowB = fabs( difference( x, lowb ) / width );
     285             :     // if( lowB<1 ) {
     286             :     //   return ( 1 - (lowB) ) / 2*width;
     287             :     // } else {
     288             :     //   return 0;
     289             :     // }
     290             :   }
     291             :   }
     292             :   //warning::unreachable
     293             :   return 0.0;
     294             : }
     295             : 
     296        9360 : double HistogramBead::uboundDerivative( const double x ) const {
     297        9360 :   switch (type) {
     298        9360 :   case KernelType::gaussian : {
     299        9360 :     double upperB = difference( x, highb ) / ( std::sqrt(2.0) * width );
     300        9360 :     return exp( -upperB*upperB ) / ( std::sqrt(2*pi)*width );
     301             :   }
     302             :   break;
     303             :   case KernelType::triangular : {
     304             :     assert(false);
     305             :     //TODO: something about this:
     306             :     // double upperB = fabs( difference( x, highb ) / width );
     307             :     // if( upperB<1 ) {
     308             :     //   return ( 1 - (upperB) ) / 2*width;
     309             :     // } else {
     310             :     //   return 0;
     311             :     // }
     312             :   }
     313             :   }
     314             :   //warning::unreachable
     315             :   return 0.0;
     316             : }
     317             : 
     318             : inline
     319     2732108 : double HistogramBead::difference( double d1, const double d2 ) const {
     320     2732108 :   switch (periodicity) {
     321             :   case Periodicity::notperiodic :
     322             :     break;
     323     1067242 :   case Periodicity::periodic: {
     324             :     // Make sure the point is in the target range
     325     1067242 :     d1*=inv_max_minus_min;
     326     1067242 :     d1=Tools::pbc(d1);
     327     1067242 :     d1*=max_minus_min;
     328             :   }
     329             :   }
     330     2732108 :   return d2-d1;
     331             : }
     332             : 
     333             : }

Generated by: LCOV version 1.16