Example #1
0
void smurf_flatfield( int *status ) {

  smfArray *bbms = NULL;     /* Bad bolometer masks */
  smfData *ffdata = NULL;   /* Pointer to output data struct */
  Grp *fgrp = NULL;         /* Filtered group, no darks */
  smfArray *flatramps = NULL;/* Flatfield ramps */
  AstKeyMap *heateffmap = NULL;    /* Heater efficiency data */
  size_t i = 0;             /* Counter, index */
  Grp *igrp = NULL;         /* Input group of files */
  Grp *ogrp = NULL;         /* Output group of files */
  size_t outsize;           /* Total number of NDF names in the output group */
  size_t size;              /* Number of files in input group */

  /* Main routine */
  ndfBegin();

  /* Get input file(s) */
  kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );

  /* Filter out darks */
  smf_find_science( NULL, igrp, &fgrp, 0, NULL, NULL, 1, 1, SMF__NULL, NULL,
                    &flatramps, &heateffmap, NULL, status );

  /* input group is now the filtered group so we can use that and
     free the old input group */
  size = grpGrpsz( fgrp, status );
  grpDelet( &igrp, status);
  igrp = fgrp;
  fgrp = NULL;

  if (size > 0) {
    /* Get output file(s) */
    kpg1Wgndf( "OUT", igrp, size, size, "More output files required...",
               &ogrp, &outsize, status );
  } else {
    msgOutif(MSG__NORM, " ","All supplied input frames were DARK,"
       " nothing to flatfield", status );
  }

  /* Get group of bolometer masks and read them into a smfArray */
  smf_request_mask( NULL, "BBM", &bbms, status );

  for (i=1; i<=size; i++ ) {
    int didflat;

    if (*status != SAI__OK) break;

    /* Call flatfield routine */
    didflat = smf_open_and_flatfield( NULL, igrp, ogrp, i, NULL, flatramps,
                                      heateffmap, &ffdata, status);

    /* Report failure by adding a message indicating which file failed */
    msgSeti("I",i);
    if (*status != SAI__OK) {
      msgSeti("N",size);
      errRep(FUNC_NAME,	"Unable to flatfield data from file ^I of ^N", status);
      break;
    }

    /* in verbose mode report whether flatfielding occurred or not */
    if (!didflat) {
      msgOutif(MSG__VERB," ",
	     "Data from file ^I are already flatfielded", status);
    } else {
      msgOutif(MSG__VERB," ", "Flat field applied to file ^I", status);
    }

    /* Mask out bad bolometers - mask data array not quality array */
    smf_apply_mask( NULL, ffdata, bbms, SMF__BBM_DATA, 0, status );

    /* Free resources for output data */
    smf_close_file( NULL, &ffdata, status );
  }

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK && ogrp ) {
    grpList( "OUTFILES", 0, 0, NULL, ogrp, status );
    if( *status == PAR__NULL ) errAnnul( status );
  }

  /* Tidy up after ourselves: release the resources used by the grp routines  */
  if (igrp) grpDelet( &igrp, status);
  if (ogrp) grpDelet( &ogrp, status);
  if (bbms) smf_close_related( NULL, &bbms, status );
  if( flatramps ) smf_close_related( NULL, &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  ndfEnd( status );
}
Example #2
0
void smurf_fts2_spectrum(int* status)
{
    if( *status != SAI__OK ) { return; }

    const char*  dataLabel    = "Spectrum";     /* Data label */
    Grp* gIn                  = NULL;           /* Input group */
    Grp* gOut                 = NULL;           /* Output group */
    Grp* gSfp                 = NULL;           /* SFP group */
    smfData* inData           = NULL;           /* Pointer to input data */
    smfData* outData          = NULL;           /* Pointer to output data */
    smfData* sfpData          = NULL;           /* Pointer to SFP data */
  /*smfData* sfp              = NULL;*/         /* Pointer to SFP index data */
    int doSFP                 = 0;              /* Only apply SFP if given */
    int zeropad               = 1;              /* Determines whether to zeropad */
    double resolution         = 0.0;            /* Spectral Resolution */
    double resolutionin       = 0.0;            /* Spectral Resolution input */
    double resolutionzp       = 0.0;            /* Spectral Resolution zero padded */
    double resolution_override= 0.0;            /* Spectral Resolution override */
    int i                     = 0;              /* Counter */
    int j                     = 0;              /* Counter */
    int k                     = 0;              /* Counter */
    int l                     = 0;              /* Counter */
    double fNyquist           = 0.0;            /* Nyquist frequency */
    double fNyquistin         = 0.0;            /* Nyquist frequency input */
    double fNyquistzp         = 0.0;            /* Nyquist frequency zero padded */
    double dSigma             = 0.0;            /* Spectral Sampling Interval */
    double dSigmain           = 0.0;            /* Spectral Sampling Interval zero padded */
    double dSigmazp           = 0.0;            /* Spectral Sampling Interval zero padded */
    double* IFG               = NULL;           /* Interferogram */
    double* SFP               = NULL;           /* Spectral Filter Profile for all pixels */
    double* SFPij             = NULL;           /* Spectral Filter Profile for a single pixel */
    double wavelen            = 0.0;            /* The central wave length of the subarray filter (m) */
    double wnSfpFirst         = 10.600;         /* Starting 850 band SFP wave number */
    double wnSfpLast          = 12.800;         /* Ending 850 band SFP wave number */
    double wnSfp850First      = 11.220;         /* Starting 850 band SFP wave number */
    double wnSfp850Last       = 12.395;         /* Ending 850 band SFP wave number */
  /*double wnSfp850First      = 10.600;*/       /* Starting 850 band SFP wave number */
  /*double wnSfp850Last       = 12.800;*/       /* Ending 850 band SFP wave number */
    double wnSfp450First      = 21.630;         /* Starting 450 band SFP wave number */
    double wnSfp450Last       = 23.105;         /* Ending 450 band SFP wave number */
    double wnSfpFirst_override= 0.0;            /* Starting SFP wave number override */
    double wnSfpLast_override = 0.0;            /* Ending SFP wave number override */
    double wnSfpResolution    = 0.025;          /* The resolution of the SFP wave numbers (1/cm) */
    double wnSfpF             = 0.0;            /* Starting SFP wave number */
    double wnSfpL             = 0.0;            /* Ending SFP wave number */
    double* WN                = NULL;           /* Wave Numbers from SFP */
    double* DS                = NULL;           /* Double Sided Interferogram */
    fftw_complex* DSIN        = NULL;           /* Double-Sided interferogram, FFT input */
    fftw_complex* SPEC        = NULL;           /* Spectrum */
    fftw_plan plan            = NULL;           /* fftw plan */
    gsl_interp_accel* ACC     = NULL;           /* SFP interpolator */
    gsl_spline* SPLINE        = NULL;           /* SFP interpolation spline */

    size_t nFiles             = 0;              /* Size of the input group */
    size_t nOutFiles          = 0;              /* Size of the output group */
    size_t nSFPFiles          = 0;              /* Size of the SFP group */
    size_t nSfp               = 89;             /* Number of SFP calibration file values */
    size_t fIndex             = 0;              /* File index */
    size_t nWidth             = 32;             /* Data cube width */
    size_t nHeight            = 40;             /* Data cube height */
    size_t nFrames            = 0;              /* Data cube depth */
    size_t nPixels            = nWidth*nHeight; /* Number of bolometers in the subarray */

    double dIntensity         = 0;
    int N                     = 0;
    int Nin                   = 0;                /* N input */
    int Nzp                   = 0;                /* N zero padded */
    int N2                    = 0;
    int N2in                  = 0;                /* N/2 input */
    int N2zp                  = 0;                /* N/2 zero padded */
    int bolIndex              = 0;
    int cubeIndex             = 0;
    int badPixel              = 0;
    int indexZPD              = 0;
    int indexZPDin            = 0;
    int indexZPDzp            = 0;
    int pad                   = 0;               /* zero padding (difference between input and zero padded interferogram length) */
    int pad2                  = 0;               /* zero padding / 2 */
    double dx                 = 0.0;             /* Delta x */
    double dxin               = 0.0;             /* Delta x input */
    double dxzp               = 0.0;             /* Delta x zero padded */
    double OPDMax             = 0.0;             /* OPD max in cm */
    double OPDMaxin           = 0.0;             /* OPD max in cm input */
    double OPDMaxzp           = 0.0;             /* OPD max in cm zero padded */
    double s                  = 0.0;             /* spectrum value */
    double f                  = 0.0;             /* filter value */

#define DEBUG 0

    /* Get Input & Output groups */
    kpg1Rgndf("IN", 0, 1, "", &gIn, &nFiles, status);
    kpg1Wgndf("OUT", gOut, nFiles, nFiles, "Equal number of input and output files expected!", &gOut, &nOutFiles, status);
    kpg1Gtgrp("SFP", &gSfp, &nSFPFiles, status);
    if(*status != SAI__OK) {
        /* TODO: Check for any other possible error conditions */
        /* Assume SFP calibration file not given, and proceed without it */
        doSFP = 0;
        *status = SAI__OK;
    } else {
	    if(nSFPFiles > 0) doSFP = 1;
    }

    /* Read in ADAM parameters */
    parGet0i("ZEROPAD", &zeropad, status);

    /* Resolution */
    parGet0d("RESOLUTION", &resolution_override, status);

    if(doSFP) {
        /* SFP WN Range overrides */
        parGet0d("WNSFPFIRST", &wnSfpFirst_override, status);
			if(*status != SAI__OK) {
				*status = SAI__OK;  /* Allow null */
				wnSfpFirst_override = 0.0;
			}
        parGet0d("WNSFPLAST", &wnSfpLast_override, status);
			if(*status != SAI__OK) {
				*status = SAI__OK;  /* Allow null */
				wnSfpLast_override = 0.0;
			}
    }

    /* BEGIN NDF */
    ndfBegin();


    /* Loop through each input file */
    for(fIndex = 1; fIndex <= nFiles; fIndex++) {
        /* Open Observation file */
        smf_open_file(NULL, gIn, fIndex, "READ", SMF__NOFIX_METADATA, &inData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to open the source file!", status);
            goto CLEANUP;
        }

        /* Data cube dimensions */
        nWidth  = inData->dims[0];
        nHeight = inData->dims[1];
        nFrames = inData->dims[2];
        nPixels = nWidth * nHeight;

        /*printf("%s: nWidth=%d, nHeight=%d, nPixels=%d, nFrames=%d\n", TASK_NAME, nWidth, nHeight, nPixels, nFrames);*/

        /* Check if the file is initialized for FTS2 processing */
        if(!(inData->fts)) {
            *status = SAI__ERROR;
            errRep( FUNC_NAME, "The file is NOT initialized for FTS2 data reduction!", status);
            goto CLEANUP;
        }

        /* Read in the Nyquist frequency from FITS component */
        smf_fits_getD(inData->hdr, "FNYQUIST", &fNyquist, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to find the Nyquist frequency in FITS component!", status);
            goto CLEANUP;
        }

        /* Read in the wave length (m) from the FITS header to determine the band */
        smf_fits_getD(inData->hdr, "WAVELEN", &wavelen, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to find the wavelen in the FITS header!", status);
            goto CLEANUP;
        }

        /* Set WN SFP range according to band */
        if(wavelen == 0.00085) {
            wnSfpFirst = wnSfp850First;
            wnSfpLast = wnSfp850Last;
        } else if(wavelen == 0.00045) {
            wnSfpFirst = wnSfp450First;
            wnSfpLast = wnSfp450Last;
        }

      /*printf("%s: wnSfpFirst_override=%f, wnSfpLast_override=%f\n", TASK_NAME, wnSfpFirst_override, wnSfpLast_override);*/
      /*printf("%s: wnSfpFirst=%f, wnSfpLast=%f\n", TASK_NAME, wnSfpFirst, wnSfpLast);*/
        if(wnSfpFirst_override) {
            wnSfpF = wnSfpFirst_override;
        } else {
            wnSfpF = wnSfpFirst;
        }
        if(wnSfpLast_override) {
            wnSfpL = wnSfpLast_override;
        } else {
            wnSfpL = wnSfpLast;
        }
      /*printf("%s: wnSfpF=%f, wnSfpL=%f\n", TASK_NAME, wnSfpF, wnSfpL);*/

        fNyquistin = fNyquistzp = 0.0;
        dx = dxin = dxzp = 0.0;
        N2 = N2in = N2zp = 0;
        indexZPD = indexZPDin = indexZPDzp = 0;
        N = Nin = Nzp = 0;
        dSigma = dSigmain = dSigmazp = 0.0;

        fNyquistin = fNyquist;
        dxin = (1/(2*fNyquistin));
        N2in = (nFrames / 2);
        indexZPDin = N2in - 1;
        Nin = 2 * N2in;
        OPDMaxin = N2in * dxin;
        if(resolution_override > 0.0) {
            resolution = resolution_override;
            resolutionin = resolution_override;
        } else {
            resolution = 1 / (2 * OPDMaxin);
            resolutionin = resolution;
        }
        dSigmain = fNyquistin / N2in;

        if(zeropad) {
            if(DEBUG) {
                /* Make the zero-padded array twice the size of the input */
                fNyquistzp = fNyquist;
                Nzp = N2in * 4;
                N2zp = Nzp / 2;
                dxzp = 1 / (2 * fNyquistzp);
                OPDMaxzp = N2zp * dxzp;
                dSigmazp = fNyquistzp / N2zp;
                resolutionzp = 1 / (2 * OPDMaxzp);
            } else {
                /* Round Nyquist frequency down to nearest integer, for calculation convenience
                fNyquistzp = floor(fNyquist);

                smf_fits_updateD(inData->hdr, "FNYQUIST", fNyquistzp, "Nyquist frequency (cm^-1)", status);*/

                /* Never change nyquist when zero padding */
                fNyquistzp = fNyquist;

                /* If resolution > 0.05, then round down to nearest 0.05 value, else set to 0.005 */
                /* Calculate resolution as 1 / (2*OPDMax) */
                /* Calculate OPDMax as N2 * dx */

                if(resolution_override) {
                    resolutionzp = resolution_override;
                } else {
                    if(resolution > 0.05) {
                        resolutionzp = floor(resolution/0.05) * 0.05;
                    } else {
                        resolutionzp = 0.005;
                    }
                }

                /* Calculate OPDMaxOut  as 1 / (2 * resolutionzp) */
                OPDMaxzp = 1 / (2 * resolutionzp);

                /* Calculate N2 */
                dxzp = (1/(2*fNyquistzp));
                N2zp = (OPDMaxzp / dxzp);
                indexZPDzp = N2zp - 1;
                Nzp = 2 * N2zp;
                dSigmazp = fNyquistzp / N2zp;
            }
        }

      /*printf("%s: Nin=%d, Nzp=%d, N2in=%d, N2zp=%d, indexZPDin=%d, indexZPDzp=%d, dSigmain=%f, dSigmazp=%f, fNyquistin=%f, fNyquistzp=%f, dxin=%f, dxzp=%f, OPDMaxin=%f, OPDMaxzp=%f, resolutionin=%f, resolutionzp=%f\n",
               TASK_NAME, Nin, Nzp, N2in, N2zp, indexZPDin, indexZPDzp, dSigmain, dSigmazp, fNyquistin, fNyquistzp, dxin, dxzp, OPDMaxin, OPDMaxzp, resolutionin, resolutionzp);*/

        if(zeropad) {
            N = Nzp;
            N2 = N2zp;
            indexZPD = indexZPDzp;
            dSigma = dSigmazp;
            fNyquist = fNyquistzp;
            dx = dxzp;
            OPDMax = OPDMaxzp;
            resolution = resolutionzp;
        } else {
            N = Nin;
            N2 = N2in;
            indexZPD = indexZPDin;
            dSigma = dSigmain;
            fNyquist = fNyquistin;
            dx = dxin;
            OPDMax = OPDMaxin;
            resolution = resolutionin;
        }

        /* Save wavenumber factor to FITS extension */
        smf_fits_updateD(inData->hdr, "WNFACT", dSigma, "Wavenumber factor cm^-1", status);

        /* TODO: Update mirror positions */
        smf_fits_updateI(inData->hdr, "MIRSTART", 0, "Frame index in which the mirror starts moving", status);
        smf_fits_updateI(inData->hdr, "MIRSTOP", N2, "Frame index in which the mirror stops moving", status);
      /*smf_fits_updateD(inData->hdr, "OPDMIN", OPD_EVEN[0], "Minimum OPD", status);
        smf_fits_updateD(inData->hdr, "OPDSTEP", dx, "OPD step size", status);*/


        /* Copy input data into output data */
        outData = smf_deepcopy_smfData(NULL, inData, 0, SMF__NOCREATE_DATA, 0, 0, status);
        outData->dtype   = SMF__DOUBLE;
        outData->ndims   = 3;
        outData->dims[0] = nWidth;
        outData->dims[1] = nHeight;
        outData->dims[2] = N2+1;
        outData->pntr[0] = (double*) astMalloc((nPixels * (N2+1)) * sizeof(double));
        if (dataLabel) { one_strlcpy(outData->hdr->dlabel, dataLabel, sizeof(outData->hdr->dlabel), status ); }

        /* Allocate memory for arrays */
        IFG  = astCalloc(N,  sizeof(*IFG));
        DS   = astCalloc(N, sizeof(*DS));
        DSIN = fftw_malloc(N * sizeof(*DSIN));
        SPEC = fftw_malloc(N * sizeof(*SPEC));

        /* Initialize arrays */
        for(k = 0; k < N; k++) { SPEC[k][0] = SPEC[k][1] = DSIN[k][0] = DSIN[k][1] = DS[k] = IFG[k] = 0.0; }

        /* Open the SFP calibration file, if given */
        if(doSFP) {
            smf_open_file(NULL, gSfp, 1, "READ", SMF__NOCREATE_QUALITY, &sfpData, status);
            if(*status != SAI__OK) {
                *status = SAI__ERROR;
                errRep(FUNC_NAME, "Unable to open the SFP calibration file!", status);
                goto CLEANUP;
            }

            /* Read in the number of data elements */
            nSfp = sfpData->dims[1] / nPixels;
            /* Allocate memory for arrays */
            SFP = astCalloc(nSfp*nPixels, sizeof(*SFP));
            SFPij = astCalloc(nSfp, sizeof(*SFP));
            WN  = astCalloc(nSfp, sizeof(*WN));

            /* DEBUG: Dispay SFP data */
          /*printf("smurf_fts2_spectrum ([%d,%d,%d] elements): WN, SFP\n", (int)sfpData->dims[0],(int)sfpData->dims[1],(int)sfpData->dims[2]);*/
            for(k=0;k<nSfp;k++){
                /* printf("WN:%.3f,SFP:%.10f\n", *((double*) (sfpData->pntr[0]) + i), *((double*) (sfpData->pntr[0]) + i+1)); */
                /* Adjust starting and ending wave number ranges for 450 or 850 bands */
                if(wavelen == 0.00085 || wavelen == 0.00045) {
                    WN[k] = wnSfpFirst + k * wnSfpResolution;
                } else {
                    *status = SAI__ERROR;
                    errRep(FUNC_NAME, "Unexpected WAVELEN value found in the FITS header!", status);
                    goto CLEANUP;
                }
              /*printf("SFP WN[%d]=%f\n",k,WN[k]);*/
                for(j=0;j<nHeight;j++) {
                    for(i=0;i<nWidth;i++) {
                        bolIndex = i + j * nWidth;
                        cubeIndex = bolIndex + k * nPixels;
                        SFP[cubeIndex] = *((double*) (sfpData->pntr[0]) + cubeIndex);
                      /*if(i==10 && j==20) printf("SFP i:%d,j:%d,k:%d,bolIndex:%d,cubeIndex:%d=%f\n",i,j,k,bolIndex,cubeIndex,SFP[cubeIndex]);*/
                    }
                }
            }

            /*printf("smurf_fts2_spectrum DEBUG: early exiting!\n");
              exit(0); */

            /* Create a 2D SFP index array and store it in the file, if given
            sfp = smf_create_smfData(SMF__NOCREATE_DA | SMF__NOCREATE_FTS, status);
            sfp->dtype   = SMF__INTEGER;
            sfp->ndims   = 2;
            sfp->dims[0] = nSfp;
            sfp->dims[1] = 2;
            sfp->pntr[0] = (int*) astCalloc(nSfp*2,  sizeof(double));
            // By default set ZPD indices to a bad value
            for(i = 0; i < nSfp; i++) {
                for(j = 0; j < 2; j++) {
                    bolIndex = i + j * 2;
                    *((int*) (sfp->pntr[0]) + bolIndex) = VAL__BADI;
                }
            } */

            /* Prepare GSL interpolator to convert SFP data to this spectrum's resolution */
            ACC    = gsl_interp_accel_alloc();
            SPLINE = gsl_spline_alloc(gsl_interp_cspline, nSfp);
        }

        for(i = 0; i < nWidth; i++) {
            for(j = 0; j < nHeight; j++) {
                bolIndex = i + j * nWidth;

                badPixel = 0;
                for(k = 0; k < Nin; k++) {
                    dIntensity = *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                    if(dIntensity == VAL__BADD) {
                        badPixel = 1;
                        break;
                    }
                }
                /* If this is a bad pixel, go to next */
                if(badPixel) {
                    for(k = 0; k <= N2in; k++) {
                        *((double*)(outData->pntr[0]) + (bolIndex + k * nPixels)) = VAL__BADD;
                    }
                    continue;
                }

                /* Double-Sided interferogram */
                if(zeropad) {
                    pad = Nzp - Nin;
                    pad2 = pad / 2;
                    /* Copy the right half of the input into the left half of this IFG, zero padded in the middle */
                    for(k=indexZPDin; k<Nin; k++) {
                        /*printf("%s: IFG: indexZPDin=%d, indexZPDzp=%d, Nin=%d, Nzp=%d, k=%d, l=%d\n", TASK_NAME, indexZPDin, indexZPDzp, Nin, Nzp, k, l);*/
                        IFG[k - indexZPDin] = *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                            printf("%s: Pixel[%d,%d]: (L<-R) IFG[k(%d)-indexZPDin(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %g\n",
                                   TASK_NAME, i, j, k, indexZPDin, (k - indexZPDin), bolIndex, k, nPixels, (bolIndex + k * nPixels), IFG[k - indexZPDin]);
                        }*/
                    }
                    /* Copy the left half of the input into the right half of this IFG, zero padded in the middle */
                    for(k=0,l=0; k<indexZPDin; k++) {
                        IFG[Nzp - indexZPDin + k] =  *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                            printf("%s: Pixel[%d,%d]: (L->R) IFG[Nzp(%d)-indexZPDin(%d)+k(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %g\n",
                                   TASK_NAME, i, j, Nzp, indexZPDin, k, (Nzp-indexZPDin+k), bolIndex, k, nPixels, (bolIndex+k*nPixels), IFG[Nzp-indexZPDin+k]);
                        }*/
                    }
                } else {
                    /* Copy the right half of the input into the left half of this IFG */
                    for(k=indexZPD; k<N; k++) {
                        IFG[k - indexZPD] = *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                            printf("%s: Pixel[%d,%d]: (L<-R) IFG[k(%d)-indexZPD(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %f\n",
                                     TASK_NAME, i, j, k, indexZPD, (k - indexZPD), bolIndex, k, nPixels, (bolIndex + k * nPixels), IFG[k - indexZPD]);
                        }*/
                    }
                    /* Copy the left half of the input into the right half of this IFG */
                    for(k=0; k<indexZPD; k++) {
                        IFG[N - indexZPD + k] =  *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                              printf("%s: Pixel[%d,%d]: (L->R) IFG[N(%d)-indexZPD(%d)+k(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %f\n",
                                     TASK_NAME, i, j, N, indexZPD, k, (N - indexZPD + k), bolIndex, k, nPixels, (bolIndex + k * nPixels), IFG[N - indexZPD + k]);
                        }*/
                    }
                }

                /* DEBUG: Write out input data
                for(k = 0; k < Nin; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + nPixels * k)) =
                    *((double*)( inData->pntr[0]) + (bolIndex + nPixels * k));
                    if(i==16 && j==25) {
                        printf("%s: inData[%d,%d,%d]=%g\n",TASK_NAME, i, j, k, *((double*)( inData->pntr[0]) + (bolIndex + nPixels * k)));
                    }
                } */

                /* DEBUG: Write out the shifted IFG
                for(k = 0; k < N; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + k* nPixels)) = IFG[k];
                    if(i==16 && j==25) {
                        printf("%s: IFG[%d,%d,%d]=%g\n",TASK_NAME, i, j, k, IFG[k]);
                    }
                } */

                /* Convert real-valued interferogram to complex-valued interferogram */
                for(k = 0; k < N; k++) { DSIN[k][0] = IFG[k]; DSIN[k][1] = 0.0; }

                /* DEBUG: Write out DSIN
                for(k = 0; k < N; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + k * nPixels)) = DSIN[k][0];
                    if(i==16 && j==25) {
                        printf("%s: DSIN[%d,%d,%d]=%g\n",TASK_NAME, i, j, k, DSIN[k][0]);
                    }
                } */

                /* FFT Double-sided complex-valued interferogram */
                plan = fftw_plan_dft_1d(N, DSIN, SPEC, FFTW_FORWARD, FFTW_ESTIMATE);
                fftw_execute(plan);

                /* Normalize spectrum */
                for(k=0;k<N;k++) { SPEC[k][0] = SPEC[k][0] / (double)(N * resolution); }

                /* Apply SFP calibration, if given */
                if(doSFP){
                    /* Get the SFP for this pixel */
                    for(k=0;k<nSfp;k++) { SFPij[k] = SFP[i + j*nWidth + k*nPixels]; }
                    /* Interpolate the SFP values from its original WN scale to the current spectrum scale */
                    gsl_spline_init(SPLINE, WN, SFPij, nSfp);

                    /* Divide the spectrum in the band pass region by the interpolated SFP value at each position */
                    for(k = 0; k < N; k++) {
                      /*if(k*dSigma >= WN[0] && k*dSigma <= WN[nSfp-1]) {*/
                        if(k*dSigma >= wnSfpF && k*dSigma <= wnSfpL) {
                            f = gsl_spline_eval(SPLINE, k*dSigma, ACC);
                            /*index = bolIndex + nPixels * k;*/
                            s = SPEC[k][0];
                            SPEC[k][0] = s / f;
                          /*if(i==10 && j==20) { printf("SFP i=%d, j=%d, k=%d, dSigma=%f, k*dSigma=%f, s=%f, f=%f, s/f=%f, \n", i, j, k, dSigma, k*dSigma, s, f, s/f); }*/
                        }
                    }
                }

                /* Write out the positive real component of the spectrum */
                for(k = 0; k <= N2; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + k * nPixels)) = SPEC[k][0];
                  /*if(i==16 && j==25) {
                        printf("%s: SPEC[%d,%d,%d]=%E\n",TASK_NAME, i, j, k, SPEC[k][0] / (double)(N * resolution));
                    }*/
                }

                /* Destroy each allocated plan */
                if(plan) { fftw_destroy_plan(plan); }
            }
        }

        /* Deallocate memory used by arrays */
        if(IFG)  { IFG = astFree(IFG); }
        if(DS)   { DS = astFree(DS); }
        if(SFP)  { SFP = astFree(SFP); }
        if(SFPij)  { SFPij = astFree(SFPij); }
        if(WN)   { WN = astFree(WN); }
        if(DSIN) { fftw_free(DSIN); DSIN = NULL; }
        if(SPEC) { fftw_free(SPEC); SPEC = NULL; }
        if(ACC)     { gsl_interp_accel_free(ACC);   ACC     = NULL; }
        if(SPLINE)  { gsl_spline_free(SPLINE);      SPLINE  = NULL; }

        /* Close the file */
        if(inData) {
            smf_close_file( NULL,&inData, status);
            if(*status != SAI__OK) {
                *status = SAI__ERROR;
                errRep(FUNC_NAME, "Unable to close the input file!", status);
                goto CLEANUP;
            }
        }

        /* Write output */
        /* outData->fts = smf_construct_smfFts(NULL, sfp, fpm, sigma, status);   // TODO: Add interpolated SFP to FITS header */
        smf_write_smfData(NULL, outData, NULL, NULL, gOut, fIndex, 0,
                          MSG__VERB, 0, NULL, NULL, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to write the output file!", status);
            goto CLEANUP;
        }
        smf_close_file( NULL,&outData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to close the output file!", status);
            goto CLEANUP;
        }
    }

