// ----- 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()
/** Compute the semi-coherent statistics * * This function computes the semi-coherent s. * */ int XLALComputeSemiCoherentStat(FILE *fp, /**< [in] the output file pointer */ REAL4DemodulatedPowerVector *power, /**< [in] the input data in the form of power */ ParameterSpace *pspace, /**< [in] the parameter space */ GridParametersVector *fgrid, /**< UNDOCUMENTED */ GridParameters *bingrid, /**< [in] the grid parameters */ INT4 ntoplist, /**< UNDOCUMENTED */ BOOLEAN with_xbins /**< enable fast summing of extra bins */ ) { toplist TL; /* the results toplist */ Template *bintemp = NULL; /* the binary parameter space template */ Template *fdots = NULL; /* the freq derivitive template for each segment */ UINT4 i,j; /* counters */ UINT4 percent = 0; /* counter for status update */ REAL8 mean = 0.0; REAL8 var = 0.0; UINT4 Ntemp = 0; /* validate input parameters */ /* if ((*SemiCo) != NULL) { */ /* LogPrintf(LOG_CRITICAL,"%s: Invalid input, output BayesianProducts structure != NULL.\n",__func__); */ /* XLAL_ERROR(XLAL_EINVAL); */ /* } */ if (power == NULL) { LogPrintf(LOG_CRITICAL,"%s: Invalid input, input REAL4DemodulatedPowerVector structure = NULL.\n",__func__); XLAL_ERROR(XLAL_EINVAL); } if (pspace == NULL) { LogPrintf(LOG_CRITICAL,"%s: Invalid input, input GridParameters structure = NULL.\n",__func__); XLAL_ERROR(XLAL_EINVAL); } if (fgrid == NULL) { LogPrintf(LOG_CRITICAL,"%s: Invalid input, input GridParametersVector structure = NULL.\n",__func__); XLAL_ERROR(XLAL_EINVAL); } if (bingrid == NULL) { LogPrintf(LOG_CRITICAL,"%s: Invalid input, input GridParameters structure = NULL.\n",__func__); XLAL_ERROR(XLAL_EINVAL); } /* check for same frequency spacing */ const REAL8 dfreq = fgrid->segment[0]->grid[0].delta; for (i=0;i<power->length;i++) { if ( dfreq != fgrid->segment[i]->grid[0].delta ) { LogPrintf(LOG_CRITICAL,"%s : inconsistent frequency spacing in segment %u, %.10g != %.10g\n",__func__,i,fgrid->segment[i]->grid[0].delta,dfreq); XLAL_ERROR(XLAL_EINVAL); } } /* check that coherent grids step by 1 in frequency */ for (i=0;i<power->length;i++) { GridParameters *fdotgrid = fgrid->segment[i]; if ( fdotgrid->prod[0] != 1 ) { LogPrintf(LOG_CRITICAL,"%s : coherent grid step in segment %u does not equal 1\n",__func__,i); XLAL_ERROR(XLAL_EINVAL); } } /* allocate memory for the results toplist */ TL.n = ntoplist; if ((TL.data = (REAL4 *)XLALCalloc(TL.n,sizeof(REAL4))) == NULL) { LogPrintf(LOG_CRITICAL,"%s : XLALCalloc() failed with error = %d\n",__func__,xlalErrno); XLAL_ERROR(XLAL_ENOMEM); } if ((TL.params = (REAL8 **)XLALCalloc(TL.n,sizeof(REAL8 *))) == NULL) { LogPrintf(LOG_CRITICAL,"%s : XLALCalloc() failed with error = %d\n",__func__,xlalErrno); XLAL_ERROR(XLAL_ENOMEM); } for (i=0;i<(UINT4)TL.n;i++) { TL.params[i] = NULL; if ((TL.params[i] = (REAL8 *)XLALCalloc(bingrid->ndim,sizeof(REAL8))) == NULL) { LogPrintf(LOG_CRITICAL,"%s : XLALCalloc() failed with error = %d\n",__func__,xlalErrno); XLAL_ERROR(XLAL_ENOMEM); } } TL.idx = 0; /* allocate memory for the fdots */ if ((fdots = XLALCalloc(power->length, sizeof(*fdots))) == NULL) { LogPrintf(LOG_CRITICAL,"%s : XLALCalloc() failed with error = %d\n",__func__,xlalErrno); XLAL_ERROR(XLAL_ENOMEM); } for (i=0;i<power->length;i++) { if ((fdots[i].x = XLALCalloc(fgrid->segment[0]->ndim,sizeof(REAL8))) == NULL) { LogPrintf(LOG_CRITICAL,"%s : XLALCalloc() failed with error = %d\n",__func__,xlalErrno); XLAL_ERROR(XLAL_ENOMEM); } if ((fdots[i].idx = XLALCalloc(fgrid->segment[0]->ndim,sizeof(INT4))) == NULL) { LogPrintf(LOG_CRITICAL,"%s : XLALCalloc() failed with error = %d\n",__func__,xlalErrno); XLAL_ERROR(XLAL_ENOMEM); } fdots[i].ndim = fgrid->segment[0]->ndim; } /* define the chi-squared threshold */ /* REAL8 thr = gsl_cdf_chisq_Qinv(frac,2*power->length); LogPrintf(LOG_DEBUG,"%s : computed the threshold as %f\n",__func__,thr); */ int (*getnext)(Template **temp,GridParameters *gridparams, ParameterSpace *space,void *); UINT8 newmax = bingrid->max; ParameterSpace *temppspace = NULL; if (bingrid->coverage>0) { getnext = &XLALGetNextRandomBinaryTemplate; newmax = bingrid->Nr; temppspace = pspace; } else getnext = &XLALGetNextTemplate; REAL4 *logLratiosumvec = NULL; /* single loop over binary templates */ double fine_deriv_t = 0; UINT8 num_fine_deriv = 0; double fine_sum_t = 0; UINT8 num_fine_sum = 0; INT4 max_tot_xbins = 0; while (getnext(&bintemp,bingrid,temppspace,r)) { const REAL8 asini = bintemp->x[1]; /* define asini */ const REAL8 omega = bintemp->x[3]; /* define omega */ /* maximum extra bins to sum in frequency at this template, while keeping correct derivative bins (minus 10% for safety) */ const INT4 xbins = !with_xbins ? 0 : (INT4) floor( 0.45 * dfreq / ( asini * omega ) ); XLAL_CHECK( xbins >= 0, XLAL_EDOM, "Invalid xbins=%d\n", xbins ); INT4 left_xbins = xbins, right_xbins = xbins; /** loop over segments **********************************************************************************/ const double fine_deriv_t0 = XLALGetCPUTime(); for (i=0;i<power->length;i++) { REAL8 tmid = XLALGPSGetREAL8(&(power->segment[i]->epoch)) + 0.5*pspace->tseg; GridParameters *fdotgrid = fgrid->segment[i]; /* REAL8 norm = (REAL8)background->data[i]; */ /* compute instantaneous frequency derivitives corresponding to the current template for this segment */ XLALComputeBinaryFreqDerivitives(&fdots[i],bintemp,tmid); /* find ndim-D indices corresponding to the spin derivitive values for the segment power */ for (j=0;j<fdots[i].ndim;j++) { fdots[i].idx[j] = lround( (fdots[i].x[j] - fdotgrid->grid[j].min)*fdotgrid->grid[j].oneoverdelta ); /* check that index is in range */ if ( fdots[i].idx[j] < 0 || fdots[i].idx[j] >= (INT4)fdotgrid->grid[j].length ) { LogPrintf(LOG_CRITICAL,"%s: stepped outside grid in segment %d, nu=%g, asini=%g, tasc=%g, omega=%g, fdots[%d] = [%g <= %g <= %g, 0 <= %d < %d]\n", __func__, i, bintemp->x[0], bintemp->x[1], bintemp->x[2], bintemp->x[3], j, fdotgrid->grid[j].min, fdots[i].x[j], fdotgrid->grid[j].min + fdotgrid->grid[j].delta*fdotgrid->grid[j].length, fdots[i].idx[j], fdotgrid->grid[j].length); XLAL_ERROR(XLAL_EDOM); } } /* ensure number of extra frequency bins do not go out of range of coherent grids */ left_xbins = GSL_MIN( left_xbins, (INT4)( fdots[i].idx[0] ) ); right_xbins = GSL_MIN( right_xbins, (INT4)( fdotgrid->grid[0].length - fdots[i].idx[0] - 1 ) ); XLAL_CHECK( left_xbins >= 0, XLAL_EDOM, "Invalid left_xbins=%d\n", left_xbins ); XLAL_CHECK( right_xbins >= 0, XLAL_EDOM, "Invalid right_xbins=%d\n", right_xbins ); } /* end loop over segments */ fine_deriv_t += XLALGetCPUTime() - fine_deriv_t0; num_fine_deriv += power->length; /*************************************************************************************/ const INT4 tot_xbins = 1 + left_xbins + right_xbins; if ( max_tot_xbins < tot_xbins ) { max_tot_xbins = tot_xbins; /* reallocate logLratiosumvec */ logLratiosumvec = XLALRealloc( logLratiosumvec, max_tot_xbins * sizeof( *logLratiosumvec ) ); XLAL_CHECK( logLratiosumvec != NULL, XLAL_ENOMEM ); } /** loop over segments **********************************************************************************/ const double fine_sum_t0 = XLALGetCPUTime(); for (i=0;i<power->length;i++) { REAL4DemodulatedPower *currentpower = power->segment[i]; GridParameters *fdotgrid = fgrid->segment[i]; /* find starting 1-D index corresponding to the spin derivitive values for the segment power */ INT4 idx0 = fdots[i].idx[0] - left_xbins; for (j=1;j<fdots[i].ndim;j++) { idx0 += fdots[i].idx[j] * fdotgrid->prod[j]; } /* define the power at this location in this segment */ if (i==0) { memcpy( logLratiosumvec, ¤tpower->data->data[idx0], tot_xbins * sizeof( *logLratiosumvec ) ); } else { XLAL_CHECK( XLALVectorAddREAL4( logLratiosumvec, logLratiosumvec, ¤tpower->data->data[idx0], tot_xbins ) == XLAL_SUCCESS, XLAL_EFUNC ); } } /* end loop over segments */ fine_sum_t += XLALGetCPUTime() - fine_sum_t0; num_fine_sum += ( power->length - 1 ) * tot_xbins; /*************************************************************************************/ /* make it a true chi-squared variable */ XLAL_CHECK( XLALVectorScaleREAL4( logLratiosumvec, 2.0, logLratiosumvec, tot_xbins ) == XLAL_SUCCESS, XLAL_EFUNC ); /* save central binary template frequency */ const REAL8 nu0 = bintemp->x[0]; for (INT4 x = -left_xbins; x <= right_xbins; ++x) { /* set binary template frequency */ bintemp->x[0] = nu0 + dfreq*x; /* output semi-coherent statistic for this template if it exceeds the threshold*/ const REAL4 logLratiosum = logLratiosumvec[x + left_xbins]; mean += logLratiosum; var += logLratiosum*logLratiosum; ++Ntemp; XLALtoplist(logLratiosum,bintemp,&TL); } /* if (logLratiosum>thr) { for (j=0;j<bingrid->ndim;j++) fprintf(fp,"%6.12f\t",bintemp->x[j]); fprintf(fp,"%6.12e\n",logLratiosum); } */ /* output status to screen */ if ( (bintemp->currentidx == 0) || (floor(100.0*(REAL8)bintemp->currentidx/(REAL8)newmax) > (REAL8)percent) ) { percent = (UINT4)floor(100*(REAL8)bintemp->currentidx/(REAL8)newmax); LogPrintf(LOG_NORMAL,"%s : completed %d%% (%"LAL_UINT8_FORMAT"/%"LAL_UINT8_FORMAT")\n",__func__,percent,bintemp->currentidx,newmax); } /* we've computed this number of extra templates */ bintemp->currentidx += left_xbins + right_xbins; } /* end loop over templates */ LogPrintf(LOG_NORMAL,"%s : time to compute fine grid derivatives = %0.12e\n",__func__, fine_deriv_t); LogPrintf(LOG_NORMAL,"%s : number of fine grid derivatives = %"LAL_UINT8_FORMAT"\n",__func__, num_fine_deriv); LogPrintf(LOG_NORMAL,"%s : time to compute fine summations = %0.12e\n",__func__, fine_sum_t); LogPrintf(LOG_NORMAL,"%s : number of fine grid summations = %"LAL_UINT8_FORMAT"\n",__func__, num_fine_sum); LogPrintf(LOG_NORMAL,"%s : summed up to %d frequency bins at a time\n", __func__, max_tot_xbins); /*************************************************************************************/ /* compute mean and variance of results */ mean = mean/(REAL8)Ntemp; var = var/(REAL8)(Ntemp-1); var = (var - mean*mean); /* modify toplist to have correct mean and variance */ for (i=0;i<(UINT4)TL.n;i++) TL.data[i] = (TL.data[i] - mean)*sqrt(4.0*power->length)/sqrt(var) + 2.0*power->length; /* output toplist to file */ for (i=0;i<(UINT4)TL.n;i++) { for (j=0;j<bingrid->ndim;j++) fprintf(fp,"%6.12f\t",TL.params[i][j]); fprintf(fp,"%6.12e\n",TL.data[i]); } /* free template memory */ for (i=0;i<power->length;i++) { XLALFree(fdots[i].x); XLALFree(fdots[i].idx); } XLALFree(fdots); XLALFree(TL.data); for (i=0;i<(UINT4)TL.n;i++) XLALFree(TL.params[i]); XLALFree(TL.params); XLALFree(logLratiosumvec); LogPrintf(LOG_DEBUG,"%s : leaving.\n",__func__); return XLAL_SUCCESS; }