コード例 #1
0
ファイル: ndf.c プロジェクト: timj/starlink-pyndf
static PyObject*
pyndf_end(NDF *self)
{
    int status = SAI__OK;
    errBegin(&status);
    ndfEnd(&status);
    if (raiseNDFException(&status)) return NULL;
    Py_RETURN_NONE;
};
コード例 #2
0
ファイル: smurf_calcdark.c プロジェクト: andrecut/starlink
void smurf_calcdark( int *status ) {

  smfArray *bbms = NULL;    /* Bad bolometer masks */
  smfArray *darks = NULL;   /* set of processed darks */
  Grp *dgrp = NULL;         /* Group of darks */
  size_t i;                 /* Loop index */
  int indf;                 /* NDF identifier for input file */
  Grp *igrp = NULL;         /* Input group of files */
  Grp *ogrp = NULL;         /* Output group of files */
  size_t outsize;           /* Total number of NDF names in the output group */
  size_t size;              /* Number of files in input group */

  /* Main routine */
  ndfBegin();

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

  /* Filter out non-darks and reduce the darks themselves */
  smf_find_science( igrp, NULL, 0, &dgrp, NULL, 1, 0, SMF__DOUBLE, &darks, NULL,
                    NULL, NULL, status );

  /* no longer need the input group */
  grpDelet( &igrp, status );

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

  /* Get group of bolometer masks and read them into a smfArray */
  smf_request_mask( "BBM", &bbms, status );

  for (i=1; i<=size && *status == SAI__OK; i++ ) {
    smfData * dark = (darks->sdata)[i-1]; /* This dark */

    /* Open input file and create output file. Do not propagate
       since we do not want to get a large file the wrong size */
    ndgNdfas( dgrp, i, "READ", &indf, status );

    smf_apply_mask( dark, bbms, SMF__BBM_DATA, 0, status );
    smf_write_smfData( dark, NULL, NULL, ogrp, i, indf, MSG__VERB, status );
    ndfAnnul( &indf, status);
  }

  /* Tidy up after ourselves: release the resources used by the grp routines  */
  grpDelet( &dgrp, status);
  grpDelet( &ogrp, status);
  smf_close_related( &darks, status );
  smf_close_related( &bbms, status );

  ndfEnd( status );
}
コード例 #3
0
void smurf_rawrewrtsc2wcs( int * status ) {

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


  if (*status != SAI__OK) return;

  ndfBegin();

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

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

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

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

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

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

  /* Cleanup */
  grpDelet( &igrp, status);
  ndfEnd( status );
}
コード例 #4
0
/* Main entry */
void smurf_checkcoords( int *status ) {

/* Local Variables */
   Grp *igrp = NULL;
   size_t i;
   size_t size;
   smfData *data = NULL;

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

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

/* Get a group of input files */
   kpg1Rgndf( "IN", 0, 1, "  Give more NDFs...", &igrp, &size, status );

/* Loop round each one. */
   for( i = 1; i <= size; i++ ) {

/* Open the file. */
      smf_open_file( NULL, igrp, i, "READ", SMF__NOCREATE_DATA, &data, status );

/* Check the detector positions (for ACSIS data). */
      msgBlank( status );
      smf_check_detpos( data, 1, status );

/* Calculate and display statistics of the AZEL <> TRACKING separations
   in the current file. */
      smf_check_coords( data, status );

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

/* Free resources. */
   grpDelet( &igrp, status );

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

/* If anything went wrong issue a context message. */
   if( *status != SAI__OK ) msgOutif( MSG__VERB, " ", "CHECKCOORDS failed.",
                                      status );
}
コード例 #5
0
void smurf_sc2expandmodel( int *status ) {
  smf_expmodelptr expptr=NULL;/* Pointer to current model calc function */
  size_t i=0;               /* Counter, index */
  smfData *idata=NULL;      /* Input data */
  Grp *igrp = NULL;         /* Input group of files */
  smfData *odata=NULL;      /* Output data */
  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 */

  /* Main routine */
  ndfBegin();

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

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

  /* Loop over input files */
  for( i=1; (*status==SAI__OK) && (i<=size); i++ ) {

    /* Open file */
    smf_open_file(NULL, igrp, i, "READ", 0, &idata, status);

    /* Check to see if this is a DIMM model component before expanding */
    if( idata && idata->hdr && (idata->hdr->mtype != SMF__NUL) ) {
      expptr = smf_model_getexpptr( idata->hdr->mtype, status );

      if( *status == SAI__OK ) {
        (*expptr)( idata, &odata, status );
        smf_write_smfData( NULL, odata, NULL, NULL, ogrp, i, 0,
                           MSG__VERB, 0, NULL, NULL, status );
      }
    }
  }

  /* Cleanup */
  grpDelet( &igrp, status);
  grpDelet( &ogrp, status);

  ndfEnd( status );
}
コード例 #6
0
void smurf_dreamweights ( int *status ) {

  /* Local Variables */
  Grp *confgrp = NULL;        /* Group containing configuration file */
  smfData *data = NULL;       /* Input data */
  const int defgridminmax[] = { -4, 4, -4, 4 }; /* Default extent xmin,xmax,ymin,ymax */
  int gridminmax[4];          /* Extent of grid points array */
  int gridpts[DREAM__MXGRID][2]; /* Array of points for reconstruction grid */
  double gridstep;            /* Size of reconstruction grid in arcsec */
  size_t i;                   /* Loop counter */
  Grp *igrp = NULL;           /* Input group of NDFs */
  size_t size;                /* Size of input Grp of files */
  AstKeyMap *keymap = NULL;   /* Pointer to keymap of config settings */
  size_t ksize;               /* Size of group containing CONFIG file */
  int ngrid;                  /* Number of points in reconstruction grid */
  Grp *ogrp = NULL;           /* Group of output weights files */
  size_t outsize;             /* Size of output Grp of files */

  /* Main routine */
  ndfBegin();

  /* Get group of input raw data NDFs */
  kpg1Rgndf( "NDF", 0, 1, "", &igrp, &size, status );

  /* Get group of output files from user: assume 1 output file for
     every input file */
  kpg1Wgndf( "OUT", igrp, size, size, "More output files required...",
             &ogrp, &outsize, status );

  /* Read configuration settings into keymap */
  if (*status == SAI__OK) {
    kpg1Gtgrp( "CONFIG", &confgrp, &ksize, status );
    if (*status == PAR__NULL) {
      /* NULL value so provide defaults */
      errAnnul( status );
      msgOutif(MSG__VERB, " ", "No config file specified - assuming default configuration parameters", status);
      keymap = astKeyMap(" " );
      astMapPut1I( keymap, "GRIDMINMAX", 4, (int*)defgridminmax, " " );
      astMapPut0D( keymap, "GRIDSTEP", 6.28, " " );
    } else {
      kpg1Kymap( confgrp, &keymap, status );
    }
    if( confgrp ) grpDelet( &confgrp, status );
  }

  /* Determine grid parameters from inputs given above */
  smf_dream_getgrid( keymap, &gridstep, &ngrid, gridminmax, gridpts, status);
  /* Annul keymap immediately as it is no longer required */
  if (keymap) keymap = astAnnul( keymap );

  /* Loop over number of files */
  for ( i=1; (i<= size) && (*status == SAI__OK); i++) {
    /* Open file */
    smf_open_file( NULL, igrp, i, "READ", 0, &data, status );

    /* Calculate weights based on this file */
    smf_dream_calcweights( data, ogrp, i, gridstep, ngrid, gridminmax,
                           &(gridpts[0]), status);

    /* Immediately check status on return and abort if an error occured */
    if ( *status != SAI__OK ) {
      msgSeti("I",i);
      msgSeti("N",size);
      errRep(FUNC_NAME, "Unable to determine DREAM weights for file ^I of ^N",
             status);
    }

    smf_close_file( NULL, &data, status );
  }

  /* Free up resources */
  if ( ogrp != NULL ) {
    grpDelet( &ogrp, status);
  }
  if ( igrp != NULL ) {
    grpDelet( &igrp, status);
  }
  ndfEnd( status );

  msgOutif(MSG__VERB," ", "DREAM weights calculation completed successfully",
           status);
}
コード例 #7
0
ファイル: write_ndf.c プロジェクト: Starlink/starlink
int write_ndf( int argc, void *argv[]) {
/*
** Declare variables
*/
void *arr;         /* Pointer to the data array */
int n_dims;        /* The number of dimensions */
int *arr_bnds;     /* The dimensions */
IDL_STRING *ndf_name;  /* The name of the NDF to be created */
IDL_STRING *comp;      /* The component name */
IDL_STRING *type;      /* The HDS type of the NDF to be created */
int badset;        /* Whether bad value is set */
void *bad_value;   /* Pointer to the bad value */

int status;        /* Starlink status */

int lbnd[5]={1L,1L,1L,1L,1L}; /* Lower bounds array */
int ndf;           /* NDF identifier */
int place;         /* NDF placeholder */
int npix;          /* Number of pixels */
void *ptr[3];      /* Pointer to mapped NDF data Fortran style */
size_t nbytes;     /* Number of bytes in NDF */
int bpix=1;        /* Number of bits/pixel */
int idltype=1;     /* Pixel type code */

int fstat;              /* Final status (before errLoad) */
int errn=0;             /* Error sequence number */
char param[ERR__SZPAR]; /* Error message parameter name */
int parlen;             /* Length of error message parameter name */
char opstr[ERR__SZMSG]; /* Error message */
int oplen;              /* Length of error message */

/*
** Start Error context
*/
   status = SAI__OK;
   errMark();

/*
** Check that the correct number of arguments were passed in
*/
   if(argc != 8) {
   /*
   ** Print an error message and return
   */
      status = SAI__ERROR;
      errRep( " ", "write_ndf: Incorrect number of arguments", &status );

   } else {
   /*
   ** Extract the arguments to comprehensible names
   */
      arr = argv[0];
      n_dims = *(int *)argv[1];
      arr_bnds = (int *)argv[2];
      ndf_name = (IDL_STRING *)argv[3];
      comp = (IDL_STRING *)argv[4];
      type = (IDL_STRING *)argv[5];
      badset = *(int *)argv[6];
      bad_value = (void *)argv[7];

   /*
   ** Enable NDF calls
   */
      ndfBegin();

      if ( !strcmp( comp->s, "DATA" ) ) {
      /*
      ** Create the NDF
      */
         ndfOpen( NULL, ndf_name->s, "WRITE", "NEW", &ndf, &place, &status );
         ndfNew( type->s, n_dims, lbnd, arr_bnds, &place, &ndf, &status );

      } else {
         if ( !strcmp( comp->s, "QUALITY") && strcmp(type->s, "_UBYTE")) {
            status = SAI__ERROR;
            errRep( " ", "write_ndf: Incorrect type for QUALITY", &status );
         }
      /*
      ** Open existing NDF
      */
         ndfOpen( NULL, ndf_name->s, "UPDATE", "OLD", &ndf, &place, &status );
      }

   /*
   **  Check the number of pixels is same in given array and NDF for QUALITY
   **  and VARIANCE.
   */
      if ( strcmp( comp->s, "DATA" ) ) {
         ndfSize( ndf, &npix, &status );

         if ( ( status == SAI__OK ) && ( npix != arr_bnds[n_dims+1] ) ) {
         /*
         **  Array size and NDF size do not agree
         */
            status = SAI__ERROR;
            errRep( " ",
              "write_ndf: Incorrect number elements supplied", &status );
         }
      }

   /*
   **  Obtain mapped access to the array component of the NDF
   */
      ndfMap( ndf, comp->s, type->s, "WRITE", ptr, &npix, &status );

   /*
   **  Now copy the values from ARR into the mapped NDF
   */
      if ( status == SAI__OK ) {
      /*
      **  First check the returned pointer is good
      */
         if ( ptr[0] == NULL ) {
         /*
         **  Fortran to C pointer conversion failed
         */
            status = SAI__ERROR;
            errRep( " ",
              "write_ndf: Fortran to C pointer conversion failed", &status );

         } else {
         /*
         **  then get the IDL type code and number of bytes per pixel
         */
            if (!strcmp(type->s, "_REAL")) {
               idltype = 4;
               bpix = 4;
            } else if (!strcmp(type->s, "_INTEGER")) {
               idltype = 3;
               bpix = 4;
            } else if (!strcmp(type->s, "_WORD")) {
               idltype = 2;
               bpix = 2;
            } else if (!strcmp(type->s, "_DOUBLE")) {
               idltype = 5;
               bpix = 8;
            } else if (!strcmp(type->s, "_UBYTE")) {
               idltype = 1;
               bpix = 1;
            } else {
               status = SAI__ERROR;
               msgSetc( "TYPE", type->s );
               errRep( " ", "Illegal type ^TYPE", &status );
            }

         /*
         **  Now copy the data from the array to the NDF.
         **  If we need to check for bad values in the array, use copybadout.
         **  If any bad values are found copybadout will replace them with the
         **  appropriate PRIMDAT bad value. The NDF bad pixel flag is then set
         **  depending on whether copybadout detected any bad values.
         **  If we need not check for bad pixels just copy the whole lot;
         */
            if ( status == SAI__OK ) {
               if ( badset ) {
                  if ( !copybadout( ptr[0], arr, npix, idltype, bad_value ) )
                     ndfSbad( 0, ndf, comp->s, &status);
               } else {
                  nbytes = bpix * npix;
                  memcpy( ptr[0], arr, nbytes );
               }
            }
         }
      }

   /*
   **  Close NDF
   */
      ndfEnd( &status );
   }

/*
**  Report any error messages
**  Adding Starlink-style !! and ! prefix
*/
   fstat = status;
   while ( status != SAI__OK ) {
      errLoad(
        param, ERR__SZPAR, &parlen, opstr, ERR__SZMSG, &oplen, &status );
      if ( status != SAI__OK )
         printf( "%s %s\r\n", errn++?"! ":"!!", opstr );
   }
   errRlse();

/*
**  That's it, return to the calling routine
*/
   return( fstat == SAI__OK );

}
コード例 #8
0
ファイル: smurf_sc2pca.c プロジェクト: joaogerd/starlink
void smurf_sc2pca( int *status ) {

  smfData *amplitudes=NULL;  /* Amplitudes of each component */
  smfArray *bbms=NULL;       /* Bad bolometer masks */
  smfData *components=NULL;  /* Components */
  smfArray *darks=NULL ;     /* Dark data */
  int ensureflat;            /* Flag for flatfielding data */
  smfData *data=NULL;        /* Pointer to input smfData */
  Grp *fgrp=NULL;            /* Filtered group, no darks */
  smfArray *flatramps=NULL;  /* Flatfield ramps */
  AstKeyMap *heateffmap = NULL;    /* Heater efficiency data */
  size_t i=0;                /* Counter, index */
  Grp *igrp=NULL;            /* Input group of files */
  Grp *outampgrp=NULL;       /* Output amplitude group of files */
  Grp *outcompgrp=NULL;      /* Output component group of files */
  size_t outampsize;         /* Total number of NDF names in ocompgrp */
  size_t outcompsize;        /* Total number of NDF names in ocompgrp */
  size_t size;               /* Number of files in input group */
  ThrWorkForce *wf=NULL;     /* Pointer to a pool of worker threads */

  /* 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 );

  /* Are we flatfielding? */
  parGet0l( "FLAT", &ensureflat, status );

  /* Filter out useful data (revert to darks if no science data) */
  smf_find_science( wf, 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;

  if( size > 0 ) {
    /* Get output file(s) */
    kpg1Wgndf( "OUTAMP", igrp, size, size, "More output files required...",
               &outampgrp, &outampsize, status );

    kpg1Wgndf( "OUTCOMP", igrp, size, size, "More output files required...",
               &outcompgrp, &outcompsize, status );
  } else {
    msgOutif(MSG__NORM, " ","All supplied input frames were DARK,"
       " nothing to flatfield", status );
  }

  /* Get group of bolometer masks and read them into a smfArray */
  smf_request_mask( wf, "BBM", &bbms, status );

  for( i=1; i<=size; i++ ) {

    if( *status != SAI__OK ) break;

    /* Load data, flatfielding and/or opening raw as double as necessary */
    smf_open_asdouble( wf, igrp, i, darks, flatramps, heateffmap, ensureflat, &data, status );

    /* Mask out bad bolometers */
    smf_apply_mask( wf, data, bbms, SMF__BBM_DATA|SMF__BBM_QUAL, 0, status );

    /* Sync quality with bad values */
    smf_update_quality( wf, data, 1, NULL, 0, 0.05, status );

    /* Calculate the PCA */
    smf_clean_pca( wf, data, 0, 0, 0, &components, &amplitudes, 0, 1, NULL,
                   status );

    /* Write out to the new files */
    smf_write_smfData( wf, amplitudes, NULL, NULL, outampgrp, i, 0, MSG__VERB,
                       0, status );
    smf_write_smfData( wf, components, NULL, NULL, outcompgrp, i, 0, MSG__VERB,
                       0, status );

    /* Free resources for output data */
    smf_close_file( wf, &data, status );
    smf_close_file( wf, &amplitudes, status );
    smf_close_file( wf, &components, status );
  }

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK && outampgrp ) {
    grpList( "OUTAMPFILES", 0, 0, NULL, outampgrp, status );
    if( *status == PAR__NULL ) errAnnul( status );
  }
  if( *status == SAI__OK && outcompgrp ) {
    grpList( "OUTCOMPFILES", 0, 0, NULL, outcompgrp, status );
    if( *status == PAR__NULL ) errAnnul( status );
  }

  /* Tidy up after ourselves: release the resources used by the grp routines  */
  if( igrp ) grpDelet( &igrp, status);
  if( outampgrp ) grpDelet( &outampgrp, status);
  if( outcompgrp ) grpDelet( &outcompgrp, status);
  if( darks ) smf_close_related( wf, &darks, status );
  if( bbms ) smf_close_related( wf, &bbms, status );
  if( flatramps ) smf_close_related( wf, &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  ndfEnd( status );
}
コード例 #9
0
ファイル: smf_get_mask.c プロジェクト: bbrond/starlink
unsigned char *smf_get_mask( ThrWorkForce *wf, smf_modeltype mtype,
                             AstKeyMap *config, smfDIMMData *dat, int flags,
                             int *status ) {

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

/* Initialise returned values */
   result = NULL;

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

/* Begin an AST context. */
   astBegin;

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

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

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

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

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

         isstatic = 1;
         nmask = 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* Return the pointer to the boolean mask. */
   return result;
}
コード例 #10
0
ファイル: configecho.c プロジェクト: bbrond/starlink
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 );
   }

}
コード例 #11
0
ファイル: smurf_unmakecube.c プロジェクト: andrecut/starlink
void smurf_unmakecube( int *status ) {

/* Local Variables */
   AstFrame *tfrm = NULL;       /* Current Frame from input WCS */
   AstFrameSet *wcsin = NULL;   /* WCS Frameset for input cube */
   AstMapping *tmap = NULL;     /* Base->current Mapping from input WCS */
   AstSkyFrame *iskyfrm = NULL; /* SkyFrame from the input WCS Frameset */
   Grp *detgrp = NULL;        /* Group of detector names */
   Grp *igrp1 = NULL;         /* Group of input sky cube files */
   Grp *igrp2 = NULL;         /* Group of input template files */
   Grp *ogrp = NULL;          /* Group containing output file */
   NdgProvenance *oprov = NULL;/* Provenance for the output NDF */
   SkyCube *sky_cubes = NULL; /* Pointer to array of sky cube descriptions */
   SkyCube *skycube = NULL;   /* Pointer to next sky cube description */
   char pabuf[ 10 ];          /* Text buffer for parameter value */
   double params[ 4 ];        /* astResample parameters */
   int axes[ 2 ];             /* Indices of selected axes */
   int blank;                 /* Was a blank line just output? */
   int flag;                  /* Was the group expression flagged? */
   int ifile;                 /* Input file index */
   int interp = 0;            /* Pixel interpolation method */
   int iskycube;              /* Index of current sky cube */
   int nel;                   /* Number of elements in 3D array */
   int nparam = 0;            /* No. of parameters required for interpolation scheme */
   int ondf;                  /* Output time series NDF identifier */
   int outax[ 2 ];            /* Indices of corresponding output axes */
   int overlap;               /* Does time series overlap sky cube? */
   int sdim[3];               /* Array of significant pixel axes */
   int usedetpos;             /* Should the detpos array be used? */
   size_t ndet;               /* Number of detectors supplied for "DETECTORS" */
   size_t nskycube;           /* Number of supplied sky cubes */
   size_t outsize;            /* Number of files in output group */
   size_t size;               /* Number of files in input group */
   smfData *data = NULL;      /* Pointer to data struct */
   void *in_data = NULL;      /* Pointer to the input cube data array */
   void *out_data = NULL;     /* Pointer to the output cube data array */

#if defined(FPTRAP)
   feenableexcept(FE_DIVBYZERO|FE_INVALID|FE_OVERFLOW);
#endif

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

/* We have not yet displayed a blank line on stdout. */
   blank = 0;

/* Begin an AST context */
   astBegin;

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

/* Get a group holding the input sky cubes. */
   kpg1Rgndf( "IN", 0, 1, "", &igrp1, &nskycube, status );

/* Create an array of structures to hold information about each input sky
   cube. */
   sky_cubes = astMalloc( sizeof( SkyCube )*(size_t) nskycube );

/* Store a description of each sky cube. */
   if( sky_cubes ) {
      for( iskycube = 0; iskycube < nskycube; iskycube++ ) {
         skycube = sky_cubes + iskycube;

/* Get an NDF identifier for the next sky cube. */
         ndgNdfas( igrp1, iskycube + 1, "READ", &(skycube->indf), status );

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

/* Get the base->current Mapping from the input WCS FrameSet, and split it
   into two Mappings; one (iskymap) that maps the first 2 GRID axes into
   celestial sky coordinates, and one (ispecmap) that maps the third GRID
   axis into a spectral coordinate. Also extract the SpecFrame and
   SkyFrame from the current Frame. */
         tmap = astGetMapping( wcsin, AST__BASE, AST__CURRENT );
         tfrm = astGetFrame( wcsin, AST__CURRENT );

         axes[ 0 ] = 1;
         axes[ 1 ] = 2;
         astMapSplit( tmap, 2, axes, outax, &(skycube->iskymap) );
         iskyfrm = astPickAxes( tfrm, 2, outax, NULL );

         axes[ 0 ] = 3;
         astMapSplit( tmap, 1, axes, outax, &(skycube->ispecmap) );
         skycube->ispecfrm = astPickAxes( tfrm, 1, outax, NULL );

/* Create a copy of "iskyfrm" representing absolute coords rather than
   offsets. We assume the target is moving if the cube represents offsets. */
         skycube->abskyfrm = astCopy( iskyfrm );
         astClear( skycube->abskyfrm, "SkyRefIs" );
         skycube->moving = ( *status == SAI__OK &&
                             !strcmp( astGetC( iskyfrm, "SkyRefIs" ),
                                      "Origin" ) ) ? 1 : 0;

/* Invert the Mappings (for the convenience of smf_resamplecube), so
   that they go from current Frame to grid axis. */
         astInvert( skycube->ispecmap );
         astInvert( skycube->iskymap );

/* For efficiency, annul manually the unneeded AST objects created in
   this loop. */
         wcsin = astAnnul( wcsin );
         tmap = astAnnul( tmap );
         tfrm = astAnnul( tfrm );
         iskyfrm = astAnnul( iskyfrm );
      }
   }

/* See if the detector positions are to be read from the RECEPPOS array
   in the template NDFs. Otherwise, they are calculated on the basis of
   the FPLANEX/Y arrays. */
   parGet0l( "USEDETPOS", &usedetpos, status );

/* Get the detectors to use. If a null value is supplied, annull the
   error. Otherwise, make the group case insensitive. */
   detgrp = NULL;
   if( *status == SAI__OK ) {
      kpg1Gtgrp( "DETECTORS", &detgrp, &ndet, status );
      if( *status == PAR__NULL ) {
         errAnnul( status );
	 if (detgrp) {
	   grpDelet( &detgrp, status );
	 }
      } else {
         grpSetcs( detgrp, 0, status );
      }
   }

/* 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 );

/* Create a group holding the names of the corresponding output NDFs. */
   ndgCreat ( "OUT", igrp2, &ogrp, &outsize, &flag, status );
   if( outsize != size && *status == SAI__OK ) {
      *status = SAI__ERROR;
      msgSeti( "O", outsize );
      msgSeti( "I", size );
      errRep( "", "Numbers of input reference cubes (^I) and output "
              "cubes (^O) differ.", status );
   }

/* Loop round all the template time series files. */
   for( ifile = 1; ifile <= size && *status == SAI__OK; ifile++ ) {

/* Start a new NDF context. */
      ndfBegin();

/* Obtain information about the current template NDF, but do not map the
   arrays. */
      smf_open_file( igrp2, ifile, "READ", SMF__NOCREATE_DATA, &data, 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( 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;

         }
      }

/* Report the name of the input template. */
      smf_smfFile_msg( data->file, "FILE", 1, "<unknown>" );
      msgSeti( "THISFILE", ifile );
      msgSeti( "NUMFILES", size );
      msgOutif( MSG__NORM, " ", "Simulating ^THISFILE/^NUMFILES ^FILE",
                status );

/* Create the output NDF by propagation from the input template NDF.
   Everything is copied except for the array components and any PROVENANCE
   extension. */
      ndgNdfpr( data->file->ndfid, "TITLE,LABEL,UNITS,AXIS,WCS,HISTORY,"
                "NOEXTENSION(PROVENANCE)", ogrp, ifile, &ondf, status );

/* Ensure the output NDF has a history component. */
      ndfHcre( ondf, status );

/* Get a pointer to the mapped output data array. Set all values bad. */
      ndfMap( ondf, "DATA", "_REAL", "WRITE/BAD", &out_data, &nel, status );

/* If the detector positions are to calculated on the basis of FPLANEX/Y
   rather than detpos, then free the detpos array in the templates smfHead
   structure. This will cause smf_tslice_ast to use the fplanex/y values. */
      if( !usedetpos && data->hdr->detpos ) {
         astFree( (double *) data->hdr->detpos );
         data->hdr->detpos = NULL;
      }

/* Get a pointer to a structure holding provenance information for the
   output time series. */
      oprov = ndgReadProv( ondf, "SMURF:UNMAKECUBE", status );

/* Record details of the template in the provenance structure for the
   output time series. */
      ndgPutProv( oprov, data->file->ndfid, NULL, 0, status );

/* Loop round all input sky cubes. */
      for( iskycube = 0; iskycube < nskycube; iskycube++ ) {
         skycube = sky_cubes + iskycube;

/* Record details of the input cube in the provenance extension of the
   output time series. */
         ndgPutProv( oprov, skycube->indf, NULL, 0, status );

/* See if the current time series overlaps the current sky cube. */
         smf_resampcube( data, skycube->abskyfrm,
                         skycube->iskymap, skycube->ispecfrm,
                         skycube->ispecmap, detgrp, skycube->moving,
                         skycube->slbnd, skycube->subnd, interp,
                         params, NULL, NULL, &overlap, status );

/* If not, pass on to the next sky cube. */
         if( overlap ) {

/* Report the name of the sky cube. */
            ndfMsg( "NDF", skycube->indf );
            msgOutif( MSG__NORM, " ", "   Re-sampling ^NDF", status );

/* Map the data array in the current sky cube. */
            ndfMap( skycube->indf, "DATA", "_REAL", "READ", &in_data, &nel,
                    status );

/* Resample the cube data into the output time series. */
            smf_resampcube( data, skycube->abskyfrm,
                            skycube->iskymap, skycube->ispecfrm,
                            skycube->ispecmap, detgrp, skycube->moving,
                            skycube->slbnd, skycube->subnd, interp,
                            params, in_data, out_data, &overlap, status );

/* Unmap the data array. */
            ndfUnmap( skycube->indf, "DATA", status );
         }
      }

/* Write the provenance structure to the output NDF, and then free it. */
      ndgWriteProv( oprov, ondf, 1, status );
      oprov =ndgFreeProv( oprov, status );

/* Close the input time series file. */
      if( data != NULL ) {
         smf_close_file( &data, status );
         data = NULL;
      }

/* 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( data != NULL ) {
      smf_close_file( &data, status );
      data = NULL;
   }

/* Free remaining resources. */
   if( detgrp != NULL) grpDelet( &detgrp, status);
   if( igrp1 != NULL) grpDelet( &igrp1, status);
   if( igrp2 != NULL) grpDelet( &igrp2, status);
   if( ogrp != NULL) grpDelet( &ogrp, status);
   sky_cubes = astFree( sky_cubes );

/* 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);
   }
}
コード例 #12
0
ファイル: smf_initial_sky.c プロジェクト: astrobuff/starlink
int smf_initial_sky( ThrWorkForce *wf, AstKeyMap *keymap, smfDIMMData *dat,
                     int *iters, int *status ) {

/* Local Variables: */
   char refparam[ DAT__SZNAM ];/* Name for reference NDF parameter */
   const char *cval;          /* The IMPORTSKY string value */
   double *ptr;               /* Pointer to NDF Data array */
   double *vptr;              /* Pointer to NDF Variance array */
   int indf1;                 /* Id. for supplied reference NDF */
   int indf2;                 /* Id. for used section of reference NDF */
   int nel;                   /* Number of mapped NDF pixels */
   int result;                /* Returned flag */
   int there;                 /* Is there a smurf extension in the NDF? */
   int update;                /* Was NDF opened for UPDATE access? */
   size_t i;                  /* Loop count */
   size_t junk;               /* Unused value */

/* Initialise the returned value to indicate no sky has been subtractred. */
   result = 0;

/* Assume the sky map was not created by an interupted previous run of
   makemap. */
   *iters = -1;

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

/* Begin an AST context. */
   astBegin;

/* The IMPORTSKY config parameter should have the name of the ADAM
   parameter to use for acquiring the NDF that contains the initial sky
   estimate. If IMPORTSKY is "1", use REF. */
   cval = NULL;
   astMapGet0C( keymap, "IMPORTSKY", &cval );
   if( cval ) {
      if( !astChrMatch( cval, "REF" ) &&
          !astChrMatch( cval, "MASK2" ) &&
          !astChrMatch( cval, "MASK3" ) ) {
         astMapGet0I( keymap, "IMPORTSKY", &result );
         cval = ( result > 0 ) ? "REF" : NULL;
      }
      if( cval ) {
         result = 1;
         strcpy( refparam, cval );
         astChrCase( NULL, refparam, 1, 0 );
      }
   }

/* Do nothing more if we are not subtracting an initial sky from the data. */
   if( result && *status == SAI__OK ) {

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

/* Get an identifier for the NDF using the associated ADAM parameter.
   First try UPDATE access. If this fails try READ access. */
      ndfAssoc( refparam, "UPDATE", &indf1, status );
      if( *status != SAI__OK ) {
         errAnnul( status );
         ndfAssoc( refparam, "READ", &indf1, status );
         update = 0;
      } else {
         update = 1;
      }

/* Tell the user what we are doing. */
      ndfMsg( "N", indf1 );
      msgOut( "", "Using ^N as the initial guess at the sky", status );

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

/* Ensure masked values are not set bad in the mapped data array. */
      ndfSbb( 0, indf2, status );

/* Map the data array section, and copy it into the map buffer. */
      ndfMap( indf2, "DATA", "_DOUBLE", "READ", (void **) &ptr, &nel, status );
      if( *status == SAI__OK ) {
         memcpy( dat->map, ptr, dat->msize*sizeof(*ptr));
      }

/* Map the variance array section, and copy it into the map buffer. */
      ndfState( indf2, "VARIANCE", &there, status );
      if( there ) {
         ndfMap( indf2, "VARIANCE", "_DOUBLE", "READ", (void **) &vptr, &nel, status );
         if( *status == SAI__OK ) {
            memcpy( dat->mapvar, vptr, dat->msize*sizeof(*vptr));
         }
      }

/* If the NDF was created by a previous run of makemap that was interupted
   using control-C, it will contain a NUMITER item in the smurf extension,
   which gives the number of iterations that were completed before the
   map was created. Obtain and return this value, if it exists. */
      ndfXstat( indf1, SMURF__EXTNAME, &there, status );
      if( there ) ndfXgt0i( indf1, SMURF__EXTNAME, "NUMITER", iters,
                            status );

/* If the NDF has a Quality component, import it and create initial AST,
   FLT, PCA, SSN and COM masks from it. These will often be over-ridden by
   new masks calculated with smf_calcmodel_ast below, but will not be
   over-written if the masks have been frozen by xxx.zero_freeze. */
      ndfState( indf2, "Quality", &there, status );
      if( there && dat->mapqual ) {
         smf_qual_t *qarray = smf_qual_map( wf, indf2, "Read", NULL, &junk,
                                            status );
         if( *status == SAI__OK ) {
            smf_qual_t *pq = qarray;
            for( i = 0; i < dat->msize; i++,pq++ ) {
               if( *pq & SMF__MAPQ_AST ) {
                  if( !dat->ast_mask ) dat->ast_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->ast_mask) ) );
                  (dat->ast_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_FLT ) {
                  if( !dat->flt_mask ) dat->flt_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->flt_mask) ) );
                  (dat->flt_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_COM ) {
                  if( !dat->com_mask ) dat->com_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->com_mask) ) );
                  (dat->com_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_SSN ) {
                  if( !dat->ssn_mask ) dat->ssn_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->ssn_mask) ) );
                  (dat->ssn_mask)[ i ] = 1;
               }
               if( *pq & SMF__MAPQ_PCA ) {
                  if( !dat->pca_mask ) dat->pca_mask = astCalloc( dat->msize,
                                                  sizeof( *(dat->pca_mask) ) );
                  (dat->pca_mask)[ i ] = 1;
               }
            }
         }
         qarray = astFree( qarray );
      }

