void smf_calc_mapcoord( ThrWorkForce *wf, AstKeyMap *config, smfData *data, AstFrameSet *outfset, int moving, int *lbnd_out, int *ubnd_out, fts2Port fts_port, int flags, int *status ) { /* Local Variables */ AstSkyFrame *abskyfrm = NULL;/* Output SkyFrame (always absolute) */ AstMapping *bolo2map=NULL; /* Combined mapping bolo->map coordinates */ int bndndf=NDF__NOID; /* NDF identifier for map bounds */ void *data_pntr[1]; /* Array of pointers to mapped arrays in ndf */ int *data_index; /* Mapped DATA_ARRAY part of NDF */ int docalc=1; /* If set calculate the LUT */ int doextension=0; /* Try to write LUT to MAPCOORD extension */ smfFile *file=NULL; /* smfFile pointer */ AstObject *fstemp = NULL; /* AstObject version of outfset */ int ii; /* loop counter */ int indf_lat = NDF__NOID; /* Identifier for NDF to receive lat values */ int indf_lon = NDF__NOID; /* Identifier for NDF to receive lon values */ smfCalcMapcoordData *job_data=NULL; /* Array of job */ int lbnd[1]; /* Pixel bounds for 1d pointing array */ int lbnd_old[2]; /* Pixel bounds for existing LUT */ int lbnd_temp[1]; /* Bounds for bounds NDF component */ int lutndf=NDF__NOID; /* NDF identifier for coordinates */ AstMapping *map2sky_old=NULL;/* Existing mapping map->celestial coord. */ HDSLoc *mapcoordloc=NULL; /* HDS locator to the MAPCOORD extension */ int nw; /* Number of worker threads */ AstFrameSet *oldfset=NULL; /* Pointer to existing WCS info */ AstSkyFrame *oskyfrm = NULL; /* SkyFrame from the output WCS Frameset */ smfCalcMapcoordData *pdata=NULL; /* Pointer to job data */ double *lat_ptr = NULL; /* Pointer to array to receive lat values */ double *lon_ptr = NULL; /* Pointer to array to receive lon values */ int ubnd[1]; /* Pixel bounds for 1d pointing array */ int ubnd_old[2]; /* Pixel bounds for existing LUT */ int ubnd_temp[1]; /* Bounds for bounds NDF component */ int *lut = NULL; /* The lookup table */ dim_t nbolo=0; /* Number of bolometers */ dim_t ntslice=0; /* Number of time slices */ int nmap; /* Number of mapped elements */ AstMapping *sky2map=NULL; /* Mapping celestial->map coordinates */ size_t step; /* step size for dividing up work */ AstCmpMap *testcmpmap=NULL; /* Combined forward/inverse mapping */ AstMapping *testsimpmap=NULL;/* Simplified testcmpmap */ double *theta = NULL; /* Scan direction at each time slice */ int tstep; /* Time slices between full Mapping calculations */ int exportlonlat; /* Dump longitude and latitude values? */ /* Main routine */ if (*status != SAI__OK) return; /* How many threads do we get to play with */ nw = wf ? wf->nworker : 1; /* Initialize bounds to avoid compiler warnings */ lbnd_old[0] = 0; lbnd_old[1] = 0; ubnd_old[0] = 0; ubnd_old[1] = 0; /* Check for pre-existing LUT and de-allocate it. This will only waste time if the MAPCOORD extension is found to be valid and it has to be re-loaded from disk. */ smf_close_mapcoord( data, status ); /* Assert ICD data order */ smf_dataOrder( data, 1, status ); /* Get the data dimensions */ smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, NULL, NULL, NULL, status ); /* If SMF__NOCREATE_FILE is not set, and file associated with an NDF, map a new MAPCOORD extension (or verify an existing one) */ if( !(flags & SMF__NOCREATE_FILE) && data->file ) { doextension = 1; } else { doextension = 0; docalc = 1; } /* Create / check for existing MAPCOORD extension */ if( doextension ) { file = data->file; /* Check type of file before proceeding */ if( file->isSc2store ) { *status = SAI__ERROR; errRep(FUNC_NAME, "File was opened by sc2store library (raw data?)", status); } if( !file->isTstream ) { *status = SAI__ERROR; errRep(FUNC_NAME, "File does not contain time stream data",status); } /* Get HDS locator to the MAPCOORD extension */ mapcoordloc = smf_get_xloc( data, "MAPCOORD", "MAP_PROJECTION", "UPDATE", 0, 0, status ); /* Obtain NDF identifier/placeholder for LUT in MAPCOORD extension*/ lbnd[0] = 0; ubnd[0] = nbolo*ntslice-1; lutndf = smf_get_ndfid( mapcoordloc, "LUT", "UPDATE", "UNKNOWN", "_INTEGER", 1, lbnd, ubnd, status ); if( *status == SAI__OK ) { /* store the NDF identifier */ file->mapcoordid = lutndf; /* Create sky to output grid mapping using the base coordinates to get the coordinates of the tangent point if it hasn't been done yet. */ sky2map = astGetMapping( outfset, AST__CURRENT, AST__BASE ); } /* Before mapping the LUT, first check for existing WCS information and LBND/UBND for the output map. If they are already correct don't bother re-calculating the LUT! */ if( *status == SAI__OK ) { /* Try reading in the WCS information */ kpg1Wread( mapcoordloc, "WCS", &fstemp, status ); oldfset = (AstFrameSet*)fstemp; if( *status == SAI__OK ) { /* Check that the old and new mappings are the same by checking that combining one with the inverse of the other reduces to a UnitMap. */ map2sky_old = astGetMapping( oldfset, AST__BASE, AST__CURRENT ); testcmpmap = astCmpMap( map2sky_old, sky2map, 1, " " ); testsimpmap = astSimplify( testcmpmap ); if( astIsAUnitMap( testsimpmap ) ) { /* The mappings are the same, now just check the pixel bounds in the output map */ lbnd_temp[0] = 1; ubnd_temp[0] = 2; bndndf = smf_get_ndfid( mapcoordloc, "LBND", "READ", "UNKNOWN", "_INTEGER", 1, lbnd_temp, ubnd_temp, status ); if( *status == SAI__OK ) { ndfMap( bndndf, "DATA", "_INTEGER", "READ", data_pntr, &nmap, status ); data_index = data_pntr[0]; if( *status == SAI__OK ) { lbnd_old[0] = data_index[0]; lbnd_old[1] = data_index[1]; } ndfAnnul( &bndndf, status ); } bndndf = smf_get_ndfid( mapcoordloc, "UBND", "READ", "UNKNOWN", "_INTEGER", 1, lbnd_temp, ubnd_temp, status ); if( *status == SAI__OK ) { ndfMap( bndndf, "DATA", "_INTEGER", "READ", data_pntr, &nmap, status ); data_index = data_pntr[0]; if( *status == SAI__OK ) { ubnd_old[0] = data_index[0]; ubnd_old[1] = data_index[1]; } ndfAnnul( &bndndf, status ); } if( *status == SAI__OK ) { /* If we get this far finally do the bounds check! */ if( (lbnd_old[0] == lbnd_out[0]) && (lbnd_old[1] == lbnd_out[1]) && (ubnd_old[0] == ubnd_out[0]) && (ubnd_old[1] == ubnd_out[1]) ) { docalc = 0; /* We don't have to re-calculate the LUT */ msgOutif(MSG__VERB," ",FUNC_NAME ": Existing LUT OK", status); } } } /* Bad status / AST errors at this point due to problems with MAPCOORD. Annul and continue calculating new MAPCOORD extension. */ astClearStatus; errAnnul(status); } else { /* Bad status due to non-existence of MAPCOORD. Annul and continue */ errAnnul(status); } } } /* If we need to calculate the LUT do it here */ if( docalc && (*status == SAI__OK) ) { msgOutif(MSG__VERB," ", FUNC_NAME ": Calculate new LUT", status); /* Get the increment in time slices between full Mapping calculations. The Mapping for intermediate time slices will be approximated. */ dim_t dimval; smf_get_nsamp( config, "TSTEP", data, &dimval, status ); tstep = dimval; /* Get space for the LUT */ if( doextension ) { /* Map the LUT array */ ndfMap( lutndf, "DATA", "_INTEGER", "WRITE", data_pntr, &nmap, status ); data_index = data_pntr[0]; if( *status == SAI__OK ) { lut = data_index; } else { errRep( FUNC_NAME, "Unable to map LUT in MAPCOORD extension", status); } } else { /* alloc the LUT and THETA arrays */ lut = astMalloc( (nbolo*ntslice)*sizeof(*(data->lut)) ); theta = astMalloc( ntslice*sizeof(*(data->theta)) ); } /* Retrieve the sky2map mapping from the output frameset (actually map2sky) */ oskyfrm = astGetFrame( outfset, AST__CURRENT ); sky2map = astGetMapping( outfset, AST__BASE, AST__CURRENT ); /* If the longitude and latitude is being dumped, create new NDFs to hold them, and map them. */ if( config ) { astMapGet0I( config, "EXPORTLONLAT", &exportlonlat ); if( exportlonlat ) { lon_ptr = smf1_calc_mapcoord1( data, nbolo, ntslice, oskyfrm, &indf_lon, 1, status ); lat_ptr = smf1_calc_mapcoord1( data, nbolo, ntslice, oskyfrm, &indf_lat, 2, status ); } } /* Invert the mapping to get Output SKY to output map coordinates */ astInvert( sky2map ); /* Create a SkyFrame in absolute coordinates */ abskyfrm = astCopy( oskyfrm ); astClear( abskyfrm, "SkyRefIs" ); astClear( abskyfrm, "SkyRef(1)" ); astClear( abskyfrm, "SkyRef(2)" ); if( *status == SAI__OK ) { /* --- Begin parellelized portion ------------------------------------ */ /* Start a new job context. Each call to thrWait within this context will wait until all jobs created within the context have completed. Jobs created in higher contexts are ignored by thrWait. */ thrBeginJobContext( wf, status ); /* Allocate job data for threads */ job_data = astCalloc( nw, sizeof(*job_data) ); if( *status == SAI__OK ) { /* Set up job data, and start calculating pointing for blocks of time slices in different threads */ if( nw > (int) ntslice ) { step = 1; } else { step = ntslice/nw; } for( ii=0; (*status==SAI__OK)&&(ii<nw); ii++ ) { pdata = job_data + ii; /* Blocks of time slices */ pdata->t1 = ii*step; pdata->t2 = (ii+1)*step-1; /* Ensure that the last thread picks up any left-over tslices */ if( (ii==(nw-1)) && (pdata->t1<(ntslice-1)) ) { pdata->t2=ntslice-1; } pdata->ijob = -1; pdata->lut = lut; pdata->theta = theta; pdata->lbnd_out = lbnd_out; pdata->moving = moving; pdata->ubnd_out = ubnd_out; pdata->tstep = tstep; pdata->lat_ptr = lat_ptr; pdata->lon_ptr = lon_ptr; pdata->fts_port = fts_port; /* Make deep copies of AST objects and unlock them so that each thread can then lock them for their own exclusive use */ pdata->abskyfrm = astCopy( abskyfrm ); astUnlock( pdata->abskyfrm, 1 ); pdata->sky2map = astCopy( sky2map ); astUnlock( pdata->sky2map, 1 ); /* Similarly, make a copy of the smfData, including only the header information which each thread will need in order to make calls to smf_rebin_totmap */ pdata->data = smf_deepcopy_smfData( data, 0, SMF__NOCREATE_FILE | SMF__NOCREATE_DA | SMF__NOCREATE_FTS | SMF__NOCREATE_DATA | SMF__NOCREATE_VARIANCE | SMF__NOCREATE_QUALITY, 0, 0, status ); smf_lock_data( pdata->data, 0, status ); } for( ii=0; ii<nw; ii++ ) { /* Submit the job */ pdata = job_data + ii; pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfCalcMapcoordPar, 0, NULL, status ); } /* Wait until all of the jobs submitted within the current job context have completed */ thrWait( wf, status ); } /* End the current job context. */ thrEndJobContext( wf, status ); /* --- End parellelized portion -------------------------------------- */ /* Set the lut pointer in data to the buffer */ data->lut = lut; data->theta = theta; /* Write the WCS for the projection to the extension */ if( doextension ) { kpg1Wwrt( (AstObject*)outfset, "WCS", mapcoordloc, status ); /* Write the pixel bounds for the map to the extension */ lbnd_temp[0] = 1; /* Don't get confused! Bounds for NDF that will */ ubnd_temp[0] = 2; /* contain the bounds for the output 2d map! */ bndndf = smf_get_ndfid( mapcoordloc, "LBND", "UPDATE", "UNKNOWN", "_INTEGER", 1, lbnd_temp, ubnd_temp, status ); ndfMap( bndndf, "DATA", "_INTEGER", "WRITE", data_pntr, &nmap, status ); data_index = data_pntr[0]; if( *status == SAI__OK ) { data_index[0] = lbnd_out[0]; data_index[1] = lbnd_out[1]; } else { errRep( FUNC_NAME, "Unable to map LBND in MAPCOORD extension", status); } ndfAnnul( &bndndf, status ); bndndf = smf_get_ndfid( mapcoordloc, "UBND", "UPDATE", "UNKNOWN", "_INTEGER", 1, lbnd_temp, ubnd_temp, status ); ndfMap( bndndf, "DATA", "_INTEGER", "WRITE", data_pntr, &nmap, status ); data_index = data_pntr[0]; if( *status == SAI__OK ) { data_index[0] = ubnd_out[0]; data_index[1] = ubnd_out[1]; } else { errRep( FUNC_NAME, "Unable to map UBND in MAPCOORD extension", status); } ndfAnnul( &bndndf, status ); } } } /* Clean Up */ if( testsimpmap ) testsimpmap = astAnnul( testsimpmap ); if( testcmpmap ) testcmpmap = astAnnul( testcmpmap ); if( map2sky_old ) map2sky_old = astAnnul( map2sky_old ); if( oldfset ) oldfset = astAnnul( oldfset ); if (sky2map) sky2map = astAnnul( sky2map ); if (bolo2map) bolo2map = astAnnul( bolo2map ); if( abskyfrm ) abskyfrm = astAnnul( abskyfrm ); if( oskyfrm ) oskyfrm = astAnnul( oskyfrm ); if( mapcoordloc ) datAnnul( &mapcoordloc, status ); if( indf_lat != NDF__NOID ) ndfAnnul( &indf_lat, status ); if( indf_lon != NDF__NOID ) ndfAnnul( &indf_lon, status ); /* If we get this far, docalc=0, and status is OK, there must be a good LUT in there already. Map it so that it is accessible to the caller; "UPDATE" so that the caller can modify it if desired. */ if( (*status == SAI__OK) && (docalc == 0) ) { smf_open_mapcoord( data, "UPDATE", status ); } /* Clean up job data */ if( job_data ) { for( ii=0; (*status==SAI__OK)&&(ii<nw); ii++ ) { pdata = job_data + ii; if( pdata->data ) { smf_lock_data( pdata->data, 1, status ); smf_close_file( &(pdata->data), status ); } astLock( pdata->abskyfrm, 0 ); pdata->abskyfrm = astAnnul( pdata->abskyfrm ); astLock( pdata->sky2map, 0 ); pdata->sky2map = astAnnul( pdata->sky2map ); } job_data = astFree( job_data ); } }
void smf_flag_spikes( ThrWorkForce *wf, smfData *data, smf_qual_t mask, double thresh, size_t box, size_t *nflagged, int *status ){ /* Local Variables */ int i; /* Loop counter */ smfFlagSpikesData *job_data=NULL;/* Array of job data for each thread */ dim_t nbolo; /* Number of bolometers */ dim_t ntime; /* Number of time-slices */ double *dat = NULL; /* Pointer to bolo data */ smfFlagSpikesData *pdata=NULL;/* Pointer to job data */ int nw; /* Number of worker threads */ size_t bstride; /* Vector stride between bolometer samples */ size_t nflag; /* Number of samples flagged */ size_t tstride; /* Vector stride between time samples */ smf_qual_t *qua = NULL; /* Pointer to quality flags */ size_t step; /* step size for dividing up work */ int njobs=0; /* Number of jobs to be processed */ /* Check inherited status. Also return immediately if no spike flagging is to be performed. */ if( *status != SAI__OK || thresh == 0.0 ) return; /* How many threads do we get to play with */ nw = wf ? wf->nworker : 1; /* Check we have double precision data. */ smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status ); /* Get a pointer to the quality array to use. */ qua = smf_select_qualpntr( data, NULL, status ); /* Report an error if we have no quality array. */ if( !qua && *status == SAI__OK ) { *status = SAI__ERROR; errRep( " ", FUNC_NAME ": No valid QUALITY array was provided", status ); } /* Get a pointer to the data array to use. Report an error if we have no data array. */ dat = data->pntr[0]; if( !dat && *status == SAI__OK ) { *status = SAI__ERROR; errRep( " ", FUNC_NAME ": smfData does not contain a DATA component", status); } /* Check the supplied thresh value is valid. */ if( thresh <= 0 && *status == SAI__OK ) { *status = SAI__ERROR; msgSetd( "THRESH", thresh ); errRep( " ", FUNC_NAME ": Can't find spikes: thresh=^THRESH, must be > 0", status); } /* Check the supplied box value is valid. */ if( box <= 2 && *status == SAI__OK ) { *status = SAI__ERROR; msgSeti( "BOX", box ); errRep( " ", FUNC_NAME ": Can't find spikes: box=^BOX, must be > 2", status); } /* Obtain data dimensions, and the stride between adjacent elements on each axis (bolometer and time). Use the existing data order to avoid the cost of re-ordering. */ smf_get_dims( data, NULL, NULL, &nbolo, &ntime, NULL, &bstride, &tstride, status ); /* Check we have room for at least 3 boxes along the time axis. */ if( 3*box > ntime && *status == SAI__OK ) { *status = SAI__ERROR; msgSeti( "BOX", box ); msgSeti( "MAX", ntime/3 - 1 ); errRep( " ", FUNC_NAME ": Can't find spikes: box=^BOX is too large, " " must be < ^MAX.", status); } /* Set up the job data */ if( nw > (int) nbolo ) { step = 1; } else { step = nbolo/nw; if( !step ) { step = 1; } } job_data = astCalloc( nw, sizeof(*job_data) ); for( i=0; (*status==SAI__OK)&&i<nw; i++ ) { pdata = job_data + i; pdata->b1 = i*step; pdata->b2 = (i+1)*step-1; /* if b1 is greater than the number of bolometers, we've run out of jobs... */ if( pdata->b1 >= nbolo ) { break; } /* increase the jobs counter */ njobs++; /* Ensure that the last thread picks up any left-over bolometers */ if( (i==(nw-1)) && (pdata->b1<(nbolo-1)) ) { pdata->b2=nbolo-1; } pdata->ijob = -1; /* Flag job as ready to start */ pdata->box = box; pdata->bstride = bstride; pdata->dat = dat; pdata->mask = mask; pdata->thresh = thresh; pdata->nbolo = nbolo; pdata->ntime = ntime; pdata->qua = qua; pdata->tstride = tstride; } /* Submit jobs to find spikes in each block of bolos */ thrBeginJobContext( wf, status ); for( i=0; (*status==SAI__OK)&&i<njobs; i++ ) { pdata = job_data + i; pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfFlagSpikesPar, 0, NULL, status ); } /* Wait until all of the submitted jobs have completed */ thrWait( wf, status ); thrEndJobContext( wf, status ); /* Count flagged samples from all of the jobs and free resources */ nflag=0; if( job_data ) { for( i=0; i<njobs; i++ ) { pdata = job_data + i; nflag += pdata->nflag; } job_data = astFree( job_data ); } /* Return the number of flagged samples, if requested */ if( nflagged ) *nflagged = nflag; }
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; }
void smf_fillgaps( ThrWorkForce *wf, smfData *data, smf_qual_t mask, int *status ) { /* Local Variables */ const gsl_rng_type *type; /* GSL random number generator type */ dim_t bpt; /* Number of bolos per thread */ dim_t i; /* Bolometer index */ dim_t nbolo; /* Number of bolos */ dim_t ntslice; /* Number of time slices */ double *dat=NULL; /* Pointer to bolo data */ int fillpad; /* Fill PAD samples? */ size_t bstride; /* bolo stride */ size_t pend; /* Last non-PAD sample */ size_t pstart; /* First non-PAD sample */ size_t tstride; /* time slice stride */ smfFillGapsData *job_data; /* Structures holding data for worker threads */ smfFillGapsData *pdata; /* Pointer to data for next worker thread */ smf_qual_t *qua=NULL; /* Pointer to quality array */ /* Main routine */ if (*status != SAI__OK) return; /* Check we have double precision data floating point data. */ if (!smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status )) return; /* Pointers to data and quality */ dat = data->pntr[0]; qua = smf_select_qualpntr( data, NULL, status ); if( !qua ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": No valid QUALITY array was provided", status ); return; } if( !dat ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": smfData does not contain a DATA component",status); return; } /* obtain data dimensions */ smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, NULL, &bstride, &tstride, status ); /* Determine how many bolometers to process in each thread, and create the structures used to pass data to the threads. */ if( wf ) { bpt = nbolo/wf->nworker; if( wf->nworker*bpt < nbolo ) bpt++; job_data = astMalloc( sizeof( smfFillGapsData )*wf->nworker ); } else { bpt = nbolo; job_data = astMalloc( sizeof( smfFillGapsData ) ); } /* Find the indices of the first and last non-PAD sample. */ smf_get_goodrange( qua, ntslice, tstride, SMF__Q_PAD, &pstart, &pend, status ); /* Report an error if it is too short. */ if( pend - pstart <= 2*BOX && *status == SAI__OK ) { *status = SAI__ERROR; errRepf( "", FUNC_NAME ": length of data (%d samples) is too small " "to fill gaps. Must have at least %d samples per bolometer.", status, (int) ( pend - pstart ), 2*BOX + 1 ); } /* If the supplied "mask" value includes SMF__Q_PAD, then we will be replacing the zero-padded region at the start and end of each time series with artificial noisey data that connects the first and last data values smoothly. Remove SMF__Q_PAD from the mask. */ if( mask & SMF__Q_PAD ) { mask &= ~SMF__Q_PAD; fillpad = 1; } else { fillpad = 0; } /* Get the default GSL randim number generator type. A separate random number generator is used for each worker thread so that the gap filling process does not depend on the the order in which threads are executed. */ type = gsl_rng_default; /* Begin a job context. */ thrBeginJobContext( wf, status ); /* Loop over bolometer in groups of "bpt". */ pdata = job_data; for( i = 0; i < nbolo; i += bpt, pdata++ ) { /* Store information for this group in the next smfFillGapsData structure. */ pdata->ntslice = ntslice; pdata->dat = dat; pdata->r = gsl_rng_alloc( type ); pdata->b1 = i; pdata->b2 = i + bpt - 1; pdata->pend = pend; pdata->fillpad = fillpad; pdata->pstart = pstart; if( pdata->b2 >= nbolo ) pdata->b2 = nbolo - 1; pdata->bstride = bstride; pdata->tstride = tstride; pdata->qua = qua; pdata->mask = mask; /* Submit a job to the workforce to process this group of bolometers. */ (void) thrAddJob( wf, 0, pdata, smfFillGapsParallel, 0, NULL, status ); } /* Wait until all jobs in the current job context have completed, and then end the job context. */ thrWait( wf, status ); thrEndJobContext( wf, status ); /* Free resources. */ if( job_data ) { pdata = job_data; for( i = 0; i < nbolo; i += bpt, pdata++ ) { if( pdata->r ) gsl_rng_free( pdata->r ); } job_data = astFree( job_data ); } }
void smf_fit_poly( ThrWorkForce *wf, smfData *data, const size_t order, int remove, double *poly, int *status) { /* Local variables */ size_t bstride; /* bolo strides */ int i; /* Loop counter */ smfFitPolyData *job_data=NULL;/* Array of job data for each thread */ dim_t nbolo=0; /* Number of bolometers */ int njobs=0; /* Number of jobs to be processed */ dim_t ntslice = 0; /* Number of time slices */ int nw; /* Number of worker threads */ smfFitPolyData *pdata=NULL; /* Pointer to job data */ const smf_qual_t *qual; /* pointer to the quality array */ size_t step; /* step size for dividing up work */ size_t tstride; /* time strides */ /* Check status */ if (*status != SAI__OK) return; /* How many threads do we get to play with */ nw = wf ? wf->nworker : 1; /* Should check data type for double */ if (!smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status)) return; if ( smf_history_check( data, FUNC_NAME, status) ) { msgSetc("F", FUNC_NAME); msgOutif(MSG__VERB," ", "^F has already been run on these data, returning to caller", status); return; } /* Get the dimensions */ smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, NULL, &bstride, &tstride, status); /* Return with error if there is no QUALITY component */ qual = smf_select_cqualpntr( data, NULL, status ); if( !qual && (*status == SAI__OK) ) { *status = SAI__ERROR; errRep( FUNC_NAME, "Data doesn't have a QUALITY component.", status ); return; } /* Return with error if order is greater than the number of data points */ if ( order >= ntslice ) { if ( *status == SAI__OK) { msgSeti("O",order); msgSeti("NF",ntslice); *status = SAI__ERROR; errRep( FUNC_NAME, "Requested polynomial order, ^O, greater than or " "equal to the number of points, ^NF. Unable to fit polynomial.", status ); } return; } /* Set up the job data */ if( nw > (int) nbolo ) { step = 1; } else { step = nbolo/nw; if( !step ) { step = 1; } } job_data = astCalloc( nw, sizeof(*job_data) ); for( i=0; (*status==SAI__OK)&&i<nw; i++ ) { pdata = job_data + i; pdata->b1 = i*step; pdata->b2 = (i+1)*step-1; /* if b1 is greater than the number of bolometers, we've run out of jobs */ if( pdata->b1 >= nbolo ) { break; } /* increase the jobs counter */ njobs++; /* Ensure that the last thread picks up any left-over bolometers */ if( (i==(nw-1)) && (pdata->b1<(nbolo-1)) ) { pdata->b2=nbolo-1; } pdata->ijob = -1; /* Flag job as ready to start */ pdata->bstride = bstride; pdata->indata = data->pntr[0]; pdata->isTordered = data->isTordered; pdata->nbolo = nbolo; pdata->ntslice = ntslice; pdata->order = order; pdata->poly = poly; pdata->qual = qual; pdata->remove = remove; pdata->tstride = tstride; } /* Submit jobs to fit polynomial baselines to block of bolos */ thrBeginJobContext( wf, status ); for( i=0; (*status==SAI__OK)&&i<njobs; i++ ) { pdata = job_data + i; pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfFitPolyPar, 0, NULL, status ); } /* Wait until all of the submitted jobs have completed */ thrWait( wf, status ); thrEndJobContext( wf, status ); /* Free local resources. */ job_data = astFree( job_data ); }