1 /* -------------------------------------------------------------------------- *
2 * BodyDragForce.cpp *
3 * -------------------------------------------------------------------------- *
4 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation. *
5 * See http://opensim.stanford.edu and the NOTICE file for more information. *
6 * OpenSim is developed at Stanford University and supported by the US *
7 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA *
8 * through the Warrior Web program. *
9 * *
10 * Copyright (c) 2005-2017 Stanford University and the Authors *
11 * Author(s): Tim Dorn *
12 * *
13 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
14 * not use this file except in compliance with the License. You may obtain a *
15 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
16 * *
17 * Unless required by applicable law or agreed to in writing, software *
18 * distributed under the License is distributed on an "AS IS" BASIS, *
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied *
20 * See the License for the specific language governing permissions and *
21 * limitations under the License. *
22 * -------------------------------------------------------------------------- */
23
24 //=============================================================================
25 // INCLUDES
26 //=============================================================================
27 #include <OpenSim/Simulation/Model/BodySet.h>
28 #include <OpenSim/Simulation/Model/Model.h>
29 #include "BodyDragForce.h"
30
31 //=============================================================================
32 // STATICS
33 //=============================================================================
34 using namespace std;
35 using namespace SimTK;
36 using namespace OpenSim;
37
38 //=============================================================================
39 // CONSTRUCTOR(S) AND DESTRUCTOR
40 //=============================================================================
41 //_____________________________________________________________________________
42 /**
43 * Default constructor
44 */
BodyDragForce()45 BodyDragForce::BodyDragForce() : Force()
46 {
47 setNull();
48 constructProperties();
49 }
50
51
52
53 //=============================================================================
54 // CONSTRUCTION
55 //=============================================================================
56 //_____________________________________________________________________________
57 /**
58 * Set the data members of this BodyDragForce to their null values.
59 */
setNull()60 void BodyDragForce::setNull()
61 {
62 // no internal data members to initialize.
63 }
64
65 //_____________________________________________________________________________
66 /**
67 * Connect properties to local pointers.
68 */
constructProperties()69 void BodyDragForce::constructProperties()
70 {
71 constructProperty_body_name("Unassigned");
72 constructProperty_coefficient(0.5);
73 constructProperty_exponent(2.0);
74
75 // Here are some examples of other constructing other scalar property types.
76 // Uncomment them as you need them.
77 // ------------------------------------------------------
78 //constructProperty_string_property("defaultString");
79 //constructProperty_int_property(10);
80 //constructProperty_bool_property(true);
81 //constructProperty_double_property(1.5);
82 }
83
84 //_____________________________________________________________________________
85 /**
86 * Perform some set up functions that happen after the
87 * object has been deserialized or copied.
88 *
89 * @param aModel OpenSim model containing this BodyDragForce.
90 */
connectToModel(Model & aModel)91 void BodyDragForce::connectToModel(Model& aModel)
92 {
93 string errorMessage;
94
95 // Base class
96 Super::connectToModel(aModel);
97
98 // Look up the body and report an error if it is not found
99 if (!aModel.updBodySet().contains(get_body_name())) {
100 errorMessage = "Invalid bodyName (" + get_body_name() + ") specified in Force " + getName();
101 throw (Exception(errorMessage.c_str()));
102 }
103 }
104
105
106 //=============================================================================
107 // COMPUTATION
108 //=============================================================================
109
computeForce(const SimTK::State & s,SimTK::Vector_<SimTK::SpatialVec> & bodyForces,SimTK::Vector & generalizedForces) const110 void BodyDragForce::computeForce(const SimTK::State& s,
111 SimTK::Vector_<SimTK::SpatialVec>& bodyForces,
112 SimTK::Vector& generalizedForces) const
113 {
114 if(!_model) return; // some minor error checking
115
116 SimTK::Vec3 bodyCoMPosBody, bodyCoMPosGround, bodyCoMVelGround, bodyCoMVelGroundRaisedPower, dragForceGround, dragForceBody, oppVelSign;
117 BodySet &bs = _model->updBodySet(); // get body set
118 const Ground &ground = _model->getGround(); // get ground body
119 Body &aBody = bs.get(get_body_name()); // get the body to apply the force to
120
121 // get CoM position of body in the BODY coordinate system
122 bodyCoMPosBody = aBody.getMassCenter();
123 // get CoM position of body in the GROUND coordinate system
124 bodyCoMPosGround = aBody.getPositionInGround(s);
125 // get CoM velocity of body in the GROUND coordinate system
126 bodyCoMVelGround = aBody.findStationVelocityInGround(s, bodyCoMPosBody);
127
128 for (int i=0; i<3;i++)
129 {
130 if (bodyCoMVelGround[i]>0) oppVelSign[i] = -1; // get opposite sign of CoM velocity (GROUND coordinate system)
131 if (bodyCoMVelGround[i]<0) oppVelSign[i] = 1;
132 if (bodyCoMVelGround[i]==0) oppVelSign[i] = 0;
133
134 dragForceGround[i] = oppVelSign[i] * get_coefficient() * std::pow(bodyCoMVelGround[i], get_exponent()); // calculate drag force in the GROUND coordinate system
135 }
136
137 // transform drag force into the BODY coordinate system
138 dragForceBody = ground.expressVectorInAnotherFrame(s,
139 dragForceGround,
140 aBody);
141
142 // Apply drag force to the body
143 // ------------------------------
144 // applyForceToPoint requires the force application point to be in the inertial (ground) frame
145 // and the force vector itself to be in the body frame
146 applyForceToPoint(s, aBody, bodyCoMPosGround, dragForceBody, bodyForces);
147
148
149
150
151 // Debuging info
152 // --------------
153 int deb = 0;
154 if (deb)
155 {
156 cout << "Time = " << s.getTime() << endl;
157 cout << aBody.getName() << " CoM position (body frame) = " << bodyCoMPosBody << endl;
158 cout << aBody.getName() << " CoM position (ground frame) = " << bodyCoMPosGround << endl;
159 cout << aBody.getName() << " CoM velocity (ground frame) = " << bodyCoMVelGround << endl;
160 cout << aBody.getName() << " CoM velocity opposite sign (ground frame) = " << oppVelSign << endl;
161 cout << aBody.getName() << " CoM velocity^" << get_exponent() << " (ground frame) = " << bodyCoMVelGroundRaisedPower << endl;
162 cout << "Drag coefficient = " << get_coefficient() << "\tDrag exponent = " << get_exponent() << endl;
163 cout << "dragForce (ground) = " << dragForceGround << endl;
164 cout << "dragForce (body frame) = " << dragForceBody << endl;
165 auto res = system("pause");
166 }
167
168 return;
169 }
170
171 /** Potential energy function */
computePotentialEnergy(const SimTK::State & s) const172 double BodyDragForce::computePotentialEnergy(const SimTK::State& s) const
173 {
174 return 0;
175 }
176
177
178 //=============================================================================
179 // REPORTING
180 //=============================================================================
181 /**
182 * Provide names of the quantities (column labels) of the force value(s) reported
183 *
184 */
getRecordLabels() const185 OpenSim::Array<std::string> BodyDragForce::getRecordLabels() const
186 {
187 OpenSim::Array<std::string> labels("");
188 labels.append(getName()+"."+get_body_name()+".force.X");
189 labels.append(getName()+"."+get_body_name()+".force.Y");
190 labels.append(getName()+"."+get_body_name()+".force.Z");
191 return labels;
192 }
193 /**
194 * Provide the value(s) to be reported that correspond to the labels
195 */
getRecordValues(const SimTK::State & s) const196 OpenSim::Array<double> BodyDragForce::getRecordValues(const SimTK::State& s) const
197 {
198 OpenSim::Array<double> values(3);
199
200 SimTK::Vec3 bodyCoMPosBody, bodyCoMPosGround, bodyCoMVelGround, bodyCoMVelGroundRaisedPower, dragForceGround, dragForceBody, oppVelSign;
201 BodySet &bs = _model->updBodySet(); // get body set
202 const Ground &ground = _model->getGround(); // get ground body
203 Body &aBody = bs.get(get_body_name()); // get the body to apply the force to
204
205 // get CoM position of body in the BODY coordinate system
206 bodyCoMPosBody = aBody.getMassCenter();
207 // get CoM position of body in the GROUND coordinate system
208 bodyCoMPosGround = aBody.getPositionInGround(s);
209 // get CoM velocity of body in the GROUND coordinate system
210 bodyCoMVelGround = aBody.findStationVelocityInGround(s, bodyCoMPosBody);
211
212 for (int i=0; i<3;i++)
213 {
214 if (bodyCoMVelGround[i]>0) oppVelSign[i] = -1; // get opposite sign of CoM velocity (GROUND coordinate system)
215 if (bodyCoMVelGround[i]<0) oppVelSign[i] = 1;
216 if (bodyCoMVelGround[i]==0) oppVelSign[i] = 0;
217
218 dragForceGround[i] = oppVelSign[i] * get_coefficient() * pow(bodyCoMVelGround[i], get_exponent()); // calculate drag force in the GROUND coordinate system
219 values.append(dragForceGround[i]);
220 }
221
222 return values;
223 }
224