ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/primitives/RigidBody.cpp
(Generate patch)

Comparing trunk/src/primitives/RigidBody.cpp (file contents):
Revision 3 by tim, Fri Sep 24 16:27:58 2004 UTC vs.
Revision 253 by tim, Thu Jan 13 19:40:37 2005 UTC

# Line 1 | Line 1
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 <math.h>
43   #include "primitives/RigidBody.hpp"
3 #include "primitives/DirectionalAtom.hpp"
44   #include "utils/simError.h"
45 < #include "math/MatVec3.h"
45 > namespace oopse {
46  
47 < RigidBody::RigidBody() : StuntDouble() {
8 <  objType = OT_RIGIDBODY;
9 <  is_linear = false;
10 <  linear_axis =  -1;
11 <  momIntTol = 1e-6;
12 < }
47 > RigidBody::RigidBody() : StuntDouble(otRigidBody, &Snapshot::rigidbodyData), inertiaTensor_(0.0){
48  
14 RigidBody::~RigidBody() {
49   }
50  
51 < void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
51 > void RigidBody::setPrevA(const RotMat3x3d& a) {
52 >    ((snapshotMan_->getPrevSnapshot())->*storage_).aMat[localIndex_] = a;
53 >    //((snapshotMan_->getPrevSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
54  
55 <  vec3 coords;
56 <  vec3 euler;
57 <  mat3x3 Atmp;
55 >    for (int i =0 ; i < atoms_.size(); ++i){
56 >        if (atoms_[i]->isDirectional()) {
57 >            atoms_[i]->setPrevA(a * refOrients_[i]);
58 >        }
59 >    }
60  
61 <  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();
61 > }
62  
63 <  refCoords.push_back(coords);
64 <  
65 <  if (at->isDirectional()) {  
63 >      
64 > void RigidBody::setA(const RotMat3x3d& a) {
65 >    ((snapshotMan_->getCurrentSnapshot())->*storage_).aMat[localIndex_] = a;
66 >    //((snapshotMan_->getCurrentSnapshot())->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;
67  
68 <    if( !ats->haveOrientation() ){
69 <      sprintf( painCave.errMsg,
70 <               "RigidBody error.\n"
71 <               "\tAtom %s does not have an orientation specified.\n"
72 <               "\tThis means RigidBody cannot set up reference orientations.\n",
73 <               ats->getType() );
49 <      painCave.isFatal = 1;
50 <      simError();
51 <    }    
68 >    for (int i =0 ; i < atoms_.size(); ++i){
69 >        if (atoms_[i]->isDirectional()) {
70 >            atoms_[i]->setA(a * refOrients_[i]);
71 >        }
72 >    }
73 > }    
74      
75 <    euler[0] = ats->getEulerPhi();
76 <    euler[1] = ats->getEulerTheta();
77 <    euler[2] = ats->getEulerPsi();
56 <    
57 <    doEulerToRotMat(euler, Atmp);
58 <    
59 <    refOrients.push_back(Atmp);
60 <    
61 <  }
62 < }
75 > void RigidBody::setA(const RotMat3x3d& a, int snapshotNo) {
76 >    ((snapshotMan_->getSnapshot(snapshotNo))->*storage_).aMat[localIndex_] = a;
77 >    //((snapshotMan_->getSnapshot(snapshotNo))->*storage_).electroFrame[localIndex_] = a.transpose() * sU_;    
78  
79 < void RigidBody::getPos(double theP[3]){
80 <  for (int i = 0; i < 3 ; i++)
81 <    theP[i] = pos[i];
82 < }      
79 >    for (int i =0 ; i < atoms_.size(); ++i){
80 >        if (atoms_[i]->isDirectional()) {
81 >            atoms_[i]->setA(a * refOrients_[i], snapshotNo);
82 >        }
83 >    }
84  
85 < void RigidBody::setPos(double theP[3]){
70 <  for (int i = 0; i < 3 ; i++)
71 <    pos[i] = theP[i];
72 < }      
85 > }  
86  
87 < void RigidBody::getVel(double theV[3]){
88 <  for (int i = 0; i < 3 ; i++)
89 <    theV[i] = vel[i];
77 < }      
87 > Mat3x3d RigidBody::getI() {
88 >    return inertiaTensor_;
89 > }    
90  
91 < void RigidBody::setVel(double theV[3]){
92 <  for (int i = 0; i < 3 ; i++)
93 <    vel[i] = theV[i];
94 < }      
91 > std::vector<double> RigidBody::getGrad() {
92 >     std::vector<double> grad(6, 0.0);
93 >    Vector3d force;
94 >    Vector3d torque;
95 >    Vector3d myEuler;
96 >    double phi, theta, psi;
97 >    double cphi, sphi, ctheta, stheta;
98 >    Vector3d ephi;
99 >    Vector3d etheta;
100 >    Vector3d epsi;
101  
102 < void RigidBody::getFrc(double theF[3]){
103 <  for (int i = 0; i < 3 ; i++)
104 <    theF[i] = frc[i];
87 < }      
102 >    force = getFrc();
103 >    torque =getTrq();
104 >    myEuler = getA().toEulerAngles();
105  
106 < void RigidBody::addFrc(double theF[3]){
107 <  for (int i = 0; i < 3 ; i++)
108 <    frc[i] += theF[i];
92 < }    
106 >    phi = myEuler[0];
107 >    theta = myEuler[1];
108 >    psi = myEuler[2];
109  
110 < void RigidBody::zeroForces() {
110 >    cphi = cos(phi);
111 >    sphi = sin(phi);
112 >    ctheta = cos(theta);
113 >    stheta = sin(theta);
114  
115 <  for (int i = 0; i < 3; i++) {
97 <    frc[i] = 0.0;
98 <    trq[i] = 0.0;
99 <  }
115 >    // get unit vectors along the phi, theta and psi rotation axes
116  
117 < }
117 >    ephi[0] = 0.0;
118 >    ephi[1] = 0.0;
119 >    ephi[2] = 1.0;
120  
121 < void RigidBody::setEuler( double phi, double theta, double psi ){
122 <  
123 <    A[0][0] = (cos(phi) * cos(psi)) - (sin(phi) * cos(theta) * sin(psi));
106 <    A[0][1] = (sin(phi) * cos(psi)) + (cos(phi) * cos(theta) * sin(psi));
107 <    A[0][2] = sin(theta) * sin(psi);
108 <    
109 <    A[1][0] = -(cos(phi) * sin(psi)) - (sin(phi) * cos(theta) * cos(psi));
110 <    A[1][1] = -(sin(phi) * sin(psi)) + (cos(phi) * cos(theta) * cos(psi));
111 <    A[1][2] = sin(theta) * cos(psi);
112 <    
113 <    A[2][0] = sin(phi) * sin(theta);
114 <    A[2][1] = -cos(phi) * sin(theta);
115 <    A[2][2] = cos(theta);
121 >    etheta[0] = cphi;
122 >    etheta[1] = sphi;
123 >    etheta[2] = 0.0;
124  
125 < }
125 >    epsi[0] = stheta * cphi;
126 >    epsi[1] = stheta * sphi;
127 >    epsi[2] = ctheta;
128  
129 < void RigidBody::getQ( double q[4] ){
130 <  
131 <  double t, s;
132 <  double ad1, ad2, ad3;
129 >    //gradient is equal to -force
130 >    for (int j = 0 ; j<3; j++)
131 >        grad[j] = -force[j];
132 >
133 >    for (int j = 0; j < 3; j++ ) {
134 >
135 >        grad[3] += torque[j]*ephi[j];
136 >        grad[4] += torque[j]*etheta[j];
137 >        grad[5] += torque[j]*epsi[j];
138 >
139 >    }
140      
141 <  t = A[0][0] + A[1][1] + A[2][2] + 1.0;
142 <  if( t > 0.0 ){
143 <    
144 <    s = 0.5 / sqrt( t );
145 <    q[0] = 0.25 / s;
146 <    q[1] = (A[1][2] - A[2][1]) * s;
147 <    q[2] = (A[2][0] - A[0][2]) * s;
148 <    q[3] = (A[0][1] - A[1][0]) * s;
149 <  }
150 <  else{
151 <    
152 <    ad1 = fabs( A[0][0] );
153 <    ad2 = fabs( A[1][1] );
154 <    ad3 = fabs( A[2][2] );
155 <    
156 <    if( ad1 >= ad2 && ad1 >= ad3 ){
140 <      
141 <      s = 2.0 * sqrt( 1.0 + A[0][0] - A[1][1] - A[2][2] );
142 <      q[0] = (A[1][2] + A[2][1]) / s;
143 <      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;
141 >    return grad;
142 > }    
143 >
144 > void RigidBody::accept(BaseVisitor* v) {
145 >    v->visit(this);
146 > }    
147 >
148 > /**@todo need modification */
149 > void  RigidBody::calcRefCoords() {
150 >    double mtmp;
151 >    Vector3d refCOM(0.0);
152 >    mass_ = 0.0;
153 >    for (std::size_t i = 0; i < atoms_.size(); ++i) {
154 >        mtmp = atoms_[i]->getMass();
155 >        mass_ += mtmp;
156 >        refCOM += refCoords_[i]*mtmp;
157      }
158 <    else if( ad2 >= ad1 && ad2 >= ad3 ){
159 <      
160 <      s = sqrt( 1.0 + A[1][1] - A[0][0] - A[2][2] ) * 2.0;
161 <      q[0] = (A[0][2] + A[2][0]) / s;
162 <      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;
158 >    refCOM /= mass_;
159 >
160 >    // Next, move the origin of the reference coordinate system to the COM:
161 >    for (std::size_t i = 0; i < atoms_.size(); ++i) {
162 >        refCoords_[i] -= refCOM;
163      }
164 <    else{
165 <      
166 <      s = sqrt( 1.0 + A[2][2] - A[0][0] - A[1][1] ) * 2.0;
167 <      q[0] = (A[0][1] + A[1][0]) / s;
168 <      q[1] = (A[0][2] + A[2][0]) / s;
169 <      q[2] = (A[1][2] + A[2][1]) / s;
170 <      q[3] = 0.5 / s;
164 >
165 > // Moment of Inertia calculation
166 >    Mat3x3d Itmp(0.0);
167 >  
168 >    for (std::size_t i = 0; i < atoms_.size(); i++) {
169 >        mtmp = atoms_[i]->getMass();
170 >        Itmp -= outProduct(refCoords_[i], refCoords_[i]) * mtmp;
171 >        double r2 = refCoords_[i].lengthSquare();
172 >        Itmp(0, 0) += mtmp * r2;
173 >        Itmp(1, 1) += mtmp * r2;
174 >        Itmp(2, 2) += mtmp * r2;
175      }
163  }
164 }
176  
177 < void RigidBody::setQ( double the_q[4] ){
177 >    //diagonalize
178 >    Vector3d evals;
179 >    Mat3x3d::diagonalize(Itmp, evals, sU_);
180  
181 <  double q0Sqr, q1Sqr, q2Sqr, q3Sqr;
182 <  
183 <  q0Sqr = the_q[0] * the_q[0];
184 <  q1Sqr = the_q[1] * the_q[1];
185 <  q2Sqr = the_q[2] * the_q[2];
186 <  q3Sqr = the_q[3] * the_q[3];
187 <  
188 <  A[0][0] = q0Sqr + q1Sqr - q2Sqr - q3Sqr;
189 <  A[0][1] = 2.0 * ( the_q[1] * the_q[2] + the_q[0] * the_q[3] );
190 <  A[0][2] = 2.0 * ( the_q[1] * the_q[3] - the_q[0] * the_q[2] );
191 <  
192 <  A[1][0] = 2.0 * ( the_q[1] * the_q[2] - the_q[0] * the_q[3] );
193 <  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;  
181 >    // zero out I and then fill the diagonals with the moments of inertia:
182 >    inertiaTensor_(0, 0) = evals[0];
183 >    inertiaTensor_(1, 1) = evals[1];
184 >    inertiaTensor_(2, 2) = evals[2];
185 >        
186 >    int nLinearAxis = 0;
187 >    for (int i = 0; i < 3; i++) {    
188 >        if (fabs(evals[i]) < oopse::epsilon) {
189 >            linear_ = true;
190 >            linearAxis_ = i;
191 >            ++ nLinearAxis;
192 >        }
193 >    }
194  
195 +    if (nLinearAxis > 1) {
196 +        sprintf( painCave.errMsg,
197 +            "RigidBody error.\n"
198 +            "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
199 +            "\tmoment of inertia.  This can happen in one of three ways:\n"
200 +            "\t 1) Only one atom was specified, or \n"
201 +            "\t 2) All atoms were specified at the same location, or\n"
202 +            "\t 3) The programmers did something stupid.\n"
203 +            "\tIt is silly to use a rigid body to describe this situation.  Be smarter.\n"
204 +            );
205 +        painCave.isFatal = 1;
206 +        simError();
207 +    }
208 +  
209   }
210  
211 < void RigidBody::getA( double the_A[3][3] ){
212 <  
213 <  for (int i = 0; i < 3; i++)
214 <    for (int j = 0; j < 3; j++)
215 <      the_A[i][j] = A[i][j];
211 > void  RigidBody::calcForcesAndTorques() {
212 >    Vector3d afrc;
213 >    Vector3d atrq;
214 >    Vector3d apos;
215 >    Vector3d rpos;
216 >    Vector3d frc(0.0);
217 >    Vector3d trq(0.0);
218 >    Vector3d pos = this->getPos();
219 >    for (int i = 0; i < atoms_.size(); i++) {
220  
221 < }
221 >        afrc = atoms_[i]->getFrc();
222 >        apos = atoms_[i]->getPos();
223 >        rpos = apos - pos;
224 >        
225 >        frc += afrc;
226  
227 < void RigidBody::setA( double the_A[3][3] ){
227 >        trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
228 >        trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
229 >        trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
230  
231 <  for (int i = 0; i < 3; i++)
232 <    for (int j = 0; j < 3; j++)
233 <      A[i][j] = the_A[i][j];
234 <  
231 >        // If the atom has a torque associated with it, then we also need to
232 >        // migrate the torques onto the center of mass:
233 >
234 >        if (atoms_[i]->isDirectional()) {
235 >            atrq = atoms_[i]->getTrq();
236 >            trq += atrq;
237 >        }
238 >        
239 >    }
240 >    
241 >    setFrc(frc);
242 >    setTrq(trq);
243 >    
244   }
245  
246 < void RigidBody::getJ( double theJ[3] ){
247 <  
248 <  for (int i = 0; i < 3; i++)
249 <    theJ[i] = ji[i];
246 > void  RigidBody::updateAtoms() {
247 >    unsigned int i;
248 >    Vector3d ref;
249 >    Vector3d apos;
250 >    DirectionalAtom* dAtom;
251 >    Vector3d pos = getPos();
252 >    RotMat3x3d a = getA();
253 >    
254 >    for (i = 0; i < atoms_.size(); i++) {
255 >    
256 >        ref = body2Lab(refCoords_[i]);
257  
258 < }
258 >        apos = pos + ref;
259  
260 < void RigidBody::setJ( double theJ[3] ){
213 <  
214 <  for (int i = 0; i < 3; i++)
215 <    ji[i] = theJ[i];
260 >        atoms_[i]->setPos(apos);
261  
262 +        if (atoms_[i]->isDirectional()) {
263 +          
264 +          dAtom = (DirectionalAtom *) atoms_[i];
265 +          dAtom->setA(a * refOrients_[i]);
266 +          //dAtom->rotateBy( A );      
267 +        }
268 +
269 +    }
270 +  
271   }
272  
219 void RigidBody::getTrq(double theT[3]){
220  for (int i = 0; i < 3 ; i++)
221    theT[i] = trq[i];
222 }      
273  
274 < void RigidBody::addTrq(double theT[3]){
275 <  for (int i = 0; i < 3 ; i++)
226 <    trq[i] += theT[i];
227 < }      
274 > bool RigidBody::getAtomPos(Vector3d& pos, unsigned int index) {
275 >    if (index < atoms_.size()) {
276  
277 < void RigidBody::getI( double the_I[3][3] ){  
277 >        Vector3d ref = body2Lab(refCoords_[index]);
278 >        pos = getPos() + ref;
279 >        return true;
280 >    } else {
281 >        std::cerr << index << " is an invalid index, current rigid body contains "
282 >                      << atoms_.size() << "atoms" << std::endl;
283 >        return false;
284 >    }    
285 > }
286  
287 <    for (int i = 0; i < 3; i++)
288 <      for (int j = 0; j < 3; j++)
289 <        the_I[i][j] = I[i][j];
290 <
287 > bool RigidBody::getAtomPos(Vector3d& pos, Atom* atom) {
288 >    std::vector<Atom*>::iterator i;
289 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
290 >    if (i != atoms_.end()) {
291 >        //RigidBody class makes sure refCoords_ and atoms_ match each other
292 >        Vector3d ref = body2Lab(refCoords_[i - atoms_.begin()]);
293 >        pos = getPos() + ref;
294 >        return true;
295 >    } else {
296 >        std::cerr << "Atom " << atom->getGlobalIndex()
297 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
298 >        return false;
299 >    }
300   }
301 + bool RigidBody::getAtomVel(Vector3d& vel, unsigned int index) {
302  
303 < void RigidBody::lab2Body( double r[3] ){
303 >    //velRot = $(A\cdot skew(I^{-1}j))^{T}refCoor$
304  
305 <  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]);
305 >    if (index < atoms_.size()) {
306  
307 < }
307 >        Vector3d velRot;
308 >        Mat3x3d skewMat;;
309 >        Vector3d ref = refCoords_[index];
310 >        Vector3d ji = getJ();
311 >        Mat3x3d I =  getI();
312  
313 < void RigidBody::body2Lab( double r[3] ){
313 >        skewMat(0, 0) =0;
314 >        skewMat(0, 1) = ji[2] /I(2, 2);
315 >        skewMat(0, 2) = -ji[1] /I(1, 1);
316  
317 <  double rb[3]; // the body frame vector
318 <  
319 <  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]);
317 >        skewMat(1, 0) = -ji[2] /I(2, 2);
318 >        skewMat(1, 1) = 0;
319 >        skewMat(1, 2) = ji[0]/I(0, 0);
320  
321 < }
321 >        skewMat(2, 0) =ji[1] /I(1, 1);
322 >        skewMat(2, 1) = -ji[0]/I(0, 0);
323 >        skewMat(2, 2) = 0;
324  
325 < double RigidBody::getZangle( ){
266 <    return zAngle;
267 < }
325 >        velRot = (getA() * skewMat).transpose() * ref;
326  
327 < void RigidBody::setZangle( double zAng ){
328 <    zAngle = zAng;
327 >        vel =getVel() + velRot;
328 >        return true;
329 >        
330 >    } else {
331 >        std::cerr << index << " is an invalid index, current rigid body contains "
332 >                      << atoms_.size() << "atoms" << std::endl;
333 >        return false;
334 >    }
335   }
336  
337 < void RigidBody::addZangle( double zAng ){
274 <    zAngle += zAng;
275 < }
337 > bool RigidBody::getAtomVel(Vector3d& vel, Atom* atom) {
338  
339 < void RigidBody::calcRefCoords( ) {
340 <
341 <  int i,j,k, it, n_linear_coords;
342 <  double mtmp;
343 <  vec3 apos;
344 <  double refCOM[3];
345 <  vec3 ptmp;
346 <  double Itmp[3][3];
285 <  double evals[3];
286 <  double evects[3][3];
287 <  double r, r2, len;
288 <
289 <  // 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;
298 <
299 <    apos = refCoords[i];
300 <    
301 <    for(j = 0; j < 3; j++) {
302 <      refCOM[j] += apos[j]*mtmp;    
339 >    std::vector<Atom*>::iterator i;
340 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
341 >    if (i != atoms_.end()) {
342 >        return getAtomVel(vel, i - atoms_.begin());
343 >    } else {
344 >        std::cerr << "Atom " << atom->getGlobalIndex()
345 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;    
346 >        return false;
347      }    
348 <  }
305 <  
306 <  for(j = 0; j < 3; j++)
307 <    refCOM[j] /= mass;
348 > }
349  
350 < // Next, move the origin of the reference coordinate system to the COM:
350 > bool RigidBody::getAtomRefCoor(Vector3d& coor, unsigned int index) {
351 >    if (index < atoms_.size()) {
352  
353 <  for (i = 0; i < myAtoms.size(); i++) {
354 <    apos = refCoords[i];
355 <    for (j=0; j < 3; j++) {
356 <      apos[j] = apos[j] - refCOM[j];
353 >        coor = refCoords_[index];
354 >        return true;
355 >    } else {
356 >        std::cerr << index << " is an invalid index, current rigid body contains "
357 >                      << atoms_.size() << "atoms" << std::endl;
358 >        return false;
359      }
316    refCoords[i] = apos;
317  }
360  
361 < // Moment of Inertia calculation
361 > }
362  
363 <  for (i = 0; i < 3; i++)
364 <    for (j = 0; j < 3; j++)
365 <      Itmp[i][j] = 0.0;  
366 <  
367 <  for (it = 0; it < myAtoms.size(); it++) {
368 <
369 <    mtmp = myAtoms[it]->getMass();
370 <    ptmp = refCoords[it];
371 <    r= norm3(ptmp.vec);
372 <    r2 = r*r;
373 <    
332 <    for (i = 0; i < 3; i++) {
333 <      for (j = 0; j < 3; j++) {
334 <        
335 <        if (i==j) Itmp[i][j] += mtmp * r2;
336 <
337 <        Itmp[i][j] -= mtmp * ptmp.vec[i]*ptmp.vec[j];
338 <      }
363 > bool RigidBody::getAtomRefCoor(Vector3d& coor, Atom* atom) {
364 >    std::vector<Atom*>::iterator i;
365 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
366 >    if (i != atoms_.end()) {
367 >        //RigidBody class makes sure refCoords_ and atoms_ match each other
368 >        coor = refCoords_[i - atoms_.begin()];
369 >        return true;
370 >    } else {
371 >        std::cerr << "Atom " << atom->getGlobalIndex()
372 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;    
373 >        return false;
374      }
340  }
341  
342  diagonalize3x3(Itmp, evals, sU);
343  
344  // zero out I and then fill the diagonals with the moments of inertia:
375  
346  n_linear_coords = 0;
347
348  for (i = 0; i < 3; i++) {
349    for (j = 0; j < 3; j++) {
350      I[i][j] = 0.0;  
351    }
352    I[i][i] = evals[i];
353
354    if (fabs(evals[i]) < momIntTol) {
355      is_linear = true;
356      n_linear_coords++;
357      linear_axis = i;
358    }
359  }
360
361  if (n_linear_coords > 1) {
362          sprintf( painCave.errMsg,
363               "RigidBody error.\n"
364               "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
365               "\tmoment of inertia.  This can happen in one of three ways:\n"
366               "\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               );
371      painCave.isFatal = 1;
372      simError();
373  }
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  }
376   }
377  
389 void RigidBody::doEulerToRotMat(vec3 &euler, mat3x3 &myA ){
378  
379 <  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);
379 > void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
380  
381 < }
382 <
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();
381 >  Vector3d coords;
382 >  Vector3d euler;
383    
422  for (i = 0; i < myAtoms.size(); i++) {
384  
385 <    myAtoms[i]->getPos(apos);
386 <    myAtoms[i]->getFrc(afrc);
387 <
388 <    for (j=0; j<3; j++) {
389 <      rpos[j] = apos[j] - pos[j];
390 <      frc[j] += afrc[j];
391 <    }
392 <    
393 <    trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
394 <    trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
434 <    trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
435 <
436 <    // If the atom has a torque associated with it, then we also need to
437 <    // 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 <    }
385 >  atoms_.push_back(at);
386 >
387 >  if( !ats->havePosition() ){
388 >    sprintf( painCave.errMsg,
389 >             "RigidBody error.\n"
390 >             "\tAtom %s does not have a position specified.\n"
391 >             "\tThis means RigidBody cannot set up reference coordinates.\n",
392 >             ats->getType() );
393 >    painCave.isFatal = 1;
394 >    simError();
395    }
396 +  
397 +  coords[0] = ats->getPosX();
398 +  coords[1] = ats->getPosY();
399 +  coords[2] = ats->getPosZ();
400  
401 <  // Convert Torque to Body-fixed coordinates:
449 <  // (Actually, on second thought, don't.  Integrator does this now.)
450 <  // lab2Body(trq);
401 >  refCoords_.push_back(coords);
402  
403 < }
453 <
454 < void RigidBody::updateAtoms() {
455 <  int i, j;
456 <  vec3 ref;
457 <  double apos[3];
458 <  DirectionalAtom* dAtom;
403 >  RotMat3x3d identMat = RotMat3x3d::identity();
404    
405 <  for (i = 0; i < myAtoms.size(); i++) {
461 <    
462 <    ref = refCoords[i];
405 >  if (at->isDirectional()) {  
406  
407 <    body2Lab(ref.vec);
407 >    if( !ats->haveOrientation() ){
408 >      sprintf( painCave.errMsg,
409 >               "RigidBody error.\n"
410 >               "\tAtom %s does not have an orientation specified.\n"
411 >               "\tThis means RigidBody cannot set up reference orientations.\n",
412 >               ats->getType() );
413 >      painCave.isFatal = 1;
414 >      simError();
415 >    }    
416      
417 <    for (j = 0; j<3; j++)
418 <      apos[j] = pos[j] + ref.vec[j];
419 <    
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 < }
417 >    euler[0] = ats->getEulerPhi();
418 >    euler[1] = ats->getEulerTheta();
419 >    euler[2] = ats->getEulerPsi();
420  
421 < void RigidBody::getGrad( double grad[6] ) {
422 <
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++ ) {
421 >    RotMat3x3d Atmp(euler);
422 >    refOrients_.push_back(Atmp);
423      
424 <    grad[3] += trq[j]*ephi[j];
425 <    grad[4] += trq[j]*etheta[j];
525 <    grad[5] += trq[j]*epsi[j];
526 <    
424 >  }else {
425 >    refOrients_.push_back(identMat);
426    }
427    
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).
428    
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;
429   }
430  
598 double RigidBody::max(double x, double  y) {  
599  return (x > y) ? x : y;
431   }
432  
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