JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGRungeKutta.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Header: FGRungeKutta.cpp
4  Author: Thomas Kreitler
5  Date started: 04/9/2010
6 
7  ------------- Copyright (C) -------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along with
20  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21  Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be found on
24  the world wide web at http://www.gnu.org.
25 
26 
27 
28 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29  INCLUDES
30 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
31 
32 #include <cstdio>
33 #include <iostream>
34 #include <cmath>
35 
36 #include "FGJSBBase.h"
37 #include "FGRungeKutta.h"
38 
39 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40  DEFINITIONS
41  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
42 
43 using std::cout;
44 using std::endl;
45 
46 namespace JSBSim {
47 
48 IDENT(IdSrc,"$Id: FGRungeKutta.cpp,v 1.3 2014/01/13 10:46:03 ehofman Exp $");
49 IDENT(IdHdr,ID_RUNGEKUTTA);
50 
51 const double FGRungeKutta::RealLimit = 1e30;
52 
53 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
54 CLASS IMPLEMENTATION
55 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
56 
57 FGRungeKutta::~FGRungeKutta() { };
58 
59 int FGRungeKutta::init(double x_start, double x_end, int intervals)
60 {
61  x0 = x_start;
62  x1 = x_end;
63  h = (x_end - x_start)/intervals;
64  safer_x1 = x1 - h*1e-6; // avoid 'intervals*h < x1'
65  h05 = h*0.5;
66  err = 0.0;
67 
68  if (x0>=x1) {
69  status &= eFaultyInit;
70  }
71  return status;
72 }
73 
74 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 
76 /*
77  Make sure that a numerical result is within +/-RealLimit.
78  This is a hapless try to be portable.
79  (There will be at least one architecture/compiler combination
80  where this will fail.)
81 */
82 
83 bool FGRungeKutta::sane_val(double x)
84 {
85  // assuming +/- inf behave as expected and 'nan' comparisons yield to false
86  if ( x < RealLimit && x > -RealLimit ) return true;
87  return false;
88 }
89 
90 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 
92 double FGRungeKutta::evolve(double y_0, FGRungeKuttaProblem *pf)
93 {
94  double x = x0;
95  double y = y_0;
96  pfo = pf;
97 
98  iterations = 0;
99 
100  if (!trace_values) {
101  while (x<safer_x1) {
102  y = approximate(x,y);
103  if (!sane_val(y)) { status &= eMathError; }
104  x += h;
105  iterations++;
106  }
107  } else {
108  while (x<safer_x1) {
109  cout << x << " " << y << endl;
110  y = approximate(x,y);
111  if (!sane_val(y)) { status &= eMathError; }
112  x += h;
113  iterations++;
114  }
115  cout << x << " " << y << endl;
116  }
117 
118  x_end = x; // twimc, store the last x used.
119  return y;
120 }
121 
122 
123 
124 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 CLASS IMPLEMENTATION
126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
127 
128 FGRK4::~FGRK4() { };
129 
130 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131 
132 double FGRK4::approximate(double x, double y)
133 {
134  double k1,k2,k3,k4;
135 
136  k1 = pfo->pFunc(x , y );
137  k2 = pfo->pFunc(x + h05, y + h05*k1);
138  k3 = pfo->pFunc(x + h05, y + h05*k2);
139  k4 = pfo->pFunc(x + h , y + h *k3);
140 
141  y += h/6.0 * ( k1 + 2.0*k2 + 2.0*k3 + k4 );
142 
143  return y;
144 }
145 
146 
147 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 CLASS IMPLEMENTATION
149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
150 
151 // Butcher tableau
152 const double FGRKFehlberg::A2[] = { 0.0, 1.0/4.0 };
153 const double FGRKFehlberg::A3[] = { 0.0, 3.0/32.0, 9.0/32.0 };
154 const double FGRKFehlberg::A4[] = { 0.0, 1932.0/2197.0, -7200.0/2197.0, 7296.0/2197.0 };
155 const double FGRKFehlberg::A5[] = { 0.0, 439.0/216.0, -8.0, 3680.0/513.0, -845.0/4104.0 };
156 const double FGRKFehlberg::A6[] = { 0.0, -8.0/27.0, 2.0, -3544.0/2565.0, 1859.0/4104.0, -11.0/40.0 };
157 
158 const double FGRKFehlberg::C[] = { 0.0, 0.0, 1.0/4.0, 3.0/8.0, 12.0/13.0, 1.0, 1.0/2.0 };
159 
160 const double FGRKFehlberg::B[] = { 0.0, 16.0/135.0, 0.0, 6656.0/12825.0, 28561.0/56430.0, -9.0/50.0, 2.0/55.0 };
161 const double FGRKFehlberg::Bs[] = { 0.0, 25.0/216.0, 0.0, 1408.0/2565.0, 2197.0/4104.0, -1.0/5.0, 0.0 };
162 
163 // use this if truncation is an issue
164 // const double Ee[] = { 0.0, 1.0/360.0, 0.0, -128.0/4275.0, -2197.0/75240.0, 1.0/50.0, 2.0/55.0 };
165 
166 FGRKFehlberg::~FGRKFehlberg() { };
167 
168 double FGRKFehlberg::approximate(double x, double y)
169 {
170 
171  double k1,k2,k3,k4,k5,k6, as;
172 
173  double y4_val;
174  double y5_val;
175  double abs_err;
176  double est_step;
177  int done = 0;
178 
179 
180  while (!done) {
181 
182  err = h*h*h*h*h; // h might change
183 
184  k1 = pfo->pFunc(x , y );
185 
186  as = h*A2[1]*k1;
187  k2 = pfo->pFunc(x + C[2]*h , y + as );
188 
189  as = h*(A3[1]*k1 + A3[2]*k2);
190  k3 = pfo->pFunc(x + C[3]*h , y + as );
191 
192  as = h*(A4[1]*k1 + A4[2]*k2 + A4[3]*k3);
193  k4 = pfo->pFunc(x + C[4]*h , y + as );
194 
195  as = h*(A5[1]*k1 + A5[2]*k2 + A5[3]*k3 + A5[4]*k4);
196  k5 = pfo->pFunc(x + C[5]*h , y + as );
197 
198  as = h*(A6[1]*k1 + A6[2]*k2 + A6[3]*k3 + A6[4]*k4 + A6[5]*k5);
199  k6 = pfo->pFunc(x + C[6]*h , y + as );
200 
201  /* B[2]*k2 and Bs[2]*k2 are zero */
202  y5_val = y + h * ( B[1]*k1 + B[3]*k3 + B[4]*k4 + B[5]*k5 + B[6]*k6);
203  y4_val = y + h * (Bs[1]*k1 + Bs[3]*k3 + Bs[4]*k4 + Bs[5]*k5);
204 
205  abs_err = fabs(y4_val-y5_val);
206  // same in green
207  // abs_err = h * (Ee[1] * k1 + Ee[3] * k3 + Ee[4] * k4 + Ee[5] * k5 + Ee[6] * k6);
208 
209  // estimate step size
210  if (abs_err > epsilon) {
211  est_step = sqrt(sqrt(epsilon*h/abs_err));
212  } else {
213  est_step=2.0*h; // cheat
214  }
215 
216  // check if a smaller step size is proposed
217 
218  if (shrink_avail>0 && est_step<h) {
219  h/=2.0;
220  shrink_avail--;
221  } else {
222  done = 1;
223  }
224 
225  }
226 
227  return y4_val;
228 }
229 
230 
231 } // namespace JSBSim