LCOV - code coverage report
Current view: top level - pamm - HBPammMatrix.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 107 114 93.9 %
Date: 2024-10-18 13:59:31 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-2020 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 "adjmat/AdjacencyMatrixBase.h"
      23             : #include "multicolvar/MultiColvarShortcuts.h"
      24             : #include "core/ActionRegister.h"
      25             : #include "core/ActionShortcut.h"
      26             : #include "core/PlumedMain.h"
      27             : #include "core/ActionSet.h"
      28             : #include "tools/IFile.h"
      29             : 
      30             : //+PLUMEDOC MATRIX HBPAMM_MATRIX
      31             : /*
      32             : Adjacency matrix in which two electronegative atoms are adjacent if they are hydrogen bonded
      33             : 
      34             : \par Examples
      35             : 
      36             : */
      37             : //+ENDPLUMEDOC
      38             : 
      39             : //+PLUMEDOC COLVAR HBPAMM_SA
      40             : /*
      41             : Calculate the number of hydrogen bonds each acceptor participates in using the HBPamm method
      42             : 
      43             : \par Examples
      44             : 
      45             : */
      46             : //+ENDPLUMEDOC
      47             : 
      48             : //+PLUMEDOC COLVAR HBPAMM_SD
      49             : /*
      50             : Calculate the number of hydrogen bonds each donor participates in using the HBPamm method
      51             : 
      52             : \par Examples
      53             : 
      54             : */
      55             : //+ENDPLUMEDOC
      56             : 
      57             : //+PLUMEDOC COLVAR HBPAMM_SH
      58             : /*
      59             : Calculate the number of hydrogen bonds each hydrogen participates in using the HBPamm method
      60             : 
      61             : \par Examples
      62             : 
      63             : */
      64             : //+ENDPLUMEDOC
      65             : 
      66             : namespace PLMD {
      67             : namespace pamm {
      68             : 
      69             : class HBPammMatrix : public adjmat::AdjacencyMatrixBase {
      70             : private:
      71             :   double regulariser;
      72             :   Tensor incoord_to_hbcoord;
      73             :   std::vector<double> weight;
      74             :   std::vector<Vector> centers;
      75             :   std::vector<Tensor> kmat;
      76             : public:
      77             : /// Create manual
      78             :   static void registerKeywords( Keywords& keys );
      79             : /// Constructor
      80             :   explicit HBPammMatrix(const ActionOptions&);
      81             : ///
      82             :   double calculateWeight( const Vector& pos1, const Vector& pos2, const unsigned& natoms, MultiValue& myvals ) const ;
      83             : };
      84             : 
      85             : PLUMED_REGISTER_ACTION(HBPammMatrix,"HBPAMM_MATRIX")
      86             : 
      87          31 : void HBPammMatrix::registerKeywords( Keywords& keys ) {
      88          31 :   adjmat::AdjacencyMatrixBase::registerKeywords( keys ); keys.use("GROUPC");
      89          62 :   keys.add("compulsory","ORDER","dah","the order in which the groups are specified in the input.  Can be dah (donor/acceptor/hydrogens), "
      90             :            "adh (acceptor/donor/hydrogens) or hda (hydrogens/donor/hydrogens");
      91          62 :   keys.add("compulsory","CLUSTERS","the name of the file that contains the definitions of all the kernels for PAMM");
      92          62 :   keys.add("compulsory","REGULARISE","0.001","don't allow the denominator to be smaller then this value");
      93          62 :   keys.add("compulsory","GAUSS_CUTOFF","6.25","the cutoff at which to stop evaluating the kernel function is set equal to sqrt(2*x)*(max(adc)+cov(adc))");
      94          93 :   keys.needsAction("PAMM"); keys.needsAction("ONES"); keys.needsAction("MATRIX_VECTOR_PRODUCT");
      95          31 : }
      96             : 
      97           6 : HBPammMatrix::HBPammMatrix(const ActionOptions& ao):
      98             :   Action(ao),
      99           6 :   AdjacencyMatrixBase(ao)
     100             : {
     101          18 :   double DP2CUTOFF; parse("GAUSS_CUTOFF",DP2CUTOFF); std::string sorder; parse("ORDER",sorder);
     102           6 :   if( sorder=="dah" ) {
     103           2 :     incoord_to_hbcoord(0,0)=1; incoord_to_hbcoord(0,1)=-1; incoord_to_hbcoord(0,2)=0;
     104           2 :     incoord_to_hbcoord(1,0)=1; incoord_to_hbcoord(1,1)=1; incoord_to_hbcoord(1,2)=0;
     105           2 :     incoord_to_hbcoord(2,0)=0; incoord_to_hbcoord(2,1)=0; incoord_to_hbcoord(2,2)=1;
     106           2 :     log.printf("  GROUPA is list of donor atoms \n");
     107           4 :   } else if( sorder=="adh" ) {
     108           2 :     incoord_to_hbcoord(0,0)=-1; incoord_to_hbcoord(0,1)=1; incoord_to_hbcoord(0,2)=0;
     109           2 :     incoord_to_hbcoord(1,0)=1; incoord_to_hbcoord(1,1)=1; incoord_to_hbcoord(1,2)=0;
     110           2 :     incoord_to_hbcoord(2,0)=0; incoord_to_hbcoord(2,1)=0; incoord_to_hbcoord(2,2)=1;
     111           2 :     log.printf("  GROUPA is list of acceptor atoms \n");
     112           2 :   } else if( sorder=="hda" ) {
     113           2 :     incoord_to_hbcoord(0,0)=-1; incoord_to_hbcoord(0,1)=0; incoord_to_hbcoord(0,2)=1;
     114           2 :     incoord_to_hbcoord(1,0)=1; incoord_to_hbcoord(1,1)=0; incoord_to_hbcoord(1,2)=1;
     115           2 :     incoord_to_hbcoord(2,0)=0; incoord_to_hbcoord(2,1)=1; incoord_to_hbcoord(2,2)=0;
     116           2 :     log.printf("  GROUPA is list of hydrogen atoms \n");
     117           0 :   } else plumed_error();
     118             :   // Read in the regularisation parameter
     119          12 :   parse("REGULARISE",regulariser);
     120             : 
     121             :   // Read in the kernels
     122             :   double sqr2pi = sqrt(2*pi); double sqrt2pi3 = sqr2pi*sqr2pi*sqr2pi;
     123          12 :   std::string fname; parse("CLUSTERS", fname); double sfmax=0, ww; Vector cent; Tensor covar;
     124           6 :   IFile ifile; ifile.open(fname); ifile.allowIgnoredFields();
     125             :   for(unsigned k=0;; ++k) {
     126         144 :     if( !ifile.scanField("height",ww) ) break;
     127         198 :     ifile.scanField("ptc",cent[0]); ifile.scanField("ssc",cent[1]); ifile.scanField("adc",cent[2]);
     128         198 :     ifile.scanField("sigma_ptc_ptc",covar[0][0]); ifile.scanField("sigma_ptc_ssc",covar[0][1]); ifile.scanField("sigma_ptc_adc",covar[0][2]);
     129         132 :     covar[1][0] = covar[0][1]; ifile.scanField("sigma_ssc_ssc",covar[1][1]); ifile.scanField("sigma_ssc_adc",covar[1][2]);
     130          66 :     covar[2][0] = covar[0][2]; covar[2][1] = covar[1][2]; ifile.scanField("sigma_adc_adc",covar[2][2]);
     131          66 :     weight.push_back( ww / ( sqrt2pi3 * sqrt(covar.determinant()) ) );
     132          66 :     centers.push_back( cent ); kmat.push_back( covar.inverse() );
     133             : 
     134          66 :     Vector eigval; Tensor eigvec; diagMatSym( covar, eigval, eigvec );
     135          66 :     unsigned ind_maxeval=0; double max_eval=eigval[0];
     136         198 :     for(unsigned i=1; i<3; ++i) {
     137         132 :       if( eigval[i]>max_eval ) { max_eval=eigval[i]; ind_maxeval=i; }
     138             :     }
     139          66 :     double rcut = cent[2] + sqrt(2.0*DP2CUTOFF)*fabs(sqrt(max_eval)*eigvec(2,ind_maxeval));
     140          66 :     if( rcut > sfmax ) sfmax = rcut;
     141          66 :     ifile.scanField();
     142          66 :   }
     143           6 :   ifile.close(); setLinkCellCutoff( false, sfmax );
     144          12 : }
     145             : 
     146       16286 : double HBPammMatrix::calculateWeight( const Vector& pos1, const Vector& pos2, const unsigned& natoms, MultiValue& myvals ) const {
     147       16286 :   Vector ddij, ddik, ddin, in_dists, hb_pamm_dists, hb_pamm_ders, real_ders;
     148       16286 :   ddin = pbcDistance( pos1, pos2 ); in_dists[2] = ddin.modulo();
     149       16286 :   if( in_dists[2]<epsilon ) return 0;
     150             : 
     151       16286 :   double tot=0; Vector disp, der, tmp_der;
     152     1572892 :   for(unsigned i=0; i<natoms; ++i) {
     153     1556606 :     ddij = getPosition(i,myvals); in_dists[0] = ddij.modulo();
     154     1556606 :     ddik = pbcDistance( pos2, getPosition(i,myvals) ); in_dists[1] = ddik.modulo();
     155     1556606 :     if( in_dists[1]<epsilon ) continue;
     156             : 
     157     1548396 :     hb_pamm_dists = matmul( incoord_to_hbcoord, in_dists );
     158     1548396 :     disp = hb_pamm_dists - centers[0]; der = matmul( kmat[0], disp );
     159     1548396 :     double vv = weight[0]*exp( -dotProduct( disp, der ) / 2. ); der *= -vv;
     160             : 
     161     6193584 :     double denom = regulariser + vv; for(unsigned j=0; j<3; ++j) hb_pamm_ders[j] = der[j];
     162    17032356 :     for(unsigned k=1; k<weight.size(); ++k) {
     163    15483960 :       disp = hb_pamm_dists - centers[k]; tmp_der = matmul( kmat[k], disp );
     164    15483960 :       double tval = weight[k]*exp( -dotProduct( disp, tmp_der ) / 2. );
     165    15483960 :       denom += tval; hb_pamm_ders += -tmp_der*tval;
     166             :     }
     167     1548396 :     double vf = vv / denom; tot += vf;
     168     1548396 :     if( fabs(vf)<epsilon ) continue;
     169             :     // Now get derivatives
     170        2241 :     real_ders = matmul( der / denom - vf*hb_pamm_ders/denom, incoord_to_hbcoord );
     171             : 
     172             :     // And add the derivatives to the underlying atoms
     173        2241 :     addAtomDerivatives( 0, -(real_ders[0]/in_dists[0])*ddij - (real_ders[2]/in_dists[2])*ddin, myvals );
     174        2241 :     addAtomDerivatives( 1, -(real_ders[1]/in_dists[1])*ddik + (real_ders[2]/in_dists[2])*ddin, myvals );
     175        2241 :     addThirdAtomDerivatives( i, (real_ders[0]/in_dists[0])*ddij + (real_ders[1]/in_dists[1])*ddik, myvals );
     176        4482 :     addBoxDerivatives( -(real_ders[0]/in_dists[0])*Tensor( ddij, ddij )
     177        4482 :                        -(real_ders[1]/in_dists[1])*Tensor( ddik, ddik )
     178        6723 :                        -(real_ders[2]/in_dists[2])*Tensor( ddin, ddin ), myvals );
     179             :   }
     180       16286 :   return tot;
     181             : }
     182             : 
     183             : class HBPammShortcut : public ActionShortcut {
     184             : public:
     185             :   static void registerKeywords( Keywords& keys );
     186             :   HBPammShortcut(const ActionOptions&);
     187             : };
     188             : 
     189             : PLUMED_REGISTER_ACTION(HBPammShortcut,"HBPAMM_SD")
     190             : PLUMED_REGISTER_ACTION(HBPammShortcut,"HBPAMM_SA")
     191             : PLUMED_REGISTER_ACTION(HBPammShortcut,"HBPAMM_SH")
     192             : 
     193          17 : void HBPammShortcut::registerKeywords( Keywords& keys ) {
     194          68 :   HBPammMatrix::registerKeywords( keys ); keys.remove("GROUP"); keys.remove("GROUPA"); keys.remove("GROUPB"); keys.remove("COMPONENTS");
     195          34 :   keys.add("optional","SITES","The list of atoms which can be part of a hydrogen bond.  When this command is used the set of atoms that can donate a "
     196             :            "hydrogen bond is assumed to be the same as the set of atoms that can form hydrogen bonds.  The atoms involved must be specified"
     197             :            "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions.  If you would just like to use "
     198             :            "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms.  Specifying your atomic positions using labels of "
     199             :            "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider "
     200             :            "variety of functions of the contact matrix as described in \\ref contactmatrix");
     201          34 :   keys.add("optional","DONORS","The list of atoms which can donate a hydrogen bond.  The atoms involved must be specified "
     202             :            "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions.  If you would just like to use "
     203             :            "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms.  Specifying your atomic positions using labels of "
     204             :            "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider "
     205             :            "variety of functions of the contact matrix as described in \\ref contactmatrix");
     206          34 :   keys.add("optional","ACCEPTORS","The list of atoms which can accept a hydrogen bond.  The atoms involved must be specified "
     207             :            "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions.  If you would just like to use "
     208             :            "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms.  Specifying your atomic positions using labels of "
     209             :            "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider "
     210             :            "variety of functions of the contact matrix as described in \\ref contactmatrix");
     211          34 :   keys.add("compulsory","HYDROGENS","The list of hydrogen atoms that can form part of a hydrogen bond.  The atoms must be specified using a comma separated list, "
     212             :            "an index range or by using a \\ref GROUP");
     213          17 :   multicolvar::MultiColvarShortcuts::shortcutKeywords( keys ); keys.needsAction("HBPAMM_MATRIX");
     214          34 :   keys.setValueDescription("vector","a vector specifiying the number of hydrogen bonds each of the specified atoms participates within");
     215          17 : }
     216             : 
     217           6 : HBPammShortcut::HBPammShortcut(const ActionOptions&ao):
     218             :   Action(ao),
     219           6 :   ActionShortcut(ao)
     220             : {
     221           6 :   std::string mwords = getShortcutLabel() + "_mat: HBPAMM_MATRIX";
     222           6 :   if( getName()=="HBPAMM_SD" ) {
     223           4 :     std::string site_str; parse("SITES",site_str);
     224           4 :     if( site_str.length()>0 ) mwords += " GROUP=" + site_str;
     225             :     else {
     226           0 :       std::string d_str; parse("DONORS",d_str); mwords += " GROUPA=" + d_str;
     227           0 :       std::string a_str; parse("ACCEPTORS",a_str); mwords += " GROUPB=" + a_str;
     228             :     }
     229           6 :     std::string h_str; parse("HYDROGENS",h_str); mwords += " GROUPC=" + h_str + " ORDER=dah";
     230           4 :   } else if( getName()=="HBPAMM_SA" ) {
     231           4 :     std::string site_str; parse("SITES",site_str);
     232           4 :     if( site_str.length()>0 ) mwords += " GROUP=" + site_str;
     233             :     else {
     234           0 :       std::string a_str; parse("ACCEPTORS",a_str); mwords += " GROUPA=" + a_str;
     235           0 :       std::string d_str; parse("DONORS",d_str); mwords += " GROUPB=" + d_str;
     236             :     }
     237           6 :     std::string h_str; parse("HYDROGENS",h_str); mwords += " GROUPC=" + h_str + " ORDER=adh";
     238           2 :   } else if( getName()=="HBPAMM_SH" ) {
     239           6 :     std::string h_str; parse("HYDROGENS",h_str); mwords += " GROUPA=" + h_str + " ORDER=hda";
     240           4 :     std::string site_str; parse("SITES",site_str);
     241           2 :     if( site_str.length()>0 ) {
     242           2 :       mwords += " GROUPB=" + site_str;
     243           4 :       mwords += " GROUPC=" + site_str;
     244             :     } else {
     245           0 :       std::string d_str; parse("DONORS",d_str); mwords += " GROUPB=" + d_str;
     246           0 :       std::string a_str; parse("ACCEPTORS",a_str); mwords += " GROUPC=" + a_str;
     247             :     }
     248             :   }
     249           6 :   std::map<std::string,std::string> keymap; multicolvar::MultiColvarShortcuts::readShortcutKeywords( keymap, this );
     250          12 :   readInputLine( mwords + " " + convertInputLineToString() );
     251           6 :   ActionWithValue* mb=plumed.getActionSet().selectWithLabel<ActionWithValue*>( getShortcutLabel() + "_mat");
     252           6 :   plumed_assert( mb ); std::string nsize; Tools::convert( (mb->copyOutput(getShortcutLabel() + "_mat"))->getShape()[1], nsize );
     253          12 :   readInputLine( getShortcutLabel() + "_ones: ONES SIZE=" + nsize );
     254          12 :   readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT ARG=" + getShortcutLabel() + "_mat," + getShortcutLabel() + "_ones");
     255          12 :   multicolvar::MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel(), "", keymap, this );
     256           6 : }
     257             : 
     258             : }
     259             : }

Generated by: LCOV version 1.16