LCOV - code coverage report
Current view: top level - colvar - DHEnergy.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 33 35 94.3 %
Date: 2020-11-18 11:20:57 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-2019 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 "CoordinationBase.h"
      23             : #include "tools/SwitchingFunction.h"
      24             : #include "ActionRegister.h"
      25             : #include "core/PlumedMain.h"
      26             : #include "core/Atoms.h"
      27             : 
      28             : #include <iostream>
      29             : 
      30             : #include <string>
      31             : 
      32             : using namespace std;
      33             : 
      34             : namespace PLMD {
      35             : namespace colvar {
      36             : 
      37             : //+PLUMEDOC COLVAR DHENERGY
      38             : /*
      39             : Calculate Debye-Huckel interaction energy among GROUPA and GROUPB.
      40             : 
      41             : This variable calculates the electrostatic interaction among GROUPA and GROUPB
      42             : using a Debye-Huckel approximation defined as
      43             : \f[
      44             : \frac{1}{4\pi\epsilon_r\epsilon_0}
      45             : \sum_{i\in A} \sum_{j \in B} q_i q_j
      46             : \frac{e^{-\kappa |{\bf r}_{ij}|}}{|{\bf r}_{ij}|}
      47             : \f]
      48             : 
      49             : This collective variable can be used to analyze or induce electrostatically driven reactions \cite do13jctc.
      50             : Notice that the value of the DHENERGY is returned in plumed units (see \ref UNITS).
      51             : 
      52             : If GROUPB is empty, it will sum the N*(N-1)/2 pairs in GROUPA. This avoids computing
      53             : twice permuted indexes (e.g. pair (i,j) and (j,i)) thus running at twice the speed.
      54             : 
      55             : Notice that if there are common atoms between GROUPA and GROUPB their interaction is discarded.
      56             : 
      57             : 
      58             : \par Examples
      59             : 
      60             : \plumedfile
      61             : # this is printing the electrostatic interaction between two groups of atoms
      62             : dh: DHENERGY GROUPA=1-10 GROUPB=11-20 EPSILON=80.0 I=0.1 TEMP=300.0
      63             : PRINT ARG=dh
      64             : \endplumedfile
      65             : 
      66             : */
      67             : //+ENDPLUMEDOC
      68             : 
      69          16 : class DHEnergy : public CoordinationBase {
      70             :   double k; // Inverse Debye screening length
      71             :   double constant;
      72             :   double epsilon;
      73             : 
      74             : public:
      75             :   explicit DHEnergy(const ActionOptions&);
      76             : // active methods:
      77             :   static void registerKeywords( Keywords& keys );
      78             :   virtual double pairing(double distance,double&dfunc,unsigned i,unsigned j)const;
      79             : };
      80             : 
      81        6460 : PLUMED_REGISTER_ACTION(DHEnergy,"DHENERGY")
      82             : 
      83           9 : void DHEnergy::registerKeywords( Keywords& keys ) {
      84           9 :   CoordinationBase::registerKeywords(keys);
      85          45 :   keys.add("compulsory","I","1.0","Ionic strength (M)");
      86          45 :   keys.add("compulsory","TEMP","300.0","Simulation temperature (K)");
      87          45 :   keys.add("compulsory","EPSILON","80.0","Dielectric constant of solvent");
      88           9 : }
      89             : 
      90             : /*
      91             : Global constants in SI unit used in this calculation:
      92             :       N_A = 6.0221412927 * 10^(23) mol^(-1) : Avogadro number
      93             :       q = 1.60217656535 * 10^(-19) C : proton charge
      94             :       e_0 = 8.854187817620 * 10^(-12) C^2/(N*m^2) : vacuum's dielectric constant
      95             :       k_B = 1.380648813 * 10^(-23) N*m/K : Boltzmann constant
      96             : In SI unit, Debye Huckel CV is defined as:
      97             :       DHen = \sum_i\sum_j (q_i*q_j*q^2*N_A)/(4*pi*eps*e_0) * exp(-k*|f_ij|)/(|f_ij|)
      98             :              + \sum_i\sum_j (q_i*q_j*q^2*N_A)/(4*pi*epp*e_0) * (1/|r_ij| - 1/|f_ij|)
      99             :            = (q^2*N_A)/(4*pi*e_0) * \sum_i\sum_j q_i*q_j * (exp(-k*|f_ij|)/(eps*|f_ij|) + 1/epp*(1/|r_ij| - 1/|f_ij|))
     100             : (in which |f_ij| = \sqrt(|r_ij|^2+\sigma_i*\sigma_j*exp(-|r_ij|^2/4*\sigma_i*\sigma_j)),
     101             :  \sigma_i and \sigma_j are the effective Born radius.)
     102             : For an efficient calculation, we group constants and variables into groups:
     103             :       constant = (q^2*N_A)/(4*pi*e_0)
     104             :       tmp = 1/eps*exp(-k*|f_ij|)/(|f_ij|) + 1/epp*(1/|r_ij| - 1/|f_ij|)
     105             : 
     106             : To speed up the loop calculation, constant can be modified as followed:
     107             :       constant= (q^2*N_A)/(4*pi*e_0*10^(-9))*10^(-3) (kJ/mol)
     108             :               = ((1.60217656535*10^(-19))^2*6.0221412927*10^(23)*10^(-3))/(4*3.14159265*8.854187817620*10^(-12)*10^(-9))
     109             :               = 138.935458111 (kJ/mol)
     110             : 
     111             : */
     112             : 
     113           8 : DHEnergy::DHEnergy(const ActionOptions&ao):
     114             :   Action(ao),
     115             :   CoordinationBase(ao),
     116             :   k(0.0),
     117           8 :   constant(0.0)
     118             : {
     119             :   double I,T;
     120          16 :   parse("I",I);
     121          16 :   parse("TEMP",T);
     122          16 :   parse("EPSILON",epsilon);
     123           8 :   checkRead();
     124           8 :   if( plumed.getAtoms().usingNaturalUnits() ) error("DHENERGY cannot be used for calculations performed with natural units");
     125           8 :   constant=138.935458111/atoms.getUnits().getEnergy()/atoms.getUnits().getLength()*atoms.getUnits().getCharge()*atoms.getUnits().getCharge();
     126           8 :   k=sqrt(I/(epsilon*T))*502.903741125*atoms.getUnits().getLength();
     127           8 :   checkRead();
     128           8 :   log<<"  with solvent dielectric constant "<<epsilon<<"\n";
     129           8 :   log<<"  at temperature "<<T<<" K\n";
     130           8 :   log<<"  at ionic strength "<<I<< "M\n";
     131           8 :   log<<"  these parameters correspond to a screening length of "<<(1.0/k)<<"\n";
     132          24 :   log<<"  Bibliography "<<plumed.cite("Do, Carloni, Varani and Bussi, J. Chem. Theory Comput. 9, 1720 (2013)")<<" \n";
     133           8 : }
     134             : 
     135         840 : double DHEnergy::pairing(double distance2,double&dfunc,unsigned i,unsigned j)const {
     136         840 :   double distance=std::sqrt(distance2);
     137        2520 :   if(getAbsoluteIndex(i)==getAbsoluteIndex(j)) {
     138           0 :     dfunc=0.0;
     139           0 :     return 0.0;
     140             :   }
     141         840 :   double invdistance=1.0/distance;
     142         840 :   double tmp=exp(-k*distance)*invdistance*constant*getCharge(i)*getCharge(j)/epsilon;
     143         840 :   double dtmp=-(k+invdistance)*tmp;
     144         840 :   dfunc=dtmp*invdistance;
     145         840 :   return tmp;
     146             : }
     147             : 
     148             : }
     149             : 
     150        4839 : }

Generated by: LCOV version 1.13