1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-24 Bradley M. Bell
// ----------------------------------------------------------------------------
/*
{xrst_begin ode_stiff.cpp}
{xrst_spell
rosen
}
A Stiff Ode: Example and Test
#############################
Define
:math:`x : \B{R} \rightarrow \B{R}^2` by
.. math::
:nowrap:
\begin{eqnarray}
x_0 (0) & = & 1 \\
x_1 (0) & = & 0 \\
x_0^\prime (t) & = & - a_0 x_0 (t) \\
x_1^\prime (t) & = & + a_0 x_0 (t) - a_1 x_1 (t)
\end{eqnarray}
If :math:`a_0 \gg a_1 > 0`, this is a stiff Ode and
the analytic solution is
.. math::
:nowrap:
\begin{eqnarray}
x_0 (t) & = & \exp( - a_0 t ) \\
x_1 (t) & = & a_0 [ \exp( - a_1 t ) - \exp( - a_0 t ) ] / ( a_0 - a_1 )
\end{eqnarray}
The example tests Rosen34 using the relations above:
{xrst_literal
// BEGIN C++
// END C++
}
{xrst_end ode_stiff.cpp}
*/
// BEGIN C++
# include <cppad/cppad.hpp>
// To print the comparison, change the 0 to 1 on the next line.
# define CPPAD_ODE_STIFF_PRINT 0
namespace {
// --------------------------------------------------------------
class Fun {
private:
CPPAD_TESTVECTOR(double) a;
public:
// constructor
Fun(const CPPAD_TESTVECTOR(double)& a_) : a(a_)
{ }
// compute f(t, x)
void Ode(
const double &t,
const CPPAD_TESTVECTOR(double) &x,
CPPAD_TESTVECTOR(double) &f)
{ f[0] = - a[0] * x[0];
f[1] = + a[0] * x[0] - a[1] * x[1];
}
// compute partial of f(t, x) w.r.t. t
void Ode_ind(
const double &t,
const CPPAD_TESTVECTOR(double) &x,
CPPAD_TESTVECTOR(double) &f_t)
{ f_t[0] = 0.;
f_t[1] = 0.;
}
// compute partial of f(t, x) w.r.t. x
void Ode_dep(
const double &t,
const CPPAD_TESTVECTOR(double) &x,
CPPAD_TESTVECTOR(double) &f_x)
{ f_x[0] = -a[0];
f_x[1] = 0.;
f_x[2] = +a[0];
f_x[3] = -a[1];
}
};
// --------------------------------------------------------------
class RungeMethod {
private:
Fun F;
public:
// constructor
RungeMethod(const CPPAD_TESTVECTOR(double) &a_) : F(a_)
{ }
void step(
double ta ,
double tb ,
CPPAD_TESTVECTOR(double) &xa ,
CPPAD_TESTVECTOR(double) &xb ,
CPPAD_TESTVECTOR(double) &eb )
{ xb = CppAD::Runge45(F, 1, ta, tb, xa, eb);
}
size_t order(void)
{ return 5; }
};
class RosenMethod {
private:
Fun F;
public:
// constructor
RosenMethod(const CPPAD_TESTVECTOR(double) &a_) : F(a_)
{ }
void step(
double ta ,
double tb ,
CPPAD_TESTVECTOR(double) &xa ,
CPPAD_TESTVECTOR(double) &xb ,
CPPAD_TESTVECTOR(double) &eb )
{ xb = CppAD::Rosen34(F, 1, ta, tb, xa, eb);
}
size_t order(void)
{ return 4; }
};
}
bool OdeStiff(void)
{ bool ok = true; // initial return value
CPPAD_TESTVECTOR(double) a(2);
a[0] = 1e3;
a[1] = 1.;
RosenMethod rosen(a);
RungeMethod runge(a);
Fun gear(a);
CPPAD_TESTVECTOR(double) xi(2);
xi[0] = 1.;
xi[1] = 0.;
CPPAD_TESTVECTOR(double) eabs(2);
eabs[0] = 1e-6;
eabs[1] = 1e-6;
CPPAD_TESTVECTOR(double) ef(2);
CPPAD_TESTVECTOR(double) xf(2);
CPPAD_TESTVECTOR(double) maxabs(2);
size_t nstep;
size_t k;
for(k = 0; k < 3; k++)
{
size_t M = 5;
double ti = 0.;
double tf = 1.;
double smin = 1e-7;
double sini = 1e-7;
double smax = 1.;
double scur = .5;
double erel = 0.;
if( k == 0 )
{ xf = CppAD::OdeErrControl(rosen, ti, tf,
xi, smin, smax, scur, eabs, erel, ef, maxabs, nstep);
}
else if( k == 1 )
{ xf = CppAD::OdeErrControl(runge, ti, tf,
xi, smin, smax, scur, eabs, erel, ef, maxabs, nstep);
}
else if( k == 2 )
{ xf = CppAD::OdeGearControl(gear, M, ti, tf,
xi, smin, smax, sini, eabs, erel, ef, maxabs, nstep);
}
double x0 = exp(-a[0]*tf);
ok &= CppAD::NearEqual(x0, xf[0], 0., eabs[0]);
ok &= CppAD::NearEqual(0., ef[0], 0., eabs[0]);
double x1 = a[0] *
(exp(-a[1]*tf) - exp(-a[0]*tf))/(a[0] - a[1]);
ok &= CppAD::NearEqual(x1, xf[1], 0., eabs[1]);
ok &= CppAD::NearEqual(0., ef[1], 0., eabs[0]);
# if CPPAD_ODE_STIFF_PRINT
const char* method[]={ "Rosen34", "Runge45", "Gear5" };
std::cout << std::endl;
std::cout << "method = " << method[k] << std::endl;
std::cout << "nstep = " << nstep << std::endl;
std::cout << "x0 = " << x0 << std::endl;
std::cout << "xf[0] = " << xf[0] << std::endl;
std::cout << "x0 - xf[0] = " << x0 - xf[0] << std::endl;
std::cout << "ef[0] = " << ef[0] << std::endl;
std::cout << "x1 = " << x1 << std::endl;
std::cout << "xf[1] = " << xf[1] << std::endl;
std::cout << "x1 - xf[1] = " << x1 - xf[1] << std::endl;
std::cout << "ef[1] = " << ef[1] << std::endl;
# endif
}
return ok;
}
// END C++
|