예제 #1
0
// ----- local function definitions ----------
static int
XLALComputeFstatDemod ( FstatResults* Fstats,
                        const FstatCommon *common,
                        void *method_data
                      )
{
  // Check input
  XLAL_CHECK(Fstats != NULL, XLAL_EFAULT);
  XLAL_CHECK(common != NULL, XLAL_EFAULT);
  XLAL_CHECK(method_data != NULL, XLAL_EFAULT);

  DemodMethodData *demod = (DemodMethodData*) method_data;
  // get internal timing info
  DemodTimingInfo *ti = &(demod->timingInfo);
  REAL8 tic = 0, toc = 0;

  // Get which F-statistic quantities to compute
  const FstatQuantities whatToCompute = Fstats->whatWasComputed;

  // handy shortcuts
  BOOLEAN returnAtoms = (whatToCompute & FSTATQ_ATOMS_PER_DET);
  PulsarDopplerParams thisPoint = Fstats->doppler;
  const REAL8 fStart = thisPoint.fkdot[0];
  const MultiSFTVector *multiSFTs = demod->multiSFTs;
  const MultiNoiseWeights *multiWeights = common->multiNoiseWeights;
  const MultiDetectorStateSeries *multiDetStates = common->multiDetectorStates;

  UINT4 numDetectors = multiSFTs->length;
  XLAL_CHECK ( multiDetStates->length == numDetectors, XLAL_EINVAL );
  XLAL_CHECK ( multiWeights==NULL || (multiWeights->length == numDetectors), XLAL_EINVAL );
  UINT4 numSFTs = 0;
  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
    numSFTs += multiDetStates->data[X]->length;
  }

  // initialize timing info struct
  if ( ti->collectTiming )
    {
      XLAL_INIT_MEM ( (*ti) );
      ti->collectTiming = 1;

      ti->numDetectors = numDetectors;
      ti->numFreqBins = Fstats->numFreqBins;
      ti->numSFTs = numSFTs;

      tic = XLALGetCPUTime();
    }

  MultiSSBtimes *multiSSB = NULL;
  MultiAMCoeffs *multiAMcoef = NULL;
  // ----- check if we have buffered SSB+AMcoef for current sky-position
  if ( (demod->prevAlpha == thisPoint.Alpha) && (demod->prevDelta == thisPoint.Delta ) &&
       (demod->prevMultiSSBtimes != NULL) && ( XLALGPSDiff(&demod->prevRefTime, &thisPoint.refTime) == 0 ) &&	// have SSB times for same reftime?
       (demod->prevMultiAMcoef != NULL)
       )
    { // if yes ==> reuse
      multiSSB    = demod->prevMultiSSBtimes;
      multiAMcoef = demod->prevMultiAMcoef;
    }
  else
    { // if not, compute SSB + AMcoef for this skyposition
      SkyPosition skypos;
      skypos.system = COORDINATESYSTEM_EQUATORIAL;
      skypos.longitude = thisPoint.Alpha;
      skypos.latitude  = thisPoint.Delta;
      XLAL_CHECK ( (multiSSB = XLALGetMultiSSBtimes ( multiDetStates, skypos, thisPoint.refTime, common->SSBprec )) != NULL, XLAL_EFUNC );
      XLAL_CHECK ( (multiAMcoef = XLALComputeMultiAMCoeffs ( multiDetStates, multiWeights, skypos )) != NULL, XLAL_EFUNC );

      // store these for possible later re-use in buffer
      XLALDestroyMultiSSBtimes ( demod->prevMultiSSBtimes );
      demod->prevMultiSSBtimes = multiSSB;
      demod->prevRefTime = thisPoint.refTime;
      XLALDestroyMultiAMCoeffs ( demod->prevMultiAMcoef );
      demod->prevMultiAMcoef = multiAMcoef;
      demod->prevAlpha = thisPoint.Alpha;
      demod->prevDelta = thisPoint.Delta;
    } // if could not reuse previously buffered quantites

  MultiSSBtimes *multiBinary = NULL;
  MultiSSBtimes *multiSSBTotal = NULL;
  // handle binary-orbital timing corrections, if applicable
  if ( thisPoint.asini > 0 )
    {
      // compute binary time corrections to the SSB time delays and SSB time derivitive
      XLAL_CHECK ( XLALAddMultiBinaryTimes ( &multiBinary, multiSSB, &thisPoint ) == XLAL_SUCCESS, XLAL_EFUNC );
      multiSSBTotal = multiBinary;
    }
  else
    {
      multiSSBTotal = multiSSB;
    }

  if ( ti->collectTiming ) {
    toc = XLALGetCPUTime();
    ti->tauBary = (toc - tic);
  }

  // ----- compute final Fstatistic-value -----
  REAL4 Ad = multiAMcoef->Mmunu.Ad;
  REAL4 Bd = multiAMcoef->Mmunu.Bd;
  REAL4 Cd = multiAMcoef->Mmunu.Cd;
  REAL4 Ed = multiAMcoef->Mmunu.Ed;;
  REAL4 Dd_inv = 1.0 / multiAMcoef->Mmunu.Dd;

  // ---------- Compute F-stat for each frequency bin ----------
  for ( UINT4 k = 0; k < Fstats->numFreqBins; k++ )
    {
      // Set frequency to search at
      thisPoint.fkdot[0] = fStart + k * Fstats->dFreq;

      COMPLEX8 Fa = 0;       		// complex amplitude Fa
      COMPLEX8 Fb = 0;                 // complex amplitude Fb
      MultiFstatAtomVector *multiFstatAtoms = NULL;	// per-IFO, per-SFT arrays of F-stat 'atoms', ie quantities required to compute F-stat

      // prepare return of 'FstatAtoms' if requested
      if ( returnAtoms )
        {
          XLAL_CHECK ( (multiFstatAtoms = XLALMalloc ( sizeof(*multiFstatAtoms) )) != NULL, XLAL_ENOMEM );
          multiFstatAtoms->length = numDetectors;
          XLAL_CHECK ( (multiFstatAtoms->data = XLALMalloc ( numDetectors * sizeof(*multiFstatAtoms->data) )) != NULL, XLAL_ENOMEM );
        } // if returnAtoms

      // loop over detectors and compute all detector-specific quantities
      for ( UINT4 X=0; X < numDetectors; X ++)
        {
          COMPLEX8 FaX, FbX;
          FstatAtomVector *FstatAtoms = NULL;
          FstatAtomVector **FstatAtoms_p = returnAtoms ? (&FstatAtoms) : NULL;

          // call XLALComputeFaFb_...() function for the user-requested hotloop variant
          XLAL_CHECK ( (demod->computefafb_func) ( &FaX, &FbX, FstatAtoms_p, multiSFTs->data[X], thisPoint.fkdot,
                                                   multiSSBTotal->data[X], multiAMcoef->data[X], demod->Dterms ) == XLAL_SUCCESS, XLAL_EFUNC );

          if ( returnAtoms ) {
            multiFstatAtoms->data[X] = FstatAtoms;     // copy pointer to IFO-specific Fstat-atoms 'contents'
          }

          XLAL_CHECK ( isfinite(creal(FaX)) && isfinite(cimag(FaX)) && isfinite(creal(FbX)) && isfinite(cimag(FbX)), XLAL_EFPOVRFLW );

          if ( whatToCompute & FSTATQ_FAFB_PER_DET )
            {
              Fstats->FaPerDet[X][k] = FaX;
              Fstats->FbPerDet[X][k] = FbX;
            }

          // compute single-IFO F-stats, if requested
          if ( whatToCompute & FSTATQ_2F_PER_DET )
            {
              REAL4 AdX = multiAMcoef->data[X]->A;
              REAL4 BdX = multiAMcoef->data[X]->B;
              REAL4 CdX = multiAMcoef->data[X]->C;
              REAL4 EdX = 0;
              REAL4 DdX_inv = 1.0 / multiAMcoef->data[X]->D;

              // compute final single-IFO F-stat
              Fstats->twoFPerDet[X][k] = XLALComputeFstatFromFaFb ( FaX, FbX, AdX, BdX, CdX, EdX, DdX_inv );

            } // if FSTATQ_2F_PER_DET

          /* Fa = sum_X Fa_X */
          Fa += FaX;

          /* Fb = sum_X Fb_X */
          Fb += FbX;

        } // for  X < numDetectors

      if ( whatToCompute & FSTATQ_2F )
        {
          Fstats->twoF[k] = XLALComputeFstatFromFaFb ( Fa, Fb, Ad, Bd, Cd, Ed, Dd_inv );
        }

      // Return multi-detector Fa & Fb
      if ( whatToCompute & FSTATQ_FAFB )
        {
          Fstats->Fa[k] = Fa;
          Fstats->Fb[k] = Fb;
        }

      // Return F-atoms per detector
      if ( whatToCompute & FSTATQ_ATOMS_PER_DET )
        {
          XLALDestroyMultiFstatAtomVector ( Fstats->multiFatoms[k] );
          Fstats->multiFatoms[k] = multiFstatAtoms;
        }

    } // for k < Fstats->numFreqBins

  // this needs to be free'ed, as it's currently not buffered
  XLALDestroyMultiSSBtimes ( multiBinary );

  // Return amplitude modulation coefficients
  Fstats->Mmunu = demod->prevMultiAMcoef->Mmunu;

  // return per-detector antenna-pattern matrices
  for ( UINT4 X=0; X < numDetectors; X ++ )
    {
      Fstats->MmunuX[X].Ad = multiAMcoef->data[X]->A;
      Fstats->MmunuX[X].Bd = multiAMcoef->data[X]->B;
      Fstats->MmunuX[X].Cd = multiAMcoef->data[X]->C;
      Fstats->MmunuX[X].Dd = multiAMcoef->data[X]->D;
      Fstats->MmunuX[X].Ed = 0;
    }

  if ( ti->collectTiming ) {
    toc = XLALGetCPUTime();
    ti->tauTotal = (toc - tic);
    ti->tauF1NoBuf = ti->tauTotal / ( Fstats->numFreqBins * numDetectors );
    ti->tauF1Buf   = (ti->tauTotal - ti->tauBary) / ( Fstats->numFreqBins * numDetectors );
  }

  return XLAL_SUCCESS;

} // XLALComputeFstatDemod()
예제 #2
0
/**
 * Function to compute transient-window "F-statistic map" over start-time and timescale {t0, tau}.
 * Returns a 2D matrix F_mn, with m = index over start-times t0, and n = index over timescales tau,
 * in steps of dt0 in [t0, t0+t0Band], and dtau in [tau, tau+tauBand] as defined in transientWindowRange
 *
 * Note: if window->type == none, we compute a single rectangular window covering all the data.
 *
 * Note2: if the experimental switch useFReg is true, returns FReg=F - log(D) instead of F. This option is of
 * little practical interest, except for demonstrating that marginalizing (1/D)e^F is *less* sensitive
 * than marginalizing e^F (see transient methods-paper [in prepartion])
 *
 */
