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