void smf_rebincube_spectab( dim_t nchan, dim_t nchanout, AstMapping *ssmap,
                            int **pspectab, int *status ){

/* Local Variables */
   double *w1 = NULL;          /* Work space */
   double *w2 = NULL;          /* Work space */
   int *spectab = NULL;        /* Returned pointer */
   dim_t ichan;                /* Index of current channel */

/* Initialise */
   *pspectab = NULL;

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

/* Allocate memory for the returned array of integer channel numbers. */
   spectab = (int *) astMalloc( sizeof( int )*nchan );

/* Allocate memory for work arrays holding floating point spectral GRID
   values. */
   w1 = (double *) astMalloc( sizeof( double )*nchan );
   w2 = (double *) astMalloc( sizeof( double )*nchan );

/* Store the GID axis value at the centre of each input spectral channel. */
   for( ichan = 0; ichan < nchan; ichan++ ) w1[ ichan ] = ichan + 1.0;

/* Use the supplied mapping to get the corresponding output spectral GRID
   values. */
   astTran1( ssmap, nchan, w1, 1, w2 );

/* Find the zero based index of the output channel containing each of
   these transformed values. Store -1 for any points that cannot be
   transformed or which are outside the spectral bounds of the outptu cube. */
   for( ichan = 0; ichan < nchan; ichan++ ) {
      if( w2[ ichan ] != AST__BAD ) {
         spectab[ ichan ] = floor( w2[ ichan ] + 0.5 ) - 1;
         if( spectab[ ichan ] < 0 || spectab[ ichan ] >= nchanout ) {
            spectab[ ichan ] = -1;
         }
      } else {
         spectab[ ichan ] = -1;
      }
   }

/* Free the work arrays. */
   w1 = astFree( w1 );
   w2 = astFree( w2 );

/* Return the array of output integer channel numbers. */
   if( *status == SAI__OK ) {
      *pspectab = spectab;
   } else {
      spectab = astFree( spectab );
   }
}
示例#2
0
文件: ndf.c 项目: timj/starlink-pyndf
static PyObject*
pyndf_gtwcs(NDF *self)
{
    AstFrameSet *wcs = NULL;
    char *string;
    PyObject *pywcs;
    PyObject *result = NULL;

    int status = SAI__OK;

#if HAVE_AST
    errBegin(&status);
    astBegin;
    ndfGtwcs(self->_ndfid, &wcs, &status );
    if( wcs ) {
        string = astToString( wcs );
        wcs = astAnnul( wcs );
        pywcs = PyAst_FromString( string );
        string = astFree( string );
        if( pywcs ) result = Py_BuildValue("O",pywcs);
        Py_XDECREF(pywcs);
    }
    astEnd;
    if (raiseNDFException(&status)) return NULL;
#else
    PyErr_SetString( PyExc_NotImplementedError,
                     "starlink.Ast must be available for WCS to be retrieved from an NDF");
#endif
    return result;
};
示例#3
0
smfDream *smf_create_smfDream( int * status ) {

  /* Need to make sure that any memory we malloc will be freed on error
     so make sure we NULL all pointers first. */
  smfDream *dream = NULL;      /* smfDream struct to fill */
  size_t i;                    /* Loop counter */

  if (*status != SAI__OK) return NULL;

  /* Create an empty smfDream  */
  dream = astMalloc( 1*sizeof(smfDream) );
  if (*status != SAI__OK) {
    /* Add our own message to the stack */
    errRep(FUNC_NAME, "Unable to allocate memory for smfDream structure",
	   status);
    goto CLEANUP;
  }

  /* Integers */
  dream->nvert = 0;
  dream->ngrid = 0;
  dream->ncycles = 0;
  dream->nsampcycle = 0;
  for ( i = 0; i < DREAM__MXVERT; i++ ) {
    (dream->jigvert)[i][0] = 0;
    (dream->jigvert)[i][1] = 0;
  }
  for ( i = 0; i < DREAM__MXGRID; i++ ) {
    (dream->gridpts)[i][0] = 0;
    (dream->gridpts)[i][1] = 0;
  }

  /* Pointers to the grid weights and inverse matrix */
  dream->gridwts = NULL;
  dream->invmatx = NULL;

  /* Doubles */
  dream->jigscal = 0.0;
  dream->gridstep = 0.0;
  for ( i = 0; i < DREAM__MXSAM; i++ ) {
    (dream->jigpath)[i][0] = 0.0;
    (dream->jigpath)[i][1] = 0.0;
  }

  return dream;

 CLEANUP:
  dream = astFree( dream );
  return NULL;
}
示例#4
0
void starFree( void * ptr ) {
#if USE_AST_MALLOC
  int ast_status = 0;
  int *old_ast_status = NULL;
#endif

#if STARMEM_DEBUG
  if (STARMEM_PRINT_MALLOC)
    printf(__FILE__": Free pointer %p\n", ptr );
#endif

  switch ( STARMEM_MALLOC ) {

  case STARMEM__SYSTEM:
    free( ptr );
    break;

  case STARMEM__AST:
#if USE_AST_MALLOC
    old_ast_status = astWatch( &ast_status );
    astFree( ptr );
    astWatch( old_ast_status );
#else
    starMemFatalAST;
#endif
    break;

  case STARMEM__DL:
    dlfree( ptr );
    break;

  case STARMEM__GC:
    /* Nothing to do if garbage collector selected */
    break;

  default:
    starMemFatalNone;
  }

  return;
}
示例#5
0
/* Main entry point. */
void smf_calcmodel_smo( ThrWorkForce *wf, smfDIMMData *dat, int chunk,
                        AstKeyMap *keymap, smfArray **allmodel,
                        int flags __attribute__((unused)),
                        int *status) {

  /* Local Variables */
  size_t bstride;               /* bolo stride */
  dim_t boxcar = 0;             /* size of boxcar smooth window */
  smf_filt_t filter_type;       /* The type of smoothing to perform */
  size_t i;                     /* Loop counter */
  dim_t idx=0;                  /* Index within subgroup */
  int iworker;                  /* Owkrer index */
  smfCalcmodelSmoJobData *job_data=NULL; /* Pointer to all job data structures */
  AstKeyMap *kmap=NULL;         /* Pointer to PLN-specific keys */
  smfArray *model=NULL;         /* Pointer to model at chunk */
  double *model_data=NULL;      /* Pointer to DATA component of model */
  double *model_data_copy=NULL; /* Copy of model_data for one bolo */
  dim_t nbolo=0;                /* Number of bolometers */
  dim_t ndata=0;                /* Total number of data points */
  int notfirst=0;               /* flag for delaying until after 1st iter */
  dim_t ntslice=0;              /* Number of time slices */
  int nworker;                  /* No. of worker threads in supplied Workforce */
  smfCalcmodelSmoJobData *pdata=NULL; /* Pointer to current data structure */
  smfArray *qua=NULL;           /* Pointer to QUA at chunk */
  smf_qual_t *qua_data=NULL; /* Pointer to quality data */
  smfArray *res=NULL;           /* Pointer to RES at chunk */
  double *res_data=NULL;        /* Pointer to DATA component of res */
  int step;                     /* Number of bolometers per thread */
  size_t tstride;               /* Time slice stride in data array */
  const char * typestr = NULL;  /* smo.type value */

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

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

  /* Obtain pointer to sub-keymap containing PLN parameters. Something will
     always be available.*/
  astMapGet0A( keymap, "SMO", &kmap );

  /* Are we skipping the first iteration? */
  astMapGet0I(kmap, "NOTFIRST", &notfirst);

  if( notfirst && (flags & SMF__DIMM_FIRSTITER) ) {
    msgOutif( MSG__VERB, "", FUNC_NAME
              ": skipping SMO this iteration", status );
    return;
  }

  /* Get the boxcar size */
  if( kmap ) smf_get_nsamp( kmap, "BOXCAR", res->sdata[0], &boxcar, status );

  /* Get the type of smoothing filter to use. Anthing that is not "MEDIAN" is mean */
  filter_type = SMF__FILT_MEAN;
  if (astMapGet0C( kmap, "TYPE", &typestr ) ) {
    if (strncasecmp( typestr, "MED", 3 ) == 0 ) {
      filter_type = SMF__FILT_MEDIAN;
    }
  }

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

  smf_get_dims( res->sdata[0],  NULL, NULL, NULL, &ntslice,
                &ndata, NULL, NULL, status);

  model = allmodel[chunk];

  msgOutiff(MSG__VERB, "",
            "    Calculating smoothed model using boxcar of width %" DIM_T_FMT " time slices",
            status, boxcar);

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

  /* Loop over index in subgrp (subarray) and put the previous iteration
     of the filtered component back into the residual before calculating
     and removing the new filtered component */
  for( idx=0; (*status==SAI__OK)&&(idx<res->ndat); idx++ ) {
    /* Obtain dimensions of the data */

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

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

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

      /* Uncomment to aid debugging */
      /*
      smf_write_smfData( res->sdata[idx], NULL, qua_data, "res_in",
                         NULL, 0, 0, MSG__VERB, 0, status );
      */

      if( *status == SAI__OK ) {
        /* Place last iteration back into residual if this is a smoothable section of the time series */
        for (i=0; i< ndata; i++) {
          if ( !(qua_data[i]&SMF__Q_FIT)  && res_data[i] != VAL__BADD && model_data[i] != VAL__BADD ) {
            res_data[i] += model_data[i];
          }
        }
      }

      /* Uncomment to aid debugging */
      /*
      smf_write_smfData( model->sdata[idx], NULL, qua_data, "model_b4",
                         NULL, 0, 0, MSG__VERB, 0, status );

      smf_write_smfData( res->sdata[idx], NULL, qua_data, "res_b4",
                         NULL, 0, 0, MSG__VERB, 0, status );
      */

      /* Determine which bolometers are to be processed by which threads. */
      step = nbolo/nworker;
      if( step < 1 ) step = 1;

      for( iworker = 0; iworker < nworker; iworker++ ) {
        pdata = job_data + iworker;
        pdata->b1 = iworker*step;
        pdata->b2 = pdata->b1 + step - 1;
      }

      /* Ensure that the last thread picks up any left-over bolometers */
      pdata->b2 = nbolo - 1;

      /* Store all the other info needed by the worker threads, and submit the
         jobs to apply the smoothing. */
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;

         pdata->boxcar = boxcar;
         pdata->bstride = bstride;
         pdata->bstride = bstride;
         pdata->filter_type = filter_type;
         pdata->model_data = model_data;
         pdata->nbolo = nbolo;
         pdata->nbolo = nbolo;
         pdata->ntslice = ntslice;
         pdata->ntslice = ntslice;
         pdata->qua_data = qua_data;
         pdata->qua_data = qua_data;
         pdata->res_data = res_data;
         pdata->res_data = res_data;
         pdata->tstride = tstride;
         pdata->tstride = tstride;

         thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calcmodel_smo_job,
                      0, NULL, status );
      }
      thrWait( wf, status );

      /* Uncomment to aid debugging */
      /*
      smf_write_smfData( res->sdata[idx], NULL, qua_data, "res_af",
                         NULL, 0, 0, MSG__VERB, 0, status );
      smf_write_smfData( model->sdata[idx], NULL, qua_data, "model_af",
                         NULL, 0, 0, MSG__VERB, 0, status );
      */

    }
  }

  /* Free work space (astFree returns without action if a NULL pointer is
     supplied). */
  model_data_copy = astFree( model_data_copy );
  job_data = astFree( job_data );

  /* Annul AST Object pointers (astAnnul reports an error if a NULL pointer
     is supplied). */
  if( kmap ) kmap = astAnnul( kmap );
}
示例#6
0
void atlKy2hd( AstKeyMap *keymap, HDSLoc *loc, int *status ) {
    /*
    *  Name:
    *     atlKy2hd

    *  Purpose:
    *     Copies values from an AST KeyMap to a primitive HDS object.

    *  Language:
    *     C.

    *  Invocation:
    *     void atlKy2hd( AstKeyMap *keymap, HDSLoc *loc, int *status )

    *  Description:
    *     This routine copies the contents of an AST KeyMap into a supplied
    *     HDS structure.

    *  Arguments:
    *     keymap
    *        An AST pointer to the KeyMap.
    *     loc
    *        A locator for the HDS object into which the KeyMap contents
    *        are to be copied. A new component is added to the HDS object for
    *        each entry in the KeyMap.
    *     status
    *        The inherited status.

    *  Copyright:
    *     Copyright (C) 2008, 2010, 2012 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
    *     TIMJ: Tim Jenness (JAC, Hawaii)
    *     {enter_new_authors_here}

    *  History:
    *     29-APR-2008 (DSB):
    *        Original version.
    *     2010-09-23 (TIMJ):
    *        Fix arrays of strings.
    *     2010-09-30 (TIMJ):
    *        Make sure that we are using the correct status pointer in AST.
    *     2010-10-01 (TIMJ):
    *        Sort the keys when writing to HDS structured.
    *     2010-10-04 (TIMJ):
    *        Support Short ints in keymap
    *     14-SEP-2012 (DSB):
    *        Moved from kaplibs to atl.
    *     17-SEP-2012 (DSB):
    *        Add support for undefined values.
    *     {enter_further_changes_here}

    *  Bugs:
    *     {note_any_bugs_here}
    */

    /* Local Varianles: */
    AstObject **objArray = NULL;
    AstObject *obj = NULL;
    HDSLoc *cloc = NULL;
    HDSLoc *dloc = NULL;
    const char *cval = NULL;
    const char *key;
    double dval;
    float fval;
    int i;
    int ival;
    int j;
    int lenc;
    int nval;
    char *oldsortby;
    int *oldstat = NULL;
    int size;
    int type;
    int veclen;
    size_t el;
    void *pntr = NULL;

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

    /* Make sure that we are checking AST status */
    oldstat = astWatch( status );

    /* If set, save the old SortBy value and then ensure alphabetical sorting.
       We need to take a copy of the original string since the buffer in which
       the string is stored may be re-used by subsequent incocations of astGetC.  */
    if( astTest( keymap, "SortBy" ) ) {
        int nc = 0;
        oldsortby = astAppendString( NULL, &nc, astGetC( keymap, "SortBy" ) );
    } else {
        oldsortby = NULL;
    }
    astSet( keymap, "SortBy=KeyUp" );

    /* Loop round each entry in the KeyMap. */
    size = astMapSize( keymap );
    for( i = 0; i < size; i++ ) {

        if (*status != SAI__OK) break;

        /* Get the key. the data type and the vector length for the current
           KeyMap entry. */
        key = astMapKey( keymap, i );
        type = astMapType( keymap, key );
        veclen = astMapLength( keymap, key );

        /* If the current entry holds one or more nested KeyMaps, then we call
           this function recursively to add them into a new HDS component. */
        if( type == AST__OBJECTTYPE ) {

            /* First deal with scalar entries holding a single KeyMap. */
            if( veclen == 1 ) {
                datNew( loc, key, "KEYMAP_ENTRY", 0, NULL, status );
                datFind( loc, key, &cloc, status );

                (void) astMapGet0A( keymap, key, &obj );

                if( astIsAKeyMap( obj ) ) {
                    atlKy2hd( (AstKeyMap *) obj, cloc, status );

                } else if( *status == SAI__OK ) {
                    *status = SAI__ERROR;
                    errRep( "", "atlKy2hd: Supplied KeyMap contains unusable AST "
                            "objects (programming error).", status );
                }

                datAnnul( &cloc, status );

                /* Now deal with vector entries holding multiple KeyMaps. */
            } else {
                datNew( loc, key, "KEYMAP_ENTRY", 1, &veclen, status );
                datFind( loc, key, &cloc, status );

                objArray = astMalloc( sizeof( AstObject *) * (size_t)veclen );
                if( objArray ) {
                    (void) astMapGet1A( keymap, key, veclen, &nval, objArray );

                    for( j = 1; j <= veclen; j++ ) {
                        datCell( cloc, 1, &j, &dloc, status );

                        if( astIsAKeyMap( objArray[ j - 1 ] ) ) {
                            atlKy2hd( (AstKeyMap *) objArray[ j - 1 ], dloc, status );

                        } else if( *status == SAI__OK ) {
                            *status = SAI__ERROR;
                            errRep( "", "atlKy2hd: Supplied KeyMap contains unusable AST "
                                    "objects (programming error).", status );
                        }

                        datAnnul( &dloc, status );
                    }

                    objArray = astFree( objArray );
                }

                datAnnul( &cloc, status );
            }

            /* For primitive types... */
        } else if( type == AST__INTTYPE ) {
            if( veclen == 1 ) {
                datNew0I( loc, key, status );
                datFind( loc, key, &cloc, status );
                (void) astMapGet0I( keymap, key, &ival );
                datPut0I( cloc, ival, status );
                datAnnul( &cloc, status );

            } else {
                datNew1I( loc, key, veclen, status );
                datFind( loc, key, &cloc, status );
                datMapV( cloc, "_INTEGER", "WRITE", &pntr, &el, status );
                (void) astMapGet1I( keymap, key, veclen, &nval, (int *) pntr );
                datUnmap( cloc, status );
                datAnnul( &cloc, status );
            }

        } else if( type == AST__SINTTYPE ) {
            short sval = 0;
            if( veclen == 1 ) {
                datNew0W( loc, key, status );
                datFind( loc, key, &cloc, status );
                (void) astMapGet0S( keymap, key, &sval );
                datPut0W( cloc, sval, status );
                datAnnul( &cloc, status );

            } else {
                datNew1W( loc, key, veclen, status );
                datFind( loc, key, &cloc, status );
                datMapV( cloc, "_WORD", "WRITE", &pntr, &el, status );
                (void) astMapGet1S( keymap, key, veclen, &nval, (short *) pntr );
                datUnmap( cloc, status );
                datAnnul( &cloc, status );
            }

        } else if( type == AST__DOUBLETYPE ) {
            if( veclen == 1 ) {
                datNew0D( loc, key, status );
                datFind( loc, key, &cloc, status );
                (void) astMapGet0D( keymap, key, &dval );
                datPut0D( cloc, dval, status );
                datAnnul( &cloc, status );

            } else {
                datNew1D( loc, key, veclen, status );
                datFind( loc, key, &cloc, status );
                datMapV( cloc, "_DOUBLE", "WRITE", &pntr, &el, status );
                (void) astMapGet1D( keymap, key, veclen, &nval, (double *) pntr );
                datUnmap( cloc, status );
                datAnnul( &cloc, status );
            }

        } else if( type == AST__FLOATTYPE ) {
            if( veclen == 1 ) {
                datNew0R( loc, key, status );
                datFind( loc, key, &cloc, status );
                (void) astMapGet0F( keymap, key, &fval );
                datPut0R( cloc, fval, status );
                datAnnul( &cloc, status );

            } else {
                datNew1R( loc, key, veclen, status );
                datFind( loc, key, &cloc, status );
                datMapV( cloc, "_REAL", "WRITE", &pntr, &el, status );
                (void) astMapGet1F( keymap, key, veclen, &nval, (float *) pntr );
                datUnmap( cloc, status );
                datAnnul( &cloc, status );
            }

        } else if( type == AST__STRINGTYPE ) {
            lenc = astMapLenC( keymap, key );

            if( veclen == 1 ) {
                datNew0C( loc, key, lenc, status );
                datFind( loc, key, &cloc, status );
                (void) astMapGet0C( keymap, key, &cval );
                datPut0C( cloc, cval, status );
                datAnnul( &cloc, status );

            } else {
                datNew1C( loc, key, lenc, veclen, status );
                datFind( loc, key, &cloc, status );
                datMapV( cloc, "_CHAR", "WRITE", &pntr, &el, status );
                (void) atlMapGet1C( keymap, key, veclen*lenc, lenc, &nval,
                                    (char *) pntr, status );
                datUnmap( cloc, status );
                datAnnul( &cloc, status );
            }

            /* KeyMap "UNDEF" values are always scalar and have no corresponding HDS
               data type. So arbitrarily use an "_INTEGER" primitive with no defined
               value to represent a KeyMap UNDEF value. */
        } else if( type == AST__UNDEFTYPE ) {
            datNew0L( loc, key, status );

            /* Unknown or unsupported data types. */
        } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            msgSeti( "T", type );
            errRep( "", "atlKy2hd: Supplied KeyMap contains entries with "
                    "unusable data type (^T) (programming error).", status );
        }
    }

    /* If it was originally set, re-instate the old SortBy value in the KeyMap,
       then free the memory. Otherwise, clear the SortBy attribute. */
    if( oldsortby ) {
        astSetC( keymap, "SortBy", oldsortby );
        oldsortby = astFree( oldsortby );
    } else {
        astClear( keymap, "SortBy" );
    }

    /* Reset AST status */
    astWatch( oldstat );

}
示例#7
0
void smf_mask_noisy( ThrWorkForce *wf, smfData *data, smfData **noise,
                     double sigcliphigh, double sigcliplow, int cliplog,
                     int zeropad, int * status ) {

  size_t i;
  dim_t nbolo = 0;             /* Number of bolometers */
  double *noisedata = NULL;    /* Pointer to the noise data array */
  smfData * noisemap = NULL;   /* Somewhere to receive the result */
  double *work = NULL;         /* Temporary work array */

  if (*status != SAI__OK) return;

  if( (sigcliphigh <= 0.0) && (sigcliplow <= 0.0) ) return;

  /* Work out how many bolometers we have */
  smf_get_dims( data, NULL, NULL, &nbolo, NULL, NULL,
                NULL, NULL, status );

  /* Create some space for the result */
  smf_create_bolfile( wf, NULL, 1, data, "Noise", "blahs s**0.5",
                      SMF__MAP_VAR, &noisemap, status );
  if (noisemap) noisedata = (noisemap->pntr)[0];

  /* Calculate the noise on each bolometer */
  smf_bolonoise( wf, data, -1.0, 0, 0.5, SMF__F_WHITELO,
                 SMF__F_WHITEHI, 0, zeropad ? SMF__MAXAPLEN : SMF__BADSZT,
                 (noisemap->pntr)[0], NULL, NULL, status );

  /* Now need to convert this to noise by square rooting */
  if (*status == SAI__OK) {
    for (i=0; i<nbolo; i++) {
      if (noisedata[i] != VAL__BADD) {
        noisedata[i] = sqrt( noisedata[i] );
      }
    }
  }

  /* Now create a mask and then mask the quality. We only mask bolometers
     that are too noisy. We also do not mask bolometers that were already
     masked. We want the statistics to reflect what we actually masked
     and not any previous masking. This will miss any bolometers masked
     out by smf_bolonoise because they had zero power. */

  msgOutif( MSG__VERB, "", FUNC_NAME
            ": Checking for bolometers with outlier noise values. ", status );

  msgOutiff( MSG__VERB, "", FUNC_NAME
             ": Units are (%s s**0.5): ", status, data->hdr->units );

  work = astCalloc( nbolo, sizeof(*work) );

  if( *status == SAI__OK ) memcpy( work, noisedata, nbolo*sizeof(*work) );

  smf_clipnoise( noisedata, nbolo, cliplog, sigcliplow, sigcliphigh, NULL,
                 status );

  /* The only bad values that should appear in noisedata are new bolometers
     that were clipped by smf_clipnoise, not bolometers that were bad before
     for other reasons. */
  if( *status == SAI__OK ) {
    for( i=0; i<nbolo; i++ ) {
      if( (noisedata[i]==VAL__BADD) && (work[i] == VAL__BADD) ) {
        noisedata[i] = 0;
      }
    }
  }

  if( work ) work = astFree( work );

  /* The mask has to be inside a smfArray */
  if (*status == SAI__OK) {
    smfArray *masks = smf_create_smfArray( status );
    if (masks) masks->owndata = 0;  /* someone else owns the smfData */
    smf_addto_smfArray( masks, noisemap, status );
    smf_apply_mask( wf, data, masks, SMF__BBM_QUAL, SMF__Q_NOISE,
                    status );
    smf_close_related( wf, &masks, status );
  }

  /* Give noisemap back to caller if requested, or close it */
  if( noise ) {
    *noise = noisemap;
  } else {
    smf_close_file( wf, &noisemap, status );
  }
}
示例#8
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();
}
示例#9
0
int *smf_jsatiles_data( Grp *igrp, size_t size, int *ntile, int *status ){

/* Local Variables */
   AstFrame *frm = NULL;
   AstFrameSet *fs;
   JCMTState *state;
   const char *trsys;
   const char *trsys_last;
   dim_t *hits = NULL;
   dim_t *ph;
   dim_t iframe;
   double *gx = NULL;
   double *gy = NULL;
   double *p1;
   double *p2;
   double *px;
   double *py;
   double *trac1 = NULL;
   double *trac2 = NULL;
   double fov;
   double point1[ 2 ];
   double point2[ 2 ];
   double search;
   int *tiles = NULL;
   int dim[ 2 ];
   int i;
   int ix;
   int iy;
   int lbnd[ 2 ];
   int ubnd[ 2 ];
   size_t ifile;
   smfData *data = NULL;
   smfHead *hdr = NULL;
   smfJSATiling skytiling;
   smf_inst_t inst = SMF__INST_NONE;
   smf_inst_t instrument;
   smf_subinst_t subinst;

/* Initialise */
   *ntile = 0;

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

/* Start an AST context so that all AST objects created in this function
   are annulled automatically. */
   astBegin;

/* Loop round all the input NDFs. */
   trsys_last = "";
   for( ifile = 1; ifile <= size && *status == SAI__OK; ifile++ ) {

/* Obtain information about the current input NDF. */
      smf_open_file( igrp, ifile, "READ", SMF__NOCREATE_DATA, &data,
                     status );

/* Get a pointer to the header. */
      hdr = data->hdr;

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

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

      } else if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         smf_smfFile_msg( data->file, "FILE", 1, "<unknown>" );
         errRep( "", "No tiles are yet defined for the instrument that "
                 "created ^FILE.", status );
      }

