예제 #1
0
void smf_write_flagmap( ThrWorkForce *wf, smf_qual_t mask, smfArray *lut, smfArray *qua,
                        smfDIMMData *dat, const Grp *flagrootgrp,
                        size_t contchunk, const int *lbnd_out,
                        const int *ubnd_out, AstFrameSet *outfset,
                        int *status ) {

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

  if( *status != SAI__OK ) return;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     /* Next quality bit. */
     }

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

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

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

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

     tfset = astAnnul( tfset );
  }

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

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

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

  if( *status != SAI__OK ) return;

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

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

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

  pname = tmpname;
  grpGet( iterrootgrp, 1, 1, &pname, sizeof(tmpname), status );
  one_strlcpy( name, tmpname, sizeof(name), status );
  one_strlcat( name, ".", sizeof(name), status );

  /* Continuous chunk number */
  sprintf(tempstr, "CH%02zd", contchunk);
  one_strlcat( name, tempstr, sizeof(name), status );

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

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

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

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

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

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

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

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

    ntslice = hdr->nframes;

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

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

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

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

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

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

  /* Clean up */
  if( mgrp ) grpDelet( &mgrp, status );
  smf_close_file( wf, &imapdata, status );
}
예제 #3
0
void smf_subip(  ThrWorkForce *wf, smfArray *res, smfArray *lut, int *lbnd_out,
                 int *ubnd_out, AstKeyMap *keymap, AstFrameSet *outfs, int *status ) {

/* Local Variables: */
   HDSLoc *loc = NULL;
   HDSLoc *sloc = NULL;
   SmfSubIPData *job_data = NULL;
   SmfSubIPData *pdata;
   char ipref[200];
   char subname[10];
   const char *ipdata;
   const char *qu;
   dim_t bolostep;
   dim_t nbolo;
   dim_t ntslice;
   double *angcdata;
   double *c0data;
   double *imapdata;
   double *ipang;
   double *p0data;
   double *p1data;
   int angcndf;
   int c0ndf;
   int imapndf;
   int iw;
   int nmap;
   int nw;
   int p0ndf;
   int p1ndf;
   size_t bstride;
   size_t idx;
   size_t tstride;
   smfData *data;
   smf_qual_t *qua_data;

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

/* Check if we have pol2 data, and see if it is Q or U. */
   qu = NULL;
   for( idx = 0; idx < res->ndat; idx++ ) {
      data = res->sdata[idx];

      if( !strcmp( data->hdr->dlabel, "Q" ) ){
         if( !qu ) {
            qu = "Q";
         } else if( strcmp( qu, "Q" ) ) {
            *status = SAI__ERROR;
            break;
         }

      } else if( !strcmp( data->hdr->dlabel, "U" ) ) {
         if( !qu ) {
            qu = "U";
         } else if( strcmp( qu, "U" ) ) {
            *status = SAI__ERROR;
            break;
         }

      } else if( qu ) {
         *status = SAI__ERROR;
         qu = NULL;
         break;
      }
   }

/* Report an error if there is a mix of pol2 and non-pol2, or a mix of Q
   and U. */
   if( *status != SAI__OK ) {
      if( qu ) {
         errRep( "", "smf_subip: Input data contains mix of Q and U "
                 "data", status );
      } else {
         errRep( "", "smf_subip: Input data contains mix of POL2 and "
                 "non-POL2 data", status );
      }

/* If we have pol2 data, get the path to the total intensity image that
   is to be used to define the level of IP correction required. If no
   value is supplied, annul the error and set "qu" NULL to indicate we should
   leave immediately. */
   } else if( qu && *status == SAI__OK ) {
      parGet0c( "IPREF", ipref, sizeof(ipref), status );
      if( *status == PAR__NULL ) {
         errAnnul( status );
         qu = NULL;
      }
   }

/* If we are applying IP correction... */
   if( qu && *status == SAI__OK ) {
      msgOutf( "", "smf_subip: applying instrumental polarisation %s "
               "correction based on total intensity map `%s'", status,
               qu, ipref );

/* Get an identifier for the IPREF NDF. */
      ndfFind( NULL, ipref, &imapndf, status );

/* Resample the NDFs data values onto the output map grid. */
      imapdata = smf_alignndf( imapndf, outfs, lbnd_out, ubnd_out,
                               status );

/* Annul the NDF identifier. */
      ndfAnnul( &imapndf, status );

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

/* Get the path to the container file holding the IP model parameters. */
      ipdata = "$STARLINK_DIR/share/smurf/ipdata.sdf";
      astMapGet0C( keymap, "IPDATA", &ipdata );

/* Open the container file. */
      hdsOpen( ipdata, "READ", &loc, status );

/* Do the IP correction for each subarray (s8a, s8b, etc) in turn. */
      for( idx = 0; idx < res->ndat && *status == SAI__OK; idx++ ) {
         data = res->sdata[idx];

/* Get an array holding the angle (rad.s) from north to focal plane Y,
   measured positive in the sense of rotation from focal plane Y to focal
   plane X, for every bolometer sample in the smfData. The values are bolo
   ordered so that "bstride" is 1 and "tstsride" is nbolo. */
         ipang = smf1_calcang( data, status );

/* Get the number of bolometers and time slices for the current subarray,
   together with the strides between adjacent bolometers and adjacent
   time slices. */
         smf_get_dims( data,  NULL, NULL, &nbolo, &ntslice, NULL, &bstride,
                       &tstride, status );

/* Get a locator for the structure holding the IP parameters for the
   current subarray */
         smf_find_subarray( data->hdr, subname, sizeof( subname ), NULL,
                            status );
         datFind( loc, subname, &sloc, status );

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

/* Get identifiers for the NDFs holding the individual parameters. Each
   NDF holds a parameter value for each bolometer. */
         ndfFind( sloc, "P0", &p0ndf, status );
         ndfFind( sloc, "P1", &p1ndf, status );
         ndfFind( sloc, "C0", &c0ndf, status );
         ndfFind( sloc, "ANGC", &angcndf, status );

/* Map them. Check each one has the expected number of elements. */
         ndfMap( p0ndf, "DATA", "_DOUBLE", "READ", (void **) &p0data,
                 &nmap, status );
         if( nmap != (int) nbolo && *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "N", p0ndf );
            errRep( "", "smf_subip: Bad dimensions for ^N - should be 32x40.", status );
         }

         ndfMap( p1ndf, "DATA", "_DOUBLE", "READ", (void **) &p1data,
                 &nmap, status );
         if( nmap != (int) nbolo && *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "N", p1ndf );
            errRep( "", "smf_subip: Bad dimensions for ^N - should be 32x40.", status );
         }

         ndfMap( c0ndf, "DATA", "_DOUBLE", "READ", (void **) &c0data,
                 &nmap, status );
         if( nmap != (int) nbolo && *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "N", c0ndf );
            errRep( "", "smf_subip: Bad dimensions for ^N - should be 32x40.", status );
         }

         ndfMap( angcndf, "DATA", "_DOUBLE", "READ", (void **) &angcdata,
                 &nmap, status );
         if( nmap != (int) nbolo && *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "N", angcndf );
            errRep( "", "smf_subip: Bad dimensions for ^N - should be 32x40.", status );
         }

/* Get a pointer to the quality array for the residuals. */
         qua_data = smf_select_qualpntr( data, NULL, status );

/* See how many bolometers to process in each thread. */
         bolostep = nbolo/nw;
         if( bolostep == 0 ) bolostep = 1;

/* Create jobs to apply the IP correction to a range of bolometers. */
         for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;

/* Set the range of bolometers (b1 to b2) to be processed by the current
   job. */
            pdata->b1 = iw*bolostep;
            if( iw < nw - 1 ) {
               pdata->b2 = pdata->b1 + bolostep - 1;
            } else {
               pdata->b2 = nbolo - 1 ;
            }

/* Store the other info needed by the worker thread. */
            pdata->ntslice = ntslice;
            pdata->nbolo = nbolo;
            pdata->res_data = res->sdata[idx]->pntr[0];
            pdata->lut_data = lut->sdata[idx]->pntr[0];
            pdata->qua_data = qua_data;
            pdata->ipang = ipang;
            pdata->bstride = bstride;
            pdata->tstride = tstride;
            pdata->imapdata = imapdata;
            pdata->qu = qu;
            pdata->p0data = p0data;
            pdata->p1data = p1data;
            pdata->c0data = c0data;
            pdata->angcdata = angcdata;
            pdata->allstate = data->hdr->allState;

/* Submit the job for execution by the next available thread. */
            thrAddJob( wf, 0, pdata, smf1_subip, 0, NULL, status );
         }

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

/* End the NDF context, thus unmapping and freeing all NDF identifiers
   created since the context was started. */
         ndfEnd( status );

/* Free locator for subarray IP parameters. */
         datAnnul( &sloc, status );
         ipang = astFree( ipang );
      }

/* Free resources. */
      datAnnul( &loc, status );
      imapdata = astFree( imapdata );
      job_data = astFree( job_data );
   }
}
예제 #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
void smf_write_bolomap( ThrWorkForce *wf, smfArray *res, smfArray *lut,
                        smfArray *qua, smfDIMMData *dat, dim_t msize,
                        const Grp *bolrootgrp, int varmapmethod,
                        const int *lbnd_out, const int *ubnd_out,
                        AstFrameSet *outfset, int *status ) {

  int addtomap=0;               /* Set if adding to existing map */
  size_t bstride;               /* Bolometer stride */
  double *curmap=NULL;          /* Pointer to current map being rebinned */
  double *curvar=NULL;          /* Pointer to variance associate with curmap */
  dim_t dsize;                  /* Size of data arrays in containers */
  size_t idx=0;                 /* index within subgroup */
  size_t k;                     /* loop counter */
  int *lut_data=NULL;           /* Pointer to DATA component of lut */
  char name[GRP__SZNAM+1];      /* Buffer for storing names */
  dim_t nbolo;                  /* Number of bolometers */
  size_t nbolomaps = 0;         /* Number of bolomaps written */
  char *pname=NULL;             /* Poiner to name */
  smf_qual_t *qua_data=NULL;    /* Pointer to DATA component of qua */
  double *res_data=NULL;        /* Pointer to DATA component of res */

  if( *status != SAI__OK ) return;

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

  /* Loop over subgroup index (subarray) */
  for( idx=0; idx<res->ndat; idx++ ) {
    smf_qual_t *bolomask = NULL;
    double *bmapweight = NULL;
    double *bmapweightsq = NULL;
    int *bhitsmap = NULL;

    /* Pointers to everything we need */
    res_data = res->sdata[idx]->pntr[0];
    lut_data = lut->sdata[idx]->pntr[0];
    qua_data = qua->sdata[idx]->pntr[0];

    smf_get_dims( res->sdata[idx], NULL, NULL, &nbolo, NULL,
                  &dsize, &bstride, NULL, status );

    /* Make a copy of the quality at first time slice as a good
       bolo mask, and then set quality to SMF__Q_BADB. Later we
       will unset BADB for one bolo at a time to make individual
       maps. */

    bolomask = astMalloc( nbolo*sizeof(*bolomask) );
    bmapweight = astMalloc( msize*sizeof(*bmapweight) );
    bmapweightsq = astMalloc( msize*sizeof(*bmapweightsq) );
    bhitsmap = astMalloc( msize*sizeof(*bhitsmap) );

    if( *status == SAI__OK ) {
      for( k=0; k<nbolo; k++ ) {
        bolomask[k] = qua_data[k*bstride];
        qua_data[k*bstride] = SMF__Q_BADB;
      }

      /* Identify good bolos in the copied mask and produce a map */
      for( k=0; (k<nbolo)&&(*status==SAI__OK); k++ ) {
        if( !(bolomask[k]&SMF__Q_BADB) ) {
          Grp *mgrp=NULL;       /* Temporary group to hold map names */
          smfData *mapdata=NULL;/* smfData for new map */
          char tmpname[GRP__SZNAM+1]; /* temp name buffer */
          char thisbol[20];     /* name particular to this bolometer */
          size_t col, row;
          char subarray[10];

          nbolomaps++;

          /* Set the quality back to good for this single bolometer */
          qua_data[k*bstride] = bolomask[k];

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

          /* Subarray, column and row. HDS does not care about case but we
             convert to upper case anyhow. */
          smf_find_subarray( res->sdata[idx]->hdr, subarray, sizeof(subarray),
                             NULL, status );
          if (*status == SAI__OK) {
            size_t len = strlen(subarray);
            size_t n = 0;
            for (n=0; n<len; n++) {
              subarray[n] = toupper(subarray[n]);
            }
          }

          col = (k % res->sdata[idx]->dims[1])+1;
          row = (k / res->sdata[idx]->dims[1])+1;

          sprintf( thisbol, "%3sC%02zuR%02zu",
                   subarray,
                   col,   /* x-coord */
                   row ); /* y-coord */

          one_strlcat( name, thisbol, sizeof(name), status );
          mgrp = grpNew( "bolomap", status );
          grpPut1( mgrp, name, 0, status );

          msgOutf( "", "*** Writing single bolo map %s", status,
                   name );

          /* Try to open an existing extention first. Create a new map
             array, and then later we'll add it to the existing
             one. If it isn't there, create it. */

          smf_open_file( mgrp, 1, "UPDATE", 0, &mapdata, status );

          if( *status == SAI__OK ) {
            /* Allocate memory for the new rebinned data */
            curmap = astCalloc( msize, sizeof(*curmap) );
            curvar = astCalloc( msize, sizeof(*curvar) );
            addtomap = 1;
          } else if( *status == DAT__NAMIN ) {
            /* Create a new extension */
            errAnnul( status );
            smf_open_newfile ( mgrp, 1, SMF__DOUBLE, 2, lbnd_out,
                               ubnd_out, SMF__MAP_VAR, &mapdata, status);

            /* Rebin directly into the newly mapped space */
            if( *status == SAI__OK ) {
              curmap = mapdata->pntr[0];
              curvar = mapdata->pntr[1];
              addtomap = 0;
            }
          }

          /* Rebin the data for this single bolometer. Don't care
             about variance weighting because all samples from
             same detector are about the same. */

          smf_rebinmap1( wf, res->sdata[idx],
                         dat->noi ? dat->noi[0]->sdata[idx] : NULL,
                         lut_data, 0, 0, 0, NULL, 0,
                         SMF__Q_GOOD, varmapmethod,
                         AST__REBININIT | AST__REBINEND,
                         curmap, bmapweight, bmapweightsq, bhitsmap,
                         curvar, msize, NULL, status );

          /* If required, add this new map to the existing one */
          if( addtomap ) {
            size_t i;
            double *oldmap=NULL;
            double *oldvar=NULL;
            double weight;

            if( *status == SAI__OK ) {

              oldmap = mapdata->pntr[0];
              oldvar = mapdata->pntr[1];

              for( i=0; i<msize; i++ ) {
                if( oldmap[i]==VAL__BADD ) {
                  /* No data in this pixel in the old map, just copy */
                  oldmap[i] = curmap[i];
                  oldvar[i] = curvar[i];
                } else if( curmap[i]!=VAL__BADD &&
                           oldvar[i]!=VAL__BADD && oldvar[i]!=0 &&
                           curvar[i]!=VAL__BADD && curvar[i]!=0 ) {
                  /* Both old and new values available */
                  weight = 1/oldvar[i] + 1/curvar[i];
                  oldmap[i] = (oldmap[i]/oldvar[i] + curmap[i]/curvar[i]) /
                    weight;
                  oldvar[i] = 1/weight;
                }
              }
            }

            /* Free up temporary arrays */
            curmap = astFree( curmap );
            curvar = astFree( curvar );
          }

          /* Write out COLNUM and ROWNUM to FITS header */
          if( *status == SAI__OK ) {
            AstFitsChan *fitschan=NULL;

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

            atlPtfti( fitschan, "COLNUM", col, "bolometer column", status);
            atlPtfti( fitschan, "ROWNUM", row, "bolometer row", status );
            atlPtfts( fitschan, "SUBARRAY", subarray, "Subarray identifier",
                      status );
            kpgPtfts( mapdata->file->ndfid, fitschan, status );

            if( fitschan ) fitschan = astAnnul( fitschan );


            /* Set the bolo to bad quality again */
            qua_data[k*bstride] = SMF__Q_BADB;

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

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

        }
      }

      /* Set quality back to its original state */
      for( k=0; k<nbolo; k++ ) {
        qua_data[k*bstride] = bolomask[k];
      }
    }

    /* Free up memory */
    bolomask = astFree( bolomask );
    bmapweight = astFree( bmapweight );
    bmapweightsq = astFree( bmapweightsq );
    bhitsmap = astFree( bhitsmap );
  }

  msgOutf( "", "*** Wrote %zu bolo maps", status, nbolomaps );

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

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

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

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

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

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

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

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

  astBegin;

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

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

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

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

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

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

        }
      }
    }

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

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

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

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

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

      switch( hdr->instrument ) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

          if (skyin) skyin = astAnnul( skyin );

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

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

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

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

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

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

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

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

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

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

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

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

        } /* End WCS FrameSet construction */
      }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        }
      }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  refsys = astFree( refsys );

  astEnd;

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

/* Local Variables */
   AstFitsChan *fc = NULL;
   AstFrameSet *fs = NULL;
   AstObject *obj;
   AstRegion *region;
   Grp *igrp = NULL;
   Grp *sgrp = NULL;
   double vertex_data[ 2*MAXVERT ];
   int *tiles = NULL;
   int i;
   int indf;
   int lbnd[2];
   int ntile;
   int nvert_dec;
   int nvert_ra;
   int ubnd[2];
   size_t size;
   size_t ssize;
   smfJSATiling tiling;

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

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

/* Attempt to to get an AST Region. */
   kpg1Gtobj( "IN", "Region",
              (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion),
              &obj, status );
   region = (AstRegion *) obj;

/* If successful, attempt to access the IN parameter as an NDF. If this
   works, we may be able to determine the instrument by looking at its
   FITS extension. */
   if( *status == SAI__OK && region ) {
      ndfExist( "IN", "Read", &indf, status );

/* If we got an NDF, get a FitsChan holding the contents of its FITS
   extension. Annul the error if the NDF has no FITS extension. */
      if( indf != NDF__NOID ) {
         kpgGtfts( indf, &fc, status );
         if( *status == KPG__NOFTS ) {
            errAnnul( status );
            fc = NULL;
         }
         ndfAnnul( &indf, status );
      }

/* Select a JSA instrument and get the parameters defining the layout of
   tiles for the selected instrument. */
      smf_jsainstrument( "INSTRUMENT", fc, SMF__INST_NONE, &tiling,
                         status );

/* Get the list of identifiers for tiles that overlap the region. */
      tiles = smf_jsatiles_region( region, &tiling, &ntile, status );

/* If a null value was supplied for IN, attempt to get the positions of
   vertices on the sky to define the region. */
   } else if( *status == PAR__NULL ) {
      errAnnul( status );
      parGet1d( "VERTEX_RA", MAXVERT, vertex_data, &nvert_ra, status );
      parGet1d( "VERTEX_DEC", MAXVERT, vertex_data + MAXVERT, &nvert_dec,
                 status );
      if( nvert_ra != nvert_dec && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( "", "Differing numbers of RA (%d) and Dec (%d) vertex values "
                 "supplied.", status, nvert_ra, nvert_dec );
      }

/* Convert from degrees to radians. */
      for( i = 0; i < nvert_ra; i++ ) {
         vertex_data[ i ] *= AST__DD2R;
         vertex_data[ MAXVERT + i ] *= AST__DD2R;
      }

/* Select a JSA instrument and get the parameters defining the layout of
   tiles for the selected instrument. */
      smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &tiling,
                         status );

/* Create a frame in which to define the region - we arbitrarily use tile 1. */
      smf_jsatile( 1, &tiling, 0, NULL, &fs, NULL, lbnd, ubnd, status );

/* Create the region. */
      region = (AstRegion *) astPolygon( fs, nvert_ra, MAXVERT, vertex_data, NULL, " " );

/* If the region is unbounded, it is probably because the vertices were
   given in the wrong order. Invert the Polyfon to correct this. */
      if( !astGetI( region, "bounded" ) ) astNegate( region );

/* Get the list of identifiers for tiles that overlap the region. */
      tiles = smf_jsatiles_region( region, &tiling, &ntile, status );
   }

/* If the IN parameter could not be accessed as a Region, annull any error
   and get a group of input data files. */
   if( !region || *status == SAI__ERROR ) {
      if( *status != SAI__OK ) errAnnul( status );
      kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );

/* Get a group containing just the files holding science data. */
      smf_find_science( NULL, igrp, &sgrp, 0, NULL, NULL, 1, 1, SMF__NULL, NULL,
                        NULL, NULL, NULL, status );

/* Check we have at least once science file. */
      ssize = grpGrpsz( sgrp, status );
      if( ssize == 0 ) {
         msgOutif( MSG__NORM, " ", "None of the supplied input frames were SCIENCE.",
                   status );

/* Get the list of identifiers for tiles that receive any data. */
      } else {
         tiles = smf_jsatiles_data( sgrp, ssize, &tiling, &ntile, status );
      }

/* Delete the groups. */
      if( igrp ) grpDelet( &igrp, status);
      if( sgrp ) grpDelet( &sgrp, status);
   }

/* Sort the list of overlapping tiles into ascending order. */
   if( *status == SAI__OK ) {
      qsort( tiles, ntile, sizeof( *tiles ), jsatilelist_icomp );

/* Display the list of overlapping tiles. */
      msgBlank( status );
      msgOutf( "", "   %s tiles touched by supplied data:", status,
               tiling.name );
      msgBlank( status );
      for( i = 0; i < ntile; i++ ) {
         msgSeti( "I", tiles[ i ] );
         msgOut( "", "   ^I", status );
      }
      msgBlank( status );

/* Write out the list of overlapping tiles to the output parameter. */
      parPut1i( "TILES", ntile, tiles, status );
   }

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

/* End the AST context. */
   astEnd;

