lisaanalysistools 1.0.14__cp312-cp312-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lisaanalysistools might be problematic. Click here for more details.
- lisaanalysistools-1.0.14.dist-info/LICENSE +201 -0
- lisaanalysistools-1.0.14.dist-info/METADATA +108 -0
- lisaanalysistools-1.0.14.dist-info/RECORD +43 -0
- lisaanalysistools-1.0.14.dist-info/WHEEL +5 -0
- lisaanalysistools-1.0.14.dist-info/top_level.txt +1 -0
- lisatools/__init__.py +0 -0
- lisatools/_version.py +4 -0
- lisatools/analysiscontainer.py +474 -0
- lisatools/cutils/__init__.py +0 -0
- lisatools/cutils/detector_cpu.cpython-312-darwin.so +0 -0
- lisatools/cutils/include/Detector.hpp +84 -0
- lisatools/cutils/include/__init__.py +0 -0
- lisatools/cutils/include/global.hpp +28 -0
- lisatools/cutils/src/Detector.cpp +307 -0
- lisatools/cutils/src/Detector.cu +307 -0
- lisatools/cutils/src/__init__.py +0 -0
- lisatools/cutils/src/pycppdetector.pyx +255 -0
- lisatools/datacontainer.py +312 -0
- lisatools/detector.py +706 -0
- lisatools/diagnostic.py +990 -0
- lisatools/sampling/__init__.py +0 -0
- lisatools/sampling/likelihood.py +882 -0
- lisatools/sampling/moves/__init__.py +0 -0
- lisatools/sampling/moves/skymodehop.py +110 -0
- lisatools/sampling/prior.py +646 -0
- lisatools/sampling/stopping.py +320 -0
- lisatools/sampling/utility.py +411 -0
- lisatools/sensitivity.py +972 -0
- lisatools/sources/__init__.py +6 -0
- lisatools/sources/bbh/__init__.py +1 -0
- lisatools/sources/bbh/waveform.py +106 -0
- lisatools/sources/defaultresponse.py +36 -0
- lisatools/sources/emri/__init__.py +1 -0
- lisatools/sources/emri/waveform.py +79 -0
- lisatools/sources/gb/__init__.py +1 -0
- lisatools/sources/gb/waveform.py +67 -0
- lisatools/sources/utils.py +456 -0
- lisatools/sources/waveformbase.py +41 -0
- lisatools/stochastic.py +327 -0
- lisatools/utils/__init__.py +0 -0
- lisatools/utils/constants.py +40 -0
- lisatools/utils/pointeradjust.py +106 -0
- lisatools/utils/utility.py +245 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import warnings
|
|
5
|
+
from abc import ABC
|
|
6
|
+
from typing import Any, Tuple, Optional, List
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from scipy import interpolate
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
|
|
14
|
+
from eryn.utils import TransformContainer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import cupy as cp
|
|
19
|
+
|
|
20
|
+
except (ModuleNotFoundError, ImportError):
|
|
21
|
+
import numpy as cp
|
|
22
|
+
|
|
23
|
+
from . import detector as lisa_models
|
|
24
|
+
from .utils.utility import AET, get_array_module
|
|
25
|
+
from .utils.constants import *
|
|
26
|
+
from .stochastic import (
|
|
27
|
+
StochasticContribution,
|
|
28
|
+
FittedHyperbolicTangentGalacticForeground,
|
|
29
|
+
)
|
|
30
|
+
from .datacontainer import DataResidualArray
|
|
31
|
+
from .sensitivity import SensitivityMatrix
|
|
32
|
+
from .diagnostic import (
|
|
33
|
+
noise_likelihood_term,
|
|
34
|
+
residual_full_source_and_noise_likelihood,
|
|
35
|
+
residual_source_likelihood_term,
|
|
36
|
+
inner_product,
|
|
37
|
+
data_signal_source_likelihood_term,
|
|
38
|
+
data_signal_full_source_and_noise_likelihood,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AnalysisContainer:
|
|
43
|
+
"""Combinatorial container that combines sensitivity and data information.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
data_res_arr: Data / Residual / Signal array.
|
|
47
|
+
sens_mat: Sensitivity information.
|
|
48
|
+
signal_gen: Callable object that takes information through ``*args`` and ``**kwargs`` and
|
|
49
|
+
generates a signal in the proper channel setup employed in ``data_res_arr`` and ``sens_mat``.
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
data_res_arr: DataResidualArray,
|
|
56
|
+
sens_mat: SensitivityMatrix,
|
|
57
|
+
signal_gen: Optional[callable] = None,
|
|
58
|
+
) -> None:
|
|
59
|
+
self.data_res_arr = data_res_arr
|
|
60
|
+
self.sens_mat = sens_mat
|
|
61
|
+
|
|
62
|
+
if signal_gen is not None:
|
|
63
|
+
self.signal_gen = signal_gen
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def data_res_arr(self) -> DataResidualArray:
|
|
67
|
+
"""Data information."""
|
|
68
|
+
return self._data_res_arr
|
|
69
|
+
|
|
70
|
+
@data_res_arr.setter
|
|
71
|
+
def data_res_arr(self, data_res_arr: DataResidualArray) -> None:
|
|
72
|
+
"""Set data."""
|
|
73
|
+
assert isinstance(data_res_arr, DataResidualArray)
|
|
74
|
+
self._data_res_arr = data_res_arr
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def sens_mat(self) -> SensitivityMatrix:
|
|
78
|
+
"""Sensitivity information."""
|
|
79
|
+
return self._sens_mat
|
|
80
|
+
|
|
81
|
+
@sens_mat.setter
|
|
82
|
+
def sens_mat(self, sens_mat: SensitivityMatrix) -> None:
|
|
83
|
+
"Set sensitivity information."
|
|
84
|
+
assert isinstance(sens_mat, SensitivityMatrix)
|
|
85
|
+
self._sens_mat = sens_mat
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def signal_gen(self) -> callable:
|
|
89
|
+
"""Signal generator."""
|
|
90
|
+
if not hasattr(self, "_signal_gen"):
|
|
91
|
+
raise ValueError(
|
|
92
|
+
"User must input signal_gen kwarg to use the signal generator."
|
|
93
|
+
)
|
|
94
|
+
return self._signal_gen
|
|
95
|
+
|
|
96
|
+
@signal_gen.setter
|
|
97
|
+
def signal_gen(self, signal_gen: callable):
|
|
98
|
+
"""Set signal generator."""
|
|
99
|
+
assert hasattr(signal_gen, "__call__")
|
|
100
|
+
self._signal_gen = signal_gen
|
|
101
|
+
|
|
102
|
+
def loglog(self) -> Tuple[plt.Figure, plt.Axes]:
|
|
103
|
+
"""Produce loglog plot of both source and sensitivity information.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Matplotlib figure and axes object in a 2-tuple.
|
|
107
|
+
|
|
108
|
+
"""
|
|
109
|
+
fig, ax = self.sens_mat.loglog(char_strain=True)
|
|
110
|
+
if self.sens_mat.ndim == 3:
|
|
111
|
+
# 3x3 most likely
|
|
112
|
+
for i in range(self.sens_mat.shape[0]):
|
|
113
|
+
for j in range(i, self.sens_mat.shape[1]):
|
|
114
|
+
# char strain
|
|
115
|
+
ax[i * self.sens_mat.shape[1] + j].loglog(
|
|
116
|
+
self.data_res_arr.f_arr,
|
|
117
|
+
self.data_res_arr.f_arr * np.abs(self.data_res_arr[i]),
|
|
118
|
+
)
|
|
119
|
+
ax[i * self.sens_mat.shape[1] + j].loglog(
|
|
120
|
+
self.data_res_arr.f_arr,
|
|
121
|
+
self.data_res_arr.f_arr * np.abs(self.data_res_arr[j]),
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
for i in range(self.sens_mat.shape[0]):
|
|
125
|
+
ax[i].loglog(
|
|
126
|
+
self.data_res_arr.f_arr,
|
|
127
|
+
self.data_res_arr.f_arr * np.abs(self.data_res_arr[i]),
|
|
128
|
+
)
|
|
129
|
+
return (fig, ax)
|
|
130
|
+
|
|
131
|
+
def inner_product(self, **kwargs: dict) -> float | complex:
|
|
132
|
+
"""Return the inner product of the current set of information
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
**kwargs: Inner product keyword arguments.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Inner product value.
|
|
139
|
+
|
|
140
|
+
"""
|
|
141
|
+
if "psd" in kwargs:
|
|
142
|
+
kwargs.pop("psd")
|
|
143
|
+
|
|
144
|
+
return inner_product(self.data_res_arr, self.data_res_arr, psd=self.sens_mat)
|
|
145
|
+
|
|
146
|
+
def snr(self, **kwargs: dict) -> float:
|
|
147
|
+
"""Return the SNR of the current set of information
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
**kwargs: Inner product keyword arguments.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
SNR value.
|
|
154
|
+
|
|
155
|
+
"""
|
|
156
|
+
return self.inner_product(**kwargs).real ** (1 / 2)
|
|
157
|
+
|
|
158
|
+
def template_inner_product(
|
|
159
|
+
self, template: DataResidualArray, **kwargs: dict
|
|
160
|
+
) -> float | complex:
|
|
161
|
+
"""Calculate the inner product of a template with the data.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
template: Template signal.
|
|
165
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Inner product value.
|
|
169
|
+
|
|
170
|
+
"""
|
|
171
|
+
if "psd" in kwargs:
|
|
172
|
+
kwargs.pop("psd")
|
|
173
|
+
|
|
174
|
+
if "include_psd_info" in kwargs:
|
|
175
|
+
kwargs.pop("include_psd_info")
|
|
176
|
+
|
|
177
|
+
ip_val = inner_product(self.data_res_arr, template, psd=self.sens_mat, **kwargs)
|
|
178
|
+
return ip_val
|
|
179
|
+
|
|
180
|
+
def template_snr(
|
|
181
|
+
self, template: DataResidualArray, phase_maximize: bool = False, **kwargs: dict
|
|
182
|
+
) -> Tuple[float, float]:
|
|
183
|
+
"""Calculate the SNR of a template, both optimal and detected.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
template: Template signal.
|
|
187
|
+
phase_maximize: If ``True``, maximize over an overall phase.
|
|
188
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
``(optimal snr, detected snr)``.
|
|
192
|
+
|
|
193
|
+
"""
|
|
194
|
+
kwargs_in = kwargs.copy()
|
|
195
|
+
if "psd" in kwargs:
|
|
196
|
+
kwargs_in.pop("psd")
|
|
197
|
+
|
|
198
|
+
if "complex" in kwargs_in:
|
|
199
|
+
kwargs_in.pop("complex")
|
|
200
|
+
|
|
201
|
+
# TODO: should we cache?
|
|
202
|
+
h_h = inner_product(template, template, psd=self.sens_mat, **kwargs_in)
|
|
203
|
+
non_marg_d_h = inner_product(
|
|
204
|
+
self.data_res_arr, template, psd=self.sens_mat, complex=True, **kwargs_in
|
|
205
|
+
)
|
|
206
|
+
d_h = np.abs(non_marg_d_h) if phase_maximize else non_marg_d_h.copy()
|
|
207
|
+
self.non_marg_d_h = non_marg_d_h
|
|
208
|
+
|
|
209
|
+
opt_snr = np.sqrt(h_h.real)
|
|
210
|
+
det_snr = d_h.real / opt_snr
|
|
211
|
+
return (opt_snr, det_snr)
|
|
212
|
+
|
|
213
|
+
def template_likelihood(
|
|
214
|
+
self,
|
|
215
|
+
template: DataResidualArray,
|
|
216
|
+
include_psd_info: bool = False,
|
|
217
|
+
phase_maximize: bool = False,
|
|
218
|
+
**kwargs: dict,
|
|
219
|
+
) -> float:
|
|
220
|
+
"""Calculate the Likelihood of a template against the data.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
template: Template signal.
|
|
224
|
+
include_psd_info: If ``True``, add the PSD term to the Likelihood value.
|
|
225
|
+
phase_maximize: If ``True``, maximize over an overall phase.
|
|
226
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Likelihood value.
|
|
230
|
+
|
|
231
|
+
"""
|
|
232
|
+
kwargs_in = kwargs.copy()
|
|
233
|
+
if "psd" in kwargs_in:
|
|
234
|
+
kwargs_in.pop("psd")
|
|
235
|
+
|
|
236
|
+
if "complex" in kwargs_in:
|
|
237
|
+
kwargs_in.pop("complex")
|
|
238
|
+
|
|
239
|
+
# TODO: should we cache?
|
|
240
|
+
d_d = inner_product(
|
|
241
|
+
self.data_res_arr, self.data_res_arr, psd=self.sens_mat, **kwargs_in
|
|
242
|
+
)
|
|
243
|
+
h_h = inner_product(template, template, psd=self.sens_mat, **kwargs_in)
|
|
244
|
+
non_marg_d_h = inner_product(
|
|
245
|
+
self.data_res_arr, template, psd=self.sens_mat, complex=True, **kwargs_in
|
|
246
|
+
)
|
|
247
|
+
d_h = np.abs(non_marg_d_h) if phase_maximize else non_marg_d_h.copy()
|
|
248
|
+
self.non_marg_d_h = non_marg_d_h
|
|
249
|
+
like_out = -1 / 2 * (d_d + h_h - 2 * d_h).real
|
|
250
|
+
|
|
251
|
+
if include_psd_info:
|
|
252
|
+
# add noise term if requested
|
|
253
|
+
like_out += self.likelihood(noise_only=True)
|
|
254
|
+
|
|
255
|
+
return like_out
|
|
256
|
+
|
|
257
|
+
def likelihood(
|
|
258
|
+
self, source_only: bool = False, noise_only: bool = False, **kwargs: dict
|
|
259
|
+
) -> float | complex:
|
|
260
|
+
"""Return the likelihood of the current arangement.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
source_only: If ``True`` return the source-only Likelihood.
|
|
264
|
+
noise_only: If ``True``, return the noise part of the Likelihood alone.
|
|
265
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Likelihood value.
|
|
269
|
+
|
|
270
|
+
"""
|
|
271
|
+
if noise_only and source_only:
|
|
272
|
+
raise ValueError("noise_only and source only cannot both be True.")
|
|
273
|
+
elif noise_only:
|
|
274
|
+
return noise_likelihood_term(self.sens_mat)
|
|
275
|
+
elif source_only:
|
|
276
|
+
return residual_source_likelihood_term(
|
|
277
|
+
self.data_res_arr, psd=self.sens_mat, **kwargs
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
return residual_full_source_and_noise_likelihood(
|
|
281
|
+
self.data_res_arr, self.sens_mat, **kwargs
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
def _calculate_signal_operation(
|
|
285
|
+
self,
|
|
286
|
+
calc: str,
|
|
287
|
+
*args: Any,
|
|
288
|
+
source_only: bool = False,
|
|
289
|
+
waveform_kwargs: Optional[dict] = {},
|
|
290
|
+
data_res_arr_kwargs: Optional[dict] = {},
|
|
291
|
+
transform_fn: Optional[TransformContainer] = None,
|
|
292
|
+
**kwargs: dict,
|
|
293
|
+
) -> float | complex:
|
|
294
|
+
"""Return the likelihood of a generated signal with the data.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
calc: Type of calculation to do. Options are ``"likelihood"``, ``"inner_product"``, or ``"snr"``.
|
|
298
|
+
*args: Arguments to waveform generating function. Must include parameters.
|
|
299
|
+
source_only: If ``True`` return the source-only Likelihood (leave out noise part).
|
|
300
|
+
waveform_kwargs: Keyword arguments to pass to waveform generator.
|
|
301
|
+
data_res_arr_kwargs: Keyword arguments for instantiation of :class:`DataResidualArray`.
|
|
302
|
+
This can be used if any transforms are desired prior to the Likelihood computation. If it is not input,
|
|
303
|
+
the kwargs are taken to be the same as those used to initalize ``self.data_res_arr``.
|
|
304
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
Likelihood value.
|
|
308
|
+
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
if data_res_arr_kwargs == {}:
|
|
312
|
+
data_res_arr_kwargs = self.data_res_arr.init_kwargs
|
|
313
|
+
|
|
314
|
+
if transform_fn is not None:
|
|
315
|
+
args_tmp = np.asarray(args)
|
|
316
|
+
args_in = tuple(transform_fn.both_transforms(args_tmp))
|
|
317
|
+
else:
|
|
318
|
+
args_in = args
|
|
319
|
+
|
|
320
|
+
template = DataResidualArray(
|
|
321
|
+
self.signal_gen(*args_in, **waveform_kwargs), **data_res_arr_kwargs
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
args_2 = (template,)
|
|
325
|
+
|
|
326
|
+
if "include_psd_info" in kwargs:
|
|
327
|
+
assert kwargs["include_psd_info"] == (not source_only)
|
|
328
|
+
kwargs.pop("include_psd_info")
|
|
329
|
+
|
|
330
|
+
kwargs = dict(psd=self.sens_mat, **kwargs)
|
|
331
|
+
|
|
332
|
+
if calc == "likelihood":
|
|
333
|
+
kwargs["include_psd_info"] = not source_only
|
|
334
|
+
return self.template_likelihood(*args_2, **kwargs)
|
|
335
|
+
elif calc == "inner_product":
|
|
336
|
+
return self.template_inner_product(*args_2, **kwargs)
|
|
337
|
+
elif calc == "snr":
|
|
338
|
+
return self.template_snr(*args_2, **kwargs)
|
|
339
|
+
else:
|
|
340
|
+
raise ValueError("`calc` must be 'likelihood', 'inner_product', or 'snr'.")
|
|
341
|
+
|
|
342
|
+
def calculate_signal_likelihood(
|
|
343
|
+
self,
|
|
344
|
+
*args: Any,
|
|
345
|
+
source_only: bool = False,
|
|
346
|
+
waveform_kwargs: Optional[dict] = {},
|
|
347
|
+
data_res_arr_kwargs: Optional[dict] = {},
|
|
348
|
+
**kwargs: dict,
|
|
349
|
+
) -> float | complex:
|
|
350
|
+
"""Return the likelihood of a generated signal with the data.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
params: Arguments to waveform generating function. Must include parameters.
|
|
354
|
+
source_only: If ``True`` return the source-only Likelihood (leave out noise part).
|
|
355
|
+
waveform_kwargs: Keyword arguments to pass to waveform generator.
|
|
356
|
+
data_res_arr_kwargs: Keyword arguments for instantiation of :class:`DataResidualArray`.
|
|
357
|
+
This can be used if any transforms are desired prior to the Likelihood computation.
|
|
358
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
Likelihood value.
|
|
362
|
+
|
|
363
|
+
"""
|
|
364
|
+
|
|
365
|
+
return self._calculate_signal_operation(
|
|
366
|
+
"likelihood",
|
|
367
|
+
*args,
|
|
368
|
+
source_only=source_only,
|
|
369
|
+
waveform_kwargs=waveform_kwargs,
|
|
370
|
+
data_res_arr_kwargs=data_res_arr_kwargs,
|
|
371
|
+
**kwargs,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
def calculate_signal_inner_product(
|
|
375
|
+
self,
|
|
376
|
+
*args: Any,
|
|
377
|
+
source_only: bool = False,
|
|
378
|
+
waveform_kwargs: Optional[dict] = {},
|
|
379
|
+
data_res_arr_kwargs: Optional[dict] = {},
|
|
380
|
+
**kwargs: dict,
|
|
381
|
+
) -> float | complex:
|
|
382
|
+
"""Return the inner product of a generated signal with the data.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
*args: Arguments to waveform generating function. Must include parameters.
|
|
386
|
+
source_only: If ``True`` return the source-only Likelihood (leave out noise part).
|
|
387
|
+
waveform_kwargs: Keyword arguments to pass to waveform generator.
|
|
388
|
+
data_res_arr_kwargs: Keyword arguments for instantiation of :class:`DataResidualArray`.
|
|
389
|
+
This can be used if any transforms are desired prior to the Likelihood computation.
|
|
390
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
Inner product value.
|
|
394
|
+
|
|
395
|
+
"""
|
|
396
|
+
|
|
397
|
+
return self._calculate_signal_operation(
|
|
398
|
+
"inner_product",
|
|
399
|
+
*args,
|
|
400
|
+
source_only=source_only,
|
|
401
|
+
waveform_kwargs=waveform_kwargs,
|
|
402
|
+
data_res_arr_kwargs=data_res_arr_kwargs,
|
|
403
|
+
**kwargs,
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
def calculate_signal_snr(
|
|
407
|
+
self,
|
|
408
|
+
*args: Any,
|
|
409
|
+
source_only: bool = False,
|
|
410
|
+
waveform_kwargs: Optional[dict] = {},
|
|
411
|
+
data_res_arr_kwargs: Optional[dict] = {},
|
|
412
|
+
**kwargs: dict,
|
|
413
|
+
) -> Tuple[float, float]:
|
|
414
|
+
"""Return the SNR of a generated signal with the data.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
*args: Arguments to waveform generating function. Must include parameters.
|
|
418
|
+
source_only: If ``True`` return the source-only Likelihood (leave out noise part).
|
|
419
|
+
waveform_kwargs: Keyword arguments to pass to waveform generator.
|
|
420
|
+
data_res_arr_kwargs: Keyword arguments for instantiation of :class:`DataResidualArray`.
|
|
421
|
+
This can be used if any transforms are desired prior to the Likelihood computation.
|
|
422
|
+
**kwargs: Keyword arguments to pass to :func:`lisatools.diagnostic.inner_product`
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Snr values (optimal, detected).
|
|
426
|
+
|
|
427
|
+
"""
|
|
428
|
+
|
|
429
|
+
return self._calculate_signal_operation(
|
|
430
|
+
"snr",
|
|
431
|
+
*args,
|
|
432
|
+
source_only=source_only,
|
|
433
|
+
waveform_kwargs=waveform_kwargs,
|
|
434
|
+
data_res_arr_kwargs=data_res_arr_kwargs,
|
|
435
|
+
**kwargs,
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
def eryn_likelihood_function(
|
|
439
|
+
self, x: np.ndarray | list | tuple, *args: Any, **kwargs: Any
|
|
440
|
+
) -> np.ndarray | float:
|
|
441
|
+
"""Likelihood function for Eryn sampler.
|
|
442
|
+
|
|
443
|
+
This function is not vectorized.
|
|
444
|
+
|
|
445
|
+
``signal_gen`` must be set to use this function.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
x: Parameters. Can be 1D list, tuple, array or 2D array.
|
|
449
|
+
If a 2D array is input, the computation is done serially.
|
|
450
|
+
*args: Likelihood args.
|
|
451
|
+
**kwargs: Likelihood kwargs.
|
|
452
|
+
|
|
453
|
+
Returns:
|
|
454
|
+
Likelihood value(s).
|
|
455
|
+
|
|
456
|
+
"""
|
|
457
|
+
assert self.signal_gen is not None
|
|
458
|
+
|
|
459
|
+
if isinstance(x, list) or isinstance(x, tuple):
|
|
460
|
+
x = np.asarray(x)
|
|
461
|
+
|
|
462
|
+
if x.ndim == 1:
|
|
463
|
+
input_vals = tuple(x) + tuple(args)
|
|
464
|
+
return self.calculate_signal_likelihood(*input_vals, **kwargs)
|
|
465
|
+
elif x.ndim == 2:
|
|
466
|
+
likelihood_out = np.zeros(x.shape[0])
|
|
467
|
+
for i in range(x.shape[0]):
|
|
468
|
+
input_vals = tuple(x[i]) + tuple(args)
|
|
469
|
+
likelihood_out[i] = self.calculate_signal_likelihood(
|
|
470
|
+
*input_vals, **kwargs
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
else:
|
|
474
|
+
raise ValueError("x must be a 1D or 2D array.")
|
|
File without changes
|
|
Binary file
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#ifndef __DETECTOR_HPP__
|
|
2
|
+
#define __DETECTOR_HPP__
|
|
3
|
+
|
|
4
|
+
#include "global.hpp"
|
|
5
|
+
#include <iostream>
|
|
6
|
+
|
|
7
|
+
class Vec
|
|
8
|
+
{
|
|
9
|
+
public:
|
|
10
|
+
double x;
|
|
11
|
+
double y;
|
|
12
|
+
double z;
|
|
13
|
+
|
|
14
|
+
CUDA_DEVICE
|
|
15
|
+
Vec(double x_, double y_, double z_)
|
|
16
|
+
{
|
|
17
|
+
x = x_;
|
|
18
|
+
y = y_;
|
|
19
|
+
z = z_;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
class Orbits
|
|
24
|
+
{
|
|
25
|
+
public:
|
|
26
|
+
double dt;
|
|
27
|
+
int N;
|
|
28
|
+
double *n_arr;
|
|
29
|
+
double *ltt_arr;
|
|
30
|
+
double *x_arr;
|
|
31
|
+
int nlinks;
|
|
32
|
+
int nspacecraft;
|
|
33
|
+
double armlength;
|
|
34
|
+
int *links;
|
|
35
|
+
int *sc_r;
|
|
36
|
+
int *sc_e;
|
|
37
|
+
|
|
38
|
+
Orbits(double dt_, int N_, double *n_arr_, double *ltt_arr_, double *x_arr_, int *links_, int *sc_r_, int *sc_e_, double armlength_)
|
|
39
|
+
{
|
|
40
|
+
dt = dt_;
|
|
41
|
+
N = N_;
|
|
42
|
+
n_arr = n_arr_;
|
|
43
|
+
ltt_arr = ltt_arr_;
|
|
44
|
+
x_arr = x_arr_;
|
|
45
|
+
nlinks = 6;
|
|
46
|
+
nspacecraft = 3;
|
|
47
|
+
|
|
48
|
+
sc_r = sc_r_;
|
|
49
|
+
sc_e = sc_e_;
|
|
50
|
+
links = links_;
|
|
51
|
+
armlength = armlength_;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
int get_sc_r_from_arr(int i)
|
|
55
|
+
{
|
|
56
|
+
return sc_r[i];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
int get_sc_e_from_arr(int i)
|
|
60
|
+
{
|
|
61
|
+
return sc_e[i];
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
int get_link_from_arr(int i)
|
|
65
|
+
{
|
|
66
|
+
return links[i];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
CUDA_DEVICE int get_window(double t);
|
|
70
|
+
CUDA_DEVICE Vec get_normal_unit_vec(double t, int link);
|
|
71
|
+
CUDA_DEVICE double interpolate(double t, double *in_arr, int window, int major_ndim, int major_ind, int ndim, int pos);
|
|
72
|
+
CUDA_DEVICE int get_link_ind(int link);
|
|
73
|
+
CUDA_DEVICE int get_sc_ind(int sc);
|
|
74
|
+
CUDA_DEVICE double get_light_travel_time(double t, int link);
|
|
75
|
+
CUDA_DEVICE Vec get_pos(double t, int sc);
|
|
76
|
+
CUDA_DEVICE void get_normal_unit_vec_ptr(Vec *vec, double t, int link);
|
|
77
|
+
CUDA_DEVICE void get_pos_ptr(Vec *vec, double t, int sc);
|
|
78
|
+
void get_light_travel_time_arr(double *ltt, double *t, int *link, int num);
|
|
79
|
+
void get_pos_arr(double *pos_x, double *pos_y, double *pos_z, double *t, int *sc, int num);
|
|
80
|
+
void get_normal_unit_vec_arr(double *normal_unit_vec_x, double *normal_unit_vec_y, double *normal_unit_vec_z, double *t, int *link, int num);
|
|
81
|
+
void dealloc() {};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
#endif // __DETECTOR_HPP__
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#ifndef __GLOBAL_HPP__
|
|
2
|
+
#define __GLOBAL_HPP__
|
|
3
|
+
|
|
4
|
+
#ifdef __CUDACC__
|
|
5
|
+
#define CUDA_KERNEL __global__
|
|
6
|
+
#define CUDA_DEVICE __device__
|
|
7
|
+
|
|
8
|
+
#else // __CUDACC__
|
|
9
|
+
#define CUDA_KERNEL
|
|
10
|
+
#define CUDA_DEVICE
|
|
11
|
+
|
|
12
|
+
#endif // __CUDACC__
|
|
13
|
+
|
|
14
|
+
#ifdef __CUDACC__
|
|
15
|
+
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
|
|
16
|
+
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
|
|
17
|
+
{
|
|
18
|
+
if (code != cudaSuccess)
|
|
19
|
+
{
|
|
20
|
+
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
|
21
|
+
if (abort) exit(code);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
#endif // __GLOBAL_HPP__
|