ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/primitives/RigidBody.cpp
Revision: 1794
Committed: Thu Sep 6 19:44:06 2012 UTC (12 years, 7 months ago) by gezelter
File size: 15623 byte(s)
Log Message:
Merging some of the trunk changes back to the development branch,
cleaning up a datastorage bug

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

Properties

Name Value
svn:keywords Author Id Revision Date