Coverage Report

Created: 2023-06-07 06:20

/src/openbabel/src/math/matrix3x3.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
matrix3x3.cpp - Handle 3D rotation matrix.
3
4
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5
Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
6
Some portions Copyright (C) 2006 by Benoit Jacob
7
8
This file is part of the Open Babel project.
9
For more information, see <http://openbabel.org/>
10
11
This program is free software; you can redistribute it and/or modify
12
it under the terms of the GNU General Public License as published by
13
the Free Software Foundation version 2 of the License.
14
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
GNU General Public License for more details.
19
***********************************************************************/
20
#include <openbabel/babelconfig.h>
21
22
#include <openbabel/math/matrix3x3.h>
23
#include <openbabel/obutil.h>
24
25
using namespace std;
26
27
namespace OpenBabel
28
{
29
30
  /** \class matrix3x3 matrix3x3.h <openbabel/math/matrix3x3.h>
31
      \brief Represents a real 3x3 matrix.
32
33
      Rotating points in space can be performed by a vector-matrix
34
      multiplication. The matrix3x3 class is designed as a helper to the
35
      vector3 class for rotating points in space. The rotation matrix may be
36
      initialised by passing in the array of floating point values, by
37
      passing euler angles, or a rotation vector and angle of rotation about
38
      that vector. Once set, the matrix3x3 class can be used to rotate
39
      vectors by the overloaded multiplication operator. The following
40
      demonstrates the usage of the matrix3x3 class:
41
42
      \code
43
      matrix3x3 mat;
44
      mat.SetupRotMat(0.0,180.0,0.0); //rotate theta by 180 degrees
45
      vector3 v = VX;
46
      v *= mat; //apply the rotation
47
      \endcode
48
49
  */
50
51
  void matrix3x3::SetupRotMat(double phi,double theta,double psi)
52
0
  {
53
0
    double p  = phi * DEG_TO_RAD;
54
0
    double h  = theta * DEG_TO_RAD;
55
0
    double b  = psi * DEG_TO_RAD;
56
57
0
    double cx = cos(p);
58
0
    double sx = sin(p);
59
0
    double cy = cos(h);
60
0
    double sy = sin(h);
61
0
    double cz = cos(b);
62
0
    double sz = sin(b);
63
64
0
    ele[0][0] = cy*cz;
65
0
    ele[0][1] = cy*sz;
66
0
    ele[0][2] = -sy;
67
68
0
    ele[1][0] = sx*sy*cz-cx*sz;
69
0
    ele[1][1] = sx*sy*sz+cx*cz;
70
0
    ele[1][2] = sx*cy;
71
72
0
    ele[2][0] = cx*sy*cz+sx*sz;
73
0
    ele[2][1] = cx*sy*sz-sx*cz;
74
0
    ele[2][2] = cx*cy;
75
0
  }
76
77
  /*! Replaces *this with a matrix that represents reflection on
78
    the plane through 0 which is given by the normal vector norm.
79
80
    \warning If the vector norm has length zero, this method will
81
    generate the 0-matrix. If the length of the axis is close to
82
    zero, but not == 0.0, this method may behave in unexpected
83
    ways and return almost random results; details may depend on
84
    your particular floating point implementation. The use of this
85
    method is therefore highly discouraged, unless you are certain
86
    that the length is in a reasonable range, away from 0.0
87
    (Stefan Kebekus)
88
89
    \deprecated This method will probably replaced by a safer
90
    algorithm in the future.
91
92
    \todo Replace this method with a more fool-proof version.
93
94
    @param norm specifies the normal to the plane
95
  */
96
  OB_DEPRECATED
97
  void matrix3x3::PlaneReflection(const vector3 &norm)
98
0
  {
99
    //@@@ add a safety net
100
101
0
    vector3 normtmp = norm;
102
0
    normtmp.normalize();
103
104
0
    SetColumn(0, vector3(1,0,0) - 2*normtmp.x()*normtmp);
105
0
    SetColumn(1, vector3(0,1,0) - 2*normtmp.y()*normtmp);
106
0
    SetColumn(2, vector3(0,0,1) - 2*normtmp.z()*normtmp);
107
0
  }
108
109
  /*! Replaces *this with a matrix that represents rotation about the
110
    axis by a an angle.
111
112
    \warning If the vector axis has length zero, this method will
113
    generate the 0-matrix. If the length of the axis is close to
114
    zero, but not == 0.0, this method may behave in unexpected ways
115
    and return almost random results; details may depend on your
116
    particular floating point implementation. The use of this method
117
    is therefore highly discouraged, unless you are certain that the
118
    length is in a reasonable range, away from 0.0 (Stefan
119
    Kebekus)
120
121
    \deprecated This method will probably replaced by a safer
122
    algorithm in the future.
123
124
    \todo Replace this method with a more fool-proof version.
125
126
    @param v specifies the axis of the rotation
127
    @param angle angle in degrees (0..360)
128
  */
129
  OB_DEPRECATED
130
  void matrix3x3::RotAboutAxisByAngle(const vector3 &v,const double angle)
131
0
  {
132
0
    double theta = angle*DEG_TO_RAD;
133
0
    double s = sin(theta);
134
0
    double c = cos(theta);
135
0
    double t = 1 - c;
136
137
0
    vector3 vtmp = v;
138
0
    vtmp.normalize();
139
140
0
    double x = vtmp.x(),
141
0
           y = vtmp.y(),
142
0
           z = vtmp.z();
143
144
0
    ele[0][0] = t*x*x + c;
145
0
    ele[0][1] = t*x*y + s*z;
146
0
    ele[0][2] = t*x*z - s*y;
147
148
0
    ele[1][0] = t*x*y - s*z;
149
0
    ele[1][1] = t*y*y + c;
150
0
    ele[1][2] = t*y*z + s*x;
151
152
0
    ele[2][0] = t*x*z + s*y;
153
0
    ele[2][1] = t*y*z - s*x;
154
0
    ele[2][2] = t*z*z + c;
155
0
  }
156
157
  void matrix3x3::SetColumn(int col, const vector3 &v)
158
#ifdef OB_OLD_MATH_CHECKS
159
  throw(OBError)
160
#endif
161
0
  {
162
#ifdef OB_OLD_MATH_CHECKS
163
    if (col > 2)
164
      {
165
        OBError er("matrix3x3::SetColumn(int col, const vector3 &v)",
166
                   "The method was called with col > 2.",
167
                   "This is a programming error in your application.");
168
        throw er;
169
      }
170
#endif
171
172
0
    ele[0][col] = v.x();
173
0
    ele[1][col] = v.y();
174
0
    ele[2][col] = v.z();
175
0
  }
176
177
  void matrix3x3::SetRow(int row, const vector3 &v)
178
#ifdef OB_OLD_MATH_CHECKS
179
  throw(OBError)
180
#endif
181
0
  {
182
#ifdef OB_OLD_MATH_CHECKS
183
    if (row > 2)
184
      {
185
        OBError er("matrix3x3::SetRow(int row, const vector3 &v)",
186
                   "The method was called with row > 2.",
187
                   "This is a programming error in your application.");
188
        throw er;
189
      }
190
#endif
191
192
0
    ele[row][0] = v.x();
193
0
    ele[row][1] = v.y();
194
0
    ele[row][2] = v.z();
195
0
  }
196
197
  vector3 matrix3x3::GetColumn(unsigned int col) const
198
#ifdef OB_OLD_MATH_CHECKS
199
  throw(OBError)
200
#endif
201
0
  {
202
#ifdef OB_OLD_MATH_CHECKS
203
    if (col > 2)
204
      {
205
        OBError er("matrix3x3::GetColumn(unsigned int col) const",
206
                   "The method was called with col > 2.",
207
                   "This is a programming error in your application.");
208
        throw er;
209
      }
210
#endif
211
212
0
    return vector3(ele[0][col], ele[1][col], ele[2][col]);
213
0
  }
214
215
  vector3 matrix3x3::GetRow(unsigned int row) const
216
#ifdef OB_OLD_MATH_CHECKS
217
  throw(OBError)
218
#endif
219
0
  {
220
#ifdef OB_OLD_MATH_CHECKS
221
    if (row > 2)
222
      {
223
        OBError er("matrix3x3::GetRow(unsigned int row) const",
224
                   "The method was called with row > 2.",
225
                   "This is a programming error in your application.");
226
        throw er;
227
      }
228
#endif
229
230
0
    return vector3(ele[row][0], ele[row][1], ele[row][2]);
231
0
  }
232
233
  /*! Calculates the product m*v of the matrix m and the column
234
    vector represented by v
235
  */
236
  vector3 operator *(const matrix3x3 &m,const vector3 &v)
237
0
  {
238
0
    vector3 vv;
239
240
0
    vv.x() = v.x()*m.ele[0][0] + v.y()*m.ele[0][1] + v.z()*m.ele[0][2];
241
0
    vv.y() = v.x()*m.ele[1][0] + v.y()*m.ele[1][1] + v.z()*m.ele[1][2];
242
0
    vv.z() = v.x()*m.ele[2][0] + v.y()*m.ele[2][1] + v.z()*m.ele[2][2];
243
244
0
    return(vv);
245
0
  }
246
247
  matrix3x3 operator *(const matrix3x3 &A,const matrix3x3 &B)
248
0
  {
249
0
    matrix3x3 result;
250
251
0
    result.ele[0][0] = A.ele[0][0]*B.ele[0][0] + A.ele[0][1]*B.ele[1][0] + A.ele[0][2]*B.ele[2][0];
252
0
    result.ele[0][1] = A.ele[0][0]*B.ele[0][1] + A.ele[0][1]*B.ele[1][1] + A.ele[0][2]*B.ele[2][1];
253
0
    result.ele[0][2] = A.ele[0][0]*B.ele[0][2] + A.ele[0][1]*B.ele[1][2] + A.ele[0][2]*B.ele[2][2];
254
255
0
    result.ele[1][0] = A.ele[1][0]*B.ele[0][0] + A.ele[1][1]*B.ele[1][0] + A.ele[1][2]*B.ele[2][0];
256
0
    result.ele[1][1] = A.ele[1][0]*B.ele[0][1] + A.ele[1][1]*B.ele[1][1] + A.ele[1][2]*B.ele[2][1];
257
0
    result.ele[1][2] = A.ele[1][0]*B.ele[0][2] + A.ele[1][1]*B.ele[1][2] + A.ele[1][2]*B.ele[2][2];
258
259
0
    result.ele[2][0] = A.ele[2][0]*B.ele[0][0] + A.ele[2][1]*B.ele[1][0] + A.ele[2][2]*B.ele[2][0];
260
0
    result.ele[2][1] = A.ele[2][0]*B.ele[0][1] + A.ele[2][1]*B.ele[1][1] + A.ele[2][2]*B.ele[2][1];
261
0
    result.ele[2][2] = A.ele[2][0]*B.ele[0][2] + A.ele[2][1]*B.ele[1][2] + A.ele[2][2]*B.ele[2][2];
262
263
0
    return(result);
264
0
  }
265
266
  /*! calculates the product m*(*this) of the matrix m and the
267
    column vector represented by *this
268
  */
269
  vector3 &vector3::operator *= (const matrix3x3 &m)
270
0
  {
271
0
    vector3 vv;
272
273
0
    vv.SetX(x()*m.Get(0,0) + y()*m.Get(0,1) + z()*m.Get(0,2));
274
0
    vv.SetY(x()*m.Get(1,0) + y()*m.Get(1,1) + z()*m.Get(1,2));
275
0
    vv.SetZ(x()*m.Get(2,0) + y()*m.Get(2,1) + z()*m.Get(2,2));
276
0
    x() = vv.x();
277
0
    y() = vv.y();
278
0
    z() = vv.z();
279
280
0
    return(*this);
281
0
  }
282
283
  /*! This method checks if the absolute value of the determinant is smaller than 1e-6. If
284
    so, nothing is done and an exception is thrown. Otherwise, the
285
    inverse matrix is calculated and returned. *this is not changed.
286
287
    \warning If the determinant is close to zero, but not == 0.0,
288
    this method may behave in unexpected ways and return almost
289
    random results; details may depend on your particular floating
290
    point implementation. The use of this method is therefore highly
291
    discouraged, unless you are certain that the determinant is in a
292
    reasonable range, away from 0.0 (Stefan Kebekus)
293
  */
294
  matrix3x3 matrix3x3::inverse(void) const
295
#ifdef OB_OLD_MATH_CHECKS
296
  throw(OBError)
297
#endif
298
0
  {
299
0
    double det = determinant();
300
301
#ifdef OB_OLD_MATH_CHECKS
302
    if (fabs(det) <= 1e-6)
303
      {
304
        OBError er("matrix3x3::invert(void)",
305
                   "The method was called on a matrix with |determinant| <= 1e-6.",
306
                   "This is a runtime or a programming error in your application.");
307
        throw er;
308
      }
309
#endif
310
311
0
    matrix3x3 returnValue;
312
0
    returnValue.ele[0][0] = ele[1][1]*ele[2][2] - ele[1][2]*ele[2][1];
313
0
    returnValue.ele[1][0] = ele[1][2]*ele[2][0] - ele[1][0]*ele[2][2];
314
0
    returnValue.ele[2][0] = ele[1][0]*ele[2][1] - ele[1][1]*ele[2][0];
315
0
    returnValue.ele[0][1] = ele[2][1]*ele[0][2] - ele[2][2]*ele[0][1];
316
0
    returnValue.ele[1][1] = ele[2][2]*ele[0][0] - ele[2][0]*ele[0][2];
317
0
    returnValue.ele[2][1] = ele[2][0]*ele[0][1] - ele[2][1]*ele[0][0];
318
0
    returnValue.ele[0][2] = ele[0][1]*ele[1][2] - ele[0][2]*ele[1][1];
319
0
    returnValue.ele[1][2] = ele[0][2]*ele[1][0] - ele[0][0]*ele[1][2];
320
0
    returnValue.ele[2][2] = ele[0][0]*ele[1][1] - ele[0][1]*ele[1][0];
321
322
0
    returnValue /= det;
323
324
0
    return(returnValue);
325
0
  }
326
327
  /* This method returns the transpose of a matrix. The original
328
     matrix remains unchanged. */
329
  matrix3x3 matrix3x3::transpose(void) const
330
0
  {
331
0
    matrix3x3 returnValue;
332
333
0
    for(unsigned int i=0; i<3; i++)
334
0
      for(unsigned int j=0; j<3; j++)
335
0
        returnValue.ele[i][j] = ele[j][i];
336
337
0
    return(returnValue);
338
0
  }
339
340
  double matrix3x3::determinant(void) const
341
0
  {
342
0
    return( ele[0][0] * (ele[1][1] * ele[2][2] - ele[1][2] * ele[2][1])
343
0
          + ele[0][1] * (ele[1][2] * ele[2][0] - ele[1][0] * ele[2][2])
344
0
          + ele[0][2] * (ele[1][0] * ele[2][1] - ele[1][1] * ele[2][0]) );
345
0
  }
346
347
  /*! \return False if there are indices i,j such that
348
    fabs(*this[i][j]-*this[j][i]) > 1e-6. Otherwise, it returns
349
    true. */
350
  bool matrix3x3::isSymmetric(void) const
351
0
  {
352
0
    return( IsApprox( ele[0][1], ele[1][0], 1e-6 )
353
0
         && IsApprox( ele[0][2], ele[2][0], 1e-6 )
354
0
         && IsApprox( ele[1][2], ele[2][1], 1e-6 ) );
355
0
  }
356
357
  /*! This method returns true if and only if the matrix is
358
   * (approximately) a diagonal matrix. The precision used
359
   * by this function is 1e-6. */
360
  bool matrix3x3::isDiagonal(void) const
361
0
  {
362
0
    return( IsNegligible( ele[1][0], ele[0][0], 1e-6 )
363
0
         && IsNegligible( ele[2][0], ele[0][0], 1e-6 )
364
0
         && IsNegligible( ele[0][1], ele[1][1], 1e-6 )
365
0
         && IsNegligible( ele[2][1], ele[1][1], 1e-6 )
366
0
         && IsNegligible( ele[0][2], ele[2][2], 1e-6 )
367
0
         && IsNegligible( ele[1][2], ele[2][2], 1e-6 ) );
368
0
  }
369
370
  /*! This method returns true if and only if the matrix is
371
   * (approximately) equal to the identity matrix. The precision used
372
   * by this function is 1e-6. */
373
  bool matrix3x3::isUnitMatrix(void) const
374
0
  {
375
0
    return ( isDiagonal()
376
0
          && IsApprox( ele[0][0], 1.0, 1e-6 )
377
0
          && IsApprox( ele[1][1], 1.0, 1e-6 )
378
0
          && IsApprox( ele[2][2], 1.0, 1e-6 ) );
379
0
  }
380
381
  /*! This method employs the static method matrix3x3::jacobi(...)
382
    to find the eigenvalues and eigenvectors of a symmetric
383
    matrix. On entry it is checked if the matrix really is
384
    symmetric: if isSymmetric() returns 'false', an OBError is
385
    thrown.
386
387
    \note The jacobi algorithm is should work great for all
388
    symmetric 3x3 matrices. If you need to find the eigenvectors
389
    of a non-symmetric matrix, you might want to resort to the
390
    sophisticated routines of LAPACK.
391
392
    @param eigenvals a reference to a vector3 where the
393
    eigenvalues will be stored. The eigenvalues are ordered so
394
    that eigenvals[0] <= eigenvals[1] <= eigenvals[2].
395
396
    @return an orthogonal matrix whose ith column is an
397
    eigenvector for the eigenvalue eigenvals[i]. Here 'orthogonal'
398
    means that all eigenvectors have length one and are mutually
399
    orthogonal. The ith eigenvector can thus be conveniently
400
    accessed by the GetColumn() method, as in the following
401
    example.
402
    \code
403
    // Calculate eigenvectors and -values
404
    vector3 eigenvals;
405
    matrix3x3 eigenmatrix = somematrix.findEigenvectorsIfSymmetric(eigenvals);
406
407
    // Print the 2nd eigenvector
408
    cout << eigenmatrix.GetColumn(1) << endl;
409
    \endcode
410
    With these conventions, a matrix is diagonalized in the following way:
411
    \code
412
    // Diagonalize the matrix
413
    matrix3x3 diagonalMatrix = eigenmatrix.inverse() * somematrix * eigenmatrix;
414
    \endcode
415
416
  */
417
  matrix3x3 matrix3x3::findEigenvectorsIfSymmetric(vector3 &eigenvals) const
418
#ifdef OB_OLD_MATH_CHECKS
419
  throw(OBError)
420
#endif
421
0
  {
422
0
    matrix3x3 result;
423
424
#ifdef OB_OLD_MATH_CHECKS
425
    if (!isSymmetric())
426
      {
427
        OBError er("matrix3x3::findEigenvectorsIfSymmetric(vector3 &eigenvals) const throw(OBError)",
428
                   "The method was called on a matrix that was not symmetric, i.e. where isSymetric() == false.",
429
                   "This is a runtime or a programming error in your application.");
430
        throw er;
431
      }
432
#endif
433
434
0
    double d[3];
435
0
    matrix3x3 copyOfThis = *this;
436
437
0
    jacobi(3, copyOfThis.ele[0], d, result.ele[0]);
438
0
    eigenvals.Set(d);
439
440
0
    return result;
441
0
  }
442
443
0
  static inline double SQUARE( double x ) { return x*x; }
444
445
  void matrix3x3::FillOrth(double Alpha,double Beta, double Gamma,
446
                           double A, double B, double C)
447
0
  {
448
0
    double V;
449
450
0
    Alpha *= DEG_TO_RAD;
451
0
    Beta  *= DEG_TO_RAD;
452
0
    Gamma *= DEG_TO_RAD;
453
454
    // from the PDB specification:
455
    //  http://www.rcsb.org/pdb/docs/format/pdbguide2.2/part_75.html
456
457
458
    // since we'll ultimately divide by (a * b), we've factored those out here
459
0
    V = C * sqrt(1 - SQUARE(cos(Alpha)) - SQUARE(cos(Beta)) - SQUARE(cos(Gamma))
460
0
                 + 2 * cos(Alpha) * cos(Beta) * cos(Gamma));
461
462
0
    ele[0][0] = A;
463
0
    ele[0][1] = B*cos(Gamma);
464
0
    ele[0][2] = C*cos(Beta);
465
466
0
    ele[1][0] = 0.0;
467
0
    ele[1][1] = B*sin(Gamma);
468
0
    ele[1][2] = C*(cos(Alpha)-cos(Beta)*cos(Gamma))/sin(Gamma);
469
470
0
    ele[2][0] = 0.0;
471
0
    ele[2][1] = 0.0;
472
0
    ele[2][2] = V / (sin(Gamma)); // again, we factored out A * B when defining V
473
0
  }
474
475
  /** Print a text representation of the matrix in the standardized form:
476
      [ a, b, c ] <br>
477
      [ d, e, f ] <br>
478
      [ g, h, i ] <br>
479
      where the letters represent the appropriate entries in the matrix.
480
      Uses the standard output format for the individual entries, separated
481
      by ", " for each column, and [ ] indicating each row.
482
   **/
483
  ostream& operator<< ( ostream& co, const matrix3x3& m )
484
485
0
  {
486
0
    co << "[ "
487
0
       << m.ele[0][0]
488
0
       << ", "
489
0
       << m.ele[0][1]
490
0
       << ", "
491
0
       << m.ele[0][2]
492
0
       << " ]" << endl;
493
494
0
    co << "[ "
495
0
       << m.ele[1][0]
496
0
       << ", "
497
0
       << m.ele[1][1]
498
0
       << ", "
499
0
       << m.ele[1][2]
500
0
       << " ]" << endl;
501
502
0
    co << "[ "
503
0
       << m.ele[2][0]
504
0
       << ", "
505
0
       << m.ele[2][1]
506
0
       << ", "
507
0
       << m.ele[2][2]
508
0
       << " ]" << endl;
509
510
0
    return co ;
511
0
  }
512
513
  /*! This static function computes the eigenvalues and
514
    eigenvectors of a SYMMETRIC nxn matrix. This method is used
515
    internally by OpenBabel, but may be useful as a general
516
    eigenvalue finder.
517
518
    The algorithm uses Jacobi transformations. It is described
519
    e.g. in Wilkinson, Reinsch "Handbook for automatic computation,
520
    Volume II: Linear Algebra", part II, contribution II/1. The
521
    implementation is also similar to the implementation in this
522
    book. This method is adequate to solve the eigenproblem for
523
    small matrices, of size perhaps up to 10x10. For bigger
524
    problems, you might want to resort to the sophisticated routines
525
    of LAPACK.
526
527
    \note If you plan to find the eigenvalues of a symmetric 3x3
528
    matrix, you will probably prefer to use the more convenient
529
    method findEigenvectorsIfSymmetric()
530
531
    @param n the size of the matrix that should be diagonalized
532
533
    @param a array of size n^2 which holds the symmetric matrix
534
    whose eigenvectors are to be computed. The convention is that
535
    the entry in row r and column c is addressed as a[n*r+c] where,
536
    of course, 0 <= r < n and 0 <= c < n. There is no check that the
537
    matrix is actually symmetric. If it is not, the behaviour of
538
    this function is undefined.  On return, the matrix is
539
    overwritten with junk.
540
541
    @param d pointer to a field of at least n doubles which will be
542
    overwritten. On return of this function, the entries d[0]..d[n-1]
543
    will contain the eigenvalues of the matrix.
544
545
    @param v an array of size n^2 where the eigenvectors will be
546
    stored. On return, the columns of this matrix will contain the
547
    eigenvectors. The eigenvectors are normalized and mutually
548
    orthogonal.
549
  */
550
  void matrix3x3::jacobi(unsigned int n, double *a, double *d, double *v)
551
0
  {
552
0
    double onorm, dnorm;
553
0
    double b, dma, q, t, c, s;
554
0
    double  atemp, vtemp, dtemp;
555
0
    int i, j, k, l;
556
0
    int nrot;
557
558
0
    int MAX_SWEEPS=50;
559
560
    // Set v to the identity matrix, set the vector d to contain the
561
    // diagonal elements of the matrix a
562
0
    for (j = 0; j < static_cast<int>(n); j++)
563
0
      {
564
0
        for (i = 0; i < static_cast<int>(n); i++)
565
0
          v[n*i+j] = 0.0;
566
0
        v[n*j+j] = 1.0;
567
0
        d[j] = a[n*j+j];
568
0
      }
569
570
0
    nrot = MAX_SWEEPS;
571
0
    for (l = 1; l <= nrot; l++)
572
0
      {
573
        // Set dnorm to be the maximum norm of the diagonal elements, set
574
        // onorm to the maximum norm of the off-diagonal elements
575
0
        dnorm = 0.0;
576
0
        onorm = 0.0;
577
0
        for (j = 0; j < static_cast<int>(n); j++)
578
0
          {
579
0
            dnorm += (double)fabs(d[j]);
580
0
            for (i = 0; i < j; i++)
581
0
              onorm += (double)fabs(a[n*i+j]);
582
0
          }
583
        // Normal end point of this algorithm.
584
0
        if((onorm/dnorm) <= 1.0e-12)
585
0
          goto Exit_now;
586
587
0
        for (j = 1; j < static_cast<int>(n); j++)
588
0
          {
589
0
            for (i = 0; i <= j - 1; i++)
590
0
              {
591
592
0
                b = a[n*i+j];
593
0
                if(fabs(b) > 0.0)
594
0
                  {
595
0
                    dma = d[j] - d[i];
596
0
                    if((fabs(dma) + fabs(b)) <=  fabs(dma))
597
0
                      t = b / dma;
598
0
                    else
599
0
                      {
600
0
                        q = 0.5 * dma / b;
601
0
                        t = 1.0/((double)fabs(q) + (double)sqrt(1.0+q*q));
602
0
                        if (q < 0.0)
603
0
                          t = -t;
604
0
                      }
605
606
0
                    c = 1.0/(double)sqrt(t*t + 1.0);
607
0
                    s = t * c;
608
0
                    a[n*i+j] = 0.0;
609
610
0
                    for (k = 0; k <= i-1; k++)
611
0
                      {
612
0
                        atemp = c * a[n*k+i] - s * a[n*k+j];
613
0
                        a[n*k+j] = s * a[n*k+i] + c * a[n*k+j];
614
0
                        a[n*k+i] = atemp;
615
0
                      }
616
617
0
                    for (k = i+1; k <= j-1; k++)
618
0
                      {
619
0
                        atemp = c * a[n*i+k] - s * a[n*k+j];
620
0
                        a[n*k+j] = s * a[n*i+k] + c * a[n*k+j];
621
0
                        a[n*i+k] = atemp;
622
0
                      }
623
624
0
                    for (k = j+1; k < static_cast<int>(n); k++)
625
0
                      {
626
0
                        atemp = c * a[n*i+k] - s * a[n*j+k];
627
0
                        a[n*j+k] = s * a[n*i+k] + c * a[n*j+k];
628
0
                        a[n*i+k] = atemp;
629
0
                      }
630
631
0
                    for (k = 0; k < static_cast<int>(n); k++)
632
0
                      {
633
0
                        vtemp = c * v[n*k+i] - s * v[n*k+j];
634
0
                        v[n*k+j] = s * v[n*k+i] + c * v[n*k+j];
635
0
                        v[n*k+i] = vtemp;
636
0
                      }
637
638
0
                    dtemp = c*c*d[i] + s*s*d[j] - 2.0*c*s*b;
639
0
                    d[j] = s*s*d[i] + c*c*d[j] +  2.0*c*s*b;
640
0
                    d[i] = dtemp;
641
0
                  } /* end if */
642
0
              } /* end for i */
643
0
          } /* end for j */
644
0
      } /* end for l */
645
646
0
  Exit_now:
647
648
    // Now sort the eigenvalues (and the eigenvectors) so that the
649
    // smallest eigenvalues come first.
650
0
    nrot = l;
651
652
0
    for (j = 0; j < static_cast<int>(n)-1; j++)
653
0
      {
654
0
        k = j;
655
0
        dtemp = d[k];
656
0
        for (i = j+1; i < static_cast<int>(n); i++)
657
0
          if(d[i] < dtemp)
658
0
            {
659
0
              k = i;
660
0
              dtemp = d[k];
661
0
            }
662
663
0
        if(k > j)
664
0
          {
665
0
            d[k] = d[j];
666
0
            d[j] = dtemp;
667
0
            for (i = 0; i < static_cast<int>(n); i++)
668
0
              {
669
0
                dtemp = v[n*i+k];
670
0
                v[n*i+k] = v[n*i+j];
671
0
                v[n*i+j] = dtemp;
672
0
              }
673
0
          }
674
0
      }
675
0
  }
676
677
} // end namespace OpenBabel
678
679
//! \file matrix3x3.cpp
680
//! \brief Handle 3D rotation matrix.
681