Ejemplo n.º 1
0
static PyObject*
pyndf_xstat(NDF *self, PyObject *args)
{
    const char *xname;
    if(!PyArg_ParseTuple(args, "si:pyndf_xstat", &xname))
	return NULL;
    int state, status = SAI__OK;
    errBegin(&status);
    ndfXstat(self->_ndfid, xname, &state, &status);
    if (raiseNDFException(&status)) return NULL;

    return PyBool_FromLong( state );
};
Ejemplo n.º 2
0
void smf_create_qualname( const char *mode, int indf, IRQLocs **qlocs,
                          int *status ) {

  int fixed;                 /* Flag to denote whether quality bit is fixed */
  size_t i;                  /* loop counter */
  int value;                 /* Value of current quality bit */
  int there = 0;             /* Flag to denote presence of NDF extension */
  HDSLoc *smurfloc = NULL;   /* HDS locator for the SMURF extension */

  if ( *status != SAI__OK ) return;

  /* Check for access mode */
  if (strncmp(mode,"READ",4) == 0 ) {
    msgOutif(MSG__DEBUG, "",
	     "Input file is read-only - unable to create quality names "
             "extension",
	     status);
    return;
  }

  msgOutif(MSG__DEBUG, "", "Creating quality names extension", status);
  ndfXstat( indf, SMURF__EXTNAME, &there, status );
  if (!there) {
    /* Create SMURF extension if it does not already exist */
    ndfXnew( indf, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &smurfloc, status );
  }

  /* Create new quality names extension */
  irqNew( indf, SMURF__EXTNAME, qlocs, status );

  /* Add SMURF quality names -- check against smf_qual_str */
  msgOutif(MSG__DEBUG, "", "Adding SMURF quality names", status);
  for (i=0; i<SMF__NQBITS_TSERIES; i++) {
    const char * qdesc = NULL; /* Description of quality */
    const char * qstr = NULL;  /* Quality string identifier */
    qstr = smf_qual_str( SMF__QFAM_TSERIES, 1, i, &qdesc, status );

    /* Set the quality name */
    irqAddqn( *qlocs, qstr, 0, qdesc, status );

    /* Now fix the bits to the desired values */
    irqFxbit( *qlocs, qstr, i+1, &fixed, status );

    /* Set names to read only */
    irqRwqn( *qlocs, qstr, 1, 1, &value, status );
  }

  if ( smurfloc ) datAnnul( &smurfloc, status);
}
Ejemplo n.º 3
0
smf_qual_t * smf_qual_unmap( ThrWorkForce *wf, int indf, smf_qfam_t family,
                             smf_qual_t * qual, smf_qual_t mask, int * status ) {
  int canwrite = 0;   /* can we write to the file? */
  size_t nqbits = 0;  /* Number of quality bits in this family */
  SmfQualUnmapData *job_data = NULL;
  SmfQualUnmapData *pdata;
  int nw;
  size_t step;
  int iw;

  if (*status != SAI__OK) goto CLEANUP;

  /* do nothing if there is no quality */
  if (!qual) return NULL;

  /* if we do not have an NDF identifier we just free the memory */
  if (indf == NDF__NOID) goto CLEANUP;

  /* See if we have WRITE access to the file */
  ndfIsacc( indf, "WRITE", &canwrite, status );

  /* if we have WRITE access and the data were not mapped we have
     to copy to the file. Also check we have a non-NULL input pointer.
     If the data were mapped we still have to make sure the quality names
     are stored. */
  if ( canwrite && qual ) {
    int highbit = -1; /* highest bit used */
    size_t i;
    int itemp;
    int lowbit = -1;  /* Lowest bit used */
    size_t nout;
    int nqual = 0;
    void *qpntr[1];
    size_t qcount[SMF__NQBITS]; /* statically allocate the largest array */
    IRQLocs *qlocs;
    unsigned char * qmap;
    int there;

    ndfMsg( "FILE", indf );
    msgOutif( MSG__DEBUG, "", "Finalising quality for file ^FILE", status);

    if (family == SMF__QFAM_TCOMP ) {
      /* note that TCOMP is not an allowed quality because SMURF should not be
         using it anywhere in a permanent way. */
      *status = SAI__ERROR;
      ndfMsg( "NDF", indf );
      errRepf( "", "Unsupported quality family '%s' for quality unmapping of "
               "file ^NDF", status, smf_qfamily_str(family,status) );
      goto CLEANUP;
    } else if (family == SMF__QFAM_NULL) {
      /* In this case we have to assume that we just cast the quality
         to UBYTE and copy it without changing anything or naming the
         entries. Use a simple type conversion. */
      ndfMap( indf, "QUALITY", "_UBYTE", "WRITE", &qpntr[0], &itemp, status );
      qmap = qpntr[0];
      nout = itemp;

      for (i = 0; i<nout; i++) {
        qmap[i] = qual[i];
      }
      ndfUnmap( indf, "QUALITY", status );

      /* Turn on all quality */
      ndfSbb( 255, indf, status );

      /* we are finished so jump to tidy up */
      goto CLEANUP;
    }

    /* work out how many quality items are in this family */
    nqbits = smf_qfamily_count( family, status );

    /* initialize qcount */
    for (i=0; i<SMF__NQBITS; i++) {
      qcount[i] = 0;
    }

    /* how many pixels in NDF (assumed to be number in quality) */
    ndfSize( indf, &itemp, status );
    nout = itemp;

    /* How many threads do we get to play with */
    nw = wf ? wf->nworker : 1;

    /* Find how many elements to process in each worker thread. */
    step = nout/nw;
    if( step == 0 ) step = 1;

    /* Allocate job data for threads, and store common values. Ensure that the
       last thread picks up any left-over elements.  */
    job_data = astCalloc( nw, sizeof(*job_data) );
    if( *status == SAI__OK ) {
      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        pdata->i1 = iw*step;
        if( iw < nw - 1 ) {
          pdata->i2 = pdata->i1 + step - 1;
        } else {
          pdata->i2 = nout - 1 ;
        }
        pdata->nqbits = nqbits;
        pdata->qual = qual;
        pdata->nout = nout;
      }
    }

    /* Work out which bits are actually used */
    if (*status == SAI__OK) {
      size_t k;
      /* now we try to be a bit clever. It may be a mistake since we have to
         do multiple passes through "qual". First determine how many quality
         bits are actually set. */

      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        pdata->operation = 1;
        thrAddJob( wf, 0, pdata, smf1_qual_unmap, 0, NULL, status );
      }
      thrWait( wf, status );

      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        for( k=0; k<nqbits; k++ ) {
          qcount[k] += pdata->qcount[k];
        }
      }

      /* Reset the counts to zero for any bits that are not required
         (i.e. are not set in "mask").  */
      for( k=0; k<nqbits; k++ ) {
         if( ! (mask & (1<<k)) ) qcount[k] = 0;
      }

      /* see how many we got */
      for (k=0; k<nqbits; k++) {

        if ( qcount[k] ) {
          nqual++;
          highbit = k;
          if (lowbit < 0) lowbit = k;
        }
      }
    }

    /* for IRQ we need to ensure the SMURF extension exists so open and annul it if it is missing.
       We are completely rewriting any IRQ information so we have to delete any previously existing
       IRQ extension. */
    irqDelet( indf, status );
    ndfXstat( indf, SMURF__EXTNAME, &there, status );
    if (!there) {
      HDSLoc * smurfloc = NULL;
      /* Create SMURF extension if it does not already exist */
      ndfXnew( indf, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &smurfloc, status );
      if (smurfloc) datAnnul( &smurfloc, status );
    }
    irqNew( indf, SMURF__EXTNAME, &qlocs, status );

    /* malloced so we need to map and copy over the values. IRQ
       names need to be set BEFORE we copy. */

    /* Map the quality component with WRITE access */
    ndfMap( indf, "QUALITY", "_UBYTE", "WRITE", &qpntr[0], &itemp, status );
    qmap = qpntr[0];

    /* we assume the number of elements in "qual" is the same as in "qmap" */
    if (*status == SAI__OK) {
      size_t k;

      /* if we only have 8 or fewer bits active we can just compress
         by mapping them to the lower 8 bits. This will work if we also
         set the IRQ quality names in the NDF. */
      if (nqual == 0 ) {
        /* easy */
        memset( qmap, 0, nout * smf_dtype_sz( SMF__UBYTE, status ) );
      } else if ( nqual <= 8 ) {
        size_t curbit = 0;

        /* and the quality names. Start at lowbit and go to highbit
           knowing that we have shifted them down so that lowbit in qual
           is bit 0 in NDF. */
        for (k=lowbit; k<=(size_t)highbit; k++) {
          if (qcount[k]) {
            int fixed = 0;             /* is bit fixed? */
            const char * qdesc = NULL; /* Description of quality */
            const char * qstr = NULL;  /* Quality string identifier */
            curbit++;
            qstr = smf_qual_str( family, 1, k, &qdesc, status );

            irqAddqn( qlocs, qstr, 0, qdesc, status );
            irqFxbit( qlocs, qstr, curbit, &fixed, status );
          }
        }

        /* shift them down */
        for( iw = 0; iw < nw; iw++ ) {
          pdata = job_data + iw;
          pdata->operation = 2;
          pdata->qmap = qmap;
          pdata->highbit = highbit;
          pdata->lowbit = lowbit;
          for( k=0; k<nqbits; k++ ) {
            pdata->qcount[k] = qcount[k];
          }
          thrAddJob( wf, 0, pdata, smf1_qual_unmap, 0, NULL, status );
        }
        thrWait( wf, status );

      } else {
        size_t curbit = 0;

        /* Quality names are now needed and we have to write them
           all out because we have not compressed the bits in the
           output quality array we've only compressed the input.
           To limit the number of active bits we'd have to copy the
           compressed bits to the output and then set the quality
           names but IRQ does not let you do that so you would need
           to run through the entire array first counting which bits
           were used. */

        for (k=0; k<SMF__NQBITS_TCOMP; k++) {
          int fixed = 0;
          const char * qdesc = NULL; /* Description of quality */
          const char * qstr = NULL;  /* Quality string identifier */
          qstr = smf_qual_str( SMF__QFAM_TCOMP, 1, k, &qdesc, status );

          /* Set the quality name */
          irqAddqn( qlocs, qstr, 0, qdesc, status );
          curbit++;
          irqFxbit( qlocs, qstr, curbit, &fixed, status );
        }

        /* compress them */
        for( iw = 0; iw < nw; iw++ ) {
          pdata = job_data + iw;
          pdata->operation = 3;
          pdata->qmap = qmap;
          thrAddJob( wf, 0, pdata, smf1_qual_unmap, 0, NULL, status );
        }
        thrWait( wf, status );

      }
    }

    /* Unmap quality */
    ndfUnmap( indf, "QUALITY", status );

    /* Set the badbits mask to enable all quality by default.
       Do not do this for MAP quality at the moment. */
    if (family != SMF__QFAM_MAP) ndfSbb( 255, indf, status );

    /* release IRQ resources */
    irqRlse( &qlocs, status );
  }

 CLEANUP:
  /* Tidy up */
  qual = astFree( qual );
  job_data = astFree( job_data );
  return NULL;

}
Ejemplo n.º 4
0
void smurf_fts2_transcorr(int* status)
{
  if( *status != SAI__OK ) { return; }

  char filename[GRP__SZNAM+1]; /* Filename */
  char *pname        = NULL; /* Pointer to filename */
  int bolCount       = 0;    /* Number of bolometers */
  int bolIndex       = 0;    /* Bolometer index */
  int count;
  int dims[NDF__MXDIM];
  int debug          = 0;    /* If not debug, include dry component */
  int ftsExists      = 0;
  int index          = 0;
  int indf;                  /* NDF identifier for TAU file */
  int KERNELLENGTH   = 101;
  int nbolX          = 0;    /* Width of the source subarray */
  int nbolY          = 0;    /* Height of the source subarray */
  int ndfTau;
  int ndim;
  int nPWV           = 0;
  int nWN            = 0;
  int N              = 0;    /* Sample count */
  int i              = 0;    /* Index */
  int j              = 0;    /* Index */
  int k              = 0;    /* Index */
  int place;
  double AM          = 0.0;  /* Airmass at ZPD */
  double DELTAPWV    = 0.0;
  double PWV0        = 0.0;
  double PWV         = 0.0;  /* PWV at ZPD */
  double wnFact      = 0.0;  /* Wave number factor */
  double* inPntr     = NULL; /* Pointer to the input data */
  double* outPntr    = NULL; /* Pointer to the output data */
  double* wnScan     = NULL;
  double* wnTau      = NULL;
  double* TAtm       = NULL;
  double* TAtmNew    = NULL;
  double* GAUSSIANKERNEL = NULL;
  double* PWVARR     = NULL;
  double* PWVNEW     = NULL;
  double* TAUNEW     = NULL;
  double* TAUWET     = NULL;
  double* TMPARR     = NULL;
  Grp* inGrp         = NULL; /* Input group */
  Grp* outGrp        = NULL; /* Output group */
  Grp* tauGrp        = NULL; /* TAU WET group */
  HDSLoc* loc        = NULL; /* HDS location */
  size_t fIndex      = 0;    /* File loop counter */
  size_t inSize      = 0;    /* Size of the input group */
  size_t outSize     = 0;    /* Size of the output group */
  size_t tauSize     = 0;    /* Size of the tau group */
  smfData* inData    = NULL; /* Pointer to input data */
  smfData* outData   = NULL; /* Pointer to output data */
  smfData* tauData   = NULL; /* Pointer to tau dry data */
  void* TAU[]        = {NULL, NULL}; /* {dry, wet} */

  const double SQRT2PI  = 2.50662827463100050242;
  const double SQRT2LN2 = 1.17741002251547469101;

  // GET INPUT GROUP
  kpg1Rgndf("IN", 0, 1, "", &inGrp, &inSize, status);
  // GET OUTPUT GROUP
  kpg1Wgndf("OUT", outGrp, inSize, inSize,
            "Equal number of input and output files expected!",
            &outGrp, &outSize, status);
  // GET TAU GROUP
  kpg1Gtgrp("TAU", &tauGrp, &tauSize, status);

  parGet0l("DEBUG", &debug, status);

  ndfBegin();

  // ===========================================================================
  // GET TAU INFORMATION
  // ===========================================================================
  int dryOK = 0;
  int wetOK = 0;
  pname = filename;
  grpGet(tauGrp, 1, 1, &pname, sizeof(filename), status);
  ndgNdfas(tauGrp, 1, "READ", &indf, status );
  if (indf == NDF__NOID) {
    *status = SAI__ERROR;
    msgSetc("FILE", filename);
    errRep("", FUNC_NAME ": Could not locate file ^FILE", status);
    return;
  }
  ndfXstat(indf, "FTS2", &ftsExists, status);
  if(*status == SAI__OK && ftsExists) {
    ndfXloc(indf, "FTS2", "READ", &loc, status);
    if(*status == SAI__OK && loc != NULL) {
      // DRY COMPONENT
      ndfOpen(loc, "DRY", "READ", "UNKNOWN", &ndfTau, &place, status);
      if(*status == SAI__OK && ndfTau != NDF__NOID) {
        ndfDim(ndfTau, NDF__MXDIM, dims, &ndim, status);
        if(*status == SAI__OK && ndim == 1) {
          ndfMap(ndfTau, "DATA", "_DOUBLE", "READ", &TAU[0], &count, status);
          dryOK = 1;
        }
      }
      // WET COMPONENT
      ndfOpen(loc, "WET", "READ", "UNKNOWN", &ndfTau, &place, status);
      if(*status == SAI__OK && ndfTau != NDF__NOID) {
        ndfDim(ndfTau, NDF__MXDIM, dims, &ndim, status);
        if(*status == SAI__OK && ndim == 2) {
          ndfMap(ndfTau, "DATA", "_DOUBLE", "READ", &TAU[1], &count, status);
          wetOK = 1;
        }
      }
    }
  }
  if(loc) { datAnnul(&loc, status); }
  if(!(dryOK && wetOK)) {
    *status = SAI__ERROR;
    errRep("", FUNC_NAME ": Unable to obtain TAU values!", status);
    return;
  }

  smf_open_file(NULL, tauGrp, 1, "READ", 0, &tauData, status);
  smf_fits_getD(tauData->hdr, "PWV0", &PWV0, status);
  smf_fits_getD(tauData->hdr, "DELTAPWV", &DELTAPWV, status);
  if(*status != SAI__OK) {
    *status = SAI__ERROR;
    errRep("", FUNC_NAME ": Unable to obtain PWV value(s)!", status);
    return;
  }

  nWN  = dims[0];
  nPWV = dims[1];
  PWVARR = astMalloc(nPWV * sizeof(*PWVARR));
  for(i = 0; i < nPWV; i++) {
    PWVARR[i] = PWV0 + i * DELTAPWV;
  }
  PWVNEW = astMalloc(1 * sizeof(*PWVNEW));
  TAUNEW = astMalloc(1 * sizeof(*TAUNEW));

  // ===========================================================================
  // LOOP THROUGH EACH NDF FILE IN THE INPUT GROUP
  // ===========================================================================
  for(fIndex = 1; fIndex <= inSize; fIndex++) {
    // OPEN INPUT FILE
    smf_open_file(NULL, inGrp, fIndex, "READ", 0, &inData, status);
    if(*status != SAI__OK) {
      *status = SAI__ERROR;
      errRep(FUNC_NAME, "Unable to open source file!", status);
      break;
    }

    outData = smf_deepcopy_smfData(NULL, inData, 0, SMF__NOCREATE_DATA, 0, 0, status);
    if(*status == SAI__OK) {
      inPntr   = inData->pntr[0];
      nbolX    = inData->dims[0];
      nbolY    = inData->dims[1];
      N        = inData->dims[2];
      bolCount = nbolX * nbolY;

      outData->dtype   = SMF__DOUBLE;
      outData->ndims   = 3;
      outData->dims[0] = inData->dims[0];
      outData->dims[1] = inData->dims[1];
      outData->dims[2] = inData->dims[2];
      outData->lbnd[0] = outData->lbnd[0];
      outData->lbnd[1] = outData->lbnd[1];
      outData->lbnd[2] = outData->lbnd[2];
      outData->pntr[0] = (double*) astMalloc( (N * bolCount)*sizeof(double) );
      outPntr          = outData->pntr[0];

      // DETERMINE WAVENUMBER FACTOR FROM FITS
      smf_fits_getD(inData->hdr, "WNFACT", &wnFact, status);
      if(*status != SAI__OK) {
        errRep(FUNC_NAME, "Unable to find wave number factor!", status);
        smf_close_file( NULL,&inData, status);
        break;
      }

      // TODO
      // DETERMINE AIRMASS AT ZPD

      // TODO
      // DETERMINE PWV AT ZPD
      PWVNEW[0] = PWV;

      // GET TAU WET FOR CORRESPONDING PWV
      TAUWET = astMalloc(nWN * sizeof(*TAUWET));
      TMPARR = astMalloc(nWN * sizeof(*TMPARR));
      for(k = 0; k < nWN; k++) {
        for(j = 0; j < nPWV; j++) {
          TMPARR[j] = *((double*) TAU[1] + j);
        }
        fts2_naturalcubicsplineinterpolator(PWVARR, TMPARR, nPWV, PWVNEW, TAUNEW, 1);
        TAUWET[k] = TAUNEW[0];
      }
      astFree(TMPARR);

      // COMPUTE ATMOSPHERIC TRANSMISSION
      // TATM = EXP(-AIRMASS * (PWV * TAUWET + TAUDRY))
      TAtm = astMalloc(nWN * sizeof(*TAtm));
      if(!debug) {
        for(i = 0; i < nWN; i++) {
          TAtm[i] = exp(-AM * (PWV * TAUWET[i] + (*((double*) TAU[0] + i))));
        }
      } else {
        for(i = 0; i < nWN; i++) {
          TAtm[i] = exp(-AM * PWV * TAUWET[i]);
        }
      }

      // SMOOTH ATMOSPHERIC TRANSMISSION VIA GAUSSIAN CONVOLUTION
      // NEED TO TRIM FROM BOTH ENDS BY HALF OF (KERNELLENGTH - 1)
      double OPDMAX = 1.0;
      double FWHM   = 1.0 / (2.0 * OPDMAX);   // FWHM = 1 / (2 x OPDMAX)
      double SDEV   = 0.5 * FWHM / SQRT2LN2;  // FWHM = 2 x SQRT(2ln2) x SDEV
      double VAR    = SDEV * SDEV;
      double VAR2   = 2.0 * VAR;
      double NORM   = 1.0 / (SDEV * SQRT2PI);
      double XMIN   = -6 * SDEV;
      double XMAX   =  6 * SDEV;
      double DX = (XMAX - XMIN) / (KERNELLENGTH - 1);
      double X = XMIN;
      for(i = 0; i < KERNELLENGTH; i++) {
        X = XMIN + i * DX;
        GAUSSIANKERNEL[i] = NORM * exp(-(X * X) / VAR2);
      }
      int M = nWN + KERNELLENGTH - 1;
      TMPARR = astMalloc(M * sizeof(*TMPARR));
      for(i = 0; i < nWN; i++) {
        for(j = 0; j < KERNELLENGTH; j++) {
          TMPARR[i + j] += (TAtm[i] * GAUSSIANKERNEL[j]);
        }
      }
      int OFFSET = (KERNELLENGTH - 1) >> 1;
      for(i = 0; i < nWN; i++) {
        TAtm[i] = TMPARR[i + OFFSET];
      }
      astFree(TMPARR);

      // INTERPOLATE ATMOSPHERIC TRANSMISSION ONTO SCAN RESOLUTION
      wnTau = astMalloc(nWN * sizeof(*wnTau));
      wnScan = astMalloc(N * sizeof(*wnScan));
      TAtmNew = astMalloc(N * sizeof(*TAtmNew));
      for(i = 0; i < N; i++) {
        wnScan[i] = i * wnFact;
      }
      for(i = 0; i < nWN; i++) {
        wnTau[i] = i;
      }
      fts2_naturalcubicsplineinterpolator(wnTau, TAtm, nWN, wnScan, TAtmNew, N);

      // TSOURCE = TOBS / TATM
      for(i = 0; i < nbolY; i++) {
        for(j = 0; j < nbolX; j++) {
          bolIndex = i + j * nbolY;
          for(k = 0; k < N; k++) {
            index = bolIndex + bolCount * k;
            outPntr[index] = inPntr[index] / TAtmNew[k];
          }
        }
      }
      astFree(wnTau);
      astFree(wnScan);
      astFree(TAtm);
      astFree(TAtmNew);

      smf_write_smfData(NULL, outData, NULL, NULL, outGrp, fIndex, 0, MSG__VERB,
                        0, status);
      smf_close_file( NULL,&outData, status);
      smf_close_file( NULL,&inData, status);
    } else {
Ejemplo n.º 5
0
int smf_initial_sky( ThrWorkForce *wf, AstKeyMap *keymap, smfDIMMData *dat,
                     int *iters, int *status ) {

/* Local Variables: */
   char refparam[ DAT__SZNAM ];/* Name for reference NDF parameter */
   const char *cval;          /* The IMPORTSKY string value */
   double *ptr;               /* Pointer to NDF Data array */
   double *vptr;              /* Pointer to NDF Variance array */
   int indf1;                 /* Id. for supplied reference NDF */
   int indf2;                 /* Id. for used section of reference NDF */
   int nel;                   /* Number of mapped NDF pixels */
   int result;                /* Returned flag */
   int there;                 /* Is there a smurf extension in the NDF? */
   int update;                /* Was NDF opened for UPDATE access? */
   size_t i;                  /* Loop count */
   size_t junk;               /* Unused value */

/* Initialise the returned value to indicate no sky has been subtractred. */
   result = 0;

/* Assume the sky map was not created by an interupted previous run of
   makemap. */
   *iters = -1;

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

/* Begin an AST context. */
   astBegin;

/* The IMPORTSKY config parameter should have the name of the ADAM
   parameter to use for acquiring the NDF that contains the initial sky
   estimate. If IMPORTSKY is "1", use REF. */
   cval = NULL;
   astMapGet0C( keymap, "IMPORTSKY", &cval );
   if( cval ) {
      if( !astChrMatch( cval, "REF" ) &&
          !astChrMatch( cval, "MASK2" ) &&
          !astChrMatch( cval, "MASK3" ) ) {
         astMapGet0I( keymap, "IMPORTSKY", &result );
         cval = ( result > 0 ) ? "REF" : NULL;
      }
      if( cval ) {
         result = 1;
         strcpy( refparam, cval );
         astChrCase( NULL, refparam, 1, 0 );
      }
   }

/* Do nothing more if we are not subtracting an initial sky from the data. */
   if( result && *status == SAI__OK ) {

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

/* Get an identifier for the NDF using the associated ADAM parameter.
   First try UPDATE access. If this fails try READ access. */
      ndfAssoc( refparam, "UPDATE", &indf1, status );
      if( *status != SAI__OK ) {
         errAnnul( status );
         ndfAssoc( refparam, "READ", &indf1, status );
         update = 0;
      } else {
         update = 1;
      }

/* Tell the user what we are doing. */
      ndfMsg( "N", indf1 );
      msgOut( "", "Using ^N as the initial guess at the sky", status );

/* Get a section from this NDF that matches the bounds of the map. */
      ndfSect( indf1, 2, dat->lbnd_out, dat->ubnd_out, &indf2, status );

/* Ensure masked values are not set bad in the mapped data array. */
      ndfSbb( 0, indf2, status );

/* Map the data array section, and copy it into the map buffer. */
      ndfMap( indf2, "DATA", "_DOUBLE", "READ", (void **) &ptr, &nel, status );
      if( *status == SAI__OK ) {
         memcpy( dat->map, ptr, dat->msize*sizeof(*ptr));
      }

/* Map the variance array section, and copy it into the map buffer. */
      ndfState( indf2, "VARIANCE", &there, status );
      if( there ) {
         ndfMap( indf2, "VARIANCE", "_DOUBLE", "READ", (void **) &vptr, &nel, status );
         if( *status == SAI__OK ) {
            memcpy( dat->mapvar, vptr, dat->msize*sizeof(*vptr));
         }
      }

/* If the NDF was created by a previous run of makemap that was interupted
   using control-C, it will contain a NUMITER item in the smurf extension,
   which gives the number of iterations that were completed before the
   map was created. Obtain and return this value, if it exists. */
      ndfXstat( indf1, SMURF__EXTNAME, &there, status );
      if( there ) ndfXgt0i( indf1, SMURF__EXTNAME, "NUMITER", iters,
                            status );

/* If the NDF has a Quality component, import it and create initial AST,
   FLT, PCA, SSN and COM masks from it. These will often be over-ridden by
   new masks calculated with smf_calcmodel_ast below, but will not be
   over-written if the masks have been frozen by xxx.zero_freeze. */
      ndfState( indf2, "Quality", &there, status );
      if( there && dat->mapqual ) {
         smf_qual_t *qarray = smf_qual_map( wf, indf2, "Read", NULL, &junk,
                                            status );
         if( *status == SAI__OK ) {
            smf_qual_t *pq = qarray;
            for( i = 0; i < dat->msize; i++,pq++ ) {
               if( *pq & SMF__MAPQ_AST ) {
                  if( !dat->ast_mask ) dat->ast_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->ast_mask) ) );
                  (dat->ast_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_FLT ) {
                  if( !dat->flt_mask ) dat->flt_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->flt_mask) ) );
                  (dat->flt_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_COM ) {
                  if( !dat->com_mask ) dat->com_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->com_mask) ) );
                  (dat->com_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_SSN ) {
                  if( !dat->ssn_mask ) dat->ssn_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->ssn_mask) ) );
                  (dat->ssn_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_PCA ) {
                  if( !dat->pca_mask ) dat->pca_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->pca_mask) ) );
                  (dat->pca_mask)[ i ] = 1;
               }
            }
         }
         qarray = astFree( qarray );
      }