/* Indicate the map arrays within the supplied smfDIMMData structure now
   contain usable values. We need to do this before calling
   smf_calcmodel_ast below so that the right mask gets used in
   smf_calcmodel_ast. */
      dat->mapok = 1;

/* Apply any existinction correction to the cleaned bolometer data. */
      if( dat->ext ) smf_calcmodel_ext( wf, dat, 0, keymap, dat->ext, 0,
                                        status);

/* Sample the above map at the position of each bolometer sample and
   subtract the sampled value from the cleaned bolometer value. */
      smf_calcmodel_ast( wf, dat, 0, keymap, NULL, SMF__DIMM_PREITER, status);

/* Remove any existinction correction to the modifed bolometer data. */
      if( dat->ext ) smf_calcmodel_ext( wf, dat, 0, keymap, dat->ext,
                                        SMF__DIMM_INVERT, status);

/* If the NDF was opened with UPDATE access, update the quality array in
   the NDF to reflect the AST mask created by smf_calcmodel_ast above. */
      if( update ) {
         smf_qual_t *qarray = astStore( NULL, dat->mapqual, dat->msize*sizeof(*qarray) );
         qarray = smf_qual_unmap( wf, indf2, SMF__QFAM_MAP, qarray, status );
      }

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

/* End the AST context. */
   astEnd;

/* Return the pointer to the boolean mask. */
   return result;
}
コード例 #13
0
ファイル: smurf_flatfield.c プロジェクト: astrobuff/starlink
void smurf_flatfield( int *status ) {

  smfArray *bbms = NULL;     /* Bad bolometer masks */
  smfData *ffdata = NULL;   /* Pointer to output data struct */
  Grp *fgrp = NULL;         /* Filtered group, no darks */
  smfArray *flatramps = NULL;/* Flatfield ramps */
  AstKeyMap *heateffmap = NULL;    /* Heater efficiency data */
  size_t i = 0;             /* Counter, index */
  Grp *igrp = NULL;         /* Input group of files */
  Grp *ogrp = NULL;         /* Output group of files */
  size_t outsize;           /* Total number of NDF names in the output group */
  size_t size;              /* Number of files in input group */

  /* Main routine */
  ndfBegin();

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

  /* Filter out darks */
  smf_find_science( NULL, igrp, &fgrp, 0, NULL, NULL, 1, 1, SMF__NULL, NULL,
                    &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;

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

  /* Get group of bolometer masks and read them into a smfArray */
  smf_request_mask( NULL, "BBM", &bbms, status );

  for (i=1; i<=size; i++ ) {
    int didflat;

    if (*status != SAI__OK) break;

    /* Call flatfield routine */
    didflat = smf_open_and_flatfield( NULL, igrp, ogrp, i, NULL, flatramps,
                                      heateffmap, &ffdata, status);

    /* Report failure by adding a message indicating which file failed */
    msgSeti("I",i);
    if (*status != SAI__OK) {
      msgSeti("N",size);
      errRep(FUNC_NAME,	"Unable to flatfield data from file ^I of ^N", status);
      break;
    }

    /* in verbose mode report whether flatfielding occurred or not */
    if (!didflat) {
      msgOutif(MSG__VERB," ",
	     "Data from file ^I are already flatfielded", status);
    } else {
      msgOutif(MSG__VERB," ", "Flat field applied to file ^I", status);
    }

    /* Mask out bad bolometers - mask data array not quality array */
    smf_apply_mask( NULL, ffdata, bbms, SMF__BBM_DATA, 0, status );

    /* Free resources for output data */
    smf_close_file( NULL, &ffdata, status );
  }

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK && ogrp ) {
    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  */
  if (igrp) grpDelet( &igrp, status);
  if (ogrp) grpDelet( &ogrp, status);
  if (bbms) smf_close_related( NULL, &bbms, status );
  if( flatramps ) smf_close_related( NULL, &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  ndfEnd( status );
}
コード例 #14
0
ファイル: smurf_unmakemap.c プロジェクト: gmarsden/starlink
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 *igrpq = NULL;         /* Group of input Q  sky files */
   Grp *igrpu = NULL;         /* Group of input U sky files */
   Grp *ogrp = NULL;          /* Group containing output file */
   ThrWorkForce *wf = NULL;   /* Pointer to a pool of worker threads */
   char pabuf[ 10 ];          /* Text buffer for parameter value */
   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 *in_data = NULL;    /* Pointer to the input I sky map */
   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 *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 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 sigma;              /* Standard deviation of noise to add to output */
   int alignsys;              /* Align data in the map's system? */
   int flag;                  /* Was the group expression flagged? */
   int harmonic;              /* The requested harmonic */
   int ifile;                 /* Input file index */
   int indf;                  /* Input sky map NDF identifier */
   int indfin;                /* Input template cube NDF identifier */
   int indfout;               /* Output cube NDF identifier */
   int indfq;                 /* Input Q map NDF identifier */
   int indfu;                 /* Input U map NDF identifier */
   int interp = 0;            /* Pixel interpolation method */
   int moving;                /* Is the telescope base position changing? */
   int nel;                   /* Number of elements in 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 */
   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 );
      }
   }

/* 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 );

/* 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 );

/* 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 );

/* Allocate room for an array to hold the anti-clockwise angle from the
   focal plane Y axis to the Y pixel axis in the reference map, at each
   time slice. */
         ang_data = astMalloc( ntslice*sizeof( *ang_data ) );

/* Resample them both into 3D time series. */
         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,
                         harmonic, status );

/* Release work space. */
         outq_data = astFree( outq_data );
         outu_data = astFree( outu_data );
         ang_data = astFree( ang_data );
      }

