Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2013-2018 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.70 // 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 "Colvar.h"
39 : #include "ActionRegister.h"
40 : #include "core/PlumedMain.h"
41 : #include "tools/OpenMP.h"
42 : #include "tools/Pbc.h"
43 : #include "tools/PDB.h"
44 : #include "tools/Torsion.h"
45 :
46 : using namespace std;
47 :
48 : namespace PLMD {
49 : namespace colvar {
50 :
51 : //+PLUMEDOC COLVAR CS2BACKBONE
52 : /*
53 : This collective variable calculates the backbone chemical shifts for a protein.
54 :
55 : The functional form is that of CamShift \cite Kohlhoff:2009us. The chemical shifts
56 : of the selected nuclei/residues are saved as components. Reference experimental values
57 : can also be stored as components. The two components can then be used to calculate
58 : either a scoring function as in \cite Robustelli:2010dn \cite Granata:2013dk, using
59 : the keyword CAMSHIFT or to calculate ensemble averages chemical shift per chemical
60 : shift as in \cite Camilloni:2012je \cite Camilloni:2013hs (see \ref STATS and
61 : \ref ENSEMBLE).
62 :
63 : CamShift calculation is relatively heavy because it often uses a large number of atoms, in order
64 : to make it faster it is currently parallelised with \ref Openmp.
65 :
66 : As a general rule, when using \ref CS2BACKBONE or other experimental restraints it is better to
67 : increase the accuracy of the constraint algorithm due to the increased strain on the bonded structure.
68 : In the case of GROMACS it is safer to use lincs-iter=2 and lincs-order=6.
69 :
70 : In general the system for which chemical shifts are calculated must be completly included in
71 : ATOMS and a TEMPLATE pdb file for the same atoms should be provided as well in the folder DATA.
72 : The atoms are made automatically whole unless NOPBC is used, in particular if the system is made of
73 : by multiple chains it is usually better to use NOPBC and make the molecule whole \ref WHOLEMOLECULES
74 : selecting an appropriate order.
75 :
76 : In addition to a pdb file one needs to provide a list of chemical shifts to be calculated using one
77 : file per nucleus type (CAshifts.dat, CBshifts.dat, Cshifts.dat, Hshifts.dat, HAshifts.dat, Nshifts.dat),
78 : all the six files should always be present. A chemical shift for a nucleus is calculated if a value
79 : greater than 0 is provided. For practical purposes the value can correspond to the experimental value.
80 : Residues numbers should go from 1 to N irrespectively of the numbers used in the pdb file. The first and
81 : last residue of each chain should be preceeded by a # character. Termini groups like ACE or NME should
82 : be removed from the PDB.
83 :
84 : \verbatim
85 : CAshifts.dat:
86 : #1 0.0
87 : 2 55.5
88 : 3 58.4
89 : .
90 : .
91 : #last 0.0
92 : #last+1 (first) of second chain
93 : .
94 : #last of second chain
95 : \endverbatim
96 :
97 : The default behaviour is to store the values for the active nuclei in components (ca_#, cb_#,
98 : co_#, ha_#, hn_#, nh_# and expca_#, expcb_#, expco_#, expha_#, exphn_#, exp_nh#) with NOEXP it is possible
99 : to only store the backcalculated values.
100 :
101 : A pdb file is needed to the generate a simple topology of the protein. For histidines in protonation
102 : states different from D the HIE/HSE HIP/HSP name should be used. GLH and ASH can be used for the alternative
103 : protonation of GLU and ASP. Non-standard amino acids and other molecules are not yet supported, but in principle
104 : they can be named UNK. If multiple chains are present the chain identifier must be in the standard PDB format,
105 : together with the TER keyword at the end of each chain.
106 :
107 : One more standard file is also needed in the folder DATA: camshift.db. This file includes all the CamShift parameters
108 : and can be found in regtest/basic/rt45/data/ .
109 :
110 : All the above files must be in a single folder that must be specified with the keyword DATA.
111 :
112 : Additional material and examples can be also found in the tutorial \ref belfast-9
113 :
114 : \par Examples
115 :
116 : In this first example the chemical shifts are used to calculate a scoring function to be used
117 : in NMR driven Metadynamics \cite Granata:2013dk :
118 :
119 : \verbatim
120 : whole: GROUP ATOMS=2612-2514:-1,961-1:-1,2466-962:-1,2513-2467:-1
121 : WHOLEMOLECULES ENTITY0=whole
122 : cs: CS2BACKBONE ATOMS=1-2612 NRES=176 DATA=../data/ TEMPLATE=template.pdb CAMSHIFT NOPBC
123 : metad: METAD ARG=cs HEIGHT=0.5 SIGMA=0.1 PACE=200 BIASFACTOR=10
124 : PRINT ARG=cs,metad.bias FILE=COLVAR STRIDE=100
125 : \endverbatim
126 :
127 : In this second example the chemical shifts are used as replica-averaged restrained as in \cite Camilloni:2012je \cite Camilloni:2013hs.
128 :
129 : \verbatim
130 : cs: CS2BACKBONE ATOMS=1-174 DATA=data/ NRES=13
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 : \endverbatim
138 :
139 : (See also \ref WHOLEMOLECULES, \ref STATS, \ref METAD, \ref RESTRAINT and \ref PRINT)
140 :
141 : */
142 : //+ENDPLUMEDOC
143 :
144 : class CS2BackboneDB {
145 : enum { STD, GLY, PRO};
146 : enum { HA_ATOM, H_ATOM, N_ATOM, CA_ATOM, CB_ATOM, C_ATOM };
147 : static const unsigned aa_kind = 3;
148 : static const unsigned atm_kind = 6;
149 : static const unsigned numXtraDists = 27;
150 :
151 : // ALA, ARG, ASN, ASP, CYS, GLU, GLN, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL
152 : double c_aa[aa_kind][atm_kind][20];
153 : double c_aa_prev[aa_kind][atm_kind][20];
154 : double c_aa_succ[aa_kind][atm_kind][20];
155 : double co_bb[aa_kind][atm_kind][16];
156 : double co_sc_[aa_kind][atm_kind][20][20];
157 : double co_xd[aa_kind][atm_kind][numXtraDists];
158 : double co_sphere[aa_kind][atm_kind][2][8];
159 : // for ring current effects
160 : // Phe, Tyr, Trp_1, Trp_2, His
161 : double co_ring[aa_kind][atm_kind][5];
162 : // for dihedral angles
163 : // co * (a * cos(3 * omega + c) + b * cos(omega + d))
164 : double co_da[aa_kind][atm_kind][3];
165 : double pars_da[aa_kind][atm_kind][3][5];
166 :
167 : public:
168 :
169 1164 : inline unsigned kind(const string &s) {
170 1164 : if(s=="GLY") return GLY;
171 948 : else if(s=="PRO") return PRO;
172 870 : return STD;
173 : }
174 :
175 108 : inline unsigned atom_kind(const string &s) {
176 108 : if(s=="HA")return HA_ATOM;
177 90 : else if(s=="H") return H_ATOM;
178 72 : else if(s=="N") return N_ATOM;
179 54 : else if(s=="CA")return CA_ATOM;
180 36 : else if(s=="CB")return CB_ATOM;
181 18 : else if(s=="C") return C_ATOM;
182 0 : return -1;
183 : }
184 :
185 27864 : unsigned get_numXtraDists() {return numXtraDists;}
186 :
187 : //PARAMETERS
188 3533 : inline double * CONSTAACURR(const unsigned a_kind, const unsigned at_kind) {return c_aa[a_kind][at_kind];}
189 3534 : inline double * CONSTAANEXT(const unsigned a_kind, const unsigned at_kind) {return c_aa_succ[a_kind][at_kind];}
190 3534 : inline double * CONSTAAPREV(const unsigned a_kind, const unsigned at_kind) {return c_aa_prev[a_kind][at_kind];}
191 3534 : inline double * CONST_BB2_PREV(const unsigned a_kind, const unsigned at_kind) {return co_bb[a_kind][at_kind];}
192 3533 : inline double * CONST_BB2_CURR(const unsigned a_kind, const unsigned at_kind) {return co_bb[a_kind][at_kind]+5;}
193 3533 : inline double * CONST_BB2_NEXT(const unsigned a_kind, const unsigned at_kind) {return co_bb[a_kind][at_kind]+11;}
194 3534 : inline double * CONST_SC2(const unsigned a_kind, const unsigned at_kind, unsigned res_type) { return co_sc_[a_kind][at_kind][res_type];}
195 3534 : inline double * CONST_XD(const unsigned a_kind, const unsigned at_kind) { return co_xd[a_kind][at_kind];}
196 7068 : inline double * CO_SPHERE(const unsigned a_kind, const unsigned at_kind, unsigned exp_type) { return co_sphere[a_kind][at_kind][exp_type];}
197 3534 : inline double * CO_RING(const unsigned a_kind, const unsigned at_kind) { return co_ring[a_kind][at_kind];}
198 3534 : inline double * CO_DA(const unsigned a_kind, const unsigned at_kind) { return co_da[a_kind][at_kind];}
199 9887 : 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];}
200 :
201 6 : void parse(const string &file, const double dscale) {
202 6 : ifstream in;
203 6 : in.open(file.c_str());
204 6 : if(!in) plumed_merror("Unable to open CS2Backbone DB file " +file);
205 :
206 6 : unsigned c_kind = 0;
207 6 : unsigned c_atom = 0;
208 6 : unsigned nline = 0;
209 :
210 114 : for(unsigned i=0; i<3; i++) for(unsigned j=0; j<6; j++) {
211 2268 : for(unsigned k=0; k<20; k++) {
212 2160 : c_aa[i][j][k]=0.;
213 2160 : c_aa_prev[i][j][k]=0.;
214 2160 : c_aa_succ[i][j][k]=0.;
215 2160 : for(unsigned m=0; m<20; m++) co_sc_[i][j][k][m]=0.;
216 : }
217 108 : for(unsigned k=0; k<16; k++) {co_bb[i][j][k]=0.; }
218 108 : for(unsigned k=0; k<8; k++) { co_sphere[i][j][0][k]=0.; co_sphere[i][j][1][k]=0.; }
219 432 : for(unsigned k=0; k<3; k++) {
220 324 : co_da[i][j][k]=0.;
221 324 : for(unsigned l=0; l<5; l++) pars_da[i][j][k][l]=0.;
222 : }
223 108 : for(unsigned k=0; k<5; k++) co_ring[i][j][k]=0.;
224 108 : for(unsigned k=0; k<numXtraDists; k++) co_xd[i][j][k]=0.;
225 : }
226 :
227 12576 : while(!in.eof()) {
228 12564 : string line;
229 12564 : getline(in,line);
230 12564 : ++nline;
231 12564 : if(line.compare(0,1,"#")==0) continue;
232 6810 : vector<string> tok;
233 6810 : vector<string> tmp;
234 6810 : tok = split(line,' ');
235 87276 : for(unsigned q=0; q<tok.size(); q++)
236 80466 : if(tok[q].size()) tmp.push_back(tok[q]);
237 6810 : tok = tmp;
238 6810 : if(tok.size()==0) continue;
239 6804 : if(tok[0]=="PAR") {
240 108 : c_kind = kind(tok[2]);
241 108 : c_atom = atom_kind(tok[1]);
242 108 : continue;
243 : }
244 6696 : else if(tok[0]=="WEIGHT") {
245 108 : continue;
246 : }
247 6588 : else if(tok[0]=="FLATBTM") {
248 108 : continue;
249 : }
250 6480 : else if (tok[0] == "SCALEHARM") {
251 108 : continue;
252 : }
253 6372 : else if (tok[0] == "TANHAMPLI") {
254 108 : continue;
255 : }
256 6264 : else if (tok[0] == "ENDHARMON") {
257 108 : continue;
258 : }
259 6156 : else if (tok[0] == "MAXRCDEVI") {
260 108 : continue;
261 : }
262 6048 : else if (tok[0] == "RANDCOIL") {
263 108 : continue;
264 : }
265 5940 : else if (tok[0] == "CONST") {
266 108 : continue;
267 : }
268 5832 : else if (tok[0] == "CONSTAA") {
269 108 : assign(c_aa[c_kind][c_atom],tok,1);
270 108 : continue;
271 : }
272 5724 : else if (tok[0] == "CONSTAA-1") {
273 108 : assign(c_aa_prev[c_kind][c_atom],tok,1);
274 108 : continue;
275 : }
276 5616 : else if (tok[0] == "CONSTAA+1") {
277 108 : assign(c_aa_succ[c_kind][c_atom],tok,1);
278 108 : continue;
279 : }
280 5508 : else if (tok[0] == "COBB1") {
281 108 : continue;
282 : }
283 5400 : else if (tok[0] == "COBB2") {
284 : //angstrom to nm
285 108 : assign(co_bb[c_kind][c_atom],tok,dscale);
286 108 : continue;
287 : }
288 5292 : else if (tok[0] == "SPHERE1") {
289 : // angstrom^-3 to nm^-3
290 108 : assign(co_sphere[c_kind][c_atom][0],tok,1./(dscale*dscale*dscale));
291 108 : continue;
292 : }
293 5184 : else if (tok[0] == "SPHERE2") {
294 : //angstrom to nm
295 108 : assign(co_sphere[c_kind][c_atom][1],tok,dscale);
296 108 : continue;
297 : }
298 5076 : else if (tok[0] == "DIHEDRALS") {
299 108 : assign(co_da[c_kind][c_atom],tok,1);
300 108 : continue;
301 : }
302 4968 : else if (tok[0] == "RINGS") {
303 : // angstrom^-3 to nm^-3
304 108 : assign(co_ring[c_kind][c_atom],tok,1./(dscale*dscale*dscale));
305 648 : for(unsigned i=1; i<tok.size(); i++)
306 540 : co_ring[c_kind][c_atom][i-1] *= 1000;
307 108 : continue;
308 : }
309 4860 : else if (tok[0] == "HBONDS") {
310 108 : continue;
311 : }
312 4752 : else if (tok[0] == "XTRADISTS") {
313 : //angstrom to nm
314 108 : assign(co_xd[c_kind][c_atom],tok,dscale);
315 108 : continue;
316 : }
317 4644 : else if(tok[0]=="DIHEDPHI") {
318 108 : assign(pars_da[c_kind][c_atom][0],tok,1);
319 108 : continue;
320 : }
321 4536 : else if(tok[0]=="DIHEDPSI") {
322 108 : assign(pars_da[c_kind][c_atom][1],tok,1);
323 108 : continue;
324 : }
325 4428 : else if(tok[0]=="DIHEDCHI1") {
326 108 : assign(pars_da[c_kind][c_atom][2],tok,1);
327 108 : continue;
328 : }
329 :
330 4320 : bool ok = false;
331 : string scIdent1 [] = {"COSCALA1", "COSCARG1", "COSCASN1", "COSCASP1", "COSCCYS1", "COSCGLN1", "COSCGLU1",
332 : "COSCGLY1", "COSCHIS1", "COSCILE1", "COSCLEU1", "COSCLYS1", "COSCMET1", "COSCPHE1",
333 : "COSCPRO1", "COSCSER1", "COSCTHR1", "COSCTRP1", "COSCTYR1", "COSCVAL1"
334 90720 : };
335 :
336 68040 : for(unsigned scC = 0; scC < 20; scC++) {
337 65880 : if(tok[0]==scIdent1[scC]) {
338 2160 : ok = true;
339 2160 : break;
340 : }
341 : }
342 4320 : if(ok) continue;
343 :
344 : string scIdent2 [] = {"COSCALA2", "COSCARG2", "COSCASN2", "COSCASP2", "COSCCYS2", "COSCGLN2", "COSCGLU2",
345 : "COSCGLY2", "COSCHIS2", "COSCILE2", "COSCLEU2", "COSCLYS2", "COSCMET2", "COSCPHE2",
346 : "COSCPRO2", "COSCSER2", "COSCTHR2", "COSCTRP2", "COSCTYR2", "COSCVAL2"
347 45360 : };
348 :
349 22680 : for(unsigned scC = 0; scC < 20; scC++) {
350 22680 : if(tok[0]==scIdent2[scC]) {
351 : //angstrom to nm
352 2160 : assign(co_sc_[c_kind][c_atom][scC],tok,dscale);
353 2160 : ok = true; break;
354 : }
355 : }
356 2160 : if(ok) continue;
357 :
358 0 : if(tok.size()) {
359 0 : string str_err = "CS2Backbone DB WARNING: unrecognized token: " + tok[0];
360 0 : plumed_merror(str_err);
361 : }
362 0 : }
363 6 : in.close();
364 6 : }
365 :
366 : private:
367 :
368 6810 : vector<string> &split(const string &s, char delim, vector<string> &elems) {
369 6810 : stringstream ss(s);
370 13620 : string item;
371 94086 : while (getline(ss, item, delim)) {
372 80466 : elems.push_back(item);
373 : }
374 13620 : return elems;
375 : }
376 :
377 6810 : vector<string> split(const string &s, char delim) {
378 6810 : vector<string> elems;
379 6810 : split(s, delim, elems);
380 6810 : return elems;
381 : }
382 :
383 3456 : void assign(double * f, const vector<string> & v, const double scale) {
384 40932 : for(unsigned i=1; i<v.size(); i++)
385 37476 : f[i-1] = scale*(atof(v[i].c_str()));
386 3456 : }
387 : };
388 :
389 12 : class CS2Backbone : public Colvar {
390 10500 : struct Fragment {
391 : vector<Value*> comp;
392 : vector<double> exp_cs;
393 : unsigned res_type_prev;
394 : unsigned res_type_curr;
395 : unsigned res_type_next;
396 : unsigned res_kind;
397 : unsigned fd;
398 : string res_name;
399 : vector<int> pos;
400 : vector<int> prev;
401 : vector<int> curr;
402 : vector<int> next;
403 : vector<int> side_chain;
404 : vector<int> xd1;
405 : vector<int> xd2;
406 : vector<unsigned> box_nb;
407 : vector<int> phi;
408 : vector<int> psi;
409 : vector<int> chi1;
410 : double t_phi;
411 : double t_psi;
412 : double t_chi1;
413 : vector<Vector> dd0, dd10, dd21, dd2;
414 :
415 1056 : Fragment() {
416 1056 : comp.resize(6);
417 1056 : exp_cs.resize(6,0);
418 1056 : res_type_prev = res_type_curr = res_type_next = 0;
419 1056 : res_kind = 0;
420 1056 : fd = 0;
421 1056 : res_name = "";
422 1056 : pos.resize(6,-1);
423 1056 : prev.reserve(5);
424 1056 : curr.reserve(6);
425 1056 : next.reserve(5);
426 1056 : side_chain.reserve(20);
427 1056 : xd1.reserve(27);
428 1056 : xd2.reserve(27);
429 1056 : box_nb.reserve(250);
430 1056 : phi.reserve(4);
431 1056 : psi.reserve(4);
432 1056 : chi1.reserve(4);
433 1056 : t_phi = t_psi = t_chi1 = 0;
434 1056 : dd0.resize(3);
435 1056 : dd10.resize(3);
436 1056 : dd21.resize(3);
437 1056 : dd2.resize(3);
438 1056 : }
439 :
440 : };
441 :
442 : struct RingInfo {
443 : enum {R_PHE, R_TYR, R_TRP1, R_TRP2, R_HIS};
444 : unsigned rtype; // one out of five different types
445 : unsigned atom[6]; // up to six member per ring
446 : unsigned numAtoms; // number of ring members (5 or 6)
447 : Vector position; // center of ring coordinates
448 : Vector normVect; // ring plane normal vector
449 : Vector n1, n2; // two atom plane normal vectors used to compute ring plane normal
450 : Vector g[6]; // vector of the vectors used to calculate n1,n2
451 : double lengthN2; // square of length of normVect
452 : double lengthNV; // length of normVect
453 120 : RingInfo():
454 : rtype(0),numAtoms(0),
455 120 : lengthN2(NAN),lengthNV(NAN)
456 120 : {for(unsigned i=0; i<6; i++) atom[i]=0;}
457 : };
458 :
459 : enum aa_t {ALA, ARG, ASN, ASP, CYS, GLN, GLU, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL, UNK};
460 : enum atom_t {D_C, D_H, D_N, D_O, D_S, D_C2, D_N2, D_O2};
461 :
462 : CS2BackboneDB db;
463 : vector<vector<Fragment> > atom;
464 : vector<RingInfo> ringInfo;
465 : vector<unsigned> seg_last;
466 : vector<unsigned> type;
467 : vector<unsigned> res_num;
468 : unsigned box_nupdate;
469 : unsigned box_count;
470 : bool camshift;
471 : bool pbc;
472 :
473 : void remove_problematic(const string &res, const string &nucl);
474 : void read_cs(const string &file, const string &k);
475 : void update_neighb();
476 : void compute_ring_parameters();
477 : void compute_dihedrals();
478 : void init_backbone(const PDB &pdb);
479 : void init_sidechain(const PDB &pdb);
480 : void init_xdist(const PDB &pdb);
481 : void init_types(const PDB &pdb);
482 : void init_rings(const PDB &pdb);
483 : aa_t frag2enum(const string &aa);
484 : vector<string> side_chain_atoms(const string &s);
485 : bool isSP2(const string & resType, const string & atomName);
486 : bool is_chi1_cx(const string & frg, const string & atm);
487 : unsigned frag_segment(const unsigned p);
488 : unsigned frag_relitive_index(const unsigned p, const unsigned s);
489 : void debug_report();
490 : void xdist_name_map(string & name);
491 :
492 : public:
493 :
494 : explicit CS2Backbone(const ActionOptions&);
495 : static void registerKeywords( Keywords& keys );
496 : virtual void calculate();
497 : };
498 :
499 2529 : PLUMED_REGISTER_ACTION(CS2Backbone,"CS2BACKBONE")
500 :
501 7 : void CS2Backbone::registerKeywords( Keywords& keys ) {
502 7 : Colvar::registerKeywords( keys );
503 7 : componentsAreNotOptional(keys);
504 7 : useCustomisableComponents(keys);
505 7 : keys.add("atoms","ATOMS","The atoms to be included in the calculation, e.g. the whole protein.");
506 7 : keys.add("compulsory","DATA","data/","The folder with the experimental chemical shifts.");
507 7 : keys.add("compulsory","TEMPLATE","template.pdb","A PDB file of the protein system to initialise ALMOST.");
508 7 : keys.add("compulsory","NEIGH_FREQ","20","Period in step for neighbour list update.");
509 7 : keys.add("compulsory","NRES","Number of residues, corresponding to the number of chemical shifts.");
510 7 : keys.addFlag("CAMSHIFT",false,"Set to TRUE if you to calculate a single CamShift score.");
511 7 : keys.addFlag("NOEXP",false,"Set to TRUE if you don't want to have fixed components with the experimetnal values.");
512 7 : keys.addOutputComponent("ha","default","the calculated Ha hydrogen chemical shifts");
513 7 : keys.addOutputComponent("hn","default","the calculated H hydrogen chemical shifts");
514 7 : keys.addOutputComponent("nh","default","the calculated N nitrogen chemical shifts");
515 7 : keys.addOutputComponent("ca","default","the calculated Ca carbon chemical shifts");
516 7 : keys.addOutputComponent("cb","default","the calculated Cb carbon chemical shifts");
517 7 : keys.addOutputComponent("co","default","the calculated C' carbon chemical shifts");
518 7 : keys.addOutputComponent("expha","default","the experimental Ha hydrogen chemical shifts");
519 7 : keys.addOutputComponent("exphn","default","the experimental H hydrogen chemical shifts");
520 7 : keys.addOutputComponent("expnh","default","the experimental N nitrogen chemical shifts");
521 7 : keys.addOutputComponent("expca","default","the experimental Ca carbon chemical shifts");
522 7 : keys.addOutputComponent("expcb","default","the experimental Cb carbon chemical shifts");
523 7 : keys.addOutputComponent("expco","default","the experimental C' carbon chemical shifts");
524 7 : }
525 :
526 6 : CS2Backbone::CS2Backbone(const ActionOptions&ao):
527 : PLUMED_COLVAR_INIT(ao),
528 : camshift(false),
529 6 : pbc(true)
530 : {
531 6 : string stringadb;
532 12 : string stringapdb;
533 :
534 6 : parseFlag("CAMSHIFT",camshift);
535 :
536 6 : bool nopbc=!pbc;
537 6 : parseFlag("NOPBC",nopbc);
538 6 : pbc=!nopbc;
539 :
540 6 : bool noexp=false;
541 6 : parseFlag("NOEXP",noexp);
542 :
543 12 : string stringa_data;
544 6 : parse("DATA",stringa_data);
545 :
546 12 : string stringa_template;
547 6 : parse("TEMPLATE",stringa_template);
548 :
549 6 : box_count=0;
550 6 : box_nupdate=20;
551 6 : parse("NEIGH_FREQ", box_nupdate);
552 :
553 : unsigned numResidues;
554 6 : parse("NRES", numResidues);
555 :
556 6 : stringadb = stringa_data + string("/camshift.db");
557 6 : stringapdb = stringa_data + string("/") + stringa_template;
558 :
559 : /* Lenght conversion (parameters are tuned for angstrom) */
560 6 : double scale=1.;
561 6 : if(!plumed.getAtoms().usingNaturalUnits()) {
562 6 : scale = 10.*atoms.getUnits().getLength();
563 : }
564 :
565 6 : log.printf(" Initialization of the predictor ...\n"); log.flush();
566 6 : db.parse(stringadb,scale);
567 12 : PDB pdb;
568 6 : if( !pdb.read(stringapdb,plumed.getAtoms().usingNaturalUnits(),1./scale) ) error("missing input file " + stringapdb);
569 6 : init_backbone(pdb);
570 6 : init_sidechain(pdb);
571 6 : init_xdist(pdb);
572 6 : init_types(pdb);
573 6 : init_rings(pdb);
574 : #ifndef NDEBUG
575 : debug_report();
576 : #endif
577 6 : log.printf(" Reading experimental data ...\n"); log.flush();
578 6 : stringadb = stringa_data + string("/CAshifts.dat");
579 6 : log.printf(" Initializing CA shifts %s\n", stringadb.c_str()); log.flush();
580 6 : read_cs(stringadb, "CA");
581 6 : stringadb = stringa_data + string("/CBshifts.dat");
582 6 : log.printf(" Initializing CB shifts %s\n", stringadb.c_str()); log.flush();
583 6 : read_cs(stringadb, "CB");
584 6 : stringadb = stringa_data + string("/Cshifts.dat");
585 6 : log.printf(" Initializing C' shifts %s\n", stringadb.c_str()); log.flush();
586 6 : read_cs(stringadb, "C");
587 6 : stringadb = stringa_data + string("/HAshifts.dat");
588 6 : log.printf(" Initializing HA shifts %s\n", stringadb.c_str()); log.flush();
589 6 : read_cs(stringadb, "HA");
590 6 : stringadb = stringa_data + string("/Hshifts.dat");
591 6 : log.printf(" Initializing H shifts %s\n", stringadb.c_str()); log.flush();
592 6 : read_cs(stringadb, "H");
593 6 : stringadb = stringa_data + string("/Nshifts.dat");
594 6 : log.printf(" Initializing N shifts %s\n", stringadb.c_str()); log.flush();
595 6 : read_cs(stringadb, "N");
596 :
597 : /* this is a workaround for those chemical shifts that can result in too large forces */
598 6 : remove_problematic("GLN", "CB");
599 6 : remove_problematic("ILE", "CB");
600 6 : remove_problematic("PRO", "N");
601 6 : remove_problematic("PRO", "H");
602 6 : remove_problematic("PRO", "CB");
603 6 : remove_problematic("GLY", "HA");
604 6 : remove_problematic("GLY", "CB");
605 : /* this is a workaround for those chemical shifts that are not parameterized */
606 6 : remove_problematic("HIE", "HA"); remove_problematic("HIP", "HA"); remove_problematic("HSP", "HA");
607 6 : remove_problematic("HIE", "H"); remove_problematic("HIP", "H"); remove_problematic("HSP", "H");
608 6 : remove_problematic("HIE", "N"); remove_problematic("HIP", "N"); remove_problematic("HSP", "N");
609 6 : remove_problematic("HIE", "CA"); remove_problematic("HIP", "CA"); remove_problematic("HSP", "CA");
610 6 : remove_problematic("HIE", "CB"); remove_problematic("HIP", "CB"); remove_problematic("HSP", "CB");
611 6 : remove_problematic("HIE", "C"); remove_problematic("HIP", "C"); remove_problematic("HSP", "C");
612 6 : remove_problematic("GLH", "HA"); remove_problematic("ASH", "HA"); remove_problematic("HSE", "HA");
613 6 : remove_problematic("GLH", "H"); remove_problematic("ASH", "H"); remove_problematic("HSE", "H");
614 6 : remove_problematic("GLH", "N"); remove_problematic("ASH", "N"); remove_problematic("HSE", "N");
615 6 : remove_problematic("GLH", "CA"); remove_problematic("ASH", "CA"); remove_problematic("HSE", "CA");
616 6 : remove_problematic("GLH", "CB"); remove_problematic("ASH", "CB"); remove_problematic("HSE", "CB");
617 6 : remove_problematic("GLH", "C"); remove_problematic("ASH", "C"); remove_problematic("HSE", "C");
618 6 : remove_problematic("UNK", "HA");
619 6 : remove_problematic("UNK", "H");
620 6 : remove_problematic("UNK", "N");
621 6 : remove_problematic("UNK", "CA");
622 6 : remove_problematic("UNK", "CB");
623 6 : remove_problematic("UNK", "C");
624 6 : remove_problematic("CYS", "HA");
625 6 : remove_problematic("CYS", "H");
626 6 : remove_problematic("CYS", "N");
627 6 : remove_problematic("CYS", "CA");
628 6 : remove_problematic("CYS", "CB");
629 6 : remove_problematic("CYS", "C");
630 6 : remove_problematic("HIS", "HA");
631 6 : remove_problematic("HIS", "H");
632 6 : remove_problematic("HIS", "N");
633 6 : remove_problematic("HIS", "CA");
634 6 : remove_problematic("HIS", "CB");
635 6 : remove_problematic("HIS", "C");
636 : /* done */
637 :
638 12 : vector<AtomNumber> atoms;
639 6 : parseAtomList("ATOMS",atoms);
640 6 : checkRead();
641 :
642 6 : log<<" Bibliography "
643 18 : <<plumed.cite("Kohlhoff K, Robustelli P, Cavalli A, Salvatella A, Vendruscolo M, J. Am. Chem. Soc. 131, 13894 (2009)")
644 18 : <<plumed.cite("Camilloni C, Robustelli P, De Simone A, Cavalli A, Vendruscolo M, J. Am. Chem. Soc. 134, 3968 (2012)")
645 18 : <<plumed.cite("Granata D, Camilloni C, Vendruscolo M, Laio A, Proc. Natl. Acad. Sci. USA 110, 6817 (2013)")<<"\n";
646 :
647 12 : const string str_cs[] = {"ha_","hn_","nh_","ca_","cb_","co_"};
648 6 : unsigned index=0;
649 6 : if(camshift) noexp = true;
650 6 : if(!camshift) {
651 15 : for(unsigned i=0; i<atom.size(); i++) {
652 890 : for(unsigned a=0; a<atom[i].size(); a++) {
653 880 : unsigned res=index+a;
654 880 : std::string num; Tools::convert(res,num);
655 6160 : for(unsigned at_kind=0; at_kind<6; at_kind++) {
656 5280 : if(atom[i][a].exp_cs[at_kind]!=0) {
657 2945 : addComponentWithDerivatives(str_cs[at_kind]+num);
658 2945 : componentIsNotPeriodic(str_cs[at_kind]+num);
659 2945 : atom[i][a].comp[at_kind] = getPntrToComponent(str_cs[at_kind]+num);
660 : }
661 : }
662 880 : }
663 10 : index += atom[i].size();
664 : }
665 : } else {
666 1 : addValueWithDerivatives();
667 1 : setNotPeriodic();
668 3 : for(unsigned i=0; i<atom.size(); i++) {
669 2 : index += atom[i].size();
670 : }
671 : }
672 :
673 6 : if(!noexp) {
674 5 : index = 0;
675 15 : for(unsigned i=0; i<atom.size(); i++) {
676 890 : for(unsigned a=0; a<atom[i].size(); a++) {
677 880 : unsigned res=index+a;
678 880 : std::string num; Tools::convert(res,num);
679 6160 : for(unsigned at_kind=0; at_kind<6; at_kind++) {
680 5280 : if(atom[i][a].exp_cs[at_kind]!=0) {
681 2945 : addComponent("exp"+str_cs[at_kind]+num);
682 2945 : componentIsNotPeriodic("exp"+str_cs[at_kind]+num);
683 2945 : Value* comp=getPntrToComponent("exp"+str_cs[at_kind]+num);
684 2945 : comp->set(atom[i][a].exp_cs[at_kind]);
685 : }
686 : }
687 880 : }
688 10 : index += atom[i].size();
689 : }
690 : }
691 :
692 : /* temporary check, the idea is that I can remove NRES completely */
693 6 : if(index!=numResidues) error("NRES and the number of residues in the PDB do not match!");
694 :
695 12 : requestAtoms(atoms);
696 6 : }
697 :
698 366 : void CS2Backbone::remove_problematic(const string &res, const string &nucl) {
699 : unsigned n;
700 366 : if(nucl=="HA") n=0;
701 306 : else if(nucl=="H") n=1;
702 246 : else if(nucl=="N") n=2;
703 186 : else if(nucl=="CA")n=3;
704 132 : else if(nucl=="CB")n=4;
705 54 : else if(nucl=="C") n=5;
706 366 : else return;
707 :
708 1098 : for(unsigned i=0; i<atom.size(); i++) {
709 65148 : for(unsigned a=0; a<atom[i].size(); a++) {
710 64416 : if(atom[i][a].res_name.c_str()==res) {
711 708 : atom[i][a].exp_cs[n] = 0;
712 : }
713 : }
714 : }
715 : }
716 :
717 36 : void CS2Backbone::read_cs(const string &file, const string &nucl) {
718 36 : ifstream in;
719 36 : in.open(file.c_str());
720 36 : if(!in) error("CS2Backbone: Unable to open " + file);
721 72 : istream_iterator<string> iter(in), end;
722 :
723 : unsigned n;
724 36 : if(nucl=="HA") n=0;
725 30 : else if(nucl=="H") n=1;
726 24 : else if(nucl=="N") n=2;
727 18 : else if(nucl=="CA")n=3;
728 12 : else if(nucl=="CB")n=4;
729 6 : else if(nucl=="C") n=5;
730 36 : else return;
731 :
732 36 : int oldseg = -1;
733 36 : int oldp = -1;
734 6408 : while(iter!=end) {
735 6336 : string tok;
736 6336 : tok = *iter; ++iter;
737 6336 : if(tok[0]=='#') { ++iter; continue;}
738 6192 : unsigned p = atoi(tok.c_str());
739 6192 : p = p - 1;
740 6192 : const unsigned seg = frag_segment(p);
741 6192 : p = frag_relitive_index(p,seg);
742 6192 : if(oldp==-1) oldp=p;
743 6192 : if(oldseg==-1) oldseg=seg;
744 6192 : if(p<oldp&&seg==oldseg) {
745 0 : string errmsg = "Error while reading " + file + "! The same residue number has been used twice!";
746 0 : error(errmsg);
747 : }
748 6192 : tok = *iter; ++iter;
749 6192 : double cs = atof(tok.c_str());
750 6192 : if(atom[seg][p].pos[n]<=0) cs=0;
751 6018 : else atom[seg][p].exp_cs[n] = cs;
752 6192 : oldseg = seg;
753 6192 : oldp = p;
754 6192 : }
755 72 : in.close();
756 : }
757 :
758 6 : void CS2Backbone::calculate()
759 : {
760 6 : if(pbc) makeWhole();
761 6 : if(getExchangeStep()) box_count=0;
762 6 : if(box_count==0) update_neighb();
763 :
764 6 : compute_ring_parameters();
765 6 : compute_dihedrals();
766 :
767 6 : double score = 0.;
768 :
769 6 : vector<double> camshift_sigma2(6);
770 6 : camshift_sigma2[0] = 0.08; // HA
771 6 : camshift_sigma2[1] = 0.30; // HN
772 6 : camshift_sigma2[2] = 9.00; // NH
773 6 : camshift_sigma2[3] = 1.30; // CA
774 6 : camshift_sigma2[4] = 1.56; // CB
775 6 : camshift_sigma2[5] = 1.70; // CO
776 :
777 6 : const unsigned chainsize = atom.size();
778 6 : const unsigned atleastned = 72+ringInfo.size()*6;
779 :
780 : // CYCLE OVER MULTIPLE CHAINS
781 17 : #pragma omp parallel num_threads(OpenMP::getNumThreads())
782 35 : for(unsigned s=0; s<chainsize; s++) {
783 23 : const unsigned psize = atom[s].size();
784 23 : vector<Vector> omp_deriv;
785 27 : if(camshift) omp_deriv.resize(getNumberOfAtoms(), Vector(0,0,0));
786 50 : #pragma omp for reduction(+:score)
787 : // SKIP FIRST AND LAST RESIDUE OF EACH CHAIN
788 25 : for(unsigned a=1; a<psize-1; a++) {
789 :
790 1033 : const Fragment *myfrag = &atom[s][a];
791 1031 : const unsigned aa_kind = myfrag->res_kind;
792 1031 : const unsigned res_type_curr = myfrag->res_type_curr;
793 1031 : const unsigned res_type_prev = myfrag->res_type_prev;
794 1031 : const unsigned res_type_next = myfrag->res_type_next;
795 1031 : const unsigned needed_atoms = atleastned+myfrag->box_nb.size();
796 :
797 : /* Extra Distances are the same for each residue */
798 1032 : const unsigned xdsize=myfrag->xd1.size();
799 1032 : vector<Vector> ext_distances(xdsize);
800 2064 : vector<double> ext_d(xdsize);
801 27862 : for(unsigned q=0; q<xdsize; q++) {
802 29638 : if(myfrag->xd1[q]==-1||myfrag->xd2[q]==-1) continue;
803 24024 : const Vector distance = delta(getPosition(myfrag->xd1[q]),getPosition(myfrag->xd2[q]));
804 24024 : ext_d[q] = distance.modulo();
805 24024 : ext_distances[q] = distance/ext_d[q];
806 : }
807 :
808 : // CYCLE OVER THE SIX BACKBONE CHEMICAL SHIFTS
809 7224 : for(unsigned at_kind=0; at_kind<6; at_kind++) {
810 6192 : if(atom[s][a].exp_cs[at_kind]!=0) {
811 : // Common constant and AATYPE
812 3534 : const double * CONSTAACURR = db.CONSTAACURR(aa_kind,at_kind);
813 3534 : const double * CONSTAANEXT = db.CONSTAANEXT(aa_kind,at_kind);
814 3534 : const double * CONSTAAPREV = db.CONSTAAPREV(aa_kind,at_kind);
815 :
816 7068 : double cs = CONSTAACURR[res_type_curr] +
817 7068 : CONSTAANEXT[res_type_next] +
818 7068 : CONSTAAPREV[res_type_prev];
819 : // this is the atom for which we are calculating the chemical shift
820 3534 : const unsigned ipos = myfrag->pos[at_kind];
821 :
822 3534 : vector<unsigned> list;
823 3533 : list.reserve(needed_atoms);
824 3534 : list.push_back(ipos);
825 7031 : vector<Vector> ff;
826 3534 : ff.reserve(needed_atoms);
827 3534 : ff.push_back(Vector(0,0,0));
828 :
829 : //PREV
830 3534 : const double * CONST_BB2_PREV = db.CONST_BB2_PREV(aa_kind,at_kind);
831 3534 : const unsigned presize = myfrag->prev.size();
832 21202 : for(unsigned q=0; q<presize; q++) {
833 17669 : const double cb2pq = CONST_BB2_PREV[q];
834 20477 : if(cb2pq==0.) continue;
835 14861 : const unsigned jpos = myfrag->prev[q];
836 14861 : list.push_back(jpos);
837 14862 : const Vector distance = delta(getPosition(jpos),getPosition(ipos));
838 14862 : const double d = distance.modulo();
839 14862 : const double fact = cb2pq/d;
840 :
841 14862 : cs += cb2pq*d;
842 14862 : const Vector der = fact*distance;
843 14862 : ff[0] += der;
844 14862 : ff.push_back(-der);
845 : }
846 :
847 : //CURR
848 3533 : const double * CONST_BB2_CURR = db.CONST_BB2_CURR(aa_kind,at_kind);
849 3533 : const unsigned cursize = myfrag->curr.size();
850 24735 : for(unsigned q=0; q<cursize; q++) {
851 21201 : const double cb2cq = CONST_BB2_CURR[q];
852 34035 : if(cb2cq==0.) continue;
853 14784 : const unsigned jpos = myfrag->curr[q];
854 14784 : if(ipos==jpos) continue;
855 14784 : list.push_back(jpos);
856 14782 : const Vector distance = delta(getPosition(jpos),getPosition(ipos));
857 14783 : const double d = distance.modulo();
858 14782 : const double fact = cb2cq/d;
859 :
860 14782 : cs += cb2cq*d;
861 14782 : const Vector der = fact*distance;
862 14784 : ff[0] += der;
863 14784 : ff.push_back(-der);
864 : }
865 :
866 : //NEXT
867 3534 : const double * CONST_BB2_NEXT = db.CONST_BB2_NEXT(aa_kind,at_kind);
868 3533 : const unsigned nexsize = myfrag->next.size();
869 21202 : for(unsigned q=0; q<nexsize; q++) {
870 17668 : const double cb2nq = CONST_BB2_NEXT[q];
871 18604 : if(cb2nq==0.) continue;
872 16732 : const unsigned jpos = myfrag->next[q];
873 16733 : list.push_back(jpos);
874 16734 : const Vector distance = delta(getPosition(jpos),getPosition(ipos));
875 16733 : const double d = distance.modulo();
876 16734 : const double fact = cb2nq/d;
877 :
878 16734 : cs += cb2nq*d;
879 16734 : const Vector der = fact*distance;
880 16734 : ff[0] += der;
881 16733 : ff.push_back(-der);
882 : }
883 :
884 : //SIDE CHAIN
885 3534 : const double * CONST_SC2 = db.CONST_SC2(aa_kind,at_kind,res_type_curr);
886 3534 : const unsigned sidsize = myfrag->side_chain.size();
887 36587 : for(unsigned q=0; q<sidsize; q++) {
888 33053 : const double cs2q = CONST_SC2[q];
889 70815 : if(cs2q==0.) continue;
890 14172 : const unsigned jpos = myfrag->side_chain[q];
891 14172 : if(ipos==jpos) continue;
892 14172 : list.push_back(jpos);
893 14172 : const Vector distance = delta(getPosition(jpos),getPosition(ipos));
894 14172 : const double d = distance.modulo();
895 14172 : const double fact = cs2q/d;
896 :
897 14172 : cs += cs2q*d;
898 14172 : const Vector der = fact*distance;
899 14172 : ff[0] += der;
900 14172 : ff.push_back(-der);
901 : }
902 :
903 : //EXTRA DIST
904 3534 : const double * CONST_XD = db.CONST_XD(aa_kind,at_kind);
905 95411 : for(unsigned q=0; q<xdsize; q++) {
906 91877 : const double cxdq = CONST_XD[q];
907 102467 : if(cxdq==0.) continue;
908 96167 : if(myfrag->xd1[q]==-1||myfrag->xd2[q]==-1) continue;
909 83393 : list.push_back(myfrag->xd2[q]);
910 83387 : list.push_back(myfrag->xd1[q]);
911 83370 : cs += cxdq*ext_d[q];
912 83381 : const Vector der = cxdq*ext_distances[q];
913 83391 : ff.push_back( der);
914 83392 : ff.push_back(-der);
915 : }
916 :
917 : //NON BOND
918 : {
919 3534 : const double * CONST_CO_SPHERE3 = db.CO_SPHERE(aa_kind,at_kind,0);
920 3534 : const double * CONST_CO_SPHERE = db.CO_SPHERE(aa_kind,at_kind,1);
921 3534 : const unsigned boxsize = myfrag->box_nb.size();
922 378308 : for(unsigned bat=0; bat<boxsize; bat++) {
923 374774 : const unsigned jpos = myfrag->box_nb[bat];
924 374801 : const Vector distance = delta(getPosition(jpos),getPosition(ipos));
925 374885 : const double d2 = distance.modulo2();
926 :
927 374747 : if(d2<cutOffDist2) {
928 65121 : double factor1 = sqrt(d2);
929 65121 : double dfactor1 = 1./factor1;
930 65121 : double factor3 = dfactor1*dfactor1*dfactor1;
931 65121 : double dfactor3 = -3.*factor3*dfactor1*dfactor1;
932 :
933 65121 : if(d2>cutOnDist2) {
934 61026 : const double af = cutOffDist2 - d2;
935 61026 : const double bf = cutOffDist2 - 3.*cutOnDist2 + 2.*d2;
936 61026 : const double cf = invswitch*af;
937 61026 : const double df = cf*af*bf;
938 61026 : factor1 *= df;
939 61026 : factor3 *= df;
940 :
941 61026 : const double d4 = d2*d2;
942 61026 : const double af1 = 15.*cutOnDist2*d2;
943 61026 : const double bf1 = -14.*d4;
944 61026 : const double cf1 = -3.*cutOffDist2*cutOnDist2 + cutOffDist2*d2;
945 61026 : const double df1 = af1+bf1+cf1;
946 61026 : dfactor1 *= cf*(cutOffDist4+df1);
947 :
948 61026 : const double af3 = +2.*cutOffDist2*cutOnDist2;
949 61026 : const double bf3 = d2*(cutOffDist2+cutOnDist2);
950 61026 : const double cf3 = -2.*d4;
951 61026 : const double df3 = (af3+bf3+cf3)*d2;
952 61026 : dfactor3 *= invswitch*(cutMixed+df3);
953 : }
954 :
955 65121 : const unsigned t = type[jpos];
956 65122 : cs += factor1*CONST_CO_SPHERE[t] + factor3*CONST_CO_SPHERE3[t] ;
957 65122 : const double fact = dfactor1*CONST_CO_SPHERE[t]+dfactor3*CONST_CO_SPHERE3[t];
958 65122 : const Vector der = fact*distance;
959 :
960 65122 : list.push_back(jpos);
961 65119 : ff[0] += der;
962 65121 : ff.push_back(-der);
963 : }
964 : }
965 : }
966 : //END NON BOND
967 :
968 : //RINGS
969 : {
970 3534 : const double *rc = db.CO_RING(aa_kind,at_kind);
971 3534 : const unsigned rsize = ringInfo.size();
972 74210 : for(unsigned i=0; i<rsize; i++) {
973 : // compute angle from ring middle point to current atom position
974 : // get distance vector from query atom to ring center and normal vector to ring plane
975 70676 : const Vector n = ringInfo[i].normVect;
976 70677 : const double nL = ringInfo[i].lengthNV;
977 70679 : const double inL2 = ringInfo[i].lengthN2;
978 :
979 70677 : const Vector d = delta(ringInfo[i].position, getPosition(ipos));
980 70676 : const double dL2 = d.modulo2();
981 70673 : const double dL = sqrt(dL2);
982 70673 : const double idL3 = 1./(dL2*dL);
983 :
984 70673 : const double dn = dotProduct(d,n);
985 70680 : const double dn2 = dn*dn;
986 70680 : const double dLnL = dL*nL;
987 70680 : const double dL_nL = dL/nL;
988 :
989 70680 : const double ang2 = dn2*inL2/dL2;
990 70680 : const double u = 1.-3.*ang2;
991 70680 : const double cc = rc[ringInfo[i].rtype];
992 :
993 70680 : cs += cc*u*idL3;
994 :
995 70680 : const double fUU = -6*dn*inL2;
996 70680 : const double fUQ = fUU/dL;
997 70680 : const Vector gradUQ = fUQ*(dL2*n - dn*d);
998 70680 : const Vector gradVQ = (3*dL*u)*d;
999 :
1000 70680 : const double fact = cc*idL3*idL3;
1001 70680 : ff[0] += fact*(gradUQ - gradVQ);
1002 :
1003 70679 : const double fU = fUU/nL;
1004 70679 : double OneOverN = 1./6.;
1005 74213 : if(ringInfo[i].numAtoms==5) OneOverN=1./3.;
1006 70680 : const Vector factor2 = OneOverN*n;
1007 70679 : const Vector factor4 = (OneOverN/dL_nL)*d;
1008 :
1009 70680 : const Vector gradV = -OneOverN*gradVQ;
1010 :
1011 70680 : if(ringInfo[i].numAtoms==6) {
1012 : // update forces on ring atoms
1013 469857 : for(unsigned at=0; at<6; at++) {
1014 402718 : const Vector ab = crossProduct(d,ringInfo[i].g[at]);
1015 402821 : const Vector c = crossProduct(n,ringInfo[i].g[at]);
1016 402813 : const Vector factor3 = 0.5*dL_nL*c;
1017 402852 : const Vector factor1 = 0.5*ab;
1018 402857 : const Vector gradU = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
1019 402835 : ff.push_back(fact*(gradU - gradV));
1020 402759 : list.push_back(ringInfo[i].atom[at]);
1021 : }
1022 : } else {
1023 14136 : for(unsigned at=0; at<3; at++) {
1024 10602 : const Vector ab = crossProduct(d,ringInfo[i].g[at]);
1025 10602 : const Vector c = crossProduct(n,ringInfo[i].g[at]);
1026 10602 : const Vector factor3 = dL_nL*c;
1027 10602 : const Vector factor1 = ab;
1028 10602 : const Vector gradU = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
1029 10602 : ff.push_back(fact*(gradU - gradV));
1030 : }
1031 3534 : list.push_back(ringInfo[i].atom[0]);
1032 3534 : list.push_back(ringInfo[i].atom[2]);
1033 3534 : list.push_back(ringInfo[i].atom[3]);
1034 : }
1035 : }
1036 : }
1037 : //END OF RINGS
1038 :
1039 : //DIHEDRAL ANGLES
1040 : {
1041 3534 : const double *CO_DA = db.CO_DA(aa_kind,at_kind);
1042 3534 : if(myfrag->phi.size()==4) {
1043 3534 : const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,0);
1044 3534 : const double val1 = 3.*myfrag->t_phi+PARS_DA[3];
1045 3534 : const double val2 = myfrag->t_phi+PARS_DA[4];
1046 3534 : cs += CO_DA[0]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
1047 3534 : const double fact = -CO_DA[0]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
1048 :
1049 3534 : ff.push_back(fact*myfrag->dd0[0]);
1050 3534 : ff.push_back(fact*myfrag->dd10[0]);
1051 3534 : ff.push_back(fact*myfrag->dd21[0]);
1052 3534 : ff.push_back(-fact*myfrag->dd2[0]);
1053 3534 : list.push_back(myfrag->phi[0]);
1054 3534 : list.push_back(myfrag->phi[1]);
1055 3534 : list.push_back(myfrag->phi[2]);
1056 3534 : list.push_back(myfrag->phi[3]);
1057 : }
1058 :
1059 3534 : if(myfrag->psi.size()==4) {
1060 3534 : const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,1);
1061 3534 : const double val1 = 3.*myfrag->t_psi+PARS_DA[3];
1062 3534 : const double val2 = myfrag->t_psi+PARS_DA[4];
1063 3534 : cs += CO_DA[1]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
1064 3534 : const double fact = -CO_DA[1]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
1065 :
1066 3534 : ff.push_back(fact*myfrag->dd0[1]);
1067 3534 : ff.push_back(fact*myfrag->dd10[1]);
1068 3534 : ff.push_back(fact*myfrag->dd21[1]);
1069 3533 : ff.push_back(-fact*myfrag->dd2[1]);
1070 3534 : list.push_back(myfrag->psi[0]);
1071 3533 : list.push_back(myfrag->psi[1]);
1072 3534 : list.push_back(myfrag->psi[2]);
1073 3534 : list.push_back(myfrag->psi[3]);
1074 : }
1075 :
1076 : //Chi
1077 3534 : if(myfrag->chi1.size()==4) {
1078 2819 : const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,2);
1079 2819 : const double val1 = 3.*myfrag->t_chi1+PARS_DA[3];
1080 2819 : const double val2 = myfrag->t_chi1+PARS_DA[4];
1081 2819 : cs += CO_DA[2]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
1082 2819 : const double fact = -CO_DA[2]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
1083 :
1084 2819 : ff.push_back(fact*myfrag->dd0[2]);
1085 2820 : ff.push_back(fact*myfrag->dd10[2]);
1086 2820 : ff.push_back(fact*myfrag->dd21[2]);
1087 2820 : ff.push_back(-fact*myfrag->dd2[2]);
1088 2820 : list.push_back(myfrag->chi1[0]);
1089 2820 : list.push_back(myfrag->chi1[1]);
1090 2820 : list.push_back(myfrag->chi1[2]);
1091 2820 : list.push_back(myfrag->chi1[3]);
1092 : }
1093 : }
1094 : //END OF DIHE
1095 :
1096 : Value * comp;
1097 3533 : double fact = 1.0;
1098 3533 : if(!camshift) {
1099 2944 : comp = atom[s][a].comp[at_kind];
1100 2944 : comp->set(cs);
1101 2944 : Tensor virial;
1102 627063 : for(unsigned i=0; i<list.size(); i++) {
1103 624094 : setAtomsDerivatives(comp,list[i],fact*ff[i]);
1104 623823 : virial-=Tensor(getPosition(list[i]),fact*ff[i]);
1105 : }
1106 2945 : setBoxDerivatives(comp,virial);
1107 : } else {
1108 : // but I would also divide for the weights derived with metainference
1109 589 : comp = getPntrToValue();
1110 588 : score += (cs - atom[s][a].exp_cs[at_kind])*(cs - atom[s][a].exp_cs[at_kind])/camshift_sigma2[at_kind];
1111 589 : fact = 2.0*(cs - atom[s][a].exp_cs[at_kind])/camshift_sigma2[at_kind];
1112 589 : for(unsigned i=0; i<list.size(); i++) omp_deriv[list[i]] += fact*ff[i];
1113 3534 : }
1114 : }
1115 1032 : }
1116 : }
1117 48 : #pragma omp critical
1118 28 : if(camshift) for(int i=0; i<getPositions().size(); i++) setAtomsDerivatives(i,omp_deriv[i]);
1119 24 : }
1120 :
1121 : // in the case of camshift we calculate the virial at the end
1122 6 : if(camshift) {
1123 1 : setBoxDerivativesNoPbc();
1124 1 : setValue(score);
1125 : }
1126 :
1127 6 : ++box_count;
1128 6 : if(box_count == box_nupdate) box_count = 0;
1129 6 : }
1130 :
1131 6 : void CS2Backbone::update_neighb() {
1132 6 : const unsigned chainsize = atom.size();
1133 18 : for(unsigned s=0; s<chainsize; s++) {
1134 12 : const unsigned psize = atom[s].size();
1135 36 : #pragma omp parallel for num_threads(OpenMP::getNumThreads())
1136 24 : for(unsigned a=1; a<psize-1; a++) {
1137 1031 : const unsigned boxsize = getNumberOfAtoms();
1138 1031 : atom[s][a].box_nb.clear();
1139 1031 : atom[s][a].box_nb.reserve(300);
1140 1032 : const unsigned res_curr = res_num[atom[s][a].pos[0]];
1141 2662960 : for(unsigned bat=0; bat<boxsize; bat++) {
1142 2661928 : const unsigned res_dist = abs(static_cast<int>(res_curr-res_num[bat]));
1143 2694210 : if(res_dist<2) continue;
1144 17643363 : for(unsigned at_kind=0; at_kind<6; at_kind++) {
1145 21530664 : if(atom[s][a].exp_cs[at_kind]==0.) continue;
1146 8570568 : const unsigned ipos = atom[s][a].pos[at_kind];
1147 8559910 : const Vector distance = delta(getPosition(bat),getPosition(ipos));
1148 8547849 : const double d2=distance.modulo2();
1149 8560869 : if(d2<cutOffNB2) {
1150 103367 : atom[s][a].box_nb.push_back(bat);
1151 103358 : break;
1152 : }
1153 : }
1154 : }
1155 : }
1156 : }
1157 6 : }
1158 :
1159 6 : void CS2Backbone::compute_ring_parameters() {
1160 126 : for(unsigned i=0; i<ringInfo.size(); i++) {
1161 120 : const unsigned size = ringInfo[i].numAtoms;
1162 120 : if(size==6) {
1163 114 : ringInfo[i].g[0] = delta(getPosition(ringInfo[i].atom[4]),getPosition(ringInfo[i].atom[2]));
1164 114 : ringInfo[i].g[1] = delta(getPosition(ringInfo[i].atom[5]),getPosition(ringInfo[i].atom[3]));
1165 114 : ringInfo[i].g[2] = delta(getPosition(ringInfo[i].atom[0]),getPosition(ringInfo[i].atom[4]));
1166 114 : ringInfo[i].g[3] = delta(getPosition(ringInfo[i].atom[1]),getPosition(ringInfo[i].atom[5]));
1167 114 : ringInfo[i].g[4] = delta(getPosition(ringInfo[i].atom[2]),getPosition(ringInfo[i].atom[0]));
1168 114 : ringInfo[i].g[5] = delta(getPosition(ringInfo[i].atom[3]),getPosition(ringInfo[i].atom[1]));
1169 114 : vector<Vector> a(size);
1170 114 : a[0] = getPosition(ringInfo[i].atom[0]);
1171 : // ring center
1172 114 : Vector midP = a[0];
1173 684 : for(unsigned j=1; j<size; j++) {
1174 570 : a[j] = getPosition(ringInfo[i].atom[j]);
1175 570 : midP += a[j];
1176 : }
1177 114 : midP /= (double) size;
1178 114 : ringInfo[i].position = midP;
1179 : // compute normal vector to plane containing first three atoms in array
1180 114 : ringInfo[i].n1 = crossProduct(delta(a[0],a[4]), delta(a[0],a[2]));
1181 : // compute normal vector to plane containing last three atoms in array
1182 : // NB: third atom of five-membered ring used for both computations above
1183 114 : ringInfo[i].n2 = crossProduct(delta(a[3],a[1]), delta(a[3],a[5]));
1184 : // ring plane normal vector is average of n1 and n2
1185 114 : ringInfo[i].normVect = 0.5*(ringInfo[i].n1 + ringInfo[i].n2);
1186 : } else {
1187 6 : ringInfo[i].g[0] = delta(getPosition(ringInfo[i].atom[3]),getPosition(ringInfo[i].atom[2]));
1188 6 : ringInfo[i].g[1] = delta(getPosition(ringInfo[i].atom[0]),getPosition(ringInfo[i].atom[3]));
1189 6 : ringInfo[i].g[2] = delta(getPosition(ringInfo[i].atom[2]),getPosition(ringInfo[i].atom[0]));
1190 6 : vector<Vector> a(size);
1191 36 : for(unsigned j=0; j<size; j++) {
1192 30 : a[j] = getPosition(ringInfo[i].atom[j]);
1193 : }
1194 : // ring center
1195 6 : Vector midP = (a[0]+a[2]+a[3])/3.;
1196 6 : ringInfo[i].position = midP;
1197 : // compute normal vector to plane containing first three atoms in array
1198 6 : ringInfo[i].n1 = crossProduct(delta(a[0],a[3]), delta(a[0],a[2]));
1199 : // ring plane normal vector is average of n1 and n2
1200 6 : ringInfo[i].normVect = ringInfo[i].n1;
1201 :
1202 : }
1203 : // calculate squared length and length of normal vector
1204 120 : ringInfo[i].lengthN2 = 1./ringInfo[i].normVect.modulo2();
1205 120 : ringInfo[i].lengthNV = 1./sqrt(ringInfo[i].lengthN2);
1206 : }
1207 6 : }
1208 :
1209 6 : void CS2Backbone::compute_dihedrals() {
1210 6 : const unsigned chainsize = atom.size();
1211 18 : for(unsigned s=0; s<chainsize; s++) {
1212 12 : const unsigned psize = atom[s].size();
1213 36 : #pragma omp parallel for num_threads(OpenMP::getNumThreads())
1214 24 : for(unsigned a=1; a<psize-1; a++) {
1215 1030 : const Fragment *myfrag = &atom[s][a];
1216 1031 : if(myfrag->phi.size()==4) {
1217 1030 : const Vector d0 = delta(getPosition(myfrag->phi[1]), getPosition(myfrag->phi[0]));
1218 1032 : const Vector d1 = delta(getPosition(myfrag->phi[2]), getPosition(myfrag->phi[1]));
1219 1032 : const Vector d2 = delta(getPosition(myfrag->phi[3]), getPosition(myfrag->phi[2]));
1220 : Torsion t;
1221 1032 : Vector dd0, dd1, dd2;
1222 1032 : atom[s][a].t_phi = t.compute(d0,d1,d2,dd0,dd1,dd2);
1223 1032 : atom[s][a].dd0[0] = dd0;
1224 1032 : atom[s][a].dd10[0] = dd1-dd0;
1225 1029 : atom[s][a].dd21[0] = dd2-dd1;
1226 1029 : atom[s][a].dd2[0] = dd2;
1227 : }
1228 1026 : if(myfrag->psi.size()==4) {
1229 1026 : const Vector d0 = delta(getPosition(myfrag->psi[1]), getPosition(myfrag->psi[0]));
1230 1032 : const Vector d1 = delta(getPosition(myfrag->psi[2]), getPosition(myfrag->psi[1]));
1231 1032 : const Vector d2 = delta(getPosition(myfrag->psi[3]), getPosition(myfrag->psi[2]));
1232 : Torsion t;
1233 1032 : Vector dd0, dd1, dd2;
1234 1032 : atom[s][a].t_psi = t.compute(d0,d1,d2,dd0,dd1,dd2);
1235 1032 : atom[s][a].dd0[1] = dd0;
1236 1032 : atom[s][a].dd10[1] = dd1-dd0;
1237 1032 : atom[s][a].dd21[1] = dd2-dd1;
1238 1032 : atom[s][a].dd2[1] = dd2;
1239 : }
1240 1032 : if(myfrag->chi1.size()==4) {
1241 796 : const Vector d0 = delta(getPosition(myfrag->chi1[1]), getPosition(myfrag->chi1[0]));
1242 798 : const Vector d1 = delta(getPosition(myfrag->chi1[2]), getPosition(myfrag->chi1[1]));
1243 798 : const Vector d2 = delta(getPosition(myfrag->chi1[3]), getPosition(myfrag->chi1[2]));
1244 : Torsion t;
1245 798 : Vector dd0, dd1, dd2;
1246 798 : atom[s][a].t_chi1 = t.compute(d0,d1,d2,dd0,dd1,dd2);
1247 798 : atom[s][a].dd0[2] = dd0;
1248 798 : atom[s][a].dd10[2] = dd1-dd0;
1249 798 : atom[s][a].dd21[2] = dd2-dd1;
1250 798 : atom[s][a].dd2[2] = dd2;
1251 : }
1252 : }
1253 : }
1254 6 : }
1255 :
1256 6 : void CS2Backbone::init_backbone(const PDB &pdb) {
1257 : // number of chains
1258 6 : vector<string> chains;
1259 6 : pdb.getChainNames( chains );
1260 6 : seg_last.resize(chains.size());
1261 6 : unsigned old_size=0;
1262 :
1263 18 : for(unsigned i=0; i<chains.size(); i++) {
1264 : unsigned start, end;
1265 12 : string errmsg;
1266 12 : pdb.getResidueRange( chains[i], start, end, errmsg );
1267 :
1268 12 : unsigned res_offset = start;
1269 12 : unsigned resrange = end-start+1;
1270 :
1271 12 : if(i==0) seg_last[i] = resrange;
1272 6 : else seg_last[i] = seg_last[i-1]+resrange;
1273 :
1274 24 : vector<int> N_;
1275 24 : vector<int> H_;
1276 24 : vector<int> CA_;
1277 24 : vector<int> CB_;
1278 24 : vector<int> HA_;
1279 24 : vector<int> C_;
1280 24 : vector<int> O_;
1281 24 : vector<int> CX_;
1282 12 : N_.resize (resrange,-1);
1283 12 : H_.resize (resrange,-1);
1284 12 : CA_.resize(resrange,-1);
1285 12 : CB_.resize(resrange,-1);
1286 12 : HA_.resize(resrange,-1);
1287 12 : C_.resize (resrange,-1);
1288 12 : O_.resize (resrange,-1);
1289 12 : CX_.resize(resrange,-1);
1290 :
1291 24 : vector<AtomNumber> allatoms = pdb.getAtomsInChain(chains[i]);
1292 : // cycle over all the atoms in the chain
1293 15684 : for(unsigned a=0; a<allatoms.size(); a++) {
1294 15672 : unsigned atm_index=a+old_size;
1295 15672 : unsigned f = pdb.getResidueNumber(allatoms[a]);
1296 15672 : unsigned f_idx = f-res_offset;
1297 15672 : string AN = pdb.getAtomName(allatoms[a]);
1298 31344 : string RES = pdb.getResidueName(allatoms[a]);
1299 15672 : if(AN=="N") N_ [f_idx] = atm_index;
1300 14616 : else if(AN=="H" ||AN=="HN" ) H_ [f_idx] = atm_index;
1301 13614 : else if(AN=="HA"||AN=="HA1") HA_[f_idx] = atm_index;
1302 12558 : else if(AN=="CA" ) CA_[f_idx] = atm_index;
1303 11502 : else if(AN=="CB" ) CB_[f_idx] = atm_index;
1304 10626 : else if(AN=="C" ) C_ [f_idx] = atm_index;
1305 9570 : else if(AN=="O" ) O_ [f_idx] = atm_index;
1306 8526 : else if(AN=="CD"&&RES=="PRO") H_[f_idx] = atm_index;
1307 15672 : if(is_chi1_cx(RES,AN)) CX_[f_idx] = atm_index;
1308 15672 : }
1309 12 : old_size+=allatoms.size();
1310 :
1311 : // vector of residues for a given chain
1312 24 : vector<Fragment> atm_;
1313 : // cycle over all residues in the chain
1314 1068 : for(unsigned a=start; a<=end; a++) {
1315 1056 : unsigned f_idx = a - res_offset;
1316 1056 : Fragment at;
1317 1056 : at.pos[0] = HA_[f_idx];
1318 1056 : at.pos[1] = H_[f_idx];
1319 1056 : at.pos[2] = N_[f_idx];
1320 1056 : at.pos[3] = CA_[f_idx];
1321 1056 : at.pos[4] = CB_[f_idx];
1322 1056 : at.pos[5] = C_[f_idx];
1323 1056 : at.res_type_prev = at.res_type_curr = at.res_type_next = 0;
1324 1056 : at.res_name = pdb.getResidueName(a, chains[i]);
1325 1056 : at.res_kind = db.kind(at.res_name);
1326 1056 : at.fd = a;
1327 : //REGISTER PREV CURR NEXT
1328 : {
1329 1056 : if(a>start) {
1330 1044 : at.prev.push_back( N_[f_idx-1]);
1331 1044 : at.prev.push_back(CA_[f_idx-1]);
1332 1044 : at.prev.push_back(HA_[f_idx-1]);
1333 1044 : at.prev.push_back( C_[f_idx-1]);
1334 1044 : at.prev.push_back( O_[f_idx-1]);
1335 1044 : at.res_type_prev = frag2enum(pdb.getResidueName(a-1, chains[i]));
1336 : }
1337 :
1338 1056 : at.curr.push_back( N_[f_idx]);
1339 1056 : at.curr.push_back( H_[f_idx]);
1340 1056 : at.curr.push_back(CA_[f_idx]);
1341 1056 : at.curr.push_back(HA_[f_idx]);
1342 1056 : at.curr.push_back( C_[f_idx]);
1343 1056 : at.curr.push_back( O_[f_idx]);
1344 1056 : at.res_type_curr = frag2enum(pdb.getResidueName(a, chains[i]));
1345 :
1346 1056 : if(a<end) {
1347 1044 : at.next.push_back (N_[f_idx+1]);
1348 1044 : at.next.push_back (H_[f_idx+1]);
1349 1044 : at.next.push_back(CA_[f_idx+1]);
1350 1044 : at.next.push_back(HA_[f_idx+1]);
1351 1044 : at.next.push_back( C_[f_idx+1]);
1352 1044 : at.res_type_next = frag2enum(pdb.getResidueName(a+1, chains[i]));
1353 : }
1354 :
1355 : //PHI | PSI | CH1
1356 1056 : if(a>start) {
1357 1044 : at.phi.push_back( C_[f_idx-1]);
1358 1044 : at.phi.push_back( N_[f_idx]);
1359 1044 : at.phi.push_back(CA_[f_idx]);
1360 1044 : at.phi.push_back( C_[f_idx]);
1361 : }
1362 :
1363 1056 : if(a<end) {
1364 1044 : at.psi.push_back( N_[f_idx]);
1365 1044 : at.psi.push_back(CA_[f_idx]);
1366 1044 : at.psi.push_back( C_[f_idx]);
1367 1044 : at.psi.push_back( N_[f_idx+1]);
1368 : }
1369 :
1370 1056 : if(CX_[f_idx]!=-1&&CB_[f_idx]!=-1) {
1371 816 : at.chi1.push_back( N_[f_idx]);
1372 816 : at.chi1.push_back(CA_[f_idx]);
1373 816 : at.chi1.push_back(CB_[f_idx]);
1374 816 : at.chi1.push_back(CX_[f_idx]);
1375 : }
1376 : }
1377 1056 : atm_.push_back(at);
1378 1056 : }
1379 12 : atom.push_back(atm_);
1380 18 : }
1381 6 : }
1382 :
1383 6 : void CS2Backbone::init_sidechain(const PDB &pdb) {
1384 6 : vector<string> chains;
1385 6 : pdb.getChainNames( chains );
1386 6 : unsigned old_size=0;
1387 : // cycle over chains
1388 18 : for(unsigned s=0; s<atom.size(); s++) {
1389 12 : AtomNumber astart, aend;
1390 12 : string errmsg;
1391 12 : pdb.getAtomRange( chains[s], astart, aend, errmsg );
1392 12 : unsigned atom_offset = astart.index();
1393 : // cycle over residues
1394 1068 : for(unsigned a=0; a<atom[s].size(); a++) {
1395 1056 : if(atom[s][a].res_name=="UNK") continue;
1396 1056 : vector<AtomNumber> atm = pdb.getAtomsInResidue(atom[s][a].fd, chains[s]);
1397 2112 : vector<string> sc_atm = side_chain_atoms(atom[s][a].res_name);
1398 :
1399 13338 : for(unsigned sc=0; sc<sc_atm.size(); sc++) {
1400 231804 : for(unsigned aa=0; aa<atm.size(); aa++) {
1401 219522 : if(pdb.getAtomName(atm[aa])==sc_atm[sc]) {
1402 9342 : atom[s][a].side_chain.push_back(atm[aa].index()-atom_offset+old_size);
1403 : }
1404 : }
1405 : }
1406 :
1407 1056 : }
1408 12 : old_size = aend.index()+1;
1409 18 : }
1410 6 : }
1411 :
1412 6 : void CS2Backbone::init_xdist(const PDB &pdb) {
1413 : const string atomsP1[] = {"H", "H", "H", "C", "C", "C",
1414 : "O", "O", "O", "N", "N", "N",
1415 : "O", "O", "O", "N", "N", "N",
1416 : "CG", "CG", "CG", "CG", "CG",
1417 : "CG", "CG", "CA"
1418 162 : };
1419 :
1420 : const int resOffsetP1 [] = {0, 0, 0, -1, -1, -1,
1421 : 0, 0, 0, 1, 1, 1,
1422 : -1, -1, -1, 0, 0, 0,
1423 : 0, 0, 0, 0, 0, -1, 1, -1
1424 6 : };
1425 :
1426 : const string atomsP2[] = {"HA", "C", "CB", "HA", "C", "CB",
1427 : "HA", "N", "CB", "HA", "N", "CB",
1428 : "HA", "N", "CB", "HA", "N", "CB",
1429 : "HA", "N", "C", "C", "N", "CA", "CA", "CA"
1430 12 : };
1431 :
1432 6 : 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};
1433 :
1434 12 : vector<string> chains;
1435 6 : pdb.getChainNames( chains );
1436 6 : unsigned old_size=0;
1437 18 : for(unsigned s=0; s<atom.size(); s++) {
1438 12 : AtomNumber astart, aend;
1439 12 : string errmsg;
1440 12 : pdb.getAtomRange( chains[s], astart, aend, errmsg );
1441 12 : unsigned atom_offset = astart.index();
1442 :
1443 1044 : for(unsigned a=1; a<atom[s].size()-1; a++) {
1444 1032 : vector<AtomNumber> atm_curr = pdb.getAtomsInResidue(atom[s][a].fd,chains[s]);
1445 2064 : vector<AtomNumber> atm_prev = pdb.getAtomsInResidue(atom[s][a].fd-1,chains[s]);
1446 2064 : vector<AtomNumber> atm_next = pdb.getAtomsInResidue(atom[s][a].fd+1,chains[s]);
1447 :
1448 27864 : for(unsigned q=0; q<db.get_numXtraDists()-1; q++) {
1449 26832 : vector<AtomNumber>::iterator at1, at1_end;
1450 26832 : vector<AtomNumber>::iterator at2, at2_end;
1451 :
1452 26832 : bool init_p1=false;
1453 26832 : AtomNumber p1;
1454 26832 : bool init_p2=false;
1455 26832 : AtomNumber p2;
1456 :
1457 26832 : if(resOffsetP1[q]== 0) { at1 = atm_curr.begin(); at1_end = atm_curr.end();}
1458 26832 : if(resOffsetP1[q]==-1) { at1 = atm_prev.begin(); at1_end = atm_prev.end();}
1459 26832 : if(resOffsetP1[q]==+1) { at1 = atm_next.begin(); at1_end = atm_next.end();}
1460 239766 : while(at1!=at1_end) {
1461 211170 : AtomNumber aa = *at1;
1462 211170 : ++at1;
1463 211170 : string name = pdb.getAtomName(aa);
1464 :
1465 211170 : xdist_name_map(name);
1466 :
1467 211170 : if(name==atomsP1[q]) {
1468 25068 : p1 = aa;
1469 25068 : init_p1=true;
1470 25068 : break;
1471 : }
1472 186102 : }
1473 :
1474 26832 : if(resOffsetP2[q]== 0) { at2 = atm_curr.begin(); at2_end = atm_curr.end();}
1475 26832 : if(resOffsetP2[q]==-1) { at2 = atm_prev.begin(); at2_end = atm_prev.end();}
1476 26832 : if(resOffsetP2[q]==+1) { at2 = atm_next.begin(); at2_end = atm_next.end();}
1477 166716 : while(at2!=at2_end) {
1478 138840 : AtomNumber aa = *at2;
1479 138840 : ++at2;
1480 138840 : string name = pdb.getAtomName(aa);
1481 :
1482 138840 : xdist_name_map(name);
1483 :
1484 138840 : if(name==atomsP2[q]) {
1485 25788 : p2 = aa;
1486 25788 : init_p2=true;
1487 25788 : break;
1488 : }
1489 113052 : }
1490 26832 : int add1 = -1;
1491 26832 : int add2 = -1;
1492 26832 : if(init_p1) add1=p1.index()-atom_offset+old_size;
1493 26832 : if(init_p2) add2=p2.index()-atom_offset+old_size;
1494 26832 : atom[s][a].xd1.push_back(add1);
1495 26832 : atom[s][a].xd2.push_back(add2);
1496 : }
1497 1032 : }
1498 12 : old_size = aend.index()+1;
1499 174 : }
1500 6 : }
1501 :
1502 6 : void CS2Backbone::init_types(const PDB &pdb) {
1503 6 : vector<AtomNumber> aa = pdb.getAtomNumbers();
1504 15678 : for(unsigned i=0; i<aa.size(); i++) {
1505 15672 : unsigned frag = pdb.getResidueNumber(aa[i]);
1506 15672 : string fragName = pdb.getResidueName(aa[i]);
1507 31344 : string atom_name = pdb.getAtomName(aa[i]);
1508 15672 : char atom_type = atom_name[0];
1509 15672 : if(isdigit(atom_name[0])) atom_type = atom_name[1];
1510 15672 : res_num.push_back(frag);
1511 15672 : unsigned t = 0;
1512 15672 : if (!isSP2(fragName, atom_name)) {
1513 12312 : if (atom_type == 'C') t = D_C;
1514 9306 : else if (atom_type == 'O') t = D_O;
1515 9150 : else if (atom_type == 'H') t = D_H;
1516 1398 : else if (atom_type == 'N') t = D_N;
1517 54 : else if (atom_type == 'S') t = D_S;
1518 0 : else plumed_merror("CS2Backbone:init_type: unknown atom type!\n");
1519 : } else {
1520 3360 : if (atom_type == 'C') t = D_C2;
1521 1368 : else if (atom_type == 'O') t = D_O2;
1522 0 : else if (atom_type == 'N') t = D_N2;
1523 0 : else plumed_merror("CS2Backbone:init_type: unknown atom type!\n");
1524 : }
1525 15672 : type.push_back(t);
1526 15678 : }
1527 6 : }
1528 :
1529 6 : void CS2Backbone::init_rings(const PDB &pdb) {
1530 :
1531 42 : const string pheTyr_n[] = {"CG","CD1","CE1","CZ","CE2","CD2"};
1532 12 : const string trp1_n[] = {"CD2","CE2","CZ2","CH2","CZ3","CE3"};
1533 12 : const string trp2_n[] = {"CG","CD1","NE1","CE2","CD2"};
1534 12 : const string his_n[] = {"CG","ND1","CD2","CE1","NE2"};
1535 :
1536 12 : vector<string> chains;
1537 6 : pdb.getChainNames( chains );
1538 12 : vector<AtomNumber> allatoms = pdb.getAtomNumbers();
1539 6 : unsigned old_size=0;
1540 :
1541 18 : for(unsigned s=0; s<atom.size(); s++) {
1542 12 : AtomNumber astart, aend;
1543 12 : string errmsg;
1544 12 : pdb.getAtomRange( chains[s], astart, aend, errmsg );
1545 12 : unsigned atom_offset = astart.index();
1546 1068 : for(unsigned r=0; r<atom[s].size(); r++) {
1547 1056 : string frg = pdb.getResidueName(atom[s][r].fd);
1548 4014 : if(!((frg=="PHE")||(frg=="TYR")||(frg=="TRP")||
1549 2826 : (frg=="HIS")||(frg=="HIP")||(frg=="HID")||
1550 1884 : (frg=="HIE")||(frg=="HSD")||(frg=="HSE")||
1551 2940 : (frg=="HSP"))) continue;
1552 :
1553 228 : vector<AtomNumber> frg_atoms = pdb.getAtomsInResidue(atom[s][r].fd,chains[s]);
1554 :
1555 114 : if(frg=="PHE"||frg=="TYR") {
1556 108 : RingInfo ri;
1557 2280 : for(unsigned a=0; a<frg_atoms.size(); a++) {
1558 2172 : unsigned atm = frg_atoms[a].index()-atom_offset+old_size;
1559 12936 : for(unsigned aa=0; aa<6; aa++) {
1560 11412 : if(pdb.getAtomName(frg_atoms[a])==pheTyr_n[aa]) {
1561 648 : ri.atom[aa] = atm;
1562 648 : break;
1563 : }
1564 : }
1565 : }
1566 108 : ri.numAtoms = 6;
1567 108 : if(frg=="PHE") ri.rtype = RingInfo::R_PHE;
1568 108 : if(frg=="TYR") ri.rtype = RingInfo::R_TYR;
1569 108 : ringInfo.push_back(ri);
1570 :
1571 6 : } else if(frg=="TRP") {
1572 : //First ring
1573 6 : RingInfo ri;
1574 150 : for(unsigned a=0; a<frg_atoms.size(); a++) {
1575 144 : unsigned atm = frg_atoms[a].index()-atom_offset+old_size;
1576 882 : for(unsigned aa=0; aa<6; aa++) {
1577 774 : if(pdb.getAtomName(frg_atoms[a])==trp1_n[aa]) {
1578 36 : ri.atom[aa] = atm;
1579 36 : break;
1580 : }
1581 : }
1582 : }
1583 6 : ri.numAtoms = 6;
1584 6 : ri.rtype = RingInfo::R_TRP1;
1585 6 : ringInfo.push_back(ri);
1586 : //Second Ring
1587 6 : RingInfo ri2;
1588 150 : for(unsigned a=0; a<frg_atoms.size(); a++) {
1589 144 : unsigned atm = frg_atoms[a].index()-atom_offset+old_size;
1590 774 : for(unsigned aa=0; aa<5; aa++) {
1591 660 : if(pdb.getAtomName(frg_atoms[a])==trp2_n[aa]) {
1592 30 : ri2.atom[aa] = atm;
1593 30 : break;
1594 : }
1595 : }
1596 : }
1597 6 : ri2.numAtoms = 5;
1598 6 : ri2.rtype = RingInfo::R_TRP2;
1599 6 : ringInfo.push_back(ri2);
1600 :
1601 0 : } else if((frg=="HIS")||(frg=="HIP")||(frg=="HID")||
1602 0 : (frg=="HIE")||(frg=="HSD")||(frg=="HSE")||
1603 0 : (frg=="HSP")) {//HIS case
1604 0 : RingInfo ri;
1605 0 : for(unsigned a=0; a<frg_atoms.size(); a++) {
1606 0 : unsigned atm = frg_atoms[a].index()-atom_offset+old_size;
1607 0 : for(unsigned aa=0; aa<5; aa++) {
1608 0 : if(pdb.getAtomName(frg_atoms[a])==his_n[aa]) {
1609 0 : ri.atom[aa] = atm;
1610 0 : break;
1611 : }
1612 : }
1613 : }
1614 0 : ri.numAtoms = 5;
1615 0 : ri.rtype = RingInfo::R_HIS;
1616 0 : ringInfo.push_back(ri);
1617 : } else {
1618 0 : plumed_merror("Unkwown Ring Fragment");
1619 : }
1620 114 : }
1621 12 : old_size = aend.index()+1;
1622 54 : }
1623 6 : }
1624 :
1625 3144 : CS2Backbone::aa_t CS2Backbone::frag2enum(const string &aa) {
1626 :
1627 3144 : aa_t type = ALA;
1628 3144 : if (aa == "ALA") type = ALA;
1629 2964 : else if (aa == "ARG") type = ARG;
1630 2838 : else if (aa == "ASN") type = ASN;
1631 2676 : else if (aa == "ASP") type = ASP;
1632 2520 : else if (aa == "ASH") type = ASP;
1633 2520 : else if (aa == "CYS") type = CYS;
1634 2448 : else if (aa == "CYM") type = CYS;
1635 2448 : else if (aa == "GLN") type = GLN;
1636 2394 : else if (aa == "GLU") type = GLU;
1637 2184 : else if (aa == "GLH") type = GLU;
1638 2184 : else if (aa == "GLY") type = GLY;
1639 1650 : else if (aa == "HIS") type = HIS;
1640 1650 : else if (aa == "HSE") type = HIS;
1641 1650 : else if (aa == "HIE") type = HIS;
1642 1650 : else if (aa == "HSP") type = HIS;
1643 1650 : else if (aa == "HIP") type = HIS;
1644 1650 : else if (aa == "HSD") type = HIS;
1645 1650 : else if (aa == "HID") type = HIS;
1646 1650 : else if (aa == "ILE") type = ILE;
1647 1470 : else if (aa == "LEU") type = LEU;
1648 1308 : else if (aa == "LYS") type = LYS;
1649 1056 : else if (aa == "MET") type = MET;
1650 972 : else if (aa == "PHE") type = PHE;
1651 684 : else if (aa == "PRO") type = PRO;
1652 558 : else if (aa == "SER") type = SER;
1653 396 : else if (aa == "THR") type = THR;
1654 198 : else if (aa == "TRP") type = TRP;
1655 180 : else if (aa == "TYR") type = TYR;
1656 144 : else if (aa == "VAL") type = VAL;
1657 0 : else if (aa == "UNK") type = UNK;
1658 0 : else plumed_merror("CS2Backbone: Error converting string " + aa + " into amino acid index: not a valid 3-letter code");
1659 3144 : return type;
1660 : }
1661 :
1662 1056 : vector<string> CS2Backbone::side_chain_atoms(const string &s) {
1663 1056 : vector<string> sc;
1664 :
1665 1056 : if(s=="ALA") {
1666 60 : sc.push_back( "CB" );
1667 60 : sc.push_back( "HB1" );
1668 60 : sc.push_back( "HB2" );
1669 60 : sc.push_back( "HB3" );
1670 60 : return sc;
1671 996 : } else if(s=="ARG") {
1672 42 : sc.push_back( "CB" );
1673 42 : sc.push_back( "CG" );
1674 42 : sc.push_back( "CD" );
1675 42 : sc.push_back( "NE" );
1676 42 : sc.push_back( "CZ" );
1677 42 : sc.push_back( "NH1" );
1678 42 : sc.push_back( "NH2" );
1679 42 : sc.push_back( "NH3" );
1680 42 : sc.push_back( "HB1" );
1681 42 : sc.push_back( "HB2" );
1682 42 : sc.push_back( "HB3" );
1683 42 : sc.push_back( "HG1" );
1684 42 : sc.push_back( "HG2" );
1685 42 : sc.push_back( "HG3" );
1686 42 : sc.push_back( "HD1" );
1687 42 : sc.push_back( "HD2" );
1688 42 : sc.push_back( "HD3" );
1689 42 : sc.push_back( "HE" );
1690 42 : sc.push_back( "HH11" );
1691 42 : sc.push_back( "HH12" );
1692 42 : sc.push_back( "HH21" );
1693 42 : sc.push_back( "HH22" );
1694 42 : sc.push_back( "1HH1" );
1695 42 : sc.push_back( "2HH1" );
1696 42 : sc.push_back( "1HH2" );
1697 42 : sc.push_back( "2HH2" );
1698 42 : return sc;
1699 954 : } else if(s=="ASN") {
1700 54 : sc.push_back( "CB" );
1701 54 : sc.push_back( "CG" );
1702 54 : sc.push_back( "OD1" );
1703 54 : sc.push_back( "ND2" );
1704 54 : sc.push_back( "HB1" );
1705 54 : sc.push_back( "HB2" );
1706 54 : sc.push_back( "HB3" );
1707 54 : sc.push_back( "HD21" );
1708 54 : sc.push_back( "HD22" );
1709 54 : sc.push_back( "1HD2" );
1710 54 : sc.push_back( "2HD2" );
1711 54 : return sc;
1712 900 : } else if(s=="ASP"||s=="ASH") {
1713 54 : sc.push_back( "CB" );
1714 54 : sc.push_back( "CG" );
1715 54 : sc.push_back( "OD1" );
1716 54 : sc.push_back( "OD2" );
1717 54 : sc.push_back( "HB1" );
1718 54 : sc.push_back( "HB2" );
1719 54 : sc.push_back( "HB3" );
1720 54 : return sc;
1721 846 : } else if(s=="CYS"||s=="CYM") {
1722 24 : sc.push_back( "CB" );
1723 24 : sc.push_back( "SG" );
1724 24 : sc.push_back( "HB1" );
1725 24 : sc.push_back( "HB2" );
1726 24 : sc.push_back( "HB3" );
1727 24 : sc.push_back( "HG1" );
1728 24 : sc.push_back( "HG" );
1729 24 : return sc;
1730 822 : } else if(s=="GLN") {
1731 18 : sc.push_back( "CB" );
1732 18 : sc.push_back( "CG" );
1733 18 : sc.push_back( "CD" );
1734 18 : sc.push_back( "OE1" );
1735 18 : sc.push_back( "NE2" );
1736 18 : sc.push_back( "HB1" );
1737 18 : sc.push_back( "HB2" );
1738 18 : sc.push_back( "HB3" );
1739 18 : sc.push_back( "HG1" );
1740 18 : sc.push_back( "HG2" );
1741 18 : sc.push_back( "HG3" );
1742 18 : sc.push_back( "HE21" );
1743 18 : sc.push_back( "HE22" );
1744 18 : sc.push_back( "1HE2" );
1745 18 : sc.push_back( "2HE2" );
1746 18 : return sc;
1747 804 : } else if(s=="GLU"||s=="GLH") {
1748 72 : sc.push_back( "CB" );
1749 72 : sc.push_back( "CG" );
1750 72 : sc.push_back( "CD" );
1751 72 : sc.push_back( "OE1" );
1752 72 : sc.push_back( "OE2" );
1753 72 : sc.push_back( "HB1" );
1754 72 : sc.push_back( "HB2" );
1755 72 : sc.push_back( "HB3" );
1756 72 : sc.push_back( "HG1" );
1757 72 : sc.push_back( "HG2" );
1758 72 : sc.push_back( "HG3" );
1759 72 : return sc;
1760 732 : } else if(s=="GLY") {
1761 180 : sc.push_back( "HA2" );
1762 180 : return sc;
1763 552 : } else if(s=="HIS"||s=="HSE"||s=="HIE"||s=="HSD"||s=="HID"||s=="HIP"||s=="HSP") {
1764 0 : sc.push_back( "CB" );
1765 0 : sc.push_back( "CG" );
1766 0 : sc.push_back( "ND1" );
1767 0 : sc.push_back( "CD2" );
1768 0 : sc.push_back( "CE1" );
1769 0 : sc.push_back( "NE2" );
1770 0 : sc.push_back( "HB1" );
1771 0 : sc.push_back( "HB2" );
1772 0 : sc.push_back( "HB3" );
1773 0 : sc.push_back( "HD1" );
1774 0 : sc.push_back( "HD2" );
1775 0 : sc.push_back( "HE1" );
1776 0 : sc.push_back( "HE2" );
1777 0 : return sc;
1778 552 : } else if(s=="ILE") {
1779 60 : sc.push_back( "CB" );
1780 60 : sc.push_back( "CG1" );
1781 60 : sc.push_back( "CG2" );
1782 60 : sc.push_back( "CD" );
1783 60 : sc.push_back( "HB" );
1784 60 : sc.push_back( "HG11" );
1785 60 : sc.push_back( "HG12" );
1786 60 : sc.push_back( "HG21" );
1787 60 : sc.push_back( "HG22" );
1788 60 : sc.push_back( "HG23" );
1789 60 : sc.push_back( "1HG1" );
1790 60 : sc.push_back( "2HG1" );
1791 60 : sc.push_back( "1HG2" );
1792 60 : sc.push_back( "2HG2" );
1793 60 : sc.push_back( "3HG2" );
1794 60 : sc.push_back( "HD1" );
1795 60 : sc.push_back( "HD2" );
1796 60 : sc.push_back( "HD3" );
1797 60 : return sc;
1798 492 : } else if(s=="LEU") {
1799 54 : sc.push_back( "CB" );
1800 54 : sc.push_back( "CG" );
1801 54 : sc.push_back( "CD1" );
1802 54 : sc.push_back( "CD2" );
1803 54 : sc.push_back( "HB1" );
1804 54 : sc.push_back( "HB2" );
1805 54 : sc.push_back( "HB3" );
1806 54 : sc.push_back( "HG" );
1807 54 : sc.push_back( "HD11" );
1808 54 : sc.push_back( "HD12" );
1809 54 : sc.push_back( "HD13" );
1810 54 : sc.push_back( "HD21" );
1811 54 : sc.push_back( "HD22" );
1812 54 : sc.push_back( "HD23" );
1813 54 : sc.push_back( "1HD1" );
1814 54 : sc.push_back( "2HD1" );
1815 54 : sc.push_back( "3HD1" );
1816 54 : sc.push_back( "1HD2" );
1817 54 : sc.push_back( "2HD2" );
1818 54 : sc.push_back( "3HD2" );
1819 54 : return sc;
1820 438 : } else if(s=="LYS") {
1821 84 : sc.push_back( "CB" );
1822 84 : sc.push_back( "CG" );
1823 84 : sc.push_back( "CD" );
1824 84 : sc.push_back( "CE" );
1825 84 : sc.push_back( "NZ" );
1826 84 : sc.push_back( "HB1" );
1827 84 : sc.push_back( "HB2" );
1828 84 : sc.push_back( "HB3" );
1829 84 : sc.push_back( "HG1" );
1830 84 : sc.push_back( "HG2" );
1831 84 : sc.push_back( "HG3" );
1832 84 : sc.push_back( "HD1" );
1833 84 : sc.push_back( "HD2" );
1834 84 : sc.push_back( "HD3" );
1835 84 : sc.push_back( "HE1" );
1836 84 : sc.push_back( "HE2" );
1837 84 : sc.push_back( "HE3" );
1838 84 : sc.push_back( "HZ1" );
1839 84 : sc.push_back( "HZ2" );
1840 84 : sc.push_back( "HZ3" );
1841 84 : return sc;
1842 354 : } else if(s=="MET") {
1843 30 : sc.push_back( "CB" );
1844 30 : sc.push_back( "CG" );
1845 30 : sc.push_back( "SD" );
1846 30 : sc.push_back( "CE" );
1847 30 : sc.push_back( "HB1" );
1848 30 : sc.push_back( "HB2" );
1849 30 : sc.push_back( "HB3" );
1850 30 : sc.push_back( "HG1" );
1851 30 : sc.push_back( "HG2" );
1852 30 : sc.push_back( "HG3" );
1853 30 : sc.push_back( "HE1" );
1854 30 : sc.push_back( "HE2" );
1855 30 : sc.push_back( "HE3" );
1856 30 : return sc;
1857 324 : } else if(s=="PHE") {
1858 96 : sc.push_back( "CB" );
1859 96 : sc.push_back( "CG" );
1860 96 : sc.push_back( "CD1" );
1861 96 : sc.push_back( "CD2" );
1862 96 : sc.push_back( "CE1" );
1863 96 : sc.push_back( "CE2" );
1864 96 : sc.push_back( "CZ" );
1865 96 : sc.push_back( "HB1" );
1866 96 : sc.push_back( "HB2" );
1867 96 : sc.push_back( "HB3" );
1868 96 : sc.push_back( "HD1" );
1869 96 : sc.push_back( "HD2" );
1870 96 : sc.push_back( "HD3" );
1871 96 : sc.push_back( "HE1" );
1872 96 : sc.push_back( "HE2" );
1873 96 : sc.push_back( "HE3" );
1874 96 : sc.push_back( "HZ" );
1875 96 : return sc;
1876 228 : } else if(s=="PRO") {
1877 42 : sc.push_back( "CB" );
1878 42 : sc.push_back( "CG" );
1879 42 : sc.push_back( "CD" );
1880 42 : sc.push_back( "HB1" );
1881 42 : sc.push_back( "HB2" );
1882 42 : sc.push_back( "HB3" );
1883 42 : sc.push_back( "HG1" );
1884 42 : sc.push_back( "HG2" );
1885 42 : sc.push_back( "HG3" );
1886 42 : sc.push_back( "HD1" );
1887 42 : sc.push_back( "HD2" );
1888 42 : sc.push_back( "HD3" );
1889 42 : return sc;
1890 186 : } else if(s=="SER") {
1891 54 : sc.push_back( "CB" );
1892 54 : sc.push_back( "OG" );
1893 54 : sc.push_back( "HB1" );
1894 54 : sc.push_back( "HB2" );
1895 54 : sc.push_back( "HB3" );
1896 54 : sc.push_back( "HG1" );
1897 54 : sc.push_back( "HG" );
1898 54 : return sc;
1899 132 : } else if(s=="THR") {
1900 66 : sc.push_back( "CB" );
1901 66 : sc.push_back( "OG1" );
1902 66 : sc.push_back( "CG2" );
1903 66 : sc.push_back( "HB" );
1904 66 : sc.push_back( "HG1" );
1905 66 : sc.push_back( "HG21" );
1906 66 : sc.push_back( "HG22" );
1907 66 : sc.push_back( "HG23" );
1908 66 : sc.push_back( "1HG2" );
1909 66 : sc.push_back( "2HG2" );
1910 66 : sc.push_back( "3HG2" );
1911 66 : return sc;
1912 66 : } else if(s=="TRP") {
1913 6 : sc.push_back( "CB" );
1914 6 : sc.push_back( "CG" );
1915 6 : sc.push_back( "CD1" );
1916 6 : sc.push_back( "CD2" );
1917 6 : sc.push_back( "NE1" );
1918 6 : sc.push_back( "CE2" );
1919 6 : sc.push_back( "CE3" );
1920 6 : sc.push_back( "CZ2" );
1921 6 : sc.push_back( "CZ3" );
1922 6 : sc.push_back( "CH2" );
1923 6 : sc.push_back( "HB1" );
1924 6 : sc.push_back( "HB2" );
1925 6 : sc.push_back( "HB3" );
1926 6 : sc.push_back( "HD1" );
1927 6 : sc.push_back( "HE1" );
1928 6 : sc.push_back( "HE3" );
1929 6 : sc.push_back( "HZ2" );
1930 6 : sc.push_back( "HZ3" );
1931 6 : sc.push_back( "HH2" );
1932 6 : return sc;
1933 60 : } else if(s=="TYR") {
1934 12 : sc.push_back( "CB" );
1935 12 : sc.push_back( "CG" );
1936 12 : sc.push_back( "CD1" );
1937 12 : sc.push_back( "CD2" );
1938 12 : sc.push_back( "CE1" );
1939 12 : sc.push_back( "CE2" );
1940 12 : sc.push_back( "CZ" );
1941 12 : sc.push_back( "OH" );
1942 12 : sc.push_back( "HB1" );
1943 12 : sc.push_back( "HB2" );
1944 12 : sc.push_back( "HB3" );
1945 12 : sc.push_back( "HD1" );
1946 12 : sc.push_back( "HD2" );
1947 12 : sc.push_back( "HD3" );
1948 12 : sc.push_back( "HE1" );
1949 12 : sc.push_back( "HE2" );
1950 12 : sc.push_back( "HE3" );
1951 12 : sc.push_back( "HH" );
1952 12 : return sc;
1953 48 : } else if(s=="VAL") {
1954 48 : sc.push_back( "CB" );
1955 48 : sc.push_back( "CG1" );
1956 48 : sc.push_back( "CG2" );
1957 48 : sc.push_back( "HB" );
1958 48 : sc.push_back( "HG11" );
1959 48 : sc.push_back( "HG12" );
1960 48 : sc.push_back( "HG13" );
1961 48 : sc.push_back( "HG21" );
1962 48 : sc.push_back( "HG22" );
1963 48 : sc.push_back( "HG23" );
1964 48 : sc.push_back( "1HG1" );
1965 48 : sc.push_back( "2HG1" );
1966 48 : sc.push_back( "3HG1" );
1967 48 : sc.push_back( "1HG2" );
1968 48 : sc.push_back( "2HG2" );
1969 48 : sc.push_back( "3HG2" );
1970 48 : return sc;
1971 0 : } else plumed_merror("CS2Backbone: side_chain_atoms unknown");
1972 : }
1973 :
1974 15672 : bool CS2Backbone::isSP2(const string & resType, const string & atomName) {
1975 15672 : bool sp2 = false;
1976 15672 : if (atomName == "C") return true;
1977 14616 : if (atomName == "O") return true;
1978 :
1979 13572 : if(resType == "TRP") {
1980 :
1981 132 : if (atomName == "CG") sp2 = true;
1982 126 : else if (atomName == "CD1") sp2 = true;
1983 120 : else if (atomName == "CD2") sp2 = true;
1984 114 : else if (atomName == "CE2") sp2 = true;
1985 108 : else if (atomName == "CE3") sp2 = true;
1986 102 : else if (atomName == "CZ2") sp2 = true;
1987 96 : else if (atomName == "CZ3") sp2 = true;
1988 90 : else if (atomName == "CH2") sp2 = true;
1989 :
1990 13440 : } else if (resType == "ASP") {
1991 :
1992 552 : if (atomName == "CG") sp2 = true;
1993 498 : else if (atomName == "OD1") sp2 = true;
1994 444 : else if (atomName == "OD2") sp2 = true;
1995 :
1996 12888 : } else if (resType == "GLU") {
1997 :
1998 948 : if (atomName == "CD") sp2 = true;
1999 876 : else if (atomName == "OE1") sp2 = true;
2000 804 : else if (atomName == "OE2") sp2 = true;
2001 :
2002 11940 : } else if (resType == "ARG") {
2003 :
2004 924 : if (atomName == "CZ") sp2 = true;
2005 :
2006 11016 : } else if (resType == "HIS") {
2007 :
2008 0 : if (atomName == "CG") sp2 = true;
2009 0 : else if (atomName == "ND1") sp2 = true;
2010 0 : else if (atomName == "CD2") sp2 = true;
2011 0 : else if (atomName == "CE1") sp2 = true;
2012 0 : else if (atomName == "NE2") sp2 = true;
2013 :
2014 11016 : } else if (resType == "PHE") {
2015 :
2016 1728 : if (atomName == "CG") sp2 = true;
2017 1632 : else if (atomName == "CD1") sp2 = true;
2018 1536 : else if (atomName == "CD2") sp2 = true;
2019 1440 : else if (atomName == "CE1") sp2 = true;
2020 1344 : else if (atomName == "CE2") sp2 = true;
2021 1248 : else if (atomName == "CZ") sp2 = true;
2022 :
2023 9288 : } else if (resType == "TYR") {
2024 :
2025 228 : if (atomName == "CG") sp2 = true;
2026 216 : else if (atomName == "CD1") sp2 = true;
2027 204 : else if (atomName == "CD2") sp2 = true;
2028 192 : else if (atomName == "CE1") sp2 = true;
2029 180 : else if (atomName == "CE2") sp2 = true;
2030 168 : else if (atomName == "CZ") sp2 = true;
2031 :
2032 9060 : } else if (resType == "ASN") {
2033 :
2034 648 : if (atomName == "CG") sp2 = true;
2035 594 : else if (atomName == "OD1") sp2 = true;
2036 :
2037 8412 : } else if (resType == "GLN") {
2038 :
2039 270 : if (atomName == "CD") sp2 = true;
2040 252 : else if (atomName == "OE1") sp2 = true;
2041 :
2042 : }
2043 :
2044 13572 : return sp2;
2045 : }
2046 :
2047 15672 : bool CS2Backbone::is_chi1_cx(const string & frg, const string & atm) {
2048 15672 : if(atm=="CG") return true;
2049 15108 : if((frg == "CYS")&&(atm =="SG")) return true;
2050 15084 : if(((frg == "ILE")||(frg == "VAL"))&&(atm == "CG1")) return true;
2051 14976 : if((frg == "SER")&&(atm == "OG")) return true;
2052 14922 : if((frg == "THR")&&(atm == "OG1")) return true;
2053 :
2054 14856 : return false;
2055 : }
2056 :
2057 6192 : unsigned CS2Backbone::frag_segment(const unsigned p) {
2058 6192 : unsigned s = 0;
2059 6516 : for(unsigned i=0; i<seg_last.size()-1; i++) {
2060 6192 : if(p>seg_last[i]) s = i+1;
2061 5868 : else break;
2062 : }
2063 6192 : return s;
2064 : }
2065 :
2066 6192 : unsigned CS2Backbone::frag_relitive_index(const unsigned p, const unsigned s) {
2067 6192 : if(s==0) return p;
2068 324 : return p-seg_last[s-1];
2069 : }
2070 :
2071 0 : void CS2Backbone::debug_report() {
2072 0 : printf("\t CS2Backbone Initialization report: \n");
2073 0 : printf("\t -------------------------------\n");
2074 0 : printf("\t Number of segments: %u\n", static_cast<unsigned>(atom.size()));
2075 0 : printf("\t Segments size: ");
2076 0 : for(unsigned i=0; i<atom.size(); i++) printf("%u ", static_cast<unsigned>(atom[i].size())); printf("\n");
2077 : printf("\t%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s \n",
2078 0 : "Seg","N","AA","Prev","Curr","Next","SC","XD1","XD2","Phi","Psi","Chi1");
2079 0 : for(unsigned i=0; i<atom.size(); i++) {
2080 0 : for(unsigned j=0; j<atom[i].size(); j++) {
2081 : printf("\t%8u %8u %8s %8u %8u %8u %8u %8u %8u %8u %8u %8u \n",
2082 : i+1, j+1,
2083 0 : atom[i][j].res_name.c_str(),
2084 0 : (unsigned)atom[i][j].prev.size(),
2085 0 : (unsigned)atom[i][j].curr.size(),
2086 0 : (unsigned)atom[i][j].next.size(),
2087 0 : (unsigned)atom[i][j].side_chain.size(),
2088 0 : (unsigned)atom[i][j].xd1.size(),
2089 0 : (unsigned)atom[i][j].xd2.size(),
2090 0 : (unsigned)atom[i][j].phi.size(),
2091 0 : (unsigned)atom[i][j].psi.size(),
2092 0 : (unsigned)atom[i][j].chi1.size());
2093 :
2094 0 : for(unsigned k=0; k<atom[i][j].prev.size(); k++) printf("%8i ", atom[i][j].prev[k]); printf("\n");
2095 0 : for(unsigned k=0; k<atom[i][j].curr.size(); k++) printf("%8i ", atom[i][j].curr[k]); printf("\n");
2096 0 : for(unsigned k=0; k<atom[i][j].next.size(); k++) printf("%8i ", atom[i][j].next[k]); printf("\n");
2097 0 : for(unsigned k=0; k<atom[i][j].side_chain.size(); k++) printf("%8i ", atom[i][j].side_chain[k]); printf("\n");
2098 0 : for(unsigned k=0; k<atom[i][j].xd1.size(); k++) printf("%8i ", atom[i][j].xd1[k]); printf("\n");
2099 0 : for(unsigned k=0; k<atom[i][j].xd2.size(); k++) printf("%8i ", atom[i][j].xd2[k]); printf("\n");
2100 0 : for(unsigned k=0; k<atom[i][j].phi.size(); k++) printf("%8i ", atom[i][j].phi[k]); printf("\n");
2101 0 : for(unsigned k=0; k<atom[i][j].psi.size(); k++) printf("%8i ", atom[i][j].psi[k]); printf("\n");
2102 0 : for(unsigned k=0; k<atom[i][j].chi1.size(); k++) printf("%8i ", atom[i][j].chi1[k]); printf("\n");
2103 :
2104 : }
2105 : }
2106 :
2107 0 : printf("\t Rings: \n");
2108 0 : printf("\t ------ \n");
2109 0 : printf("\t Number of rings: %u\n", static_cast<unsigned>(ringInfo.size()));
2110 0 : printf("\t%8s %8s %8s %8s\n", "Num","Type","RType","N.atoms");
2111 0 : for(unsigned i=0; i<ringInfo.size(); i++) {
2112 0 : printf("\t%8u %8u %8u \n",i+1,ringInfo[i].rtype,ringInfo[i].numAtoms);
2113 0 : for(unsigned j=0; j<ringInfo[i].numAtoms; j++) printf("%8u ", ringInfo[i].atom[j]); printf("\n");
2114 : }
2115 0 : }
2116 :
2117 350010 : void CS2Backbone::xdist_name_map(string & name) {
2118 350010 : if((name == "OT1")||(name == "OC1")) name = "O";
2119 350010 : else if ((name == "HN") || (name == "HT1") || (name == "H1")) name = "H";
2120 1394034 : else if ((name == "CG1")|| (name == "OG")||
2121 1047654 : (name == "SG") || (name == "OG1")) name = "CG";
2122 344826 : else if ((name == "HA1")) name = "HA";
2123 350010 : }
2124 :
2125 : }
2126 2523 : }
|