CppNoddy  0.92
Loading...
Searching...
No Matches
ODE_IVP.cpp
Go to the documentation of this file.
1/// \file ODE_IVP.cpp
2/// Implementation of an \f$n\f$-th order system
3/// of ODEs that form the IVP:
4/// \f[ \underline{ \dot f} (t) = \underline R ( \underline f (t), t) \,, \f]
5/// where \f$ \underline f (0) \f$ is known.
6
7#include <string>
8
9#include <Types.h>
10#include <Equation.h>
11#include <OneD_Node_Mesh.h>
12#include <ODE_IVP.h>
13#include <Exceptions.h>
14#include <Utility.h>
15
16namespace CppNoddy {
17
18 template <typename _Type>
20 const double &x1, const double &x2,
21 const std::size_t &num_of_points) :
22 X_INIT(x1),
23 X_FINAL(x2),
24 H_INIT((x2 - x1) / num_of_points),
25 N(num_of_points),
26 p_EQUATION(ptr),
27 STORE_EVERY(1) {
28 p_EQUATION -> coord(0) = X_INIT;
29 }
30
31 template <typename _Type>
33 {}
34
35 template <typename _Type>
37
38 double x = X_INIT;
39 const double h = H_INIT;
40 const double hby2 = h / 2.;
41 const double hby6 = h / 6.;
42 const double hby3 = h / 3.;
43 const int order = u.size();
44
45 DenseVector<_Type> z(order, 0.0), k1(order, 0.0), k2(order, 0.0), k3(order, 0.0), k4(order, 0.0);
46
48 std::vector< DenseVector<_Type> > values;
50 coords.push_back(x);
51 values.push_back(u);
52
53 for(unsigned i = 0; i < N; i++) {
54 // k1 = F(u,x)
55 p_EQUATION -> coord(0) = x;
56 p_EQUATION -> residual_fn(u, k1);
57 z = u + k1 * hby2;
58
59 x += hby2;
60
61 // k2 = F(z,xhh)
62 p_EQUATION -> coord(0) = x;
63 p_EQUATION -> residual_fn(z, k2);
64 z = u + k2 * hby2;
65
66 // k3 = F(z,xhh)
67 p_EQUATION -> coord(0) = x;
68 p_EQUATION -> residual_fn(z, k3);
69 z = u + k3 * h;
70
71 x += hby2;
72
73 // k4 = F(z,xh)
74 p_EQUATION -> coord(0) = x;
75 p_EQUATION -> residual_fn(z, k4);
76 u += k1 * hby6 + k2 * hby3 + k3 * hby3 + k4 * hby6;
77
78 if(i % STORE_EVERY == 0) {
79 coords.push_back(x);
80 values.push_back(u);
81 }
82
83 } //for loop stepping across domain
84
85 // construct the solution mesh stored in this object
86 SOLN = OneD_Node_Mesh<_Type>(coords, p_EQUATION -> get_order());
87 for(unsigned i = 0; i < coords.size(); ++i) {
88 // fill mesh
89 SOLN.set_nodes_vars(i, values[i]);
90 }
91 return u;
92 }
93
94 template <typename _Type>
95 DenseVector<_Type> ODE_IVP<_Type>::shoot45(DenseVector<_Type> u, const double& tol, const double& h_init) {
96 bool ok(false);
97 unsigned step = 0;
98 double x = X_INIT;
99 double h = h_init;
100 double c, diff;
101
102 static const double X2 = 1. / 4.;
103 static const double X3 = 3. / 8.;
104 static const double X4 = 12. / 13.;
105 static const double X5 = 1.;
106 static const double X6 = 1. / 2.;
107
108 static const double W21 = 1. / 4.;
109
110 static const double W31 = 3. / 32.;
111 static const double W32 = 9. / 32.;
112
113 static const double W41 = 1932. / 2197.;
114 static const double W42 = -7200. / 2197.;
115 static const double W43 = 7296. / 2197.;
116
117 static const double W51 = 439. / 216.;
118 static const double W52 = -8.;
119 static const double W53 = 3680. / 513.;
120 static const double W54 = -845. / 4104;
121
122 static const double W61 = -8. / 27.;
123 static const double W62 = 2.;
124 static const double W63 = -3544. / 2565.;
125 static const double W64 = 1859. / 4104.;
126 static const double W65 = -11. / 40.;
127
128 static const double U1 = 25. / 216.;
129 static const double U3 = 1408. / 2565.;
130 static const double U4 = 2197. / 4104.;
131 static const double U5 = -1. / 5.;
132
133 static const double Z1 = 16. / 135.;
134 static const double Z3 = 6656. / 12825.;
135 static const double Z4 = 28561. / 56430.;
136 static const double Z5 = -9. / 50.;
137 static const double Z6 = 2. / 55.;
138
139 const unsigned order = u.size();
140
141 DenseVector<_Type> z(order, 0.0), e(order, 0.0), k1(order, 0.0),
142 k2(order, 0.0), k3(order, 0.0), k4(order, 0.0), k5(order, 0.0), k6(order, 0.0);
143
145 std::vector< DenseVector<_Type> > values;
146
147 coords.push_back(x);
148 values.push_back(u);
149
150 do {
151 step += 1;
152 // k1 = F(u,x)
153 p_EQUATION -> coord(0) = x;
154 p_EQUATION -> residual_fn(u, k1);
155 k1 *= h;
156 z = u + k1 * W21;
157
158 // k2 = F(z,x+X2*h)
159 p_EQUATION -> coord(0) = x + X2 * h;
160 p_EQUATION -> residual_fn(z, k2);
161 k2 *= h;
162 z = u + k1 * W31 + k2 * W32;
163
164 // k3 = F(z,x+X3*h)
165 p_EQUATION -> coord(0) = x + X3 * h;
166 p_EQUATION -> residual_fn(z, k3);
167 k3 *= h;
168 z = u + k1 * W41 + k2 * W42 + k3 * W43;
169
170 // k4 = F(z,x+X4*h)
171 p_EQUATION -> coord(0) = x + X4 * h;
172 p_EQUATION -> residual_fn(z, k4);
173 k4 *= h;
174 z = u + k1 * W51 + k2 * W52 + k3 * W53 + k4 * W54;
175
176 // k5 = F(z,x+X5*h)
177 p_EQUATION -> coord(0) = x + X5 * h;
178 p_EQUATION -> residual_fn(z, k5);
179 k5 *= h;
180 z = u + k1 * W61 + k2 * W62 + k3 * W63 + k4 * W64 + k5 * W65;
181
182 // k6 = F(z,x+X6*h)
183 p_EQUATION -> coord(0) = x + X6 * h;
184 p_EQUATION -> residual_fn(z, k6);
185 k6 *= h;
186
187 e = k1 * U1 + k3 * U3 + k4 * U4 + k5 * U5;
188 z = k1 * Z1 + k3 * Z3 + k4 * Z4 + k5 * Z5 + k6 * Z6;
189
190 e -= z;
191
192 diff = e.inf_norm();
193
194 c = sqrt(sqrt(tol * h / (2 * diff)));
195 ok = true;
196
197 // is the first step ok? or does it need reducing?
198 if((step == 1) && (c < 1.0)) {
199 // step needs reducing so start from initial value again
200 ok = false;
201 step = 1;
202 }
203
204
205 if(ok) {
206 x += h;
207 u += z;
208
209 if(step % STORE_EVERY == 0) {
210 coords.push_back(x);
211 values.push_back(u);
212 }
213
214 }
215
216 h *= c;
217
218 if(x + h > X_FINAL) {
219 h = (X_FINAL - x);
220 }
221
222 if(step >= N) {
223 std::string problem;
224 problem = "The ODE.shoot45 method reached the maximum \n";
225 problem += "number of steps specified by the user. \n";
226 throw ExceptionRuntime(problem);
227 }
228
229 } while(std::abs(x - X_FINAL) > tol); // end loop stepping across domain
230
231 // construct the solution mesh stored in this object
232 SOLN = OneD_Node_Mesh<_Type>(coords, p_EQUATION -> get_order());
233 for(unsigned i = 0; i < coords.size(); ++i) {
234 // fill mesh
235 SOLN.set_nodes_vars(i, values[i]);
236 }
237
238 return u;
239 }
240
241 template <typename _Type>
243 return SOLN;
244 }
245
246 template <typename _Type>
248 return STORE_EVERY;
249 }
250
251 // the templated versions we require are:
252 template class ODE_IVP<double>
253 ;
254 template class ODE_IVP<std::complex<double> >
255 ;
256
257} // end namespace
258
A templated class for equations that can be inherited from to allow instantiation of ODE/PDE objects ...
The collection of CppNoddy exceptions.
A specification for a class to solve initial value problems of the form.
A specification for a one dimensional mesh object.
A spec for a collection of utility functions.
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
void push_back(const _Type &fill)
A pass-thru definition of push_back.
Definition: DenseVector.h:310
std::size_t size() const
A pass-thru definition to get the size of the vector.
Definition: DenseVector.h:330
An equation object base class used in the BVP/IVP classes.
Definition: Equation.h:22
A generic runtime exception.
Definition: Exceptions.h:158
A templated object for real/complex vector system of first-order ordinary differential equations.
Definition: ODE_IVP.h:20
OneD_Node_Mesh< _Type > & get_mesh()
Return the history of the stepped solution.
Definition: ODE_IVP.cpp:242
unsigned & store_every()
Return a handle to the STORE_EVERY object.
Definition: ODE_IVP.cpp:247
ODE_IVP(Equation< _Type > *equation_ptr, const double &x_init, const double &x_final, const std::size_t &num_of_steps)
The class is defined by a vector function for the system.
Definition: ODE_IVP.cpp:19
DenseVector< _Type > shoot4(DenseVector< _Type > u)
A fixed step 4th order Runge-Kutta method.
Definition: ODE_IVP.cpp:36
DenseVector< _Type > shoot45(DenseVector< _Type > u, const double &tol, const double &h_init)
A Runge-Kutta-Fehlberg integrator.
Definition: ODE_IVP.cpp:95
A one dimensional mesh utility object.
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt