Viewing contents of file '../idllib/astron/contrib/varosi/vlib/allpro/fitexy.pro'
function chisq_fitexy, B_angle

; NAME:
;	chisq_fitexy
; PURPOSE:
;	Function minimized by fitexy  (computes chi-square of linear fit).
;	It is called by minimization procedures during execution of fitexy.
; CALLING:
;		chisq = chisq_fitexy( B_angle )
; INPUTS:
;	B_angle = arc-tangent of B_slope of linear fit.
; OUTPUTS:
;	Result of function = chi_square - offs  (offs is in COMMON).
; COMMON:
;	common fitexy, communicates the data from pro fitexy.
; PROCEDURE:
;	From "Numerical Recipes" column: Computer in Physics Vol.6 No.3
; MODIFICATION HISTORY:
;	Written, Frank Varosi NASA/GSFC 1992.

  common fitexy, xx, yy, sigx, sigy, ww, Ai, offs

	B_slope = tan( B_angle )
	ww = 1/( ( (B_slope * sigx)^2 + sigy^2 ) > 1.e-30 )
	if N_elements( ww ) EQ 1 then sumw = ww * N_elements( xx ) $
				 else sumw = total( ww )
	y_Bx = yy - B_slope * xx
	Ai = total( ww * y_Bx )/sumw

return, total( ww * (y_Bx - Ai)^2 ) - offs
end
;-------------------------------------------------------------------------------
pro fitexy, x, y, A_intercept, B_slope, sigma_A_B, chi_sq, TOLERANCE=Tol, $
					X_SIGMA=x_sigma, Y_SIGMA=y_sigma
;+
; NAME:
;	fitexy
; PURPOSE:
;	Linear Least-squares approximation in one-dimension (y = a + b*x),
;		when both x and y data have errors (e.g. Gaussian noise).
; CALLING EXAMPLE:
;	fitexy, x, y, A, B, X_SIG=sigx, Y_SIG=sigy, [sigmas, covar, chi_sq]
; INPUTS:
;	x = array of values for independent variable.
;	y = array of data values assumed to be linearly dependent on x.
; KEYWORDS:
;	X_SIGMA = scalar or array specifying the standard deviation of x data.
;	Y_SIGMA = scalar or array specifying the standard deviation of y data.
;	TOLERANCE = desired accuracy of minimum & zero location, default=1.e-3.
; OUTPUTS:
;	A_intercept = constant parameter result of linear fit,
;	B_slope = slope parameter, so that:
;			( A_intercept + B_slope * x ) approximates the y data.
; OPTIONAL OUTPUT:
;	sigma_A_B = two element array giving standard deviation of 
;			A_intercept and B_slope parameters, respectively.
;	chi_sq = resulting minimum Chi-Square of Linear fit.
; COMMON:
;	common fitexy, communicates the data for computation of chi-square.
; CALLS:
;	function chisq_fitexy
;	pro minf_bracket
;	pro minf_parabolic
;	function zbrent
; PROCEDURE:
;	From "Numerical Recipes" column: Computer in Physics Vol.6 No.3
; MODIFICATION HISTORY:
;	Written, Frank Varosi NASA/GSFC 1992.
;-
  common fitexy, xx, yy, sigx, sigy, ww, Ai, offs

	scale = sqrt( stdev( x )/stdev( y ) )
	xx = x
	yy = y * scale
	sigx = x_sigma
	sigy = y_sigma * scale

;Compute first guess for B_slope using standard 1-D Linear Least-squares fit,
; where the non-linear term involving errors in x are ignored.
; (note that Tx is a transform to reduce roundoff errors)

	ww = sigx^2 + sigy^2
	if N_elements( ww ) EQ 1 then sumw = ww * N_elements( xx ) $
				 else sumw = total( ww )
	Sx = total( xx * ww )
	Tx = x - Sx/sumw
	B = total( ww * yy * Tx ) / total( ww * Tx^2 )

;Find the minimum chi-sq while including the non-linear term (B * sigx)^2
; involving variance in x data (computed by function chisq_fitexy):

	offs = 0
	ang = [ 0, atan( B ), 1.57 ]
	chi = fltarr( 3 )
	for j=0,2 do chi(j) = chisq_fitexy( ang(j) )	;this is for later...

	if N_elements( Tol ) NE 1 then Tol=1.e-3
	a0 = ang(0)
	a1 = ang(1)
	minf_bracket, a0,a1,a2, c0,c1,c2, FUNC="chisq_fitexy"
	minf_parabolic, a0,a1,a2, Bang, chi_sq, FUNC="chisq_fitexy", TOL=Tol

	A_intercept = Ai	;computed in function chisq_fitexy
	ang = [a0,a1,a2,ang]
	chi = [c0,c1,c2,chi]

;Now compute the variances of estimated parameters,
; by finding roots of ( (chi_sq + 1) - chisq_fitexy ).
;Note: ww, Ai are computed in function chisq_fitexy.

	offs = chi_sq + 1
	wc = where( chi GT offs, nc )

	if (nc GT 0) then begin

		angw = [ang(wc)]
		d1 = abs( angw - Bang ) MOD !PI
		d2 = !PI - d1
		wa = where( angw LT Bang, na )

		if (na GT 0) then begin
			d = d1(wa)
			d1(wa) = d2(wa)
			d2(wa) = B
		   endif

		Bmax = zbrent( Bang,Bang+max(d1),F="chisq_fitexy",T=Tol ) -Bang
		Amax = Ai - A_intercept
		Bmin = zbrent( Bang,Bang-min(d2),F="chisq_fitexy",T=Tol ) -Bang
		Amin = Ai - A_intercept

		if N_elements( ww ) EQ 1 then r2 = 2/( ww * N_elements( x ) ) $
					 else r2 = 2/total( ww )

	  	sigma_A_B = [ Amin^2 + Amax^2 + r2 , Bmin^2 + Bmax^2 ]
	  	sigma_A_B = sqrt( sigma_A_B/2 ) / (scale*[1,cos(Bang)^2])

	  endif else sigma_A_B = [1.e33,1.e33]

;Finally, transform parameters back to orignal units.

	A_intercept = A_intercept/scale
	B_slope = tan( Bang )/scale
return
end