defcmn Subroutine

private subroutine defcmn(Ndata, Xdata, Ydata, Sddata, Nord, Nbkpt, Bkptin, Mdein, Mdeout, Coeff, Bf, Xtemp, Ptemp, Bkpt, g, Mdg, w, Mdw, Lw)

This is a companion subprogram to DEFC. This subprogram does weighted least squares fitting of data by B-spline curves. The documentation for DEFC has complete usage instructions.

Revision history

  • 800801 DATE WRITTEN. Hanson, R. J., (SNLA)
  • 890531 Changed all specific intrinsics to generic. (WRB)
  • 890618 Completely restructured and extensively revised (WRB & RWC)
  • 891214 Prologue converted to Version 4.0 format. (BAB)
  • 900315 CALLs to XERROR changed to CALLs to XERMSG. (THJ)
  • 900328 Added TYPE section. (WRB)
  • 900510 Convert XERRWV calls to XERMSG calls. (RWC)
  • 900604 DP version created from SP version. (RWC)

Arguments

Type IntentOptional Attributes Name
integer :: Ndata
real(kind=wp) :: Xdata(*)
real(kind=wp) :: Ydata(*)
real(kind=wp) :: Sddata(*)
integer :: Nord
integer :: Nbkpt
real(kind=wp) :: Bkptin(*)
integer :: Mdein
integer :: Mdeout
real(kind=wp) :: Coeff(*)
real(kind=wp) :: Bf(Nord,*)
real(kind=wp) :: Xtemp(*)
real(kind=wp) :: Ptemp(*)
real(kind=wp) :: Bkpt(*)
real(kind=wp) :: g(Mdg,*)
integer :: Mdg
real(kind=wp) :: w(Mdw,*)
integer :: Mdw
integer :: Lw

Calls

proc~~defcmn~~CallsGraph proc~defcmn bspline_defc_module::defcmn proc~dbndac bspline_defc_module::dbndac proc~defcmn->proc~dbndac proc~dbndsl bspline_defc_module::dbndsl proc~defcmn->proc~dbndsl proc~dcopy bspline_blas_module::dcopy proc~defcmn->proc~dcopy proc~dfspvn bspline_defc_module::dfspvn proc~defcmn->proc~dfspvn proc~dscal bspline_blas_module::dscal proc~defcmn->proc~dscal proc~dsort bspline_defc_module::dsort proc~defcmn->proc~dsort proc~dh12 bspline_defc_module::dh12 proc~dbndac->proc~dh12 proc~sort_ascending bspline_defc_module::sort_ascending proc~dsort->proc~sort_ascending proc~daxpy bspline_blas_module::daxpy proc~dh12->proc~daxpy proc~ddot bspline_blas_module::ddot proc~dh12->proc~ddot proc~dswap bspline_blas_module::dswap proc~dh12->proc~dswap

Called by

proc~~defcmn~~CalledByGraph proc~defcmn bspline_defc_module::defcmn proc~defc bspline_defc_module::defc proc~defc->proc~defcmn

