ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/branches/new_design/OOPSE-3.0/src/primitives/RigidBody.cpp
Revision: 1870
Committed: Thu Dec 9 15:45:21 2004 UTC (19 years, 8 months ago) by tim
File size: 11510 byte(s)
Log Message:
Fix a bug in calculating torque in rigid body

File Contents

# Content
1 /*
2 * Copyright (C) 2000-2004 Object Oriented Parallel Simulation Engine (OOPSE) project
3 *
4 * Contact: oopse@oopse.org
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
10 * All we ask is that proper credit is given for our work, which includes
11 * - but is not limited to - adding the above copyright notice to the beginning
12 * of your source code files, and to any copyright notice that you may distribute
13 * with programs based on this work.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 *
24 */
25
26 #include "primitives/RigidBody.hpp"
27 #include "utils/simError.h"
28 namespace oopse {
29
30 RigidBody::RigidBody() : StuntDouble(otRigidBody, &Snapshot::rigidbodyData), inertiaTensor_(0.0){
31
32 }
33
34 void RigidBody::setPrevA(const RotMat3x3d& a) {
35 ((snapshotMan_->getPrevSnapshot())->*storage_).aMat[localIndex_] = a;
36 //((snapshotMan_->getPrevSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
37
38 //for (int i =0 ; i < atoms_.size(); ++i){
39 // if (atoms_[i]->isDirectional()) {
40 // atoms_[i]->setPrevA(a * refOrients_[i]);
41 // }
42 //}
43
44 }
45
46
47 void RigidBody::setA(const RotMat3x3d& a) {
48 ((snapshotMan_->getCurrentSnapshot())->*storage_).aMat[localIndex_] = a;
49 //((snapshotMan_->getCurrentSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
50
51 //for (int i =0 ; i < atoms_.size(); ++i){
52 // if (atoms_[i]->isDirectional()) {
53 // atoms_[i]->setA(a * refOrients_[i]);
54 // }
55 //}
56 }
57
58 void RigidBody::setA(const RotMat3x3d& a, int snapshotNo) {
59 ((snapshotMan_->getSnapshot(snapshotNo))->*storage_).aMat[localIndex_] = a;
60 //((snapshotMan_->getSnapshot(snapshotNo))->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
61
62 //for (int i =0 ; i < atoms_.size(); ++i){
63 // if (atoms_[i]->isDirectional()) {
64 // atoms_[i]->setA(a * refOrients_[i], snapshotNo);
65 // }
66 //}
67
68 }
69
70 Mat3x3d RigidBody::getI() {
71 return inertiaTensor_;
72 }
73
74 std::vector<double> RigidBody::getGrad() {
75 std::vector<double> grad(6, 0.0);
76 Vector3d force;
77 Vector3d torque;
78 Vector3d myEuler;
79 double phi, theta, psi;
80 double cphi, sphi, ctheta, stheta;
81 Vector3d ephi;
82 Vector3d etheta;
83 Vector3d epsi;
84
85 force = getFrc();
86 torque =getTrq();
87 myEuler = getA().toEulerAngles();
88
89 phi = myEuler[0];
90 theta = myEuler[1];
91 psi = myEuler[2];
92
93 cphi = cos(phi);
94 sphi = sin(phi);
95 ctheta = cos(theta);
96 stheta = sin(theta);
97
98 // get unit vectors along the phi, theta and psi rotation axes
99
100 ephi[0] = 0.0;
101 ephi[1] = 0.0;
102 ephi[2] = 1.0;
103
104 etheta[0] = cphi;
105 etheta[1] = sphi;
106 etheta[2] = 0.0;
107
108 epsi[0] = stheta * cphi;
109 epsi[1] = stheta * sphi;
110 epsi[2] = ctheta;
111
112 //gradient is equal to -force
113 for (int j = 0 ; j<3; j++)
114 grad[j] = -force[j];
115
116 for (int j = 0; j < 3; j++ ) {
117
118 grad[3] += torque[j]*ephi[j];
119 grad[4] += torque[j]*etheta[j];
120 grad[5] += torque[j]*epsi[j];
121
122 }
123
124 return grad;
125 }
126
127 void RigidBody::accept(BaseVisitor* v) {
128 v->visit(this);
129 }
130
131 /**@todo need modification */
132 void RigidBody::calcRefCoords() {
133 double mtmp;
134 Vector3d refCOM(0.0);
135 mass_ = 0.0;
136 for (int i = 0; i < atoms_.size(); ++i) {
137 mtmp = atoms_[i]->getMass();
138 mass_ += mtmp;
139 refCOM += refCoords_[i]*mtmp;
140 }
141 refCOM /= mass_;
142
143 // Next, move the origin of the reference coordinate system to the COM:
144 for (int i = 0; i < atoms_.size(); ++i) {
145 refCoords_[i] -= refCOM;
146 }
147
148 // Moment of Inertia calculation
149 Mat3x3d Itmp(0.0);
150
151 for (int i = 0; i < atoms_.size(); i++) {
152 mtmp = atoms_[i]->getMass();
153 Itmp -= outProduct(refCoords_[i], refCoords_[i]) * mtmp;
154 double r2 = refCoords_[i].lengthSquare();
155 Itmp(0, 0) += mtmp * r2;
156 Itmp(1, 1) += mtmp * r2;
157 Itmp(2, 2) += mtmp * r2;
158 }
159
160 //diagonalize
161 Vector3d evals;
162 Mat3x3d::diagonalize(Itmp, evals, sU_);
163
164 // zero out I and then fill the diagonals with the moments of inertia:
165 inertiaTensor_(0, 0) = evals[0];
166 inertiaTensor_(1, 1) = evals[1];
167 inertiaTensor_(2, 2) = evals[2];
168
169 int nLinearAxis = 0;
170 for (int i = 0; i < 3; i++) {
171 if (fabs(evals[i]) < oopse::epsilon) {
172 linear_ = true;
173 linearAxis_ = i;
174 ++ nLinearAxis;
175 }
176 }
177
178 if (nLinearAxis > 1) {
179 sprintf( painCave.errMsg,
180 "RigidBody error.\n"
181 "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
182 "\tmoment of inertia. This can happen in one of three ways:\n"
183 "\t 1) Only one atom was specified, or \n"
184 "\t 2) All atoms were specified at the same location, or\n"
185 "\t 3) The programmers did something stupid.\n"
186 "\tIt is silly to use a rigid body to describe this situation. Be smarter.\n"
187 );
188 painCave.isFatal = 1;
189 simError();
190 }
191
192 }
193
194 void RigidBody::calcForcesAndTorques() {
195 Vector3d afrc;
196 Vector3d atrq;
197 Vector3d apos;
198 Vector3d rpos;
199 Vector3d frc(0.0);
200 Vector3d trq(0.0);
201 Vector3d pos = this->getPos();
202 for (int i = 0; i < atoms_.size(); i++) {
203
204 afrc = atoms_[i]->getFrc();
205 apos = atoms_[i]->getPos();
206 rpos = apos - pos;
207
208 frc += afrc;
209
210 trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
211 trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
212 trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
213
214 // If the atom has a torque associated with it, then we also need to
215 // migrate the torques onto the center of mass:
216
217 if (atoms_[i]->isDirectional()) {
218 atrq = atoms_[i]->getTrq();
219 trq += atrq;
220 }
221
222 }
223
224 setFrc(frc);
225 setTrq(trq);
226
227 }
228
229 void RigidBody::updateAtoms() {
230 unsigned int i;
231 unsigned int j;
232 Vector3d ref;
233 Vector3d apos;
234 DirectionalAtom* dAtom;
235 Vector3d pos = getPos();
236 RotMat3x3d a = getA();
237
238 for (i = 0; i < atoms_.size(); i++) {
239
240 ref = body2Lab(refCoords_[i]);
241
242 apos = pos + ref;
243
244 atoms_[i]->setPos(apos);
245
246 if (atoms_[i]->isDirectional()) {
247
248 dAtom = (DirectionalAtom *) atoms_[i];
249 dAtom->setA(a * refOrients_[i]);
250 //dAtom->rotateBy( A );
251 }
252
253 }
254
255 }
256
257
258 bool RigidBody::getAtomPos(Vector3d& pos, unsigned int index) {
259 if (index < atoms_.size()) {
260
261 Vector3d ref = body2Lab(refCoords_[index]);
262 pos = getPos() + ref;
263 return true;
264 } else {
265 std::cerr << index << " is an invalid index, current rigid body contains "
266 << atoms_.size() << "atoms" << std::endl;
267 return false;
268 }
269 }
270
271 bool RigidBody::getAtomPos(Vector3d& pos, Atom* atom) {
272 std::vector<Atom*>::iterator i;
273 i = find(atoms_.begin(), atoms_.end(), atom);
274 if (i != atoms_.end()) {
275 //RigidBody class makes sure refCoords_ and atoms_ match each other
276 Vector3d ref = body2Lab(refCoords_[i - atoms_.begin()]);
277 pos = getPos() + ref;
278 return true;
279 } else {
280 std::cerr << "Atom " << atom->getGlobalIndex()
281 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
282 return false;
283 }
284 }
285 bool RigidBody::getAtomVel(Vector3d& vel, unsigned int index) {
286
287 //velRot = $(A\cdot skew(I^{-1}j))^{T}refCoor$
288
289 if (index < atoms_.size()) {
290
291 Vector3d velRot;
292 Mat3x3d skewMat;;
293 Vector3d ref = refCoords_[index];
294 Vector3d ji = getJ();
295 Mat3x3d I = getI();
296
297 skewMat(0, 0) =0;
298 skewMat(0, 1) = ji[2] /I(2, 2);
299 skewMat(0, 2) = -ji[1] /I(1, 1);
300
301 skewMat(1, 0) = -ji[2] /I(2, 2);
302 skewMat(1, 1) = 0;
303 skewMat(1, 2) = ji[0]/I(0, 0);
304
305 skewMat(2, 0) =ji[1] /I(1, 1);
306 skewMat(2, 1) = -ji[0]/I(0, 0);
307 skewMat(2, 2) = 0;
308
309 velRot = (getA() * skewMat).transpose() * ref;
310
311 vel =getVel() + velRot;
312 return true;
313
314 } else {
315 std::cerr << index << " is an invalid index, current rigid body contains "
316 << atoms_.size() << "atoms" << std::endl;
317 return false;
318 }
319 }
320
321 bool RigidBody::getAtomVel(Vector3d& vel, Atom* atom) {
322
323 std::vector<Atom*>::iterator i;
324 i = find(atoms_.begin(), atoms_.end(), atom);
325 if (i != atoms_.end()) {
326 return getAtomVel(vel, i - atoms_.begin());
327 } else {
328 std::cerr << "Atom " << atom->getGlobalIndex()
329 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
330 return false;
331 }
332 }
333
334 bool RigidBody::getAtomRefCoor(Vector3d& coor, unsigned int index) {
335 if (index < atoms_.size()) {
336
337 coor = refCoords_[index];
338 return true;
339 } else {
340 std::cerr << index << " is an invalid index, current rigid body contains "
341 << atoms_.size() << "atoms" << std::endl;
342 return false;
343 }
344
345 }
346
347 bool RigidBody::getAtomRefCoor(Vector3d& coor, Atom* atom) {
348 std::vector<Atom*>::iterator i;
349 i = find(atoms_.begin(), atoms_.end(), atom);
350 if (i != atoms_.end()) {
351 //RigidBody class makes sure refCoords_ and atoms_ match each other
352 coor = refCoords_[i - atoms_.begin()];
353 return true;
354 } else {
355 std::cerr << "Atom " << atom->getGlobalIndex()
356 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
357 return false;
358 }
359
360 }
361
362
363 void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
364
365 Vector3d coords;
366 Vector3d euler;
367
368
369 atoms_.push_back(at);
370
371 if( !ats->havePosition() ){
372 sprintf( painCave.errMsg,
373 "RigidBody error.\n"
374 "\tAtom %s does not have a position specified.\n"
375 "\tThis means RigidBody cannot set up reference coordinates.\n",
376 ats->getType() );
377 painCave.isFatal = 1;
378 simError();
379 }
380
381 coords[0] = ats->getPosX();
382 coords[1] = ats->getPosY();
383 coords[2] = ats->getPosZ();
384
385 refCoords_.push_back(coords);
386
387 RotMat3x3d identMat = RotMat3x3d::identity();
388
389 if (at->isDirectional()) {
390
391 if( !ats->haveOrientation() ){
392 sprintf( painCave.errMsg,
393 "RigidBody error.\n"
394 "\tAtom %s does not have an orientation specified.\n"
395 "\tThis means RigidBody cannot set up reference orientations.\n",
396 ats->getType() );
397 painCave.isFatal = 1;
398 simError();
399 }
400
401 euler[0] = ats->getEulerPhi();
402 euler[1] = ats->getEulerTheta();
403 euler[2] = ats->getEulerPsi();
404
405 RotMat3x3d Atmp(euler);
406 refOrients_.push_back(Atmp);
407
408 }else {
409 refOrients_.push_back(identMat);
410 }
411
412
413 }
414
415 }
416