예제 #1
0
void smurf_rawrewrtsc2wcs( int * status ) {

  size_t i;
  Grp *igrp = NULL;          /* Input group */
  size_t size;               /* Number of files in input group */


  if (*status != SAI__OK) return;

  ndfBegin();

  /* Read the input file group */
  kpg1Rgndf( "NDF", 0, 1, "", &igrp, &size, status );

  for (i=1; i<=size && ( *status == SAI__OK ); i++) {
    int indf = NDF__NOID;
    smfData *data = NULL;
    AstFrameSet * fixedwcs = NULL;
    int isok = 1;

    /* First open in READ mode as a sanity check */
    smf_open_file( igrp, i, "READ", 0, &data, status );
    if (*status != SAI__OK) break;
    if (data->hdr->instrument != INST__SCUBA2) {
      isok = 0;
      msgOut( "", "This command only works on SCUBA-2 data files", status );
    }

    /* Get a fixed WCS frameset */
    if (isok) {
      smf_create_tswcs( data->hdr, &fixedwcs, status );
    }

    /* close up and skip if this is not a good file */
    smf_close_file( &data, status );
    if (!isok) continue;

    /* Now we try to update the file using NDF */
    ndgNdfas( igrp, i, "UPDATE", &indf, status );
    ndfPtwcs( fixedwcs, indf, status );
    ndfAnnul( &indf, status );
  }

  /* Cleanup */
  grpDelet( &igrp, status);
  ndfEnd( status );
}
예제 #2
0
void smf_open_ndfname( const HDSLoc *loc, const char accmode[],
                       const char extname[], const char state[], const char dattype[],
                       const int ndims, const int lbnd[], const int ubnd[],
                       const char datalabel[], const char dataunits[],
                       const AstFrameSet* wcs,
                       smfData **ndfdata,
                       int *status) {

  /* Local variables */
  void *datarr[] = { NULL, NULL }; /* Pointers for data */
  int dims[NDF__MXDIM];         /* Extent of each dimension */
  smf_dtype dtype;              /* Data type */
  int flags = 0;                /* Flags for creating smfDA, smfFile and
				   smfHead components in the output smfData */
  int i;
  int ndat;                     /* Number of elements mapped in the requested NDF */
  char ndfaccmode[NDF__SZMMD+1];/* Access mode to use to open the file */
  int ndimsmapped;              /* Number of dimensions in mapped NDF */
  int ndfid;                    /* NDF identifier */
  AstFrameSet *ndfwcs = NULL;   /* Copy of input FrameSet to write to NDF */
  smfFile *newfile = NULL;      /* New smfFile with details of requested NDF */
  int place;                    /* Placeholder for NDF */
  int updating = 0;             /* True if the extension is being updated */

  /* Initialize the output smfData to NULL pointer */
  *ndfdata = NULL;

  if ( *status != SAI__OK ) return;

  /* Check to see if the HDS Locator is null and retrieve the NDF id */
  if ( loc ==  NULL ) {
    errRep( FUNC_NAME, "Given HDS locator is NULL", status );
    return;
  }

  /* Start be assuming the requested access mode can be used for mapping
     and file opening */
  one_strlcpy( ndfaccmode, accmode, sizeof(ndfaccmode), status );

  /* Note: write access clears the contents of the NDF */
  if ( strncmp( accmode, "WRITE", 5 ) == 0 ) {
    msgOutif(MSG__DEBUG," ", "Opening NDF with WRITE access: this will clear the current contents if the NDF exists.", status);
    updating = 1;

    /* We can have WRITE/ZERO or WRITE/BAD so we need to force WRITE
       into the NDF open access mode */
    one_strlcpy( ndfaccmode, "WRITE", sizeof(ndfaccmode), status );

  } else if ( strncmp( accmode, "UPDATE", 6) == 0) {
    updating = 1;
  }
  ndfOpen( loc, extname, ndfaccmode, state, &ndfid, &place, status );
  if ( *status != SAI__OK ) {
    errRep( FUNC_NAME,
	    "Call to ndfOpen failed: unable to obtain an NDF identifier",
	    status );
    return;
  }

  /* No placeholder => NDF exists */
  if ( place != NDF__NOPL ) {
    /* Define properties of NDF */
    ndfNew( dattype, ndims, lbnd, ubnd, &place, &ndfid, status );
    if ( *status != SAI__OK ) {
      errRep( FUNC_NAME, "Unable to create a new NDF", status );
      return;
    }
  }

  /* Convert the data type string to SMURF dtype */
  dtype = smf_dtype_fromstring( dattype, status );

  /* First step is to create an empty smfData with no extra components */
  flags |= SMF__NOCREATE_DA;
  flags |= SMF__NOCREATE_FTS;
  flags |= SMF__NOCREATE_HEAD;
  flags |= SMF__NOCREATE_FILE;
  *ndfdata = smf_create_smfData( flags, status);
  /* Set the requested data type */
  (*ndfdata)->dtype = dtype;

  /* OK, now map the data array */
  ndfMap( ndfid, "DATA", dattype, accmode, &datarr[0], &ndat, status );
  if ( *status != SAI__OK ) {
    errRep( FUNC_NAME, "Unable to map data array: invalid NDF identifier?", status );
  }
  /* Retrieve dimensions of mapped array */
  ndfDim( ndfid, NDF__MXDIM, dims, &ndimsmapped, status );
  if ( *status != SAI__OK ) {
    errRep( FUNC_NAME, "Problem identifying dimensions of requested NDF", status );
  }
  /* Consistency check */
  if ( ndimsmapped != ndims ) {
    if ( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "Number of dimensions in new NDF not equal to number of dimensions specified", status );
    }
  }

  if (*status == SAI__OK) {
    for (i=0; i<ndims; i++) {
      ((*ndfdata)->dims)[i] = dims[i];
      ((*ndfdata)->lbnd)[i] = lbnd[i];
    }
  }

  /* Allow for label, units and WCS to be written */
  if (updating) {
    if (datalabel) ndfCput( datalabel, ndfid, "Label", status );
    if (dataunits) ndfCput( dataunits, ndfid, "Unit", status );
    if (wcs) {
      /* Take a copy of the input WCS and modify if necessary that
	 before writing to the NDF */
      ndfwcs = astCopy( wcs );
      smf_set_moving( (AstFrame *) ndfwcs, NULL, status );
      ndfPtwcs( ndfwcs, ndfid, status );
      if (ndfwcs) ndfwcs = astAnnul( ndfwcs );
    }
  }


  /* Create the smfFile */
  newfile = smf_construct_smfFile( newfile, ndfid, 0, 0, NULL, status );
  if ( *status != SAI__OK ) {
    errRep( FUNC_NAME, "Unable to construct new smfFile", status );
  }

  /* And populate the new smfData */
  *ndfdata = smf_construct_smfData( *ndfdata, newfile, NULL, NULL, NULL, dtype,
                                    datarr, NULL, SMF__QFAM_NULL, NULL, 0, 1,
                                    (*ndfdata)->dims, (*ndfdata)->lbnd, ndims,
                                    0, 0, NULL, NULL, status );

}
예제 #3
0
static void smf1_jsadicer( int indfo, int *olbnd, int *oubnd,
                           AstMapping *tile_map, AstFrame *tile_frm,
                           AstMapping *p2pmap, void *ipd, void *ipv,
                           unsigned char *ipq, int *status ){
/*
*  Name:
*     smf1_jsadicer

*  Purpose:
*     Copy one tile from the input NDF into a specified output NDF.

*  Language:
*     Starlink ANSI C

*  Type of Module:
*     C function

*  Invocation:
*     void smf1_jsadicer( int indfo, int *olbnd, int *oubnd,
*                         AstMapping *tile_map, AstFrame *tile_frm,
*                         AstMapping *p2pmap, void *ipd, void *ipv,
*                         unsigned char *ipq, int *status )

*  Arguments:
*     indfo = int (Given)
*        An identifier for the NDF in which the copied data is to be
*        stored. It's original pixel bounds are used as the bounds of the
*        ipd, ipv and ipq arrays.
*     olbnd = int * (Given)
*        The new lower pixel bounds required for the output NDF. The bounds
*        of the supplied NDF are changed to match these values.
*     oubnd = int * (Given)
*        The new upper pixel bounds required for the output NDF. The bounds
*        of the supplied NDF are changed to match these values.
*     tile_map = AstMapping * (Given)
*        The mapping from pixel coords in the output NDF to WCS coords.
*     tile_frm = AstMapping * (Given)
*        The WCS Frame for the output NDF.
*     p2pmap = AstMapping * (Given)
*        The mapping from pixel coords in the input NDF to pixel coords in
*        the output NDF.
*     ipd = void * (Given)
*        Pointer to the start of the input data array. If this is NULL,
*        the existing contents of the NDF are used as input.
*     ipv = void * (Given)
*        Pointer to the start of the input variance array. Should be NULL
*        if no variances are available.
*     ipq = unsigned char * (Given)
*        Pointer to the start of the input quality array. Should be NULL
*        if no quality is available.
*     status = int * (Given)
*        Pointer to the inherited status variable.
*/

/* Local Variables: */
   AstFrame *use_frm = NULL;
   AstFrameSet *owcs;
   AstMapping *use_map = NULL;
   AstMapping *use_p2pmap = NULL;
   AstShiftMap *sm;
   char type[ NDF__SZTYP + 1 ];
   double shifts[ 3 ];
   int axes[ 2 ];
   int axout[ NDF__MXDIM ];
   int free_arrays;
   int isreal;
   int lbnd_tile[ 3 ];
   int ndim;
   int nel;
   int nin;
   int there;
   int ubnd_tile[ 3 ];
   unsigned char *ipq_out = NULL;
   void *ipd_out = NULL;
   void *ipv_out = NULL;

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST context. */
   astBegin;

/* Get the NDF data type - _REAL or _DOUBLE. */
   ndfType( indfo, "Data", type, sizeof(type), status );
   isreal = !strcmp( type, "_REAL" );

/* Get the existing bounds of the NDF. */
   ndfBound( indfo, 3, lbnd_tile, ubnd_tile, &ndim, status );

/* If no data array has been supplied, take a copy of the original Data,
   Quality and Variance arrays and use these as the input arrays. */
   if( !ipd ) {
      free_arrays = 1;

      ndfMap( indfo, "Data", type, "Read", &ipd_out, &nel, status );
      ipd = astStore( NULL, ipd_out,
                      nel*(isreal?sizeof(float):sizeof(double)) );
      ndfUnmap( indfo, "Data", status );

      ndfState( indfo, "Variance", &there, status );
      if( there ) {
         ndfMap( indfo, "Variance", type, "Read", &ipv_out, &nel, status );
         ipv = astStore( NULL, ipv_out,
                         nel*(isreal?sizeof(float):sizeof(double)) );
         ndfUnmap( indfo, "Variance", status );
      } else {
         ipv = NULL;
      }

      ndfState( indfo, "Quality", &there, status );
      if( there ) {
         ndfMap( indfo, "Quality", "_UBYTE", "Read", (void **) &ipq_out,
                 &nel, status );
         ipq = astStore( NULL, ipq_out, nel*sizeof(*ipq) );
         ndfUnmap( indfo, "Quality", status );
      } else {
         ipq = NULL;
      }

   } else {
      free_arrays = 0;
   }

/* Set the bounds of the NDF to the required values. */
   ndfSbnd( ndim, olbnd, oubnd, indfo, status );

/* Erase the existing WCS FrameSet and then get the default WCS FrameSet. */
   ndfReset( indfo, "WCS", status );
   ndfGtwcs( indfo, &owcs, status );

/* If the supplied mapping and Frame have two many axes, strip some off.
   The orering of pixel axes in the output JSA tile is hardwired by SMURF
   as (ra,dec,spec). */
   nin = astGetI( tile_map, "Nin" );
   if( nin == 3 && ndim == 2 ) {
      axes[ 0 ] = 1;
      axes[ 1 ] = 2;
      astMapSplit( tile_map, 2, axes, axout, &use_map );
      if( use_map ) {
         use_frm = astPickAxes( tile_frm, 2, axout, NULL );
      } else if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( " ", "smf1_jsadicer: cannot split mapping (programming "
                  "error).", status );
      }

      astMapSplit( p2pmap, 2, axes, axout, &use_p2pmap );
      if( !use_p2pmap && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( " ", "smf1_jsadicer: cannot split mapping (programming "
                  "error).", status );
      }

   } else if( nin == ndim ) {
      use_p2pmap = astClone( p2pmap );
      use_map = astClone( tile_map );
      use_frm = astClone( tile_frm );

   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRepf( " ", "smf1_jsadicer: unexpected combination of nin (%d) and "
               "ndim (%d) (programming error).", status, nin, ndim );
   }

