lisaanalysistools 1.1.6__cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.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.

Files changed (42) hide show
  1. lisaanalysistools/git_version.py +7 -0
  2. lisaanalysistools-1.1.6.dist-info/METADATA +295 -0
  3. lisaanalysistools-1.1.6.dist-info/RECORD +42 -0
  4. lisaanalysistools-1.1.6.dist-info/WHEEL +6 -0
  5. lisaanalysistools-1.1.6.dist-info/licenses/LICENSE +201 -0
  6. lisatools/__init__.py +58 -0
  7. lisatools/_version.py +34 -0
  8. lisatools/analysiscontainer.py +474 -0
  9. lisatools/cutils/__init__.py +126 -0
  10. lisatools/datacontainer.py +312 -0
  11. lisatools/detector.py +704 -0
  12. lisatools/diagnostic.py +990 -0
  13. lisatools/git_version.py.in +7 -0
  14. lisatools/orbit_files/equalarmlength-orbits-best-fit-to-esa.h5 +0 -0
  15. lisatools/orbit_files/equalarmlength-orbits.h5 +0 -0
  16. lisatools/orbit_files/esa-trailing-orbits.h5 +0 -0
  17. lisatools/sampling/__init__.py +0 -0
  18. lisatools/sampling/likelihood.py +882 -0
  19. lisatools/sampling/moves/__init__.py +0 -0
  20. lisatools/sampling/moves/skymodehop.py +110 -0
  21. lisatools/sampling/prior.py +646 -0
  22. lisatools/sampling/stopping.py +320 -0
  23. lisatools/sampling/utility.py +411 -0
  24. lisatools/sensitivity.py +972 -0
  25. lisatools/sources/__init__.py +6 -0
  26. lisatools/sources/bbh/__init__.py +1 -0
  27. lisatools/sources/bbh/waveform.py +106 -0
  28. lisatools/sources/defaultresponse.py +36 -0
  29. lisatools/sources/emri/__init__.py +1 -0
  30. lisatools/sources/emri/waveform.py +79 -0
  31. lisatools/sources/gb/__init__.py +1 -0
  32. lisatools/sources/gb/waveform.py +69 -0
  33. lisatools/sources/utils.py +459 -0
  34. lisatools/sources/waveformbase.py +41 -0
  35. lisatools/stochastic.py +327 -0
  36. lisatools/utils/__init__.py +0 -0
  37. lisatools/utils/constants.py +54 -0
  38. lisatools/utils/exceptions.py +95 -0
  39. lisatools/utils/parallelbase.py +11 -0
  40. lisatools/utils/utility.py +245 -0
  41. lisatools_backend_cpu/git_version.py +7 -0
  42. lisatools_backend_cpu/pycppdetector.cpython-310-aarch64-linux-gnu.so +0 -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.")