/* Issue a status indication.*/
   msgBlank( status );
   if( *status == SAI__OK ) {
      msgOutif( MSG__VERB, "", "JSATILELIST succeeded.", status);
   } else {
      msgOutif( MSG__VERB, "", "JSATILELIST failed.", status);
   }
}
예제 #8
0
void smf_write_shortmap( ThrWorkForce *wf, int shortmap, smfArray *res,
                         smfArray *lut, smfArray *qua, smfDIMMData *dat,
                         dim_t msize, const Grp *shortrootgrp, size_t contchunk,
                         int varmapmethod, const int *lbnd_out,
                         const int *ubnd_out, AstFrameSet *outfset,
                         int *status ) {

  dim_t dsize;                  /* Size of data arrays in containers */
  size_t i;                     /* loop counter */
  size_t idx=0;                 /* index within subgroup */
  size_t istart;                /* First useful timeslice */
  size_t iend;                  /* Last useful timeslice */
  int *lut_data=NULL;           /* Pointer to DATA component of lut */
  char name[GRP__SZNAM+1];      /* Buffer for storing names */
  size_t nshort=0;              /* Number of short maps */
  dim_t ntslice;                /* Number of time slices */
  char *pname=NULL;             /* Poiner to name */
  smf_qual_t *qua_data=NULL;    /* Pointer to DATA component of qua */
  double *res_data=NULL;        /* Pointer to DATA component of res */
  size_t sc;                    /* Short map counter */
  double *shortmapweight=NULL;  /* buffer for shotmap weights */
  double *shortmapweightsq=NULL;/* buffer for shotmap weights squared */
  int *shorthitsmap=NULL;       /* buffer for shotmap hits */
  size_t shortstart;            /* first time slice of short map */
  size_t shortend;              /* last time slice of short map */
  size_t tstride;               /* Time stride */

  if( *status != SAI__OK ) return;

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

  if( !res || !res->sdata || !res->sdata[idx] || !res->sdata[idx]->hdr ||
      !res->sdata[idx]->hdr->allState ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": RES does not contain JCMTState", status );
    return;
  }

  /* Allocate space for the arrays */
  shortmapweight = astMalloc( msize*sizeof(*shortmapweight) );
  shortmapweightsq = astMalloc( msize*sizeof(*shortmapweightsq) );
  shorthitsmap = astMalloc( msize*sizeof(*shorthitsmap) );

  /* Use first subarray to figure out time dimension. Get the
     useful start and end points of the time series, and then
     determine "nshort" -- the number of complete blocks of
     shortmap time slices in the useful range. */

  smf_get_dims( qua->sdata[0], NULL, NULL, NULL, &ntslice,
                NULL, NULL, &tstride, status );

  qua_data = (qua->sdata[0]->pntr)[0];
  smf_get_goodrange( qua_data, ntslice, tstride, SMF__Q_BOUND,
                     &istart, &iend, status );

  shortstart = istart;

  if( *status == SAI__OK ) {
    if( shortmap == -1 ) {
      nshort = res->sdata[idx]->hdr->allState[iend].tcs_index -
        res->sdata[idx]->hdr->allState[istart].tcs_index + 1;

      msgOutf( "", FUNC_NAME
               ": writing %zu short maps, once each time TCS_INDEX increments",
               status, nshort );
    } else {
      nshort = (iend-istart+1)/shortmap;

      if( nshort ) {
        msgOutf( "", FUNC_NAME
                 ": writing %zu short maps of length %i time slices.",
                 status, nshort, shortmap );
      } else {
        /* Generate warning message if requested short maps are too long*/
        msgOutf( "", FUNC_NAME
                 ": Warning! short maps of lengths %i requested, but "
                 "data only %zu time slices.", status, shortmap,
                 iend-istart+1 );
      }
    }
  }

  /* Loop over short maps */
  for( sc=0; (sc<nshort)&&(*status==SAI__OK); sc++ ) {

    Grp *mgrp=NULL;             /* Temporary group for map names */
    smfData *mapdata=NULL;      /* smfData for new map */
    char tempstr[20];           /* Temporary string */
    char tmpname[GRP__SZNAM+1]; /* temp name buffer */
    char thisshort[20];         /* name particular to this shortmap */

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

    /* Continuous chunk number */
    sprintf(tempstr, "CH%02zd", contchunk);
    one_strlcat( name, tempstr, sizeof(name), status );

    /* Shortmap number */
    sprintf( thisshort, "SH%06zu", sc );
    one_strlcat( name, thisshort, sizeof(name), status );
    mgrp = grpNew( "shortmap", status );
    grpPut1( mgrp, name, 0, status );

    msgOutf( "", "*** Writing short map (%zu / %zu) %s", status,
             sc+1, nshort, name );

    smf_open_newfile ( wf, mgrp, 1, SMF__DOUBLE, 2, lbnd_out,
                       ubnd_out, SMF__MAP_VAR, &mapdata,
                       status);

    /* Time slice indices for start and end of short map -- common to
       all subarrays */

    if( shortmap > 0) {
      /* Evenly-spaced shortmaps in time */
      shortstart = istart+sc*shortmap;
      shortend = istart+(sc+1)*shortmap-1;
    } else {
      /* One map each time TCS_INDEX increments -- just uses header
         for the first subarray */
      for(i=shortstart+1; (i<=iend) &&
            (res->sdata[0]->hdr->allState[i].tcs_index ==
             res->sdata[0]->hdr->allState[shortstart].tcs_index);
          i++ );
      shortend = i-1;
    }

    /* Bad status if we have invalid shortmap ranges. This might
       happen if there is ever a jump in TCS_INDEX for the shortmap=-1
       case since the total number of shortmaps is calculated simply
       as the difference between the first and final TCS indices. */

    if( !nshort || (iend<istart) || (iend>=ntslice) ) {
      *status = SAI__ERROR;
      errRepf( "", FUNC_NAME ": invalid shortmap range (%zu--%zu, ntslice=%zu)"
               "encountered", status, istart, iend, ntslice );
      break;
    }

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

      /* Pointers to everything we need */
      res_data = (res->sdata[idx]->pntr)[0];
      lut_data = (lut->sdata[idx]->pntr)[0];
      qua_data = (qua->sdata[idx]->pntr)[0];

      smf_get_dims( res->sdata[idx], NULL, NULL, NULL, &ntslice,
                    &dsize, NULL, &tstride, status );

      /* Rebin the data for this range of tslices. */
      if( idx == 0 ) {
        rebinflag |= AST__REBININIT;
      }

      if( idx == (res->ndat-1) ) {
        rebinflag |= AST__REBINEND;
      }

      smf_rebinmap1( NULL, res->sdata[idx],
                     dat->noi ? dat->noi[0]->sdata[idx] : NULL,
                     lut_data, shortstart, shortend, 1, NULL, 0,
                     SMF__Q_GOOD, varmapmethod,
                     rebinflag,
                     mapdata->pntr[0],
                     shortmapweight, shortmapweightsq, shorthitsmap,
                     mapdata->pntr[1], msize, NULL, status );

      /* Write out FITS header */
      if( (*status == SAI__OK) && res->sdata[idx]->hdr &&
          res->sdata[idx]->hdr->allState ) {
        AstFitsChan *fitschan=NULL;
        JCMTState *allState = res->sdata[idx]->hdr->allState;
        size_t midpnt = (shortstart + shortend) / 2;

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

        atlPtfti( fitschan, "SEQSTART", allState[shortstart].rts_num,
                  "RTS index number of first frame", status );
        atlPtfti( fitschan, "SEQEND", allState[shortend].rts_num,
                  "RTS index number of last frame", status);
        atlPtftd( fitschan, "MJD-AVG", allState[midpnt].rts_end,
                  "Average MJD of this map", status );
        atlPtfts( fitschan, "TIMESYS", "TAI", "Time system for MJD-AVG",
                  status );
        atlPtfti( fitschan, "TCSINDST", allState[shortstart].tcs_index,
                  "TCS index of first frame", status );
        atlPtfti( fitschan, "TCSINDEN", allState[shortend].tcs_index,
                  "TCS index of last frame", status );


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

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

    /* Update shortstart in case we are counting steps in TCS_INDEX */
    shortstart = shortend+1;

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

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

  }

  /* Free up memory */
  shortmapweight = astFree( shortmapweight );
  shortmapweightsq = astFree( shortmapweightsq );
  shorthitsmap = astFree( shorthitsmap );

}
예제 #9
0
void smurf_sc2threadtest( int *status ) {

  /* Local Variables */
  smfArray **res=NULL;       /* array of smfArrays of test data */
  smfData *data=NULL;        /* Pointer to SCUBA2 data struct */
  dim_t datalen;             /* Number of data points */
  smfFilter *filt=NULL;      /* Frequency domain filter */
  size_t i;                  /* Loop counter */
  size_t j;                  /* Loop counter */
  smfTimeChunkData *job_data=NULL; /* Array of pointers for job data */
  size_t joblen;             /* Number of chunks per job */
  size_t k;                  /* Loop counter */
  size_t nchunks;            /* Number of chunks */
  size_t nsub;               /* Number of subarrays */
  int nthread;               /* Number of threads */
  smfTimeChunkData *pdata=NULL; /* Pointer to data for single job */
  int temp;                  /* Temporary integer */
  size_t tsteps;             /* How many time steps in chunk */
  struct timeval tv1, tv2;   /* Timers */
  ThrWorkForce *wf = NULL;   /* Pointer to a pool of worker threads */

  double *dat=NULL;
  dim_t nbolo;
  dim_t ntslice;
  dim_t ndata;
  size_t bstride;
  size_t tstride;
  dim_t offset;

  if (*status != SAI__OK) return;

  /* Get input parameters */
  parGdr0i( "NTHREAD", 1, 1, NUM__MAXI, 1, &nthread, status );
  parGdr0i( "TSTEPS", 6000, 0, NUM__MAXI, 1, &temp, status );
  tsteps = (size_t) temp;
  parGdr0i( "NCHUNKS", 1, 1, NUM__MAXI, 1, &temp, status );
  nchunks = (size_t) temp;
  parGdr0i( "NSUB", 1, 1, 4, 1, &temp, status );
  nsub = (size_t) temp;

  msgSeti("N",nthread);
  msgOut( "", TASK_NAME ": Running test with ^N threads", status );

  /*** TIMER ***/
  smf_timerinit( &tv1, &tv2, status );

  /* Create some fake test data in the form of an array of smfArrays */

  msgSeti("T",tsteps);
  msgSeti("C",nchunks);
  msgSeti("NS",nsub);
  msgOut( "", TASK_NAME
          ": Creating ^NS subarrays of data with ^C chunks * ^T samples",
          status );

  res = astCalloc( nchunks, sizeof(*res) );

  for( k=0; (*status==SAI__OK)&&(k<nchunks); k++ ) {

    res[k] = smf_create_smfArray( status );

    for( i=0; (*status==SAI__OK)&&(i<nsub); i++ ) {
      /* Create individual smfDatas and add to array */
      data = smf_create_smfData( SMF__NOCREATE_FILE |
                                 SMF__NOCREATE_DA |
                                 SMF__NOCREATE_FTS, status );

      if( *status==SAI__OK ) {
        data->dtype=SMF__DOUBLE;
        data->ndims=3;
        data->dims[0]=40;
        data->dims[1]=32;
        data->dims[2]=(dim_t) tsteps;
        datalen=1;
        data->isFFT=-1;
        for( j=0; j<data->ndims; j++ ) datalen *= data->dims[j];

        data->hdr->steptime = 0.005;

        data->pntr[0] = astCalloc( datalen, smf_dtype_sz(data->dtype,status) );
        data->qual = astCalloc( datalen, sizeof(*data->qual) );
      }

      smf_addto_smfArray( res[k], data, status );
    }
  }

  /*** TIMER ***/
  msgOutf( "", "** %f seconds generating data", status,
           smf_timerupdate(&tv1,&tv2,status) );

  msgOut( "", TASK_NAME
          ": Starting test 1 __parallel time: dataOrder__", status );

  /* Create a pool of threads. */
  wf = thrGetWorkforce( nthread, status );

  /* Work out number of chunks per thread */
  joblen = nchunks/nthread;
  if( joblen == 0 ) joblen = 1; /* At least one chunk per thread */

  /* The first test will process separate time chunks of data in
     parallel, re-ordering each to bolo-ordered format. All subarrays
     and an integer number of input file chunks all go into a single
     thread. Start by allocating and initializing a number of
     smfTimeChunkData's that hold the information required for each
     thread */

  job_data = astCalloc( nthread, sizeof(*job_data) );

  for( i=0; (i<(size_t)nthread) && (*status==SAI__OK); i++ ) {
    pdata = job_data + i;

    pdata->type = 0;                /* Start with a data re-order */
    pdata->data = res;              /* Pointer to main data array */
    pdata->chunk1 = i*joblen;       /* Index of first chunk for job */
    pdata->nchunks = nchunks;       /* Total number of time chunks in data */
    pdata->ijob = -1;               /* Flag job as available to do work */

    /* The last thread has to pick up the remainder of chunks */
    if( i==(size_t)(nthread-1) ) pdata->chunk2=nchunks-1;
    else pdata->chunk2 = (i+1)*joblen-1; /* Index of last chunk for job */

    /* Ensure a valid chunk range, or set to a length that we know to ignore */
    if( pdata->chunk1 >= nchunks ) {
      pdata->chunk1 = nchunks;
      pdata->chunk2 = nchunks;
    } else if( pdata->chunk2 >= nchunks ) {
      pdata->chunk2 = nchunks-1;
    }

    if( pdata->chunk1 >= nchunks ) {
      /* Nothing for this thread to do */
      msgSeti( "W", i+1);
      msgOutif( MSG__DEBUG, "",
                "-- parallel time: skipping thread ^W, nothing to do",
                status);
    } else {
      /* Since we know there is one job_data per thread, just submit jobs
         immediately */
      pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfParallelTime,
                                 0, NULL, status );
    }
  }

  /* Wait until all of the submitted jobs have completed */
  thrWait( wf, status );

  /* Annul the bad status that we set in smfParallelTime */
  if( *status == SMF__INSMP ) {
    errAnnul( status );
    msgOut( "", " *** Annulled SMF__INSMP set in smfParallelTime *** ",
            status );
  } else {
    msgOut( "", " *** Flushing good status *** ", status );
    errFlush( status );
  }

  /*** TIMER ***/
  msgOutf( "", "** %f seconds to complete test", status,
           smf_timerupdate(&tv1,&tv2,status) );

  /* The second test will boxcar smooth bolometers from time chunks in
     parallel */

  msgOut( "", TASK_NAME
          ": Starting test 2 __parallel time: boxcar smooth__", status );

  for( i=0; (i<(size_t)nthread) && (*status==SAI__OK); i++ ) {
    pdata = job_data + i;

    pdata->type = 1;                /* Boxcar smooth */

    if( pdata->chunk1 >= nchunks ) {
      /* Nothing for this thread to do */
      msgSeti( "W", i+1);
      msgOutif( MSG__DEBUG, "",
                "-- parallel time: skipping thread ^W, nothing to do",
                status);
    } else {
      /* Since we know there is one job_data per thread, just submit jobs
         immediately */
      pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfParallelTime,
                                 0, NULL, status );
    }
  }

  /* Wait until all of the submitted jobs have completed */
  thrWait( wf, status );

  /*** TIMER ***/
  msgOutf( "", "** %f seconds to complete test", status,
           smf_timerupdate(&tv1,&tv2,status) );

  msgOut( "", TASK_NAME
          ": *** Next 2 tests will be done twice due to FFTW planning *****",
          status );

  for( k=0; k<2; k++ ) {

    /* The third test will FFT filter bolometers from time chunks in
       parallel */

    msgOut( "", TASK_NAME
            ": Starting test 3 __parallel time: FFT filter__", status );

    for( i=0; (i<(size_t)nthread) && (*status==SAI__OK); i++ ) {
      pdata = job_data + i;

      pdata->type = 2;                /* FFT filter */

      if( pdata->chunk1 >= nchunks ) {
        /* Nothing for this thread to do */
        msgSeti( "W", i+1);
        msgOutif( MSG__DEBUG, "",
                  "-- parallel time: skipping thread ^W, nothing to do",
                  status);
      } else {
        /* Since we know there is one job_data per thread, just submit jobs
           immediately */
        pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfParallelTime,
                                 0, NULL, status );
      }
    }

    /* Wait until all of the submitted jobs have completed */
    thrWait( wf, status );

    /*** TIMER ***/
    msgOutf( "", "** %f seconds to complete test", status,
             smf_timerupdate(&tv1,&tv2,status) );

    msgOut( "", TASK_NAME
            ": Starting test 4 __FFTW filter using internal threading__",
            status );

    for( i=0; (*status==SAI__OK)&&(i<nchunks); i++ ) {
      filt = smf_create_smfFilter( res[i]->sdata[0], status );
      smf_filter_ident( filt, 1, status );

      for( j=0; (*status==SAI__OK)&&(j<nsub); j++ ) {
        msgOutiff( MSG__DEBUG, "", "  filter chunk %zu/%zu, bolo %zu/%zu",
                   status, i+1, nchunks, j+1, nsub );
        smf_filter_execute( wf, res[i]->sdata[j], filt, 0, 0, status );
      }

      if( filt ) filt = smf_free_smfFilter( filt, status );
    }
    /*** TIMER ***/
    msgOutf( "", "** %f seconds to complete test", status,
             smf_timerupdate(&tv1,&tv2,status) );
  }

  msgOut( "", TASK_NAME
          ": **************************************************************",
          status );

  /* Series of short single-thread array index tests */
  data = res[0]->sdata[0];
  dat = data->pntr[0];

  smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, &ndata, &bstride,
                &tstride, status );

  msgOut("","Array index test #1: two multiplies in inner loop",status);
  smf_timerinit( &tv1, &tv2, status );
  for( i=0; i<nbolo; i++ ) {
    for( j=0; j<ntslice; j++ ) {
      dat[i*bstride + j*tstride] += 5;
    }
  }
  msgOutf( "", "** %f seconds to complete test", status,
           smf_timerupdate(&tv1,&tv2,status) );

  msgOut("","Array index test #2: only index increments",status);
  smf_timerinit( &tv1, &tv2, status );
  for( i=0; i<nbolo*bstride; i+=bstride ) {
    for( j=i; j<(i+ntslice*tstride); j+=tstride ) {
      dat[j] += 5;
    }
  }
  msgOutf( "", "** %f seconds to complete test", status,
           smf_timerupdate(&tv1,&tv2,status) );

  msgOut("","Array index test #3: one multiply in outer loop",status);
  smf_timerinit( &tv1, &tv2, status );
  offset = 0;
  for( i=0; i<nbolo; i++ ) {
    offset = i*bstride;
    for( j=0; j<ntslice; j++ ) {
      dat[offset] += 5;
      offset += tstride;
    }
  }
  msgOutf( "", "** %f seconds to complete test", status,
           smf_timerupdate(&tv1,&tv2,status) );

  /* Clean up */
  if( res ) {
    for( i=0; i<nchunks; i++ ) {
      if( res[i] ) {
        smf_close_related( &res[i], status );
      }
    }
    res = astFree( res );
  }
  job_data = astFree( job_data );

  /* Ensure that FFTW doesn't have any used memory kicking around */
  fftw_cleanup();

}
예제 #10
0
static void DisplayKeyMap( AstKeyMap *km, int sort, const char *prefix,
                           AstKeyMap *refkm, int *status ){
/*
*  Name:
*     DisplayKeyMap

*  Purpose:
*     Display the contents of a keymap.

*  Synopsis:
*     void DisplayKeyMap( AstKeyMap *km, int sort, const char *prefix,
*                         int *status )

*  Arguments:
*     km
*        Pointer to the KeyMaps containing the values to display.
*     sort
*        If non-zero, sort the values alphabetically by their keys.
*     prefix
*        A string to prepend to eack key.
*     refkm
*        Reference key map (e.g. values from the supplied configuration
*        rather than the NDF history), or null if not required.
*     status
*        Inherited status pointer.

*  Description:
*     This function displays the contents of a supplied KeyMap as
*     a series of "key = value" strings, one per line. It calls itself
*     recursively if a nested KeyMap is found, adding a suitable
*     prefix to the nested keys.  If a reference key map is supplied then
*     the output shows how the main key map differs from it.
*/

/* Local Variables: */
   AstObject *avalue;
   AstObject *refavalue;
   char cbuffer[ 255 ];
   char newpref[ 255 ];
   const char *cvalue;
   const char *refcvalue;
   const char *key;
   int ikey;
   int ival;
   int nc;
   int nkey;
   int nval;

/* Check the inherited status */
   if( *status != SAI__OK ) return;
   if (refkm) astClear(refkm, "KeyError");

/* Sort the supplied KeyMap is required. */
   if( sort ) astSetC( km, "SortBy", "KeyUp" );

/* Loop round all keys in the supplied KeyMap. */
   nkey = astMapSize( km );
   for( ikey = 0; ikey < nkey; ikey++ ) {
      key = astMapKey( km, ikey );

/* If the current entry is a nest KeyMap, get a pointer to it and call
   this function recurisvely to display it, modifying the prefix to add
   to each key so that it includes the key associated with the nest keymap. */
      if( astMapType( km, key ) == AST__OBJECTTYPE ) {
         astMapGet0A( km, key, &avalue );
         if (refkm) {
            if (! astMapGet0A(refkm, key, &refavalue)) {
               refavalue = (AstObject*) astKeyMap("");
            }
         }
         else {
            refavalue = NULL;
         }
         sprintf( newpref, "%s%s.", prefix, key );
         DisplayKeyMap( (AstKeyMap *) avalue, sort, newpref,
                        (AstKeyMap *) refavalue, status );
         avalue = astAnnul( avalue );
         if (refavalue) refavalue = astAnnul(refavalue);

/* If the current entry is not a nested keymap, we display it now. */
      } else {

/* Get the vector length of the entry. */
         nval = astMapLength( km, key );

/* If it is a scalar, just get its value as a character string using
   the automatic type conversion provided by the KeyMap class, and
   display it, putting the supplied prefix at the start of the key. */
         if( nval <= 1 ) {
            cvalue = "<undef>";
            astMapGet0C( km, key, &cvalue );
            if (refkm) {
               refcvalue = "<undef>";
               if (astMapGet0C(refkm, key, &refcvalue)
                     && ! strcmp(cvalue, refcvalue)) {
                  msgOutf("", "- %s%s = %s", status, prefix, key, cvalue);
               }
               else {
                  msgOutf("", "+ %s%s = %s", status, prefix, key, cvalue);
               }
            }
            else {
               msgOutf( "", "%s%s = %s", status, prefix, key, cvalue );
            }

/* If it is a vector, we construct a string containing a comma-separated
   list of elements, enclosed in parentheses. */
         } else {
            nc = 0;
            cvalue = astAppendString( NULL, &nc, "(" );
            for( ival = 0; ival < nval; ival++ ) {
               if( astMapGetElemC( km, key, sizeof( cbuffer) - 1, ival,
                                   cbuffer ) ) {
                  cvalue = astAppendString( (char *) cvalue, &nc, cbuffer );
               }
               if( ival < nval - 1 ) cvalue = astAppendString( (char *) cvalue,
                                                                &nc, "," );
            }
            cvalue = astAppendString( (char *) cvalue, &nc, ")" );

/* Do the same for the reference KeyMap. */
            if (refkm && (nval = astMapLength(refkm, key))) {
               nc = 0;
               refcvalue = astAppendString(NULL, &nc, "(");
               for (ival = 0; ival < nval; ival++) {
                  if (ival) {
                     refcvalue = astAppendString((char*) refcvalue, &nc, "," );
                  }

                  if (astMapGetElemC(refkm, key, sizeof(cbuffer) - 1, ival,
                                      cbuffer)) {
                     refcvalue = astAppendString((char*) refcvalue, &nc,
                                                 cbuffer);
                  }
               }
               refcvalue = astAppendString((char*) refcvalue, &nc, ")");
            }
            else {
               refcvalue = NULL;
            }

/* Display the total string, with the current key prefix, and free the memory
   used to store it. */
            if (refkm) {
               if (refcvalue && ! strcmp(cvalue, refcvalue)) {
                  msgOutf("", "- %s%s = %s", status, prefix, key, cvalue);
               }
               else {
                  msgOutf("", "+ %s%s = %s", status, prefix, key, cvalue);
               }
            }
            else {
               msgOutf( "", "%s%s = %s", status, prefix, key, cvalue );
            }
            cvalue = astFree( (void *) cvalue );
            if (refcvalue) refcvalue = astFree((void*) refcvalue);
         }
      }
   }
}
예제 #11
0
void smurf_sc2filtermap( int *status ) {

  Grp *fgrp = NULL;         /* Output filter group */
  smfFilter *filt=NULL;     /* Filter */
  double filt_edgehigh=0;   /* High-pass filter */
  double filt_edgelow=0;    /* Low-pass filter */
  size_t fsize;             /* Number of files in fgrp */
  size_t i;                 /* Loop (grp) counter */
  smfData *idata;           /* Pointer to input smfData */
  Grp *igrp = NULL;         /* Input group of files */
  int isfft=0;              /* Are data fft or real space? */
  int *mask=NULL;           /* Mask indicating where bad data are */
  size_t ndata=0;           /* Number of pixels in the map */
  size_t ndims;             /* Number of real space dimensions */
  smfData *odata=NULL;      /* Pointer to output smfData to be exported */
  Grp *ogrp = NULL;         /* Output group of files */
  size_t outsize;           /* Number of files in output group */
  size_t size;              /* Number of files in input group */
  ThrWorkForce *wf = NULL;  /* Pointer to a pool of worker threads */
  smfData *wrefmap=NULL;    /* Whitening reference map */
  int whiten;               /* Applying whitening filter? */
  Grp *wgrp = NULL;         /* Whitening reference map group */
  size_t wsize;             /* Size of wgrp */
  int zerobad;              /* Zero VAL__BADD before taking FFT? */

  /* Main routine */
  ndfBegin();

  /* Find the number of cores/processors available and create a pool of
     threads of the same size. */
  wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status );

  /* Get input file(s) */
  kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );
  size = grpGrpsz( igrp, status );

  if (size > 0) {
    int parstate=0;           /* ADAM parameter state */

    /* Get output file(s) */
    kpg1Wgndf( "OUT", igrp, size, size, "More output files required...",
               &ogrp, &outsize, status );

    /* Write out the filter? */
    parState( "OUTFILTER", &parstate, status );
    if( parstate != PAR__GROUND ) {
      kpg1Wgndf( "OUTFILTER", igrp, size, size,
                 "More output filter files required...",
                 &fgrp, &fsize, status );
    }

  }

  /* Are we going to zero bad values first? */
  parGet0l( "ZEROBAD", &zerobad, status );

  /* High/low-pass filters? */
  parGet0d( "FILT_EDGEHIGH", &filt_edgehigh, status );
  parGet0d( "FILT_EDGELOW", &filt_edgelow, status );

  /* Are we applying a spatial whitening filter? */
  parGet0l( "WHITEN", &whiten, status );

  if( whiten ) {
    /* We also need the reference map to measure the whitening filter. We
       make a deep copy of it so that we can set bad values to 0 etc. */

    smfData *tempdata=NULL;

    kpg1Rgndf( "whiterefmap", 0, 1, "", &wgrp, &wsize, status );
    if( (*status == SAI__OK) && (wsize != 1) ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": WHITEREFMAP must be a single reference map",
              status );
    }

    smf_open_file( wgrp, 1, "READ", SMF__NOTTSERIES, &tempdata, status );
    wrefmap = smf_deepcopy_smfData( tempdata, 0, 0, 0, 0, status );
    smf_close_file( &tempdata, status );

    /* Set VAL__BADD to zero if requested */
    if( (*status==SAI__OK) && zerobad ) {
      double *d=NULL;
      size_t j;

      ndata=1;
      for( j=0; j<wrefmap->ndims; j++ ) ndata *= wrefmap->dims[j];

      d = wrefmap->pntr[0];

      if( d ) {
        for( j=0; j<ndata; j++ ) {
          if( d[j] == VAL__BADD ) {
            d[j] = 0;
          }
        }
      }
    }

  }

  for( i=1;(*status==SAI__OK)&&i<=size; i++ ) {
    smf_open_file( igrp, i, "READ", SMF__NOTTSERIES, &idata, status );
    isfft = smf_isfft( idata, NULL, NULL, NULL, NULL, &ndims, status);

    if( (*status==SAI__OK) && isfft ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": Input data are FFT, not real-space!\n",
              status );
      break;
    }

    if( (*status==SAI__OK) && (ndims != 2) ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": Input data not a 2D map!\n",
              status );
      break;
    }

    /* smf_filter_execute operates in-place, so first create the output
       data as a copy of the input */

    odata = smf_deepcopy_smfData( idata, 0, 0, 0, 0, status );

    /* Set VAL__BADD to zero if requested */
    if( (*status==SAI__OK) && zerobad ) {
      double *d=NULL;
      size_t j, k;

      ndata=1;
      for( j=0; j<odata->ndims; j++ ) ndata *= odata->dims[j];

      mask = astCalloc( ndata, sizeof(*mask) );

      /* Do both DATA and VARIANCE */
      if( *status == SAI__OK ) {
        for( k=0; k<2; k++ ) {
          d = odata->pntr[k];

          if( d ) {
            for( j=0; j<ndata; j++ ) {
              if( d[j] == VAL__BADD ) {
                d[j] = 0;
                mask[j] = 1;
              }
            }
          }
        }
      }

    }

    /* Measure and apply the whitening filter. We need to do this
       every time because the dimensions of filt need to match idata
       (not the wrefmap) and they might be different each time. We
       could try to be more clever in the future if this is too slow. */

    filt = smf_create_smfFilter( idata, status );
    /* Set to the identity in case no whitening is applied */
    msgOut( "", TASK_NAME ": initializing filter", status );
    smf_filter_ident( filt, 0, status );

    if( whiten ) {
      msgOut( "", TASK_NAME ": whitening the filter", status );
      smf_filter2d_whiten( wf, filt, wrefmap, 0, 0, 3, status );
    }

    if( filt_edgelow ) {
      msgOutf( "", TASK_NAME ": applying low-pass at < %lg 1/arcsec", status,
               filt_edgelow );
      smf_filter2d_edge( filt, filt_edgelow, 1, status );
    }

    if( filt_edgehigh ) {
      msgOutf( "", TASK_NAME ": applying high-pass at >= %lg 1/arcsec", status,
               filt_edgehigh );
      smf_filter2d_edge( filt, filt_edgehigh, 0, status );
    }

    smf_filter_execute( wf, odata, filt, 0, 0, status );

    /* Set bad values from the mask */
    if( mask ) {
      double *d=NULL;
      size_t j, k;

      /* Do both DATA and VARIANCE */
      for( k=0; k<2; k++ ) {
        d = odata->pntr[k];

        if( d ) {
          for( j=0; j<ndata; j++ ) {
            if( mask[j] ) {
              d[j] = VAL__BADD;
            }
          }
        }
      }
    }

    /* Export the data to a new file */
    smf_write_smfData( odata, NULL, NULL, ogrp, i, 0, MSG__NORM, status );

    /* Write out filters? */
    if( fgrp ) smf_write_smfFilter( filt, NULL, fgrp, i, status );
    if( filt ) smf_free_smfFilter( filt, status );

  }

  /* Tidy up after ourselves */

  if( fgrp ) grpDelet( &fgrp, status);
  if( igrp ) grpDelet( &igrp, status);
  if( ogrp ) grpDelet( &ogrp, status);
  if( wgrp ) grpDelet( &wgrp, status );

  if( odata ) smf_close_file( &odata, status );
  if( wrefmap ) smf_close_file( &wrefmap, status );

  if( mask ) mask = astFree( mask );

  ndfEnd( status );

  /* Ensure that FFTW doesn't have any used memory kicking around */
  fftw_cleanup();
}
예제 #12
0
F77_SUBROUTINE(configecho)( INTEGER(STATUS) ){
/*
*+
*  Name:
*     CONFIGECHO

*  Purpose:
*     Displays one or more configuration parameters.

*  Language:
*     C (designed to be called from Fortran)

*  Type of Module:
*     ADAM A-task

*  Invocation:
*     CALL CONFIGECHO( STATUS )

*  Arguments:
*     STATUS = INTEGER (Given and Returned)
*        The global status.

*  Description:
*     This application displays the name and value of one or all
*     configuration parameters, specified using Parameters CONFIG or
*     NDF. If a single parameter is displayed, its value is also
*     written to an output parameter. If the parameter value is not
*     specified by the CONFIG, NDF or DEFAULTS parameter, then the
*     value supplied for DEFVAL is displayed.
*
*     If an input NDF is supplied then configuration parameters
*     are read from its history (see Parameters NDF and APPLICATION).
*
*     If values are supplied for both CONFIG and NDF, then the
*     differences between the two sets of configuration parameters
*     are displayed (see Parameter NDF).

*  Usage:
*     configecho name config [defaults] [select] [defval]

*  ADAM Parameters:
*     APPLICATION = LITERAL (Read)
*        When reading configuration parameters from the history
*        of an NDF, this parameter specifies the name of the application
*        to find in the history. There must be a history component
*        corresponding to the value of this parameter, and it must
*        include a CONFIG group. [current value]
*     CONFIG = GROUP (Read)
*        Specifies values for the configuration parameters. If the string
*        "def" (case-insensitive) or a null (!) value is supplied, the
*        configuration parameters are obtained using Parameter NDF. If
*        a null value is also supplied for NDF, a set of default
*        configuration parameter values will be used, as specified by
*        Parameter DEFAULTS.
*
*        The supplied value should be either a comma-separated list of
*        strings or the name of a text file preceded by an up-arrow
*        character "^", containing one or more comma-separated lists of
*        strings. Each string is either a "keyword=value" setting, or the
*        name of a text file preceded by an up-arrow character "^". Such
*        text files should contain further comma-separated lists which
*        will be read and interpreted in the same manner (any blank lines
*        or lines beginning with "#" are ignored). Within a text file,
*        newlines can be used as delimiters, as well as commas. Settings
*        are applied in the order in which they occur within the list,
*        with later settings overriding any earlier settings given for
*        the same keyword.
*
*        Each individual setting should be of the form "<keyword>=<value>".
*        If a non-null value is supplied for Parameter DEFAULTS, an error
*        will be reported if CONFIG includes values for any parameters
*        that are not included in DEFAULTS.
*     DEFAULTS = LITERAL (Read)
*        The path to a file containing the default value for every
*        allowed configuration parameter. If null (!) is supplied, no
*        defaults will be supplied for parameters that are not specified
*        by CONFIG, and no tests will be performed on the validity of
*        paramter names supplied by CONFIG. [!]
*     DEFVAL = LITERAL (Read)
*        The value to return if no value can be obtained for the named
*        parameter, or if the value is "<undef>".  [<***>]
*     NAME = LITERAL (Read)
*        The name of the configuration parameter to display.  If set to
*        null (!), then all parameters defined in the configuration are
*        displayed.
*     NDF = NDF (Read)
*        An NDF file containing history entries which include
*        configuration parameters. If not null (!) the history
*        of the NDF will be searched for a component corresponding
*        to the Parameter APPLICATION.  The Parameter CONFIG
*        is then optional, but if it too is not null (!) then
*        the output will show the differences between the configuration
*        stored in the NDF history and the given configuration:
*        new parameters and those different from the reference
*        configuration (given by Parameter CONFIG) are prefixed
*        with "+" and those which are the same as the reference
*        configuration are prefixed with "-". [!]
*     SELECT = GROUP (Read)
*        A group that specifies any alternative prefixes that can be
*        included at the start of any parameter name. For instance, if
*        this group contains the two entries "450=1" and "850=0", then
*        either CONFIG or DEFAULTS can specify two values for any single
*        parameter -- one for the parameter prefixed by "450." and another
*        for the parameter prefixed by "850.". Thus, for instance, if
*        DEFAULTS defines a parameter called "filter", it could include
*        "450.filter=300" and "850.filter=600". The CONFIG parameter could
*        then either set the filter parameter for a specific prefix (as
*        in "450.filter=234"); or it could leave the prefix unspecified,
*        in which case the prefix used is the first one with a
*        non-zero value in SELECT (450 in the case of this example - 850
*        has a value zero in SELECT). Thus the names of the items in
*        SELECT define the set of allowed alternative prefixes, and the
*        values indicate which one of these alternatives is to be used
*        (the first one with non-zero value). [!]
*     SORT = _LOGICAL (Read)
*        If TRUE then sort the listed parameters in to alphabetical order.
*        Otherwise, retain the order they have in the supplied
*        configuration. Only used if a null (!) value is supplied for
*        Parameter NAME. [FALSE]
*     VALUE = LITERAL (Write)
*        The value of the configuration parameter, or "<***>" if the
*        parameter has no value in CONFIG and DEFAULTS.

*  Examples:
*     configecho m81 ^myconf
*        Report the value of configuration parameter "m81" defined within
*        the file "myconf". If the file does not contain a value for
*        "m81", then "<***>" is displayed.
*     configecho type ^myconf select="m57=0,m31=1,m103=0"
*        Report the value of configuration parameter "type" defined within
*        the file "myconf". If the file does not contain a value for
*        "type", then the value of "m31.type" will be reported instead. If
*        neither is present, then "<***>" is displayed.
*     configecho flt.filt_edge_largescale \
*                config=^/star/share/smurf/dimmconfig.lis \
*                defaults=/star/bin/smurf/smurf_makemap.def \
*                select="450=1,850=0"
*        Report the value of configuration parameter "flt.filt_edge_largescale"
*        defined within the file "/star/share/smurf/dimmconfig.lis", using
*        defaults from the file "/star/bin/smurf/smurf_makemap.def". If
*        dimmconfig.lis does not contain a value for "flt.filt_edge_largescale"
*        then it is searched for "450.flt.filt_edge_largescale" instead. An
*        error is reported if dimmconfig.lis contains values for any
*        items that are not defined in smurf_makemap.def.
*     configecho ndf=omc1 config=^/star/share/smurf/dimmconfig.lis \
*                defaults=/star/bin/smurf/smurf_makemap.def \
*                application=makemap name=! sort select="450=0,850=1"
*        Show how the configuration used to generate the 850um map
*        of OMC1 differs from the basic dimmconfig.lis file.

*  Copyright:
*     Copyright (C) 2012-3 Science & Technology Facilities 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
*     GSB: Graham S. Bell
*     {enter_new_authors_here}

*  History:
*     10-DEC-2012 (DSB):
*        Original version.
*     6-FEB-2013 (DSB):
*        Added parameter DEFVAL.
*     11-FEB-2013 (DSB):
*        Added parameter SORT and allow all parameters to be listed by
*        providing a null value for NAME.
*     11-FEB-2013 (GSB):
*        Added ability to read configuration from history entries.
*     13-FEB-2013 (DSB):
*        Nullify AST object pointers when the objects are annulled,
*        to avoid re-use of dead pointers.
*     14-FEB-2013 (DSB):
*        Allow the SELECT feature to be used even if no DEFAULTS file is
*        supplied (see the new entry in the "Examples:" section).
*     15-FEB-2013 (DSB):
*        Expand the prologue docs, and use NULL in place of zero for pointers.
*     22-FEB-2013 (DSB):
*        Guard against seg fault in HistoryKeymap when the NDF does 
*        not contain the required CONFIG entry in the History 
*        component.
*     {enter_further_changes_here}

*-
*/

   GENPTR_INTEGER(STATUS)

/* Local Variables: */
   AstKeyMap *keymap2;
   AstKeyMap *keymap;
   Grp *grp = NULL;
   char *dot;
   char *pname;
   char defs[250];
   char defval[250];
   char name[250];
   const char *value;
   const char *historyValue = NULL;
   int showall;
   int sort;
   size_t size;
   int indf = 0;
   int nrec;
   int i;
   char application[NDF__SZAPP];
   char applicationi[NDF__SZAPP];

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

/* Begin an AST context */
   astBegin;

/* Get the value to return if no value can be obtained for the named
   parameter, of it it has a value of <undef>. */
   parGet0c( "DEFVAL", defval, sizeof(defval), STATUS );

/* Get any defaults file, annuling the error if null (!) is supplied. */
   if( *STATUS == SAI__OK ) {
      parGet0c( "DEFAULTS", defs, sizeof(defs), STATUS );
      if( *STATUS == PAR__NULL ) {
         errAnnul( STATUS );
         defs[0] = 0;
      }
   }

/* Get the NDF identifier if requested. */
   ndfBegin();
   if (*STATUS == SAI__OK) {
      ndfAssoc("NDF", "READ", &indf, STATUS);
      if (*STATUS == PAR__NULL) {
         errAnnul(STATUS);
         indf = 0;
      }
      else {
         parGet0c("APPLICATION", application, sizeof(application), STATUS);
         /* Check now for error because the block below allowing an undefined
          * CONFIG clears this status otherwise. */
         if (*STATUS != SAI__OK) goto L999;
      }
   }

/* See if any alternate keyword prefixes are allowed, and if so determine
   which of the alternatices is to be displayed. */
   kpg1Gtgrp( "SELECT", &grp, &size, STATUS );
   if( *STATUS == PAR__NULL ) {
      grpDelet( &grp, STATUS );
      errAnnul( STATUS );
      keymap2 = NULL;
   } else {
      kpg1Kymap( grp, &keymap2, STATUS );
      grpDelet( &grp, STATUS );
   }

/* Create a KeyMap holding the selected alternative for each keyword, and
   also supply defaults for any missing values (if a defaults file was
   supplied by the user). */
   keymap = kpg1Config( "CONFIG", defs[0]?defs:NULL, keymap2, 0, STATUS );

/* Allow it to be NULL if we're reading an NDF because we'll replace
   keymap with historyConfig later if necessary. */
   if( indf && *STATUS == PAR__NULL ) {
      errAnnul(STATUS);
      keymap = NULL;
   }

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

/* Get the name of the required parameter, and convert to upper case (if
   supplied). If not supplied, set a flag indicating that all parameters
   should be displayed. */
   parGet0c( "NAME", name, sizeof(name), STATUS );
   if( *STATUS == PAR__NULL ) {
      errAnnul( STATUS );
      showall = 1;
   } else {
      showall = 0;
      astChrCase( NULL, name, 1, 0 );
   }

/* Attempt to find the NDF's corresponding history record. */
   if (indf && *STATUS == SAI__OK) {
      ndfHnrec(indf, &nrec, STATUS);
      for (i = 0; i < nrec; i ++) {
         ndfHinfo(indf, "APPLICATION", i + 1, applicationi,
                  sizeof(applicationi), STATUS);
         if (! strncasecmp(application, applicationi, strlen(application))) {
            ndfHout(indf, i + 1, HistoryKeyMap, STATUS);
            break;
         }
      }

      if (*STATUS == SAI__OK && ! historyConfig) {
         *STATUS = SAI__ERROR;

         errRepf("CONFIGECHO_ERR", "CONFIGECHO: Failed to find %s "
                 "configuration in NDF history.", STATUS, application);
      }
      else if (! keymap) {
         keymap = historyConfig;
         historyConfig = NULL;
      }
   }

   if( *STATUS == SAI__OK ) {

/* First deal with cases where we are displaying a single parameter
   value. */
      if( !showall ) {

/* Loop round each section of the name that ends with a dot. */
         value = defval;
         pname = name;

         dot = strchr( pname, '.' );
         while( dot && keymap ) {

/* Get a nested keymap with the name that occurs prior to the dot. If
   found, use it in place of the parent keymap. */
            pname[ dot - pname ] = 0;
            if( astMapGet0A( keymap, pname, &keymap2 ) ) {
               astAnnul( keymap );
               keymap = keymap2;
            } else {
               keymap = astAnnul( keymap );
            }

/* If historyConfig exists, do the same there. */
            if (historyConfig) {
               if (astMapGet0A(historyConfig, pname, &keymap2)) {
                  astAnnul(historyConfig);
                  historyConfig = keymap2;
               }
               else {
                  historyConfig = astAnnul(historyConfig);
               }
            }

/* Re-instate the original dot, and move on to find the next dot. */
            pname[ dot - pname ] = '.';
            pname = dot + 1;
            dot = strchr( pname, '.' );
         }

/* Ensure no error is reported if the parameter is not found in the
   KeyMap. */
         if( keymap ) {
            astClear( keymap, "KeyError" );

/* Get the parameter value as a string. */
            astMapGet0C( keymap, pname, &value );
         }

         if (historyConfig) {
            astClear(historyConfig, "KeyError");
            astMapGet0C(historyConfig, pname, &historyValue);

/* In NDF history mode we only want to return a value if it
   was found in the configuration from the history. */

            if (historyValue) {
               if (strcmp(value, historyValue)) {
                  msgOutf("", "+ %s", STATUS, historyValue);
               }
               else {
                  msgOutf("", "- %s", STATUS, historyValue);
               }
               parPut0c("VALUE", historyValue, STATUS);
            }
         }
         else {
/* Display it. */
            msgOut( "", value, STATUS );

/* Write it to the output parameter. */
            parPut0c( "VALUE", value, STATUS );
         }

/* Now deal with cases were we are displaying all parameter values. */
      } else {

/* See if the values should be sorted. */
         parGet0l( "SORT", &sort, STATUS );

/* Display them. */
         if (historyConfig) {
            DisplayKeyMap( historyConfig , sort, "", keymap, STATUS );
         }
         else {
            DisplayKeyMap( keymap, sort, "", NULL, STATUS );
         }
      }
   }

/* Tidy up. */
L999:;

/* End the AST context */
   astEnd;

/* Close the NDF if open. */
   ndfEnd(STATUS);

/* If an error has occurred, issue another error report identifying the
   program which has failed (i.e. this one). */
   if( *STATUS != SAI__OK ) {
      errRep( "CONFIGECHO_ERR", "CONFIGECHO: Failed to echo configuration "
              "parameters.", STATUS );
   }

}
예제 #13
0
void gsdac_putFits ( const gsdVars *gsdVars, const int subBandNum,
                     const int nSubsys, const int obsNum,
                     const int utDate, const int nSteps,
                     const char *backend, const int recepsUsed,
                     char *recepNames[], const char *samMode,
                     const char *obsType, const dateVars *dateVars,
                     const mapVars *mapVars, const double *lineFreqs,
                     const double *IFFreqs, const gsdWCS *wcs,
                     AstFitsChan *fitschan, int *status )