/* Add the tile WCS Frame into the output NDF's WCS FrameSet, using "tilemap"
   to connect it to the PIXEL Frame (NDF ensure Frame 2 is the PIXEL
   Frame). */
   astAddFrame( owcs, 2, use_map, use_frm );

/* The astResample function is odd in that it assumes that pixel coords
   are defined such that the centre of pixel "I" has integral pixel
   coord "I" (rather than "I-0.5" as is usual in Starlink). So we need to
   use a half-pixel ShiftMap at start and end of the p2pmap Mapping to
   account for this. */
   shifts[ 0 ] = -0.5;
   shifts[ 1 ] = -0.5;
   shifts[ 2 ] = -0.5;
   sm = astShiftMap( ndim, shifts, " " );
   use_p2pmap = (AstMapping *) astCmpMap( sm, use_p2pmap, 1, " " );
   astInvert( sm );
   use_p2pmap = (AstMapping *) astCmpMap( use_p2pmap, sm, 1, " " );

/* Store this modified WCS FrameSet in the output NDF. */
   ndfPtwcs( owcs, indfo, status );

/* Map the required arrays of the output NDF. */
   ndfMap( indfo, "Data", type, "Write", &ipd_out, &nel, status );
   if( ipv ) ndfMap( indfo, "Variance", type, "Write", &ipv_out, &nel,
                     status );
   if( ipq ) ndfMap( indfo, "Quality", "_UBYTE", "Write",
                      (void **) &ipq_out, &nel, status );

/* Copy the input data values to the output, using nearest neighbour
   interpolation (the mapping should always map input pixel centres onto
   output pixel centres). We can set the "tol" argument non-zero (e.g. 0.1)
   without introducing any error because the the p2pmap mapping will be
   piecewise linear. This gives a factor of about 5 decrease in the time
   spent within astResample. */
   if( !strcmp( type, "_REAL" ) ) {
      (void) astResampleF( use_p2pmap, ndim, lbnd_tile, ubnd_tile, (float *) ipd,
                           (float *) ipv, AST__NEAREST, NULL, NULL,
                           AST__USEBAD, 0.1, 1000, VAL__BADR, ndim,
                           olbnd, oubnd, olbnd, oubnd,
                           (float *) ipd_out, (float *) ipv_out );
   } else {
      (void) astResampleD( use_p2pmap, ndim, lbnd_tile, ubnd_tile, (double *) ipd,
                           (double *) ipv, AST__NEAREST, NULL, NULL,
                           AST__USEBAD, 0.1, 1000, VAL__BADD, ndim,
                           olbnd, oubnd, olbnd, oubnd,
                           (double *) ipd_out, (double *) ipv_out );
   }

   if( ipq ) {
      (void) astResampleUB( use_p2pmap, ndim, lbnd_tile, ubnd_tile, ipq, NULL,
                            AST__NEAREST, NULL, NULL, 0, 0.1, 1000, 0,
                            ndim, olbnd, oubnd, olbnd, oubnd, ipq_out,
                            NULL );
   }

/* Unmap everything the output NDF. */
   ndfUnmap( indfo, "*", status );

/* Free the input arrays if they were allocated in this function. */
   if( free_arrays ) {
      ipd = astFree( ipd );
      ipv = astFree( ipv );
      ipq = astFree( ipq );
   }

/* End the AST context. */
   astEnd;
}
예제 #4
0
void smf_write_flagmap( ThrWorkForce *wf, smf_qual_t mask, smfArray *lut, smfArray *qua,
                        smfDIMMData *dat, const Grp *flagrootgrp,
                        size_t contchunk, const int *lbnd_out,
                        const int *ubnd_out, AstFrameSet *outfset,
                        int *status ) {

  AstFrameSet *tfset;          /* Temporary FrameSet pointer */
  Grp *mgrp=NULL;               /* Temporary group for map names */
  char *pname=NULL;             /* Poiner to name */
  char name[GRP__SZNAM+1];      /* Buffer for storing names */
  char tempstr[20];             /* Temporary string */
  char tmpname[GRP__SZNAM+1];   /* temp name buffer */
  dim_t nbolo;                  /* Number of bolometers */
  dim_t ntslice;                /* Number of time slices */
  double shift[ 1 ];            /* Shift from GRID to bit number */
  int *flagmap=NULL;            /* pointer to flagmap data */
  int *lut_data=NULL;           /* Pointer to DATA component of lut */
  int ibit;                     /* Quality bit number */
  int lbnd3d[3];                /* Lower bounds for 3D output */
  int npix;                     /* Number of pixels per plane */
  int target;                   /* Target value for incrementing pixel count */
  int ubnd3d[3];                /* Upper bounds for 3D output */
  size_t bstride;               /* Bolometer stride */
  size_t i;                     /* loop counter */
  size_t idx=0;                 /* index within subgroup */
  size_t ii;                    /* array offset index */
  size_t j;                     /* loop counter */
  size_t tstride;               /* Time stride */
  smfData *mapdata=NULL;        /* smfData for new map */
  smf_qual_t *qua_data=NULL;    /* Pointer to DATA component of qua */

  if( *status != SAI__OK ) return;

  if( !lut || !qua || !dat || !flagrootgrp || !lbnd_out || !ubnd_out ||
      !outfset ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": NULL inputs supplied", status );
    return;
  }

  /* Create a name for the flagmap, taking into account the chunk
     number. Only required if we are using a single output
     container. */
  pname = tmpname;
  grpGet( flagrootgrp, 1, 1, &pname, sizeof(tmpname), status );
  one_strlcpy( name, tmpname, sizeof(name), status );
  one_strlcat( name, ".", sizeof(name), status );

  sprintf(tempstr, "CH%02zd", contchunk);
  one_strlcat( name, tempstr, sizeof(name), status );
  mgrp = grpNew( "flagmap", status );
  grpPut1( mgrp, name, 0, status );

  msgOutf( "", "*** Writing flagmap %s", status, name );

  /* If a non-zero mask value wassupplied, the flagmap is 2-dimensional
     and each pixel value counts the number of samples flagged by any of
     the qualities included in the mask. */
  if( mask ) {

     smf_open_newfile( wf, mgrp, 1, SMF__INTEGER, 2, lbnd_out, ubnd_out, 0, &mapdata,
                       status);
     flagmap = mapdata->pntr[0];

     /* Loop over subgroup index (subarray) */
     for( idx=0; (idx<qua->ndat)&&(*status==SAI__OK); idx++ ) {

          smf_get_dims( qua->sdata[idx], NULL, NULL, &nbolo, &ntslice,
                        NULL, &bstride, &tstride, status );
          qua_data = (qua->sdata[idx]->pntr)[0];
          lut_data = (lut->sdata[idx]->pntr)[0];

          /* Loop over bolometer and time slice and create map */
          for( i=0; i<nbolo; i++ ) {
            /* Skip bolometers only if SMF__Q_BADB is set both in the
               data and the mask */
            if( !(qua_data[i*bstride] & mask & SMF__Q_BADB) ) {
              for( j=0; j<ntslice; j++ ) {
                ii = i*bstride + j*tstride;
                if( (qua_data[ii] & mask) && (lut_data[ii] != VAL__BADI) ) {
                  flagmap[lut_data[ii]]++;
                }
              }
            }
          }
        }

     /* Write WCS */
     smf_set_moving( (AstFrame *) outfset, NULL, status );
     ndfPtwcs( outfset, mapdata->file->ndfid, status );

  /* If the mask is zero, the flagmap is 3-dimensional and contains a
     plane for each quality bit, plus an additional plane (plane 1)
     containing the number of unflagged samples in each pixel. */
  } else {
     lbnd3d[ 0 ] = lbnd_out[ 0 ];
     lbnd3d[ 1 ] = lbnd_out[ 1 ];
     lbnd3d[ 2 ] = -1;
     ubnd3d[ 0 ] = ubnd_out[ 0 ];
     ubnd3d[ 1 ] = ubnd_out[ 1 ];
     ubnd3d[ 2 ] = SMF__NQBITS_TSERIES - 1;

     smf_open_newfile( wf, mgrp, 1, SMF__INTEGER, 3, lbnd3d, ubnd3d, 0,
                       &mapdata, status);
     flagmap = mapdata->pntr[0];

     /* No. of pixels in one plane */
     npix = ( ubnd3d[ 1 ] - lbnd3d[ 1 ] + 1 )*( ubnd3d[ 0 ] - lbnd3d[ 0 ] + 1 );

     /* Loop over each quality bit (-1 == "no flags"). */
     for( ibit = -1; ibit < SMF__NQBITS_TSERIES; ibit++ ) {

        /* The test of each sample is performed by checking if the
           sample's quality value ANDed with "mask" is equal to "target".
           This is requires since ibit==-1 (i.e. "count all samples that
           have no flags set") requires a different logic to the other
           ibit values. */
        if( ibit == -1 ) {
           mask = SMF__Q_GOOD;
           target = 0;
        } else {
           mask = BIT_TO_VAL(ibit);
           target = mask;
        }

        /* Loop over subgroup index (subarray) */
        for( idx=0; (idx<qua->ndat)&&(*status==SAI__OK); idx++ ) {

           smf_get_dims( qua->sdata[idx], NULL, NULL, &nbolo, &ntslice,
                           NULL, &bstride, &tstride, status );
           qua_data = (qua->sdata[idx]->pntr)[0];
           lut_data = (lut->sdata[idx]->pntr)[0];

           /* Loop over bolometer and time slice and create map */
           for( i=0; i<nbolo; i++ ) {

              /* Skip bolometers only if SMF__Q_BADB is set both in the
                 data and the mask */
              for( j=0; j<ntslice; j++ ) {
                 ii = i*bstride + j*tstride;
                 if( ( (qua_data[ii] & mask) == target ) &&
                     (lut_data[ii] != VAL__BADI) ) {
                   flagmap[lut_data[ii]]++;
                 }
              }
           }
        }

        /* Move the pointer on to th enext plane. */
        flagmap += npix;

     /* Next quality bit. */
     }

     /* Take a copy of the supplied FrameSet so we do not modify it. */
     tfset = astCopy( outfset );

     /* Set atributes for moving target if necessary. */
     smf_set_moving( (AstFrame *) tfset, NULL, status );

     /* Modify the WCS FrameSet so that the base and current Frames are
        3-dimensional. The current Frame is expanded by adding in a simple
        1D Frame representing quality bit, and the base Frame is expanded
        by adding in a 3rd GRID axis. Other Frames are left unchanged.
        The quality bit Frame and the new GRID axis are connected using
        a ShiftMap that gives the right zero-based bit numbers (which
        also correspond to PIXEL indices). */
     shift[ 0 ] = -2.0;
     atlAddWcsAxis( tfset, (AstMapping *) astShiftMap( 1, shift, " " ),
                    astFrame( 1, "Label(1)=Quality bit,Domain=QUALITY" ),
                    NULL, NULL, status );

     /* Store the FrameSet in the 3D NDF. */
     ndfPtwcs( tfset, mapdata->file->ndfid, status );

     tfset = astAnnul( tfset );
  }

  /* Clean up */
  if( mgrp ) grpDelet( &mgrp, status );
  smf_close_file( wf, &mapdata, status );

}
예제 #5
0
void smf_write_itermap( ThrWorkForce *wf, const double *map, const double *mapvar,
                        const smf_qual_t *mapqua, dim_t msize,
                        const Grp *iterrootgrp, size_t contchunk, int iter,
                        const int *lbnd_out, const int *ubnd_out,
                        AstFrameSet *outfset, const smfHead *hdr,
                        const smfArray *qua, int *status ) {

  int flags;                  /* Flags indicating required NDF components */
  Grp *mgrp=NULL;             /* Temporary group to hold map name */
  smfData *imapdata=NULL;     /* smfData for this iteration map */
  char name[GRP__SZNAM+1];    /* Buffer for storing name */
  char *pname=NULL;           /* Poiner to name */
  char tmpname[GRP__SZNAM+1]; /* temp name buffer */
  char tempstr[20];

  if( *status != SAI__OK ) return;

  if( !map || !mapvar || !iterrootgrp || !lbnd_out || !ubnd_out || !outfset ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": NULL inputs supplied", status );
    return;
  }

  if( hdr && !qua ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": hdr supplied but qua is NULL", status );
    return;
  }

  /* Create a name for this iteration map, take into
     account the chunk number. Only required if we are
     using a single output container. */

  pname = tmpname;
  grpGet( iterrootgrp, 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 );

  /* Iteration number */
  sprintf( tempstr, "I%03i", iter+1 );
  one_strlcat( name, tempstr, sizeof(name), status );
  mgrp = grpNew( "itermap", status );
  grpPut1( mgrp, name, 0, status );

  msgOutf( "", "*** Writing map from this iteration to %s", status,
           name );

  flags = SMF__MAP_VAR;
  if( mapqua ) flags |= SMF__MAP_QUAL;

  smf_open_newfile ( wf, mgrp, 1, SMF__DOUBLE, 2, lbnd_out,
                     ubnd_out, flags, &imapdata, status);

  /* Copy over the signal and variance maps */
  if( *status == SAI__OK ) {
    memcpy( imapdata->pntr[0], map, msize*sizeof(*map) );
    memcpy( imapdata->pntr[1], mapvar, msize*sizeof(*mapvar) );
    if( mapqua ) memcpy( imapdata->qual, mapqua, msize*sizeof(*mapqua) );
  }

  /* Write out a FITS header */
  if( (*status == SAI__OK) && hdr && hdr->allState ) {
    AstFitsChan *fitschan=NULL;
    JCMTState *allState = hdr->allState;
    char *obsidss=NULL;
    char obsidssbuf[SZFITSTR];
    double iter_nboloeff;
    size_t nmap;
    size_t ngood_tslices;
    dim_t ntslice;                /* Number of time slices */

    fitschan = astFitsChan ( NULL, NULL, " " );

    obsidss = smf_getobsidss( hdr->fitshdr,
                              NULL, 0, obsidssbuf,
                              sizeof(obsidssbuf), status );
    if( obsidss ) {
      atlPtfts( fitschan, "OBSIDSS", obsidss,
                "Unique observation subsys identifier", status );
    }
    atlPtfti( fitschan, "SEQSTART", allState[0].rts_num,
              "RTS index number of first frame", status );

    ntslice = hdr->nframes;

    atlPtfti( fitschan, "SEQEND", allState[ntslice-1].rts_num,
              "RTS index number of last frame", status );

    /* calculate the effective number of bolometers for this
       iteration */
    smf_qualstats_model( wf, SMF__QFAM_TSERIES, 1, qua, NULL, NULL, &nmap,
                         NULL, NULL, &ngood_tslices, NULL, NULL, status );

    iter_nboloeff = (double)nmap / (double)ngood_tslices;
    atlPtftd( fitschan, "NBOLOEFF", iter_nboloeff,
              "Effective bolometer count", status );

    kpgPtfts( imapdata->file->ndfid, fitschan, status );

    if( fitschan ) fitschan = astAnnul( fitschan );
  }

  /* Write WCS (protecting the pointer dereference) */
  smf_set_moving(outfset,NULL,status);
  if (*status == SAI__OK && imapdata) {
    ndfPtwcs( outfset, imapdata->file->ndfid, status );
  }

  /* Clean up */
  if( mgrp ) grpDelet( &mgrp, status );
  smf_close_file( wf, &imapdata, status );
}
예제 #6
0
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 );

}
예제 #7
0
void smurf_jsatileinfo( int *status ) {

/* Local Variables */
   AstCmpRegion *overlap;
   AstFitsChan *fc;
   AstFrameSet *fs;
   AstObject *obj;
   AstRegion *region;
   AstRegion *target;
   HDSLoc *cloc = NULL;
   HDSLoc *xloc = NULL;
   char *jcmt_tiles;
   char *tilendf = NULL;
   char text[ 200 ];
   double dec[ 8 ];
   double dist;
   double dlbnd[ 2 ];
   double dubnd[ 2 ];
   double gx[ 8 ];
   double gy[ 8 ];
   double maxdist;
   double norm_radec[2];
   double point1[ 2 ];
   double point2[ 2 ];
   double ra[ 8 ];
   double ra0;
   double dec0;
   int *ipntr;
   int axes[ 2 ];
   int create;
   int dirlen;
   int el;
   int exists;
   int flag;
   int i;
   int indf1;
   int indf2;
   int indf3;
   int itile;
   int iv;
   int jtile;
   int lbnd[ 2 ];
   int local_origin;
   int nc;
   int place;
   int tlbnd[ 2 ];
   int tubnd[ 2 ];
   int ubnd[ 2 ];
   smf_jsaproj_t proj;
   int xt;
   int yt;
   smfJSATiling skytiling;
   void *pntr;

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Start a new AST context. */
   astBegin;

/* Get the instrument to use abnd get the parameters describing the
   layout of its JSA tiles. */
   smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &skytiling,
                      status );

