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

# Content
1 #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 int i, j, it, n_linear_coords;
177 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 void RigidBody::doEulerToRotMat(double euler[3], double myA[3][3] ){
285
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 double ctheta;
345 double stheta;
346
347 // 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 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 void RigidBody::findCOM() {
421
422 size_t i;
423 int j;
424 double mtmp;
425 double ptmp[3];
426
427 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 }