/* If this is the first file, it defines the instrument in use. */
      if( ifile == 1 ) {
         instrument = inst;

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

/* Create a FrameSet describing the whole sky in which each pixel
   corresponds to a single tile. The current Frame is ICRS (RA,Dec) and
   the base Frame is grid coords in which each grid pixel corresponds to
   a single tile. */
         smf_jsatile( 0, &skytiling, 0, NULL, &fs, NULL, lbnd, ubnd, status );

/* Allocate an image with one pixel for each tile, and fill it with
   zeros. */
         dim[ 0 ] = ubnd[ 0 ] - lbnd[ 0 ] + 1;
         dim[ 1 ] = ubnd[ 1 ] - lbnd[ 1 ] + 1;
         hits = astCalloc( dim[0]*dim[1], sizeof( *hits ) );

/* Get the radius of the field of view in radians. */
         fov = 0.5*(skytiling.fov*AST__DD2R)/3600.0;

/* If this is not the first file, report an error if the instrument has
   changed... */
      } else if( instrument != inst && *status == SAI__OK ) {
         smf_smfFile_msg( data->file, "FILE", 1, "<unknown>" );
         errRep( "", "The file ^FILE was created by a different instrument "
                 "to the previous files.", status );
      }

/* Re-map the current Frame of the hits map WCS FrameSet to be the tracking
   system used by the current file (if it has changed). */
      trsys = sc2ast_convert_system( (hdr->allState)[0].tcs_tr_sys,
                                      status );
      if( *status == SAI__OK && strcmp( trsys, trsys_last ) ) {
         astSetC( fs, "System", trsys );
         trsys_last = trsys;
         frm = astGetFrame( fs, AST__CURRENT );
      }

/* Get the radius of the search circle. */
      search = fov + sqrt( hdr->instap[ 0 ]*hdr->instap[ 0 ] +
                           hdr->instap[ 1 ]*hdr->instap[ 1 ] );

/* Ensure our work arrays are big enough to hold the current file. */
      trac1 = astGrow( trac1, 4*hdr->nframes, sizeof( *trac1 ) );
      trac2 = astGrow( trac2, 4*hdr->nframes, sizeof( *trac2 ) );
      gx = astGrow( gx, 4*hdr->nframes, sizeof( *gx ) );
      gy = astGrow( gy, 4*hdr->nframes, sizeof( *gy ) );

/* Check pointers can be used safely. */
      if( *status == SAI__OK ) {

/* Loop round all time slices, getting the tracking coords at the corners
   of a box that enclose the field of view. */
         p1 = trac1;
         p2 = trac2;
         state = hdr->allState;
         for( iframe = 0; iframe < hdr->nframes; iframe++,state++ ) {
            point1[ 0 ] = state->tcs_tr_ac1;
            point1[ 1 ] = state->tcs_tr_ac2;
            for( i = 0; i < 4; i++ ) {
               astOffset2( frm, point1, i*AST__DPIBY2, search, point2 );
               *(p1++) = point2[ 0 ];
               *(p2++) = point2[ 1 ];
            }
         }

/* Convert them to grid coords in the hits map. */
         astTran2( fs, 4*hdr->nframes, trac1, trac2, 0, gx, gy );

/* Loop round them all again. Update the hits map to indicate how many
   points fall in each tile. */
         px = gx;
         py = gy;
         for( iframe = 0; iframe < 4*hdr->nframes; iframe++,px++,py++ ) {
            ix = (int)( *px + 0.5 ) - 1;
            iy = (int)( *py + 0.5 ) - 1;
            hits[ ix + iy*dim[ 0 ] ]++;
         }
      }

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

/* Form a list of all the tiles that receive any data. */
   ph = hits;
   for( iy = 0; iy < dim[ 1 ]; iy++ ) {
      for( ix = 0; ix < dim[ 0 ]; ix++,ph++ ) {
         if( *ph > 0 ) {
            tiles = astGrow( tiles, ++(*ntile), sizeof( *tiles ) );
            if( *status == SAI__OK ) {
               tiles[ *ntile - 1 ] = smf_jsatilexy2i( ix, iy, &skytiling,
                                                      status );
            }
         }
      }
   }

/* Free resources. */
   hits = astFree( hits );
   trac1 = astFree( trac1 );
   trac2 = astFree( trac2 );
   gx = astFree( gx );
   gy = astFree( gy );

   if( *status != SAI__OK ) {
      tiles = astFree( tiles );
      *ntile = 0;
   }

   astEnd;

   return tiles;
}
示例#10
0
unsigned char *smf_get_mask( ThrWorkForce *wf, smf_modeltype mtype,
                             AstKeyMap *config, smfDIMMData *dat, int flags,
                             int *status ) {

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

/* Initialise returned values */
   result = NULL;

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

/* Begin an AST context. */
   astBegin;

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

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

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

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

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

         isstatic = 1;
         nmask = 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* Return the pointer to the boolean mask. */
   return result;
}
示例#11
0
void smf_calcmodel_noi( ThrWorkForce *wf, smfDIMMData *dat, int chunk,
                        AstKeyMap *keymap, smfArray **allmodel, int flags,
                        int *status) {

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

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

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

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

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

  /* Obtain parameters for NOI */

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

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

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

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

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

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

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

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

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

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

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

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

          if (var) {

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

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

            var = astFree( var );
          }


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            var = astFree( var );
          }

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

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

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

      }

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

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

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

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

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

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

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

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

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

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

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

  /* Clean Up */
  if( kmap ) kmap = astAnnul( kmap );
}
示例#12
0
void smf_resampcube_nn( smfData *data, dim_t nchan,
                        dim_t ndet, dim_t nslice, dim_t nxy,
                        dim_t dim[3], AstMapping *ssmap,
                        AstSkyFrame *abskyfrm, AstMapping *iskymap,
                        Grp *detgrp, int moving, float *in_data,
                        float *out_data, int *overlap, int *status ){

/* Local Variables */
   AstMapping *totmap = NULL;  /* WCS->GRID Mapping from template WCS FrameSet */
   const char *name = NULL;    /* Pointer to current detector name */
   dim_t timeslice_size;       /* No of detector values in one time slice */
   double *detxtemplt = NULL;  /* Work space for template X grid coords */
   double *detxskycube = NULL; /* Work space for sky cube X grid coords */
   double *detytemplt = NULL;  /* Work space for template Y grid coords */
   double *detyskycube = NULL; /* Work space for sky cube Y grid coords */
   float *ddata = NULL;        /* Pointer to start of output detector data */
   float *tdata = NULL;        /* Pointer to start of sky cube time slice data */
   int *spectab = NULL;        /* Template->sky cube channel number conversion table */
   int found;                  /* Was current detector name found in detgrp? */
   dim_t gxsky;                /* Sky cube X grid index */
   dim_t gysky;                /* Sky cube Y grid index */
   dim_t idet;                 /* Detector index */
   dim_t itime;                /* Index of current time slice */
   int iv0;                    /* Offset for pixel in 1st sky cube spectral channel */
   smfHead *hdr = NULL;        /* Pointer to data header for this time slice */

/* Initialise */
   *overlap = 0;

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

/* Store a pointer to the template NDFs smfHead structure. */
   hdr = data->hdr;

/* Store the number of pixels in one time slice */
   timeslice_size = ndet*nchan;

/* Use the supplied mapping to get the zero-based sky cube channel number
   corresponding to each template channel number. */
   smf_rebincube_spectab( nchan, dim[ 2 ], ssmap, &spectab, status );
   if( !spectab ) goto L999;

/* Allocate work arrays to hold the template and sky cube grid coords for each
   detector. */
   detxtemplt = astMalloc( ndet*sizeof( double ) );
   detytemplt = astMalloc( ndet*sizeof( double ) );
   detxskycube = astMalloc( ndet*sizeof( double ) );
   detyskycube = astMalloc( ndet*sizeof( double ) );

/* Initialise a string to point to the name of the first detector for which
   data is to be created. */
   name = hdr->detname;

/* Fill the arrays with the grid coords of each detector. */
   for( idet = 0; idet < ndet; idet++ ) {
      detxtemplt[ idet ] = (double) idet + 1.0;
      detytemplt[ idet ] = 1.0;

/* If a group of detectors to be used was supplied, search the group for
   the name of the current detector. If not found, set the GRID coord
   bad. */
      if( detgrp ) {
         found = grpIndex( name, detgrp, 1, status );
         if( !found ) {
            detxtemplt[ idet ] = AST__BAD;
            detytemplt[ idet ] = AST__BAD;
         }
      }

/* Move on to the next available detector name. */
      name += strlen( name ) + 1;
   }

/* Loop round all time slices in the template NDF. */
   for( itime = 0; itime < nslice && *status == SAI__OK; itime++ ) {

/* Store a pointer to the first output data value in this time slice. */
      tdata = in_data ? ( out_data + itime*timeslice_size ) : NULL;

/* Begin an AST context. Having this context within the time slice loop
   helps keep the number of AST objects in use to a minimum. */
      astBegin;

/* Get a Mapping from the spatial GRID axes in the template to the spatial
   GRID axes in the sky cube for the current time slice. Note this has
   to be done first since it stores details of the current time slice
   in the "smfHead" structure inside "data", and this is needed by
   subsequent functions. */
      totmap = smf_rebin_totmap( data, itime, abskyfrm, iskymap, moving,
				 status );
      if( !totmap ) {
         astEnd;
         break;
      }

/* Use this Mapping to get the sky cube spatial grid coords for each
   template detector. */
      astTran2( totmap, ndet, detxtemplt, detytemplt, 1, detxskycube,
                detyskycube );

/* Loop round each detector, obtaining its output value from the sky cube. */
      for( idet = 0; idet < ndet; idet++ ) {

/* Get a pointer to the start of the output spectrum data. */
         ddata = tdata + idet*nchan;

/* Check the detector has a valid position in sky cube grid coords */
         if( detxskycube[ idet ] != AST__BAD && detyskycube[ idet ] != AST__BAD ){

/* Find the closest sky cube pixel and check it is within the bounds of the
   sky cube. */
            gxsky = floor( detxskycube[ idet ] + 0.5 );
            gysky = floor( detyskycube[ idet ] + 0.5 );
            if( gxsky >= 1 && gxsky <= dim[ 0 ] &&
                gysky >= 1 && gysky <= dim[ 1 ] ) {

/* Get the offset of the sky cube array element that corresponds to this
   pixel in the first spectral channel. */
               iv0 = ( gysky - 1 )*dim[ 0 ] + ( gxsky - 1 );

/* Copy the sky cube spectrum into the output time series cube. */
               *overlap = 1;
               if( in_data ) {
                  smf_resampcube_copy( nchan, spectab, iv0, nxy,
                                       ddata, in_data, status );
               } else {
                  break;
               }
            }
         }
      }

/* End the AST context. */
      astEnd;

/* If no input data was supplied, and we have found at least one input
   spectrum that overlaps the sky cube, we can finish early. */
      if( !in_data && *overlap ) break;
   }

/* Free non-static resources. */
L999:;
   spectab = astFree( spectab );
   detxtemplt = astFree( detxtemplt );
   detytemplt = astFree( detytemplt );
   detxskycube = astFree( detxskycube );
   detyskycube = astFree( detyskycube );

}
示例#13
0
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);
   }
}
示例#14
0
void smf_calc_smoothedwvm ( ThrWorkForce *wf, const smfArray * alldata,
                            const smfData * adata, AstKeyMap* extpars, double **wvmtau,
                            size_t *nelems, size_t *ngoodvals, int * status ) {
  size_t i;
  size_t nrelated = 0;          /* Number of entries in smfArray */
  size_t nframes = 0;           /* Number of timeslices */
  size_t ngood = 0;             /* Number of elements with good tau */
  double *taudata = NULL;       /* Local version of WVM tau */
  const smfArray * thesedata = NULL;  /* Collection of smfDatas to analyse */
  smfArray * tmpthesedata = NULL; /* Local version of adata in a smfArray */

  if (*status != SAI__OK) return;

  if (alldata && adata) {
    *status = SAI__ERROR;
    errRep("", "smf_calc_smoothedwvm can not be given non-NULL alldata and non-NULL adata arguments"
           " (possible programming error)", status );
    return;
  }

  if (!alldata && !adata) {
    *status = SAI__ERROR;
    errRep("", "smf_calc_smoothedwvm: One of alldata or adata must be non-NULL",
           status);
    return;
  }

  if (!wvmtau) {
    *status = SAI__ERROR;
    errRep("", "Must supply a non-NULL pointer for wvmtau argument"
           " (possible programming error)", status );
    return;
  }

  /* if we have a single smfData put it in a smfArray */
  if (alldata) {
    if (alldata->ndat == 0 ) {
      *status = SAI__ERROR;
      errRep("", "No smfDatas present in supplied smfArray for WVM smoothing"
             " (possible programming error)", status );
      return;
    }
    thesedata = alldata;
  } else {
    tmpthesedata = smf_create_smfArray( status );
    if (tmpthesedata) {
      tmpthesedata->owndata = 0; /*not owned by the smfArray */

      /* we know that the smfData here will not be touched in this
         function so we do the BAD thing of casting const to non-const */
      smf_addto_smfArray( tmpthesedata, (smfData *)adata, status );
    }
    thesedata = tmpthesedata;
  }

  /* Check that we have headers and that the smfData are the same length */
  nrelated = thesedata->ndat;

  for (i = 0; i < nrelated; i++ ) {
    smfData * data = (thesedata->sdata)[i];
    smfHead * hdr = data->hdr;
    dim_t thisframes = 0;
    if ( !hdr) {
      *status = SAI__ERROR;
      errRepf( "", "smfData %zu has no header. Aborting WVM smoothing",
               status, i );
      return;
    }

    smf_get_dims( data, NULL, NULL, NULL, &thisframes, NULL, NULL, NULL, status );
    if (!nframes) nframes = thisframes;
    if (thisframes != nframes) {
      *status = SAI__ERROR;
      errRepf( "", "smfData %zu has different length. Aborting WVM smoothing",
               status, i );
      return;
    }
  }

  /* We will need the earliest and last airmass value in order
     to calculate a zenith tau */

  /* As a first step, just fill the time series with calculated WVM
     tau values even though we know there are about 240 fewer tau
     readings in reality. This initial approach will make it easier to
     use the smoothed data directly rather than having to interpolate
     from the 1.2 second data back into the 200 Hz data. */

  taudata = astCalloc( nframes, sizeof(*taudata) );

  if (*status == SAI__OK) {
    double amprev = VAL__BADD;
    double steptime;
    size_t maxgap;
    struct timeval tv1;
    struct timeval tv2;
    smfCalcWvmJobData *job_data = NULL;
    int nworker;

    /* We need to know the steptime so we can define the max good gap
       in seconds and convert it to steps*/

    steptime = (thesedata->sdata)[0]->hdr->steptime;
    maxgap = (size_t)( 5.0 / steptime );  /* 5 seconds is just larger than 2 WVM readings */

    /* Assume all files have the same airmass information */
    smf_find_airmass_interval( (thesedata->sdata)[0]->hdr, &amprev, NULL, NULL, NULL, status );

    smf_timerinit( &tv1, &tv2, status );


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

    if (*status == SAI__OK) {
      dim_t tstep;
      int iworker;
      smfCalcWvmJobData *pdata = NULL;

      /* Get the number of time slices to process in each thread. */
      if( nworker > (int) nframes ) {
        tstep = 1;
      } else {
        tstep = nframes/nworker;
      }

      /* to return the same values for one thread and multiple threads
         we need to break the threads on wvm sample boundaries wherever
         possible. We make an initial estimate of the number of WVM measurements
         by assuming one every two seconds. */
      {
        smfData * curdata = NULL;
        size_t nwvm = 0;
        double prevtime = VAL__BADD;
        double curtime;
        size_t *boundaries = astGrow(NULL, nframes*(size_t)(steptime/2.0), sizeof(*boundaries));
        for (i=0; i<nframes; i++) {
          if (!curdata) {
            SELECT_DATA( thesedata, curdata, VAL__BADD, wvm_time, i );
          }

          if (curdata) smf_tslice_ast( curdata, i, 0, NO_FTS, status );

          if ( !curdata || curdata->hdr->state->wvm_time == VAL__BADD ) {
            /* Try the other datas */
            SELECT_DATA( thesedata, curdata, VAL__BADD, wvm_time, i );
          }
          if (*status != SAI__OK) break;

          if (!curdata) {
            curtime = VAL__BADD;
          } else {
            curtime = curdata->hdr->state->wvm_time;
          }

          if (curtime != prevtime || nwvm == 0 ) {
            /* Store the index in the boundaries array */
            nwvm++;
            boundaries = astGrow(boundaries, nwvm, sizeof(*boundaries));
            if (!boundaries) { /* this is serious */
              if (*status == SAI__OK) *status = SAI__ERROR;
              errRep("", "Error allocating temporary memory for WVM calculation\n",
                     status );
              break;
            }
            boundaries[nwvm-1] = i;
            prevtime = curtime;
          }
        }

        /* No point using too many threads */
        if (*status == SAI__OK) {
          if (nworker >= (int)nwvm) {
            nworker = nwvm;

            /* Allocate a measurement per thread */
            for( iworker = 0; iworker < nworker; iworker++ ) {
              pdata = job_data + iworker;
              pdata->t1 = boundaries[iworker];
              if (iworker+1 < nworker) pdata->t2 = boundaries[iworker+1]-1;
            }

            /* Ensure that the last thread picks up any left-over time slices */
            pdata->t2 = nframes - 1;

          } else {
            /* Allocate the workers to slices of approximate size tstep */
            size_t prevend = 0; /* End of previous slice */
            size_t prevbnd = 0; /* Index into previous boundaries[] array selection */
            for( iworker = 0; iworker < nworker; iworker++ ) {
              size_t belowidx = prevend+1;
              size_t aboveidx = nframes;
              size_t lbnd;
              size_t ubnd;
              size_t j;
              size_t guess;

              pdata = job_data + iworker;

              if (iworker == 0) { /* always start at the beginning */
                pdata->t1 = 0;
              } else { /* Start one after the previous block */
                pdata->t1 = prevend + 1;
              }

              /* Now we have to find the end of this slice */
              guess = (iworker*tstep) + tstep - 1;
              if (guess <= pdata->t1) guess = pdata->t1 + tstep;

              /* find nearest boundaries */
              for (j=prevbnd; j<nwvm; j++) {
                if ( boundaries[j] > guess ) {
                  aboveidx = boundaries[j];
                  ubnd = j;
                  if (j>0) {
                    belowidx = boundaries[j-1];
                    lbnd = j -1 ;
                  } else {
                    lbnd = 0;
                  }
                  break;
                }
              }

              /* Choose the closest, making sure that we are not choosing t1 */
              if ( (guess - belowidx < aboveidx - guess) && belowidx > pdata->t1 ) {
                pdata->t2 = belowidx - 1;
                prevbnd = lbnd;
              } else {
                pdata->t2 = aboveidx - 1;
                prevbnd = ubnd;
              }

              prevend = pdata->t2;

              if (prevend == nframes - 1 && iworker < nworker-1 ) {
                /* we have run out of slices so just use fewer workers */
                nworker = iworker + 1;
                break;
              }

            }

            /* Ensure that the last thread picks up any left-over time slices */
            pdata->t2 = nframes - 1;

          }

          /* Tidy up */
          boundaries = astFree( boundaries );
        }
      }

      /* Store all the other info needed by the worker threads, and submit the
         jobs to fix the steps in each bolo, and then wait for them to complete. */
      for( iworker = 0; iworker < nworker; iworker++ ) {
        smfArray *thrdata = NULL;
        pdata = job_data + iworker;

        pdata->nframes = nframes;
        pdata->airmass = amprev; /* really need to get it from the start of each chunk */
        pdata->taudata = taudata;
        pdata->maxgap = maxgap;

        /* Need to copy the smfDatas and create a new smfArray for each
           thread */
        thrdata = smf_create_smfArray( status );
        for (i=0;i<nrelated;i++) {
          smfData *tmpdata = NULL;
          tmpdata = smf_deepcopy_smfData( wf, (thesedata->sdata)[i], 0, SMF__NOCREATE_FILE |
                                          SMF__NOCREATE_DA |
                                          SMF__NOCREATE_FTS |
                                          SMF__NOCREATE_DATA |
                                          SMF__NOCREATE_VARIANCE |
                                          SMF__NOCREATE_QUALITY, 0, 0,
                                          status );
          smf_lock_data( tmpdata, 0, status );
          smf_addto_smfArray( thrdata, tmpdata, status );
        }
        pdata->thesedata = thrdata;

        /* Need to do a deep copy of ast data and unlock them */
        pdata->extpars = astCopy(extpars);
        astUnlock( pdata->extpars, 1 );

        /* Pass the job to the workforce for execution. */
        thrAddJob( wf, THR__REPORT_JOB, pdata, smf__calc_wvm_job, 0, NULL,
                   status );
      }

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

      /* Now free the resources we allocated during job creation
         and calculate the number of good values */
      for( iworker = 0; iworker < nworker; iworker++ ) {
        smfArray * thrdata;
        pdata = job_data + iworker;
        astLock( pdata->extpars, 0 );
        pdata->extpars = astAnnul( pdata->extpars );
        thrdata = pdata->thesedata;
        for (i=0;i<thrdata->ndat;i++) {
          smf_lock_data( (thrdata->sdata)[i], 1, status );
        }
        smf_close_related( wf, &thrdata, status );
        ngood += pdata->ngood;
      }
    }
    job_data = astFree( job_data );

    msgOutiff( MSG__NORM, "", FUNC_NAME ": %f s to calculate unsmoothed WVM tau values",
               status, smf_timerupdate(&tv1,&tv2,status) );

  }




  if (*status == SAI__OK && extpars) {
    /* Read extpars to see if we need to smooth */
    double smoothtime = VAL__BADD;

    if (astMapGet0D( extpars, "SMOOTHWVM", &smoothtime ) ) {
      if (smoothtime != VAL__BADD && smoothtime > 0.0) {
        smfData * data = (thesedata->sdata)[0];
        double steptime = data->hdr->steptime;
        dim_t boxcar = (dim_t)( smoothtime / steptime );

        msgOutiff( MSG__VERB, "",
                   "Smoothing WVM data with %f s tophat function",
                   status, smoothtime );

        smf_tophat1D( taudata, nframes, boxcar, NULL, 0, 0.0, status );

        /* The tophat smoothing puts a bad value at the start and end of
           the time series so we replace that with the adjacent value since
           the step time is much smaller than WVM readout time. If more than
           one value is bad we do not try to find the good value. */
        taudata[0] = taudata[1];
        taudata[nframes-1] = taudata[nframes-2];
      }
    }
  }

  /* Use this to get the raw WVM output for debugging */
  /*
  if (*status == SAI__OK) {
    smfData *data = (thesedata->sdata)[0];
    smfHead *hdr = data->hdr;
    printf("# IDX TAU RTS_NUM RTS_END WVM_TIME\n");
    for (i=0; i<nframes;i++) {
      JCMTState * state;
      state = &(hdr->allState)[i];
      printf("%zu %.*g %d %.*g %.*g\n", i, DBL_DIG, taudata[i], state->rts_num,
             DBL_DIG, state->rts_end, DBL_DIG, state->wvm_time);
    }
  } */

  /* Free resources */
  if (tmpthesedata) smf_close_related( wf, &tmpthesedata, status );

  if (*status != SAI__OK) {
    if (taudata) taudata = astFree( taudata );
    *nelems = 0;
    *ngoodvals = 0;
  } else {
    *wvmtau = taudata;
    *nelems = nframes;
    *ngoodvals = ngood;
  }

}
示例#15
0
                                   INTEGER(TO),
                                   CHARACTER(NAMELIST),
                                   INTEGER(STATUS)
                                   TRAIL(NAMELIST) ) {
   GENPTR_INTEGER(FROM)
   GENPTR_INTEGER(TO)
   GENPTR_INTEGER(NAMELIST)
   F77_INTEGER_TYPE(RESULT);
   char *namelist;

   astAt( "AST_CONVERT", NULL, 0 );
   astWatchSTATUS(
      namelist = astString( NAMELIST, NAMELIST_length );
      RESULT = astP2I( astConvert( astI2P( *FROM ), astI2P( *TO ),
                                   namelist ) );
      namelist = astFree( namelist );
   )
   return RESULT;
}