CLEANUP:
    if(IFG)  { IFG = astFree(IFG); }
    if(DS)   { DS = astFree(DS); }
    if(SFP)  { SFP = astFree(SFP); }
    if(SFPij)  { SFPij = astFree(SFPij); }
    if(WN)   { WN = astFree(WN); }
    if(DSIN) { fftw_free(DSIN); DSIN = NULL; }
    if(SPEC) { fftw_free(SPEC); SPEC = NULL; }
    if(ACC)     { gsl_interp_accel_free(ACC);   ACC     = NULL; }
    if(SPLINE)  { gsl_spline_free(SPLINE);      SPLINE  = NULL; }

    /* Close files if still open */
    if(inData) {
        smf_close_file( NULL,&inData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "CLEANUP: Unable to close the input file!", status);
        }
    }
    if(outData) {
        smf_close_file( NULL,&outData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "CLEANUP: Unable to close the output file!", status);
        }
    }
    if(sfpData) {
        smf_close_file( NULL,&sfpData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "CLEANUP: Unable to close the SFP file!", status);
        }
    }

    /* END NDF */
    ndfEnd(status);

    /* Delete Groups */
    if(gIn) grpDelet(&gIn, status);
    if(gOut) grpDelet(&gOut, status);
    if(gSfp) grpDelet(&gSfp, status);
}
Example #3
0
void smurf_unmakemap( int *status ) {

/* Local Variables */
   AstFrameSet *wcsin = NULL; /* WCS Frameset for input cube */
   AstMapping *skymap;        /* GRID->SkyFrame Mapping from input WCS */
   AstSkyFrame *abskyfrm;     /* Input SkyFrame (always absolute) */
   AstSkyFrame *skyfrm = NULL;/* SkyFrame from the input WCS Frameset */
   Grp *igrp1 = NULL;         /* Group of input sky files */
   Grp *igrp2 = NULL;         /* Group of input template files */
   Grp *igrpq = NULL;         /* Group of input Q  sky files */
   Grp *igrpu = NULL;         /* Group of input U sky files */
   Grp *ogrp = NULL;          /* Group containing output file */
   ThrWorkForce *wf = NULL;   /* Pointer to a pool of worker threads */
   char pabuf[ 10 ];          /* Text buffer for parameter value */
   dim_t iel;                 /* Index of next element */
   dim_t ndata;               /* Number of elements in array */
   dim_t ntslice;             /* Number of time slices in array */
   double *ang_data = NULL;   /* Pointer to the FP orientation angles */
   double *in_data = NULL;    /* Pointer to the input I sky map */
   double *inq_data = NULL;   /* Pointer to the input Q sky map */
   double *inu_data = NULL;   /* Pointer to the input U sky map */
   double *outq_data = NULL;  /* Pointer to the Q time series data */
   double *outu_data = NULL;  /* Pointer to the U time series data */
   double *pd;                /* Pointer to next element */
   double *pq = NULL;         /* Pointer to next Q time series value */
   double *pu = NULL;         /* Pointer to next U time series value */
   double angrot;             /* Angle from focal plane X axis to fixed analyser */
   double paoff;              /* WPLATE value corresponding to POL_ANG=0.0 */
   double params[ 4 ];        /* astResample parameters */
   double sigma;              /* Standard deviation of noise to add to output */
   int alignsys;              /* Align data in the map's system? */
   int flag;                  /* Was the group expression flagged? */
   int harmonic;              /* The requested harmonic */
   int ifile;                 /* Input file index */
   int indf;                  /* Input sky map NDF identifier */
   int indfin;                /* Input template cube NDF identifier */
   int indfout;               /* Output cube NDF identifier */
   int indfq;                 /* Input Q map NDF identifier */
   int indfu;                 /* Input U map NDF identifier */
   int interp = 0;            /* Pixel interpolation method */
   int moving;                /* Is the telescope base position changing? */
   int nel;                   /* Number of elements in array */
   int nelqu;                 /* Number of elements in Q or U array */
   int ngood;                 /* No. of good values in putput cube */
   int nparam = 0;            /* No. of parameters required for interpolation scheme */
   int pasign;                /* Indicates sense of POL_ANG value */
   int sdim[ 2 ];             /* Array of significant pixel axes */
   int slbnd[ 2 ];            /* Array of lower bounds of input map */
   int subnd[ 2 ];            /* Array of upper bounds of input map */
   size_t nskymap;            /* Number of supplied sky cubes */
   size_t outsize;            /* Number of files in output group */
   size_t size;               /* Number of files in input group */
   smfData *odata = NULL;     /* Pointer to output data struct */

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST context */
   astBegin;

/* Begin an NDF context. */
   ndfBegin();

/* Find the number of cores/processors available and create a pool of
   threads of the same size. */
   wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status );

