LALPulsar  6.1.0.1-89842e6
PulsarCrossCorr_v2.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012, 2013 John Whelan, Shane Larson and Badri Krishnan
3  * Copyright (C) 2013, 2014 Badri Krishnan, John Whelan, Yuanhao Zhang
4  * Copyright (C) 2016, 2017 Grant David Meadors
5  * Copyright (C) 2023 John Whelan
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with with program; see the file COPYING. If not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20  * MA 02110-1301 USA
21  */
22 
23 #include <lal/PulsarCrossCorr_v2.h>
24 
25 #define SQUARE(x) ((x)*(x))
26 #define QUAD(x) ((x)*(x)*(x)*(x))
27 #define GPSDIFF(x,y) (1.0*((x).gpsSeconds - (y).gpsSeconds) + ((x).gpsNanoSeconds - (y).gpsNanoSeconds)*1e-9)
28 #define MYMAX(x,y) ( (x) > (y) ? (x) : (y) )
29 #define MYMIN(x,y) ( (x) < (y) ? (x) : (y) )
30 #define USE_ALIGNED_MEMORY_ROUTINES
31 #define TRUE (1==1)
32 #define FALSE (1==0)
33 
34 
35 // ----- local prototypes ----------
36 static int
38 (
39  COMPLEX8 *restrict xOut,
40  const COMPLEX8TimeSeries *restrict xIn,
41  const PulsarDopplerParams *restrict doppler,
42  const REAL8 freqShift,
43  const UINT4 indexStartResamp,
44  const UINT4 indexEndResamp,
45  const UINT4 numSamplesIn,
46  const UINT4 insertPoint
47 );
48 
49 static int
51  ResampCrossCorrWorkspace *restrict ws2L,
52  COMPLEX8 *restrict wsFaX_k,
53  COMPLEX8 *restrict wsFbX_k,
54  const MultiResampSFTPairMultiIndexList *restrict resampMultiPairs,
55  const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_a,
56  const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_b,
57  const PulsarDopplerParams *restrict dopplerpos,
58  const PulsarDopplerParams *restrict binaryTemplateSpacings,
59  const REAL8 SRCsampPerTcoh,
60  const UINT4 detX,
61  const UINT4 sftK,
62  const UINT4 detY,
63  const BOOLEAN isL
64 );
65 // ==================== function definitions ====================
66 
67 /// \addtogroup PulsarCrossCorr_v2_h
68 /// @{
69 
70 
71 /** Calculate the Doppler-shifted frequency associated with each SFT in a list */
72 /* This is according to Eqns 2.11 and 2.12 of Dhurandhar et al 2008 */
73 /* Also returns the signal phase according to eqn 2.4 */
75 (
76  REAL8Vector *shiftedFreqs, /**< Output list of shifted frequencies */
77  UINT4Vector *lowestBins, /**< Output list of bin indices */
78  COMPLEX8Vector *expSignalPhases, /**< Output list of signal phases */
79  REAL8VectorSequence *sincList, /**< Output list of sinc factors */
80  UINT4 numBins, /**< Number of frequency bins to use */
81  PulsarDopplerParams *dopp, /**< Doppler parameters for signal */
82  SFTIndexList *sftIndices, /**< List of indices for SFTs */
83  MultiSFTVector *inputSFTs, /**< SFT data (needed for f0) */
84  MultiSSBtimes *multiTimes, /**< SSB or Binary times */
85  MultiUINT4Vector *badBins, /**< List of bin indices contaminated by known lines */
86  REAL8 Tsft /**< SFT duration */
87 )
88 {
89  UINT4 numSFTs = sftIndices->length;
90  if ( expSignalPhases->length != numSFTs
91  || shiftedFreqs->length != numSFTs
92  || lowestBins->length != numSFTs
93  || sincList->length != numSFTs ) {
94  XLALPrintError( "Lengths of SFT-indexed lists don't match!" );
96  }
97 
98  UINT4 numDets = inputSFTs->length;
99  if ( multiTimes->length != numDets
100  || ( badBins && badBins->length != numDets )
101  ) {
102  XLALPrintError( "Lengths of detector-indexed lists don't match!" );
104  }
105 
106  if ( numBins < 1 ) {
107  XLALPrintError( "Must specify a positive number of bins to use!" );
109  }
110 
111  /* now calculate the intrinsic signal frequency in the SFT */
112  /* fhat = f_0 + f_1(t-t0) + f_2(t-t0)^2/2 + ... */
113 
114  /* this is the sft reference time - the pulsar reference time */
115  for ( UINT4 sftNum = 0; sftNum < numSFTs; sftNum++ ) {
116  UINT4 detInd = sftIndices->data[sftNum].detInd;
117  XLAL_CHECK( ( detInd < inputSFTs->length ),
118  XLAL_EINVAL,
119  "SFT asked for detector index off end of list:\n sftNum=%"LAL_UINT4_FORMAT", detInd=%"LAL_UINT4_FORMAT", inputSFTs->length=%d\n",
120  sftNum, detInd, inputSFTs->length );
121 
122  UINT4 numSFTsDet = inputSFTs->data[detInd]->length;
123  SSBtimes *times;
124  times = multiTimes->data[detInd];
125  XLAL_CHECK( ( times->DeltaT->length == numSFTsDet )
126  && ( times->Tdot->length == numSFTsDet ),
127  XLAL_EBADLEN,
128  "Lengths of multilists don't match!" );
129 
130  UINT4 sftInd = sftIndices->data[sftNum].sftInd;
131  XLAL_CHECK( ( sftInd < numSFTsDet ),
132  XLAL_EINVAL,
133  "SFT asked for SFT index off end of list:\n sftNum=%"LAL_UINT4_FORMAT", detInd=%"LAL_UINT4_FORMAT", sftInd=%"LAL_UINT4_FORMAT", numSFTsDet=%"LAL_UINT4_FORMAT"\n",
134  sftNum, detInd, sftInd, numSFTsDet );
135  REAL8 timeDiff = times->DeltaT->data[sftInd]
136  + XLALGPSDiff( &( times->refTime ), &( dopp->refTime ) );
137  REAL8 fhat = dopp->fkdot[0]; /* initialization */
138  REAL8 phiByTwoPi = fmod( fhat * timeDiff, 1.0 );
139  REAL8 factor = timeDiff;
140 
141  for ( UINT4 k = 1; k < PULSAR_MAX_SPINS; k++ ) {
142  fhat += dopp->fkdot[k] * factor;
143  factor *= timeDiff / ( k + 1 );
144  phiByTwoPi += dopp->fkdot[k] * factor;
145  }
146  REAL4 sinPhi, cosPhi; /*Phi -> Phase of each SFT*/
147  if ( XLALSinCos2PiLUT( &sinPhi, &cosPhi, phiByTwoPi ) != XLAL_SUCCESS ) {
148  LogPrintf( LOG_CRITICAL, "%s: XLALSinCos2PiLUT() failed with errno=%d in XLALGetDopplerShiftedFrequencyInfo\n", __func__, xlalErrno );
150  }
151  expSignalPhases->data[sftNum] = cosPhi + I * sinPhi;
152  shiftedFreqs->data[sftNum] = fhat * times->Tdot->data[sftInd];
153  REAL8 fminusf0 = shiftedFreqs->data[sftNum] - inputSFTs->data[detInd]->data[sftInd].f0;
154  lowestBins->data[sftNum] = ceil( fminusf0 * Tsft - 0.5 * numBins );
155 #define SINC_SAFETY 1e-5
156  for ( UINT4 l = 0; l < numBins; l++ ) {
157  sincList->data[sftNum * numBins + l] = 1.0;
158  if ( badBins && badBins->data[detInd] ) {
159  for ( UINT4 j = 0;
160  sincList->data[sftNum * numBins + l] != 0.0
161  && j < badBins->data[detInd]->length;
162  j++ ) {
163  if ( lowestBins->data[sftNum] + l
164  == badBins->data[detInd]->data[j] ) {
165  sincList->data[sftNum * numBins + l] = 0.0;
166  }
167  }
168  }
169 
170  if ( !badBins || !( badBins->data[detInd] )
171  || sincList->data[sftNum * numBins + l] != 0.0 ) {
172  /* Calculate normalized sinc, i.e., sin(pi*x)/(pi*x) */
173  REAL4 sinPiX, cosPiX;
174  REAL8 X = lowestBins->data[sftNum] - fminusf0 * Tsft + l;
175  if ( X > SINC_SAFETY || ( X < - SINC_SAFETY ) ) {
176  XLAL_CHECK( XLALSinCos2PiLUT( &sinPiX, &cosPiX, 0.5 * X ) == XLAL_SUCCESS, XLAL_EFUNC ); /*sin(2*pi*0.5*x)=sin(pi*x)*/
177  sincList->data[sftNum * numBins + l] = LAL_1_PI * sinPiX / X; /*1/(pi*x) =1/pi*1/x*/
178  }
179  }
180  }
181 
182  /* printf("f=%.7f, f0=%.7f, Tsft=%g, numbins=%d, lowestbin=%d, kappa=%g\n",
183  shiftedFreqs->data[sftNum],
184  inputSFTs->data[detInd]->data[sftInd].f0,
185  Tsft, numBins, lowestBins->data[sftNum],
186  kappaValues->data[sftNum]); */
187 
188  }
189 
190  return XLAL_SUCCESS;
191 
192 }
193 
194 /** Construct flat SFTIndexList out of a MultiSFTVector */
195 /* Allocates memory as well */
197 (
198  SFTIndexList **indexList, /* Output: flat list of indices to locate SFTs */
199  MultiSFTVector *sfts /* Input: set of per-detector SFT vectors */
200 )
201 {
202  SFTIndexList *ret = NULL;
203 
204  UINT4 numDets = numDets = sfts->length;
205  UINT4 numSFTs = 0;
206  UINT4 j = 0;
207 
208  for ( UINT4 k = 0; k < numDets; k++ ) {
209  numSFTs += sfts->data[k]->length;
210  }
211 
212  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
214  }
215  ret->length = numSFTs;
216  if ( ( ret->data = XLALCalloc( numSFTs, sizeof( *ret->data ) ) ) == NULL ) {
217  XLALFree( ret );
219  }
220 
221  for ( UINT4 k = 0; k < numDets; k++ ) {
222  UINT4 numForDet = sfts->data[k]->length;
223  for ( UINT4 l = 0; l < numForDet; l++ ) {
224  ret->data[j].detInd = k;
225  ret->data[j].sftInd = l;
226  ++j;
227  }
228  }
229  /* should sort list by GPS time if possible */
230  /* qsort(ret->data, ret->length, sizeof(ret->data[0]), CompareGPSTime ) */
231 
232  ( *indexList ) = ret;
233 
234  return XLAL_SUCCESS;
235 }
236 
237 /** Construct list of SFT pairs for inclusion in statistic */
238 /* Allocates memory as well */
240 (
241  SFTPairIndexList **pairIndexList, /* Output: list of SFT pairs */
242  SFTIndexList *indexList, /* Input: list of indices to locate SFTs */
243  MultiSFTVector *sfts, /* Input: set of per-detector SFT vectors */
244  REAL8 maxLag, /* Maximum allowed lag time */
245  BOOLEAN inclAutoCorr /* Flag indicating whether a "pair" of an SFT with itself is allowed */
246 )
247 {
248  SFTPairIndexList *ret = NULL;
249 
250  UINT4 numSFTs = indexList->length;
251  UINT4 j = 0;
252 
253  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
255  }
256 
257  /* do two passes, one to count the number of pairs so the list can be allocated, and one to actually populate the list. */
258 
259  /* maximum possible number of pairs */
260 
261  for ( UINT4 k = 0; k < numSFTs; k++ ) {
262  UINT4 lMin;
263  if ( inclAutoCorr ) {
264  lMin = k;
265  } else {
266  lMin = k + 1;
267  }
268  LIGOTimeGPS gps1 = sfts->data[indexList->data[k].detInd]->data[indexList->data[k].sftInd].epoch;
269  for ( UINT4 l = lMin; l < numSFTs; l++ ) {
270  LIGOTimeGPS gps2 = sfts->data[indexList->data[l].detInd]->data[indexList->data[l].sftInd].epoch;
271  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
272  if ( fabs( timeDiff ) <= maxLag ) {
273  ++j;
274  }
275  }
276  }
277  ret->length = j;
278  if ( ( ret->data = XLALCalloc( ret->length, sizeof( *ret->data ) ) ) == NULL ) {
279  XLALFree( ret );
281  }
282  j = 0;
283  for ( UINT4 k = 0; k < numSFTs; k++ ) {
284  UINT4 lMin;
285  if ( inclAutoCorr ) {
286  lMin = k;
287  } else {
288  lMin = k + 1;
289  }
290  LIGOTimeGPS gps1 = sfts->data[indexList->data[k].detInd]->data[indexList->data[k].sftInd].epoch;
291  for ( UINT4 l = lMin; l < numSFTs; l++ ) {
292  LIGOTimeGPS gps2 = sfts->data[indexList->data[l].detInd]->data[indexList->data[l].sftInd].epoch;
293  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
294  if ( fabs( timeDiff ) <= maxLag ) {
295  ret->data[j].sftNum[0] = k;
296  ret->data[j].sftNum[1] = l;
297  ++j;
298  }
299  }
300  }
301 
302 
303  ( *pairIndexList ) = ret;
304 
305  return XLAL_SUCCESS;
306 }
307 
308 
309 /** Resampling-modified: construct list of SFT pairs for inclusion in statistic */
310 /* Allocates memory as well */
312 (
313  MultiResampSFTPairMultiIndexList **resampMultiPairIndexList, /**< [out] resamp list of SFT pairs */
314  SFTPairIndexList **pairIndexList, /**< [out] list of SFT pairs */
315  SFTIndexList *indexList, /**< [in] list of indices to locate SFTs */
316  MultiSFTVector *sfts, /**< [in] set of per-detector SFT vectors */
317  REAL8 maxLag, /**< [in] Maximum allowed lag time */
318  BOOLEAN inclAutoCorr, /**< [in] Flag indicating whether a "pair" of an SFT with itself is allowed */
319  BOOLEAN inclSameDetector, /**< [in] Flag indicating whether a "pair" of a detector with itself is allowed */
320  REAL8 Tsft, /**< [in] duration of a single SFT */
321  REAL8 Tshort /**< [in] resampling Tshort */
322 )
323 {
324  /* Note, inclSameDetect not same as inclAutoCorr; is effectively "Yes" in demod search;
325  * should make user variable*/
326 
327  SFTPairIndexList *ret = NULL;
328  MultiResampSFTPairMultiIndexList *resampMultiRet = NULL;
329 
330  UINT4 numSFTs = indexList->length;
331  UINT4 numDets = sfts->length;
332  UINT4 j = 0;
333 
334  fprintf( stdout, "Number of detectors in SFT list: %u\n", numDets );
335  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
337  }
338  if ( ( resampMultiRet = XLALCalloc( 1, sizeof( *resampMultiRet ) ) ) == NULL ) {
340  }
341 
342  /* Resamp block: */
343  /* first, make an array to store the number of matching L */
344  MultiResampSFTMultiCountList *MultiListOfLmatchingGivenMultiK;
345  if ( ( MultiListOfLmatchingGivenMultiK = XLALCalloc( 1, sizeof( *MultiListOfLmatchingGivenMultiK ) ) ) == NULL ) {
347  }
348  MultiListOfLmatchingGivenMultiK->length = numDets; /* Because it is a multi-multi-list */
349  /* next, Allocate detectors X*/
350  if ( ( MultiListOfLmatchingGivenMultiK->data = XLALCalloc( MultiListOfLmatchingGivenMultiK->length, sizeof( *MultiListOfLmatchingGivenMultiK->data ) ) ) == NULL ) {
351  XLALFree( MultiListOfLmatchingGivenMultiK );
353  }
354  /* furthermore, scroll through each detector X to read how many SFTs K_X it has */
355  for ( UINT4 detX = 0; detX < numDets; detX++ ) {
356  MultiListOfLmatchingGivenMultiK->data[detX].length = sfts->data[detX]->length;
357  if ( ( MultiListOfLmatchingGivenMultiK->data[detX].data = XLALCalloc( MultiListOfLmatchingGivenMultiK->data[detX].length, sizeof( *MultiListOfLmatchingGivenMultiK->data[detX].data ) ) ) == NULL ) {
358  XLALFree( MultiListOfLmatchingGivenMultiK->data[detX].data );
360  }
361  /* Now we can count how many matching detectors Y are available to K_X*/
362  /* Go through all possible Y given K_X */
363  for ( UINT4 k = 0; k < MultiListOfLmatchingGivenMultiK->data[detX].length; k++ ) {
364  /* Note that we may have to adjust this to handle gaps in the data */
365  MultiListOfLmatchingGivenMultiK->data[detX].data[k].length = numDets;
366  if ( ( MultiListOfLmatchingGivenMultiK->data[detX].data[k].data = XLALCalloc( MultiListOfLmatchingGivenMultiK->data[detX].data[k].length, sizeof( *MultiListOfLmatchingGivenMultiK->data[detX].data[k].data ) ) ) == NULL ) {
367  XLALFree( MultiListOfLmatchingGivenMultiK->data[detX].data[k].data );
369  }
370  }
371  }
372  /* end resamp block */
373 
374  /* do two passes, one to count the number of pairs so the list can be allocated, and one to actually populate the list. */
375  /* maximum possible number of pairs */
376  for ( UINT4 k = 0; k < numSFTs; k++ ) {
377  UINT4 lMin;
378  if ( inclAutoCorr ) {
379  lMin = k;
380  } else {
381  lMin = k + 1;
382  }
383  LIGOTimeGPS gps1 = sfts->data[indexList->data[k].detInd]->data[indexList->data[k].sftInd].epoch;
384  for ( UINT4 l = lMin; l < numSFTs; l++ ) {
385  LIGOTimeGPS gps2 = sfts->data[indexList->data[l].detInd]->data[indexList->data[l].sftInd].epoch;
386  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
387  if ( fabs( timeDiff ) <= maxLag ) {
388  ++j;
389  }
390  }
391  /* Assign the number of matching L to the list */
392  }
393  /* MULTI-RESAMPLING maximum possible number of pairs */
394  UINT4 lMinMulti;
395  for ( UINT4 detX = 0; detX < numDets; detX++ ) {
396  MultiListOfLmatchingGivenMultiK->data[detX].detInd = detX;
397  for ( UINT4 k = 0; k < MultiListOfLmatchingGivenMultiK->data[detX].length; k++ ) {
398  MultiListOfLmatchingGivenMultiK->data[detX].data[k].sftInd = k;
399  for ( UINT4 detY = 0; detY < numDets; detY++ ) {
400  UINT4 LmatchingGivenKMulti = 0;
401  if ( ( ( detY == detX ) && inclSameDetector ) || ( detY > detX ) ) {
402  if ( detY == detX ) {
403  if ( inclAutoCorr ) {
404  lMinMulti = k;
405  } else {
406  lMinMulti = k + 1;
407  }
408  } else {
409  lMinMulti = 0;
410  }
411  LIGOTimeGPS gps1 = sfts->data[detX]->data[k].epoch;
412  for ( UINT4 l = lMinMulti; l < sfts->data[detY]->length; l++ ) {
413  LIGOTimeGPS gps2 = sfts->data[detY]->data[l].epoch;
414  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
415  if ( fabs( timeDiff ) <= maxLag ) {
416  ++LmatchingGivenKMulti;
417  }
418  }
419  MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].detInd = detY;
420  MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].sftCount = LmatchingGivenKMulti;
421  }
422  }
423  }
424  }
425 
426  ret->length = j;
427  if ( ( ret->data = XLALCalloc( ret->length, sizeof( *ret->data ) ) ) == NULL ) {
428  XLALFree( ret );
430  }
431  j = 0;
432  /* Now assign the lists of lists */
433 
434  /* Assign memory to the return structure based on what we found about how
435  * many matching indices exist for the multi-multi struct */
436  /* first, tell the resampling-return how many detectors there are */
437  resampMultiRet->length = numDets;
438  resampMultiRet->maxLag = maxLag;
439  resampMultiRet->Tsft = Tsft;
440  resampMultiRet->Tshort = Tshort;
441  resampMultiRet->inclAutoCorr = inclAutoCorr;
442  resampMultiRet->inclSameDetector = inclSameDetector;
443  if ( ( resampMultiRet->data = XLALCalloc( resampMultiRet->length, sizeof( *resampMultiRet->data ) ) ) == NULL ) {
444  XLALFree( resampMultiRet );
446  }
447  /* Now assign the multi-list of multi-lists */
448  for ( UINT4 detX = 0; detX < resampMultiRet->length; detX++ ) {
449  resampMultiRet->data[detX].length = MultiListOfLmatchingGivenMultiK->data[detX].length;
450  /* Explicitly save detX index. Likely safe regardless because detX loops over numDets; could use detX */
451  resampMultiRet->data[detX].detInd = MultiListOfLmatchingGivenMultiK->data[detX].detInd;
452  if ( ( resampMultiRet->data[detX].data = XLALCalloc( resampMultiRet->data[detX].length, sizeof( *resampMultiRet->data[detX].data ) ) ) == NULL ) {
453  XLALFree( resampMultiRet->data[detX].data );
455  }
456  for ( UINT4 k = 0; k < resampMultiRet->data[detX].length; k++ ) {
457  resampMultiRet->data[detX].data[k].length = MultiListOfLmatchingGivenMultiK->data[detX].data[k].length;
458  /* Explicitly save K_X index. Likely safe regardless because K_X loops over all SFTs in X; could use k */
459  resampMultiRet->data[detX].data[k].sftInd = MultiListOfLmatchingGivenMultiK->data[detX].data[k].sftInd;
460  if ( ( resampMultiRet->data[detX].data[k].data = XLALCalloc( resampMultiRet->data[detX].data[k].length, sizeof( *resampMultiRet->data[detX].data[k].data ) ) ) == NULL ) {
461  XLALFree( resampMultiRet->data[detX].data[k].data );
463  }
464  for ( UINT4 detY = 0; detY < resampMultiRet->data[detX].data[k].length; detY++ ) {
465  resampMultiRet->data[detX].data[k].data[detY].length = MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].sftCount;
466  /* Explicitly save L_K_X index. Needs explicit safety because not all detectors may be online */
467  resampMultiRet->data[detX].data[k].data[detY].detInd = MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].detInd;
468  if ( ( resampMultiRet->data[detX].data[k].data[detY].data = XLALCalloc( resampMultiRet->data[detX].data[k].data[detY].length, sizeof( *resampMultiRet->data[detX].data[k].data[detY].data ) ) ) == NULL ) {
469  XLALFree( resampMultiRet->data[detX].data[k].data[detY].data );
471  }
472  }
473  }
474  }
475 
476  XLALDestroyMultiMatchList( MultiListOfLmatchingGivenMultiK );
477 
478  /* Ascertain and transcribe the matches into the return structure*/
479  for ( UINT4 k = 0; k < numSFTs; k++ ) {
480  UINT4 lMin;
481  if ( inclAutoCorr ) {
482  lMin = k;
483  } else {
484  lMin = k + 1;
485  }
486  LIGOTimeGPS gps1 = sfts->data[indexList->data[k].detInd]->data[indexList->data[k].sftInd].epoch;
487  for ( UINT4 l = lMin; l < numSFTs; l++ ) {
488  LIGOTimeGPS gps2 = sfts->data[indexList->data[l].detInd]->data[indexList->data[l].sftInd].epoch;
489  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
490  if ( fabs( timeDiff ) <= maxLag ) {
491  ret->data[j].sftNum[0] = k;
492  ret->data[j].sftNum[1] = l;
493  ++j;
494  }
495  }
496  }
497 
498  /* Multi-Ascertain and transcribe the matches into the return structure for resampling*/
499  UINT4 allPairCounter = 0;
500  UINT4 kFlatCounter = 0;
501  UINT4 lFlatCounter = 0;
502  for ( UINT4 detX = 0; detX < resampMultiRet->length; detX++ ) {
503  for ( UINT4 k = 0; k < resampMultiRet->data[detX].length; k++ ) {
504  /* Reinitialize the l-flat counter because now we are
505  * searching against the OTHER SFTs, with their own count */
506  if ( inclAutoCorr ) {
507  lFlatCounter = kFlatCounter;
508  } else {
509  lFlatCounter = kFlatCounter + 1;
510  }
511  for ( UINT4 detY = 0; detY < resampMultiRet->data[detX].data[k].length; detY++ ) {
512  /* note that naively, resampMultiRet->data[detX].data[k].length = numDets,
513  * so we search all detectors. This choice may need to be revisited when
514  * we have gaps in the data */
515  UINT4 outLmatchingGivenKMulti = 0;
516  /* Repeating the following check is necessary, because in general
517  * our index "l" is not the internal SFT vector index for detector Y.
518  * This is in constrast to k, which is (because it is the first index).
519  */
520  if ( ( ( detY == detX ) && inclSameDetector ) || ( detY > detX ) ) {
521  if ( detY == detX ) {
522  if ( inclAutoCorr ) {
523  lMinMulti = k;
524  } else {
525  lMinMulti = k + 1;
526  }
527  } else {
528  lMinMulti = 0;
529  }
530  LIGOTimeGPS gps1 = sfts->data[detX]->data[k].epoch;
531  for ( UINT4 l = lMinMulti; l < sfts->data[detY]->length; l++ ) {
532  LIGOTimeGPS gps2 = sfts->data[detY]->data[l].epoch;
533  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
534  if ( fabs( timeDiff ) <= maxLag ) {
535  /* Must refer to sft vectors, not the flat index*/
536  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].sftInd = l;
537  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].detInd = detY;
538  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].flatInd = lFlatCounter;
539  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].pairInd = allPairCounter;
540  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].sciFlag = 1.0;
541  ++outLmatchingGivenKMulti;
542  ++allPairCounter;
543  }
544  ++lFlatCounter;
545  } // end l
546  } // similarity check: end
547  } // end detY
548  resampMultiRet->data[detX].data[k].flatInd = kFlatCounter;
549  resampMultiRet->data[detX].data[k].sciFlag = 1.0;
550  ++kFlatCounter;
551  } // end k
552  } // end detX
553  resampMultiRet->oldPairCount = ret->length;
554  resampMultiRet->allPairCount = allPairCounter;
555 
556  ( *pairIndexList ) = ret;
557  ( *resampMultiPairIndexList ) = resampMultiRet;
558 
559  return XLAL_SUCCESS;
560 } // end XLALCreateSFTPairIndexListResamp
561 
562 
563 /** With Tshort, and Resampling-modified: construct list of SFT pairs for inclusion in statistic */
564 /* Allocates memory as well, with Tshort */
566 (
567  MultiResampSFTPairMultiIndexList **resampMultiPairIndexList, /**< [out] resamp list of SFT pairs */
568  const REAL8 maxLag, /**< [in] Maximum allowed lag time */
569  const BOOLEAN inclAutoCorr, /**< [in] Flag indicating whether a "pair" of an SFT with itself is allowed */
570  const BOOLEAN inclSameDetector, /**< [in] Flag indicating whether a "pair" of a detector with itself is allowed */
571  const REAL8 Tsft, /**< [in] duration of a single SFT */
572  const MultiLIGOTimeGPSVector *restrict multiTimes /**< [in] timestamps containing Tshort times for each detector */
573 )
574 {
575  /* Note, inclSameDetector not same as inclAutoCorr; is effectively "Yes" in demod search;
576  * have made user variable*/
577 
578  XLAL_CHECK( multiTimes != NULL, XLAL_EINVAL );
579  MultiResampSFTPairMultiIndexList *restrict resampMultiRet = NULL;
580 
581  const UINT4 numDets = multiTimes->length;
582  const UINT4 numShortPerDet = multiTimes->data[0]->length;
583  const UINT4 numSFTs = numShortPerDet * numDets;
584  const REAL8 Tshort = multiTimes->data[0]->deltaT;
585 
586  if ( ( resampMultiRet = XLALCalloc( 1, sizeof( *resampMultiRet ) ) ) == NULL ) {
588  }
589 
590  /* First, let us provide a consistent zero-padded length to all
591  * detectors for their time series of Tshorts. We will then add
592  * supplementary information to indicate was is and is not in science */
593 
594  /* Resamp block: */
595  /* first, make an array to store the number of matching L */
596  MultiResampSFTMultiCountList *restrict MultiListOfLmatchingGivenMultiK;
597  if ( ( MultiListOfLmatchingGivenMultiK = XLALCalloc( 1, sizeof( *MultiListOfLmatchingGivenMultiK ) ) ) == NULL ) {
599  }
600  MultiListOfLmatchingGivenMultiK->length = numDets; /* Because it is a multi-multi-list */
601  /* next, Allocate detectors X*/
602  if ( ( MultiListOfLmatchingGivenMultiK->data = XLALCalloc( MultiListOfLmatchingGivenMultiK->length, sizeof( *MultiListOfLmatchingGivenMultiK->data ) ) ) == NULL ) {
603  XLALFree( MultiListOfLmatchingGivenMultiK );
605  }
606  /* furthermore, scroll through each detector X to read how many SFTs K_X it has */
607  for ( UINT4 detX = 0; detX < numDets; detX++ ) {
608  MultiListOfLmatchingGivenMultiK->data[detX].length = numShortPerDet;
609  if ( ( MultiListOfLmatchingGivenMultiK->data[detX].data = XLALCalloc( MultiListOfLmatchingGivenMultiK->data[detX].length, sizeof( *MultiListOfLmatchingGivenMultiK->data[detX].data ) ) ) == NULL ) {
610  XLALFree( MultiListOfLmatchingGivenMultiK->data[detX].data );
612  }
613  /* Now we can count how many matching detectors Y are available to K_X*/
614  /* Go through all possible Y given K_X */
615  for ( UINT4 k = 0; k < MultiListOfLmatchingGivenMultiK->data[detX].length; k++ ) {
616  /* Note that we may have to adjust this to handle gaps in the data */
617  MultiListOfLmatchingGivenMultiK->data[detX].data[k].length = numDets;
618  if ( ( MultiListOfLmatchingGivenMultiK->data[detX].data[k].data = XLALCalloc( MultiListOfLmatchingGivenMultiK->data[detX].data[k].length, sizeof( *MultiListOfLmatchingGivenMultiK->data[detX].data[k].data ) ) ) == NULL ) {
619  XLALFree( MultiListOfLmatchingGivenMultiK->data[detX].data[k].data );
621  }
622  }
623  }
624  /* end resamp block */
625 
626  /* do two passes, one to count the number of pairs so the list can be allocated, and one to actually populate the list. */
627  /* maximum possible number of pairs */
628  /* MULTI-RESAMPLING maximum possible number of pairs */
629  UINT4 lMinMulti;
630  UINT4 lMaxMulti = 0;
631  for ( UINT4 detX = 0; detX < numDets; detX++ ) {
632  MultiListOfLmatchingGivenMultiK->data[detX].detInd = detX;
633  for ( UINT4 k = 0; k < MultiListOfLmatchingGivenMultiK->data[detX].length; k++ ) {
634  MultiListOfLmatchingGivenMultiK->data[detX].data[k].sftInd = k;
635  for ( UINT4 detY = 0; detY < numDets; detY++ ) {
636  UINT4 LmatchingGivenKMulti = 0;
637  if ( ( ( detY == detX ) && inclSameDetector ) || ( detY > detX ) ) {
638  if ( detY == detX ) {
639  if ( inclAutoCorr ) {
640  lMinMulti = k;
641  } else {
642  lMinMulti = k + 1;
643  }
644  } else {
645  lMinMulti = ( UINT4 )MYMAX( 0, k - round( 2 * maxLag / Tshort ) - 2 );
646  }
647  /* new style, for Tshort */
648  LIGOTimeGPS gps1 = multiTimes->data[detX]->data[k];
649  /* For speed */
650  lMaxMulti = ( UINT4 )MYMIN( numShortPerDet, lMinMulti + round( 4 * maxLag / Tshort ) + 4 );
651  for ( UINT4 l = lMinMulti; l < lMaxMulti; l++ ) {
652  LIGOTimeGPS gps2 = multiTimes->data[detY]->data[l];
653  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
654  if ( fabs( timeDiff ) <= maxLag ) {
655  ++LmatchingGivenKMulti;
656  }
657  }
658  MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].detInd = detY;
659  MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].sftCount = LmatchingGivenKMulti;
660  }
661  }
662  }
663  }
664 
665  /* Now assign the lists of lists */
666 
667  /* Assign memory to the return structure based on what we found about how
668  * many matching indices exist for the multi-multi struct */
669  /* first, tell the resampling-return how many detectors there are */
670  resampMultiRet->length = numDets;
671  resampMultiRet->maxLag = maxLag;
672  resampMultiRet->Tsft = Tsft;
673  resampMultiRet->Tshort = Tshort;
674  resampMultiRet->inclAutoCorr = inclAutoCorr;
675  resampMultiRet->inclSameDetector = inclSameDetector;
676  if ( ( resampMultiRet->data = XLALCalloc( resampMultiRet->length, sizeof( *resampMultiRet->data ) ) ) == NULL ) {
677  XLALFree( resampMultiRet );
679  }
680  /* Now assign the multi-list of multi-lists */
681  for ( UINT4 detX = 0; detX < resampMultiRet->length; detX++ ) {
682  resampMultiRet->data[detX].length = MultiListOfLmatchingGivenMultiK->data[detX].length;
683  /* Explicitly save detX index. Likely safe regardless because detX loops over numDets; could use detX */
684  resampMultiRet->data[detX].detInd = MultiListOfLmatchingGivenMultiK->data[detX].detInd;
685  if ( ( resampMultiRet->data[detX].data = XLALCalloc( resampMultiRet->data[detX].length, sizeof( *resampMultiRet->data[detX].data ) ) ) == NULL ) {
686  XLALFree( resampMultiRet->data[detX].data );
688  }
689  for ( UINT4 k = 0; k < resampMultiRet->data[detX].length; k++ ) {
690  resampMultiRet->data[detX].data[k].length = MultiListOfLmatchingGivenMultiK->data[detX].data[k].length;
691  /* Explicitly save K_X index. Likely safe regardless because K_X loops over all SFTs in X; could use k */
692  resampMultiRet->data[detX].data[k].sftInd = MultiListOfLmatchingGivenMultiK->data[detX].data[k].sftInd;
693  if ( ( resampMultiRet->data[detX].data[k].data = XLALCalloc( resampMultiRet->data[detX].data[k].length, sizeof( *resampMultiRet->data[detX].data[k].data ) ) ) == NULL ) {
694  XLALFree( resampMultiRet->data[detX].data[k].data );
696  }
697  for ( UINT4 detY = 0; detY < resampMultiRet->data[detX].data[k].length; detY++ ) {
698  resampMultiRet->data[detX].data[k].data[detY].length = MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].sftCount;
699  /* Explicitly save L_K_X index. Needs explicit safety because not all detectors may be online */
700  resampMultiRet->data[detX].data[k].data[detY].detInd = MultiListOfLmatchingGivenMultiK->data[detX].data[k].data[detY].detInd;
701  if ( ( resampMultiRet->data[detX].data[k].data[detY].data = XLALCalloc( resampMultiRet->data[detX].data[k].data[detY].length, sizeof( *resampMultiRet->data[detX].data[k].data[detY].data ) ) ) == NULL ) {
702  XLALFree( resampMultiRet->data[detX].data[k].data[detY].data );
704  }
705  }
706  }
707  }
708 
709  XLALDestroyMultiMatchList( MultiListOfLmatchingGivenMultiK );
710 
711  /* Prepare the outer, flat list as well */
712  SFTIndexList *restrict flatIndexList = NULL;
713  if ( ( flatIndexList = XLALCalloc( 1, sizeof( *flatIndexList ) ) ) == NULL ) {
715  }
716  flatIndexList->length = numSFTs;
717  if ( ( flatIndexList->data = XLALCalloc( numSFTs, sizeof( *flatIndexList->data ) ) ) == NULL ) {
718  XLALFree( flatIndexList );
720  }
721 
722  /* Multi-Ascertain and transcribe the matches into the return structure for resampling*/
723  UINT4 allPairCounter = 0;
724  UINT4 kFlatCounter = 0;
725  UINT4 lFlatCounter = 0;
726  for ( UINT4 detX = 0; detX < resampMultiRet->length; detX++ ) {
727  for ( UINT4 k = 0; k < resampMultiRet->data[detX].length; k++ ) {
728  kFlatCounter = numShortPerDet * detX + k;
729  /* Reinitialize the l-flat counter because now we are
730  searching against the OTHER SFTs, with their own count */
731  for ( UINT4 detY = 0; detY < resampMultiRet->data[detX].data[k].length; detY++ ) {
732  /* note that naively, resampMultiRet->data[detX].data[k].length = numDets,
733  * so we search all detectors. This choice may need to be revisited when
734  * we have gaps in the data */
735  UINT4 outLmatchingGivenKMulti = 0;
736  /* Repeating the following check is necessary, because in general
737  * our index "l" is not the internal SFT vector index for detector Y.
738  * This is in contrast to k, which is (because it is the first index).
739  */
740  if ( ( ( detY == detX ) && inclSameDetector ) || ( detY > detX ) ) {
741  if ( detY == detX ) {
742  if ( inclAutoCorr ) {
743  lMinMulti = k;
744  } else {
745  lMinMulti = k + 1;
746  }
747  } else {
748  lMinMulti = ( UINT4 )MYMAX( 0, k - round( 2 * maxLag / Tshort ) - 2 );
749  }
750  /* new style, for Tshort */
751  LIGOTimeGPS gps1 = multiTimes->data[detX]->data[k];
752  lMaxMulti = ( UINT4 )MYMIN( numShortPerDet, lMinMulti + round( 4 * maxLag / Tshort ) + 4 );
753  for ( UINT4 l = lMinMulti; l < lMaxMulti; l++ ) {
754  LIGOTimeGPS gps2 = multiTimes->data[detY]->data[l];
755  REAL8 timeDiff = XLALGPSDiff( &gps1, &gps2 );
756  if ( fabs( timeDiff ) <= maxLag ) {
757  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].sftInd = l;
758  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].detInd = detY;
759  lFlatCounter = numShortPerDet * detY + l;
760  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].flatInd = lFlatCounter;
761  /* note that pairInd = alpha in the Whelan et al 2015 paper's notation */
762  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].pairInd = allPairCounter;
763  resampMultiRet->data[detX].data[k].data[detY].data[outLmatchingGivenKMulti].sciFlag = 1.0;
764  ++outLmatchingGivenKMulti;
765  ++allPairCounter;
766  }
767  } // end l
768  } // similarity check: end
769  } // end detY
770  resampMultiRet->data[detX].data[k].flatInd = kFlatCounter;
771  resampMultiRet->data[detX].data[k].sciFlag = 1.0;
772  flatIndexList->data[kFlatCounter].detInd = detX;
773  /* Note, the SFT index is probably just k, but best to be safe */
774  flatIndexList->data[kFlatCounter].sftInd = resampMultiRet->data[detX].data[k].sftInd;
775  /* kFlatCounter should serve as a flat index of all SFTs, or Shorts,
776  * because k passes through all, for all detectors, even if a given
777  * one does not match anything (perhaps b/c it was already assigned
778  * to all appropriate pairs */
779  } // end k
780  } // end detX
781  resampMultiRet->allPairCount = allPairCounter;
782  /* Add one to counts because this is C, with 0-indexing;
783  * remember we assigned kFlatCounter not incrementally but directly */
784  resampMultiRet->sftTotalCount = 1 + kFlatCounter;
785  resampMultiRet->indexList = flatIndexList;
786 
787  /* Prepare the standard, old-school pair list too */
788  SFTPairIndexList *restrict standardPairIndexList = NULL;
789  if ( ( standardPairIndexList = XLALCalloc( 1, sizeof( *standardPairIndexList ) ) ) == NULL ) {
791  }
792  standardPairIndexList->length = resampMultiRet->allPairCount;
793  if ( ( standardPairIndexList->data = XLALCalloc( standardPairIndexList->length, sizeof( *standardPairIndexList->data ) ) ) == NULL ) {
794  XLALFree( standardPairIndexList );
796  }
797 
798  UINT4 sftNum1;
799  UINT4 sftNum2;
800 
801  UINT4 standardPairCount = 0;
802  for ( UINT4 detX = 0; detX < resampMultiRet->length; detX++ ) {
803  for ( UINT4 k = 0; k < resampMultiRet->data[detX].length; k++ ) {
804  for ( UINT4 detY = 0; detY < resampMultiRet->data[detX].data[k].length; detY++ ) {
805  for ( UINT4 l = 0; l < resampMultiRet->data[detX].data[k].data[detY].length; l++ ) {
806  /* Here we must us the flat SFT number */
807  sftNum1 = numShortPerDet * detX + resampMultiRet->data[detX].data[k].sftInd;
808  sftNum2 = numShortPerDet * detY + resampMultiRet->data[detX].data[k].data[detY].data[l].sftInd;
809  standardPairIndexList->data[standardPairCount].sftNum[0] = sftNum1;
810  standardPairIndexList->data[standardPairCount].sftNum[1] = sftNum2;
811  ++standardPairCount;
812  }
813  }
814  }
815  }
816  resampMultiRet->pairIndexList = standardPairIndexList;
817  resampMultiRet->oldPairCount = standardPairCount;
818  ( *resampMultiPairIndexList ) = resampMultiRet;
819 
820  return XLAL_SUCCESS;
821 } // end XLALCreateSFTPairIndexListShortResamp
822 
823 /** Check that the contents of a resampling multi-pair index list are sensible by inspection */
825 (
826  MultiResampSFTPairMultiIndexList *resampMultiPairIndexList /**< [in] resamp list of SFT pairs */
827 )
828 {
829  MultiResampSFTPairMultiIndexList *resampMultiRet = resampMultiPairIndexList;
830  /* SANITY CHECK */
831  UINT4 grandTotalCounter = 0;
832  for ( UINT4 detX = 0; detX < resampMultiRet->length; detX++ ) {
833  for ( UINT4 k = 0; k < resampMultiRet->data[detX].length; k++ ) {
834  for ( UINT4 detY = 0; detY < resampMultiRet->data[detX].data[k].length; detY++ ) {
835  for ( UINT4 l = 0; l < resampMultiRet->data[detX].data[k].data[detY].length; l++ ) {
836  ++grandTotalCounter;
837  fprintf( stdout, "SFT INDEX: %u\n", resampMultiRet->data[detX].data[k].data[detY].data[l].sftInd );
838  fprintf( stdout, "det INDEX: %u\n", resampMultiRet->data[detX].data[k].data[detY].data[l].detInd );
839  fprintf( stdout, "pair INDEX: %u\n", resampMultiRet->data[detX].data[k].data[detY].data[l].pairInd );
840  }
841  }
842  }
843  }
844  fprintf( stdout, "Sanity check: GRAND TOTAL of passes through loop: %u\n", grandTotalCounter );
845  fprintf( stdout, "Pairing completed\n" );
846  /* SANITY CHECK 2 */
847  UINT4 newKFlatCounter = 0;
848  for ( UINT4 detX = 0; detX < resampMultiRet->length; detX++ ) {
849  for ( UINT4 k = 0; k < resampMultiRet->data[detX].length; k++ ) {
850  printf( "detInd: %u\n", resampMultiRet->indexList->data[newKFlatCounter].detInd );
851  printf( "sftInd: %u\n", resampMultiRet->indexList->data[newKFlatCounter].sftInd );
852  newKFlatCounter++;
853  }
854  }
855  printf( "newKFlatCounter: %u\n", newKFlatCounter );
856  return XLAL_SUCCESS;
857 } // end XLALTestResampPairIndexList
858 
859 
860 /** Construct vector of G_alpha amplitudes for each SFT pair */
861 /* This is averaged over unknown cosi and psi */
862 /* Allocates memory as well */
864 (
865  REAL8Vector **Gamma_ave, /* Output: vector of aa+bb values */
866  REAL8Vector **Gamma_circ, /* Output: vector of ab-ba values */
867  SFTPairIndexList *pairIndexList, /* Input: list of SFT pairs */
868  SFTIndexList *indexList, /* Input: list of SFTs */
869  MultiAMCoeffs *multiCoeffs /* Input: AM coefficients */
870 )
871 {
872 
873  UINT4 numPairs = pairIndexList->length;
874 
875  REAL8Vector *ret1 = NULL;
876  XLAL_CHECK( ( ret1 = XLALCreateREAL8Vector( numPairs ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numPairs );
877  REAL8Vector *ret2 = NULL;
878  XLAL_CHECK( ( ret2 = XLALCreateREAL8Vector( numPairs ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numPairs );
879 
880  for ( UINT4 j = 0; j < numPairs; j++ ) {
881  UINT4 sftNum1 = pairIndexList->data[j].sftNum[0];
882  UINT4 sftNum2 = pairIndexList->data[j].sftNum[1];
883  UINT4 detInd1 = indexList->data[sftNum1].detInd;
884  UINT4 detInd2 = indexList->data[sftNum2].detInd;
885  UINT4 sftInd1 = indexList->data[sftNum1].sftInd;
886  UINT4 sftInd2 = indexList->data[sftNum2].sftInd;
887  ret1->data[j] = 0.1 * ( multiCoeffs->data[detInd1]->a->data[sftInd1]
888  * multiCoeffs->data[detInd2]->a->data[sftInd2]
889  + multiCoeffs->data[detInd1]->b->data[sftInd1]
890  * multiCoeffs->data[detInd2]->b->data[sftInd2] );
891  ret2->data[j] = 0.1 * ( multiCoeffs->data[detInd1]->a->data[sftInd1]
892  * multiCoeffs->data[detInd2]->b->data[sftInd2]
893  - multiCoeffs->data[detInd1]->b->data[sftInd1]
894  * multiCoeffs->data[detInd2]->a->data[sftInd2] );
895  }
896 
897  ( *Gamma_ave ) = ret1;
898  ( *Gamma_circ ) = ret2;
899  return XLAL_SUCCESS;
900 }
901 
902 /** test function for RESAMPLING */
903 /** Construct multi-dimensional array of G_L_Y_K_X amplitudes for each SFT pair */
904 /* This is averaged over unknwon cosi and psi */
905 /* Allocates memory as well */
907 (
908  REAL8Vector **Gamma_ave, /**< Output: vector of aa+bb values */
909  REAL8Vector **Gamma_circ, /**< Output: vector of ab-ba values */
910  MultiResampSFTPairMultiIndexList *resampMultiPairIndexList, /**< Input: resamp list of SFT pairs */
911  MultiAMCoeffs *multiCoeffs /**< Input: AM coefficients */
912 )
913 {
914  UINT4 numPairs = resampMultiPairIndexList->allPairCount;
915 
916  REAL8Vector *ret1 = NULL;
917  XLAL_CHECK( ( ret1 = XLALCreateREAL8Vector( numPairs ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numPairs );
918  REAL8Vector *ret2 = NULL;
919  XLAL_CHECK( ( ret2 = XLALCreateREAL8Vector( numPairs ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numPairs );
920 
921 
922  /* beware segfault from stack overflow here for large numPairs */
923  UINT4 detInd1[numPairs];
924  UINT4 detInd2[numPairs];
925  UINT4 sftInd1[numPairs];
926  UINT4 sftInd2[numPairs];
927 
928  UINT4 pairCount = 0;
929  for ( UINT4 detX = 0; detX < resampMultiPairIndexList->length; detX++ ) {
930  for ( UINT4 k = 0; k < resampMultiPairIndexList->data[detX].length; k++ ) {
931  for ( UINT4 detY = 0; detY < resampMultiPairIndexList->data[detX].data[k].length; detY++ ) {
932  for ( UINT4 l = 0; l < resampMultiPairIndexList->data[detX].data[k].data[detY].length; l++ ) {
933  /* This way works if multiCoeffs is allocated for SFTs wrt original
934  * vector (as is the case) */
935  detInd1[pairCount] = resampMultiPairIndexList->data[detX].detInd;
936  detInd2[pairCount] = resampMultiPairIndexList->data[detX].data[k].data[detY].detInd;
937  sftInd1[pairCount] = resampMultiPairIndexList->data[detX].data[k].sftInd;
938  sftInd2[pairCount] = resampMultiPairIndexList->data[detX].data[k].data[detY].data[l].sftInd;
939  ++pairCount;
940  }
941  }
942  }
943  }
944  for ( UINT4 j = 0; j < numPairs; j++ ) {
945  ret1->data[j] = 0.1 * ( multiCoeffs->data[detInd1[j]]->a->data[sftInd1[j]]
946  * multiCoeffs->data[detInd2[j]]->a->data[sftInd2[j]]
947  + multiCoeffs->data[detInd1[j]]->b->data[sftInd1[j]]
948  * multiCoeffs->data[detInd2[j]]->b->data[sftInd2[j]] );
949  ret2->data[j] = 0.1 * ( multiCoeffs->data[detInd1[j]]->a->data[sftInd1[j]]
950  * multiCoeffs->data[detInd2[j]]->b->data[sftInd2[j]]
951  - multiCoeffs->data[detInd1[j]]->b->data[sftInd1[j]]
952  * multiCoeffs->data[detInd2[j]]->a->data[sftInd2[j]] );
953  }
954 
955  ( *Gamma_ave ) = ret1;
956  ( *Gamma_circ ) = ret2;
957  return XLAL_SUCCESS;
958 } // end XLALCalculateCrossCorrGammasResamp
959 
960 /** test function for RESAMPLING with tShort*/
961 /** Construct multi-dimensional array of G_L_Y_K_X amplitudes for each SFT pair */
962 /* This is averaged over unknwon cosi and psi */
963 /* Allocates memory as well */
965 (
966  REAL8Vector **Gamma_ave, /**< Output: vector of aa+bb values */
967  REAL8Vector **Gamma_circ, /**< Output: vector of ab-ba values */
968  MultiResampSFTPairMultiIndexList *resampMultiPairIndexList, /**< Input: resamp list of SFT pairs */
969  MultiAMCoeffs *multiCoeffs /**< Input: AM coefficients */
970 )
971 {
972  UINT4 numPairs = resampMultiPairIndexList->allPairCount;
973 
974  REAL8Vector *ret1 = NULL;
975  XLAL_CHECK( ( ret1 = XLALCreateREAL8Vector( numPairs ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numPairs );
976  REAL8Vector *ret2 = NULL;
977  XLAL_CHECK( ( ret2 = XLALCreateREAL8Vector( numPairs ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numPairs );
978 
979  REAL4 eleMultiCoeffs1a = 0;
980  REAL4 eleMultiCoeffs2a = 0;
981  REAL4 eleMultiCoeffs1b = 0;
982  REAL4 eleMultiCoeffs2b = 0;
983 
984  REAL4 sciMultiCoeffs1a = 0;
985  REAL4 sciMultiCoeffs2a = 0;
986  REAL4 sciMultiCoeffs1b = 0;
987  REAL4 sciMultiCoeffs2b = 0;
988 
989  /* beware segfault from stack overflow here for large numPairs */
990  REAL4 castSciFlag1[numPairs];
991  REAL4 castSciFlag2[numPairs];
992 
993  UINT4 detInd1[numPairs];
994  UINT4 detInd2[numPairs];
995  UINT4 sftInd1[numPairs];
996  UINT4 sftInd2[numPairs];
997 
998  UINT4 pairCount = 0;
999  for ( UINT4 detX = 0; detX < resampMultiPairIndexList->length; detX++ ) {
1000  for ( UINT4 k = 0; k < resampMultiPairIndexList->data[detX].length; k++ ) {
1001  for ( UINT4 detY = 0; detY < resampMultiPairIndexList->data[detX].data[k].length; detY++ ) {
1002  for ( UINT4 l = 0; l < resampMultiPairIndexList->data[detX].data[k].data[detY].length; l++ ) {
1003  /* This way works if multiCoeffs is allocated for SFTs wrt original
1004  * vector (as is the case) */
1005  detInd1[pairCount] = resampMultiPairIndexList->data[detX].detInd;
1006  detInd2[pairCount] = resampMultiPairIndexList->data[detX].data[k].data[detY].detInd;
1007  sftInd1[pairCount] = resampMultiPairIndexList->data[detX].data[k].sftInd;
1008  sftInd2[pairCount] = resampMultiPairIndexList->data[detX].data[k].data[detY].data[l].sftInd;
1009  /* Can use the science flags; will produce slightly different
1010  * results due to sharper edges than A and B time series;
1011  * however, by themselves, A and B are zero-padded and so
1012  * can handle gaps. */
1013  //castSciFlag1[pairCount] = resampMultiPairIndexList->data[detX].data[k].sciFlag;
1014  //castSciFlag2[pairCount] = resampMultiPairIndexList->data[detX].data[k].data[detY].data[l].sciFlag;
1015  castSciFlag1[pairCount] = 1.0;
1016  castSciFlag2[pairCount] = 1.0;
1017  ++pairCount;
1018  }
1019  }
1020  }
1021  }
1022  for ( UINT4 j = 0; j < numPairs; j++ ) {
1023  eleMultiCoeffs1a = multiCoeffs->data[detInd1[j]]->a->data[sftInd1[j]];
1024  eleMultiCoeffs2a = multiCoeffs->data[detInd2[j]]->a->data[sftInd2[j]];
1025  eleMultiCoeffs1b = multiCoeffs->data[detInd1[j]]->b->data[sftInd1[j]];
1026  eleMultiCoeffs2b = multiCoeffs->data[detInd2[j]]->b->data[sftInd2[j]];
1027 
1028  sciMultiCoeffs1a = eleMultiCoeffs1a * castSciFlag1[j];
1029  sciMultiCoeffs2a = eleMultiCoeffs2a * castSciFlag2[j];
1030  sciMultiCoeffs1b = eleMultiCoeffs1b * castSciFlag1[j];
1031  sciMultiCoeffs2b = eleMultiCoeffs2b * castSciFlag2[j];
1032  ret1->data[j] = 0.1 * ( sciMultiCoeffs1a
1033  * sciMultiCoeffs2a
1034  + sciMultiCoeffs1b
1035  * sciMultiCoeffs2b );
1036  ret2->data[j] = 0.1 * ( sciMultiCoeffs1a
1037  * sciMultiCoeffs2b
1038  - sciMultiCoeffs1b
1039  * sciMultiCoeffs2a );
1040  }
1041 
1042  ( *Gamma_ave ) = ret1;
1043  ( *Gamma_circ ) = ret2;
1044  return XLAL_SUCCESS;
1045 } // end XLALCalculateCrossCorrGammasResampShort
1046 
1047 
1048 /** Calculate multi-bin cross-correlation statistic */
1049 /* This assumes rectangular or nearly-rectangular windowing */
1051 (
1052  REAL8 *ccStat, /* Output: cross-correlation statistic rho */
1053  REAL8 *evSquared, /* Output: (E[rho]/h0^2)^2 */
1054  REAL8Vector *curlyGAmp, /* Input: Amplitude of curly G for each pair */
1055  COMPLEX8Vector *expSignalPhases, /* Input: Phase of signal for each SFT */
1056  UINT4Vector *lowestBins, /* Input: Bin index to start with for each SFT */
1057  REAL8VectorSequence *sincList, /* Input: input the sinc factors*/
1058  SFTPairIndexList *sftPairs, /* Input: flat list of SFT pairs */
1059  SFTIndexList *sftIndices, /* Input: flat list of SFTs */
1060  MultiSFTVector *inputSFTs, /* Input: SFT data */
1061  MultiNoiseWeights *multiWeights, /* Input: nomalizeation factor S^-1 & weights for each SFT */
1062  UINT4 numBins /* Input Number of frequency bins to be taken into calc */
1063 )
1064 {
1065 
1066  UINT4 numSFTs = sftIndices->length;
1067  if ( expSignalPhases->length != numSFTs
1068  || lowestBins->length != numSFTs
1069  || sincList->length != numSFTs ) {
1070  XLALPrintError( "Lengths of SFT-indexed lists don't match!" );
1072  }
1073 
1074  UINT4 numPairs = sftPairs->length;
1075  if ( curlyGAmp->length != numPairs ) {
1076  XLALPrintError( "Lengths of pair-indexed lists don't match!" );
1078  }
1079  REAL8 nume = 0;
1080  REAL8 curlyGSqr = 0;
1081  *ccStat = 0.0;
1082  *evSquared = 0.0;
1083  for ( UINT4 alpha = 0; alpha < numPairs; alpha++ ) {
1084  UINT4 sftNum1 = sftPairs->data[alpha].sftNum[0];
1085  UINT4 sftNum2 = sftPairs->data[alpha].sftNum[1];
1086 
1087  XLAL_CHECK( ( sftNum1 < numSFTs ) && ( sftNum2 < numSFTs ),
1088  XLAL_EINVAL,
1089  "SFT pair asked for SFT index off end of list:\n alpha=%"LAL_UINT4_FORMAT", sftNum1=%"LAL_UINT4_FORMAT", sftNum2=%"LAL_UINT4_FORMAT", numSFTs=%"LAL_UINT4_FORMAT"\n",
1090  alpha, sftNum1, sftNum2, numSFTs );
1091 
1092  UINT4 detInd1 = sftIndices->data[sftNum1].detInd;
1093  UINT4 detInd2 = sftIndices->data[sftNum2].detInd;
1094 
1095  XLAL_CHECK( ( detInd1 < inputSFTs->length )
1096  && ( detInd2 < inputSFTs->length ),
1097  XLAL_EINVAL,
1098  "SFT asked for detector index off end of list:\n sftNum1=%"LAL_UINT4_FORMAT", sftNum2=%"LAL_UINT4_FORMAT", detInd1=%"LAL_UINT4_FORMAT", detInd2=%"LAL_UINT4_FORMAT", inputSFTs->length=%d\n",
1099  sftNum1, sftNum2, detInd1, detInd2, inputSFTs->length );
1100 
1101  UINT4 sftInd1 = sftIndices->data[sftNum1].sftInd;
1102  UINT4 sftInd2 = sftIndices->data[sftNum2].sftInd;
1103 
1104  XLAL_CHECK( ( sftInd1 < inputSFTs->data[detInd1]->length )
1105  && ( sftInd2 < inputSFTs->data[detInd2]->length ),
1106  XLAL_EINVAL,
1107  "SFT asked for SFT index off end of list:\n sftNum1=%"LAL_UINT4_FORMAT", sftNum2=%"LAL_UINT4_FORMAT", detInd1=%"LAL_UINT4_FORMAT", detInd2=%"LAL_UINT4_FORMAT", sftInd1=%"LAL_UINT4_FORMAT", sftInd2=%"LAL_UINT4_FORMAT", inputSFTs->data[detInd1]->length=%d, inputSFTs->data[detInd2]->length=%d\n",
1108  sftNum1, sftNum2, detInd1, detInd2, sftInd1, sftInd2,
1109  inputSFTs->data[detInd1]->length,
1110  inputSFTs->data[detInd2]->length );
1111 
1112  COMPLEX8 *dataArray1 = inputSFTs->data[detInd1]->data[sftInd1].data->data;
1113  COMPLEX8 *dataArray2 = inputSFTs->data[detInd2]->data[sftInd2].data->data;
1114  UINT4 lenDataArray1 = inputSFTs->data[detInd1]->data[sftInd1].data->length;
1115  UINT4 lenDataArray2 = inputSFTs->data[detInd2]->data[sftInd2].data->length;
1116  COMPLEX8 GalphaCC = curlyGAmp->data[alpha]
1117  * expSignalPhases->data[sftNum1]
1118  * conj( expSignalPhases->data[sftNum2] );
1119  INT4 baseCCSign = 1; /* Alternating sign is (-1)**(k1-k2) */
1120  if ( ( ( lowestBins->data[sftNum1] - lowestBins->data[sftNum2] ) % 2 ) != 0 ) {
1121  baseCCSign = -1;
1122  }
1123 
1124  UINT4 lowestBin1 = lowestBins->data[sftNum1];
1125  XLAL_CHECK( ( ( lowestBin1 + numBins - 1 ) < lenDataArray1 ),
1126  XLAL_EINVAL,
1127  "Loop would run off end of array:\n lowestBin1=%d, numBins=%d, len(dataArray1)=%d\n",
1128  lowestBin1, numBins, lenDataArray1 );
1129  for ( UINT4 j = 0; j < numBins; j++ ) {
1130  COMPLEX8 data1 = dataArray1[lowestBin1 + j];
1131 
1132  INT4 ccSign = baseCCSign;
1133  UINT4 lowestBin2 = lowestBins->data[sftNum2];
1134  XLAL_CHECK( ( ( lowestBin2 + numBins - 1 ) < lenDataArray2 ),
1135  XLAL_EINVAL,
1136  "Loop would run off end of array:\n lowestBin2=%d, numBins=%d, len(dataArray2)=%d\n",
1137  lowestBin2, numBins, lenDataArray2 );
1138  for ( UINT4 k = 0; k < numBins; k++ ) {
1139  COMPLEX8 data2 = dataArray2[lowestBins->data[sftNum2] + k];
1140  REAL8 sincFactor = 1;
1141 
1142  sincFactor = sincList->data[sftNum1 * numBins + j] * sincList->data[sftNum2 * numBins + k];
1143  nume += ccSign * sincFactor * creal( GalphaCC * conj( data1 ) * data2 );
1144  /*nume += creal ( GalphaCC * ccSign * sincFactor * conj(data1) * data2 );=> abs(GalphaCC)*abs(data1)*abs(data2) * cos(arg(GalphaCC)-arg(data1)+arg(data2))*/
1145  /*multiWeights->data[detInd1]->data[sftNum1] * multiWeights->data[detInd2]->data[sftNum2] **/
1146  REAL8 GalphaAmp = curlyGAmp->data[alpha] * sincFactor ;
1147  /** multiWeights->data[detInd1]->data[sftNum1] * multiWeights->data[detInd2]->data[sftNum2]*/
1148  curlyGSqr += SQUARE( GalphaAmp );
1149  ccSign *= -1;
1150  }
1151  baseCCSign *= -1;
1152  }
1153  }
1154  if ( curlyGSqr == 0.0 ) {
1155  *evSquared = 0.0;
1156  *ccStat = 0.0;
1157  } else {
1158  *evSquared = 8 * SQUARE( multiWeights->Sinv_Tsft ) * curlyGSqr;
1159  *ccStat = 4 * multiWeights->Sinv_Tsft * nume / sqrt( *evSquared );
1160  }
1161  return XLAL_SUCCESS;
1162 }
1163 
1164 /** Calculate multi-bin cross-correlation statistic using resampling */
1165 /* This assumes rectangular or nearly-rectangular windowing */
1167 (
1168  REAL8Vector *restrict ccStatVector, /**< [out] vector cross-correlation statistic rho */
1169  REAL8Vector *restrict evSquaredVector, /**< [out] vector (E[rho]/h0^2) */
1170  REAL8Vector *restrict numeEquivAve, /**< [out] vector for intermediate average statistic */
1171  REAL8Vector *restrict numeEquivCirc, /**< [out] vector for intermediate circular statistic */
1172  const REAL8Vector *restrict resampCurlyGAmp, /**< [in] amplitude of curly G for each L_Y_K_X (alpha-indexed) */
1173  const MultiResampSFTPairMultiIndexList *restrict resampMultiPairs, /**< [in] resamp multi list of SFT pairs */
1174  const MultiNoiseWeights *restrict multiWeights, /**< [in] normalization factor S^-1 & weights for each SFT */
1175  const PulsarDopplerParams *restrict binaryTemplateSpacings, /**< [in] Set of spacings for search */
1176  const PulsarDopplerParams *restrict dopplerpos, /**< [in] Doppler point to search */
1177  const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_a, /**< [in] resampled time series A */
1178  const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_b, /**< [in] resampled time series B */
1179  ResampCrossCorrWorkspace *restrict ws, /**< [in/out] first workspace */
1180  COMPLEX8 *restrict ws1KFaX_k, /**< [in/out] holder for detector 1 Fa */
1181  COMPLEX8 *restrict ws1KFbX_k, /**< [in/out] holder for detector 1 Fb */
1182  COMPLEX8 *restrict ws2LFaX_k, /**< [in/out] holder for detector 2 Fa */
1183  COMPLEX8 *restrict ws2LFbX_k /**< [in/out] holder for detector 2 Fb */
1184 )
1185 {
1186  XLAL_CHECK( ws != NULL, XLAL_EINVAL );
1187  XLAL_CHECK( ws1KFaX_k != NULL, XLAL_EINVAL );
1188  XLAL_CHECK( ws1KFbX_k != NULL, XLAL_EINVAL );
1189  XLAL_CHECK( ws2LFaX_k != NULL, XLAL_EINVAL );
1190  XLAL_CHECK( ws2LFbX_k != NULL, XLAL_EINVAL );
1191 
1192  /* Initialize nume holders for resamp */
1193  REAL8 curlyEquivGSqrSum = 0;
1194  for ( UINT4 j = 0; j < ws->numFreqBinsOut; j++ ) {
1195  numeEquivAve->data[j] = 0;
1196  numeEquivCirc->data[j] = 0;
1197  ccStatVector->data[j] = 0;
1198  evSquaredVector->data[j] = 0;
1199  }
1200 
1201  const REAL8 dt_SRC = multiTimeSeries_SRC_b->data[0]->deltaT;
1202  const REAL8 SRCsampPerTcoh = resampMultiPairs->Tshort / dt_SRC;
1203 
1204  /* MAIN LOOP (RESAMPLING) */
1205  for ( UINT4 detX = 0; detX < resampMultiPairs->length; detX++ ) {
1206  for ( UINT4 sftK = 0; sftK < resampMultiPairs->data[detX].length; sftK++ ) {
1207  if ( ( XLALComputeFaFb_CrossCorrResamp( ws, ws1KFaX_k, ws1KFbX_k, resampMultiPairs, multiTimeSeries_SRC_a, multiTimeSeries_SRC_b, dopplerpos, binaryTemplateSpacings, SRCsampPerTcoh, detX, sftK, 0, FALSE ) ) != XLAL_SUCCESS ) {
1208  LogPrintf( LOG_CRITICAL, "%s: XLALComputeFaFb_CrossCorrResamp() failed with errno=%d\n", __func__, xlalErrno );
1210  }
1211  for ( UINT4 detY = 0; detY < resampMultiPairs->data[detX].data[sftK].length; detY++ ) {
1212  if ( ( XLALComputeFaFb_CrossCorrResamp( ws, ws2LFaX_k, ws2LFbX_k, resampMultiPairs, multiTimeSeries_SRC_a, multiTimeSeries_SRC_b, dopplerpos, binaryTemplateSpacings, SRCsampPerTcoh, detX, sftK, detY, TRUE ) ) != XLAL_SUCCESS ) {
1213  LogPrintf( LOG_CRITICAL, "%s: XLALComputeFaFb_CrossCorrResamp() failed with errno=%d\n", __func__, xlalErrno );
1215  }
1216  /* -...-...-...- NEW CORE -...-...-...- */
1217  for ( UINT8 j = 0; j < ws->numFreqBinsOut; j++ ) {
1218  numeEquivAve->data[j] += creal( 0.1 * ( conj( ws1KFaX_k[j] ) * ws2LFaX_k[j] + conj( ws1KFbX_k[j] ) * ws2LFbX_k[j] ) );
1219  /* Can use for circular polarization:
1220  * numeEquivCirc->data[j] += creal(0.1 * ( conj(ws1KFaX_k[j]) * ws2LFbX_k[j] - conj(ws1KFbX_k[j]) * ws2LFaX_k[j] ) ); */
1221  }
1222  /* -...-...-...- END NEW CORE -...-...-...- */
1223  } /* detY */
1224  } /* sftK */
1225  } /* detX */ /* end main loop (NOW WITH RESAMPLING) */
1226 
1227  /* ENDING RESAMPLING SECTION */
1228 
1229  /* Normalization factors moved outside of core: */
1230  for ( UINT4 alpha = 0; alpha < resampMultiPairs->allPairCount; alpha++ ) {
1231  REAL8 GalphaResampAmp = resampCurlyGAmp->data[alpha];
1232  curlyEquivGSqrSum += SQUARE( GalphaResampAmp );
1233  }
1234  /* Because FstatInput in the outer for-loop read in and normalized
1235  * sfts according to their original SFT length, and that determines
1236  * the scale of Fa, Fb, and therefore numeEquivAve (according to
1237  * to Wiener-Kinchine, E[|data|^2] = Tsft * Sn / 2 for spectral
1238  * noise Sn, and compare XLALNormalizeMultiSFTVect and
1239  * XLALNormalizeSFT we need to access the original
1240  * multi-weights S inverse Tsft for normalize numeEquivAve. However,
1241  * we use the modified multi-weights S inverse Tsft for curlyEquivGSqrSum,
1242  * because that was created with Tshort and the modified S inverse Tsft.
1243  * Note that
1244  * multiWeights->Sinv_Tsft =...
1245  * sum_dets(sum_sfts( length_sft/(running median_sft ) ) ),
1246  * ergo 1/Sinv_Tsft is the harmonic mean of running median noise.
1247  * Therefore this normalization should be valid even when used with
1248  * detectors with different noise levels.
1249  */
1250  const REAL8 originalMultiWeightsSinvTsft = multiWeights->Sinv_Tsft * ( resampMultiPairs->Tsft / resampMultiPairs->Tshort );
1251  for ( UINT8 j = 0; j < ws->numFreqBinsOut; j++ ) {
1252  evSquaredVector->data[j] = 8 * SQUARE( multiWeights->Sinv_Tsft ) * curlyEquivGSqrSum;
1253  ccStatVector->data[j] = 4 * originalMultiWeightsSinvTsft * numeEquivAve->data[j] / sqrt( evSquaredVector->data[j] );
1254  }
1255  return XLAL_SUCCESS;
1256 } // end XLALCalculatePulsarCrossCorrStatisticResamp
1257 
1258 /** calculate signal phase derivatives wrt Doppler coords, for each SFT */
1259 /* allocates memory as well */
1261 (
1262  REAL8VectorSequence **phaseDerivs, /**< Output: dPhi_K/dlambda_i; i is the "sequence" index, K is the "vector" index */
1263  const PulsarDopplerParams *dopplerPoint, /**< Input: pulsar/binary orbit paramaters */
1264  const EphemerisData *edat, /**< Input: Earth/Sun ephemeris */
1265  SFTIndexList *indexList, /**< Input: list of SFT indices */
1266  MultiSSBtimes *multiTimes, /**< Input: barycentered times of SFTs */
1267  const DopplerCoordinateSystem *coordSys /**< Input: coordinates with which to differentiate */
1268 )
1269 {
1270  XLAL_CHECK( dopplerPoint != NULL, XLAL_EINVAL );
1271  XLAL_CHECK( edat != NULL, XLAL_EINVAL );
1272  XLAL_CHECK( indexList != NULL, XLAL_EINVAL );
1273  XLAL_CHECK( multiTimes != NULL, XLAL_EINVAL );
1274  XLAL_CHECK( coordSys != NULL, XLAL_EINVAL );
1275 
1276  const UINT4 numCoords = coordSys->dim;
1277  const UINT4 numSFTs = indexList->length;
1278 
1279  REAL8VectorSequence *ret = NULL;
1280 
1281  XLAL_CHECK( ( ret = XLALCreateREAL8VectorSequence( numCoords, numSFTs ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8VectorSequence ( %"LAL_UINT4_FORMAT", %"LAL_UINT4_FORMAT" ) failed.", numCoords, numSFTs );
1282 
1283  for ( UINT4 coordNum = 0; coordNum < numCoords; coordNum++ ) {
1284  for ( UINT4 sftNum = 0; sftNum < numSFTs; sftNum++ ) {
1285  UINT4 detInd = indexList->data[sftNum].detInd;
1286  UINT4 sftInd = indexList->data[sftNum].sftInd;
1287  SSBtimes *times;
1288  times = multiTimes->data[detInd];
1289  REAL8 refTime8 = XLALGPSGetREAL8( &( times->refTime ) );
1290  UINT4 numSFTsDet = times->DeltaT->length;
1291  XLAL_CHECK( ( sftInd < numSFTsDet ), XLAL_EINVAL, "SFT asked for SFT index off end of list:\n sftNum=%"LAL_UINT4_FORMAT", detInd=%"LAL_UINT4_FORMAT", sftInd=%"LAL_UINT4_FORMAT", numSFTsDet=%"LAL_UINT4_FORMAT"\n", sftNum, detInd, sftInd, numSFTsDet );
1292  REAL8 tSSB = refTime8 + times->DeltaT->data[sftInd];
1293  ret->data[coordNum * numSFTs + sftNum] = XLALComputePhaseDerivative( tSSB, dopplerPoint, ( coordSys->coordIDs[coordNum] ), edat, NULL, 0 );
1294  XLAL_CHECK( xlalErrno == 0, XLAL_EFUNC, "XLALComputePhaseDerivative() failed with xlalErrno = %d\n", xlalErrno );
1295  }
1296  }
1297 
1298  ( *phaseDerivs ) = ret;
1299 
1300  return XLAL_SUCCESS;
1301 
1302 }
1303 
1304 /** (test function) MODIFIED for Tshort */
1305 /** calculate signal phase derivatives wrt Doppler coords, for each SFT */
1306 /* allocates memory as well */
1308 (
1309  REAL8VectorSequence **resampPhaseDerivs, /**< [out] dPhi_K/dlambda_i; i is the "sequence" index, K is the "vector" index */
1310  const PulsarDopplerParams *dopplerPoint, /**< [in] pulsar/binary orbit paramaters */
1311  const EphemerisData *edat, /**< [in Earth/Sun ephemeris */
1312  SFTIndexList *indexList, /**< [in] list of SFT indices */
1313  MultiResampSFTPairMultiIndexList *resampMultiPairs, /**< [in] resamp list of SFT pairs */
1314  MultiSSBtimes *multiTimes, /**< [in] barycentered times of SFTs */
1315  const DopplerCoordinateSystem *coordSys /**< [in] coordinates with which to differentiate */
1316 )
1317 {
1318  /* Note: the use of tSSBApprox rather than the true tSSB contributes
1319  * a very small but observable difference between this function and
1320  * a correctly-configured call to the normal phase derivatives function. */
1321  XLAL_CHECK( dopplerPoint != NULL, XLAL_EINVAL );
1322  XLAL_CHECK( edat != NULL, XLAL_EINVAL );
1323  XLAL_CHECK( indexList != NULL, XLAL_EINVAL );
1324  XLAL_CHECK( resampMultiPairs != NULL, XLAL_EINVAL );
1325  XLAL_CHECK( multiTimes != NULL, XLAL_EINVAL );
1326  XLAL_CHECK( coordSys != NULL, XLAL_EINVAL );
1327 
1328  /* The actual SFT indices from the original catalog are no longer
1329  * relevant; in resampling, we use new SFTs. These are not evenly
1330  * spaced in the detector frame, but for the purpose of taking the
1331  * values for gamma ave that is needed for the metric, and hence
1332  * for the returned resampPhaseDerivs, this should average out. */
1333  const UINT4 numCoords = coordSys->dim;
1334  const UINT4 numShorts = resampMultiPairs->sftTotalCount;
1335  const REAL8 Tshort = resampMultiPairs->Tshort;
1336  printf( "numShorts: %u\n", numShorts );
1337 
1338  REAL8VectorSequence *retNew = NULL;
1339  XLAL_CHECK( ( retNew = XLALCreateREAL8VectorSequence( numCoords, numShorts ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8VectorSequence ( %"LAL_UINT4_FORMAT", %"LAL_UINT4_FORMAT" ) failed.", numCoords, numShorts );
1340 
1341  for ( UINT4 coordNum = 0; coordNum < numCoords; coordNum++ ) {
1342  for ( UINT4 detX = 0; detX < resampMultiPairs->length; detX++ ) {
1343  for ( UINT4 k = 0; k < resampMultiPairs->data[detX].length; k++ ) {
1344  /* Both detectors' resampled time series have the same start time now,
1345  * or should be aligned to be so. We just need the nominal time in SSB,
1346  * so we could probably calculate the start time of the first SFT and
1347  * add the number of Tshort segments that follow */
1348  REAL8 startTime8 = XLALGPSGetREAL8( &( multiTimes->data[0]->refTime ) ) + multiTimes->data[0]->DeltaT->data[0];
1349  /* Cannot use Tshort * shortNum -- it needs to be the number
1350  * within THAT detector */
1351  UINT4 shortSFTIndOwn = resampMultiPairs->data[detX].data[k].sftInd;
1352  UINT4 shortSFTInd = resampMultiPairs->data[detX].data[k].flatInd;
1353  REAL8 tSSBApprox = startTime8 + Tshort * shortSFTIndOwn;
1354  retNew->data[coordNum * numShorts + shortSFTInd] = XLALComputePhaseDerivative( tSSBApprox, dopplerPoint, ( coordSys->coordIDs[coordNum] ), edat, NULL, 0 );
1355  XLAL_CHECK( xlalErrno == 0, XLAL_EFUNC, "XLALComputePhaseDerivative() failed with xlalErrno = %d\n", xlalErrno );
1356  }
1357  }
1358  }
1359  ( *resampPhaseDerivs ) = retNew;
1360 
1361  return XLAL_SUCCESS;
1362 } /* end XLALCalculateCrossCorrPhaseDerivativesShort */
1363 
1364 /** calculate phase metric for CW cross-correlation search, as well as vector used for parameter offsets */
1365 /** This calculates the metric defined in (4.7) of Whelan et al 2015 and the parameter offset epsilon_i */
1366 /** (not including the cosi-dependent prefactor) in defined in (4.8) */
1367 /* allocates memory as well */
1369 (
1370  gsl_matrix **g_ij, /**< Output: parameter space metric */
1371  gsl_vector **eps_i, /**< Output: parameter offset vector from (4.8) of WSZP15 */
1372  REAL8 *sumGammaSq, /**< Output: sum of (Gamma_ave)^2 for normalization and sensitivity */
1373  const REAL8VectorSequence *phaseDerivs, /**< Input: dPhi_K/dlambda_i; i is the "sequence" index, K is the "vector" */
1374  const SFTPairIndexList *pairIndexList, /**< Input: list of SFT pairs */
1375  const REAL8Vector *Gamma_ave, /**< Input: vector of aa+bb values */
1376  const REAL8Vector *Gamma_circ, /**< Input: vector of ab-ba values */
1377  const DopplerCoordinateSystem *coordSys /**< Input: coordinate directions for metric */
1378 )
1379 {
1380  XLAL_CHECK( sumGammaSq != NULL, XLAL_EINVAL );
1381  XLAL_CHECK( phaseDerivs != NULL, XLAL_EINVAL );
1382  XLAL_CHECK( pairIndexList != NULL, XLAL_EINVAL );
1383  XLAL_CHECK( Gamma_ave != NULL, XLAL_EINVAL );
1384  XLAL_CHECK( Gamma_circ != NULL, XLAL_EINVAL );
1385  XLAL_CHECK( coordSys != NULL, XLAL_EINVAL );
1386 
1387  const UINT4 numCoords = coordSys->dim;
1388  XLAL_CHECK( ( phaseDerivs->length == numCoords ), XLAL_EINVAL, "Length mismatch: phaseDerivs->length=%"LAL_UINT4_FORMAT", numCoords=%"LAL_UINT4_FORMAT"\n", phaseDerivs->length, numCoords );
1389  const UINT4 numSFTs = phaseDerivs->vectorLength;
1390  const UINT4 numPairs = pairIndexList->length;
1391  XLAL_CHECK( ( Gamma_ave->length == numPairs ), XLAL_EINVAL, "Length mismatch: Gamma_ave->length=%"LAL_UINT4_FORMAT", numPairs=%"LAL_UINT4_FORMAT"\n", Gamma_ave->length, numPairs );
1392  XLAL_CHECK( ( Gamma_circ->length == numPairs ), XLAL_EINVAL, "Length mismatch: Gamma_circ->length=%"LAL_UINT4_FORMAT", numPairs=%"LAL_UINT4_FORMAT"\n", Gamma_circ->length, numPairs );
1393 
1394  /* ---------- prepare output metric ---------- */
1395  gsl_matrix *ret_g;
1396  if ( ( ret_g = gsl_matrix_calloc( numCoords, numCoords ) ) == NULL ) {
1397  XLALPrintError( "%s: gsl_matrix_calloc(%d, %d) failed.\n\n", __func__, numCoords, numCoords );
1399 
1400  }
1401  gsl_vector *ret_e;
1402  if ( ( ret_e = gsl_vector_calloc( numCoords ) ) == NULL ) {
1403  XLALPrintError( "%s: gsl_vector_calloc(%d) failed.\n\n", __func__, numCoords );
1405  }
1406 
1407  REAL8Vector *dDeltaPhi_i = NULL;
1408  REAL8 denom = 0;
1409  XLAL_CHECK( ( dDeltaPhi_i = XLALCreateREAL8Vector( numCoords ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numCoords );
1410  for ( UINT4 pairNum = 0; pairNum < numPairs; pairNum++ ) {
1411  UINT4 sftNum1 = pairIndexList->data[pairNum].sftNum[0];
1412  UINT4 sftNum2 = pairIndexList->data[pairNum].sftNum[1];
1413  REAL8 aveWeight = SQUARE( Gamma_ave->data[pairNum] );
1414  denom += aveWeight;
1415  REAL8 circWeight = Gamma_ave->data[pairNum] * Gamma_circ->data[pairNum];
1416  for ( UINT4 i = 0; i < numCoords; i++ ) {
1417  dDeltaPhi_i->data[i] = phaseDerivs->data[i * numSFTs + sftNum1] - phaseDerivs->data[i * numSFTs + sftNum2];
1418  REAL8 epsi = gsl_vector_get( ret_e, i );
1419  epsi += circWeight * dDeltaPhi_i->data[i];
1420  gsl_vector_set( ret_e, i, epsi );
1421  for ( UINT4 j = 0; j <= i; j++ ) { /* Doing the loop this way ensures dDeltaPhi_i[j] has been set */
1422  REAL8 gij = gsl_matrix_get( ret_g, i, j );
1423  gij += aveWeight * dDeltaPhi_i->data[i] * dDeltaPhi_i->data[j];
1424  gsl_matrix_set( ret_g, i, j, gij );
1425  }
1426  }
1427  }
1428 
1429  XLALDestroyREAL8Vector( dDeltaPhi_i );
1430 
1431  for ( UINT4 i = 0; i < numCoords; i++ ) {
1432  REAL8 epsi = gsl_vector_get( ret_e, i );
1433  epsi /= denom;
1434  gsl_vector_set( ret_e, i, epsi );
1435  for ( UINT4 j = 0; j <= i; j++ ) { /* Doing the loop the same way as above */
1436  REAL8 gij = gsl_matrix_get( ret_g, i, j );
1437  gij /= ( 2.*denom );
1438  gsl_matrix_set( ret_g, i, j, gij );
1439  if ( i != j ) {
1440  gsl_matrix_set( ret_g, j, i, gij );
1441  }
1442  }
1443  }
1444 
1445  ( *g_ij ) = ret_g;
1446  ( *eps_i ) = ret_e;
1447  ( *sumGammaSq ) = denom;
1448 
1449  return XLAL_SUCCESS;
1450 
1451 }
1452 
1453 /** (test function) Redesigning to use Tshort instead */
1454 /** calculate phase metric for CW cross-correlation search, as well as vector used for parameter offsets */
1455 /** This calculates the metric defined in (4.7) of Whelan et al 2015 and the parameter offset epsilon_i */
1456 /** (not including the cosi-dependent prefactor) in defined in (4.8) */
1457 /* allocates memory as well */
1459 (
1460  gsl_matrix **g_ij, /**< [out] parameter space metric */
1461  gsl_vector **eps_i, /**< [out] parameter offset vector from (4.8) of WSZP15 */
1462  REAL8 *sumGammaSq, /**< [out] sum of (Gamma_ave)^2 for normalization and sensitivity */
1463  const REAL8VectorSequence *phaseDerivs, /**< [in] dPhi_K/dlambda_i; i is the "sequence" index, K is the "vector" */
1464  const MultiResampSFTPairMultiIndexList *resampMultiPairs, /**< [in] resamp multi list of SFT pairs */
1465  const REAL8Vector *Gamma_ave, /**< [in]: vector of aa+bb values */
1466  const REAL8Vector *Gamma_circ, /**< [in] vector of ab-ba values */
1467  const DopplerCoordinateSystem *coordSys /**< [in] coordinate directions for metric */
1468 )
1469 {
1470  XLAL_CHECK( sumGammaSq != NULL, XLAL_EINVAL );
1471  XLAL_CHECK( phaseDerivs != NULL, XLAL_EINVAL );
1472  XLAL_CHECK( Gamma_ave != NULL, XLAL_EINVAL );
1473  XLAL_CHECK( Gamma_circ != NULL, XLAL_EINVAL );
1474  XLAL_CHECK( coordSys != NULL, XLAL_EINVAL );
1475 
1476  const UINT4 numCoords = coordSys->dim;
1477  XLAL_CHECK( ( phaseDerivs->length == numCoords ), XLAL_EINVAL, "Length mismatch: phaseDerivs->length=%"LAL_UINT4_FORMAT", numCoords=%"LAL_UINT4_FORMAT"\n", phaseDerivs->length, numCoords );
1478  const UINT4 numSFTs = phaseDerivs->vectorLength;
1479  const UINT4 numShorts = resampMultiPairs->sftTotalCount;
1480  XLAL_CHECK( ( numSFTs == numShorts ), XLAL_EINVAL, "Length mismatch: phaseDerivs->vectorLength=%"LAL_UINT4_FORMAT", resampMultiPairs->sftTotalCount=%"LAL_UINT4_FORMAT"\n", numSFTs, numShorts );
1481  const UINT4 numShortPairs = resampMultiPairs->allPairCount;
1482  XLAL_CHECK( ( Gamma_ave->length == numShortPairs ), XLAL_EINVAL, "Length mismatch: Gamma_ave->length=%"LAL_UINT4_FORMAT", numPairs=%"LAL_UINT4_FORMAT"\n", Gamma_ave->length, numShortPairs );
1483  XLAL_CHECK( ( Gamma_circ->length == numShortPairs ), XLAL_EINVAL, "Length mismatch: Gamma_circ->length=%"LAL_UINT4_FORMAT", numPairs=%"LAL_UINT4_FORMAT"\n", Gamma_circ->length, numShortPairs );
1484 
1485  /* ---------- prepare output metric ---------- */
1486  gsl_matrix *ret_gNew;
1487  if ( ( ret_gNew = gsl_matrix_calloc( numCoords, numCoords ) ) == NULL ) {
1488  XLALPrintError( "%s: gsl_matrix_calloc(%d, %d) failed.\n\n", __func__, numCoords, numCoords );
1490 
1491  }
1492  gsl_vector *ret_eNew;
1493  if ( ( ret_eNew = gsl_vector_calloc( numCoords ) ) == NULL ) {
1494  XLALPrintError( "%s: gsl_vector_calloc(%d) failed.\n\n", __func__, numCoords );
1496  }
1497 
1498  REAL8Vector *dDeltaPhiNew_i = NULL;
1499  XLAL_CHECK( ( dDeltaPhiNew_i = XLALCreateREAL8Vector( numCoords ) ) != NULL, XLAL_EFUNC, "XLALCreateREAL8Vector ( %"LAL_UINT4_FORMAT" ) failed.", numCoords );
1500 
1501  /* new style, with proper sftIndices Tshort */
1502  UINT4 pairMetric = 0;
1503  UINT4 sftInd1 = 0;
1504  UINT4 sftInd2 = 0;
1505  REAL8 aveNewWeight = 0.0;
1506  REAL8 denomNew = 0.0;
1507  REAL8 circNewWeight = 0.0;
1508  for ( UINT4 detX = 0; detX < resampMultiPairs->length; detX++ ) {
1509  for ( UINT4 k = 0; k < resampMultiPairs->data[detX].length; k++ ) {
1510  for ( UINT4 detY = 0; detY < resampMultiPairs->data[detX].data[k].length; detY++ ) {
1511  for ( UINT4 l = 0; l < resampMultiPairs->data[detX].data[k].data[detY].length; l++ ) {
1512  sftInd1 = resampMultiPairs->data[detX].data[k].flatInd;
1513  sftInd2 = resampMultiPairs->data[detX].data[k].data[detY].data[l].flatInd;
1514  pairMetric = resampMultiPairs->data[detX].data[k].data[detY].data[l].pairInd;
1515  aveNewWeight = SQUARE( Gamma_ave->data[pairMetric] );
1516  denomNew += aveNewWeight;
1517  circNewWeight = Gamma_ave->data[pairMetric] * Gamma_circ->data[pairMetric];
1518  for ( UINT4 i = 0; i < numCoords; i++ ) {
1519  dDeltaPhiNew_i->data[i] = phaseDerivs->data[i * numShorts + sftInd1] - phaseDerivs->data[i * numShorts + sftInd2];
1520  REAL8 epsNewi = gsl_vector_get( ret_eNew, i );
1521  epsNewi += circNewWeight * dDeltaPhiNew_i->data[i];
1522  gsl_vector_set( ret_eNew, i, epsNewi );
1523  for ( UINT4 j = 0; j <= i; j++ ) { /* Doing the loop this way ensures dDeltaPhi_i[j] has been set */
1524  REAL8 gijNew = gsl_matrix_get( ret_gNew, i, j );
1525  gijNew += aveNewWeight * dDeltaPhiNew_i->data[i] * dDeltaPhiNew_i->data[j];
1526  gsl_matrix_set( ret_gNew, i, j, gijNew );
1527  } // end j loop
1528  } // end i loop over coords
1529  }
1530  }
1531  }
1532  }
1533 
1534  XLALDestroyREAL8Vector( dDeltaPhiNew_i );
1535 
1536  for ( UINT4 i = 0; i < numCoords; i++ ) {
1537  REAL8 epsNewi = gsl_vector_get( ret_eNew, i );
1538  epsNewi /= denomNew;
1539  gsl_vector_set( ret_eNew, i, epsNewi );
1540  for ( UINT4 j = 0; j <= i; j++ ) { /* Doing the loop the same way as above */
1541  REAL8 gijNew = gsl_matrix_get( ret_gNew, i, j );
1542  gijNew /= ( 2.*denomNew );
1543  gsl_matrix_set( ret_gNew, i, j, gijNew );
1544  if ( i != j ) {
1545  gsl_matrix_set( ret_gNew, j, i, gijNew );
1546  }
1547  }
1548  }
1549 
1550  ( *g_ij ) = ret_gNew;
1551  ( *eps_i ) = ret_eNew;
1552  ( *sumGammaSq ) = denomNew;
1553 
1554  return XLAL_SUCCESS;
1555 
1556 } // end XLALCalculateCrossCorrPhaseMetricShort
1557 
1558 /*calculate metric diagonal components, also include the estimation of sensitivity E[rho]/(h_0)^2*/
1560 (
1561  REAL8 *hSens, /* Output: sensitivity*/
1562  REAL8 *g_ff, /* Output: Diagonal frequency metric element */
1563  REAL8 *g_aa, /* Output: Diagonal binary projected semimajor axis metric element*/
1564  REAL8 *g_TT, /* Output: Diagonal reference time metric element*/
1565  REAL8 *g_pp, /* Output: Diagonal orbital period metric element */
1566  REAL8 *weightedMuTAve, /* output: weighred T mean*/
1567  PulsarDopplerParams DopplerParams, /* Input: pulsar/binary orbit paramaters*/
1568  REAL8Vector *G_alpha, /* Input: vector of curlyGunshifted values */
1569  SFTPairIndexList *pairIndexList, /* Input: list of SFT pairs */
1570  SFTIndexList *indexList, /* Input: list of SFTs */
1571  MultiSFTVector *sfts, /* Input: set of per-detector SFT vectors */
1572  MultiNoiseWeights *multiWeights /* Input: Input: nomalizeation factor S^-1 & weights for each SFT*/
1573 )
1574 
1575 {
1576  UINT4 sftNum1 = 0;
1577  UINT4 sftNum2 = 0;
1578  REAL8 TDiff = 0;
1579  REAL8 TMean = 0;
1580  REAL8 denom = 0;
1581  REAL8 TSquaWeightedAve = 0;
1582  REAL8 SinSquaWeightedAve = 0;
1583  REAL8 muT = 0;
1584  REAL8 muTSqr = 0;
1585  REAL8 muTAve = 0;
1586  REAL8 muTAveSqr = 0;
1587  REAL8 muTSqrAve = 0;
1588  REAL8 sinSquare = 0;
1589  REAL8 tSquare = 0;
1590  REAL8 rhosum = 0;
1591  LIGOTimeGPS *T1 = NULL;
1592  LIGOTimeGPS *T2 = NULL;
1593  UINT4 numalpha = G_alpha->length;
1594 
1595 
1596  for ( UINT4 j = 0; j < numalpha; j++ ) {
1597  sftNum1 = pairIndexList->data[j].sftNum[0];
1598  sftNum2 = pairIndexList->data[j].sftNum[1];
1599  UINT4 detInd1 = indexList->data[sftNum1].detInd;
1600  UINT4 detInd2 = indexList->data[sftNum2].detInd;
1601  UINT4 sftInd1 = indexList->data[sftNum1].sftInd;
1602  UINT4 sftInd2 = indexList->data[sftNum2].sftInd;
1603  T1 = &( sfts->data[detInd1]->data[sftInd1].epoch );
1604  T2 = &( sfts->data[detInd2]->data[sftInd2].epoch );
1605  TDiff = XLALGPSDiff( T1, T2 );
1606  TMean = 0.5 * ( XLALGPSGetREAL8( T1 ) + XLALGPSGetREAL8( T2 ) );
1607  REAL8 sqrG_alpha = SQUARE( G_alpha->data[j] ); /*(curlyG_{\alpha})^2*/
1608  muT += sqrG_alpha * TMean; /*(curlyG_\alpha)^2 * \bar{t}_{\alpha}*/
1609  muTSqr += sqrG_alpha * SQUARE( TMean ); /*(curlyG_\alpha)^2 * (\bar{t}_{\alpha})^2*/
1610  sinSquare += sqrG_alpha * SQUARE( sin( LAL_PI * TDiff / ( DopplerParams.period ) ) ); /*(G_{\alpha})^2*(sin(\pi*T/T_orbit))^2*/
1611  tSquare += sqrG_alpha * SQUARE( TDiff ); /*(\curlyg_{\alpha}*)^2*T^2*/
1612  denom += sqrG_alpha; /*calculate the denominator*/
1613  rhosum += 2 * sqrG_alpha;
1614  }
1615 
1616  muTAve = muT / denom;
1617  muTAveSqr = SQUARE( muTAve );
1618  muTSqrAve = muTSqr / denom;
1619  REAL8 sigmaTSqr = muTSqrAve - muTAveSqr;
1620  TSquaWeightedAve = tSquare / denom;
1621  SinSquaWeightedAve = sinSquare / denom;
1622  *hSens = 4 * SQUARE( multiWeights->Sinv_Tsft ) * rhosum;
1623  *g_ff = TSquaWeightedAve * 2 * SQUARE( LAL_PI );
1624  *g_aa = SinSquaWeightedAve * SQUARE( 2. * LAL_PI * DopplerParams.fkdot[0] );
1625  *g_TT = SinSquaWeightedAve * SQUARE( SQUARE( 2. * LAL_PI ) * ( DopplerParams.fkdot[0] ) * ( DopplerParams.asini ) / ( DopplerParams.period ) );
1626  *g_pp = SinSquaWeightedAve * sigmaTSqr * 16 * QUAD( LAL_PI ) * SQUARE( DopplerParams.fkdot[0] ) * SQUARE( DopplerParams.asini ) / ( QUAD( DopplerParams.period ) );
1627  *weightedMuTAve = muTAve;
1628 
1629  return XLAL_SUCCESS;
1630 
1631 }
1632 
1633 /** MODIFIED for Tshort:
1634  * calculate metric diagonal components, also include the estimation of sensitivity E[rho]/(h_0)^2*/
1636 (
1637  REAL8 *hSens, /**< [out] sensitivity */
1638  REAL8 *g_ff, /**< [out] Diagonal frequency metric element */
1639  REAL8 *g_aa, /**< [out] Diagonal binary projected semimajor axis metric element*/
1640  REAL8 *g_TT, /**< [out] Diagonal reference time metric element */
1641  REAL8 *g_pp, /**< [out] Diagonal orbital period metric element */
1642  const PulsarDopplerParams DopplerParams, /**< [in] pulsar/binary orbit paramaters */
1643  const REAL8Vector *restrict G_alpha, /**< [in] vector of curlyGunshifted values */
1644  const MultiResampSFTPairMultiIndexList *restrict resampMultiPairIndexList, /**< [in] resamp list of SFT pairs */
1645  const MultiLIGOTimeGPSVector *restrict timestamps, /**< [in] timestamps for resampling */
1646  const MultiNoiseWeights *restrict multiWeights /**< [in] normalization factor S^-1 & weights for each SFT */
1647 )
1648 
1649 {
1650  UINT4 sftNum1 = 0;
1651  UINT4 sftNum2 = 0;
1652  REAL8 TDiff = 0;
1653  REAL8 TMean = 0;
1654  REAL8 denom = 0;
1655  REAL8 TSquaWeightedAve = 0;
1656  REAL8 SinSquaWeightedAve = 0;
1657  REAL8 muT = 0;
1658  REAL8 muTSqr = 0;
1659  REAL8 muTAve = 0;
1660  REAL8 muTAveSqr = 0;
1661  REAL8 muTSqrAve = 0;
1662  REAL8 sinSquare = 0;
1663  REAL8 tSquare = 0;
1664  REAL8 rhosum = 0;
1665  LIGOTimeGPS *T1 = NULL;
1666  LIGOTimeGPS *T2 = NULL;
1667 
1668  UINT4 numPairs = resampMultiPairIndexList->allPairCount;
1669  SFTPairIndexList *pairIndexList = resampMultiPairIndexList->pairIndexList;
1670  SFTIndexList *indexList = resampMultiPairIndexList->indexList;
1671 
1672  for ( UINT4 j = 0; j < numPairs; j++ ) {
1673  sftNum1 = pairIndexList->data[j].sftNum[0];
1674  sftNum2 = pairIndexList->data[j].sftNum[1];
1675  UINT4 detInd1 = indexList->data[sftNum1].detInd;
1676  UINT4 detInd2 = indexList->data[sftNum2].detInd;
1677  UINT4 sftInd1 = indexList->data[sftNum1].sftInd;
1678  UINT4 sftInd2 = indexList->data[sftNum2].sftInd;
1679  T1 = &( timestamps->data[detInd1]->data[sftInd1] ) ;
1680  T2 = &( timestamps->data[detInd2]->data[sftInd2] ) ;
1681  TDiff = XLALGPSDiff( T1, T2 );
1682  TMean = 0.5 * ( XLALGPSGetREAL8( T1 ) + XLALGPSGetREAL8( T2 ) );
1683  REAL8 sqrG_alpha = SQUARE( G_alpha->data[j] ); /*(curlyG_{\alpha})^2*/
1684  muT += sqrG_alpha * TMean; /*(curlyG_\alpha)^2 * \bar{t}_{\alpha}*/
1685  muTSqr += sqrG_alpha * SQUARE( TMean ); /*(curlyG_\alpha)^2 * (\bar{t}_{\alpha})^2*/
1686  sinSquare += sqrG_alpha * SQUARE( sin( LAL_PI * TDiff / ( DopplerParams.period ) ) ); /*(G_{\alpha})^2*(sin(\pi*T/T_orbit))^2*/
1687  tSquare += sqrG_alpha * SQUARE( TDiff ); /*(\curlyg_{\alpha}*)^2*T^2*/
1688  denom += sqrG_alpha; /*calculate the denominator*/
1689  rhosum += 2 * sqrG_alpha;
1690  }
1691  muTAve = muT / denom;
1692  muTAveSqr = SQUARE( muTAve );
1693  muTSqrAve = muTSqr / denom;
1694  REAL8 sigmaTSqr = muTSqrAve - muTAveSqr;
1695  TSquaWeightedAve = tSquare / denom;
1696  SinSquaWeightedAve = sinSquare / denom;
1697  *hSens = 4 * SQUARE( multiWeights->Sinv_Tsft ) * rhosum;
1698  *g_ff = TSquaWeightedAve * 2 * SQUARE( LAL_PI );
1699  *g_aa = SinSquaWeightedAve * SQUARE( 2. * LAL_PI * DopplerParams.fkdot[0] );
1700  *g_TT = SinSquaWeightedAve * SQUARE( SQUARE( 2. * LAL_PI ) * ( DopplerParams.fkdot[0] ) * ( DopplerParams.asini ) / ( DopplerParams.period ) );
1701  *g_pp = SinSquaWeightedAve * sigmaTSqr * 16 * QUAD( LAL_PI ) * SQUARE( DopplerParams.fkdot[0] ) * SQUARE( DopplerParams.asini ) / ( QUAD( DopplerParams.period ) );
1702 
1703  return XLAL_SUCCESS;
1704 
1705 } // end XLALCalculateLMXBCrossCorrDiagMetricShort
1706 
1707 ///** (possible future function) Wrapper for Bessel Orbital Space stepper in the manner of V. Dergachev's loosely-coherent search */
1708 //int
1709 //XLALBesselCrossCorrOrbitalSpaceStep( COMPLEX8 * xTildeOut, /**< output Fa or Fb (FFT of resampled time series) */
1710 // COMPLEX8 * xTildeIn, /**< input Fa or Fb (FFT of resampled time series) */
1711 // PulsarDopplerParams * dopplerPoint, /**< Input: Doppler point to search */
1712 // PulsarDopplerParams * binaryTemplateSpacings, /**< Input: Set of spacings for search */
1713 // INT4 aStep, /**< how many steps in a sin i */
1714 // INT4 pStep, /**< how many steps in period */
1715 // INT4 tStep, /**< how many steps in time of ascension */
1716 // INT4 nFFT, /**< number of samples in the FFT */
1717 // UINT4 nTermsMax /**< Maximum number of terms in convolution */
1718 //)
1719 //{
1720 // /* Experimental shift */
1721 // /* Example call to this function from Compute Fa Fb: */
1722 // //XLALBesselCrossCorrOrbitalSpaceStep(ws->FaX_k, ws->FaX_k, dopplerpos, binaryTemplateSpacings, 0, 0, 0, ws->numFreqBinsOut, 10);
1723 // //XLALBesselCrossCorrOrbitalSpaceStep(ws->FbX_k, ws->FbX_k, dopplerpos, binaryTemplateSpacings, 0, 0, 0, ws->numFreqBinsOut, 10);
1724 //
1725 // XLAL_CHECK ( xTildeOut != NULL, XLAL_EINVAL );
1726 // XLAL_CHECK ( xTildeIn != NULL, XLAL_EINVAL );
1727 // XLAL_CHECK ( dopplerPoint != NULL, XLAL_EINVAL );
1728 // if (pStep > (INT4)nTermsMax){
1729 // fprintf(stdout, "pStep seems suspiciously large\n");
1730 // }
1731 // if (tStep > (INT4)nTermsMax){
1732 // fprintf(stdout, "tStep seems suspiciously large\n");
1733 // }
1734 // //fprintf(stdout, "aStep, pStep, tStep, nFFT, nTermsMax: %i, %i, %i, %i, %u\n", aStep, pStep, tStep, nFFT, nTermsMax);
1735 //
1736 // COMPLEX8 *besselFX_k;
1737 // XLAL_CHECK ( (besselFX_k = fftw_malloc ( nFFT * sizeof(COMPLEX8) )) != NULL, XLAL_ENOMEM );
1738 // memset ( besselFX_k, 0, nFFT * sizeof(besselFX_k[0]) );
1739 // //memcpy ( besselFX_k, xTildeIn, nFFT);
1740 //
1741 // /* Act upon the input */
1742 // /* Simple test */
1743 // //for ( INT4 k = 0; k < nFFT; k++ )
1744 // //{
1745 // // COMPLEX8 normX_k = 10.0 ;
1746 // // besselFX_k[k] = normX_k * xTildeIn[k];
1747 // // //if (k == nFFT-1){
1748 // // // fprintf(stdout, "Made it!\n");
1749 // // //}
1750 // //} // for k < nFFT
1751 //
1752 // //REAL8 asiniPos = dopplerPoint->asini;
1753 // REAL8 minFreq = dopplerPoint->fkdot[0];
1754 // REAL8 nominalPeriod = dopplerPoint->period;
1755 // REAL8 nominalTp = XLALGPSGetREAL8(&dopplerPoint->tp);
1756 // REAL8 asiniSpace = binaryTemplateSpacings->asini;
1757 // //REAL8 tpSpace = XLALGPSGetREAL8(&binaryTemplateSpacings->tp);
1758 // //REAL8 periodSpace = binaryTemplateSpacings->period;
1759 // REAL8 asiniShift = aStep * asiniSpace;
1760 // //REAL8 tpShift = tStep * tpSpace;
1761 // //REAL8 periodShift = pStep * periodSpace;
1762 // REAL8 argBessel = 2 * LAL_PI * minFreq * asiniShift;
1763 // /* Number of sidebands is 1 + 2*(2*pi*f0*asini)*/
1764 // INT4 oneSidedNsidebands = (INT4)floor(argBessel);
1765 // if ( (UINT4)oneSidedNsidebands > nTermsMax){
1766 // fprintf(stdout, "Warning! large number of sidebands! Is this the right part of space?\n");
1767 // }
1768 // INT4 nSidebands = 1 + 2 * oneSidedNsidebands;
1769 // /* Orbital phase shift */
1770 // REAL8 orbitalPhaseShift = fmod( (2 * LAL_PI)/(nominalPeriod) * (nominalTp), 2 * LAL_PI );
1771 //
1772 // /* For reference */
1773 // //REAL8 f_k = (offset_bins2L + (UINT4)floor(k*DedecimateFFT2L)) * dFreqFFT2L+0.0;
1774 // //REAL8 cycles = - (f_k) * (dtauX2L - dtauX1K); /* Back to usual FFT trick */
1775 // //REAL4 sinphase, cosphase;
1776 // //XLALSinCos2PiLUT ( &sinphase, &cosphase, cycles );
1777 // //COMPLEX8 normX_k = dt_SRC * crectf ( cosphase, sinphase );
1778 //
1779 // INT4 sidebandIndex;
1780 // REAL8 cycles;
1781 // REAL8Vector *besselCoeffs = NULL;
1782 // XLAL_CHECK ( (besselCoeffs = XLALCreateREAL8Vector ( nSidebands )) != NULL, XLAL_EFUNC );
1783 // for ( INT4 j = 0; j < nSidebands; j++){
1784 // /* Wrap argBessel in J_s to get true filter coefficients */
1785 // /* Note that J_s has s = (j - oneSidedNsidebands), it this notation */
1786 // /* TECHNICALLY, this should depend on the frequency too */
1787 // besselCoeffs->data[j] = argBessel;
1788 // }
1789 // COMPLEX8Vector *shiftsInPhase = NULL;
1790 // REAL4 sinphase, cosphase;
1791 // XLAL_CHECK ( (shiftsInPhase = XLALCreateCOMPLEX8Vector ( nSidebands )) != NULL, XLAL_EFUNC );
1792 // for ( INT4 j = 0; j < nSidebands; j++){
1793 // sidebandIndex = j - oneSidedNsidebands;
1794 // cycles = sidebandIndex * orbitalPhaseShift;
1795 // XLALSinCos2PiLUT ( &sinphase, &cosphase, cycles );
1796 // shiftsInPhase->data[j] = crectf( cosphase, sinphase );
1797 // }
1798 //
1799 //
1800 // //fprintf(stdout, "nSidebands, tpShift, periodShift: %u, %f, %f\n", nSidebands, tpShift, periodShift);
1801 // //fprintf(stdout, "nSidebands, argBessel, orbitalPhaseShift: %u, %f, %f\n", nSidebands, argBessel, orbitalPhaseShift);
1802 // //fprintf(stdout, "nSidebands, besselCoeffs, cycles: %u, %f, %f\n", nSidebands, besselCoeffs->data[0], cycles);
1803 // fprintf(stdout, "nSidebands, besselCoeffs, shiftsInPhase: %u, %f, %f\n", nSidebands, besselCoeffs->data[0], cimag(shiftsInPhase->data[0]));
1804 // //fprintf(stdout, "asini, spacing: %f, %f\n", asiniPos, asiniSpace);
1805 // /* More complex test */
1806 // //COMPLEX8 partialSumK = 0;
1807 // INT4 edgeOfSidebands = 0;
1808 // //INT4 localNsidebands = 0;
1809 // INT4 diffInEdge = 0;
1810 // for ( INT4 k = 0; k < nFFT; k++ )
1811 // {
1812 // //COMPLEX8 normX_k = 1.0 ;
1813 // //besselFX_k[k] = normX_k * xTildeIn[k];
1814 // /* start bessel application */
1815 // edgeOfSidebands = MYMIN(k, oneSidedNsidebands);
1816 // diffInEdge = oneSidedNsidebands - edgeOfSidebands;
1817 // //localNsidebands = MYMIN(2*edgeOfSidebands+1, nSidebands);
1818 // for ( INT4 j = 0; j < nSidebands; j++){
1819 // sidebandIndex = j - edgeOfSidebands;
1820 // /* May need to take frequency spacing into account very soon*/
1821 // //fprintf(stdout, "diffInEdge!: %i\n", diffInEdge);
1822 // besselFX_k[k] += besselCoeffs->data[j+diffInEdge] * xTildeIn[k+sidebandIndex] * shiftsInPhase->data[j+diffInEdge];
1823 // }
1824 // /* end bessel application */
1825 // //if (k == nFFT-1){
1826 // // fprintf(stdout, "Made it!\n");
1827 // //}
1828 // } // for k < nFFT
1829 //
1830 //
1831 // /* for testing */
1832 // //xTildeOut = xTildeIn;
1833 // memcpy (xTildeOut, besselFX_k, nFFT * sizeof(COMPLEX8));
1834 // //for ( INT4 l = 0; l < nFFT; l++ )
1835 // //{
1836 // // xTildeOut[l] = besselFX_k[l];
1837 // //}
1838 // free (besselFX_k);
1839 // XLALDestroyREAL8Vector(besselCoeffs);
1840 // XLALDestroyCOMPLEX8Vector(shiftsInPhase);
1841 // return XLAL_SUCCESS;
1842 //} // XLALBesselCrossCorrOrbitalSpaceStep
1843 
1844 /** Function to extract timestamps with tShort */
1847  REAL8TimeSeries **sciFlag, /**< [out] science or not flag */
1848  const SFTVector *sfts, /**< [in] input SFT-vector */
1849  REAL8 tShort, /**< [in] new time baseline, Tshort */
1850  UINT4 numShortPerDet /**< [in] number of Tshort per detector */
1851 )
1852 {
1853 
1854  REAL8TimeSeries *retFlag = NULL;
1855  /* check input consistency */
1856  if ( !sfts ) {
1857  XLALPrintError( "%s: invalid NULL input 'sfts'\n", __func__ );
1859  }
1860 
1861  UINT4 numSFTsNew = numShortPerDet;
1862  /* create output vector */
1863  LIGOTimeGPSVector *ret = NULL;
1864  if ( ( ret = XLALCreateTimestampVector( numSFTsNew ) ) == NULL ) {
1865  XLALPrintError( "%s: XLALCreateTimestampVector(%d) failed.\n", __func__, numSFTsNew );
1867  }
1868  ret->deltaT = tShort;
1869  ret->length = numSFTsNew;
1870 
1871  UINT4 i;
1872  LIGOTimeGPS epochHolder = {0, 0};
1873  LIGOTimeGPS naiveEpoch = sfts->data[0].epoch;
1874  REAL8 naiveEpochReal = XLALGPSGetREAL8( &( naiveEpoch ) );
1875  /* Wanting a consistent baseline, calculate this externally */
1876  for ( i = 0; i < numShortPerDet; i ++ ) {
1877  epochHolder.gpsSeconds = 0;
1878  epochHolder.gpsNanoSeconds = 0;
1879  XLALGPSAdd( &( epochHolder ), naiveEpochReal );
1880  XLALGPSAdd( &( epochHolder ), i * tShort );
1881  ret->data[i] = epochHolder;
1882  }
1883 
1884  retFlag = XLALCrossCorrGapFinderResampAlt( ret, sfts );
1885  /* done: return Ts-vector */
1886  ( *sciFlag ) = retFlag;
1887  return ret;
1888 
1889 } /* XLALExtractTimestampsFromSFTsShort() */
1890 
1891 /** Modify timestamps from one detector with tShort */
1894  REAL8TimeSeries **sciFlag, /**< [out] science or not flag */
1895  const LIGOTimeGPSVector *restrict Times, /**< [in] input SFT-vector */
1896  const REAL8 tShort, /**< [in] new time baseline, Tshort */
1897  const UINT4 numShortPerDet /**< [in] number of Tshort per detector */
1898 )
1899 {
1900 
1901  REAL8TimeSeries *retFlag = NULL;
1902  /* check input consistency */
1903  if ( !Times ) {
1904  XLALPrintError( "%s: invalid NULL input 'Times'\n", __func__ );
1906  }
1907 
1908  UINT4 numSFTsNew = numShortPerDet;
1909  /* create output vector */
1910  LIGOTimeGPSVector *ret = NULL;
1911  if ( ( ret = XLALCreateTimestampVector( numSFTsNew ) ) == NULL ) {
1912  XLALPrintError( "%s: XLALCreateTimestampVector(%d) failed.\n", __func__, numSFTsNew );
1914  }
1915  ret->deltaT = tShort;
1916  ret->length = numSFTsNew;
1917 
1918  UINT4 i;
1919  LIGOTimeGPS epochHolder = {0, 0};
1920  LIGOTimeGPS naiveEpoch = Times->data[0];
1921  REAL8 naiveEpochReal = XLALGPSGetREAL8( &( naiveEpoch ) );
1922  /* Wanting a consistent baseline, calculate this externally */
1923  for ( i = 0; i < numShortPerDet; i ++ ) {
1924  epochHolder.gpsSeconds = 0;
1925  epochHolder.gpsNanoSeconds = 0;
1926  XLALGPSAdd( &( epochHolder ), naiveEpochReal );
1927  XLALGPSAdd( &( epochHolder ), i * tShort );
1928  ret->data[i] = epochHolder;
1929  }
1930  retFlag = XLALCrossCorrGapFinderResamp( ret, Times );
1931  /* done: return Ts-vector */
1932  ( *sciFlag ) = retFlag;
1933  return ret;
1934 
1935 } /* XLALModifyTimestampsFromSFTsShort() */
1936 
1937 /**
1938  * Given a multi-SFT vector, return a MultiLIGOTimeGPSVector holding the
1939  * modified SFT timestamps (production function using tShort)
1940  */
1943  MultiREAL8TimeSeries **scienceFlagVect, /**< [out] science flag vector */
1944  const MultiLIGOTimeGPSVector *restrict multiTimes, /**< [in] multiTimes, standard */
1945  const REAL8 tShort, /**< [in] new time baseline, Tshort */
1946  const UINT4 numShortPerDet /**< [in] number of Tshort per detector */
1947 )
1948 {
1949 
1950  MultiREAL8TimeSeries *retFlagVect = NULL;
1951  /* check input consistency */
1952  if ( !multiTimes || multiTimes->length == 0 ) {
1953  XLALPrintError( "%s: illegal NULL or empty input 'multiTimes'.\n", __func__ );
1955  }
1956  UINT4 numIFOs = multiTimes->length;
1957 
1958  /* create output vector */
1959  MultiLIGOTimeGPSVector *ret = NULL;
1960  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
1961  XLALPrintError( "%s: failed to XLALCalloc ( 1, %zu ).\n", __func__, sizeof( *ret ) );
1963  }
1964 
1965  if ( ( ret->data = XLALCalloc( numIFOs, sizeof( *ret->data ) ) ) == NULL ) {
1966  XLALPrintError( "%s: failed to XLALCalloc ( %d, %zu ).\n", __func__, numIFOs, sizeof( ret->data[0] ) );
1967  XLALFree( ret );
1969  }
1970  ret->length = numIFOs;
1971 
1972  /* new: duplicate above for the science flag vector */
1973  if ( ( retFlagVect = XLALCalloc( 1, sizeof( *retFlagVect ) ) ) == NULL ) {
1974  XLALPrintError( "%s: failed to XLALCalloc ( 1, %zu ).\n", __func__, sizeof( *retFlagVect ) );
1976  }
1977 
1978  if ( ( retFlagVect->data = XLALCalloc( numIFOs, sizeof( *retFlagVect->data ) ) ) == NULL ) {
1979  XLALPrintError( "%s: failed to XLALCalloc ( %d, %zu ).\n", __func__, numIFOs, sizeof( retFlagVect->data[0] ) );
1980  XLALFree( retFlagVect );
1982  }
1983  retFlagVect->length = numIFOs;
1984 
1985  /* now extract timestamps vector from each SFT-vector */
1986  UINT4 X;
1987  for ( X = 0; X < numIFOs; X ++ ) {
1988  if ( ( ret->data[X] = XLALModifyTimestampsFromSFTsShort( &retFlagVect->data[X], multiTimes->data[X], tShort, numShortPerDet ) ) == NULL ) {
1989  XLALPrintError( "%s: XLALExtractTimestampsFromSFTs() failed for X=%d\n", __func__, X );
1992  }
1993 
1994  } /* for X < numIFOs */
1995 
1996  ( *scienceFlagVect ) = retFlagVect;
1997  return ret;
1998 
1999 } /* XLALModifyMultiTimestampsFromSFTsShort() */
2000 
2001 /**
2002  * Given a multi-SFT vector, return a MultiLIGOTimeGPSVector holding the
2003  * SFT timestamps (test function using tShort)
2004  */
2007  MultiREAL8TimeSeries **scienceFlagVect, /**< [out] science flag vector */
2008  const MultiSFTVector *multiSFTs, /**< [in] multiSFT vector */
2009  REAL8 tShort, /**< [in] new time baseline, Tshort */
2010  UINT4 numShortPerDet /**< [in] number of Tshort per detector */
2011 )
2012 {
2013 
2014  MultiREAL8TimeSeries *retFlagVect = NULL;
2015  /* check input consistency */
2016  if ( !multiSFTs || multiSFTs->length == 0 ) {
2017  XLALPrintError( "%s: illegal NULL or empty input 'multiSFTs'.\n", __func__ );
2019  }
2020  UINT4 numIFOs = multiSFTs->length;
2021 
2022  /* create output vector */
2023  MultiLIGOTimeGPSVector *ret = NULL;
2024  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
2025  XLALPrintError( "%s: failed to XLALCalloc ( 1, %zu ).\n", __func__, sizeof( *ret ) );
2027  }
2028 
2029  if ( ( ret->data = XLALCalloc( numIFOs, sizeof( *ret->data ) ) ) == NULL ) {
2030  XLALPrintError( "%s: failed to XLALCalloc ( %d, %zu ).\n", __func__, numIFOs, sizeof( ret->data[0] ) );
2031  XLALFree( ret );
2033  }
2034  ret->length = numIFOs;
2035 
2036  /* new: duplicate above for the science flag vector */
2037  if ( ( retFlagVect = XLALCalloc( 1, sizeof( *retFlagVect ) ) ) == NULL ) {
2038  XLALPrintError( "%s: failed to XLALCalloc ( 1, %zu ).\n", __func__, sizeof( *retFlagVect ) );
2040  }
2041 
2042  if ( ( retFlagVect->data = XLALCalloc( numIFOs, sizeof( *retFlagVect->data ) ) ) == NULL ) {
2043  XLALPrintError( "%s: failed to XLALCalloc ( %d, %zu ).\n", __func__, numIFOs, sizeof( retFlagVect->data[0] ) );
2044  XLALFree( retFlagVect );
2046  }
2047  retFlagVect->length = numIFOs;
2048 
2049  /* now extract timestamps vector from each SFT-vector */
2050  UINT4 X;
2051  for ( X = 0; X < numIFOs; X ++ ) {
2052 
2053  if ( ( ret->data[X] = XLALExtractTimestampsFromSFTsShort( &retFlagVect->data[X], multiSFTs->data[X], tShort, numShortPerDet ) ) == NULL ) {
2054  XLALPrintError( "%s: XLALExtractTimestampsFromSFTsShort() failed for X=%d\n", __func__, X );
2057  }
2058 
2059  } /* for X < numIFOs */
2060 
2061  ( *scienceFlagVect ) = retFlagVect;
2062  return ret;
2063 
2064 } /* XLALExtractMultiTimestampsFromSFTsShort() */
2065 
2066 /** (test function) fill detector state with tShort, importing various slightly-modified LALPulsar functions for testing */
2067 int
2068 XLALFillDetectorTensorShort( DetectorState *detState, /**< [out,in]: detector state: fill in detector-tensor */
2069  const LALDetector *detector /**< [in]: which detector */
2070  )
2071 {
2072  const CHAR *prefix;
2073 
2074  if ( !detState || !detector ) {
2076  return -1;
2077  }
2078 
2079  prefix = detector->frDetector.prefix;
2080 
2081  /* we need to distinguish two cases: space-borne (i.e. LISA) and Earth-based detectors */
2082  if ( prefix[0] == 'Z' ) { /* LISA */
2083  //if ( XLALprecomputeLISAarms ( detState ) != 0 ) {
2084  // XLALPrintError ("\nXLALprecomputeLISAarms() failed !\n\n");
2085  // xlalErrno = XLAL_EINVAL;
2086  // return -1;
2087  //}
2088  //
2089  //if ( XLALgetLISADetectorTensorLWL ( &(detState->detT), detState->detArms, prefix[1] ) != 0 ) {
2090  // XLALPrintError ("\nXLALgetLISADetectorTensorLWL() failed !\n\n");
2091  // xlalErrno = XLAL_EINVAL;
2092  // return -1;
2093  //}
2094 
2095  } /* if LISA */
2096  else {
2097  REAL4 sinG, cosG, sinGcosG, sinGsinG, cosGcosG;
2098  SymmTensor3 *detT = &( detState->detT );
2099 
2100  XLAL_CHECK( XLALSinCosLUT( &sinG, &cosG, detState->earthState.gmstRad ) == XLAL_SUCCESS, XLAL_EFUNC );
2101  sinGsinG = sinG * sinG;
2102  sinGcosG = sinG * cosG;
2103  cosGcosG = cosG * cosG;
2104 
2105  /*
2106  printf("GMST = %fdeg; cosG = %f, sinG= %f\n",
2107  LAL_180_PI * atan2(sinG,cosG), cosG, sinG);
2108  */
2109 
2110  detT->d11 = detector->response[0][0] * cosGcosG
2111  - 2 * detector->response[0][1] * sinGcosG
2112  + detector->response[1][1] * sinGsinG;
2113  detT->d22 = detector->response[0][0] * sinGsinG
2114  + 2 * detector->response[0][1] * sinGcosG
2115  + detector->response[1][1] * cosGcosG;
2116  detT->d12 = ( detector->response[0][0] - detector->response[1][1] )
2117  * sinGcosG
2118  + detector->response[0][1] * ( cosGcosG - sinGsinG );
2119  detT->d13 = detector->response[0][2] * cosG
2120  - detector->response[1][2] * sinG;
2121  detT->d23 = detector->response[0][2] * sinG
2122  + detector->response[1][2] * cosG;
2123  detT->d33 = detector->response[2][2];
2124 
2125  /*
2126  printf("d = (%f %f %f\n",detT->d11,detT->d12,detT->d13);
2127  printf(" %f %f %f\n",detT->d12,detT->d22,detT->d23);
2128  printf(" %f %f %f)\n",detT->d13,detT->d23,detT->d33);
2129 
2130  printf("d*= (%f %f %f\n",detector->response[0][0],
2131  detector->response[0][1],detector->response[0][2]);
2132  printf(" %f %f %f\n",detector->response[1][0],
2133  detector->response[1][1],detector->response[1][2]);
2134  printf(" %f %f %f)\n",detector->response[2][0],
2135  detector->response[2][1],detector->response[2][2]);
2136  */
2137 
2138  } /* if Earth-based */
2139 
2140  return 0;
2141 
2142 } /* XLALFillDetectorTensorShort() */
2143 
2144 /** (test function) get detector states for tShort */
2146 XLALGetDetectorStatesShort( const LIGOTimeGPSVector *timestamps, /**< array of GPS timestamps t_i */
2147  const LALDetector *detector, /**< detector info */
2148  const EphemerisData *edat, /**< ephemeris file data */
2149  REAL8 tOffset, /**< compute detector states at timestamps SHIFTED by tOffset */
2150  REAL8 tShort, /**< [in] new time baseline, Tshort */
2151  UINT4 numShortPerDet /**< [in] number of Tshort per detector */
2152  )
2153 {
2154  /* check input consistency */
2155  if ( !timestamps || !detector || !edat ) {
2156  XLALPrintError( "%s: invalid NULL input, timestamps=%p, detector=%p, edat=%p\n", __func__, timestamps, detector, edat );
2158  }
2159 
2160  /* prepare return vector */
2161  UINT4 numSteps = numShortPerDet;
2162  printf( "numSteps in GetDetectorStatesShort: %u\n", numSteps );
2163  DetectorStateSeries *ret = NULL;
2164  if ( ( ret = XLALCreateDetectorStateSeries( numSteps ) ) == NULL ) {
2165  XLALPrintError( "%s: XLALCreateDetectorStateSeries(%d) failed.\n", __func__, numSteps );
2167  }
2168 
2169  /* enter detector-info into the head of the state-vector */
2170  ret->detector = ( *detector );
2171 
2172  /* set 'time-span' associated with each timestamp */
2173  //ret->deltaT = timestamps->deltaT;
2174  ret->deltaT = tShort;
2175 
2176  /* set SSB coordinate system used: EQUATORIAL for Earth-based, ECLIPTIC for LISA */
2177  if ( detector->frDetector.prefix[0] == 'Z' ) { /* LISA */
2179  } else { /* Earth-based */
2181  }
2182 
2183  /* now fill all the vector-entries corresponding to different timestamps */
2184  UINT4 i;
2185  for ( i = 0; i < numSteps; i++ ) {
2186  BarycenterInput baryinput;
2187  EmissionTime emit;
2188  DetectorState *state = &( ret->data[i] );
2189  EarthState *earth = &( state->earthState );
2190  LIGOTimeGPS tgps;
2191 
2192  /* shift timestamp by tOffset */
2193  tgps = timestamps->data[i];
2194  XLALGPSAdd( &tgps, tOffset );
2195  /*----- first get earth-state */
2196  if ( XLALBarycenterEarth( earth, &tgps, edat ) != XLAL_SUCCESS ) {
2198  XLALPrintError( "%s: XLALBarycenterEarth() failed with xlalErrno=%d\n", __func__, xlalErrno );
2200  }
2201 
2202  /*----- then get detector-specific info */
2203  baryinput.tgps = tgps;
2204  baryinput.site = ( *detector );
2205  baryinput.site.location[0] /= LAL_C_SI;
2206  baryinput.site.location[1] /= LAL_C_SI;
2207  baryinput.site.location[2] /= LAL_C_SI;
2208  baryinput.alpha = baryinput.delta = 0; /* irrelevant */
2209  baryinput.dInv = 0;
2210 
2211  if ( XLALBarycenter( &emit, &baryinput, earth ) != XLAL_SUCCESS ) {
2213  XLALPrintError( "%s: XLALBarycenterEarth() failed with xlalErrno=%d\n", __func__, xlalErrno );
2215  }
2216 
2217  /*----- extract the output-data from this */
2218  UINT4 j;
2219  for ( j = 0; j < 3; j++ ) { /* copy detector's position and velocity */
2220  state->rDetector[j] = emit.rDetector[j];
2221  state->vDetector[j] = emit.vDetector[j];
2222  } /* for j < 3 */
2223 
2224  /* local mean sidereal time = GMST + longitude */
2225  state->LMST = earth->gmstRad + detector->frDetector.vertexLongitudeRadians;
2226  state->LMST = fmod( state->LMST, LAL_TWOPI ); /* normalize */
2227 
2228  /* insert timestamp */
2229  state->tGPS = tgps;
2230 
2231  /* compute the detector-tensor at this time-stamp in SSB-fixed Cartesian coordinates
2232  * [EQUATORIAL for Earth-based, ECLIPTIC for LISA]
2233  */
2234  /* XLALFillDetectorTensorShort should be identical to non-short
2235  version, simply a copy because non-short was inaccessible
2236  without editing header files (i.e., it is internal to other file) */
2237  if ( XLALFillDetectorTensorShort( state, detector ) != 0 ) {
2239  XLALPrintError( "%s: XLALFillDetectorTensorShort() failed ... errno = %d\n\n", __func__, xlalErrno );
2241  }
2242 
2243  } /* for i < numSteps */
2244 
2245  /* return result */
2246  return ret;
2247 
2248 } /* XLALGetDetectorStatesShort() */
2249 
2250 /** (test function) get multi detector states for tShort */
2252 XLALGetMultiDetectorStatesShort( const MultiLIGOTimeGPSVector *multiTS, /**< [in] multi-IFO timestamps */
2253  const MultiLALDetector *multiIFO, /**< [in] multi-IFO array holding detector info */
2254  const EphemerisData *edat, /**< [in] ephemeris data */
2255  REAL8 tOffset, /**< [in] shift all timestamps by this amount */
2256  REAL8 tShort, /**< [in] new time baseline, Tshort */
2257  UINT4 numShortPerDet /**< [in] number of Tshort segments per detector */
2258  )
2259 {
2260  /* check input consistency */
2261  if ( !multiIFO || !multiTS || !edat ) {
2262  XLALPrintError( "%s: invalid NULL input (multiIFO=%p, multiTS=%p or edat=%p)\n", __func__, multiIFO, multiTS, edat );
2264  }
2265 
2267  numDetectors = multiIFO->length;
2268  if ( numDetectors != multiTS->length ) {
2269  XLALPrintError( "%s: inconsistent number of IFOs in 'multiIFO' (%d) and 'multiTS' (%d)\n", __func__, multiIFO->length, multiTS->length );
2271  }
2272 
2273  /* prepare return-structure */
2274  MultiDetectorStateSeries *ret = NULL;
2275  if ( ( ret = LALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
2276  XLALPrintError( "%s: LALCalloc ( 1, %zu ) failed\n", __func__, sizeof( *ret ) );
2278  }
2279  if ( ( ret->data = LALCalloc( numDetectors, sizeof( *( ret->data ) ) ) ) == NULL ) {
2280  XLALFree( ret );
2281  XLALPrintError( "%s: LALCalloc ( %d, %zu ) failed\n", __func__, numDetectors, sizeof( *( ret->data ) ) );
2283  }
2284  ret->length = numDetectors;
2285 
2287  REAL8 t1 = 0;
2288  //REAL8 deltaT = tShort;
2289  //LIGOTimeGPS startTime = {0, 0};
2290  /* loop over detectors */
2291  UINT4 X;
2292  for ( X = 0; X < numDetectors; X ++ ) {
2293  LIGOTimeGPSVector *tsX = multiTS->data[X];
2294  const LALDetector *detX = &( multiIFO->sites[X] );
2295 
2296  if ( !tsX || !detX ) {
2297  XLALPrintError( "%s: invalid NULL data-vector tsX[%d] = %p, detX[%d] = %p\n", __func__, X, tsX, X, detX );
2299  }
2300 
2301  /* fill in the detector-state series for this detector */
2302  if ( ( ret->data[X] = XLALGetDetectorStatesShort( tsX, detX, edat, tOffset, tShort, numShortPerDet ) ) == NULL ) {
2303  XLALPrintError( "%s: XLALGetDetectorStates() failed.\n", __func__ );
2305  }
2306 
2307  /* keep track of earliest/latest timestamp in order to determine total Tspan */
2308  /* This remains very close to true even with Tshort */
2309  UINT4 numTS = tsX->length;
2310  REAL8 t0_X = XLALGPSGetREAL8( &tsX->data[0] );
2311  REAL8 t1_X = XLALGPSGetREAL8( &tsX->data[numTS - 1] );
2312 
2313  if ( t0_X < t0 ) {
2314  t0 = t0_X;
2315  //startTime = tsX->data[0];
2316  }
2317  if ( t1_X > t1 ) {
2318  t1 = t1_X;
2319  }
2320 
2321  } /* for X < numDetectors */
2322 
2323  //ret->Tspan = t1 - t0 + deltaT; /* total time spanned by all SFTs */
2324  //ret->startTime = startTime; /* earliest start-time of observation */
2325 
2326  return ret;
2327 
2328 } /* XLALGetMultiDetectorStatesShort() */
2329 
2330 
2331 /** Modify amplitude weight coefficients for tShort */
2332 int
2334  REAL8Vector **resampMultiWeightsX, /**< [out] new weights */
2335  const MultiNoiseWeights *restrict multiWeights, /**< [in] old weights */
2336  const REAL8 tShort, /**< [in] new time baseline, Tshort */
2337  const REAL8 tSFTOld, /**< [in] old time baseline, tSFTOld */
2338  const UINT4 numShortPerDet, /**< [in] number of tShort segments per detector */
2339  const MultiLIGOTimeGPSVector *restrict multiTimes, /**< [in] multi-times vector to tell us when the SFTs were */
2340  const UINT4 maxNumStepsOldIfGapless, /**< [in] how many SFTs there would be without gaps */
2341  const UINT4 X /**< [in] detector number */
2342 )
2343 {
2344  REAL8Vector *ret = NULL;
2345  UINT4 numStepsXNew = numShortPerDet;
2346  COMPLEX8Vector *newWeightsX = NULL;
2347  REAL8Vector *newWeightStamps = NULL;
2348  REAL8Vector *newWeightsXReal = NULL;
2349 
2350  XLAL_CHECK( ( newWeightsXReal = XLALCreateREAL8Vector( numStepsXNew ) ) != NULL, XLAL_EFUNC );
2351  XLAL_CHECK( ( newWeightsX = XLALCreateCOMPLEX8Vector( numStepsXNew ) ) != NULL, XLAL_EFUNC );
2352  XLAL_CHECK( ( newWeightStamps = XLALCreateREAL8Vector( numStepsXNew ) ) != NULL, XLAL_EFUNC );
2353  COMPLEX8TimeSeries *oldTSWeightsX = NULL;
2354 
2355  for ( UINT4 alphaFuture = 0; alphaFuture < numStepsXNew; alphaFuture++ ) {
2356  newWeightStamps->data[alphaFuture] = alphaFuture * tShort;
2357  }
2358  REAL8Vector *weightsX = multiWeights->data[X];
2359  LIGOTimeGPS weightEpoch = {0, 0};
2360  /* The idea: we are going to sinc interpolate to find what the
2361  * weights should be for the coefficients. However, we need to
2362  * first make the old weights, in weightsX, into an evenly-sampled
2363  * series, with zeroes filling any gaps. That is oldTSWeightX. We
2364  * then can interpolate oldTSWeightX into newWeightsX, with
2365  * spacing according to tShort instead of tSFTOld. */
2366  oldTSWeightsX = XLALCreateCOMPLEX8TimeSeries( "old TS weights", &weightEpoch, 0, tSFTOld, &lalDimensionlessUnit, maxNumStepsOldIfGapless );
2367  UINT4 jj = 0;
2368  REAL8 tAlpha = 0;
2369  REAL8 tAlphaOldWithGaps = 0;
2370  /* The for-loop is over alphaLoad, an index at a cadence of the
2371  * old SFTs, as if they did not have gaps */
2372  for ( UINT4 alphaLoad = 0; alphaLoad < maxNumStepsOldIfGapless; alphaLoad++ ) {
2373  /* tAlpha is the time in this gapless sequence*/
2374  tAlpha = alphaLoad * tSFTOld;
2375  /* tAlphaOldWithGaps is the actual SFT time from timestamps */
2376  tAlphaOldWithGaps = XLALGPSDiff( &( multiTimes->data[X]->data[jj] ), &( multiTimes->data[X]->data[0] ) );
2377  for ( UINT4 kk = jj; kk < multiTimes->data[X]->length ; kk++ ) {
2378  /* Will overshoot gap to next SFT when reached */
2379  tAlphaOldWithGaps = XLALGPSDiff( &( multiTimes->data[X]->data[kk] ), &( multiTimes->data[X]->data[0] ) );
2380  if ( tAlphaOldWithGaps <= tAlpha ) {
2381  /* In this branch if we are at least the time of first old SFT */
2382  jj = kk;
2383  } else {
2384  /* in this branch, we do not match any old sfts */
2385  break;
2386  }
2387  if ( ( tAlpha - tAlphaOldWithGaps ) < tSFTOld ) {
2388  /* Standard progression without gaps, assuming constant cadence */
2389  oldTSWeightsX->data->data[alphaLoad] = weightsX->data[jj] + 0.0 * I;
2390  } else {
2391  /* in this branch, we do not match match the next sft:
2392  * probably there was a gap */
2393  oldTSWeightsX->data->data[alphaLoad] = 0.0 + 0.0 * I;
2394  }
2395  } // for kk
2396  } // for alphaLoad
2397  XLAL_CHECK( XLALSincInterpolateCOMPLEX8TimeSeries( newWeightsX, newWeightStamps, oldTSWeightsX, 8 ) == XLAL_SUCCESS, XLAL_EFUNC );
2398  /* Note that this above sequence differs from that in the
2399  * timestamps, because here we simply transcribed the old weights
2400  * into a zero-padded sequence at the same cadence and used the
2401  * sinc interpolation to do the heavy-lifting into the new
2402  * timeseries at new cadence. In the timestamps, we were creating,
2403  * in effect, a Boolean sequence in the next time series from
2404  * branch checks alone, with no sinc interpolation. */
2405  for ( UINT4 alphaReal = 0; alphaReal < numStepsXNew; alphaReal++ ) {
2406  /* Weights must never be negative or else next loop yields nans*/
2407  newWeightsXReal->data[alphaReal] = MYMAX( 0, creal( newWeightsX->data[alphaReal] ) );
2408  }
2409  ret = newWeightsXReal;
2410  XLALDestroyCOMPLEX8TimeSeries( oldTSWeightsX );
2411  XLALDestroyCOMPLEX8Vector( newWeightsX );
2412  XLALDestroyREAL8Vector( newWeightStamps );
2413  ( *resampMultiWeightsX ) = ret;
2414  return XLAL_SUCCESS;
2415 } // XLALModifyAMCoeffsWeights
2416 
2417 
2418 /** Modify multiple detectors' amplitude weight coefficients for tShort */
2419 int
2421  MultiNoiseWeights **multiWeights, /**< [in/out] old and new weights */
2422  const REAL8 tShort, /**< [in] new time baseline, Tshort */
2423  const REAL8 tSFTOld, /**< [in] old time baseline, tSFTOld */
2424  const UINT4 numShortPerDet, /**< [in] number of tShort segments per detector */
2425  const MultiLIGOTimeGPSVector *restrict multiTimes /**< [in] multi-times vector to tell us when the SFTs were */
2426 )
2427 {
2428 
2429  /* ----- input sanity checks ----- */
2430  MultiNoiseWeights *multiWeightsLocal = ( *multiWeights );
2431  UINT4 numDetectors = multiWeightsLocal->length;
2432  UINT4 numIFOs = numDetectors;
2433 
2434  REAL8 ratioSFTs = tShort / tSFTOld;
2435 
2436  /* Prepare output values */
2437  /* create multi noise weights for output */
2438 
2439  MultiNoiseWeights *ret = NULL;
2440  XLAL_CHECK( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) != NULL, XLAL_EFUNC );
2441  XLAL_CHECK( ( ret->data = XLALCalloc( numIFOs, sizeof( *ret->data ) ) ) != NULL, XLAL_EFUNC );
2442  ret->length = numIFOs;
2443  /* As documented for MultiNoiseWeights, the S inv Tsft field is a
2444  * normalization factor equal to S^(-1) Tsft. Since we changed the
2445  * effective Tsft from Tsft to Tshort = ratioSFTs*Tsft, we also
2446  * need to multiply this normalization factor by ratioSFTs. */
2447  ret->Sinv_Tsft = multiWeightsLocal->Sinv_Tsft * ratioSFTs;
2448 
2449  REAL8 Tobs = numShortPerDet * tShort;
2450  UINT4 maxNumStepsOldIfGapless = lround( Tobs / tSFTOld );
2451 
2452  /* ---------- main loop over detectors X ---------- */
2453  UINT4 X;
2454 
2455  for ( X = 0; X < numDetectors; X ++ ) {
2456  XLALModifyAMCoeffsWeights( &ret->data[X], multiWeightsLocal, tShort, tSFTOld, numShortPerDet, multiTimes, maxNumStepsOldIfGapless, X );
2457  }
2458 
2459  XLALDestroyMultiNoiseWeights( ( *multiWeights ) );
2460  ( *multiWeights ) = ret;
2461  return XLAL_SUCCESS;
2462 
2463 } /* XLALModifyMultiAMCoeffsWeights() */
2464 
2465 
2466 /** (test function) used for weighting multi amplitude modulation coefficients */
2467 int
2469  MultiAMCoeffs *multiAMcoef, /**< [in/out] amplitude coefficients */
2470  const MultiNoiseWeights *multiWeights, /**< [in/out] weights */
2471  REAL8 tShort, /**< [in] new time baseline, Tshort */
2472  REAL8 tSFTOld, /**< [in] old time baseline, tSFTOld */
2473  UINT4 numShortPerDet, /**< [in] number of tShort segments per detector */
2474  MultiLIGOTimeGPSVector *multiTimes /**< [in] multi-times vector to tell us when the SFTs were */
2475 )
2476 {
2477 
2478  /* ----- input sanity checks ----- */
2479  if ( !multiAMcoef ) {
2480  XLALPrintError( "%s: illegal NULL input received in 'multiAMcoefs'.\n", __func__ );
2482  }
2483  UINT4 numDetectors = multiAMcoef->length;
2484  /* make sure identical number of detectors in amCoefs and weights */
2485  if ( multiWeights && ( multiWeights->length != numDetectors ) ) {
2486  XLALPrintError( "%s: multiWeights must be NULL or have the same number of detectors (numDet=%d) as mulitAMcoef (numDet=%d)!\n", __func__, multiWeights->length, numDetectors );
2488  }
2489 
2490  REAL8 ratioSFTs = tShort / tSFTOld;
2491 
2492  REAL4 Ad = 0, Bd = 0, Cd = 0; // multi-IFO values
2493 
2494  REAL8 Tobs = numShortPerDet * tShort;
2495  UINT4 maxNumStepsOldIfGapless = lround( Tobs / tSFTOld );
2496 
2497  /* ---------- main loop over detectors X ---------- */
2498  UINT4 X;
2499  for ( X = 0; X < numDetectors; X ++ ) {
2500  AMCoeffs *amcoeX = multiAMcoef->data[X];
2501  UINT4 numStepsXNew = numShortPerDet;
2502  if ( multiWeights ) {
2503  COMPLEX8Vector *newWeightsX = NULL;
2504  REAL8Vector *newWeightStamps = NULL;
2505  REAL8Vector *newWeightsXReal = NULL;
2506  XLAL_CHECK( ( newWeightsXReal = XLALCreateREAL8Vector( numStepsXNew ) ) != NULL, XLAL_EFUNC );
2507  XLAL_CHECK( ( newWeightsX = XLALCreateCOMPLEX8Vector( numStepsXNew ) ) != NULL, XLAL_EFUNC );
2508  XLAL_CHECK( ( newWeightStamps = XLALCreateREAL8Vector( numStepsXNew ) ) != NULL, XLAL_EFUNC );
2509  for ( UINT4 alphaFuture = 0; alphaFuture < numStepsXNew; alphaFuture++ ) {
2510  newWeightStamps->data[alphaFuture] = alphaFuture * tShort;
2511  }
2512  REAL8Vector *weightsX = multiWeights->data[X];
2513  COMPLEX8TimeSeries *oldTSWeightsX = NULL;
2514  LIGOTimeGPS weightEpoch = {0, 0};
2515  /* The idea: we are going to sinc interpolate to find what the
2516  * weights should be for the coefficients. However, we need to
2517  * first make the old weights, in weightsX, into an evenly-sampled
2518  * series, with zeroes filling any gaps. That is oldTSWeightX. We
2519  * then can interpolate oldTSWeightX into newWeightsX, with
2520  * spacing according to tShort instead of tSFTOld. */
2521  oldTSWeightsX = XLALCreateCOMPLEX8TimeSeries( "old TS weights", &weightEpoch, 0, tSFTOld, &lalDimensionlessUnit, maxNumStepsOldIfGapless );
2522  UINT4 jj = 0;
2523  REAL8 tAlpha = 0;
2524  REAL8 tAlphaOldWithGaps = 0;
2525  /* The for-loop is over alphaLoad, an index at a cadence of the
2526  * old SFTs, as if they did not have gaps */
2527  for ( UINT4 alphaLoad = 0; alphaLoad < maxNumStepsOldIfGapless; alphaLoad++ ) {
2528  /* tAlpha is the time in this gapless sequence*/
2529  tAlpha = alphaLoad * tSFTOld;
2530  /* tAlphaOldWithGaps is the actual SFT time from timestamps */
2531  tAlphaOldWithGaps = XLALGPSDiff( &( multiTimes->data[X]->data[jj] ), &( multiTimes->data[X]->data[0] ) );
2532  for ( UINT4 kk = jj; kk < multiTimes->data[X]->length ; kk++ ) {
2533  /* Will overshoot gap to next SFT when reached */
2534  tAlphaOldWithGaps = XLALGPSDiff( &( multiTimes->data[X]->data[kk] ), &( multiTimes->data[X]->data[0] ) );
2535 
2536  if ( tAlphaOldWithGaps <= tAlpha ) {
2537  /* In this branch if we are at least the time of first old SFT */
2538  jj = kk;
2539  } else {
2540  /* in this branch, we do not match any old sfts */
2541  //oldTSWeightsX->data->data[alphaLoad] = 0.0 + 0.0*I;
2542  break;
2543  }
2544  if ( ( tAlpha - tAlphaOldWithGaps ) < tSFTOld ) {
2545  /* Standard progression without gaps, assuming constant cadence */
2546  oldTSWeightsX->data->data[alphaLoad] = weightsX->data[jj] + 0.0 * I;
2547  } else {
2548  /* in this branch, we do not match match the next sft:
2549  * probably there was a gap */
2550  oldTSWeightsX->data->data[alphaLoad] = 0.0 + 0.0 * I;
2551  }
2552  } // for kk
2553 
2554  } // for alphaLoad
2555  XLAL_CHECK( XLALSincInterpolateCOMPLEX8TimeSeries( newWeightsX, newWeightStamps, oldTSWeightsX, 8 ) == XLAL_SUCCESS, XLAL_EFUNC );
2556  /* Note that this above sequence differs from that in the
2557  * timestamps, because here we simply transcribed the old weights
2558  * into a zero-padded sequence at the same cadence and used the
2559  * sinc interpolation to do the heavy-lifting into the new
2560  * timeseries at new cadence. In the timestamps, we were creating,
2561  * in effect, a Boolean sequence in the next time series from
2562  * branch checks alone, with no sinc interpolation. */
2563 
2564  for ( UINT4 alphaReal = 0; alphaReal < numStepsXNew; alphaReal++ ) {
2565  /* Weights must never be negative or else next loop yields nans*/
2566  newWeightsXReal->data[alphaReal] = MYMAX( 0, creal( newWeightsX->data[alphaReal] ) );
2567  }
2568  UINT4 alpha;
2569  for ( alpha = 0; alpha < numStepsXNew; alpha++ ) {
2570  REAL8 Sqwi = sqrt( newWeightsXReal->data[alpha] );
2571  amcoeX->a->data[alpha] *= Sqwi;
2572  amcoeX->b->data[alpha] *= Sqwi;
2573  } // for alphaOld < numSteps
2574  XLALDestroyCOMPLEX8TimeSeries( oldTSWeightsX );
2575  XLALDestroyCOMPLEX8Vector( newWeightsX );
2576  XLALDestroyREAL8Vector( newWeightsXReal );
2577  XLALDestroyREAL8Vector( newWeightStamps );
2578  } // if weights
2579 
2580 
2581  UINT4 alpha; // SFT-index
2582  REAL4 AdX = 0, BdX = 0, CdX = 0; // single-IFO values
2583  /* compute single-IFO antenna-pattern coefficients AX,BX,CX, by summing over time-steps 'alpha' */
2584  for ( alpha = 0; alpha < numStepsXNew; alpha++ ) {
2585  REAL4 ahat = amcoeX->a->data[alpha];
2586  REAL4 bhat = amcoeX->b->data[alpha];
2587 
2588  AdX += ahat * ahat;
2589  BdX += bhat * bhat;
2590  CdX += ahat * bhat;
2591  //printf("Final alpha! %u\n", alpha);
2592  } /* for alpha < numStepsXNew */
2593 
2594  /* store those */
2595  amcoeX->A = AdX;
2596  amcoeX->B = BdX;
2597  amcoeX->C = CdX;
2598  amcoeX->D = AdX * BdX - CdX * CdX;
2599 
2600  // in the unlikely event of a degenerate M-matrix with D = det[A, C; C, B] <= 0,
2601  // we set D->inf, in order to set the corresponding F-value to zero rather than >>1
2602  // By setting 'D=inf', we also allow upstream catching/filtering on such singular cases
2603  if ( amcoeX->D <= 0 ) {
2604  amcoeX->D = INFINITY;
2605  }
2606  /* compute multi-IFO antenna-pattern coefficients A,B,C by summing over IFOs X */
2607  Ad += AdX;
2608  Bd += BdX;
2609  Cd += CdX;
2610 
2611  } /* for X < numDetectors */
2612  //printf("Final A, B, C, D: %f %f %f %f\n", Ad, Bd, Cd, Ad * Bd - Cd * Cd);
2613 
2614  multiAMcoef->Mmunu.Ad = Ad;
2615  multiAMcoef->Mmunu.Bd = Bd;
2616  multiAMcoef->Mmunu.Cd = Cd;
2617  multiAMcoef->Mmunu.Dd = Ad * Bd - Cd * Cd;
2618 
2619  // in the unlikely event of a degenerate M-matrix with D = det[A, C; C, B] <= 0,
2620  // we set D->inf, in order to set the corresponding F-value to zero rather than >>1
2621  // By setting 'D=inf', we also allow upstream catching/filtering on such singular cases
2622  if ( multiAMcoef->Mmunu.Dd <= 0 ) {
2623  multiAMcoef->Mmunu.Dd = INFINITY;
2624  }
2625 
2626 
2627  if ( multiWeights ) {
2628  //multiAMcoef->Mmunu.Sinv_Tsft = multiWeights->Sinv_Tsft;
2629  multiAMcoef->Mmunu.Sinv_Tsft = multiWeights->Sinv_Tsft * ratioSFTs;
2630  }
2631 
2632  return XLAL_SUCCESS;
2633 
2634 } /* XLALWeightMultiAMCoeffsShort() */
2635 
2636 /** (test function) used for computing amplitude modulation weights */
2637 AMCoeffs *
2638 XLALComputeAMCoeffsShort( const DetectorStateSeries *DetectorStates, /**< timeseries of detector states */
2639  SkyPosition skypos /**< {alpha,delta} of the source */
2640  )
2641 {
2642  /* ---------- check input consistency ---------- */
2643  if ( !DetectorStates ) {
2644  XLALPrintError( "%s: invalid NULL input 'DetectorStates'\n", __func__ );
2646  }
2647 
2648  /* currently requires sky-pos to be in equatorial coordinates (FIXME) */
2649  if ( skypos.system != COORDINATESYSTEM_EQUATORIAL ) {
2650  XLALPrintError( "%s: only equatorial coordinates currently supported in 'skypos'\n", __func__ );
2652  }
2653 
2654  /*---------- We write components of xi and eta vectors in SSB-fixed coords */
2655  REAL4 alpha = skypos.longitude;
2656  REAL4 delta = skypos.latitude;
2657 
2658  REAL4 sin1delta, cos1delta;
2659  REAL4 sin1alpha, cos1alpha;
2660  XLAL_CHECK_NULL( XLALSinCosLUT( &sin1delta, &cos1delta, delta ) == XLAL_SUCCESS, XLAL_EFUNC );
2661  XLAL_CHECK_NULL( XLALSinCosLUT( &sin1alpha, &cos1alpha, alpha ) == XLAL_SUCCESS, XLAL_EFUNC );
2662 
2663  REAL4 xi1 = - sin1alpha;
2664  REAL4 xi2 = cos1alpha;
2665  REAL4 eta1 = sin1delta * cos1alpha;
2666  REAL4 eta2 = sin1delta * sin1alpha;
2667  REAL4 eta3 = - cos1delta;
2668 
2669  /* prepare output vector */
2670  UINT4 numSteps = DetectorStates->length;
2671  //printf("numSteps in ComputeAMCoeffsShort: %u\n", numSteps);
2672  AMCoeffs *coeffs;
2673  if ( ( coeffs = XLALCreateAMCoeffs( numSteps ) ) == NULL ) {
2674  XLALPrintError( "%s: XLALCreateAMCoeffs(%d) failed\n", __func__, numSteps );
2676  }
2677 
2678  /*---------- Compute the a(t_i) and b(t_i) ---------- */
2679  UINT4 i;
2680  for ( i = 0; i < numSteps; i++ ) {
2681  REAL4 ai, bi;
2682 
2683  SymmTensor3 *d = &( DetectorStates->data[i].detT );
2684 
2685  ai = d->d11 * ( xi1 * xi1 - eta1 * eta1 )
2686  + 2 * d->d12 * ( xi1 * xi2 - eta1 * eta2 )
2687  - 2 * d->d13 * eta1 * eta3
2688  + d->d22 * ( xi2 * xi2 - eta2 * eta2 )
2689  - 2 * d->d23 * eta2 * eta3
2690  - d->d33 * eta3 * eta3;
2691 
2692  bi = d->d11 * 2 * xi1 * eta1
2693  + 2 * d->d12 * ( xi1 * eta2 + xi2 * eta1 )
2694  + 2 * d->d13 * xi1 * eta3
2695  + d->d22 * 2 * xi2 * eta2
2696  + 2 * d->d23 * xi2 * eta3;
2697 
2698  coeffs->a->data[i] = ai;
2699  coeffs->b->data[i] = bi;
2700  //printf("ai, bi: %f %f\n", ai, bi);
2701 
2702  } /* for i < numSteps */
2703 
2704  /* return the result */
2705  return coeffs;
2706 
2707 } /* XLALComputeAMCoeffsShort() */
2708 
2709 
2710 /** (test function) used for computing multi amplitude modulation weights */
2711 MultiAMCoeffs *
2713  const MultiDetectorStateSeries *multiDetStates, /**< [in] detector-states at timestamps t_i */
2714  const MultiNoiseWeights *multiWeights, /**< [in] noise-weights at timestamps t_i (can be NULL) */
2715  SkyPosition skypos, /**< source sky-position [in equatorial coords!] */
2716  REAL8 tShort, /**< [in] new time baseline, Tshort */
2717  REAL8 tSFTOld, /**< [in] old time baseline, tSFTOld */
2718  UINT4 numShortPerDet, /**< [in] number of tShort segments per detector */
2719  MultiLIGOTimeGPSVector *multiTimes /**< [in] multi-times vector to tell us when the SFTs were */
2720 )
2721 {
2722  /* check input consistency */
2723  if ( !multiDetStates ) {
2724  XLALPrintError( "%s: invalid NULL input argument 'multiDetStates'\n", __func__ );
2726  }
2727 
2728  UINT4 numDetectors = multiDetStates->length;
2729 
2730  /* prepare output vector */
2731  MultiAMCoeffs *ret;
2732  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
2733  XLALPrintError( "%s: failed to XLALCalloc( 1, %zu)\n", __func__, sizeof( *ret ) );
2735  }
2736 
2737  ret->length = numDetectors;
2738  if ( ( ret->data = XLALCalloc( numDetectors, sizeof( *ret->data ) ) ) == NULL ) {
2739  XLALPrintError( "%s: failed to XLALCalloc(%d, %zu)\n", __func__, numDetectors, sizeof( *ret->data ) );
2740  XLALFree( ret );
2742  }
2743 
2744  /* loop over detectors and generate AMCoeffs for each one */
2745  UINT4 X;
2746  for ( X = 0; X < numDetectors; X ++ ) {
2747  if ( ( ret->data[X] = XLALComputeAMCoeffsShort( multiDetStates->data[X], skypos ) ) == NULL ) {
2748  XLALPrintError( "%s: call to XLALComputeAMCoeffs() failed with xlalErrno = %d\n", __func__, xlalErrno );
2749  XLALDestroyMultiAMCoeffs( ret );
2751  }
2752 
2753  } /* for X < numDetectors */
2754 
2755  /* Note that the weighting is the only place where multiTimes are used,
2756  * and for that, the old vector is the right one, because we need to
2757  * know when the old SFTs were */
2758  /* apply noise-weights and compute antenna-pattern matrix {A,B,C} */
2759  if ( XLALWeightMultiAMCoeffsShort( ret, multiWeights, tShort, tSFTOld, numShortPerDet, multiTimes ) != XLAL_SUCCESS ) {
2760  /* Turns out tShort and tSFTOld are, surprisingly, irrelevant (I think) */
2761  XLALPrintError( "%s: call to XLALWeightMultiAMCoeffs() failed with xlalErrno = %d\n", __func__, xlalErrno );
2762  XLALDestroyMultiAMCoeffs( ret );
2764  }
2765 
2766  /* return result */
2767  return ret;
2768 
2769 } /* XLALComputeMultiAMCoeffsShort() */
2770 
2771 
2772 /** Compute the number of tShort segments per detector */
2773 UINT4
2775  const REAL8 resampTshort, /**< [in] resampling Tshort */
2776  const INT4 startTime, /**< [in] start time of observation */
2777  const INT4 endTime /**< [in] end time of observation */
2778 )
2779 {
2780  UINT4 numShortPerDet = 0;
2781  REAL8 Tobs = ( REAL8 )( endTime - startTime );
2782  numShortPerDet = lround( Tobs / resampTshort );
2783  return numShortPerDet;
2784 } /* XLALCrossCorrNumShortPerDetector */
2785 
2786 /** Find gaps in the data given the SFTs*/
2789  LIGOTimeGPSVector *restrict timestamps, /**< [in] timestamps vector */
2790  const LIGOTimeGPSVector *restrict Times /**< [in] input SFT-vector */
2791 )
2792 {
2793  UINT4 numSFTsNew = timestamps->length;
2794  REAL8TimeSeries *retFlag = NULL;
2795  /* creation and memory allocation for the science-or-not vector */
2796  if ( ( retFlag = XLALCreateREAL8TimeSeries( "science-or-not Boolean-as-real vector", &( timestamps->data[0] ), 0, ( timestamps->deltaT ), &lalDimensionlessUnit, numSFTsNew ) ) == NULL ) {
2797  XLALPrintError( "%s: XLALCreateREAL8TimeSeries(%d) failed.\n", __func__, numSFTsNew );
2799  }
2800  REAL8 Tsft = Times->deltaT;
2801  UINT4 jj = 0;
2802  REAL8 tAlpha = 0;
2803  REAL8 tAlphaOldWithGaps = 0;
2804  /* Now make the science-or-not vector */
2805  for ( UINT4 ii = 0; ii < numSFTsNew; ii++ ) {
2806  /* tAlpha is the time in this gapless sequence,
2807  * equivalent to corresponding epoch holder */
2808  /* for tAlpha, use tShort*/
2809  tAlpha = XLALGPSDiff( &( timestamps->data[ii] ), &( timestamps->data[0] ) );
2810  /* tAlphaOldWithGaps is the actual SFT time from timestamps */
2811  tAlphaOldWithGaps = XLALGPSDiff( &( Times->data[jj] ), &( Times->data[0] ) );
2812  /* A science segment begins with an old stamp, continues, and ends
2813  * when the next stamp is more than 1 usual SFT time away -- the
2814  * ending time is that one SFT time */
2815  /* First goal: find out what is the last tAlphaOldWithGaps <= tAlpha;
2816  * then can come the second goal: is tAlpha - tAlphaOldWithGaps < Tsft?
2817  * If yes, then is science (flagHolder = 1), else not (flagHolder = 0) */
2818  for ( UINT4 kk = jj; kk < Times->length ; kk++ ) {
2819  tAlphaOldWithGaps = XLALGPSDiff( &( Times->data[kk] ), &( Times->data[0] ) );
2820  if ( tAlphaOldWithGaps <= tAlpha ) {
2821  jj = kk;
2822  /* At this point, tAlphaOldWithGaps is right for this kk,
2823  * and jj has been set */
2824  } else {
2825  /* Then it has gone too far */
2826  break;
2827  } /* Goal 1: done */
2828  if ( tAlpha - tAlphaOldWithGaps < Tsft ) {
2829  /* time is within an SFT and thus science */
2830  retFlag->data->data[ii] = 1.0;
2831  } else {
2832  /* time is outside an SFT and thus not science */
2833  retFlag->data->data[ii] = 0.0;
2834  } /* Goal 2: done */
2835  }
2836  }
2837  return retFlag;
2838 } /* XLALCrossCorrGapFinderResamp */
2839 
2840 /** (test function) find gaps in the data given the SFTs */
2841 //LIGOTimeGPSVector *
2844  LIGOTimeGPSVector *restrict timestamps, /**< [in] timestamps vector */
2845  const SFTVector *restrict sfts /**< [in] input SFT-vector */
2846 )
2847 {
2848  UINT4 numSFTsNew = timestamps->length;
2849  REAL8TimeSeries *retFlag = NULL;
2850  /* creation and memory allocation for the science-or-not vector */
2851  if ( ( retFlag = XLALCreateREAL8TimeSeries( "science-or-not Boolean-as-real vector", &( timestamps->data[0] ), 0, ( timestamps->deltaT ), &lalDimensionlessUnit, numSFTsNew ) ) == NULL ) {
2852  XLALPrintError( "%s: XLALCreateREAL8TimeSeries(%d) failed.\n", __func__, numSFTsNew );
2854  }
2855  REAL8 Tsft = 1.0 / sfts->data[0].deltaF;
2856  UINT4 jj = 0;
2857  REAL8 tAlpha = 0;
2858  REAL8 tAlphaOldWithGaps = 0;
2859  /* Now make the science-or-not vector */
2860  for ( UINT4 ii = 0; ii < numSFTsNew; ii++ ) {
2861  /* tAlpha is the time in this gapless sequence,
2862  * equivalent to corresponding epoch holder */
2863  /* for tAlpha, use tShort*/
2864  tAlpha = XLALGPSDiff( &( timestamps->data[ii] ), &( timestamps->data[0] ) );
2865  /* tAlphaOldWithGaps is the actual SFT time from timestamps */
2866  tAlphaOldWithGaps = XLALGPSDiff( &( sfts->data[jj].epoch ), &( sfts->data[0] ).epoch );
2867  /* A science segment begins with an old stamp, continues, and ends
2868  * when the next stamp is more than 1 usual SFT time away -- the
2869  * ending time is that one SFT time */
2870  /* First goal: find out what is the last tAlphaOldWithGaps <= tAlpha;
2871  * then can come the second goal: is tAlpha - tAlphaOldWithGaps < Tsft?
2872  * If yes, then is science (flagHolder = 1), else not (flagHolder = 0) */
2873  for ( UINT4 kk = jj; kk < sfts->length ; kk++ ) {
2874  tAlphaOldWithGaps = XLALGPSDiff( &( sfts->data[kk].epoch ), &( sfts->data[0] ).epoch );
2875  if ( tAlphaOldWithGaps <= tAlpha ) {
2876  jj = kk;
2877  /* At this point, tAlphaOldWithGaps is right for this kk,
2878  * and jj has been set */
2879  } else {
2880  /* Then it has gone too far */
2881  break;
2882  } /* Goal 1: done */
2883  if ( tAlpha - tAlphaOldWithGaps < Tsft ) {
2884  /* time is within an SFT and thus science */
2885  retFlag->data->data[ii] = 1.0;
2886  } else {
2887  /* time is outside an SFT and thus not science */
2888  retFlag->data->data[ii] = 0.0;
2889  } /* Goal 2: done */
2890  }
2891  }
2892  return retFlag;
2893 } /* XLALCrossCorrGapFinderResampAlt */
2894 
2895 
2896 /** Demarcate pairs with flags about whether data exists in zero-padded timeseries */
2897 int
2899  MultiResampSFTPairMultiIndexList *resampMultiPairs, /**< [in] resampling pairs */
2900  MultiREAL8TimeSeries *scienceFlagVect /**< [in] science flags */
2901 )
2902 {
2903  /* Note that some functions see the science segment gaps implicitly,
2904  * as with the gammas function being interpolated with zeroes at gaps,
2905  * and the gamma function thus affecting, via the coefficient of pairs
2906  * of phase derivatives, the metric. For these purposes, the science
2907  * flags serve simply as a sanity check. */
2908  REAL4 castSciFlag1 = 0;
2909  REAL4 castSciFlag2 = 0;
2910  UINT4 detInd1;
2911  UINT4 detInd2;
2912  UINT4 sftInd1;
2913  UINT4 sftInd2;
2914  for ( UINT4 detX = 0; detX < resampMultiPairs->length; detX++ ) {
2915  detInd1 = resampMultiPairs->data[detX].detInd;
2916  for ( UINT4 k = 0; k < resampMultiPairs->data[detX].length; k++ ) {
2917  sftInd1 = resampMultiPairs->data[detX].data[k].sftInd;
2918  castSciFlag1 = ( REAL4 )scienceFlagVect->data[detInd1]->data->data[sftInd1];
2919  resampMultiPairs->data[detX].data[k].sciFlag = castSciFlag1;
2920  for ( UINT4 detY = 0; detY < resampMultiPairs->data[detX].data[k].length; detY++ ) {
2921  detInd2 = resampMultiPairs->data[detX].data[k].data[detY].detInd;
2922  for ( UINT4 l = 0; l < resampMultiPairs->data[detX].data[k].data[detY].length; l++ ) {
2923  sftInd2 = resampMultiPairs->data[detX].data[k].data[detY].data[l].sftInd;
2924  castSciFlag2 = ( REAL4 )scienceFlagVect->data[detInd2]->data->data[sftInd2];
2925  resampMultiPairs->data[detX].data[k].data[detY].data[l].sciFlag = castSciFlag2;
2926  }
2927  }
2928  }
2929  }
2930  return XLAL_SUCCESS;
2931 } /* XLALEquipCrossCorrPairsWithScienceFlags */
2932 
2933 ///** (possible future function) does not work -- would adjust timestamps of an SFT vector */
2934 //MultiSFTVector
2935 //*XLALModifyCrossCorrTimestampsIntoSFTVector(
2936 // const MultiLIGOTimeGPSVector *multiTimes /**< [in] timestamps */
2937 //)
2938 //{
2939 // //XLAL_CHECK ( multiTimes != NULL, XLAL_EINVAL );
2940 // //XLAL_CHECK ( multiTimes->length != 0, XLAL_EINVAL );
2941 //
2942 // UINT4 numIFOs = multiTimes->length;
2943 // UINT4 nSFTs = 0;
2944 //
2945 // /* create multi sft vector */
2946 // MultiSFTVector *multiSFTs = NULL;
2947 // //XLAL_CHECK_NULL ( (multiSFTs = XLALCalloc(1, sizeof(*multiSFTs))) != NULL, XLAL_ENOMEM );
2948 // //XLAL_CHECK_NULL ( (multiSFTs->data = XLALCalloc ( numIFOs, sizeof(*multiSFTs->data))) != NULL, XLAL_ENOMEM );
2949 // multiSFTs = XLALCalloc(1, sizeof(*multiSFTs));
2950 // multiSFTs->data = XLALCalloc ( numIFOs, sizeof(*multiSFTs->data));
2951 // multiSFTs->length = numIFOs;
2952 //
2953 // for ( UINT4 X = 0; X < numIFOs; X++ )
2954 // {
2955 // nSFTs = multiTimes->data[X]->length;
2956 // multiSFTs->data[X]->length = nSFTs;
2957 // //SFTVector* sftVector = NULL;
2958 // //sftVector = XLALCreateSFTVector (nSFTs, 1);
2959 // //if (!(sftVector = XLALCreateSFTVector (nSFTs, 1))) {
2960 // // XLALPrintError("ERROR: Couldn't create short sftVector\n");
2961 // // XLALLOADSFTSERROR(XLAL_EINVAL);
2962 // //}
2963 // for ( UINT4 jj = 0; jj < nSFTs; jj++)
2964 // {
2965 // multiSFTs->data[X]->data[jj].epoch = multiTimes->data[X]->data[jj];
2966 // }
2967 // } // for X < numIFOs
2968 //
2969 // return multiSFTs;
2970 //} /* XLALModifyCrossCorrTimestampsIntoSFTVector */
2971 
2972 
2973 /** Generates a resampling workspace for CrossCorr */
2974 int
2976  ResampCrossCorrWorkspace **wsOut, /**< [out] workspace for one cross-correlation */
2977  COMPLEX8 **ws1KFaX_kOut, /**< [out] holder for detector 1 Fa */
2978  COMPLEX8 **ws1KFbX_kOut, /**< [out] holder for detector 1 Fb */
2979  COMPLEX8 **ws2LFaX_kOut, /**< [out] holder for detector 2 Fa */
2980  COMPLEX8 **ws2LFbX_kOut, /**< [out] holder for detector 2 Fb */
2981  MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_aOut, /**< [out] resampling A time series */
2982  MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_bOut, /**< [out] resampling B time series */
2983  const PulsarDopplerParams binaryTemplateSpacings, /**< [in ]binary template spacings */
2984  FstatInput *resampFstatInput, /**< [in] resampling f-statistic input */
2985  const UINT4 numFreqBins, /**< [in] number of frequency bins */
2986  const REAL8 tCoh, /**< [in] Tcoh = 2 * max lag + resampling tShort */
2987  const BOOLEAN treatWarningsAsErrors /**< [in] abort program if any warnings encountered */
2988 )
2989 {
2990 
2991  MultiCOMPLEX8TimeSeries *multiTimeSeries_SRC_a = ( *multiTimeSeries_SRC_aOut );
2992  MultiCOMPLEX8TimeSeries *multiTimeSeries_SRC_b = ( *multiTimeSeries_SRC_bOut );
2993 
2994  COMPLEX8 *restrict ws1KFaX_k = ( *ws1KFaX_kOut );
2995  COMPLEX8 *restrict ws1KFbX_k = ( *ws1KFbX_kOut );
2996  COMPLEX8 *restrict ws2LFaX_k = ( *ws2LFaX_kOut );
2997  COMPLEX8 *restrict ws2LFbX_k = ( *ws2LFbX_kOut );
2998  /* Extract base info from the resampled time series.
2999  * Use both a and b time series structs to make vars used */
3000  XLALExtractResampledTimeseries( &multiTimeSeries_SRC_a, &multiTimeSeries_SRC_b, resampFstatInput );
3001  const REAL8 dt_SRC = multiTimeSeries_SRC_b->data[0]->deltaT;
3002  ( *multiTimeSeries_SRC_aOut ) = multiTimeSeries_SRC_a;
3003  ( *multiTimeSeries_SRC_bOut ) = multiTimeSeries_SRC_b;
3004  /* extract more by using the workspace */
3005 
3006  /* Compare with the timing model document, T1600531, for the F-stat.
3007  * Tcoh here matches Tcoh there, but note that the metric is defined in
3008  * terms of maxLag instead. Tcoh = 2*maxLag + tShort. In this stage, we
3009  * no longer access dt_DET, only dt_SRC.
3010  * In source frame, SRCsampPerTcoh = tCoh / dt_SRC. But we can also
3011  * define the metric timescale,
3012  * metricSRCsampPerTcoh = 1/(dFreqMetric*dt_SRC),
3013  * then round each up to the nearest power of 2 to define,
3014  * metricNumSamplesFFT = (UINT4)pow(2, ceil(log2(metricSRCsampPerTcoh))),
3015  * shortNumSamplesFFT = (UINT4)pow(2, ceil(log2(metricSRCsampPeTcoh))),
3016  * and choose the maximum between the two to be numSampledFFT. This is
3017  * equivalent to how Fstat calculates it.
3018  * To see why, note: our SRCsampPerTcoh is Fstat's N^SRC_samp. We can
3019  * access it immediately because the resampling is already done for us.
3020  * If decimateFFT = (UINT4)ceil( tCoh / TspanFFT),
3021  * = (UINT4)ceil( tCoh * dFreqMetric ),
3022  * then numSamplesFFT0 = (UINT4)ceil(decimateFFT * TspanFFT / dt_SRC)
3023  * for us -- note, dt_SRC, because we have no access to the detector.
3024  * and, numSamplesFFT0 = (UINT4)ceil(decimateFFT / (dFreqMetric*dt_SRC)),
3025  * then rounded up to the nearest power of 2, numSamplesFFT0.
3026  * Ergo, comingling our two notations,
3027  * numSamplesFFT0 = (UINT4)ceil(decimateFFT * metricSRCsampPerTcoh),
3028  * and the exact same error should be thrown if decimateFFT > 1 as if
3029  * shortNumSamplesFFT <= metricNumSamplesFFT.
3030  * Beware: we divide the resampled time-series up into sections, and
3031  * in the statistic this plays a crucial role.
3032  * The equivalent of decimate is the quantity,
3033  * RedecimateFFT
3034  * = binaryTemplateSpacings->fkdot[0] * (dt_SRC) * (ws->numSamplesFFT)
3035  * = dFreqMetric * dt_SRC * (UINT4)pow(2, ceil(log2(...
3036  * (UINT4)ceil(decimateFFT / (dFreqMetric * dt_SRC)) )))
3037  * which although proportional to decimateFFT is not equal to it, and
3038  * is a real quantity rather than integer.
3039  * (GDM)
3040  */
3041  /* Metric spacing: */
3042  const REAL8 dFreqMetric = binaryTemplateSpacings.fkdot[0];
3043  // determine resampled timeseries parameters
3044  const REAL8 TspanFFT = 1.0 / dFreqMetric;
3045  const UINT4 decimateFFT = ( UINT4 )ceil( tCoh / TspanFFT ); // larger than 1 means we need to artificially increase dFreqFFT by 'decimateFFT'
3046  if ( 1 <= ( dFreqMetric * dt_SRC ) ) {
3047  printf( "Warning! Metric spacing less than one FFT sample,...\n ...is maxLag < tShort? \n ...proceeding in radiometer mode...\n ...intended for non-production comparison tests only!\n" );
3048  if ( treatWarningsAsErrors ) {
3049  XLALPrintError( "Error! (treating warnings as errors) metric spacing less than one FFT sample.\n" );
3050  XLAL_CHECK( 1 >= ( dFreqMetric * dt_SRC ), XLAL_EFUNC );
3051  }
3052  }
3053  if ( decimateFFT > 1 ) {
3054  printf( "Warning! Frequency spacing larger than 1/Tcoh, decimation being applied of %" LAL_UINT4_FORMAT "\n", decimateFFT );
3055  if ( treatWarningsAsErrors == TRUE ) {
3056  XLALPrintError( "Error! (treating warnings as errors) FFT samples limited by tCoh (not metric), unexpected unless high mismatchF.\n" );
3057  XLAL_CHECK( ( decimateFFT < 1 ), XLAL_EFUNC );
3058  }
3059  }
3060  const REAL8 TspanFFT1 = decimateFFT * TspanFFT;
3061  /* Note difference from Fstat in using dt_SRC rather than dt_DET here */
3062  const UINT4 numSamplesFFT0 = ( UINT4 ) ceil( TspanFFT1 / dt_SRC ); // we use ceil() so that we artificially widen the band rather than reduce it
3063  const UINT4 numSamplesFFT = ( UINT4 ) pow( 2, ceil( log2( numSamplesFFT0 ) ) ); // round numSamplesFFT up to next power of 2 for most effiecient FFT
3064  ResampCrossCorrWorkspace *restrict ws = NULL;
3065  /* CP'd from ComputeFstat_resamp:538 */
3066  const int fft_plan_flags = FFTW_MEASURE;
3067  //int fft_plan_flags=FFTW_ESTIMATE;
3068  const double fft_plan_timeout = FFTW_NO_TIMELIMIT ;
3069  /* Memory pre-allocate: */
3070  XLAL_CHECK( ( ws = XLALCalloc( 1, sizeof( *ws ) ) ) != NULL, XLAL_ENOMEM );
3071  XLAL_CHECK( ( ws->TStmp1_SRC = XLALCreateCOMPLEX8Vector( numSamplesFFT ) ) != NULL, XLAL_EFUNC );
3072  XLAL_CHECK( ( ws->TStmp2_SRC = XLALCreateCOMPLEX8Vector( numSamplesFFT ) ) != NULL, XLAL_EFUNC );
3073  XLAL_CHECK( ( ws->SRCtimes_DET = XLALCreateREAL8Vector( numSamplesFFT ) ) != NULL, XLAL_EFUNC );
3074  XLAL_CHECK( ( ws->FaX_k = fftw_malloc( numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3075  XLAL_CHECK( ( ws->FbX_k = fftw_malloc( numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3076  XLAL_CHECK( ( ws->FabX_Raw = fftw_malloc( numSamplesFFT * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3077  XLAL_CHECK( ( ws->TS_FFT = fftw_malloc( numSamplesFFT * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3078  ws->decimateFFT = decimateFFT;
3079  ws->numSamplesFFT = numSamplesFFT;
3080  ws->numFreqBinsOut = numFreqBins;
3081  /* -- create FFT plan with FFTW */
3083  //XLALGetFFTPlanHints (& fft_plan_flags , & fft_plan_timeout );
3084  fftw_set_timelimit( fft_plan_timeout );
3085  XLAL_CHECK( ( ws->fftplan = fftwf_plan_dft_1d( numSamplesFFT, ws->TS_FFT, ws->FabX_Raw, FFTW_FORWARD, fft_plan_flags ) ) != NULL, XLAL_EFAILED, "fftwf_plan_dft_1d() failed\n" );
3087  /* -- finish creating FFT plan with FFTW */
3088 
3089  XLAL_CHECK( ( ws1KFaX_k = fftw_malloc( numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3090  XLAL_CHECK( ( ws1KFbX_k = fftw_malloc( numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3091  XLAL_CHECK( ( ws2LFaX_k = fftw_malloc( numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3092  XLAL_CHECK( ( ws2LFbX_k = fftw_malloc( numFreqBins * sizeof( COMPLEX8 ) ) ) != NULL, XLAL_ENOMEM );
3093  ( *ws1KFaX_kOut ) = ws1KFaX_k;
3094  ( *ws1KFbX_kOut ) = ws1KFbX_k;
3095  ( *ws2LFaX_kOut ) = ws2LFaX_k;
3096  ( *ws2LFbX_kOut ) = ws2LFbX_k;
3097  ( *wsOut ) = ws;
3098  return XLAL_SUCCESS;
3099 } /* XLALCreateCrossCorrWorkspace */
3100 
3101 /* ===== Object destruction functions ===== */
3102 
3103 /**
3104  * Destroy a SFTIndexList structure.
3105  * Note, this is "NULL-robust" in the sense that it will not crash
3106  * on NULL-entries anywhere in this struct, so it can be used
3107  * for failure-cleanup even on incomplete structs
3108  */
3109 void
3111 {
3112  if ( ! sftIndices ) {
3113  return;
3114  }
3115 
3116  if ( sftIndices->data ) {
3117  XLALFree( sftIndices->data );
3118  }
3119 
3120  XLALFree( sftIndices );
3121 
3122  return;
3123 
3124 } /* XLALDestroySFTIndexList() */
3125 
3126 /**
3127  * Destroy a SFTPairIndexList structure.
3128  * Note, this is "NULL-robust" in the sense that it will not crash
3129  * on NULL-entries anywhere in this struct, so it can be used
3130  * for failure-cleanup even on incomplete structs
3131  */
3132 void
3134 {
3135  if ( ! sftPairs ) {
3136  return;
3137  }
3138 
3139  if ( sftPairs->data ) {
3140  XLALFree( sftPairs->data );
3141  }
3142 
3143  XLALFree( sftPairs );
3144 
3145  return;
3146 
3147 } /* XLALDestroySFTPairIndexList() */
3148 
3150 {
3151  if ( !sftResampList ) {
3152  return;
3153  }
3154 
3155  if ( sftResampList->data ) {
3156  XLALFree( sftResampList->data );
3157  }
3158 
3159  //XLALFree( sftResampList );
3160 
3161  return;
3162 } /* XLALDestroyResampSFTIndexList */
3163 
3165 {
3166  if ( !sftResampMultiList ) {
3167  return;
3168  }
3169 
3170  for ( UINT4 detY = 0; detY < sftResampMultiList->length; detY++ ) {
3171  XLALDestroyResampSFTIndexList( & sftResampMultiList->data[detY] );
3172  }
3173 
3174  if ( sftResampMultiList->data ) {
3175  XLALFree( sftResampMultiList->data );
3176  }
3177 
3178 
3179  return;
3180 } /* XLALDestroyResampSFTMultiIndexList */
3181 
3183 {
3184  if ( !sftResampPairMultiList ) {
3185  return;
3186  }
3187 
3188  for ( UINT4 k = 0; k < sftResampPairMultiList->length; k++ ) {
3189  XLALDestroyResampSFTMultiIndexList( & sftResampPairMultiList->data[k] );
3190  }
3191 
3192  if ( sftResampPairMultiList->data ) {
3193  XLALFree( sftResampPairMultiList->data );
3194  }
3195 
3196 
3197  return;
3198 } /* XLALDestroyResampSFTPairMultiIndexList */
3199 
3200 void
3202 {
3203  if ( ! sftMultiPairsResamp ) {
3204  return;
3205  }
3206 
3207  /* Iterate through the structure and destroy completely */
3208  for ( UINT4 detX = 0; detX < sftMultiPairsResamp->length; detX++ ) {
3209  XLALDestroyResampSFTPairMultiIndexList( & sftMultiPairsResamp->data[detX] );
3210  }
3211 
3212  /* Rely on external functions to clear pairs and flat index
3213  for now, to make robust */
3214 
3215  if ( sftMultiPairsResamp->data ) {
3216  XLALFree( sftMultiPairsResamp->data );
3217  }
3218 
3219  XLALFree( sftMultiPairsResamp );
3220 
3221  return;
3222 
3223 } /* XLALDestroyMultiResampSFTPairMultiIndexList() */
3224 
3225 /* Destroy the struct that matched pairs */
3226 void
3227 XLALDestroyMultiMatchList( MultiResampSFTMultiCountList *localMultiListOfLmatchingGivenMultiK )
3228 {
3229 
3230  if ( ! localMultiListOfLmatchingGivenMultiK ) {
3231  return;
3232  }
3233 
3234  UINT4 numDets = localMultiListOfLmatchingGivenMultiK->length; /* Because it is a multi-multi-list */
3235  /* furthermore, scroll through each detector X to read how many SFTs K_X it has */
3236  for ( UINT4 detX = 0; detX < numDets; detX++ ) {
3237  for ( UINT4 k = 0; k < localMultiListOfLmatchingGivenMultiK->data[detX].length; k++ ) {
3238  if ( localMultiListOfLmatchingGivenMultiK->data[detX].data[k].data ) {
3239  XLALFree( localMultiListOfLmatchingGivenMultiK->data[detX].data[k].data );
3240  }
3241  }
3242  if ( localMultiListOfLmatchingGivenMultiK->data[detX].data ) {
3243  XLALFree( localMultiListOfLmatchingGivenMultiK->data[detX].data );
3244  }
3245  }
3246 
3247  if ( localMultiListOfLmatchingGivenMultiK->data ) {
3248  XLALFree( localMultiListOfLmatchingGivenMultiK->data );
3249  }
3250 
3251  XLALFree( localMultiListOfLmatchingGivenMultiK );
3252 
3253 }
3254 
3255 void
3257 {
3258  ResampCrossCorrWorkspace *ws = ( ResampCrossCorrWorkspace * ) workspace;
3259 
3263 
3265  fftwf_destroy_plan( ws->fftplan );
3267 
3268  fftw_free( ws->FabX_Raw );
3269  fftw_free( ws->TS_FFT );
3270 
3271  XLALFree( ws->FaX_k );
3272  XLALFree( ws->FbX_k );
3273  XLALFree( ws->Fa_k );
3274  XLALFree( ws->Fb_k );
3275 
3276  XLALFree( ws );
3277  return;
3278 
3279 } // XLALDestroyResampWorkspace()
3280 
3281 // ---------- internal functions ----------
3282 
3283 /** Imported and modified from ComputeFstat_Resamp.c */
3284 static int
3286 (
3287  COMPLEX8 *restrict xOut, ///< [out] the spindown-corrected SRC-frame timeseries
3288  const COMPLEX8TimeSeries *restrict xIn, ///< [in] the input SRC-frame timeseries
3289  const PulsarDopplerParams *restrict doppler, ///< [in] containing spindown parameters
3290  const REAL8 freqShift, ///< [in] frequency-shift to apply, sign is "new - old"
3291  const UINT4 indexStartResamp, ///< [in] index in resampling time series to start
3292  const UINT4 indexEndResamp, ///< [in] index in resampling time series to end
3293  const UINT4 numSamplesIn, ///< [in] number of samples in the output
3294  const UINT4 insertPoint ///< [in] number of sample indices offset to begin output
3295 )
3296 {
3297  // input sanity checks
3298  XLAL_CHECK( xOut != NULL, XLAL_EINVAL );
3299  XLAL_CHECK( xIn != NULL, XLAL_EINVAL );
3300  XLAL_CHECK( doppler != NULL, XLAL_EINVAL );
3301 
3302  //// determine number of spin downs to include
3303  //UINT4 s_max = PULSAR_MAX_SPINS - 1;
3304  //while ( (s_max > 0) && (doppler->fkdot[s_max] == 0) ) {
3305  // s_max --;
3306  //}
3307 
3308  const REAL8 dt = xIn->deltaT;
3309  if ( insertPoint > numSamplesIn ) {
3310  XLALPrintError( "ERROR! Would insert off end of matrix, numSamplesIn < insertPoint: %i, %i\n", numSamplesIn, insertPoint );
3312  }
3313  /* original */ //UINT4 numSamplesIn = xIn->data->length;
3314  /* resampling: use user input */
3315 
3316  const LIGOTimeGPS epoch = xIn->epoch;
3317  const REAL8 Dtau0 = GPSDIFF( epoch, doppler->refTime );
3318 
3319  // loop over time samples
3320  if ( ( indexEndResamp - indexStartResamp ) > numSamplesIn ) {
3321  XLALPrintError( "indexStartResamp, indexEndResamp: %u %u\n", indexStartResamp, indexEndResamp );
3322  XLALPrintError( "ERROR! numSamplesIn only: %u\n", numSamplesIn );
3323  XLALPrintError( "diff in indices, and num samples: %i %u\n", ( indexEndResamp - indexStartResamp ), numSamplesIn );
3325  }
3326 
3327  REAL8 taup_j = 0.0;
3328  REAL8 cycles = 0.0;
3329  REAL4 cosphase, sinphase;
3330  COMPLEX8 em2piphase;
3331  for ( UINT4 j = 0; j < ( indexEndResamp - indexStartResamp ); j ++ ) {
3332  /* j does appear to need indexStartResamp: count from overall start */
3333  taup_j = ( j + indexStartResamp ) * dt + Dtau0;
3334  //REAL8 Dtau_alpha_j = Dtau0 + taup_j;
3335 
3336  cycles = - freqShift * taup_j;
3337 
3338  //REAL8 Dtau_pow_kp1 = Dtau_alpha_j;
3339  /* Unused because we ignore spindown in CrossCorr */
3340  //for ( UINT4 k = 1; k <= s_max; k++ )
3341  // {
3342  // Dtau_pow_kp1 *= Dtau_alpha_j;
3343  // cycles += - LAL_FACT_INV[k+1] * doppler->fkdot[k] * Dtau_pow_kp1;
3344  // } // for k = 1 ... s_max
3345 
3346  XLAL_CHECK( XLALSinCos2PiLUT( &sinphase, &cosphase, cycles ) == XLAL_SUCCESS, XLAL_EFUNC );
3347  em2piphase = crectf( cosphase, sinphase );
3348 
3349  // weight the complex timeseries by the antenna patterns
3350  /* old comment above? I think it means by any freqshift */
3351  xOut[j + insertPoint] = em2piphase * xIn->data->data[( j + indexStartResamp )];
3352 
3353  } // for j < numSamplesIn
3354 
3355  return XLAL_SUCCESS;
3356 
3357 } // XLALApplyCrossCorrFreqShiftResamp()
3358 
3359 /** Compute the equivalent of Fa and Fb for CrossCorr's rho statistic */
3360 static int
3362 (
3363  ResampCrossCorrWorkspace *restrict ws, /**< [out] contains modified Fa and Fb for cross-correlation */
3364  COMPLEX8 *restrict wsFaX_k, /**< [out] contains modified and normalized Fa for cross-correlation statistic */
3365  COMPLEX8 *restrict wsFbX_k, /**< [out] contains modified and normalized Fb for cross-correlation statistic */
3366  const MultiResampSFTPairMultiIndexList *restrict resampMultiPairs, /**< [in] resamp multi list of SFT pairs */
3367  const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_a, /**< [in] Resampled, heterodyned A(t)x(t) */
3368  const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_b, /**< [in] Resampled, heterodyned B(t)x(t) */
3369  const PulsarDopplerParams *restrict dopplerpos, /**< [in] Doppler point to search */
3370  const PulsarDopplerParams *restrict binaryTemplateSpacings, /**< [in] spacings for the search */
3371  const REAL8 SRCsampPerTcoh, /**< [in] floating point number of samples per tShort equivalent */
3372  const UINT4 detX, /**< [in] detector X index */
3373  const UINT4 sftK, /**< [in] tShort K index*/
3374  const UINT4 detY, /**< [in] detector Y index */
3375  const BOOLEAN isL /**< [in] Indicates that is not K but L, the second half of the cross-corr pair */
3376 )
3377 {
3378  XLAL_CHECK( ws != NULL, XLAL_EINVAL );
3379  XLAL_CHECK( wsFaX_k != NULL, XLAL_EINVAL );
3380  XLAL_CHECK( wsFbX_k != NULL, XLAL_EINVAL );
3381  const REAL8 FreqOut0 = dopplerpos->fkdot[0];
3382  const REAL8 fHet = multiTimeSeries_SRC_a->data[0]->f0;
3383  const REAL8 dt_SRC = multiTimeSeries_SRC_b->data[0]->deltaT;
3384  const REAL8 dFreqMetric = binaryTemplateSpacings->fkdot[0];
3385 
3386  /* Compare to the F-statistic timing model, T1600531. Here, we cannot
3387  * change dt_SRC -- it is fixed and given to us. We cannot change it
3388  * because dt_SRC, after ceiling and power-of-two rounding, determined
3389  * by TspanFFT in SetupFstatResamp, and that TspanFFT must be = Tobs
3390  * for us to get the resampling data.
3391  * Where the F-statistic handles power-of-two rounding by reducing
3392  * dt_SRC, we must instead increase T_FFT by zero-padding.
3393  * Yet the number of bins, numSamplesFFT, is fixed.
3394  * What does this imply? Namely, we have a finer frequency resolution,
3395  * which we must use to evaluate cycles for times inside the FFT (as
3396  * well as for bin shifts):
3397  * dFreqMetric -> dFreqFFT
3398  * How do we find dFreqFFT? It is not dFreqMetric/decimateFFT now,
3399  * because T_FFT was lengthened. Whereas F-stat has a higher maximum
3400  * frequency of the band, we have a higher frequency resolution.
3401  * Nevertheless dFreqFFT remains equal to
3402  * dFreqFFT = 1/T_FFT = 1/(dt_SRC * numSamplesFFT), definitionally.
3403  * So if we defined a variable RedecimateFFT, by
3404  * dFreqFFT := dFreqMetric/RedecimateFFT
3405  * ->RedecimateFFT = dFreqMetric/(dFreqFFT)
3406  * = dFreqMetric * dt_SRC * numSamplesFFT
3407  * The finer frequency resolution needed by our FFT means that
3408  * RedecimateFFT is bigger than decimateFFT, by between 1x and 2x.
3409  * Thus, we must also change multiplications,
3410  * x * decimateFFT -> (UINT4)floor( x * RedecimateFFT )
3411  * - - - Comparison to the timing model document - - -
3412  * In the workspace function, we note that
3413  * our SRCsampPerTcoh corresponds to N^SRC_samp from the document.
3414  * However, our N^SRC_samp for a given Tcoh will be smaller than
3415  * The F-statistic, because for fixed number of FFT bins, dt_SRC
3416  * will be bigger than in the F-statistic (because it was not
3417  * reducable to fit the next power of 2). Correspondingly, our R
3418  * is smaller. Specifically,
3419  * R_crosscorr / R_fstat = D_fstat / D_crosscorr,
3420  * Where D_fstat is decimateFFT and D_crosscorr is RedecimateFFT.
3421  * This ratio is simply the power-of-2 rounding, i.e.,
3422  * R_crosscorr / R_fstat = numSamplesFFT0 / numSamplesFFT,
3423  * - - - CrossCorr timing model by analogy - - -
3424  * Whereas the F-stat timing model had,
3425  * tau^eff_F = tau^(0)_Fbin +
3426  * N^FFT_samp / N_fbin * (
3427  * R(tau^(0)_spin +b tau^(0)_bary) +5log_2(N^FFT_samp) tau^(0)_FFT
3428  * ),
3429  * we have no search over spin-down and our b = 1 always.
3430  * Our equivalent of tau^(0)_Fbin, however, is different, but the
3431  * more critical difference is the way that semicoherent segments are
3432  * combined. Namely, instead of multiplying
3433  * tau_semi_F = tau^eff_F by (Tobs/Tcoh) Ndet, [not in timing document]
3434  * we must calculate the above and multiply by the overlap factor,
3435  * (tCoh/tShort), after adding in any paired detectors. So we will have
3436  * tau_semi_CC ~= tau^eff_CC (Tobs/Tshort) * (Ndet + (Ndet+1)Ndet/2 ) ,
3437  * where
3438  * tau^eff_CC ~= tau^(0)_CCbin +
3439  * N^FFT_samp / N_CCbin * (
3440  * R_CC b tau^(0)_bary + 5log_2(N^FFT_samp) tau^(0)_FFT
3441  * ).
3442  * More accurately, the Ndet term must go inside, because barycentering
3443  * occurs once per detector, the first FFT of a pair happens once per
3444  * detector, and the second FFT of a pair happens Triangular(Ndet),
3445  * where Triangular is the triangular number sequence,
3446  * Triangular(Ndet) = (Ndet)(Ndet+1)/2.
3447  * Thus the full semicoherent number should be
3448  * tau_semi_CC = (Tobs/Tshort) tau^(0)_CCbin + N^FFT_samp/N_CCbin *(
3449  * (R_CC b tau^(0)_bary) * Ndet +
3450  * (5log_2(N^FFT_samp) tau^(0)_FFT) * (Ndet + Ndet(Ndet+1)/2)
3451  * ).
3452  * Accurately calculating N^FFT_samp = numSamplesFFT is therefore key:
3453  * following from the timing model document for the F-stat,
3454  * numSamplesFFT0 = (Delta f_SFT) decimateFFT / dFreqMetric,
3455  * where,
3456  * delta f_SFT = (1+4/(2 Dterms +1))(Delta f+Delta f_drift+16/Tsft)
3457  * with Delta_f = f_max - f_min,
3458  * for Sco X-1,
3459  * Delta f_drift = v_earth / c + 2 pi f_max / (c Period)
3460  * Putting it altogether, where
3461  * N^FFT_samp = numSamplesFFT,
3462  * = (UINT4)pow(2, ceil(log2(numSamplesFFT0))),
3463  * = (UINT4)pow(2, ceil(log2(
3464  * (decimateFFT/dFreqMetric) *
3465  * (
3466  * (1+4/(2 Dterms + 1)) *
3467  * ( f_max - f_min + 16/Tsft +
3468  * v_earth/c +2 pi f_max /(c Period)
3469  * )
3470  * )
3471  * ))).
3472  * That forms the basis of the CrossCorr timing model.
3473  * (GDM)
3474  */
3475  const REAL4 RedecimateFFT = dFreqMetric * dt_SRC * ( ws->numSamplesFFT ); //Equals metric freq res divided by freq res of our FFT
3476  const REAL8 dFreqFFT = dFreqMetric / RedecimateFFT;
3477  const REAL8 freqShiftInFFT = remainder( FreqOut0 - fHet, dFreqFFT ); // frequency shift to closest bin in final resolution
3478  const REAL8 fMinFFT = fHet + freqShiftInFFT - dFreqFFT * ( ws->numSamplesFFT / 2 ); // we'll shift DC into the *middle bin* N/2 [N always even!]
3479  XLAL_CHECK( FreqOut0 >= fMinFFT, XLAL_EDOM, "Lowest output frequency outside the available frequency band: [FreqOut0 = %.16g] < [fMinFFT = %.16g]\n", FreqOut0, fMinFFT );
3480  /* -> THIS AFFECTS indices below, in FaX_k loop */
3481  const UINT4 offset_bins = ( UINT4 ) lround( ( FreqOut0 - fMinFFT ) / dFreqFFT );
3482  const UINT4 maxOutputBin = offset_bins + ( UINT4 )floor( ( ws->numFreqBinsOut - 1 ) * RedecimateFFT );
3483  XLAL_CHECK( maxOutputBin < ws->numSamplesFFT, XLAL_EDOM, "Highest output frequency bin outside available band: [maxOutputBin = %d] >= [ws->numSamplesFFT = %d]\n", maxOutputBin, ws->numSamplesFFT );
3484 
3485  /* start and stop variables */
3486  UINT4 startFirstInd = 0;
3487  UINT4 startInd = 0;
3488  UINT4 endInd = 0;
3489  UINT4 sftIndFirst = 0;
3490  UINT4 detInd = 0;
3491  UINT4 sftInd = 0;
3492 
3493  /* set sftInd and dftInd values using the like-named fields encoded in
3494  * resampMultiPairs, which are with respect to the sft vector,
3495  * inputSFTs. This should handle gaps correctly.
3496  * For any loops over derived values, determined only for matching sfts,
3497  * instead use detX, sftK, detY, sftL, otherwise index may be out-of-bound
3498  */
3499  const ResampSFTPairMultiIndexList *restrict resampMultiPairsDetX = &( resampMultiPairs->data[detX] );
3500  const ResampSFTMultiIndexList *restrict resampMultiPairsDetXsftK = &( resampMultiPairsDetX->data[sftK] );
3501 
3502  if ( isL == TRUE ) {
3503  detInd = resampMultiPairsDetXsftK->data[detY].detInd;
3504  } else {
3505  detInd = resampMultiPairsDetX->detInd;
3506  }
3507 
3508  /* ------- begin FFT replacement using RESAMP ------- */
3509  /* resamp data */
3510  const COMPLEX8TimeSeries *restrict resampDataArrayA = multiTimeSeries_SRC_a->data[detInd];
3511  const COMPLEX8TimeSeries *restrict resampDataArrayB = multiTimeSeries_SRC_b->data[detInd];
3512 
3513  if ( isL == TRUE ) {
3514  /* Need to consider handling if no sftInd exists because none match */
3515  if ( resampMultiPairsDetXsftK->data[detY].length > 0 ) {
3516  sftIndFirst = resampMultiPairsDetXsftK->data[detY].data[0].sftInd;
3517  startFirstInd = ( UINT4 )round( sftIndFirst * SRCsampPerTcoh );
3518  }
3519  } else {
3520  sftIndFirst = resampMultiPairsDetXsftK->sftInd;
3521  startFirstInd = ( UINT4 )round( sftIndFirst * SRCsampPerTcoh );
3522  }
3523  if ( startFirstInd > resampDataArrayA->data->length ) {
3524  startFirstInd = resampDataArrayA->data->length;
3525  }
3526 
3527  memset( ws->TS_FFT, 0, ws->numSamplesFFT * sizeof( ws->TS_FFT[0] ) );
3528  UINT4 sftLength = 0;
3529  if ( isL == TRUE ) {
3530  sftLength = resampMultiPairsDetXsftK->data[detY].length;
3531  } else {
3532  sftLength = 1;
3533  }
3534  // Load and FFT A time series
3535  for ( UINT4 sft = 0; sft < sftLength; sft++ ) {
3536  //if (resampMultiPairsDetXsftK->data[detY].data[sft].sciFlag > 0){
3537  /* Needs to be defined wrt resamp time series, so:*/
3538  if ( isL == TRUE ) {
3539  sftInd = resampMultiPairsDetXsftK->data[detY].data[sft].sftInd;
3540  } else {
3541  sftInd = resampMultiPairsDetXsftK->sftInd;
3542  }
3543  startInd = ( UINT4 )round( sftInd * SRCsampPerTcoh );
3544  endInd = ( UINT4 )round( ( sftInd + 1 ) * SRCsampPerTcoh );
3545  if ( startInd > resampDataArrayA->data->length ) {
3546  startInd = resampDataArrayA->data->length;
3547  }
3548  if ( endInd > resampDataArrayA->data->length ) {
3549  endInd = resampDataArrayA->data->length;
3550  }
3551  if ( startInd > endInd ) {
3552  startInd = endInd;
3553  }
3554  UINT4 headOfSliceIndex = startInd - startFirstInd;
3555  XLAL_CHECK( XLALApplyCrossCorrFreqShiftResamp( ws->TS_FFT, resampDataArrayA, dopplerpos, freqShiftInFFT, startInd, endInd, ws->numSamplesFFT, headOfSliceIndex ) == XLAL_SUCCESS, XLAL_EFUNC );
3556  //}
3557  }
3558  fftwf_execute( ws->fftplan );
3559  for ( UINT4 k = 0; k < ws->numFreqBinsOut; k++ ) {
3560  ws->FaX_k[k] = ws->FabX_Raw [ offset_bins + ( UINT4 )floor( k * RedecimateFFT ) ];
3561  }
3562  // END load and FFT A time series
3563 
3564  // Load and FFT B time series
3565  memset( ws->TS_FFT, 0, ws->numSamplesFFT * sizeof( ws->TS_FFT[0] ) );
3566  for ( UINT4 sft = 0; sft < sftLength; sft++ ) {
3567  //if (resampMultiPairsDetXsftK->data[detY].data[sft].sciFlag > 0){
3568  if ( isL == TRUE ) {
3569  sftInd = resampMultiPairsDetXsftK->data[detY].data[sft].sftInd;
3570  } else {
3571  sftInd = resampMultiPairsDetXsftK->sftInd;
3572  }
3573  startInd = ( UINT4 )round( sftInd * SRCsampPerTcoh );
3574  endInd = ( UINT4 )round( ( sftInd + 1 ) * SRCsampPerTcoh );
3575  if ( startInd > resampDataArrayB->data->length ) {
3576  startInd = resampDataArrayB->data->length;
3577  }
3578  if ( endInd > resampDataArrayB->data->length ) {
3579  endInd = resampDataArrayB->data->length;
3580  }
3581  if ( startInd > endInd ) {
3582  startInd = endInd;
3583  }
3584  UINT4 headOfSliceIndex = startInd - startFirstInd;
3585  XLAL_CHECK( XLALApplyCrossCorrFreqShiftResamp( ws->TS_FFT, resampDataArrayB, dopplerpos, freqShiftInFFT, startInd, endInd, ws->numSamplesFFT, headOfSliceIndex ) == XLAL_SUCCESS, XLAL_EFUNC );
3586  //}
3587  }
3588  fftwf_execute( ws->fftplan );
3589  for ( UINT4 k = 0; k < ws->numFreqBinsOut; k++ ) {
3590  ws->FbX_k[k] = ws->FabX_Raw [ offset_bins + ( UINT4 )floor( k * RedecimateFFT ) ];
3591  }
3592  // End load and FFT B time series
3593 
3594  const REAL8 dtauX = GPSDIFF( resampDataArrayB->epoch, dopplerpos->refTime );
3595  const REAL8 timeFromResampStartToSFTFirst = startFirstInd * dt_SRC;
3596  REAL8 f_kOut;
3597  REAL8 f_kIn;
3598  REAL8 cyclesOut;
3599  REAL8 cyclesIn;
3600  REAL8 cycles;
3601  REAL4 sinphase, cosphase;
3602  COMPLEX8 normX_k;
3603  for ( UINT4 k = 0; k < ws->numFreqBinsOut; k++ ) {
3604  f_kOut = FreqOut0 + k * dFreqMetric;
3605  f_kIn = ( offset_bins + ( UINT4 )floor( k * RedecimateFFT ) ) * dFreqFFT;
3606  cyclesOut = - f_kOut * dtauX;
3607  cyclesIn = -f_kIn * timeFromResampStartToSFTFirst;
3608  cycles = cyclesOut + cyclesIn;
3609  XLALSinCos2PiLUT( &sinphase, &cosphase, cycles );
3610  normX_k = dt_SRC * crectf( cosphase, sinphase );
3611  wsFaX_k[k] = normX_k * ws->FaX_k[k];
3612  wsFbX_k[k] = normX_k * ws->FbX_k[k];
3613  } // for k < numFreqBinsOut
3614 
3615  return XLAL_SUCCESS;
3616 } // XLALComputeFaFb_CrossCorrResamp()
3617 
3618 /// @}
#define __func__
log an I/O error, i.e.
#define LAL_FFTW_WISDOM_UNLOCK
#define LAL_FFTW_WISDOM_LOCK
int j
int k
#define LALCalloc(m, n)
static double double delta
#define MYMIN(x, y)
#define SINC_SAFETY
#define GPSDIFF(x, y)
#define MYMAX(x, y)
#define SQUARE(x)
#define TRUE
#define FALSE
#define QUAD(x)
const WeaveSearchTimingDenominator denom
Definition: SearchTiming.c:95
LIGOTimeGPSVector * timestamps
#define fprintf
int l
const double xi2
REAL8VectorSequence * XLALCreateREAL8VectorSequence(UINT4 length, UINT4 veclen)
int XLALExtractResampledTimeseries(MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_a, MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_b, FstatInput *input)
Extracts the resampled timeseries from a given FstatInput structure (must have been initialized previ...
DetectorStateSeries * XLALCreateDetectorStateSeries(UINT4 length)
Create a DetectorStateSeries with length entries.
void XLALDestroyDetectorStateSeries(DetectorStateSeries *detStates)
Get rid of a DetectorStateSeries.
int XLALBarycenterEarth(EarthState *earth, const LIGOTimeGPS *tGPS, const EphemerisData *edat)
Computes the position and orientation of the Earth, at some arrival time , specified LIGOTimeGPS inp...
Definition: LALBarycenter.c:78
int XLALBarycenter(EmissionTime *emit, const BarycenterInput *baryinput, const EarthState *earth)
Transforms from detector arrival time in GPS (as specified in the LIGOTimeGPS structure) to pulse em...
void XLALDestroyMultiAMCoeffs(MultiAMCoeffs *multiAMcoef)
Destroy a MultiAMCoeffs structure.
Definition: LALComputeAM.c:469
AMCoeffs * XLALCreateAMCoeffs(UINT4 numSteps)
Create an AMCeoffs vector for given number of timesteps.
Definition: LALComputeAM.c:435
#define LAL_REAL4_MAX
#define LAL_PI
#define LAL_1_PI
#define LAL_TWOPI
unsigned char BOOLEAN
uint64_t UINT8
double REAL8
#define crectf(re, im)
char CHAR
uint32_t UINT4
float complex COMPLEX8
int32_t INT4
float REAL4
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
#define LAL_UINT4_FORMAT
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 LogPrintf(LogLevel_t, const char *format,...) _LAL_GCC_PRINTF_FORMAT_(2
LOG_CRITICAL
void XLALDestroyMultiNoiseWeights(MultiNoiseWeights *weights)
Destroy a MultiNoiseWeights object.
Definition: PSDutils.c:172
int XLALEquipCrossCorrPairsWithScienceFlags(MultiResampSFTPairMultiIndexList *resampMultiPairs, MultiREAL8TimeSeries *scienceFlagVect)
Demarcate pairs with flags about whether data exists in zero-padded timeseries.
void XLALDestroyResampSFTIndexList(ResampSFTIndexList *sftResampList)
void XLALDestroySFTPairIndexList(SFTPairIndexList *sftPairs)
Destroy a SFTPairIndexList structure.
void XLALDestroyResampCrossCorrWorkspace(void *workspace)
int XLALCreateCrossCorrWorkspace(ResampCrossCorrWorkspace **wsOut, COMPLEX8 **ws1KFaX_kOut, COMPLEX8 **ws1KFbX_kOut, COMPLEX8 **ws2LFaX_kOut, COMPLEX8 **ws2LFbX_kOut, MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_aOut, MultiCOMPLEX8TimeSeries **multiTimeSeries_SRC_bOut, const PulsarDopplerParams binaryTemplateSpacings, FstatInput *resampFstatInput, const UINT4 numFreqBins, const REAL8 tCoh, const BOOLEAN treatWarningsAsErrors)
‍** (possible future function) does not work – would adjust timestamps of an SFT vector *‍/
int XLALCalculateCrossCorrPhaseDerivatives(REAL8VectorSequence **phaseDerivs, const PulsarDopplerParams *dopplerPoint, const EphemerisData *edat, SFTIndexList *indexList, MultiSSBtimes *multiTimes, const DopplerCoordinateSystem *coordSys)
calculate signal phase derivatives wrt Doppler coords, for each SFT
int XLALModifyMultiAMCoeffsWeights(MultiNoiseWeights **multiWeights, const REAL8 tShort, const REAL8 tSFTOld, const UINT4 numShortPerDet, const MultiLIGOTimeGPSVector *restrict multiTimes)
Modify multiple detectors' amplitude weight coefficients for tShort.
int XLALCreateSFTPairIndexList(SFTPairIndexList **pairIndexList, SFTIndexList *indexList, MultiSFTVector *sfts, REAL8 maxLag, BOOLEAN inclAutoCorr)
Construct list of SFT pairs for inclusion in statistic.
AMCoeffs * XLALComputeAMCoeffsShort(const DetectorStateSeries *DetectorStates, SkyPosition skypos)
(test function) used for computing amplitude modulation weights
int XLALCalculateLMXBCrossCorrDiagMetric(REAL8 *hSens, REAL8 *g_ff, REAL8 *g_aa, REAL8 *g_TT, REAL8 *g_pp, REAL8 *weightedMuTAve, PulsarDopplerParams DopplerParams, REAL8Vector *G_alpha, SFTPairIndexList *pairIndexList, SFTIndexList *indexList, MultiSFTVector *sfts, MultiNoiseWeights *multiWeights)
int XLALCalculateCrossCorrGammasResampShort(REAL8Vector **Gamma_ave, REAL8Vector **Gamma_circ, MultiResampSFTPairMultiIndexList *resampMultiPairIndexList, MultiAMCoeffs *multiCoeffs)
test function for RESAMPLING with tShort
LIGOTimeGPSVector * XLALModifyTimestampsFromSFTsShort(REAL8TimeSeries **sciFlag, const LIGOTimeGPSVector *restrict Times, const REAL8 tShort, const UINT4 numShortPerDet)
Modify timestamps from one detector with tShort.
int XLALFillDetectorTensorShort(DetectorState *detState, const LALDetector *detector)
(test function) fill detector state with tShort, importing various slightly-modified LALPulsar functi...
int XLALWeightMultiAMCoeffsShort(MultiAMCoeffs *multiAMcoef, const MultiNoiseWeights *multiWeights, REAL8 tShort, REAL8 tSFTOld, UINT4 numShortPerDet, MultiLIGOTimeGPSVector *multiTimes)
(test function) used for weighting multi amplitude modulation coefficients
LIGOTimeGPSVector * XLALExtractTimestampsFromSFTsShort(REAL8TimeSeries **sciFlag, const SFTVector *sfts, REAL8 tShort, UINT4 numShortPerDet)
‍** (possible future function) Wrapper for Bessel Orbital Space stepper in the manner of V....
int XLALCalculateCrossCorrGammas(REAL8Vector **Gamma_ave, REAL8Vector **Gamma_circ, SFTPairIndexList *pairIndexList, SFTIndexList *indexList, MultiAMCoeffs *multiCoeffs)
Construct vector of G_alpha amplitudes for each SFT pair.
int XLALCalculatePulsarCrossCorrStatisticResamp(REAL8Vector *restrict ccStatVector, REAL8Vector *restrict evSquaredVector, REAL8Vector *restrict numeEquivAve, REAL8Vector *restrict numeEquivCirc, const REAL8Vector *restrict resampCurlyGAmp, const MultiResampSFTPairMultiIndexList *restrict resampMultiPairs, const MultiNoiseWeights *restrict multiWeights, const PulsarDopplerParams *restrict binaryTemplateSpacings, const PulsarDopplerParams *restrict dopplerpos, const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_a, const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_b, ResampCrossCorrWorkspace *restrict ws, COMPLEX8 *restrict ws1KFaX_k, COMPLEX8 *restrict ws1KFbX_k, COMPLEX8 *restrict ws2LFaX_k, COMPLEX8 *restrict ws2LFbX_k)
Calculate multi-bin cross-correlation statistic using resampling.
int XLALTestResampPairIndexList(MultiResampSFTPairMultiIndexList *resampMultiPairIndexList)
Check that the contents of a resampling multi-pair index list are sensible by inspection.
int XLALCreateSFTPairIndexListResamp(MultiResampSFTPairMultiIndexList **resampMultiPairIndexList, SFTPairIndexList **pairIndexList, SFTIndexList *indexList, MultiSFTVector *sfts, REAL8 maxLag, BOOLEAN inclAutoCorr, BOOLEAN inclSameDetector, REAL8 Tsft, REAL8 Tshort)
Resampling-modified: construct list of SFT pairs for inclusion in statistic.
MultiAMCoeffs * XLALComputeMultiAMCoeffsShort(const MultiDetectorStateSeries *multiDetStates, const MultiNoiseWeights *multiWeights, SkyPosition skypos, REAL8 tShort, REAL8 tSFTOld, UINT4 numShortPerDet, MultiLIGOTimeGPSVector *multiTimes)
(test function) used for computing multi amplitude modulation weights
int XLALCalculateCrossCorrPhaseMetricShort(gsl_matrix **g_ij, gsl_vector **eps_i, REAL8 *sumGammaSq, const REAL8VectorSequence *phaseDerivs, const MultiResampSFTPairMultiIndexList *resampMultiPairs, const REAL8Vector *Gamma_ave, const REAL8Vector *Gamma_circ, const DopplerCoordinateSystem *coordSys)
(test function) Redesigning to use Tshort instead
int XLALCalculatePulsarCrossCorrStatistic(REAL8 *ccStat, REAL8 *evSquared, REAL8Vector *curlyGAmp, COMPLEX8Vector *expSignalPhases, UINT4Vector *lowestBins, REAL8VectorSequence *sincList, SFTPairIndexList *sftPairs, SFTIndexList *sftIndices, MultiSFTVector *inputSFTs, MultiNoiseWeights *multiWeights, UINT4 numBins)
Calculate multi-bin cross-correlation statistic.
int XLALModifyAMCoeffsWeights(REAL8Vector **resampMultiWeightsX, const MultiNoiseWeights *restrict multiWeights, const REAL8 tShort, const REAL8 tSFTOld, const UINT4 numShortPerDet, const MultiLIGOTimeGPSVector *restrict multiTimes, const UINT4 maxNumStepsOldIfGapless, const UINT4 X)
Modify amplitude weight coefficients for tShort.
void XLALDestroySFTIndexList(SFTIndexList *sftIndices)
Destroy a SFTIndexList structure.
static int XLALApplyCrossCorrFreqShiftResamp(COMPLEX8 *restrict xOut, const COMPLEX8TimeSeries *restrict xIn, const PulsarDopplerParams *restrict doppler, const REAL8 freqShift, const UINT4 indexStartResamp, const UINT4 indexEndResamp, const UINT4 numSamplesIn, const UINT4 insertPoint)
Imported and modified from ComputeFstat_Resamp.c.
void XLALDestroyMultiResampSFTPairMultiIndexList(MultiResampSFTPairMultiIndexList *sftMultiPairsResamp)
REAL8TimeSeries * XLALCrossCorrGapFinderResamp(LIGOTimeGPSVector *restrict timestamps, const LIGOTimeGPSVector *restrict Times)
Find gaps in the data given the SFTs.
void XLALDestroyResampSFTMultiIndexList(ResampSFTMultiIndexList *sftResampMultiList)
int XLALCreateSFTIndexListFromMultiSFTVect(SFTIndexList **indexList, MultiSFTVector *sfts)
Construct flat SFTIndexList out of a MultiSFTVector.
int XLALGetDopplerShiftedFrequencyInfo(REAL8Vector *shiftedFreqs, UINT4Vector *lowestBins, COMPLEX8Vector *expSignalPhases, REAL8VectorSequence *sincList, UINT4 numBins, PulsarDopplerParams *dopp, SFTIndexList *sftIndices, MultiSFTVector *inputSFTs, MultiSSBtimes *multiTimes, MultiUINT4Vector *badBins, REAL8 Tsft)
Calculate the Doppler-shifted frequency associated with each SFT in a list.
int XLALCalculateCrossCorrGammasResamp(REAL8Vector **Gamma_ave, REAL8Vector **Gamma_circ, MultiResampSFTPairMultiIndexList *resampMultiPairIndexList, MultiAMCoeffs *multiCoeffs)
test function for RESAMPLING
int XLALCalculateCrossCorrPhaseMetric(gsl_matrix **g_ij, gsl_vector **eps_i, REAL8 *sumGammaSq, const REAL8VectorSequence *phaseDerivs, const SFTPairIndexList *pairIndexList, const REAL8Vector *Gamma_ave, const REAL8Vector *Gamma_circ, const DopplerCoordinateSystem *coordSys)
calculate phase metric for CW cross-correlation search, as well as vector used for parameter offsets
void XLALDestroyMultiMatchList(MultiResampSFTMultiCountList *localMultiListOfLmatchingGivenMultiK)
MultiLIGOTimeGPSVector * XLALExtractMultiTimestampsFromSFTsShort(MultiREAL8TimeSeries **scienceFlagVect, const MultiSFTVector *multiSFTs, REAL8 tShort, UINT4 numShortPerDet)
Given a multi-SFT vector, return a MultiLIGOTimeGPSVector holding the SFT timestamps (test function u...
int XLALCalculateLMXBCrossCorrDiagMetricShort(REAL8 *hSens, REAL8 *g_ff, REAL8 *g_aa, REAL8 *g_TT, REAL8 *g_pp, const PulsarDopplerParams DopplerParams, const REAL8Vector *restrict G_alpha, const MultiResampSFTPairMultiIndexList *restrict resampMultiPairIndexList, const MultiLIGOTimeGPSVector *restrict timestamps, const MultiNoiseWeights *restrict multiWeights)
MODIFIED for Tshort: calculate metric diagonal components, also include the estimation of sensitivity...
static int XLALComputeFaFb_CrossCorrResamp(ResampCrossCorrWorkspace *restrict ws2L, COMPLEX8 *restrict wsFaX_k, COMPLEX8 *restrict wsFbX_k, const MultiResampSFTPairMultiIndexList *restrict resampMultiPairs, const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_a, const MultiCOMPLEX8TimeSeries *restrict multiTimeSeries_SRC_b, const PulsarDopplerParams *restrict dopplerpos, const PulsarDopplerParams *restrict binaryTemplateSpacings, const REAL8 SRCsampPerTcoh, const UINT4 detX, const UINT4 sftK, const UINT4 detY, const BOOLEAN isL)
Compute the equivalent of Fa and Fb for CrossCorr's rho statistic.
MultiLIGOTimeGPSVector * XLALModifyMultiTimestampsFromSFTs(MultiREAL8TimeSeries **scienceFlagVect, const MultiLIGOTimeGPSVector *restrict multiTimes, const REAL8 tShort, const UINT4 numShortPerDet)
Given a multi-SFT vector, return a MultiLIGOTimeGPSVector holding the modified SFT timestamps (produc...
UINT4 XLALCrossCorrNumShortPerDetector(const REAL8 resampTshort, const INT4 startTime, const INT4 endTime)
Compute the number of tShort segments per detector.
DetectorStateSeries * XLALGetDetectorStatesShort(const LIGOTimeGPSVector *timestamps, const LALDetector *detector, const EphemerisData *edat, REAL8 tOffset, REAL8 tShort, UINT4 numShortPerDet)
(test function) get detector states for tShort
int XLALCreateSFTPairIndexListShortResamp(MultiResampSFTPairMultiIndexList **resampMultiPairIndexList, const REAL8 maxLag, const BOOLEAN inclAutoCorr, const BOOLEAN inclSameDetector, const REAL8 Tsft, const MultiLIGOTimeGPSVector *restrict multiTimes)
With Tshort, and Resampling-modified: construct list of SFT pairs for inclusion in statistic.
void XLALDestroyResampSFTPairMultiIndexList(ResampSFTPairMultiIndexList *sftResampPairMultiList)
MultiDetectorStateSeries * XLALGetMultiDetectorStatesShort(const MultiLIGOTimeGPSVector *multiTS, const MultiLALDetector *multiIFO, const EphemerisData *edat, REAL8 tOffset, REAL8 tShort, UINT4 numShortPerDet)
(test function) get multi detector states for tShort
REAL8TimeSeries * XLALCrossCorrGapFinderResampAlt(LIGOTimeGPSVector *restrict timestamps, const SFTVector *restrict sfts)
(test function) find gaps in the data given the SFTs
int XLALCalculateCrossCorrPhaseDerivativesShort(REAL8VectorSequence **resampPhaseDerivs, const PulsarDopplerParams *dopplerPoint, const EphemerisData *edat, SFTIndexList *indexList, MultiResampSFTPairMultiIndexList *resampMultiPairs, MultiSSBtimes *multiTimes, const DopplerCoordinateSystem *coordSys)
(test function) MODIFIED for Tshort
#define PULSAR_MAX_SPINS
maximal number of spin-parameters (Freq + spindowns) we can handle
LIGOTimeGPSVector * XLALCreateTimestampVector(UINT4 len)
Allocate a LIGOTimeGPSVector.
Definition: SFTtimestamps.c:47
void XLALDestroyMultiTimestamps(MultiLIGOTimeGPSVector *multiTS)
Destroy a MultiLIGOTimeGPSVector timestamps vector.
int XLALSinCosLUT(REAL4 *sinx, REAL4 *cosx, REAL8 x)
Calculate sin(x) and cos(x) to roughly 1e-7 precision using a lookup-table and Taylor-expansion.
Definition: SinCosLUT.c:83
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_ECLIPTIC
COORDINATESYSTEM_EQUATORIAL
REAL8TimeSeries * XLALCreateREAL8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
COMPLEX8TimeSeries * XLALCreateCOMPLEX8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
void XLALDestroyCOMPLEX8TimeSeries(COMPLEX8TimeSeries *series)
const LALUnit lalDimensionlessUnit
REAL8 XLALComputePhaseDerivative(REAL8 t, const PulsarDopplerParams *dopplerPoint, DopplerCoordinateID coordID, const EphemerisData *edat, const LALDetector *site, BOOLEAN includeRoemer)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
COMPLEX8Vector * XLALCreateCOMPLEX8Vector(UINT4 length)
void XLALDestroyCOMPLEX8Vector(COMPLEX8Vector *vector)
#define XLAL_ERROR_NULL(...)
#define xlalErrno
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK_NULL(assertion,...)
XLAL_EBADLEN
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
XLAL_EINVAL
XLAL_EFAILED
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
REAL8 XLALGPSGetREAL8(const LIGOTimeGPS *epoch)
REAL8 XLALGPSDiff(const LIGOTimeGPS *t1, const LIGOTimeGPS *t0)
string prefix
double alpha
size_t numDetectors
double t0
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
REAL8 Sinv_Tsft
normalization-factor (using single-sided PSD!)
Definition: LALComputeAM.h:133
REAL4 Dd
determinant factor , such that
Definition: LALComputeAM.h:132
Basic input structure to LALBarycenter.c.
REAL8 alpha
Source right ascension in ICRS J2000 coords (radians).
REAL8 dInv
1/(distance to source), in 1/sec.
LIGOTimeGPS tgps
input GPS arrival time.
REAL8 delta
Source declination in ICRS J2000 coords (radians)
LALDetector site
detector site info.
COMPLEX8Sequence * data
A vector of COMPLEX8FrequencySeries.
COMPLEX8FrequencySeries * data
Pointer to the data array.
UINT4 length
Number of elements in array.
COMPLEX8Sequence * data
COMPLEX8 * data
State-info about position, velocity and LMST of a detector together with corresponding EarthState.
REAL8 vDetector[3]
Cart.
EarthState earthState
EarthState information.
REAL8 rDetector[3]
Cartesian coords of detector position in ICRS J2000.
LIGOTimeGPS tGPS
GPS timestamps corresponding to this entry.
SymmTensor3 detT
Detector-tensor components in SSB-fixed, Cartesian coordinates.
REAL8 LMST
local mean sidereal time at the detector-location in radians
Timeseries of DetectorState's, representing the detector-info at different timestamps.
REAL8 deltaT
timespan centered on each timestamp (e.g.
CoordinateSystem system
The coordinate system used for detector's position/velocity and detector-tensor.
DetectorState * data
array of DetectorState entries
UINT4 length
total number of entries
LALDetector detector
detector-info corresponding to this timeseries
type describing a Doppler coordinate system: lists the number of dimensions and the symbolic names of...
DopplerCoordinateID coordIDs[DOPPLERMETRIC_MAX_DIM]
coordinate 'names'
UINT4 dim
number of dimensions covered
Basic output structure of LALBarycenterEarth.c.
REAL8 gmstRad
Greenwich Mean Sidereal Time (GMST) in radians, at tgps.
Basic output structure produced by LALBarycenter.c.
REAL8 rDetector[3]
Cartesian coords (0=x,1=y,2=z) of detector position at $t_a$ (GPS), in ICRS J2000 coords.
REAL8 vDetector[3]
This structure contains all information about the center-of-mass positions of the Earth and Sun,...
REAL8 location[3]
INT4 gpsNanoSeconds
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
UINT4 length
number of IFOs
Definition: LALComputeAM.h:138
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
Multi-IFO time-series of DetectorStates.
UINT4 length
number of detectors
DetectorStateSeries ** data
vector of pointers to DetectorStateSeries
array of detectors definitions 'LALDetector'
UINT4 length
number of detectors
LALDetector sites[PULSAR_MAX_DETECTORS]
array of site information
A collection of (multi-IFO) LIGOTimeGPSVector time-stamps vectors.
Definition: SFTfileIO.h:198
UINT4 length
number of timestamps vectors or ifos
Definition: SFTfileIO.h:202
LIGOTimeGPSVector ** data
timestamps vector for each ifo
Definition: SFTfileIO.h:203
One noise-weight (number) per SFT (therefore indexed over IFOs and SFTs.
Definition: PSDutils.h:71
REAL8 Sinv_Tsft
normalization factor used: (using single-sided PSD!)
Definition: PSDutils.h:77
UINT4 length
number of detectors
Definition: PSDutils.h:75
REAL8Vector ** data
weights-vector for each detector
Definition: PSDutils.h:76
A collection of (multi-IFO) REAL8 time-series.
REAL8TimeSeries ** data
Pointer to the data array.
UINT4 length
Number of elements in array.
OUTER List of SFT indices.
ResampSFTMultiCountListDet * data
list per-detectors X
UINT4 length
number of detectors X
Resampling Multi List of all paired SFTs L_Y_K_X, top level (multiple pairs, multiple detectors)
UINT4 oldPairCount
count of sft pairs, old-style
REAL8 Tshort
Duration of resamp Tshort.
REAL8 maxLag
Maximum allowed lag time.
UINT4 sftTotalCount
count of all sfts
BOOLEAN inclSameDetector
Do we include same detectors?
ResampSFTPairMultiIndexList * data
list per-detector X
UINT4 length
number of detectors X
REAL8 Tsft
Duration of one SFT.
SFTIndexList * indexList
Make an overall flat index list.
UINT4 allPairCount
count of all pairs
BOOLEAN inclAutoCorr
Do we include auto-correlation?
A collection of SFT vectors – one for each IFO in a multi-IFO search.
Definition: SFTfileIO.h:179
UINT4 length
number of ifos
Definition: SFTfileIO.h:183
SFTVector ** data
sftvector for each ifo
Definition: SFTfileIO.h:184
Multi-IFO container for SSB timings.
Definition: SSBtimes.h:67
SSBtimes ** data
array of SSBtimes (pointers)
Definition: SSBtimes.h:69
UINT4 length
number of IFOs
Definition: SSBtimes.h:68
A collection of UINT4Vectors – one for each IFO
UINT4Vector ** data
unit4vector for each ifo
UINT4 length
number of ifos
Type containing the 'Doppler-parameters' affecting the time-evolution of the phase.
REAL8 period
Binary: orbital period (sec)
PulsarSpins fkdot
Intrinsic spins: [Freq, f1dot, f2dot, ...
LIGOTimeGPS refTime
Reference time of pulsar parameters (in SSB!)
REAL8 asini
Binary: projected, normalized orbital semi-major axis (s).
REAL4 * data
REAL8Sequence * data
REAL8 * data
COMPLEX8 * FabX_Raw
raw full-band FFT result Fa,Fb
COMPLEX8 * Fa_k
properly normalized F_a(f_k) over output bins
COMPLEX8Vector * TStmp2_SRC
can hold a single-detector SRC-frame spindown-corrected timeseries [without zero-padding]
COMPLEX8 * FaX_k
properly normalized F_a^X(f_k) over output bins
REAL8Vector * SRCtimes_DET
holds uniformly-spaced SRC-frame timesteps translated into detector frame [for interpolation]
fftwf_plan fftplan
buffer FFT plan for given numSamplesOut length
COMPLEX8 * TS_FFT
zero-padded, spindown-corr SRC-frame TS
COMPLEX8 * Fb_k
properly normalized F_b(f_k) over output bins
COMPLEX8 * FbX_k
properly normalized F_b^X(f_k) over output bins
COMPLEX8Vector * TStmp1_SRC
can hold a single-detector SRC-frame spindown-corrected timeseries [without zero-padding]
REAL4 sciFlag
science-or-not value: 1 is science mode, 0 is in a gap
UINT4 detInd
index of detector in list
UINT4 pairInd
index of SFT among overall pairs
UINT4 sftInd
index of SFT in list for this detector L
UINT4 flatInd
index in the flat SFT list
Resampling: List of SFT indices L for a given detector Y_K_X: indexing method is nominally original v...
UINT4 length
number of SFTs
ResampSFTIndex * data
array of SFT indices
UINT4 detInd
original vector index of detector Y
UINT4 length
number of SFTs K_X
UINT4 detInd
original vector index of detector X
ResampSFTMultiCountList * data
array of SFT L_Y indices for given SFT K_X at detector X
UINT4 sftInd
original vector index of sft K
UINT4 length
number of detectors Y
SFTCount * data
arrays of count of SFTs L_Y, at given detector Y, that match each given SFT K_X
Resampling: Multi List of indices of SFT L_Y, for a given sft K_X
ResampSFTIndexList * data
array, per detector, of lists of SFT indices
UINT4 sftInd
original vector index of sft K
UINT4 length
number of detectors Y
UINT4 flatInd
index in the flat SFT list
REAL4 sciFlag
science-or-not value: 1 is science mode, 0 is in a gap
Resampling Multi List of SFT pair indices (L_Y_K), for a given detector X.
UINT4 length
number of K SFTs at detector X
ResampSFTMultiIndexList * data
array of SFT L_Y indices for given SFT K_X at detector X
UINT4 detInd
original vector index of detector X
UINT4 sftCount
number of matching SFTs
UINT4 detInd
original vector index of detector Y
UINT4 sftInd
index of SFT in list for this detector
UINT4 detInd
index of detector in list
List of SFT indices.
UINT4 length
number of SFTs
SFTIndex * data
array of SFT indices
UINT4 sftNum[2]
ordinal numbers of first and second SFTs
List of SFT pair indices.
UINT4 length
number of SFT Pairs
SFTPairIndex * data
array of SFT Pair indices
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
A symmetric 3x3 tensor (such as detector-tensors), storing only the upper triangle.
UINT4 * data
enum @1 epoch