F77_DOUBLE_FUNCTION(ast_angle)( INTEGER(THIS),
                                   DOUBLE_ARRAY(A),
                                   DOUBLE_ARRAY(B),
                                   DOUBLE_ARRAY(C),
                                   INTEGER(STATUS) ) {
   GENPTR_INTEGER(THIS)
   GENPTR_DOUBLE_ARRAY(A)
   GENPTR_DOUBLE_ARRAY(B)
   GENPTR_DOUBLE_ARRAY(C)
   F77_DOUBLE_TYPE(RESULT);
示例#16
0
void smf_close_file( smfData ** data, int * status ) {

  void *buf=NULL;         /* Buffer pointer */
  size_t buflen=0;        /* Size of buffer */
  smfDA   * da;           /* pointer to smfDA in smfData */
  smfFts* fts;            /* pointer to smfFts in smfData */
  size_t datalen=0;       /* Size of data buffer in bytes */
  smfDream *dream = NULL; /* Pointer to smfDream in smfData */
  smfFile * file;         /* pointer to smfFile in smfData */
  int       freedata = 0; /* should the data arrays be freed? */
  smfHead * hdr;          /* pointer to smfHead in smfData */
  size_t headlen=0;       /* Size of header (mmap'd files) in bytes */
  size_t       i;         /* loop counter */
  smfDIMMHead *temphead=NULL; /* Pointer to DIMM header */


  /* we need to be able to clean up even if input status is bad -
     this requires some defensive programming. */

  if ( *data == NULL ) {
    if ( *status == SAI__OK ) {
      /* Status is good so we have a problem */
      *status = SAI__ERROR;
      errRep( ERRFUNC, "Attempt to close file when smfData pointer is NULL (possible programming error)",
              status );
    }
    /* null pointer so just return since there is nothing to free */
    return;
  }

  /* Process reference count */
  /* Only proceed if the decremented reference count is 0 */
  (*data)->refcount--;

  if ((*data)->refcount > 0 ) return;

  /* Get the header and file, since we need them for checking */
  hdr = (*data)->hdr;

  /* Before annulling close NDF try closing SCU2RED.MAPCOORD */
  smf_close_mapcoord( *data, status );

  /* Display any warnings generated by AST and stored in the FitsChan. */
  file = (*data)->file;
  if( hdr && hdr->fitshdr ) {
    fts1Astwn( hdr->fitshdr,
               file ? file->ndfid : NDF__NOID,
               status );
  }

  /* now file information */
  if (file != NULL) {

    if ( file->isSc2store ) {
      /* Nothing to free here except for data */
      freedata = 1;

    } else if ( file->ndfid != NDF__NOID ) {

      /* Handle quality as a special case */
      if ( (*data)->qual) {
        (*data)->qual = smf_qual_unmap( file->ndfid, (*data)->qfamily,
                                        (*data)->qual, status );
      }

      /* Annul the NDF (which will unmap things) */
      ndfAnnul( &(file->ndfid), status );

    } else if( file->fd ) {
      /* Array was mmap'd to a file, and must now be sync'd and unmapped,
         and the file descriptor closed */

      /* Get the size of the header and data section */
      smf_calc_mmapsize( sizeof(*temphead), *data, &headlen, &datalen,
                         &buflen, status );

      /* The header is in the same mapped array as the data array,
         but headlen bytes earlier. Point temphead to this location and
         update relevant header values before closing */

      buf = ((char*)((*data)->pntr[0]) - headlen);
      temphead = (smfDIMMHead *) buf;
      temphead->data.isTordered = (*data)->isTordered;
      temphead->data.dtype = (*data)->dtype;
      temphead->data.ndims = (*data)->ndims;
      memcpy( temphead->data.dims, (*data)->dims, sizeof( temphead->data.dims));

      if( msync( buf, buflen, MS_ASYNC ) == -1 ) {
        *status = SAI__ERROR;
        errRep( ERRFUNC, "Unable to synch model container file", status );
      } else if( munmap( buf, buflen ) == -1 ) {
        *status = SAI__ERROR;
        errRep( ERRFUNC, "Unable to unmap model container file", status );
      } else if( close( file->fd ) == -1 ) {
        *status = SAI__ERROR;
        errRep( ERRFUNC, "Unable to close model container file", status );
      } else {
        file->fd = 0;
      }

    } else {
      /* No file so free the data */
      freedata = 1;
    }

    (*data)->file = astFree( (*data)->file );
  } else {
    /* no file - data is ours to free */
    freedata = 1;
  }


  /* Tidy up the header */
  if (hdr != NULL) {
    if (hdr->wcs != NULL) hdr->wcs = astAnnul( hdr->wcs );
    if (hdr->tswcs != NULL) hdr->tswcs = astAnnul( hdr->tswcs );
    if (hdr->fitshdr != NULL) hdr->fitshdr = astAnnul( hdr->fitshdr );

    if( hdr->cache1 ) hdr->cache1 = sc2ast_createwcs2( SC2AST__NULLSUB, NULL, 0.0, NULL, NULL, NULL,
                                                       hdr->cache1, status );
    if( hdr->cache2 ) hdr->cache2 = smf_create_lutwcs( 1, NULL, NULL, 0, NULL, 0.0, NULL,
                                                       NULL, NULL, hdr->cache2, status );
    if( hdr->cache3 ) hdr->cache3 = smf_detpos_wcs( NULL, -1, 0.0, NULL, NULL, hdr->cache3,
                                                    status );

    if (!hdr->isCloned) {
      /* We are responsible for this memory - although what happens
         when we are cloned and the original is freed first? Need
         to think carefully about memory management. */
      if (hdr->allState != NULL) {
        hdr->allState = astFree( hdr->allState );
      }
      if (hdr->fplanex) hdr->fplanex = astFree( hdr->fplanex );
      if (hdr->fplaney) hdr->fplaney = astFree( hdr->fplaney );
      if (hdr->detpos) hdr->detpos = astFree( hdr->detpos );
      if (hdr->tsys) hdr->tsys = astFree( hdr->tsys );
      if (hdr->detname) hdr->detname = astFree( hdr->detname );
      if (hdr->ocsconfig) hdr->ocsconfig = astFree( hdr->ocsconfig );
    }
    hdr = astFree( hdr );
  }

  /* Now the smfDA itself */
  if ( (*data)->da != NULL ) {
    da = (*data)->da;
    da->flatcal = astFree( da->flatcal );
    da->flatpar = astFree( da->flatpar );
    if( da->dksquid) smf_close_file( &da->dksquid, status );
    da->heatval = astFree( da->heatval );
    da = astFree( da );
  }

  /* Free smfFts */
  if((*data)->fts != NULL) {
    fts = (*data)->fts;
    if(fts->zpd) { smf_close_file(&fts->zpd, status); }
    if(fts->fpm) { smf_close_file(&fts->fpm, status); }
    if(fts->sigma) { smf_close_file(&fts->sigma, status); }
    fts = astFree(fts);
  }

  /* Free smfDream */
  if ( (*data)->dream != NULL ) {
    dream = (*data)->dream;
    if ( dream->gridwts != NULL)
      dream->gridwts = astFree( dream->gridwts );
    if ( dream->invmatx != NULL)
      dream->invmatx = astFree( dream->invmatx );
    dream= astFree( dream );
  }

  /* Free up other pointers in the smfData: */
  if ( (*data)->poly ) {
    (*data)->poly = astFree( (*data)->poly );
  }
  if ( (*data)->lut ) {
    (*data)->lut = astFree( (*data)->lut );
  }
  if( (*data)->theta ) {
    (*data)->theta = astFree( (*data)->theta );
  }

  /* Free the data arrays if they are non-null (they should have been
     freed if they were mapped to a file but not if they were stored
     in a separate action as temp storage */
  if (freedata) {
    for (i = 0; i < 2; i++ ) {
      if ( ((*data)->pntr)[i] != NULL )
        ((*data)->pntr)[i] = astFree( ((*data)->pntr)[i] );
    }
    if ( (*data)->qual ) {
      (*data)->qual = astFree( (*data)->qual );
    }
  }

  /* finally free smfData */
  *data = astFree( *data );

}
示例#17
0
void smf_rebincube_ast( ThrWorkForce *wf, smfData *data, int first, int last,
                      int *ptime, dim_t nchan, dim_t ndet, dim_t nslice,
                      dim_t nel, dim_t nxy, dim_t nout, dim_t dim[3],
                      AstMapping *ssmap, AstSkyFrame *abskyfrm,
                      AstMapping *oskymap, Grp *detgrp, int moving,
                      int usewgt, int spread, const double params[],
                      int genvar, double tfac, double fcon,
                      float *data_array, float *var_array,
                      double *wgt_array, float *texp_array,
                      float *teff_array, int *good_tsys, int *nused,
                      int *status ){

/* Local Variables */
   AstCmpMap *detmap = NULL;   /* Mapping from 1D det. index to 2D i/p "grid" coords */
   AstMapping *dtotmap = NULL; /* 1D det index->o/p GRID Mapping */
   AstMapping *fullmap = NULL; /* WCS->GRID LutMap from input WCS FrameSet */
   AstMapping *lutmap = NULL;  /* Mapping that identifies detectors to be used */
   AstMapping *splut = NULL;   /* Spatial LutMap */
   AstMapping *sslut = NULL;   /* Spectral LutMap */
   AstMapping *totmap = NULL;  /* WCS->GRID Mapping from input WCS FrameSet */
   AstPermMap *pmap;           /* Mapping to rearrange output axes */
   const char *name = NULL;    /* Pointer to current detector name */
   const double *tsys = NULL;  /* Pointer to Tsys value for first detector */
   dim_t iv;                   /* Vector index into output 3D array */
   double *detlut = NULL;      /* Work space for detector mask */
   double blk_bot[ 2*MAXTHREADS + 1 ]; /* First o/p channel no. in each block */
   double con;                 /* Constant value */
   double dtemp;               /* Temporary value */
   double tcon;                /* Variance factor for whole time slice */
   float *detwork = NULL;      /* Work array for detector values */
   float *tdata = NULL;        /* Pointer to start of input time slice data */
   float *varwork = NULL;      /* Work array holding variances for 1 slice/channel */
   float *vp = NULL;           /* Pointer to next "varwork" element */
   float invar;                /* Input variance */
   float rtsys;                /* Tsys value */
   float teff;                 /* Effective integration time */
   float texp;                 /* Total time ( = ton + toff ) */
   int *nexttime;              /* Pointer to next time slice index to use */
   int ast_flags;              /* Basic flags to use with astRebinSeq */
   int blk_size;               /* Number of channels processed by a single thread */
   int found;                  /* Was current detector name found in detgrp? */
   int iblock;                 /* Index of current spectral block */
   dim_t ichan;                /* Index of current channel */
   dim_t idet;                 /* detector index */
   int ignore;                 /* Ignore this time slice? */
   int inperm[ 3 ];            /* Input axis permutation array */
   dim_t itime;                /* Index of current time slice */
   int junk;                   /* Unused parameter */
   int lbnd_in[ 2 ];           /* Lower input bounds on receptor axis */
   int ldim[ 3 ];              /* Output array lower GRID bounds */
   int maxthreads;             /* Max no. of threads to use when re-binning */
   int nblock;                 /* Number of spectral blocks */
   int nthreads;               /* Number of threads to use when re-binning */
   int outperm[ 3 ];           /* Output axis permutation array */
   int timeslice_size;         /* Number of elements in a time slice */
   int ubnd_in[ 2 ];           /* Upper input bounds on receptor axis */
   int uddim[ 1 ];             /* Detector array upper GRID bounds */
   int udim[ 3 ];              /* Output array upper GRID bounds */
   smfHead *hdr = NULL;        /* Pointer to data header for this time slice */

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

/* Store a pointer to the input NDFs smfHead structure. */
   hdr = data->hdr;

/* Fill an array with the lower grid index bounds of the output. */
   ldim[ 0 ] = 1;
   ldim[ 1 ] = 1;
   ldim[ 2 ] = 1;

/* Integer upper grid index bounds of the output. */
   udim[ 0 ] = dim[ 0 ];
   udim[ 1 ] = dim[ 1 ];
   udim[ 2 ] = dim[ 2 ];

/* Integer upper bounds of detector array. */
   uddim[ 0 ] = ndet;

/* Store the size of an input time slice. */
   timeslice_size = nel/nslice;

/* Create a LutMap that holds the output spectral axis GRID value at
   the centre of each input spectral axis pixel. LutMaps are faster to
   evaluate, and so astRebinSeq will go faster. We can use LutMaps without
   loosing accuracy since astRebinSeq only ever transforms the GRID
   values at input pixel centres (i.e. integer GRID values), and so the
   LutMap will always return a tabulated value rather than an
   interpolated value. */
   atlTolut( (AstMapping *) ssmap, 1.0, (double) nchan, 1.0, "LutInterp=1",
              &sslut, status );

/* If this is the first pass through this file, initialise the arrays. */
   if( first ) smf_rebincube_init( 0, nxy, nout, genvar, data_array, var_array,
                                   wgt_array, texp_array, teff_array, &junk, status );

/* Initialisation the flags for astRebinSeq (we do not include flag
   AST__REBININIT because the arrays have been initialised). */
   ast_flags = AST__USEBAD;
   if( usewgt ) ast_flags = ast_flags | AST__VARWGT;

   if( genvar == 1 ) {
      ast_flags = ast_flags | AST__GENVAR;
   } else if( genvar == 2 ) {
      ast_flags = ast_flags | AST__USEVAR;
   }

/* If required, allocate a work array to hold all the input variances for a
   single time slice. */
   if( usewgt || genvar == 2 ) varwork = astMalloc( timeslice_size * sizeof( float ) );

/* Allocate a work array to hold the exposure time for each detector. */
   detwork = astMalloc( ndet * sizeof( float ) );

/* If we are dealing with more than 1 detector, create a LutMap that holds
   the input GRID index of every detector to be included in the output, and
   AST__BAD for every detector that is not to be included in the output cube.
   First allocate the work space for the LUT. */
   if( ndet > 1 ) {
      detlut = astMalloc( ndet*sizeof( double ) );

/* Initialise a string to point to the name of the first detector for which
   data is available */
      name = hdr->detname;

/* Loop round all detectors for which data is available. */
      for( idet = 0; idet < ndet; idet++ ) {

/* Store the input GRID coord of this detector. GRID coords start at 1,
   not 0. */
         detlut[ idet ] = idet + 1.0;

/* If a group of detectors to be used was supplied, search the group for
   the name of the current detector. If not found, set the GRID coord bad.
   This will cause astRebinSeq to ignore data from the detector. */
         if( detgrp ) {
            found = grpIndex( name, detgrp, 1, status );
            if( !found ) detlut[ idet ] = AST__BAD;
         }

/* Move on to the next available detector name. */
         name += strlen( name ) + 1;
      }

/* Create the LutMap. */
      lutmap = (AstMapping *) astLutMap( ndet, detlut, 1.0, 1.0,
                                         "LutInterp=1" );

/* If we only have 1 detector, use a UnitMap instead of a LutMap (lutMaps
   must have 2 or more table entries). */
   } else {
      lutmap = (AstMapping *) astUnitMap( 1, " " );
   }

/* Combine the above LutMap with a 1-input, 2-output PermMap that copies its
   input to create its first output, and assigns a constant value of 1.0 to
   its second output. We need to do this because smf_tslice returns a 2D
   GRID system (even though the second GRID axis is not actually used). */
   inperm[ 0 ] = 1;
   outperm[ 0 ] = 1;
   outperm[ 1 ] = -1;
   con = 1.0;
   detmap = astCmpMap( lutmap, astPermMap( 1, inperm, 2, outperm, &con, " " ),
                       1, " " );

/* Store the bounds of a single time slice grid. */
   lbnd_in[ 0 ] = 1;
   ubnd_in[ 0 ] = nchan;
   lbnd_in[ 1 ] = 1;
   ubnd_in[ 1 ] = ndet;

/* Create a PermMap that can be used to re-order the output axes so that
   channel number is axis 3. */
   outperm[ 0 ] = 2;
   outperm[ 1 ] = 3;
   outperm[ 2 ] = 1;
   inperm[ 0 ] = 3;
   inperm[ 1 ] = 1;
   inperm[ 2 ] = 2;
   pmap = astPermMap( 3, inperm, 3, outperm, NULL, " " );

/* If we are using multiple threads to rebin spectral blocks in parallel,
   calculate the number of channels that are processed by each thread,
   and the number of threads to use. The whole output spectrum is divided
   up into blocks. The number of blocks is two times the number of
   threads, and each thread rebins two adjacent blocks. Alternate blocks
   are re-binned simultanously. First, the odd numbered blocks are re-binned
   (one by each thread). When all odd numbered blocks have been re-binned,
   the even numbered blocks are re-binned. We ensure that the number of
   threads used results in a block size that is larger than the spreading
   width produced by the requested spreading scheme. This means that no
   pair of simultanously executing threads will ever try to write to the
   same channel of the output spectrum. */
   maxthreads = wf ? wf->nworker : 1;
   if( maxthreads > MAXTHREADS ) maxthreads = MAXTHREADS;
   if( maxthreads > 1 ) {

/* Find the largest number of threads into which each output spectrum can
   be split. The limit is imposes by the requirement that each block is
   larger than the pixel spreading produced by the requested spreading
   scheme. */
      nthreads = ( ( dim[ 2 ] + 1 )/2 )/smf_spreadwidth( spread, params,
                                                         status );

/* If the spectral range is less than twice the spreading width, we
   cannot use multiple threads. */
      if( nthreads > 1 ) {

/* Restrict the number of threads to be no more than the number of workers
   available in the work force. */
         if( nthreads > maxthreads ) nthreads = maxthreads;

/* Find the number of output channels in each spectral block. */
         blk_size = ( dim[ 2 ] - 1 )/( 2*nthreads ) + 1;

/* Set up the first output channel number within each block. */
         nblock = 2*nthreads;
         for( iblock = 0; iblock < nblock; iblock++ ) {
            blk_bot[ iblock ] = (double) ( iblock*blk_size + 1 );
         }

/* Add in the first channel number beyond the last block. */
         blk_bot[ nblock ] = blk_bot[ nblock - 1 ] + blk_size;

/* If the output spectrum is too short to guarantee that there are any
   independent blocks of output channels, we process the whole spectrum
   in a single thread. */
      } else {
         nthreads = 1;
         nblock = 1;
         blk_bot[ 0 ] = 1.0;
         blk_bot[ 1 ] = (double) ( dim[ 2 ] + 1 );
      }

/* If multiple threads are not available, we process the whole spectrum
   in a single thread. */
   } else {
      nthreads = 1;
      nblock = 1;
      blk_bot[ 0 ] = 1.0;
      blk_bot[ 1 ] = (double) ( dim[ 2 ] + 1 );
   }

/* Convert the block boundaries from output channel numbers into input
   channel numbers. */
   astTran1( ssmap, nblock + 1, blk_bot, 0, blk_bot );

/* Ensure they are in increasing order, and are not outside the bounds of
   the input array. */
   if( blk_bot[ 0 ] > blk_bot[ 1 ] ) {
      for( iblock = 0; iblock < ( nblock + 1 )/2; iblock++ ) {
         dtemp = blk_bot[ nblock - iblock ];
         blk_bot[ nblock - iblock ] = blk_bot[ iblock ];
         blk_bot[ iblock ] = dtemp;
      }
   }

   for( iblock = 0; iblock <= nblock; iblock++ ) {
      if( blk_bot[ iblock ] < 1 ) {
         blk_bot[ iblock ] = 1.0;
      } else if( blk_bot[ iblock ] > nchan ) {
         blk_bot[ iblock ] = nchan;
      }
   }

/* Initialise a pointer to the next time slice index to be used. */
   nexttime = ptime;

/* Initialise the progress meter. */
   smf_reportprogress( nslice, status );

/* Loop round all time slices in the input NDF. */
   for( itime = 0; itime < nslice && *status == SAI__OK; itime++ ) {

/* If this time slice is not being pasted into the output cube, pass on. */
      if( nexttime ){
         if( *nexttime != (int) itime ) continue;
         nexttime++;
      }

/* Store a pointer to the first input data value in this time slice. */
      tdata = ( (float *) (data->pntr)[ 0 ] ) + itime*timeslice_size;

/* Begin an AST context. Having this context within the time slice loop
   helps keep the number of AST objects in use to a minimum. */
      astBegin;

/* Get a Mapping from the spatial GRID axes in the input the spatial
   GRID axes in the output for the current time slice. Note this has
   to be done first since it stores details of the current time slice
   in the "smfHead" structure inside "data", and this is needed by
   subsequent functions. */
      totmap = smf_rebin_totmap( data, itime, abskyfrm, oskymap, moving,
				 status );
      if( !totmap ) break;

/* Get the effective exposure time, the total exposure time, and the
   Tsys->Variance onversion factor for this time slice. Also get a
   pointer to the start of the Tsys array. */
      tsys = smf_rebincube_tcon( hdr, itime, fcon, &texp, &teff, &tcon,
                                 status );

/* So "totmap" is a 2-input, 2-output Mapping that transforms the input
   spatial GRID coords into output spatial GRID coords. In order to speed
   up astRebinSeq we represent this by a pair of parallel LutMaps. To do
   this (using atlTolut) we need a Mapping which only has 1 input, so we
   preceed "totmap" with "detmap" (which also has the effect of exluding
   data from unrequired detectors). We then combine this Mapping in
   parallel with the spectral LutMap to get a 2-input (channel number,
   detector index) and 3-output (output grid coords) Mapping. We finally
   add a PermMap to re-arrange the output axes so that channel number is
   axis 3 in the output. */
      dtotmap = (AstMapping *) astCmpMap( detmap, totmap, 1, " " );
      if( ndet > 1 ) {
         atlTolut( dtotmap, 1.0, (double) ndet, 1.0, "LutInterp=1", &splut,
                   status );
      } else {
         splut = astClone( dtotmap );
      }

      fullmap = astSimplify( astCmpMap( astCmpMap( sslut, splut, 0, " " ),
                                        pmap, 1, " " ) );

/* If required calculate the variance associated with each value in the
   current time slice. based on the input Tsys values. If they are
   needed, but not available, ignored the time slice. */
      ignore = 0;
      if( varwork ) {
         ignore = 1;
         vp = varwork;
         for( idet = 0; idet < ndet; idet++ ) {
            invar = VAL__BADR;
            rtsys = tsys ? (float) tsys[ idet ] : VAL__BADR;
            if( rtsys <= 0.0 ) rtsys = VAL__BADR;
            if( rtsys != VAL__BADR ) {
               *good_tsys = 1;
               if( tcon != VAL__BADD ) {
                  invar = tcon*rtsys*rtsys;
                  ignore = 0;
               }
            }
            for( ichan = 0; ichan < nchan; ichan++ ) *(vp++) = invar;
         }
      }

/* Unless we are ignoring this time slice, paste it into the 3D output
   cube. The smf_rebincube_seqf function is a wrapper for astRebinSeqF
   that splits the total job up between "nthreads" threads running in
   parallel. */
      if( !ignore ) {
         smf_rebincube_seqf( wf, nthreads, blk_bot, fullmap, 0.0, 2, lbnd_in,
                             ubnd_in, tdata, varwork, spread, params,
                             ast_flags, 0.0, 50, VAL__BADR, 3, ldim, udim,
                             lbnd_in, ubnd_in, data_array, var_array,
                             wgt_array, nused, status );

/* Now we update the total exposure time array. Scale the exposure time
   of this time slice in order to reduce its influence on the output
   expsoure times if it does not have much spectral overlap with the
   output cube. then fill the 1D work array with this constant value and
   paste it into the 2D texp_array using the spatial mapping. Note we
   want the simple sum of the exposure times, with no normalisation. SO
   we use the AST__NONORM flag which means we do not need to supply a
   weights array.  */
         if( texp != VAL__BADR ) {
            texp *= tfac;
            for( iv = 0; iv < ndet; iv++ ) detwork[ iv ] = texp;
            astRebinSeqF( splut, 0.0, 1, ldim, uddim, detwork, NULL,
                          spread, params, AST__NONORM, 0.0, 50,
                          VAL__BADR, 2, ldim, udim, ldim, uddim, texp_array,
                          NULL, NULL, NULL );
         }

/* Now do the same with the effective exposure time. */
         if( teff != VAL__BADR ) {
            teff *= tfac;
            for( iv = 0; iv < ndet; iv++ ) detwork[ iv ] = teff;
            astRebinSeqF( splut, 0.0, 1, ldim, uddim, detwork, NULL,
                          spread, params, AST__NONORM, 0.0, 50, VAL__BADR, 2,
                          ldim, udim, ldim, uddim, teff_array, NULL, NULL,
                          NULL );
         }
      }

/* Update the progress meter. */
      smf_reportprogress( 0, status );

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

/* If this is the final pass through this function, normalise the returned
   data and variance values. */
   if( last ) {

/* Create a dummy mapping that can be used with astRebinSeq (it is not
   actually used for anything since we are not adding any more data into the
   output arrays). */
      fullmap = (AstMapping *) astPermMap( 2, NULL, 3, NULL, NULL, " " );

/* Normalise the data values. We do not normalise the exposure time arrays. */
      astRebinSeqF( fullmap, 0.0, 2, lbnd_in,
                    ubnd_in, NULL, NULL, spread, params,
                    AST__REBINEND | ast_flags, 0.0, 50, VAL__BADR, 3,
                    ldim, udim, lbnd_in, ubnd_in, data_array, var_array,
                    wgt_array, nused );
      fullmap = astAnnul(fullmap);
   }

/* Free resources. */
   detlut = astFree( detlut );
   detwork = astFree( detwork );
   varwork = astFree( varwork );
}
示例#18
0
/* Main entry */
void smf_jsadicer( int indf, const char *base, int trim, smf_inst_t instrument,
                   smf_jsaproj_t proj, size_t *ntile, Grp *grp, int *status ){

/* Local Variables: */
   AstBox *box;
   AstFitsChan *fc;
   AstFrame *specfrm = NULL;
   AstFrame *tile_frm = NULL;
   AstFrameSet *iwcs;
   AstFrameSet *tfs = NULL;
   AstFrameSet *tile_wcs;
   AstMapping *ndf_map = NULL;
   AstMapping *p2pmap = NULL;
   AstMapping *specmap = NULL;
   AstMapping *tile_map = NULL;
   AstRegion *region;
   Grp *grpt = NULL;
   char *path;
   char dtype[ NDF__SZFTP + 1 ];
   char jsatile_comment[45];
   char type[ NDF__SZTYP + 1 ];
   const char *dom = NULL;
   const char *keyword;
   const char *latsys = NULL;
   const char *lonsys = NULL;
   double *pd;
   double dlbnd[3];
   double dubnd[3];
   double gcen[3];
   double lbnd_in[3];
   double lbnd_out[3];
   double ubnd_in[3];
   double ubnd_out[3];
   float *pf;
   int *created_tiles = NULL;
   int *tiles;
   int axlat;
   int axlon;
   int axspec;
   int bbox[ 6 ];
   int i;
   int ifrm;
   int igrid;
   int indfo;
   int indfs;
   int indfx;
   int inperm[3];
   int ipixel;
   int ishpx;
   int isxph;
   int itile;
   int ix;
   int iy;
   int iz;
   int junk;
   int latax = -1;
   int lbnd[3];
   int lbnd_tile[ 3 ];
   int lbndx[ NDF__MXDIM ];
   int lonax = -1;
   int nbase;
   int ndim;
   int ndimx;
   int nfrm;
   int nsig;
   int ntiles;
   int olbnd[ 3 ];
   int oubnd[ 3 ];
   int outperm[ 3 ];
   int place;
   int qual;
   int tile_index;
   int tile_lbnd[2];
   int tile_ubnd[2];
   int ubnd[3];
   int ubnd_tile[ 3 ];
   int ubndx[ NDF__MXDIM ];
   int var;
   size_t iext;
   size_t size;
   smfJSATiling tiling;
   unsigned char *ipq = NULL;
   void *ipd = NULL;
   void *ipv = NULL;

/* Initialise */
   *ntile = 0;

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

/* Begin an AST context. */
   astBegin;

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

/* Note the used length of the supplied base string. If it ends with
   ".sdf", reduce it by 4. */
   nbase = astChrLen( base );
   if( !strcmp( base + nbase - 4, ".sdf" ) ) nbase -= 4;

/* Allocate a buffer large enough to hold the full path for an output NDF. */
   path = astMalloc( nbase + 25 );

/* Get the WCS from the NDF. */
   kpg1Gtwcs( indf, &iwcs, status );

/* Note if the NDF projection is HPX or XPH. */
   ishpx = astChrMatch( astGetC( iwcs, "Projection" ), "HEALPix" );
   isxph = astChrMatch( astGetC( iwcs, "Projection" ), "polar HEALPix" );

/* Report an error if the NDFs projection is neither of these. */
   if( !ishpx && !isxph && *status == SAI__OK ) {
      ndfMsg( "N", indf );
      *status = SAI__ERROR;
      errRep( "", "The input NDF (^N) does not appear to be gridded "
              "on the JSA all-sky pixel grid.", status );
   }

/* Get the bounds of the NDF in pixel indices and the the corresponding
   double precision GRID bounds (reduce the size of the grid by a small
   amount to avoid problems with tiles that are on the edge of the valid sky
   regions - astMapRegion can report an error for such tiles). Also store
   the GRID coords of the centre. Also count the number of significant
   pixel axes. */
   ndfBound( indf, 3, lbnd, ubnd, &ndim, status );
   nsig = 0;
   for( i = 0; i < ndim; i++ ) {
      dlbnd[ i ] = 0.5 + 0.1;
      dubnd[ i ] = ubnd[ i ] - lbnd[ i ]  + 1.5 - 0.1;
      gcen[ i ] = 0.5*( dlbnd[ i ] + dubnd[ i ] );
      if( ubnd[ i ] > lbnd[ i ] ) nsig++;
   }

/* Find the one-based indices of the RA, Dec and spectral axes in the
   current Frame of the NDF. */
   axlon = 0;
   if( astGetI( iwcs, "IsLonAxis(1)" ) ) {
      axlon = 1;
      lonsys = astGetC( iwcs, "System(1)" );
   } else if( astGetI( iwcs, "IsLonAxis(2)" ) ) {
      axlon = 2;
      lonsys = astGetC( iwcs, "System(2)" );
   } else if( ndim == 3 && astGetI( iwcs, "IsLonAxis(3)" ) ) {
      axlon = 3;
      lonsys = astGetC( iwcs, "System(3)" );
   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: Cannot find the longitude axis in the "
              "input NDF.", status );
   }

   axlat = 0;
   if( astGetI( iwcs, "IsLatAxis(1)" ) ) {
      axlat = 1;
      latsys = astGetC( iwcs, "System(1)" );
   } else if( astGetI( iwcs, "IsLatAxis(2)" ) ) {
      axlat = 2;
      latsys = astGetC( iwcs, "System(2)" );
   } else if( ndim == 3 && astGetI( iwcs, "IsLatAxis(3)" ) ) {
      axlat = 3;
      latsys = astGetC( iwcs, "System(3)" );
   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: Cannot find the latitude axis in the "
              "input NDF.", status );
   }

   axspec = 6 - axlon - axlat;

/* Report an error if the spatial axes are not ICRS RA and Dec. */
   if( ( lonsys && strcmp( lonsys, "ICRS" ) ) ||
       ( latsys && strcmp( latsys, "ICRS" ) ) ) {
      if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         ndfMsg( "N", indf );
         errRep( "", "smf_jsadicer: The spatial axes in '^N' are not "
                 "ICRS RA and Dec.", status );
      }
   }