@@ -0,0 +1,126 @@
1
+ from __future__ import annotations
2
+ import dataclasses
3
+ import enum
4
+ import types
5
+ import typing
6
+ import abc
7
+ from typing import Optional, Sequence, TypeVar, Union
8
+ from ..utils.exceptions import *
9
+
10
+ from gpubackendtools.gpubackendtools import BackendMethods, CpuBackend, Cuda11xBackend, Cuda12xBackend
11
+ from gpubackendtools.exceptions import *
12
+
13
+ @dataclasses.dataclass
14
+ class LISAToolsBackendMethods(BackendMethods):
15
+ pycppDetector: object
16
+
17
+ class LISAToolsBackend:
18
+ # TODO: not ClassVar?
19
+ pycppDetector: object
20
+
21
+ def __init__(self, lisatools_backend_methods):
22
+
23
+ # set direct lisatools methods
24
+ # pass rest to general backend
25
+ assert isinstance(lisatools_backend_methods, LISAToolsBackendMethods)
26
+ self.pycppDetector = lisatools_backend_methods.pycppDetector
27
+
28
+
29
+ class LISAToolsCpuBackend(CpuBackend, LISAToolsBackend):
30
+ """Implementation of the CPU backend"""
31
+
32
+ _backend_name = "lisatools_backend_cpu"
33
+ _name = "lisatools_cpu"
34
+ def __init__(self, *args, **kwargs):
35
+ CpuBackend.__init__(self, *args, **kwargs)
36
+ LISAToolsBackend.__init__(self, self.cpu_methods_loader())
37
+
38
+ @staticmethod
39
+ def cpu_methods_loader() -> LISAToolsBackendMethods:
40
+ try:
41
+ import lisatools_backend_cpu.pycppdetector
42
+
43
+ except (ModuleNotFoundError, ImportError) as e:
44
+ raise BackendUnavailableException(
45
+ "'cpu' backend could not be imported."
46
+ ) from e
47
+
48
+ numpy = LISAToolsCpuBackend.check_numpy()
49
+
50
+ return LISAToolsBackendMethods(
51
+ pycppDetector=lisatools_backend_cpu.pycppdetector.pycppDetector,
52
+ xp=numpy,
53
+ )
54
+
55
+
56
+ class LISAToolsCuda11xBackend(Cuda11xBackend, LISAToolsBackend):
57
+
58
+ """Implementation of CUDA 11.x backend"""
59
+ _backend_name : str = "lisatools_backend_cuda11x"
60
+ _name = "lisatools_cuda11x"
61
+
62
+ def __init__(self, *args, **kwargs):
63
+ Cuda11xBackend.__init__(self, *args, **kwargs)
64
+ LISAToolsBackend.__init__(self, self.cuda11x_module_loader())
65
+
66
+ @staticmethod
67
+ def cuda11x_module_loader():
68
+ try:
69
+ import lisatools_backend_cuda11x.utils
70
+
71
+ except (ModuleNotFoundError, ImportError) as e:
72
+ raise BackendUnavailableException(
73
+ "'cuda11x' backend could not be imported."
74
+ ) from e
75
+
76
+ try:
77
+ import cupy
78
+ except (ModuleNotFoundError, ImportError) as e:
79
+ raise MissingDependencies(
80
+ "'cuda11x' backend requires cupy", pip_deps=["cupy-cuda11x"]
81
+ ) from e
82
+
83
+ return LISAToolsBackendMethods(
84
+ pycppDetector=lisatools_backend_cuda11x.pycppdetector.pycppDetector,
85
+ xp=cupy,
86
+ )
87
+
88
+ class LISAToolsCuda12xBackend(Cuda12xBackend, LISAToolsBackend):
89
+ """Implementation of CUDA 12.x backend"""
90
+ _backend_name : str = "lisatools_backend_cuda12x"
91
+ _name = "lisatools_cuda12x"
92
+
93
+ def __init__(self, *args, **kwargs):
94
+ Cuda12xBackend.__init__(self, *args, **kwargs)
95
+ LISAToolsBackend.__init__(self, self.cuda12x_module_loader())
96
+
97
+ @staticmethod
98
+ def cuda12x_module_loader():
99
+ try:
100
+ import lisatools_backend_cuda12x.utils
101
+
102
+ except (ModuleNotFoundError, ImportError) as e:
103
+ raise BackendUnavailableException(
104
+ "'cuda12x' backend could not be imported."
105
+ ) from e
106
+
107
+ try:
108
+ import cupy
109
+ except (ModuleNotFoundError, ImportError) as e:
110
+ raise MissingDependencies(
111
+ "'cuda12x' backend requires cupy", pip_deps=["cupy-cuda12x"]
112
+ ) from e
113
+
114
+ return LISAToolsBackendMethods(
115
+ pycppDetector=lisatools_backend_cuda12x.pycppdetector.pycppDetector,
116
+ xp=cupy,
117
+ )
118
+
119
+
120
+ KNOWN_BACKENDS = {
121
+ "cuda12x": LISAToolsCuda12xBackend,
122
+ "cuda11x": LISAToolsCuda11xBackend,
123
+ "cpu": LISAToolsCpuBackend,
124
+ }
125
+
126
+ """List of existing backends, per default order of preference."""