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; }
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; }
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; }