ode.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /Commando/Code/wwmath/ODE.CPP 8 7/02/99 10:32a Greg_h $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando *
  24. * *
  25. * $Archive:: /Commando/Code/wwmath/ODE.CPP $*
  26. * *
  27. * Author:: Greg_h *
  28. * *
  29. * $Modtime:: 6/25/99 6:23p $*
  30. * *
  31. * $Revision:: 8 $*
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * Euler_Integrate -- uses Eulers method to integrate a system of ODE's *
  36. * Midpoint_Integrate -- midpoint method (Runge-Kutta 2) for integration *
  37. * Runge_Kutta_Integrate -- Runge Kutta 4 method *
  38. * Runge_Kutta5_Integrate -- 5th order Runge-Kutta *
  39. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  40. #include "ode.h"
  41. #include <assert.h>
  42. static StateVectorClass Y0;
  43. static StateVectorClass Y1;
  44. static StateVectorClass _WorkVector0;
  45. static StateVectorClass _WorkVector1;
  46. static StateVectorClass _WorkVector2;
  47. static StateVectorClass _WorkVector3;
  48. static StateVectorClass _WorkVector4;
  49. static StateVectorClass _WorkVector5;
  50. static StateVectorClass _WorkVector6;
  51. static StateVectorClass _WorkVector7;
  52. /***********************************************************************************************
  53. * Euler_Solve -- uses Eulers method to integrate a system of ODE's *
  54. * *
  55. * INPUT: *
  56. * odesys - pointer to the ODE system to integrate *
  57. * dt - size of the timestep *
  58. * *
  59. * OUTPUT: *
  60. * state vector in odesys will be updated for the next timestep *
  61. * *
  62. * WARNINGS: *
  63. * *
  64. * HISTORY: *
  65. * 08/11/1997 GH : Created. *
  66. * 6/25/99 GTH : Updated to the new integrator system *
  67. *=============================================================================================*/
  68. void IntegrationSystem::Euler_Integrate(ODESystemClass * sys, float dt)
  69. {
  70. WWASSERT(sys != NULL);
  71. /*
  72. ** Get the current state
  73. */
  74. Y0.Reset();
  75. sys->Get_State(Y0);
  76. Y1.Resize(Y0.Count());
  77. /*
  78. ** make aliases to the work-vectors we need
  79. */
  80. StateVectorClass & dydt = _WorkVector0;
  81. dydt.Resize(Y0.Count());
  82. /*
  83. ** Euler method, just evaluate the derivative, multiply
  84. ** by the time-step and add to the current state vector.
  85. */
  86. sys->Compute_Derivatives(0,NULL,&dydt);
  87. Y1.Resize(Y0.Count());
  88. for (int i = 0; i < Y0.Count(); i++) {
  89. Y1[i] = Y0[i] + dydt[i] * dt;
  90. }
  91. sys->Set_State(Y1);
  92. }
  93. /***********************************************************************************************
  94. * Midpoint_Integrate -- midpoint method (Runge-Kutta 2) *
  95. * *
  96. * INPUT: *
  97. * sys - pointer to the ODE system to integrate *
  98. * dt - size of the timestep *
  99. * *
  100. * OUTPUT: *
  101. * state vector in odesys will be updated for the next timestep *
  102. * *
  103. * WARNINGS: *
  104. * *
  105. * HISTORY: *
  106. * 08/11/1997 GH : Created. *
  107. * 6/25/99 GTH : Updated to the new integrator system *
  108. *=============================================================================================*/
  109. void IntegrationSystem::Midpoint_Integrate(ODESystemClass * sys,float dt)
  110. {
  111. int i;
  112. /*
  113. ** Get the current state
  114. */
  115. Y0.Reset();
  116. sys->Get_State(Y0);
  117. Y1.Resize(Y0.Count());
  118. /*
  119. ** make aliases to the work-vectors we need
  120. */
  121. StateVectorClass & dydt = _WorkVector0;
  122. StateVectorClass & ymid = _WorkVector1;
  123. dydt.Resize(Y0.Count());
  124. ymid.Resize(Y0.Count());
  125. /*
  126. ** MidPoint method, first evaluate the derivitives of the
  127. ** state vector just like the Euler method.
  128. */
  129. sys->Compute_Derivatives(0.0f,NULL,&dydt);
  130. /*
  131. ** Compute the midpoint between the Euler solution and
  132. ** the input values.
  133. */
  134. for (i=0; i<Y0.Count(); i++) {
  135. ymid[i] = Y0[i] + dt * dydt[i] / 2.0f;
  136. }
  137. /*
  138. ** Re-compute derivatives at this point.
  139. */
  140. sys->Compute_Derivatives(dt/2.0f,&ymid,&dydt);
  141. /*
  142. ** Use these derivatives to compute the solution.
  143. */
  144. for (i=0; i<Y0.Count(); i++) {
  145. Y1[i] = Y0[i] + dt * dydt[i];
  146. }
  147. sys->Set_State(Y1);
  148. }
  149. /***********************************************************************************************
  150. * Runge_Kutta_Integrate -- Runge Kutta 4 method *
  151. * *
  152. * INPUT: *
  153. * odesys - pointer to the ODE system to integrate *
  154. * dt - size of the timestep *
  155. * *
  156. * OUTPUT: *
  157. * state vector in odesys will be updated for the next timestep *
  158. * *
  159. * WARNINGS: *
  160. * *
  161. * HISTORY: *
  162. * 08/11/1997 GH : Created. *
  163. *=============================================================================================*/
  164. void IntegrationSystem::Runge_Kutta_Integrate(ODESystemClass * sys,float dt)
  165. {
  166. int i;
  167. float dt2 = dt / 2.0f;
  168. float dt6 = dt / 6.0f;
  169. /*
  170. ** Get the current state
  171. */
  172. Y0.Reset();
  173. sys->Get_State(Y0);
  174. Y1.Resize(Y0.Count());
  175. /*
  176. ** make aliases to the work-vectors we need
  177. */
  178. StateVectorClass & dydt = _WorkVector0;
  179. StateVectorClass & dym = _WorkVector1;
  180. StateVectorClass & dyt = _WorkVector2;
  181. StateVectorClass & yt = _WorkVector3;
  182. dydt.Resize(Y0.Count());
  183. dym.Resize(Y0.Count());
  184. dyt.Resize(Y0.Count());
  185. yt.Resize(Y0.Count());
  186. /*
  187. ** First Step
  188. */
  189. sys->Compute_Derivatives(0.0f,NULL,&dydt);
  190. for (i=0; i<Y0.Count(); i++) {
  191. yt[i] = Y0[i] + dt2 * dydt[i];
  192. }
  193. /*
  194. ** Second Step
  195. */
  196. sys->Compute_Derivatives(dt2, &yt, &dyt);
  197. for (i=0; i<Y0.Count(); i++) {
  198. yt[i] = Y0[i] + dt2 * dyt[i];
  199. }
  200. /*
  201. ** Third Step
  202. */
  203. sys->Compute_Derivatives(dt2, &yt, &dym);
  204. for (i=0; i<Y0.Count(); i++) {
  205. yt[i] = Y0[i] + dt*dym[i];
  206. dym[i] += dyt[i];
  207. }
  208. /*
  209. ** Fourth Step
  210. */
  211. sys->Compute_Derivatives(dt, &yt, &dyt);
  212. for (i=0; i<Y0.Count(); i++) {
  213. Y1[i] = Y0[i] + dt6 * (dydt[i] + dyt[i] + 2.0f*dym[i]);
  214. }
  215. sys->Set_State(Y1);
  216. }
  217. /***********************************************************************************************
  218. * Runge_Kutta5_Integrate -- 5th order Runge-Kutta *
  219. * *
  220. * INPUT: *
  221. * odesys - pointer to the ODE system to integrate *
  222. * dt - size of the timestep *
  223. * *
  224. * OUTPUT: *
  225. * state vector in odesys will be updated for the next timestep *
  226. * *
  227. * WARNINGS: *
  228. * *
  229. * HISTORY: *
  230. * 08/11/1997 GH : Created. *
  231. * 6/25/99 GTH : Converted to the new Integrator system *
  232. *=============================================================================================*/
  233. void IntegrationSystem::Runge_Kutta5_Integrate(ODESystemClass * odesys,float dt)
  234. {
  235. int i;
  236. int veclen;
  237. static const float a2 = 0.2f;
  238. static const float a3 = 0.3f;
  239. static const float a4 = 0.6f;
  240. static const float a5 = 1.0f;
  241. static const float a6 = 0.875f;
  242. static const float b21 = 0.2f;
  243. static const float b31 = 3.0f/40.0f;
  244. static const float b32 = 9.0f/40.0f;
  245. static const float b41 = 0.3f;
  246. static const float b42 = -0.9f;
  247. static const float b43 = 1.2f;
  248. static const float b51 = -11.0f /54.0f;
  249. static const float b52 = 2.5f;
  250. static const float b53 = -70.0f/27.0f;
  251. static const float b54 = 35.0f/27.0f;
  252. static const float b61 = 1631.0f/55296.0f;
  253. static const float b62 = 175.0f/512.0f;
  254. static const float b63 = 575.0f/13824.0f;
  255. static const float b64 = 44275.0f/110592.0f;
  256. static const float b65 = 253.0f/4096.0f;
  257. static const float c1 = 37.0f/378.0f;
  258. static const float c3 = 250.0f/621.0f;
  259. static const float c4 = 125.0f/594.0f;
  260. static const float c6 = 512.0f/1771.0f;
  261. static const float dc5 = -277.0f/14336.0f;
  262. static const float dc1 = c1 - 2825.0f/27648.0f;
  263. static const float dc3 = c3 - 18575.0f/48384.0f;
  264. static const float dc4 = c4 - 13525.0f/55296.0f;
  265. static const float dc6 = c6 - 0.25f;
  266. /*
  267. ** Get the current state
  268. */
  269. Y0.Reset();
  270. odesys->Get_State(Y0);
  271. veclen = Y0.Count();
  272. Y1.Resize(veclen);
  273. /*
  274. ** make aliases to the work-vectors we need
  275. */
  276. StateVectorClass & dydt = _WorkVector0;
  277. StateVectorClass & ak2 = _WorkVector1;
  278. StateVectorClass & ak3 = _WorkVector2;
  279. StateVectorClass & ak4 = _WorkVector3;
  280. StateVectorClass & ak5 = _WorkVector4;
  281. StateVectorClass & ak6 = _WorkVector5;
  282. StateVectorClass & ytmp = _WorkVector6;
  283. StateVectorClass & yerr = _WorkVector7;
  284. dydt.Resize(veclen);
  285. ak2.Resize(veclen);
  286. ak3.Resize(veclen);
  287. ak4.Resize(veclen);
  288. ak5.Resize(veclen);
  289. ak6.Resize(veclen);
  290. ytmp.Resize(veclen);
  291. yerr.Resize(veclen);
  292. // First step
  293. odesys->Compute_Derivatives(0.0f,NULL,&dydt);
  294. for (i=0;i<veclen;i++) {
  295. ytmp[i] = Y0[i] + b21*dt*dydt[i];
  296. }
  297. // Second step
  298. odesys->Compute_Derivatives(a2*dt, &ytmp, &ak2);
  299. for (i=0; i<veclen; i++) {
  300. ytmp[i] = Y0[i] + dt*(b31*dydt[i] + b32*ak2[i]);
  301. }
  302. // Third step
  303. odesys->Compute_Derivatives(a3*dt, &ytmp, &ak3);
  304. for (i=0; i<veclen; i++) {
  305. ytmp[i] = Y0[i] + dt*(b41*dydt[i] + b42*ak2[i] + b43*ak3[i]);
  306. }
  307. // Fourth step
  308. odesys->Compute_Derivatives(a4*dt, &ytmp, &ak4);
  309. for (i=0; i<veclen; i++) {
  310. ytmp[i] = Y0[i] + dt*(b51*dydt[i] + b52*ak2[i] + b53*ak3[i] + b54*ak4[i]);
  311. }
  312. // Fifth step
  313. odesys->Compute_Derivatives(a5*dt, &ytmp, &ak5);
  314. for (i=0; i<veclen; i++) {
  315. ytmp[i] = Y0[i] + dt*(b61*dydt[i] + b62*ak2[i] + b63*ak3[i] + b64*ak4[i] + b65*ak5[i]);
  316. }
  317. // Sixth step
  318. odesys->Compute_Derivatives(a6*dt, &ytmp, &ak6);
  319. for (i=0; i<veclen; i++) {
  320. Y1[i] = Y0[i] + dt*(c1*dydt[i] + c3*ak3[i] + c4*ak4[i] + c6*ak6[i]);
  321. }
  322. // Error approximation!
  323. // (maybe I should use this someday? nah not going to use this integrator anyway...)
  324. for (i=0; i<veclen; i++) {
  325. yerr[i] = dt*(dc1*dydt[i] + dc3*ak3[i] + dc4*ak4[i] + dc5*ak5[i] + dc6*ak6[i]);
  326. }
  327. odesys->Set_State(Y1);
  328. }