/* Return the maximum tile index. */
   parPut0i( "MAXTILE", skytiling.ntiles - 1, status );

/* Abort if an error has occurred. */
   if( *status != SAI__OK ) goto L999;

/* Decide what sort of projection to use. */
   parChoic( "PROJ", "HPX", "HPX,HPX12,XPHN,XPHS", 1, text, sizeof(text),
             status );
   proj = smf_jsaproj_fromstr( text, 1, status );

/* If required, create an all-sky NDF in which each pixel covers the area
   of a single tile, and holds the integer tile index. The NDF has an
   initial size of 1x1 pixels, but is expanded later to the required size. */
   lbnd[ 0 ] = ubnd[ 0 ] = lbnd[ 1 ] = ubnd[ 1 ] = 1;
   ndfCreat( "ALLSKY", "_INTEGER", 2, lbnd, ubnd, &indf3, status );

/* If a null (!) value was supplied for parameter ALLSKY, annull the
   error and pass on. */
   if( *status == PAR__NULL ) {
      errAnnul( status );

/* Otherwise, create a FrameSet describing the whole sky in which each
   pixel corresponds to a single tile. */
   } else {
      smf_jsatile( -1, &skytiling, 0, proj, NULL, &fs, NULL, lbnd, ubnd,
                   status );

/* Change the bounds of the output NDF. */
      ndfSbnd( 2, lbnd, ubnd, indf3, status );

/* Store the FrameSet in the NDF. */
      ndfPtwcs( fs, indf3, status );

/* Map the data array. */
      ndfMap( indf3, "Data", "_INTEGER", "WRITE/BAD", (void **) &ipntr, &el,
              status );

/* Create all-sky map using XPH projection. */
      if( *status == SAI__OK ) {

/* Loop round every tile index. */
         for( jtile = 0; jtile < skytiling.ntiles; jtile++ ) {

/* Get the zero-based (x,y) indices of the tile within an HPX projection.
   This flips the bottom left half-facet up to the top right. */
            smf_jsatilei2xy( jtile, &skytiling, &xt, &yt, NULL, status );

/* Convert these HPX indices to the corresponding indices within the
   required projection. Note, the lower left facet is split by the above
   call to smf_jsatilei2xy tile (i.e. (xt,yt) indices are *not* in the
   "raw" mode). For instance, (0,0) is not a valid tile. */
            smf_jsatilexyconv( &skytiling, proj, xt, yt, 0, &xt, &yt, status );

/* Get the vector index of the corresponding element of the all-sky NDF. */
            if( proj == SMF__JSA_HPX || proj == SMF__JSA_HPX12 ) {
               iv = xt + 5*skytiling.ntpf*yt;
            } else {
               iv = xt + 4*skytiling.ntpf*yt;
            }

/* Report an error if this element has already been assigned a tile
   index. Otherwise, store the tile index. */
            if( ipntr[ iv ] == VAL__BADI ) {
               ipntr[ iv ] = jtile;
            } else if( *status == SAI__OK ) {
               *status = SAI__ERROR;
               errRepf( "", "%s projection assigns multiple tiles to "
                        "pixel (%d,%d).", status, text, xt, yt );
               break;
            }
         }
      }

/* Store NDF title. */
      sprintf( text, "JSA tile indices for %s data", skytiling.name );
      ndfCput( text, indf3, "TITLE", status );

/* Store the instrument as a component in the SMURF extension. */
      ndfXnew( indf3, "SMURF", "INSTRUMENT", 0, 0, &xloc, status );
      ndfXpt0c( skytiling.name, indf3, "SMURF", "INSTRUMENT", status );
      datAnnul( &xloc, status );

/* Close the NDF. */
      ndfAnnul( &indf3, status );
   }

/* Abort if an error has occurred. */
   if( *status != SAI__OK ) goto L999;

/* Get the zero-based index of the required tile. If a null value is
   supplied, annull the error and skip to the end. */
   parGdr0i( "ITILE", 0, 0, skytiling.ntiles - 1, 0, &itile, status );
   if( *status == PAR__NULL ) {
       errAnnul( status );
       goto L999;
   }

/* See if the pixel origin is to be at the centre of the tile. */
   parGet0l( "LOCAL", &local_origin, status );

/* Display the tile number. */
   msgBlank( status );
   msgSeti( "ITILE", itile );
   msgSeti( "MAXTILE", skytiling.ntiles - 1);
   msgOut( " ", "   Tile ^ITILE (from 0 to ^MAXTILE):", status );

/* Get the FITS header, FrameSet and Region defining the tile, and the tile
   bounds in pixel indices. */
   smf_jsatile( itile, &skytiling, local_origin,  proj, &fc, &fs, &region,
                lbnd, ubnd, status );

/* Write the FITS headers out to a file, annulling the error if the
   header is not required. */
   if( *status == SAI__OK ) {
      atlDumpFits( "HEADER", fc, status );
      if( *status == PAR__NULL ) errAnnul( status );
   }

/* If required, write the Region out to a text file. */
   if( *status == SAI__OK ) {
      atlCreat( "REGION", (AstObject *) region, status );
      if( *status == PAR__NULL ) errAnnul( status );
   }

/* Store the lower and upper pixel bounds of the tile. */
   parPut1i( "LBND", 2, lbnd, status );
   parPut1i( "UBND", 2, ubnd, status );

/* Display pixel bounds on the screen. */
   msgSeti( "XL", lbnd[ 0 ] );
   msgSeti( "XU", ubnd[ 0 ] );
   msgSeti( "YL", lbnd[ 1 ] );
   msgSeti( "YU", ubnd[ 1 ] );
   msgOut( " ", "      Pixel bounds: (^XL:^XU,^YL:^YU)", status );

