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