void smf_getrefwcs( const char *param, Grp *igrp, AstFrameSet **specwcs, AstFrameSet **spacewcs, int *isjsa, int *status ){ /* Local Variables */ AstFrame *frm = NULL; AstFrameSet *refwcs = NULL; /* The WCS FrameSet from the reference NDF */ AstRegion *circle; char text[ 255 ]; /* Parameter value */ int *tiles; int i; int jsatiles; int lbnd[2]; /* Lower pixel index bounds of mid tile */ int ntile; int perm[ 2 ]; int refndf; /* NDF identifier for the refence NDF */ int ubnd[2]; /* Upper pixel index bounds of mid tile */ size_t code; smfData *data = NULL; /* Structure describing 1st input file */ smfJSATiling skytiling; smf_inst_t inst = SMF__INST_NONE; smf_jsaproj_t proj; /* Specific JSA projection to use */ smf_subinst_t subinst; /* Initialise the returned values. */ *specwcs = NULL; *spacewcs = NULL; *isjsa = 0; /* Check inherited status */ if( *status != SAI__OK ) return; /* Begin an AST context. */ astBegin; /* If the JSAILES parameter is TRUE, then we use the JSA all-sky pixel grid regardless of the setting of REF. */ parGet0l( "JSATILES", &jsatiles, status ); if( jsatiles ) { strcpy( text, "JSA" ); *isjsa = 1; /* Otherwise, first get the parameter value as a string. Use subpar to avoid problem caused by interpretion of the text within the parameter system. */ } else { subParFindpar( param, &code, status ); subParGetname( code, text, sizeof(text), status ); } /* If no value was supplied, annul the error and do nothing more. */ if( *status == PAR__NULL ) { errAnnul( status ); /* If it is "JSA", or one of the JSA projection codes, we return WCS that describes one of the the JSA all-sky pixel grids. */ } else if( *status == SAI__OK ) { proj = smf_jsaproj_fromstr( text, 0, status ); if( astChrMatch( text, "JSA" ) || proj != SMF__JSA_NULL ) { *isjsa = 1; /* Report an error if the instrument cannot be determined. */ if( !igrp ) { *status = SAI__ERROR; errRep( "", "smf_getrefwcs: Cannot use the JSA all-sky pixel " "grid since no input group has been supplied (possibly " "programming error).", status ); } else { /* Open the first input file. */ smf_open_file( NULL, igrp, 1, "READ", SMF__NOCREATE_DATA, &data, status ); if( *status == SAI__OK ) { /* Get the instrument. */ if( data->hdr->instrument == INST__SCUBA2 ) { subinst = smf_calc_subinst( data->hdr, status ); if( subinst == SMF__SUBINST_850 ) { inst = SMF__INST_SCUBA_2_850; } else { inst = SMF__INST_SCUBA_2_450; } } else if( data->hdr->instrument == INST__ACSIS ) { inst = SMF__INST_ACSIS; } else if( *status == SAI__OK ) { *status = SAI__ERROR; if( data->file ) { smf_smfFile_msg( data->file, "FILE", 1, "one or more of " "the input data files" ); } else { msgSetc( "FILE", "one or more of the input data files" ); } errRep( "", "No tiles are yet defined for the instrument that " "created ^FILE.", status ); } /* Get the parameters that define the layout of sky tiles for the instrument. */ smf_jsatiling( inst, &skytiling, status ); /* For "JSA" - choose the best projection. */ if( astChrMatch( text, "JSA" ) ) { /* Use the FITS headers in the first raw data file to create an AST Circle describing the approximate area of the observation within the tracking system. */ circle = smf_mapregion_approx( igrp, status ); /* Convert the circle to ICRS (as used by the JSA all-sky grid). */ astSetC( circle, "System", "ICRS" ); /* Get a list of the tiles that touch this circle. */ tiles = smf_jsatiles_region( circle, &skytiling, &ntile, status ); /* Choose the best projection (i.e. the projection that puts the circle furthest away from any singularities). */ proj = smf_jsaproj( ntile, tiles, &skytiling, status); /* Free resources. */ tiles = astFree( tiles ); circle = astAnnul( circle ); /* If a good projection was specified, use it. Otherwise report an error. */ } else if( proj == SMF__JSA_NULL && *status == SAI__OK ) { *status = SAI__ERROR; errRepf( "", "Bad value '%s' supplied for parameter %s.", status, text, param ); } /* Report the projection type. */ msgOutf( " ", "The %s will be created on the JSA %s " "pixel grid.", status, (data->hdr->instrument==INST__ACSIS)?"cube":"map", smf_jsaproj_tostr( proj ) ); /* All tiles within the same JSA projection use the same WCS, so we get the WCS FrameSet for an arbitrary central tile, and use it for the full map. The exception is that tiles within the HPX facet that is split between bottom-left and top-right, use a different WCS (they have different reference points). But our choice of projection should mean that the map never falls in that facet. The base Frame will be GRID coords within the tile, and the current Frame will be ICRS (RA,Dec). */ smf_jsatile( ((skytiling.ntpf * skytiling.ntpf - 1) * 2) / 3, &skytiling, 0, proj, NULL, spacewcs, NULL, lbnd, ubnd, status ); /* Change the base Frame to be PIXEL. */ for( i = 1; i <= astGetI( *spacewcs, "NFrame" ); i++ ) { frm = astGetFrame( *spacewcs, i ); if( astChrMatch( astGetC( frm, "Domain" ), "PIXEL" ) ) { astSetI( *spacewcs, "Base", i ); } frm = astAnnul( frm ); } } /* Close the current input data file. */ smf_close_file( NULL, &data, status); } /* Otherwise get the parameter value as an NDF. */ } else { ndfAssoc( param, "READ", &refndf, status ); /* Get the WCS FrameSet from the reference NDF. */ ndfGtwcs( refndf, &refwcs, status ); /* Attempt to extract a new FrameSet from this WCS FrameSet, in which the current Frame is a SkyFrame, and the base Frame is a 2D PIXEL Frame. Since the NDF library sets the GRID Frame to be the Base Frame, we need to make the PIXEL Frame the base Frame first. The NDF library ensures that the pixel Frame is Frame 2. */ astSetI( refwcs, "Base", 2 ); *spacewcs = atlFrameSetSplit( refwcs, "SKY", NULL, NULL, status ); if( !(*spacewcs) ) { if( *status == SAI__OK ) { ndfMsg( "N", refndf ); *status = SAI__ERROR; errRep( "", "The supplied reference NDF (^N) either has no " "celestial WCS axes, or the celestial axes cannot " "be separated from the non-celestial axes.", status ); } /* The rest of makemap assumes that the sky frame axes are in the default order (lon,lat). If this is not the case, permute them. */ } else if( astGetI( *spacewcs, "IsLatAxis(1)" ) ) { perm[ 0 ] = 2; perm[ 1 ] = 1; astPermAxes( *spacewcs, perm ); } /* Now look for the spectral WCS (described by a DSBSpecFrame). */ smf_getspectralwcs( refwcs, 1, specwcs, status ); /* We no longer need the NDF so annul it. */ ndfAnnul( &refndf, status ); } } /* If no error has occurred, export any returned FrameSet pointers from the current AST context so that it will not be annulled when the AST context is ended. Otherwise, ensure a null pointer is returned. */ if( *status == SAI__OK ) { if( *spacewcs ) astExport( *spacewcs ); if( *specwcs ) astExport( *specwcs ); } else { if( *spacewcs ) *spacewcs = astAnnul( *spacewcs ); if( *specwcs ) *specwcs = astAnnul( *specwcs ); } /* End the AST context. This will annul all AST objects created within the context (except for those that have been exported from the context). */ astEnd; }
/* Main entry */ void smf_jsadicer( int indf, const char *base, int trim, smf_inst_t instrument, smf_jsaproj_t proj, size_t *ntile, Grp *grp, int *status ){ /* Local Variables: */ AstBox *box; AstFitsChan *fc; AstFrame *specfrm = NULL; AstFrame *tile_frm = NULL; AstFrameSet *iwcs; AstFrameSet *tfs = NULL; AstFrameSet *tile_wcs; AstMapping *ndf_map = NULL; AstMapping *p2pmap = NULL; AstMapping *specmap = NULL; AstMapping *tile_map = NULL; AstRegion *region; Grp *grpt = NULL; char *path; char dtype[ NDF__SZFTP + 1 ]; char jsatile_comment[45]; char type[ NDF__SZTYP + 1 ]; const char *dom = NULL; const char *keyword; const char *latsys = NULL; const char *lonsys = NULL; double *pd; double dlbnd[3]; double dubnd[3]; double gcen[3]; double lbnd_in[3]; double lbnd_out[3]; double ubnd_in[3]; double ubnd_out[3]; float *pf; int *created_tiles = NULL; int *tiles; int axlat; int axlon; int axspec; int bbox[ 6 ]; int i; int ifrm; int igrid; int indfo; int indfs; int indfx; int inperm[3]; int ipixel; int ishpx; int isxph; int itile; int ix; int iy; int iz; int junk; int latax = -1; int lbnd[3]; int lbnd_tile[ 3 ]; int lbndx[ NDF__MXDIM ]; int lonax = -1; int nbase; int ndim; int ndimx; int nfrm; int nsig; int ntiles; int olbnd[ 3 ]; int oubnd[ 3 ]; int outperm[ 3 ]; int place; int qual; int tile_index; int tile_lbnd[2]; int tile_ubnd[2]; int ubnd[3]; int ubnd_tile[ 3 ]; int ubndx[ NDF__MXDIM ]; int var; size_t iext; size_t size; smfJSATiling tiling; unsigned char *ipq = NULL; void *ipd = NULL; void *ipv = NULL; /* Initialise */ *ntile = 0; /* Check inherited status */ if( *status != SAI__OK ) return; /* Begin an AST context. */ astBegin; /* Begin an NDF context. */ ndfBegin(); /* Note the used length of the supplied base string. If it ends with ".sdf", reduce it by 4. */ nbase = astChrLen( base ); if( !strcmp( base + nbase - 4, ".sdf" ) ) nbase -= 4; /* Allocate a buffer large enough to hold the full path for an output NDF. */ path = astMalloc( nbase + 25 ); /* Get the WCS from the NDF. */ kpg1Gtwcs( indf, &iwcs, status ); /* Note if the NDF projection is HPX or XPH. */ ishpx = astChrMatch( astGetC( iwcs, "Projection" ), "HEALPix" ); isxph = astChrMatch( astGetC( iwcs, "Projection" ), "polar HEALPix" ); /* Report an error if the NDFs projection is neither of these. */ if( !ishpx && !isxph && *status == SAI__OK ) { ndfMsg( "N", indf ); *status = SAI__ERROR; errRep( "", "The input NDF (^N) does not appear to be gridded " "on the JSA all-sky pixel grid.", status ); } /* Get the bounds of the NDF in pixel indices and the the corresponding double precision GRID bounds (reduce the size of the grid by a small amount to avoid problems with tiles that are on the edge of the valid sky regions - astMapRegion can report an error for such tiles). Also store the GRID coords of the centre. Also count the number of significant pixel axes. */ ndfBound( indf, 3, lbnd, ubnd, &ndim, status ); nsig = 0; for( i = 0; i < ndim; i++ ) { dlbnd[ i ] = 0.5 + 0.1; dubnd[ i ] = ubnd[ i ] - lbnd[ i ] + 1.5 - 0.1; gcen[ i ] = 0.5*( dlbnd[ i ] + dubnd[ i ] ); if( ubnd[ i ] > lbnd[ i ] ) nsig++; } /* Find the one-based indices of the RA, Dec and spectral axes in the current Frame of the NDF. */ axlon = 0; if( astGetI( iwcs, "IsLonAxis(1)" ) ) { axlon = 1; lonsys = astGetC( iwcs, "System(1)" ); } else if( astGetI( iwcs, "IsLonAxis(2)" ) ) { axlon = 2; lonsys = astGetC( iwcs, "System(2)" ); } else if( ndim == 3 && astGetI( iwcs, "IsLonAxis(3)" ) ) { axlon = 3; lonsys = astGetC( iwcs, "System(3)" ); } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "smf_jsadicer: Cannot find the longitude axis in the " "input NDF.", status ); } axlat = 0; if( astGetI( iwcs, "IsLatAxis(1)" ) ) { axlat = 1; latsys = astGetC( iwcs, "System(1)" ); } else if( astGetI( iwcs, "IsLatAxis(2)" ) ) { axlat = 2; latsys = astGetC( iwcs, "System(2)" ); } else if( ndim == 3 && astGetI( iwcs, "IsLatAxis(3)" ) ) { axlat = 3; latsys = astGetC( iwcs, "System(3)" ); } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "smf_jsadicer: Cannot find the latitude axis in the " "input NDF.", status ); } axspec = 6 - axlon - axlat; /* Report an error if the spatial axes are not ICRS RA and Dec. */ if( ( lonsys && strcmp( lonsys, "ICRS" ) ) || ( latsys && strcmp( latsys, "ICRS" ) ) ) { if( *status == SAI__OK ) { *status = SAI__ERROR; ndfMsg( "N", indf ); errRep( "", "smf_jsadicer: The spatial axes in '^N' are not " "ICRS RA and Dec.", status ); } } /* Create a Box describing the region covered by the NDF pixel grid in GRID coords. */ box = astBox( astGetFrame( iwcs, AST__BASE ), 1, dlbnd, dubnd, AST__NULL, " " ); /* Map this Box into the current WCS Frame of the NDF. */ region = astMapRegion( box, iwcs, iwcs ); /* If no instrument was specified, we will determine the instrument from the contexts of the FITS extension. Copy the NDF FITS extension to a FitsChan. Annul the error if the NDF no FITS extension. */ if( instrument == SMF__INST_NONE && *status == SAI__OK ) { kpgGtfts( indf, &fc, status ); if( *status == KPG__NOFTS ) { errAnnul( status ); fc = NULL; } } else { fc = NULL; } /* Get the parameters of the required tiling scheme. */ smf_jsainstrument( NULL, fc, instrument, &tiling, status ); /* Get a list of the JSA tiles touched by the supplied NDF. */ tiles = smf_jsatiles_region( region, &tiling, &ntiles, status ); if( ntiles == 0 && *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "smf_jsadicer: No JSA tiles found touching supplied NDF " "(programming error).", status ); } /* Does the input NDF have a Variance component? */ ndfState( indf, "Variance", &var, status ); /* Does the input NDF have a Quality component? */ ndfState( indf, "Quality", &qual, status ); /* Decide on the data type to use: _REAL or _DOUBLE. */ ndfMtype( "_REAL,_DOUBLE", indf, indf, "Data", type, sizeof(type), dtype, sizeof(dtype), status ); /* Tell the user what is happening. */ msgBlank( status ); msgOutf( "", "Dicing %s into JSA tiles:", status, ( nsig == 2 ) ? "map" : "cube" ); /* Loop round all tiles that overlap the supplied NDF. */ for( itile = 0; itile < ntiles && *status == SAI__OK; itile++ ) { tile_index = tiles[ itile ]; /* Get the spatial pixel bounds of the current tile within the requested JSA all-sky projection. Also get the (2D) WCS FrameSet for the tile. */ smf_jsatile( tile_index, &tiling, 0, proj, NULL, &tile_wcs, NULL, tile_lbnd, tile_ubnd, status ); /* Extract the tile pixel->WCS mapping and WCS Frame. We know the indices of the required Frames because they are hard-wired in smf_jsatile. */ tile_map = astGetMapping( tile_wcs, 3, 2 ); tile_frm = astGetFrame( tile_wcs, 2 ); /* Find the indices of the grid and pixel frames in the input NDF. */ ipixel = -1; igrid = astGetI( iwcs, "Base" ); nfrm = astGetI( iwcs, "NFrame" ); for( ifrm = 0; ifrm < nfrm; ifrm++ ) { dom = astGetC( astGetFrame( iwcs, ifrm + 1 ), "Domain" ); if( astChrMatch( dom, "PIXEL" ) ) ipixel = ifrm + 1; } /* If required, extract the pixel->spectral mapping and spectral frame in the input NDF, and add it in parallel with the above tile mapping. */ if( ndim == 3 ) { astSetI( iwcs, "Base", ipixel ); tfs = atlFrameSetSplit( iwcs, "DSBSPECTRUM SPECTRUM", NULL, NULL, status ); astSetI( iwcs, "Base", igrid ); if( tfs ) { specmap = astGetMapping( tfs, AST__BASE, AST__CURRENT ); specfrm = astGetFrame( tfs, AST__CURRENT ); } else if( *status == SAI__OK ) { *status = SAI__ERROR; ndfMsg( "N", indf ); errRep( "", "smf_jsadicer: Cannot find the spectral axis " "in '^N'.", status ); } tile_map = (AstMapping *) astCmpMap( tile_map, specmap, 0, " " ); tile_frm = (AstFrame *) astCmpFrame( tile_frm, specfrm, " " ); } /* Ensure the Epoch is inherited form the input NDF. */ astSetD( tile_frm, "Epoch", astGetD( iwcs, "Epoch" ) ); /* Currently tile axis 1 is RA, axis 2 is Dec and axis 3 (if present) is spectral. Append a PermMap that re-orders these tile WCS axes to match those of the NDF. */ outperm[ axlon - 1 ] = 1; outperm[ axlat - 1 ] = 2; outperm[ axspec - 1 ] = 3; inperm[ 0 ] = axlon; inperm[ 1 ] = axlat; inperm[ 2 ] = axspec; tile_map = (AstMapping *) astCmpMap( tile_map, astPermMap( ndim, inperm, ndim, outperm, NULL, " " ), 1, " " ); tile_map = astSimplify( tile_map ); /* Also re-order the WCS axes in the tile frame. */ astPermAxes( tile_frm, outperm ); /* We want the zero-based indicies of the input pixel axes corresponding to ra, dec and spectral. So find the indicies of the pixel axes in the supplied NDF that are most closely aligned with each WCS axis. */ atlPairAxes( iwcs, NULL, gcen, NULL, inperm, status ); if( inperm[ 0 ] == axlon ) { lonax = 0; } else if( inperm[ 1 ] == axlon ) { lonax = 1; } else { lonax = 2; } if( inperm[ 0 ] == axlat ) { latax = 0; } else if( inperm[ 1 ] == axlat ) { latax = 1; } else { latax = 2; } /* To get the mapping from pixel coords in the input NDF to pixel coords in the output NDF, we invert the above mapping so that it goes from WCS to pixel, and append it to the end of the NDF pixel->WCS mapping. */ ndf_map = astGetMapping( iwcs, ipixel, AST__CURRENT ); astInvert( tile_map ); p2pmap = (AstMapping *) astCmpMap( ndf_map, tile_map, 1, " " ); p2pmap = astSimplify( p2pmap ); astInvert( tile_map ); /* Show the bounds of the tile within the input NDF. */ msgOutiff( MSG__DEBUG, "", " tile %d has bounds (%d:%d,%d:%d) " "within the output NDF.", status, tile_index, tile_lbnd[ 0 ], tile_ubnd[ 0 ], tile_lbnd[ 1 ], tile_ubnd[ 1 ] ); /* Next job is to find the pixel bounds of the output NDF to create which will hold data for the current tile. First map the pixel bounds of the whole tile from output to input. */ lbnd_in[ 0 ] = tile_lbnd[ 0 ] - 0.5; lbnd_in[ 1 ] = tile_lbnd[ 1 ] - 0.5; lbnd_in[ 2 ] = lbnd[ 2 ] - 0.5; ubnd_in[ 0 ] = tile_ubnd[ 0 ] - 0.5; ubnd_in[ 1 ] = tile_ubnd[ 1 ] - 0.5; ubnd_in[ 2 ] = ubnd[ 2 ] - 0.5; astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 1, lbnd_out + 0, ubnd_out + 0, NULL, NULL ); astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 2, lbnd_out + 1, ubnd_out + 1, NULL, NULL ); if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 3, lbnd_out + 2, ubnd_out + 2, NULL, NULL ); lbnd_tile[ 0 ] = floor( lbnd_out[ 0 ] ) + 1; lbnd_tile[ 1 ] = floor( lbnd_out[ 1 ] ) + 1; lbnd_tile[ 2 ] = floor( lbnd_out[ 2 ] ) + 1; ubnd_tile[ 0 ] = floor( ubnd_out[ 0 ] ) + 1; ubnd_tile[ 1 ] = floor( ubnd_out[ 1 ] ) + 1; ubnd_tile[ 2 ] = floor( ubnd_out[ 2 ] ) + 1; /* Show the bounds of the tile within the input NDF. */ msgOutiff( MSG__DEBUG, "", " tile %d has bounds (%d:%d,%d:%d) " "within the input NDF.", status, tile_index, lbnd_tile[ 0 ], ubnd_tile[ 0 ], lbnd_tile[ 1 ], ubnd_tile[ 1 ] ); /* If required, trim the bounds to the extent of the input NDF. */ if( trim ) { if( lbnd_tile[ 0 ] < lbnd[ 0 ] ) lbnd_tile[ 0 ] = lbnd[ 0 ]; if( lbnd_tile[ 1 ] < lbnd[ 1 ] ) lbnd_tile[ 1 ] = lbnd[ 1 ]; if( lbnd_tile[ 2 ] < lbnd[ 2 ] ) lbnd_tile[ 2 ] = lbnd[ 2 ]; if( ubnd_tile[ 0 ] > ubnd[ 0 ] ) ubnd_tile[ 0 ] = ubnd[ 0 ]; if( ubnd_tile[ 1 ] > ubnd[ 1 ] ) ubnd_tile[ 1 ] = ubnd[ 1 ]; if( ubnd_tile[ 2 ] > ubnd[ 2 ] ) ubnd_tile[ 2 ] = ubnd[ 2 ]; } /* Check there is some overlap. */ if( lbnd_tile[ 0 ] <= ubnd_tile[ 0 ] && lbnd_tile[ 1 ] <= ubnd_tile[ 1 ] && lbnd_tile[ 2 ] <= ubnd_tile[ 2 ] ){ /* Now need to check if this section of the input NDF contains any good values. We also find the bounding box of the good values (within the input pixel coordinate system). So first obtain and map the required section of the input NDF. */ ndfSect( indf, ndim, lbnd_tile, ubnd_tile, &indfs, status ); ndfMap( indfs, "Data", type, "Read", &ipd, &junk, status ); if( var ) ndfMap( indfs, "Variance", type, "Read", &ipv, &junk, status ); if( qual ) ndfMap( indfs, "Quality", "_UBYTE", "Read", (void **) &ipq, &junk, status ); /* Initialise the pixel bounds (within the input NDF) of the box holding good data values for the current tile. */ bbox[ 0 ] = INT_MAX; bbox[ 1 ] = INT_MAX; bbox[ 2 ] = INT_MAX; bbox[ 3 ] = -INT_MAX; bbox[ 4 ] = -INT_MAX; bbox[ 5 ] = -INT_MAX; /* Loop round all pixels in the section. */ if( *status == SAI__OK ) { if( !strcmp( type, "_REAL" ) ) { pf = (float *) ipd; for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) { for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) { for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) { if( *(pf++) != VAL__BADR ) { if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix; if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy; if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz; if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix; if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy; if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz; } } } } } else { pd = (double *) ipd; for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) { for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) { for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) { if( *(pd++) != VAL__BADD ) { if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix; if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy; if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz; if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix; if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy; if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz; } } } } } /* Skip empty tiles. */ if( bbox[ 0 ] != INT_MAX ) { msgOutf( "", " tile %d", status, tile_index ); /* If required, trim the bounds to the edges of the bounding box. */ if( trim >= 2 ) { olbnd[ 0 ] = bbox[ 0 ]; olbnd[ 1 ] = bbox[ 1 ]; olbnd[ 2 ] = bbox[ 2 ]; oubnd[ 0 ] = bbox[ 3 ]; oubnd[ 1 ] = bbox[ 4 ]; oubnd[ 2 ] = bbox[ 5 ]; } else { olbnd[ 0 ] = lbnd_tile[ 0 ]; olbnd[ 1 ] = lbnd_tile[ 1 ]; olbnd[ 2 ] = lbnd_tile[ 2 ]; oubnd[ 0 ] = ubnd_tile[ 0 ]; oubnd[ 1 ] = ubnd_tile[ 1 ]; oubnd[ 2 ] = ubnd_tile[ 2 ]; } /* Modify these pixel bounds so that they refer to the output NDF. */ lbnd_in[ 0 ] = olbnd[ 0 ] - 0.5; lbnd_in[ 1 ] = olbnd[ 1 ] - 0.5; lbnd_in[ 2 ] = olbnd[ 2 ] - 0.5; ubnd_in[ 0 ] = oubnd[ 0 ] - 0.5; ubnd_in[ 1 ] = oubnd[ 1 ] - 0.5; ubnd_in[ 2 ] = oubnd[ 2 ] - 0.5; astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 1, lbnd_out + 0, ubnd_out + 0, NULL, NULL ); astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 2, lbnd_out + 1, ubnd_out + 1, NULL, NULL ); if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 3, lbnd_out + 2, ubnd_out + 2, NULL, NULL ); olbnd[ 0 ] = floor( lbnd_out[ 0 ] ) + 1; olbnd[ 1 ] = floor( lbnd_out[ 1 ] ) + 1; olbnd[ 2 ] = floor( lbnd_out[ 2 ] ) + 1; oubnd[ 0 ] = floor( ubnd_out[ 0 ] ) + 1; oubnd[ 1 ] = floor( ubnd_out[ 1 ] ) + 1; oubnd[ 2 ] = floor( ubnd_out[ 2 ] ) + 1; /* Get the full path to the output NDF for the current tile, and create an NDF placeholder for it. */ sprintf( path, "%.*s_%d", nbase, base, tile_index ); ndfPlace( NULL, path, &place, status ); /* Create a new output NDF by copying the meta-data from the input NDF section. */ ndfScopy( indfs, "Units", &place, &indfo, status ); /* Set the pixel bounds of the output NDF to the values found above and copy the input data for the current tile into it. */ smf1_jsadicer( indfo, olbnd, oubnd, tile_map, tile_frm, p2pmap, ipd, ipv, ipq, status ); /* Add the name of this output NDF to the group holding the names of the output NDFs that have actually been created. */ if( grp ) grpPut1( grp, path, 0, status ); /* Add a TILENUM header to the output FITS extension. */ kpgGtfts( indfo, &fc, status ); if( *status == KPG__NOFTS ) { errAnnul( status ); fc = astFitsChan( NULL, NULL, " " ); /* If the last card is "END", remove it. */ } else { astSetI( fc, "Card", astGetI( fc, "NCARD" ) ); keyword = astGetC( fc, "CardName" ); if( keyword && !strcmp( keyword, "END" ) ) astDelFits( fc ); } one_snprintf(jsatile_comment, 45, "JSA all-sky tile index (Nside=%i)", status, tiling.ntpf); atlPtfti( fc, "TILENUM", tile_index, jsatile_comment, status ); kpgPtfts( indfo, fc, status ); fc = astAnnul( fc ); /* Now store an STC-S polygon that describes the shortest boundary enclosing the good data in the output NDF, and store it as an NDF extension. */ kpgPutOutline( indfo, 0.5, 1, status ); /* We now reshape any extension NDFs contained within the output NDF to have the same spatial bounds as the main NDF (but only for extension NDFs that originally have the same spatial bounds as the supplied NDF). Get a group containing paths to all extension NDFs in the output NDF. */ ndgMoreg( indfo, &grpt, &size, status ); /* Loop round each output extension NDF. */ for( iext = 1; iext <= size && *status == SAI__OK; iext++ ) { ndgNdfas( grpt, iext, "Update", &indfx, status ); /* Get its bounds. */ ndfBound( indfx, NDF__MXDIM, lbndx, ubndx, &ndimx, status ); /* See if this extension NDF has the same bounds on the spatial axes as the supplied NDF. */ if( ndimx > 1 && lbndx[ lonax ] == lbnd[ lonax ] && lbndx[ latax ] == lbnd[ latax ] && ubndx[ lonax ] == ubnd[ lonax ] && ubndx[ latax ] == ubnd[ latax ] ) { /* If so, change the bounds of the output extension NDF so that they are the same as the main NDF on the spatial axes, and map the original contents of the NDF onto the new pixel grid. */ smf1_jsadicer( indfx, olbnd, oubnd, tile_map, tile_frm, p2pmap, NULL, NULL, NULL, status ); } /* Annul the extension NDF identifier. */ ndfAnnul( &indfx, status ); } /* Free resources associated with the current tile. */ grpDelet( &grpt, status ); ndfAnnul( &indfo, status ); /* Issue warnings about empty tiles. */ } else { msgOutiff( MSG__VERB, "", " tile %d is empty and so will not be " "created", status, tile_index ); } } /* Free the section of the input NDF. */ ndfAnnul( &indfs, status ); /* Append the index of this tile in the list of tiles to be created. */ created_tiles = astGrow( created_tiles, ++(*ntile), sizeof( *created_tiles ) ); if( *status == SAI__OK ) created_tiles[ *ntile - 1 ] = tile_index; } else { msgOutiff( MSG__DEBUG, "", " Tile %d does not overlap the input " "NDF after trimming.", status, tile_index ); } } msgBlank( status ); /* Write the indicies of the created tiles out to a parameter. */ if( *ntile ) parPut1i( "JSATILELIST", *ntile, created_tiles, status ); /* Free resources. */ created_tiles = astFree( created_tiles ); tiles = astFree( tiles ); path = astFree( path ); /* End the NDF context. */ ndfEnd( status ); /* End the AST context. */ astEnd; }
void smurf_jsatilelist( int *status ) { /* Local Variables */ AstFitsChan *fc = NULL; AstFrameSet *fs = NULL; AstObject *obj; AstRegion *region; Grp *igrp = NULL; Grp *sgrp = NULL; double vertex_data[ 2*MAXVERT ]; int *tiles = NULL; int i; int indf; int lbnd[2]; int ntile; int nvert_dec; int nvert_ra; int ubnd[2]; size_t size; size_t ssize; smfJSATiling tiling; /* Check inherited status */ if( *status != SAI__OK ) return; /* Start a new AST context. */ astBegin; /* Attempt to to get an AST Region. */ kpg1Gtobj( "IN", "Region", (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion), &obj, status ); region = (AstRegion *) obj; /* If successful, attempt to access the IN parameter as an NDF. If this works, we may be able to determine the instrument by looking at its FITS extension. */ if( *status == SAI__OK && region ) { ndfExist( "IN", "Read", &indf, status ); /* If we got an NDF, get a FitsChan holding the contents of its FITS extension. Annul the error if the NDF has no FITS extension. */ if( indf != NDF__NOID ) { kpgGtfts( indf, &fc, status ); if( *status == KPG__NOFTS ) { errAnnul( status ); fc = NULL; } ndfAnnul( &indf, status ); } /* Select a JSA instrument and get the parameters defining the layout of tiles for the selected instrument. */ smf_jsainstrument( "INSTRUMENT", fc, SMF__INST_NONE, &tiling, status ); /* Get the list of identifiers for tiles that overlap the region. */ tiles = smf_jsatiles_region( region, &tiling, &ntile, status ); /* If a null value was supplied for IN, attempt to get the positions of vertices on the sky to define the region. */ } else if( *status == PAR__NULL ) { errAnnul( status ); parGet1d( "VERTEX_RA", MAXVERT, vertex_data, &nvert_ra, status ); parGet1d( "VERTEX_DEC", MAXVERT, vertex_data + MAXVERT, &nvert_dec, status ); if( nvert_ra != nvert_dec && *status == SAI__OK ) { *status = SAI__ERROR; errRepf( "", "Differing numbers of RA (%d) and Dec (%d) vertex values " "supplied.", status, nvert_ra, nvert_dec ); } /* Convert from degrees to radians. */ for( i = 0; i < nvert_ra; i++ ) { vertex_data[ i ] *= AST__DD2R; vertex_data[ MAXVERT + i ] *= AST__DD2R; } /* Select a JSA instrument and get the parameters defining the layout of tiles for the selected instrument. */ smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &tiling, status ); /* Create a frame in which to define the region - we arbitrarily use tile 1. */ smf_jsatile( 1, &tiling, 0, NULL, &fs, NULL, lbnd, ubnd, status ); /* Create the region. */ region = (AstRegion *) astPolygon( fs, nvert_ra, MAXVERT, vertex_data, NULL, " " ); /* If the region is unbounded, it is probably because the vertices were given in the wrong order. Invert the Polyfon to correct this. */ if( !astGetI( region, "bounded" ) ) astNegate( region ); /* Get the list of identifiers for tiles that overlap the region. */ tiles = smf_jsatiles_region( region, &tiling, &ntile, status ); } /* If the IN parameter could not be accessed as a Region, annull any error and get a group of input data files. */ if( !region || *status == SAI__ERROR ) { if( *status != SAI__OK ) errAnnul( status ); kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status ); /* Get a group containing just the files holding science data. */ smf_find_science( NULL, igrp, &sgrp, 0, NULL, NULL, 1, 1, SMF__NULL, NULL, NULL, NULL, NULL, status ); /* Check we have at least once science file. */ ssize = grpGrpsz( sgrp, status ); if( ssize == 0 ) { msgOutif( MSG__NORM, " ", "None of the supplied input frames were SCIENCE.", status ); /* Get the list of identifiers for tiles that receive any data. */ } else { tiles = smf_jsatiles_data( sgrp, ssize, &tiling, &ntile, status ); } /* Delete the groups. */ if( igrp ) grpDelet( &igrp, status); if( sgrp ) grpDelet( &sgrp, status); } /* Sort the list of overlapping tiles into ascending order. */ if( *status == SAI__OK ) { qsort( tiles, ntile, sizeof( *tiles ), jsatilelist_icomp ); /* Display the list of overlapping tiles. */ msgBlank( status ); msgOutf( "", " %s tiles touched by supplied data:", status, tiling.name ); msgBlank( status ); for( i = 0; i < ntile; i++ ) { msgSeti( "I", tiles[ i ] ); msgOut( "", " ^I", status ); } msgBlank( status ); /* Write out the list of overlapping tiles to the output parameter. */ parPut1i( "TILES", ntile, tiles, status ); } /* Free resources. */ tiles = astFree( tiles ); /* End the AST context. */ astEnd; /* Issue a status indication.*/ msgBlank( status ); if( *status == SAI__OK ) { msgOutif( MSG__VERB, "", "JSATILELIST succeeded.", status); } else { msgOutif( MSG__VERB, "", "JSATILELIST failed.", status); } }