/* Get an identifier for the input NDF. We use NDG (via kpg1Rgndf)
   instead of calling ndfAssoc directly since NDF/HDS has problems with
   file names containing spaces, which NDG does not have. */
   kpg1Rgndf( "IN", 1, 1, "", &igrp1, &nskymap, status );
   ndgNdfas( igrp1, 1, "READ", &indf, status );

/* Map the data array in the input sky map. */
   ndfMap( indf, "DATA", "_DOUBLE", "READ", (void **) &in_data, &nel,
           status );

/* Get the WCS FrameSet from the sky map, together with its pixel index
   bounds. */
   kpg1Asget( indf, 2, 0, 1, 1, sdim, slbnd, subnd, &wcsin, status );

/* Check the current Frame is a SKY frame. */
   skyfrm = astGetFrame( wcsin, AST__CURRENT );
   if( !astIsASkyFrame( skyfrm ) && *status == SAI__OK ) {
      ndfMsg( "N", indf );
      *status = SAI__ERROR;
      errRep( " ", " Current Frame in ^N is not a SKY Frame.", status );
   }

/* Get a copy of the current frame that represents absolute coords rather
   than offsets. We assume the target is moving if the map represents
   offsets. */
   moving = ( *status == SAI__OK &&
              !strcmp( astGetC( skyfrm, "SkyRefIs" ), "Origin" ) ) ? 1 : 0;
   abskyfrm = astCopy( skyfrm );
   astClear( abskyfrm, "SkyRefIs" );

/* If the ALIGNSYS parameter is TRUE then we align the raw data with the
   map in the current system of the map, rather than the default ICRS. */
   parGet0l( "ALIGNSYS", &alignsys, status );
   if( alignsys ) astSetC( abskyfrm, "AlignSystem", astGetC( abskyfrm,
                                                             "System" ) );

/* Get the Mapping from the Sky Frame to grid axis in the iput map. */
   skymap = astGetMapping( wcsin, AST__CURRENT, AST__BASE );

/* Get the pixel interpolation scheme to use. */
   parChoic( "INTERP", "NEAREST", "NEAREST,LINEAR,SINC,"
             "SINCSINC,SINCCOS,SINCGAUSS,SOMB,SOMBCOS",
             1, pabuf, 10, status );

   if( !strcmp( pabuf, "NEAREST" ) ) {
      interp = AST__NEAREST;
      nparam = 0;

   } else if( !strcmp( pabuf, "LINEAR" ) ) {
      interp = AST__LINEAR;
      nparam = 0;

   } else if( !strcmp( pabuf, "SINC" ) ) {
      interp = AST__SINC;
      nparam = 1;

   } else if( !strcmp( pabuf, "SINCSINC" ) ) {
      interp = AST__SINCSINC;
      nparam = 2;

   } else if( !strcmp( pabuf, "SINCCOS" ) ) {
      interp = AST__SINCCOS;
      nparam = 2;

   } else if( !strcmp( pabuf, "SINCGAUSS" ) ) {
      interp = AST__SINCGAUSS;
      nparam = 2;

   } else if( !strcmp( pabuf, "SOMB" ) ) {
      interp = AST__SOMB;
      nparam = 1;

   } else if( !strcmp( pabuf, "SOMBCOS" ) ) {
      interp = AST__SOMBCOS;
      nparam = 2;

   } else if( *status == SAI__OK ) {
      nparam = 0;
      *status = SAI__ERROR;
      msgSetc( "V", pabuf );
      errRep( "", "Support not available for INTERP = ^V (programming "
              "error)", status );
   }

/* Get an additional parameter vector if required. */
   if( nparam > 0 ) parExacd( "PARAMS", nparam, params, status );

/* Get a group of reference time series files to use as templates for
   the output time series files.*/
   ndgAssoc( "REF", 1, &igrp2, &size, &flag, status );

/* Get output file(s) */
   kpg1Wgndf( "OUT", igrp2, size, size, "More output files required...",
              &ogrp, &outsize, status );

/* Get he noise level to add to the output data. */
   parGet0d( "SIGMA", &sigma, status );

/* Get any Q and U input maps. */
   if( *status == SAI__OK ) {

      kpg1Rgndf( "QIN", 1, 1, "", &igrpq, &nskymap, status );
      ndgNdfas( igrpq, 1, "READ", &indfq, status );
      ndfMap( indfq, "DATA", "_DOUBLE", "READ", (void **) &inq_data, &nelqu,
              status );
      if( nelqu != nel && *status == SAI__OK ) {
         ndfMsg( "Q", indfq );
         *status = SAI__ERROR;
         errRep( "", "Q image '^Q' is not the same size as the I image.",
                 status );
      }

      kpg1Rgndf( "UIN", 1, 1, "", &igrpu, &nskymap, status );
      ndgNdfas( igrpu, 1, "READ", &indfu, status );
      ndfMap( indfu, "DATA", "_DOUBLE", "READ", (void **) &inu_data, &nelqu,
              status );
      if( nelqu != nel && *status == SAI__OK ) {
         ndfMsg( "U", indfu );
         *status = SAI__ERROR;
         errRep( "", "U image '^U' is not the same size as the I image.",
                 status );
      }

      if( *status == PAR__NULL ) {
         ndfAnnul( &indfq, status );
         ndfAnnul( &indfu, status );
         inq_data = NULL;
         inu_data = NULL;
         errAnnul( status );
      } else {
         parGet0d( "ANGROT", &angrot, status );
         parGet0d( "PAOFF", &paoff, status );
         parGet0l( "PASIGN", &pasign, status );
      }
   }

/* Loop round all the template time series files. */
   for( ifile = 1; ifile <= (int) size && *status == SAI__OK; ifile++ ) {

/* Start a new NDF context. */
      ndfBegin();

/* Create the output NDF by propagating everything from the input, except
   for quality and variance. */
      ndgNdfas( igrp2, ifile, "READ", &indfin, status );

      ndfMsg( "FILE", indfin );
      msgSeti( "THISFILE", ifile );
      msgSeti( "NUMFILES", size );
      msgOutif( MSG__NORM, " ", "Simulating ^THISFILE/^NUMFILES ^FILE",
                status );

      ndgNdfpr( indfin, "DATA,HISTORY,LABEL,TITLE,WCS,UNITS,EXTENSION(*)",
                ogrp, ifile, &indfout, status );
      ndfAnnul( &indfin, status );
      ndfAnnul( &indfout, status );

/* We now re-open the output NDF and then modify its data values. */
      smf_open_file( wf, ogrp, ifile, "UPDATE", 0, &odata, status );

/* Issue a suitable message and abort if anything went wrong. */
      if( *status != SAI__OK ) {
         errRep( FUNC_NAME, "Could not open input template file.", status );
         break;

      } else {
         if( odata->file == NULL ) {
            *status = SAI__ERROR;
            errRep( FUNC_NAME, "No smfFile associated with smfData.",
                    status );
            break;

         } else if( odata->hdr == NULL ) {
            *status = SAI__ERROR;
            errRep( FUNC_NAME, "No smfHead associated with smfData.",
                    status );
            break;
         }
      }

/* Check the reference time series contains double precision values. */
     smf_dtype_check_fatal( odata, NULL, SMF__DOUBLE, status );

/* Get the total number of data elements, and the number of time slices. */
     smf_get_dims( odata, NULL, NULL, NULL, &ntslice, &ndata, NULL,
                   NULL, status );

/* Fill the output with bad values. */
      if( *status == SAI__OK ) {
         pd = odata->pntr[ 0 ];
         for( iel = 0; iel < ndata; iel++ ) *(pd++) = VAL__BADD;
      }

/* Resample the sky map data into the output time series. */
      smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd,
                     interp, params, sigma, in_data, odata->pntr[ 0 ],
                     NULL, &ngood, status );

/* Issue a wrning if there is no good data in the output cube. */
      if( ngood == 0 ) msgOutif( MSG__NORM, " ", "   Output contains no "
                                 "good data values.", status );

/* If Q and U maps have been given, allocate room to hold resampled Q and
   U values, and fill them with bad values. */
      if( inq_data && inu_data ) {
         pq = outq_data = astMalloc( ndata*sizeof( *outq_data ) );
         pu = outu_data = astMalloc( ndata*sizeof( *outu_data ) );
         if( *status == SAI__OK ) {
            for( iel = 0; iel < ndata; iel++ ) {
               *(pu++) = VAL__BADD;
               *(pq++) = VAL__BADD;
            }
         }

/* Determine the harmonic to use. */
         parGet0i( "HARMONIC", &harmonic, status );

/* Allocate room for an array to hold the anti-clockwise angle from the
   focal plane Y axis to the Y pixel axis in the reference map, at each
   time slice. */
         ang_data = astMalloc( ntslice*sizeof( *ang_data ) );

/* Resample them both into 3D time series. */
         smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd,
                        interp, params, sigma, inq_data, outq_data,
                        ang_data, &ngood, status );
         smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd,
                        interp, params, sigma, inu_data, outu_data,
                        NULL, &ngood, status );

/* Combine these time series with the main output time series so that the
   main output is analysed intensity. */
         smf_uncalc_iqu( wf, odata, odata->pntr[ 0 ], outq_data, outu_data,
                         ang_data, pasign, AST__DD2R*paoff, AST__DD2R*angrot,
                         harmonic, status );

/* Release work space. */
         outq_data = astFree( outq_data );
         outu_data = astFree( outu_data );
         ang_data = astFree( ang_data );
      }

/* Close the output time series file. */
      smf_close_file( wf, &odata, status );

/* End the NDF context. */
      ndfEnd( status );
   }

/* Close any input data file that is still open due to an early exit from
   the above loop. */
   if( odata != NULL ) {
      smf_close_file( wf, &odata, status );
      odata = NULL;
   }

/* Free remaining resources. */
   if( igrp1 != NULL) grpDelet( &igrp1, status);
   if( igrp2 != NULL) grpDelet( &igrp2, status);
   if( igrpq != NULL) grpDelet( &igrpq, status);
   if( igrpu != NULL) grpDelet( &igrpu, status);
   if( ogrp != NULL) grpDelet( &ogrp, status);

/* End the NDF context. */
   ndfEnd( status );

/* End the tile's AST context. */
   astEnd;

