DBINT4 computes the B representation (t,bcoef,n,k) of a
cubic spline (k=4) which interpolates data (x(i),y(i)),i=1,ndata.
Parameters ibcl, ibcr, fbcl, fbcr allow the specification of the spline
first or second derivative at both x(1) and x(ndata). When this data is not specified
by the problem, it is common practice to use a natural spline by setting second
derivatives at x(1) and x(ndata) to zero (ibcl=ibcr=2,fbcl=fbcr=0.0).
The spline is defined on t(4) <= x <= t(n+1) with (ordered) interior knots at
x(i) values where n=ndata+2. The knots t(1),t(2),t(3) lie to the left of
t(4)=x(1) and the knots t(n+2), t(n+3), t(n+4) lie to the right of t(n+1)=x(ndata)
in increasing order.
x(1),x(ndata)) is anticipated, the
knots t(1)=t(2)=t(3)=t(4)=x(1) and t(n+2)=t(n+3)=t(n+4)=t(n+1)=x(ndata)
can be specified by kntopt=1.kntopt=2 selects a knot placement for t(1), t(2), t(3) to make the
first 7 knots symmetric about t(4)=x(1) and similarly for
t(n+2), t(n+3), t(n+4) about t(n+1)=x(ndata).kntopt=3 allows the user to make his own selection, in increasing order,
for t(1), t(2), t(3) to the left of x(1) and t(n+2), t(n+3), t(n+4) to
the right of x(ndata).In any case, the interpolation on t(4) <= x <= t(n+1)
by using function dbvalu is unique for given boundary
conditions.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in), | dimension(:) | :: | x |
x vector of abscissae of length |
|
| real(kind=wp), | intent(in), | dimension(:) | :: | y |
y vector of ordinates of length ndata |
|
| integer(kind=ip), | intent(in) | :: | ndata |
number of data points, |
||
| integer(kind=ip), | intent(in) | :: | ibcl |
selection parameter for left boundary condition:
|
||
| integer(kind=ip), | intent(in) | :: | ibcr |
selection parameter for right boundary condition:
|
||
| real(kind=wp), | intent(in) | :: | fbcl |
left boundary values governed by |
||
| real(kind=wp), | intent(in) | :: | fbcr |
right boundary values governed by |
||
| integer(kind=ip), | intent(in) | :: | kntopt |
knot selection parameter:
|
||
| real(kind=wp), | intent(in), | dimension(3) | :: | tleft |
when |
|
| real(kind=wp), | intent(in), | dimension(3) | :: | tright |
when |
|
| real(kind=wp), | intent(out), | dimension(:) | :: | t |
knot array of length |
|
| real(kind=wp), | intent(out), | dimension(:) | :: | bcoef |
b spline coefficient array of length |
|
| integer(kind=ip), | intent(out) | :: | n |
number of coefficients, |
||
| integer(kind=ip), | intent(out) | :: | k |
order of spline, |
||
| real(kind=wp), | intent(inout), | dimension(5,ndata+2) | :: | w |
work array |
|
| integer(kind=ip), | intent(out) | :: | iflag |
status flag:
|
pure subroutine dbint4(x,y,ndata,ibcl,ibcr,fbcl,fbcr,kntopt,tleft,tright,t,bcoef,n,k,w,iflag) implicit none real(wp),dimension(:),intent(in) :: x !! x vector of abscissae of length `ndata`, distinct !! and in increasing order real(wp),dimension(:),intent(in) :: y !! y vector of ordinates of length ndata integer(ip),intent(in) :: ndata !! number of data points, `ndata >= 2` integer(ip),intent(in) :: ibcl !! selection parameter for left boundary condition: !! !! * `ibcl = 1` constrain the first derivative at `x(1)` to `fbcl` !! * `ibcl = 2` constrain the second derivative at `x(1)` to `fbcl` integer(ip),intent(in) :: ibcr !! selection parameter for right boundary condition: !! !! * `ibcr = 1` constrain first derivative at `x(ndata)` to `fbcr` !! * `ibcr = 2` constrain second derivative at `x(ndata)` to `fbcr` real(wp),intent(in) :: fbcl !! left boundary values governed by `ibcl` real(wp),intent(in) :: fbcr !! right boundary values governed by `ibcr` integer(ip),intent(in) :: kntopt !! knot selection parameter: !! !! * `kntopt = 1` sets knot multiplicity at `t(4)` and !! `t(n+1)` to 4 !! * `kntopt = 2` sets a symmetric placement of knots !! about `t(4)` and `t(n+1)` !! * `kntopt = 3` sets `t(i)=tleft(i)` and !! `t(n+1+i)=tright(i)`,`i=1,3` real(wp),dimension(3),intent(in) :: tleft !! when `kntopt = 3`: `t(1:3)` in increasing !! order to be supplied by the user. real(wp),dimension(3),intent(in) :: tright !! when `kntopt = 3`: `t(n+2:n+4)` in increasing !! order to be supplied by the user. real(wp),dimension(:),intent(out) :: t !! knot array of length `n+4` real(wp),dimension(:),intent(out) :: bcoef !! b spline coefficient array of length `n` integer(ip),intent(out) :: n !! number of coefficients, `n=ndata+2` integer(ip),intent(out) :: k !! order of spline, `k=4` real(wp),dimension(5,ndata+2),intent(inout) :: w !! work array integer(ip),intent(out) :: iflag !! status flag: !! !! * 0: no errors !! * 2001: `ndata` is less than 2 !! * 2002: `x` values are not distinct or not ordered !! * 2003: `ibcl` is not 1 or 2 !! * 2004: `ibcr` is not 1 or 2 !! * 2005: `kntopt` is not 1, 2, or 3 !! * 2006: knot input through `tleft`, `tright` is !! not ordered properly !! * 2007: the system of equations is singular integer(ip) :: i, ilb, ileft, it, iub, iw, iwp, j, jw, ndm, np, nwrow real(wp) :: txn, tx1, xl real(wp),dimension(4,4) :: vnikx real(wp),dimension(15) :: work !! work array for [[dbspvd]] -- length `(k+1)*(k+2)/2` real(wp),parameter :: wdtol = epsilon(1.0_wp) !! d1mach(4) real(wp),parameter :: tol = sqrt(wdtol) if (ndata<2_ip) then iflag = 2001_ip ! ndata is less than 2 return end if ndm = ndata - 1_ip do i=1_ip,ndm if (x(i)>=x(i+1_ip)) then iflag = 2002_ip ! x values are not distinct or not ordered return end if end do if (ibcl<1_ip .or. ibcl>2_ip) then iflag = 2003_ip ! ibcl is not 1 or 2 return end if if (ibcr<1_ip .or. ibcr>2_ip) then iflag = 2004_ip ! ibcr is not 1 or 2 return end if if (kntopt<1_ip .or. kntopt>3_ip) then iflag = 2005_ip ! kntopt is not 1, 2, or 3 return end if iflag = 0_ip k = 4_ip n = ndata + 2_ip np = n + 1_ip do i=1_ip,ndata t(i+3) = x(i) end do select case (kntopt) case(1_ip) ! set up knot array with multiplicity 4 at x(1) and x(ndata) do i=1,3_ip t(4-i) = x(1) t(np+i) = x(ndata) end do case(2_ip) !set up knot array with symmetric placement about end points if (ndata>3) then tx1 = x(1) + x(1) txn = x(ndata) + x(ndata) do i=1,3 t(4-i) = tx1 - x(i+1) t(np+i) = txn - x(ndata-i) end do else xl = (x(ndata)-x(1))/3.0_wp do i=1,3 t(4-i) = t(5-i) - xl t(np+i) = t(np+i-1) + xl end do end if case(3) ! set up knot array less than x(1) and greater than x(ndata) to be ! supplied by user in tleft & tright when kntopt=3 t(1:3) = tleft t(ndata+4:ndata+6) = tright do i=1,3 if ((t(4-i)>t(5-i)) .or. (t(np+i)<t(np+i-1))) then iflag = 2006_ip ! knot input through tleft, tright is not ordered properly return end if end do end select w = 0.0_wp ! set up left interpolation point and left boundary condition for ! right limits it = ibcl + 1 call dbspvd(t, k, it, x(1), k, 4_ip, vnikx, work, iflag) if (iflag/=0_ip) return ! error check iw = 0_ip if (abs(vnikx(3,1))<tol) iw = 1_ip do j=1,3 w(j+1,4-j) = vnikx(4-j,it) w(j,4-j) = vnikx(4-j,1) end do bcoef(1) = y(1) bcoef(2) = fbcl ! set up interpolation equations for points i=2 to i=ndata-1 ileft = 4_ip if (ndm>=2) then do i=2,ndm ileft = ileft + 1_ip call dbspvd(t, k, 1_ip, x(i), ileft, 4_ip, vnikx, work, iflag) if (iflag/=0_ip) return ! error check do j=1,3 w(j+1,3+i-j) = vnikx(4-j,1) end do bcoef(i+1) = y(i) end do end if ! set up right interpolation point and right boundary condition for ! left limits(ileft is associated with t(n)=x(ndata-1)) it = ibcr + 1_ip call dbspvd(t, k, it, x(ndata), ileft, 4_ip, vnikx, work, iflag) if (iflag/=0_ip) return ! error check jw = 0_ip if (abs(vnikx(2,1))<tol) jw = 1_ip do j=1,3 w(j+1,3+ndata-j) = vnikx(5-j,it) w(j+2,3+ndata-j) = vnikx(5-j,1) end do bcoef(n-1) = fbcr bcoef(n) = y(ndata) ! solve system of equations ilb = 2_ip - jw iub = 2_ip - iw nwrow = 5_ip iwp = iw + 1_ip call dbnfac(w(iwp,1), nwrow, n, ilb, iub, iflag) if (iflag==2_ip) then iflag = 2007_ip ! the system of equations is singular else iflag = 0_ip ! success call dbnslv(w(iwp,1), nwrow, n, ilb, iub, bcoef) end if end subroutine dbint4