ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/openbabel/rotor.cpp
Revision: 2440
Committed: Wed Nov 16 19:42:11 2005 UTC (18 years, 8 months ago) by tim
File size: 30926 byte(s)
Log Message:
adding openbabel

File Contents

# User Rev Content
1 tim 2440 /**********************************************************************
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     _dir = BABEL_DATADIR;
874     _envvar = "BABEL_DATADIR";
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.