/* Issue a status indication.*/
   if( *status == SAI__OK ) {
      msgOutif(MSG__VERB," ",TASK_NAME " succeeded, time series written.", status);
   } else {
      msgOutif(MSG__VERB," ",TASK_NAME " failed.", status);
   }
}
Example #4
0
/* Main entry */
void smurf_jsadicer( int *status ) {

/* Local Variables */
   AstFitsChan *fc;
   Grp *igrp = NULL;
   Grp *ogrp = NULL;
   char *pname;
   char basename[ 255 ];
   int indf;
   int trim;
   size_t ntile;
   size_t size;
   smfJSATiling tiling;

/* Check inherited status */
   if (*status != SAI__OK) return;

/* Begin AST and NDF contexts. */
   astBegin;
   ndfBegin();

/* Get the name of the input NDF. */
   kpg1Rgndf( "IN", 1, 1, "", &igrp, &size, status );
   ndgNdfas( igrp, 1, "READ", &indf, status );

/* Get the base name for the output NDFs. */
   if( *status == SAI__OK ) {
      parGet0c( "OUT", basename, sizeof(basename), status );
      if( *status == PAR__NULL ) {
         errAnnul( status );
         pname = basename;
         grpGet( igrp, 1, 1, &pname, sizeof(basename), status );
      }
   }

/* See how the output NDFs are to be trimmed. */
   parGet0i( "TRIM", &trim, status );

/* Get a FitsChan holding the contents of the FITS extension from the
   input NDF. Annul the error if the NDF has no FITS extension. */
   if( *status == SAI__OK ) {
      kpgGtfts( indf, &fc, status );
      if( *status == KPG__NOFTS ) {
         errAnnul( status );
         fc = NULL;
      }
   }

/* Select a JSA instrument and get the parameters defining the layout of
   tiles for the selected instrument. */
   smf_jsainstrument( "INSTRUMENT", fc, SMF__INST_NONE, &tiling,
                      status );

/* Create a new group to hold the names of the output NDFs that have been
   created. This group does not include any NDFs that correspond to tiles
   that contain no input data. */
   ogrp = grpNew( "", status );

/* Dice the map into output NDFs. */
   smf_jsadicer( indf, basename, trim, tiling.instrument, &ntile,
                 ogrp, status );

/* Write out the list of output NDF names, annulling the error if a null
   parameter value is supplied. */
   if( *status == SAI__OK && ogrp ) {
      grpList( "OUTFILES", 0, 0, NULL, ogrp, status );
      if( *status == PAR__NULL ) errAnnul( status );
   }

/* Write the number of tiles being created to an output parameter. */
   parPut0i( "NTILE", ntile, status );

/* Free resources. */
   grpDelet( &igrp, status );
   grpDelet( &ogrp, status );

/* End the NDF and AST context. */
   ndfEnd( status );
   astEnd;

/* If anything went wrong issue a context message. */
   if( *status != SAI__OK ) msgOutif( MSG__VERB, " ", "JSADICER failed.",
                                      status );
}
Example #5
0
void smurf_sc2filtermap( int *status ) {

  Grp *fgrp = NULL;         /* Output filter group */
  smfFilter *filt=NULL;     /* Filter */
  double filt_edgehigh=0;   /* High-pass filter */
  double filt_edgelow=0;    /* Low-pass filter */
  size_t fsize;             /* Number of files in fgrp */
  size_t i;                 /* Loop (grp) counter */
  smfData *idata;           /* Pointer to input smfData */
  Grp *igrp = NULL;         /* Input group of files */
  int isfft=0;              /* Are data fft or real space? */
  int *mask=NULL;           /* Mask indicating where bad data are */
  size_t ndata=0;           /* Number of pixels in the map */
  size_t ndims;             /* Number of real space dimensions */
  smfData *odata=NULL;      /* Pointer to output smfData to be exported */
  Grp *ogrp = NULL;         /* Output group of files */
  size_t outsize;           /* Number of files in output group */
  size_t size;              /* Number of files in input group */
  ThrWorkForce *wf = NULL;  /* Pointer to a pool of worker threads */
  smfData *wrefmap=NULL;    /* Whitening reference map */
  int whiten;               /* Applying whitening filter? */
  Grp *wgrp = NULL;         /* Whitening reference map group */
  size_t wsize;             /* Size of wgrp */
  int zerobad;              /* Zero VAL__BADD before taking FFT? */

  /* Main routine */
  ndfBegin();

  /* Find the number of cores/processors available and create a pool of
     threads of the same size. */
  wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status );

  /* Get input file(s) */
  kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );
  size = grpGrpsz( igrp, status );

  if (size > 0) {
    int parstate=0;           /* ADAM parameter state */

    /* Get output file(s) */
    kpg1Wgndf( "OUT", igrp, size, size, "More output files required...",
               &ogrp, &outsize, status );

    /* Write out the filter? */
    parState( "OUTFILTER", &parstate, status );
    if( parstate != PAR__GROUND ) {
      kpg1Wgndf( "OUTFILTER", igrp, size, size,
                 "More output filter files required...",
                 &fgrp, &fsize, status );
    }

  }

  /* Are we going to zero bad values first? */
  parGet0l( "ZEROBAD", &zerobad, status );

  /* High/low-pass filters? */
  parGet0d( "FILT_EDGEHIGH", &filt_edgehigh, status );
  parGet0d( "FILT_EDGELOW", &filt_edgelow, status );

  /* Are we applying a spatial whitening filter? */
  parGet0l( "WHITEN", &whiten, status );

  if( whiten ) {
    /* We also need the reference map to measure the whitening filter. We
       make a deep copy of it so that we can set bad values to 0 etc. */

    smfData *tempdata=NULL;

    kpg1Rgndf( "whiterefmap", 0, 1, "", &wgrp, &wsize, status );
    if( (*status == SAI__OK) && (wsize != 1) ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": WHITEREFMAP must be a single reference map",
              status );
    }

    smf_open_file( wgrp, 1, "READ", SMF__NOTTSERIES, &tempdata, status );
    wrefmap = smf_deepcopy_smfData( tempdata, 0, 0, 0, 0, status );
    smf_close_file( &tempdata, status );

    /* Set VAL__BADD to zero if requested */
    if( (*status==SAI__OK) && zerobad ) {
      double *d=NULL;
      size_t j;

      ndata=1;
      for( j=0; j<wrefmap->ndims; j++ ) ndata *= wrefmap->dims[j];

      d = wrefmap->pntr[0];

      if( d ) {
        for( j=0; j<ndata; j++ ) {
          if( d[j] == VAL__BADD ) {
            d[j] = 0;
          }
        }
      }
    }

  }

  for( i=1;(*status==SAI__OK)&&i<=size; i++ ) {
    smf_open_file( igrp, i, "READ", SMF__NOTTSERIES, &idata, status );
    isfft = smf_isfft( idata, NULL, NULL, NULL, NULL, &ndims, status);

    if( (*status==SAI__OK) && isfft ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": Input data are FFT, not real-space!\n",
              status );
      break;
    }

    if( (*status==SAI__OK) && (ndims != 2) ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": Input data not a 2D map!\n",
              status );
      break;
    }

    /* smf_filter_execute operates in-place, so first create the output
       data as a copy of the input */

    odata = smf_deepcopy_smfData( idata, 0, 0, 0, 0, status );

    /* Set VAL__BADD to zero if requested */
    if( (*status==SAI__OK) && zerobad ) {
      double *d=NULL;
      size_t j, k;

      ndata=1;
      for( j=0; j<odata->ndims; j++ ) ndata *= odata->dims[j];

      mask = astCalloc( ndata, sizeof(*mask) );

      /* Do both DATA and VARIANCE */
      if( *status == SAI__OK ) {
        for( k=0; k<2; k++ ) {
          d = odata->pntr[k];

          if( d ) {
            for( j=0; j<ndata; j++ ) {
              if( d[j] == VAL__BADD ) {
                d[j] = 0;
                mask[j] = 1;
              }
            }
          }
        }
      }

    }

    /* Measure and apply the whitening filter. We need to do this
       every time because the dimensions of filt need to match idata
       (not the wrefmap) and they might be different each time. We
       could try to be more clever in the future if this is too slow. */

    filt = smf_create_smfFilter( idata, status );
    /* Set to the identity in case no whitening is applied */
    msgOut( "", TASK_NAME ": initializing filter", status );
    smf_filter_ident( filt, 0, status );

    if( whiten ) {
      msgOut( "", TASK_NAME ": whitening the filter", status );
      smf_filter2d_whiten( wf, filt, wrefmap, 0, 0, 3, status );
    }

    if( filt_edgelow ) {
      msgOutf( "", TASK_NAME ": applying low-pass at < %lg 1/arcsec", status,
               filt_edgelow );
      smf_filter2d_edge( filt, filt_edgelow, 1, status );
    }

    if( filt_edgehigh ) {
      msgOutf( "", TASK_NAME ": applying high-pass at >= %lg 1/arcsec", status,
               filt_edgehigh );
      smf_filter2d_edge( filt, filt_edgehigh, 0, status );
    }

    smf_filter_execute( wf, odata, filt, 0, 0, status );

    /* Set bad values from the mask */
    if( mask ) {
      double *d=NULL;
      size_t j, k;

      /* Do both DATA and VARIANCE */
      for( k=0; k<2; k++ ) {
        d = odata->pntr[k];

        if( d ) {
          for( j=0; j<ndata; j++ ) {
            if( mask[j] ) {
              d[j] = VAL__BADD;
            }
          }
        }
      }
    }

    /* Export the data to a new file */
    smf_write_smfData( odata, NULL, NULL, ogrp, i, 0, MSG__NORM, status );

    /* Write out filters? */
    if( fgrp ) smf_write_smfFilter( filt, NULL, fgrp, i, status );
    if( filt ) smf_free_smfFilter( filt, status );

  }

  /* Tidy up after ourselves */

  if( fgrp ) grpDelet( &fgrp, status);
  if( igrp ) grpDelet( &igrp, status);
  if( ogrp ) grpDelet( &ogrp, status);
  if( wgrp ) grpDelet( &wgrp, status );

  if( odata ) smf_close_file( &odata, status );
  if( wrefmap ) smf_close_file( &wrefmap, status );

  if( mask ) mask = astFree( mask );

  ndfEnd( status );

  /* Ensure that FFTW doesn't have any used memory kicking around */
  fftw_cleanup();
}
Example #6
0
void clumpinfo( int *status ) {
    /*
    *+
    *  Name:
    *     CLUMPINFO

    *  Purpose:
    *     Obtain information about one or more previously identified clumps.

    *  Language:
    *     C

    *  Type of Module:
    *     ADAM A-task

    *  Description:
    *     This application returns various items of information about a
    *     single clump, or a collection of clumps, previously identified
    *     using FINDCLUMPS or EXTRACTCLUMPS.

    *  Usage:
    *     clumpinfo ndf clumps quiet

    *  ADAM Parameters:
    *     CLUMPS = LITERAL (Read)
    *        Specifies the indices of the clumps to be included in the
    *        returned information. It can take any of the following values:
    *
    *        - "ALL" or "*" --  All clumps.
    *
    *        - "xx,yy,zz" -- A list of clump indices.
    *
    *        - "xx:yy" --  Clump indices between xx and yy inclusively.  When
    *        xx is omitted the range begins from one; when yy is omitted the
    *        range ends with the final clump index.
    *
    *        - Any reasonable combination of above values separated by
    *        commas.
    *     FLBND( ) = _DOUBLE (Write)
    *          The lower bounds of the bounding box enclosing the selected
    *          clumps in the current WCS Frame of the input NDF. Celestial axis
    *          values are always in units of radians, but spectral axis units
    *          will be in the spectral units used by the current WCS Frame.
    *     FUBND( ) = _DOUBLE (Write)
    *          The upper bounds of the bounding box enclosing the selected
    *          clumps. See parameter FLBND for more details.
    *     LBOUND( ) = _INTEGER (Write)
    *          The lower pixel bounds of bounding box enclosing the selected
    *          clumps.
    *     NCLUMPS = _INTEGER (Write)
    *        The total number of clumps descrriptions stored within the supplied
    *        NDF.
    *     NDF = NDF (Read)
    *        The NDF defining the previously identified clumps. This
    *        should contain a CUPID extension describing all the identified
    *        clumps, in the format produced by FINDCLUMPS or EXTRACTCLUMPS.
    *     QUIET = _LOGICAL (Read)
    *        If TRUE, then no information is written out to the screen,
    *        although the output parameters are still assigned values. [FALSE]
    *     UBOUND( ) = _INTEGER (Write)
    *          The upper pixel bounds of bounding box enclosing the selected
    *          clumps.

    *  Notes:
    *     - It is hoped to extend the range of information reported by this
    *     application as new requirements arise.

    *  Synopsis:
    *     void clumpinfo( int *status );

    *  Copyright:
    *     Copyright (C) 2007 Particle Physics & Astronomy Research Council.
    *     All Rights Reserved.

    *  Licence:
    *     This program is free software; you can redistribute it and/or
    *     modify it under the terms of the GNU General Public License as
    *     published by the Free Software Foundation; either version 2 of
    *     the License, or (at your option) any later version.
    *
    *     This program is distributed in the hope that it will be
    *     useful, but WITHOUT ANY WARRANTY; without even the implied
    *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
    *     PURPOSE. See the GNU General Public License for more details.
    *
    *     You should have received a copy of the GNU General Public License
    *     along with this program; if not, write to the Free Software
    *     Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA
    *     02110-1301, USA

    *  Authors:
    *     DSB: David S. Berry
    *     {enter_new_authors_here}

    *  History:
    *     22-MAR-2007 (DSB):
    *        Original version.
    *     {enter_further_changes_here}

    *  Bugs:
    *     {note_any_bugs_here}

    *-
    */

    /* Local Variables: */
    AstFrame *cfrm;      /* Pointer to current WCS Frame */
    AstMapping *cmap;    /* Pointer to PIXEL->current Frame Mapping */
    CupidClumpInfo info; /* Structure holding returned information */
    Grp *grp = NULL;     /* GRP group holding input NDF name */
    HDSLoc *aloc = NULL; /* Locator for CLUMPS array in CUPID extension */
    HDSLoc *cloc = NULL; /* Locator for a single CLUMP structure */
    HDSLoc *xloc = NULL; /* Locator for CUPID extension */
    char *p;             /* Pointer into tmpstr string */
    char tmpstr[ 100 ];  /* Buffer for temporary strings */
    const char *dom;     /* Pointer to axis Domain name */
    double flbnd[ NDF__MXDIM ]; /* Lower bounds of WCS bounding box */
    double fubnd[ NDF__MXDIM ]; /* Upper bounds of WCS bounding box */
    double plbnd[ NDF__MXDIM ]; /* Lower bounds of PIXEL bounding box */
    double pubnd[ NDF__MXDIM ]; /* Upper bounds of PIXEL bounding box */
    int *clump_flags = NULL;  /* Flags indicating if each clump is to be used */
    int *clump_indices = NULL;/* List of indices of clumps to be used */
    int i;               /* Loop count */
    int iclump;          /* One-based clump index */
    int indf;            /* NDF identifier for input NDF */
    int ipix;            /* Index of PIXEL Frame */
    size_t nclumps;      /* No. of clump descriptions within the supplied NDF */
    int nuse;            /* Number of clumps to be used */
    int primary;         /* Value for locator primary flag */
    int quiet;           /* Supress screen output? */
    size_t size;         /* Number of values in group "*grp" */
    int there;           /* Does the enquired object exist? */

    /* Abort if an error has already occurred. */
    if( *status != SAI__OK ) return;

    /* Begin an AST context */
    astBegin;

    /* Start an NDF context */
    ndfBegin();



    /* Obtain the input NDF and get a locator for the array of clump
       descriptions within it.
       -----------------------------------------------------------------  */

    /* Get an identifier for the input NDF. We use NDG (via kpg1_Rgndf)
       instead of calling ndfAssoc directly since NDF/HDS has problems with
       file names containing spaces, which NDG does not have. */
    kpg1Rgndf( "NDF", 1, 1, "", &grp, &size, status );
    ndgNdfas( grp, 1, "READ", &indf, status );
    grpDelet( &grp, status );

    /* Check the NDF has a suitable CUPID extension containing an array of
       clump cut-outs. Get an HDS locator for the array. */
    ndfXstat( indf, "CUPID", &there, status );
    if( !there ) {
        if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "NDF", indf );
            errRep( "", "The NDF \"^NDF\" does not contain a CUPID extension "
                    "such as created by FINDCLUMPS or EXTRACTCLUMPS.", status );
        }

    } else {
        ndfXloc( indf, "CUPID", "READ", &xloc, status );
        datThere( xloc, "CLUMPS", &there, status );
        if( !there ) {
            if( *status == SAI__OK ) {
                *status = SAI__ERROR;
                ndfMsg( "NDF", indf );
                errRep( "", "The CUPID extension within NDF \"^NDF\" does not "
                        "contain an array of clumps such as created by "
                        "FINDCLUMPS or EXTRACTCLUMPS.", status );
            }

        } else {
            datFind( xloc, "CLUMPS", &aloc, status );
            primary = 1;
            datPrmry( 1, &aloc, &primary, status );

        }
        datAnnul( &xloc, status );
    }

    /* Abort if we have no clumps array locator, or if an error occurred. */
    if( !aloc || *status != SAI__OK ) goto L999;



    /* Calculate the required clump information, and store it in the "info"
       structure.
       -----------------------------------------------------------------  */

    /* Indicate that the structure holding the returned information has not
       yet been initialised. */
    info.init = 0;

    /* Get the WCS FrameSet from the input NDF, and store a pointer to it in
       the "info" structure. */
    kpg1Gtwcs( indf, &(info.iwcs), status );

    /* Get the number of clumps defined within the input NDF. */
    datSize( aloc, &nclumps, status );

    /* Get the list of clump indices to iclude in the returned information. */
    clump_flags = astMalloc( sizeof( int )*nclumps );
    clump_indices = astMalloc( sizeof( int )*nclumps );
    kpg1Gilst( 1, (int) nclumps, (int) nclumps, "CLUMPS", clump_flags, clump_indices,
               &nuse, status );

    /* Loop round all clumps that are to be used. */
    for( i = 0; i < nuse && *status == SAI__OK; i++ ) {
        iclump = clump_indices[ i ];

        /* Get a locator for this clump. */
        datCell( aloc, 1, &iclump, &cloc, status );

        /* Update the returned information to include this clump. */
        cupidClumpInfo1( cloc, &info, status );

        /* Annul the clump structure locator. */
        datAnnul( &cloc, status );

    }



    /* Write out the information to the screen and to appropriate output
       parameters.
       -----------------------------------------------------------------  */

    /* See if screen output is required. */
    parGet0l( "QUIET", &quiet, status );
    if( !quiet ) msgBlank( status );

    /* The number of clumps defined within the input NDF... */
    parPut0i( "NCLUMPS", (int) nclumps, status );
    if( ! quiet ) {
        msgSeti( "NCLUMPS", (int) nclumps );
        msgOut( "", "   Total no. of clumps: ^NCLUMPS", status );
    }

    /* Pixel index bounding box... */
    parPut1i( "LBOUND", info.npix, info.lbnd, status );
    parPut1i( "UBOUND", info.npix, info.ubnd, status );

    if( !quiet ) {
        p = tmpstr + sprintf( tmpstr, "( " );
        for( i = 0; i < info.npix; i++) {
            p += sprintf( p, "%d:%d", info.lbnd[ i ], info.ubnd[ i ] );
            if( i < info.npix - 1 ) p += sprintf( p, ", " );
        }
        p += sprintf( p, " )" );

        msgSetc( "SECTION", tmpstr );
        msgOut( "", "   Pixel index bounding box: ^SECTION", status );
    }

    /* WCS bounding box (first convert the pixel index bounding box into WCS
       coords)... */
    cfrm = astGetFrame( info.iwcs, AST__CURRENT );

    kpg1Asffr( info.iwcs, "PIXEL", &ipix, status );
    cmap = astGetMapping( info.iwcs, ipix, AST__CURRENT );

    for( i = 0; i < info.npix; i++ ) {
        plbnd[ i ] = info.lbnd[ i ] - 1.0;
        pubnd[ i ] = info.ubnd[ i ];
    }

    for( i = 0; i < info.nwcs; i++ ) {
        astMapBox( cmap, plbnd, pubnd, 1, i + 1, flbnd + i, fubnd + i,
                   NULL, NULL);
    }

    astNorm( cfrm, flbnd );
    astNorm( cfrm, fubnd );

    parPut1d( "FLBND", info.nwcs,  flbnd, status );
    parPut1d( "FUBND", info.nwcs,  fubnd, status );

    if( !quiet ) {
        msgOut( "", "   WCS bounding box:", status );

        for( i = 0; i < info.nwcs; i++) {
            msgSetc( "L", astFormat( cfrm, i + 1, flbnd[ i ] ) );
            msgSetc( "U", astFormat( cfrm, i + 1, fubnd[ i ] ) );

            sprintf( tmpstr, "Domain(%d)", i + 1 );
            dom = astGetC( cfrm, tmpstr );
            if( dom && strcmp( dom, "SKY" ) ) {
                sprintf( tmpstr, "Unit(%d)", i + 1 );
                msgSetc( "UNT", astGetC( cfrm, tmpstr ) );
            } else {
                msgSetc( "UNT", "" );
            }

            sprintf( tmpstr, "Label(%d)", i + 1 );
            msgSetc( "LAB", astGetC( cfrm, tmpstr ) );

            msgOut( "", "        ^LAB: ^L -> ^U ^UNT", status );
        }
    }

    if( !quiet ) msgBlank( status );



    /* Tidy up.
       --------      */
