示例#1
0
QStringList Hero::formatWorldCursor(const std::vector<double> & coords, bool normalize)
{
    if( m_ast.origWcsInfo == AST__NULL) {
        // format the cursor
        QStringList res;
        for( auto i = 1 ; i <= naxes() ; i ++ ) {
            res.append( QString::number( coords[i-1]));
        }
        return res;
    }

    if( int(coords.size()) != naxes()) {
        LTHROW( QString( "formatWorldCursor called with coords.size=%1 but naxes=%2").arg(coords.size()).arg(naxes()));
    }
    // make a copy of the coordinates
    auto wrld = coords;
    // apply normalization to it
    if( normalize) {
        astNorm( m_ast.currWcsInfo, & wrld.front());
    }
    // format the cursor
    QStringList res;
    for( auto i = 1 ; i <= naxes() ; i ++ ) {
        res.append( astFormat( m_ast.currWcsInfo, i, wrld[i-1]));
    }
    return res;
}
示例#2
0
QString Hero::formatWorldValue(double val, int axis)
{
    if( m_ast.origWcsInfo == AST__NULL) {
        return QString::number( val);
    }

    if( axis >= naxes()) {
        LTHROW( QString( "formatWorldValue called with axis=%1 but naxes=%2").arg(axis).arg(naxes()));
    }
    // format the cursor
    QString res = astFormat( m_ast.currWcsInfo, axis + 1, val);
    return res;
}
示例#3
0
unsigned char *smf_get_mask( ThrWorkForce *wf, smf_modeltype mtype,
                             AstKeyMap *config, smfDIMMData *dat, int flags,
                             int *status ) {

/* Local Variables: */
   AstCircle *circle;         /* AST Region used to mask a circular area */
   AstKeyMap *akm;            /* KeyMap holding AST config values */
   AstKeyMap *subkm;          /* KeyMap holding model config values */
   char refparam[ DAT__SZNAM ];/* Name for reference NDF parameter */
   char words[100];           /* Buffer for variable message words */
   const char *cval;          /* The ZERO_MASK string value */
   const char *modname;       /* The name of the model  being masked */
   const char *skyrefis;      /* Pointer to SkyRefIs attribute value */
   dim_t i;                   /* Pixel index */
   double *pd;                /* Pointer to next element of map data */
   double *predef;            /* Pointer to mask defined by previous run */
   double *ptr;               /* Pointer to NDF  Data array */
   double *pv;                /* Pointer to next element of map variance */
   double centre[ 2 ];        /* Coords of circle centre in radians */
   double meanhits;           /* Mean hits in the map */
   double radius[ 1 ];        /* Radius of circle in radians */
   double zero_circle[ 3 ];   /* LON/LAT/Radius of circular mask */
   double zero_lowhits;       /* Fraction of mean hits at which to threshold */
   double zero_snr;           /* Higher SNR at which to threshold */
   double zero_snrlo;         /* Lower SNR at which to threshold */
   int *ph;                   /* Pointer to next hits value */
   int have_mask;             /* Did a mask already exist on entry? */
   int imask;                 /* Index of next mask type */
   int indf1;                 /* Id. for supplied reference NDF */
   int indf2;                 /* Id. for used section of reference NDF */
   int isstatic;              /* Are all used masks static? */
   int lbnd_grid[ 2 ];        /* Lower bounds of map in GRID coords */
   int mask_types[ NTYPE ];   /* Identifier for the types of mask to use */
   int munion;                /* Use union of supplied masks */
   int nel;                   /* Number of mapped NDF pixels */
   int nmask;                 /* The number of masks to be combined */
   int nsource;               /* No. of source pixels in final mask */
   int skip;                  /* No. of iters for which AST is not subtracted */
   int thresh;                /* Absolute threshold on hits */
   int ubnd_grid[ 2 ];        /* Upper bounds of map in GRID coords */
   int zero_c_n;              /* Number of zero circle parameters read */
   int zero_mask;             /* Use the reference NDF as a mask? */
   int zero_niter;            /* Only mask for the first "niter" iterations. */
   int zero_notlast;          /* Don't zero on last iteration? */
   size_t ngood;              /* Number good samples for stats */
   smf_qual_t *pq;            /* Pinter to map quality */
   unsigned char **mask;      /* Address of model's mask pointer */
   unsigned char *newmask;    /* Individual mask work space */
   unsigned char *pm;         /* Pointer to next returned mask pixel */
   unsigned char *pn;         /* Pointer to next new mask pixel */
   unsigned char *result;     /* Returned mask pointer */

/* Initialise returned values */
   result = NULL;

/* Check inherited status. Also check that a map is being created.  */
   if( *status != SAI__OK || !dat || !dat->map ) return result;

/* Begin an AST context. */
   astBegin;

/* Get the sub-keymap containing the configuration parameters for the
   requested model. Also get a pointer to the mask array to use (there is
   one for each maskable model)*/
   if( mtype == SMF__COM ) {
      modname = "COM";
      mask = &(dat->com_mask);
   } else if( mtype == SMF__AST ) {
      modname = "AST";
      mask = &(dat->ast_mask);
   } else if( mtype == SMF__FLT ) {
      modname = "FLT";
      mask = &(dat->flt_mask);
   } else {
      modname = NULL;
      mask = NULL;
      *status = SAI__ERROR;
      errRepf( " ", "smf_get_mask: Unsupported model type %d supplied - "
               "must be COM, FLT or AST.", status, mtype );
   }
   subkm = NULL;
   astMapGet0A( config, modname, &subkm );

/* Get the "ast.skip" value - when considering "zero_niter" and
   "zero_freeze", we only count iterations for which the AST model
   is subtracted (i.e. the ones following the initial "ast.skip"
   iterations). */
   astMapGet0A( config, "AST", &akm );
   astMapGet0I( akm, "SKIP", &skip );
   akm = astAnnul( akm );

/* Get the number of iterations over which the mask is to be applied. Zero
   means all. Return with no mask if this number of iterations has
   already been performed. */
   zero_niter = 0;
   astMapGet0I( subkm, "ZERO_NITER", &zero_niter );
   if( zero_niter == 0 || dat->iter < zero_niter + skip ) {

/* Only return a mask if this is not the last iteration, or if ZERO_NOTLAST
   is unset. */
      zero_notlast = 0;
      astMapGet0I( subkm, "ZERO_NOTLAST", &zero_notlast );
      if( !( flags & SMF__DIMM_LASTITER ) || !zero_notlast ) {

/* Create a list of the mask types to be combined to get the final mask by
   looking for non-default values for the corresponding configuration
   parameters in the supplied KeyMap. Static masks (predefined, circles
   or external NDFs) may be used on any iteration, but dynamic masks
   (lowhits, snr) will only be avialable once the map has been determined
   at the end of the first iteration. This means that when masking anything
   but the AST model (which is determined after the map), the dynamic masks
   cannot be used on the first iteration. Make a note if all masks being
   used are static. */

         isstatic = 1;
         nmask = 0;

         zero_lowhits = 0.0;
         astMapGet0D( subkm, "ZERO_LOWHITS", &zero_lowhits );
         if( zero_lowhits > 0.0 ) {
            if( mtype == SMF__AST || !( flags & SMF__DIMM_FIRSTITER ) ) {
               mask_types[ nmask++] = LOWHITS;
               isstatic = 0;
            }
         } else if( zero_lowhits <  0.0 && *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRepf( " ", "Bad value for config parameter %s.ZERO_LOWHITS (%g) - "
                     "it must not be negative.", status, modname, zero_lowhits );
         }

         if( astMapGet1D( subkm, "ZERO_CIRCLE", 3, &zero_c_n, zero_circle ) ) {
            if( zero_c_n == 1 || zero_c_n == 3 ) {
               mask_types[ nmask++] = CIRCLE;
            } else if( *status == SAI__OK ) {
               *status = SAI__ERROR;
               errRepf( " ", "Bad number of values (%d) for config parameter "
                        "%s.ZERO_CIRCLE - must be 1 or 3.", status, zero_c_n,
                        modname );
            }
         }

         cval = NULL;
         astMapGet0C( subkm, "ZERO_MASK", &cval );
         if( cval ) {
            if( !astChrMatch( cval, "REF" ) &&
                !astChrMatch( cval, "MASK2" ) &&
                !astChrMatch( cval, "MASK3" ) ) {
               astMapGet0I( subkm, "ZERO_MASK", &zero_mask );
               cval = ( zero_mask > 0 ) ? "REF" : NULL;
            }
            if( cval ) {
               strcpy( refparam, cval );
               astChrCase( NULL, refparam, 1, 0 );
               mask_types[ nmask++] = REFNDF;
            }
         }

         zero_snr = 0.0;
         astMapGet0D( subkm, "ZERO_SNR", &zero_snr );
         if( zero_snr > 0.0 ) {
            if( mtype == SMF__AST || !( flags & SMF__DIMM_FIRSTITER ) ) {
               mask_types[ nmask++] = SNR;
               isstatic = 0;
            }
         } else if( zero_snr <  0.0 && *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRepf( " ", "Bad value for config parameter %s.ZERO_SNR (%g) - "
                     "it must not be negative.", status, modname, zero_snr );
         }

         if( astMapHasKey( subkm, "ZERO_MASK_POINTER" ) ) {
            astMapGet0P( subkm, "ZERO_MASK_POINTER", (void **) &predef );
            if( predef ) mask_types[ nmask++] = PREDEFINED;
         }

/* No need to create a mask if no masking was requested or possible. */
         if( nmask > 0 ) {

/* Decide if we are using the union or intersection of the masks. */
            astMapGet0I( subkm, "ZERO_UNION", &munion );

/* Note if a mask existed on entry. If not, create a mask now, and
   initialise it to hold the mask defined by the initial sky map. */
            if( *mask == NULL ) {
               have_mask = 0;
               if( dat->initqual ) {
                  *mask = astMalloc( dat->msize*sizeof( **mask ) );
                  if( *mask ) {
                     pm = *mask;
                     pq = dat->initqual;
                     for( i = 0; i < dat->msize; i++ ) {
                        *(pm++) = ( *(pq++) != 0 );
                     }
                  }
               } else{
                  *mask = astCalloc( dat->msize, sizeof( **mask ) );
               }
            } else {
               have_mask = 1;
            }

/* If we are combining more than one mask, we need work space to hold
   an individual mask independently of the total mask. If we are using
   only one mask, then just use the main mask array. */
            if( nmask > 1 ) {
               newmask = astMalloc( dat->msize*sizeof( *newmask ) );
            } else {
               newmask = *mask;
            }

/* Get the number of iterations after which the mask is to be frozen.
   Zero means "never freeze the mask". */
            int zero_freeze = 0;
            astMapGet0I( subkm, "ZERO_FREEZE", &zero_freeze );

/* Loop round each type of mask to be used. */
            for( imask = 0; imask < nmask && *status == SAI__OK; imask++ ){

/* If the mask is now frozen, we just return the existing mask. So leave the
   loop. */
               if( zero_freeze != 0 && dat->iter > zero_freeze + skip ) {
                  break;

/* Low hits masking... */
               } else if( mask_types[ imask ] == LOWHITS ) {

/* Set hits pixels with 0 hits to VAL__BADI so that stats1 ignores them */
                  ph = dat->hitsmap;
                  for( i = 0; i < dat->msize; i++,ph++ ) {
                     if( *ph == 0 ) *ph = VAL__BADI;
                  }

/* Find the mean hits in the map */
                  smf_stats1I( dat->hitsmap, 1, dat->msize, NULL, 0, 0, &meanhits,
                               NULL, NULL, &ngood, status );
                  msgOutiff( MSG__DEBUG, " ", "smf_get_mask: mean hits = %lf, ngood "
                             "= %zd", status, meanhits, ngood );

/* Create the mask */
                  thresh = meanhits*zero_lowhits;
                  ph = dat->hitsmap;
                  pn = newmask;
                  for( i = 0; i < dat->msize; i++,ph++ ) {
                     *(pn++) = ( *ph != VAL__BADI && *ph < thresh ) ? 1 : 0;
                  }

/* Report masking info. */
                  msgOutiff( MSG__DEBUG, " ", "smf_get_mask: masking %s "
                             "model at hits = %d.", status, modname, thresh );

/* Circle masking... */
               } else if( mask_types[ imask ] == CIRCLE ) {

/* If we had a mask on entry, then there is no need to create a new one
   since it will not have changed. But we need to recalculate the circle
   mask if are combining it with any non-static masks. */
                  if( ! have_mask || ! isstatic ) {

/* If only one parameter supplied it is radius, assume reference
   LON/LAT from the frameset to get the centre. If the SkyFrame
   represents offsets from the reference position (i.e. the source is
   moving), assume the circle is to be centred on the origin.  */
                     if( zero_c_n == 1 ) {
                        zero_circle[ 2 ] = zero_circle[ 0 ];

                        skyrefis = astGetC( dat->outfset, "SkyRefIs" );
                        if( skyrefis && !strcmp( skyrefis, "Origin" ) ) {
                           zero_circle[ 0 ] = 0.0;
                           zero_circle[ 1 ] = 0.0;
                        } else {
                           zero_circle[ 0 ] = astGetD( dat->outfset, "SkyRef(1)" );
                           zero_circle[ 1 ] = astGetD( dat->outfset, "SkyRef(2)" );
                        }

                        zero_circle[ 0 ] *= AST__DR2D;
                        zero_circle[ 1 ] *= AST__DR2D;
                     }

/* The supplied bounds are for pixel coordinates... we need bounds for grid
    coordinates which have an offset */
                     lbnd_grid[ 0 ] = 1;
                     lbnd_grid[ 1 ] = 1;
                     ubnd_grid[ 0 ] = dat->ubnd_out[ 0 ] - dat->lbnd_out[ 0 ] + 1;
                     ubnd_grid[ 1 ] = dat->ubnd_out[ 1 ] - dat->lbnd_out[ 1 ] + 1;

/* Coordinates & radius of the circular region converted from degrees
   to radians */
                     centre[ 0 ] = zero_circle[ 0 ]*AST__DD2R;
                     centre[ 1 ] = zero_circle[ 1 ]*AST__DD2R;
                     radius[ 0 ] = zero_circle[ 2 ]*AST__DD2R;

/* Create the Circle, defined in the current Frame of the FrameSet (i.e.
   the sky frame). */
                     circle = astCircle( astGetFrame( dat->outfset, AST__CURRENT), 1,
                                         centre, radius, NULL, " " );

/* Fill the mask with zeros. */
                     memset( newmask, 0, sizeof( *newmask )*dat->msize );

/* Get the mapping from the sky frame (current) to the grid frame (base),
   and then set the mask to 1 for all of the values outside this circle */
                     astMaskUB( circle, astGetMapping( dat->outfset, AST__CURRENT,
                                                       AST__BASE ),
                                0, 2, lbnd_grid, ubnd_grid, newmask, 1 );

/* Report masking info. */
                     if( zero_niter == 0 ) {
                        sprintf( words, "on each iteration" );
                     } else {
                        sprintf( words, "for %d iterations", zero_niter );
                     }

                     msgOutiff( MSG__DEBUG, " ", "smf_get_mask: The %s model will"
                                " be masked %s using a circle of "
                                "radius %g arc-secs, centred at %s=%s, %s=%s.",
                                status, modname, words, radius[0]*AST__DR2D*3600,
                                astGetC( dat->outfset, "Symbol(1)" ),
                                astFormat( dat->outfset, 1, centre[ 0 ] ),
                                astGetC( dat->outfset, "Symbol(2)" ),
                                astFormat( dat->outfset, 2, centre[ 1 ] ) );
                  }

/* Reference NDF masking... */
               } else if( mask_types[ imask ] == REFNDF ) {

/* If we had a mask on entry, then there is no need to create a new one
   since it will not have changed. But we need to recalculate the NDF
   mask if are combining it with any non-static masks. */
                  if( ! have_mask || ! isstatic ) {

/* Begin an NDF context. */
                     ndfBegin();

/* Get an identifier for the NDF using the associated ADAM parameter. */
                     ndfAssoc( refparam, "READ", &indf1, status );

/* Get a section from this NDF that matches the bounds of the map. */
                     ndfSect( indf1, 2, dat->lbnd_out, dat->ubnd_out, &indf2,
                              status );

/* Map the section. */
                     ndfMap( indf2, "DATA", "_DOUBLE", "READ", (void **) &ptr,
                             &nel, status );

/* Check we can use the pointer safely. */
                     if( *status == SAI__OK ) {

/* Find bad pixels in the NDF and set those pixels to 1 in the mask. */
                        pn = newmask;
                        for( i = 0; i < dat->msize; i++ ) {
                           *(pn++) = ( *(ptr++) == VAL__BADD ) ? 1 : 0;
                        }

/* Report masking info. */
                        ndfMsg( "N", indf2 );
                        msgSetc( "M", modname );
                        if( zero_niter == 0 ) {
                           msgOutiff( MSG__DEBUG, " ", "smf_get_mask: The ^M "
                                      "model will be masked on each iteration "
                                      "using the bad pixels in NDF '^N'.",
                                      status );
                        } else {
                           msgSeti( "I", zero_niter );
                           msgOutiff( MSG__DEBUG, " ", "smf_get_mask: The ^M "
                                      "model will be masked for ^I iterations "
                                      "using the bad pixels in NDF '^N'.",
                                      status );
                        }
                     }

/* End the NDF context. */
                     ndfEnd( status );
                  }

/* SNR masking... */
               } else if( mask_types[ imask ] == SNR ) {

/* Get the lower SNR limit. */
                  zero_snrlo = 0.0;
                  astMapGet0D( subkm, "ZERO_SNRLO", &zero_snrlo );
                  if( zero_snrlo <= 0.0 ) {
                     zero_snrlo = zero_snr;
                  } else if( zero_snrlo > zero_snr && *status == SAI__OK ) {
                     *status = SAI__ERROR;
                     errRepf( " ", "Bad value for config parameter "
                              "%s.ZERO_SNRLO (%g) - it must not be higher "
                              "than %s.ZERO_SNR (%g).", status, modname,
                              zero_snrlo, modname, zero_snr );
                  }

/* If the higher and lower SNR limits are equal, just do a simple
   threshold on the SNR values to get the mask. */
                  if( zero_snr == zero_snrlo ) {
                     pd = dat->map;
                     pv = dat->mapvar;
                     pn = newmask;
                     for( i = 0; i < dat->msize; i++,pd++,pv++ ) {
                        *(pn++) = ( *pd != VAL__BADD && *pv != VAL__BADD &&
                                    *pv >= 0.0 && *pd < zero_snr*sqrt( *pv ) ) ? 1 : 0;
                     }

/* Report masking info. */
                     if( !have_mask ) {
                        if( zero_niter == 0 ) {
                           sprintf( words, "on each iteration" );
                        } else {
                           sprintf( words, "for %d iterations", zero_niter );
                        }
                        msgOutiff( MSG__DEBUG, " ", "smf_get_mask: The %s model "
                                   "will be masked %s using an SNR limit of %g.",
                                   status, modname, words, zero_snr );
                     }

/* If the higher and lower SNR limits are different, create an initial
   mask by thresholding at the ZERO_SNR value, and then extend the source
   areas within the mask down to an SNR limit of ZERO_SNRLO. */
                  } else {
                     smf_snrmask( wf, dat->map, dat->mapvar, dat->mdims,
                                  zero_snr, zero_snrlo, newmask, status );

/* Report masking info. */
                     if( !have_mask ) {
                        if( zero_niter == 0 ) {
                           sprintf( words, "on each iteration" );
                        } else {
                           sprintf( words, "for %d iterations", zero_niter );
                        }
                        msgOutiff( MSG__DEBUG, " ", "smf_get_mask: The %s model "
                                   "will be masked %s using an SNR limit of %g "
                                   "extended down to %g.", status, modname,
                                   words, zero_snr, zero_snrlo );
                     }
                  }

/* Predefined masking... */
               } else if( mask_types[ imask ] == PREDEFINED ) {

/* If we had a mask on entry, then there is no need to create a new one
   since it will not have changed. But we need to recalculate the
   mask if are combining it with any non-static masks. */
                  if( ! have_mask || ! isstatic ) {

/* Find bad pixels in the predefined array and set those pixels to 1 in
   the mask. */
                     pn = newmask;
                     for( i = 0; i < dat->msize; i++ ) {
                        *(pn++) = ( *(predef++) == VAL__BADD ) ? 1 : 0;
                     }

/* Report masking info. */
                     if( zero_niter == 0 ) {
                        sprintf( words, "on each iteration" );
                     } else {
                        sprintf( words, "for %d iterations", zero_niter );
                     }
                     msgOutiff( MSG__DEBUG, " ", "smf_get_mask: The %s model "
                                "will be masked %s using a smoothed form of "
                                "the final mask created with the previous map.",
                                status, modname, words );
                  }
               }

/* If required, add the new mask into the returned mask. If this is the
   first mask, we just copy the new mask to form the returned mask.
   Otherwise, we combine it with the existing returned mask. */
               if( ! have_mask || ! isstatic ) {
                  if( nmask > 1 ) {
                     if( imask == 0 ) {
                        memcpy( *mask, newmask, dat->msize*sizeof(*newmask));
                     } else {
                        pm = *mask;
                        pn = newmask;
                        if( munion ) {
                           for( i = 0; i < dat->msize; i++,pm++ ) {
                              if( *(pn++) == 0 ) *pm = 0;
                           }
                        } else {
                           for( i = 0; i < dat->msize; i++,pm++ ) {
                              if( *(pn++) == 1 ) *pm = 1;
                           }
                        }
                     }
                  }
               }
            }

/* Free the individual mask work array if it was used. */
            if( nmask > 1 ) newmask = astFree( newmask );

/* Check that the mask has some source pixels (i.e. pixels that have non-bad data values -
   we do not also check variance values since they are not available until the second
   iteration). */
            if( *status == SAI__OK ) {
               nsource = 0;
               pm = *mask;
               pd = dat->map;
               for( i = 0; i < dat->msize; i++,pd++,pv++,pm++ ) {
                  if( *pd != VAL__BADD && *pm == 0 ) nsource++;
               }
               if( nsource < 5 && *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  errRepf( "", "The %s mask being used has fewer than 5 "
                           "source pixels.", status, modname );
                  if( zero_snr > 0.0 ) {
                     errRepf( "", "Maybe your zero_snr value (%g) is too high?",
                              status, zero_snr );
                  }
               }
            }

/* Return the mask pointer if all has gone well. */
            if( *status == SAI__OK ) result = *mask;
         }
      }
   }

/* End the AST context, annulling all AST Objects created in the context. */
   astEnd;

/* Return the pointer to the boolean mask. */
   return result;
}
示例#4
0
void smurf_jsatileinfo( int *status ) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   } else {

      nc = 512;
      jcmt_tiles = astMalloc( nc );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* End the AST context. */
   astEnd;

/* Issue a status indication.*/
   msgBlank( status );
   if( *status == SAI__OK ) {
      msgOutif( MSG__VERB, "", "JSATILEINFO succeeded.", status);
   } else {
      msgOutif( MSG__VERB, "", "JSATILEINFO failed.", status);
   }
}
示例#5
0
int smf_fix_metadata_scuba2 ( msglev_t msglev, smfData * data, int have_fixed, int *ncards, int * status ) {

  AstFitsChan * fits = NULL; /* FITS header (FitsChan) */
  struct FitsHeaderStruct fitsvals; /* Quick access Fits header struct */
  smfHead *hdr = NULL;       /* Data header struct */
  AstKeyMap * obsmap = NULL; /* Info from all observations */
  AstKeyMap * objmap = NULL; /* All the object names used */

  if (*status != SAI__OK) return have_fixed;

  /* Validate arguments - need smfFile and smfHead */
  smf_validate_smfData( data, 1, 1, status );
  if (*status != SAI__OK) return have_fixed;

  hdr = data->hdr;
  smf_validate_smfHead( hdr, 1, 1, status );
  if (*status != SAI__OK) return have_fixed;

  fits = hdr->fitshdr;

  if (hdr->instrument != INST__SCUBA2) {
    if (*status != SAI__OK) {
      *status = SAI__ERROR;
      errRep("", " Attempting to fix metadata using SCUBA-2 algorithms but this is not SCUBA-2 data",
             status );
    }
    return have_fixed;
  }

  /* Update units string to something that is FITS standard compliant
     - we used "DAC units" for a while but in FITS land this becomes
     "decacoulomb * units" */
  if ( strncmp( hdr->units, "DAC", 3) == 0 ) {
    one_strlcpy( hdr->units, "adu", SMF__CHARLABEL, status );
  }

  /* Clock jitter and readout efficiencies mean we need to recalculate STEPTIME from the data.
     This is possible because we know that we have a continuous sequence in each file (unlike
     ACSIS). */
  if (hdr->allState) {
    /* it will be odd if it is not there */
    size_t nframes = hdr->nframes;

    size_t istart = 0;
    double start_time = (hdr->allState)[istart].rts_end;
    while( start_time == VAL__BADD && ++istart < nframes ) {
      start_time = (hdr->allState)[istart].rts_end;
    }

    size_t iend = nframes - 1;
    double end_time = (hdr->allState)[iend].rts_end;
    while( end_time == VAL__BADD && iend-- > 0 ) {
      end_time = (hdr->allState)[iend].rts_end;
    }

    double steptime = VAL__BADD;
    double newstep;

    smf_getfitsd( hdr, "STEPTIME", &steptime, status );
    newstep = steptime;

    /* it is possible for a file to contain only one step since
       the DA just dumps every N-steps. We can not recalculate the
       step time in that case. */
    nframes = iend - istart + 1;
    if (nframes > 1) {

      /* duration of file in days */
      newstep = end_time - start_time;

      /* convert to seconds */
      newstep *= SPD;

      /* Convert to step time */
      newstep /= (nframes - 1);
    } else if( nframes > 0 ) {
      /* work it out from RTS_END and TCS_TAI */
      JCMTState * onlystate = &((hdr->allState)[istart]);
      if ( onlystate->tcs_tai != VAL__BADD &&
           onlystate->tcs_tai != onlystate->rts_end) {
        /* TCS_TAI is in the middle of the step */
        newstep = 2.0 * ( onlystate->rts_end - onlystate->tcs_tai ) * SPD;
      }
    } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      if( data->file ) {
         smf_smfFile_msg( data->file, "N", 1, "<unknown>" );
         errRep("", "No valid RTS_END values found in NDF '^N'.", status );
      } else {
         errRep("", "No valid RTS_END values found.", status );
      }
    }

    if (steptime != newstep) {
      msgOutiff( msglev, "", INDENT "Recalculated step time as %g sec from JCMTSTATE (was %g sec)",
                 status, newstep, steptime);
      smf_fits_updateD( hdr, "STEPTIME", newstep, NULL, status );
      have_fixed |= SMF__FIXED_FITSHDR;
    }
  }


  /* Read some FITS headers, intialising the struct first */
  fitsvals.utdate = VAL__BADI;
  *(fitsvals.instrume) = '\0';
  smf_getfitsi( hdr, "UTDATE", &(fitsvals.utdate), status );
  smf_getfitss( hdr, "INSTRUME", fitsvals.instrume, sizeof(fitsvals.instrume), status );

  /* Print out summary of this observation - this may get repetitive if multiple files come
     from the same observation in one invocation but it seems better to describe each fix up
     separately and in context. */
  obsmap = astKeyMap( " " );
  objmap = astKeyMap( " " );
  smf_obsmap_fill( data, obsmap, objmap, status );
  smf_obsmap_report( msglev, obsmap, objmap, status );
  obsmap = astAnnul( obsmap );
  objmap = astAnnul( objmap );

  /* First we need to look for a BACKEND header which we do not write to the raw
     data files but CADC would like to see equal to INSTRUME */
  if (!astTestFits( fits, "BACKEND", NULL ) ) {
    have_fixed |= SMF__FIXED_FITSHDR;
    smf_fits_updateS( hdr, "BACKEND", fitsvals.instrume, "Name of the backend", status );
    msgOutif( msglev, "",  INDENT "Setting backend for SCUBA-2 observation.", status);
  }

  /* BASETEMP was reading MUXTEMP for pre-20091101 data */
  if ( fitsvals.utdate < 20091101 ) {
    double muxtemp = 0.0;
    have_fixed |= SMF__FIXED_FITSHDR;
    smf_getfitsd( hdr, "BASETEMP", &muxtemp, status );
    smf_fits_updateU( hdr, "BASETEMP", "[K] Base temperature", status );
    smf_fits_updateD( hdr, "MUXTEMP", muxtemp, "[K] Mux temperature", status );
    msgOutif( msglev, "", INDENT "Mux temperature is being read from BASETEMP header.", status );
  }

  /* Sometime before 20091119 the SHUTTER keyword was written as a string
     OPEN or CLOSED. Rewrite those as numbers */
  if (fitsvals.utdate < 20091119) {
    double shutval = 0.0;
    /* Try to read as a double. */
    smf_fits_getD( hdr, "SHUTTER", &shutval, status );

    /* Old data was a string. Convert to a double */
    if (*status == AST__FTCNV) {
      char shutter[100];
      errAnnul( status );
      smf_fits_getS( hdr, "SHUTTER", shutter, sizeof(shutter), status);
      if (strcmp(shutter, "CLOSED") == 0) {
        shutval = 0.0;
      } else {
        shutval = 1.0;
      }
      /* update the value */
      have_fixed |= SMF__FIXED_FITSHDR;
      smf_fits_updateD( hdr, "SHUTTER", shutval, "shutter position 0-Closed 1-Open", status );
      msgOutif( msglev, "", INDENT "Forcing SHUTTER header to be numeric", status );
    }
  }

  /* Engineering data with just SCUBA2 and no RTS left the RTS_NUM field
     filled with zeroes. Just assume that a zero in RTS_NUM is always
     indicative of a private sequence. */
  if (fitsvals.utdate < 20110401) {
    size_t nframes = hdr->nframes;
    JCMTState * curstate = &((hdr->allState)[0]);
    JCMTState * endstate = &((hdr->allState)[nframes-1]);
    if (curstate->rts_num == 0 && endstate->rts_num == 0) {
      /* have to set the values from the SEQSTART and SEQEND headers
         since those were set correctly (although any value would
         do of course apart from the sanity check in smf_find_science. */
      size_t i;
      int seqnum = 1;
      smf_fits_getI( hdr, "SEQSTART", &seqnum, status );
      for ( i=0; i<nframes; i++) {
        curstate = &((hdr->allState)[i]);
        curstate->rts_num = seqnum;
        seqnum++;
      }
      have_fixed |= SMF__FIXED_JCMTSTATE;
      msgOutif( msglev, "", INDENT "Private RTS sequence. Fixing RTS_NUM.", status );
    }
  }

  /* work out if this is a fast flat observation taken before May 2010 */
  if (fitsvals.utdate > 20100218 && fitsvals.utdate < 20100501) {
    char buff[100];
    /* need to know whether this is a FASTFLAT */
    smf_getfitss( hdr, "SEQ_TYPE", buff, sizeof(buff), status );

    if (strcmp( buff, "FASTFLAT" ) == 0 ) {

      /* Fast flats had incorrect SHUTTER settings for one night */
      if (fitsvals.utdate == 20100223) {
        have_fixed |= SMF__FIXED_FITSHDR;
        smf_fits_updateD( hdr, "SHUTTER", 1.0, "shutter position 0-Closed 1-Open", status );
        msgOutif( msglev, "", INDENT "Shutter was open for fast flatfield ramp. Correcting.", status );
      }

      /* Need to fix up SC2_HEAT ramps */
      /* the problem is that the data were assumed to be taken with 3 measurements
         in each heater setting. What actually happened was that the first 5 were
         done at the reference setting and then the data were grouped in threes
         finishing with a single value at the reference setting again.

         For example the heater values and the actual values look something like

           Stored    1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
           Actual    0 0 0 0 0 2 2 2 3 3 3 4 4 4 5

         So we can correct for this by starting at the end and copying in the value
         two slots further down until we get to position #4. Then replacing that with
         the PIXHEAT number.
      */

      {
        size_t i;
        int pixheat = 0;
        size_t nframes = hdr->nframes;
        smf_getfitsi( hdr, "PIXHEAT", &pixheat, status );

        /* shift everything up by 2 */
        for (i=nframes-1; i > 4; i--) {
          JCMTState * curstate = &((hdr->allState)[i]);
          JCMTState * prevstate = &((hdr->allState)[i-2]);
          curstate->sc2_heat = prevstate->sc2_heat;
        }

        /* fill in the first 5 slots with the same value */
        for (i=0; i<5; i++) {
          JCMTState * curstate = &((hdr->allState)[i]);
          curstate->sc2_heat = pixheat;
        }
        have_fixed |= SMF__FIXED_JCMTSTATE;
      }
    }
  }

  /* We always recalculate the WVM start and end tau values so that the header
     reflects something approximating the value that was actually used in the
     extinction correction.

     Note that smf_calc_smoothedwvm can do a better job because it has multiple
     subarrays to get all the values from. We just have to try with what we
     have from a single subarray. We do step into the time series until we
     find something good.

     The header values should mostly agree with the recalculated values if the
     WVM code at the time matches the code in SMURF for that date. This has not
     been true in cases where we have retrospectively realised that there has been
     a calibration error in the WVM. So that we do not have to keep track of those
     times explicitly we currently recalculate every time. If this recalculation
     becomes a problem (smf_calc_wvm has a cache now to minimize this) it should
     be possible to disable this recalculation if the file is less than, say,
     30 minutes old to indicate we are running in near realtime.

     As a special case we do not recalculate the headers for FOCUS observations
     as the WVM reading is somewhat irrelevant and simply slows things down.

  */

  if( *status == SAI__OK ){

    /* Have not parsed header yet to extract type so do it explicitly here */
    char obstype[100];
    smf_getfitss( hdr, "OBS_TYPE", obstype, sizeof(obstype), status );

    if (strcasecmp( obstype, "focus") != 0) {

      size_t i;
      size_t nframes = hdr->nframes;
      double starttau = VAL__BADD;
      double starttime = VAL__BADD;
      double endtau = VAL__BADD;
      double endtime = VAL__BADD;

      /* Create a TimeFrame that can be used to format MJD values into ISO
         date-time strings, including a "T" separator between time and date. */
      AstTimeFrame *tf = astTimeFrame( "Format=iso.0T" );

      for (i=0; i < nframes && *status == SAI__OK; i++) {
        smf__calc_wvm_index( hdr, "AMSTART", i, &starttau, &starttime, status );
        if (starttau != VAL__BADD) break;
        if (*status == SAI__ERROR) errAnnul( status );
      }

      /* if we did not get a start tau we are not going to get an end tau */
      if (starttau != VAL__BADD) {
        for (i=0; i < nframes && *status == SAI__OK; i++) {
          smf__calc_wvm_index( hdr, "AMEND", nframes - 1 - i, &endtau, &endtime, status );
          if (endtau != VAL__BADD) break;
          if (*status == SAI__ERROR) errAnnul( status );
        }
      }

      /* If we could not find any WVM readings then we have a bit of a problem.
         Do we clear the FITS headers or do we leave them untouched? Leave them
         alone for now. */
      if (starttau != VAL__BADD && starttime != VAL__BADD) {
        smf_fits_updateD( hdr, "WVMTAUST", starttau, "186GHz Tau from JCMT WVM at start", status );

        /* Convert starttime MJD to ISO format and update the value in the
           FITS header. */
        smf_fits_updateS( hdr, "WVMDATST", astFormat( tf, 1, starttime ),
                          "Time of WVMTAUST", status );
        have_fixed |= SMF__FIXED_FITSHDR;
      }

      if (endtau != VAL__BADD && endtime != VAL__BADD) {
        smf_fits_updateD( hdr, "WVMTAUEN", endtau, "186GHz Tau from JCMT WVM at end", status );

        /* Convert endtime MJD to ISO format and update the value in the
           FITS header. */
        smf_fits_updateS( hdr, "WVMDATEN", astFormat( tf, 1, endtime ),
                          "Time of WVMTAUEN", status );
        have_fixed |= SMF__FIXED_FITSHDR;
      }

      /* Free the TimeFrame. */
      tf = astAnnul( tf );

    }
  }


  /* SEQ_TYPE header turned up in 20091125. Before that date the SEQ_TYPE only
     had two values. If the shutter was open then SEQ_TYPE is just OBS_TYPE. In the
     dark only a FLATFIELD sometimes finished with a noise but in that case CALCFLAT
     doesn't care so we just call it a flatfield sequence anyhow. We could look at
     the OBSEND flag but I'm not sure it makes a difference. */
  if ( fitsvals.utdate < 20091125 ) {
    char obstype[100];
    char seqtype[100];
    double shutval = 0.0;
    /* need to know what type of observation this is */
    smf_getfitss( hdr, "OBS_TYPE", obstype, sizeof(obstype), status );
    /* and the shutter status */
    smf_fits_getD( hdr, "SHUTTER", &shutval, status );

    if (shutval == 0.0 && strcasecmp( obstype, "flatfield" ) != 0 ) {
      /* flatfield was the only non-noise observation in the dark */
      one_strlcpy( seqtype, "NOISE", sizeof(seqtype), status );
      msgOutif( msglev, "", INDENT "Setting sequence type to NOISE", status );
    } else {
      /* Shutter was open so SEQ_TYPE is just OBS_TYPE */
      one_strlcpy( seqtype, obstype, sizeof(seqtype), status );
      msgOutif( msglev, "",  INDENT "Setting sequence type to obs type", status);
    }
    smf_fits_updateS( hdr, "SEQ_TYPE", seqtype, "Type of sequence", status );
    have_fixed |= SMF__FIXED_FITSHDR;
  }

  /* The telescope goes crazy at the end of observation 56 on 20110530. Null
     the telescope data for subscans 30, 31 and 32 */
  if (fitsvals.utdate == 20110530) {
    char obsid[81];
    smf_getobsidss( hdr->fitshdr, obsid, sizeof(obsid), NULL, 0, status);

    if (strcmp(obsid, "scuba2_00056_20110530T135530") == 0 ) {
      int subscan;
      smf_getfitsi( hdr, "NSUBSCAN", &subscan, status );
      if (subscan == 30 || subscan == 31 || subscan == 32) {
        size_t nframes = hdr->nframes;
        JCMTState * curstate;
        size_t i;
        for ( i=0; i<nframes; i++ ) {
          curstate = &((hdr->allState)[i]);
          curstate->jos_drcontrol |= DRCNTRL__PTCS_BIT;
        }
        msgOutif( msglev, "", INDENT "Blanking telescope data due to extreme excursion", status );
        have_fixed |= SMF__FIXED_JCMTSTATE;
      }
    }
  }

  /* The second half of observation 14 on 20111215 (scuba2_00014_20111215T061536)
     has a elevation pointing shift */
  if (fitsvals.utdate == 20111215) {
    char obsid[81];
    const char fitskey[] = "FIXPCORR";
    smf_getobsidss( hdr->fitshdr, obsid, sizeof(obsid), NULL, 0, status);

    if (strcmp(obsid, "scuba2_00014_20111215T061536") == 0 ) {
      int seqcount;
      smf_getfitsi( hdr, "SEQCOUNT", &seqcount, status );
      if (seqcount == 5) {
        int have_fixed_pntg = 0;
        smf_fits_getL( hdr, fitskey, &have_fixed_pntg, status );
        if (*status == SMF__NOKWRD) {
          have_fixed = 0;
          errAnnul( status );
        }
        if (!have_fixed_pntg) {
          size_t nframes = hdr->nframes;
          size_t i;
          const double dlon = 0.0;
          const double dlat = -16.83; /* From making maps of each half */
          /* Correct the pointing */
          msgOutif( msglev, "", INDENT "Applying pointing anomaly correction", status );
          for (i=0;i<nframes;i++) {
            JCMTState * curstate = &((hdr->allState)[i]);
            /* This is an AZEL correction */
            smf_add_smu_pcorr( curstate, 1, dlon, dlat, status );
          }
          smf_fits_updateL(hdr, fitskey, 1, "Applied internal pointing correction", status);
          have_fixed |= SMF__FIXED_JCMTSTATE;
        }
      }
    }

  }

  /* For POL-2 data prior to 18-JAN-2013, the POL_CRD header was always
     "FPLANE" in reality, even if the POL_CRD value in JCMTSTATE said
     something else. */
  if ( fitsvals.utdate < 20130118 ) {
    char polcrd[80] = "<unset>";
    smf_getfitss( hdr, "POL_CRD", polcrd, sizeof(polcrd), status );
    if (*status == SMF__NOKWRD) {
       errAnnul( status );
    } else if( !strcmp( polcrd, "TRACKING" ) || !strcmp( polcrd, "AZEL" ) ) {
      msgOutiff( msglev, "",  INDENT "Changing POL_CRD from %s to FPLANE", status, polcrd);
      smf_fits_updateS( hdr, "POL_CRD", "FPLANE",
                        "Coordinate system of polarimeter", status );
      have_fixed |= SMF__FIXED_FITSHDR;
    }
  }


  return have_fixed;
}
示例#6
0
void gsdac_getDateVars ( const gsdVars *gsdVars, const char *backend,
                         const int obsNum, dateVars *dateVars,
                         int *status )

