ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/SHAPES/RigidBody.cpp
Revision: 1276
Committed: Thu Jun 17 21:27:38 2004 UTC (20 years ago) by chrisfen
File size: 10978 byte(s)
Log Message:
Cleaned up unused variables.  Added findMaxExtent to RigidBody.cpp

File Contents

# User Rev Content
1 gezelter 1271 #include <math.h>
2     #include "RigidBody.hpp"
3     #include "VDWAtom.hpp"
4     #include "MatVec3.h"
5    
6     RigidBody::RigidBody() {
7     is_linear = false;
8     linear_axis = -1;
9     momIntTol = 1e-6;
10     }
11    
12     RigidBody::~RigidBody() {
13     }
14    
15     void RigidBody::addAtom(VDWAtom* at) {
16    
17     vec3 coords;
18    
19     myAtoms.push_back(at);
20    
21     at->getPos(coords.vec);
22     refCoords.push_back(coords);
23     }
24    
25     void RigidBody::getPos(double theP[3]){
26     for (int i = 0; i < 3 ; i++)
27     theP[i] = pos[i];
28     }
29    
30     void RigidBody::setPos(double theP[3]){
31     for (int i = 0; i < 3 ; i++)
32     pos[i] = theP[i];
33     }
34    
35    
36     void RigidBody::setEuler( double phi, double theta, double psi ){
37    
38     A[0][0] = (cos(phi) * cos(psi)) - (sin(phi) * cos(theta) * sin(psi));
39     A[0][1] = (sin(phi) * cos(psi)) + (cos(phi) * cos(theta) * sin(psi));
40     A[0][2] = sin(theta) * sin(psi);
41    
42     A[1][0] = -(cos(phi) * sin(psi)) - (sin(phi) * cos(theta) * cos(psi));
43     A[1][1] = -(sin(phi) * sin(psi)) + (cos(phi) * cos(theta) * cos(psi));
44     A[1][2] = sin(theta) * cos(psi);
45    
46     A[2][0] = sin(phi) * sin(theta);
47     A[2][1] = -cos(phi) * sin(theta);
48     A[2][2] = cos(theta);
49    
50     }
51    
52     void RigidBody::getQ( double q[4] ){
53    
54     double t, s;
55     double ad1, ad2, ad3;
56    
57     t = A[0][0] + A[1][1] + A[2][2] + 1.0;
58     if( t > 0.0 ){
59    
60     s = 0.5 / sqrt( t );
61     q[0] = 0.25 / s;
62     q[1] = (A[1][2] - A[2][1]) * s;
63     q[2] = (A[2][0] - A[0][2]) * s;
64     q[3] = (A[0][1] - A[1][0]) * s;
65     }
66     else{
67    
68     ad1 = fabs( A[0][0] );
69     ad2 = fabs( A[1][1] );
70     ad3 = fabs( A[2][2] );
71    
72     if( ad1 >= ad2 && ad1 >= ad3 ){
73    
74     s = 2.0 * sqrt( 1.0 + A[0][0] - A[1][1] - A[2][2] );
75     q[0] = (A[1][2] + A[2][1]) / s;
76     q[1] = 0.5 / s;
77     q[2] = (A[0][1] + A[1][0]) / s;
78     q[3] = (A[0][2] + A[2][0]) / s;
79     }
80     else if( ad2 >= ad1 && ad2 >= ad3 ){
81    
82     s = sqrt( 1.0 + A[1][1] - A[0][0] - A[2][2] ) * 2.0;
83     q[0] = (A[0][2] + A[2][0]) / s;
84     q[1] = (A[0][1] + A[1][0]) / s;
85     q[2] = 0.5 / s;
86     q[3] = (A[1][2] + A[2][1]) / s;
87     }
88     else{
89    
90     s = sqrt( 1.0 + A[2][2] - A[0][0] - A[1][1] ) * 2.0;
91     q[0] = (A[0][1] + A[1][0]) / s;
92     q[1] = (A[0][2] + A[2][0]) / s;
93     q[2] = (A[1][2] + A[2][1]) / s;
94     q[3] = 0.5 / s;
95     }
96     }
97     }
98    
99     void RigidBody::setQ( double the_q[4] ){
100    
101     double q0Sqr, q1Sqr, q2Sqr, q3Sqr;
102    
103     q0Sqr = the_q[0] * the_q[0];
104     q1Sqr = the_q[1] * the_q[1];
105     q2Sqr = the_q[2] * the_q[2];
106     q3Sqr = the_q[3] * the_q[3];
107    
108     A[0][0] = q0Sqr + q1Sqr - q2Sqr - q3Sqr;
109     A[0][1] = 2.0 * ( the_q[1] * the_q[2] + the_q[0] * the_q[3] );
110     A[0][2] = 2.0 * ( the_q[1] * the_q[3] - the_q[0] * the_q[2] );
111    
112     A[1][0] = 2.0 * ( the_q[1] * the_q[2] - the_q[0] * the_q[3] );
113     A[1][1] = q0Sqr - q1Sqr + q2Sqr - q3Sqr;
114     A[1][2] = 2.0 * ( the_q[2] * the_q[3] + the_q[0] * the_q[1] );
115    
116     A[2][0] = 2.0 * ( the_q[1] * the_q[3] + the_q[0] * the_q[2] );
117     A[2][1] = 2.0 * ( the_q[2] * the_q[3] - the_q[0] * the_q[1] );
118     A[2][2] = q0Sqr - q1Sqr -q2Sqr +q3Sqr;
119    
120     }
121    
122     void RigidBody::getA( double the_A[3][3] ){
123    
124     for (int i = 0; i < 3; i++)
125     for (int j = 0; j < 3; j++)
126     the_A[i][j] = A[i][j];
127    
128     }
129    
130     void RigidBody::setA( double the_A[3][3] ){
131    
132     for (int i = 0; i < 3; i++)
133     for (int j = 0; j < 3; j++)
134     A[i][j] = the_A[i][j];
135    
136     }
137    
138     void RigidBody::getI( double the_I[3][3] ){
139    
140     for (int i = 0; i < 3; i++)
141     for (int j = 0; j < 3; j++)
142     the_I[i][j] = I[i][j];
143    
144     }
145    
146     void RigidBody::lab2Body( double r[3] ){
147    
148     double rl[3]; // the lab frame vector
149    
150     rl[0] = r[0];
151     rl[1] = r[1];
152     rl[2] = r[2];
153    
154     r[0] = (A[0][0] * rl[0]) + (A[0][1] * rl[1]) + (A[0][2] * rl[2]);
155     r[1] = (A[1][0] * rl[0]) + (A[1][1] * rl[1]) + (A[1][2] * rl[2]);
156     r[2] = (A[2][0] * rl[0]) + (A[2][1] * rl[1]) + (A[2][2] * rl[2]);
157    
158     }
159    
160     void RigidBody::body2Lab( double r[3] ){
161    
162     double rb[3]; // the body frame vector
163    
164     rb[0] = r[0];
165     rb[1] = r[1];
166     rb[2] = r[2];
167    
168     r[0] = (A[0][0] * rb[0]) + (A[1][0] * rb[1]) + (A[2][0] * rb[2]);
169     r[1] = (A[0][1] * rb[0]) + (A[1][1] * rb[1]) + (A[2][1] * rb[2]);
170     r[2] = (A[0][2] * rb[0]) + (A[1][2] * rb[1]) + (A[2][2] * rb[2]);
171    
172     }
173    
174     void RigidBody::calcRefCoords( ) {
175    
176 chrisfen 1276 int i, j, it, n_linear_coords;
177 gezelter 1271 double mtmp;
178     vec3 apos;
179     double refCOM[3];
180     vec3 ptmp;
181     double Itmp[3][3];
182     double evals[3];
183     double r, r2, len;
184    
185     // First, find the center of mass:
186    
187     mass = 0.0;
188     for (j=0; j<3; j++)
189     refCOM[j] = 0.0;
190    
191     for (i = 0; i < myAtoms.size(); i++) {
192     mtmp = myAtoms[i]->getMass();
193     mass += mtmp;
194    
195     apos = refCoords[i];
196    
197     for(j = 0; j < 3; j++) {
198     refCOM[j] += apos[j]*mtmp;
199     }
200     }
201    
202     for(j = 0; j < 3; j++)
203     refCOM[j] /= mass;
204    
205     // Next, move the origin of the reference coordinate system to the COM:
206    
207     for (i = 0; i < myAtoms.size(); i++) {
208     apos = refCoords[i];
209     for (j=0; j < 3; j++) {
210     apos[j] = apos[j] - refCOM[j];
211     }
212     refCoords[i] = apos;
213     }
214    
215     // Moment of Inertia calculation
216    
217     for (i = 0; i < 3; i++)
218     for (j = 0; j < 3; j++)
219     Itmp[i][j] = 0.0;
220    
221     for (it = 0; it < myAtoms.size(); it++) {
222    
223     mtmp = myAtoms[it]->getMass();
224     ptmp = refCoords[it];
225     r= norm3(ptmp.vec);
226     r2 = r*r;
227    
228     for (i = 0; i < 3; i++) {
229     for (j = 0; j < 3; j++) {
230    
231     if (i==j) Itmp[i][j] += mtmp * r2;
232    
233     Itmp[i][j] -= mtmp * ptmp.vec[i]*ptmp.vec[j];
234     }
235     }
236     }
237    
238     diagonalize3x3(Itmp, evals, sU);
239    
240     // zero out I and then fill the diagonals with the moments of inertia:
241    
242     n_linear_coords = 0;
243    
244     for (i = 0; i < 3; i++) {
245     for (j = 0; j < 3; j++) {
246     I[i][j] = 0.0;
247     }
248     I[i][i] = evals[i];
249    
250     if (fabs(evals[i]) < momIntTol) {
251     is_linear = true;
252     n_linear_coords++;
253     linear_axis = i;
254     }
255     }
256    
257     if (n_linear_coords > 1) {
258     printf(
259     "RigidBody error.\n"
260     "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
261     "\tmoment of inertia. This can happen in one of three ways:\n"
262     "\t 1) Only one atom was specified, or \n"
263     "\t 2) All atoms were specified at the same location, or\n"
264     "\t 3) The programmers did something stupid.\n"
265     "\tIt is silly to use a rigid body to describe this situation. Be smarter.\n"
266     );
267     exit(-1);
268     }
269    
270     // renormalize column vectors:
271    
272     for (i=0; i < 3; i++) {
273     len = 0.0;
274     for (j = 0; j < 3; j++) {
275     len += sU[i][j]*sU[i][j];
276     }
277     len = sqrt(len);
278     for (j = 0; j < 3; j++) {
279     sU[i][j] /= len;
280     }
281     }
282     }
283    
284 chrisfen 1276 void RigidBody::doEulerToRotMat(double euler[3], double myA[3][3] ){
285 gezelter 1271
286     double phi, theta, psi;
287    
288     phi = euler[0];
289     theta = euler[1];
290     psi = euler[2];
291    
292     myA[0][0] = (cos(phi) * cos(psi)) - (sin(phi) * cos(theta) * sin(psi));
293     myA[0][1] = (sin(phi) * cos(psi)) + (cos(phi) * cos(theta) * sin(psi));
294     myA[0][2] = sin(theta) * sin(psi);
295    
296     myA[1][0] = -(cos(phi) * sin(psi)) - (sin(phi) * cos(theta) * cos(psi));
297     myA[1][1] = -(sin(phi) * sin(psi)) + (cos(phi) * cos(theta) * cos(psi));
298     myA[1][2] = sin(theta) * cos(psi);
299    
300     myA[2][0] = sin(phi) * sin(theta);
301     myA[2][1] = -cos(phi) * sin(theta);
302     myA[2][2] = cos(theta);
303    
304     }
305    
306     void RigidBody::updateAtoms() {
307     int i, j;
308     vec3 ref;
309     double apos[3];
310    
311     for (i = 0; i < myAtoms.size(); i++) {
312    
313     ref = refCoords[i];
314    
315     body2Lab(ref.vec);
316    
317     for (j = 0; j<3; j++)
318     apos[j] = pos[j] + ref.vec[j];
319    
320     myAtoms[i]->setPos(apos);
321    
322     }
323     }
324    
325     /**
326     * getEulerAngles computes a set of Euler angle values consistent
327     * with an input rotation matrix. They are returned in the following
328     * order:
329     * myEuler[0] = phi;
330     * myEuler[1] = theta;
331     * myEuler[2] = psi;
332     */
333     void RigidBody::getEulerAngles(double myEuler[3]) {
334    
335     // We use so-called "x-convention", which is the most common
336     // definition. In this convention, the rotation given by Euler
337     // angles (phi, theta, psi), where the first rotation is by an angle
338     // phi about the z-axis, the second is by an angle theta (0 <= theta
339     // <= 180) about the x-axis, and the third is by an angle psi about
340     // the z-axis (again).
341    
342    
343     double phi,theta,psi,eps;
344 chrisfen 1276 double ctheta;
345     double stheta;
346    
347 gezelter 1271 // set the tolerance for Euler angles and rotation elements
348    
349     eps = 1.0e-8;
350    
351     theta = acos(min(1.0,max(-1.0,A[2][2])));
352     ctheta = A[2][2];
353     stheta = sqrt(1.0 - ctheta * ctheta);
354    
355     // when sin(theta) is close to 0, we need to consider the
356     // possibility of a singularity. In this case, we can assign an
357     // arbitary value to phi (or psi), and then determine the psi (or
358     // phi) or vice-versa. We'll assume that phi always gets the
359     // rotation, and psi is 0 in cases of singularity. we use atan2
360     // instead of atan, since atan2 will give us -Pi to Pi. Since 0 <=
361     // theta <= 180, sin(theta) will be always non-negative. Therefore,
362     // it never changes the sign of both of the parameters passed to
363     // atan2.
364    
365     if (fabs(stheta) <= eps){
366     psi = 0.0;
367     phi = atan2(-A[1][0], A[0][0]);
368     }
369     // we only have one unique solution
370     else{
371     phi = atan2(A[2][0], -A[2][1]);
372     psi = atan2(A[0][2], A[1][2]);
373     }
374    
375     //wrap phi and psi, make sure they are in the range from 0 to 2*Pi
376     //if (phi < 0)
377     // phi += M_PI;
378    
379     //if (psi < 0)
380     // psi += M_PI;
381    
382     myEuler[0] = phi;
383     myEuler[1] = theta;
384     myEuler[2] = psi;
385    
386     return;
387     }
388    
389     double RigidBody::max(double x, double y) {
390     return (x > y) ? x : y;
391     }
392    
393     double RigidBody::min(double x, double y) {
394     return (x > y) ? y : x;
395     }
396    
397 chrisfen 1276 double RigidBody::findMaxExtent(){
398     int i;
399     double refAtomPos[3];
400     double maxExtent;
401     double tempExtent;
402    
403     //zero the extent variables
404     maxExtent = 0.0;
405     tempExtent = 0.0;
406     for (i=0; i<3; i++)
407     refAtomPos[i] = 0.0;
408    
409     //loop over all atoms
410     for (i=0; i<myAtoms.size(); i++){
411     getAtomRefCoor(refAtomPos, i);
412     tempExtent = sqrt(refAtomPos[0]*refAtomPos[0] + refAtomPos[1]*refAtomPos[1]
413     + refAtomPos[2]*refAtomPos[2]);
414     if (tempExtent > maxExtent)
415     maxExtent = tempExtent;
416     }
417     return maxExtent;
418     }
419    
420 gezelter 1271 void RigidBody::findCOM() {
421    
422     size_t i;
423     int j;
424     double mtmp;
425     double ptmp[3];
426 chrisfen 1276
427 gezelter 1271 for(j = 0; j < 3; j++) {
428     pos[j] = 0.0;
429     }
430     mass = 0.0;
431    
432     for (i = 0; i < myAtoms.size(); i++) {
433    
434     mtmp = myAtoms[i]->getMass();
435     myAtoms[i]->getPos(ptmp);
436    
437     mass += mtmp;
438    
439     for(j = 0; j < 3; j++) {
440     pos[j] += ptmp[j]*mtmp;
441     }
442    
443     }
444    
445     for(j = 0; j < 3; j++) {
446     pos[j] /= mass;
447     }
448    
449     }
450    
451     void RigidBody::getAtomPos(double theP[3], int index){
452     vec3 ref;
453    
454     if (index >= myAtoms.size())
455     printf( "%d is an invalid index, current rigid body contains "
456     "%d atoms\n", index, myAtoms.size());
457    
458     ref = refCoords[index];
459     body2Lab(ref.vec);
460    
461     theP[0] = pos[0] + ref[0];
462     theP[1] = pos[1] + ref[1];
463     theP[2] = pos[2] + ref[2];
464     }
465    
466    
467     void RigidBody::getAtomRefCoor(double pos[3], int index){
468     vec3 ref;
469    
470     ref = refCoords[index];
471     pos[0] = ref[0];
472     pos[1] = ref[1];
473     pos[2] = ref[2];
474    
475     }