{

  /* Local variables */

  char bwMode[SZFITSTR];      /* ACSIS total bandwidth setup */
  char curChar;               /* character pointer */
  int day;                    /* days for time conversion. */
  char doppler[SZFITSTR];     /* doppler velocity definition */
  double etal;                /* telescope efficiency */
  int hour;                   /* hours for time conversion. */
  int i;                      /* loop counter */
  float IFchanSp;             /* TOPO IF channel spacing (Hz) */
  char instrume[SZFITSTR];    /* front-end receiver */
  double intTime;             /* total time spent integrating (s) */
  int josMult;                /* times around the jiggle (i.e. 1) */
  int josMin;                 /* minimum step time psw */
  int min;                    /* minutes for time conversion. */
  const char *molecule;       /* target molecular species */
  int month;                  /* months for time conversion. */
  int nMix;                   /* number of mixers */
  double nRefStep;            /* number of nod sets repeated */
  char object[SZFITSTR];      /* object of interest */
  char object2[SZFITSTR];     /* object of interest (second half of name) */
  double obsgeo[3];           /* cartesian coordinates of telescope */
  char obsIDSS[SZFITSTR];     /* unique observation number + subsystem
                                 number in format
                                 INSTR_NNNNN_YYYYMMDDTHHMMSS_N */
  char obsSB[SZFITSTR];       /* observed sideband */
  int parse;                  /* flag for incorrect date string. */
  char recipe[25];            /* ORAC-DR recipe name */
  char recptors[SZFITSTR];    /* active FE receptor IDs for this obs */
  double refChan;             /* reference IF channel no. */
  int seeingok;               /* True if the seeing measurement is okay */
  char seeDatSt[SZFITSTR];    /* time of seeingSt in format
                                 YYYY-MM-DDTHH:MM:SS */
  char sSysObs[SZFITSTR];     /* spectral ref. frame during observation */
  int standard;               /* true for spectral line standards */
  int startIdx;               /* index in pattern at start of observation */
  int stBetRef;               /* max number of steps between refs */
  int stBetRef_defined;       /* Use the stBetRef value? */
  double stepTime;            /* RTS step time */
  char subBands[SZFITSTR];    /* ACSIS sub-band set-up */
  int tauok;                  /* True if the tau measurement is okay */
  char tauDatSt[SZFITSTR];    /* time of tau225St observation in
                                 format YYYY-MM-DDTHH:MM:SS */
  const char *transiti;       /* target transition for molecule */
  int year;                   /* year for time conversion. */

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

  /* Get the cartesian coordinates of the telescope's location. */
  smf_terr( gsdVars->telLatitude * DD2R, gsdVars->telHeight * 1000.0,
            -gsdVars->telLongitude * DD2R, obsgeo );

  /* Get the telescope efficiency and convert from percentage to decimal */
  etal = gsdVars->etal / 100.0;


  /* Obs Id, Date, Pointing Info */

  /* Truncate the object names and concatenate. */
  cnfImprt ( gsdVars->object1, 16, object );

  if ( strncmp ( gsdVars->object2, " ", 1 ) != 0 ) {

    cnfImprt ( gsdVars->object2, 16, object2 );
    strcat ( object, ", " );
    strcat ( object, object2 );

  }

  /* Determine if this is a spectral line standard. */
  /* Loop through the array of standards and see if the object matches
     one of them. */
  standard = 0;
  i = 0;
  while ( strcmp ( standards[i], "" ) != 0 ) {
    if ( strcmp ( object, standards[i] ) == 0 ) {
      standard = 1;
    }
    i++;
  }

  /* Copy the obsID into the obsIDSS and add the subsystem number. */
  sprintf ( obsIDSS, "%s_%i", dateVars->obsID,
            subBandNum % nSubsys + 1 );


  /* Integration time related. */

  /* Get the sum of the integration times.  This is either the
     sum of the elements of the intTimes table for grids, or
     the scan time times the number of scans for rasters. */
  if ( gsdVars->obsContinuous ) {

    intTime = gsdVars->scanTime * gsdVars->nScan;

  } else {

    intTime = gsdVars->nCycle * gsdVars->cycleTime;

  }

  /* ACSIS Specific. */

  /* Get the molecule and transition. */
  smf_get_moltrans ( lineFreqs[subBandNum] * 1000.0, &molecule, &transiti,
                     status );

  /* Get the bandwidth setup. */
/***** NOTE: may be different for rxb widebands *****/
  sprintf ( bwMode, "%iMHzx%i", (int)(gsdVars->bandwidths[subBandNum]),
            gsdVars->BEChans[subBandNum] );

/***** NOTE: Possibly undef? *****/
  strcpy ( subBands, bwMode );

  /* Get the reference channel (offset from channel which contains
     IFFreq). */
  refChan = ( (double)( gsdVars->BEChans[subBandNum] ) / 2.0 ) +
            ( ( IFFreqs[subBandNum] - gsdVars->totIFs[subBandNum] ) /
              ( fabs(gsdVars->freqRes[subBandNum]) / 1000.0 ) );

  IFchanSp = gsdVars->freqRes[subBandNum] * 1000000.0;

  strcpy( recipe, "REDUCE_SCIENCE" );

  /* Is this a pointing? */
  if ( strncasecmp( gsdVars->backend, "DAS", 3 ) == 0 &&
       strncasecmp( gsdVars->obsType, "FIVEPOINT", 9 ) == 0 )
     strcpy( recipe, "REDUCE_POINTING" );

  else if ( strncasecmp( gsdVars->obsType, "focus", 5 ) == 0 )
            strcpy( recipe, "REDUCE_FOCUS" );

  /* Solar-system objects have a different default recipe. */
  else if ( strncasecmp( gsdVars->object1, "SUN", 3 )     == 0 ||
            strncasecmp( gsdVars->object1, "MERCURY", 7 ) == 0 ||
            strncasecmp( gsdVars->object1, "VENUS", 5 )   == 0 ||
            strncasecmp( gsdVars->object1, "MOON", 4 )    == 0 ||
            strncasecmp( gsdVars->object1, "MARS", 4 )    == 0 ||
            strncasecmp( gsdVars->object1, "JUPITER", 7 ) == 0 ||
            strncasecmp( gsdVars->object1, "SATURN", 6 )  == 0 ||
            strncasecmp( gsdVars->object1, "TITAN", 5 )   == 0 ||
            strncasecmp( gsdVars->object1, "URANUS", 6 )  == 0 ||
            strncasecmp( gsdVars->object1, "NEPTUNE", 7 ) == 0 ||
            strncasecmp( gsdVars->object1, "PLUTO", 5 )   == 0 )
     strcpy( recipe, "REDUCE_SCIENCE_CONTINUUM" );

  /* Try to catch most galaxies but exclude regions of the Galaxy. */
  else if ( gsdVars->velocity > 120 )
     strcpy( recipe, "REDUCE_SCIENCE_BROADLINE" );

  else if ( strncmp( mapVars->swMode, "freq", 4 ) == 0  )
     strcpy( recipe, "REDUCE_SCIENCE_FSW" );

  /* FE Specific. */

  /* We need to take the opportunity to correct the frontend name.
     In many cases, especially in B-band, the instrument names are
     incorrect. */
  gsdac_getRealInstrumentName( gsdVars, instrume, sizeof(instrume), status );

  /* Get the number of mixers, 2 for RXB3 & RXW, 1 for others.
     but note that RXB3I has 1. We know that instrume is nul-terminated.
     Both RXWC and RXWD have two mixers so just check first 3 characters.
  */
  if ( strcmp ( "RXB3", instrume ) == 0 ||
       strncmp ( "RXW", instrume, 3 ) == 0 ) {
    nMix = 2;
  } else {
    nMix = 1;
  }

  /* Get the observed sideband (-ve value = LSB, +ve value = USB ). */
  if ( gsdVars->sbSigns[subBandNum] > 0 ) strcpy ( obsSB, "USB" );
  else strcpy ( obsSB, "LSB" );

  /* Get the names of the receptors. */
  strcpy ( recptors, recepNames[0] );
  for ( i = 1; i < recepsUsed; i++ ) {
    strcat ( recptors, " " );
    strcat ( recptors, recepNames[i] );
  }

  /* Truncate the doppler velocity definition and set
     to lowercase. */
  cnfImprt ( gsdVars->velDefn, 16, doppler );
  i = 0;
  curChar = doppler[i];
  while ( curChar != '\0' ) {
    doppler[i] = tolower(curChar);
    i++;
    curChar = doppler[i];
  }

/***** NOTE : Possibly comes from VEL_REF (c12vref). */
  strcpy ( sSysObs, "TOPOCENT" );


  /* Environmental data. */

  /* The GSD magic value for bad seeing and tau seems to be VAL__BADR */

  tauDatSt[0] = '\0'; /* make sure it is initialised */

  if (gsdVars->tau225 == VAL__BADR) {
    tauok = 0;

  } else {
    tauok = 1;

    /* Convert dates from YYMMDDHHMMSS to
       YYYY-MM-DDTHH:MM:SS. */
    parse = sscanf ( gsdVars->tauTime, "%02d%02d%02d%02d%02d", &year,
                     &month, &day, &hour, &min );

    if ( parse == 0 || parse == EOF ) {

      msgOutf ( FUNC_NAME, "Couldn't convert CSO tau time of '%s', continuing anyway.",
                status, gsdVars->tauTime );

    } else {

      /* Inelegant method to get YYYY from YY. */
      if ( year > 70 ) year = year + 1900;
      else year = year + 2000;

      sprintf ( tauDatSt, "%04d-%02d-%02dT%02d:%02d:00",
                year, month, day, hour, min );

    }
  }

  /* The GSD magic value for bad seeing and tau seems to be VAL__BADR */

  seeDatSt[0] = '\0'; /* Make sure it is initialised */

  if (gsdVars->seeing == VAL__BADR) {
    seeingok = 0;

  } else {
    seeingok = 1;

    /* Convert dates from YYMMDDHHMMSS to
       YYYY-MM-DDTHH:MM:SS. */
    parse = sscanf ( gsdVars->seeTime, "%02d%02d%02d%02d%02d", &year,
                     &month, &day, &hour, &min );

    if ( parse == 0 || parse == EOF ) {
      msgOutiff(MSG__VERB," ",
                "Couldn't convert seeing time of '%s', continuing anyway.", status,
                gsdVars->seeTime );

    } else {

      /* Kludge to get YYYY from YY. */
      if ( year > 70 ) year = year + 1900;
      else year = year + 2000;

      sprintf ( seeDatSt, "%04d-%02d-%02dT%02d:%02d:00",
                year, month, day, hour, min );

    }
  }

  /* JOS parameters */

  /* STEPTIME is SCAN_TIME divided by the number of points in a scan
     for rasters. For PSW spectra it is SCAN_TIME/2 and for BSW
     it is SCAN_TIME/4 -- because acsis expects a minimum unit
     of ABBA for the nod --*/
  if ( strcmp ( samMode, "scan" ) == 0 ) {
    if ( strncmp ( gsdVars->obsDirection, "HORIZONTAL", 10 ) == 0 ) {
      stepTime = gsdVars->scanTime / gsdVars->nMapPtsX;
    } else {
      stepTime = gsdVars->scanTime / gsdVars->nMapPtsY;
    }
    josMin = 1;
    josMult = 0;
  } else if ( strcmp ( mapVars->swMode, "chop" ) == 0 ) {
      stepTime = gsdVars->scanTime / 4.0;
      josMin = 0;
      josMult = 1;
  } else {
      stepTime = gsdVars->scanTime / 2.0;
      josMin = stepTime;
      josMult = 0;
  }


  /* Get the length of time in the reference, and the number
     of steps between references. set up defaults first to avoid compiler
     warnings. */
  nRefStep = 1;
  stBetRef = 1;

  if ( gsdVars->obsContinuous ) {

    /* For rasters, determine the number of time scanning
       each point in one row from the total time for
       the row / number of points in the row.  The length
       of time in the reference is then sqrt (number of
       points in the row) * (time per point). */
    nRefStep = sqrt ( (double)(gsdVars->nScanPts) ) *
           ( (double)(gsdVars->scanTime) / (double)(gsdVars->nScanPts) );

    stBetRef = gsdVars->nScanPts;

  }

  /* Set a flag indicating if the stBetRef value is defined. */
  stBetRef_defined =   ( strcmp ( mapVars->swMode, "chop" ) != 0 );

  /* Get the starting index into the pattern. */
  gsdac_getStartIdx ( gsdVars, samMode, &startIdx, status );



  /************************************/
  /*      WRITE OUT FITS HEADERS      */
  /************************************/

  astSetFitsS ( fitschan, "TELESCOP", gsdVars->telName,
	        "Name of Telescope", 0 );

  astSetFitsS ( fitschan, "ORIGIN", "Joint Astronomy Centre, Hilo",
                "Origin of file", 0 );

  astSetFitsF ( fitschan, "ALT-OBS", gsdVars->telHeight * 1000.0,
                "[m] Height of observation above sea level", 0 );

  astSetFitsF ( fitschan, "LAT-OBS", gsdVars->telLatitude,
                "[deg] Latitude of Observatory", 0 );

  astSetFitsF ( fitschan, "LONG-OBS", -(gsdVars->telLongitude),
                "[deg] East longitude of Observatory", 0 );

  astSetFitsF ( fitschan, "OBSGEO-X", obsgeo[0],
                "[m]", 0 );

  astSetFitsF ( fitschan, "OBSGEO-Y", obsgeo[1],
                "[m]", 0 );

  astSetFitsF ( fitschan, "OBSGEO-Z", obsgeo[2],
                "[m]", 0 );

  astSetFitsF ( fitschan, "ETAL", etal,
                "Telescope efficiency", 0 );


  /* OMP and ORAC-DR Specific */
  astSetFitsCM ( fitschan,
                 "---- OMP and ORAC-DR Specific ----", 0 );

  astSetFitsS ( fitschan, "PROJECT", gsdVars->project,
	        "PATT number", 0 );

/***** NOTE: possibly REDUCE_POINTING for spectral 5 points *****/
  astSetFitsS ( fitschan, "RECIPE", recipe, "ORAC-DR recipe", 0 );

  astSetFitsU ( fitschan, "DRGROUP", "Data Reduction group ID", 0 );

  astSetFitsS ( fitschan, "MSBID", "GSD2ACSIS_V1",
                "ID of minimum schedulable block", 0 );

  astSetFitsU ( fitschan, "MSBTID", "Transaction ID of MSB", 0 );

  astSetFitsU ( fitschan, "SURVEY", "Survey Name", 0 );

  astSetFitsU ( fitschan, "RMTAGENT", "name of Remote Agent", 0 );

  astSetFitsU ( fitschan, "AGENTID", "Unique identifier for remote agent", 0 );


  /* Obs Id, Date, Pointing Info */
  astSetFitsCM ( fitschan,
                 "---- Obs Id, Date, pointing Info ----", 0 );

  astSetFitsS ( fitschan, "OBJECT", object,
	        "Object of interest", 0 );

  astSetFitsL ( fitschan, "STANDARD", standard,
                "True if the spectral line is a standard", 0 );

  astSetFitsI ( fitschan, "OBSNUM", obsNum,
                "Observation number", 0 );

  astSetFitsI ( fitschan, "NSUBSCAN", 1,
		"Sub-scan number", 0 );

  astSetFitsL ( fitschan, "OBSEND", 1,
                "True if the file is the last in current observation", 0 );

  astSetFitsI ( fitschan, "UTDATE", utDate,
                "UT Date as integer in yyyymmdd format", 0 );

  astSetFitsS ( fitschan, "DATE-OBS", dateVars->dateObs,
                "UTC Datetime of start of observation", 0 );

  astSetFitsS ( fitschan, "DATE-END", dateVars->dateEnd,
                "UTC Datetime of end of observation", 0 );

  astSetFitsF ( fitschan, "DUT1", gsdVars->obsUT1C,
                "[d] UT1-UTC correction", 0 );

  astSetFitsS ( fitschan, "OBSID", dateVars->obsID,
                "Unique observation identifier", 0 );

  astSetFitsS ( fitschan, "OBSIDSS", obsIDSS,
                "Unique observation + subsystem ID", 0 );

/***** NOTE: possibly same as REFRECEP *****/
  astSetFitsU ( fitschan, "INSTAP", "Receptor at tracking centre (if any)", 0 );

  astSetFitsF ( fitschan, "INSTAP_X", 0.0,
                "[arcsec] Aperture X off. rel. to instr centre", 0 );

  astSetFitsF ( fitschan, "INSTAP_Y", 0.0,
                "[arcsec] Aperture Y off. rel. to instr centre", 0 );

  /* The following 6 cards are just placeholders and will be
     updated later. */
  astSetFitsU ( fitschan, "AMSTART", "Airmass at start of observation", 0 );

  astSetFitsU ( fitschan, "AMEND", "Airmass at end of observation", 0 );

  astSetFitsU ( fitschan, "AZSTART", "[deg] Azimuth at start of observation", 0 );

  astSetFitsU ( fitschan, "AZEND", "[deg] Azimuth at end of observation", 0 );

  astSetFitsU ( fitschan, "ELSTART", "[deg] Elevation at start of observation", 0 );

  astSetFitsU ( fitschan, "ELEND", "[deg] Elevation at end of observation", 0 );

  /* Base position in tracking coordinates */
  astSetFitsS( fitschan, "TRACKSYS", gsdac_code2tcssys(gsdVars->centreCode, status),
               "TCS tracking coordinate system", 0 );
  astSetFitsF ( fitschan, "BASEC1", wcs->baseTr1 * AST__DR2D,
                "[deg] TCS BASE position (longitude) in TRACKSYS", 0 );
  astSetFitsF ( fitschan, "BASEC2", wcs->baseTr2 * AST__DR2D,
                "[deg] TCS BASE position (latitude) in TRACKSYS", 0 );


  astSetFitsS ( fitschan, "HSTSTART", dateVars->HSTstart,
                "HST at start of observation", 0 );

  astSetFitsS ( fitschan, "HSTEND", dateVars->HSTend,
                "HST at end of observation", 0 );

  astSetFitsS ( fitschan, "LSTSTART", dateVars->LSTstart,
                "LST at start of observation", 0 );

  astSetFitsS ( fitschan, "LSTEND", dateVars->LSTend,
                "LST at end of observation", 0 );

  /* Integration time related. */
  astSetFitsCM ( fitschan,
                 "---- Integration time related ----", 0 );

  astSetFitsF ( fitschan, "INT_TIME", intTime,
                "Time spent integrating, entire", 0 );

  /* DAS Specific */
  astSetFitsCM ( fitschan,
                 "---- DAS Specific ----", 0 );
  astSetFitsI ( fitschan, "SPECID", gsdVars->BESubsys[subBandNum],
                "Spectrum ID for this subband", 0 );

  /* ACSIS Specific. */
  astSetFitsCM ( fitschan,
                 "---- ACSIS Specific ----", 0 );

  astSetFitsS ( fitschan, "BACKEND", backend,
                "Name of the backend", 0 );

  astSetFitsS ( fitschan, "MOLECULE", molecule,
                "Target molecular species", 0 );

  astSetFitsS ( fitschan, "TRANSITI", transiti,
                "Target transition for MOLECULE", 0 );

  astSetFitsU ( fitschan, "DRRECIPE", "ACSIS-DR recipe name", 0 );

  astSetFitsS ( fitschan, "BWMODE", bwMode,
                "Bandwidth setup", 0 );

  astSetFitsI ( fitschan, "SUBSYSNR", ( subBandNum % nSubsys ) + 1,
                "Sub-system number", 0 );

  astSetFitsS ( fitschan, "SUBBANDS", bwMode,
                "Sub-band setup", 0 );

  astSetFitsI ( fitschan, "NSUBBAND", 1,
                "Number of subbands", 0 );

  astSetFitsF ( fitschan, "SUBREFP1", refChan,
                "Reference channel for subband1", 0 );

  astSetFitsU ( fitschan, "SUBREFP2", "Reference channel for subband2", 0 );

  astSetFitsI ( fitschan, "NCHNSUBS", gsdVars->BEChans[subBandNum],
                "Number of subbands", 0 );

  astSetFitsF ( fitschan, "REFCHAN", refChan,
                "Reference IF channel No.", 0 );

  astSetFitsF ( fitschan, "IFCHANSP", IFchanSp,
                "[Hz] TOPO IF channel spacing (signed)", 0 );

  astSetFitsS ( fitschan, "FFT_WIN", "truncate",
	        "Type of window used for FFT", 0 );

  if ( strncmp ( gsdVars->backend, "DAS", 3 ) == 0 ) {

    astSetFitsF ( fitschan, "BEDEGFAC", 1.15,
	          "Backend degradation factor", 0 );

  } else if ( strncmp ( gsdVars->backend, "AOSC", 4 ) == 0 ) {

    astSetFitsF ( fitschan, "BEDEGFAC", 1.0,
	          "Backend degradation factor", 0 );

  } else {

    astSetFitsU ( fitschan, "BEDEGFAC", "Backend degradation factor", 0 );

  }

  astSetFitsU ( fitschan, "MSROOT", "Root name of raw measurement sets", 0 );


  /* FE Specific. */
  astSetFitsCM ( fitschan,
                 "---- FE Specific ----", 0 );

  astSetFitsS ( fitschan, "INSTRUME", instrume,
	        "Front-end receiver", 0 );

  astSetFitsS ( fitschan, "SB_MODE", gsdVars->sbMode,
	        "Sideband mode", 0 );

  astSetFitsF ( fitschan, "IFFREQ", IFFreqs[subBandNum],
                "[GHz] IF Frequency", 0 );

  astSetFitsI ( fitschan, "N_MIX", nMix,
                "No. of mixers", 0 );

  astSetFitsS ( fitschan, "OBS_SB", obsSB,
		"The observed sideband", 0 );

  astSetFitsF ( fitschan, "LOFREQS", gsdVars->LOFreqs[subBandNum],
		"[GHz] LO Frequency at start of obs", 0 );

  astSetFitsF ( fitschan, "LOFREQE", gsdVars->LOFreqs[subBandNum],
                "[GHz] LO Frequency at end of obs", 0 );

  astSetFitsS ( fitschan, "RECPTORS", recptors,
                "Active FE receptor IDs for this obs", 0 );

  astSetFitsS ( fitschan, "REFRECEP", recepNames[0],
                "Receptor with unit sensitivity", 0 );

  if ( strcmp ( samMode, "grid" ) == 0 ) {
    astSetFitsU ( fitschan, "MEDTSYS", "[K] Median of the T-sys across all receptors", 0 );
  } else {
    astSetFitsF ( fitschan, "MEDTSYS",
                  gsdVars->sourceSysTemps[subBandNum],
		  "[K] Median of the T-sys across all receptors", 0 );
  }

  astSetFitsS ( fitschan, "TEMPSCAL", "TA*",
                "Temperature scale in use", 0 );

  astSetFitsS ( fitschan, "DOPPLER", doppler,
                "Doppler velocity definition", 0 );

  astSetFitsS ( fitschan, "SSYSOBS", sSysObs,
                "Spectral ref. frame during observation", 0 );


  /* Environmental data. */
  astSetFitsCM ( fitschan,
                 "---- Environmental Data ----", 0 );

  astSetFitsF ( fitschan, "ATSTART", gsdVars->tamb,
                "[degC] Air temp at start of observation", 0 );

  astSetFitsF ( fitschan, "ATEND", gsdVars->tamb,
                "[degC] Air temp at end of observation", 0 );

  astSetFitsF ( fitschan, "HUMSTART",gsdVars->hamb ,
                "Rel Humidity at observation start", 0 );

  astSetFitsF ( fitschan, "HUMEND", gsdVars->hamb,
                "Rel Humidity observation end", 0 );

  astSetFitsF ( fitschan, "BPSTART", gsdVars->pamb,
                "[mbar] Pressure at observation start", 0 );

  astSetFitsF ( fitschan, "BPEND", gsdVars->pamb,
                "[mbar] Pressure at observation end", 0 );

  astSetFitsU ( fitschan, "WNDSPDST", "[km/h] Wind Speed at obs start", 0 );

  astSetFitsU ( fitschan, "WNDSPDEN", "[km/h] Wind Speed at obs end", 0 );

  astSetFitsU ( fitschan, "WNDDIRST", "[deg] Wind direction, azimuth at obs start", 0 );

  astSetFitsU ( fitschan, "WNDDIREN", "[deg] Wind direction, azimuth at obs end", 0 );

  if (tauok) {
    astSetFitsF ( fitschan, "TAU225ST", gsdVars->tau225,
                  "Tau at 225 GHz from CSO at start", 0 );

    astSetFitsF ( fitschan, "TAU225EN", gsdVars->tau225,
                  "Tau at 225 GHz from CSO at end", 0 );
  } else {
    astSetFitsU ( fitschan, "TAU225ST",
                  "Tau at 225 GHz from CSO at start", 0 );

    astSetFitsU ( fitschan, "TAU225EN",
                  "Tau at 225 GHz from CSO at end", 0 );
  }

  if (tauok && tauDatSt[0]) {
    astSetFitsS ( fitschan, "TAUDATST", tauDatSt,
                  "Time of TAU225ST observation", 0 );

    astSetFitsS ( fitschan, "TAUDATEN", tauDatSt,
                  "Time of TAU225EN observation", 0 );
  } else {
    astSetFitsU ( fitschan, "TAUDATST",
                  "Time of TAU225ST observation", 0 );

    astSetFitsU ( fitschan, "TAUDATEN",
                  "Time of TAU225EN observation", 0 );
  }


  astSetFitsS ( fitschan, "TAUSRC", "CSO225GHZ",
		"Source of the TAU225 value", 0 );

  astSetFitsU ( fitschan, "WVMTAUST", "186GHz Tau from JCMT WVM at start", 0 );

  astSetFitsU ( fitschan, "WVMTAUEN", "185GHz Tau from JCMT WVM at end", 0 );

  astSetFitsU ( fitschan, "WVMDATST", "Time of WVMTAUST", 0 );

  astSetFitsU ( fitschan, "WVMDATEN", "Time of WVMTAUEN", 0 );

  if ( seeingok ) {
    astSetFitsF ( fitschan, "SEEINGST", gsdVars->seeing,
                  "[arcsec] SAO atmospheric seeing (start)", 0 );

    astSetFitsF ( fitschan, "SEEINGEN", gsdVars->seeing,
                  "[arcsec] SAO atmospheric seeing (end)", 0 );

  } else {
    /* Use undefined header value if there was no measurement */
    astSetFitsU ( fitschan, "SEEINGST",
                  "[arcsec] SAO atmospheric seeing (start)", 0 );

    astSetFitsU ( fitschan, "SEEINGEN",
                  "[arcsec] SAO atmospheric seeing (end)", 0 );
  }

  if (seeingok && seeDatSt[0] ) {
    astSetFitsS ( fitschan, "SEEDATST", seeDatSt,
                  "Date/Time of SEEINGST", 0 );

    astSetFitsS ( fitschan, "SEEDATEN", seeDatSt,
                  "Date/Time of SEEINGEN", 0 );
  } else {
    astSetFitsU ( fitschan, "SEEDATST",
                  "Date/Time of SEEINGST", 0 );

    astSetFitsU ( fitschan, "SEEDATEN",
                  "Date/Time of SEEINGEN", 0 );
  }

  astSetFitsU ( fitschan, "FRLEGTST", "[degC] Mean Front leg temperature - Start", 0 );

  astSetFitsU ( fitschan, "FRLEGTEN", "[degC] Mean Front leg temperature - End", 0 );

  astSetFitsU ( fitschan, "BKLEGTST", "[degC] Mean Back leg temperature - Start", 0 );

  astSetFitsU ( fitschan, "BKLEGTEN", "[degC] Mean Back leg temperature - End", 0 );


  /* Switching and Map setup for the observation. */
  astSetFitsCM ( fitschan,
                 "---- Switching and Map setup for the observationi ----", 0 );

  astSetFitsS ( fitschan, "SAM_MODE", samMode,
                "Sampling Mode", 0 );

  astSetFitsS ( fitschan, "SW_MODE", mapVars->swMode,
                "Switch Mode", 0 );

  astSetFitsS ( fitschan, "SKYREFX", mapVars->skyRefX,
                "X co-ord of Reference Position", 0 );

  astSetFitsS ( fitschan, "SKYREFY", mapVars->skyRefY,
                "Y co-ord of Reference Position", 0 );

  astSetFitsS ( fitschan, "OBS_TYPE", obsType,
		"Type of observation", 0 );

  if ( strcmp ( samMode, "grid" ) == 0
       && strcmp ( mapVars->swMode, "chop" ) == 0 ) {

    astSetFitsS ( fitschan, "CHOP_CRD", mapVars->chopCrd,
                  "Chopping co-ordinate system", 0 );

    astSetFitsF ( fitschan, "CHOP_FRQ", gsdVars->chopFrequency,
		  "[Hz] Chop frequency", 0 );

    astSetFitsF ( fitschan, "CHOP_PA", gsdVars->chopPA,
		  "[deg] Chop PA; 0=in lat, 90=in long", 0 );

    astSetFitsF ( fitschan, "CHOP_THR", gsdVars->chopThrow,
		  "[arcsec] Chop throw", 0 );

  } else {

    astSetFitsU ( fitschan, "CHOP_CRD", "Chopping co-ordinate system", 0 );

    astSetFitsU ( fitschan, "CHOP_FRQ", "[Hz] Chop frequency", 0 );

    astSetFitsU ( fitschan, "CHOP_PA", "[deg] Chop PA; 0=in lat, 90=in long", 0 );

    astSetFitsU ( fitschan, "CHOP_THR", "[arcsec] Chop throw", 0 );

  }

  astSetFitsU ( fitschan, "ROT_CRD", "Coordinate frame of image rotator", 0 );

  astSetFitsU ( fitschan, "ROT_PA", "[[deg] Angle of image rotator", 0 );

  astSetFitsU ( fitschan, "JIGL_CNT", "Number of offsets in jiggle pattern", 0 );

  astSetFitsU ( fitschan, "JIGL_NAM", "File containing the jiggle offsets", 0 );

  astSetFitsU ( fitschan, "JIG_PA", "[deg] Jiggle PA; 0=in lat, 90=in long", 0 );

  astSetFitsU ( fitschan, "JIG_CRD", "Jiggling co-ordinate system", 0 );

  astSetFitsU ( fitschan, "JIG_SCAL", "Scale size of jiggle pattern", 0 );

  if ( strcmp ( samMode, "scan" ) == 0
       && strcmp ( mapVars->swMode, "pssw" ) == 0 ) {

    astSetFitsF ( fitschan, "MAP_HGHT", mapVars->mapHght,
		  "[arcsec] Requested height of map", 0 );

    astSetFitsF ( fitschan, "MAP_PA", mapVars->mapPA,
		  "[deg] Requested PA of map", 0 );

    astSetFitsF ( fitschan, "MAP_WDTH", mapVars->mapWdth,
		  "[arcsec] Requested width of map", 0 );

    astSetFitsS ( fitschan, "LOCL_CRD", mapVars->loclCrd,
		  "Local offset/map PA co-ordinate system", 0 );

    astSetFitsF ( fitschan, "MAP_X", gsdVars->centreOffsetX,
		  "[arcsec] Requested map offset from telescope centre", 0 );

    astSetFitsF ( fitschan, "MAP_Y", gsdVars->centreOffsetY,
		  "[arcsec] Requested map offset from telescope centre", 0 );

    astSetFitsS ( fitschan, "SCAN_CRD", mapVars->scanCrd,
		  "Co-ordinate system for scan", 0 );

    astSetFitsF ( fitschan, "SCAN_VEL", mapVars->scanVel,
		  "[arcsec/sec] Scan velocity along scan direction", 0 );

    astSetFitsF ( fitschan, "SCAN_DY", mapVars->scanDy,
		  "[arcsec] Scan spacing perp. to scan", 0 );

    astSetFitsS ( fitschan, "SCAN_PAT", mapVars->scanPat,
		  "Scan pattern name", 0 );

  } else {

    astSetFitsU ( fitschan, "MAP_HGHT", "[arcsec] Requested height of map", 0 );

    astSetFitsU ( fitschan, "MAP_PA", "[deg] Requested PA of map", 0 );

    astSetFitsU ( fitschan, "MAP_WDTH",  "[arcsec] Requested width of map", 0 );

    astSetFitsU ( fitschan, "LOCL_CRD", "Local offset/map PA co-ordinate system", 0 );

    astSetFitsU ( fitschan, "MAP_X", "[arcsec] Requested map offset from telescope centre", 0 );

    astSetFitsU ( fitschan, "MAP_Y", "[arcsec] Requested map offset from telescope centre", 0 );

    astSetFitsU ( fitschan, "SCAN_CRD", "Co-ordinate system for scan", 0 );

    astSetFitsU ( fitschan, "SCAN_VEL", "[arcsec/sec] Scan velocity along scan direction", 0 );

    astSetFitsU ( fitschan, "SCAN_DY", "[arcsec] Scan spacing perp. to scan", 0 );

    astSetFitsU ( fitschan, "SCAN_PAT", "Scan pattern name", 0 );

  }


  /* SMU */
  astSetFitsCM ( fitschan,
                 "---- SMU ----", 0 );

  astSetFitsF ( fitschan, "ALIGN_DX", gsdVars->smuDX,
		"SMU tables X axis focus offset", 0 );

  astSetFitsF ( fitschan, "ALIGN_DY", gsdVars->smuDY,
		"SMU tables Y axis focus offset", 0 );

  astSetFitsF ( fitschan, "FOCUS_DZ", gsdVars->smuDZ,
		"SMU tables Z axis focus offset", 0 );

  astSetFitsF ( fitschan, "DAZ", gsdVars->smuOffsEW,
		"SMU azimuth pointing offset", 0 );

  astSetFitsF ( fitschan, "DEL", gsdVars->smuOffsNS,
		"SMU elevation pointing offset", 0 );

  astSetFitsF ( fitschan, "UAZ", gsdVars->errAz,
		"User azimuth pointing offset", 0 );

  astSetFitsF ( fitschan, "UEL", gsdVars->errEl,
		"User elevation pointing offset", 0 );


  /* JOS parameters */
  astSetFitsCM ( fitschan,
                 "---- JOS parameters ----", 0 );

  astSetFitsF ( fitschan, "STEPTIME", stepTime,
                "RTS step time during an RTS sequence", 0 );

  /* Since coadding is happening in the correlator before writing out
  ** the spectrum, in ACSIS land the number of cycles is 1 instead
  ** of gsdVars->nCycle
  */

  astSetFitsI ( fitschan, "NUM_CYC", 1,
                "Number of times to repeat entire recipe", 0 );

  astSetFitsI ( fitschan, "NUM_NODS", 1,
                "Number of times to repeat nod set", 0 );

  if (josMult == 0) {
    astSetFitsU ( fitschan, "JOS_MULT", "Nr of steps between bsw", 0 );
  } else {
    astSetFitsI ( fitschan, "JOS_MULT", josMult, "Nr of steps between bsw", 0 );
  }

  if (josMin == 0) {
    astSetFitsU ( fitschan, "JOS_MIN", "Nr of steps between psw", 0 );
  } else {
    astSetFitsI ( fitschan, "JOS_MIN", josMin, "Nr of steps between psw", 0 );
  }

  astSetFitsU ( fitschan, "NCALSTEP", "Number of RTS steps for each CAL", 0 );

  astSetFitsF ( fitschan, "NREFSTEP", nRefStep,
		"Mean no. of RTS steps for each REF", 0 );

  if( stBetRef_defined ) {
     astSetFitsI ( fitschan, "STBETREF", stBetRef,
   		   "Target number of RTS steps between REFs", 0 );
  } else {
     astSetFitsU ( fitschan, "STBETREF", "Target number of RTS steps between REFs", 0 );
  }

  astSetFitsU ( fitschan, "STBETCAL", "Target number of RTS steps between CALs",0 );

  astSetFitsI ( fitschan, "STARTIDX", startIdx,
		"Index into pattern at start of obs", 0 );

  astSetFitsU ( fitschan, "FOCAXIS", "Focus Axis to move (X, Y, Z)", 0 );

  astSetFitsU ( fitschan, "NFOCSTEP", "Number of focal position steps", 0 );

  astSetFitsU ( fitschan, "FOCSTEP", "Distance between focal steps", 0 );


  /* Miscellaneous parameters */
  astSetFitsCM ( fitschan,
                 "---- Miscellaneous ----", 0 );

  astSetFitsU ( fitschan, "OCSCFG", "OCS config filename", 0 );

  astSetFitsL ( fitschan, "SIMULATE", 0,
		"True if any data are simulated", 0 );

  astSetFitsL ( fitschan, "SIM_CORR", 0,
		"True if any CORRTASK is simualted", 0 );

  astSetFitsL ( fitschan, "SIM_SMU", 0,
		"True if SMU data is simulated", 0 );

  astSetFitsL ( fitschan, "SIM_TCS", 0,
		"True if TCS data is simulated", 0 );

  astSetFitsL ( fitschan, "SIM_RTS", 0,
		"True if RTS data is simulated", 0 );

  astSetFitsL ( fitschan, "SIM_IF", 0,
		"True if IF data is simulated", 0 );

  astSetFitsS ( fitschan, "STATUS", "NORMAL",
		"Status at end of observation", 0 );


  /* Rover=specific parameters */
  astSetFitsCM ( fitschan,
                 "---- ROVER Specific ----", 0 );

  astSetFitsL ( fitschan, "POL_CONN", 0,
		"True if ROVER is connected", 0 );

  astSetFitsU ( fitschan, "POL_MODE", "Step-and-integrate (STEPINT) or spinning (SPIN)", 0 );

  astSetFitsU ( fitschan, "ROTAFREQ", "[Hz] Spin frequency (if spinning)", 0 );

  astSetFitsU ( fitschan, "POL_CRD", "Coordinate frame of polarimeter angles", 0 );

  astSetFitsU ( fitschan, "POL_PA", "[[deg] Angle of pol fast axis", 0 );

  astSetFitsS ( fitschan, "BUNIT", "K", "", 0 );


}
예제 #14
0
void smf_getrefwcs( const char *param, Grp *igrp, AstFrameSet **specwcs,
                    AstFrameSet **spacewcs, int *isjsa, int *status ){

/* Local Variables */
   AstFrame *frm = NULL;
   AstFrameSet *refwcs = NULL;  /* The WCS FrameSet from the reference NDF */
   AstRegion *circle;
   char text[ 255 ];            /* Parameter value */
   int *tiles;
   int i;
   int jsatiles;
   int lbnd[2];                 /* Lower pixel index bounds of mid tile */
   int ntile;
   int perm[ 2 ];
   int refndf;                  /* NDF identifier for the refence NDF */
   int ubnd[2];                 /* Upper pixel index bounds of mid tile */
   size_t code;
   smfData *data = NULL;        /* Structure describing 1st input file */
   smfJSATiling skytiling;
   smf_inst_t inst = SMF__INST_NONE;
   smf_jsaproj_t proj;          /* Specific JSA projection to use */
   smf_subinst_t subinst;

/* Initialise the returned values. */
   *specwcs = NULL;
   *spacewcs = NULL;
   *isjsa = 0;

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

/* Begin an AST context. */
   astBegin;

/* If the JSAILES parameter is TRUE, then we use the JSA all-sky pixel
   grid regardless of the setting of REF. */
   parGet0l( "JSATILES", &jsatiles, status );
   if( jsatiles ) {
      strcpy( text, "JSA" );
      *isjsa = 1;

/* Otherwise, first get the parameter value as a string. Use subpar to avoid problem
   caused by interpretion of the text within the parameter system. */
   } else {
      subParFindpar( param, &code, status );
      subParGetname( code, text, sizeof(text), status );
   }

/* If no value was supplied, annul the error and do nothing more. */
   if( *status == PAR__NULL ) {
      errAnnul( status );

/* If it is "JSA", or one of the JSA projection codes, we return WCS that
   describes one of the the JSA all-sky pixel grids. */
   } else if( *status == SAI__OK ) {
      proj = smf_jsaproj_fromstr( text, 0, status );
      if( astChrMatch( text, "JSA" ) || proj != SMF__JSA_NULL ) {
         *isjsa = 1;

/* Report an error if the instrument cannot be determined. */
         if( !igrp ) {
            *status = SAI__ERROR;
            errRep( "", "smf_getrefwcs: Cannot use the JSA all-sky pixel "
                    "grid since no input group has been supplied (possibly "
                    "programming error).", status );
         } else {

/* Open the first input file. */
            smf_open_file( NULL, igrp, 1, "READ", SMF__NOCREATE_DATA, &data,
                           status );
            if( *status == SAI__OK ) {

/* Get the instrument. */
               if( data->hdr->instrument == INST__SCUBA2 ) {
                  subinst = smf_calc_subinst( data->hdr, status );
                  if( subinst == SMF__SUBINST_850 ) {
                     inst = SMF__INST_SCUBA_2_850;
                  } else {
                     inst = SMF__INST_SCUBA_2_450;
                  }

               } else if( data->hdr->instrument == INST__ACSIS ) {
                  inst = SMF__INST_ACSIS;

               } else if( *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  if( data->file ) {
                     smf_smfFile_msg( data->file, "FILE", 1, "one or more of "
                                      "the input data files" );
                  } else {
                     msgSetc( "FILE", "one or more of the input data files" );
                  }
                  errRep( "", "No tiles are yet defined for the instrument that "
                          "created ^FILE.", status );
               }

/* Get the parameters that define the layout of sky tiles for the
   instrument. */
               smf_jsatiling( inst, &skytiling, status );

/* For "JSA" - choose the best projection. */
               if( astChrMatch( text, "JSA" ) ) {

/* Use the FITS headers in the first raw data file to create an AST Circle
   describing the approximate area of the observation within the tracking
   system. */
                  circle = smf_mapregion_approx( igrp, status );

/* Convert the circle to ICRS (as used by the JSA all-sky grid). */
                  astSetC( circle, "System", "ICRS" );

/* Get a list of the tiles that touch this circle. */
                  tiles = smf_jsatiles_region( circle, &skytiling,
                                               &ntile, status );

/* Choose the best projection (i.e. the projection that puts the circle
   furthest away from any singularities). */
                  proj = smf_jsaproj( ntile, tiles, &skytiling, status);

/* Free resources. */
                  tiles = astFree( tiles );
                  circle = astAnnul( circle );

/* If a good projection was specified, use it. Otherwise report an error. */
               } else if( proj == SMF__JSA_NULL && *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  errRepf( "", "Bad value '%s' supplied for parameter %s.",
                           status, text, param );
               }

/* Report the projection type. */
               msgOutf( " ", "The %s will be created on the JSA %s "
                        "pixel grid.", status,
                        (data->hdr->instrument==INST__ACSIS)?"cube":"map",
                        smf_jsaproj_tostr( proj ) );

/* All tiles within the same JSA projection use the same WCS, so we get
   the WCS FrameSet for an arbitrary central tile, and use it for the
   full map. The exception is that tiles within the HPX facet that is
   split between bottom-left and top-right, use a different WCS (they
   have different reference points). But our choice of projection should
   mean that the map never falls in that facet. The base Frame will be
   GRID coords within the tile, and the current Frame will be ICRS
   (RA,Dec). */
               smf_jsatile( ((skytiling.ntpf * skytiling.ntpf - 1) * 2) / 3,
                            &skytiling, 0, proj, NULL, spacewcs, NULL, lbnd,
                            ubnd, status );

/* Change the base Frame to be PIXEL. */
               for( i = 1; i <= astGetI( *spacewcs, "NFrame" ); i++ ) {
                  frm = astGetFrame( *spacewcs, i );
                  if( astChrMatch( astGetC( frm, "Domain" ), "PIXEL" ) ) {
                     astSetI( *spacewcs, "Base", i );
                  }
                  frm = astAnnul( frm );
               }
            }

/* Close the current input data file. */
            smf_close_file( NULL, &data, status);
         }

/* Otherwise get the parameter value as an NDF. */
      } else {
         ndfAssoc( param, "READ", &refndf, status );

/* Get the WCS FrameSet from the reference NDF. */
         ndfGtwcs( refndf, &refwcs, status );

/* Attempt to extract a new FrameSet from this WCS FrameSet, in which the
   current Frame is a SkyFrame, and the base Frame is a 2D PIXEL Frame.
   Since the NDF library sets the GRID Frame to be the Base Frame, we need
   to make the PIXEL Frame the base Frame first. The NDF library ensures
   that the pixel Frame is Frame 2. */
         astSetI( refwcs, "Base", 2 );
         *spacewcs = atlFrameSetSplit( refwcs, "SKY", NULL, NULL, status );
         if( !(*spacewcs) ) {
            if( *status == SAI__OK ) {
               ndfMsg( "N", refndf );
               *status = SAI__ERROR;
               errRep( "", "The supplied reference NDF (^N) either has no "
                       "celestial WCS axes, or the celestial axes cannot "
                       "be separated from the non-celestial axes.", status );
            }

/* The rest of makemap assumes that the sky frame axes are in the default
   order (lon,lat). If this is not the case, permute them. */
         } else if( astGetI( *spacewcs, "IsLatAxis(1)" ) ) {
            perm[ 0 ] = 2;
            perm[ 1 ] = 1;
            astPermAxes( *spacewcs, perm );
         }

/* Now look for the spectral WCS (described by a DSBSpecFrame). */
         smf_getspectralwcs( refwcs, 1, specwcs, status );

/* We no longer need the NDF so annul it. */
         ndfAnnul( &refndf, status );
      }
   }

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

/* End the AST context. This will annul all AST objects created within the
   context (except for those that have been exported from the context). */
   astEnd;

}
예제 #15
0
void smf_calcmodel_noi( ThrWorkForce *wf, smfDIMMData *dat, int chunk,
                        AstKeyMap *keymap, smfArray **allmodel, int flags,
                        int *status) {

  /* Local Variables */
  dim_t bolostep;               /* Number of bolos per thread */
  dim_t boxsize;                /* No. of time slices in each noise box */
  smfData *box = NULL;          /* SmfData holding one box of input data */
  size_t bstride;               /* bolometer stride */
  int calcfirst=0;              /* Were bolo noises already measured? */
  int dclimcorr;                /* Min number of correlated steps */
  int dcmaxsteps;               /* Maximum allowed number of dc jumps */
  dim_t dcfitbox;               /* Width of box for DC step detection */
  double dcthresh;              /* Threshold for DC step detection */
  dim_t dcsmooth;               /* Width of median filter in DC step detection*/
  double *din;                  /* Pointer to next input value */
  double *dout;                 /* Pointer to next output value */
  int fillgaps;                 /* If set perform gap filling */
  dim_t i;                      /* Loop counter */
  dim_t ibolo;                  /* Bolometer index */
  int ibox;                     /* Index of current noise box */
  dim_t itime;                  /* Time slice index */
  dim_t idx=0;                  /* Index within subgroup */
  JCMTState *instate=NULL;      /* Pointer to input JCMTState */
  int iw;                       /* Thread index */
  dim_t j;                      /* Loop counter */
  AstKeyMap *kmap=NULL;         /* Local keymap */
  size_t mbstride;              /* model bolometer stride */
  dim_t mntslice;               /* Number of model time slices */
  size_t mtstride;              /* model time slice stride */
  smfArray *model=NULL;         /* Pointer to model at chunk */
  double *model_data=NULL;      /* Pointer to DATA component of model */
  dim_t nbolo;                  /* Number of bolometers */
  int nbox = 0;                 /* Number of noise boxes */
  size_t nchisq;                /* Number of data points in chisq calc */
  dim_t nelbox;                 /* Number of data points in a noise box */
  dim_t ndata;                  /* Total number of data points */
  size_t nflag;                 /* Number of new flags */
  int nleft;                    /* Number of samples not in a noise box */
  dim_t ntslice;                /* Number of time slices */
  int nw;                       /* Number of worker threads */
  size_t pend;                  /* Last non-PAD sample */
  size_t pstart;                /* First non-PAD sample */
  smf_qual_t *qin;              /* Pointer to next input quality value */
  smf_qual_t *qout;             /* Pointer to next output quality value */
  smfArray *qua=NULL;           /* Pointer to RES at chunk */
  smf_qual_t *qua_data=NULL; /* Pointer to RES at chunk */
  smfArray *res=NULL;           /* Pointer to RES at chunk */
  double *res_data=NULL;        /* Pointer to DATA component of res */
  dim_t spikebox=0;             /* Box size for spike detection */
  double spikethresh=0;         /* Threshold for spike detection */
  size_t tend;                  /* Last input sample to copy */
  size_t tstart;                /* First input sample to copy */
  size_t tstride;               /* time slice stride */
  double *var=NULL;             /* Sample variance */
  size_t xbstride;              /* Box bolometer stride */
  int zeropad;                  /* Pad with zeros? */

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

  /* Obtain pointer to sub-keymap containing NOI parameters */
  astMapGet0A( keymap, "NOI", &kmap );

  /* Assert bolo-ordered data */
  smf_model_dataOrder( dat, allmodel, chunk, SMF__RES|SMF__QUA, 0, status );

  /* Obtain pointers to relevant smfArrays for this chunk */
  res = dat->res[chunk];
  qua = dat->qua[chunk];
  model = allmodel[chunk];

  /* Obtain parameters for NOI */

  /* Data-cleaning parameters  */
  smf_get_cleanpar( kmap, res->sdata[0], NULL, &dcfitbox, &dcmaxsteps, &dcthresh,
                    &dcsmooth, &dclimcorr, NULL, &fillgaps, &zeropad, NULL,
                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                    &spikethresh, &spikebox, NULL, NULL, NULL, NULL, NULL, NULL,
                    NULL, NULL, NULL, NULL, status );

  /* Did we already calculate the noise on each detector? */
  astMapGet0I( kmap, "CALCFIRST", &calcfirst );

  /* Initialize chisquared */
  dat->chisquared[chunk] = 0;
  nchisq = 0;

  /* Loop over index in subgrp (subarray) */
  for( idx=0; idx<res->ndat; idx++ ) {

    /* Get pointers to DATA components */
    res_data = (res->sdata[idx]->pntr)[0];
    model_data = (model->sdata[idx]->pntr)[0];
    qua_data = (qua->sdata[idx]->pntr)[0];

    if( (res_data == NULL) || (model_data == NULL) || (qua_data == NULL) ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME ": Null data in inputs", status);
    } else {

      /* Get the raw data dimensions */
      smf_get_dims( res->sdata[idx], NULL, NULL, &nbolo, &ntslice, &ndata,
                    &bstride, &tstride, status );

      /* NOI model dimensions */
      smf_get_dims( model->sdata[idx], NULL, NULL, NULL, &mntslice, NULL,
                    &mbstride, &mtstride, status );

      /* Only estimate the white noise level once at the beginning - the
         reason for this is to make measurements of the convergence
         easier. We either do it prior to the start of iterations (in which
         case the relative weights will be influeced by low-frequency noise,
         this is initialized in smf_model_create), or else we calculate
         the noise after the first iteration. */

      if( (flags & SMF__DIMM_FIRSTITER) && (!calcfirst) ) {

        /* There are two forms for the NOI model: one constant noise value
           for each bolometer, or "ntslice" noise values for each bolometer.
           Handle the first case now. */
        if( mntslice == 1 ) {

          var = astMalloc( nbolo*sizeof(*var) );

          if (var) {

            /* Measure the noise from power spectra */
            smf_bolonoise( wf, res->sdata[idx], 0, 0.5, SMF__F_WHITELO,
                           SMF__F_WHITEHI, 0, zeropad ? SMF__MAXAPLEN : SMF__BADSZT,
                           var, NULL, NULL, status );

            for( i=0; i<nbolo; i++ ) if( !(qua_data[i*bstride]&SMF__Q_BADB) ) {
                /* Loop over time and store the variance for each sample */
                for( j=0; j<mntslice; j++ ) {
                  model_data[i*mbstride+(j%mntslice)*mtstride] = var[i];
                }
              }

            var = astFree( var );
          }


        /* If the NOI model is of the second form, the noise is estimated
           in boxes of samples lasting "NOI.BOX_SIZE" seconds, and then the
           noise level in the box is assigned to all samples in the box. */
        } else if( mntslice == ntslice ) {

          /* If not already done, get NOI.BOX_SIZE and convert from seconds to
             samples. */
          if( idx == 0 ) {
            boxsize = 0;
            smf_get_nsamp( kmap, "BOX_SIZE", res->sdata[0], &boxsize, status );

            msgOutf( "", FUNC_NAME ": Calculating a NOI variance for each "
                     "box of %d samples.", status, (int) boxsize );

            /* Find the indices of the first and last non-PAD sample. */
            smf_get_goodrange( qua_data, ntslice, tstride, SMF__Q_PAD,
                               &pstart, &pend, status );

            /* How many whole boxes fit into this range? */
            nbox = ( pend - pstart + 1 ) / boxsize;
            if( nbox == 0 ) nbox = 1;

            /* How many samples would be left over at the end if we used this
               many boxes? */
            nleft = ( pend - pstart + 1 ) - nbox*boxsize;

            /* Increase "boxsize" to reduce this number as far as possible.
               Any samples that are left over after this increase of boxsize
               will not be used when calculating the noise levels in each
               bolometer. */
            boxsize += nleft/nbox;

            /* Create a smfData to hold one box-worth of input data. We
               do not need to copy jcmtstate information. */
            if( res->sdata[idx]->hdr ) {
               instate = res->sdata[idx]->hdr->allState;
               res->sdata[idx]->hdr->allState = NULL;
            }
            box = smf_deepcopy_smfData( res->sdata[idx], 0,
                                        SMF__NOCREATE_DATA |
                                        SMF__NOCREATE_VARIANCE |
                                        SMF__NOCREATE_QUALITY,
                                        0, 0, status );
            if( instate ) res->sdata[idx]->hdr->allState = instate;

            /* Set the length of the time axis to the box size plus padding,
               and create empty data and quality arrays for it. */
            if( *status == SAI__OK ) {
               box->dims[  box->isTordered?2:0 ] = boxsize + pstart + (ntslice - pend - 1);
               smf_get_dims( box, NULL, NULL, NULL, NULL, &nelbox,
                             &xbstride, NULL, status );
               box->pntr[0] = astMalloc( sizeof( double )*nelbox );
               box->qual = astMalloc( sizeof( smf_qual_t )*nelbox );

               /* For every bolometer, flag the start and end of the quality
                  array as padding, and store zeros in the data array. */
               for( ibolo = 0; ibolo < nbolo; ibolo++ ) {
                  dout = ((double *) box->pntr[0]) + xbstride*ibolo;
                  qout = box->qual + xbstride*ibolo;
                  for( itime = 0; itime < pstart; itime++ ) {
                     *(qout++) = SMF__Q_PAD;
                     *(dout++) = 0.0;
                  }

                  dout = ((double *) box->pntr[0]) + xbstride*ibolo + pstart + boxsize;;
                  qout = box->qual + xbstride*ibolo + pstart + boxsize;
                  for( itime = pend + 1; itime < ntslice; itime++ ) {
                     *(qout++) = SMF__Q_PAD;
                     *(dout++) = 0.0;
                  }
               }
            }
          }

          /* Work space to hold the variance for each bolometer in a box */
          var = astMalloc( nbolo*sizeof(*var) );
          if( *status == SAI__OK ) {

            /* Index of the first time slice within the input smfData
               that is included in the first box. */
            tstart = pstart;

            /* Loop round each noise box */
            for( ibox = 0; ibox < nbox; ibox++ ) {

               /* Copy the data and quality values for this box from the
                 input smfData into "box", leaving room for padding at
                 both ends of box. Note, data is bolo-ordered so we
                 can assume that "tstride" is 1. */
               din = ((double *)(res->sdata[idx]->pntr[0])) + tstart;
               dout = ((double *)(box->pntr[0])) + pstart;
               qin = qua_data + tstart;
               qout = box->qual + pstart;

               for( ibolo = 0; ibolo < nbolo; ibolo++ ) {
                  memcpy( dout, din, boxsize*sizeof( *din ) );
                  memcpy( qout, qin, boxsize*sizeof( *qin ) );
                  din += bstride;
                  dout += xbstride;
                  qin += bstride;
                  qout += xbstride;
               }

               /* Measure the noise from power spectra in the box. */
               smf_bolonoise( wf, box, 0, 0.5, SMF__F_WHITELO, SMF__F_WHITEHI,
                              0, zeropad ? SMF__MAXAPLEN : SMF__BADSZT, var,
                              NULL, NULL, status );

               /* Loop over time and store the variance for each sample in
                  the NOI model. On the last box, pick up any left over time
                  slices. */
               if( ibox < nbox - 1 ) {
                  tend = tstart + boxsize - 1;
               } else {
                  tend = pend;
               }

               for( ibolo = 0; ibolo < nbolo; ibolo++ ) {
                  if( !( qua_data[ ibolo*bstride ] & SMF__Q_BADB ) ) {
                     dout =  model_data + ibolo*bstride + tstart;
                     for( itime = tstart; itime <= tend; itime++ ) {
                        *(dout++) = var[ ibolo ];
                     }
                  }
               }

               /* Update the index of the first time slice within the input
                  smfData that is included in the next box. */
               tstart += boxsize;
            }

            var = astFree( var );
          }

        /* Report an error if the number of samples for each bolometer in
           the NOI model is not 1 or "ntslice". */
        } else if( *status == SAI__OK ) {
           *status = SAI__ERROR;
           errRepf( "", FUNC_NAME ": NOI model has %d samples - should be "
                    "%d or 1.", status, (int) mntslice, (int) ntslice);
        }
      }

      if( kmap ) {
        /* Flag spikes in the residual after first iteration */
        if( spikethresh && !(flags&SMF__DIMM_FIRSTITER) ) {
          /* Now re-flag */
          smf_flag_spikes( wf, res->sdata[idx], SMF__Q_MOD,
                           spikethresh, spikebox, &nflag, status );
          msgOutiff(MSG__VERB," ", "   flagged %zu new %lf-sig spikes",
                    status, nflag, spikethresh );
        }

        if( dcthresh && dcfitbox ) {
          smf_fix_steps( wf, res->sdata[idx], dcthresh, dcsmooth,
                         dcfitbox, dcmaxsteps, dclimcorr, 1, &nflag, NULL,
                         NULL, status );
          msgOutiff(MSG__VERB, "","   detected %zu bolos with DC steps\n",
                    status, nflag);
        }

      }

      /* Now calculate contribution to chi^2. This bit takes along time
         if there is a lot of data so share the work out amongst the available
         worker threads. How many threads do we get to play with */
      nw = wf ? wf->nworker : 1;

      /* Find how many bolometers to process in each worker thread. */
      bolostep = nbolo/nw;
      if( bolostep == 0 ) bolostep = 1;

      /* Allocate job data for threads, and store the range of bolos to be
         processed by each one. Ensure that the last thread picks up any
         left-over bolos. */
      SmfCalcModelNoiData *job_data = astCalloc( nw, sizeof(*job_data) );
      if( *status == SAI__OK ) {
        SmfCalcModelNoiData *pdata;

        for( iw = 0; iw < nw; iw++ ) {
           pdata = job_data + iw;
           pdata->b1 = iw*bolostep;
           if( iw < nw - 1 ) {
              pdata->b2 = pdata->b1 + bolostep - 1;
           } else {
              pdata->b2 = nbolo - 1 ;
           }

           /* Store other values common to all jobs. */
           pdata->ntslice = ntslice;
           pdata->mntslice = mntslice;
           pdata->qua_data = qua_data;
           pdata->model_data = model_data;
           pdata->res_data = res_data;
           pdata->bstride = bstride;
           pdata->tstride = tstride;
           pdata->mbstride = mbstride;
           pdata->mtstride = mtstride;

           /* Submit the job to the workforce. */
           thrAddJob( wf, 0, pdata, smf1_calcmodel_noi, 0, NULL, status );
        }

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

        /* Accumulate the results from all the worker threads. */
        for( iw = 0; iw < nw; iw++ ) {
           pdata = job_data + iw;
           dat->chisquared[chunk] += pdata->chisquared;
           nchisq += pdata->nchisq;
        }

/* Free the job data. */
        job_data = astFree( job_data );
      }
    }
  }

  /* Free resources */
  if( box ) {
     box->pntr[0] = astFree( box->pntr[0] );
     box->qual = astFree( box->qual );
     smf_close_file( &box, status );
  }

  /* Normalize chisquared for this chunk */
  if( (*status == SAI__OK) && (nchisq >0) ) {
    dat->chisquared[chunk] /= (double) nchisq;
  }

  /* Clean Up */
  if( kmap ) kmap = astAnnul( kmap );
}
예제 #16
0
void smurf_unmakemap( int *status ) {

/* Local Variables */
   AstFrameSet *wcsin = NULL; /* WCS Frameset for input cube */
   AstMapping *skymap;        /* GRID->SkyFrame Mapping from input WCS */
   AstSkyFrame *abskyfrm;     /* Input SkyFrame (always absolute) */
   AstSkyFrame *skyfrm = NULL;/* SkyFrame from the input WCS Frameset */
   Grp *igrp1 = NULL;         /* Group of input sky files */
   Grp *igrp2 = NULL;         /* Group of input template files */
   Grp *igrpc = NULL;         /* Group of input COM files */
   Grp *igrpg = NULL;         /* Group of input GAI files */
   Grp *igrpq = NULL;         /* Group of input Q  sky files */
   Grp *igrpu = NULL;         /* Group of input U sky files */
   Grp *ogrp = NULL;          /* Group containing output file */
   HDSLoc *cloc = NULL;       /* HDS locator for component ipdata structure */
   HDSLoc *iploc = NULL;      /* HDS locator for top level ipdata structure */
   ThrWorkForce *wf = NULL;   /* Pointer to a pool of worker threads */
   char ipdata[ 200 ];        /* Text buffer for IPDATA value */
   char pabuf[ 10 ];          /* Text buffer for parameter value */
   char subarray[ 5 ];        /* Name of SCUBA-2 subarray (s8a,s8b,etc) */
   dim_t iel;                 /* Index of next element */
   dim_t ndata;               /* Number of elements in array */
   dim_t ntslice;             /* Number of time slices in array */
   double *ang_data = NULL;   /* Pointer to the FP orientation angles */
   double *angc_data = NULL;  /* Pointer to the instrumental ANGC data */
   double *c0_data = NULL;    /* Pointer to the instrumental C0 data */
   double *gai_data = NULL;   /* Pointer to the input GAI map */
   double *in_data = NULL;    /* Pointer to the input I sky map */
   double *inc_data = NULL;   /* Pointer to the input COM data */
   double *inq_data = NULL;   /* Pointer to the input Q sky map */
   double *inu_data = NULL;   /* Pointer to the input U sky map */
   double *outq_data = NULL;  /* Pointer to the Q time series data */
   double *outu_data = NULL;  /* Pointer to the U time series data */
   double *p0_data = NULL;    /* Pointer to the instrumental P0 data */
   double *p1_data = NULL;    /* Pointer to the instrumental P1 data */
   double *pd;                /* Pointer to next element */
   double *pq = NULL;         /* Pointer to next Q time series value */
   double *pu = NULL;         /* Pointer to next U time series value */
   double *qinst_data = NULL; /* Pointer to the instrumental Q data */
   double *uinst_data = NULL; /* Pointer to the instrumental U data */
   double amp16;              /* Amplitude of 16 Hz signal */
   double amp2;               /* Amplitude of 2 Hz signal */
   double amp4;               /* Amplitude of 4 Hz signal */
   double angrot;             /* Angle from focal plane X axis to fixed analyser */
   double paoff;              /* WPLATE value corresponding to POL_ANG=0.0 */
   double params[ 4 ];        /* astResample parameters */
   double phase16;            /* Phase of 16 Hz signal */
   double phase2;             /* Phase of 2 Hz signal */
   double phase4;             /* Phase of 4 Hz signal */
   double sigma;              /* Standard deviation of noise to add to output */
   int alignsys;              /* Align data in the map's system? */
   int cdims[ 3 ];            /* Common-mode NDF dimensions */
   int dims[ NDF__MXDIM ];    /* NDF dimensions */
   int flag;                  /* Was the group expression flagged? */
   int gdims[ 3 ];            /* GAI model NDF dimensions */
   int harmonic;              /* The requested harmonic */
   int ifile;                 /* Input file index */
   int indf;                  /* Input sky map NDF identifier */
   int indfangc;              /* IP ANGC values NDF identifier */
   int indfc0;                /* IP C0 values NDF identifier */
   int indfc;                 /* Input COM NDF identifier */
   int indfcs;                /* NDF identifier for matching section of COM */
   int indfg;                 /* Input GAI NDF identifier */
   int indfin;                /* Input template cube NDF identifier */
   int indfiq;                /* Input instrumental Q NDF */
   int indfiu;                /* Input instrumental U NDF */
   int indfout;               /* Output cube NDF identifier */
   int indfp0;                /* IP P0 values NDF identifier */
   int indfp1;                /* IP P1 values NDF identifier */
   int indfq;                 /* Input Q map NDF identifier */
   int indfu;                 /* Input U map NDF identifier */
   int interp = 0;            /* Pixel interpolation method */
   int lbndc[ 3 ];            /* Array of lower bounds of COM NDF */
   int moving;                /* Is the telescope base position changing? */
   int ndim;                  /* Number of pixel axes in NDF */
   int ndimc;                 /* Number of pixel axes in common-mode NDF */
   int ndimg;                 /* Number of pixel axes in GAI NDF */
   int nel;                   /* Number of elements in array */
   int nelc;                  /* Number of elements in COM array */
   int nelg;                  /* Number of elements in GAI array */
   int nelqu;                 /* Number of elements in Q or U array */
   int ngood;                 /* No. of good values in putput cube */
   int nparam = 0;            /* No. of parameters required for interpolation scheme */
   int pasign;                /* Indicates sense of POL_ANG value */
   int sdim[ 2 ];             /* Array of significant pixel axes */
   int slbnd[ 2 ];            /* Array of lower bounds of input map */
   int subnd[ 2 ];            /* Array of upper bounds of input map */
   int ubndc[ 3 ];            /* Array of upper bounds of COM NDF */
   size_t ncom;               /* Number of com files */
   size_t ngai;               /* Number of gai files */
   size_t nskymap;            /* Number of supplied sky cubes */
   size_t outsize;            /* Number of files in output group */
   size_t size;               /* Number of files in input group */
   smfData *odata = NULL;     /* Pointer to output data struct */

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

/* Begin an AST context */
   astBegin;

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

/* Find the number of cores/processors available and create a pool of
   threads of the same size. */
   wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status );

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

