ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/primitives/RigidBody.cpp
Revision: 1842
Committed: Tue Jan 29 19:10:04 2013 UTC (12 years, 3 months ago) by gezelter
File size: 16267 byte(s)
Log Message:
Only compute field for sites not excluded from the pairwise electrostatic contribution.
Also, now compute the mean field felt by the sites in a rigid body, and report that as
the rigid body's field.

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

Properties

Name Value
svn:keywords Author Id Revision Date