SUBROUTINE SFIT( STATUS ) *+ * Name: * SFIT * Purpose: * Spectral fitting program * Language: * Starlink Fortran * Type of Module: * ASTERIX task * Invocation: * CALL SFIT( STATUS ) * Arguments: * STATUS = INTEGER (Given and Returned) * The global status. * Description: * Adjusts parameters in a multicomponent model to achieve minimum * chi-squared or maximum likelihood fit to one or more datasets. * Only a single input dataset can be entered - if multiple datasets are * to be fitted a file containing references to them must be first set up * using SDATA. * The user can abort the program with ^C and will retain the last update * to the parameter values, which can then be used to generate plotted * output and taken as the starting point for further iteration. * Up to three user-defined models: FIT_USER1, _USER2 and _USER3, can be * linked to a private version of the program. * Usage: * sfit {parameter_usage} * Environment Parameters: * LIK = LOGICAL (read) * Likelihood fit (else chi-squared) * INP = CHAR (read) * Input data (either a single dataset or a file of references). * Z = REAL (read) * Redshift of spectrum * MODEL = CHAR (read) * Data object containing model specification * MAX = INTEGER (read) * Max number of iterations to be performed * MINS = REAL (read) * Minimum `reduced statistic' slope forcing continued iteration * NUP = INTEGER (read) * Number of iterations between updates of model parameter file * ERR = LOGICAL (read) * Evaluate approximate parameter errors and write to model file? * OUT = LOGICAL (read) * Spool (or send to file) summary of fit results? * FITOUT = CHAR (read) * File name for fit text output * APPEND = LOGICAL (read) * Append o/p to existing file? * Examples: * {routine_example_text} * {routine_example_description} * Pitfalls: * {pitfall_description}... * Notes: * {routine_notes}... * Prior Requirements: * {routine_prior_requirements}... * Side Effects: * {routine_side_effects}... * Algorithm: * Get genus, data, response and model spec. * Set up arrays required for fitting * Loop NITMAX/NUPDATE times * Call FIT_MIN performing NUPDATE iterations * Type diagnostic info * Update model parameters in model_spec object * End loop * Optionally compute approximate errors for free parameters and * write to model file * Display and optionally print the results * * The fit optimisation is done by FIT_MIN - a combined * gradient/quadratic-fitting minimisation routine based on the CURFIT * program of Bevington. Parameter bounds are incorporated by 'pegging' * parameters on bounds and excluding them from the fitting process until * the fitstat gradient takes them back into the allowed region. 'FROZEN' * parameters are never allowed to vary. Computing time is saved by using an * approximation to the fitstat second derivs within FIT_DERIVS, rather * than a rigorous evaluation. * Details of the model prescription (though not the parameter values and * bounds) and the observed and predicted data are not required by the * main fitting routine itself, only by the routines which evaluate the * fitstat value and its derivatives. These details (or in some cases * pointers to them) are stored in FORTRAN structures (for neatness given * the possibility of multiple datasets) and passed through FIT_MIN * intact. * For the spectral fitting case, a redshift may be incorporated by scaling * all the model space bounds by 1+z, to shift them into the source frame. * Accuracy: * {routine_accuracy} * Timing: * {routine_timing} * Implementation Status: * {routine_implementation_status} * External Routines Used: * {name_of_facility_or_package}: * {routine_used}... * Implementation Deficiencies: * {routine_deficiencies}... * References: * {task_references}... * Keywords: * sfit, usage:public * Copyright: * Copyright (C) University of Birmingham, 1995 * Authors: * TJP: Trevor Ponman (University of Birmingham) * DJA: David J. Allan (Jet-X, University of Birmingham) * {enter_new_authors_here} * History: * 31 Mar 1987 V0.6-1 (TJP): * Original GENFIT * 15 May 1987 V0.6-2 (TJP): * Parameter error estimates & printout of results * 11 Jun 1987 V0.6-3 (TJP): * Data file names returned from FIT_DATGET & output * 26 Oct 1988 V0.6-4 (TJP): * Model listed in printed output * 7 Jun 1989 V1.0-1 (TJP): * ASTERIX88 version * 7 Dec 1990 V1.4-1 (TJP): * Bug with multiple spectra and model compts fixed * 1 May 1991 V1.5-1 (TJP): * Common block allows 1st run to be flagged * 5 Aug 1991 V1.5-2 (TJP): * Minor fix to allow printout when all params frozen * 1 Apr 1992 V1.5-3 (RJV): * FIT_CHIFIT merged into top level * 15 Jun 1992 V1.6-1 (TJP): * Supports likelihood fitting * 9 Aug 1992 V1.6-2 (TJP): * Internal write replaces overwrite in printed o/p * 23 Sep 1992 V1.6-3 (DJA): * Use D.P. for statistic * 4 Dec 1992 V1.7-0 (DJA): * Fit error report and red-shift in subroutines * 21 Dec 1992 V1.7-1 (DJA): * Terminal output via MSG * 11 Jan 1993 V1.7-2 (DJA): * Output open/close moved to subroutines * 8 Sep 1993 V1.7-3 (DJA) * Added SPEC_INIT call and removed reference to SPEC_CMN_RZ * 23 May 1994 V1.7-4 (DJA): * Added parameter tying * 21 Jul 1994 V1.7-5 (DJA): * File output moved to SFIT_OPFILES * 25 Jul 1994 V1.7-6 (DJA): * File output now completely using AIO * 7 Sep 1994 V1.8-0 (DJA): * Print out fit probability * 24 Nov 1994 V1.8-1 (DJA): * Now use USI for user interface * 21 Apr 1995 V1.8-2 (DJA): * Removed explicit use of HDS * 30 Nov 1995 V2.0-0 (DJA): * ADI port * 17 Apr 1996 V2.0-1 (DJA): * New minimisation control * 13 May 1996 V2.0-2 (DJA): * Ensure tieing takes place for MAX=0 * {enter_changes_here} * Bugs: * {note_any_bugs_here} *- * Type Definitions: IMPLICIT NONE ! No implicit typing * Global Constants: INCLUDE 'SAE_PAR' ! Standard SAE constants INCLUDE 'ADI_PAR' INCLUDE 'FIT_PAR' * Structure Definitions: INCLUDE 'FIT_STRUC' * Status: INTEGER STATUS ! Global status * External References: EXTERNAL FIT_PREDDAT * Local Constants: INTEGER OPCHAN ! Output channel for diagnostic PARAMETER ( OPCHAN = 6 ) ! messages ( <1 for no messages) CHARACTER*30 VERSION PARAMETER ( VERSION = 'SFIT Version V2.0-2' ) * Local Variables: RECORD /DATASET/ OBDAT(NDSMAX) ! Observed datasets RECORD /INSTR_RESP/ INSTR(NDSMAX) ! Instrument responses RECORD /PREDICTION/ PREDDAT(NDSMAX) ! Data predicted by model RECORD /MODEL_SPEC/ MODEL ! Model specification DOUBLE PRECISION STAT ! Fit statistic DOUBLE PRECISION FPROB ! Fit probability REAL PARAM(NPAMAX) ! Model parameters REAL LB(NPAMAX) ! Parameter lower bounds REAL UB(NPAMAX) ! Parameter upper bounds REAL LE(NPAMAX) ! Lower error estimate REAL UE(NPAMAX) ! Upper error estimate REAL DPAR(NPAMAX) ! Differential parameter increments REAL PARSIG(NPAMAX) ! Parameter 1 sigma errors (approx) REAL Z ! Redshift [ Eobs/Esource=1/(1+z) ] INTEGER IFID ! Input dataset id INTEGER MCTRL ! Minimisation control INTEGER MFID ! Model spec id INTEGER NDS ! No of datasets INTEGER NGOOD ! No. good data elements INTEGER SSCALE ! Factor for scaling fitstat INTEGER NDOF ! No of degrees of freedom - should be ! no of data - no of unfrozen params INTEGER NITMAX ! Max # iterations INTEGER NPAR ! No of parameters INTEGER FITERR ! Fitting error encountered INTEGER OCI ! Output channel INTEGER FSTAT ! See FIT_PAR for info LOGICAL LIKSTAT ! Fitstat is Cash likelihood statistic? LOGICAL WORKSPACE ! Set up workspace for STAT gradients? LOGICAL FROZEN(NPAMAX) ! Frozen parameter flag LOGICAL PEGGED(NPAMAX) ! Parameter pegged on bound LOGICAL FINISHED ! Minimum found LOGICAL NOFREE ! No parameters free LOGICAL ER ! Parameter error calculation required? LOGICAL OP ! Printout required? *. * Check inherited global status. IF ( STATUS .NE. SAI__OK ) RETURN * Version id CALL MSG_PRNT( VERSION ) * Initialise ASTERIX CALL AST_INIT() CALL SPEC_INIT( STATUS ) * Set up model genus MODEL.GENUS = 'SPEC' * Chi-squared or likelihood fitting? CALL USI_GET0L( 'LIK', LIKSTAT, STATUS ) IF ( LIKSTAT ) THEN FSTAT=FIT__LOGL ELSE FSTAT=FIT__CHISQ END IF * Get observed data (setting up data weights) and response CALL USI_ASSOC( 'INP', 'FileSet|BinDS', 'READ', IFID, STATUS ) WORKSPACE = .TRUE. CALL FIT_GETDAT( ADI__NULLID, IFID, 'SPEC', FSTAT, WORKSPACE, : (.NOT. LIKSTAT), NDS, : OBDAT, NGOOD, SSCALE, PREDDAT, INSTR, STATUS ) IF ( STATUS .NE. SAI__OK ) GOTO 99 * Look for redshift CALL SFIT_GETZ( Z, STATUS ) * Apply red-shift and check data structures CALL SFIT_PRECHK( NDS, Z, PREDDAT, STATUS ) * Get model specification CALL USI_ASSOC( 'MODEL', '*', 'UPDATE', MFID, STATUS ) CALL FIT_MODGET( MFID, MODEL, NPAR, PARAM, LB, UB, LE, UE, : FROZEN, STATUS ) IF ( STATUS .NE. SAI__OK ) GOTO 99 * Number of degrees of freedom for chi-squared IF ( .NOT. LIKSTAT ) THEN * Finds NDOF from frozen array and constraints CALL FIT1_NDOF( NGOOD, MODEL, FROZEN, NDOF, STATUS ) * NDOF to be used for scaling chisq statistic SSCALE = NDOF END IF * Get minimisation control CALL FCI_GETMC( MCTRL, STATUS ) * Set up workspace for model stack CALL SFIT_MAPMODSTK( NDS, PREDDAT, MODEL.STACKPTR, STATUS ) IF ( STATUS .NE. SAI__OK ) GOTO 99 * Zero iterations means just print the statistic CALL ADI_CGET0I( MCTRL, 'MaxIt', NITMAX, STATUS ) IF ( NITMAX .EQ. 0 ) THEN * Evaluate the statistic CALL FIT_APPTIE( MODEL, .FALSE., PARAM, LB, UB, STATUS ) CALL FIT_STAT( NDS, OBDAT, INSTR, MODEL, PARAM, FSTAT, : FIT_PREDDAT, PREDDAT, STAT, STATUS ) * Report value of statistic CALL SFIT_OPSTAT( FSTAT, STAT, SSCALE, NGOOD, 0, STATUS ) * Goodness of fit CALL FIT_MPROB( NDS, OBDAT, FSTAT, SSCALE, PREDDAT, STAT, : FPROB, STATUS ) CALL MSG_SETD( 'FPROB', FPROB ) CALL MSG_PRNT( 'Prob = ^FPROB' ) CALL MSG_BLNK() GOTO 99 END IF * Perform fit iteration CALL FIT_MIN( NDS, OBDAT, INSTR, MODEL, MCTRL, OPCHAN, .TRUE., : NPAR, LB, UB, FROZEN, SSCALE, FSTAT, : FIT_PREDDAT, PREDDAT, PARAM, DPAR, PEGGED, : STAT, FINISHED, FITERR, STATUS ) IF ( STATUS .NE. SAI__OK ) GOTO 99 * Fitting error? IF (FITERR.EQ.2.OR.FITERR.EQ.3)THEN * No free parameters? NOFREE=.TRUE. FINISHED=.TRUE. * Fatal fitting error? ELSE IF ( FITERR .NE. 0 )THEN CALL FIT_REPFERR( FITERR, STATUS ) GOTO 99 END IF * Calculate approximate parameter errors and display IF ( NOFREE ) THEN ER = .FALSE. ELSE CALL USI_GET0L('ERR',ER,STATUS) END IF IF ( ER ) THEN CALL MSG_BLNK() CALL MSG_PRNT( 'Calculating approximate parameter errors' ) CALL FIT_PARERR(NDS,OBDAT,INSTR,MODEL,NPAR,PARAM,LB,UB,DPAR, : FROZEN,PEGGED,SSCALE,FSTAT,FIT_PREDDAT,PREDDAT,PARSIG,STATUS) CALL ARR_COP1R( NPAR, PARSIG, LE, STATUS ) CALL ARR_COP1R( NPAR, PARSIG, UE, STATUS ) ELSE * Reset array to ensure tidy print out CALL ARR_INIT1R( 0.0, NPAR, PARSIG, STATUS ) END IF * Report parameter values CALL SFIT_OPTABLE( NPAR, PARAM, FROZEN, PEGGED, PARSIG, MODEL, : 0, STATUS ) * Report value of statistic CALL SFIT_OPSTAT( FSTAT, STAT, NDOF, NGOOD, 0, STATUS ) * Report red-shift IF ( Z .NE. 0.0 ) THEN CALL MSG_BLNK() CALL MSG_FMTR( 'Z', 'F7.5', Z ) CALL MSG_PRNT( '--- Redshift = ^Z' ) CALL MSG_BLNK() END IF * Update model_spec errors IF ( ER ) THEN CALL FIT_MODUP(MFID,MODEL.NCOMP,NPAR,PARAM,LE,UE,1.0,STATUS) CALL MSG_PRNT( '** Error estimates entered in model spec. **' ) CALL MSG_BLNK() END IF * Printed summary of fit results wanted? CALL SFIT_OPOPEN( OP, OCI, STATUS ) * Write output? IF ( OP ) THEN * Write header CALL AIO_TITLE( OCI, VERSION, STATUS ) * File list CALL SFIT_OPFILES( FSTAT, NDS, OBDAT, MODEL, OCI, STATUS ) * Red-shift IF ( Z .NE. 0.0 ) THEN CALL MSG_FMTR( 'Z', 'F7.5', Z ) CALL AIO_WRITE( OCI, '--- Redshifted to z = ^Z', STATUS ) CALL AIO_BLNK( OCI, STATUS ) END IF * Status of minimisation CALL AIO_BLNK( OCI, STATUS ) IF ( FINISHED ) THEN CALL AIO_WRITE( OCI, 'Minimum found', STATUS ) ELSE CALL AIO_WRITE( OCI, 'Minimum not found', STATUS ) END IF * Report parameter values CALL SFIT_OPTABLE( NPAR, PARAM, FROZEN, PEGGED, PARSIG, : MODEL, OCI, STATUS ) * Value of statistic CALL SFIT_OPSTAT( FSTAT, STAT, NDOF, NGOOD, OCI, STATUS ) * Close file CALL SFIT_OPCLOSE( OCI, STATUS ) END IF * Tidy up & exit 99 CALL USI_ANNUL( 'MODEL', STATUS ) CALL USI_ANNUL( 'INP', STATUS ) CALL AST_CLOSE() CALL AST_ERR( STATUS ) END