/* Map the data array in the input sky map. */
   ndfMap( indf, "DATA", "_DOUBLE", "READ", (void **) &in_data, &nel,
           status );

/* Get the WCS FrameSet from the sky map, together with its pixel index
   bounds. */
   kpg1Asget( indf, 2, 0, 1, 1, sdim, slbnd, subnd, &wcsin, status );

/* Check the current Frame is a SKY frame. */
   skyfrm = astGetFrame( wcsin, AST__CURRENT );
   if( !astIsASkyFrame( skyfrm ) && *status == SAI__OK ) {
      ndfMsg( "N", indf );
      *status = SAI__ERROR;
      errRep( " ", " Current Frame in ^N is not a SKY Frame.", status );
   }

/* Get a copy of the current frame that represents absolute coords rather
   than offsets. We assume the target is moving if the map represents
   offsets. */
   moving = ( *status == SAI__OK &&
              !strcmp( astGetC( skyfrm, "SkyRefIs" ), "Origin" ) ) ? 1 : 0;
   abskyfrm = astCopy( skyfrm );
   astClear( abskyfrm, "SkyRefIs" );

/* If the ALIGNSYS parameter is TRUE then we align the raw data with the
   map in the current system of the map, rather than the default ICRS. */
   parGet0l( "ALIGNSYS", &alignsys, status );
   if( alignsys ) astSetC( abskyfrm, "AlignSystem", astGetC( abskyfrm,
                                                             "System" ) );

