void smf_write_bolomap( ThrWorkForce *wf, smfArray *res, smfArray *lut, smfArray *qua, smfDIMMData *dat, dim_t msize, const Grp *bolrootgrp, int varmapmethod, const int *lbnd_out, const int *ubnd_out, AstFrameSet *outfset, int *status ) { int addtomap=0; /* Set if adding to existing map */ size_t bstride; /* Bolometer stride */ double *curmap=NULL; /* Pointer to current map being rebinned */ double *curvar=NULL; /* Pointer to variance associate with curmap */ dim_t dsize; /* Size of data arrays in containers */ size_t idx=0; /* index within subgroup */ size_t k; /* loop counter */ int *lut_data=NULL; /* Pointer to DATA component of lut */ char name[GRP__SZNAM+1]; /* Buffer for storing names */ dim_t nbolo; /* Number of bolometers */ size_t nbolomaps = 0; /* Number of bolomaps written */ char *pname=NULL; /* Poiner to name */ smf_qual_t *qua_data=NULL; /* Pointer to DATA component of qua */ double *res_data=NULL; /* Pointer to DATA component of res */ if( *status != SAI__OK ) return; if( !res || !lut || !qua || !dat || !bolrootgrp || !lbnd_out || !ubnd_out || !outfset ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": NULL inputs supplied", status ); return; } /* Loop over subgroup index (subarray) */ for( idx=0; idx<res->ndat; idx++ ) { smf_qual_t *bolomask = NULL; double *bmapweight = NULL; double *bmapweightsq = NULL; int *bhitsmap = NULL; /* Pointers to everything we need */ res_data = res->sdata[idx]->pntr[0]; lut_data = lut->sdata[idx]->pntr[0]; qua_data = qua->sdata[idx]->pntr[0]; smf_get_dims( res->sdata[idx], NULL, NULL, &nbolo, NULL, &dsize, &bstride, NULL, status ); /* Make a copy of the quality at first time slice as a good bolo mask, and then set quality to SMF__Q_BADB. Later we will unset BADB for one bolo at a time to make individual maps. */ bolomask = astMalloc( nbolo*sizeof(*bolomask) ); bmapweight = astMalloc( msize*sizeof(*bmapweight) ); bmapweightsq = astMalloc( msize*sizeof(*bmapweightsq) ); bhitsmap = astMalloc( msize*sizeof(*bhitsmap) ); if( *status == SAI__OK ) { for( k=0; k<nbolo; k++ ) { bolomask[k] = qua_data[k*bstride]; qua_data[k*bstride] = SMF__Q_BADB; } /* Identify good bolos in the copied mask and produce a map */ for( k=0; (k<nbolo)&&(*status==SAI__OK); k++ ) { if( !(bolomask[k]&SMF__Q_BADB) ) { Grp *mgrp=NULL; /* Temporary group to hold map names */ smfData *mapdata=NULL;/* smfData for new map */ char tmpname[GRP__SZNAM+1]; /* temp name buffer */ char thisbol[20]; /* name particular to this bolometer */ size_t col, row; char subarray[10]; nbolomaps++; /* Set the quality back to good for this single bolometer */ qua_data[k*bstride] = bolomask[k]; /* Create a name for the new map, take into account the chunk number and subarray. Only required if we are using a single output container. */ pname = tmpname; grpGet( bolrootgrp, 1, 1, &pname, sizeof(tmpname), status ); one_strlcpy( name, tmpname, sizeof(name), status ); one_strlcat( name, ".", sizeof(name), status ); /* Subarray, column and row. HDS does not care about case but we convert to upper case anyhow. */ smf_find_subarray( res->sdata[idx]->hdr, subarray, sizeof(subarray), NULL, status ); if (*status == SAI__OK) { size_t len = strlen(subarray); size_t n = 0; for (n=0; n<len; n++) { subarray[n] = toupper(subarray[n]); } } col = (k % res->sdata[idx]->dims[1])+1; row = (k / res->sdata[idx]->dims[1])+1; sprintf( thisbol, "%3sC%02zuR%02zu", subarray, col, /* x-coord */ row ); /* y-coord */ one_strlcat( name, thisbol, sizeof(name), status ); mgrp = grpNew( "bolomap", status ); grpPut1( mgrp, name, 0, status ); msgOutf( "", "*** Writing single bolo map %s", status, name ); /* Try to open an existing extention first. Create a new map array, and then later we'll add it to the existing one. If it isn't there, create it. */ smf_open_file( mgrp, 1, "UPDATE", 0, &mapdata, status ); if( *status == SAI__OK ) { /* Allocate memory for the new rebinned data */ curmap = astCalloc( msize, sizeof(*curmap) ); curvar = astCalloc( msize, sizeof(*curvar) ); addtomap = 1; } else if( *status == DAT__NAMIN ) { /* Create a new extension */ errAnnul( status ); smf_open_newfile ( mgrp, 1, SMF__DOUBLE, 2, lbnd_out, ubnd_out, SMF__MAP_VAR, &mapdata, status); /* Rebin directly into the newly mapped space */ if( *status == SAI__OK ) { curmap = mapdata->pntr[0]; curvar = mapdata->pntr[1]; addtomap = 0; } } /* Rebin the data for this single bolometer. Don't care about variance weighting because all samples from same detector are about the same. */ smf_rebinmap1( wf, res->sdata[idx], dat->noi ? dat->noi[0]->sdata[idx] : NULL, lut_data, 0, 0, 0, NULL, 0, SMF__Q_GOOD, varmapmethod, AST__REBININIT | AST__REBINEND, curmap, bmapweight, bmapweightsq, bhitsmap, curvar, msize, NULL, status ); /* If required, add this new map to the existing one */ if( addtomap ) { size_t i; double *oldmap=NULL; double *oldvar=NULL; double weight; if( *status == SAI__OK ) { oldmap = mapdata->pntr[0]; oldvar = mapdata->pntr[1]; for( i=0; i<msize; i++ ) { if( oldmap[i]==VAL__BADD ) { /* No data in this pixel in the old map, just copy */ oldmap[i] = curmap[i]; oldvar[i] = curvar[i]; } else if( curmap[i]!=VAL__BADD && oldvar[i]!=VAL__BADD && oldvar[i]!=0 && curvar[i]!=VAL__BADD && curvar[i]!=0 ) { /* Both old and new values available */ weight = 1/oldvar[i] + 1/curvar[i]; oldmap[i] = (oldmap[i]/oldvar[i] + curmap[i]/curvar[i]) / weight; oldvar[i] = 1/weight; } } } /* Free up temporary arrays */ curmap = astFree( curmap ); curvar = astFree( curvar ); } /* Write out COLNUM and ROWNUM to FITS header */ if( *status == SAI__OK ) { AstFitsChan *fitschan=NULL; fitschan = astFitsChan ( NULL, NULL, " " ); atlPtfti( fitschan, "COLNUM", col, "bolometer column", status); atlPtfti( fitschan, "ROWNUM", row, "bolometer row", status ); atlPtfts( fitschan, "SUBARRAY", subarray, "Subarray identifier", status ); kpgPtfts( mapdata->file->ndfid, fitschan, status ); if( fitschan ) fitschan = astAnnul( fitschan ); /* Set the bolo to bad quality again */ qua_data[k*bstride] = SMF__Q_BADB; /* Write WCS */ smf_set_moving(outfset,NULL,status); ndfPtwcs( outfset, mapdata->file->ndfid, status ); } /* Clean up */ if( mgrp ) grpDelet( &mgrp, status ); if( mapdata ) smf_close_file( &mapdata, status ); } } /* Set quality back to its original state */ for( k=0; k<nbolo; k++ ) { qua_data[k*bstride] = bolomask[k]; } } /* Free up memory */ bolomask = astFree( bolomask ); bmapweight = astFree( bmapweight ); bmapweightsq = astFree( bmapweightsq ); bhitsmap = astFree( bhitsmap ); } msgOutf( "", "*** Wrote %zu bolo maps", status, nbolomaps ); }
void smf_write_shortmap( ThrWorkForce *wf, int shortmap, smfArray *res, smfArray *lut, smfArray *qua, smfDIMMData *dat, dim_t msize, const Grp *shortrootgrp, size_t contchunk, int varmapmethod, const int *lbnd_out, const int *ubnd_out, AstFrameSet *outfset, int *status ) { dim_t dsize; /* Size of data arrays in containers */ size_t i; /* loop counter */ size_t idx=0; /* index within subgroup */ size_t istart; /* First useful timeslice */ size_t iend; /* Last useful timeslice */ int *lut_data=NULL; /* Pointer to DATA component of lut */ char name[GRP__SZNAM+1]; /* Buffer for storing names */ size_t nshort=0; /* Number of short maps */ dim_t ntslice; /* Number of time slices */ char *pname=NULL; /* Poiner to name */ smf_qual_t *qua_data=NULL; /* Pointer to DATA component of qua */ double *res_data=NULL; /* Pointer to DATA component of res */ size_t sc; /* Short map counter */ double *shortmapweight=NULL; /* buffer for shotmap weights */ double *shortmapweightsq=NULL;/* buffer for shotmap weights squared */ int *shorthitsmap=NULL; /* buffer for shotmap hits */ size_t shortstart; /* first time slice of short map */ size_t shortend; /* last time slice of short map */ size_t tstride; /* Time stride */ if( *status != SAI__OK ) return; if( !res || !lut || !qua || !dat || !shortrootgrp || !lbnd_out || !ubnd_out || !outfset || !shortmap ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": NULL inputs supplied", status ); return; } if( !res || !res->sdata || !res->sdata[idx] || !res->sdata[idx]->hdr || !res->sdata[idx]->hdr->allState ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": RES does not contain JCMTState", status ); return; } /* Allocate space for the arrays */ shortmapweight = astMalloc( msize*sizeof(*shortmapweight) ); shortmapweightsq = astMalloc( msize*sizeof(*shortmapweightsq) ); shorthitsmap = astMalloc( msize*sizeof(*shorthitsmap) ); /* Use first subarray to figure out time dimension. Get the useful start and end points of the time series, and then determine "nshort" -- the number of complete blocks of shortmap time slices in the useful range. */ smf_get_dims( qua->sdata[0], NULL, NULL, NULL, &ntslice, NULL, NULL, &tstride, status ); qua_data = (qua->sdata[0]->pntr)[0]; smf_get_goodrange( qua_data, ntslice, tstride, SMF__Q_BOUND, &istart, &iend, status ); shortstart = istart; if( *status == SAI__OK ) { if( shortmap == -1 ) { nshort = res->sdata[idx]->hdr->allState[iend].tcs_index - res->sdata[idx]->hdr->allState[istart].tcs_index + 1; msgOutf( "", FUNC_NAME ": writing %zu short maps, once each time TCS_INDEX increments", status, nshort ); } else { nshort = (iend-istart+1)/shortmap; if( nshort ) { msgOutf( "", FUNC_NAME ": writing %zu short maps of length %i time slices.", status, nshort, shortmap ); } else { /* Generate warning message if requested short maps are too long*/ msgOutf( "", FUNC_NAME ": Warning! short maps of lengths %i requested, but " "data only %zu time slices.", status, shortmap, iend-istart+1 ); } } } /* Loop over short maps */ for( sc=0; (sc<nshort)&&(*status==SAI__OK); sc++ ) { Grp *mgrp=NULL; /* Temporary group for map names */ smfData *mapdata=NULL; /* smfData for new map */ char tempstr[20]; /* Temporary string */ char tmpname[GRP__SZNAM+1]; /* temp name buffer */ char thisshort[20]; /* name particular to this shortmap */ /* Create a name for the new map, take into account the chunk number. Only required if we are using a single output container. */ pname = tmpname; grpGet( shortrootgrp, 1, 1, &pname, sizeof(tmpname), status ); one_strlcpy( name, tmpname, sizeof(name), status ); one_strlcat( name, ".", sizeof(name), status ); /* Continuous chunk number */ sprintf(tempstr, "CH%02zd", contchunk); one_strlcat( name, tempstr, sizeof(name), status ); /* Shortmap number */ sprintf( thisshort, "SH%06zu", sc ); one_strlcat( name, thisshort, sizeof(name), status ); mgrp = grpNew( "shortmap", status ); grpPut1( mgrp, name, 0, status ); msgOutf( "", "*** Writing short map (%zu / %zu) %s", status, sc+1, nshort, name ); smf_open_newfile ( wf, mgrp, 1, SMF__DOUBLE, 2, lbnd_out, ubnd_out, SMF__MAP_VAR, &mapdata, status); /* Time slice indices for start and end of short map -- common to all subarrays */ if( shortmap > 0) { /* Evenly-spaced shortmaps in time */ shortstart = istart+sc*shortmap; shortend = istart+(sc+1)*shortmap-1; } else { /* One map each time TCS_INDEX increments -- just uses header for the first subarray */ for(i=shortstart+1; (i<=iend) && (res->sdata[0]->hdr->allState[i].tcs_index == res->sdata[0]->hdr->allState[shortstart].tcs_index); i++ ); shortend = i-1; } /* Bad status if we have invalid shortmap ranges. This might happen if there is ever a jump in TCS_INDEX for the shortmap=-1 case since the total number of shortmaps is calculated simply as the difference between the first and final TCS indices. */ if( !nshort || (iend<istart) || (iend>=ntslice) ) { *status = SAI__ERROR; errRepf( "", FUNC_NAME ": invalid shortmap range (%zu--%zu, ntslice=%zu)" "encountered", status, istart, iend, ntslice ); break; } /* Loop over subgroup index (subarray) */ for( idx=0; (idx<res->ndat)&&(*status==SAI__OK); idx++ ) { int rebinflag = 0; /* Pointers to everything we need */ res_data = (res->sdata[idx]->pntr)[0]; lut_data = (lut->sdata[idx]->pntr)[0]; qua_data = (qua->sdata[idx]->pntr)[0]; smf_get_dims( res->sdata[idx], NULL, NULL, NULL, &ntslice, &dsize, NULL, &tstride, status ); /* Rebin the data for this range of tslices. */ if( idx == 0 ) { rebinflag |= AST__REBININIT; } if( idx == (res->ndat-1) ) { rebinflag |= AST__REBINEND; } smf_rebinmap1( NULL, res->sdata[idx], dat->noi ? dat->noi[0]->sdata[idx] : NULL, lut_data, shortstart, shortend, 1, NULL, 0, SMF__Q_GOOD, varmapmethod, rebinflag, mapdata->pntr[0], shortmapweight, shortmapweightsq, shorthitsmap, mapdata->pntr[1], msize, NULL, status ); /* Write out FITS header */ if( (*status == SAI__OK) && res->sdata[idx]->hdr && res->sdata[idx]->hdr->allState ) { AstFitsChan *fitschan=NULL; JCMTState *allState = res->sdata[idx]->hdr->allState; size_t midpnt = (shortstart + shortend) / 2; fitschan = astFitsChan ( NULL, NULL, " " ); atlPtfti( fitschan, "SEQSTART", allState[shortstart].rts_num, "RTS index number of first frame", status ); atlPtfti( fitschan, "SEQEND", allState[shortend].rts_num, "RTS index number of last frame", status); atlPtftd( fitschan, "MJD-AVG", allState[midpnt].rts_end, "Average MJD of this map", status ); atlPtfts( fitschan, "TIMESYS", "TAI", "Time system for MJD-AVG", status ); atlPtfti( fitschan, "TCSINDST", allState[shortstart].tcs_index, "TCS index of first frame", status ); atlPtfti( fitschan, "TCSINDEN", allState[shortend].tcs_index, "TCS index of last frame", status ); kpgPtfts( mapdata->file->ndfid, fitschan, status ); if( fitschan ) fitschan = astAnnul( fitschan ); } } /* Update shortstart in case we are counting steps in TCS_INDEX */ shortstart = shortend+1; /* Write WCS */ smf_set_moving( (AstFrame *) outfset, NULL, status ); ndfPtwcs( outfset, mapdata->file->ndfid, status ); /* Clean up */ if( mgrp ) grpDelet( &mgrp, status ); smf_close_file( wf, &mapdata, status ); } /* Free up memory */ shortmapweight = astFree( shortmapweight ); shortmapweightsq = astFree( shortmapweightsq ); shorthitsmap = astFree( shorthitsmap ); }