/* Close the output time series file. */
      smf_close_file( wf, &odata, 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( ogrp != NULL) grpDelet( &ogrp, 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);
   }
}
コード例 #15
0
void smurf_fts2_spectrum(int* status)
{
    if( *status != SAI__OK ) { return; }

    const char*  dataLabel    = "Spectrum";     /* Data label */
    Grp* gIn                  = NULL;           /* Input group */
    Grp* gOut                 = NULL;           /* Output group */
    Grp* gSfp                 = NULL;           /* SFP group */
    smfData* inData           = NULL;           /* Pointer to input data */
    smfData* outData          = NULL;           /* Pointer to output data */
    smfData* sfpData          = NULL;           /* Pointer to SFP data */
  /*smfData* sfp              = NULL;*/         /* Pointer to SFP index data */
    int doSFP                 = 0;              /* Only apply SFP if given */
    int zeropad               = 1;              /* Determines whether to zeropad */
    double resolution         = 0.0;            /* Spectral Resolution */
    double resolutionin       = 0.0;            /* Spectral Resolution input */
    double resolutionzp       = 0.0;            /* Spectral Resolution zero padded */
    double resolution_override= 0.0;            /* Spectral Resolution override */
    int i                     = 0;              /* Counter */
    int j                     = 0;              /* Counter */
    int k                     = 0;              /* Counter */
    int l                     = 0;              /* Counter */
    double fNyquist           = 0.0;            /* Nyquist frequency */
    double fNyquistin         = 0.0;            /* Nyquist frequency input */
    double fNyquistzp         = 0.0;            /* Nyquist frequency zero padded */
    double dSigma             = 0.0;            /* Spectral Sampling Interval */
    double dSigmain           = 0.0;            /* Spectral Sampling Interval zero padded */
    double dSigmazp           = 0.0;            /* Spectral Sampling Interval zero padded */
    double* IFG               = NULL;           /* Interferogram */
    double* SFP               = NULL;           /* Spectral Filter Profile for all pixels */
    double* SFPij             = NULL;           /* Spectral Filter Profile for a single pixel */
    double wavelen            = 0.0;            /* The central wave length of the subarray filter (m) */
    double wnSfpFirst         = 10.600;         /* Starting 850 band SFP wave number */
    double wnSfpLast          = 12.800;         /* Ending 850 band SFP wave number */
    double wnSfp850First      = 11.220;         /* Starting 850 band SFP wave number */
    double wnSfp850Last       = 12.395;         /* Ending 850 band SFP wave number */
  /*double wnSfp850First      = 10.600;*/       /* Starting 850 band SFP wave number */
  /*double wnSfp850Last       = 12.800;*/       /* Ending 850 band SFP wave number */
    double wnSfp450First      = 21.630;         /* Starting 450 band SFP wave number */
    double wnSfp450Last       = 23.105;         /* Ending 450 band SFP wave number */
    double wnSfpFirst_override= 0.0;            /* Starting SFP wave number override */
    double wnSfpLast_override = 0.0;            /* Ending SFP wave number override */
    double wnSfpResolution    = 0.025;          /* The resolution of the SFP wave numbers (1/cm) */
    double wnSfpF             = 0.0;            /* Starting SFP wave number */
    double wnSfpL             = 0.0;            /* Ending SFP wave number */
    double* WN                = NULL;           /* Wave Numbers from SFP */
    double* DS                = NULL;           /* Double Sided Interferogram */
    fftw_complex* DSIN        = NULL;           /* Double-Sided interferogram, FFT input */
    fftw_complex* SPEC        = NULL;           /* Spectrum */
    fftw_plan plan            = NULL;           /* fftw plan */
    gsl_interp_accel* ACC     = NULL;           /* SFP interpolator */
    gsl_spline* SPLINE        = NULL;           /* SFP interpolation spline */

    size_t nFiles             = 0;              /* Size of the input group */
    size_t nOutFiles          = 0;              /* Size of the output group */
    size_t nSFPFiles          = 0;              /* Size of the SFP group */
    size_t nSfp               = 89;             /* Number of SFP calibration file values */
    size_t fIndex             = 0;              /* File index */
    size_t nWidth             = 32;             /* Data cube width */
    size_t nHeight            = 40;             /* Data cube height */
    size_t nFrames            = 0;              /* Data cube depth */
    size_t nPixels            = nWidth*nHeight; /* Number of bolometers in the subarray */

    double dIntensity         = 0;
    int N                     = 0;
    int Nin                   = 0;                /* N input */
    int Nzp                   = 0;                /* N zero padded */
    int N2                    = 0;
    int N2in                  = 0;                /* N/2 input */
    int N2zp                  = 0;                /* N/2 zero padded */
    int bolIndex              = 0;
    int cubeIndex             = 0;
    int badPixel              = 0;
    int indexZPD              = 0;
    int indexZPDin            = 0;
    int indexZPDzp            = 0;
    int pad                   = 0;               /* zero padding (difference between input and zero padded interferogram length) */
    int pad2                  = 0;               /* zero padding / 2 */
    double dx                 = 0.0;             /* Delta x */
    double dxin               = 0.0;             /* Delta x input */
    double dxzp               = 0.0;             /* Delta x zero padded */
    double OPDMax             = 0.0;             /* OPD max in cm */
    double OPDMaxin           = 0.0;             /* OPD max in cm input */
    double OPDMaxzp           = 0.0;             /* OPD max in cm zero padded */
    double s                  = 0.0;             /* spectrum value */
    double f                  = 0.0;             /* filter value */

#define DEBUG 0

    /* Get Input & Output groups */
    kpg1Rgndf("IN", 0, 1, "", &gIn, &nFiles, status);
    kpg1Wgndf("OUT", gOut, nFiles, nFiles, "Equal number of input and output files expected!", &gOut, &nOutFiles, status);
    kpg1Gtgrp("SFP", &gSfp, &nSFPFiles, status);
    if(*status != SAI__OK) {
        /* TODO: Check for any other possible error conditions */
        /* Assume SFP calibration file not given, and proceed without it */
        doSFP = 0;
        *status = SAI__OK;
    } else {
	    if(nSFPFiles > 0) doSFP = 1;
    }

    /* Read in ADAM parameters */
    parGet0i("ZEROPAD", &zeropad, status);

    /* Resolution */
    parGet0d("RESOLUTION", &resolution_override, status);

    if(doSFP) {
        /* SFP WN Range overrides */
        parGet0d("WNSFPFIRST", &wnSfpFirst_override, status);
			if(*status != SAI__OK) {
				*status = SAI__OK;  /* Allow null */
				wnSfpFirst_override = 0.0;
			}
        parGet0d("WNSFPLAST", &wnSfpLast_override, status);
			if(*status != SAI__OK) {
				*status = SAI__OK;  /* Allow null */
				wnSfpLast_override = 0.0;
			}
    }

    /* BEGIN NDF */
    ndfBegin();


    /* Loop through each input file */
    for(fIndex = 1; fIndex <= nFiles; fIndex++) {
        /* Open Observation file */
        smf_open_file(NULL, gIn, fIndex, "READ", SMF__NOFIX_METADATA, &inData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to open the source file!", status);
            goto CLEANUP;
        }

        /* Data cube dimensions */
        nWidth  = inData->dims[0];
        nHeight = inData->dims[1];
        nFrames = inData->dims[2];
        nPixels = nWidth * nHeight;

        /*printf("%s: nWidth=%d, nHeight=%d, nPixels=%d, nFrames=%d\n", TASK_NAME, nWidth, nHeight, nPixels, nFrames);*/

        /* Check if the file is initialized for FTS2 processing */
        if(!(inData->fts)) {
            *status = SAI__ERROR;
            errRep( FUNC_NAME, "The file is NOT initialized for FTS2 data reduction!", status);
            goto CLEANUP;
        }

        /* Read in the Nyquist frequency from FITS component */
        smf_fits_getD(inData->hdr, "FNYQUIST", &fNyquist, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to find the Nyquist frequency in FITS component!", status);
            goto CLEANUP;
        }

        /* Read in the wave length (m) from the FITS header to determine the band */
        smf_fits_getD(inData->hdr, "WAVELEN", &wavelen, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to find the wavelen in the FITS header!", status);
            goto CLEANUP;
        }

        /* Set WN SFP range according to band */
        if(wavelen == 0.00085) {
            wnSfpFirst = wnSfp850First;
            wnSfpLast = wnSfp850Last;
        } else if(wavelen == 0.00045) {
            wnSfpFirst = wnSfp450First;
            wnSfpLast = wnSfp450Last;
        }

      /*printf("%s: wnSfpFirst_override=%f, wnSfpLast_override=%f\n", TASK_NAME, wnSfpFirst_override, wnSfpLast_override);*/
      /*printf("%s: wnSfpFirst=%f, wnSfpLast=%f\n", TASK_NAME, wnSfpFirst, wnSfpLast);*/
        if(wnSfpFirst_override) {
            wnSfpF = wnSfpFirst_override;
        } else {
            wnSfpF = wnSfpFirst;
        }
        if(wnSfpLast_override) {
            wnSfpL = wnSfpLast_override;
        } else {
            wnSfpL = wnSfpLast;
        }
      /*printf("%s: wnSfpF=%f, wnSfpL=%f\n", TASK_NAME, wnSfpF, wnSfpL);*/

        fNyquistin = fNyquistzp = 0.0;
        dx = dxin = dxzp = 0.0;
        N2 = N2in = N2zp = 0;
        indexZPD = indexZPDin = indexZPDzp = 0;
        N = Nin = Nzp = 0;
        dSigma = dSigmain = dSigmazp = 0.0;

        fNyquistin = fNyquist;
        dxin = (1/(2*fNyquistin));
        N2in = (nFrames / 2);
        indexZPDin = N2in - 1;
        Nin = 2 * N2in;
        OPDMaxin = N2in * dxin;
        if(resolution_override > 0.0) {
            resolution = resolution_override;
            resolutionin = resolution_override;
        } else {
            resolution = 1 / (2 * OPDMaxin);
            resolutionin = resolution;
        }
        dSigmain = fNyquistin / N2in;

        if(zeropad) {
            if(DEBUG) {
                /* Make the zero-padded array twice the size of the input */
                fNyquistzp = fNyquist;
                Nzp = N2in * 4;
                N2zp = Nzp / 2;
                dxzp = 1 / (2 * fNyquistzp);
                OPDMaxzp = N2zp * dxzp;
                dSigmazp = fNyquistzp / N2zp;
                resolutionzp = 1 / (2 * OPDMaxzp);
            } else {
                /* Round Nyquist frequency down to nearest integer, for calculation convenience
                fNyquistzp = floor(fNyquist);

                smf_fits_updateD(inData->hdr, "FNYQUIST", fNyquistzp, "Nyquist frequency (cm^-1)", status);*/

                /* Never change nyquist when zero padding */
                fNyquistzp = fNyquist;

                /* If resolution > 0.05, then round down to nearest 0.05 value, else set to 0.005 */
                /* Calculate resolution as 1 / (2*OPDMax) */
                /* Calculate OPDMax as N2 * dx */

                if(resolution_override) {
                    resolutionzp = resolution_override;
                } else {
                    if(resolution > 0.05) {
                        resolutionzp = floor(resolution/0.05) * 0.05;
                    } else {
                        resolutionzp = 0.005;
                    }
                }

                /* Calculate OPDMaxOut  as 1 / (2 * resolutionzp) */
                OPDMaxzp = 1 / (2 * resolutionzp);

                /* Calculate N2 */
                dxzp = (1/(2*fNyquistzp));
                N2zp = (OPDMaxzp / dxzp);
                indexZPDzp = N2zp - 1;
                Nzp = 2 * N2zp;
                dSigmazp = fNyquistzp / N2zp;
            }
        }

      /*printf("%s: Nin=%d, Nzp=%d, N2in=%d, N2zp=%d, indexZPDin=%d, indexZPDzp=%d, dSigmain=%f, dSigmazp=%f, fNyquistin=%f, fNyquistzp=%f, dxin=%f, dxzp=%f, OPDMaxin=%f, OPDMaxzp=%f, resolutionin=%f, resolutionzp=%f\n",
               TASK_NAME, Nin, Nzp, N2in, N2zp, indexZPDin, indexZPDzp, dSigmain, dSigmazp, fNyquistin, fNyquistzp, dxin, dxzp, OPDMaxin, OPDMaxzp, resolutionin, resolutionzp);*/

        if(zeropad) {
            N = Nzp;
            N2 = N2zp;
            indexZPD = indexZPDzp;
            dSigma = dSigmazp;
            fNyquist = fNyquistzp;
            dx = dxzp;
            OPDMax = OPDMaxzp;
            resolution = resolutionzp;
        } else {
            N = Nin;
            N2 = N2in;
            indexZPD = indexZPDin;
            dSigma = dSigmain;
            fNyquist = fNyquistin;
            dx = dxin;
            OPDMax = OPDMaxin;
            resolution = resolutionin;
        }

        /* Save wavenumber factor to FITS extension */
        smf_fits_updateD(inData->hdr, "WNFACT", dSigma, "Wavenumber factor cm^-1", status);

        /* TODO: Update mirror positions */
        smf_fits_updateI(inData->hdr, "MIRSTART", 0, "Frame index in which the mirror starts moving", status);
        smf_fits_updateI(inData->hdr, "MIRSTOP", N2, "Frame index in which the mirror stops moving", status);
      /*smf_fits_updateD(inData->hdr, "OPDMIN", OPD_EVEN[0], "Minimum OPD", status);
        smf_fits_updateD(inData->hdr, "OPDSTEP", dx, "OPD step size", status);*/


        /* Copy input data into output data */
        outData = smf_deepcopy_smfData(NULL, inData, 0, SMF__NOCREATE_DATA, 0, 0, status);
        outData->dtype   = SMF__DOUBLE;
        outData->ndims   = 3;
        outData->dims[0] = nWidth;
        outData->dims[1] = nHeight;
        outData->dims[2] = N2+1;
        outData->pntr[0] = (double*) astMalloc((nPixels * (N2+1)) * sizeof(double));
        if (dataLabel) { one_strlcpy(outData->hdr->dlabel, dataLabel, sizeof(outData->hdr->dlabel), status ); }

        /* Allocate memory for arrays */
        IFG  = astCalloc(N,  sizeof(*IFG));
        DS   = astCalloc(N, sizeof(*DS));
        DSIN = fftw_malloc(N * sizeof(*DSIN));
        SPEC = fftw_malloc(N * sizeof(*SPEC));

        /* Initialize arrays */
        for(k = 0; k < N; k++) { SPEC[k][0] = SPEC[k][1] = DSIN[k][0] = DSIN[k][1] = DS[k] = IFG[k] = 0.0; }

        /* Open the SFP calibration file, if given */
        if(doSFP) {
            smf_open_file(NULL, gSfp, 1, "READ", SMF__NOCREATE_QUALITY, &sfpData, status);
            if(*status != SAI__OK) {
                *status = SAI__ERROR;
                errRep(FUNC_NAME, "Unable to open the SFP calibration file!", status);
                goto CLEANUP;
            }

            /* Read in the number of data elements */
            nSfp = sfpData->dims[1] / nPixels;
            /* Allocate memory for arrays */
            SFP = astCalloc(nSfp*nPixels, sizeof(*SFP));
            SFPij = astCalloc(nSfp, sizeof(*SFP));
            WN  = astCalloc(nSfp, sizeof(*WN));

            /* DEBUG: Dispay SFP data */
          /*printf("smurf_fts2_spectrum ([%d,%d,%d] elements): WN, SFP\n", (int)sfpData->dims[0],(int)sfpData->dims[1],(int)sfpData->dims[2]);*/
            for(k=0;k<nSfp;k++){
                /* printf("WN:%.3f,SFP:%.10f\n", *((double*) (sfpData->pntr[0]) + i), *((double*) (sfpData->pntr[0]) + i+1)); */
                /* Adjust starting and ending wave number ranges for 450 or 850 bands */
                if(wavelen == 0.00085 || wavelen == 0.00045) {
                    WN[k] = wnSfpFirst + k * wnSfpResolution;
                } else {
                    *status = SAI__ERROR;
                    errRep(FUNC_NAME, "Unexpected WAVELEN value found in the FITS header!", status);
                    goto CLEANUP;
                }
              /*printf("SFP WN[%d]=%f\n",k,WN[k]);*/
                for(j=0;j<nHeight;j++) {
                    for(i=0;i<nWidth;i++) {
                        bolIndex = i + j * nWidth;
                        cubeIndex = bolIndex + k * nPixels;
                        SFP[cubeIndex] = *((double*) (sfpData->pntr[0]) + cubeIndex);
                      /*if(i==10 && j==20) printf("SFP i:%d,j:%d,k:%d,bolIndex:%d,cubeIndex:%d=%f\n",i,j,k,bolIndex,cubeIndex,SFP[cubeIndex]);*/
                    }
                }
            }

            /*printf("smurf_fts2_spectrum DEBUG: early exiting!\n");
              exit(0); */

            /* Create a 2D SFP index array and store it in the file, if given
            sfp = smf_create_smfData(SMF__NOCREATE_DA | SMF__NOCREATE_FTS, status);
            sfp->dtype   = SMF__INTEGER;
            sfp->ndims   = 2;
            sfp->dims[0] = nSfp;
            sfp->dims[1] = 2;
            sfp->pntr[0] = (int*) astCalloc(nSfp*2,  sizeof(double));
            // By default set ZPD indices to a bad value
            for(i = 0; i < nSfp; i++) {
                for(j = 0; j < 2; j++) {
                    bolIndex = i + j * 2;
                    *((int*) (sfp->pntr[0]) + bolIndex) = VAL__BADI;
                }
            } */

            /* Prepare GSL interpolator to convert SFP data to this spectrum's resolution */
            ACC    = gsl_interp_accel_alloc();
            SPLINE = gsl_spline_alloc(gsl_interp_cspline, nSfp);
        }

        for(i = 0; i < nWidth; i++) {
            for(j = 0; j < nHeight; j++) {
                bolIndex = i + j * nWidth;

                badPixel = 0;
                for(k = 0; k < Nin; k++) {
                    dIntensity = *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                    if(dIntensity == VAL__BADD) {
                        badPixel = 1;
                        break;
                    }
                }
                /* If this is a bad pixel, go to next */
                if(badPixel) {
                    for(k = 0; k <= N2in; k++) {
                        *((double*)(outData->pntr[0]) + (bolIndex + k * nPixels)) = VAL__BADD;
                    }
                    continue;
                }

                /* Double-Sided interferogram */
                if(zeropad) {
                    pad = Nzp - Nin;
                    pad2 = pad / 2;
                    /* Copy the right half of the input into the left half of this IFG, zero padded in the middle */
                    for(k=indexZPDin; k<Nin; k++) {
                        /*printf("%s: IFG: indexZPDin=%d, indexZPDzp=%d, Nin=%d, Nzp=%d, k=%d, l=%d\n", TASK_NAME, indexZPDin, indexZPDzp, Nin, Nzp, k, l);*/
                        IFG[k - indexZPDin] = *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                            printf("%s: Pixel[%d,%d]: (L<-R) IFG[k(%d)-indexZPDin(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %g\n",
                                   TASK_NAME, i, j, k, indexZPDin, (k - indexZPDin), bolIndex, k, nPixels, (bolIndex + k * nPixels), IFG[k - indexZPDin]);
                        }*/
                    }
                    /* Copy the left half of the input into the right half of this IFG, zero padded in the middle */
                    for(k=0,l=0; k<indexZPDin; k++) {
                        IFG[Nzp - indexZPDin + k] =  *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                            printf("%s: Pixel[%d,%d]: (L->R) IFG[Nzp(%d)-indexZPDin(%d)+k(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %g\n",
                                   TASK_NAME, i, j, Nzp, indexZPDin, k, (Nzp-indexZPDin+k), bolIndex, k, nPixels, (bolIndex+k*nPixels), IFG[Nzp-indexZPDin+k]);
                        }*/
                    }
                } else {
                    /* Copy the right half of the input into the left half of this IFG */
                    for(k=indexZPD; k<N; k++) {
                        IFG[k - indexZPD] = *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                            printf("%s: Pixel[%d,%d]: (L<-R) IFG[k(%d)-indexZPD(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %f\n",
                                     TASK_NAME, i, j, k, indexZPD, (k - indexZPD), bolIndex, k, nPixels, (bolIndex + k * nPixels), IFG[k - indexZPD]);
                        }*/
                    }
                    /* Copy the left half of the input into the right half of this IFG */
                    for(k=0; k<indexZPD; k++) {
                        IFG[N - indexZPD + k] =  *((double*)(inData->pntr[0]) + (bolIndex + k * nPixels));
                      /*if(i==16 && j==25) {
                              printf("%s: Pixel[%d,%d]: (L->R) IFG[N(%d)-indexZPD(%d)+k(%d)=%d] = inData->pntr[bolIndex(%d)+k(%d)*nPixels(%d)=%d] = %f\n",
                                     TASK_NAME, i, j, N, indexZPD, k, (N - indexZPD + k), bolIndex, k, nPixels, (bolIndex + k * nPixels), IFG[N - indexZPD + k]);
                        }*/
                    }
                }

                /* DEBUG: Write out input data
                for(k = 0; k < Nin; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + nPixels * k)) =
                    *((double*)( inData->pntr[0]) + (bolIndex + nPixels * k));
                    if(i==16 && j==25) {
                        printf("%s: inData[%d,%d,%d]=%g\n",TASK_NAME, i, j, k, *((double*)( inData->pntr[0]) + (bolIndex + nPixels * k)));
                    }
                } */

                /* DEBUG: Write out the shifted IFG
                for(k = 0; k < N; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + k* nPixels)) = IFG[k];
                    if(i==16 && j==25) {
                        printf("%s: IFG[%d,%d,%d]=%g\n",TASK_NAME, i, j, k, IFG[k]);
                    }
                } */

                /* Convert real-valued interferogram to complex-valued interferogram */
                for(k = 0; k < N; k++) { DSIN[k][0] = IFG[k]; DSIN[k][1] = 0.0; }

                /* DEBUG: Write out DSIN
                for(k = 0; k < N; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + k * nPixels)) = DSIN[k][0];
                    if(i==16 && j==25) {
                        printf("%s: DSIN[%d,%d,%d]=%g\n",TASK_NAME, i, j, k, DSIN[k][0]);
                    }
                } */

                /* FFT Double-sided complex-valued interferogram */
                plan = fftw_plan_dft_1d(N, DSIN, SPEC, FFTW_FORWARD, FFTW_ESTIMATE);
                fftw_execute(plan);

                /* Normalize spectrum */
                for(k=0;k<N;k++) { SPEC[k][0] = SPEC[k][0] / (double)(N * resolution); }

                /* Apply SFP calibration, if given */
                if(doSFP){
                    /* Get the SFP for this pixel */
                    for(k=0;k<nSfp;k++) { SFPij[k] = SFP[i + j*nWidth + k*nPixels]; }
                    /* Interpolate the SFP values from its original WN scale to the current spectrum scale */
                    gsl_spline_init(SPLINE, WN, SFPij, nSfp);

                    /* Divide the spectrum in the band pass region by the interpolated SFP value at each position */
                    for(k = 0; k < N; k++) {
                      /*if(k*dSigma >= WN[0] && k*dSigma <= WN[nSfp-1]) {*/
                        if(k*dSigma >= wnSfpF && k*dSigma <= wnSfpL) {
                            f = gsl_spline_eval(SPLINE, k*dSigma, ACC);
                            /*index = bolIndex + nPixels * k;*/
                            s = SPEC[k][0];
                            SPEC[k][0] = s / f;
                          /*if(i==10 && j==20) { printf("SFP i=%d, j=%d, k=%d, dSigma=%f, k*dSigma=%f, s=%f, f=%f, s/f=%f, \n", i, j, k, dSigma, k*dSigma, s, f, s/f); }*/
                        }
                    }
                }

                /* Write out the positive real component of the spectrum */
                for(k = 0; k <= N2; k++) {
                    *((double*)(outData->pntr[0]) + (bolIndex + k * nPixels)) = SPEC[k][0];
                  /*if(i==16 && j==25) {
                        printf("%s: SPEC[%d,%d,%d]=%E\n",TASK_NAME, i, j, k, SPEC[k][0] / (double)(N * resolution));
                    }*/
                }

                /* Destroy each allocated plan */
                if(plan) { fftw_destroy_plan(plan); }
            }
        }

        /* Deallocate memory used by arrays */
        if(IFG)  { IFG = astFree(IFG); }
        if(DS)   { DS = astFree(DS); }
        if(SFP)  { SFP = astFree(SFP); }
        if(SFPij)  { SFPij = astFree(SFPij); }
        if(WN)   { WN = astFree(WN); }
        if(DSIN) { fftw_free(DSIN); DSIN = NULL; }
        if(SPEC) { fftw_free(SPEC); SPEC = NULL; }
        if(ACC)     { gsl_interp_accel_free(ACC);   ACC     = NULL; }
        if(SPLINE)  { gsl_spline_free(SPLINE);      SPLINE  = NULL; }

        /* Close the file */
        if(inData) {
            smf_close_file( NULL,&inData, status);
            if(*status != SAI__OK) {
                *status = SAI__ERROR;
                errRep(FUNC_NAME, "Unable to close the input file!", status);
                goto CLEANUP;
            }
        }

        /* Write output */
        /* outData->fts = smf_construct_smfFts(NULL, sfp, fpm, sigma, status);   // TODO: Add interpolated SFP to FITS header */
        smf_write_smfData(NULL, outData, NULL, NULL, gOut, fIndex, 0,
                          MSG__VERB, 0, NULL, NULL, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to write the output file!", status);
            goto CLEANUP;
        }
        smf_close_file( NULL,&outData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "Unable to close the output file!", status);
            goto CLEANUP;
        }
    }