/* Get the RA,Dec at the tile centre. */
   if( astTest( fs, "SkyRef" ) ) {
      ra0 = astGetD( fs, "SkyRef(1)" );
      dec0 = astGetD( fs, "SkyRef(2)" );

/* Format the central RA and Dec. and display. Call astNorm on the
   coordinates provided that the frame set has the correct number of
   axes (which it should as it comes from smf_jsatile). */
      norm_radec[0] = ra0;
      norm_radec[1] = dec0;
      if (astGetI(fs, "Naxes") == 2) astNorm(fs, norm_radec);
      msgSetc( "RACEN",  astFormat( fs, 1, norm_radec[ 0 ] ));
      msgSetc( "DECCEN",  astFormat( fs, 2, norm_radec[ 1 ] ));
      msgOut( " ", "      Centre (ICRS): RA=^RACEN DEC=^DECCEN", status );

/* Transform a collection of points on the edge of the region (corners and
   side mid-points) from GRID coords to RA,Dec. */
      point1[ 0 ] = 0.5;
      point1[ 1 ] = 0.5;
      point2[ 0 ] = ubnd[ 0 ] - lbnd[ 0 ] + 1;
      point2[ 1 ] = ubnd[ 1 ] - lbnd[ 1 ] + 1;

      gx[ 0 ] = point1[ 0 ];         /* Bottom left */
      gy[ 0 ] = point1[ 1 ];

      gx[ 1 ] = point1[ 0 ];         /* Centre left */
      gy[ 1 ] = gy[ 0 ];

      gx[ 2 ] = point1[ 0 ];         /* Top left */
      gy[ 2 ] = point2[ 1 ];

      gx[ 3 ] = gx[ 0 ];             /* Top centre */
      gy[ 3 ] = point2[ 1 ];

      gx[ 4 ] = point2[ 0 ];         /* Top right */
      gy[ 4 ] = point2[ 1 ];

      gx[ 5 ] = point2[ 0 ];         /* Centre right */
      gy[ 5 ] = gy[ 0 ];

      gx[ 6 ] = point2[ 0 ];         /* Bottom right */
      gy[ 6 ] = point1[ 1 ];

      gx[ 7 ] = gx[ 0 ];             /* Bottom centre */
      gy[ 7 ] = point1[ 1 ];

      astTran2( fs, 8, gx, gy, 1, ra, dec );

/* Find the arc-distance from the centre to the furthest point from the
   centre. */
      point1[ 0 ] = ra0;
      point1[ 1 ] = dec0;
      maxdist = -1.0;

      for( i = 1; i < 8; i++ ) {
         if( ra[ i ] != AST__BAD && dec[ i ] != AST__BAD ) {
            point2[ 0 ] = ra[ i ];
            point2[ 1 ] = dec[ i ];
            dist = astDistance( fs, point1, point2 );
            if( dist > maxdist ) maxdist = dist;
         }
      }

/* Convert from radius to diameter. */
      maxdist *= 2.0;

/* Format this size as a dec value (i.e. arc-distance) and display it. */
      if( maxdist > 0.0 ) {
         msgSetc( "SIZE",  astFormat( fs, 2, maxdist ) );
         msgOut( " ", "      Size: ^SIZE", status );
      } else {
         maxdist = AST__BAD;
         msgOut( " ", "      Size: <unknown>", status );
      }

/* If a discontinuity passes through the tile, the centre and size may be
   unknown. */
   } else {
      ra0 = AST__BAD;
      dec0 = AST__BAD;
      maxdist = AST__BAD;
      msgOut( " ", "      Centre (ICRS): RA=<unknown> DEC=<unknown>", status );
      msgOut( " ", "      Size: <unknown>", status );
   }

/* Write the tile centre ra and dec in radians to the output parameters. */
   parPut0d( "RACEN", norm_radec[ 0 ], status );
   parPut0d( "DECCEN", norm_radec[ 1 ], status );

/* Write the size to the output parameter as radians. */
   parPut0d( "SIZE", maxdist, status );

/* Get the translation of the environment variable JSA_TILE_DIR. */
   jcmt_tiles = getenv( "JSA_TILE_DIR" );

/* Initialise the path to the tile's NDF to hold the root directory.
   Use the current working directory if JSA_TILE_DIR is undefined. */
   if( jcmt_tiles ) {
      nc = 0;
      tilendf = astAppendString( tilendf, &nc, jcmt_tiles );

   } else {

      nc = 512;
      jcmt_tiles = astMalloc( nc );

      while( !getcwd( jcmt_tiles, nc ) ) {
         nc *= 2;
         jcmt_tiles = astRealloc( jcmt_tiles, nc );
      }

      nc = 0;
      tilendf = astAppendString( tilendf, &nc, jcmt_tiles );
      jcmt_tiles = astFree( jcmt_tiles );
   }

/* Complete the path to the tile's NDF. */
   tilendf = astAppendString( tilendf, &nc, "/" );
   tilendf = astAppendString( tilendf, &nc, skytiling.subdir );
   dirlen = nc;
   sprintf( text, "/tile_%d.sdf", itile );
   tilendf = astAppendString( tilendf, &nc, text );

/* Write it to the output parameter. */
   parPut0c( "TILENDF", tilendf, status );

/* See if the NDF exists, and store the flag in the output parameter. */
   exists = access( tilendf, F_OK ) ? 0 : 1;
   parPut0l( "EXISTS", exists, status );

/* If the NDF does not exist, create it if required. */
   parGet0l( "CREATE", &create, status );
   if( !exists && create && *status == SAI__OK ) {

/* Write the NDF info to the screen. */
      msgSetc( "NDF",  tilendf );
      msgOutif( MSG__NORM, " ", "      NDF: ^NDF (created)", status );

/* Temporarily terminate the NDF path at the end of the subdirectory. */
      tilendf[ dirlen ] = 0;

/* Create the required directory (does nothing if the directory
   already exists).  It is given read/write/search permissions for owner
   and group, and read/search permissions for others. */
      (void) mkdir( tilendf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );

/* Replace the character temporarily overwritten above. */
      tilendf[ dirlen ] = '/';

/* Now create the tile's NDF. */
      ndfPlace( NULL, tilendf, &place, status );
      ndfNew( skytiling.type, 2, lbnd, ubnd, &place, &indf1, status );

/* Fill its data array with zeros. */
      ndfMap( indf1, "Data", skytiling.type, "WRITE/ZERO", &pntr, &el,
              status );

/* Store the WCS FrameSet. */
      ndfPtwcs( fs, indf1, status );

/* If the instrument jsatiles.have variance, fill the variance array with zeros. */
      if( skytiling.var ) {
         ndfMap( indf1, "Variance", skytiling.type, "WRITE/ZERO", &pntr,
                 &el, status );
      }

/* Create a SMURF extension. */
      ndfXnew( indf1, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &xloc, status );

/* Store the tile number and instrument name in the extension. */
      datNew0I( xloc, "TILE", status );
      datFind( xloc, "TILE", &cloc, status );
      datPut0I( cloc, itile, status );
      datAnnul( &cloc, status );

      datNew0C( xloc, "INSTRUMENT", strlen( skytiling.name ), status );
      datFind( xloc, "INSTRUMENT", &cloc, status );
      datPut0C( cloc, skytiling.name, status );
      datAnnul( &cloc, status );

/* Create a weights NDF within the SMURF extension, and fill its data
   array with zeros. */
      ndfPlace( xloc, "WEIGHTS", &place, status );
      ndfNew( skytiling.type, 2, lbnd, ubnd, &place, &indf2, status );
      ndfMap( indf2, "Data", skytiling.type, "WRITE/ZERO", &pntr, &el,
              status );
      ndfPtwcs( fs, indf2, status );
      ndfAnnul( &indf2, status );

/* Annul the extension locator and the main NDF identifier. */
      datAnnul( &xloc, status );
      ndfAnnul( &indf1, status );

/* Write the NDF info to the screen. */
   } else {
      msgSetc( "NDF",  tilendf );
      msgSetc( "E",  exists ? "exists" : "does not exist" );
      msgOut( " ", "      NDF: ^NDF (^E)", status );
   }

/* Initialise TBND and TLBND to indicate no overlap. */
   tlbnd[ 0 ] = 1;
   tlbnd[ 1 ] = 1;
   tubnd[ 0 ] = 0;
   tubnd[ 1 ] = 0;

/* Attempt to to get an AST Region (assumed to be in some 2D sky coordinate
   system) using parameter "TARGET". */
   if( *status == SAI__OK ) {
      kpg1Gtobj( "TARGET", "Region",
                 (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion),
                 &obj, status );

/* Annul the error if none was obtained. */
      if( *status == PAR__NULL ) {
         errAnnul( status );

/* Otherwise, use the supplied object. */
      } else {
         target = (AstRegion *) obj;

/* If the target Region is 3-dimensional, remove the third axis, which
   is assumed to be a spectral axis. */
         if( astGetI( target, "Naxes" ) == 3 ) {
            axes[ 0 ] = 1;
            axes[ 1 ] = 2;
            target = astPickAxes( target, 2, axes, NULL );
         }

/* See if there is any overlap between the target and the tile. */
         overlap = NULL;
         flag = astOverlap( region, target );

         if( flag == 0 ) {
            msgOut( "", "      Cannot convert between the coordinate system of the "
                    "supplied target and the tile.", status );

         } else if( flag == 1 || flag == 6 ) {
            msgOut( "", "      There is no overlap between the target and the tile.",
                    status );

         } else if( flag == 2 ) {
            msgOut( "", "      The tile is contained within the target.",
                    status );
            tlbnd[ 0 ] = lbnd[ 0 ];
            tlbnd[ 1 ] = lbnd[ 1 ];
            tubnd[ 0 ] = ubnd[ 0 ];
            tubnd[ 1 ] = ubnd[ 1 ];

         } else if( flag == 3 ) {
            overlap = astCmpRegion( region, target, AST__AND, " " );

         } else if( flag == 4 ) {
            overlap = astCmpRegion( region, target, AST__AND, " " );

         } else if( flag == 5 ) {
            msgOut( "", "      The target and tile are identical.",
                    status );
            tlbnd[ 0 ] = lbnd[ 0 ];
            tlbnd[ 1 ] = lbnd[ 1 ];
            tubnd[ 0 ] = ubnd[ 0 ];
            tubnd[ 1 ] = ubnd[ 1 ];

         } else if( *status == SAI__OK ) {
            *status = SAI__OK;
            errRepf( "", "Unexpected value %d returned by astOverlap "
                     "(programming error).", status, flag );
         }

/* If a region containing the intersection of the tile and target was
   created above, map it into the grid coordinate system of the tile. */
         if( overlap ) {
            overlap = astMapRegion( overlap, astGetMapping( fs, AST__CURRENT,
                                                            AST__BASE ),
                                    astGetFrame( fs, AST__BASE ) );

/* Get its GRID bounds. */
            astGetRegionBounds( overlap, dlbnd, dubnd );

/* Convert to integer. */
            tlbnd[ 0 ] = ceil( dlbnd[ 0 ] - 0.5 );
            tlbnd[ 1 ] = ceil( dlbnd[ 1 ] - 0.5 );
            tubnd[ 0 ] = ceil( dubnd[ 0 ] - 0.5 );
            tubnd[ 1 ] = ceil( dubnd[ 1 ] - 0.5 );

/* Convert to PIXEL indices within the tile. */
            tlbnd[ 0 ] += lbnd[ 0 ] - 1;
            tlbnd[ 1 ] += lbnd[ 1 ] - 1;
            tubnd[ 0 ] += lbnd[ 0 ] - 1;
            tubnd[ 1 ] += lbnd[ 1 ] - 1;

            msgOutf( "", "      The target overlaps section (%d:%d,%d:%d).",
                     status, tlbnd[ 0 ], tubnd[ 0 ], tlbnd[ 1 ], tubnd[ 1 ] );
         }
      }
   }

/* Store the pixel index bounds of the tiles overlap with the target. */
   parPut1i( "TLBND", 2, tlbnd, status );
   parPut1i( "TUBND", 2, tubnd, status );

/* Arrive here if an error occurs. */
   L999:;

/* Free resources. */
   tilendf = astFree( tilendf );

/* End the AST context. */
   astEnd;

