Exemplo n.º 1
0
static void smf1_rebinmap1( void *job_data_ptr, int *status ) {

    /* Local Variables: */
    SmfRebinMap1Data *pdata;
    dim_t di;                  /* data array index */
    dim_t vi;                  /* variance array index */
    double R;                  /* Another temp variable for variance calc */
    double delta;              /* Offset for weighted mean */
    double temp;               /* Temporary calculation */
    double thisweight;         /* The weight at this point */
    size_t ibolo;              /* Bolometer index */
    size_t ipix;               /* Map pixel index */
    size_t itime;              /* Time slice index */

    /* 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 = (SmfRebinMap1Data *) job_data_ptr;

    /* Map variance from spread of input values - quality checking version.
       ================================================================== */
    if( pdata->operation == 1 ) {

        /* Loop round all bolometers. */
        for( ibolo = 0; ibolo < pdata->nbolo; ibolo++ ) {

            /* Skip bad bolometers. */
            if( !( (pdata->qual)[ ibolo*(pdata->dbstride) ] & SMF__Q_BADB ) ) {

                /* Loop round all time slices being included in the map. */
                for( itime = pdata->t1; itime <= pdata->t2; itime++ ) {

                    /* Get the 1D vector index of the data sample. */
                    di = ibolo*pdata->dbstride + itime*pdata->dtstride;

                    /* Get the corresponding map pixel index. */
                    ipix = pdata->lut[ di ];

                    /* Skip to the next sample if the map pixel is not being processed by the
                       current thread. */
                    if( ipix >= pdata->p1 && ipix <= pdata->p2 ) {

                        /* Get the 1D vector index of the corresponding variane value. */
                        vi = ibolo*pdata->vbstride +
                             ( itime % pdata->vntslice )*pdata->vtstride;

                        /* Get the offset to the start of the buffer in which to store the pixel
                           value. */
                        if( pdata->whichmap ) {
                            if( pdata->whichmap[ itime ] != VAL__BADI ) {
                                ipix += pdata->whichmap[ itime ]*pdata->msize;
                            } else {
                                ipix = SMF__BADDIMT;
                            }
                        }

                        /* Check that the data and variance values are valid */
                        if( !( pdata->qual[ di ] & pdata->mask ) &&
                                ( pdata->var[ vi ] != 0.0 ) &&
                                ( ipix != SMF__BADDIMT ) ) {

                            /* Update things. */
                            pdata->hitsmap[ ipix ]++;
                            thisweight = 1/pdata->var[ vi ];

                            /* Weighted incremental algorithm */
                            temp = pdata->mapweight[ ipix ] + thisweight;
                            delta = pdata->dat[ di ] - pdata->map[ ipix ];
                            R = delta * thisweight / temp;
                            pdata->map[ ipix ] += R;
                            pdata->mapvar[ ipix ] += pdata->mapweight[ ipix ]*delta*R;
                            pdata->mapweight[ ipix ] = temp;

                            /* We don't need this sum anymore, but calculate it for consistency with the
                               interface */
                            pdata->mapweightsq[ ipix ] += thisweight*thisweight;
                        }
                    }
                }
            }
        }


        /* Map variance from spread of input values - VAL__BADD checking version.
           ==================================================================== */
    } else if( pdata->operation == 1 ) {

        for( ibolo = 0; ibolo < pdata->nbolo; ibolo++ ) {
            for( itime = pdata->t1; itime <= pdata->t2; itime++ ) {

                di = ibolo*pdata->dbstride + itime*pdata->dtstride;
                ipix = pdata->lut[ di ];
                if( ipix >= pdata->p1 && ipix <= pdata->p2 ) {
                    vi = ibolo*pdata->vbstride +
                         ( itime % pdata->vntslice )*pdata->vtstride;

                    if( pdata->whichmap ) {
                        if( pdata->whichmap[ itime ] != VAL__BADI ) {
                            ipix += pdata->whichmap[ itime ]*pdata->msize;
                        } else {
                            ipix = SMF__BADDIMT;
                        }
                    }


                    if( pdata->dat[ di ] != VAL__BADD &&
                            pdata->var[ vi ] != VAL__BADD &&
                            pdata->var[ vi ] != 0.0 && ipix != SMF__BADDIMT ) {

                        pdata->hitsmap[ ipix ]++;
                        thisweight = 1/pdata->var[ vi ];

                        temp = pdata->mapweight[ ipix ] + thisweight;
                        delta = pdata->dat[ di ] - pdata->map[ ipix ];
                        R = delta * thisweight / temp;
                        pdata->map[ ipix ] += R;
                        pdata->mapvar[ ipix ] += pdata->mapweight[ ipix ]*delta*R;
                        pdata->mapweight[ ipix ] = temp;

                        pdata->mapweightsq[ ipix ] += thisweight*thisweight;
                    }
                }
            }
        }

        /* Map variance from error propagation - quality checking version.
           ============================================================== */
    } else if( pdata->operation == 3 ) {

        for( ibolo = 0; ibolo < pdata->nbolo; ibolo++ ) {
            if( !( pdata->qual[ ibolo*pdata->dbstride ] & SMF__Q_BADB ) ) {
                for( itime = pdata->t1; itime <= pdata->t2; itime++ ) {
                    di = ibolo*pdata->dbstride + itime*pdata->dtstride;
                    ipix = pdata->lut[ di ];
                    if( ipix >= pdata->p1 && ipix <= pdata->p2 ) {
                        vi = ibolo*pdata->vbstride +
                             ( itime % pdata->vntslice )*pdata->vtstride;
                        if( pdata->whichmap ) {
                            if( pdata->whichmap[ itime ] != VAL__BADI ) {
                                ipix += pdata->whichmap[ itime ]*pdata->msize;
                            } else {
                                ipix = SMF__BADDIMT;
                            }
                        }

                        if( !( pdata->qual[ di ] & pdata->mask ) &&
                                ( pdata->var[ vi ] != 0.0 ) &&
                                ( ipix != SMF__BADDIMT ) ) {

                            thisweight = 1/pdata->var[ vi ];
                            pdata->map[ ipix ] += thisweight*pdata->dat[ di ];
                            pdata->mapweight[ ipix ] += thisweight;
                            pdata->mapweightsq[ ipix ] += thisweight*thisweight;
                            pdata->hitsmap[ ipix ]++;
                        }
                    }
                }
            }
        }

        /* Map variance from error propagation - VAL__BADD checking version.
           ============================================================== */
    } else if( pdata->operation == 4 ) {

        for( ibolo = 0; ibolo < pdata->nbolo; ibolo++ ) {
            for( itime = pdata->t1; itime <= pdata->t2; itime++ ) {
                di = ibolo*pdata->dbstride + itime*pdata->dtstride;
                ipix = pdata->lut[ di ];
                if( ipix >= pdata->p1 && ipix <= pdata->p2 ) {
                    vi = ibolo*pdata->vbstride +
                         ( itime % pdata->vntslice )*pdata->vtstride;
                    if( pdata->whichmap ) {
                        if( pdata->whichmap[ itime ] != VAL__BADI ) {
                            ipix += pdata->whichmap[ itime ]*pdata->msize;
                        } else {
                            ipix = SMF__BADDIMT;
                        }
                    }

                    if( pdata->dat[ di ] != VAL__BADD &&
                            pdata->var[ vi ] != VAL__BADD &&
                            pdata->var[ vi ] != 0.0 && ipix != SMF__BADDIMT  ) {

                        thisweight = 1/pdata->var[ vi ];
                        pdata->map[ ipix ] += thisweight*pdata->dat[ di ];
                        pdata->mapweight[ ipix ] += thisweight;
                        pdata->mapweightsq[ ipix ] += thisweight*thisweight;
                        pdata->hitsmap[ ipix ]++;
                    }
                }
            }
        }

        /* No variances - quality checking version.
           ========================================= */
    } else if( pdata->operation == 5 ) {

        for( ibolo = 0; ibolo < pdata->nbolo; ibolo++ ) {
            if( !( pdata->qual[ ibolo*pdata->dbstride ] & SMF__Q_BADB ) ) {
                for( itime = pdata->t1; itime <= pdata->t2; itime++ ) {
                    di = ibolo*pdata->dbstride + itime*pdata->dtstride;
                    ipix = pdata->lut[ di ];
                    if( ipix >= pdata->p1 && ipix <= pdata->p2 ) {
                        if( pdata->whichmap ) {
                            if( pdata->whichmap[ itime ] != VAL__BADI ) {
                                ipix += pdata->whichmap[ itime ]*pdata->msize;
                            } else {
                                ipix = SMF__BADDIMT;
                            }
                        }

                        if( !( pdata->qual[ di ] & pdata->mask ) &&
                                ( ipix != SMF__BADDIMT ) ) {
                            pdata->hitsmap[ ipix ]++;
                            temp = pdata->mapweight[ ipix ] + 1.0;
                            delta = pdata->dat[ di ] - pdata->map[ ipix ];
                            R = delta / temp;
                            pdata->map[ ipix ] += R;
                            pdata->mapvar[ ipix ] += pdata->mapweight[ ipix ]*delta*R;
                            pdata->mapweight[ ipix ] = temp;

                            /* We don't need this sum anymore, but calculate it for consistency with the
                               interface */
                            pdata->mapweightsq[ ipix ]++;
                        }
                    }
                }
            }
        }

        /* No variances - VAL__BADD checking version.
           ========================================= */
    } else if( pdata->operation == 6 ) {

        for( ibolo = 0; ibolo < pdata->nbolo; ibolo++ ) {
            for( itime = pdata->t1; itime <= pdata->t2; itime++ ) {
                di = ibolo*pdata->dbstride + itime*pdata->dtstride;
                ipix = pdata->lut[ di ];
                if( ipix >= pdata->p1 && ipix <= pdata->p2 ) {
                    if( pdata->whichmap ) {
                        if( pdata->whichmap[ itime ] != VAL__BADI ) {
                            ipix += pdata->whichmap[ itime ]*pdata->msize;
                        } else {
                            ipix = SMF__BADDIMT;
                        }
                    }

                    if( pdata->dat[ di ] != VAL__BADD &&
                            ipix != SMF__BADDIMT ) {
                        pdata->hitsmap[ ipix ]++;
                        temp = pdata->mapweight[ ipix ] + 1.0;
                        delta = pdata->dat[ di ] - pdata->map[ ipix ];
                        R = delta / temp;
                        pdata->map[ ipix ] += R;
                        pdata->mapvar[ ipix ] += pdata->mapweight[ ipix ]*delta*R;
                        pdata->mapweight[ ipix ] = temp;

                        /* We don't need this sum anymore, but calculate it for consistency with the
                           interface */
                        pdata->mapweightsq[ ipix ]++;
                    }
                }
            }
        }


        /* Final normalisation - input sample variance
           ========================================= */
    } else if( pdata->operation == 7 ) {

        pdata->scaleweight=0;
        pdata->scalevar=0;

        for( ipix = pdata->p1; ipix <= pdata->p2; ipix++ ) {

            /* If 0 weight set pixels to bad */
            if( pdata->mapweight[ ipix ] == 0.0 ) {
                pdata->mapweight[ ipix ] = VAL__BADD;
                pdata->map[ ipix ] = VAL__BADD;
                pdata->mapvar[ ipix ] = VAL__BADD;

                /* Otherwise re-normalize... although variance only reliable if we had
                   enough samples */
            } else if( pdata->hitsmap[ ipix ] >= SMF__MINSTATSAMP ) {
                double variance_n = pdata->mapvar[ ipix ]/pdata->mapweight[ ipix ];
                pdata->mapvar[ ipix ] = variance_n/( (double)(pdata->hitsmap[ ipix ]) - 1 );

                /* Work out average scale factor so that supplied weights would produce the
                   same map variance estimate as the sample variance calculation that we just
                   did. The average value is weighted by number of hits in the pixel to weight
                   well-sampled pixels more heavily */
                pdata->scalevar += pdata->hitsmap[ ipix ]*pdata->mapvar[ ipix ]
                                   *pdata->mapweight[ ipix ];
                pdata->scaleweight += pdata->hitsmap[ ipix ];
            } else {
                pdata->mapvar[ ipix ] = VAL__BADD;
            }
        }

        /* Final normalisation - error propagation
           ========================================= */
    } else if( pdata->operation == 8 ) {

        for( ipix = pdata->p1; ipix <= pdata->p2; ipix++ ) {

            /* If 0 weight set pixels to bad */
            if( pdata->mapweight[ ipix ] == 0.0 ) {
                pdata->mapweight[ ipix ] = VAL__BADD;
                pdata->mapweightsq[ ipix ] = VAL__BADD;
                pdata->map[ ipix ] = VAL__BADD;
                pdata->mapvar[ ipix ] = VAL__BADD;

                /* Otherwise re-normalize */
            } else {
                pdata->mapvar[ ipix ] = 1.0/pdata->mapweight[ ipix ];
                pdata->map[ ipix ] *= pdata->mapvar[ ipix ];
            }
        }


        /* Report an error if the worker was to do an unknown job.
           ====================================================== */
    } else {
        *status = SAI__ERROR;
        errRepf( "", "smf1_rebinmap1: Invalid operation (%d) supplied.",
                 status, pdata->operation );
    }
}
Exemplo n.º 2
0
void smf_write_shortmap( ThrWorkForce *wf, int shortmap, smfArray *res,
                         smfArray *lut, smfArray *qua, smfDIMMData *dat,
                         dim_t msize, const Grp *shortrootgrp, size_t contchunk,
                         int varmapmethod, const int *lbnd_out,
                         const int *ubnd_out, AstFrameSet *outfset,
                         int *status ) {

  dim_t dsize;                  /* Size of data arrays in containers */
  size_t i;                     /* loop counter */
  size_t idx=0;                 /* index within subgroup */
  size_t istart;                /* First useful timeslice */
  size_t iend;                  /* Last useful timeslice */
  int *lut_data=NULL;           /* Pointer to DATA component of lut */
  char name[GRP__SZNAM+1];      /* Buffer for storing names */
  size_t nshort=0;              /* Number of short maps */
  dim_t ntslice;                /* Number of time slices */
  char *pname=NULL;             /* Poiner to name */
  smf_qual_t *qua_data=NULL;    /* Pointer to DATA component of qua */
  double *res_data=NULL;        /* Pointer to DATA component of res */
  size_t sc;                    /* Short map counter */
  double *shortmapweight=NULL;  /* buffer for shotmap weights */
  double *shortmapweightsq=NULL;/* buffer for shotmap weights squared */
  int *shorthitsmap=NULL;       /* buffer for shotmap hits */
  size_t shortstart;            /* first time slice of short map */
  size_t shortend;              /* last time slice of short map */
  size_t tstride;               /* Time stride */

  if( *status != SAI__OK ) return;

  if( !res || !lut || !qua || !dat || !shortrootgrp ||
      !lbnd_out || !ubnd_out || !outfset || !shortmap ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": NULL inputs supplied", status );
    return;
  }

  if( !res || !res->sdata || !res->sdata[idx] || !res->sdata[idx]->hdr ||
      !res->sdata[idx]->hdr->allState ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": RES does not contain JCMTState", status );
    return;
  }

  /* Allocate space for the arrays */
  shortmapweight = astMalloc( msize*sizeof(*shortmapweight) );
  shortmapweightsq = astMalloc( msize*sizeof(*shortmapweightsq) );
  shorthitsmap = astMalloc( msize*sizeof(*shorthitsmap) );

  /* Use first subarray to figure out time dimension. Get the
     useful start and end points of the time series, and then
     determine "nshort" -- the number of complete blocks of
     shortmap time slices in the useful range. */

  smf_get_dims( qua->sdata[0], NULL, NULL, NULL, &ntslice,
                NULL, NULL, &tstride, status );

  qua_data = (qua->sdata[0]->pntr)[0];
  smf_get_goodrange( qua_data, ntslice, tstride, SMF__Q_BOUND,
                     &istart, &iend, status );

  shortstart = istart;

  if( *status == SAI__OK ) {
    if( shortmap == -1 ) {
      nshort = res->sdata[idx]->hdr->allState[iend].tcs_index -
        res->sdata[idx]->hdr->allState[istart].tcs_index + 1;

      msgOutf( "", FUNC_NAME
               ": writing %zu short maps, once each time TCS_INDEX increments",
               status, nshort );
    } else {
      nshort = (iend-istart+1)/shortmap;

      if( nshort ) {
        msgOutf( "", FUNC_NAME
                 ": writing %zu short maps of length %i time slices.",
                 status, nshort, shortmap );
      } else {
        /* Generate warning message if requested short maps are too long*/
        msgOutf( "", FUNC_NAME
                 ": Warning! short maps of lengths %i requested, but "
                 "data only %zu time slices.", status, shortmap,
                 iend-istart+1 );
      }
    }
  }

  /* Loop over short maps */
  for( sc=0; (sc<nshort)&&(*status==SAI__OK); sc++ ) {

    Grp *mgrp=NULL;             /* Temporary group for map names */
    smfData *mapdata=NULL;      /* smfData for new map */
    char tempstr[20];           /* Temporary string */
    char tmpname[GRP__SZNAM+1]; /* temp name buffer */
    char thisshort[20];         /* name particular to this shortmap */

    /* Create a name for the new map, take into account the
       chunk number. Only required if we are using a single
       output container. */
    pname = tmpname;
    grpGet( shortrootgrp, 1, 1, &pname, sizeof(tmpname), status );
    one_strlcpy( name, tmpname, sizeof(name), status );
    one_strlcat( name, ".", sizeof(name), status );

    /* Continuous chunk number */
    sprintf(tempstr, "CH%02zd", contchunk);
    one_strlcat( name, tempstr, sizeof(name), status );

    /* Shortmap number */
    sprintf( thisshort, "SH%06zu", sc );
    one_strlcat( name, thisshort, sizeof(name), status );
    mgrp = grpNew( "shortmap", status );
    grpPut1( mgrp, name, 0, status );

    msgOutf( "", "*** Writing short map (%zu / %zu) %s", status,
             sc+1, nshort, name );

    smf_open_newfile ( wf, mgrp, 1, SMF__DOUBLE, 2, lbnd_out,
                       ubnd_out, SMF__MAP_VAR, &mapdata,
                       status);

    /* Time slice indices for start and end of short map -- common to
       all subarrays */

    if( shortmap > 0) {
      /* Evenly-spaced shortmaps in time */
      shortstart = istart+sc*shortmap;
      shortend = istart+(sc+1)*shortmap-1;
    } else {
      /* One map each time TCS_INDEX increments -- just uses header
         for the first subarray */
      for(i=shortstart+1; (i<=iend) &&
            (res->sdata[0]->hdr->allState[i].tcs_index ==
             res->sdata[0]->hdr->allState[shortstart].tcs_index);
          i++ );
      shortend = i-1;
    }

    /* Bad status if we have invalid shortmap ranges. This might
       happen if there is ever a jump in TCS_INDEX for the shortmap=-1
       case since the total number of shortmaps is calculated simply
       as the difference between the first and final TCS indices. */

    if( !nshort || (iend<istart) || (iend>=ntslice) ) {
      *status = SAI__ERROR;
      errRepf( "", FUNC_NAME ": invalid shortmap range (%zu--%zu, ntslice=%zu)"
               "encountered", status, istart, iend, ntslice );
      break;
    }

    /* Loop over subgroup index (subarray) */
    for( idx=0; (idx<res->ndat)&&(*status==SAI__OK); idx++ ) {
      int rebinflag = 0;

      /* Pointers to everything we need */
      res_data = (res->sdata[idx]->pntr)[0];
      lut_data = (lut->sdata[idx]->pntr)[0];
      qua_data = (qua->sdata[idx]->pntr)[0];

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

      /* Rebin the data for this range of tslices. */
      if( idx == 0 ) {
        rebinflag |= AST__REBININIT;
      }

      if( idx == (res->ndat-1) ) {
        rebinflag |= AST__REBINEND;
      }

      smf_rebinmap1( NULL, res->sdata[idx],
                     dat->noi ? dat->noi[0]->sdata[idx] : NULL,
                     lut_data, shortstart, shortend, 1, NULL, 0,
                     SMF__Q_GOOD, varmapmethod,
                     rebinflag,
                     mapdata->pntr[0],
                     shortmapweight, shortmapweightsq, shorthitsmap,
                     mapdata->pntr[1], msize, NULL, status );

      /* Write out FITS header */
      if( (*status == SAI__OK) && res->sdata[idx]->hdr &&
          res->sdata[idx]->hdr->allState ) {
        AstFitsChan *fitschan=NULL;
        JCMTState *allState = res->sdata[idx]->hdr->allState;
        size_t midpnt = (shortstart + shortend) / 2;

        fitschan = astFitsChan ( NULL, NULL, " " );

        atlPtfti( fitschan, "SEQSTART", allState[shortstart].rts_num,
                  "RTS index number of first frame", status );
        atlPtfti( fitschan, "SEQEND", allState[shortend].rts_num,
                  "RTS index number of last frame", status);
        atlPtftd( fitschan, "MJD-AVG", allState[midpnt].rts_end,
                  "Average MJD of this map", status );
        atlPtfts( fitschan, "TIMESYS", "TAI", "Time system for MJD-AVG",
                  status );
        atlPtfti( fitschan, "TCSINDST", allState[shortstart].tcs_index,
                  "TCS index of first frame", status );
        atlPtfti( fitschan, "TCSINDEN", allState[shortend].tcs_index,
                  "TCS index of last frame", status );


        kpgPtfts( mapdata->file->ndfid, fitschan, status );

        if( fitschan ) fitschan = astAnnul( fitschan );
      }
    }

    /* Update shortstart in case we are counting steps in TCS_INDEX */
    shortstart = shortend+1;

    /* Write WCS */
    smf_set_moving( (AstFrame *) outfset, NULL, status );
    ndfPtwcs( outfset, mapdata->file->ndfid, status );

    /* Clean up */
    if( mgrp ) grpDelet( &mgrp, status );
    smf_close_file( wf, &mapdata, status );

  }

  /* Free up memory */
  shortmapweight = astFree( shortmapweight );
  shortmapweightsq = astFree( shortmapweightsq );
  shorthitsmap = astFree( shorthitsmap );

}
Exemplo n.º 3
0
static void smf1_qual_unmap( void *job_data_ptr, int *status ) {
/*
*  Name:
*     smf1_qual_unmap

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

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

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

*/

/* Local Variables: */
   SmfQualUnmapData *pdata;
   size_t *qcount;
   size_t i1;
   size_t i2;
   size_t i;
   size_t k;
   size_t nqbits;
   smf_qual_t *p1;
   unsigned char *p2;

/* 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 = (SmfQualUnmapData *) job_data_ptr;

   i1 = pdata->i1;
   i2 = pdata->i2;
   nqbits = pdata->nqbits;
   qcount = pdata->qcount;

   if( pdata->operation == 1 ){
      for( k=0; k<nqbits; k++ ) {
        qcount[k] = 0;
      }

      p1 = pdata->qual + i1;
      for( i = i1; i <= i2; i++,p1++) {
        for( k=0; k<nqbits; k++ ) {
          if( *p1 & BIT_TO_VAL(k) ) {
            qcount[k]++;
          }
        }
      }

   } else if( pdata->operation == 2 ){
      size_t curbit;
      size_t lowbit = pdata->lowbit;
      size_t highbit = pdata->highbit;
      p1 = pdata->qual + i1;
      p2 = pdata->qmap + i1;
      for( i = i1; i <= i2; i++,p1++,p2++) {
         curbit = 0;
         *p2 = 0;
         for( k=lowbit; k<=highbit; k++) {

/* was this bit used by this data array? */
            if( qcount[k] ) {

/* was the bit set for this location? */
              if( *p1 & BIT_TO_VAL(k) ) {
                *p2 |= BIT_TO_VAL(curbit);
              }

              curbit++;
            }
          }
        }

   } else if( pdata->operation == 3 ){

      p1 = pdata->qual + i1;
      p2 = pdata->qmap + i1;
      for( i = i1; i <= i2; i++,p1++,p2++) {

        *p2 = 0;
        if( *p1 ) {
          if ( *p1 & (SMF__Q_BADDA|SMF__Q_BADB|SMF__Q_NOISE) ) {
            *p2 |= SMF__TCOMPQ_BAD;
          }
          if ( *p1 & (SMF__Q_APOD|SMF__Q_PAD) ) {
            *p2 |= SMF__TCOMPQ_ENDS;
          }
          if ( *p1 & (SMF__Q_JUMP|SMF__Q_IP|SMF__Q_SPIKE|SMF__Q_FILT|SMF__Q_EXT|SMF__Q_LOWAP|SMF__Q_BADEF) ) {
            *p2 |= SMF__TCOMPQ_BLIP;
          }
          if ( *p1 & (SMF__Q_COM|SMF__Q_SSN|SMF__Q_PCA) ) {
            *p2 |= SMF__TCOMPQ_MATCH;
          }
          if ( *p1 & (SMF__Q_RING) ) {
            *p2 |= SMF__TCOMPQ_RING;
          }
          if ( *p1 & (SMF__Q_STAT) ) {
            *p2 |= SMF__TCOMPQ_TEL;
          }
          if (*p2 == 0 ) {

/* something went wrong. We missed a quality bit somewhere */
            msgOutiff(MSG__QUIET, "", FUNC_NAME ": Untested quality bit found"
                      " in position %zu with value %u", status,
                      i, (unsigned int)*p1);
          }
        }
      }

   } else {
      *status = SAI__ERROR;
      errRepf( "", "smf1_qual_unmap: Invalid operation (%d) supplied.",
               status, pdata->operation );
   }
}
Exemplo n.º 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 box;
  int minbox;
  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( !dat ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": smfData does not contain a DATA component",status);
    return;
  }

  if( !data->hdr ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": smfData does not contain a header",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. */
  if( qua ) {
     smf_get_goodrange( qua, ntslice, tstride, SMF__Q_PAD, &pstart, &pend,
                        status );
  } else {
    pstart = 0;
    pend = ntslice - 1;
  }

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

  /* We use smaller boxes for very slow scans (sample rates under 20 Hz).
     For instance, POL-2 Stokes parameter data created by calcqu. Also,
     we do not add noise for very slow scans, so set the random number
     generator type NULL. */
  if( 1.0/data->hdr->steptime < 20 ) {
    box = BOX/2;
    minbox = MINBOX/2;
    type = NULL;
  } else {
    box = BOX;
    minbox = MINBOX;
  }

  /* 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 = type ? gsl_rng_alloc( type ) : NULL;
    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;
    pdata->box = box;
    pdata->minbox = minbox;

    /* 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 );
  }
}
Exemplo n.º 5
0
void smf_addmap1( int contchunk, double *map1, double *mapweight1, double *boloweight1,
                  int *hitsmap1, double *mapvar1, smf_qual_t *mapqual1,
                  double *map2, double *boloweight2, int *hitsmap2,
                  double *mapvar2, smf_qual_t *mapqual2, dim_t msize,
                  double chunkweight2, int *status ) {

  /* Local Variables */
  dim_t i;                   /* Loop counter */

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

  /* Check for NULL inputs */
  if( (map1==NULL) || (boloweight1==NULL) || (hitsmap1==NULL) ||
      (mapvar1==NULL) || (map2==NULL) || (boloweight2==NULL) ||
      (hitsmap2==NULL) || (mapvar2==NULL) ) {
      *status = SAI__ERROR;
      errRep(FUNC_NAME, "Addmap failed due to NULL inputs.", status);
      return;
  }

  /* If this is the first chunk, just update the mapweight array. */
  if( contchunk == 0 ) {
    for( i=0; i<msize; i++ ) {
       if( mapvar1[ i ] != VAL__BADD ) {
          mapweight1[ i ] = chunkweight2/mapvar1[ i ];
          boloweight1[ i ] *= chunkweight2;
          hitsmap1[ i ] *= chunkweight2;
       }
    }

  /* Otherwise, loop over every pixel and store the weighted values in
     arrays associated with map1 */
  } else {
    for( i=0; i<msize; i++ ) {
      if( (map1[i] == VAL__BADD) || (mapvar1[i] == VAL__BADD) ) {

        /* If bad pixel in map1 just copy map2 regardless */
        map1[i] = map2[i];
        mapweight1[i] = chunkweight2/mapvar2[ i ];
        boloweight1[i] = boloweight2[i];
        hitsmap1[i] = hitsmap2[i];
        mapvar1[i] = mapvar2[i];
        mapqual1[i] = mapqual2[i];

      } else if( (map2[i] != VAL__BADD) && (mapvar2[i] != VAL__BADD) ) {

        /* Add together if both maps have good pixels */
        if( (mapvar1[i]<=0) || (mapvar2[i]<=0) ) {
          *status = SAI__ERROR;
          errRepf("", FUNC_NAME ": invalid variance(s) <=0 detected (%g and %g)", status,
                  mapvar1[i], mapvar2[i]);
          return;

        } else {
          double w1 = mapweight1[ i ];
          double w2 = chunkweight2/mapvar2[ i ];
          double wnew = w1 + w2;
          map1[ i ] = ( map1[i]*w1 + map2[i]*w2 )/wnew;
          mapvar1[ i ] = ( mapvar1[ i ]*w1*w1 + chunkweight2*w2 )/( wnew*wnew );
          boloweight1[ i ] += boloweight2[i]*chunkweight2;
          hitsmap1[ i ] += hitsmap2[i]*chunkweight2;
          mapqual1[ i ] &= mapqual2[i];
          mapweight1[ i ] = wnew;
        }
      }
    }
  }
}
Exemplo n.º 6
0
void smf_import_array( smfData *refdata, const char *name, int bad,
                       int expand, double *dataptr, int *status ) {

/* Local Variables: */
   Grp *igrp;                  /* Group holding NDF name */
   dim_t nbolo;                /* Number of bolometers */
   dim_t ntslice;              /* Number of time slices */
   double *pin;                /* Pointer to next input value */
   double *pout;               /* Pointer to next output value */
   double mean;                /* Mean value int he plane */
   double vsum;                /* Sum of good data values */
   int nbad;                   /* Number of bad data values */
   int ngood;                  /* Number of good data values */
   size_t bstride;             /* Stride between bolometer values */
   size_t i;                   /* Loop count */
   size_t j;                   /* Loop count */
   dim_t nel;                  /* Number of elements in array */
   size_t tstride;             /* Stride between time slices */
   smfData *data;              /* Model for one sub-array */

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

/* Attempt to open the NDF. */
   igrp = grpNew( " ", status );
   grpPut1( igrp, name, 0, status );
   smf_open_file( igrp, 1, "READ", 0, &data, status );
   grpDelet( &igrp, status );

/* Ensure the smfData read from the NDF uses the same data ordering as the
   reference smfData. */
   smf_dataOrder( data, refdata->isTordered, status );
   if( *status == SAI__OK ) {

/* Check the data type and dimensions of the NDF are the same as the
   reference NDF. */
      if( data->dtype != SMF__DOUBLE ) {
         *status = SAI__ERROR;
         errRepf( " ", "NDF '%s' has incorrect data type - should be "
                  "DOUBLE PRECISION.", status, name );

      } else if( data->ndims != refdata->ndims ) {
         *status = SAI__ERROR;
         errRepf( " ", "NDF '%s' is %zu dimensional - must be %zu "
                  "dimensional.", status, name, data->ndims, refdata->ndims );

      } else if( !expand || refdata->ndims != 3 ) {
         expand = 0;

         for( i = 0; i < refdata->ndims; i++ ) {
            if( data->dims[i] != refdata->dims[i] &&
                *status == SAI__OK ){
               *status = SAI__ERROR;
               errRepf( " ", "NDF '%s' has incorrect dimension %zu on "
                        "pixel axis %zu - should be %zu.", status,
                        name, data->dims[i], i + 1, refdata->dims[i] );
            } else if( data->lbnd[i] != refdata->lbnd[i] &&
                *status == SAI__OK ){
               *status = SAI__ERROR;
               errRepf( " ", "NDF '%s' has incorrect lower bound %d on "
                        "pixel axis %zu - should be %d.", status,
                        name, data->lbnd[i], i + 1, refdata->lbnd[i] );
            }
         }

      } else {
         for( i = 0; i < refdata->ndims; i++ ) {

            if( data->dims[i] == 1 ) {

            } else if( data->dims[i] != refdata->dims[i] &&
                *status == SAI__OK ){
               *status = SAI__ERROR;
               errRepf( " ", "NDF '%s' has incorrect dimension %zu on "
                        "pixel axis %zu - should be %zu.", status,
                        name, data->dims[i], i + 1, refdata->dims[i] );
            } else if( data->lbnd[i] != refdata->lbnd[i] &&
                *status == SAI__OK ){
               *status = SAI__ERROR;
               errRepf( " ", "NDF '%s' has incorrect lower bound %d on "
                        "pixel axis %zu - should be %d.", status,
                        name, data->lbnd[i], i + 1, refdata->lbnd[i] );
            }
         }

      }

/* Get the smfData dimensions and strides. */
      smf_get_dims( refdata, NULL, NULL, &nbolo, &ntslice, &nel, &bstride,
                    &tstride, status );

/* Copy the values into the model array, replacing bad values as required. */
      if( *status == SAI__OK ) {
         pin = data->pntr[0];
         pout = dataptr;
         if( data->ndims < 3 ) data->dims[2] = 1;
         if( data->ndims < 2 ) data->dims[1] = 1;

         /* Copy the data into the returned array unchanged. */
         if( expand ) {

            pin = (double *) data->pntr[0];
            for( i = 0; i < ntslice; i++,pin++ ) {
               pout = dataptr + i*tstride;

               for( j = 0; j < nbolo; j++ ) {
                  if( *pin != VAL__BADD ) {
                     *pout = *pin;
                  } else {
                     *pout = VAL__BADD;
                  }
                  pout += bstride;
               }
            }

         } else {
            memcpy( pout, pin, nel*sizeof(*pin) );
         }

/* Retain bad values. */
         if( bad == 0 )  {

/* Replace bad values with zero. */
         } else if( bad == 1 )  {
            pout = dataptr;
            for( i = 0; i < nel; i++,pout++ ) {
               if( *pout == VAL__BADD ) *pout = 0.0;
            }

/* Replace bad values with the mean value in the time slice. */
         } else if( bad == 2 )  {
            pout = dataptr;
            mean = VAL__BADD;

            for( i = 0; i < ntslice; i++ ) {
               vsum = 0.0;
               ngood = 0;
               nbad = 0;
               pout = dataptr + i*tstride;

               for( j = 0; j < nbolo; j++ ) {
                  if( *pout != VAL__BADD ) {
                     vsum += *pout;
                     ngood++;
                  } else {
                     nbad++;
                  }
                  pout += bstride;
               }

               if( ngood > 0 ) mean = vsum/ngood;

               if( nbad > 0 ) {
                  if( mean != VAL__BADD ) {
                     pout = dataptr + i*tstride;
                     for( j = 0; j < nbolo; j++ ) {
                        if( *pout == VAL__BADD ) *pout = mean;
                        pout += bstride;
                     }
                  } else {
                     *status = SAI__ERROR;
                     errRepf( " ", "NDF '%s' has no good values in plane "
                              "%zu.", status, name, i );
                     break;
                  }
               }
            }
         }
      }

/* Close the NDF. */
      smf_close_file( &data, status );
   }
}
Exemplo n.º 7
0
void smf__calc_wvm_job( void *job_data, int *status ) {

  struct timeval tv1;
  struct timeval tv2;
  smfData * curdata = NULL;
  smfArray * thesedata;
  double prevtime = VAL__BADD;
  double prevtau = VAL__BADD;
  double lastgoodtau = VAL__BADD;   /* most recent good tau */
  size_t lastgoodidx = SMF__BADSZT; /* index of most recent good value */
  size_t nbadidx = 0;    /* number of time slices in the current gap */
  size_t maxgap;
  dim_t t1;
  dim_t t2;
  size_t nrelated;

  double * taudata = NULL;
  size_t ngood = 0;
  dim_t i;
  smfCalcWvmJobData *pdata;
  double amprev;
  AstKeyMap * extpars;

  if (*status != SAI__OK) return;

  pdata = (smfCalcWvmJobData *)job_data;
  t1 = pdata->t1;
  t2 = pdata->t2;
  amprev = pdata->airmass;
  thesedata = pdata->thesedata;
  taudata = pdata->taudata;
  nrelated = thesedata->ndat;
  extpars = pdata->extpars;
  maxgap = pdata->maxgap;

  /* Lock the AST pointers to this thread */
  astLock( extpars, 0 );
  for (i=0;i<thesedata->ndat;i++) {
    smf_lock_data( (thesedata->sdata)[i], 1, status );
  }

/* Debugging message indicating thread started work */
  msgOutiff( SMF__TIMER_MSG, "", "smfCalcSmoothedWVM: thread starting on slices %" DIM_T_FMT
             " -- %" DIM_T_FMT,
             status, t1, t2 );
  smf_timerinit( &tv1, &tv2, status);

  for (i=t1; i<=t2; i++) {

    if (!curdata) {
      SELECT_DATA( thesedata, curdata, VAL__BADD, wvm_time, i );
    }

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

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

    /* if we have no good data we store a bad value */
    if (!curdata) {
      prevtau = VAL__BADD;
    } else {
      const JCMTState * state = NULL;
      state = curdata->hdr->state;

      /* if we have old values from the WVM or no value we don't trust them */
      if ( state->wvm_time != VAL__BADD &&
           (fabs(state->wvm_time - state->rts_end) * SPD) < 60.0 ) {
        /* Only calculate a tau when we have new values */
        if ( prevtime != state->wvm_time ) {
          double thistau = VAL__BADD;
          double airmass = VAL__BADD;

          prevtime = state->wvm_time;

          airmass = state->tcs_airmass;
          if (airmass == VAL__BADD) {
            airmass = amprev;
          } else {
            amprev = airmass;
          }

          thistau = smf_calc_wvm( curdata->hdr, airmass, extpars, status );

          /* Check status and/or value of tau */
          if ( thistau == VAL__BADD ) {
            if ( *status == SAI__OK ) {
              *status = SAI__ERROR;
              errRepf("", "Error calculating tau from WVM temperatures at time slice %" DIM_T_FMT,
                      status, i);
            }
          } else if ( thistau < 0.0 ) {
            msgOutiff( MSG__QUIET, "", "WARNING: Negative WVM tau calculated (%g). Ignoring.",
                       status, thistau );
            prevtau = VAL__BADD;
          } else {
            prevtau = thistau;
          }
        } else {
          /* We use the previous tau since we should have calculated it earlier */
        }
      } else {
        /* No good reading so tau is bad */
        prevtau = VAL__BADD;
      }
    }

    /* Prevtau is the tau that should be assigned to the current position */

    /* see about gaps */
    if (prevtau == VAL__BADD) {
      nbadidx++;
    } else {
      /* we have a good value so we now have to see if there is a gap to fill */
      if (i > 0 && lastgoodidx != (i-1) ) {
        /* the previous value was bad so we may have to patch up if small */
        if ( nbadidx < maxgap ) {
          size_t j;
          if (lastgoodidx == SMF__BADSZT) {
            /* gap is at the start so fill with current value */
            for (j=t1; j<i;j++) {
              taudata[j] = prevtau;
              ngood++;
            }
          } else {
            /* replace with mean value */
            double meantau = (lastgoodtau + prevtau) / 2.0;
            for (j=lastgoodidx+1; j<i; j++) {
              taudata[j] = meantau;
              ngood++;
            }
          }
        }
      }

      /* we know this index was good */
      lastgoodidx = i;
      lastgoodtau = prevtau;
      nbadidx = 0;
      ngood++;

    }

    /* Store the current tau value */
    taudata[i] = prevtau;

  }

  /* if the last value in the time series was bad we need to see about
     filling with the last good value */
  if (*status == SAI__OK && nbadidx > 0 && nbadidx < maxgap) {
    for (i=lastgoodidx+1; i<=t2; i++) {
      taudata[i] = lastgoodtau;
      ngood++;
    }
  }

/* Report the time taken in this thread. */
  msgOutiff( SMF__TIMER_MSG, "",
             "smfCalcSmoothedWVM: thread finishing slices %" DIM_T_FMT
             " -- %" DIM_T_FMT " (%zu good) (%.3f sec)",
             status, t1, t2, ngood, smf_timerupdate( &tv1, &tv2, status ) );

  /* Store number of good values */
  pdata->ngood = ngood;

  /* Unlock the AST pointers from this thread */
  astUnlock( extpars, 1 );
  for (i=0;i<thesedata->ndat;i++) {
    smf_lock_data( (thesedata->sdata)[i], 0, status );
  }

}
Exemplo n.º 8
0
void smurf_jsatilelist( int *status ) {

/* Local Variables */
   AstFitsChan *fc = NULL;
   AstFrameSet *fs = NULL;
   AstObject *obj;
   AstRegion *region;
   Grp *igrp = NULL;
   Grp *sgrp = NULL;
   double vertex_data[ 2*MAXVERT ];
   int *tiles = NULL;
   int i;
   int indf;
   int lbnd[2];
   int ntile;
   int nvert_dec;
   int nvert_ra;
   int ubnd[2];
   size_t size;
   size_t ssize;
   smfJSATiling tiling;

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

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

/* Attempt to to get an AST Region. */
   kpg1Gtobj( "IN", "Region",
              (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion),
              &obj, status );
   region = (AstRegion *) obj;

/* If successful, attempt to access the IN parameter as an NDF. If this
   works, we may be able to determine the instrument by looking at its
   FITS extension. */
   if( *status == SAI__OK && region ) {
      ndfExist( "IN", "Read", &indf, status );

/* If we got an NDF, get a FitsChan holding the contents of its FITS
   extension. Annul the error if the NDF has no FITS extension. */
      if( indf != NDF__NOID ) {
         kpgGtfts( indf, &fc, status );
         if( *status == KPG__NOFTS ) {
            errAnnul( status );
            fc = NULL;
         }
         ndfAnnul( &indf, status );
      }

/* Select a JSA instrument and get the parameters defining the layout of
   tiles for the selected instrument. */
      smf_jsainstrument( "INSTRUMENT", fc, SMF__INST_NONE, &tiling,
                         status );

/* Get the list of identifiers for tiles that overlap the region. */
      tiles = smf_jsatiles_region( region, &tiling, &ntile, status );

/* If a null value was supplied for IN, attempt to get the positions of
   vertices on the sky to define the region. */
   } else if( *status == PAR__NULL ) {
      errAnnul( status );
      parGet1d( "VERTEX_RA", MAXVERT, vertex_data, &nvert_ra, status );
      parGet1d( "VERTEX_DEC", MAXVERT, vertex_data + MAXVERT, &nvert_dec,
                 status );
      if( nvert_ra != nvert_dec && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( "", "Differing numbers of RA (%d) and Dec (%d) vertex values "
                 "supplied.", status, nvert_ra, nvert_dec );
      }

/* Convert from degrees to radians. */
      for( i = 0; i < nvert_ra; i++ ) {
         vertex_data[ i ] *= AST__DD2R;
         vertex_data[ MAXVERT + i ] *= AST__DD2R;
      }

/* Select a JSA instrument and get the parameters defining the layout of
   tiles for the selected instrument. */
      smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &tiling,
                         status );

/* Create a frame in which to define the region - we arbitrarily use tile 1. */
      smf_jsatile( 1, &tiling, 0, NULL, &fs, NULL, lbnd, ubnd, status );

/* Create the region. */
      region = (AstRegion *) astPolygon( fs, nvert_ra, MAXVERT, vertex_data, NULL, " " );

/* If the region is unbounded, it is probably because the vertices were
   given in the wrong order. Invert the Polyfon to correct this. */
      if( !astGetI( region, "bounded" ) ) astNegate( region );

/* Get the list of identifiers for tiles that overlap the region. */
      tiles = smf_jsatiles_region( region, &tiling, &ntile, status );
   }

/* If the IN parameter could not be accessed as a Region, annull any error
   and get a group of input data files. */
   if( !region || *status == SAI__ERROR ) {
      if( *status != SAI__OK ) errAnnul( status );
      kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );

/* Get a group containing just the files holding science data. */
      smf_find_science( NULL, igrp, &sgrp, 0, NULL, NULL, 1, 1, SMF__NULL, NULL,
                        NULL, NULL, NULL, status );

/* Check we have at least once science file. */
      ssize = grpGrpsz( sgrp, status );
      if( ssize == 0 ) {
         msgOutif( MSG__NORM, " ", "None of the supplied input frames were SCIENCE.",
                   status );

/* Get the list of identifiers for tiles that receive any data. */
      } else {
         tiles = smf_jsatiles_data( sgrp, ssize, &tiling, &ntile, status );
      }

/* Delete the groups. */
      if( igrp ) grpDelet( &igrp, status);
      if( sgrp ) grpDelet( &sgrp, status);
   }

/* Sort the list of overlapping tiles into ascending order. */
   if( *status == SAI__OK ) {
      qsort( tiles, ntile, sizeof( *tiles ), jsatilelist_icomp );

/* Display the list of overlapping tiles. */
      msgBlank( status );
      msgOutf( "", "   %s tiles touched by supplied data:", status,
               tiling.name );
      msgBlank( status );
      for( i = 0; i < ntile; i++ ) {
         msgSeti( "I", tiles[ i ] );
         msgOut( "", "   ^I", status );
      }
      msgBlank( status );

/* Write out the list of overlapping tiles to the output parameter. */
      parPut1i( "TILES", ntile, tiles, status );
   }

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

/* End the AST context. */
   astEnd;

