bascmp Subroutine

private subroutine bascmp(me, x, nderiv, xmin, nodes, icol, basm)

This routine does basis function computations for natural splines. This routine is called by routines SPLCW and SPLDE to compute ICOL and BASM, which are defined as follows:

  • The MDIM indices in IB (defined in splpak_type) determine a specific node in the node grid (see routine SPLCC for a description of the node grid). Every node is associated with an MDIM-dimensional basis function and a corresponding column in the least squares matrix (or element of the coefficient vector). The column index (which may be thought of as a linear address for the MDIM-dimensional node grid) corresponding to the specified node is computed as ICOL. The associated basis function evaluated at X (an MDIM-vector) is computed as BASM (a scalar).

In case NDERIV is not all zero, BASM will not be the value of the basis function but rather a partial derivative of that function as follows:

  • The order of the partial derivative in the direction of the IDIM coordinate is NDERIV(IDIM) (for IDIM <= MDIM). This routine will compute incorrect values if NDERIV(IDIM) is not in the range 0 to 2.

The technique of this routine is to transform the independent variable in each dimension such that the nodes fall on suitably chosen integers. On this transformed space, the 1-dimensional basis functions and their derivatives have a particularly simple form. The desired MDIM-dimensional basis function (or any of its partial derivatives) is computed as a product of such 1-dimensional functions (tensor product method of defining multi-dimensional splines). The values which determine the location of the nodes, and hence the above transform, are passed through common and the argument list.

Type Bound

splpak_type

Arguments

Type IntentOptional Attributes Name
class(splpak_type), intent(inout) :: me
real(kind=wp), intent(in) :: x(:)
integer, intent(in) :: nderiv(:)
real(kind=wp), intent(in) :: xmin(:)
integer, intent(in) :: nodes(:)
integer, intent(out) :: icol
real(kind=wp), intent(out) :: basm

Called by

proc~~bascmp~~CalledByGraph proc~bascmp splpak_module::splpak_type%bascmp proc~splcw splpak_module::splpak_type%splcw proc~splcw->proc~bascmp proc~splde splpak_module::splpak_type%splde proc~splde->proc~bascmp proc~splcc splpak_module::splpak_type%splcc proc~splcc->proc~splcw proc~splfe splpak_module::splpak_type%splfe proc~splfe->proc~splde

Source Code

