db1extremum Subroutine

private pure subroutine db1extremum(tx, nx, kx, bcoef, xa, xb, find_max, xopt, fopt, iflag)

Global minimum or maximum of a 1D b-spline on . Used by db1min and db1max.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in), dimension(nx+kx) :: tx

knot array

integer(kind=ip), intent(in) :: nx

number of b-spline coefficients

integer(kind=ip), intent(in) :: kx

order of the b-spline, kx >= 2

real(kind=wp), intent(in), dimension(nx) :: bcoef

b-spline coefficient array

real(kind=wp), intent(in) :: xa

one end of the interval

real(kind=wp), intent(in) :: xb

other end of the interval

logical, intent(in) :: find_max

find the maximum (otherwise the minimum)

real(kind=wp), intent(out) :: xopt

location of the extremum

real(kind=wp), intent(out) :: fopt

value of the spline at xopt

integer(kind=ip), intent(out) :: iflag

status flag (see db1min)


Calls

proc~~db1extremum~~CallsGraph proc~db1extremum db1extremum proc~check_root_inputs check_root_inputs proc~db1extremum->proc~check_root_inputs proc~dbspvd dbspvd proc~db1extremum->proc~dbspvd proc~dbvalu dbvalu proc~db1extremum->proc~dbvalu proc~spline_derivative spline_derivative proc~db1extremum->proc~spline_derivative proc~spline_roots spline_roots proc~db1extremum->proc~spline_roots proc~dbspvn dbspvn proc~dbspvd->proc~dbspvn proc~dintrv dintrv proc~dbvalu->proc~dintrv proc~spline_roots->proc~dbvalu proc~in_flat_region in_flat_region proc~spline_roots->proc~in_flat_region proc~root_dup_tol root_dup_tol proc~spline_roots->proc~root_dup_tol proc~sort_unique sort_unique proc~spline_roots->proc~sort_unique proc~get_temp_x_for_extrap get_temp_x_for_extrap proc~dintrv->proc~get_temp_x_for_extrap proc~in_flat_region->proc~dintrv

Called by

proc~~db1extremum~~CalledByGraph proc~db1extremum db1extremum proc~db1max db1max proc~db1max->proc~db1extremum proc~db1min db1min proc~db1min->proc~db1extremum proc~maximum_1d bspline_1d%maximum_1d proc~maximum_1d->proc~db1max proc~minimum_1d bspline_1d%minimum_1d proc~minimum_1d->proc~db1min

Source Code

    pure subroutine db1extremum(tx,nx,kx,bcoef,xa,xb,find_max,xopt,fopt,iflag)

    implicit none

    integer(ip),intent(in)               :: nx       !! number of b-spline coefficients
    integer(ip),intent(in)               :: kx       !! order of the b-spline, `kx >= 2`
    real(wp),dimension(nx+kx),intent(in) :: tx       !! knot array
    real(wp),dimension(nx),intent(in)    :: bcoef    !! b-spline coefficient array
    real(wp),intent(in)                  :: xa       !! one end of the interval
    real(wp),intent(in)                  :: xb       !! other end of the interval
    logical,intent(in)                   :: find_max !! find the maximum (otherwise the minimum)
    real(wp),intent(out)                 :: xopt     !! location of the extremum
    real(wp),intent(out)                 :: fopt     !! value of the spline at `xopt`
    integer(ip),intent(out)              :: iflag    !! status flag (see [[db1min]])

    real(wp),dimension(:),allocatable :: crit  !! critical points (roots of \( s'(x) \))
    real(wp),dimension(:),allocatable :: td    !! knots of \( s'(x) \)
    real(wp),dimension(:),allocatable :: d     !! coefficients of \( s'(x) \)
    real(wp),dimension(:),allocatable :: xc    !! candidate points
    real(wp),dimension(3*kx) :: work  !! work array for [[dbvalu]]
    real(wp),dimension(kx,1) :: vnikx  !! basis function values from [[dbspvd]]
    real(wp),dimension((kx+1)*(kx+2)/2) :: work2  !! work array for [[dbspvd]]
    integer(ip) :: i       !! counter
    integer(ip) :: m       !! multiplicity of an interior knot
    integer(ip) :: inbv    !! initialization parameter for [[dbvalu]]
    integer(ip) :: iflag2  !! status flag from [[spline_roots]] for \( s'(x) \) (not returned)
    real(wp) :: x1         !! left end of the interval: `min(xa,xb)`
    real(wp) :: x2         !! right end of the interval: `max(xa,xb)`
    real(wp) :: f          !! spline value at a candidate point

    xopt = 0.0_wp
    fopt = 0.0_wp

    call check_root_inputs(nx,kx,iflag); if (iflag/=0_ip) return

    x1 = min(xa,xb)
    x2 = max(xa,xb)
    if (x1<tx(kx) .or. x2>tx(nx+1_ip)) then
        iflag = 4003_ip
        return
    end if

    ! candidates: the end points, the interior knots (the derivative
    ! may be discontinuous there), and the critical points
    xc = [x1, x2, pack(tx(kx+1_ip:nx), tx(kx+1_ip:nx)>x1 .and. tx(kx+1_ip:nx)<x2)]
    if (kx>=3_ip) then
        call spline_derivative(tx,bcoef,nx,kx,td,d)
        call spline_roots(td,d,nx-1_ip,kx-1_ip,0.0_wp,crit,iflag2)  ! flat intervals are covered by the knots
        xc = [xc, pack(crit, crit>x1 .and. crit<x2)]
    end if

    inbv = 1_ip
    do i = 1_ip, size(xc,kind=ip)
        call dbvalu(tx,bcoef,nx,kx,0_ip,xc(i),inbv,work,iflag,f)
        if (iflag/=0_ip) return
        if (i==1_ip .or. (find_max .and. f>fopt) .or. (.not. find_max .and. f<fopt)) then
            xopt = xc(i)
            fopt = f
        end if
    end do

    ! the limits from the left at interior knots where the spline is
    ! discontinuous (multiplicity >= kx), in (x1,x2]. Each such knot is
    ! processed at the first of its copies, i, so interval i-1 is the
    ! nonempty interval to its left.
    do i = kx+1_ip, nx
        if (tx(i)<=x1 .or. tx(i)>x2 .or. tx(i)==tx(i-1_ip)) cycle
        m = 1_ip
        do while (i+m<=nx+kx)
            if (tx(i+m)/=tx(i)) exit
            m = m + 1_ip
        end do
        if (m<kx .or. tx(i)>=tx(nx+1_ip)) cycle  ! continuous, or the right end (where
                                                 ! s(x) is already the limit from the left)
        call dbspvd(tx,kx,1_ip,tx(i),i-1_ip,kx,vnikx,work2,iflag2)
        if (iflag2/=0_ip) cycle
        f = dot_product(vnikx(:,1), bcoef(i-kx:i-1_ip))
        if ((find_max .and. f>fopt) .or. (.not. find_max .and. f<fopt)) then
            xopt = tx(i)
            fopt = f
            iflag = 4007_ip
        end if
    end do

    end subroutine db1extremum