L999:
    ;

    /* Free resources. */
    clump_flags = astFree( clump_flags );
    clump_indices = astFree( clump_indices );
    if( aloc ) datAnnul( &aloc, status );

    /* End the NDF context */
    ndfEnd( status );

    /* End the AST context */
    astEnd;

    /* If an error has occurred, issue another error report identifying the
       program which has failed (i.e. this one). */
    if( *status != SAI__OK ) {
        errRep( "CLUMPINFO_ERR", "CLUMPINFO: Failed to obtain information "
                "about one or more previously identified clumps.", status );
    }

}
Example #7
0
F77_SUBROUTINE(configecho)( INTEGER(STATUS) ){
/*
*+
*  Name:
*     CONFIGECHO

*  Purpose:
*     Displays one or more configuration parameters.

*  Language:
*     C (designed to be called from Fortran)

*  Type of Module:
*     ADAM A-task

*  Invocation:
*     CALL CONFIGECHO( STATUS )

*  Arguments:
*     STATUS = INTEGER (Given and Returned)
*        The global status.

*  Description:
*     This application displays the name and value of one or all
*     configuration parameters, specified using Parameters CONFIG or
*     NDF. If a single parameter is displayed, its value is also
*     written to an output parameter. If the parameter value is not
*     specified by the CONFIG, NDF or DEFAULTS parameter, then the
*     value supplied for DEFVAL is displayed.
*
*     If an input NDF is supplied then configuration parameters
*     are read from its history (see Parameters NDF and APPLICATION).
*
*     If values are supplied for both CONFIG and NDF, then the
*     differences between the two sets of configuration parameters
*     are displayed (see Parameter NDF).

*  Usage:
*     configecho name config [defaults] [select] [defval]

*  ADAM Parameters:
*     APPLICATION = LITERAL (Read)
*        When reading configuration parameters from the history
*        of an NDF, this parameter specifies the name of the application
*        to find in the history. There must be a history component
*        corresponding to the value of this parameter, and it must
*        include a CONFIG group. [current value]
*     CONFIG = GROUP (Read)
*        Specifies values for the configuration parameters. If the string
*        "def" (case-insensitive) or a null (!) value is supplied, the
*        configuration parameters are obtained using Parameter NDF. If
*        a null value is also supplied for NDF, a set of default
*        configuration parameter values will be used, as specified by
*        Parameter DEFAULTS.
*
*        The supplied value should be either a comma-separated list of
*        strings or the name of a text file preceded by an up-arrow
*        character "^", containing one or more comma-separated lists of
*        strings. Each string is either a "keyword=value" setting, or the
*        name of a text file preceded by an up-arrow character "^". Such
*        text files should contain further comma-separated lists which
*        will be read and interpreted in the same manner (any blank lines
*        or lines beginning with "#" are ignored). Within a text file,
*        newlines can be used as delimiters, as well as commas. Settings
*        are applied in the order in which they occur within the list,
*        with later settings overriding any earlier settings given for
*        the same keyword.
*
*        Each individual setting should be of the form "<keyword>=<value>".
*        If a non-null value is supplied for Parameter DEFAULTS, an error
*        will be reported if CONFIG includes values for any parameters
*        that are not included in DEFAULTS.
*     DEFAULTS = LITERAL (Read)
*        The path to a file containing the default value for every
*        allowed configuration parameter. If null (!) is supplied, no
*        defaults will be supplied for parameters that are not specified
*        by CONFIG, and no tests will be performed on the validity of
*        paramter names supplied by CONFIG. [!]
*     DEFVAL = LITERAL (Read)
*        The value to return if no value can be obtained for the named
*        parameter, or if the value is "<undef>".  [<***>]
*     NAME = LITERAL (Read)
*        The name of the configuration parameter to display.  If set to
*        null (!), then all parameters defined in the configuration are
*        displayed.
*     NDF = NDF (Read)
*        An NDF file containing history entries which include
*        configuration parameters. If not null (!) the history
*        of the NDF will be searched for a component corresponding
*        to the Parameter APPLICATION.  The Parameter CONFIG
*        is then optional, but if it too is not null (!) then
*        the output will show the differences between the configuration
*        stored in the NDF history and the given configuration:
*        new parameters and those different from the reference
*        configuration (given by Parameter CONFIG) are prefixed
*        with "+" and those which are the same as the reference
*        configuration are prefixed with "-". [!]
*     SELECT = GROUP (Read)
*        A group that specifies any alternative prefixes that can be
*        included at the start of any parameter name. For instance, if
*        this group contains the two entries "450=1" and "850=0", then
*        either CONFIG or DEFAULTS can specify two values for any single
*        parameter -- one for the parameter prefixed by "450." and another
*        for the parameter prefixed by "850.". Thus, for instance, if
*        DEFAULTS defines a parameter called "filter", it could include
*        "450.filter=300" and "850.filter=600". The CONFIG parameter could
*        then either set the filter parameter for a specific prefix (as
*        in "450.filter=234"); or it could leave the prefix unspecified,
*        in which case the prefix used is the first one with a
*        non-zero value in SELECT (450 in the case of this example - 850
*        has a value zero in SELECT). Thus the names of the items in
*        SELECT define the set of allowed alternative prefixes, and the
*        values indicate which one of these alternatives is to be used
*        (the first one with non-zero value). [!]
*     SORT = _LOGICAL (Read)
*        If TRUE then sort the listed parameters in to alphabetical order.
*        Otherwise, retain the order they have in the supplied
*        configuration. Only used if a null (!) value is supplied for
*        Parameter NAME. [FALSE]
*     VALUE = LITERAL (Write)
*        The value of the configuration parameter, or "<***>" if the
*        parameter has no value in CONFIG and DEFAULTS.

*  Examples:
*     configecho m81 ^myconf
*        Report the value of configuration parameter "m81" defined within
*        the file "myconf". If the file does not contain a value for
*        "m81", then "<***>" is displayed.
*     configecho type ^myconf select="m57=0,m31=1,m103=0"
*        Report the value of configuration parameter "type" defined within
*        the file "myconf". If the file does not contain a value for
*        "type", then the value of "m31.type" will be reported instead. If
*        neither is present, then "<***>" is displayed.
*     configecho flt.filt_edge_largescale \
*                config=^/star/share/smurf/dimmconfig.lis \
*                defaults=/star/bin/smurf/smurf_makemap.def \
*                select="450=1,850=0"
*        Report the value of configuration parameter "flt.filt_edge_largescale"
*        defined within the file "/star/share/smurf/dimmconfig.lis", using
*        defaults from the file "/star/bin/smurf/smurf_makemap.def". If
*        dimmconfig.lis does not contain a value for "flt.filt_edge_largescale"
*        then it is searched for "450.flt.filt_edge_largescale" instead. An
*        error is reported if dimmconfig.lis contains values for any
*        items that are not defined in smurf_makemap.def.
*     configecho ndf=omc1 config=^/star/share/smurf/dimmconfig.lis \
*                defaults=/star/bin/smurf/smurf_makemap.def \
*                application=makemap name=! sort select="450=0,850=1"
*        Show how the configuration used to generate the 850um map
*        of OMC1 differs from the basic dimmconfig.lis file.

*  Copyright:
*     Copyright (C) 2012-3 Science & Technology Facilities Council.
*     All Rights Reserved.

*  Licence:
*     This program is free software; you can redistribute it and/or
*     modify it under the terms of the GNU General Public License as
*     published by the Free Software Foundation; either Version 2 of
*     the License, or (at your option) any later version.
*
*     This program is distributed in the hope that it will be
*     useful, but WITHOUT ANY WARRANTY; without even the implied
*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
*     PURPOSE. See the GNU General Public License for more details.
*
*     You should have received a copy of the GNU General Public License
*     along with this program; if not, write to the Free Software
*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
*     02110-1301, USA.

*  Authors:
*     DSB: David S. Berry
*     GSB: Graham S. Bell
*     {enter_new_authors_here}

*  History:
*     10-DEC-2012 (DSB):
*        Original version.
*     6-FEB-2013 (DSB):
*        Added parameter DEFVAL.
*     11-FEB-2013 (DSB):
*        Added parameter SORT and allow all parameters to be listed by
*        providing a null value for NAME.
*     11-FEB-2013 (GSB):
*        Added ability to read configuration from history entries.
*     13-FEB-2013 (DSB):
*        Nullify AST object pointers when the objects are annulled,
*        to avoid re-use of dead pointers.
*     14-FEB-2013 (DSB):
*        Allow the SELECT feature to be used even if no DEFAULTS file is
*        supplied (see the new entry in the "Examples:" section).
*     15-FEB-2013 (DSB):
*        Expand the prologue docs, and use NULL in place of zero for pointers.
*     22-FEB-2013 (DSB):
*        Guard against seg fault in HistoryKeymap when the NDF does 
*        not contain the required CONFIG entry in the History 
*        component.
*     {enter_further_changes_here}

*-
*/

   GENPTR_INTEGER(STATUS)

/* Local Variables: */
   AstKeyMap *keymap2;
   AstKeyMap *keymap;
   Grp *grp = NULL;
   char *dot;
   char *pname;
   char defs[250];
   char defval[250];
   char name[250];
   const char *value;
   const char *historyValue = NULL;
   int showall;
   int sort;
   size_t size;
   int indf = 0;
   int nrec;
   int i;
   char application[NDF__SZAPP];
   char applicationi[NDF__SZAPP];

/* Abort if an error has already occurred. */
   if( *STATUS != SAI__OK ) return;

/* Begin an AST context */
   astBegin;

/* Get the value to return if no value can be obtained for the named
   parameter, of it it has a value of <undef>. */
   parGet0c( "DEFVAL", defval, sizeof(defval), STATUS );

/* Get any defaults file, annuling the error if null (!) is supplied. */
   if( *STATUS == SAI__OK ) {
      parGet0c( "DEFAULTS", defs, sizeof(defs), STATUS );
      if( *STATUS == PAR__NULL ) {
         errAnnul( STATUS );
         defs[0] = 0;
      }
   }

/* Get the NDF identifier if requested. */
   ndfBegin();
   if (*STATUS == SAI__OK) {
      ndfAssoc("NDF", "READ", &indf, STATUS);
      if (*STATUS == PAR__NULL) {
         errAnnul(STATUS);
         indf = 0;
      }
      else {
         parGet0c("APPLICATION", application, sizeof(application), STATUS);
         /* Check now for error because the block below allowing an undefined
          * CONFIG clears this status otherwise. */
         if (*STATUS != SAI__OK) goto L999;
      }
   }

/* See if any alternate keyword prefixes are allowed, and if so determine
   which of the alternatices is to be displayed. */
   kpg1Gtgrp( "SELECT", &grp, &size, STATUS );
   if( *STATUS == PAR__NULL ) {
      grpDelet( &grp, STATUS );
      errAnnul( STATUS );
      keymap2 = NULL;
   } else {
      kpg1Kymap( grp, &keymap2, STATUS );
      grpDelet( &grp, STATUS );
   }

/* Create a KeyMap holding the selected alternative for each keyword, and
   also supply defaults for any missing values (if a defaults file was
   supplied by the user). */
   keymap = kpg1Config( "CONFIG", defs[0]?defs:NULL, keymap2, 0, STATUS );

/* Allow it to be NULL if we're reading an NDF because we'll replace
   keymap with historyConfig later if necessary. */
   if( indf && *STATUS == PAR__NULL ) {
      errAnnul(STATUS);
      keymap = NULL;
   }

/* Abort if an error has occurred. */
   if( *STATUS != SAI__OK ) goto L999;

/* Get the name of the required parameter, and convert to upper case (if
   supplied). If not supplied, set a flag indicating that all parameters
   should be displayed. */
   parGet0c( "NAME", name, sizeof(name), STATUS );
   if( *STATUS == PAR__NULL ) {
      errAnnul( STATUS );
      showall = 1;
   } else {
      showall = 0;
      astChrCase( NULL, name, 1, 0 );
   }

/* Attempt to find the NDF's corresponding history record. */
   if (indf && *STATUS == SAI__OK) {
      ndfHnrec(indf, &nrec, STATUS);
      for (i = 0; i < nrec; i ++) {
         ndfHinfo(indf, "APPLICATION", i + 1, applicationi,
                  sizeof(applicationi), STATUS);
         if (! strncasecmp(application, applicationi, strlen(application))) {
            ndfHout(indf, i + 1, HistoryKeyMap, STATUS);
            break;
         }
      }

      if (*STATUS == SAI__OK && ! historyConfig) {
         *STATUS = SAI__ERROR;

         errRepf("CONFIGECHO_ERR", "CONFIGECHO: Failed to find %s "
                 "configuration in NDF history.", STATUS, application);
      }
      else if (! keymap) {
         keymap = historyConfig;
         historyConfig = NULL;
      }
   }

   if( *STATUS == SAI__OK ) {

/* First deal with cases where we are displaying a single parameter
   value. */
      if( !showall ) {

/* Loop round each section of the name that ends with a dot. */
         value = defval;
         pname = name;

         dot = strchr( pname, '.' );
         while( dot && keymap ) {

/* Get a nested keymap with the name that occurs prior to the dot. If
   found, use it in place of the parent keymap. */
            pname[ dot - pname ] = 0;
            if( astMapGet0A( keymap, pname, &keymap2 ) ) {
               astAnnul( keymap );
               keymap = keymap2;
            } else {
               keymap = astAnnul( keymap );
            }

/* If historyConfig exists, do the same there. */
            if (historyConfig) {
               if (astMapGet0A(historyConfig, pname, &keymap2)) {
                  astAnnul(historyConfig);
                  historyConfig = keymap2;
               }
               else {
                  historyConfig = astAnnul(historyConfig);
               }
            }

/* Re-instate the original dot, and move on to find the next dot. */
            pname[ dot - pname ] = '.';
            pname = dot + 1;
            dot = strchr( pname, '.' );
         }

/* Ensure no error is reported if the parameter is not found in the
   KeyMap. */
         if( keymap ) {
            astClear( keymap, "KeyError" );

/* Get the parameter value as a string. */
            astMapGet0C( keymap, pname, &value );
         }

         if (historyConfig) {
            astClear(historyConfig, "KeyError");
            astMapGet0C(historyConfig, pname, &historyValue);

/* In NDF history mode we only want to return a value if it
   was found in the configuration from the history. */

            if (historyValue) {
               if (strcmp(value, historyValue)) {
                  msgOutf("", "+ %s", STATUS, historyValue);
               }
               else {
                  msgOutf("", "- %s", STATUS, historyValue);
               }
               parPut0c("VALUE", historyValue, STATUS);
            }
         }
         else {
/* Display it. */
            msgOut( "", value, STATUS );

/* Write it to the output parameter. */
            parPut0c( "VALUE", value, STATUS );
         }

/* Now deal with cases were we are displaying all parameter values. */
      } else {

/* See if the values should be sorted. */
         parGet0l( "SORT", &sort, STATUS );

/* Display them. */
         if (historyConfig) {
            DisplayKeyMap( historyConfig , sort, "", keymap, STATUS );
         }
         else {
            DisplayKeyMap( keymap, sort, "", NULL, STATUS );
         }
      }
   }

/* Tidy up. */
L999:;

/* End the AST context */
   astEnd;

/* Close the NDF if open. */
   ndfEnd(STATUS);

/* If an error has occurred, issue another error report identifying the
   program which has failed (i.e. this one). */
   if( *STATUS != SAI__OK ) {
      errRep( "CONFIGECHO_ERR", "CONFIGECHO: Failed to echo configuration "
              "parameters.", STATUS );
   }

}
Example #8
0
void smurf_sc2fft( int *status ) {

  int avpspec=0;            /* Flag for doing average power spectrum */
  double avpspecthresh=0;   /* Threshold noise for detectors in avpspec */
  Grp * basegrp = NULL;     /* Basis group for output filenames */
  smfArray *bbms = NULL;    /* Bad bolometer masks */
  smfArray *concat=NULL;    /* Pointer to a smfArray */
  size_t contchunk;         /* Continuous chunk counter */
  smfArray *darks = NULL;   /* dark frames */
  int ensureflat;           /* Flag for flatfielding data */
  Grp *fgrp = NULL;         /* Filtered group, no darks */
  smfArray *flatramps = NULL;/* Flatfield ramps */
  AstKeyMap *heateffmap = NULL;    /* Heater efficiency data */
  size_t gcount=0;          /* Grp index counter */
  size_t i;                 /* Loop counter */
  smfGroup *igroup=NULL;    /* smfGroup corresponding to igrp */
  Grp *igrp = NULL;         /* Input group of files */
  int inverse=0;            /* If set perform inverse transform */
  int isfft=0;              /* Are data fft or real space? */
  dim_t maxconcat=0;        /* Longest continuous chunk length in samples */
  size_t ncontchunks=0;     /* Number continuous chunks outside iter loop */
  smfData *odata=NULL;      /* Pointer to output smfData to be exported */
  Grp *ogrp = NULL;         /* Output group of files */
  size_t outsize;           /* Total number of NDF names in the output group */
  int polar=0;              /* Flag for FFT in polar coordinates */
  int power=0;              /* Flag for squaring amplitude coeffs */
  size_t size;              /* Number of files in input group */
  smfData *tempdata=NULL;   /* Temporary smfData pointer */
  int weightavpspec=0;      /* Flag for 1/noise^2 weighting */
  ThrWorkForce *wf = NULL;  /* Pointer to a pool of worker threads */
  int zerobad;              /* Zero VAL__BADD before taking FFT? */

  /* Main routine */
  ndfBegin();

  /* Find the number of cores/processors available and create a pool of
     threads of the same size. */
  wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status );

  /* Get input file(s) */
  kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );

  /* Filter out darks */
  smf_find_science( igrp, &fgrp, 1, NULL, NULL, 1, 1, SMF__NULL, &darks,
                    &flatramps, &heateffmap, NULL, status );

  /* input group is now the filtered group so we can use that and
     free the old input group */
  size = grpGrpsz( fgrp, status );
  grpDelet( &igrp, status);
  igrp = fgrp;
  fgrp = NULL;

  /* We now need to combine files from the same subarray and same sequence
     to form a continuous time series */
  smf_grp_related( igrp, size, 1, 0, 0, NULL, NULL, &maxconcat, NULL, &igroup,
                   &basegrp, NULL, status );

  /* Get output file(s) */
  size = grpGrpsz( basegrp, status );
  if( size > 0 ) {
    kpg1Wgndf( "OUT", basegrp, size, size, "More output files required...",
               &ogrp, &outsize, status );
  } else {
    msgOutif(MSG__NORM, " ", TASK_NAME ": All supplied input frames were DARK,"
             " nothing to do", status );
  }

  /* Get group of bolometer masks and read them into a smfArray */
  smf_request_mask( "BBM", &bbms, status );

  /* Obtain the number of continuous chunks and subarrays */
  if( *status == SAI__OK ) {
    ncontchunks = igroup->chunk[igroup->ngroups-1]+1;
  }
  msgOutiff( MSG__NORM, "", "Found %zu continuous chunk%s", status, ncontchunks,
             (ncontchunks > 1 ? "s" : "") );

  /* Are we flatfielding? */
  parGet0l( "FLAT", &ensureflat, status );

  /* Are we doing an inverse transform? */
  parGet0l( "INVERSE", &inverse, status );

  /* Are we using polar coordinates instead of cartesian for the FFT? */
  parGet0l( "POLAR", &polar, status );

  /* Are we going to assume amplitudes are squared? */
  parGet0l( "POWER", &power, status );

  /* Are we going to zero bad values first? */
  parGet0l( "ZEROBAD", &zerobad, status );

  /* Are we calculating the average power spectrum? */
  parGet0l( "AVPSPEC", &avpspec, status );

  if( avpspec ) {
    power = 1;
    parGet0d( "AVPSPECTHRESH", &avpspecthresh, status );

    parGet0l( "WEIGHTAVPSPEC", &weightavpspec, status );
  }

  /* If power is true, we must be in polar form */
  if( power && !polar) {
    msgOutif( MSG__NORM, " ", TASK_NAME
              ": power spectrum requested so setting POLAR=TRUE", status );
    polar = 1;
  }

  gcount = 1;
  for( contchunk=0;(*status==SAI__OK)&&contchunk<ncontchunks; contchunk++ ) {
    size_t idx;

    /* Concatenate this continuous chunk but forcing a raw data read.
       We will need quality. */
    smf_concat_smfGroup( wf, NULL, igroup, darks, NULL, flatramps, heateffmap,
                         contchunk, ensureflat, 1, NULL, 0, NULL, NULL, 0, 0, 0,
                         &concat, NULL, status );

    /* Now loop over each subarray */
    /* Export concatenated data for each subarray to NDF file */
    for( idx=0; (*status==SAI__OK)&&idx<concat->ndat; idx++ ) {
      if( concat->sdata[idx] ) {
        smfData * idata = concat->sdata[idx];
        int provid = NDF__NOID;
        dim_t nbolo;                /* Number of detectors  */
        dim_t ndata;                /* Number of data points */

        /* Apply a mask to the quality array and data array */
        smf_apply_mask( idata, bbms, SMF__BBM_QUAL|SMF__BBM_DATA, 0, status );

        smf_get_dims( idata,  NULL, NULL, &nbolo, NULL, &ndata, NULL, NULL,
                      status );


        /* Check for double precision data */
        if( idata->dtype != SMF__DOUBLE ) {
          *status = SAI__ERROR;
          errRep( "", FUNC_NAME ": data are not double precision.", status );
        }

        /* Are we zeroing VAL__BADD? */
        if( (*status==SAI__OK) && zerobad ) {
          double *data= (double *) idata->pntr[0];

          for( i=0; i<ndata; i++ ) {
            if( data[i] == VAL__BADD ) {
              data[i] = 0;
            }
          }
        }

        /* Check whether we need to transform the data at all */
        isfft = smf_isfft(idata,NULL,NULL,NULL,NULL,NULL,status);

        if( isfft && avpspec && (*status == SAI__OK) ) {
          *status = SAI__ERROR;
          errRep( "", FUNC_NAME
                  ": to calculate average power spectrum input data cannot "
                  "be FFT", status );
        }

        if( (*status == SAI__OK) && (isfft == inverse) ) {

          if( avpspec ) {
            /* If calculating average power spectrum do the transforms with
               smf_bolonoise so that we can also measure the noise of
               each detector */

            double *whitenoise=NULL;
            smf_qual_t *bolomask=NULL;
            double mean, sig, freqlo;
            size_t ngood, newgood;

            whitenoise = astCalloc( nbolo, sizeof(*whitenoise) );
            bolomask = astCalloc( nbolo, sizeof(*bolomask) );

	    freqlo = 1. / (idata->hdr->steptime * idata->hdr->nframes);

            smf_bolonoise( wf, idata, 1, freqlo, SMF__F_WHITELO,
                           SMF__F_WHITEHI, 1, 0, whitenoise, NULL, &odata,
                           status );

            /* Initialize quality */
            for( i=0; i<nbolo; i++ ) {
              if( whitenoise[i] == VAL__BADD ) {
                bolomask[i] = SMF__Q_BADB;
              } else {
                /* smf_bolonoise returns a variance, so take sqrt */
                whitenoise[i] = sqrt(whitenoise[i]);
              }
            }

            ngood=-1;
            newgood=0;

            /* Iteratively cut n-sigma noisy outlier detectors */
            while( ngood != newgood ) {
              ngood = newgood;
              smf_stats1D( whitenoise, 1, nbolo, bolomask, 1, SMF__Q_BADB,
                           &mean, &sig, NULL, NULL, status );
              msgOutiff( MSG__DEBUG, "", TASK_NAME
                         ": mean=%lf sig=%lf ngood=%li\n", status,
                         mean, sig, ngood);

              newgood=0;
              for( i=0; i<nbolo; i++ ) {
                if( whitenoise[i] != VAL__BADD ){
                  if( (whitenoise[i] - mean) > avpspecthresh *sig ) {
                    whitenoise[i] = VAL__BADD;
                    bolomask[i] = SMF__Q_BADB;
                  } else {
                    newgood++;
                  }
                }
              }
            }

            msgOutf( "", TASK_NAME
                     ": Calculating average power spectrum of best %li "
                     " bolometers.", status, newgood);

            /* If using 1/noise^2 weights, calculate 1/whitenoise^2 in-place
               to avoid allocating another array */
            if( weightavpspec ) {
              msgOutif( MSG__VERB, "", TASK_NAME ": using 1/noise^2 weights",
                        status );

              for( i=0; i<nbolo; i++ ) {
                if( whitenoise[i] && (whitenoise[i] != VAL__BADD) ) {
                  whitenoise[i] = 1/(whitenoise[i]*whitenoise[i]);
                }
              }
            }

            /* Calculate the average power spectrum of good detectors */
            tempdata = smf_fft_avpspec( odata, bolomask, 1, SMF__Q_BADB,
                                        weightavpspec ? whitenoise : NULL,
                                        status );
            smf_close_file( &odata, status );
            whitenoise = astFree( whitenoise );
            bolomask = astFree( bolomask );
            odata = tempdata;
            tempdata = NULL;
	    /* Store the number of good bolometers */
	    parPut0i( "NGOOD", newgood, status );
          } else {
            /* Otherwise do forward/inverse transforms here as needed */

            /* If inverse transform convert to cartesian representation first */
            if( inverse && polar ) {
              smf_fft_cart2pol( wf, idata, 1, power, status );
            }

            /* Tranform the data */
            odata = smf_fft_data( wf, idata, NULL, inverse, 0, status );
            smf_convert_bad( wf, odata, status );

            if( inverse ) {
              /* If output is time-domain, ensure that it is ICD bolo-ordered */
              smf_dataOrder( odata, 1, status );
            } else if( polar ) {
              /* Store FFT of data in polar form */
              smf_fft_cart2pol( wf, odata, 0, power, status );
            }
          }

          /* open a reference input file for provenance propagation */
          ndgNdfas( basegrp, gcount, "READ", &provid, status );

          /* Export the data to a new file */
          smf_write_smfData( odata, NULL, NULL, ogrp, gcount, provid,
                             MSG__VERB, status );

          /* Free resources */
          ndfAnnul( &provid, status );
          smf_close_file( &odata, status );
        } else {
          msgOutif( MSG__NORM, " ",
                    "Data are already transformed. No output will be produced",
                    status );
        }
      }

      /* Update index into group */
      gcount++;
    }

    /* Close the smfArray */
    smf_close_related( &concat, status );
  }

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK ) {
    grpList( "OUTFILES", 0, 0, NULL, ogrp, status );
    if( *status == PAR__NULL ) errAnnul( status );
  }

  /* Tidy up after ourselves: release the resources used by the grp routines */
  grpDelet( &igrp, status);
  grpDelet( &ogrp, status);
  if (basegrp) grpDelet( &basegrp, status );
  if( igroup ) smf_close_smfGroup( &igroup, status );
  if( flatramps ) smf_close_related( &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  if (bbms) smf_close_related( &bbms, status );

  ndfEnd( status );

  /* Ensure that FFTW doesn't have any used memory kicking around */
  fftw_cleanup();
}
Example #9
0
int write_ndf( int argc, void *argv[]) {
/*
** Declare variables
*/
void *arr;         /* Pointer to the data array */
int n_dims;        /* The number of dimensions */
int *arr_bnds;     /* The dimensions */
IDL_STRING *ndf_name;  /* The name of the NDF to be created */
IDL_STRING *comp;      /* The component name */
IDL_STRING *type;      /* The HDS type of the NDF to be created */
int badset;        /* Whether bad value is set */
void *bad_value;   /* Pointer to the bad value */

int status;        /* Starlink status */

int lbnd[5]={1L,1L,1L,1L,1L}; /* Lower bounds array */
int ndf;           /* NDF identifier */
int place;         /* NDF placeholder */
int npix;          /* Number of pixels */
void *ptr[3];      /* Pointer to mapped NDF data Fortran style */
size_t nbytes;     /* Number of bytes in NDF */
int bpix=1;        /* Number of bits/pixel */
int idltype=1;     /* Pixel type code */

int fstat;              /* Final status (before errLoad) */
int errn=0;             /* Error sequence number */
char param[ERR__SZPAR]; /* Error message parameter name */
int parlen;             /* Length of error message parameter name */
char opstr[ERR__SZMSG]; /* Error message */
int oplen;              /* Length of error message */

/*
** Start Error context
*/
   status = SAI__OK;
   errMark();

/*
** Check that the correct number of arguments were passed in
*/
   if(argc != 8) {
   /*
   ** Print an error message and return
   */
      status = SAI__ERROR;
      errRep( " ", "write_ndf: Incorrect number of arguments", &status );

   } else {
   /*
   ** Extract the arguments to comprehensible names
   */
      arr = argv[0];
      n_dims = *(int *)argv[1];
      arr_bnds = (int *)argv[2];
      ndf_name = (IDL_STRING *)argv[3];
      comp = (IDL_STRING *)argv[4];
      type = (IDL_STRING *)argv[5];
      badset = *(int *)argv[6];
      bad_value = (void *)argv[7];

   /*
   ** Enable NDF calls
   */
      ndfBegin();

      if ( !strcmp( comp->s, "DATA" ) ) {
      /*
      ** Create the NDF
      */
         ndfOpen( NULL, ndf_name->s, "WRITE", "NEW", &ndf, &place, &status );
         ndfNew( type->s, n_dims, lbnd, arr_bnds, &place, &ndf, &status );

      } else {
         if ( !strcmp( comp->s, "QUALITY") && strcmp(type->s, "_UBYTE")) {
            status = SAI__ERROR;
            errRep( " ", "write_ndf: Incorrect type for QUALITY", &status );
         }
      /*
      ** Open existing NDF
      */
         ndfOpen( NULL, ndf_name->s, "UPDATE", "OLD", &ndf, &place, &status );
      }

   /*
   **  Check the number of pixels is same in given array and NDF for QUALITY
   **  and VARIANCE.
   */
      if ( strcmp( comp->s, "DATA" ) ) {
         ndfSize( ndf, &npix, &status );

         if ( ( status == SAI__OK ) && ( npix != arr_bnds[n_dims+1] ) ) {
         /*
         **  Array size and NDF size do not agree
         */
            status = SAI__ERROR;
            errRep( " ",
              "write_ndf: Incorrect number elements supplied", &status );
         }
      }

   /*
   **  Obtain mapped access to the array component of the NDF
   */
      ndfMap( ndf, comp->s, type->s, "WRITE", ptr, &npix, &status );

   /*
   **  Now copy the values from ARR into the mapped NDF
   */
      if ( status == SAI__OK ) {
      /*
      **  First check the returned pointer is good
      */
         if ( ptr[0] == NULL ) {
         /*
         **  Fortran to C pointer conversion failed
         */
            status = SAI__ERROR;
            errRep( " ",
              "write_ndf: Fortran to C pointer conversion failed", &status );

         } else {
         /*
         **  then get the IDL type code and number of bytes per pixel
         */
            if (!strcmp(type->s, "_REAL")) {
               idltype = 4;
               bpix = 4;
            } else if (!strcmp(type->s, "_INTEGER")) {
               idltype = 3;
               bpix = 4;
            } else if (!strcmp(type->s, "_WORD")) {
               idltype = 2;
               bpix = 2;
            } else if (!strcmp(type->s, "_DOUBLE")) {
               idltype = 5;
               bpix = 8;
            } else if (!strcmp(type->s, "_UBYTE")) {
               idltype = 1;
               bpix = 1;
            } else {
               status = SAI__ERROR;
               msgSetc( "TYPE", type->s );
               errRep( " ", "Illegal type ^TYPE", &status );
            }

         /*
         **  Now copy the data from the array to the NDF.
         **  If we need to check for bad values in the array, use copybadout.
         **  If any bad values are found copybadout will replace them with the
         **  appropriate PRIMDAT bad value. The NDF bad pixel flag is then set
         **  depending on whether copybadout detected any bad values.
         **  If we need not check for bad pixels just copy the whole lot;
         */
            if ( status == SAI__OK ) {
               if ( badset ) {
                  if ( !copybadout( ptr[0], arr, npix, idltype, bad_value ) )
                     ndfSbad( 0, ndf, comp->s, &status);
               } else {
                  nbytes = bpix * npix;
                  memcpy( ptr[0], arr, nbytes );
               }
            }
         }
      }

   /*
   **  Close NDF
   */
      ndfEnd( &status );
   }

/*
**  Report any error messages
**  Adding Starlink-style !! and ! prefix
*/
   fstat = status;
   while ( status != SAI__OK ) {
      errLoad(
        param, ERR__SZPAR, &parlen, opstr, ERR__SZMSG, &oplen, &status );
      if ( status != SAI__OK )
         printf( "%s %s\r\n", errn++?"! ":"!!", opstr );
   }
   errRlse();

/*
**  That's it, return to the calling routine
*/
   return( fstat == SAI__OK );

}
Example #10
0
/* Main entry */
void smurf_fixsteps( int *status ) {

/* Local Variables */
   AstKeyMap *keymap;        /* Default config parameter values */
   AstKeyMap *sub_instruments; /* Info about sub-instruments */
   FILE *fd = NULL;          /* File descriptor */
   Grp *igrp = NULL;         /* Input group of files */
   Grp *ogrp = NULL;         /* Output group of files */
   dim_t dcfitbox;           /* DCFITBOX config parameter */
   dim_t dcsmooth;           /* DCSMOOTH config parameter */
   dim_t nx;                 /* Length of first pixel axis */
   double dcthresh;          /* DCTHRESH config parameter */
   double sizetol;           /* Tolerance allowed on step height */
   int changed;              /* Have any step fixes changed? */
   int dclimcorr;            /* DCLIMCORR config parameter */
   int dcmaxsteps;           /* DCMAXSTEPS config parameter */
   int first;                /* Index of first change to report */
   int itemp;                /* Intermediate value */
   int meanshift;            /* Use a mean shift filter? */
   int nnew;                 /* Number of new step fixes */
   int nold;                 /* Number of old step fixes */
   size_t nrej;              /* Number of rejected bolometers */
   size_t outsize;           /* Total number of NDF names in the output group */
   size_t size;              /* Number of files in input group */
   smfData *data = NULL;     /* Output smfData */
   smfData *indata = NULL;   /* Input smfData */
   smfStepFix *newsteps = NULL; /* New step fix descriptions */
   smfStepFix *oldsteps = NULL; /* Old step fix descriptions */
   ThrWorkForce *wf = NULL;  /* Pointer to a pool of worker threads */

/* Check inherited status */
   if (*status != SAI__OK) return;

/* begin an NDF context. */
   ndfBegin();

/* Get the name of the input NDF. */
   kpg1Rgndf( "IN", 1, 1, "", &igrp, &size, status );

/* Get output file(s) */
   kpg1Wgndf( "OUT", igrp, size, 0, "More output files required...",
               &ogrp, &outsize, status );

/* Open the input data file, read-only. */
   smf_open_file( igrp, 1, "Read", 0, &indata, status );

/* Since we will be modifying the data values, we need a deep copy. */
   data = smf_deepcopy_smfData( indata, 0, 0, 0, 0, status );

/* Place cleaning parameters into a keymap and set defaults. Note that we
   use the map-maker defaults file here so that we populate the locked
   keymap with all the parameters that people may come across to allow
   them to load their map-maker config directly this application. */
   sub_instruments = smf_subinst_keymap( SMF__SUBINST_NONE, data, NULL, 0,
                                         status );
   keymap = kpg1Config( "CONFIG", "$SMURF_DIR/smurf_makemap.def",
                        sub_instruments, status );
   sub_instruments = astAnnul( sub_instruments );

/* Set the default for each of the step fixing config parameters. */
   astMapGet0I( keymap, "DCSMOOTH", &itemp );
   parDef0i( "DCSMOOTH", itemp, status );

   astMapGet0I( keymap, "DCFITBOX", &itemp );
   parDef0i( "DCFITBOX", itemp, status );

   astMapGet0I( keymap, "DCMAXSTEPS", &itemp );
   parDef0i( "DCMAXSTEPS", itemp, status );

   astMapGet0I( keymap, "DCLIMCORR", &itemp );
   parDef0i( "DCLIMCORR", itemp, status );

   astMapGet0D( keymap, "DCTHRESH", &dcthresh );
   parDef0d( "DCTHRESH", dcthresh, status );

/* Get values for the config params */
   parGet0i( "DCSMOOTH", &itemp, status );
   dcsmooth = itemp;

   parGet0i( "DCFITBOX", &itemp, status );
   dcfitbox = itemp;

   parGet0i( "DCMAXSTEPS", &itemp, status );
   dcmaxsteps = itemp;

   parGet0i( "DCLIMCORR", &itemp, status );
   dclimcorr = itemp;

   parGet0d( "DCTHRESH", &dcthresh, status );

   parGet0l( "MEANSHIFT", &meanshift, status );

/* Find the number of cores/processors available and create a pool of
   threads of the same size. */
   wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status );

