OpenLibm/slatec/defcmn.f
Viral B. Shah c977aa998f Add Makefile.extras to build libopenlibm-extras.
Replace amos with slatec
2012-12-31 16:37:05 -05:00

236 lines
6.9 KiB
Fortran

*DECK DEFCMN
SUBROUTINE DEFCMN (NDATA, XDATA, YDATA, SDDATA, NORD, NBKPT,
+ BKPTIN, MDEIN, MDEOUT, COEFF, BF, XTEMP, PTEMP, BKPT, G, MDG,
+ W, MDW, LW)
C***BEGIN PROLOGUE DEFCMN
C***SUBSIDIARY
C***PURPOSE Subsidiary to DEFC
C***LIBRARY SLATEC
C***TYPE DOUBLE PRECISION (EFCMN-S, DEFCMN-D)
C***AUTHOR Hanson, R. J., (SNLA)
C***DESCRIPTION
C
C This is a companion subprogram to DEFC( ).
C This subprogram does weighted least squares fitting of data by
C B-spline curves.
C The documentation for DEFC( ) has complete usage instructions.
C
C***SEE ALSO DEFC
C***ROUTINES CALLED DBNDAC, DBNDSL, DCOPY, DFSPVN, DSCAL, DSORT, XERMSG
C***REVISION HISTORY (YYMMDD)
C 800801 DATE WRITTEN
C 890531 Changed all specific intrinsics to generic. (WRB)
C 890618 Completely restructured and extensively revised (WRB & RWC)
C 891214 Prologue converted to Version 4.0 format. (BAB)
C 900315 CALLs to XERROR changed to CALLs to XERMSG. (THJ)
C 900328 Added TYPE section. (WRB)
C 900510 Convert XERRWV calls to XERMSG calls. (RWC)
C 900604 DP version created from SP version. (RWC)
C***END PROLOGUE DEFCMN
INTEGER LW, MDEIN, MDEOUT, MDG, MDW, NBKPT, NDATA, NORD
DOUBLE PRECISION BF(NORD,*), BKPT(*), BKPTIN(*), COEFF(*),
* G(MDG,*), PTEMP(*), SDDATA(*), W(MDW,*), XDATA(*), XTEMP(*),
* YDATA(*)
C
EXTERNAL DBNDAC, DBNDSL, DCOPY, DFSPVN, DSCAL, DSORT, XERMSG
C
DOUBLE PRECISION DUMMY, RNORM, XMAX, XMIN, XVAL
INTEGER I, IDATA, ILEFT, INTSEQ, IP, IR, IROW, L, MT, N, NB,
* NORDM1, NORDP1, NP1
CHARACTER*8 XERN1, XERN2
C
C***FIRST EXECUTABLE STATEMENT DEFCMN
C
C Initialize variables and analyze input.
C
N = NBKPT - NORD
NP1 = N + 1
C
C Initially set all output coefficients to zero.
C
CALL DCOPY (N, 0.D0, 0, COEFF, 1)
MDEOUT = -1
IF (NORD.LT.1 .OR. NORD.GT.20) THEN
CALL XERMSG ('SLATEC', 'DEFCMN',
+ 'IN DEFC, THE ORDER OF THE B-SPLINE MUST BE 1 THRU 20.',
+ 3, 1)
RETURN
ENDIF
C
IF (NBKPT.LT.2*NORD) THEN
CALL XERMSG ('SLATEC', 'DEFCMN',
+ 'IN DEFC, THE NUMBER OF KNOTS MUST BE AT LEAST TWICE ' //
+ 'THE B-SPLINE ORDER.', 4, 1)
RETURN
ENDIF
C
IF (NDATA.LT.0) THEN
CALL XERMSG ('SLATEC', 'DEFCMN',
+ 'IN DEFC, THE NUMBER OF DATA POINTS MUST BE NONNEGATIVE.',
+ 5, 1)
RETURN
ENDIF
C
NB = (NBKPT-NORD+3)*(NORD+1) + (NBKPT+1)*(NORD+1) +
+ 2*MAX(NBKPT,NDATA) + NBKPT + NORD**2
IF (LW .LT. NB) THEN
WRITE (XERN1, '(I8)') NB
WRITE (XERN2, '(I8)') LW
CALL XERMSG ('SLATEC', 'DEFCMN',
* 'IN DEFC, INSUFFICIENT STORAGE FOR W(*). CHECK FORMULA ' //
* 'THAT READS LW.GE. ... . NEED = ' // XERN1 //
* ' GIVEN = ' // XERN2, 6, 1)
MDEOUT = -1
RETURN
ENDIF
C
IF (MDEIN.NE.1 .AND. MDEIN.NE.2) THEN
CALL XERMSG ('SLATEC', 'DEFCMN',
+ 'IN DEFC, INPUT VALUE OF MDEIN MUST BE 1-2.', 7, 1)
RETURN
ENDIF
C
C Sort the breakpoints.
C
CALL DCOPY (NBKPT, BKPTIN, 1, BKPT, 1)
CALL DSORT (BKPT, DUMMY, NBKPT, 1)
C
C Save interval containing knots.
C
XMIN = BKPT(NORD)
XMAX = BKPT(NP1)
NORDM1 = NORD - 1
NORDP1 = NORD + 1
C
C Process least squares equations.
C
C Sort data and an array of pointers.
C
CALL DCOPY (NDATA, XDATA, 1, XTEMP, 1)
DO 100 I = 1,NDATA
PTEMP(I) = I
100 CONTINUE
C
IF (NDATA.GT.0) THEN
CALL DSORT (XTEMP, PTEMP, NDATA, 2)
XMIN = MIN(XMIN,XTEMP(1))
XMAX = MAX(XMAX,XTEMP(NDATA))
ENDIF
C
C Fix breakpoint array if needed. This should only involve very
C minor differences with the input array of breakpoints.
C
DO 110 I = 1,NORD
BKPT(I) = MIN(BKPT(I),XMIN)
110 CONTINUE
C
DO 120 I = NP1,NBKPT
BKPT(I) = MAX(BKPT(I),XMAX)
120 CONTINUE
C
C Initialize parameters of banded matrix processor, DBNDAC( ).
C
MT = 0
IP = 1
IR = 1
ILEFT = NORD
INTSEQ = 1
DO 150 IDATA = 1,NDATA
C
C Sorted indices are in PTEMP(*).
C
L = PTEMP(IDATA)
XVAL = XDATA(L)
C
C When interval changes, process equations in the last block.
C
IF (XVAL.GE.BKPT(ILEFT+1)) THEN
CALL DBNDAC (G, MDG, NORD, IP, IR, MT, ILEFT-NORDM1)
MT = 0
C
C Move pointer up to have BKPT(ILEFT).LE.XVAL, ILEFT.LE.N.
C
DO 130 ILEFT = ILEFT,N
IF (XVAL.LT.BKPT(ILEFT+1)) GO TO 140
IF (MDEIN.EQ.2) THEN
C
C Data is being sequentially accumulated.
C Transfer previously accumulated rows from W(*,*) to
C G(*,*) and process them.
C
CALL DCOPY (NORDP1, W(INTSEQ,1), MDW, G(IR,1), MDG)
CALL DBNDAC (G, MDG, NORD, IP, IR, 1, INTSEQ)
INTSEQ = INTSEQ + 1
ENDIF
130 CONTINUE
ENDIF
C
C Obtain B-spline function value.
C
140 CALL DFSPVN (BKPT, NORD, 1, XVAL, ILEFT, BF)
C
C Move row into place.
C
IROW = IR + MT
MT = MT + 1
CALL DCOPY (NORD, BF, 1, G(IROW,1), MDG)
G(IROW,NORDP1) = YDATA(L)
C
C Scale data if uncertainty is nonzero.
C
IF (SDDATA(L).NE.0.D0) CALL DSCAL (NORDP1, 1.D0/SDDATA(L),
+ G(IROW,1), MDG)
C
C When staging work area is exhausted, process rows.
C
IF (IROW.EQ.MDG-1) THEN
CALL DBNDAC (G, MDG, NORD, IP, IR, MT, ILEFT-NORDM1)
MT = 0
ENDIF
150 CONTINUE
C
C Process last block of equations.
C
CALL DBNDAC (G, MDG, NORD, IP, IR, MT, ILEFT-NORDM1)
C
C Finish processing any previously accumulated rows from W(*,*)
C to G(*,*).
C
IF (MDEIN.EQ.2) THEN
DO 160 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))
160 CONTINUE
ENDIF
C
C Last call to adjust block positioning.
C
CALL DCOPY (NORDP1, 0.D0, 0, G(IR,1), MDG)
CALL DBNDAC (G, MDG, NORD, IP, IR, 1, NP1)
C
C Transfer accumulated rows from G(*,*) to W(*,*) for
C possible later sequential accumulation.
C
DO 170 I = 1,NP1
CALL DCOPY (NORDP1, G(I,1), MDG, W(I,1), MDW)
170 CONTINUE
C
C Solve for coefficients when possible.
C
DO 180 I = 1,N
IF (G(I,1).EQ.0.D0) THEN
MDEOUT = 2
RETURN
ENDIF
180 CONTINUE
C
C All the diagonal terms in the accumulated triangular
C matrix are nonzero. The solution can be computed but
C it may be unsuitable for further use due to poor
C conditioning or the lack of constraints. No checking
C for either of these is done here.
C
CALL DBNDSL (1, G, MDG, NORD, IP, IR, COEFF, N, RNORM)
MDEOUT = 1
RETURN
END