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 1492 by tim, Fri Sep 24 16:27:58 2004 UTC vs.
Revision 1957 by tim, Tue Jan 25 17:45:23 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 >    //project the inertial moment of directional atoms into this rigid body
178 >    for (std::size_t i = 0; i < atoms_.size(); i++) {
179 >        if (atoms_[i]->isDirectional()) {
180 >            RectMatrix<double, 3, 3> Iproject = refOrients_[i].transpose() * atoms_[i]->getI();
181 >            Itmp(0, 0) += Iproject(0, 0);
182 >            Itmp(1, 1) += Iproject(1, 1);
183 >            Itmp(2, 2) += Iproject(2, 2);
184 >        }
185 >    }
186  
187 <  double q0Sqr, q1Sqr, q2Sqr, q3Sqr;
188 <  
189 <  q0Sqr = the_q[0] * the_q[0];
171 <  q1Sqr = the_q[1] * the_q[1];
172 <  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;  
187 >    //diagonalize
188 >    Vector3d evals;
189 >    Mat3x3d::diagonalize(Itmp, evals, sU_);
190  
191 < }
191 >    // zero out I and then fill the diagonals with the moments of inertia:
192 >    inertiaTensor_(0, 0) = evals[0];
193 >    inertiaTensor_(1, 1) = evals[1];
194 >    inertiaTensor_(2, 2) = evals[2];
195 >        
196 >    int nLinearAxis = 0;
197 >    for (int i = 0; i < 3; i++) {    
198 >        if (fabs(evals[i]) < oopse::epsilon) {
199 >            linear_ = true;
200 >            linearAxis_ = i;
201 >            ++ nLinearAxis;
202 >        }
203 >    }
204  
205 < void RigidBody::getA( double the_A[3][3] ){
205 >    if (nLinearAxis > 1) {
206 >        sprintf( painCave.errMsg,
207 >            "RigidBody error.\n"
208 >            "\tOOPSE found more than one axis in this rigid body with a vanishing \n"
209 >            "\tmoment of inertia.  This can happen in one of three ways:\n"
210 >            "\t 1) Only one atom was specified, or \n"
211 >            "\t 2) All atoms were specified at the same location, or\n"
212 >            "\t 3) The programmers did something stupid.\n"
213 >            "\tIt is silly to use a rigid body to describe this situation.  Be smarter.\n"
214 >            );
215 >        painCave.isFatal = 1;
216 >        simError();
217 >    }
218    
191  for (int i = 0; i < 3; i++)
192    for (int j = 0; j < 3; j++)
193      the_A[i][j] = A[i][j];
194
219   }
220  
221 < void RigidBody::setA( double the_A[3][3] ){
221 > void  RigidBody::calcForcesAndTorques() {
222 >    Vector3d afrc;
223 >    Vector3d atrq;
224 >    Vector3d apos;
225 >    Vector3d rpos;
226 >    Vector3d frc(0.0);
227 >    Vector3d trq(0.0);
228 >    Vector3d pos = this->getPos();
229 >    for (int i = 0; i < atoms_.size(); i++) {
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 <  
235 < }
231 >        afrc = atoms_[i]->getFrc();
232 >        apos = atoms_[i]->getPos();
233 >        rpos = apos - pos;
234 >        
235 >        frc += afrc;
236  
237 < void RigidBody::getJ( double theJ[3] ){
238 <  
239 <  for (int i = 0; i < 3; i++)
208 <    theJ[i] = ji[i];
237 >        trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
238 >        trq[1] += rpos[2]*afrc[0] - rpos[0]*afrc[2];
239 >        trq[2] += rpos[0]*afrc[1] - rpos[1]*afrc[0];
240  
241 < }
241 >        // If the atom has a torque associated with it, then we also need to
242 >        // migrate the torques onto the center of mass:
243  
244 < void RigidBody::setJ( double theJ[3] ){
245 <  
246 <  for (int i = 0; i < 3; i++)
247 <    ji[i] = theJ[i];
248 <
244 >        if (atoms_[i]->isDirectional()) {
245 >            atrq = atoms_[i]->getTrq();
246 >            trq += atrq;
247 >        }
248 >        
249 >    }
250 >    
251 >    setFrc(frc);
252 >    setTrq(trq);
253 >    
254   }
255  
256 < void RigidBody::getTrq(double theT[3]){
257 <  for (int i = 0; i < 3 ; i++)
258 <    theT[i] = trq[i];
259 < }      
256 > void  RigidBody::updateAtoms() {
257 >    unsigned int i;
258 >    Vector3d ref;
259 >    Vector3d apos;
260 >    DirectionalAtom* dAtom;
261 >    Vector3d pos = getPos();
262 >    RotMat3x3d a = getA();
263 >    
264 >    for (i = 0; i < atoms_.size(); i++) {
265 >    
266 >        ref = body2Lab(refCoords_[i]);
267  
268 < void RigidBody::addTrq(double theT[3]){
225 <  for (int i = 0; i < 3 ; i++)
226 <    trq[i] += theT[i];
227 < }      
268 >        apos = pos + ref;
269  
270 < void RigidBody::getI( double the_I[3][3] ){  
270 >        atoms_[i]->setPos(apos);
271  
272 <    for (int i = 0; i < 3; i++)
273 <      for (int j = 0; j < 3; j++)
274 <        the_I[i][j] = I[i][j];
272 >        if (atoms_[i]->isDirectional()) {
273 >          
274 >          dAtom = (DirectionalAtom *) atoms_[i];
275 >          dAtom->setA(a * refOrients_[i]);
276 >          //dAtom->rotateBy( A );      
277 >        }
278  
279 +    }
280 +  
281   }
282  
237 void RigidBody::lab2Body( double r[3] ){
283  
284 <  double rl[3]; // the lab frame vector
285 <  
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]);
284 > bool RigidBody::getAtomPos(Vector3d& pos, unsigned int index) {
285 >    if (index < atoms_.size()) {
286  
287 +        Vector3d ref = body2Lab(refCoords_[index]);
288 +        pos = getPos() + ref;
289 +        return true;
290 +    } else {
291 +        std::cerr << index << " is an invalid index, current rigid body contains "
292 +                      << atoms_.size() << "atoms" << std::endl;
293 +        return false;
294 +    }    
295   }
296  
297 < void RigidBody::body2Lab( double r[3] ){
297 > bool RigidBody::getAtomPos(Vector3d& pos, Atom* atom) {
298 >    std::vector<Atom*>::iterator i;
299 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
300 >    if (i != atoms_.end()) {
301 >        //RigidBody class makes sure refCoords_ and atoms_ match each other
302 >        Vector3d ref = body2Lab(refCoords_[i - atoms_.begin()]);
303 >        pos = getPos() + ref;
304 >        return true;
305 >    } else {
306 >        std::cerr << "Atom " << atom->getGlobalIndex()
307 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;
308 >        return false;
309 >    }
310 > }
311 > bool RigidBody::getAtomVel(Vector3d& vel, unsigned int index) {
312  
313 <  double rb[3]; // the body frame vector
254 <  
255 <  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]);
313 >    //velRot = $(A\cdot skew(I^{-1}j))^{T}refCoor$
314  
315 < }
315 >    if (index < atoms_.size()) {
316  
317 < double RigidBody::getZangle( ){
318 <    return zAngle;
319 < }
317 >        Vector3d velRot;
318 >        Mat3x3d skewMat;;
319 >        Vector3d ref = refCoords_[index];
320 >        Vector3d ji = getJ();
321 >        Mat3x3d I =  getI();
322  
323 < void RigidBody::setZangle( double zAng ){
324 <    zAngle = zAng;
323 >        skewMat(0, 0) =0;
324 >        skewMat(0, 1) = ji[2] /I(2, 2);
325 >        skewMat(0, 2) = -ji[1] /I(1, 1);
326 >
327 >        skewMat(1, 0) = -ji[2] /I(2, 2);
328 >        skewMat(1, 1) = 0;
329 >        skewMat(1, 2) = ji[0]/I(0, 0);
330 >
331 >        skewMat(2, 0) =ji[1] /I(1, 1);
332 >        skewMat(2, 1) = -ji[0]/I(0, 0);
333 >        skewMat(2, 2) = 0;
334 >
335 >        velRot = (getA() * skewMat).transpose() * ref;
336 >
337 >        vel =getVel() + velRot;
338 >        return true;
339 >        
340 >    } else {
341 >        std::cerr << index << " is an invalid index, current rigid body contains "
342 >                      << atoms_.size() << "atoms" << std::endl;
343 >        return false;
344 >    }
345   }
346  
347 < void RigidBody::addZangle( double zAng ){
274 <    zAngle += zAng;
275 < }
347 > bool RigidBody::getAtomVel(Vector3d& vel, Atom* atom) {
348  
349 < void RigidBody::calcRefCoords( ) {
350 <
351 <  int i,j,k, it, n_linear_coords;
352 <  double mtmp;
353 <  vec3 apos;
354 <  double refCOM[3];
355 <  vec3 ptmp;
356 <  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;    
349 >    std::vector<Atom*>::iterator i;
350 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
351 >    if (i != atoms_.end()) {
352 >        return getAtomVel(vel, i - atoms_.begin());
353 >    } else {
354 >        std::cerr << "Atom " << atom->getGlobalIndex()
355 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;    
356 >        return false;
357      }    
358 <  }
305 <  
306 <  for(j = 0; j < 3; j++)
307 <    refCOM[j] /= mass;
358 > }
359  
360 < // Next, move the origin of the reference coordinate system to the COM:
360 > bool RigidBody::getAtomRefCoor(Vector3d& coor, unsigned int index) {
361 >    if (index < atoms_.size()) {
362  
363 <  for (i = 0; i < myAtoms.size(); i++) {
364 <    apos = refCoords[i];
365 <    for (j=0; j < 3; j++) {
366 <      apos[j] = apos[j] - refCOM[j];
363 >        coor = refCoords_[index];
364 >        return true;
365 >    } else {
366 >        std::cerr << index << " is an invalid index, current rigid body contains "
367 >                      << atoms_.size() << "atoms" << std::endl;
368 >        return false;
369      }
316    refCoords[i] = apos;
317  }
370  
371 < // Moment of Inertia calculation
371 > }
372  
373 <  for (i = 0; i < 3; i++)
374 <    for (j = 0; j < 3; j++)
375 <      Itmp[i][j] = 0.0;  
376 <  
377 <  for (it = 0; it < myAtoms.size(); it++) {
378 <
379 <    mtmp = myAtoms[it]->getMass();
380 <    ptmp = refCoords[it];
381 <    r= norm3(ptmp.vec);
382 <    r2 = r*r;
383 <    
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 <      }
373 > bool RigidBody::getAtomRefCoor(Vector3d& coor, Atom* atom) {
374 >    std::vector<Atom*>::iterator i;
375 >    i = std::find(atoms_.begin(), atoms_.end(), atom);
376 >    if (i != atoms_.end()) {
377 >        //RigidBody class makes sure refCoords_ and atoms_ match each other
378 >        coor = refCoords_[i - atoms_.begin()];
379 >        return true;
380 >    } else {
381 >        std::cerr << "Atom " << atom->getGlobalIndex()
382 >                      <<" does not belong to Rigid body "<< getGlobalIndex() << std::endl;    
383 >        return false;
384      }
340  }
341  
342  diagonalize3x3(Itmp, evals, sU);
343  
344  // zero out I and then fill the diagonals with the moments of inertia:
385  
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  }
386   }
387  
389 void RigidBody::doEulerToRotMat(vec3 &euler, mat3x3 &myA ){
388  
389 <  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);
389 > void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
390  
391 < }
392 <
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();
391 >  Vector3d coords;
392 >  Vector3d euler;
393    
422  for (i = 0; i < myAtoms.size(); i++) {
394  
395 <    myAtoms[i]->getPos(apos);
396 <    myAtoms[i]->getFrc(afrc);
397 <
398 <    for (j=0; j<3; j++) {
399 <      rpos[j] = apos[j] - pos[j];
400 <      frc[j] += afrc[j];
401 <    }
402 <    
403 <    trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
404 <    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 <    }
395 >  atoms_.push_back(at);
396 >
397 >  if( !ats->havePosition() ){
398 >    sprintf( painCave.errMsg,
399 >             "RigidBody error.\n"
400 >             "\tAtom %s does not have a position specified.\n"
401 >             "\tThis means RigidBody cannot set up reference coordinates.\n",
402 >             ats->getType() );
403 >    painCave.isFatal = 1;
404 >    simError();
405    }
406 +  
407 +  coords[0] = ats->getPosX();
408 +  coords[1] = ats->getPosY();
409 +  coords[2] = ats->getPosZ();
410  
411 <  // Convert Torque to Body-fixed coordinates:
449 <  // (Actually, on second thought, don't.  Integrator does this now.)
450 <  // lab2Body(trq);
411 >  refCoords_.push_back(coords);
412  
413 < }
453 <
454 < void RigidBody::updateAtoms() {
455 <  int i, j;
456 <  vec3 ref;
457 <  double apos[3];
458 <  DirectionalAtom* dAtom;
413 >  RotMat3x3d identMat = RotMat3x3d::identity();
414    
415 <  for (i = 0; i < myAtoms.size(); i++) {
461 <    
462 <    ref = refCoords[i];
415 >  if (at->isDirectional()) {  
416  
417 <    body2Lab(ref.vec);
417 >    if( !ats->haveOrientation() ){
418 >      sprintf( painCave.errMsg,
419 >               "RigidBody error.\n"
420 >               "\tAtom %s does not have an orientation specified.\n"
421 >               "\tThis means RigidBody cannot set up reference orientations.\n",
422 >               ats->getType() );
423 >      painCave.isFatal = 1;
424 >      simError();
425 >    }    
426      
427 <    for (j = 0; j<3; j++)
428 <      apos[j] = pos[j] + ref.vec[j];
429 <    
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 < }
427 >    euler[0] = ats->getEulerPhi();
428 >    euler[1] = ats->getEulerTheta();
429 >    euler[2] = ats->getEulerPsi();
430  
431 < void RigidBody::getGrad( double grad[6] ) {
432 <
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++ ) {
431 >    RotMat3x3d Atmp(euler);
432 >    refOrients_.push_back(Atmp);
433      
434 <    grad[3] += trq[j]*ephi[j];
435 <    grad[4] += trq[j]*etheta[j];
525 <    grad[5] += trq[j]*epsi[j];
526 <    
434 >  }else {
435 >    refOrients_.push_back(identMat);
436    }
437    
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).
438    
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;
439   }
440  
598 double RigidBody::max(double x, double  y) {  
599  return (x > y) ? x : y;
441   }
442  
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