Advertisement
term007

simple cubic spline module

Nov 9th, 2012
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Fortran 11.15 KB | None | 0 0
  1.     ! =======================================================================
  2.     ! Module
  3.     ! =======================================================================
  4.     module spline_module
  5.       ! [specification part]
  6.       implicit none
  7.       integer, parameter, private :: dp = kind(1.0d0)
  8.  
  9.       private
  10.  
  11.       public :: spline,splint,ratint,polint
  12.  
  13.       ! [execution part]
  14.  
  15.     contains
  16.       ! [your functions]
  17.     ! =======================================================================
  18.     ! subroutine
  19.     ! =======================================================================
  20.       subroutine spline(x,y,yp1,ypn,y2)
  21.         implicit none
  22.         real (dp), dimension (:), intent (in) :: x, y
  23.         real (dp), intent (in) :: yp1, ypn
  24.         real (dp), dimension (:), intent (inout) :: y2
  25.         integer :: n
  26.         real (dp), dimension (size(x)) :: a, b, c, r
  27.  
  28.         n = assert_eq3(size(x),size(y),size(y2),'spline')
  29.         c(1:n-1) = x(2:n) - x(1:n-1)
  30.         r(1:n-1) = 6.0_dp*((y(2:n)-y(1:n-1))/c(1:n-1))
  31.         r(2:n-1) = r(2:n-1) - r(1:n-2)
  32.         a(2:n-1) = c(1:n-2)
  33.         b(2:n-1) = 2.0_dp*(c(2:n-1)+a(2:n-1))
  34.         b(1) = 1.0_dp
  35.         b(n) = 1.0_dp
  36.         if (yp1>0.99d30) then
  37.           r(1) = 0.0_dp
  38.           c(1) = 0.0_dp
  39.         else
  40.           r(1) = (3.0_dp/(x(2)-x(1)))*((y(2)-y(1))/(x(2)-x(1))-yp1)
  41.           c(1) = 0.5_dp
  42.         end if
  43.         if (ypn>0.99d30) then
  44.           r(n) = 0.0_dp
  45.           a(n) = 0.0_dp
  46.         else
  47.           r(n) = (-3.0_dp/(x(n)-x(n-1)))*((y(n)-y(n-1))/(x(n)-x(n-1))-ypn)
  48.           a(n) = 0.5_dp
  49.         end if
  50.         call tridag_par(a(2:n),b(1:n),c(1:n-1),r(1:n),y2(1:n))
  51.       end subroutine spline
  52.  
  53.     ! =======================================================================
  54.     ! subroutine
  55.     ! =======================================================================
  56.       function splint(xa,ya,y2a,x)
  57.  
  58.         implicit none
  59.         real (dp), dimension (:), intent (in) :: xa, ya, y2a
  60.         real (dp), intent (in) :: x
  61.         real (dp) :: splint
  62.         integer :: khi, klo, n
  63.         real (dp) :: a, b, h
  64.  
  65.         n = assert_eq3(size(xa),size(ya),size(y2a),'splint')
  66.         klo = max(min(locate(xa,x),n-1),1)
  67.         khi = klo + 1
  68.         h = xa(khi) - xa(klo)
  69.         if (h==0.0_dp) call nrerror('bad xa input in splint') ! MOD
  70.         a = (xa(khi)-x)/h
  71.         b = (x-xa(klo))/h
  72.         splint = a*ya(klo) + b*ya(khi) + ((a**3-a)*y2a(klo)+(b**3-b)*y2a(khi)) *(h**2)/6.0_dp
  73.       end function splint
  74.  
  75.  
  76.  
  77.     ! =======================================================================
  78.     ! subroutine
  79.     ! =======================================================================
  80.       subroutine polint(xa,ya,x,y,dy)
  81.         implicit none
  82.         real (dp), dimension (:), intent (in) :: xa, ya
  83.         real (dp), intent (in) :: x
  84.         real (dp), intent (out) :: y, dy
  85.         integer :: m, n, ns
  86.         real (dp), dimension (size(xa)) :: c, d, den, ho
  87.  
  88.         n = assert_eq2(size(xa),size(ya),'polint')
  89.         c = ya
  90.         d = ya
  91.         ho = xa - x
  92.         ns = iminloc(abs(xa-x))
  93.         y = ya(ns)
  94.         ns = ns - 1
  95.         do m = 1, n - 1
  96.           den(1:n-m) = ho(1:n-m) - ho(1+m:n)
  97.           if (any(den(1:n-m)==0.0_dp)) call nrerror('polint: calculation failure') ! MOD
  98.           den(1:n-m) = (c(2:n-m+1)-d(1:n-m))/den(1:n-m)
  99.           d(1:n-m) = ho(1+m:n)*den(1:n-m)
  100.           c(1:n-m) = ho(1:n-m)*den(1:n-m)
  101.           if (2*ns<n-m) then
  102.             dy = c(ns+1)
  103.           else
  104.             dy = d(ns)
  105.             ns = ns - 1
  106.           end if
  107.           y = y + dy
  108.         end do
  109.       end subroutine polint
  110.  
  111.     ! =======================================================================
  112.     ! subroutine
  113.     ! =======================================================================
  114.       subroutine ratint(xa,ya,x,y,dy)
  115.         implicit none
  116.         real (dp), dimension (:), intent (in) :: xa, ya
  117.         real (dp), intent (in) :: x
  118.         real (dp), intent (out) :: y, dy
  119.         integer :: m, n, ns
  120.         real (dp), dimension (size(xa)) :: c, d, dd, h, t
  121.         real (dp), parameter :: MTINY = 1.0d-25
  122.  
  123.         n = assert_eq2(size(xa),size(ya),'ratint')
  124.         h = xa - x
  125.         ns = iminloc(abs(h))
  126.         y = ya(ns)
  127.         if (x==xa(ns)) then        ! TODO
  128.           dy = 0.0_dp
  129.           return
  130.         end if
  131.         c = ya
  132.         d = ya + MTINY
  133.         ns = ns - 1
  134.         do m = 1, n - 1
  135.           t(1:n-m) = (xa(1:n-m)-x)*d(1:n-m)/h(1+m:n)
  136.           dd(1:n-m) = t(1:n-m) - c(2:n-m+1)
  137.           if (any(dd(1:n-m)==0.0_dp)) call nrerror('failure in ratint') ! MOD
  138.           dd(1:n-m) = (c(2:n-m+1)-d(1:n-m))/dd(1:n-m)
  139.           d(1:n-m) = c(2:n-m+1)*dd(1:n-m)
  140.           c(1:n-m) = t(1:n-m)*dd(1:n-m)
  141.           if (2*ns<n-m) then
  142.             dy = c(ns+1)
  143.           else
  144.             dy = d(ns)
  145.             ns = ns - 1
  146.           end if
  147.           y = y + dy
  148.         end do
  149.       end subroutine ratint
  150.  
  151.  
  152.     ! =======================================================================
  153.     ! subroutine
  154.     ! =======================================================================
  155.       subroutine tridag_ser(a,b,c,r,u)
  156.         implicit none
  157.         real (dp), dimension (:), intent (in) :: a, b, c, r
  158.         real (dp), dimension (:), intent (inout) :: u
  159.         real (dp), dimension (size(b)) :: gam
  160.         integer :: n, j
  161.         real (dp) :: bet
  162.  
  163.         n = assert_eqn((/size(a)+1,size(b),size(c)+1,size(r),size(u)/), 'tridag_ser')
  164.         bet = b(1)
  165.         if (bet==0.0_dp) call nrerror('tridag_ser: error at code stage 1')
  166.         ! MOD
  167.         u(1) = r(1)/bet
  168.         do j = 2, n
  169.           gam(j) = c(j-1)/bet
  170.           bet = b(j) - a(j-1)*gam(j)
  171.           if (bet==0.0_dp) call nrerror('tridag_ser: error at code stage 2')
  172.           ! MOD
  173.           u(j) = (r(j)-a(j-1)*u(j-1))/bet
  174.         end do
  175.         do j = n - 1, 1, -1
  176.           u(j) = u(j) - gam(j+1)*u(j+1)
  177.         end do
  178.       end subroutine tridag_ser
  179.  
  180.     ! =======================================================================
  181.     ! subroutine
  182.     ! =======================================================================
  183.       recursive subroutine tridag_par(a,b,c,r,u)
  184.         implicit none
  185.         real (dp), dimension (:), intent (in) :: a, b, c, r
  186.         real (dp), dimension (:), intent (inout) :: u
  187.         integer, parameter :: NPAR_TRIDAG = 4
  188.         integer :: n, n2, nm, nx
  189.         real (dp), dimension (size(b)/2) :: y, q, piva
  190.         real (dp), dimension (size(b)/2-1) :: x, z
  191.         real (dp), dimension (size(a)/2) :: pivc
  192.  
  193.         n = assert_eqn((/size(a)+1,size(b),size(c)+1,size(r),size(u)/), 'tridag_par')
  194.         if (n<NPAR_TRIDAG) then
  195.           call tridag_ser(a,b,c,r,u)
  196.         else
  197.           if (maxval(abs(b(1:n)))==0.0_dp) call nrerror('tridag_par: possible singular matrix') ! MOD
  198.           n2 = size(y)
  199.           nm = size(pivc)
  200.           nx = size(x)
  201.           piva = a(1:n-1:2)/b(1:n-1:2)
  202.           pivc = c(2:n-1:2)/b(3:n:2)
  203.           y(1:nm) = b(2:n-1:2) - piva(1:nm)*c(1:n-2:2) - pivc*a(2:n-1:2)
  204.           q(1:nm) = r(2:n-1:2) - piva(1:nm)*r(1:n-2:2) - pivc*r(3:n:2)
  205.           if (nm<n2) then
  206.             y(n2) = b(n) - piva(n2)*c(n-1)
  207.             q(n2) = r(n) - piva(n2)*r(n-1)
  208.           end if
  209.           x = -piva(2:n2)*a(2:n-2:2)
  210.           z = -pivc(1:nx)*c(3:n-1:2)
  211.           call tridag_par(x,y,z,q,u(2:n:2))
  212.           u(1) = (r(1)-c(1)*u(2))/b(1)
  213.           u(3:n-1:2) = (r(3:n-1:2)-a(2:n-2:2)*u(2:n-2:2)-c(3:n-1:2)*u(4:n:2))/b(3:n-1:2)
  214.           if (nm==n2) u(n) = (r(n)-a(n-1)*u(n-1))/b(n)
  215.         end if
  216.       end subroutine tridag_par
  217.  
  218.     ! =======================================================================
  219.     ! function
  220.     ! =======================================================================
  221.       function locate(xx,x)
  222.         implicit none
  223.         real (dp), dimension (:), intent (in) :: xx
  224.         real (dp), intent (in) :: x
  225.         integer :: locate
  226.         integer :: n, jl, jm, ju
  227.         logical :: ascnd
  228.  
  229.         n = size(xx)
  230.         ascnd = (xx(n)>=xx(1))
  231.         jl = 0
  232.         ju = n + 1
  233.         do
  234.           if (ju-jl<=1) exit
  235.           jm = (ju+jl)/2
  236.           if (ascnd .eqv. (x>=xx(jm))) then
  237.             jl = jm
  238.           else
  239.             ju = jm
  240.           end if
  241.         end do
  242.         if (x==xx(1)) then         ! TODO
  243.           locate = 1
  244.         else if (x==xx(n)) then    ! TODO
  245.           locate = n - 1
  246.         else
  247.           locate = jl
  248.         end if
  249.       end function locate
  250.  
  251.     ! =======================================================================
  252.     ! function
  253.     ! =======================================================================
  254.       function assert_eq2(n1,n2,string)
  255.         implicit none
  256.         character (len=*), intent (in) :: string
  257.         integer, intent (in) :: n1, n2
  258.         integer :: assert_eq2
  259.  
  260.         if (n1==n2) then
  261.           assert_eq2 = n1
  262.         else
  263.           write (*,*) 'nrerror: an assert_eq failed with this tag:', string
  264.           stop 'program terminated by assert_eq2'
  265.         end if
  266.       end function assert_eq2
  267.  
  268.     ! =======================================================================
  269.     ! function
  270.     ! =======================================================================
  271.       function assert_eq3(n1,n2,n3,string)
  272.         implicit none
  273.         character (len=*), intent (in) :: string
  274.         integer, intent (in) :: n1, n2, n3
  275.         integer :: assert_eq3
  276.  
  277.         if (n1==n2 .and. n2==n3) then
  278.           assert_eq3 = n1
  279.         else
  280.           write (*,*) 'nrerror: an assert_eq failed with this tag:', string
  281.           stop 'program terminated by assert_eq3'
  282.         end if
  283.       end function assert_eq3
  284.  
  285.     ! =======================================================================
  286.     ! function
  287.     ! =======================================================================
  288.       function assert_eqn(nn,string)
  289.         implicit none
  290.         character (len=*), intent (in) :: string
  291.         integer, dimension (:), intent (in) :: nn
  292.         integer :: assert_eqn
  293.  
  294.         if (all(nn(2:)==nn(1))) then
  295.           assert_eqn = nn(1)
  296.         else
  297.           write (*,*) 'nrerror: an assert_eq failed with this tag:', string
  298.           stop 'program terminated by assert_eqn'
  299.         end if
  300.       end function assert_eqn
  301.  
  302.     ! =======================================================================
  303.     ! subroutine
  304.     ! =======================================================================
  305.       subroutine nrerror(string)
  306.         character (len=*), intent (in) :: string
  307.  
  308.         write (*,*) 'nrerror: ', string
  309.         stop 'program terminated by nrerror'
  310.       end subroutine nrerror
  311.  
  312.     ! =======================================================================
  313.     ! function
  314.     ! =======================================================================
  315.       function iminloc(arr)
  316.         implicit none
  317.         real (dp), dimension (:), intent (in) :: arr
  318.         integer, dimension (1) :: imin
  319.         integer :: iminloc
  320.  
  321.         imin = minloc(arr(:))
  322.         iminloc = imin(1)
  323.       end function iminloc
  324.  
  325.     end module spline_module
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement