52#include "utils/Constants.hpp"
53#include "utils/simError.h"
57 RigidBody::RigidBody() :
61 ((snapshotMan_->getPrevSnapshot())->*storage_).aMat[localIndex_] = a;
63 for (
unsigned int i = 0; i < atoms_.size(); ++i) {
65 atoms_[i]->setPrevA(refOrients_[i].transpose() * a);
71 ((snapshotMan_->getCurrentSnapshot())->*storage_).aMat[localIndex_] = a;
73 for (
unsigned int i = 0; i < atoms_.size(); ++i) {
75 atoms_[i]->setA(refOrients_[i].transpose() * a);
81 ((snapshotMan_->getSnapshot(snapshotNo))->*storage_).aMat[localIndex_] = a;
83 for (
unsigned int i = 0; i < atoms_.size(); ++i) {
85 atoms_[i]->setA(refOrients_[i].transpose() * a, snapshotNo);
93 std::vector<RealType> grad(6, 0.0);
98 RealType cphi, sphi, ctheta, stheta;
106 myEuler =
getA().toEulerAngles();
116 if (fabs(stheta) < 1.0E-9) { stheta = 1.0E-9; }
118 ephi[0] = -sphi * ctheta / stheta;
119 ephi[1] = cphi * ctheta / stheta;
126 epsi[0] = sphi / stheta;
127 epsi[1] = -cphi / stheta;
131 for (
int j = 0; j < 3; j++)
134 for (
int j = 0; j < 3; j++) {
135 grad[3] -= torque[j] * ephi[j];
136 grad[4] -= torque[j] * etheta[j];
137 grad[5] -= torque[j] * epsi[j];
148 Vector3d refCOM(0.0);
150 for (std::size_t i = 0; i < atoms_.size(); ++i) {
151 mtmp = atoms_[i]->getMass();
153 refCOM += refCoords_[i] * mtmp;
155 refCOM_ = refCOM / mass_;
158 for (std::size_t i = 0; i < atoms_.size(); ++i) {
159 refCoords_[i] -= refCOM_;
164 for (std::size_t i = 0; i < atoms_.size(); i++) {
166 mtmp = atoms_[i]->getMass();
167 IAtom -= outProduct(refCoords_[i], refCoords_[i]) * mtmp;
168 RealType r2 = refCoords_[i].lengthSquare();
169 IAtom(0, 0) += mtmp * r2;
170 IAtom(1, 1) += mtmp * r2;
171 IAtom(2, 2) += mtmp * r2;
176 Itmp += refOrients_[i].transpose() * atoms_[i]->getI() * refOrients_[i];
185 inertiaTensor_(0, 0) = evals[0];
186 inertiaTensor_(1, 1) = evals[1];
187 inertiaTensor_(2, 2) = evals[2];
190 for (
int i = 0; i < 3; i++) {
191 if (fabs(evals[i]) < OpenMD::epsilon) {
198 if (nLinearAxis > 1) {
200 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
202 "\tOpenMD found more than one axis in this rigid body with a "
204 "\tmoment of inertia. This can happen in one of three ways:\n"
205 "\t 1) Only one atom was specified, or \n"
206 "\t 2) All atoms were specified at the same location, or\n"
207 "\t 3) The programmers did something stupid.\n"
208 "\tIt is silly to use a rigid body to describe this situation. Be "
210 painCave.isFatal = 1;
223 Vector3d pos = this->
getPos();
228 ((snapshotMan_->getCurrentSnapshot())->*storage_).getStorageLayout();
230 for (
unsigned int i = 0; i < atoms_.size(); i++) {
231 atype = atoms_[i]->getAtomType();
233 afrc = atoms_[i]->getFrc();
234 apos = atoms_[i]->getPos();
239 trq[0] += rpos[1] * afrc[2] - rpos[2] * afrc[1];
240 trq[1] += rpos[2] * afrc[0] - rpos[0] * afrc[2];
241 trq[2] += rpos[0] * afrc[1] - rpos[1] * afrc[0];
247 atrq = atoms_[i]->getTrq();
251 if ((sl & DataStorage::dslElectricField) && (atype->isElectrostatic())) {
252 ef += atoms_[i]->getElectricField();
259 if (sl & DataStorage::dslElectricField) {
277 Vector3d pos = this->
getPos();
281 ((snapshotMan_->getCurrentSnapshot())->*storage_).getStorageLayout();
283 for (
unsigned int i = 0; i < atoms_.size(); i++) {
284 atype = atoms_[i]->getAtomType();
286 afrc = atoms_[i]->getFrc();
287 apos = atoms_[i]->getPos();
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];
300 atrq = atoms_[i]->getTrq();
304 if ((sl & DataStorage::dslElectricField) && (atype->isElectrostatic())) {
305 ef += atoms_[i]->getElectricField();
309 tau_(0, 0) -= rpos[0] * afrc[0];
310 tau_(0, 1) -= rpos[0] * afrc[1];
311 tau_(0, 2) -= rpos[0] * afrc[2];
312 tau_(1, 0) -= rpos[1] * afrc[0];
313 tau_(1, 1) -= rpos[1] * afrc[1];
314 tau_(1, 2) -= rpos[1] * afrc[2];
315 tau_(2, 0) -= rpos[2] * afrc[0];
316 tau_(2, 1) -= rpos[2] * afrc[1];
317 tau_(2, 2) -= rpos[2] * afrc[2];
322 if (sl & DataStorage::dslElectricField) {
336 RotMat3x3d a =
getA();
338 for (i = 0; i < atoms_.size(); i++) {
343 atoms_[i]->setPos(apos);
347 dAtom->
setA(refOrients_[i].transpose() * a);
357 Vector3d pos = getPos(frame);
358 RotMat3x3d a = getA(frame);
360 for (i = 0; i < atoms_.size(); i++) {
361 ref = body2Lab(refCoords_[i], frame);
365 atoms_[i]->setPos(apos, frame);
367 if (atoms_[i]->isDirectional()) {
369 dAtom->
setA(refOrients_[i].transpose() * a, frame);
374 void RigidBody::updateAtomVel() {
377 Vector3d ji = getJ();
381 skewMat(0, 1) = ji[2] / I(2, 2);
382 skewMat(0, 2) = -ji[1] / I(1, 1);
384 skewMat(1, 0) = -ji[2] / I(2, 2);
386 skewMat(1, 2) = ji[0] / I(0, 0);
388 skewMat(2, 0) = ji[1] / I(1, 1);
389 skewMat(2, 1) = -ji[0] / I(0, 0);
392 Mat3x3d mat = (getA() * skewMat).transpose();
393 Vector3d rbVel = getVel();
396 for (
unsigned int i = 0; i < refCoords_.size(); ++i) {
397 atoms_[i]->setVel(rbVel + mat * refCoords_[i]);
401 void RigidBody::updateAtomVel(
int frame) {
405 Vector3d ji = getJ(frame);
409 skewMat(0, 1) = ji[2] / I(2, 2);
410 skewMat(0, 2) = -ji[1] / I(1, 1);
412 skewMat(1, 0) = -ji[2] / I(2, 2);
414 skewMat(1, 2) = ji[0] / I(0, 0);
416 skewMat(2, 0) = ji[1] / I(1, 1);
417 skewMat(2, 1) = -ji[0] / I(0, 0);
420 Mat3x3d mat = (getA(frame) * skewMat).transpose();
421 Vector3d rbVel = getVel(frame);
424 for (
unsigned int i = 0; i < refCoords_.size(); ++i) {
425 atoms_[i]->setVel(rbVel + mat * refCoords_[i], frame);
430 if (index < atoms_.size()) {
431 Vector3d ref =
body2Lab(refCoords_[index]);
436 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
437 "%d is an invalid index. The current rigid body contans %zu atoms.\n",
438 index, atoms_.size());
439 painCave.isFatal = 0;
446 std::vector<Atom*>::iterator i;
447 i = std::find(atoms_.begin(), atoms_.end(), atom);
448 if (i != atoms_.end()) {
450 Vector3d ref =
body2Lab(refCoords_[i - atoms_.begin()]);
454 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
455 "Atom %d does not belong to rigid body %d.\n",
457 painCave.isFatal = 0;
465 if (index < atoms_.size()) {
469 Vector3d ref = refCoords_[index];
470 Vector3d ji =
getJ();
474 skewMat(0, 1) = ji[2] / I(2, 2);
475 skewMat(0, 2) = -ji[1] / I(1, 1);
477 skewMat(1, 0) = -ji[2] / I(2, 2);
479 skewMat(1, 2) = ji[0] / I(0, 0);
481 skewMat(2, 0) = ji[1] / I(1, 1);
482 skewMat(2, 1) = -ji[0] / I(0, 0);
485 velRot = (
getA() * skewMat).transpose() * ref;
492 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
493 "Index %d is an invalid index, the current rigid body contains %zu "
495 index, atoms_.size());
496 painCave.isFatal = 0;
503 std::vector<Atom*>::iterator i;
504 i = std::find(atoms_.begin(), atoms_.end(), atom);
505 if (i != atoms_.end()) {
508 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
509 "Atom %d does not belong to rigid body %d.\n",
511 painCave.isFatal = 0;
518 if (index < atoms_.size()) {
519 coor = refCoords_[index];
523 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
524 "Index %d is an invalid index, the current rigid body contains %zu "
526 index, atoms_.size());
527 painCave.isFatal = 0;
534 std::vector<Atom*>::iterator i;
535 i = std::find(atoms_.begin(), atoms_.end(), atom);
536 if (i != atoms_.end()) {
538 coor = refCoords_[i - atoms_.begin()];
541 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
542 "Atom %d does not belong to rigid body %d.\n",
544 painCave.isFatal = 0;
554 atoms_.push_back(at);
556 if (!ats->havePosition()) {
557 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
559 "\tAtom %s does not have a position specified.\n"
560 "\tThis means RigidBody cannot set up reference coordinates.\n",
561 ats->getType().c_str());
562 painCave.isFatal = 1;
566 coords[0] = ats->getPosX();
567 coords[1] = ats->getPosY();
568 coords[2] = ats->getPosZ();
570 refCoords_.push_back(coords);
572 RotMat3x3d identMat = RotMat3x3d::identity();
574 if (at->isDirectional()) {
575 if (!ats->haveOrientation()) {
577 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
579 "\tAtom %s does not have an orientation specified.\n"
580 "\tThis means RigidBody cannot set up reference orientations.\n",
581 ats->getType().c_str());
582 painCave.isFatal = 1;
586 euler[0] = ats->getEulerPhi() * Constants::PI / 180.0;
587 euler[1] = ats->getEulerTheta() * Constants::PI / 180.0;
588 euler[2] = ats->getEulerPsi() * Constants::PI / 180.0;
590 RotMat3x3d Atmp(euler);
591 refOrients_.push_back(Atmp);
594 refOrients_.push_back(identMat);
AtomType is what OpenMD looks to for unchanging data about an atom.
virtual void setA(const RotMat3x3d &a)
Sets the current rotation matrix of this stuntdouble.
void calcRefCoords()
calculates the reference coordinates
virtual void setPrevA(const RotMat3x3d &a)
Sets the previous rotation matrix of this stuntdouble.
bool getAtomRefCoor(Vector3d &coor, unsigned int index)
Return the reference coordinate of atom which belongs to this rigid body.
virtual void setA(const RotMat3x3d &a)
Sets the current rotation matrix of this stuntdouble.
void updateAtoms()
update the positions of atoms belong to this rigidbody
virtual std::vector< RealType > getGrad()
Returns the gradient of this stuntdouble.
Mat3x3d calcForcesAndTorquesAndVirial()
Converts Atomic forces and torques to total forces and torques and computes the rigid body contributi...
virtual Mat3x3d getI()
Returns the inertia tensor of this stuntdouble.
void calcForcesAndTorques()
Converts Atomic forces and torques to total forces and torques.
virtual void accept(BaseVisitor *v)
bool getAtomPos(Vector3d &pos, unsigned int index)
Return the position of atom which belongs to this rigid body.
bool getAtomVel(Vector3d &vel, unsigned int index)
Return the velocity of atom which belongs to this rigid body.
The Snapshot class is a repository storing dynamic data during a Simulation.
"Don't move, or you're dead! Stand up! Captain, we've got them!"
Vector3d getTrq()
Returns the current torque of this stuntDouble.
RotMat3x3d getA()
Returns the current rotation matrix of this stuntDouble.
Vector3d getVel()
Returns the current velocity of this stuntDouble.
Vector3d getPos()
Returns the current position of this stuntDouble.
Vector3d body2Lab(const Vector3d &v)
Converts a body fixed vector to a lab fixed vector.
void setElectricField(const Vector3d &eField)
Sets the current electric field of this stuntDouble.
void addTrq(const Vector3d &trq)
Adds torque into the current torque of this stuntDouble.
Vector3d getJ()
Returns the current angular momentum of this stuntDouble (body -fixed).
int getGlobalIndex()
Returns the global index of this stuntDouble.
bool isDirectional()
Tests if this stuntDouble is a directional one.
Vector3d getFrc()
Returns the current force of this stuntDouble.
void addFrc(const Vector3d &frc)
Adds force into the current force of this stuntDouble.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.