Example #1
0
int main(){
   double a[2] = {0.0,0.0};

/* Initialise the flag that indicates if the error handler has been
   called. */
   flag = 0;

/* Register the error handler. */
   astSetPutErr( myPutErr );

/* Generate an error by making a ShiftMap with a negative number of axes.
   The error handler will set the flag to a special value. */
   AstShiftMap *map = astShiftMap( -1, a, " " );

/* Clear the error status. */
   astClearStatus;

/* Clear the error reporter so that the default error reporter is used. */
   astSetPutErr( NULL );

/* Report an error if the flag was not set to the correct value. */
   if( flag != ERRVAL ) {
      astError( AST__INTER, "Error reporting function has not been "
                "called." );
   }

   if( astOK ) {
      printf(" All Error tests passed\n");
   } else {
      printf("Error tests failed\n");
   }

}
Example #2
0
void smf_mapbounds( int fast, Grp *igrp,  int size, const char *system,
                    AstFrameSet *spacerefwcs, int alignsys, int *lbnd_out,
                    int *ubnd_out, AstFrameSet **outframeset, int *moving,
                    smfBox ** boxes, fts2Port fts_port, int *status ) {

  /* Local Variables */
  AstSkyFrame *abskyframe = NULL; /* Output Absolute SkyFrame */
  int actval;           /* Number of parameter values supplied */
  AstMapping *bolo2map = NULL; /* Combined mapping bolo->map
                                  coordinates, WCS->GRID Mapping from
                                  input WCS FrameSet */
  smfBox *box = NULL;          /* smfBox for current file */
  smfData *data = NULL;        /* pointer to  SCUBA2 data struct */
  double dlbnd[ 2 ];    /* Floating point lower bounds for output map */
  drcntrl_bits drcntrl_mask = 0;/* Mask to use for DRCONTROL on this instrument */
  double dubnd[ 2 ];    /* Floating point upper bounds for output map */
  AstMapping *fast_map = NULL; /* Mapping from tracking to absolute map coords */
  smfFile *file = NULL;        /* SCUBA2 data file information */
  int first;                   /* Is this the first good subscan ? */
  AstFitsChan *fitschan = NULL;/* Fits channels to construct WCS header */
  AstFrameSet *fs = NULL;      /* A general purpose FrameSet pointer */
  smfHead *hdr = NULL;         /* Pointer to data header this time slice */
  int i;                       /* Loop counter */
  dim_t j;                     /* Loop counter */
  AstSkyFrame *junksky = NULL; /* Unused SkyFrame argument */
  dim_t k;                     /* Loop counter */
  int lbnd0[ 2 ];              /* Defaults for LBND parameter */
  double map_pa=0;             /* Map PA in output coord system (rads) */
  dim_t maxloop;               /* Number of times to go round the time slice loop */
  dim_t nbadt  = 0;            /* Number of bad time slices */
  dim_t ngoodt = 0;            /* Number of good time slices */
  double par[7];               /* Projection parameters */
  double shift[ 2 ];           /* Shifts from PIXEL to GRID coords */
  AstMapping *oskymap = NULL;  /* Mapping celestial->map coordinates,
                                  Sky <> PIXEL mapping in output
                                  FrameSet */
  AstSkyFrame *oskyframe = NULL;/* Output SkyFrame */
  char *refsys = NULL;         /* Sky system from supplied reference FrameSet */
  dim_t textreme[4];           /* Time index corresponding to minmax TCS posn */
  AstFrame *skyin = NULL;      /* Sky Frame in input FrameSet */
  double skyref[ 2 ];          /* Values for output SkyFrame SkyRef attribute */
  struct timeval tv1;          /* Timer */
  struct timeval tv2;          /* Timer */
  AstMapping *tmap;            /* Temporary Mapping */
  int trim;                    /* Trim borders of bad pixels from o/p image? */
  int ubnd0[ 2 ];              /* Defaults for UBND parameter */
  double x_array_corners[4];   /* X-Indices for corner bolos in array */
  double x_map[4];             /* Projected X-coordinates of corner bolos */
  double y_array_corners[4];   /* Y-Indices for corner pixels in array */
  double y_map[4];             /* Projected X-coordinates of corner bolos */

  /* Main routine */
  if (*status != SAI__OK) return;

  /* Start a timer to see how long this takes */
  smf_timerinit( &tv1, &tv2, status );

  /* Initialize pointer to output FrameSet and moving-source flag */
  *outframeset = NULL;
  *moving = 0;

  /* initialize double precision output bounds and the proj pars */
  for( i = 0; i < 7; i++ ) par[ i ] = AST__BAD;
  dlbnd[ 0 ] = VAL__MAXD;
  dlbnd[ 1 ] = VAL__MAXD;
  dubnd[ 0 ] = VAL__MIND;
  dubnd[ 1 ] = VAL__MIND;

  /* If we have a supplied reference WCS we can use that directly
     without having to calculate it from the data. Replace the requested
     system with the system from the reference FrameSet (take a copy of the
     string since astGetC may re-use its buffer). */
  if (spacerefwcs) {
     oskyframe = astGetFrame( spacerefwcs, AST__CURRENT );
     int nc = 0;
     refsys = astAppendString( NULL, &nc, astGetC( oskyframe, "System" ) );
     system = refsys;
  }

  /* Create array of returned smfBox structures and store a pointer
     to the next one to be initialised. */
  *boxes = astMalloc( sizeof( smfBox ) * size );
  box = *boxes;

  astBegin;

  /* Loop over all files in the Grp */
  first = 1;
  for( i=1; i<=size; i++, box++ ) {

    /* Initialise the spatial bounds of section of the the output cube that is
       contributed to by the current ionput file. */
    box->lbnd[ 0 ] = VAL__MAXD;
    box->lbnd[ 1 ] = VAL__MAXD;
    box->ubnd[ 0 ] = VAL__MIND;
    box->ubnd[ 1 ] = VAL__MIND;

    /* Read data from the ith input file in the group */
    smf_open_file( NULL, igrp, i, "READ", SMF__NOCREATE_DATA, &data, status );

    if (*status != SAI__OK) {
      msgSeti( "I", i );
      errRep( "smf_mapbounds", "Could not open data file no ^I.", status );
      break;
    } else {
      if( *status == SAI__OK ) {
        if( data->file == NULL ) {
          *status = SAI__ERROR;
          errRep( FUNC_NAME, "No smfFile associated with smfData.",
                  status );
          break;

        } else if( data->hdr == NULL ) {
          *status = SAI__ERROR;
          errRep( FUNC_NAME, "No smfHead associated with smfData.",
                  status );
          break;

        } else if( data->hdr->fitshdr == NULL ) {
          *status = SAI__ERROR;
          errRep( FUNC_NAME, "No FITS header associated with smfHead.",
                  status );
          break;

        }
      }
    }

    /* convenience pointers */
    file = data->file;
    hdr = data->hdr;

    /* report name of the input file */
    smf_smfFile_msg( file, "FILE", 1, "<unknown>" );
    msgSeti("I", i);
    msgSeti("N", size);
    msgOutif(MSG__VERB, " ",
             "SMF_MAPBOUNDS: Processing ^I/^N ^FILE",
             status);

/* Check that there are 3 pixel axes. */
    if( data->ndims != 3 ) {
      smf_smfFile_msg( file, "FILE", 1, "<unknown>" );
      msgSeti( "NDIMS", data->ndims );
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "^FILE has ^NDIMS pixel axes, should be 3.",
              status );
      break;
    }

    /* Check that the data dimensions are 3 (for time ordered data) */
    if( *status == SAI__OK ) {

      /* If OK Decide which detectors (GRID coord) to use for
         checking bounds, depending on the instrument in use. */

      switch( hdr->instrument ) {

      case INST__SCUBA2:
        drcntrl_mask = DRCNTRL__POSITION;
        /* 4 corner bolometers of the subarray */
        x_array_corners[0] = 1;
        x_array_corners[1] = 1;
        x_array_corners[2] = (data->dims)[0];
        x_array_corners[3] = (data->dims)[0];

        y_array_corners[0] = 1;
        y_array_corners[1] = (data->dims)[1];
        y_array_corners[2] = 1;
        y_array_corners[3] = (data->dims)[1];
        break;

      case INST__AZTEC:
        /* Rough guess for extreme bolometers around the edge */
        x_array_corners[0] = 22;
        x_array_corners[1] = 65;
        x_array_corners[2] = 73;
        x_array_corners[3] = 98;

        y_array_corners[0] = 1; /* Always 1 for AzTEC */
        y_array_corners[1] = 1;
        y_array_corners[2] = 1;
        y_array_corners[3] = 1;
        break;

      case INST__ACSIS:
        smf_find_acsis_corners( data, x_array_corners, y_array_corners,
                                status);
        break;

      default:
        *status = SAI__ERROR;
        errRep(FUNC_NAME, "Don't know how to calculate mapbounds for data created with this instrument", status);
      }
    }

    if( *status == SAI__OK) {
      size_t goodidx = SMF__BADSZT;

      /* Need to build up a frameset based on good telescope position.
         We can not assume that we the first step will be a good TCS position
         so we look for one. If we can not find anything we skip to the
         next file. */
      maxloop = (data->dims)[2];
      for (j=0; j<maxloop; j++) {
        JCMTState state = (hdr->allState)[j];
        if (state.jos_drcontrol >= 0 && state.jos_drcontrol & drcntrl_mask ) {
          /* bad TCS - so try again */
        } else {
          /* Good tcs */
          goodidx = j;
          break;
        }
      }

      if (goodidx == SMF__BADSZT) {
        smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
        msgOutif( MSG__QUIET, "", "No good telescope positions found in file ^FILE. Ignoring",
                  status );
        smf_close_file( NULL, &data, status );
        continue;
      }

      /* If we are dealing with the first good file, create the output
         SkyFrame. */
      if( first ) {
        first = 0;

        /* Create output SkyFrame if it has not come from a reference */
        if ( oskyframe == NULL ) {

          /* smf_tslice_ast only needs to get called once to set up framesets */
          if( hdr->wcs == NULL ) {
            smf_tslice_ast( data, goodidx, 1, fts_port, status);
          }

          /* Retrieve input SkyFrame */
          skyin = astGetFrame( hdr->wcs, AST__CURRENT );

          smf_calc_skyframe( skyin, system, hdr, alignsys, &oskyframe, skyref,
                             moving, status );

          /* Get the orientation of the map vertical within the output celestial
             coordinate system. This is derived form the MAP_PA FITS header, which
             gives the orientation of the map vertical within the tracking system. */
          map_pa = smf_calc_mappa( hdr, system, skyin, status );

          /* Provide a sensible default for the pixel size based on wavelength */
          par[4] = smf_calc_telres( hdr->fitshdr, status );
          par[4] *= AST__DD2R/3600.0;
          par[5] = par[4];

          /* Calculate the projection parameters. We do not enable autogrid determination
             for SCUBA-2 so we do not need to obtain all the data before calculating
             projection parameters. */
          smf_get_projpar( oskyframe, skyref, *moving, 0, 0, NULL, 0,
                           map_pa, par, NULL, NULL, status );

          if (skyin) skyin = astAnnul( skyin );

        /* If the output skyframe has been supplied, we still need to
           determine whether the source is moving or not, and set the
           reference position. */
        } else {

          /* smf_tslice_ast only needs to get called once to set up framesets */
          if( hdr->wcs == NULL ) {
            smf_tslice_ast( data, goodidx, 1, fts_port, status);
          }

          /* Retrieve input SkyFrame */
          skyin = astGetFrame( hdr->wcs, AST__CURRENT );
          smf_calc_skyframe( skyin, system, hdr, alignsys, &junksky, skyref,
                             moving, status );

          /* Store the sky reference position. If the target is moving,
             ensure the returned SkyFrame represents offsets from the
             reference position rather than absolute coords. */
          astSetD( oskyframe, "SkyRef(1)", skyref[ 0 ] );
          astSetD( oskyframe, "SkyRef(2)", skyref[ 1 ] );
          if( *moving ) astSet( oskyframe, "SkyRefIs=Origin" );

          /* Ensure the Epoch attribute in the map is set to the date of
             the first data in the map, rather than the date in supplied
             reference WCS. */
          astSetD( oskyframe, "Epoch", astGetD( junksky, "Epoch" ) );
        }

        if ( *outframeset == NULL && oskyframe != NULL && (*status == SAI__OK)){
          /* Now created a spatial Mapping. Use the supplied reference frameset
             if supplied */
          if (spacerefwcs) {
            oskymap = astGetMapping( spacerefwcs, AST__BASE, AST__CURRENT );
          } else {
            /* Now populate a FitsChan with FITS-WCS headers describing
               the required tan plane projection. The longitude and
               latitude axis types are set to either (RA,Dec) or (AZ,EL)
               to get the correct handedness. */
            fitschan = astFitsChan ( NULL, NULL, " " );
            smf_makefitschan( astGetC( oskyframe, "System"), &(par[0]),
                              &(par[2]), &(par[4]), par[6], fitschan, status );
            astClear( fitschan, "Card" );
            fs = astRead( fitschan );

            /* Extract the output PIXEL->SKY Mapping. */
            oskymap = astGetMapping( fs, AST__BASE, AST__CURRENT );

            /* Tidy up */
            fs = astAnnul( fs );
          }

          /* Create the output FrameSet */
          *outframeset = astFrameSet( astFrame(2, "Domain=GRID"), " " );

          /* Now add the SkyFrame to it */
          astAddFrame( *outframeset, AST__BASE, oskymap, oskyframe );

          /* Now add a POLANAL Frame if required (i.e. if the input time
             series are POL-2 Q/U values). */
          smf_addpolanal( *outframeset, hdr, status );

          /* Invert the oskymap mapping */
          astInvert( oskymap );

        } /* End WCS FrameSet construction */
      }

      /* Get a copy of the output SkyFrame and ensure it represents
         absolute coords rather than offset coords. */
      abskyframe = astCopy( oskyframe );
      astClear( abskyframe, "SkyRefIs" );
      astClear( abskyframe, "AlignOffset" );

      maxloop = (data->dims)[2];
      if (fast) {
        /* For scan map we scan through looking for largest telescope moves.
           For dream/stare we just look at the start and end time slices to
           account for sky rotation. */

        if (hdr->obsmode != SMF__OBS_SCAN) {
          textreme[0] = 0;
          textreme[1] = (data->dims)[2] - 1;
          maxloop = 2;

        } else {
          const char *tracksys;
          double *ac1list, *ac2list, *bc1list, *bc2list, *p1, *p2, *p3, *p4;
          double flbnd[4], fubnd[4];
          JCMTState state;

          /* If the output and tracking systems are different, get a
             Mapping between them. */
          tracksys = sc2ast_convert_system( (hdr->allState)[goodidx].tcs_tr_sys,
                                            status );
          if( strcmp( system, tracksys ) ) {
             AstSkyFrame *tempsf = astCopy( abskyframe );
             astSetC( tempsf, "System", tracksys );
             AstFrameSet *tempfs = astConvert( tempsf, abskyframe, "" );
             tmap = astGetMapping( tempfs, AST__BASE, AST__CURRENT );
             fast_map = astSimplify( tmap );
             tmap = astAnnul( tmap );
             tempsf = astAnnul( tempsf );
             tempfs = astAnnul( tempfs );
          } else {
             fast_map = NULL;
          }

          /* Copy all ac1/2 positions into two array, and transform them
             from tracking to absolute output sky coords. */
          ac1list = astMalloc( maxloop*sizeof( *ac1list ) );
          ac2list = astMalloc( maxloop*sizeof( *ac2list ) );
          if( *status == SAI__OK ) {
             p1 = ac1list;
             p2 = ac2list;
             for( j = 0; j < maxloop; j++ ) {
                state = (hdr->allState)[ j ];
                *(p1++) = state.tcs_tr_ac1;
                *(p2++) = state.tcs_tr_ac2;
             }
             if( fast_map ) astTran2( fast_map, maxloop, ac1list, ac2list, 1,
                                      ac1list, ac2list );
          }

          /* If the target is moving, we need to adjust these ac1/2 values
             to represent offsets from the base position. */
          if( *moving ) {

          /* Copy all bc1/2 positions into two arrays. */
             bc1list = astMalloc( maxloop*sizeof( *bc1list ) );
             bc2list = astMalloc( maxloop*sizeof( *bc2list ) );
             if( *status == SAI__OK ) {
                p1 = bc1list;
                p2 = bc2list;

                for( j = 0; j < maxloop; j++ ) {
                   state = (hdr->allState)[ j ];
                   *(p1++) = state.tcs_tr_bc1;
                   *(p2++) = state.tcs_tr_bc2;
                }

                /* Transform them from tracking to absolute output sky coords. */
                if( fast_map ) astTran2( fast_map, maxloop, bc1list, bc2list,
                                         1, bc1list, bc2list );

                /* Replace each ac1/2 position with the offsets from the
                   corresponding base position. */
                p1 = bc1list;
                p2 = bc2list;
                p3 = ac1list;
                p4 = ac2list;
                for( j = 0; j < maxloop; j++ ) {
                  smf_offsets( *(p1++), *(p2++), p3++, p4++, status );
                }
             }

             /* We no longer need the base positions. */
             bc1list = astFree( bc1list );
             bc2list = astFree( bc2list );
          }

          /* Transform the ac1/2 position from output sky coords to
             output pixel coords. */
          astTran2( oskymap, maxloop, ac1list, ac2list, 1, ac1list, ac2list );

          /* Find the bounding box containing these pixel coords and the
             time slices at which the boresight touches each edge of this
             box. */
          flbnd[ 0 ] = VAL__MAXD;
          flbnd[ 1 ] = VAL__MAXD;
          fubnd[ 0 ] = VAL__MIND;
          fubnd[ 1 ] = VAL__MIND;
          for( j = 0; j < 4; j++ ) textreme[ j ] = (dim_t) VAL__BADI;

          if( *status == SAI__OK ) {
             p1 = ac1list;
             p2 = ac2list;
             for( j = 0; j < maxloop; j++,p1++,p2++ ) {
                if( *p1 != VAL__BADD && *p2 != VAL__BADD ){

                   if ( *p1 < flbnd[0] ) { flbnd[0] = *p1; textreme[0] = j; }
                   if ( *p2 < flbnd[1] ) { flbnd[1] = *p2; textreme[1] = j; }
                   if ( *p1 > fubnd[0] ) { fubnd[0] = *p1; textreme[2] = j; }
                   if ( *p2 > fubnd[1] ) { fubnd[1] = *p2; textreme[3] = j; }
                }
             }
          }

          maxloop = 4;
          msgSetd("X1", textreme[0]);
          msgSetd("X2", textreme[1]);
          msgSetd("X3", textreme[2]);
          msgSetd("X4", textreme[3]);
          msgOutif( MSG__DEBUG, " ",
                    "Extrema time slices are ^X1, ^X2, ^X3 and ^X4",
                    status);

          ac1list = astFree( ac1list );
          ac2list = astFree( ac2list );

        }
      }

      /* Get the astrometry for all the relevant time slices in this data file */
      for( j=0; j<maxloop; j++ ) {
        dim_t ts;  /* Actual time slice to use */

        /* if we are doing the fast loop, we need to read the time slice
           index from textreme. Else we just use the index */
        if (fast) {
          /* get the index but make sure it is good */
          ts = textreme[j];
          if (ts == (dim_t)VAL__BADI) continue;
        } else {
          ts = j;
        }
        /* Calculate the bolo to map-pixel transformation for this tslice */
        bolo2map = smf_rebin_totmap( data, ts, abskyframe, oskymap,
                                     *moving, fts_port, status );

        if ( *status == SAI__OK ) {
          /* skip if we did not get a mapping this time round */
          if (!bolo2map) continue;

          /* Check corner pixels in the array for their projected extent
             on the sky to set the pixel bounds */
          astTran2( bolo2map, 4, x_array_corners, y_array_corners, 1,
                    x_map, y_map );

          /* Update min/max for this time slice */
          for( k=0; k<4; k++ ) {

            if( x_map[k] != AST__BAD && y_map[k] != AST__BAD ) {
              if( x_map[k] < dlbnd[0] ) dlbnd[0] = x_map[k];
              if( y_map[k] < dlbnd[1] ) dlbnd[1] = y_map[k];
              if( x_map[k] > dubnd[0] ) dubnd[0] = x_map[k];
              if( y_map[k] > dubnd[1] ) dubnd[1] = y_map[k];

              if( x_map[k] < box->lbnd[0] ) box->lbnd[0] = x_map[k];
              if( y_map[k] < box->lbnd[1] ) box->lbnd[1] = y_map[k];
              if( x_map[k] > box->ubnd[0] ) box->ubnd[0] = x_map[k];
              if( y_map[k] > box->ubnd[1] ) box->ubnd[1] = y_map[k];

            } else if( *status == SAI__OK ) {
              *status = SAI__ERROR;
              errRep( FUNC_NAME, "Extreme positions are bad.", status );
              break;
            }
          }
        }
        /* Explicitly annul these mappings each time slice for reduced
           memory usage */
        if (bolo2map) bolo2map = astAnnul( bolo2map );
        if (fs) fs = astAnnul( fs );

        /* Break out of loop over time slices if bad status */
        if (*status != SAI__OK) goto CLEANUP;
      }

      /* Annul any remaining Ast objects before moving on to the next file */
      if (fs) fs = astAnnul( fs );
      if (bolo2map) bolo2map = astAnnul( bolo2map );
    }

    /* Close the data file */
    smf_close_file( NULL, &data, status);

    /* Break out of loop over data files if bad status */
    if (*status != SAI__OK) goto CLEANUP;
  }

  /* make sure we got values - should not be possible with good status */
  if (dlbnd[0] == VAL__MAXD || dlbnd[1] == VAL__MAXD) {
    if (*status == SAI__OK) {
      *status = SAI__ERROR;
      errRep( " ", "Unable to find any valid map bounds", status );
    }
  }

  if (nbadt > 0) {
    msgOutf( "", "   Processed %zu time slices to calculate bounds,"
             " of which %zu had bad telescope data and were skipped",
             status, (size_t)(ngoodt+nbadt), (size_t)nbadt );
  }

  /* If spatial reference wcs was supplied, store par values that result in
     no change to the pixel origin. */
  if( spacerefwcs ){
    par[ 0 ] = 0.5;
    par[ 1 ] = 0.5;
  }

  /* Need to re-align with the interim GRID coordinates */
  lbnd_out[0] = ceil( dlbnd[0] - par[0] + 0.5 );
  ubnd_out[0] = ceil( dubnd[0] - par[0] + 0.5 );
  lbnd_out[1] = ceil( dlbnd[1] - par[1] + 0.5 );
  ubnd_out[1] = ceil( dubnd[1] - par[1] + 0.5 );

  /* Do the same with the individual input file bounding boxes */
  box = *boxes;
  for (i = 1; i <= size; i++, box++) {
    box->lbnd[0] = ceil( box->lbnd[0] - par[0] + 0.5);
    box->ubnd[0] = ceil( box->ubnd[0] - par[0] + 0.5);
    box->lbnd[1] = ceil( box->lbnd[1] - par[1] + 0.5);
    box->ubnd[1] = ceil( box->ubnd[1] - par[1] + 0.5);
  }

  /* Apply a ShiftMap to the output FrameSet to re-align the GRID
     coordinates */
  shift[0] = 2.0 - par[0] - lbnd_out[0];
  shift[1] = 2.0 - par[1] - lbnd_out[1];
  astRemapFrame( *outframeset, AST__BASE, astShiftMap( 2, shift, " " ) );

  /* Set the dynamic defaults for lbnd/ubnd */
  lbnd0[ 0 ] = lbnd_out[ 0 ];
  lbnd0[ 1 ] = lbnd_out[ 1 ];
  parDef1i( "LBND", 2, lbnd0, status );

  ubnd0[ 0 ] = ubnd_out[ 0 ];
  ubnd0[ 1 ] = ubnd_out[ 1 ];
  parDef1i( "UBND", 2, ubnd0, status );

  parGet1i( "LBND", 2, lbnd_out, &actval, status );
  if( actval == 1 ) lbnd_out[ 1 ] = lbnd_out[ 0 ];

  parGet1i( "UBND", 2, ubnd_out, &actval, status );
  if( actval == 1 ) ubnd_out[ 1 ] = ubnd_out[ 0 ];

  /* Ensure the bounds are the right way round. */
  if( lbnd_out[ 0 ] > ubnd_out[ 0 ] ) {
    int itmp = lbnd_out[ 0 ];
    lbnd_out[ 0 ] = ubnd_out[ 0 ];
    ubnd_out[ 0 ] = itmp;
  }

  if( lbnd_out[ 1 ] > ubnd_out[ 1 ] ) {
    int itmp = lbnd_out[ 1 ];
    lbnd_out[ 1 ] = ubnd_out[ 1 ];
    ubnd_out[ 1 ] = itmp;
  }

  /* If borders of bad pixels are being trimmed from the output image,
     then do not allow the user-specified bounds to extend outside the
     default bounding box (since we know that the default bounding box
     encloses all available data). */
  parGet0l( "TRIM", &trim, status );
  if( trim ) {
     if( lbnd_out[ 0 ] < lbnd0[ 0 ] ) lbnd_out[ 0 ] = lbnd0[ 0 ];
     if( lbnd_out[ 1 ] < lbnd0[ 1 ] ) lbnd_out[ 1 ] = lbnd0[ 1 ];
     if( ubnd_out[ 0 ] > ubnd0[ 0 ] ) ubnd_out[ 0 ] = ubnd0[ 0 ];
     if( ubnd_out[ 1 ] > ubnd0[ 1 ] ) ubnd_out[ 1 ] = ubnd0[ 1 ];
  }

  /* Modify the returned FrameSet to take account of the new pixel origin. */
  shift[ 0 ] = lbnd0[ 0 ] - lbnd_out[ 0 ];
  shift[ 1 ] = lbnd0[ 1 ] - lbnd_out[ 1 ];
  if( shift[ 0 ] != 0.0 || shift[ 1 ] != 0.0 ) {
    astRemapFrame( *outframeset, AST__BASE, astShiftMap( 2, shift, " " ) );
  }