/* Indicate the map arrays within the supplied smfDIMMData structure now
   contain usable values. We need to do this before calling
   smf_calcmodel_ast below so that the right mask gets used in
   smf_calcmodel_ast. */
      dat->mapok = 1;

/* Apply any existinction correction to the cleaned bolometer data. */
      if( dat->ext ) smf_calcmodel_ext( wf, dat, 0, keymap, dat->ext, 0,
                                        status);

/* Sample the above map at the position of each bolometer sample and
   subtract the sampled value from the cleaned bolometer value. */
      smf_calcmodel_ast( wf, dat, 0, keymap, NULL, SMF__DIMM_PREITER, status);

/* Remove any existinction correction to the modifed bolometer data. */
      if( dat->ext ) smf_calcmodel_ext( wf, dat, 0, keymap, dat->ext,
                                        SMF__DIMM_INVERT, status);

/* If the NDF was opened with UPDATE access, update the quality array in
   the NDF to reflect the AST mask created by smf_calcmodel_ast above. */
      if( update ) {
         smf_qual_t *qarray = astStore( NULL, dat->mapqual, dat->msize*sizeof(*qarray) );
         qarray = smf_qual_unmap( wf, indf2, SMF__QFAM_MAP, qarray, status );
      }

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

/* End the AST context. */
   astEnd;

