ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/primitives/RigidBody.cpp
Revision: 2345
Committed: Wed Oct 5 19:12:02 2005 UTC (18 years, 9 months ago) by tim
File size: 14343 byte(s)
Log Message:
fix a bug in creating cutoffGroup. When cutoffGroup is turned off, there is a mismatch between group and center of mass array

File Contents

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