/* Fix the steps. */
   smf_fix_steps( wf, data, dcthresh, dcsmooth, dcfitbox, dcmaxsteps,
                  dclimcorr, meanshift, &nrej, &newsteps, &nnew, status );

/* Display a summary of what was done by the step fixer. */
   msgBlank( status );
   if( nrej == 0 ) {
      msgOut( "", "No bolometers were rejected", status );
   } else if( nrej == 1 ) {
      msgOut( "", "One bolometer was rejected", status );
   } else {
      msgSeti( "NREJ", nrej );
      msgOut( "", "^NREJ bolometers were rejected", status );
   }
   parPut0i( "NREJECTED", nrej, status );

   if( nnew == 0 ) {
      msgOut( "", "No steps were fixed", status );
   } else if( nnew == 1 ) {
      msgOut( "", "One step was fixed", status );
   } else {
      msgSeti( "NNEW", nnew );
      msgOut( "", "^NNEW steps were fixed", status );
   }
   parPut0i( "NFIXED", nnew, status );

/* If required, write out to a text file details of the steps that were
   fixed. */
   fd = smf_open_textfile( "NEWSTEPS", "w", "<none>", status );
   if( fd ) {
      smf1_write_steps( fd, indata, nnew, newsteps, dcthresh, dcsmooth,
                        dcfitbox, dcmaxsteps, dclimcorr, nrej, status );
      fclose( fd );
   }

