void smf_clean_dksquid( smfData *indata, smf_qual_t mask, size_t window, smfData *model,
                        int calcdk, int nofit, int replacebad, int *status ) {

  dim_t b;                /* Bolometer index */
  size_t bstride;         /* Bolometer index stride */
  double corr;            /* Linear correlation coefficient */
  double *corrbuf=NULL;   /* Array of correlation coeffs all bolos this col */
  int needDA=0;           /* Do we need dksquids from the DA? */
  int *dkgood=NULL;       /* Flag for non-constant dark squid */
  double *dksquid=NULL;   /* Buffer for smoothed dark squid */
  double *dkav=NULL;      /* Buffer for average dark squid */
  double firstdk;         /* First value in dksquid signal */
  double gain;            /* Gain parameter from template fit */
  double *gainbuf=NULL;   /* Array of gains for all bolos in this col */
  size_t i;               /* Loop counter */
  size_t jt1;
  size_t jt2;
  size_t jf1;             /* Starting tslice that should be fit */
  size_t jf2;             /* Final tslice that should be fit */
  size_t j;               /* Loop counter */
  size_t k;               /* Loop counter */
  size_t nbad=0;          /* Number of new bad bolos due to bad dark squid */
  dim_t nbolo;            /* Number of bolometers */
  dim_t ncol;             /* Number of columns */
  dim_t ndata;            /* Number of data points */
  size_t nfit;            /* number of samples over good range to fit */
  size_t ngood=0;         /* number of good dark squids */
  dim_t nrow;             /* Number of rows */
  size_t ntot;
  dim_t ntslice;          /* Number of time slices */
  double offset;          /* Offset parameter from template fit */
  double *offsetbuf=NULL; /* Array of offsets for all bolos in this col */
  int pass;               /* two passes over data to get estimate of average */
  smf_qual_t *qua=NULL;/* Pointer to quality array */
  size_t tstride;         /* Time slice index stride */

  if (*status != SAI__OK) return;

  /* Check for NULL smfData pointer */
  if( !indata ) {
    *status = SAI__ERROR;
    errRep( " ", FUNC_NAME
            ": possible programming error, smfData pointer is NULL", status );
    return;
  }

  /* Decide if we need the DA extension or not */
  if( (!model) || (model && calcdk) ) {
    needDA = 1;
    if( !indata->da) {
      /* Check for NULL smfDA */
      *status = SAI__ERROR;
      errRep( " ", FUNC_NAME
              ": possible programming error, no smfDA struct in smfData",
              status);
      return;
    } else if( !indata->da->dksquid) {
      /* Check for NULL dksquid */
      *status = SAI__ERROR;
      errRep( " ", FUNC_NAME
              ": possible programming error, no dksquid array in smfData",
              status);
      return;
    }

    /* Assert the correct data order here */
    smf_dataOrder( indata->da->dksquid, 1, status );
  }

  /* Check for 3-d data and get dimensions */
  smf_get_dims( indata, &nrow, &ncol, &nbolo, &ntslice, &ndata, &bstride,
                &tstride, status );

  /* Identify the range of data that should be fit using SMF__Q_BOUND */
  if( qua ) {
    smf_get_goodrange( qua, ntslice, tstride, SMF__Q_BOUND, &jf1, &jf2,
                       status );
  } else {
    jf1 = 0;
    jf2 = ntslice-1;
  }
  nfit = jf2-jf1+1;

  /* Total total range only using SMF__Q_PAD */
  if( qua ) {
    smf_get_goodrange( qua, ntslice, tstride, SMF__Q_BOUND, &jt1, &jt2,
                       status );
  } else {
    jt1 = 0;
    jt2 = ntslice-1;
  }
  ntot = jt2-jt1+1;

  if( model ) {
    /* Check for valid model dimensions if supplied */
    if( model->dtype != SMF__DOUBLE ) {
      msgSetc("DT", smf_dtype_str(model->dtype, status) );
      *status = SAI__ERROR;
      errRep(" ", FUNC_NAME ": Data type ^DT for model not supported.",
             status );
      return;
    }

    if( (model->ndims != 2) ||
        (model->dims[0] != ntslice+nrow*3) ||
        (model->dims[1] != ncol) ) {
      *status = SAI__ERROR;
      errRep(" ", FUNC_NAME ": model has incorrect dimensions", status );
      return;
    }
  } else {
    /* Otherwise allocate space for local dksquid buffer */
    dksquid = astCalloc( ntslice, sizeof(*dksquid) );
  }

  /* Pointer to quality */
  qua = smf_select_qualpntr( indata, 0, status );

  /* Two passes: in the first we calculate an average dark squid to use as
     a surrogate for columns with dead dark squids. In the second we do the
     actual cleaning etc. */

  dkgood = astCalloc( ncol, sizeof(*dkgood) );
  dkav = astCalloc( ntslice, sizeof(*dkav) );

  for( pass=0; (*status==SAI__OK)&&(pass<2); pass++ ) {

    /* Loop over columns */
    for( i=0; (*status==SAI__OK)&&(i<ncol); i++ ) {

      /* Point dksquid, gainbuf, offsetbuf and corrbuf to the right
         place in model if supplied. */
      if( model ) {
        dksquid = model->pntr[0];
        dksquid += i*(ntslice+nrow*3);
        gainbuf = dksquid + ntslice;
        offsetbuf = gainbuf + nrow;
        corrbuf = offsetbuf + nrow;
      }

      /* First pass is just to copy the dark squid over to the model and replace
         dead dark squids with the average */
      if( pass==0 ) {

        /* Copy dark squids from the DA extension into dksquid */
        if( needDA && calcdk && model ) {
          double *ptr = indata->da->dksquid->pntr[0];
          for( j=0; j<ntslice; j++ ) {
            dksquid[j] = ptr[i+ncol*j];
          }
        }

        /* Check for a good dark squid by seeing if it ever changes */
        firstdk = VAL__BADD;
        for( j=jt1; j<=jt2; j++ ) {
          if(  dksquid[j] != VAL__BADD ) {
            if( firstdk == VAL__BADD ) {
              firstdk = dksquid[j];
            } else if( dksquid[j] != firstdk ) {
              dkgood[i] = 1;
              ngood++;

              /* Add good squid to average dksquid */
              for( k=jt1; k<=jt2; k++ ) {
                dkav[k] += dksquid[k];
              }
              break;
            }
          }
        }
      }

      /* Second pass actually do the fitting / replace with average dksquid if
         dksquid was dead */
      if( pass==1 ) {

        /* Do some dksquid initialization if requested  */
        if( (*status==SAI__OK) && needDA && calcdk && model && dkgood[i] ) {
          /* Smooth the dark squid template */
          smf_boxcar1D( &dksquid[jt1], ntot, window, NULL, 0, status );
        }

        /* Initialize fit coeffs to VAL__BADD */
        if( (*status == SAI__OK) && model ) {
          for( j=0; j<nrow; j++ ) {
            gainbuf[j] = VAL__BADD;
            offsetbuf[j] = VAL__BADD;
            corrbuf[j] = VAL__BADD;
          }
        }

        /* Loop over rows, removing the fitted dksquid template. */
        for( j=0; (!nofit) && (*status==SAI__OK) && (j<nrow); j++ ) {

          /* Calculate bolometer index from row/col counters */
          if( SC2STORE__COL_INDEX ) {
            b = i*nrow + j;
          } else {
            b = i + j*ncol;
          }

          /* If dark squid is bad, flag entire bolo as bad if it isn't already */
          if( !dkgood[i] && qua && !(qua[b*bstride]&SMF__Q_BADB) ) {
            nbad++;
            for( k=0; k<ntslice; k++ ) {
              qua[b*bstride+k*tstride] |= SMF__Q_BADB;
            }
          }

          /* Try to fit if we think we have a good dark squid and bolo, and only
             the goodrange of data (excluding padding etc.) */
          if((!qua && dkgood[i]) ||
             (qua && dkgood[i] && !(qua[b*bstride]&SMF__Q_BADB))) {
            double *d_d;
            int *d_i;

            switch( indata->dtype ) {
            case SMF__DOUBLE:
              d_d = (double *) indata->pntr[0];
              smf_templateFit1D( &d_d[b*bstride+jf1*tstride],
                                 &qua[b*bstride+jf1*tstride], NULL, NULL,
                                 mask, mask, nfit, tstride, &dksquid[jf1], 1,
                                 1, &gain, &offset, &corr, status );
              break;

            case SMF__INTEGER:
              d_i = (int *) indata->pntr[0];
              smf_templateFit1I( &d_i[b*bstride+jf1*tstride],
                                 &qua[b*bstride+jf1*tstride], NULL, NULL, mask,
                                 mask, nfit, tstride, &dksquid[jf1], 1, 1,
                                 &gain, &offset, &corr, status );
              break;

            default:
              msgSetc( "DT", smf_dtype_string( indata, status ));
              *status = SAI__ERROR;
              errRep( " ", FUNC_NAME
                      ": Unsupported data type for dksquid cleaning (^DT)",
                      status );
            }

            if( *status == SMF__INSMP || *status == SMF__DIVBZ ) {
              int wasinsmp = (*status == SMF__INSMP ? 1 : 0 );
              /* Annul SMF__INSMP as it was probably due to a bad bolometer */
              errAnnul( status );
              msgOutiff( MSG__DEBUG, "", FUNC_NAME
                         ": ROW,COL (%zu,%zu) %s", status, j, i,
                         (wasinsmp ? "insufficient good samples" : "division by zero" ));

              /* Flag entire bolo as bad if it isn't already */
              if( qua && !(qua[b*bstride]&SMF__Q_BADB) ) {
                for( k=0; k<ntslice; k++ ) {
                  qua[b*bstride+k*tstride] |= SMF__Q_BADB;
                }
              }
            } else {
              /* Store gain and offset in model */
              if( model ) {
                gainbuf[j] = gain;
                offsetbuf[j] = offset;
                corrbuf[j] = corr;
              }

              if( msgFlevok( MSG__DEBUG1, status ) ) {
                msgSeti( "COL", i );
                msgSeti( "ROW", j );
                msgSetd( "GAI", gain );
                msgSetd( "OFF", offset );
                msgSetd( "CORR", corr );
                msgOutif( MSG__DEBUG1, "", FUNC_NAME
                          ": ROW,COL (^ROW,^COL) GAIN,OFFSET,CORR "
                          "(^GAI,^OFF,^CORR)", status );
              }
            }
          }
        }
      }
    }

    /* Re-normalize the average dark-squid here at the end of pass 0 */
    if( (pass==0) && (ngood) && (*status==SAI__OK) ) {
      for( j=jt1; j<=jt2; j++ ) {
        dkav[j] /= ngood;
      }
    }

    /* Replace bad bolos in model with the average? */
    if( replacebad && calcdk && needDA && model && (*status==SAI__OK) ) {
      for( i=0; i<ncol; i++ ) {
        dksquid = model->pntr[0];
        dksquid += i*(ntslice+nrow*3);

        if( !dkgood[i] ) {
          memcpy( dksquid, dkav, sizeof(*dksquid)*ntslice );
          dkgood[i] = 1;
        }
      }
    }
  }

  /* Report number of new bad bolos that were flagged */
  if( !replacebad && nbad ) {
    msgOutiff( MSG__VERB, "", FUNC_NAME
               ": %zu new bolos flagged bad due to dead DKS", status, nbad );
  }

  /* Free dksquid only if it was a local buffer */
  if( !model && dksquid ) dksquid = astFree( dksquid );

  dkgood = astFree( dkgood );
  dkav = astFree( dkav );

}
Exemple #2
0
void smf_update_quality( ThrWorkForce *wf, smfData *data, int syncbad,
			 const int *badmask, smf_qual_t addqual, double badfrac,
			 int *status ) {

  dim_t nbolo;                  /* Number of bolometers */
  dim_t ndata;                  /* Number of data points */
  dim_t ntslice;                /* Number of time slices */
  size_t bstride;               /* bol stride */
  size_t tstride;               /* time slice stride */
  smf_qual_t *qual=NULL;        /* Pointer to the QUALITY array */
  SmfUpdateQualityData *job_data = NULL;
  SmfUpdateQualityData *pdata;
  int nw;
  size_t istep;
  size_t bstep;
  int iw;

  if ( *status != SAI__OK ) return;

  /* Check for QUALITY */
  qual = smf_select_qualpntr( data, NULL, status );
  if (!qual) {
    if (*status == SAI__OK) {
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "smfData does not contain a QUALITY component",
              status);
    }
    return;
  }

  /* Check for DATA */
  if( !data->pntr[0] ) {
    *status = SAI__ERROR;
    errRep( FUNC_NAME, "smfData does not contain a DATA component", status );
    return;
  }

  /* Check for valid badfrac */
  if( (badfrac < 0) || (badfrac > 1) ) {
    msgSeti( "BADFRAC", badfrac );
    errRep(FUNC_NAME,
           "Invalid badfrac: ^BADFRAC. Must be in range (0 -- 1).", status);
  }

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

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

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

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

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

  if( *status == SAI__OK ) {
    /* some pointers to the data array if needed */
    double * ddata = NULL;
    int * idata = NULL;

    /* we will need the data array if we are checking it for bad values
       or looking for bad fraction */
    if (syncbad || badfrac) {
      smf_select_pntr( data->pntr, data->dtype, &ddata, NULL,
                       &idata, NULL, status);
    }

    /* Synchronize SMF__Q_BADDA quality and VAL__BADD in data array */
    if( syncbad ) {
      if (data->dtype == SMF__DOUBLE) {
        for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->operation = 1;
            pdata->ddata = ddata;
            thrAddJob( wf, 0, pdata, smf1_update_quality, 0, NULL, status );
        }
        thrWait( wf, status );

      } else if (data->dtype == SMF__INTEGER) {
        for( iw = 0; iw < nw; iw++ ) {
            pdata = job_data + iw;
            pdata->operation = 2;
            pdata->idata = idata;
            thrAddJob( wf, 0, pdata, smf1_update_quality, 0, NULL, status );
        }
        thrWait( wf, status );

      } else {
        msgSetc( "TYP", smf_dtype_string( data, status ));
        *status = SAI__ERROR;
        errRep( "",FUNC_NAME " data is of unsupported type (^TYP)",
                status);
        return;
      }
    }

    /* Apply badmask if available */
    if( badmask || badfrac ) {

      /* calculate the badfraction threshold in terms of number of bad
         found so that we do not have to continually divide to calculate
         the current fraction */
      dim_t badthresh = ntslice;
      /* special case 0 */
      if (badfrac) badthresh = badfrac * (double)ntslice;

      /* Submit the jobs and wait for them all to finish. */
      for( iw = 0; iw < nw; iw++ ) {
          pdata = job_data + iw;
          pdata->operation = 3;
          pdata->badthresh = badthresh;
          pdata->addqual = addqual;
          pdata->ntslice = ntslice;
          pdata->bstride = bstride;
          pdata->tstride = tstride;
          pdata->badmask = badmask;
          pdata->syncbad = syncbad;
          pdata->idata = idata;
          pdata->ddata = ddata;
          thrAddJob( wf, 0, pdata, smf1_update_quality, 0, NULL, status );
      }
      thrWait( wf, status );
    }
  }

  job_data = astFree( job_data );
}