ode.pas 9.2 KB

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