ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/primitives/RigidBody.cpp
Revision: 1767
Committed: Fri Jul 6 22:01:58 2012 UTC (12 years, 9 months ago) by gezelter
File size: 15736 byte(s)
Log Message:
Various fixes required to compile OpenMD with the MS Visual C++ compiler

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

Properties

Name Value
svn:keywords Author Id Revision Date