transientFstatMap_t *
XLALComputeTransientFstatMap ( const MultiFstatAtomVector *multiFstatAtoms, 	/**< [in] multi-IFO F-statistic atoms */
                               transientWindowRange_t windowRange,		/**< [in] type and parameters specifying transient window range to search */
                               BOOLEAN useFReg					/**< [in] experimental switch: compute FReg = F - log(D) instead of F */
                               )
{
  /* check input consistency */
  if ( !multiFstatAtoms || !multiFstatAtoms->data || !multiFstatAtoms->data[0]) {
    XLALPrintError ("%s: invalid NULL input.\n", __func__ );
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }
  if ( windowRange.type >= TRANSIENT_LAST ) {
    XLALPrintError ("%s: unknown window-type (%d) passes as input. Allowed are [0,%d].\n", __func__, windowRange.type, TRANSIENT_LAST-1);
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }

  /* ----- pepare return container ----- */
  transientFstatMap_t *ret;
  if ( (ret = XLALCalloc ( 1, sizeof(*ret) )) == NULL ) {
    XLALPrintError ("%s: XLALCalloc(1,%zu) failed.\n", __func__, sizeof(*ret) );
    XLAL_ERROR_NULL ( XLAL_ENOMEM );
  }

  /* ----- first combine all multi-atoms into a single atoms-vector with *unique* timestamps */
  FstatAtomVector *atoms;
  UINT4 TAtom = multiFstatAtoms->data[0]->TAtom;
  UINT4 TAtomHalf = TAtom/2;	/* integer division */

  if ( (atoms = XLALmergeMultiFstatAtomsBinned ( multiFstatAtoms, TAtom )) == NULL ) {
    XLALPrintError ("%s: XLALmergeMultiFstatAtomsSorted() failed with code %d\n", __func__, xlalErrno );
    XLAL_ERROR_NULL ( XLAL_EFUNC );
  }
  UINT4 numAtoms = atoms->length;
  /* actual data spans [t0_data, t0_data + numAtoms * TAtom] in steps of TAtom */
  UINT4 t0_data = atoms->data[0].timestamp;
  UINT4 t1_data = atoms->data[numAtoms-1].timestamp + TAtom;

  /* ----- special treatment of window_type = none ==> replace by rectangular window spanning all the data */
  if ( windowRange.type == TRANSIENT_NONE )
    {
      windowRange.type = TRANSIENT_RECTANGULAR;
      windowRange.t0 = t0_data;
      windowRange.t0Band = 0;
      windowRange.dt0 = TAtom;	/* irrelevant */
      windowRange.tau = numAtoms * TAtom;
      windowRange.tauBand = 0;
      windowRange.dtau = TAtom;	/* irrelevant */
    }

  /* NOTE: indices {i,j} enumerate *actual* atoms and their timestamps t_i, while the
   * indices {m,n} enumerate the full grid of values in [t0_min, t0_max]x[Tcoh_min, Tcoh_max] in
   * steps of deltaT. This allows us to deal with gaps in the data in a transparent way.
   *
   * NOTE2: we operate on the 'binned' atoms returned from XLALmergeMultiFstatAtomsBinned(),
   * which means we can safely assume all atoms to be lined up perfectly on a 'deltaT' binned grid.
   *
   * The mapping used will therefore be {i,j} -> {m,n}:
   *   m = offs_i  / deltaT		= start-time offset from t0_min measured in deltaT
   *   n = Tcoh_ij / deltaT		= duration Tcoh_ij measured in deltaT,
   *
   * where
   *   offs_i  = t_i - t0_min
   *   Tcoh_ij = t_j - t_i + deltaT
   *
   */

  /* We allocate a matrix  {m x n} = t0Range * TcohRange elements
   * covering the full timerange the transient window-range [t0,t0+t0Band]x[tau,tau+tauBand]
   */
  UINT4 N_t0Range  = (UINT4) floor ( windowRange.t0Band / windowRange.dt0 ) + 1;
  UINT4 N_tauRange = (UINT4) floor ( windowRange.tauBand / windowRange.dtau ) + 1;

  if ( ( ret->F_mn = gsl_matrix_calloc ( N_t0Range, N_tauRange )) == NULL ) {
    XLALPrintError ("%s: failed ret->F_mn = gsl_matrix_calloc ( %d, %d )\n", __func__, N_tauRange, N_t0Range );
    XLAL_ERROR_NULL ( XLAL_ENOMEM );
  }

  transientWindow_t win_mn;
  win_mn.type = windowRange.type;
  ret->maxF = -1.0;	// keep track of loudest F-stat point. Initializing to a negative value ensures that we always update at least once and hence return sane t0_d_ML, tau_d_ML even if there is only a single bin where F=0 happens.
  UINT4 m, n;
  /* ----- OUTER loop over start-times [t0,t0+t0Band] ---------- */
  for ( m = 0; m < N_t0Range; m ++ ) /* m enumerates 'binned' t0 start-time indices  */
    {
      /* compute Fstat-atom index i_t0 in [0, numAtoms) */
      win_mn.t0 = windowRange.t0 + m * windowRange.dt0;
      INT4 i_tmp = ( win_mn.t0 - t0_data + TAtomHalf ) / TAtom;	// integer round: floor(x+0.5)
      if ( i_tmp < 0 ) i_tmp = 0;
      UINT4 i_t0 = (UINT4)i_tmp;
      if ( i_t0 >= numAtoms ) i_t0 = numAtoms - 1;

      /* ----- INNER loop over timescale-parameter tau ---------- */
      REAL4 Ad=0, Bd=0, Cd=0;
      COMPLEX8 Fa=0, Fb=0;
      UINT4 i_t1_last = i_t0;

      for ( n = 0; n < N_tauRange; n ++ )
        {
          /* translate n into an atoms end-index for this search interval [t0, t0+Tcoh],
           * giving the index range of atoms to sum over
           */
          win_mn.tau = windowRange.tau + n * windowRange.dtau;

          /* get end-time t1 of this transient-window search */
          UINT4 t0, t1;
          if ( XLALGetTransientWindowTimespan ( &t0, &t1, win_mn ) != XLAL_SUCCESS ) {
            XLALPrintError ("%s: XLALGetTransientWindowTimespan() failed.\n", __func__ );
            XLAL_ERROR_NULL ( XLAL_EFUNC );
          }

          /* compute window end-time Fstat-atom index i_t1 in [0, numAtoms) */
          i_tmp = ( t1 - t0_data + TAtomHalf ) / TAtom  - 1;	// integer round: floor(x+0.5)
          if ( i_tmp < 0 ) i_tmp = 0;
          UINT4 i_t1 = (UINT4)i_tmp;
          if ( i_t1 >= numAtoms ) i_t1 = numAtoms - 1;

          /* protection against degenerate 1-atom case: (this implies D=0 and therefore F->inf) */
          if ( i_t1 == i_t0 ) {
            XLALPrintError ("%s: encountered a single-atom Fstat-calculation. This is degenerate and cannot be computed!\n", __func__ );
            XLALPrintError ("Window-values m=%d (t0=%d=t0_data + %d), n=%d (tau=%d) ==> t1_data - t0 = %d\n",
                            m, win_mn.t0, i_t0 * TAtom, n, win_mn.tau, t1_data - win_mn.t0 );
            XLALPrintError ("The most likely cause is that your t0-range covered all of your data: t0 must stay away *at least* 2*TAtom from the end of the data!\n");
            XLAL_ERROR_NULL ( XLAL_EDOM );
          }

          /* now we have two valid atoms-indices [i_t0, i_t1] spanning our Fstat-window to sum over,
           * using weights according to the window-type
           */
          switch ( windowRange.type )
            {
            case TRANSIENT_RECTANGULAR:
#if 0
              /* 'vanilla' unoptimized method, for sanity checks with 'optimized' method */
              Ad=0; Bd=0; Cd=0; Fa=0; Fb=0;
              for ( UINT4 i = i_t0; i <= i_t1; i ++ )
#else
              /* special optimiziation in the rectangular-window case: just add on to previous tau values
               * ie re-use the sum over [i_t0, i_t1_last] from the pevious tau-loop iteration
               */
              for ( UINT4 i = i_t1_last; i <= i_t1; i ++ )
#endif
                {
                  FstatAtom *thisAtom_i = &atoms->data[i];

                  /* now add on top of previous values, summed from [i_t0, i_t1_last] */
                  Ad += thisAtom_i->a2_alpha;
                  Bd += thisAtom_i->b2_alpha;
                  Cd += thisAtom_i->ab_alpha;

                  Fa += thisAtom_i->Fa_alpha;
                  Fb += thisAtom_i->Fb_alpha;

                } /* for i = i_t1_last : i_t1 */

              i_t1_last = i_t1 + 1;		/* keep track of up to where we summed for the next iteration */

              break;

            case TRANSIENT_EXPONENTIAL:
              /* reset all values */
              Ad=0; Bd=0; Cd=0; Fa=0; Fb=0;

              for ( UINT4 i = i_t0; i <= i_t1; i ++ )
                {
                  FstatAtom *thisAtom_i = &atoms->data[i];
                  UINT4 t_i = thisAtom_i->timestamp;

                  REAL8 win_i;
                  win_i = XLALGetExponentialTransientWindowValue ( t_i, t0, t1, win_mn.tau );

                  REAL8 win2_i = win_i * win_i;

                  Ad += thisAtom_i->a2_alpha * win2_i;
                  Bd += thisAtom_i->b2_alpha * win2_i;
                  Cd += thisAtom_i->ab_alpha * win2_i;

                  Fa += thisAtom_i->Fa_alpha * win_i;
                  Fb += thisAtom_i->Fb_alpha * win_i;

                } /* for i in [i_t0, i_t1] */
              break;

            default:
              XLALPrintError ("%s: invalid transient window type %d not in [%d, %d].\n",
                              __func__, windowRange.type, TRANSIENT_NONE, TRANSIENT_LAST -1 );
              XLAL_ERROR_NULL ( XLAL_EINVAL );
              break;

            } /* switch window.type */


          /* generic F-stat calculation from A,B,C, Fa, Fb */
          REAL4 Dd = ( Ad * Bd - Cd * Cd );
          REAL4 DdInv = 0;
          if ( Dd > 0 ) { /* safety catch as in XLALWeightMultiAMCoeffs(): make it so that in the end F=0 instead of -nan */
            DdInv = 1.0f / Dd;
          }
          REAL4 twoF = XLALComputeFstatFromFaFb ( Fa, Fb, Ad, Bd, Cd, 0, DdInv );
          REAL4 F = 0.5 * twoF;
          /* keep track of loudest F-stat value encountered over the m x n matrix */
          if ( F > ret->maxF )
            {
              ret->maxF = F;
              ret->t0_ML  = win_mn.t0;	/* start-time t0 corresponding to Fmax */
              ret->tau_ML = win_mn.tau;	/* timescale tau corresponding to Fmax */
            }

          /* if requested: use 'regularized' F-stat: log ( 1/D * e^F ) = F + log(1/D) */
          if ( useFReg )
            F += log( DdInv );

          /* and store this in Fstat-matrix as element {m,n} */
          gsl_matrix_set ( ret->F_mn, m, n, F );

        } /* for n in n[tau] : n[tau+tauBand] */

    } /* for m in m[t0] : m[t0+t0Band] */

  /* free internal mem */
  XLALDestroyFstatAtomVector ( atoms );

  /* return end product: F-stat map */
  return ret;

} /* XLALComputeTransientFstatMap() */