Source Code

   subroutine defcmn(Ndata, Xdata, Ydata, Sddata, Nord, Nbkpt, Bkptin, &
                     Mdein, Mdeout, Coeff, Bf, Xtemp, Ptemp, Bkpt, g, Mdg, w, &
                     Mdw, Lw)

      integer :: Lw, Mdein, Mdeout, Mdg, Mdw, Nbkpt, Ndata, Nord
      real(wp) :: Bf(Nord, *), Bkpt(*), Bkptin(*), Coeff(*), &
                  g(Mdg, *), Ptemp(*), Sddata(*), w(Mdw, *), &
                  Xdata(*), Xtemp(*), Ydata(*)

      real(wp) :: rnorm, xmax, xmin, xval
      integer :: i, idata, ileft, intseq, ip, ir, irow, l, mt, n, &
                 nb, nordm1, nordp1, np1
      character(len=8) :: xern1, xern2
      integer :: dfspvn_j
      real(wp), dimension(20) :: dfspvn_deltam, dfspvn_deltap

      ! Initialize variables and analyze input.

      n = Nbkpt - Nord
      np1 = n + 1

      ! Initially set all output coefficients to zero.

      call dcopy(n, [0.0_wp], 0, Coeff, 1)

      Mdeout = -1
      if (Nord < 1 .or. Nord > 20) then
         write (*, *) 'IN DEFC, THE ORDER OF THE B-SPLINE MUST BE 1 THRU 20.'
         return
      end if

      if (Nbkpt < 2*Nord) then
         write (*, *) 'IN DEFC, THE NUMBER OF KNOTS MUST BE AT LEAST TWICE THE B-SPLINE ORDER.'
         return
      end if

      if (Ndata < 0) then
         write (*, *) 'IN DEFC, THE NUMBER OF DATA POINTS MUST BE NONNEGATIVE.'
         return
      end if

      nb = (Nbkpt - Nord + 3)*(Nord + 1) + (Nbkpt + 1)*(Nord + 1) &
           + 2*max(Nbkpt, Ndata) + Nbkpt + Nord**2
      if (Lw < nb) then
         write (xern1, '(I8)') nb
         write (xern2, '(I8)') Lw
         write (*, *) 'IN DEFC, INSUFFICIENT STORAGE FOR W(*).  CHECK FORMULA '// &
            'THAT READS LW>= ... .  NEED = '//xern1// &
            ' GIVEN = '//xern2
         Mdeout = -1
         return
      end if

      if (Mdein /= 1 .and. Mdein /= 2) then
         write (*, *) 'IN DEFC, INPUT VALUE OF MDEIN MUST BE 1-2.'
         return
      end if

      ! Sort the breakpoints.

      call dcopy(Nbkpt, Bkptin, 1, Bkpt, 1)
      call dsort(Nbkpt, 1, Bkpt)

      ! Save interval containing knots.

      xmin = Bkpt(Nord)
      xmax = Bkpt(np1)
      nordm1 = Nord - 1
      nordp1 = Nord + 1

      ! Process least squares equations.

      ! Sort data and an array of pointers.

      call dcopy(Ndata, Xdata, 1, Xtemp, 1)
      do i = 1, Ndata
         Ptemp(i) = i
      end do
      ! JW : really Ptemp should be an integer array.
      !      it is real because they are stuffing it in
      !      a real work array and also using dsort on it.

      if (Ndata > 0) then
         call dsort(Ndata, 2, Xtemp, Ptemp)
         xmin = min(xmin, Xtemp(1))
         xmax = max(xmax, Xtemp(Ndata))
      end if

      ! Fix breakpoint array if needed. This should only involve very
      ! minor differences with the input array of breakpoints.

      do i = 1, Nord
         Bkpt(i) = min(Bkpt(i), xmin)
      end do

      do i = np1, Nbkpt
         Bkpt(i) = max(Bkpt(i), xmax)
      end do

      ! set up variables for dfspvn
      dfspvn_j = 1
      dfspvn_deltam = 0.0_wp
      dfspvn_deltap = 0.0_wp

      ! Initialize parameters of banded matrix processor, DBNDAC( ).

      mt = 0
      ip = 1
      ir = 1
      ileft = Nord
      intseq = 1
      do idata = 1, Ndata

         ! Sorted indices are in PTEMP(*).

         l = int(Ptemp(idata))
         xval = Xdata(l)

         ! When interval changes, process equations in the last block.

         if (xval >= Bkpt(ileft + 1)) then
            call dbndac(g, Mdg, Nord, ip, ir, mt, ileft - nordm1)
            mt = 0

            ! Move pointer up to have BKPT(ILEFT)<=XVAL, ILEFT<=N.

            do ileft = ileft, n
               if (xval < Bkpt(ileft + 1)) exit
               if (Mdein == 2) then
                  !  Data is being sequentially accumulated.
                  !  Transfer previously accumulated rows from W(*,*) to
                  !  G(*,*) and process them.
                  call dcopy(nordp1, w(intseq, 1), Mdw, g(ir, 1), Mdg)
                  call dbndac(g, Mdg, Nord, ip, ir, 1, intseq)
                  intseq = intseq + 1
               end if
            end do
         end if

         ! Obtain B-spline function value.

         call dfspvn(Bkpt, Nord, 1, xval, ileft, Bf, &
                     dfspvn_j, dfspvn_deltam, dfspvn_deltap)

         ! Move row into place.

         irow = ir + mt
         mt = mt + 1
         call dcopy(Nord, Bf, 1, g(irow, 1), Mdg)
         g(irow, nordp1) = Ydata(l)

         ! Scale data if uncertainty is nonzero.

         if (Sddata(l) /= 0.0_wp) call dscal(nordp1, 1.0_wp/Sddata(l), g(irow, 1), Mdg)

         ! When staging work area is exhausted, process rows.

         if (irow == Mdg - 1) then
            call dbndac(g, Mdg, Nord, ip, ir, mt, ileft - nordm1)
            mt = 0
         end if
      end do

      ! Process last block of equations.

      call dbndac(g, Mdg, Nord, ip, ir, mt, ileft - nordm1)

      ! Finish processing any previously accumulated rows from W(*,*)
      ! to G(*,*).

      if (Mdein == 2) then
         do i = intseq, np1
            call dcopy(nordp1, w(i, 1), Mdw, g(ir, 1), Mdg)
            call dbndac(g, Mdg, Nord, ip, ir, 1, min(n, i))
         end do
      end if

      ! Last call to adjust block positioning.

      call dcopy(nordp1, [0.0_wp], 0, g(ir, 1), Mdg)
      call dbndac(g, Mdg, Nord, ip, ir, 1, np1)

      ! Transfer accumulated rows from G(*,*) to W(*,*) for
      ! possible later sequential accumulation.

      do i = 1, np1
         call dcopy(nordp1, g(i, 1), Mdg, w(i, 1), Mdw)
      end do

     ! Solve for coefficients when possible.

      do i = 1, n
         if (g(i, 1) == 0.0_wp) then
            Mdeout = 2
            return
         end if
      end do

      ! All the diagonal terms in the accumulated triangular
      ! matrix are nonzero.  The solution can be computed but
      ! it may be unsuitable for further use due to poor
      ! conditioning or the lack of constraints.  No checking
      ! for either of these is done here.

      call dbndsl(1, g, Mdg, Nord, ip, ir, Coeff, n, rnorm)
      Mdeout = 1

   end subroutine defcmn