Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
NstarTools.py
Go to the documentation of this file.
1# Copyright (C) 2017 Gregory Ashton
2#
3# This program is free software; you can redistribute it and/or modify it
4# under the terms of the GNU General Public License as published by the
5# Free Software Foundation; either version 2 of the License, or (at your
6# option) any later version.
7#
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11# Public License for more details.
12#
13# You should have received a copy of the GNU General Public License along
14# with this program; if not, write to the Free Software Foundation, Inc.,
15# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16"""
17
18Tools to estimate Nstar and related functions
19
20"""
21from __future__ import division, absolute_import, print_function
22
23import pprint
24import itertools
25import logging
26import numpy as np
27
28try:
29 import lal
30except ImportError:
31 raise ImportError("SWIG wrappings of LAL cannot be imported")
32
33try:
34 import lalpulsar
35except ImportError:
36 raise ImportError("SWIG wrappings of LALPulsar cannot be imported")
37
38
39def _extract_data_from_prior(prior):
40 """Calculate the input data from the prior
41
42 Parameters
43 ----------
44 prior: dict
45 For each key in 'Alpha', 'Delta', 'F0', 'F1', 'F2', either a scalar
46 value (not searched over), or a pair of the upper and lower limit.
47
48 Returns
49 -------
50 p : ndarray
51 Matrix with columns being the edges of the uniform bounding box
52 spindowns : int
53 The number of spindowns
54 sky : bool
55 If true, search includes the sky position
56 fiducial_freq : float
57 Fidicual frequency
58
59 """
60 keys = ["Alpha", "Delta", "F0", "F1", "F2"]
61 spindown_keys = keys[3:]
62 sky_keys = keys[:2]
63 lims = []
64 lims_keys = []
65 scalar_keys = []
66 unfound_keys = []
67 lims_idxs = []
68 for i, key in enumerate(keys):
69 array_like = isinstance(prior[key], (list, tuple, np.ndarray))
70 if key not in keys:
71 raise ValueError("Key {}={} not understood".format(key, prior[key]))
72 elif array_like and len(prior[key]) == 2:
73 lims.append([prior[key][0], prior[key][1]])
74 lims_keys.append(key)
75 lims_idxs.append(i)
76 elif np.isscalar(prior[key]) or len(prior[key] == 1):
77 scalar_keys.append(key)
78 if key in sky_keys:
79 lims.append([prior[key], 0])
80 else:
81 unfound_keys.append(key)
82 logging.info(
83 "Computing Nstar over dimensions {} while {} are scalar and {} unused".format(
84 lims_keys, scalar_keys, unfound_keys
85 )
86 )
87 lims = np.array(lims)
88 lims_keys = np.array(lims_keys)
89 base = lims[:, 0]
90 p = [base]
91 for i in lims_idxs:
92 basex = base.copy()
93 basex[i] = lims[i, 1]
94 p.append(basex)
95 spindowns = np.sum([np.sum(lims_keys == k) for k in spindown_keys])
96 sky = any([key in lims_keys for key in sky_keys])
97 fiducial_freq = np.max(prior["F0"])
98
99 return np.array(p).T, spindowns, sky, fiducial_freq
100
101
102def _convert_array_to_gsl_matrix(array):
103 gsl_matrix = lal.gsl_matrix(*array.shape)
104 gsl_matrix.data = array
105 return gsl_matrix
106
107
109 nsegs,
110 tref,
111 minStartTime,
112 maxStartTime,
113 prior,
114 detector_names,
115 earth_ephem_file="earth00-40-DE405.dat.gz",
116 sun_ephem_file="sun00-40-DE405.dat.gz",
117):
118 """Returns N* estimated from the super-sky metric
119
120 Nstar is the approximate number of unit-mismatch templates, see
121 https://dcc.ligo.org/P1700455 for further details.
122
123 Parameters
124 ----------
125 nsegs : int
126 Number of semi-coherent segments
127 tref : int
128 Reference time in GPS seconds
129 minStartTime, maxStartTime : int
130 Minimum and maximum SFT timestamps
131 prior: dict
132 For each key in 'Alpha', 'Delta', 'F0', 'F1', 'F2', either a scalar
133 value (not searched over), or a pair of the upper and lower limit.
134 detector_names : list
135 List of detectors to average over, e.g. ['H1']
136
137 Returns
138 -------
139 Nstar: int
140 The estimated approximate number of templates to cover the prior
141 parameter space at a mismatch of unity, assuming the normalised
142 thickness is unity.
143
144 Example
145 --------
146
147 An example for a directed search where the Nstar can be estimated from the
148 metric directly. This estimate is used to define the frequency and
149 spin-down uncertainty. The calculated estimate using `get_Nstar_estimate`
150 agrees with this input value.
151
152 >>> from lalpulsar import NstarTools
153 >>> nsegs = 1
154 >>> minStartTime = 1000000000
155 >>> duration = 10 * 86400
156 >>> maxStartTime = minStartTime + duration
157 >>> tref = minStartTime + .5*duration
158 >>> detector_names = ['H1']
159 >>> F0 = 30
160 >>> F1 = -1e-10
161 >>> F2 = 0
162 >>> Alpha = 0.5
163 >>> Delta = 1.5
164 >>> Nstar = 1e3
165 >>> DeltaF0 = np.sqrt(Nstar) * np.sqrt(3)/(np.pi*duration)
166 >>> DeltaF1 = np.sqrt(Nstar) * np.sqrt(180)/(np.pi*duration**2)
167 >>> prior = {'F0': [F0-DeltaF0/2., F0+DeltaF0/2],
168 >>> 'F1': [F1-DeltaF1/2., F1+DeltaF1/2],
169 >>> 'F2': F2,
170 >>> 'Alpha': Alpha
171 >>> 'Delta': Delta}
172 >>> print NstarTools.get_Nstar_estimate(
173 >>> nsegs, tref, minStartTime, maxStartTime, prior, detector_names)
174 1000.00000009
176 Note
177 ----
178
179 To see detailed information about each set of dimensions Nstar, add the
180 following before calling get_Nstar_estimate()
181 >>> import logging
182 >>> logging.basicConfig(level=logging.DEBUG)
183
184 """
185 detector_names = list(detector_names)
186
187 in_phys, spindowns, sky, fiducial_freq = _extract_data_from_prior(prior)
188 out_rssky = np.zeros(in_phys.shape)
189
190 # Convert to Alpha, Delta, Fn, Fn-1, Fn-2,.. ordering
191 in_phys[2:] = in_phys[2:][::-1]
192
193 in_phys = _convert_array_to_gsl_matrix(in_phys)
194 out_rssky = _convert_array_to_gsl_matrix(out_rssky)
195
196 tboundaries = np.linspace(minStartTime, maxStartTime, nsegs + 1)
197
198 ref_time = lal.LIGOTimeGPS(tref)
199 segments = lal.SegListCreate()
200 for j in range(len(tboundaries) - 1):
201 seg = lal.SegCreate(
202 lal.LIGOTimeGPS(tboundaries[j]), lal.LIGOTimeGPS(tboundaries[j + 1]), j
203 )
204 lal.SegListAppend(segments, seg)
205 detNames = lal.CreateStringVector(*detector_names)
206 detectors = lalpulsar.MultiLALDetector()
207 lalpulsar.ParseMultiLALDetector(detectors, detNames)
208 detector_weights = None
209 detector_motion = lalpulsar.DETMOTION_SPIN + lalpulsar.DETMOTION_ORBIT
210 ephemeris = lalpulsar.InitBarycenter(earth_ephem_file, sun_ephem_file)
211 try:
212 SSkyMetric = lalpulsar.ComputeSuperskyMetrics(
213 lalpulsar.SUPERSKY_METRIC_TYPE,
214 spindowns,
215 ref_time,
216 segments,
217 fiducial_freq,
218 detectors,
219 detector_weights,
220 detector_motion,
221 ephemeris,
222 )
223 except RuntimeError as e:
224 logging.warning("Encountered run-time error {}".format(e))
225 raise RuntimeError("Calculation of the SSkyMetric failed")
226
227 if sky:
228 i = 0
229 else:
230 i = 2
231
232 lalpulsar.ConvertPhysicalToSuperskyPoints(
233 out_rssky, in_phys, SSkyMetric.semi_rssky_transf
234 )
235
236 d = out_rssky.data
237 g = SSkyMetric.semi_rssky_metric.data
238
239 g[2:, 2:] = g[2:, 2:][::-1, ::-1] # Convert to Alpha, Delta, F0, F1, F2
240
241 # Remove sky if required
242 g = g[i:, i:]
243 d = d[i:, i:]
244
245 # Calculate parallelepiped of differences
246 parallelepiped = (d[:, 1:].T - d[:, 0]).T
247
248 labels = np.array(["Alpha", "Delta", "F0", "F1", "F2"])[i:]
249
250 # Compute Nstar over all allowed combinations then take maximum
251 Nstars = {}
252 for j in range(1, len(g) + 1):
253 for idx in itertools.combinations(np.arange(len(g)), j):
254 idx = list(idx)
255 dV = np.abs(np.linalg.det(parallelepiped[idx][:, idx]))
256 sqrtdetG = np.sqrt(np.abs(np.linalg.det(g[idx][:, idx])))
257 Nstars["".join(labels[idx])] = sqrtdetG * dV
258 logging.debug(pprint.pformat(Nstars))
259 return np.max(Nstars.values())
def get_Nstar_estimate(nsegs, tref, minStartTime, maxStartTime, prior, detector_names, earth_ephem_file="earth00-40-DE405.dat.gz", sun_ephem_file="sun00-40-DE405.dat.gz")
Returns N* estimated from the super-sky metric.
Definition: NstarTools.py:184