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

  /* Local Variables */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if( *status == SAI__OK ) {

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

      if( *status == SAI__OK ) {

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

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

        if( astIsAUnitMap( testsimpmap ) ) {

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

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

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

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

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

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

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

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

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

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

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

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

  }

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

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

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


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

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

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

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

    if( *status == SAI__OK ) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        ndfAnnul( &bndndf, status );

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

  /* Clean Up */

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


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

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

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

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

}
Example #2
0
void smf_flag_spikes( ThrWorkForce *wf, smfData *data, smf_qual_t mask,
                      double thresh, size_t box, size_t *nflagged,
                      int *status ){

/* Local Variables */
   int i;                      /* Loop counter */
   smfFlagSpikesData *job_data=NULL;/* Array of job data for each thread */
   dim_t nbolo;                /* Number of bolometers */
   dim_t ntime;                /* Number of time-slices */
   double *dat = NULL;         /* Pointer to bolo data */
   smfFlagSpikesData *pdata=NULL;/* Pointer to job data */
   int nw;                     /* Number of worker threads */
   size_t bstride;             /* Vector stride between bolometer samples */
   size_t nflag;               /* Number of samples flagged */
   size_t tstride;             /* Vector stride between time samples */
   smf_qual_t *qua = NULL;     /* Pointer to quality flags */
   size_t step;                /* step size for dividing up work */
   int njobs=0;                /* Number of jobs to be processed */

/* Check inherited status. Also return immediately if no spike flagging
   is to be performed. */
   if( *status != SAI__OK || thresh == 0.0 ) return;

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

/* Check we have double precision data. */
   smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status );

/* Get a pointer to the quality array to use. */
   qua = smf_select_qualpntr( data, NULL, status );

/* Report an error if we have no quality array. */
   if( !qua && *status == SAI__OK ) {
     *status = SAI__ERROR;
     errRep( " ", FUNC_NAME ": No valid QUALITY array was provided", status );
   }

/* Get a pointer to the data array to use. Report an error if we have
   no data array. */
   dat = data->pntr[0];
   if( !dat && *status == SAI__OK ) {
     *status = SAI__ERROR;
     errRep( " ", FUNC_NAME ": smfData does not contain a DATA component",
             status);
   }

/* Check the supplied thresh value is valid. */
   if( thresh <= 0 && *status == SAI__OK ) {
      *status = SAI__ERROR;
      msgSetd( "THRESH", thresh );
      errRep( " ", FUNC_NAME ": Can't find spikes: thresh=^THRESH, must be > 0",
              status);
   }

/* Check the supplied box value is valid. */
   if( box <= 2 && *status == SAI__OK ) {
      *status = SAI__ERROR;
      msgSeti( "BOX", box );
      errRep( " ", FUNC_NAME ": Can't find spikes: box=^BOX, must be > 2",
              status);
   }

/* Obtain data dimensions, and the stride between adjacent elements on
   each axis (bolometer and time). Use the existing data order to avoid
   the cost of re-ordering. */
   smf_get_dims( data,  NULL, NULL, &nbolo, &ntime, NULL, &bstride, &tstride,
                 status );

/* Check we have room for at least 3 boxes along the time axis. */
   if( 3*box > ntime && *status == SAI__OK ) {
      *status = SAI__ERROR;
      msgSeti( "BOX", box );
      msgSeti( "MAX", ntime/3 - 1 );
      errRep( " ", FUNC_NAME ": Can't find spikes: box=^BOX is too large, "
              " must be < ^MAX.", status);
   }

/* Set up the job data */

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

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

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

     pdata->b1 = i*step;
     pdata->b2 = (i+1)*step-1;

/* if b1 is greater than the number of bolometers, we've run out of jobs... */
     if( pdata->b1 >= nbolo ) {
       break;
     }

/* increase the jobs counter */
     njobs++;

/* Ensure that the last thread picks up any left-over bolometers */
     if( (i==(nw-1)) && (pdata->b1<(nbolo-1)) ) {
       pdata->b2=nbolo-1;
     }

     pdata->ijob = -1;   /* Flag job as ready to start */
     pdata->box = box;
     pdata->bstride = bstride;
     pdata->dat = dat;
     pdata->mask = mask;
     pdata->thresh = thresh;
     pdata->nbolo = nbolo;
     pdata->ntime = ntime;
     pdata->qua = qua;
     pdata->tstride = tstride;
   }