{

  /* Local variables */
  char dateString[SZFITSTR];  /* temporary string for date conversions. */
  int day;                    /* days */
  double dLST;                /* difference in LST */
  double dut1;                /* UT1-UTC correction */
  int hour;                   /* hours */
  int min;                    /* minutes */
  int month;                  /* months */
  float sec;                  /* seconds */
  int tableDims;              /* dimensionality of data table */
  int tableSize;              /* number of elements of data table */
  int tableElement;           /* index of element in data table */
  AstTimeFrame *tempFrame = NULL; /* AstTimeFrame for UT1-UTC conversion */
  const char *tempString;     /* temporary string */
  AstTimeFrame *tFrame = NULL;  /* AstTimeFrame for UT1-UTC conversion */
  double utcEnd;              /* end UTC time */
  double HSTend;              /* end HST time */
  double HSTstart;            /* start HST time */
  double utcStart;            /* start UTC time */
  int year;                   /* years */

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

  /* Get the DATE-OBS. */

  /* Parse date to get year/month/day. */
  sprintf ( dateString, "%8.4f", gsdVars->obsUT1d );
  sscanf ( dateString, "%04d.%02d%02d", &year, &month, &day );

  /* Parse time to get hour/min/sec: can not use usual (int) scoping
     because of danger to get hh:05:60.00 instead of hh:06:00.00 */
  hour = (int) gsdVars->obsUT1h;
  min =  60.0 * fmodf( gsdVars->obsUT1h, 1.0 );
  sec =  60.0 * fmodf( 60.0*gsdVars->obsUT1h, 1.0 );

  /* Set up the timeframe. */
  tFrame = astTimeFrame ( "timescale=UT1" );

  astSet ( tFrame, "TimeOrigin=%04d-%02d-%02dT%02d:%02d:%f",
           year, month, day, hour, min, sec );

  /* Apply the UT1-UTC correction. */
  dut1 = gsdVars->obsUT1C * 86400.0;

  astSet ( tFrame, "DUT1=%f", dut1 );
  astSet ( tFrame, "timescale=UTC" );

  utcStart = astGetD ( tFrame, "timeOrigin" );

  tempFrame = astCopy ( tFrame );
  astClear ( tempFrame, "timeOrigin" );
  astSet ( tempFrame, "format(1)=iso.2" );

  tempString = astFormat ( tempFrame, 1, utcStart );

  /* Copy the UTC date string. */
  strncpy ( dateVars->dateObs, tempString, 10 );
  dateVars->dateObs[10] =  'T';
  strcpy ( &(dateVars->dateObs[11]), &(tempString[11]) );

  /* Get the OBSID. */

  /* Check to see that the backend is DAS. */
  if ( strncmp ( backend, "DAS", 3 ) != 0 &&
       strncmp ( backend, "AOSC", 4 ) != 0 ) {
    *status = SAI__ERROR;
    msgSetc ( "BACKEND", backend );
    errRep ( "gsdac_getDateVars", "Backend ^BACKEND not supported", status );
    return;
  }

  sprintf ( dateVars->obsID, "%s_%05d_%04d%02d%02dT%02d%02d%02d",
            backend, obsNum, year, month, day, hour, min, (int)sec );

  /* Convert to lowercase to give a consistent format for the JSA. */
  astChrCase( NULL, dateVars->obsID, 0, 0 );


  /* Get the DATE-END. This will be DATE-OBS + ( last LST - first LST ). */
  tableSize = gsdVars->nScanVars1 * gsdVars->nScan;
  tableDims = gsdVars->nScanVars1;
  tableElement = 0;          /* In case unfilled table */
  if ( (tableSize-tableDims) >= 0 ) {
    tableElement = tableSize-tableDims;
  }

  dLST = ( gsdVars->scanTable1[tableElement] -
	     gsdVars->scanTable1[0] ) / 24.0;

  /* Correct for difference between solar and sidereal time. */
  utcEnd = utcStart + ( dLST / SOLSID );

  tempString = astFormat ( tempFrame, 1, utcEnd );

  /* Copy the UTC date string. */
  strncpy ( dateVars->dateEnd, tempString, 10 );
  dateVars->dateEnd[10] =  'T';
  strcpy ( &(dateVars->dateEnd[11]), &(tempString[11]) );

  /* Get the LSTstart. */
  hour = (int) gsdVars->scanTable1[0];
  min =  60.0 * fmodf( gsdVars->scanTable1[0], 1.0 );
  sec =  60.0 * fmodf( 60.0*gsdVars->scanTable1[0], 1.0 );

  sprintf ( dateVars->LSTstart, "%02d:%02d:%07.4f", hour, min, sec );

  /* Get the LSTend. */
  hour = (int) gsdVars->scanTable1[tableElement];
  min =  60.0 * fmodf( gsdVars->scanTable1[tableElement], 1.0 );
  sec =  60.0 * fmodf( 60.0*gsdVars->scanTable1[tableElement], 1.0 );

  sprintf ( dateVars->LSTend, "%02d:%02d:%07.4f", hour, min, sec );

  /* Get the HSTstart and HSTend. */
  HSTstart = utcStart - 10.0 / 24.0;
  HSTend = utcEnd - 10.0 / 24.0;

  tempString = astFormat ( tempFrame, 1, HSTstart );

  /* Copy the HST date string. */
  strncpy ( dateVars->HSTstart, tempString, 10 );
  dateVars->HSTstart[10] =  'T';
  strcpy ( &(dateVars->HSTstart[11]), &(tempString[11]) );

  tempString = astFormat ( tempFrame, 1, HSTend );

  /* Copy the HST date string. */
  strncpy ( dateVars->HSTend, tempString, 10 );
  dateVars->HSTend[10] =  'T';
  strcpy ( &(dateVars->HSTend[11]), &(tempString[11]) );

}
void
smf_store_outputbounds (int updatepars, const int lbnd_out[3],
                        const int ubnd_out[3],
                        const AstFrameSet * wcsout,
                        const AstSkyFrame *oskyfrm,
                        const AstMapping * oskymap, int *status) {

  double corner[2];          /* WCS of a corner (SKY) */
  int i;                     /* loop counter */
  double glbnd_out[ 3 ];     /* double prec Lower GRID bounds for output map */
  double gubnd_out[ 3 ];     /* double prec Upper GRID bounds for output map */
  double gx_in[ 4 ];         /* X Grid coordinates of four corners */
  double gx_out[ 4 ];        /* X WCS coordinates of four corners */
  double gy_in[ 4 ];         /* Y Grid coordinates of four corners */
  double gy_out[ 4 ];        /* Y WCS coordinates of four corners */
  int ndims;                 /* Number of active dimensions */
  char tmpstr[10];           /* temporary unit string */
  double wcslbnd_out[3];     /* Array of lower bounds of output cube */
  double wcsubnd_out[3];     /* Array of upper bounds of output cube */

  /* Parameter names associated with the bounds */
  const char * bounds[] = {
    "FTR", "FTL", "FBR", "FBL", NULL
  };


  if (*status != SAI__OK) return;

/* work out how many dimensions we have */
  ndims = astGetI( wcsout, "Naxes");

/* Calculate and output the WCS bounds (matching NDFTRACE output). The bounds
   are normalised. Celestial coordinates will use radians. */
   for( i = 0; i < ndims; i++ ) {
     glbnd_out[ i ] = 0.5;
     gubnd_out[ i ] = ubnd_out[ i ] - lbnd_out[i] + 1.5;
   }

   for( i = 0; i < ndims; i++ ) {
     astMapBox( wcsout, glbnd_out, gubnd_out, 1, i+1, &(wcslbnd_out[ i ]),
                &(wcsubnd_out[ i ]), NULL, NULL );
   }

   astNorm( wcsout, wcslbnd_out );
   astNorm( wcsout, wcsubnd_out );

   /* adjust resolution of output frameset since in some cases we are interested in
      sub-arcsec resolution when comparing positions with different arguments
      (especially with RxA and using very small pixel sizes. Use digits() rather
      than format() so that we do not have to worry about hms vs dms */
   astSet( (AstFrameSet*)wcsout, "digits(1)=9,digits(2)=9" );

   if (ndims == 3) {
     msgOutif( MSG__NORM, "WCS_WBND1",
               "   Output cube WCS bounds:", status );
   } else {
     msgOutif( MSG__NORM, "WCS_WBND1",
               "   Output map WCS bounds:", status );
   }

   for( i = 0; i < ndims && *status == SAI__OK; i++ ) {
     msgSetc( "L", astFormat( wcsout, i+1, wcslbnd_out[i]));
     msgSetc( "U", astFormat( wcsout, i+1, wcsubnd_out[i]));

     if( i == 2 ) {
       sprintf( tmpstr, "unit(%d)", i+1 );
       msgSetc( "UNT", astGetC( wcsout, tmpstr ));
     } else {
       msgSetc( "UNT", "" );
     }

     sprintf( tmpstr, "label(%d)", i + 1 );
     msgSetc( "LAB", astGetC( wcsout, tmpstr ) );

     msgOutif( MSG__NORM, "WCS_WBND2",
	       "        ^LAB: ^L -> ^U ^UNT", status );
   }

   /* Return if we are not required to update the parameters */
   if (!updatepars) return;

   parPut1d( "FLBND", ndims,  wcslbnd_out, status );
   parPut1d( "FUBND", ndims,  wcsubnd_out, status );

   /* if we have a 2d frameset we can use that directly rather
      than having to split the mapping or provide explicit 2d
      versions. Since we know that MAKECUBE already calculates
      2d mappings/frames and we also know that MAKEMAP doesn't
      we provide some logic here to switch on Naxes */
   if (ndims == 2) {
     if (oskyfrm == NULL) oskyfrm = (AstSkyFrame*)wcsout;
     if (oskymap == NULL) oskymap = (AstMapping*)wcsout;
   }

/* Now also calculate the spatial coordinates of the four corners (required
   for CADC science archive. First, calculate input GRID coordinates for 4
   corners: TR, TL, BR, BL. Use pixel centres for reporting. This is
   important for cases where the pixels are very large and we want to make
   sure that we are conservative with the database reporting. */

   gx_in[ 0 ] = ubnd_out[ 0 ] - lbnd_out[ 0 ] + 1.0; /* Right */
   gx_in[ 1 ] = 1.0;                                 /* Left */
   gx_in[ 2 ] = gx_in[ 0 ];                          /* Right */
   gx_in[ 3 ] = gx_in[ 1 ];                          /* Left */
   gy_in[ 0 ] = ubnd_out[ 1 ] - lbnd_out[ 1 ] + 1.0; /* Top */
   gy_in[ 1 ] = gy_in[ 0 ];                          /* Top */
   gy_in[ 2 ] = 1.0;                                 /* Bottom */
   gy_in[ 3 ] = gy_in[ 2 ];                          /* Bottom */

   astTran2( oskymap, 4, gx_in, gy_in, 1, gx_out, gy_out );

   /* Store the bounds in the parameters */
   for (i = 0; i < 4; i++) {
     corner[ 0 ] = gx_out[ i ];
     corner[ 1 ] = gy_out[ i ];
     astNorm( oskyfrm, corner );
     parPut1d( bounds[i], 2, corner, status );
   }

}
示例#8
0
void clumpinfo( int *status ) {
    /*
    *+
    *  Name:
    *     CLUMPINFO

    *  Purpose:
    *     Obtain information about one or more previously identified clumps.

    *  Language:
    *     C

    *  Type of Module:
    *     ADAM A-task

    *  Description:
    *     This application returns various items of information about a
    *     single clump, or a collection of clumps, previously identified
    *     using FINDCLUMPS or EXTRACTCLUMPS.

    *  Usage:
    *     clumpinfo ndf clumps quiet

    *  ADAM Parameters:
    *     CLUMPS = LITERAL (Read)
    *        Specifies the indices of the clumps to be included in the
    *        returned information. It can take any of the following values:
    *
    *        - "ALL" or "*" --  All clumps.
    *
    *        - "xx,yy,zz" -- A list of clump indices.
    *
    *        - "xx:yy" --  Clump indices between xx and yy inclusively.  When
    *        xx is omitted the range begins from one; when yy is omitted the
    *        range ends with the final clump index.
    *
    *        - Any reasonable combination of above values separated by
    *        commas.
    *     FLBND( ) = _DOUBLE (Write)
    *          The lower bounds of the bounding box enclosing the selected
    *          clumps in the current WCS Frame of the input NDF. Celestial axis
    *          values are always in units of radians, but spectral axis units
    *          will be in the spectral units used by the current WCS Frame.
    *     FUBND( ) = _DOUBLE (Write)
    *          The upper bounds of the bounding box enclosing the selected
    *          clumps. See parameter FLBND for more details.
    *     LBOUND( ) = _INTEGER (Write)
    *          The lower pixel bounds of bounding box enclosing the selected
    *          clumps.
    *     NCLUMPS = _INTEGER (Write)
    *        The total number of clumps descrriptions stored within the supplied
    *        NDF.
    *     NDF = NDF (Read)
    *        The NDF defining the previously identified clumps. This
    *        should contain a CUPID extension describing all the identified
    *        clumps, in the format produced by FINDCLUMPS or EXTRACTCLUMPS.
    *     QUIET = _LOGICAL (Read)
    *        If TRUE, then no information is written out to the screen,
    *        although the output parameters are still assigned values. [FALSE]
    *     UBOUND( ) = _INTEGER (Write)
    *          The upper pixel bounds of bounding box enclosing the selected
    *          clumps.

    *  Notes:
    *     - It is hoped to extend the range of information reported by this
    *     application as new requirements arise.

    *  Synopsis:
    *     void clumpinfo( int *status );

    *  Copyright:
    *     Copyright (C) 2007 Particle Physics & Astronomy Research Council.
    *     All Rights Reserved.

    *  Licence:
    *     This program is free software; you can redistribute it and/or
    *     modify it under the terms of the GNU General Public License as
    *     published by the Free Software Foundation; either version 2 of
    *     the License, or (at your option) any later version.
    *
    *     This program is distributed in the hope that it will be
    *     useful, but WITHOUT ANY WARRANTY; without even the implied
    *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
    *     PURPOSE. See the GNU General Public License for more details.
    *
    *     You should have received a copy of the GNU General Public License
    *     along with this program; if not, write to the Free Software
    *     Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA
    *     02110-1301, USA

    *  Authors:
    *     DSB: David S. Berry
    *     {enter_new_authors_here}

    *  History:
    *     22-MAR-2007 (DSB):
    *        Original version.
    *     {enter_further_changes_here}

    *  Bugs:
    *     {note_any_bugs_here}

    *-
    */

    /* Local Variables: */
    AstFrame *cfrm;      /* Pointer to current WCS Frame */
    AstMapping *cmap;    /* Pointer to PIXEL->current Frame Mapping */
    CupidClumpInfo info; /* Structure holding returned information */
    Grp *grp = NULL;     /* GRP group holding input NDF name */
    HDSLoc *aloc = NULL; /* Locator for CLUMPS array in CUPID extension */
    HDSLoc *cloc = NULL; /* Locator for a single CLUMP structure */
    HDSLoc *xloc = NULL; /* Locator for CUPID extension */
    char *p;             /* Pointer into tmpstr string */
    char tmpstr[ 100 ];  /* Buffer for temporary strings */
    const char *dom;     /* Pointer to axis Domain name */
    double flbnd[ NDF__MXDIM ]; /* Lower bounds of WCS bounding box */
    double fubnd[ NDF__MXDIM ]; /* Upper bounds of WCS bounding box */
    double plbnd[ NDF__MXDIM ]; /* Lower bounds of PIXEL bounding box */
    double pubnd[ NDF__MXDIM ]; /* Upper bounds of PIXEL bounding box */
    int *clump_flags = NULL;  /* Flags indicating if each clump is to be used */
    int *clump_indices = NULL;/* List of indices of clumps to be used */
    int i;               /* Loop count */
    int iclump;          /* One-based clump index */
    int indf;            /* NDF identifier for input NDF */
    int ipix;            /* Index of PIXEL Frame */
    size_t nclumps;      /* No. of clump descriptions within the supplied NDF */
    int nuse;            /* Number of clumps to be used */
    int primary;         /* Value for locator primary flag */
    int quiet;           /* Supress screen output? */
    size_t size;         /* Number of values in group "*grp" */
    int there;           /* Does the enquired object exist? */

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

    /* Begin an AST context */
    astBegin;

    /* Start an NDF context */
    ndfBegin();



    /* Obtain the input NDF and get a locator for the array of clump
       descriptions within it.
       -----------------------------------------------------------------  */

    /* Get an identifier for the input NDF. We use NDG (via kpg1_Rgndf)
       instead of calling ndfAssoc directly since NDF/HDS has problems with
       file names containing spaces, which NDG does not have. */
    kpg1Rgndf( "NDF", 1, 1, "", &grp, &size, status );
    ndgNdfas( grp, 1, "READ", &indf, status );
    grpDelet( &grp, status );

    /* Check the NDF has a suitable CUPID extension containing an array of
       clump cut-outs. Get an HDS locator for the array. */
    ndfXstat( indf, "CUPID", &there, status );
    if( !there ) {
        if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "NDF", indf );
            errRep( "", "The NDF \"^NDF\" does not contain a CUPID extension "
                    "such as created by FINDCLUMPS or EXTRACTCLUMPS.", status );
        }

    } else {
        ndfXloc( indf, "CUPID", "READ", &xloc, status );
        datThere( xloc, "CLUMPS", &there, status );
        if( !there ) {
            if( *status == SAI__OK ) {
                *status = SAI__ERROR;
                ndfMsg( "NDF", indf );
                errRep( "", "The CUPID extension within NDF \"^NDF\" does not "
                        "contain an array of clumps such as created by "
                        "FINDCLUMPS or EXTRACTCLUMPS.", status );
            }

        } else {
            datFind( xloc, "CLUMPS", &aloc, status );
            primary = 1;
            datPrmry( 1, &aloc, &primary, status );

        }
        datAnnul( &xloc, status );
    }

    /* Abort if we have no clumps array locator, or if an error occurred. */
    if( !aloc || *status != SAI__OK ) goto L999;



    /* Calculate the required clump information, and store it in the "info"
       structure.
       -----------------------------------------------------------------  */

    /* Indicate that the structure holding the returned information has not
       yet been initialised. */
    info.init = 0;

    /* Get the WCS FrameSet from the input NDF, and store a pointer to it in
       the "info" structure. */
    kpg1Gtwcs( indf, &(info.iwcs), status );

    /* Get the number of clumps defined within the input NDF. */
    datSize( aloc, &nclumps, status );

    /* Get the list of clump indices to iclude in the returned information. */
    clump_flags = astMalloc( sizeof( int )*nclumps );
    clump_indices = astMalloc( sizeof( int )*nclumps );
    kpg1Gilst( 1, (int) nclumps, (int) nclumps, "CLUMPS", clump_flags, clump_indices,
               &nuse, status );

    /* Loop round all clumps that are to be used. */
    for( i = 0; i < nuse && *status == SAI__OK; i++ ) {
        iclump = clump_indices[ i ];

        /* Get a locator for this clump. */
        datCell( aloc, 1, &iclump, &cloc, status );

        /* Update the returned information to include this clump. */
        cupidClumpInfo1( cloc, &info, status );

        /* Annul the clump structure locator. */
        datAnnul( &cloc, status );

    }



    /* Write out the information to the screen and to appropriate output
       parameters.
       -----------------------------------------------------------------  */

    /* See if screen output is required. */
    parGet0l( "QUIET", &quiet, status );
    if( !quiet ) msgBlank( status );

    /* The number of clumps defined within the input NDF... */
    parPut0i( "NCLUMPS", (int) nclumps, status );
    if( ! quiet ) {
        msgSeti( "NCLUMPS", (int) nclumps );
        msgOut( "", "   Total no. of clumps: ^NCLUMPS", status );
    }

    /* Pixel index bounding box... */
    parPut1i( "LBOUND", info.npix, info.lbnd, status );
    parPut1i( "UBOUND", info.npix, info.ubnd, status );

    if( !quiet ) {
        p = tmpstr + sprintf( tmpstr, "( " );
        for( i = 0; i < info.npix; i++) {
            p += sprintf( p, "%d:%d", info.lbnd[ i ], info.ubnd[ i ] );
            if( i < info.npix - 1 ) p += sprintf( p, ", " );
        }
        p += sprintf( p, " )" );

        msgSetc( "SECTION", tmpstr );
        msgOut( "", "   Pixel index bounding box: ^SECTION", status );
    }

    /* WCS bounding box (first convert the pixel index bounding box into WCS
       coords)... */
    cfrm = astGetFrame( info.iwcs, AST__CURRENT );

    kpg1Asffr( info.iwcs, "PIXEL", &ipix, status );
    cmap = astGetMapping( info.iwcs, ipix, AST__CURRENT );

    for( i = 0; i < info.npix; i++ ) {
        plbnd[ i ] = info.lbnd[ i ] - 1.0;
        pubnd[ i ] = info.ubnd[ i ];
    }

    for( i = 0; i < info.nwcs; i++ ) {
        astMapBox( cmap, plbnd, pubnd, 1, i + 1, flbnd + i, fubnd + i,
                   NULL, NULL);
    }

    astNorm( cfrm, flbnd );
    astNorm( cfrm, fubnd );

    parPut1d( "FLBND", info.nwcs,  flbnd, status );
    parPut1d( "FUBND", info.nwcs,  fubnd, status );

    if( !quiet ) {
        msgOut( "", "   WCS bounding box:", status );

        for( i = 0; i < info.nwcs; i++) {
            msgSetc( "L", astFormat( cfrm, i + 1, flbnd[ i ] ) );
            msgSetc( "U", astFormat( cfrm, i + 1, fubnd[ i ] ) );

            sprintf( tmpstr, "Domain(%d)", i + 1 );
            dom = astGetC( cfrm, tmpstr );
            if( dom && strcmp( dom, "SKY" ) ) {
                sprintf( tmpstr, "Unit(%d)", i + 1 );
                msgSetc( "UNT", astGetC( cfrm, tmpstr ) );
            } else {
                msgSetc( "UNT", "" );
            }

            sprintf( tmpstr, "Label(%d)", i + 1 );
            msgSetc( "LAB", astGetC( cfrm, tmpstr ) );

            msgOut( "", "        ^LAB: ^L -> ^U ^UNT", status );
        }
    }

    if( !quiet ) msgBlank( status );



    /* Tidy up.
       --------      */