/* Create a Box describing the region covered by the NDF pixel grid in
   GRID coords. */
   box = astBox( astGetFrame( iwcs, AST__BASE ), 1, dlbnd, dubnd,
                 AST__NULL, " " );

/* Map this Box into the current WCS Frame of the NDF. */
   region = astMapRegion( box, iwcs, iwcs );

/* If no instrument was specified, we will determine the instrument from
   the contexts of the FITS extension. Copy the NDF FITS extension to a
   FitsChan. Annul the error if the NDF no FITS extension. */
   if( instrument == SMF__INST_NONE && *status == SAI__OK ) {
      kpgGtfts( indf, &fc, status );
      if( *status == KPG__NOFTS ) {
         errAnnul( status );
         fc = NULL;
      }
   } else {
      fc = NULL;
   }

/* Get the parameters of the required tiling scheme. */
   smf_jsainstrument( NULL, fc, instrument, &tiling, status );

/* Get a list of the JSA tiles touched by the supplied NDF. */
   tiles = smf_jsatiles_region( region, &tiling, &ntiles, status );
   if( ntiles == 0 && *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: No JSA tiles found touching supplied NDF "
              "(programming error).", status );
   }

/* Does the input NDF have a Variance component? */
   ndfState( indf, "Variance", &var, status );

/* Does the input NDF have a Quality component? */
   ndfState( indf, "Quality", &qual, status );

/* Decide on the data type to use: _REAL or _DOUBLE. */
   ndfMtype( "_REAL,_DOUBLE", indf, indf, "Data", type, sizeof(type), dtype,
             sizeof(dtype), status );

/* Tell the user what is happening. */
   msgBlank( status );
   msgOutf( "", "Dicing %s into JSA tiles:", status,
            ( nsig == 2 ) ? "map" : "cube" );

/* Loop round all tiles that overlap the supplied NDF. */
   for( itile = 0; itile < ntiles && *status == SAI__OK; itile++ ) {
      tile_index = tiles[ itile ];

/* Get the spatial pixel bounds of the current tile within the requested
   JSA all-sky projection. Also get the (2D) WCS FrameSet for the tile. */
      smf_jsatile( tile_index, &tiling, 0, proj, NULL, &tile_wcs, NULL,
                   tile_lbnd, tile_ubnd, status );

/* Extract the tile pixel->WCS mapping and WCS Frame. We know the indices
   of the required Frames because they are hard-wired in smf_jsatile. */
      tile_map = astGetMapping( tile_wcs, 3, 2 );
      tile_frm = astGetFrame( tile_wcs, 2 );

/* Find the indices of the grid and pixel frames in the input NDF. */
      ipixel = -1;
      igrid = astGetI( iwcs, "Base" );
      nfrm = astGetI( iwcs, "NFrame" );
      for( ifrm = 0; ifrm < nfrm; ifrm++ ) {
         dom = astGetC( astGetFrame( iwcs, ifrm + 1 ), "Domain" );
         if( astChrMatch( dom, "PIXEL" ) ) ipixel = ifrm + 1;
      }

/* If required, extract the pixel->spectral mapping and spectral frame in
   the input NDF, and add it in parallel with the above tile mapping. */
      if( ndim == 3 ) {
         astSetI( iwcs, "Base", ipixel );
         tfs = atlFrameSetSplit( iwcs, "DSBSPECTRUM SPECTRUM", NULL,
                                 NULL, status );
         astSetI( iwcs, "Base", igrid );
         if( tfs ) {
            specmap = astGetMapping( tfs, AST__BASE, AST__CURRENT );
            specfrm = astGetFrame( tfs, AST__CURRENT );
         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indf );
            errRep( "", "smf_jsadicer: Cannot find the spectral axis "
                    "in '^N'.", status );
         }

         tile_map = (AstMapping *) astCmpMap( tile_map, specmap, 0, " " );
         tile_frm = (AstFrame *) astCmpFrame( tile_frm, specfrm, " " );
      }

/* Ensure the Epoch is inherited form the input NDF. */
      astSetD( tile_frm, "Epoch", astGetD( iwcs, "Epoch" ) );

/* Currently tile axis 1 is RA, axis 2 is Dec and axis 3 (if present) is
   spectral. Append a PermMap that re-orders these tile WCS axes to match
   those of the NDF. */
      outperm[ axlon - 1 ] = 1;
      outperm[ axlat - 1 ] = 2;
      outperm[ axspec - 1 ] = 3;
      inperm[ 0 ] = axlon;
      inperm[ 1 ] = axlat;
      inperm[ 2 ] = axspec;
      tile_map = (AstMapping *) astCmpMap( tile_map, astPermMap( ndim, inperm,
                                                                 ndim, outperm,
                                                                 NULL, " " ),
                                           1, " " );
      tile_map = astSimplify( tile_map );

/* Also re-order the WCS axes in the tile frame. */
      astPermAxes( tile_frm, outperm );

/* We want the zero-based indicies of the input pixel axes corresponding
   to ra, dec and spectral. So find the indicies of the pixel axes in the
   supplied NDF that are most closely aligned with each WCS axis. */
      atlPairAxes( iwcs, NULL, gcen, NULL, inperm, status );
      if( inperm[ 0 ] == axlon ) {
         lonax = 0;
      } else if( inperm[ 1 ] == axlon ) {
         lonax = 1;
      } else {
         lonax = 2;
      }
      if( inperm[ 0 ] == axlat ) {
         latax = 0;
      } else if( inperm[ 1 ] == axlat ) {
         latax = 1;
      } else {
         latax = 2;
      }

/* To get the mapping from pixel coords in the input NDF to pixel coords
   in the output NDF, we invert the above mapping so that it goes from WCS
   to pixel, and append it to the end of the NDF pixel->WCS mapping. */
      ndf_map = astGetMapping( iwcs, ipixel, AST__CURRENT );
      astInvert( tile_map );
      p2pmap = (AstMapping *) astCmpMap( ndf_map, tile_map, 1, " " );
      p2pmap = astSimplify( p2pmap );
      astInvert( tile_map );

/* Show the bounds of the tile within the input NDF. */
      msgOutiff( MSG__DEBUG, "", "   tile %d has bounds (%d:%d,%d:%d) "
                 "within the output NDF.", status, tile_index,
                 tile_lbnd[ 0 ], tile_ubnd[ 0 ], tile_lbnd[ 1 ],
                 tile_ubnd[ 1 ] );

/* Next job is to find the pixel bounds of the output NDF to create
   which will hold data for the current tile. First map the pixel bounds
   of the whole tile from output to input. */
      lbnd_in[ 0 ] = tile_lbnd[ 0 ] - 0.5;
      lbnd_in[ 1 ] = tile_lbnd[ 1 ] - 0.5;
      lbnd_in[ 2 ] = lbnd[ 2 ] - 0.5;
      ubnd_in[ 0 ] = tile_ubnd[ 0 ] - 0.5;
      ubnd_in[ 1 ] = tile_ubnd[ 1 ] - 0.5;
      ubnd_in[ 2 ] = ubnd[ 2 ] - 0.5;

      astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 1, lbnd_out + 0,
                 ubnd_out + 0, NULL, NULL );
      astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 2, lbnd_out + 1,
                 ubnd_out + 1, NULL, NULL );
      if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 3,
                                 lbnd_out + 2, ubnd_out + 2, NULL,
                                 NULL );


      lbnd_tile[ 0 ] = floor( lbnd_out[ 0 ] ) + 1;
      lbnd_tile[ 1 ] = floor( lbnd_out[ 1 ] ) + 1;
      lbnd_tile[ 2 ] = floor( lbnd_out[ 2 ] ) + 1;
      ubnd_tile[ 0 ] = floor( ubnd_out[ 0 ] ) + 1;
      ubnd_tile[ 1 ] = floor( ubnd_out[ 1 ] ) + 1;
      ubnd_tile[ 2 ] = floor( ubnd_out[ 2 ] ) + 1;

/* Show the bounds of the tile within the input NDF. */
      msgOutiff( MSG__DEBUG, "", "   tile %d has bounds (%d:%d,%d:%d) "
                 "within the input NDF.", status, tile_index,
                 lbnd_tile[ 0 ], ubnd_tile[ 0 ], lbnd_tile[ 1 ],
                 ubnd_tile[ 1 ] );

/* If required, trim the bounds to the extent of the input NDF. */
      if( trim ) {
         if( lbnd_tile[ 0 ] < lbnd[ 0 ] ) lbnd_tile[ 0 ] = lbnd[ 0 ];
         if( lbnd_tile[ 1 ] < lbnd[ 1 ] ) lbnd_tile[ 1 ] = lbnd[ 1 ];
         if( lbnd_tile[ 2 ] < lbnd[ 2 ] ) lbnd_tile[ 2 ] = lbnd[ 2 ];
         if( ubnd_tile[ 0 ] > ubnd[ 0 ] ) ubnd_tile[ 0 ] = ubnd[ 0 ];
         if( ubnd_tile[ 1 ] > ubnd[ 1 ] ) ubnd_tile[ 1 ] = ubnd[ 1 ];
         if( ubnd_tile[ 2 ] > ubnd[ 2 ] ) ubnd_tile[ 2 ] = ubnd[ 2 ];
      }

/* Check there is some overlap. */
      if( lbnd_tile[ 0 ] <= ubnd_tile[ 0 ] &&
          lbnd_tile[ 1 ] <= ubnd_tile[ 1 ] &&
          lbnd_tile[ 2 ] <= ubnd_tile[ 2 ] ){

/* Now need to check if this section of the input NDF contains any good
   values. We also find the bounding box of the good values (within the
   input pixel coordinate system). So first obtain and map the required
   section of the input NDF. */
         ndfSect( indf, ndim, lbnd_tile, ubnd_tile, &indfs, status );
         ndfMap( indfs, "Data", type, "Read", &ipd, &junk, status );
         if( var ) ndfMap( indfs, "Variance", type, "Read", &ipv, &junk, status );
         if( qual ) ndfMap( indfs, "Quality", "_UBYTE", "Read", (void **) &ipq,
                            &junk, status );

/* Initialise the pixel bounds (within the input NDF) of the box holding
   good data values for the current tile. */
         bbox[ 0 ] = INT_MAX;
         bbox[ 1 ] = INT_MAX;
         bbox[ 2 ] = INT_MAX;
         bbox[ 3 ] = -INT_MAX;
         bbox[ 4 ] = -INT_MAX;
         bbox[ 5 ] = -INT_MAX;

/* Loop round all pixels in the section. */
         if( *status == SAI__OK ) {
            if( !strcmp( type, "_REAL" ) ) {
               pf = (float *) ipd;
               for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) {
                  for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) {
                     for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) {
                        if( *(pf++) != VAL__BADR ) {
                           if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix;
                           if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy;
                           if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz;
                           if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix;
                           if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy;
                           if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz;
                        }
                     }
                  }
               }
            } else {
               pd = (double *) ipd;
               for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) {
                  for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) {
                     for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) {
                        if( *(pd++) != VAL__BADD ) {
                           if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix;
                           if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy;
                           if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz;
                           if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix;
                           if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy;
                           if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz;
                        }
                     }
                  }
               }
            }

