Exemple #1
0
void smf_pcorr( smfHead *head, const Grp *igrp, int *status ){

/* Local Variables: */
   AstMapping *dlatmap;
   AstMapping *dlonmap;
   JCMTState *state;
   char buff[ GRP__SZNAM + 1 ];
   dim_t iframe;
   double *dlat;
   double *dlon;
   double *tai;
   double dlat_az;
   double dlat_tr;
   double dlon_az;
   double dlon_tr;
   int azel;
   void *p;

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

/* See if the supplied group has a metadata item called "DLONMAP". If
   not, there are no pointing corrections to apply. */
   buff[ 0 ] = 0;
   smf_get_grp_metadata( igrp, "DLONMAP", buff, status );
   if( buff[ 0 ] ) {

/* The value of the DLONMAP metadata item in the group is the formatted
   pointer to an AST Mapping from TAI MJD to arc-distance offsets
   parallel to the longitude axis (in arc-seconds). Unformat the text to
   get the usable pointer. */
      sscanf( buff, "%p", &p );
      dlonmap = (AstMapping *) p;

/* Likewise, get a pointer to the DLATMAP Mapping, from TAI MJD to arc-distance
   offsets parallel to the latitude axis (in arc-seconds). */
      buff[ 0 ] = 0;
      smf_get_grp_metadata( igrp, "DLATMAP", buff, status );
      if( !buff[ 0 ] ) {
         dlatmap = NULL;
         *status = SAI__ERROR;
         errRep( " ", "smf_pcorr: DLATMAP not found in group metadata.",
                 status );
      } else {
         sscanf( buff, "%p", &p );
         dlatmap = (AstMapping *) p;
      }

/* Also get the system of the axes - AZEL or TRACKING. Default to AZEL. */
      azel = 1;
      buff[ 0 ] = 0;
      smf_get_grp_metadata( igrp, "PSYSTEM", buff, status );
      if( buff[ 0 ] ) {
         buff[ astChrLen( buff ) ] = 0;
         if( astChrMatch( buff, "TRACKING" ) ) {
            azel = 0;
         } else if( !astChrMatch( buff, "AZEL" ) && *status == SAI__OK ) {
            *status = SAI__ERROR;
            msgSetc( "S", buff );
            errRep( " ", "smf_pcorr: Bad system (^S).", status );
         }
      }

/* Allocate arrays to hold the tai, dlon and dlat values at every frame. */
      tai = astMalloc( head->nframes*sizeof( double ) );
      dlon = astMalloc( head->nframes*sizeof( double ) );
      dlat = astMalloc( head->nframes*sizeof( double ) );
      if( *status == SAI__OK ) {

/* Store the TAI at every frame. */
         for( iframe = 0; iframe < head->nframes; iframe++ ){
            state = head->allState + iframe;
            tai[ iframe ] = state->tcs_tai;
         }

/* Lock the Mappings for use by this thread. Wait for them if they are
   currently in use by a different thread. */
         astLock( dlonmap, 1 );
         astLock( dlatmap, 1 );

/* Use the Mappings to transform TAI into DLON and DLAT values at every frame
   (still in arc-seconds). */
         astTran1( dlonmap, head->nframes, tai, 1, dlon );
         astTran1( dlatmap, head->nframes, tai, 1, dlat );

/* We have now finished with the Mappings, so unlock them so that hey can
   be used by other threads. */
         astUnlock( dlonmap, 1 );
         astUnlock( dlatmap, 1 );

/* Loop round every time slice */
         dlon_az = AST__BAD;
         dlat_az = AST__BAD;
         dlon_tr = AST__BAD;
         dlat_tr = AST__BAD;

         for( iframe = 0; iframe < head->nframes ; iframe++ ){
            state = head->allState + iframe;

/* Apply the correction */
            smf_add_smu_pcorr( state, azel, dlon[ iframe ],
                               dlat[ iframe ], status );

         }
      }

/* Free resources. */
      tai = astFree( tai );
      dlon = astFree( dlon );
      dlat = astFree( dlat );
   }
}
Exemple #2
0
void smf_snrmask( ThrWorkForce *wf, int abssnr, unsigned char *oldmask,
                  const double *map, const double *mapvar,
                  const dim_t *dims, double snr_hi, double snr_lo,
                  unsigned char *mask, int *status ){

/* Local Variables: */
   const double *pm = NULL;
   const double *pv = NULL;
   dim_t i;
   dim_t j;
   double snr;
   int *cindex = NULL;
   int *ps = NULL;
   int *psn = NULL;
   int *table = NULL;
   int iass;
   int iclean;
   int iclump;
   int ineb;
   int itemp;
   int itop1;
   int itop2;
   int iworker;
   int neb_offset[ 4 ];
   int nworker;
   int ok;
   int rowstep;
   int top;
   smfSnrMaskJobData *job_data = NULL;
   smfSnrMaskJobData *pdata = NULL;
   unsigned char *maskold = NULL;

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

/* Save a copy of the old mask, if supplied. Doing it now, means that the
   old and new mask pointers can be the same. */
   if( oldmask ) maskold = astStore( NULL, oldmask,
                                     sizeof(*oldmask)*dims[0]*dims[1] );

/* Allocate an array to hold a clump index for every map pixel. Initialise
   it to hold zeros. */
   cindex = astCalloc( dims[ 0 ]*dims[ 1 ], sizeof( *cindex ) );

/* Initialise the index to assign to the next clump of pixels found above
   the lower SNR limit. Note, no clump is given an index of zero. */
   top = 1;

/* Initialise the pointer to the table holding associated clump indices.
   The first element is unused, so set it to a safe value of zero (i.e.
   "no clump"). */
   table = astCalloc( top, sizeof( *table ) );

/* Set up the vector offsets to the three neighbouring pixels in the lower
   row, and the left hand neighbour in the current row. */
   neb_offset[ 0 ] = -1;              /* Left neighbour in current row */
   neb_offset[ 1 ] = -dims[ 0 ] - 1;  /* Left neighbour in lower row */
   neb_offset[ 2 ] = -dims[ 0 ];      /* Central neighbour in lower row */
   neb_offset[ 3 ] = -dims[ 0 ] + 1;  /* Right neighbour in lower row */

/* Loop round the map, looking for pixels that are above the lower SNR
   limit. Within this loop we store a positive clump index for each pixel that
   is above the lower SNR limit. Each clump of contiguous pixel above the limit
   has a separate clump index. If two clumps touch each other, we associate
   their indices together using a table to indicate that they are part of the
   same physical clump. */
   pm = map;
   pv = mapvar;
   ps = cindex;
   for( j = 0; j < dims[ 1 ] && *status == SAI__OK; j++ ) {
      for( i = 0; i < dims[ 0 ]; i++, pm++, pv++, ps++ ) {

/* Get the SNR value. */
         if( mapvar ) {
            if( *pm != VAL__BADD && *pv != VAL__BADD && *pv > 0.0 ){
               snr = *pm / sqrt( *pv );
            } else {
               snr = VAL__BADD;
            }
         } else {
            snr = *pm;
         }

/* If source can be negative as well as positive, use the absolute SNR in
   the following check. */
         if( abssnr && snr != VAL__BADD ) snr = fabs( snr );

/* Check the SNR is good and above the lower limit. */
         if( snr != VAL__BADD && snr > snr_lo ){

/* The three neighbouring pixels on row (j-1), and the left hand
   neighbouring pixel on row j, have already been checked on earlier
   passes round this loop. Check each of these four pixels in turn to see
   if they were flagged as being above the lower SNR limit. */
            itop1 = 0;
            for( ineb = 0; ineb < 4; ineb++ ) {

/* Get a pointer to the neighbouring clump index value, checking it is not off
   the edge of the array. */
               if( ineb == 0 ) {
                  ok = ( i > 0 );
               } else if( ineb == 1 ) {
                  ok = ( i > 0 && j > 0 );
               } else if( ineb == 2 ) {
                  ok = ( j > 0 );
               } else {
                  ok = ( i < dims[ 0 ] - 1 && j > 0 );
               }
               if( ok ) {
                  psn = ps + neb_offset[ ineb ];

/* If this neighbour is flagged as above the lower SNR limit (i.e. has a
   positive clump index), and the current pixel has not yet been assigned to
   an existing clump, assign the neighbour's clump index to the current pixel. */
                  if( *psn > 0 ) {
                     if( *ps == 0 ) {
                        *ps = *psn;

/* Find the clump index at the top of the tree containing the neighbouring pixel. */
                        itop1 = *psn;
                        while( table[ itop1 ] ) itop1 = table[ itop1 ];

/* If this neighbour is flagged as above the lower SNR limit, but the
   current pixel has already been assigned to an existing clump, the current
   pixel is adjacent to both clumps and so joins them into one. So record that
   this neighbours clump index should be associated with the clump index of
   the current pixel. */
                     } else {

/* We need to check first that the two clump indices are not already part
   of the same tree of associated clumps. Without this we could produce
   loops in the tree. Find the clump indices at the top of the tree
   containing the neighbouring pixel. */
                        itop2 = *psn;
                        while( table[ itop2 ] ) itop2 = table[ itop2 ];

/* If the two clumps are not in the same tree, indicate that the pixel
   index at the top of the tree for the neighbouring pixels clump index is
   associated with the central pixel's clump index. */
                        if( itop1 != itop2 ) table[ itop2 ] = *ps;
                     }
                  }
               }
            }

/* If the current pixel has no neighbours that are above the lower SNR
   limit, we start a new clump for the current pixel. */
            if( *ps == 0 ) {

/* Assign the next clump index to the current pixel, and then increment
   the next clump index. Report an error if we have reached the max
   allowable clump index value. */
               if( top == INT_MAX ) {
                  *status = SAI__ERROR;
                  errRep( "", "smf_snrmask: Too many low-SNR clumps found.",
                          status );
                  break;
               }
               *ps = top++;

/* Extend the table that holds the associations between clumps. This
   table has one element for each clump index (plus an unused element at the
   start for the unused clump index "0"). The value stored in this table
   for a given clump index is the index of another clump with which the
   first clump should be associated. If two clumps are associated it
   indicates that they are part of the same physical clump. Associations
   form a tree structure. A value of zero in this table indicates that
   the clump is either unassociated with any other clump, or is at the head
   of a tree of associated clumps. */
               table = astGrow( table, top, sizeof( *table ) );
               if( *status != SAI__OK ) break;
               table[ *ps ] = 0;
            }
         }
      }
   }

/* We now loop round the map again, this time looking for pixels that are
   above the higher SNR limit. */
   pm = map;
   pv = mapvar;
   ps = cindex;
   for( j = 0; j < dims[ 1 ]; j++ ) {
      for( i = 0; i < dims[ 0 ]; i++, pm++, pv++, ps++ ) {

/* Get the SNR value. */
         if( mapvar ) {
            if( *pm != VAL__BADD && *pv != VAL__BADD && *pv > 0.0 ){
               snr = *pm / sqrt( *pv );
            } else {
               snr = VAL__BADD;
            }
         } else {
            snr = *pm;
         }

/* If source can be negative as well as positive, use the absolute SNR. */
         if( abssnr && snr != VAL__BADD ) snr = fabs( snr );

/* Check the SNR is good and above the upper limit. */
         if( snr != VAL__BADD && snr > snr_hi ){

/* Since this pixel is above the higher SNR limit, it must also be above
   the lower SNR Limit, and so will have a non-zero clump index. We flag that
   this clump contains "source" pixels by storing a value of -1 for it in the
   clump association table. First record the original value for later use. */
            iass = table[ *ps ];
            table[ *ps ] = -1;

/* If this clump index is associated with another clump (i.e. had a non-zero
   value in the clump association table), the two clumps adjoins each other.
   So indicate that the second clump also contains "source" pixels by
   changing its table value to -1. Enter a loop to do this all the way up
   to the top of the association tree. Note, this is not necessarily all
   adjoining clumps, since we have only gone "up" the tree - there may be
   other adjoining clumps lower down the tree. */
            while( iass > 0 ) {
               itemp =  table[ iass ];
               table[ iass ] = -1;
               iass = itemp;
            }
         }
      }
   }

/* Now check all cumps to see if they adjoin a "source" clump. Note, no
   clumps are given the index zero, so we skip the first element of the
   table. */
   for( iclump = 1; iclump < top; iclump++ ) {
      iass = table[ iclump ];

/* Work up the tree of neighbouring clumps until we find a clump that has
   an index of 0 or -1. If 0, it means that we have reached the top of
   the tree without finding a "source" clump. If -1 it means we have
   reached a source clump. */
      while( iass > 0 ) {
         iass =  table[ iass ];
      }

/* If we have found a source clump, then all clumps above it in the tree
   should already be set to -1. We now walk up the tree from the current
   clump until we reach the source clump, marking all intermediate clumps
   as source clumps by setting them to -1 in the table. */
      if( iass < 0 ) {
         iass = iclump;
         while( iass > 0 ) {
            itemp =  table[ iass ];
            table[ iass ] = -1;
            iass = itemp;
         }

/* If no source clump was found, mark all intermediate clumps as
   non-source by setting theem to zero in the table. This may give us a
   little extra speed (maybe) since subsequent walks will terminate
   sooner. */
      } else {
         iass = iclump;
         while( iass > 0 ) {
            itemp =  table[ iass ];
            table[ iass ] = 0;
            iass = itemp;
         }
      }
   }

/* One last pass, to store the final mask values. We can multi-thread
   this bit. Create structures used to pass information to the worker
   threads. If we have more threads than rows, we will process one row
   in each thread and so we can reduce the number of threads used to
   equal the number of rows. */
   nworker = wf ? wf->nworker : 1;
   if( nworker > (int) dims[ 1 ] ) nworker = dims[ 1 ];
   job_data = astMalloc( nworker*sizeof( *job_data ) );

/* Check we can de-reference the job data pointer safely. */
   if( *status == SAI__OK ) {

/* Decide how many rows to process in each thread. */
      rowstep = dims[ 1 ]/nworker;
      if( rowstep == 0 ) rowstep = 1;

/* Set up the information needed by each thread, */
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         pdata->operation = 1;
         pdata->cindex = cindex;
         pdata->jlo = iworker*rowstep;
         if( iworker == nworker - 1 ) {
            pdata->jhi = dims[ 1 ] - 1;
         } else {
            pdata->jhi = pdata->jlo + rowstep - 1;
         }
         pdata->rowlen = dims[ 0 ];
         pdata->mask = mask;
         pdata->table = table;

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

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

/* Now clean up the very crinkly edges of the mask. Also, the mask may
   contain small holes which need to be cleaned. Clean it NCLEAN times. */
      for( iclean = 0; iclean < NCLEAN; iclean++ ) {

/* Clean the mask, putting the cleaned mask into "cindex" array. We
   exclude pixels in the first and last rows since they do not have a
   complete set of neighbours (each worker thread also ignores the first
   and last pixel in each row for the same reason). Decide how many rows
   to process in each thread. */
         rowstep = ( dims[ 1 ] - 2 )/nworker;
         if( rowstep == 0 ) rowstep = 1;

/* Modify the information needed by each thread, */
         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;
            pdata->operation = 2;
            pdata->jlo = iworker*rowstep + 1;
            if( iworker == nworker - 1 ) {
               pdata->jhi = dims[ 1 ] - 2;
            } else {
               pdata->jhi = pdata->jlo + rowstep - 1;
            }

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

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

/* Transfer the new mask from the "cindex" array back to the "mask" array.
   Add in any source pixels from the old mask if required. */
         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;
            pdata->maskold = maskold;
            pdata->operation = 3;
            thrAddJob( wf, 0, pdata, smf1_snrmask_job, 0, NULL, status );
         }
         thrWait( wf, status );

/* If an old mask was supplied, ensure any source pixels in the old mask
   are also source pixels in the new mask. */
         if( oldmask ) {
            for( iworker = 0; iworker < nworker; iworker++ ) {
               pdata = job_data + iworker;
               pdata->maskold = maskold;
               pdata->operation = 4;
               thrAddJob( wf, 0, pdata, smf1_snrmask_job, 0, NULL, status );
            }
            thrWait( wf, status );
         }
      }
   }

