ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/openbabel/rotor.cpp
Revision: 2450
Committed: Thu Nov 17 20:38:45 2005 UTC (18 years, 7 months ago) by gezelter
File size: 30935 byte(s)
Log Message:
Unifying config.h stuff and making sure the OpenBabel codes can find
our default (and environment variable) Force Field directories.

File Contents

# Content
1 /**********************************************************************
2 rotor.cpp - Rotate dihedral angles according to rotor rules.
3
4 Copyright (C) 1998-2000 by OpenEye Scientific Software, Inc.
5 Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
6
7 This file is part of the Open Babel project.
8 For more information, see <http://openbabel.sourceforge.net/>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation version 2 of the License.
13
14 This program 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 General Public License for more details.
18 ***********************************************************************/
19
20 #include "mol.hpp"
21 #include "rotor.hpp"
22 #include "torlib.hpp"
23
24 using namespace std;
25 namespace OpenBabel
26 {
27
28 #define OB_DEFAULT_DELTA 10.0
29 static bool GetDFFVector(OBMol&,vector<int>&,OBBitVec&);
30 static bool CompareRotor(const pair<OBBond*,int>&,const pair<OBBond*,int>&);
31
32
33 //**************************************
34 //**** OBRotorList Member Functions ****
35 //**************************************
36
37 bool OBRotorList::Setup(OBMol &mol)
38 {
39 Clear();
40 FindRotors(mol);
41 if (!Size())
42 return(false);
43
44 SetEvalAtoms(mol);
45 AssignTorVals(mol);
46
47 OBRotor *rotor;
48 vector<OBRotor*>::iterator i;
49 for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i))
50 if (!rotor->Size())
51 {
52 int ref[4];
53 rotor->GetDihedralAtoms(ref);
54 char buffer[BUFF_SIZE];
55 sprintf(buffer,"The rotor has no associated torsion values -> %d %d %d %d",ref[0],ref[1],ref[2],ref[3]);
56
57 obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug);
58 }
59
60 return(true);
61 }
62
63 bool OBRotorList::FindRotors(OBMol &mol)
64 {
65 mol.FindRingAtomsAndBonds();
66 vector<int> gtd;
67 mol.GetGTDVector(gtd);
68
69 obErrorLog.ThrowError(__FUNCTION__,
70 "Ran OpenBabel::FindRotors", obAuditMsg);
71
72 OBBond *bond;
73 vector<OBEdgeBase*>::iterator i;
74 vector<pair<OBBond*,int> > vtmp;
75
76 int score;
77 for (bond = mol.BeginBond(i);bond;bond = mol.NextBond(i))
78 if (bond->IsRotor())
79 {
80 if (HasFixedAtoms() && IsFixedBond(bond))
81 continue;
82 score = gtd[bond->GetBeginAtomIdx()-1] +
83 gtd[bond->GetEndAtomIdx()-1];
84 vtmp.push_back(pair<OBBond*,int> (bond,score));
85 }
86
87 sort(vtmp.begin(),vtmp.end(),CompareRotor);
88
89 OBRotor *rotor;
90 int count;
91 vector<pair<OBBond*,int> >::iterator j;
92 for (j = vtmp.begin(),count=0;j != vtmp.end();j++,count++)
93 {
94 rotor = new OBRotor;
95 rotor->SetBond((*j).first);
96 rotor->SetIdx(count);
97 rotor->SetNumCoords(mol.NumAtoms()*3);
98 _rotor.push_back(rotor);
99 }
100
101 return(true);
102 }
103
104 bool OBRotorList::IsFixedBond(OBBond *bond)
105 {
106 OBAtom *a1,*a2,*a3;
107 vector<OBEdgeBase*>::iterator i;
108
109 a1 = bond->GetBeginAtom();
110 a2 = bond->GetEndAtom();
111 if (!_fix[a1->GetIdx()] || !_fix[a2->GetIdx()])
112 return(false);
113
114 bool isfixed=false;
115 for (a3 = a1->BeginNbrAtom(i);a3;a3 = a1->NextNbrAtom(i))
116 if (a3 != a2 && _fix[a3->GetIdx()])
117 {
118 isfixed = true;
119 break;
120 }
121
122 if (!isfixed)
123 return(false);
124
125 isfixed = false;
126 for (a3 = a2->BeginNbrAtom(i);a3;a3 = a2->NextNbrAtom(i))
127 if (a3 != a1 && _fix[a3->GetIdx()])
128 {
129 isfixed = true;
130 break;
131 }
132
133 return(isfixed);
134 }
135
136 bool GetDFFVector(OBMol &mol,vector<int> &dffv,OBBitVec &bv)
137 {
138 dffv.clear();
139 dffv.resize(mol.NumAtoms());
140
141 int dffcount,natom;
142 OBBitVec used,curr,next;
143 OBAtom *atom,*atom1;
144 OBBond *bond;
145 vector<OBNodeBase*>::iterator i;
146 vector<OBEdgeBase*>::iterator j;
147
148 next.Clear();
149
150 for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
151 {
152 if (bv[atom->GetIdx()])
153 {
154 dffv[atom->GetIdx()-1] = 0;
155 continue;
156 }
157
158 dffcount = 0;
159 used.Clear();
160 curr.Clear();
161 used.SetBitOn(atom->GetIdx());
162 curr.SetBitOn(atom->GetIdx());
163
164 while (!curr.IsEmpty() && (bv&curr).Empty())
165 {
166 next.Clear();
167 for (natom = curr.NextBit(-1);natom != curr.EndBit();natom = curr.NextBit(natom))
168 {
169 atom1 = mol.GetAtom(natom);
170 for (bond = atom1->BeginBond(j);bond;bond = atom1->NextBond(j))
171 if (!used.BitIsOn(bond->GetNbrAtomIdx(atom1)) &&
172 !curr.BitIsOn(bond->GetNbrAtomIdx(atom1)))
173 if (!(bond->GetNbrAtom(atom1))->IsHydrogen())
174 next.SetBitOn(bond->GetNbrAtomIdx(atom1));
175 }
176
177 used |= next;
178 curr = next;
179 dffcount++;
180 }
181
182 dffv[atom->GetIdx()-1] = dffcount;
183 }
184
185 return(true);
186 }
187
188
189 static double MinimumPairRMS(OBMol&,double*,double*,bool &);
190
191 //! Rotates each bond to zero and 180 degrees and tests
192 //! if the 2 conformers are duplicates. if so - the symmetric torsion
193 //! values are removed from consideration during a search
194 void OBRotorList::RemoveSymVals(OBMol &mol)
195 {
196 double *c,*c1,*c2;
197 c1 = new double [mol.NumAtoms()*3];
198 c2 = new double [mol.NumAtoms()*3];
199 c = mol.GetCoordinates();
200 bool one2one;
201 double cutoff = 0.20;
202
203 OBRotor *rotor;
204 vector<OBRotor*>::iterator i;
205 for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i))
206 {
207 //look for 2-fold symmetry about a bond
208 memcpy(c1,c,sizeof(double)*mol.NumAtoms()*3);
209 memcpy(c2,c,sizeof(double)*mol.NumAtoms()*3);
210 rotor->SetToAngle(c1,(double)(0.0*DEG_TO_RAD));
211 rotor->SetToAngle(c2,(double)(180.0*DEG_TO_RAD));
212
213 if (MinimumPairRMS(mol,c1,c2,one2one) <cutoff && !one2one)
214 {
215 rotor->RemoveSymTorsionValues(2);
216 OBBond *bond = rotor->GetBond();
217
218 if (!_quiet)
219 {
220 #ifdef HAVE_SSTREAM
221 stringstream errorMsg;
222 #else
223 strstream errorMsg;
224 #endif
225 errorMsg << "symmetry found = " << ' ';
226 errorMsg << bond->GetBeginAtomIdx() << ' ' << bond->GetEndAtomIdx() << ' ' ;
227 errorMsg << "rms = " << ' ';
228 errorMsg << MinimumPairRMS(mol,c1,c2,one2one) << endl;
229 obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obDebug);
230 }
231 continue;
232 }
233
234 //look for 3-fold symmetry about a bond
235 memcpy(c1,c,sizeof(double)*mol.NumAtoms()*3);
236 memcpy(c2,c,sizeof(double)*mol.NumAtoms()*3);
237 rotor->SetToAngle(c1,(double)(0.0*DEG_TO_RAD));
238 rotor->SetToAngle(c2,(double)(120.0*DEG_TO_RAD));
239
240 if (MinimumPairRMS(mol,c1,c2,one2one) <cutoff && !one2one)
241 {
242 rotor->RemoveSymTorsionValues(3);
243 OBBond *bond = rotor->GetBond();
244
245 if (!_quiet)
246 {
247 #ifdef HAVE_SSTREAM
248 stringstream errorMsg;
249 #else
250 strstream errorMsg;
251 #endif
252 errorMsg << "3-fold symmetry found = " << ' ';
253 errorMsg << bond->GetBeginAtomIdx() << ' ' << bond->GetEndAtomIdx() << ' ' ;
254 errorMsg << "rms = " << ' ';
255 errorMsg << MinimumPairRMS(mol,c1,c2,one2one) << endl;
256 obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obDebug);
257 }
258 }
259 }
260
261 delete [] c1;
262 delete [] c2;
263
264 //pattern based duplicate removal
265 int ref[4];
266 vector<vector<int> > mlist;
267 vector<vector<int> >::iterator k;
268 vector<pair<OBSmartsPattern*,pair<int,int> > >::iterator j;
269 for (j = _vsym2.begin();j != _vsym2.end();j++)
270 if (j->first->Match(mol))
271 {
272 mlist = j->first->GetUMapList();
273
274 for (k = mlist.begin();k != mlist.end();k++)
275 for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i))
276 {
277 rotor->GetDihedralAtoms(ref);
278 if (((*k)[j->second.first] == ref[1] && (*k)[j->second.second] == ref[2]) ||
279 ((*k)[j->second.first] == ref[2] && (*k)[j->second.second] == ref[1]))
280 {
281 rotor->RemoveSymTorsionValues(2);
282 if (!_quiet)
283 {
284 #ifdef HAVE_SSTREAM
285 stringstream errorMsg;
286 #else
287 strstream errorMsg;
288 #endif
289 errorMsg << "2-fold pattern-based symmetry found = " << ' ';
290 errorMsg << ref[1] << ' ' << ref[2] << endl;
291 obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obDebug);
292 }
293 }
294 }
295 }
296
297 for (j = _vsym3.begin();j != _vsym3.end();j++)
298 if (j->first->Match(mol))
299 {
300 mlist = j->first->GetUMapList();
301
302 for (k = mlist.begin();k != mlist.end();k++)
303 for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i))
304 {
305 rotor->GetDihedralAtoms(ref);
306 if (((*k)[j->second.first] == ref[1] && (*k)[j->second.second] == ref[2]) ||
307 ((*k)[j->second.first] == ref[2] && (*k)[j->second.second] == ref[1]))
308 {
309 rotor->RemoveSymTorsionValues(3);
310 if (!_quiet)
311 {
312 #ifdef HAVE_SSTREAM
313 stringstream errorMsg;
314 #else
315 strstream errorMsg;
316 #endif
317 errorMsg << "3-fold pattern-based symmetry found = " << ' ';
318 errorMsg << ref[1] << ' ' << ref[2] << endl;
319 obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obDebug);
320 }
321 }
322 }
323 }
324 }
325
326 static double MinimumPairRMS(OBMol &mol,double *a,double *b,bool &one2one)
327 {
328 int i,j,k=0;
329 double min,tmp,d_2 = 0.0;
330 OBBitVec bset;
331 one2one = true;
332 vector<OBNodeBase*> _atom;
333 _atom.resize(mol.NumAtoms());
334 for (i = 0;i < (signed)mol.NumAtoms();i++)
335 _atom[i] = mol.GetAtom(i+1);
336
337 for (i = 0;i < (signed)mol.NumAtoms();i++)
338 {
339 min = 10E10;
340 for (j = 0;j < (signed)mol.NumAtoms();j++)
341 if ((_atom[i])->GetAtomicNum() == (_atom[j])->GetAtomicNum() &&
342 (_atom[i])->GetHyb() == (_atom[j])->GetHyb())
343 if (!bset[j])
344 {
345 tmp = SQUARE(a[3*i]-b[3*j]) +
346 SQUARE(a[3*i+1]-b[3*j+1]) +
347 SQUARE(a[3*i+2]-b[3*j+2]);
348 if (tmp < min)
349 {
350 k = j;
351 min = tmp;
352 }
353 }
354
355 if (i != j)
356 one2one = false;
357 bset.SetBitOn(k);
358 d_2 += min;
359 }
360
361 d_2 /= (double)mol.NumAtoms();
362
363 return(sqrt(d_2));
364 }
365
366 //! Determines which atoms the internal energy should be calculated
367 //! if a the dihedral angle of the rotor is modified
368 bool OBRotorList::SetEvalAtoms(OBMol &mol)
369 {
370 int j;
371 OBBond *bond;
372 OBAtom *a1,*a2;
373 OBRotor *rotor;
374 vector<OBRotor*>::iterator i;
375 OBBitVec eval,curr,next;
376 vector<OBEdgeBase*>::iterator k;
377
378 for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i))
379 {
380 bond = rotor->GetBond();
381 curr.Clear();
382 eval.Clear();
383 curr.SetBitOn(bond->GetBeginAtomIdx());
384 curr.SetBitOn(bond->GetEndAtomIdx());
385 eval |= curr;
386
387 //follow all non-rotor bonds and add atoms to eval list
388 for (;!curr.Empty();)
389 {
390 next.Clear();
391 for (j = curr.NextBit(0);j != curr.EndBit();j = curr.NextBit(j))
392 {
393 a1 = mol.GetAtom(j);
394 for (a2 = a1->BeginNbrAtom(k);a2;a2 = a1->NextNbrAtom(k))
395 if (!eval[a2->GetIdx()])
396 if (!((OBBond*)*k)->IsRotor()||(HasFixedAtoms()&&IsFixedBond((OBBond*)*k)))
397 {
398 next.SetBitOn(a2->GetIdx());
399 eval.SetBitOn(a2->GetIdx());
400 }
401 }
402 curr = next;
403 }
404
405 //add atoms alpha to eval list
406 next.Clear();
407 for (j = eval.NextBit(0);j != eval.EndBit();j = eval.NextBit(j))
408 {
409 a1 = mol.GetAtom(j);
410 for (a2 = a1->BeginNbrAtom(k);a2;a2 = a1->NextNbrAtom(k))
411 next.SetBitOn(a2->GetIdx());
412 }
413 eval |= next;
414 rotor->SetEvalAtoms(eval);
415 }
416
417 return(true);
418 }
419
420 bool OBRotorList::AssignTorVals(OBMol &mol)
421 {
422 OBBond *bond;
423 OBRotor *rotor;
424 vector<OBRotor*>::iterator i;
425
426 int ref[4];
427 double delta;
428 vector<double> res;
429 vector<int> itmp1;
430 vector<int>::iterator j;
431 for (i = _rotor.begin();i != _rotor.end();i++)
432 {
433 rotor=*i;
434 bond = rotor->GetBond();
435 _rr.GetRotorIncrements(mol,bond,ref,res,delta);
436 rotor->SetTorsionValues(res);
437 rotor->SetDelta(delta);
438
439 mol.FindChildren(itmp1,ref[1],ref[2]);
440 if (itmp1.size()+1 > mol.NumAtoms()/2)
441 {
442 itmp1.clear();
443 mol.FindChildren(itmp1,ref[2],ref[1]);
444 swap(ref[0],ref[3]);
445 swap(ref[1],ref[2]);
446 }
447
448 for (j = itmp1.begin();j != itmp1.end();j++)
449 *j = ((*j)-1)*3;
450 rotor->SetRotAtoms(itmp1);
451 rotor->SetDihedralAtoms(ref);
452 }
453
454 return(true);
455 }
456
457 bool OBRotorList::SetRotAtoms(OBMol &mol)
458 {
459 OBRotor *rotor;
460 vector<int> rotatoms,dihed;
461 vector<OBRotor*>::iterator i;
462
463 int ref[4];
464 vector<int>::iterator j;
465 for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i))
466 {
467 dihed = rotor->GetDihedralAtoms();
468 ref[0] = dihed[0]/3+1;
469 ref[1] = dihed[1]/3+1;
470 ref[2] = dihed[2]/3+1;
471 ref[3] = dihed[3]/3+1;
472
473 mol.FindChildren(rotatoms,ref[1],ref[2]);
474 if (rotatoms.size()+1 > mol.NumAtoms()/2)
475 {
476 rotatoms.clear();
477 mol.FindChildren(rotatoms,ref[2],ref[1]);
478 swap(ref[0],ref[3]);
479 swap(ref[1],ref[2]);
480 }
481
482 for (j = rotatoms.begin();j != rotatoms.end();j++)
483 *j = ((*j)-1)*3;
484 rotor->SetRotAtoms(rotatoms);
485 rotor->SetDihedralAtoms(ref);
486 }
487
488 return(true);
489 }
490
491 void OBRotorList::SetRotAtomsByFix(OBMol &mol)
492 {
493 int ref[4];
494 OBRotor *rotor;
495 vector<int> rotatoms,dihed;
496 vector<int>::iterator j;
497 vector<OBRotor*>::iterator i;
498
499 GetDFFVector(mol,_dffv,_fix);
500
501 for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i))
502 {
503 rotatoms.clear();
504 dihed = rotor->GetDihedralAtoms();
505 ref[0] = dihed[0]/3+1;
506 ref[1] = dihed[1]/3+1;
507 ref[2] = dihed[2]/3+1;
508 ref[3] = dihed[3]/3+1;
509
510 if (_fix[ref[1]] && _fix[ref[2]])
511 {
512 if (!_fix[ref[0]])
513 {
514 swap(ref[0],ref[3]);
515 swap(ref[1],ref[2]);
516 mol.FindChildren(rotatoms,ref[1],ref[2]);
517 for (j = rotatoms.begin();j != rotatoms.end();j++)
518 *j = ((*j)-1)*3;
519 rotor->SetRotAtoms(rotatoms);
520 rotor->SetDihedralAtoms(ref);
521 }
522 }
523 else
524 if (_dffv[ref[1]-1] > _dffv[ref[2]-1])
525 {
526 swap(ref[0],ref[3]);
527 swap(ref[1],ref[2]);
528 mol.FindChildren(rotatoms,ref[1],ref[2]);
529 for (j = rotatoms.begin();j != rotatoms.end();j++)
530 *j = ((*j)-1)*3;
531 rotor->SetRotAtoms(rotatoms);
532 rotor->SetDihedralAtoms(ref);
533 }
534 }
535 }
536
537 OBRotorList::OBRotorList()
538 {
539 _rotor.clear();
540 _quiet=false;
541 _removesym=true;
542
543 //para-disub benzene
544 OBSmartsPattern *sp;
545 sp = new OBSmartsPattern;
546 sp->Init("*c1[cD2][cD2]c(*)[cD2][cD2]1");
547 _vsym2.push_back(pair<OBSmartsPattern*,pair<int,int> > (sp,pair<int,int> (0,1)));
548
549 //piperidine amide
550 sp = new OBSmartsPattern;
551 sp->Init("O=CN1[CD2][CD2][CD2][CD2][CD2]1");
552 _vsym2.push_back(pair<OBSmartsPattern*,pair<int,int> > (sp,pair<int,int> (1,2)));
553
554 //terminal phosphate
555 sp = new OBSmartsPattern;
556 sp->Init("[#8D2][#15,#16](~[#8D1])(~[#8D1])~[#8D1]");
557 _vsym3.push_back(pair<OBSmartsPattern*,pair<int,int> > (sp,pair<int,int> (0,1)));
558
559 }
560
561 OBRotorList::~OBRotorList()
562 {
563 vector<OBRotor*>::iterator i;
564 for (i = _rotor.begin();i != _rotor.end();i++)
565 delete *i;
566
567 vector<pair<OBSmartsPattern*,pair<int,int> > >::iterator j;
568 for (j = _vsym2.begin();j != _vsym2.end();j++)
569 delete j->first;
570
571 for (j = _vsym3.begin();j != _vsym3.end();j++)
572 delete j->first;
573 }
574
575 void OBRotorList::Clear()
576 {
577 vector<OBRotor*>::iterator i;
578 for (i = _rotor.begin();i != _rotor.end();i++)
579 delete *i;
580 _rotor.clear();
581 _fix.Clear();
582 }
583
584 bool CompareRotor(const pair<OBBond*,int> &a,const pair<OBBond*,int> &b)
585 {
586 //return(a.second > b.second); //outside->in
587 return(a.second < b.second); //inside->out
588 }
589
590 //**********************************
591 //**** OBRotor Member Functions ****
592 //**********************************
593
594 OBRotor::OBRotor()
595 {
596 _delta = 10.0;
597 _rotatoms = NULL;
598 }
599
600 double OBRotor::CalcTorsion(double *c)
601 {
602 double v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z;
603 double c1x,c1y,c1z,c2x,c2y,c2z,c3x,c3y,c3z;
604 double c1mag,c2mag,ang,costheta;
605
606 //
607 //calculate the torsion angle
608 //
609 v1x = c[_torsion[0]] - c[_torsion[1]];
610 v1y = c[_torsion[0]+1] - c[_torsion[1]+1];
611 v1z = c[_torsion[0]+2] - c[_torsion[1]+2];
612 v2x = c[_torsion[1]] - c[_torsion[2]];
613 v2y = c[_torsion[1]+1] - c[_torsion[2]+1];
614 v2z = c[_torsion[1]+2] - c[_torsion[2]+2];
615 v3x = c[_torsion[2]] - c[_torsion[3]];
616 v3y = c[_torsion[2]+1] - c[_torsion[3]+1];
617 v3z = c[_torsion[2]+2] - c[_torsion[3]+2];
618
619 c1x = v1y*v2z - v1z*v2y;
620 c2x = v2y*v3z - v2z*v3y;
621 c1y = -v1x*v2z + v1z*v2x;
622 c2y = -v2x*v3z + v2z*v3x;
623 c1z = v1x*v2y - v1y*v2x;
624 c2z = v2x*v3y - v2y*v3x;
625 c3x = c1y*c2z - c1z*c2y;
626 c3y = -c1x*c2z + c1z*c2x;
627 c3z = c1x*c2y - c1y*c2x;
628
629 c1mag = SQUARE(c1x)+SQUARE(c1y)+SQUARE(c1z);
630 c2mag = SQUARE(c2x)+SQUARE(c2y)+SQUARE(c2z);
631 if (c1mag*c2mag < 0.01)
632 costheta = 1.0; //avoid div by zero error
633 else
634 costheta = (c1x*c2x + c1y*c2y + c1z*c2z)/(sqrt(c1mag*c2mag));
635
636 if (costheta < -0.9999999)
637 costheta = -0.9999999;
638 if (costheta > 0.9999999)
639 costheta = 0.9999999;
640
641 if ((v2x*c3x + v2y*c3y + v2z*c3z) > 0.0)
642 ang = -acos(costheta);
643 else
644 ang = acos(costheta);
645
646 return(ang);
647 }
648
649 double OBRotor::CalcBondLength(double *c)
650 {
651 double dx,dy,dz;
652
653 dx = c[_torsion[1]] - c[_torsion[2]];
654 dy = c[_torsion[1]+1] - c[_torsion[2]+1];
655 dz = c[_torsion[1]+2] - c[_torsion[2]+2];
656 return(sqrt(SQUARE(dx)+SQUARE(dy)+SQUARE(dz)));
657 }
658
659 void OBRotor::Precalc(vector<double*> &cv)
660 {
661 double *c,ang;
662 vector<double*>::iterator i;
663 vector<double>::iterator j;
664 vector<double> cs,sn,t;
665 for (i = cv.begin();i != cv.end();i++)
666 {
667 c = *i;
668 cs.clear();
669 sn.clear();
670 t.clear();
671 ang = CalcTorsion(c);
672
673 for (j = _res.begin();j != _res.end();j++)
674 {
675 cs.push_back(cos(*j-ang));
676 sn.push_back(sin(*j-ang));
677 t.push_back(1 - cos(*j-ang));
678 }
679
680 _cs.push_back(cs);
681 _sn.push_back(sn);
682 _t.push_back(t);
683 _invmag.push_back(1.0/CalcBondLength(c));
684 }
685 }
686
687
688 void OBRotor::SetRotor(double *c,int idx,int prev)
689 {
690 double ang,sn,cs,t,dx,dy,dz,mag;
691
692 if (prev == -1)
693 ang = _res[idx] - CalcTorsion(c);
694 else
695 ang = _res[idx] - _res[prev];
696
697 sn = sin(ang);
698 cs = cos(ang);
699 t = 1 - cs;
700
701 dx = c[_torsion[1]] - c[_torsion[2]];
702 dy = c[_torsion[1]+1] - c[_torsion[2]+1];
703 dz = c[_torsion[1]+2] - c[_torsion[2]+2];
704 mag = sqrt(SQUARE(dx) + SQUARE(dy) + SQUARE(dz));
705
706 Set(c,sn,cs,t,1.0/mag);
707 }
708
709 void OBRotor::Precompute(double *c)
710 {
711 double dx,dy,dz;
712 dx = c[_torsion[1]] - c[_torsion[2]];
713 dy = c[_torsion[1]+1] - c[_torsion[2]+1];
714 dz = c[_torsion[1]+2] - c[_torsion[2]+2];
715 _imag = 1.0/sqrt(SQUARE(dx) + SQUARE(dy) + SQUARE(dz));
716
717 _refang = CalcTorsion(c);
718 }
719
720 void OBRotor::Set(double *c,int idx)
721 {
722 double ang,sn,cs,t;
723
724 ang = _res[idx] - _refang;
725 sn = sin(ang);
726 cs = cos(ang);
727 t = 1-cs;
728
729 double x,y,z,tx,ty,tz,m[9];
730
731 x = c[_torsion[1]] - c[_torsion[2]];
732 y = c[_torsion[1]+1] - c[_torsion[2]+1];
733 z = c[_torsion[1]+2] - c[_torsion[2]+2];
734
735 x *= _imag;
736 y *= _imag;
737 z *= _imag; //normalize the rotation vector
738
739 //set up the rotation matrix
740 tx = t*x;
741 ty = t*y;
742 tz = t*z;
743 m[0]= tx*x + cs;
744 m[1] = tx*y + sn*z;
745 m[2] = tx*z - sn*y;
746 m[3] = tx*y - sn*z;
747 m[4] = ty*y + cs;
748 m[5] = ty*z + sn*x;
749 m[6] = tx*z + sn*y;
750 m[7] = ty*z - sn*x;
751 m[8] = tz*z + cs;
752
753 //
754 //now the matrix is set - time to rotate the atoms
755 //
756 tx = c[_torsion[1]];
757 ty = c[_torsion[1]+1];
758 tz = c[_torsion[1]+2];
759 int i,j;
760 for (i = 0;i < _size;i++)
761 {
762 j = _rotatoms[i];
763 c[j] -= tx;
764 c[j+1] -= ty;
765 c[j+2]-= tz;
766 x = c[j]*m[0] + c[j+1]*m[1] + c[j+2]*m[2];
767 y = c[j]*m[3] + c[j+1]*m[4] + c[j+2]*m[5];
768 z = c[j]*m[6] + c[j+1]*m[7] + c[j+2]*m[8];
769 c[j] = x+tx;
770 c[j+1] = y+ty;
771 c[j+2] = z+tz;
772 }
773 }
774
775 void OBRotor::Set(double *c,double sn,double cs,double t,double invmag)
776 {
777 double x,y,z,tx,ty,tz,m[9];
778
779 x = c[_torsion[1]] - c[_torsion[2]];
780 y = c[_torsion[1]+1] - c[_torsion[2]+1];
781 z = c[_torsion[1]+2] - c[_torsion[2]+2];
782
783 //normalize the rotation vector
784
785 x *= invmag;
786 y *= invmag;
787 z *= invmag;
788
789 //set up the rotation matrix
790 tx = t*x;
791 ty = t*y;
792 tz = t*z;
793 m[0]= tx*x + cs;
794 m[1] = tx*y + sn*z;
795 m[2] = tx*z - sn*y;
796 m[3] = tx*y - sn*z;
797 m[4] = ty*y + cs;
798 m[5] = ty*z + sn*x;
799 m[6] = tx*z + sn*y;
800 m[7] = ty*z - sn*x;
801 m[8] = tz*z + cs;
802
803 //
804 //now the matrix is set - time to rotate the atoms
805 //
806 tx = c[_torsion[1]];
807 ty = c[_torsion[1]+1];
808 tz = c[_torsion[1]+2];
809 int i,j;
810 for (i = 0;i < _size;i++)
811 {
812 j = _rotatoms[i];
813 c[j] -= tx;
814 c[j+1] -= ty;
815 c[j+2]-= tz;
816 x = c[j]*m[0] + c[j+1]*m[1] + c[j+2]*m[2];
817 y = c[j]*m[3] + c[j+1]*m[4] + c[j+2]*m[5];
818 z = c[j]*m[6] + c[j+1]*m[7] + c[j+2]*m[8];
819 c[j] = x+tx;
820 c[j+1] = y+ty;
821 c[j+2] = z+tz;
822 }
823 }
824
825 void OBRotor::RemoveSymTorsionValues(int fold)
826 {
827 vector<double>::iterator i;
828 vector<double> tv;
829 if (_res.size() == 1)
830 return;
831
832 for (i = _res.begin();i != _res.end();i++)
833 if (*i >= 0.0)
834 {
835 if (fold == 2 && *i < DEG_TO_RAD*180.0)
836 tv.push_back(*i);
837 if (fold == 3 && *i < DEG_TO_RAD*120.0)
838 tv.push_back(*i);
839 }
840
841 if (tv.empty())
842 return;
843 _res = tv;
844 }
845
846 void OBRotor::SetDihedralAtoms(int ref[4])
847 {
848 for (int i = 0;i < 4;i++)
849 _ref[i] = ref[i];
850 _torsion.resize(4);
851 _torsion[0] = (ref[0]-1)*3;
852 _torsion[1] = (ref[1]-1)*3;
853 _torsion[2] = (ref[2]-1)*3;
854 _torsion[3] = (ref[3]-1)*3;
855 }
856
857 void OBRotor::SetRotAtoms(vector<int> &vi)
858 {
859 if (_rotatoms)
860 delete [] _rotatoms;
861 _rotatoms = new int [vi.size()];
862 copy(vi.begin(),vi.end(),_rotatoms);
863 _size = vi.size();
864 }
865
866 //***************************************
867 //**** OBRotorRules Member functions ****
868 //***************************************
869 OBRotorRules::OBRotorRules()
870 {
871 _quiet=false;
872 _init = false;
873 STR_DEFINE(_dir, FRC_PATH);
874 _envvar = "FORCE_PARAM_PATH";
875 _filename = "torlib.txt";
876 _subdir = "data";
877 _dataptr = TorsionDefaults;
878 }
879
880 void OBRotorRules::ParseLine(const char *buffer)
881 {
882 int i;
883 int ref[4];
884 double delta;
885 vector<double> vals;
886 vector<string> vs;
887 vector<string>::iterator j;
888 char temp_buffer[BUFF_SIZE];
889
890 if (buffer[0] == '#')
891 return;
892 tokenize(vs,buffer);
893 if (vs.empty())
894 return;
895
896 if (EQn(buffer,"SP3-SP3",7))
897 {
898 _sp3sp3.clear();
899 for (j = vs.begin(),j++;j != vs.end();j++)
900 _sp3sp3.push_back(DEG_TO_RAD*atof(j->c_str()));
901 return;
902 }
903
904 if (EQn(buffer,"SP3-SP2",7))
905 {
906 _sp3sp2.clear();
907 for (j = vs.begin(),j++;j != vs.end();j++)
908 _sp3sp2.push_back(DEG_TO_RAD*atof(j->c_str()));
909 return;
910 }
911
912 if (EQn(buffer,"SP2-SP2",7))
913 {
914 _sp2sp2.clear();
915 for (j = vs.begin(),j++;j != vs.end();j++)
916 _sp2sp2.push_back(DEG_TO_RAD*atof(j->c_str()));
917 return;
918 }
919
920 if (!vs.empty() && vs.size() > 5)
921 {
922 strcpy(temp_buffer,vs[0].c_str());
923 //reference atoms
924 for (i = 0;i < 4;i++)
925 ref[i] = atoi(vs[i+1].c_str())-1;
926 //possible torsions
927 vals.clear();
928 delta = OB_DEFAULT_DELTA;
929 for (i = 5;(unsigned)i < vs.size();i++)
930 {
931 if (i == (signed)(vs.size()-2) && vs[i] == "Delta")
932 {
933 delta = atof(vs[i+1].c_str());
934 i += 2;
935 }
936 else
937 vals.push_back(DEG_TO_RAD*atof(vs[i].c_str()));
938 }
939
940 if (vals.empty())
941 {
942 string err = "The following rule has no associated torsions: ";
943 err += vs[0];
944 obErrorLog.ThrowError(__FUNCTION__, err, obDebug);
945 }
946 OBRotorRule *rr = new OBRotorRule (temp_buffer,ref,vals,delta);
947 if (rr->IsValid())
948 _vr.push_back(rr);
949 else
950 delete rr;
951 }
952
953 }
954
955 void OBRotorRules::GetRotorIncrements(OBMol &mol,OBBond *bond,
956 int ref[4],vector<double> &vals,double &delta)
957 {
958 vals.clear();
959 vector<pair<int,int> > vpr;
960 vpr.push_back(pair<int,int> (0,bond->GetBeginAtomIdx()));
961 vpr.push_back(pair<int,int> (0,bond->GetEndAtomIdx()));
962
963 delta = OB_DEFAULT_DELTA;
964
965 int j;
966 OBSmartsPattern *sp;
967 vector<vector<int> > map;
968 vector<OBRotorRule*>::iterator i;
969 for (i = _vr.begin();i != _vr.end();i++)
970 {
971 sp = (*i)->GetSmartsPattern();
972 (*i)->GetReferenceAtoms(ref);
973 vpr[0].first = ref[1];
974 vpr[1].first = ref[2];
975
976 if (!sp->RestrictedMatch(mol,vpr,true))
977 {
978 swap(vpr[0].first,vpr[1].first);
979 if (!sp->RestrictedMatch(mol,vpr,true))
980 continue;
981 }
982
983 map = sp->GetMapList();
984 for (j = 0;j < 4;j++)
985 ref[j] = map[0][ref[j]];
986 vals = (*i)->GetTorsionVals();
987 delta = (*i)->GetDelta();
988
989 OBAtom *a1,*a2,*a3,*a4,*r;
990 a1 = mol.GetAtom(ref[0]);
991 a4 = mol.GetAtom(ref[3]);
992 if (a1->IsHydrogen() && a4->IsHydrogen())
993 continue; //don't allow hydrogens at both ends
994 if (a1->IsHydrogen() || a4->IsHydrogen()) //need a heavy atom reference - can use hydrogen
995 {
996 bool swapped = false;
997 a2 = mol.GetAtom(ref[1]);
998 a3 = mol.GetAtom(ref[2]);
999 if (a4->IsHydrogen())
1000 {
1001 swap(a1,a4);
1002 swap(a2,a3);
1003 swapped = true;
1004 }
1005
1006 vector<OBEdgeBase*>::iterator k;
1007 for (r = a2->BeginNbrAtom(k);r;r = a2->NextNbrAtom(k))
1008 if (!r->IsHydrogen() && r != a3)
1009 break;
1010
1011 if (!r)
1012 continue; //unable to find reference heavy atom
1013 // cerr << "r = " << r->GetIdx() << endl;
1014
1015 double t1 = mol.GetTorsion(a1,a2,a3,a4);
1016 double t2 = mol.GetTorsion(r,a2,a3,a4);
1017 double diff = t2 - t1;
1018 if (diff > 180.0)
1019 diff -= 360.0;
1020 if (diff < -180.0)
1021 diff += 360.0;
1022 diff *= DEG_TO_RAD;
1023
1024 vector<double>::iterator m;
1025 for (m = vals.begin();m != vals.end();m++)
1026 {
1027 *m += diff;
1028 if (*m < PI)
1029 *m += 2.0*PI;
1030 if (*m > PI)
1031 *m -= 2.0*PI;
1032 }
1033
1034 if (swapped)
1035 ref[3] = r->GetIdx();
1036 else
1037 ref[0] = r->GetIdx();
1038
1039 /*
1040 mol.SetTorsion(r,a2,a3,a4,vals[0]);
1041 cerr << "test = " << (vals[0]-diff)*RAD_TO_DEG << ' ';
1042 cerr << mol.GetTorsion(a1,a2,a3,a4) << ' ';
1043 cerr << mol.GetTorsion(r,a2,a3,a4) << endl;
1044 */
1045 }
1046
1047 char buffer[BUFF_SIZE];
1048 if (!_quiet)
1049 {
1050 sprintf(buffer,"%3d%3d%3d%3d %s",
1051 ref[0],ref[1],ref[2],ref[3],
1052 ((*i)->GetSmartsString()).c_str());
1053 obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug);
1054 }
1055 return;
1056 }
1057
1058 //***didn't match any rules - assign based on hybridization***
1059 OBAtom *a1,*a2,*a3,*a4;
1060 a2 = bond->GetBeginAtom();
1061 a3 = bond->GetEndAtom();
1062 vector<OBEdgeBase*>::iterator k;
1063
1064 for (a1 = a2->BeginNbrAtom(k);a1;a1 = a2->NextNbrAtom(k))
1065 if (!a1->IsHydrogen() && a1 != a3)
1066 break;
1067 for (a4 = a3->BeginNbrAtom(k);a4;a4 = a3->NextNbrAtom(k))
1068 if (!a4->IsHydrogen() && a4 != a2)
1069 break;
1070
1071 ref[0] = a1->GetIdx();
1072 ref[1] = a2->GetIdx();
1073 ref[2] = a3->GetIdx();
1074 ref[3] = a4->GetIdx();
1075
1076 if (a2->GetHyb() == 3 && a3->GetHyb() == 3) //sp3-sp3
1077 {
1078 vals = _sp3sp3;
1079
1080 if (!_quiet)
1081 {
1082 char buffer[BUFF_SIZE];
1083 sprintf(buffer,"%3d%3d%3d%3d %s",
1084 ref[0],ref[1],ref[2],ref[3],"sp3-sp3");
1085 obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug);
1086 }
1087 }
1088 else
1089 if (a2->GetHyb() == 2 && a3->GetHyb() == 2) //sp2-sp2
1090 {
1091 vals = _sp2sp2;
1092
1093 if (!_quiet)
1094 {
1095 char buffer[BUFF_SIZE];
1096 sprintf(buffer,"%3d%3d%3d%3d %s",
1097 ref[0],ref[1],ref[2],ref[3],"sp2-sp2");
1098 obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug);
1099 }
1100 }
1101 else //must be sp2-sp3
1102 {
1103 vals = _sp3sp2;
1104
1105 if (!_quiet)
1106 {
1107 char buffer[BUFF_SIZE];
1108 sprintf(buffer,"%3d%3d%3d%3d %s",
1109 ref[0],ref[1],ref[2],ref[3],"sp2-sp3");
1110 obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug);
1111 }
1112 }
1113 }
1114
1115 OBRotorRules::~OBRotorRules()
1116 {
1117 vector<OBRotorRule*>::iterator i;
1118 for (i = _vr.begin();i != _vr.end();i++)
1119 delete (*i);
1120 }
1121
1122 #undef OB_DEFAULT_DELTA
1123 }
1124
1125 //! \file rotor.cpp
1126 //! \brief Rotate dihedral angles according to rotor rules.