/* Submit jobs to find spikes in each block of bolos */
   thrBeginJobContext( wf, status );
   for( i=0; (*status==SAI__OK)&&i<njobs; i++ ) {
     pdata = job_data + i;
     pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata,
                                smfFlagSpikesPar, 0, NULL, status );
   }

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

/* Count flagged samples from all of the jobs and free resources */
   nflag=0;
   if( job_data ) {
     for( i=0; i<njobs; i++ ) {
       pdata = job_data + i;
       nflag += pdata->nflag;
     }
     job_data = astFree( job_data );
   }

/* Return the number of flagged samples, if requested */
   if( nflagged ) *nflagged = nflag;

}
Example #3
0
smf_qual_t * smf_qual_map( ThrWorkForce *wf, int indf, const char mode[],
                           smf_qfam_t *family, size_t *nmap, int * status ) {

  size_t i;             /* Loop counter */
  int itemp = 0;        /* temporary int */
  smf_qfam_t lfamily = SMF__QFAM_NULL; /* Local quality family */
  size_t nout;          /* Number of elements mapped */
  size_t numqn = 0;     /* number of quality names */
  IRQLocs *qlocs = NULL;/* IRQ Quality */
  unsigned char *qmap;  /* pointer to mapped unsigned bytes */
  void *qpntr[1];       /* Somewhere to put the mapped pointer */
  smf_qual_t *retval = NULL; /* Returned pointer */
  int there;            /* Does the NDF Have a Quality component? */
  char xname[DAT__SZNAM+1];  /* Name of extension holding quality names */
  SmfQualMapData *job_data = NULL;
  SmfQualMapData *pdata;
  int nw;
  size_t step;
  int iw;


  if (*status != SAI__OK) return retval;

  /* Ensure jobs submitted to the workforce within this function are
     handled separately to any jobs submitted earlier (or later) by any
     other function. */
  thrBeginJobContext( wf, status );

  /* how many elements do we need */
  ndfSize( indf, &itemp, status );
  nout = itemp;
  if (nmap) *nmap = nout;

  /* malloc the QUALITY buffer. Initialise to zero to simplify logic
     below. It is difficult to determine in advance which case can use
     initialisation. */
  retval = astCalloc( nout, sizeof(*retval) );

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

  /* Find how many elements to process in each worker thread. */
  step = nout/nw;
  if( step == 0 ) step = 1;

  /* Allocate job data for threads, and store common values. Ensure that the
     last thread picks up any left-over elements.  */
  job_data = astCalloc( nw, sizeof(*job_data) );
  if( *status == SAI__OK ) {
    for( iw = 0; iw < nw; iw++ ) {
      pdata = job_data + iw;
      pdata->i1 = iw*step;
      if( iw < nw - 1 ) {
        pdata->i2 = pdata->i1 + step - 1;
      } else {
        pdata->i2 = nout - 1 ;
      }
      pdata->retval = retval;

    }
  }

  /* If the NDF has no QUality component, return the buffer filled with
     zeros. */
  ndfState( indf, "QUALITY", &there, status );
  if( there ) {

    /* READ and UPDATE mode require that the QUALITY is processed
       and copied before being returned. WRITE mode means that the
       buffer contains no information to copy yet. WRITE/ZERO
       and WRITE/BAD also require that we do not do any quality
       handling */
    if ( strncmp(mode, "WRITE",5) == 0 ) {
      /* WRITE and WRITE/ZERO are actually treated the same way
         because we always initialise */
      if ( strcmp( mode, "WRITE/BAD") == 0 ) {
        for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->operation = 1;
            thrAddJob( wf, 0, pdata, smf1_qual_map, 0, NULL, status );
        }
        thrWait( wf, status );
      }

      /* unmap the NDF buffer and return the pointer */
      if (family) *family = lfamily;
      return retval;
    }

    /* Map the quality component (we always need to do this) */
    ndfMap( indf, "QUALITY", "_UBYTE", mode, &qpntr[0], &itemp, status );
    qmap = qpntr[0];

    /* Need to find out what quality names are in play so we
       can work out which family to translate them to */
    irqFind( indf, &qlocs, xname, status );
    numqn = irqNumqn( qlocs, status );

    if ( *status == IRQ__NOQNI || numqn == 0) {
      /* do not have any names defined so we have no choice
         in copying the values directly out the file */
      if (*status != SAI__OK) errAnnul( status );

      /* simple copy with type conversion */

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

    } else {
      IRQcntxt contxt = 0;
      int ndfqtosmf[NDFBITS];        /* NDF bit (arr index) and SMURF alternative */
      int ndfqtoval[NDFBITS];        /* NDF bit (arr index) and corresponding Qual value */
      int ndfqval[NDFBITS];          /* Bit values for NDF quality */
      int identity = 1;        /* Is this a simple identity map? */

      /* prefill the mapping with bit to bit mapping */
      for (i=0; i<NDFBITS; i++) {
        ndfqtosmf[i] = i;
        ndfqtoval[i] = BIT_TO_VAL(i);
        ndfqval[i] = ndfqtoval[i];
      }

      /* Now translate each name to a bit */
      for (i = 0; i < numqn && *status == SAI__OK; i++) {
        char qname[IRQ__SZQNM+1];
        char commnt[IRQ__SZCOM+1];
        int fixed;
        int value;
        int bit;
        int done;
        smf_qual_t qval;
        smf_qfam_t tmpfam = 0;

        irqNxtqn( qlocs, &contxt, qname, &fixed, &value, &bit,
                  commnt,sizeof(commnt), &done, status );
        bit--;    /* IRQ starts at 1 */

        /* Now convert the quality name to a quality value
           and convert that to a bit. These should all be
           less than 9 bits because they are in the NDF file. */
        qval = smf_qual_str_to_val( qname, &tmpfam, status );

        if (*status == SMF__BADQNM ) {
          /* annul status and just copy this bit from the file
             to SMURF without change. This might result in a clash
             of bits but we either do that or drop out the loop
             and assume everything is broken */
          if (*status != SAI__OK) errAnnul(status);
          ndfqtosmf[bit] = bit;
          ndfqtoval[bit] = BIT_TO_VAL(bit);

        } else if( *status == SAI__OK ){
          if (lfamily == SMF__QFAM_NULL) {
            lfamily = tmpfam;
          } else if (lfamily != tmpfam) {
            msgOutif(MSG__QUIET, "",
                     "WARNING: Quality names in file come from different families",
                     status );
          }
          ndfqtosmf[bit] = smf_qual_to_bit( qval, status );
          ndfqtoval[bit] = qval;

          /* not a 1 to 1 bit translation */
          if (bit != ndfqtosmf[bit]) identity = 0;
        }
      }

      /* Now copy from the file and translate the bits. If this is an
         identity mapping or we do not know the family then we go quick. */
      if (*status == SAI__OK) {
        if ( (identity && lfamily != SMF__QFAM_TCOMP) || lfamily == SMF__QFAM_NULL) {
          for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->qmap = qmap;
            pdata->ndfqval = ndfqval;
            pdata->lfamily = lfamily;
            pdata->ndfqtoval = ndfqtoval;
            pdata->ndfqval = ndfqval;
            pdata->operation = 2;
            thrAddJob( wf, 0, pdata, smf1_qual_map, 0, NULL, status );
          }
          thrWait( wf, status );

        } else {

          for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->qmap = qmap;
            pdata->ndfqval = ndfqval;
            pdata->lfamily = lfamily;
            pdata->ndfqtoval = ndfqtoval;
            pdata->ndfqval = ndfqval;
            pdata->operation = 3;
            thrAddJob( wf, 0, pdata, smf1_qual_map, 0, NULL, status );
          }
          thrWait( wf, status );

          /* we have uncompressed */
          if (lfamily == SMF__QFAM_TCOMP) lfamily = SMF__QFAM_TSERIES;
        }
      }
    }

    /* Free quality */
    irqRlse( &qlocs, status );

    /* no longer need the mapped data */
    ndfUnmap( indf, "QUALITY", status );
  }

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

  /* Free other resources. */
  job_data = astFree( job_data );

  if (family) *family = lfamily;
  return retval;
}
Example #4
0
void  smf_fillgaps( ThrWorkForce *wf, smfData *data,
                    smf_qual_t mask, int *status ) {

/* Local Variables */
  const gsl_rng_type *type;     /* GSL random number generator type */
  dim_t bpt;                    /* Number of bolos per thread */
  dim_t i;                      /* Bolometer index */
  dim_t nbolo;                  /* Number of bolos */
  dim_t ntslice;                /* Number of time slices */
  double *dat=NULL;             /* Pointer to bolo data */
  int fillpad;                  /* Fill PAD samples? */
  size_t bstride;               /* bolo stride */
  size_t pend;                  /* Last non-PAD sample */
  size_t pstart;                /* First non-PAD sample */
  size_t tstride;               /* time slice stride */
  smfFillGapsData *job_data;    /* Structures holding data for worker threads */
  smfFillGapsData *pdata;       /* Pointer to data for next worker thread */
  smf_qual_t *qua=NULL;         /* Pointer to quality array */

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

/* Check we have double precision data floating point data. */
  if (!smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status )) return;

