ode.pas 9.4 KB

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