num_interp.F90 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. module num_interp
  2. implicit none
  3. ! --- in/out -------------------
  4. private
  5. public :: Interp_Lin
  6. public :: Interp_Lin_Weight
  7. public :: CircInterp_Lin
  8. public :: Interp_MuHerm
  9. ! --- const ---------------------------------
  10. character(len=*), parameter :: mname = 'num_interp'
  11. ! --- interfaces -----------------
  12. interface Interp_Lin
  13. module procedure linterp_1
  14. module procedure linterp_1_row
  15. module procedure linterp_2
  16. module procedure linterp_3
  17. end interface
  18. interface CircInterp_Lin
  19. module procedure linterp_1_circ
  20. end interface
  21. contains
  22. ! =====================================================
  23. !----------------------------------------------------------------------
  24. ! NAME
  25. ! linterp - makes a linear interpolation.
  26. !
  27. ! SYNOPSIS
  28. ! call linterp( x,y, x0,y0, last )
  29. !
  30. ! ARGUMENTS
  31. ! x (in) the array of x-values
  32. ! y (in) the array of y-values
  33. ! x0 (in) the location where interpolation is desired
  34. ! y0 (out) The interpolated value
  35. ! last (inout) A first guess of the index of the left hand
  36. ! edge of the interval, in which x0 lies. On return
  37. ! this variable has the exact index.
  38. !
  39. ! DESCRIPTION
  40. ! This version uses linear interpolation only in the interior of
  41. ! the array x. If x0<x(1), or if x0>x(end) then y0 will be
  42. ! x(1) or x(end) resp.
  43. !
  44. ! The modified Boor routine INTERVAL is used to locate x0 within
  45. ! the array x.
  46. !
  47. !-----------------------------------------------------------------------
  48. subroutine linterp_1( x,y, x0, y0, last, status )
  49. use GO, only : gol, goErr
  50. use num_tools, only : interval
  51. ! --- in/out ------------------------
  52. real, intent(in) :: x(:), y(:)
  53. real, intent(in) :: x0
  54. real, intent(out) :: y0
  55. integer, intent(inout) :: last
  56. integer, intent(out) :: status
  57. ! --- const ---------------------------------
  58. character(len=*), parameter :: rname = mname//'/linterp_1'
  59. ! --- local -------------------------
  60. integer :: mflag
  61. integer :: n
  62. ! --- begin -----------------------
  63. ! length of input arrays
  64. n = size(x)
  65. if ( size(y) /= n ) then
  66. write (gol,'("x and y should have same lengths:")'); call goErr
  67. write (gol,'(" size(x) : ",i6)') size(x); call goErr
  68. write (gol,'(" size(y) : ",i6)') size(y); call goErr
  69. write (gol,'("in ",a)') rname; call goErr; status=1; return
  70. end if
  71. ! determine interval in x that contains x0 :
  72. call Interval( x, x0, last, mflag )
  73. if ( mflag == 0 ) then
  74. y0 = y(last) + (x0-x(last))*(y(last+1)-y(last))/(x(last+1)-x(last))
  75. else if ( mflag .lt. 0 ) then
  76. ! x0 is <x(1)
  77. y0 = y(1)
  78. else
  79. ! x0 is >x(n)
  80. y0 = y(n)
  81. endif
  82. ! ok
  83. status = 0
  84. end subroutine linterp_1
  85. ! ===
  86. ! similar, but now y is a rank 2 array;
  87. ! last dimension corresponds to 'x'
  88. subroutine linterp_2( x, y, x0, y0, last, status )
  89. use GO , only : gol, goErr
  90. use num_tools, only : interval
  91. ! --- in/out ------------------------
  92. real, intent(in) :: x(:), y(:,:)
  93. real, intent(in) :: x0
  94. real, intent(out) :: y0(:)
  95. integer, intent(inout) :: last
  96. integer, intent(out) :: status
  97. ! --- const ---------------------------------
  98. character(len=*), parameter :: rname = mname//'/linterp_2'
  99. ! --- local -------------------------
  100. integer :: mflag
  101. integer :: n
  102. ! --- begin -----------------------
  103. ! length of input arrays
  104. n = size(x)
  105. if ( size(y,2) /= n ) then
  106. write (gol,'("dim 2 of y should have same length as x :")'); call goErr
  107. write (gol,'(" size(x) : ", i6)') size(x); call goErr
  108. write (gol,'(" shape(y) : ",2i6)') shape(y); call goErr
  109. write (gol,'("in ",a)') rname; call goErr; status=1; return
  110. stop
  111. end if
  112. if ( size(y0) /= size(y,1) ) then
  113. write (gol,'("output y0 should have same number of elements as first dim of y:")'); call goErr
  114. write (gol,'(" size(y0) : ", i6)') size(y0); call goErr
  115. write (gol,'(" shape(y) : ",2i6)') shape(y); call goErr
  116. write (gol,'("in ",a)') rname; call goErr; status=1; return
  117. stop
  118. end if
  119. ! determine position of x0 in array x :
  120. call Interval( x, x0, last, mflag )
  121. ! inter- or extra-polation based on position of x0:
  122. if ( mflag == 0 ) then
  123. y0 = y(:,last) + (x0-x(last))*(y(:,last+1)-y(:,last))/(x(last+1)-x(last))
  124. else if ( mflag .lt. 0 ) then
  125. ! x0 is <x(1)
  126. y0 = y(:,1)
  127. else
  128. ! x0 is >x(n)
  129. y0 = y(:,n)
  130. endif
  131. ! ok
  132. status = 0
  133. end subroutine linterp_2
  134. ! ===
  135. ! similar, but now y is a rank 3 array;
  136. ! last dimension corresponds to 'x'
  137. subroutine linterp_3( x, y, x0, y0, last, status )
  138. use GO , only : gol, goErr
  139. use num_tools, only : interval
  140. ! --- in/out ------------------------
  141. real, intent(in) :: x(:), y(:,:,:)
  142. real, intent(in) :: x0
  143. real, intent(out) :: y0(size(y,1),size(y,2))
  144. integer, intent(inout) :: last
  145. integer, intent(out) :: status
  146. ! --- const ---------------------------------
  147. character(len=*), parameter :: rname = mname//'/linterp_3'
  148. ! --- local -------------------------
  149. integer :: n
  150. integer :: mflag
  151. ! --- begin -----------------------
  152. ! length of input arrays
  153. n = size(x)
  154. if ( size(y,3) /= n ) then
  155. write (gol,'("dim 3 of y should have same length as x :")'); call goErr
  156. write (gol,'(" size(x) : ", i6)') size(x); call goErr
  157. write (gol,'(" shape(y) : ",3i6)') shape(y); call goErr
  158. write (gol,'("in ",a)') rname; call goErr; status=1; return
  159. stop
  160. end if
  161. if ( (size(y0,1) /= size(y,1)) .or. (size(y0,2) /= size(y,2)) ) then
  162. write (gol,'("output y0 should have same shape as first dims of y:")'); call goErr
  163. write (gol,'(" shape(y0) : ",2i6)') shape(y0); call goErr
  164. write (gol,'(" shape(y) : ",3i6)') shape(y); call goErr
  165. write (gol,'("in ",a)') rname; call goErr; status=1; return
  166. stop
  167. end if
  168. ! determine position of x0 in array x :
  169. call Interval( x, x0, last, mflag )
  170. ! inter- or extra-polation based on position of x0:
  171. if ( mflag == 0 ) then
  172. ! x0 in [x(last),x(last+1)]
  173. y0 = y(:,:,last) + (x0-x(last))*(y(:,:,last+1)-y(:,:,last))/(x(last+1)-x(last))
  174. else if ( mflag .lt. 0 ) then
  175. ! x0 is <x(1)
  176. y0 = y(:,:,1)
  177. else
  178. ! x0 is >x(n)
  179. y0 = y(:,:,n)
  180. endif
  181. ! ok
  182. status = 0
  183. end subroutine linterp_3
  184. ! ===
  185. !
  186. ! weights such that:
  187. !
  188. ! y(:) defined on axis x(:)
  189. ! x0 on axis x(:)
  190. ! y interpolated to x0 = sum( y(:) * w(:) )
  191. !
  192. subroutine Interp_Lin_Weight( x, x0, w, status )
  193. use GO , only : gol, goErr
  194. use num_tools, only : interval
  195. ! --- in/out ------------------------
  196. real, intent(in) :: x(:)
  197. real, intent(in) :: x0
  198. real, intent(out) :: w(:)
  199. integer, intent(out) :: status
  200. ! --- const ---------------------------------
  201. character(len=*), parameter :: rname = mname//'/Interp_Lin_Weight'
  202. ! --- local -------------------------
  203. integer :: last
  204. integer :: mflag
  205. integer :: n
  206. ! --- begin -----------------------
  207. ! length of input arrays
  208. n = size(x)
  209. if ( size(w) /= n ) then
  210. write (gol,'("arrays x and w should have same length:")'); call goErr
  211. write (gol,'(" size(x) : ",i6)') size(x); call goErr
  212. write (gol,'(" size(w) : ",i6)') size(w); call goErr
  213. write (gol,'("in ",a)') rname; call goErr; status=1; return
  214. end if
  215. ! initial zero
  216. w = 0.0
  217. last = 1
  218. call Interval( x, x0, last, mflag )
  219. if ( mflag == 0 ) then
  220. ! y0 = y(last) + (x0-x(last))*(y(last+1)-y(last))/(x(last+1)-x(last))
  221. ! = [1-(x0-x(last))/(x(last+1)-x(last))]*y(last) + [(x0-x(last))/(x(last+1)-x(last))]*y(last+1)
  222. w(last+1) = (x0-x(last))/(x(last+1)-x(last))
  223. w(last ) = 1.0 - w(last+1)
  224. else if ( mflag .lt. 0 ) then
  225. ! x0 is <x(1)
  226. !y0 = y(1)
  227. w(1) = 1.0
  228. else
  229. ! x0 is >x(n)
  230. !y0 = y(n)
  231. w(n) = 1.0
  232. endif
  233. ! ok
  234. status = 0
  235. end subroutine Interp_Lin_Weight
  236. ! ===
  237. ! idem with x periodic with periode p
  238. !
  239. ! 25-04-2002
  240. ! Debugged: division by zero if x(n)==x(1)
  241. !
  242. subroutine linterp_1_circ( x, p, y, x0, y0, last, status )
  243. use GO , only : gol, goErr
  244. use num_tools, only : Interval
  245. ! --- in/out ------------------------
  246. real, intent(in) :: x(:), y(:)
  247. real, intent(in) :: p
  248. real, intent(in) :: x0
  249. real, intent(out) :: y0
  250. integer, intent(inout) :: last
  251. integer, intent(out) :: status
  252. ! --- const ---------------------------------
  253. character(len=*), parameter :: rname = mname//'/linterp_1_circ'
  254. ! --- local -------------------------
  255. integer :: mflag
  256. integer :: n, i
  257. real :: x0p
  258. ! --- begin -----------------------
  259. ! length of input arrays
  260. n = size(x)
  261. if ( size(y) /= n ) then
  262. write (gol,'("x and y should have same lengths:")'); call goErr
  263. write (gol,'(" size(x) : ",i6)') size(x); call goErr
  264. write (gol,'(" size(y) : ",i6)') size(y); call goErr
  265. write (gol,'("in ",a)') rname; call goErr; status=1; return
  266. end if
  267. ! check position of x0
  268. if ( x0 >= x(1) .and. x0 <= x(n) ) then
  269. ! x0 in [x(1),x(n)]
  270. x0p = x0
  271. else
  272. ! set x0p in [x(1),x(1)+p)
  273. x0p = x(1) + modulo(x0-x(1),p)
  274. end if
  275. ! deterimine interval with x0p :
  276. call Interval( x, x0p, last, mflag )
  277. if ( mflag == 0 ) then
  278. ! default interpolation
  279. y0 = y(last) + (x0p-x(last))*(y(last+1)-y(last))/(x(last+1)-x(last))
  280. else if ( mflag < 0 ) then
  281. ! impossible that x0 < x(1) ...
  282. write (gol,'("internal error: x0 is smaller than x(1) :")'); call goErr
  283. write (gol,'(" x0 : ",e16.4)') x0; call goErr
  284. write (gol,'(" p : ",e16.4)') p; call goErr
  285. write (gol,'(" x0p : ",e16.4)') x0p; call goErr
  286. write (gol,'(" x : ",e16.4)') x; call goErr
  287. write (gol,'("in ",a)') rname; call goErr; status=1; return
  288. else
  289. ! mflag > 0, thus x0p is between x(n) and first x(i) > x(n)
  290. i = 1
  291. do
  292. if ( x(n) < p+x(i) ) exit
  293. i = i + 1
  294. end do
  295. y0 = y(n) + (x0p-x(n))*(y(i)-y(n))/(modulo(x(i),p)-modulo(x(n),p))
  296. end if
  297. ! ok
  298. status = 0
  299. end subroutine linterp_1_circ
  300. ! ===
  301. subroutine linterp_1_row( x,y, x0, y0, status )
  302. use GO, only : gol, goErr
  303. ! --- in/out ------------------------
  304. real, intent(in) :: x(:), y(:)
  305. real, intent(in) :: x0(:)
  306. real, intent(out) :: y0(:)
  307. integer, intent(out) :: status
  308. ! --- const ---------------------------------
  309. character(len=*), parameter :: rname = mname//'/linterp_1_row'
  310. ! --- local -------------------------
  311. integer :: n
  312. integer :: i
  313. integer :: last
  314. ! --- begin -----------------------
  315. ! check input shapes:
  316. n = size(x0)
  317. if ( size(y0) /= n ) then
  318. write (gol,'("x and y should have same lengths:")'); call goErr
  319. write (gol,'(" size(x) : ",i6)') size(x); call goErr
  320. write (gol,'(" size(y) : ",i6)') size(y); call goErr
  321. write (gol,'("in ",a)') rname; call goErr; status=1; return
  322. end if
  323. ! loop over interpolation points:
  324. last = 0
  325. do i = 1, n
  326. call Interp_lin( x, y, x0(i), y0(i), last, status )
  327. if (status/=0) then; write (gol,'("ERROR in ",a)') rname; status=1; return; end if
  328. end do
  329. ! ok
  330. status = 0
  331. end subroutine linterp_1_row
  332. ! =======================================================================
  333. !----------------------------------------------------------------------
  334. ! Hermite cubic interpolation from one vector to annother
  335. ! Input: x the array of x-values
  336. ! y the array of y-values
  337. ! n the no. of x and y values
  338. ! x0 the locations where interpolation is desired
  339. ! Output: y0 the interpolated values
  340. ! Input: m no of values to interpolate
  341. !
  342. ! both arrays x(n) and x0(m) are assumed to be strictly monotonically
  343. ! increasing
  344. !
  345. ! If x0.lt.x(1), or if x0.gt.x(n) then y0 will be extrapolated
  346. ! linearly
  347. !
  348. !-----------------------------------------------------------------------
  349. ! original name: muherm
  350. subroutine Interp_MuHerm( x, y, x0, y0, status )
  351. ! --- in/out ----------------------------------
  352. real, intent(in) :: x(:)
  353. real, intent(in) :: y(size(x))
  354. real, intent(in) :: x0(:)
  355. real, intent(out) :: y0(size(x0))
  356. integer, intent(out) :: status
  357. ! --- const ---------------------------------
  358. character(len=*), parameter :: rname = mname//'/Interp_MuHerm'
  359. ! --- local -----------------------------------
  360. integer :: n, m
  361. integer :: last, mflag
  362. real :: fx(size(x))
  363. real :: a1, a2, a3, a4
  364. real :: g1, g2, g3
  365. real :: hp, hm
  366. real :: xi
  367. integer :: i, k
  368. integer :: il
  369. ! --- begin -------------------------------------
  370. n = size(x)
  371. m = size(x0)
  372. ! calculate slopes first
  373. ! use 3pt formula at borders
  374. g1=(2*x(1)-x(2)-x(3))/(x(1)-x(2))/(x(1)-x(3))
  375. g2=(x(1)-x(3))/(x(2)-x(1))/(x(2)-x(3))
  376. g3=(x(1)-x(2))/(x(3)-x(1))/(x(3)-x(2))
  377. fx(1)=g1*y(1)+g2*y(2)+g3*y(3)
  378. g1=(x(n)-x(n-1))/(x(n-2)-x(n-1))/(x(n-2)-x(n))
  379. g2=(x(n)-x(n-2))/(x(n-1)-x(n-2))/(x(n-1)-x(n))
  380. g3=(2*x(n)-x(n-1)-x(n-2))/(x(n)-x(n-2))/(x(n)-x(n-1))
  381. fx(n)=g1*y(n-2)+g2*y(n-1)+g3*y(n)
  382. do i = 2, n-1
  383. hp=x(i+1)-x(i)
  384. hm=x(i)-x(i-1)
  385. g1=-hp/(hm*(hp+hm))
  386. g2=(hp-hm)/(hp*hm)
  387. g3=hm/(hp*(hp+hm))
  388. fx(i)=y(i-1)*g1+y(i)*g2+y(i+1)*g3
  389. end do
  390. ! do now the interpolation
  391. ! index of left border of interval where x0(k) is located
  392. il=1
  393. do k = 1, m
  394. if(x0(k).lt.x(1)) then
  395. y0(k)=y(1)+fx(1)*(x0(k)-x(1))
  396. else if(x0(k).gt.x(n)) then
  397. y0(k)=y(n)+fx(n)*(x0(k)-x(n))
  398. else
  399. do
  400. if ( x0(k) .gt. x(il+1) ) then
  401. il=il+1
  402. cycle
  403. else
  404. xi=(x0(k)-x(il))/(x(il+1)-x(il))
  405. a1=f1(1-xi)
  406. a2=f1(xi)
  407. a3=-f2(1-xi)
  408. a4=f2(xi)
  409. y0(k)=a1*y(il)+a2*y(il+1)+(x(il+1)-x(il))*(a3*fx(il)+a4*fx(il+1))
  410. exit
  411. end if
  412. end do
  413. endif
  414. end do
  415. ! ok
  416. status = 0
  417. return
  418. contains
  419. real function f1(u)
  420. real, intent(in) :: u
  421. f1 = u*u*(-2*u+3)
  422. end function f1
  423. real function f2(u)
  424. real, intent(in) :: u
  425. f2 = u*u*(u-1)
  426. end function f2
  427. end subroutine Interp_MuHerm
  428. end module num_interp