/* Get the Mapping from the Sky Frame to grid axis in the iput map. */
   skymap = astGetMapping( wcsin, AST__CURRENT, AST__BASE );

/* Get the pixel interpolation scheme to use. */
   parChoic( "INTERP", "NEAREST", "NEAREST,LINEAR,SINC,"
             "SINCSINC,SINCCOS,SINCGAUSS,SOMB,SOMBCOS",
             1, pabuf, 10, status );

   if( !strcmp( pabuf, "NEAREST" ) ) {
      interp = AST__NEAREST;
      nparam = 0;

   } else if( !strcmp( pabuf, "LINEAR" ) ) {
      interp = AST__LINEAR;
      nparam = 0;

   } else if( !strcmp( pabuf, "SINC" ) ) {
      interp = AST__SINC;
      nparam = 1;

   } else if( !strcmp( pabuf, "SINCSINC" ) ) {
      interp = AST__SINCSINC;
      nparam = 2;

   } else if( !strcmp( pabuf, "SINCCOS" ) ) {
      interp = AST__SINCCOS;
      nparam = 2;

   } else if( !strcmp( pabuf, "SINCGAUSS" ) ) {
      interp = AST__SINCGAUSS;
      nparam = 2;

   } else if( !strcmp( pabuf, "SOMB" ) ) {
      interp = AST__SOMB;
      nparam = 1;

   } else if( !strcmp( pabuf, "SOMBCOS" ) ) {
      interp = AST__SOMBCOS;
      nparam = 2;

   } else if( *status == SAI__OK ) {
      nparam = 0;
      *status = SAI__ERROR;
      msgSetc( "V", pabuf );
      errRep( "", "Support not available for INTERP = ^V (programming "
              "error)", status );
   }

