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

File Contents

# User Rev Content
1 tim 2440 /**********************************************************************
2     obutil.cpp - Various utility methods.
3    
4     Copyright (C) 1998-2001 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 "babelconfig.hpp"
21     #include "matrix3x3.hpp"
22     #include "vector3.hpp"
23     #include "mol.hpp"
24     #include "obutil.hpp"
25    
26     #if HAVE_CONIO_H
27     #include <conio.h>
28     #endif
29    
30     using namespace std;
31     namespace OpenBabel
32     {
33    
34     /*! \class OBStopwatch
35     \brief Stopwatch class used for timing length of execution
36    
37     The OBStopwatch class makes timing the execution of blocks of
38     code to microsecond accuracy very simple. The class effectively
39     has two functions, Start() and Elapsed(). The usage of the
40     OBStopwatch class is demonstrated by the following code:
41     \code
42     OBStopwatch sw;
43     sw.Start();
44     //insert code here
45     cout << "Elapsed time = " << sw.Elapsed() << endl;
46     \endcode
47     */
48    
49     //! Deprecated: use the OBMessageHandler class instead
50     //! \deprecated Throw an error through the OpenBabel::OBMessageHandler class
51     OBAPI void ThrowError(char *str)
52     {
53     obErrorLog.ThrowError("", str, obInfo);
54     }
55    
56     //! Deprecated: use the OBMessageHandler class instead
57     //! \deprecated Throw an error through the OpenBabel::OBMessageHandler class
58     OBAPI void ThrowError(std::string &str)
59     {
60     obErrorLog.ThrowError("", str, obInfo);
61     }
62    
63     // Comparison function (for sorting ints) returns a < b
64     OBAPI bool OBCompareInt(const int &a,const int &b)
65     {
66     return(a<b);
67     }
68    
69     // Comparison function (for sorting unsigned ints) returns a < b
70     OBAPI bool OBCompareUnsigned(const unsigned int &a,const unsigned int &b)
71     {
72     return(a<b);
73     }
74    
75     // Comparison for doubles: returns a < (b + epsilon)
76     OBAPI bool IsNear(const double &a, const double &b, const double epsilon)
77     {
78     return (fabs(a - b) < epsilon);
79     }
80    
81     // Comparison for doubles: returns a < (0.0 + epsilon)
82     OBAPI bool IsNearZero(const double &a, const double epsilon)
83     {
84     return (fabs(a) < epsilon);
85     }
86    
87     //! Utility function: replace the last extension in string &src with new extension char *ext.
88     OBAPI string NewExtension(string &src,char *ext)
89     {
90     unsigned int pos = (unsigned int)src.find_last_of(".");
91     string dst;
92    
93     if (pos != string::npos)
94     dst = src.substr(0,pos+1);
95     else
96     {
97     dst = src;
98     dst += ".";
99     }
100    
101     dst += ext;
102     return(dst);
103     }
104    
105     //! Return the geometric centroid to an array of coordinates in double* format
106     //! and center the coordinates to the origin. Operates on the first "size"
107     //! coordinates in the array.
108     OBAPI vector3 center_coords(double *c, unsigned int size)
109     {
110     if (size == 0)
111     {
112     vector3 v(0.0f, 0.0f, 0.0f);
113     return(v);
114     }
115     unsigned int i;
116     double x=0,y=0,z=0;
117     for (i = 0;i < size;i++)
118     {
119     x += c[i*3];
120     y += c[i*3+1];
121     z += c[i*3+2];
122     }
123     x /= (double) size;
124     y /= (double) size;
125     z /= (double) size;
126     for (i = 0;i < size;i++)
127     {
128     c[i*3] -= x;
129     c[i*3+1] -= y;
130     c[i*3+2] -= z;
131     }
132     vector3 v(x,y,z);
133     return(v);
134     }
135    
136     //! Rotates the coordinate set *c by the transformation matrix m[3][3]
137     //! Operates on the first "size" coordinates in the array.
138     OBAPI void rotate_coords(double *c,double m[3][3],unsigned int size)
139     {
140     double x,y,z;
141     for (unsigned int i = 0;i < size;i++)
142     {
143     x = c[i*3]*m[0][0] + c[i*3+1]*m[0][1] + c[i*3+2]*m[0][2];
144     y = c[i*3]*m[1][0] + c[i*3+1]*m[1][1] + c[i*3+2]*m[1][2];
145     z = c[i*3]*m[2][0] + c[i*3+1]*m[2][1] + c[i*3+2]*m[2][2];
146     c[i*3] = x;
147     c[i*3+1] = y;
148     c[i*3+2] = z;
149     }
150     }
151    
152     //! Calculate the RMS deviation between the first N coordinates of *r and *f
153     OBAPI double calc_rms(double *r,double *f, unsigned int N)
154     {
155     if (N == 0)
156     return 0.0f; // no RMS deviation between two empty sets
157    
158     double d2=0.0;
159     for (unsigned int i = 0;i < N;i++)
160     {
161     d2 += SQUARE(r[i*3] - f[i*3]) +
162     SQUARE(r[i*3+1] - f[i*3+1]) +
163     SQUARE(r[i*3+2] - f[i*3+2]);
164     }
165    
166     d2 /= (double) N;
167     return(sqrt(d2));
168     }
169    
170     //! Rotate the coordinates of 'atoms'
171     //! such that tor == ang - atoms in 'tor' should be ordered such
172     //! that the 3rd atom is the pivot around which atoms rotate
173     OBAPI void SetRotorToAngle(double *c,vector<int> &tor,double ang,vector<int> &atoms)
174     {
175     double v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z;
176     double c1x,c1y,c1z,c2x,c2y,c2z,c3x,c3y,c3z;
177     double c1mag,c2mag,radang,costheta,m[9];
178     double x,y,z,mag,rotang,sn,cs,t,tx,ty,tz;
179    
180     //
181     //calculate the torsion angle
182     //
183     v1x = c[tor[0]] - c[tor[1]];
184     v2x = c[tor[1]] - c[tor[2]];
185     v1y = c[tor[0]+1] - c[tor[1]+1];
186     v2y = c[tor[1]+1] - c[tor[2]+1];
187     v1z = c[tor[0]+2] - c[tor[1]+2];
188     v2z = c[tor[1]+2] - c[tor[2]+2];
189     v3x = c[tor[2]] - c[tor[3]];
190     v3y = c[tor[2]+1] - c[tor[3]+1];
191     v3z = c[tor[2]+2] - c[tor[3]+2];
192    
193     c1x = v1y*v2z - v1z*v2y;
194     c2x = v2y*v3z - v2z*v3y;
195     c1y = -v1x*v2z + v1z*v2x;
196     c2y = -v2x*v3z + v2z*v3x;
197     c1z = v1x*v2y - v1y*v2x;
198     c2z = v2x*v3y - v2y*v3x;
199     c3x = c1y*c2z - c1z*c2y;
200     c3y = -c1x*c2z + c1z*c2x;
201     c3z = c1x*c2y - c1y*c2x;
202    
203     c1mag = SQUARE(c1x)+SQUARE(c1y)+SQUARE(c1z);
204     c2mag = SQUARE(c2x)+SQUARE(c2y)+SQUARE(c2z);
205     if (c1mag*c2mag < 0.01)
206     costheta = 1.0; //avoid div by zero error
207     else
208     costheta = (c1x*c2x + c1y*c2y + c1z*c2z)/(sqrt(c1mag*c2mag));
209    
210     if (costheta < -0.999999)
211     costheta = -0.999999;
212     if (costheta > 0.999999)
213     costheta = 0.999999;
214    
215     if ((v2x*c3x + v2y*c3y + v2z*c3z) > 0.0)
216     radang = -acos(costheta);
217     else
218     radang = acos(costheta);
219    
220     //
221     // now we have the torsion angle (radang) - set up the rot matrix
222     //
223    
224     //find the difference between current and requested
225     rotang = ang - radang;
226    
227     sn = sin(rotang);
228     cs = cos(rotang);
229     t = 1 - cs;
230     //normalize the rotation vector
231     mag = sqrt(SQUARE(v2x)+SQUARE(v2y)+SQUARE(v2z));
232     x = v2x/mag;
233     y = v2y/mag;
234     z = v2z/mag;
235    
236     //set up the rotation matrix
237     m[0]= t*x*x + cs;
238     m[1] = t*x*y + sn*z;
239     m[2] = t*x*z - sn*y;
240     m[3] = t*x*y - sn*z;
241     m[4] = t*y*y + cs;
242     m[5] = t*y*z + sn*x;
243     m[6] = t*x*z + sn*y;
244     m[7] = t*y*z - sn*x;
245     m[8] = t*z*z + cs;
246    
247     //
248     //now the matrix is set - time to rotate the atoms
249     //
250     tx = c[tor[1]];
251     ty = c[tor[1]+1];
252     tz = c[tor[1]+2];
253     vector<int>::iterator i;
254     int j;
255     for (i = atoms.begin();i != atoms.end();i++)
256     {
257     j = *i;
258     c[j] -= tx;
259     c[j+1] -= ty;
260     c[j+2]-= tz;
261     x = c[j]*m[0] + c[j+1]*m[1] + c[j+2]*m[2];
262     y = c[j]*m[3] + c[j+1]*m[4] + c[j+2]*m[5];
263     z = c[j]*m[6] + c[j+1]*m[7] + c[j+2]*m[8];
264     c[j] = x;
265     c[j+1] = y;
266     c[j+2] = z;
267     c[j] += tx;
268     c[j+1] += ty;
269     c[j+2] += tz;
270     }
271     }
272    
273     //! Safely open the supplied filename and return an ifstream, throwing an error
274     //! to the default OBMessageHandler error log if it fails.
275     OBAPI bool SafeOpen(ifstream &fs,char *filename)
276     {
277     #ifdef WIN32
278     string s = filename;
279     if (s.find(".bin") != string::npos)
280     fs.open(filename,ios::binary);
281     else
282     #endif
283    
284     fs.open(filename);
285    
286     if (!fs)
287     {
288     string error = "Unable to open file \'";
289     error += filename;
290     error += "\' in read mode";
291     obErrorLog.ThrowError(__FUNCTION__, error, obError);
292     return(false);
293     }
294    
295     return(true);
296     }
297    
298    
299     //! Safely open the supplied filename and return an ofstream, throwing an error
300     //! to the default OBMessageHandler error log if it fails.
301     OBAPI bool SafeOpen(ofstream &fs,char *filename)
302     {
303     #ifdef WIN32
304     string s = filename;
305     if (s.find(".bin") != string::npos)
306     fs.open(filename,ios::binary);
307     else
308     #endif
309    
310     fs.open(filename);
311    
312     if (!fs)
313     {
314     string error = "Unable to open file \'";
315     error += filename;
316     error += "\' in write mode";
317     obErrorLog.ThrowError(__FUNCTION__, error, obError);
318     return(false);
319     }
320    
321     return(true);
322     }
323    
324     //! Safely open the supplied filename and return an ifstream, throwing an error
325     //! to the default OBMessageHandler error log if it fails.
326     OBAPI bool SafeOpen(ifstream &fs,string &filename)
327     {
328     return(SafeOpen(fs,(char*)filename.c_str()));
329     }
330    
331     //! Safely open the supplied filename and return an ofstream, throwing an error
332     //! to the default OBMessageHandler error log if it fails.
333     OBAPI bool SafeOpen(ofstream &fs,string &filename)
334     {
335     return(SafeOpen(fs,(char*)filename.c_str()));
336     }
337    
338     //! Shift the supplied string to uppercase
339     OBAPI void ToUpper(std::string &s)
340     {
341     if (s.empty())
342     return;
343     unsigned int i;
344     for (i = 0;i < s.size();i++)
345     if (isalpha(s[i]) && !isdigit(s[i]))
346     s[i] = toupper(s[i]);
347     }
348    
349     //! Shift the supplied char* to uppercase
350     OBAPI void ToUpper(char *cptr)
351     {
352     char *c;
353     for (c = cptr;*c != '\0';c++)
354     if (isalpha(*c) && !isdigit(*c))
355     *c = toupper(*c);
356     }
357    
358     //! Shift the supplied string to lowercase
359     OBAPI void ToLower(std::string &s)
360     {
361     if (s.empty())
362     return;
363     unsigned int i;
364     for (i = 0;i < s.size();i++)
365     if (isalpha(s[i]) && !isdigit(s[i]))
366     s[i] = tolower(s[i]);
367     }
368    
369     //! Shift the supplied char* to lowercase
370     OBAPI void ToLower(char *cptr)
371     {
372     char *c;
373     for (c = cptr;*c != '\0';c++)
374     if (isalpha(*c) && !isdigit(*c))
375     *c = tolower(*c);
376     }
377    
378     //! "Clean" the supplied atom type, shifting the first character to uppercase,
379     //! the second character (if it's a letter) to lowercase, and terminating with a NULL
380     //! to strip off any trailing characters
381     OBAPI void CleanAtomType(char *id)
382     {
383     id[0] = toupper(id[0]);
384     if (isalpha(id[1]) == 0)
385     id[1] = '\0';
386     else
387     {
388     id[1] = tolower(id[1]);
389     id[2] = '\0';
390     }
391     }
392    
393     //! Transform the supplied vector<OBInternalCoord*> into cartesian and update
394     //! the OBMol accordingly.
395     //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#zmatrixCoordinatesIntoCartesianCoordinates">blue-obelisk:zmatrixCoordinatesIntoCartesianCoordinates</a>
396     OBAPI void InternalToCartesian(std::vector<OBInternalCoord*> &vic,OBMol &mol)
397     {
398     vector3 n,nn,v1,v2,v3,avec,bvec,cvec;
399     double dst = 0.0, ang = 0.0, tor = 0.0;
400     OBAtom *atom;
401     vector<OBNodeBase*>::iterator i;
402     int index;
403    
404     if (vic.empty())
405     return;
406    
407     obErrorLog.ThrowError(__FUNCTION__,
408     "Ran OpenBabel::InternalToCartesian", obAuditMsg);
409    
410     for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
411     {
412     index = atom->GetIdx();
413    
414     if (!vic[index]) // make sure we always have valid pointers
415     return;
416    
417     if (vic[index]->_a) // make sure we have a valid ptr
418     {
419     avec = vic[index]->_a->GetVector();
420     dst = vic[index]->_dst;
421     }
422     else
423     {
424     // atom 1
425     atom->SetVector(0.0, 0.0, 0.0);
426     continue;
427     }
428    
429     if (vic[index]->_b)
430     {
431     bvec = vic[index]->_b->GetVector();
432     ang = vic[index]->_ang * DEG_TO_RAD;
433     }
434     else
435     {
436     // atom 2
437     atom->SetVector(dst, 0.0, 0.0);
438     continue;
439     }
440    
441     if (vic[index]->_c)
442     {
443     cvec = vic[index]->_c->GetVector();
444     tor = vic[index]->_tor * DEG_TO_RAD;
445     }
446     else
447     {
448     // atom 3
449     cvec = VY;
450     tor = 90. * DEG_TO_RAD;
451     }
452    
453     v1 = avec - bvec;
454     v2 = avec - cvec;
455     n = cross(v1,v2);
456     nn = cross(v1,n);
457     n.normalize();
458     nn.normalize();
459    
460     n *= -sin(tor);
461     nn *= cos(tor);
462     v3 = n + nn;
463     v3.normalize();
464     v3 *= dst * sin(ang);
465     v1.normalize();
466     v1 *= dst * cos(ang);
467     v2 = avec + v3 - v1;
468    
469     atom->SetVector(v2);
470     }
471    
472     // Delete dummy atoms
473     for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
474     if (atom->GetAtomicNum() == 0)
475     mol.DeleteAtom(atom);
476     }
477    
478     //! Use the supplied OBMol and its Cartesian coordinates to generate
479     //! a set of internal (z-matrix) coordinates as supplied in the
480     //! vector<OBInternalCoord*> argument.
481     //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#cartesianCoordinatesIntoZmatrixCoordinates">blue-obelisk:cartesianCoordinatesIntoZmatrixCoordinates</a>.
482     OBAPI void CartesianToInternal(std::vector<OBInternalCoord*> &vic,OBMol &mol)
483     {
484     double r,sum;
485     OBAtom *atom,*nbr,*ref;
486     vector<OBNodeBase*>::iterator i,j,m;
487    
488     obErrorLog.ThrowError(__FUNCTION__,
489     "Ran OpenBabel::CartesianToInternal", obAuditMsg);
490    
491     //set reference atoms
492     for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
493     {
494     if (atom->GetIdx() == 1)
495     continue;
496     else if (atom->GetIdx() == 2)
497     {
498     vic[atom->GetIdx()]->_a = mol.GetAtom(1);
499     continue;
500     }
501     else if (atom->GetIdx() == 3)
502     {
503     if( (atom->GetVector()-mol.GetAtom(2)->GetVector()).length_2()
504     <(atom->GetVector()-mol.GetAtom(1)->GetVector()).length_2())
505     {
506     vic[atom->GetIdx()]->_a = mol.GetAtom(2);
507     vic[atom->GetIdx()]->_b = mol.GetAtom(1);
508     }
509     else
510     {
511     vic[atom->GetIdx()]->_a = mol.GetAtom(1);
512     vic[atom->GetIdx()]->_b = mol.GetAtom(2);
513     }
514     continue;
515     }
516     sum=1.0E10;
517     ref = mol.GetAtom(1);
518     for(nbr = mol.BeginAtom(j);nbr && (i != j);nbr = mol.NextAtom(j))
519     {
520     r = (atom->GetVector()-nbr->GetVector()).length_2();
521     if((r < sum) && (vic[nbr->GetIdx()]->_a != nbr) &&
522     (vic[nbr->GetIdx()]->_b != nbr))
523     {
524     sum = r;
525     ref = nbr;
526     }
527     }
528    
529     vic[atom->GetIdx()]->_a = ref;
530     if (ref->GetIdx() >= 3)
531     {
532     vic[atom->GetIdx()]->_b = vic[ref->GetIdx()]->_a;
533     vic[atom->GetIdx()]->_c = vic[ref->GetIdx()]->_b;
534     }
535     else
536     {
537     if(ref->GetIdx()== 1)
538     {
539     vic[atom->GetIdx()]->_b = mol.GetAtom(2);
540     vic[atom->GetIdx()]->_c = mol.GetAtom(3);
541     }
542     else
543     {//ref->GetIdx()== 2
544     vic[atom->GetIdx()]->_b = mol.GetAtom(1);
545     vic[atom->GetIdx()]->_c = mol.GetAtom(3);
546     }
547     }
548     }
549    
550     //fill in geometries
551     unsigned int k;
552     vector3 v1,v2;
553     OBAtom *a,*b,*c;
554     for (k = 2;k <= mol.NumAtoms();k++)
555     {
556     atom = mol.GetAtom(k);
557     a = vic[k]->_a;
558     b = vic[k]->_b;
559     c = vic[k]->_c;
560     if (k == 2)
561     {
562     vic[k]->_dst = (atom->GetVector() - a->GetVector()).length();
563     continue;
564     }
565    
566     v1 = atom->GetVector() - a->GetVector();
567     v2 = b->GetVector() - a->GetVector();
568     vic[k]->_dst = v1.length();
569     vic[k]->_ang = vectorAngle(v1,v2);
570    
571     if (k == 3)
572     continue;
573     vic[k]->_tor = CalcTorsionAngle(atom->GetVector(),
574     a->GetVector(),
575     b->GetVector(),
576     c->GetVector());
577     }
578    
579     //check for linear geometries and try to correct if possible
580     bool done;
581     double ang;
582     for (k = 2;k <= mol.NumAtoms();k++)
583     {
584     ang = fabs(vic[k]->_ang);
585     if (ang > 5.0 && ang < 175.0)
586     continue;
587     atom = mol.GetAtom(k);
588     done = false;
589     for (a = mol.BeginAtom(i);a && a->GetIdx() < k && !done;a = mol.NextAtom(i))
590     for (b=mol.BeginAtom(j);b && b->GetIdx()<a->GetIdx() && !done;b = mol.NextAtom(j))
591     {
592     v1 = atom->GetVector() - a->GetVector();
593     v2 = b->GetVector() - a->GetVector();
594     ang = fabs(vectorAngle(v1,v2));
595     if (ang < 5.0 || ang > 175.0)
596     continue;
597    
598     for (c = mol.BeginAtom(m);c && c->GetIdx() < atom->GetIdx();c = mol.NextAtom(m))
599     if (c != atom && c != a && c != b)
600     break;
601     if (!c)
602     continue;
603    
604     vic[k]->_a = a;
605     vic[k]->_b = b;
606     vic[k]->_c = c;
607     vic[k]->_dst = v1.length();
608     vic[k]->_ang = vectorAngle(v1,v2);
609     vic[k]->_tor = CalcTorsionAngle(atom->GetVector(),
610     a->GetVector(),
611     b->GetVector(),
612     c->GetVector());
613     done = true;
614     }
615     }
616     }
617    
618     OBAPI void qtrfit (double *r,double *f,int size, double u[3][3])
619     {
620     register int i;
621     double xxyx, xxyy, xxyz;
622     double xyyx, xyyy, xyyz;
623     double xzyx, xzyy, xzyz;
624     double d[4],q[4];
625     double c[16],v[16];
626     double rx,ry,rz,fx,fy,fz;
627    
628     /* generate the upper triangle of the quadratic form matrix */
629    
630     xxyx = 0.0;
631     xxyy = 0.0;
632     xxyz = 0.0;
633     xyyx = 0.0;
634     xyyy = 0.0;
635     xyyz = 0.0;
636     xzyx = 0.0;
637     xzyy = 0.0;
638     xzyz = 0.0;
639    
640     for (i = 0; i < size; i++)
641     {
642     rx = r[i*3];
643     ry = r[i*3+1];
644     rz = r[i*3+2];
645     fx = f[i*3];
646     fy = f[i*3+1];
647     fz = f[i*3+2];
648    
649     xxyx += fx * rx;
650     xxyy += fx * ry;
651     xxyz += fx * rz;
652     xyyx += fy * rx;
653     xyyy += fy * ry;
654     xyyz += fy * rz;
655     xzyx += fz * rx;
656     xzyy += fz * ry;
657     xzyz += fz * rz;
658     }
659    
660     c[4*0+0] = xxyx + xyyy + xzyz;
661    
662     c[4*0+1] = xzyy - xyyz;
663     c[4*1+1] = xxyx - xyyy - xzyz;
664    
665     c[4*0+2] = xxyz - xzyx;
666     c[4*1+2] = xxyy + xyyx;
667     c[4*2+2] = xyyy - xzyz - xxyx;
668    
669     c[4*0+3] = xyyx - xxyy;
670     c[4*1+3] = xzyx + xxyz;
671     c[4*2+3] = xyyz + xzyy;
672     c[4*3+3] = xzyz - xxyx - xyyy;
673    
674     /* diagonalize c */
675    
676     matrix3x3::jacobi(4, c, d, v);
677    
678     /* extract the desired quaternion */
679    
680     q[0] = v[4*0+3];
681     q[1] = v[4*1+3];
682     q[2] = v[4*2+3];
683     q[3] = v[4*3+3];
684    
685     /* generate the rotation matrix */
686    
687     u[0][0] = q[0]*q[0] + q[1]*q[1] - q[2]*q[2] - q[3]*q[3];
688     u[1][0] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
689     u[2][0] = 2.0 * (q[1] * q[3] + q[0] * q[2]);
690    
691     u[0][1] = 2.0 * (q[2] * q[1] + q[0] * q[3]);
692     u[1][1] = q[0]*q[0] - q[1]*q[1] + q[2]*q[2] - q[3]*q[3];
693     u[2][1] = 2.0 * (q[2] * q[3] - q[0] * q[1]);
694    
695     u[0][2] = 2.0 * (q[3] * q[1] - q[0] * q[2]);
696     u[1][2] = 2.0 * (q[3] * q[2] + q[0] * q[1]);
697     u[2][2] = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
698     }
699    
700    
701    
702     static double Roots[4];
703    
704     #define ApproxZero 1E-7
705     #define IsZero(x) ((double)fabs(x)<ApproxZero)
706     #ifndef PI
707     #define PI 3.14159265358979323846226433
708     #endif
709     #define OneThird (1.0/3.0)
710     #define FourThirdsPI (4.0*PI/3.0)
711     #define TwoThirdsPI (2.0*PI/3.0)
712    
713     #ifdef OLD_RMAT
714    
715     /*FUNCTION */
716     /* recieves: the co-efficients for a general
717     * equation of degree one.
718     * Ax + B = 0 !!
719     */
720     OBAPI static int SolveLinear(double A,double B)
721     {
722     if( IsZero(A) )
723     return( 0 );
724     Roots[0] = -B/A;
725     return( 1 );
726     }
727    
728     /*FUNCTION */
729     /* recieves: the co-efficients for a general
730     * linear equation of degree two.
731     * Ax^2 + Bx + C = 0 !!
732     */
733     OBAPI static int SolveQuadratic(double A,double B,double C)
734     {
735     register double Descr, Temp, TwoA;
736    
737     if( IsZero(A) )
738     return( SolveLinear(B,C) );
739    
740     TwoA = A+A;
741     Temp = TwoA*C;
742     Descr = B*B - (Temp+Temp);
743     if( Descr<0.0 )
744     return( 0 );
745    
746     if( Descr>0.0 )
747     {
748     Descr = sqrt(Descr);
749     #ifdef ORIG
750    
751     Roots[0] = (-B-Descr)/TwoA;
752     Roots[1] = (-B+Descr)/TwoA;
753     #else
754     /* W. Press, B. Flannery, S. Teukolsky and W. Vetterling,
755     * "Quadratic and Cubic Equations", Numerical Recipes in C,
756     * Chapter 5, pp. 156-157, 1989.
757     */
758     Temp = (B<0.0)? -0.5*(B-Descr) : -0.5*(B+Descr);
759     Roots[0] = Temp/A;
760     Roots[1] = C/Temp;
761     #endif
762    
763     return( 2 );
764     }
765     Roots[0] = -B/TwoA;
766     return( 1 );
767     }
768    
769     /*FUNCTION */
770     /* task: to return the cube root of the
771     * given value taking into account
772     * that it may be negative.
773     */
774     OBAPI static double CubeRoot(double X)
775     {
776     if( X>=0.0 )
777     {
778     return pow( X, OneThird );
779     }
780     else
781     return -pow( -X, OneThird );
782     }
783    
784     OBAPI static int SolveCubic(double A,double B,double C,double D)
785     {
786     register double TwoA, ThreeA, BOver3A;
787     register double Temp, POver3, QOver2;
788     register double Desc, Rho, Psi;
789    
790    
791     if( IsZero(A) )
792     {
793     return( SolveQuadratic(B,C,D) );
794     }
795    
796     TwoA = A+A;
797     ThreeA = TwoA+A;
798     BOver3A = B/ThreeA;
799     QOver2 = ((TwoA*BOver3A*BOver3A-C)*BOver3A+D)/TwoA;
800     POver3 = (C-B*BOver3A)/ThreeA;
801    
802    
803     Rho = POver3*POver3*POver3;
804     Desc = QOver2*QOver2 + Rho;
805    
806     if( Desc<=0.0 )
807     {
808     Rho = sqrt( -Rho );
809     Psi = OneThird*acos(-QOver2/Rho);
810     Temp = CubeRoot( Rho );
811     Temp = Temp+Temp;
812    
813     Roots[0] = Temp*cos( Psi )-BOver3A;
814     Roots[1] = Temp*cos( Psi+TwoThirdsPI )-BOver3A;
815     Roots[2] = Temp*cos( Psi+FourThirdsPI )-BOver3A;
816     return( 3 );
817     }
818    
819     if( Desc> 0.0 )
820     {
821     Temp = CubeRoot( -QOver2 );
822     Roots[0] = Temp+Temp-BOver3A;
823     Roots[1] = -Temp-BOver3A;
824     return( 2 );
825     }
826    
827     Desc = sqrt( Desc );
828     Roots[0] = CubeRoot(Desc-QOver2)-CubeRoot(Desc+QOver2) - BOver3A;
829    
830     return( 1 );
831     }
832     #endif
833    
834    
835     #define MAX_SWEEPS 50
836    
837     OBAPI void ob_make_rmat(double a[3][3],double rmat[9])
838     {
839     double onorm, dnorm;
840     double b, dma, q, t, c, s,d[3];
841     double atemp, vtemp, dtemp,v[3][3];
842     double r1[3],r2[3],v1[3],v2[3],v3[3];
843     int i, j, k, l;
844    
845     memset((char*)d,'\0',sizeof(double)*3);
846    
847     for (j = 0; j < 3; j++)
848     {
849     for (i = 0; i < 3; i++)
850     v[i][j] = 0.0;
851    
852     v[j][j] = 1.0;
853     d[j] = a[j][j];
854     }
855    
856     for (l = 1; l <= MAX_SWEEPS; l++)
857     {
858     dnorm = 0.0;
859     onorm = 0.0;
860     for (j = 0; j < 3; j++)
861     {
862     dnorm = dnorm + (double)fabs(d[j]);
863     for (i = 0; i <= j - 1; i++)
864     {
865     onorm = onorm + (double)fabs(a[i][j]);
866     }
867     }
868    
869     if((onorm/dnorm) <= 1.0e-12)
870     goto Exit_now;
871     for (j = 1; j < 3; j++)
872     {
873     for (i = 0; i <= j - 1; i++)
874     {
875     b = a[i][j];
876     if(fabs(b) > 0.0)
877     {
878     dma = d[j] - d[i];
879     if((fabs(dma) + fabs(b)) <= fabs(dma))
880     t = b / dma;
881     else
882     {
883     q = 0.5 * dma / b;
884     t = 1.0/((double)fabs(q) + (double)sqrt(1.0+q*q));
885     if(q < 0.0)
886     t = -t;
887     }
888     c = 1.0/(double)sqrt(t * t + 1.0);
889     s = t * c;
890     a[i][j] = 0.0;
891     for (k = 0; k <= i-1; k++)
892     {
893     atemp = c * a[k][i] - s * a[k][j];
894     a[k][j] = s * a[k][i] + c * a[k][j];
895     a[k][i] = atemp;
896     }
897     for (k = i+1; k <= j-1; k++)
898     {
899     atemp = c * a[i][k] - s * a[k][j];
900     a[k][j] = s * a[i][k] + c * a[k][j];
901     a[i][k] = atemp;
902     }
903     for (k = j+1; k < 3; k++)
904     {
905     atemp = c * a[i][k] - s * a[j][k];
906     a[j][k] = s * a[i][k] + c * a[j][k];
907     a[i][k] = atemp;
908     }
909     for (k = 0; k < 3; k++)
910     {
911     vtemp = c * v[k][i] - s * v[k][j];
912     v[k][j] = s * v[k][i] + c * v[k][j];
913     v[k][i] = vtemp;
914     }
915     dtemp = c*c*d[i] + s*s*d[j] - 2.0*c*s*b;
916     d[j] = s*s*d[i] + c*c*d[j] + 2.0*c*s*b;
917     d[i] = dtemp;
918     } /* end if */
919     } /* end for i */
920     } /* end for j */
921     } /* end for l */
922    
923     Exit_now:
924    
925     /* max_sweeps = l;*/
926    
927     for (j = 0; j < 3-1; j++)
928     {
929     k = j;
930     dtemp = d[k];
931     for (i = j+1; i < 3; i++)
932     if(d[i] < dtemp)
933     {
934     k = i;
935     dtemp = d[k];
936     }
937    
938     if(k > j)
939     {
940     d[k] = d[j];
941     d[j] = dtemp;
942     for (i = 0; i < 3 ; i++)
943     {
944     dtemp = v[i][k];
945     v[i][k] = v[i][j];
946     v[i][j] = dtemp;
947     }
948     }
949     }
950    
951     r1[0] = v[0][0];
952     r1[1] = v[1][0];
953     r1[2] = v[2][0];
954     r2[0] = v[0][1];
955     r2[1] = v[1][1];
956     r2[2] = v[2][1];
957    
958     v3[0] = r1[1]*r2[2] - r1[2]*r2[1];
959     v3[1] = -r1[0]*r2[2] + r1[2]*r2[0];
960     v3[2] = r1[0]*r2[1] - r1[1]*r2[0];
961     s = (double)sqrt(v3[0]*v3[0] + v3[1]*v3[1] + v3[2]*v3[2]);
962     v3[0] /= s;
963     v3[0] /= s;
964     v3[0] /= s;
965    
966     v2[0] = v3[1]*r1[2] - v3[2]*r1[1];
967     v2[1] = -v3[0]*r1[2] + v3[2]*r1[0];
968     v2[2] = v3[0]*r1[1] - v3[1]*r1[0];
969     s = (double)sqrt(v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2]);
970     v2[0] /= s;
971     v2[0] /= s;
972     v2[0] /= s;
973    
974     v1[0] = v2[1]*v3[2] - v2[2]*v3[1];
975     v1[1] = -v2[0]*v3[2] + v2[2]*v3[0];
976     v1[2] = v2[0]*v3[1] - v2[1]*v3[0];
977     s = (double)sqrt(v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2]);
978     v1[0] /= s;
979     v1[0] /= s;
980     v1[0] /= s;
981    
982     rmat[0] = v1[0];
983     rmat[1] = v1[1];
984     rmat[2] = v1[2];
985     rmat[3] = v2[0];
986     rmat[4] = v2[1];
987     rmat[5] = v2[2];
988     rmat[6] = v3[0];
989     rmat[7] = v3[1];
990     rmat[8] = v3[2];
991     }
992    
993     static int get_roots_3_3(double mat[3][3], double roots[3])
994     {
995     double rmat[9];
996    
997     ob_make_rmat(mat,rmat);
998    
999     mat[0][0]=rmat[0];
1000     mat[0][1]=rmat[3];
1001     mat[0][2]=rmat[6];
1002     mat[1][0]=rmat[1];
1003     mat[1][1]=rmat[4];
1004     mat[1][2]=rmat[7];
1005     mat[2][0]=rmat[2];
1006     mat[2][1]=rmat[5];
1007     mat[2][2]=rmat[8];
1008    
1009     roots[0]=(double)Roots[0];
1010     roots[1]=(double)Roots[1];
1011     roots[2]=(double)Roots[2];
1012    
1013     return 1;
1014     }
1015    
1016     OBAPI double superimpose(double *r,double *f,int size)
1017     {
1018     int i,j;
1019     double x,y,z,d2;
1020     double mat[3][3],rmat[3][3],mat2[3][3],roots[3];
1021    
1022     /* make inertial cross tensor */
1023     for(i=0;i<3;i++)
1024     for(j=0;j<3;j++)
1025     mat[i][j]=0.0;
1026    
1027     for(i=0;i < size;i++)
1028     {
1029     mat[0][0]+=r[3*i] *f[3*i];
1030     mat[1][0]+=r[3*i+1]*f[3*i];
1031     mat[2][0]+=r[3*i+2]*f[3*i];
1032     mat[0][1]+=r[3*i] *f[3*i+1];
1033     mat[1][1]+=r[3*i+1]*f[3*i+1];
1034     mat[2][1]+=r[3*i+2]*f[3*i+1];
1035     mat[0][2]+=r[3*i] *f[3*i+2];
1036     mat[1][2]+=r[3*i+1]*f[3*i+2];
1037     mat[2][2]+=r[3*i+2]*f[3*i+2];
1038     }
1039    
1040     d2=mat[0][0]*(mat[1][1]*mat[2][2]-mat[1][2]*mat[2][1])
1041     -mat[0][1]*(mat[1][0]*mat[2][2]-mat[1][2]*mat[2][0])
1042     +mat[0][2]*(mat[1][0]*mat[2][1]-mat[1][1]*mat[2][0]);
1043    
1044    
1045     /* square matrix= ((mat transpose) * mat) */
1046     for(i=0;i<3;i++)
1047     for(j=0;j<3;j++)
1048     {
1049     x=mat[0][i]*mat[0][j]+mat[1][i]*mat[1][j]+mat[2][i]*mat[2][j];
1050     mat2[i][j]=mat[i][j];
1051     rmat[i][j]=x;
1052     }
1053     get_roots_3_3(rmat,roots);
1054    
1055     roots[0]=(roots[0]<0.0001) ? 0.0: (roots[0]);
1056     roots[1]=(roots[1]<0.0001) ? 0.0: (roots[1]);
1057     roots[2]=(roots[2]<0.0001) ? 0.0: (roots[2]);
1058    
1059     /* make sqrt of rmat, store in mat*/
1060    
1061     roots[0]=roots[0]<0.0001? 0.0: 1.0/(double)sqrt(roots[0]);
1062     roots[1]=roots[1]<0.0001? 0.0: 1.0/(double)sqrt(roots[1]);
1063     roots[2]=roots[2]<0.0001? 0.0: 1.0/(double)sqrt(roots[2]);
1064    
1065     if(d2<0.0)
1066     {
1067     if( (roots[0]>=roots[1]) && (roots[0]>=roots[2]) )
1068     roots[0]*=-1.0;
1069     if( (roots[1]>roots[0]) && (roots[1]>=roots[2]) )
1070     roots[1]*=-1.0;
1071     if( (roots[2]>roots[1]) && (roots[2]>roots[0]) )
1072     roots[2]*=-1.0;
1073     }
1074    
1075     for(i=0;i<3;i++)
1076     for(j=0;j<3;j++)
1077     mat[i][j]=roots[0]*rmat[i][0]*rmat[j][0]+
1078     roots[1]*rmat[i][1]*rmat[j][1]+
1079     roots[2]*rmat[i][2]*rmat[j][2];
1080    
1081     /* and multiply into original inertial cross matrix, mat2 */
1082     for(i=0;i<3;i++)
1083     for(j=0;j<3;j++)
1084     rmat[i][j]=mat[0][j]*mat2[i][0]+
1085     mat[1][j]*mat2[i][1]+
1086     mat[2][j]*mat2[i][2];
1087    
1088     /* rotate all coordinates */
1089     d2 = 0.0;
1090     for(i=0;i<size;i++)
1091     {
1092     x=f[3*i]*rmat[0][0]+f[3*i+1]*rmat[0][1]+f[3*i+2]*rmat[0][2];
1093     y=f[3*i]*rmat[1][0]+f[3*i+1]*rmat[1][1]+f[3*i+2]*rmat[1][2];
1094     z=f[3*i]*rmat[2][0]+f[3*i+1]*rmat[2][1]+f[3*i+2]*rmat[2][2];
1095     f[3*i ]=x;
1096     f[3*i+1]=y;
1097     f[3*i+2]=z;
1098    
1099     x = r[i*3] - f[i*3];
1100     y = r[i*3+1] - f[i*3+1];
1101     z = r[i*3+2] - f[i*3+2];
1102     d2 += x*x+y*y+z*z;
1103     }
1104    
1105     d2 /= (double) size;
1106    
1107     return((double)sqrt(d2));
1108     }
1109    
1110     OBAPI void get_rmat(double *rvec,double *r,double *f,int size)
1111     {
1112     int i,j;
1113     double x,d2;
1114     double mat[3][3],rmat[3][3],mat2[3][3],roots[3];
1115    
1116     /* make inertial cross tensor */
1117     for(i=0;i<3;i++)
1118     for(j=0;j<3;j++)
1119     mat[i][j]=0.0;
1120    
1121     for(i=0;i < size;i++)
1122     {
1123     mat[0][0]+=r[3*i] *f[3*i];
1124     mat[1][0]+=r[3*i+1]*f[3*i];
1125     mat[2][0]+=r[3*i+2]*f[3*i];
1126     mat[0][1]+=r[3*i] *f[3*i+1];
1127     mat[1][1]+=r[3*i+1]*f[3*i+1];
1128     mat[2][1]+=r[3*i+2]*f[3*i+1];
1129     mat[0][2]+=r[3*i] *f[3*i+2];
1130     mat[1][2]+=r[3*i+1]*f[3*i+2];
1131     mat[2][2]+=r[3*i+2]*f[3*i+2];
1132     }
1133    
1134     d2=mat[0][0]*(mat[1][1]*mat[2][2]-mat[1][2]*mat[2][1])
1135     -mat[0][1]*(mat[1][0]*mat[2][2]-mat[1][2]*mat[2][0])
1136     +mat[0][2]*(mat[1][0]*mat[2][1]-mat[1][1]*mat[2][0]);
1137    
1138     /* square matrix= ((mat transpose) * mat) */
1139     for(i=0;i<3;i++)
1140     for(j=0;j<3;j++)
1141     {
1142     x=mat[0][i]*mat[0][j]+mat[1][i]*mat[1][j]+mat[2][i]*mat[2][j];
1143     mat2[i][j]=mat[i][j];
1144     rmat[i][j]=x;
1145     }
1146     get_roots_3_3(rmat,roots);
1147    
1148     roots[0]=(roots[0]<0.0001) ? 0.0: (roots[0]);
1149     roots[1]=(roots[1]<0.0001) ? 0.0: (roots[1]);
1150     roots[2]=(roots[2]<0.0001) ? 0.0: (roots[2]);
1151    
1152     /* make sqrt of rmat, store in mat*/
1153    
1154     roots[0]=(roots[0]<0.0001) ? 0.0: 1.0/(double)sqrt(roots[0]);
1155     roots[1]=(roots[1]<0.0001) ? 0.0: 1.0/(double)sqrt(roots[1]);
1156     roots[2]=(roots[2]<0.0001) ? 0.0: 1.0/(double)sqrt(roots[2]);
1157    
1158     if(d2<0.0)
1159     {
1160     if( (roots[0]>=roots[1]) && (roots[0]>=roots[2]) )
1161     roots[0]*=-1.0;
1162     if( (roots[1]>roots[0]) && (roots[1]>=roots[2]) )
1163     roots[1]*=-1.0;
1164     if( (roots[2]>roots[1]) && (roots[2]>roots[0]) )
1165     roots[2]*=-1.0;
1166     }
1167    
1168     for(i=0;i<3;i++)
1169     for(j=0;j<3;j++)
1170     mat[i][j]=roots[0]*rmat[i][0]*rmat[j][0]+
1171     roots[1]*rmat[i][1]*rmat[j][1]+
1172     roots[2]*rmat[i][2]*rmat[j][2];
1173    
1174     /* and multiply into original inertial cross matrix, mat2 */
1175     for(i=0;i<3;i++)
1176     for(j=0;j<3;j++)
1177     rmat[i][j]=mat[0][j]*mat2[i][0]+
1178     mat[1][j]*mat2[i][1]+
1179     mat[2][j]*mat2[i][2];
1180    
1181     rvec[0] = rmat[0][0];
1182     rvec[1] = rmat[0][1];
1183     rvec[2] = rmat[0][2];
1184     rvec[3] = rmat[1][0];
1185     rvec[4] = rmat[1][1];
1186     rvec[5] = rmat[1][2];
1187     rvec[6] = rmat[2][0];
1188     rvec[7] = rmat[2][1];
1189     rvec[8] = rmat[2][2];
1190     }
1191    
1192     } // end namespace OpenBabel
1193    
1194     //! \file obutil.cpp
1195     //! \brief Various utility methods.