LALPulsar  6.1.0.1-fe68b98
ComputeFstat_Resamp_Generic.c
Go to the documentation of this file.
1 //
2 // Copyright (C) 2009, 2014--2015 Reinhard Prix
3 // Copyright (C) 2012--2015 Karl Wette
4 // Copyright (C) 2009 Chris Messenger, Pinkesh Patel, Xavier Siemens, Holger Pletsch
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with with program; see the file COPYING. If not, write to the
18 // Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 // MA 02110-1301 USA
20 //
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include <complex.h>
26 #include <fftw3.h>
27 
28 #include "ComputeFstat_internal.h"
30 
31 #include <lal/FFTWMutex.h>
32 #include <lal/Factorial.h>
33 #include <lal/LFTandTSutils.h>
34 #include <lal/LogPrintf.h>
35 #include <lal/SinCosLUT.h>
36 #include <lal/TimeSeries.h>
37 #include <lal/Units.h>
38 
39 ///
40 /// \defgroup ComputeFstat_Resamp_Generic_c Module ComputeFstat_Resamp_Generic.c
41 /// \ingroup ComputeFstat_h
42 /// \brief Implements a generic version \cite Prix2022 of the \a Resamp FFT-based resampling algorithm for
43 /// computing the \f$ \mathcal{F} \f$ -statistic \cite JKS98 .
44 ///
45 
46 /// @{
47 
48 // ========== Resamp internals ==========
49 
50 // ----- local constants ----------
51 
52 // ----- local macros ----------
53 
54 // ----- local types ----------
55 
56 // ----- workspace ----------
57 typedef struct tagResampGenericWorkspace {
58  // intermediate quantities to interpolate and operate on SRC-frame timeseries
59  COMPLEX8Vector *TStmp1_SRC; // can hold a single-detector SRC-frame spindown-corrected timeseries [without zero-padding]
60  COMPLEX8Vector *TStmp2_SRC; // can hold a single-detector SRC-frame spindown-corrected timeseries [without zero-padding]
61  REAL8Vector *SRCtimes_DET; // holds uniformly-spaced SRC-frame timesteps translated into detector frame [for interpolation]
62 
63  // input padded timeseries ts(t) and output Fab(f) of length 'numSamplesFFT'
64  UINT4 numSamplesFFTAlloc; // allocated number of zero-padded SRC-frame time samples (related to dFreq)
65  COMPLEX8 *TS_FFT; // zero-padded, spindown-corr SRC-frame TS
66  COMPLEX8 *FabX_Raw; // raw full-band FFT result Fa,Fb
67 
68  // arrays of size numFreqBinsOut over frequency bins f_k:
69  COMPLEX8 *FaX_k; // properly normalized F_a^X(f_k) over output bins
70  COMPLEX8 *FbX_k; // properly normalized F_b^X(f_k) over output bins
71  COMPLEX8 *Fa_k; // properly normalized F_a(f_k) over output bins
72  COMPLEX8 *Fb_k; // properly normalized F_b(f_k) over output bins
73  UINT4 numFreqBinsAlloc; // internal: keep track of allocated length of frequency-arrays
74 
76 
77 typedef struct {
78  UINT4 Dterms; // Number of terms to use (on either side) in Windowed-Sinc interpolation kernel
79  MultiCOMPLEX8TimeSeries *multiTimeSeries_DET; // input SFTs converted into a heterodyned timeseries
80  // ----- buffering -----
81  PulsarDopplerParams prev_doppler; // buffering: previous phase-evolution ("doppler") parameters
82  MultiAMCoeffs *multiAMcoef; // buffered antenna-pattern functions
83  MultiSSBtimes *multiSSBtimes; // buffered SSB times, including *only* sky-position corrections, not binary
84  MultiSSBtimes *multiBinaryTimes; // buffered SRC times, including both sky- and binary corrections [to avoid re-allocating this]
85 
86  AntennaPatternMatrix Mmunu; // combined multi-IFO antenna-pattern coefficients {A,B,C,E}
87  AntennaPatternMatrix MmunuX[PULSAR_MAX_DETECTORS]; // per-IFO antenna-pattern coefficients {AX,BX,CX,EX}
88 
89  MultiCOMPLEX8TimeSeries *multiTimeSeries_SRC_a; // multi-detector SRC-frame timeseries, multiplied by AM function a(t)
90  MultiCOMPLEX8TimeSeries *multiTimeSeries_SRC_b; // multi-detector SRC-frame timeseries, multiplied by AM function b(t)
91 
92  UINT4 numSamplesFFT; // length of zero-padded SRC-frame timeseries (related to dFreq)
93  UINT4 decimateFFT; // output every n-th frequency bin, with n>1 iff (dFreq > 1/Tspan), and was internally decreased by n
94  fftwf_plan fftplan; // FFT plan
95 
96  // ----- timing -----
97  BOOLEAN collectTiming; // flag whether or not to collect timing information
98  FstatTimingGeneric timingGeneric; // measured (generic) F-statistic timing values
99  FstatTimingResamp timingResamp; // measured Resamp-specific timing model data
100 
102 
103 
104 // ----- local prototypes ----------
105 
106 int XLALSetupFstatResampGeneric( void **method_data, FstatCommon *common, FstatMethodFuncs *funcs, MultiSFTVector *multiSFTs, const FstatOptionalArgs *optArgs );
107 int XLALExtractResampledTimeseries_ResampGeneric( MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_a, MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_b, void *method_data );
108 int XLALGetFstatTiming_ResampGeneric( const void *method_data, FstatTimingGeneric *timingGeneric, FstatTimingModel *timingModel );
109 
110 static int XLALComputeFstatResampGeneric( FstatResults *Fstats, const FstatCommon *common, void *method_data );
111 static int XLALApplySpindownAndFreqShiftGeneric( COMPLEX8 *xOut, const COMPLEX8TimeSeries *xIn, const PulsarDopplerParams *doppler, REAL8 freqShift );
113 static int XLALComputeFaFb_ResampGeneric( ResampGenericMethodData *resamp, ResampGenericWorkspace *ws, const PulsarDopplerParams thisPoint, REAL8 dFreq, UINT4 numFreqBins, const COMPLEX8TimeSeries *TimeSeries_SRC_a, const COMPLEX8TimeSeries *TimeSeries_SRC_b );
114 static void XLALGetFFTPlanHints( int *planMode, double *planGenTimeoutSeconds );
115 static void XLALDestroyResampGenericWorkspace( void *workspace );
116 static void XLALDestroyResampGenericMethodData( void *method_data );
117 
118 // ==================== function definitions ====================
119 
120 static void XLALDestroyResampGenericWorkspace( void *workspace )
121 {
122  ResampGenericWorkspace *ws = ( ResampGenericWorkspace * ) workspace;
123 
127 
128  fftw_free( ws->FabX_Raw );
129  fftw_free( ws->TS_FFT );
130 
131  XLALFree( ws->FaX_k );
132  XLALFree( ws->FbX_k );
133  XLALFree( ws->Fa_k );
134  XLALFree( ws->Fb_k );
135 
136  XLALFree( ws );
137  return;
138 
139 } // XLALDestroyResampGenericWorkspace()
140 
141 static void XLALDestroyResampGenericMethodData( void *method_data )
142 {
143 
144  ResampGenericMethodData *resamp = ( ResampGenericMethodData * ) method_data;
145 
147 
148  // ----- free buffer
154 
156  fftwf_destroy_plan( resamp->fftplan );
158 
159  XLALFree( resamp );
160 
161 } // XLALDestroyResampGenericMethodData()
162 
163 int
164 XLALSetupFstatResampGeneric( void **method_data,
165  FstatCommon *common,
166  FstatMethodFuncs *funcs,
168  const FstatOptionalArgs *optArgs
169  )
170 {
171  // Check input
172  XLAL_CHECK( method_data != NULL, XLAL_EFAULT );
173  XLAL_CHECK( common != NULL, XLAL_EFAULT );
174  XLAL_CHECK( funcs != NULL, XLAL_EFAULT );
175  XLAL_CHECK( multiSFTs != NULL, XLAL_EFAULT );
176  XLAL_CHECK( optArgs != NULL, XLAL_EFAULT );
177 
178  // Allocate method data
179  ResampGenericMethodData *resamp = *method_data = XLALCalloc( 1, sizeof( *resamp ) );
180  XLAL_CHECK( resamp != NULL, XLAL_ENOMEM );
181 
182  resamp->Dterms = optArgs->Dterms;
183 
184  // Set method function pointers
188 
189  // Extra band needed for resampling: Hamming-windowed sinc used for interpolation has a transition bandwith of
190  // TB=(4/L)*fSamp, where L=2*Dterms+1 is the window-length, and here fSamp=Band (i.e. the full SFT frequency band)
191  // However, we're only interested in the physical band and we'll be throwing away all bins outside of this.
192  // This implies that we're only affected by *half* the transition band TB/2 on either side, as the other half of TB is outside of the band of interest
193  // (and will actually get aliased, i.e. the region [-fNy - TB/2, -fNy] overlaps with [fNy-TB/2,fNy] and vice-versa: [fNy,fNy+TB/2] overlaps with [-fNy,-fNy+TB/2])
194  // ==> therefore we only need to add an extra TB/2 on each side to be able to safely avoid the transition-band effects
195  REAL8 f0 = multiSFTs->data[0]->data[0].f0;
196  REAL8 dFreq = multiSFTs->data[0]->data[0].deltaF;
197  REAL8 Band = multiSFTs->data[0]->data[0].data->length * dFreq;
198  REAL8 extraBand = 2.0 / ( 2 * optArgs->Dterms + 1 ) * Band;
199  XLAL_CHECK( XLALMultiSFTVectorResizeBand( multiSFTs, f0 - extraBand, Band + 2 * extraBand ) == XLAL_SUCCESS, XLAL_EFUNC );
200  // Convert SFTs into heterodyned complex timeseries [in detector frame]
202 
203  XLALDestroyMultiSFTVector( multiSFTs ); // don't need them SFTs any more ...
204 
206  REAL8 dt_DET = resamp->multiTimeSeries_DET->data[0]->deltaT;
207  REAL8 fHet = resamp->multiTimeSeries_DET->data[0]->f0;
208  REAL8 Tsft = common->multiTimestamps->data[0]->deltaT;
209 
210  // determine resampled timeseries parameters
211  REAL8 TspanFFT = 1.0 / common->dFreq;
212 
213  // check that TspanFFT >= TspanX for all detectors X, otherwise increase TspanFFT by an integer factor 'decimateFFT' such that this is true
214  REAL8 TspanXMax = 0;
215  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
216  UINT4 numSamples_DETX = resamp->multiTimeSeries_DET->data[X]->data->length;
217  REAL8 TspanX = numSamples_DETX * dt_DET;
218  TspanXMax = fmax( TspanXMax, TspanX );
219  }
220  UINT4 decimateFFT = ( UINT4 )ceil( TspanXMax / TspanFFT ); // larger than 1 means we need to artificially increase dFreqFFT by 'decimateFFT'
221  if ( decimateFFT > 1 ) {
222  XLALPrintWarning( "WARNING: Frequency spacing larger than 1/Tspan, we'll internally decimate FFT frequency bins by a factor of %" LAL_UINT4_FORMAT "\n", decimateFFT );
223  }
224  TspanFFT *= decimateFFT;
225  resamp->decimateFFT = decimateFFT;
226 
227  UINT4 numSamplesFFT0 = ( UINT4 ) ceil( TspanFFT / dt_DET ); // we use ceil() so that we artificially widen the band rather than reduce it
228  UINT4 numSamplesFFT = 0;
229  if ( optArgs->resampFFTPowerOf2 ) {
230  numSamplesFFT = ( UINT4 ) pow( 2, ceil( log2( numSamplesFFT0 ) ) ); // round numSamplesFFT up to next power of 2 for most effiecient FFT
231  } else {
232  numSamplesFFT = ( UINT4 ) 2 * ceil( numSamplesFFT0 / 2 ); // always ensure numSamplesFFT is even
233  }
234 
235  REAL8 dt_SRC = TspanFFT / numSamplesFFT; // adjust sampling rate to allow achieving exact requested dFreq=1/TspanFFT !
236 
237  resamp->numSamplesFFT = numSamplesFFT;
238  // ----- allocate buffer Memory ----------
239 
240  // header for SRC-frame resampled timeseries buffer
241  XLAL_CHECK( ( resamp->multiTimeSeries_SRC_a = XLALCalloc( 1, sizeof( MultiCOMPLEX8TimeSeries ) ) ) != NULL, XLAL_ENOMEM );
244 
245  XLAL_CHECK( ( resamp->multiTimeSeries_SRC_b = XLALCalloc( 1, sizeof( MultiCOMPLEX8TimeSeries ) ) ) != NULL, XLAL_ENOMEM );
248 
249  LIGOTimeGPS XLAL_INIT_DECL( epoch0 ); // will be set to corresponding SRC-frame epoch when barycentering
250  UINT4 numSamplesMax_SRC = 0;
251  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
252  // ----- check input consistency ----------
253  REAL8 dt_DETX = resamp->multiTimeSeries_DET->data[X]->deltaT;
254  XLAL_CHECK( dt_DET == dt_DETX, XLAL_EINVAL, "Input timeseries must have identical 'deltaT(X=%d)' (%.16g != %.16g)\n", X, dt_DET, dt_DETX );
255 
256  REAL8 fHetX = resamp->multiTimeSeries_DET->data[X]->f0;
257  XLAL_CHECK( fabs( fHet - fHetX ) < LAL_REAL8_EPS * fHet, XLAL_EINVAL, "Input timeseries must have identical heterodyning frequency 'f0(X=%d)' (%.16g != %.16g)\n", X, fHet, fHetX );
258 
259  REAL8 TsftX = common->multiTimestamps->data[X]->deltaT;
260  XLAL_CHECK( Tsft == TsftX, XLAL_EINVAL, "Input timestamps must have identical stepsize 'Tsft(X=%d)' (%.16g != %.16g)\n", X, Tsft, TsftX );
261 
262  // ----- prepare Memory fo SRC-frame timeseries and AM coefficients
263  const char *nameX = resamp->multiTimeSeries_DET->data[X]->name;
264  UINT4 numSamples_DETX = resamp->multiTimeSeries_DET->data[X]->data->length;
265  UINT4 numSamples_SRCX = ( UINT4 )ceil( numSamples_DETX * dt_DET / dt_SRC );
266 
267  XLAL_CHECK( ( resamp->multiTimeSeries_SRC_a->data[X] = XLALCreateCOMPLEX8TimeSeries( nameX, &epoch0, fHet, dt_SRC, &lalDimensionlessUnit, numSamples_SRCX ) ) != NULL, XLAL_EFUNC );
268  XLAL_CHECK( ( resamp->multiTimeSeries_SRC_b->data[X] = XLALCreateCOMPLEX8TimeSeries( nameX, &epoch0, fHet, dt_SRC, &lalDimensionlessUnit, numSamples_SRCX ) ) != NULL, XLAL_EFUNC );
269 
270  numSamplesMax_SRC = MYMAX( numSamplesMax_SRC, numSamples_SRCX );
271  } // for X < numDetectors
272 
273  XLAL_CHECK( numSamplesFFT >= numSamplesMax_SRC, XLAL_EFAILED, "[numSamplesFFT = %d] < [numSamplesMax_SRC = %d]\n", numSamplesFFT, numSamplesMax_SRC );
274 
275  // ---- re-use shared workspace, or allocate here ----------
277  if ( ws != NULL ) {
278  if ( numSamplesFFT > ws->numSamplesFFTAlloc ) {
279  fftw_free( ws->FabX_Raw );
280  XLAL_CHECK( ( ws->FabX_Raw = fftw_malloc( numSamplesFFT * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
281  fftw_free( ws->TS_FFT );
282  XLAL_CHECK( ( ws->TS_FFT = fftw_malloc( numSamplesFFT * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
283 
284  ws->numSamplesFFTAlloc = numSamplesFFT;
285  }
286 
287  // adjust maximal SRC-frame timeseries length, if necessary
288  if ( numSamplesMax_SRC > ws->TStmp1_SRC->length ) {
289  XLAL_CHECK( ( ws->TStmp1_SRC->data = XLALRealloc( ws->TStmp1_SRC->data, numSamplesMax_SRC * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
290  ws->TStmp1_SRC->length = numSamplesMax_SRC;
291  XLAL_CHECK( ( ws->TStmp2_SRC->data = XLALRealloc( ws->TStmp2_SRC->data, numSamplesMax_SRC * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
292  ws->TStmp2_SRC->length = numSamplesMax_SRC;
293  XLAL_CHECK( ( ws->SRCtimes_DET->data = XLALRealloc( ws->SRCtimes_DET->data, numSamplesMax_SRC * sizeof( REAL8 ) ) ) != NULL, XLAL_ENOMEM );
294  ws->SRCtimes_DET->length = numSamplesMax_SRC;
295  }
296 
297  } // end: if shared workspace given
298  else {
299  XLAL_CHECK( ( ws = XLALCalloc( 1, sizeof( *ws ) ) ) != NULL, XLAL_ENOMEM );
300  XLAL_CHECK( ( ws->TStmp1_SRC = XLALCreateCOMPLEX8Vector( numSamplesMax_SRC ) ) != NULL, XLAL_EFUNC );
301  XLAL_CHECK( ( ws->TStmp2_SRC = XLALCreateCOMPLEX8Vector( numSamplesMax_SRC ) ) != NULL, XLAL_EFUNC );
302  XLAL_CHECK( ( ws->SRCtimes_DET = XLALCreateREAL8Vector( numSamplesMax_SRC ) ) != NULL, XLAL_EFUNC );
303 
304  XLAL_CHECK( ( ws->FabX_Raw = fftw_malloc( numSamplesFFT * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
305  XLAL_CHECK( ( ws->TS_FFT = fftw_malloc( numSamplesFFT * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
306  ws->numSamplesFFTAlloc = numSamplesFFT;
307 
308  common->workspace = ws;
309  } // end: if we create our own workspace
310 
311  // ----- compute and buffer FFT plan ----------
312  int fft_plan_flags = FFTW_MEASURE;
313  double fft_plan_timeout = FFTW_NO_TIMELIMIT ;
314  char *wisdom_filename;
315  static int tried_wisdom = 0;
316 
318  // if FFTWF_WISDOM_FILENAME is set, try to import that wisdom
319  wisdom_filename = getenv( "FFTWF_WISDOM_FILENAME" );
320  if ( wisdom_filename && !tried_wisdom ) {
321  FILE *fp = fopen( wisdom_filename, "r" );
322  if ( !fp ) {
323  XLALPrintWarning( "WARNING: Couldn't open wisdom file '%s'\n", wisdom_filename );
324  } else if ( fftwf_import_wisdom_from_file( fp ) ) {
325  XLALPrintInfo( "INFO: imported wisdom from file '%s'\n", wisdom_filename );
326  fclose( fp );
327  } else {
328  XLALPrintWarning( "WARNING: Couldn't import wisdom from file '%s'\n", wisdom_filename );
329  fclose( fp );
330  }
331  tried_wisdom = -1;
332  }
333  XLALGetFFTPlanHints( & fft_plan_flags, & fft_plan_timeout );
334  fftw_set_timelimit( fft_plan_timeout );
335  XLAL_CHECK( ( resamp->fftplan = fftwf_plan_dft_1d( resamp->numSamplesFFT, ws->TS_FFT, ws->FabX_Raw, FFTW_FORWARD, fft_plan_flags ) ) != NULL, XLAL_EFAILED, "fftwf_plan_dft_1d() failed\n" );
337 
338  // turn on timing collection if requested
339  resamp->collectTiming = optArgs->collectTiming;
340 
341  // initialize struct for collecting timing data, store invariant 'meta' quantities about this setup
342  if ( resamp->collectTiming ) {
343  XLAL_INIT_MEM( resamp->timingGeneric );
344  resamp->timingGeneric.Ndet = numDetectors;
345 
346  XLAL_INIT_MEM( resamp->timingResamp );
347  resamp->timingResamp.Resolution = TspanXMax / TspanFFT;
348  resamp->timingResamp.NsampFFT0 = numSamplesFFT0;
349  resamp->timingResamp.NsampFFT = numSamplesFFT;
350  }
351 
352  return XLAL_SUCCESS;
353 
354 } // XLALSetupFstatResampGeneric()
355 
356 
357 static int
359  const FstatCommon *common,
360  void *method_data
361  )
362 {
363  // Check input
364  XLAL_CHECK( Fstats != NULL, XLAL_EFAULT );
365  XLAL_CHECK( common != NULL, XLAL_EFAULT );
366  XLAL_CHECK( method_data != NULL, XLAL_EFAULT );
367 
368  ResampGenericMethodData *resamp = ( ResampGenericMethodData * ) method_data;
369 
370  const FstatQuantities whatToCompute = Fstats->whatWasComputed;
371  XLAL_CHECK( !( whatToCompute & FSTATQ_ATOMS_PER_DET ), XLAL_EINVAL, "Resampling does not currently support atoms per detector" );
372 
374 
375  // ----- handy shortcuts ----------
376  PulsarDopplerParams thisPoint = Fstats->doppler;
377  const MultiCOMPLEX8TimeSeries *multiTimeSeries_DET = resamp->multiTimeSeries_DET;
378  UINT4 numDetectors = multiTimeSeries_DET->length;
379 
380  // collect internal timing info
381  BOOLEAN collectTiming = resamp->collectTiming;
382  Timings_t *Tau = &( resamp->timingResamp.Tau );
383  XLAL_INIT_MEM( ( *Tau ) ); // these need to be initialized to 0 for each call
384 
385  REAL8 ticStart = 0, tocEnd = 0;
386  REAL8 tic = 0, toc = 0;
387  if ( collectTiming ) {
388  XLAL_INIT_MEM( ( *Tau ) ); // re-set all timings to 0 at beginning of each Fstat-call
389  ticStart = XLALGetCPUTime();
390  }
391  // Note: all buffering is done within that function
393 
394  if ( whatToCompute == FSTATQ_NONE ) {
395  return XLAL_SUCCESS;
396  }
397 
398  MultiCOMPLEX8TimeSeries *multiTimeSeries_SRC_a = resamp->multiTimeSeries_SRC_a;
399  MultiCOMPLEX8TimeSeries *multiTimeSeries_SRC_b = resamp->multiTimeSeries_SRC_b;
400 
401  // ============================== check workspace is properly allocated and initialized ===========
402 
403  // ----- workspace that depends on maximal number of output frequency bins 'numFreqBins' ----------
404  UINT4 numFreqBins = Fstats->numFreqBins;
405 
406  if ( collectTiming ) {
407  tic = XLALGetCPUTime();
408  }
409 
410  // NOTE: we try to use as much existing memory as possible in FstatResults, so we only
411  // allocate local 'workspace' storage in case there's not already a vector allocated in FstatResults for it
412  // this also avoid having to copy these results in case the user asked for them to be returned
413  if ( whatToCompute & FSTATQ_FAFB ) {
414  XLALFree( ws->Fa_k ); // avoid memory leak if allocated in previous call
415  ws->Fa_k = Fstats->Fa;
416  XLALFree( ws->Fb_k ); // avoid memory leak if allocated in previous call
417  ws->Fb_k = Fstats->Fb;
418  } // end: if returning FaFb we can use that return-struct as 'workspace'
419  else { // otherwise: we (re)allocate it locally
420  if ( numFreqBins > ws->numFreqBinsAlloc ) {
421  XLAL_CHECK( ( ws->Fa_k = XLALRealloc( ws->Fa_k, numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
422  XLAL_CHECK( ( ws->Fb_k = XLALRealloc( ws->Fb_k, numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
423  } // only increase workspace arrays
424  }
425 
426  if ( whatToCompute & FSTATQ_FAFB_PER_DET ) {
427  XLALFree( ws->FaX_k ); // avoid memory leak if allocated in previous call
428  ws->FaX_k = NULL; // will be set in loop over detectors X
429  XLALFree( ws->FbX_k ); // avoid memory leak if allocated in previous call
430  ws->FbX_k = NULL; // will be set in loop over detectors X
431  } // end: if returning FaFbPerDet we can use that return-struct as 'workspace'
432  else { // otherwise: we (re)allocate it locally
433  if ( numFreqBins > ws->numFreqBinsAlloc ) {
434  XLAL_CHECK( ( ws->FaX_k = XLALRealloc( ws->FaX_k, numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
435  XLAL_CHECK( ( ws->FbX_k = XLALRealloc( ws->FbX_k, numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
436  } // only increase workspace arrays
437  }
438  if ( numFreqBins > ws->numFreqBinsAlloc ) {
439  ws->numFreqBinsAlloc = numFreqBins; // keep track of allocated array length
440  }
441 
442  if ( collectTiming ) {
443  toc = XLALGetCPUTime();
444  Tau->Mem = ( toc - tic ); // this one doesn't scale with number of detector!
445  }
446  // ====================================================================================================
447 
448  // loop over detectors
449  for ( UINT4 X = 0; X < numDetectors; X++ ) {
450  // if return-struct contains memory for holding FaFbPerDet: use that directly instead of local memory
451  if ( whatToCompute & FSTATQ_FAFB_PER_DET ) {
452  ws->FaX_k = Fstats->FaPerDet[X];
453  ws->FbX_k = Fstats->FbPerDet[X];
454  }
455  const COMPLEX8TimeSeries *TimeSeriesX_SRC_a = multiTimeSeries_SRC_a->data[X];
456  const COMPLEX8TimeSeries *TimeSeriesX_SRC_b = multiTimeSeries_SRC_b->data[X];
457 
458  // compute {Fa^X(f_k), Fb^X(f_k)}: results returned via workspace ws
459  XLAL_CHECK( XLALComputeFaFb_ResampGeneric( resamp, ws, thisPoint, common->dFreq, numFreqBins, TimeSeriesX_SRC_a, TimeSeriesX_SRC_b ) == XLAL_SUCCESS, XLAL_EFUNC );
460 
461  if ( collectTiming ) {
462  tic = XLALGetCPUTime();
463  }
464  if ( X == 0 ) {
465  // avoid having to memset this array: for the first detector we *copy* results
466  for ( UINT4 k = 0; k < numFreqBins; k++ ) {
467  ws->Fa_k[k] = ws->FaX_k[k];
468  ws->Fb_k[k] = ws->FbX_k[k];
469  }
470  } // end: if X==0
471  else {
472  // for subsequent detectors we *add to* them
473  for ( UINT4 k = 0; k < numFreqBins; k++ ) {
474  ws->Fa_k[k] += ws->FaX_k[k];
475  ws->Fb_k[k] += ws->FbX_k[k];
476  }
477  } // end:if X>0
478 
479  if ( collectTiming ) {
480  toc = XLALGetCPUTime();
481  Tau->SumFabX += ( toc - tic );
482  tic = toc;
483  }
484 
485  // ----- if requested: compute per-detector Fstat_X_k
486  if ( whatToCompute & FSTATQ_2F_PER_DET ) {
487  const REAL4 AdX = resamp->MmunuX[X].Ad;
488  const REAL4 BdX = resamp->MmunuX[X].Bd;
489  const REAL4 CdX = resamp->MmunuX[X].Cd;
490  const REAL4 EdX = resamp->MmunuX[X].Ed;
491  const REAL4 DdX_inv = 1.0f / resamp->MmunuX[X].Dd;
492  for ( UINT4 k = 0; k < numFreqBins; k ++ ) {
493  Fstats->twoFPerDet[X][k] = compute_fstat_from_fa_fb( ws->FaX_k[k], ws->FbX_k[k], AdX, BdX, CdX, EdX, DdX_inv );
494  } // for k < numFreqBins
495  } // end: if compute F_X
496 
497  if ( collectTiming ) {
498  toc = XLALGetCPUTime();
499  Tau->Fab2F += ( toc - tic );
500  }
501 
502  } // for X < numDetectors
503 
504  if ( collectTiming ) {
505  Tau->SumFabX /= numDetectors;
506  Tau->Fab2F /= numDetectors;
507  tic = XLALGetCPUTime();
508  }
509 
510  if ( whatToCompute & FSTATQ_2F ) {
511  const REAL4 Ad = resamp->Mmunu.Ad;
512  const REAL4 Bd = resamp->Mmunu.Bd;
513  const REAL4 Cd = resamp->Mmunu.Cd;
514  const REAL4 Ed = resamp->Mmunu.Ed;
515  const REAL4 Dd_inv = 1.0f / resamp->Mmunu.Dd;
516  for ( UINT4 k = 0; k < numFreqBins; k++ ) {
517  Fstats->twoF[k] = compute_fstat_from_fa_fb( ws->Fa_k[k], ws->Fb_k[k], Ad, Bd, Cd, Ed, Dd_inv );
518  }
519  } // if FSTATQ_2F
520  if ( whatToCompute & FSTATQ_2F_CUDA ) {
521  XLAL_ERROR( XLAL_EINVAL, "Not implemented for FSTATQ_2F_CUDA" );
522  }
523 
524  if ( collectTiming ) {
525  toc = XLALGetCPUTime();
526  Tau->Fab2F += ( toc - tic );
527  }
528 
529  // Return F-atoms per detector
530  if ( whatToCompute & FSTATQ_ATOMS_PER_DET ) {
531  XLAL_ERROR( XLAL_EFAILED, "NOT implemented!" );
532  }
533 
534  // Return antenna-pattern matrix
535  Fstats->Mmunu = resamp->Mmunu;
536 
537  // return per-detector antenna-pattern matrices
538  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
539  Fstats->MmunuX[X] = resamp->MmunuX[X];
540  }
541 
542  // ----- workspace memory management:
543  // if we used the return struct directly to store Fa,Fb results,
544  // make sure to wipe those pointers to avoid mistakenly considering them as 'local' memory
545  // and re-allocing it in another call to this function
546  if ( whatToCompute & FSTATQ_FAFB ) {
547  ws->Fa_k = NULL;
548  ws->Fb_k = NULL;
549  }
550  if ( whatToCompute & FSTATQ_FAFB_PER_DET ) {
551  ws->FaX_k = NULL;
552  ws->FbX_k = NULL;
553  }
554 
555  if ( collectTiming ) {
556  tocEnd = XLALGetCPUTime();
557 
558  FstatTimingGeneric *tiGen = &( resamp->timingGeneric );
559  FstatTimingResamp *tiRS = &( resamp->timingResamp );
560  XLAL_CHECK( numDetectors == tiGen->Ndet, XLAL_EINVAL, "Inconsistent number of detectors between XLALCreateSetup() [%d] and XLALComputeFstat() [%d]\n", tiGen->Ndet, numDetectors );
561 
562  Tau->Total = ( tocEnd - ticStart );
563  // rescale all relevant timings to per-detector
564  Tau->Total /= numDetectors;
565  Tau->Bary /= numDetectors;
566  Tau->Spin /= numDetectors;
567  Tau->FFT /= numDetectors;
568  Tau->Norm /= numDetectors;
569  Tau->Copy /= numDetectors;
570  REAL8 Tau_buffer = Tau->Bary;
571  // compute generic F-stat timing model contributions
572  UINT4 NFbin = Fstats->numFreqBins;
573  REAL8 tauF_eff = Tau->Total / NFbin;
574  REAL8 tauF_core = ( Tau->Total - Tau_buffer ) / NFbin;
575 
576  // compute resampling timing model coefficients
577  REAL8 tau0_Fbin = ( Tau->Copy + Tau->Norm + Tau->SumFabX + Tau->Fab2F ) / NFbin;
578  REAL8 tau0_spin = Tau->Spin / ( tiRS->Resolution * tiRS->NsampFFT );
579  REAL8 tau0_FFT = Tau->FFT / ( 5.0 * tiRS->NsampFFT * log2( tiRS->NsampFFT ) );
580 
581  // update the averaged timing-model quantities
582  tiGen->NCalls ++; // keep track of number of Fstat-calls for timing
583 #define updateAvgF(q) tiGen->q = ((tiGen->q *(tiGen->NCalls-1) + q)/(tiGen->NCalls))
584  updateAvgF( tauF_eff );
585  updateAvgF( tauF_core );
586  // we also average NFbin, which can be different between different calls to XLALComputeFstat() (contrary to Ndet)
587  updateAvgF( NFbin );
588 
589 #define updateAvgRS(q) tiRS->q = ((tiRS->q *(tiGen->NCalls-1) + q)/(tiGen->NCalls))
590  updateAvgRS( tau0_Fbin );
591  updateAvgRS( tau0_spin );
592  updateAvgRS( tau0_FFT );
593 
594  // buffer-quantities only updated if buffer was actually recomputed
595  if ( Tau->BufferRecomputed ) {
596  REAL8 tau0_bary = Tau_buffer / ( tiRS->Resolution * tiRS->NsampFFT );
597  REAL8 tauF_buffer = Tau_buffer / NFbin;
598 
599  updateAvgF( tauF_buffer );
600  updateAvgRS( tau0_bary );
601  } // if BufferRecomputed
602 
603  } // if collectTiming
604 
605  return XLAL_SUCCESS;
606 
607 } // XLALComputeFstatResampGeneric()
608 
609 
610 static int
611 XLALComputeFaFb_ResampGeneric( ResampGenericMethodData *resamp, //!< [in,out] buffered resampling data and workspace
612  ResampGenericWorkspace *ws, //!< [in,out] resampling workspace (memory-sharing across segments)
613  const PulsarDopplerParams thisPoint, //!< [in] Doppler point to compute {FaX,FbX} for
614  REAL8 dFreq, //!< [in] output frequency resolution
615  UINT4 numFreqBins, //!< [in] number of output frequency bins
616  const COMPLEX8TimeSeries *restrict TimeSeries_SRC_a, //!< [in] SRC-frame single-IFO timeseries * a(t)
617  const COMPLEX8TimeSeries *restrict TimeSeries_SRC_b //!< [in] SRC-frame single-IFO timeseries * b(t)
618  )
619 {
620  XLAL_CHECK( ( resamp != NULL ) && ( ws != NULL ) && ( TimeSeries_SRC_a != NULL ) && ( TimeSeries_SRC_b != NULL ), XLAL_EINVAL );
621  XLAL_CHECK( dFreq > 0, XLAL_EINVAL );
622  XLAL_CHECK( numFreqBins <= ws->numFreqBinsAlloc, XLAL_EINVAL );
623 
624  REAL8 FreqOut0 = thisPoint.fkdot[0];
625 
626  // compute frequency shift to align heterodyne frequency with output frequency bins
627  REAL8 fHet = TimeSeries_SRC_a->f0;
628  REAL8 dt_SRC = TimeSeries_SRC_a->deltaT;
629 
630  REAL8 dFreqFFT = dFreq / resamp->decimateFFT; // internally may be using higher frequency resolution dFreqFFT than requested
631  REAL8 freqShift = remainder( FreqOut0 - fHet, dFreq ); // frequency shift to closest bin
632  REAL8 fMinFFT = fHet + freqShift - dFreqFFT * ( resamp->numSamplesFFT / 2 ); // we'll shift DC into the *middle bin* N/2 [N always even!]
633  XLAL_CHECK( FreqOut0 >= fMinFFT, XLAL_EDOM, "Lowest output frequency outside the available frequency band: [FreqOut0 = %.16g] < [fMinFFT = %.16g]\n", FreqOut0, fMinFFT );
634  UINT4 offset_bins = ( UINT4 ) lround( ( FreqOut0 - fMinFFT ) / dFreqFFT );
635  UINT4 maxOutputBin = offset_bins + ( numFreqBins - 1 ) * resamp->decimateFFT;
636  XLAL_CHECK( maxOutputBin < resamp->numSamplesFFT, XLAL_EDOM, "Highest output frequency bin outside available band: [maxOutputBin = %d] >= [numSamplesFFT = %d]\n", maxOutputBin, resamp->numSamplesFFT );
637 
638  FstatTimingResamp *tiRS = &( resamp->timingResamp );
639  BOOLEAN collectTiming = resamp->collectTiming;
640  REAL8 tic = 0, toc = 0;
641 
642  XLAL_CHECK( resamp->numSamplesFFT >= TimeSeries_SRC_a->data->length, XLAL_EFAILED, "[numSamplesFFT = %d] < [len(TimeSeries_SRC_a) = %d]\n", resamp->numSamplesFFT, TimeSeries_SRC_a->data->length );
643  XLAL_CHECK( resamp->numSamplesFFT >= TimeSeries_SRC_b->data->length, XLAL_EFAILED, "[numSamplesFFT = %d] < [len(TimeSeries_SRC_b) = %d]\n", resamp->numSamplesFFT, TimeSeries_SRC_b->data->length );
644 
645  if ( collectTiming ) {
646  tic = XLALGetCPUTime();
647  }
648  memset( ws->TS_FFT, 0, resamp->numSamplesFFT * sizeof( ws->TS_FFT[0] ) );
649  // ----- compute FaX_k
650  // apply spindown phase-factors, store result in zero-padded timeseries for 'FFT'ing
651  XLAL_CHECK( XLALApplySpindownAndFreqShiftGeneric( ws->TS_FFT, TimeSeries_SRC_a, &thisPoint, freqShift ) == XLAL_SUCCESS, XLAL_EFUNC );
652 
653  if ( collectTiming ) {
654  toc = XLALGetCPUTime();
655  tiRS->Tau.Spin += ( toc - tic );
656  tic = toc;
657  }
658 
659  // Fourier transform the resampled Fa(t)
660  fftwf_execute_dft( resamp->fftplan, ws->TS_FFT, ws->FabX_Raw );
661 
662  if ( collectTiming ) {
663  toc = XLALGetCPUTime();
664  tiRS->Tau.FFT += ( toc - tic );
665  tic = toc;
666  }
667 
668  for ( UINT4 k = 0; k < numFreqBins; k++ ) {
669  ws->FaX_k[k] = ws->FabX_Raw [ offset_bins + k * resamp->decimateFFT ];
670  }
671 
672  if ( collectTiming ) {
673  toc = XLALGetCPUTime();
674  tiRS->Tau.Copy += ( toc - tic );
675  tic = toc;
676  }
677 
678  // ----- compute FbX_k
679  // apply spindown phase-factors, store result in zero-padded timeseries for 'FFT'ing
680  XLAL_CHECK( XLALApplySpindownAndFreqShiftGeneric( ws->TS_FFT, TimeSeries_SRC_b, &thisPoint, freqShift ) == XLAL_SUCCESS, XLAL_EFUNC );
681 
682  if ( collectTiming ) {
683  toc = XLALGetCPUTime();
684  tiRS->Tau.Spin += ( toc - tic );
685  tic = toc;
686  }
687 
688  // Fourier transform the resampled Fa(t)
689  fftwf_execute_dft( resamp->fftplan, ws->TS_FFT, ws->FabX_Raw );
690 
691  if ( collectTiming ) {
692  toc = XLALGetCPUTime();
693  tiRS->Tau.FFT += ( toc - tic );
694  tic = toc;
695  }
696 
697  for ( UINT4 k = 0; k < numFreqBins; k++ ) {
698  ws->FbX_k[k] = ws->FabX_Raw [ offset_bins + k * resamp->decimateFFT ];
699  }
700 
701  if ( collectTiming ) {
702  toc = XLALGetCPUTime();
703  tiRS->Tau.Copy += ( toc - tic );
704  tic = toc;
705  }
706 
707  // ----- normalization factors to be applied to Fa and Fb:
708  const REAL8 dtauX = GPSDIFF( TimeSeries_SRC_a->epoch, thisPoint.refTime );
709  for ( UINT4 k = 0; k < numFreqBins; k++ ) {
710  REAL8 f_k = FreqOut0 + k * dFreq;
711  REAL8 cycles = - f_k * dtauX;
712  REAL4 sinphase, cosphase;
713  XLALSinCos2PiLUT( &sinphase, &cosphase, cycles );
714  COMPLEX8 normX_k = dt_SRC * crectf( cosphase, sinphase );
715  ws->FaX_k[k] *= normX_k;
716  ws->FbX_k[k] *= normX_k;
717  } // for k < numFreqBinsOut
718 
719  if ( collectTiming ) {
720  toc = XLALGetCPUTime();
721  tiRS->Tau.Norm += ( toc - tic );
722  tic = toc;
723  }
724 
725  return XLAL_SUCCESS;
726 
727 } // XLALComputeFaFb_ResampGeneric()
728 
729 static int
730 XLALApplySpindownAndFreqShiftGeneric( COMPLEX8 *restrict xOut, ///< [out] the spindown-corrected SRC-frame timeseries
731  const COMPLEX8TimeSeries *restrict xIn, ///< [in] the input SRC-frame timeseries
732  const PulsarDopplerParams *restrict doppler, ///< [in] containing spindown parameters
733  REAL8 freqShift ///< [in] frequency-shift to apply, sign is "new - old"
734  )
735 {
736  // input sanity checks
737  XLAL_CHECK( xOut != NULL, XLAL_EINVAL );
738  XLAL_CHECK( xIn != NULL, XLAL_EINVAL );
739  XLAL_CHECK( doppler != NULL, XLAL_EINVAL );
740 
741  // determine number of spin downs to include
742  UINT4 s_max = PULSAR_MAX_SPINS - 1;
743  while ( ( s_max > 0 ) && ( doppler->fkdot[s_max] == 0 ) ) {
744  s_max --;
745  }
746 
747  REAL8 dt = xIn->deltaT;
748  UINT4 numSamplesIn = xIn->data->length;
749 
750  LIGOTimeGPS epoch = xIn->epoch;
751  REAL8 Dtau0 = GPSDIFF( epoch, doppler->refTime );
752 
753  // loop over time samples
754  for ( UINT4 j = 0; j < numSamplesIn; j ++ ) {
755  REAL8 taup_j = j * dt;
756  REAL8 Dtau_alpha_j = Dtau0 + taup_j;
757 
758  REAL8 cycles = - freqShift * taup_j;
759 
760  REAL8 Dtau_pow_kp1 = Dtau_alpha_j;
761  for ( UINT4 k = 1; k <= s_max; k++ ) {
762  Dtau_pow_kp1 *= Dtau_alpha_j;
763  cycles += - LAL_FACT_INV[k + 1] * doppler->fkdot[k] * Dtau_pow_kp1;
764  } // for k = 1 ... s_max
765 
766  REAL4 cosphase, sinphase;
767  XLAL_CHECK( XLALSinCos2PiLUT( &sinphase, &cosphase, cycles ) == XLAL_SUCCESS, XLAL_EFUNC );
768  COMPLEX8 em2piphase = crectf( cosphase, sinphase );
769 
770  // weight the complex timeseries by the antenna patterns
771  xOut[j] = em2piphase * xIn->data->data[j];
772 
773  } // for j < numSamplesIn
774 
775  return XLAL_SUCCESS;
776 
777 } // XLALApplySpindownAndFreqShiftGeneric()
778 
779 ///
780 /// Performs barycentric resampling on a multi-detector timeseries, updates resampling buffer with results
781 ///
782 /// NOTE Buffering: this function does check
783 /// 1) whether the previously-buffered solution can be completely reused (same sky-position and binary parameters), or
784 /// 2) if at least sky-dependent quantities can be re-used (antenna-patterns + timings) in case only binary parameters changed
785 ///
786 static int
788  ResampGenericMethodData *resamp, // [in/out] resampling input and buffer (to store resampling TS)
789  const PulsarDopplerParams *thisPoint, // [in] current skypoint and reftime
790  const FstatCommon *common // [in] various input quantities and parameters used here
791 )
792 {
793  // check input sanity
794  XLAL_CHECK( thisPoint != NULL, XLAL_EINVAL );
795  XLAL_CHECK( common != NULL, XLAL_EINVAL );
796  XLAL_CHECK( resamp != NULL, XLAL_EINVAL );
797  XLAL_CHECK( resamp->multiTimeSeries_DET != NULL, XLAL_EINVAL );
798  XLAL_CHECK( resamp->multiTimeSeries_SRC_a != NULL, XLAL_EINVAL );
799  XLAL_CHECK( resamp->multiTimeSeries_SRC_b != NULL, XLAL_EINVAL );
800 
802 
804  XLAL_CHECK( resamp->multiTimeSeries_SRC_a->length == numDetectors, XLAL_EINVAL, "Inconsistent number of detectors tsDET(%d) != tsSRC(%d)\n", numDetectors, resamp->multiTimeSeries_SRC_a->length );
805  XLAL_CHECK( resamp->multiTimeSeries_SRC_b->length == numDetectors, XLAL_EINVAL, "Inconsistent number of detectors tsDET(%d) != tsSRC(%d)\n", numDetectors, resamp->multiTimeSeries_SRC_b->length );
806 
807  // ============================== BEGIN: handle buffering =============================
808  BOOLEAN same_skypos = ( resamp->prev_doppler.Alpha == thisPoint->Alpha ) && ( resamp->prev_doppler.Delta == thisPoint->Delta );
809  BOOLEAN same_refTime = ( GPSDIFF( resamp->prev_doppler.refTime, thisPoint->refTime ) == 0 );
810  BOOLEAN same_binary = \
811  ( resamp->prev_doppler.asini == thisPoint->asini ) &&
812  ( resamp->prev_doppler.period == thisPoint->period ) &&
813  ( resamp->prev_doppler.ecc == thisPoint->ecc ) &&
814  ( GPSDIFF( resamp->prev_doppler.tp, thisPoint->tp ) == 0 ) &&
815  ( resamp->prev_doppler.argp == thisPoint->argp );
816 
817  Timings_t *Tau = &( resamp->timingResamp.Tau );
818  REAL8 tic = 0, toc = 0;
819  BOOLEAN collectTiming = resamp->collectTiming;
820 
821  // if same sky-position *and* same binary, we can simply return as there's nothing to be done here
822  if ( same_skypos && same_refTime && same_binary ) {
823  Tau->BufferRecomputed = 0;
824  return XLAL_SUCCESS;
825  }
826  // else: keep track of 'buffer miss', ie we need to recompute the buffer
827  Tau->BufferRecomputed = 1;
828  resamp->timingGeneric.NBufferMisses ++;
829  if ( collectTiming ) {
830  tic = XLALGetCPUTime();
831  }
832 
833  MultiSSBtimes *multiSRCtimes = NULL;
834 
835  // only if different sky-position: re-compute antenna-patterns and SSB timings, re-use from buffer otherwise
836  if ( !( same_skypos && same_refTime ) ) {
837  SkyPosition skypos;
839  skypos.longitude = thisPoint->Alpha;
840  skypos.latitude = thisPoint->Delta;
841 
843  XLAL_CHECK( ( resamp->multiAMcoef = XLALComputeMultiAMCoeffs( common->multiDetectorStates, common->multiNoiseWeights, skypos ) ) != NULL, XLAL_EFUNC );
844  resamp->Mmunu = resamp->multiAMcoef->Mmunu;
845  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
846  resamp->MmunuX[X].Ad = resamp->multiAMcoef->data[X]->A;
847  resamp->MmunuX[X].Bd = resamp->multiAMcoef->data[X]->B;
848  resamp->MmunuX[X].Cd = resamp->multiAMcoef->data[X]->C;
849  resamp->MmunuX[X].Ed = 0;
850  resamp->MmunuX[X].Dd = resamp->multiAMcoef->data[X]->D;
851  }
852 
854  XLAL_CHECK( ( resamp->multiSSBtimes = XLALGetMultiSSBtimes( common->multiDetectorStates, skypos, thisPoint->refTime, common->SSBprec ) ) != NULL, XLAL_EFUNC );
855 
856  } // if cannot re-use buffered solution ie if !(same_skypos && same_binary)
857 
858  if ( thisPoint->asini > 0 ) { // binary case
860  multiSRCtimes = resamp->multiBinaryTimes;
861  } else { // isolated case
862  multiSRCtimes = resamp->multiSSBtimes;
863  }
864 
865  // record barycenter parameters in order to allow re-usal of this result ('buffering')
866  resamp->prev_doppler = ( *thisPoint );
867 
868  // shorthands
869  REAL8 fHet = resamp->multiTimeSeries_DET->data[0]->f0;
870  REAL8 Tsft = common->multiTimestamps->data[0]->deltaT;
871  REAL8 dt_SRC = resamp->multiTimeSeries_SRC_a->data[0]->deltaT;
872 
873  const REAL4 signumLUT[2] = {1, -1};
874 
875  // loop over detectors X
876  for ( UINT4 X = 0; X < numDetectors; X++ ) {
877  // shorthand pointers: input
878  const COMPLEX8TimeSeries *TimeSeries_DETX = resamp->multiTimeSeries_DET->data[X];
879  const LIGOTimeGPSVector *Timestamps_DETX = common->multiTimestamps->data[X];
880  const SSBtimes *SRCtimesX = multiSRCtimes->data[X];
881  const AMCoeffs *AMcoefX = resamp->multiAMcoef->data[X];
882 
883  // shorthand pointers: output
884  COMPLEX8TimeSeries *TimeSeries_SRCX_a = resamp->multiTimeSeries_SRC_a->data[X];
885  COMPLEX8TimeSeries *TimeSeries_SRCX_b = resamp->multiTimeSeries_SRC_b->data[X];
886  REAL8Vector *ti_DET = ws->SRCtimes_DET;
887 
888  // useful shorthands
889  REAL8 refTime8 = GPSGETREAL8( &SRCtimesX->refTime );
890  UINT4 numSFTsX = Timestamps_DETX->length;
891  UINT4 numSamples_DETX = TimeSeries_DETX->data->length;
892  UINT4 numSamples_SRCX = TimeSeries_SRCX_a->data->length;
893 
894  // sanity checks on input data
895  XLAL_CHECK( numSamples_SRCX == TimeSeries_SRCX_b->data->length, XLAL_EINVAL );
896  XLAL_CHECK( dt_SRC == TimeSeries_SRCX_a->deltaT, XLAL_EINVAL );
897  XLAL_CHECK( dt_SRC == TimeSeries_SRCX_b->deltaT, XLAL_EINVAL );
898  XLAL_CHECK( numSamples_DETX > 0, XLAL_EINVAL, "Input timeseries for detector X=%d has zero samples. Can't handle that!\n", X );
899  XLAL_CHECK( ( SRCtimesX->DeltaT->length == numSFTsX ) && ( SRCtimesX->Tdot->length == numSFTsX ), XLAL_EINVAL );
900  REAL8 fHetX = resamp->multiTimeSeries_DET->data[X]->f0;
901  XLAL_CHECK( fabs( fHet - fHetX ) < LAL_REAL8_EPS * fHet, XLAL_EINVAL, "Input timeseries must have identical heterodyning frequency 'f0(X=%d)' (%.16g != %.16g)\n", X, fHet, fHetX );
902  REAL8 TsftX = common->multiTimestamps->data[X]->deltaT;
903  XLAL_CHECK( Tsft == TsftX, XLAL_EINVAL, "Input timestamps must have identical stepsize 'Tsft(X=%d)' (%.16g != %.16g)\n", X, Tsft, TsftX );
904 
905  TimeSeries_SRCX_a->f0 = fHet;
906  TimeSeries_SRCX_b->f0 = fHet;
907  // set SRC-frame time-series start-time
908  REAL8 tStart_SRC_0 = refTime8 + SRCtimesX->DeltaT->data[0] - ( 0.5 * Tsft ) * SRCtimesX->Tdot->data[0];
910  GPSSETREAL8( epoch, tStart_SRC_0 );
911  TimeSeries_SRCX_a->epoch = epoch;
912  TimeSeries_SRCX_b->epoch = epoch;
913 
914  // make sure all output samples are initialized to zero first, in case of gaps
915  memset( TimeSeries_SRCX_a->data->data, 0, TimeSeries_SRCX_a->data->length * sizeof( TimeSeries_SRCX_a->data->data[0] ) );
916  memset( TimeSeries_SRCX_b->data->data, 0, TimeSeries_SRCX_b->data->length * sizeof( TimeSeries_SRCX_b->data->data[0] ) );
917  // make sure detector-frame timesteps to interpolate to are initialized to 0, in case of gaps
918  memset( ws->SRCtimes_DET->data, 0, ws->SRCtimes_DET->length * sizeof( ws->SRCtimes_DET->data[0] ) );
919 
920  memset( ws->TStmp1_SRC->data, 0, ws->TStmp1_SRC->length * sizeof( ws->TStmp1_SRC->data[0] ) );
921  memset( ws->TStmp2_SRC->data, 0, ws->TStmp2_SRC->length * sizeof( ws->TStmp2_SRC->data[0] ) );
922 
923  REAL8 tStart_DET_0 = GPSGETREAL8( &( Timestamps_DETX->data[0] ) ); // START time of the SFT at the detector
924 
925  // loop over SFT timestamps and compute the detector frame time samples corresponding to uniformly sampled SRC time samples
926  for ( UINT4 alpha = 0; alpha < numSFTsX; alpha ++ ) {
927  // define some useful shorthands
928  REAL8 Tdot_al = SRCtimesX->Tdot->data [ alpha ]; // the instantaneous time derivitive dt_SRC/dt_DET at the MID-POINT of the SFT
929  REAL8 tMid_SRC_al = refTime8 + SRCtimesX->DeltaT->data[alpha]; // MID-POINT time of the SFT at the SRC
930  REAL8 tStart_SRC_al = tMid_SRC_al - 0.5 * Tsft * Tdot_al; // approximate START time of the SFT at the SRC
931  REAL8 tEnd_SRC_al = tMid_SRC_al + 0.5 * Tsft * Tdot_al; // approximate END time of the SFT at the SRC
932 
933  REAL8 tStart_DET_al = GPSGETREAL8( &( Timestamps_DETX->data[alpha] ) ); // START time of the SFT at the detector
934  REAL8 tMid_DET_al = tStart_DET_al + 0.5 * Tsft; // MID-POINT time of the SFT at the detector
935 
936  // indices of first and last SRC-frame sample corresponding to this SFT
937  UINT4 iStart_SRC_al = lround( ( tStart_SRC_al - tStart_SRC_0 ) / dt_SRC ); // the index of the resampled timeseries corresponding to the start of the SFT
938  UINT4 iEnd_SRC_al = lround( ( tEnd_SRC_al - tStart_SRC_0 ) / dt_SRC ); // the index of the resampled timeseries corresponding to the end of the SFT
939 
940  // truncate to actual SRC-frame timeseries
941  iStart_SRC_al = MYMIN( iStart_SRC_al, numSamples_SRCX - 1 );
942  iEnd_SRC_al = MYMIN( iEnd_SRC_al, numSamples_SRCX - 1 );
943  UINT4 numSamplesSFT_SRC_al = iEnd_SRC_al - iStart_SRC_al + 1; // the number of samples in the SRC-frame for this SFT
944 
945  REAL4 a_al = AMcoefX->a->data[alpha];
946  REAL4 b_al = AMcoefX->b->data[alpha];
947  for ( UINT4 j = 0; j < numSamplesSFT_SRC_al; j++ ) {
948  UINT4 iSRC_al_j = iStart_SRC_al + j;
949 
950  // for each time sample in the SRC frame, we estimate the corresponding detector time,
951  // using a linear approximation expanding around the midpoint of each SFT
952  REAL8 t_SRC = tStart_SRC_0 + iSRC_al_j * dt_SRC;
953  ti_DET->data [ iSRC_al_j ] = tMid_DET_al + ( t_SRC - tMid_SRC_al ) / Tdot_al;
954 
955  // pre-compute correction factors due to non-zero heterodyne frequency of input
956  REAL8 tDiff = iSRC_al_j * dt_SRC + ( tStart_DET_0 - ti_DET->data [ iSRC_al_j ] ); // tSRC_al_j - tDET(tSRC_al_j)
957  REAL8 cycles = fmod( fHet * tDiff, 1.0 ); // the accumulated heterodyne cycles
958 
959  // use a look-up-table for speed to compute real and imaginary phase
960  REAL4 cosphase, sinphase; // the real and imaginary parts of the phase correction
961  XLAL_CHECK( XLALSinCos2PiLUT( &sinphase, &cosphase, -cycles ) == XLAL_SUCCESS, XLAL_EFUNC );
962  COMPLEX8 ei2piphase = crectf( cosphase, sinphase );
963 
964  // apply AM coefficients a(t), b(t) to SRC frame timeseries [alternate sign to get final FFT return DC in the middle]
965  REAL4 signum = signumLUT [( iSRC_al_j % 2 ) ]; // alternating sign, avoid branching
966  ei2piphase *= signum;
967  ws->TStmp1_SRC->data [ iSRC_al_j ] = ei2piphase * a_al;
968  ws->TStmp2_SRC->data [ iSRC_al_j ] = ei2piphase * b_al;
969  } // for j < numSamples_SRC_al
970 
971  } // for alpha < numSFTsX
972 
973  XLAL_CHECK( ti_DET->length >= TimeSeries_SRCX_a->data->length, XLAL_EINVAL );
974  UINT4 bak_length = ti_DET->length;
975  ti_DET->length = TimeSeries_SRCX_a->data->length;
976  XLAL_CHECK( XLALSincInterpolateCOMPLEX8TimeSeries( TimeSeries_SRCX_a->data, ti_DET, TimeSeries_DETX, resamp->Dterms ) == XLAL_SUCCESS, XLAL_EFUNC );
977  ti_DET->length = bak_length;
978 
979  // apply heterodyne correction and AM-functions a(t) and b(t) to interpolated timeseries
980  for ( UINT4 j = 0; j < numSamples_SRCX; j ++ ) {
981  TimeSeries_SRCX_b->data->data[j] = TimeSeries_SRCX_a->data->data[j] * ws->TStmp2_SRC->data[j];
982  TimeSeries_SRCX_a->data->data[j] *= ws->TStmp1_SRC->data[j];
983  } // for j < numSamples_SRCX
984 
985  } // for X < numDetectors
986 
987  if ( collectTiming ) {
988  toc = XLALGetCPUTime();
989  Tau->Bary = ( toc - tic );
990  }
991 
992  return XLAL_SUCCESS;
993 
994 } // XLALBarycentricResampleMultiCOMPLEX8TimeSeriesGeneric()
995 
996 static void
997 XLALGetFFTPlanHints( int *planMode,
998  double *planGenTimeoutSeconds
999  )
1000 {
1001  char *planMode_env = getenv( "LAL_FSTAT_FFT_PLAN_MODE" );
1002  char *planGenTimeout_env = getenv( "LAL_FSTAT_FFT_PLAN_TIMEOUT" );;
1003  int fft_plan_flags = FFTW_MEASURE;
1004  double fft_plan_timeout = FFTW_NO_TIMELIMIT ;
1005 
1006  if ( planGenTimeout_env ) {
1007  char *end;
1008  fft_plan_timeout = strtod( planGenTimeout_env, & end );
1009  if ( end[0] != '\0' ) {
1010  fft_plan_timeout = FFTW_NO_TIMELIMIT;
1011  }
1012  }
1013 
1014  if ( planMode_env ) {
1015  if ( strcmp( planMode_env, "ESTIMATE" ) == 0 ) {
1016  fft_plan_flags = FFTW_ESTIMATE;
1017  }
1018 
1019  if ( strcmp( planMode_env, "MEASURE" ) == 0 ) {
1020  fft_plan_flags = FFTW_MEASURE;
1021  }
1022 
1023  if ( strcmp( planMode_env, "PATIENT" ) == 0 ) {
1024  fft_plan_flags = FFTW_PATIENT;
1025  }
1026  }
1027  *planMode = fft_plan_flags;
1028  *planGenTimeoutSeconds = fft_plan_timeout;
1029 } // XLALGetFFTPlanHints
1030 
1031 int
1032 XLALExtractResampledTimeseries_ResampGeneric( MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_a, MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_b, void *method_data )
1033 {
1034  XLAL_CHECK( method_data != NULL, XLAL_EINVAL );
1035  XLAL_CHECK( ( multiTimeSeries_SRC_a != NULL ) && ( multiTimeSeries_SRC_b != NULL ), XLAL_EINVAL );
1036  XLAL_CHECK( method_data != NULL, XLAL_EINVAL );
1037 
1038  ResampGenericMethodData *resamp = ( ResampGenericMethodData * ) method_data;
1039  *multiTimeSeries_SRC_a = resamp->multiTimeSeries_SRC_a;
1040  *multiTimeSeries_SRC_b = resamp->multiTimeSeries_SRC_b;
1041 
1042  return XLAL_SUCCESS;
1043 
1044 } // XLALExtractResampledTimeseries_intern()
1045 
1046 int
1047 XLALGetFstatTiming_ResampGeneric( const void *method_data, FstatTimingGeneric *timingGeneric, FstatTimingModel *timingModel )
1048 {
1049  XLAL_CHECK( method_data != NULL, XLAL_EINVAL );
1050  XLAL_CHECK( timingGeneric != NULL, XLAL_EINVAL );
1051  XLAL_CHECK( timingModel != NULL, XLAL_EINVAL );
1052 
1053  const ResampGenericMethodData *resamp = ( const ResampGenericMethodData * ) method_data;
1054  XLAL_CHECK( resamp != NULL, XLAL_EINVAL );
1055 
1056  ( *timingGeneric ) = resamp->timingGeneric; // struct-copy generic timing measurements
1057 
1059 
1060  return XLAL_SUCCESS;
1061 } // XLALGetFstatTiming_ResampGeneric()
1062 
1063 /// @}
#define updateAvgF(q)
#define updateAvgRS(q)
#define GPSGETREAL8(x)
#define GPSSETREAL8(gps, r8)
#define GPSDIFF(x, y)
static int XLALGetFstatTiming_Resamp_intern(const FstatTimingResamp *tiRS, FstatTimingModel *timingModel)
static REAL4 compute_fstat_from_fa_fb(COMPLEX8 Fa, COMPLEX8 Fb, REAL4 A, REAL4 B, REAL4 C, REAL4 E, REAL4 Dinv)
#define LAL_FFTW_WISDOM_UNLOCK
#define LAL_FFTW_WISDOM_LOCK
int j
int k
static int XLALComputeFstatResampGeneric(FstatResults *Fstats, const FstatCommon *common, void *method_data)
static void XLALDestroyResampGenericMethodData(void *method_data)
static int XLALApplySpindownAndFreqShiftGeneric(COMPLEX8 *xOut, const COMPLEX8TimeSeries *xIn, const PulsarDopplerParams *doppler, REAL8 freqShift)
static int XLALComputeFaFb_ResampGeneric(ResampGenericMethodData *resamp, ResampGenericWorkspace *ws, const PulsarDopplerParams thisPoint, REAL8 dFreq, UINT4 numFreqBins, const COMPLEX8TimeSeries *TimeSeries_SRC_a, const COMPLEX8TimeSeries *TimeSeries_SRC_b)
int XLALExtractResampledTimeseries_ResampGeneric(MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_a, MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_b, void *method_data)
int XLALGetFstatTiming_ResampGeneric(const void *method_data, FstatTimingGeneric *timingGeneric, FstatTimingModel *timingModel)
static int XLALBarycentricResampleMultiCOMPLEX8TimeSeriesGeneric(ResampGenericMethodData *resamp, const PulsarDopplerParams *thisPoint, const FstatCommon *common)
Performs barycentric resampling on a multi-detector timeseries, updates resampling buffer with result...
int XLALSetupFstatResampGeneric(void **method_data, FstatCommon *common, FstatMethodFuncs *funcs, MultiSFTVector *multiSFTs, const FstatOptionalArgs *optArgs)
static void XLALGetFFTPlanHints(int *planMode, double *planGenTimeoutSeconds)
static void XLALDestroyResampGenericWorkspace(void *workspace)
FstatQuantities
Bit-field of -statistic quantities which can be computed by XLALComputeFstat().
Definition: ComputeFstat.h:94
@ FSTATQ_2F
Compute multi-detector .
Definition: ComputeFstat.h:96
@ FSTATQ_FAFB_PER_DET
Compute and for each detector.
Definition: ComputeFstat.h:99
@ FSTATQ_FAFB
Compute multi-detector and .
Definition: ComputeFstat.h:97
@ FSTATQ_NONE
Do not compute -statistic, still compute buffered quantities.
Definition: ComputeFstat.h:95
@ FSTATQ_2F_CUDA
Compute multi-detector , store results on CUDA GPU (CUDA implementation of Resamp only).
Definition: ComputeFstat.h:101
@ FSTATQ_ATOMS_PER_DET
Compute per-SFT -statistic atoms for each detector (Demod only).
Definition: ComputeFstat.h:100
@ FSTATQ_2F_PER_DET
Compute for each detector.
Definition: ComputeFstat.h:98
static const REAL8 LAL_FACT_INV[]
void XLALDestroyMultiAMCoeffs(MultiAMCoeffs *multiAMcoef)
Destroy a MultiAMCoeffs structure.
Definition: LALComputeAM.c:469
MultiAMCoeffs * XLALComputeMultiAMCoeffs(const MultiDetectorStateSeries *multiDetStates, const MultiNoiseWeights *multiWeights, SkyPosition skypos)
Multi-IFO version of XLALComputeAMCoeffs().
Definition: LALComputeAM.c:379
#define LAL_REAL8_EPS
unsigned char BOOLEAN
#define XLAL_INIT_MEM(x)
double REAL8
#define XLAL_INIT_DECL(var,...)
#define crectf(re, im)
uint32_t UINT4
float complex COMPLEX8
float REAL4
void * XLALCalloc(size_t m, size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
#define LAL_UINT4_FORMAT
MultiCOMPLEX8TimeSeries * XLALMultiSFTVectorToCOMPLEX8TimeSeries(const MultiSFTVector *multisfts)
Turn the given multiSFTvector into multiple long COMPLEX8TimeSeries, properly dealing with gaps.
int XLALSincInterpolateCOMPLEX8TimeSeries(COMPLEX8Vector *y_out, const REAL8Vector *t_out, const COMPLEX8TimeSeries *ts_in, UINT4 Dterms)
Interpolate a given regularly-spaced COMPLEX8 timeseries 'ts_in = x_in(j * dt)' onto new samples 'y_o...
void XLALDestroyMultiCOMPLEX8TimeSeries(MultiCOMPLEX8TimeSeries *multiTimes)
Destroy a MultiCOMPLEX8TimeSeries structure.
REAL8 XLALGetCPUTime(void)
#define PULSAR_MAX_DETECTORS
maximal number of detectors we can handle (for static arrays of detector quantities)
#define PULSAR_MAX_SPINS
maximal number of spin-parameters (Freq + spindowns) we can handle
void XLALDestroyMultiSFTVector(MultiSFTVector *multvect)
Destroy a multi SFT-vector.
Definition: SFTtypes.c:424
int XLALMultiSFTVectorResizeBand(MultiSFTVector *multiSFTs, REAL8 f0, REAL8 Band)
Resize the frequency-band of a given multi-SFT vector to [f0, f0+Band].
Definition: SFTtypes.c:946
MultiSSBtimes * XLALGetMultiSSBtimes(const MultiDetectorStateSeries *multiDetStates, SkyPosition skypos, LIGOTimeGPS refTime, SSBprecision precision)
Multi-IFO version of XLALGetSSBtimes().
Definition: SSBtimes.c:657
void XLALDestroyMultiSSBtimes(MultiSSBtimes *multiSSB)
Destroy a MultiSSBtimes structure.
Definition: SSBtimes.c:845
int XLALAddMultiBinaryTimes(MultiSSBtimes **multiSSBOut, const MultiSSBtimes *multiSSBIn, const PulsarDopplerParams *Doppler)
Multi-IFO version of XLALAddBinaryTimes().
Definition: SSBtimes.c:413
int XLALSinCos2PiLUT(REAL4 *sin2pix, REAL4 *cos2pix, REAL8 x)
Calculate sin(2*pi*x) and cos(2*pi*x) to roughly 1e-7 precision using a lookup-table and Taylor-expan...
Definition: SinCosLUT.c:97
COORDINATESYSTEM_EQUATORIAL
COMPLEX8TimeSeries * XLALCreateCOMPLEX8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
const LALUnit lalDimensionlessUnit
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
COMPLEX8Vector * XLALCreateCOMPLEX8Vector(UINT4 length)
void XLALDestroyCOMPLEX8Vector(COMPLEX8Vector *vector)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EINVAL
XLAL_EFAILED
end
#define MYMIN(x, y)
#define MYMAX(x, y)
double alpha
size_t numDetectors
This structure contains the per-SFT (weighted) antenna-pattern functions , with the SFT-index,...
Definition: LALComputeAM.h:63
REAL4 B
summed antenna-pattern matrix coefficient:
Definition: LALComputeAM.h:67
REAL4Vector * b
(weighted) per-SFT antenna-pattern function
Definition: LALComputeAM.h:65
REAL4 A
summed antenna-pattern matrix coefficient:
Definition: LALComputeAM.h:66
REAL4 C
summed antenna-pattern matrix coefficient:
Definition: LALComputeAM.h:68
REAL4Vector * a
(weighted) per-SFT antenna-pattern function
Definition: LALComputeAM.h:64
REAL4 D
determinant
Definition: LALComputeAM.h:69
Struct holding the "antenna-pattern" matrix , in terms of the multi-detector scalar product.
Definition: LALComputeAM.h:127
REAL4 Dd
determinant factor , such that
Definition: LALComputeAM.h:132
CHAR name[LALNameLength]
LIGOTimeGPS epoch
COMPLEX8Sequence * data
COMPLEX8 * data
MultiDetectorStateSeries * multiDetectorStates
SSBprecision SSBprec
MultiLIGOTimeGPSVector * multiTimestamps
MultiNoiseWeights * multiNoiseWeights
void(* workspace_destroy_func)(void *)
void(* method_data_destroy_func)(void *)
int(* compute_func)(FstatResults *, const FstatCommon *, void *)
Struct of optional 'advanced level' and (potentially method-specific) arguments to be passed to the ...
Definition: ComputeFstat.h:136
BOOLEAN resampFFTPowerOf2
Resamp: round up FFT lengths to next power of 2; see FstatMethodType.
Definition: ComputeFstat.h:147
BOOLEAN collectTiming
a flag to turn on/off the collection of F-stat-method-specific timing-data
Definition: ComputeFstat.h:146
UINT4 Dterms
Number of Dirichlet kernel terms, used by some Demod methods; see FstatMethodType.
Definition: ComputeFstat.h:139
XLALComputeFstat() computed results structure.
Definition: ComputeFstat.h:201
AntennaPatternMatrix MmunuX[PULSAR_MAX_DETECTORS]
Per detector antenna pattern matrix , used in computing .
Definition: ComputeFstat.h:230
COMPLEX8 * Fb
Definition: ComputeFstat.h:259
AntennaPatternMatrix Mmunu
Antenna pattern matrix , used in computing .
Definition: ComputeFstat.h:227
REAL4 * twoFPerDet[PULSAR_MAX_DETECTORS]
If whatWasComputed & FSTATQ_2F_PER_DET is true, the values computed at numFreqBins frequencies space...
Definition: ComputeFstat.h:268
FstatQuantities whatWasComputed
Bit-field of which -statistic quantities were computed.
Definition: ComputeFstat.h:233
COMPLEX8 * FaPerDet[PULSAR_MAX_DETECTORS]
If whatWasComputed & FSTATQ_PARTS_PER_DET is true, the and values computed at numFreqBins frequenci...
Definition: ComputeFstat.h:278
UINT4 numFreqBins
Number of frequencies at which the were computed.
Definition: ComputeFstat.h:216
REAL4 * twoF
If whatWasComputed & FSTATQ_2F is true, the multi-detector values computed at numFreqBins frequencie...
Definition: ComputeFstat.h:241
COMPLEX8 * Fa
If whatWasComputed & FSTATQ_PARTS is true, the multi-detector and computed at numFreqBins frequenci...
Definition: ComputeFstat.h:258
COMPLEX8 * FbPerDet[PULSAR_MAX_DETECTORS]
Definition: ComputeFstat.h:279
PulsarDopplerParams doppler
Doppler parameters, including the starting frequency, at which the were computed.
Definition: ComputeFstat.h:205
Generic F-stat timing coefficients (times in seconds) [see https://dcc.ligo.org/LIGO-T1600531-v4 for ...
Definition: ComputeFstat.h:307
Struct to carry the -statistic method-specific timing model in terms of a list of variable names and...
Definition: ComputeFstat.h:326
A vector of 'timestamps' of type LIGOTimeGPS.
Definition: SFTfileIO.h:188
REAL8 deltaT
'length' of each timestamp (e.g.
Definition: SFTfileIO.h:194
LIGOTimeGPS * data
array of timestamps
Definition: SFTfileIO.h:193
UINT4 length
number of timestamps
Definition: SFTfileIO.h:192
Multi-IFO container for antenna-pattern coefficients and atenna-pattern matrix .
Definition: LALComputeAM.h:137
AMCoeffs ** data
noise-weighted AM-coeffs , and
Definition: LALComputeAM.h:139
AntennaPatternMatrix Mmunu
antenna-pattern matrix
Definition: LALComputeAM.h:140
Multi-IFO container for COMPLEX8 resampled timeseries.
Definition: LFTandTSutils.h:52
COMPLEX8TimeSeries ** data
array of COMPLEX8TimeSeries (pointers)
Definition: LFTandTSutils.h:54
UINT4 length
number of IFOs
Definition: LFTandTSutils.h:53
LIGOTimeGPSVector ** data
timestamps vector for each ifo
Definition: SFTfileIO.h:203
A collection of SFT vectors – one for each IFO in a multi-IFO search.
Definition: SFTfileIO.h:179
Multi-IFO container for SSB timings.
Definition: SSBtimes.h:67
SSBtimes ** data
array of SSBtimes (pointers)
Definition: SSBtimes.h:69
Type containing the 'Doppler-parameters' affecting the time-evolution of the phase.
REAL8 period
Binary: orbital period (sec)
LIGOTimeGPS tp
Binary: time of observed periapsis passage (in SSB)
PulsarSpins fkdot
Intrinsic spins: [Freq, f1dot, f2dot, ...
REAL8 Delta
Sky position: DEC (latitude) in equatorial coords and radians.
LIGOTimeGPS refTime
Reference time of pulsar parameters (in SSB!)
REAL8 Alpha
Sky position: RA (longitude) in equatorial coords and radians.
REAL8 ecc
Binary: orbital eccentricity.
REAL8 asini
Binary: projected, normalized orbital semi-major axis (s).
REAL8 argp
Binary: argument of periapsis (radians)
REAL4 * data
REAL8 * data
MultiCOMPLEX8TimeSeries * multiTimeSeries_DET
MultiCOMPLEX8TimeSeries * multiTimeSeries_SRC_a
AntennaPatternMatrix MmunuX[PULSAR_MAX_DETECTORS]
MultiCOMPLEX8TimeSeries * multiTimeSeries_SRC_b
Simple container for two REAL8-vectors, namely the SSB-timings DeltaT_alpha and Tdot_alpha,...
Definition: SSBtimes.h:60
REAL8Vector * Tdot
dT/dt : time-derivative of SSB-time wrt local time for SFT-alpha
Definition: SSBtimes.h:63
REAL8Vector * DeltaT
Time-difference of SFT-alpha - tau0 in SSB-frame.
Definition: SSBtimes.h:62
LIGOTimeGPS refTime
reference-time 'tau0'
Definition: SSBtimes.h:61
REAL8 longitude
REAL8 latitude
CoordinateSystem system
enum @1 epoch