L999:
    ;

    /* Free resources. */
    clump_flags = astFree( clump_flags );
    clump_indices = astFree( clump_indices );
    if( aloc ) datAnnul( &aloc, status );

    /* End the NDF context */
    ndfEnd( status );

    /* End the AST context */
    astEnd;

    /* If an error has occurred, issue another error report identifying the
       program which has failed (i.e. this one). */
    if( *status != SAI__OK ) {
        errRep( "CLUMPINFO_ERR", "CLUMPINFO: Failed to obtain information "
                "about one or more previously identified clumps.", status );
    }

}
示例#9
0
void smf_get_projpar( AstSkyFrame *skyframe, const double skyref[2],
                      int moving, int autogrid, int nallpos,
                      const double * allpos, float telres, double map_pa,
                      double par[7], int * issparse,int *usedefs, int *status ) {

/* Local Variables */
   char reflat[ 41 ];    /* Reference latitude string */
   char reflon[ 41 ];    /* Reference longitude string */
   char usesys[ 41 ];    /* Output skyframe system */
   const char *deflat;   /* Default for REFLAT */
   const char *deflon;   /* Default for REFLON */
   const double fbpixsize = 6.0; /* Fallback pixel size if we have no other information */
   double autorot;       /* Autogrid default for CROTA parameter */
   double defsize[ 2 ];  /* Default pixel sizes in arc-seconds */
   double pixsize[ 2 ];  /* Pixel sizes in arc-seconds */
   double refpix[ 2 ];   /* New REFPIX values */
   double rdiam;         /* Diameter of bounding circle, in rads */
   int coin;             /* Are all points effectively co-incident? */
   int i;
   int nval;             /* Number of values supplied */
   int refine_crpix;     /* Should the pixel ref position be updated? */
   int sparse = 0;       /* Local definition of sparseness */
   int udefs = 0;        /* Flag for defaults used or not */

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

/* If the number of supplied positions is 0 or null pointer,
   disable autogrid */
   if( nallpos == 0 || !allpos ) autogrid = 0;

/* Get the output system */
   one_strlcpy( usesys, astGetC( skyframe, "SYSTEM"), sizeof(usesys),
                status );

/* Ensure the reference position in the returned SkyFrame is set to the
   first telescope base pointing position. */
   astSetD( skyframe, "SkyRef(1)", skyref[ 0 ] );
   astSetD( skyframe, "SkyRef(2)", skyref[ 1 ] );

/* If the target is moving, ensure the returned SkyFrame represents
   offsets from the first telescope base pointing position rather than
   absolute coords. */
   if( moving ) smf_set_moving( (AstFrame *) skyframe, NULL, status );

/* Set a flag indicating if all the points are co-incident. */
   coin = 0;

/* Set the sky axis values at the tangent point. If the target is moving,
   the tangent point is at (0,0) (i.e. it is at the origin of the offset
   coordinate system). If the target is not moving, the tangent point is
   at the position held in "skyref". */
   if( par ) {
      if( moving ){
         par[ 2 ] = 0.0;
         par[ 3 ] = 0.0;
      } else {
         par[ 2 ] = skyref[ 0 ];
         par[ 3 ] = skyref[ 1 ];
      }

/* If required, calculate the optimal projection parameters. If the target
   is moving, these refer to the offset coordinate system centred on the
   first time slice base pointing position, with north defined by the
   requested output coordinate system. The values found here are used as
   dynamic defaults for the environment parameter */
      if( autogrid ) {
         kpg1Opgrd( nallpos, allpos, strcmp( usesys, "AZEL" ), par, &rdiam,
                          status );

/* See if all the points are effectively co-incident (i.e. within an Airy
   disk). If so, we use default grid parameters that result in a grid of
   1x1 spatial pixels. The grid pixel sizes (par[4] and par[5]) are made
   larger than the area covered by the points in order to avoid points
   spanning two pixels. */
         if( rdiam < telres || nallpos < 3 ) {
            if( rdiam < 0.1*AST__DD2R/3600.0 ) rdiam = 0.1*AST__DD2R/3600.0;
            par[ 0 ] = 0.0;
            par[ 1 ] = 0.0;
            par[ 4 ] = -rdiam*4;
            par[ 5 ] = -par[ 4 ];
            par[ 6 ] = 0.0;

            coin = 1;

/* If the sky positions are not co-incident, and the automatic grid
   determination failed, we cannot use a grid, so warn the user. */
         } else if( par[ 0 ] == AST__BAD ) {
            msgOutif( MSG__NORM, " ", "   Automatic grid determination "
                           "failed: the detector samples do not form a "
                           "regular grid.", status );
         }
      }

/* If autogrid values were not found, use the following fixed default
   values. Do not override extenal defaults for pixel size. */
      if( !autogrid || ( autogrid && par[ 0 ] == AST__BAD ) ) {
         par[ 0 ] = 0.0;
         par[ 1 ] = 0.0;
         if (par[4] == AST__BAD || par[5] == AST__BAD ) {
           par[ 4 ] = (fbpixsize/3600.0)*AST__DD2R;
           par[ 5 ] = (fbpixsize/3600.0)*AST__DD2R;
         }
         par[ 6 ] = map_pa;
      }

/* Ensure the default pixel sizes have the correct signs. */
      if( par[ 4 ] != AST__BAD ) {
         if( !strcmp( usesys, "AZEL" ) ) {
            par[ 4 ] = fabs( par[ 4 ] );
         } else {
            par[ 4 ] = -fabs( par[ 4 ] );
         }
         par[ 5 ] = fabs( par[ 5 ] );
      }

/* See if the output cube is to include a spatial projection, or a sparse
   list of spectra. Disabled if the sparse pointer is NULL. */
      if (issparse) {
        parDef0l( "SPARSE", ( par[ 0 ] == AST__BAD ), status );
        parGet0l( "SPARSE",  &sparse, status );

      }

/* If we are producing an output cube with the XY plane being a spatial
   projection, then get the parameters describing the projection, using the
   defaults calculated above. */
      if( !sparse && *status == SAI__OK ) {
         const int ndigits = 8; /* Number of digits for deflat/deflon precision */

/* If the target is moving, display the tracking centre coordinates for
   the first time slice. */
         if( moving ) {
            astClear( skyframe, "SkyRefIs" );
            msgBlank( status );
            msgSetc( "S1", astGetC( skyframe, "Symbol(1)" ) );
            msgSetc( "S2", astGetC( skyframe, "Symbol(2)" ) );
            msgOutif( MSG__NORM, " ", "   Output sky coordinates are "
                           "(^S1,^S2) offsets from the (moving)", status );
            msgSetc( "S1", astGetC( skyframe, "Symbol(1)" ) );
            msgSetc( "S2", astGetC( skyframe, "Symbol(2)" ) );
            msgSetc( "SREF", astGetC( skyframe, "SkyRef" ) );
            msgOutif( MSG__NORM, " ", "   telescope base position, which "
                           "started at (^S1,^S2) = (^SREF).", status );
            astSet( skyframe, "SkyRefIs=Origin" );
         }

/* Set up a flag indicating that the default values calculated by autogrid
   are being used. */
         udefs = 1;

/* Ensure we have usable CRPIX1/2 values */
         if( par[ 0 ] == AST__BAD ) par[ 0 ] = 1.0;
         if( par[ 1 ] == AST__BAD ) par[ 1 ] = 1.0;

/* Get the crpix1/2 (in the interim GRID frame) to use. Note if the user
   specifies any values. These parameters have vpath=default (which is null)
   and ppath=dynamic. */
         refine_crpix = 0;
         parDef0d( "REFPIX1", par[ 0 ], status );
         parDef0d( "REFPIX2", par[ 1 ], status );
         if( *status == SAI__OK ) {
            parGet0d( "REFPIX1", refpix + 0, status );
            parGet0d( "REFPIX2", refpix + 1, status );
            if( *status == PAR__NULL ) {
               errAnnul( status );
               refine_crpix = 1;
            } else {
               par[ 0 ] = refpix[ 0 ];
               par[ 1 ] = refpix[ 1 ];
            }
         }

/* Get the sky coords reference position strings. Use the returned SkyFrame
   to format and unformat them. */
         if( par[ 2 ] != AST__BAD ) {
            int curdigits;
            curdigits = astGetI( skyframe, "digits(1)" );
            astSetI( skyframe, "digits(1)", ndigits );
            deflon = astFormat( skyframe, 1, par[ 2 ] );
            astSetI( skyframe, "digits(1)", curdigits );
            parDef0c( "REFLON", deflon, status );
         } else {
            deflon = NULL;
         }

         if( par[ 3 ] != AST__BAD ) {
            int curdigits;
            curdigits = astGetI( skyframe, "digits(2)" );
            astSetI( skyframe, "digits(2)", ndigits );
            deflat = astFormat( skyframe, 2, par[ 3 ] );
            astSetI( skyframe, "digits(2)", curdigits );
            parDef0c( "REFLAT", deflat, status );
         } else {
            deflat = NULL;
         }

         parGet0c( "REFLON", reflon, 40, status );
         parGet0c( "REFLAT", reflat, 40, status );

         if( *status == SAI__OK ) {

            if( ( deflat && strcmp( deflat, reflat ) ) ||
                  ( deflon && strcmp( deflon, reflon ) ) ) udefs = 0;

            if( astUnformat( skyframe, 1, reflon, par + 2 ) == 0 && *status == SAI__OK ) {
               msgSetc( "REFLON", reflon );
               errRep( "", "Bad value supplied for REFLON: '^REFLON'", status );
            }

            if( astUnformat( skyframe, 2, reflat, par + 3 ) == 0 && *status == SAI__OK ) {
               msgSetc( "REFLAT", reflat );
               errRep( "", "Bad value supplied for REFLAT: '^REFLAT'", status );
            }

/* Ensure the reference position in the returned SkyFrame is set to the
   supplied position (which defaults to the first telescope base pointing
   position). */
            if( !moving ){
               astSetD( skyframe, "SkyRef(1)", par[ 2 ] );
               astSetD( skyframe, "SkyRef(2)", par[ 3 ] );
            }
         }

/* Get the user defined spatial pixel size in arcsec (the calibration for
   the spectral axis is fixed by the first input data file - see
   smf_cubebounds.c). First convert the autogrid values form rads to arcsec
   and establish them as the dynamic default for "PIXSIZE". */
         nval = 0;
         if( par[ 4 ] != AST__BAD || par[ 5 ] != AST__BAD ) {
           for ( i = 4; i <= 5; i++ ) {
             if ( par[ i ] != AST__BAD ) {
               defsize[ nval ] = 0.1*NINT( fabs( par[ i ] )*AST__DR2D*36000.0 );
               nval++;
             }
           }
           /* set the dynamic default, handling case where both dimensions
              have same default. */
           if (nval == 1) {
             defsize[1] = defsize[0];
           } else if (nval == 2 && defsize[0] == defsize[1]) {
             nval = 1;
           }
           parDef1d( "PIXSIZE", nval, defsize, status );

         } else {
           /* pick a default in case something odd happens and we have
              no other values*/
           defsize[ 0 ] = fbpixsize;
           defsize[ 1 ] = defsize[ 0 ];
           nval = 2;
         }
         if (*status == SAI__OK) {
           pixsize[0] = AST__BAD;
           pixsize[1] = AST__BAD;
           parGet1d( "PIXSIZE", 2, pixsize, &nval, status );
           if (*status == PAR__NULL) {
             /* Null just defaults to what we had before */
             errAnnul( status );
             pixsize[0] = defsize[0];
             pixsize[1] = defsize[1];
             nval = 2;
           }
         }

/* If OK, duplicate the first value if only one value was supplied. */
         if( *status == SAI__OK ) {
            if( nval < 2 ) pixsize[ 1 ] = pixsize[ 0 ];

            if( defsize[ 0 ] != pixsize[ 0 ] ||
                  defsize[ 1 ] != pixsize[ 1 ] ) udefs = 0;

/* Check the values are OK. */
            if( pixsize[ 0 ] <= 0 || pixsize[ 1 ] <= 0 ) {
               msgSetd( "P1", pixsize[ 0 ] );
               msgSetd( "P2", pixsize[ 1 ] );
               *status = SAI__ERROR;
               errRep( FUNC_NAME, "Invalid pixel sizes (^P1,^P2).", status);
            }

/* Convert to rads, and set the correct signs. */
            if( par[ 4 ] == AST__BAD || par[ 4 ] < 0.0 ) {
               par[ 4 ] = -pixsize[ 0 ]*AST__DD2R/3600.0;
            } else {
               par[ 4 ] = pixsize[ 0 ]*AST__DD2R/3600.0;
            }

            if( par[ 5 ] == AST__BAD || par[ 5 ] < 0.0 ) {
               par[ 5 ] = -pixsize[ 1 ]*AST__DD2R/3600.0;
            } else {
               par[ 5 ] = pixsize[ 1 ]*AST__DD2R/3600.0;
            }

         }

/* Convert the autogrid CROTA value from rads to degs and set as the
   dynamic default for parameter CROTA (the position angle of the output
   Y axis, in degrees). The get the CROTA value and convert to rads. */
         if( par[ 6 ] != AST__BAD ) {
            autorot = par[ 6 ]*AST__DR2D;
            parDef0d( "CROTA", autorot, status );

         } else {
            parDef0d( "CROTA", map_pa*AST__DR2D, status );
            autorot = AST__BAD;
         }

         parGet0d( "CROTA", par + 6, status );
         if( par[ 6 ] != autorot ) udefs = 0;
         par[ 6 ] *= AST__DD2R;

/* If any parameter were given explicit values which differ from the
   autogrid default values, then we need to re-calculate the optimal CRPIX1/2
   values. We also do this if all the points are effectively co-incident. */
         if( ( coin || !udefs ) && autogrid && refine_crpix ) {
            par[ 0 ] = AST__BAD;
            par[ 1 ] = AST__BAD;
            kpg1Opgrd( nallpos, allpos, strcmp( usesys, "AZEL" ), par,
                       &rdiam, status );
         }

/* Display the projection parameters being used. */
         smf_display_projpars( skyframe, par, status );

/* Write out the reference grid coords to output parameter PIXREF. */
         parPut1d( "PIXREF", 2, par, status );

/* If no grid was found, indicate that no spatial projection will be used. */
      } else {
         msgBlank( status );
         msgOutif( MSG__NORM, " ", "   The output will be a sparse array "
                        "containing a list of spectra.", status );
      }

/* If we have a pre-defined spatial projection, indicate that the output
   array need not be sparse. */
   } else {
      sparse = 0;
   }

/* Return usedefs if requested */
   if( usedefs ) {
     *usedefs = udefs;
   }

/* Set sparse if requested */
   if( issparse ) *issparse = sparse;

}