/* Get an additional parameter vector if required. */
   if( nparam > 0 ) parExacd( "PARAMS", nparam, params, status );

/* Get a group of reference time series files to use as templates for
   the output time series files.*/
   ndgAssoc( "REF", 1, &igrp2, &size, &flag, status );

/* Get output file(s) */
   kpg1Wgndf( "OUT", igrp2, size, size, "More output files required...",
              &ogrp, &outsize, status );

/* Get he noise level to add to the output data. */
   parGet0d( "SIGMA", &sigma, status );

/* Get any Q and U input maps. */
   if( *status == SAI__OK ) {

      kpg1Rgndf( "QIN", 1, 1, "", &igrpq, &nskymap, status );
      ndgNdfas( igrpq, 1, "READ", &indfq, status );
      ndfMap( indfq, "DATA", "_DOUBLE", "READ", (void **) &inq_data, &nelqu,
              status );
      if( nelqu != nel && *status == SAI__OK ) {
         ndfMsg( "Q", indfq );
         *status = SAI__ERROR;
         errRep( "", "Q image '^Q' is not the same size as the I image.",
                 status );
      }

      kpg1Rgndf( "UIN", 1, 1, "", &igrpu, &nskymap, status );
      ndgNdfas( igrpu, 1, "READ", &indfu, status );
      ndfMap( indfu, "DATA", "_DOUBLE", "READ", (void **) &inu_data, &nelqu,
              status );
      if( nelqu != nel && *status == SAI__OK ) {
         ndfMsg( "U", indfu );
         *status = SAI__ERROR;
         errRep( "", "U image '^U' is not the same size as the I image.",
                 status );
      }

      if( *status == PAR__NULL ) {
         ndfAnnul( &indfq, status );
         ndfAnnul( &indfu, status );
         inq_data = NULL;
         inu_data = NULL;
         errAnnul( status );
      } else {
         parGet0d( "ANGROT", &angrot, status );
         parGet0d( "PAOFF", &paoff, status );
         parGet0l( "PASIGN", &pasign, status );
      }
   }

/* Get any common-mode files. */
   if( *status == SAI__OK ) {
      kpg1Rgndf( "COM", size, size, "", &igrpc, &ncom, status );
      if( *status == PAR__NULL ) {
         errAnnul( status );
         ncom = 0;
      }
   }

/* Get any GAI files. */
   if( *status == SAI__OK ) {
      kpg1Rgndf( "GAI", size, size, "", &igrpg, &ngai, status );
      if( *status == PAR__NULL ) {
         errAnnul( status );
         ngai = 0;
      }
   }

/* Get any instrumental polarisation files. */
   if( *status == SAI__OK ) {

/* First see if the user wants to use the "INSTQ/INSTU" scheme for
   specifying instrumental polarisation. */
      ndfAssoc( "INSTQ", "Read", &indfiq, status );
      ndfAssoc( "INSTU", "Read", &indfiu, status );

      if( *status == PAR__NULL ) {
         ndfAnnul( &indfiq, status );
         ndfAnnul( &indfiu, status );
         errAnnul( status );

      } else {
         msgOut( " ", "Using user-defined IP model", status );

         ndfDim( indfiq, 2, dims, &ndim, status );
         if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indfiq );
            errRep( " ", "Instrumental polarisation file ^N has bad "
                    "dimensions - should be 32x40.", status );
         } else {
            ndfMap( indfiq, "DATA", "_DOUBLE", "READ", (void **) &qinst_data,
                    &nel, status );
         }

         ndfDim( indfiu, 2, dims, &ndim, status );
         if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indfiu );
            errRep( " ", "Instrumental polarisation file ^N has bad "
                    "dimensions - should be 32x40.", status );
         } else {
            ndfMap( indfiu, "DATA", "_DOUBLE", "READ", (void **) &uinst_data,
                    &nel, status );
         }
      }

/* If not, see if the user wants to use the Johnstone/Kennedy instrumental
   polarisation model. The IPDATA parameter gives the path to an HDS
   container file contining NDFs holding the required IP data for all
   subarrays. */
      if( !qinst_data ) {
         parGet0c( "IPDATA", ipdata, sizeof(ipdata), status );
         if( *status == PAR__NULL ) {
            errAnnul( status );
         } else {
            msgOutf( " ", "Using Johnstone/Kennedy IP model in %s",
                     status, ipdata );
            hdsOpen( ipdata, "READ", &iploc, status );
         }
      }
   }

/* Loop round all the template time series files. */
   for( ifile = 1; ifile <= (int) size && *status == SAI__OK; ifile++ ) {

/* Start a new NDF context. */
      ndfBegin();

/* Create the output NDF by propagating everything from the input, except
   for quality and variance. */
      ndgNdfas( igrp2, ifile, "READ", &indfin, status );

      ndfMsg( "FILE", indfin );
      msgSeti( "THISFILE", ifile );
      msgSeti( "NUMFILES", size );
      msgOutif( MSG__NORM, " ", "Simulating ^THISFILE/^NUMFILES ^FILE",
                status );

      ndgNdfpr( indfin, "DATA,HISTORY,LABEL,TITLE,WCS,UNITS,EXTENSION(*)",
                ogrp, ifile, &indfout, status );
      ndfAnnul( &indfin, status );
      ndfAnnul( &indfout, status );

/* We now re-open the output NDF and then modify its data values. */
      smf_open_file( wf, ogrp, ifile, "UPDATE", 0, &odata, status );

/* Issue a suitable message and abort if anything went wrong. */
      if( *status != SAI__OK ) {
         errRep( FUNC_NAME, "Could not open input template file.", status );
         break;

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

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

/* Check the reference time series contains double precision values. */
      smf_dtype_check_fatal( odata, NULL, SMF__DOUBLE, status );

/* Get the total number of data elements, and the number of time slices. */
      smf_get_dims( odata, NULL, NULL, NULL, &ntslice, &ndata, NULL,
                    NULL, status );

/* Get the subarray name */
      smf_fits_getS( odata->hdr, "SUBARRAY", subarray, sizeof(subarray),
                     status );

/* If we are using the Johnstone/Kennedy IP model, open and map the
   relevant parameter NDFs within the IPDATA container file. */
      if( iploc ) {
         datFind( iploc, subarray, &cloc, status );

         ndfFind( cloc, "C0", &indfc0, status );
         ndfDim( indfc0, 2, dims, &ndim, status );
         if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indfc0 );
            errRep( " ", "Instrumental polarisation file ^N has bad "
                    "dimensions - should be 32x40.", status );
         } else {
            ndfMap( indfc0, "DATA", "_DOUBLE", "READ", (void **) &c0_data,
                    &nel, status );
         }

         ndfFind( cloc, "P0", &indfp0, status );
         ndfDim( indfp0, 2, dims, &ndim, status );
         if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indfp0 );
            errRep( " ", "Instrumental polarisation file ^N has bad "
                    "dimensions - should be 32x40.", status );
         } else {
            ndfMap( indfp0, "DATA", "_DOUBLE", "READ", (void **) &p0_data,
                    &nel, status );
         }

         ndfFind( cloc, "P1", &indfp1, status );
         ndfDim( indfp1, 2, dims, &ndim, status );
         if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indfp1 );
            errRep( " ", "Instrumental polarisation file ^N has bad "
                    "dimensions - should be 32x40.", status );
         } else {
            ndfMap( indfp1, "DATA", "_DOUBLE", "READ", (void **) &p1_data,
                    &nel, status );
         }

         ndfFind( cloc, "ANGC", &indfangc, status );
         ndfDim( indfangc, 2, dims, &ndim, status );
         if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indfangc );
            errRep( " ", "Instrumental polarisation file ^N has bad "
                    "dimensions - should be 32x40.", status );
         } else {
            ndfMap( indfangc, "DATA", "_DOUBLE", "READ", (void **) &angc_data,
                    &nel, status );
         }
      }

/* Open any COM file. */
      if( ncom ) {
         ndgNdfas( igrpc, ifile, "READ", &indfc, status );
         ndfDim( indfc, 3, cdims, &ndimc, status );

/* Check its dimensions. */
         if( *status == SAI__OK ) {
            if( ndimc == 1 ) {
               if( cdims[ 0 ] < (int) ntslice ) {
                  *status = SAI__ERROR;
                  ndfMsg( "C", indfc );
                  ndfMsg( "R", indfin );
                  msgSeti( "N", cdims[ 0 ] );
                  msgSeti( "M", ntslice );
                  errRep( " ", "Supplied COM file (^C) has ^N time-slices, but "
                          "the reference NDF (^R) has ^M time-slices.", status );
               } else {
                  ndfBound( indfc, 3, lbndc, ubndc, &ndimc, status );
                  ubndc[ 0 ] = lbndc[ 0 ] + ntslice - 1;
                  ndfSect( indfc, 1, lbndc, ubndc, &indfcs, status );
               }
            } else if( ndimc == 3 ) {
               if( cdims[ 0 ] != 1 || cdims[ 1 ] != 1 ) {
                  *status = SAI__ERROR;
                  ndfMsg( "C", indfc );
                  errRep( " ", "Supplied 3D COM file (^C) has bad "
                          "dimensions for axis 1 and/or 2 (should "
                          "both be 1 pixel long).", status );
               } else if( cdims[ 2 ] < (int) ntslice ) {
                  *status = SAI__ERROR;
                  ndfMsg( "C", indfc );
                  ndfMsg( "R", indfin );
                  msgSeti( "N", cdims[ 2 ] );
                  msgSeti( "M", ntslice );
                  errRep( " ", "Supplied COM file (^C) has ^N time-slices, but "
                          "the reference NDF (^R) has ^M time-slices.", status );
               } else {
                  ndfBound( indfc, 3, lbndc, ubndc, &ndimc, status );
                  ubndc[ 2 ] = lbndc[ 2 ] + ntslice - 1;
                  ndfSect( indfc, 3, lbndc, ubndc, &indfcs, status );
               }
            } else {
               *status = SAI__ERROR;
               ndfMsg( "C", indfc );
               msgSeti( "N", ndimc );
               errRep( " ", "Supplied COM file (^C) has ^N dimensions - "
                       "must be 3.", status );
            }
         }

         ndfMap( indfcs, "DATA", "_DOUBLE", "READ", (void **) &inc_data,
                 &nelc, status );

      } else {
         indfcs = NDF__NOID;
         inc_data = NULL;
      }

/* Open any GAI files. */
      if( ngai ) {
         ndgNdfas( igrpg, ifile, "READ", &indfg, status );
         ndfDim( indfg, 3, gdims, &ndimg, status );

/* Check its dimensions, and map it if OK. */
         if( *status == SAI__OK ) {
            if( ndimg != 2 ) {
               *status = SAI__ERROR;
               ndfMsg( "C", indfg );
               msgSeti( "N", ndimg );
               errRep( " ", "Supplied GAI file (^C) has ^N dimensions - "
                       "must be 2.", status );
            } else if( gdims[ 0 ] != 32 || gdims[ 1 ] != 40 ) {
               *status = SAI__ERROR;
               ndfMsg( "C", indfg );
               errRep( " ", "Supplied GAI file (^C) has has bad "
                       "dimensions - should be 32x40.", status );
            }
         }
         ndfMap( indfg, "DATA", "_DOUBLE", "READ", (void **) &gai_data,
                 &nelg, status );

      } else {
         indfg = NDF__NOID;
         gai_data = NULL;
      }

/* Fill the output with bad values. */
      if( *status == SAI__OK ) {
         pd = odata->pntr[ 0 ];
         for( iel = 0; iel < ndata; iel++ ) *(pd++) = VAL__BADD;
      }

/* Resample the sky map data into the output time series. */
      smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd,
                     interp, params, sigma, in_data, odata->pntr[ 0 ],
                     NULL, &ngood, status );

/* Add on any COM data. */
      smf_addcom( wf, odata, inc_data, status );

/* Issue a wrning if there is no good data in the output cube. */
      if( ngood == 0 ) msgOutif( MSG__NORM, " ", "   Output contains no "
                                 "good data values.", status );

/* If Q and U maps have been given, allocate room to hold resampled Q and
   U values, and fill them with bad values. */
      if( inq_data && inu_data ) {
         pq = outq_data = astMalloc( ndata*sizeof( *outq_data ) );
         pu = outu_data = astMalloc( ndata*sizeof( *outu_data ) );
         if( *status == SAI__OK ) {
            for( iel = 0; iel < ndata; iel++ ) {
               *(pu++) = VAL__BADD;
               *(pq++) = VAL__BADD;
            }
         }

/* Determine the harmonic to use. */
         parGet0i( "HARMONIC", &harmonic, status );

/* If producing the normal 8 Hz harmonic, get the amplitude and phase of a
   other signals to add onto the 8 Hz signal. */
         if( harmonic == 4 ) {
            parGet0d( "AMP2", &amp2, status );
            parGet0d( "PHASE2", &phase2, status );
            parGet0d( "AMP4", &amp4, status );
            parGet0d( "PHASE4", &phase4, status );
            parGet0d( "AMP16", &amp16, status );
            parGet0d( "PHASE16", &phase16, status );
         } else {
            amp2 = 0.0;
            phase2 = 0.0;
            amp4 = 0.0;
            phase4 = 0.0;
            amp16 = 0.0;
            phase16 = 0.0;
         }

/* Allocate room for an array to hold the angle from the Y pixel axis
   in the sky map to the focal plane Y axis, in radians, at each time
   slice. Positive rotation is in the same sense as rotation from
   focal plane X to focal plane Y. */
         ang_data = astMalloc( ntslice*sizeof( *ang_data ) );

/* Resample them both into 3D time series. These Q/U values arw with
  respect to the sky image Y axis. */
         smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd,
                        interp, params, sigma, inq_data, outq_data,
                        ang_data, &ngood, status );
         smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd,
                        interp, params, sigma, inu_data, outu_data,
                        NULL, &ngood, status );

/* Combine these time series with the main output time series so that the
   main output is analysed intensity. */
         smf_uncalc_iqu( wf, odata, odata->pntr[ 0 ], outq_data, outu_data,
                         ang_data, pasign, AST__DD2R*paoff, AST__DD2R*angrot,
                         amp2, AST__DD2R*phase2, amp4, AST__DD2R*phase4,
                         amp16, AST__DD2R*phase16, qinst_data, uinst_data,
                         c0_data, p0_data, p1_data, angc_data, harmonic,
                         status );

/* Release work space. */
         outq_data = astFree( outq_data );
         outu_data = astFree( outu_data );
         ang_data = astFree( ang_data );
      }

/* Factor in any GAI data. */
      smf_addgai( wf, odata, gai_data, status );

/* Close the output time series file. */
      smf_close_file( wf, &odata, status );

/* Close the IP data container for the current subarray, if it is open. */
      if( cloc ) datAnnul( &cloc, status );

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

/* Close any input data file that is still open due to an early exit from
   the above loop. */
   if( odata != NULL ) {
      smf_close_file( wf, &odata, status );
      odata = NULL;
   }

/* Free remaining resources. */
   if( igrp1 != NULL) grpDelet( &igrp1, status);
   if( igrp2 != NULL) grpDelet( &igrp2, status);
   if( igrpq != NULL) grpDelet( &igrpq, status);
   if( igrpu != NULL) grpDelet( &igrpu, status);
   if( igrpc != NULL) grpDelet( &igrpc, status);
   if( igrpg != NULL) grpDelet( &igrpg, status);
   if( ogrp != NULL) grpDelet( &ogrp, status);
   if( iploc ) datAnnul( &iploc, status );

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

/* End the tile's AST context. */
   astEnd;

