LALPulsar  6.1.0.1-fe68b98
PtoleMetric.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 David M. Whitbeck, Thomas Essinger-Hileman, Jolien Creighton, Ian Jones, Benjamin Owen, Reinhard Prix, Karl Wette
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19 
20 #include <math.h>
21 #include <stdlib.h>
22 #include <gsl/gsl_matrix.h>
23 #include <lal/AVFactories.h>
24 #include <lal/DetectorSite.h>
25 #include <lal/LALStdlib.h>
26 #include <lal/PtoleMetric.h>
27 #include <lal/GetEarthTimes.h>
28 #include <lal/Factorial.h>
29 
30 /* Bounds on acceptable parameters, may be somewhat arbitrary */
31 #define MIN_DURATION (LAL_DAYSID_SI/LAL_TWOPI) /* Metric acts funny if duration too short */
32 #define MIN_MAXFREQ 1. /* Arbitrary */
33 
34 /* A private factorial function */
35 /* static int factrl( int ); */
36 
37 /**
38  * \author Jones D. I., Owen, B. J., and Whitbeck, D. M.
39  * \date 2001-2005
40  * \brief Computes metric components for a pulsar search in the ``Ptolemaic''
41  * approximation; both the Earth's spin and orbit are included.
42  *
43  * ### Description ###
44  *
45  * This function computes metric components in a way that yields results
46  * very similar to those of LALCoherentMetric() called with the
47  * output of LALTBaryPtolemaic(). The CPU demand, however, is less,
48  * and the metric components can be expressed analytically, lending
49  * themselves to better understanding of the behavior of the parameter
50  * space. For short durations (less than about 70000 seconds or 20 hours) a
51  * Taylor series expansion is used to improve the accuracy with which several
52  * terms are computed.
53  *
54  * ### Algorithm ###
55  *
56  * For speed and checking reasons, a minimum of numerical computation is
57  * involved. The metric components can be expressed analytically (though not
58  * tidily) in terms of trig functions and are much too large to be worth
59  * writing down here. More comprehensive documentation on the derivation of
60  * the metric components can be found in the pulgroup CVS archive as
61  * docs/S2/FDS/Isolated/ptolemetric.tex. Jones, Owen, and Whitbeck will write
62  * up the calculation and some tests as a journal article.
63  *
64  * The function XLALGetEarthTimes() is used to calculate the spin and
65  * rotational phase of the Earth at the beginning of the observation.
66  *
67  * On output, the \a metric->data is arranged with the same indexing
68  * scheme as in LALCoherentMetric(). The order of the parameters is
69  * \f$ (f_0, \alpha, \delta) \f$ .
70  *
71  * ### Notes ###
72  *
73  * The analytic metric components were derived separately by Jones and
74  * Whitbeck (and partly by Owen) and found to agree. Also, the output of this
75  * function has been compared against that of the function combination
76  * (CoherentMetric + TDBaryPtolemaic), which is a numerical implementation of
77  * the Ptolemaic approximation, and found to agree up to the fourth
78  * significant figure or better. Even using DTEphemeris.c for the true
79  * Earth's orbit only causes errors in the metric components of order 10\%,
80  * with (so far) no noticeable effect on the sky coverage.
81  *
82  * At present, only one spindown parameter can be included with the sky
83  * location. The code contains (commented out) expressions for
84  * spindown-spindown metric components for an arbitrary number of spindowns,
85  * but the (commented out) spindown-sky components neglect orbital motion.
86  *
87  * A separate routine, XLALSpindownMetric(), has been added to compute the
88  * metric for multiple spindowns but for fixed sky position, suitable for
89  * e.g. directed searches.
90  */
92  REAL8Vector *metric,
93  PtoleMetricIn *input )
94 {
95  INT2 j; /* Loop counters */
96  /*REAL8 temp1, temp2, temp3, temp4; dummy variables */
97  REAL8 R_o, R_s; /* Amplitude of daily/yearly modulation, s */
98  REAL8 lat, lon; /* latitude and longitude of detector site */
99  REAL8 omega_s, omega_o; /* Ang freq of daily/yearly modulation, rad/s */
100  REAL8 phi_o_i; /* Phase of Earth's orbit at begining (epoch) */
101  REAL8 phi_o_f; /* Phase of Earth's orbit at end (epoch+duration) */
102  REAL8 phi_s_i; /* Phase of Earth's spin at beginning (epoch) */
103  REAL8 phi_s_f; /* Phase of Earth's spin at end (epoch+duration) */
104  REAL8 cos_l, sin_l, sin_2l; /* Trig fns for detector lattitude */
105  REAL8 cos_i, sin_i; /* Trig fns for inclination of Earth's spin */
106  REAL8 cos_a, sin_a, sin_2a; /* Trig fns for source RA */
107  REAL8 cos_d, sin_d, sin_2d; /* Trig fns for source declination */
108  REAL8 A[22]; /* Array of intermediate quantities */
109  REAL8 B[10]; /* Array of intermediate quantities */
110  REAL8 Is[5]; /* Array of integrals needed for spindown.*/
111  UINT2 dim; /* Dimension of parameter space */
112  REAL8 tMidnight, tAutumn; /* Needed to calculate phases of spin*/
113  /* and orbit at t_gps =0 */
114  REAL8Vector *big_metric; /* 10-dim metric in (phi,f,a,d,f1) for internal use */
115  REAL8 T; /* Duration of observation */
116  REAL8 f; /* Frequency */
117  /* Some useful short-hand notations involving the orbital phase: */
118  REAL8 D_p_o;
119  REAL8 sin_p_o;
120  REAL8 cos_p_o;
121  REAL8 D_sin_p_o;
122  REAL8 D_cos_p_o;
123  REAL8 D_sin_2p_o;
124  REAL8 D_cos_2p_o;
125  /* Some useful short-hand notations involving the spin phase: */
126  REAL8 D_p_s;
127  REAL8 sin_p_s;
128  REAL8 cos_p_s;
129  REAL8 D_sin_p_s;
130  REAL8 D_cos_p_s;
131  REAL8 D_sin_2p_s;
132  REAL8 D_cos_2p_s;
133  /* Some useful short-hand notations involving spin and orbital phases: */
134  REAL8 D_sin_p_o_plus_s;
135  REAL8 D_sin_p_o_minus_s;
136  REAL8 D_cos_p_o_plus_s;
137  REAL8 D_cos_p_o_minus_s;
138  /* Quantities related to the short-time Tatlor expansions : */
139  REAL8 D_p_o_crit; /* The orbital phase BELOW which series used. */
140  REAL8 sum1, sum2, sum3;
141  REAL8 next1, next2, next3;
142  INT2 j_max; /* Number of terms in series */
143 
144 
145  INITSTATUS( status );
146 
147  /* Check for valid input structure. */
148  ASSERT( input != NULL, status, PTOLEMETRICH_ENULL,
150 
151  /* Check for valid sky position. */
158  ASSERT( fabs( input->position.latitude ) <= LAL_PI_2, status,
160 
161  /* Check for valid maximum frequency. */
164 
165  /* Check for valid detector location. */
170 
171  if ( input->spindown ) {
172  dim = 2 + input->spindown->length;
173  } else {
174  dim = 2;
175  }
176  ASSERT( metric != NULL, status, PTOLEMETRICH_ENULL,
178  ASSERT( metric->data != NULL, status, PTOLEMETRICH_ENULL,
180  ASSERT( metric->length == ( UINT4 )( dim + 1 ) * ( dim + 2 ) / 2, status, PTOLEMETRICH_EDIM,
182 
183  /* A bigger metric that includes phase for internal use only: */
184  /* Apart from normalization, this is just the information matrix. */
185  big_metric = NULL;
186  LALDCreateVector( status, &big_metric, ( dim + 2 ) * ( dim + 3 ) / 2 );
187 
188  /* Detector location: */
189  lat = input->site->frDetector.vertexLatitudeRadians;
190  lon = input->site->frDetector.vertexLongitudeRadians;
191  cos_l = cos( lat );
192  sin_l = sin( lat );
193  sin_2l = sin( 2 * lat );
194 
195  /* Inclination of Earth's spin-axis to ecliptic */
196  sin_i = sin( LAL_IEARTH );
197  cos_i = cos( LAL_IEARTH );
198 
199  /* Radii of circular motions in seconds: */
200  R_s = LAL_REARTH_SI / LAL_C_SI;
201  R_o = LAL_AU_SI / LAL_C_SI;
202 
203  /* To switch off orbital motion uncomment this: */
204  /* R_o = 0.0; */
205 
206  /* To switch off spin motion uncomment this: */
207  /* R_s = 0.0; */
208 
209  /* Angular velocities: */
210  omega_s = LAL_TWOPI / LAL_DAYSID_SI;
211  omega_o = LAL_TWOPI / LAL_YRSID_SI;
212 
213  /* Duration of observation */
214  T = input->duration;
215 
216  /* Frequency: */
217  f = input->maxFreq;
218 
219  /* Source RA: */
220  sin_a = sin( input->position.longitude );
221  cos_a = cos( input->position.longitude );
222  sin_2a = sin( 2 * ( input->position.longitude ) );
223 
224  /* Source declination: */
225  sin_d = sin( input->position.latitude );
226  cos_d = cos( input->position.latitude );
227  sin_2d = sin( 2 * ( input->position.latitude ) );
228 
229  /* Calculation of phases of spin and orbit at start: */
230  XLAL_CHECK_LAL( status, XLALGetEarthTimes( &input->epoch, &tMidnight, &tAutumn ) == XLAL_SUCCESS, XLAL_EFUNC );
231  phi_o_i = -tAutumn / LAL_YRSID_SI * LAL_TWOPI;
232  phi_s_i = -tMidnight / LAL_DAYSID_SI * LAL_TWOPI + lon;
233 
234 
235  /* Quantities involving the orbital phase: */
236  phi_o_f = phi_o_i + omega_o * T;
237  D_p_o = omega_o * T;
238  sin_p_o = sin( phi_o_f );
239  cos_p_o = cos( phi_o_f );
240  D_sin_p_o = ( sin( phi_o_f ) - sin( phi_o_i ) ) / D_p_o;
241  D_cos_p_o = ( cos( phi_o_f ) - cos( phi_o_i ) ) / D_p_o;
242  D_sin_2p_o = ( sin( 2 * phi_o_f ) - sin( 2 * phi_o_i ) ) / 2.0 / D_p_o;
243  D_cos_2p_o = ( cos( 2 * phi_o_f ) - cos( 2 * phi_o_i ) ) / 2.0 / D_p_o;
244 
245  /* Quantities involving the spin phase: */
246  phi_s_f = phi_s_i + omega_s * T;
247  D_p_s = omega_s * T;
248  sin_p_s = sin( phi_s_f );
249  cos_p_s = cos( phi_s_f );
250  D_sin_p_s = ( sin( phi_s_f ) - sin( phi_s_i ) ) / D_p_s;
251  D_cos_p_s = ( cos( phi_s_f ) - cos( phi_s_i ) ) / D_p_s;
252  D_sin_2p_s = ( sin( 2 * phi_s_f ) - sin( 2 * phi_s_i ) ) / 2.0 / D_p_s;
253  D_cos_2p_s = ( cos( 2 * phi_s_f ) - cos( 2 * phi_s_i ) ) / 2.0 / D_p_s;
254 
255  /* Some mixed quantities: */
256  D_sin_p_o_plus_s
257  = ( sin( phi_o_f + phi_s_f ) - sin( phi_o_i + phi_s_i ) ) / ( D_p_o + D_p_s );
258  D_sin_p_o_minus_s
259  = ( sin( phi_o_f - phi_s_f ) - sin( phi_o_i - phi_s_i ) ) / ( D_p_o - D_p_s );
260  D_cos_p_o_plus_s
261  = ( cos( phi_o_f + phi_s_f ) - cos( phi_o_i + phi_s_i ) ) / ( D_p_o + D_p_s );
262  D_cos_p_o_minus_s
263  = ( cos( phi_o_f - phi_s_f ) - cos( phi_o_i - phi_s_i ) ) / ( D_p_o - D_p_s );
264 
265 
266 
267  /***************************************************************/
268  /* Small D_p_o overwrite: */
269  /***************************************************************/
270  j_max = 7;
271  D_p_o_crit = 1.4e-2; /* This corresponds to about 70000 seconds */
272 
273  sum1 = next1 = D_p_o / 2.0;
274  sum2 = next2 = D_p_o / 3.0 / 2.0;
275  sum3 = next3 = D_p_o;
276 
277  for ( j = 1; j <= j_max; j++ ) {
278  next1 *= -pow( D_p_o, 2.0 ) / ( 2.0 * j + 1.0 ) / ( 2.0 * j + 2.0 );
279  sum1 += next1;
280  next2 *= -pow( D_p_o, 2.0 ) / ( 2.0 * j + 2.0 ) / ( 2.0 * j + 3.0 );
281  sum2 += next2;
282  next3 *= -pow( 2.0 * D_p_o, 2.0 ) / ( 2.0 * j + 1.0 ) / ( 2.0 * j + 2.0 );
283  sum3 += next3;
284  }
285 
286  if ( D_p_o < D_p_o_crit ) {
287  D_sin_p_o = sin( phi_o_f ) * sum1 + cos( phi_o_f ) * sin( D_p_o ) / D_p_o;
288  D_cos_p_o = cos( phi_o_f ) * sum1 - sin( phi_o_f ) * sin( D_p_o ) / D_p_o;
289  D_sin_2p_o
290  = sin( 2.0 * phi_o_f ) * sum3 + cos( 2.0 * phi_o_f ) * sin( 2.0 * D_p_o ) / 2.0 / D_p_o;
291  D_cos_2p_o
292  = cos( 2.0 * phi_o_f ) * sum3 - sin( 2.0 * phi_o_f ) * sin( 2.0 * D_p_o ) / 2.0 / D_p_o;
293  }
294  /****************************************************************/
295 
296 
297  /* The A[i] quantities: */
298  A[1] =
299  R_o * D_sin_p_o + R_s * cos_l * D_sin_p_s;
300 
301  A[2] =
302  R_o * cos_i * D_cos_p_o + R_s * cos_l * D_cos_p_s;
303 
304  A[3] =
305  -R_o * sin_i * D_cos_p_o + R_s * sin_l;
306 
307  A[4] =
308  R_o * ( sin_p_o / D_p_o + D_cos_p_o / D_p_o );
309 
310  A[5] =
311  R_s * ( sin_p_s / D_p_s + D_cos_p_s / D_p_s );
312 
313  A[6] =
314  R_o * ( -cos_p_o / D_p_o + D_sin_p_o / D_p_o );
315 
316  /* Special overwrite for A4 and A6: *********************/
317  if ( D_p_o < D_p_o_crit ) {
318  A[4] = R_o * ( cos( phi_o_f ) * sum1 / D_p_o + sin( phi_o_f ) * sum2 );
319  A[6] = R_o * ( sin( phi_o_f ) * sum1 / D_p_o - cos( phi_o_f ) * sum2 );
320  }
321  /***********************************************************/
322 
323  A[7] =
324  R_s * ( -cos_p_s / D_p_s + D_sin_p_s / D_p_s );
325 
326  A[8] =
327  R_o * R_o * ( 1 + D_sin_2p_o );
328 
329  A[9] =
330  R_o * R_s * ( D_sin_p_o_minus_s + D_sin_p_o_plus_s );
331 
332  A[10] =
333  R_s * R_s * ( 1 + D_sin_2p_s );
334 
335  A[11] =
336  R_o * R_o * D_cos_2p_o;
337 
338  A[12] =
339  R_o * R_s * ( -D_cos_p_o_minus_s + D_cos_p_o_plus_s );
340 
341  A[13] =
342  R_o * R_s * ( D_cos_p_o_minus_s + D_cos_p_o_plus_s );
343 
344  A[14] =
345  R_s * R_s * D_cos_2p_s;
346 
347  A[15] =
348  R_o * R_o * ( 1 - D_sin_2p_o );
349 
350  A[16] =
351  R_o * R_s * ( D_sin_p_o_minus_s - D_sin_p_o_plus_s );
352 
353  A[17] =
354  R_s * R_s * ( 1 - D_sin_2p_s );
355 
356  A[18] =
357  R_o * R_s * D_sin_p_o;
358 
359  A[19] =
360  R_s * R_s * D_sin_p_s;
361 
362  A[20] =
363  R_o * R_s * D_cos_p_o;
364 
365  A[21] =
366  R_s * R_s * D_cos_p_s;
367 
368 
369  /* The B[i] quantities: */
370  B[1] =
371  A[4] + A[5] * cos_l;
372 
373  B[2] =
374  A[6] * cos_i + A[7] * cos_l;
375 
376  B[3] =
377  A[6] * sin_i + R_s * sin_l / 2;
378 
379  B[4] =
380  A[8] + 2 * A[9] * cos_l + A[10] * cos_l * cos_l;
381 
382  B[5] =
383  A[11] * cos_i + A[12] * cos_l + A[13] * cos_i * cos_l + A[14] * cos_l * cos_l;
384 
385  B[6] =
386  A[15] * cos_i * cos_i + 2 * A[16] * cos_i * cos_l + A[17] * cos_l * cos_l;
387 
388  B[7] =
389  -A[11] * sin_i + 2 * A[18] * sin_l - A[13] * sin_i * cos_l + A[19] * sin_2l;
390 
391  B[8] =
392  A[15] * sin_i * cos_i - 2 * A[20] * cos_i * sin_l + A[16] * sin_i * cos_l - A[21] * sin_2l;
393 
394  B[9] =
395  A[15] * sin_i * sin_i - 4 * A[20] * sin_i * sin_l + 2 * R_s * R_s * sin_l * sin_l;
396 
397  /* The spindown integrals. */
398 
399  /* orbital t^2 cos */
400 
401  Is[1] = ( 2 * sin( phi_o_i ) + 2 * omega_o * T * cos_p_o + ( -2 + pow( omega_o * T, 2 ) ) * sin_p_o ) / pow( omega_o * T, 3 );
402 
403  /* spin t^2 cos */
404  Is[2] = ( 2 * sin( phi_s_i ) + 2 * omega_s * T * cos_p_s + ( -2 + pow( omega_s * T, 2 ) ) * sin_p_s ) / pow( omega_s * T, 3 );
405 
406  /* orbital t^2 sin */
407  Is[3] = ( -2 * cos( phi_o_i ) + 2 * omega_o * T * sin_p_o - ( -2 + pow( omega_o * T, 2 ) ) * cos_p_o ) / pow( omega_o * T, 3 );
408 
409  /*spin t^2 sin */
410 
411  Is[4] = ( -2 * cos( phi_s_i ) + 2 * omega_s * T * sin_p_s - ( -2 + pow( omega_s * T, 2 ) ) * cos_p_s ) / pow( omega_s * T, 3 );
412 
413 
414 
415  /* The 4-dim metric components: */
416  /* g_pp = */
417  big_metric->data[0] =
418  1;
419 
420  /* g_pf = */
421  big_metric->data[1] =
422  LAL_PI * T;
423 
424  /* g_pa = */
425  big_metric->data[3] =
426  -LAL_TWOPI * f * cos_d * ( A[1] * sin_a + A[2] * cos_a );
427 
428  /* g_pd = */
429  big_metric->data[6] =
430  LAL_TWOPI * f * ( -A[1] * sin_d * cos_a + A[2] * sin_d * sin_a + A[3] * cos_d );
431 
432  /* g_ff = */
433  big_metric->data[2] =
434  pow( LAL_TWOPI * T, 2 ) / 3;
435 
436  /* g_fa = */
437  big_metric->data[4] =
438  pow( LAL_TWOPI, 2 ) * f * cos_d * T * ( -B[1] * sin_a + B[2] * cos_a );
439 
440  /* g_fd = */
441  big_metric->data[7] =
442  pow( LAL_TWOPI, 2 ) * f * T * ( -B[1] * sin_d * cos_a - B[2] * sin_d * sin_a + B[3] * cos_d );
443 
444  /* g_aa = */
445  big_metric->data[5] =
446  2 * pow( LAL_PI * f * cos_d, 2 ) * ( B[4] * sin_a * sin_a + B[5] * sin_2a + B[6] * cos_a * cos_a );
447 
448  /* g_ad = */
449  big_metric->data[8] =
450  2 * pow( LAL_PI * f, 2 ) * cos_d * ( B[4] * sin_a * cos_a * sin_d - B[5] * sin_a * sin_a * sin_d
451  - B[7] * sin_a * cos_d + B[5] * cos_a * cos_a * sin_d - B[6] * sin_a * cos_a * sin_d
452  + B[8] * cos_a * cos_d );
453 
454  /* g_dd = */
455  big_metric->data[9] =
456  2 * pow( LAL_PI * f, 2 ) * ( B[4] * pow( cos_a * sin_d, 2 ) + B[6] * pow( sin_a * sin_d, 2 )
457  + B[9] * pow( cos_d, 2 ) - B[5] * sin_2a * pow( sin_d, 2 ) - B[8] * sin_a * sin_2d
458  - B[7] * cos_a * sin_2d );
459 
460  /*The spindown components*/
461  if ( dim == 3 ) {
462  /* g_p1 = */
463  big_metric->data[10] =
464  T * LAL_PI * f * T / 3;
465 
466  /* g_f1= */
467  big_metric->data[11] =
468  T * pow( LAL_PI * T, 2 ) * f / 2;
469 
470  /* g_a1 = */
471  big_metric->data[12] = T * 2 * pow( LAL_PI * f, 2 ) * T * ( -cos_d * sin_a * ( R_o * Is[1] + R_s * cos_l * Is[2] ) + cos_d * cos_a * ( R_o * cos_i * Is[3] + R_s * cos_l * Is[4] ) );
472 
473  /* g_d1 = */
474  big_metric->data[13] = T * 2 * pow( LAL_PI * f, 2 ) * T * ( -sin_d * cos_a * ( R_o * Is[1] + R_s * cos_l * Is[2] ) - sin_d * sin_a * ( R_o * cos_i * Is[3] + R_s * cos_l * Is[4] ) + cos_d * ( R_o * sin_i * Is[3] + R_s * sin_l / 3 ) );
475 
476  /* g_11 = */
477  big_metric->data[14] = T * T * pow( LAL_PI * f * T, 2 ) / 5;
478  }
479 
480 
481  /**********************************************************/
482  /* Spin-down stuff not consistent with rest of code - don't uncomment! */
483  /* Spindown-spindown metric components, before projection
484  if( input->spindown )
485  for (j=1; j<=dim-2; j++)
486  for (k=1; k<=j; k++)
487  metric->data[(k+2)+(j+2)*(j+3)/2] = pow(LAL_TWOPI*input->maxFreq
488  *input->duration,2)/(j+2)/(k+2)/(j+k+3);
489 
490  Spindown-angle metric components, before projection
491  if( input->spindown )
492  for (j=1; j<=(INT4)input->spindown->length; j++) {
493 
494  Spindown-RA: 1+(j+2)*(j+3)/2
495  metric->data[1+(j+2)*(j+3)/2] = 0;
496  temp1=0;
497  temp2=0;
498  for (k=j+1; k>=0; k--) {
499  metric->data[1+(j+2)*(j+3)/2] += pow(-1,(k+1)/2)*factrl(j+1)
500  /factrl(j+1-k)/pow(D_p_s,k)*((k%2)?sin_p_s:cos_p_s);
501  metric->data[1+(j+2)*(j+3)/2] += pow(-1,j/2)/pow(D_p_s,j+1)*factrl(j+1)
502  *((j%2)?cos(phi_s_i):sin(phi_s_i));
503  metric->data[1+(j+2)*(j+3)/2] -= (cos_p_s-cos(phi_s_i))/(j+2);
504  metric->data[1+(j+2)*(j+3)/2] *= -pow(LAL_TWOPI*input->maxFreq,2)*R_s*cos_l
505  *cos_d/omega_s/(j+1);
506  temp1+=pow(-1,(k+1)/2)*factrl(j+1)
507  /factrl(j+1-k)/pow(D_p_s,k)*((k%2)?sin_p_s:cos_p_s);
508  temp2+=pow(-1,(k+1)/2)*factrl(j+1)
509  /factrl(j+1-k)/pow(D_p_o,k)*((k%2)?sin_p_o:cos_p_o);
510  }
511  temp1+=pow(-1,j/2)/pow(D_p_s,j+1)*factrl(j+1)
512  *((j%2)?cos(phi_s_i):sin(phi_s_i));
513  temp2+=pow(-1,j/2)/pow(D_p_o,j+1)*factrl(j+1)
514  *((j%2)?cos(phi_o_i):sin(phi_o_i));
515  temp1-=(cos_p_s-cos(phi_s_i))/(j+2);
516  temp2-=(cos_p_o-cos(phi_o_i))/(j+2);
517  temp1*=-pow(LAL_TWOPI*input->maxFreq,2)*R_s*cos_l
518  *cos_d/omega_s/(j+1);
519  temp2*=-pow(LAL_TWOPI*input->maxFreq,2)*R_o*cos_i
520  *cos_d/omega_o/(j+1);
521  metric->data[1+(j+2)*(j+3)/2]+=temp1+temp2;
522  Spindown-dec: 2+(j+2)*(j+3)/2
523  metric->data[2+(j+2)*(j+3)/2] = 0;
524  temp3=0;
525  temp4=0;
526  for (k=j+1; k>=0; k--) {
527  metric->data[2+(j+2)*(j+3)/2] -= pow(-1,k/2)*factrl(j+1)/factrl(j+1-k)
528  /pow(D_p_s,k)*((k%2)?cos_p_s:sin_p_s);
529  metric->data[2+(j+2)*(j+3)/2] += pow(-1,(j+1)/2)/pow(D_p_s,j+1)
530  *factrl(j+1)*((j%2)?sin(phi_s_i):cos(phi_s_i));
531  metric->data[2+(j+2)*(j+3)/2] += (sin_p_s-sin(phi_s_i))/(j+2);
532  metric->data[2+(j+2)*(j+3)/2] *= pow(LAL_TWOPI*input->maxFreq,2)*R_s*cos_l
533  *sin_d/omega_s/(j+1);
534  } for( j... )
535  temp3-=pow(-1,k/2)*factrl(j+1)/factrl(j+1-k)
536  /pow(D_p_s,k)*((k%2)?cos_p_s:sin_p_s);
537  temp4-=pow(-1,k/2)*factrl(j+1)/factrl(j+1-k)
538  /pow(D_p_o,k)*((k%2)?cos_p_o:sin_p_o);
539  }
540  temp3+=pow(-1,(j+1)/2)/pow(D_p_s,j+1)
541  *factrl(j+1)*((j%2)?sin(phi_s_i):cos(phi_s_i));
542  temp4+=pow(-1,(j+1)/2)/pow(D_p_o,j+1)
543  *factrl(j+1)*((j%2)?sin(phi_o_i):cos(phi_o_i));
544  temp3+=(sin_p_s-sin(phi_s_i))/(j+2);
545  temp4+=(sin_p_o-sin(phi_o_i))/(j+2);
546  temp3*=pow(LAL_TWOPI*input->maxFreq,2)*R_s*cos_l
547  *sin_d/omega_s/(j+1);
548  temp4*=pow(LAL_TWOPI*input->maxFreq,2)*R_s*cos_i
549  *sin_d/omega_o/(j+1);
550  metric->data[2+(j+2)*(j+3)/2]=temp3+temp4;
551  }
552  f0-spindown : 0+(j+2)*(j+3)/2
553  if( input->spindown )
554  for (j=1; j<=dim-2; j++)
555  metric->data[(j+2)*(j+3)/2] = 2*pow(LAL_PI,2)*input->maxFreq
556  *pow(input->duration,2)/(j+2)/(j+3);*/
557  /*************************************************************/
558 
559 
560  /* Project down to 4-dim metric: */
561 
562  /*f-f component */
563  metric->data[0] = big_metric->data[2]
564  - big_metric->data[1] * big_metric->data[1] / big_metric->data[0];
565  /*f-a component */
566  metric->data[1] = big_metric->data[4]
567  - big_metric->data[1] * big_metric->data[3] / big_metric->data[0];
568  /*a-a component */
569  metric->data[2] = big_metric->data[5]
570  - big_metric->data[3] * big_metric->data[3] / big_metric->data[0];
571  /*f-d component */
572  metric->data[3] = big_metric->data[7]
573  - big_metric->data[6] * big_metric->data[1] / big_metric->data[0];
574  /*a-d component */
575  metric->data[4] = big_metric->data[8]
576  - big_metric->data[6] * big_metric->data[3] / big_metric->data[0];
577  /*d-d component */
578  metric->data[5] = big_metric->data[9]
579  - big_metric->data[6] * big_metric->data[6] / big_metric->data[0];
580  if ( dim == 3 ) {
581 
582  /*f-f1 component */
583  metric->data[6] = big_metric->data[11]
584  - big_metric->data[1] * big_metric->data[10] / big_metric->data[0];
585 
586  /*a-f1 component */
587  metric->data[7] = big_metric->data[12]
588  - big_metric->data[3] * big_metric->data[10] / big_metric->data[0];
589 
590  /*d-f1 component */
591  metric->data[8] = big_metric->data[13]
592  - big_metric->data[6] * big_metric->data[10] / big_metric->data[0];
593 
594  /* f1-f1 component */
595  metric->data[9] = big_metric->data[14]
596  - big_metric->data[10] * big_metric->data[10] / big_metric->data[0];
597  }
598 
599  LALDDestroyVector( status, &big_metric );
600  /* All done */
601  RETURN( status );
602 } /* LALPtoleMetric() */
603 
604 
605 /* This is a dead simple, no error-checking, private factorial function. */
606 /* static int factrl( int arg ) */
607 /* { */
608 /* int ans = 1; */
609 
610 /* if (arg==0) return 1; */
611 /* do { */
612 /* ans *= arg; */
613 /* } */
614 /* while(--arg>0); */
615 /* return ans; */
616 /* } */ /* factrl() */
617 
618 
619 /**
620  * \brief Unified "wrapper" to provide a uniform interface to LALPtoleMetric() and LALCoherentMetric().
621  * \author Reinhard Prix
622  *
623  * The parameter structure of LALPtoleMetric() was used, because it's more compact.
624  */
626  REAL8Vector **metric,
627  PtoleMetricIn *input )
628 {
629  UINT4 nSpin, dim;
630 
631  INITSTATUS( stat );
633 
637 
638  if ( input->spindown ) {
639  nSpin = input->spindown->length;
640  } else {
641  nSpin = 0;
642  }
643 
644 
645  /* allocate the output-metric */
646  dim = 3 + nSpin; /* dimensionality of parameter-space: Alpha,Delta,f + spindowns */
647 
648  TRY( LALDCreateVector( stat->statusPtr, metric, dim * ( dim + 1 ) / 2 ), stat );
649 
650  switch ( input->metricType ) {
651  case LAL_PMETRIC_COH_PTOLE_ANALYTIC: /* use Ben&Ian's analytic ptolemaic metric */
652  LALPtoleMetric( stat->statusPtr, *metric, input );
653  BEGINFAIL( stat ) {
654  LALDDestroyVector( stat->statusPtr, metric );
655  }
656  ENDFAIL( stat );
657  break;
658 
659  default:
660  XLALPrintError( "Unknown metric type `%d`\n", input->metricType );
662  break;
663 
664  } /* switch type */
665 
667  RETURN( stat );
668 
669 } /* LALPulsarMetric() */
670 
671 
672 /**
673  * \brief Project out the zeroth dimension of a metric.
674  * \author Creighton, T. D.
675  * \date 2000
676  *
677  * ### Description ###
678  *
679  * This function takes a metric \f$ g_{\alpha\beta} \f$ , where
680  * \f$ \alpha,\beta=0,1,\ldots,n \f$ , and computes the projected metric
681  * \f$ \gamma_{ij} \f$ on the subspace \f$ i,j=1,\ldots,n \f$ , as described in the
682  * header StackMetric.h.
683  *
684  * The argument \a *metric stores the metric components in the manner
685  * used by the functions LALCoherentMetric() and
686  * LALStackMetric(), and \a errors indicates whether error
687  * estimates are included in \a *metric. Thus \a *metric is a
688  * vector of length \f$ (n+1)(n+2)/2 \f$ if \a errors is zero, or of length
689  * \f$ (n+1)(n+2) \f$ if \a errors is nonzero; see LALCoherentMetric()
690  * for the indexing scheme.
691  *
692  * Upon return, \a *metric stores the components of \f$ \gamma_{ij} \f$ in
693  * the same manner as above, with the physically meaningless components
694  * \f$ \gamma_{\alpha0} = \gamma_{0\alpha} \f$ (and their uncertainties) set
695  * identically to zero.
696  *
697  * ### Algorithm ###
698  *
699  * The function simply implements \eqref{eq_gij_gab} in
700  * StackMetric.h. The formula used to convert uncertainties
701  * \f$ s_{\alpha\beta} \f$ in the metric components \f$ g_{\alpha\beta} \f$ into
702  * uncertainties \f$ \sigma_{ij} \f$ in \f$ \gamma_{ij} \f$ is:
703  * \f[
704  * \sigma_{ij} = s_{ij}
705  * + s_{0i}\left|\frac{g_{0j}}{g_{00}}\right|
706  * + s_{0j}\left|\frac{g_{0i}}{g_{00}}\right|
707  * + s_{00}\left|\frac{g_{0i}g_{0j}}{(g_{00})^2}\right| \; .
708  * \f]
709  * Note that if the metric is highly degenerate, one may find that one or
710  * more projected components are comparable in magnitude to their
711  * estimated numerical uncertainties. This can occur when the
712  * observation times are very short or very long compared to the
713  * timescales over which the timing derivatives are varying. In the
714  * former case, one is advised to use analytic approximations or a
715  * different parameter basis. In the latter case, the degenerate
716  * components are often not relevant for data analysis, and can be
717  * effectively set to zero.
718  *
719  * Technically, starting from a full metric
720  * \f$ g_{\alpha\beta}(\mathbf{\lambda}) \f$ , the projection
721  * \f$ \gamma_{ij}(\vec\lambda) \f$ is the metric of a subspace
722  * \f$ \{\vec\lambda\} \f$ passing through the point \f$ \mathbf{\lambda} \f$ on a plane
723  * orthogonal to the \f$ \lambda^0 \f$ axis. In order for \f$ \gamma_{ij} \f$ to
724  * measure the \em maximum distance between points \f$ \vec\lambda \f$ , it
725  * is important to evaluate \f$ g_{\alpha\beta} \f$ at the value of \f$ \lambda^0 \f$
726  * that gives the largest possible separations. For the pulsar search
727  * formalism discussed in StackMetric.h, this is always
728  * achieved by choosing the largest value of \f$ \lambda^0=f_\mathrm{max} \f$
729  * that is to be covered in the search.
730  */
731 void
733 {
734  UINT4 s; /* The number of parameters before projection. */
735  UINT4 i, j; /* Indecies. */
736  REAL8 *data; /* The metric data array. */
737 
738  INITSTATUS( stat );
739 
740  /* Check that data exist. */
743  data = metric->data;
744 
745  /* Make sure the metric's length is compatible with some
746  dimensionality s. */
747  for ( s = 0, i = 1; i < metric->length; s++ ) {
748  i = s * ( s + 1 );
749  if ( !errors ) {
750  i = i >> 1;
751  }
752  }
753  s--; /* counteract the final s++ */
754  ASSERT( i == metric->length, stat, PTOLEMETRICH_EPARM,
756 
757  /* Now project out the zeroth component of the metric. */
758  for ( i = 1; i < s; i++ )
759  for ( j = 1; j <= i; j++ ) {
760  INT4 i0 = ( i * ( i + 1 ) ) >> 1;
761  INT4 myj0 = ( j * ( j + 1 ) ) >> 1;
762  INT4 ij = i0 + j;
763  if ( errors ) {
764  data[2 * ij] -= data[2 * i0] * data[2 * myj0] / data[0];
765  data[2 * ij + 1] += data[2 * i0 + 1] * fabs( data[2 * myj0] / data[0] )
766  + data[2 * myj0 + 1] * fabs( data[2 * i0] / data[0] )
767  + data[1] * fabs( data[2 * i0] / data[0] ) * fabs( data[2 * myj0] / data[0] );
768  } else {
769  data[ij] -= data[i0] * data[myj0] / data[0];
770  }
771  }
772 
773  /* Set all irrelevant metric coefficients to zero. */
774  for ( i = 0; i < s; i++ ) {
775  INT4 i0 = i * ( i + 1 ) >> 1;
776  if ( errors ) {
777  data[2 * i0] = data[2 * i0 + 1] = 0.0;
778  } else {
779  data[i0] = 0.0;
780  }
781  }
782 
783  /* And that's it! */
784  RETURN( stat );
785 }
786 
787 
788 /**
789  * \brief Figure out dimension of a REAL8Vector -encoded metric (see PMETRIC_INDEX() ).
790  * Return error if input-vector is NULL or not consistent with a quadratic matrix.
791  */
792 int
794 {
795  UINT4 dim;
796  UINT4 length;
797  UINT4 trylength;
798 
799  if ( !metric ) {
800  XLALPrintError( "\nNULL Input received!\n\n" );
802  }
803 
804  length = metric->length;
805  if ( length == 0 ) {
806  return 0;
807  }
808 
809  dim = 1;
810  while ( ( trylength = dim * ( dim + 1 ) / 2 ) <= length ) {
811  if ( length == trylength ) {
812  return dim;
813  } else {
814  dim ++;
815  }
816  }
817 
818  /* no fitting dimension found ==> error */
819  XLALPrintError( "\nInput vector is inconsisten with symmetric quadratic matrix!\n\n" );
821 
822 }/* XLALFindMetricDim() */
823 
824 /**
825  * Frequency and frequency derivative components of the metric, suitable for a directed
826  * search with only one fixed sky position. The units are those expected by ComputeFstat.
827  */
829  gsl_matrix *metric, /**< [in] Matrix containing the metric */
830  double Tspan /**< [in] Time span of the data set */
831 )
832 {
833 
834  // Check input
835  XLAL_CHECK( metric != NULL, XLAL_EFAULT );
836  XLAL_CHECK( metric->size1 == metric->size2, XLAL_ESIZE );
837  XLAL_CHECK( Tspan > 0, XLAL_EINVAL );
838 
839  // Calculate metric
840  for ( size_t i = 0; i < metric->size1; ++i ) {
841  for ( size_t j = i; j < metric->size2; ++j ) {
842  gsl_matrix_set( metric, i, j, (
843  4.0 * LAL_PI * LAL_PI * pow( Tspan, i + j + 2 ) * ( i + 1 ) * ( j + 1 )
844  ) / (
845  LAL_FACT[i + 1] * LAL_FACT[j + 1] * ( i + 2 ) * ( j + 2 ) * ( i + j + 3 )
846  ) );
847  gsl_matrix_set( metric, j, i, gsl_matrix_get( metric, i, j ) );
848  }
849  }
850 
851  return XLAL_SUCCESS;
852 
853 } // XLALSpindownMetric
int j
#define ABORT(statusptr, code, mesg)
#define XLAL_CHECK_LAL(sp, assertion,...)
#define ENDFAIL(statusptr)
#define TRY(func, statusptr)
#define ATTATCHSTATUSPTR(statusptr)
#define ASSERT(assertion, statusptr, code, mesg)
#define DETATCHSTATUSPTR(statusptr)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
#define BEGINFAIL(statusptr)
#define MIN_MAXFREQ
Definition: PtoleMetric.c:32
UINT2 A
Definition: SFTnaming.c:46
UINT2 B
Definition: SFTnaming.c:47
int s
static const UINT8 LAL_FACT[]
int XLALGetEarthTimes(const LIGOTimeGPS *tepoch, REAL8 *tMidnight, REAL8 *tAutumn)
This function takes a GPS time from tepoch and uses it to assign tAutumn and tMidnight,...
Definition: GetEarthTimes.c:76
#define LAL_PI_2
#define LAL_IEARTH
#define LAL_DAYSID_SI
#define LAL_PI
#define LAL_YRSID_SI
#define LAL_TWOPI
unsigned char BOOLEAN
double REAL8
int16_t INT2
uint16_t UINT2
uint32_t UINT4
int32_t INT4
#define PTOLEMETRICH_MSGEPARM
Definition: PtoleMetric.h:87
#define PTOLEMETRICH_EDIM
Definition: PtoleMetric.h:82
#define PTOLEMETRICH_MSGEMETRIC
Definition: PtoleMetric.h:90
#define PTOLEMETRICH_MSGENONULL
Definition: PtoleMetric.h:89
void LALPtoleMetric(LALStatus *status, REAL8Vector *metric, PtoleMetricIn *input)
Computes metric components for a pulsar search in the `‘Ptolemaic’' approximation; both the Earth's s...
Definition: PtoleMetric.c:91
#define PTOLEMETRICH_ENULL
Definition: PtoleMetric.h:80
void LALProjectMetric(LALStatus *stat, REAL8Vector *metric, BOOLEAN errors)
Project out the zeroth dimension of a metric.
Definition: PtoleMetric.c:732
#define PTOLEMETRICH_EPARM
Definition: PtoleMetric.h:81
#define PTOLEMETRICH_MSGEDIM
Definition: PtoleMetric.h:88
#define PTOLEMETRICH_EMETRIC
Definition: PtoleMetric.h:84
int XLALSpindownMetric(gsl_matrix *metric, double Tspan)
Frequency and frequency derivative components of the metric, suitable for a directed search with only...
Definition: PtoleMetric.c:828
#define PTOLEMETRICH_MSGENULL
Definition: PtoleMetric.h:86
#define PTOLEMETRICH_ENONULL
Definition: PtoleMetric.h:83
void LALPulsarMetric(LALStatus *stat, REAL8Vector **metric, PtoleMetricIn *input)
Unified "wrapper" to provide a uniform interface to LALPtoleMetric() and LALCoherentMetric().
Definition: PtoleMetric.c:625
int XLALFindMetricDim(const REAL8Vector *metric)
Figure out dimension of a REAL8Vector -encoded metric (see PMETRIC_INDEX() ).
Definition: PtoleMetric.c:793
@ LAL_PMETRIC_COH_PTOLE_ANALYTIC
Definition: PtoleMetric.h:97
COORDINATESYSTEM_EQUATORIAL
void LALDCreateVector(LALStatus *, REAL8Vector **, UINT4)
void LALDDestroyVector(LALStatus *, REAL8Vector **)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_ESIZE
XLAL_EINVAL
T
LALFrDetector frDetector
REAL8 vertexLongitudeRadians
REAL8 vertexLatitudeRadians
This structure will likely be changed to match up better with those under StackMetric....
Definition: PtoleMetric.h:110
SkyPosition position
The equatorial coordinates at which the metric components are evaluated.
Definition: PtoleMetric.h:111
REAL4Vector * spindown
The (dimensionless) spindown parameters for which the metric components are evaluated.
Definition: PtoleMetric.h:112
REAL4 maxFreq
The maximum frequency to be searched, in Hz.
Definition: PtoleMetric.h:115
LALPulsarMetricType metricType
The type of metric to use: analytic, Ptolemaic or fully ephemeris-based.
Definition: PtoleMetric.h:118
const LALDetector * site
The detector site, used only for its latitude and longitude.
Definition: PtoleMetric.h:116
REAL4 duration
Duration of integration, in seconds.
Definition: PtoleMetric.h:114
LIGOTimeGPS epoch
When the coherent integration begins.
Definition: PtoleMetric.h:113
REAL8 * data
REAL8 longitude
REAL8 latitude
CoordinateSystem system