ode.pas 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. {
  2. This file is part of the Numlib package.
  3. Copyright (c) 1986-2000 by
  4. Kees van Ginneken, Wil Kortsmit and Loek van Reij of the
  5. Computational centre of the Eindhoven University of Technology
  6. FPC port Code by Marco van de Voort ([email protected])
  7. documentation by Michael van Canneyt ([email protected])
  8. Solve first order starting value differential eqs, and
  9. sets of first order starting value differential eqs,
  10. Both versions are not suited for stiff differential equations
  11. See the file COPYING.FPC, included in this distribution,
  12. for details about the copyright.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16. **********************************************************************}
  17. {$IFNDEF FPC_DOTTEDUNITS}
  18. Unit ode;
  19. {$ENDIF FPC_DOTTEDUNITS}
  20. {$I DIRECT.INC}
  21. interface
  22. {$IFDEF FPC_DOTTEDUNITS}
  23. uses NumLib.Typ;
  24. {$ELSE FPC_DOTTEDUNITS}
  25. uses typ;
  26. {$ENDIF FPC_DOTTEDUNITS}
  27. {Solve first order, starting value, differential eqs,
  28. Calc y(b) for dy/dx=f(x,y) and y(a)=ae}
  29. Procedure odeiv1(f: rfunc2r; a, ya: ArbFloat; Var b, yb: ArbFloat;
  30. ae: ArbFloat; Var term: ArbInt);
  31. { The same as above, for a set of equations. ya and yb are vectors}
  32. Procedure odeiv2(f: oderk1n; a: ArbFloat; Var ya, b, yb: ArbFloat;
  33. n: ArbInt; ae: ArbFloat; Var term: ArbInt);
  34. implementation
  35. Procedure odeiv1(f: rfunc2r; a, ya: ArbFloat; Var b, yb: ArbFloat;
  36. ae: ArbFloat; Var term: ArbInt);
  37. Var last, first, reject, goon : boolean;
  38. x, y, d, h, xl, yl, int, hmin,
  39. absh,k0, k1, k2, k3, k4, k5,
  40. discr, tol, mu, mu1, fh, hl : ArbFloat;
  41. Begin
  42. x := a;
  43. y := ya;
  44. d := b-a;
  45. yb := y;
  46. term := 1;
  47. If ae <= 0 Then
  48. Begin
  49. term := 3;
  50. exit
  51. End;
  52. If d <> 0 Then
  53. Begin
  54. xl := x;
  55. yl := y;
  56. h := d/4;
  57. absh := abs(h);
  58. int := abs(d);
  59. hmin := int*1e-6;
  60. ae := ae/int;
  61. first := true;
  62. goon := true;
  63. while goon Do
  64. Begin
  65. absh := abs(h);
  66. If absh < hmin Then
  67. Begin
  68. If h>0 Then h := hmin
  69. Else h := -hmin;
  70. absh := hmin
  71. End;
  72. If (h >= b-xl) = (h >= 0) Then
  73. Begin
  74. last := true;
  75. h := b-xl;
  76. absh := abs(h)
  77. End
  78. Else last := false;
  79. x := xl;
  80. y := yl;
  81. k0 := f(x,y)*h;
  82. x := xl+h*2/9;
  83. y := yl+k0*2/9;
  84. k1 := f(x,y)*h;
  85. x := xl+h/3;
  86. y := yl+(k0+k1*3)/12;
  87. k2 := f(x,y)*h;
  88. x := xl+h/2;
  89. y := yl+(k0+k2*3)/8;
  90. k3 := f(x,y)*h;
  91. x := xl+h*0.8;
  92. y := yl+(k0*53-k1*135+k2*126+k3*56)/125;
  93. k4 := f(x,y)*h;
  94. If last Then x := b
  95. Else x := xl+h;
  96. y := yl+(k0*133-k1*378+k2*276+k3*112+k4*25)/168;
  97. k5 := f(x,y)*h;
  98. discr := abs(21*(k0-k3)-162*(k2-k3)-125*(k4-k3)+42*(k5-k3))/14;
  99. tol := absh*ae;
  100. mu := 1/(1+discr/tol)+0.45;
  101. reject := discr > tol;
  102. If reject Then
  103. Begin
  104. If absh <= hmin Then
  105. Begin
  106. b := xl;
  107. yb := yl;
  108. term := 2;
  109. exit
  110. End;
  111. h := mu*h
  112. End
  113. Else
  114. Begin
  115. If first Then
  116. Begin
  117. first := false;
  118. hl := h;
  119. h := mu*h
  120. End
  121. Else
  122. Begin
  123. fh := mu*h/hl+mu-mu1;
  124. hl := h;
  125. h := fh*h
  126. End;
  127. mu1 := mu;
  128. y := yl+(-k0*63+k1*189-k2*36-k3*112+k4*50)/28;
  129. k5 := f(x,y)*hl;
  130. y := yl+(k0*35+k2*162+k4*125+k5*14)/336;
  131. If b <> x Then
  132. Begin
  133. xl := x;
  134. yl := y
  135. End
  136. Else
  137. Begin
  138. yb := y;
  139. goon := false
  140. End
  141. End {not reject}
  142. End; {while}
  143. End {d<>0}
  144. End; {odeiv1}
  145. Procedure odeiv2(f: oderk1n; a: ArbFloat; Var ya, b, yb: ArbFloat;
  146. n: ArbInt; ae: ArbFloat; Var term: ArbInt);
  147. Var pya, pyb, yl, k0, k1, k2, k3, k4, k5, y : ^arfloat1;
  148. i, jj, ns : ArbInt;
  149. last, first, reject, goon : boolean;
  150. x, xl, hmin, int, hl, absh, fhm,
  151. discr, tol, mu, mu1, fh, d, h : ArbFloat;
  152. Begin
  153. If (ae <= 0) Or (n < 1) Then
  154. Begin
  155. term := 3;
  156. exit
  157. End;
  158. ns := n*sizeof(ArbFloat);
  159. pya := @ya;
  160. pyb := @yb;
  161. move(pya^[1], pyb^[1], ns);
  162. term := 1;
  163. getmem(yl, ns);
  164. getmem(k0, ns);
  165. getmem(k1, ns);
  166. getmem(k2, ns);
  167. getmem(k3, ns);
  168. getmem(k4, ns);
  169. getmem(k5, ns);
  170. getmem(y, ns);
  171. x := a;
  172. d := b-a;
  173. move(pya^[1], y^[1], ns);
  174. If d <> 0 Then
  175. Begin
  176. xl := x;
  177. move(y^[1], yl^[1], ns);
  178. h := d/4;
  179. absh := abs(h);
  180. int := abs(d);
  181. hmin := int*1e-6;
  182. hl := ae;
  183. ae := ae/int;
  184. first := true;
  185. goon := true;
  186. while goon Do
  187. Begin
  188. absh := abs(h);
  189. If absh < hmin Then
  190. Begin
  191. If h > 0 Then h := hmin
  192. Else h := -hmin;
  193. absh := hmin
  194. End;
  195. If (h >= b-xl) = (h >= 0) Then
  196. Begin
  197. last := true;
  198. h := b-xl;
  199. absh := abs(h)
  200. End
  201. Else last := false;
  202. x := xl;
  203. move(yl^[1], y^[1], ns);
  204. f(x, y^[1], k0^[1]);
  205. For i:=1 To n Do
  206. k0^[i] := k0^[i]*h;
  207. x := xl+h*2/9;
  208. For jj:=1 To n Do
  209. y^[jj] := yl^[jj]+k0^[jj]*2/9;
  210. f(x, y^[1], k1^[1]);
  211. For i:=1 To n Do
  212. k1^[i] := k1^[i]*h;
  213. x := xl+h/3;
  214. For jj:=1 To n Do
  215. y^[jj] := yl^[jj]+(k0^[jj]+k1^[jj]*3)/12;
  216. f(x, y^[1], k2^[1]);
  217. For i:=1 To n Do
  218. k2^[i] := k2^[i]*h;
  219. x := xl+h/2;
  220. For jj:=1 To n Do
  221. y^[jj] := yl^[jj]+(k0^[jj]+k2^[jj]*3)/8;
  222. f(x, y^[1], k3^[1]);
  223. For i:=1 To n Do
  224. k3^[i] := k3^[i]*h;
  225. x := xl+h*0.8;
  226. For jj:=1 To n Do
  227. y^[jj] := yl^[jj]+
  228. (k0^[jj]*53-k1^[jj]*135+k2^[jj]*126+k3^[jj]*56)/125;
  229. f(x, y^[1], k4^[1]);
  230. For i:=1 To n Do
  231. k4^[i] := k4^[i]*h;
  232. If last Then x := b
  233. Else x := xl+h;
  234. For jj:=1 To n Do
  235. y^[jj] := yl^[jj]+(k0^[jj]*133-k1^[jj]*378+k2^[jj]*276+
  236. k3^[jj]*112+k4^[jj]*25)/168;
  237. f(x, y^[1], k5^[1]);
  238. For i:=1 To n Do
  239. k5^[i] := k5^[i]*h;
  240. reject := false;
  241. fhm := 0;
  242. tol := absh*ae;
  243. For jj:=1 To n Do
  244. Begin
  245. discr := abs((k0^[jj]-k3^[jj])*21-(k2^[jj]-k3^[jj])*162-
  246. (k4^[jj]-k3^[jj])*125+(k5^[jj]-k3^[jj])*42)/14;
  247. reject := (discr > tol) Or reject;
  248. fh := discr/tol;
  249. If fh > fhm Then fhm := fh
  250. End; {jj}
  251. mu := 1/(1+fhm)+0.45;
  252. If reject Then
  253. Begin
  254. If absh <= hmin Then
  255. Begin
  256. b := xl;
  257. move(yl^[1], pyb^[1], ns);
  258. term := 2;
  259. freemem(yl, ns);
  260. freemem(k0, ns);
  261. freemem(k1, ns);
  262. freemem(k2, ns);
  263. freemem(k3, ns);
  264. freemem(k4, ns);
  265. freemem(k5, ns);
  266. freemem(y, ns);
  267. exit
  268. End;
  269. h := mu*h
  270. End
  271. Else
  272. Begin
  273. If first Then
  274. Begin
  275. first := false;
  276. hl := h;
  277. h := mu*h
  278. End
  279. Else
  280. Begin
  281. fh := mu*h/hl+mu-mu1;
  282. hl := h;
  283. h := fh*h
  284. End;
  285. mu1 := mu;
  286. For jj:=1 To n Do
  287. y^[jj] := yl^[jj]+(-k0^[jj]*63+k1^[jj]*189
  288. -k2^[jj]*36-k3^[jj]*112+k4^[jj]*50)/28;
  289. f(x, y^[1], k5^[1]);
  290. For i:=1 To n Do
  291. k5^[i] := k5^[i]*hl;
  292. For jj:=1 To n Do
  293. y^[jj] := yl^[jj]+(k0^[jj]*35+k2^[jj]*162+k4^[jj]*125
  294. +k5^[jj]*14)/336;
  295. If b <> x Then
  296. Begin
  297. xl := x;
  298. move(y^[1], yl^[1], ns)
  299. End
  300. Else
  301. Begin
  302. move(y^[1], pyb^[1], ns);
  303. goon := false
  304. End
  305. End {not reject}
  306. End {while}
  307. End; {d<>0}
  308. freemem(yl, ns);
  309. freemem(k0, ns);
  310. freemem(k1, ns);
  311. freemem(k2, ns);
  312. freemem(k3, ns);
  313. freemem(k4, ns);
  314. freemem(k5, ns);
  315. freemem(y, ns)
  316. End; {odeiv2}
  317. End.