/* Issue a status indication.*/
   msgBlank( status );
   if( *status == SAI__OK ) {
      msgOutif( MSG__VERB, "", "JSATILEINFO succeeded.", status);
   } else {
      msgOutif( MSG__VERB, "", "JSATILEINFO failed.", status);
   }
}
예제 #8
0
void smf_flat_write( smf_flatmeth flatmeth, const char * flatname,
                     double refres, const smfData * bolval,
                     const smfData * powref, const smfData * bolref,
                     const smfData * polyfit, const Grp * prvgrp, int * status ) {

  size_t colsize;              /* number of columns */
  double *dbuf = NULL;         /* input double buffer for mean data */
  double *dvar = NULL;         /* input double buffer for variance of data */
  char fitsrec[SC2STORE__MAXFITS*SZFITSCARD+1]; /* Store for FITS records */
  int *ibuf = NULL;            /* int buffer for mean data */
  int indf = NDF__NOID;        /* NDF identifier for output file */
  size_t ncards;               /* number of fits cards */
  size_t numbols;              /* number of bolometers */
  double *outvar = NULL;       /* buffer for variance of data */
  int place = NDF__NOPL;       /* Dummy placeholder for NDF */
  size_t rowsize;              /* number of rows */
  JCMTState *state = NULL;     /* State for this flatfield */
  sc2ast_subarray_t subnum;    /* subarray number */

  AstFrameSet *result, *spacefset;
  AstLutMap *heatmap;
  AstFrame *heatfrm;


  int *dksquid;           /* pointer to dummy dark SQUID data */
  size_t j;               /* loop counter */
  int jig_vert[1][2];     /* dummy jiggle vertices */
  double jig_path[1][2];  /* dummy jiggle path */
  size_t nframes = 0;     /* Number of frames in bolval */
  int npath = 0;          /* size of jiggle path */
  int nvert = 0;          /* number of jiggle vertices */
  char *xmlfile = NULL;   /* dummy xmlfile name */

  if (*status != SAI__OK) return;

  if (!bolval->da) {
    *status = SAI__ERROR;
    errRep( "", "No flatfield solution provided for writing",
            status );
    return;
  }

  if (!bolval->da->heatval) {
    *status = SAI__ERROR;
    errRep( "", "Must provide heater values in DA struct to smf_flat_write"
            " (possible programming error)", status );
    return;
  }

  /* note that colsize is the number of rows and rowsize is the number of
     columns */
  colsize = (bolval->dims)[SC2STORE__ROW_INDEX];
  rowsize = (bolval->dims)[SC2STORE__COL_INDEX];
  numbols = colsize * rowsize;
  nframes = (bolval->dims)[2];

  /* Make sure we have a FLAT header that reflects this file
     as the flatfield solution */
  smf_fits_updateS( bolval->hdr, "FLAT", flatname, "Name of flat-field file",
                    status );

  /* Create a FITS header for DA */
  smf_fits_export2DA( bolval->hdr->fitshdr, &ncards, fitsrec, status );

  /* Copy the data as integers so it can be written to data file. To
     prevent overflow in the variance we store that as doubles */

  ibuf = astMalloc( (numbols * nframes)*sizeof(*ibuf) );
  outvar = astMalloc( (numbols * nframes)*sizeof(*outvar) );

  dbuf = (bolval->pntr)[0];
  dvar = (bolval->pntr)[1];

  if (*status == SAI__OK) {
    for (j = 0; j < (nframes * numbols); j++) {
      /* These started off as integers so the mean value must fit in
         an integer */
      if ( dbuf[j] == VAL__BADD) {
        ibuf[j] = VAL__BADI;
      } else {
        ibuf[j] = (int)dbuf[j];
      }
      /* Same data type so no need to convert bad values */
      if (dvar) {
        outvar[j] = dvar[j];
      } else {
        outvar[j] = VAL__BADD;
      }
    }
  }

  /* get subarray number */
  smf_find_subarray( bolval->hdr, NULL, 0, &subnum, status );

  /* Create dummy components for output file */
  dksquid = astCalloc ( rowsize* nframes, sizeof(*dksquid) );
  jig_vert[0][0] = 0;
  jig_vert[0][1] = 0;
  jig_path[0][0] = 0.0;
  jig_path[0][1] = 0.0;

  sc2store_setcompflag ( SC2STORE__NONE, status );
  sc2store_wrtstream ( flatname, subnum, ncards,
                       fitsrec, colsize, rowsize, nframes,
                       (bolref->dims)[2], refres, 0, smf_flat_methstring( flatmeth, status ),
                       bolval->hdr->allState, NULL,
                       ibuf, dksquid, (bolref->pntr)[0], (powref->pntr)[0],
                       "FLATCAL", NULL, NULL, jig_vert,
                       nvert, jig_path, npath, xmlfile, status );

  sc2store_free ( status );

  /* To copy in the variance and modify fix up the WCS we need to reopen
     the file */

  ndfOpen( NULL, flatname, "UPDATE", "OLD", &indf, &place, status );

  /* make sure that history is not written twice */
  ndfHsmod( "SKIP", indf, status );

  if (outvar) {
    void *pntr[3];
    int el;
    ndfStype( "_DOUBLE", indf, "VARIANCE", status );
    ndfMap( indf, "VARIANCE", "_DOUBLE", "WRITE", pntr, &el, status );
    if (*status == SAI__OK) {
      memcpy( pntr[0], outvar, sizeof(*outvar)*el );
    }
  }

  /* For the WCS a time frame is less relevant than heater settings */
  astBegin;

  /* Create frame for focal plane coordinates */
  sc2ast_createwcs( subnum, NULL, NULL, NULL, NO_FTS, &spacefset, status );

  /* Copy it to make sure we do not mess with the cache */
  result = astCopy( spacefset );

  /* and switch to BOLO frame which is best for bolometer analysis */
  {
    int frnum = AST__NOFRAME;
    kpg1Asffr( result, "BOLO", &frnum, status );
    if (frnum != AST__NOFRAME) astSetI( result, "CURRENT", frnum );
  }

  /* Create a simple frame for heater settings */
  heatfrm = astFrame( 1, "Domain=HEATER,Label(1)=Heater Setting" );
  heatmap = astLutMap( nframes, bolval->da->heatval, 1.0, 1.0, " " );

  /* Append the heater axis to the spatial frameset */
  atlAddWcsAxis( result, (AstMapping *)heatmap, (AstFrame *) heatfrm,
                 NULL, NULL, status );

  /* write it to the NDF */
  ndfPtwcs( result, indf, status );


  /* Write provenance information */
  if (prvgrp) {
    size_t size = grpGrpsz( prvgrp, status );
    char prvname[ 2 * PAR__SZNAM + 1];

    smf_get_taskname( NULL, prvname, status );
    for (j=1; j<=size; j++) {
      smf_accumulate_prov( NULL, prvgrp, j, indf, prvname, NULL, status );
    }

  }

  /* Write the polynomial expansion into an extension */
  if (polyfit) {
    char fitfile[GRP__SZNAM+1];
    int fndf = NDF__NOID;
    place = NDF__NOPL;
    one_strlcpy( fitfile, flatname, sizeof(fitfile), status );
    one_strlcat( fitfile, ".MORE.SMURF.FLATFIT", sizeof(fitfile), status );

    /* create the file */
    smf_write_smfData( polyfit, NULL, fitfile, NULL, 0, NDF__NOID,
                       MSG__VERB, 0, status );

    /* Same WCS as the main file */
    ndfOpen( NULL, fitfile, "UPDATE", "OLD", &fndf, &place, status );
    ndfPtwcs( result, fndf, status );
    ndfAnnul( &fndf, status );

  }

  astEnd;

  ndfAnnul( &indf, status);

  if (ibuf) ibuf = astFree( ibuf );
  if (outvar) outvar = astFree( outvar );
  if (dksquid) dksquid = astFree( dksquid );
  if (state) state = astFree( state );
}
예제 #9
0
void smf_store_image( smfData *data, HDSLoc *scu2redloc, int cycle, int ndim,
		      int dims[], int nsampcycle, int vxmin, int vymin,
		      double *image, double *zero, int *status) {

  smfHead *hdr = NULL;             /* Pointer to header struct */
  HDSLoc *bz_imloc = NULL;         /* HDS locator */
  int bzindf;                      /* NDF identifier for bolometer zero points */
  double *bzptr = NULL;            /* Pointer to mapped space for zero points */
  int el;                          /* Number of elements mapped */
  int frame;                       /* Mean timeslice index for image */
  AstFitsChan *imfits=NULL;        /* FITS header for each reconstructed image */
  char imname[DAT__SZNAM];         /* Name of structure for image */
  double *imptr = NULL;            /* Pointer to mapped space for image */
  int j;                           /* Loop counter */
  int lbnd[2];                     /* Lower dimension bounds */
  int ntot;                        /* Total number of elements */
  int place;                       /* NDF placeholder */
  char prvname[2*PAR__SZNAM +1];   /* Provenance creator */
  int seqend;                      /* End index */
  int seqstart;                    /* Starting index */
  int slice;                       /* Index of current time slice */
  int strnum;                      /* Structure element number */
  sc2ast_subarray_t subnum;        /* Subarray index number */
  int ubnd[2];                     /* Upper dimension bounds */
  int uindf;                       /* NDF identifier */
  AstFrameSet *wcs = NULL;         /* WCS info */

  if ( *status != SAI__OK ) return;

  seqstart = cycle * nsampcycle;
  seqend = seqstart + nsampcycle - 1;

  slice = (int)( (seqstart + seqend ) /2);
  smf_tslice_ast( data, slice, 1, status);

  astBegin;

  /* Old beginning */

  /* Get structure for nth constructed image */
  strnum = cycle + 1;
  sprintf ( imname, "I%d", strnum );

  ntot = 1;
  for ( j=0; j<ndim; j++ ) {
    lbnd[j] = 1;
    ubnd[j] = lbnd[j] + dims[j] - 1;
    ntot *= dims[j];
  }
  ndfPlace ( scu2redloc, imname, &place, status );
  ndfNew ( "_DOUBLE", ndim, lbnd, ubnd, &place, &uindf, status );
  ndfHcre ( uindf, status );

  /* Map the data array */
  ndfMap ( uindf, "DATA", "_DOUBLE", "WRITE", (void *)&imptr, &el,
	   status );

  /* Copy image array */
  if ( *status == SAI__OK ) {
    memcpy( imptr, image, ntot*sizeof(*imptr));
  }

  /* Derive WCS */
  hdr = data->hdr;
  smf_find_subarray(hdr, NULL, 0, &subnum, status );
  sc2ast_createwcs( subnum, hdr->state, hdr->instap, hdr->telpos, &wcs, status );

  /* Shift the coord frame is either vxmin or vymin is non-zero */
  if ( vxmin != 0 || vymin != 0 ) {
    sc2ast_moveframe ( -(double)vxmin, -(double)vymin, wcs, status );
  }

  /* This should probably be a user-option but ICRS is probably a safe
     assumption */
  sc2ast_set_output_system( hdr->state->tcs_tr_sys, wcs, status );

  /* Sort out provenance. */
  smf_get_taskname( NULL, prvname, status );
  smf_updateprov( uindf, data, NDF__NOID, prvname, NULL, status );

  /* Store world coordinate transformations */
  ndfPtwcs ( wcs, uindf, status );

  /* Store the bolometer zero points as an NDF in the extension */
  if (zero) {
    ndfXnew ( uindf, "BOLZERO", "SCUBA2_ZER_ARR", 0, 0, &bz_imloc,
	      status );
    ndfPlace ( bz_imloc, "ZERO", &place, status );

    /* Create the array for bolometer zeros */
    lbnd[0] = SC2STORE__BOL_LBND;
    ubnd[0] = lbnd[0] + dims[0] - 1;
    lbnd[1] = SC2STORE__BOL_LBND;
    ubnd[1] = lbnd[1] + dims[1] - 1;
    ndfNew ( "_DOUBLE", 2, lbnd, ubnd, &place, &bzindf, status );
    ndfHcre ( bzindf, status );

    /* Map the data array */
    ndfMap ( bzindf, "DATA", "_DOUBLE", "WRITE", (void *)&bzptr, &el,
	     status );

    /* Copy image array */
    if ( *status == SAI__OK ) {
      memcpy( bzptr, zero, dims[0]*dims[1]*sizeof(*zero));
    }

    /* Unmap the data array */
    ndfUnmap ( bzindf, "DATA", status );
    ndfAnnul ( &bzindf, status );

    /* Free the locators for the frame */
    datAnnul ( &bz_imloc, status );

  }

  /* Store the FITS headers */
  frame = (int)( (seqstart + seqend ) /2);
  /* Quick and dirty method - just copy the full FITS header */
  imfits = astCopy( hdr->fitshdr );
  astSetFitsI( imfits, "SUBSCAN", strnum,
	       "Subscan number of reconstructed image", 0);

  kpgPtfts( uindf, imfits, status );

  /* Unmap the data array */
  ndfUnmap ( uindf, "DATA", status );
  ndfAnnul ( &uindf, status );

  astEnd;

}
예제 #10
0
void smf_add_spectral_axis( int indf, AstFitsChan *fc, int *status ){

/* Local Variables */
   AstFrame *cfrm;         /* Pointer to the current WCS Frame in the NDF */
   AstFrameSet *wcs;       /* Pointer to the WCS FrameSet for the NDF */
   AstSpecFrame *specfrm;  /* Pointer to the new SpecFrame */
   AstWinMap *specmap;     /* Pointer to Mapping from GRID to wavelength */
   char attrib[ 10 ];      /* Buffer for attribute name */
   double bandwid;         /* Bandwidth, in metres */
   double grid_hi;         /* GRID coord at upper edge of spectral pixel */
   double grid_lo;         /* GRID coord at lower edge of spectral pixel */
   double ref_lat;         /* Celestial latitude at reference point */
   double ref_lon;         /* Celestial longitude at reference point */
   double spec_hi;         /* Wavelength at upper edge of spectral pixel */
   double spec_lo;         /* Wavelength at lower edge of spectral pixel */
   double wavelen;         /* Central wavelength, in metres */
   int lbnd[ NDF__MXDIM ]; /* Original lower pixel bounds of the NDF */
   int ndim;               /* Original number of pixel axis in the the NDF */
   int ubnd[ NDF__MXDIM ]; /* Original lower pixel bounds of the NDF */

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST Object context so that we do not need to annul explicitly
   the AST Objects created in this function. */
   astBegin;

/* Get the pixel bounds of the NDF. */
   ndfBound( indf, NDF__MXDIM, lbnd, ubnd, &ndim, status );

/* Get the required FITS header. Return without further action if either
   is not present in the supplied FitsChan, or if the NDF is not
   2-dimensional. */
   if( astGetFitsF( fc, "WAVELEN", &wavelen ) &&
       astGetFitsF( fc, "BANDWID", &bandwid ) && ndim == 2 ) {

/* Get the current WCS FrameSet from the supplied NDF, and get a pointer
   to its current Frame. */
      ndfGtwcs( indf, &wcs, status );
      cfrm = astGetFrame( wcs, AST__CURRENT );

/* Return without action if this is not a SkyFrame. */
      if( astIsASkyFrame( cfrm ) ) {

/* Construct a topocentric wavelength SpecFrame to describe the new spectral
   WCS axis. */
         specfrm = astSpecFrame( "System=wavelen,StdOfRest=topo,Unit=m" );

/* We set the RefRA and RefDec attributes for the SpecFrame to the FK5
   J2000 equivalent of the SkyRef attribute in the current Frame. */
         sprintf( attrib, "SkyRef(%d)", astGetI( cfrm, "LonAxis" ) );
         ref_lon = astGetD( cfrm, attrib );

         sprintf( attrib, "SkyRef(%d)", astGetI( cfrm, "LatAxis" ) );
         ref_lat = astGetD( cfrm, attrib );

         astSetRefPos( specfrm, cfrm, ref_lon, ref_lat );

/* Inherit other relevant Frame attributes from the SkyFrame. */
#define OVERLAY(attr) \
         if( astTest( cfrm, attr ) ) { \
            astSetC( specfrm, attr, astGetC( cfrm, attr ) ); \
         }

         OVERLAY( "Dut1" );
         OVERLAY( "Epoch" );
         OVERLAY( "ObsAlt" );
         OVERLAY( "ObsLat" );
         OVERLAY( "ObsLon" );

#undef OVERLAY

/* Create a WinMap that gives wavelength as a function of spectral GRID
   position. Assume the pixel centre maps onto WAVELEN and the pixel
   width is BANDWID. */
         grid_lo= 0.5;
         grid_hi = 1.5;
         spec_lo = wavelen - 0.5*bandwid;
         spec_hi = spec_lo + bandwid;
         specmap = astWinMap( 1, &grid_lo, &grid_hi, &spec_lo, &spec_hi, " " );

/* Modify the WCS FrameSet so that the base and current Frames are
   3-dimensional. The current Frame is expanded by adding in the
   SpecFrame, and the base Frame is expanded by adding in a 3rd GRID
   axis. Other Frames are left unchanged. The SpecFrame and the new GRID
   axis are connected using the WinMap created above. */
         atlAddWcsAxis( wcs, (AstMapping *) specmap, (AstFrame *) specfrm,
                        NULL, NULL, status );

/* Change the NDF bounds to include a 3rd axis with pixel bounds "1:1". */
         lbnd[ 2 ] = 1;
         ubnd[ 2 ] = 1;
         ndfSbnd( 3, lbnd, ubnd, indf, status );

/* Store the modified WCS FrameSet in the NDF. */
         ndfPtwcs( wcs, indf, status );
      }
   }

/* End the AST Object context. This will annull annull the AST Objects
   created in this function. */
   astEnd;
}
예제 #11
0
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 );

}
예제 #12
0
void smf_calc_iqu( ThrWorkForce *wf, smfData *data, int block_start,
                  int block_end, int ipolcrd, int qplace, int uplace,
                  int iplace, NdgProvenance *oprov, AstFitsChan *fc,
                  int pasign, double paoff, double angrot, int submean,
                  int *status ){

/* Local Variables: */
   AstFrameSet *wcs;          /* WCS FrameSet for output NDFs */
   AstWinMap *wm;             /* Mapping to reverse the X GRID axis */
   const JCMTState *state;    /* JCMTState info for current time slice */
   dim_t nbolo;               /* No. of bolometers */
   dim_t ncol;                /* No. of columns of bolometers */
   dim_t nrow;                /* No. of rows of bolometers */
   dim_t ntslice;             /* Number of time-slices in data */
   double *ipi;               /* Pointer to output I array */
   double *ipq;               /* Pointer to output Q array */
   double *ipu;               /* Pointer to output U array */
   double ina[ 2 ];           /* Bolometer coords at bottom left */
   double inb[ 2 ];           /* Bolometer coords at top right */
   double outa[ 2 ];          /* NDF GRID coords at bottom left */
   double outb[ 2 ];          /* NDF GRID coords at top right */
   int bstep;                 /* Bolometer step between threads */
   int el;                    /* Number of mapped array elements */
   int indfi;                 /* Identifier for NDF holding I values */
   int indfq;                 /* Identifier for NDF holding Q values */
   int indfu;                 /* Identifier for NDF holding Q values */
   int itime;                 /* Time slice index */
   int iworker;               /* Index of a worker thread */
   int lbnd[ 2 ];             /* Lower pixel bounds of output NDF */
   int ntime;                 /* Time slices to check */
   int nworker;               /* No. of worker threads */
   int old;                   /* Data has old-style POL_ANG values? */
   int ubnd[ 2 ];             /* Upper pixel bounds of output NDF */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfCalcIQUJobData *job_data = NULL; /* Pointer to all job data */
   smfCalcIQUJobData *pdata = NULL;/* Pointer to next job data */
   smfHead *hdr;              /* Pointer to data header this time slice */
   double *mean;
   int tstep;                 /* Time slice step between threads */

/* Check the inherited status. */
   if( *status != SAI__OK ) return;

/* Convenience pointers. */
   hdr = data->hdr;

/* Obtain number of time slices - will also check for 3d-ness. Also get
   the dimensions of the bolometer array and the strides between adjacent
   bolometer values. */
   smf_get_dims( data, &nrow, &ncol, &nbolo, &ntslice, NULL, &bstride,
                 &tstride, status );

/* Report an error if the block of time slices extends of either end. */
   if( block_start < 0 || block_end >= (int) ntslice ) {
      if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         msgSeti( "S", block_start );
         msgSeti( "E", block_end );
         msgSeti( "N", ntslice );
         errRep( " ", "smf_calc_iqu: invalid block of time slices - ^S to "
                 "^E (^N time slices are available).", status );
      }
   }