/* Skip empty tiles. */
            if( bbox[ 0 ] != INT_MAX ) {
               msgOutf( "", "   tile %d", status, tile_index );

/* If required, trim the bounds to the edges of the bounding box. */
               if( trim >= 2 ) {
                  olbnd[ 0 ] = bbox[ 0 ];
                  olbnd[ 1 ] = bbox[ 1 ];
                  olbnd[ 2 ] = bbox[ 2 ];
                  oubnd[ 0 ] = bbox[ 3 ];
                  oubnd[ 1 ] = bbox[ 4 ];
                  oubnd[ 2 ] = bbox[ 5 ];
               } else {
                  olbnd[ 0 ] = lbnd_tile[ 0 ];
                  olbnd[ 1 ] = lbnd_tile[ 1 ];
                  olbnd[ 2 ] = lbnd_tile[ 2 ];
                  oubnd[ 0 ] = ubnd_tile[ 0 ];
                  oubnd[ 1 ] = ubnd_tile[ 1 ];
                  oubnd[ 2 ] = ubnd_tile[ 2 ];
               }

/* Modify these pixel bounds so that they refer to the output NDF. */
               lbnd_in[ 0 ] = olbnd[ 0 ] - 0.5;
               lbnd_in[ 1 ] = olbnd[ 1 ] - 0.5;
               lbnd_in[ 2 ] = olbnd[ 2 ] - 0.5;
               ubnd_in[ 0 ] = oubnd[ 0 ] - 0.5;
               ubnd_in[ 1 ] = oubnd[ 1 ] - 0.5;
               ubnd_in[ 2 ] = oubnd[ 2 ] - 0.5;

               astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 1, lbnd_out + 0,
                          ubnd_out + 0, NULL, NULL );
               astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 2, lbnd_out + 1,
                          ubnd_out + 1, NULL, NULL );
               if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 3,
                                          lbnd_out + 2, ubnd_out + 2, NULL,
                                          NULL );

               olbnd[ 0 ] = floor( lbnd_out[ 0 ] ) + 1;
               olbnd[ 1 ] = floor( lbnd_out[ 1 ] ) + 1;
               olbnd[ 2 ] = floor( lbnd_out[ 2 ] ) + 1;
               oubnd[ 0 ] = floor( ubnd_out[ 0 ] ) + 1;
               oubnd[ 1 ] = floor( ubnd_out[ 1 ] ) + 1;
               oubnd[ 2 ] = floor( ubnd_out[ 2 ] ) + 1;

/* Get the full path to the output NDF for the current tile, and create an
   NDF placeholder for it. */
               sprintf( path, "%.*s_%d", nbase, base, tile_index );
               ndfPlace( NULL, path, &place, status );

/* Create a new output NDF by copying the meta-data from the input NDF
   section. */
               ndfScopy( indfs, "Units", &place, &indfo, status );

/* Set the pixel bounds of the output NDF to the values found above and copy
   the input data for the current tile into it. */
               smf1_jsadicer( indfo, olbnd, oubnd, tile_map, tile_frm, p2pmap,
                              ipd, ipv, ipq, status );

/* Add the name of this output NDF to the group holding the names of the
   output NDFs that have actually been created. */
               if( grp ) grpPut1( grp, path, 0, status );

/* Add a TILENUM header to the output FITS extension. */
               kpgGtfts( indfo, &fc, status );
               if( *status == KPG__NOFTS ) {
                  errAnnul( status );
                  fc = astFitsChan( NULL, NULL, " " );

/* If the last card is "END", remove it. */
               } else {
                  astSetI( fc, "Card", astGetI( fc, "NCARD" ) );
                  keyword = astGetC( fc, "CardName" );
                  if( keyword && !strcmp( keyword, "END" ) ) astDelFits( fc );
               }

               one_snprintf(jsatile_comment, 45, "JSA all-sky tile index (Nside=%i)",
                            status, tiling.ntpf);
               atlPtfti( fc, "TILENUM", tile_index, jsatile_comment, status );
               kpgPtfts( indfo, fc, status );
               fc = astAnnul( fc );

/* Now store an STC-S polygon that describes the shortest boundary
   enclosing the good data in the output NDF, and store it as an NDF extension. */
               kpgPutOutline( indfo, 0.5, 1, status );

/* We now reshape any extension NDFs contained within the output NDF to
   have the same spatial bounds as the main NDF (but only for extension
   NDFs that originally have the same spatial bounds as the supplied NDF).
   Get a group containing paths to all extension NDFs in the output NDF. */
               ndgMoreg( indfo, &grpt, &size, status );

/* Loop round each output extension NDF. */
               for( iext = 1; iext <= size && *status == SAI__OK; iext++ ) {
                  ndgNdfas( grpt, iext, "Update", &indfx, status );

/* Get its bounds. */
                  ndfBound( indfx, NDF__MXDIM, lbndx, ubndx, &ndimx, status );

/* See if this extension NDF has the same bounds on the spatial axes as
   the supplied NDF. */
                  if( ndimx > 1 && lbndx[ lonax ] == lbnd[ lonax ] &&
                                   lbndx[ latax ] == lbnd[ latax ] &&
                                   ubndx[ lonax ] == ubnd[ lonax ] &&
                                   ubndx[ latax ] == ubnd[ latax ] ) {

/* If so, change the bounds of the output extension NDF so that they are
   the same as the main NDF on the spatial axes, and map the original
   contents of the NDF onto the new pixel grid. */
                     smf1_jsadicer( indfx, olbnd, oubnd, tile_map, tile_frm, p2pmap,
                                    NULL, NULL, NULL, status );
                  }

/* Annul the extension NDF identifier. */
                  ndfAnnul( &indfx, status );
               }

/* Free resources associated with the current tile. */
               grpDelet( &grpt, status );
               ndfAnnul( &indfo, status );

/* Issue warnings about empty tiles. */
            } else {
               msgOutiff( MSG__VERB, "", "   tile %d is empty and so will not be "
                          "created", status, tile_index );
            }
         }

/* Free the section of the input NDF. */
         ndfAnnul( &indfs, status );

/* Append the index of this tile in the list of tiles to be created. */
         created_tiles = astGrow( created_tiles, ++(*ntile),
                                  sizeof( *created_tiles ) );
         if( *status == SAI__OK ) created_tiles[ *ntile - 1 ] = tile_index;

      } else {
         msgOutiff( MSG__DEBUG, "", "   Tile %d does not overlap the input "
                    "NDF after trimming.", status, tile_index );
      }
   }
   msgBlank( status );

/* Write the indicies of the created tiles out to a parameter. */
   if( *ntile ) parPut1i( "JSATILELIST", *ntile, created_tiles, status );

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

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

/* End the AST context. */
   astEnd;

}
示例#19
0
void smf_collapse_tseries( const smfData *indata, int nclip, const float clip[],
                           double snrlim, int flagconst, smf_dtype dtype,
                           smfData **outdata,
                           int *status ) {

  /* Per type pointers */
  double *avg_d = NULL;
  double *var_d = NULL;
  int *avg_i = NULL;
  int *var_i = NULL;

  dim_t dims[2];      /* dimensions of data array */
  smfHead *hdr = NULL; /* copy of header */
  AstKeyMap * history = NULL; /* history */
  size_t nbperel;  /* Number of bytes in dtype */
  size_t nelem;   /* number of elements in mean image */
  void *pntr[] = { NULL, NULL }; /* pointers to data */

  if (*status != SAI__OK) return;

  /* see if we have a 2d input (likely reduced) */
  if (indata->ndims == 2 ||
      (indata->ndims == 3 && (indata->dims)[2] == 1) ) {
    *outdata = NULL;
    return;
  }

  /* Trap SMF__NULL */
  if (dtype == SMF__NULL) dtype = indata->dtype;

  /* Get some memory of the right type - data and variance */
  dims[0] = (indata->dims)[0];
  dims[1] = (indata->dims)[1];
  nelem = dims[0] * dims[1];
  nbperel = smf_dtype_sz(dtype, status);
  pntr[0] = astMalloc( nelem*nbperel );
  pntr[1] = astMalloc( nelem*nbperel );


  /* Assign the pointers */
  smf_select_pntr( pntr, dtype, &avg_d, &var_d, &avg_i, &var_i, status );

  if (*status == SAI__OK) {
    dim_t i,j;

    /* get statistics for each bolometer */
    for (i = 0; i < dims[0]; i++) {
      for (j = 0; j < dims[1]; j++) {
        double mean = VAL__BADD;
        double stdev = VAL__BADD;
        double variance = VAL__BADD;
        dim_t index;
        index = ( j * dims[0] ) + i;

        smf_calc_stats( indata, "b", index, 0, 0, nclip, clip,
                        &mean, &stdev, status );

        if (flagconst && stdev == 0.0) {
          mean = VAL__BADD;
          stdev = VAL__BADD;
        }
        if (snrlim > 0 && mean != VAL__BADD && stdev != VAL__BADD
            && stdev != 0.0) {
          double snr;
          snr = fabs(mean/stdev);
          if (snr < snrlim) {
            mean = VAL__BADD;
            stdev = VAL__BADD;
          }
        }
        if (stdev != VAL__BADD) {
          variance = stdev * stdev;
        }

        switch (dtype) {
        case SMF__DOUBLE:
          avg_d[index] = mean;
          var_d[index] = variance;
          break;
        case SMF__INTEGER:
          if (isnan(mean) || mean == VAL__BADD ) {
            avg_i[index] = VAL__BADI;
          } else {
            avg_i[index] = (int)mean;
          }
          if (isnan(stdev) || stdev == VAL__BADD) {
            var_i[index] = VAL__BADI;
          } else if ( variance > (double)VAL__MAXI ) {
            /* overflow. Convert to BAD */
            var_i[index] = VAL__BADI;
            avg_i[index] = VAL__BADI;
          } else {
            var_i[index] = (int)variance;
          }
          break;
        default:
          *status = SAI__ERROR;
          errRep( " ", "Should be impossible to get here", status );
          goto L999;
        }

      }
    }
  }

 L999:

  /* now create a new smfData - we need to copy the header info */
  hdr = smf_deepcopy_smfHead( indata->hdr, status );
  if (indata->history) history = astCopy( indata->history );

  *outdata = smf_construct_smfData( NULL, NULL,  hdr, NULL, NULL,
                                    dtype, pntr, NULL, SMF__QFAM_TSERIES,
                                    NULL, 0, 1, dims, indata->lbnd, 2, 0, 0,
                                    NULL, history, status );

  /* must free the data if outdata is null */
  if (*outdata == NULL) {
    pntr[0] = astFree( pntr[0] );
    pntr[1] = astFree( pntr[1] );
  }

  return;
}
示例#20
0
static void smf1_jsadicer( int indfo, int *olbnd, int *oubnd,
                           AstMapping *tile_map, AstFrame *tile_frm,
                           AstMapping *p2pmap, void *ipd, void *ipv,
                           unsigned char *ipq, int *status ){
/*
*  Name:
*     smf1_jsadicer

*  Purpose:
*     Copy one tile from the input NDF into a specified output NDF.

*  Language:
*     Starlink ANSI C

*  Type of Module:
*     C function

*  Invocation:
*     void smf1_jsadicer( int indfo, int *olbnd, int *oubnd,
*                         AstMapping *tile_map, AstFrame *tile_frm,
*                         AstMapping *p2pmap, void *ipd, void *ipv,
*                         unsigned char *ipq, int *status )

*  Arguments:
*     indfo = int (Given)
*        An identifier for the NDF in which the copied data is to be
*        stored. It's original pixel bounds are used as the bounds of the
*        ipd, ipv and ipq arrays.
*     olbnd = int * (Given)
*        The new lower pixel bounds required for the output NDF. The bounds
*        of the supplied NDF are changed to match these values.
*     oubnd = int * (Given)
*        The new upper pixel bounds required for the output NDF. The bounds
*        of the supplied NDF are changed to match these values.
*     tile_map = AstMapping * (Given)
*        The mapping from pixel coords in the output NDF to WCS coords.
*     tile_frm = AstMapping * (Given)
*        The WCS Frame for the output NDF.
*     p2pmap = AstMapping * (Given)
*        The mapping from pixel coords in the input NDF to pixel coords in
*        the output NDF.
*     ipd = void * (Given)
*        Pointer to the start of the input data array. If this is NULL,
*        the existing contents of the NDF are used as input.
*     ipv = void * (Given)
*        Pointer to the start of the input variance array. Should be NULL
*        if no variances are available.
*     ipq = unsigned char * (Given)
*        Pointer to the start of the input quality array. Should be NULL
*        if no quality is available.
*     status = int * (Given)
*        Pointer to the inherited status variable.
*/

/* Local Variables: */
   AstFrame *use_frm = NULL;
   AstFrameSet *owcs;
   AstMapping *use_map = NULL;
   AstMapping *use_p2pmap = NULL;
   AstShiftMap *sm;
   char type[ NDF__SZTYP + 1 ];
   double shifts[ 3 ];
   int axes[ 2 ];
   int axout[ NDF__MXDIM ];
   int free_arrays;
   int isreal;
   int lbnd_tile[ 3 ];
   int ndim;
   int nel;
   int nin;
   int there;
   int ubnd_tile[ 3 ];
   unsigned char *ipq_out = NULL;
   void *ipd_out = NULL;
   void *ipv_out = NULL;

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

/* Begin an AST context. */
   astBegin;

/* Get the NDF data type - _REAL or _DOUBLE. */
   ndfType( indfo, "Data", type, sizeof(type), status );
   isreal = !strcmp( type, "_REAL" );

/* Get the existing bounds of the NDF. */
   ndfBound( indfo, 3, lbnd_tile, ubnd_tile, &ndim, status );

/* If no data array has been supplied, take a copy of the original Data,
   Quality and Variance arrays and use these as the input arrays. */
   if( !ipd ) {
      free_arrays = 1;

      ndfMap( indfo, "Data", type, "Read", &ipd_out, &nel, status );
      ipd = astStore( NULL, ipd_out,
                      nel*(isreal?sizeof(float):sizeof(double)) );
      ndfUnmap( indfo, "Data", status );

      ndfState( indfo, "Variance", &there, status );
      if( there ) {
         ndfMap( indfo, "Variance", type, "Read", &ipv_out, &nel, status );
         ipv = astStore( NULL, ipv_out,
                         nel*(isreal?sizeof(float):sizeof(double)) );
         ndfUnmap( indfo, "Variance", status );
      } else {
         ipv = NULL;
      }

      ndfState( indfo, "Quality", &there, status );
      if( there ) {
         ndfMap( indfo, "Quality", "_UBYTE", "Read", (void **) &ipq_out,
                 &nel, status );
         ipq = astStore( NULL, ipq_out, nel*sizeof(*ipq) );
         ndfUnmap( indfo, "Quality", status );
      } else {
         ipq = NULL;
      }

   } else {
      free_arrays = 0;
   }

/* Set the bounds of the NDF to the required values. */
   ndfSbnd( ndim, olbnd, oubnd, indfo, status );

/* Erase the existing WCS FrameSet and then get the default WCS FrameSet. */
   ndfReset( indfo, "WCS", status );
   ndfGtwcs( indfo, &owcs, status );

/* If the supplied mapping and Frame have two many axes, strip some off.
   The orering of pixel axes in the output JSA tile is hardwired by SMURF
   as (ra,dec,spec). */
   nin = astGetI( tile_map, "Nin" );
   if( nin == 3 && ndim == 2 ) {
      axes[ 0 ] = 1;
      axes[ 1 ] = 2;
      astMapSplit( tile_map, 2, axes, axout, &use_map );
      if( use_map ) {
         use_frm = astPickAxes( tile_frm, 2, axout, NULL );
      } else if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( " ", "smf1_jsadicer: cannot split mapping (programming "
                  "error).", status );
      }

      astMapSplit( p2pmap, 2, axes, axout, &use_p2pmap );
      if( !use_p2pmap && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( " ", "smf1_jsadicer: cannot split mapping (programming "
                  "error).", status );
      }

   } else if( nin == ndim ) {
      use_p2pmap = astClone( p2pmap );
      use_map = astClone( tile_map );
      use_frm = astClone( tile_frm );

   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRepf( " ", "smf1_jsadicer: unexpected combination of nin (%d) and "
               "ndim (%d) (programming error).", status, nin, ndim );
   }

/* Add the tile WCS Frame into the output NDF's WCS FrameSet, using "tilemap"
   to connect it to the PIXEL Frame (NDF ensure Frame 2 is the PIXEL
   Frame). */
   astAddFrame( owcs, 2, use_map, use_frm );

/* The astResample function is odd in that it assumes that pixel coords
   are defined such that the centre of pixel "I" has integral pixel
   coord "I" (rather than "I-0.5" as is usual in Starlink). So we need to
   use a half-pixel ShiftMap at start and end of the p2pmap Mapping to
   account for this. */
   shifts[ 0 ] = -0.5;
   shifts[ 1 ] = -0.5;
   shifts[ 2 ] = -0.5;
   sm = astShiftMap( ndim, shifts, " " );
   use_p2pmap = (AstMapping *) astCmpMap( sm, use_p2pmap, 1, " " );
   astInvert( sm );
   use_p2pmap = (AstMapping *) astCmpMap( use_p2pmap, sm, 1, " " );

/* Store this modified WCS FrameSet in the output NDF. */
   ndfPtwcs( owcs, indfo, status );

/* Map the required arrays of the output NDF. */
   ndfMap( indfo, "Data", type, "Write", &ipd_out, &nel, status );
   if( ipv ) ndfMap( indfo, "Variance", type, "Write", &ipv_out, &nel,
                     status );
   if( ipq ) ndfMap( indfo, "Quality", "_UBYTE", "Write",
                      (void **) &ipq_out, &nel, status );

/* Copy the input data values to the output, using nearest neighbour
   interpolation (the mapping should always map input pixel centres onto
   output pixel centres). We can set the "tol" argument non-zero (e.g. 0.1)
   without introducing any error because the the p2pmap mapping will be
   piecewise linear. This gives a factor of about 5 decrease in the time
   spent within astResample. */
   if( !strcmp( type, "_REAL" ) ) {
      (void) astResampleF( use_p2pmap, ndim, lbnd_tile, ubnd_tile, (float *) ipd,
                           (float *) ipv, AST__NEAREST, NULL, NULL,
                           AST__USEBAD, 0.1, 1000, VAL__BADR, ndim,
                           olbnd, oubnd, olbnd, oubnd,
                           (float *) ipd_out, (float *) ipv_out );
   } else {
      (void) astResampleD( use_p2pmap, ndim, lbnd_tile, ubnd_tile, (double *) ipd,
                           (double *) ipv, AST__NEAREST, NULL, NULL,
                           AST__USEBAD, 0.1, 1000, VAL__BADD, ndim,
                           olbnd, oubnd, olbnd, oubnd,
                           (double *) ipd_out, (double *) ipv_out );
   }

   if( ipq ) {
      (void) astResampleUB( use_p2pmap, ndim, lbnd_tile, ubnd_tile, ipq, NULL,
                            AST__NEAREST, NULL, NULL, 0, 0.1, 1000, 0,
                            ndim, olbnd, oubnd, olbnd, oubnd, ipq_out,
                            NULL );
   }

/* Unmap everything the output NDF. */
   ndfUnmap( indfo, "*", status );

/* Free the input arrays if they were allocated in this function. */
   if( free_arrays ) {
      ipd = astFree( ipd );
      ipv = astFree( ipv );
      ipq = astFree( ipq );
   }

