ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/primitives/RigidBody.cpp
Revision: 2002
Committed: Sun Feb 13 06:57:48 2005 UTC (19 years, 4 months ago) by tim
File size: 14695 byte(s)
Log Message:
adding dynamicProps

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