ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/primitives/RigidBody.cpp
(Generate patch)

Comparing trunk/OOPSE-4/src/primitives/RigidBody.cpp (file contents):
Revision 1490 by gezelter, Fri Sep 24 04:16:43 2004 UTC vs.
Revision 1930 by gezelter, Wed Jan 12 22:41:40 2005 UTC

# Line 1 | Line 1
1 < #include <math.h>
2 < #include "RigidBody.hpp"
3 < #include "DirectionalAtom.hpp"
4 < #include "simError.h"
5 < #include "MatVec3.h"
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. Acknowledgement of the program authors must be made in any
10 > *    publication of scientific results based in part on use of the
11 > *    program.  An acceptable form of acknowledgement is citation of
12 > *    the article in which the program was described (Matthew
13 > *    A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14 > *    J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15 > *    Parallel Simulation Engine for Molecular Dynamics,"
16 > *    J. Comput. Chem. 26, pp. 252-271 (2005))
17 > *
18 > * 2. Redistributions of source code must retain the above copyright
19 > *    notice, this list of conditions and the following disclaimer.
20 > *
21 > * 3. Redistributions in binary form must reproduce the above copyright
22 > *    notice, this list of conditions and the following disclaimer in the
23 > *    documentation and/or other materials provided with the
24 > *    distribution.
25 > *
26 > * This software is provided "AS IS," without a warranty of any
27 > * kind. All express or implied conditions, representations and
28 > * warranties, including any implied warranty of merchantability,
29 > * fitness for a particular purpose or non-infringement, are hereby
30 > * excluded.  The University of Notre Dame and its licensors shall not
31 > * be liable for any damages suffered by licensee as a result of
32 > * using, modifying or distributing the software or its
33 > * derivatives. In no event will the University of Notre Dame or its
34 > * licensors be liable for any lost revenue, profit or data, or for
35 > * direct, indirect, special, consequential, incidental or punitive
36 > * damages, however caused and regardless of the theory of liability,
37 > * arising out of the use of or inability to use software, even if the
38 > * University of Notre Dame has been advised of the possibility of
39 > * such damages.
40 > */
41 > #include <algorithm>
42 > #include "primitives/RigidBody.hpp"
43 > #include "utils/simError.h"
44 > namespace oopse {
45  
46 < RigidBody::RigidBody() : StuntDouble() {
8 <  objType = OT_RIGIDBODY;
9 <  is_linear = false;
10 <  linear_axis =  -1;
11 <  momIntTol = 1e-6;
12 < }
46 > RigidBody::RigidBody() : StuntDouble(otRigidBody, &Snapshot::rigidbodyData), inertiaTensor_(0.0){
47  
14 RigidBody::~RigidBody() {
48   }
49  
50 < void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
50 > void RigidBody::setPrevA(const RotMat3x3d& a) {
51 >    ((snapshotMan_->getPrevSnapshot())->*storage_).aMat[localIndex_] = a;
52 >    //((snapshotMan_->getPrevSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
53  
54 <  vec3 coords;
55 <  vec3 euler;
56 <  mat3x3 Atmp;
54 >    for (int i =0 ; i < atoms_.size(); ++i){
55 >        if (atoms_[i]->isDirectional()) {
56 >            atoms_[i]->setPrevA(a * refOrients_[i]);
57 >        }
58 >    }
59  
60 <  myAtoms.push_back(at);
24 <
25 <  if( !ats->havePosition() ){
26 <    sprintf( painCave.errMsg,
27 <             "RigidBody error.\n"
28 <             "\tAtom %s does not have a position specified.\n"
29 <             "\tThis means RigidBody cannot set up reference coordinates.\n",
30 <             ats->getType() );
31 <    painCave.isFatal = 1;
32 <    simError();
33 <  }
34 <  
35 <  coords[0] = ats->getPosX();
36 <  coords[1] = ats->getPosY();
37 <  coords[2] = ats->getPosZ();
60 > }
61  
62 <  refCoords.push_back(coords);
63 <  
64 <  if (at->isDirectional()) {  
62 >      
63 > void RigidBody::setA(const RotMat3x3d& a) {
64 >    ((snapshotMan_->getCurrentSnapshot())->*storage_).aMat[localIndex_] = a;
65 >    //((snapshotMan_->getCurrentSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
66  
67 <    if( !ats->haveOrientation() ){
68 <      sprintf( painCave.errMsg,
69 <               "RigidBody error.\n"
70 <               "\tAtom %s does not have an orientation specified.\n"
71 <               "\tThis means RigidBody cannot set up reference orientations.\n",
72 <               ats->getType() );
49 <      painCave.isFatal = 1;
50 <      simError();
51 <    }    
67 >    for (int i =0 ; i < atoms_.size(); ++i){
68 >        if (atoms_[i]->isDirectional()) {
69 >            atoms_[i]->setA(a * refOrients_[i]);
70 >        }
71 >    }
72 > }    
73      
74 <    euler[0] = ats->getEulerPhi();
75 <    euler[1] = ats->getEulerTheta();
76 <    euler[2] = ats->getEulerPsi();
56 <    
57 <    doEulerToRotMat(euler, Atmp);
58 <    
59 <    refOrients.push_back(Atmp);
60 <    
61 <  }
62 < }
74 > void RigidBody::setA(const RotMat3x3d& a, int snapshotNo) {
75 >    ((snapshotMan_->getSnapshot(snapshotNo))->*storage_).aMat[localIndex_] = a;
76 >    //((snapshotMan_->getSnapshot(snapshotNo))->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;    
77  
78 < void RigidBody::getPos(double theP[3]){
79 <  for (int i = 0; i < 3 ; i++)
80 <    theP[i] = pos[i];
81 < }      
78 >    for (int i =0 ; i < atoms_.size(); ++i){
79 >        if (atoms_[i]->isDirectional()) {
80 >            atoms_[i]->setA(a * refOrients_[i], snapshotNo);
81 >        }
82 >    }
83  
84 < void RigidBody::setPos(double theP[3]){
70 <  for (int i = 0; i < 3 ; i++)
71 <    pos[i] = theP[i];
72 < }      
84 > }  
85  
86 < void RigidBody::getVel(double theV[3]){
87 <  for (int i = 0; i < 3 ; i++)
88 <    theV[i] = vel[i];
77 < }      
86 > Mat3x3d RigidBody::getI() {
87 >    return inertiaTensor_;
88 > }    
89  
90 < void RigidBody::setVel(double theV[3]){
91 <  for (int i = 0; i < 3 ; i++)
92 <    vel[i] = theV[i];
93 < }      
90 > std::vector<double> RigidBody::getGrad() {
91 >     std::vector<double> grad(6, 0.0);
92 >    Vector3d force;
93 >    Vector3d torque;
94 >    Vector3d myEuler;
95 >    double phi, theta, psi;
96 >    double cphi, sphi, ctheta, stheta;
97 >    Vector3d ephi;
98 >    Vector3d etheta;
99 >    Vector3d epsi;
100  
101 < void RigidBody::getFrc(double theF[3]){
102 <  for (int i = 0; i < 3 ; i++)
103 <    theF[i] = frc[i];
87 < }      
101 >    force = getFrc();
102 >    torque =getTrq();
103 >    myEuler = getA().toEulerAngles();
104  
105 < void RigidBody::addFrc(double theF[3]){
106 <  for (int i = 0; i < 3 ; i++)
107 <    frc[i] += theF[i];
105 >    phi = myEuler[0];
106 >    theta = myEuler[1];
107 >    psi = myEuler[2];
108 >
109 >    cphi = cos(phi);
110 >    sphi = sin(phi);
111 >    ctheta = cos(theta);
112 >    stheta = sin(theta);
113 >
114 >    // get unit vectors along the phi, theta and psi rotation axes
115 >
116 >    ephi[0] = 0.0;
117 >    ephi[1] = 0.0;
118 >    ephi[2] = 1.0;
119 >
120 >    etheta[0] = cphi;
121 >    etheta[1] = sphi;
122 >    etheta[2] = 0.0;
123 >
124 >    epsi[0] = stheta * cphi;
125 >    epsi[1] = stheta * sphi;
126 >    epsi[2] = ctheta;
127 >
128 >    //gradient is equal to -force
129 >    for (int j = 0 ; j<3; j++)
130 >        grad[j] = -force[j];
131 >
132 >    for (int j = 0; j < 3; j++ ) {
133 >
134 >        grad[3] += torque[j]*ephi[j];
135 >        grad[4] += torque[j]*etheta[j];
136 >        grad[5] += torque[j]*epsi[j];
137 >
138 >    }
139 >    
140 >    return grad;
141   }    
142  
143 < void RigidBody::zeroForces() {
143 > void RigidBody::accept(BaseVisitor* v) {
144 >    v->visit(this);
145 > }    
146  
147 <  for (int i = 0; i < 3; i++) {
148 <    frc[i] = 0.0;
149 <    trq[i] = 0.0;
150 <  }
147 > /**@todo need modification */
148 > void  RigidBody::calcRefCoords() {
149 >    double mtmp;
150 >    Vector3d refCOM(0.0);
151 >    mass_ = 0.0;
152 >    for (std::size_t i = 0; i < atoms_.size(); ++i) {
153 >        mtmp = atoms_[i]->getMass();
154 >        mass_ += mtmp;
155 >        refCOM += refCoords_[i]*mtmp;
156 >    }
157 >    refCOM /= mass_;
158  
159 < }
159 >    // Next, move the origin of the reference coordinate system to the COM:
160 >    for (std::size_t i = 0; i < atoms_.size(); ++i) {
161 >        refCoords_[i] -= refCOM;
162 >    }
163  
164 < void RigidBody::setEuler( double phi, double theta, double psi ){
164 > // Moment of Inertia calculation
165 >    Mat3x3d Itmp(0.0);
166    
167 <    A[0][0] = (cos(phi) * cos(psi)) - (sin(phi) * cos(theta) * sin(psi));
168 <    A[0][1] = (sin(phi) * cos(psi)) + (cos(phi) * cos(theta) * sin(psi));
169 <    A[0][2] = sin(theta) * sin(psi);
170 <    
171 <    A[1][0] = -(cos(phi) * sin(psi)) - (sin(phi) * cos(theta) * cos(psi));
172 <    A[1][1] = -(sin(phi) * sin(psi)) + (cos(phi) * cos(theta) * cos(psi));
173 <    A[1][2] = sin(theta) * cos(psi);
174 <    
175 <    A[2][0] = sin(phi) * sin(theta);
176 <    A[2][1] = -cos(phi) * sin(theta);
177 <    A[2][2] = cos(theta);
178 <
179 < }
180 <
181 < void RigidBody::getQ( double q[4] ){
182 <  
183 <  double t, s;
184 <  double ad1, ad2, ad3;
185 <    
186 <  t = A[0][0] + A[1][1] + A[2][2] + 1.0;
187 <  if( t > 0.0 ){
188 <    
189 <    s = 0.5 / sqrt( t );
190 <    q[0] = 0.25 / s;
191 <    q[1] = (A[1][2] - A[2][1]) * s;
192 <    q[2] = (A[2][0] - A[0][2]) * s;
193 <    q[3] = (A[0][1] - A[1][0]) * s;
194 <  }
195 <  else{
196 <    
197 <    ad1 = fabs( A[0][0] );
198 <    ad2 = fabs( A[1][1] );
199 <    ad3 = fabs( A[2][2] );
200 <    
201 <    if( ad1 >= ad2 && ad1 >= ad3 ){
202 <      
203 <      s = 2.0 * sqrt( 1.0 + A[0][0] - A[1][1] - A[2][2] );
204 <      q[0] = (A[1][2] + A[2][1]) / s;
205 <      q[1] = 0.5 / s;
144 <      q[2] = (A[0][1] + A[1][0]) / s;
145 <      q[3] = (A[0][2] + A[2][0]) / s;
167 >    for (std::size_t i = 0; i < atoms_.size(); i++) {
168 >        mtmp = atoms_[i]->getMass();
169 >        Itmp -= outProduct(refCoords_[i], refCoords_[i]) * mtmp;
170 >        double r2 = refCoords_[i].lengthSquare();
171 >        Itmp(0, 0) += mtmp * r2;
172 >        Itmp(1, 1) += mtmp * r2;
173 >        Itmp(2, 2) += mtmp * r2;
174 >    }
175 >
176 >    //diagonalize
177 >    Vector3d evals;
178 >    Mat3x3d::diagonalize(Itmp, evals, sU_);
179 >
180 >    // zero out I and then fill the diagonals with the moments of inertia:
181 >    inertiaTensor_(0, 0) = evals[0];
182 >    inertiaTensor_(1, 1) = evals[1];
183 >    inertiaTensor_(2, 2) = evals[2];
184 >        
185 >    int nLinearAxis = 0;
186 >    for (int i = 0; i < 3; i++) {    
187 >        if (fabs(evals[i]) < oopse::epsilon) {
188 >            linear_ = true;
189 >            linearAxis_ = i;
190 >            ++ nLinearAxis;
191 >        }
192 >    }
193 >
194 >    if (nLinearAxis > 1) {
195 >        sprintf( painCave.errMsg,
196 >            "RigidBody error.\n"
197 >            "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
198 >            "\tmoment of inertia.  This can happen in one of three ways:\n"
199 >            "\t 1) Only one atom was specified, or \n"
200 >            "\t 2) All atoms were specified at the same location, or\n"
201 >            "\t 3) The programmers did something stupid.\n"
202 >            "\tIt is silly to use a rigid body to describe this situation.  Be smarter.\n"
203 >            );
204 >        painCave.isFatal = 1;
205 >        simError();
206      }
207 <    else if( ad2 >= ad1 && ad2 >= ad3 ){
148 <      
149 <      s = sqrt( 1.0 + A[1][1] - A[0][0] - A[2][2] ) * 2.0;
150 <      q[0] = (A[0][2] + A[2][0]) / s;
151 <      q[1] = (A[0][1] + A[1][0]) / s;
152 <      q[2] = 0.5 / s;
153 <      q[3] = (A[1][2] + A[2][1]) / s;
154 <    }
155 <    else{
156 <      
157 <      s = sqrt( 1.0 + A[2][2] - A[0][0] - A[1][1] ) * 2.0;
158 <      q[0] = (A[0][1] + A[1][0]) / s;
159 <      q[1] = (A[0][2] + A[2][0]) / s;
160 <      q[2] = (A[1][2] + A[2][1]) / s;
161 <      q[3] = 0.5 / s;
162 <    }
163 <  }
207 >  
208   }
209  
210 < void RigidBody::setQ( double the_q[4] ){
210 > void  RigidBody::calcForcesAndTorques() {
211 >    Vector3d afrc;
212 >    Vector3d atrq;
213 >    Vector3d apos;
214 >    Vector3d rpos;
215 >    Vector3d frc(0.0);
216 >    Vector3d trq(0.0);
217 >    Vector3d pos = this->getPos();
218 >    for (int i = 0; i < atoms_.size(); i++) {
219  
220 <  double q0Sqr, q1Sqr, q2Sqr, q3Sqr;
221 <  
222 <  q0Sqr = the_q[0] * the_q[0];
223 <  q1Sqr = the_q[1] * the_q[1];
224 <  q2Sqr = the_q[2] * the_q[2];
173 <  q3Sqr = the_q[3] * the_q[3];
174 <  
175 <  A[0][0] = q0Sqr + q1Sqr - q2Sqr - q3Sqr;
176 <  A[0][1] = 2.0 * ( the_q[1] * the_q[2] + the_q[0] * the_q[3] );
177 <  A[0][2] = 2.0 * ( the_q[1] * the_q[3] - the_q[0] * the_q[2] );
178 <  
179 <  A[1][0] = 2.0 * ( the_q[1] * the_q[2] - the_q[0] * the_q[3] );
180 <  A[1][1] = q0Sqr - q1Sqr + q2Sqr - q3Sqr;
181 <  A[1][2] = 2.0 * ( the_q[2] * the_q[3] + the_q[0] * the_q[1] );
182 <  
183 <  A[2][0] = 2.0 * ( the_q[1] * the_q[3] + the_q[0] * the_q[2] );
184 <  A[2][1] = 2.0 * ( the_q[2] * the_q[3] - the_q[0] * the_q[1] );
185 <  A[2][2] = q0Sqr - q1Sqr -q2Sqr +q3Sqr;  
220 >        afrc = atoms_[i]->getFrc();
221 >        apos = atoms_[i]->getPos();
222 >        rpos = apos - pos;
223 >        
224 >        frc += afrc;
225  
226 < }
226 >        trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
227 >        trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
228 >        trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
229  
230 < void RigidBody::getA( double the_A[3][3] ){
231 <  
191 <  for (int i = 0; i < 3; i++)
192 <    for (int j = 0; j < 3; j++)
193 <      the_A[i][j] = A[i][j];
230 >        // If the atom has a torque associated with it, then we also need to
231 >        // migrate the torques onto the center of mass:
232  
233 +        if (atoms_[i]->isDirectional()) {
234 +            atrq = atoms_[i]->getTrq();
235 +            trq += atrq;
236 +        }
237 +        
238 +    }
239 +    
240 +    setFrc(frc);
241 +    setTrq(trq);
242 +    
243   }
244  
245 < void RigidBody::setA( double the_A[3][3] ){
245 > void  RigidBody::updateAtoms() {
246 >    unsigned int i;
247 >    Vector3d ref;
248 >    Vector3d apos;
249 >    DirectionalAtom* dAtom;
250 >    Vector3d pos = getPos();
251 >    RotMat3x3d a = getA();
252 >    
253 >    for (i = 0; i < atoms_.size(); i++) {
254 >    
255 >        ref = body2Lab(refCoords_[i]);
256  
257 <  for (int i = 0; i < 3; i++)
200 <    for (int j = 0; j < 3; j++)
201 <      A[i][j] = the_A[i][j];
202 <  
203 < }
257 >        apos = pos + ref;
258  
259 < void RigidBody::getJ( double theJ[3] ){
206 <  
207 <  for (int i = 0; i < 3; i++)
208 <    theJ[i] = ji[i];
259 >        atoms_[i]->setPos(apos);
260  
261 < }
261 >        if (atoms_[i]->isDirectional()) {
262 >          
263 >          dAtom = (DirectionalAtom *) atoms_[i];
264 >          dAtom->setA(a * refOrients_[i]);
265 >          //dAtom->rotateBy( A );      
266 >        }
267  
268 < void RigidBody::setJ( double theJ[3] ){
268 >    }
269    
214  for (int i = 0; i < 3; i++)
215    ji[i] = theJ[i];
216
270   }
271  
219 void RigidBody::getTrq(double theT[3]){
220  for (int i = 0; i < 3 ; i++)
221    theT[i] = trq[i];
222 }      
272  
273 < void RigidBody::addTrq(double theT[3]){
274 <  for (int i = 0; i < 3 ; i++)
226 <    trq[i] += theT[i];
227 < }      
273 > bool RigidBody::getAtomPos(Vector3d& pos, unsigned int index) {
274 >    if (index < atoms_.size()) {
275  
276 < void RigidBody::getI( double the_I[3][3] ){  
276 >        Vector3d ref = body2Lab(refCoords_[index]);
277 >        pos = getPos() + ref;
278 >        return true;
279 >    } else {
280 >        std::cerr << index << " is an invalid index, current rigid body contains "
281 >                      << atoms_.size() << "atoms" << std::endl;
282 >        return false;
283 >    }    
284 > }
285  
286 <    for (int i = 0; i < 3; i++)
287 <      for (int j = 0; j < 3; j++)
288 <        the_I[i][j] = I[i][j];
289 <
286 > bool RigidBody::getAtomPos(Vector3d& pos, Atom* atom) {
287 >    std::vector<Atom*>::iterator i;
288 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
289 >    if (i != atoms_.end()) {
290 >        //RigidBody class makes sure refCoords_ and atoms_ match each other
291 >        Vector3d ref = body2Lab(refCoords_[i - atoms_.begin()]);
292 >        pos = getPos() + ref;
293 >        return true;
294 >    } else {
295 >        std::cerr << "Atom " << atom->getGlobalIndex()
296 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
297 >        return false;
298 >    }
299   }
300 + bool RigidBody::getAtomVel(Vector3d& vel, unsigned int index) {
301  
302 < void RigidBody::lab2Body( double r[3] ){
302 >    //velRot = $(A\cdot skew(I^{-1}j))^{T}refCoor$
303  
304 <  double rl[3]; // the lab frame vector
240 <  
241 <  rl[0] = r[0];
242 <  rl[1] = r[1];
243 <  rl[2] = r[2];
244 <  
245 <  r[0] = (A[0][0] * rl[0]) + (A[0][1] * rl[1]) + (A[0][2] * rl[2]);
246 <  r[1] = (A[1][0] * rl[0]) + (A[1][1] * rl[1]) + (A[1][2] * rl[2]);
247 <  r[2] = (A[2][0] * rl[0]) + (A[2][1] * rl[1]) + (A[2][2] * rl[2]);
304 >    if (index < atoms_.size()) {
305  
306 < }
306 >        Vector3d velRot;
307 >        Mat3x3d skewMat;;
308 >        Vector3d ref = refCoords_[index];
309 >        Vector3d ji = getJ();
310 >        Mat3x3d I =  getI();
311  
312 < void RigidBody::body2Lab( double r[3] ){
312 >        skewMat(0, 0) =0;
313 >        skewMat(0, 1) = ji[2] /I(2, 2);
314 >        skewMat(0, 2) = -ji[1] /I(1, 1);
315  
316 <  double rb[3]; // the body frame vector
317 <  
318 <  rb[0] = r[0];
256 <  rb[1] = r[1];
257 <  rb[2] = r[2];
258 <  
259 <  r[0] = (A[0][0] * rb[0]) + (A[1][0] * rb[1]) + (A[2][0] * rb[2]);
260 <  r[1] = (A[0][1] * rb[0]) + (A[1][1] * rb[1]) + (A[2][1] * rb[2]);
261 <  r[2] = (A[0][2] * rb[0]) + (A[1][2] * rb[1]) + (A[2][2] * rb[2]);
316 >        skewMat(1, 0) = -ji[2] /I(2, 2);
317 >        skewMat(1, 1) = 0;
318 >        skewMat(1, 2) = ji[0]/I(0, 0);
319  
320 < }
320 >        skewMat(2, 0) =ji[1] /I(1, 1);
321 >        skewMat(2, 1) = -ji[0]/I(0, 0);
322 >        skewMat(2, 2) = 0;
323  
324 < double RigidBody::getZangle( ){
266 <    return zAngle;
267 < }
324 >        velRot = (getA() * skewMat).transpose() * ref;
325  
326 < void RigidBody::setZangle( double zAng ){
327 <    zAngle = zAng;
326 >        vel =getVel() + velRot;
327 >        return true;
328 >        
329 >    } else {
330 >        std::cerr << index << " is an invalid index, current rigid body contains "
331 >                      << atoms_.size() << "atoms" << std::endl;
332 >        return false;
333 >    }
334   }
335  
336 < void RigidBody::addZangle( double zAng ){
337 <    zAngle += zAng;
336 > bool RigidBody::getAtomVel(Vector3d& vel, Atom* atom) {
337 >
338 >    std::vector<Atom*>::iterator i;
339 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
340 >    if (i != atoms_.end()) {
341 >        return getAtomVel(vel, i - atoms_.begin());
342 >    } else {
343 >        std::cerr << "Atom " << atom->getGlobalIndex()
344 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;    
345 >        return false;
346 >    }    
347   }
348  
349 < void RigidBody::calcRefCoords( ) {
349 > bool RigidBody::getAtomRefCoor(Vector3d& coor, unsigned int index) {
350 >    if (index < atoms_.size()) {
351  
352 <  int i,j,k, it, n_linear_coords;
353 <  double mtmp;
354 <  vec3 apos;
355 <  double refCOM[3];
356 <  vec3 ptmp;
357 <  double Itmp[3][3];
358 <  double evals[3];
286 <  double evects[3][3];
287 <  double r, r2, len;
352 >        coor = refCoords_[index];
353 >        return true;
354 >    } else {
355 >        std::cerr << index << " is an invalid index, current rigid body contains "
356 >                      << atoms_.size() << "atoms" << std::endl;
357 >        return false;
358 >    }
359  
360 <  // First, find the center of mass:
290 <  
291 <  mass = 0.0;
292 <  for (j=0; j<3; j++)
293 <    refCOM[j] = 0.0;
294 <  
295 <  for (i = 0; i < myAtoms.size(); i++) {
296 <    mtmp = myAtoms[i]->getMass();
297 <    mass += mtmp;
360 > }
361  
362 <    apos = refCoords[i];
363 <    
364 <    for(j = 0; j < 3; j++) {
365 <      refCOM[j] += apos[j]*mtmp;    
366 <    }    
367 <  }
368 <  
369 <  for(j = 0; j < 3; j++)
370 <    refCOM[j] /= mass;
362 > bool RigidBody::getAtomRefCoor(Vector3d& coor, Atom* atom) {
363 >    std::vector<Atom*>::iterator i;
364 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
365 >    if (i != atoms_.end()) {
366 >        //RigidBody class makes sure refCoords_ and atoms_ match each other
367 >        coor = refCoords_[i - atoms_.begin()];
368 >        return true;
369 >    } else {
370 >        std::cerr << "Atom " << atom->getGlobalIndex()
371 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;    
372 >        return false;
373 >    }
374  
375 < // Next, move the origin of the reference coordinate system to the COM:
375 > }
376  
311  for (i = 0; i < myAtoms.size(); i++) {
312    apos = refCoords[i];
313    for (j=0; j < 3; j++) {
314      apos[j] = apos[j] - refCOM[j];
315    }
316    refCoords[i] = apos;
317  }
377  
378 < // Moment of Inertia calculation
378 > void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
379  
380 <  for (i = 0; i < 3; i++)
381 <    for (j = 0; j < 3; j++)
323 <      Itmp[i][j] = 0.0;  
380 >  Vector3d coords;
381 >  Vector3d euler;
382    
325  for (it = 0; it < myAtoms.size(); it++) {
383  
384 <    mtmp = myAtoms[it]->getMass();
385 <    ptmp = refCoords[it];
386 <    r= norm3(ptmp.vec);
387 <    r2 = r*r;
388 <    
389 <    for (i = 0; i < 3; i++) {
390 <      for (j = 0; j < 3; j++) {
391 <        
392 <        if (i==j) Itmp[i][j] += mtmp * r2;
393 <
337 <        Itmp[i][j] -= mtmp * ptmp.vec[i]*ptmp.vec[j];
338 <      }
339 <    }
384 >  atoms_.push_back(at);
385 >
386 >  if( !ats->havePosition() ){
387 >    sprintf( painCave.errMsg,
388 >             "RigidBody error.\n"
389 >             "\tAtom %s does not have a position specified.\n"
390 >             "\tThis means RigidBody cannot set up reference coordinates.\n",
391 >             ats->getType() );
392 >    painCave.isFatal = 1;
393 >    simError();
394    }
395    
396 <  diagonalize3x3(Itmp, evals, sU);
397 <  
398 <  // zero out I and then fill the diagonals with the moments of inertia:
396 >  coords[0] = ats->getPosX();
397 >  coords[1] = ats->getPosY();
398 >  coords[2] = ats->getPosZ();
399  
400 <  n_linear_coords = 0;
400 >  refCoords_.push_back(coords);
401  
402 <  for (i = 0; i < 3; i++) {
403 <    for (j = 0; j < 3; j++) {
404 <      I[i][j] = 0.0;  
351 <    }
352 <    I[i][i] = evals[i];
402 >  RotMat3x3d identMat = RotMat3x3d::identity();
403 >  
404 >  if (at->isDirectional()) {  
405  
406 <    if (fabs(evals[i]) < momIntTol) {
407 <      is_linear = true;
356 <      n_linear_coords++;
357 <      linear_axis = i;
358 <    }
359 <  }
360 <
361 <  if (n_linear_coords > 1) {
362 <          sprintf( painCave.errMsg,
406 >    if( !ats->haveOrientation() ){
407 >      sprintf( painCave.errMsg,
408                 "RigidBody error.\n"
409 <               "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
410 <               "\tmoment of inertia.  This can happen in one of three ways:\n"
411 <               "\t 1) Only one atom was specified, or \n"
367 <               "\t 2) All atoms were specified at the same location, or\n"
368 <               "\t 3) The programmers did something stupid.\n"
369 <               "\tIt is silly to use a rigid body to describe this situation.  Be smarter.\n"
370 <               );
409 >               "\tAtom %s does not have an orientation specified.\n"
410 >               "\tThis means RigidBody cannot set up reference orientations.\n",
411 >               ats->getType() );
412        painCave.isFatal = 1;
413        simError();
414 <  }
374 <  
375 <  // renormalize column vectors:
376 <  
377 <  for (i=0; i < 3; i++) {
378 <    len = 0.0;
379 <    for (j = 0; j < 3; j++) {
380 <      len += sU[i][j]*sU[i][j];
381 <    }
382 <    len = sqrt(len);
383 <    for (j = 0; j < 3; j++) {
384 <      sU[i][j] /= len;
385 <    }
386 <  }
387 < }
388 <
389 < void RigidBody::doEulerToRotMat(vec3 &euler, mat3x3 &myA ){
390 <
391 <  double phi, theta, psi;
392 <  
393 <  phi = euler[0];
394 <  theta = euler[1];
395 <  psi = euler[2];
396 <  
397 <  myA[0][0] = (cos(phi) * cos(psi)) - (sin(phi) * cos(theta) * sin(psi));
398 <  myA[0][1] = (sin(phi) * cos(psi)) + (cos(phi) * cos(theta) * sin(psi));
399 <  myA[0][2] = sin(theta) * sin(psi);
400 <  
401 <  myA[1][0] = -(cos(phi) * sin(psi)) - (sin(phi) * cos(theta) * cos(psi));
402 <  myA[1][1] = -(sin(phi) * sin(psi)) + (cos(phi) * cos(theta) * cos(psi));
403 <  myA[1][2] = sin(theta) * cos(psi);
404 <  
405 <  myA[2][0] = sin(phi) * sin(theta);
406 <  myA[2][1] = -cos(phi) * sin(theta);
407 <  myA[2][2] = cos(theta);
408 <
409 < }
410 <
411 < void RigidBody::calcForcesAndTorques() {
412 <
413 <  // Convert Atomic forces and torques to total forces and torques:
414 <  int i, j;
415 <  double apos[3];
416 <  double afrc[3];
417 <  double atrq[3];
418 <  double rpos[3];
419 <
420 <  zeroForces();
421 <  
422 <  for (i = 0; i < myAtoms.size(); i++) {
423 <
424 <    myAtoms[i]->getPos(apos);
425 <    myAtoms[i]->getFrc(afrc);
426 <
427 <    for (j=0; j<3; j++) {
428 <      rpos[j] = apos[j] - pos[j];
429 <      frc[j] += afrc[j];
430 <    }
414 >    }    
415      
416 <    trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
417 <    trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
418 <    trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
416 >    euler[0] = ats->getEulerPhi();
417 >    euler[1] = ats->getEulerTheta();
418 >    euler[2] = ats->getEulerPsi();
419  
420 <    // If the atom has a torque associated with it, then we also need to
421 <    // migrate the torques onto the center of mass:
438 <
439 <    if (myAtoms[i]->isDirectional()) {
440 <
441 <      myAtoms[i]->getTrq(atrq);
442 <      
443 <      for (j=0; j<3; j++)
444 <        trq[j] += atrq[j];
445 <    }
446 <  }
447 <
448 <  // Convert Torque to Body-fixed coordinates:
449 <  // (Actually, on second thought, don't.  Integrator does this now.)
450 <  // lab2Body(trq);
451 <
452 < }
453 <
454 < void RigidBody::updateAtoms() {
455 <  int i, j;
456 <  vec3 ref;
457 <  double apos[3];
458 <  DirectionalAtom* dAtom;
459 <  
460 <  for (i = 0; i < myAtoms.size(); i++) {
461 <    
462 <    ref = refCoords[i];
463 <
464 <    body2Lab(ref.vec);
420 >    RotMat3x3d Atmp(euler);
421 >    refOrients_.push_back(Atmp);
422      
423 <    for (j = 0; j<3; j++)
424 <      apos[j] = pos[j] + ref.vec[j];
468 <    
469 <    myAtoms[i]->setPos(apos);
470 <    
471 <    if (myAtoms[i]->isDirectional()) {
472 <      
473 <      dAtom = (DirectionalAtom *) myAtoms[i];
474 <      dAtom->rotateBy( A );
475 <      
476 <    }
477 <  }  
478 < }
479 <
480 < void RigidBody::getGrad( double grad[6] ) {
481 <
482 <  double myEuler[3];
483 <  double phi, theta, psi;
484 <  double cphi, sphi, ctheta, stheta;
485 <  double ephi[3];
486 <  double etheta[3];
487 <  double epsi[3];
488 <  
489 <  this->getEulerAngles(myEuler);
490 <
491 <  phi = myEuler[0];
492 <  theta = myEuler[1];
493 <  psi = myEuler[2];
494 <
495 <  cphi = cos(phi);
496 <  sphi = sin(phi);
497 <  ctheta = cos(theta);
498 <  stheta = sin(theta);
499 <
500 <  // get unit vectors along the phi, theta and psi rotation axes
501 <
502 <  ephi[0] = 0.0;
503 <  ephi[1] = 0.0;
504 <  ephi[2] = 1.0;
505 <
506 <  etheta[0] = cphi;
507 <  etheta[1] = sphi;
508 <  etheta[2] = 0.0;
509 <  
510 <  epsi[0] = stheta * cphi;
511 <  epsi[1] = stheta * sphi;
512 <  epsi[2] = ctheta;
513 <  
514 <  for (int j = 0 ; j<3; j++)
515 <    grad[j] = frc[j];
516 <
517 <  grad[3] = 0.0;
518 <  grad[4] = 0.0;
519 <  grad[5] = 0.0;
520 <  
521 <  for (int j = 0; j < 3; j++ ) {
522 <    
523 <    grad[3] += trq[j]*ephi[j];
524 <    grad[4] += trq[j]*etheta[j];
525 <    grad[5] += trq[j]*epsi[j];
526 <    
423 >  }else {
424 >    refOrients_.push_back(identMat);
425    }
426    
529 }
530
531 /**
532  * getEulerAngles computes a set of Euler angle values consistent
533  * with an input rotation matrix.  They are returned in the following
534  * order:
535  *  myEuler[0] = phi;
536  *  myEuler[1] = theta;
537  *  myEuler[2] = psi;
538 */
539 void RigidBody::getEulerAngles(double myEuler[3]) {
540
541  // We use so-called "x-convention", which is the most common
542  // definition.  In this convention, the rotation given by Euler
543  // angles (phi, theta, psi), where the first rotation is by an angle
544  // phi about the z-axis, the second is by an angle theta (0 <= theta
545  // <= 180) about the x-axis, and the third is by an angle psi about
546  // the z-axis (again).
427    
548  
549  double phi,theta,psi,eps;
550  double pi;
551  double cphi,ctheta,cpsi;
552  double sphi,stheta,spsi;
553  double b[3];
554  int flip[3];
555  
556  // set the tolerance for Euler angles and rotation elements
557  
558  eps = 1.0e-8;
559
560  theta = acos(min(1.0,max(-1.0,A[2][2])));
561  ctheta = A[2][2];
562  stheta = sqrt(1.0 - ctheta * ctheta);
563
564  // when sin(theta) is close to 0, we need to consider the
565  // possibility of a singularity. In this case, we can assign an
566  // arbitary value to phi (or psi), and then determine the psi (or
567  // phi) or vice-versa.  We'll assume that phi always gets the
568  // rotation, and psi is 0 in cases of singularity.  we use atan2
569  // instead of atan, since atan2 will give us -Pi to Pi.  Since 0 <=
570  // theta <= 180, sin(theta) will be always non-negative. Therefore,
571  // it never changes the sign of both of the parameters passed to
572  // atan2.
573  
574  if (fabs(stheta) <= eps){
575    psi = 0.0;
576    phi = atan2(-A[1][0], A[0][0]);  
577  }
578  // we only have one unique solution
579  else{    
580    phi = atan2(A[2][0], -A[2][1]);
581    psi = atan2(A[0][2], A[1][2]);
582  }
583  
584  //wrap phi and psi, make sure they are in the range from 0 to 2*Pi
585  //if (phi < 0)
586  //  phi += M_PI;
587  
588  //if (psi < 0)
589  //  psi += M_PI;
590  
591  myEuler[0] = phi;
592  myEuler[1] = theta;
593  myEuler[2] = psi;
594  
595  return;
428   }
429  
598 double RigidBody::max(double x, double  y) {  
599  return (x > y) ? x : y;
430   }
431  
602 double RigidBody::min(double x, double  y) {  
603  return (x > y) ? y : x;
604 }
605
606 void RigidBody::findCOM() {
607  
608  size_t i;
609  int j;
610  double mtmp;
611  double ptmp[3];
612  double vtmp[3];
613  
614  for(j = 0; j < 3; j++) {
615    pos[j] = 0.0;
616    vel[j] = 0.0;
617  }
618  mass = 0.0;
619  
620  for (i = 0; i < myAtoms.size(); i++) {
621    
622    mtmp = myAtoms[i]->getMass();    
623    myAtoms[i]->getPos(ptmp);
624    myAtoms[i]->getVel(vtmp);
625    
626    mass += mtmp;
627    
628    for(j = 0; j < 3; j++) {
629      pos[j] += ptmp[j]*mtmp;
630      vel[j] += vtmp[j]*mtmp;
631    }
632    
633  }
634  
635  for(j = 0; j < 3; j++) {
636    pos[j] /= mass;
637    vel[j] /= mass;
638  }
639
640 }
641
642 void RigidBody::accept(BaseVisitor* v){
643  vector<Atom*>::iterator atomIter;
644  v->visit(this);
645
646  //for(atomIter = myAtoms.begin(); atomIter != myAtoms.end(); ++atomIter)
647  //  (*atomIter)->accept(v);
648 }
649 void RigidBody::getAtomRefCoor(double pos[3], int index){
650  vec3 ref;
651
652  ref = refCoords[index];
653  pos[0] = ref[0];
654  pos[1] = ref[1];
655  pos[2] = ref[2];
656  
657 }
658
659
660 void RigidBody::getAtomPos(double theP[3], int index){
661  vec3 ref;
662
663  if (index >= myAtoms.size())
664    cerr << index << " is an invalid index, current rigid body contains " << myAtoms.size() << "atoms" << endl;
665
666  ref = refCoords[index];
667  body2Lab(ref.vec);
668  
669  theP[0] = pos[0] + ref[0];
670  theP[1] = pos[1] + ref[1];
671  theP[2] = pos[2] + ref[2];
672 }
673
674
675 void RigidBody::getAtomVel(double theV[3], int index){
676  vec3 ref;
677  double velRot[3];
678  double skewMat[3][3];
679  double aSkewMat[3][3];
680  double aSkewTransMat[3][3];
681  
682  //velRot = $(A\cdot skew(I^{-1}j))^{T}refCoor$
683
684  if (index >= myAtoms.size())
685    cerr << index << " is an invalid index, current rigid body contains " << myAtoms.size() << "atoms" << endl;
686
687  ref = refCoords[index];
688
689  skewMat[0][0] =0;
690  skewMat[0][1] = ji[2] /I[2][2];
691  skewMat[0][2] = -ji[1] /I[1][1];
692
693  skewMat[1][0] = -ji[2] /I[2][2];
694  skewMat[1][1] = 0;
695  skewMat[1][2] = ji[0]/I[0][0];
696
697  skewMat[2][0] =ji[1] /I[1][1];
698  skewMat[2][1] = -ji[0]/I[0][0];
699  skewMat[2][2] = 0;
700  
701  matMul3(A, skewMat, aSkewMat);
702
703  transposeMat3(aSkewMat, aSkewTransMat);
704
705  matVecMul3(aSkewTransMat, ref.vec, velRot);
706  theV[0] = vel[0] + velRot[0];
707  theV[1] = vel[1] + velRot[1];
708  theV[2] = vel[2] + velRot[2];
709 }
710
711

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines