예제 #1
0
void smf_flat_malloc( size_t nheat, const smfData * refdata,
                      smfData **powvald, smfData **bolvald, int *status ) {

  size_t rowidx = SC2STORE__ROW_INDEX;
  size_t colidx = SC2STORE__COL_INDEX;
  double * bolval = NULL; /* Data array inside bolrefd */
  double * bolvalvar = NULL; /* Variance inside bolrefd */
  dim_t dims[] = { 1, 1, 1 }; /* Default dimensions */
  smfHead * hdr = NULL;      /* New header */
  int lbnd[] = { 1, 1, 1 };  /* Default pixel lower bounds */
  size_t nelem = 0;      /* Number of elements in first two dimensions of refdims */
  smfHead * oldhdr = NULL;   /* header from refdata */
  void *pntr[] = { NULL, NULL };          /* pointers for smfData */
  double * powval = NULL; /* Data array inside powrefd */

  if (bolvald) *bolvald = NULL;
  if (powvald) *powvald = NULL;

  if ( *status != SAI__OK ) return;

  if ( !bolvald && !powvald) {
    *status = SAI__ERROR;
    errRep( "", "Must provide at least one non-NULL pointer to smf_flat_malloc"
            " (possible programming error)", status );
    return;
  }

  /* Sanity check */
  if ( nheat == 0 ) {
    *status = SAI__ERROR;
    errRep( "", "No flatfield information present for creating new smfData",
            status );
    return;
  }

  if ( !smf_validate_smfData( refdata, 1, 0, status ) ) return;
  oldhdr = refdata->hdr;

  if (powvald) {
    powval = astCalloc( nheat, sizeof(*powval) );
    pntr[0] = powval;
    pntr[1] = NULL;
    dims[0] = nheat;
    *powvald = smf_construct_smfData( NULL, NULL, NULL, NULL, NULL, SMF__DOUBLE,
                                      pntr, NULL, SMF__QFAM_NULL, NULL, 0, 1,
                                      dims, NULL, 1, 0, 0, NULL,
                                      NULL, status );
  }

  if (bolvald) {
    /* Handle data ordering */
    if ( ! refdata->isTordered ) {
      rowidx++;
      colidx++;
    }

    nelem = refdata->dims[rowidx] * refdata->dims[colidx];
    bolval = astCalloc( nheat * nelem, sizeof(*bolval) );
    bolvalvar = astCalloc( nheat * nelem, sizeof(*bolvalvar) );
    pntr[0] = bolval;
    pntr[1] = bolvalvar;
    dims[SC2STORE__ROW_INDEX] = refdata->dims[rowidx];
    dims[SC2STORE__COL_INDEX] = refdata->dims[colidx];
    dims[2] = nheat;
    lbnd[SC2STORE__ROW_INDEX] = refdata->lbnd[rowidx];
    lbnd[SC2STORE__COL_INDEX] = refdata->lbnd[colidx];
    lbnd[2] = 1;

    /* Create a header to attach to the bolometer data. We only want the basic 2-d
       information to propagate. */
    hdr = smf_construct_smfHead( NULL, oldhdr->instrument, NULL, NULL,
                                 astCopy( oldhdr->fitshdr ), NULL, 0,
                                 oldhdr->instap, nheat, oldhdr->steptime,
                                 oldhdr->scanvel, oldhdr->obsmode,
                                 oldhdr->swmode, oldhdr->obstype,
                                 oldhdr->seqtype, oldhdr->inbeam, 0, NULL, NULL,
                                 NULL, NULL, 0, NULL,
                                 "Flatfield measurement", "Response",
                                 oldhdr->units, oldhdr->telpos,
                                 NULL, oldhdr->obsidss, status );

    *bolvald = smf_construct_smfData( NULL, NULL, hdr, NULL, NULL, SMF__DOUBLE,
                                      pntr, NULL, SMF__QFAM_TSERIES, NULL, 0, 1,
                                      dims, lbnd, 3, 0, 0, NULL, NULL, status );
  }

  return;
}
예제 #2
0
int smf_fix_data ( msglev_t msglev, smfData * data, int * status ) {

  int have_fixed = 0;        /* Did we fix anything? */
  smfHead *hdr = NULL;       /* Data header struct */
  size_t i;                  /* Loop counter */
  size_t j;                  /* Loop counter */
  size_t k;                  /* Loop counter */
  size_t l;                  /* Loop counter */
  sc2ast_subarray_t subnum;  /* subarray number */
  int was_fixed = 0;         /* Were these data fixed before? */

  if (*status != SAI__OK) return have_fixed;

  /* Validate arguments - need smfData with smfHead including FITS
     and state */
  smf_validate_smfData( data, 1, 0, status );
  if (*status != SAI__OK) return have_fixed;

  hdr = data->hdr;
  smf_validate_smfHead( hdr, 1, 1, status );
  if (*status != SAI__OK) return have_fixed;

  /* Only works on SCUBA-2 time-series data */
  if( (hdr->instrument != INST__SCUBA2) ||
      (data->ndims != 3) ) {
    return have_fixed;
  }

  /* Need to at least have a DATA component. It might be a good idea
     to check if there is a file associated with the data, and check
     to see whether the caller mapped the DATA, VARIANCE, QUALITY. If
     they only mapped a subset of those, we could generate a warning that
     this routine may be introducing an inconsistency */
  if( !data->pntr[0] ) {
    return have_fixed;
  }

  /* Check to see if a FIXDATA FITS keyword exists -- if so, smf_fix_data
     has already been run on the data and we return. */
  smf_getfitsi( hdr, SMFFIXDATA, &was_fixed, status );
  if( *status == SMF__NOKWRD ) {
    errAnnul( status );
  } else {
    return have_fixed;
  }

  /* Fix the May/June 2011 s4a row readout order error. Check the
     subarray first, then get the MJD for the start of the observation
     to decide if we need to proceed. */

  smf_find_subarray( hdr, NULL, 0, &subnum, status );
  if( (*status == SAI__OK) && (subnum == S4A) ) {
    double dateendfix;       /* UTC MJD end date when fix needed */
    double dateobs;          /* UTC MJD observation start */
    double datestartfix;     /* UTS MJD start date when fix needed */
    AstTimeFrame *tf = NULL; /* time frame for date conversion */

    /* Get the MJD for start of the observation */
    smf_find_dateobs( hdr, &dateobs, NULL, status );

    /* Get the MJD for the first and last dates bracketing the period
       during which the row order fix needs to be done */

    tf = astTimeFrame( " " );
    astSet( tf, "TimeScale=UTC" );

    /* From Mike Macintosh Thu, 7 Jul 2011 15:07:51 +0000:

       "I did a scan of the engineering MCE status files and it looks
       the 'missing' row on s4a originated between 09:30 and 10:30 HST
       on 26 May 2011. I haven't checked in detail whether the
       'missing' row was consistently missing after that date but the
       assumption is that it was."
    */

    astSet( tf, "TimeOrigin=%s", "2011-05-26T19:00:00" );
    datestartfix = astGetD( tf, "TimeOrigin" );

    /* From Dan Bintley Wed, 06 Jul 2011 00:23:18 -1000:

       "I have changed the source code in

       /jac_sw/itsroot/scuba2_src/scuba2Da/setup/SG450_M1004D1000/mce_zero.txt"
    */

    astSet( tf, "TimeOrigin=%s", "2011-07-06T10:23:00" );
    dateendfix = astGetD( tf, "TimeOrigin" );

    tf = astAnnul( tf );

    /* Proceed with fix if within date range */
    if( (*status == SAI__OK) && (dateobs >= datestartfix) &&
        (dateobs <= dateendfix) ) {
      size_t targetbolo;
      size_t sourcebolo;
      size_t bstride;
      dim_t ncols;
      dim_t nrows;
      dim_t ntslice;
      size_t tstride;

      msgOutif( msglev, "", INDENT "Reparing row order readout error", status );

      smf_get_dims( data, &nrows, &ncols, NULL, &ntslice, NULL, &bstride,
                    &tstride, status );

      if( (*status==SAI__OK) && (nrows != 40) ) {
        *status = SAI__ERROR;
        errRep( "", FUNC_NAME ": looks like we need to fix the data, but we "
                "don't have 40 rows.", status );
      }

      /* Rows 0--13 are OK, row 14 was not read out
         (FIXDATA_S4A_MISSROW), so we need to move all of rows 14--38
         up to the range 15--39. After doing the shift, overwrite the
         missing row 14 with 0 (or should this be VAL__BAD? in some
         situations?) */

      if( *status==SAI__OK ) {
        /* Row counter */
        for( i=nrows-1; (*status==SAI__OK)&&(i>=(FIXDATA_S4A_MISSROW+1)); i-- ){
          for( j=0; (*status==SAI__OK)&&(j<ncols); j++ ) {
            smf_qual_t *qual = data->qual;

            /* Calculate the bolo index */
            if( SC2STORE__ROW_INDEX ) {
              /* Fastest changing index is column number */
              sourcebolo = (i-1)*ncols + j;
              targetbolo = i*ncols + j;
            } else {
              /* Fastest changing index is row number */
              sourcebolo = (i-1) + j*nrows;
              targetbolo = i + j*nrows;
            }

            /* Loop for DATA / VARIANCE components */
            for( l=0; (*status==SAI__OK)&&(l<2); l++ ) {
              void *buf = data->pntr[l];

              if( buf ) {
                switch( data->dtype ) {
                case SMF__INTEGER:
                  for( k=0; k<ntslice; k++ ) {
                    ((int *)buf)[targetbolo*bstride + k*tstride] =
                      ((int *)buf)[sourcebolo*bstride + k*tstride];
                  }

                  if( i==(FIXDATA_S4A_MISSROW+1) ) {
                    for( k=0; k<ntslice; k++ ) {
                      ((int *)buf)[sourcebolo*bstride + k*tstride] = 0;
                    }
                  }
                  break;
     
                case SMF__USHORT:
                  for( k=0; k<ntslice; k++ ) {
                    ((unsigned short *)buf)[targetbolo*bstride + k*tstride] =
                      ((unsigned short *)buf)[sourcebolo*bstride + k*tstride];
                  }

                  if( i==(FIXDATA_S4A_MISSROW+1) ) {
                    for( k=0; k<ntslice; k++ ) {
                      ((unsigned short *)buf)[sourcebolo*bstride + k*tstride] =
                        0;
                    }
                  }

                  break;
           
                case SMF__DOUBLE:
                  for( k=0; k<ntslice; k++ ) {
                    ((double *)buf)[targetbolo*bstride + k*tstride] =
                      ((double *)buf)[sourcebolo*bstride + k*tstride];
                  }

                  if( i==(FIXDATA_S4A_MISSROW+1) ) {
                    for( k=0; k<ntslice; k++ ) {
                      ((double *)buf)[sourcebolo*bstride + k*tstride] =
                        0;
                    }
                  }

                  break;

                default:
                  *status = SAI__ERROR;
                  errRepf( "", FUNC_NAME
                           ": Don't know how to handle %s type.", status,
                           smf_dtype_str(data->dtype,status) );
                }
              }
            }

            /* Now do quality: Just set SMF__Q_BADDA for the dead
               row. Not sure if I should do something with sidecar
               quality as well? */
            if( qual ) {
              for( k=0; k<ntslice; k++ ) {
                qual[targetbolo*bstride + k*tstride] =
                  qual[sourcebolo*bstride + k*tstride];
              }
              
              if( i==(FIXDATA_S4A_MISSROW+1) ) {
                for( k=0; k<ntslice; k++ ) {
                  qual[sourcebolo*bstride + k*tstride] = SMF__Q_BADDA;
                }
              }
            }



          }
        }
      }

      /* If we get here and status is OK, set return value */
      if( *status == SAI__OK ) {
        have_fixed |= SMF__FIXED_ROWORDER;
      }
    }
  }

  /* Set FITS header so that we know smf_fix_data was run */
  smf_fits_updateL( hdr, SMFFIXDATA, have_fixed,
                    (have_fixed ? "Data have been fixed" : "Data do not require fixing"),
                    status );

  return have_fixed;
}
예제 #3
0
int smf_fix_metadata_scuba2 ( msglev_t msglev, smfData * data, int have_fixed, int *ncards, int * status ) {

  AstFitsChan * fits = NULL; /* FITS header (FitsChan) */
  struct FitsHeaderStruct fitsvals; /* Quick access Fits header struct */
  smfHead *hdr = NULL;       /* Data header struct */
  AstKeyMap * obsmap = NULL; /* Info from all observations */
  AstKeyMap * objmap = NULL; /* All the object names used */

  if (*status != SAI__OK) return have_fixed;

  /* Validate arguments - need smfFile and smfHead */
  smf_validate_smfData( data, 1, 1, status );
  if (*status != SAI__OK) return have_fixed;

  hdr = data->hdr;
  smf_validate_smfHead( hdr, 1, 1, status );
  if (*status != SAI__OK) return have_fixed;

  fits = hdr->fitshdr;

  if (hdr->instrument != INST__SCUBA2) {
    if (*status != SAI__OK) {
      *status = SAI__ERROR;
      errRep("", " Attempting to fix metadata using SCUBA-2 algorithms but this is not SCUBA-2 data",
             status );
    }
    return have_fixed;
  }

  /* Update units string to something that is FITS standard compliant
     - we used "DAC units" for a while but in FITS land this becomes
     "decacoulomb * units" */
  if ( strncmp( hdr->units, "DAC", 3) == 0 ) {
    one_strlcpy( hdr->units, "adu", SMF__CHARLABEL, status );
  }

  /* Clock jitter and readout efficiencies mean we need to recalculate STEPTIME from the data.
     This is possible because we know that we have a continuous sequence in each file (unlike
     ACSIS). */
  if (hdr->allState) {
    /* it will be odd if it is not there */
    size_t nframes = hdr->nframes;

    size_t istart = 0;
    double start_time = (hdr->allState)[istart].rts_end;
    while( start_time == VAL__BADD && ++istart < nframes ) {
      start_time = (hdr->allState)[istart].rts_end;
    }

    size_t iend = nframes - 1;
    double end_time = (hdr->allState)[iend].rts_end;
    while( end_time == VAL__BADD && iend-- > 0 ) {
      end_time = (hdr->allState)[iend].rts_end;
    }

    double steptime = VAL__BADD;
    double newstep;

    smf_getfitsd( hdr, "STEPTIME", &steptime, status );
    newstep = steptime;

    /* it is possible for a file to contain only one step since
       the DA just dumps every N-steps. We can not recalculate the
       step time in that case. */
    nframes = iend - istart + 1;
    if (nframes > 1) {

      /* duration of file in days */
      newstep = end_time - start_time;

      /* convert to seconds */
      newstep *= SPD;

      /* Convert to step time */
      newstep /= (nframes - 1);
    } else if( nframes > 0 ) {
      /* work it out from RTS_END and TCS_TAI */
      JCMTState * onlystate = &((hdr->allState)[istart]);
      if ( onlystate->tcs_tai != VAL__BADD &&
           onlystate->tcs_tai != onlystate->rts_end) {
        /* TCS_TAI is in the middle of the step */
        newstep = 2.0 * ( onlystate->rts_end - onlystate->tcs_tai ) * SPD;
      }
    } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      if( data->file ) {
         smf_smfFile_msg( data->file, "N", 1, "<unknown>" );
         errRep("", "No valid RTS_END values found in NDF '^N'.", status );
      } else {
         errRep("", "No valid RTS_END values found.", status );
      }
    }

    if (steptime != newstep) {
      msgOutiff( msglev, "", INDENT "Recalculated step time as %g sec from JCMTSTATE (was %g sec)",
                 status, newstep, steptime);
      smf_fits_updateD( hdr, "STEPTIME", newstep, NULL, status );
      have_fixed |= SMF__FIXED_FITSHDR;
    }
  }


  /* Read some FITS headers, intialising the struct first */
  fitsvals.utdate = VAL__BADI;
  *(fitsvals.instrume) = '\0';
  smf_getfitsi( hdr, "UTDATE", &(fitsvals.utdate), status );
  smf_getfitss( hdr, "INSTRUME", fitsvals.instrume, sizeof(fitsvals.instrume), status );

  /* Print out summary of this observation - this may get repetitive if multiple files come
     from the same observation in one invocation but it seems better to describe each fix up
     separately and in context. */
  obsmap = astKeyMap( " " );
  objmap = astKeyMap( " " );
  smf_obsmap_fill( data, obsmap, objmap, status );
  smf_obsmap_report( msglev, obsmap, objmap, status );
  obsmap = astAnnul( obsmap );
  objmap = astAnnul( objmap );

  /* First we need to look for a BACKEND header which we do not write to the raw
     data files but CADC would like to see equal to INSTRUME */
  if (!astTestFits( fits, "BACKEND", NULL ) ) {
    have_fixed |= SMF__FIXED_FITSHDR;
    smf_fits_updateS( hdr, "BACKEND", fitsvals.instrume, "Name of the backend", status );
    msgOutif( msglev, "",  INDENT "Setting backend for SCUBA-2 observation.", status);
  }

  /* BASETEMP was reading MUXTEMP for pre-20091101 data */
  if ( fitsvals.utdate < 20091101 ) {
    double muxtemp = 0.0;
    have_fixed |= SMF__FIXED_FITSHDR;
    smf_getfitsd( hdr, "BASETEMP", &muxtemp, status );
    smf_fits_updateU( hdr, "BASETEMP", "[K] Base temperature", status );
    smf_fits_updateD( hdr, "MUXTEMP", muxtemp, "[K] Mux temperature", status );
    msgOutif( msglev, "", INDENT "Mux temperature is being read from BASETEMP header.", status );
  }

  /* Sometime before 20091119 the SHUTTER keyword was written as a string
     OPEN or CLOSED. Rewrite those as numbers */
  if (fitsvals.utdate < 20091119) {
    double shutval = 0.0;
    /* Try to read as a double. */
    smf_fits_getD( hdr, "SHUTTER", &shutval, status );

    /* Old data was a string. Convert to a double */
    if (*status == AST__FTCNV) {
      char shutter[100];
      errAnnul( status );
      smf_fits_getS( hdr, "SHUTTER", shutter, sizeof(shutter), status);
      if (strcmp(shutter, "CLOSED") == 0) {
        shutval = 0.0;
      } else {
        shutval = 1.0;
      }
      /* update the value */
      have_fixed |= SMF__FIXED_FITSHDR;
      smf_fits_updateD( hdr, "SHUTTER", shutval, "shutter position 0-Closed 1-Open", status );
      msgOutif( msglev, "", INDENT "Forcing SHUTTER header to be numeric", status );
    }
  }

  /* Engineering data with just SCUBA2 and no RTS left the RTS_NUM field
     filled with zeroes. Just assume that a zero in RTS_NUM is always
     indicative of a private sequence. */
  if (fitsvals.utdate < 20110401) {
    size_t nframes = hdr->nframes;
    JCMTState * curstate = &((hdr->allState)[0]);
    JCMTState * endstate = &((hdr->allState)[nframes-1]);
    if (curstate->rts_num == 0 && endstate->rts_num == 0) {
      /* have to set the values from the SEQSTART and SEQEND headers
         since those were set correctly (although any value would
         do of course apart from the sanity check in smf_find_science. */
      size_t i;
      int seqnum = 1;
      smf_fits_getI( hdr, "SEQSTART", &seqnum, status );
      for ( i=0; i<nframes; i++) {
        curstate = &((hdr->allState)[i]);
        curstate->rts_num = seqnum;
        seqnum++;
      }
      have_fixed |= SMF__FIXED_JCMTSTATE;
      msgOutif( msglev, "", INDENT "Private RTS sequence. Fixing RTS_NUM.", status );
    }
  }

  /* work out if this is a fast flat observation taken before May 2010 */
  if (fitsvals.utdate > 20100218 && fitsvals.utdate < 20100501) {
    char buff[100];
    /* need to know whether this is a FASTFLAT */
    smf_getfitss( hdr, "SEQ_TYPE", buff, sizeof(buff), status );

    if (strcmp( buff, "FASTFLAT" ) == 0 ) {

      /* Fast flats had incorrect SHUTTER settings for one night */
      if (fitsvals.utdate == 20100223) {
        have_fixed |= SMF__FIXED_FITSHDR;
        smf_fits_updateD( hdr, "SHUTTER", 1.0, "shutter position 0-Closed 1-Open", status );
        msgOutif( msglev, "", INDENT "Shutter was open for fast flatfield ramp. Correcting.", status );
      }

      /* Need to fix up SC2_HEAT ramps */
      /* the problem is that the data were assumed to be taken with 3 measurements
         in each heater setting. What actually happened was that the first 5 were
         done at the reference setting and then the data were grouped in threes
         finishing with a single value at the reference setting again.

         For example the heater values and the actual values look something like

           Stored    1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
           Actual    0 0 0 0 0 2 2 2 3 3 3 4 4 4 5

         So we can correct for this by starting at the end and copying in the value
         two slots further down until we get to position #4. Then replacing that with
         the PIXHEAT number.
      */

      {
        size_t i;
        int pixheat = 0;
        size_t nframes = hdr->nframes;
        smf_getfitsi( hdr, "PIXHEAT", &pixheat, status );

        /* shift everything up by 2 */
        for (i=nframes-1; i > 4; i--) {
          JCMTState * curstate = &((hdr->allState)[i]);
          JCMTState * prevstate = &((hdr->allState)[i-2]);
          curstate->sc2_heat = prevstate->sc2_heat;
        }

        /* fill in the first 5 slots with the same value */
        for (i=0; i<5; i++) {
          JCMTState * curstate = &((hdr->allState)[i]);
          curstate->sc2_heat = pixheat;
        }
        have_fixed |= SMF__FIXED_JCMTSTATE;
      }
    }
  }

  /* We always recalculate the WVM start and end tau values so that the header
     reflects something approximating the value that was actually used in the
     extinction correction.

     Note that smf_calc_smoothedwvm can do a better job because it has multiple
     subarrays to get all the values from. We just have to try with what we
     have from a single subarray. We do step into the time series until we
     find something good.

     The header values should mostly agree with the recalculated values if the
     WVM code at the time matches the code in SMURF for that date. This has not
     been true in cases where we have retrospectively realised that there has been
     a calibration error in the WVM. So that we do not have to keep track of those
     times explicitly we currently recalculate every time. If this recalculation
     becomes a problem (smf_calc_wvm has a cache now to minimize this) it should
     be possible to disable this recalculation if the file is less than, say,
     30 minutes old to indicate we are running in near realtime.

     As a special case we do not recalculate the headers for FOCUS observations
     as the WVM reading is somewhat irrelevant and simply slows things down.

  */

  if( *status == SAI__OK ){

    /* Have not parsed header yet to extract type so do it explicitly here */
    char obstype[100];
    smf_getfitss( hdr, "OBS_TYPE", obstype, sizeof(obstype), status );

    if (strcasecmp( obstype, "focus") != 0) {

      size_t i;
      size_t nframes = hdr->nframes;
      double starttau = VAL__BADD;
      double starttime = VAL__BADD;
      double endtau = VAL__BADD;
      double endtime = VAL__BADD;

      /* Create a TimeFrame that can be used to format MJD values into ISO
         date-time strings, including a "T" separator between time and date. */
      AstTimeFrame *tf = astTimeFrame( "Format=iso.0T" );

      for (i=0; i < nframes && *status == SAI__OK; i++) {
        smf__calc_wvm_index( hdr, "AMSTART", i, &starttau, &starttime, status );
        if (starttau != VAL__BADD) break;
        if (*status == SAI__ERROR) errAnnul( status );
      }

      /* if we did not get a start tau we are not going to get an end tau */
      if (starttau != VAL__BADD) {
        for (i=0; i < nframes && *status == SAI__OK; i++) {
          smf__calc_wvm_index( hdr, "AMEND", nframes - 1 - i, &endtau, &endtime, status );
          if (endtau != VAL__BADD) break;
          if (*status == SAI__ERROR) errAnnul( status );
        }
      }

      /* If we could not find any WVM readings then we have a bit of a problem.
         Do we clear the FITS headers or do we leave them untouched? Leave them
         alone for now. */
      if (starttau != VAL__BADD && starttime != VAL__BADD) {
        smf_fits_updateD( hdr, "WVMTAUST", starttau, "186GHz Tau from JCMT WVM at start", status );

        /* Convert starttime MJD to ISO format and update the value in the
           FITS header. */
        smf_fits_updateS( hdr, "WVMDATST", astFormat( tf, 1, starttime ),
                          "Time of WVMTAUST", status );
        have_fixed |= SMF__FIXED_FITSHDR;
      }

      if (endtau != VAL__BADD && endtime != VAL__BADD) {
        smf_fits_updateD( hdr, "WVMTAUEN", endtau, "186GHz Tau from JCMT WVM at end", status );

        /* Convert endtime MJD to ISO format and update the value in the
           FITS header. */
        smf_fits_updateS( hdr, "WVMDATEN", astFormat( tf, 1, endtime ),
                          "Time of WVMTAUEN", status );
        have_fixed |= SMF__FIXED_FITSHDR;
      }

      /* Free the TimeFrame. */
      tf = astAnnul( tf );

    }
  }


  /* SEQ_TYPE header turned up in 20091125. Before that date the SEQ_TYPE only
     had two values. If the shutter was open then SEQ_TYPE is just OBS_TYPE. In the
     dark only a FLATFIELD sometimes finished with a noise but in that case CALCFLAT
     doesn't care so we just call it a flatfield sequence anyhow. We could look at
     the OBSEND flag but I'm not sure it makes a difference. */
  if ( fitsvals.utdate < 20091125 ) {
    char obstype[100];
    char seqtype[100];
    double shutval = 0.0;
    /* need to know what type of observation this is */
    smf_getfitss( hdr, "OBS_TYPE", obstype, sizeof(obstype), status );
    /* and the shutter status */
    smf_fits_getD( hdr, "SHUTTER", &shutval, status );

    if (shutval == 0.0 && strcasecmp( obstype, "flatfield" ) != 0 ) {
      /* flatfield was the only non-noise observation in the dark */
      one_strlcpy( seqtype, "NOISE", sizeof(seqtype), status );
      msgOutif( msglev, "", INDENT "Setting sequence type to NOISE", status );
    } else {
      /* Shutter was open so SEQ_TYPE is just OBS_TYPE */
      one_strlcpy( seqtype, obstype, sizeof(seqtype), status );
      msgOutif( msglev, "",  INDENT "Setting sequence type to obs type", status);
    }
    smf_fits_updateS( hdr, "SEQ_TYPE", seqtype, "Type of sequence", status );
    have_fixed |= SMF__FIXED_FITSHDR;
  }

  /* The telescope goes crazy at the end of observation 56 on 20110530. Null
     the telescope data for subscans 30, 31 and 32 */
  if (fitsvals.utdate == 20110530) {
    char obsid[81];
    smf_getobsidss( hdr->fitshdr, obsid, sizeof(obsid), NULL, 0, status);

    if (strcmp(obsid, "scuba2_00056_20110530T135530") == 0 ) {
      int subscan;
      smf_getfitsi( hdr, "NSUBSCAN", &subscan, status );
      if (subscan == 30 || subscan == 31 || subscan == 32) {
        size_t nframes = hdr->nframes;
        JCMTState * curstate;
        size_t i;
        for ( i=0; i<nframes; i++ ) {
          curstate = &((hdr->allState)[i]);
          curstate->jos_drcontrol |= DRCNTRL__PTCS_BIT;
        }
        msgOutif( msglev, "", INDENT "Blanking telescope data due to extreme excursion", status );
        have_fixed |= SMF__FIXED_JCMTSTATE;
      }
    }
  }

  /* The second half of observation 14 on 20111215 (scuba2_00014_20111215T061536)
     has a elevation pointing shift */
  if (fitsvals.utdate == 20111215) {
    char obsid[81];
    const char fitskey[] = "FIXPCORR";
    smf_getobsidss( hdr->fitshdr, obsid, sizeof(obsid), NULL, 0, status);

    if (strcmp(obsid, "scuba2_00014_20111215T061536") == 0 ) {
      int seqcount;
      smf_getfitsi( hdr, "SEQCOUNT", &seqcount, status );
      if (seqcount == 5) {
        int have_fixed_pntg = 0;
        smf_fits_getL( hdr, fitskey, &have_fixed_pntg, status );
        if (*status == SMF__NOKWRD) {
          have_fixed = 0;
          errAnnul( status );
        }
        if (!have_fixed_pntg) {
          size_t nframes = hdr->nframes;
          size_t i;
          const double dlon = 0.0;
          const double dlat = -16.83; /* From making maps of each half */
          /* Correct the pointing */
          msgOutif( msglev, "", INDENT "Applying pointing anomaly correction", status );
          for (i=0;i<nframes;i++) {
            JCMTState * curstate = &((hdr->allState)[i]);
            /* This is an AZEL correction */
            smf_add_smu_pcorr( curstate, 1, dlon, dlat, status );
          }
          smf_fits_updateL(hdr, fitskey, 1, "Applied internal pointing correction", status);
          have_fixed |= SMF__FIXED_JCMTSTATE;
        }
      }
    }

  }

  /* For POL-2 data prior to 18-JAN-2013, the POL_CRD header was always
     "FPLANE" in reality, even if the POL_CRD value in JCMTSTATE said
     something else. */
  if ( fitsvals.utdate < 20130118 ) {
    char polcrd[80] = "<unset>";
    smf_getfitss( hdr, "POL_CRD", polcrd, sizeof(polcrd), status );
    if (*status == SMF__NOKWRD) {
       errAnnul( status );
    } else if( !strcmp( polcrd, "TRACKING" ) || !strcmp( polcrd, "AZEL" ) ) {
      msgOutiff( msglev, "",  INDENT "Changing POL_CRD from %s to FPLANE", status, polcrd);
      smf_fits_updateS( hdr, "POL_CRD", "FPLANE",
                        "Coordinate system of polarimeter", status );
      have_fixed |= SMF__FIXED_FITSHDR;
    }
  }


  return have_fixed;
}
예제 #4
0
void smf_choose_darks( const smfArray *darks, const smfData *indata,
                       size_t *dark1, size_t *dark2, int * status ) {
  size_t i;          /* loop counter */
  int refseq;        /* Sequence count of input science data */
  sc2ast_subarray_t refsubnum;     /* Subarray number of science data */

  *dark1 = SMF__BADIDX;
  *dark2 = SMF__BADIDX;

  if (*status  != SAI__OK) return;
  if (!darks) return;
  if (!smf_validate_smfData( indata, 1, 0, status ) ) return;

  /* get reference sequence counter and subarray number */
  smf_find_seqcount( indata->hdr, &refseq, status );
  smf_find_subarray( indata->hdr, NULL, (size_t)0, &refsubnum, status );

  /* Loop through all the darks looking for ones that only differ
     from the reference sequence counter by 1 */
  for (i=0; i< darks->ndat; i++) {
    smfData *thisdark = (darks->sdata)[i];
    sc2ast_subarray_t thissubnum;
    smf_find_subarray( thisdark->hdr, NULL, (size_t)0, &thissubnum, status );

    /* see if we even need to look at the sequence counter */
    if (thissubnum == refsubnum &&
        strcmp( indata->hdr->obsidss, thisdark->hdr->obsidss ) == 0 ) {
      int thisseq;
      int seqdiff;
      smf_find_seqcount( thisdark->hdr, &thisseq, status );
      seqdiff = refseq - thisseq;

      if ( seqdiff == 1 ) {
        /* Valid previous dark */
        *dark1 = i;
      } else if (seqdiff == -1 ) {
        /* Valid next dark */
        *dark2 = i;
      } else if (seqdiff == 0) {
        /* should not be possible */
        if (*status == SAI__OK) {
          *status = SAI__ERROR;
          errRep(" ","Should not be possible for dark and science "
                 "observation to have identical sequence counter.", status );
          return;
        }
      }
    }

    /* finish if we have everything */
    if (*dark1 != SMF__BADIDX && *dark2 != SMF__BADIDX) break;

  }

  if (*dark1 == SMF__BADIDX) {
    msgOutif( MSG__VERB, " ","Unable to find any prior dark", status );
  }
  if (*dark2 == SMF__BADIDX) {
    msgOutif( MSG__VERB, " ","Unable to find any following dark", status );
  }

}
예제 #5
0
void smf_flat_malloc( size_t nheat, const smfData * refdata,
                      smfData **powvald, smfData **bolvald, int *status ) {

  size_t rowidx = SC2STORE__ROW_INDEX;
  size_t colidx = SC2STORE__COL_INDEX;
  double * bolval = NULL; /* Data array inside bolrefd */
  double * bolvalvar = NULL; /* Variance inside bolrefd */
  dim_t dims[] = { 1, 1, 1 }; /* Default dimensions */
  smfHead * hdr = NULL;      /* New header */
  int lbnd[] = { 1, 1, 1 };  /* Default pixel lower bounds */
  size_t nelem = 0;      /* Number of elements in first two dimensions of refdims */
  smfHead * oldhdr = NULL;   /* header from refdata */
  void *pntr[] = { NULL, NULL };          /* pointers for smfData */
  double * powval = NULL; /* Data array inside powrefd */
  const char *dom;        /* Domain of axis 1 */
  AstFrameSet *new_fs;    /* New FrameSet for returned *bolvald */
  AstMapping *map;        /* Mapping from pixel index 3 to heater index */
  AstFrame *frm;          /* Frame describing heater index */
  int ubnd[ 1 ];          /* Upper bound on heater index */

  if (bolvald) *bolvald = NULL;
  if (powvald) *powvald = NULL;

  if ( *status != SAI__OK ) return;

  if ( !bolvald && !powvald) {
    *status = SAI__ERROR;
    errRep( "", "Must provide at least one non-NULL pointer to smf_flat_malloc"
            " (possible programming error)", status );
    return;
  }

  /* Sanity check */
  if ( nheat == 0 ) {
    *status = SAI__ERROR;
    errRep( "", "No flatfield information present for creating new smfData",
            status );
    return;
  }

  if ( !smf_validate_smfData( refdata, 1, 0, status ) ) return;
  oldhdr = refdata->hdr;

  if (powvald) {
    powval = astCalloc( nheat, sizeof(*powval) );
    pntr[0] = powval;
    pntr[1] = NULL;
    dims[0] = nheat;
    *powvald = smf_construct_smfData( NULL, NULL, NULL, NULL, NULL, SMF__DOUBLE,
                                      pntr, NULL, SMF__QFAM_NULL, NULL, 0, 1,
                                      dims, NULL, 1, 0, 0, NULL,
                                      NULL, status );
  }

  if (bolvald) {
    /* Handle data ordering */
    if ( ! refdata->isTordered ) {
      rowidx++;
      colidx++;
    }

    nelem = refdata->dims[rowidx] * refdata->dims[colidx];
    bolval = astCalloc( nheat * nelem, sizeof(*bolval) );
    bolvalvar = astCalloc( nheat * nelem, sizeof(*bolvalvar) );
    pntr[0] = bolval;
    pntr[1] = bolvalvar;
    dims[SC2STORE__ROW_INDEX] = refdata->dims[rowidx];
    dims[SC2STORE__COL_INDEX] = refdata->dims[colidx];
    dims[2] = nheat;
    lbnd[SC2STORE__ROW_INDEX] = refdata->lbnd[rowidx];
    lbnd[SC2STORE__COL_INDEX] = refdata->lbnd[colidx];
    lbnd[2] = 1;

    /* Create a header to attach to the bolometer data. We only want the basic 2-d
       information to propagate. */
    hdr = smf_construct_smfHead( NULL, oldhdr->instrument, NULL, NULL,
                                 astCopy( oldhdr->fitshdr ), NULL, 0,
                                 oldhdr->instap, nheat, oldhdr->steptime,
                                 oldhdr->scanvel, oldhdr->obsmode,
                                 oldhdr->swmode, oldhdr->obstype,
                                 oldhdr->seqtype, oldhdr->inbeam, 0, NULL, NULL,
                                 NULL, NULL, 0, NULL,
                                 "Flatfield measurement", "Response",
                                 oldhdr->units, oldhdr->telpos,
                                 NULL, oldhdr->obsidss, status );

    *bolvald = smf_construct_smfData( NULL, NULL, hdr, NULL, NULL, SMF__DOUBLE,
                                      pntr, NULL, SMF__QFAM_TSERIES, NULL, 0, 1,
                                      dims, lbnd, 3, 0, 0, NULL, NULL, status );

    /* Assign a 3D WCS FRameSet in which the third axis represents heater
       value index (note, not actual heater value, since we do not yet
       know what the heater values are). First split the supplied time-series
       WCS FrameSet to extract a FrameSet in which the current Frame
       contains only the axes within the ame Domain as the first axis
       (this is safe because the first axis is always a spatial axis). */
    if( oldhdr->tswcs ) {
      dom = astGetC( oldhdr->tswcs, "Domain(1)" );
      new_fs = atlFrameSetSplit( oldhdr->tswcs, dom, NULL, NULL, status );

      /* Check this FrameSet is 2D, and if so, add in a third axis describing
         heater value index. */
      if( new_fs && astGetI( new_fs, "Naxes" ) == 2 ) {
         map = (AstMapping *) astUnitMap( 1, " " );
         frm = astFrame( 1, "Domain=HEATER_INDEX" );
         ubnd[ 0 ] = nheat;
         atlAddWcsAxis(  new_fs, map, frm, NULL, ubnd, status );
         map = astAnnul( map );
         frm = astAnnul( frm );

         /* Hand over the FrameSet pointer to the returned smfData. */
         (*bolvald)->hdr->tswcs = new_fs;

      }
    }
  }

  return;
}