ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/primitives/RigidBody.cpp
Revision: 1797
Committed: Mon Sep 10 20:58:00 2012 UTC (12 years, 7 months ago) by gezelter
File size: 15755 byte(s)
Log Message:
More linux compilation fixes

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

Properties

Name Value
svn:keywords Author Id Revision Date