lisaanalysistools 1.0.0__cp312-cp312-macosx_10_9_x86_64.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.0.dist-info/LICENSE +201 -0
- lisaanalysistools-1.0.0.dist-info/METADATA +80 -0
- lisaanalysistools-1.0.0.dist-info/RECORD +37 -0
- lisaanalysistools-1.0.0.dist-info/WHEEL +5 -0
- lisaanalysistools-1.0.0.dist-info/top_level.txt +2 -0
- lisatools/__init__.py +0 -0
- lisatools/_version.py +4 -0
- lisatools/analysiscontainer.py +438 -0
- lisatools/cutils/detector.cpython-312-darwin.so +0 -0
- lisatools/datacontainer.py +292 -0
- lisatools/detector.py +410 -0
- lisatools/diagnostic.py +976 -0
- lisatools/glitch.py +193 -0
- lisatools/sampling/__init__.py +0 -0
- lisatools/sampling/likelihood.py +882 -0
- lisatools/sampling/moves/__init__.py +0 -0
- lisatools/sampling/moves/gbgroupstretch.py +53 -0
- lisatools/sampling/moves/gbmultipletryrj.py +1287 -0
- lisatools/sampling/moves/gbspecialgroupstretch.py +671 -0
- lisatools/sampling/moves/gbspecialstretch.py +1836 -0
- lisatools/sampling/moves/mbhspecialmove.py +286 -0
- lisatools/sampling/moves/placeholder.py +16 -0
- lisatools/sampling/moves/skymodehop.py +110 -0
- lisatools/sampling/moves/specialforegroundmove.py +564 -0
- lisatools/sampling/prior.py +508 -0
- lisatools/sampling/stopping.py +320 -0
- lisatools/sampling/utility.py +324 -0
- lisatools/sensitivity.py +888 -0
- lisatools/sources/__init__.py +0 -0
- lisatools/sources/emri/__init__.py +1 -0
- lisatools/sources/emri/tdiwaveform.py +72 -0
- lisatools/stochastic.py +291 -0
- lisatools/utils/__init__.py +0 -0
- lisatools/utils/constants.py +40 -0
- lisatools/utils/multigpudataholder.py +730 -0
- lisatools/utils/pointeradjust.py +106 -0
- lisatools/utils/utility.py +240 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# check to see if cupy is available for gpus
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
import cupy as xp
|
|
6
|
+
|
|
7
|
+
gpu = True
|
|
8
|
+
|
|
9
|
+
except (ImportError, ModuleNotFoundError) as e:
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
gpu = False
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def wrapper(*args, **kwargs):
|
|
16
|
+
"""Function to convert array and C/C++ class arguments to ptrs
|
|
17
|
+
|
|
18
|
+
This function checks the object type. If it is a cupy or numpy array,
|
|
19
|
+
it will determine its pointer by calling the proper attributes. If you design
|
|
20
|
+
a Cython class to be passed through python, it must have a :code:`ptr`
|
|
21
|
+
attribute.
|
|
22
|
+
|
|
23
|
+
If you use this function, you must convert input arrays to size_t data type in Cython and
|
|
24
|
+
then properly cast the pointer as it enters the c++ function. See the
|
|
25
|
+
Cython codes
|
|
26
|
+
`here <https://github.com/BlackHolePerturbationToolkit/FastEMRIWaveforms/tree/master/src>`_
|
|
27
|
+
for examples.
|
|
28
|
+
|
|
29
|
+
args:
|
|
30
|
+
*args (list): list of the arguments for a function.
|
|
31
|
+
**kwargs (dict): dictionary of keyword arguments to be converted.
|
|
32
|
+
|
|
33
|
+
returns:
|
|
34
|
+
Tuple: (targs, tkwargs) where t indicates target (with pointer values
|
|
35
|
+
rather than python objects).
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
# declare target containers
|
|
39
|
+
targs = []
|
|
40
|
+
tkwargs = {}
|
|
41
|
+
|
|
42
|
+
# args first
|
|
43
|
+
for arg in args:
|
|
44
|
+
if gpu:
|
|
45
|
+
# cupy arrays
|
|
46
|
+
if isinstance(arg, xp.ndarray):
|
|
47
|
+
targs.append(arg.data.mem.ptr)
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
# numpy arrays
|
|
51
|
+
if isinstance(arg, np.ndarray):
|
|
52
|
+
targs.append(arg.__array_interface__["data"][0])
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
# cython classes
|
|
57
|
+
targs.append(arg.ptr)
|
|
58
|
+
continue
|
|
59
|
+
except AttributeError:
|
|
60
|
+
# regular argument
|
|
61
|
+
targs.append(arg)
|
|
62
|
+
|
|
63
|
+
# kwargs next
|
|
64
|
+
for key, arg in kwargs.items():
|
|
65
|
+
if gpu:
|
|
66
|
+
# cupy arrays
|
|
67
|
+
if isinstance(arg, xp.ndarray):
|
|
68
|
+
tkwargs[key] = arg.data.mem.ptr
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
if isinstance(arg, np.ndarray):
|
|
72
|
+
# numpy arrays
|
|
73
|
+
tkwargs[key] = arg.__array_interface__["data"][0]
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
# cython classes
|
|
78
|
+
tkwargs[key] = arg.ptr
|
|
79
|
+
continue
|
|
80
|
+
except AttributeError:
|
|
81
|
+
# other arguments
|
|
82
|
+
tkwargs[key] = arg
|
|
83
|
+
|
|
84
|
+
return (targs, tkwargs)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def pointer_adjust(func):
|
|
88
|
+
"""Decorator function for cupy/numpy agnostic cython
|
|
89
|
+
|
|
90
|
+
This decorator applies :func:`few.utils.utility.wrapper` to functions
|
|
91
|
+
via the decorator construction.
|
|
92
|
+
|
|
93
|
+
If you use this decorator, you must convert input arrays to size_t data type in Cython and
|
|
94
|
+
then properly cast the pointer as it enters the c++ function. See the
|
|
95
|
+
Cython codes
|
|
96
|
+
`here <https://github.com/BlackHolePerturbationToolkit/FastEMRIWaveforms/tree/master/src>`_
|
|
97
|
+
for examples.
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def func_wrapper(*args, **kwargs):
|
|
102
|
+
# get pointers
|
|
103
|
+
targs, tkwargs = wrapper(*args, **kwargs)
|
|
104
|
+
return func(*targs, **tkwargs)
|
|
105
|
+
|
|
106
|
+
return func_wrapper
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
from multiprocessing.sharedctypes import Value
|
|
2
|
+
from types import ModuleType, NoneType
|
|
3
|
+
from typing import Tuple
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
# from ..sensitivity import get_sensitivity
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import cupy as cp
|
|
10
|
+
|
|
11
|
+
except (ModuleNotFoundError, ImportError):
|
|
12
|
+
import numpy as cp
|
|
13
|
+
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_array_module(arr: np.ndarray | cp.ndarray) -> ModuleType:
|
|
18
|
+
"""Return array library of an array (np/cp).
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
arr: Numpy or Cupy array.
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
if isinstance(arr, np.ndarray):
|
|
25
|
+
return np
|
|
26
|
+
elif isinstance(arr, cp.ndarray):
|
|
27
|
+
return cp
|
|
28
|
+
else:
|
|
29
|
+
raise ValueError("arr must be a numpy or cupy array.")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def generate_noise_fd(freqs, df, *sensitivity_args, func=None, **sensitivity_kwargs):
|
|
33
|
+
if func is None:
|
|
34
|
+
func = get_sensitivity
|
|
35
|
+
|
|
36
|
+
norm = 0.5 * (1.0 / df) ** 0.5
|
|
37
|
+
psd = func(freqs, *sensitivity_args, **sensitivity_kwargs)
|
|
38
|
+
noise_to_add = psd ** (1 / 2) * (
|
|
39
|
+
np.random.normal(0, norm, len(freqs))
|
|
40
|
+
+ 1j * np.random.normal(0, norm, len(freqs))
|
|
41
|
+
)
|
|
42
|
+
return noise_to_add
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def AET(
|
|
46
|
+
X: float | np.ndarray, Y: float | np.ndarray, Z: float | np.ndarray
|
|
47
|
+
) -> Tuple[float | np.ndarray, float | np.ndarray, float | np.ndarray]:
|
|
48
|
+
"""Transform to AET from XYZ
|
|
49
|
+
|
|
50
|
+
.. math::
|
|
51
|
+
|
|
52
|
+
A = (Z - X) / \\sqrt(2)
|
|
53
|
+
|
|
54
|
+
.. math::
|
|
55
|
+
|
|
56
|
+
E = (X - 2Y + Z) / \\sqrt(6)
|
|
57
|
+
|
|
58
|
+
.. math::
|
|
59
|
+
|
|
60
|
+
T = (X + Y + Z) / \\sqrt(3)
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
X: X-channel information.
|
|
64
|
+
Y: Y-channel information.
|
|
65
|
+
Z: Z-channel information.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
A, E, T Channels.
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
return (
|
|
72
|
+
(Z - X) / np.sqrt(2.0),
|
|
73
|
+
(X - 2.0 * Y + Z) / np.sqrt(6.0),
|
|
74
|
+
(X + Y + Z) / np.sqrt(3.0),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def searchsorted2d_vec(a, b, xp=None, gpu=None, **kwargs):
|
|
79
|
+
if xp is None:
|
|
80
|
+
xp = np
|
|
81
|
+
else:
|
|
82
|
+
try:
|
|
83
|
+
xp.cuda.runtime.setDevice(gpu)
|
|
84
|
+
except AttributeError:
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
m, n = a.shape
|
|
88
|
+
max_num = xp.maximum(a.max() - a.min(), b.max() - b.min()) + 1
|
|
89
|
+
r = max_num * xp.arange(a.shape[0])[:, None]
|
|
90
|
+
p = xp.searchsorted((a + r).ravel(), (b + r).ravel(), **kwargs).reshape(m, -1)
|
|
91
|
+
|
|
92
|
+
out = p - n * (xp.arange(m)[:, None])
|
|
93
|
+
try:
|
|
94
|
+
xp.cuda.runtime.deviceSynchronize()
|
|
95
|
+
except AttributeError:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
return out
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_groups_from_band_structure(
|
|
102
|
+
f0, band_edges, f0_2=None, xp=None, num_groups_base=3, fix_f_test=None, inds=None
|
|
103
|
+
):
|
|
104
|
+
if num_groups_base not in [2, 3, 4]:
|
|
105
|
+
raise ValueError("num_groups_base must be 2 or 3 or 4.")
|
|
106
|
+
if xp is None:
|
|
107
|
+
xp = np
|
|
108
|
+
|
|
109
|
+
else:
|
|
110
|
+
try:
|
|
111
|
+
xp.cuda.runtime.setDevice(xp.cuda.runtime.getDevice())
|
|
112
|
+
|
|
113
|
+
except AttributeError:
|
|
114
|
+
# it is numpy
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
if not isinstance(f0, xp.ndarray) or not isinstance(band_edges, xp.ndarray):
|
|
118
|
+
raise TypeError(
|
|
119
|
+
"f0 and band_edges must be xp.ndarray with xp as numpy or cupy as given by the xp kwarg."
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
shape = f0.shape
|
|
123
|
+
|
|
124
|
+
# remove any above or below bands
|
|
125
|
+
bad = (f0 < band_edges.min()) | (f0 > band_edges.max())
|
|
126
|
+
|
|
127
|
+
band_indices = xp.searchsorted(band_edges, f0.flatten()).reshape(shape) - 1
|
|
128
|
+
|
|
129
|
+
# sort the bands in, but keep places with inds_band_indices
|
|
130
|
+
band_indices_sorted = xp.sort(band_indices, axis=-1)
|
|
131
|
+
inds_band_indices = xp.argsort(band_indices, axis=-1)
|
|
132
|
+
|
|
133
|
+
if f0_2 is not None:
|
|
134
|
+
assert f0_2.shape == f0.shape
|
|
135
|
+
band_indices_2 = xp.searchsorted(band_edges, f0_2.flatten()).reshape(shape) - 1
|
|
136
|
+
band_indices_2_sorted = xp.take_along_axis(
|
|
137
|
+
band_indices_2, inds_band_indices, axis=-1
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# very important: ensures the proposed new point is not further than 1 band away.
|
|
141
|
+
diff = 1 if num_groups_base > 2 else 0
|
|
142
|
+
keep = (
|
|
143
|
+
np.abs(band_indices_2_sorted.flatten() - band_indices_sorted.flatten())
|
|
144
|
+
<= diff
|
|
145
|
+
)
|
|
146
|
+
if fix_f_test is not None:
|
|
147
|
+
keep[fix_f_test.flatten()] = False
|
|
148
|
+
remove = ~keep
|
|
149
|
+
|
|
150
|
+
else:
|
|
151
|
+
keep = np.ones(np.prod(band_indices_sorted.shape), dtype=bool)
|
|
152
|
+
|
|
153
|
+
# temperature index associated with each band
|
|
154
|
+
temp_inds = xp.repeat(
|
|
155
|
+
xp.arange(band_indices_sorted.shape[0]), np.prod(band_indices_sorted.shape[1:])
|
|
156
|
+
)[
|
|
157
|
+
keep
|
|
158
|
+
] # .reshape(shape)
|
|
159
|
+
|
|
160
|
+
# walker index associated with each band
|
|
161
|
+
walker_inds = (
|
|
162
|
+
xp.tile(
|
|
163
|
+
xp.arange(band_indices_sorted.shape[1]),
|
|
164
|
+
(band_indices_sorted.shape[0], band_indices_sorted.shape[2], 1),
|
|
165
|
+
)
|
|
166
|
+
.transpose((0, 2, 1))
|
|
167
|
+
.flatten()[keep]
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if f0_2 is not None:
|
|
171
|
+
temp_inds_remove = xp.repeat(
|
|
172
|
+
xp.arange(band_indices_sorted.shape[0]),
|
|
173
|
+
np.prod(band_indices_sorted.shape[1:]),
|
|
174
|
+
)[
|
|
175
|
+
remove
|
|
176
|
+
] # .reshape(shape)
|
|
177
|
+
|
|
178
|
+
# walker index associated with each band
|
|
179
|
+
walker_inds_remove = (
|
|
180
|
+
xp.tile(
|
|
181
|
+
xp.arange(band_indices_sorted.shape[1]),
|
|
182
|
+
(band_indices_sorted.shape[0], band_indices_sorted.shape[2], 1),
|
|
183
|
+
)
|
|
184
|
+
.transpose((0, 2, 1))
|
|
185
|
+
.flatten()[remove]
|
|
186
|
+
)
|
|
187
|
+
inds_band_indices_remove = inds_band_indices.flatten()[remove]
|
|
188
|
+
|
|
189
|
+
# special indexing method
|
|
190
|
+
band_indices_sorted_special = (
|
|
191
|
+
band_indices_sorted.flatten()[keep]
|
|
192
|
+
+ int(1e12) * temp_inds
|
|
193
|
+
+ int(1e6) * walker_inds
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# get the unique special indicators
|
|
197
|
+
(
|
|
198
|
+
unique_special,
|
|
199
|
+
unique_special_start_inds,
|
|
200
|
+
unique_special_reverse,
|
|
201
|
+
unique_special_counts,
|
|
202
|
+
) = np.unique(
|
|
203
|
+
band_indices_sorted_special,
|
|
204
|
+
return_index=True,
|
|
205
|
+
return_inverse=True,
|
|
206
|
+
return_counts=True,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# this basically makes mini arange setups for each band
|
|
210
|
+
# the added_contribution for the first unique band index is removed
|
|
211
|
+
added_contribution = xp.arange(band_indices_sorted_special.shape[0])
|
|
212
|
+
|
|
213
|
+
# gets the groups
|
|
214
|
+
combined = band_indices_sorted_special + added_contribution
|
|
215
|
+
groups = (
|
|
216
|
+
combined - (combined[unique_special_start_inds])[unique_special_reverse]
|
|
217
|
+
) # .reshape(shape)
|
|
218
|
+
|
|
219
|
+
groups_even_odd_tmp = xp.asarray(
|
|
220
|
+
[
|
|
221
|
+
(num_groups_base * groups + i)
|
|
222
|
+
* (band_indices_sorted.flatten()[keep] % num_groups_base == i)
|
|
223
|
+
for i in range(num_groups_base)
|
|
224
|
+
]
|
|
225
|
+
)
|
|
226
|
+
groups_even_odd = xp.sum(groups_even_odd_tmp, axis=0)
|
|
227
|
+
|
|
228
|
+
groups_out = -2 * xp.ones_like(f0, dtype=int)
|
|
229
|
+
groups_out[
|
|
230
|
+
(temp_inds, walker_inds, inds_band_indices.flatten()[keep])
|
|
231
|
+
] = groups_even_odd
|
|
232
|
+
|
|
233
|
+
groups_out[bad] = -1
|
|
234
|
+
|
|
235
|
+
"""if f0_2 is not None and not np.all(keep):
|
|
236
|
+
fix = (temp_inds_remove, walker_inds_remove, inds_band_indices_remove)
|
|
237
|
+
fix_2 = band_indices_2[fix]
|
|
238
|
+
fix_1 = band_indices[fix]"""
|
|
239
|
+
|
|
240
|
+
return groups_out
|