LCOV - code coverage report
Current view: top level - isdb - NOE.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 124 127 97.6 %
Date: 2019-08-13 10:15:31 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-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/NeighborList.h"
      25             : #include "tools/Pbc.h"
      26             : 
      27             : #include <string>
      28             : #include <cmath>
      29             : #include <memory>
      30             : 
      31             : using namespace std;
      32             : 
      33             : namespace PLMD {
      34             : namespace isdb {
      35             : 
      36             : //+PLUMEDOC ISDB_COLVAR NOE
      37             : /*
      38             : Calculates NOE intensities as sums of 1/r^6, also averaging over multiple equivalent atoms
      39             :  or ambiguous NOE.
      40             : 
      41             : Each NOE is defined by two groups containing the same number of atoms, distances are
      42             : calculated in pairs, transformed in 1/r^6, summed and saved as components.
      43             : 
      44             : \f[
      45             : NOE() = (\frac{1}{N_{eq}}\sum_j^{N_{eq}} (\frac{1}{r_j^6}))
      46             : \f]
      47             : 
      48             : NOE can be used to calculate a Metainference score over one or more replicas using the intrinsic implementation
      49             : of \ref METAINFERENCE that is activated by DOSCORE.
      50             : 
      51             : \par Examples
      52             : In the following examples three noes are defined, the first is calculated based on the distances
      53             : of atom 1-2 and 3-2; the second is defined by the distance 5-7 and the third by the distances
      54             : 4-15,4-16,8-15,8-16. \ref METAINFERENCE is activated using DOSCORE.
      55             : 
      56             : \plumedfile
      57             : NOE ...
      58             : GROUPA1=1,3 GROUPB1=2,2
      59             : GROUPA2=5 GROUPB2=7
      60             : GROUPA3=4,4,8,8 GROUPB3=15,16,15,16
      61             : DOSCORE
      62             : LABEL=noes
      63             : ... NOE
      64             : 
      65             : PRINT ARG=noes.* FILE=colvar
      66             : \endplumedfile
      67             : 
      68             : */
      69             : //+ENDPLUMEDOC
      70             : 
      71          33 : class NOE :
      72             :   public MetainferenceBase
      73             : {
      74             : private:
      75             :   bool             pbc;
      76             :   vector<unsigned> nga;
      77             :   std::unique_ptr<NeighborList> nl;
      78             :   unsigned         tot_size;
      79             : public:
      80             :   static void registerKeywords( Keywords& keys );
      81             :   explicit NOE(const ActionOptions&);
      82             :   void calculate() override;
      83             :   void update() override;
      84             : };
      85             : 
      86        7854 : PLUMED_REGISTER_ACTION(NOE,"NOE")
      87             : 
      88          12 : void NOE::registerKeywords( Keywords& keys ) {
      89          12 :   componentsAreNotOptional(keys);
      90          12 :   MetainferenceBase::registerKeywords(keys);
      91          36 :   keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
      92             :   keys.add("numbered","GROUPA","the atoms involved in each of the contacts you wish to calculate. "
      93             :            "Keywords like GROUPA1, GROUPA2, GROUPA3,... should be listed and one contact will be "
      94          48 :            "calculated for each ATOM keyword you specify.");
      95             :   keys.add("numbered","GROUPB","the atoms involved in each of the contacts you wish to calculate. "
      96             :            "Keywords like GROUPB1, GROUPB2, GROUPB3,... should be listed and one contact will be "
      97          48 :            "calculated for each ATOM keyword you specify.");
      98          36 :   keys.reset_style("GROUPA","atoms");
      99          36 :   keys.reset_style("GROUPB","atoms");
     100          48 :   keys.add("numbered","NOEDIST","Add an experimental value for each NOE.");
     101          48 :   keys.addOutputComponent("noe","default","the # NOE");
     102          48 :   keys.addOutputComponent("exp","NOEDIST","the # NOE experimental distance");
     103          12 : }
     104             : 
     105          11 : NOE::NOE(const ActionOptions&ao):
     106             :   PLUMED_METAINF_INIT(ao),
     107          22 :   pbc(true)
     108             : {
     109          11 :   bool nopbc=!pbc;
     110          22 :   parseFlag("NOPBC",nopbc);
     111          11 :   pbc=!nopbc;
     112             : 
     113             :   // Read in the atoms
     114             :   vector<AtomNumber> t, ga_lista, gb_lista;
     115          22 :   for(int i=1;; ++i ) {
     116          66 :     parseAtomList("GROUPA", i, t );
     117          33 :     if( t.empty() ) break;
     118          88 :     for(unsigned j=0; j<t.size(); j++) ga_lista.push_back(t[j]);
     119          44 :     nga.push_back(t.size());
     120          22 :     t.resize(0);
     121          22 :   }
     122             :   vector<unsigned> ngb;
     123          22 :   for(int i=1;; ++i ) {
     124          66 :     parseAtomList("GROUPB", i, t );
     125          33 :     if( t.empty() ) break;
     126          88 :     for(unsigned j=0; j<t.size(); j++) gb_lista.push_back(t[j]);
     127          44 :     ngb.push_back(t.size());
     128          66 :     if(ngb[i-1]!=nga[i-1]) error("The same number of atoms is expected for the same GROUPA-GROUPB couple");
     129          22 :     t.resize(0);
     130          22 :   }
     131          11 :   if(nga.size()!=ngb.size()) error("There should be the same number of GROUPA and GROUPB keywords");
     132             :   // Create neighbour lists
     133          22 :   nl.reset( new NeighborList(ga_lista,gb_lista,true,pbc,getPbc()) );
     134             : 
     135             :   // Optionally add an experimental value (like with RDCs)
     136             :   vector<double> noedist;
     137          11 :   noedist.resize( nga.size() );
     138             :   unsigned ntarget=0;
     139          58 :   for(unsigned i=0; i<nga.size(); ++i) {
     140          40 :     if( !parseNumbered( "NOEDIST", i+1, noedist[i] ) ) break;
     141          18 :     ntarget++;
     142             :   }
     143             :   bool addexp=false;
     144          22 :   if(ntarget!=nga.size() && ntarget!=0) error("found wrong number of NOEDIST values");
     145          11 :   if(ntarget==nga.size()) addexp=true;
     146          11 :   if(getDoScore()&&!addexp) error("with DOSCORE you need to set the NOEDIST values");
     147             : 
     148             :   // Ouput details of all contacts
     149             :   unsigned index=0;
     150          55 :   for(unsigned i=0; i<nga.size(); ++i) {
     151          22 :     log.printf("  The %uth NOE is calculated using %u equivalent couples of atoms\n", i, nga[i]);
     152          88 :     for(unsigned j=0; j<nga[i]; j++) {
     153          66 :       log.printf("    couple %u is %d %d.\n", j, ga_lista[index].serial(), gb_lista[index].serial() );
     154          33 :       index++;
     155             :     }
     156             :   }
     157          11 :   tot_size = index;
     158             : 
     159          11 :   if(pbc)      log.printf("  using periodic boundary conditions\n");
     160           0 :   else         log.printf("  without periodic boundary conditions\n");
     161             : 
     162          33 :   log << " Bibliography" << plumed.cite("Bonomi, Camilloni, Bioinformatics, 33, 3999 (2017)") << "\n";
     163             : 
     164          11 :   if(!getDoScore()) {
     165          35 :     for(unsigned i=0; i<nga.size(); i++) {
     166          14 :       string num; Tools::convert(i,num);
     167          28 :       addComponentWithDerivatives("noe-"+num);
     168          28 :       componentIsNotPeriodic("noe-"+num);
     169             :     }
     170           7 :     if(addexp) {
     171          25 :       for(unsigned i=0; i<nga.size(); i++) {
     172          10 :         string num; Tools::convert(i,num);
     173          20 :         addComponent("exp-"+num);
     174          20 :         componentIsNotPeriodic("exp-"+num);
     175          20 :         Value* comp=getPntrToComponent("exp-"+num);
     176          10 :         comp->set(noedist[i]);
     177             :       }
     178             :     }
     179             :   } else {
     180          20 :     for(unsigned i=0; i<nga.size(); i++) {
     181           8 :       string num; Tools::convert(i,num);
     182          16 :       addComponent("noe-"+num);
     183          16 :       componentIsNotPeriodic("noe-"+num);
     184             :     }
     185          20 :     for(unsigned i=0; i<nga.size(); i++) {
     186           8 :       string num; Tools::convert(i,num);
     187          16 :       addComponent("exp-"+num);
     188          16 :       componentIsNotPeriodic("exp-"+num);
     189          16 :       Value* comp=getPntrToComponent("exp-"+num);
     190           8 :       comp->set(noedist[i]);
     191             :     }
     192             :   }
     193             : 
     194          11 :   requestAtoms(nl->getFullAtomList(), false);
     195          11 :   if(getDoScore()) {
     196           4 :     setParameters(noedist);
     197           4 :     Initialise(nga.size());
     198             :   }
     199          11 :   setDerivatives();
     200          11 :   checkRead();
     201          11 : }
     202             : 
     203         456 : void NOE::calculate()
     204             : {
     205         456 :   const unsigned ngasz=nga.size();
     206         456 :   vector<Vector> deriv(tot_size, Vector{0,0,0});
     207             : 
     208        1366 :   #pragma omp parallel for num_threads(OpenMP::getNumThreads())
     209             :   for(unsigned i=0; i<ngasz; i++) {
     210         906 :     Tensor dervir;
     211             :     double noe=0;
     212             :     unsigned index=0;
     213        1821 :     for(unsigned k=0; k<i; k++) index+=nga[k];
     214         909 :     string num; Tools::convert(i,num);
     215        1813 :     Value* val=getPntrToComponent("noe-"+num);
     216             :     // cycle over equivalent atoms
     217        4552 :     for(unsigned j=0; j<nga[i]; j++) {
     218        2728 :       const unsigned i0=nl->getClosePair(index+j).first;
     219        1366 :       const unsigned i1=nl->getClosePair(index+j).second;
     220             : 
     221        1368 :       Vector distance;
     222        5468 :       if(pbc) distance=pbcDistance(getPosition(i0),getPosition(i1));
     223           0 :       else    distance=delta(getPosition(i0),getPosition(i1));
     224             : 
     225        1366 :       const double ir2=1./distance.modulo2();
     226        1368 :       const double ir6=ir2*ir2*ir2;
     227        1368 :       const double ir8=6*ir6*ir2;
     228             : 
     229        1368 :       noe += ir6;
     230        2736 :       deriv[index+j] = ir8*distance;
     231        1367 :       if(!getDoScore()) {
     232        2446 :         dervir += Tensor(distance, deriv[index+j]);
     233        2448 :         setAtomsDerivatives(val, i0,  deriv[index+j]);
     234        2446 :         setAtomsDerivatives(val, i1, -deriv[index+j]);
     235             :       }
     236             :     }
     237             :     val->set(noe);
     238         911 :     if(!getDoScore()) {
     239         816 :       setBoxDerivatives(val, dervir);
     240             :     } else setCalcData(i, noe);
     241             :   }
     242             : 
     243         456 :   if(getDoScore()) {
     244             :     /* Metainference */
     245          48 :     Tensor dervir;
     246          48 :     double score = getScore();
     247             :     setScore(score);
     248             : 
     249             :     /* calculate final derivatives */
     250          96 :     Value* val=getPntrToComponent("score");
     251         144 :     for(unsigned i=0; i<ngasz; i++) {
     252             :       unsigned index=0;
     253          96 :       for(unsigned k=0; k<i; k++) index+=nga[k];
     254             :       // cycle over equivalent atoms
     255         384 :       for(unsigned j=0; j<nga[i]; j++) {
     256         288 :         const unsigned i0=nl->getClosePair(index+j).first;
     257         144 :         const unsigned i1=nl->getClosePair(index+j).second;
     258             : 
     259         144 :         Vector distance;
     260         432 :         if(pbc) distance=pbcDistance(getPosition(i0),getPosition(i1));
     261           0 :         else    distance=delta(getPosition(i0),getPosition(i1));
     262             : 
     263         288 :         dervir += Tensor(distance,deriv[index+j]*getMetaDer(i));
     264         144 :         setAtomsDerivatives(val, i0,  deriv[index+j]*getMetaDer(i));
     265         144 :         setAtomsDerivatives(val, i1, -deriv[index+j]*getMetaDer(i));
     266             :       }
     267             :     }
     268          48 :     setBoxDerivatives(val, dervir);
     269             :   }
     270         456 : }
     271             : 
     272         132 : void NOE::update() {
     273             :   // write status file
     274         264 :   if(getWstride()>0&& (getStep()%getWstride()==0 || getCPT()) ) writeStatus();
     275         132 : }
     276             : 
     277             : }
     278        5874 : }

Generated by: LCOV version 1.14