Simbody
3.4 (development)
|
00001 #ifndef SimTK_SimTKCOMMON_FUNCTION_H_ 00002 #define SimTK_SimTKCOMMON_FUNCTION_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK 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/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2008-12 Stanford University and the Authors. * 00013 * Authors: Peter Eastman * 00014 * Contributors: Michael Sherman * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00027 // Note: this file was moved from Simmath to SimTKcommon 20100601; see the 00028 // Simmath repository for earlier history. 00029 00030 #include "SimTKcommon/basics.h" 00031 #include "SimTKcommon/Simmatrix.h" 00032 #include <cassert> 00033 00034 namespace SimTK { 00035 00050 template <class T> 00051 class Function_ { 00052 public: 00053 class Constant; 00054 class Linear; 00055 class Polynomial; 00056 class Sinusoid; 00057 class Step; 00058 virtual ~Function_() { 00059 } 00066 virtual T calcValue(const Vector& x) const = 0; 00086 virtual T calcDerivative(const Array_<int>& derivComponents, 00087 const Vector& x) const = 0; 00088 00091 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00092 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00093 00097 virtual int getArgumentSize() const = 0; 00101 virtual int getMaxDerivativeOrder() const = 0; 00102 }; 00103 00106 typedef Function_<Real> Function; 00107 00108 00109 00114 template <class T> 00115 class Function_<T>::Constant : public Function_<T> { 00116 public: 00124 explicit Constant(T value, int argumentSize=1) 00125 : argumentSize(argumentSize), value(value) { 00126 } 00127 T calcValue(const Vector& x) const { 00128 assert(x.size() == argumentSize); 00129 return value; 00130 } 00131 T calcDerivative(const Array_<int>& derivComponents, const Vector& x) const { 00132 return static_cast<T>(0); 00133 } 00134 virtual int getArgumentSize() const { 00135 return argumentSize; 00136 } 00137 int getMaxDerivativeOrder() const { 00138 return std::numeric_limits<int>::max(); 00139 } 00140 00143 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00144 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00145 00146 private: 00147 const int argumentSize; 00148 const T value; 00149 }; 00150 00155 template <class T> 00156 class Function_<T>::Linear : public Function_<T> { 00157 public: 00168 explicit Linear(const Vector_<T>& coefficients) : coefficients(coefficients) { 00169 } 00170 T calcValue(const Vector& x) const { 00171 assert(x.size() == coefficients.size()-1); 00172 T value = static_cast<T>(0); 00173 for (int i = 0; i < x.size(); ++i) 00174 value += x[i]*coefficients[i]; 00175 value += coefficients[x.size()]; 00176 return value; 00177 } 00178 T calcDerivative(const Array_<int>& derivComponents, const Vector& x) const { 00179 assert(x.size() == coefficients.size()-1); 00180 assert(derivComponents.size() > 0); 00181 if (derivComponents.size() == 1) 00182 return coefficients(derivComponents[0]); 00183 return static_cast<T>(0); 00184 } 00185 virtual int getArgumentSize() const { 00186 return coefficients.size()-1; 00187 } 00188 int getMaxDerivativeOrder() const { 00189 return std::numeric_limits<int>::max(); 00190 } 00191 00194 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00195 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00196 private: 00197 const Vector_<T> coefficients; 00198 }; 00199 00200 00205 template <class T> 00206 class Function_<T>::Polynomial : public Function_<T> { 00207 public: 00214 Polynomial(const Vector_<T>& coefficients) : coefficients(coefficients) { 00215 } 00216 T calcValue(const Vector& x) const { 00217 assert(x.size() == 1); 00218 Real arg = x[0]; 00219 T value = static_cast<T>(0); 00220 for (int i = 0; i < coefficients.size(); ++i) 00221 value = value*arg + coefficients[i]; 00222 return value; 00223 } 00224 T calcDerivative(const Array_<int>& derivComponents, const Vector& x) const { 00225 assert(x.size() == 1); 00226 assert(derivComponents.size() > 0); 00227 Real arg = x[0]; 00228 T value = static_cast<T>(0); 00229 const int derivOrder = (int)derivComponents.size(); 00230 const int polyOrder = coefficients.size()-1; 00231 for (int i = 0; i <= polyOrder-derivOrder; ++i) { 00232 T coeff = coefficients[i]; 00233 for (int j = 0; j < derivOrder; ++j) 00234 coeff *= polyOrder-i-j; 00235 value = value*arg + coeff; 00236 } 00237 return value; 00238 } 00239 virtual int getArgumentSize() const { 00240 return 1; 00241 } 00242 int getMaxDerivativeOrder() const { 00243 return std::numeric_limits<int>::max(); 00244 } 00245 00248 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00249 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00250 private: 00251 const Vector_<T> coefficients; 00252 }; 00253 00254 00262 template <> 00263 class Function_<Real>::Sinusoid : public Function_<Real> { 00264 public: 00272 Sinusoid(Real amplitude, Real frequency, Real phase=0) 00273 : a(amplitude), w(frequency), p(phase) {} 00274 00275 void setAmplitude(Real amplitude) {a=amplitude;} 00276 void setFrequency(Real frequency) {w=frequency;} 00277 void setPhase (Real phase) {p=phase;} 00278 00279 Real getAmplitude() const {return a;} 00280 Real getFrequency() const {return w;} 00281 Real getPhase () const {return p;} 00282 00283 // Implementation of Function_<T> virtuals. 00284 00285 virtual Real calcValue(const Vector& x) const { 00286 const Real t = x[0]; // we expect just one argument 00287 return a*std::sin(w*t + p); 00288 } 00289 00290 virtual Real calcDerivative(const Array_<int>& derivComponents, 00291 const Vector& x) const { 00292 const Real t = x[0]; // time is the only argument 00293 const int order = derivComponents.size(); 00294 // The n'th derivative is 00295 // sign * a * w^n * sc 00296 // where sign is -1 if floor(order/2) is odd, else 1 00297 // and sc is cos(w*t+p) if order is odd, else sin(w*t+p) 00298 switch(order) { 00299 case 0: return a* std::sin(w*t + p); 00300 case 1: return a*w* std::cos(w*t + p); 00301 case 2: return -a*w*w* std::sin(w*t + p); 00302 case 3: return -a*w*w*w*std::cos(w*t + p); 00303 default: 00304 const Real sign = Real(((order/2) & 0x1) ? -1 : 1); 00305 const Real sc = (order & 0x1) ? std::cos(w*t+p) : std::sin(w*t+p); 00306 const Real wn = std::pow(w, order); 00307 return sign*a*wn*sc; 00308 } 00309 } 00310 00311 virtual int getArgumentSize() const {return 1;} // just time 00312 virtual int getMaxDerivativeOrder() const { 00313 return std::numeric_limits<int>::max(); 00314 } 00315 00318 Real calcDerivative(const std::vector<int>& derivComponents, 00319 const Vector& x) const 00320 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00321 private: 00322 Real a, w, p; 00323 }; 00324 00332 template <class T> 00333 class Function_<T>::Step : public Function_<T> { 00334 public: 00352 Step(const T& y0, const T& y1, Real x0, Real x1) 00353 : m_y0(y0), m_y1(y1), m_yr(y1-y0), m_zero(Real(0)*y0), 00354 m_x0(x0), m_x1(x1), m_ooxr(1/(x1-x0)), m_sign(sign(m_ooxr)) 00355 { SimTK_ERRCHK1_ALWAYS(x0 != x1, "Function_<T>::Step::ctor()", 00356 "A zero-length switching interval is illegal; both ends were %g.", x0); 00357 } 00358 00359 T calcValue(const Vector& xin) const { 00360 SimTK_ERRCHK1_ALWAYS(xin.size() == 1, 00361 "Function_<T>::Step::calcValue()", 00362 "Expected just one input argument but got %d.", xin.size()); 00363 00364 const Real x = xin[0]; 00365 if ((x-m_x0)*m_sign <= 0) return m_y0; 00366 if ((x-m_x1)*m_sign >= 0) return m_y1; 00367 // f goes from 0 to 1 as x goes from x0 to x1. 00368 const Real f = stepAny(0,1,m_x0,m_ooxr, x); 00369 return m_y0 + f*m_yr; 00370 } 00371 00372 T calcDerivative(const Array_<int>& derivComponents, const Vector& xin) const { 00373 SimTK_ERRCHK1_ALWAYS(xin.size() == 1, 00374 "Function_<T>::Step::calcDerivative()", 00375 "Expected just one input argument but got %d.", xin.size()); 00376 00377 const int derivOrder = (int)derivComponents.size(); 00378 SimTK_ERRCHK1_ALWAYS(1 <= derivOrder && derivOrder <= 3, 00379 "Function_<T>::Step::calcDerivative()", 00380 "Only 1st, 2nd, and 3rd derivatives of the step are available," 00381 " but derivative %d was requested.", derivOrder); 00382 const Real x = xin[0]; 00383 if ((x-m_x0)*m_sign <= 0) return m_zero; 00384 if ((x-m_x1)*m_sign >= 0) return m_zero; 00385 switch(derivOrder) { 00386 case 1: return dstepAny (1,m_x0,m_ooxr, x) * m_yr; 00387 case 2: return d2stepAny(1,m_x0,m_ooxr, x) * m_yr; 00388 case 3: return d3stepAny(1,m_x0,m_ooxr, x) * m_yr; 00389 default: assert(!"impossible derivOrder"); 00390 } 00391 return NaN*m_yr; /*NOTREACHED*/ 00392 } 00393 00394 virtual int getArgumentSize() const {return 1;} 00395 int getMaxDerivativeOrder() const {return 3;} 00396 00399 T calcDerivative(const std::vector<int>& derivComponents, const Vector& x) const 00400 { return calcDerivative(ArrayViewConst_<int>(derivComponents),x); } 00401 private: 00402 const T m_y0, m_y1, m_yr; // precalculate yr=(y1-y0) 00403 const T m_zero; // precalculate T(0) 00404 const Real m_x0, m_x1, m_ooxr; // precalculate ooxr=1/(x1-x0) 00405 const Real m_sign; // sign(x1-x0) is 1 or -1 00406 }; 00407 00408 } // namespace SimTK 00409 00410 #endif // SimTK_SimTKCOMMON_FUNCTION_H_ 00411 00412