Exemplo n.º 1
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;

}
Exemplo n.º 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;

}
Exemplo n.º 3
0
smfDetposWcsCache *smf_detpos_wcs( smfHead *hdr, int index, double dut1,
                                   const double telpos[3],
                                   AstFrameSet **fset, smfDetposWcsCache *cache,
                                   int *status ) {

/* Local Variables: */
   AstCmpMap *cmap1 = NULL;    /* Parallel CmpMap holding both LutMaps */
   AstLutMap *latmap = NULL;   /* LutMap holding latitude values */
   AstLutMap *lonmap = NULL;   /* LutMap holding longitude values */
   AstMapping *map = NULL;     /* GRID->SKY Mapping */
   AstSkyFrame *csky = NULL;   /* SkyFrame to put in returned FrameSet */
   const double *p1;           /* Pointer to next lon or lat value to copy */
   double *p2;                 /* Pointer to next lon value */
   double *p3;                 /* Pointer to next lat value */
   int i;                      /* Index of current detector */
   int nrec;                   /* Number of detectors */
   int outperm[ 2 ];           /* Axis permutation */
   smfDetposWcsCache *result;  /* Pointer to returned cache structure */

/* If a negative index was supplied just free the allocated resources and
   return. */
   if( index < 0 && cache ) {
      if( cache->latlut ) cache->latlut = astFree( cache->latlut );
      if( cache->lonlut ) cache->lonlut = astFree( cache->lonlut );
      if( cache->pmap ) cache->pmap = astAnnul( cache->pmap );
      if( cache->grid ) cache->grid = astAnnul( cache->grid );
      if( cache->sky ) cache->sky = astAnnul( cache->sky );
      cache = astFree( cache );
      return NULL;
   }

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

/* If no cache structure was supplied, allocate and initialise one now. */
   if( !cache ) {
      cache = astMalloc( sizeof( *cache ) );
      if( cache ) {
         cache->latlut = NULL;
         cache->lonlut = NULL;
         cache->pmap = NULL;
         cache->grid = NULL;
         cache->sky = NULL;
         result = cache;

      } else {
         *status = SAI__ERROR;
         errRep( FUNC_NAME, FUNC_NAME": Can't allocate memory for cache.",
                 status);
         return NULL;
      }
   }

/* Get the number of detectors. */
   nrec = hdr->ndet;

/* Get a pointer to the start of the detpos values for the requested
   time slice. */
   p1 = hdr->detpos + 2*nrec*index;

/* Check there is more than 1 detector. */
   if( nrec > 1 ) {

/* It is possible that we have not allocated enough memory since
   this memory is allocated for the first file but subsequent files
   may have more receptors. So we use astGrow. */

/* If required, allocate memory to hold the individual look up tables for
   lon and lat vaues. */
      cache->lonlut = astGrow( cache->lonlut, nrec, sizeof( double ) );
      cache->latlut = astGrow( cache->latlut, nrec, sizeof( double ) );

/* Check the memory was allocated succesfully. */
      if( cache->lonlut && cache->latlut ) {

/* Copy the lon and lat values for the requested time slice from the
   smfHead structure to the local lut arrays. */
         p2 = cache->lonlut;
         p3 = cache->latlut;
         for( i = 0; i < nrec; i++ ) {
            *(p2++) = *(p1++);
            *(p3++) = *(p1++);
         }

/* Create the Mapping from GRID to SKY positions. This is a PermMap to
   duplicate the detector index, followed by 2 LutMaps in parallel to
   generate the lon and lat values. Set the LutInterpattribute in these
   LutMaps so that they use nearest neighbour interpolation. */
         lonmap = astLutMap( nrec, cache->lonlut, 1.0, 1.0, "LutInterp=1" );
         latmap = astLutMap( nrec, cache->latlut, 1.0, 1.0, "LutInterp=1" );
         cmap1 = astCmpMap( lonmap, latmap, 0, " " );

         latmap = astAnnul( latmap );
         lonmap = astAnnul( lonmap );

         if( !cache->pmap ) {
            outperm[ 0 ] = 1;
            outperm[ 1 ] = 1;
            cache->pmap = astPermMap( 2, NULL, 2, outperm, NULL, " " );
            astExempt( cache->pmap );
         }
         map = (AstMapping *) astCmpMap( cache->pmap, cmap1, 1, " " );

         cache->pmap = astAnnul( cache->pmap );
         cmap1 = astAnnul( cmap1 );
      }

/* If thre is only one detector, use a PermMap to describe this one
   position. rather than a LutMap (LutMaps cannot describe a single
   position). */
   } else {
      outperm[ 0 ] = -1;
      outperm[ 1 ] = -2;
      map = (AstMapping *) astPermMap( 2, NULL, 2, outperm, p1, " " );
   }

/* Create two Frames to put in the FrameSet. */
   if( !cache->grid ) {
      cache->grid = astFrame( 2, "Domain=GRID" );
      astExempt( cache->grid );
   }

   if( !cache->sky ) {
      cache->sky = astSkyFrame( "System=AzEl" );
      astSetD( cache->sky, "ObsLon", -telpos[ 0 ] );
      astSetD( cache->sky, "ObsLat", telpos[ 1 ] );
      astExempt( cache->sky );

/* If the detpos positions are referred to the TRACKING frame, change
   the SkyFrame from AZEL to the AST equivalent of the TRACKING Frame. */
      if( !hdr->dpazel ) {
         astSetC( cache->sky, "System", sc2ast_convert_system( hdr->state->tcs_tr_sys,
                                                     status ) );
      }
   }

/* Take a copy of the skyframe, and then modify its Epoch attribute. We take a
   copy since otherwise all FrameSets returned by this function would share
   the same current Frame, and so the attribute change would affect them all.
   Always use TCS_TAI. smf_open_file corrects the JCMTState structure
   if TCS_TAI is missing. Remember to convert from TAI to TDB (as required by
   the Epoch attribute). */
   csky = astClone( cache->sky );
   astSet( csky, "Epoch=MJD %.*g, dut1=%.*g",
           DBL_DIG, hdr->state->tcs_tai + 32.184/SPD,
           DBL_DIG, dut1 );

/* Create the FrameSet */
   *fset = astFrameSet( cache->grid, " " );
   astAddFrame( *fset, AST__BASE, map, csky );

/* Free resources */
   map =astAnnul( map );
   csky =astAnnul( csky );

/* Exempt the FrameSet pointer from the AST context system rather because
   we do not know when, or in which context, it will be used. It will be
   annulled either in smf_tslice_ast or in smf_close_file. */
   astExempt( *fset );

   return result;
}