LCOV - code coverage report
Current view: top level - tools - SwitchingFunction.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 212 275 77.1 %
Date: 2018-12-19 07:49:13 Functions: 14 17 82.4 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2018 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 "SwitchingFunction.h"
      23             : #include "Tools.h"
      24             : #include "Keywords.h"
      25             : #include "OpenMP.h"
      26             : #include <vector>
      27             : #include <limits>
      28             : 
      29             : #ifdef __PLUMED_HAS_MATHEVAL
      30             : #include <matheval.h>
      31             : #endif
      32             : 
      33             : using namespace std;
      34             : namespace PLMD {
      35             : 
      36             : //+PLUMEDOC INTERNAL switchingfunction
      37             : /*
      38             : Functions that measure whether values are less than a certain quantity.
      39             : 
      40             : Switching functions \f$s(r)\f$ take a minimum of one input parameter \f$d_0\f$.
      41             : For \f$r \le d_0 \quad s(r)=1.0\f$ while for \f$r > d_0\f$ the function decays smoothly to 0.
      42             : The various switching functions available in plumed differ in terms of how this decay is performed.
      43             : 
      44             : Where there is an accepted convention in the literature (e.g. \ref COORDINATION) on the form of the
      45             : switching function we use the convention as the default.  However, the flexibility to use different
      46             : switching functions is always present generally through a single keyword. This keyword generally
      47             : takes an input with the following form:
      48             : 
      49             : \verbatim
      50             : KEYWORD={TYPE <list of parameters>}
      51             : \endverbatim
      52             : 
      53             : The following table contains a list of the various switching functions that are available in plumed 2
      54             : together with an example input.
      55             : 
      56             : <table align=center frame=void width=95%% cellpadding=5%%>
      57             : <tr>
      58             : <td> TYPE </td> <td> FUNCTION </td> <td> EXAMPLE INPUT </td> <td> DEFAULT PARAMETERS </td>
      59             : </tr> <tr> <td>RATIONAL </td> <td>
      60             : \f$
      61             : s(r)=\frac{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{n} }{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{m} }
      62             : \f$
      63             : </td> <td>
      64             : {RATIONAL R_0=\f$r_0\f$ D_0=\f$d_0\f$ NN=\f$n\f$ MM=\f$m\f$}
      65             : </td> <td> \f$d_0=0.0\f$, \f$n=6\f$, \f$m=2n\f$ </td>
      66             : </tr> <tr>
      67             : <td> EXP </td> <td>
      68             : \f$
      69             : s(r)=\exp\left(-\frac{ r - d_0 }{ r_0 }\right)
      70             : \f$
      71             : </td> <td>
      72             : {EXP  R_0=\f$r_0\f$ D_0=\f$d_0\f$}
      73             : </td> <td> \f$d_0=0.0\f$ </td>
      74             : </tr> <tr>
      75             : <td> GAUSSIAN </td> <td>
      76             : \f$
      77             : s(r)=\exp\left(-\frac{ (r - d_0)^2 }{ 2r_0^2 }\right)
      78             : \f$
      79             : </td> <td>
      80             : {GAUSSIAN R_0=\f$r_0\f$ D_0=\f$d_0\f$}
      81             : </td> <td> \f$d_0=0.0\f$ </td>
      82             : </tr> <tr>
      83             : <td> SMAP </td> <td>
      84             : \f$
      85             : s(r) = \left[ 1 + ( 2^{a/b} -1 )\left( \frac{r-d_0}{r_0} \right)^a \right]^{-b/a}
      86             : \f$
      87             : </td> <td>
      88             : {SMAP R_0=\f$r_0\f$ D_0=\f$d_0\f$ A=\f$a\f$ B=\f$b\f$}
      89             : </td> <td> \f$d_0=0.0\f$ </td>
      90             : </tr> <tr>
      91             : <td> Q </td> <td>
      92             : \f$
      93             : s(r) = \frac{1}{1 + \exp(\beta(r_{ij} - \lambda r_{ij}^0))}
      94             : \f$
      95             : </td> <td>
      96             : {Q REF=\f$r_{ij}^0\f$ BETA=\f$\beta\f$ LAMBDA=\f$\lambda\f$ }
      97             : </td> <td> \f$\lambda=1.8\f$,  \f$\beta=50 nm^-1\f$ (all-atom)<br/>\f$\lambda=1.5\f$,  \f$\beta=50 nm^-1\f$ (coarse-grained)  </td>
      98             : </tr> <tr>
      99             : <td> CUBIC </td> <td>
     100             : \f$
     101             : s(r) = (y-1)^2(1+2y) \qquad \textrm{where} \quad y = \frac{r - r_1}{r_0-r_1}
     102             : \f$
     103             : </td> <td>
     104             : {CUBIC D_0=\f$r_1\f$ D_MAX=\f$r_0\f$}
     105             : </td> <td> </td>
     106             : </tr> <tr>
     107             : <td> TANH </td> <td>
     108             : \f$
     109             : s(r) = 1 - \tanh\left( \frac{ r - d_0 }{ r_0 } \right)
     110             : \f$
     111             : </td> <td>
     112             : {TANH R_0=\f$r_0\f$ D_0=\f$d_0\f$}
     113             : </td> <td> </td>
     114             : </tr> <tr>
     115             : <td> MATHEVAL </td> <td>
     116             : \f$
     117             : s(r) = FUNC
     118             : \f$
     119             : </td> <td>
     120             : {MATHEVAL FUNC=1/(1+x^6) R_0=\f$r_0\f$ D_0=\f$d_0\f$}
     121             : </td> <td> </td>
     122             : </tr>
     123             : </table>
     124             : 
     125             : \attention
     126             : Similarly to the \ref MATHEVAL function, the MATHEVAL switching function
     127             : only works if libmatheval is installed on the system and
     128             : PLUMED has been linked to it
     129             : Also notice that using MATHEVAL is much slower than using e.g. RATIONAL.
     130             : Thus, the MATHEVAL switching function is useful to perform quick
     131             : tests on switching functions with arbitrary form before proceeding to their
     132             : implementation in C++.
     133             : 
     134             : For all the switching functions in the above table one can also specify a further (optional) parameter using the parameter
     135             : keyword D_MAX to assert that for \f$r>d_{\textrm{max}}\f$ the switching function can be assumed equal to zero.
     136             : In this case the function is brought smoothly to zero by stretching and shifting it.
     137             : \verbatim
     138             : KEYWORD={RATIONAL R_0=1 D_MAX=3}
     139             : \endverbatim
     140             : the resulting switching function will be
     141             : \f$
     142             : s(r) = \frac{s'(r)-s'(d_{max})}{s'(0)-s'(d_{max})}
     143             : \f$
     144             : where
     145             : \f$
     146             : s'(r)=\frac{1-r^6}{1-r^{12}}
     147             : \f$
     148             : Since PLUMED 2.2 this is the default. The old behavior (no stretching) can be obtained with the
     149             : NOSTRETCH flag. The NOSTRETCH keyword is only provided for backward compatibility and might be
     150             : removed in the future. Similarly, the STRETCH keyword is still allowed but has no effect.
     151             : 
     152             : Notice that switching functions defined with the simplified syntax are never stretched
     153             : for backward compatibility. This might change in the future.
     154             : 
     155             : */
     156             : //+ENDPLUMEDOC
     157             : 
     158          82 : void SwitchingFunction::registerKeywords( Keywords& keys ) {
     159          82 :   keys.add("compulsory","R_0","the value of R_0 in the switching function");
     160          82 :   keys.add("compulsory","D_0","0.0","the value of D_0 in the switching function");
     161          82 :   keys.add("optional","D_MAX","the value at which the switching function can be assumed equal to zero");
     162          82 :   keys.add("compulsory","NN","6","the value of n in the switching function (only needed for TYPE=RATIONAL)");
     163          82 :   keys.add("compulsory","MM","0","the value of m in the switching function (only needed for TYPE=RATIONAL); 0 implies 2*NN");
     164          82 :   keys.add("compulsory","A","the value of a in the switching funciton (only needed for TYPE=SMAP)");
     165          82 :   keys.add("compulsory","B","the value of b in the switching funciton (only needed for TYPE=SMAP)");
     166          82 : }
     167             : 
     168         590 : void SwitchingFunction::set(const std::string & definition,std::string& errormsg) {
     169         590 :   vector<string> data=Tools::getWords(definition);
     170         590 :   if( data.size()<1 ) errormsg="missing all input for switching function";
     171        1180 :   string name=data[0];
     172         590 :   data.erase(data.begin());
     173         590 :   invr0=0.0;
     174         590 :   invr0_2=0.0;
     175         590 :   d0=0.0;
     176         590 :   dmax=std::numeric_limits<double>::max();
     177         590 :   dmax_2=std::numeric_limits<double>::max();
     178         590 :   stretch=1.0;
     179         590 :   shift=0.0;
     180         590 :   init=true;
     181             : 
     182             :   bool present;
     183             : 
     184         590 :   present=Tools::findKeyword(data,"D_0");
     185         590 :   if(present && !Tools::parse(data,"D_0",d0)) errormsg="could not parse D_0";
     186             : 
     187         590 :   present=Tools::findKeyword(data,"D_MAX");
     188         590 :   if(present && !Tools::parse(data,"D_MAX",dmax)) errormsg="could not parse D_MAX";
     189         590 :   if(dmax<std::sqrt(std::numeric_limits<double>::max())) dmax_2=dmax*dmax;
     190         590 :   bool dostretch=false;
     191         590 :   Tools::parseFlag(data,"STRETCH",dostretch); // this is ignored now
     192         590 :   dostretch=true;
     193         590 :   bool dontstretch=false;
     194         590 :   Tools::parseFlag(data,"NOSTRETCH",dontstretch); // this is ignored now
     195         590 :   if(dontstretch) dostretch=false;
     196             :   double r0;
     197         590 :   if(name=="CUBIC") {
     198          17 :     r0 = dmax - d0;
     199             :   } else {
     200         573 :     bool found_r0=Tools::parse(data,"R_0",r0);
     201         573 :     if(!found_r0) errormsg="R_0 is required";
     202             :   }
     203         590 :   invr0=1.0/r0;
     204         590 :   invr0_2=invr0*invr0;
     205             : 
     206         590 :   if(name=="RATIONAL") {
     207         201 :     type=rational;
     208         201 :     nn=6;
     209         201 :     mm=0;
     210         201 :     present=Tools::findKeyword(data,"NN");
     211         201 :     if(present && !Tools::parse(data,"NN",nn)) errormsg="could not parse NN";
     212         201 :     present=Tools::findKeyword(data,"MM");
     213         201 :     if(present && !Tools::parse(data,"MM",mm)) errormsg="could not parse MM";
     214         201 :     if(mm==0) mm=2*nn;
     215         389 :   } else if(name=="SMAP") {
     216           0 :     type=smap;
     217           0 :     present=Tools::findKeyword(data,"A");
     218           0 :     if(present && !Tools::parse(data,"A",a)) errormsg="could not parse A";
     219           0 :     present=Tools::findKeyword(data,"B");
     220           0 :     if(present && !Tools::parse(data,"B",b)) errormsg="could not parse B";
     221           0 :     c=pow(2., static_cast<double>(a)/static_cast<double>(b) ) - 1;
     222           0 :     d = -static_cast<double>(b) / static_cast<double>(a);
     223             :   }
     224         389 :   else if(name=="Q") {
     225         278 :     type=nativeq;
     226         278 :     beta = 50.0;  // nm-1
     227         278 :     lambda = 1.8; // unitless
     228         278 :     present=Tools::findKeyword(data,"BETA");
     229         278 :     if(present && !Tools::parse(data, "BETA", beta)) errormsg="could not parse BETA";
     230         278 :     present=Tools::findKeyword(data,"LAMBDA");
     231         278 :     if(present && !Tools::parse(data, "LAMBDA", lambda)) errormsg="could not parse LAMBDA";
     232         278 :     bool found_ref=Tools::parse(data,"REF",ref); // nm
     233         278 :     if(!found_ref) errormsg="REF (reference disatance) is required for native Q";
     234             : 
     235             :   }
     236         111 :   else if(name=="EXP") type=exponential;
     237          57 :   else if(name=="GAUSSIAN") type=gaussian;
     238          22 :   else if(name=="CUBIC") type=cubic;
     239           5 :   else if(name=="TANH") type=tanh;
     240             : #ifdef __PLUMED_HAS_MATHEVAL
     241           3 :   else if(name=="MATHEVAL") {
     242           3 :     type=matheval;
     243           3 :     std::string func;
     244           3 :     Tools::parse(data,"FUNC",func);
     245           3 :     const unsigned nt=OpenMP::getNumThreads();
     246           3 :     plumed_assert(nt>0);
     247           3 :     evaluator.resize(nt);
     248           9 :     for(unsigned i=0; i<nt; i++) {
     249           6 :       evaluator[i]=evaluator_create(const_cast<char*>(func.c_str()));
     250             :     }
     251             :     char **check_names;
     252             :     int    check_count;
     253           3 :     evaluator_get_variables(evaluator[0],&check_names,&check_count);
     254           3 :     if(check_count!=1) {
     255           0 :       errormsg="wrong number of arguments in MATHEVAL switching function";
     256           0 :       return;
     257             :     }
     258           3 :     if(std::string(check_names[0])!="x") {
     259           0 :       errormsg ="argument should be named 'x'";
     260           0 :       return;
     261             :     }
     262           3 :     evaluator_deriv.resize(nt);
     263           9 :     for(unsigned i=0; i<nt; i++) {
     264           6 :       evaluator_deriv[i]=evaluator_derivative(evaluator[i],const_cast<char*>("x"));
     265           3 :     }
     266             :   }
     267             : #endif
     268           0 :   else errormsg="cannot understand switching function type '"+name+"'";
     269         590 :   if( !data.empty() ) {
     270           0 :     errormsg="found the following rogue keywords in switching function input : ";
     271           0 :     for(unsigned i=0; i<data.size(); ++i) errormsg = errormsg + data[i] + " ";
     272             :   }
     273             : 
     274         590 :   if(dostretch && dmax!=std::numeric_limits<double>::max()) {
     275             :     double dummy;
     276          52 :     double s0=calculate(0.0,dummy);
     277          52 :     double sd=calculate(dmax,dummy);
     278          52 :     stretch=1.0/(s0-sd);
     279          52 :     shift=-sd*stretch;
     280         590 :   }
     281             : }
     282             : 
     283         620 : std::string SwitchingFunction::description() const {
     284         620 :   std::ostringstream ostr;
     285         620 :   ostr<<1./invr0<<".  Using ";
     286         620 :   if(type==rational) {
     287         235 :     ostr<<"rational";
     288         385 :   } else if(type==exponential) {
     289          50 :     ostr<<"exponential";
     290         335 :   } else if(type==nativeq) {
     291         278 :     ostr<<"nativeq";
     292          57 :   } else if(type==gaussian) {
     293          35 :     ostr<<"gaussian";
     294          22 :   } else if(type==smap) {
     295           0 :     ostr<<"smap";
     296          22 :   } else if(type==cubic) {
     297          17 :     ostr<<"cubic";
     298           5 :   } else if(type==tanh) {
     299           2 :     ostr<<"tanh";
     300             : #ifdef __PLUMED_HAS_MATHEVAL
     301           3 :   } else if(type==matheval) {
     302           3 :     ostr<<"matheval";
     303             : #endif
     304             :   } else {
     305           0 :     plumed_merror("Unknown switching function type");
     306             :   }
     307         620 :   ostr<<" swiching function with parameters d0="<<d0;
     308         620 :   if(type==rational) {
     309         235 :     ostr<<" nn="<<nn<<" mm="<<mm;
     310         385 :   } else if(type==nativeq) {
     311         278 :     ostr<<" beta="<<beta<<" lambda="<<lambda<<" ref="<<ref;
     312         107 :   } else if(type==smap) {
     313           0 :     ostr<<" a="<<a<<" b="<<b;
     314         107 :   } else if(type==cubic) {
     315          17 :     ostr<<" dmax="<<dmax;
     316             : #ifdef __PLUMED_HAS_MATHEVAL
     317          90 :   } else if(type==matheval) {
     318           3 :     ostr<<" func="<<evaluator_get_string(evaluator[0]);
     319             : #endif
     320             : 
     321             :   }
     322         620 :   return ostr.str();
     323             : }
     324             : 
     325    10996735 : double SwitchingFunction::do_rational(double rdist,double&dfunc,int nn,int mm)const {
     326             :   double result;
     327    10996735 :   if(2*nn==mm) {
     328             : // if 2*N==M, then (1.0-rdist^N)/(1.0-rdist^M) = 1.0/(1.0+rdist^N)
     329    10957641 :     double rNdist=Tools::fastpow(rdist,nn-1);
     330    10955969 :     double iden=1.0/(1+rNdist*rdist);
     331    10955969 :     dfunc = -nn*rNdist*iden*iden;
     332    10955969 :     result = iden;
     333             :   } else {
     334       39094 :     if(rdist>(1.-100.0*epsilon) && rdist<(1+100.0*epsilon)) {
     335           0 :       result=nn/mm;
     336           0 :       dfunc=0.5*nn*(nn-mm)/mm;
     337             :     } else {
     338       39094 :       double rNdist=Tools::fastpow(rdist,nn-1);
     339       39116 :       double rMdist=Tools::fastpow(rdist,mm-1);
     340       39115 :       double num = 1.-rNdist*rdist;
     341       39115 :       double iden = 1./(1.-rMdist*rdist);
     342       39115 :       double func = num*iden;
     343       39115 :       result = func;
     344       39115 :       dfunc = ((-nn*rNdist*iden)+(func*(iden*mm)*rMdist));
     345             :     }
     346             :   }
     347    10995084 :   return result;
     348             : }
     349             : 
     350    10903863 : double SwitchingFunction::calculateSqr(double distance2,double&dfunc)const {
     351    10903863 :   if(type==rational && nn%2==0 && mm%2==0 && d0==0.0) {
     352     7852389 :     if(distance2>dmax_2) {
     353       91945 :       dfunc=0.0;
     354       91945 :       return 0.0;
     355             :     }
     356     7760444 :     const double rdist_2 = distance2*invr0_2;
     357     7760444 :     double result=do_rational(rdist_2,dfunc,nn/2,mm/2);
     358             : // chain rule:
     359     7760581 :     dfunc*=2*invr0_2;
     360             : // stretch:
     361     7760581 :     result=result*stretch+shift;
     362     7760581 :     dfunc*=stretch;
     363     7760581 :     return result;
     364             :   } else {
     365     3051474 :     double distance=std::sqrt(distance2);
     366     3051474 :     return calculate(distance,dfunc);
     367             :   }
     368             : }
     369             : 
     370     6605527 : double SwitchingFunction::calculate(double distance,double&dfunc)const {
     371     6605527 :   plumed_massert(init,"you are trying to use an unset SwitchingFunction");
     372     6605527 :   if(distance>dmax) {
     373       61113 :     dfunc=0.0;
     374       61113 :     return 0.0;
     375             :   }
     376     6544414 :   const double rdist = (distance-d0)*invr0;
     377             :   double result;
     378             : 
     379     6544414 :   if(rdist<=0.) {
     380      534918 :     result=1.;
     381      534918 :     dfunc=0.0;
     382             :   } else {
     383     6009496 :     if(type==smap) {
     384           0 :       double sx=c*pow( rdist, a );
     385           0 :       result=pow( 1.0 + sx, d );
     386           0 :       dfunc=-b*sx/rdist*result/(1.0+sx);
     387     6009496 :     } else if(type==rational) {
     388     3236316 :       result=do_rational(rdist,dfunc,nn,mm);
     389     2773180 :     } else if(type==exponential) {
     390     1210199 :       result=exp(-rdist);
     391     1210199 :       dfunc=-result;
     392     1562981 :     } else if(type==nativeq) {
     393         278 :       double rdist2 = beta*(distance - lambda * ref);
     394         278 :       double exprdist=exp(rdist2);
     395         278 :       double exprmdist=1.0/exprdist;
     396         278 :       result=1./(1.+exprdist);
     397         278 :       dfunc=-1.0/(exprmdist+1.0)/(1.+exprdist);
     398     1562703 :     } else if(type==gaussian) {
     399      179898 :       result=exp(-0.5*rdist*rdist);
     400      179898 :       dfunc=-rdist*result;
     401     1382805 :     } else if(type==cubic) {
     402      126990 :       double tmp1=rdist-1, tmp2=(1+2*rdist);
     403      126990 :       result=tmp1*tmp1*tmp2;
     404      126990 :       dfunc=2*tmp1*tmp2 + 2*tmp1*tmp1;
     405     1255815 :     } else if(type==tanh) {
     406        7961 :       double tmp1=std::tanh(rdist);
     407        7961 :       result = 1.0 - tmp1;
     408        7961 :       dfunc=-(1-tmp1*tmp1);
     409             : #ifdef __PLUMED_HAS_MATHEVAL
     410     1247854 :     } else if(type==matheval) {
     411     1247854 :       const unsigned it=OpenMP::getThreadNum();
     412     1248071 :       result=evaluator_evaluate_x(evaluator[it],rdist);
     413     1248009 :       dfunc=evaluator_evaluate_x(evaluator_deriv[it],rdist);
     414             : #endif
     415           0 :     } else plumed_merror("Unknown switching function type");
     416             : // this is for the chain rule:
     417     6009799 :     dfunc*=invr0;
     418             : // this is because calculate() sets dfunc to the derivative divided times the distance.
     419             : // (I think this is misleading and I would like to modify it - GB)
     420     6009799 :     dfunc/=distance;
     421             :   }
     422             : 
     423     6544717 :   result=result*stretch+shift;
     424     6544717 :   dfunc*=stretch;
     425             : 
     426     6544717 :   return result;
     427             : }
     428             : 
     429         356 : SwitchingFunction::SwitchingFunction():
     430             :   init(false),
     431             :   type(rational),
     432             :   invr0(0.0),
     433             :   d0(0.0),
     434             :   dmax(0.0),
     435             :   nn(6),
     436             :   mm(0),
     437             :   a(0.0),
     438             :   b(0.0),
     439             :   c(0.0),
     440             :   d(0.0),
     441             :   lambda(0.0),
     442             :   beta(0.0),
     443             :   ref(0.0),
     444             :   invr0_2(0.0),
     445             :   dmax_2(0.0),
     446             :   stretch(1.0),
     447         356 :   shift(0.0)
     448             : {
     449         356 : }
     450             : 
     451     1216749 : SwitchingFunction::SwitchingFunction(const SwitchingFunction&sf):
     452             :   init(sf.init),
     453             :   type(sf.type),
     454             :   invr0(sf.invr0),
     455             :   d0(sf.d0),
     456             :   dmax(sf.dmax),
     457             :   nn(sf.nn),
     458             :   mm(sf.mm),
     459             :   a(sf.a),
     460             :   b(sf.b),
     461             :   c(sf.c),
     462             :   d(sf.d),
     463             :   lambda(sf.lambda),
     464             :   beta(sf.beta),
     465             :   ref(sf.ref),
     466             :   invr0_2(sf.invr0_2),
     467             :   dmax_2(sf.dmax_2),
     468             :   stretch(sf.stretch),
     469     1216749 :   shift(sf.shift)
     470             : {
     471             : #ifdef __PLUMED_HAS_MATHEVAL
     472     1216647 :   if(sf.evaluator.size()>0) {
     473           0 :     const unsigned nt=OpenMP::getNumThreads();
     474           0 :     plumed_assert(nt>0);
     475           0 :     evaluator.resize(nt);
     476           0 :     evaluator_deriv.resize(nt);
     477           0 :     for(unsigned i=0; i<nt; i++) {
     478           0 :       evaluator[i]=evaluator_create(evaluator_get_string(sf.evaluator[0]));
     479           0 :       evaluator_deriv[i]=evaluator_create(evaluator_get_string(sf.evaluator_deriv[0]));
     480             :     }
     481             :   }
     482             : #endif
     483     1216680 : }
     484             : 
     485           0 : SwitchingFunction & SwitchingFunction::operator=(const SwitchingFunction& sf) {
     486           0 :   if(&sf==this) return *this;
     487           0 :   init=sf.init;
     488           0 :   type=sf.type;
     489           0 :   invr0=sf.invr0;
     490           0 :   d0=sf.d0;
     491           0 :   dmax=sf.dmax;
     492           0 :   nn=sf.nn;
     493           0 :   mm=sf.mm;
     494           0 :   a=sf.a;
     495           0 :   b=sf.b;
     496           0 :   c=sf.c;
     497           0 :   d=sf.d;
     498           0 :   lambda=sf.lambda;
     499           0 :   beta=sf.beta;
     500           0 :   ref=sf.ref;
     501           0 :   invr0_2=sf.invr0_2;
     502           0 :   dmax_2=sf.dmax_2;
     503           0 :   stretch=sf.stretch;
     504           0 :   shift=sf.shift;
     505             : #ifdef __PLUMED_HAS_MATHEVAL
     506           0 :   if(sf.evaluator.size()>0) {
     507           0 :     const unsigned nt=OpenMP::getNumThreads();
     508           0 :     plumed_assert(nt>0);
     509           0 :     evaluator.resize(nt);
     510           0 :     evaluator_deriv.resize(nt);
     511           0 :     for(unsigned i=0; i<nt; i++) {
     512           0 :       evaluator[i]=evaluator_create(evaluator_get_string(sf.evaluator[0]));
     513           0 :       evaluator_deriv[i]=evaluator_create(evaluator_get_string(sf.evaluator_deriv[0]));
     514             :     }
     515             :   }
     516             : #endif
     517           0 :   return *this;
     518             : }
     519             : 
     520             : 
     521          38 : void SwitchingFunction::set(int nn,int mm,double r0,double d0) {
     522          38 :   init=true;
     523          38 :   type=rational;
     524          38 :   if(mm==0) mm=2*nn;
     525          38 :   this->nn=nn;
     526          38 :   this->mm=mm;
     527          38 :   this->invr0=1.0/r0;
     528          38 :   this->invr0_2=this->invr0*this->invr0;
     529          38 :   this->d0=d0;
     530          38 :   this->dmax=d0+r0*pow(0.00001,1./(nn-mm));
     531          38 :   this->dmax_2=this->dmax*this->dmax;
     532          38 : }
     533             : 
     534           0 : double SwitchingFunction::get_r0() const {
     535           0 :   return 1./invr0;
     536             : }
     537             : 
     538           0 : double SwitchingFunction::get_d0() const {
     539           0 :   return d0;
     540             : }
     541             : 
     542         276 : double SwitchingFunction::get_dmax() const {
     543         276 :   return dmax;
     544             : }
     545             : 
     546      116843 : double SwitchingFunction::get_dmax2() const {
     547      116843 :   return dmax_2;
     548             : }
     549             : 
     550     2434258 : SwitchingFunction::~SwitchingFunction() {
     551             : #ifdef __PLUMED_HAS_MATHEVAL
     552     1217110 :   for(unsigned i=0; i<evaluator.size(); i++) evaluator_destroy(evaluator[i]);
     553     1217118 :   for(unsigned i=0; i<evaluator_deriv.size(); i++) evaluator_destroy(evaluator_deriv[i]);
     554             : #endif
     555     1217087 : }
     556             : 
     557             : 
     558        2523 : }
     559             : 
     560             : 
     561             : 

Generated by: LCOV version 1.13