This atomic class computes the analytical solution (a.k.a. closed-form solution) of the first-order, constant coefficient, linear, homogeneous ODE.
For more details, consult http://oregonstate.edu/dept/math/CalculusQuestStudyGuides/ode/first/linear/linear.html
/// analytical_frst_ord.cc /// Atomic class that computes the analytical solution (a.k.a. closed-form solution) /// of the first-order, constant coefficient, linear, homogeneous ODE. /// /// ODE: /// xdot = B - A*x /// /// Initial conditions: /// x(t_IC) = x_IC /// /// Analytical solution: (can be used to compute the true integration error) /// For more details, consult /// http://oregonstate.edu/dept/math/CalculusQuestStudyGuides/ode/first/linear/linear.html /// /// x(t) = C * exp(-A*(t-t_IC)) + B/A /// where: /// C + b/a = x_IC /// b/a = lim x (t->inf) /// /// where : /// x : dynamic variable /// xdot : first derivative of x /// /// A : constant coefficient /// B : constant coefficient /// /////////////////////////////////////////////////////////////////////////////// #ifdef SPARK_PARSER PORT time "time" [s]; PORT A "A"; PORT B "B"; PORT x "x"; PORT xdot "xdot"; PORT x_IC "initial condition for x"; EQUATIONS { x, xdot = analytical_frst_ord( time, x_IC, A, B ); } FUNCTIONS { x, xdot = analytical_frst_ord__evaluate( time ) CONSTRUCT = analytical_frst_ord__construct( time, x_IC, A, B ) DESTRUCT = analytical_frst_ord__destruct( ) ; } #endif /*SPARK_PARSER*/ #include <strstream> using std::ostrstream; using std::ends; #include <iostream> using std::endl; #include "spark.h" // Class that calculates the analytical solution of a 1st-order // ODE with constant, linear coefficients. The equations // describing the analytical solution are constructed in the class // constructor. class TData { public: // Structors TData(double t_IC, double x_IC, double a, double b) : T_IC(t_IC), C(x_IC - B/A), A(a), B(b) {} ~TData() {} // Main methods double x(double time) { return C * exp(-A*(time-T_IC)) + B/A; } double xdot(double time) { return -A * C * exp(-A*(time-T_IC)); } double GetA() const { return A; } double GetB() const { return B; } double GetC() const { return C; } double GetT_IC() const { return T_IC; } private: // Private data double T_IC; double A ; double B ; double C; }; EVALUATE( analytical_frst_ord__evaluate ) { ARGUMENT( 0, time ); TARGET( 0, x ); TARGET( 1, xdot ); // Retrieve private data GET_DATA( THIS, TData, MyData ); // The previous line is equivalent to: // TData* MyData = static_cast<TData*>( THIS->GetData() ); // Set target values x = MyData->x( time ); xdot = MyData->xdot( time ); } CONSTRUCT( analytical_frst_ord__construct ) { ARGUMENT( 0, time ); ARGUMENT( 1, x_IC ); ARGUMENT( 2, A ); ARGUMENT( 3, B ); // Allocate instance private data TData* MyData = new TData( time, x_IC, A, B ); // Check whether memory was allocated correctly or not if ( MyData == 0 ) { REQUEST__ABORT( "Could not allocate instance private data!" ); } // Store pointer to private data within this object SET_DATA( THIS, TData, MyData ); // The previous line is equivalent to: // THIS->SetData( MyData ); // Report equation string for analytical solution to run log file ostrstream Text; Text << "x(t) = " << MyData->GetC() << " * exp(" << MyData->GetA() << "*( time - " << MyData->GetT_IC() << ") ) + " << MyData->GetB()/MyData->GetA() << ends; RUN_LOG( Text.str() ); } DESTRUCT( analytical_frst_ord__destruct ) { // Release allocated memory // (the false flag indicates that this not a built-in array type) DELETE_DATA( THIS, TData, false ); // The previous line is equivalent to: // TData* MyData = static_cast<TData*>( THIS->GetData() ); // if ( MyData ) { // delete MyData; // } }