CLEANUP:
    if(IFG)  { IFG = astFree(IFG); }
    if(DS)   { DS = astFree(DS); }
    if(SFP)  { SFP = astFree(SFP); }
    if(SFPij)  { SFPij = astFree(SFPij); }
    if(WN)   { WN = astFree(WN); }
    if(DSIN) { fftw_free(DSIN); DSIN = NULL; }
    if(SPEC) { fftw_free(SPEC); SPEC = NULL; }
    if(ACC)     { gsl_interp_accel_free(ACC);   ACC     = NULL; }
    if(SPLINE)  { gsl_spline_free(SPLINE);      SPLINE  = NULL; }

    /* Close files if still open */
    if(inData) {
        smf_close_file( NULL,&inData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "CLEANUP: Unable to close the input file!", status);
        }
    }
    if(outData) {
        smf_close_file( NULL,&outData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "CLEANUP: Unable to close the output file!", status);
        }
    }
    if(sfpData) {
        smf_close_file( NULL,&sfpData, status);
        if(*status != SAI__OK) {
            *status = SAI__ERROR;
            errRep(FUNC_NAME, "CLEANUP: Unable to close the SFP file!", status);
        }
    }

    /* END NDF */
    ndfEnd(status);

    /* Delete Groups */
    if(gIn) grpDelet(&gIn, status);
    if(gOut) grpDelet(&gOut, status);
    if(gSfp) grpDelet(&gSfp, status);
}
コード例 #16
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();
}
コード例 #17
0
ファイル: smurf_jsadicer.c プロジェクト: dt888/starlink
/* Main entry */
void smurf_jsadicer( int *status ) {

/* Local Variables */
   AstFitsChan *fc;
   Grp *igrp = NULL;
   Grp *ogrp = NULL;
   char *pname;
   char basename[ 255 ];
   int indf;
   int trim;
   size_t ntile;
   size_t size;
   smfJSATiling tiling;

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

/* Begin AST and NDF contexts. */
   astBegin;
   ndfBegin();

/* Get the name of the input NDF. */
   kpg1Rgndf( "IN", 1, 1, "", &igrp, &size, status );
   ndgNdfas( igrp, 1, "READ", &indf, status );

/* Get the base name for the output NDFs. */
   if( *status == SAI__OK ) {
      parGet0c( "OUT", basename, sizeof(basename), status );
      if( *status == PAR__NULL ) {
         errAnnul( status );
         pname = basename;
         grpGet( igrp, 1, 1, &pname, sizeof(basename), status );
      }
   }

/* See how the output NDFs are to be trimmed. */
   parGet0i( "TRIM", &trim, status );

/* Get a FitsChan holding the contents of the FITS extension from the
   input NDF. Annul the error if the NDF has no FITS extension. */
   if( *status == SAI__OK ) {
      kpgGtfts( indf, &fc, status );
      if( *status == KPG__NOFTS ) {
         errAnnul( status );
         fc = NULL;
      }
   }

/* 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 );

/* Create a new group to hold the names of the output NDFs that have been
   created. This group does not include any NDFs that correspond to tiles
   that contain no input data. */
   ogrp = grpNew( "", status );

/* Dice the map into output NDFs. */
   smf_jsadicer( indf, basename, trim, tiling.instrument, &ntile,
                 ogrp, status );

/* Write out the list of output NDF names, annulling the error if a null
   parameter value is supplied. */
   if( *status == SAI__OK && ogrp ) {
      grpList( "OUTFILES", 0, 0, NULL, ogrp, status );
      if( *status == PAR__NULL ) errAnnul( status );
   }

/* Write the number of tiles being created to an output parameter. */
   parPut0i( "NTILE", ntile, status );

/* Free resources. */
   grpDelet( &igrp, status );
   grpDelet( &ogrp, status );

/* End the NDF and AST context. */
   ndfEnd( status );
   astEnd;

/* If anything went wrong issue a context message. */
   if( *status != SAI__OK ) msgOutif( MSG__VERB, " ", "JSADICER failed.",
                                      status );
}
コード例 #18
0
ファイル: smurf_extinction.c プロジェクト: bbrond/starlink
void smurf_extinction( int * status ) {

  /* Local Variables */
  smfArray *bbms = NULL;     /* Bad bolometer masks */
  smfArray *darks = NULL;    /* Dark data */
  AstKeyMap *extpars = NULL; /* Tau relation keymap */
  Grp *fgrp = NULL;          /* Filtered group, no darks */
  smfArray *flatramps = NULL;/* Flatfield ramps */
  int has_been_sky_removed = 0;/* Data are sky-removed */
  AstKeyMap *heateffmap = NULL;    /* Heater efficiency data */
  size_t i;                  /* Loop counter */
  Grp *igrp = NULL;          /* Input group */
  AstKeyMap *keymap=NULL;    /* Keymap for storing parameters */
  smf_tausrc tausrc;         /* enum value of optical depth source */
  smf_extmeth extmeth;       /* Extinction correction method */
  char tausource[LEN__METHOD];  /* String for optical depth source */
  char method[LEN__METHOD];  /* String for extinction airmass method */
  smfData *odata = NULL;     /* Output data struct */
  Grp *ogrp = NULL;          /* Output group */
  size_t outsize;            /* Total number of NDF names in the output group */
  size_t size;               /* Number of files in input group */
  double tau = 0.0;          /* Zenith tau at this wavelength */
  ThrWorkForce *wf = NULL;   /* Pointer to a pool of worker threads */

  if (*status != SAI__OK) return;

  /* 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 );

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

  /* Filter out darks */
  smf_find_science( igrp, &fgrp, 0, 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;

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

  /* Get group of pixel masks and read them into a smfArray */
  smf_request_mask( "BBM", &bbms, status );

  /* Read the tau relations from config file or group. We do not
     allow sub instrument overloading because these are all values
     based on filter name. */
  keymap = kpg1Config( "TAUREL", "$SMURF_DIR/smurf_extinction.def", NULL,
                       1, status );

  /* and we need to use the EXT entry */
  astMapGet0A( keymap, "EXT", &extpars );
  keymap = astAnnul( keymap );

  /* Get tau source */
  parChoic( "TAUSRC", "Auto",
            "Auto,CSOtau,CSOFit, Filtertau, WVMraw", 1,
            tausource, sizeof(tausource), status);

  /* Decide how the correction is to be applied - convert to flag */
  parChoic( "METHOD", "ADAPTIVE",
            "Adaptive,Quick,Full,", 1, method, sizeof(method), status);

  /* Place parameters into a keymap and extract values */
  if( *status == SAI__OK ) {
    keymap = astKeyMap( " " );
    if( astOK ) {
      astMapPut0C( keymap, "TAUSRC", tausource, NULL );
      astMapPut0C( keymap, "TAUMETHOD", method, NULL );
      smf_get_extpar( keymap, &tausrc, &extmeth, NULL, status );
    }
  }

  for (i=1; i<=size && ( *status == SAI__OK ); i++) {

    /* Flatfield - if necessary */
    smf_open_and_flatfield( igrp, ogrp, i, darks, flatramps, heateffmap,
                            &odata, status );

    if (*status != SAI__OK) {
      /* Error flatfielding: tell the user which file it was */
      msgSeti("I",i);
      errRep(TASK_NAME, "Unable to open the ^I th file", status);
    }

    /* Mask out bad pixels - mask data array not quality array */
    smf_apply_mask( odata, bbms, SMF__BBM_DATA, 0, status );

    /* Now check that the data are sky-subtracted */
    if ( !smf_history_check( odata, "smf_subtract_plane", status ) ) {

      /* Should we override remsky check? */
      parGet0l("HASSKYREM", &has_been_sky_removed, status);

      if ( !has_been_sky_removed && *status == SAI__OK ) {
        *status = SAI__ERROR;
        msgSeti("I",i);
        errRep("", "Input data from file ^I are not sky-subtracted", status);
      }
    }

    /* If status is OK, make decisions on source keywords the first
       time through. */
    if ( *status == SAI__OK && i == 1 ) {
      if (tausrc == SMF__TAUSRC_CSOTAU ||
          tausrc == SMF__TAUSRC_AUTO ||
          tausrc == SMF__TAUSRC_TAU) {
        double deftau;
        const char * param = NULL;
        smfHead *ohdr = odata->hdr;

        /* get default CSO tau -- this could be calculated from CSO fits */
        deftau = smf_calc_meantau( ohdr, status );

        /* Now ask for desired CSO tau */
        if ( tausrc == SMF__TAUSRC_CSOTAU || tausrc == SMF__TAUSRC_AUTO) {
          param = "CSOTAU";
        } else if (tausrc == SMF__TAUSRC_TAU) {
          param = "FILTERTAU";
          deftau = smf_cso2filt_tau( ohdr, deftau, extpars, status );
        }
        parGdr0d( param, deftau, 0.0,1.0, 1, &tau, status );
      } else if ( tausrc == SMF__TAUSRC_CSOFIT || tausrc == SMF__TAUSRC_WVMRAW ) {
        /* Defer a message until after extinction correction */
      } else {
        *status = SAI__ERROR;
        errRep("", "Unsupported opacity source. Possible programming error.",
               status);
      }
    }

    /* Apply extinction correction - note that a check is made to
       determine whether the data have already been extinction
       corrected */
    smf_correct_extinction( wf, odata, &tausrc, extmeth, extpars, tau, NULL, NULL, status );

    if ( tausrc == SMF__TAUSRC_WVMRAW ) {
      msgOutif(MSG__VERB," ", "Used Raw WVM data for extinction correction", status);
    } else if ( tausrc == SMF__TAUSRC_CSOFIT ) {
      msgOutif(MSG__VERB," ", "Used fit to CSO data for extinction correction", status);
    } else if ( tausrc == SMF__TAUSRC_CSOTAU ) {
      msgOutif(MSG__VERB," ", "Used an explicit CSO tau value for extinction correction", status);
    } else if ( tausrc == SMF__TAUSRC_TAU ) {
      msgOutif(MSG__VERB," ", "Used an explicit filter tau value for extinction correction", status);
    } else {
      if (*status == SAI__OK) {
        const char * taustr = smf_tausrc_str( tausrc, status );
        *status = SAI__ERROR;
        errRepf( "", "Unexpected opacity source used for extinction correction of %s."
                 " Possible programming error.", status, taustr );
      }
    }

    /* Set character labels */
    smf_set_clabels( "Extinction corrected",NULL, NULL, odata->hdr, status);
    smf_write_clabels( odata, status );

    /* Free resources for output data */
    smf_close_file( &odata, status );
  }

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK && ogrp ) {
    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  */
  if (darks) smf_close_related( &darks, status );
  if (bbms) smf_close_related( &bbms, status );
  if( flatramps ) smf_close_related( &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  grpDelet( &igrp, status);
  grpDelet( &ogrp, status);
  if( keymap ) keymap = astAnnul( keymap );
  if (extpars) extpars = astAnnul( extpars );
  ndfEnd( status );
}
コード例 #19
0
ファイル: smurf_fts2_split.c プロジェクト: bbrond/starlink
void smurf_fts2_split(int* status)
{
  if( *status != SAI__OK ) { return; }

  const double STAGE_LENGTH = 450.0;    /* mm */
  int LR                    = 0;        /* Treat as Low Resolution scan */
  Grp* gIn                  = NULL;     /* Input group */
  Grp* gOut                 = NULL;     /* Output group */
  Grp* gTmp                 = NULL;     /* Temporary group */
  smfData* inData           = NULL;     /* Pointer to input data */
  smfData* outData          = NULL;     /* Pointer to output data */
  double* outData_pntr      = NULL;     /* Pointer to output data values array */
  int nMirPos               = 0;        /* Number of frames where the mirror actually moves */
  int nStart                = 0;        /* Frame index where the mirror starts moving */
  int nStartNext            = 0;        /* Frame index where the mirror starts moving in the next scan */
  int nStop                 = 0;        /* Frame index where the mirror stops */
  int lrStart               = 0;        /* Frame index where low resolution mirror limit starts */
  int hrStop                = 0;        /* Frame index where high resolution mirror limit stops */
  int hrStart               = 0;        /* Frame index where high resolution mirror limit starts */
  int lrStop                = 0;        /* Frame index where low resolution mirror limit stops */
  int lrCentre              = 0;        /* Frame index at centre of low resolution mirror positions */
  int i                     = 0;        /* Counter */
  int j                     = 0;        /* Counter */
  int k                     = 0;        /* Counter */
  int n                     = 0;        /* Counter */
  double fNyquist           = 0.0;      /* Nyquist frequency */
  double dz                 = 0.0;      /* Step size in evenly spaced OPD grid */
  double* MIRPOS            = NULL;     /* Mirror positions */

  size_t nFiles             = 0;        /* Size of the input group */
  size_t nOutFiles          = 0;        /* Size of the output group */
  size_t fIndex             = 0;        /* File index */
  size_t nWidth             = 0;        /* Data cube width */
  size_t nHeight            = 0;        /* Data cube height */
  size_t nFrames            = 0;        /* Data cube depth in input file */
  size_t nFramesOut         = 0;        /* Data cube depth in output file */
  size_t nFramesOutPrev     = 0;        /* Data cube depth in previous output file */
  size_t hrFramesOut        = 0;        /* Data cube depth in high res output file */
  size_t hrFramesOutPrev    = 0;        /* Data cube depth in previous high res output file */
  size_t lrFramesOut        = 0;        /* Data cube depth in low res output file */
  size_t lrFramesOutPrev    = 0;        /* Data cube depth in previous low res output file */
  size_t nPixels            = 0;        /* Number of bolometers in the subarray */

  char object[SZFITSTR];
  char subarray[SZFITSTR];
  char obsID[SZFITSTR];
  char scanMode[SZFITSTR];

  double scanVel            = 0.0;      /* Mirror speed in mm/sec */
  double stepTime           = 0.0;      /* RTS step time, average sample rate */
  double minOPD             = 0;        /* OPD minimum */
  double maxOPD             = 0;        /* OPD maximum */
  double ZPD                = 0;
  double lrmmBandPass       = 0.0;      /* low res mm +/- offset from centre */
  int lrBandPassFrames      = 0;        /* Number of low res band pass frames from centre +/- length of lrmmBandPass */
  int nTmp                  = 0;
  int nMax                  = 0;
  int nOPD                  = 0;
  int bolIndex              = 0;
  int index                 = 0;
  int indexIn               = 0;
  int indexOut              = 0;
  int badPixel              = 0;
  int k0                    = 0;
  int indexZPD              = 0;
  int done                  = 0;        /* Track completion of extracting multiple scans */
  int outDataCount          = 0;        /* The number of output data files being written */

  double lenLeft,
         lenRight,
         minLenLeft,
         minLenRight,
         minLen,
         minZPD,
         maxZPD,
         midZPD             = 0.0;      /* Mirror position half side measures */
  int midZPDPos             = 0;        /* Middle ZPD position in mirror position array */

  double EPSILON            = 0.0;
  char fileName[SMF_PATH_MAX+1];
  char scanNumStr[5+1];                 /* String form of scan number of the input file */
  int scanNum               = 0;        /* Scan number of the input file */
  int conNum                = 0;        /* Concatenation number of the input file (left shifted scanNum) */
  int scanDir               = 0;        /* Scan direction: 1 -> back to front (positive), -1 -> front to back (negative) */
  JCMTState *allState       = NULL;     /* Temporary buffer for reduced header allState array data */


  /* Get Input, Output groups */
  kpg1Rgndf("IN", 0, 1, "", &gIn, &nFiles, status);
  kpg1Wgndf("OUT", gOut, nFiles, nFiles, "More output files expected!", &gOut, &nOutFiles, status);

  /* Read in ADAM parameters */
  parGet0d("BANDPASS", &lrmmBandPass, status);          /* Low res mm band +/- offset from centre */

  /* Treat as Low Resolution scan? */
  if(lrmmBandPass > 0) {
      LR = 1;
  }

  /* Eliminate the first record in the output group, since it will be replaced later */
  gTmp = grpCopy(gOut, 1, 1, 1, status);
  grpDelet(&gOut, status);
  gOut = gTmp;

  /* BEGIN NDF */
  ndfBegin();

  /* Loop through each input file */
  for(fIndex = 1; fIndex <= nFiles; fIndex++) {
    /* Open Observation file */
    smf_open_file(gIn, fIndex, "READ", 0, &inData, status);
    if(*status != SAI__OK) {
      *status = SAI__ERROR;
      errRep(FUNC_NAME, "Unable to open the source file!", status);
      goto CLEANUP;
    }

    smf_fits_getS(inData->hdr, "OBJECT", object, sizeof(object), status);
    smf_fits_getS(inData->hdr, "SUBARRAY", subarray, sizeof(subarray), status);
    smf_fits_getS(inData->hdr, "OBSID", obsID, sizeof(obsID), status);
    smf_fits_getS(inData->hdr, "FTS_MODE", scanMode, sizeof(scanMode), status);
    smf_fits_getD(inData->hdr, "SCANVEL", &scanVel, status);
    smf_fits_getD(inData->hdr, "STEPTIME", &stepTime, status);

    /* Nyquist frequency */
    fNyquist = 10.0 / (8.0 * scanVel * stepTime);
    dz = 1.0 / (2.0 * fNyquist);
    EPSILON = scanVel * stepTime / 2;

    /* Extract the scan number from the input file to be incremented in the output files */
    one_strlcpy(scanNumStr, &(inData->file->name[strlen(inData->file->name) - 8]),
               astMIN(SMF_PATH_MAX + 1, 5), status);
    if (*status == ONE__TRUNC) {
        errRep(FUNC_NAME, "Error extracting scanNumStr!", status);
        errAnnul(status);
    }

    /* Create a temporary base file name from input file name */
    one_strlcpy(fileName, inData->file->name,
                astMIN(SMF_PATH_MAX + 1, strlen(inData->file->name) - 7), status);
    if (*status == ONE__TRUNC) {
        errRep(FUNC_NAME, "Error extracting base fileName!", status);
        errAnnul(status);
    }
    scanNum = (int) one_strtod(scanNumStr, status);
    if (*status != SAI__OK) {
        errRep(FUNC_NAME, "Error extracting scanNum!", status);
        errAnnul(status);
    }

    /* Left shift scanNum to conNum as a prefix to make output scan number unique */
    if(scanNum < 100) {
      conNum = scanNum * 100;
    } else if(scanNum < 1000) {
      conNum = scanNum * 10;
    }

    /*printf("%s: Processing file: %s, having basename: %s and scanNumStr: %s, scanNum: %04d\n",
           TASK_NAME, inData->file->name, fileName, scanNumStr, scanNum);*/

    /* Data cube dimensions */
    nWidth  = inData->dims[0];
    nHeight = inData->dims[1];
    nFrames = inData->dims[2];
    nPixels = nWidth * nHeight;

    /* Mirror positions in mm */
    nTmp = nFrames;
    MIRPOS = astCalloc(nFrames, sizeof(*MIRPOS));
    fts2_getmirrorpositions(inData, MIRPOS, &nTmp, status); // (mm)
    if(*status != SAI__OK) {
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "Unable to get the mirror positions!", status);
      goto CLEANUP;
    }

    nStart = -1;
    nStop = -1;
    nStartNext = 0;
    hrStart = -1;
    hrStop = -1;
    lrStart = -1;
    lrStop = -1;
    outDataCount = 0;
    done = 0;
    do {
        /* Find the next range of single scan mirror positions for which to extract corresponding NDF data */
        for(n=nStartNext; n<nFrames-1; n++){
            if(hrStart < 0 && fabs(MIRPOS[n+1] - MIRPOS[n]) >= EPSILON) {
                nStart = n;
                hrStart = n;
                /*printf("%s: Split nStart=%d\n", TASK_NAME, nStart);*/
            }
            if(hrStart >= 0 && hrStop < 0 && (fabs(MIRPOS[n+1] - MIRPOS[n]) < EPSILON || n+1 == nFrames-1)) {
                hrStop = n+1;
                hrFramesOutPrev = hrFramesOut;
                hrFramesOut = abs(hrStop - hrStart) + 1;
                outDataCount++;

                nStop = hrStop;
                nFramesOutPrev = hrFramesOutPrev;
                nFramesOut = hrFramesOut;

                /*printf("%s: Split: %d of %d frames found at hrStart=%d, hrStop=%d\n",
                       TASK_NAME, outDataCount, hrFramesOut, hrStart, hrStop);*/
                break;
            }
        }

        /* Determine scan direction */
        if(MIRPOS[hrStart] < MIRPOS[hrStop]) {
            scanDir = 1;    /* Positive */
        } else {
            scanDir = -1;   /* Negative */
        }

        /* Limit to specified mirror position range */
        if(LR) {
            /* Calculate how many frames correspond to the given +/- mm of LR bandpass */
            lrBandPassFrames = lrmmBandPass / dz;

            /* Find the centre of the current scan */
            lrCentre = floor((abs(hrStop-hrStart)+1)/2);

            /* Set low res start and stop values at corresponding frame offsets from centre */
            lrStart = lrCentre - lrBandPassFrames;
            lrStop = lrCentre + lrBandPassFrames;
            lrFramesOutPrev = lrFramesOut;
            lrFramesOut = abs(lrStop - lrStart) + 1;

            nStart = lrStart;
            nStop = lrStop;
            nFramesOutPrev = lrFramesOutPrev;
            nFramesOut = lrFramesOut;

            /*printf("%s: LR Split: %d of %d frames found at lrStart=%d, lrStop=%d\n",
                   TASK_NAME, outDataCount, lrFramesOut, lrStart, lrStop);*/
        }

        /* Check for end of data condition */
        if(hrStop < hrStart  || hrStop >= nFrames-1) {
            hrStop = nFrames-1;
            done = 1;
        }

        /* Output scan if there is a start and stop position found,
           and for the last scan if it's the only one
           and if it's not too short (compared to the previous one) */
        /*printf("%s: nStart=%d, nStop=%d, nFramesOutPrev=%d, nFramesOut=%d\n", TASK_NAME, nStart, nStop, nFramesOutPrev, nFramesOut);*/
        if(nStart >=0 && nStop > 0 &&
            (nFramesOutPrev == 0 ||
              (nFramesOutPrev > 0 && nFramesOut > 0 && (double)hrFramesOut/(double)hrFramesOutPrev >= 0.5))) {
            /* Copy single scan NDF data from input to output */
            outData = smf_deepcopy_smfData(inData, 0, SMF__NOCREATE_DATA | SMF__NOCREATE_FTS, 0, 0, status);
            outData->dtype   = SMF__DOUBLE;
            outData->ndims   = 3;
            outData->dims[0] = nWidth;
            outData->dims[1] = nHeight;
            outData->dims[2] = nFramesOut;
            outData_pntr = (double*) astMalloc((nPixels * nFramesOut) * sizeof(*outData_pntr));
            outData->pntr[0] = outData_pntr;
            outData->hdr->nframes = nFramesOut;

            for(i=0; i<nWidth; i++) {
                for(j=0; j<nHeight; j++) {
                    bolIndex = i + j * nWidth;
                    for(k=nStart; k<=nStop; k++) {
                        indexIn = bolIndex + k * nPixels;
                        indexOut = bolIndex + (k-nStart) * nPixels;
                        *((double*)(outData->pntr[0]) + indexOut) = *((double*)(inData->pntr[0]) + indexIn);
                    }
                }
            }

            /* Update the FITS headers */
            outData->fts = smf_create_smfFts(status);
            /* Update FITS component */
            smf_fits_updateD(outData->hdr, "FNYQUIST", fNyquist, "Nyquist frequency (cm^-1)", status);
            smf_fits_updateI(outData->hdr, "MIRSTART", 1, "Frame index in which the mirror starts moving", status);
            smf_fits_updateI(outData->hdr, "MIRSTOP", nFramesOut, "Frame index in which the mirror stops moving", status);
            smf_fits_updateI(outData->hdr, "SCANDIR", scanDir, "Scan direction", status);
            smf_fits_updateD(outData->hdr, "OPDMIN", 0.0, "Minimum OPD", status);
            smf_fits_updateD(outData->hdr, "OPDSTEP", 0.0, "OPD step size", status);

            /* Update the JCMTSTATE header */
            /* Reallocate outData header array memory to reduced size */
            allState = (JCMTState*) astRealloc(outData->hdr->allState, nFramesOut * sizeof(*(outData->hdr->allState)));
            if(*status == SAI__OK && allState) {
                outData->hdr->allState = allState;
            } else {
                errRepf(TASK_NAME, "Error reallocating allState JCMTState header", status);
                goto CLEANUP;
            }
            for(k=nStart; k<=nStop; k++) {
                /* Copy over JCMTstate */
                /*printf("%s: memcpy allState: %d to: %p from: %p size: %d\n",TASK_NAME, k,
                       (void *) &(outData->hdr->allState[k-nStart]), (void *) &(inData->hdr->allState[k]), sizeof(*(outData->hdr->allState)) );*/
                memcpy( (void *) &(outData->hdr->allState[k-nStart]), (void *) &(inData->hdr->allState[k]), sizeof(*(outData->hdr->allState)) );

                /*printf("%s: Scan: %d index: %d rts_num: %d\n", TASK_NAME, outDataCount, k-nStart, outData->hdr->allState[k-nStart].rts_num);*/
                /*printf("%s: Scan: %d index: %d fts_pos: %f\n", TASK_NAME, outDataCount, k-nStart, outData->hdr->allState[k-nStart].fts_pos);*/
            }

            /* Write output */
            /* Append unique suffix to fileName */
            /* This must be modified by the concatenation file scan number to improve uniqueness */
            n = one_snprintf(outData->file->name, SMF_PATH_MAX, "%s%04d_scn.sdf", status, fileName, conNum+outDataCount);
            /*printf("%s: Writing outData->file->name: %s\n", TASK_NAME, outData->file->name);*/
            if(n < 0 || n >= SMF_PATH_MAX) {
                errRepf(TASK_NAME, "Error creating outData->file->name", status);
                goto CLEANUP;
            }
            /* Update the list of output _scn file names */
            grpPut1(gOut, outData->file->name, 0, status);
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error saving outData file name", status);
                goto CLEANUP;
            }
            smf_write_smfData(outData, NULL, outData->file->name, gOut, fIndex, 0, MSG__VERB, 0, status);
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error writing outData file", status);
                goto CLEANUP;
            }
            smf_close_file(&outData, status);
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error closing outData file", status);
                goto CLEANUP;
            }
            if(*status != SAI__OK) {
                errRepf(TASK_NAME, "Error closing outData file", status);
                goto CLEANUP;
            }
        }/* else {
            if(!(nStart >=0 && nStop)) printf("%s: Output scan condition failed: nStart(%d) >= nStop(%d) is FALSE\n",TASK_NAME, nStart, nStop);
            if(!(nFramesOutPrev == 0 ||
              (nFramesOutPrev > 0 && nFramesOut > 0 && (double)nFramesOut/(double)nFramesOutPrev >= 0.5))) printf("%s: Output scan condition failed: nFramesOutPrev(%d) == 0 || (nFramesOutPrev(%d) > 0 && nFramesOut(%d) > 0 && nFramesOut/nFramesOutPrev (%f) >= 0.5) is FALSE\n", TASK_NAME, nFramesOutPrev, nFramesOutPrev, nFramesOut, (double)nFramesOut/(double)nFramesOutPrev);
        }*/

        /* Prepare for next iteration */
        nStartNext = hrStop + 1;
        hrStart = -1;
        hrStop = -1;

    } while (!done);


    /* Deallocate memory used by arrays */
    if(MIRPOS)  { MIRPOS    = astFree(MIRPOS); }

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

  }
  CLEANUP:
  /* Deallocate memory used by arrays */
  if(inData)  { smf_close_file(&inData, status); }
  if(outData) { smf_close_file(&outData, status); }

  /* END NDF */
  ndfEnd(status);

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK && gOut ) {
      grpList( "OUTFILES", 0, 0, NULL, gOut, status );
          if( *status == PAR__NULL ) {
              errRep(FUNC_NAME, "Error writing OUTFILES!", status);
              errAnnul( status );
          }
  }

  /* Delete groups */
  if(gIn)     { grpDelet(&gIn, status);  }
  if(gOut)    { grpDelet(&gOut, status); }
}
コード例 #20
0
ファイル: smurf_sc2concat.c プロジェクト: bbrond/starlink
void smurf_sc2concat( int *status ) {

  /* Local Variables */
  Grp *basegrp=NULL;         /* Grp containing first file each chunk */
  size_t basesize;           /* Number of files in base group */
  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 idx;                /* Subarray counter */
  int usedarks;              /* flag for using darks */
  Grp *igrp = NULL;          /* Group of input files */
  smfGroup *igroup=NULL;     /* smfGroup corresponding to igrp */
  size_t isize;              /* Number of files in input group */
  dim_t maxconcat=0;         /* Longest continuous chunk length in samples */
  double maxlen;             /* Constrain maxconcat to this many seconds */
  size_t ncontchunks=0;      /* Number continuous chunks outside iter loop */
  Grp *ogrp = NULL;          /* Output files  */
  size_t osize;              /* Number of files in input group */
  dim_t padStart=0;          /* How many samples padding at start */
  dim_t padEnd=0;            /* How many samples padding at end */
  int temp;                  /* Temporary signed integer */
  ThrWorkForce *wf = NULL;   /* Pointer to a pool of worker threads */

  if (*status != SAI__OK) return;

  /* 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 );

  /* Read the input file */
  kpg1Rgndf( "IN", 0, 1, "", &igrp, &isize, 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 */
  isize = grpGrpsz( fgrp, status );
  grpDelet( &igrp, status);
  igrp = fgrp;
  fgrp = NULL;

  if (isize == 0) {
    msgOutif(MSG__NORM, " ","All supplied input frames were filtered,"
       " nothing to do", status );
    goto CLEANUP;
  }

  /* --- Parse ADAM parameters ------------------------ */

  /* Maximum length of a continuous chunk */
  parGdr0d( "MAXLEN", 0, 0, VAL__MAXD, 1, &maxlen, status );

  /* Padding */
  parGdr0i( "PADSTART", 0, 0, VAL__MAXI, 1, &temp, status );
  padStart = (dim_t) temp;

  parGdr0i( "PADEND", 0, 0, VAL__MAXI, 1, &temp, status );
  padEnd = (dim_t) temp;

  /* Are we using darks? */
  parGet0l( "USEDARKS", &usedarks, status );

  /* Are we flatfielding? */
  parGet0l( "FLAT", &ensureflat, status );

  /* Group the input files by subarray and continuity */
  smf_grp_related( igrp, isize, 1, 0, maxlen-padStart-padEnd, NULL, NULL,
                   &maxconcat, NULL, &igroup, &basegrp, NULL, status );

  /* Obtain the number of continuous chunks and subarrays */
  if( *status == SAI__OK ) {
    ncontchunks = igroup->chunk[igroup->ngroups-1]+1;
  }

  basesize = grpGrpsz( basegrp, status );

  /* Get output file(s) */
  kpg1Wgndf( "OUT", basegrp, basesize, basesize,
             "More output files required...",
             &ogrp, &osize, status );

  /* Loop over continuous chunks */
  gcount = 1;
  for( contchunk=0;(*status==SAI__OK)&&contchunk<ncontchunks; contchunk++ ) {

    /* Concatenate this continuous chunk */
    smf_concat_smfGroup( wf, NULL, igroup, usedarks ? darks:NULL, NULL, flatramps,
                         heateffmap, contchunk, ensureflat, 1, NULL, 0, NULL, NULL,
                         NO_FTS, padStart, padEnd, 0, &concat, NULL, status );

    /* Export concatenated data for each subarray to NDF file */
    for( idx=0; (*status==SAI__OK)&&idx<concat->ndat; idx++ ) {
      if( concat->sdata[idx]->file && concat->sdata[idx]->file->name ) {
        smf_write_smfData( concat->sdata[idx], NULL, NULL, ogrp, gcount,
                           NDF__NOID, MSG__VERB, 0, status );
      } else {
        *status = SAI__ERROR;
        errRep( FUNC_NAME,
                "Unable to determine file name for concatenated data.",
                status );
      }

      /* Increment the group index counter */
      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 && ogrp ) {
    grpList( "OUTFILES", 0, 0, NULL, ogrp, status );
    if( *status == PAR__NULL ) errAnnul( status );
  }

 CLEANUP:
  if( darks ) smf_close_related( &darks, status );
  if( flatramps ) smf_close_related( &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  if( igrp ) grpDelet( &igrp, status);
  if( basegrp ) grpDelet( &basegrp, status );
  if( ogrp ) grpDelet( &ogrp, status );
  if( igroup ) smf_close_smfGroup( &igroup, status );

  ndfEnd( status );

  if( *status == SAI__OK ) {
    msgOutif(MSG__VERB," ","SC2CONCAT succeeded.", status);
  } else {
    msgOutif(MSG__VERB," ","SC2CONCAT failed.", status);
  }

}
コード例 #21
0
ファイル: smurf_unmakemap.c プロジェクト: wadawson/starlink
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);
   }
}
コード例 #22
0
ファイル: clumpinfo.c プロジェクト: joaogerd/starlink
void clumpinfo( int *status ) {
    /*
    *+
    *  Name:
    *     CLUMPINFO

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

    *  Language:
    *     C

    *  Type of Module:
    *     ADAM A-task

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

    *  Usage:
    *     clumpinfo ndf clumps quiet

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

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

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

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

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

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

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

    *  Bugs:
    *     {note_any_bugs_here}

    *-
    */

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

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

    /* Begin an AST context */
    astBegin;

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



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

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

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

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

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

        }
        datAnnul( &xloc, status );
    }

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



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

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

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

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

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

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

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

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

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

    }



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if( !quiet ) msgBlank( status );



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

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

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

    /* End the AST context */
    astEnd;

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

}
コード例 #23
0
ファイル: smf_jsadicer.c プロジェクト: gmarsden/starlink
/* 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;

}
コード例 #24
0
ファイル: findback.c プロジェクト: andrecut/starlink
void findback( int *status ){
/*
*+
*  Name:
*     FINDBACK

*  Purpose:
*     Estimate the background in an NDF by removing small scale structure.

*  Language:
*     C

*  Type of Module:
*     ADAM A-task

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

*  Description:
*     This application uses spatial filtering to remove structure with a
*     scale size less than a specified size from a 1, 2, or 3 dimensional
*     NDF, thus producing an estimate of the local background within the NDF.
*
*     The algorithm proceeds as follows. A filtered form of the input data
*     is first produced by replacing every input pixel by the minimum of
*     the input values within a rectangular box centred on the pixel.
*     This filtered data is then filtered again, using a filter that
*     replaces every pixel value by the maximum value in a box centred on
*     the pixel. This produces an estimate of the lower envelope of the data,
*     but usually contains unacceptable sharp edges. In addition, this
*     filtered data has a tendency to hug the lower envelope of the
*     noise, thus under-estimating the true background of the noise-free
*     data. The first problem is minimised by smoothing the background
*     estimate using a filter that replaces every pixel value by the mean
*     of the values in a box centred on the pixel. The second problem
*     is minimised by estimating the difference between the input data
*     and the background estimate within regions well removed from any
*     bright areas. This difference is then extrapolated into the bright
*     source regions and used as a correction to the background estimate.
*     Specifically, the residuals between the input data and the initial
*     background estimate are first formed, and residuals which are more
*     than three times the RMS noise are set bad. The remaining residuals
*     are smoothed with a mean filter. This smoothing will replace a lot
*     of the bad values rejected above, but may not remove them all. Any
*     remaining bad values are estimated by linear interpolation between
*     the nearest good values along the first axis. The interpolated
*     residuals are then smoothed again using a mean filter, to get a
*     surface representing the bias in the initial background estimate.
*     This surface is finally added onto the initial background estimate
*     to obtain the output NDF.

*  Usage:
*     findback in out box

*  ADAM Parameters:
*     BOX() = _INTEGER (Read)
*        The dimensions of each of the filters, in pixels. Each value
*        should be odd (if an even value is supplied, the next higher odd
*        value will be used). The number of values supplied should not
*        exceed the number of significant (i.e. more than one element)
*        pixel axes in the input array. If any trailing values of 1 are
*        supplied, then each pixel value on the corresponding axes
*        will be fitted independently of its neighbours. For instance,
*        if the data array is 3-dimensional, and the third BOX value is 1,
*        then each x-y plane will be fitted independently of the neighbouring
*        planes. If the NDF has more than 1 pixel axis but only 1 value is
*        supplied, then the same value will be used for the both the first
*        and second pixel axes (a value of 1 will be assumed for the third
*        axis if the input array is 3-dimensional).
*     MSG_FILTER = _CHAR (Read)
*        Controls the amount of diagnostic information reported. This is the
*        standard messaging level. The default messaging level is NORM (2).
*        A value of NONE or 0 will suppress all screen output. VERB (3) will
*        indicate progress through the various stages of the algorithm. [NORM]
*     IN = NDF (Read)
*        The input NDF.
*     RMS = _DOUBLE (Read)
*        Specifies a value to use as the global RMS noise level in the
*        supplied data array. The suggested default value is the square root
*        of the mean of the values in the input NDF's Variance component.
*        If the NDF has no Variance component, the suggested default
*        is based on the differences between neighbouring pixel values,
*        measured over the entire input NDF. If multiple slices within the
*        NDF are to be processed independently (see parameter BOX), it
*        may be more appropriate for a separate default RMS to be calculated
*        for each slice. This will normally be the case if the noise could
*        be different in each of the slices. In such cases a null (!) can
*        be supplied for the RMS parameter, which forces a separate
*        default RMS value to be found and used for each slice. Any
*        pixel-to-pixel correlation in the noise can result in these
*        defaults being too low.
*     SUB = _LOGICAL (Read)
*        If a TRUE value is supplied, the output NDF will contain the
*        difference between the supplied input data and the estimated
*        background. If a FALSE value is supplied, the output NDF will
*        contain the estimated background itself. [FALSE]
*     OUT = NDF (Write)
*        The output NDF containing either the estimated background, or the
*        background-subtracted input data, as specified by parameter SUB.

*  Notes:
*     - Smoothing cubes in 3 dimensions can be very slow.

*  Copyright:
*     Copyright (C) 2009 Science and Technology Facilities Council.
*     Copyright (C) 2006, 2007 Particle Physics & Astronomy Research Council.
*     All Rights Reserved.

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

*  Authors:
*     DSB: David S. Berry
*     TIMJ: Tim Jenness (JAC, Hawaii)
*     {enter_new_authors_here}

*  History:
*     13-SEP-2006 (DSB):
*        Original version.
*     19-MAR-2007 (DSB):
*        - Added parameters SUB and RMS.
*        - Fix bug that left the output NDF uninitialised if ILEVEL is set
*        non-zero.
*        - Use generic data type handling as in FINDCLUMPS.
*     14-JAN-2009 (TIMJ):
*        Use MERS for message filtering.
*     29-JUL-2009 (TIMJ):
*        Rename ILEVEL to MSG_FILTER
*     17-MAY-2011 (DSB):
*        Use sqrt rather than sqrtf when calculating RMS.
*     12-SEP-2011 (DSB):
*        Process slices in separate threads.
*     {enter_further_changes_here}

*-
*/

