/* COPYRIGHT (c) 1990 Kapteyn Astronomical Institute University of Groningen, The Netherlands All Rights Reserved. #> moments.dc1 Program: MOMENTS Purpose: Program to calculate moments and other properties of a profile Category: MANIPULATION, CALCULATION, PROFILES File: moments.c Author: M. Vogelaar Keywords: INSET= Give set (, subsets): Maximum number of subsets is 2048. BOX= Frame for input subsets. [entire subset] OPTION= Give option(s) 0..7 [List options] 0: Sum of profile amplitudes (zeroth moment, without multiplication with the channel spacing). 1: Intensity weighted mean of physical coordinates along profile (first moment). 2: Dispersion in intensity weighted physical coordinates along profile (second moment). 3: Physical coordinate of peak value in profile. 4: Peak value in profile. 5: Dispersion in intensities. 6: Number of subset contributions. 7: Intensity weighted Mode (only with WINDOW=0). OUTSET= Output set (,subsets). Maximum number of subsets is equal to the maximum number of different options. RANGE= Give range of levels to work on. [All levels] Input consists of two values. The first value may be greater than the second. See the description for the correct use of this keyword. INF and -INF are accepted as input. WINDOW= Give window for data selection: [0, i.e. no window] See description. WINMODE= Stat. in most sign. peak(0), or all peaks(1): [0]/1 See description. Description: To calculate moments in profiles you first need to specify the set and the subsets. The number of subsets must be greater than 1 and less than 2048 and the sub- sets are specified by giving the name of the axis in the direction in which you want your profiles. Suppose your set AURORA has the axes: RA-NCP from -7 to 8 DEC-NCP from -7 to 8 FREQ-OHEL from 1 to 59 and you want to make an integrated line emission map; SUM[I] . Channel interval (in mapunits.channel) (e.g. K km/s) a velocity map; = SUM[I.V]/SUM[I] (in CUNITs of V axis) and a velocity dispersion map; = SQRT[ - ] of all channel maps, you specify: INSET=AURORA FREQ Choose option 0, 1 and 2 from the OPTION menu and give a name for the output set. The program will create a new set in which the FREQ axis disappeared and a new axis (PARAM) is made with length 3. The first subset along the PARAM axis contains the integrated subsets (in units of the original data) and the second one contains the velocity field (m/s) and the third the dispersion in m/s. The velocity is an intensity weighted mean of the converted velocities along your operation axis (the FREQ axis in the example). In general, the program will work for profiles in any direction and instead of velocity you could think of any kind of physical coordinate. The program inserts automatically the correct units in the header of the output set. Use can be made of a cutoff in the data values. This is achieved by specifying a range in amplitudes with the keyword RANGE= Examples of the use of the RANGE= keyword: RANGE=0, 20 (If 0 moments MOMENTS Version 1.0 (Oct 9 1992) MOMENTS INSET=M8320 f Set M8320 has 3 axes RA-NCP from -50 to 40 DEC-NCP from -50 to 20 FREQ-OHEL from 1 to 59 MOMENTS BOX=-10 -10 10 10 BOX range for set M8320 : RA-NCP from -10 to 10 DEC-NCP from -10 to 10 MOMENTS OPTION=1 3 4:6 MOMENTS OUTSET=M8320moments Set M8320moments has 3 axes RA-NCP from -50 to 40 DEC-NCP from -50 to 20 PARAM-MOMENTS from 0 to 4 MOMENTS RANGE= MOMENTS WINDOW= ============================= MOMENTS =========================== Profiles examined from set [M8320] Results in output set [M8320moments] -subset 0: Intensity weighted mean of physical coords. -subset 1: Physical coordinate of peak value in profile. -subset 2: Peak value in profile. -subset 3: Dispersion in intensities. -subset 4: Number of subset contributions. Units of operation axis: KM/S Units of data: W.U. MOMENTS +++ FINISHED +++ Updates: Apr 22, 1991: VOG, Document created. Oct 8, 1992: VOG, Store physical coordinate of peak also (option 3). Jan 20, 1993: VOG, Profile statistics in function, keyword WINMODE= added. Jul 1, 1994: VOG, 'Mode' option implemented. Oct 25, 1995: VOG, Changed sigma in 3rd moment (skewness) Feb 1, 2000: JPT, Increased number of subsets. May 26, 2000: VOG, Added option flag for st_weights to be able to get a stand alone dispersion set. Apr 20, 2007: VOG, Change documentation about profile integration #< */ #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 "float.h" #include "gdsinp.h" #include "gdsasn.h" #include "gdscpa.h" #include "gdsout.h" #include "gdsc_ndims.h" #include "setfblank.h" #include "myname.h" #include "anyout.h" #include "nelc.h" #include "cancel.h" #include "gdsc_range.h" #include "gdsc_grid.h" #include "gdsbox.h" #include "gdsc_fill.h" #include "gdsi_read.h" #include "gdsi_write.h" #include "userint.h" #include "usertext.h" #include "cotrans.h" #include "cancel.h" #include "gdsd_rchar.h" #include "gdsd_wchar.h" #include "gdsd_wvar.h" #include "error.h" #include "stabar.h" #include "axunit.h" #include "gdsc_name.h" #include "userreal.h" #include "userlog.h" #include "userint.h" #include "reject.h" #include "getrange.h" #include "minmax3.h" #include "wminmax.h" #include "setnfblank.h" #include "presetd.h" #include "preseti.h" #include "presetr.h" #include "clipper.h" #include "status.h" #include "time.h" #define AXESMAX 10 /* Max. allowed number of axes in a set */ #define SUBSMAX 2048 /* Max. number of substructures to be specified */ #define MAXBUF 1024 /* Buffer size for I/O */ #define MAXMOMENTS 8 /* Total numer of possible options */ #define BIGSTORE 80 /* Length of a string */ #define VERSION "1.0" /* Version number of this program */ #define NONE 0 /* Default values for use in userxxx routines */ #define REQUEST 1 #define HIDDEN 2 #define EXACT 4 #define EPSILON 0.0000001 #define false 0 #define true 1 /* Keywords and messages */ #define KEY_INSET tofchar("INSET=") #define MES_INSET tofchar("Give set (, subsets): " ) #define KEY_OUTSET tofchar("OUTSET=") #define MES_OUTSET tofchar("Give output set: ") #define KEY_BOX tofchar("BOX=") #define MES_BOX tofchar(" ") #define KEY_OPTION tofchar("OPTION=") #define MES_OPTION tofchar("Give option(s) 0..7 [List options]") #define KEY_RANGE tofchar("RANGE=") #define MES_RANGE tofchar("Give range of levels to work on: [all]") #define KEY_WINDOW tofchar("WINDOW=") #define MES_WINDOW tofchar("Give window: [0, i.e. no window]") #define KEY_WINMODE tofchar("WINMODE=") #define MES_WINMODE tofchar("Stat. in most sign. peak(0), or all peaks(1): [0]/1") /* Initialize string with macro */ #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)) /* Input of set, subsets: */ static fchar Fsetin; /* Name of the set */ static fint Fsubin[SUBSMAX]; /* Array for the subset coordinate words */ static fint FnsubsI; /* Number of input subsets */ static fint Fdfault; /* Default option for input etc */ static fint Faxnum[AXESMAX]; /* GDSINP axis numbers array */ static fint Faxcount[AXESMAX]; /* GDSINP axis lengths array */ static fint Fclass = 2; /* Axis is operation axis */ static fint Fsetdim; /* Dimension of the set */ static fint Fsubdim; /* Dimension of the subset */ static fint Fscrnum = 11; /* Destination of log output */ static fint Fmaxaxes = AXESMAX; /* Convert parameters to variables */ static fint Fmaxsubs = SUBSMAX; static fint FmaxIObuf = MAXBUF; static int subnr; /* Index of current subset */ static int paramnr; /* Index of current output subset */ static int i,j, m; /* Counters */ static fint Fwholeset = 0; /* Indicate set level */ static fint Faxesoutsidesub; static fint Foptions[MAXMOMENTS]; /* Output set related */ static fchar Fsetout; /* Name of the set */ static fint Fsubout[SUBSMAX]; /* Array for the subset coordinate words */ static fint FnsubsO; /* Number of input subsets */ static fint FaxnumO[AXESMAX]; /* GDSINP axis numbers array */ static fint FaxcountO[AXESMAX]; /* GDSINP axis lengths array */ /* Input of area etc.:*/ static fint Fcwlo[SUBSMAX]; /* Coordinate words */ static fint Fcwhi[SUBSMAX]; static fint FcwloOUT[MAXMOMENTS]; static fint FcwhiOUT[MAXMOMENTS]; static fint FgridLO[AXESMAX]; /* Coordinate words for frame */ static fint FgridHI[AXESMAX]; static fint FgridLOO[AXESMAX]; /* Coordinate words for frame */ static fint FgridHIO[AXESMAX]; static fint BgridLO[AXESMAX]; /* Coordinate words for box */ static fint BgridHI[AXESMAX]; static fint Fboxopt; /* Input option for 'gdsbox' */ /* Data transfer: */ static fint Ftotpixels; /* Total number of pixels in input */ static fint Fpixelsdone; static fint FtidIN[SUBSMAX]; static fint FtidOUT[MAXMOMENTS]; /* Transfer id's */ static float imageIN[MAXBUF]; /* Multiple buffer for all subsets */ /* Related to update of header etc: */ static float datamin[MAXMOMENTS]; static float datamax[MAXMOMENTS]; static fint Fnblanks[MAXMOMENTS]; static fint Fremove; static fchar Faxunits; static fchar Fdataunits; /* Stabar related: */ static float STBstart; static float STBend; static float STBcurrent; /* Miscellaneous: */ static fint Fnumitems; /* Max. number of input items in userxxx routines */ static fint Fr1, Fr2; /* Results of userxxx routines */ static float blank; /* Value of system blank */ static char messbuf[BIGSTORE]; /* Buffer for text message */ static fint Foutaxislen; static fint Fmcount[MAXMOMENTS]; /* Counter for 'minmax3' routine */ static float range[2]; /* User given data in or out range */ static float st_sum[MAXBUF]; /* Same arrays, but only for 1 peak */ static float st_weidisp[MAXBUF]; static float st_peakwidth[MAXBUF]; static float st_maximum[MAXBUF]; static float st_maxphys[MAXBUF]; static float st_profdisp[MAXBUF]; static float st_wmean[MAXBUF]; static float st_mode[MAXBUF]; static fint Fwindow; /* Width of selected window */ static fint Fmode; static float value; static int moment; static float physcoord[SUBSMAX]; /* Physical coordinates */ static int agreed; static int optionflag[MAXMOMENTS]; /* Which options were selected? */ static int optionparam[MAXMOMENTS]; /* Select output subset number */ static bool blankcube; static float profiles[MAXBUF][SUBSMAX]; /* MAXBUF profiles of length SUBSMAX each */ static void anyoutC( int dev, char *anyCstr ) /*------------------------------------------------------------------*/ /* The C version of 'anyout_c' needs two parameters: */ /* an integer and a C-type string. The integer determines */ /* the destination of the output which is: */ /* 0 use default [set by HERMES to 3 but can be changed by user]*/ /* 1 terminal */ /* 2 LOG file */ /* 8 terminal, suppressed in "experienced mode" */ /* 16 terminal, only when in "test mode" */ /*------------------------------------------------------------------*/ { fint ldev = (fint) dev; anyout_c( &ldev, tofchar( anyCstr ) ); } static double getphyscoord( fchar Fsetname, fint cowosubset, int subnr ) /* *------------------------------------------------------------------------------ * This function return the physical coordinate of a grid position on * the operation axis. *------------------------------------------------------------------------------ */ { fint Fdirect = 1; /* grid coord. -> physical coord. */ double coordin[AXESMAX]; /* grids before cotrans */ double coordout[AXESMAX]; /* Phys. coords after cotrans */ fint Fres; int n; double zero = 0.0; /* Preset array to zero */ fint Fwholeset = 0; fint Fr1; Fsetdim = gdsc_ndims_c( Fsetin, &Fwholeset ); (void) presetd_c( &zero, coordin, &Fsetdim ); n = (int) Fsetdim - 1; /* Axnum = 1, 2, ... */ Fr1 = 0; coordin[(int) Faxnum[n]-1] = (double) gdsc_grid_c( Fsetin, &Faxnum[n], &cowosubset, &Fr1 ); Fres = cotrans_c( Fsetin, &cowosubset, coordin, coordout, &Fdirect ); if ((int) Fres != 0) { if (subnr == 0) { anyoutC(3, "MOMENTS: Cannot find physical coordinates!"); anyoutC(3, "MOMENTS: Substituting subset numbers."); } coordout[(int) Faxnum[n]-1] = (double) subnr + 1; } return ( coordout[(int) Faxnum[n] - 1] ); } static char *makedate( char *buffer, int maxlen ) /*------------------------------------------------------------*/ /* PURPOSE: Return date in format : 29-NOV-1990 */ /* 'maxlen' gives max. length of buffer. */ /*------------------------------------------------------------*/ { struct tm *ptr; time_t lt; lt = time(NULL); /* Get the coded calendar time */ ptr = localtime(<); strftime( buffer, maxlen, "%d-%b-%Y", ptr ); return( buffer ); } static void writeandupdate( float *imageOUT, int paramnr ) /* *------------------------------------------------------------------------------ * Write part of image to disk, and keep administration for header update. * Note: Almost all variables are global! *------------------------------------------------------------------------------ */ { gdsi_write_c( Fsetout, &FcwloOUT[paramnr], &FcwhiOUT[paramnr], imageOUT, &Fpixelsdone, &Fpixelsdone, &FtidOUT[paramnr] ); (void) minmax3_c( imageOUT, &Fpixelsdone, &datamin[paramnr], &datamax[paramnr], &Fnblanks[paramnr], &Fmcount[paramnr] ); } static void blankoutset( fchar Setout ) /*---------------------------------------------*/ /* Blank the output set */ /*---------------------------------------------*/ { float blankarray[MAXBUF]; fint maxlen = MAXBUF; fint pixelsdone; fint tid = 0; fint setlevel = 0; fint r1 = 0; fint cwlo, cwhi; (void) gdsc_range_c( Setout, &setlevel, &cwlo, &cwhi, &r1 ); setnfblank_c( blankarray, &maxlen ); do { gdsi_write_c( Setout, &cwlo, &cwhi, blankarray, &maxlen, &pixelsdone, &tid ); } while( tid != 0 ); } static void profstat( float *profile, int ndat, int *optionflag, int minwinwidth, int winmode, float *vsum, float *vweimean, float *vweidisp, float *vmaxphys, float *vmaximum, float *vprofdisp, float *vpeakwidth, float *vmode ) /*--------------------------------------------------------------------------*/ /* If no window was specified (window == 0) then calculate sum etc of all */ /* non blank elements in this profile. If there is a window, there are two */ /* modes of operation: 1) (winmode == 0) Return values of peak with grea- */ /* test flux, or 2) (winmode == 1) return values of all selected peaks. */ /*--------------------------------------------------------------------------*/ { float sum; float weightedsum; float sumvel; float sumweights; float peakwidth; float sumsqr; float sumsqrunw; float sumsqrAmpl; float maximum; float maxphys; float value; int i,j; /* Index from 0 to profile length (ndat) */ bool winselect; float st_sum = blank; /* Blank for initialization */ float st_peakwidth = 0.0; float st_weightedsum = 0.0; float st_sumweights = 0.0; float st_sumvel = 0.0; float st_sumsqr = 0.0; float st_sumsqrunw = 0.0; float st_sumsqrAmpl = 0.0; float st_maximum = blank; float st_maxphys = blank; *vsum = blank; /* In case profile contains blanks only */ *vweimean = blank; *vweidisp = blank; *vmaxphys = blank; *vmaximum = blank; *vprofdisp = blank; *vpeakwidth = blank; winselect = (minwinwidth > 0); /* Find first non blank in profile */ i = 0; while ((profile[i] == blank) && (i < ndat)) i++; if (i == ndat-1) { /* All data blank, return. */ return; } sum = 0.0; weightedsum = 0.0; sumvel = 0.0; sumweights = 0.0; peakwidth = 0.0; sumsqr = 0.0; sumsqrunw = 0.0; sumsqrAmpl = 0.0; maximum = profile[i]; /* value of first non blank pixel */ maxphys = physcoord[i]; for (j = i; j < ndat; j++) { value = profile[j]; if (value != blank) { sum += value; peakwidth += 1.0; if ((optionflag[1] || optionflag[2] || optionflag[7])) { /* Intensity weighted mean */ weightedsum += physcoord[j] * value; sumvel += physcoord[j]; /* Included for option 7 */ sumweights += value; } if (optionflag[2] || optionflag[7]) { /* Dispersion in operation axis units */ sumsqr += value * physcoord[j] * physcoord[j]; sumsqrunw += physcoord[j] * physcoord[j]; /* Included for option 7 */ } if (optionflag[3] || optionflag[4]) { if (maximum != blank) { if (value > maximum) { maximum = value; maxphys = physcoord[j]; } } else { maximum = value; maxphys = physcoord[j]; } } if (optionflag[5]) { /* Dispersion in amplitude */ sumsqrAmpl += value * value; } } if (winselect) { /* Is windowing on? */ if ( (value == blank) || (j == ndat - 1) ) { /* Is this the end of a window? */ if (winmode == 0) { /*-------------------------------------------*/ /* Store if this window was ok and it is the */ /* first peak. If it is not the first peak, */ /* compare with the previous one. */ /*-------------------------------------------*/ if ((int) peakwidth >= minwinwidth) { /* Width is ok! */ if ( (st_sum == blank) || (st_sum != blank && sum > st_sum) ) { st_sum = sum; st_peakwidth = peakwidth; if (optionflag[1] || optionflag[2] || optionflag[7]) { st_weightedsum = weightedsum; st_sumweights = sumweights; } if (optionflag[2]) st_sumsqr = sumsqr; if (optionflag[3]) st_maxphys = maxphys; if (optionflag[4]) st_maximum = maximum; if (optionflag[5]) st_sumsqrAmpl = sumsqrAmpl; if (optionflag[7]) st_sumsqrunw = sumsqrunw; } } maximum = blank; /* Forget previous values */ maxphys = blank; } else { /*---------------------------------------------------*/ /* If this window was ok, add sums etc. to previous */ /* windows. */ /*---------------------------------------------------*/ if ((int) peakwidth >= minwinwidth) { /* Width is ok! */ if (st_sum == blank) { st_sum = sum; st_peakwidth = peakwidth; if (optionflag[1] || optionflag[2] || optionflag[7]) { st_weightedsum = weightedsum; st_sumweights = sumweights; } if (optionflag[2]) st_sumsqr = sumsqr; if (optionflag[3]) st_maxphys = maxphys; if (optionflag[4]) st_maximum = maximum; if (optionflag[5]) st_sumsqrAmpl = sumsqrAmpl; if (optionflag[7]) st_sumsqrunw = sumsqrunw; } else { st_sum += sum; /* Just ADD to the total */ st_peakwidth += peakwidth; if (optionflag[1] || optionflag[2] || optionflag[7]) { st_weightedsum += weightedsum; st_sumweights += sumweights; } if (optionflag[2]) st_sumsqr += sumsqr; if (optionflag[5]) st_sumsqrAmpl += sumsqrAmpl; if (optionflag[3]) st_maxphys = maxphys; /*Current max.*/ if (optionflag[4]) st_maximum = maximum; if (optionflag[7]) st_sumsqrunw += sumsqrunw; } } } /* End of window, so reset arrays */ sum = 0.0; peakwidth = 0.0; weightedsum = 0.0; sumweights = 0.0; sumsqr = 0.0; sumsqrunw = 0.0; } } } if (!winselect) { st_sum = sum; if (optionflag[1] || optionflag[2] || optionflag[7]) { st_weightedsum = weightedsum; st_sumweights = sumweights; st_sumvel = sumvel; } if (optionflag[2] || optionflag[7]) st_sumsqr += sumsqr; if (optionflag[3]) st_maxphys = maxphys; if (optionflag[4]) st_maximum = maximum; if (optionflag[5]) st_sumsqrAmpl = sumsqrAmpl; if (optionflag[7]) st_sumsqrunw += sumsqrunw; st_peakwidth = peakwidth; } *vsum = st_sum; *vpeakwidth = st_peakwidth; if (optionflag[1] || optionflag[2] || optionflag[7]) { value = st_sumweights; if ((value == blank) || (fabs(value) < EPSILON)) { *vweimean = blank; } else { *vweimean = st_weightedsum / st_sumweights; /* sprintf( messbuf, "mode, weisum, sumwe, mean=%d %f %f %f", winmode, st_weightedsum,st_sumweights,*vweimean ); anyoutC( 1, messbuf ); */ } } if (optionflag[2]) { value = st_sumweights; if ((value == blank) || (fabs(value) < EPSILON) || (*vweimean == blank)) { *vweidisp = blank; } else { *vweidisp = st_sumsqr/st_sumweights - (*vweimean) * (*vweimean); if (*vweidisp >= 0.0) { *vweidisp = sqrt( *vweidisp ); } else { *vweidisp = blank; } } } if (optionflag[3]) { *vmaxphys = st_maxphys; } if (optionflag[4]) { *vmaximum = st_maximum; } if (optionflag[5]) { value = st_peakwidth; if ((value == blank) || (value == 0.0)) { *vprofdisp = blank; } else { *vprofdisp = st_sumsqrAmpl/st_peakwidth - (st_sum/st_peakwidth)*(st_sum/st_peakwidth); if (*vprofdisp >= 0.0) { *vprofdisp = sqrt( *vprofdisp ); } else { *vprofdisp = blank; } } } if (optionflag[7]) { /* Added on june 29 1994. Calculate mode using third moment. */ /* You need an extra loop through the profile. */ /* The use of a window is not yet implemented. */ if ((st_sumsqr == blank) || (*vweimean == blank)) { *vmode = blank; } else { float skewhalf = 0.0; float ave_vel; i = 0; while ((profile[i] == blank) && (i < ndat)) i++; if (i == ndat-1) { /* All data blank, return. */ return; } for (j = i; j < ndat; j++) { value = profile[j]; if (value != blank) { skewhalf += pow( (physcoord[j] - *vweimean), 3 ) * value; } } skewhalf /= st_sumweights; ave_vel = st_sumvel/st_peakwidth; st_sumsqrunw = *vweidisp; /*----------------------------------------------------------*/ /* Note that the dispersion used in the skewness formula is */ /* the intensity weighted dispersion. This is changed at */ /* 25 oct 1995. */ /*----------------------------------------------------------*/ /* st_sumsqrunw = (st_sumsqrunw/(st_peakwidth)) - (ave_vel*ave_vel); st_sumsqrunw = sqrt(st_sumsqrunw); */ if (st_sumsqrunw <= 0.0) *vmode = blank; else *vmode = *vweimean - (skewhalf / (st_sumsqrunw*st_sumsqrunw) ); /* sprintf( messbuf, "vmode=%f, weimean=%f skewhalf=%f st_sumsqr=%f vweidisp=%f ave_vel=%f", *vmode, *vweimean , skewhalf, st_sumsqrunw, *vweidisp, ave_vel ); anyoutC(1, messbuf ); */ } } } MAIN_PROGRAM_ENTRY { init_c(); /* contact Hermes */ /* Task identification */ { static 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 char. */ IDENTIFICATION( Ftask.a, VERSION ); /* Show task and version */ } setfblank_c( &blank ); fmake(Fsetin, 80); /* *---------------------------------------------------------------------------- * Because Fortran passes all arguments by reference, all C functions with * a Fortran equivalent must do this also (GIPSY programmers guide, * Chapter 9). * If the subset dimension 'Fsubdim' is set to 0 before the call to 'gdsinp', * the input routine accepts subsets of arbitrary dimensions smaller than * the dimension of the set, and it returns the dimension of the user created * subset. *---------------------------------------------------------------------------- */ Fdfault = NONE; Faxesoutsidesub = 1; Fscrnum = 3; Fclass = 2; FnsubsI = gdsinp_c( Fsetin, Fsubin, &Fmaxsubs, &Fdfault, KEY_INSET, MES_INSET, &Fscrnum, Faxnum, Faxcount, &Fmaxaxes, &Fclass, &Faxesoutsidesub ); Fsetdim = gdsc_ndims_c( Fsetin, &Fwholeset ); Fsubdim = Fsetdim - Faxesoutsidesub; /* *---------------------------------------------------------------------------- * Determine the edges of this its frame (FgridLO/HI) *---------------------------------------------------------------------------- */ Fr1 = 0; (void) gdsc_range_c( Fsetin, &Fwholeset, &Fcwlo[0], &Fcwhi[0], &Fr1 ); Fr1 = Fr2 = 0; for (m = 0; m < (int) Fsetdim; m++) { FgridLO[m] = gdsc_grid_c( Fsetin, &Faxnum[m], &Fcwlo[0], &Fr1 ); FgridHI[m] = gdsc_grid_c( Fsetin, &Faxnum[m], &Fcwhi[0], &Fr2 ); } /* *---------------------------------------------------------------------------- * Prepare a box for INSET. Default is a box equal to the frame. *---------------------------------------------------------------------------- */ Fdfault = REQUEST; Fboxopt = 0; Fscrnum = 3; (void) gdsbox_c( BgridLO, BgridHI, Fsetin, Fsubin, &Fdfault, KEY_BOX, MES_BOX, &Fscrnum, &Fboxopt ); /* Count number of pixels in this substructure */ Ftotpixels = 1; /* Total number of pixels in (boxed) subset */ for(m = 0; m < (int) Fsubdim; m++) Ftotpixels *= (BgridHI[m] - BgridLO[m] + 1); /* *---------------------------------------------------------------------------- * GDSASN is needed before the call to GDSOUT to obtain * an output set. GDSASN copies the axis names from the * set previously opened by GDSINP in the order as determined * by the user at the associated GDSINP request. This buffer * will be read by GDSOUT, which will create an output set * according to the specifications in this buffer. *---------------------------------------------------------------------------- */ (void) gdsasn_c( KEY_INSET, KEY_OUTSET, &Fclass ); /* *---------------------------------------------------------------------------- * GDSCPA changes the primary axis of an output set to be * obtained by GDSOUT. In this case add 'PARAM' axis to GDSOUT buffer *---------------------------------------------------------------------------- */ { #define AXNAME tofchar("PARAM-MOMENTS") #define CUNIT tofchar(" ") fint Fpmask; fint Faxisnumber; double outcdelt = 1.0; double outcrota = 0.0; double outcrpix = 1.0; /* ==> param 0 = moment 0 */ double outcrval = 0.0; int outsubs = 0; /* Get options from user to determine the length of the param axis */ Fnumitems = MAXMOMENTS; Fdfault = REQUEST; do { Fr1 = userint_c( Foptions, &Fnumitems, &Fdfault, KEY_OPTION, MES_OPTION ); agreed = false; if ((int) Fr1 == 0) { anyoutC(3, " ======MOMENTS======"); anyoutC(3, "0 Integrate subsets along operation axis" ); anyoutC(3, "1 Intensity-weighted mean in profile" ); anyoutC(3, "2 Intensity weighted dispersion in profile" ); anyoutC(3, "3 Physical coordinate of maximum value on operating axis"); anyoutC(3, "4 Maximum values on operating axis" ); anyoutC(3, "5 Dispersion in intensities" ); anyoutC(3, "6 Number of subsets" ); anyoutC(3, "7 Intensity weighted Mode (only with WINDOW=0)" ); (void) cancel_c( KEY_OPTION ); } else { for (moment = 0; moment < MAXMOMENTS; moment++) { optionflag[moment] = 0; for (j = 0; j < (int) Fr1; j++) { if (moment == Foptions[j]) { optionflag[moment] = 1; } } } /* Check whether at least one flag is set and give each moment a unique output subset number. */ outsubs = 0; for (moment = 0; moment < MAXMOMENTS; moment++) { if (optionflag[moment]) { agreed = true; optionparam[moment] = outsubs++; } } if (!agreed) (void) reject_c( KEY_OPTION, tofchar("Nothing selected!") ); } } while (!agreed); Foutaxislen = outsubs; Fpmask = 14; /* pmask = 14 (2 + 4 + 8) means that CTYPE, CRPIX and CRVAL are defined.*/ Faxisnumber = Fsubdim + 1; (void) gdscpa_c( KEY_OUTSET, /* Keyword associated with a GDSOUT call.*/ &Faxisnumber, /* The axis number of the axis to be changed.*/ &Foutaxislen, /* Size of the axis.*/ &outcdelt, /* Increment in physical units along axis.*/ &outcrota, /* Rotation angle of axis.*/ &outcrpix, /* Reference pixel of axis.*/ &outcrval, /* Physical reference value at reference pixel.*/ AXNAME, /* New axis name.*/ CUNIT, /* Physical units of axis.*/ &Fpmask ); /* Bit mask denoting which of the six above values are defined.*/ } /* *---------------------------------------------------------------------------- * Get output set: *---------------------------------------------------------------------------- */ fmake(Fsetout, BIGSTORE); Fdfault = NONE; FnsubsO = gdsout_c( Fsetout, Fsubout, &Foutaxislen, &Fdfault, KEY_OUTSET, MES_OUTSET, &Fscrnum, FaxnumO, FaxcountO, &Fmaxaxes ); Fr1 = 0; (void) gdsc_range_c( Fsetout, &Fwholeset, &FcwloOUT[0], &FcwhiOUT[0], &Fr1 ); Fr1 = Fr2 = 0; for (m = 0; m < (int) Fsetdim; m++) { FgridLOO[m] = gdsc_grid_c( Fsetout, &FaxnumO[m], &FcwloOUT[0], &Fr1 ); FgridHIO[m] = gdsc_grid_c( Fsetout, &FaxnumO[m], &FcwhiOUT[0], &Fr2 ); } blankcube = 0; for (m = 0; m < (int) Fsubdim; m++) { blankcube = (blankcube || (BgridLO[m] != FgridLO[m]) || (BgridHI[m] != FgridHI[m])); } if (blankcube) { status_c(tofchar("Blanking outside box")); blankoutset( Fsetout ); } /* Define a data range */ range[0] = -1.0*FLT_MAX; /* Defined in float.h */ range[1] = FLT_MAX; Fdfault = REQUEST; getrange_c( range, &Fdfault, KEY_RANGE, MES_RANGE ); Fdfault = REQUEST; Fnumitems = 1; do { Fwindow = 0; Fr1 = userint_c( &Fwindow, &Fnumitems, &Fdfault, KEY_WINDOW, MES_WINDOW ); agreed = ((Fwindow >= 0) && (Fwindow <= FnsubsI)); if (!agreed) reject_c( KEY_WINDOW, tofchar("Not allowed!") ); } while (!agreed); if (Fwindow > 0) { Fdfault = REQUEST; Fnumitems = 1; do { Fr1 = userint_c( &Fmode, &Fnumitems, &Fdfault, KEY_WINMODE, MES_WINMODE ); agreed = ((Fmode == 0) || (Fmode == 1)); if (!agreed) reject_c( KEY_WINMODE, tofchar("Not allowed!") ); } while (!agreed); } /* Get units of operation axis and data units */ { fint Fresult; fint Ferrlev = 4; fint n = Fsetdim - 1; fmake( Faxunits, BIGSTORE ); Fresult = axunit_c( Fsetin, &Faxnum[n], Faxunits ); if (Fresult == 1) (void) error_c( &Ferrlev, tofchar("A cotrans error occured!") ); if (Fresult == 2) (void) error_c( &Ferrlev, tofchar("Axis not present in set!") ); if (Fresult == 3) (void) error_c( &Ferrlev, tofchar("Output character string not large enough!") ); fmake( Fdataunits, BIGSTORE ); Fr1 = 0; gdsd_rchar_c( Fsetin, tofchar("BUNIT"), &Fwholeset, Fdataunits, &Fr1 ); if (Fr1 < 0) { anyoutC(3, "MOMENTS: Cannot find map units (BUNIT) in header"); strcpy( Fdataunits.a, "?" ); } } /* *---------------------------------------------------------------------------- * Give user some data in log-file *---------------------------------------------------------------------------- */ sprintf( messbuf, "=================================== MOMENTS =================================" ); anyoutC( 3, messbuf ); sprintf( messbuf, "Profiles examined from set [%.*s]", nelc_c(Fsetin), Fsetin.a ); anyoutC( 3, messbuf ); sprintf( messbuf, "Results in output set [%.*s]", nelc_c(Fsetout), Fsetout.a ); anyoutC( 3, messbuf ); for(m = 0, subnr = 0; m < MAXMOMENTS; m++) { if (optionflag[m]) { sprintf( messbuf, " -subset %d:", subnr++ ); switch (m) { case 0: sprintf( messbuf, "%.*s Sum of profile amplitudes (0 moment).", strlen(messbuf), messbuf ); break; case 1: sprintf( messbuf, "%.*s Intensity weighted mean of physical coords. (1 moment).", strlen(messbuf), messbuf ); break; case 2: sprintf( messbuf, "%.*s Dispersion in intensity weighted physical coords. (2 moment).", strlen(messbuf), messbuf ); break; case 3: sprintf( messbuf, "%.*s Physical coordinate of peak value in profile.", strlen(messbuf), messbuf ); break; case 4: sprintf( messbuf, "%.*s Peak value in profile.", strlen(messbuf), messbuf ); break; case 5: sprintf( messbuf, "%.*s Dispersion in intensities.", strlen(messbuf), messbuf ); break; case 6: sprintf( messbuf, "%.*s Number of subset contributions.", strlen(messbuf), messbuf ); break; case 7: sprintf( messbuf, "%.*s Intensity weighted Mode.", strlen(messbuf), messbuf ); break; } anyoutC( 3, messbuf ); } } sprintf( messbuf, "Units of operation axis: %.*s", nelc_c(Faxunits), Faxunits.a ); anyoutC( 3, messbuf ); sprintf( messbuf, "Units of data: %.*s", nelc_c(Fdataunits), Fdataunits.a ); anyoutC( 3, messbuf ); /* *---------------------------------------------------------------------------- * Select mode: Initialize coordinate words etc. and start calculating. *---------------------------------------------------------------------------- */ for(subnr = 0; subnr < (int) FnsubsI; subnr++) { /* Create coordinate words for the input subsets */ Fcwlo[subnr] = gdsc_fill_c( Fsetin, &Fsubin[subnr], BgridLO ); Fcwhi[subnr] = gdsc_fill_c( Fsetin, &Fsubin[subnr], BgridHI ); /* Reset tranfer id's */ FtidIN[subnr] = 0; /* For each grid on the operation axis, get physical value */ physcoord[subnr] = (float) getphyscoord( Fsetin, Fsubin[subnr], subnr ); /* sprintf(messbuf, "%d %f", subnr, physcoord[subnr]); anyoutC( 3, messbuf ); */ } /* Create coordinate words for the output subsets */ for(paramnr = 0; paramnr < (int) FnsubsO; paramnr++) { FcwloOUT[paramnr] = gdsc_fill_c( Fsetout, &Fsubout[paramnr], BgridLO ); FcwhiOUT[paramnr] = gdsc_fill_c( Fsetout, &Fsubout[paramnr], BgridHI ); FtidOUT[paramnr] = 0; Fmcount[paramnr] = 0; } /* Initialize stabar */ STBstart = 0.0; STBend = (float) Ftotpixels * FnsubsI; STBcurrent = 0.0; (void) stabar_c( &STBstart, &STBend, &STBcurrent ); /*----------------------------------------------------------------*/ /* Start reading data until Transfer id == 0. Read MAXBUF pixels */ /* of each subset and store in array 'profiles'. */ /*----------------------------------------------------------------*/ do { float rangelo = range[0]; float rangehi = range[1]; /* Loop through input subsets */ for (subnr = 0; subnr < (int) FnsubsI; subnr++) { /* Read data from disk */ (void) gdsi_read_c( Fsetin, &Fcwlo[subnr], &Fcwhi[subnr], imageIN, &FmaxIObuf, &Fpixelsdone, &FtidIN[subnr] ); /* Show progress */ STBcurrent += (float) Fpixelsdone; (void) stabar_c( &STBstart, &STBend, &STBcurrent ); /* Blank values in or out range. Store the data */ if (rangelo <= rangehi) { for (i = 0; i < (int) Fpixelsdone; i++) { value = imageIN[i]; if (value <= rangelo) { value = blank; } else { if (value >= rangehi) value = blank; } profiles[i][subnr] = value; } } else { /* rangelo greater than rangehi */ for (i = 0; i < (int) Fpixelsdone; i++) { value = imageIN[i]; if ((value >= rangehi) && (value <= rangelo)) { value = blank; } profiles[i][subnr] = value; } } } /* Profiles filled for all subsets */ /*---------------------------------------------------------------*/ /* Now loop over all profiles and do statistics for each profile */ /*---------------------------------------------------------------*/ for (i = 0; i < (int) Fpixelsdone; i++) { int proflen = (int) FnsubsI; int window = (int) Fwindow; int windowmode = (int) Fmode; profstat( &profiles[i][0], proflen, optionflag, window, windowmode, &st_sum[i], &st_wmean[i], &st_weidisp[i], &st_maxphys[i], &st_maximum[i], &st_profdisp[i], &st_peakwidth[i], &st_mode[i] ); } /*--------------------------------------------------------------------*/ /* Write the calculated arrays to disk and keep administration for */ /* header update. */ /*--------------------------------------------------------------------*/ if (optionflag[0]) { /* Write the sum of profile values */ (void) writeandupdate( st_sum, optionparam[0] ); } if (optionflag[1]) { /* Write weighted mean */ (void) writeandupdate( st_wmean, optionparam[1] ); } if (optionflag[2]) { /* Write dispersion */ (void) writeandupdate( st_weidisp, optionparam[2] ); } if (optionflag[3]) { /* Write peak in profile */ (void) writeandupdate( st_maxphys, optionparam[3] ); } if (optionflag[4]) { /* Write peak in profile */ (void) writeandupdate( st_maximum, optionparam[4] ); } if (optionflag[5]) { /* Write dispersion in profile amplitudes */ (void) writeandupdate( st_profdisp, optionparam[5] ); } if (optionflag[6]) { /* Write number of valid subsets */ (void) writeandupdate( st_peakwidth, optionparam[6] ); } if (optionflag[7]) { /* Write number of valid subsets */ (void) writeandupdate( st_mode, optionparam[7] ); } } while( FtidIN[0] != 0 ); if (optionflag[0]) { Fr1 = 0; /* Units are units of the data */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[0]], Fdataunits, &Fr1 ); } if (optionflag[1]) { Fr1 = 0; /* Operation axis units */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[1]], Faxunits, &Fr1 ); } if (optionflag[2]) { Fr1 = 0; /* Operation axis units */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[2]], Faxunits, &Fr1 ); } if (optionflag[3]) { Fr1 = 0; /* Operation axis units */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[3]], Faxunits, &Fr1 ); } if (optionflag[4]) { Fr1 = 0; /* Data units */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[4]], Fdataunits, &Fr1 ); } if (optionflag[5]) { Fr1 = 0; /* Data units */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[5]], Fdataunits, &Fr1 ); } if (optionflag[6]) { Fr1 = 0; /* No units, just numbers */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[6]], tofchar("Numbers"), &Fr1 ); } if (optionflag[7]) { Fr1 = 0; /* Operation axis units */ gdsd_wchar_c( Fsetout, tofchar("BUNIT"), &Fsubout[optionparam[7]], Faxunits, &Fr1 ); } Fremove = 1; /* Update header of new set */ (void) wminmax_c( Fsetout, Fsubout, datamin, datamax, Fnblanks, &FnsubsO, &Fremove ); { char timebuf[21]; sprintf( messbuf, "Header copied by program MOMENTS from set %.*s at %s", nelc_c(Fsetin), /* Output setname */ Fsetin.a, makedate(timebuf,20) ); /* Current date */ } Fr1 = 0; gdsd_wvar_c( Fsetout, tofchar("COMMENT"), &Fwholeset, tofchar(messbuf), &Fr1 ); finis_c(); /* Quit Hermes */ return 1; /* Dummy return for main */ }