/* End the AST context. */
   astEnd;
}
示例#21
0
void smf_calcmodel_gai( ThrWorkForce *wf, smfDIMMData *dat, int chunk,
                        AstKeyMap *keymap, smfArray **allmodel, int flags,
                        int *status) {

  /* Local Variables */
  size_t bstride;               /* bolometer stride */
  dim_t gain_box=0;             /* No. of time slices in a block */
  size_t gbstride;              /* GAIn bolo stride */
  size_t gcstride;              /* GAIn coeff stride */
  int gflat=0;                  /* correct flatfield using GAI */
  dim_t i;                      /* Loop counter */
  dim_t idx=0;                  /* Index within subgroup */
  dim_t j;                      /* Loop counter */
  AstKeyMap *kmap=NULL;         /* Local GAIn keymap */
  smfArray *model=NULL;         /* Pointer to model at chunk */
  double *model_data=NULL;      /* Pointer to DATA component of model */
  dim_t nblock;                 /* No. of time slice blocks */
  dim_t nbolo;                  /* Number of bolometers */
  dim_t ndata;                  /* Number of data points */
  smfArray *noi=NULL;           /* Pointer to NOI at chunk */
  double *noi_data=NULL;        /* Pointer to DATA component of model */
  size_t noibstride;            /* bolo stride for noise */
  dim_t nointslice;             /* number of time slices for noise */
  size_t noitstride;            /* Time stride for noise */
  dim_t npar;                   /* No. of parameters per bolometer */
  dim_t ntslice;                /* Number of time slices */
  int oldalg = 1;               /* Is the old COM algorithm being used? */
  smfArray *qua=NULL;           /* Pointer to QUA at chunk */
  smf_qual_t *qua_data=NULL; /* Pointer to quality data */
  smfArray *res=NULL;           /* Pointer to RES at chunk */
  double *res_data=NULL;        /* Pointer to DAT */
  double *scale;                /* Pointer to scale factor */
  size_t tstride;               /* time slice stride */
  double *wg;                   /* Workspace holding time slice gains */
  double *woff;                 /* Workspace holding time slice offsets */

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

  /* See if the new sigma-clipping COM algorithm is being used. */
  astMapGet0A( keymap, "COM", &kmap );
  astMapGet0I( kmap, "OLDALG", &oldalg );
  kmap = astAnnul( kmap );

  /* Obtain pointer to sub-keymap containing GAI parameters */
  if( !astMapHasKey( keymap, "GAI" ) ) return;
  astMapGet0A( keymap, "GAI", &kmap );

  astMapGet0I( kmap, "FLATFIELD", &gflat );
  if( kmap ) kmap = astAnnul( kmap );

  /* Report an error if gai.flatfield is used with the new COM algorithm. */
  if( !oldalg && gflat && *status == SAI__OK ) {
     errRep( "", "Cannot use GAI.FLATFIELD with new COM algorithm.", status );
  }

  /* Only have to do something if gai.flatfield set */
  if( !gflat || *status != SAI__OK ) return;

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

  /* Get the number of blocks into which to split each time series. Each box
     (except possibly the last one contains "gain_box" time slices. */
  astMapGet0A( keymap, "COM", &kmap );
  smf_get_nsamp( kmap, "GAIN_BOX", res->sdata[0], &gain_box, status );
  if (kmap) kmap = astAnnul( kmap );
  if (*status != SAI__OK) return;

  /* Ensure everything is in bolo-order */
  smf_model_dataOrder( wf, dat, allmodel, chunk, SMF__RES|SMF__QUA|SMF__NOI, 0, status );

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

    /* Get pointers to DATA components */
    res_data = (res->sdata[idx]->pntr)[0];
    qua_data = (qua->sdata[idx]->pntr)[0];
    model_data = (model->sdata[idx]->pntr)[0];
    if( noi ) {
      smf_get_dims( noi->sdata[idx],  NULL, NULL, NULL, &nointslice,
                    NULL, &noibstride, &noitstride, status);
      noi_data = (double *)(noi->sdata[idx]->pntr)[0];
    }

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

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

      smf_get_dims( model->sdata[idx],  NULL, NULL, NULL, &npar, NULL,
                    &gbstride, &gcstride, status);

      /* If com.gain_box is zero, use a value of ntslice, so that a single
         box will be used covering the whoel time stream. */
      if( gain_box == 0 ) gain_box = ntslice;

      /* Allocate work space for the gain and offset for each time slice. */
      woff = astMalloc( ntslice*sizeof( *woff ) );
      wg = astMalloc( ntslice*sizeof( *wg ) );

      /* Get the number of blocks into which the time stream is divided.
         Each block has a separate gain, offset and correlation factor
         for each bolometer. */
      nblock = npar/3;

      /* Undo the gain correction stored in GAI (the gain is applied to
         the signal and noise in smf_calcmodel_com) */
      for( i=0; i<nbolo; i++ ) {
        if( !(qua_data[i*bstride]&SMF__Q_BADB) ) {

          /* Get the gain and offset for each time slice of this bolometer. */
          smf_gandoff( i, 0, ntslice - 1, ntslice, gbstride, gcstride,
                       model_data, nblock, gain_box, wg, woff, NULL, status );

          /* First undo the flatfield correction to the signal */
          scale = wg;
          for( j=0; j<ntslice; j++,scale++ ) {
            if( !(qua_data[i*bstride + j*tstride]&SMF__Q_MOD) &&
                *scale != VAL__BADD && *scale > 0.0 ) {
              res_data[i*bstride + j*tstride] *= *scale;
            }
          }

          /* Then scale the noise. */
          if( noi ) {
            scale = wg;
            for( j=0; j<nointslice; j++,scale++ ) {
              if( noi_data[i*noibstride + j*noitstride] != VAL__BADD &&
                  *scale != VAL__BADD && *scale > 0.0 ) {
                noi_data[i*noibstride + j*noitstride] *= (*scale) * (*scale);
              }
            }
          }
        }
      }

      /* Free work space. */
      woff = astFree( woff );
      wg = astFree( wg );

    }
  }

}
示例#22
0
void smf_addcom( ThrWorkForce *wf, smfData *data, const double *com,
                 int *status ) {

    /* Local Variables */
    dim_t nbolo;
    dim_t ntslice;
    dim_t step;
    int iw;
    int nw;
    smfAddComData *job_data;
    smfAddComData *pdata;

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

    /* Check supplied smfData is time ordered (i.e. bstride=1, tstride=nbolo). */
    if( !data->isTordered ) {
        *status = SAI__ERROR;
        errRep( " ", "smf_addcom: Supplied smfData is not time-ordered.",
                status );
    }

    /* Note the number of time slices and bolometers. */
    smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, NULL, NULL, NULL,
                  status );

    /* Store the number of workers in the work force. */
    nw = wf ? wf->nworker : 1;

    /* Allocate job data for threads */
    job_data = astMalloc( nw*sizeof(*job_data) );
    if( *status == SAI__OK ) {

        /* Get the number of time slices to process in each thread. */
        if( nw > (int) ntslice ) {
            step = 1;
        } else {
            step = ntslice/nw;
        }

        /* Set up the job data for each thread. */
        for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;

            /* The first and last time slice to be processed by the thread. */
            pdata->t1 = iw*step;
            if( iw < nw - 1 ) {
                pdata->t2 = ( iw + 1 )*step - 1;
            } else {
                pdata->t2 = ntslice - 1;
            }

            /* Pointer to the first output data element for the first time slice. */
            pdata->out = ( (double *) data->pntr[0] ) + pdata->t1*nbolo;

            /* Pointer to the first COM data element. */
            pdata->com = com + pdata->t1;

            /* Number of bolometers. */
            pdata->nbolo = nbolo;
        }

        /* Add each job to the job queue. */
        for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            (void) thrAddJob( wf, 0, pdata, smf1AddCom, 0, NULL, status );
        }

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

    /* Free resources. */
    job_data = astFree( job_data );
}
示例#23
0
void smf_rebinsparse( smfData *data, int first, int *ptime, AstFrame *ospecfrm,
                      AstMapping *ospecmap, AstSkyFrame *oskyframe,
                      Grp *detgrp, int lbnd_out[ 3 ], int ubnd_out[ 3 ],
                      int genvar, float *data_array, float *var_array,
                      int *ispec, float *texp_array, float *teff_array,
                      double *fcon, int *status ){

/* Local Variables */
   AstCmpMap *fmap = NULL;      /* Mapping from spectral grid to topo freq Hz */
   AstCmpMap *ssmap = NULL;     /* I/p GRID-> o/p PIXEL Mapping for spectral axis */
   AstFitsChan *fc = NULL;      /* Storage for FITS headers */
   AstFrame *specframe = NULL;  /* Spectral Frame in input FrameSet */
   AstFrame *specframe2 = NULL; /* Temporary copy of SpecFrame in input WCS */
   AstFrameSet *fs = NULL;      /* A general purpose FrameSet pointer */
   AstFrameSet *swcsin = NULL;  /* FrameSet describing spatial input WCS */
   AstMapping *fsmap = NULL;    /* Base->Current Mapping extracted from a FrameSet */
   AstMapping *specmap = NULL;  /* PIXEL -> Spec mapping in input FrameSet */
   char *fftwin = NULL;  /* Name of FFT windowing function */
   const char *name = NULL; /* Pointer to current detector name */
   const double *tsys=NULL; /* Pointer to Tsys value for first detector */
   dim_t timeslice_size; /* No of detector values in one time slice */
   double *spectab = NULL;/* Workspace for spectral output grid positions */
   double *xin = NULL;   /* Workspace for detector input grid positions */
   double *xout = NULL;  /* Workspace for detector output pixel positions */
   double *yin = NULL;   /* Workspace for detector input grid positions */
   double *yout = NULL;  /* Workspace for detector output pixel positions */
   double at;            /* Frequency at which to take the gradient */
   double dnew;          /* Channel width in Hz */
   double fcon2;         /* Variance factor for whole file */
   double k;             /* Back-end degradation factor */
   double tcon;          /* Variance factor for whole time slice */
   float *pdata = NULL;  /* Pointer to next data sample */
   float *qdata = NULL;  /* Pointer to next data sample */
   float rtsys;          /* Tsys value */
   float teff;           /* Effective integration time, times 4 */
   float texp;           /* Total time ( = ton + toff ) */
   float toff;           /* Off time */
   float ton;            /* On time */
   int *nexttime = NULL; /* Pointer to next time slice index to use */
   int dim[ 3 ];         /* Output array dimensions */
   int found;            /* Was current detector name found in detgrp? */
   int good;             /* Are there any good detector samples? */
   int ibasein;          /* Index of base Frame in input FrameSet */
   int ichan;            /* Index of current channel */
   int iv;               /* Offset to next element */
   int iz;               /* Output grid index on axis 3 */
   int nchan;            /* Number of input spectral channels */
   int pixax[ 3 ];       /* The output fed by each selected mapping input */
   int specax;           /* Index of spectral axis in input FrameSet */
   size_t irec;          /* Index of current input detector */
   size_t itime;         /* Index of current time slice */
   smfHead *hdr = NULL;  /* Pointer to data header for this time slice */

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

/* Begin an AST context.*/
   astBegin;

/* Store a pointer to the input NDFs smfHead structure. */
   hdr = data->hdr;

/* Store the dimensions of the output array. */
   dim[ 0 ] = ubnd_out[ 0 ] - lbnd_out[ 0 ] + 1;
   dim[ 1 ] = ubnd_out[ 1 ] - lbnd_out[ 1 ] + 1;
   dim[ 2 ] = ubnd_out[ 2 ] - lbnd_out[ 2 ] + 1;

/* Store the number of pixels in one time slice */
   timeslice_size = (data->dims)[ 0 ]*(data->dims)[ 1 ];

/* We want a description of the spectral WCS axis in the input file. If
   the input file has a WCS FrameSet containing a SpecFrame, use it,
   otherwise we will obtain it from the FITS header later. NOTE, if we knew
   that all the input NDFs would have the same spectral axis calibration,
   then the spectral WCS need only be obtained from the first NDF. However,
   in the general case, I presume that data files may be combined that use
   different spectral axis calibrations, and so these differences need to
   be taken into account. */
   if( hdr->tswcs ) {
      fs = astClone( hdr->tswcs );

/* The first axis should be a SpecFrame. See if this is so. If not annul
   the specframe pointer. */
      specax = 1;
      specframe = astPickAxes( fs, 1, &specax, NULL );
      if( !astIsASpecFrame( specframe ) ) specframe = astAnnul( specframe );
   }

/* If the above did not yield a SpecFrame, use the FITS-WCS headers in the
   FITS extension of the input NDF. Take a copy of the FITS header (so that
   the contents of the header are not changed), and then read a FrameSet
   out of it. */
   if( !specframe ) {
      fc = astCopy( hdr->fitshdr );
      astClear( fc, "Card" );
      fs = astRead( fc );

/* Extract the SpecFrame that describes the spectral axis from the current
   Frame of this FrameSet. This is assumed to be the third WCS axis (NB
   the different axis number). */
      specax = 3;
      specframe = astPickAxes( fs, 1, &specax, NULL );
   }

/* Split off the 1D Mapping for this single axis from the 3D Mapping for
   the whole WCS. This results in "specmap" holding the Mapping from
   SpecFrame value to GRID value. */
   fsmap = astGetMapping( fs, AST__CURRENT, AST__BASE );
   astMapSplit( fsmap, 1, &specax, pixax, &specmap );

/* Invert the Mapping for the spectral axis so that it goes from input GRID
   coord to spectral coord. */
   astInvert( specmap );

/* Get a Mapping that converts values in the input spectral system to the
   corresponding values in the output spectral system. */
   fs = astConvert( specframe, ospecfrm, "" );

/* Concatenate these Mappings with the supplied spectral Mapping to get
   a Mapping from the input spectral grid axis (pixel axis 1) to the
   output spectral grid axis (pixel axis 3). Simplify the Mapping. */
   ssmap = astCmpMap( astCmpMap( specmap, astGetMapping( fs, AST__BASE,
                                                         AST__CURRENT ),
                                 1, " " ),
                      ospecmap, 1, " " );
   ssmap = astSimplify( ssmap );

/* Create a table with one element for each channel in the input array,
   holding the index of the nearest corresponding output channel. */
   nchan = (data->dims)[ 0 ];
   spectab = astMalloc( sizeof( *spectab )*nchan );
   if( spectab ) {
      for( ichan = 0; ichan < nchan; ichan++ ) spectab[ ichan ] = ichan + 1;
      astTran1( ssmap, nchan, spectab, 1, spectab );
      for( ichan = 0; ichan < nchan; ichan++ ) {
         if( spectab[ ichan ] != AST__BAD ) {
            iz = floor( spectab[ ichan ] + 0.5 );
            if( iz >= 1 && iz <= dim[ 2 ] ) {
               spectab[ ichan ] = iz;
            } else {
               spectab[ ichan ] = 0;
            }
         } else {
            spectab[ ichan ] = 0;
         }
      }
   }

/* Allocate work arrays big enough to hold the coords of all the
   detectors in the current input file.*/
   xin = astMalloc( (data->dims)[ 1 ] * sizeof( *xin ) );
   yin = astMalloc( (data->dims)[ 1 ] * sizeof( *yin ) );
   xout = astMalloc( (data->dims)[ 1 ] * sizeof( *xout ) );
   yout = astMalloc( (data->dims)[ 1 ] * sizeof( *yout ) );

/* Initialise a string to point to the name of the first detector for which
   data is available */
   name = hdr->detname;

/* Store input coords for the detectors. Axis 1 is the detector index, and
   axis 2 is a dummy axis that always has the value 1. */
   for( irec = 0; irec < (data->dims)[ 1 ]; irec++ ) {
      xin[ irec ] = irec + 1.0;
      yin[ irec ] = 1.0;

/* If a group of detectors to be used was supplied, search the group for
   the name of the current detector. If not found, set the GRID coords bad. */
      if( detgrp ) {
         found = grpIndex( name, detgrp, 1, status );
         if( !found ) {
            xin[ irec ] = AST__BAD;
            yin[ irec ] = AST__BAD;
         }
      }

/* Move on to the next available detector name. */
      name += strlen( name ) + 1;
   }

/* Find the constant factor associated with the current input file. This
   is the squared backend degradation factor, divided by the noise bandwidth.
   Get the required FITS headers, checking they were found. */
   if( astGetFitsF( hdr->fitshdr, "BEDEGFAC", &k ) &&
       astGetFitsS( hdr->fitshdr, "FFT_WIN", &fftwin ) ){

/* Get a Mapping that converts values in the input spectral system to
   topocentric frequency in Hz, and concatenate this Mapping with the
   Mapping from input GRID coord to the input spectral system. The result
   is a Mapping from input GRID coord to topocentric frequency in Hz. */
      specframe2 = astCopy( specframe );
      astSet( specframe2, "system=freq,stdofrest=topo,unit=Hz" );
      fmap = astCmpMap( specmap, astGetMapping( astConvert( specframe,
                                                            specframe2,
                                                            "" ),
                                                AST__BASE, AST__CURRENT ),
                        1, " " );

/* Differentiate this Mapping at the mid channel position to get the width
   of an input channel in Hz. */
      at = 0.5*nchan;
      dnew = astRate( fmap, &at, 1, 1 );

/* Modify the channel width to take account of the effect of the FFT windowing
   function. Allow undef value because FFT_WIN for old data had a broken value
   in hybrid subband modes. */
      if( dnew != AST__BAD ) {
         dnew = fabs( dnew );

         if( !strcmp( fftwin, "truncate" ) ) {
            dnew *= 1.0;

         } else if( !strcmp( fftwin, "hanning" ) ) {
            dnew *= 1.5;

	    } else if( !strcmp( fftwin, "<undefined>" ) ) {
	      /* Deal with broken data - make an assumption */
	       dnew *= 1.0;

         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            msgSetc( "W", fftwin );
            errRep( FUNC_NAME, "FITS header FFT_WIN has unknown value "
                    "'^W' (programming error).", status );
         }

/* Form the required constant. */
         fcon2 = k*k/dnew;

      } else {
         fcon2 = VAL__BADD;
      }

   } else {
      fcon2 = VAL__BADD;
   }

/* Return the factor needed for calculating Tsys from the variance. */
   if( first ) {
      *fcon = fcon2;
   } else if( fcon2 != *fcon ) {
      *fcon = VAL__BADD;
   }

/* Initialise a pointer to the next time slice index to be used. */
   nexttime = ptime;

/* Loop round all the time slices in the input file. */
   for( itime = 0; itime < (data->dims)[ 2 ] && *status == SAI__OK; itime++ ) {

/* If this time slice is not being pasted into the output cube, pass on. */
      if( nexttime ){
         if( *nexttime != itime ) continue;
         nexttime++;
      }

/* Store a pointer to the first input data value in this time slice. */
      pdata = ( (float *) (data->pntr)[ 0 ] ) + itime*timeslice_size;

/* Get a FrameSet describing the spatial coordinate systems associated with
   the current time slice of the current input data file. The base frame in
   the FrameSet will be a 2D Frame in which axis 1 is detector number and
   axis 2 is unused. The current Frame will be a SkyFrame (the SkyFrame
   System may be any of the JCMT supported systems). The Epoch will be
   set to the epoch of the time slice. */
      smf_tslice_ast( data, itime, 1, NO_FTS, status );
      swcsin = hdr->wcs;

/* Note the total exposure time (texp) for all the input spectra produced by
   this time slice. */
      ton = hdr->state->acs_exposure;
      if( ton == 0.0 ) ton = VAL__BADR;

      toff = hdr->state->acs_offexposure;
      if( toff == 0.0 ) toff = VAL__BADR;

      if( ton != VAL__BADR && toff != VAL__BADR ) {
         texp = ton + toff;
         teff = 4*ton*toff/( ton + toff );
      } else {
         texp = VAL__BADR;
         teff = VAL__BADR;
      }

/* If output variances are being calculated on the basis of Tsys values
   in the input, find the constant factor associated with the current
   time slice. */
      tcon = AST__BAD;
      if( genvar == 2 && fcon2 != AST__BAD && texp != VAL__BADR ) {
         tcon = fcon2*( 1.0/ton + 1.0/toff );

/* Get a pointer to the start of the Tsys values for this time slice. */
         tsys = hdr->tsys + hdr->ndet*itime;
      }

/* We now create a Mapping from detector index to position in oskyframe. */
      astInvert( swcsin );
      ibasein = astGetI( swcsin, "Base" );
      fs = astConvert( swcsin, oskyframe, "SKY" );
      astSetI( swcsin, "Base", ibasein );
      astInvert( swcsin );

      if( fs == NULL ) {
         if( *status == SAI__OK ) {
            if (data->file) {
               smf_smfFile_msg(data->file, "FILE", 1, "<unknown>");
            } else {
               msgSetc( "FILE", "<unknown>" );
            }
            *status = SAI__ERROR;
            errRep( FUNC_NAME, "The spatial coordinate system in ^FILE "
                    "is not compatible with the spatial coordinate "
                    "system in the first input file.", status );
         }
         break;
      }

/* Transform the positions of the detectors from input GRID to oskyframe
   coords. */
      astTran2( fs, (data->dims)[ 1 ], xin, yin, 1, xout, yout );

/* Loop round all detectors. */
      for( irec = 0; irec < (data->dims)[ 1 ]; irec++ ) {

/* If the detector has a valid position, see if it produced any good
   data values. */
         if( xout[ irec ] != AST__BAD && yout[ irec ] != AST__BAD ) {
            qdata = pdata;
            good = 0;
            for( ichan = 0; ichan < nchan; ichan++ ){
               if( *(qdata++) != VAL__BADR ) {
                  good = 1;
                  break;
               }
            }

/* If it did, calculate the variance associated with each detector
   sample (if required), based on the input Tsys values, and copy the
   spectrum to the output NDF. */
            if( good ) {
               if( *ispec < dim[ 0 ] ){
                  rtsys = tsys ? (float) tsys[ irec ] : VAL__BADR;
                  if( rtsys <= 0.0 ) rtsys = VAL__BADR;
                  if( tcon != AST__BAD && genvar == 2 && rtsys != VAL__BADR ) {
                     var_array[ *ispec ] = tcon*rtsys*rtsys;
                  } else if( var_array ) {
                     var_array[ *ispec ] = VAL__BADR;
                  }

                  if( texp != VAL__BADR ) {
                     texp_array[ *ispec ] = texp;
                     teff_array[ *ispec ] = teff;
                  }

                  for( ichan = 0; ichan < nchan; ichan++, pdata++ ) {
                     iz = spectab[ ichan ] - 1;
                     if( iz >= 0 && iz < dim[ 2 ] ) {
                        iv = *ispec + dim[ 0 ]*iz;
                        data_array[ iv ] = *pdata;
                     }
                  }

                  (*ispec)++;

               } else if( *status == SAI__OK ){
                  *status = SAI__ERROR;
                  msgSeti( "DIM", dim[ 0 ] );
                  errRep( " ", "Too many spectra (more than ^DIM) for "
                          "the output NDF (programming error).", status );
                  break;
               }

/* If this detector does not have any valid data values, increment the data
   pointer to point at the first sample for the next detector. */
            } else {
               pdata += nchan;
            }

/* If this detector does not have a valid position, increment the data
   pointer to point at the first sample for the next detector. */
         } else {
            pdata += nchan;
         }
      }

/* For efficiency, explicitly annul the AST Objects created in this tight
   loop. */
      fs = astAnnul( fs );
   }

/* Free resources */
   spectab = astFree( spectab );
   xin = astFree( xin );
   yin = astFree( yin );
   xout = astFree( xout );
   yout = astFree( yout );

/* End the AST context. This will annul all AST objects created within the
   context (except for those that have been exported from the context). */
   astEnd;
}
示例#24
0
void smf_rebinmap1( ThrWorkForce *wf, smfData *data, smfData *variance, int *lut,
                    size_t tslice1, size_t tslice2, int trange,
                    int *whichmap, dim_t nmap, smf_qual_t mask, int sampvar,
                    int flags, double *map, double *mapweight,
                    double *mapweightsq, int *hitsmap,
                    double *mapvar, dim_t msize, double *scalevariance,
                    int *status ) {

  /* Local Variables */
  SmfRebinMap1Data *job_data = NULL;
  SmfRebinMap1Data *pdata;
  double *dat=NULL;          /* Pointer to data array */
  size_t dbstride;           /* bolo stride of data */
  size_t dtstride;           /* tstride of data */
  int iw;                    /* Thread index */
  dim_t mbufsize;            /* Size of full (multi-map) map buffers */
  dim_t nbolo;               /* number of bolos */
  dim_t ntslice;             /* number of time slices */
  int nw;                    /* Number of worker threads */
  size_t pixstep;            /* Number of map pixels per thread */
  dim_t bolostep;            /* Number of bolos per thread */
  smf_qual_t * qual = NULL;  /* Quality pointer */
  double scalevar;           /* variance scale factor */
  double scaleweight;        /* weights for calculating scalevar */
  size_t t1, t2;             /* range of time slices to re-grid */
  double *var=NULL;          /* Pointer to variance array */
  size_t vbstride;           /* bolo stride of variance */
  dim_t vnbolo;              /* number of bolos in variance */
  dim_t vntslice;            /* number of bolos in variance */
  size_t vtstride;           /* tstride of variance */

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

  /* Check inputs */
  if( !data || !map || !lut || !mapweight || !mapweightsq || !mapvar ||
      !hitsmap ) {
    *status = SAI__ERROR;
    errRep(" ", FUNC_NAME ": Null inputs", status );
    return;
  }

  if( !data->pntr[0] ) {
    *status = SAI__ERROR;
    errRep(" ", FUNC_NAME ": supplied data is empty", status );
    return;
  }

  dat = data->pntr[0];
  qual = smf_select_qualpntr( data, NULL, status );
  smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, NULL, &dbstride,
                &dtstride, status );

  /* Size of full map buffers */
  if( whichmap ) {
    mbufsize = nmap * msize;
  } else {
    mbufsize = msize;
  }

  if( variance ) {
    var = variance->pntr[0];
    smf_get_dims( variance, NULL, NULL, &vnbolo, &vntslice, NULL, &vbstride,
                  &vtstride, status );

    /* Check that the variance dimensions are compatible with data */
    if( (*status==SAI__OK) &&
        ((vnbolo != nbolo) || ((vntslice>1)&&(vntslice!=ntslice))) ) {
      *status = SAI__ERROR;
      errRep(" ", FUNC_NAME ": variance dimensions incompatible with data",
             status );
      return;
    }
  }

  /* Range of time slices to regrid */
  if( trange ) {

    if( tslice2 >= ntslice ) {
      *status = SAI__ERROR;
      errRepf( "", FUNC_NAME ": tslice2 (%zu) can't be >= ntslice (%zu)",
               status, tslice2, ntslice );
      return;
    }

    if( tslice1 > tslice2  ) {
      *status = SAI__ERROR;
      errRepf( "", FUNC_NAME ": tslice1 (%zu) > tslice2 (%zu)",
               status, tslice1, tslice2 );
      return;
    }

    t1 = tslice1;
    t2 = tslice2;
  } else {
    t1 = 0;
    t2 = ntslice-1;
  }

  /* How many threads do we get to play with */
  nw = wf ? wf->nworker : 1;

  /* If this is the first data to be accumulated zero the arrays */
  if( flags & AST__REBININIT ) {
    memset( map, 0, nw*mbufsize*sizeof(*map) );
    memset( mapweight, 0, nw*mbufsize*sizeof(*mapweight) );
    memset( mapweightsq, 0, nw*mbufsize*sizeof(*mapweightsq) );
    memset( mapvar, 0, nw*mbufsize*sizeof(*mapvar) );
    memset( hitsmap, 0, nw*mbufsize*sizeof(*hitsmap) );
  }

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

  /* Allocate job data for threads, and store the range of bolos to be
     processed by each one. Ensure that the last thread picks up any
     left-over bolos. */
  job_data = astCalloc( nw, sizeof(*job_data) );
  if( *status == SAI__OK ) {
    for( iw = 0; iw < nw; iw++ ) {
      pdata = job_data + iw;
      pdata->p1 = iw*bolostep;
      if( iw < nw - 1 ) {
        pdata->p2 = pdata->p1 + bolostep - 1;
      } else {
        pdata->p2 = nbolo - 1 ;
      }

/* Store other values common to all jobs. */
      pdata->msize = msize;
      pdata->nbolo = nbolo;
      pdata->t1 = t1;
      pdata->t2 = t2;
      pdata->vntslice = vntslice;
      pdata->dat = dat;
      pdata->map = map;
      pdata->mapvar = mapvar;
      pdata->mapweightsq = mapweightsq;
      pdata->mapweight = mapweight;
      pdata->var = var;
      pdata->hitsmap = hitsmap;
      pdata->lut = lut;
      pdata->whichmap = whichmap;
      pdata->dbstride = dbstride;
      pdata->dtstride = dtstride;
      pdata->vbstride = vbstride;
      pdata->vtstride = vtstride;
      pdata->mask = mask;
      pdata->qual = qual;
      pdata->mbufsize = mbufsize;
      pdata->nw = nw; /* used for final summing/rescaling */
      pdata->iw = iw; /* so the thread knows with chunk it's working on */
    }
  }

  if( var ) {
    /* Accumulate data and weights in the case that variances are given*/

    if( sampvar ) {

      /* Measure weighted sample variance for varmap */
      if( qual ) {       /* QUALITY checking version */

        /* Set up jobs to add the previous estimate of COM back on to the
           residuals, and then wait for the jobs to complete. These jobs also
           clear any SMF__Q_COM flags set by previous iterations. */
        for( iw = 0; iw < nw; iw++ ) {
           pdata = job_data + iw;
           pdata->operation = 1;
           thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
        }
        thrWait( wf, status );

      } else {           /* VAL__BADD checking version */
        for( iw = 0; iw < nw; iw++ ) {
           pdata = job_data + iw;
           pdata->operation = 2;
           thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
        }
        thrWait( wf, status );

      }

    } else {
      /* Otherwise use simple error propagation for varmap */

      if( qual ) {       /* QUALITY checking version */
        for( iw = 0; iw < nw; iw++ ) {
           pdata = job_data + iw;
           pdata->operation = 3;
           thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
        }
        thrWait( wf, status );

      } else {           /* VAL__BADD checking version */
        for( iw = 0; iw < nw; iw++ ) {
           pdata = job_data + iw;
           pdata->operation = 4;
           thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
        }
        thrWait( wf, status );

      }
    }

  } else {
    /* Accumulate data and weights when no variances are given. In this case
       the variance map is always estimated from the sample variance */

    if( qual ) {       /* QUALITY checking version */
      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        pdata->operation = 5;
        thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
      }
      thrWait( wf, status );

    } else {           /* VAL__BADD checking version */
      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        pdata->operation = 6;
        thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
      }
      thrWait( wf, status );
    }
  }

  /* If this is the last data to be accumulated re-normalize */
  if( flags & AST__REBINEND ) {

  /* Find how many buffer pixels to process in each worker thread. */
    pixstep = mbufsize/nw;
    if( pixstep == 0 ) pixstep = 1;

    for( iw = 0; iw < nw; iw++ ) {
      pdata = job_data + iw;
      pdata->p1 = iw*pixstep;
      if( iw < nw - 1 ) {
        pdata->p2 = pdata->p1 + pixstep - 1;
      } else {
        pdata->p2 = mbufsize - 1 ;
      }
    }

    if( sampvar || !var ) {

      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        pdata->operation = 7;
        thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
      }
      thrWait( wf, status );

      scaleweight=0;
      scalevar=0;
      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        scaleweight += pdata->scaleweight;
        scalevar += pdata->scalevar;
      }

      /* Re-normalize scalevar */
      if( scaleweight ) {
        scalevar /= scaleweight;

        if( scalevariance ) {
          *scalevariance = scalevar;
        }
      }

    } else {
      /* Re-normalization for error propagation case */

      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        pdata->operation = 8;
        thrAddJob( wf, 0, pdata, smf1_rebinmap1, 0, NULL, status );
      }
      thrWait( wf, status );

    }
  }

  job_data = astFree( job_data );

}
示例#25
0
void
smf_flat_standardpow( const smfData * bolvald, double refohms,
                      const double resistance[],
                      smfData ** powrefd, smfData ** bolrefd, int * status) {

  double current;         /* current through heaters */
  double *heatframe = NULL; /* Pointer to flatfield heater data  */
  double *heatframevar = NULL; /* Pointer to flatfield heatframe variance */
  double * heatref = NULL; /* local copy of heater settings */
  size_t i;               /* loop counter */
  size_t j;               /* loop counter */
  size_t k;               /* loop counter */
  size_t nheat;           /* Number of input frames */
  size_t numbol;          /* Number of bolometers */
  double *powbol = NULL;  /* pointer to individual bolometer powers */
  double s;               /* interpolation slope factor */

  double * powref = NULL; /* Data array inside powrefd */
  double * bolref = NULL; /* Data array inside bolrefd */
  double * bolrefvar = NULL; /* Variance inside bolrefd */

  *powrefd = NULL;
  *bolrefd = NULL;

  if (*status != SAI__OK) return;

  if ( !smf_dtype_check_fatal( bolvald, NULL, SMF__DOUBLE, status ) ) return;

  if (!bolvald->da) {
    *status = SAI__ERROR;
    errRep( "", "Unable to proceed with flatfield calculation. Heater settings not "
            "present in smfData", status);
    return;
  }

  nheat = (bolvald->dims)[2];
  numbol = (bolvald->dims)[0] * (bolvald->dims)[1];
  heatref = bolvald->da->heatval;

  /* Create a smfData for powref and bolref */
  smf_flat_malloc( nheat, bolvald, powrefd, bolrefd, status );

  if (*status == SAI__OK) {
    powref = (*powrefd)->pntr[0];
    bolref = (*bolrefd)->pntr[0];
    bolrefvar = (*bolrefd)->pntr[1];
  }

  /* Get some memory -
     bolometer power per heater setting */
  powbol = astCalloc( nheat, sizeof(*powbol) );

  /* pointers to the flatfield data and variance */
  heatframe = (bolvald->pntr)[0];
  heatframevar = (bolvald->pntr)[1];

  /* Choose the reference heater powers to be the actual heater settings acting on
     the adopted reference resistance.  */

  for ( j=0; j<nheat; j++ ) {
    current = heatref[j] * SC2FLAT__DTOI;
    powref[j] = SIMULT * current * current * refohms;
  }

  if (*status != SAI__OK) goto CLEANUP;

  /* For each bolometer interpolate to find the measurement it would report at the
     standard power input values */

  for ( i=0; i<numbol; i++ )
    {

      /* Calculate the actual power seen by each bolometer at each heater setting */

      for ( j=0; j<nheat; j++ )
        {
          current = heatref[j] * SC2FLAT__DTOI;
          if ( resistance[i] == VAL__BADD )
            {
              powbol[j] = VAL__BADD;
            }
          else
            {
              powbol[j] = SIMULT * current * current * resistance[i];
            }
        }

      /* Trap bolometers that have any bad values in their measurements */
      for ( j=0; j<nheat; j++) {
        if ( heatframe[i + j*numbol] == VAL__BADD) {
          powbol[0] = VAL__BADD;
          break;
        }
      }

      /* Trap bolometers which are unresponsive */

      if ( powbol[0] != VAL__BADD &&
           (heatframe[i] == VAL__BADD || heatframe[i + (nheat-1)*numbol] == VAL__BADD ||
            (fabs ( heatframe[i] - heatframe[i + (nheat-1)*numbol] ) < 1.0) ) )
        {
          powbol[0] = VAL__BADD;
        }

      for ( j=0; j<nheat; j++ )
        {
          if ( powbol[0] == VAL__BADD )
            {
              bolref[j*numbol+i] = VAL__BADD;
              bolrefvar[j*numbol+i] = VAL__BADD;
            }
          else
            {

              if ( powref[j] < powbol[0] )
                {
                  double var = VAL__BADD;

                  /* Standard point is below actual measured range for this bolometer,
                     extrapolate */

                  s = ( heatframe[i + 1*numbol] - heatframe[i + 0*numbol] ) /
                    ( powbol[1] - powbol[0] );

                  /* calculate error in gradient using standard rules */
                  if (heatframevar && heatframevar[i+ 1*numbol] != VAL__BADD &&
                      heatframevar[i + 0*numbol] != VAL__BADD) {
                    var = ( heatframevar[i + 1*numbol] + heatframevar[i + 0*numbol] )
                      / pow( powbol[1] - powbol[0], 2 );
                  }

                  bolref[j*numbol+i] = heatframe[i+ 0*numbol] +
                    s * ( powref[j] - powbol[0] );

                  if (var != VAL__BADD) {
                    bolrefvar[j*numbol+i] = heatframevar[i + 0*numbol] +
                      ( var * pow( powref[j] - powbol[0], 2 ));

                  } else {
                    bolrefvar[j*numbol+i] = VAL__BADD;
                  }


                }
              else if ( powref[j] > powbol[nheat-1] )
                {
                  double var = VAL__BADD;

                  /* Standard point is above actual measured range for this bolometer,
                     extrapolate */

                  s = ( heatframe[i + (nheat-1)*numbol] - heatframe[i + (nheat-2)*numbol] ) /
                    ( powbol[nheat-1] - powbol[nheat-2] );

                  /* calculate error in gradient using standard rules */
                  if (heatframevar && heatframevar[i + (nheat-1)*numbol] != VAL__BADD &&
                      heatframevar[i + (nheat-2)*numbol] != VAL__BADD) {
                    var = ( heatframevar[i + (nheat-1)] + heatframevar[i + (nheat-2)*numbol] )
                      / pow( powbol[nheat-1] - powbol[nheat-2], 2 );
                  }

                  bolref[j*numbol+i] = heatframe[i + (nheat-2)*numbol] +
                    s * ( powref[j] - powbol[nheat-2] );

                  if (var != VAL__BADD) {
                    bolrefvar[j*numbol+i] = heatframevar[i +(nheat-2)*numbol] +
                      ( var * pow( powref[j] - powbol[nheat-2], 2 ));

                  } else {
                    bolrefvar[j*numbol+i] = VAL__BADD;
                  }

                }
              else
                {

                  /* Standard point is within actual measured range for this bolometer,
                     search for the points to interpolate */

                  for ( k=1; k<nheat; k++ )
                    {
                      if ( powref[j] <= powbol[k] )
                        {
                          double var = VAL__BADD;
                          s = ( heatframe[i + k*numbol] -
                                heatframe[i + (k-1)*numbol] ) /
                            ( powbol[k] - powbol[k-1] );

                          /* calculate error in gradient using standard rules */
                          if (heatframevar && heatframevar[i + k*numbol] != VAL__BADD &&
                              heatframevar[i +(k-1)*numbol] != VAL__BADD) {
                            var = ( heatframevar[i + k*numbol] + heatframevar[i + (k-1)*numbol] )
                              / pow( powbol[k] - powbol[k-1], 2 );
                          }
                          bolref[j*numbol+i] = heatframe[i + (k-1)*numbol] +
                            s * ( powref[j] - powbol[k-1] );

                          if (var != VAL__BADD) {
                            bolrefvar[j*numbol+i] = heatframevar[i +(k-1)*numbol] +
                              ( var * pow( powref[j] - powbol[k-1], 2 ));
                          } else {
                            bolrefvar[j*numbol+i] = VAL__BADD;
                          }

                          break;
                        }
                    }

                }
            }

        }
    }

 CLEANUP:
  if (powbol) powbol = astFree( powbol );

  if (*status != SAI__OK) {
    if (*bolrefd) smf_close_file( NULL, bolrefd, status );
    if (*powrefd) smf_close_file( NULL, powrefd, status );
  }

}
示例#26
0
void smf_uncalc_iqu( ThrWorkForce *wf, smfData *data,
                     double *idata, double *qdata, double *udata,
                     int *status ){

/* Local Variables: */
   const JCMTState *state;    /* JCMTState info for current time slice */
   dim_t nbolo;               /* No. of bolometers */
   dim_t ntslice;             /* Number of time-slices in data */
   int bstep;                 /* Bolometer step between threads */
   int itime;                 /* Time slice index */
   int iworker;               /* Index of a worker thread */
   int ntime;                 /* Time slices to check */
   int nworker;               /* No. of worker threads */
   int old;                   /* Data has old-style POL_ANG values? */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfHead *hdr;              /* Pointer to data header this time slice */
   smfUncalcIQUJobData *job_data = NULL; /* Pointer to all job data */
   smfUncalcIQUJobData *pdata = NULL;/* Pointer to next job data */
   char headval[ 81 ];        /* FITS header value */
   int ipolcrd;               /* Reference direction for waveplate angles */

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

/* Convenience pointer. */
   hdr = data->hdr;

/* Check the half-waveplate and analyser were in the beam. */
   headval[ 0 ] = 0;
   smf_getfitss( hdr, "POLWAVIN", headval, sizeof(headval), status );
   if( strcmp( headval, "Y" ) && *status == SAI__OK ) {
      smf_smfFile_msg( data->file, "N", 0, "" );
      *status = SAI__ERROR;
      errRep( " ", "Half-waveplate was not in the beam for "
              "input NDF ^N.", status );
   }

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

/* Get the reference direction for JCMTSTATE:POL_ANG values. */
   smf_getfitss( hdr, "POL_CRD", headval, sizeof(headval), status );
   if( !strcmp( headval, "FPLANE" ) ) {
      ipolcrd = 0;
   } else if( !strcmp( headval, "AZEL" ) ) {
      ipolcrd = 1;
   } else if( !strcmp( headval, "TRACKING" ) ) {
      ipolcrd = 2;
   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      smf_smfFile_msg( data->file, "N", 0, "" );
      msgSetc( "V", headval );
      errRep( " ", "Input NDF ^N contains unknown value "
              "'^V' for FITS header 'POL_CRD'.", status );
   }

/* Obtain number of time slices - will also check for 3d-ness. Also get
   the dimensions of the bolometer array and the strides between adjacent
   bolometer values. */
   smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, NULL, &bstride,
                 &tstride, status );

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