/* Create the output NDFs. Each one is a 2D array with dimensions
   equal to the bolometer array. */
   lbnd[ 0 ] = 1;
   lbnd[ 1 ] = 1;
   ubnd[ 0 ] = ncol;
   ubnd[ 1 ] = nrow;
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &qplace, &indfq, status );
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &uplace, &indfu, status );
   if( iplace != NDF__NOPL ) {
      ndfNew( "_DOUBLE", 2, lbnd, ubnd, &iplace, &indfi, status );
   } else {
      indfi = NDF__NOID;
   }

/* Store any supplied provenance in all NDFs. */
   if( oprov ) {
      ndgWriteProv( oprov, indfq, 1, status );
      ndgWriteProv( oprov, indfu, 1, status );
      if( indfi != NDF__NOID ) ndgWriteProv( oprov, indfi, 1, status );
   }

/* Store any supplied FITS headers in all NDFs.*/
   if( fc && astGetI( fc, "NCard" ) > 0 ) {
      kpgPtfts( indfq, fc, status );
      kpgPtfts( indfu, fc, status );
      if( indfi != NDF__NOID )  kpgPtfts( indfi, fc, status );
   }

/* Store the WCS frameSet in all NDFs. First get the FrameSet for the
   central time slice in the block, and set its current Frame to the
   tracking frame. */
   smf_tslice_ast( data, ( block_start + block_end )/2, 1, status);
   astSetC( hdr->wcs, "System",
            sc2ast_convert_system( (data->hdr->allState)[0].tcs_tr_sys,
                                    status ) );

/* Take a copy and then reverse the X axis of the GRID Frame by remaping the
   base Frame using a WinMap. This produces a pixel grid such as you would
   see by looking up at the sky from underneath the array, rather than looking
   down at the ground from above the array. */
   wcs = astCopy( hdr->wcs );
   ina[ 0 ] = 1.0;
   inb[ 0 ] = ncol;
   ina[ 1 ] = 1.0;
   inb[ 1 ] = nrow;

   outa[ 0 ] = ncol;
   outb[ 0 ] = 1.0;
   outa[ 1 ] = 1.0;
   outb[ 1 ] = nrow;

   wm = astWinMap( 2, ina, inb, outa, outb, " " );
   astRemapFrame( wcs, AST__BASE, wm );
   wm = astAnnul( wm );

/* Store the FrameSet in the output NDFs, then annull the copy. */
   ndfPtwcs( wcs, indfq, status );
   ndfPtwcs( wcs, indfu, status );
   if( indfi != NDF__NOID ) ndfPtwcs( wcs, indfi, status );
   wcs = astAnnul( wcs );

/* Map the Data array in each NDF. */
   ndfMap( indfq, "Data", "_DOUBLE", "WRITE", (void **) &ipq, &el, status );
   ndfMap( indfu, "Data", "_DOUBLE", "WRITE", (void **) &ipu, &el, status );
   if( indfi != NDF__NOID ) {
      ndfMap( indfi, "Data", "_DOUBLE", "WRITE", (void **) &ipi, &el, status );
   } else {
      ipi = NULL;
   }


/* If required, allocate memory to hold the mean bolometer value at each
   time slice. */
   mean = submean ? astMalloc( ntslice*sizeof( *mean ) ) : NULL;