/* If required, create the output NDF. */
   if( outsize > 0 && indata && indata->file ) {
      smf_write_smfData( data, NULL, NULL, ogrp, 1,
                         indata->file->ndfid, MSG__VERB, status );
   }

/* Save the length of the first pixel axis. */
   nx = data ? data->dims[ 0 ] : 0;

/* Close the NDFs. */
   smf_close_file( &data, status );
   smf_close_file( &indata, status );

/* Attempt to open a file containing descriptions of steps fixed by a
   previous invocation of this program. */
   fd = smf_open_textfile( "OLDSTEPS", "r", "<none>", status );
   if( fd ) {

/* Get SIZETOL - the minimum significant fractional error in step sizes. */
      parGet0d( "SIZETOL", &sizetol, status );

/* Read the contents of the file, issuing a warning if the global
   properties read from the file (e.g. parameters used, no. of steps
   found, etc) differ from those of the current invocation. */
      msgBlank( status );
      oldsteps = smf1_read_steps( fd, dcthresh, dcsmooth,
                                  dcfitbox, dcmaxsteps, dclimcorr,
                                  nrej, nnew, &nold, status );

/* Get the index of the first change to report. */
      parGet0i( "FIRST", &first, status );

/* Compare the new step fixes with the old step fixes, issuing a warning
   for the first step fix that has changed. */
      changed = smf1_check_steps( "CONTINUE", first, nx, sizetol,
                                  nold, nnew, oldsteps, newsteps, status );

/* Store a flag indicating if any sstep fixes have chnaged. */
      parPut0l( "CHANGED", changed, status );

/* Tell the user if nothing has changed. */
      if( ! changed ) {
         msgOut( "", "There are no significant differences "
                 "between old and new step fixes.", status );
      }
      msgBlank( status );

/* Close the old steps file, and free the memory holding the old step
   descriptions. */
      fclose( fd );
      oldsteps = astFree( oldsteps );
   }

/* Free resources. */
   newsteps = astFree( newsteps );
   grpDelet( &igrp, status );
   grpDelet( &ogrp, status );

/* End the NDF context. */
   ndfEnd( status );

