LAL  7.5.0.1-8883986
Skymap.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (C) 2008 Antony Searle
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13  * Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include <math.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 
25 #include <gsl/gsl_linalg.h>
26 
27 #include <lal/LALConstants.h>
28 #include <lal/LALMalloc.h>
29 #include <lal/XLALError.h>
30 #include <lal/DetResponse.h>
31 #include <lal/Skymap.h>
32 
33 // Convenience functions for tiny stack vectors and matrices
34 
35 // Dot product of 3-vectors
36 
37 static double dot3(double a[3], double b[3])
38 {
39  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
40 }
41 
42 // Inverse of a 2x2 matrix
43 
44 static void inv22(double a[2][2], double b[2][2])
45 {
46  double c = b[0][0] * b[1][1] - b[0][1] * b[1][0];
47  a[0][0] = b[1][1] / c;
48  a[0][1] = -b[0][1] / c;
49  a[1][0] = -b[1][0] / c;
50  a[1][1] = b[0][0] / c;
51 }
52 
53 // Determinant of a 2x2 matrix
54 
55 static double det22(double a[2][2])
56 {
57  return a[0][0] * a[1][1] - a[0][1] * a[1][0];
58 }
59 
60 // Coordinate transformation theta,phi -> x,y,z
61 
62 void XLALSkymapCartesianFromSpherical(double a[3], double b[2])
63 {
64  a[0] = sin(b[0]) * cos(b[1]);
65  a[1] = sin(b[0]) * sin(b[1]);
66  a[2] = cos(b[0]);
67 }
68 
69 // Coordinate transformation x,y,z -> theta,phi
70 
71 void XLALSkymapSphericalFromCartesian(double a[2], double b[3])
72 {
73  a[0] = acos(b[2]);
74  a[1] = atan2(b[1], b[0]);
75 }
76 
77 // Time of arrival at a detector, relative to center of Earth, for signals
78 // from a given (unit) direction
79 
80 static double site_time(LALDetector* site, double direction[3])
81 {
82  return -dot3(site->location, direction) / LAL_C_SI;
83 }
84 
85 // Plus and cross polarization response of a detector for signals from a
86 // given direction
87 
88 static void site_response(double f[2], const LALDetector* site, double direction[3])
89 {
90  double thetaphi[2];
91  XLALSkymapSphericalFromCartesian(thetaphi, direction);
92  XLALComputeDetAMResponse(&f[0], &f[1], site->response, thetaphi[1], LAL_PI_2 - thetaphi[0], 0, 0);
93 }
94 
95 // XLALSkymapLogSumExp(a, b) computes log(exp(a) + exp(b)) but will not
96 // overflow for a or b > ~300
97 //
98 // For a > b, we use the identity
99 //
100 // log(exp(a) + exp(b)
101 // = log(exp(a) * (1 + exp(b) / exp(a)))
102 // = a + log(1 + exp(b - a))
103 // = a + log1p(exp(b - a))
104 //
105 // where b - a < 0 and exp(b - a) cannot overflow (though it may
106 // underflow).
107 //
108 // And for a < b
109 //
110 // log(exp(a) + exp(b))
111 // = log(exp(b) * (exp(a) / exp(b) + 1))
112 // = b + log(exp(a - b) + 1)
113 // = b + log1p(exp(a - b))
114 //
115 // If neither a < b nor a > b, we either have equality or both values
116 // are (the same) plus or minus infinity. Forming (a - b) in the case of
117 // infinities results in a NaN, so we must use a third expression
118 //
119 // log(exp(a) + exp(b))
120 // = log(exp(a) + exp(a))
121 // = log(2 * exp(a))
122 // = log(2) + a
123 
124 double XLALSkymapLogSumExp(double a, double b)
125 {
126  return (a < b) ?
127  (b + log1p(exp(a - b))) :
128  ((b < a) ? (a + log1p(exp(b - a))) : (a + log(2)));
129 }
130 
131 // Find the maximum of a sequence of doubles and return a pointer to it
132 
133 static double* findmax(double* begin, double* end)
134 {
135  double* p;
136  double* m;
137  m = begin;
138  for (p = begin; p != end; ++p)
139  {
140  if (*m < *p)
141  {
142  m = p;
143  }
144  }
145  return m;
146 }
147 
148 // Find log sum_i exp(a[i])) given max_i a[i], using the same technique as
149 // XLALSkymapLogSumExp to accumulate the result without overflowing for
150 // a[i] > ~300
151 
152 static double logtotalexpwithmax(double* begin, double* end, double m)
153 {
154  double t;
155  double* p;
156  t = 0;
157  for (p = begin; p != end; ++p)
158  {
159  t += exp(*p - m);
160  }
161  return m + log(t);
162 }
163 
164 // Find log sum_i exp(a[i]) using findmax and logtotalexpwithmax
165 
166 double XLALSkymapLogTotalExp(double* begin, double* end)
167 {
168  return logtotalexpwithmax(begin, end, *findmax(begin, end));
169 }
170 
171 // To cubic interpolate
172 // x(0 <= t <= 1)
173 // from
174 // x[-1], x[0], x[1], x[2]
175 // we compute
176 // w_t[-1], w_t[0], w_t[1], w_t[2]
177 // such that
178 // x(t) = sum_i x[i] w_t[i]
179 
180 double XLALSkymapInterpolate(double t, double* x)
181 {
182  int whole = floor(t);
183  t -= whole;
184 
185  double h[4], w[4];
186 
187  // Hermite basis functions at t
188 
189  h[0] = (1. + 2. * t) * (1. - t) * (1. - t);
190  h[1] = t * (1. - t) * (1. - t);
191  h[2] = t * t * (3. - 2. * t);
192  h[3] = t * t * (t - 1.);
193 
194  // Weights
195 
196  w[0] = -0.5 * h[1];
197  w[1] = h[0] - 0.5 * h[3];
198  w[2] = h[2] + 0.5 * h[1];
199  w[3] = 0.5 * h[3];
200 
201  double y = 0;
202  int i;
203 
204  for (i = 0; i != 4; ++i)
205  {
206  y += x[whole + i - 1] * w[i];
207  }
208 
209  return y;
210 
211 
212 }
213 
214 // Construct an XLALSkymap2PlanType in the given memory from
215 // sample frequency of matched filter timeseries
216 // number of detectors
217 // list of detector LAL ID numbers
218 
219 void XLALSkymapPlanConstruct(int sampleFrequency, int n, int* detectors, XLALSkymapPlanType* plan)
220 {
221  int i;
222 
223  plan->sampleFrequency = sampleFrequency;
224  plan->n = n;
225 
226  for (i = 0; i != plan->n; ++i)
227  {
228  plan->site[i] = lalCachedDetectors[detectors[i]];
229  }
230 
231 }
232 
233 // Construct an XLALSkymap2DirectionProperties object in the given memory
234 // from
235 // a plan
236 // a theta, phi tuple
237 
239  XLALSkymapPlanType* plan,
240  double directions[2],
242  )
243 {
244  double x[3];
245  int j;
246 
247  // Convert theta, phi direction to cartesian
248  XLALSkymapCartesianFromSpherical(x, directions);
249 
250  for (j = 0; j != plan->n; ++j)
251  {
252  // Delay (in seconds)
253  properties->delay[j] = site_time(plan->site + j, x);
254  // Plus and cross polarization responses
255  site_response(properties->f[j], plan->site + j, x);
256  }
257 }
258 
259 // Construct a XLALSkymap2Kernel object in the given memory from
260 // a plan
261 // direction properties (time delays, interpolation weights and
262 // antenna patterns)
263 // the noise-weighted inner product of the template with itself
264 
266  XLALSkymapPlanType* plan,
268  double* wSw,
269  XLALSkymapKernelType* kernel
270  )
271 {
272 
273  int i, j, k, l;
274 
275  //
276  // W = diag(w.S_j^{-1}.w)
277  //
278  // F (F^T W F + I) F^T
279  //
280 
281  double a[2][2]; // F^T W F
282  double b[2][2]; // inv(A)
283 
284  // Compute the kernel
285 
286  // F^T W F + I
287 
288  for (i = 0; i != 2; ++i)
289  {
290  for (j = 0; j != 2; ++j)
291  {
292  a[i][j] = ((i == j) ? 1.0 : 0.0);
293  for (k = 0; k != plan->n; ++k)
294  {
295  a[i][j] += properties->f[k][i] * wSw[k] * properties->f[k][j];
296  }
297  }
298  }
299 
300  // (F^T W F + I)^{-1}
301 
302  inv22(b, a);
303 
304  // F (F^T W F + I)^{-1} F^T
305 
306  for (i = 0; i != plan->n; ++i)
307  {
308  for (j = 0; j != plan->n; ++j)
309  {
310  kernel->k[i][j] = 0.0;
311  for (k = 0; k != 2; ++k)
312  {
313  for (l = 0; l != 2; ++l)
314  {
315  kernel->k[i][j] += properties->f[i][k] * b[k][l] * properties->f[j][l];
316  }
317  }
318  }
319  }
320 
321  kernel->logNormalization = 0.5 * log(det22(b));
322 
323 }
324 
325 // Construct a XLALSkymapKernel object in the given memory from
326 // a plan
327 // direction properties (time delays, interpolation weights and
328 // antenna patterns)
329 // the noise-weighted inner product of the template with itself
330 // the amplitude calibration error
331 
333  XLALSkymapPlanType* plan,
335  double* wSw,
336  double* error,
337  XLALSkymapKernelType* kernel
338  )
339 {
340 
341  int i, j, k;
342 
343  double a[XLALSKYMAP_N][XLALSKYMAP_N];
344 
345  // compute the signal covariance matrix
346 
347  for (i = 0; i != plan->n; ++i)
348  {
349  for (j = 0; j != plan->n; ++j)
350  {
351  a[i][j] = 0;
352  for (k = 0; k != 2; ++k)
353  {
354  a[i][j] += properties->f[i][k] * properties->f[j][k]; // antenna factors
355  }
356  a[i][j] *= wSw[i] * wSw[j]; // snr factors
357  }
358  a[i][i] *= 1 + error[i] * error[i]; // error factors
359  a[i][i] += wSw[i]; // noise covariance
360  }
361 
362  // invert the covariance
363 
364  gsl_matrix_view m = gsl_matrix_view_array_with_tda(a[0], plan->n, plan->n, XLALSKYMAP_N);
365  gsl_permutation* p = gsl_permutation_alloc(plan->n);
366  int s;
367 
368  gsl_linalg_LU_decomp(&m.matrix, p, &s);
369 
370  gsl_matrix_view inverse = gsl_matrix_view_array_with_tda(kernel->k[0], plan->n, plan->n, XLALSKYMAP_N);
371 
372  gsl_linalg_LU_invert(&m.matrix, p, &inverse.matrix);
373 
374  gsl_permutation_free(p);
375 
376  // subtract inverse signal covariance from inverse noise covariance
377 
378  for (i = 0; i != plan->n; ++i)
379  {
380  for (j = 0; j != plan->n; ++j)
381  {
382  kernel->k[i][j] = -kernel->k[i][j];
383  }
384  kernel->k[i][i] += 1. / wSw[i];
385  }
386 
387  // log normalization
388 
389  kernel->logNormalization = 0;
390  for (i = 0; i != plan->n; ++i)
391  {
392  // accumulate the log determinant of the noise covariance
393  kernel->logNormalization += log(wSw[i]);
394  }
395  kernel->logNormalization -= gsl_linalg_LU_lndet(&m.matrix); // log determinant of the signal covariance
396  kernel->logNormalization *= 0.5; // square root
397 
398 }
399 
400 // Compute the marginalization integral over a_plus and a_cross for the
401 // system described by
402 // a plan
403 // a direction's properties
404 // a kernel
405 // a matched filter time series for each detector
406 // a signal arrival time
407 
409  XLALSkymapPlanType* plan,
411  XLALSkymapKernelType* kernel,
412  double** xSw,
413  double tau,
414  double* posterior
415  )
416 {
417  double a;
418  int i, j;
419 
420  double x[XLALSKYMAP_N];
421 
422  // Interpolate the matched filter values
423 
424  for (i = 0; i != plan->n; ++i)
425  {
426  x[i] = XLALSkymapInterpolate((tau + properties->delay[i]) * plan->sampleFrequency, xSw[i]);
427  }
428 
429  // This implementation does not exploit the symmetry of the expression
430 
431  // Compute x^T.K.x
432 
433  a = 0;
434 
435  for (i = 0; i != plan->n; ++i)
436  {
437  for (j = 0; j != plan->n; ++j)
438  {
439  a += x[i] * kernel->k[i][j] * x[j];
440  }
441  }
442 
443  // Scale and apply the normalization
444 
445  *posterior = 0.5 * a + kernel->logNormalization;
446 
447 }
448 
449 
static double site_time(LALDetector *site, double direction[3])
Definition: Skymap.c:80
void XLALSkymapDirectionPropertiesConstruct(XLALSkymapPlanType *plan, double directions[2], XLALSkymapDirectionPropertiesType *properties)
Definition: Skymap.c:238
static void site_response(double f[2], const LALDetector *site, double direction[3])
Definition: Skymap.c:88
static double det22(double a[2][2])
Definition: Skymap.c:55
void XLALSkymapSphericalFromCartesian(double a[2], double b[3])
Definition: Skymap.c:71
void XLALSkymapUncertainKernelConstruct(XLALSkymapPlanType *plan, XLALSkymapDirectionPropertiesType *properties, double *wSw, double *error, XLALSkymapKernelType *kernel)
Definition: Skymap.c:332
double XLALSkymapLogTotalExp(double *begin, double *end)
Definition: Skymap.c:166
static double * findmax(double *begin, double *end)
Definition: Skymap.c:133
double XLALSkymapLogSumExp(double a, double b)
Definition: Skymap.c:124
static void inv22(double a[2][2], double b[2][2])
Definition: Skymap.c:44
double XLALSkymapInterpolate(double t, double *x)
Definition: Skymap.c:180
void XLALSkymapApply(XLALSkymapPlanType *plan, XLALSkymapDirectionPropertiesType *properties, XLALSkymapKernelType *kernel, double **xSw, double tau, double *posterior)
Definition: Skymap.c:408
static double logtotalexpwithmax(double *begin, double *end, double m)
Definition: Skymap.c:152
static double dot3(double a[3], double b[3])
Definition: Skymap.c:37
void XLALSkymapPlanConstruct(int sampleFrequency, int n, int *detectors, XLALSkymapPlanType *plan)
Definition: Skymap.c:219
void XLALSkymapKernelConstruct(XLALSkymapPlanType *plan, XLALSkymapDirectionPropertiesType *properties, double *wSw, XLALSkymapKernelType *kernel)
Definition: Skymap.c:265
void XLALSkymapCartesianFromSpherical(double a[3], double b[2])
Definition: Skymap.c:62
#define XLALSKYMAP_N
Definition: Skymap.h:45
static REAL8TimeSeries * error(const REAL8TimeSeries *s1, const REAL8TimeSeries *s0)
static double f(double theta, double y, double xi)
Definition: XLALMarcumQ.c:258
const LALDetector lalCachedDetectors[LAL_NUM_DETECTORS]
Pre-existing detectors.
void XLALComputeDetAMResponse(double *fplus, double *fcross, const REAL4 D[3][3], const double ra, const double dec, const double psi, const double gmst)
An implementation of the detector response formulae in Anderson et al PRD 63 042003 (2001) .
Definition: DetResponse.c:44
#define LAL_PI_2
pi/2
Definition: LALConstants.h:181
#define LAL_C_SI
Speed of light in vacuum, m s^-1.
Definition: LALConstants.h:198
static const INT4 m
Definition: Random.c:80
static const INT4 a
Definition: Random.c:79
Detector structure.
Definition: LALDetectors.h:278
double f[XLALSKYMAP_N][2]
Definition: Skymap.h:77
double delay[XLALSKYMAP_N]
Definition: Skymap.h:78
double logNormalization
Definition: Skymap.h:93
double k[XLALSKYMAP_N][XLALSKYMAP_N]
Definition: Skymap.h:92
int sampleFrequency
Definition: Skymap.h:60
LALDetector site[XLALSKYMAP_N]
Definition: Skymap.h:62
enum @4 site