1 /* -------------------------------------------------------------------------- *
2  *                               Simbody(tm)                                  *
3  * -------------------------------------------------------------------------- *
4  * This is part of the SimTK biosimulation toolkit originating from           *
5  * Simbios, the NIH National Center for Physics-Based Simulation of           *
6  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
7  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
8  *                                                                            *
9  * Portions copyright (c) 2008-12 Stanford University and the Authors.        *
10  * Authors: Peter Eastman, Michael Sherman                                    *
11  * Contributors:                                                              *
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 #include "SimTKcommon.h"
25 
26 #include "simbody/internal/common.h"
27 #include "simbody/internal/MobilizedBody.h"
28 #include "simbody/internal/SimbodyMatterSubsystem.h"
29 #include "simbody/internal/MultibodySystem.h"
30 #include "simbody/internal/Force.h"
31 #include "simbody/internal/Force_BuiltIns.h"
32 
33 #include "ForceImpl.h"
34 
35 namespace SimTK {
36 
37 //------------------------------------------------------------------------------
38 //                                  FORCE
39 //------------------------------------------------------------------------------
40 
setDisabledByDefault(bool shouldBeDisabled)41 void Force::setDisabledByDefault(bool shouldBeDisabled)
42 {   updImpl().setDisabledByDefault(shouldBeDisabled); }
isDisabledByDefault() const43 bool Force::isDisabledByDefault() const
44 {   return getImpl().isDisabledByDefault(); }
45 
disable(State & state) const46 void Force::disable(State& state) const
47 {   getForceSubsystem().setForceIsDisabled(state, getForceIndex(), true); }
enable(State & state) const48 void Force::enable(State& state) const
49 {   getForceSubsystem().setForceIsDisabled(state, getForceIndex(), false); }
isDisabled(const State & state) const50 bool Force::isDisabled(const State& state) const
51 {   return getForceSubsystem().isForceDisabled(state, getForceIndex()); }
52 
calcForceContribution(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const53 void Force::calcForceContribution(const State&   state,
54                            Vector_<SpatialVec>&  bodyForces,
55                            Vector_<Vec3>&        particleForces,
56                            Vector&               mobilityForces) const
57 {
58     const MultibodySystem& mbs = getForceSubsystem().getMultibodySystem();
59     const SimbodyMatterSubsystem& matter = mbs.getMatterSubsystem();
60 
61     // Resize if necessary.
62     bodyForces.resize(matter.getNumBodies());
63     particleForces.resize(matter.getNumParticles());
64     mobilityForces.resize(matter.getNumMobilities());
65 
66     // Set all forces to zero.
67     bodyForces.setToZero();
68     particleForces.setToZero();
69     mobilityForces.setToZero();
70     if (isDisabled(state)) return;
71 
72     // Add in force element contributions.
73     getImpl().calcForce(state,bodyForces,particleForces,mobilityForces);
74 }
75 
calcPotentialEnergyContribution(const State & state) const76 Real Force::calcPotentialEnergyContribution(const State& state) const {
77     if (isDisabled(state)) return 0;
78     return getImpl().calcPotentialEnergy(state);
79 }
80 
getForceSubsystem() const81 const GeneralForceSubsystem& Force::getForceSubsystem() const
82 {   return getImpl().getForceSubsystem(); }
getForceIndex() const83 ForceIndex Force::getForceIndex() const
84 {   return getImpl().getForceIndex(); }
85 
86 //-------------------------- TwoPointLinearSpring ------------------------------
87 //------------------------------------------------------------------------------
88 
89 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::TwoPointLinearSpring, Force::TwoPointLinearSpringImpl, Force);
90 
TwoPointLinearSpring(GeneralForceSubsystem & forces,const MobilizedBody & body1,const Vec3 & station1,const MobilizedBody & body2,const Vec3 & station2,Real k,Real x0)91 Force::TwoPointLinearSpring::TwoPointLinearSpring(GeneralForceSubsystem& forces, const MobilizedBody& body1, const Vec3& station1,
92         const MobilizedBody& body2, const Vec3& station2, Real k, Real x0) : Force(new TwoPointLinearSpringImpl(
93         body1, station1, body2, station2, k, x0)) {
94     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
95 }
96 
TwoPointLinearSpringImpl(const MobilizedBody & body1,const Vec3 & station1,const MobilizedBody & body2,const Vec3 & station2,Real k,Real x0)97 Force::TwoPointLinearSpringImpl::TwoPointLinearSpringImpl(const MobilizedBody& body1, const Vec3& station1,
98         const MobilizedBody& body2, const Vec3& station2, Real k, Real x0) : matter(body1.getMatterSubsystem()),
99         body1(body1.getMobilizedBodyIndex()), station1(station1),
100         body2(body2.getMobilizedBodyIndex()), station2(station2), k(k), x0(x0) {
101 }
102 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const103 void Force::TwoPointLinearSpringImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
104     const Transform& X_GB1 = matter.getMobilizedBody(body1).getBodyTransform(state);
105     const Transform& X_GB2 = matter.getMobilizedBody(body2).getBodyTransform(state);
106 
107     const Vec3 s1_G = X_GB1.R() * station1;
108     const Vec3 s2_G = X_GB2.R() * station2;
109 
110     const Vec3 p1_G = X_GB1.p() + s1_G; // station measured from ground origin
111     const Vec3 p2_G = X_GB2.p() + s2_G;
112 
113     const Vec3 r_G       = p2_G - p1_G; // vector from point1 to point2
114     const Real d         = r_G.norm();  // distance between the points
115     const Real stretch   = d - x0;      // + -> tension, - -> compression
116     const Real frcScalar = k*stretch;   // k(x-x0)
117 
118     const Vec3 f1_G = (frcScalar/d) * r_G;
119     bodyForces[body1] +=  SpatialVec(s1_G % f1_G, f1_G);
120     bodyForces[body2] -=  SpatialVec(s2_G % f1_G, f1_G);
121 }
122 
calcPotentialEnergy(const State & state) const123 Real Force::TwoPointLinearSpringImpl::calcPotentialEnergy(const State& state) const {
124     const Transform& X_GB1 = matter.getMobilizedBody(body1).getBodyTransform(state);
125     const Transform& X_GB2 = matter.getMobilizedBody(body2).getBodyTransform(state);
126 
127     const Vec3 s1_G = X_GB1.R() * station1;
128     const Vec3 s2_G = X_GB2.R() * station2;
129 
130     const Vec3 p1_G = X_GB1.p() + s1_G; // station measured from ground origin
131     const Vec3 p2_G = X_GB2.p() + s2_G;
132 
133     const Vec3 r_G = p2_G - p1_G; // vector from point1 to point2
134     const Real d   = r_G.norm();  // distance between the points
135     const Real stretch   = d - x0; // + -> tension, - -> compression
136 
137     return k*stretch*stretch/2; // 1/2 k (x-x0)^2
138 }
139 
140 
141 void Force::TwoPointLinearSpringImpl::
calcDecorativeGeometryAndAppend(const State & state,Stage stage,Array_<DecorativeGeometry> & geom) const142 calcDecorativeGeometryAndAppend(const State& state, Stage stage,
143                                 Array_<DecorativeGeometry>& geom) const {
144     if (stage==Stage::Position && matter.getShowDefaultGeometry()) {
145         const Transform& X_GB1 = matter.getMobilizedBody(body1)
146                                        .getBodyTransform(state);
147         const Transform& X_GB2 = matter.getMobilizedBody(body2)
148                                        .getBodyTransform(state);
149 
150         const Vec3 s1_G = X_GB1.R() * station1;
151         const Vec3 s2_G = X_GB2.R() * station2;
152 
153         const Vec3 p1_G = X_GB1.p() + s1_G; // measured from ground origin
154         const Vec3 p2_G = X_GB2.p() + s2_G;
155 
156         geom.push_back(DecorativeLine(p1_G,p2_G).setColor(Orange));
157     }
158 }
159 
160 
161 //-------------------------- TwoPointLinearDamper ------------------------------
162 //------------------------------------------------------------------------------
163 
164 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::TwoPointLinearDamper, Force::TwoPointLinearDamperImpl, Force);
165 
TwoPointLinearDamper(GeneralForceSubsystem & forces,const MobilizedBody & body1,const Vec3 & station1,const MobilizedBody & body2,const Vec3 & station2,Real damping)166 Force::TwoPointLinearDamper::TwoPointLinearDamper(GeneralForceSubsystem& forces, const MobilizedBody& body1, const Vec3& station1,
167         const MobilizedBody& body2, const Vec3& station2, Real damping) : Force(new TwoPointLinearDamperImpl(
168         body1, station1, body2, station2, damping)) {
169     assert(damping >= 0);
170     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
171 }
172 
TwoPointLinearDamperImpl(const MobilizedBody & body1,const Vec3 & station1,const MobilizedBody & body2,const Vec3 & station2,Real damping)173 Force::TwoPointLinearDamperImpl::TwoPointLinearDamperImpl(const MobilizedBody& body1, const Vec3& station1,
174         const MobilizedBody& body2, const Vec3& station2, Real damping) : matter(body1.getMatterSubsystem()),
175         body1(body1.getMobilizedBodyIndex()), station1(station1),
176         body2(body2.getMobilizedBodyIndex()), station2(station2), damping(damping) {
177 }
178 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const179 void Force::TwoPointLinearDamperImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
180     const Transform& X_GB1 = matter.getMobilizedBody(body1).getBodyTransform(state);
181     const Transform& X_GB2 = matter.getMobilizedBody(body2).getBodyTransform(state);
182 
183     const Vec3 s1_G = X_GB1.R() * station1;
184     const Vec3 s2_G = X_GB2.R() * station2;
185 
186     const Vec3 p1_G = X_GB1.p() + s1_G; // station measured from ground origin
187     const Vec3 p2_G = X_GB2.p() + s2_G;
188 
189     const Vec3 v1_G = matter.getMobilizedBody(body1).findStationVelocityInGround(state, station1);
190     const Vec3 v2_G = matter.getMobilizedBody(body2).findStationVelocityInGround(state, station2);
191     const Vec3 vRel = v2_G - v1_G; // relative velocity
192 
193     const UnitVec3 d(p2_G - p1_G); // direction from point1 to point2
194     const Real frc = damping*dot(vRel, d); // c*v
195 
196     const Vec3 f1_G = frc*d;
197     bodyForces[body1] +=  SpatialVec(s1_G % f1_G, f1_G);
198     bodyForces[body2] -=  SpatialVec(s2_G % f1_G, f1_G);
199 }
200 
calcPotentialEnergy(const State & state) const201 Real Force::TwoPointLinearDamperImpl::calcPotentialEnergy(const State& state) const {
202     return 0;
203 }
204 
205 
206 //-------------------------- TwoPointConstantForce -----------------------------
207 //------------------------------------------------------------------------------
208 
209 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::TwoPointConstantForce, Force::TwoPointConstantForceImpl, Force);
210 
TwoPointConstantForce(GeneralForceSubsystem & forces,const MobilizedBody & body1,const Vec3 & station1,const MobilizedBody & body2,const Vec3 & station2,Real force)211 Force::TwoPointConstantForce::TwoPointConstantForce(GeneralForceSubsystem& forces, const MobilizedBody& body1, const Vec3& station1,
212         const MobilizedBody& body2, const Vec3& station2, Real force) : Force(new TwoPointConstantForceImpl(
213         body1, station1, body2, station2, force)) {
214     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
215 }
216 
TwoPointConstantForceImpl(const MobilizedBody & body1,const Vec3 & station1,const MobilizedBody & body2,const Vec3 & station2,Real force)217 Force::TwoPointConstantForceImpl::TwoPointConstantForceImpl(const MobilizedBody& body1, const Vec3& station1,
218         const MobilizedBody& body2, const Vec3& station2, Real force) : matter(body1.getMatterSubsystem()),
219         body1(body1.getMobilizedBodyIndex()), station1(station1),
220         body2(body2.getMobilizedBodyIndex()), station2(station2), force(force) {
221 }
222 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const223 void Force::TwoPointConstantForceImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
224     const Transform& X_GB1 = matter.getMobilizedBody(body1).getBodyTransform(state);
225     const Transform& X_GB2 = matter.getMobilizedBody(body2).getBodyTransform(state);
226 
227     const Vec3 s1_G = X_GB1.R() * station1;
228     const Vec3 s2_G = X_GB2.R() * station2;
229 
230     const Vec3 p1_G = X_GB1.p() + s1_G; // station measured from ground origin
231     const Vec3 p2_G = X_GB2.p() + s2_G;
232 
233     const Vec3 r_G = p2_G - p1_G; // vector from point1 to point2
234     const Real x   = r_G.norm();  // distance between the points
235     const UnitVec3 d(r_G/x, true);
236 
237     const Vec3 f2_G = force * d;
238     bodyForces[body1] -=  SpatialVec(s1_G % f2_G, f2_G);
239     bodyForces[body2] +=  SpatialVec(s2_G % f2_G, f2_G);
240 }
241 
calcPotentialEnergy(const State & state) const242 Real Force::TwoPointConstantForceImpl::calcPotentialEnergy(const State& state) const {
243     return 0;
244 }
245 
246 
247 //--------------------------- MobilityLinearSpring -----------------------------
248 //------------------------------------------------------------------------------
249 
250 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::MobilityLinearSpring,
251                                         Force::MobilityLinearSpringImpl,
252                                         Force);
253 
254 Force::MobilityLinearSpring::
MobilityLinearSpring(GeneralForceSubsystem & forces,const MobilizedBody & mobod,MobilizerQIndex whichQ,Real defaultStiffness,Real defaultQZero)255 MobilityLinearSpring(GeneralForceSubsystem&  forces,
256                      const MobilizedBody&    mobod,
257                      MobilizerQIndex         whichQ,
258                      Real                    defaultStiffness,
259                      Real                    defaultQZero)
260 :   Force(new MobilityLinearSpringImpl(mobod, whichQ,
261                                        defaultStiffness, defaultQZero))
262 {
263     SimTK_ERRCHK1_ALWAYS(defaultStiffness >= 0,
264         "Force::MobilityLinearSpring::MobilityLinearSpring()",
265         "Stiffness coefficient must be nonnegative "
266         "(defaultStiffness=%g).", defaultStiffness);
267 
268     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
269 }
270 
271 Force::MobilityLinearSpring& Force::MobilityLinearSpring::
setDefaultStiffness(Real defaultStiffness)272 setDefaultStiffness(Real defaultStiffness) {
273     SimTK_ERRCHK1_ALWAYS(defaultStiffness >= 0,
274         "Force::MobilityLinearSpring::setDefaultStiffness()",
275         "Stiffness coefficient must be nonnegative "
276         "(defaultStiffness=%g).", defaultStiffness);
277 
278     MobilityLinearSpringImpl& impl = updImpl();
279     if (impl.m_defaultStiffness != defaultStiffness) {
280         impl.m_defaultStiffness = defaultStiffness;
281         impl.invalidateTopologyCache();
282     }
283     return *this;
284 }
285 
286 
287 Force::MobilityLinearSpring& Force::MobilityLinearSpring::
setDefaultQZero(Real defaultQZero)288 setDefaultQZero(Real defaultQZero) {
289     MobilityLinearSpringImpl& impl = updImpl();
290     if (impl.m_defaultQZero != defaultQZero) {
291         impl.m_defaultQZero = defaultQZero;
292         impl.invalidateTopologyCache();
293     }
294     return *this;
295 }
296 
297 Real Force::MobilityLinearSpring::
getDefaultStiffness() const298 getDefaultStiffness() const
299 {   return getImpl().m_defaultStiffness; }
300 
301 Real Force::MobilityLinearSpring::
getDefaultQZero() const302 getDefaultQZero() const
303 {   return getImpl().m_defaultQZero; }
304 
305 const Force::MobilityLinearSpring& Force::MobilityLinearSpring::
setStiffness(State & state,Real stiffness) const306 setStiffness(State& state, Real stiffness) const {
307     SimTK_ERRCHK1_ALWAYS(stiffness >= 0,
308         "Force::MobilityLinearSpring::setStiffness()",
309         "Stiffness coefficient must be nonnegative "
310         "(stiffness=%g).", stiffness);
311 
312     getImpl().updParams(state).first = stiffness;
313     return *this;
314 }
315 
316 const Force::MobilityLinearSpring& Force::MobilityLinearSpring::
setQZero(State & state,Real qZero) const317 setQZero(State& state, Real qZero) const
318 {   getImpl().updParams(state).second = qZero; return *this; }
319 
320 Real Force::MobilityLinearSpring::
getStiffness(const State & state) const321 getStiffness(const State& state) const
322 {   return getImpl().getParams(state).first; }
323 
324 Real Force::MobilityLinearSpring::
getQZero(const State & state) const325 getQZero(const State& state) const
326 {   return getImpl().getParams(state).second; }
327 
328 Force::MobilityLinearSpringImpl::
MobilityLinearSpringImpl(const MobilizedBody & mobod,MobilizerQIndex whichQ,Real defaultStiffness,Real defaultQZero)329 MobilityLinearSpringImpl(const MobilizedBody&    mobod,
330                          MobilizerQIndex         whichQ,
331                          Real                    defaultStiffness,
332                          Real                    defaultQZero)
333 :   m_matter(mobod.getMatterSubsystem()),
334     m_mobodIx(mobod.getMobilizedBodyIndex()), m_whichQ(whichQ),
335     m_defaultStiffness(defaultStiffness), m_defaultQZero(defaultQZero)
336 {
337 }
338 
339 void Force::MobilityLinearSpringImpl::
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const340 calcForce(const State& state, Vector_<SpatialVec>& bodyForces,
341           Vector_<Vec3>& particleForces, Vector& mobilityForces) const
342 {
343     const MobilizedBody& mb = m_matter.getMobilizedBody(m_mobodIx);
344     const Real q = mb.getOneQ(state, m_whichQ);
345     const std::pair<Real,Real>& params = getParams(state);
346     const Real k = params.first, q0 = params.second;
347     const Real frc = -k*(q-q0);
348     // bug: this is depending on qdot=u
349     mb.applyOneMobilityForce(state, MobilizerUIndex((int)m_whichQ),
350                              frc, mobilityForces);
351 }
352 
353 Real Force::MobilityLinearSpringImpl::
calcPotentialEnergy(const State & state) const354 calcPotentialEnergy(const State& state) const {
355     const MobilizedBody& mb = m_matter.getMobilizedBody(m_mobodIx);
356     const Real q = mb.getOneQ(state, m_whichQ);
357     const std::pair<Real,Real>& params = getParams(state);
358     const Real k = params.first, q0 = params.second;
359     const Real frc = -k*(q-q0);
360     return k*square(q-q0)/2;
361 }
362 
363 
364 
365 //--------------------------- MobilityLinearDamper -----------------------------
366 //------------------------------------------------------------------------------
367 
368 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::MobilityLinearDamper,
369                                         Force::MobilityLinearDamperImpl,
370                                         Force);
371 
372 Force::MobilityLinearDamper::
MobilityLinearDamper(GeneralForceSubsystem & forces,const MobilizedBody & mobod,MobilizerUIndex whichU,Real defaultDamping)373 MobilityLinearDamper(GeneralForceSubsystem& forces,
374                      const MobilizedBody&   mobod,
375                      MobilizerUIndex        whichU,
376                      Real                   defaultDamping)
377 :   Force(new MobilityLinearDamperImpl(mobod, whichU, defaultDamping))
378 {
379     SimTK_ERRCHK1_ALWAYS(defaultDamping >= 0,
380         "Force::MobilityLinearDamper::MobilityLinearDamper()",
381         "Damping coefficient must be nonnegative "
382         "(defaultDamping=%g).", defaultDamping);
383 
384     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
385 }
386 
387 
388 Force::MobilityLinearDamper& Force::MobilityLinearDamper::
setDefaultDamping(Real defaultDamping)389 setDefaultDamping(Real defaultDamping) {
390     SimTK_ERRCHK1_ALWAYS(defaultDamping >= 0,
391         "Force::MobilityLinearDamper::setDefaultDamping()",
392         "Damping coefficient must be nonnegative "
393         "(defaultDamping=%g).", defaultDamping);
394 
395     MobilityLinearDamperImpl& impl = updImpl();
396     if (impl.m_defaultDamping != defaultDamping) {
397         impl.m_defaultDamping = defaultDamping;
398         impl.invalidateTopologyCache();
399     }
400     return *this;
401 }
402 
403 Real Force::MobilityLinearDamper::
getDefaultDamping() const404 getDefaultDamping() const
405 {   return getImpl().m_defaultDamping; }
406 
407 const Force::MobilityLinearDamper& Force::MobilityLinearDamper::
setDamping(State & state,Real damping) const408 setDamping(State& state, Real damping) const
409 {
410     SimTK_ERRCHK1_ALWAYS(damping >= 0,
411         "Force::MobilityLinearDamper::setDamping()",
412         "Damping coefficient must be nonnegative "
413         "(damping=%g).", damping);
414 
415     getImpl().updDamping(state) = damping;
416     return *this;
417 }
418 
419 Real Force::MobilityLinearDamper::
getDamping(const State & state) const420 getDamping(const State& state) const
421 {   return getImpl().getDamping(state); }
422 
423 
424 Force::MobilityLinearDamperImpl::
MobilityLinearDamperImpl(const MobilizedBody & mobod,MobilizerUIndex whichU,Real defaultDamping)425 MobilityLinearDamperImpl(const MobilizedBody&   mobod,
426                          MobilizerUIndex        whichU,
427                          Real                   defaultDamping)
428 :   m_matter(mobod.getMatterSubsystem()),
429     m_mobodIx(mobod.getMobilizedBodyIndex()), m_whichU(whichU),
430     m_defaultDamping(defaultDamping)
431 {
432 }
433 
434 void Force::MobilityLinearDamperImpl::
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const435 calcForce(const State& state, Vector_<SpatialVec>& bodyForces,
436           Vector_<Vec3>& particleForces, Vector& mobilityForces) const
437 {
438     const MobilizedBody& mb = m_matter.getMobilizedBody(m_mobodIx);
439     const Real u = mb.getOneU(state, m_whichU);
440     const Real damping = getDamping(state);
441     const Real frc = -damping*u;
442     mb.applyOneMobilityForce(state, m_whichU, frc, mobilityForces);
443 }
444 
445 Real Force::MobilityLinearDamperImpl::
calcPotentialEnergy(const State & state) const446 calcPotentialEnergy(const State& state) const {
447     return 0;
448 }
449 
450 
451 
452 //-------------------------- MobilityConstantForce -----------------------------
453 //------------------------------------------------------------------------------
454 
455 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::MobilityConstantForce,
456                                         Force::MobilityConstantForceImpl,
457                                         Force);
458 
MobilityConstantForce(GeneralForceSubsystem & forces,const MobilizedBody & mobod,MobilizerUIndex whichU,Real defaultForce)459 Force::MobilityConstantForce::MobilityConstantForce
460    (GeneralForceSubsystem&  forces,
461     const MobilizedBody&    mobod,
462     MobilizerUIndex         whichU,
463     Real                    defaultForce)
464 : Force(new MobilityConstantForceImpl(mobod, whichU, defaultForce)) {
465     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
466 }
467 
468 Force::MobilityConstantForce& Force::MobilityConstantForce::
setDefaultForce(Real defaultForce)469 setDefaultForce(Real defaultForce) {
470     MobilityConstantForceImpl& impl = updImpl();
471     if (impl.m_defaultForce != defaultForce) {
472         impl.m_defaultForce = defaultForce;
473         impl.invalidateTopologyCache();
474     }
475     return *this;
476 }
477 
478 Real Force::MobilityConstantForce::
getDefaultForce() const479 getDefaultForce() const
480 {   return getImpl().m_defaultForce; }
481 
482 void Force::MobilityConstantForce::
setForce(State & state,Real force) const483 setForce(State& state, Real force) const {
484     getImpl().updForce(state) = force;
485 }
486 
487 Real Force::MobilityConstantForce::
getForce(const State & state) const488 getForce(const State& state) const
489 {   return getImpl().getForce(state); }
490 
MobilityConstantForceImpl(const MobilizedBody & mobod,MobilizerUIndex whichU,Real defaultForce)491 Force::MobilityConstantForceImpl::MobilityConstantForceImpl
492    (const MobilizedBody&    mobod,
493     MobilizerUIndex         whichU,
494     Real                    defaultForce)
495 :   m_matter(mobod.getMatterSubsystem()),
496     m_mobodIx(mobod.getMobilizedBodyIndex()), m_whichU(whichU),
497     m_defaultForce(defaultForce)
498 {
499 }
500 
501 void Force::MobilityConstantForceImpl::
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const502 calcForce(const State& state, Vector_<SpatialVec>& bodyForces,
503           Vector_<Vec3>& particleForces, Vector& mobilityForces) const
504 {
505     const MobilizedBody& mb = m_matter.getMobilizedBody(m_mobodIx);
506     mb.applyOneMobilityForce(state, m_whichU, getForce(state), mobilityForces);
507 }
508 
509 
510 //---------------------------- MobilityLinearStop ------------------------------
511 //------------------------------------------------------------------------------
512 
513 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::MobilityLinearStop,
514                                         Force::MobilityLinearStopImpl,
515                                         Force);
516 
MobilityLinearStop(GeneralForceSubsystem & forces,const MobilizedBody & mobod,MobilizerQIndex whichQ,Real defaultStiffness,Real defaultDissipation,Real defaultQLow,Real defaultQHigh)517 Force::MobilityLinearStop::MobilityLinearStop
518    (GeneralForceSubsystem&    forces,
519     const MobilizedBody&      mobod,
520     MobilizerQIndex           whichQ,
521     Real                      defaultStiffness,
522     Real                      defaultDissipation,
523     Real                      defaultQLow,
524     Real                      defaultQHigh)
525 :   Force(new MobilityLinearStopImpl(mobod,whichQ,
526                                      defaultStiffness, defaultDissipation,
527                                      defaultQLow, defaultQHigh))
528 {
529     SimTK_ERRCHK2_ALWAYS(defaultStiffness >= 0 && defaultDissipation >= 0,
530         "Force::MobilityLinearStop::MobilityLinearStop()",
531         "Stiffness and dissipation coefficient must be nonnegative "
532         "(defaultStiffness=%g, defaultDissipation=%g).",
533         defaultStiffness, defaultDissipation);
534     SimTK_ERRCHK2_ALWAYS(defaultQLow <= defaultQHigh,
535         "Force::MobilityLinearStop::MobilityLinearStop()",
536         "Lower bound can't be larger than upper bound "
537         "(defaultQLow=%g, defaultQHigh=%g).",
538         defaultQLow, defaultQHigh);
539 
540     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
541 }
542 
543 Force::MobilityLinearStop& Force::MobilityLinearStop::
setDefaultBounds(Real defaultQLow,Real defaultQHigh)544 setDefaultBounds(Real defaultQLow, Real defaultQHigh) {
545     SimTK_ERRCHK2_ALWAYS(defaultQLow <= defaultQHigh,
546         "Force::MobilityLinearStop::setDefaultBounds()",
547         "Lower bound can't be larger than upper bound "
548         "(defaultQLow=%g, defaultQHigh=%g).",
549         defaultQLow, defaultQHigh);
550 
551     MobilityLinearStopImpl& impl = updImpl();
552     if (impl.m_defQLow != defaultQLow || impl.m_defQHigh != defaultQHigh) {
553         impl.m_defQLow = defaultQLow;
554         impl.m_defQHigh = defaultQHigh;
555         impl.invalidateTopologyCache();
556     }
557     return *this;
558 }
559 
560 Force::MobilityLinearStop& Force::MobilityLinearStop::
setDefaultMaterialProperties(Real defaultStiffness,Real defaultDissipation)561 setDefaultMaterialProperties(Real defaultStiffness, Real defaultDissipation) {
562     SimTK_ERRCHK2_ALWAYS(defaultStiffness >= 0 && defaultDissipation >= 0,
563         "Force::MobilityLinearStop::setDefaultMaterialProperties()",
564         "Stiffness and dissipation coefficient must be nonnegative "
565         "(defaultStiffness=%g, defaultDissipation=%g).",
566         defaultStiffness, defaultDissipation);
567 
568     MobilityLinearStopImpl& impl = updImpl();
569     if (   impl.m_defStiffness   != defaultStiffness
570         || impl.m_defDissipation != defaultDissipation) {
571         impl.m_defStiffness = defaultStiffness;
572         impl.m_defDissipation = defaultDissipation;
573         impl.invalidateTopologyCache();
574     }
575     return *this;
576 }
577 
getDefaultLowerBound() const578 Real Force::MobilityLinearStop::getDefaultLowerBound() const
579 {   return getImpl().m_defQLow; }
getDefaultUpperBound() const580 Real Force::MobilityLinearStop::getDefaultUpperBound() const
581 {   return getImpl().m_defQHigh; }
getDefaultStiffness() const582 Real Force::MobilityLinearStop::getDefaultStiffness() const
583 {   return getImpl().m_defStiffness; }
getDefaultDissipation() const584 Real Force::MobilityLinearStop::getDefaultDissipation() const
585 {   return getImpl().m_defDissipation; }
586 
587 
588 void Force::MobilityLinearStop::
setBounds(State & state,Real qLow,Real qHigh) const589 setBounds(State& state, Real qLow, Real qHigh) const {
590     SimTK_ERRCHK2_ALWAYS(qLow <= qHigh,
591         "Force::MobilityLinearStop::setBounds()",
592         "Lower bound can't be larger than upper bound (qLow=%g, qHigh=%g).",
593         qLow, qHigh);
594 
595     MobilityLinearStopImpl::Parameters& params =
596         getImpl().updParameters(state); // invalidates Dynamics stage
597     params.qLow = qLow; params.qHigh = qHigh;
598 }
599 void Force::MobilityLinearStop::
setMaterialProperties(State & state,Real stiffness,Real dissipation) const600 setMaterialProperties(State& state, Real stiffness, Real dissipation) const {
601     SimTK_ERRCHK2_ALWAYS(stiffness >= 0 && dissipation >= 0,
602         "Force::MobilityLinearStop::setMaterialProperties()",
603         "Stiffness and dissipation coefficient must be nonnegative "
604         "(stiffness=%g, dissipation=%g).",
605         stiffness, dissipation);
606 
607     MobilityLinearStopImpl::Parameters& params =
608         getImpl().updParameters(state); // invalidates Dynamics stage
609     params.k = stiffness; params.d = dissipation;
610 }
611 
getLowerBound(const State & state) const612 Real Force::MobilityLinearStop::getLowerBound(const State& state) const
613 {   return getImpl().getParameters(state).qLow; }
getUpperBound(const State & state) const614 Real Force::MobilityLinearStop::getUpperBound(const State& state) const
615 {   return getImpl().getParameters(state).qHigh; }
getStiffness(const State & state) const616 Real Force::MobilityLinearStop::getStiffness(const State& state) const
617 {   return getImpl().getParameters(state).k; }
getDissipation(const State & state) const618 Real Force::MobilityLinearStop::getDissipation(const State& state) const
619 {   return getImpl().getParameters(state).d; }
620 
621 
MobilityLinearStopImpl(const MobilizedBody & mobod,MobilizerQIndex whichQ,Real defaultStiffness,Real defaultDissipation,Real defaultQLow,Real defaultQHigh)622 Force::MobilityLinearStopImpl::MobilityLinearStopImpl
623    (const MobilizedBody&      mobod,
624     MobilizerQIndex           whichQ,
625     Real                      defaultStiffness,
626     Real                      defaultDissipation,
627     Real                      defaultQLow,
628     Real                      defaultQHigh)
629 :   m_matter(mobod.getMatterSubsystem()),
630     m_mobodIx(mobod.getMobilizedBodyIndex()), m_whichQ(whichQ),
631     m_defStiffness(defaultStiffness), m_defDissipation(defaultDissipation),
632     m_defQLow(defaultQLow), m_defQHigh(defaultQHigh)
633 {
634 }
635 
636 
637 void Force::MobilityLinearStopImpl::
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const638 calcForce(const State& state, Vector_<SpatialVec>& bodyForces,
639           Vector_<Vec3>& particleForces, Vector& mobilityForces) const
640 {
641     const Parameters& param = getParameters(state);
642     if (param.k == 0) return; // no stiffness, no force
643 
644     const MobilizedBody& mb = m_matter.getMobilizedBody(m_mobodIx);
645     const Real q = mb.getOneQ(state, m_whichQ);
646 
647     // Don't ask for velocity-dependent qdot if there is no dissipation.
648     const Real qdot = param.d != 0 ? mb.getOneQDot(state, m_whichQ)
649                                    : Real(0);
650 
651     if (q > param.qHigh) {
652         const Real x = q-param.qHigh;  // x > 0
653         const Real fraw = param.k*x*(1+param.d*qdot); // should be >= 0
654         mb.applyOneMobilityForce(state,
655             MobilizerUIndex(m_whichQ), // TODO: only works qdot & u match
656             std::min(Real(0), -fraw), mobilityForces);
657     } else if (q < param.qLow) {
658         const Real x = q-param.qLow;    // x < 0
659         const Real fraw = param.k*x*(1-param.d*qdot); // should be <= 0
660         mb.applyOneMobilityForce(state,
661             MobilizerUIndex(m_whichQ), // TODO: only works qdot & u match
662             std::max(Real(0), -fraw), mobilityForces);
663     }
664 }
665 
666 Real Force::MobilityLinearStopImpl::
calcPotentialEnergy(const State & state) const667 calcPotentialEnergy(const State& state) const {
668     const Parameters& param = getParameters(state);
669     if (param.k == 0) return 0; // no stiffness, no energy stored
670 
671     const MobilizedBody& mb = m_matter.getMobilizedBody(m_mobodIx);
672     const Real q = mb.getOneQ(state, m_whichQ);
673     Real x = 0;
674     if      (q > param.qHigh) x = q-param.qHigh;
675     else if (q < param.qLow)  x = q-param.qLow;
676     else return 0; // neither stop is engaged
677 
678     return param.k*x*x/2;  // 1/2 k x^2
679 }
680 
681 //-------------------------- MobilityDiscreteForce -----------------------------
682 //------------------------------------------------------------------------------
683 
684 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::MobilityDiscreteForce,
685                                         Force::MobilityDiscreteForceImpl,
686                                         Force);
687 
MobilityDiscreteForce(GeneralForceSubsystem & forces,const MobilizedBody & mobod,MobilizerUIndex whichU,Real defaultForce)688 Force::MobilityDiscreteForce::MobilityDiscreteForce
689    (GeneralForceSubsystem& forces, const MobilizedBody& mobod,
690     MobilizerUIndex whichU, Real defaultForce)
691 :   Force(new MobilityDiscreteForceImpl(mobod, whichU, defaultForce)) {
692     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
693 }
694 
695 Force::MobilityDiscreteForce& Force::MobilityDiscreteForce::
setDefaultMobilityForce(Real defaultForce)696 setDefaultMobilityForce(Real defaultForce) {
697     updImpl().m_defaultVal = defaultForce;
698     getImpl().invalidateTopologyCache();
699     return *this;
700 }
701 
702 Real Force::MobilityDiscreteForce::
getDefaultMobilityForce() const703 getDefaultMobilityForce() const {
704     return getImpl().m_defaultVal;
705 }
706 
707 void Force::MobilityDiscreteForce::
setMobilityForce(State & state,Real f) const708 setMobilityForce(State& state, Real f) const {
709     getImpl().setMobilityForce(state, f);
710 }
711 
712 Real Force::MobilityDiscreteForce::
getMobilityForce(const State & state) const713 getMobilityForce(const State& state) const {
714     return getImpl().getMobilityForce(state);
715 }
716 
MobilityDiscreteForceImpl(const MobilizedBody & mobod,MobilizerUIndex whichU,Real defaultForce)717 Force::MobilityDiscreteForceImpl::MobilityDiscreteForceImpl
718    (const MobilizedBody& mobod, MobilizerUIndex whichU, Real defaultForce)
719 :   m_matter(mobod.getMatterSubsystem()),
720     m_mobodIx(mobod.getMobilizedBodyIndex()),
721     m_whichU(whichU), m_defaultVal(defaultForce) {
722 }
723 
724 void Force::MobilityDiscreteForceImpl::
setMobilityForce(State & state,Real f) const725 setMobilityForce(State& state, Real f) const {
726     const GeneralForceSubsystem& forces = getForceSubsystem();
727     Real& fInState = Value<Real>::updDowncast
728                             (forces.updDiscreteVariable(state, m_forceIx));
729     fInState = f;
730 }
731 
732 // Get the value of the generalized force to be applied.
733 Real Force::MobilityDiscreteForceImpl::
getMobilityForce(const State & state) const734 getMobilityForce(const State& state) const {
735     const GeneralForceSubsystem& forces = getForceSubsystem();
736     const Real& fInState = Value<Real>::downcast
737                             (forces.getDiscreteVariable(state, m_forceIx));
738     return fInState;
739 }
740 
741 void Force::MobilityDiscreteForceImpl::
calcForce(const State & state,Vector_<SpatialVec> &,Vector_<Vec3> &,Vector & mobilityForces) const742 calcForce(  const State&         state,
743             Vector_<SpatialVec>& /*bodyForces*/,
744             Vector_<Vec3>&       /*particleForces*/,
745             Vector&              mobilityForces) const
746 {
747     const GeneralForceSubsystem& forces = getForceSubsystem();
748     const Real f = Value<Real>::downcast
749                             (forces.getDiscreteVariable(state, m_forceIx));
750     const MobilizedBody& mobod = m_matter.getMobilizedBody(m_mobodIx);
751     mobod.applyOneMobilityForce(state, m_whichU, f, mobilityForces);
752 }
753 
754 void Force::MobilityDiscreteForceImpl::
realizeTopology(State & state) const755 realizeTopology(State& state) const {
756     const GeneralForceSubsystem& forces = getForceSubsystem();
757     m_forceIx = forces.allocateDiscreteVariable
758         (state, Stage::Dynamics, new Value<Real>(m_defaultVal));
759 }
760 
761 
762 
763 
764 //------------------------------ DiscreteForces --------------------------------
765 //------------------------------------------------------------------------------
766 
767 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::DiscreteForces,
768                                         Force::DiscreteForcesImpl,
769                                         Force);
770 
DiscreteForces(GeneralForceSubsystem & forces,const SimbodyMatterSubsystem & matter)771 Force::DiscreteForces::DiscreteForces
772    (GeneralForceSubsystem& forces, const SimbodyMatterSubsystem& matter)
773 :   Force(new DiscreteForcesImpl(matter)) {
774     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
775 }
776 
777 void Force::DiscreteForces::
clearAllMobilityForces(State & state) const778 clearAllMobilityForces(State& state) const {
779     getImpl().updAllMobilityForces(state).clear(); // set size to zero
780 }
781 
782 
783 void Force::DiscreteForces::
clearAllBodyForces(State & state) const784 clearAllBodyForces(State& state) const {
785     getImpl().updAllBodyForces(state).clear(); // set size to zero
786 }
787 
788 void Force::DiscreteForces::
setOneMobilityForce(State & state,const MobilizedBody & mobod,MobilizerUIndex whichU,Real f) const789 setOneMobilityForce(State& state, const MobilizedBody& mobod,
790                     MobilizerUIndex whichU, Real f) const {
791     Vector& mobForces = getImpl().updAllMobilityForces(state);
792     if (mobForces.size() == 0) {
793         mobForces.resize(state.getNU());
794         mobForces.setToZero();
795     }
796     // Don't use "apply" here because that would add in the force.
797     mobod.updOneFromUPartition(state, whichU, mobForces) = f;
798 }
799 
800 Real Force::DiscreteForces::
getOneMobilityForce(const State & state,const MobilizedBody & mobod,MobilizerUIndex whichU) const801 getOneMobilityForce(const State& state, const MobilizedBody& mobod,
802                     MobilizerUIndex whichU) const {
803     const Vector& mobForces = getImpl().getAllMobilityForces(state);
804     if (mobForces.size() == 0) {return 0;}
805 
806     return mobod.getOneFromUPartition(state, whichU, mobForces);
807 }
808 
809 
810 void Force::DiscreteForces::
setAllMobilityForces(State & state,const Vector & f) const811 setAllMobilityForces(State& state, const Vector& f) const {
812     if (f.size()==0) {clearAllMobilityForces(state); return;}
813     SimTK_ERRCHK2_ALWAYS(f.size() == state.getNU(),
814         "Force::DiscreteForces::setAllMobilityForces()",
815         "Mobility force vector f had wrong size %d; should have been %d.",
816         f.size(), state.getNU());
817 
818     getImpl().updAllMobilityForces(state) = f;
819 }
820 
821 const Vector& Force::DiscreteForces::
getAllMobilityForces(const State & state) const822 getAllMobilityForces(const State& state) const
823 {   return getImpl().getAllMobilityForces(state); }
824 
825 void Force::DiscreteForces::
setOneBodyForce(State & state,const MobilizedBody & mobod,const SpatialVec & spatialForceInG) const826 setOneBodyForce(State& state, const MobilizedBody& mobod,
827                 const SpatialVec& spatialForceInG) const {
828     Vector_<SpatialVec>& bodyForces = getImpl().updAllBodyForces(state);
829     if (bodyForces.size() == 0) {
830         bodyForces.resize(getImpl().m_matter.getNumBodies());
831         bodyForces.setToZero();
832     }
833     bodyForces[mobod.getMobilizedBodyIndex()] = spatialForceInG;
834 }
835 
836 
837 SpatialVec Force::DiscreteForces::
getOneBodyForce(const State & state,const MobilizedBody & mobod) const838 getOneBodyForce(const State& state, const MobilizedBody& mobod) const {
839     const Vector_<SpatialVec>& bodyForces = getImpl().getAllBodyForces(state);
840     if (bodyForces.size() == 0) {return SpatialVec(Vec3(0),Vec3(0));}
841 
842     return bodyForces[mobod.getMobilizedBodyIndex()];
843 }
844 
845 const Vector_<SpatialVec>& Force::DiscreteForces::
getAllBodyForces(const State & state) const846 getAllBodyForces(const State& state) const
847 {   return getImpl().getAllBodyForces(state); }
848 
849 void Force::DiscreteForces::
setAllBodyForces(State & state,const Vector_<SpatialVec> & bodyForcesInG) const850 setAllBodyForces(State& state, const Vector_<SpatialVec>& bodyForcesInG) const {
851     if (bodyForcesInG.size()==0) {clearAllBodyForces(state); return;}
852     const int numBodies = getImpl().m_matter.getNumBodies();
853     SimTK_ERRCHK2_ALWAYS(bodyForcesInG.size() == numBodies,
854       "Force::DiscreteForces::setAllBodyForces()",
855       "Body force vector bodyForcesInG had wrong size %d; "
856       "should have been %d (0th entry is for Ground).",
857       bodyForcesInG.size(), numBodies);
858 
859     getImpl().updAllBodyForces(state) = bodyForcesInG;
860 }
861 
862 
863 void Force::DiscreteForces::
addForceToBodyPoint(State & state,const MobilizedBody & mobod,const Vec3 & pointInB,const Vec3 & forceInG) const864 addForceToBodyPoint(State& state, const MobilizedBody& mobod,
865                     const Vec3& pointInB, const Vec3& forceInG) const {
866     Vector_<SpatialVec>& bodyForces = getImpl().updAllBodyForces(state);
867     if (bodyForces.size() == 0) {
868         bodyForces.resize(getImpl().m_matter.getNumBodies());
869         bodyForces.setToZero();
870     }
871     mobod.applyForceToBodyPoint(state, pointInB, forceInG, bodyForces);
872 }
873 
DiscreteForcesImpl(const SimbodyMatterSubsystem & matter)874 Force::DiscreteForcesImpl::DiscreteForcesImpl
875    (const SimbodyMatterSubsystem& matter) : m_matter(matter) {}
876 
877 const Vector& Force::DiscreteForcesImpl::
getAllMobilityForces(const State & state) const878 getAllMobilityForces(const State& state) const {
879     const GeneralForceSubsystem& forces = getForceSubsystem();
880     const Vector& fInState = Value<Vector>::downcast
881                             (forces.getDiscreteVariable(state, m_mobForcesIx));
882     return fInState;
883 }
884 
885 Vector& Force::DiscreteForcesImpl::
updAllMobilityForces(State & state) const886 updAllMobilityForces(State& state) const  {
887     const GeneralForceSubsystem& forces = getForceSubsystem();
888     Vector& fInState = Value<Vector>::updDowncast
889                             (forces.updDiscreteVariable(state, m_mobForcesIx));
890     return fInState;
891 }
892 
893 const Vector_<SpatialVec>& Force::DiscreteForcesImpl::
getAllBodyForces(const State & state) const894 getAllBodyForces(const State& state) const {
895     const GeneralForceSubsystem& forces = getForceSubsystem();
896     const Vector_<SpatialVec>& FInState = Value< Vector_<SpatialVec> >::downcast
897                             (forces.getDiscreteVariable(state, m_bodyForcesIx));
898     return FInState;
899 }
900 Vector_<SpatialVec>& Force::DiscreteForcesImpl::
updAllBodyForces(State & state) const901 updAllBodyForces(State& state) const {
902     const GeneralForceSubsystem& forces = getForceSubsystem();
903     Vector_<SpatialVec>& FInState = Value< Vector_<SpatialVec> >::updDowncast
904                             (forces.updDiscreteVariable(state, m_bodyForcesIx));
905     return FInState;
906 }
907 
908 void Force::DiscreteForcesImpl::
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> &,Vector & mobilityForces) const909 calcForce(  const State&         state,
910             Vector_<SpatialVec>& bodyForces,
911             Vector_<Vec3>&       /*particleForces*/,
912             Vector&              mobilityForces) const
913 {
914     const GeneralForceSubsystem& forces = getForceSubsystem();
915     const Vector& f = Value<Vector>::downcast
916                             (forces.getDiscreteVariable(state, m_mobForcesIx));
917     const Vector_<SpatialVec>& F = Value< Vector_<SpatialVec> >::downcast
918                             (forces.getDiscreteVariable(state, m_bodyForcesIx));
919     if (f.size()) mobilityForces += f;
920     if (F.size()) bodyForces += F;
921 }
922 
923 void Force::DiscreteForcesImpl::
realizeTopology(State & state) const924 realizeTopology(State& state) const {
925     const GeneralForceSubsystem& forces = getForceSubsystem();
926     m_mobForcesIx = forces.allocateDiscreteVariable
927         (state, Stage::Dynamics, new Value<Vector>());
928     m_bodyForcesIx = forces.allocateDiscreteVariable
929         (state, Stage::Dynamics, new Value< Vector_<SpatialVec> >());
930 }
931 
932 
933 
934 //------------------------------ ConstantForce ---------------------------------
935 //------------------------------------------------------------------------------
936 
937 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::ConstantForce, Force::ConstantForceImpl, Force);
938 
ConstantForce(GeneralForceSubsystem & forces,const MobilizedBody & body,const Vec3 & station,const Vec3 & force)939 Force::ConstantForce::ConstantForce(GeneralForceSubsystem& forces, const MobilizedBody& body, const Vec3& station, const Vec3& force) :
940         Force(new ConstantForceImpl(body, station, force)) {
941     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
942 }
943 
ConstantForceImpl(const MobilizedBody & body,const Vec3 & station,const Vec3 & force)944 Force::ConstantForceImpl::ConstantForceImpl(const MobilizedBody& body, const Vec3& station, const Vec3& force) :
945         matter(body.getMatterSubsystem()), body(body.getMobilizedBodyIndex()), station(station), force(force) {
946 }
947 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const948 void Force::ConstantForceImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
949     const Transform& X_GB = matter.getMobilizedBody(body).getBodyTransform(state);
950     const Vec3 station_G = X_GB.R() * station;
951     bodyForces[body] += SpatialVec(station_G % force, force);
952 }
953 
calcPotentialEnergy(const State & state) const954 Real Force::ConstantForceImpl::calcPotentialEnergy(const State& state) const {
955     return 0;
956 }
957 
958 
959 //------------------------------ ConstantTorque --------------------------------
960 //------------------------------------------------------------------------------
961 
962 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::ConstantTorque, Force::ConstantTorqueImpl, Force);
963 
ConstantTorque(GeneralForceSubsystem & forces,const MobilizedBody & body,const Vec3 & torque)964 Force::ConstantTorque::ConstantTorque(GeneralForceSubsystem& forces, const MobilizedBody& body, const Vec3& torque) :
965         Force(new ConstantTorqueImpl(body, torque)) {
966     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
967 }
968 
ConstantTorqueImpl(const MobilizedBody & body,const Vec3 & torque)969 Force::ConstantTorqueImpl::ConstantTorqueImpl(const MobilizedBody& body, const Vec3& torque) :
970         matter(body.getMatterSubsystem()), body(body.getMobilizedBodyIndex()), torque(torque) {
971 }
972 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const973 void Force::ConstantTorqueImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
974     bodyForces[body][0] += torque;
975 }
976 
calcPotentialEnergy(const State & state) const977 Real Force::ConstantTorqueImpl::calcPotentialEnergy(const State& state) const {
978     return 0;
979 }
980 
981 
982 //------------------------------- GlobalDamper ---------------------------------
983 //------------------------------------------------------------------------------
984 
985 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::GlobalDamper, Force::GlobalDamperImpl, Force);
986 
GlobalDamper(GeneralForceSubsystem & forces,const SimbodyMatterSubsystem & matter,Real damping)987 Force::GlobalDamper::GlobalDamper(GeneralForceSubsystem& forces, const SimbodyMatterSubsystem& matter,
988         Real damping) : Force(new GlobalDamperImpl(matter, damping)) {
989     assert(damping >= 0);
990     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
991 }
992 
GlobalDamperImpl(const SimbodyMatterSubsystem & matter,Real damping)993 Force::GlobalDamperImpl::GlobalDamperImpl(const SimbodyMatterSubsystem& matter, Real damping) : matter(matter), damping(damping) {
994 }
995 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const996 void Force::GlobalDamperImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
997     mobilityForces -= damping*matter.getU(state);
998 }
999 
calcPotentialEnergy(const State & state) const1000 Real Force::GlobalDamperImpl::calcPotentialEnergy(const State& state) const {
1001     return 0;
1002 }
1003 
1004 
1005 //------------------------------ UniformGravity --------------------------------
1006 //------------------------------------------------------------------------------
1007 
1008 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::UniformGravity, Force::UniformGravityImpl, Force);
1009 
UniformGravity(GeneralForceSubsystem & forces,const SimbodyMatterSubsystem & matter,const Vec3 & g,Real zeroHeight)1010 Force::UniformGravity::UniformGravity(GeneralForceSubsystem& forces, const SimbodyMatterSubsystem& matter,
1011         const Vec3& g, Real zeroHeight) : Force(new UniformGravityImpl(matter, g, zeroHeight)) {
1012     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
1013 }
1014 
getGravity() const1015 Vec3 Force::UniformGravity::getGravity() const {
1016     return getImpl().getGravity();
1017 }
1018 
setGravity(const Vec3 & g)1019 void Force::UniformGravity::setGravity(const Vec3& g) {
1020     updImpl().setGravity(g);
1021 }
1022 
getZeroHeight() const1023 Real Force::UniformGravity::getZeroHeight() const {
1024     return getImpl().getZeroHeight();
1025 }
1026 
setZeroHeight(Real height)1027 void Force::UniformGravity::setZeroHeight(Real height) {
1028     updImpl().setZeroHeight(height);
1029 }
1030 
UniformGravityImpl(const SimbodyMatterSubsystem & matter,const Vec3 & g,Real zeroHeight)1031 Force::UniformGravityImpl::UniformGravityImpl(const SimbodyMatterSubsystem& matter, const Vec3& g, Real zeroHeight) : matter(matter), g(g), zeroHeight(zeroHeight) {
1032 }
1033 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const1034 void Force::UniformGravityImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
1035     const int nBodies    = matter.getNumBodies();
1036     const int nParticles = matter.getNumParticles();
1037 
1038     if (nParticles) {
1039         const Vector& m = matter.getAllParticleMasses(state);
1040         const Vector_<Vec3>& loc_G = matter.getAllParticleLocations(state);
1041         for (int i=0; i < nParticles; ++i) {
1042             particleForces[i] += g * m[i];
1043         }
1044     }
1045 
1046     // no need to apply gravity to Ground!
1047     for (MobilizedBodyIndex i(1); i < nBodies; ++i) {
1048         const MassProperties& mprops = matter.getMobilizedBody(i).getBodyMassProperties(state);
1049         const Real&      m       = mprops.getMass();
1050         const Vec3&      com_B   = mprops.getMassCenter();
1051         const Transform& X_GB    = matter.getMobilizedBody(i).getBodyTransform(state);
1052         const Vec3       com_B_G = X_GB.R()*com_B;
1053         const Vec3       frc_G   = m*g;
1054 
1055         bodyForces[i] += SpatialVec(com_B_G % frc_G, frc_G);
1056     }
1057 }
1058 
calcPotentialEnergy(const State & state) const1059 Real Force::UniformGravityImpl::calcPotentialEnergy(const State& state) const {
1060     const int nBodies    = matter.getNumBodies();
1061     const int nParticles = matter.getNumParticles();
1062     Real pe = 0.0;
1063 
1064     if (nParticles) {
1065         const Vector& m = matter.getAllParticleMasses(state);
1066         const Vector_<Vec3>& loc_G = matter.getAllParticleLocations(state);
1067         for (int i=0; i < nParticles; ++i) {
1068             pe -= m[i]*(~g*loc_G[i] + zeroHeight); // odd signs because height is in -g direction
1069         }
1070     }
1071 
1072     // no need to apply gravity to Ground!
1073     for (MobilizedBodyIndex i(1); i < nBodies; ++i) {
1074         const MassProperties& mprops = matter.getMobilizedBody(i).getBodyMassProperties(state);
1075         const Real&      m       = mprops.getMass();
1076         const Vec3&      com_B   = mprops.getMassCenter();
1077         const Transform& X_GB    = matter.getMobilizedBody(i).getBodyTransform(state);
1078         const Vec3       com_B_G = X_GB.R()*com_B;
1079         const Vec3       com_G   = X_GB.p() + com_B_G;
1080 
1081         pe -= m*(~g*com_G + zeroHeight); // odd signs because height is in -g direction
1082     }
1083     return pe;
1084 }
1085 
1086 
1087 //---------------------------------- Custom ------------------------------------
1088 //------------------------------------------------------------------------------
1089 
1090 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Force::Custom, Force::CustomImpl, Force);
1091 
Custom(GeneralForceSubsystem & forces,Implementation * implementation)1092 Force::Custom::Custom(GeneralForceSubsystem& forces, Implementation* implementation) :
1093         Force(new CustomImpl(implementation)) {
1094     updImpl().setForceSubsystem(forces, forces.adoptForce(*this));
1095 }
1096 
getImplementation() const1097 const Force::Custom::Implementation& Force::Custom::getImplementation() const {
1098     return getImpl().getImplementation();
1099 }
1100 
updImplementation()1101 Force::Custom::Implementation& Force::Custom::updImplementation() {
1102     return updImpl().updImplementation();
1103 }
1104 
1105 
CustomImpl(Force::Custom::Implementation * implementation)1106 Force::CustomImpl::CustomImpl(Force::Custom::Implementation* implementation) : implementation(implementation) {
1107 }
1108 
calcForce(const State & state,Vector_<SpatialVec> & bodyForces,Vector_<Vec3> & particleForces,Vector & mobilityForces) const1109 void Force::CustomImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
1110     implementation->calcForce(state, bodyForces, particleForces, mobilityForces);
1111 }
1112 
calcPotentialEnergy(const State & state) const1113 Real Force::CustomImpl::calcPotentialEnergy(const State& state) const {
1114     return implementation->calcPotentialEnergy(state);
1115 }
1116 
1117 } // namespace SimTK
1118 
1119