Simbody
|
00001 #ifndef SimTK_SimTKCOMMON_FUNCTION_H_ 00002 #define SimTK_SimTKCOMMON_FUNCTION_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org. * 00011 * * 00012 * Portions copyright (c) 2008-10 Stanford University and the Authors. * 00013 * Authors: Peter Eastman * 00014 * Contributors: Michael Sherman * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00035 // Note: this file was moved from Simmath to SimTKcommon 20100601; see the 00036 // Simmath repository for earlier history. 00037 00038 #include "SimTKcommon/basics.h" 00039 #include "SimTKcommon/Simmatrix.h" 00040 #include <cassert> 00041 00042 namespace SimTK { 00043 00058 template <class T> 00059 class Function_ { 00060 public: 00061 class Constant; 00062 class Linear; 00063 class Polynomial; 00064 class Step; 00065 virtual ~Function_() { 00066 } 00073 virtual T calcValue(const Vector& x) const = 0; 00093 virtual T calcDerivative(const Array_<int>& derivComponents, 00094 const Vector& x) const = 0; 00095 00098 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00099 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00100 00104 virtual int getArgumentSize() const = 0; 00108 virtual int getMaxDerivativeOrder() const = 0; 00109 }; 00110 00113 typedef Function_<Real> Function; 00114 00115 00116 00121 template <class T> 00122 class Function_<T>::Constant : public Function_<T> { 00123 public: 00131 explicit Constant(T value, int argumentSize=1) 00132 : argumentSize(argumentSize), value(value) { 00133 } 00134 T calcValue(const Vector& x) const { 00135 assert(x.size() == argumentSize); 00136 return value; 00137 } 00138 T calcDerivative(const Array_<int>& derivComponents, const Vector& x) const { 00139 return static_cast<T>(0); 00140 } 00141 virtual int getArgumentSize() const { 00142 return argumentSize; 00143 } 00144 int getMaxDerivativeOrder() const { 00145 return std::numeric_limits<int>::max(); 00146 } 00147 00150 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00151 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00152 00153 private: 00154 const int argumentSize; 00155 const T value; 00156 }; 00157 00162 template <class T> 00163 class Function_<T>::Linear : public Function_<T> { 00164 public: 00175 explicit Linear(const Vector_<T>& coefficients) : coefficients(coefficients) { 00176 } 00177 T calcValue(const Vector& x) const { 00178 assert(x.size() == coefficients.size()-1); 00179 T value = static_cast<T>(0); 00180 for (int i = 0; i < x.size(); ++i) 00181 value += x[i]*coefficients[i]; 00182 value += coefficients[x.size()]; 00183 return value; 00184 } 00185 T calcDerivative(const Array_<int>& derivComponents, const Vector& x) const { 00186 assert(x.size() == coefficients.size()-1); 00187 assert(derivComponents.size() > 0); 00188 if (derivComponents.size() == 1) 00189 return coefficients(derivComponents[0]); 00190 return static_cast<T>(0); 00191 } 00192 virtual int getArgumentSize() const { 00193 return coefficients.size()-1; 00194 } 00195 int getMaxDerivativeOrder() const { 00196 return std::numeric_limits<int>::max(); 00197 } 00198 00201 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00202 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00203 private: 00204 const Vector_<T> coefficients; 00205 }; 00206 00207 00212 template <class T> 00213 class Function_<T>::Polynomial : public Function_<T> { 00214 public: 00221 Polynomial(const Vector_<T>& coefficients) : coefficients(coefficients) { 00222 } 00223 T calcValue(const Vector& x) const { 00224 assert(x.size() == 1); 00225 Real arg = x[0]; 00226 T value = static_cast<T>(0); 00227 for (int i = 0; i < coefficients.size(); ++i) 00228 value = value*arg + coefficients[i]; 00229 return value; 00230 } 00231 T calcDerivative(const Array_<int>& derivComponents, const Vector& x) const { 00232 assert(x.size() == 1); 00233 assert(derivComponents.size() > 0); 00234 Real arg = x[0]; 00235 T value = static_cast<T>(0); 00236 const int derivOrder = (int)derivComponents.size(); 00237 const int polyOrder = coefficients.size()-1; 00238 for (int i = 0; i <= polyOrder-derivOrder; ++i) { 00239 T coeff = coefficients[i]; 00240 for (int j = 0; j < derivOrder; ++j) 00241 coeff *= polyOrder-i-j; 00242 value = value*arg + coeff; 00243 } 00244 return value; 00245 } 00246 virtual int getArgumentSize() const { 00247 return 1; 00248 } 00249 int getMaxDerivativeOrder() const { 00250 return std::numeric_limits<int>::max(); 00251 } 00252 00255 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00256 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00257 private: 00258 const Vector_<T> coefficients; 00259 }; 00260 00268 template <class T> 00269 class Function_<T>::Step : public Function_<T> { 00270 public: 00288 Step(const T& y0, const T& y1, Real x0, Real x1) 00289 : m_y0(y0), m_y1(y1), m_yr(y1-y0), m_zero(Real(0)*y0), 00290 m_x0(x0), m_x1(x1), m_ooxr(1/(x1-x0)), m_sign(sign(m_ooxr)) 00291 { SimTK_ERRCHK1_ALWAYS(x0 != x1, "Function_<T>::Step::ctor()", 00292 "A zero-length switching interval is illegal; both ends were %g.", x0); 00293 } 00294 00295 T calcValue(const Vector& xin) const { 00296 SimTK_ERRCHK1_ALWAYS(xin.size() == 1, 00297 "Function_<T>::Step::calcValue()", 00298 "Expected just one input argument but got %d.", xin.size()); 00299 00300 const Real x = xin[0]; 00301 if ((x-m_x0)*m_sign <= 0) return m_y0; 00302 if ((x-m_x1)*m_sign >= 0) return m_y1; 00303 // f goes from 0 to 1 as x goes from x0 to x1. 00304 const Real f = stepAny(0,1,m_x0,m_ooxr, x); 00305 return m_y0 + f*m_yr; 00306 } 00307 00308 T calcDerivative(const Array_<int>& derivComponents, const Vector& xin) const { 00309 SimTK_ERRCHK1_ALWAYS(xin.size() == 1, 00310 "Function_<T>::Step::calcDerivative()", 00311 "Expected just one input argument but got %d.", xin.size()); 00312 00313 const int derivOrder = (int)derivComponents.size(); 00314 SimTK_ERRCHK1_ALWAYS(1 <= derivOrder && derivOrder <= 3, 00315 "Function_<T>::Step::calcDerivative()", 00316 "Only 1st, 2nd, and 3rd derivatives of the step are available," 00317 " but derivative %d was requested.", derivOrder); 00318 const Real x = xin[0]; 00319 if ((x-m_x0)*m_sign <= 0) return m_zero; 00320 if ((x-m_x1)*m_sign >= 0) return m_zero; 00321 switch(derivOrder) { 00322 case 1: return dstepAny (1,m_x0,m_ooxr, x) * m_yr; 00323 case 2: return d2stepAny(1,m_x0,m_ooxr, x) * m_yr; 00324 case 3: return d3stepAny(1,m_x0,m_ooxr, x) * m_yr; 00325 default: assert(!"impossible derivOrder"); 00326 } 00327 return NaN*m_yr; /*NOTREACHED*/ 00328 } 00329 00330 virtual int getArgumentSize() const {return 1;} 00331 int getMaxDerivativeOrder() const {return 3;} 00332 00335 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00336 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00337 private: 00338 const T m_y0, m_y1, m_yr; // precalculate yr=(y1-y0) 00339 const T m_zero; // precalculate T(0) 00340 const Real m_x0, m_x1, m_ooxr; // precalculate ooxr=1/(x1-x0) 00341 const Real m_sign; // sign(x1-x0) is 1 or -1 00342 }; 00343 00344 } // namespace SimTK 00345 00346 #endif // SimTK_SimTKCOMMON_FUNCTION_H_ 00347 00348