/* Local Variables: */
   CupidFindback0Data *job_data; /* Pointer to data for all jobs */
   CupidFindback0Data *pdata; /* Pointer to data for current job */
   Grp *grp;                 /* GRP identifier for configuration settings */
   ThrWorkForce *wf = NULL;  /* Pool of persistent worker threads */
   char dtype[ 21 ];         /* HDS data type for output NDF */
   char itype[ 21 ];         /* HDS data type to use when processing */
   double *ipv;              /* Pointer to Variance array */
   double *pd1;              /* Pointer to double precision input data */
   double *pd2;              /* Pointer to double precision output data */
   double rms;               /* Global rms error in data */
   double sum;               /* Sum of variances */
   float *pf1;               /* Pointer to single precision input data */
   float *pf2;               /* Pointer to single precision output data */
   int *old_status;          /* Pointer to original status value */
   int box[ 3 ];             /* Dimensions of each cell in pixels */
   int dim[ NDF__MXDIM ];    /* Dimensions of each NDF pixel axis */
   int el;                   /* Number of elements mapped */
   int i;                    /* Loop count */
   int indf1;                /* Identifier for input NDF */
   int indf2;                /* Identifier for output NDF */
   int islice;               /* Slice index */
   int iystep;               /* Index of slice in ydirection */
   int izstep;               /* Index of slice in z direction */
   int lbnd[ NDF__MXDIM ];   /* Lower pixel bounds of slice */
   int n;                    /* Number of values summed in "sum" */
   int ndim;                 /* Total number of pixel axes in NDF */
   int newalg;               /* Use experimental algorithm variations? */
   int nsdim;                /* Number of significant pixel axes in NDF */
   int nslice;               /* Number of slices to process */
   int nval;                 /* Number of values supplied */
   int nystep;               /* Number of independent y slices */
   int nzstep;               /* Number of slices in z direction */
   int sdim[ 3 ];            /* Dimensions of each significant NDF axis */
   int slice_dim[ 3 ];       /* Dimensions of each significant slice axis */
   int slice_lbnd[ 3 ];      /* Lower bounds of each significant slice axis */
   int slice_size;           /* Number of pixels in each slice */
   int state;                /* Parameter state */
   int sub;                  /* Output the background-subtracted input data? */
   int type;                 /* Integer identifier for data type */
   int ubnd[ NDF__MXDIM ];   /* Upper pixel bounds of slice */
   int var;                  /* Does i/p NDF have a Variance component? */
   size_t size;              /* Size of GRP group */
   void *ipd1;               /* Pointer to input Data array */
   void *ipd2;               /* Pointer to output Data array */
   void *ipdin;              /* Pointer to input Data array */
   void *ipdout;             /* Pointer to output Data array */

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

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