/* Return the pointer to the boolean mask. */
   return result;
}
Ejemplo n.º 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 );
    }

}
Ejemplo n.º 7
0
smf_qual_t * smf_qual_unmap( int indf, smf_qfam_t family, smf_qual_t * qual, int * status ) {
  int canwrite = 0;   /* can we write to the file? */
  size_t nqbits = 0;  /* Number of quality bits in this family */

  if (*status != SAI__OK) goto CLEANUP;

  /* do nothing if there is no quality */
  if (!qual) return NULL;

  /* if we do not have an NDF identifier we just free the memory */
  if (indf == NDF__NOID) goto CLEANUP;

  /* See if we have WRITE access to the file */
  ndfIsacc( indf, "WRITE", &canwrite, status );

  /* if we have WRITE access and the data were not mapped we have
     to copy to the file. Also check we have a non-NULL input pointer.
     If the data were mapped we still have to make sure the quality names
     are stored. */
  if ( canwrite && qual ) {
    int highbit = -1; /* highest bit used */
    size_t i;
    int itemp;
    int lowbit = -1;  /* Lowest bit used */
    size_t nout;
    int nqual = 0;
    void *qpntr[1];
    size_t qcount[SMF__NQBITS]; /* statically allocate the largest array */
    IRQLocs *qlocs;
    unsigned char * qmap;
    int there;

    ndfMsg( "FILE", indf );
    msgOutif( MSG__DEBUG, "", "Finalising quality for file ^FILE", status);

    if (family == SMF__QFAM_TCOMP ) {
      /* note that TCOMP is not an allowed quality because SMURF should not be
         using it anywhere in a permanent way. */
      *status = SAI__ERROR;
      ndfMsg( "NDF", indf );
      errRepf( "", "Unsupported quality family '%s' for quality unmapping of "
               "file ^NDF", status, smf_qfamily_str(family,status) );
      goto CLEANUP;
    } else if (family == SMF__QFAM_NULL) {
      /* In this case we have to assume that we just cast the quality
         to UBYTE and copy it without changing anything or naming the
         entries. Use a simple type conversion. */
      ndfMap( indf, "QUALITY", "_UBYTE", "WRITE", &qpntr[0], &itemp, status );
      qmap = qpntr[0];
      nout = itemp;

      for (i = 0; i<nout; i++) {
        qmap[i] = qual[i];
      }
      ndfUnmap( indf, "QUALITY", status );

      /* Turn on all quality */
      ndfSbb( 255, indf, status );

      /* we are finished so jump to tidy up */
      goto CLEANUP;
    }

    /* work out how many quality items are in this family */
    nqbits = smf_qfamily_count( family, status );

    /* initialize qcount */
    for (i=0; i<SMF__NQBITS; i++) {
      qcount[i] = 0;
    }

    /* how many pixels in NDF (assumed to be number in quality) */
    ndfSize( indf, &itemp, status );
    nout = itemp;

    /* Work out which bits are actually used */
    if (*status == SAI__OK) {
      size_t k;
      /* now we try to be a bit clever. It may be a mistake since we have to
         do multiple passes through "qual". First determine how many quality
         bits are actually set. */
      for (i = 0; i<nout; i++) {
        /* try all the bits */
        for( k=0; k<nqbits; k++ ) {
          if( qual[i] & BIT_TO_VAL(k) ) {
            qcount[k]++;
          }
        }
      }

      /* see how many we got */
      for (k=0; k<nqbits; k++) {
        if ( qcount[k] ) {
          nqual++;
          highbit = k;
          if (lowbit < 0) lowbit = k;
        }
      }
    }

    /* for IRQ we need to ensure the SMURF extension exists so open and annul it if it is missing.
       We are completely rewriting any IRQ information so we have to delete any previously existing
       IRQ extension. */
    irqDelet( indf, status );
    ndfXstat( indf, SMURF__EXTNAME, &there, status );
    if (!there) {
      HDSLoc * smurfloc = NULL;
      /* Create SMURF extension if it does not already exist */
      ndfXnew( indf, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &smurfloc, status );
      if (smurfloc) datAnnul( &smurfloc, status );
    }
    irqNew( indf, SMURF__EXTNAME, &qlocs, status );

    /* malloced so we need to map and copy over the values. IRQ
       names need to be set BEFORE we copy. */

    /* Map the quality component with WRITE access */
    ndfMap( indf, "QUALITY", "_UBYTE", "WRITE", &qpntr[0], &itemp, status );
    qmap = qpntr[0];

    /* we assume the number of elements in "qual" is the same as in "qmap" */
    if (*status == SAI__OK) {
      size_t k;

      /* if we only have 8 or fewer bits active we can just compress
         by mapping them to the lower 8 bits. This will work if we also
         set the IRQ quality names in the NDF. */
      if (nqual == 0 ) {
        /* easy */
        memset( qmap, 0, nout * smf_dtype_sz( SMF__UBYTE, status ) );
      } else if ( nqual <= 8 ) {
        size_t curbit = 0;

        /* and the quality names. Start at lowbit and go to highbit
           knowing that we have shifted them down so that lowbit in qual
           is bit 0 in NDF. */
        for (k=lowbit; k<=(size_t)highbit; k++) {
          if (qcount[k]) {
            int fixed = 0;             /* is bit fixed? */
            const char * qdesc = NULL; /* Description of quality */
            const char * qstr = NULL;  /* Quality string identifier */
            curbit++;
            qstr = smf_qual_str( family, 1, k, &qdesc, status );

            irqAddqn( qlocs, qstr, 0, qdesc, status );
            irqFxbit( qlocs, qstr, curbit, &fixed, status );
          }
        }

        /* shift them down */
        for (i=0; i<nout; i++) {
          curbit = 0;
          qmap[i] = 0;

          for (k=lowbit; k<=(size_t)highbit; k++) {
            /* was this bit used by this data array? */
            if (qcount[k]) {
              /* was the bit set for this location? */
              if ( qual[i]&BIT_TO_VAL(k)) {
                qmap[i] |= BIT_TO_VAL(curbit);
              }
              curbit++;
            }
          }
        }

      } else {
        size_t curbit = 0;

        /* Quality names are now needed and we have to write them
           all out because we have not compressed the bits in the
           output quality array we've only compressed the input.
           To limit the number of active bits we'd have to copy the
           compressed bits to the output and then set the quality
           names but IRQ does not let you do that so you would need
           to run through the entire array first counting which bits
           were used. */

        for (k=0; k<SMF__NQBITS_TCOMP; k++) {
          int fixed = 0;
          const char * qdesc = NULL; /* Description of quality */
          const char * qstr = NULL;  /* Quality string identifier */
          qstr = smf_qual_str( SMF__QFAM_TCOMP, 1, k, &qdesc, status );

          /* Set the quality name */
          irqAddqn( qlocs, qstr, 0, qdesc, status );
          curbit++;
          irqFxbit( qlocs, qstr, curbit, &fixed, status );
        }

        /* compress them */
        for (i = 0; i<nout; i++) {
          qmap[i] = 0;
          if (qual[i]) {
            if ( qual[i] & (SMF__Q_BADDA|SMF__Q_BADB|SMF__Q_NOISE) ) {
              qmap[i] |= SMF__TCOMPQ_BAD;
            }
            if ( qual[i] & (SMF__Q_APOD|SMF__Q_PAD) ) {
              qmap[i] |= SMF__TCOMPQ_ENDS;
            }
            if ( qual[i] & (SMF__Q_JUMP|SMF__Q_SPIKE|SMF__Q_FILT|SMF__Q_EXT|SMF__Q_LOWAP|SMF__Q_BADEF) ) {
              qmap[i] |= SMF__TCOMPQ_BLIP;
            }
            if ( qual[i] & (SMF__Q_COM) ) {
              qmap[i] |= SMF__TCOMPQ_MATCH;
            }
            if ( qual[i] & (SMF__Q_STAT) ) {
              qmap[i] |= SMF__TCOMPQ_TEL;
            }
            if (qmap[i] == 0 ) {
              /* something went wrong. We missed a quality bit somewhere */
              msgOutiff(MSG__QUIET, "", FUNC_NAME ": Untested quality bit found"
                        " in position %zu with value %u", status,
                        i, (unsigned int)qual[i]);
            }
          }
        }

      }
    }

    /* Unmap quality */
    ndfUnmap( indf, "QUALITY", status );

    /* Set the badbits mask to enable all quality by default.
       Do not do this for MAP quality at the moment. */
    if (family != SMF__QFAM_MAP) ndfSbb( 255, indf, status );

    /* release IRQ resources */
    irqRlse( &qlocs, status );
  }

 CLEANUP:
  /* Tidy up */
  if (qual) qual = astFree( qual );
  return NULL;

}