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