LCOV - code coverage report
Current view: top level - isdb - Jcoupling.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 186 199 93.5 %
Date: 2020-11-18 11:20:57 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-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 "MetainferenceBase.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "tools/Pbc.h"
      25             : #include "tools/Torsion.h"
      26             : 
      27             : using namespace std;
      28             : 
      29             : namespace PLMD {
      30             : namespace isdb {
      31             : 
      32             : //+PLUMEDOC ISDB_COLVAR JCOUPLING
      33             : /*
      34             : Calculates \f$^3J\f$ coupling constants for a dihedral angle.
      35             : 
      36             : The J-coupling between two atoms is given by the Karplus relation:
      37             : 
      38             : \f[
      39             : ^3J(\theta)=A\cos^2(\theta+\Delta\theta)+B\cos(\theta+\Delta\theta)+C
      40             : \f]
      41             : 
      42             : where \f$A\f$, \f$B\f$ and \f$C\f$ are the Karplus parameters and \f$\Delta\theta\f$ is an additional constant
      43             : added on to the dihedral angle \f$\theta\f$. The Karplus parameters are determined empirically and are dependent
      44             : on the type of J-coupling.
      45             : 
      46             : This collective variable computes the J-couplings for a set of atoms defining a dihedral angle. You can specify
      47             : the atoms involved using the \ref MOLINFO notation. You can also specify the experimental couplings using the
      48             : ADDCOUPLINGS flag and COUPLING keywords. These will be included in the output. You must choose the type of
      49             : coupling using the type keyword, you can also supply custom Karplus parameters using TYPE=CUSTOM and the A, B, C
      50             : and SHIFT keywords. You will need to make sure you are using the correct dihedral angle:
      51             : 
      52             : - Ha-N: \f$\psi\f$
      53             : - Ha-HN: \f$\phi\f$
      54             : - N-C\f$\gamma\f$: \f$\chi_1\f$
      55             : - CO-C\f$\gamma\f$: \f$\chi_1\f$
      56             : 
      57             : J-couplings can be used to calculate a Metainference score using the internal keyword DOSCORE and all the options
      58             : of \ref METAINFERENCE .
      59             : 
      60             : \par Examples
      61             : 
      62             : In the following example we calculate the Ha-N J-coupling from a set of atoms involved in
      63             : dihedral \f$\psi\f$ angles in the peptide backbone. We also add the experimental datapoints and compute
      64             : the correlation and other measures and finally print the results.
      65             : 
      66             : \plumedfile
      67             : 
      68             : MOLINFO MOLTYPE=protein STRUCTURE=peptide.pdb
      69             : WHOLEMOLECULES ENTITY0=1-111
      70             : 
      71             : JCOUPLING ...
      72             :     ADDCOUPLINGS
      73             :     TYPE=HAN
      74             :     ATOMS1=@psi-2 COUPLING1=-0.49
      75             :     ATOMS2=@psi-4 COUPLING2=-0.54
      76             :     ATOMS3=@psi-5 COUPLING3=-0.53
      77             :     ATOMS4=@psi-7 COUPLING4=-0.39
      78             :     ATOMS5=@psi-8 COUPLING5=-0.39
      79             :     LABEL=jhan
      80             : ... JCOUPLING
      81             : 
      82             : jhanst: STATS ARG=(jhan\.j_.*) PARARG=(jhan\.exp_.*)
      83             : 
      84             : PRINT ARG=jhanst.*,jhan.* FILE=COLVAR STRIDE=100
      85             : \endplumedfile
      86             : 
      87             : */
      88             : //+ENDPLUMEDOC
      89             : 
      90          12 : class JCoupling :
      91             :   public MetainferenceBase
      92             : {
      93             : private:
      94             :   bool pbc;
      95             :   enum { HAN, HAHN, CCG, NCG, CUSTOM };
      96             :   unsigned ncoupl_;
      97             :   double ka_;
      98             :   double kb_;
      99             :   double kc_;
     100             :   double kshift_;
     101             : 
     102             : public:
     103             :   static void registerKeywords(Keywords& keys);
     104             :   explicit JCoupling(const ActionOptions&);
     105             :   void calculate();
     106             :   void update();
     107             : };
     108             : 
     109        6458 : PLUMED_REGISTER_ACTION(JCoupling, "JCOUPLING")
     110             : 
     111           7 : void JCoupling::registerKeywords(Keywords& keys) {
     112           7 :   componentsAreNotOptional(keys);
     113           7 :   useCustomisableComponents(keys);
     114           7 :   MetainferenceBase::registerKeywords(keys);
     115          21 :   keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
     116          28 :   keys.add("numbered", "ATOMS", "the 4 atoms involved in each of the bonds for which you wish to calculate the J-coupling. "
     117             :            "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one J-coupling will be "
     118             :            "calculated for each ATOMS keyword you specify.");
     119          21 :   keys.reset_style("ATOMS", "atoms");
     120          21 :   keys.addFlag("ADDCOUPLINGS", false, "Set this flag if you want to have fixed components with the experimental values.");
     121          28 :   keys.add("compulsory", "TYPE", "Type of J-coupling to compute (HAN,HAHN,CCG,NCG,CUSTOM)");
     122          28 :   keys.add("optional", "A", "Karplus parameter A");
     123          28 :   keys.add("optional", "B", "Karplus parameter B");
     124          28 :   keys.add("optional", "C", "Karplus parameter C");
     125          28 :   keys.add("optional", "SHIFT", "Angle shift in radians");
     126          28 :   keys.add("numbered", "COUPLING", "Add an experimental value for each coupling");
     127          28 :   keys.addOutputComponent("j", "default", "the calculated J-coupling");
     128          28 :   keys.addOutputComponent("exp", "ADDCOUPLINGS", "the experimental J-coupling");
     129           7 : }
     130             : 
     131           6 : JCoupling::JCoupling(const ActionOptions&ao):
     132             :   PLUMED_METAINF_INIT(ao),
     133           6 :   pbc(true)
     134             : {
     135           6 :   bool nopbc = !pbc;
     136          12 :   parseFlag("NOPBC", nopbc);
     137           6 :   pbc =! nopbc;
     138             : 
     139             :   // Read in the atoms
     140             :   vector<AtomNumber> t, atoms;
     141          28 :   for (int i = 1; ; ++i) {
     142          68 :     parseAtomList("ATOMS", i, t );
     143          34 :     if (t.empty()) {
     144             :       break;
     145             :     }
     146             : 
     147          28 :     if (t.size() != 4) {
     148             :       std::string ss;
     149           0 :       Tools::convert(i, ss);
     150           0 :       error("ATOMS" + ss + " keyword has the wrong number of atoms");
     151             :     }
     152             : 
     153             :     // This makes the distance calculation easier later on (see Torsion implementation)
     154          28 :     atoms.push_back(t[0]);
     155          28 :     atoms.push_back(t[1]);
     156          28 :     atoms.push_back(t[1]);
     157          28 :     atoms.push_back(t[2]);
     158          28 :     atoms.push_back(t[2]);
     159          28 :     atoms.push_back(t[3]);
     160          28 :     t.resize(0);
     161          28 :   }
     162             : 
     163             :   // We now have 6 atoms per datapoint
     164           6 :   ncoupl_ = atoms.size()/6;
     165             : 
     166             :   // Parse J-Coupling type, this will determine the Karplus parameters
     167             :   unsigned jtype_ = CUSTOM;
     168             :   string string_type;
     169          12 :   parse("TYPE", string_type);
     170           6 :   if(string_type == "HAN") {
     171             :     jtype_ = HAN;
     172           5 :   } else if(string_type == "HAHN") {
     173             :     jtype_ = HAHN;
     174           2 :   } else if(string_type == "CCG") {
     175             :     jtype_ = CCG;
     176           1 :   } else if(string_type == "NCG") {
     177             :     jtype_ = NCG;
     178           0 :   } else if(string_type == "CUSTOM") {
     179             :     jtype_ = CUSTOM;
     180             :   } else {
     181           0 :     error("Unknown J-coupling type!");
     182             :   }
     183             : 
     184             :   // Optionally add an experimental value (like with RDCs)
     185             :   vector<double> coupl;
     186           6 :   bool addcoupling = false;
     187          12 :   parseFlag("ADDCOUPLINGS", addcoupling);
     188          12 :   if (addcoupling||getDoScore()) {
     189           1 :     coupl.resize(ncoupl_);
     190             :     unsigned ntarget = 0;
     191           8 :     for (unsigned i = 0; i < ncoupl_; ++i) {
     192          21 :       if (!parseNumbered("COUPLING", i+1, coupl[i])) {
     193             :         break;
     194             :       }
     195             :       ntarget++;
     196             :     }
     197           1 :     if (ntarget != ncoupl_) {
     198           0 :       error("found wrong number of COUPLING values");
     199             :     }
     200             :   }
     201             : 
     202             :   // For custom types we allow use of custom Karplus parameters
     203           6 :   if (jtype_ == CUSTOM) {
     204           0 :     parse("A", ka_);
     205           0 :     parse("B", kb_);
     206           0 :     parse("C", kc_);
     207           0 :     parse("SHIFT", kshift_);
     208             :   }
     209             : 
     210           6 :   log << "  Bibliography ";
     211             : 
     212             :   // Set Karplus parameters
     213           6 :   switch (jtype_) {
     214           1 :   case HAN:
     215           1 :     ka_ = -0.88;
     216           1 :     kb_ = -0.61;
     217           1 :     kc_ = -0.27;
     218           1 :     kshift_ = pi / 3.0;
     219           1 :     log.printf("J-coupling type is HAN, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_);
     220           3 :     log << plumed.cite("Wang A C, Bax A, J. Am. Chem. Soc. 117, 1810 (1995)");
     221           1 :     break;
     222           3 :   case HAHN:
     223           3 :     ka_ = 7.09;
     224           3 :     kb_ = -1.42;
     225           3 :     kc_ = 1.55;
     226           3 :     kshift_ = -pi / 3.0;
     227           3 :     log.printf("J-coupling type is HAHN, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_);
     228           9 :     log << plumed.cite("Hu J-S, Bax A, J. Am. Chem. Soc. 119, 6360 (1997)");
     229           3 :     break;
     230           1 :   case CCG:
     231           1 :     ka_ = 2.31;
     232           1 :     kb_ = -0.87;
     233           1 :     kc_ = 0.55;
     234           1 :     kshift_ = (2.0 * pi) / 3.0;
     235           1 :     log.printf("J-coupling type is CCG, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_);
     236           3 :     log << plumed.cite("Perez C, Löhr F, Rüterjans H, Schmidt J, J. Am. Chem. Soc. 123, 7081 (2001)");
     237           1 :     break;
     238           1 :   case NCG:
     239           1 :     ka_ = 1.29;
     240           1 :     kb_ = -0.49;
     241           1 :     kc_ = 0.37;
     242           1 :     kshift_ = 0.0;
     243           1 :     log.printf("J-coupling type is NCG, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_);
     244           3 :     log << plumed.cite("Perez C, Löhr F, Rüterjans H, Schmidt J, J. Am. Chem. Soc. 123, 7081 (2001)");
     245           1 :     break;
     246           0 :   case CUSTOM:
     247           0 :     log.printf("J-coupling type is custom, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_);
     248             :     break;
     249             :   }
     250          18 :   log<<plumed.cite("Bonomi, Camilloni, Bioinformatics, 33, 3999 (2017)");
     251           6 :   log<<"\n";
     252             : 
     253          34 :   for (unsigned i = 0; i < ncoupl_; ++i) {
     254          56 :     log.printf("  The %uth J-Coupling is calculated from atoms : %d %d %d %d.",
     255         112 :                i+1, atoms[6*i].serial(), atoms[6*i+1].serial(), atoms[6*i+3].serial(), atoms[6*i+5].serial());
     256          28 :     if (addcoupling) {
     257           0 :       log.printf(" Experimental J-Coupling is %f.", coupl[i]);
     258             :     }
     259          28 :     log.printf("\n");
     260             :   }
     261             : 
     262           6 :   if (pbc) {
     263           0 :     log.printf("  using periodic boundary conditions\n");
     264             :   } else {
     265           6 :     log.printf("  without periodic boundary conditions\n");
     266             :   }
     267             : 
     268           6 :   if(!getDoScore()) {
     269          47 :     for (unsigned i = 0; i < ncoupl_; i++) {
     270          21 :       std::string num; Tools::convert(i, num);
     271          42 :       addComponentWithDerivatives("j_" + num);
     272          42 :       componentIsNotPeriodic("j_" + num);
     273             :     }
     274             :   } else {
     275          15 :     for (unsigned i = 0; i < ncoupl_; i++) {
     276           7 :       std::string num; Tools::convert(i, num);
     277          14 :       addComponent("j_" + num);
     278          14 :       componentIsNotPeriodic("j_" + num);
     279             :     }
     280             :   }
     281             : 
     282          12 :   if (addcoupling||getDoScore()) {
     283          15 :     for (unsigned i = 0; i < ncoupl_; i++) {
     284           7 :       std::string num; Tools::convert(i, num);
     285          14 :       addComponent("exp_" + num);
     286          14 :       componentIsNotPeriodic("exp_" + num);
     287          14 :       Value* comp = getPntrToComponent("exp_" + num);
     288          14 :       comp->set(coupl[i]);
     289             :     }
     290             :   }
     291             : 
     292           6 :   requestAtoms(atoms);
     293           6 :   if(getDoScore()) {
     294           1 :     setParameters(coupl);
     295           1 :     Initialise(ncoupl_);
     296             :   }
     297           6 :   setDerivatives();
     298           6 :   checkRead();
     299           6 : }
     300             : 
     301          16 : void JCoupling::calculate()
     302             : {
     303          16 :   if (pbc) makeWhole();
     304          16 :   vector<Vector> deriv(ncoupl_*6);
     305          16 :   vector<double> j(ncoupl_,0.);
     306             : 
     307          48 :   #pragma omp parallel num_threads(OpenMP::getNumThreads())
     308             :   {
     309             :     #pragma omp for
     310             :     // Loop through atoms, with steps of 6 atoms (one iteration per datapoint)
     311          32 :     for (unsigned r=0; r<ncoupl_; r++) {
     312             :       // Index is the datapoint index
     313          98 :       unsigned a0 = 6*r;
     314             : 
     315             :       // 6 atoms -> 3 vectors
     316         294 :       Vector d0 = delta(getPosition(a0+1), getPosition(a0));
     317         294 :       Vector d1 = delta(getPosition(a0+3), getPosition(a0+2));
     318         294 :       Vector d2 = delta(getPosition(a0+5), getPosition(a0+4));
     319             : 
     320             :       // Calculate dihedral with 3 vectors, get the derivatives
     321          98 :       Vector dd0, dd1, dd2;
     322             :       PLMD::Torsion t;
     323          98 :       double torsion = t.compute(d0, d1, d2, dd0, dd1, dd2);
     324             : 
     325             :       // Calculate the Karplus relation and its derivative
     326          98 :       double theta = torsion + kshift_;
     327          98 :       double cos_theta = cos(theta);
     328          98 :       double sin_theta = sin(theta);
     329         196 :       j[r] = ka_*cos_theta*cos_theta + kb_*cos_theta + kc_;
     330          98 :       double derj = -2.*ka_*sin_theta*cos_theta - kb_*sin_theta;
     331             : 
     332          98 :       dd0 *= derj;
     333          98 :       dd1 *= derj;
     334          98 :       dd2 *= derj;
     335             : 
     336         182 :       if(getDoScore()) setCalcData(r, j[r]);
     337         196 :       deriv[a0] =  dd0;
     338         196 :       deriv[a0+1] = -dd0;
     339         196 :       deriv[a0+2] =  dd1;
     340         196 :       deriv[a0+3] = -dd1;
     341         196 :       deriv[a0+4] =  dd2;
     342         196 :       deriv[a0+5] = -dd2;
     343             :     }
     344             :   }
     345             : 
     346          16 :   if(getDoScore()) {
     347             :     /* Metainference */
     348           6 :     double score = getScore();
     349             :     setScore(score);
     350             : 
     351             :     /* calculate final derivatives */
     352           6 :     Tensor virial;
     353          12 :     Value* val=getPntrToComponent("score");
     354          90 :     for (unsigned r=0; r<ncoupl_; r++) {
     355          42 :       const unsigned a0 = 6*r;
     356          84 :       setAtomsDerivatives(val, a0, deriv[a0]*getMetaDer(r));
     357          84 :       setAtomsDerivatives(val, a0+1, deriv[a0+1]*getMetaDer(r));
     358          84 :       setAtomsDerivatives(val, a0+2, deriv[a0+2]*getMetaDer(r));
     359          84 :       setAtomsDerivatives(val, a0+3, deriv[a0+3]*getMetaDer(r));
     360          84 :       setAtomsDerivatives(val, a0+4, deriv[a0+4]*getMetaDer(r));
     361          84 :       setAtomsDerivatives(val, a0+5, deriv[a0+5]*getMetaDer(r));
     362          84 :       virial-=Tensor(getPosition(a0), deriv[a0]*getMetaDer(r));
     363          84 :       virial-=Tensor(getPosition(a0+1), deriv[a0+1]*getMetaDer(r));
     364          84 :       virial-=Tensor(getPosition(a0+2), deriv[a0+2]*getMetaDer(r));
     365          84 :       virial-=Tensor(getPosition(a0+3), deriv[a0+3]*getMetaDer(r));
     366          84 :       virial-=Tensor(getPosition(a0+4), deriv[a0+4]*getMetaDer(r));
     367          84 :       virial-=Tensor(getPosition(a0+5), deriv[a0+5]*getMetaDer(r));
     368             :     }
     369           6 :     setBoxDerivatives(val, virial);
     370             :   } else {
     371         122 :     for (unsigned r=0; r<ncoupl_; r++) {
     372          56 :       const unsigned a0 = 6*r;
     373          56 :       string num; Tools::convert(r,num);
     374         112 :       Value* val=getPntrToComponent("j_"+num);
     375         112 :       val->set(j[r]);
     376         112 :       setAtomsDerivatives(val, a0, deriv[a0]);
     377         112 :       setAtomsDerivatives(val, a0+1, deriv[a0+1]);
     378         112 :       setAtomsDerivatives(val, a0+2, deriv[a0+2]);
     379         112 :       setAtomsDerivatives(val, a0+3, deriv[a0+3]);
     380         112 :       setAtomsDerivatives(val, a0+4, deriv[a0+4]);
     381         112 :       setAtomsDerivatives(val, a0+5, deriv[a0+5]);
     382          56 :       Tensor virial;
     383         112 :       virial-=Tensor(getPosition(a0), deriv[a0]);
     384         112 :       virial-=Tensor(getPosition(a0+1), deriv[a0+1]);
     385         112 :       virial-=Tensor(getPosition(a0+2), deriv[a0+2]);
     386         112 :       virial-=Tensor(getPosition(a0+3), deriv[a0+3]);
     387         112 :       virial-=Tensor(getPosition(a0+4), deriv[a0+4]);
     388         112 :       virial-=Tensor(getPosition(a0+5), deriv[a0+5]);
     389          56 :       setBoxDerivatives(val, virial);
     390             :     }
     391             :   }
     392          16 : }
     393             : 
     394          16 : void JCoupling::update() {
     395             :   // write status file
     396          32 :   if(getWstride()>0&& (getStep()%getWstride()==0 || getCPT()) ) writeStatus();
     397          16 : }
     398             : 
     399             : }
     400        4839 : }

Generated by: LCOV version 1.13