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

Generated by: LCOV version 1.14