/* Issue a status indication.*/
   msgBlank( status );
   if( *status == SAI__OK ) {
      msgOutif( MSG__VERB, "", "JSATILELIST succeeded.", status);
   } else {
      msgOutif( MSG__VERB, "", "JSATILELIST failed.", status);
   }
}
Exemplo n.º 9
0
void smf_filter_execute( ThrWorkForce *wf, smfData *data, smfFilter *filt,
                         int complement, int whiten, int *status ) {

  /* Local Variables */
  size_t apod_length=0;           /* apodization length */
  fftw_iodim dims;                /* I/O dimensions for transformations */
  size_t first;                   /* First sample apodization at start */
  int i;                          /* Loop counter */
  smfFilterExecuteData *job_data=NULL;/* Array of job data for each thread */
  size_t last;                    /* Last sample apodization at end */
  dim_t nbolo=0;                  /* Number of bolometers */
  dim_t ndata=0;                  /* Total number of data points */
  int nw;                         /* Number of worker threads */
  dim_t ntslice=0;                /* Number of time slices */
  smf_qual_t *qua=NULL;           /* Pointer to quality flags */
  smfFilterExecuteData *pdata=NULL; /* Pointer to current job data */
  size_t step;                    /* step size for dividing up work */

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

  /* Check for NULL pointers */
  if( !data ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": NULL smfData pointer", status );
    return;
  }

  if( !filt ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": NULL smfFilter pointer", status );
    return;
  }

  if( filt->ndims == 2 ) {
    smf_filter2d_execute( wf, data, filt, complement, status );
    return;
  }

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

  /* Ensure that the smfData is ordered correctly (bolo ordered) */
  smf_dataOrder( wf, data, 0, status );

  /* Obtain the dimensions of the array being filtered */
  smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, &ndata, NULL, NULL, status);

  if( *status != SAI__OK ) return;

  /* Using complement of the filter? */
  if( complement ) smf_filter_complement( filt, status );

  /* Pointers to quality */
  qua = smf_select_qualpntr( data, NULL, status );

  /* Determine the first and last samples to apodize (after padding), if
     any. Assumed to be the same for all bolometers. */
  if( qua ) {
     smf_get_goodrange( qua, ntslice, 1, SMF__Q_PAD, &first, &last, status );
  } else {
     first = 0;
     last = ntslice - 1;
  }

  /* Can we apodize? */
  apod_length = filt->apod_length;
  if( *status == SAI__OK ) {
    if( apod_length == SMF__MAXAPLEN ) {
      apod_length = (last-first+1)/2;
      msgOutiff( MSG__DEBUG, "", FUNC_NAME
                 ": Using maximum apodization length, %zu samples.",
                 status, apod_length );
    } else if( (last-first+1) < (2*apod_length) && apod_length != SMF__BADSZT ){
      *status = SAI__ERROR;
      errRepf("", FUNC_NAME
              ": Can't apodize, not enough samples (%zu < %zu).", status,
              last-first+1, 2*apod_length);
    }
  }

  /* If apodising is switched off, fill gaps in the data and re-create
     the artifical data used for padding based on the current contents of
     the smfData. */
  if( apod_length == SMF__BADSZT ) {
    smf_fillgaps( wf, data, SMF__Q_PAD | SMF__Q_GAP, status );

  /* If apodising is switched on, fill the data (retaining the zero padding)
     and apodise the data. */
  } else {
    smf_fillgaps( wf, data, SMF__Q_GAP, status );
    if( apod_length > 0 ) smf_apodize( data, apod_length, 1, status );
  }

  /* Describe the input and output array dimensions for FFTW guru interface.
     - dims describes the length and stepsize of time slices within a bolometer
  */

  dims.n = ntslice;
  dims.is = 1;
  dims.os = 1;

  /* Set up the job data */

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

  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;

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

    pdata->data_fft_r = astMalloc(filt->fdims[0]*sizeof(*pdata->data_fft_r));
    pdata->data_fft_i = astMalloc(filt->fdims[0]*sizeof(*pdata->data_fft_i));
    pdata->filt = filt;
    pdata->whiten = whiten;
    pdata->complement = complement;
    pdata->ijob = -1;   /* Flag job as ready to start */

    /* Setup forward FFT plan using guru interface. Requires protection
       with a mutex */
    thrMutexLock( &smf_filter_execute_mutex, status );

    if( *status == SAI__OK ) {
      /* Just use the data_fft_* arrays from the first chunk of job data since
         the guru interface allows you to use the same plans for multiple
         transforms. */
      pdata->plan_forward = fftw_plan_guru_split_dft_r2c( 1, &dims, 0, NULL,
                                                          data->pntr[0],
                                                          pdata->data_fft_r,
                                                          pdata->data_fft_i,
                                                          FFTW_ESTIMATE |
                                                          FFTW_UNALIGNED );
    }

    thrMutexUnlock( &smf_filter_execute_mutex, status );

    if( !pdata->plan_forward && (*status == SAI__OK) ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME
              ": FFTW3 could not create plan for forward transformation",
              status);
    }

    /* Setup inverse FFT plan using guru interface */
    thrMutexLock( &smf_filter_execute_mutex, status );

    if( *status == SAI__OK ) {
      pdata->plan_inverse = fftw_plan_guru_split_dft_c2r( 1, &dims, 0, NULL,
                                                          pdata->data_fft_r,
                                                          pdata->data_fft_i,
                                                          data->pntr[0],
                                                          FFTW_ESTIMATE |
                                                          FFTW_UNALIGNED);
    }

    thrMutexUnlock( &smf_filter_execute_mutex, status );

    if( !pdata->plan_inverse && (*status==SAI__OK) ) {
      *status = SAI__ERROR;
      errRep( "", FUNC_NAME
              ": FFTW3 could not create plan for inverse transformation",
              status);
    }

  }

  /* Execute the filter */
  for( i=0; (*status==SAI__OK)&&i<nw; i++ ) {
    pdata = job_data + i;
    pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata,
                               smfFilterExecuteParallel, 0,
                               NULL, status );
  }

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

  /* Clean up the job data array */
  if( job_data ) {
    for( i=0; i<nw; i++ ) {
      pdata = job_data + i;
      if( pdata->data_fft_r ) pdata->data_fft_r = astFree( pdata->data_fft_r );
      if( pdata->data_fft_i ) pdata->data_fft_i = astFree( pdata->data_fft_i );

      /* Destroy the plans */
      thrMutexLock( &smf_filter_execute_mutex, status );
      fftw_destroy_plan( pdata->plan_forward );
      fftw_destroy_plan( pdata->plan_inverse );
      thrMutexUnlock( &smf_filter_execute_mutex, status );
    }
    job_data = astFree( job_data );
  }

  /* Return the filter to its original state if required */
  if( complement == -1 ) smf_filter_complement( filt, status );


  /* Remove the effects of the apodisation from the filtered data. */
  if( apod_length != SMF__BADSZT && apod_length > 0 ) {
     smf_apodize( data, apod_length, 0, status );
  }

}
Exemplo n.º 10
0
void smf_uncalc_iqu( ThrWorkForce *wf, smfData *data, double *idata,
                     double *qdata, double *udata, double *angdata,
                     int pasign, double paoff, double angrot, double amp2,
                     double phase2, double amp4, double phase4, double amp16,
                     double phase16, const double *qinst, const double *uinst,
                     int harmonic, int *status ){

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

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

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

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

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

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

/* Can only handle POL_CRD = FPLANE at the moment. */
   if( ipolcrd != 0 && *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRepf( "", "smf_uncalc_iqu: currently only POL_CRD = FPLANE is "
               "supported.", status );
   }

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

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

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

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

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

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

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

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

         pdata->bstride = bstride;
         pdata->nbolo = nbolo;
         pdata->tstride = tstride;
         pdata->allstates = hdr->allState;
         pdata->ipi = idata;
         pdata->ipq = qdata;
         pdata->ipu = udata;
         pdata->ipang = angdata;
         pdata->ipolcrd = ipolcrd;
         pdata->old = old;
         pdata->ntslice = ntslice;
         pdata->pasign = pasign ? +1: -1;
         pdata->paoff = paoff;
         pdata->angrot = angrot;
         pdata->angfac = harmonic/4.0;
         pdata->amp2 = amp2;
         pdata->amp4 = amp4;
         pdata->amp16 = amp16;
         pdata->phase2 = phase2;
         pdata->phase4 = phase4;
         pdata->phase16 = phase16;
         pdata->qinst = qinst;
         pdata->uinst = uinst;

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

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

/* Free resources. */
   job_data = astFree( job_data );
}
Exemplo n.º 11
0
static void smf1_uncalc_iqu_job( void *job_data, int *status ) {
/*
*  Name:
*     smf1_uncalc_iqu_job

*  Purpose:
*     Calculate I, Q and U for a block of bolometers.

*  Invocation:
*     void smf1_uncalc_iqu_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
*        smfUncalcIQUJobData structure.
*     status = int * (Given and Returned)
*        Pointer to global status.

*  Description:
*     This routine calculate the I, Q and U values for each bolometer in
*     a block of bolometers. It runs within a thread instigated by
*     smf_uncalc_iqu.

*/

/* Local Variables: */
   const JCMTState *allstates;/* Pointer to array of JCMTState structures */
   const JCMTState *state;    /* JCMTState info for current time slice */
   dim_t b1;                  /* First bolometer index */
   dim_t b2;                  /* Last bolometer index */
   dim_t ibolo;               /* Bolometer index */
   dim_t nbolo;               /* Total number of bolometers */
   double *iin;               /* Pointer to I array for each bolometer*/
   double *ipang;             /* Pointer to supplied FP orientation array */
   double *ipi0;              /* Pointer to input I array for 1st time */
   double *ipi;               /* Pointer to supplied I array */
   double *ipq0;              /* Pointer to input Q array for 1st time */
   double *ipq;               /* Pointer to supplied Q array */
   double *ipu0;              /* Pointer to input U array for 1st time */
   double *ipu;               /* Pointer to supplied U array */
   double *qin;               /* Pointer to Q array for each bolometer*/
   double *uin;               /* Pointer to U array for each bolometer*/
   double amp2;
   double amp4;
   double amp16;
   double phase2;
   double phase4;
   double phase16;
   double angfac;
   double angle;              /* Phase angle for FFT */
   double angrot;             /* Angle from focal plane X axis to fixed analyser */
   double cosval;             /* Cos of twice reference rotation angle */
   double ip_qi;              /* normalised instrument Q for current bolo */
   double ip_ui;              /* normalised instrument U for current bolo */
   double ival;               /* I  value */
   double paoff;              /* WPLATE value corresponding to POL_ANG=0.0 */
   double phi;                /* Angle from fixed analyser to effective analyser */
   double qval;               /* Q value wrt fixed analyser */
   double sinval;             /* Sin of twice reference rotation angle */
   double uval;               /* U value wrt fixed analyser */
   double wplate;             /* Angle from fixed analyser to have-wave plate */
   int ipolcrd;               /* Reference direction for pol_ang */
   int itime;                 /* Time slice index */
   int ntslice;               /* Number of time slices */
   int old;                   /* Data has old-style POL_ANG values? */
   int pasign;                /* +1 or -1 indicating sense of POL_ANG value */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfUncalcIQUJobData *pdata;   /* Pointer to job data */

/* 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 = (smfUncalcIQUJobData *) job_data;

   b1 = pdata->b1;
   b2 = pdata->b2;
   bstride = pdata->bstride;
   nbolo = pdata->nbolo;
   tstride = pdata->tstride;
   allstates = pdata->allstates;
   ipi = pdata->ipi;
   ipq = pdata->ipq;
   ipu = pdata->ipu;
   ipolcrd = pdata->ipolcrd;
   ntslice = pdata->ntslice;
   old = pdata->old;
   pasign = pdata->pasign;
   paoff = pdata->paoff;
   angrot = pdata->angrot;
   angfac = pdata->angfac;
   amp2 = pdata->amp2;
   phase2 = pdata->phase2;
   amp4 = pdata->amp4;
   phase4 = pdata->phase4;
   amp16 = pdata->amp16;
   phase16 = pdata->phase16;

/* Check we have something to do. */
   if( b1 < nbolo ) {

/* Initialise pointers to the first time slice I, Q and U values for
   the first bolometer to be processed. */
      ipi0 = ipi + bstride*b1;
      ipq0 = ipq + bstride*b1;
      ipu0 = ipu + bstride*b1;

/* Loop round all bolometers to be processed by this thread. */
      for( ibolo = b1; ibolo <= b2; ibolo++ ) {

/* The instrumental polarisation seen by this bolometer. These are
   normalised Q and U values. Multiply them by the total intensity to
   get the instrument Q and U, with respect to the fixed analyser. */
         ip_qi = pdata->qinst ? pdata->qinst[ ibolo ] : 0.0;
         ip_ui = pdata->uinst ? pdata->uinst[ ibolo ] : 0.0;

/* Initialise pointers to the next I, Q and U time slice values for
   the current bolometer. */
         iin = ipi0;
         qin = ipq0;
         uin = ipu0;

/* Initialise a pointer to the anti-clockwise angle from the Q/U reference
   direction to the focal plane Y axis, at the next time slice. */
         ipang = pdata->ipang;

/* Loop round all time slices. */
         state = allstates;
         for( itime = 0; itime < ntslice; itime++,state++,ipang++ ) {

/* Get the POL_ANG value for this time slice. */
            angle = state->pol_ang;

/* Check the I, Q, U and angle values are good. */
            if( *iin != VAL__BADD && *qin != VAL__BADD &&
                *uin != VAL__BADD && angle != VAL__BADD &&
                *ipang != VAL__BADD ) {

/* If POL_ANG is stored in arbitrary encoder units, convert to radians. */
               if( old ) angle = angle*TORADS;

/* Following SUN/223 (section "Single-beam polarimetry"/"The Polarimeter"),
   get the angle from the fixed analyser to the half-waveplate axis, in radians.
   Positive rotation is from focal plane axis 1 (x) to focal plane axis 2 (y).

   Not sure about the sign of tcs_az/tr_ang at the moment so do not use them
   yet. */
               wplate = 0.0;
               if( ipolcrd == 0 ) {
                  wplate = pasign*angle + paoff;

               } else if( *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  errRepf( "", "smf_uncalc_iqu: currently only POL_CRD = "
                           "FPLANE is supported.", status );
               }

/*
               if( ipolcrd == 1 ) {
                  wplate += state->tcs_az_ang;
               } else if( ipolcrd == 2 ) {
                  wplate += state->tcs_tr_ang;
               }
*/

/* Get the angle from the fixed analyser to the effective analyser
   position (see SUN/223 again). The effective analyser angle rotates twice
   as fast as the half-wave plate which is why there is a factor of 2 here. */
               phi = 2*wplate;

/* Rotate the Q,U values so that they refer to a reference direction
   parallel to the fixed analyser. */
               angle = 2*( *ipang + angrot - AST__DPIBY2 );
               cosval = cos( angle );
               sinval = sin( angle );
               qval = (*qin)*cosval + (*uin)*sinval;
               uval = (*uin)*cosval - (*qin)*sinval;

/* Add in the instrumental polarisation. This is assumed to be fixed in
   focal planee coords, which means it is also fixed with respect to the
   analyser. */
               ival = *iin;
               qval += ip_qi*ival;
               uval += ip_ui*ival;

/* Calculate the analysed intensity and store it in place of the I value.
   A phi value of zero corresponds to the fixed analyser (i.e. the new Q/U
   reference direction). Allow the angle to be scaled by some user-specified
   factor. This is to allow the investigation of other harmonics. */
               *iin = 0.5*( ival + qval*cos( 2*phi*angfac ) +
                                   uval*sin( 2*phi*angfac ) );

/* If producing the usuall 8Hz harmonic, optionally add in 2, 4 and 16 Hz
   components to the signal. */
               if( angfac == 1 ) {
                  if( amp2 != 0.0 ) *iin += amp2*ival*sin( phi/2 + phase2 );
                  if( amp4 != 0.0 ) *iin += amp4*ival*sin( phi + phase4 );
                  if( amp16 != 0.0 ) *iin += amp16*ival*sin( 4*phi + phase16 );
               }

            } else {
               *iin = VAL__BADD;
            }

/* Update pointers to the next I, Q and U time slice values. */
            iin += tstride;
            qin += tstride;
            uin += tstride;
         }

/* Update the pointers to the first I, Q and U time slice values for
   the next bolometer. */
         ipi0 += bstride;
         ipq0 += bstride;
         ipu0 += bstride;
      }
   }
}
Exemplo n.º 12
0
static void smf1_qual_map( void *job_data_ptr, int *status ) {
/*
*  Name:
*     smf1_qual_map

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

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

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

*/

/* Local Variables: */
   SmfQualMapData *pdata;
   size_t i1;
   size_t i2;
   size_t i;
   smf_qual_t *p1;
   unsigned char *p2;

/* 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 = (SmfQualMapData *) job_data_ptr;

   i1 = pdata->i1;
   i2 = pdata->i2;

   if( pdata->operation == 1 ){
      p1 = pdata->retval + i1;
      for( i = i1; i <= i2; i++) {
         *(p1++) = VAL__BADQ;
      }

   } else if( pdata->operation == 2 ){
      p1 = pdata->retval + i1;
      p2 = pdata->qmap + i1;
      for( i = i1; i <= i2; i++) {
         *(p1++) = *(p2++);
      }

   } else if( pdata->operation == 3 ){
      p1 = pdata->retval + i1;
      p2 = pdata->qmap + i1;
      for( i = i1; i <= i2; i++,p1++,p2++) {

/* Output buffer would be set to zero but it already has that value so do
   nothing. */
         if( *p2 == 0 ) {

/* This becomes a very laborious bitwise copy. */
         } else {

/* One to one mapping for TSERIES and MAP families. */
            if( pdata->lfamily == SMF__QFAM_TSERIES ||
                pdata->lfamily == SMF__QFAM_MAP ) {
               size_t k;
               for( k = 0; k < NDFBITS; k++ ) {
                  if( *p2 & pdata->ndfqval[k] ) *p1 |=  pdata->ndfqtoval[ k ];
               }

            } else if( pdata->lfamily == SMF__QFAM_TCOMP ) {
               size_t k;

/* This requires some guess work */
               for( k = 0; k < NDFBITS; k++ ) {
                  if( *p2 &  pdata->ndfqval[k] ) {
                     if(  pdata->ndfqtoval[k] & SMF__TCOMPQ_BAD ) {
                        *p1 |= (SMF__Q_BADB|SMF__Q_BADDA);
                     } else if( pdata->ndfqtoval[k] & SMF__TCOMPQ_ENDS ) {
                        *p1 |= (SMF__Q_PAD|SMF__Q_APOD);
                     } else if( pdata->ndfqtoval[k] & SMF__TCOMPQ_BLIP ) {
                        *p1 |= (SMF__Q_SPIKE | SMF__Q_JUMP | SMF__Q_FILT | SMF__Q_LOWAP | SMF__Q_BADEF);
                     } else if( pdata->ndfqtoval[k] & SMF__TCOMPQ_MATCH ) {
                        *p1 |= SMF__Q_COM;
                     } else if( pdata->ndfqtoval[k] & SMF__TCOMPQ_TEL ) {
                        *p1 |= SMF__Q_STAT;
                     } else {

/* just do the normal mapping */
                        *p1 |= pdata->ndfqtoval[k];
                     }
                  }
               }

            } else {
               *status = SAI__ERROR;
               errRep("", "Did not recognize quality family. "
                      "(Possible programming error)", status );
               break;
            }
         }
      }

   } else {
      *status = SAI__ERROR;
      errRepf( "", "smf1_qual_map: Invalid operation (%d) supplied.",
               status, pdata->operation );
   }
}
Exemplo n.º 13
0
static void smf1_fit_qui_job( void *job_data, int *status ) {
/*
*  Name:
*     smf1_fit_qui_job

*  Purpose:
*     Calculate I, Q and U for a block of bolometers.

*  Invocation:
*     void smf1_fit_qui_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
*        smfFitQUIJobData structure.
*     status = int * (Given and Returned)
*        Pointer to global status.

*  Description:
*     This routine calculate the I, Q and U values for each bolometer in
*     a block of bolometers. It runs within a thread instigated by
*     smf_fit_qui.

*/

/* Local Variables: */
   AstFrameSet *wcs;          /* WCS FrameSet for current time slice */
   AstMapping *g2s;           /* GRID to SKY mapping */
   AstMapping *s2f;           /* SKY to focal plane mapping */
   const JCMTState *allstates;/* Pointer to array of JCMTState structures */
   const JCMTState *state;    /* JCMTState info for current time slice */
   dim_t b1;                  /* First bolometer index */
   dim_t b2;                  /* Last bolometer index */
   dim_t box_size;            /* NFirst time slice in box */
   dim_t ibolo;               /* Bolometer index */
   dim_t ibox;
   dim_t ncol;
   dim_t nbolo;               /* Total number of bolometers */
   double *dat;               /* Pointer to start of input data values */
   double *din;               /* Pointer to input data array for bolo/time */
   double *ipi;               /* Pointer to output I array */
   double *ipq;               /* Pointer to output Q array */
   double *ipu;               /* Pointer to output U array */
   double *ipv;               /* Pointer to output weights array */
   double *pm;
   double *ps;
   double angle;              /* Phase angle for FFT */
   double angrot;             /* Angle from focal plane X axis to fixed analyser */
   double c1;
   double c2;
   double c4;
   double c8;
   double cosval;             /* Cos of angrot */
   double fit;
   double fx[2];              /* Focal plane X coord at bolometer and northern point*/
   double fy[2];              /* Focal plane Y coord at bolometer and northern point*/
   double gx;                 /* GRID X coord at bolometer */
   double gy;                 /* GRID Y coord at bolometer */
   double matrix[ NPAR*NPAR ];
   double paoff;              /* WPLATE value corresponding to POL_ANG=0.0 */
   double phi;                /* Angle from fixed analyser to effective analyser */
   double res;
   double s1;                 /* Sum of weighted cosine terms */
   double s2;                 /* Sum of weighted sine terms */
   double s4;
   double s8;
   double sinval;             /* Sin of angrot */
   double solution[ NPAR ];
   double sum1;               /* Sum of squared residuals */
   double sums[NSUM];         /* Sum of bolometer values */
   double sx[2];              /* SKY X coord at bolometer and northern point*/
   double sy[2];              /* SKY Y coord at bolometer and northern point*/
   double tr_angle;
   double twophi;
   double vector[ NPAR ];
   double wplate;             /* Angle from fixed analyser to have-wave plate */
   gsl_matrix_view gsl_m;
   gsl_vector_view gsl_b;
   gsl_vector_view gsl_x;
   int ipolcrd;               /* Reference direction for pol_ang */
   int nsum1;
   int pasign;                /* +1 or -1 indicating sense of POL_ANG value */
   smfFitQUIJobData *pdata;   /* Pointer to job data */
   smf_qual_t *qin;           /* Pointer to input quality array for bolo/time */
   smf_qual_t *qua;           /* Pointer to start of input quality values */

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

/* Begin an AST context */
   astBegin;

/* Create views of the matrix and vector buffers that can be used by GSL. */
   gsl_m = gsl_matrix_view_array( matrix, NPAR, NPAR );
   gsl_b = gsl_vector_view_array( vector, NPAR );
   gsl_x = gsl_vector_view_array( solution, NPAR );

/* Get a pointer to the job data, and then extract its contents into a
   set of local variables. */
   pdata = (smfFitQUIJobData *) job_data;

   b1 = pdata->b1;
   b2 = pdata->b2;
   nbolo = pdata->nbolo;
   ncol = pdata->ncol;

   dat = pdata->dat + b1;
   qua = pdata->qua + b1;
   allstates = pdata->allstates;

   ipi = pdata->ipi ? pdata->ipi + b1 : NULL;
   ipq = pdata->ipq + b1;
   ipu = pdata->ipu + b1;
   ipv = pdata->ipv + b1;

   ipolcrd = pdata->ipolcrd;
   pasign = pdata->pasign;
   paoff = pdata->paoff;
   angrot = pdata->angrot;
   box_size = pdata->box_size;

   wcs = pdata->wcs;
   if( wcs ) {
      astLock( wcs, 0 );

/* Get the mapping from GRID to SKY. */
      g2s = astSimplify( astGetMapping( wcs, AST__BASE, AST__CURRENT ));

/* Get the mapping from SKY to focal plane (x,y) (the index of the FPLANE
   Frame is fixed at 3 by file sc2ast.c). */
      s2f = astSimplify( astGetMapping( wcs, AST__CURRENT, 3 ) );

   } else{
      g2s = s2f = NULL;
   }

/* Check we have something to do. */
   if( b1 < nbolo && *status == SAI__OK ) {

/* Loop round all bolometers to be processed by this thread. */
      for( ibolo = b1; ibolo <= b2; ibolo++,qua++,dat++ ) {

/* If the returned Stokes parameters are to be with respect to Tracking
   North, get the angle from tracking north at the current bolometer to
   focal plane Y, measured positive in the sense of rotation from focal
   plane Y to focal plane X (note this angle may change across the focal
   plane due to focal plane distortion). Otherwise, use zero. */
         if( pdata->wcs ) {

/* Get the grid coords of the current bolometer, and transform them to SKY
   coordinates using the FrameSet. */
            gx = ibolo % ncol + 1;
            gy = ibolo / ncol + 1;
            astTran2( g2s, 1, &gx, &gy, 1, sx, sy );

/* Increment the sky position slightly to the north. */
            sx[ 1 ] = sx[ 0 ];
            sy[ 1 ] = sy[ 0 ] + 1.0E-6;

/* Transform both sky positions into focal plane coords. */
            astTran2( s2f, 2, sx, sy, 1, fx, fy );

/* Get the angle from north to focal plane Y, measured positive in the
   sense of rotation from focal plane Y to focal plane X. */
            if( fx[0] != VAL__BADD && fy[0] != VAL__BADD &&
                fx[1] != VAL__BADD && fy[1] != VAL__BADD ) {
               tr_angle = atan2( fx[0] - fx[1], fy[1] - fy[0] );
            } else {
               tr_angle = VAL__BADD;
            }

         } else {
            tr_angle = 0.0;
         }

/* If the whole bolometer is bad, put bad values into the outputs. */
         if( *qua & SMF__Q_BADB || tr_angle == VAL__BADD ) {
            if( ipi ) *(ipi++) = VAL__BADD;
            *(ipq++) = VAL__BADD;
            *(ipu++) = VAL__BADD;
            *(ipv++) = VAL__BADD;

/* If the bolometer is good, calculate and store the output i, q and u
   values. */
         } else {

/* Initialise pointers to the first input data value, quality value and
   state info to be used in the current fitting box. */
            din = dat;
            qin = qua;
            state = allstates;

/* Form the sums needed to calculate the best fit Q, U and I. This
   involves looping over all input samples that fall within the fitting box
   centred on the current output sample. The 44 sums are stored in the
   "sums" array. Initialise it to hold zeros.  */
            memset( sums, 0, NSUM*sizeof(*sums) );
            for( ibox = 0; ibox <  box_size; ibox++,state++ ) {

/* Get the POL_ANG value for this time slice. */
               angle = state->pol_ang;

/* Check the input sample has not been flagged during cleaning and is
   not bad. */
               if( !( *qin & SMF__Q_FIT ) && *din != VAL__BADD &&
                   angle != VAL__BADD ) {

/* Following SUN/223 (section "Single-beam polarimetry"/"The Polarimeter"),
   get the angle from the fixed analyser to the half-waveplate axis, in radians.
   Positive rotation is from focal plane axis 1 (x) to focal plane axis 2 (y).

   Not sure about the sign of tcs_az/tr_ang at the moment so do not use them
   yet. */
                  wplate = 0.0;
                  if( ipolcrd == 0 ) {
                     wplate = pasign*angle + paoff;

                  } else if( *status == SAI__OK ) {
                     *status = SAI__ERROR;
                     errRepf( "", "smf_fit_qui: currently only POL_CRD = "
                              "FPLANE is supported.", status );
                  }

/*
                     if( ipolcrd == 1 ) {
                        wplate += state->tcs_az_ang;
                     } else if( ipolcrd == 2 ) {
                        wplate += state->tcs_tr_ang;
                     }
*/

/* Get the angle from the fixed analyser to the effective analyser
   position (see SUN/223 again). The effective analyser angle rotates twice
   as fast as the half-wave plate which is why there is a factor of 2 here. */
                  phi = 2*wplate;
                  twophi = 2*phi;

/* Form the trig values needed for the sums. */
                  s8 = sin( 2*twophi );
                  c8 = cos( 2*twophi );
                  s4 = sin( twophi );
                  c4 = cos( twophi );
                  s2 = sin( phi );
                  c2 = cos( phi );
                  s1 = sin( wplate );
                  c1 = cos( wplate );

/* Update the sums. The order of the following lines define the index
   within "sums" at which each sum is stored. */
                  ps = sums;
                  *(ps++) += s4*s4;
                  *(ps++) += s4*c4;
                  *(ps++) += s4*s2;
                  *(ps++) += s4*c2;
                  *(ps++) += s4*s1;
                  *(ps++) += s4*c1;
                  *(ps++) += s4*ibox;
                  *(ps++) += s4;
                  *(ps++) += s4*(*din);

                  *(ps++) += s2*c4;
                  *(ps++) += s2*s2;
                  *(ps++) += s2*c2;
                  *(ps++) += s2*s1;
                  *(ps++) += s2*c1;
                  *(ps++) += s2*ibox;
                  *(ps++) += s2;
                  *(ps++) += s2*(*din);

                  *(ps++) += s1*c4;
                  *(ps++) += s1*c2;
                  *(ps++) += s1*s1;
                  *(ps++) += s1*c1;
                  *(ps++) += s1*ibox;
                  *(ps++) += s1;
                  *(ps++) += s1*(*din);

                  *(ps++) += c4*c4;
                  *(ps++) += c4*c2;
                  *(ps++) += c4*c1;
                  *(ps++) += c4*ibox;
                  *(ps++) += c4;
                  *(ps++) += c4*(*din);

                  *(ps++) += c2*c2;
                  *(ps++) += c2*c1;
                  *(ps++) += c2*ibox;
                  *(ps++) += c2;
                  *(ps++) += c2*(*din);

                  *(ps++) += c1*c1;
                  *(ps++) += c1*ibox;
                  *(ps++) += c1;
                  *(ps++) += c1*(*din);

                  *(ps++) += ibox*ibox;
                  *(ps++) += ibox;
                  *(ps++) += ibox*(*din);

                  *(ps++) += 1.0;
                  *(ps++) += *din;

                  *(ps++) += s4*s8;
                  *(ps++) += s4*c8;

                  *(ps++) += s2*s8;
                  *(ps++) += s2*c8;

                  *(ps++) += s1*s8;
                  *(ps++) += s1*c8;

                  *(ps++) += s8*c4;
                  *(ps++) += s8*c2;
                  *(ps++) += s8*c1;
                  *(ps++) += s8*ibox;
                  *(ps++) += s8;
                  *(ps++) += s8*(*din);
                  *(ps++) += s8*s8;
                  *(ps++) += s8*c8;

                  *(ps++) += c4*c8;

                  *(ps++) += c2*c8;

                  *(ps++) += c1*c8;

                  *(ps++) += c8*ibox;
                  *(ps++) += c8;
                  *(ps++) += c8*(*din);
                  *(ps++) += c8*c8;
               }

               din += nbolo;
               qin += nbolo;

            }

/* Now find the parameters of the best fit. First check that there were
   sufficient good samples in the fitting box. */
            if( sums[42] > 0.8*box_size ) {

/* Copy the sums to the correct elements of the 10x10 matrix. */
               pm = matrix;
               *(pm++) = sums[ 0 ];
               *(pm++) = sums[ 1 ];
               *(pm++) = sums[ 2 ];
               *(pm++) = sums[ 3 ];
               *(pm++) = sums[ 4 ];
               *(pm++) = sums[ 5 ];
               *(pm++) = sums[ 6 ];
               *(pm++) = sums[ 7 ];
               *(pm++) = sums[ 44 ];
               *(pm++) = sums[ 45 ];


               *(pm++) = sums[ 1 ];
               *(pm++) = sums[ 24 ];
               *(pm++) = sums[ 9 ];
               *(pm++) = sums[ 25 ];
               *(pm++) = sums[ 17 ];
               *(pm++) = sums[ 26 ];
               *(pm++) = sums[ 27 ];
               *(pm++) = sums[ 28 ];
               *(pm++) = sums[ 50 ];
               *(pm++) = sums[ 58 ];

               *(pm++) = sums[ 2 ];
               *(pm++) = sums[ 9 ];
               *(pm++) = sums[ 10 ];
               *(pm++) = sums[ 11 ];
               *(pm++) = sums[ 12 ];
               *(pm++) = sums[ 13 ];
               *(pm++) = sums[ 14 ];
               *(pm++) = sums[ 15 ];
               *(pm++) = sums[ 46 ];
               *(pm++) = sums[ 47 ];

               *(pm++) = sums[ 3 ];
               *(pm++) = sums[ 25 ];
               *(pm++) = sums[ 11 ];
               *(pm++) = sums[ 30 ];
               *(pm++) = sums[ 18 ];
               *(pm++) = sums[ 31 ];
               *(pm++) = sums[ 32 ];
               *(pm++) = sums[ 33 ];
               *(pm++) = sums[ 51 ];
               *(pm++) = sums[ 59 ];

               *(pm++) = sums[ 4 ];
               *(pm++) = sums[ 17 ];
               *(pm++) = sums[ 12 ];
               *(pm++) = sums[ 18 ];
               *(pm++) = sums[ 19 ];
               *(pm++) = sums[ 20 ];
               *(pm++) = sums[ 21 ];
               *(pm++) = sums[ 22 ];
               *(pm++) = sums[ 48 ];
               *(pm++) = sums[ 49 ];

               *(pm++) = sums[ 5 ];
               *(pm++) = sums[ 26 ];
               *(pm++) = sums[ 13 ];
               *(pm++) = sums[ 31 ];
               *(pm++) = sums[ 20 ];
               *(pm++) = sums[ 35 ];
               *(pm++) = sums[ 36 ];
               *(pm++) = sums[ 37 ];
               *(pm++) = sums[ 52 ];
               *(pm++) = sums[ 60 ];

               *(pm++) = sums[ 6 ];
               *(pm++) = sums[ 27 ];
               *(pm++) = sums[ 14 ];
               *(pm++) = sums[ 32 ];
               *(pm++) = sums[ 21 ];
               *(pm++) = sums[ 36 ];
               *(pm++) = sums[ 39 ];
               *(pm++) = sums[ 40 ];
               *(pm++) = sums[ 53 ];
               *(pm++) = sums[ 61 ];

               *(pm++) = sums[ 7 ];
               *(pm++) = sums[ 28 ];
               *(pm++) = sums[ 15 ];
               *(pm++) = sums[ 33 ];
               *(pm++) = sums[ 22 ];
               *(pm++) = sums[ 37 ];
               *(pm++) = sums[ 40 ];
               *(pm++) = sums[ 42 ];
               *(pm++) = sums[ 54 ];
               *(pm++) = sums[ 62 ];

               *(pm++) = sums[ 44 ];
               *(pm++) = sums[ 50 ];
               *(pm++) = sums[ 46 ];
               *(pm++) = sums[ 51 ];
               *(pm++) = sums[ 48 ];
               *(pm++) = sums[ 52 ];
               *(pm++) = sums[ 53 ];
               *(pm++) = sums[ 54 ];
               *(pm++) = sums[ 56 ];
               *(pm++) = sums[ 57 ];

               *(pm++) = sums[ 45 ];
               *(pm++) = sums[ 58 ];
               *(pm++) = sums[ 47 ];
               *(pm++) = sums[ 59 ];
               *(pm++) = sums[ 49 ];
               *(pm++) = sums[ 60 ];
               *(pm++) = sums[ 61 ];
               *(pm++) = sums[ 62 ];
               *(pm++) = sums[ 57 ];
               *(pm++) = sums[ 64 ];

/* Copy the remaining sums to the correct elements of the 8 vector. */
               pm = vector;
               *(pm++) = sums[ 8 ];
               *(pm++) = sums[ 29 ];
               *(pm++) = sums[ 16 ];
               *(pm++) = sums[ 34 ];
               *(pm++) = sums[ 23 ];
               *(pm++) = sums[ 38 ];
               *(pm++) = sums[ 41 ];
               *(pm++) = sums[ 43 ];
               *(pm++) = sums[ 55 ];
               *(pm++) = sums[ 63 ];

/* Find the solution to the 10x10 set of linear equations. The matrix is
   symmetric and positive-definite so use Cholesky decomposition.  */
               memset( solution, 0, NPAR*sizeof(*solution) );
               gsl_linalg_cholesky_decomp( &gsl_m.matrix );
               gsl_linalg_cholesky_solve( &gsl_m.matrix, &gsl_b.vector,
                                          &gsl_x.vector );

/* Modify Q and U so they use the requested reference direction, and store in
   the output arrays. */
               cosval = cos( 2*( angrot - tr_angle ) );
               sinval = sin( 2*( angrot - tr_angle ) );
               *(ipq++) = 2*( -solution[ 1 ]*cosval + solution[ 0 ]*sinval );
               *(ipu++) = 2*( -solution[ 1 ]*sinval - solution[ 0 ]*cosval );

/* Store the correspoinding I value. */
               if( ipi ) *(ipi++) = solution[ 6 ]*box_size + 2*solution[ 7 ];

/* Loop over the data again in the same way to calculate the variance of the
   residuals between the above fit and the supplied data. */
               din = dat;
               qin = qua;
               state = allstates;

               sum1 = 0.0;
               nsum1 = 0;

               for( ibox = 0; ibox <  box_size; ibox++,state++ ) {
                  angle = state->pol_ang;

                  if( !( *qin & SMF__Q_FIT ) && *din != VAL__BADD &&
                        angle != VAL__BADD ) {
                     wplate = pasign*angle + paoff;
/*
                        if( ipolcrd == 1 ) {
                           wplate += state->tcs_az_ang;
                        } else if( ipolcrd == 2 ) {
                           wplate += state->tcs_tr_ang;
                        }
*/
                     phi = 2*wplate;
                     twophi = 2*phi;

                     s8 = sin( 2*twophi );
                     c8 = cos( 2*twophi );
                     s4 = sin( twophi );
                     c4 = cos( twophi );
                     s2 = sin( phi );
                     c2 = cos( phi );
                     s1 = sin( wplate );
                     c1 = cos( wplate );

                     fit = solution[0]*s4 +
                           solution[1]*c4 +
                           solution[2]*s2 +
                           solution[3]*c2 +
                           solution[4]*s1 +
                           solution[5]*c1 +
                           solution[6]*ibox +
                           solution[7] +
                           solution[8]*s8 +
                           solution[9]*c8;

                     res = *din - fit;

                     sum1 += res*res;
                     nsum1++;
                  }

                  din += nbolo;
                  qin += nbolo;
               }

/* Calculate the variance of the residuals, and then scale it to get the
   notional variance for the returned Q,. U and I values. The scaling
   factor is determined emprically to get reasonable agreement between these
   notional variances and the noise actually seen in the Q and U values
   for 10 test observations. The reason for storing these as Q/U variances
   rather than as a weights component in the SMURF extension is so that
   makemap can pick them up easily and use them to initialise the NOI
   model, which is used for weighting the bolometer data when forming the
   COM model on the first iteration. */
               *(ipv++) = 0.0253*sum1/nsum1;

/* Store bad values if there were too few good samples in the fitting
   box. */
            } else {
               if( ipi ) *(ipi++) = VAL__BADD;
               *(ipq++) = VAL__BADD;
               *(ipu++) = VAL__BADD;
               *(ipv++) = VAL__BADD;
            }
         }
      }
   }

   if( wcs ) {
      g2s = astAnnul( g2s );
      s2f = astAnnul( s2f );
      astUnlock( wcs, 1 );
   }

/* End the AST context */
   astEnd;
}
Exemplo n.º 14
0
int smf_correct_extinction(ThrWorkForce *wf, smfData *data, smf_tausrc tausrc, smf_extmeth method,
                            AstKeyMap * extpars, double tau, double *allextcorr,
                            double **wvmtaucache, int *status) {

  /* Local variables */
  int allquick = 0;        /* Is the extinction for all bolometers the same? */
  double amstart = VAL__BADD; /* Airmass at start */
  double amend = VAL__BADD;   /* Airmass at end */
  double elstart = VAL__BADD; /* Elevation at start (radians) */
  double elend = VAL__BADD;/* Elevation at end (radians) */
  smfHead *hdr = NULL;     /* Pointer to full header struct */
  double *indata = NULL;   /* Pointer to data array */
  int isTordered;          /* data order of input data */
  int lbnd[2];             /* Lower bound */
  size_t ndims;            /* Number of dimensions in input data */
  dim_t nframes = 0;       /* Number of frames */
  dim_t npts = 0;          /* Number of data points */
  dim_t nx = 0;            /* # pixels in x-direction */
  dim_t ny = 0;            /* # pixels in y-direction */
  int ubnd[2];             /* Upper bound */
  double *vardata = NULL;  /* Pointer to variance array */
  double * wvmtau = NULL;  /* WVM tau (smoothed or not) for these data */
  int nw;                  /* Number of worker threads */
  int iw;                  /* Thread index */
  SmfCorrectExtinctionData *job_data = NULL;  /* Array of job descriptions */
  SmfCorrectExtinctionData *pdata;   /* Pointer to next job description */
  size_t framestep;         /* Number of frames per thread */

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

  /* If no correction requested, return */
  if( method==SMF__EXTMETH_NONE ) {
    msgOutif(MSG__VERB, "", FUNC_NAME ": Extinction method=none, returning",
             status );
    return allquick;
  }

  /* If no opacity monitor specified generate bad status */
  if( tausrc==SMF__TAUSRC_NULL ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": No extinction monitor specified",
            status );
    return allquick;
  }

  if( smf_history_check( data, FUNC_NAME, status) ) {
    /* If caller not requesting allextcorr fail here */
    if( !allextcorr ) {
      msgSetc("F", FUNC_NAME);
      msgOutif(MSG__VERB," ",
               "^F has already been run on these data, returning to caller",
               status);
      return allquick;
    }
  }

  /* Acquire the data order */
  isTordered = data->isTordered;

  /* make sure we have a header */
  hdr = data->hdr;
  if( hdr == NULL ) {
    *status = SAI__ERROR;
    errRep( FUNC_NAME, "Input data has no header", status);
    return allquick;
  }

  /* Do we have 2-D image data? */
  ndims = data->ndims;
  if (ndims == 2) {
    nframes = 1;
    nx = (data->dims)[0];
    ny = (data->dims)[1];
    npts = nx*ny;
  } else {
    /* this routine will also check for dimensionality */
    smf_get_dims( data, &nx, &ny, &npts, &nframes, NULL, NULL, NULL, status );
  }

  /* Tell user we're correcting for extinction */
  msgOutif(MSG__VERB," ",
           "Correcting for extinction.", status);

  /* Should check data type for double if not allextcorr case */
  if( !allextcorr ) {
    if (!smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status)) return allquick;
  }

  /* Check that we're not trying to use the WVM for 2-D data */
  if ( ndims == 2 && tausrc == SMF__TAUSRC_WVMRAW ) {
    if ( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "Method WVMRaw can not be used on 2-D image data", status );
      return allquick;
    }
  } else if (ndims < 2 || ndims > 3) {
    if (*status == SAI__OK) {
      *status = SAI__ERROR;
      errRepf( FUNC_NAME, "Can not extinction correct data with %zd dimension(s)", status,
              ndims );
      return allquick;
    }
  }

  if (tausrc == SMF__TAUSRC_WVMRAW) {
    size_t ntotaltau = 0;
    size_t ngoodtau = 0;
    /* calculate WVM unless we have external values */
    if (wvmtaucache && *wvmtaucache) {
      wvmtau = *wvmtaucache;
      smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
      msgOutiff( MSG__VERB, "", "Using cached WVM data for extinction correction of ^FILE",
                 status);
    } else {
      smf_calc_smoothedwvm( wf, NULL, data, extpars, &wvmtau, &ntotaltau,
                            &ngoodtau, status );
      smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
      msgOutiff( MSG__VERB, "", "Using WVM mode for extinction correction of ^FILE"
                 " %.0f %% of WVM data are present", status,
                 (double)(100.0*(double)ngoodtau/(double)ntotaltau) );
    }
  }

  /* Check auto mode */
  if (tausrc == SMF__TAUSRC_AUTO && *status == SAI__OK) {
    smf_smfFile_msg( data->file, "FILE", 1, "<unknown>" );

    if (ndims == 2) {
      /* have to use CSO mode */
      tausrc = SMF__TAUSRC_CSOTAU;
    } else if (ndims == 3) {
      /* Calculate the WVM tau data and see if we have enough good data */
      size_t ngoodtau = 0;
      size_t ntotaltau = 0;
      double percentgood = 0.0;

      if (wvmtaucache && *wvmtaucache) {
        wvmtau = *wvmtaucache;
        tausrc = SMF__TAUSRC_WVMRAW;
        smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
        msgOutiff( MSG__VERB, "", "Using cached WVM data for extinction correction of ^FILE",
                   status );
      } else {
        smf_calc_smoothedwvm( wf, NULL, data, extpars, &wvmtau, &ntotaltau,
                              &ngoodtau, status );
        percentgood = 100.0 * ((double)ngoodtau / (double)ntotaltau);

        if ( percentgood > 80.0) {
          tausrc = SMF__TAUSRC_WVMRAW;
          msgOutiff( MSG__VERB, "", "Selecting WVM mode for extinction correction of ^FILE."
                     " %.0f %% of WVM data are present", status, percentgood );
        } else {
          tausrc = SMF__TAUSRC_CSOTAU;
          if (wvmtau) wvmtau = astFree( wvmtau );
        }
      }
    }
    if (tausrc == SMF__TAUSRC_CSOTAU) {
      msgOutiff( MSG__VERB, "", "Selecting CSO mode for extinction correction of ^FILE", status );
    } else if (tausrc == SMF__TAUSRC_WVMRAW) {
      /* Dealt with this above */
    } else {
      /* oops. Fall back position */
      tausrc = SMF__TAUSRC_CSOTAU;
      msgOutiff( MSG__VERB, "", "Selecting CSO mode as unexpected fallback for extinction correction of ^FILE", status );
    }
  }

  /* If we have a CSO Tau then convert it to the current filter. This will also
     convert bad values to a value derived from the header if appropriate. */
  if ( tausrc == SMF__TAUSRC_CSOTAU ) {
    tau = smf_cso2filt_tau( hdr, tau, extpars, status );
    /* The tau source is now a real tau */
    tausrc = SMF__TAUSRC_TAU;
  }

  /* Find the airmass range for this data */
  smf_find_airmass_interval( hdr, &amstart, &amend, &elstart, &elend, status );
  if (*status == SAI__OK && (amstart == VAL__BADD || amend == VAL__BADD)) {
    *status = SAI__ERROR;
    errRep( "", "No good airmass values found in JCMTSTATE structure for these data",
            status );
  }

  /* if we are not doing WVM correction but are in adaptive mode we can determine
     whether or not we will have to use full or single mode just by looking at the
     airmass data. */
  if (ndims == 3 && tausrc != SMF__TAUSRC_WVMRAW && method == SMF__EXTMETH_ADAPT) {
    /* first and last is a good approximation given that most SCUBA-2 files will only
       be a minute duration. */
    double refel;
    double refam;

    /* only need to examine the largest airmass */
    if (amstart > amend) {
      refam = amstart;
      refel = elstart;
    } else {
      refam = amend;
      refel = elend;
    }

    /* and choose a correction method */
    if (is_large_delta_atau( refam, refel, tau, status) ) {
      method = SMF__EXTMETH_FULL;
      msgOutiff(MSG__DEBUG, " ",
               "Adaptive extinction algorithm selected per-bolometer airmass value "
               "per time slice (am=%g, tau=%g)", status, refam, tau);
    } else {
      msgOutiff(MSG__DEBUG, " ",
               "Adaptive extinction algorithm selected single airmass value per time slice"
               " (am=%g, tau=%g)", status, refam, tau);
      method = SMF__EXTMETH_SINGLE;
    }

  }

  /* Assign pointer to input data array if status is good */
  if ( *status == SAI__OK ) {
    indata = (data->pntr)[0];
    vardata = (data->pntr)[1];
  }

  /* Jump to the cleanup section if status is bad by this point
     since we need to free memory */
  if (*status != SAI__OK) goto CLEANUP;

  /* Array bounds for astTranGrid call */
  lbnd[0] = 1;
  lbnd[1] = 1;
  ubnd[0] = nx;
  ubnd[1] = ny;

  /* Unlock the AST objects in the smfData so that the worker threads can
     lock them. */
  smf_lock_data( data, 0, status );

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

  /* Find how many frames to process in each worker thread. */
  framestep = nframes/nw;
  if( framestep == 0 ) {
    framestep = 1;
    nw = nframes;
  }

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

      pdata->nframes = nframes;
      pdata->npts = npts;
      pdata->allextcorr = allextcorr;
      pdata->indata = indata;
      pdata->tau = tau;
      pdata->vardata = vardata;
      pdata->wvmtau = wvmtau;
      pdata->amstart = amstart;
      pdata->amfirst = amstart + ( amend - amstart )*pdata->f1/( nframes - 1 );
      pdata->lbnd = lbnd;
      pdata->ubnd = ubnd;
      pdata->isTordered = isTordered;
      pdata->ndims = ndims;
      pdata->data = data;
      pdata->hdr = hdr;
      pdata->method = method;
      pdata->tausrc = tausrc;

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

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

    /* Record if all time slices used a single air mass. */
    allquick = 1;
    for( iw = 0; iw < nw; iw++ ) {
      pdata = job_data + iw;
      if( ! pdata->allquick ) {
        allquick = 0;
        break;
      }
    }

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

  /* Lock the AST objects in the smfData for use by this thread. */
  smf_lock_data( data, 1, status );

  /* Add history entry if !allextcorr */
  if( (*status == SAI__OK) && !allextcorr ) {
    smf_history_add( data, FUNC_NAME, status);
  }

 CLEANUP:
  if (wvmtaucache) {
    if (!*wvmtaucache) {
      *wvmtaucache = wvmtau;
    }
  } else {
    wvmtau = astFree( wvmtau );
  }

  return allquick;
}
Exemplo n.º 15
0
static void smf1_update_quality( void *job_data_ptr, int *status ) {
/*
*  Name:
*     smf1_update_quality

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

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

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

*/

/* Local Variables: */
   SmfUpdateQualityData *pdata;
   const int *p4;
   double *p1;
   int *p3;
   size_t b1;
   size_t b2;
   size_t i1;
   size_t i2;
   size_t i;
   smf_qual_t *p2;

/* 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 = (SmfUpdateQualityData *) job_data_ptr;

   i1 = pdata->i1;
   i2 = pdata->i2;
   b1 = pdata->b1;
   b2 = pdata->b2;

   if( pdata->operation == 1 ){
      p1 = pdata->ddata + i1;
      p2 = pdata->qual + i1;
      for( i = i1; i <= i2; i++,p2++) {
         if( *(p1++) == VAL__BADD ) *p2 |= SMF__Q_BADDA;
      }

   } else if( pdata->operation == 2 ){
      p3 = pdata->idata + i1;
      p2 = pdata->qual + i1;
      for( i = i1; i <= i2; i++,p2++) {
         if( *(p3++) == VAL__BADI ) *p2 |= SMF__Q_BADDA;
      }

   } else if( pdata->operation == 3 ){
      dim_t badthresh = pdata->badthresh;
      dim_t j;
      dim_t nbad;
      dim_t ntslice = pdata->ntslice;
      int syncbad = pdata->syncbad;
      size_t bstride = pdata->bstride;
      size_t tstride = pdata->tstride;
      smf_qual_t addqual = pdata->addqual;

/* Loop over detector */
      p1 = pdata->ddata;
      p2 = pdata->qual;
      p3 = pdata->idata;
      p4 = pdata->badmask;

      for( i = b1; i <= b2; i++ ) {
         dim_t c = bstride * i;  /* constant offset for this bolometer */
         int isbad = 0;

/* preset bad flag based on mask (if defined) */
         if( p4 && p4[ i ] == VAL__BADI) isbad = 1;

/* Update badmask if badfrac specified */
         if( ( badthresh < ntslice ) && !isbad ) {
            nbad = 0;

/* Loop over samples and count the number with SMF__Q_BADDA set. Note that
   if syncbad is false we also check the data array. */
            for( j = 0; j < ntslice; j++ ) {
               size_t ind = tstride*j + c;
               if( p2[ ind ] & SMF__Q_BADDA ) {
                  nbad++;
               } else if( !syncbad ) {
                  if( p3 && p3[ ind ] == VAL__BADI) {
                     nbad++;
                  } else if( p1 && p1[ ind ] == VAL__BADD) {
                     nbad++;
                  }
               }
            }
            if( nbad > badthresh ) isbad = 1;
         }

/* Now apply the badmask */
         if( isbad ) {
            smf_qual_t outqual = SMF__Q_BADB | addqual;
            for( j = 0; j < ntslice; j++ ) {
               p2[ tstride*j + c ] |= outqual;
            }
         }
      }

   } else {
      *status = SAI__ERROR;
      errRepf( "", "smf1_update_quality: Invalid operation (%d) supplied.",
               status, pdata->operation );
   }
}
Exemplo n.º 16
0
int smf_correct_extinction(ThrWorkForce *wf, smfData *data, smf_tausrc *thetausrc, smf_extmeth method,
                            AstKeyMap * extpars, double tau, double *allextcorr,
                            double **wvmtaucache, int *status) {

  /* Local variables */
  int allquick = 0;        /* Is the extinction for all bolometers the same? */
  double amstart = VAL__BADD; /* Airmass at start */
  double amend = VAL__BADD;   /* Airmass at end */
  double elstart = VAL__BADD; /* Elevation at start (radians) */
  double elend = VAL__BADD;/* Elevation at end (radians) */
  smfHead *hdr = NULL;     /* Pointer to full header struct */
  double *indata = NULL;   /* Pointer to data array */
  int isTordered;          /* data order of input data */
  int lbnd[2];             /* Lower bound */
  size_t ndims;            /* Number of dimensions in input data */
  dim_t nframes = 0;       /* Number of frames */
  dim_t npts = 0;          /* Number of data points */
  dim_t nx = 0;            /* # pixels in x-direction */
  dim_t ny = 0;            /* # pixels in y-direction */
  smf_tausrc tausrc;       /* Local copy of tausrc value */
  int ubnd[2];             /* Upper bound */
  double *vardata = NULL;  /* Pointer to variance array */
  double * wvmtau = NULL;  /* WVM tau (smoothed or not) for these data */
  int nw;                  /* Number of worker threads */
  int iw;                  /* Thread index */
  SmfCorrectExtinctionData *job_data = NULL;  /* Array of job descriptions */
  SmfCorrectExtinctionData *pdata;   /* Pointer to next job description */
  size_t framestep;         /* Number of frames per thread */

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

  /* If no correction requested, return */
  if( method==SMF__EXTMETH_NONE ) {
    msgOutif(MSG__VERB, "", FUNC_NAME ": Extinction method=none, returning",
             status );
    return allquick;
  }

  if ( ! thetausrc ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": Must supply a thetausrc argument. Possible programming error.",
            status );
    return allquick;
  }

  /* Use a local value for tausrc as we update it in this routine. In particular,
     CSOFIT becomes WVMRAW and this would be confusing to the caller */
  tausrc = *thetausrc;

  /* If no opacity monitor specified generate bad status */
  if( tausrc==SMF__TAUSRC_NULL ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": No source of opacity information could be determined",
            status );
    return allquick;
  }

  if( smf_history_check( data, FUNC_NAME, status) ) {
    /* If caller not requesting allextcorr fail here */
    if( !allextcorr ) {
      msgSetc("F", FUNC_NAME);
      msgOutif(MSG__VERB," ",
               "^F has already been run on these data, returning to caller",
               status);
      return allquick;
    }
  }

  /* Acquire the data order */
  isTordered = data->isTordered;

  /* make sure we have a header */
  hdr = data->hdr;
  if( hdr == NULL ) {
    *status = SAI__ERROR;
    errRep( FUNC_NAME, "Input data has no header", status);
    return allquick;
  }

  /* Do we have 2-D image data? */
  ndims = data->ndims;
  if (ndims == 2) {
    nframes = 1;
    nx = (data->dims)[0];
    ny = (data->dims)[1];
    npts = nx*ny;
  } else {
    /* this routine will also check for dimensionality */
    smf_get_dims( data, &nx, &ny, &npts, &nframes, NULL, NULL, NULL, status );
  }

  /* Tell user we're correcting for extinction */
  msgOutif(MSG__VERB," ",
           "Correcting for extinction.", status);

  /* Should check data type for double if not allextcorr case */
  if( !allextcorr ) {
    if (!smf_dtype_check_fatal( data, NULL, SMF__DOUBLE, status)) return allquick;
  }

  /* Check that we're not trying to use the WVM for 2-D data */
  if ( ndims == 2 && tausrc == SMF__TAUSRC_WVMRAW ) {
    if ( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "Method WVMRaw can not be used on 2-D image data", status );
      return allquick;
    }
  } else if (ndims == 2 && tausrc == SMF__TAUSRC_CSOFIT ) {
    /* This is CSOTAU mode with the value calculated from the fits. We have to either
       calculate the value here based on the FITS headers or we have to ensure that
       when this mode triggers we've been given the fallback tau derived in this manner.
       Revisit this as the code develops (we do not want to be reading fits multiple times).
    */
    if (*status == SAI__OK) {
      *status = SAI__ERROR;
      errRep( FUNC_NAME, "Method CSOFIT not yet supported on 2-D image data", status );
      return allquick;
    }
  } else if (ndims < 2 || ndims > 3) {
    if (*status == SAI__OK) {
      *status = SAI__ERROR;
      errRepf( FUNC_NAME, "Can not extinction correct data with %zd dimension(s)", status,
              ndims );
      return allquick;
    }
  }

  /* if we are WVMRAW, CSOFIT or AUTO and we have a cache we should always use it since
     we assume it was filled in properly the previous time. */
  if (wvmtaucache && *wvmtaucache &&
      (tausrc == SMF__TAUSRC_WVMRAW ||
       tausrc == SMF__TAUSRC_AUTO ||
       tausrc == SMF__TAUSRC_CSOFIT)) {
    wvmtau = *wvmtaucache;
    smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
    msgOutiff( MSG__VERB, "", "Using cached high resolution data for extinction correction of ^FILE",
               status);
    tausrc = SMF__TAUSRC_WVMRAW; /* We are now WVMRAW as we have the data */

    /* Assume that we only do not know the provenance if in AUTO mode */
    if (tausrc == SMF__TAUSRC_AUTO) *thetausrc = SMF__TAUSRC_CACHED;
  }

  if (!wvmtau && tausrc == SMF__TAUSRC_WVMRAW) {
    size_t ntotaltau = 0;
    size_t ngoodtau = 0;
    smf_calc_smoothedwvm( wf, NULL, data, extpars, &wvmtau, &ntotaltau,
                          &ngoodtau, status );
    smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
    msgOutiff( MSG__VERB, "", "Using WVM mode for extinction correction of ^FILE"
               " %.0f %% of WVM data are present", status,
               (double)(100.0*(double)ngoodtau/(double)ntotaltau) );
  }

  if (*status == SAI__OK && tausrc == SMF__TAUSRC_CSOFIT) {
    /* Calculate the fit but we can use the same cache that WVM uses */
    size_t nframes = 0;
    smf_calc_csofit( data, extpars, &wvmtau, &nframes, status );
    smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
    msgOutiff( MSG__QUIET, "", "Using CSO fits for extinction correction of ^FILE",
               status );
    /* Rebrand as WVM data from this point on */
    tausrc = SMF__TAUSRC_WVMRAW;
  }

  /* AUTO mode logic */
  /*
   * Default position is to use WVM data but we have two caveats
   *
   *  1. Was this observation done during a period where the WVM has been flagged as unreliable?
   *  2. If the WVM is nominally okay, do we have sufficient good data during this period?
   *
   * If the WVM should not be used we fallback to seeing if we have a fit available for this
   * night from the CSO data.
   *
   * If we do not have a reliable WVM or CSO fit then we fallback to using a fixed CSO number
   * from the header.
   *
   * This final fallback position is unfortunate as it is highly likely that this is not a reliable
   * number if we have fits for every night of observing (we have no information on whether a missing
   * fit indicates the CSO was too unstable to use or whether it means we simply haven't got to it
   * yet).
   *
   */

  /* Check auto mode */
  if (tausrc == SMF__TAUSRC_AUTO && *status == SAI__OK) {

    smf_smfFile_msg( data->file, "FILE", 1, "<unknown>" );

    if (ndims == 2) {
      /* have to use CSO mode */
      tausrc = SMF__TAUSRC_CSOTAU;
      *thetausrc = tausrc;
    } else if (ndims == 3) {
      /* We have already done the cache test so not needed here */

      /* Is the WVM nominally stable for this night? */
      if (smf_is_wvm_usable( data->hdr, status ) ) {

        /* Calculate the WVM tau data and see if we have enough good data */
        size_t ngoodtau = 0;
        size_t ntotaltau = 0;
        double percentgood = 0.0;
        smf_calc_smoothedwvm( wf, NULL, data, extpars, &wvmtau, &ntotaltau,
                              &ngoodtau, status );
        percentgood = 100.0 * ((double)ngoodtau / (double)ntotaltau);

        if ( percentgood > 80.0) {
          tausrc = SMF__TAUSRC_WVMRAW;
          msgOutiff( MSG__VERB, "", "Selecting WVM mode for extinction correction of ^FILE."
                     " %.0f %% of WVM data are present", status, percentgood );
          *thetausrc = tausrc;
        } else {
          tausrc = SMF__TAUSRC_AUTO; /* keep it AUTO (a no-op but make it clear) */
          if (wvmtau) wvmtau = astFree( wvmtau );
        }
      }

      /* at this point we either have WVM data handled or we still think we are AUTO.
         Do a CSO FIT check */
      if (tausrc == SMF__TAUSRC_AUTO && *status == SAI__OK) {
        size_t nframes = 0;
        smf_calc_csofit( data, extpars, &wvmtau, &nframes, status );
        if (*status == SAI__OK) {
          smf_smfFile_msg( data->file, "FILE", 1, "<unknown>");
          msgOutiff( MSG__QUIET, "", "Using CSO fits for extinction correction of ^FILE",
                     status );
          /* Rebrand as WVM data from this point on */
          tausrc = SMF__TAUSRC_WVMRAW;
          *thetausrc = SMF__TAUSRC_CSOFIT;
        } else if (*status == SMF__BADFIT) {
          /* No fit, carry on. */
          errAnnul( status );
        }
      }

      /* At this point if we are not WVMRAW then we have a serious issue. It means that
         WVM was unusable and we did not have a good CSO fit. We should not continue at this
         point as to continue implies that we know what we should do. The user should decide
         how much they trust the opacity for the night. There has to be a reason why there
         is no CSO fit for the night. */
      if (*status == SAI__OK && tausrc != SMF__TAUSRC_WVMRAW) {
        *status = SAI__ERROR;
        errRep("", "Unable to determine opacity data for this observation. Both WVM and CSO fits failed. Please investigate and if necessary use CSO mode explicitly but proceed with caution.", status );
      }
    }
  }

  /* If we have a CSO Tau then convert it to the current filter. This will also
     convert bad values to a value derived from the header if appropriate. */
  if ( tausrc == SMF__TAUSRC_CSOTAU ) {
    tau = smf_cso2filt_tau( hdr, tau, extpars, status );
    /* The tau source is now a real tau */
    tausrc = SMF__TAUSRC_TAU;
  }

  /* Find the airmass range for this data */
  smf_find_airmass_interval( hdr, &amstart, &amend, &elstart, &elend, status );
  if (*status == SAI__OK && (amstart == VAL__BADD || amend == VAL__BADD)) {
    *status = SAI__ERROR;
    errRep( "", "No good airmass values found in JCMTSTATE structure for these data",
            status );
  }

  /* if we are not doing WVM correction but are in adaptive mode we can determine
     whether or not we will have to use full or single mode just by looking at the
     airmass data. */
  if (ndims == 3 && tausrc != SMF__TAUSRC_WVMRAW && method == SMF__EXTMETH_ADAPT) {
    /* first and last is a good approximation given that most SCUBA-2 files will only
       be a minute duration. */
    double refel;
    double refam;

    /* only need to examine the largest airmass */
    if (amstart > amend) {
      refam = amstart;
      refel = elstart;
    } else {
      refam = amend;
      refel = elend;
    }

    /* and choose a correction method */
    if (is_large_delta_atau( refam, refel, tau, status) ) {
      method = SMF__EXTMETH_FULL;
      msgOutiff(MSG__DEBUG, " ",
               "Adaptive extinction algorithm selected per-bolometer airmass value "
               "per time slice (am=%g, tau=%g)", status, refam, tau);
    } else {
      msgOutiff(MSG__DEBUG, " ",
               "Adaptive extinction algorithm selected single airmass value per time slice"
               " (am=%g, tau=%g)", status, refam, tau);
      method = SMF__EXTMETH_SINGLE;
    }

  }

  /* Assign pointer to input data array if status is good */
  if ( *status == SAI__OK ) {
    indata = (data->pntr)[0];
    vardata = (data->pntr)[1];
  }

  /* Jump to the cleanup section if status is bad by this point
     since we need to free memory */
  if (*status != SAI__OK) goto CLEANUP;

  /* Array bounds for astTranGrid call */
  lbnd[0] = 1;
  lbnd[1] = 1;
  ubnd[0] = nx;
  ubnd[1] = ny;

  /* Unlock the AST objects in the smfData so that the worker threads can
     lock them. */
  smf_lock_data( data, 0, status );

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

  /* Find how many frames to process in each worker thread. */
  framestep = nframes/nw;
  if( framestep == 0 ) {
    framestep = 1;
    nw = nframes;
  }

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

      pdata->nframes = nframes;
      pdata->npts = npts;
      pdata->allextcorr = allextcorr;
      pdata->indata = indata;
      pdata->tau = tau;
      pdata->vardata = vardata;
      pdata->wvmtau = wvmtau;
      pdata->amstart = amstart;
      pdata->amfirst = amstart + ( amend - amstart )*pdata->f1/( nframes - 1 );
      pdata->lbnd = lbnd;
      pdata->ubnd = ubnd;
      pdata->isTordered = isTordered;
      pdata->ndims = ndims;
      pdata->data = data;
      pdata->hdr = hdr;
      pdata->method = method;
      pdata->tausrc = tausrc;

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

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

    /* Record if all time slices used a single air mass. */
    allquick = 1;
    for( iw = 0; iw < nw; iw++ ) {
      pdata = job_data + iw;
      if( ! pdata->allquick ) {
        allquick = 0;
        break;
      }
    }

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

  /* Lock the AST objects in the smfData for use by this thread. */
  smf_lock_data( data, 1, status );

  /* Add history entry if !allextcorr */
  if( (*status == SAI__OK) && !allextcorr ) {
    smf_history_add( data, FUNC_NAME, status);
  }

 CLEANUP:
  if (wvmtaucache) {
    if (!*wvmtaucache) {
      *wvmtaucache = wvmtau;
    }
  } else {
    wvmtau = astFree( wvmtau );
  }

  return allquick;
}
Exemplo n.º 17
0
static void smf1_calc_iqu_job( void *job_data, int *status ) {
/*
*  Name:
*     smf1_calc_iqu_job

*  Purpose:
*     Calculate I, Q and U for a block of bolometers.

*  Invocation:
*     void smf1_calc_iqu_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
*        smfCalcIQUJobData structure.
*     status = int * (Given and Returned)
*        Pointer to global status.

*  Description:
*     This routine calculate the I, Q and U values for each bolometer in
*     a block of bolometers. It runs within a thread instigated by
*     smf_calc_iqu.

*/

/* Local Variables: */
   const JCMTState *allstates;/* Pointer to array of JCMTState structures */
   const JCMTState *state;    /* JCMTState info for current time slice */
   dim_t b1;                  /* First bolometer index */
   dim_t b2;                  /* Last bolometer index */
   dim_t ibolo;               /* Bolometer index */
   dim_t ipix;                /* Pixel index */
   dim_t nbolo;               /* Total number of bolometers */
   double *dat;               /* Pointer to start of input data values */
   double *din0;              /* Pointer to input data array for 1st time */
   double *din;               /* Pointer to input data array for bolo/time */
   double *ipi;               /* Pointer to output I array */
   double *ipiv;
   double *ipq;               /* Pointer to output Q array */
   double *ipqv;
   double *ipu;               /* Pointer to output U array */
   double *ipuv;
   double *pm;                /* Pointer to next time slice mean value */
   double ang;
   double angfac;
   double angle;              /* Phase angle for FFT */
   double angle_l;
   double angrot;             /* Angle from focal plane X axis to fixed analyser */
   double cosval;             /* Cos of twice reference rotation angle */
   double dang;
   double den;
   double fpr0;
   double fprinc;
   double i;                  /* Output I value */
   double paoff;              /* WPLATE value corresponding to POL_ANG=0.0 */
   double phi;                /* Angle from fixed analyser to effective analyser */
   double q0;                 /* Q value with respect to fixed analyser */
   double q;                  /* Output Q value */
   double rot;                /* Rotation angle included in current s1/2/3 values */
   double s1;                 /* Sum of weighted cosine terms */
   double s2;                 /* Sum of weighted sine terms */
   double s3;                 /* Sum of weights */
   double sinval;             /* Sin of twice reference rotation angle */
   double sum;                /* Sum of bolometer values */
   double sw;
   double swi;
   double swii;
   double swq;
   double swqq;
   double swu;
   double swuu;
   double sww;
   double u0;                 /* U value with respect to fixed analyser */
   double u;                  /* Output U value */
   double v;                  /* Analysed intensity to use */
   double vi;
   double vq0;
   double vq;
   double vu0;
   double vu;
   double wplate;             /* Angle from fixed analyser to have-wave plate */
   int block_end;             /* Last time slice to process */
   int block_start;           /* First time slice to process */
   int ipolcrd;               /* Reference direction for pol_ang */
   int itime;                 /* Time slice index */
   int itime_start;           /* Time slice index at start of section */
   int limit2;                /* Min no of good i/p values for a good single estimate */
   int limit;                 /* Min no of good i/p values for a good o/p value */
   int n;                     /* Number of contributing values in S1, S2 and S3 */
   int ncol;                  /* No. of bolometers in one row */
   int nn;                    /* Number of good bolometer values */
   int nrot;
   int old;                   /* Data has old-style POL_ANG values? */
   int pasign;                /* +1 or -1 indicating sense of POL_ANG value */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfCalcIQUJobData *pdata;  /* Pointer to job data */
   smf_qual_t *qin0;          /* Pointer to input quality array for 1st time */
   smf_qual_t *qin;           /* Pointer to input quality array for bolo/time */
   smf_qual_t *qua;           /* Pointer to start of input quality values */

/* 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 = (smfCalcIQUJobData *) job_data;

   b1 = pdata->b1;
   b2 = pdata->b2;
   bstride = pdata->bstride;
   dat = pdata->dat;
   nbolo = pdata->nbolo;
   qua = pdata->qua;
   tstride = pdata->tstride;
   allstates = pdata->allstates;
   ipi = pdata->ipi;
   ipq = pdata->ipq;
   ipu = pdata->ipu;
   ipiv = pdata->ipiv;
   ipqv = pdata->ipqv;
   ipuv = pdata->ipuv;
   ipolcrd = pdata->ipolcrd;
   block_start = pdata->block_start;
   block_end = pdata->block_end;
   old = pdata->old;
   ncol = pdata->ncol;
   pasign = pdata->pasign;
   paoff = pdata->paoff;
   angrot = pdata->angrot;
   angfac = pdata->angfac;
   fpr0 = pdata->fpr0;
   fprinc = pdata->fprinc;

/* Assume we are not returning any variance values. */
   pdata->gotvar = 0;

/* Calculate Q and U if required. */
   if( pdata->action == 0 ) {

/* Check we have something to do. */
      if( b1 < nbolo ) {

/* The minimum number of samples required for a good output value. Half
   of the available input samples must be good. */
         limit = 0.5*( block_end - block_start );
         limit2 = 10;

/* Initialise pointers to the first time slice data and quality value for
   the first bolometer to be processed in the current block of time slices. */
         din0 = dat + bstride*b1 + tstride*block_start;
         qin0 = qua + bstride*b1 + tstride*block_start;

/* Loop round all bolometers to be processed by this thread. */
         for( ibolo = b1; ibolo <= b2; ibolo++ ) {

/* If the whole bolometer is bad, just use bad q and u values. */
            if( *qin0 & SMF__Q_BADB ) {
               i = VAL__BADD;
               u = VAL__BADD;
               q = VAL__BADD;
               vi = VAL__BADD;
               vu = VAL__BADD;
               vq = VAL__BADD;

/* If the bolometer is good, calculate and store the q and u values. */
            } else {

/* Initialise pointers to the next time slice data and quality value for
   the current bolometer. */
               din = din0;
               qin = qin0;

/* Initialise the sums used to find Q and U at this bolometer. */
               s1 = 0.0;
               s2 = 0.0;
               s3 = 0.0;
               n = 0.0;
               rot = 0.0;
               angle_l = VAL__BADD;

               swq = 0.0;
               swqq = 0.0;
               swu = 0.0;
               swuu = 0.0;
               swi = 0.0;
               swii = 0.0;
               sw = 0.0;
               sww = 0.0;
               nrot = 0;

/* Loop round all time slices. */
               pm = pdata->mean;
               if( pm )  pm += block_start;
               state = allstates + block_start;
               itime_start = block_start;
               for( itime = block_start; itime <= block_end; itime++,state++ ) {

/* Get the POL_ANG value for this time slice. */
                  angle = state->pol_ang;

/* Check the input sample has not been flagged during cleaning and is
   not bad. */
                  if( !( *qin & SMF__Q_FIT ) && *din != VAL__BADD &&
                      angle != VAL__BADD && ( !pm || *pm != VAL__BADD ) ) {

/* If POL_ANG is stored in arbitrary encoder units, convert to radians. */
                     if( old ) angle = angle*TORADS;

/* Following SUN/223 (section "Single-beam polarimetry"/"The Polarimeter"),
   get the angle from the fixed analyser to the half-waveplate axis, in radians.
   Positive rotation is from focal plane axis 1 (x) to focal plane axis 2 (y).

   Not sure about the sign of tcs_az/tr_ang at the moment so do not use them
   yet. */
                     wplate = 0.0;
                     if( ipolcrd == 0 ) {
                        wplate = pasign*angle + paoff;

                     } else if( *status == SAI__OK ) {
                        *status = SAI__ERROR;
                        errRepf( "", "smf_calc_iqu: currently only POL_CRD = "
                                 "FPLANE is supported.", status );
                     }

/*
                  if( ipolcrd == 1 ) {
                     wplate += state->tcs_az_ang;
                  } else if( ipolcrd == 2 ) {
                     wplate += state->tcs_tr_ang;
                  }
*/

/* Get the angle from the fixed analyser to the effective analyser
   position (see SUN/223 again). The effective analyser angle rotates twice
   as fast as the half-wave plate which is why there is a factor of 2 here. */
                     phi = 2*wplate;

/* Increment the sums needed to find the Fourier component of the time
   series corresponding to the frequency introduced by the rotation of
   the half wave plate. */
                     angle = 2*phi;

/* Allow the angle to be scaled by some user-specified factor. This is to
   allow the investigation of other harmonics. */
                     angle *= angfac;

/* If we have now done the required amount of rotation, calculate new Q and
   U values. */
                     if( rot >= ROT_PER_SAMPLE ) {

/* If we have sufficient points, calculate the I, Q and U values for the
   revolution that has just ended, and then update the running sums used
   to find the final values and variances. */
                        if( n > limit2 ) {
                           q0 = 4*s1/n;
                           u0 = 4*s2/n;
                           i = 2*s3/n;

/* Rotate the Q and U values to take account of the difference between the
   orientation of the focal plane at the middle time slice included in
   the current values, and the focal plane in the output NDF. */
                           ang = fpr0 + 0.5*fprinc*( itime_start + itime - 1 );
                           cosval = cos(2*ang);
                           sinval = sin(2*ang);
                           q = q0*cosval + u0*sinval;
                           u = -q0*sinval + u0*cosval;

                           swq += n*q;
                           swqq += n*q*q;
                           swu += n*u;
                           swuu += n*u*u;
                           swi += n*i;
                           swii += n*i*i;
                           sw += n;
                           sww += n*n;
                           nrot++;

                           itime_start = itime;
                        }

/* Prepare for a new revolution. */
                        s1 = 0.0;
                        s2 = 0.0;
                        n = 0;
                        rot = 0.0;
                     }

/* Increment the total rotation angle since the last calculation of Q and U. */
                     dang = ( angle_l != VAL__BADD ) ? angle - angle_l : 0.0;
                     while( dang < -AST__DPI ) dang += 2*AST__DPI;
                     rot += dang;
                     angle_l = angle;

/* Increment the sums to include the current time slice. */
                     v = pm ? *din - *pm : *din;
                     s1 += v*cos( angle );
                     s2 += v*sin( angle );
                     s3 += v;
                     n++;
                  }

/* Update pointers to the next time slice data and quality value for
   the current bolometer. */
                  din += tstride;
                  qin += tstride;
                  if( pm ) pm++;
               }

/* Add in the I, Q and U values determined from the final block. */
               if( n > limit2 ) {
                  q0 = 4*s1/n;
                  u0 = 4*s2/n;
                  i = 2*s3/n;

                  ang = fpr0 + 0.5*fprinc*( itime_start + itime - 1 );
                  cosval = cos(2*ang);
                  sinval = sin(2*ang);
                  q = q0*cosval + u0*sinval;
                  u = -q0*sinval + u0*cosval;

                  swq += n*q;
                  swqq += n*q*q;
                  swu += n*u;
                  swuu += n*u*u;
                  swi += n*i;
                  swii += n*i*i;
                  sw += n;
                  sww += n*n;
                  nrot++;
               }

/* Calculate the mean q, u and i values variances. These use the
   fixed analyser in the output as the reference direction. */
               q = VAL__BADD;
               u = VAL__BADD;
               i = VAL__BADD;
               vq = VAL__BADD;
               vu = VAL__BADD;
               vi = VAL__BADD;

               if( sw > limit && nrot > 0 ) {
                  msgOutiff( MSG__DEBUG, "", "Bolo %d split into %d values "
                             "(%g samples per value)", status, (int) ibolo,
                             nrot, sw/nrot );

                  q0 = swq/sw;
                  u0 = swu/sw;
                  i = swi/sw;

/* Modify Q and U so they use the focal plane Y as the reference direction. */
                  cosval = cos(2*angrot);
                  sinval = sin(2*angrot);
                  q = -q0*cosval + u0*sinval;
                  u = -q0*sinval - u0*cosval;

/* If we had at least 4 rotations, also calculate the variances, and
   rotate them. */
                  den = sw*sw - sww;
                  if( den > 0 && nrot > 3 ) {
                     vq0 = sww*( swqq/sw - q0*q0 )/den;
                     vu0 = sww*( swuu/sw - u0*u0 )/den;
                     vi = sww*( swii/sw - i*i )/den;

                     vq = cosval*cosval*vq0 + sinval*sinval*vu0;
                     vu = sinval*sinval*vq0 + cosval*cosval*vu0;

                     pdata->gotvar = 1;
                  }
               }
            }

/* Calculate the vector index into the output NDFs at which to store the
   current bolometer. This implements a reversal of the pixels along each
   row, in order to produce the usual right-handed view of the sky. */
            ipix = ncol + ibolo - 2*( ibolo % ncol ) - 1;

/* Store the values in the output NDFs. */
            ipq[ ipix ] = q;
            ipu[ ipix ] = u;
            if( ipi ) ipi[ ipix ] = i;

            ipqv[ ipix ] = vq;
            ipuv[ ipix ] = vu;
            if( ipiv ) ipiv[ ipix ] = vi;

/* Update the pointers to the first time slice data and quality value for
   the next bolometer. */
            din0 += bstride;
            qin0 += bstride;
         }
      }

/* Calculate mean value in each time slice if required. */
   } else {

      pm = pdata->mean + block_start;
      for( itime = block_start; itime <= block_end; itime++,pm++ ) {
         din = dat + itime*tstride;
         qin = qua + itime*tstride;

         sum = 0;
         nn = 0;

         for( ibolo = 0; ibolo < nbolo; ibolo++ ) {

            if( !( *qin & SMF__Q_FIT ) && *din != VAL__BADD ) {
               sum += *din;
               nn++;

            }

            din += bstride;
            qin += bstride;
         }

         if( nn > 0 ) {
            *pm = sum/nn;
         } else {
            *pm = VAL__BADD;
         }
      }
   }
}
Exemplo n.º 18
0
void smf_getrefwcs( const char *param, Grp *igrp, AstFrameSet **specwcs,
                    AstFrameSet **spacewcs, int *isjsa, int *status ){

/* Local Variables */
   AstFrame *frm = NULL;
   AstFrameSet *refwcs = NULL;  /* The WCS FrameSet from the reference NDF */
   AstRegion *circle;
   char text[ 255 ];            /* Parameter value */
   int *tiles;
   int i;
   int jsatiles;
   int lbnd[2];                 /* Lower pixel index bounds of mid tile */
   int ntile;
   int perm[ 2 ];
   int refndf;                  /* NDF identifier for the refence NDF */
   int ubnd[2];                 /* Upper pixel index bounds of mid tile */
   size_t code;
   smfData *data = NULL;        /* Structure describing 1st input file */
   smfJSATiling skytiling;
   smf_inst_t inst = SMF__INST_NONE;
   smf_jsaproj_t proj;          /* Specific JSA projection to use */
   smf_subinst_t subinst;

/* Initialise the returned values. */
   *specwcs = NULL;
   *spacewcs = NULL;
   *isjsa = 0;

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

/* Begin an AST context. */
   astBegin;

/* If the JSAILES parameter is TRUE, then we use the JSA all-sky pixel
   grid regardless of the setting of REF. */
   parGet0l( "JSATILES", &jsatiles, status );
   if( jsatiles ) {
      strcpy( text, "JSA" );
      *isjsa = 1;

/* Otherwise, first get the parameter value as a string. Use subpar to avoid problem
   caused by interpretion of the text within the parameter system. */
   } else {
      subParFindpar( param, &code, status );
      subParGetname( code, text, sizeof(text), status );
   }

/* If no value was supplied, annul the error and do nothing more. */
   if( *status == PAR__NULL ) {
      errAnnul( status );

/* If it is "JSA", or one of the JSA projection codes, we return WCS that
   describes one of the the JSA all-sky pixel grids. */
   } else if( *status == SAI__OK ) {
      proj = smf_jsaproj_fromstr( text, 0, status );
      if( astChrMatch( text, "JSA" ) || proj != SMF__JSA_NULL ) {
         *isjsa = 1;

/* Report an error if the instrument cannot be determined. */
         if( !igrp ) {
            *status = SAI__ERROR;
            errRep( "", "smf_getrefwcs: Cannot use the JSA all-sky pixel "
                    "grid since no input group has been supplied (possibly "
                    "programming error).", status );
         } else {

/* Open the first input file. */
            smf_open_file( NULL, igrp, 1, "READ", SMF__NOCREATE_DATA, &data,
                           status );
            if( *status == SAI__OK ) {

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

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

               } else if( *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  if( data->file ) {
                     smf_smfFile_msg( data->file, "FILE", 1, "one or more of "
                                      "the input data files" );
                  } else {
                     msgSetc( "FILE", "one or more of the input data files" );
                  }
                  errRep( "", "No tiles are yet defined for the instrument that "
                          "created ^FILE.", status );
               }

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

/* For "JSA" - choose the best projection. */
               if( astChrMatch( text, "JSA" ) ) {

/* Use the FITS headers in the first raw data file to create an AST Circle
   describing the approximate area of the observation within the tracking
   system. */
                  circle = smf_mapregion_approx( igrp, status );

/* Convert the circle to ICRS (as used by the JSA all-sky grid). */
                  astSetC( circle, "System", "ICRS" );

/* Get a list of the tiles that touch this circle. */
                  tiles = smf_jsatiles_region( circle, &skytiling,
                                               &ntile, status );

/* Choose the best projection (i.e. the projection that puts the circle
   furthest away from any singularities). */
                  proj = smf_jsaproj( ntile, tiles, &skytiling, status);

/* Free resources. */
                  tiles = astFree( tiles );
                  circle = astAnnul( circle );

/* If a good projection was specified, use it. Otherwise report an error. */
               } else if( proj == SMF__JSA_NULL && *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  errRepf( "", "Bad value '%s' supplied for parameter %s.",
                           status, text, param );
               }

/* Report the projection type. */
               msgOutf( " ", "The %s will be created on the JSA %s "
                        "pixel grid.", status,
                        (data->hdr->instrument==INST__ACSIS)?"cube":"map",
                        smf_jsaproj_tostr( proj ) );

/* All tiles within the same JSA projection use the same WCS, so we get
   the WCS FrameSet for an arbitrary central tile, and use it for the
   full map. The exception is that tiles within the HPX facet that is
   split between bottom-left and top-right, use a different WCS (they
   have different reference points). But our choice of projection should
   mean that the map never falls in that facet. The base Frame will be
   GRID coords within the tile, and the current Frame will be ICRS
   (RA,Dec). */
               smf_jsatile( ((skytiling.ntpf * skytiling.ntpf - 1) * 2) / 3,
                            &skytiling, 0, proj, NULL, spacewcs, NULL, lbnd,
                            ubnd, status );

/* Change the base Frame to be PIXEL. */
               for( i = 1; i <= astGetI( *spacewcs, "NFrame" ); i++ ) {
                  frm = astGetFrame( *spacewcs, i );
                  if( astChrMatch( astGetC( frm, "Domain" ), "PIXEL" ) ) {
                     astSetI( *spacewcs, "Base", i );
                  }
                  frm = astAnnul( frm );
               }
            }

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

/* Otherwise get the parameter value as an NDF. */
      } else {
         ndfAssoc( param, "READ", &refndf, status );

/* Get the WCS FrameSet from the reference NDF. */
         ndfGtwcs( refndf, &refwcs, status );

/* Attempt to extract a new FrameSet from this WCS FrameSet, in which the
   current Frame is a SkyFrame, and the base Frame is a 2D PIXEL Frame.
   Since the NDF library sets the GRID Frame to be the Base Frame, we need
   to make the PIXEL Frame the base Frame first. The NDF library ensures
   that the pixel Frame is Frame 2. */
         astSetI( refwcs, "Base", 2 );
         *spacewcs = atlFrameSetSplit( refwcs, "SKY", NULL, NULL, status );
         if( !(*spacewcs) ) {
            if( *status == SAI__OK ) {
               ndfMsg( "N", refndf );
               *status = SAI__ERROR;
               errRep( "", "The supplied reference NDF (^N) either has no "
                       "celestial WCS axes, or the celestial axes cannot "
                       "be separated from the non-celestial axes.", status );
            }

/* The rest of makemap assumes that the sky frame axes are in the default
   order (lon,lat). If this is not the case, permute them. */
         } else if( astGetI( *spacewcs, "IsLatAxis(1)" ) ) {
            perm[ 0 ] = 2;
            perm[ 1 ] = 1;
            astPermAxes( *spacewcs, perm );
         }

/* Now look for the spectral WCS (described by a DSBSpecFrame). */
         smf_getspectralwcs( refwcs, 1, specwcs, status );

/* We no longer need the NDF so annul it. */
         ndfAnnul( &refndf, status );
      }
   }

/* If no error has occurred, export any returned FrameSet pointers from
   the current AST context so that it will not be annulled when the AST
   context is ended. Otherwise, ensure a null pointer is returned. */
   if( *status == SAI__OK ) {
      if( *spacewcs ) astExport( *spacewcs );
      if( *specwcs ) astExport( *specwcs );
   } else {
      if( *spacewcs ) *spacewcs = astAnnul( *spacewcs );
      if( *specwcs ) *specwcs = astAnnul( *specwcs );
   }

/* End the AST context. This will annul all AST objects created within the
   context (except for those that have been exported from the context). */
   astEnd;

}
Exemplo n.º 19
0
void smf_calc_smoothedwvm ( ThrWorkForce *wf, const smfArray * alldata,
                            const smfData * adata, AstKeyMap* extpars, double **wvmtau,
                            size_t *nelems, size_t *ngoodvals, int * status ) {
  size_t i;
  size_t nrelated = 0;          /* Number of entries in smfArray */
  size_t nframes = 0;           /* Number of timeslices */
  size_t ngood = 0;             /* Number of elements with good tau */
  double *taudata = NULL;       /* Local version of WVM tau */
  const smfArray * thesedata = NULL;  /* Collection of smfDatas to analyse */
  smfArray * tmpthesedata = NULL; /* Local version of adata in a smfArray */

  if (*status != SAI__OK) return;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    smf_timerinit( &tv1, &tv2, status );


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

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

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

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

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

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

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

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

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

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

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

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

              pdata = job_data + iworker;

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

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

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

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

              prevend = pdata->t2;

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

            }

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

          }

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

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

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

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

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

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

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

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

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

  }




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

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

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

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

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

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

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

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

}
Exemplo n.º 20
0
void smf_svd( ThrWorkForce *wf, dim_t n, double *a, double *sigma,
              double *u, double eps, int sort, int *status ) {

/* Local Variables */
   SmfSvdData *job_data = NULL;
   SmfSvdData *pdata = NULL;
   dim_t *sobhigh = NULL;
   dim_t *soblow = NULL;
   dim_t i;
   dim_t j;
   dim_t k;
   dim_t irow;
   dim_t iter;
   dim_t nbig;
   dim_t nsmall;
   dim_t nstep;
   dim_t p;
   dim_t rpb;
   dim_t s;
   double *aorig;
   double sigold;
   double delta;
   int *dn = NULL;
   int *up = NULL;
   int converged;

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

/* The number of threads to use. */
   p = wf ? wf->nworker : 1;

/* If we have more processors than blocks in the matrix, limit the number
   of processors. */
   if( 4*p > n ) p = n/4;
   if( p == 0  ) {
      *status = SAI__ERROR;
      errRepf( "", "smf_svd: Too few rows (%zu) in matrix - must "
               "be no fewer than 4", status, n );
   }

/* Allocate required arrays. */
   sobhigh = astMalloc( 2*p*sizeof( *sobhigh ) );
   soblow = astMalloc( 2*p*sizeof( *soblow ) );
   up = astMalloc( p*sizeof( *up ) );
   dn = astMalloc( p*sizeof( *dn ) );
   job_data = astMalloc( 2*p*sizeof( *job_data ) );
   aorig = u ? astStore( NULL, a, n*n*sizeof(*a) ) : NULL;

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

/* Decide on the first and last element to be processed by each thread,
   for "simple" tasks. At the same time, set up jobs to find the sum
   of the squares of all data values (a simple task). */
      nstep = (n*n)/p;
      for( i = 0; i < p; i++ ) {
         pdata = job_data + i;
         pdata->i1 = i*nstep;
         if( i < p - 1 ){
            pdata->i2 = pdata->i1 + nstep - 1;
         } else {
            pdata->i2 = n*n - 1;
         }
         pdata->a = a;
         pdata->oper = 0;
         thrAddJob( wf, 0, pdata, smf1_svd, 0, NULL, status );
      }

      thrWait( wf, status );

      delta = 0.0;
      for( i = 0; i < p; i++ ) {
         pdata = job_data + i;
         delta += pdata->delta;
      }
      delta *= eps;

/* Set up the "size of block" (sob) arrays: soblow holds the zero-based index
   of the first matrix row in each block, and sobhigh holds the zero-based
   index of the last matrix row in each block. We want 2*P blocks (i.e. twice
   the number of threads). Distribute any left over rows evenly amongst the
   blocks so that some blocks have n/2p rows (small blocks), and some have
   n/2p+1 rows (big blocks). */
      rpb = n/(2*p);        /* Nominal number of rows per block */
      nbig = n - 2*p*rpb;   /* Number of big blocks */
      nsmall = 2*p - nbig;  /* Number of small blocks */

/* If we have more small blocks than big blocks, we start with "nbig" pairs
   of blocks in which the first block is big and the second block is small,
   and then pad the end with the surplus number of small blocks. */
      if( nbig < nsmall ) {
         s = 0;
         irow = 0;
         for( i = 0; i < nbig; i++ ) {
            soblow[ s ] = irow;
            irow += rpb;
            sobhigh[ s ] = irow;

            irow++;
            s++;

            soblow[ s ] = irow;
            irow += rpb - 1;
            sobhigh[ s ] = irow;

            irow++;
            s++;
         }

         for( i = s; i < 2*p; i++ ) {
            soblow[ i ] = irow;
            irow += rpb - 1;
            sobhigh[ i ] = irow;
            irow++;
         }

/* If we have more big blocks than small blocks, we start with "nsmall" pairs
   of blocks in which the first block is big and the second block is small,
   and then pad the end with the surplus number of big blocks. */
      } else {
         s = 0;
         irow = 0;
         for( i = 0; i < nsmall; i++ ) {
            soblow[ s ] = irow;
            irow += rpb;
            sobhigh[ s ] = irow;

            irow++;
            s++;

            soblow[ s ] = irow;
            irow += rpb - 1;
            sobhigh[ s ] = irow;

            irow++;
            s++;
         }

         for( i = s; i < 2*p; i++ ) {
            soblow[ i ] = irow;
            irow += rpb;
            sobhigh[ i ] = irow;
            irow++;
         }
      }

/* Sanity check. */
      if( ( irow != n || i != 2*p ) && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRep( "", "smf_svd: Error setting up the SOB arrays.", status );
         goto L999;
      }

/* Now proceed with the "Block JRS Algorithm" algorithm, as described
   in "A Block JRS Algorithm for Highly Parallel Computation of SVDs"
   (Soliman, et al, DOI: 10.1007/978-3-540-75444-2_36). Note, integer
   counters are one-based in the pseudo-code in the paper, but here
   we use zero-based counters as is normal in C. */

      for( i = 0; i < p; i++ ) {
         up[ i ] = 2*i + 1;
         dn[ i ] = 2*i;
      }

      converged = 0;
      while( !converged ) {
         converged = 1;

         for( s = 0; s < 2*p; s++ ) {
            pdata = job_data + s;
            pdata->oper = 1;
            pdata->soblow = soblow[s];
            pdata->sobhigh = sobhigh[s];
            pdata->delta = delta;
            pdata->a = a;
            pdata->n = n;
            thrAddJob( wf, 0, pdata, smf1_svd, 0, NULL, status );
         }
         thrWait( wf, status );

         for( s = 0; s < 2*p; s++ ) {
            if( !job_data[s].converged ) converged = 0;
         }

         for( iter = 1; iter < 2*p; iter++ ) {

            for( s = 0; s < p; s++ ) {
               pdata = job_data + s;
               pdata->oper = 2;
               pdata->upsoblow = soblow[up[s]];
               pdata->upsobhigh = sobhigh[up[s]];
               pdata->dnsoblow = soblow[dn[s]];
               pdata->dnsobhigh = sobhigh[dn[s]];
               thrAddJob( wf, 0, pdata, smf1_svd, 0, NULL, status );
            }
            thrWait( wf, status );

            for( s = 0; s < 2*p; s++ ) {
               if( !job_data[s].converged ) converged = 0;
            }

            smf1_roundrobin( p, up, dn );
         }
      }

      nstep = n/p;
      for( i = 0; i < p; i++ ) {
         pdata = job_data + i;
         pdata->j1 = i*nstep;
         if( i < p - 1 ){
            pdata->j2 = pdata->j1 + nstep - 1;
         } else {
            pdata->j2 = n - 1;
         }
         pdata->sigma = sigma;
         pdata->oper  = 3;
         thrAddJob( wf, 0, pdata, smf1_svd, 0, NULL, status );
      }

      thrWait( wf, status );

/* If required, sort the singular values into descending order. */
      if( sort ) {
         Sigma_array = sigma;

         double *arowold = astMalloc( n*sizeof( *arowold ) );
         int *index = astMalloc( n*sizeof( *index ) );
         if( *status == SAI__OK ) {

            for( i = 0; i < n; i++ ) index[ i ] = i;
            qsort( index, n, sizeof(*index), smf1_compare );
            for( i = 0; i < n; i++ ) {
               sigold = sigma[ i ];
               memcpy( arowold, a + i*n, n*sizeof(*a) );
               j = i;
               while( 1 ) {
                  k = index[ j ];
                  index[ j ] = j;
                  if( k == i ) break;
                  sigma[ j ] = sigma[ k ];
                  memcpy( a + j*n, a + k*n, n*sizeof(*a) );

                  j = k;
               }
               sigma[ j ] = sigold;
               memcpy( a + j*n, arowold, n*sizeof(*a) );
            }
         }
         index = astFree( index );
         arowold = astFree( arowold );
      }

/* If required, calculate the U matrix. */
      if( u ) {
         for( i = 0; i < p; i++ ) {
            pdata = job_data + i;
            pdata->u = u;
            pdata->aorig = aorig;
            pdata->oper = 4;
            thrAddJob( wf, 0, pdata, smf1_svd, 0, NULL, status );
         }

         thrWait( wf, status );
      }

   }