/* If anything went wrong issue a context message. */
   if( *status != SAI__OK ) msgOutif( MSG__VERB, " ", "FIXSTEPS failed.",
                                      status );
}
Example #11
0
static PyObject*
pyndf_begin(NDF *self)
{
    ndfBegin();
    Py_RETURN_NONE;
};
Example #12
0
void smurf_smurfcopy ( int * status ) {

  smfData * data = NULL;     /* input file struct */
  size_t dtypsz;             /* Number of bytes in data type */
  Grp *fgrp = NULL;          /* Filtered group, no darks */
  size_t i;                  /* Loop counter */
  smfFile * ifile = NULL;    /* Input smfFile */
  Grp *igrp = NULL;          /* Input group */
  unsigned char * inptr = NULL; /* Pointer to start of section to copy */
  int islice;                /* int time slice from parameter */
  int lbnd[2];               /* Lower coordinate bounds of output file */
  size_t nelem;              /* Number of elements to copy */
  smfData * odata = NULL;    /* output file struct */
  size_t offset;             /* offset into data array */
  smfFile * ofile = NULL;    /* output smfFile */
  Grp *ogrp = NULL;          /* Output group */
  size_t outsize;            /* Total number of NDF names in the output group */
  dim_t slice;               /* Time index to extract */
  size_t size;               /* Number of files in input group */
  int ubnd[2];               /* Upper coordinate bounds of output file */

  if (*status != SAI__OK) return;

  ndfBegin();

  /* Read the input file */
  /* As a proof of concept do not allow multiple input files */
  kpg1Rgndf( "IN", 1, 1, "", &igrp, &size, status );

  /* Filter out darks */
  smf_find_science( igrp, &fgrp, 1, NULL, NULL, 0, 0, SMF__NULL, NULL, NULL,
                    NULL, NULL, status );

  /* input group is now the filtered group so we can use that and
     free the old input group */
  size = grpGrpsz( fgrp, status );
  grpDelet( &igrp, status);
  igrp = fgrp;
  fgrp = NULL;

  if (size > 0) {
  /* Get output file(s) */
  kpg1Wgndf( "OUT", igrp, size, size, "More output files required...",
             &ogrp, &outsize, status );
  } else {
    msgOutif(MSG__NORM, " ","All supplied input frames were DARK,"
       " nothing to extract", status );
  }

  /* Allow the user to specify a text file containing a table of pointing
     corrections. Corresponding Mappings are created form the column data
     in this table and stored in the "igrp" group as items of metadata. */
  smf_pread( igrp, "POINTING", status );

  /* Use a loop so that we look like other routines and simplify
     the change if we support multiple input files */
  for (i=1; i<=size; i++) {

    /* Open the input file using standard routine */
    smf_open_and_flatfield( igrp, NULL, i, NULL, NULL, NULL, &data, status );
    if (*status != SAI__OK) break;

    if (*status == SAI__OK) {
      if (!data->file->isTstream  || data->ndims != 3) {
        smf_close_file( &data, status );
        *status = SAI__ERROR;
        errRep(" ", "Input data do not represent time series", status);
        break;
      }
    }

    /* get the slice position - knowing the maximum allowed
       Somewhat problematic in a loop if we want to allow
       different slices per file. Best bet is to allow multiple
       slices in a single file but only one file.
     */

    msgSeti( "MAX", (data->dims)[2] );
    msgOutif( MSG__NORM, " ", "File has ^MAX slices.", status );

    parGdr0i( "SLICE",1, 0, (data->dims)[2], 1, &islice, status);
    slice = islice;
    if (slice == 0) slice = (data->dims)[2];

    /* construct output bounds */
    lbnd[0] = (data->lbnd)[0];
    lbnd[1] = (data->lbnd)[1];
    ubnd[0] = lbnd[0] + (data->dims)[0] - 1;
    ubnd[1] = lbnd[1] + (data->dims)[1] - 1;

    /* Open an output file (losing history) but we do not want
       to propagate the full NDF size to the output file */

    smf_open_newfile( ogrp, i, data->dtype, 2, lbnd, ubnd, 0,
                      &odata, status );
    ofile = odata->file;
    ifile = data->file;

    /* protect against null pointer smfFile */
    if (*status == SAI__OK) {

      /* sort out provenance */
      smf_accumulate_prov( data, igrp, i, ofile->ndfid,
                           "SMURF:SMURFCOPY", NULL, status );

      /* copy the slice in */
      dtypsz = smf_dtype_size( odata, status );
      nelem = (data->dims)[0] * (data->dims)[1];
      offset = (slice - 1) * nelem * dtypsz;
      inptr = (data->pntr)[0];
      memcpy( (odata->pntr)[0], inptr + offset, nelem * dtypsz );

      /* World coordinates - note the 0 indexing relative to GRID */
      smf_tslice_ast( data, slice-1, 1, status );
      ndfPtwcs( data->hdr->wcs, ofile->ndfid, status );

      /* Write the FITS header */
      kpgPtfts( ofile->ndfid, data->hdr->fitshdr, status );

      /* JCMTSTATE */
      sc2store_writejcmtstate( ofile->ndfid, 1, &((data->hdr->allState)[slice-1]),
                               status );

    }

    /* cleanup */
    smf_close_file( &data, status );
    smf_close_file( &odata, status );

  }

  /* tidy */
  if (igrp) {
    smf_pread( igrp, NULL, status );
    grpDelet( &igrp, status );
  }
  if (ogrp) grpDelet( &ogrp, status );

  ndfEnd(status);

}
Example #13
0
int read_ndf( int argc, void *argv[] ) {
/*
** Declare variables
*/
IDL_STRING *ndf_name;  /* The name of the NDF to be read */
IDL_STRING *comp;      /* The component name */
IDL_STRING *type;      /* The HDS type of the component to be read */
void *arr;         /* Pointer to the data array */
int badset;        /* Whether bad value is set */
void *bad_value;   /* Pointer to the bad value */

int status;        /* Starlink status */

int ndf;           /* NDF identifier */
int place;         /* NDF placeholder */
int npix;          /* Number of pixels */
void *ptr[3];      /* Pointer to mapped NDF data Fortran style */
size_t nbytes;     /* Number of bytes in NDF */
int bpix=1;        /* Number of bits/pixel */
int idltype=1;     /* Pixel type code */
int bad;           /* If bad pixels need handling */

int fstat;              /* Final status (before errLoad) */
int errn=0;             /* Error sequence number */
char param[ERR__SZPAR]; /* Error message parameter name */
int parlen;             /* Length of error message parameter name */
char opstr[ERR__SZMSG]; /* Error message */
int oplen;              /* Length of error message */

/*
** Start Error context
*/
   status = SAI__OK;
   errMark();

/*
** Check that the correct number of arguments were passed in
*/
   if(argc != 6) {
   /*
   ** Print an error message and return
   */
      status = SAI__ERROR;
      errRep( " ", "read_ndf: Incorrect number of arguments", &status );
   } else {
   /*
   ** Extract the arguments to comprehensible names
   */
      ndf_name = (IDL_STRING *)argv[0];
      comp = (IDL_STRING *)argv[1];
      type = (IDL_STRING *)argv[2];
      arr = argv[3];
      badset = *(int *)argv[4];
      bad_value = (void *)argv[5];

   /*
   ** Enable NDF calls
   */
      ndfBegin();
/*      ptr[2]=malloc(256);*/
   /*
   ** Open the NDF
   */
      ndfOpen( NULL, ndf_name->s, "READ", "OLD", &ndf, &place, &status );
   /*
   **  Obtain mapped access to the array component of the first NDF
   */
      ndfMap( ndf, comp->s, type->s, "READ", ptr, &npix, &status );
   /*
   **  Now copy the values from the mapped NDF into ARR
   */
      if ( status == SAI__OK ) {
      /*
      **  First check the returned pointer is good
      */
         if ( ptr[0] == NULL ) {
         /*
         **  Fortran to C pointer conversion failed
         */
            status = SAI__ERROR;
            errRep( " ",
              "read_ndf: Fortran to C pointer conversion failed", &status );

         } else {
         /*
         **  then get the IDL type and number of bytes per pixel
         */
            if (!strcmp(type->s, "_REAL")) {
               idltype = 4;
               bpix = 4;
            } else if (!strcmp(type->s, "_INTEGER")) {
               idltype = 3;
               bpix = 4;
            } else if (!strcmp(type->s, "_WORD")) {
               idltype = 2;
               bpix = 2;
            } else if (!strcmp(type->s, "_DOUBLE")) {
               idltype = 5;
               bpix = 8;
            } else if (!strcmp(type->s, "_UBYTE")) {
               idltype = 1;
               bpix = 1;
            } else {
               status = SAI__ERROR;
               msgSetc( "TYPE", type->s );
               errRep( " ", "Illegal type ^TYPE", &status );
            }
         /*
         **  If badset is false, we can just copy everything; otherwise see if
         **  bad pixels may be set and act accordingly. Set bad if we need to check
         **  for bad pixels.
         */
            bad = 0;
            if ( badset ) ndfBad( ndf, "DATA", 0, &bad, &status );

         /*
         **  Now copy the data from the NDF to the array.
         **  If we need not check for bad pixels just copy the whole lot
         */
            if ( status == SAI__OK ) {
               if ( bad ) {
                  copybadin( arr, ptr[0], npix, idltype, bad_value );
               } else {
                  nbytes = bpix * npix;
                  memcpy( arr, ptr[0], nbytes );
               }
            }
         }
      }

   /*
   **  Close NDF
   */
      ndfEnd( &status );
   }

/*
**  Report any error messages
**  Adding Starlink-style !! and ! prefix
*/
   fstat = status;
   while ( status != SAI__OK ) {
      errLoad(
         param, ERR__SZPAR, &parlen, opstr, ERR__SZMSG, &oplen, &status );
      if ( status != SAI__OK )
         printf( "%s %s\r\n", errn++?"! ":"!!", opstr );
   }
   errRlse();

/*
**  That's it, return to the calling routine
*/
   return( fstat == SAI__OK );
}
Example #14
0
void smurf_fts2_split(int* status)
{
  if( *status != SAI__OK ) { return; }

  const double STAGE_LENGTH = 450.0;    /* mm */
  int LR                    = 0;        /* Treat as Low Resolution scan */
  Grp* gIn                  = NULL;     /* Input group */
  Grp* gOut                 = NULL;     /* Output group */
  Grp* gTmp                 = NULL;     /* Temporary group */
  smfData* inData           = NULL;     /* Pointer to input data */
  smfData* outData          = NULL;     /* Pointer to output data */
  double* outData_pntr      = NULL;     /* Pointer to output data values array */
  int nMirPos               = 0;        /* Number of frames where the mirror actually moves */
  int nStart                = 0;        /* Frame index where the mirror starts moving */
  int nStartNext            = 0;        /* Frame index where the mirror starts moving in the next scan */
  int nStop                 = 0;        /* Frame index where the mirror stops */
  int lrStart               = 0;        /* Frame index where low resolution mirror limit starts */
  int hrStop                = 0;        /* Frame index where high resolution mirror limit stops */
  int hrStart               = 0;        /* Frame index where high resolution mirror limit starts */
  int lrStop                = 0;        /* Frame index where low resolution mirror limit stops */
  int lrCentre              = 0;        /* Frame index at centre of low resolution mirror positions */
  int i                     = 0;        /* Counter */
  int j                     = 0;        /* Counter */
  int k                     = 0;        /* Counter */
  int n                     = 0;        /* Counter */
  double fNyquist           = 0.0;      /* Nyquist frequency */
  double dz                 = 0.0;      /* Step size in evenly spaced OPD grid */
  double* MIRPOS            = NULL;     /* Mirror positions */
  double* MIRRTS            = NULL;     /* Mirror times */

  size_t nFiles             = 0;        /* Size of the input group */
  size_t nOutFiles          = 0;        /* Size of the output group */
  size_t fIndex             = 0;        /* File index */
  size_t nWidth             = 0;        /* Data cube width */
  size_t nHeight            = 0;        /* Data cube height */
  size_t nFrames            = 0;        /* Data cube depth in input file */
  size_t nFramesOut         = 0;        /* Data cube depth in output file */
  size_t nFramesOutPrev     = 0;        /* Data cube depth in previous output file */
  size_t hrFramesOut        = 0;        /* Data cube depth in high res output file */
  size_t hrFramesOutPrev    = 0;        /* Data cube depth in previous high res output file */
  size_t lrFramesOut        = 0;        /* Data cube depth in low res output file */
  size_t lrFramesOutPrev    = 0;        /* Data cube depth in previous low res output file */
  size_t nPixels            = 0;        /* Number of bolometers in the subarray */

  char object[SZFITSTR];
  char subarray[SZFITSTR];
  char obsID[SZFITSTR];
  char scanMode[SZFITSTR];

  double scanVel            = 0.0;      /* Mirror speed in mm/sec */
  double stepTime           = 0.0;      /* RTS step time, average sample rate */
  double minOPD             = 0;        /* OPD minimum */
  double maxOPD             = 0;        /* OPD maximum */
  double ZPD                = 0;
  double lrmmBandPass       = 0.0;      /* low res mm +/- offset from centre */
  int lrBandPassFrames      = 0;        /* Number of low res band pass frames from centre +/- length of lrmmBandPass */
  int nTmp                  = 0;
  int nMax                  = 0;
  int nOPD                  = 0;
  int bolIndex              = 0;
  int index                 = 0;
  int indexIn               = 0;
  int indexOut              = 0;
  int badPixel              = 0;
  int k0                    = 0;
  int indexZPD              = 0;
  int done                  = 0;        /* Track completion of extracting multiple scans */
  int outDataCount          = 0;        /* The number of output data files being written */

  double lenLeft,
         lenRight,
         minLenLeft,
         minLenRight,
         minLen,
         minZPD,
         maxZPD,
         midZPD             = 0.0;      /* Mirror position half side measures */
  int midZPDPos             = 0;        /* Middle ZPD position in mirror position array */

  double EPSILON            = 0.0;
  char fileName[SMF_PATH_MAX+1];
  char scanNumStr[5+1];                 /* String form of scan number of the input file */
  int scanNum               = 0;        /* Scan number of the input file */
  int conNum                = 0;        /* Concatenation number of the input file (left shifted scanNum) */
  int scanDir               = 0;        /* Scan direction: 1 -> back to front (positive), -1 -> front to back (negative) */
  JCMTState *allState       = NULL;     /* Temporary buffer for reduced header allState array data */


  /* Get Input, Output groups */
  kpg1Rgndf("IN", 0, 1, "", &gIn, &nFiles, status);
  kpg1Wgndf("OUT", gOut, nFiles, nFiles, "More output files expected!", &gOut, &nOutFiles, status);

  /* Read in ADAM parameters */
  parGet0d("BANDPASS", &lrmmBandPass, status);          /* Low res mm band +/- offset from centre */

  /* Treat as Low Resolution scan? */
  if(lrmmBandPass > 0) {
      LR = 1;
  }

  /* Eliminate the first record in the output group, since it will be replaced later */
  gTmp = grpCopy(gOut, 1, 1, 1, status);
  grpDelet(&gOut, status);
  gOut = gTmp;

  /* BEGIN NDF */
  ndfBegin();

  /* Loop through each input file */
  for(fIndex = 1; fIndex <= nFiles; fIndex++) {
    /* Open Observation file */
    smf_open_file(NULL, gIn, fIndex, "READ", 0, &inData, status);
    if(*status != SAI__OK) {
      *status = SAI__ERROR;
      errRep(FUNC_NAME, "Unable to open the source file!", status);
      goto CLEANUP;
    }

    smf_fits_getS(inData->hdr, "OBJECT", object, sizeof(object), status);
    smf_fits_getS(inData->hdr, "SUBARRAY", subarray, sizeof(subarray), status);
    smf_fits_getS(inData->hdr, "OBSID", obsID, sizeof(obsID), status);
    smf_fits_getS(inData->hdr, "FTS_MODE", scanMode, sizeof(scanMode), status);
    smf_fits_getD(inData->hdr, "SCANVEL", &scanVel, status);
    smf_fits_getD(inData->hdr, "STEPTIME", &stepTime, status);

    /* Nyquist frequency */
    fNyquist = 10.0 / (8.0 * scanVel * stepTime);
    dz = 1.0 / (2.0 * fNyquist);
    EPSILON = scanVel * stepTime / 2;

    /* Extract the scan number from the input file to be incremented in the output files */
    one_strlcpy(scanNumStr, &(inData->file->name[strlen(inData->file->name) - 8]),
               astMIN(SMF_PATH_MAX + 1, 5), status);
    if (*status == ONE__TRUNC) {
        errRep(FUNC_NAME, "Error extracting scanNumStr!", status);
        errAnnul(status);
    }

    /* Create a temporary base file name from input file name */
    one_strlcpy(fileName, inData->file->name,
                astMIN(SMF_PATH_MAX + 1, strlen(inData->file->name) - 7), status);
    if (*status == ONE__TRUNC) {
        errRep(FUNC_NAME, "Error extracting base fileName!", status);
        errAnnul(status);
    }
    scanNum = (int) one_strtod(scanNumStr, status);
    if (*status != SAI__OK) {
        errRep(FUNC_NAME, "Error extracting scanNum!", status);
        errAnnul(status);
    }

    /* Left shift scanNum to conNum as a prefix to make output scan number unique */
    if(scanNum < 100) {
      conNum = scanNum * 100;
    } else if(scanNum < 1000) {
      conNum = scanNum * 10;
    }

    /*printf("%s: Processing file: %s, having basename: %s and scanNumStr: %s, scanNum: %04d\n",
           TASK_NAME, inData->file->name, fileName, scanNumStr, scanNum);*/

    /* Data cube dimensions */
    nWidth  = inData->dims[0];
    nHeight = inData->dims[1];
    nFrames = inData->dims[2];
    nPixels = nWidth * nHeight;

    /* Mirror positions in mm */
    nTmp = nFrames;
    MIRPOS = astCalloc(nFrames, sizeof(*MIRPOS));
    MIRRTS = astCalloc(nFrames, sizeof(*MIRRTS));
    fts2_getmirrorpositions(inData, MIRPOS, MIRRTS, &nTmp, status); // (mm)
    if(*status != SAI__OK) {
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "Unable to get the mirror positions!", status);
      goto CLEANUP;
    }

    nStart = -1;
    nStop = -1;
    nStartNext = 0;
    hrStart = -1;
    hrStop = -1;
    lrStart = -1;
    lrStop = -1;
    outDataCount = 0;
    done = 0;
    do {
        /* Find the next range of single scan mirror positions for which to extract corresponding NDF data */
        for(n=nStartNext; n<nFrames-1; n++){
            if(hrStart < 0 && fabs(MIRPOS[n+1] - MIRPOS[n]) >= EPSILON) {
                nStart = n;
                hrStart = n;
                /*printf("%s: Split nStart=%d\n", TASK_NAME, nStart);*/
            }
            if(hrStart >= 0 && hrStop < 0 && (fabs(MIRPOS[n+1] - MIRPOS[n]) < EPSILON || n+1 == nFrames-1)) {
                hrStop = n+1;
                hrFramesOutPrev = hrFramesOut;
                hrFramesOut = abs(hrStop - hrStart) + 1;
                outDataCount++;

                nStop = hrStop;
                nFramesOutPrev = hrFramesOutPrev;
                nFramesOut = hrFramesOut;

                /*printf("%s: Split: %d of %d frames found at hrStart=%d, hrStop=%d, where nFrames=%d\n",
                       TASK_NAME, outDataCount, hrFramesOut, hrStart, hrStop, nFrames);*/
                break;
            }
        }

        /* Determine scan direction */
        if(MIRPOS[hrStart] < MIRPOS[hrStop]) {
            scanDir = 1;    /* Positive */
        } else {
            scanDir = -1;   /* Negative */
        }

        /* Limit to specified mirror position range */
        if(LR) {
            /* Calculate how many frames correspond to the given +/- mm of LR bandpass */
            lrBandPassFrames = lrmmBandPass / dz;

            /* Find the centre of the current scan */
            lrCentre = floor((abs(hrStop-hrStart)+1)/2);

            /* Set low res start and stop values at corresponding frame offsets from centre */
            lrStart = lrCentre - lrBandPassFrames;
            lrStop = lrCentre + lrBandPassFrames;
            lrFramesOutPrev = lrFramesOut;
            lrFramesOut = abs(lrStop - lrStart) + 1;

            nStart = lrStart;
            nStop = lrStop;
            nFramesOutPrev = lrFramesOutPrev;
            nFramesOut = lrFramesOut;

            /*printf("%s: LR Split: %d of %d frames found at lrStart=%d, lrStop=%d\n",
                   TASK_NAME, outDataCount, lrFramesOut, lrStart, lrStop);*/
        }

        /* Check for end of data condition */
        if(hrStop < hrStart  || (nFrames - hrStop) < (hrStop - hrStart)/2) {
            done = 1;
        }

        /* Output scan if there is a start and stop position found,
           and for the last scan if it's the only one
           and if it's not too short (compared to the previous one) */
        /*printf("%s: nStart=%d, nStop=%d, nFramesOutPrev=%d, nFramesOut=%d\n", TASK_NAME, nStart, nStop, nFramesOutPrev, nFramesOut);*/
        if(nStart >=0 && nStop > 0 &&
            (nFramesOutPrev == 0 ||
              (nFramesOutPrev > 0 && nFramesOut > 0 && (double)hrFramesOut/(double)hrFramesOutPrev >= 0.5))) {
            /* Copy single scan NDF data from input to output */
            outData = smf_deepcopy_smfData(NULL, inData, 0, SMF__NOCREATE_DATA | SMF__NOCREATE_FTS, 0, 0, status);
            outData->dtype   = SMF__DOUBLE;
            outData->ndims   = 3;
            outData->dims[0] = nWidth;
            outData->dims[1] = nHeight;
            outData->dims[2] = nFramesOut;
            outData_pntr = (double*) astMalloc((nPixels * nFramesOut) * sizeof(*outData_pntr));
            outData->pntr[0] = outData_pntr;
            outData->hdr->nframes = nFramesOut;

            for(i=0; i<nWidth; i++) {
                for(j=0; j<nHeight; j++) {
                    bolIndex = i + j * nWidth;
                    for(k=nStart; k<=nStop; k++) {
                        indexIn = bolIndex + k * nPixels;
                        indexOut = bolIndex + (k-nStart) * nPixels;
                        *((double*)(outData->pntr[0]) + indexOut) = *((double*)(inData->pntr[0]) + indexIn);
                    }
                }
            }

            /* Update the FITS headers */
            outData->fts = smf_create_smfFts(status);
            /* Update FITS component */
            smf_fits_updateD(outData->hdr, "FNYQUIST", fNyquist, "Nyquist frequency (cm^-1)", status);
            smf_fits_updateI(outData->hdr, "MIRSTART", 1, "Frame index in which the mirror starts moving", status);
            smf_fits_updateI(outData->hdr, "MIRSTOP", nFramesOut, "Frame index in which the mirror stops moving", status);
            smf_fits_updateI(outData->hdr, "SCANDIR", scanDir, "Scan direction", status);
            smf_fits_updateD(outData->hdr, "OPDMIN", 0.0, "Minimum OPD", status);
            smf_fits_updateD(outData->hdr, "OPDSTEP", 0.0, "OPD step size", status);

            /* Update the JCMTSTATE header */
            /* Reallocate outData header array memory to reduced size */
            allState = (JCMTState*) astRealloc(outData->hdr->allState, nFramesOut * sizeof(*(outData->hdr->allState)));
            if(*status == SAI__OK && allState) {
                outData->hdr->allState = allState;
            } else {
                errRepf(TASK_NAME, "Error reallocating allState JCMTState header", status);
                goto CLEANUP;
            }
            for(k=nStart; k<=nStop; k++) {
                /* Copy over JCMTstate */
                /*printf("%s: memcpy allState: %d to: %p from: %p size: %d\n",TASK_NAME, k,
                       (void *) &(outData->hdr->allState[k-nStart]), (void *) &(inData->hdr->allState[k]), sizeof(*(outData->hdr->allState)) );*/
                memcpy( (void *) &(outData->hdr->allState[k-nStart]), (void *) &(inData->hdr->allState[k]), sizeof(*(outData->hdr->allState)) );

                /*printf("%s: Scan: %d index: %d rts_num: %d\n", TASK_NAME, outDataCount, k-nStart, outData->hdr->allState[k-nStart].rts_num);*/
                /*printf("%s: Scan: %d index: %d fts_pos: %f\n", TASK_NAME, outDataCount, k-nStart, outData->hdr->allState[k-nStart].fts_pos);*/
            }

            /* Write output */
            /* Append unique suffix to fileName */
            /* This must be modified by the concatenation file scan number to improve uniqueness */
            n = one_snprintf(outData->file->name, SMF_PATH_MAX, "%s%04d_scn.sdf", status, fileName, conNum+outDataCount);
            /*printf("%s: Writing outData->file->name: %s\n", TASK_NAME, outData->file->name);*/
            if(n < 0 || n >= SMF_PATH_MAX) {
                errRepf(TASK_NAME, "Error creating outData->file->name", status);
                goto CLEANUP;
            }
            /* Update the list of output _scn file names */
            grpPut1(gOut, outData->file->name, 0, status);
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error saving outData file name", status);
                goto CLEANUP;
            }
            smf_write_smfData(NULL, outData, NULL, outData->file->name, gOut, fIndex, 0, MSG__VERB, 0, status);
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error writing outData file", status);
                goto CLEANUP;
            }
            smf_close_file( NULL,&outData, status);
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error closing outData file", status);
                goto CLEANUP;
            }
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error closing outData file", status);
                goto CLEANUP;
            }
        }/* else {
            if(!(nStart >=0 && nStop)) printf("%s: Output scan condition failed: nStart(%d) >= nStop(%d) is FALSE\n",TASK_NAME, nStart, nStop);
            if(!(nFramesOutPrev == 0 ||
              (nFramesOutPrev > 0 && nFramesOut > 0 && (double)nFramesOut/(double)nFramesOutPrev >= 0.5))) printf("%s: Output scan condition failed: nFramesOutPrev(%d) == 0 || (nFramesOutPrev(%d) > 0 && nFramesOut(%d) > 0 && nFramesOut/nFramesOutPrev (%f) >= 0.5) is FALSE\n", TASK_NAME, nFramesOutPrev, nFramesOutPrev, nFramesOut, (double)nFramesOut/(double)nFramesOutPrev);
        }*/

        /* Prepare for next iteration */
        nStartNext = hrStop + 1;
        hrStart = -1;
        hrStop = -1;

    } while (!done);


    /* Deallocate memory used by arrays */
    if(MIRPOS)  { MIRPOS    = astFree(MIRPOS); }
    if(MIRRTS)  { MIRRTS    = astFree(MIRRTS); }

    /* Close the file */
    smf_close_file( NULL,&inData, status);

  }
  CLEANUP:
  /* Deallocate memory used by arrays */
  if(MIRPOS)  { MIRPOS    = astFree(MIRPOS); }
  if(MIRRTS)  { MIRRTS    = astFree(MIRRTS); }
  if(inData)  { smf_close_file( NULL,&inData, status); }
  if(outData) { smf_close_file( NULL,&outData, status); }

  /* END NDF */
  ndfEnd(status);

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK && gOut ) {
      grpList( "OUTFILES", 0, 0, NULL, gOut, status );
          if( *status == PAR__NULL ) {
              errRep(FUNC_NAME, "Error writing OUTFILES!", status);
              errAnnul( status );
          }
  }

  /* Delete groups */
  if(gIn)     { grpDelet(&gIn, status);  }
  if(gOut)    { grpDelet(&gOut, status); }
}