/* Issue a status indication.*/
   if( *status == SAI__OK ) {
      msgOutif(MSG__VERB," ",TASK_NAME " succeeded, time series written.", status);
   } else {
      msgOutif(MSG__VERB," ",TASK_NAME " failed.", status);
   }
}
예제 #17
0
/* Main entry */
void smf_jsadicer( int indf, const char *base, int trim, smf_inst_t instrument,
                   smf_jsaproj_t proj, size_t *ntile, Grp *grp, int *status ){

/* Local Variables: */
   AstBox *box;
   AstFitsChan *fc;
   AstFrame *specfrm = NULL;
   AstFrame *tile_frm = NULL;
   AstFrameSet *iwcs;
   AstFrameSet *tfs = NULL;
   AstFrameSet *tile_wcs;
   AstMapping *ndf_map = NULL;
   AstMapping *p2pmap = NULL;
   AstMapping *specmap = NULL;
   AstMapping *tile_map = NULL;
   AstRegion *region;
   Grp *grpt = NULL;
   char *path;
   char dtype[ NDF__SZFTP + 1 ];
   char jsatile_comment[45];
   char type[ NDF__SZTYP + 1 ];
   const char *dom = NULL;
   const char *keyword;
   const char *latsys = NULL;
   const char *lonsys = NULL;
   double *pd;
   double dlbnd[3];
   double dubnd[3];
   double gcen[3];
   double lbnd_in[3];
   double lbnd_out[3];
   double ubnd_in[3];
   double ubnd_out[3];
   float *pf;
   int *created_tiles = NULL;
   int *tiles;
   int axlat;
   int axlon;
   int axspec;
   int bbox[ 6 ];
   int i;
   int ifrm;
   int igrid;
   int indfo;
   int indfs;
   int indfx;
   int inperm[3];
   int ipixel;
   int ishpx;
   int isxph;
   int itile;
   int ix;
   int iy;
   int iz;
   int junk;
   int latax = -1;
   int lbnd[3];
   int lbnd_tile[ 3 ];
   int lbndx[ NDF__MXDIM ];
   int lonax = -1;
   int nbase;
   int ndim;
   int ndimx;
   int nfrm;
   int nsig;
   int ntiles;
   int olbnd[ 3 ];
   int oubnd[ 3 ];
   int outperm[ 3 ];
   int place;
   int qual;
   int tile_index;
   int tile_lbnd[2];
   int tile_ubnd[2];
   int ubnd[3];
   int ubnd_tile[ 3 ];
   int ubndx[ NDF__MXDIM ];
   int var;
   size_t iext;
   size_t size;
   smfJSATiling tiling;
   unsigned char *ipq = NULL;
   void *ipd = NULL;
   void *ipv = NULL;

/* Initialise */
   *ntile = 0;

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

/* Begin an AST context. */
   astBegin;

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

/* Note the used length of the supplied base string. If it ends with
   ".sdf", reduce it by 4. */
   nbase = astChrLen( base );
   if( !strcmp( base + nbase - 4, ".sdf" ) ) nbase -= 4;

/* Allocate a buffer large enough to hold the full path for an output NDF. */
   path = astMalloc( nbase + 25 );

/* Get the WCS from the NDF. */
   kpg1Gtwcs( indf, &iwcs, status );

/* Note if the NDF projection is HPX or XPH. */
   ishpx = astChrMatch( astGetC( iwcs, "Projection" ), "HEALPix" );
   isxph = astChrMatch( astGetC( iwcs, "Projection" ), "polar HEALPix" );

/* Report an error if the NDFs projection is neither of these. */
   if( !ishpx && !isxph && *status == SAI__OK ) {
      ndfMsg( "N", indf );
      *status = SAI__ERROR;
      errRep( "", "The input NDF (^N) does not appear to be gridded "
              "on the JSA all-sky pixel grid.", status );
   }

/* Get the bounds of the NDF in pixel indices and the the corresponding
   double precision GRID bounds (reduce the size of the grid by a small
   amount to avoid problems with tiles that are on the edge of the valid sky
   regions - astMapRegion can report an error for such tiles). Also store
   the GRID coords of the centre. Also count the number of significant
   pixel axes. */
   ndfBound( indf, 3, lbnd, ubnd, &ndim, status );
   nsig = 0;
   for( i = 0; i < ndim; i++ ) {
      dlbnd[ i ] = 0.5 + 0.1;
      dubnd[ i ] = ubnd[ i ] - lbnd[ i ]  + 1.5 - 0.1;
      gcen[ i ] = 0.5*( dlbnd[ i ] + dubnd[ i ] );
      if( ubnd[ i ] > lbnd[ i ] ) nsig++;
   }

/* Find the one-based indices of the RA, Dec and spectral axes in the
   current Frame of the NDF. */
   axlon = 0;
   if( astGetI( iwcs, "IsLonAxis(1)" ) ) {
      axlon = 1;
      lonsys = astGetC( iwcs, "System(1)" );
   } else if( astGetI( iwcs, "IsLonAxis(2)" ) ) {
      axlon = 2;
      lonsys = astGetC( iwcs, "System(2)" );
   } else if( ndim == 3 && astGetI( iwcs, "IsLonAxis(3)" ) ) {
      axlon = 3;
      lonsys = astGetC( iwcs, "System(3)" );
   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: Cannot find the longitude axis in the "
              "input NDF.", status );
   }

   axlat = 0;
   if( astGetI( iwcs, "IsLatAxis(1)" ) ) {
      axlat = 1;
      latsys = astGetC( iwcs, "System(1)" );
   } else if( astGetI( iwcs, "IsLatAxis(2)" ) ) {
      axlat = 2;
      latsys = astGetC( iwcs, "System(2)" );
   } else if( ndim == 3 && astGetI( iwcs, "IsLatAxis(3)" ) ) {
      axlat = 3;
      latsys = astGetC( iwcs, "System(3)" );
   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: Cannot find the latitude axis in the "
              "input NDF.", status );
   }

   axspec = 6 - axlon - axlat;

/* Report an error if the spatial axes are not ICRS RA and Dec. */
   if( ( lonsys && strcmp( lonsys, "ICRS" ) ) ||
       ( latsys && strcmp( latsys, "ICRS" ) ) ) {
      if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         ndfMsg( "N", indf );
         errRep( "", "smf_jsadicer: The spatial axes in '^N' are not "
                 "ICRS RA and Dec.", status );
      }
   }

/* Create a Box describing the region covered by the NDF pixel grid in
   GRID coords. */
   box = astBox( astGetFrame( iwcs, AST__BASE ), 1, dlbnd, dubnd,
                 AST__NULL, " " );

/* Map this Box into the current WCS Frame of the NDF. */
   region = astMapRegion( box, iwcs, iwcs );

/* If no instrument was specified, we will determine the instrument from
   the contexts of the FITS extension. Copy the NDF FITS extension to a
   FitsChan. Annul the error if the NDF no FITS extension. */
   if( instrument == SMF__INST_NONE && *status == SAI__OK ) {
      kpgGtfts( indf, &fc, status );
      if( *status == KPG__NOFTS ) {
         errAnnul( status );
         fc = NULL;
      }
   } else {
      fc = NULL;
   }

/* Get the parameters of the required tiling scheme. */
   smf_jsainstrument( NULL, fc, instrument, &tiling, status );

/* Get a list of the JSA tiles touched by the supplied NDF. */
   tiles = smf_jsatiles_region( region, &tiling, &ntiles, status );
   if( ntiles == 0 && *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: No JSA tiles found touching supplied NDF "
              "(programming error).", status );
   }

/* Does the input NDF have a Variance component? */
   ndfState( indf, "Variance", &var, status );

/* Does the input NDF have a Quality component? */
   ndfState( indf, "Quality", &qual, status );

/* Decide on the data type to use: _REAL or _DOUBLE. */
   ndfMtype( "_REAL,_DOUBLE", indf, indf, "Data", type, sizeof(type), dtype,
             sizeof(dtype), status );

/* Tell the user what is happening. */
   msgBlank( status );
   msgOutf( "", "Dicing %s into JSA tiles:", status,
            ( nsig == 2 ) ? "map" : "cube" );

/* Loop round all tiles that overlap the supplied NDF. */
   for( itile = 0; itile < ntiles && *status == SAI__OK; itile++ ) {
      tile_index = tiles[ itile ];

/* Get the spatial pixel bounds of the current tile within the requested
   JSA all-sky projection. Also get the (2D) WCS FrameSet for the tile. */
      smf_jsatile( tile_index, &tiling, 0, proj, NULL, &tile_wcs, NULL,
                   tile_lbnd, tile_ubnd, status );

/* Extract the tile pixel->WCS mapping and WCS Frame. We know the indices
   of the required Frames because they are hard-wired in smf_jsatile. */
      tile_map = astGetMapping( tile_wcs, 3, 2 );
      tile_frm = astGetFrame( tile_wcs, 2 );

/* Find the indices of the grid and pixel frames in the input NDF. */
      ipixel = -1;
      igrid = astGetI( iwcs, "Base" );
      nfrm = astGetI( iwcs, "NFrame" );
      for( ifrm = 0; ifrm < nfrm; ifrm++ ) {
         dom = astGetC( astGetFrame( iwcs, ifrm + 1 ), "Domain" );
         if( astChrMatch( dom, "PIXEL" ) ) ipixel = ifrm + 1;
      }

/* If required, extract the pixel->spectral mapping and spectral frame in
   the input NDF, and add it in parallel with the above tile mapping. */
      if( ndim == 3 ) {
         astSetI( iwcs, "Base", ipixel );
         tfs = atlFrameSetSplit( iwcs, "DSBSPECTRUM SPECTRUM", NULL,
                                 NULL, status );
         astSetI( iwcs, "Base", igrid );
         if( tfs ) {
            specmap = astGetMapping( tfs, AST__BASE, AST__CURRENT );
            specfrm = astGetFrame( tfs, AST__CURRENT );
         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indf );
            errRep( "", "smf_jsadicer: Cannot find the spectral axis "
                    "in '^N'.", status );
         }

         tile_map = (AstMapping *) astCmpMap( tile_map, specmap, 0, " " );
         tile_frm = (AstFrame *) astCmpFrame( tile_frm, specfrm, " " );
      }

/* Ensure the Epoch is inherited form the input NDF. */
      astSetD( tile_frm, "Epoch", astGetD( iwcs, "Epoch" ) );

/* Currently tile axis 1 is RA, axis 2 is Dec and axis 3 (if present) is
   spectral. Append a PermMap that re-orders these tile WCS axes to match
   those of the NDF. */
      outperm[ axlon - 1 ] = 1;
      outperm[ axlat - 1 ] = 2;
      outperm[ axspec - 1 ] = 3;
      inperm[ 0 ] = axlon;
      inperm[ 1 ] = axlat;
      inperm[ 2 ] = axspec;
      tile_map = (AstMapping *) astCmpMap( tile_map, astPermMap( ndim, inperm,
                                                                 ndim, outperm,
                                                                 NULL, " " ),
                                           1, " " );
      tile_map = astSimplify( tile_map );

/* Also re-order the WCS axes in the tile frame. */
      astPermAxes( tile_frm, outperm );

/* We want the zero-based indicies of the input pixel axes corresponding
   to ra, dec and spectral. So find the indicies of the pixel axes in the
   supplied NDF that are most closely aligned with each WCS axis. */
      atlPairAxes( iwcs, NULL, gcen, NULL, inperm, status );
      if( inperm[ 0 ] == axlon ) {
         lonax = 0;
      } else if( inperm[ 1 ] == axlon ) {
         lonax = 1;
      } else {
         lonax = 2;
      }
      if( inperm[ 0 ] == axlat ) {
         latax = 0;
      } else if( inperm[ 1 ] == axlat ) {
         latax = 1;
      } else {
         latax = 2;
      }

/* To get the mapping from pixel coords in the input NDF to pixel coords
   in the output NDF, we invert the above mapping so that it goes from WCS
   to pixel, and append it to the end of the NDF pixel->WCS mapping. */
      ndf_map = astGetMapping( iwcs, ipixel, AST__CURRENT );
      astInvert( tile_map );
      p2pmap = (AstMapping *) astCmpMap( ndf_map, tile_map, 1, " " );
      p2pmap = astSimplify( p2pmap );
      astInvert( tile_map );

/* Show the bounds of the tile within the input NDF. */
      msgOutiff( MSG__DEBUG, "", "   tile %d has bounds (%d:%d,%d:%d) "
                 "within the output NDF.", status, tile_index,
                 tile_lbnd[ 0 ], tile_ubnd[ 0 ], tile_lbnd[ 1 ],
                 tile_ubnd[ 1 ] );

/* Next job is to find the pixel bounds of the output NDF to create
   which will hold data for the current tile. First map the pixel bounds
   of the whole tile from output to input. */
      lbnd_in[ 0 ] = tile_lbnd[ 0 ] - 0.5;
      lbnd_in[ 1 ] = tile_lbnd[ 1 ] - 0.5;
      lbnd_in[ 2 ] = lbnd[ 2 ] - 0.5;
      ubnd_in[ 0 ] = tile_ubnd[ 0 ] - 0.5;
      ubnd_in[ 1 ] = tile_ubnd[ 1 ] - 0.5;
      ubnd_in[ 2 ] = ubnd[ 2 ] - 0.5;

      astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 1, lbnd_out + 0,
                 ubnd_out + 0, NULL, NULL );
      astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 2, lbnd_out + 1,
                 ubnd_out + 1, NULL, NULL );
      if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 3,
                                 lbnd_out + 2, ubnd_out + 2, NULL,
                                 NULL );


      lbnd_tile[ 0 ] = floor( lbnd_out[ 0 ] ) + 1;
      lbnd_tile[ 1 ] = floor( lbnd_out[ 1 ] ) + 1;
      lbnd_tile[ 2 ] = floor( lbnd_out[ 2 ] ) + 1;
      ubnd_tile[ 0 ] = floor( ubnd_out[ 0 ] ) + 1;
      ubnd_tile[ 1 ] = floor( ubnd_out[ 1 ] ) + 1;
      ubnd_tile[ 2 ] = floor( ubnd_out[ 2 ] ) + 1;

/* Show the bounds of the tile within the input NDF. */
      msgOutiff( MSG__DEBUG, "", "   tile %d has bounds (%d:%d,%d:%d) "
                 "within the input NDF.", status, tile_index,
                 lbnd_tile[ 0 ], ubnd_tile[ 0 ], lbnd_tile[ 1 ],
                 ubnd_tile[ 1 ] );

/* If required, trim the bounds to the extent of the input NDF. */
      if( trim ) {
         if( lbnd_tile[ 0 ] < lbnd[ 0 ] ) lbnd_tile[ 0 ] = lbnd[ 0 ];
         if( lbnd_tile[ 1 ] < lbnd[ 1 ] ) lbnd_tile[ 1 ] = lbnd[ 1 ];
         if( lbnd_tile[ 2 ] < lbnd[ 2 ] ) lbnd_tile[ 2 ] = lbnd[ 2 ];
         if( ubnd_tile[ 0 ] > ubnd[ 0 ] ) ubnd_tile[ 0 ] = ubnd[ 0 ];
         if( ubnd_tile[ 1 ] > ubnd[ 1 ] ) ubnd_tile[ 1 ] = ubnd[ 1 ];
         if( ubnd_tile[ 2 ] > ubnd[ 2 ] ) ubnd_tile[ 2 ] = ubnd[ 2 ];
      }

/* Check there is some overlap. */
      if( lbnd_tile[ 0 ] <= ubnd_tile[ 0 ] &&
          lbnd_tile[ 1 ] <= ubnd_tile[ 1 ] &&
          lbnd_tile[ 2 ] <= ubnd_tile[ 2 ] ){

/* Now need to check if this section of the input NDF contains any good
   values. We also find the bounding box of the good values (within the
   input pixel coordinate system). So first obtain and map the required
   section of the input NDF. */
         ndfSect( indf, ndim, lbnd_tile, ubnd_tile, &indfs, status );
         ndfMap( indfs, "Data", type, "Read", &ipd, &junk, status );
         if( var ) ndfMap( indfs, "Variance", type, "Read", &ipv, &junk, status );
         if( qual ) ndfMap( indfs, "Quality", "_UBYTE", "Read", (void **) &ipq,
                            &junk, status );

/* Initialise the pixel bounds (within the input NDF) of the box holding
   good data values for the current tile. */
         bbox[ 0 ] = INT_MAX;
         bbox[ 1 ] = INT_MAX;
         bbox[ 2 ] = INT_MAX;
         bbox[ 3 ] = -INT_MAX;
         bbox[ 4 ] = -INT_MAX;
         bbox[ 5 ] = -INT_MAX;

/* Loop round all pixels in the section. */
         if( *status == SAI__OK ) {
            if( !strcmp( type, "_REAL" ) ) {
               pf = (float *) ipd;
               for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) {
                  for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) {
                     for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) {
                        if( *(pf++) != VAL__BADR ) {
                           if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix;
                           if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy;
                           if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz;
                           if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix;
                           if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy;
                           if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz;
                        }
                     }
                  }
               }
            } else {
               pd = (double *) ipd;
               for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) {
                  for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) {
                     for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) {
                        if( *(pd++) != VAL__BADD ) {
                           if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix;
                           if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy;
                           if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz;
                           if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix;
                           if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy;
                           if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz;
                        }
                     }
                  }
               }
            }

/* Skip empty tiles. */
            if( bbox[ 0 ] != INT_MAX ) {
               msgOutf( "", "   tile %d", status, tile_index );

/* If required, trim the bounds to the edges of the bounding box. */
               if( trim >= 2 ) {
                  olbnd[ 0 ] = bbox[ 0 ];
                  olbnd[ 1 ] = bbox[ 1 ];
                  olbnd[ 2 ] = bbox[ 2 ];
                  oubnd[ 0 ] = bbox[ 3 ];
                  oubnd[ 1 ] = bbox[ 4 ];
                  oubnd[ 2 ] = bbox[ 5 ];
               } else {
                  olbnd[ 0 ] = lbnd_tile[ 0 ];
                  olbnd[ 1 ] = lbnd_tile[ 1 ];
                  olbnd[ 2 ] = lbnd_tile[ 2 ];
                  oubnd[ 0 ] = ubnd_tile[ 0 ];
                  oubnd[ 1 ] = ubnd_tile[ 1 ];
                  oubnd[ 2 ] = ubnd_tile[ 2 ];
               }

/* Modify these pixel bounds so that they refer to the output NDF. */
               lbnd_in[ 0 ] = olbnd[ 0 ] - 0.5;
               lbnd_in[ 1 ] = olbnd[ 1 ] - 0.5;
               lbnd_in[ 2 ] = olbnd[ 2 ] - 0.5;
               ubnd_in[ 0 ] = oubnd[ 0 ] - 0.5;
               ubnd_in[ 1 ] = oubnd[ 1 ] - 0.5;
               ubnd_in[ 2 ] = oubnd[ 2 ] - 0.5;

               astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 1, lbnd_out + 0,
                          ubnd_out + 0, NULL, NULL );
               astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 2, lbnd_out + 1,
                          ubnd_out + 1, NULL, NULL );
               if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 3,
                                          lbnd_out + 2, ubnd_out + 2, NULL,
                                          NULL );

               olbnd[ 0 ] = floor( lbnd_out[ 0 ] ) + 1;
               olbnd[ 1 ] = floor( lbnd_out[ 1 ] ) + 1;
               olbnd[ 2 ] = floor( lbnd_out[ 2 ] ) + 1;
               oubnd[ 0 ] = floor( ubnd_out[ 0 ] ) + 1;
               oubnd[ 1 ] = floor( ubnd_out[ 1 ] ) + 1;
               oubnd[ 2 ] = floor( ubnd_out[ 2 ] ) + 1;

/* Get the full path to the output NDF for the current tile, and create an
   NDF placeholder for it. */
               sprintf( path, "%.*s_%d", nbase, base, tile_index );
               ndfPlace( NULL, path, &place, status );

/* Create a new output NDF by copying the meta-data from the input NDF
   section. */
               ndfScopy( indfs, "Units", &place, &indfo, status );

/* Set the pixel bounds of the output NDF to the values found above and copy
   the input data for the current tile into it. */
               smf1_jsadicer( indfo, olbnd, oubnd, tile_map, tile_frm, p2pmap,
                              ipd, ipv, ipq, status );

/* Add the name of this output NDF to the group holding the names of the
   output NDFs that have actually been created. */
               if( grp ) grpPut1( grp, path, 0, status );

/* Add a TILENUM header to the output FITS extension. */
               kpgGtfts( indfo, &fc, status );
               if( *status == KPG__NOFTS ) {
                  errAnnul( status );
                  fc = astFitsChan( NULL, NULL, " " );

/* If the last card is "END", remove it. */
               } else {
                  astSetI( fc, "Card", astGetI( fc, "NCARD" ) );
                  keyword = astGetC( fc, "CardName" );
                  if( keyword && !strcmp( keyword, "END" ) ) astDelFits( fc );
               }

               one_snprintf(jsatile_comment, 45, "JSA all-sky tile index (Nside=%i)",
                            status, tiling.ntpf);
               atlPtfti( fc, "TILENUM", tile_index, jsatile_comment, status );
               kpgPtfts( indfo, fc, status );
               fc = astAnnul( fc );

/* Now store an STC-S polygon that describes the shortest boundary
   enclosing the good data in the output NDF, and store it as an NDF extension. */
               kpgPutOutline( indfo, 0.5, 1, status );

/* We now reshape any extension NDFs contained within the output NDF to
   have the same spatial bounds as the main NDF (but only for extension
   NDFs that originally have the same spatial bounds as the supplied NDF).
   Get a group containing paths to all extension NDFs in the output NDF. */
               ndgMoreg( indfo, &grpt, &size, status );

/* Loop round each output extension NDF. */
               for( iext = 1; iext <= size && *status == SAI__OK; iext++ ) {
                  ndgNdfas( grpt, iext, "Update", &indfx, status );

/* Get its bounds. */
                  ndfBound( indfx, NDF__MXDIM, lbndx, ubndx, &ndimx, status );

/* See if this extension NDF has the same bounds on the spatial axes as
   the supplied NDF. */
                  if( ndimx > 1 && lbndx[ lonax ] == lbnd[ lonax ] &&
                                   lbndx[ latax ] == lbnd[ latax ] &&
                                   ubndx[ lonax ] == ubnd[ lonax ] &&
                                   ubndx[ latax ] == ubnd[ latax ] ) {

/* If so, change the bounds of the output extension NDF so that they are
   the same as the main NDF on the spatial axes, and map the original
   contents of the NDF onto the new pixel grid. */
                     smf1_jsadicer( indfx, olbnd, oubnd, tile_map, tile_frm, p2pmap,
                                    NULL, NULL, NULL, status );
                  }

/* Annul the extension NDF identifier. */
                  ndfAnnul( &indfx, status );
               }

/* Free resources associated with the current tile. */
               grpDelet( &grpt, status );
               ndfAnnul( &indfo, status );

/* Issue warnings about empty tiles. */
            } else {
               msgOutiff( MSG__VERB, "", "   tile %d is empty and so will not be "
                          "created", status, tile_index );
            }
         }

/* Free the section of the input NDF. */
         ndfAnnul( &indfs, status );

/* Append the index of this tile in the list of tiles to be created. */
         created_tiles = astGrow( created_tiles, ++(*ntile),
                                  sizeof( *created_tiles ) );
         if( *status == SAI__OK ) created_tiles[ *ntile - 1 ] = tile_index;

      } else {
         msgOutiff( MSG__DEBUG, "", "   Tile %d does not overlap the input "
                    "NDF after trimming.", status, tile_index );
      }
   }
   msgBlank( status );

/* Write the indicies of the created tiles out to a parameter. */
   if( *ntile ) parPut1i( "JSATILELIST", *ntile, created_tiles, status );

/* Free resources. */
   created_tiles = astFree( created_tiles );
   tiles = astFree( tiles );
   path = astFree( path );

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