/* Record the existing AST status pointer, and ensure AST uses the supplied
   status pointer instead. */
   old_status = astWatch( status );

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

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

/* Identify and count the number of significant axes (i.e. axes spanning
   more than 1 pixel). Also record their dimensions. */
   nsdim = 0;
   for( i = 0; i < ndim; i++ ) {
      dim[ i ] = ubnd[ i ] - lbnd[ i ] + 1;
      if( dim[ i ] > 1 ) sdim[ nsdim++ ] = dim[ i ];
   }

/* If there are too many significant axes, report an error. */
   if( nsdim > 3 && *status == SAI__OK ) {
       *status = SAI__ERROR;
       ndfMsg( "N", indf1 );
       msgSeti( "NS", nsdim );
       errRep( "", "The NDF '^N' has ^NS significant pixel axes, but this"
               "application requires 1, 2 or 3.", status );
   }

/* Ensure we have 3 values in sdim (pad with trailings 1's if required). */
   if( nsdim < 3 ) sdim[ 2 ] = 1;
   if( nsdim < 2 ) sdim[ 1 ] = 1;

/* See if the output is to contain the background-subtracted data, or the
   background estimate itself. */
   parGet0l( "SUB", &sub, status );

/* Create the output by propagating everything except the Data and
   (if we are outputting the background itself) Variance arrays. */
   if( sub ) {
      ndfProp( indf1, "UNITS,AXIS,WCS,QUALITY,VARIANCE", "OUT", &indf2,
               status );
   } else {
      ndfProp( indf1, "UNITS,AXIS,WCS,QUALITY", "OUT", &indf2, status );
   }

   msgBlankif( MSG__VERB, status );

/* Get the dimensions of each of the filters, in pixels. If only one
   value is supplied, duplicate it as the second value if the second axis
   is significant. If fewer than 3 values were supplied, use 1 for the 3rd
   value (whether or not it is significant). This results in each plane
   being fitted independently of the adjacent planes by default. */
   parGet1i( "BOX", nsdim, box, &nval, status );
   if( *status != SAI__OK ) goto L999;
   if( nval < 2 ) box[ 1 ] = ( nsdim > 1 ) ? box[ 0 ] : 1;
   if( nval < 3 ) box[ 2 ] = 1;

/* Ensure box sizes are odd. */
   box[ 0 ] = 2*( box[ 0 ] / 2 ) + 1;
   box[ 1 ] = 2*( box[ 1 ] / 2 ) + 1;
   box[ 2 ] = 2*( box[ 2 ] / 2 ) + 1;

   msgOutiff( MSG__VERB, "", "Using box sizes [%d,%d,%d].", status,
              box[0], box[1], box[2]);

/* If any trailing axes have a cell size of 1, then we apply the algorithm
   independently to every pixel index on the trailing axes. First of all
   set things up assuming that there are no trailing axes with cell size
   of 1. */
   nystep = 1;
   nzstep = 1;
   slice_dim[ 0 ] = sdim[ 0 ];
   slice_dim[ 1 ] = sdim[ 1 ];
   slice_dim[ 2 ] = sdim[ 2 ];
   slice_lbnd[ 0 ] = lbnd[ 0 ];
   slice_lbnd[ 1 ] = lbnd[ 1 ];
   slice_lbnd[ 2 ] = lbnd[ 2 ];

/* If the 3rd pixel axis has a cell size of 1, arrange that each slice
   contains a single plane. */
   if( box[ 2 ] == 1 ) {
      nzstep = sdim[ 2 ];
      slice_dim[ 2 ] = 1;

/* If the 2nd pixel axis also has a cell size of 1, arrange that each slice
   contains a single row. */
      if( box[ 1 ] == 1 ) {
         nystep = sdim[ 1 ];
         slice_dim[ 1 ] = 1;
      }
   }

/* Determine the number of pixels in each independent slice. */
   slice_size = slice_dim[ 0 ]*slice_dim[ 1 ]*slice_dim[ 2 ];

/* Decide what numeric data type to use, and set the output NDF data type. */
   ndfMtype( "_REAL,_DOUBLE", indf1, indf1, "Data,Variance", itype,
             20, dtype, 20, status );
   if( !strcmp( itype, "_DOUBLE" ) ) {
      type = CUPID__DOUBLE;
   } else {
      type = CUPID__FLOAT;
   }

   ndfStype( dtype, indf2, "Data,Variance", status );

/* Map the input and output arrays. */
   ndfMap( indf1, "Data", itype, "READ", &ipdin, &el, status );
   ndfMap( indf2, "Data", itype, "WRITE", &ipdout, &el, status );

/* If the rms value is supplied on the command, there is no need to
   calculate a default value. */
   parState( "RMS", &state, status );
   if( state == PAR__GROUND ) {

/* Calculate the default RMS value. If the NDF has a Variance component
   it is the square root of the mean Variance value. Otherwise, it is found
   by looking at differences between adjacent pixel values in the Data
   component. */
      ndfState( indf1, "VARIANCE", &var, status );
      if( *status == SAI__OK && var ) {
         ndfMap( indf1, "VARIANCE", "_DOUBLE", "READ", (void *) &ipv, &el, status );

         sum = 0.0;
         n = 0;
         for( i = 0; i < el; i++ ) {
            if( ipv[ i ] != VAL__BADD ) {
               sum += ipv[ i ];
               n++;
            }
         }

         if( n > 0 ) {
            rms = sqrt( sum/n );

         } else {
            *status = SAI__ERROR;
            errRep( "", "The supplied data contains insufficient "
                    "good Variance values to continue.", status );
         }

      } else {
         ipv = NULL;
         rms = cupidRms( type, ipdin, el, sdim[ 0 ], status );
      }

/* Set the default RMS noise level. */
      parDef0d( "RMS", rms, status );
   }

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

/* Get the RMS noise level. */
   parGet0d( "RMS", &rms, status );

/* Annul the error and use an RMS value of VAL__BAD if a null parameter
   value was supplied. This causes an independent default noise estimate to
   be used for each slice of the base NDF. */
   if( *status == PAR__NULL ) {
      errAnnul( status );
      rms = VAL__BADD;
   }

/* See if any experimental algorithm variations are to be used. */
   parGet0l( "NEWALG", &newalg, status );

/* Create a pool of worker threads. */
   wf = thrCreateWorkforce( thrGetNThread( "CUPID_THREADS", status ), status );

/* Get memory to hold a description of each job passed to a worker. There
   is one job for each slice. */
   nslice = nystep*nzstep;
   job_data = astMalloc( nslice*sizeof( *job_data ) );
   if( *status == SAI__OK ) {

/* Loop round all slices to be processed. */
      ipd1 = ipdin;
      ipd2 = ipdout;
      islice = 0;
      pdata = job_data;

      for( izstep = 0; izstep < nzstep ; izstep++ ) {

         slice_lbnd[ 1 ] = lbnd[ 1 ];

         for( iystep = 0; iystep < nystep; iystep++, islice++,pdata++ ) {

/* Store the information needed by the function (cupidFindback0) that
   does the work in a thread. */
            pdata->islice = islice;
            pdata->nslice = nslice;
            pdata->type = type;
            pdata->ndim = ndim;
            pdata->box[ 0 ] = box[ 0 ];
            pdata->box[ 1 ] = box[ 1 ];
            pdata->box[ 2 ] = box[ 2 ];
            pdata->rms = rms;
            pdata->ipd1 = ipd1;
            pdata->ipd2 = ipd2;
            pdata->slice_dim[ 0 ] = slice_dim[ 0 ];
            pdata->slice_lbnd[ 0 ] = slice_lbnd[ 0 ];
            pdata->slice_dim[ 1 ] = slice_dim[ 1 ];
            pdata->slice_lbnd[ 1 ] = slice_lbnd[ 1 ];
            pdata->slice_dim[ 2 ] = slice_dim[ 2 ];
            pdata->slice_lbnd[ 2 ] = slice_lbnd[ 2 ];
            pdata->newalg = newalg;
            pdata->slice_size = slice_size;

/* Submit a job to the workforce to process the current slice. */
            thrAddJob( wf, 0, pdata, cupidFindback0, 0, NULL, status );

/* Update pointers to the start of the next slice in the input and output
   arrays. */
            if( type == CUPID__FLOAT ) {
               ipd1 = ( (float *) ipd1 ) + slice_size;
               ipd2 = ( (float *) ipd2 ) + slice_size;
            } else {
               ipd1 = ( (double *) ipd1 ) + slice_size;
               ipd2 = ( (double *) ipd2 ) + slice_size;
            }

/* Increment the lower bound on the 2nd pixel axis. */
            slice_lbnd[ 1 ]++;
         }

/* Increment the lower bound on the 3rd pixel axis. */
         slice_lbnd[ 2 ]++;
      }

/* Wait until all jobs have finished. */
      thrWait( wf, status );
   }

/* The output currently holds the background estimate. If the user has
   requested that the output should hold the background-subtracted input
   data, then do the arithmetic now. */
   if( sub && *status == SAI__OK ) {
      if( type == CUPID__FLOAT ) {
         pf1 = (float *) ipdin;
         pf2 = (float *) ipdout;
         for( i = 0; i < el; i++, pf1++, pf2++ ) {
            if( *pf1 != VAL__BADR && *pf2 != VAL__BADR ) {
               *pf2 = *pf1 - *pf2;
            } else {
               *pf2 = VAL__BADR;
            }
         }

      } else {
         pd1 = (double *) ipdin;
         pd2 = (double *) ipdout;
         for( i = 0; i < el; i++, pd1++, pd2++ ) {
            if( *pd1 != VAL__BADD && *pd2 != VAL__BADD ) {
               *pd2 = *pd1 - *pd2;
            } else {
               *pd2 = VAL__BADD;
            }
         }

      }
   }

/* Tidy up */
L999:;
   msgBlankif( MSG__VERB, status );

/* Free workspace. */
   job_data = astFree( job_data );
   wf = thrDestroyWorkforce( wf );

/* Reinstate the original AST inherited status value. */
   astWatch( old_status );