/* Create structures used to pass information to the worker threads. */
   nworker = wf ? wf->nworker : 1;
   job_data = astMalloc( nworker*sizeof( *job_data ) );

/* Check the above pointers can be used safely. */
   if( *status == SAI__OK ) {

/* Go through the first thousand POL_ANG values to see if they are in
   units of radians (new data) or arbitrary encoder units (old data).
   They are assumed to be in radians if no POL_ANG value is larger than
   20. */
      old = 0;
      state = hdr->allState;
      ntime = ( ntslice > 1000 ) ? 1000 : ntslice;
      for( itime = 0; itime < ntime; itime++,state++ ) {
         if( state->pol_ang > 20 ) {
            old = 1;
            msgOutif( MSG__VERB, "","   POL2 data contains POL_ANG values "
                      "in encoder units - converting to radians.", status );
            break;
         }
      }

/* If required, find the mean bolometer value at each time slice. */
      if( submean ) {

/* Determine which time-slices are to be processed by which threads. */
         tstep = ntslice/nworker;
         if( tstep < 1 ) tstep = 1;

         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;
            pdata->block_start = iworker*tstep;
            if( iworker < nworker - 1 ) {
               pdata->block_end = pdata->block_start + tstep - 1;
            } else {
               pdata->block_end = ntslice - 1;
            }
         }

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;

            pdata->bstride = bstride;
            pdata->dat = data->pntr[0];
            pdata->nbolo = nbolo;
            pdata->qua = smf_select_qualpntr( data, NULL, status );;
            pdata->tstride = tstride;
            pdata->mean = mean;
            pdata->action = 1;

/* Pass the job to the workforce for execution. */
            thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                         status );
         }

/* Wait for the workforce to complete all jobs. */
         thrWait( wf, status );

      }

/* Determine which bolometers are to be processed by which threads. */
      bstep = nbolo/nworker;
      if( bstep < 1 ) bstep = 1;

      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         pdata->b1 = iworker*bstep;
         pdata->b2 = pdata->b1 + bstep - 1;
      }

/* Ensure that the last thread picks up any left-over bolometers */
      pdata->b2 = nbolo - 1;

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;

         pdata->bstride = bstride;
         pdata->dat = data->pntr[0];;
         pdata->nbolo = nbolo;
         pdata->qua = smf_select_qualpntr( data, NULL, status );;
         pdata->tstride = tstride;
         pdata->allstates = hdr->allState;
         pdata->ipq = ipq;
         pdata->ipu = ipu;
         pdata->ipi = ipi;
         pdata->ipolcrd = ipolcrd;
         pdata->block_start = block_start;
         pdata->block_end = block_end;
         pdata->old = old;
         pdata->ncol = ncol;
         pdata->pasign = pasign ? +1: -1;
         pdata->paoff = paoff;
         pdata->angrot = angrot;
         pdata->action = 0;
         pdata->mean = mean;

/* Pass the job to the workforce for execution. */
         thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                      status );
      }

/* Wait for the workforce to complete all jobs. */
      thrWait( wf, status );
   }

/* Add POLANAL Frames to the WCS FrameSet in each output NDF. This Frame
   is used by POLPACK to determine the reference direction of the Stokes
   vectors (focal plane Y in this case, i.e. zero-based axis 1 ). */
   smf_polext( indfq, 0, 0.0, "FPLANE", 1, status );
   smf_polext( indfu, 0, 0.0, "FPLANE", 1, status );
   if( ipi ) smf_polext( indfi, 0, 0.0, "FPLANE", 1, status );

/* Free the two output NDFs. */
   ndfAnnul( &indfq, status );
   ndfAnnul( &indfu, status );
   if( ipi ) ndfAnnul( &indfi, status );

/* Free other resources. */
   job_data = astFree( job_data );
   mean = astFree( mean );
}
예제 #13
0
void smf_calc_iqu( ThrWorkForce *wf, smfData *data, int block_start,
                  int block_end, int ipolcrd, int qplace, int uplace,
                  int iplace, NdgProvenance *oprov, AstFitsChan *fc,
                  int pasign, double paoff, double angrot, int submean,
                  int harmonic, int *status ){

/* Local Variables: */
   AstCmpMap *cm1;
   AstCmpMap *cm2;
   AstFrameSet *wcs;          /* WCS FrameSet for output NDFs */
   AstMapping *fpmap1;
   AstMapping *fpmap2;
   AstMapping *oskymap;
   AstMapping *totmap;
   AstSkyFrame *oskyfrm;
   AstWinMap *wm;             /* Mapping to reverse the X GRID axis */
   const JCMTState *state;    /* JCMTState info for current time slice */
   const char *usesys;        /* Used system string */
   dim_t itime;               /* Time slice index */
   dim_t nbolo;               /* No. of bolometers */
   dim_t ncol;                /* No. of columns of bolometers */
   dim_t nrow;                /* No. of rows of bolometers */
   dim_t ntime;               /* Time slices to check */
   dim_t ntslice;             /* Number of time-slices in data */
   double *ipi;               /* Pointer to output I array */
   double *ipiv;              /* Pointer to output I variance array */
   double *ipq;               /* Pointer to output Q array */
   double *ipqv;              /* Pointer to output Q variance array */
   double *ipu;               /* Pointer to output U array */
   double *ipuv;              /* Pointer to output U variance array */
   double *mean;
   double ang_data[2];
   double fox[2];
   double foy[2];
   double fpr0;
   double fprinc;
   double fx[2];
   double fy[2];
   double ina[ 2 ];           /* Bolometer coords at bottom left */
   double inb[ 2 ];           /* Bolometer coords at top right */
   double outa[ 2 ];          /* NDF GRID coords at bottom left */
   double outb[ 2 ];          /* NDF GRID coords at top right */
   int bstep;                 /* Bolometer step between threads */
   int el;                    /* Number of mapped array elements */
   int gotvar;                /* Were any output variances created? */
   int indfi;                 /* Identifier for NDF holding I values */
   int indfq;                 /* Identifier for NDF holding Q values */
   int indfu;                 /* Identifier for NDF holding Q values */
   int iworker;               /* Index of a worker thread */
   int lbnd[ 2 ];             /* Lower pixel bounds of output NDF */
   int moving;
   int nworker;               /* No. of worker threads */
   int old;                   /* Data has old-style POL_ANG values? */
   int tstep;                 /* Time slice step between threads */
   int ubnd[ 2 ];             /* Upper pixel bounds of output NDF */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfCalcIQUJobData *job_data = NULL; /* Pointer to all job data */
   smfCalcIQUJobData *pdata = NULL;/* Pointer to next job data */
   smfHead *hdr;              /* Pointer to data header this time slice */

/* Check the inherited status. */
   if( *status != SAI__OK ) return;

/* Convenience pointers. */
   hdr = data->hdr;

/* Obtain number of time slices - will also check for 3d-ness. Also get
   the dimensions of the bolometer array and the strides between adjacent
   bolometer values. */
   smf_get_dims( data, &nrow, &ncol, &nbolo, &ntslice, NULL, &bstride,
                 &tstride, status );

/* Report an error if the block of time slices extends of either end. */
   if( block_start < 0 || block_end >= (int) ntslice ) {
      if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         msgSeti( "S", block_start );
         msgSeti( "E", block_end );
         msgSeti( "N", ntslice );
         errRep( " ", "smf_calc_iqu: invalid block of time slices - ^S to "
                 "^E (^N time slices are available).", status );
      }
   }

/* Create the output NDFs. Each one is a 2D array with dimensions
   equal to the bolometer array. */
   lbnd[ 0 ] = 1;
   lbnd[ 1 ] = 1;
   ubnd[ 0 ] = ncol;
   ubnd[ 1 ] = nrow;
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &qplace, &indfq, status );
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &uplace, &indfu, status );
   if( iplace != NDF__NOPL ) {
      ndfNew( "_DOUBLE", 2, lbnd, ubnd, &iplace, &indfi, status );
   } else {
      indfi = NDF__NOID;
   }

/* Store any supplied provenance in all NDFs. */
   if( oprov ) {
      ndgWriteProv( oprov, indfq, 1, status );
      ndgWriteProv( oprov, indfu, 1, status );
      if( indfi != NDF__NOID ) ndgWriteProv( oprov, indfi, 1, status );
   }

/* Store any supplied FITS headers in all NDFs.*/
   if( fc && astGetI( fc, "NCard" ) > 0 ) {
      kpgPtfts( indfq, fc, status );
      kpgPtfts( indfu, fc, status );
      if( indfi != NDF__NOID )  kpgPtfts( indfi, fc, status );
   }

/* Store the WCS frameSet in all NDFs. First get the FrameSet for the
   central time slice in the block, and set its current Frame to the
   tracking frame. */
   smf_tslice_ast( data, ( block_start + block_end )/2, 1, NO_FTS, status);
   usesys = sc2ast_convert_system( (data->hdr->allState)[0].tcs_tr_sys,
                                    status );
   astSetC( hdr->wcs, "System", usesys );

/* Get the Mapping from focal plane coords to bolometer grid coords. This
   is the same for all time slices. sc2ast ensures that frame 3 is FPLANE. */
   fpmap1 = astGetMapping( hdr->wcs, 3, AST__BASE );

/* Take a copy and then reverse the X axis of the GRID Frame by remaping the
   base Frame using a WinMap. This produces a pixel grid such as you would
   see by looking up at the sky from underneath the array, rather than looking
   down at the ground from above the array. */
   wcs = astCopy( hdr->wcs );
   ina[ 0 ] = 1.0;
   inb[ 0 ] = ncol;
   ina[ 1 ] = 1.0;
   inb[ 1 ] = nrow;

   outa[ 0 ] = ncol;
   outb[ 0 ] = 1.0;
   outa[ 1 ] = 1.0;
   outb[ 1 ] = nrow;

   wm = astWinMap( 2, ina, inb, outa, outb, " " );
   astRemapFrame( wcs, AST__BASE, wm );
   wm = astAnnul( wm );

/* Get the Mapping from output grid coords to focal plane coords. */
   fpmap2 = astGetMapping( wcs, AST__BASE, 3 );

/* If the target is moving (assumed to be the case if the tracking
   system is AZEL or GAPPT), make the FrameSet current Frame represent
   offsets from the reference position (i.e. the moving target), and
   indicate that the offset coord system should be used for alignment. */
   if( !strcmp( usesys, "AZEL" ) || !strcmp( usesys, "GAPPT" ) ){
      astSet( wcs, "SkyRefIs=Origin,AlignOffset=1" );
      moving = 1;
   } else {
      moving = 0;
   }

/* Store the FrameSet in the output NDFs. */
   ndfPtwcs( wcs, indfq, status );
   ndfPtwcs( wcs, indfu, status );
   if( indfi != NDF__NOID ) ndfPtwcs( wcs, indfi, status );

/* Map the Data array in each NDF. */
   ndfMap( indfq, "Data", "_DOUBLE", "WRITE", (void **) &ipq, &el, status );
   ndfMap( indfu, "Data", "_DOUBLE", "WRITE", (void **) &ipu, &el, status );
   if( indfi != NDF__NOID ) {
      ndfMap( indfi, "Data", "_DOUBLE", "WRITE", (void **) &ipi, &el, status );
   } else {
      ipi = NULL;
   }

/* Map the Variance array in each NDF. */
   ndfMap( indfq, "Variance", "_DOUBLE", "WRITE", (void **) &ipqv, &el, status );
   ndfMap( indfu, "Variance", "_DOUBLE", "WRITE", (void **) &ipuv, &el, status );
   if( indfi != NDF__NOID ) {
      ndfMap( indfi, "Variance", "_DOUBLE", "WRITE", (void **) &ipiv, &el, status );
   } else {
      ipiv = NULL;
   }

/* If required, allocate memory to hold the mean bolometer value at each
   time slice. */
   mean = submean ? astMalloc( ntslice*sizeof( *mean ) ) : NULL;

/* Create structures used to pass information to the worker threads. */
   nworker = wf ? wf->nworker : 1;
   job_data = astMalloc( nworker*sizeof( *job_data ) );

