ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/primitives/RigidBody.cpp
Revision: 2071
Committed: Sat Mar 7 21:41:51 2015 UTC (10 years, 1 month ago) by gezelter
File size: 16568 byte(s)
Log Message:
Reducing the number of warnings when using g++ to compile.

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

Properties

Name Value
svn:keywords Author Id Revision Date