1 /* -------------------------------------------------------------------------- *
2 * OpenSim: HuntCrossleyForce.cpp *
3 * -------------------------------------------------------------------------- *
4 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation. *
5 * See http://opensim.stanford.edu and the NOTICE file for more information. *
6 * OpenSim is developed at Stanford University and supported by the US *
7 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA *
8 * through the Warrior Web program. *
9 * *
10 * Copyright (c) 2005-2017 Stanford University and the Authors *
11 * Author(s): Peter Eastman *
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 "HuntCrossleyForce.h"
25 #include "ContactGeometry.h"
26 #include "Model.h"
27
28 #include "simbody/internal/HuntCrossleyForce.h"
29
30 namespace OpenSim {
31
32 //==============================================================================
33 // HUNT CROSSLEY FORCE
34 //==============================================================================
35 // Uses default (compiler-generated) destructor, copy constructor, copy
36 // assignment operator.
37
38 // Default constructor.
HuntCrossleyForce()39 HuntCrossleyForce::HuntCrossleyForce()
40 {
41 constructProperties();
42 }
43
44 // Take over ownership of supplied object.
HuntCrossleyForce(ContactParameters * params)45 HuntCrossleyForce::HuntCrossleyForce(ContactParameters* params)
46 {
47 constructProperties();
48 addContactParameters(params);
49 }
50
51
extendAddToSystem(SimTK::MultibodySystem & system) const52 void HuntCrossleyForce::extendAddToSystem(SimTK::MultibodySystem& system) const
53 {
54 Super::extendAddToSystem(system);
55
56 const ContactParametersSet& contactParametersSet =
57 get_contact_parameters();
58 const double& transitionVelocity = get_transition_velocity();
59
60 SimTK::GeneralContactSubsystem& contacts = system.updContactSubsystem();
61 SimTK::ContactSetIndex set = contacts.createContactSet();
62 SimTK::HuntCrossleyForce force(_model->updForceSubsystem(), contacts, set);
63 force.setTransitionVelocity(transitionVelocity);
64 for (int i = 0; i < contactParametersSet.getSize(); ++i)
65 {
66 ContactParameters& params = contactParametersSet.get(i);
67 for (int j = 0; j < params.getGeometry().size(); ++j) {
68 // TODO: Dependency of HuntCrossleyForce on ContactGeometry
69 // should be handled by Sockets.
70 const ContactGeometry* contactGeom = nullptr;
71 if (getModel().hasComponent<ContactGeometry>(params.getGeometry()[j]))
72 contactGeom = &getModel().getComponent<ContactGeometry>(
73 params.getGeometry()[j]);
74 else
75 contactGeom = &getModel().getComponent<ContactGeometry>(
76 "./contactgeometryset/" + params.getGeometry()[j]);
77
78 const ContactGeometry& geom = *contactGeom;
79 // B: base Frame (Body or Ground)
80 // F: PhysicalFrame that this ContactGeometry is connected to
81 // P: the frame defined (relative to F) by the location and
82 // orientation properties.
83 const auto& X_BF = geom.getFrame().findTransformInBaseFrame();
84 const auto& X_FP = geom.getTransform();
85 const auto X_BP = X_BF * X_FP;
86 contacts.addBody(set, geom.getFrame().getMobilizedBody(),
87 geom.createSimTKContactGeometry(), X_BP);
88 force.setBodyParameters(
89 SimTK::ContactSurfaceIndex(contacts.getNumBodies(set)-1),
90 params.getStiffness(), params.getDissipation(),
91 params.getStaticFriction(), params.getDynamicFriction(),
92 params.getViscousFriction());
93 }
94 }
95
96 // Beyond the const Component get the index so we can access the
97 // SimTK::Force later.
98 HuntCrossleyForce* mutableThis = const_cast<HuntCrossleyForce *>(this);
99 mutableThis->_index = force.getForceIndex();
100 }
101
constructProperties()102 void HuntCrossleyForce::constructProperties()
103 {
104 constructProperty_contact_parameters(ContactParametersSet());
105 constructProperty_transition_velocity(0.01);
106 }
107
108 HuntCrossleyForce::ContactParametersSet& HuntCrossleyForce::
updContactParametersSet()109 updContactParametersSet()
110 {
111 return upd_contact_parameters();
112 }
113
114 const HuntCrossleyForce::ContactParametersSet& HuntCrossleyForce::
getContactParametersSet()115 getContactParametersSet()
116 {
117 return get_contact_parameters();
118 }
119
120 void HuntCrossleyForce::
addContactParameters(HuntCrossleyForce::ContactParameters * params)121 addContactParameters(HuntCrossleyForce::ContactParameters* params)
122 {
123 updContactParametersSet().adoptAndAppend(params);
124 }
125
getTransitionVelocity() const126 double HuntCrossleyForce::getTransitionVelocity() const
127 {
128 return get_transition_velocity();
129 }
130
setTransitionVelocity(double velocity)131 void HuntCrossleyForce::setTransitionVelocity(double velocity)
132 {
133 set_transition_velocity(velocity);
134 }
135 /**
136 * The following set of functions are introduced for convenience to get/set values in HuntCrossleyForce::ContactParameters
137 * and for access in Matlab without exposing HuntCrossleyForce::ContactParameters. pending refactoring contact forces
138 */
getStiffness()139 double HuntCrossleyForce::getStiffness() {
140 if (get_contact_parameters().getSize()==0)
141 updContactParametersSet().adoptAndAppend(
142 new HuntCrossleyForce::ContactParameters());
143 return get_contact_parameters().get(0).getStiffness();
144 };
setStiffness(double stiffness)145 void HuntCrossleyForce::setStiffness(double stiffness) {
146 if (get_contact_parameters().getSize()==0)
147 updContactParametersSet().adoptAndAppend(
148 new HuntCrossleyForce::ContactParameters());
149 upd_contact_parameters()[0].setStiffness(stiffness);
150 };
getDissipation()151 double HuntCrossleyForce::getDissipation() {
152 if (get_contact_parameters().getSize()==0)
153 updContactParametersSet().adoptAndAppend(
154 new HuntCrossleyForce::ContactParameters());
155 return get_contact_parameters().get(0).getDissipation();
156 };
setDissipation(double dissipation)157 void HuntCrossleyForce::setDissipation(double dissipation) {
158 if (get_contact_parameters().getSize()==0)
159 updContactParametersSet().adoptAndAppend(
160 new HuntCrossleyForce::ContactParameters());
161 upd_contact_parameters()[0].setDissipation(dissipation);
162 };
getStaticFriction()163 double HuntCrossleyForce::getStaticFriction() {
164 if (get_contact_parameters().getSize()==0)
165 updContactParametersSet().adoptAndAppend(
166 new HuntCrossleyForce::ContactParameters());
167 return get_contact_parameters().get(0).getStaticFriction();
168 };
setStaticFriction(double friction)169 void HuntCrossleyForce::setStaticFriction(double friction) {
170 if (get_contact_parameters().getSize()==0)
171 updContactParametersSet().adoptAndAppend(
172 new HuntCrossleyForce::ContactParameters());
173 upd_contact_parameters()[0].setStaticFriction(friction);
174 };
getDynamicFriction()175 double HuntCrossleyForce::getDynamicFriction() {
176 if (get_contact_parameters().getSize()==0)
177 updContactParametersSet().adoptAndAppend(
178 new HuntCrossleyForce::ContactParameters());
179 return get_contact_parameters().get(0).getDynamicFriction();
180 };
setDynamicFriction(double friction)181 void HuntCrossleyForce::setDynamicFriction(double friction) {
182 if (get_contact_parameters().getSize()==0)
183 updContactParametersSet().adoptAndAppend(
184 new HuntCrossleyForce::ContactParameters());
185 upd_contact_parameters()[0].setDynamicFriction(friction);
186 };
getViscousFriction()187 double HuntCrossleyForce::getViscousFriction() {
188 if (get_contact_parameters().getSize()==0)
189 updContactParametersSet().adoptAndAppend(
190 new HuntCrossleyForce::ContactParameters());
191 return get_contact_parameters().get(0).getViscousFriction();
192 };
setViscousFriction(double friction)193 void HuntCrossleyForce::setViscousFriction(double friction) {
194 if (get_contact_parameters().getSize()==0)
195 updContactParametersSet().adoptAndAppend(
196 new HuntCrossleyForce::ContactParameters());
197 upd_contact_parameters()[0].setViscousFriction(friction);
198 };
199
addGeometry(const std::string & name)200 void HuntCrossleyForce::addGeometry(const std::string& name)
201 {
202 if (get_contact_parameters().getSize()==0)
203 updContactParametersSet().adoptAndAppend(
204 new HuntCrossleyForce::ContactParameters());
205 upd_contact_parameters()[0].addGeometry(name);
206 }
207 //==============================================================================
208 // HUNT CROSSLEY FORCE :: CONTACT PARAMETERS
209 //==============================================================================
210
211 // Default constructor.
ContactParameters()212 HuntCrossleyForce::ContactParameters::ContactParameters()
213 {
214 constructProperties();
215 }
216
217 // Constructor specifying material properties.
ContactParameters(double stiffness,double dissipation,double staticFriction,double dynamicFriction,double viscousFriction)218 HuntCrossleyForce::ContactParameters::ContactParameters
219 (double stiffness, double dissipation, double staticFriction,
220 double dynamicFriction, double viscousFriction)
221 {
222 constructProperties();
223 set_stiffness(stiffness);
224 set_dissipation(dissipation);
225 set_static_friction(staticFriction);
226 set_dynamic_friction(dynamicFriction);
227 set_viscous_friction(viscousFriction);
228 }
229
230
constructProperties()231 void HuntCrossleyForce::ContactParameters::constructProperties()
232 {
233 constructProperty_geometry(); // a list of strings
234 constructProperty_stiffness(0.0);
235 constructProperty_dissipation(0.0);
236 constructProperty_static_friction(0.0);
237 constructProperty_dynamic_friction(0.0);
238 constructProperty_viscous_friction(0.0);
239 }
240
getGeometry() const241 const Property<std::string>& HuntCrossleyForce::ContactParameters::getGeometry() const
242 {
243 return getProperty_geometry();
244 }
245
updGeometry()246 Property<std::string>& HuntCrossleyForce::ContactParameters::updGeometry()
247 {
248 return updProperty_geometry();
249 }
250
addGeometry(const std::string & name)251 void HuntCrossleyForce::ContactParameters::addGeometry(const std::string& name)
252 {
253 updGeometry().appendValue(name);
254 }
255
getStiffness() const256 double HuntCrossleyForce::ContactParameters::getStiffness() const
257 {
258 return get_stiffness();
259 }
260
setStiffness(double stiffness)261 void HuntCrossleyForce::ContactParameters::setStiffness(double stiffness)
262 {
263 set_stiffness(stiffness);
264 }
265
getDissipation() const266 double HuntCrossleyForce::ContactParameters::getDissipation() const
267 {
268 return get_dissipation();
269 }
270
setDissipation(double dissipation)271 void HuntCrossleyForce::ContactParameters::setDissipation(double dissipation)
272 {
273 set_dissipation(dissipation);
274 }
275
getStaticFriction() const276 double HuntCrossleyForce::ContactParameters::getStaticFriction() const
277 {
278 return get_static_friction();
279 }
280
setStaticFriction(double friction)281 void HuntCrossleyForce::ContactParameters::setStaticFriction(double friction)
282 {
283 set_static_friction(friction);
284 }
285
getDynamicFriction() const286 double HuntCrossleyForce::ContactParameters::getDynamicFriction() const
287 {
288 return get_dynamic_friction();
289 }
290
setDynamicFriction(double friction)291 void HuntCrossleyForce::ContactParameters::setDynamicFriction(double friction)
292 {
293 set_dynamic_friction(friction);
294 }
295
getViscousFriction() const296 double HuntCrossleyForce::ContactParameters::getViscousFriction() const
297 {
298 return get_viscous_friction();
299 }
300
setViscousFriction(double friction)301 void HuntCrossleyForce::ContactParameters::setViscousFriction(double friction)
302 {
303 set_viscous_friction(friction);
304 }
305
setNull()306 void HuntCrossleyForce::ContactParametersSet::setNull()
307 {
308 setAuthors("Peter Eastman");
309 }
310
ContactParametersSet()311 HuntCrossleyForce::ContactParametersSet::ContactParametersSet()
312 {
313 setNull();
314 }
315
316
317 //=============================================================================
318 // Reporting
319 //=============================================================================
320 /* Provide names of the quantities (column labels) of the force value(s)
321 * to be reported. */
getRecordLabels() const322 OpenSim::Array<std::string> HuntCrossleyForce::getRecordLabels() const
323 {
324 OpenSim::Array<std::string> labels("");
325
326 const ContactParametersSet& contactParametersSet =
327 get_contact_parameters();
328
329 for (int i = 0; i < contactParametersSet.getSize(); ++i)
330 {
331 ContactParameters& params = contactParametersSet.get(i);
332 for (int j = 0; j < params.getGeometry().size(); ++j)
333 {
334 // TODO: Dependency of HuntCrossleyForce on ContactGeometry
335 // should be handled by Sockets.
336 const ContactGeometry* contactGeom = nullptr;
337 if (getModel().hasComponent<ContactGeometry>(params.getGeometry()[j]))
338 contactGeom = &getModel().getComponent<ContactGeometry>(
339 params.getGeometry()[j]);
340 else
341 contactGeom = &getModel().getComponent<ContactGeometry>(
342 "./contactgeometryset/" + params.getGeometry()[j]);
343
344 const ContactGeometry& geom = *contactGeom;
345 std::string frameName = geom.getFrame().getName();
346 labels.append(getName()+"."+frameName+".force.X");
347 labels.append(getName()+"."+frameName+".force.Y");
348 labels.append(getName()+"."+frameName+".force.Z");
349 labels.append(getName()+"."+frameName+".torque.X");
350 labels.append(getName()+"."+frameName+".torque.Y");
351 labels.append(getName()+"."+frameName+".torque.Z");
352 }
353 }
354
355 return labels;
356 }
357 /**
358 * Provide the value(s) to be reported that correspond to the labels
359 */
360 OpenSim::Array<double> HuntCrossleyForce::
getRecordValues(const SimTK::State & state) const361 getRecordValues(const SimTK::State& state) const
362 {
363 OpenSim::Array<double> values(1);
364
365 const ContactParametersSet& contactParametersSet =
366 get_contact_parameters();
367
368 const auto& forceSubsys = _model->getForceSubsystem();
369 const SimTK::Force& abstractForce = forceSubsys.getForce(_index);
370 const auto& simtkForce = (SimTK::HuntCrossleyForce &)(abstractForce);
371
372 SimTK::Vector_<SimTK::SpatialVec> bodyForces(0);
373 SimTK::Vector_<SimTK::Vec3> particleForces(0);
374 SimTK::Vector mobilityForces(0);
375
376 //get the net force added to the system contributed by the Spring
377 simtkForce.calcForceContribution(state, bodyForces, particleForces,
378 mobilityForces);
379
380 for (int i = 0; i < contactParametersSet.getSize(); ++i)
381 {
382 ContactParameters& params = contactParametersSet.get(i);
383 for (int j = 0; j < params.getGeometry().size(); ++j)
384 {
385 // TODO: Dependency of HuntCrossleyForce on ContactGeometry
386 // should be handled by Sockets.
387 const ContactGeometry* contactGeom = nullptr;
388 if (getModel().hasComponent<ContactGeometry>(params.getGeometry()[j]))
389 contactGeom = &getModel().getComponent<ContactGeometry>(
390 params.getGeometry()[j]);
391 else
392 contactGeom = &getModel().getComponent<ContactGeometry>(
393 "./contactgeometryset/" + params.getGeometry()[j]);
394
395 const ContactGeometry& geom = *contactGeom;
396
397 const auto& mbi = geom.getFrame().getMobilizedBodyIndex();
398 const auto& thisBodyForce = bodyForces(mbi);
399 SimTK::Vec3 forces = thisBodyForce[1];
400 SimTK::Vec3 torques = thisBodyForce[0];
401
402 values.append(3, &forces[0]);
403 values.append(3, &torques[0]);
404 }
405 }
406
407 return values;
408 }
409
410 }// end of namespace OpenSim
411