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 1930 by gezelter, Wed Jan 12 22:41:40 2005 UTC

# Line 1 | Line 1
1 < #include <math.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"
3 #include "primitives/DirectionalAtom.hpp"
43   #include "utils/simError.h"
44 < #include "math/MatVec3.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];
92 < }    
105 >    phi = myEuler[0];
106 >    theta = myEuler[1];
107 >    psi = myEuler[2];
108  
109 < void RigidBody::zeroForces() {
109 >    cphi = cos(phi);
110 >    sphi = sin(phi);
111 >    ctheta = cos(theta);
112 >    stheta = sin(theta);
113  
114 <  for (int i = 0; i < 3; i++) {
97 <    frc[i] = 0.0;
98 <    trq[i] = 0.0;
99 <  }
114 >    // get unit vectors along the phi, theta and psi rotation axes
115  
116 < }
116 >    ephi[0] = 0.0;
117 >    ephi[1] = 0.0;
118 >    ephi[2] = 1.0;
119  
120 < void RigidBody::setEuler( double phi, double theta, double psi ){
121 <  
122 <    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);
120 >    etheta[0] = cphi;
121 >    etheta[1] = sphi;
122 >    etheta[2] = 0.0;
123  
124 < }
124 >    epsi[0] = stheta * cphi;
125 >    epsi[1] = stheta * sphi;
126 >    epsi[2] = ctheta;
127  
128 < void RigidBody::getQ( double q[4] ){
129 <  
130 <  double t, s;
131 <  double ad1, ad2, ad3;
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 <  t = A[0][0] + A[1][1] + A[2][2] + 1.0;
141 <  if( t > 0.0 ){
142 <    
143 <    s = 0.5 / sqrt( t );
144 <    q[0] = 0.25 / s;
145 <    q[1] = (A[1][2] - A[2][1]) * s;
146 <    q[2] = (A[2][0] - A[0][2]) * s;
147 <    q[3] = (A[0][1] - A[1][0]) * s;
148 <  }
149 <  else{
150 <    
151 <    ad1 = fabs( A[0][0] );
152 <    ad2 = fabs( A[1][1] );
153 <    ad3 = fabs( A[2][2] );
154 <    
155 <    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;
140 >    return grad;
141 > }    
142 >
143 > void RigidBody::accept(BaseVisitor* v) {
144 >    v->visit(this);
145 > }    
146 >
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 <    else if( ad2 >= ad1 && ad2 >= ad3 ){
158 <      
159 <      s = sqrt( 1.0 + A[1][1] - A[0][0] - A[2][2] ) * 2.0;
160 <      q[0] = (A[0][2] + A[2][0]) / s;
161 <      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;
157 >    refCOM /= mass_;
158 >
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 <    else{
164 <      
165 <      s = sqrt( 1.0 + A[2][2] - A[0][0] - A[1][1] ) * 2.0;
166 <      q[0] = (A[0][1] + A[1][0]) / s;
167 <      q[1] = (A[0][2] + A[2][0]) / s;
168 <      q[2] = (A[1][2] + A[2][1]) / s;
169 <      q[3] = 0.5 / s;
163 >
164 > // Moment of Inertia calculation
165 >    Mat3x3d Itmp(0.0);
166 >  
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      }
163  }
164 }
175  
176 < void RigidBody::setQ( double the_q[4] ){
176 >    //diagonalize
177 >    Vector3d evals;
178 >    Mat3x3d::diagonalize(Itmp, evals, sU_);
179  
180 <  double q0Sqr, q1Sqr, q2Sqr, q3Sqr;
181 <  
182 <  q0Sqr = the_q[0] * the_q[0];
183 <  q1Sqr = the_q[1] * the_q[1];
184 <  q2Sqr = the_q[2] * the_q[2];
185 <  q3Sqr = the_q[3] * the_q[3];
186 <  
187 <  A[0][0] = q0Sqr + q1Sqr - q2Sqr - q3Sqr;
188 <  A[0][1] = 2.0 * ( the_q[1] * the_q[2] + the_q[0] * the_q[3] );
189 <  A[0][2] = 2.0 * ( the_q[1] * the_q[3] - the_q[0] * the_q[2] );
190 <  
191 <  A[1][0] = 2.0 * ( the_q[1] * the_q[2] - the_q[0] * the_q[3] );
192 <  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;  
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 +  
208   }
209  
210 < void RigidBody::getA( double the_A[3][3] ){
211 <  
212 <  for (int i = 0; i < 3; i++)
213 <    for (int j = 0; j < 3; j++)
214 <      the_A[i][j] = A[i][j];
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 < }
220 >        afrc = atoms_[i]->getFrc();
221 >        apos = atoms_[i]->getPos();
222 >        rpos = apos - pos;
223 >        
224 >        frc += afrc;
225  
226 < void RigidBody::setA( double the_A[3][3] ){
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 <  for (int i = 0; i < 3; i++)
231 <    for (int j = 0; j < 3; j++)
232 <      A[i][j] = the_A[i][j];
233 <  
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::getJ( double theJ[3] ){
246 <  
247 <  for (int i = 0; i < 3; i++)
248 <    theJ[i] = ji[i];
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 < }
257 >        apos = pos + ref;
258  
259 < void RigidBody::setJ( double theJ[3] ){
213 <  
214 <  for (int i = 0; i < 3; i++)
215 <    ji[i] = theJ[i];
259 >        atoms_[i]->setPos(apos);
260  
261 +        if (atoms_[i]->isDirectional()) {
262 +          
263 +          dAtom = (DirectionalAtom *) atoms_[i];
264 +          dAtom->setA(a * refOrients_[i]);
265 +          //dAtom->rotateBy( A );      
266 +        }
267 +
268 +    }
269 +  
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 ){
274 <    zAngle += zAng;
275 < }
336 > bool RigidBody::getAtomVel(Vector3d& vel, Atom* atom) {
337  
338 < void RigidBody::calcRefCoords( ) {
339 <
340 <  int i,j,k, it, n_linear_coords;
341 <  double mtmp;
342 <  vec3 apos;
343 <  double refCOM[3];
344 <  vec3 ptmp;
345 <  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;    
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 <  }
305 <  
306 <  for(j = 0; j < 3; j++)
307 <    refCOM[j] /= mass;
347 > }
348  
349 < // Next, move the origin of the reference coordinate system to the COM:
349 > bool RigidBody::getAtomRefCoor(Vector3d& coor, unsigned int index) {
350 >    if (index < atoms_.size()) {
351  
352 <  for (i = 0; i < myAtoms.size(); i++) {
353 <    apos = refCoords[i];
354 <    for (j=0; j < 3; j++) {
355 <      apos[j] = apos[j] - refCOM[j];
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      }
316    refCoords[i] = apos;
317  }
359  
360 < // Moment of Inertia calculation
360 > }
361  
362 <  for (i = 0; i < 3; i++)
363 <    for (j = 0; j < 3; j++)
364 <      Itmp[i][j] = 0.0;  
365 <  
366 <  for (it = 0; it < myAtoms.size(); it++) {
367 <
368 <    mtmp = myAtoms[it]->getMass();
369 <    ptmp = refCoords[it];
370 <    r= norm3(ptmp.vec);
371 <    r2 = r*r;
372 <    
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 <      }
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      }
340  }
341  
342  diagonalize3x3(Itmp, evals, sU);
343  
344  // zero out I and then fill the diagonals with the moments of inertia:
374  
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  }
375   }
376  
389 void RigidBody::doEulerToRotMat(vec3 &euler, mat3x3 &myA ){
377  
378 <  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);
378 > void RigidBody::addAtom(Atom* at, AtomStamp* ats) {
379  
380 < }
381 <
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();
380 >  Vector3d coords;
381 >  Vector3d euler;
382    
422  for (i = 0; i < myAtoms.size(); i++) {
383  
384 <    myAtoms[i]->getPos(apos);
385 <    myAtoms[i]->getFrc(afrc);
386 <
387 <    for (j=0; j<3; j++) {
388 <      rpos[j] = apos[j] - pos[j];
389 <      frc[j] += afrc[j];
390 <    }
391 <    
392 <    trq[0] += rpos[1]*afrc[2] - rpos[2]*afrc[1];
393 <    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 <    }
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 +  coords[0] = ats->getPosX();
397 +  coords[1] = ats->getPosY();
398 +  coords[2] = ats->getPosZ();
399  
400 <  // Convert Torque to Body-fixed coordinates:
449 <  // (Actually, on second thought, don't.  Integrator does this now.)
450 <  // lab2Body(trq);
400 >  refCoords_.push_back(coords);
401  
402 < }
453 <
454 < void RigidBody::updateAtoms() {
455 <  int i, j;
456 <  vec3 ref;
457 <  double apos[3];
458 <  DirectionalAtom* dAtom;
402 >  RotMat3x3d identMat = RotMat3x3d::identity();
403    
404 <  for (i = 0; i < myAtoms.size(); i++) {
461 <    
462 <    ref = refCoords[i];
404 >  if (at->isDirectional()) {  
405  
406 <    body2Lab(ref.vec);
406 >    if( !ats->haveOrientation() ){
407 >      sprintf( painCave.errMsg,
408 >               "RigidBody error.\n"
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 >    }    
415      
416 <    for (j = 0; j<3; j++)
417 <      apos[j] = pos[j] + ref.vec[j];
418 <    
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 < }
416 >    euler[0] = ats->getEulerPhi();
417 >    euler[1] = ats->getEulerTheta();
418 >    euler[2] = ats->getEulerPsi();
419  
420 < void RigidBody::getGrad( double grad[6] ) {
421 <
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++ ) {
420 >    RotMat3x3d Atmp(euler);
421 >    refOrients_.push_back(Atmp);
422      
423 <    grad[3] += trq[j]*ephi[j];
424 <    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