/* End the AST context. */
   astEnd;

}
예제 #18
0
void smf_clean_smfArray( ThrWorkForce *wf, smfArray *array,
                         smfArray **noisemaps, smfArray **com, smfArray **gai,
                         AstKeyMap *keymap, int *status ) {

  /* Local Variables */
  double badfrac;           /* Fraction of bad samples to flag bad bolo */
  smfData *data=NULL;       /* Pointer to individual smfData */
  int compreprocess;        /* COMmon-mode cleaning as pre-processing step */
  dim_t dcfitbox;           /* width of box for measuring DC steps */
  int dclimcorr;            /* Min number of correlated steps */
  int dcmaxsteps;           /* number of DC steps/min. to flag bolo bad */
  dim_t dcsmooth;           /* median filter width before finding DC steps */
  double dcthresh;          /* n-sigma threshold for primary DC steps */
  int dofft;                /* are we doing a freq.-domain filter? */
  int dkclean;              /* Flag for dark squid cleaning */
  smfFilter *filt=NULL;     /* Frequency domain filter */
  double flagfast;          /* Threshold for flagging slow slews */
  double flagslow;          /* Threshold for flagging slow slews */
  dim_t idx;                /* Index within subgroup */
  size_t nflag;             /* Number of elements flagged */
  double noisecliphigh = 0; /* Sigma clip high-noise outlier bolos */
  double noisecliplow = 0;  /* Sigma clip low-noise outlier bolos */
  int noiseclipprecom = 0;  /* Noise clipping before common-mode cleaning? */
  const char *opteff=NULL;  /* Pointer to optical efficiency NDF file name*/
  int opteffdiv;            /* Divide data by the optical efficiencies? */
  int order;                /* Order of polynomial for baseline fitting */
  char param[ 20 ];         /* Buffer for config parameter name */
  dim_t pcalen;             /* Chunk length for PCA cleaning */
  double pcathresh;         /* n-sigma threshold for PCA cleaning */
  double spikethresh;       /* Threshold for finding spikes */
  dim_t spikebox=0;         /* Box size for spike finder */
  struct timeval tv1, tv2;  /* Timers */
  int whiten;               /* Apply whitening filter? */
  int zeropad;              /* Pad with zeros? */

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

  /*** TIMER ***/
  smf_timerinit( &tv1, &tv2, status );

  /* Check for valid inputs */

  if( !array || (array->ndat < 1) ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": No data supplied", status );
  }

  if( array->sdata[0]->ndims != 3 ) {
    *status = SMF__WDIM;
    errRepf( "", FUNC_NAME ": Supplied smfData has %zu dims, needs 3", status,
             data->ndims );
    return;
  }

  if( !keymap ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": NULL AstKeyMap supplied", status );
    return;
  }

  /* Get cleaning parameters */
  smf_get_cleanpar( keymap, array->sdata[0], &badfrac, &dcfitbox, &dcmaxsteps,
                    &dcthresh, &dcsmooth, &dclimcorr, &dkclean,
                    NULL, &zeropad, NULL, NULL, NULL, NULL, NULL,
                    NULL, NULL, NULL, &flagslow, &flagfast, &order,
                    &spikethresh, &spikebox, &noisecliphigh, &noisecliplow,
                    NULL, &compreprocess, &pcalen, &pcathresh, NULL, NULL, NULL,
                    &noiseclipprecom, status );

  /* Loop over subarray */
  for( idx=0; (idx<array->ndat)&&(*status==SAI__OK); idx++ ) {
    data = array->sdata[idx];

    /* Update quality by synchronizing to the data array VAL__BADD values */
    msgOutif(MSG__VERB,"", FUNC_NAME ": update quality", status);
    smf_update_quality( data, 1, NULL, 0, badfrac, status );

    /*** TIMER ***/
    msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME ":   ** %f s updating quality",
               status, smf_timerupdate(&tv1,&tv2,status) );

    /* Fix DC steps */
    if( dcthresh && dcfitbox ) {
      msgOutiff(MSG__VERB, "", FUNC_NAME
                ": Flagging bolos with %lf-sigma DC steps in %" DIM_T_FMT " "
                "samples as bad, using %" DIM_T_FMT
                "-sample median filter and max %d "
                "DC steps per min before flagging entire bolo bad...", status,
                dcthresh, dcfitbox, dcsmooth, dcmaxsteps);

      smf_fix_steps( wf, data, dcthresh, dcsmooth, dcfitbox, dcmaxsteps,
                     dclimcorr, 0, &nflag, NULL, NULL, status );

      msgOutiff(MSG__VERB, "", FUNC_NAME": ...%zd flagged\n", status, nflag);

      /*** TIMER ***/
      msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME ":   ** %f s fixing DC steps",
                 status, smf_timerupdate(&tv1,&tv2,status) );
    }

    /* Flag Spikes */
    if( spikethresh ) {
      msgOutif(MSG__VERB," ", FUNC_NAME ": flag spikes...", status);
      smf_flag_spikes( wf, data, SMF__Q_FIT, spikethresh, spikebox,
                       &nflag, status );
      msgOutiff(MSG__VERB,"", FUNC_NAME ": ...found %zd", status, nflag );

      /*** TIMER ***/
      msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME ":   ** %f s flagging spikes",
                 status, smf_timerupdate(&tv1,&tv2,status) );
    }

    /*  Flag periods of stationary pointing, and update scanspeed to more
        accurate value */
    if( flagslow || flagfast ) {
      if( data->hdr && data->hdr->allState ) {
        double scanvel=0;

        if( flagslow ) {
          msgOutiff( MSG__VERB, "", FUNC_NAME
                     ": Flagging regions with slew speeds < %.2lf arcsec/sec",
                     status, flagslow );
        }

        if( flagfast ) {
          msgOutiff( MSG__VERB, "", FUNC_NAME
                     ": Flagging regions with slew speeds > %.2lf arcsec/sec",
                     status, flagfast );


          /* Check to see if this was a sequence type that involved
             motion.  If not, skip this section */
          if( data && data->hdr && (
                                    (data->hdr->seqtype==SMF__TYP_SCIENCE) ||
                                    (data->hdr->seqtype==SMF__TYP_POINTING) ||
                                    (data->hdr->seqtype==SMF__TYP_FOCUS) ||
                                    (data->hdr->seqtype==SMF__TYP_SKYDIP))
                                 && (data->hdr->obsmode!=SMF__OBS_STARE) ) {

            smf_flag_slewspeed( data, flagslow, flagfast, &nflag, &scanvel,
                              status );
            msgOutiff( MSG__VERB,"", "%zu new time slices flagged", status,
                       nflag);

            if( msgIflev( NULL, status ) >= MSG__VERB ) {
              msgOutf( "", FUNC_NAME ": mean SCANVEL=%.2lf arcsec/sec"
                       " (was %.2lf)", status, scanvel, data->hdr->scanvel );
            }

            data->hdr->scanvel = scanvel;

            /*** TIMER ***/
            msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME
                       ":   ** %f s flagging outlier slew speeds",
                       status, smf_timerupdate(&tv1,&tv2,status) );
          } else {
            msgOutif( MSG__VERB, "", FUNC_NAME
                      ": not a moving sequence or missing header, "
                      "skipping slew speed flagging", status );
          }
        }
      } else {
        msgOutif( MSG__DEBUG, "", FUNC_NAME
                  ": Skipping flagslow/flagfast because no header present",
                  status );
      }
    }

    /* Clean out the dark squid signal */
    if( dkclean ) {
      msgOutif(MSG__VERB, "", FUNC_NAME
               ": Cleaning dark squid signals from data.", status);
      smf_clean_dksquid( data, 0, 100, NULL, 0, 0, 0, status );

      /*** TIMER ***/
      msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME ":   ** %f s DKSquid cleaning",
                 status, smf_timerupdate(&tv1,&tv2,status) );
    }

    /* Apply optical efficiency corrections. */
    one_strlcpy( param, "OPTEFF", sizeof(param), status );
    smf_find_subarray( data->hdr, param + strlen(param),
                       sizeof(param) - strlen(param), NULL, status );
    astChrCase( NULL, param, 1, 0 );
    if( astMapHasKey( keymap, param ) ) {
      astMapGet0I( keymap, "OPTEFFDIV", &opteffdiv );
      if ( astMapGet0C( keymap, param, &opteff ) ) {
        msgOutiff( MSG__VERB,"", FUNC_NAME ": %s bolometer values "
                   "by factors read from NDF %s", status,
                   opteffdiv ? "Dividing" : "Multiplying", opteff );
        smf_scale_bols( wf, data, NULL, opteff, param, opteffdiv, status );
      }
    }

    /* Remove baselines */
    if( order >= 0 ) {
      msgOutiff( MSG__VERB,"", FUNC_NAME
                 ": Fitting and removing %i-order polynomial baselines",
                 status, order );

      smf_fit_poly( wf, data, order, 1, NULL, status );

      /*** TIMER ***/
      msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME
                 ":   ** %f s removing poly baseline",
                 status, smf_timerupdate(&tv1,&tv2,status) );
    }
  }

  /* Mask noisy bolos here if happening before common-mode cleaning */
  if( (*status == SAI__OK) && ((noisecliphigh>0.0) || (noisecliplow>0.0)) &&
      noiseclipprecom ) {

    smf__noisymask( wf, data, noisemaps, noisecliphigh, noisecliplow,
                    zeropad, &tv1, &tv2, status );
  }


  /* Optionally call smf_calcmodel_com to perform a subset of the following
     tasks as a pre-processing step:

       - remove the common-mode
       - flag outlier data using common-mode rejection
       - determine relative flatfields using amplitude of common-mode

     In order to do this we need to set up some temporary model container
     files so that the routine can be called properly. All of the same
     COMmon-mode and GAIn model parameters (e.g. com.* and gai.*) will be
     used here. However, in addition the "compreprocess" flag must be set
     for this operation to be performed. */

  if( compreprocess ) {
    smfArray *comdata = NULL;
    smfGroup *comgroup = NULL;
    smfDIMMData dat;
    smfArray *gaidata = NULL;
    smfGroup *gaigroup = NULL;
    smfArray *quadata = NULL;
    smfData *thisqua=NULL;

    msgOutif(MSG__VERB," ", FUNC_NAME ": Remove common-mode", status);

    /* Create model containers for COM, GAI */
    smf_model_create( wf, NULL, &array, NULL, NULL, NULL, NULL, NULL, 1, SMF__COM,
                      0, NULL, 0, NULL, NULL, &comgroup, &comdata, keymap,
                      status );

    smf_model_create( wf, NULL, &array, NULL, NULL, NULL, NULL, NULL, 1, SMF__GAI,
                      0, NULL, 0, NULL, NULL, &gaigroup, &gaidata, keymap,
                      status );

    /* Manually create quadata to share memory with the quality already
       stored in array */

    quadata = smf_create_smfArray( status );
    for( idx=0; (*status==SAI__OK) && (idx<array->ndat); idx++ ) {
      /* Create several new smfDatas, but they will all be freed
         properly when we close quadata */
      thisqua = smf_create_smfData( SMF__NOCREATE_DA | SMF__NOCREATE_HEAD |
                                    SMF__NOCREATE_FILE, status );

      /* Probably only need pntr->[0], but fill in the dimensionality
         information to be on the safe side */
      thisqua->dtype = SMF__QUALTYPE;
      thisqua->ndims = array->sdata[idx]->ndims;
      thisqua->isTordered = array->sdata[idx]->isTordered;
      memcpy( thisqua->dims, array->sdata[idx]->dims, sizeof(thisqua->dims) );
      memcpy( thisqua->lbnd, array->sdata[idx]->lbnd, sizeof(thisqua->lbnd) );
      thisqua->pntr[0] = smf_select_qualpntr( array->sdata[idx], NULL, status );

      smf_addto_smfArray( quadata, thisqua, status );
    }

    /* Set up the smfDIMMData and call smf_calcmodel_com */
    memset( &dat, 0, sizeof(dat) );
    dat.res = &array;
    dat.gai = &gaidata;
    dat.qua = &quadata;
    dat.noi = NULL;

    smf_calcmodel_com( wf, &dat, 0, keymap, &comdata, SMF__DIMM_FIRSTITER,
                       status );

    /*** TIMER ***/
    msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME
               ":   ** %f s removing common-mode",
               status, smf_timerupdate(&tv1,&tv2,status) );

    /* Clean up and/or return values */
    if( com ) {
      *com = comdata;
    } else {
      if( comdata ) smf_close_related( &comdata, status );
    }

    if( gai ) {
      *gai = gaidata;
    } else {
      if( gaidata ) smf_close_related( &gaidata, status );
    }

    if( comgroup ) smf_close_smfGroup( &comgroup, status );
    if( gaigroup ) smf_close_smfGroup( &gaigroup, status );

    /* Before closing quadata unset all the pntr[0] since this is shared
       memory with the quality associated with array */
    if( quadata ) {
      for( idx=0; idx<quadata->ndat; idx++ ) {
        quadata->sdata[idx]->pntr[0] = NULL;
      }
      if( quadata ) smf_close_related( &quadata, status );
    }
  }

  /* PCA cleaning */
  if( pcathresh ) {
    /* Loop over subarray */
    for( idx=0; (idx<array->ndat)&&(*status==SAI__OK); idx++ ) {
      data = array->sdata[idx];

      smf_clean_pca_chunks( wf, data, pcalen, pcathresh, keymap, status );
    }

    /*** TIMER ***/
    msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME ":   ** %f s PCA cleaning",
               status, smf_timerupdate(&tv1,&tv2,status) );
  }

  /* Allocate space for noisemaps if required */

  if( noisemaps ) {
    *noisemaps = smf_create_smfArray( status );
  }

  /* Loop over subarray */

  for( idx=0; (idx<array->ndat)&&(*status==SAI__OK); idx++ ) {
    data = array->sdata[idx];

    /* Filter the data. Note that we call smf_filter_execute to apply
       a per-bolometer whitening filter even if there is no
       explicitly requested smfFilter (in which case the
       smf_filter_fromkeymap call will leave the real/imaginary parts
       of the filter as NULL pointers and they will get ignored inside
       smf_filter_execute). */

    filt = smf_create_smfFilter( data, status );
    smf_filter_fromkeymap( filt, keymap, data->hdr, &dofft, &whiten, status );

    if( (*status == SAI__OK) && dofft ) {
      msgOutif( MSG__VERB, "", FUNC_NAME ": frequency domain filter", status );
      smf_filter_execute( wf, data, filt, 0, whiten, status );

      /*** TIMER ***/
      msgOutiff( SMF__TIMER_MSG, "", FUNC_NAME ":   ** %f s filtering data",
                 status, smf_timerupdate(&tv1,&tv2,status) );
    }
    filt = smf_free_smfFilter( filt, status );

    /* Mask noisy bolos here if happening after common-mode cleaning */
    if( (*status == SAI__OK) && ((noisecliphigh>0.0) || (noisecliplow>0.0)) &&
        !noiseclipprecom ) {

      smf__noisymask( wf, data, noisemaps, noisecliphigh, noisecliplow,
                      zeropad, &tv1, &tv2, status );
    }

  }
}
예제 #19
0
void smurf_sc2fft( int *status ) {

  int avpspec=0;            /* Flag for doing average power spectrum */
  double avpspecthresh=0;   /* Threshold noise for detectors in avpspec */
  Grp * basegrp = NULL;     /* Basis group for output filenames */
  smfArray *bbms = NULL;    /* Bad bolometer masks */
  smfArray *concat=NULL;    /* Pointer to a smfArray */
  size_t contchunk;         /* Continuous chunk counter */
  smfArray *darks = NULL;   /* dark frames */
  int ensureflat;           /* Flag for flatfielding data */
  Grp *fgrp = NULL;         /* Filtered group, no darks */
  smfArray *flatramps = NULL;/* Flatfield ramps */
  AstKeyMap *heateffmap = NULL;    /* Heater efficiency data */
  size_t gcount=0;          /* Grp index counter */
  size_t i;                 /* Loop counter */
  smfGroup *igroup=NULL;    /* smfGroup corresponding to igrp */
  Grp *igrp = NULL;         /* Input group of files */
  int inverse=0;            /* If set perform inverse transform */
  int isfft=0;              /* Are data fft or real space? */
  dim_t maxconcat=0;        /* Longest continuous chunk length in samples */
  size_t ncontchunks=0;     /* Number continuous chunks outside iter loop */
  smfData *odata=NULL;      /* Pointer to output smfData to be exported */
  Grp *ogrp = NULL;         /* Output group of files */
  size_t outsize;           /* Total number of NDF names in the output group */
  int polar=0;              /* Flag for FFT in polar coordinates */
  int power=0;              /* Flag for squaring amplitude coeffs */
  size_t size;              /* Number of files in input group */
  smfData *tempdata=NULL;   /* Temporary smfData pointer */
  int weightavpspec=0;      /* Flag for 1/noise^2 weighting */
  ThrWorkForce *wf = NULL;  /* Pointer to a pool of worker threads */
  int zerobad;              /* Zero VAL__BADD before taking FFT? */

  /* Main routine */
  ndfBegin();

  /* Find the number of cores/processors available and create a pool of
     threads of the same size. */
  wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status );

  /* Get input file(s) */
  kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );

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

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

  /* We now need to combine files from the same subarray and same sequence
     to form a continuous time series */
  smf_grp_related( igrp, size, 1, 0, 0, NULL, NULL, &maxconcat, NULL, &igroup,
                   &basegrp, NULL, status );

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

  /* Get group of bolometer masks and read them into a smfArray */
  smf_request_mask( "BBM", &bbms, status );

  /* Obtain the number of continuous chunks and subarrays */
  if( *status == SAI__OK ) {
    ncontchunks = igroup->chunk[igroup->ngroups-1]+1;
  }
  msgOutiff( MSG__NORM, "", "Found %zu continuous chunk%s", status, ncontchunks,
             (ncontchunks > 1 ? "s" : "") );

  /* Are we flatfielding? */
  parGet0l( "FLAT", &ensureflat, status );

  /* Are we doing an inverse transform? */
  parGet0l( "INVERSE", &inverse, status );

  /* Are we using polar coordinates instead of cartesian for the FFT? */
  parGet0l( "POLAR", &polar, status );

  /* Are we going to assume amplitudes are squared? */
  parGet0l( "POWER", &power, status );

  /* Are we going to zero bad values first? */
  parGet0l( "ZEROBAD", &zerobad, status );

  /* Are we calculating the average power spectrum? */
  parGet0l( "AVPSPEC", &avpspec, status );

  if( avpspec ) {
    power = 1;
    parGet0d( "AVPSPECTHRESH", &avpspecthresh, status );

    parGet0l( "WEIGHTAVPSPEC", &weightavpspec, status );
  }

  /* If power is true, we must be in polar form */
  if( power && !polar) {
    msgOutif( MSG__NORM, " ", TASK_NAME
              ": power spectrum requested so setting POLAR=TRUE", status );
    polar = 1;
  }

  gcount = 1;
  for( contchunk=0;(*status==SAI__OK)&&contchunk<ncontchunks; contchunk++ ) {
    size_t idx;

    /* Concatenate this continuous chunk but forcing a raw data read.
       We will need quality. */
    smf_concat_smfGroup( wf, NULL, igroup, darks, NULL, flatramps, heateffmap,
                         contchunk, ensureflat, 1, NULL, 0, NULL, NULL, 0, 0, 0,
                         &concat, NULL, status );

    /* Now loop over each subarray */
    /* Export concatenated data for each subarray to NDF file */
    for( idx=0; (*status==SAI__OK)&&idx<concat->ndat; idx++ ) {
      if( concat->sdata[idx] ) {
        smfData * idata = concat->sdata[idx];
        int provid = NDF__NOID;
        dim_t nbolo;                /* Number of detectors  */
        dim_t ndata;                /* Number of data points */

        /* Apply a mask to the quality array and data array */
        smf_apply_mask( idata, bbms, SMF__BBM_QUAL|SMF__BBM_DATA, 0, status );

        smf_get_dims( idata,  NULL, NULL, &nbolo, NULL, &ndata, NULL, NULL,
                      status );


        /* Check for double precision data */
        if( idata->dtype != SMF__DOUBLE ) {
          *status = SAI__ERROR;
          errRep( "", FUNC_NAME ": data are not double precision.", status );
        }

        /* Are we zeroing VAL__BADD? */
        if( (*status==SAI__OK) && zerobad ) {
          double *data= (double *) idata->pntr[0];

          for( i=0; i<ndata; i++ ) {
            if( data[i] == VAL__BADD ) {
              data[i] = 0;
            }
          }
        }

        /* Check whether we need to transform the data at all */
        isfft = smf_isfft(idata,NULL,NULL,NULL,NULL,NULL,status);

        if( isfft && avpspec && (*status == SAI__OK) ) {
          *status = SAI__ERROR;
          errRep( "", FUNC_NAME
                  ": to calculate average power spectrum input data cannot "
                  "be FFT", status );
        }

        if( (*status == SAI__OK) && (isfft == inverse) ) {

          if( avpspec ) {
            /* If calculating average power spectrum do the transforms with
               smf_bolonoise so that we can also measure the noise of
               each detector */

            double *whitenoise=NULL;
            smf_qual_t *bolomask=NULL;
            double mean, sig, freqlo;
            size_t ngood, newgood;

            whitenoise = astCalloc( nbolo, sizeof(*whitenoise) );
            bolomask = astCalloc( nbolo, sizeof(*bolomask) );

	    freqlo = 1. / (idata->hdr->steptime * idata->hdr->nframes);

            smf_bolonoise( wf, idata, 1, freqlo, SMF__F_WHITELO,
                           SMF__F_WHITEHI, 1, 0, whitenoise, NULL, &odata,
                           status );

            /* Initialize quality */
            for( i=0; i<nbolo; i++ ) {
              if( whitenoise[i] == VAL__BADD ) {
                bolomask[i] = SMF__Q_BADB;
              } else {
                /* smf_bolonoise returns a variance, so take sqrt */
                whitenoise[i] = sqrt(whitenoise[i]);
              }
            }

            ngood=-1;
            newgood=0;

            /* Iteratively cut n-sigma noisy outlier detectors */
            while( ngood != newgood ) {
              ngood = newgood;
              smf_stats1D( whitenoise, 1, nbolo, bolomask, 1, SMF__Q_BADB,
                           &mean, &sig, NULL, NULL, status );
              msgOutiff( MSG__DEBUG, "", TASK_NAME
                         ": mean=%lf sig=%lf ngood=%li\n", status,
                         mean, sig, ngood);

              newgood=0;
              for( i=0; i<nbolo; i++ ) {
                if( whitenoise[i] != VAL__BADD ){
                  if( (whitenoise[i] - mean) > avpspecthresh *sig ) {
                    whitenoise[i] = VAL__BADD;
                    bolomask[i] = SMF__Q_BADB;
                  } else {
                    newgood++;
                  }
                }
              }
            }

            msgOutf( "", TASK_NAME
                     ": Calculating average power spectrum of best %li "
                     " bolometers.", status, newgood);

            /* If using 1/noise^2 weights, calculate 1/whitenoise^2 in-place
               to avoid allocating another array */
            if( weightavpspec ) {
              msgOutif( MSG__VERB, "", TASK_NAME ": using 1/noise^2 weights",
                        status );

              for( i=0; i<nbolo; i++ ) {
                if( whitenoise[i] && (whitenoise[i] != VAL__BADD) ) {
                  whitenoise[i] = 1/(whitenoise[i]*whitenoise[i]);
                }
              }
            }

            /* Calculate the average power spectrum of good detectors */
            tempdata = smf_fft_avpspec( odata, bolomask, 1, SMF__Q_BADB,
                                        weightavpspec ? whitenoise : NULL,
                                        status );
            smf_close_file( &odata, status );
            whitenoise = astFree( whitenoise );
            bolomask = astFree( bolomask );
            odata = tempdata;
            tempdata = NULL;
	    /* Store the number of good bolometers */
	    parPut0i( "NGOOD", newgood, status );
          } else {
            /* Otherwise do forward/inverse transforms here as needed */

            /* If inverse transform convert to cartesian representation first */
            if( inverse && polar ) {
              smf_fft_cart2pol( wf, idata, 1, power, status );
            }

            /* Tranform the data */
            odata = smf_fft_data( wf, idata, NULL, inverse, 0, status );
            smf_convert_bad( wf, odata, status );

            if( inverse ) {
              /* If output is time-domain, ensure that it is ICD bolo-ordered */
              smf_dataOrder( odata, 1, status );
            } else if( polar ) {
              /* Store FFT of data in polar form */
              smf_fft_cart2pol( wf, odata, 0, power, status );
            }
          }

          /* open a reference input file for provenance propagation */
          ndgNdfas( basegrp, gcount, "READ", &provid, status );

          /* Export the data to a new file */
          smf_write_smfData( odata, NULL, NULL, ogrp, gcount, provid,
                             MSG__VERB, 0, status );

          /* Free resources */
          ndfAnnul( &provid, status );
          smf_close_file( &odata, status );
        } else {
          msgOutif( MSG__NORM, " ",
                    "Data are already transformed. No output will be produced",
                    status );
        }
      }

      /* Update index into group */
      gcount++;
    }

    /* Close the smfArray */
    smf_close_related( &concat, status );
  }

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK ) {
    grpList( "OUTFILES", 0, 0, NULL, ogrp, status );
    if( *status == PAR__NULL ) errAnnul( status );
  }

  /* Tidy up after ourselves: release the resources used by the grp routines */
  grpDelet( &igrp, status);
  grpDelet( &ogrp, status);
  if (basegrp) grpDelet( &basegrp, status );
  if( igroup ) smf_close_smfGroup( &igroup, status );
  if( flatramps ) smf_close_related( &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  if (bbms) smf_close_related( &bbms, status );

  ndfEnd( status );

  /* Ensure that FFTW doesn't have any used memory kicking around */
  fftw_cleanup();
}
예제 #20
0
static void smf1_check_quality( void *job_data_ptr, int *status ) {
/*
*  Name:
*     smf1_check_quality

*  Purpose:
*     Executed in a worker thread to do various calculations for
*     smf_check_quality.

*  Invocation:
*     smf1_check_quality( void *job_data_ptr, int *status )

*  Arguments:
*     job_data_ptr = SmfCheckQualityData * (Given)
*        Data structure describing the job to be performed by the worker
*        thread.
*     status = int * (Given and Returned)
*        Inherited status.

*/

/* Local Variables: */
   SmfCheckQualityData *pdata;
   double *pd;
   int badqual;
   int isbad;
   size_t bolnum;
   size_t i;
   size_t tslice;
   smf_qual_t *pq;

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

/* Get a pointer that can be used for accessing the required items in the
   supplied structure. */
   pdata = (SmfCheckQualityData *) job_data_ptr;

/* Initialise returned chisquared increment and count of values. */
   pdata->nbad = 0;
   pdata->nnan = 0;
   pdata->ninf = 0;
   pdata->nqualincon = 0;

/* Initialise pointers to the first data and quality value to be
   processed by this thread. */
   pq = pdata->qual + pdata->d1;
   pd = pdata->d + pdata->d1;

/* Loop round all values to be processed by this thread. */
   for( i = pdata->d1; i <= pdata->d2; i++, pq++,pd++ ) {
      isbad = 0;
      badqual = (*pq) & SMF__Q_BADDA;

/* Do the finite test first since if it is not finite there is no point
   testing if it is BADD as well */
      if( !isfinite( *pd ) ) {
         isbad = 1;

         if( isnan( *pd ) ) {
            pdata->nnan++;
         } else {
            pdata->ninf++;
         }

         if( pdata->showbad ) {
            smf__index_to_tbol( pdata->bstride, pdata->tstride, i, &bolnum,
                                &tslice, status );
            msgOutf( "", "b%zu t%zu: non-finite %s value encountered",
                     status, bolnum, tslice, (isnan(*pd) ? "NaN" : "Inf") );
         }

      } else if( *pd == VAL__BADD && !badqual ) {
         isbad = 1;
         if( pdata->showbad ) {
            smf__index_to_tbol( pdata->bstride, pdata->tstride, i, &bolnum,
                                &tslice, status );
            msgOutf( "", "b%zu t%zu: VAL__BADD without SMF__Q_BADDA",
                     status, bolnum, tslice );
         }

      } else if( badqual && *pd != VAL__BADD ) {
         isbad = 1;
         pdata->nqualincon++;
         if( pdata->showbad ) {
            smf__index_to_tbol( pdata->bstride, pdata->tstride, i, &bolnum,
                                &tslice, status );
            msgOutf( "", "b%zu t%zu: SMF__Q_BADDA without VAL__BADD",
                     status, bolnum, tslice );
         }

      }
      if( isbad ) pdata->nbad++;
   }
}