ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/primitives/RigidBody.cpp
Revision: 1844
Committed: Wed Jan 30 14:43:08 2013 UTC (12 years, 3 months ago) by gezelter
File size: 16481 byte(s)
Log Message:
Only compute fields for electrostatic AtomTypes.

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;
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 afrc = atoms_[i]->getFrc();
294 apos = atoms_[i]->getPos();
295 rpos = apos - pos;
296
297 frc += afrc;
298
299 trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
300 trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
301 trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
302
303 // If the atom has a torque associated with it, then we also need to
304 // migrate the torques onto the center of mass:
305
306 if (atoms_[i]->isDirectional()) {
307 atrq = atoms_[i]->getTrq();
308 trq += atrq;
309 }
310 if ((sl & DataStorage::dslElectricField) && (atype->isElectrostatic())) {
311 ef += atoms_[i]->getElectricField();
312 eCount++;
313 }
314
315 tau_(0,0) -= rpos[0]*afrc[0];
316 tau_(0,1) -= rpos[0]*afrc[1];
317 tau_(0,2) -= rpos[0]*afrc[2];
318 tau_(1,0) -= rpos[1]*afrc[0];
319 tau_(1,1) -= rpos[1]*afrc[1];
320 tau_(1,2) -= rpos[1]*afrc[2];
321 tau_(2,0) -= rpos[2]*afrc[0];
322 tau_(2,1) -= rpos[2]*afrc[1];
323 tau_(2,2) -= rpos[2]*afrc[2];
324
325 }
326 addFrc(frc);
327 addTrq(trq);
328
329 if (sl & DataStorage::dslElectricField) {
330 ef /= eCount;
331 setElectricField(ef);
332 }
333
334 return tau_;
335 }
336
337 void RigidBody::updateAtoms() {
338 unsigned int i;
339 Vector3d ref;
340 Vector3d apos;
341 DirectionalAtom* dAtom;
342 Vector3d pos = getPos();
343 RotMat3x3d a = getA();
344
345 for (i = 0; i < atoms_.size(); i++) {
346
347 ref = body2Lab(refCoords_[i]);
348
349 apos = pos + ref;
350
351 atoms_[i]->setPos(apos);
352
353 if (atoms_[i]->isDirectional()) {
354
355 dAtom = (DirectionalAtom *) atoms_[i];
356 dAtom->setA(refOrients_[i].transpose() * a);
357 }
358
359 }
360
361 }
362
363
364 void RigidBody::updateAtoms(int frame) {
365 unsigned int i;
366 Vector3d ref;
367 Vector3d apos;
368 DirectionalAtom* dAtom;
369 Vector3d pos = getPos(frame);
370 RotMat3x3d a = getA(frame);
371
372 for (i = 0; i < atoms_.size(); i++) {
373
374 ref = body2Lab(refCoords_[i], frame);
375
376 apos = pos + ref;
377
378 atoms_[i]->setPos(apos, frame);
379
380 if (atoms_[i]->isDirectional()) {
381
382 dAtom = (DirectionalAtom *) atoms_[i];
383 dAtom->setA(refOrients_[i].transpose() * a, frame);
384 }
385
386 }
387
388 }
389
390 void RigidBody::updateAtomVel() {
391 Mat3x3d skewMat;;
392
393 Vector3d ji = getJ();
394 Mat3x3d I = getI();
395
396 skewMat(0, 0) =0;
397 skewMat(0, 1) = ji[2] /I(2, 2);
398 skewMat(0, 2) = -ji[1] /I(1, 1);
399
400 skewMat(1, 0) = -ji[2] /I(2, 2);
401 skewMat(1, 1) = 0;
402 skewMat(1, 2) = ji[0]/I(0, 0);
403
404 skewMat(2, 0) =ji[1] /I(1, 1);
405 skewMat(2, 1) = -ji[0]/I(0, 0);
406 skewMat(2, 2) = 0;
407
408 Mat3x3d mat = (getA() * skewMat).transpose();
409 Vector3d rbVel = getVel();
410
411
412 Vector3d velRot;
413 for (unsigned int i = 0 ; i < refCoords_.size(); ++i) {
414 atoms_[i]->setVel(rbVel + mat * refCoords_[i]);
415 }
416
417 }
418
419 void RigidBody::updateAtomVel(int frame) {
420 Mat3x3d skewMat;;
421
422 Vector3d ji = getJ(frame);
423 Mat3x3d I = getI();
424
425 skewMat(0, 0) =0;
426 skewMat(0, 1) = ji[2] /I(2, 2);
427 skewMat(0, 2) = -ji[1] /I(1, 1);
428
429 skewMat(1, 0) = -ji[2] /I(2, 2);
430 skewMat(1, 1) = 0;
431 skewMat(1, 2) = ji[0]/I(0, 0);
432
433 skewMat(2, 0) =ji[1] /I(1, 1);
434 skewMat(2, 1) = -ji[0]/I(0, 0);
435 skewMat(2, 2) = 0;
436
437 Mat3x3d mat = (getA(frame) * skewMat).transpose();
438 Vector3d rbVel = getVel(frame);
439
440
441 Vector3d velRot;
442 for (unsigned int i = 0 ; i < refCoords_.size(); ++i) {
443 atoms_[i]->setVel(rbVel + mat * refCoords_[i], frame);
444 }
445
446 }
447
448
449
450 bool RigidBody::getAtomPos(Vector3d& pos, unsigned int index) {
451 if (index < atoms_.size()) {
452
453 Vector3d ref = body2Lab(refCoords_[index]);
454 pos = getPos() + ref;
455 return true;
456 } else {
457 std::cerr << index << " is an invalid index, current rigid body contains "
458 << atoms_.size() << "atoms" << std::endl;
459 return false;
460 }
461 }
462
463 bool RigidBody::getAtomPos(Vector3d& pos, Atom* atom) {
464 std::vector<Atom*>::iterator i;
465 i = std::find(atoms_.begin(), atoms_.end(), atom);
466 if (i != atoms_.end()) {
467 //RigidBody class makes sure refCoords_ and atoms_ match each other
468 Vector3d ref = body2Lab(refCoords_[i - atoms_.begin()]);
469 pos = getPos() + ref;
470 return true;
471 } else {
472 std::cerr << "Atom " << atom->getGlobalIndex()
473 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
474 return false;
475 }
476 }
477 bool RigidBody::getAtomVel(Vector3d& vel, unsigned int index) {
478
479 //velRot = $(A\cdot skew(I^{-1}j))^{T}refCoor$
480
481 if (index < atoms_.size()) {
482
483 Vector3d velRot;
484 Mat3x3d skewMat;;
485 Vector3d ref = refCoords_[index];
486 Vector3d ji = getJ();
487 Mat3x3d I = getI();
488
489 skewMat(0, 0) =0;
490 skewMat(0, 1) = ji[2] /I(2, 2);
491 skewMat(0, 2) = -ji[1] /I(1, 1);
492
493 skewMat(1, 0) = -ji[2] /I(2, 2);
494 skewMat(1, 1) = 0;
495 skewMat(1, 2) = ji[0]/I(0, 0);
496
497 skewMat(2, 0) =ji[1] /I(1, 1);
498 skewMat(2, 1) = -ji[0]/I(0, 0);
499 skewMat(2, 2) = 0;
500
501 velRot = (getA() * skewMat).transpose() * ref;
502
503 vel =getVel() + velRot;
504 return true;
505
506 } else {
507 std::cerr << index << " is an invalid index, current rigid body contains "
508 << atoms_.size() << "atoms" << std::endl;
509 return false;
510 }
511 }
512
513 bool RigidBody::getAtomVel(Vector3d& vel, Atom* atom) {
514
515 std::vector<Atom*>::iterator i;
516 i = std::find(atoms_.begin(), atoms_.end(), atom);
517 if (i != atoms_.end()) {
518 return getAtomVel(vel, i - atoms_.begin());
519 } else {
520 std::cerr << "Atom " << atom->getGlobalIndex()
521 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
522 return false;
523 }
524 }
525
526 bool RigidBody::getAtomRefCoor(Vector3d& coor, unsigned int index) {
527 if (index < atoms_.size()) {
528
529 coor = refCoords_[index];
530 return true;
531 } else {
532 std::cerr << index << " is an invalid index, current rigid body contains "
533 << atoms_.size() << "atoms" << std::endl;
534 return false;
535 }
536
537 }
538
539 bool RigidBody::getAtomRefCoor(Vector3d& coor, Atom* atom) {
540 std::vector<Atom*>::iterator i;
541 i = std::find(atoms_.begin(), atoms_.end(), atom);
542 if (i != atoms_.end()) {
543 //RigidBody class makes sure refCoords_ and atoms_ match each other
544 coor = refCoords_[i - atoms_.begin()];
545 return true;
546 } else {
547 std::cerr << "Atom " << atom->getGlobalIndex()
548 <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
549 return false;
550 }
551
552 }
553
554
555 void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
556
557 Vector3d coords;
558 Vector3d euler;
559
560
561 atoms_.push_back(at);
562
563 if( !ats->havePosition() ){
564 sprintf( painCave.errMsg,
565 "RigidBody error.\n"
566 "\tAtom %s does not have a position specified.\n"
567 "\tThis means RigidBody cannot set up reference coordinates.\n",
568 ats->getType().c_str() );
569 painCave.isFatal = 1;
570 simError();
571 }
572
573 coords[0] = ats->getPosX();
574 coords[1] = ats->getPosY();
575 coords[2] = ats->getPosZ();
576
577 refCoords_.push_back(coords);
578
579 RotMat3x3d identMat = RotMat3x3d::identity();
580
581 if (at->isDirectional()) {
582
583 if( !ats->haveOrientation() ){
584 sprintf( painCave.errMsg,
585 "RigidBody error.\n"
586 "\tAtom %s does not have an orientation specified.\n"
587 "\tThis means RigidBody cannot set up reference orientations.\n",
588 ats->getType().c_str() );
589 painCave.isFatal = 1;
590 simError();
591 }
592
593 euler[0] = ats->getEulerPhi() * NumericConstant::PI /180.0;
594 euler[1] = ats->getEulerTheta() * NumericConstant::PI /180.0;
595 euler[2] = ats->getEulerPsi() * NumericConstant::PI /180.0;
596
597 RotMat3x3d Atmp(euler);
598 refOrients_.push_back(Atmp);
599
600 }else {
601 refOrients_.push_back(identMat);
602 }
603
604
605 }
606
607 }
608

Properties

Name Value
svn:keywords Author Id Revision Date