/* Check the above pointers can be used safely. */
   if( *status == SAI__OK ) {

/* Go through the first thousand POL_ANG values to see if they are in
   units of radians (new data) or arbitrary encoder units (old data).
   They are assumed to be in radians if no POL_ANG value is larger than
   20. */
      old = 0;
      state = hdr->allState;
      ntime = ( ntslice > 1000 ) ? 1000 : ntslice;
      for( itime = 0; itime < ntime; itime++,state++ ) {
         if( state->pol_ang > 20 ) {
            old = 1;
            msgOutif( MSG__VERB, "","   POL2 data contains POL_ANG values "
                      "in encoder units - converting to radians.", status );
            break;
         }
      }

/* If required, find the mean bolometer value at each time slice. */
      if( submean ) {

/* Determine which time-slices are to be processed by which threads. */
         tstep = ntslice/nworker;
         if( tstep < 1 ) tstep = 1;

         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;
            pdata->block_start = iworker*tstep;
            if( iworker < nworker - 1 ) {
               pdata->block_end = pdata->block_start + tstep - 1;
            } else {
               pdata->block_end = ntslice - 1;
            }
         }

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;

            pdata->bstride = bstride;
            pdata->dat = data->pntr[0];
            pdata->nbolo = nbolo;
            pdata->qua = smf_select_qualpntr( data, NULL, status );;
            pdata->tstride = tstride;
            pdata->mean = mean;
            pdata->action = 1;

/* Pass the job to the workforce for execution. */
            thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                         status );
         }

/* Wait for the workforce to complete all jobs. */
         thrWait( wf, status );

      }

/* Get the Frame representing absolute sky coords in the output NDF,
   and the Mapping from sky to grid in the output NDF. */
      oskyfrm = astCopy( astGetFrame( wcs, AST__CURRENT ) );
      astSet( oskyfrm, "SkyRefIs=Ignored" );
      oskymap = astGetMapping( wcs, AST__CURRENT, AST__BASE );
      wcs = astAnnul( wcs );

/* Find the first and last time slices, calculate the angle between the
   focal pane Y axis at the time slice, and the focal plane Y axis in
   the output NDF. For intervening time-slices, the angle is found by
   linear interpolation between the extreme time slices. */
      for( el = 0; el < 2; el++ ) {

/* Get the mapping from GRID coords in the input time slice to GRID
   coords in the output. */
         totmap = smf_rebin_totmap( data, el?ntslice-1:0, oskyfrm, oskymap,
                                    moving, NO_FTS, status );

/* Modify it to be the Mapping from focal plane coords in the input time
   slice to focal plane coords in the output. */
         cm1 = astCmpMap( fpmap1, totmap, 1, " " );
         cm2 = astCmpMap( cm1, fpmap2, 1, " " );

/* Use this Mapping to convert two points on the focal plane Y axis from
   the input to the output. */
         fx[0] = 0.0;
         fy[0] = 0.0;
         fx[1] = 0.0;
         fy[1] = 4.0;
         astTran2( cm2, 2, fx, fy, 1, fox, foy );

/* The angle from the focal plane Y axis in the output to the focal plane
   Y axis in the input time slice, measured positive in sense of rotation
   from Fy to Fx. */
         ang_data[ el ] = atan2( fox[1]-fox[0], foy[1]-foy[0] );

/* Free resources for this time slice. */
         totmap = astAnnul( totmap );
         cm1 = astAnnul( cm1 );
         cm2 = astAnnul( cm2 );
      }

/* Annul objects. */
      oskymap = astAnnul( oskymap );
      oskyfrm = astAnnul( oskyfrm );
      fpmap1 = astAnnul( fpmap1 );
      fpmap2 = astAnnul( fpmap2 );

/* Get the constants of the linear relationship between focal plane
   rotation and time slice index "fpr = fpr0 + itime*fprinc". */
      fpr0 = ang_data[ 0 ];
      fprinc = ( ang_data[ 1 ] - fpr0 )/( ntslice - 1 );

/* Determine which bolometers are to be processed by which threads. */
      bstep = nbolo/nworker;
      if( bstep < 1 ) bstep = 1;

      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         pdata->b1 = iworker*bstep;
         pdata->b2 = pdata->b1 + bstep - 1;
      }

/* Ensure that the last thread picks up any left-over bolometers */
      pdata->b2 = nbolo - 1;

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;

         pdata->bstride = bstride;
         pdata->dat = data->pntr[0];;
         pdata->nbolo = nbolo;
         pdata->qua = smf_select_qualpntr( data, NULL, status );;
         pdata->tstride = tstride;
         pdata->allstates = hdr->allState;
         pdata->ipq = ipq;
         pdata->ipu = ipu;
         pdata->ipi = ipi;
         pdata->ipqv = ipqv;
         pdata->ipuv = ipuv;
         pdata->ipiv = ipiv;
         pdata->ipolcrd = ipolcrd;
         pdata->block_start = block_start;
         pdata->block_end = block_end;
         pdata->old = old;
         pdata->ncol = ncol;
         pdata->pasign = pasign ? +1: -1;
         pdata->paoff = paoff;
         pdata->angrot = angrot;
         pdata->fpr0 = fpr0;
         pdata->fprinc = fprinc;
         pdata->angfac = harmonic/4.0;
         pdata->action = 0;
         pdata->mean = mean;

/* Pass the job to the workforce for execution. */
         thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                      status );
      }

/* Wait for the workforce to complete all jobs. */
      thrWait( wf, status );

/* See if any thread produced non-bad variance values. */
      gotvar = 0;
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         if( pdata->gotvar ) gotvar = 1;
      }

/* If no variances were created, erase the Variance component and tell
   the user. */
      ndfUnmap( indfq, "*", status );
      ndfUnmap( indfu, "*", status );
      if( ipi ) ndfUnmap( indfi, "*", status );

      if( !gotvar ) {
         ndfReset( indfq, "Variance", status );
         ndfReset( indfu, "Variance", status );
         if( ipi ) ndfReset( indfi, "Variance", status );
         msgOut( "", "Warning: Insufficient input data to produce variances",
                 status );
      }
   }

/* Add POLANAL Frames to the WCS FrameSet in each output NDF. This Frame
   is used by POLPACK to determine the reference direction of the Stokes
   vectors (focal plane Y in this case, i.e. zero-based axis 1 ). */
   smf_polext( indfq, 0, 0.0, "FPLANE", 1, status );
   smf_polext( indfu, 0, 0.0, "FPLANE", 1, status );
   if( ipi ) smf_polext( indfi, 0, 0.0, "FPLANE", 1, status );

/* Free the two output NDFs. */
   ndfAnnul( &indfq, status );
   ndfAnnul( &indfu, status );
   if( ipi ) ndfAnnul( &indfi, status );

/* Free other resources. */
   job_data = astFree( job_data );
   mean = astFree( mean );
}
예제 #14
0
void smurf_smurfcopy ( int * status ) {

  smfData * data = NULL;     /* input file struct */
  size_t dtypsz;             /* Number of bytes in data type */
  Grp *fgrp = NULL;          /* Filtered group, no darks */
  size_t i;                  /* Loop counter */
  smfFile * ifile = NULL;    /* Input smfFile */
  Grp *igrp = NULL;          /* Input group */
  unsigned char * inptr = NULL; /* Pointer to start of section to copy */
  int islice;                /* int time slice from parameter */
  int lbnd[2];               /* Lower coordinate bounds of output file */
  size_t nelem;              /* Number of elements to copy */
  smfData * odata = NULL;    /* output file struct */
  size_t offset;             /* offset into data array */
  smfFile * ofile = NULL;    /* output smfFile */
  Grp *ogrp = NULL;          /* Output group */
  size_t outsize;            /* Total number of NDF names in the output group */
  dim_t slice;               /* Time index to extract */
  size_t size;               /* Number of files in input group */
  int ubnd[2];               /* Upper coordinate bounds of output file */

  if (*status != SAI__OK) return;

  ndfBegin();

  /* Read the input file */
  /* As a proof of concept do not allow multiple input files */
  kpg1Rgndf( "IN", 1, 1, "", &igrp, &size, status );

  /* Filter out darks */
  smf_find_science( igrp, &fgrp, 1, NULL, NULL, 0, 0, SMF__NULL, NULL, NULL,
                    NULL, NULL, status );

  /* input group is now the filtered group so we can use that and
     free the old input group */
  size = grpGrpsz( fgrp, status );
  grpDelet( &igrp, status);
  igrp = fgrp;
  fgrp = NULL;

  if (size > 0) {
  /* Get output file(s) */
  kpg1Wgndf( "OUT", igrp, size, size, "More output files required...",
             &ogrp, &outsize, status );
  } else {
    msgOutif(MSG__NORM, " ","All supplied input frames were DARK,"
       " nothing to extract", status );
  }

  /* Allow the user to specify a text file containing a table of pointing
     corrections. Corresponding Mappings are created form the column data
     in this table and stored in the "igrp" group as items of metadata. */
  smf_pread( igrp, "POINTING", status );

  /* Use a loop so that we look like other routines and simplify
     the change if we support multiple input files */
  for (i=1; i<=size; i++) {

    /* Open the input file using standard routine */
    smf_open_and_flatfield( igrp, NULL, i, NULL, NULL, NULL, &data, status );
    if (*status != SAI__OK) break;

    if (*status == SAI__OK) {
      if (!data->file->isTstream  || data->ndims != 3) {
        smf_close_file( &data, status );
        *status = SAI__ERROR;
        errRep(" ", "Input data do not represent time series", status);
        break;
      }
    }

    /* get the slice position - knowing the maximum allowed
       Somewhat problematic in a loop if we want to allow
       different slices per file. Best bet is to allow multiple
       slices in a single file but only one file.
     */

    msgSeti( "MAX", (data->dims)[2] );
    msgOutif( MSG__NORM, " ", "File has ^MAX slices.", status );

    parGdr0i( "SLICE",1, 0, (data->dims)[2], 1, &islice, status);
    slice = islice;
    if (slice == 0) slice = (data->dims)[2];

    /* construct output bounds */
    lbnd[0] = (data->lbnd)[0];
    lbnd[1] = (data->lbnd)[1];
    ubnd[0] = lbnd[0] + (data->dims)[0] - 1;
    ubnd[1] = lbnd[1] + (data->dims)[1] - 1;

    /* Open an output file (losing history) but we do not want
       to propagate the full NDF size to the output file */

    smf_open_newfile( ogrp, i, data->dtype, 2, lbnd, ubnd, 0,
                      &odata, status );
    ofile = odata->file;
    ifile = data->file;

    /* protect against null pointer smfFile */
    if (*status == SAI__OK) {

      /* sort out provenance */
      smf_accumulate_prov( data, igrp, i, ofile->ndfid,
                           "SMURF:SMURFCOPY", NULL, status );

      /* copy the slice in */
      dtypsz = smf_dtype_size( odata, status );
      nelem = (data->dims)[0] * (data->dims)[1];
      offset = (slice - 1) * nelem * dtypsz;
      inptr = (data->pntr)[0];
      memcpy( (odata->pntr)[0], inptr + offset, nelem * dtypsz );

      /* World coordinates - note the 0 indexing relative to GRID */
      smf_tslice_ast( data, slice-1, 1, status );
      ndfPtwcs( data->hdr->wcs, ofile->ndfid, status );

      /* Write the FITS header */
      kpgPtfts( ofile->ndfid, data->hdr->fitshdr, status );

      /* JCMTSTATE */
      sc2store_writejcmtstate( ofile->ndfid, 1, &((data->hdr->allState)[slice-1]),
                               status );

    }

    /* cleanup */
    smf_close_file( &data, status );
    smf_close_file( &odata, status );

  }

  /* tidy */
  if (igrp) {
    smf_pread( igrp, NULL, status );
    grpDelet( &igrp, status );
  }
  if (ogrp) grpDelet( &ogrp, status );

  ndfEnd(status);

}