PRO AMOEBA_F,FNAME,PARAM,ACCURACY=ACCURACY,MAX_ITER=MAX_ITER, $ LAMBDA=LAMBDA0,CHISQR=CHISQR,N_ITER=ITER,NOPRINT=NOPRINT ;+ ; Project : SOHO - CDS ; ; Name : AMOEBA_F ; ; Purpose : Reiteratively minimizes an arbitrary function ; ; Explanation : Minimizes an arbitrary function via a least-squares reiterative ; technique. ; ; The procedure used is taken from Numerical Recipes. ; ; Use : AMOEBA_F, FNAME, PARAM ; ; Inputs : FNAME = Name of function to be minimized (string variable). ; PARAM = Parameters of fit. Passed as first guess. Returned ; as fitted values. ; ; Opt. Inputs : None. ; ; Outputs : PARAM = Parameters of fit. See note above. ; ; Opt. Outputs: None. ; ; Keywords : ACCURACY = Accuracy to cut off at. Defaults to 1E-5. ; MAX_ITER = Maximum number of reiterations. Defaults to 20. ; LAMBDA = Initial step sizes for PARAM, or if scalar then ; fraction of PARAM. Defaults to 1E-2. ; NOPRINT = If set, then no printout is generated. ; CHISQR = Returned value of chi-squared. Only relevant if ; ERROR passed explicitly. ; N_ITER = Number of iterations used. ; ; Calls : None. ; ; Common : None ; ; Restrictions: The user defined function is passed by name as a character ; string in the variable FNAME. The function must have the form. ; ; Y = F(PARAM) ; ; where PARAM is the vector containing the parameters of the fit. ; ; Unless LAMBDA is passed as an array, the initial guess for ; PARAM must not contain any zeroes. ; ; Side effects: None. ; ; Category : Utilities, Curve_Fitting ; ; Prev. Hist. : William Thompson, August, 1989. ; William Thompson, June 1991, modified to use keywords. ; ; Written : William Thompson, GSFC, August 1989 ; ; Modified : Version 1, William Thompson, GSFC, 9 January 1995 ; Incorporated into CDS library ; Version 2, William Thompson, GSFC, 6 October 1995 ; Fixed typo. ; Version 3, William Thompson, GSFC, 05-Jun-1998 ; Fixed bug where LAMBDA was not being properly accepted ; if a vector. ; ; Version : Version 3, 05-Jun-1998 ;- ; ON_ERROR,2 ; ; Check the number of parameters passed. ; IF N_PARAMS(0) NE 2 THEN BEGIN PRINT,' This procedure must be called with two parameters:' PRINT,' FNAME, PARAMS' RETURN ENDIF ; ; Set up the default parameters. ; ACCUR = 1E-5 IF N_ELEMENTS(ACCURACY) EQ 1 THEN $ IF ACCURACY GT 0 THEN ACCUR = ACCURACY ; IF N_ELEMENTS(MAX_ITER) EQ 1 THEN NMAX = MAX_ITER ELSE NMAX = 20 ; LAMBDA = 1E-2 IF N_ELEMENTS(LAMBDA0) GT 1 THEN $ IF MIN(ABS(LAMBDA0)) GT 0 THEN LAMBDA = LAMBDA0 ; ; Define NPAR from the input array. Start ITER at zero. ; NPAR = N_ELEMENTS(PARAM) IF NPAR EQ 1 THEN PARAM = MAKE_ARRAY(PARAM) ITER = 0 ; ; Check the array or scalar LAMBDA. ; NLAMB = N_ELEMENTS(LAMBDA) IF (NLAMB NE NPAR) AND (NLAMB NE 1) THEN BEGIN PRINT,'*** LAMBDA must have 1 or ' + FIX(NPAR) + $ ' elements, routine AMOEBA_F.' RETURN ENDIF ; ; Calculate the array of parameters to start with. ; P = PARAM # REPLICATE(1.,NPAR+1) FOR I = 0,NPAR-1 DO BEGIN IF NLAMB EQ NPAR THEN P(I,I+1) = PARAM(I) + LAMBDA(I) $ ELSE P(I,I+1) = PARAM(I) * (1. + LAMBDA) ENDFOR ; ; Initialize the array containing chi-squared. ; CHI = 0.*[0,PARAM] FOR I = 0,NPAR DO BEGIN TEST = EXECUTE('CHI(I) = ' + FNAME + '(P(*,I))') ENDFOR ; ; Print the header. ; IF (NMAX GT 0) AND (NOT KEYWORD_SET(NOPRINT)) THEN BEGIN PRINT,FORMAT="(1H1,3X,'I',10X,'log',20X,'log',16X,'I')" PRINT,FORMAT="(1X,I4,9X,'ERROR',17X,'CHISQR',7X,I9)",NMAX,NMAX PRINT,FORMAT="(2X,4(1H-),5X,10(1H-),5X,25(1H-),4X,4(1H-))" ENDIF ; ; Starting point for all iterations. Find the highest, next highest, and ; lowest values of CHI. ; ITERATE: ITER = ITER + 1 ILO = 0 IF CHI(0) GT CHI(1) THEN BEGIN IHI = 0 INHI = 1 END ELSE BEGIN IHI = 1 INHI = 0 ENDELSE FOR I = 0,NPAR DO BEGIN IF CHI(I) LT CHI(ILO) THEN ILO = I IF CHI(I) GT CHI(IHI) THEN BEGIN INHI = IHI IHI = I END ELSE IF (CHI(I) GT CHI(INHI)) AND (I NE IHI) THEN INHI = I ENDFOR ; ; Find the average of P for all points other than IHI. ; PBAR = 0*PARAM FOR I = 0,NPAR DO IF I NE IHI THEN PBAR = PBAR + P(*,I) PBAR = PBAR / NPAR ; ; Reflect from the high point through PBAR. ; PR = 2*PBAR - P(*,IHI) TEST = EXECUTE('CR = ' + FNAME + '(PR)') ; ; If an improvement was achieved, try an additional extrapolation. ; IF CR LE CHI(ILO) THEN BEGIN PRR = 2*PR - PBAR TEST = EXECUTE('CRR = ' + FNAME + '(PRR)') ; ; If an additional improvement was achieved, use the second extrapolation. ; IF CRR LT CHI(ILO) THEN BEGIN P(0,IHI) = PRR CHI(IHI) = CRR ; ; Otherwise use the first extrapolation (reflection). ; END ELSE BEGIN P(0,IHI) = PR CHI(IHI) = CR ENDELSE ; ; If the reflection yields a value between the highest value and the next ; highest value, use it. ; END ELSE IF CR GE CHI(INHI) THEN BEGIN IF CR LT CHI(IHI) THEN BEGIN P(0,IHI) = PR CHI(IHI) = CR ENDIF ; ; Look for an intermediate lower point. If it's an improvement use it. ; PRR = (P(*,IHI) + PBAR) / 2. TEST = EXECUTE('CRR = ' + FNAME + '(PRR)') IF CRR LT CHI(IHI) THEN BEGIN P(0,IHI) = PRR CHI(IHI) = CRR ; ; Nothing seems to help. Contract about the lowest point. ; END ELSE BEGIN FOR I = 0,NPAR DO IF I NE ILO THEN BEGIN PR = (P(*,I) + P(*,ILO)) / 2. P(0,I) = PR TEST = EXECUTE('CHI(I) = ' + FNAME + '(PRR)') ENDIF ENDELSE ; ; The reflection yields an intermediate value. Use it. ; END ELSE BEGIN P(0,IHI) = PR CHI(IHI) = CR ENDELSE ; ; Print out the iteration information. ; ERROR = TOTAL( (P(*,IHI) - P(*,ILO))^2 / (P(*,IHI)^2 + P(*,ILO)^2) ) BANG_C = !C CHI_HI = ABS(MAX(CHI)) CHI_LO = ABS(MIN(CHI)) I_LOW = !C !C = BANG_C IF ERROR GT 0 THEN ERRORLG = ALOG10(ERROR)/2 ELSE ERRORLG = -999 IF CHI_HI GT 0 THEN CHILOG = ALOG10(CHI_HI) ELSE CHILOG = -999 IF CHI_LO GT 0 THEN CLOLOG = ALOG10(CHI_LO) ELSE CLOLOG = -999 FORMAT = "(I5,3F15.5,I8)" IF NOT KEYWORD_SET(NOPRINT) THEN PRINT,FORMAT=FORMAT,ITER,ERRORLG, $ CHILOG,CLOLOG,ITER IF (ERROR GT ACCUR^2) AND (ITER LT NMAX) THEN GOTO,ITERATE ; ; The program has either converged or reached its maximum number of ; iterations. ; PARAM = P(*,I_LOW) CHISQR = CHI(I_LOW) END