/* Free resources. */
L999:
   job_data = astFree( job_data );
   up = astFree( up );
   dn = astFree( dn );
   soblow = astFree( soblow );
   sobhigh = astFree( sobhigh );
   aorig = astFree( aorig );

}
Exemplo n.º 21
0
void smf_addpolanal( AstFrameSet *fset, smfHead *hdr, AstKeyMap *config,
                     int *status ){

/* Local Variables */
   AstCmpMap *tmap;
   AstFrame *cfrm;
   AstFrame *pfrm;
   AstFrame *tfrm;
   AstFrameSet *tfs;
   AstPermMap *pm;
   char *polnorth = NULL;
   const char *cursys;
   const char *trsys;
   int aloff;
   int icurr;
   int inperm[2];
   int outperm[2];
   int pol2fp;

/* Check inherited status, and also check the supplied angle is not bad. */
   if( *status != SAI__OK ) return;

/* Begin an AST object context. */
   astBegin;

/* Get the value of the POLNORTH FITS keyword from the supplied header.
   The rest only happens if the keyword is found. */
   if( astGetFitsS( hdr->fitshdr, "POLNORTH", &polnorth ) ) {

/* Normally, we do not allow maps to be made from Q/U time streams that
   use focal plane Y as the reference direction (because of the problems
   of sky rotation). Therefore we report an error. However, we do need to
   make such maps as part of the process of determining the parameters of
   the Instrumental Polarisation (IP) model. So only report the error if
   "pol2fp" config parameter is non-zero. */
      if( !strcmp( polnorth, "FPLANE" ) ) {
         astMapGet0I( config, "POL2FP", &pol2fp );

         if( pol2fp ) {
            msgBlank( status );
            msgOut( "", "WARNING: The input NDFs hold POL-2 Q/U data specified "
                    "with respect to focal plane Y.",status );
            msgOut( "", "Maps should normally be made from POL-2 data specified "
                    "with respect to celestial north.",status );
            msgOut( "", "The output map will not contain a POLANAL Frame and "
                    "so will be unusable by POLPACK applications.",status );
            msgBlank( status );

         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRep( "", "The input NDFs hold POL-2 Q/U data specified with "
                    "respect to focal plane Y.",status );
            errRep( "", "Maps can only be made from POL-2 data specified with "
                    "respect to celestial north.",status );
         }

/* If the ref. direction is celestial north, create a suitable Frame and
   Mapping and add them into the supplied FrameSet. */
      } else {

/* Check the current Frame is a SkyFrame. */
         cfrm = astGetFrame( fset, AST__CURRENT );
         if( astIsASkyFrame( cfrm ) ) {

/* Create a POLANAL Frame. */
            pfrm = astFrame( 2, "Domain=POLANAL" );
            astSet( pfrm, "Title=Polarimetry reference frame" );
            astSet( pfrm, "Label(1)=Polarimetry reference direction" );
            astSet( pfrm, "Label(2)=" );

/* Create a PermMap that ensures that axis 1 of the POLANAL Frame is parallel
   to the latitude axis (i.e. north) of the curent Frame (the current Frame axes
   may have been swapped). */
            outperm[ 0 ] = astGetI( cfrm, "LatAxis" );
            outperm[ 1 ] = astGetI( cfrm, "LonAxis" );
            inperm[ outperm[ 0 ] - 1 ] = 1;
            inperm[ outperm[ 1 ] - 1 ] = 2;
            pm = astPermMap( 2, inperm, 2, outperm, NULL, " " );

/* Record the index of the original current Frame. */
            icurr = astGetI( fset, "Current" );

/* Determine the system to use. */
            if( !strcmp( polnorth, "TRACKING" ) ) {
               trsys = sc2ast_convert_system( hdr->state->tcs_tr_sys, status );
            } else {
               trsys = polnorth;
            }

/* If the current Frame in the supplied FrameSet has this system. Then we
   use the above PermMap to connect the POLANAL Frame directly to the current
   Frame. */
            cursys = astGetC( cfrm, "System" );
            if( trsys && cursys && !strcmp( cursys, trsys ) ) {
               astAddFrame( fset, AST__CURRENT, pm, pfrm );

/* Otherwise we need to get a Mapping from the current Frame to the
   required frame. */
            } else {

/* Take a copy of the current Frame (in order to pick up epoch, observatory
   position, etc), and set its System to the required system. */
               tfrm = astCopy( cfrm );
               astSetC( tfrm, "System", trsys );

/* Get the Mapping from the original current Frame to this modified copy.
   Ensure alignment happens in absolute coords (alignment in offset
   coords is always a unit mapping and so no rotation occurs). */
               aloff = astGetI( cfrm, "AlignOffset" );
               if( aloff ) {
                  astSetI( cfrm, "AlignOffset", 0 );
                  astSetI( tfrm, "AlignOffset", 0 );
               }
               tfs = astConvert( cfrm, tfrm, "SKY" );
               if( aloff ) {
                  astSetI( cfrm, "AlignOffset", 1 );
                  astSetI( tfrm, "AlignOffset", 1 );
               }
               if( tfs ) {

/* Use it, in series with with the above PermMap, to connect the POLANAL frame
   to the current Frame. */
                  tmap = astCmpMap( astGetMapping( tfs, AST__BASE,
                                                   AST__CURRENT ),
                                    pm, 1, " " );
                  astAddFrame( fset, AST__CURRENT, astSimplify( tmap ),
                               pfrm );

/* Report an error if the mapping from current to required system could
   not be found. */
               } else if( *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  errRepf( "", "smf_addpolanal: Could not convert Frame "
                           "from %s to %s (prgramming error).", status,
                           cursys, trsys );
               }
            }

/* Re-instate the original current Frame. */
            astSetI( fset, "Current", icurr );

/* Report an error if the current Frame is not a SkyFrame. */
         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRep( "", "smf_addpolanal: The current Frame in the "
                    "supplied FrameSet is not a SkyFrame (prgramming "
                    "error).", status );
         }
      }
   }

/* End the AST object context. */
   astEnd;
}
Exemplo n.º 22
0
static void smf1_svd( void *job_data_ptr, int *status ) {
/*
*  Name:
*     smf1_svd

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

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

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

*/

/* Local Variables: */
   SmfSvdData *pdata;
   dim_t bsize2;
   dim_t bsize;
   dim_t i;
   dim_t icol;
   dim_t ind;
   dim_t irow;
   dim_t j;
   dim_t k;
   dim_t n;
   double *c;
   double *pa;
   double *paorig;
   double *pi;
   double *pj;
   double *ps;
   double *pu;
   double *s;
   double dii;
   double dij;
   double djj;
   double sum;
   double sv;
   double t;
   double tau;
   double temp;

/* 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 = (SmfSvdData *) job_data_ptr;

   n = pdata->n;

   if( pdata->oper == 0 ) {
      pa = pdata->a + pdata->i1;
      pdata->delta = 0.0;
      for( i = pdata->i1; i <= pdata->i2; i++,pa++ ) {
         pdata->delta += (*pa)*(*pa);
      }

   } else if( pdata->oper == 1 ) {
      bsize = pdata->sobhigh - pdata->soblow + 1;
      c = astMalloc( sizeof(*c)*bsize*(bsize-1)/2 );
      s = astMalloc( sizeof(*s)*bsize*(bsize-1)/2 );
      if( *status == SAI__OK ) {
         pdata->converged = 1;

         ind = 0;
         for( i = pdata->soblow; i < pdata->sobhigh; i++ ) {
            for( j = i + 1; j <= pdata->sobhigh; j++ ) {
               pi = pdata->a + i*n;
               pj = pdata->a + j*n;
               dii = 0.0;
               djj = 0.0;
               dij = 0.0;
               for( k = 0; k < n; k++,pi++,pj++ ) {
                  dii += *(pi)*(*pi);
                  djj += *(pj)*(*pj);
                  dij += *(pi)*(*pj);
               }

               if( fabs( dij) > pdata->delta ) pdata->converged = 0;
               if( dij != 0.0 ) {
                  tau = ( djj - dii ) /(2*dij);
                  t = (1.0 - GAMMA)/( fabs(tau) + sqrt(tau*tau+1.0-GAMMA*GAMMA) );
                  if( tau < 0.0 ) t = -t;
                  c[ ind ] = 1.0/sqrt(t*t+1.0);
                  s[ ind ] = t*c[ ind ];
               } else {
                  c[ ind ] = 1.0;
                  s[ ind ] = 0.0;
               }
               ind++;
            }
         }

         ind = 0;
         for( i = pdata->soblow; i < pdata->sobhigh; i++ ) {
            for( j = i + 1; j <= pdata->sobhigh; j++ ) {
               pi = pdata->a + i*n;
               pj = pdata->a + j*n;
               for( k = 0; k < n; k++,pi++,pj++ ) {
                  temp = c[ind]*(*pi) - s[ind]*(*pj);
                  *pj = s[ind]*(*pi) + c[ind]*(*pj);
                  *pi = temp;
               }
               ind++;
            }
         }
      }
      c = astFree( c );
      s = astFree( s );

   } else if( pdata->oper == 2 ) {
      bsize = pdata->upsobhigh - pdata->upsoblow + 1;
      bsize2 = pdata->dnsobhigh - pdata->dnsoblow + 1;
      c = astMalloc( sizeof(*c)*bsize*bsize2 );
      s = astMalloc( sizeof(*s)*bsize*bsize2 );
      if( *status == SAI__OK ) {
         pdata->converged = 1;

         ind = 0;
         for( i = pdata->upsoblow; i <= pdata->upsobhigh; i++ ) {
            for( j = pdata->dnsoblow; j <= pdata->dnsobhigh; j++ ) {
               pi = pdata->a + i*n;
               pj = pdata->a + j*n;
               dii = 0.0;
               djj = 0.0;
               dij = 0.0;
               for( k = 0; k < n; k++,pi++,pj++ ) {
                  dii += *(pi)*(*pi);
                  djj += *(pj)*(*pj);
                  dij += *(pi)*(*pj);
               }

               if( fabs( dij) > pdata->delta ) pdata->converged = 0;
               if( dij != 0.0 ) {
                  tau = ( djj - dii ) /(2*dij);
                  t = (1.0 - GAMMA)/( fabs(tau) + sqrt(tau*tau+1.0-GAMMA*GAMMA) );
                  if( tau < 0.0 ) t = -t;
                  c[ ind ] = 1.0/sqrt(t*t+1.0);
                  s[ ind ] = t*c[ ind ];
               } else {
                  c[ ind ] = 1.0;
                  s[ ind ] = 0.0;
               }
               ind++;
            }
         }

         ind = 0;
         for( i = pdata->upsoblow; i <= pdata->upsobhigh; i++ ) {
            for( j = pdata->dnsoblow; j <= pdata->dnsobhigh; j++ ) {
               pi = pdata->a + i*n;
               pj = pdata->a + j*n;
               for( k = 0; k < n; k++,pi++,pj++ ) {
                  temp = c[ind]*(*pi) - s[ind]*(*pj);
                  *pj = s[ind]*(*pi) + c[ind]*(*pj);
                  *pi = temp;
               }
               ind++;
            }
         }
      }
      c = astFree( c );
      s = astFree( s );

   } else if( pdata->oper == 3 ) {
      pa = pdata->a + n*pdata->j1;
      for( i = pdata->j1; i <= pdata->j2; i++ ) {
         sv = 0.0;
         for( k = 0; k < n; k++,pa++ ) {
            sv += (*pa)*(*pa);
         }
         sv = ( sv > 0.0 ) ? sqrt( sv ) : 0.0;
         if(pdata->sigma) (pdata->sigma)[ i ] = sv;

         pa -= n;
         if( sv > 0.0 ){
            for( k = 0; k < n; k++,pa++ ) *pa /= sv;
         } else {
            for( k = 0; k < n; k++,pa++ ) *pa = 0.0;
         }
      }

   } else if( pdata->oper == 4 ) {
      pu = pdata->u + pdata->i1;

      for( i = pdata->i1; i <= pdata->i2; i++ ) {
         irow = i/n;
         icol = i - n*irow;

         paorig = pdata->aorig + irow*n;
         pa = pdata->a + icol*n;
         ps = pdata->sigma;

         sum = 0.0;
         for( k = 0; k < n; k++ ) {
            if( pdata->sigma[icol] != 0.0 ) {
               sum += (*(paorig++))*(*(pa++))/pdata->sigma[icol];
            } else {
               paorig++;
               pa++;
               ps++;
            }
         }

         *(pu++) = sum;
      }

   } else if( *status == SAI__OK ){
      *status = SAI__ERROR;
      errRepf( "", "smf1_svd: Invalid operation (%d) supplied.",
               status, pdata->oper );
   }
}
Exemplo n.º 23
0
void smf_fit_pspec( const double *pspec, dim_t nf, size_t box, double df,
                    double minfreq, double whitefreq, double maxfreq,
                    double *a, double *b, double *w, int *status ) {

  double A=VAL__BADD;    /* Amplitude of 1/f component */
  double B=VAL__BADD;    /* Exponent of 1/f component */
  int converged;         /* Has white noise level calc converged? */
  double fit[2];         /* fit coefficients */
  size_t i;              /* Loop counter */
  size_t i_flo;          /* Index of lowest frequency for calculating 1/f  */
  size_t i_whi;          /* Index of high-freq. edge for white-noise level */
  size_t i_wlo;          /* Index of low-freq. edge for white-noise level */
  size_t nbad;           /* Number of outliers in white noise calc */
  smf_qual_t *qual=NULL; /* Quality to go with pspec */
  double sigma;          /* Uncertainty in white noise level */
  size_t thisnbad;       /* Outliers in white noise calc, this iteration */
  double white=VAL__BADD;/* White noise level */
  double *x=NULL;        /* Independent axis for 1/f fit */
  double *y=NULL;        /* Dependent axis for 1/f fit */

  if (*status != SAI__OK) return;

  if( (df<=0) || (nf<1) ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": invalid frequency information supplied.", status );
    return;
  }

  /* Convert frequencies to array indices (but only consider above DC) */
  i_flo = smf_get_findex( minfreq, df, nf, status );
  i_wlo = smf_get_findex( whitefreq, df, nf, status );

  if( !maxfreq ) {
    /* If maxfreq is 0 set to Nyquist */
    i_whi = nf-1;
  } else {
    i_whi = smf_get_findex( maxfreq, df, nf, status );
  }

  if( i_flo+box*2 > nf ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": box too large compared to number of frequencies",
            status );
    return;
  }

  /* Create a local quality array to go with pspec */
  qual = astCalloc( nf, sizeof(*qual) );

  if( i_flo == 0 ) i_flo = 1;

  if( (*status==SAI__OK) && ((i_flo > i_wlo) || (i_wlo > i_whi)) ) {
    *status = SAI__ERROR;
    errRepf( "", FUNC_NAME
            ": must have i_maxfreq (%zu) > i_whitefreq (%zu) > "
             "i_minfreq (%zu)", status, i_whi, i_wlo, i_flo );
  }

  /* Calculate the white noise level */
  converged = 0;
  nbad = 0;

  while( (!converged) && (*status==SAI__OK) ) {
    double thresh;

    smf_stats1D( pspec+i_wlo, 1, i_whi-i_wlo+1, qual, 1, SMF__Q_SPIKE, &white,
                 &sigma, NULL, NULL, status );

    if( *status==SAI__OK ) {

      thresh = white + SMF__FPSPEC_WHITESNR*sigma;
      thisnbad = 0;

      for( i=i_wlo; i<=i_whi; i++ ) {
        if( pspec[i] > thresh ) {
          qual[i] = SMF__Q_SPIKE;
          thisnbad++;
        }
      }

      if( thisnbad==nbad ) {
        converged = 1;
      }

      nbad = thisnbad;
    }
  }

  /* Now identify and fit the 1/f part of the power spectrum. We use a
     rolling box and increase the frequency of its centre until the fraction
     of samples below some threshold above the white level is exceeded.
     We then fit a straight line to the logarithm of the x- and y-axes. */

  if( *status == SAI__OK ) {
    size_t nfit;
    size_t ngood = 0;
    size_t nused;
    double thresh = white + SMF__FPSPEC_KNEESNR*sigma;

    /* Initialize ngood -- skip the DC term in the FFT */
    for( i=i_flo; i<(i_flo+box); i++ ) {
      if( pspec[i] > thresh ) {
        ngood++;
      }
    }

    /* Continuing from next element, and go until we hit the end or we reach
       the threshold number of samples below the threshold SNR above
       the white noise level. */

    for( i=i_flo+1; (i<(nf-(box-1))) && (ngood >= SMF__FPSPEC_KNEETHRESH*box);
         i++ ) {
      /* If the previous first element was good remove it */
      if( pspec[i-1] >= thresh ) {
        ngood--;
      }

      /* If the new last element is good add it */
      if( pspec[i+box-1] >= thresh ) {
        ngood++;
      }
    }

    /* We will fit the power-law from elements i_flo to nfit-1. We then
       evaluate the fitted power law as

                       y = A * x^B

       where x is the index in the frequency array
             A = exp( fit[0] )
             B = fit[1]                                           */

    nfit = i+box/2-i_flo;

    msgOutiff( MSG__DEBUG, "", FUNC_NAME
               ": i_flow=%zu nfit=%zu i_wlo=%zu i_whi=%zu\n", status,
               i_flo, nfit-1, i_wlo, i_whi);


    /* If we've entered the white-noise band in order to fit the 1/f
       noise give up */
    if( i >= i_wlo ) {
      *status = SMF__BADFIT;
      errRep( "", FUNC_NAME
              ": unable to fit 1/f spectrum with provided frequency ranges",
              status);
      goto CLEANUP;
    }

    /* Now fit a straight line to the log of the two axes */
    x = astMalloc( (nfit-1)*sizeof(*x) );
    y = astMalloc( (nfit-1)*sizeof(*y) );

    if( *status == SAI__OK ) {
      for( i=0; i<(nfit-1); i++ ) {
        x[i] = log((i+i_flo)*df);
        y[i] = log(pspec[i+i_flo]);
      }
    }

    smf_fit_poly1d( 1, nfit-1, 0, x, y, NULL, NULL, fit, NULL, NULL, &nused,
                    status );

    if( *status == SAI__OK ) {

      /* if the exponent is positive the fit is either garbage, or
         else there just isn't very much low frequency noise compared
         to the white noise level. Set B to 0 but generate a warning
         message */

      if( fit[1] >= 0 ) {
        *status = SMF__BADFIT;
        errRep( "", FUNC_NAME
                ": fit to 1/f component encountered rising spectrum!",
                status);
        goto CLEANUP;
      } else {
        B = fit[1];
      }

      A = (exp(fit[0]));
    }
  }

  /* Return fit values */
  if( a ) *a = A;
  if( b ) *b = B;
  if( w ) *w = white;

 CLEANUP:

  qual = astFree( qual );
  x = astFree( x );
  y = astFree( y );
}
Exemplo n.º 24
0
F77_SUBROUTINE(configecho)( INTEGER(STATUS) ){
/*
*+
*  Name:
*     CONFIGECHO

*  Purpose:
*     Displays one or more configuration parameters.

*  Language:
*     C (designed to be called from Fortran)

*  Type of Module:
*     ADAM A-task

*  Invocation:
*     CALL CONFIGECHO( STATUS )

*  Arguments:
*     STATUS = INTEGER (Given and Returned)
*        The global status.

*  Description:
*     This application displays the name and value of one or all
*     configuration parameters, specified using Parameters CONFIG or
*     NDF. If a single parameter is displayed, its value is also
*     written to an output parameter. If the parameter value is not
*     specified by the CONFIG, NDF or DEFAULTS parameter, then the
*     value supplied for DEFVAL is displayed.
*
*     If an input NDF is supplied then configuration parameters
*     are read from its history (see Parameters NDF and APPLICATION).
*
*     If values are supplied for both CONFIG and NDF, then the
*     differences between the two sets of configuration parameters
*     are displayed (see Parameter NDF).

*  Usage:
*     configecho name config [defaults] [select] [defval]

*  ADAM Parameters:
*     APPLICATION = LITERAL (Read)
*        When reading configuration parameters from the history
*        of an NDF, this parameter specifies the name of the application
*        to find in the history. There must be a history component
*        corresponding to the value of this parameter, and it must
*        include a CONFIG group. [current value]
*     CONFIG = GROUP (Read)
*        Specifies values for the configuration parameters. If the string
*        "def" (case-insensitive) or a null (!) value is supplied, the
*        configuration parameters are obtained using Parameter NDF. If
*        a null value is also supplied for NDF, a set of default
*        configuration parameter values will be used, as specified by
*        Parameter DEFAULTS.
*
*        The supplied value should be either a comma-separated list of
*        strings or the name of a text file preceded by an up-arrow
*        character "^", containing one or more comma-separated lists of
*        strings. Each string is either a "keyword=value" setting, or the
*        name of a text file preceded by an up-arrow character "^". Such
*        text files should contain further comma-separated lists which
*        will be read and interpreted in the same manner (any blank lines
*        or lines beginning with "#" are ignored). Within a text file,
*        newlines can be used as delimiters, as well as commas. Settings
*        are applied in the order in which they occur within the list,
*        with later settings overriding any earlier settings given for
*        the same keyword.
*
*        Each individual setting should be of the form "<keyword>=<value>".
*        If a non-null value is supplied for Parameter DEFAULTS, an error
*        will be reported if CONFIG includes values for any parameters
*        that are not included in DEFAULTS.
*     DEFAULTS = LITERAL (Read)
*        The path to a file containing the default value for every
*        allowed configuration parameter. If null (!) is supplied, no
*        defaults will be supplied for parameters that are not specified
*        by CONFIG, and no tests will be performed on the validity of
*        paramter names supplied by CONFIG. [!]
*     DEFVAL = LITERAL (Read)
*        The value to return if no value can be obtained for the named
*        parameter, or if the value is "<undef>".  [<***>]
*     NAME = LITERAL (Read)
*        The name of the configuration parameter to display.  If set to
*        null (!), then all parameters defined in the configuration are
*        displayed.
*     NDF = NDF (Read)
*        An NDF file containing history entries which include
*        configuration parameters. If not null (!) the history
*        of the NDF will be searched for a component corresponding
*        to the Parameter APPLICATION.  The Parameter CONFIG
*        is then optional, but if it too is not null (!) then
*        the output will show the differences between the configuration
*        stored in the NDF history and the given configuration:
*        new parameters and those different from the reference
*        configuration (given by Parameter CONFIG) are prefixed
*        with "+" and those which are the same as the reference
*        configuration are prefixed with "-". [!]
*     SELECT = GROUP (Read)
*        A group that specifies any alternative prefixes that can be
*        included at the start of any parameter name. For instance, if
*        this group contains the two entries "450=1" and "850=0", then
*        either CONFIG or DEFAULTS can specify two values for any single
*        parameter -- one for the parameter prefixed by "450." and another
*        for the parameter prefixed by "850.". Thus, for instance, if
*        DEFAULTS defines a parameter called "filter", it could include
*        "450.filter=300" and "850.filter=600". The CONFIG parameter could
*        then either set the filter parameter for a specific prefix (as
*        in "450.filter=234"); or it could leave the prefix unspecified,
*        in which case the prefix used is the first one with a
*        non-zero value in SELECT (450 in the case of this example - 850
*        has a value zero in SELECT). Thus the names of the items in
*        SELECT define the set of allowed alternative prefixes, and the
*        values indicate which one of these alternatives is to be used
*        (the first one with non-zero value). [!]
*     SORT = _LOGICAL (Read)
*        If TRUE then sort the listed parameters in to alphabetical order.
*        Otherwise, retain the order they have in the supplied
*        configuration. Only used if a null (!) value is supplied for
*        Parameter NAME. [FALSE]
*     VALUE = LITERAL (Write)
*        The value of the configuration parameter, or "<***>" if the
*        parameter has no value in CONFIG and DEFAULTS.

*  Examples:
*     configecho m81 ^myconf
*        Report the value of configuration parameter "m81" defined within
*        the file "myconf". If the file does not contain a value for
*        "m81", then "<***>" is displayed.
*     configecho type ^myconf select="m57=0,m31=1,m103=0"
*        Report the value of configuration parameter "type" defined within
*        the file "myconf". If the file does not contain a value for
*        "type", then the value of "m31.type" will be reported instead. If
*        neither is present, then "<***>" is displayed.
*     configecho flt.filt_edge_largescale \
*                config=^/star/share/smurf/dimmconfig.lis \
*                defaults=/star/bin/smurf/smurf_makemap.def \
*                select="450=1,850=0"
*        Report the value of configuration parameter "flt.filt_edge_largescale"
*        defined within the file "/star/share/smurf/dimmconfig.lis", using
*        defaults from the file "/star/bin/smurf/smurf_makemap.def". If
*        dimmconfig.lis does not contain a value for "flt.filt_edge_largescale"
*        then it is searched for "450.flt.filt_edge_largescale" instead. An
*        error is reported if dimmconfig.lis contains values for any
*        items that are not defined in smurf_makemap.def.
*     configecho ndf=omc1 config=^/star/share/smurf/dimmconfig.lis \
*                defaults=/star/bin/smurf/smurf_makemap.def \
*                application=makemap name=! sort select="450=0,850=1"
*        Show how the configuration used to generate the 850um map
*        of OMC1 differs from the basic dimmconfig.lis file.

*  Copyright:
*     Copyright (C) 2012-3 Science & Technology Facilities Council.
*     All Rights Reserved.

*  Licence:
*     This program is free software; you can redistribute it and/or
*     modify it under the terms of the GNU General Public License as
*     published by the Free Software Foundation; either Version 2 of
*     the License, or (at your option) any later version.
*
*     This program is distributed in the hope that it will be
*     useful, but WITHOUT ANY WARRANTY; without even the implied
*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
*     PURPOSE. See the GNU General Public License for more details.
*
*     You should have received a copy of the GNU General Public License
*     along with this program; if not, write to the Free Software
*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
*     02110-1301, USA.

*  Authors:
*     DSB: David S. Berry
*     GSB: Graham S. Bell
*     {enter_new_authors_here}

*  History:
*     10-DEC-2012 (DSB):
*        Original version.
*     6-FEB-2013 (DSB):
*        Added parameter DEFVAL.
*     11-FEB-2013 (DSB):
*        Added parameter SORT and allow all parameters to be listed by
*        providing a null value for NAME.
*     11-FEB-2013 (GSB):
*        Added ability to read configuration from history entries.
*     13-FEB-2013 (DSB):
*        Nullify AST object pointers when the objects are annulled,
*        to avoid re-use of dead pointers.
*     14-FEB-2013 (DSB):
*        Allow the SELECT feature to be used even if no DEFAULTS file is
*        supplied (see the new entry in the "Examples:" section).
*     15-FEB-2013 (DSB):
*        Expand the prologue docs, and use NULL in place of zero for pointers.
*     22-FEB-2013 (DSB):
*        Guard against seg fault in HistoryKeymap when the NDF does 
*        not contain the required CONFIG entry in the History 
*        component.
*     {enter_further_changes_here}

*-
*/

   GENPTR_INTEGER(STATUS)

/* Local Variables: */
   AstKeyMap *keymap2;
   AstKeyMap *keymap;
   Grp *grp = NULL;
   char *dot;
   char *pname;
   char defs[250];
   char defval[250];
   char name[250];
   const char *value;
   const char *historyValue = NULL;
   int showall;
   int sort;
   size_t size;
   int indf = 0;
   int nrec;
   int i;
   char application[NDF__SZAPP];
   char applicationi[NDF__SZAPP];

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

/* Begin an AST context */
   astBegin;

/* Get the value to return if no value can be obtained for the named
   parameter, of it it has a value of <undef>. */
   parGet0c( "DEFVAL", defval, sizeof(defval), STATUS );

/* Get any defaults file, annuling the error if null (!) is supplied. */
   if( *STATUS == SAI__OK ) {
      parGet0c( "DEFAULTS", defs, sizeof(defs), STATUS );
      if( *STATUS == PAR__NULL ) {
         errAnnul( STATUS );
         defs[0] = 0;
      }
   }

/* Get the NDF identifier if requested. */
   ndfBegin();
   if (*STATUS == SAI__OK) {
      ndfAssoc("NDF", "READ", &indf, STATUS);
      if (*STATUS == PAR__NULL) {
         errAnnul(STATUS);
         indf = 0;
      }
      else {
         parGet0c("APPLICATION", application, sizeof(application), STATUS);
         /* Check now for error because the block below allowing an undefined
          * CONFIG clears this status otherwise. */
         if (*STATUS != SAI__OK) goto L999;
      }
   }

/* See if any alternate keyword prefixes are allowed, and if so determine
   which of the alternatices is to be displayed. */
   kpg1Gtgrp( "SELECT", &grp, &size, STATUS );
   if( *STATUS == PAR__NULL ) {
      grpDelet( &grp, STATUS );
      errAnnul( STATUS );
      keymap2 = NULL;
   } else {
      kpg1Kymap( grp, &keymap2, STATUS );
      grpDelet( &grp, STATUS );
   }

/* Create a KeyMap holding the selected alternative for each keyword, and
   also supply defaults for any missing values (if a defaults file was
   supplied by the user). */
   keymap = kpg1Config( "CONFIG", defs[0]?defs:NULL, keymap2, 0, STATUS );

/* Allow it to be NULL if we're reading an NDF because we'll replace
   keymap with historyConfig later if necessary. */
   if( indf && *STATUS == PAR__NULL ) {
      errAnnul(STATUS);
      keymap = NULL;
   }

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

/* Get the name of the required parameter, and convert to upper case (if
   supplied). If not supplied, set a flag indicating that all parameters
   should be displayed. */
   parGet0c( "NAME", name, sizeof(name), STATUS );
   if( *STATUS == PAR__NULL ) {
      errAnnul( STATUS );
      showall = 1;
   } else {
      showall = 0;
      astChrCase( NULL, name, 1, 0 );
   }

/* Attempt to find the NDF's corresponding history record. */
   if (indf && *STATUS == SAI__OK) {
      ndfHnrec(indf, &nrec, STATUS);
      for (i = 0; i < nrec; i ++) {
         ndfHinfo(indf, "APPLICATION", i + 1, applicationi,
                  sizeof(applicationi), STATUS);
         if (! strncasecmp(application, applicationi, strlen(application))) {
            ndfHout(indf, i + 1, HistoryKeyMap, STATUS);
            break;
         }
      }

      if (*STATUS == SAI__OK && ! historyConfig) {
         *STATUS = SAI__ERROR;

         errRepf("CONFIGECHO_ERR", "CONFIGECHO: Failed to find %s "
                 "configuration in NDF history.", STATUS, application);
      }
      else if (! keymap) {
         keymap = historyConfig;
         historyConfig = NULL;
      }
   }

   if( *STATUS == SAI__OK ) {

/* First deal with cases where we are displaying a single parameter
   value. */
      if( !showall ) {

/* Loop round each section of the name that ends with a dot. */
         value = defval;
         pname = name;

         dot = strchr( pname, '.' );
         while( dot && keymap ) {

/* Get a nested keymap with the name that occurs prior to the dot. If
   found, use it in place of the parent keymap. */
            pname[ dot - pname ] = 0;
            if( astMapGet0A( keymap, pname, &keymap2 ) ) {
               astAnnul( keymap );
               keymap = keymap2;
            } else {
               keymap = astAnnul( keymap );
            }

/* If historyConfig exists, do the same there. */
            if (historyConfig) {
               if (astMapGet0A(historyConfig, pname, &keymap2)) {
                  astAnnul(historyConfig);
                  historyConfig = keymap2;
               }
               else {
                  historyConfig = astAnnul(historyConfig);
               }
            }

/* Re-instate the original dot, and move on to find the next dot. */
            pname[ dot - pname ] = '.';
            pname = dot + 1;
            dot = strchr( pname, '.' );
         }

/* Ensure no error is reported if the parameter is not found in the
   KeyMap. */
         if( keymap ) {
            astClear( keymap, "KeyError" );

/* Get the parameter value as a string. */
            astMapGet0C( keymap, pname, &value );
         }

         if (historyConfig) {
            astClear(historyConfig, "KeyError");
            astMapGet0C(historyConfig, pname, &historyValue);

/* In NDF history mode we only want to return a value if it
   was found in the configuration from the history. */

            if (historyValue) {
               if (strcmp(value, historyValue)) {
                  msgOutf("", "+ %s", STATUS, historyValue);
               }
               else {
                  msgOutf("", "- %s", STATUS, historyValue);
               }
               parPut0c("VALUE", historyValue, STATUS);
            }
         }
         else {
/* Display it. */
            msgOut( "", value, STATUS );

/* Write it to the output parameter. */
            parPut0c( "VALUE", value, STATUS );
         }

/* Now deal with cases were we are displaying all parameter values. */
      } else {

/* See if the values should be sorted. */
         parGet0l( "SORT", &sort, STATUS );

/* Display them. */
         if (historyConfig) {
            DisplayKeyMap( historyConfig , sort, "", keymap, STATUS );
         }
         else {
            DisplayKeyMap( keymap, sort, "", NULL, STATUS );
         }
      }
   }

/* Tidy up. */
L999:;

/* End the AST context */
   astEnd;

/* Close the NDF if open. */
   ndfEnd(STATUS);

/* If an error has occurred, issue another error report identifying the
   program which has failed (i.e. this one). */
   if( *STATUS != SAI__OK ) {
      errRep( "CONFIGECHO_ERR", "CONFIGECHO: Failed to echo configuration "
              "parameters.", STATUS );
   }

}
Exemplo n.º 25
0
static void smf1_calc_iqu_job( void *job_data, int *status ) {
/*
*  Name:
*     smf1_calc_iqu_job

*  Purpose:
*     Calculate I, Q and U for a block of bolometers.

*  Invocation:
*     void smf1_calc_iqu_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
*        smfCalcIQUJobData structure.
*     status = int * (Given and Returned)
*        Pointer to global status.

*  Description:
*     This routine calculate the I, Q and U values for each bolometer in
*     a block of bolometers. It runs within a thread instigated by
*     smf_calc_iqu.

*/

/* Local Variables: */
   const JCMTState *allstates;/* Pointer to array of JCMTState structures */
   const JCMTState *state;    /* JCMTState info for current time slice */
   dim_t b1;                  /* First bolometer index */
   dim_t b2;                  /* Last bolometer index */
   dim_t ibolo;               /* Bolometer index */
   dim_t ipix;                /* Pixel index */
   dim_t nbolo;               /* Total number of bolometers */
   double *dat;               /* Pointer to start of input data values */
   double *din0;              /* Pointer to input data array for 1st time */
   double *din;               /* Pointer to input data array for bolo/time */
   double *ipi;               /* Pointer to output I array */
   double *ipq;               /* Pointer to output Q array */
   double *ipu;               /* Pointer to output U array */
   double *pm;                /* Pointer to next time slice mean value */
   double angle;              /* Phase angle for FFT */
   double angrot;             /* Angle from focal plane X axis to fixed analyser */
   double cosval;             /* Cos of twice reference rotation angle */
   double i;                  /* Output I value */
   double paoff;              /* WPLATE value corresponding to POL_ANG=0.0 */
   double phi;                /* Angle from fixed analyser to effective analyser */
   double q0;                 /* Q value with respect to fixed analyser */
   double q;                  /* Output Q value */
   double s1;                 /* Sum of weighted cosine terms */
   double s2;                 /* Sum of weighted sine terms */
   double s3;                 /* Sum of weights */
   double sinval;             /* Sin of twice reference rotation angle */
   double sum;                /* Sum of bolometer values */
   double u0;                 /* U value with respect to fixed analyser */
   double u;                  /* Output U value */
   double v;                  /* Analysed intensity to use */
   double wplate;             /* Angle from fixed analyser to have-wave plate */
   int block_end;             /* Last time slice to process */
   int block_start;           /* First time slice to process */
   int ipolcrd;               /* Reference direction for pol_ang */
   int itime;                 /* Time slice index */
   int limit;                 /* Min no of good i/p values for a godo o/p value */
   int n;                     /* Number of contributing values in S1, S2 and S3 */
   int ncol;                  /* No. of bolometers in one row */
   int nn;                    /* Number of good bolometer values */
   int old;                   /* Data has old-style POL_ANG values? */
   int pasign;                /* +1 or -1 indicating sense of POL_ANG value */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfCalcIQUJobData *pdata;  /* Pointer to job data */
   smf_qual_t *qin0;          /* Pointer to input quality array for 1st time */
   smf_qual_t *qin;           /* Pointer to input quality array for bolo/time */
   smf_qual_t *qua;           /* Pointer to start of input quality values */

/* 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 = (smfCalcIQUJobData *) job_data;

   b1 = pdata->b1;
   b2 = pdata->b2;
   bstride = pdata->bstride;
   dat = pdata->dat;
   nbolo = pdata->nbolo;
   qua = pdata->qua;
   tstride = pdata->tstride;
   allstates = pdata->allstates;
   ipi = pdata->ipi;
   ipq = pdata->ipq;
   ipu = pdata->ipu;
   ipolcrd = pdata->ipolcrd;
   block_start = pdata->block_start;
   block_end = pdata->block_end;
   old = pdata->old;
   ncol = pdata->ncol;
   pasign = pdata->pasign;
   paoff = pdata->paoff;
   angrot = pdata->angrot;

/* Calculate Q and U if required. */
   if( pdata->action == 0 ) {

/* Check we have something to do. */
      if( b1 < nbolo ) {

/* The minimum number of samples required for a good output value. Half
   of the available input samples must be good. */
         limit = 0.5*( block_end - block_start );

/* Initialise pointers to the first time slice data and quality value for
   the first bolometer to be processed in the current block of time slices. */
         din0 = dat + bstride*b1 + tstride*block_start;
         qin0 = qua + bstride*b1 + tstride*block_start;

/* Loop round all bolometers to be processed by this thread. */
         for( ibolo = b1; ibolo <= b2; ibolo++ ) {

/* If the whole bolometer is bad, just use bad q and u values. */
            if( *qin0 & SMF__Q_BADB ) {
               i = VAL__BADD;
               u = VAL__BADD;
               q = VAL__BADD;

/* If the bolometer is good, calculate and store the q and u values. */
            } else {

/* Initialise pointers to the next time slice data and quality value for
   the current bolometer. */
               din = din0;
               qin = qin0;

/* Initialise the sums used to find Q and U at this bolometer. */
               s1 = 0.0;
               s2 = 0.0;
               s3 = 0.0;
               n = 0.0;

/* Loop round all time slices. */
               pm = pdata->mean;
               if( pm )  pm += block_start;
               state = allstates + block_start;
               for( itime = block_start; itime <= block_end; itime++,state++ ) {

/* Get the POL_ANG value for this time slice. */
                  angle = state->pol_ang;

/* Check the input sample has not been flagged during cleaning and is
   not bad. */
                  if( !( *qin & SMF__Q_FIT ) && *din != VAL__BADD &&
                      angle != VAL__BADD && ( !pm || *pm != VAL__BADD ) ) {

/* If POL_ANG is stored in arbitrary encoder units, convert to radians. */
                     if( old ) angle = angle*TORADS;

/* Following SUN/223 (section "Single-beam polarimetry"/"The Polarimeter"),
   get the angle from the fixed analyser to the half-waveplate axis, in radians.
   Positive rotation is from focal plane axis 1 (x) to focal plane axis 2 (y).

   Not sure about the sign of tcs_az/tr_ang at the moment so do not use them
   yet. */
                     wplate = 0.0;
                     if( ipolcrd == 0 ) {
                        wplate = pasign*angle + paoff;

                     } else if( *status == SAI__OK ) {
                        *status = SAI__ERROR;
                        errRepf( "", "smf_calc_iqu: currently only POL_CRD = "
                                 "FPLANE is supported.", status );
                     }

/*
                  if( ipolcrd == 1 ) {
                     wplate += state->tcs_az_ang;
                  } else if( ipolcrd == 2 ) {
                     wplate += state->tcs_tr_ang;
                  }
*/

/* Get the angle from the fixed analyser to the effective analyser
   position (see SUN/223 again). The effective analyser angle rotates twice
   as fast as the half-wave plate which is why there is a factor of 2 here. */
                     phi = 2*wplate;

/* Increment the sums needed to find the Fourier component of the time
   series corresponding to the frequency introduced by the rotation of
   the half wave plate. */
                     angle = 2*phi;
                     v = pm ? *din - *pm : *din;
                     s1 += v*cos( angle );
                     s2 += v*sin( angle );
                     s3 += v;
                     n++;
                  }

/* Update pointers to the next time slice data and quality value for
   the current bolometer. */
                  din += tstride;
                  qin += tstride;
                  if( pm ) pm++;
               }

/* Calculate the q, u and i values in the output NDF. The error on these values
   will be enormous if there are not many values, so use a large lower limit.
   These use the fixed analyser as the reference direction. */
               if( n > limit ) {
                  q0 = 4*s1/n;
                  u0 = 4*s2/n;
                  i = 2*s3/n;

/* Modify Q and U so they use the focal plane Y as the reference direction. */
                  cosval = cos(2*angrot);
                  sinval = sin(2*angrot);
                  q = -q0*cosval + u0*sinval;
                  u = -q0*sinval - u0*cosval;

               } else {
                  q = VAL__BADD;
                  u = VAL__BADD;
                  i = VAL__BADD;
               }
            }

/* Calculate the vector index into the output NDFs at which to store the
   current bolometer. This implements a reversal of the pixels along each
   row, in order to produce the usual right-handed view of the sky. */
            ipix = ncol + ibolo - 2*( ibolo % ncol ) - 1;

/* Store the q and u values in the output NDFs. */
            ipq[ ipix ] = q;
            ipu[ ipix ] = u;
            if( ipi ) ipi[ ipix ] = i;

/* Update the pointers to the first time slice data and quality value for
   the next bolometer. */
            din0 += bstride;
            qin0 += bstride;
         }
      }

/* Calculate mean value in each time slice if required. */
   } else {

      pm = pdata->mean + block_start;
      for( itime = block_start; itime <= block_end; itime++,pm++ ) {
         din = dat + itime*tstride;
         qin = qua + itime*tstride;

         sum = 0;
         nn = 0;

         for( ibolo = 0; ibolo < nbolo; ibolo++ ) {

            if( !( *qin & SMF__Q_FIT ) && *din != VAL__BADD ) {
               sum += *din;
               nn++;

            }

            din += bstride;
            qin += bstride;
         }

         if( nn > 0 ) {
            *pm = sum/nn;
         } else {
            *pm = VAL__BADD;
         }
      }

   }


}
Exemplo n.º 26
0
void smf_export_noi( smfData *noi, const char *name, int boxsize, int *status ){

/* Local Variables */
   HDSLoc *xloc = NULL;
   dim_t ntslice;
   dim_t nrows;
   dim_t ncols;
   dim_t nbolo;
   double *ip;
   double *dataptr;
   double *dp;
   double *pd;
   int el;
   int ibolo;
   int indf;
   int itime;
   int lbnd[ 3 ];
   int nz;
   int place;
   int ubnd[ 3 ];
   size_t bstride;
   size_t tstride;
   int iz;

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

/* Report an error if the number of time slices that share a single NOI
   value is not known. */
   if( boxsize == 0 ) {
      *status = SAI__ERROR;
      errRep( "", "smf_export_noi: noise boxsize is not yet known "
              "(programming error).", status );
      return;
   }

/* Get the dimensions of the NOI model. */
   smf_get_dims( noi, &nrows, &ncols, &nbolo, &ntslice, NULL, &bstride,
                 &tstride, status );

/* Determine the number of boxes to use. This is the length of 3rd axis.
   of the new NDF. */
   if( ntslice == 1 ) {
      nz = 1;
   } else {
      nz = ntslice / boxsize;
   }

   if( nz <= 0 && *status == SAI__OK ){
      *status = SAI__ERROR;
      errRepf("", "smf_export_noi: boxsize (%d) and ntslice (%d) are "
              "inconsistent (programming error).", status, boxsize,
              (int) ntslice );
   }

/* Get a pointer to the NOI data values. */
   dataptr = noi->pntr[ 0 ];

/* Create the NDF. Use the axis ordering needed by smf_model_create. This
   avoid re-ordering the values every time it is read in. */
   ndfPlace( NULL, name, &place, status );
   lbnd[ 0 ] = 1;
   lbnd[ 1 ] = 1;
   lbnd[ 2 ] = 1;
   ubnd[ 0 ] = nz;
   ubnd[ 1 ] = ncols;
   ubnd[ 2 ] = nrows;
   ndfNew( "_DOUBLE", 3, lbnd, ubnd, &place, &indf, status );

/* Map the Data array of the NDF and copy the NOI values into it. */
   ndfMap( indf, "DATA", "_DOUBLE", "WRITE", (void **) &ip, &el, status );
   if( *status == SAI__OK ) {

/* Initialise the time slice at the middle of the current box in the model. */
      itime = ( nz == 1 ) ? 0 : boxsize/2;

/* We step sequentially through teh NDF pixels. Initialise a pointer to
   the first pixel value. */
      pd = ip;

/* Loop round each bolometer. */
      for( ibolo = 0; ibolo < (int) nbolo; ibolo++ ) {

/* Get a pointer to the noise value for the current bolometer at the
   centre of the first box. */
         dp = dataptr + ibolo*bstride + itime*tstride;

/* Now loop round each box of time slices. */
         for( iz = 0; iz < nz; iz++ ) {

/* The NOI model is filled with 1.0 values by smf_model_create, and can also
   be set to zero to indicate missing values. Therefore convert both these
   values into VAL__BADD. */
            *(pd++) = (*dp == 0.0 || *dp == 1.0) ? VAL__BADD : *dp;

/* Move the input pointer on to the next box. */
            dp += boxsize*tstride;
         }
      }

/* Store the box size as an extension item in the NDF. */
      ndfXnew( indf, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &xloc, status );
      ndfXpt0i( boxsize, indf, SMURF__EXTNAME, "NOI_BOXSIZE", status );
      datAnnul( &xloc, status );
   }

/* Annul the NDF identifier. */
   ndfAnnul( &indf, status );
}
Exemplo n.º 27
0
smf_qual_t * smf_qual_unmap( ThrWorkForce *wf, int indf, smf_qfam_t family,
                             smf_qual_t * qual, smf_qual_t mask, int * status ) {
  int canwrite = 0;   /* can we write to the file? */
  size_t nqbits = 0;  /* Number of quality bits in this family */
  SmfQualUnmapData *job_data = NULL;
  SmfQualUnmapData *pdata;
  int nw;
  size_t step;
  int iw;

  if (*status != SAI__OK) goto CLEANUP;

  /* do nothing if there is no quality */
  if (!qual) return NULL;

  /* if we do not have an NDF identifier we just free the memory */
  if (indf == NDF__NOID) goto CLEANUP;

  /* See if we have WRITE access to the file */
  ndfIsacc( indf, "WRITE", &canwrite, status );

  /* if we have WRITE access and the data were not mapped we have
     to copy to the file. Also check we have a non-NULL input pointer.
     If the data were mapped we still have to make sure the quality names
     are stored. */
  if ( canwrite && qual ) {
    int highbit = -1; /* highest bit used */
    size_t i;
    int itemp;
    int lowbit = -1;  /* Lowest bit used */
    size_t nout;
    int nqual = 0;
    void *qpntr[1];
    size_t qcount[SMF__NQBITS]; /* statically allocate the largest array */
    IRQLocs *qlocs;
    unsigned char * qmap;
    int there;

    ndfMsg( "FILE", indf );
    msgOutif( MSG__DEBUG, "", "Finalising quality for file ^FILE", status);

    if (family == SMF__QFAM_TCOMP ) {
      /* note that TCOMP is not an allowed quality because SMURF should not be
         using it anywhere in a permanent way. */
      *status = SAI__ERROR;
      ndfMsg( "NDF", indf );
      errRepf( "", "Unsupported quality family '%s' for quality unmapping of "
               "file ^NDF", status, smf_qfamily_str(family,status) );
      goto CLEANUP;
    } else if (family == SMF__QFAM_NULL) {
      /* In this case we have to assume that we just cast the quality
         to UBYTE and copy it without changing anything or naming the
         entries. Use a simple type conversion. */
      ndfMap( indf, "QUALITY", "_UBYTE", "WRITE", &qpntr[0], &itemp, status );
      qmap = qpntr[0];
      nout = itemp;

      for (i = 0; i<nout; i++) {
        qmap[i] = qual[i];
      }
      ndfUnmap( indf, "QUALITY", status );

      /* Turn on all quality */
      ndfSbb( 255, indf, status );

      /* we are finished so jump to tidy up */
      goto CLEANUP;
    }

    /* work out how many quality items are in this family */
    nqbits = smf_qfamily_count( family, status );

    /* initialize qcount */
    for (i=0; i<SMF__NQBITS; i++) {
      qcount[i] = 0;
    }

    /* how many pixels in NDF (assumed to be number in quality) */
    ndfSize( indf, &itemp, status );
    nout = itemp;

    /* 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->nqbits = nqbits;
        pdata->qual = qual;
        pdata->nout = nout;
      }
    }

    /* Work out which bits are actually used */
    if (*status == SAI__OK) {
      size_t k;
      /* now we try to be a bit clever. It may be a mistake since we have to
         do multiple passes through "qual". First determine how many quality
         bits are actually set. */

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

      for( iw = 0; iw < nw; iw++ ) {
        pdata = job_data + iw;
        for( k=0; k<nqbits; k++ ) {
          qcount[k] += pdata->qcount[k];
        }
      }

      /* Reset the counts to zero for any bits that are not required
         (i.e. are not set in "mask").  */
      for( k=0; k<nqbits; k++ ) {
         if( ! (mask & (1<<k)) ) qcount[k] = 0;
      }

      /* see how many we got */
      for (k=0; k<nqbits; k++) {

        if ( qcount[k] ) {
          nqual++;
          highbit = k;
          if (lowbit < 0) lowbit = k;
        }
      }
    }

    /* for IRQ we need to ensure the SMURF extension exists so open and annul it if it is missing.
       We are completely rewriting any IRQ information so we have to delete any previously existing
       IRQ extension. */
    irqDelet( indf, status );
    ndfXstat( indf, SMURF__EXTNAME, &there, status );
    if (!there) {
      HDSLoc * smurfloc = NULL;
      /* Create SMURF extension if it does not already exist */
      ndfXnew( indf, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &smurfloc, status );
      if (smurfloc) datAnnul( &smurfloc, status );
    }
    irqNew( indf, SMURF__EXTNAME, &qlocs, status );

    /* malloced so we need to map and copy over the values. IRQ
       names need to be set BEFORE we copy. */

    /* Map the quality component with WRITE access */
    ndfMap( indf, "QUALITY", "_UBYTE", "WRITE", &qpntr[0], &itemp, status );
    qmap = qpntr[0];

    /* we assume the number of elements in "qual" is the same as in "qmap" */
    if (*status == SAI__OK) {
      size_t k;

      /* if we only have 8 or fewer bits active we can just compress
         by mapping them to the lower 8 bits. This will work if we also
         set the IRQ quality names in the NDF. */
      if (nqual == 0 ) {
        /* easy */
        memset( qmap, 0, nout * smf_dtype_sz( SMF__UBYTE, status ) );
      } else if ( nqual <= 8 ) {
        size_t curbit = 0;

        /* and the quality names. Start at lowbit and go to highbit
           knowing that we have shifted them down so that lowbit in qual
           is bit 0 in NDF. */
        for (k=lowbit; k<=(size_t)highbit; k++) {
          if (qcount[k]) {
            int fixed = 0;             /* is bit fixed? */
            const char * qdesc = NULL; /* Description of quality */
            const char * qstr = NULL;  /* Quality string identifier */
            curbit++;
            qstr = smf_qual_str( family, 1, k, &qdesc, status );

            irqAddqn( qlocs, qstr, 0, qdesc, status );
            irqFxbit( qlocs, qstr, curbit, &fixed, status );
          }
        }

        /* shift them down */
        for( iw = 0; iw < nw; iw++ ) {
          pdata = job_data + iw;
          pdata->operation = 2;
          pdata->qmap = qmap;
          pdata->highbit = highbit;
          pdata->lowbit = lowbit;
          for( k=0; k<nqbits; k++ ) {
            pdata->qcount[k] = qcount[k];
          }
          thrAddJob( wf, 0, pdata, smf1_qual_unmap, 0, NULL, status );
        }
        thrWait( wf, status );

      } else {
        size_t curbit = 0;

        /* Quality names are now needed and we have to write them
           all out because we have not compressed the bits in the
           output quality array we've only compressed the input.
           To limit the number of active bits we'd have to copy the
           compressed bits to the output and then set the quality
           names but IRQ does not let you do that so you would need
           to run through the entire array first counting which bits
           were used. */

        for (k=0; k<SMF__NQBITS_TCOMP; k++) {
          int fixed = 0;
          const char * qdesc = NULL; /* Description of quality */
          const char * qstr = NULL;  /* Quality string identifier */
          qstr = smf_qual_str( SMF__QFAM_TCOMP, 1, k, &qdesc, status );

          /* Set the quality name */
          irqAddqn( qlocs, qstr, 0, qdesc, status );
          curbit++;
          irqFxbit( qlocs, qstr, curbit, &fixed, status );
        }

        /* compress them */
        for( iw = 0; iw < nw; iw++ ) {
          pdata = job_data + iw;
          pdata->operation = 3;
          pdata->qmap = qmap;
          thrAddJob( wf, 0, pdata, smf1_qual_unmap, 0, NULL, status );
        }
        thrWait( wf, status );

      }
    }

    /* Unmap quality */
    ndfUnmap( indf, "QUALITY", status );

    /* Set the badbits mask to enable all quality by default.
       Do not do this for MAP quality at the moment. */
    if (family != SMF__QFAM_MAP) ndfSbb( 255, indf, status );

    /* release IRQ resources */
    irqRlse( &qlocs, status );
  }

 CLEANUP:
  /* Tidy up */
  qual = astFree( qual );
  job_data = astFree( job_data );
  return NULL;

}
Exemplo n.º 28
0
void smurf_jsatileinfo( int *status ) {

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

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

/* Decide what sort of projection to use. */
   parChoic( "PROJ", "HPX", "HPX,HPX12,XPHN,XPHS", 1, text, sizeof(text),
             status );
   proj = smf_jsaproj_fromstr( text, 1, status );

/* 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, proj, 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/BAD", (void **) &ipntr, &el,
              status );

/* Create all-sky map using XPH projection. */
      if( *status == SAI__OK ) {

/* Loop round every tile index. */
         for( jtile = 0; jtile < skytiling.ntiles; jtile++ ) {

/* Get the zero-based (x,y) indices of the tile within an HPX projection.
   This flips the bottom left half-facet up to the top right. */
            smf_jsatilei2xy( jtile, &skytiling, &xt, &yt, NULL, status );

/* Convert these HPX indices to the corresponding indices within the
   required projection. Note, the lower left facet is split by the above
   call to smf_jsatilei2xy tile (i.e. (xt,yt) indices are *not* in the
   "raw" mode). For instance, (0,0) is not a valid tile. */
            smf_jsatilexyconv( &skytiling, proj, xt, yt, 0, &xt, &yt, status );

/* Get the vector index of the corresponding element of the all-sky NDF. */
            if( proj == SMF__JSA_HPX || proj == SMF__JSA_HPX12 ) {
               iv = xt + 5*skytiling.ntpf*yt;
            } else {
               iv = xt + 4*skytiling.ntpf*yt;
            }

/* Report an error if this element has already been assigned a tile
   index. Otherwise, store the tile index. */
            if( ipntr[ iv ] == VAL__BADI ) {
               ipntr[ iv ] = jtile;
            } else if( *status == SAI__OK ) {
               *status = SAI__ERROR;
               errRepf( "", "%s projection assigns multiple tiles to "
                        "pixel (%d,%d).", status, text, xt, yt );
               break;
            }
         }
      }

/* 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,  proj, &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 );

/* Get the RA,Dec at the tile centre. */
   if( astTest( fs, "SkyRef" ) ) {
      ra0 = astGetD( fs, "SkyRef(1)" );
      dec0 = astGetD( fs, "SkyRef(2)" );

/* 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] = ra0;
      norm_radec[1] = dec0;
      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 );

/* Transform 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 ] = point1[ 0 ];         /* Bottom left */
      gy[ 0 ] = point1[ 1 ];

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

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

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

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

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

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

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

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

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

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

/* Convert from radius to diameter. */
      maxdist *= 2.0;

/* Format this size as a dec value (i.e. arc-distance) and display it. */
      if( maxdist > 0.0 ) {
         msgSetc( "SIZE",  astFormat( fs, 2, maxdist ) );
         msgOut( " ", "      Size: ^SIZE", status );
      } else {
         maxdist = AST__BAD;
         msgOut( " ", "      Size: <unknown>", status );
      }

/* If a discontinuity passes through the tile, the centre and size may be
   unknown. */
   } else {
      ra0 = AST__BAD;
      dec0 = AST__BAD;
      maxdist = AST__BAD;
      msgOut( " ", "      Centre (ICRS): RA=<unknown> DEC=<unknown>", status );
      msgOut( " ", "      Size: <unknown>", status );
   }

/* Write the tile centre ra and dec in radians to the output parameters. */
   parPut0d( "RACEN", norm_radec[ 0 ], status );
   parPut0d( "DECCEN", norm_radec[ 1 ], 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);
   }
}
Exemplo n.º 29
0
void smfParallelTime( void *job_data_ptr, int *status ) {
  smfArray **array=NULL;       /* array of smfArrays that we're working on */
  smfTimeChunkData *data=NULL; /* Pointer to job data */
  smfFilter *filt=NULL;        /* Frequency domain filter */
  size_t i;                    /* Loop counter */
  size_t j;                    /* Loop counter */
  size_t k;                    /* Loop counter */
  dim_t nbolo;                 /* Number of bolos in smfData */
  dim_t ndata;                 /* Size of DATA component in smfData */
  dim_t ntslice;               /* Number of time slices in smfData */
  dim_t nsub;                  /* Number of subarrays */
  double *val=NULL;            /* Pointer to DATA component of smfData */

  if( *status != SAI__OK ) return;

  /* Pointer to the data that this thread will process */
  data = job_data_ptr;

  /* Check for valid inputs */
  if( !data ) {
    *status = SAI__ERROR;
    errRep( "", "smfParallelTime: job_data_ptr is NULL.", status );
    return;
  }

  if( !(array=data->data) ) {
    *status = SAI__ERROR;
    errRep( "", "smfParallelTime: data array is NULL.", status );
    return;
  }

  /* Message indicating the thread started */
  msgSeti( "C1", data->chunk1);
  msgSeti( "C2", data->chunk2);
  msgOutif( MSG__DEBUG, "",
            "-- parallel time: thread starting on chunks ^C1 -- ^C2",
            status );

  /* Loop over time chunk. Some chunks may be flagged to skip if
     chunk1=nchunks */
  for( i=data->chunk1; (i<=data->chunk2)&&(i<data->nchunks)&&(*status==SAI__OK);
       i++ ) {

    nsub = array[i]->ndat;

    /* Initialize filter -- assume same data dimensions for all subarrays */
    if( data->type == 2 ) {
      filt = smf_create_smfFilter( array[i]->sdata[0], status );
      smf_filter_ident( filt, 1, status );
    }

    /* Loop over subarray */
    for( j=0; (j<nsub)&&(*status==SAI__OK); j++ ) {
      /* Change to bolo-ordered data */

      if( data->type == 0 ) {
        /* --- Re-order the data --- */
        smf_dataOrder( array[i]->sdata[j], 0, status );
      }

      smf_get_dims( array[i]->sdata[j], NULL, NULL, &nbolo, &ntslice, &ndata,
                    NULL, NULL, status );

      if( data->type == 1 ) {
        /* --- Boxcar smooth the data --- */
        for( k=0; (*status==SAI__OK)&&(k<nbolo); k++ ) {
          val = array[i]->sdata[j]->pntr[0];
          val += k*ntslice;

          /* Boxcar smooth each bolometer by 500 samples */
          smf_boxcar1D( val, ntslice, 500, NULL, 0, status );
        }
      }

      if( data->type == 2 ) {
        /* --- FFT filter the data --- */
        smf_filter_execute( NULL, array[i]->sdata[j], filt, 0, 0, status );
      }
    }

    if( filt ) filt = smf_free_smfFilter( filt, status );
  }


  /* Message indicating the thread started */
  msgSeti( "C1", data->chunk1);
  msgSeti( "C2", data->chunk2);
  msgOutif( MSG__DEBUG, "",
            "-- parallel time: thread finished chunks ^C1 -- ^C2",
            status );

  /* Try setting some status in thread to test merging mechanism */
  *status = SMF__INSMP;
  errRepf( " ", "Set SMF__INSMP in thread chunks %zu -- %zu", status,
           data->chunk1, data->chunk2 );
}
Exemplo n.º 30
0
void smf_rebinmap1( ThrWorkForce *wf, smfData *data, smfData *variance, int *lut,
                    size_t tslice1, size_t tslice2, int trange,
                    int *whichmap, dim_t nmap, smf_qual_t mask, int sampvar,
                    int flags, double *map, double *mapweight,
                    double *mapweightsq, int *hitsmap,
                    double *mapvar, dim_t msize, double *scalevariance,
                    int *status ) {

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

            /* Store other values common to all jobs. */
            pdata->msize = msize;
            pdata->nbolo = nbolo;
            pdata->t1 = t1;
            pdata->t2 = t2;
            pdata->vntslice = vntslice;
            pdata->dat = dat;
            pdata->map = map;
            pdata->mapvar = mapvar;
            pdata->mapweightsq = mapweightsq;
            pdata->mapweight = mapweight;
            pdata->var = var;
            pdata->hitsmap = hitsmap;
            pdata->lut = lut;
            pdata->whichmap = whichmap;
            pdata->dbstride = dbstride;
            pdata->dtstride = dtstride;
            pdata->vbstride = vbstride;
            pdata->vtstride = vtstride;
            pdata->mask = mask;
            pdata->qual = qual;
            pdata->mbufsize = mbufsize;
        }
    }


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

        if( sampvar ) {

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

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

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

            }

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

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

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

            }
        }


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

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

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

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

        /* Find how many buffer pixels to process in each worker thread. May be
           different to the number of map pixels set up earlier. */
        pixstep = mbufsize/nw;
        if( pixstep == 0 ) pixstep = 1;

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


        if( sampvar || !var ) {

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

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

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

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

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

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

        }
    }

    job_data = astFree( job_data );

}