/* Check the above pointers can be used safely. */
   if( *status == SAI__OK ) {

/* Go through the first thousand POL_ANG values to see if they are in
   units of radians (new data) or arbitrary encoder units (old data).
   They are assumed to be in radians if no POL_ANG value is larger than
   20. */
      old = 0;
      state = hdr->allState;
      ntime = ( ntslice > 1000 ) ? 1000 : ntslice;
      for( itime = 0; itime < ntime; itime++,state++ ) {
         if( state->pol_ang > 20 ) {
            old = 1;
            msgOutif( MSG__VERB, "","   POL2 data contains POL_ANG values "
                      "in encoder units - converting to radians.", status );
            break;
         }
      }

/* Determine which bolometers are to be processed by which threads. */
      bstep = nbolo/nworker;
      if( bstep < 1 ) bstep = 1;

      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         pdata->b1 = iworker*bstep;
         pdata->b2 = pdata->b1 + bstep - 1;
      }

/* Ensure that the last thread picks up any left-over bolometers */
      pdata->b2 = nbolo - 1;

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the analysed intensity values in each bolo, and then
   wait for them to complete. */
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;

         pdata->bstride = bstride;
         pdata->nbolo = nbolo;
         pdata->tstride = tstride;
         pdata->allstates = hdr->allState;
         pdata->ipi = idata;
         pdata->ipq = qdata;
         pdata->ipu = udata;
         pdata->ipolcrd = ipolcrd;
         pdata->old = old;
         pdata->ntslice = ntslice;

/* Pass the job to the workforce for execution. */
         thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_uncalc_iqu_job, 0, NULL,
                      status );
      }

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