subroutine bascmp(me,x,nderiv,xmin,nodes,icol,basm)

    class(splpak_type),intent(inout) :: me
    real(wp),intent(in) :: x(:)
    integer,intent(in) :: nderiv(:)
    real(wp),intent(in) :: xmin(:)
    integer,intent(in) :: nodes(:)
    integer,intent(out) :: icol
    real(wp),intent(out) :: basm

    real(wp) :: xb,bas1,z,fact,z1
    integer :: idim,mdmid,ntyp,ngo

    ! ICOL will be a linear address corresponding to the indices in IB.
    icol = 0

    ! BASM will be M-dimensional basis function evaluated at X.
    basm = 1.0_wp
    do idim = 1,me%mdim

        ! Compute ICOL by Horner's method.
        mdmid = me%mdim + 1 - idim
        icol = nodes(mdmid)*icol + me%ib(mdmid)

        ! NGO depends upon function type and NDERIV.
        ntyp = 1

        ! Function type 1 (left linear) for IB = 0 or 1.
        if (me%ib(idim)>1) then
            ntyp = 2
            ! Function type 2 (chapeau function) for 2 LT IB LT NODES-2.
            if (me%ib(idim)>=nodes(idim)-2) then
                ntyp = 3
            end if
        end if

        ! Function type 3 (right linear) for IB = NODES-2 or NODES-1.
        ngo = 3*ntyp + nderiv(idim) - 2

        !  XB is X value of node IB (center of basis function).
        xb = xmin(idim) + real(me%ib(idim),wp)*me%dx(idim)

        !  BAS1 will be the 1-dimensional basis function evaluated at X.
        bas1 = 0.0_wp

        select case (ngo)

        case(4)

            !  Function type 2 (chapeau function).
            !
            !  Transform so that XB is at the origin and the other nodes are at
            !  the integers.
            z = abs(me%dxin(idim)* (x(idim)-xb)) - 2.0_wp

            !  This chapeau function is then that unique cubic spline which is
            !  identically zero for ABS(Z) GE 2 and is 1 at the origin.  This
            !  function is the general interior node basis function.
            if (z<0.0_wp) then
                bas1 = -0.25_wp*z**3
                z = z + 1.0_wp
                if (z<0.0_wp) then
                    bas1 = bas1 + z**3
                end if
            end if

        case(5)

            !  1st derivative.
            z = x(idim) - xb
            fact = me%dxin(idim)
            if (z<0.0_wp) fact = -fact
            z = fact*z - 2.0_wp
            if (z<0.0_wp) then
                bas1 = -0.75_wp*z**2
                z = z + 1.0_wp
                if (z<0.0_wp) then
                    bas1 = bas1 + 3.0_wp*z**2
                end if
                bas1 = fact*bas1
            end if

        case(6) ! 108

            !  2nd derivative.
            fact = me%dxin(idim)
            z = fact*abs(x(idim)-xb) - 2.0_wp
            if (z<0.0_wp) then
                bas1 = -1.5_wp*z
                z = z + 1.0_wp
                if (z<0.0_wp) then
                    bas1 = bas1 + 6.0_wp*z
                end if
                bas1 = (fact**2)*bas1
            end if

        case(2,8)

            !  1st derivative.
            if (ngo==2) then
                fact = -me%dxin(idim)
            else if (ngo==8) then
                fact = me%dxin(idim)
            end if
            z = fact* (x(idim)-xb) + 2.0_wp
            if (z<0.0_wp) then
                if (z<2.0_wp) then
                    bas1 = 1.5_wp*z**2
                    z = z - 1.0_wp
                    if (z>0.0_wp) then
                        bas1 = bas1 - 3.0_wp*z**2
                    end if
                    bas1 = fact*bas1
                else
                    bas1 = 3.0_wp*fact
                end if
            end if

        case(3,9)

            !  2nd derivative.
            if (ngo==3) then
                fact = -me%dxin(idim)
            else if (ngo==9) then
                fact = me%dxin(idim)
            end if
            z = fact* (x(idim)-xb) + 2.0_wp
            z1 = z - 1.0_wp
            if (abs(z1)<1.0_wp) then
                bas1 = 3.0_wp*z
                if (z1>0.0_wp) then
                    bas1 = bas1 - 6.0_wp*z1
                end if
                bas1 = (fact**2)*bas1
            end if

        case default ! case(1,7) ! or ngo some other value (does that ever happen?)
                     !             (due to the computed goto in the original code)

            if (ngo/=7) then
                !  Function type 1 (left linear) is mirror image of function type 3.
                !
                !  Transform so that XB is at 2 and the other nodes are at the integers
                !  (with ordering reversed to form a mirror image).
                z = me%dxin(idim)* (xb-x(idim)) + 2.0_wp
            else
                !  Function type 3 (right linear).
                !
                !  Transform so that XB is at 2 and the other nodes are at the integers.
                z = me%dxin(idim)* (x(idim)-xb) + 2.0_wp
            end if

            !  This right linear function is defined to be that unique cubic spline
            !  which is identically zero for Z <= 0 and is 3*Z-3 for Z GE 2.
            !  This function (obviously having zero 2nd derivative for
            !  Z GE 2) is used for the two nodes nearest an edge in order
            !  to generate natural splines, which must by definition have
            !  zero 2nd derivative at the boundary.
            !
            !  Note that this method of generating natural splines also provides
            !  a linear extrapolation which has 2nd order continuity with
            !  the interior splines at the boundary.

            if (z>0.0_wp) then
                if (z<2.0_wp) then
                    bas1 = 0.5_wp*z**3
                    z = z - 1.0_wp
                    if (z>0.0_wp) then
                        bas1 = bas1 - z**3
                    end if
                else
                    bas1 = 3.0_wp*z - 3.0_wp
                end if
            end if

        end select

        basm = basm*bas1

    end do

    icol = icol + 1

end subroutine bascmp