/* Free resources. */
   job_data = astFree( job_data );
   maskold = astFree( maskold );
   table = astFree( table );
   cindex = astFree( cindex );
}
Exemple #3
0
static void smf1_correct_extinction( void *job_data_ptr, int *status ) {
/*
*  Name:
*     smf1_correct_extinction

*  Purpose:
*     Executed in a worker thread to do various calculations for
*     smf_correct_extinction.

*  Invocation:
*     smf1_correct_extinction( void *job_data_ptr, int *status )

*  Arguments:
*     job_data_ptr = SmfCorrectExtinctionData * (Given)
*        Data structure describing the job to be performed by the worker
*        thread.
*     status = int * (Given and Returned)
*        Inherited status.

*/

  /* Local Variables: */
  SmfCorrectExtinctionData *pdata;
  double airmass;          /* Airmass */
  double state_airmass;    /* Airmass read from header */
  double state_az_ac2;     /* Elevation read from header */
  double amprev;           /* Previous airmass in loop */
  double *azel = NULL;     /* AZEL coordinates */
  size_t base;             /* Offset into 3d data array */
  double extcorr = 1.0;    /* Extinction correction factor */
  dim_t i;                 /* Loop counter */
  dim_t k;                 /* Loop counter */
  AstFrameSet *wcs = NULL; /* Pointer to AST WCS frameset */
  AstFrameSet *state_wcs = NULL; /* Pointer to copy of frameset from header */

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

  /* Get a pointer that can be used for accessing the required items in the
  supplied structure. */
  pdata = (SmfCorrectExtinctionData *) job_data_ptr;

  /* It is more efficient to call astTranGrid than astTran2
     Allocate memory in adaptive mode just in case. */
  if (pdata->method == SMF__EXTMETH_FULL ||
      pdata->method == SMF__EXTMETH_ADAPT ) {
    azel = astMalloc( (2*pdata->npts)*sizeof(*azel) );
  }

  amprev = pdata->amfirst;

  /* Assume we are using quick mode for all time slices. */
  pdata->allquick = 1;

  for ( k=pdata->f1; k<=pdata->f2 && (*status == SAI__OK) ; k++) {
    /* Flags to indicate which mode we are using for this time slice */
    int quick = 0;  /* use single airmass */
    int adaptive = 0; /* switch from quick to full if required */
    if (pdata->method == SMF__EXTMETH_SINGLE) {
      quick = 1;
    } else if (pdata->method == SMF__EXTMETH_ADAPT) {
      quick = 1;
      adaptive = 1;
    } else {
      pdata->allquick = 0;
    }

    /* Call tslice_ast to update the header for the particular
       timeslice. If we're in QUICK mode then we don't need the WCS. Use
       a mutex to prevent multiple threads writing to the header at the same
       time.  */
    thrMutexLock( &data_mutex, status );
    smf_lock_data( pdata->data, 1, status );
    smf_tslice_ast( pdata->data, k, !quick, NO_FTS, status );

    /* Copy the required bit of the header into thread-local storage. */
    if( *status == SAI__OK ) {
       state_airmass = pdata->hdr->state->tcs_airmass;
       state_az_ac2 = pdata->hdr->state->tcs_az_ac2;
       if( !quick && pdata->tau != VAL__BADD && pdata->hdr->wcs) state_wcs = astCopy( pdata->hdr->wcs );
    }

    /* Unlock the AST Objects in the smfData then unlock the local mutex. */
    smf_lock_data( pdata->data, 0, status );
    thrMutexUnlock( &data_mutex, status );

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

    /* Read the WVM tau value if required */
    if (pdata->tausrc == SMF__TAUSRC_WVMRAW) {
      pdata->tau = pdata->wvmtau[k];
    }

    /* in all modes we need to keep track of the previous airmass in case
       we need to gap fill bad telescope data */
    if ( quick && pdata->ndims == 2 ) {
      /* for 2-D we use the FITS header directly */
      /* This may change depending on exact FITS keyword */
      airmass = pdata->amstart;

      /* speed is not an issue for a 2d image */
      adaptive = 0;

    } else {
      /* Else use airmass value in state structure */
      airmass = state_airmass;

      /* if things have gone bad use the previous value else store
         this value. We also need to switch to quick mode and disable adaptive. */
      if (airmass == VAL__BADD || airmass == 0.0 ) {
        if ( state_az_ac2 != VAL__BADD ) {
          /* try the elevation */
          airmass = palAirmas( M_PI_2 - state_az_ac2 );
        } else {
          airmass = amprev;
          quick = 1;
          adaptive = 0;
        }
      } else {
        amprev = airmass;
      }
    }

    /* If we're using the FAST application method, we assume a single
       airmass and tau for the whole array but we have to consider adaptive mode.
       If the tau is bad the extinction correction must also be bad. */
    if( pdata->tau == VAL__BADD) {
      extcorr = VAL__BADD;
    } else if (quick) {
      /* we have an airmass, see if we need to provide per-pixel correction */
      if (adaptive) {
        if (is_large_delta_atau( airmass, state_az_ac2, pdata->tau, status) ) {
          /* we need WCS if we disable fast mode */
          quick = 0;
          pdata->allquick = 0;

          thrMutexLock( &data_mutex, status );
          smf_lock_data( pdata->data, 1, status );
          smf_tslice_ast( pdata->data, k, 1, NO_FTS, status );
          state_airmass = pdata->hdr->state->tcs_airmass;
          state_az_ac2 = pdata->hdr->state->tcs_az_ac2;
          if (pdata->hdr->wcs) state_wcs = astCopy( pdata->hdr->wcs );
          smf_lock_data( pdata->data, 0, status );
          thrMutexUnlock( &data_mutex, status );

        }
      }

      if (quick) extcorr = exp(airmass*pdata->tau);
    }

    /* The previous test may have forced quick off so we can not combine
       the tests in one if-then-else block */
    if (!quick && pdata->tau != VAL__BADD )  {
      /* Not using quick so retrieve WCS to obtain elevation info */
      wcs = state_wcs;
      /* Check current frame, store it and then select the AZEL
         coordinate system */
      if (wcs != NULL) {
        if (strcmp(astGetC(wcs,"SYSTEM"), "AZEL") != 0) {
          astSet( wcs, "SYSTEM=AZEL"  );
        }
        /* Transfrom from pixels to AZEL */
        astTranGrid( wcs, 2, pdata->lbnd, pdata->ubnd, 0.1, 1000000, 1, 2,
                     pdata->npts, azel );
      } else {
        /* this time slice may have bad telescope data so we trap for this and re-enable
           "quick" with a default value. We'll only get here if airmass was good but
           SMU was bad so we use the good airmass. The map-maker won't be using this
           data but we need to use something plausible so that we do not throw off the FFTs */
        quick = 1;
        extcorr = exp(airmass*pdata->tau);
      }
    }
    /* Loop over data in time slice. Start counting at 1 since this is
       the GRID coordinate frame */
    base = pdata->npts * k;  /* Offset into 3d data array (time-ordered) */

    for (i=0; i < pdata->npts && ( *status == SAI__OK ); i++ ) {
      /* calculate array indices - assumes that astTranGrid fills up
         azel[] array in same order as bolometer data are aligned */
      size_t index;
      if ( pdata->isTordered ) {
        index = base + i;
      } else {
        index = k + (pdata->nframes * i);
      }

      if (!quick) {
        if (pdata->tau != VAL__BADD) {
          double zd;
          zd = M_PI_2 - azel[pdata->npts+i];
          airmass = palAirmas( zd );
          extcorr = exp(airmass*pdata->tau);
        } else {
          extcorr = VAL__BADD;
        }
      }

      if( pdata->allextcorr ) {
        /* Store extinction correction factor */
        pdata->allextcorr[index] = extcorr;
      } else {
        /* Otherwise Correct the data */
        if (extcorr != VAL__BADD) {
          if( pdata->indata && (pdata->indata[index] != VAL__BADD) ) {
            pdata->indata[index] *= extcorr;
          }

          /* Correct the variance */
          if( pdata->vardata && (pdata->vardata[index] != VAL__BADD) ) {
            pdata->vardata[index] *= extcorr * extcorr;
          }
        } else {
          if (pdata->indata) pdata->indata[index] = VAL__BADD;
          if (pdata->vardata) pdata->vardata[index] = VAL__BADD;
        }
      }

    }

    /* Note that we do not need to free "wcs" or revert its SYSTEM
       since smf_tslice_ast will replace the object immediately. */
  } /* End loop over timeslice */

  azel = astFree( azel );

}
Exemple #4
0
void smf_fit_qui( ThrWorkForce *wf, smfData *idata, smfData **odataq,
                  smfData **odatau, smfData **odatai, dim_t box, int ipolcrd,
                  int pasign, double paoff, double angrot, int north,
                  int *status ){

/* Local Variables: */
   AstFrameSet *wcs;        /* WCS FrameSet for current time slice */
   JCMTState *instate=NULL; /* Pointer to input JCMTState */
   JCMTState *outstate=NULL;/* Pointer to output JCMTState */
   const char *usesys;      /* Tracking system */
   dim_t *box_starts;       /* Array holding time slice at start of each box */
   dim_t box_size;          /* First time slice in box */
   dim_t intslice;          /* ntslice of idata */
   dim_t istart;            /* Input time index at start of fitting box */
   dim_t itime;             /* Time slice index */
   dim_t nbolo;             /* No. of bolometers */
   dim_t ncol;              /* No. of columns of bolometers in the array */
   dim_t ntime;             /* Time slices to check */
   dim_t ondata;            /* ndata of odata */
   dim_t ontslice;          /* ntslice of odata */
   double scale;            /* how much longer new samples are */
   int bstep;               /* Bolometer step between threads */
   int iworker;             /* Index of a worker thread */
   int nworker;             /* No. of worker threads */
   size_t i;                /* loop counter */
   smfData *indksquid=NULL; /* Pointer to input dksquid data */
   smfFitQUIJobData *job_data = NULL; /* Pointer to all job data */
   smfFitQUIJobData *pdata = NULL;/* Pointer to next job data */
   smfHead *hdr;            /* Pointer to data header this time slice */
   smf_qual_t *qua;         /* Input quality pointer */

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

/* Check supplied arguments. */
   if( !idata || !odataq || !odatau ) {
      *status = SAI__ERROR;
      errRep( "", "smf_fit_qui: NULL inputs supplied", status );
      return;
   }

   if( idata->ndims != 3 ) {
      *status = SAI__ERROR;
      errRep( "", "smf_fit_qui: idata is not 3-dimensional", status );
      return;
   }

/* Ensure the supplied smfData is time-ordered. So "bstride" is 1 and "tstride"
   is nbolo. */
   smf_dataOrder( wf, idata, 1, status );

/* Dimensions of input. */
   smf_get_dims( idata, NULL, &ncol, &nbolo, &intslice, NULL, NULL, NULL,
                 status );

/* Store a pointer to the quality array for the input smfData. */
   qua = smf_select_qualpntr( idata, NULL, status );;

/* 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. This function can only handle new data. */
   hdr = idata->hdr;
   instate = hdr->allState;
   ntime = ( intslice > 1000 ) ? 1000 : intslice;
   for( itime = 0; itime < ntime; itime++,instate++ ) {
      if( instate->pol_ang > 20 ) {
         *status = SAI__ERROR;
         errRep( " ","   POL2 data contains POL_ANG values in encoder "
                 "units - connot fit to such old data.", status );
         break;
      }
   }

/* Find the input time slice at which each fitting box starts, and the
   length of the output time axis (in time-slices). */
   smf1_find_boxes( intslice, hdr->allState, box, &ontslice, &box_starts,
                    status );

/* Time axis scaling factor. */
   scale = (double) intslice / (double) ontslice;

/* First copy everything from input to output except for the data that needs
   to be downsampled */

/* We want to copy everything in the smfHead except for allState. So we
   make a copy of the allState pointer, and then set it to NULL in the
   header before the copy */
   if( idata->hdr ) {
     instate = idata->hdr->allState;
     idata->hdr->allState = NULL;
   }

/* Similarly, we want everything in the smfDa except for the dksquid. */
   if( idata->da ) {
     indksquid = idata->da->dksquid;
     idata->da->dksquid = NULL;
   }

/* Create copies, storing them in the supplied  output smfData
   structures. Omit the header for U and I, as we will be copying the Q
   header into them.  */
   *odataq = smf_deepcopy_smfData( wf, idata, 0, SMF__NOCREATE_DATA |
                                SMF__NOCREATE_VARIANCE | SMF__NOCREATE_QUALITY,
                                0, 0, status );

   *odatau = smf_deepcopy_smfData( wf, idata, 0, SMF__NOCREATE_DATA |
                                SMF__NOCREATE_VARIANCE | SMF__NOCREATE_QUALITY |
                                SMF__NOCREATE_HEAD, 0, 0, status );

   if( odatai ) {
      *odatai = smf_deepcopy_smfData( wf, idata, 0, SMF__NOCREATE_DATA |
                                SMF__NOCREATE_VARIANCE | SMF__NOCREATE_QUALITY |
                                SMF__NOCREATE_HEAD, 0, 0, status );
   }

/* Restore values in idata now that we're done */
   if( instate ) idata->hdr->allState = instate;
   if( indksquid ) idata->da->dksquid = indksquid;

/* Store the required length for the output time axis. The time axis is
   axis two because the data is time-ordered. */
   (*odataq)->dims[ 2 ] = ontslice;
   (*odatau)->dims[ 2 ] = ontslice;
   if( odatai) (*odatai)->dims[ 2 ] = ontslice;

/* Get output dimensions - assumed to be the same for all three outputs. */
   ondata = ontslice*idata->dims[0]*idata->dims[1];

/* Allocate the data arrays for the outputs. */
   (*odataq)->pntr[0] = astCalloc( ondata, sizeof(double) );
   (*odatau)->pntr[0] = astCalloc( ondata, sizeof(double) );
   if( odatai ) (*odatai)->pntr[0] = astCalloc( ondata, sizeof(double) );

/* Allocate arrays for the output variances. */
   (*odataq)->pntr[1] = astCalloc( ondata, sizeof(double) );
   (*odatau)->pntr[1] = astCalloc( ondata, sizeof(double) );
   if( odatai ) (*odatai)->pntr[1] = astCalloc( ondata, sizeof(double) );

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

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

/* Loop round all output time slices. */
      for( itime = 0; itime < ontslice; itime++ ) {

/* Get the index of the first input time slice that contributes to the
   current output time slice. */
         istart = box_starts[ itime ];

/* Get the number of input time slices that contribute to the output time
   slice. */
         box_size = box_starts[ itime + 1 ] - istart;

/* If we are using north as the reference direction, get the WCS FrameSet
   for the input time slice that is at the middle of the output time
   slice, and set its current Frame to the tracking frame. */
         if( north ) {
            smf_tslice_ast( idata, istart + box_size/2, 1, NO_FTS, status );
            wcs = idata->hdr->wcs;
            usesys = sc2ast_convert_system( (idata->hdr->allState)[0].tcs_tr_sys,
                                            status );
            astSetC( wcs, "System", usesys );
         } else {
            wcs = NULL;
         }

/* Now enter the parellel code in which each thread calculates the values
   for a range of bolometers at the current output slice. */
         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;

            pdata->dat = ((double *) idata->pntr[0] ) + istart*nbolo;
            pdata->qua = qua + istart*nbolo;
            pdata->allstates = hdr->allState + istart;

            pdata->ipi = odatai ? ( (double*) (*odatai)->pntr[0] ) + itime*nbolo : NULL;
            pdata->ipq = ( (double*) (*odataq)->pntr[0] ) + itime*nbolo;
            pdata->ipu = ( (double*) (*odatau)->pntr[0] ) + itime*nbolo;
            pdata->ipv = ( (double*) (*odataq)->pntr[1] ) + itime*nbolo;

            pdata->nbolo = nbolo;
            pdata->ncol = ncol;
            pdata->box_size = box_size;
            pdata->ipolcrd = ipolcrd;
            pdata->pasign = pasign ? +1: -1;
            pdata->paoff = paoff;
            pdata->angrot = angrot;
            if( wcs ) {
               pdata->wcs = astCopy( wcs );
               astUnlock( pdata->wcs, 1 );
            } else {
               pdata->wcs = NULL;
            }

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

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

/* Lock and annul the AST objects used by each thread. */
         if( wcs ) {
            for( iworker = 0; iworker < nworker; iworker++ ) {
               pdata = job_data + iworker;
               astLock( pdata->wcs, 0 );
               pdata->wcs = astAnnul( pdata->wcs );
            }
         }
      }

/* Down-sample the smfHead -------------------------------------------------*/
      smfHead *hdr = (*odataq)->hdr;

      hdr->curframe = (dim_t) (((double) hdr->curframe + 0.5) / scale);
      hdr->nframes = ontslice;
      hdr->steptime *= scale;
      strcpy( hdr->dlabel, "Q" );
      strncpy( hdr->title, "POL-2 Stokes parameter Q", SMF__CHARLABEL );

/* Down-sample all the JCMTState values using nearest neighbours */
      instate = idata->hdr->allState;
      if( instate ) {

         hdr->allState = astCalloc( ontslice, sizeof(*instate) );
         outstate = hdr->allState;

         if( *status == SAI__OK ) {
            size_t frame;  /* index of nearest neighbour JCMTState */

            for( i=0; i<ontslice; i++ ) {
               frame = (size_t) round(((double) i + 0.5)*scale);
               memcpy( outstate + i, instate + frame, sizeof(*instate) );
            }

/* Then go back and properly down-sample the more important fast-changing
   fields like pointing. Note that since there are approximate values there
   already we need to explicitly re-initialize to 0. */

            RESAMPSTATE(instate, outstate, rts_end, intslice, ontslice, 0);

            RESAMPSTATE(instate, outstate, smu_az_jig_x, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, smu_az_jig_y, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, smu_az_chop_x, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, smu_az_chop_y, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, smu_tr_jig_x, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, smu_tr_jig_y, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, smu_tr_chop_x, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, smu_tr_chop_y, intslice, ontslice, 0);

            RESAMPSTATE(instate, outstate, tcs_tai, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, tcs_airmass, intslice, ontslice, 0);

/* Second coordinates (Dec, El etc) can not wrap 0 to 360 so we do not need
   to test for those cases */
            RESAMPSTATE(instate, outstate, tcs_az_ang, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_az_ac1, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_az_ac2, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, tcs_az_dc1, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_az_dc2, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, tcs_az_bc1, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_az_bc2, intslice, ontslice, 0);

            RESAMPSTATE(instate, outstate, tcs_tr_ang, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_tr_ac1, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_tr_ac2, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, tcs_tr_dc1, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_tr_dc2, intslice, ontslice, 0);
            RESAMPSTATE(instate, outstate, tcs_tr_bc1, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_tr_bc2, intslice, ontslice, 0);

            RESAMPSTATE(instate, outstate, tcs_en_dc1, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_en_dc2, intslice, ontslice, 0);

            RESAMPSTATE(instate, outstate, tcs_dm_abs, intslice, ontslice, 1);
            RESAMPSTATE(instate, outstate, tcs_dm_rel, intslice, ontslice, 0);

/* Wait for all the above smf_downsamp1 jobs to finish. */
            thrWait( wf, status );

         }
      }

/* Add a keyword to the Q header indicating the polarimetric reference
   direction. */
      smf_fits_updateL( (*odataq)->hdr, "POLNORTH", north,
                        north ? "Pol ref dir is tracking north" :
                                "Pol ref dir is focal plane Y", status );

/* Copy the Q header to the other outputs. */
      hdr = smf_deepcopy_smfHead( (*odataq)->hdr, status );
      (*odatau)->hdr = hdr;
      if( *status == SAI__OK ) {
         strcpy( hdr->dlabel, "U" );
         strncpy( hdr->title, "POL-2 Stokes parameter U", SMF__CHARLABEL );
      }

      if( odatai ) {
         hdr = smf_deepcopy_smfHead( (*odataq)->hdr, status );
         (*odatai)->hdr = hdr;
         if( *status == SAI__OK ) {
            strcpy( hdr->dlabel, "I" );
            strncpy( hdr->title, "POL-2 Stokes parameter I", SMF__CHARLABEL );
         }
      }
   }

