File indexing completed on 2024-04-21 03:51:24

0001 /*
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /** \file solver.h
0008  *  \brief Solver interface
0009  */
0010 
0011 #ifndef STEPCORE_SOLVER_H
0012 #define STEPCORE_SOLVER_H
0013 
0014 #include "object.h"
0015 #include "vector.h"
0016 
0017 namespace StepCore
0018 {
0019 
0020 /** \ingroup solvers
0021  *  \brief Generic Solver interface
0022  *  
0023  *  Provides generic interface suitable for large variety of ordinary
0024  *  differential equations integration algorithms.
0025  *
0026  *  It solves system of the first order differential equations:
0027  *  \f{eqnarray*}
0028  *      \frac{dy_i(t)}{dt} &=& f(y_i(t), t) \\
0029  *      y_i(t_0) &=& y^0_i
0030  *  \f}
0031  *
0032  *  Dimension of system is provided via setDimension(),
0033  *  function \f$f\f$ is provided via setFunction().
0034  *
0035  *  It also provides interface for setting allowed local tolerance.
0036  *  It can be defined using two properties: toleranceAbs and toleranceRel.
0037  *
0038  *  On each step solver calculates local error estimation (which depends on
0039  *  used integration method) and local error ratio for each variable
0040  *  using the following formula:
0041  *  \f[
0042  *      \mbox{localErrorRatio}_i = \frac{|\mbox{localError}_i|}
0043  *          {\mbox{toleranceAbs} + \mbox{toleranceRel} \cdot | y_i |}
0044  *  \f]
0045  *
0046  *  Non-adaptive solvers cancel current step if maximal local error ratio is
0047  *  bigger than 1.1 (exact value depends on solver) and doEvolve() function
0048  *  returns false.
0049  *
0050  *  Adaptive solvers use maximal local error ratio to change time step until
0051  *  the ratio becomes almost equal 1. If it can't be made smaller than 1.1
0052  *  (exact value depends on solver), solvers cancel current step and doEvolve()
0053  *  function returns false. 
0054  *
0055  *  Maximal (over all variables) error estimation and error ratio from last
0056  *  time step can be obtained using localError() and localErrorRatio() methods.
0057  */
0058 class Solver: public Object
0059 {
0060     //Q_OBJECT
0061     STEPCORE_OBJECT(Solver)
0062 
0063 public:
0064     /** Callback function type */
0065     typedef int (*Function)(double t, const double* y, const double* yvar,
0066                              double* f, double* fvar, void* params);
0067 
0068     /** Constructs a solver */
0069     explicit Solver(int dimension = 0, Function function = nullptr,
0070                 void* params = nullptr, double stepSize = 0.001);
0071     /** Constructs a solver */
0072     explicit Solver(double stepSize);
0073 
0074     virtual ~Solver() {}
0075 
0076     /** Get solver type */
0077     QString solverType() const { return metaObject()->className(); }
0078 
0079     /** Get ODE dimension */
0080     int dimension() const { return _dimension; }
0081     /** Set ODE dimension */
0082     virtual void setDimension(int dimension) { _dimension = dimension; }
0083 
0084     /** Get callback function */
0085     Function function() const { return _function; }
0086     /** Set callback function */
0087     virtual void setFunction(Function function) { _function = function; }
0088 
0089     /** Get callback function params */
0090     void* params() const { return _params; }
0091     /** Set callback function params */
0092     virtual void setParams(void* params) { _params = params; }
0093 
0094     /** Get step size */
0095     double stepSize() const { return _stepSize; }
0096     /** Set step size (solver can adjust it later) */
0097     virtual void setStepSize(double stepSize) { _stepSize = stepSize; }
0098 
0099     /** Get absolute allowed local tolerance */
0100     double toleranceAbs() const { return _toleranceAbs; }
0101     /** Set absolute allowed local tolerance */
0102     virtual void setToleranceAbs(double toleranceAbs) { _toleranceAbs = toleranceAbs; }
0103 
0104     /** Get relative allowed local tolerance */
0105     double toleranceRel() const { return _toleranceRel; }
0106     /** Set relative allowed local tolerance */
0107     virtual void setToleranceRel(double toleranceRel) { _toleranceRel = toleranceRel; }
0108 
0109     /** Get error estimation from last step */
0110     double localError() const { return _localError; }
0111     /** Get local tolerance calculated at last step */
0112     double localErrorRatio() const { return _localErrorRatio; }
0113 
0114     /** Calculate function value */
0115     virtual int doCalcFn(double* t, const VectorXd* y, const VectorXd* yvar = nullptr,
0116                             VectorXd* f = nullptr, VectorXd* fvar = nullptr) = 0;
0117 
0118     /** Integrate.
0119      *  \param t Current time (will be updated by the new value)
0120      *  \param t1 Target time
0121      *  \param y Function value
0122      *  \param yvar Function variance
0123      *  \return Solver::OK on success, error status on failure
0124      *  \todo Provide error message
0125      */
0126     virtual int doEvolve(double* t, double t1, VectorXd* y, VectorXd* yvar) = 0;
0127 
0128 public:
0129     /** Status codes for doCalcFn and doEvolve */
0130     enum { OK = 0,
0131            ToleranceError = 2048,
0132            InternalError = 2049,
0133            CollisionDetected = 4096,
0134            IntersectionDetected = 4097,
0135            Aborted = 8192,
0136            CollisionError = 16384,
0137            ConstraintError = 32768
0138     };
0139 
0140 protected:
0141     int      _dimension;
0142     Function _function;
0143     void*    _params;
0144 
0145     double   _stepSize;
0146     double   _toleranceAbs;
0147     double   _toleranceRel;
0148     double   _localError;
0149     double   _localErrorRatio;
0150 };
0151 
0152 inline Solver::Solver(int dimension, Function function, void* params, double stepSize)
0153      : _dimension(dimension), _function(function), _params(params), _stepSize(stepSize),
0154        _toleranceAbs(0.001), _toleranceRel(0.001), _localError(0), _localErrorRatio(0)
0155 {
0156 }
0157 
0158 inline Solver::Solver(double stepSize)
0159      : _dimension(0), _function(nullptr), _params(nullptr), _stepSize(stepSize),
0160        _toleranceAbs(0.001), _toleranceRel(0.001), _localError(0), _localErrorRatio(0)
0161 {
0162 }
0163 
0164 } // namespace StepCore
0165 
0166 #endif
0167