/* Free resources. */
   job_data = astFree( job_data );
}
int cupidRFillClumps( int *ipa, int *out, int nel, int ndim, int skip[ 3 ],
                      int dims[ 3 ], int peakval, int *status ){
/*
*+
*  Name:
*     cupidRFillClumps

*  Purpose:
*     Identify clumps by filling in the volume enclosed by the marked
*     edges.

*  Language:
*     Starlink C

*  Synopsis:
*     int cupidRFillClumps( int *ipa, int *out, int nel, int ndim,
*                           int skip[ 3 ], int dims[ 3 ], int peakval,
*                           int *status )

*  Description:
*     This function is supplied with an array in which pixels marking the
*     edges of clumps are flagged using the value CUPID__KEDGE, and
*     pixels marking the peak value within a clump are marked by the
*     value "peakval". It assigns a unique integer index to each peak
*     and then finds the extent of the clump surrounding the peak. In the
*     returned array, all pixels assigned to a peaks clump hold the integer
*     index associated with the clump. Pixels not in any clump have the
*     value -INT_MAX. Edge pixels are not considered to be part of any clump.
*
*     If more than one peak claims a pixel, the pixel is given to the
*     closest peak.
*
*     Note, the algorithm used for filling is not fool-proof and cannot
*     in general deal with clumps which are "S" shaped (for instance).

*  Parameters:
*     ipa
*        Pointer to an array which is the same shape and size as the data
*        array, and which holds a flag for every pixel. On entry, if the
*        pixel is an edge pixel this flag will be CUPID__KEDGE. If it is a
*        peak pixel it will have the value "peakval". Unchanged on exit.
*     out
*        Pointer to an array which is the same shape and size as the data
*        array, and which holds a flag for every pixel. On exit it holds
*        the pixel index (0 or more) at all pixels which are deemed to be
*        within a clump, and -INT_MAX everywhere else.
*     nel
*        The number of elements in "ipa".
*     ndim
*        The number of pixel axes in the data (this can be less than 3).
*     skip
*        The increment in 1D vector index required to move a distance of 1
*        pixel along each axis. This allows conversion between indexing
*        the array using a single 1D vector index and using nD coords. This
*        array should have 3 elements even if there are less than 3 pixel
*        axes, and the extra elements should be filled with zero's.
*     dims
*        The no. of pixels along each pixel axis. This array should have 3
*        elements even if there are less than 3 pixel axes, and the extra
*        elements should be filled with one's.
*     peakval
*        The "ipa" value used to flag peaks.
*     status
*        Pointer to the inherited status value.

*  Returned Value:
*     The largest integer clump identifier present in the "out" array.
*     The smallest identifier value is zero.

*  Copyright:
*     Copyright (C) 2006 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:
*     24-JAN-2006 (DSB):
*        Original version.
*     {enter_further_changes_here}

*  Bugs:
*     {note_any_bugs_here}

*-
*/

/* Local Variables: */

   int *pa;              /* Pointer to next "ipa" element */
   int gp[ 3 ];          /* Grid coords of peak position */
   int i;                /* Index of next "ipa" element */
   int ipeak;            /* Index of next clump */
   int ix;               /* The X Grid coord of the current pixel */
   int iy;               /* The Y Grid coord of the current pixel */
   int iz;               /* The Z Grid coord of the current pixel */
   int npeak;            /* Number of peaks being produced */
   int *gpeak[ 3 ];      /* Pointers to arrays of peak axis values */

/* Initialise */
   ipeak = -1;

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

/* Fill the output array with -INT_MAX. */
   for( i = 0; i < nel; i++ ) out[ i ] = -INT_MAX;

/* So far we have no peaks */
   npeak = 0;
   gpeak[ 0 ] = astMalloc( sizeof( int )*30 );
   gpeak[ 1 ] = astMalloc( sizeof( int )*30 );
   gpeak[ 2 ] = astMalloc( sizeof( int )*30 );

/* Scan the ipa array looking for peaks. */
   pa = ipa;
   i = 0;

   for( iz = 1; iz <= dims[ 2 ]; iz++ ) {
      for( iy = 1; iy <= dims[ 1 ]; iy++ ) {
         for( ix = 1; ix <= dims[ 0 ]; ix++, i++, pa++ ) {
            if( *pa == peakval ) {

/* Find the integer identifier for this peak. */
               ipeak = npeak++;

/* Save thre grid coords of the peak in the gpeak array, extending it if
   necessary to make room. */
               gpeak[ 0 ] = astGrow( gpeak[ 0 ], npeak, sizeof( int ) );
               gpeak[ 1 ] = astGrow( gpeak[ 1 ], npeak, sizeof( int ) );
               gpeak[ 2 ] = astGrow( gpeak[ 2 ], npeak, sizeof( int ) );
               if( gpeak[ 2 ] ) {
                  gpeak[ 0 ][ ipeak ] = ix;
                  gpeak[ 1 ][ ipeak ] = iy;
                  gpeak[ 2 ][ ipeak ] = iz;
               }

/* Fill the volume between the edges marked in the "ipa" array by first
   moving out away from the peak along a 1D line parallel to the X axis
   until edge pixels are encountered. At each position along this line,
   store the "ipeak" value in the corresponding pixel of the "out" array,
   and then move out away from the position along a 1D line parallel to
   the Y axis until edge pixels are encountered. At each position along
   this line, store the "ipeak" value in the corresponding pixel of the
   "out" array, and then move out away from the position along a 1D line
   parallel to the Z axis until edge pixels are encountered. At each
   position along this line, store the "ipeak" value in the corresponding
   pixel of the "out" array. */
               gp[ 0 ] = ix;
               gp[ 1 ] = iy;
               gp[ 2 ] = iz;
               cupidRFillLine( ipa, out, nel, ndim, skip, dims, gp, i, 0,
                               ipeak, 1, gpeak, status );
            }
         }
      }
   }

/* If we are dealing with 2 or 3 d data, we do the whole process again
   (without re-initialising the "out" array), but this time scanning the
   axes in the order Y, Z, X (instead of X,Y,Z). */
   if( ndim > 1 ) {
      npeak = 0;
      pa = ipa;
      i = 0;

      for( iz = 1; iz <= dims[ 2 ]; iz++ ) {
         for( iy = 1; iy <= dims[ 1 ]; iy++ ) {
            for( ix = 1; ix <= dims[ 0 ]; ix++, i++, pa++ ) {
               if( *pa == peakval ) {
                  ipeak = npeak++;
                  gp[ 0 ] = ix;
                  gp[ 1 ] = iy;
                  gp[ 2 ] = iz;
                  cupidRFillLine( ipa, out, nel, ndim, skip, dims, gp, i, 1,
                                  ipeak, 1, gpeak, status );
               }
            }
         }
      }

/* If we are dealing with 3 d data, we do the whole process again (without
   re-initialising the "out" array), but this time scanning the axes in the
   order Z, X, Y. */
      if( ndim > 2 ) {
         npeak = 0;
         pa = ipa;
         i = 0;

         for( iz = 1; iz <= dims[ 2 ]; iz++ ) {
            for( iy = 1; iy <= dims[ 1 ]; iy++ ) {
               for( ix = 1; ix <= dims[ 0 ]; ix++, i++, pa++ ) {
                  if( *pa == peakval ) {
                     ipeak = npeak++;
                     gp[ 0 ] = ix;
                     gp[ 1 ] = iy;
                     gp[ 2 ] = iz;
                     cupidRFillLine( ipa, out, nel, ndim, skip, dims, gp, i, 2,
                                     ipeak, 1, gpeak, status );
                  }
               }
            }
         }
      }
   }

/* Free resources. */
   gpeak[ 0 ] = astFree( gpeak[ 0 ] );
   gpeak[ 1 ] = astFree( gpeak[ 1 ] );
   gpeak[ 2 ] = astFree( gpeak[ 2 ] );

/* Return the largest identifier present in "out". */
   return ipeak;

}
示例#28
0
void smf_calc_mapcoord( ThrWorkForce *wf, AstKeyMap *config, smfData *data,
                        AstFrameSet *outfset, int moving, int *lbnd_out,
                        int *ubnd_out, fts2Port fts_port, int flags,
                        int *status ) {

  /* Local Variables */

  AstSkyFrame *abskyfrm = NULL;/* Output SkyFrame (always absolute) */
  AstMapping *bolo2map=NULL;   /* Combined mapping bolo->map coordinates */
  int bndndf=NDF__NOID;        /* NDF identifier for map bounds */
  void *data_pntr[1];          /* Array of pointers to mapped arrays in ndf */
  int *data_index;             /* Mapped DATA_ARRAY part of NDF */
  int docalc=1;                /* If set calculate the LUT */
  int doextension=0;           /* Try to write LUT to MAPCOORD extension */
  smfFile *file=NULL;          /* smfFile pointer */
  AstObject *fstemp = NULL;    /* AstObject version of outfset */
  int ii;                      /* loop counter */
  int indf_lat = NDF__NOID;    /* Identifier for NDF to receive lat values */
  int indf_lon = NDF__NOID;    /* Identifier for NDF to receive lon values */
  smfCalcMapcoordData *job_data=NULL; /* Array of job */
  int lbnd[1];                 /* Pixel bounds for 1d pointing array */
  int lbnd_old[2];             /* Pixel bounds for existing LUT */
  int lbnd_temp[1];            /* Bounds for bounds NDF component */
  int lutndf=NDF__NOID;        /* NDF identifier for coordinates */
  AstMapping *map2sky_old=NULL;/* Existing mapping map->celestial coord. */
  HDSLoc *mapcoordloc=NULL;    /* HDS locator to the MAPCOORD extension */
  int nw;                      /* Number of worker threads */
  AstFrameSet *oldfset=NULL;   /* Pointer to existing WCS info */
  AstSkyFrame *oskyfrm = NULL; /* SkyFrame from the output WCS Frameset */
  smfCalcMapcoordData *pdata=NULL; /* Pointer to job data */
  double *lat_ptr = NULL;      /* Pointer to array to receive lat values */
  double *lon_ptr = NULL;      /* Pointer to array to receive lon values */
  int ubnd[1];                 /* Pixel bounds for 1d pointing array */
  int ubnd_old[2];             /* Pixel bounds for existing LUT */
  int ubnd_temp[1];            /* Bounds for bounds NDF component */
  int *lut = NULL;             /* The lookup table */
  dim_t nbolo=0;               /* Number of bolometers */
  dim_t ntslice=0;             /* Number of time slices */
  int nmap;                    /* Number of mapped elements */
  AstMapping *sky2map=NULL;    /* Mapping celestial->map coordinates */
  size_t step;                 /* step size for dividing up work */
  AstCmpMap *testcmpmap=NULL;  /* Combined forward/inverse mapping */
  AstMapping *testsimpmap=NULL;/* Simplified testcmpmap */
  double *theta = NULL;        /* Scan direction at each time slice */
  int tstep;                   /* Time slices between full Mapping calculations */
  int exportlonlat;            /* Dump longitude and latitude values? */

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

  /* How many threads do we get to play with */
  nw = wf ? wf->nworker : 1;

  /* Initialize bounds to avoid compiler warnings */
  lbnd_old[0] = 0;
  lbnd_old[1] = 0;
  ubnd_old[0] = 0;
  ubnd_old[1] = 0;

  /* Check for pre-existing LUT and de-allocate it. This will only waste
     time if the MAPCOORD extension is found to be valid and it has
     to be re-loaded from disk. */
  smf_close_mapcoord( data, status );

  /* Assert ICD data order */
  smf_dataOrder( data, 1, status );

  /* Get the data dimensions */
  smf_get_dims( data,  NULL, NULL, &nbolo, &ntslice, NULL, NULL, NULL, status );

  /* If SMF__NOCREATE_FILE is not set, and file associated with an NDF,
     map a new MAPCOORD extension (or verify an existing one) */

  if( !(flags & SMF__NOCREATE_FILE) && data->file ) {
    doextension = 1;
  } else {
    doextension = 0;
    docalc = 1;
  }

  /* Create / check for existing MAPCOORD extension */
  if( doextension ) {
    file = data->file;

    /* Check type of file before proceeding */
    if( file->isSc2store ) {
      *status = SAI__ERROR;
      errRep(FUNC_NAME,
             "File was opened by sc2store library (raw data?)",
             status);
    }

    if( !file->isTstream ) {
      *status = SAI__ERROR;
      errRep(FUNC_NAME,	"File does not contain time stream data",status);
    }

    /* Get HDS locator to the MAPCOORD extension */
    mapcoordloc = smf_get_xloc( data, "MAPCOORD", "MAP_PROJECTION", "UPDATE",
                                0, 0, status );

    /* Obtain NDF identifier/placeholder for LUT in MAPCOORD extension*/
    lbnd[0] = 0;
    ubnd[0] = nbolo*ntslice-1;
    lutndf = smf_get_ndfid( mapcoordloc, "LUT", "UPDATE", "UNKNOWN",
                            "_INTEGER", 1, lbnd, ubnd, status );

    if( *status == SAI__OK ) {
      /* store the NDF identifier */
      file->mapcoordid = lutndf;

      /* Create sky to output grid mapping using the base coordinates to
         get the coordinates of the tangent point if it hasn't been done
         yet. */
      sky2map = astGetMapping( outfset, AST__CURRENT, AST__BASE );
    }

    /* Before mapping the LUT, first check for existing WCS information
       and LBND/UBND for the output map. If they are already correct don't
       bother re-calculating the LUT! */

    if( *status == SAI__OK ) {

      /* Try reading in the WCS information */
      kpg1Wread( mapcoordloc, "WCS", &fstemp, status );
      oldfset = (AstFrameSet*)fstemp;

      if( *status == SAI__OK ) {

        /* Check that the old and new mappings are the same by
           checking that combining one with the inverse of the other
           reduces to a UnitMap. */

        map2sky_old = astGetMapping( oldfset, AST__BASE, AST__CURRENT );
        testcmpmap = astCmpMap( map2sky_old, sky2map, 1, " " );
        testsimpmap = astSimplify( testcmpmap );

        if( astIsAUnitMap( testsimpmap ) ) {

          /* The mappings are the same, now just check the pixel
             bounds in the output map */

          lbnd_temp[0] = 1;
          ubnd_temp[0] = 2;

          bndndf = smf_get_ndfid( mapcoordloc, "LBND", "READ", "UNKNOWN",
                                  "_INTEGER", 1, lbnd_temp, ubnd_temp,
                                  status );

          if( *status == SAI__OK ) {
            ndfMap( bndndf, "DATA", "_INTEGER", "READ", data_pntr, &nmap,
                    status );
            data_index = data_pntr[0];

            if( *status == SAI__OK ) {
              lbnd_old[0] = data_index[0];
              lbnd_old[1] = data_index[1];
            }
            ndfAnnul( &bndndf, status );
          }

          bndndf = smf_get_ndfid( mapcoordloc, "UBND", "READ", "UNKNOWN",
                                  "_INTEGER", 1, lbnd_temp, ubnd_temp,
                                  status );

          if( *status == SAI__OK ) {
            ndfMap( bndndf, "DATA", "_INTEGER", "READ", data_pntr, &nmap,
                    status );
            data_index = data_pntr[0];

            if( *status == SAI__OK ) {
              ubnd_old[0] = data_index[0];
              ubnd_old[1] = data_index[1];
            }
            ndfAnnul( &bndndf, status );
          }

          if( *status == SAI__OK ) {
            /* If we get this far finally do the bounds check! */
            if( (lbnd_old[0] == lbnd_out[0]) &&
                (lbnd_old[1] == lbnd_out[1]) &&
                (ubnd_old[0] == ubnd_out[0]) &&
                (ubnd_old[1] == ubnd_out[1]) ) {

              docalc = 0; /* We don't have to re-calculate the LUT */
              msgOutif(MSG__VERB," ",FUNC_NAME ": Existing LUT OK",
                       status);
            }
          }
        }

        /* Bad status / AST errors at this point due to problems with
           MAPCOORD. Annul and continue calculating new MAPCOORD extension. */
        astClearStatus;
        errAnnul(status);

      } else {
        /* Bad status due to non-existence of MAPCOORD. Annul and continue */
        errAnnul(status);
      }
    }

  }

  /* If we need to calculate the LUT do it here */
  if( docalc && (*status == SAI__OK) ) {
    msgOutif(MSG__VERB," ", FUNC_NAME ": Calculate new LUT",
             status);

    /* Get the increment in time slices between full Mapping calculations.
       The Mapping for intermediate time slices will be approximated. */
    dim_t dimval;
    smf_get_nsamp( config, "TSTEP", data, &dimval, status );
    tstep = dimval;

    /* Get space for the LUT */
    if( doextension ) {
      /* Map the LUT array */
      ndfMap( lutndf, "DATA", "_INTEGER", "WRITE", data_pntr, &nmap,
              status );
      data_index = data_pntr[0];
      if( *status == SAI__OK ) {
        lut = data_index;
      } else {
        errRep( FUNC_NAME, "Unable to map LUT in MAPCOORD extension",
                status);
      }
    } else {
      /* alloc the LUT and THETA arrays */
      lut = astMalloc( (nbolo*ntslice)*sizeof(*(data->lut)) );
      theta = astMalloc( ntslice*sizeof(*(data->theta)) );
    }


    /* Retrieve the sky2map mapping from the output frameset (actually
       map2sky) */
    oskyfrm = astGetFrame( outfset, AST__CURRENT );
    sky2map = astGetMapping( outfset, AST__BASE, AST__CURRENT );

    /* If the longitude and latitude is being dumped, create new NDFs to
       hold them, and map them. */
    if( config ) {
       astMapGet0I( config, "EXPORTLONLAT", &exportlonlat );
       if( exportlonlat ) {
          lon_ptr = smf1_calc_mapcoord1( data, nbolo, ntslice, oskyfrm,
                                         &indf_lon, 1, status );
          lat_ptr = smf1_calc_mapcoord1( data, nbolo, ntslice, oskyfrm,
                                         &indf_lat, 2, status );
       }
    }

    /* Invert the mapping to get Output SKY to output map coordinates */
    astInvert( sky2map );

    /* Create a SkyFrame in absolute coordinates */
    abskyfrm = astCopy( oskyfrm );
    astClear( abskyfrm, "SkyRefIs" );
    astClear( abskyfrm, "SkyRef(1)" );
    astClear( abskyfrm, "SkyRef(2)" );

    if( *status == SAI__OK ) {

      /* --- Begin parellelized portion ------------------------------------ */

      /* Start a new job context. Each call to thrWait within this
         context will wait until all jobs created within the context have
         completed. Jobs created in higher contexts are ignored by thrWait. */
      thrBeginJobContext( wf, status );

      /* Allocate job data for threads */
      job_data = astCalloc( nw, sizeof(*job_data) );
      if( *status == SAI__OK ) {

        /* Set up job data, and start calculating pointing for blocks of
           time slices in different threads */

        if( nw > (int) ntslice ) {
          step = 1;
        } else {
          step = ntslice/nw;
        }

        for( ii=0; (*status==SAI__OK)&&(ii<nw); ii++ ) {
          pdata = job_data + ii;

          /* Blocks of time slices */
          pdata->t1 = ii*step;
          pdata->t2 = (ii+1)*step-1;

          /* Ensure that the last thread picks up any left-over tslices */
          if( (ii==(nw-1)) && (pdata->t1<(ntslice-1)) ) {
            pdata->t2=ntslice-1;
          }

          pdata->ijob = -1;
          pdata->lut = lut;
          pdata->theta = theta;
          pdata->lbnd_out = lbnd_out;
          pdata->moving = moving;
          pdata->ubnd_out = ubnd_out;
          pdata->tstep = tstep;
          pdata->lat_ptr = lat_ptr;
          pdata->lon_ptr = lon_ptr;
          pdata->fts_port = fts_port;

          /* Make deep copies of AST objects and unlock them so that each
             thread can then lock them for their own exclusive use */

          pdata->abskyfrm = astCopy( abskyfrm );
          astUnlock( pdata->abskyfrm, 1 );
          pdata->sky2map = astCopy( sky2map );
          astUnlock( pdata->sky2map, 1 );

          /* Similarly, make a copy of the smfData, including only the header
             information which each thread will need in order to make calls to
             smf_rebin_totmap */

          pdata->data = smf_deepcopy_smfData( data, 0, SMF__NOCREATE_FILE |
                                              SMF__NOCREATE_DA |
                                              SMF__NOCREATE_FTS |
                                              SMF__NOCREATE_DATA |
                                              SMF__NOCREATE_VARIANCE |
                                              SMF__NOCREATE_QUALITY, 0, 0,
                                              status );
          smf_lock_data( pdata->data, 0, status );
        }

        for( ii=0; ii<nw; ii++ ) {
          /* Submit the job */
          pdata = job_data + ii;
          pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata,
                                     smfCalcMapcoordPar, 0, NULL, status );
        }

        /* Wait until all of the jobs submitted within the current job
           context have completed */
        thrWait( wf, status );
      }

      /* End the current job context. */
      thrEndJobContext( wf, status );

      /* --- End parellelized portion -------------------------------------- */

      /* Set the lut pointer in data to the buffer */
      data->lut = lut;
      data->theta = theta;

      /* Write the WCS for the projection to the extension */
      if( doextension ) {
        kpg1Wwrt( (AstObject*)outfset, "WCS", mapcoordloc, status );

        /* Write the pixel bounds for the map to the extension */

        lbnd_temp[0] = 1; /* Don't get confused! Bounds for NDF that will */
        ubnd_temp[0] = 2; /* contain the bounds for the output 2d map!    */

        bndndf = smf_get_ndfid( mapcoordloc, "LBND", "UPDATE", "UNKNOWN",
                                "_INTEGER", 1, lbnd_temp, ubnd_temp, status );

        ndfMap( bndndf, "DATA", "_INTEGER", "WRITE", data_pntr, &nmap,
                status );
        data_index = data_pntr[0];
        if( *status == SAI__OK ) {
          data_index[0] = lbnd_out[0];
          data_index[1] = lbnd_out[1];
        } else {
          errRep( FUNC_NAME, "Unable to map LBND in MAPCOORD extension",
                  status);
        }

        ndfAnnul( &bndndf, status );

        bndndf = smf_get_ndfid( mapcoordloc, "UBND", "UPDATE", "UNKNOWN",
                                "_INTEGER", 1, lbnd_temp, ubnd_temp, status );
        ndfMap( bndndf, "DATA", "_INTEGER", "WRITE", data_pntr, &nmap,
                status );
        data_index = data_pntr[0];
        if( *status == SAI__OK ) {
          data_index[0] = ubnd_out[0];
          data_index[1] = ubnd_out[1];
        } else {
          errRep( FUNC_NAME, "Unable to map UBND in MAPCOORD extension",
                  status);
        }
        ndfAnnul( &bndndf, status );
      }
    }
  }

  /* Clean Up */

  if( testsimpmap ) testsimpmap = astAnnul( testsimpmap );
  if( testcmpmap ) testcmpmap = astAnnul( testcmpmap );
  if( map2sky_old ) map2sky_old = astAnnul( map2sky_old );
  if( oldfset ) oldfset = astAnnul( oldfset );
  if (sky2map) sky2map  = astAnnul( sky2map );
  if (bolo2map) bolo2map = astAnnul( bolo2map );
  if( abskyfrm ) abskyfrm = astAnnul( abskyfrm );
  if( oskyfrm ) oskyfrm = astAnnul( oskyfrm );
  if( mapcoordloc ) datAnnul( &mapcoordloc, status );
  if( indf_lat != NDF__NOID ) ndfAnnul( &indf_lat, status );
  if( indf_lon != NDF__NOID ) ndfAnnul( &indf_lon, status );


  /* If we get this far, docalc=0, and status is OK, there must be
     a good LUT in there already. Map it so that it is accessible to
     the caller; "UPDATE" so that the caller can modify it if desired. */
  if( (*status == SAI__OK) && (docalc == 0) ) {
    smf_open_mapcoord( data, "UPDATE", status );
  }

  /* Clean up job data */
  if( job_data ) {
    for( ii=0; (*status==SAI__OK)&&(ii<nw); ii++ ) {
      pdata = job_data + ii;

      if( pdata->data ) {
        smf_lock_data( pdata->data, 1, status );
        smf_close_file( &(pdata->data), status );
      }
      astLock( pdata->abskyfrm, 0 );
      pdata->abskyfrm = astAnnul( pdata->abskyfrm );

      astLock( pdata->sky2map, 0 );
      pdata->sky2map = astAnnul( pdata->sky2map );
    }
    job_data = astFree( job_data );
  }

}
示例#29
0
static void smf1_calcmodel_smo_job( void *job_data, int *status ) {
/*
*  Name:
*     smf1_calcmodel_smo_job

*  Purpose:
*     Smooth each bolometer.

*  Invocation:
*     void smf1_calcmodel_smo_job( void *job_data, int *status )

*  Arguments:
*     job_data = void * (Given)
*        Pointer to the data needed by the job. Should be a pointer to a
*        smfCalcmodelSmoJobData structure.
*     status = int * (Given and Returned)
*        Pointer to global status.

*  Description:
*     This routine runs in a worker thread to smooth the specified bolometer
*     time streams using the specified filter.

*/

/* Local Variables: */
   dim_t b1;
   dim_t b2;
   dim_t i;
   dim_t nbolo;
   dim_t ntslice;
   double *boldata = NULL;
   double *model_data;
   double *res_data;
   double *w1 = NULL;
   int *w3 = NULL;
   smf_filt_t filter_type;
   size_t boxcar;
   size_t bstride;
   size_t tstride;
   size_t *w2 = NULL;
   smfCalcmodelSmoJobData *pdata;
   smf_qual_t *bolqua = NULL;
   smf_qual_t *qua_data;
   struct timeval tv1;
   struct timeval tv2;

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

   /* Get a pointer to the job data, and then extract its contents into a
      set of local variables. */
   pdata = (smfCalcmodelSmoJobData *) job_data;

   b1 = pdata->b1;
   b2 = pdata->b2;
   boxcar = pdata->boxcar;
   bstride = pdata->bstride;
   filter_type = pdata->filter_type;
   model_data = pdata->model_data;
   nbolo = pdata->nbolo;
   ntslice = pdata->ntslice;
   qua_data = pdata->qua_data;
   res_data = pdata->res_data;
   tstride = pdata->tstride;

   /* Check we have something to do. */
   if( b1 < nbolo ) {

      /* Debugging message indicating thread started work */
      msgOutiff( SMF__TIMER_MSG, "", "smf_calcmodel_smo: thread starting on bolos %" DIM_T_FMT
                 " -- %" DIM_T_FMT,
                 status, b1, b2 );
      smf_timerinit( &tv1, &tv2, status);

      /* Allocate work space */
      boldata = astMalloc( ntslice*sizeof( *boldata ) );
      bolqua  = astMalloc( ntslice*sizeof( *bolqua ) );
      if( filter_type == SMF__FILT_MEDIAN ) {
        w1 = astMalloc( boxcar*sizeof( *w1 ) );
        w2 = astMalloc( boxcar*sizeof( *w2 ) );
        w3 = astMalloc( boxcar*sizeof( *w3 ) );
      }

      /* Loop round all the bolometers to be processed by this thread. */
      for( i = b1; i <= b2 && *status == SAI__OK; i++ ) {

        /* Smooth the data and subtract it from res */
        size_t j;
        size_t boloff = i*bstride;

        /* Copy the data for this bolometer into a temporary buffer */
        for (j=0; j<ntslice; j++) {
          size_t thisidx = boloff+j*tstride;
          boldata[j] = res_data[thisidx];
          bolqua[j] = qua_data[thisidx];
        }

        /* Smooth that bolometer time series */
        if( filter_type == SMF__FILT_MEDIAN ) {
           smf_median_smooth( (dim_t) boxcar, SMF__FILT_MEDIAN, 0.0, ntslice,
                              res_data+boloff, qua_data+boloff, 1, SMF__Q_FIT,
                              boldata, w1, w2, w3, status );
        } else {
           smf_tophat1D( boldata, ntslice, boxcar, bolqua, SMF__Q_FIT,
                         0.0, status );
        }

        /* Remove this model from the residual data and copy the data to the model */
        for (j=0; j<ntslice; j++) {
          size_t thisidx = boloff+j*tstride;

          /* Modify RES if this section has smoothable quality */
          if (! (qua_data[thisidx] & SMF__Q_FIT) ) {
            if (boldata[j] == VAL__BADD) {
              /* Need to set to bad quality but since SMO can not
                 introduce bad values we shouldn't get here. For now
                 we use the COM quality bit just in case. */
              qua_data[thisidx] |= SMF__Q_COM;
            } else if (res_data[thisidx] != VAL__BADD) {
              res_data[thisidx] -= boldata[j];
            }
            /* Store the model */
            model_data[thisidx] = boldata[j];
          } else {
            /* store bad value in the model */
            model_data[thisidx] = VAL__BADD;
          }
        }
      }

/* Free work space. */
      w1 = astFree( w1 );
      w2 = astFree( w2 );
      w3 = astFree( w3 );
      boldata = astFree( boldata );
      bolqua = astFree( bolqua );

/* Report the time taken in this thread. */
      msgOutiff( SMF__TIMER_MSG, "",
                 "smf_calcmodel_smo: thread finishing bolos %" DIM_T_FMT
                 " -- %" DIM_T_FMT "(%.3f sec)",
                 status, b1, b2, smf_timerupdate( &tv1, &tv2, status ) );
   }
}
示例#30
0
void smf_mapbounds( int fast, Grp *igrp,  int size, const char *system,
                    AstFrameSet *spacerefwcs, int alignsys, int *lbnd_out,
                    int *ubnd_out, AstFrameSet **outframeset, int *moving,
                    smfBox ** boxes, fts2Port fts_port, int *status ) {

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

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

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

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

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

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

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

  astBegin;

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

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

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

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

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

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

        }
      }
    }

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

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

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

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

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

      switch( hdr->instrument ) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

          if (skyin) skyin = astAnnul( skyin );

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

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

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

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

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

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

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

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

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

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

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

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

        } /* End WCS FrameSet construction */
      }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        }
      }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  refsys = astFree( refsys );

  astEnd;

}