/* Report the pixel bounds of the cube. */
  if( *status == SAI__OK ) {
    msgOutif( MSG__NORM, " ", " ", status );
    msgSeti( "XL", lbnd_out[ 0 ] );
    msgSeti( "YL", lbnd_out[ 1 ] );
    msgSeti( "XU", ubnd_out[ 0 ] );
    msgSeti( "YU", ubnd_out[ 1 ] );
    msgOutif( MSG__NORM, " ", "   Output map pixel bounds: ( ^XL:^XU, ^YL:^YU )",
              status );

    if( ( ubnd_out[ 0 ] - lbnd_out[ 0 ] + 1 ) > MAX_DIM ||
        ( ubnd_out[ 1 ] - lbnd_out[ 1 ] + 1 ) > MAX_DIM ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": The map is too big. Check your list of input "
              "data files does not include widely separated observations.",
              status );
    }
  }

  /* If no error has occurred, export the returned FrameSet pointer from the
     current AST context so that it will not be annulled when the AST
     context is ended. Otherwise, ensure a null pointer is returned. */
  if( *status == SAI__OK ) {
    astExport( *outframeset );
  } else {
    *outframeset = astAnnul( *outframeset );
  }

  msgOutiff( SMF__TIMER_MSG, "",
             "Took %.3f s to calculate map bounds",
             status, smf_timerupdate( &tv1, &tv2, status ) );

  /* Clean Up */
 CLEANUP:
  if (*status != SAI__OK) {
    errRep(FUNC_NAME, "Unable to determine map bounds", status);
  }
  if (oskymap) oskymap  = astAnnul( oskymap );
  if (bolo2map) bolo2map = astAnnul( bolo2map );
  if (fitschan) fitschan = astAnnul( fitschan );

  if( data != NULL )
    smf_close_file( NULL, &data, status );

  refsys = astFree( refsys );

  astEnd;

}
Example #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;
}
Example #4
0
void smf_mapbounds_approx( Grp *igrp,  size_t index, char *system,
			   int *lbnd_out, int *ubnd_out, AstFrameSet **outframeset,
			   int *moving, int *status ) {

  /* Local variables */
  smfData *data = NULL;        /* pointer to  SCUBA2 data struct */
  int dxpix;                   /* Map X offset in pixels */
  int dypix;                   /* Map Y offset in pixels */
  smfFile *file = NULL;        /* SCUBA2 data file information */
  AstFitsChan *fitschan = NULL;/* Fits channels to construct WCS header */
  AstFrameSet *fs = NULL;      /* A general purpose FrameSet pointer */
  smfHead *hdr = NULL;         /* Pointer to data header this time slice */
  double hghtbox;              /* Map height in arcsec */
  int hghtpix;                 /* RA-Dec map height in pixels */
  int i;                       /* loop counter */
  dim_t k;                     /* Loop counter */
  double maphght = 0.0;        /* Map height in radians */
  double mappa = 0.0;          /* Map position angle in radians */
  double mapwdth = 0.0;        /* Map width in radians */
  double mapx;                 /* Map X offset in radians */
  double mapy;                 /* Map Y offset in radians */
  double par[7];               /* Projection parameters */
  double pixsize = 0.0;        /* Requested pixel size */
  double shift[ 2 ];           /* Shifts from PIXEL to GRID coords */
  AstMapping *sky2map = NULL;  /* Mapping celestial->map coordinates */
  AstSkyFrame *skyframe = NULL;/* Output SkyFrame */
  AstFrame *skyin = NULL;      /* Sky Frame in input FrameSet */
  double skyref[ 2 ];          /* Values for output SkyFrame SkyRef attribute */
  AstFrameSet *swcsin = NULL;  /* FrameSet describing input WCS */
  int temp;                    /* Temporary variable  */
  double wdthbox;              /* Map width in arcsec */
  int wdthpix;                 /* RA-Dec map width in pixels */
  double x_array_corners[4];   /* X-Indices for corner bolos in array */
  double y_array_corners[4];   /* Y-Indices for corner pixels in array */

  /* Main routine */
  if (*status != SAI__OK) return;

  /* Begin an AST context to ensure that all AST objects are annuled
     before returning to caller */
  astBegin;

  /* Initialize output frameset pointer to NULL */
  *outframeset = NULL;
  for( i = 0; i < 7; i++ ) par[ i ] = AST__BAD;

  /* Read data from the given input file in the group - note index
     should be 1 as we use the first file in the Grp to define the map
     bounds */
  smf_open_file( igrp, index, "READ", SMF__NOCREATE_DATA, &data, status );

  /* Simply abort if it is not a scan */
  if (*status == SAI__OK && data->hdr->obsmode != SMF__OBS_SCAN) {
    *status = SAI__ERROR;
    errRep(" ", "Can not call smf_mapbounds_approx with non-scan observation"
           " (possible programming error)", status);
    goto CLEANUP;
  }

  /* Retrieve file name for use feedback */
  file = data->file;
  smf_smfFile_msg( file, "FILE", 1, "<unknown>" );
  if( *status == SAI__OK ) {
    msgOutif(MSG__VERB, " ",
	     "SMF_MAPBOUNDS_APPROX: Processing ^FILE",
	     status);
  } else {
    errRep( "smf_mapbounds_approx", "Couldn't open input file, ^FILE", status );
  }

  /* Check that the data dimensions are 3 (for time ordered data) */
  if( *status == SAI__OK ) {
    if( data->ndims != 3 ) {
      smf_smfFile_msg( file, "FILE", 1, "<unknown>" );
      msgSeti("THEDIMS", data->ndims);
      *status = SAI__ERROR;
      errRep("smf_mapbounds_approx",
	     "^FILE data has ^THEDIMS dimensions, should be 3.",
	     status);
    }
  }

  /* Construct the WCS for the first time slice in this file */
  smf_tslice_ast( data, 1, 1, NO_FTS, status);

  /* Retrieve header for later constructing output WCS */
  if( *status == SAI__OK) {
    hdr = data->hdr;
    swcsin = hdr->wcs;

    /* Calculate default pixel size */
    pixsize = smf_calc_telres( hdr->fitshdr, status );

    /* Get the user defined pixel size - we trust that smf_get_projpar will
       also read PIXSIZE and get the same answer. We pre-fill par[] to allow
       PIXSIZE=! to accept the dynamic default in both places.*/
    parGdr0d( "PIXSIZE", pixsize, 0, 60, 1, &pixsize, status );
    par[4] = pixsize*AST__DD2R/3600.0;
    par[5] = par[4];

    /* Retrieve input SkyFrame */
    skyin = astGetFrame( swcsin, AST__CURRENT );

    /* Retrieve map height and width from header - will be undef for
       non-scan so set up defaults first. */
    mapwdth = 0.0;
    maphght = 0.0;
    smf_getfitsd( hdr, "MAP_WDTH", &mapwdth, status );
    smf_getfitsd( hdr, "MAP_HGHT", &maphght, status );

    /* Make an approximation if map height and width are not set -
       note that this should ONLY apply for non-scan mode data */
    if ( !mapwdth || !maphght ) {
      if (*status == SAI__OK) {
        *status = SAI__ERROR;
        errRep(" ", "MAP_WDTH and MAP_HGHT must be > 0", status);
        goto CLEANUP;
      }
    }

    mapx = 0.0;   /* Used if the FITS keyword values are undefed */
    mapy = 0.0;
    smf_getfitsd( hdr, "MAP_X", &mapx, status );
    smf_getfitsd( hdr, "MAP_Y", &mapy, status );

    /* Convert map Position Angle to radians */
    mappa = 0.0;
    smf_fits_getD( hdr, "MAP_PA", &mappa, status );
    mappa *= AST__DD2R;

    /* Calculate size of output map in pixels */
    /* Note: this works for the simulator... */
    wdthbox = mapwdth*fabs(cos(mappa)) + maphght*fabs(sin(mappa));
    hghtbox = maphght*fabs(cos(mappa)) + mapwdth*fabs(sin(mappa));
    wdthpix = (int) ( wdthbox / pixsize);
    hghtpix = (int) ( wdthbox / pixsize);
    dxpix = (int) (mapx / pixsize);
    dypix = (int) (mapy / pixsize);

    /* Get the offsets for each corner of the array */
    temp = (wdthpix - 1) / 2;
    x_array_corners[0] = dxpix - temp;
    x_array_corners[1] = dxpix - temp;
    x_array_corners[2] = dxpix + temp;
    x_array_corners[3] = dxpix + temp;

    temp = (hghtpix - 1) / 2;
    y_array_corners[0] = dypix - temp;
    y_array_corners[1] = dypix + temp;
    y_array_corners[2] = dypix - temp;
    y_array_corners[3] = dypix + temp;

    lbnd_out[0] = x_array_corners[0];
    ubnd_out[0] = x_array_corners[0];
    lbnd_out[1] = y_array_corners[0];
    ubnd_out[1] = y_array_corners[0];

    /* Update min/max  */
    for( k=0; k<4; k++ ) {
      if( x_array_corners[k] < lbnd_out[0] ) lbnd_out[0] = x_array_corners[k];
      if( y_array_corners[k] < lbnd_out[1] ) lbnd_out[1] = y_array_corners[k];
      if( x_array_corners[k] > ubnd_out[0] ) ubnd_out[0] = x_array_corners[k];
      if( y_array_corners[k] > ubnd_out[1] ) ubnd_out[1] = y_array_corners[k];
    }

  } else {
    goto CLEANUP;
  }

  /* Now create the output FrameSet. */
  smf_calc_skyframe( skyin, system, hdr, 0, &skyframe, skyref, moving,
                     status );

  /* Get the orientation of the map vertical within the output celestial
     coordinate system. This is derived form the MAP_PA FITS header, which
     gives the orientation of the map vertical within the tracking system. */
  mappa = smf_calc_mappa( hdr, system, skyin, status );

  /* Calculate the projection parameters. We do not enable autogrid determination
     for SCUBA-2 so we do not need to obtain all the data before calculating
     projection parameters. */
  smf_get_projpar( skyframe, skyref, *moving, 0, 0, NULL, 0,
                   mappa, par, NULL, NULL, status );



  /* Now populate a FitsChan with FITS-WCS headers describing the
     required tan plane projection. The longitude and latitude axis
     types are set to either (RA,Dec) or (AZ,EL) to get the correct
     handedness. */
  fitschan = astFitsChan ( NULL, NULL, " " );
  smf_makefitschan( astGetC( skyframe, "System"), &(par[0]),
                    &(par[2]), &(par[4]), par[6], fitschan, status );
  astClear( fitschan, "Card" );
  fs = astRead( fitschan );

  /* Extract the output PIXEL->SKY Mapping - note this is will be
     inverted later to create the sk2map mapping */
  sky2map = astGetMapping( fs, AST__BASE, AST__CURRENT );

  /* Create the output FrameSet */
  *outframeset = astFrameSet( astFrame(2, "Domain=GRID"), " " );

  /* Now add the SkyFrame to it */
  astAddFrame( *outframeset, AST__BASE, sky2map, skyframe );

  /* Apply a ShiftMap to the output FrameSet to re-align the GRID
     coordinates */
  shift[0] = -lbnd_out[0];
  shift[1] = -lbnd_out[1];
  astRemapFrame( *outframeset, AST__BASE, astShiftMap( 2, shift, " " ) );

  astExport( *outframeset );

/* Report the pixel bounds of the cube. */
   if( *status == SAI__OK ) {
      msgOutif( MSG__NORM, " ", " ", status );
      msgSeti( "XL", lbnd_out[ 0 ] );
      msgSeti( "YL", lbnd_out[ 1 ] );
      msgSeti( "XU", ubnd_out[ 0 ] );
      msgSeti( "YU", ubnd_out[ 1 ] );
      msgOutif( MSG__NORM, " ", "   Output map pixel bounds: ( ^XL:^XU, ^YL:^YU )",
                status );
   }


  /* Change the pixel bounds to be consistent with the new CRPIX */
  ubnd_out[0] -= lbnd_out[0]-1;
  lbnd_out[0] = 1;

  ubnd_out[1] -= lbnd_out[1]-1;
  lbnd_out[1] = 1;

  /* Clean Up */
 CLEANUP:
  if (*status != SAI__OK) {
    errRep(FUNC_NAME, "Unable to determine map bounds", status);
  }

  if( data != NULL )
    smf_close_file( &data, status);

  astEnd;

}
Example #5
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 );

}
Example #6
0
void smf_coords_lut( smfData *data, int tstep, dim_t itime_lo,
                     dim_t itime_hi, AstSkyFrame *abskyfrm,
                     AstMapping *oskymap, int moving, int olbnd[ 2 ],
                     int oubnd[ 2 ], fts2Port fts_port, int *lut,
                     double *angle,
                     double *lon, double *lat, int *status ) {

/* Local Variables */
   AstCmpMap *bsmap = NULL;     /* Tracking -> output grid Mapping */
   AstFrame *trfrm = NULL;      /* Tracking Frame */
   AstFrameSet *fs = NULL;      /* Tracking -> output sky FrameSet */
   AstMapping *fullmap = NULL;  /* Full Mapping from bolo GRID to output map GRID */
   AstMapping *offmap = NULL;   /* Mapping from absolute to offset sky coords */
   AstMapping *tr2skyabs = NULL;/* Tracking -> output sky Mapping */
   AstSkyFrame *offsky = NULL;  /* Offset sky frame */
   JCMTState *state;     /* Pointer to telescope info for time slice */
   dim_t ibolo;          /* Vector index of bolometer */
   dim_t idimx;          /* Bolometers per row */
   dim_t idimy;          /* Bolometers per column */
   dim_t ilut;           /* Index of LUT element */
   dim_t itime0;         /* Time slice index at next full calculation */
   dim_t itime;          /* Time slice index */
   dim_t nbolo;          /* Total number of bolometers */
   double *outmapcoord;  /* Array holding output map GRID coords */
   double *px;           /* Pointer to next output map X GRID coord */
   double *py;           /* Pointer to next output map Y GRID coord */
   double *pgx;          /* Pointer to next X output grid coords */
   double *pgy;          /* Pointer to next Y output grid coords */
   double *wgx = NULL;   /* Work space to hold X output grid coords */
   double *wgy = NULL;   /* Work space to hold Y output grid coords */
   double bsx0;          /* Boresight output map GRID X at previous full calc */
   double bsx;           /* Boresight output map GRID X at current time slice */
   double bsxlast;       /* Boresight output map GRID X at previous time slice*/
   double bsy0;          /* Boresight output map GRID Y at previous full calc */
   double bsy;           /* Boresight output map GRID Y at current time slice */
   double bsylast;       /* Boresight output map GRID Y at previous time slice*/
   double dx;            /* Offset in GRID X from previous full calc */
   double dxlast;        /* Offset in GRID X from previous time slice */
   double dy;            /* Offset in GRID Y from previous full calc */
   double dylast;        /* Offset in GRID Y from previous time slice */
   double shift[ 2 ];    /* Shift from PIXEL to GRID in output map */
   double x;             /* Output GRID X at current bolo in current row */
   double xin[ 2 ];      /* Input X values */
   double xout[ 2 ];     /* Output X values */
   double y;             /* Output GRID Y at current bolo in current row */
   double yin[ 2 ];      /* Input Y values */
   double yout[ 2 ];     /* Output Y values */
   int lbnd_in[ 2 ];     /* Lower bounds of input array */
   int np;               /* Number of positions to transform */
   int odimx;            /* Output map X dimension in pixels */
   int odimy;            /* Output map Y dimension in pixels */
   int ox;               /* Output X GRID index (-1) containing current bolo */
   int oy;               /* Output Y GRID index (-1) containing current bolo */
   int ubnd_in[ 2 ];     /* Upper bounds of input array */

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

/* Begin an AST context. */
   astBegin;

/* Get the dimensions of the output map. */
   odimx = oubnd[ 0 ] - olbnd[ 0 ] + 1;
   odimy = oubnd[ 1 ] - olbnd[ 1 ] + 1;

/* Get the dimensions of the bolometer array. */
   idimx = (data->dims)[ 0 ];
   idimy = (data->dims)[ 1 ];

/* Store integer bounds within the input bolometer GRID system. */
   lbnd_in[ 0 ] = 1;
   lbnd_in[ 1 ] = 1;
   ubnd_in[ 0 ] = idimx;
   ubnd_in[ 1 ] = idimy;

/* Determine the number of bolometers. */
   nbolo = idimx*idimy;

/* Initialise the index of the next LUT element to write. */
   ilut = 0;

/* Ensure tstep is at least one. */
   if( tstep < 1 ) tstep = 1;

/* Get the time slice index at which to do the next full calculation. */
   itime0 = itime_lo;

/* We only need the following AST objects if we will be approximating
   some caclulations. */
   if( tstep > 1 ) {

/* We need to find the first good TCS index in order to get the
   tracking system (Which for SCUBA-2 won't be changing in the sequence) */
      itime0 = VAL__BADI;
      for (itime = itime_lo; itime <= itime_hi; itime++) {
        JCMTState * slice = &((data->hdr->allState)[itime]);
        if (!(slice->jos_drcontrol >= 0 && slice->jos_drcontrol & DRCNTRL__POSITION)) {
          itime0 = itime;
          break;
        }
      }

      if ((int)itime0 != VAL__BADI) {

/* We need a Frame describing absolute tracking system coords. Take a
   copy of the supplied skyframe (to inherit obslat, obslon, epoch,
   etc), and then set its system to the tracking system. */
        trfrm = astCopy( abskyfrm );
        astSetC( trfrm, "System",
                 sc2ast_convert_system( (data->hdr->allState)[itime0].tcs_tr_sys,
                                        status ) );

/* Get the Mapping from the tracking system to the output (absolute, since
   abskyfrm is absolute) sky system. */
        fs = astConvert( trfrm, abskyfrm, " " );
        if( !fs && *status == SAI__OK ) {
          *status = SAI__ERROR;
          errRep( " ", "smf_coords_lut: Failed to convert from "
                  "tracking system to output WCS system.", status );
        }
        tr2skyabs = astSimplify( astGetMapping( fs, AST__BASE, AST__CURRENT ) );

/* For moving targets, we also need a Frame describing offset sky
   coordinates in the output map, in which the reference point is the
   current telescope base position. This will involve changing the
   SkyRef attribute of the Frame for every time slice, so take a
   copy of the supplied SkyFrame to avoid changing it. */
        if( moving ) {
          offsky = astCopy( abskyfrm );
          astSet( offsky, "SkyRefIs=Origin" );
        }

/* Create the Mapping from offsets within the output map sky coordinate
   system output to map GRID coords to output map GRID coords. This uses a
   ShiftMap to convert from output PIXEL coords (produced by "oskymap") to
   output GRID coords. Note, if the target is moving, "oskymap" maps from
   sky *offsets* to output map PIXEL coords. */
        shift[ 0 ] = 1.5 - olbnd[ 0 ];
        shift[ 1 ] = 1.5 - olbnd[ 1 ];
        bsmap = astCmpMap( oskymap, astShiftMap( 2, shift, " " ), 1, " " );
      } else {
        /* We did not find any good TCS data so force us into tstep==1
         case and end up with VAL__BADI for every element. */
        tstep = 1;
        itime0 = itime_lo;
        msgOutiff(MSG__VERB, "", "All time slices from %zu -- %zu had bad TCS data.",
                 status, (size_t)itime_lo, (size_t)itime_hi );
      }
   }

/* Allocate memory to hold the (x,y) output map grid coords at each bolo
   for a single time slice. */
   outmapcoord = astMalloc( sizeof( *outmapcoord )*2*nbolo );

/* Initialise boresight position for the benefit of the tstep == 1 case. */
   bsx = bsy = 0.0;
   bsx0 = bsy0 = AST__BAD;
   bsxlast = bsylast = AST__BAD;

/* If lon and lat arrays are to be returned, allocate memory to hold the grid
   coords of every bolometer for a single sample. */
   if( lon && lat ) {
      wgx = astMalloc( nbolo*sizeof( *wgx ) );
      wgy = astMalloc( nbolo*sizeof( *wgy ) );
   }

/* Loop round each time slice. */
   state = data->hdr->allState + itime_lo;
   for( itime = itime_lo; itime <= itime_hi && *status == SAI__OK;
        itime++,state++ ) {

/* No need to get the boresight position if we are doing full
   calculations at every time slice. If this time slice has bad
   TCS data then the problem will be caught in smf_rebin_totmap. */
      if( tstep > 1 ) {

/* Transform the current boresight and base (if moving) positions from
   tracking coords to absolute output map sky coords. */
         xin[ 0 ] = state->tcs_tr_ac1;
         yin[ 0 ] = state->tcs_tr_ac2;
         if( moving ) {
            xin[ 1 ] = state->tcs_tr_bc1;
            yin[ 1 ] = state->tcs_tr_bc2;
            np = 2;
         } else {
            np = 1;
         }
         astTran2( tr2skyabs, np, xin, yin, 1, xout, yout );

/* If the target is moving, find the offsets within the output map sky
   coordinate system, from base to boresight at the current time slice.
   These offsets become the new "boresight" position (in xin/yin). Guard
   against assigning bad values to the ref pos, which can cause AST to
   report errors. */
         if( moving && xout[ 1 ] != AST__BAD && yout[ 1 ] != AST__BAD ) {

/* Set the current telescope base position as the reference point in
   "offsky". Then get the Mapping from absolute to offset sky coords. */
            astSetD( offsky, "SkyRef(1)", xout[ 1 ] );
            astSetD( offsky, "SkyRef(2)", yout[ 1 ] );
            offmap = astSkyOffsetMap( offsky );

/* Use this Mapping to convert the current boresight position from
   absolute sky coords to offsets from the current base position. */
            astTran2( offmap, 1, xout, yout, 1, xin, yin );

/* Annul the Mapping to avoid keep the number of AST objects to a minimum. */
            offmap = astAnnul( offmap );

/* If the target is stationary, we can just use the absolute boresight
   position as it is. */
         } else {
            xin[ 0 ] = xout[ 0 ];
            yin[ 0 ] = yout[ 0 ];
         }

/* Transform the above boresight position from output map sky coords to output
   map GRID coords. */
         astTran2( bsmap, 1, xin, yin, 1, &bsx, &bsy );
      }

/* If we have reached the next full calculation... */
      if( itime == itime0 ) {

/* Calculate the full bolometer to map-pixel transformation for the current
   time slice */
         fullmap = smf_rebin_totmap( data, itime, abskyfrm, oskymap, moving,
                                     fts_port, status );

/* If succesful, use it to transform every bolometer position from bolo
   GRID coords to output map GRID coords. */
         if( fullmap ) {
            itime0 += tstep;
            astTranGrid( fullmap, 2, lbnd_in, ubnd_in, 0.1, 1000000, 1,
                         2, nbolo, outmapcoord );
            fullmap = astAnnul( fullmap );

/* Record the boresight grid coords at this time slice. */
            bsx0 = bsx;
            bsy0 = bsy;

/* If we cannot determine a full Mapping for this time slice, move the
   node to the next time slice (otherwise we would loose all the data to
   the next node), and set the boresight position bad to indicate we
   have no mapping for this time slice. */
         } else {
            itime0++;
            bsx0 = AST__BAD;
            bsy0 = AST__BAD;
         }
      }

/* Get the offset from the boresight position at the previous full
   calculation and the current boresight position, in output map GRID
   coords. */
      dx = ( bsx != AST__BAD && bsx0 != AST__BAD ) ? bsx - bsx0 : AST__BAD;
      dy = ( bsy != AST__BAD && bsy0 != AST__BAD ) ? bsy - bsy0 : AST__BAD;

/* Work out the scan direction based on the GRID offsets between this and
   the previous time slice. Angles are calculated using atan2, with values
   ranging from -pi to +pi. */
      if( angle ) {
        double theta = AST__BAD;

        dxlast = ( bsx != AST__BAD && bsxlast != AST__BAD ) ?
          bsx - bsxlast : AST__BAD;

        dylast = ( bsy != AST__BAD && bsylast != AST__BAD ) ?
          bsy - bsylast : AST__BAD;

        if( dxlast != AST__BAD && dylast != AST__BAD &&
            !( !dxlast && !dylast ) ) {
          theta = atan2( dylast, dxlast );
        }

        angle[itime-itime_lo] = theta;

        bsxlast = bsx;
        bsylast = bsy;
      }

/* Initialise pointers to the place to store the final grid coords for
   each bolometer. */
      pgx = wgx;
      pgy = wgy;

/*   Loop round all bolometers. */
      px = outmapcoord;
      py = outmapcoord + nbolo;
      for( ibolo = 0; ibolo < nbolo; ibolo++ ){

/* If good, get the x and y output map GRID coords for this bolometer. */
         if( dx != AST__BAD && dy != AST__BAD ) {
            x = *(px++) + dx;
            y = *(py++) + dy;

/* If required, store them so that we can convert them into lon/lat
   values later. */
            if( pgx && pgy ) {
               *(pgx++) = x;
               *(pgy++) = y;
            }

/* Find the grid indices (minus one) of the output map pixel containing the
   mapped bolo grid coords. One is subtracted in order to simplify the
   subsequent calculation of the vector index. */
            ox = (int) ( x - 0.5 );
            oy = (int) ( y - 0.5 );

/* Check it is within the output map */
            if( ox >= 0 && ox < odimx && oy >= 0 && oy < odimy ) {

/* Find the 1-dimensional vector index into the output array for this
   pixel and store in the next element of the returned LUT. */
               lut[ ilut++ ] = ox + oy*odimx;

/* Store a bad value for points that are off the edge of the output map. */
            } else {
               lut[ ilut++ ] = VAL__BADI;
            }

/* If good, store a bad index in the LUT and move on to the next pixel. */
         } else {
            lut[ ilut++ ] = VAL__BADI;
            px++;
            py++;
            if( pgx && pgy ) {
               *(pgx++) = AST__BAD;
               *(pgy++) = AST__BAD;
            }
         }
      }

/* If required transform the grid coords into (lon,lat) coords and store in
   the relevant elements of the supplied "lon" and "lat" arrays. */
      if( wgx && wgy ) {
         astTran2( oskymap, nbolo, wgx, wgy, 0, lon + itime*nbolo,
                   lat + itime*nbolo );

/* Convert from rads to degs. */
         pgx = lon + itime*nbolo;
         pgy = lat + itime*nbolo;
         for( ibolo = 0; ibolo < nbolo; ibolo++ ) {
            if( *pgx != AST__BAD && *pgy != AST__BAD ) {
               *(pgx++) *= AST__DR2D;
               *(pgy++) *= AST__DR2D;
            } else {
               pgx++;
               pgy++;
            }
         }
      }
   }

/* To obtain a reasonable value for the first entry of angle, we simply
   duplicate the second value. */
   if( angle && (itime_hi > itime_lo) ) {
     angle[0] = angle[1];
   }

/* Free remaining work space. */
   outmapcoord = astFree( outmapcoord );
   wgx = astFree( wgx );
   wgy = astFree( wgy );

/* Export the WCS pointer in the data header since it will be annulled at
   a higher level. Note the FrameSet pointer may be null if the last
   full calculation was for a slice with bad telescope data. */
   if( data->hdr->wcs ) astExport( data->hdr->wcs );

/* End the AST context. */
   astEnd;
}