ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/primitives/RigidBody.cpp
Revision: 2340
Committed: Mon Oct 3 14:31:31 2005 UTC (18 years, 9 months ago) by tim
File size: 14235 byte(s)
Log Message:
fix a bug in projecting the inertia tensor of directional atom in rigibody into rigidbody's body frame

File Contents

# Content
1 /*
2 * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3 *
4 * 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 * 1. Acknowledgement of the program authors must be made in any
10 * publication of scientific results based in part on use of the
11 * program. An acceptable form of acknowledgement is citation of
12 * the article in which the program was described (Matthew
13 * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14 * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15 * Parallel Simulation Engine for Molecular Dynamics,"
16 * J. Comput. Chem. 26, pp. 252-271 (2005))
17 *
18 * 2. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * 3. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the
24 * distribution.
25 *
26 * This software is provided "AS IS," without a warranty of any
27 * kind. All express or implied conditions, representations and
28 * warranties, including any implied warranty of merchantability,
29 * fitness for a particular purpose or non-infringement, are hereby
30 * excluded. The University of Notre Dame and its licensors shall not
31 * be liable for any damages suffered by licensee as a result of
32 * using, modifying or distributing the software or its
33 * derivatives. In no event will the University of Notre Dame or its
34 * licensors be liable for any lost revenue, profit or data, or for
35 * direct, indirect, special, consequential, incidental or punitive
36 * damages, however caused and regardless of the theory of liability,
37 * arising out of the use of or inability to use software, even if the
38 * University of Notre Dame has been advised of the possibility of
39 * such damages.
40 */
41 #include <algorithm>
42 #include <math.h>
43 #include "primitives/RigidBody.hpp"
44 #include "utils/simError.h"
45 #include "utils/NumericConstant.hpp"
46 namespace oopse {
47
48 RigidBody::RigidBody() : StuntDouble(otRigidBody, &Snapshot::rigidbodyData), inertiaTensor_(0.0){
49
50 }
51
52 void RigidBody::setPrevA(const RotMat3x3d& a) {
53 ((snapshotMan_->getPrevSnapshot())->*storage_).aMat[localIndex_] = a;
54 //((snapshotMan_->getPrevSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
55
56 for (int i =0 ; i < atoms_.size(); ++i){
57 if (atoms_[i]->isDirectional()) {
58 atoms_[i]->setPrevA(a * refOrients_[i]);
59 }
60 }
61
62 }
63
64
65 void RigidBody::setA(const RotMat3x3d& a) {
66 ((snapshotMan_->getCurrentSnapshot())->*storage_).aMat[localIndex_] = a;
67 //((snapshotMan_->getCurrentSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
68
69 for (int i =0 ; i < atoms_.size(); ++i){
70 if (atoms_[i]->isDirectional()) {
71 atoms_[i]->setA(a * refOrients_[i]);
72 }
73 }
74 }
75
76 void RigidBody::setA(const RotMat3x3d& a, int snapshotNo) {
77 ((snapshotMan_->getSnapshot(snapshotNo))->*storage_).aMat[localIndex_] = a;
78 //((snapshotMan_->getSnapshot(snapshotNo))->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
79
80 for (int i =0 ; i < atoms_.size(); ++i){
81 if (atoms_[i]->isDirectional()) {
82 atoms_[i]->setA(a * refOrients_[i], snapshotNo);
83 }
84 }
85
86 }
87
88 Mat3x3d RigidBody::getI() {
89 return inertiaTensor_;
90 }
91
92 std::vector<double> RigidBody::getGrad() {
93 std::vector<double> grad(6, 0.0);
94 Vector3d force;
95 Vector3d torque;
96 Vector3d myEuler;
97 double phi, theta, psi;
98 double cphi, sphi, ctheta, stheta;
99 Vector3d ephi;
100 Vector3d etheta;
101 Vector3d epsi;
102
103 force = getFrc();
104 torque =getTrq();
105 myEuler = getA().toEulerAngles();
106
107 phi = myEuler[0];
108 theta = myEuler[1];
109 psi = myEuler[2];
110
111 cphi = cos(phi);
112 sphi = sin(phi);
113 ctheta = cos(theta);
114 stheta = sin(theta);
115
116 // get unit vectors along the phi, theta and psi rotation axes
117
118 ephi[0] = 0.0;
119 ephi[1] = 0.0;
120 ephi[2] = 1.0;
121
122 etheta[0] = cphi;
123 etheta[1] = sphi;
124 etheta[2] = 0.0;
125
126 epsi[0] = stheta * cphi;
127 epsi[1] = stheta * sphi;
128 epsi[2] = ctheta;
129
130 //gradient is equal to -force
131 for (int j = 0 ; j<3; j++)
132 grad[j] = -force[j];
133
134 for (int j = 0; j < 3; j++ ) {
135
136 grad[3] += torque[j]*ephi[j];
137 grad[4] += torque[j]*etheta[j];
138 grad[5] += torque[j]*epsi[j];
139
140 }
141
142 return grad;
143 }
144
145 void RigidBody::accept(BaseVisitor* v) {
146 v->visit(this);
147 }
148
149 /**@todo need modification */
150 void RigidBody::calcRefCoords() {
151 double mtmp;
152 Vector3d refCOM(0.0);
153 mass_ = 0.0;
154 for (std::size_t i = 0; i < atoms_.size(); ++i) {
155 mtmp = atoms_[i]->getMass();
156 mass_ += mtmp;
157 refCOM += refCoords_[i]*mtmp;
158 }
159 refCOM /= mass_;
160
161 // Next, move the origin of the reference coordinate system to the COM:
162 for (std::size_t i = 0; i < atoms_.size(); ++i) {
163 refCoords_[i] -= refCOM;
164 }
165
166 // Moment of Inertia calculation
167 Mat3x3d Itmp(0.0);
168
169 for (std::size_t i = 0; i < atoms_.size(); i++) {
170 mtmp = atoms_[i]->getMass();
171 Itmp -= outProduct(refCoords_[i], refCoords_[i]) * mtmp;
172 double r2 = refCoords_[i].lengthSquare();
173 Itmp(0, 0) += mtmp * r2;
174 Itmp(1, 1) += mtmp * r2;
175 Itmp(2, 2) += mtmp * r2;
176 }
177
178 //project the inertial moment of directional atoms into this rigid body
179 for (std::size_t i = 0; i < atoms_.size(); i++) {
180 if (atoms_[i]->isDirectional()) {
181 Itmp += refOrients_[i].transpose() * atoms_[i]->getI() * refOrients_[i];
182 }
183 }
184
185 //diagonalize
186 Vector3d evals;
187 Mat3x3d::diagonalize(Itmp, evals, sU_);
188
189 // zero out I and then fill the diagonals with the moments of inertia:
190 inertiaTensor_(0, 0) = evals[0];
191 inertiaTensor_(1, 1) = evals[1];
192 inertiaTensor_(2, 2) = evals[2];
193
194 int nLinearAxis = 0;
195 for (int i = 0; i < 3; i++) {
196 if (fabs(evals[i]) < oopse::epsilon) {
197 linear_ = true;
198 linearAxis_ = i;
199 ++ nLinearAxis;
200 }
201 }
202
203 if (nLinearAxis > 1) {
204 sprintf( painCave.errMsg,
205 "RigidBody error.\n"
206 "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
207 "\tmoment of inertia. This can happen in one of three ways:\n"
208 "\t 1) Only one atom was specified, or \n"
209 "\t 2) All atoms were specified at the same location, or\n"
210 "\t 3) The programmers did something stupid.\n"
211 "\tIt is silly to use a rigid body to describe this situation. Be smarter.\n"
212 );
213 painCave.isFatal = 1;
214 simError();
215 }
216
217 }
218
219 void RigidBody::calcForcesAndTorques() {
220 Vector3d afrc;
221 Vector3d atrq;
222 Vector3d apos;
223 Vector3d rpos;
224 Vector3d frc(0.0);
225 Vector3d trq(0.0);
226 Vector3d pos = this->getPos();
227 for (int i = 0; i < atoms_.size(); i++) {
228
229 afrc = atoms_[i]->getFrc();
230 apos = atoms_[i]->getPos();
231 rpos = apos - pos;
232
233 frc += afrc;
234
235 trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
236 trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
237 trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
238
239 // If the atom has a torque associated with it, then we also need to
240 // migrate the torques onto the center of mass:
241
242 if (atoms_[i]->isDirectional()) {
243 atrq = atoms_[i]->getTrq();
244 trq += atrq;
245 }
246
247 }
248
249 setFrc(frc);
250 setTrq(trq);
251
252 }
253
254 void RigidBody::updateAtoms() {
255 unsigned int i;
256 Vector3d ref;
257 Vector3d apos;
258 DirectionalAtom* dAtom;
259 Vector3d pos = getPos();
260 RotMat3x3d a = getA();
261
262 for (i = 0; i < atoms_.size(); i++) {
263
264 ref = body2Lab(refCoords_[i]);
265
266 apos = pos + ref;
267
268 atoms_[i]->setPos(apos);
269
270 if (atoms_[i]->isDirectional()) {
271
272 dAtom = (DirectionalAtom *) atoms_[i];
273 dAtom->setA(refOrients_[i] * a);
274 }
275
276 }
277
278 }
279
280
281 void RigidBody::updateAtoms(int frame) {
282 unsigned int i;
283 Vector3d ref;
284 Vector3d apos;
285 DirectionalAtom* dAtom;
286 Vector3d pos = getPos(frame);
287 RotMat3x3d a = getA(frame);
288
289 for (i = 0; i < atoms_.size(); i++) {
290
291 ref = body2Lab(refCoords_[i], frame);
292
293 apos = pos + ref;
294
295 atoms_[i]->setPos(apos, frame);
296
297 if (atoms_[i]->isDirectional()) {
298
299 dAtom = (DirectionalAtom *) atoms_[i];
300 dAtom->setA(refOrients_[i] * a, frame);
301 }
302
303 }
304
305 }
306
307 void RigidBody::updateAtomVel() {
308 Mat3x3d skewMat;;
309
310 Vector3d ji = getJ();
311 Mat3x3d I = getI();
312
313 skewMat(0, 0) =0;
314 skewMat(0, 1) = ji[2] /I(2, 2);
315 skewMat(0, 2) = -ji[1] /I(1, 1);
316
317 skewMat(1, 0) = -ji[2] /I(2, 2);
318 skewMat(1, 1) = 0;
319 skewMat(1, 2) = ji[0]/I(0, 0);
320
321 skewMat(2, 0) =ji[1] /I(1, 1);
322 skewMat(2, 1) = -ji[0]/I(0, 0);
323 skewMat(2, 2) = 0;
324
325 Mat3x3d mat = (getA() * skewMat).transpose();
326 Vector3d rbVel = getVel();
327
328
329 Vector3d velRot;
330 for (int i =0 ; i < refCoords_.size(); ++i) {
331 atoms_[i]->setVel(rbVel + mat * refCoords_[i]);
332 }
333
334 }
335
336 void RigidBody::updateAtomVel(int frame) {
337 Mat3x3d skewMat;;
338
339 Vector3d ji = getJ(frame);
340 Mat3x3d I = getI();
341
342 skewMat(0, 0) =0;
343 skewMat(0, 1) = ji[2] /I(2, 2);
344 skewMat(0, 2) = -ji[1] /I(1, 1);
345
346 skewMat(1, 0) = -ji[2] /I(2, 2);
347 skewMat(1, 1) = 0;
348 skewMat(1, 2) = ji[0]/I(0, 0);
349
350 skewMat(2, 0) =ji[1] /I(1, 1);
351 skewMat(2, 1) = -ji[0]/I(0, 0);
352 skewMat(2, 2) = 0;
353
354 Mat3x3d mat = (getA(frame) * skewMat).transpose();
355 Vector3d rbVel = getVel(frame);
356
357
358 Vector3d velRot;
359 for (int i =0 ; i < refCoords_.size(); ++i) {
360 atoms_[i]->setVel(rbVel + mat * refCoords_[i], frame);
361 }
362
363 }
364
365
366
367 bool RigidBody::getAtomPos(Vector3d& pos, unsigned int index) {
368 if (index < atoms_.size()) {
369
370 Vector3d ref = body2Lab(refCoords_[index]);
371 pos = getPos() + ref;
372 return true;
373 } else {
374 std::cerr << index << " is an invalid index, current rigid body contains "
375 << atoms_.size() << "atoms" << std::endl;
376 return false;
377 }
378 }
379
380 bool RigidBody::getAtomPos(Vector3d& pos, Atom* atom) {
381 std::vector<Atom*>::iterator i;
382 i = std::find(atoms_.begin(), atoms_.end(), atom);
383 if (i != atoms_.end()) {
384 //RigidBody class makes sure refCoords_ and atoms_ match each other
385 Vector3d ref = body2Lab(refCoords_[i - atoms_.begin()]);
386 pos = getPos() + ref;
387 return true;
388 } else {
389 std::cerr << "Atom " << atom->getGlobalIndex()
390 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
391 return false;
392 }
393 }
394 bool RigidBody::getAtomVel(Vector3d& vel, unsigned int index) {
395
396 //velRot = $(A\cdot skew(I^{-1}j))^{T}refCoor$
397
398 if (index < atoms_.size()) {
399
400 Vector3d velRot;
401 Mat3x3d skewMat;;
402 Vector3d ref = refCoords_[index];
403 Vector3d ji = getJ();
404 Mat3x3d I = getI();
405
406 skewMat(0, 0) =0;
407 skewMat(0, 1) = ji[2] /I(2, 2);
408 skewMat(0, 2) = -ji[1] /I(1, 1);
409
410 skewMat(1, 0) = -ji[2] /I(2, 2);
411 skewMat(1, 1) = 0;
412 skewMat(1, 2) = ji[0]/I(0, 0);
413
414 skewMat(2, 0) =ji[1] /I(1, 1);
415 skewMat(2, 1) = -ji[0]/I(0, 0);
416 skewMat(2, 2) = 0;
417
418 velRot = (getA() * skewMat).transpose() * ref;
419
420 vel =getVel() + velRot;
421 return true;
422
423 } else {
424 std::cerr << index << " is an invalid index, current rigid body contains "
425 << atoms_.size() << "atoms" << std::endl;
426 return false;
427 }
428 }
429
430 bool RigidBody::getAtomVel(Vector3d& vel, Atom* atom) {
431
432 std::vector<Atom*>::iterator i;
433 i = std::find(atoms_.begin(), atoms_.end(), atom);
434 if (i != atoms_.end()) {
435 return getAtomVel(vel, i - atoms_.begin());
436 } else {
437 std::cerr << "Atom " << atom->getGlobalIndex()
438 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
439 return false;
440 }
441 }
442
443 bool RigidBody::getAtomRefCoor(Vector3d& coor, unsigned int index) {
444 if (index < atoms_.size()) {
445
446 coor = refCoords_[index];
447 return true;
448 } else {
449 std::cerr << index << " is an invalid index, current rigid body contains "
450 << atoms_.size() << "atoms" << std::endl;
451 return false;
452 }
453
454 }
455
456 bool RigidBody::getAtomRefCoor(Vector3d& coor, Atom* atom) {
457 std::vector<Atom*>::iterator i;
458 i = std::find(atoms_.begin(), atoms_.end(), atom);
459 if (i != atoms_.end()) {
460 //RigidBody class makes sure refCoords_ and atoms_ match each other
461 coor = refCoords_[i - atoms_.begin()];
462 return true;
463 } else {
464 std::cerr << "Atom " << atom->getGlobalIndex()
465 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
466 return false;
467 }
468
469 }
470
471
472 void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
473
474 Vector3d coords;
475 Vector3d euler;
476
477
478 atoms_.push_back(at);
479
480 if( !ats->havePosition() ){
481 sprintf( painCave.errMsg,
482 "RigidBody error.\n"
483 "\tAtom %s does not have a position specified.\n"
484 "\tThis means RigidBody cannot set up reference coordinates.\n",
485 ats->getType() );
486 painCave.isFatal = 1;
487 simError();
488 }
489
490 coords[0] = ats->getPosX();
491 coords[1] = ats->getPosY();
492 coords[2] = ats->getPosZ();
493
494 refCoords_.push_back(coords);
495
496 RotMat3x3d identMat = RotMat3x3d::identity();
497
498 if (at->isDirectional()) {
499
500 if( !ats->haveOrientation() ){
501 sprintf( painCave.errMsg,
502 "RigidBody error.\n"
503 "\tAtom %s does not have an orientation specified.\n"
504 "\tThis means RigidBody cannot set up reference orientations.\n",
505 ats->getType() );
506 painCave.isFatal = 1;
507 simError();
508 }
509
510 euler[0] = ats->getEulerPhi() * NumericConstant::PI /180.0;
511 euler[1] = ats->getEulerTheta() * NumericConstant::PI /180.0;
512 euler[2] = ats->getEulerPsi() * NumericConstant::PI /180.0;
513
514 RotMat3x3d Atmp(euler);
515 refOrients_.push_back(Atmp);
516
517 }else {
518 refOrients_.push_back(identMat);
519 }
520
521
522 }
523
524 }
525