LCOV - code coverage report
Current view: top level - pamm - HBPammMatrix.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 169 182 92.9 %
Date: 2025-11-25 13:55:50 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 );
      89          31 :   keys.use("GROUPC");
      90          62 :   keys.add("compulsory","ORDER","dah","the order in which the groups are specified in the input.  Can be dah (donor/acceptor/hydrogens), "
      91             :            "adh (acceptor/donor/hydrogens) or hda (hydrogens/donor/hydrogens");
      92          62 :   keys.add("compulsory","CLUSTERS","the name of the file that contains the definitions of all the kernels for PAMM");
      93          62 :   keys.add("compulsory","REGULARISE","0.001","don't allow the denominator to be smaller then this value");
      94          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))");
      95          31 :   keys.needsAction("PAMM");
      96          31 :   keys.needsAction("ONES");
      97          31 :   keys.needsAction("MATRIX_VECTOR_PRODUCT");
      98          31 : }
      99             : 
     100           6 : HBPammMatrix::HBPammMatrix(const ActionOptions& ao):
     101             :   Action(ao),
     102           6 :   AdjacencyMatrixBase(ao) {
     103             :   double DP2CUTOFF;
     104          12 :   parse("GAUSS_CUTOFF",DP2CUTOFF);
     105             :   std::string sorder;
     106          12 :   parse("ORDER",sorder);
     107           6 :   if( sorder=="dah" ) {
     108           2 :     incoord_to_hbcoord(0,0)=1;
     109           2 :     incoord_to_hbcoord(0,1)=-1;
     110           2 :     incoord_to_hbcoord(0,2)=0;
     111           2 :     incoord_to_hbcoord(1,0)=1;
     112           2 :     incoord_to_hbcoord(1,1)=1;
     113           2 :     incoord_to_hbcoord(1,2)=0;
     114           2 :     incoord_to_hbcoord(2,0)=0;
     115           2 :     incoord_to_hbcoord(2,1)=0;
     116           2 :     incoord_to_hbcoord(2,2)=1;
     117           2 :     log.printf("  GROUPA is list of donor atoms \n");
     118           4 :   } else if( sorder=="adh" ) {
     119           2 :     incoord_to_hbcoord(0,0)=-1;
     120           2 :     incoord_to_hbcoord(0,1)=1;
     121           2 :     incoord_to_hbcoord(0,2)=0;
     122           2 :     incoord_to_hbcoord(1,0)=1;
     123           2 :     incoord_to_hbcoord(1,1)=1;
     124           2 :     incoord_to_hbcoord(1,2)=0;
     125           2 :     incoord_to_hbcoord(2,0)=0;
     126           2 :     incoord_to_hbcoord(2,1)=0;
     127           2 :     incoord_to_hbcoord(2,2)=1;
     128           2 :     log.printf("  GROUPA is list of acceptor atoms \n");
     129           2 :   } else if( sorder=="hda" ) {
     130           2 :     incoord_to_hbcoord(0,0)=-1;
     131           2 :     incoord_to_hbcoord(0,1)=0;
     132           2 :     incoord_to_hbcoord(0,2)=1;
     133           2 :     incoord_to_hbcoord(1,0)=1;
     134           2 :     incoord_to_hbcoord(1,1)=0;
     135           2 :     incoord_to_hbcoord(1,2)=1;
     136           2 :     incoord_to_hbcoord(2,0)=0;
     137           2 :     incoord_to_hbcoord(2,1)=1;
     138           2 :     incoord_to_hbcoord(2,2)=0;
     139           2 :     log.printf("  GROUPA is list of hydrogen atoms \n");
     140             :   } else {
     141           0 :     plumed_error();
     142             :   }
     143             :   // Read in the regularisation parameter
     144          12 :   parse("REGULARISE",regulariser);
     145             : 
     146             :   // Read in the kernels
     147             :   double sqr2pi = sqrt(2*pi);
     148             :   double sqrt2pi3 = sqr2pi*sqr2pi*sqr2pi;
     149             :   std::string fname;
     150           6 :   parse("CLUSTERS", fname);
     151           6 :   double sfmax=0, ww;
     152           6 :   Vector cent;
     153           6 :   Tensor covar;
     154           6 :   IFile ifile;
     155           6 :   ifile.open(fname);
     156           6 :   ifile.allowIgnoredFields();
     157             :   for(unsigned k=0;; ++k) {
     158         144 :     if( !ifile.scanField("height",ww) ) {
     159             :       break;
     160             :     }
     161          66 :     ifile.scanField("ptc",cent[0]);
     162          66 :     ifile.scanField("ssc",cent[1]);
     163          66 :     ifile.scanField("adc",cent[2]);
     164          66 :     ifile.scanField("sigma_ptc_ptc",covar[0][0]);
     165          66 :     ifile.scanField("sigma_ptc_ssc",covar[0][1]);
     166          66 :     ifile.scanField("sigma_ptc_adc",covar[0][2]);
     167          66 :     covar[1][0] = covar[0][1];
     168          66 :     ifile.scanField("sigma_ssc_ssc",covar[1][1]);
     169          66 :     ifile.scanField("sigma_ssc_adc",covar[1][2]);
     170          66 :     covar[2][0] = covar[0][2];
     171          66 :     covar[2][1] = covar[1][2];
     172          66 :     ifile.scanField("sigma_adc_adc",covar[2][2]);
     173          66 :     weight.push_back( ww / ( sqrt2pi3 * sqrt(covar.determinant()) ) );
     174          66 :     centers.push_back( cent );
     175          66 :     kmat.push_back( covar.inverse() );
     176             : 
     177          66 :     Vector eigval;
     178          66 :     Tensor eigvec;
     179          66 :     diagMatSym( covar, eigval, eigvec );
     180             :     unsigned ind_maxeval=0;
     181          66 :     double max_eval=eigval[0];
     182         198 :     for(unsigned i=1; i<3; ++i) {
     183         132 :       if( eigval[i]>max_eval ) {
     184             :         max_eval=eigval[i];
     185             :         ind_maxeval=i;
     186             :       }
     187             :     }
     188          66 :     double rcut = cent[2] + sqrt(2.0*DP2CUTOFF)*fabs(sqrt(max_eval)*eigvec(2,ind_maxeval));
     189          66 :     if( rcut > sfmax ) {
     190          24 :       sfmax = rcut;
     191             :     }
     192          66 :     ifile.scanField();
     193          66 :   }
     194           6 :   ifile.close();
     195           6 :   setLinkCellCutoff( false, sfmax );
     196          12 : }
     197             : 
     198       16286 : double HBPammMatrix::calculateWeight( const Vector& pos1, const Vector& pos2, const unsigned& natoms, MultiValue& myvals ) const {
     199       16286 :   Vector ddij, ddik, ddin, in_dists, hb_pamm_dists, hb_pamm_ders, real_ders;
     200       16286 :   ddin = pbcDistance( pos1, pos2 );
     201       16286 :   in_dists[2] = ddin.modulo();
     202       16286 :   if( in_dists[2]<epsilon ) {
     203             :     return 0;
     204             :   }
     205             : 
     206             :   double tot=0;
     207       16286 :   Vector disp, der, tmp_der;
     208     1572892 :   for(unsigned i=0; i<natoms; ++i) {
     209     1556606 :     ddij = getPosition(i,myvals);
     210     1556606 :     in_dists[0] = ddij.modulo();
     211     1556606 :     ddik = pbcDistance( pos2, getPosition(i,myvals) );
     212     1556606 :     in_dists[1] = ddik.modulo();
     213     1556606 :     if( in_dists[1]<epsilon ) {
     214        8210 :       continue;
     215             :     }
     216             : 
     217     1548396 :     hb_pamm_dists = matmul( incoord_to_hbcoord, in_dists );
     218     1548396 :     disp = hb_pamm_dists - centers[0];
     219     1548396 :     der = matmul( kmat[0], disp );
     220     1548396 :     double vv = weight[0]*exp( -dotProduct( disp, der ) / 2. );
     221     1548396 :     der *= -vv;
     222             : 
     223     1548396 :     double denom = regulariser + vv;
     224     6193584 :     for(unsigned j=0; j<3; ++j) {
     225     4645188 :       hb_pamm_ders[j] = der[j];
     226             :     }
     227    17032356 :     for(unsigned k=1; k<weight.size(); ++k) {
     228    15483960 :       disp = hb_pamm_dists - centers[k];
     229    15483960 :       tmp_der = matmul( kmat[k], disp );
     230    15483960 :       double tval = weight[k]*exp( -dotProduct( disp, tmp_der ) / 2. );
     231    15483960 :       denom += tval;
     232    15483960 :       hb_pamm_ders += -tmp_der*tval;
     233             :     }
     234     1548396 :     double vf = vv / denom;
     235     1548396 :     tot += vf;
     236     1548396 :     if( fabs(vf)<epsilon ) {
     237     1546155 :       continue;
     238             :     }
     239             :     // Now get derivatives
     240        2241 :     real_ders = matmul( der / denom - vf*hb_pamm_ders/denom, incoord_to_hbcoord );
     241             : 
     242             :     // And add the derivatives to the underlying atoms
     243        2241 :     addAtomDerivatives( 0, -(real_ders[0]/in_dists[0])*ddij - (real_ders[2]/in_dists[2])*ddin, myvals );
     244        2241 :     addAtomDerivatives( 1, -(real_ders[1]/in_dists[1])*ddik + (real_ders[2]/in_dists[2])*ddin, myvals );
     245        2241 :     addThirdAtomDerivatives( i, (real_ders[0]/in_dists[0])*ddij + (real_ders[1]/in_dists[1])*ddik, myvals );
     246        4482 :     addBoxDerivatives( -(real_ders[0]/in_dists[0])*Tensor( ddij, ddij )
     247        4482 :                        -(real_ders[1]/in_dists[1])*Tensor( ddik, ddik )
     248        6723 :                        -(real_ders[2]/in_dists[2])*Tensor( ddin, ddin ), myvals );
     249             :   }
     250       16286 :   return tot;
     251             : }
     252             : 
     253             : class HBPammShortcut : public ActionShortcut {
     254             : public:
     255             :   static void registerKeywords( Keywords& keys );
     256             :   HBPammShortcut(const ActionOptions&);
     257             : };
     258             : 
     259             : PLUMED_REGISTER_ACTION(HBPammShortcut,"HBPAMM_SD")
     260             : PLUMED_REGISTER_ACTION(HBPammShortcut,"HBPAMM_SA")
     261             : PLUMED_REGISTER_ACTION(HBPammShortcut,"HBPAMM_SH")
     262             : 
     263          17 : void HBPammShortcut::registerKeywords( Keywords& keys ) {
     264          17 :   HBPammMatrix::registerKeywords( keys );
     265          17 :   keys.remove("GROUP");
     266          17 :   keys.remove("GROUPA");
     267          17 :   keys.remove("GROUPB");
     268          17 :   keys.remove("COMPONENTS");
     269          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 "
     270             :            "hydrogen bond is assumed to be the same as the set of atoms that can form hydrogen bonds.  The atoms involved must be specified"
     271             :            "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions.  If you would just like to use "
     272             :            "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms.  Specifying your atomic positions using labels of "
     273             :            "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider "
     274             :            "variety of functions of the contact matrix as described in \\ref contactmatrix");
     275          34 :   keys.add("optional","DONORS","The list of atoms which can donate a hydrogen bond.  The atoms involved must be specified "
     276             :            "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions.  If you would just like to use "
     277             :            "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms.  Specifying your atomic positions using labels of "
     278             :            "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider "
     279             :            "variety of functions of the contact matrix as described in \\ref contactmatrix");
     280          34 :   keys.add("optional","ACCEPTORS","The list of atoms which can accept a hydrogen bond.  The atoms involved must be specified "
     281             :            "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions.  If you would just like to use "
     282             :            "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms.  Specifying your atomic positions using labels of "
     283             :            "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider "
     284             :            "variety of functions of the contact matrix as described in \\ref contactmatrix");
     285          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, "
     286             :            "an index range or by using a \\ref GROUP");
     287          17 :   multicolvar::MultiColvarShortcuts::shortcutKeywords( keys );
     288          17 :   keys.needsAction("HBPAMM_MATRIX");
     289          17 : }
     290             : 
     291           6 : HBPammShortcut::HBPammShortcut(const ActionOptions&ao):
     292             :   Action(ao),
     293           6 :   ActionShortcut(ao) {
     294           6 :   std::string mwords = getShortcutLabel() + "_mat: HBPAMM_MATRIX";
     295           6 :   if( getName()=="HBPAMM_SD" ) {
     296             :     std::string site_str;
     297           4 :     parse("SITES",site_str);
     298           2 :     if( site_str.length()>0 ) {
     299           4 :       mwords += " GROUP=" + site_str;
     300             :     } else {
     301             :       std::string d_str;
     302           0 :       parse("DONORS",d_str);
     303           0 :       mwords += " GROUPA=" + d_str;
     304             :       std::string a_str;
     305           0 :       parse("ACCEPTORS",a_str);
     306           0 :       mwords += " GROUPB=" + a_str;
     307             :     }
     308             :     std::string h_str;
     309           2 :     parse("HYDROGENS",h_str);
     310           4 :     mwords += " GROUPC=" + h_str + " ORDER=dah";
     311           4 :   } else if( getName()=="HBPAMM_SA" ) {
     312             :     std::string site_str;
     313           4 :     parse("SITES",site_str);
     314           2 :     if( site_str.length()>0 ) {
     315           4 :       mwords += " GROUP=" + site_str;
     316             :     } else {
     317             :       std::string a_str;
     318           0 :       parse("ACCEPTORS",a_str);
     319           0 :       mwords += " GROUPA=" + a_str;
     320             :       std::string d_str;
     321           0 :       parse("DONORS",d_str);
     322           0 :       mwords += " GROUPB=" + d_str;
     323             :     }
     324             :     std::string h_str;
     325           2 :     parse("HYDROGENS",h_str);
     326           4 :     mwords += " GROUPC=" + h_str + " ORDER=adh";
     327           2 :   } else if( getName()=="HBPAMM_SH" ) {
     328             :     std::string h_str;
     329           2 :     parse("HYDROGENS",h_str);
     330           4 :     mwords += " GROUPA=" + h_str + " ORDER=hda";
     331             :     std::string site_str;
     332           4 :     parse("SITES",site_str);
     333           2 :     if( site_str.length()>0 ) {
     334           2 :       mwords += " GROUPB=" + site_str;
     335           4 :       mwords += " GROUPC=" + site_str;
     336             :     } else {
     337             :       std::string d_str;
     338           0 :       parse("DONORS",d_str);
     339           0 :       mwords += " GROUPB=" + d_str;
     340             :       std::string a_str;
     341           0 :       parse("ACCEPTORS",a_str);
     342           0 :       mwords += " GROUPC=" + a_str;
     343             :     }
     344             :   }
     345             :   std::map<std::string,std::string> keymap;
     346           6 :   multicolvar::MultiColvarShortcuts::readShortcutKeywords( keymap, this );
     347          12 :   readInputLine( mwords + " " + convertInputLineToString() );
     348           6 :   ActionWithValue* mb=plumed.getActionSet().selectWithLabel<ActionWithValue*>( getShortcutLabel() + "_mat");
     349           6 :   plumed_assert( mb );
     350             :   std::string nsize;
     351           6 :   Tools::convert( (mb->copyOutput(getShortcutLabel() + "_mat"))->getShape()[1], nsize );
     352          12 :   readInputLine( getShortcutLabel() + "_ones: ONES SIZE=" + nsize );
     353          12 :   readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT ARG=" + getShortcutLabel() + "_mat," + getShortcutLabel() + "_ones");
     354          12 :   multicolvar::MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel(), "", keymap, this );
     355           6 : }
     356             : 
     357             : }
     358             : }

Generated by: LCOV version 1.16