Beispiel #1
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;

}
Beispiel #2
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 );

}
Beispiel #3
0
// Reads an NDF into a numpy array
static PyObject*
pyndf_read(NDF *self, PyObject *args)
{
    int i;
    const char *comp;
    if(!PyArg_ParseTuple(args, "s:pyndf_read", &comp))
	return NULL;

    // series of declarations in an attempt to avoid problem with
    // goto fail
    const int MXLEN=32;
    char type[MXLEN+1];
    size_t nbyte;
    int npix, nelem;

    // Return None if component does not exist
    int state, status = SAI__OK;
    errBegin(&status);
    ndfState(self->_ndfid, comp, &state, &status);
    if (raiseNDFException(&status)) return NULL;
    if(!state)
	Py_RETURN_NONE;

    PyArrayObject* arr = NULL;

    // Get dimensions, reverse order to account for C vs Fortran
    int idim[NDF__MXDIM];
    npy_intp rdim[NDF__MXDIM];

    int ndim;
    errBegin(&status);
    ndfDim(self->_ndfid, NDF__MXDIM, idim, &ndim, &status);
    if (raiseNDFException(&status)) return NULL;

    // Reverse order to account for C vs Fortran
    for(i=0; i<ndim; i++) rdim[i] = idim[ndim-i-1];

    // Determine the data type
    errBegin(&status);
    ndfType(self->_ndfid, comp, type, MXLEN+1, &status);
    if (raiseNDFException(&status)) return NULL;

    // Create array of correct dimensions and type to save data to
    int npytype = ndftype2numpy( type, &nbyte );
    if (npytype == 0) return NULL;
    arr = (PyArrayObject*) PyArray_SimpleNew(ndim, rdim, npytype);
    if(arr == NULL) goto fail;

    // get number of elements, allocate space, map, store

    errBegin(&status);
    ndfSize(self->_ndfid, &npix, &status);
    if (raiseNDFException(&status)) goto fail;
    void *pntr[1];
    errBegin(&status);
    ndfMap(self->_ndfid, comp, type, "READ", pntr, &nelem, &status);
    if (raiseNDFException(&status)) goto fail;
    if(nelem != npix){
	PyErr_SetString(PyExc_IOError, "ndf_read error: number of elements different from number expected");
	goto fail;
    }
    memcpy(arr->data, pntr[0], npix*nbyte);
    errBegin(&status);
    ndfUnmap(self->_ndfid, comp, &status);
    if (raiseNDFException(&status)) goto fail;

    return Py_BuildValue("N", PyArray_Return(arr));

fail:
    Py_XDECREF(arr);
    return NULL;
};
Beispiel #4
0
smf_qual_t * smf_qual_map( ThrWorkForce *wf, int indf, const char mode[],
                           smf_qfam_t *family, size_t *nmap, int * status ) {

  size_t i;             /* Loop counter */
  int itemp = 0;        /* temporary int */
  smf_qfam_t lfamily = SMF__QFAM_NULL; /* Local quality family */
  size_t nout;          /* Number of elements mapped */
  size_t numqn = 0;     /* number of quality names */
  IRQLocs *qlocs = NULL;/* IRQ Quality */
  unsigned char *qmap;  /* pointer to mapped unsigned bytes */
  void *qpntr[1];       /* Somewhere to put the mapped pointer */
  smf_qual_t *retval = NULL; /* Returned pointer */
  int there;            /* Does the NDF Have a Quality component? */
  char xname[DAT__SZNAM+1];  /* Name of extension holding quality names */
  SmfQualMapData *job_data = NULL;
  SmfQualMapData *pdata;
  int nw;
  size_t step;
  int iw;


  if (*status != SAI__OK) return retval;

  /* Ensure jobs submitted to the workforce within this function are
     handled separately to any jobs submitted earlier (or later) by any
     other function. */
  thrBeginJobContext( wf, status );

  /* how many elements do we need */
  ndfSize( indf, &itemp, status );
  nout = itemp;
  if (nmap) *nmap = nout;

  /* malloc the QUALITY buffer. Initialise to zero to simplify logic
     below. It is difficult to determine in advance which case can use
     initialisation. */
  retval = astCalloc( nout, sizeof(*retval) );

  /* 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->retval = retval;

    }
  }

  /* If the NDF has no QUality component, return the buffer filled with
     zeros. */
  ndfState( indf, "QUALITY", &there, status );
  if( there ) {

    /* READ and UPDATE mode require that the QUALITY is processed
       and copied before being returned. WRITE mode means that the
       buffer contains no information to copy yet. WRITE/ZERO
       and WRITE/BAD also require that we do not do any quality
       handling */
    if ( strncmp(mode, "WRITE",5) == 0 ) {
      /* WRITE and WRITE/ZERO are actually treated the same way
         because we always initialise */
      if ( strcmp( mode, "WRITE/BAD") == 0 ) {
        for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->operation = 1;
            thrAddJob( wf, 0, pdata, smf1_qual_map, 0, NULL, status );
        }
        thrWait( wf, status );
      }

      /* unmap the NDF buffer and return the pointer */
      if (family) *family = lfamily;
      return retval;
    }

    /* Map the quality component (we always need to do this) */
    ndfMap( indf, "QUALITY", "_UBYTE", mode, &qpntr[0], &itemp, status );
    qmap = qpntr[0];

    /* Need to find out what quality names are in play so we
       can work out which family to translate them to */
    irqFind( indf, &qlocs, xname, status );
    numqn = irqNumqn( qlocs, status );

    if ( *status == IRQ__NOQNI || numqn == 0) {
      /* do not have any names defined so we have no choice
         in copying the values directly out the file */
      if (*status != SAI__OK) errAnnul( status );

      /* simple copy with type conversion */

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

    } else {
      IRQcntxt contxt = 0;
      int ndfqtosmf[NDFBITS];        /* NDF bit (arr index) and SMURF alternative */
      int ndfqtoval[NDFBITS];        /* NDF bit (arr index) and corresponding Qual value */
      int ndfqval[NDFBITS];          /* Bit values for NDF quality */
      int identity = 1;        /* Is this a simple identity map? */

      /* prefill the mapping with bit to bit mapping */
      for (i=0; i<NDFBITS; i++) {
        ndfqtosmf[i] = i;
        ndfqtoval[i] = BIT_TO_VAL(i);
        ndfqval[i] = ndfqtoval[i];
      }

      /* Now translate each name to a bit */
      for (i = 0; i < numqn && *status == SAI__OK; i++) {
        char qname[IRQ__SZQNM+1];
        char commnt[IRQ__SZCOM+1];
        int fixed;
        int value;
        int bit;
        int done;
        smf_qual_t qval;
        smf_qfam_t tmpfam = 0;

        irqNxtqn( qlocs, &contxt, qname, &fixed, &value, &bit,
                  commnt,sizeof(commnt), &done, status );
        bit--;    /* IRQ starts at 1 */

        /* Now convert the quality name to a quality value
           and convert that to a bit. These should all be
           less than 9 bits because they are in the NDF file. */
        qval = smf_qual_str_to_val( qname, &tmpfam, status );

        if (*status == SMF__BADQNM ) {
          /* annul status and just copy this bit from the file
             to SMURF without change. This might result in a clash
             of bits but we either do that or drop out the loop
             and assume everything is broken */
          if (*status != SAI__OK) errAnnul(status);
          ndfqtosmf[bit] = bit;
          ndfqtoval[bit] = BIT_TO_VAL(bit);

        } else if( *status == SAI__OK ){
          if (lfamily == SMF__QFAM_NULL) {
            lfamily = tmpfam;
          } else if (lfamily != tmpfam) {
            msgOutif(MSG__QUIET, "",
                     "WARNING: Quality names in file come from different families",
                     status );
          }
          ndfqtosmf[bit] = smf_qual_to_bit( qval, status );
          ndfqtoval[bit] = qval;

          /* not a 1 to 1 bit translation */
          if (bit != ndfqtosmf[bit]) identity = 0;
        }
      }

      /* Now copy from the file and translate the bits. If this is an
         identity mapping or we do not know the family then we go quick. */
      if (*status == SAI__OK) {
        if ( (identity && lfamily != SMF__QFAM_TCOMP) || lfamily == SMF__QFAM_NULL) {
          for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->qmap = qmap;
            pdata->ndfqval = ndfqval;
            pdata->lfamily = lfamily;
            pdata->ndfqtoval = ndfqtoval;
            pdata->ndfqval = ndfqval;
            pdata->operation = 2;
            thrAddJob( wf, 0, pdata, smf1_qual_map, 0, NULL, status );
          }
          thrWait( wf, status );

        } else {

          for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->qmap = qmap;
            pdata->ndfqval = ndfqval;
            pdata->lfamily = lfamily;
            pdata->ndfqtoval = ndfqtoval;
            pdata->ndfqval = ndfqval;
            pdata->operation = 3;
            thrAddJob( wf, 0, pdata, smf1_qual_map, 0, NULL, status );
          }
          thrWait( wf, status );

          /* we have uncompressed */
          if (lfamily == SMF__QFAM_TCOMP) lfamily = SMF__QFAM_TSERIES;
        }
      }
    }

    /* Free quality */
    irqRlse( &qlocs, status );

    /* no longer need the mapped data */
    ndfUnmap( indf, "QUALITY", status );
  }

  /* End the Thr job context */
  thrEndJobContext( wf, status );

  /* Free other resources. */
  job_data = astFree( job_data );

  if (family) *family = lfamily;
  return retval;
}
Beispiel #5
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;

}