Viewing contents of file '../idllib/deutsch/misc/splinefit.pro'
FUNCTION SPLINEFIT,X,Y,W,XS,YS,SIGYS,DELY
;+
; NAME:
;	SPLINEFIT
; PURPOSE:
;	Non-linear least squares fit to a cubic spline function of an
;	arbitrary number of nodes.
; CATEGORY:
;	E2 - Curve and Surface Fitting
; CALLING SEQUENCE:
;	YFIT = SPINEFIT(X,Y,W,XS,YS,SIGYS,DELY)
; INPUTS:
;	X = Row vector of independent variables.
;	Y = Row vector of dependent variable, same length as x.
;	W = Row vector of weights, same length as x and y.
;		For no weighting
;		w(i) = 1., instrumental weighting w(i) =
;		1./y(i), etc.
;	XS = Vector containing the x-positions of the spline nodes
;	YS = Vector containing the intial y-position for the spline
;		at each node (same length as XS)
; OPTIONAL INPUTS:
;	DELY = distance to use in computing numerical derivatives
;		with respect to YS values.  The distance is DELY*YS(i)
;		(Default= 0.001)
;
; OUTPUTS:
;	YS = Vector of parameters containing fit.
;	Function result = YFIT = Vector of calculated
;		values. YFIT=CSPLINE(XS,YS,X)
; OPTIONAL OUTPUT PARAMETERS:
;	Sigys = Vector of standard deviations for parameters
;		ys.
;	
; COMMON BLOCKS:
;	NONE.
; RESTRICTIONS:
;	NONE.
; PROCEDURE:
;	Copied from "CURFIT", least squares fit to a non-linear
;	function, pages 237-239, Bevington, Data Reduction and Error
;	Analysis for the Physical Sciences.
;
;	"This method is the Gradient-expansion algorithm which
;	compines the best features of the gradient search with
;	the method of linearizing the fitting function."
;
;	Iterations are perform until the chi square changes by
;	only 0.1% or until 20 iterations have been performed.
;
;	The initial guess of the parameter values should be
;	as close to the actual values as possible or the solution
;	may not converge.
;
; MODIFICATION HISTORY:
;	Modified (D. Lindler, Feb. 87) version of IDL routine CURVEFIT
;	written by DMS, RSI, September, 1982.
;-
	ON_ERROR,2		;RETURN TO CALLER IF ERROR
	YS = 1.*YS		;MAKE PARAMS FLOATING
	NTERMS = N_ELEMENTS(YS)	;# OF PARAMS.
	NFREE = (N_ELEMENTS(Y)<N_ELEMENTS(X))-NTERMS ;Degs of freedom
	IF NFREE LE 0 THEN STOP,'Curvefit - not enough data points.'
; DEFAULT DELY AND TENSION
	IF N_PARAMS(0) LT 7 THEN DELY=0.001
	IF N_PARAMS(0) LT 8 THEN TENSION=1.0
;
	FLAMBDA = 0.001		;Initial lambda
	DIAG = INDGEN(NTERMS)*(NTERMS+1) ;SUBSCRIPTS OF DIAGONAL ELEMENTS
;
	FOR ITER = 1,20 DO BEGIN	;Iteration loop
;
; COMPUTE SPLINE FUNCTION AND DERIV. FOR YS
;
	YFIT=CSPLINE(XS,YS,X)
	PDER=FLTARR(N_ELEMENTS(YFIT),NTERMS)
	FOR I=0,NTERMS-1 DO BEGIN
		NEWYS=YS & NEWYS(I)=YS(I)+DELY*YS(I)
		PDER(0,I)=(CSPLINE(XS,NEWYS,X)-YFIT)/(DELY*YS(I))
	END
;
;		EVALUATE ALPHA AND BETA MATRICIES.
;
	BETA = (Y-YFIT)*W # PDER
	ALPHA = TRANSPOSE(PDER) # (W # (FLTARR(NTERMS)+1)*PDER)
;
	CHISQ1 = TOTAL(W*(Y-YFIT)^2)/NFREE ;PRESENT CHI SQUARED.
;
;	INVERT MODIFIED CURVATURE MATRIX TO FIND NEW PARAMETERS.
;
	REPEAT BEGIN
		C = SQRT(ALPHA(DIAG) # ALPHA(DIAG))
		ARRAY = ALPHA/C
		ARRAY(DIAG) = 1.+FLAMBDA
		ARRAY = INVERT(ARRAY)
		B = YS+ ARRAY/C # TRANSPOSE(BETA) ;NEW PARAMS
		YFIT=CSPLINE(XS,B,X) ;EVALUATE SPLINE
		CHISQR = TOTAL(W*(Y-YFIT)^2)/NFREE ;NEW CHISQR
		FLAMBDA = FLAMBDA*10.	;ASSUME FIT GOT WORSE
		ENDREP UNTIL CHISQR LE CHISQ1
;
	FLAMBDA = FLAMBDA/100.	;DECREASE FLAMBDA BY FACTOR OF 10
	YS=B			;SAVE NEW PARAMETER ESTIMATE.
;	PRINT,'ITERATION =',ITER,' ,CHISQR =',CHISQR
;	PRINT,YS
	IF ((CHISQ1-CHISQR)/CHISQ1) LE .001 THEN GOTO,DONE ;Finished?
	ENDFOR			;ITERATION LOOP
;
	PRINT,'CURVEFIT - Failed to converge'
;
DONE:	SIGYS = SQRT(ARRAY(DIAG)/ALPHA(DIAG)) ;RETURN SIGMA'S
	RETURN,YFIT		;RETURN RESULT
END