banded5x5.f 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. c banded5x5.f
  2. c
  3. c This Fortran library contains implementations of the
  4. c differential equation
  5. c dy/dt = A*y
  6. c where A is a 5x5 banded matrix (see below for the actual
  7. c values). These functions will be used to test
  8. c scipy.integrate.odeint.
  9. c
  10. c The idea is to solve the system two ways: pure Fortran, and
  11. c using odeint. The "pure Fortran" solver is implemented in
  12. c the subroutine banded5x5_solve below. It calls LSODA to
  13. c solve the system.
  14. c
  15. c To solve the same system using odeint, the functions in this
  16. c file are given a python wrapper using f2py. Then the code
  17. c in test_odeint_jac.py uses the wrapper to implement the
  18. c equation and Jacobian functions required by odeint. Because
  19. c those functions ultimately call the Fortran routines defined
  20. c in this file, the two method (pure Fortran and odeint) should
  21. c produce exactly the same results. (That's assuming floating
  22. c point calculations are deterministic, which can be an
  23. c incorrect assumption.) If we simply re-implemented the
  24. c equation and Jacobian functions using just python and numpy,
  25. c the floating point calculations would not be performed in
  26. c the same sequence as in the Fortran code, and we would obtain
  27. c different answers. The answer for either method would be
  28. c numerically "correct", but the errors would be different,
  29. c and the counts of function and Jacobian evaluations would
  30. c likely be different.
  31. c
  32. block data jacobian
  33. implicit none
  34. double precision bands
  35. dimension bands(4,5)
  36. common /jac/ bands
  37. c The data for a banded Jacobian stored in packed banded
  38. c format. The full Jacobian is
  39. c
  40. c -1, 0.25, 0, 0, 0
  41. c 0.25, -5, 0.25, 0, 0
  42. c 0.10, 0.25, -25, 0.25, 0
  43. c 0, 0.10, 0.25, -125, 0.25
  44. c 0, 0, 0.10, 0.25, -625
  45. c
  46. c The columns in the following layout of numbers are
  47. c the upper diagonal, main diagonal and two lower diagonals
  48. c (i.e. each row in the layout is a column of the packed
  49. c banded Jacobian). The values 0.00D0 are in the "don't
  50. c care" positions.
  51. data bands/
  52. + 0.00D0, -1.0D0, 0.25D0, 0.10D0,
  53. + 0.25D0, -5.0D0, 0.25D0, 0.10D0,
  54. + 0.25D0, -25.0D0, 0.25D0, 0.10D0,
  55. + 0.25D0, -125.0D0, 0.25D0, 0.00D0,
  56. + 0.25D0, -625.0D0, 0.00D0, 0.00D0
  57. + /
  58. end
  59. subroutine getbands(jac)
  60. double precision jac
  61. dimension jac(4, 5)
  62. cf2py intent(out) jac
  63. double precision bands
  64. dimension bands(4,5)
  65. common /jac/ bands
  66. integer i, j
  67. do 5 i = 1, 4
  68. do 5 j = 1, 5
  69. jac(i, j) = bands(i, j)
  70. 5 continue
  71. return
  72. end
  73. c
  74. c Differential equations, right-hand-side
  75. c
  76. subroutine banded5x5(n, t, y, f)
  77. implicit none
  78. integer n
  79. double precision t, y, f
  80. dimension y(n), f(n)
  81. double precision bands
  82. dimension bands(4,5)
  83. common /jac/ bands
  84. f(1) = bands(2,1)*y(1) + bands(1,2)*y(2)
  85. f(2) = bands(3,1)*y(1) + bands(2,2)*y(2) + bands(1,3)*y(3)
  86. f(3) = bands(4,1)*y(1) + bands(3,2)*y(2) + bands(2,3)*y(3)
  87. + + bands(1,4)*y(4)
  88. f(4) = bands(4,2)*y(2) + bands(3,3)*y(3) + bands(2,4)*y(4)
  89. + + bands(1,5)*y(5)
  90. f(5) = bands(4,3)*y(3) + bands(3,4)*y(4) + bands(2,5)*y(5)
  91. return
  92. end
  93. c
  94. c Jacobian
  95. c
  96. c The subroutine assumes that the full Jacobian is to be computed.
  97. c ml and mu are ignored, and nrowpd is assumed to be n.
  98. c
  99. subroutine banded5x5_jac(n, t, y, ml, mu, jac, nrowpd)
  100. implicit none
  101. integer n, ml, mu, nrowpd
  102. double precision t, y, jac
  103. dimension y(n), jac(nrowpd, n)
  104. integer i, j
  105. double precision bands
  106. dimension bands(4,5)
  107. common /jac/ bands
  108. do 15 i = 1, 4
  109. do 15 j = 1, 5
  110. if ((i - j) .gt. 0) then
  111. jac(i - j, j) = bands(i, j)
  112. end if
  113. 15 continue
  114. return
  115. end
  116. c
  117. c Banded Jacobian
  118. c
  119. c ml = 2, mu = 1
  120. c
  121. subroutine banded5x5_bjac(n, t, y, ml, mu, bjac, nrowpd)
  122. implicit none
  123. integer n, ml, mu, nrowpd
  124. double precision t, y, bjac
  125. dimension y(5), bjac(nrowpd, n)
  126. integer i, j
  127. double precision bands
  128. dimension bands(4,5)
  129. common /jac/ bands
  130. do 20 i = 1, 4
  131. do 20 j = 1, 5
  132. bjac(i, j) = bands(i, j)
  133. 20 continue
  134. return
  135. end
  136. subroutine banded5x5_solve(y, nsteps, dt, jt, nst, nfe, nje)
  137. c jt is the Jacobian type:
  138. c jt = 1 Use the full Jacobian.
  139. c jt = 4 Use the banded Jacobian.
  140. c nst, nfe and nje are outputs:
  141. c nst: Total number of internal steps
  142. c nfe: Total number of function (i.e. right-hand-side)
  143. c evaluations
  144. c nje: Total number of Jacobian evaluations
  145. implicit none
  146. external banded5x5
  147. external banded5x5_jac
  148. external banded5x5_bjac
  149. external LSODA
  150. c Arguments...
  151. double precision y, dt
  152. integer nsteps, jt, nst, nfe, nje
  153. cf2py intent(inout) y
  154. cf2py intent(in) nsteps, dt, jt
  155. cf2py intent(out) nst, nfe, nje
  156. c Local variables...
  157. double precision atol, rtol, t, tout, rwork
  158. integer iwork
  159. dimension y(5), rwork(500), iwork(500)
  160. integer neq, i
  161. integer itol, iopt, itask, istate, lrw, liw
  162. c Common block...
  163. double precision jacband
  164. dimension jacband(4,5)
  165. common /jac/ jacband
  166. c --- t range ---
  167. t = 0.0D0
  168. c --- Solver tolerances ---
  169. rtol = 1.0D-11
  170. atol = 1.0D-13
  171. itol = 1
  172. c --- Other LSODA parameters ---
  173. neq = 5
  174. itask = 1
  175. istate = 1
  176. iopt = 0
  177. iwork(1) = 2
  178. iwork(2) = 1
  179. lrw = 500
  180. liw = 500
  181. c --- Call LSODA in a loop to compute the solution ---
  182. do 40 i = 1, nsteps
  183. tout = i*dt
  184. if (jt .eq. 1) then
  185. call LSODA(banded5x5, neq, y, t, tout,
  186. & itol, rtol, atol, itask, istate, iopt,
  187. & rwork, lrw, iwork, liw,
  188. & banded5x5_jac, jt)
  189. else
  190. call LSODA(banded5x5, neq, y, t, tout,
  191. & itol, rtol, atol, itask, istate, iopt,
  192. & rwork, lrw, iwork, liw,
  193. & banded5x5_bjac, jt)
  194. end if
  195. 40 if (istate .lt. 0) goto 80
  196. nst = iwork(11)
  197. nfe = iwork(12)
  198. nje = iwork(13)
  199. return
  200. 80 write (6,89) istate
  201. 89 format(1X,"Error: istate=",I3)
  202. return
  203. end