/* Copy the variances from the Q smfData into the U and (and I) smfData. */
   if( *odataq && *status == SAI__OK ) {
      if( *odatau ) {
         memcpy( (*odatau)->pntr[1], (*odataq)->pntr[1], ondata*sizeof(double));
      }
      if( odatai && *odatai ) {
         memcpy( (*odatai)->pntr[1], (*odataq)->pntr[1], ondata*sizeof(double));
      }
   }

/* Ensure all smfDatas are time-ordered. */
   smf_dataOrder( wf, idata, 1, status );
   if( odatai && *odatai ) smf_dataOrder( wf, *odatai, 1, status );
   if( *odataq ) smf_dataOrder( wf, *odataq, 1, status );
   if( *odatau ) smf_dataOrder( wf, *odatau, 1, status );

/* Free resources. */
   job_data = astFree( job_data );
   box_starts = astFree( box_starts );
}
Exemple #5
0
static void smfFitPolyPar( void *job_data_ptr, int *status ) {
  size_t bstride;             /* bolo strides */
  double *curbolo=NULL;       /* pointer to current bolo data */
  double *curpoly=NULL;       /* pointer to poly coeffs fit to curbolo */
  double *curpolydata=NULL;   /* evaluated poly for curbolo */
  smf_qual_t *curqual=NULL;   /* pointer to current bolo quality */
  size_t i;                   /* Loop counter */
  double *indata=NULL;        /* Pointer to data array */
  size_t j;                   /* Loop counter */
  size_t k;                   /* Loop counter */
  dim_t nbolo;                /* Number of bolometers */
  size_t ncoeff;              /* Number of poly coeffs */
  dim_t ntslice;              /* Number of time slices */
  size_t nused;               /* Number of samples used in fit */
  smfFitPolyData *pdata=NULL; /* Pointer to job data */
  double *poly=NULL;          /* Pointer external poly coeff storage buffer */
  smf_qual_t *qual=NULL;      /* Pointer to QUALITY component */
  size_t tstride;             /* time strides */

  /* Retrieve job data */
  pdata = job_data_ptr;
  bstride = pdata->bstride;
  indata = pdata->indata;
  nbolo = pdata->nbolo;
  ntslice = pdata->ntslice;
  poly = pdata->poly;
  qual = (smf_qual_t *) pdata->qual;
  tstride = pdata->tstride;

  ncoeff = pdata->order + 1;

  /* Debugging message indicating thread started work */
  msgOutiff( SMF__TIMER_MSG, "",
             "smfFitPolyPar: thread starting on bolos %zu -- %zu",
             status, pdata->b1, pdata->b2 );

  /* If time-ordered need to copy bolometer into contiguous arrays.
     Otherwise we can use the bolometer data in-place. Polynomial
     data per-bolo also needs to be re-ordered so allocate a temp array. */

  if( pdata->isTordered ) {
    curbolo = astMalloc( ntslice*sizeof(*curbolo) );
    curqual = astMalloc( ntslice*sizeof(*curqual) );
  }
  curpoly = astMalloc( ncoeff*sizeof(*curpoly) );

  /* If removing the fit from the data, allocate space for evaluated
     polynomial here */

  if( pdata->remove ) {
    curpolydata = astMalloc( ntslice*sizeof(*curpolydata) );
  }

  /* Loop over bolometers. Only fit this bolometer if it is not
     flagged SMF__Q_BADB */
  for ( j=pdata->b1; (j<=pdata->b2) && (*status==SAI__OK); j++) {
    if( !(qual[j*bstride] & SMF__Q_BADB) ) {

      /* Pointer to current bolometer data */
      if( pdata->isTordered ) {
        for( i=0; i<ntslice; i++ ) {
          curbolo[i] = indata[i*tstride + j*bstride];
          curqual[i] = qual[i*tstride + j*bstride];
        }
      } else {
        curbolo = indata + j*bstride;
        curqual = (smf_qual_t *) qual + j*bstride;
      }

      smf_fit_poly1d( pdata->order, ntslice, 0, NULL, curbolo, NULL, curqual,
                      curpoly,NULL, curpolydata, &nused, status );

      if( *status == SAI__OK ) {
        /* Remove fit from data */
        if( pdata->remove ) {
          for( i=0; i<ntslice; i++ ) {
            if( (indata[i*tstride + j*bstride] != VAL__BADD) &&
                !(qual[j*bstride + i*tstride]&SMF__Q_MOD) ) {
              indata[i*tstride + j*bstride] -= curpolydata[i];
            }
          }
        }

        /* Copy the poly coefficients for this bolometer into poly */
        if( poly ) {
          for ( k=0; k<ncoeff; k++) {
            poly[j + k*nbolo] = curpoly[k];
          }
        }
      }
    }
  }

  /* Free up temp space */
  if( pdata->isTordered ) {
    curbolo = astFree( curbolo );
    curqual = astFree( curqual );
  }
  curpoly = astFree( curpoly );
  curpolydata = astFree( curpolydata );

  /* Debugging message indicating thread finished work */
  msgOutiff( SMF__TIMER_MSG, "",
             "smfFitPolyPar: thread finishing bolos %zu -- %zu",
             status, pdata->b1, pdata->b2 );
}
Exemple #6
0
static smfStepFix *smf1_read_steps( FILE *fd, double dcthresh0,
                                    dim_t dcsmooth0, dim_t dcfitbox0,
                                    int dcmaxsteps0, int dclimcorr0,
                                    size_t nrej0, int nstep0, int *nstep,
                                    int *status ) {
/*
*  Name:
*     smf1_read_steps

*  Purpose:
*     Read step descriptions from a file, and check global values.

*  Invocation:
*     smfStepFix *smf1_read_steps( FILE *fd, double dcthresh0,
*                                  dim_t dcsmooth0, dim_t dcfitbox0,
*                                  int dcmaxsteps0, int dclimcorr0,
*                                  size_t nrej0, int nstep0, int *nstep,
*                                  int *status )

*  Arguments:
*     fd = FILE * (Given)
*        A file descriptor from which to read the details of a set of
*        steps.
*     dcthresh0 = double (Given)
*        Expected value of DCTHRESH.
*     dcsmooth0 = dim_t (Given)
*        Expected value of DCSMOOTH.
*     dcfitbox0 = dim_t (Given)
*        Expected value of DCFITBOX.
*     dcmaxsteps0 = int (Given)
*        Expected value of DCMAXSTEPS.
*     dclimcorr = int (Given)
*        Expected value of DCLIMCORR.
*     nrej0 = size_t (Given)
*        The expected number of bolometers rejected.
*     nstep0 = int (Given)
*        The expected number of step fixes.
*     nstep = int * (Returned)
*        The number of steps fixes read from the file.
*     status = int* (Given and Returned)
*        Pointer to global status.

*  Description:
*     Reads information from the supplied file, returning an array of
*     step fixes. It also issues warnings if any of the global values
*     read from the file are not equal to the supplied expected values.

*  Returned Value:
*     A pointer to an array of smfStepFix structures describing the
*     steps fixes read form the file. The length of this array is equal
*     to "*nstep". The array should be freed using astFree when no longer
*     needed.

*/

/* Local Variables: */
   smfStepFix *result;
   char buf[ 256 ];
   char *c;
   double dval;
   double size;
   int bad;
   int corr;
   int end;
   int ibolo;
   int iline;
   int istep;
   int ival;
   int nc;
   int nold;
   int stage;
   int start;

/* Initialise */
   result = NULL;
   *nstep = 0;

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

/* Indicate we have not yet reached the tabular data. */
   stage = 0;

/* Initialise the index of the next step */
   istep = 0;

/* Indicate we do not yet know how many steps are described in the text
   file. */
   nold = -1;

/* Indicate no bad lines found yet. */
   bad = 0;

/* Loop round reading lines of text from the supplied file until an
   illegal line is read or the end of file is reached. */
   iline = 0;
   while( !bad && fgets( buf, sizeof(buf), fd ) && *status == SAI__OK ) {
      iline++;

/* Remove trailing white space. */
      c = buf + strlen( buf ) - 1;
      while( isspace( *c ) && c > buf ) c--;
      c[ 1 ] = 0;

/* scanf indicates success if the strings do not fail to match before the
   end of the shorter of the two. So we need to check that sufficient
   characters are compared. Initialise the number of characters compared. */
      nc = 0;

/* If we are not yet in the tabular data, look for header lines, and
   issue a message if the old value is different to the new value. */
      if( stage == 0 ) {

         if( sscanf( buf, "# Number of steps fixed = %d%n", &ival, &nc )
                     && nc > 26 ) {
            if( ival != nstep0 ) {
               msgSeti( "O", ival );
               msgSeti( "N", nstep0 );
               msgOut( "", "No. of steps fixed changed from ^O to ^N",
                       status );
            }

            nold = ival;

         } else if( sscanf( buf, "# Number of bolometers rejected = %d%n",
                            &ival, &nc ) && nc > 34 ) {
            if( ival != (int) nrej0 ) {
               msgSeti( "O", ival );
               msgSeti( "N", nrej0 );
               msgOut( "", "No. of bolometers rejected changed from ^O to ^N",
                       status );
            }

         } else if( sscanf( buf, "# DCFITBOX = %d%n", &ival, &nc ) && nc > 13 ) {
            if( ival != (int) dcfitbox0 ) {
               msgSeti( "O", ival );
               msgSeti( "N", dcfitbox0 );
               msgOut( "", "Warning: DCFITBOX changed from ^O to ^N", status );
            }

         } else if( sscanf( buf, "# DCMAXSTEPS = %d%n", &ival, &nc ) && nc > 14 ) {
            if( ival != dcmaxsteps0 ) {
               msgSeti( "O", ival );
               msgSeti( "N", dcmaxsteps0 );
               msgOut( "", "Warning: DCMAXSTEPS changed from ^O to ^N", status );
            }

         } else if( sscanf( buf, "# DCLIMCORR = %d%n", &ival, &nc ) && nc > 14 ) {
            if( ival != dclimcorr0 ) {
               msgSeti( "O", ival );
               msgSeti( "N", dclimcorr0 );
               msgOut( "", "Warning: DCLIMCORR changed from ^O to ^N", status );
            }

         } else if( sscanf( buf, "# DCSMOOTH = %d%n", &ival, &nc )
                    && nc > 18 ) {
            if( ival != (int) dcsmooth0 ) {
               msgSeti( "O", ival );
               msgSeti( "N", dcsmooth0 );
               msgOut( "", "Warning: DCSMOOTH changed from ^O to ^N", status );
            }

         } else if( sscanf( buf, "# DCTHRESH = %lg%n", &dval, &nc ) && nc > 13 ) {
            if( fabs( dval - dcthresh0 ) > 1.0E-10 ) {
               msgSetd( "O", dval );
               msgSetd( "N", dcthresh0 );
               msgOut( "", "Warning: DCTHRESH changed from ^O to ^N", status );
            }

/* Look for the line that marks the start of the tabular data. */
         } else if( !strcmp( buf, "# istep start end ibolo size corr" ) ) {
            stage = 1;
            msgBlank( status );

/* Allocate the returned array. */
            result = astMalloc( nold*sizeof( *result ) );
            *nstep = nold;

/* Abort if an illegal header line is read. */
         } else if( strcmp( buf, "#" ) &&
                    strncmp( buf, "# Steps fixed in '", 18 ) ) {
            bad = 1;
         }

/* If we are now reading tabular data... */
      } else {

/* Extract the numerical values from the line of text. */
         if( sscanf( buf, "%d %d %d %d %lg %d%n", &ival, &start, &end, &ibolo,
                     &size, &corr, &nc ) == 6 && nc > 14 ) {

/* Report an error if there is a jump in the step index (indicates lines
   missing from the supplied file). */
            if( ival != istep ) {
               *status = SAI__ERROR;
               msgSeti( "I", istep );
               errRep( "", "Step ^I data not found in old steps file:", status );
               bad = 1;

/* Otherwise, store the numerical values in the next element of the
   returned array. */
            } else if( istep < nold ){
               result[ istep ].id = ival;
               result[ istep ].ibolo = ibolo;
               result[ istep ].start = start;
               result[ istep ].end = end;
               result[ istep ].size = size;
               result[ istep ].corr = corr;
            }

/* Increment the index of the next step to check. */
            istep++;

/* Abort if the numerical values cannot be read from the line of text. */
         } else {
            bad = 1;
         }
      }
   }

/* Report an error if the last line read was illegal. */
   if( bad ) {
      *status = SAI__ERROR;
      msgSeti( "I", iline );
      errRep( "", "Illegal line found in old steps file (line ^I):", status );
      msgSetc( "L", buf );
      errRep( "", "'^L'", status );

/* Report an error if the number of steps in the old file is still unknown */
   } else if( nold == -1 ) {
      *status = SAI__ERROR;
      errRep( "", "Required line not found in old steps file:", status );
      errRep( "", "'# Number of steps fixed = ...'", status );

/* Report an error if the number of lines of tabular data was wrong. */
   } else if( istep != nold ) {
      *status = SAI__ERROR;
      errRep( "", "Incorrect number of step descriptions in old steps file.",
              status );
      msgSeti( "I", istep );
      msgSeti( "N", nold );
      errRep( "", "Header says file contains ^N steps but data for ^I "
              "steps was found.", status );
   }

   return result;
}
Exemple #7
0
int smf_despike_wvm(double* data, int n, int width, double tol, int* status) {
    int i, j;
    int removed = 0;
    double* box;
    int prev_box_start = -1;
    int box_start;
    int box_end;
    int max_box_start;
    int box_slop;
    int box_n;
    int half_width;
    double median = 0;

    if (*status != SAI__OK) {
        return 0;
    }

    /* Ensure box width is odd (so that it's got a simple median). */
    width |= 1;

    /* Check box isn't wider than data array. */
    if (width > n) {
        return 0;
    }

    /* Allocate temporary array for box in which we will calculate median. */
    box = astMalloc(width * sizeof(*box));
    if (!box) {
        return 0;
    }

    /* Pre-calculate furthest position through the array we could place
       the box and other box parameters. */
    max_box_start = n - width;
    half_width = width / 2;
    box_slop = width / 10;

    for (i = 0; i < n; i ++) {
        /* Determine box position in data array. */
        box_start = i - half_width;
        if (box_start < 0) {
            box_start = 0;
        }
        if (box_start > max_box_start) {
            box_start = max_box_start;
        }

        /* If the box moved significantly, recalculate the median. */
        if ((prev_box_start == -1)
                || (abs(box_start - prev_box_start) > box_slop)) {
            prev_box_start = box_start;
            box_end = box_start + width;
            box_n = 0;
            for (j = box_start; j < box_end; j++) {
                if (data[j] != VAL__BADD) {
                    box[box_n ++] = data[j];
                }
            }

            /* Check we've got a resonable amount of data. */
            if (box_n > half_width) {
                /* (If there were an odd number of bad values, box_n may be
                    even, in which case this isn't the true median.) */
                gsl_sort(box, 1, box_n);
                median = box[box_n / 2];
            }
            else {
                median = 0;
            }
        }


        /* If we've got a valid median, compare the value to it. */
        if (median) {
            if (fabs(data[i] - median) / median > tol) {
                data[i] = VAL__BADD;
                removed ++;
            }
        }
    }

    /* Free the temporary array and return the number of points removed. */
    astFree(box);

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

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

  /* Assert bolo-ordered data */
  smf_model_dataOrder( 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, 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, status );

      smf_write_smfData( res->sdata[idx], NULL, qua_data, "res_b4",
                         NULL, 0, 0, MSG__VERB, 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, status );
      smf_write_smfData( model->sdata[idx], NULL, qua_data, "model_af",
                         NULL, 0, 0, MSG__VERB, 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 );
}
Exemple #10
0
HDSLoc *cupidReinhold( int type, int ndim, int *slbnd, int *subnd, void *ipd,
                     double *ipv, double rms, AstKeyMap *config, int velax,
                     double beamcorr[ 3 ], int *status ){
/*
*+
*  Name:
*     cupidReinhold

*  Purpose:
*     Identify clumps of emission within a 1, 2 or 3 dimensional NDF using
*     the REINHOLD algorithm.

*  Language:
*     Starlink C

*  Synopsis:
*     HDSLoc *cupidReinhold( int type, int ndim, int *slbnd, int *subnd,
*                          void *ipd, double *ipv, double rms,
*                          AstKeyMap *config, int velax,
*                          double beamcorr[ 3 ], int *status )

*  Description:
*     This function identifies clumps within a 1, 2 or 3 dimensional data
*     array using the REINHOLD algorithm, developed by Kim Reinhold at
*     JAC. This algorithm identifies the boundaries between clumps by
*     looking for minima in 1D sections through the data. No a priori clump
*     profile is assumed. In this algorithm, clumps never overlap.

*  Parameters:
*     type
*        An integer identifying the data type of the array values pointed to
*        by "ipd". Must be either CUPID__DOUBLE or CUPID__FLOAT (defined in
*        cupid.h).
*     ndim
*        The number of dimensions in the data array. Must be 2 or 3.
*     slbnd
*        Pointer to an array holding the lower pixel index bound of the
*        data array on each axis.
*     subnd
*        Pointer to an array holding the upper pixel index bound of the
*        data array on each axis.
*     ipd
*        Pointer to the data array. The elements should be stored in
*        Fortran order. The data type of this array is given by "itype".
*     ipv
*        Pointer to the input Variance array, or NULL if there is no Variance
*        array. The elements should be stored in Fortran order. The data
*        type of this array is "double".
*     rms
*        The default value for the global RMS error in the data array.
*     config
*        An AST KeyMap holding tuning parameters for the algorithm.
*     velax
*        The index of the velocity axis in the data array (if any). Only
*        used if "ndim" is 3.
*     beamcorr
*        An array in which is returned the FWHM (in pixels) describing the
*        instrumental smoothing along each pixel axis. The clump widths
*        stored in the output catalogue are reduced to correct for this
*        smoothing.
*     status
*        Pointer to the inherited status value.

*  Returned Value:
*     A locator for a new HDS object which is an array of NDF structures.
*     Each NDF will hold the data values associated with a single clump
*     and will be the smallest possible NDF that completely contains the
*     corresponding clump. Pixels not in the clump will be set bad. The
*     pixel origin is set to the same value as the supplied NDF.

*  Copyright:
*     Copyright (C) 2009 Science & Technology Facilities Council.
*     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
*     TIMJ: Tim Jenness (JAC, Hawaii)
*     {enter_new_authors_here}

*  History:
*     16-JAN-2006 (DSB):
*        Original version.
*     14-JAN-2009 (TIMJ):
*        Use MERS for message filtering.
*     20-NOV-2013 (DSB):
*        Supplied config KeyMap now holds the method parameters directly,
*        rather than holding them in a sub-KeyMap.
*     25-MAY-2017 (DSB):
*        Switch off group history and provenance recording whilst creating
*        clump NDFs. This is because it can inflate the time taken to run
*        findclumps enormously if there are many thousands of clumps.
*     {enter_further_changes_here}

*  Bugs:
*     {note_any_bugs_here}

*-
*/

/* Local Variables: */

   HDSLoc *ret;         /* Locator for the returned array of NDFs */
   double *pd;          /* Pointer to next element of data array */
   double *peakvals;    /* Pointer to array holding clump peak values */
   double cathresh;     /* Threshold for second cellular automata */
   double flatslope;    /* Minimum significant slope at edge of a peak */
   double noise;        /* Noise level */
   double pv;           /* Pixel value */
   double thresh;       /* Minimum peak value to be considered */
   float *pf;           /* Pointer to next element of data array */
   int *clbnd;          /* Array holding lower axis bounds of all clumps */
   int *cubnd;          /* Array holding upper axis bounds of all clumps */
   int *igood;          /* Pointer to array holding usable clump indices */
   int *m1;             /* Pointer to mask array */
   int *m2;             /* Pointer to mask array */
   int *m3;             /* Pointer to mask array */
   int *mask2;          /* Pointer to array marking out edge pixels */
   int *mask;           /* Pointer to array marking out edge pixels */
   int *nrem;           /* Pointer to array marking out edge pixels */
   int *pa;             /* Pointer to next element in the pixel assignment array */
   int caiter;          /* The number of CA iterations to perform */
   int dims[3];         /* Pointer to array of array dimensions */
   int el;              /* Number of elements in array */
   int fixiter;         /* The number of CA iterations to perform */
   int i;               /* Loop count */
   int ii;              /* Loop count */
   int ix;              /* Grid index on 1st axis */
   int iy;              /* Grid index on 2nd axis */
   int iz;              /* Grid index on 3rd axis */
   int j;               /* Loop count */
   int maxid;           /* Largest id for any peak (smallest is zero) */
   int minlen;          /* Minimum size of a clump in pixels along one dimension*/
   int minpix;          /* Minimum total size of a clump in pixels */
   int more;            /* Continue looping?*/
   int ngood;           /* Number of good clumps */
   int nsmall;          /* Number of clumps that are too small */
   int nthin;           /* Number of clumps that span only a single pixel */
   int old_ghstate;     /* Non-zero if group history recording is switched on */
   int old_pvstate;     /* Non-zero if provenance recording is switched on */
   int peakval;         /* Minimum value used to flag peaks */
   int skip[3];         /* Pointer to array of axis skips */

/* Initialise */
   ret = NULL;

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

/* Say which method is being used. */
   msgBlankif( MSG__NORM, status );
   msgOutif( MSG__NORM, "", "Reinhold:", status );

/* Return the instrumental smoothing FWHMs */
   beamcorr[ 0 ] = cupidConfigD( config, "FWHMBEAM", 2.0, status );
   beamcorr[ 1 ] = beamcorr[ 0 ];
   if( ndim == 3 ) {
      beamcorr[ 2 ] = beamcorr[ 0 ];
      beamcorr[ velax ]= cupidConfigD( config, "VELORES", 2.0, status );
   }

/* Find the size of each dimension of the data array, and the total number
   of elements in the array, and the skip in 1D vector index needed to
   move by pixel along an axis. We use the memory management functions of the
   AST library since they provide greater security and functionality than
   direct use of malloc, etc. */
   el = 1;
   for( i = 0; i < ndim; i++ ) {
      dims[ i ] = subnd[ i ] - slbnd[ i ] + 1;
      el *= dims[ i ];
      skip[ i ] = ( i == 0 ) ? 1 : skip[ i - 1 ]*dims[ i - 1 ];
   }
   for( ; i < 3; i++ ) {
      dims[ i ] = 1;
      skip[ i ] = 0;
   }

/* Get various configuration parameters. */
   rms = cupidConfigD( config, "RMS", rms, status );
   minlen = cupidConfigI( config, "MINLEN", 4, status );
   noise = cupidConfigRMS( config, "NOISE", rms, 2*rms, status );
   thresh = cupidConfigRMS( config, "THRESH", rms, noise + 2*rms, status );
   flatslope = cupidConfigRMS( config, "FLATSLOPE", rms, rms, status );
   cathresh = pow( 3, ndim ) - 1.0;
   cathresh = cupidConfigI( config, "CATHRESH", (int) cathresh, status );
   caiter = cupidConfigI( config, "CAITERATIONS", 1, status );
   fixiter = cupidConfigI( config, "FIXCLUMPSITERATIONS", 1, status );

/* Get the minimum allowed number of pixels in a clump. */
   minpix = cupidDefMinPix( ndim, beamcorr, noise, thresh, status );
   minpix = cupidConfigI( config, "MINPIX", minpix, status );

/* Convert CATHRESH from a number of pixels to a fraction. */
   cathresh = cathresh/pow( 3, ndim );
   if( cathresh > 0.98 ) cathresh = 0.98;
   if( cathresh < 0 ) cathresh = 0.0;
   cathresh += 0.01;

/* Get a mask which is the same size and shape as the data array and which
   holds CUPID__KEDGE at every pixel thought to be on the edge of a clump.
   This is done by scanning the data cube using sets of parallel lines in
   different directions. Peaks are searched for in each line, and then the
   edges found by following the curve down from each peak until the
   gradient becomes zero or positive, or until the data value drops below a
   threshold value. Pixels which correspond to peaks in the data cube
   are flagged with the value greater than or equal to the returned
   "*peakval" value. All other pixels are set to some other value (which
   will usually be CUPID__KBACK but will be something else at positions of
   peaks which were not peaks in all scan directions). */
   msgOutif( MSG__DEBUG, "", "Finding clump edges...", status );
   mask = cupidRInitEdges( type, ipd, el, ndim, dims, skip, minlen, thresh,
                           noise, rms, flatslope, &peakval, status );

/* Dilate the edge regions using a cellular automata. This creates a new
   mask array in which a pixel is marked as an edge pixel if any of its
   neighbours are marked as edge pixels in the mask array created above. */
   msgOutif( MSG__DEBUG, "", "Dilating clump edges...", status );
   mask2 = cupidRCA( mask, NULL, el, dims, skip, 0.0, peakval, CUPID__KEDGE,
                     CUPID__KBACK, 0, status );

/* Erode the edge regions using a second cellular automata. This over-writes
   the original mask array so that a pixel is marked as an edge pixel if a
   fraction greater than "cathresh" of neighbouring pixels are marked as edge
   pixels in "mask2". We loop doing this "CAiteration" times. */
   if( caiter > 0 ) msgOutif( MSG__DEBUG,"", "Eroding clump edges...", status );
   m1 = mask;
   m2 = mask2;
   for( i = 0; i < caiter; i++ ) {
      m1 = cupidRCA( m2, m1, el, dims, skip, cathresh, peakval, CUPID__KEDGE,
                     CUPID__KBACK, 0, status );
      m3 = m1;
      m1 = m2;
      m2 = m3;
   }

/* Fill the volume around each peak with integer values which indicate
   which peak they are close to. All the pixels around one peak form one
   clump. */
   msgOutif( MSG__DEBUG, "", "Filling clumps...", status );
   maxid = cupidRFillClumps( m2, m1, el, ndim, skip, dims, peakval, status );

/* Abort if no clumps found. */
   if( maxid < 0 ) {
      msgOutif( MSG__NORM, "", "No usable clumps found.", status );
      msgBlankif( MSG__NORM, status );
      goto L10;
   }

/* Smooth the boundaries between the clumps. This cellular automata replaces
   each output pixel by the most commonly occuring value within a 3x3x3
   cube of input pixels centred on the output pixel. Put the smoothed
   results back into the supplied "m1" array. */
   if( fixiter >0 ) msgOutif( MSG__DEBUG, "", "Smoothing clump boundaries...", status );
   for( i = 0; i < fixiter; i++ ) {
      m2 = cupidRCA2( m1, m2, el, dims, skip, status );
      m3 = m2;
      m2 = m1;
      m1 = m3;
   }

/* Allocate an array used to store the number of pixels remaining in each
   clump. */
   nrem = astMalloc( sizeof( int )*( maxid + 1 ) );

/* Allocate an array used to store the peak value in every clump. */
   peakvals = astMalloc( sizeof( double )*( maxid + 1 ) );

/* Determine the bounding box of every clump. First allocate memory to
   hold the bounding boxes. */
   clbnd = astMalloc( sizeof( int )*( maxid + 1 )*3 );
   cubnd = astMalloc( sizeof( int )*( maxid + 1 )*3 );
   igood = astMalloc( sizeof( int )*( maxid + 1 ) );
   if( igood ) {

/* Initialise a list to hold zero for every clump id. These values are
   used to count the number of pixels remaining in each clump. Also
   initialise the peak values to a very negative value. */
      for( i = 0; i <= maxid; i++ ) {
         nrem[ i ] = 0;
         peakvals[ i ] = VAL__MIND;
      }

/* Initialise the bounding boxes. */
      for( i = 0; i < 3*( maxid + 1 ); i++ ) {
         clbnd[ i ] = VAL__MAXI;
         cubnd[ i ] = VAL__MINI;
      }

/* Loop round every pixel in the final pixel assignment array. */
      if( type == CUPID__DOUBLE ) {
         pd = (double *) ipd;
         pf = NULL;
      } else {
         pf = (float *) ipd;
         pd = NULL;
      }
      pa = m1;
      for( iz = 1; iz <= dims[ 2 ]; iz++ ){
         for( iy = 1; iy <= dims[ 1 ]; iy++ ){
            for( ix = 1; ix <= dims[ 0 ]; ix++, pa++ ){

/* Get the data value at this pixel */
               if( type == CUPID__DOUBLE ) {
                  pv = *(pd++);
               } else {
                  pv = (double) *(pf++);
               }

/* Skip pixels which are not in any clump. */
               if( *pa >= 0 ) {

/* Increment the number of pixels in this clump. */
                  ++( nrem[ *pa ] );

/* If this pixel value is larger than the current peak value for this
   clump, record it. */
                  if( pv > (double) peakvals[ *pa ] ) peakvals[ *pa ] = pv;

/* Get the index within the clbnd and cubnd arrays of the current bounds
   on the x axis for this clump. */
                  i = 3*( *pa );

/* Update the bounds for the x axis, then increment to get the index of the y
   axis bounds. */
                  if( ix < clbnd[ i ] ) clbnd[ i ] = ix;
                  if( ix > cubnd[ i ] ) cubnd[ i ] = ix;
                  i++;

/* Update the bounds for the y axis, then increment to get the index of the z
   axis bounds. */
                  if( iy < clbnd[ i ] ) clbnd[ i ] = iy;
                  if( iy > cubnd[ i ] ) cubnd[ i ] = iy;
                  i++;

/* Update the bounds for the z axis. */
                  if( iz < clbnd[ i ] ) clbnd[ i ] = iz;
                  if( iz > cubnd[ i ] ) cubnd[ i ] = iz;
               }
            }
         }
      }

/* Loop round counting the clumps which are too small or too low. Put the
   indices of usable clumps into another array. */
      nsmall = 0;
      ngood = 0;
      nthin = 0;
      for( i = 0; i <= maxid; i++ ) {
         j = 3*i;

         if( nrem[ i ] <= minpix ) {
            nsmall++;

         } else if( clbnd[ j ] == cubnd[ j ] ||
                  ( clbnd[ j + 1 ] == cubnd[ j + 1 ] && ndim > 1 ) ||
                  ( clbnd[ j + 2 ] == cubnd[ j + 2 ] && ndim > 2 ) ) {
            nthin++;

         } else {
            igood[ ngood++ ] = i;
         }
      }

      if( ngood == 0 ) msgOutif( MSG__NORM,"", "No usable clumps found.", status );

      if( nsmall == 1 ){
        msgOutif( MSG__NORM, "", "One clump rejected because it contains too few pixels.", status );
      } else if( nsmall > 1 ) {
        msgSeti( "N", nsmall );
        msgOutif( MSG__NORM, "", "^N clumps rejected because they contain too few pixels.", status );
      }
      if( nthin == 1 ) {
        msgOutif( MSG__NORM, "", "1 clump rejected because it spans only a single "
                  "pixel along one or more axes.", status );

      } else if( nthin > 1 ) {
        msgSeti( "N", nthin );
        msgOutif( MSG__NORM, "", "^N clumps rejected because they spans only a single "
                  "pixel along one or more axes.", status );
      }

/* Sort the clump indices into descending order of peak value. */
      j = ngood;
      more = 1;
      while( more ) {
         j--;
         more = 0;
         for( i = 0; i < j; i++ ) {
            if( peakvals[ igood[ i ] ] < peakvals[ igood[ i + 1 ] ] ) {
               ii = igood[ i + 1 ];
               igood[ i + 1 ] = igood[ i ];
               igood[ i ] = ii;
               more = 1;
            }
         }
      }

/* Loop round creating an NDF describing each usable clump. Temporarily
   switch off group history and provenance recording since there can be
   thousands of these NDFs. */
      ndgHltgh( 0, &old_ghstate, status );
      ndgHltpv( 0, &old_pvstate, status );
      for( j = 0; j < ngood; j++ ) {
         i = igood[ j ];
         ret = cupidNdfClump( type, ipd, m1, el, ndim, dims, skip, slbnd,
                              i, clbnd + 3*i, cubnd + 3*i, NULL, ret,
                              cupidConfigD( config, "MAXBAD", 0.05, status ),
                              status );
      }
      ndgHltgh( old_ghstate, NULL, status );
      ndgHltpv( old_pvstate, NULL, status );

/* Free resources */
      clbnd = astFree( clbnd );
      cubnd = astFree( cubnd );
      igood = astFree( igood );
   }

   peakvals = astFree( peakvals );
   nrem = astFree( nrem );

L10:;

/* Free resources */
   mask = astFree( mask );
   mask2 = astFree( mask2 );

/* Return the list of clump NDFs. */
   return ret;

}
Exemple #11
0
void smurf_fts2_split(int* status)
{
  if( *status != SAI__OK ) { return; }

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

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

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

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

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

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


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

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

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

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

  /* BEGIN NDF */
  ndfBegin();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    } while (!done);


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

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

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

  /* END NDF */
  ndfEnd(status);

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

  /* Delete groups */
  if(gIn)     { grpDelet(&gIn, status);  }
  if(gOut)    { grpDelet(&gOut, status); }
}
Exemple #12
0
void smurf_jsatileinfo( int *status ) {

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

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

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

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

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

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

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

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

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

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

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

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

/* Loop round every row and column */
      for( j = 0; j < ubnd[ 1 ] - lbnd[ 1 ] + 1; j++ ) {
         for( i = 0; i < ubnd[ 0 ] - lbnd[ 0 ] + 1; i++ ) {

/* Store the tile index at this pixel. */
            *(ipntr++) = smf_jsatilexy2i( i, j, &skytiling, status );
         }
      }

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

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

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

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

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

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

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

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

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

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

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

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

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

   gx[ 0 ] = 0.5*( point1[ 0 ] + point2[ 0 ] );   /* Centre */
   gy[ 0 ] = 0.5*( point1[ 1 ] + point2[ 1 ] );

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

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

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

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

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

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

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

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

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

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

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

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

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

/* Format this size as a dec value (i.e. arc-distance) and display it. */
   msgSetc( "SIZE",  astFormat( fs, 2, maxdist ) );
   msgOut( " ", "      Size: ^SIZE", status );

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

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

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

   } else {

      nc = 512;
      jcmt_tiles = astMalloc( nc );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* End the AST context. */
   astEnd;

/* Issue a status indication.*/
   msgBlank( status );
   if( *status == SAI__OK ) {
      msgOutif( MSG__VERB, "", "JSATILEINFO succeeded.", status);
   } else {
      msgOutif( MSG__VERB, "", "JSATILEINFO failed.", status);
   }
}