1 /* -------------------------------------------------------------------------- *
2 * OpenSim: FiberCompressiveForceLengthCurve.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): Matthew Millard *
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 #include "FiberCompressiveForceLengthCurve.h"
24 #include <OpenSim/Common/SmoothSegmentedFunctionFactory.h>
25
26 using namespace OpenSim;
27 using namespace SimTK;
28 using namespace std;
29
30 //=============================================================================
31 // CONSTRUCTION
32 //=============================================================================
33 // Uses default (compiler-generated) destructor, copy constructor,
34 // copy assignment.
35
36 FiberCompressiveForceLengthCurve::
FiberCompressiveForceLengthCurve()37 FiberCompressiveForceLengthCurve()
38 {
39 setNull();
40 constructProperties();
41 setName("default_FiberCompressiveForceLengthCurve");
42
43 ensureCurveUpToDate();
44 }
45
FiberCompressiveForceLengthCurve(double normLengthAtZeroForce,double stiffnessAtZeroLength,double curviness,const std::string & muscleName)46 FiberCompressiveForceLengthCurve::FiberCompressiveForceLengthCurve
47 ( double normLengthAtZeroForce,
48 double stiffnessAtZeroLength,
49 double curviness,
50 const std::string& muscleName)
51 {
52 setNull();
53 constructProperties();
54 setName(muscleName + "_FiberCompressiveForceLengthCurve");
55
56 set_norm_length_at_zero_force(normLengthAtZeroForce);
57 set_stiffness_at_zero_length(stiffnessAtZeroLength);
58 set_curviness(curviness);
59
60 ensureCurveUpToDate();
61 }
62
63
setNull()64 void FiberCompressiveForceLengthCurve::setNull()
65 {
66
67 setAuthors("Matthew Millard");
68 }
69
constructProperties()70 void FiberCompressiveForceLengthCurve::constructProperties()
71 {
72 constructProperty_norm_length_at_zero_force(0.5);
73 constructProperty_stiffness_at_zero_length();
74 constructProperty_curviness();
75 }
76
77
buildCurve(bool computeIntegral)78 void FiberCompressiveForceLengthCurve::buildCurve( bool computeIntegral )
79 {
80 SmoothSegmentedFunction* f = SmoothSegmentedFunctionFactory::
81 createFiberCompressiveForceLengthCurve(
82 get_norm_length_at_zero_force(),
83 m_stiffnessAtZeroLengthInUse,
84 m_curvinessInUse,
85 computeIntegral,
86 getName());
87
88 m_curve = *f;
89
90 delete f;
91
92 setObjectIsUpToDateWithProperties();
93 }
94
95
ensureCurveUpToDate()96 void FiberCompressiveForceLengthCurve::ensureCurveUpToDate()
97 {
98 if(isObjectUpToDateWithProperties() == false){
99
100 //=====================================================================
101 //Compute the optional properties if they have not been set
102 //=====================================================================
103 if(getProperty_stiffness_at_zero_length().empty() == true &&
104 getProperty_curviness().empty() == true)
105 {
106 double lengthAtZeroForce = get_norm_length_at_zero_force();
107
108 m_stiffnessAtZeroLengthInUse= -2.0/lengthAtZeroForce;
109 m_curvinessInUse = 0.5;
110 m_isFittedCurveBeingUsed = true;
111 }
112
113 //=====================================================================
114 //Use the optional properties if they have been set
115 //=====================================================================
116 if(getProperty_stiffness_at_zero_length().empty() == false &&
117 getProperty_curviness().empty() == false)
118 {
119
120 m_stiffnessAtZeroLengthInUse = get_stiffness_at_zero_length();
121 m_curvinessInUse = get_curviness();
122 m_isFittedCurveBeingUsed = false;
123 }
124
125 //=====================================================================
126 //Error condition if only one optional parameter is set.
127 //=====================================================================
128 bool a = getProperty_stiffness_at_zero_length().empty();
129 bool b = getProperty_curviness().empty();
130
131 //This is really a XOR operation ...
132 if( ( a && !b ) || ( !a && b ) ){
133
134 //This error condition is checked to make sure that the reference
135 //fiber is being used to populate all optional properties or none
136 //of them. Anything different would result in an inconsistency in
137 //the computed curve - it wouldn't reflect the reference curve.
138 SimTK_ERRCHK1_ALWAYS(false,
139 "FiberCompressiveForceLengthCurve::ensureCurveUpToDate()",
140 "%s: Optional parameters stiffness and curviness must both"
141 "be set, or both remain empty. You have set one parameter"
142 "and left the other blank.",
143 getName().c_str());
144 }
145
146 buildCurve();
147 }
148
149 //Since the name is not counted as a property, but it can change,
150 //and needs to be kept up to date.
151 std::string name = getName();
152 m_curve.setName(name);
153 }
154
155
156 //=============================================================================
157 // OpenSim::Function Interface
158 //=============================================================================
159
createSimTKFunction() const160 SimTK::Function* FiberCompressiveForceLengthCurve::createSimTKFunction() const
161 {
162 // back the OpenSim::Function with this SimTK::Function
163
164 return SmoothSegmentedFunctionFactory::
165 createFiberCompressiveForceLengthCurve(
166 get_norm_length_at_zero_force(),
167 m_stiffnessAtZeroLengthInUse,
168 m_curvinessInUse,
169 false,
170 getName());
171 }
172
173
174
175 //=============================================================================
176 // GET & SET METHODS
177 //=============================================================================
getNormLengthAtZeroForce() const178 double FiberCompressiveForceLengthCurve::getNormLengthAtZeroForce() const
179 {
180 return get_norm_length_at_zero_force();
181 }
182
getStiffnessAtZeroLengthInUse() const183 double FiberCompressiveForceLengthCurve::getStiffnessAtZeroLengthInUse() const
184 {
185 return m_stiffnessAtZeroLengthInUse;
186 }
187
getCurvinessInUse() const188 double FiberCompressiveForceLengthCurve::getCurvinessInUse() const
189 {
190 return m_curvinessInUse;
191 }
192
isFittedCurveBeingUsed() const193 bool FiberCompressiveForceLengthCurve::isFittedCurveBeingUsed() const
194 {
195 return m_isFittedCurveBeingUsed;
196 }
197
198
199 void FiberCompressiveForceLengthCurve::
setNormLengthAtZeroForce(double aNormLengthAtZeroForce)200 setNormLengthAtZeroForce(double aNormLengthAtZeroForce)
201 {
202 set_norm_length_at_zero_force(aNormLengthAtZeroForce);
203 ensureCurveUpToDate();
204 }
205
206 void FiberCompressiveForceLengthCurve::
setOptionalProperties(double aStiffnessAtZeroLength,double aCurviness)207 setOptionalProperties(double aStiffnessAtZeroLength, double aCurviness)
208 {
209 set_stiffness_at_zero_length(aStiffnessAtZeroLength);
210 set_curviness(aCurviness);
211 ensureCurveUpToDate();
212 }
213
214
215 //=============================================================================
216 // SERVICES
217 //=============================================================================
218
calcValue(double aNormLength) const219 double FiberCompressiveForceLengthCurve::calcValue(double aNormLength) const
220 {
221 SimTK_ASSERT(isObjectUpToDateWithProperties()==true,
222 "FiberCompressiveForceLengthCurve: Curve is not"
223 " to date with its properties");
224 return m_curve.calcValue(aNormLength);
225 }
226
calcIntegral(double aNormLength) const227 double FiberCompressiveForceLengthCurve::calcIntegral(double aNormLength) const
228 {
229 SimTK_ASSERT(isObjectUpToDateWithProperties()==true,
230 "FiberCompressiveForceLengthCurve: Curve is not"
231 " to date with its properties");
232
233 if (!m_curve.isIntegralAvailable()) {
234 FiberCompressiveForceLengthCurve* mutableThis =
235 const_cast<FiberCompressiveForceLengthCurve*>(this);
236 mutableThis->buildCurve(true);
237 }
238
239 return m_curve.calcIntegral(aNormLength);
240 }
241
242 double FiberCompressiveForceLengthCurve::
calcDerivative(double aNormLength,int order) const243 calcDerivative(double aNormLength, int order) const
244 {
245 SimTK_ASSERT(isObjectUpToDateWithProperties()==true,
246 "FiberCompressiveForceLengthCurve: Curve is not"
247 " to date with its properties");
248
249 SimTK_ERRCHK1_ALWAYS(order >= 0 && order <= 2,
250 "FiberCompressiveForceLengthCurve::calcDerivative",
251 "order must be 0, 1, or 2, but %i was entered", order);
252
253 return m_curve.calcDerivative(aNormLength,order);
254 }
255
256 double FiberCompressiveForceLengthCurve::
calcDerivative(const std::vector<int> & derivComponents,const SimTK::Vector & x) const257 calcDerivative(const std::vector<int>& derivComponents,
258 const SimTK::Vector& x) const
259 {
260 return m_curve.calcDerivative(derivComponents, x);
261 }
262
getCurveDomain() const263 SimTK::Vec2 FiberCompressiveForceLengthCurve::getCurveDomain() const
264 {
265 SimTK_ASSERT(isObjectUpToDateWithProperties()==true,
266 "FiberCompressiveForceLengthCurve: Curve is not"
267 " to date with its properties");
268 return m_curve.getCurveDomain();
269 }
270
271 void FiberCompressiveForceLengthCurve::
printMuscleCurveToCSVFile(const std::string & path)272 printMuscleCurveToCSVFile(const std::string& path)
273 {
274 ensureCurveUpToDate();
275
276 double xmin = 0;
277 double xmax = max(1.0,get_norm_length_at_zero_force());
278
279 m_curve.printMuscleCurveToCSVFile(path,xmin,xmax);
280 }
281