/* COPYRIGHT (c) 1990 Kapteyn Astronomical Institute University of Groningen, The Netherlands All Rights Reserved. #> qfit.dc1 Program: QFIT Purpose: Interactive fit of 2-D gaussians Category: ANALYSIS, PROFILES, MODELS, FITTING File: qfit.c Author: M. Vogelaar Keywords: FILENAME= Name of output ASCII file: [No output to file] If a name is specified, an ASCII file is created where fit parameters are listed in a row. If you press carriage return, there will be no output to an ASCII file. APPEND= File exists, ok to append? [Y]/N The file specified in FILENAME= already exists. You can append to this file with APPEND=Y. If APPEND=N you will be prompted for another name. ==== Next keywords are asked in a loop, to be ==== ==== aborted with INSET= ==== INSET= Give input set, subset(s): [STOP Program] Maximum number of subsets is 2048. For each subset a fit is made with the same parameters as the first subset. The INSET= keyword is asked in a loop that is aborted with carriage return ( ). AUTOVIEW= Do you want to display input set in GIDS? Y/[N] For interactive fitting it is convenient to determine a 'fitbox' on the display. If AUTOVIEW=Y, the program VIEW will be started to display the current INSET= (See also keywords in 'VIEW' like CLIP=, NEXT=) ==== Next keywords are asked in a loop, to be ==== ==== aborted with BOX= ==== BOX= Frame for input subsets. [STOP] Total number of pixels in box must not exceed 128x128 . Keyword is prompted in a loop which is aborted with BOX= For each box, all specified subsets are examined before asking the next box. Estimates and fixed values ========================== The following keywords are used to give a value to the parameters that are kept fixed in the fit, or to give a reasonable initial estimate for the free parameters. AMPLITUDE= Amplitude (map units): [Calculated] BEAM= Beam, fwhm in x & y: [Calculated] If indicated, in seconds of arc. X0Y0= Centre in grids: [Calculated] ANGLE= Angle of FWHM in x wrt. pos. X-axis (deg): [Calculated] ZERO= Zero level (map units): [Calculated] MASK= Mask (0=fixed,1=free): [parameter list] ** TOLERANCE= Convergence criterion. [0.01] Relative tolerance. Fitting of the function stops when successive iterations fail to produce a decrement in reduced chi-squared less than TOLERANCE. If its value is less than the minimum tolerance possible, it will be set to this value. This means that maximum accuracy can be obtained by setting TOLERANCE=0.0. ** LAB= Mixing parameter: [0.01] Mixing parameter, LAB determines the initial weight of steepest descent method relative to the Taylor method. LAB should be a small value (i.e. 0.01). ** CLIPLOHI= Give clip levels: [Include all data] Examples: 1) CLIPLOHI= include all data 2) CLIPLOHI=3 include all data >= 3 3) CLIPLOHI=3 5 include all data >=3 and <= 5 Description: QFIT fits 2-dim gaussian to data from INSET= in a given box in BOX= with a limit of 128x128 pixels. The program can be used for example as an flexible alternative for ANTPAT to find beam parameters or to find the exact position of a source. The 2d-gaussian is: F(x,y) = par(0) * EXP( -4.0*ALOG(2.0) * [(xr / par(1))**2 + (yr / par(2))**2] + par(6) where: xr = xo * cos(par(5)) + yo * sin(par(5)) yr = -xo * sin(par(5)) + yo * cos(par(5)) and: xo = x - par(3) yo = y - par(4) The gauss parameters are: 1. Amplitude in Map units 2. FWHMx in arcs 3. FWHMy in arcs 4. X0, center of gauss in grids 5. Y0, center of gauss in grids 6. Rotation angle deg. wrt. pos. x-axis. 7. Zero level in map units The fit routine needs estimates for all parameters. If you use the default of the AMPLITUDE=, BEAM=, X0Y0=, ANGLE= and ZERO= keywords, then, in most circumstances you are using reasonable values. The estimated zero level is the mean of all the pixels on the borders of your selected box (BOX=). The estimated amplitude is the calculated maximum of the data in the box minus the zero level. The estimated FWHM's and position angle are calculated from the data. The center positions are copied from the positions of the calculated maximum. If you want to change these estimates, specify alternative values for one or more keywords. If, for example, you try to fit a 2d-gaussian for which the major axis equals the minor axis but leaving the rotation angle free (in this case the PA has no meaning), there will be probably an error in the fit. In this case you want to do the fit with the rotation angle fixed. Parameters can be used as fixed or free parameters depending on the setting in MASK= To fix a parameter use 0. A free parameter is indicated with 1. The keywords TOLERANCE= and LAB= are fine tuning parameters for a least squares routine. The table, created in the ASCII file (FILENAME=) has a layout set by the user which can easily be changed to suit personal whishes.. Example: Fit gaussian in set 'n4736ave' subset 1. Put results in ASCII file with name 'data'. Use box -4 -10 9 5 and let all parameters be free in the fit: qfit QFIT FILENAME=data QFIT APPEND= QFIT AUTOVIEW=y QFIT INSET=n4736ave 1 Set n4736ave has 3 axes RA from -20 to 20 DEC from -31 to 20 LAMBDA from 0 to 1 BOX range for set n4736ave : RA from -20 to 20 DEC from -31 to 20 QFIT CLIPLOHI= QFIT BOX=-4 -10 9 5 BOX range for set n4736ave : RA from -4 to 9 DEC from -10 to 5 Initial estimates (inserted without the units): Amplitude: 347.534729 (MJY / S) FWHMx: 123.429893 (ARCSEC) FWHMy: 63.259651 (ARCSEC) X0: 2.000000 (grids) Y0: -1.000000 (grids) Angle: 84.357887 (deg) wrt pos. x-axis: Zero level: 10.616884 (MJY / S) QFIT AMPLITUDE= QFIT BEAM= QFIT X0Y0= QFIT ANGLE= QFIT ZERO= QFIT MASK=1 1 1 1 1 1 1 Fitted Gaussian in box: [-4 -10, 9 5] in set: n4736ave (iters:4) ======================================================================= (free) Amplitude: 356.619019 +/- 5.177855 (MJY / S) (free) FWHMx: 120.598099 +/- 2.123478 (ARCSEC) (free) FWHMy: 117.960548 +/- 2.053111 (ARCSEC) (free) Center X0: 1.82 +/- 0.04 (grids) = 192.119869 (DEGREE) = 192d 7m 11.5s = 12h 48m 28.77s (free) Center Y0: -1.87 +/- 0.04 (grids) = 41.389586 (DEGREE) = 41d 23m 22.5s (free) PA major axis: 1.22 +/- 25.28 (deg) wrt to North (free) Zero level: 8.160992 +/- 1.876477 (MJY / S) No offset rotation in header, 0 is assumed. Grid spacing x-direction: -20.00 (ARCSEC) Grid spacing y-direction: 20.00 (ARCSEC) Level: (*,*,0.0001 METER) Tolerance = 0.010000, mixing factor lab = 0.010000 ======================================================================= QFIT BOX= QFIT INSET= QFIT +++ FINISHED +++ Updates: Feb 3, 1992: VOG, Document created Apr 1, 1992: VOG, Rewritten in C Sep 21, 1992: VOG, New FITGAUSS2D routine implemented. May 19, 1993: FL, Coordinate output improved. Sep 20, 1995: VOG, Minor improvements. Documentation updated. Feb 1, 2000: JPT, Increased number of subsets. #< */ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "math.h" #include "cmain.h" #include "gipsyc.h" #include "init.h" #include "finis.h" #include "gdsinp.h" #include "gdsc_ndims.h" #include "setfblank.h" #include "myname.h" #include "anyout.h" #include "nelc.h" #include "cotrans.h" #include "hms.h" #include "dms.h" #include "gdsc_range.h" #include "gdsc_grid.h" #include "gdsbox.h" #include "gdsc_fill.h" #include "gdsi_read.h" #include "userint.h" #include "userlog.h" #include "userfio.h" #include "cancel.h" #include "gdsasn.h" #include "gdscss.h" #include "gdscpa.h" #include "gdsd_rdble.h" #include "error.h" #include "gdsout.h" #include "gdsi_write.h" #include "minmax3.h" #include "stabar.h" #include "wminmax.h" #include "gdsc_name.h" #include "axunit.h" #include "userreal.h" #include "userint.h" #include "lsqfit.h" #include "gauest.h" #include "gdsd_rchar.h" #include "axtype.h" #include "reject.h" #include "deputy.h" #include "gds_close.h" #include "fitgauss2d.h" #define AXESMAX 10 #define SUBSMAX 2048 #define MAXBUF 128*128 /* Buffer size for I/O */ #define MESSLEN 120 #define VERSION "1.0" #define NONE 0 #define REQUEST 1 #define HIDDEN 2 #define EXACT 4 #define fmake(fchr,size) { \ static char buff[size+1]; \ int i; \ for (i = 0; i < size; buff[i++] = ' '); \ buff[i] = 0; \ fchr.a = buff; \ fchr.l = size; \ } /* Malloc version of 'fmake' */ #define finit( fc , len ) { fc.a = malloc( ( len + 1 ) * sizeof( char ) ) ; \ fc.a[ len ] = '\0' ; \ fc.l = len ; } #define MYMAX(a,b) ( (a) > (b) ? (a) : (b) ) #define MYMIN(a,b) ( (a) > (b) ? (b) : (a) ) #define NINT(a) ( (a) < 0 ? (int)((a)-.5) : (int)((a)+.5) ) #define ABS(a) ( (a) < 0 ? (-(a)) : (a) ) #define PI 3.141592653589793 #define TORAD(a) ( (a)*PI/180.0 ) /* Convert degrees to radians */ #define TODEG(a) ( (a)*180.0/PI ) /* Convert radians to degrees */ #define YES 1 #define NO 0 static fchar setin; static fint subin[SUBSMAX]; static fint nsubsI; /* Number of input subsets */ static fint class = 1; static fint dfault; /* Default option for input etc */ static fchar keyword, fmessage; static fint axnum[AXESMAX]; static fint axcount[AXESMAX]; static fint subdim = 2; static fint setdim; static fint result; static fint maxsubs = SUBSMAX; static fint maxaxes = AXESMAX; static fint boxlo[AXESMAX], boxhi[AXESMAX]; static fint framelo[AXESMAX], framehi[AXESMAX]; static fint option; static fint scrnum; /* Set properties */ static double cdelt[2]; static double gridspac[2]; static fchar cunit[2]; static fchar ctype[2]; static fchar bunit; static double crota; static fint skysys, prosys, velsys; static fint axistype[2]; /* read data */ static float image[MAXBUF]; /* global fit data */ static int i; static float parlist[7]; static float errlist[7]; static fint nitems; /* miscellaneous */ static fint setlevel = 0; static float blank; static char message[MESSLEN]; static fint r1, r2; static bool agreed; static fint fitlen[2]; static double physXY[2]; static bool cotransok; static bool fromheader; static fint subnr; static bool autoview; FILE *fp; static char filename[120]; static fchar convlon, convlat; static fint first = YES; static float clip[2]; static void anyborder( int dest, char ch, int len ) /*------------------------------------------------------------*/ /* PURPOSE: Create a string with length 'len' filled with */ /* 'ch' characters. */ /*------------------------------------------------------------*/ { char *str; str = malloc( len + 1 ); if (str == NULL) { anyoutf( 1, "Cannot allocate %d characters for border!", len ); return; } memset( str, ch, len ); str[len] = '\0'; anyoutf( dest, str ); free( str ); } FILE *fopenC( char *filename ) /*------------------------------------------------------------*/ /* Open file to write data extern. The macro 'fmake' must be */ /* available. */ /*------------------------------------------------------------*/ { #include "usertext.h" #include "userlog.h" #include "cancel.h" #include "reject.h" #define FILENAMELEN 80 #define KEY_FILENAME tofchar("FILENAME=") #define MES_FILENAME tofchar("Name of output ASCII file: [No output to file]") #define KEY_APPEND tofchar("APPEND=") #define MES_APPEND tofchar("File exists, ok to append? [Y]/N") #define YES 1 #define NO 0 fchar Filename; bool append; fint request = 1; fint hidden = 2; fint dfault; fint n; fint nitems; fint agreed; FILE *fp; dfault = request; fmake( Filename, FILENAMELEN ); do { append = toflog(YES); /* Default APPEND=Y */ n = usertext_c( Filename, &dfault, KEY_FILENAME, MES_FILENAME ); if (n == 0) return NULL; strcpy( filename, strtok(Filename.a, " ") ); /* Delete after space */ fp = fopen(filename, "r"); if (fp != NULL) /* The file exists */ { nitems = 1; n = userlog_c( &append, &nitems, &dfault, KEY_APPEND, MES_APPEND ); append = tobool( append ); fclose( fp ); cancel_c( KEY_APPEND ); } if (!append) { cancel_c( KEY_FILENAME ); agreed = NO; } else { fp = fopen(filename, "a"); agreed = (fp != NULL); if (!agreed) { reject_c( KEY_FILENAME, tofchar("Cannot open, try another!") ); } } } while (!agreed); return fp; } static void showcoord( fchar Fsetin, fint *Fsubin, fint *Faxnum, fint *Fsubdim, fint *Fsetdim, fchar Fshowstr ) /*------------------------------------------------------------*/ /* Create the string 'Fshowstr' containing information about */ /* the axes. Example: Fshowstr = "(*,29.5 DEGREE,200 KM/S)". */ /* This string can be appended to the string obtained after */ /* a call to 'showsubset". The definitions for BIGSTORE and */ /* AXESMAX must be available. */ /*------------------------------------------------------------*/ { int n; fchar Fcunit; char cunitbuf[20+1]; fint Ferr = 0; fint Fres; fint Fgrid; char dummystr[80]; char rightbuf[80]; /* Coordinate transformation */ fint Fdirect; /* grid coord. -> physical coord. */ double coordin[AXESMAX]; /* Grids before transformation */ double coordout[AXESMAX]; /* Physical coordinates after transformation */ sprintf( rightbuf, "%c", '(' ); for (n = 0; n < *Fsetdim; n++ ) { if (n >= *Fsubdim) { Fgrid = gdsc_grid_c( Fsetin, &Faxnum[n], Fsubin, &Ferr ); coordin[ (int) Faxnum[n]-1 ] = (double) Fgrid; } else { coordin[ (int) Faxnum[n]-1 ] = 0.0; } } Fdirect = 1; /* grid coord. -> physical coord. */ Fres = cotrans_c( Fsetin, Fsubin, coordin, coordout, &Fdirect ); for (n = 0; n < *Fsetdim; n++ ) { if (n >= *Fsubdim) { Fcunit.a = cunitbuf; Fcunit.l = 20; cunitbuf[20] = '\0'; Fres = axunit_c( Fsetin, &Faxnum[n], Fcunit ); sprintf( dummystr, "%.6g %.*s", coordout[ (int) Faxnum[n]-1 ], (int) nelc_c( Fcunit ), Fcunit.a ); } else { sprintf( dummystr, "%c", '*' ); } if (( n + 1 ) == *Fsetdim) { sprintf( rightbuf, "%.*s%s", strlen(rightbuf), rightbuf, dummystr ); } else /* Add comma */ { sprintf( rightbuf, "%.*s%s,", strlen(rightbuf), rightbuf, dummystr ); } } sprintf( Fshowstr.a, "%s)", rightbuf ); } static float toangle( float Angle, float Maxangle ) /*---------------------------------------------------*/ /* Return angle between 0 and < 180.'Maxangle' */ /*---------------------------------------------------*/ { while (Angle < 0.0) Angle += Maxangle; while (Angle > Maxangle) Angle -= Maxangle; return Angle; } void errormess( int result ) { switch (result) { case -1 : { anyoutf( 1, "Too many free parameters in fit" ); } break; case -2 : { anyoutf( 1, "No free parameters in fit" ); } break; case -3 : { anyoutf( 1, "Not enough degrees of freedom" ); } break; case -4 : { anyoutf( 1, "Max number of iterations too small" ); } break; case -5 : { anyoutf( 1, "Diagonal of matrix contains zeros" ); } break; case -6 : { anyoutf( 1, "Determinant of coeff. matrix is zero" ); } break; case -7 : { anyoutf( 1, "Square root of negative number" ); } break; } } float func_c( float *xdat, float *parlist, fint *npar, fint *fopt ) /*---------------------------------------------------------------------- PURPOSE: Calculate the value of a gaussian with parameters P at the position Xdat. The parameters are: parlist(0) : Amplitude parlist(1) : Axis (FWHM) in X-direction parlist(2) : Axis (FWHM) in Y-direction parlist(3) : X0, center of gauss wrt center of subset parlist(4) : Y0, center of gauss wrt center of subset parlist(5) : Rotation angle in radians wrt. positive X-axis counted anti-clockwise parlist(6) : Zero level Units center and FWHM are the same The 2d-gaussian is: F(x,y) = par(0) * EXP( -4.0*ALOG(2.0) * [(xr / par(1))**2 + (yr / par(2))**2] + par(6) where: xr = xo * cos(par(5)) + yo * sin(par(5)) yr = -xo * sin(par(5)) + yo * cos(par(5)) and: xo = x - par(3) yo = y - par(4) ----------------------------------------------------------------------*/ { double xd, yd; /* FWHM's of ellipse */ double x, y; /* Position */ double sinpa, cospa; /* Sine, cosine of position angle */ double argXD, argYD; /* Arguments in the exponent */ xd = fabs((double) parlist[1]); yd = fabs((double) parlist[2]); x = (double)xdat[0] - (double)parlist[3]; y = (double)xdat[1] - (double)parlist[4]; cospa = cos( parlist[5] ); sinpa = sin( parlist[5] ); /* What are the values of x,y in an unrotated frame? */ argXD = x * cospa + y * sinpa; argYD = -x * sinpa + y * cospa; return ( (float) ( (double)parlist[0] * exp( -4.0*log(2.0) * ( (argXD/xd)*(argXD/xd) + (argYD/yd)*(argYD/yd) ) ) + (double)parlist[6] ) ); } void derv_c( float *xdat, float *fpar, float *dervs, fint *npar, fint *fopt ) /*---------------------------------------------------------------------- PURPOSE: Calculate the partial derivatives wrt. the parameters for a gaussian with parameters 'parlist' at position Xdat The parameters are: parlist(0) : Amplitude parlist(1) : Axis (FWHM) in X-direction parlist(2) : Axis (FWHM) in Y-direction parlist(3) : X0, center of gauss wrt center of subset parlist(4) : Y0, center of gauss wrt center of subset parlist(5) : Rotation angle in radians wrt. positive X-axis counted anti-clockwise parlist(6) : Zero level Units center and FWHM are the same ----------------------------------------------------------------------*/ { /* Major and minor axis */ double XD, YD; /* Position */ double x, y; /* Sine, cosine of rotation angle */ double sinpa, cospa; /* Arguments in the exponent */ double argXD, argYD; double expon; /* Positive widths */ XD = fabs((double) parlist[1]); YD = fabs((double) parlist[2]); /* Offset from position peak */ x = (double)xdat[0] - (double)parlist[3]; y = (double)xdat[1] - (double)parlist[4]; cospa = cos( (double)parlist[5] ); sinpa = sin( (double)parlist[5] ); argXD = x * cospa + y * sinpa; argYD = -x * sinpa + y * cospa; /* Determine the derivatives: */ expon = -4.0*log(2.0) * ( (argXD/XD)*(argXD/XD) + (argYD/YD)*(argYD/YD) ); expon = exp( expon ); /* Partial derivative amplitude */ dervs[0] = (float) expon; /* Calculate A.exp(-arg) */ expon = (double) parlist[0] * expon; /* Partial derivative fwhm x */ dervs[1] = (float) ( expon * 8.0 * log(2.0) * argXD*argXD / (XD*XD*XD) ); /* Partial derivative fwhm y axis */ dervs[2] = (float) ( expon * 8.0 * log(2.0) * argYD*argYD / (YD*YD*YD) ); /* Partial derivative x-position*/ dervs[3] = (float) ( expon * -8.0*log(2.0) * ( -argXD*cospa/(XD*XD) + argYD*sinpa/(YD*YD) ) ); /* Partial derivative y-position */ dervs[4] = (float) ( expon * -8.0 * log(2.0) * ( -argXD*sinpa/(XD*XD) - argYD*cospa/(YD*YD) ) ); /* Partial derivative rotation angle*/ dervs[5] = (float) ( expon * -8.0 * log(2.0) * argYD * argXD * ( 1.0/(XD*XD) - 1.0/(YD*YD) ) ); /* Partial derivative zero level */ dervs[6] = 1.0; } static void fitgauss( fint *boxlo, fint *boxhi, float *parlist, float *errlist, fint subnr ) /*-----------------------------------------------------*/ /* Fit a 2-dim gauss (see func_c) to data in input box */ /*-----------------------------------------------------*/ { fint mpar[7]; float tol; fint xdim; fint its; float lab; fint iters; int i; int slen; /* read data */ fint tid; fint totpixels; fint pixelsdone; fint cwlo, cwhi; fchar showstr; cwlo = gdsc_fill_c( setin, &subin[subnr], boxlo ); cwhi = gdsc_fill_c( setin, &subin[subnr], boxhi ); totpixels = fitlen[0] * fitlen[1]; tid = 0; gdsi_read_c( setin, &cwlo, &cwhi, image, &totpixels, &pixelsdone, &tid ); /*--------------------------------------------------*/ /* Put all data in arrays with positions, values */ /* and weights suitable for the LSQFIT function: */ /*--------------------------------------------------*/ nitems = 7; for( i = 0; i < nitems; i++ ) mpar[i] = 1; dfault = REQUEST; do { result = userint_c( mpar, &nitems, &dfault, tofchar("MASK="), tofchar("Mask (0=fixed,1=free): [parameter list]")); if (result == 0) { slen = sprintf( message, "=================== PARAMETERS =====================" ); anyoutf( 1, message ); anyoutf( 1, " 1: Amplitude"); anyoutf( 1, " 2: Axis (FWHM) in X-direction"); anyoutf( 1, " 3: Axis (FWHM) in Y-direction"); anyoutf( 1, " 4: X0, horizontal center of gauss"); anyoutf( 1, " 5: Y0, vertical center of gauss"); anyoutf( 1, " 6: Rotation angle"); anyoutf( 1, " 7: Zero level"); anyoutf( 1, " "); anyoutf( 1, "Use 0 or 1 for each parameter: 0=fixed, 1=free"); anyborder( 1, '=', slen ); anyoutf( 1, " "); cancel_c( tofchar("MASK=") ); } } while (!result); slen = sprintf( message, "======================= YOUR CHOICE ============================"); if (!mpar[0]) anyoutf( 1, " 1:(FIXED) Amplitude fixed to AMPLITUDE="); else anyoutf( 1, " 1:(FREE) Amplitude"); if (!mpar[1]) anyoutf( 1, " 2:(FIXED) Axis (FWHM) in X-direction fixed to BEAM="); else anyoutf( 1, " 2:(FREE) Axis (FWHM) in X-direction"); if (!mpar[2]) anyoutf( 1, " 3:(FIXED) Axis (FWHM) in Y-direction fixed to BEAM="); else anyoutf( 1, " 3:(FREE) Axis (FWHM) in Y-direction");; if (!mpar[3]) anyoutf( 1, " 4:(FIXED) X0, horizontal center of gauss fixed to X0Y0="); else anyoutf( 1, " 4:(FREE) X0, horizontal center of gauss"); if (!mpar[4]) anyoutf( 1, " 5:(FIXED) Y0, vertical center of gauss fixed to X0Y0="); else anyoutf( 1, " 5:(FREE) Y0, vertical center of gauss"); if (!mpar[5]) anyoutf( 1, " 6:(FIXED) Rotation angle fixed to ANGLE="); else anyoutf( 1, " 6:(FREE) Rotation angle"); if (!mpar[6]) anyoutf( 1, " 7:(FIXED) Zero level fixed to ZERO="); else anyoutf( 1, " 7:(FREE) Zero level"); anyborder( 1, '=', slen ); anyoutf( 1, " "); xdim = 2; its = 100; tol = 0.01; /* Get the tolerance */ dfault = HIDDEN; keyword = tofchar("TOLERANCE="); fmessage = tofchar("Tolerance in fit: [0.01] "); nitems = 1; result = userreal_c( &tol, &nitems, &dfault, keyword, fmessage ); lab = 0.01; dfault = HIDDEN; keyword = tofchar("LAB="); fmessage = tofchar("Mixing parameter: [0.01] "); nitems = 1; result = userreal_c( &lab, &nitems, &dfault, keyword, fmessage ); nitems = 7; its = 100; for( i = 0; i < nitems; i++ ) parlist[i] = blank; gridspac[0] = fabs(cdelt[0]); gridspac[1] = fabs(cdelt[1]); dfault = REQUEST; keyword = tofchar( "AMPLITUDE=" ); fmessage = tofchar( "Amplitude (map units): [Calculated]"); nitems = 1; result = userreal_c( &parlist[0], &nitems, &dfault, keyword, fmessage ); keyword = tofchar( "BEAM=" ); if (strstr( cunit[0].a, "DEGREE" ) && strstr( cunit[1].a, "DEGREE" )) { fmessage = tofchar( "Beam, fwhm in x & y (arcsec): [Calculated]"); } else { (void) sprintf( message, "Beam, fwhm in x & y (%.*s x %.*s)", nelc_c(cunit[0]), cunit[0].a, nelc_c(cunit[1]), cunit[1].a ); fmessage = tofchar( message ); } nitems = 2; result = userreal_c( &parlist[1], &nitems, &dfault, keyword, fmessage ); if (strstr( cunit[0].a, "DEGREE" ) && strstr( cunit[1].a, "DEGREE" )) { if (parlist[1] != blank) parlist[1] /= 3600.0; if (parlist[2] != blank) parlist[2] /= 3600.0; } keyword = tofchar( "X0Y0=" ); fmessage = tofchar( "Centre in grids: [Calculated]"); nitems = 2; result = userreal_c( &parlist[3], &nitems, &dfault, keyword, fmessage ); if (parlist[3] != blank) parlist[3] = (parlist[3] - boxlo[0]) * gridspac[0]; if (parlist[4] != blank) parlist[4] = (parlist[4] - boxlo[1]) * gridspac[1]; keyword = tofchar( "ANGLE=" ); fmessage = tofchar( "Angle of FWHM in x wrt. pos. X-axis (deg): [Calculated]"); nitems = 1; result = userreal_c( &parlist[5], &nitems, &dfault, keyword, fmessage ); if (parlist[5] != blank) parlist[5] = TORAD(parlist[5]); keyword = tofchar( "ZERO=" ); fmessage = tofchar( "Zero level (map units): [Calculated]"); nitems = 1; result = userreal_c( &parlist[6], &nitems, &dfault, keyword, fmessage ); clip[0] = blank; clip[1] = blank; dfault = HIDDEN; nitems = 2; keyword = tofchar( "CLIPLOHI=" ); fmessage = tofchar("Give clip levels: [No clip levels]"); result = userreal_c( clip, &nitems, &dfault, keyword, fmessage ); iters = fitgauss2d_c( image, &fitlen[0], &fitlen[1], &gridspac[0], &gridspac[1], parlist, errlist, mpar, &tol, &its, &lab, clip ); if (iters < 0) { switch( (int) iters ) { case -1: anyoutf( 1, "LSQFIT: Too many free parameters, maximum is 32."); break; case -2: anyoutf( 1, "LSQFIT: No free parameters. "); break; case -3: anyoutf( 1, "LSQFIT: Not enough degrees of freedom."); break; case -4: anyoutf( 1, "LSQFIT: Maximum number of iterations too small to obtain a solution " ); anyoutf( 1, " which satisfies TOL."); break; case -5: anyoutf( 1, "LSQFIT: Diagonal of matrix contains elements which are zero."); break; case -6: anyoutf( 1, "LSQFIT: Determinant of the coefficient matrix is zero."); break; case -7: anyoutf( 1, "LSQFIT: Square root of negative number."); break; case -8: anyoutf( 1, "FITGAUSS2D: Box too big."); break; case -9: anyoutf( 1, "FITGAUSS2D: Box contains only blanks."); break; case -10: anyoutf( 1, "FITGAUSS2D: Box length == 1 in x or y direction."); } anyoutf( 1, "No fit ..." ); } else { /* Write the results to screen and logfile: */ anyoutf( 3, " " ); sprintf( message, " Fitted Gaussian in box: [%d %d, %d %d] in set: %.*s (iters:%d)", boxlo[0], boxlo[1], boxhi[0], boxhi[1], nelc_c( setin ), setin.a, iters ); anyoutf( 3, message ); slen = 76; anyborder( 3, '=', slen ); if (mpar[0]) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) Amplitude: %f +/- %f (%.*s)", parlist[0], errlist[0], nelc_c( bunit ), bunit.a ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) Amplitude: %f (%.*s)", parlist[0], nelc_c( bunit ), bunit.a ); } anyoutf( 3, message ); if (strstr( cunit[0].a, "DEGREE" )) { parlist[1] *= 3600.0; errlist[1] *= 3600.0; if (mpar[1]) { if (parlist[1] < 0.0) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMx:(suspicious)%f +/- %f (ARCSEC)", parlist[1], errlist[1] ); } else { if (parlist[1] > 3600.0*parlist[2]) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMx (Major): %f +/- %f (ARCSEC)", parlist[1], errlist[1] ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMx (Minor): %f +/- %f (ARCSEC)", parlist[1], errlist[1] ); } } } else { if (parlist[1] > 3600.0*parlist[2]) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) FWHMx (Major): %f (ARCSEC)", parlist[1] ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) FWHMx (Minor): %f (ARCSEC)", parlist[1] ); } } } else { if (mpar[1]) { if (parlist[1] < 0.0) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMx:(suspicious)%f +/- %f (%.*s)", parlist[1], errlist[1], nelc_c( cunit[0] ), cunit[0].a ); } else { if (parlist[1] > parlist[2]) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMx (Major): %f +/- %f (%.*s)", parlist[1], errlist[1], nelc_c( cunit[0] ), cunit[0].a ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMx (Minor): %f +/- %f (%.*s)", parlist[1], errlist[1], nelc_c( cunit[0] ), cunit[0].a ); } } } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) FWHMx: %f (%.*s)", parlist[1], nelc_c( cunit[0] ), cunit[0].a ); } } anyoutf( 3, message ); if (strstr( cunit[1].a, "DEGREE" )) { parlist[2] *= 3600.0; errlist[2] *= 3600.0; if (mpar[2]) { if (parlist[2] < 0.0) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMy:(suspicious)%f +/- %f (ARCSEC)", parlist[2], errlist[2] ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMy: %f +/- %f (ARCSEC)", parlist[2], errlist[2] ); } } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) FWHMy: %f (ARCSEC)", parlist[2] ); } } else { if (mpar[2]) { if (parlist[2] < 0.0) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMy:(suspicious)%f +/- %f (%.*s)", parlist[2], errlist[2], nelc_c( cunit[1] ), cunit[1].a ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) FWHMy: %f +/- %f (%.*s)", parlist[2], errlist[2], nelc_c( cunit[1] ), cunit[1].a ); } } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) FWHMy: %f (%.*s)", parlist[2], nelc_c( cunit[1] ), cunit[1].a ); } } anyoutf( 3, message ); parlist[3] /= fabs(gridspac[0]); errlist[3] /= fabs(gridspac[0]); parlist[4] /= fabs(gridspac[1]); errlist[4] /= fabs(gridspac[1]); parlist[3] += boxlo[0]; parlist[4] += boxlo[1]; { fint grid2phys = 1; double phys[AXESMAX]; double grids[AXESMAX]; grids[0] = (double) parlist[3]; grids[1] = (double) parlist[4]; r1 = cotrans_c( setin, &subin[subnr], grids, phys, &grid2phys ); if (r1 == 0) { cotransok = YES; physXY[0] = phys[axnum[0]-1]; physXY[1] = phys[axnum[1]-1]; } else { cotransok = NO; physXY[0] = grids[0]; physXY[1] = grids[1]; } } if (mpar[3]) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) Center X0: %.2f +/- %.2f (grids)", parlist[3], errlist[3] ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) Center X0: %.2f (grids)", parlist[3] ); } if (cotransok) { sprintf( message, "%.*s = %f (%.*s)", strlen( message ), message, physXY[0], nelc_c( cunit[0] ), cunit[0].a ); } anyoutf( 3, message ); fmake( convlon, 40 ); fmake( convlat, 40 ); strcpy( convlon.a, "hms?" ); strcpy( convlat.a, "dms?" ); if (axistype[0] == 1) { /* spatial axis longitude */ if (skysys == 1) { /* equatorial */ fint output = 0, prec = 1; hms_c( &physXY[0], convlon, NULL, &prec, &output ); /*"+++++++_++++++++++++++++++%*/ (void) sprintf( message, " = %.*s", nelc_c( convlon ), convlon.a ); } else { /* not equatorial */ fint output = 0, prec = 1; dms_c( &physXY[0], convlon, NULL, &prec, &output ); /*"+++++++_++++++++++++++++++%*/ sprintf( message, " = %.*s", nelc_c( convlon ), convlon.a ); } } if (axistype[0] == 2) { /* spatial axis latitude */ fint output = 0, prec = 1; dms_c( &physXY[0], convlat, NULL, &prec, &output ); /*"+++++++_++++++++++++++++++%*/ sprintf( message, " = %.*s", nelc_c( convlat ), convlat.a ); } anyoutf( 3, message ); if (mpar[4]) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) Center Y0: %.2f +/- %.2f (grids)", parlist[4], errlist[4] ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) Center Y0: %.2f (grids)", parlist[4] ); } if (cotransok) { sprintf( message, "%.*s = %f (%.*s)", strlen( message ), message, physXY[1], nelc_c( cunit[1] ), cunit[1].a ); } anyoutf( 3, message ); if (axistype[1] == 1) { /* spatial axis longitude */ if (skysys == 1) { /* equatorial */ fint output = 0, prec = 1; hms_c( &physXY[1], convlon, NULL, &prec, &output ); /*"+++++++_++++++++++++++++++%*/ (void) sprintf( message, " = %.*s", nelc_c( convlon ), convlon.a ); } else { /* not equatorial */ fint output = 0, prec = 1; dms_c( &physXY[1], convlon, NULL, &prec, &output ); /*"+++++++_++++++++++++++++++%*/ sprintf( message, " = %.*s", nelc_c( convlon ), convlon.a ); } } if (axistype[1] == 2) { /* spatial axis latitude */ fint output = 0, prec = 1; dms_c( &physXY[1], convlat, NULL, &prec, &output ); /*"+++++++_++++++++++++++++++%*/ sprintf( message, " = %.*s", nelc_c( convlat ), convlat.a ); } anyoutf( 3, message ); /* Correct for rotation direction */ parlist[5] = TODEG(parlist[5]); if (parlist[1] > parlist[2]) { /* FWHMx > FWHMy */ parlist[5] -= 90.0; } parlist[5] += crota; /* Correct for rotation angle from header */ parlist[5] = toangle( parlist[5], 180.0 ); if (mpar[5]) { errlist[5] = TODEG(errlist[5]); sprintf( message, /*"+++++++_++++++++++++++++++%*/ "(free) PA major axis: %.2f +/- %.2f (deg) wrt to North", parlist[5], errlist[5] ); } else { sprintf( message, /*"+++++++_++++++++++++++++++%*/ "(fixed) PA major axis: %f (deg) wrt to North", parlist[5] ); } anyoutf( 3, message ); if (mpar[6]) { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(free) Zero level: %f +/- %f (%.*s)", parlist[6], errlist[6], nelc_c( bunit ), bunit.a ); } else { /*"+++++++_++++++++++++++++++%*/ sprintf( message, "(fixed) Zero level: %f (%.*s)", parlist[6], nelc_c( bunit ), bunit.a ); } anyoutf( 3, message ); anyoutf( 3, " " ); if (fromheader) { sprintf( message, "PA latitude axis from header: %.2f deg.", crota ); anyoutf( 3, message ); } else { anyoutf( 3, "No offset rotation in header, 0 is assumed." ); } if (strstr( cunit[0].a, "DEGREE" )) { sprintf( message, "Grid spacing x-direction: %.2f (ARCSEC)", cdelt[0]*3600.0 ); } else { sprintf( message, "Grid spacing x-direction: %.2f (%.*s)", cdelt[0], nelc_c( cunit[0] ), cunit[0].a ); } anyoutf( 3, message ); if (strstr( cunit[1].a, "DEGREE" )) { sprintf( message, "Grid spacing y-direction: %.2f (ARCSEC)", cdelt[1]*3600.0 ); } else { sprintf( message, "Grid spacing y-direction: %.2f (%.*s)", cdelt[1], nelc_c( cunit[1] ), cunit[1].a ); } anyoutf( 3, message ); fmake( showstr, 80 ); if (setdim > subdim ) { showcoord( setin, &subin[subnr], axnum, &subdim, &setdim, showstr ); (void) sprintf( message, "Level: %.*s", nelc_c( showstr ), showstr.a ); anyoutf( 3, message ); } sprintf( message, "Tolerance = %f, mixing factor lab = %f", tol, lab ); anyoutf( 3, message ); if (clip[0] != blank) { if (clip[1] == blank) { (void) sprintf( message, "Clip level: %f", clip[0] ); } else { (void) sprintf( message, "Clip levels: %f %f", clip[0], clip[1] ); } } else { (void) sprintf( message, "No clip levels selected."); } anyoutf( 3, message ); anyborder( 3, '=', slen ); /* Is output to an ASCII file requested? */ if (fp != NULL) { float major, minor, majerr, minerr; fint subgrid; char subtxt[10]; if (parlist[1] > parlist[2]) { major = parlist[1]; minor = parlist[2]; majerr = errlist[1]; minerr = errlist[2]; } else { major = parlist[2]; minor = parlist[1]; majerr = errlist[2]; minerr = errlist[1]; } if (setdim == subdim) { strcpy( subtxt, "Top" ); } else { r1 = 0; subgrid = gdsc_grid_c( setin, &axnum[setdim-1], &subin[subnr], &r1 ); if (r1 >= 0) { (void) sprintf( subtxt, "%d", subgrid ); } else { (void) strcpy( subtxt, "?" ); } } if (first) { /* Print a header */ first = NO; if( skysys == 1 ) { (void) fprintf( fp, /*------------#---#-------#+-#------#-------#+-#-----#--------------#--------------#------#+-#---#------#+-#---#-----#+-#---#--------#--------#----#----#----#----#--*/ "Setname sub X0 Y0 RA DEC Major Minor Pos. angle Ampl. Zero lev. Box itr.\n"); (void) fprintf( fp, "============================================================================================================================================================\n"); } else { (void) fprintf( fp, /*------------#---#-------#+-#------#-------#+-#------#--------------#--------------#------#+-#---#------#+-#---#-----#+-#---#--------#--------#----#----#----#----#--*/ "Setname sub X0 Y0 lon lat Major Minor Pos. angle Ampl. Zero lev. Box itr.\n"); (void) fprintf( fp, "============================================================================================================================================================\n"); } } (void) fprintf( fp, "%-12.12s %3.3s %7.1g +- %6.1g %7.1g +- %6.1g %14.14s %14.14s %6.1f +- %3.1f %6.1f +- %3.1f %5.1f +- %3.1f %8g %8g %4d %4d %4d %4d %2d\n", setin.a, subtxt, parlist[3], errlist[3], parlist[4], errlist[4], convlon.a, convlat.a, major, majerr, minor, minerr, parlist[5], errlist[5], parlist[0], parlist[6], boxlo[0], boxlo[1], boxhi[0], boxhi[1], iters ); } } /* End display if fit was found */ } /* End of fitgauss */ MAIN_PROGRAM_ENTRY /*-------------------------------------------------------------*/ /* QFIT main. */ /*-------------------------------------------------------------*/ { bool quit; init_c(); /* contact Hermes */ /* Task identification */ { fchar Ftask; /* Name of current task */ fmake( Ftask, 20 ); /* Macro 'fmake' must be available */ myname_c( Ftask ); /* Get task name */ Ftask.a[nelc_c(Ftask)] = '\0'; /* Terminate task name with null */ IDENTIFICATION( Ftask.a, VERSION ); /* Show task and version */ } setfblank_c( &blank ); fp = fopenC( filename ); do { autoview = toflog( NO ); dfault = REQUEST; nitems = 1; r1 = userlog_c( &autoview, &nitems, &dfault, tofchar("AUTOVIEW="), tofchar("Do you want to display input set in GIDS? Y/[N]") ); autoview = tobool( autoview ); fmake(setin, 80); keyword = tofchar("INSET="); fmessage = tofchar("Give set (, subsets): [STOP Program]"); dfault = REQUEST; subdim = 2; scrnum = 3; nsubsI = gdsinp_c( setin, subin, &maxsubs, &dfault, keyword, fmessage, &scrnum, axnum, axcount, &maxaxes, &class, &subdim ); if (nsubsI == 0) /* Abort program because was pressed */ quit = YES; else quit = NO; if (!quit) { bool exitloop = NO; /* Continue program if setname was given */ setdim = gdsc_ndims_c( setin, &setlevel ); /* *------------------------------------------------------ * Determine the edges of this its frame (FgridLO/HI) *------------------------------------------------------ */ { fint cwloI, cwhiI; r1 = 0; gdsc_range_c( setin, &setlevel, &cwloI, &cwhiI, &r1 ); r1 = r2 = 0; for (i = 0; i < subdim; i++) { framelo[i] = gdsc_grid_c( setin, &axnum[i], &cwloI, &r1 ); framehi[i] = gdsc_grid_c( setin, &axnum[i], &cwhiI, &r2 ); } } /* Get grid spacings from header */ for (i = 0; i < subdim; i++) /* Append number to name */ { result = sprintf( message, "CDELT%d", axnum[i] ); r1 = 0; /* Get the pixel separation of the axes */ gdsd_rdble_c( setin, tofchar(message), &setlevel, &cdelt[i], &r1 ); if (r1 < 0) errorf( 4, "No grid spacings in header of this set!" ); result = sprintf( message, "CUNIT%d", axnum[i] ); r1 = 0; /* Get the units of the axes */ finit( cunit[i], 40 ); gdsd_rchar_c( setin, tofchar(message), &setlevel, cunit[i], &r1 ); if (r1 < 0) strcpy( cunit[i].a, "?" ); finit( ctype[i], 40 ); r1 = 0; (void) sprintf( message, "CTYPE%d", axnum[i] ); gdsd_rchar_c( setin, tofchar(message), &setlevel, ctype[i], &r1 ); if (r1 < 0) { (void) strcpy( ctype[i].a, "PIXELS" ); axistype[i] = 0; } else { fchar dunit, nunit; fmake( dunit, 20 ); fmake( nunit, 20 ); axistype[i] = axtype_c( ctype[i], nunit, /* Natural units */ dunit, &skysys, &prosys, &velsys ); } } r1 = 0; finit( bunit, 40 ); gdsd_rchar_c( setin, tofchar("BUNIT"), &setlevel, bunit, &r1 ); if (r1 < 0) strcpy( bunit.a, "units ?" ); bunit.l = 7; /* Get rotation angle */ for (i = 0; i < setdim; i++) /* Append number to name */ { result = sprintf( message, "CROTA%d", axnum[i] ); r1 = 0; gdsd_rdble_c( setin, tofchar(message), &setlevel, &crota, &r1 ); if (r1 < 0) { fromheader = NO; crota = 0.0; } else { if (crota != 0.0) { fromheader = YES; break; } } } if (autoview) { fint status; deputy_c( tofchar("VIEW"), &status ); if (status == 1) anyoutf( 1, "Starting VIEW."); if (status == 5) anyoutf( 1, "Called task (VIEW) disconnected" ); if (status ==-6) anyoutf( 1, "Called task (VIEW) not present" ); if (status ==-7) anyoutf( 1, "Max. number of tasks already active" ); } exitloop = NO; while (!exitloop) { dfault = REQUEST; keyword = tofchar( "BOX=" ); (void) sprintf( message, "Give box in %s %s [STOP]", strtok( ctype[0].a, " -" ), strtok( ctype[1].a, " -" ) ); fmessage = tofchar( message ); /* Default is entire subset */ option = 0; scrnum = 3; do { gdsbox_c( boxlo, boxhi, setin, subin, &dfault, keyword, fmessage, &scrnum, &option ); (void) cancel_c( keyword ); fitlen[0] = boxhi[0] - boxlo[0] + 1; fitlen[1] = boxhi[1] - boxlo[1] + 1; if ((boxlo[0] == framelo[0]) && (boxlo[1] == framelo[1]) && (boxhi[0] == framehi[0]) && (boxhi[1] == framehi[1])) { /* End loop */ exitloop = YES; agreed = YES; } if (!exitloop) { agreed = (fitlen[0]*fitlen[1] <= MAXBUF); if (!agreed) reject_c( keyword, tofchar("# > 128*128") ); else { agreed = ( (boxlo[0] >= framelo[0]) && (boxlo[1] >= framelo[1]) && (boxhi[0] <= framehi[0]) && (boxhi[1] <= framehi[1]) ); if (!agreed) reject_c( keyword, tofchar("value(s) outside frame") ); } } } while (!agreed); if (!exitloop) { for (subnr = 0; subnr < (int) nsubsI; subnr++) fitgauss( boxlo, boxhi, parlist, errlist, subnr ); } } cancel_c( tofchar("BOX=") ); cancel_c( tofchar("INSET=") ); r1 = 0; gds_close_c( setin, &r1 ); } } while (!quit); if (fp != NULL) fclose( fp ); /* Close the ASCII file */ finis_c( ); }