LCOV - code coverage report
Current view: top level - isdb - CS2Backbone.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 1111 1163 95.5 %
Date: 2021-11-18 15:22:58 Functions: 33 34 97.1 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-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             : 
      23             : #define cutOffNB      0.60      // buffer distance for neighbour-lists 
      24             : #define cutOffDist    0.50      // cut off distance for non-bonded pairwise forces
      25             : #define cutOnDist     0.32      // cut off distance for non-bonded pairwise forces
      26             : #define cutOffNB2     cutOffNB*cutOffNB // squared buffer distance for neighbour-lists 
      27             : #define cutOffDist2   cutOffDist*cutOffDist
      28             : #define cutOnDist2    cutOnDist*cutOnDist
      29             : #define invswitch     1.0/((cutOffDist2-cutOnDist2)*(cutOffDist2-cutOnDist2)*(cutOffDist2-cutOnDist2))
      30             : #define cutOffDist4   cutOffDist2*cutOffDist2
      31             : #define cutMixed      cutOffDist2*cutOffDist2*cutOffDist2 -3.*cutOffDist2*cutOffDist2*cutOnDist2
      32             : 
      33             : #include <string>
      34             : #include <fstream>
      35             : #include <iterator>
      36             : #include <sstream>
      37             : 
      38             : #include "MetainferenceBase.h"
      39             : #include "core/ActionRegister.h"
      40             : #include "tools/Pbc.h"
      41             : #include "tools/PDB.h"
      42             : #include "tools/Torsion.h"
      43             : 
      44             : using namespace std;
      45             : 
      46             : namespace PLMD {
      47             : namespace isdb {
      48             : 
      49             : //+PLUMEDOC ISDB_COLVAR CS2BACKBONE
      50             : /*
      51             : Calculates the backbone chemical shifts for a protein.
      52             : 
      53             : The functional form is that of CamShift \cite Kohlhoff:2009us. The chemical shift
      54             : of the selected nuclei can be saved as components. Alternatively one can calculate either
      55             : the CAMSHIFT score (useful as a collective variable \cite Granata:2013dk or as a scoring
      56             : function \cite Robustelli:2010dn) or a \ref METAINFERENCE score (using DOSCORE).
      57             : For these two latter cases experimental chemical shifts must be provided.
      58             : 
      59             : CS2BACKBONE calculation can be relatively heavy because it often uses a large number of atoms, it can
      60             : be run in parallel using MPI and \ref Openmp.
      61             : 
      62             : As a general rule, when using \ref CS2BACKBONE or other experimental restraints it may be better to
      63             : increase the accuracy of the constraint algorithm due to the increased strain on the bonded structure.
      64             : In the case of GROMACS it is safer to use lincs-iter=2 and lincs-order=6.
      65             : 
      66             : In general the system for which chemical shifts are calculated must be completely included in
      67             : ATOMS and a TEMPLATE pdb file for the same atoms should be provided as well in the folder DATADIR.
      68             : The system is made automatically whole unless NOPBC is used, in particular if the system is made
      69             : by multiple chains it is usually better to use NOPBC and make the molecule whole \ref WHOLEMOLECULES
      70             : selecting an appropriate order of the atoms. The pdb file is needed to the generate a simple topology of the protein.
      71             : For histidine residues in protonation states different from D the HIE/HSE HIP/HSP name should be used.
      72             : GLH and ASH can be used for the alternative protonation of GLU and ASP. Non-standard amino acids and other
      73             : molecules are not yet supported, but in principle they can be named UNK. If multiple chains are present
      74             : the chain identifier must be in the standard PDB format, together with the TER keyword at the end of each chain.
      75             : Termini groups like ACE or NME should be removed from the TEMPLATE pdb because they are not recognized by
      76             : CS2BACKBONE.
      77             : 
      78             : In addition to a pdb file one needs to provide a list of chemical shifts to be calculated using one
      79             : file per nucleus type (CAshifts.dat, CBshifts.dat, Cshifts.dat, Hshifts.dat, HAshifts.dat, Nshifts.dat),
      80             : add only the files for the nuclei you need, but each file should include all protein residues.
      81             : A chemical shift for a nucleus is calculated if a value greater than 0 is provided.
      82             : For practical purposes the value can correspond to the experimental value.
      83             : Residues numbers should match that used in the pdb file, but must be positive, so double check the pdb.
      84             : The first and last residue of each chain should be preceded by a # character.
      85             : 
      86             : \verbatim
      87             : CAshifts.dat:
      88             : #1 0.0
      89             : 2 55.5
      90             : 3 58.4
      91             : .
      92             : .
      93             : #last 0.0
      94             : #first of second chain
      95             : .
      96             : #last of second chain
      97             : \endverbatim
      98             : 
      99             : The default behavior is to store the values for the active nuclei in components (ca_#, cb_#,
     100             : co_#, ha_#, hn_#, nh_# and expca_#, expcb_#, expco_#, expha_#, exphn_#, exp_nh#) with NOEXP it is possible
     101             : to only store the back-calculated values, where # includes a chain and residue number.
     102             : 
     103             : One additional file is always needed in the folder DATADIR: camshift.db. This file includes all the parameters needed to
     104             : calculate the chemical shifts and can be found in regtest/isdb/rt-cs2backbone/data/ .
     105             : 
     106             : Additional material and examples can be also found in the tutorial \ref isdb-1 as well as in the cs2backbone regtests
     107             : in the isdb folder.
     108             : 
     109             : \par Examples
     110             : 
     111             : In this first example the chemical shifts are used to calculate a collective variable to be used
     112             : in NMR driven Metadynamics \cite Granata:2013dk :
     113             : 
     114             : \plumedfile
     115             : whole: GROUP ATOMS=2612-2514:-1,961-1:-1,2466-962:-1,2513-2467:-1
     116             : WHOLEMOLECULES ENTITY0=whole
     117             : cs: CS2BACKBONE ATOMS=1-2612 DATADIR=data/ TEMPLATE=template.pdb CAMSHIFT NOPBC
     118             : metad: METAD ARG=cs HEIGHT=0.5 SIGMA=0.1 PACE=200 BIASFACTOR=10
     119             : PRINT ARG=cs,metad.bias FILE=COLVAR STRIDE=100
     120             : \endplumedfile
     121             : 
     122             : In this second example the chemical shifts are used as replica-averaged restrained as in \cite Camilloni:2012je \cite Camilloni:2013hs.
     123             : 
     124             : \plumedfile
     125             : cs: CS2BACKBONE ATOMS=1-174 DATADIR=data/
     126             : encs: ENSEMBLE ARG=(cs\.hn_.*),(cs\.nh_.*)
     127             : stcs: STATS ARG=encs.* SQDEVSUM PARARG=(cs\.exphn_.*),(cs\.expnh_.*)
     128             : RESTRAINT ARG=stcs.sqdevsum AT=0 KAPPA=0 SLOPE=24
     129             : 
     130             : PRINT ARG=(cs\.hn_.*),(cs\.nh_.*) FILE=RESTRAINT STRIDE=100
     131             : 
     132             : \endplumedfile
     133             : 
     134             : This third example show how to use chemical shifts to calculate a \ref METAINFERENCE score .
     135             : 
     136             : \plumedfile
     137             : cs: CS2BACKBONE ATOMS=1-174 DATADIR=data/ SIGMA_MEAN0=1.0 DOSCORE
     138             : csbias: BIASVALUE ARG=cs.score
     139             : 
     140             : PRINT ARG=(cs\.hn_.*),(cs\.nh_.*) FILE=CS.dat STRIDE=1000
     141             : PRINT ARG=cs.score FILE=BIAS STRIDE=100
     142             : \endplumedfile
     143             : 
     144             : */
     145             : //+ENDPLUMEDOC
     146             : 
     147             : class CS2BackboneDB {
     148             :   enum { STD, GLY, PRO};
     149             :   enum { HA_ATOM, H_ATOM, N_ATOM, CA_ATOM, CB_ATOM, C_ATOM };
     150             :   static const unsigned aa_kind = 3;
     151             :   static const unsigned atm_kind = 6;
     152             :   static const unsigned numXtraDists = 27;
     153             : 
     154             :   // ALA, ARG, ASN, ASP, CYS, GLU, GLN, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL
     155             :   double c_aa[aa_kind][atm_kind][20];
     156             :   double c_aa_prev[aa_kind][atm_kind][20];
     157             :   double c_aa_succ[aa_kind][atm_kind][20];
     158             :   double co_bb[aa_kind][atm_kind][16];
     159             :   double co_sc_[aa_kind][atm_kind][20][20];
     160             :   double co_xd[aa_kind][atm_kind][numXtraDists];
     161             :   double co_sphere[aa_kind][atm_kind][2][8];
     162             :   // for ring current effects
     163             :   // Phe, Tyr, Trp_1, Trp_2, His
     164             :   double co_ring[aa_kind][atm_kind][5];
     165             :   // for dihedral angles
     166             :   // co * (a * cos(3 * omega + c) + b * cos(omega + d))
     167             :   double co_da[aa_kind][atm_kind][3];
     168             :   double pars_da[aa_kind][atm_kind][3][5];
     169             : 
     170             : public:
     171             : 
     172       10926 :   inline unsigned kind(const string &s) {
     173       10926 :     if(s=="GLY") return GLY;
     174        9324 :     else if(s=="PRO") return PRO;
     175        9108 :     return STD;
     176             :   }
     177             : 
     178       10926 :   inline unsigned atom_kind(const string &s) {
     179       10926 :     if(s=="HA")return HA_ATOM;
     180       10872 :     else if(s=="H") return H_ATOM;
     181        8010 :     else if(s=="N") return N_ATOM;
     182        5148 :     else if(s=="CA")return CA_ATOM;
     183        2160 :     else if(s=="CB")return CB_ATOM;
     184          54 :     else if(s=="C") return C_ATOM;
     185           0 :     return -1;
     186             :   }
     187             : 
     188             :   unsigned get_numXtraDists() {return numXtraDists;}
     189             : 
     190             :   //PARAMETERS
     191        5890 :   inline double * CONSTAACURR(const unsigned a_kind, const unsigned at_kind) {return c_aa[a_kind][at_kind];}
     192        5890 :   inline double * CONSTAANEXT(const unsigned a_kind, const unsigned at_kind) {return c_aa_succ[a_kind][at_kind];}
     193        5890 :   inline double * CONSTAAPREV(const unsigned a_kind, const unsigned at_kind) {return c_aa_prev[a_kind][at_kind];}
     194        5890 :   inline double * CONST_BB2(const unsigned a_kind, const unsigned at_kind) {return co_bb[a_kind][at_kind];}
     195        5890 :   inline double * CONST_SC2(const unsigned a_kind, const unsigned at_kind, unsigned res_type) { return co_sc_[a_kind][at_kind][res_type];}
     196        5890 :   inline double * CONST_XD(const unsigned a_kind, const unsigned at_kind) { return co_xd[a_kind][at_kind];}
     197        5890 :   inline double * CO_SPHERE(const unsigned a_kind, const unsigned at_kind, unsigned exp_type) { return co_sphere[a_kind][at_kind][exp_type];}
     198        5890 :   inline double * CO_RING(const unsigned a_kind, const unsigned at_kind) { return co_ring[a_kind][at_kind];}
     199        5890 :   inline double * CO_DA(const unsigned a_kind, const unsigned at_kind) { return co_da[a_kind][at_kind];}
     200       16480 :   inline double * PARS_DA(const unsigned a_kind, const unsigned at_kind, const unsigned ang_kind) { return pars_da[a_kind][at_kind][ang_kind];}
     201             : 
     202          18 :   void parse(const string &file, const double dscale) {
     203          36 :     ifstream in;
     204          18 :     in.open(file.c_str());
     205          18 :     if(!in) plumed_merror("Unable to open DB file: " + file);
     206             : 
     207             :     unsigned c_kind = 0;
     208             :     unsigned c_atom = 0;
     209             :     unsigned nline = 0;
     210             : 
     211         396 :     for(unsigned i=0; i<3; i++) for(unsigned j=0; j<6; j++) {
     212       13284 :         for(unsigned k=0; k<20; k++) {
     213        6480 :           c_aa[i][j][k]=0.;
     214        6480 :           c_aa_prev[i][j][k]=0.;
     215        6480 :           c_aa_succ[i][j][k]=0.;
     216      136080 :           for(unsigned m=0; m<20; m++) co_sc_[i][j][k][m]=0.;
     217             :         }
     218        5508 :         for(unsigned k=0; k<16; k++) {co_bb[i][j][k]=0.; }
     219        2916 :         for(unsigned k=0; k<8; k++) { co_sphere[i][j][0][k]=0.; co_sphere[i][j][1][k]=0.; }
     220        2268 :         for(unsigned k=0; k<3; k++) {
     221         972 :           co_da[i][j][k]=0.;
     222        5832 :           for(unsigned l=0; l<5; l++) pars_da[i][j][k][l]=0.;
     223             :         }
     224        1944 :         for(unsigned k=0; k<5; k++) co_ring[i][j][k]=0.;
     225        9072 :         for(unsigned k=0; k<numXtraDists; k++) co_xd[i][j][k]=0.;
     226             :       }
     227             : 
     228       37710 :     while(!in.eof()) {
     229             :       string line;
     230       37692 :       getline(in,line);
     231             :       ++nline;
     232       37692 :       if(line.compare(0,1,"#")==0) continue;
     233           0 :       vector<string> tok;
     234           0 :       vector<string> tmp;
     235       40860 :       tok = split(line,' ');
     236      765054 :       for(unsigned q=0; q<tok.size(); q++)
     237      241398 :         if(tok[q].size()) tmp.push_back(tok[q]);
     238       20430 :       tok = tmp;
     239       40860 :       if(tok.size()==0) continue;
     240       20736 :       if(tok[0]=="PAR") {
     241         324 :         c_kind = kind(tok[2]);
     242         324 :         c_atom = atom_kind(tok[1]);
     243         324 :         continue;
     244             :       }
     245       20088 :       else if(tok[0]=="WEIGHT") {
     246         324 :         continue;
     247             :       }
     248       19764 :       else if(tok[0]=="FLATBTM") {
     249         324 :         continue;
     250             :       }
     251       19440 :       else if (tok[0] == "SCALEHARM") {
     252         324 :         continue;
     253             :       }
     254       19116 :       else if (tok[0] == "TANHAMPLI") {
     255         324 :         continue;
     256             :       }
     257       18792 :       else if (tok[0] == "ENDHARMON") {
     258         324 :         continue;
     259             :       }
     260       18468 :       else if (tok[0] == "MAXRCDEVI") {
     261         324 :         continue;
     262             :       }
     263       18144 :       else if (tok[0] == "RANDCOIL") {
     264         324 :         continue;
     265             :       }
     266       17820 :       else if (tok[0] == "CONST") {
     267         324 :         continue;
     268             :       }
     269       17820 :       else if (tok[0] == "CONSTAA") {
     270         324 :         assign(c_aa[c_kind][c_atom],tok,1);
     271         324 :         continue;
     272             :       }
     273       17496 :       else if (tok[0] == "CONSTAA-1") {
     274         324 :         assign(c_aa_prev[c_kind][c_atom],tok,1);
     275         324 :         continue;
     276             :       }
     277       17172 :       else if (tok[0] == "CONSTAA+1") {
     278         324 :         assign(c_aa_succ[c_kind][c_atom],tok,1);
     279         324 :         continue;
     280             :       }
     281       16524 :       else if (tok[0] == "COBB1") {
     282         324 :         continue;
     283             :       }
     284       16524 :       else if (tok[0] == "COBB2") {
     285             :         //angstrom to nm
     286         324 :         assign(co_bb[c_kind][c_atom],tok,dscale);
     287         324 :         continue;
     288             :       }
     289       16200 :       else if (tok[0] == "SPHERE1") {
     290             :         // angstrom^-3 to nm^-3
     291         324 :         assign(co_sphere[c_kind][c_atom][0],tok,1./(dscale*dscale*dscale));
     292         324 :         continue;
     293             :       }
     294       15876 :       else if (tok[0] == "SPHERE2") {
     295             :         //angstrom to nm
     296         324 :         assign(co_sphere[c_kind][c_atom][1],tok,dscale);
     297         324 :         continue;
     298             :       }
     299       15552 :       else if (tok[0] == "DIHEDRALS") {
     300         324 :         assign(co_da[c_kind][c_atom],tok,1);
     301         324 :         continue;
     302             :       }
     303       14904 :       else if (tok[0] == "RINGS") {
     304             :         // angstrom^-3 to nm^-3
     305         324 :         assign(co_ring[c_kind][c_atom],tok,1./(dscale*dscale*dscale));
     306        5508 :         for(unsigned i=1; i<tok.size(); i++)
     307        1620 :           co_ring[c_kind][c_atom][i-1] *= 1000;
     308         324 :         continue;
     309             :       }
     310       14580 :       else if (tok[0] == "HBONDS") {
     311         324 :         continue;
     312             :       }
     313       14580 :       else if (tok[0] == "XTRADISTS") {
     314             :         //angstrom to nm
     315         324 :         assign(co_xd[c_kind][c_atom],tok,dscale);
     316         324 :         continue;
     317             :       }
     318       14256 :       else if(tok[0]=="DIHEDPHI") {
     319         324 :         assign(pars_da[c_kind][c_atom][0],tok,1);
     320         324 :         continue;
     321             :       }
     322       13932 :       else if(tok[0]=="DIHEDPSI") {
     323         324 :         assign(pars_da[c_kind][c_atom][1],tok,1);
     324         324 :         continue;
     325             :       }
     326       13608 :       else if(tok[0]=="DIHEDCHI1") {
     327         324 :         assign(pars_da[c_kind][c_atom][2],tok,1);
     328         324 :         continue;
     329             :       }
     330             : 
     331             :       bool ok = false;
     332             :       string scIdent1 [] = {"COSCALA1", "COSCARG1", "COSCASN1", "COSCASP1", "COSCCYS1", "COSCGLN1", "COSCGLU1",
     333             :                             "COSCGLY1", "COSCHIS1", "COSCILE1", "COSCLEU1", "COSCLYS1", "COSCMET1", "COSCPHE1",
     334             :                             "COSCPRO1", "COSCSER1", "COSCTHR1", "COSCTRP1", "COSCTYR1", "COSCVAL1"
     335       12960 :                            };
     336             : 
     337      395280 :       for(unsigned scC = 0; scC < 20; scC++) {
     338      395280 :         if(tok[0]==scIdent1[scC]) {
     339             :           ok = true;
     340             :           break;
     341             :         }
     342             :       }
     343      285120 :       if(ok) continue;
     344             : 
     345             :       string scIdent2 [] = {"COSCALA2", "COSCARG2", "COSCASN2", "COSCASP2", "COSCCYS2", "COSCGLN2", "COSCGLU2",
     346             :                             "COSCGLY2", "COSCHIS2", "COSCILE2", "COSCLEU2", "COSCLYS2", "COSCMET2", "COSCPHE2",
     347             :                             "COSCPRO2", "COSCSER2", "COSCTHR2", "COSCTRP2", "COSCTYR2", "COSCVAL2"
     348        6480 :                            };
     349             : 
     350      129600 :       for(unsigned scC = 0; scC < 20; scC++) {
     351      136080 :         if(tok[0]==scIdent2[scC]) {
     352             :           //angstrom to nm
     353        6480 :           assign(co_sc_[c_kind][c_atom][scC],tok,dscale);
     354             :           ok = true; break;
     355             :         }
     356             :       }
     357      142560 :       if(ok) continue;
     358             : 
     359           0 :       if(tok.size()) {
     360           0 :         string str_err = "DB WARNING: unrecognized token: " + tok[0];
     361           0 :         plumed_merror(str_err);
     362             :       }
     363             :     }
     364          18 :     in.close();
     365          18 :   }
     366             : 
     367             : private:
     368             : 
     369       20430 :   vector<string> &split(const string &s, char delim, vector<string> &elems) {
     370       40860 :     stringstream ss(s);
     371             :     string item;
     372      523656 :     while (getline(ss, item, delim)) {
     373      241398 :       elems.push_back(item);
     374             :     }
     375       20430 :     return elems;
     376             :   }
     377             : 
     378       20430 :   vector<string> split(const string &s, char delim) {
     379             :     vector<string> elems;
     380       20430 :     split(s, delim, elems);
     381       20430 :     return elems;
     382             :   }
     383             : 
     384       10368 :   void assign(double * f, const vector<string> & v, const double scale) {
     385      358020 :     for(unsigned i=1; i<v.size(); i++) {
     386      112428 :       f[i-1] = scale*(atof(v[i].c_str()));
     387      112428 :       if(fabs(f[i-1])<0.000001) f[i-1]=0.;
     388             :     }
     389       10368 :   }
     390             : };
     391             : 
     392          54 : class CS2Backbone : public MetainferenceBase {
     393      166284 :   struct ChemicalShift {
     394             :     double exp_cs;              // a reference chemical shifts
     395             :     Value *comp;                // a pointer to the component
     396             :     unsigned res_kind;          // residue type (STD/GLY/PRO)
     397             :     unsigned atm_kind;          // nuclues (HA/CA/CB/CO/NH/HN)
     398             :     unsigned res_type_prev;     // previuos residue (ALA/VAL/..)
     399             :     unsigned res_type_curr;     // current residue (ALA/VAL/..)
     400             :     unsigned res_type_next;     // next residue (ALA/VAL/..)
     401             :     string res_name;            // residue name
     402             :     string nucleus;             // chemical shift
     403             :     bool has_chi1;              // does we have a chi1
     404             :     unsigned csatoms;           // fixed number of atoms used
     405             :     unsigned totcsatoms;        // number of atoms used
     406             :     unsigned res_num;           // residue number
     407             :     unsigned chain;             // chain number
     408             :     unsigned ipos;              // index of the atom for which we are calculating the chemical shifts
     409             :     vector<unsigned> bb;        // atoms for the previous, current and next backbone
     410             :     vector<unsigned> side_chain;// atoms for the current sidechain
     411             :     vector<int> xd1;            // additional couple of atoms
     412             :     vector<int> xd2;            // additional couple of atoms
     413             :     vector<unsigned> box_nb;    // non-bonded atoms
     414             : 
     415       10602 :     ChemicalShift():
     416             :       exp_cs(0.),
     417             :       comp(NULL),
     418             :       res_kind(0),
     419             :       atm_kind(0),
     420             :       res_type_prev(0),
     421             :       res_type_curr(0),
     422             :       res_type_next(0),
     423             :       res_name(""),
     424             :       nucleus(""),
     425             :       has_chi1(true),
     426             :       csatoms(0),
     427             :       totcsatoms(0),
     428             :       res_num(0),
     429             :       chain(0),
     430       42408 :       ipos(0)
     431             :     {
     432       10602 :       xd1.reserve(26);
     433       10602 :       xd2.reserve(26);
     434       10602 :       box_nb.reserve(150);
     435       10602 :     }
     436             :   };
     437             : 
     438             :   struct RingInfo {
     439             :     enum {R_PHE, R_TYR, R_TRP1, R_TRP2, R_HIS};
     440             :     unsigned rtype;    // one out of five different types
     441             :     unsigned atom[6];  // up to six member per ring
     442             :     unsigned numAtoms; // number of ring members (5 or 6)
     443             :     Vector position;   // center of ring coordinates
     444             :     Vector normVect;   // ring plane normal vector
     445             :     Vector g[6];       // vector of the vectors used for normVect
     446             :     double lengthN2;   // square of length of normVect
     447             :     double lengthNV;   // length of normVect
     448         360 :     RingInfo():
     449             :       rtype(0),
     450             :       numAtoms(0),
     451             :       lengthN2(NAN),
     452         360 :       lengthNV(NAN)
     453             :     {
     454        2520 :       for(unsigned i=0; i<6; i++) atom[i]=0;
     455         360 :     }
     456             :   };
     457             : 
     458             :   enum aa_t {ALA, ARG, ASN, ASP, CYS, GLN, GLU, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL, UNK};
     459             :   enum sequence_t {Np, CAp, HAp, Cp, Op, Nc, Hc, CAc, HAc, Cc, Oc, Nn, Hn, CAn, HAn, Cn, CBc, CGc};
     460             : 
     461             :   CS2BackboneDB    db;
     462             :   vector<ChemicalShift> chemicalshifts;
     463             : 
     464             :   vector<RingInfo> ringInfo;
     465             :   vector<unsigned> type;
     466             :   vector<unsigned> res_num;
     467             :   unsigned         max_cs_atoms;
     468             :   unsigned         box_nupdate;
     469             :   unsigned         box_count;
     470             :   bool             camshift;
     471             :   bool             pbc;
     472             :   bool             serial;
     473             : 
     474             :   void init_cs(const string &file, const string &k, const PDB &pdb);
     475             :   void update_neighb();
     476             :   void compute_ring_parameters();
     477             :   void init_types(const PDB &pdb);
     478             :   void init_rings(const PDB &pdb);
     479             :   aa_t frag2enum(const string &aa);
     480             :   vector<string> side_chain_atoms(const string &s);
     481             :   bool isSP2(const string & resType, const string & atomName);
     482             :   bool is_chi1_cx(const string & frg, const string & atm);
     483             :   void xdist_name_map(string & name);
     484             : 
     485             : public:
     486             : 
     487             :   explicit CS2Backbone(const ActionOptions&);
     488             :   static void registerKeywords( Keywords& keys );
     489             :   void calculate();
     490             :   void update();
     491             : };
     492             : 
     493        7392 : PLUMED_REGISTER_ACTION(CS2Backbone,"CS2BACKBONE")
     494             : 
     495          19 : void CS2Backbone::registerKeywords( Keywords& keys ) {
     496          19 :   componentsAreNotOptional(keys);
     497          19 :   useCustomisableComponents(keys);
     498          19 :   MetainferenceBase::registerKeywords( keys );
     499          57 :   keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
     500          57 :   keys.addFlag("SERIAL",false,"Perform the calculation in serial - for debug purpose");
     501          76 :   keys.add("atoms","ATOMS","The atoms to be included in the calculation, e.g. the whole protein.");
     502          95 :   keys.add("compulsory","DATADIR","data/","The folder with the experimental chemical shifts.");
     503          95 :   keys.add("compulsory","TEMPLATE","template.pdb","A PDB file of the protein system.");
     504          95 :   keys.add("compulsory","NEIGH_FREQ","20","Period in step for neighbor list update.");
     505          57 :   keys.addFlag("CAMSHIFT",false,"Set to TRUE if you to calculate a single CamShift score.");
     506          57 :   keys.addFlag("NOEXP",false,"Set to TRUE if you don't want to have fixed components with the experimental values.");
     507          76 :   keys.addOutputComponent("ha","default","the calculated Ha hydrogen chemical shifts");
     508          76 :   keys.addOutputComponent("hn","default","the calculated H hydrogen chemical shifts");
     509          76 :   keys.addOutputComponent("nh","default","the calculated N nitrogen chemical shifts");
     510          76 :   keys.addOutputComponent("ca","default","the calculated Ca carbon chemical shifts");
     511          76 :   keys.addOutputComponent("cb","default","the calculated Cb carbon chemical shifts");
     512          76 :   keys.addOutputComponent("co","default","the calculated C' carbon chemical shifts");
     513          76 :   keys.addOutputComponent("expha","default","the experimental Ha hydrogen chemical shifts");
     514          76 :   keys.addOutputComponent("exphn","default","the experimental H hydrogen chemical shifts");
     515          76 :   keys.addOutputComponent("expnh","default","the experimental N nitrogen chemical shifts");
     516          76 :   keys.addOutputComponent("expca","default","the experimental Ca carbon chemical shifts");
     517          76 :   keys.addOutputComponent("expcb","default","the experimental Cb carbon chemical shifts");
     518          76 :   keys.addOutputComponent("expco","default","the experimental C' carbon chemical shifts");
     519          19 : }
     520             : 
     521          18 : CS2Backbone::CS2Backbone(const ActionOptions&ao):
     522             :   PLUMED_METAINF_INIT(ao),
     523             :   max_cs_atoms(0),
     524             :   camshift(false),
     525             :   pbc(true),
     526          36 :   serial(false)
     527             : {
     528             :   vector<AtomNumber> used_atoms;
     529          36 :   parseAtomList("ATOMS",used_atoms);
     530             : 
     531          36 :   parseFlag("CAMSHIFT",camshift);
     532          23 :   if(camshift&&getDoScore()) plumed_merror("It is not possible to use CAMSHIFT and DOSCORE at the same time");
     533             : 
     534          18 :   bool nopbc=!pbc;
     535          54 :   parseFlag("NOPBC",nopbc);
     536          18 :   pbc=!nopbc;
     537             : 
     538          36 :   parseFlag("SERIAL",serial);
     539             : 
     540          18 :   bool noexp=false;
     541          36 :   parseFlag("NOEXP",noexp);
     542             : 
     543             :   string stringa_data;
     544          36 :   parse("DATADIR",stringa_data);
     545             : 
     546             :   string stringa_template;
     547          36 :   parse("TEMPLATE",stringa_template);
     548             : 
     549          18 :   box_count=0;
     550          18 :   box_nupdate=20;
     551          36 :   parse("NEIGH_FREQ", box_nupdate);
     552             : 
     553          36 :   string stringadb  = stringa_data + string("/camshift.db");
     554          54 :   string stringapdb = stringa_data + string("/") + stringa_template;
     555             : 
     556             :   /* Lenght conversion (parameters are tuned for angstrom) */
     557             :   double scale=1.;
     558          18 :   if(!plumed.getAtoms().usingNaturalUnits()) {
     559          18 :     scale = 10.*atoms.getUnits().getLength();
     560             :   }
     561             : 
     562          18 :   log.printf("  Initialization of the predictor ...\n");
     563          18 :   db.parse(stringadb,scale);
     564             : 
     565          36 :   PDB pdb;
     566          36 :   if( !pdb.read(stringapdb,plumed.getAtoms().usingNaturalUnits(),1./scale) ) plumed_merror("missing input file " + stringapdb);
     567             : 
     568             :   // first of all we build the list of chemical shifts we want to predict
     569          18 :   log.printf("  Reading experimental data ...\n"); log.flush();
     570          54 :   stringadb = stringa_data + string("/CAshifts.dat");
     571          36 :   log.printf("  Initializing CA shifts %s\n", stringadb.c_str());
     572          36 :   init_cs(stringadb, "CA", pdb);
     573          54 :   stringadb = stringa_data + string("/CBshifts.dat");
     574          36 :   log.printf("  Initializing CB shifts %s\n", stringadb.c_str());
     575          36 :   init_cs(stringadb, "CB", pdb);
     576          54 :   stringadb = stringa_data + string("/Cshifts.dat");
     577          36 :   log.printf("  Initializing C' shifts %s\n", stringadb.c_str());
     578          36 :   init_cs(stringadb, "C", pdb);
     579          54 :   stringadb = stringa_data + string("/HAshifts.dat");
     580          36 :   log.printf("  Initializing HA shifts %s\n", stringadb.c_str());
     581          36 :   init_cs(stringadb, "HA", pdb);
     582          54 :   stringadb = stringa_data + string("/Hshifts.dat");
     583          36 :   log.printf("  Initializing H shifts %s\n", stringadb.c_str());
     584          36 :   init_cs(stringadb, "H", pdb);
     585          54 :   stringadb = stringa_data + string("/Nshifts.dat");
     586          36 :   log.printf("  Initializing N shifts %s\n", stringadb.c_str());
     587          36 :   init_cs(stringadb, "N", pdb);
     588             : 
     589          18 :   if(chemicalshifts.size()==0) plumed_merror("There are no chemical shifts to calculate, there must be at least a not empty file (CA|CB|C|HA|H|N|shifts.dat)");
     590             : 
     591          18 :   init_types(pdb);
     592          18 :   init_rings(pdb);
     593             : 
     594          18 :   log<<"  Bibliography "
     595          54 :      <<plumed.cite("Kohlhoff K, Robustelli P, Cavalli A, Salvatella A, Vendruscolo M, J. Am. Chem. Soc. 131, 13894 (2009)");
     596          28 :   if(camshift) log<<plumed.cite("Granata D, Camilloni C, Vendruscolo M, Laio A, Proc. Natl. Acad. Sci. USA 110, 6817 (2013)");
     597          39 :   else log<<plumed.cite("Camilloni C, Robustelli P, De Simone A, Cavalli A, Vendruscolo M, J. Am. Chem. Soc. 134, 3968 (2012)");
     598          54 :   log<<plumed.cite("Bonomi M, Camilloni C, Bioinformatics, 33, 3999 (2017)");
     599          18 :   log<<"\n";
     600             : 
     601          18 :   if(camshift) {
     602           5 :     noexp = true;
     603           5 :     addValueWithDerivatives();
     604           5 :     setNotPeriodic();
     605             :   } else {
     606       22997 :     for(unsigned cs=0; cs<chemicalshifts.size(); cs++) {
     607        7657 :       std::string num; Tools::convert(chemicalshifts[cs].res_num,num);
     608        7657 :       std::string chain_num; Tools::convert(chemicalshifts[cs].chain,chain_num);
     609        7657 :       if(getDoScore()) {
     610       11780 :         addComponent(chemicalshifts[cs].nucleus+chain_num+"_"+num);
     611        9424 :         componentIsNotPeriodic(chemicalshifts[cs].nucleus+chain_num+"_"+num);
     612       11780 :         chemicalshifts[cs].comp = getPntrToComponent(chemicalshifts[cs].nucleus+chain_num+"_"+num);
     613        2356 :         setParameter(chemicalshifts[cs].exp_cs);
     614             :       } else {
     615       26505 :         addComponentWithDerivatives(chemicalshifts[cs].nucleus+chain_num+"_"+num);
     616       21204 :         componentIsNotPeriodic(chemicalshifts[cs].nucleus+chain_num+"_"+num);
     617       26505 :         chemicalshifts[cs].comp = getPntrToComponent(chemicalshifts[cs].nucleus+chain_num+"_"+num);
     618             :       }
     619             :     }
     620          13 :     if(getDoScore()) Initialise(chemicalshifts.size());
     621             :   }
     622             : 
     623          18 :   if(!noexp) {
     624       22997 :     for(unsigned cs=0; cs<chemicalshifts.size(); cs++) {
     625        7657 :       std::string num; Tools::convert(chemicalshifts[cs].res_num,num);
     626        7657 :       std::string chain_num; Tools::convert(chemicalshifts[cs].chain,chain_num);
     627       45942 :       addComponent("exp"+chemicalshifts[cs].nucleus+chain_num+"_"+num);
     628       38285 :       componentIsNotPeriodic("exp"+chemicalshifts[cs].nucleus+chain_num+"_"+num);
     629       38285 :       Value* comp=getPntrToComponent("exp"+chemicalshifts[cs].nucleus+chain_num+"_"+num);
     630        7657 :       comp->set(chemicalshifts[cs].exp_cs);
     631             :     }
     632             :   }
     633             : 
     634          18 :   requestAtoms(used_atoms, false);
     635          18 :   setDerivatives();
     636          18 :   checkRead();
     637          18 : }
     638             : 
     639         108 : void CS2Backbone::init_cs(const string &file, const string &nucl, const PDB &pdb) {
     640             :   // number of chains
     641         108 :   vector<string> chains;
     642         108 :   pdb.getChainNames( chains );
     643             :   unsigned ichain=0;
     644             : 
     645         216 :   ifstream in;
     646         108 :   in.open(file.c_str());
     647         108 :   if(!in) return;
     648         108 :   istream_iterator<string> iter(in), end;
     649             :   unsigned begin=0;
     650             : 
     651             :   while(iter!=end) {
     652             :     string tok = *iter;
     653             :     ++iter;
     654       19440 :     if(tok[0]=='#') {
     655             :       ++iter;
     656         432 :       if(begin==1) {
     657             :         begin=0;
     658         216 :         ichain++;
     659             :       } else begin=1;
     660         432 :       continue;
     661             :     }
     662             :     int ro = atoi(tok.c_str());
     663       18576 :     if(ro<0) plumed_merror("Residue numbers should be positive\n");
     664       18576 :     unsigned resnum = static_cast<unsigned> (ro);
     665             :     tok = *iter;
     666             :     ++iter;
     667             :     double cs = atof(tok.c_str());
     668       18576 :     if(cs==0) continue;
     669             : 
     670             :     unsigned fres, lres;
     671             :     string errmsg;
     672       22140 :     pdb.getResidueRange(chains[ichain], fres, lres, errmsg);
     673       11070 :     if(resnum==fres||resnum==lres) plumed_merror("First and Last residue of each chain should be annotated as # in " + file + " Remember that residue numbers should match");
     674             : 
     675             :     // check in the PDB for the chain/residue/atom and enable the chemical shift
     676       11070 :     string RES = pdb.getResidueName(resnum, chains[ichain]);
     677       99054 :     if(RES=="HIE"||RES=="HIP"||RES=="HIS"||RES=="HSP"||RES=="HSE"||RES=="CYS"||RES=="GLH"||RES=="ASH"||RES=="UNK") continue;
     678       10944 :     if(RES=="GLN"&&nucl=="CB") continue;
     679       11322 :     if(RES=="ILE"&&nucl=="CB") continue;
     680       10998 :     if(RES=="PRO"&&nucl=="N") continue;
     681       10998 :     if(RES=="PRO"&&nucl=="H") continue;
     682       11106 :     if(RES=="PRO"&&nucl=="CB") continue;
     683       12240 :     if(RES=="GLY"&&nucl=="HA") continue;
     684       12312 :     if(RES=="GLY"&&nucl=="CB") continue;
     685             : 
     686       21204 :     ChemicalShift tmp_cs;
     687             : 
     688       10602 :     tmp_cs.exp_cs = cs;
     689       10602 :     if(nucl=="CA")      tmp_cs.nucleus = "ca_";
     690        7668 :     else if(nucl=="CB") tmp_cs.nucleus = "cb_";
     691        5616 :     else if(nucl=="C")  tmp_cs.nucleus = "co_";
     692        5616 :     else if(nucl=="HA") tmp_cs.nucleus = "ha_";
     693        5616 :     else if(nucl=="H")  tmp_cs.nucleus = "hn_";
     694        2808 :     else if(nucl=="N")  tmp_cs.nucleus = "nh_";
     695       10602 :     tmp_cs.chain = ichain;
     696       10602 :     tmp_cs.res_num = resnum;
     697       10602 :     tmp_cs.res_type_curr = frag2enum(RES);
     698       21204 :     tmp_cs.res_type_prev = frag2enum(pdb.getResidueName(resnum-1, chains[ichain]));
     699       21204 :     tmp_cs.res_type_next = frag2enum(pdb.getResidueName(resnum+1, chains[ichain]));
     700             :     tmp_cs.res_name = RES;
     701       10602 :     tmp_cs.res_kind = db.kind(RES);
     702       10602 :     tmp_cs.atm_kind = db.atom_kind(nucl);
     703       29016 :     if(RES!="ALA"&&RES!="GLY") {tmp_cs.bb.resize(18); tmp_cs.has_chi1=true;}
     704        4284 :     else {tmp_cs.bb.resize(16); tmp_cs.has_chi1=false;}
     705             : 
     706       10602 :     vector<AtomNumber> res_atoms = pdb.getAtomsInResidue(resnum, chains[ichain]);
     707             :     // find the position of the nucleus and of the other backbone atoms as well as for phi/psi/chi
     708      509202 :     for(unsigned a=0; a<res_atoms.size(); a++) {
     709      162666 :       string AN = pdb.getAtomName(res_atoms[a]);
     710      162666 :       if(nucl=="HA"&&(AN=="HA"||AN=="HA1"||AN=="HA3")) tmp_cs.ipos = res_atoms[a].index();
     711      247338 :       else if(nucl=="H"&&(AN=="H"||AN=="HN"))          tmp_cs.ipos = res_atoms[a].index();
     712      205056 :       else if(nucl=="N"&&AN=="N")                      tmp_cs.ipos = res_atoms[a].index();
     713      203796 :       else if(nucl=="CA"&&AN=="CA")                    tmp_cs.ipos = res_atoms[a].index();
     714      190296 :       else if(nucl=="CB"&&AN=="CB")                    tmp_cs.ipos = res_atoms[a].index();
     715      152064 :       else if(nucl=="C"&&AN=="C" )                     tmp_cs.ipos = res_atoms[a].index();
     716             :     }
     717             : 
     718       10602 :     vector<AtomNumber> prev_res_atoms = pdb.getAtomsInResidue(resnum-1, chains[ichain]);
     719             :     // find the position of the previous residues backbone atoms
     720      494892 :     for(unsigned a=0; a<prev_res_atoms.size(); a++) {
     721      157896 :       string AN = pdb.getAtomName(prev_res_atoms[a]);
     722      168498 :       if(AN=="N")                             { tmp_cs.bb[Np]  = prev_res_atoms[a].index(); }
     723      157896 :       else if(AN=="CA")                       { tmp_cs.bb[CAp] = prev_res_atoms[a].index(); }
     724      401292 :       else if(AN=="HA"||AN=="HA1"||AN=="HA3") { tmp_cs.bb[HAp] = prev_res_atoms[a].index(); }
     725      136692 :       else if(AN=="C" )                       { tmp_cs.bb[Cp]  = prev_res_atoms[a].index(); }
     726      126090 :       else if(AN=="O" )                       { tmp_cs.bb[Op]  = prev_res_atoms[a].index(); }
     727             :     }
     728             : 
     729      509202 :     for(unsigned a=0; a<res_atoms.size(); a++) {
     730      162666 :       string AN = pdb.getAtomName(res_atoms[a]);
     731      173268 :       if(AN=="N")                                         { tmp_cs.bb[Nc]  = res_atoms[a].index(); }
     732      448884 :       else if(AN=="H" ||AN=="HN"||(AN=="CD"&&RES=="PRO")) { tmp_cs.bb[Hc]  = res_atoms[a].index(); }
     733      152064 :       else if(AN=="CA")                                   { tmp_cs.bb[CAc] = res_atoms[a].index(); }
     734      383472 :       else if(AN=="HA"||AN=="HA1"||AN=="HA3")             { tmp_cs.bb[HAc] = res_atoms[a].index(); }
     735      130860 :       else if(AN=="C" )                                   { tmp_cs.bb[Cc]  = res_atoms[a].index(); }
     736      120258 :       else if(AN=="O" )                                   { tmp_cs.bb[Oc]  = res_atoms[a].index(); }
     737             : 
     738      318852 :       if(RES!="ALA"&&RES!="GLY") {
     739      154188 :         if(AN=="CB") tmp_cs.bb[CBc] = res_atoms[a].index();
     740      154188 :         if(is_chi1_cx(RES,AN)) tmp_cs.bb[CGc] = res_atoms[a].index();
     741             :       }
     742             :     }
     743             : 
     744       10602 :     vector<AtomNumber> next_res_atoms = pdb.getAtomsInResidue(resnum+1, chains[ichain]);
     745       10602 :     string NRES = pdb.getResidueName(resnum+1, chains[ichain]);
     746             :     // find the position of the previous residues backbone atoms
     747      496242 :     for(unsigned a=0; a<next_res_atoms.size(); a++) {
     748      158346 :       string AN = pdb.getAtomName(next_res_atoms[a]);
     749      168948 :       if(AN=="N")                                          { tmp_cs.bb[Nn]  = next_res_atoms[a].index(); }
     750      436698 :       else if(AN=="H" ||AN=="HN"||(AN=="CD"&&NRES=="PRO")) { tmp_cs.bb[Hn]  = next_res_atoms[a].index(); }
     751      147744 :       else if(AN=="CA")                                    { tmp_cs.bb[CAn] = next_res_atoms[a].index(); }
     752      370800 :       else if(AN=="HA"||AN=="HA1"||AN=="HA3")              { tmp_cs.bb[HAn] = next_res_atoms[a].index(); }
     753      126540 :       else if(AN=="C" )                                    { tmp_cs.bb[Cn]  = next_res_atoms[a].index(); }
     754             :     }
     755             : 
     756             :     // set sidechain atoms
     757       21204 :     vector<string> sc_atm = side_chain_atoms(RES);
     758             : 
     759      412650 :     for(unsigned sc=0; sc<sc_atm.size(); sc++) {
     760     7373142 :       for(unsigned aa=0; aa<res_atoms.size(); aa++) {
     761     4741452 :         if(pdb.getAtomName(res_atoms[aa])==sc_atm[sc]) {
     762      198324 :           tmp_cs.side_chain.push_back(res_atoms[aa].index());
     763             :         }
     764             :       }
     765             :     }
     766             : 
     767             :     // find atoms for extra distances
     768      296856 :     const string atomsP1[] =  {"H", "H", "H", "C", "C", "C", "O", "O", "O", "N", "N", "N", "O", "O", "O", "N", "N", "N", "CG", "CG", "CG", "CG", "CG", "CG", "CG", "CA"};
     769       10602 :     const int resOffsetP1[] = { 0,   0,   0,  -1,  -1,  -1,   0,   0,   0,   1,   1,   1,   -1,  -1,  -1,  0,   0,   0,   0,    0,    0,    0,    0,    -1,   1,    -1};
     770             : 
     771      296856 :     const string atomsP2[] =  {"HA", "C", "CB", "HA", "C", "CB", "HA", "N", "CB", "HA", "N", "CB", "HA", "N", "CB", "HA", "N", "CB", "HA", "N", "C", "C", "N", "CA", "CA", "CA"};
     772       10602 :     const int resOffsetP2[] = { 0,    0,   0,    0,    0,   0,    0,    0,   0,    0,    0,   0,    -1,  -1,   -1,   -1,  -1,   -1,   0,    0,   0,   -1,  1,   0,    0,    1};
     773             : 
     774      561906 :     for(unsigned q=0; q<db.get_numXtraDists()-1; q++) {
     775             :       vector<AtomNumber> at1;
     776      275652 :       if(resOffsetP1[q]== 0) at1 = res_atoms;
     777      275652 :       if(resOffsetP1[q]==-1) at1 = prev_res_atoms;
     778      275652 :       if(resOffsetP1[q]==+1) at1 = next_res_atoms;
     779             : 
     780             :       vector<AtomNumber> at2;
     781      275652 :       if(resOffsetP2[q]== 0) at2 = res_atoms;
     782      275652 :       if(resOffsetP2[q]==-1) at2 = prev_res_atoms;
     783      275652 :       if(resOffsetP2[q]==+1) at2 = next_res_atoms;
     784             : 
     785      275652 :       int tmp1 = -1;
     786     6317046 :       for(unsigned a=0; a<at1.size(); a++) {
     787     2181708 :         string name = pdb.getAtomName(at1[a]);
     788     2181708 :         xdist_name_map(name);
     789             : 
     790     2181708 :         if(name==atomsP1[q]) {
     791      259794 :           tmp1 = at1[a].index();
     792             :           break;
     793             :         }
     794             :       }
     795             : 
     796      275652 :       int tmp2 = -1;
     797     4007412 :       for(unsigned a=0; a<at2.size(); a++) {
     798             :         string name = pdb.getAtomName(at2[a]);
     799     1418076 :         xdist_name_map(name);
     800             : 
     801     1418076 :         if(name==atomsP2[q]) {
     802      266040 :           tmp2 = at2[a].index();
     803             :           break;
     804             :         }
     805             :       }
     806             : 
     807      275652 :       tmp_cs.xd1.push_back(tmp1);
     808      275652 :       tmp_cs.xd2.push_back(tmp2);
     809             :     }
     810             : 
     811             :     // ready to add a new chemical shifts
     812       21204 :     tmp_cs.csatoms = 1 + 16 + tmp_cs.side_chain.size() + 2*tmp_cs.xd1.size();
     813       20556 :     if(tmp_cs.res_name!="ALA"&&tmp_cs.res_name!="GLY") tmp_cs.csatoms += 2;
     814       10602 :     chemicalshifts.push_back(tmp_cs);
     815             :   }
     816             : 
     817         108 :   in.close();
     818             : }
     819             : 
     820             : // this assigns an atom-type to each atom of the pdb
     821          18 : void CS2Backbone::init_types(const PDB &pdb) {
     822             :   enum atom_t {D_C, D_H, D_N, D_O, D_S, D_C2, D_N2, D_O2};
     823          18 :   vector<AtomNumber> aa = pdb.getAtomNumbers();
     824      141084 :   for(unsigned i=0; i<aa.size(); i++) {
     825       47016 :     unsigned frag = pdb.getResidueNumber(aa[i]);
     826       47016 :     string fragName = pdb.getResidueName(aa[i]);
     827       47016 :     string atom_name = pdb.getAtomName(aa[i]);
     828       47016 :     char atom_type = atom_name[0];
     829       47016 :     if(isdigit(atom_name[0])) atom_type = atom_name[1];
     830       47016 :     res_num.push_back(frag);
     831       47016 :     unsigned t = 0;
     832       47016 :     if (!isSP2(fragName, atom_name)) {
     833       36936 :       if (atom_type == 'C') t = D_C;
     834       27918 :       else if (atom_type == 'O') t = D_O;
     835       27450 :       else if (atom_type == 'H') t = D_H;
     836        4194 :       else if (atom_type == 'N') t = D_N;
     837         162 :       else if (atom_type == 'S') t = D_S;
     838           0 :       else plumed_merror("Unknown atom type: " + atom_name);
     839             :     } else {
     840       10080 :       if (atom_type == 'C') t = D_C2;
     841        4104 :       else if (atom_type == 'O') t = D_O2;
     842           0 :       else if (atom_type == 'N') t = D_N2;
     843           0 :       else plumed_merror("Unknown atom type: " + atom_name);
     844             :     }
     845       47016 :     type.push_back(t);
     846             :   }
     847          18 : }
     848             : 
     849          18 : void CS2Backbone::init_rings(const PDB &pdb)
     850             : {
     851         144 :   const string pheTyr_n[] = {"CG","CD1","CE1","CZ","CE2","CD2"};
     852         144 :   const string trp1_n[]   = {"CD2","CE2","CZ2","CH2","CZ3","CE3"};
     853         126 :   const string trp2_n[]   = {"CG","CD1","NE1","CE2","CD2"};
     854         126 :   const string his_n[]    = {"CG","ND1","CD2","CE1","NE2"};
     855             : 
     856             :   // number of chains
     857          18 :   vector<string> chains;
     858          18 :   pdb.getChainNames( chains );
     859             :   unsigned total_rings_atoms = 0;
     860             : 
     861             :   // cycle over chains
     862         144 :   for(unsigned i=0; i<chains.size(); i++) {
     863             :     unsigned start, end;
     864             :     string errmsg;
     865          36 :     pdb.getResidueRange( chains[i], start, end, errmsg );
     866             :     // cycle over residues
     867        3168 :     for(unsigned res=start; res<end; res++) {
     868        3132 :       string frg = pdb.getResidueName(res, chains[i]);
     869       14364 :       if(!((frg=="PHE")||(frg=="TYR")||(frg=="TRP")||
     870        8370 :            (frg=="HIS")||(frg=="HIP")||(frg=="HID")||
     871        5580 :            (frg=="HIE")||(frg=="HSD")||(frg=="HSE")||
     872             :            (frg=="HSP"))) continue;
     873             : 
     874         342 :       vector<AtomNumber> frg_atoms = pdb.getAtomsInResidue(res,chains[i]);
     875             : 
     876         396 :       if(frg=="PHE"||frg=="TYR") {
     877         324 :         RingInfo ri;
     878       20196 :         for(unsigned a=0; a<frg_atoms.size(); a++) {
     879             :           unsigned atm = frg_atoms[a].index();
     880       71100 :           for(unsigned aa=0; aa<6; aa++) {
     881      102708 :             if(pdb.getAtomName(frg_atoms[a])==pheTyr_n[aa]) {
     882        1944 :               ri.atom[aa] = atm;
     883        1944 :               break;
     884             :             }
     885             :           }
     886             :         }
     887         324 :         ri.numAtoms = 6;
     888         324 :         total_rings_atoms += 6;
     889         324 :         if(frg=="PHE") ri.rtype = RingInfo::R_PHE;
     890         324 :         if(frg=="TYR") ri.rtype = RingInfo::R_TYR;
     891         324 :         ringInfo.push_back(ri);
     892             : 
     893          18 :       } else if(frg=="TRP") {
     894             :         //First ring
     895          18 :         RingInfo ri;
     896        1332 :         for(unsigned a=0; a<frg_atoms.size(); a++) {
     897             :           unsigned atm = frg_atoms[a].index();
     898        4860 :           for(unsigned aa=0; aa<6; aa++) {
     899        6966 :             if(pdb.getAtomName(frg_atoms[a])==trp1_n[aa]) {
     900         108 :               ri.atom[aa] = atm;
     901         108 :               break;
     902             :             }
     903             :           }
     904             :         }
     905          18 :         ri.numAtoms = 6;
     906             :         total_rings_atoms += 6;
     907          18 :         ri.rtype = RingInfo::R_TRP1;
     908          18 :         ringInfo.push_back(ri);
     909             :         //Second Ring
     910          18 :         RingInfo ri2;
     911        1332 :         for(unsigned a=0; a<frg_atoms.size(); a++) {
     912             :           unsigned atm = frg_atoms[a].index();
     913        4212 :           for(unsigned aa=0; aa<5; aa++) {
     914        5940 :             if(pdb.getAtomName(frg_atoms[a])==trp2_n[aa]) {
     915          90 :               ri2.atom[aa] = atm;
     916          90 :               break;
     917             :             }
     918             :           }
     919             :         }
     920          18 :         ri2.numAtoms = 5;
     921          18 :         total_rings_atoms += 3;
     922          18 :         ri2.rtype = RingInfo::R_TRP2;
     923          18 :         ringInfo.push_back(ri2);
     924             : 
     925           0 :       } else if((frg=="HIS")||(frg=="HIP")||(frg=="HID")||
     926           0 :                 (frg=="HIE")||(frg=="HSD")||(frg=="HSE")||
     927             :                 (frg=="HSP")) {//HIS case
     928           0 :         RingInfo ri;
     929           0 :         for(unsigned a=0; a<frg_atoms.size(); a++) {
     930             :           unsigned atm = frg_atoms[a].index();
     931           0 :           for(unsigned aa=0; aa<5; aa++) {
     932           0 :             if(pdb.getAtomName(frg_atoms[a])==his_n[aa]) {
     933           0 :               ri.atom[aa] = atm;
     934           0 :               break;
     935             :             }
     936             :           }
     937             :         }
     938           0 :         ri.numAtoms = 5;
     939           0 :         total_rings_atoms += 3;
     940           0 :         ri.rtype = RingInfo::R_HIS;
     941           0 :         ringInfo.push_back(ri);
     942             :       } else {
     943           0 :         plumed_merror("Unknown Ring Fragment: " + frg);
     944             :       }
     945             :     }
     946             :   }
     947             : 
     948       31842 :   for(unsigned cs=0; cs<chemicalshifts.size(); cs++) chemicalshifts[cs].csatoms += total_rings_atoms;
     949          18 : }
     950             : 
     951          18 : void CS2Backbone::calculate()
     952             : {
     953          18 :   if(pbc) makeWhole();
     954          18 :   if(getExchangeStep()) box_count=0;
     955          18 :   if(box_count==0) update_neighb();
     956          18 :   compute_ring_parameters();
     957             : 
     958          18 :   vector<double> camshift_sigma2(6);
     959          18 :   camshift_sigma2[0] = 0.08; // HA
     960          18 :   camshift_sigma2[1] = 0.30; // HN
     961          18 :   camshift_sigma2[2] = 9.00; // NH
     962          18 :   camshift_sigma2[3] = 1.30; // CA
     963          18 :   camshift_sigma2[4] = 1.56; // CB
     964          18 :   camshift_sigma2[5] = 1.70; // CO
     965             : 
     966             :   vector<Vector>   cs_derivs;
     967             :   vector<Vector>   aa_derivs;
     968             :   vector<unsigned> cs_atoms;
     969             :   vector<double>   all_shifts;
     970             : 
     971          36 :   cs_derivs.resize(chemicalshifts.size()*max_cs_atoms,Vector(0,0,0));
     972          36 :   cs_atoms.resize(chemicalshifts.size()*max_cs_atoms,0);
     973          36 :   all_shifts.resize(chemicalshifts.size(),0);
     974          40 :   if(camshift||getDoScore()) aa_derivs.resize(getNumberOfAtoms(),Vector(0,0,0));
     975             : 
     976          18 :   unsigned stride = comm.Get_size();
     977          18 :   unsigned rank   = comm.Get_rank();
     978          18 :   if(serial) {
     979             :     stride = 1;
     980             :     rank   = 0;
     981             :   }
     982             : 
     983          18 :   unsigned nt=OpenMP::getNumThreads();
     984          36 :   if(nt*stride*2>chemicalshifts.size()) nt=1;
     985             : 
     986             :   // a single loop over all chemical shifts
     987          54 :   #pragma omp parallel num_threads(nt)
     988             :   {
     989             :     #pragma omp for schedule(dynamic)
     990             :     for(unsigned cs=rank; cs<chemicalshifts.size(); cs+=stride) {
     991        5890 :       const unsigned kdx=cs*max_cs_atoms;
     992        5890 :       const ChemicalShift *myfrag = &chemicalshifts[cs];
     993        5890 :       const unsigned aa_kind = myfrag->res_kind;
     994        5890 :       const unsigned at_kind = myfrag->atm_kind;
     995             : 
     996       11780 :       double shift = db.CONSTAAPREV(aa_kind,at_kind)[myfrag->res_type_prev] +
     997        5890 :                      db.CONSTAACURR(aa_kind,at_kind)[myfrag->res_type_curr] +
     998        5890 :                      db.CONSTAANEXT(aa_kind,at_kind)[myfrag->res_type_next];
     999             : 
    1000        5890 :       const unsigned ipos = myfrag->ipos;
    1001       11780 :       cs_atoms[kdx+0] = ipos;
    1002             :       unsigned atom_counter = 1;
    1003             : 
    1004             :       //BACKBONE (PREV CURR NEXT)
    1005             :       const double * CONST_BB2 = db.CONST_BB2(aa_kind,at_kind);
    1006             :       const unsigned bbsize = 16;
    1007      194370 :       for(unsigned q=0; q<bbsize; q++) {
    1008       94240 :         const double cb2q = CONST_BB2[q];
    1009      128120 :         if(cb2q==0.) continue;
    1010       77300 :         const unsigned jpos = myfrag->bb[q];
    1011       77300 :         if(ipos==jpos) continue;
    1012      231900 :         const Vector distance = delta(getPosition(jpos),getPosition(ipos));
    1013       77300 :         const double d = distance.modulo();
    1014       77300 :         const double fact = cb2q/d;
    1015             : 
    1016       77300 :         shift += cb2q*d;
    1017       77300 :         const Vector der = fact*distance;
    1018             : 
    1019      154600 :         cs_derivs[kdx+0] += der;
    1020      154600 :         cs_derivs[kdx+q+atom_counter] = -der;
    1021      154600 :         cs_atoms[kdx+q+atom_counter] = jpos;
    1022             :       }
    1023             : 
    1024             :       atom_counter += bbsize;
    1025             : 
    1026             :       //DIHEDRAL ANGLES
    1027             :       const double *CO_DA = db.CO_DA(aa_kind,at_kind);
    1028             :       //Phi
    1029             :       {
    1030       17670 :         const Vector d0 = delta(getPosition(myfrag->bb[Nc]), getPosition(myfrag->bb[Cp]));
    1031       17670 :         const Vector d1 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
    1032       17670 :         const Vector d2 = delta(getPosition(myfrag->bb[Cc]), getPosition(myfrag->bb[CAc]));
    1033             :         Torsion t;
    1034        5890 :         Vector dd0, dd1, dd2;
    1035        5890 :         const double t_phi = t.compute(d0,d1,d2,dd0,dd1,dd2);
    1036             :         const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,0);
    1037        5890 :         const double val1 = 3.*t_phi+PARS_DA[3];
    1038        5890 :         const double val2 = t_phi+PARS_DA[4];
    1039        5890 :         shift += CO_DA[0]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
    1040        5890 :         const double fact = -CO_DA[0]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
    1041             : 
    1042       11780 :         cs_derivs[kdx+Cp+1] += fact*dd0;
    1043       11780 :         cs_derivs[kdx+Nc+1] += fact*(dd1-dd0);
    1044       11780 :         cs_derivs[kdx+CAc+1]+= fact*(dd2-dd1);
    1045       11780 :         cs_derivs[kdx+Cc+1] += -fact*dd2;
    1046       11780 :         cs_atoms[kdx+Cp+1] = myfrag->bb[Cp];
    1047        5890 :         cs_atoms[kdx+Nc+1] = myfrag->bb[Nc];
    1048        5890 :         cs_atoms[kdx+CAc+1]= myfrag->bb[CAc];
    1049        5890 :         cs_atoms[kdx+Cc+1] = myfrag->bb[Cc];
    1050             :       }
    1051             : 
    1052             :       //Psi
    1053             :       {
    1054       17670 :         const Vector d0 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
    1055       17670 :         const Vector d1 = delta(getPosition(myfrag->bb[Cc]), getPosition(myfrag->bb[CAc]));
    1056       17670 :         const Vector d2 = delta(getPosition(myfrag->bb[Nn]), getPosition(myfrag->bb[Cc]));
    1057             :         Torsion t;
    1058        5890 :         Vector dd0, dd1, dd2;
    1059        5890 :         const double t_psi = t.compute(d0,d1,d2,dd0,dd1,dd2);
    1060             :         const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,1);
    1061        5890 :         const double val1 = 3.*t_psi+PARS_DA[3];
    1062        5890 :         const double val2 = t_psi+PARS_DA[4];
    1063        5890 :         shift += CO_DA[1]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
    1064        5890 :         const double fact = -CO_DA[1]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
    1065             : 
    1066       11780 :         cs_derivs[kdx+Nc+1] += fact*dd0;
    1067       11780 :         cs_derivs[kdx+CAc+1] += fact*(dd1-dd0);
    1068       11780 :         cs_derivs[kdx+Cc+1] += fact*(dd2-dd1);
    1069       11780 :         cs_derivs[kdx+Nn+1] += -fact*dd2;
    1070       11780 :         cs_atoms[kdx+Nc+1] = myfrag->bb[Nc];
    1071        5890 :         cs_atoms[kdx+CAc+1]= myfrag->bb[CAc];
    1072        5890 :         cs_atoms[kdx+Cc+1] = myfrag->bb[Cc];
    1073        5890 :         cs_atoms[kdx+Nn+1] = myfrag->bb[Nn];
    1074             :       }
    1075             : 
    1076             :       //Chi
    1077        5890 :       if(myfrag->has_chi1) {
    1078       14100 :         const Vector d0 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
    1079       14100 :         const Vector d1 = delta(getPosition(myfrag->bb[CBc]), getPosition(myfrag->bb[CAc]));
    1080       14100 :         const Vector d2 = delta(getPosition(myfrag->bb[CGc]), getPosition(myfrag->bb[CBc]));
    1081             :         Torsion t;
    1082        4700 :         Vector dd0, dd1, dd2;
    1083        4700 :         const double t_chi1 = t.compute(d0,d1,d2,dd0,dd1,dd2);
    1084             :         const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,2);
    1085        4700 :         const double val1 = 3.*t_chi1+PARS_DA[3];
    1086        4700 :         const double val2 = t_chi1+PARS_DA[4];
    1087        4700 :         shift += CO_DA[2]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
    1088        4700 :         const double fact = -CO_DA[2]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
    1089             : 
    1090        9400 :         cs_derivs[kdx+Nc+1] += fact*dd0;
    1091        9400 :         cs_derivs[kdx+CAc+1] += fact*(dd1-dd0);
    1092        9400 :         cs_derivs[kdx+CBc+1] += fact*(dd2-dd1);
    1093        9400 :         cs_derivs[kdx+CGc+1] += -fact*dd2;
    1094        9400 :         cs_atoms[kdx+Nc+1]  = myfrag->bb[Nc];
    1095        4700 :         cs_atoms[kdx+CAc+1] = myfrag->bb[CAc];
    1096        4700 :         cs_atoms[kdx+CBc+1] = myfrag->bb[CBc];
    1097        4700 :         cs_atoms[kdx+CGc+1] = myfrag->bb[CGc];
    1098             : 
    1099             :         atom_counter += 2;
    1100             :       }
    1101             :       //END OF DIHE
    1102             : 
    1103             :       //SIDE CHAIN
    1104        5890 :       const double * CONST_SC2 = db.CONST_SC2(aa_kind,at_kind,myfrag->res_type_curr);
    1105        5890 :       const unsigned sidsize = myfrag->side_chain.size();
    1106      116070 :       for(unsigned q=0; q<sidsize; q++) {
    1107       55090 :         const double cs2q = CONST_SC2[q];
    1108      118030 :         if(cs2q==0.) continue;
    1109       23620 :         const unsigned jpos = myfrag->side_chain[q];
    1110       23620 :         if(ipos==jpos) continue;
    1111       70860 :         const Vector distance = delta(getPosition(jpos),getPosition(ipos));
    1112       23620 :         const double d = distance.modulo();
    1113       23620 :         const double fact = cs2q/d;
    1114             : 
    1115       23620 :         shift += cs2q*d;
    1116       23620 :         const Vector der = fact*distance;
    1117       47240 :         cs_derivs[kdx+0] += der;
    1118       47240 :         cs_derivs[kdx+q+atom_counter] = -der;
    1119       47240 :         cs_atoms[kdx+q+atom_counter] = jpos;
    1120             :       }
    1121             : 
    1122        5890 :       atom_counter += sidsize;
    1123             : 
    1124             :       //EXTRA DIST
    1125             :       const double * CONST_XD  = db.CONST_XD(aa_kind,at_kind);
    1126        5890 :       const unsigned xdsize=myfrag->xd1.size();
    1127      312170 :       for(unsigned q=0; q<xdsize; q++) {
    1128      153140 :         const double cxdq = CONST_XD[q];
    1129      170790 :         if(cxdq==0.) continue;
    1130      301300 :         if(myfrag->xd1[q]==-1||myfrag->xd2[q]==-1) continue;
    1131      138990 :         const Vector distance = delta(getPosition(myfrag->xd1[q]),getPosition(myfrag->xd2[q]));
    1132      138990 :         const double d = distance.modulo();
    1133      138990 :         const double fact = cxdq/d;
    1134             : 
    1135      138990 :         shift += cxdq*d;
    1136      138990 :         const Vector der = fact*distance;
    1137      277980 :         cs_derivs[kdx+2*q+atom_counter  ] = der;
    1138      277980 :         cs_derivs[kdx+2*q+atom_counter+1] = -der;
    1139      277980 :         cs_atoms[kdx+2*q+atom_counter] = myfrag->xd2[q];
    1140      277980 :         cs_atoms[kdx+2*q+atom_counter+1] = myfrag->xd1[q];
    1141             :       }
    1142             : 
    1143        5890 :       atom_counter += 2*xdsize;
    1144             : 
    1145             :       //RINGS
    1146             :       const double *rc = db.CO_RING(aa_kind,at_kind);
    1147        5890 :       const unsigned rsize = ringInfo.size();
    1148             :       // cycle over the list of rings
    1149      241490 :       for(unsigned q=0; q<rsize; q++) {
    1150             :         // compute angle from ring middle point to current atom position
    1151             :         // get distance vector from query atom to ring center and normal vector to ring plane
    1152      235600 :         const Vector n   = ringInfo[q].normVect;
    1153      117800 :         const double nL  = ringInfo[q].lengthNV;
    1154      117800 :         const double inL2 = ringInfo[q].lengthN2;
    1155             : 
    1156      235600 :         const Vector d = delta(ringInfo[q].position, getPosition(ipos));
    1157      117800 :         const double dL2 = d.modulo2();
    1158      117800 :         double dL  = sqrt(dL2);
    1159      117800 :         const double idL3 = 1./(dL2*dL);
    1160             : 
    1161      117800 :         const double dn    = dotProduct(d,n);
    1162      117800 :         const double dn2   = dn*dn;
    1163      117800 :         const double dLnL  = dL*nL;
    1164      117800 :         const double dL_nL = dL/nL;
    1165             : 
    1166      117800 :         const double ang2 = dn2*inL2/dL2;
    1167      117800 :         const double u    = 1.-3.*ang2;
    1168      117800 :         const double cc   = rc[ringInfo[q].rtype];
    1169             : 
    1170      117800 :         shift += cc*u*idL3;
    1171             : 
    1172      117800 :         const double fUU    = -6.*dn*inL2;
    1173      117800 :         const double fUQ    = fUU/dL;
    1174      117800 :         const Vector gradUQ = fUQ*(dL2*n - dn*d);
    1175      117800 :         const Vector gradVQ = (3.*dL*u)*d;
    1176             : 
    1177      117800 :         const double fact   = cc*idL3*idL3;
    1178      235600 :         cs_derivs[kdx+0] += fact*(gradUQ - gradVQ);
    1179             : 
    1180      117800 :         const double fU       = fUU/nL;
    1181             :         double OneOverN = 1./6.;
    1182      117800 :         if(ringInfo[q].numAtoms==5) OneOverN=1./3.;
    1183      117800 :         const Vector factor2  = OneOverN*n;
    1184      117800 :         const Vector factor4  = (OneOverN/dL_nL)*d;
    1185             : 
    1186      117800 :         const Vector gradV    = -OneOverN*gradVQ;
    1187             : 
    1188      117800 :         if(ringInfo[q].numAtoms==6) {
    1189             :           // update forces on ring atoms
    1190     1454830 :           for(unsigned at=0; at<6; at++) {
    1191      671460 :             const Vector ab = crossProduct(d,ringInfo[q].g[at]);
    1192      671460 :             const Vector c  = crossProduct(n,ringInfo[q].g[at]);
    1193      671460 :             const Vector factor3 = 0.5*dL_nL*c;
    1194      671460 :             const Vector factor1 = 0.5*ab;
    1195      671460 :             const Vector gradU   = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
    1196     1342920 :             cs_derivs[kdx+at+atom_counter] = fact*(gradU - gradV);
    1197     1342920 :             cs_atoms[kdx+at+atom_counter] = ringInfo[q].atom[at];
    1198             :           }
    1199      111910 :           atom_counter += 6;
    1200             :         }  else {
    1201       41230 :           for(unsigned at=0; at<3; at++) {
    1202       17670 :             const Vector ab = crossProduct(d,ringInfo[q].g[at]);
    1203       17670 :             const Vector c  = crossProduct(n,ringInfo[q].g[at]);
    1204       17670 :             const Vector factor3 = dL_nL*c;
    1205       17670 :             const Vector factor1 = ab;
    1206       17670 :             const Vector gradU   = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
    1207       35340 :             cs_derivs[kdx+at+atom_counter] = fact*(gradU - gradV);
    1208             :           }
    1209       11780 :           cs_atoms[kdx+atom_counter] = ringInfo[q].atom[0];
    1210       11780 :           cs_atoms[kdx+atom_counter+1] = ringInfo[q].atom[2];
    1211       11780 :           cs_atoms[kdx+atom_counter+2] = ringInfo[q].atom[3];
    1212        5890 :           atom_counter += 3;
    1213             :         }
    1214             :       }
    1215             :       //END OF RINGS
    1216             : 
    1217             :       //NON BOND
    1218             :       const double * CONST_CO_SPHERE3 = db.CO_SPHERE(aa_kind,at_kind,0);
    1219             :       const double * CONST_CO_SPHERE  = db.CO_SPHERE(aa_kind,at_kind,1);
    1220        5890 :       const unsigned boxsize = myfrag->box_nb.size();
    1221      496838 :       for(unsigned q=0; q<boxsize; q++) {
    1222      490948 :         const unsigned jpos = myfrag->box_nb[q];
    1223      736422 :         const Vector distance = delta(getPosition(jpos),getPosition(ipos));
    1224      245474 :         const double d2 = distance.modulo2();
    1225             : 
    1226      245474 :         if(d2<cutOffDist2) {
    1227      108442 :           double factor1  = sqrt(d2);
    1228      108442 :           double dfactor1 = 1./factor1;
    1229      108442 :           double factor3  = dfactor1*dfactor1*dfactor1;
    1230      108442 :           double dfactor3 = -3.*factor3*dfactor1*dfactor1;
    1231             : 
    1232      108442 :           if(d2>cutOnDist2) {
    1233      101620 :             const double af = cutOffDist2 - d2;
    1234      101620 :             const double bf = cutOffDist2 - 3.*cutOnDist2 + 2.*d2;
    1235      101620 :             const double cf = invswitch*af;
    1236      101620 :             const double df = cf*af*bf;
    1237      101620 :             factor1 *= df;
    1238      101620 :             factor3 *= df;
    1239             : 
    1240      101620 :             const double d4  = d2*d2;
    1241      101620 :             const double af1 = 15.*cutOnDist2*d2;
    1242      101620 :             const double bf1 = -14.*d4;
    1243      101620 :             const double cf1 = -3.*cutOffDist2*cutOnDist2 + cutOffDist2*d2;
    1244      101620 :             const double df1 = af1+bf1+cf1;
    1245      101620 :             dfactor1 *= cf*(cutOffDist4+df1);
    1246             : 
    1247             :             const double af3 = +2.*cutOffDist2*cutOnDist2;
    1248      101620 :             const double bf3 = d2*(cutOffDist2+cutOnDist2);
    1249      101620 :             const double cf3 = -2.*d4;
    1250      101620 :             const double df3 = (af3+bf3+cf3)*d2;
    1251      101620 :             dfactor3 *= invswitch*(cutMixed+df3);
    1252             :           }
    1253             : 
    1254      216884 :           const unsigned t = type[jpos];
    1255      108442 :           shift += factor1*CONST_CO_SPHERE[t] + factor3*CONST_CO_SPHERE3[t] ;
    1256      108442 :           const double fact = dfactor1*CONST_CO_SPHERE[t]+dfactor3*CONST_CO_SPHERE3[t];
    1257      108442 :           const Vector der  = fact*distance;
    1258             : 
    1259      216884 :           cs_derivs[kdx+0] += der;
    1260      216884 :           cs_derivs[kdx+q+atom_counter] = -der;
    1261      216884 :           cs_atoms[kdx+q+atom_counter] = jpos;
    1262             :         }
    1263             :       }
    1264             :       //END NON BOND
    1265             : 
    1266             :       atom_counter += boxsize;
    1267       11780 :       all_shifts[cs] = shift;
    1268             :     }
    1269             :   }
    1270             : 
    1271          18 :   ++box_count;
    1272          18 :   if(box_count == box_nupdate) box_count = 0;
    1273             : 
    1274          18 :   if(!camshift) {
    1275          13 :     if(!serial) {
    1276          13 :       if(!getDoScore()) {
    1277          18 :         comm.Sum(&cs_derivs[0][0], 3*cs_derivs.size());
    1278          18 :         comm.Sum(&cs_atoms[0], cs_atoms.size());
    1279             :       }
    1280          39 :       comm.Sum(&all_shifts[0], chemicalshifts.size());
    1281             :     }
    1282       22997 :     for(unsigned cs=0; cs<chemicalshifts.size(); cs++) {
    1283        7657 :       Value *comp = chemicalshifts[cs].comp;
    1284        7657 :       comp->set(all_shifts[cs]);
    1285       10013 :       if(getDoScore()) setCalcData(cs, all_shifts[cs]);
    1286             :       else {
    1287        5301 :         const unsigned kdx=cs*max_cs_atoms;
    1288        5301 :         Tensor csvirial;
    1289     2534953 :         for(unsigned i=0; i<chemicalshifts[cs].totcsatoms; i++) {
    1290     2529652 :           setAtomsDerivatives(comp,cs_atoms[kdx+i],cs_derivs[kdx+i]);
    1291     2529652 :           csvirial-=Tensor(getPosition(cs_atoms[kdx+i]),cs_derivs[kdx+i]);
    1292             :         }
    1293        5301 :         setBoxDerivatives(comp,csvirial);
    1294             :       }
    1295             :     }
    1296          13 :     if(!getDoScore()) return;
    1297             :   }
    1298             : 
    1299           9 :   double score = 0.;
    1300             : 
    1301             :   /* Metainference */
    1302           9 :   if(getDoScore()) {
    1303           4 :     score = getScore();
    1304        3542 :     for(unsigned cs=rank; cs<chemicalshifts.size(); cs+=stride) {
    1305        1178 :       const unsigned kdx=cs*max_cs_atoms;
    1306             :       const double fact = getMetaDer(cs);
    1307      563252 :       for(unsigned i=0; i<chemicalshifts[cs].totcsatoms; i++) {
    1308     1124148 :         aa_derivs[cs_atoms[kdx+i]] += cs_derivs[kdx+i]*fact;
    1309             :       }
    1310             :     }
    1311             :   }
    1312             : 
    1313             :   /* camshift */
    1314           9 :   if(camshift) {
    1315        5311 :     for(unsigned cs=rank; cs<chemicalshifts.size(); cs+=stride) {
    1316        1767 :       const unsigned kdx=cs*max_cs_atoms;
    1317        5301 :       score += (all_shifts[cs] - chemicalshifts[cs].exp_cs)*(all_shifts[cs] - chemicalshifts[cs].exp_cs)/camshift_sigma2[chemicalshifts[cs].atm_kind];
    1318        1767 :       double fact = 2.0*(all_shifts[cs] - chemicalshifts[cs].exp_cs)/camshift_sigma2[chemicalshifts[cs].atm_kind];
    1319      845197 :       for(unsigned i=0; i<chemicalshifts[cs].totcsatoms; i++) {
    1320     1686860 :         aa_derivs[cs_atoms[kdx+i]] += cs_derivs[kdx+i]*fact;
    1321             :       }
    1322             :     }
    1323             :   }
    1324             : 
    1325           9 :   if(!serial) {
    1326          18 :     comm.Sum(&aa_derivs[0][0], 3*aa_derivs.size());
    1327           9 :     if(camshift) comm.Sum(&score, 1);
    1328             :   }
    1329             : 
    1330           9 :   Tensor virial;
    1331       26129 :   for(unsigned i=rank; i<getNumberOfAtoms(); i+=stride) {
    1332       39180 :     virial += Tensor(getPosition(i), aa_derivs[i]);
    1333             :   }
    1334             : 
    1335           9 :   if(!serial) {
    1336           9 :     comm.Sum(&virial[0][0], 9);
    1337             :   }
    1338             : 
    1339             :   /* calculate final derivatives */
    1340             :   Value* val;
    1341           9 :   if(getDoScore()) {
    1342           8 :     val=getPntrToComponent("score");
    1343           4 :     setScore(score);
    1344             :   } else {
    1345           5 :     val=getPntrToValue();
    1346           5 :     setValue(score);
    1347             :   }
    1348             : 
    1349             :   /* at this point we cycle over all atoms */
    1350       47025 :   for(unsigned i=0; i<getNumberOfAtoms(); i++) setAtomsDerivatives(val, i,  aa_derivs[i]);
    1351           9 :   setBoxDerivatives(val,-virial);
    1352             : }
    1353             : 
    1354          18 : void CS2Backbone::update_neighb() {
    1355          18 :   max_cs_atoms=0;
    1356             :   // cycle over chemical shifts
    1357       31842 :   for(unsigned cs=0; cs<chemicalshifts.size(); cs++) {
    1358             :     const unsigned boxsize = getNumberOfAtoms();
    1359             :     chemicalshifts[cs].box_nb.clear();
    1360       10602 :     chemicalshifts[cs].box_nb.reserve(150);
    1361       21204 :     const unsigned res_curr = res_num[chemicalshifts[cs].ipos];
    1362    27703026 :     for(unsigned bat=0; bat<boxsize; bat++) {
    1363    55384848 :       const unsigned res_dist = abs(static_cast<int>(res_curr-res_num[bat]));
    1364    27692424 :       if(res_dist<2) continue;
    1365    81640548 :       const Vector distance = delta(getPosition(bat),getPosition(chemicalshifts[cs].ipos));
    1366    27213516 :       const double d2=distance.modulo2();
    1367    27655114 :       if(d2<cutOffNB2) chemicalshifts[cs].box_nb.push_back(bat);
    1368             :     }
    1369       21204 :     chemicalshifts[cs].totcsatoms = chemicalshifts[cs].csatoms + chemicalshifts[cs].box_nb.size();
    1370       10602 :     if(chemicalshifts[cs].totcsatoms>max_cs_atoms) max_cs_atoms = chemicalshifts[cs].totcsatoms;
    1371             :   }
    1372          18 : }
    1373             : 
    1374          18 : void CS2Backbone::compute_ring_parameters() {
    1375        1116 :   for(unsigned i=0; i<ringInfo.size(); i++) {
    1376         360 :     const unsigned size = ringInfo[i].numAtoms;
    1377         360 :     if(size==6) {
    1378        1026 :       ringInfo[i].g[0] = delta(getPosition(ringInfo[i].atom[4]),getPosition(ringInfo[i].atom[2]));
    1379        1026 :       ringInfo[i].g[1] = delta(getPosition(ringInfo[i].atom[5]),getPosition(ringInfo[i].atom[3]));
    1380        1026 :       ringInfo[i].g[2] = delta(getPosition(ringInfo[i].atom[0]),getPosition(ringInfo[i].atom[4]));
    1381        1026 :       ringInfo[i].g[3] = delta(getPosition(ringInfo[i].atom[1]),getPosition(ringInfo[i].atom[5]));
    1382        1026 :       ringInfo[i].g[4] = delta(getPosition(ringInfo[i].atom[2]),getPosition(ringInfo[i].atom[0]));
    1383        1026 :       ringInfo[i].g[5] = delta(getPosition(ringInfo[i].atom[3]),getPosition(ringInfo[i].atom[1]));
    1384         342 :       vector<Vector> a(6);
    1385         684 :       a[0] = getPosition(ringInfo[i].atom[0]);
    1386             :       // ring center
    1387         342 :       Vector midP = a[0];
    1388        3762 :       for(unsigned j=1; j<size; j++) {
    1389        5130 :         a[j] = getPosition(ringInfo[i].atom[j]);
    1390        1710 :         midP += a[j];
    1391             :       }
    1392         342 :       ringInfo[i].position = midP/6.;
    1393             :       // compute normal vector to plane
    1394         684 :       Vector n1 = crossProduct(delta(a[0],a[4]), delta(a[0],a[2]));
    1395         684 :       Vector n2 = crossProduct(delta(a[3],a[1]), delta(a[3],a[5]));
    1396         684 :       ringInfo[i].normVect = 0.5*(n1 + n2);
    1397             :     }  else {
    1398          54 :       ringInfo[i].g[0] = delta(getPosition(ringInfo[i].atom[3]),getPosition(ringInfo[i].atom[2]));
    1399          54 :       ringInfo[i].g[1] = delta(getPosition(ringInfo[i].atom[0]),getPosition(ringInfo[i].atom[3]));
    1400          54 :       ringInfo[i].g[2] = delta(getPosition(ringInfo[i].atom[2]),getPosition(ringInfo[i].atom[0]));
    1401          18 :       vector<Vector> a(size);
    1402         198 :       for(unsigned j=0; j<size; j++) {
    1403         270 :         a[j] = getPosition(ringInfo[i].atom[j]);
    1404             :       }
    1405             :       // ring center
    1406          36 :       ringInfo[i].position = (a[0]+a[2]+a[3])/3.;
    1407             :       // ring plane normal vector
    1408          54 :       ringInfo[i].normVect = crossProduct(delta(a[0],a[3]), delta(a[0],a[2]));
    1409             : 
    1410             :     }
    1411             :     // calculate squared length and length of normal vector
    1412         360 :     ringInfo[i].lengthN2 = 1./ringInfo[i].normVect.modulo2();
    1413         720 :     ringInfo[i].lengthNV = 1./sqrt(ringInfo[i].lengthN2);
    1414             :   }
    1415          18 : }
    1416             : 
    1417       31806 : CS2Backbone::aa_t CS2Backbone::frag2enum(const string &aa) {
    1418             :   aa_t type = ALA;
    1419       31806 :   if (aa == "ALA") type = ALA;
    1420       29934 :   else if (aa == "ARG") type = ARG;
    1421       28548 :   else if (aa == "ASN") type = ASN;
    1422       26910 :   else if (aa == "ASP") type = ASP;
    1423       25380 :   else if (aa == "ASH") type = ASP;
    1424       25380 :   else if (aa == "CYS") type = CYS;
    1425       24858 :   else if (aa == "CYM") type = CYS;
    1426       24858 :   else if (aa == "GLN") type = GLN;
    1427       24390 :   else if (aa == "GLU") type = GLU;
    1428       22068 :   else if (aa == "GLH") type = GLU;
    1429       22068 :   else if (aa == "GLY") type = GLY;
    1430       16974 :   else if (aa == "HIS") type = HIS;
    1431       16974 :   else if (aa == "HSE") type = HIS;
    1432       16974 :   else if (aa == "HIE") type = HIS;
    1433       16974 :   else if (aa == "HSP") type = HIS;
    1434       16974 :   else if (aa == "HIP") type = HIS;
    1435       16974 :   else if (aa == "HSD") type = HIS;
    1436       16974 :   else if (aa == "HID") type = HIS;
    1437       16974 :   else if (aa == "ILE") type = ILE;
    1438       15174 :   else if (aa == "LEU") type = LEU;
    1439       13536 :   else if (aa == "LYS") type = LYS;
    1440       10746 :   else if (aa == "MET") type = MET;
    1441        9936 :   else if (aa == "PHE") type = PHE;
    1442        6876 :   else if (aa == "PRO") type = PRO;
    1443        5940 :   else if (aa == "SER") type = SER;
    1444        4302 :   else if (aa == "THR") type = THR;
    1445        2196 :   else if (aa == "TRP") type = TRP;
    1446        1980 :   else if (aa == "TYR") type = TYR;
    1447        1602 :   else if (aa == "VAL") type = VAL;
    1448           0 :   else if (aa == "UNK") type = UNK;
    1449           0 :   else plumed_merror("Error converting string " + aa + " into amino acid index: not a valid 3-letter code");
    1450       31806 :   return type;
    1451             : }
    1452             : 
    1453       10602 : vector<string> CS2Backbone::side_chain_atoms(const string &s) {
    1454             :   vector<string> sc;
    1455             : 
    1456       10602 :   if(s=="ALA") {
    1457        1296 :     sc.push_back( "CB" );
    1458        1296 :     sc.push_back( "HB1" );
    1459        1296 :     sc.push_back( "HB2" );
    1460        1296 :     sc.push_back( "HB3" );
    1461         648 :     return sc;
    1462        9954 :   } else if(s=="ARG") {
    1463         936 :     sc.push_back( "CB" );
    1464         936 :     sc.push_back( "CG" );
    1465         936 :     sc.push_back( "CD" );
    1466         936 :     sc.push_back( "NE" );
    1467         936 :     sc.push_back( "CZ" );
    1468         936 :     sc.push_back( "NH1" );
    1469         936 :     sc.push_back( "NH2" );
    1470         936 :     sc.push_back( "NH3" );
    1471         936 :     sc.push_back( "HB1" );
    1472         936 :     sc.push_back( "HB2" );
    1473         936 :     sc.push_back( "HB3" );
    1474         936 :     sc.push_back( "HG1" );
    1475         936 :     sc.push_back( "HG2" );
    1476         936 :     sc.push_back( "HG3" );
    1477         936 :     sc.push_back( "HD1" );
    1478         936 :     sc.push_back( "HD2" );
    1479         936 :     sc.push_back( "HD3" );
    1480         936 :     sc.push_back( "HE" );
    1481         936 :     sc.push_back( "HH11" );
    1482         936 :     sc.push_back( "HH12" );
    1483         936 :     sc.push_back( "HH21" );
    1484         936 :     sc.push_back( "HH22" );
    1485         936 :     sc.push_back( "1HH1" );
    1486         936 :     sc.push_back( "2HH1" );
    1487         936 :     sc.push_back( "1HH2" );
    1488         936 :     sc.push_back( "2HH2" );
    1489         468 :     return sc;
    1490        9486 :   } else if(s=="ASN") {
    1491        1188 :     sc.push_back( "CB" );
    1492        1188 :     sc.push_back( "CG" );
    1493        1188 :     sc.push_back( "OD1" );
    1494        1188 :     sc.push_back( "ND2" );
    1495        1188 :     sc.push_back( "HB1" );
    1496        1188 :     sc.push_back( "HB2" );
    1497        1188 :     sc.push_back( "HB3" );
    1498        1188 :     sc.push_back( "HD21" );
    1499        1188 :     sc.push_back( "HD22" );
    1500        1188 :     sc.push_back( "1HD2" );
    1501        1188 :     sc.push_back( "2HD2" );
    1502         594 :     return sc;
    1503       17226 :   } else if(s=="ASP"||s=="ASH") {
    1504        1116 :     sc.push_back( "CB" );
    1505        1116 :     sc.push_back( "CG" );
    1506        1116 :     sc.push_back( "OD1" );
    1507        1116 :     sc.push_back( "OD2" );
    1508        1116 :     sc.push_back( "HB1" );
    1509        1116 :     sc.push_back( "HB2" );
    1510        1116 :     sc.push_back( "HB3" );
    1511         558 :     return sc;
    1512       16668 :   } else if(s=="CYS"||s=="CYM") {
    1513           0 :     sc.push_back( "CB" );
    1514           0 :     sc.push_back( "SG" );
    1515           0 :     sc.push_back( "HB1" );
    1516           0 :     sc.push_back( "HB2" );
    1517           0 :     sc.push_back( "HB3" );
    1518           0 :     sc.push_back( "HG1" );
    1519           0 :     sc.push_back( "HG" );
    1520           0 :     return sc;
    1521        8334 :   } else if(s=="GLN") {
    1522         324 :     sc.push_back( "CB" );
    1523         324 :     sc.push_back( "CG" );
    1524         324 :     sc.push_back( "CD" );
    1525         324 :     sc.push_back( "OE1" );
    1526         324 :     sc.push_back( "NE2" );
    1527         324 :     sc.push_back( "HB1" );
    1528         324 :     sc.push_back( "HB2" );
    1529         324 :     sc.push_back( "HB3" );
    1530         324 :     sc.push_back( "HG1" );
    1531         324 :     sc.push_back( "HG2" );
    1532         324 :     sc.push_back( "HG3" );
    1533         324 :     sc.push_back( "HE21" );
    1534         324 :     sc.push_back( "HE22" );
    1535         324 :     sc.push_back( "1HE2" );
    1536         324 :     sc.push_back( "2HE2" );
    1537         162 :     return sc;
    1538       15552 :   } else if(s=="GLU"||s=="GLH") {
    1539        1584 :     sc.push_back( "CB" );
    1540        1584 :     sc.push_back( "CG" );
    1541        1584 :     sc.push_back( "CD" );
    1542        1584 :     sc.push_back( "OE1" );
    1543        1584 :     sc.push_back( "OE2" );
    1544        1584 :     sc.push_back( "HB1" );
    1545        1584 :     sc.push_back( "HB2" );
    1546        1584 :     sc.push_back( "HB3" );
    1547        1584 :     sc.push_back( "HG1" );
    1548        1584 :     sc.push_back( "HG2" );
    1549        1584 :     sc.push_back( "HG3" );
    1550         792 :     return sc;
    1551        7380 :   } else if(s=="GLY") {
    1552        2988 :     sc.push_back( "HA2" );
    1553        1494 :     return sc;
    1554       41202 :   } else if(s=="HIS"||s=="HSE"||s=="HIE"||s=="HSD"||s=="HID"||s=="HIP"||s=="HSP") {
    1555           0 :     sc.push_back( "CB" );
    1556           0 :     sc.push_back( "CG" );
    1557           0 :     sc.push_back( "ND1" );
    1558           0 :     sc.push_back( "CD2" );
    1559           0 :     sc.push_back( "CE1" );
    1560           0 :     sc.push_back( "NE2" );
    1561           0 :     sc.push_back( "HB1" );
    1562           0 :     sc.push_back( "HB2" );
    1563           0 :     sc.push_back( "HB3" );
    1564           0 :     sc.push_back( "HD1" );
    1565           0 :     sc.push_back( "HD2" );
    1566           0 :     sc.push_back( "HE1" );
    1567           0 :     sc.push_back( "HE2" );
    1568           0 :     return sc;
    1569        5886 :   } else if(s=="ILE") {
    1570        1080 :     sc.push_back( "CB" );
    1571        1080 :     sc.push_back( "CG1" );
    1572        1080 :     sc.push_back( "CG2" );
    1573        1080 :     sc.push_back( "CD" );
    1574        1080 :     sc.push_back( "HB" );
    1575        1080 :     sc.push_back( "HG11" );
    1576        1080 :     sc.push_back( "HG12" );
    1577        1080 :     sc.push_back( "HG21" );
    1578        1080 :     sc.push_back( "HG22" );
    1579        1080 :     sc.push_back( "HG23" );
    1580        1080 :     sc.push_back( "1HG1" );
    1581        1080 :     sc.push_back( "2HG1" );
    1582        1080 :     sc.push_back( "1HG2" );
    1583        1080 :     sc.push_back( "2HG2" );
    1584        1080 :     sc.push_back( "3HG2" );
    1585        1080 :     sc.push_back( "HD1" );
    1586        1080 :     sc.push_back( "HD2" );
    1587        1080 :     sc.push_back( "HD3" );
    1588         540 :     return sc;
    1589        5346 :   } else if(s=="LEU") {
    1590        1296 :     sc.push_back( "CB" );
    1591        1296 :     sc.push_back( "CG" );
    1592        1296 :     sc.push_back( "CD1" );
    1593        1296 :     sc.push_back( "CD2" );
    1594        1296 :     sc.push_back( "HB1" );
    1595        1296 :     sc.push_back( "HB2" );
    1596        1296 :     sc.push_back( "HB3" );
    1597        1296 :     sc.push_back( "HG" );
    1598        1296 :     sc.push_back( "HD11" );
    1599        1296 :     sc.push_back( "HD12" );
    1600        1296 :     sc.push_back( "HD13" );
    1601        1296 :     sc.push_back( "HD21" );
    1602        1296 :     sc.push_back( "HD22" );
    1603        1296 :     sc.push_back( "HD23" );
    1604        1296 :     sc.push_back( "1HD1" );
    1605        1296 :     sc.push_back( "2HD1" );
    1606        1296 :     sc.push_back( "3HD1" );
    1607        1296 :     sc.push_back( "1HD2" );
    1608        1296 :     sc.push_back( "2HD2" );
    1609        1296 :     sc.push_back( "3HD2" );
    1610         648 :     return sc;
    1611        4698 :   } else if(s=="LYS") {
    1612        2016 :     sc.push_back( "CB" );
    1613        2016 :     sc.push_back( "CG" );
    1614        2016 :     sc.push_back( "CD" );
    1615        2016 :     sc.push_back( "CE" );
    1616        2016 :     sc.push_back( "NZ" );
    1617        2016 :     sc.push_back( "HB1" );
    1618        2016 :     sc.push_back( "HB2" );
    1619        2016 :     sc.push_back( "HB3" );
    1620        2016 :     sc.push_back( "HG1" );
    1621        2016 :     sc.push_back( "HG2" );
    1622        2016 :     sc.push_back( "HG3" );
    1623        2016 :     sc.push_back( "HD1" );
    1624        2016 :     sc.push_back( "HD2" );
    1625        2016 :     sc.push_back( "HD3" );
    1626        2016 :     sc.push_back( "HE1" );
    1627        2016 :     sc.push_back( "HE2" );
    1628        2016 :     sc.push_back( "HE3" );
    1629        2016 :     sc.push_back( "HZ1" );
    1630        2016 :     sc.push_back( "HZ2" );
    1631        2016 :     sc.push_back( "HZ3" );
    1632        1008 :     return sc;
    1633        3690 :   } else if(s=="MET") {
    1634         576 :     sc.push_back( "CB" );
    1635         576 :     sc.push_back( "CG" );
    1636         576 :     sc.push_back( "SD" );
    1637         576 :     sc.push_back( "CE" );
    1638         576 :     sc.push_back( "HB1" );
    1639         576 :     sc.push_back( "HB2" );
    1640         576 :     sc.push_back( "HB3" );
    1641         576 :     sc.push_back( "HG1" );
    1642         576 :     sc.push_back( "HG2" );
    1643         576 :     sc.push_back( "HG3" );
    1644         576 :     sc.push_back( "HE1" );
    1645         576 :     sc.push_back( "HE2" );
    1646         576 :     sc.push_back( "HE3" );
    1647         288 :     return sc;
    1648        3402 :   } else if(s=="PHE") {
    1649        2196 :     sc.push_back( "CB" );
    1650        2196 :     sc.push_back( "CG" );
    1651        2196 :     sc.push_back( "CD1" );
    1652        2196 :     sc.push_back( "CD2" );
    1653        2196 :     sc.push_back( "CE1" );
    1654        2196 :     sc.push_back( "CE2" );
    1655        2196 :     sc.push_back( "CZ" );
    1656        2196 :     sc.push_back( "HB1" );
    1657        2196 :     sc.push_back( "HB2" );
    1658        2196 :     sc.push_back( "HB3" );
    1659        2196 :     sc.push_back( "HD1" );
    1660        2196 :     sc.push_back( "HD2" );
    1661        2196 :     sc.push_back( "HD3" );
    1662        2196 :     sc.push_back( "HE1" );
    1663        2196 :     sc.push_back( "HE2" );
    1664        2196 :     sc.push_back( "HE3" );
    1665        2196 :     sc.push_back( "HZ" );
    1666        1098 :     return sc;
    1667        2304 :   } else if(s=="PRO") {
    1668         216 :     sc.push_back( "CB" );
    1669         216 :     sc.push_back( "CG" );
    1670         216 :     sc.push_back( "CD" );
    1671         216 :     sc.push_back( "HB1" );
    1672         216 :     sc.push_back( "HB2" );
    1673         216 :     sc.push_back( "HB3" );
    1674         216 :     sc.push_back( "HG1" );
    1675         216 :     sc.push_back( "HG2" );
    1676         216 :     sc.push_back( "HG3" );
    1677         216 :     sc.push_back( "HD1" );
    1678         216 :     sc.push_back( "HD2" );
    1679         216 :     sc.push_back( "HD3" );
    1680         108 :     return sc;
    1681        2196 :   } else if(s=="SER") {
    1682        1260 :     sc.push_back( "CB" );
    1683        1260 :     sc.push_back( "OG" );
    1684        1260 :     sc.push_back( "HB1" );
    1685        1260 :     sc.push_back( "HB2" );
    1686        1260 :     sc.push_back( "HB3" );
    1687        1260 :     sc.push_back( "HG1" );
    1688        1260 :     sc.push_back( "HG" );
    1689         630 :     return sc;
    1690        1566 :   } else if(s=="THR") {
    1691        1548 :     sc.push_back( "CB" );
    1692        1548 :     sc.push_back( "OG1" );
    1693        1548 :     sc.push_back( "CG2" );
    1694        1548 :     sc.push_back( "HB" );
    1695        1548 :     sc.push_back( "HG1" );
    1696        1548 :     sc.push_back( "HG21" );
    1697        1548 :     sc.push_back( "HG22" );
    1698        1548 :     sc.push_back( "HG23" );
    1699        1548 :     sc.push_back( "1HG2" );
    1700        1548 :     sc.push_back( "2HG2" );
    1701        1548 :     sc.push_back( "3HG2" );
    1702         774 :     return sc;
    1703         792 :   } else if(s=="TRP") {
    1704         144 :     sc.push_back( "CB" );
    1705         144 :     sc.push_back( "CG" );
    1706         144 :     sc.push_back( "CD1" );
    1707         144 :     sc.push_back( "CD2" );
    1708         144 :     sc.push_back( "NE1" );
    1709         144 :     sc.push_back( "CE2" );
    1710         144 :     sc.push_back( "CE3" );
    1711         144 :     sc.push_back( "CZ2" );
    1712         144 :     sc.push_back( "CZ3" );
    1713         144 :     sc.push_back( "CH2" );
    1714         144 :     sc.push_back( "HB1" );
    1715         144 :     sc.push_back( "HB2" );
    1716         144 :     sc.push_back( "HB3" );
    1717         144 :     sc.push_back( "HD1" );
    1718         144 :     sc.push_back( "HE1" );
    1719         144 :     sc.push_back( "HE3" );
    1720         144 :     sc.push_back( "HZ2" );
    1721         144 :     sc.push_back( "HZ3" );
    1722         144 :     sc.push_back( "HH2" );
    1723          72 :     return sc;
    1724         720 :   } else if(s=="TYR") {
    1725         288 :     sc.push_back( "CB" );
    1726         288 :     sc.push_back( "CG" );
    1727         288 :     sc.push_back( "CD1" );
    1728         288 :     sc.push_back( "CD2" );
    1729         288 :     sc.push_back( "CE1" );
    1730         288 :     sc.push_back( "CE2" );
    1731         288 :     sc.push_back( "CZ" );
    1732         288 :     sc.push_back( "OH" );
    1733         288 :     sc.push_back( "HB1" );
    1734         288 :     sc.push_back( "HB2" );
    1735         288 :     sc.push_back( "HB3" );
    1736         288 :     sc.push_back( "HD1" );
    1737         288 :     sc.push_back( "HD2" );
    1738         288 :     sc.push_back( "HD3" );
    1739         288 :     sc.push_back( "HE1" );
    1740         288 :     sc.push_back( "HE2" );
    1741         288 :     sc.push_back( "HE3" );
    1742         288 :     sc.push_back( "HH" );
    1743         144 :     return sc;
    1744         576 :   } else if(s=="VAL") {
    1745        1152 :     sc.push_back( "CB" );
    1746        1152 :     sc.push_back( "CG1" );
    1747        1152 :     sc.push_back( "CG2" );
    1748        1152 :     sc.push_back( "HB" );
    1749        1152 :     sc.push_back( "HG11" );
    1750        1152 :     sc.push_back( "HG12" );
    1751        1152 :     sc.push_back( "HG13" );
    1752        1152 :     sc.push_back( "HG21" );
    1753        1152 :     sc.push_back( "HG22" );
    1754        1152 :     sc.push_back( "HG23" );
    1755        1152 :     sc.push_back( "1HG1" );
    1756        1152 :     sc.push_back( "2HG1" );
    1757        1152 :     sc.push_back( "3HG1" );
    1758        1152 :     sc.push_back( "1HG2" );
    1759        1152 :     sc.push_back( "2HG2" );
    1760        1152 :     sc.push_back( "3HG2" );
    1761         576 :     return sc;
    1762           0 :   } else plumed_merror("Sidechain atoms unknown: " + s);
    1763             : }
    1764             : 
    1765       47016 : bool CS2Backbone::isSP2(const string & resType, const string & atomName) {
    1766             :   bool sp2 = false;
    1767       47016 :   if (atomName == "C") return true;
    1768       43848 :   if (atomName == "O") return true;
    1769             : 
    1770       40716 :   if(resType == "TRP") {
    1771         396 :     if      (atomName == "CG")  sp2 = true;
    1772         378 :     else if (atomName == "CD1") sp2 = true;
    1773         360 :     else if (atomName == "CD2") sp2 = true;
    1774         342 :     else if (atomName == "CE2") sp2 = true;
    1775         324 :     else if (atomName == "CE3") sp2 = true;
    1776         306 :     else if (atomName == "CZ2") sp2 = true;
    1777         288 :     else if (atomName == "CZ3") sp2 = true;
    1778         270 :     else if (atomName == "CH2") sp2 = true;
    1779       40320 :   } else if (resType == "ASP") {
    1780        1656 :     if      (atomName == "CG")  sp2 = true;
    1781        1494 :     else if (atomName == "OD1") sp2 = true;
    1782        1332 :     else if (atomName == "OD2") sp2 = true;
    1783       38664 :   } else if (resType == "GLU") {
    1784        2844 :     if      (atomName == "CD")  sp2 = true;
    1785        2628 :     else if (atomName == "OE1") sp2 = true;
    1786        2412 :     else if (atomName == "OE2") sp2 = true;
    1787       35820 :   } else if (resType == "ARG") {
    1788        2772 :     if (atomName == "CZ") sp2 = true;
    1789       33048 :   } else if (resType == "HIS") {
    1790           0 :     if      (atomName == "CG")  sp2 = true;
    1791           0 :     else if (atomName == "ND1") sp2 = true;
    1792           0 :     else if (atomName == "CD2") sp2 = true;
    1793           0 :     else if (atomName == "CE1") sp2 = true;
    1794           0 :     else if (atomName == "NE2") sp2 = true;
    1795       33048 :   } else if (resType == "PHE") {
    1796        5184 :     if      (atomName == "CG")  sp2 = true;
    1797        4896 :     else if (atomName == "CD1") sp2 = true;
    1798        4608 :     else if (atomName == "CD2") sp2 = true;
    1799        4320 :     else if (atomName == "CE1") sp2 = true;
    1800        4032 :     else if (atomName == "CE2") sp2 = true;
    1801        3744 :     else if (atomName == "CZ")  sp2 = true;
    1802       27864 :   } else if (resType == "TYR") {
    1803         684 :     if      (atomName == "CG")  sp2 = true;
    1804         648 :     else if (atomName == "CD1") sp2 = true;
    1805         612 :     else if (atomName == "CD2") sp2 = true;
    1806         576 :     else if (atomName == "CE1") sp2 = true;
    1807         540 :     else if (atomName == "CE2") sp2 = true;
    1808         504 :     else if (atomName == "CZ")  sp2 = true;
    1809       27180 :   } else if (resType == "ASN") {
    1810        1944 :     if      (atomName == "CG")  sp2 = true;
    1811        1782 :     else if (atomName == "OD1") sp2 = true;
    1812       25236 :   } else if (resType == "GLN") {
    1813         810 :     if      (atomName == "CD")  sp2 = true;
    1814         756 :     else if (atomName == "OE1") sp2 = true;
    1815             :   }
    1816             : 
    1817             :   return sp2;
    1818             : }
    1819             : 
    1820      145728 : bool CS2Backbone::is_chi1_cx(const string & frg, const string & atm) {
    1821      145728 :   if(atm=="CG")                                        return true;
    1822      139788 :   if((frg == "CYS")&&(atm =="SG"))                     return true;
    1823      288792 :   if(((frg == "ILE")||(frg == "VAL"))&&(atm == "CG1")) return true;
    1824      145602 :   if((frg == "SER")&&(atm == "OG"))                    return true;
    1825      148878 :   if((frg == "THR")&&(atm == "OG1"))                   return true;
    1826             : 
    1827             :   return false;
    1828             : }
    1829             : 
    1830     3599784 : void CS2Backbone::xdist_name_map(string & name) {
    1831     7199568 :   if((name == "OT1")||(name == "OC1")) name = "O";
    1832    10799352 :   else if ((name == "HN") || (name == "HT1") || (name == "H1")) name = "H";
    1833     7139232 :   else if ((name == "CG1")|| (name == "OG")||
    1834     7159572 :            (name == "SG") || (name == "OG1")) name = "CG";
    1835     7040070 :   else if ((name == "HA1")|| (name == "HA3")) name = "HA";
    1836     3599784 : }
    1837             : 
    1838          18 : void CS2Backbone::update() {
    1839             :   // write status file
    1840          36 :   if(getWstride()>0&& (getStep()%getWstride()==0 || getCPT()) ) writeStatus();
    1841          18 : }
    1842             : 
    1843             : }
    1844        5517 : }

Generated by: LCOV version 1.14