/* Pointers to data and quality */
  dat = data->pntr[0];
  qua = smf_select_qualpntr( data, NULL, status );

  if( !qua ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": No valid QUALITY array was provided", status );
    return;
  }

  if( !dat ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": smfData does not contain a DATA component",status);
    return;
  }

 /* obtain data dimensions */
  smf_get_dims( data,  NULL, NULL, &nbolo, &ntslice, NULL, &bstride, &tstride,
                status );

  /* Determine how many bolometers to process in each thread, and create
     the structures used to pass data to the threads. */
  if( wf ) {
     bpt = nbolo/wf->nworker;
     if( wf->nworker*bpt < nbolo ) bpt++;
     job_data = astMalloc( sizeof( smfFillGapsData )*wf->nworker );
  } else {
     bpt = nbolo;
     job_data = astMalloc( sizeof( smfFillGapsData ) );
  }

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

  /* Report an error if it is too short. */
  if( pend - pstart <= 2*BOX && *status == SAI__OK ) {
    *status = SAI__ERROR;
    errRepf( "", FUNC_NAME ": length of data (%d samples) is too small "
             "to fill gaps. Must have at least %d samples per bolometer.",
             status, (int) ( pend - pstart ), 2*BOX + 1 );
  }

  /* If the supplied "mask" value includes SMF__Q_PAD, then we will be
  replacing the zero-padded region at the start and end of each time series
  with artificial noisey data that connects the first and last data values
  smoothly. Remove SMF__Q_PAD from the mask. */
  if( mask & SMF__Q_PAD ) {
     mask &= ~SMF__Q_PAD;
     fillpad = 1;
  } else {
     fillpad = 0;
  }

  /* Get the default GSL randim number generator type. A separate random
     number generator is used for each worker thread so that the gap filling
     process does not depend on the the order in which threads are
     executed. */
  type = gsl_rng_default;

  /* Begin a job context. */
  thrBeginJobContext( wf, status );

  /* Loop over bolometer in groups of "bpt". */
  pdata = job_data;
  for( i = 0; i < nbolo; i += bpt, pdata++ ) {

    /* Store information for this group in the  next smfFillGapsData
       structure. */
    pdata->ntslice = ntslice;
    pdata->dat = dat;
    pdata->r = gsl_rng_alloc( type );
    pdata->b1 = i;
    pdata->b2 = i + bpt - 1;
    pdata->pend = pend;
    pdata->fillpad = fillpad;
    pdata->pstart = pstart;
    if( pdata->b2 >= nbolo ) pdata->b2 = nbolo - 1;
    pdata->bstride = bstride;
    pdata->tstride = tstride;
    pdata->qua = qua;
    pdata->mask = mask;

    /* Submit a job to the workforce to process this group of bolometers. */
    (void) thrAddJob( wf, 0, pdata, smfFillGapsParallel, 0, NULL, status );
  }

  /* Wait until all jobs in the current job context have completed, and
     then end the job context. */
  thrWait( wf, status );
  thrEndJobContext( wf, status );

  /* Free resources. */
  if( job_data ) {
    pdata = job_data;
    for( i = 0; i < nbolo; i += bpt, pdata++ ) {
      if( pdata->r ) gsl_rng_free( pdata->r );
    }
    job_data = astFree( job_data );
  }
}
Example #5
0
void smf_fit_poly( ThrWorkForce *wf, smfData *data, const size_t order,
                   int remove, double *poly, int *status) {

  /* Local variables */
  size_t bstride;             /* bolo strides */
  int i;                      /* Loop counter */
  smfFitPolyData *job_data=NULL;/* Array of job data for each thread */
  dim_t nbolo=0;              /* Number of bolometers */
  int njobs=0;                /* Number of jobs to be processed */
  dim_t ntslice = 0;          /* Number of time slices */
  int nw;                     /* Number of worker threads */
  smfFitPolyData *pdata=NULL; /* Pointer to job data */
  const smf_qual_t *qual;     /* pointer to the quality array */
  size_t step;                /* step size for dividing up work */
  size_t tstride;             /* time strides */

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

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

  /* Should check data type for double */
  if (!smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status)) return;

  if ( smf_history_check( data, FUNC_NAME, status) ) {
    msgSetc("F", FUNC_NAME);
    msgOutif(MSG__VERB," ",
             "^F has already been run on these data, returning to caller",
             status);
    return;
  }

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

  /* Return with error if there is no QUALITY component */
  qual = smf_select_cqualpntr( data, NULL, status );

  if( !qual && (*status == SAI__OK) ) {
    *status = SAI__ERROR;
    errRep( FUNC_NAME, "Data doesn't have a QUALITY component.", status );
    return;
  }

  /* Return with error if order is greater than the number of data
     points */
  if ( order >= ntslice ) {
    if ( *status == SAI__OK) {
      msgSeti("O",order);
      msgSeti("NF",ntslice);
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "Requested polynomial order, ^O, greater than or "
              "equal to the number of points, ^NF. Unable to fit polynomial.",
              status );
    }
    return;
  }

  /* Set up the job data */

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

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

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

     pdata->b1 = i*step;
     pdata->b2 = (i+1)*step-1;

     /* if b1 is greater than the number of bolometers, we've run out of jobs */
     if( pdata->b1 >= nbolo ) {
       break;
     }

     /* increase the jobs counter */
     njobs++;

     /* Ensure that the last thread picks up any left-over bolometers */
     if( (i==(nw-1)) && (pdata->b1<(nbolo-1)) ) {
       pdata->b2=nbolo-1;
     }

     pdata->ijob = -1;   /* Flag job as ready to start */
     pdata->bstride = bstride;
     pdata->indata = data->pntr[0];
     pdata->isTordered = data->isTordered;
     pdata->nbolo = nbolo;
     pdata->ntslice = ntslice;
     pdata->order = order;
     pdata->poly = poly;
     pdata->qual = qual;
     pdata->remove = remove;
     pdata->tstride = tstride;
   }

  /* Submit jobs to fit polynomial baselines to block of bolos */
  thrBeginJobContext( wf, status );
  for( i=0; (*status==SAI__OK)&&i<njobs; i++ ) {
    pdata = job_data + i;
    pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata,
                               smfFitPolyPar, 0, NULL, status );
  }

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

  /* Free local resources. */
  job_data = astFree( job_data );

}