/* End the NDF context */
   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( "FINDBACK_ERR", "FINDBACK: Failed to find the background "
              "of an NDF.", status );
   }
}
コード例 #25
0
void smurf_calcqu( int *status ) {

    /* Local Variables: */
    AstFitsChan *fc;           /* Holds FITS headers for output NDFs */
    AstKeyMap *config;         /* Holds all cleaning parameters */
    AstKeyMap *dkpars;         /* Holds dark squid cleaning parameters */
    AstKeyMap *heateffmap = NULL; /* Heater efficiency data */
    AstKeyMap *sub_instruments;/* Indicates which instrument is being used */
    Grp *bgrp = NULL;          /* Group of base names for each chunk */
    Grp *igrp = NULL;          /* Group of input files */
    Grp *ogrp = NULL;          /* Group of output files  */
    Grp *sgrp = NULL;          /* Group of science files */
    HDSLoc *loci = NULL;       /* Locator for output I container file */
    HDSLoc *locq = NULL;       /* Locator for output Q container file */
    HDSLoc *locu = NULL;       /* Locator for output U container file */
    NdgProvenance *oprov;      /* Provenance to store in each output NDF */
    ThrWorkForce *wf;          /* Pointer to a pool of worker threads */
    char headval[ 81 ];        /* FITS header value */
    char ndfname[ 30 ];        /* Name of output Q or U NDF */
    char polcrd[ 81 ];         /* FITS 'POL_CRD' header value */
    char subarray[ 10 ];       /* Subarray name (e.g. "s4a", etc) */
    double angrot;             /* Angle from focal plane X axis to fixed analyser */
    double paoff;              /* WPLATE value corresponding to POL_ANG=0.0 */
    float arcerror;            /* Max acceptable error (arcsec) in one block */
    int block_end;             /* Index of last time slice in block */
    int block_start;           /* Index of first time slice in block */
    int dkclean;               /* Clean dark squids? */
    int fix;                   /* Fix the POL-2 triggering issue? */
    int iblock;                /* Index of current block */
    int iplace;                /* NDF placeholder for current block's I image */
    int ipolcrd;               /* Reference direction for waveplate angles */
    int maxsize;               /* Max no. of time slices in a block */
    int minsize;               /* Min no. of time slices in a block */
    int nc;                    /* Number of characters written to a string */
    int pasign;                /* +1 or -1 indicating sense of POL_ANG value */
    int qplace;                /* NDF placeholder for current block's Q image */
    int submean;               /* Subtract mean value from each time slice? */
    int uplace;                /* NDF placeholder for current block's U image */
    size_t ichunk;             /* Continuous chunk counter */
    size_t idx;                /* Subarray counter */
    size_t igroup;             /* Index for group of related input NDFs */
    size_t inidx;              /* Index into group of science input NDFs */
    size_t nchunk;             /* Number continuous chunks outside iter loop */
    size_t ssize;              /* Number of science files in input group */
    smfArray *concat = NULL;   /* Pointer to smfArray holding bolometer data */
    smfArray *darks = NULL;    /* dark frames */
    smfArray *dkarray = NULL;  /* Pointer to smfArray holding dark squid data */
    smfArray *flatramps = NULL;/* Flatfield ramps */
    smfData *data = NULL;      /* Concatenated data for one subarray */
    smfData *dkdata = NULL;    /* Concatenated dark squid data for one subarray */
    smfGroup *sgroup = NULL;   /* smfGroup corresponding to sgrp */

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

    /* Start new AST and NDF contexts. */
    astBegin;
    ndfBegin();

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

    /* Get a group of input files */
    kpg1Rgndf( "IN", 0, 1, "  Give more NDFs...", &igrp, &ssize, status );

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

    /* Check we have at least once science file. */
    ssize = grpGrpsz( sgrp, status );
    if( ssize == 0 ) {
        msgOutif( MSG__NORM, " ", "All supplied input frames were DARK.",
                  status );
    } else {

        /* See if a correction should be made for the POL2 triggering issue. */
        parGet0l( "FIX", &fix, status );

        /* Create HDS container files to hold the output NDFs. */
        datCreat( "OUTQ", "CALCQU", 0, 0, status );
        datCreat( "OUTU", "CALCQU", 0, 0, status );

        /* Associate the locators with the structures. */
        datAssoc( "OUTQ", "WRITE", &locq, status );
        datAssoc( "OUTU", "WRITE", &locu, status );

        /* The I images are optional. */
        if( *status == SAI__OK ) {
            datCreat( "OUTI", "CALCQU", 0, 0, status );
            datAssoc( "OUTI", "WRITE", &loci, status );
            if( *status == PAR__NULL ) {
                errAnnul( status );
                loci = NULL;
            }
        }

        /* Group the input files so that all files within a single group have the
           same wavelength and belong to the same subscan of the same observation.
           Also identify chunks of data that are contiguous in time, and
           determine to which such chunk each group belongs. All this information
           is returned in a smfGroup structure ("*sgroup"). */
        smf_grp_related( sgrp, ssize, 1, 1, 0, NULL, NULL, NULL,
                         NULL, &sgroup, &bgrp, NULL, status );

        /* Obtain the number of contiguous chunks. */
        if( *status == SAI__OK ) {
            nchunk = sgroup->chunk[ sgroup->ngroups - 1 ] + 1;
        } else {
            nchunk = 0;
        }

        /* Indicate we have not yet found a value for the ARCERROR parameter. */
        arcerror = 0.0;

        /* Loop over all contiguous chunks */
        for( ichunk = 0; ichunk < nchunk && *status == SAI__OK; ichunk++ ) {

            /* Display the chunk number. */
            if( nchunk > 1 ) {
                msgOutiff( MSG__VERB, "", "   Doing chunk %d of %d.",
                           status, (int) ichunk + 1, (int) nchunk );
            }

            /* Concatenate the data within this contiguous chunk. This produces a
               smfArray ("concat") containing a smfData for each subarray present in
               the chunk. Each smfData holds the concatenated data for a single
               subarray. */
            smf_concat_smfGroup( wf, NULL, sgroup, darks, NULL, flatramps,
                                 heateffmap, ichunk, 1, 1, NULL, 0, NULL, NULL,
                                 0, 0, 0, &concat, NULL, status );

            /* Get a KeyMap holding values for the configuration parameters. Since we
               sorted by wavelength when calling smf_grp_related, we know that all
               smfDatas in the current smfArray (i.e. chunk) will relate to the same
               wavelength. Therefore we can use the same parameters for all smfDatas in
               the current smfArray. */
            sub_instruments = smf_subinst_keymap( SMF__SUBINST_NONE,
                                                  concat->sdata[ 0 ], NULL,
                                                  0, status );
            config = kpg1Config( "CONFIG", "$SMURF_DIR/smurf_calcqu.def",
                                 sub_instruments, status );
            sub_instruments = astAnnul( sub_instruments );


            /* Get the CALCQU specific parameters. */
            if( !astMapGet0I( config, "PASIGN", &pasign ) ) pasign = 1;
            msgOutiff( MSG__VERB, "", "PASIGN=%d", status, pasign );
            if( !astMapGet0D( config, "PAOFF", &paoff ) ) paoff = 0.0;
            msgOutiff( MSG__VERB, "", "PAOFF=%g", status, paoff );
            if( !astMapGet0D( config, "ANGROT", &angrot ) ) angrot = 90.0;
            msgOutiff( MSG__VERB, "", "ANGROT=%g", status, angrot );
            if( !astMapGet0I( config, "SUBMEAN", &submean ) ) submean = 0;
            msgOutiff( MSG__VERB, "", "SUBMEAN=%d", status, submean );

            /* See if the dark squids should be cleaned. */
            if( !astMapGet0I( config, "DKCLEAN", &dkclean ) ) dkclean = 0;

            /* If required, clean the dark squids now since we might need to use them to
               clean the bolometer data. */
            if( dkclean ) {

                /* Create a smfArray containing the dark squid data. For each one, store
                   a pointer to the main header so that smf_clean_smfArray can get at the
                   JCMTState information. */
                dkarray = smf_create_smfArray( status );
                for( idx = 0; idx < concat->ndat && *status == SAI__OK; idx++ ) {
                    data = concat->sdata[ idx ];
                    if( data && data->da && data->da->dksquid ) {
                        dkdata = data->da->dksquid;
                        dkdata->hdr = data->hdr;
                        smf_addto_smfArray( dkarray, dkdata, status );
                    }
                }

                /* Clean the smfArray containing the dark squid data. Use the "CLEANDK.*"
                   parameters. */
                (void) astMapGet0A( config, "CLEANDK", &dkpars );
                smf_clean_smfArray( wf, dkarray, NULL, NULL, NULL, dkpars, status );
                dkpars = astAnnul( dkpars );

                /* Nullify the header pointers so that we don't accidentally close any. */
                if( dkarray ) {
                    for( idx = 0; idx < dkarray->ndat; idx++ ) {
                        dkdata = dkarray->sdata[ idx ];
                        dkdata->hdr = NULL;
                    }

                    /* Free the smfArray holding the dark squid data, but do not free the
                       individual smfDatas within it. */
                    dkarray->owndata = 0;
                    smf_close_related( &dkarray, status );
                }
            }

            /* Now clean the bolometer data */
            smf_clean_smfArray( wf, concat, NULL, NULL, NULL, config, status );

            /* If required correct for the POL2 triggering issue. */
            if( fix ) smf_fix_pol2( wf, concat, status );

            /* Loop round each sub-array in the current contiguous chunk of data. */
            for( idx = 0; idx < concat->ndat && *status == SAI__OK; idx++ ) {
                data = concat->sdata[ idx ];

                /* Find the name of the subarray that generated the data. */
                smf_find_subarray( data->hdr, subarray, sizeof(subarray), NULL,
                                   status );

                /* Display the sub-array. */
                if( concat->ndat > 1 ) {
                    msgOutiff( MSG__VERB, "", "   Doing sub-array %s.",
                               status, subarray );
                }

                /* Create an empty provenance structure. Each input NDF that contributes
                   to the current chunk and array will be added as an ancestor to this
                   structure, which will later be stored in each output NDF created for
                   this chunk and array. */
                oprov = ndgReadProv( NDF__NOID, "SMURF:CALCQU", status );

                /* Indicate we do not yet have any FITS headers for the output NDFs */
                fc = NULL;

                /* Indicate we do not yet know the coordinate reference frame for the
                   half-waveplate angle. */
                polcrd[ 0 ] = 0;
                ipolcrd = 0;

                /* Go through the smfGroup looking for groups of related input NDFs that
                   contribute to the current chunk. */
                for( igroup = 0; igroup < sgroup->ngroups; igroup++ ) {
                    if( sgroup->chunk[ igroup ] == ichunk ) {

                        /* Get the integer index into the GRP group (sgrp) that holds the input NDFs.
                           This index identifies the input NDF that provides the data for the current
                           chunk and subarray. This assumes that the order in which smf_concat_smfGroup
                           stores arrays in the "concat" smfArray matches the order in which
                           smf_grp_related stores arrays within the sgroup->subgroups. */
                        inidx = sgroup->subgroups[ igroup ][ idx ];

                        /* Add this input NDF as an ancestor into the output provenance structure. */
                        smf_accumulate_prov( NULL, sgrp, inidx, NDF__NOID,
                                             "SMURF:CALCQU", &oprov, status );

                        /* Merge the FITS headers from the current input NDF into the FitsChan
                           that holds headers for the output NDFs. The merging retains only those
                           headers which have the same value in all input NDFs. */
                        smf_fits_outhdr( data->hdr->fitshdr, &fc, status );

                        /* Get the polarimetry related FITS headers and check that all input NDFs
                           have usabie values. */
                        headval[ 0 ] = 0;
                        smf_getfitss( data->hdr, "POL_MODE", headval,
                                      sizeof(headval), status );
                        if( strcmp( headval, "CONSTANT" ) && *status == SAI__OK ) {
                            *status = SAI__ERROR;
                            grpMsg( "N", sgrp, inidx );
                            errRep( " ", "Input NDF ^N does not contain "
                                    "polarimetry data obtained with a spinning "
                                    "half-waveplate.", status );
                        }

                        headval[ 0 ] = 0;
                        smf_getfitss( data->hdr, "POLWAVIN", headval,
                                      sizeof(headval), status );
                        if( strcmp( headval, "Y" ) && *status == SAI__OK ) {
                            *status = SAI__ERROR;
                            grpMsg( "N", sgrp, inidx );
                            errRep( " ", "Half-waveplate was not in the beam for "
                                    "input NDF ^N.", status );
                        }

                        headval[ 0 ] = 0;
                        smf_getfitss( data->hdr, "POLANLIN", headval,
                                      sizeof(headval), status );
                        if( strcmp( headval, "Y" ) && *status == SAI__OK ) {
                            *status = SAI__ERROR;
                            grpMsg( "N", sgrp, inidx );
                            errRep( " ", "Analyser was not in the beam for input "
                                    "NDF ^N.", status );
                        }

                        if( polcrd[ 0 ] ) {
                            headval[ 0 ] = 0;
                            smf_getfitss( data->hdr, "POL_CRD", headval,
                                          sizeof(headval), status );
                            if( strcmp( headval, polcrd ) && *status == SAI__OK ) {
                                *status = SAI__ERROR;
                                errRep( " ", "Input NDFs have differing values for "
                                        "FITS header 'POL_CRD'.", status );
                            }

                        } else {
                            smf_getfitss( data->hdr, "POL_CRD", polcrd,
                                          sizeof(polcrd), status );
                            if( !strcmp( polcrd, "FPLANE" ) ) {
                                ipolcrd = 0;
                            } else if( !strcmp( polcrd, "AZEL" ) ) {
                                ipolcrd = 1;
                            } else if( !strcmp( polcrd, "TRACKING" ) ) {
                                ipolcrd = 2;
                            } else if( *status == SAI__OK ) {
                                *status = SAI__ERROR;
                                msgSetc( "N", data->file->name );
                                msgSetc( "V", polcrd );
                                errRep( " ", "Input NDF ^N contains unknown value "
                                        "'^V' for FITS header 'POL_CRD'.", status );
                            }
                        }
                    }
                }

                /* If not already done, get the maximum spatial drift (in arc-seconds) that
                   can be tolerated whilst creating a single I/Q/U image. The default value is
                   half the makemap default pixel size. Also get limits on the number of
                   time slices in any block. */
                if( arcerror == 0.0 ) {
                    parDef0d( "ARCERROR", 0.5*smf_calc_telres( data->hdr->fitshdr,
                              status ), status );
                    parGet0r( "ARCERROR", &arcerror, status );

                    parGet0i( "MAXSIZE", &maxsize, status );
                    parGet0i( "MINSIZE", &minsize, status );
                    if( maxsize > 0 && maxsize < minsize && *status == SAI__OK ) {
                        *status = SAI__ERROR;
                        errRepf( "", "Value of parameter MAXSIZE (%d) is less "
                                 "than value of parameter MINSIZE (%d)", status,
                                 maxsize, minsize );
                    }
                }

                /* The algorithm that calculates I, Q and U assumes that all samples for a
                   single bolometer measure flux from the same point on the sky. Due to
                   sky rotation, this will not be the case - each bolometer will drift
                   slowly across the sky. However, since the drift is (or should be)
                   slow we can apply the I/Q/U algorithm to blocks of contiguous data over
                   which the bolometers do not move significantly. We produce a separate
                   I, Q and U image for each such block. The first block starts at the first
                   time slice in the smfData. */
                block_start = 0;

                /* Find the time slice at which the corner bolometers have moved
                   a critical distance (given by parameter ARCERROR) from their
                   positions at the start of the block. Then back off some time slices
                   to ensure that the block holds an integral number of half-waveplate
                   rotations. */
                block_end = smf_block_end( data, block_start, ipolcrd, arcerror,
                                           maxsize, status );

                /* Loop round creating I/Q/U images for each block. Count them. */
                iblock = 0;
                while( block_end >= 0 && *status == SAI__OK ) {

                    /* Skip very short blocks. */
                    if( block_end - block_start > minsize ) {

                        /* Display the start and end of the block. */
                        msgOutiff( MSG__VERB, "", "   Doing time slice block %d "
                                   "-> %d", status, (int) block_start,
                                   (int) block_end );

                        /* Get the name for the Q NDF for this block. Start of with "Q" followed by
                           the block index. */
                        iblock++;
                        nc = sprintf( ndfname, "Q%d", iblock );

                        /* Append the subarray name to the NDF name. */
                        nc += sprintf( ndfname + nc, "_%s", subarray );

                        /* Append the chunk index to the NDF name. */
                        nc += sprintf( ndfname + nc, "_%d", (int) ichunk );

                        /* Get NDF placeholder for the Q NDF. The NDFs are created inside the
                           output container file. */
                        ndfPlace( locq, ndfname, &qplace, status );

                        /* The name of the U NDF is the same except the initial "Q" is changed to
                           "U". */
                        ndfname[ 0 ] = 'U';
                        ndfPlace( locu, ndfname, &uplace, status );

                        /* The name of the I NDF is the same except the initial "Q" is changed to
                           "I". */
                        if( loci ) {
                            ndfname[ 0 ] = 'I';
                            ndfPlace( loci, ndfname, &iplace, status );
                        } else {
                            iplace = NDF__NOPL;
                        }

                        /* Store the chunk and block numbers as FITS headers. */
                        atlPtfti( fc, "POLCHUNK", (int) ichunk, "Chunk index used by CALCQU", status );
                        atlPtfti( fc, "POLBLOCK", iblock, "Block index used by CALCQU", status );

                        /* Create the Q and U images for the current block of time slices from
                           the subarray given by "idx", storing them in the output container
                           file. */
                        smf_calc_iqu( wf, data, block_start, block_end, ipolcrd,
                                      qplace, uplace, iplace, oprov, fc,
                                      pasign, AST__DD2R*paoff, AST__DD2R*angrot,
                                      submean, status );

                        /* Warn about short blocks. */
                    } else {
                        msgOutiff( MSG__VERB, "", "   Skipping short block of %d "
                                   "time slices (parameter MINSIZE=%d).", status,
                                   block_end - block_start - 1, minsize );
                    }

                    /* The next block starts at the first time slice following the previous
                       block. */
                    block_start = block_end + 1;

                    /* Find the time slice at which the corner bolometers have moved
                       a critical distance (given by parameter ARCERROR) from their
                       positions at the start of the block. Then back off some time slices
                       to ensure that the block holds an integral number of half-waveplate
                       rotations. This returns -1 if all time slices have been used. */
                    block_end = smf_block_end( data, block_start, ipolcrd,
                                               arcerror, maxsize, status );
                }

                /* Free resources */
                oprov = ndgFreeProv( oprov, status );
                fc = astAnnul( fc );
            }
            config = astAnnul( config );

            /* Close the smfArray. */
            smf_close_related( &concat, status );
        }

        /* Annul the locators for the output container files. */
        datAnnul( &locq, status );
        datAnnul( &locu, status );
        if( loci ) datAnnul( &loci, status );

        /* The parameter system hangs onto a primary locator for each container
           file, so cancel the parameters to annul these locators. */
        datCancl( "OUTQ", status );
        datCancl( "OUTU", status );
        datCancl( "OUTI", status );
    }

    /* Free resources. */
    smf_close_related( &darks, status );
    smf_close_related( &flatramps, status );

    if( igrp ) grpDelet( &igrp, status);
    if( sgrp ) grpDelet( &sgrp, status);
    if( bgrp ) grpDelet( &bgrp, status );
    if( ogrp ) grpDelet( &ogrp, status );
    if( sgroup ) smf_close_smfGroup( &sgroup, status );
    if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );

    /* End the NDF and AST contexts. */
    ndfEnd( status );
    astEnd;

    /* Issue a status indication.*/
    if( *status == SAI__OK ) {
        msgOutif( MSG__VERB, " ", "CALCQU succeeded.", status);
    } else {
        msgOutif( MSG__VERB, " ", "CALCQU failed.", status);
    }
}
コード例 #26
0
/* Main entry */
void smurf_fixsteps( int *status ) {

/* Local Variables */
   AstKeyMap *keymap;        /* Default config parameter values */
   AstKeyMap *sub_instruments; /* Info about sub-instruments */
   FILE *fd = NULL;          /* File descriptor */
   Grp *igrp = NULL;         /* Input group of files */
   Grp *ogrp = NULL;         /* Output group of files */
   dim_t dcfitbox;           /* DCFITBOX config parameter */
   dim_t dcsmooth;           /* DCSMOOTH config parameter */
   dim_t nx;                 /* Length of first pixel axis */
   double dcthresh;          /* DCTHRESH config parameter */
   double sizetol;           /* Tolerance allowed on step height */
   int changed;              /* Have any step fixes changed? */
   int dclimcorr;            /* DCLIMCORR config parameter */
   int dcmaxsteps;           /* DCMAXSTEPS config parameter */
   int first;                /* Index of first change to report */
   int itemp;                /* Intermediate value */
   int meanshift;            /* Use a mean shift filter? */
   int nnew;                 /* Number of new step fixes */
   int nold;                 /* Number of old step fixes */
   size_t nrej;              /* Number of rejected bolometers */
   size_t outsize;           /* Total number of NDF names in the output group */
   size_t size;              /* Number of files in input group */
   smfData *data = NULL;     /* Output smfData */
   smfData *indata = NULL;   /* Input smfData */
   smfStepFix *newsteps = NULL; /* New step fix descriptions */
   smfStepFix *oldsteps = NULL; /* Old step fix descriptions */
   ThrWorkForce *wf = NULL;  /* Pointer to a pool of worker threads */

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

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

/* Get the name of the input NDF. */
   kpg1Rgndf( "IN", 1, 1, "", &igrp, &size, status );

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

/* Open the input data file, read-only. */
   smf_open_file( igrp, 1, "Read", 0, &indata, status );

/* Since we will be modifying the data values, we need a deep copy. */
   data = smf_deepcopy_smfData( indata, 0, 0, 0, 0, status );

/* Place cleaning parameters into a keymap and set defaults. Note that we
   use the map-maker defaults file here so that we populate the locked
   keymap with all the parameters that people may come across to allow
   them to load their map-maker config directly this application. */
   sub_instruments = smf_subinst_keymap( SMF__SUBINST_NONE, data, NULL, 0,
                                         status );
   keymap = kpg1Config( "CONFIG", "$SMURF_DIR/smurf_makemap.def",
                        sub_instruments, status );
   sub_instruments = astAnnul( sub_instruments );

/* Set the default for each of the step fixing config parameters. */
   astMapGet0I( keymap, "DCSMOOTH", &itemp );
   parDef0i( "DCSMOOTH", itemp, status );

   astMapGet0I( keymap, "DCFITBOX", &itemp );
   parDef0i( "DCFITBOX", itemp, status );

   astMapGet0I( keymap, "DCMAXSTEPS", &itemp );
   parDef0i( "DCMAXSTEPS", itemp, status );

   astMapGet0I( keymap, "DCLIMCORR", &itemp );
   parDef0i( "DCLIMCORR", itemp, status );

   astMapGet0D( keymap, "DCTHRESH", &dcthresh );
   parDef0d( "DCTHRESH", dcthresh, status );

/* Get values for the config params */
   parGet0i( "DCSMOOTH", &itemp, status );
   dcsmooth = itemp;

   parGet0i( "DCFITBOX", &itemp, status );
   dcfitbox = itemp;

   parGet0i( "DCMAXSTEPS", &itemp, status );
   dcmaxsteps = itemp;

   parGet0i( "DCLIMCORR", &itemp, status );
   dclimcorr = itemp;

   parGet0d( "DCTHRESH", &dcthresh, status );

   parGet0l( "MEANSHIFT", &meanshift, status );

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

/* Fix the steps. */
   smf_fix_steps( wf, data, dcthresh, dcsmooth, dcfitbox, dcmaxsteps,
                  dclimcorr, meanshift, &nrej, &newsteps, &nnew, status );

/* Display a summary of what was done by the step fixer. */
   msgBlank( status );
   if( nrej == 0 ) {
      msgOut( "", "No bolometers were rejected", status );
   } else if( nrej == 1 ) {
      msgOut( "", "One bolometer was rejected", status );
   } else {
      msgSeti( "NREJ", nrej );
      msgOut( "", "^NREJ bolometers were rejected", status );
   }
   parPut0i( "NREJECTED", nrej, status );

   if( nnew == 0 ) {
      msgOut( "", "No steps were fixed", status );
   } else if( nnew == 1 ) {
      msgOut( "", "One step was fixed", status );
   } else {
      msgSeti( "NNEW", nnew );
      msgOut( "", "^NNEW steps were fixed", status );
   }
   parPut0i( "NFIXED", nnew, status );

/* If required, write out to a text file details of the steps that were
   fixed. */
   fd = smf_open_textfile( "NEWSTEPS", "w", "<none>", status );
   if( fd ) {
      smf1_write_steps( fd, indata, nnew, newsteps, dcthresh, dcsmooth,
                        dcfitbox, dcmaxsteps, dclimcorr, nrej, status );
      fclose( fd );
   }

/* If required, create the output NDF. */
   if( outsize > 0 && indata && indata->file ) {
      smf_write_smfData( data, NULL, NULL, ogrp, 1,
                         indata->file->ndfid, MSG__VERB, 0, status );
   }

/* Save the length of the first pixel axis. */
   nx = data ? data->dims[ 0 ] : 0;

/* Close the NDFs. */
   smf_close_file( &data, status );
   smf_close_file( &indata, status );

/* Attempt to open a file containing descriptions of steps fixed by a
   previous invocation of this program. */
   fd = smf_open_textfile( "OLDSTEPS", "r", "<none>", status );
   if( fd ) {

/* Get SIZETOL - the minimum significant fractional error in step sizes. */
      parGet0d( "SIZETOL", &sizetol, status );

/* Read the contents of the file, issuing a warning if the global
   properties read from the file (e.g. parameters used, no. of steps
   found, etc) differ from those of the current invocation. */
      msgBlank( status );
      oldsteps = smf1_read_steps( fd, dcthresh, dcsmooth,
                                  dcfitbox, dcmaxsteps, dclimcorr,
                                  nrej, nnew, &nold, status );

/* Get the index of the first change to report. */
      parGet0i( "FIRST", &first, status );

/* Compare the new step fixes with the old step fixes, issuing a warning
   for the first step fix that has changed. */
      changed = smf1_check_steps( "CONTINUE", first, nx, sizetol,
                                  nold, nnew, oldsteps, newsteps, status );

/* Store a flag indicating if any sstep fixes have chnaged. */
      parPut0l( "CHANGED", changed, status );

/* Tell the user if nothing has changed. */
      if( ! changed ) {
         msgOut( "", "There are no significant differences "
                 "between old and new step fixes.", status );
      }
      msgBlank( status );

/* Close the old steps file, and free the memory holding the old step
   descriptions. */
      fclose( fd );
      oldsteps = astFree( oldsteps );
   }

/* Free resources. */
   newsteps = astFree( newsteps );
   grpDelet( &igrp, status );
   grpDelet( &ogrp, status );

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

/* If anything went wrong issue a context message. */
   if( *status != SAI__OK ) msgOutif( MSG__VERB, " ", "FIXSTEPS failed.",
                                      status );
}
コード例 #27
0
void smurf_sc2clean( int *status ) {
  smfArray *array = NULL;    /* Data to be cleaned */
  Grp *basegrp=NULL;         /* Grp containing first file each chunk */
  size_t basesize;           /* Number of files in base group */
  smfArray *bbms = NULL;     /* Bad bolometer masks */
  smfArray *concat=NULL;     /* Pointer to a smfArray */
  size_t contchunk;          /* Continuous chunk counter */
  smfArray *darks = NULL;    /* Dark data */
  int ensureflat;            /* Flag for flatfielding data */
  smfArray *flatramps = NULL;/* Flatfield ramps */
  AstKeyMap *heateffmap = NULL;    /* Heater efficiency data */
  smfData *odata = NULL;     /* Pointer to output data struct */
  Grp *fgrp = NULL;          /* Filtered group, no darks */
  size_t gcount=0;           /* Grp index counter */
  size_t idx;                /* Subarray counter */
  Grp *igrp = NULL;          /* Input group of files */
  smfGroup *igroup=NULL;     /* smfGroup corresponding to igrp */
  dim_t maxconcat=0;         /* Longest continuous chunk length in samples */
  double maxlen=0;           /* Constrain maxconcat to this many seconds */
  size_t ncontchunks=0;      /* Number continuous chunks outside iter loop */
  Grp *ogrp = NULL;          /* Output group of files */
  size_t osize;              /* Total number of NDF names in the output group */
  dim_t padStart=0;          /* How many samples padding at start */
  dim_t padEnd=0;            /* How many samples padding at end */
  size_t size;               /* Number of files in input group */
  int temp;                  /* Temporary signed integer */
  int usedarks;              /* flag for using darks */
  ThrWorkForce *wf = NULL;   /* Pointer to a pool of worker threads */
  int writecom;              /* Write COMmon mode to NDF if calculated? */
  int writegai;              /* Write GAIns to NDF if calculated? */

  /* 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 );

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

  /* Filter out darks */
  smf_find_science( wf, 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;

  if (size == 0) {
    msgOutif(MSG__NORM, " ","All supplied input frames were filtered,"
       " nothing to do", status );
    goto CLEANUP;
  }

  /* --- Parse ADAM parameters ---------------------------------------------- */

  /* Maximum length of a continuous chunk */
  parGdr0d( "MAXLEN", 0, 0, VAL__MAXD, 1, &maxlen, status );

  /* Padding */
  parGdr0i( "PADSTART", 0, 0, VAL__MAXI, 1, &temp, status );
  padStart = (dim_t) temp;

  parGdr0i( "PADEND", 0, 0, VAL__MAXI, 1, &temp, status );
  padEnd = (dim_t) temp;

  /* Are we using darks? */
  parGet0l( "USEDARKS", &usedarks, status );

  /* Are we flatfielding? */
  parGet0l( "FLAT", &ensureflat, status );

  /* Write COM/GAI to NDFs if calculated? */
  parGet0l( "COM", &writecom, status );
  parGet0l( "GAI", &writegai, status );

  /* Get group of bolometer masks and read them into a smfArray */
  smf_request_mask( wf, "BBM", &bbms, status );

  /* Group the input files by subarray and continuity ----------------------- */
  smf_grp_related( igrp, size, 1, 0, maxlen-padStart-padEnd, NULL, NULL,
                   &maxconcat, NULL, &igroup, &basegrp, NULL, status );

  /* Obtain the number of continuous chunks and subarrays */
  if( *status == SAI__OK ) {
    ncontchunks = igroup->chunk[igroup->ngroups-1]+1;
  }

  basesize = grpGrpsz( basegrp, status );

  /* Get output file(s) */
  kpg1Wgndf( "OUT", basegrp, basesize, basesize,
             "More output files required...",
             &ogrp, &osize, status );

  /* Loop over continuous chunks and clean -----------------------------------*/
  gcount = 1;
  for( contchunk=0;(*status==SAI__OK)&&contchunk<ncontchunks; contchunk++ ) {
    AstKeyMap *keymap=NULL;
    int dkclean;
    AstKeyMap *sub_instruments=NULL;

    /* Place cleaning parameters into a keymap and set defaults. Do
       this inside the loop in case we are cleaning files with
       differing sub-instruments.  Note that we use the map-maker
       defaults file here (which loads the sc2clean defaults) so that
       we populate the locked keymap with all the parameters that
       people may come across to allow them to load their map-maker
       config directly into sc2clean.
    */

    sub_instruments = smf_subinst_keymap( SMF__SUBINST_NONE,
                                          NULL, igrp,
                                          igroup->subgroups[contchunk][0],
                                          status );

    keymap = kpg1Config( "CONFIG", "$SMURF_DIR/smurf_makemap.def",
                         sub_instruments, 1, status );
    if( sub_instruments ) sub_instruments = astAnnul( sub_instruments );

    /* Now rerun smf_grp_related to figure out how long each downsampled
       chunk of data will be. */

    if( basegrp ) grpDelet( &basegrp, status );
    if( igroup ) smf_close_smfGroup( &igroup, status );

    smf_grp_related( igrp, size, 1, 0, maxlen-padStart-padEnd, NULL, keymap,
                     &maxconcat, NULL, &igroup, &basegrp, NULL, status );

    /* Concatenate this continuous chunk */
    smf_concat_smfGroup( wf, NULL, igroup, usedarks ? darks:NULL, bbms, flatramps,
                         heateffmap, contchunk, ensureflat, 1, NULL, 0, NULL,
                         NULL, NO_FTS, padStart, padEnd, 0, &concat, NULL, status );

    if( *status == SAI__OK) {
      /* clean the dark squids now since we might need to use them
         to clean the bolometer data */

      smf_get_cleanpar( keymap, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                        &dkclean, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                        NULL, NULL, NULL, status );

      for( idx=0; dkclean&&(*status==SAI__OK)&&idx<concat->ndat; idx++ ) {
        odata = concat->sdata[idx];

        if( odata && odata->da && odata->da->dksquid ) {
          smfData *dksquid = odata->da->dksquid;
          AstKeyMap *kmap=NULL;

          msgOut("", TASK_NAME ": cleaning dark squids", status);

          /* fudge the header so that we can get at JCMTState */
          dksquid->hdr = odata->hdr;

          /* clean darks using cleandk.* parameters */
          astMapGet0A( keymap, "CLEANDK", &kmap );
          array = smf_create_smfArray( status );
          smf_addto_smfArray( array, dksquid, status );
          smf_clean_smfArray( wf, array, NULL, NULL, NULL, kmap, status );
          if( array ) {
            array->owndata = 0;
            smf_close_related( wf, &array, status );
          }
          if( kmap ) kmap = astAnnul( kmap );

          /* Unset hdr pointer so that we don't accidentally close it */
          dksquid->hdr = NULL;
        }
      }

      /* Then the main data arrays */
      if( *status == SAI__OK ) {
        smfArray *com = NULL;
        smfArray *gai = NULL;
        char filename[GRP__SZNAM+1];

        msgOut("", TASK_NAME ": cleaning bolometer data", status );
        smf_clean_smfArray( wf, concat, NULL, &com, &gai, keymap, status );

        /* If ADAM parameters for COM or GAI were specified, and the
           common-mode was calculated, export to files here */

        if( writecom && com ) {
          for( idx=0; (*status==SAI__OK)&&(idx<com->ndat); idx++ ) {
            smf_model_createHdr( com->sdata[idx], SMF__COM, concat->sdata[idx],
                                 status );
            smf_stripsuffix( com->sdata[idx]->file->name,
                             SMF__DIMM_SUFFIX, filename, status );

            smf_dataOrder( wf, com->sdata[idx], 1, status );

            smf_write_smfData( wf, com->sdata[idx], NULL, filename, NULL, 0,
                               NDF__NOID, MSG__NORM, 0, NULL, NULL, status );
          }
        }

        if( writegai && gai ) {
          for( idx=0; (*status==SAI__OK)&&(idx<gai->ndat); idx++ ) {
            smf_model_createHdr( gai->sdata[idx], SMF__GAI, concat->sdata[idx],
                                 status );
            smf_stripsuffix( gai->sdata[idx]->file->name,
                             SMF__DIMM_SUFFIX, filename, status );

            smf_dataOrder( wf, gai->sdata[idx], 1, status );
            smf_write_smfData( wf, gai->sdata[idx], NULL, filename, NULL, 0,
                               NDF__NOID, MSG__NORM, 0, NULL, NULL, status );
          }
        }

        /* Close com and gai */
        if( com ) smf_close_related( wf, &com, status );
        if( gai ) smf_close_related( wf, &gai, status );

      }

      /* Report statistics (currently need a smfArray for that) */
      if (*status == SAI__OK) {
        size_t last_qcount[SMF__NQBITS];
        size_t last_nmap = 0;
        smf_qualstats_report( wf, MSG__VERB, SMF__QFAM_TSERIES, 1, concat,
                              last_qcount, &last_nmap, 1, NULL, NULL, status );
      }

      /* Clean up for contchunk loop */
      if( keymap ) keymap = astAnnul( keymap );
    }

    /* Export concatenated/cleaned data for each subarray to NDF file */
    for( idx=0; (*status==SAI__OK)&&idx<concat->ndat; idx++ ) {
      odata = concat->sdata[idx];

      /* Complete the history information in the output NDF so that it
         includes group parameters accessed since the default history
         information was written to the NDF (in smf_open_and_flatfield). */
      smf_puthistory( odata, "SMURF:SC2CLEAN", status );

      /* Ensure ICD data order */
      smf_dataOrder( wf, odata, 1, status );

      if( odata->file && odata->file->name ) {
        smf_write_smfData( wf, odata, NULL, NULL, ogrp, gcount, NDF__NOID,
                           MSG__VERB, 0, NULL, NULL, status );
      } else {
        *status = SAI__ERROR;
        errRep( FUNC_NAME,
                "Unable to determine file name for concatenated data.",
                status );
      }

      /* Increment the group index counter */
      gcount++;
    }

    /* Close the smfArray */
    smf_close_related( wf, &concat, status );
  }

  /* Write out the list of output NDF names, annulling the error if a null
     parameter value is supplied. */
  if( *status == SAI__OK && ogrp ) {
    grpList( "OUTFILES", 0, 0, NULL, ogrp, status );
    if( *status == PAR__NULL ) errAnnul( status );
  }

 CLEANUP:

  /* Tidy up after ourselves: release the resources used by the grp routines */
  if( darks ) smf_close_related( wf, &darks, status );
  if( flatramps ) smf_close_related( wf, &flatramps, status );
  if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status );
  if( bbms ) smf_close_related( wf, &bbms, status );
  if( igrp ) grpDelet( &igrp, status);
  if( ogrp ) grpDelet( &ogrp, status);
  if( basegrp ) grpDelet( &basegrp, status );
  if( igroup ) smf_close_smfGroup( &igroup, status );
  fftw_cleanup();
  ndfEnd( status );
}
コード例 #28
0
ファイル: cupidgcndfclump.c プロジェクト: Starlink/starlink
void cupidGCNdfClump( HDSLoc **obj, double sum, double *par, double rms,
                    int ndim, int *lbox, int *ubox, int list_size,
                    double *mlist, int *plist, int *lbnd, int iclump,
                    int *dax, AstKeyMap *extra, int bad, int *status ){
/*
*+
*  Name:
*     cupidGCNdfClump

*  Purpose:
*     Create an NDF containing a description of a single clump.

*  Language:
*     Starlink C

*  Synopsis:
*     void cupidGCNdfClump( HDSLoc **obj, double sum, double *par, double rms,
*                         int ndim, int *lbox, int *ubox, int list_size,
*                         double *mlist, int *plist, int *lbnd, int iclump,
*                         int *dax, AstKeyMap *extra, int bad,
*                         int *status )

*  Description:
*     This function creates a temporary NDF and stores the integrated
*     intensity of the clump in its Data component. The bounds of the NDF
*     will be the smallest possible which still encompass the clump. In
*     addition, if required it will create a Cupid extension in the NDF
*     containing
*
*     - The parameters of a Gaussian approximation to the clump (if supplied).
*     - Any supplied extra information.

*  Parameters:
*     obj
*        A pointer to a locator for an HDS array of NDF objects. The array
*        will be extended to accomodate the new NDF. If NULL is supplied a
*        new temporary HDS object is created, and the locator stored at the
*        given address.
*     sum
*        The integrated intensity in the clump. Note, unlike par[0] and
*        par[1], this value should not be normalised to the RMS noise.
*     par
*        Pointer to an array holding the parameters of a Gaussian
*        approximation to the clump, or NULL. How many of these are used
*        depends on the value of "ndim": if "ndim" is 1 only elements 0 to
*        3 are used, if "ndim" is 2 only elements 0 to 6 are used, if "ndim"
*        is 3 all elements are used. All axis values are represented in GRID
*        pixels:
*
*           par[0]: Peak intensity of clump (in units of the RMS noise level).
*           par[1]: Constant intensity offset (in units of the RMS noise level).
*           par[2]: Model centre on internal axis 0 (in pixels)
*           par[3]: Intrinsic FWHM on axis 0 (in pixels)
*           par[4]: Model centre on internal axis 1 (in pixels)
*           par[5]: Intrinsic FWHM on axis 1 (in pixels)
*           par[6]: Spatial orientation angle (in radians, positive from
*                   +ve GRID1 axis to +ve GRID2 axis).
*           par[7]: Model centre on internal axis 3 (velocity) (in pixels)
*           par[8]: Intrinsic FWHM on velocity axis (in pixels)
*           par[9]: Axis 0 of internal velocity gradient vector (in velocity
*                   pixels per spatial pixel).
*           par[10]: Axis 1 of internal velocity gradient vector (in
*                   velocity pixels per spatial pixel).
*     rms
*        The RMS noise level.
*     ndim
*        The number of pixel axes in the array.
*     lbox
*        The lower grid index bounds of the area containing the clump
*        (using internal axis numbering).
*     ubox
*        The upper grid index bounds of the area containing the clump
*        (using internal axis numbering).
*     list_size
*        The number of values supplied in mlist and plist.
*     mlist
*        An array of "list_size" elements containing the clump values at
*        each pixel.
*     plist
*        An array of "ndim*list_size" elements in which each group of
*        "ndim" adjacent values forms the grid indices of the corresponding
*        value in "mlist". This uses external axis ordering.
*     lbnd
*        Pointer to array holding the pixel indices of the first pixel in
*        the user-supplied NDF (using external axis numbering).
*     iclump
*        The index of the current clump.
*     dax
*        Array holding external axis number indexed by internal axis number.
*     extra
*        An AstKeyMap holding extra diagnositic information to add to the
*        clump structure.
*     bad
*        Set the Unit component of the NDF to "BAD". This is used as a
*        flag to indicate that the clump touches too many areas of bad
*        pixels.
*     status
*        Pointer to the inherited status value.

*  Copyright:
*     Copyright (C) 2009 Science and Technology Facilities Council.
*     Copyright (C) 2005,2007 Particle Physics & Astronomy Research Council.
*     All Rights Reserved.

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

*  Authors:
*     DSB: David S. Berry
*     TIMJ: Tim Jenness (JAC, Hawaii)
*     {enter_new_authors_here}

*  History:
*     10-NOV-2005 (DSB):
*        Original version.
*     5-MAR-2007 (DSB):
*        Initiaslise "exloc" locator to NULL before calling datFind.
*     13-JAN-2009 (TIMJ):
*        DO NOT CAST int* to size_t* since that is not going to work for long.
*     26-JAN-2011 (DSB):
*        Ensure the "m" pointer is incremented even if the currrent model pixel
*        is off the edge of the NDF. Previously, this bug caused a stripey
*        "aliasing" type effect if the supplied model data extends outside the
*        bounds of the NDF.
*     25-MAY-2017 (DSB):
*        Switch off group history and provenance recording during this
*        function. This is because it can inflate the time taken to run
*        findclumps enormously if there are many thousands of clumps.
*     {enter_further_changes_here}

*  Bugs:
*     {note_any_bugs_here}

*-
*/

/* Local Variables: */

   const char *cen[] = { "CENTRE1", "CENTRE2", "CENTRE3" };
   const char *fwhm[] = { "FWHM1", "FWHM2", "FWHM3" };
   const char *vgrad[] = { "VGRAD1", "VGRAD2", "VGRAD3" };

   HDSLoc *cloc;                /* Cell locator */
   HDSLoc *dloc;                /* Component locator */
   HDSLoc *xloc;                /* Extension locator */
   HDSLoc *exloc;               /* Locator for structure holding extra info */
   const char *key;             /* KeyMap key name */
   double *ipd;                 /* Pointer to Data array */
   double *m;                   /* Pointer to next data value */
   double dval;                 /* Double value to store */
   int *p;                      /* Pointer to next grid axis value */
   int el;                      /* Number of elements mapped */
   int elb[ 3 ];                /* The lower NDF limit on each external axis */
   int elbox[ 3 ];              /* The lower box limit on each external axis */
   int estep[ 3 ];              /* The step size on each external axis */
   int eub[ 3 ];                /* The upper NDF limit on each external axis */
   int eubox[ 3 ];              /* The upper box limit on each external axis */
   int i;                       /* Point index */
   int indf;                    /* NDF identifier */
   int iv;                      /* 1D vector index for current data value */
   int j;                       /* Axis index */
   int lb[ 3 ];                 /* Lower pixel index bounds of NDF */
   int nex;                     /* No. of extra items of information */
   int ok;                      /* Pixel within clump NDF? */
   int old_ghstate;             /* Non-zero if group history recording is switched on */
   int old_pvstate;             /* Non-zero if provenance recording is switched on */
   int place;                   /* NDF place holder */
   int pv;                      /* Pixel offset */
   size_t oldsize;              /* Size of original NDF */
   hdsdim size[1];              /* No of elements in NDF array */
   int step[ 3 ];               /* The step size on each internal axis */
   int ub[ 3 ];                 /* Upper pixel index bounds of NDF */

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

/* If no array was supplied create one of length 1. */
   if( !(*obj) ) {
      size[0] = 1;
      datTemp( "NDF", 1, size, obj, status );

/* Otherwise, get the number of NDFs already in the supplied array of
   NDFs, and increase it by 1. */
   } else {
      datSize( *obj, &oldsize, status );
      size[0] = oldsize + 1;
      datAlter( *obj, 1, size, status );
   }

/* Get a locator for the new cell. */
   cloc = NULL;
   datCell( *obj, 1, size, &cloc, status );

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

/* Temporaily switch off group history and provenance recording since there
   can be thousands of clump NDFs. */
   ndgHltgh( 0, &old_ghstate, status );
   ndgHltpv( 0, &old_pvstate, status );

/* Find the pixel index bounds of the NDF and the step between adjacent
   pixels on each axis. */
   lb[ 0 ] = lbox[ 0 ] - 1 + lbnd[ dax[ 0 ] ];
   ub[ 0 ] = ubox[ 0 ] - 1 + lbnd[ dax[ 0 ] ];
   step[ 0 ] = 1;

   for( i = 1; i < ndim; i++ ) {
      lb[ i ] = lbox[ i ] - 1 + lbnd[ dax[ i ] ];
      ub[ i ] = ubox[ i ] - 1 + lbnd[ dax[ i ] ];
      step[ i ] = ( ub[ i - 1 ] - lb[ i - 1 ] + 1 )*step[ i - 1 ];
   }

/* Convert lbox, lb, ub and step from internal axis numbering to external axis
   numbering. */
   for( i = 0; i < ndim; i++ ) {
     elbox[ dax[ i ] ] = lbox[ i ];
     eubox[ dax[ i ] ] = ubox[ i ];
     elb[ dax[ i ] ] = lb[ i ];
     eub[ dax[ i ] ] = ub[ i ];
     estep[ dax[ i ] ] = step[ i ];
   }

/* Create a place holder for the new NDF within the new cell. The NDF will be
   copied to its final resting place before the program exits. */
   ndfPlace( cloc, " ", &place, status );

/* Create the NDF to receive the clump values. The size of this NDF is the
   minimum needed to contain the clump. */
   ndfNew( "_DOUBLE", ndim, elb, eub, &place, &indf, status );

/* Map the NDFs Data array, filling it with bad values. */
   ndfMap( indf, "DATA", "_DOUBLE", "WRITE/BAD", (void *) &ipd, &el, status );
   if( ipd ) {

/* Store every supplied model value in the NDF data array. */
      m = mlist;
      p = plist;
      for( i = 0; i < list_size; i++,m++ ) {

/* Find the 1D vector index into the NDF data array corresponding to the
   grid indices (within the user supplied NDF) of the current point.*/
         pv = *(p++);
         iv = pv - elbox[ 0 ];
         ok = ( pv >= elbox[ 0 ] && pv <= eubox[ 0 ] );
         for( j = 1; j < ndim; j++ ) {
            pv = *(p++);
            iv += ( pv - elbox[ j ] )*estep[ j ];
            if( pv < elbox[ j ] || pv > eubox[ j ] ) ok = 0;
         }

/* Store the value. */
         if( ok ) ipd[ iv ] = *m;
      }

/* Unmap the NDFs Data array. */
      ndfUnmap( indf, "DATA", status );
   }

/* If required, create a Cupid extension in the NDF. */
   if( par || extra ) {
      xloc = NULL;
      ndfXnew( indf, "CUPID", "CUPID_EXT", 0, NULL, &xloc, status );

/* First do Gaussian parameters. */
      if( par ) {

/* Store the integrated intensity in the clump. */
         dloc = NULL;
         datNew( xloc, "SUM", "_DOUBLE", 0, NULL, status );
         datFind( xloc, "SUM", &dloc, status );
         datPutD( dloc, 0, NULL, &sum, status );
         datAnnul( &dloc, status );

/* Store the parameters of the Gaussian approximation, taking out the
   normalisation by the RMS noise level.*/
         datNew( xloc, "PEAK", "_DOUBLE", 0, NULL, status );
         datFind( xloc, "PEAK", &dloc, status );
         dval = rms*par[ 0 ];
         datPutD( dloc, 0, NULL, &dval, status );
         datAnnul( &dloc, status );

         datNew( xloc, "OFFSET", "_DOUBLE", 0, NULL, status );
         datFind( xloc, "OFFSET", &dloc, status );
         dval = rms*par[ 1 ];
         datPutD( dloc, 0, NULL, &dval, status );
         datAnnul( &dloc, status );

         datNew( xloc, cen[ dax[ 0 ] ], "_DOUBLE", 0, NULL, status );
         datFind( xloc, cen[ dax[ 0 ] ], &dloc, status );
         dval = par[ 2 ] + lbnd[ dax[ 0 ] ] - 1.5;
         datPutD( dloc, 0, NULL, &dval, status );
         datAnnul( &dloc, status );

         datNew( xloc, fwhm[ dax[ 0 ] ], "_DOUBLE", 0, NULL, status );
         datFind( xloc, fwhm[ dax[ 0 ] ], &dloc, status );
         datPutD( dloc, 0, NULL, par + 3, status );
         datAnnul( &dloc, status );

         if( ndim > 1 ) {
            datNew( xloc, cen[ dax[ 1 ] ], "_DOUBLE", 0, NULL, status );
            datFind( xloc, cen[ dax[ 1 ] ], &dloc, status );
            dval = par[ 4 ] + lbnd[ dax[ 1 ] ] - 1.5;
            datPutD( dloc, 0, NULL, &dval, status );
            datAnnul( &dloc, status );

            datNew( xloc, fwhm[ dax[ 1 ] ], "_DOUBLE", 0, NULL, status );
            datFind( xloc, fwhm[ dax[ 1 ] ], &dloc, status );
            datPutD( dloc, 0, NULL, par + 5, status );
            datAnnul( &dloc, status );

            datNew( xloc, "ANGLE", "_DOUBLE", 0, NULL, status );
            datFind( xloc, "ANGLE", &dloc, status );
            dval = par[ 6 ]*AST__DR2D;
            datPutD( dloc, 0, NULL,  &dval, status );
            datAnnul( &dloc, status );

            if( ndim > 2 ) {

               datNew( xloc, cen[ dax[ 2 ] ], "_DOUBLE", 0, NULL, status );
               datFind( xloc, cen[ dax[ 2 ] ], &dloc, status );
               dval = par[ 7 ] + lbnd[ dax[ 2 ] ] - 1.5;
               datPutD( dloc, 0, NULL, &dval, status );
               datAnnul( &dloc, status );

               datNew( xloc, fwhm[ dax[ 2 ] ], "_DOUBLE", 0, NULL, status );
               datFind( xloc, fwhm[ dax[ 2 ] ], &dloc, status );
               datPutD( dloc, 0, NULL, par + 8, status );
               datAnnul( &dloc, status );

               datNew( xloc, vgrad[ dax[ 0 ] ], "_DOUBLE", 0, NULL, status );
               datFind( xloc, vgrad[ dax[ 0 ] ], &dloc, status );
               datPutD( dloc, 0, NULL, par + 9, status );
               datAnnul( &dloc, status );

               datNew( xloc, vgrad[ dax[ 1 ] ], "_DOUBLE", 0, NULL, status );
               datFind( xloc, vgrad[ dax[ 1 ] ], &dloc, status );
               datPutD( dloc, 0, NULL, par + 10, status );
               datAnnul( &dloc, status );

            }
         }
      }

/* Now store any extra diagnostic information. */
      if( extra ) {
         datNew( xloc, "EXTRA", "EXTRA", 0, NULL, status );
         exloc = NULL;
         datFind( xloc, "EXTRA", &exloc, status );

         nex = astMapSize( extra );
         for( i = 0; i < nex; i++ ) {
            key = astMapKey( extra, i );
            if( astMapGet0D( extra, key, &dval ) ) {
               datNew( exloc, key, "_DOUBLE", 0, NULL, status );
               datFind( exloc, key, &dloc, status );
               datPutD( dloc, 0, NULL, &dval, status );
               datAnnul( &dloc, status );
            }
         }

         datAnnul( &exloc, status );

      }

/* Release the extension locator. */
      datAnnul( &xloc, status );
   }

/* If required set the Unit component to "BAD". */
   if( bad ) ndfCput( "BAD", indf, "Unit", status );

/* Switch group history and provenance recording back to their original
   states. */
   ndgHltgh( old_ghstate, NULL, status );
   ndgHltpv( old_pvstate, NULL, status );

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

/* Release the cell locator. */
   datAnnul( &cloc, status );

}
コード例 #29
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();
}
コード例 #30
0
ファイル: smf_subip.c プロジェクト: edwardchapin/starlink
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 );
   }
}