ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/math/SquareMatrix3.hpp
Revision: 2000
Committed: Sat May 31 22:35:05 2014 UTC (10 years, 11 months ago) by gezelter
File size: 18721 byte(s)
Log Message:
Bug Fixes

File Contents

# User Rev Content
1 gezelter 507 /*
2 gezelter 246 * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3 tim 70 *
4 gezelter 246 * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9 gezelter 1390 * 1. Redistributions of source code must retain the above copyright
10 gezelter 246 * notice, this list of conditions and the following disclaimer.
11     *
12 gezelter 1390 * 2. Redistributions in binary form must reproduce the above copyright
13 gezelter 246 * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the
15     * distribution.
16     *
17     * This software is provided "AS IS," without a warranty of any
18     * kind. All express or implied conditions, representations and
19     * warranties, including any implied warranty of merchantability,
20     * fitness for a particular purpose or non-infringement, are hereby
21     * excluded. The University of Notre Dame and its licensors shall not
22     * be liable for any damages suffered by licensee as a result of
23     * using, modifying or distributing the software or its
24     * derivatives. In no event will the University of Notre Dame or its
25     * licensors be liable for any lost revenue, profit or data, or for
26     * direct, indirect, special, consequential, incidental or punitive
27     * damages, however caused and regardless of the theory of liability,
28     * arising out of the use of or inability to use software, even if the
29     * University of Notre Dame has been advised of the possibility of
30     * such damages.
31 gezelter 1390 *
32     * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33     * research, please cite the appropriate papers when you publish your
34     * work. Good starting points are:
35     *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37     * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 gezelter 1879 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
39 gezelter 1782 * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40     * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 tim 70 */
42 gezelter 246
43 tim 70 /**
44     * @file SquareMatrix3.hpp
45     * @author Teng Lin
46     * @date 10/11/2004
47     * @version 1.0
48     */
49 gezelter 507 #ifndef MATH_SQUAREMATRIX3_HPP
50 tim 99 #define MATH_SQUAREMATRIX3_HPP
51 gezelter 1782 #include "config.h"
52     #include <cmath>
53 tim 895 #include <vector>
54 tim 93 #include "Quaternion.hpp"
55 tim 70 #include "SquareMatrix.hpp"
56 tim 93 #include "Vector3.hpp"
57 tim 451 #include "utils/NumericConstant.hpp"
58 gezelter 1390 namespace OpenMD {
59 tim 70
60 gezelter 507 template<typename Real>
61     class SquareMatrix3 : public SquareMatrix<Real, 3> {
62     public:
63 tim 137
64 gezelter 507 typedef Real ElemType;
65     typedef Real* ElemPoinerType;
66 tim 70
67 gezelter 507 /** default constructor */
68     SquareMatrix3() : SquareMatrix<Real, 3>() {
69     }
70 tim 70
71 gezelter 507 /** Constructs and initializes every element of this matrix to a scalar */
72     SquareMatrix3(Real s) : SquareMatrix<Real,3>(s){
73     }
74 tim 151
75 gezelter 507 /** Constructs and initializes from an array */
76     SquareMatrix3(Real* array) : SquareMatrix<Real,3>(array){
77     }
78 tim 151
79    
80 gezelter 507 /** copy constructor */
81     SquareMatrix3(const SquareMatrix<Real, 3>& m) : SquareMatrix<Real, 3>(m) {
82     }
83 gezelter 246
84 gezelter 507 SquareMatrix3( const Vector3<Real>& eulerAngles) {
85     setupRotMat(eulerAngles);
86     }
87 tim 93
88 gezelter 507 SquareMatrix3(Real phi, Real theta, Real psi) {
89     setupRotMat(phi, theta, psi);
90     }
91 tim 93
92 gezelter 507 SquareMatrix3(const Quaternion<Real>& q) {
93     setupRotMat(q);
94 tim 113
95 gezelter 507 }
96 tim 93
97 gezelter 507 SquareMatrix3(Real w, Real x, Real y, Real z) {
98     setupRotMat(w, x, y, z);
99     }
100 tim 93
101 gezelter 507 /** copy assignment operator */
102     SquareMatrix3<Real>& operator =(const SquareMatrix<Real, 3>& m) {
103     if (this == &m)
104     return *this;
105     SquareMatrix<Real, 3>::operator=(m);
106     return *this;
107     }
108 tim 76
109 gezelter 246
110 gezelter 507 SquareMatrix3<Real>& operator =(const Quaternion<Real>& q) {
111     this->setupRotMat(q);
112     return *this;
113     }
114 gezelter 246
115 gezelter 1782
116 gezelter 507 /**
117     * Sets this matrix to a rotation matrix by three euler angles
118     * @ param euler
119     */
120     void setupRotMat(const Vector3<Real>& eulerAngles) {
121     setupRotMat(eulerAngles[0], eulerAngles[1], eulerAngles[2]);
122     }
123 tim 76
124 gezelter 507 /**
125     * Sets this matrix to a rotation matrix by three euler angles
126     * @param phi
127     * @param theta
128 gezelter 1879 * @param psi
129 gezelter 507 */
130     void setupRotMat(Real phi, Real theta, Real psi) {
131     Real sphi, stheta, spsi;
132     Real cphi, ctheta, cpsi;
133 tim 76
134 gezelter 507 sphi = sin(phi);
135     stheta = sin(theta);
136     spsi = sin(psi);
137     cphi = cos(phi);
138     ctheta = cos(theta);
139     cpsi = cos(psi);
140 tim 76
141 gezelter 507 this->data_[0][0] = cpsi * cphi - ctheta * sphi * spsi;
142     this->data_[0][1] = cpsi * sphi + ctheta * cphi * spsi;
143     this->data_[0][2] = spsi * stheta;
144 tim 93
145 gezelter 507 this->data_[1][0] = -spsi * ctheta - ctheta * sphi * cpsi;
146     this->data_[1][1] = -spsi * stheta + ctheta * cphi * cpsi;
147     this->data_[1][2] = cpsi * stheta;
148 tim 93
149 gezelter 507 this->data_[2][0] = stheta * sphi;
150     this->data_[2][1] = -stheta * cphi;
151     this->data_[2][2] = ctheta;
152     }
153 tim 93
154    
155 gezelter 507 /**
156     * Sets this matrix to a rotation matrix by quaternion
157     * @param quat
158     */
159     void setupRotMat(const Quaternion<Real>& quat) {
160     setupRotMat(quat.w(), quat.x(), quat.y(), quat.z());
161     }
162 tim 76
163 gezelter 507 /**
164     * Sets this matrix to a rotation matrix by quaternion
165     * @param w the first element
166     * @param x the second element
167     * @param y the third element
168     * @param z the fourth element
169     */
170     void setupRotMat(Real w, Real x, Real y, Real z) {
171     Quaternion<Real> q(w, x, y, z);
172     *this = q.toRotationMatrix3();
173     }
174 tim 76
175 tim 891 void setupSkewMat(Vector3<Real> v) {
176     setupSkewMat(v[0], v[1], v[2]);
177     }
178    
179     void setupSkewMat(Real v1, Real v2, Real v3) {
180     this->data_[0][0] = 0;
181     this->data_[0][1] = -v3;
182     this->data_[0][2] = v2;
183     this->data_[1][0] = v3;
184     this->data_[1][1] = 0;
185     this->data_[1][2] = -v1;
186     this->data_[2][0] = -v2;
187     this->data_[2][1] = v1;
188     this->data_[2][2] = 0;
189    
190    
191     }
192    
193    
194 gezelter 507 /**
195     * Returns the quaternion from this rotation matrix
196     * @return the quaternion from this rotation matrix
197     * @exception invalid rotation matrix
198     */
199     Quaternion<Real> toQuaternion() {
200     Quaternion<Real> q;
201     Real t, s;
202     Real ad1, ad2, ad3;
203     t = this->data_[0][0] + this->data_[1][1] + this->data_[2][2] + 1.0;
204 tim 76
205 tim 637 if( t > NumericConstant::epsilon ){
206 tim 93
207 gezelter 507 s = 0.5 / sqrt( t );
208     q[0] = 0.25 / s;
209     q[1] = (this->data_[1][2] - this->data_[2][1]) * s;
210     q[2] = (this->data_[2][0] - this->data_[0][2]) * s;
211     q[3] = (this->data_[0][1] - this->data_[1][0]) * s;
212     } else {
213 tim 93
214 tim 633 ad1 = this->data_[0][0];
215     ad2 = this->data_[1][1];
216     ad3 = this->data_[2][2];
217 tim 93
218 gezelter 507 if( ad1 >= ad2 && ad1 >= ad3 ){
219 tim 93
220 gezelter 507 s = 0.5 / sqrt( 1.0 + this->data_[0][0] - this->data_[1][1] - this->data_[2][2] );
221     q[0] = (this->data_[1][2] - this->data_[2][1]) * s;
222     q[1] = 0.25 / s;
223     q[2] = (this->data_[0][1] + this->data_[1][0]) * s;
224     q[3] = (this->data_[0][2] + this->data_[2][0]) * s;
225     } else if ( ad2 >= ad1 && ad2 >= ad3 ) {
226     s = 0.5 / sqrt( 1.0 + this->data_[1][1] - this->data_[0][0] - this->data_[2][2] );
227     q[0] = (this->data_[2][0] - this->data_[0][2] ) * s;
228     q[1] = (this->data_[0][1] + this->data_[1][0]) * s;
229     q[2] = 0.25 / s;
230     q[3] = (this->data_[1][2] + this->data_[2][1]) * s;
231     } else {
232 tim 93
233 gezelter 507 s = 0.5 / sqrt( 1.0 + this->data_[2][2] - this->data_[0][0] - this->data_[1][1] );
234     q[0] = (this->data_[0][1] - this->data_[1][0]) * s;
235     q[1] = (this->data_[0][2] + this->data_[2][0]) * s;
236     q[2] = (this->data_[1][2] + this->data_[2][1]) * s;
237     q[3] = 0.25 / s;
238     }
239     }
240 tim 93
241 gezelter 507 return q;
242 tim 93
243 gezelter 507 }
244 tim 93
245 gezelter 507 /**
246     * Returns the euler angles from this rotation matrix
247     * @return the euler angles in a vector
248     * @exception invalid rotation matrix
249     * We use so-called "x-convention", which is the most common definition.
250 cli2 1360 * In this convention, the rotation given by Euler angles (phi, theta,
251     * psi), where the first rotation is by an angle phi about the z-axis,
252     * the second is by an angle theta (0 <= theta <= 180) about the x-axis,
253     * and the third is by an angle psi about the z-axis (again).
254 gezelter 507 */
255     Vector3<Real> toEulerAngles() {
256     Vector3<Real> myEuler;
257     Real phi;
258     Real theta;
259     Real psi;
260     Real ctheta;
261     Real stheta;
262 tim 93
263 gezelter 507 // set the tolerance for Euler angles and rotation elements
264 tim 93
265 tim 963 theta = acos(std::min((RealType)1.0, std::max((RealType)-1.0,this->data_[2][2])));
266 gezelter 507 ctheta = this->data_[2][2];
267     stheta = sqrt(1.0 - ctheta * ctheta);
268 tim 93
269 cli2 1360 // when sin(theta) is close to 0, we need to consider
270     // singularity In this case, we can assign an arbitary value to
271     // phi (or psi), and then determine the psi (or phi) or
272     // vice-versa. We'll assume that phi always gets the rotation,
273     // and psi is 0 in cases of singularity.
274 gezelter 507 // we use atan2 instead of atan, since atan2 will give us -Pi to Pi.
275 cli2 1360 // Since 0 <= theta <= 180, sin(theta) will be always
276     // non-negative. Therefore, it will never change the sign of both of
277     // the parameters passed to atan2.
278 tim 93
279 cli2 1360 if (fabs(stheta) < 1e-6){
280 gezelter 507 psi = 0.0;
281     phi = atan2(-this->data_[1][0], this->data_[0][0]);
282     }
283     // we only have one unique solution
284     else{
285     phi = atan2(this->data_[2][0], -this->data_[2][1]);
286     psi = atan2(this->data_[0][2], this->data_[1][2]);
287     }
288 tim 93
289 gezelter 507 //wrap phi and psi, make sure they are in the range from 0 to 2*Pi
290     if (phi < 0)
291 cli2 1360 phi += 2.0 * M_PI;
292 tim 93
293 gezelter 507 if (psi < 0)
294 cli2 1360 psi += 2.0 * M_PI;
295 tim 93
296 gezelter 507 myEuler[0] = phi;
297     myEuler[1] = theta;
298     myEuler[2] = psi;
299 tim 93
300 gezelter 507 return myEuler;
301     }
302 tim 70
303 gezelter 507 /** Returns the determinant of this matrix. */
304     Real determinant() const {
305     Real x,y,z;
306 tim 101
307 gezelter 507 x = this->data_[0][0] * (this->data_[1][1] * this->data_[2][2] - this->data_[1][2] * this->data_[2][1]);
308     y = this->data_[0][1] * (this->data_[1][2] * this->data_[2][0] - this->data_[1][0] * this->data_[2][2]);
309     z = this->data_[0][2] * (this->data_[1][0] * this->data_[2][1] - this->data_[1][1] * this->data_[2][0]);
310 tim 101
311 gezelter 507 return(x + y + z);
312     }
313 gezelter 246
314 gezelter 507 /** Returns the trace of this matrix. */
315     Real trace() const {
316     return this->data_[0][0] + this->data_[1][1] + this->data_[2][2];
317     }
318 tim 101
319 gezelter 507 /**
320     * Sets the value of this matrix to the inversion of itself.
321     * @note since simple algorithm can be applied to inverse the 3 by 3 matrix, we hide the
322     * implementation of inverse in SquareMatrix class
323     */
324     SquareMatrix3<Real> inverse() const {
325     SquareMatrix3<Real> m;
326 tim 963 RealType det = determinant();
327 gezelter 1390 if (fabs(det) <= OpenMD::epsilon) {
328 gezelter 507 //"The method was called on a matrix with |determinant| <= 1e-6.",
329     //"This is a runtime or a programming error in your application.");
330 tim 895 std::vector<int> zeroDiagElementIndex;
331     for (int i =0; i < 3; ++i) {
332 gezelter 1390 if (fabs(this->data_[i][i]) <= OpenMD::epsilon) {
333 tim 895 zeroDiagElementIndex.push_back(i);
334     }
335     }
336 tim 70
337 tim 895 if (zeroDiagElementIndex.size() == 2) {
338     int index = zeroDiagElementIndex[0];
339     m(index, index) = 1.0 / this->data_[index][index];
340     }else if (zeroDiagElementIndex.size() == 1) {
341 tim 101
342 tim 895 int a = (zeroDiagElementIndex[0] + 1) % 3;
343     int b = (zeroDiagElementIndex[0] + 2) %3;
344 tim 963 RealType denom = this->data_[a][a] * this->data_[b][b] - this->data_[b][a]*this->data_[a][b];
345 tim 895 m(a, a) = this->data_[b][b] /denom;
346     m(b, a) = -this->data_[b][a]/denom;
347    
348     m(a,b) = -this->data_[a][b]/denom;
349     m(b, b) = this->data_[a][a]/denom;
350    
351     }
352    
353     /*
354     for(std::vector<int>::iterator iter = zeroDiagElementIndex.begin(); iter != zeroDiagElementIndex.end() ++iter) {
355 gezelter 1390 if (this->data_[*iter][0] > OpenMD::epsilon || this->data_[*iter][1] ||this->data_[*iter][2] ||
356     this->data_[0][*iter] > OpenMD::epsilon || this->data_[1][*iter] ||this->data_[2][*iter] ) {
357 tim 895 std::cout << "can not inverse matrix" << std::endl;
358     }
359     }
360     */
361     } else {
362    
363     m(0, 0) = this->data_[1][1]*this->data_[2][2] - this->data_[1][2]*this->data_[2][1];
364     m(1, 0) = this->data_[1][2]*this->data_[2][0] - this->data_[1][0]*this->data_[2][2];
365     m(2, 0) = this->data_[1][0]*this->data_[2][1] - this->data_[1][1]*this->data_[2][0];
366     m(0, 1) = this->data_[2][1]*this->data_[0][2] - this->data_[2][2]*this->data_[0][1];
367     m(1, 1) = this->data_[2][2]*this->data_[0][0] - this->data_[2][0]*this->data_[0][2];
368     m(2, 1) = this->data_[2][0]*this->data_[0][1] - this->data_[2][1]*this->data_[0][0];
369     m(0, 2) = this->data_[0][1]*this->data_[1][2] - this->data_[0][2]*this->data_[1][1];
370     m(1, 2) = this->data_[0][2]*this->data_[1][0] - this->data_[0][0]*this->data_[1][2];
371     m(2, 2) = this->data_[0][0]*this->data_[1][1] - this->data_[0][1]*this->data_[1][0];
372    
373     m /= det;
374     }
375 gezelter 507 return m;
376     }
377 tim 883
378     SquareMatrix3<Real> transpose() const{
379     SquareMatrix3<Real> result;
380    
381     for (unsigned int i = 0; i < 3; i++)
382     for (unsigned int j = 0; j < 3; j++)
383     result(j, i) = this->data_[i][j];
384    
385     return result;
386     }
387 gezelter 507 /**
388     * Extract the eigenvalues and eigenvectors from a 3x3 matrix.
389     * The eigenvectors (the columns of V) will be normalized.
390     * The eigenvectors are aligned optimally with the x, y, and z
391     * axes respectively.
392     * @param a symmetric matrix whose eigenvectors are to be computed. On return, the matrix is
393     * overwritten
394     * @param w will contain the eigenvalues of the matrix On return of this function
395     * @param v the columns of this matrix will contain the eigenvectors. The eigenvectors are
396     * normalized and mutually orthogonal.
397     * @warning a will be overwritten
398     */
399     static void diagonalize(SquareMatrix3<Real>& a, Vector3<Real>& w, SquareMatrix3<Real>& v);
400     };
401     /*=========================================================================
402 tim 76
403 tim 123 Program: Visualization Toolkit
404     Module: $RCSfile: SquareMatrix3.hpp,v $
405 tim 99
406 tim 123 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
407     All rights reserved.
408     See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
409 tim 101
410 gezelter 507 This software is distributed WITHOUT ANY WARRANTY; without even
411     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
412     PURPOSE. See the above copyright notice for more information.
413 tim 101
414 gezelter 507 =========================================================================*/
415     template<typename Real>
416     void SquareMatrix3<Real>::diagonalize(SquareMatrix3<Real>& a, Vector3<Real>& w,
417     SquareMatrix3<Real>& v) {
418     int i,j,k,maxI;
419     Real tmp, maxVal;
420     Vector3<Real> v_maxI, v_k, v_j;
421 tim 101
422 gezelter 507 // diagonalize using Jacobi
423 gezelter 1610 SquareMatrix3<Real>::jacobi(a, w, v);
424 gezelter 507 // if all the eigenvalues are the same, return identity matrix
425     if (w[0] == w[1] && w[0] == w[2] ) {
426     v = SquareMatrix3<Real>::identity();
427     return;
428     }
429 tim 101
430 gezelter 507 // transpose temporarily, it makes it easier to sort the eigenvectors
431     v = v.transpose();
432 tim 123
433 gezelter 507 // if two eigenvalues are the same, re-orthogonalize to optimally line
434     // up the eigenvectors with the x, y, and z axes
435     for (i = 0; i < 3; i++) {
436     if (w((i+1)%3) == w((i+2)%3)) {// two eigenvalues are the same
437     // find maximum element of the independant eigenvector
438     maxVal = fabs(v(i, 0));
439     maxI = 0;
440     for (j = 1; j < 3; j++) {
441     if (maxVal < (tmp = fabs(v(i, j)))){
442     maxVal = tmp;
443     maxI = j;
444     }
445     }
446 tim 123
447 gezelter 507 // swap the eigenvector into its proper position
448     if (maxI != i) {
449     tmp = w(maxI);
450     w(maxI) = w(i);
451     w(i) = tmp;
452 tim 101
453 gezelter 507 v.swapRow(i, maxI);
454     }
455     // maximum element of eigenvector should be positive
456     if (v(maxI, maxI) < 0) {
457     v(maxI, 0) = -v(maxI, 0);
458     v(maxI, 1) = -v(maxI, 1);
459     v(maxI, 2) = -v(maxI, 2);
460     }
461 tim 101
462 gezelter 507 // re-orthogonalize the other two eigenvectors
463     j = (maxI+1)%3;
464     k = (maxI+2)%3;
465 tim 101
466 gezelter 507 v(j, 0) = 0.0;
467     v(j, 1) = 0.0;
468     v(j, 2) = 0.0;
469     v(j, j) = 1.0;
470 tim 101
471 gezelter 507 /** @todo */
472     v_maxI = v.getRow(maxI);
473     v_j = v.getRow(j);
474     v_k = cross(v_maxI, v_j);
475     v_k.normalize();
476     v_j = cross(v_k, v_maxI);
477     v.setRow(j, v_j);
478     v.setRow(k, v_k);
479 tim 101
480    
481 gezelter 507 // transpose vectors back to columns
482     v = v.transpose();
483     return;
484     }
485     }
486 tim 101
487 gezelter 507 // the three eigenvalues are different, just sort the eigenvectors
488     // to align them with the x, y, and z axes
489 tim 101
490 gezelter 507 // find the vector with the largest x element, make that vector
491     // the first vector
492     maxVal = fabs(v(0, 0));
493     maxI = 0;
494     for (i = 1; i < 3; i++) {
495     if (maxVal < (tmp = fabs(v(i, 0)))) {
496     maxVal = tmp;
497     maxI = i;
498     }
499     }
500 tim 101
501 gezelter 507 // swap eigenvalue and eigenvector
502     if (maxI != 0) {
503     tmp = w(maxI);
504     w(maxI) = w(0);
505     w(0) = tmp;
506     v.swapRow(maxI, 0);
507     }
508     // do the same for the y element
509     if (fabs(v(1, 1)) < fabs(v(2, 1))) {
510     tmp = w(2);
511     w(2) = w(1);
512     w(1) = tmp;
513     v.swapRow(2, 1);
514     }
515 tim 101
516 gezelter 507 // ensure that the sign of the eigenvectors is correct
517     for (i = 0; i < 2; i++) {
518     if (v(i, i) < 0) {
519     v(i, 0) = -v(i, 0);
520     v(i, 1) = -v(i, 1);
521     v(i, 2) = -v(i, 2);
522     }
523     }
524 tim 70
525 gezelter 507 // set sign of final eigenvector to ensure that determinant is positive
526     if (v.determinant() < 0) {
527     v(2, 0) = -v(2, 0);
528     v(2, 1) = -v(2, 1);
529     v(2, 2) = -v(2, 2);
530 tim 123 }
531 gezelter 246
532 gezelter 507 // transpose the eigenvectors back again
533     v = v.transpose();
534     return ;
535     }
536 gezelter 246
537 gezelter 507 /**
538     * Return the multiplication of two matrixes (m1 * m2).
539     * @return the multiplication of two matrixes
540     * @param m1 the first matrix
541     * @param m2 the second matrix
542     */
543     template<typename Real>
544     inline SquareMatrix3<Real> operator *(const SquareMatrix3<Real>& m1, const SquareMatrix3<Real>& m2) {
545     SquareMatrix3<Real> result;
546 gezelter 246
547 gezelter 507 for (unsigned int i = 0; i < 3; i++)
548     for (unsigned int j = 0; j < 3; j++)
549     for (unsigned int k = 0; k < 3; k++)
550     result(i, j) += m1(i, k) * m2(k, j);
551 gezelter 246
552 gezelter 507 return result;
553     }
554 gezelter 246
555 gezelter 507 template<typename Real>
556     inline SquareMatrix3<Real> outProduct(const Vector3<Real>& v1, const Vector3<Real>& v2) {
557     SquareMatrix3<Real> result;
558    
559     for (unsigned int i = 0; i < 3; i++) {
560     for (unsigned int j = 0; j < 3; j++) {
561     result(i, j) = v1[i] * v2[j];
562     }
563     }
564 gezelter 246
565 gezelter 507 return result;
566     }
567 gezelter 246
568    
569 tim 963 typedef SquareMatrix3<RealType> Mat3x3d;
570     typedef SquareMatrix3<RealType> RotMat3x3d;
571 tim 93
572 gezelter 2000 const Mat3x3d M3Zero(0.0);
573    
574    
575 gezelter 1390 } //namespace OpenMD
576 tim 93 #endif // MATH_SQUAREMATRIX_HPP
577 tim 123

Properties

Name Value
svn:keywords Author Id Revision Date