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