LCOV - code coverage report
Current view: top level - isdb - NOE.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 132 135 97.8 %
Date: 2020-11-18 11:20:57 Functions: 12 14 85.7 %

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

Generated by: LCOV version 1.13