Simbody  3.4 (development)
Function.h
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines