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: 1809
Committed: Wed Dec 1 02:24:57 2004 UTC (19 years, 6 months ago) by tim
File size: 12148 byte(s)
Log Message:
minor fix

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