pybhpt 0.9.4__cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_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 pybhpt might be problematic. Click here for more details.

pybhpt/__init__.py ADDED
File without changes
pybhpt/flux.py ADDED
@@ -0,0 +1,124 @@
1
+ from cybhpt_full import FluxList as FluxListCython
2
+ from cybhpt_full import flux as FluxCython
3
+
4
+ class FluxList:
5
+ """A class for storing fluxes of energy, angular momentum, and Carter constant.
6
+
7
+ Parameters
8
+ ----------
9
+ fluxes : list of dicts, optional
10
+ A list containing three dictionaries, each with keys "I" and "H" representing the fluxes at infinity and on the horizon, respectively.
11
+ If not provided, initializes with zero fluxes for all three components.
12
+
13
+ Attributes
14
+ ----------
15
+ fluxes : list of dicts
16
+ A list containing three dictionaries, each with keys "I" and "H" representing the fluxes at infinity and on the horizon, respectively.
17
+ The first dictionary corresponds to energy flux,
18
+ the second to angular momentum flux, and the third to Carter constant flux.
19
+
20
+ Methods
21
+ -------
22
+ __call__():
23
+ Returns the list of fluxes.
24
+ """
25
+ def __init__(self, fluxes=None):
26
+ if fluxes is None:
27
+ self.fluxes = [{"I": 0., "H": 0.}, {"I": 0., "H": 0.}, {"I": 0., "H": 0.}]
28
+ elif len(fluxes) != 3:
29
+ self.fluxes = [{"I": 0., "H": 0.}, {"I": 0., "H": 0.}, {"I": 0., "H": 0.}]
30
+ else:
31
+ self.fluxes = fluxes
32
+
33
+ # def __add__(self, fluxlist2):
34
+ # for i in range(3):
35
+ # for bc in ["H", "I"]:
36
+ # self.fluxes[i][bc] += fluxlist2.fluxes[i][bc]
37
+
38
+ @property
39
+ def energy(self):
40
+ return self.fluxes[0]
41
+
42
+ @property
43
+ def angularmomentum(self):
44
+ return self.fluxes[1]
45
+
46
+ @property
47
+ def carterconstant(self):
48
+ return self.fluxes[2]
49
+
50
+ def __call__(self):
51
+ return self.fluxes
52
+
53
+
54
+ class FluxMode:
55
+ """A class for computing fluxes of energy, angular momentum, and Carter constant for a given Teukolsky mode.
56
+
57
+ Parameters
58
+ ----------
59
+ geo : KerrGeodesic class instance
60
+ KerrGeodesic object containing the background motion of the point-particle source.
61
+
62
+ teuk : TeukolskyMode object
63
+ TeukolskyMode object containing mode solutions to the point-particle-sourced Teukolsky equation.
64
+
65
+ Attributes
66
+ ----------
67
+ energy : dict
68
+ A dictionary containing the energy flux at infinity and on the horizon.
69
+ The keys are "I" for infinity and "H" for the horizon.
70
+ angularmomentum : dict
71
+ A dictionary containing the angular momentum flux at infinity and on the horizon.
72
+ The keys are "I" for infinity and "H" for the horizon.
73
+ carterconstant : dict
74
+ A dictionary containing the Carter constant flux at infinity and on the horizon.
75
+ The keys are "I" for infinity and "H" for the horizon.
76
+ fluxes : FluxList
77
+ A FluxList object containing the energy, angular momentum, and Carter constant fluxes.
78
+ horizonfluxes : list
79
+ A list containing the energy, angular momentum, and Carter constant fluxes on the horizon.
80
+ infinityfluxes : list
81
+ A list containing the energy, angular momentum, and Carter constant fluxes at infinity.
82
+ totalfluxes : list
83
+ A list containing the total fluxes, which are the sum of the horizon and infinity fluxes.
84
+ """
85
+ def __init__(self, geo, teuk):
86
+ self.base = FluxCython(teuk.spinweight, geo.base, teuk.base)
87
+
88
+ @property
89
+ def energy(self):
90
+ return self.base.energy
91
+
92
+ @property
93
+ def angularmomentum(self):
94
+ return self.base.angularmomentum
95
+
96
+ @property
97
+ def carterconstant(self):
98
+ return self.base.carterconstant
99
+
100
+ @property
101
+ def Edot(self):
102
+ return self.energy
103
+ @property
104
+ def Ldot(self):
105
+ return self.angularmomentum
106
+ @property
107
+ def Qdot(self):
108
+ return self.carterconstant
109
+
110
+ @property
111
+ def fluxes(self):
112
+ return FluxList([self.energy, self.angularmomentum, self.carterconstant])
113
+
114
+ @property
115
+ def horizonfluxes(self):
116
+ return [self.energy["H"], self.angularmomentum["H"], self.carterconstant["H"]]
117
+
118
+ @property
119
+ def infinityfluxes(self):
120
+ return [self.energy["I"], self.angularmomentum["I"], self.carterconstant["I"]]
121
+
122
+ @property
123
+ def totalfluxes(self):
124
+ return [self.energy["I"] + self.energy["H"], self.angularmomentum["I"] + self.angularmomentum["H"], self.carterconstant["I"] + self.carterconstant["H"]]
pybhpt/geo.py ADDED
@@ -0,0 +1,407 @@
1
+ from cybhpt_full import KerrGeodesic as KerrGeodesicCython
2
+ from cybhpt_full import kerr_geo_V01, kerr_geo_V02, kerr_geo_V11, kerr_geo_V22, kerr_geo_V31, kerr_geo_V32
3
+ from cybhpt_full import kerr_mino_frequencies_wrapper, kerr_orbital_constants_wrapper
4
+ import numpy as np
5
+
6
+ def kerrgeo_Vt_radial(a, En, Lz, Q, r):
7
+ return kerr_geo_V01(a, En, Lz, Q, r)
8
+
9
+ def kerrgeo_Vt_polar(a, En, Lz, Q, theta):
10
+ return kerr_geo_V02(a, En, Lz, Q, theta)
11
+
12
+ def kerrgeo_Vr(a, En, Lz, Q, r):
13
+ return kerr_geo_V11(a, En, Lz, Q, r)
14
+
15
+ def kerrgeo_Vtheta(a, En, Lz, Q, theta):
16
+ return kerr_geo_V22(a, En, Lz, Q, theta)
17
+
18
+ def kerrgeo_Vphi_radial(a, En, Lz, Q, r):
19
+ return kerr_geo_V31(a, En, Lz, Q, r)
20
+
21
+ def kerrgeo_Vphi_polar(a, En, Lz, Q, theta):
22
+ return kerr_geo_V32(a, En, Lz, Q, theta)
23
+
24
+ def kerr_mino_frequencies(a, p, e, x):
25
+ """
26
+ Returns the Mino frequencies of a Kerr geodesic.
27
+
28
+ Parameters
29
+ ----------
30
+ a : float
31
+ The black hole spin parameter.
32
+ p : float
33
+ The semilatus rectum of the orbit.
34
+ e : float
35
+ The eccentricity of the orbit.
36
+ x : float
37
+ The inclination of the orbit.
38
+
39
+ Returns
40
+ -------
41
+ numpy.ndarray
42
+ The Mino time frequencies of the orbit.
43
+ """
44
+ return kerr_mino_frequencies_wrapper(a, p, e, x)
45
+
46
+ def kerr_fundamental_frequencies(a, p, e, x):
47
+ """
48
+ Returns the fundamental (time) frequencies of a Kerr geodesic.
49
+
50
+ Parameters
51
+ ----------
52
+ a : float
53
+ The black hole spin parameter.
54
+ p : float
55
+ The semilatus rectum of the orbit.
56
+ e : float
57
+ The eccentricity of the orbit.
58
+ x : float
59
+ The inclination of the orbit.
60
+
61
+ Returns
62
+ -------
63
+ numpy.ndarray
64
+ The fundamental frequencies of the orbit.
65
+ """
66
+ Ups = kerr_mino_frequencies(a, p, e, x)
67
+ return Ups[1:]/Ups[0]
68
+
69
+ def kerr_orbital_constants(a, p, e, x):
70
+ """
71
+ Returns the orbital constants of a Kerr geodesic (En, Lz, Qc).
72
+
73
+ Parameters
74
+ ----------
75
+ a : float
76
+ The black hole spin parameter.
77
+ p : float
78
+ The semilatus rectum of the orbit.
79
+ e : float
80
+ The eccentricity of the orbit.
81
+ x : float
82
+ The inclination of the orbit.
83
+
84
+ Returns
85
+ -------
86
+ numpy.ndarray
87
+ The orbital constants (En, Lz, Qc) of the orbit.
88
+ """
89
+ return kerr_orbital_constants_wrapper(a, p, e, x)
90
+
91
+ def is_power_of_two(n: int) -> bool:
92
+ return n > 0 and (n & (n - 1)) == 0
93
+
94
+ class KerrGeodesic:
95
+ """
96
+ Class that produces a Kerr geodesic given the parameters of the orbit.
97
+ This class is a wrapper around the Cython implementation of the Kerr geodesic
98
+ and provides a Python interface to the underlying C++ code.
99
+ Parameters
100
+ ----------
101
+ a : float
102
+ The black hole spin parameter.
103
+ p : float
104
+ The semilatus rectum of the orbit.
105
+ e : float
106
+ The eccentricity of the orbit.
107
+ x : float
108
+ The inclination of the orbit.
109
+ nsamples : int
110
+ The number of samples to use for the geodesic. Must be a power of two. Default is 256.
111
+
112
+ Attributes
113
+ ----------
114
+ blackholespin : float
115
+ The black hole spin parameter.
116
+ semilatusrectum : float
117
+ The semilatus rectum of the orbit.
118
+ eccentricity : float
119
+ The eccentricity of the orbit.
120
+ inclination : float
121
+ The inclination of the orbit.
122
+ orbitalenergy : float
123
+ The orbital energy En of the orbit.
124
+ orbitalangularmomentum : float
125
+ Th z-component of the orbital angular momentum Lz of the orbit.
126
+ carterconstant : float
127
+ The Carter constant Qc of the orbit.
128
+ orbitalconstants : numpy.ndarray
129
+ The orbital constants (En, Lz, Qc) of the orbit.
130
+ radialroots : numpy.ndarray
131
+ The roots of the radial equation.
132
+ polarroots : numpy.ndarray
133
+ The roots of the polar equation.
134
+ minofrequencies : numpy.ndarray
135
+ The orbital frequencies with respect to Mino time.
136
+ timefrequencies : numpy.ndarray
137
+ The orbital frequencies with respect to the time coordinate.
138
+ frequencies : numpy.ndarray
139
+ The (coordinate time) frequencies of the orbit.
140
+ carterfrequencies : numpy.ndarray
141
+ The frequencies for computing Carter constant fluxes.
142
+ timeradialfourier : numpy.ndarray
143
+ The Fourier coefficients of coordinate time with respect to the radial Mino phase.
144
+ timepolarfourier : numpy.ndarray
145
+ The Fourier coefficients of coordinate time with respect to the polar Mino phase.
146
+ radialfourier : numpy.ndarray
147
+ The Fourier coefficients of radial position with respect to the radial Mino phase.
148
+ polarfourier : numpy.ndarray
149
+ The Fourier coefficients of polar position with respect to the polar Mino phase.
150
+ azimuthalradialfourier : numpy.ndarray
151
+ The Fourier coefficients of azimuthal position with respect to the radial Mino phase.
152
+ azimuthalpolarfourier : numpy.ndarray
153
+ The Fourier coefficients of azimuthal position with respect to the polar Mino phase.
154
+ """
155
+ def __init__(self, a, p, e, x, nsamples = 2**8):
156
+ if a < 0 or a > 1:
157
+ raise ValueError(f"Black hole spin parameter {a} must be in the range [0, 1].")
158
+ if not is_power_of_two(nsamples):
159
+ raise ValueError(f"Number of samples {nsamples} must be a power of 2.")
160
+
161
+ self.base = KerrGeodesicCython(a, p, e, x, nsamples)
162
+ """The base class that contains the Cython implementation of the Kerr geodesic."""
163
+ self.timeradial = self.base.get_time_accumulation(1)
164
+ self.timepolar = self.base.get_time_accumulation(2)
165
+ self.radialpoints = self.base.get_radial_points()
166
+ self.polarpoints = self.base.get_polar_points()
167
+ self.azimuthalradial = self.base.get_azimuthal_accumulation(1)
168
+ self.azimuthalpolar = self.base.get_azimuthal_accumulation(2)
169
+ self.nsamples = self.base.nsamples
170
+
171
+ if np.isnan(self.frequencies).any():
172
+ raise ValueError(f"Orbital parameters (a, p, e, x) = {self.apex} do not represent a valid bound non-plunging orbit.")
173
+
174
+ @property
175
+ def blackholespin(self):
176
+ """
177
+ The black hole spin parameter.
178
+ """
179
+ return self.base.blackholespin
180
+
181
+ @property
182
+ def semilatusrectum(self):
183
+ """
184
+ The semilatus rectum of the orbit.
185
+ """
186
+ return self.base.semilatusrectum
187
+
188
+ @property
189
+ def eccentricity(self):
190
+ """
191
+ The eccentricity of the orbit.
192
+ """
193
+ return self.base.eccentricity
194
+
195
+ @property
196
+ def inclination(self):
197
+ """
198
+ The cosine of the inclination angle of the orbit with respect to the equatorial plane.
199
+ """
200
+ return self.base.inclination
201
+
202
+ @property
203
+ def a(self):
204
+ """
205
+ The black hole spin parameter.
206
+ """
207
+ return self.blackholespin
208
+
209
+ @property
210
+ def p(self):
211
+ """
212
+ The semilatus rectum of the orbit.
213
+ """
214
+ return self.semilatusrectum
215
+
216
+ @property
217
+ def e(self):
218
+ """
219
+ The eccentricity of the orbit.
220
+ """
221
+ return self.eccentricity
222
+
223
+ @property
224
+ def x(self):
225
+ """
226
+ The inclination of the orbit.
227
+ """
228
+ return self.inclination
229
+
230
+ @property
231
+ def apex(self):
232
+ """
233
+ The parameters of the orbit (a, p, e, x).
234
+ """
235
+ return np.array([self.blackholespin, self.semilatusrectum, self.eccentricity, self.inclination])
236
+
237
+ @property
238
+ def orbitalparameters(self):
239
+ """
240
+ The parameters of the orbit (a, p, e, x).
241
+ """
242
+ return self.apex
243
+
244
+ @property
245
+ def orbitalenergy(self):
246
+ """
247
+ The orbital energy En of the orbit.
248
+ """
249
+ return self.base.orbitalenergy
250
+
251
+ @property
252
+ def orbitalangularmomentum(self):
253
+ """
254
+ The z-component of the orbital angular momentum Lz of the orbit.
255
+ """
256
+ return self.base.orbitalangularmomentum
257
+
258
+ @property
259
+ def carterconstant(self):
260
+ """
261
+ The Carter constant Qc of the orbit.
262
+ """
263
+ return self.base.carterconstant
264
+
265
+ @property
266
+ def orbitalconstants(self):
267
+ """
268
+ The orbital constants (En, Lz, Qc) of the orbit.
269
+ """
270
+ return np.array([self.orbitalenergy, self.orbitalangularmomentum, self.carterconstant])
271
+
272
+ @property
273
+ def radialroots(self):
274
+ """
275
+ The roots of the radial equation.
276
+ """
277
+ return self.base.radialroots
278
+
279
+ @property
280
+ def polarroots(self):
281
+ """
282
+ The roots of the polar equation.
283
+ """
284
+ return self.base.polarroots
285
+
286
+ @property
287
+ def minofrequencies(self):
288
+ """
289
+ The orbital frequencies with respect to Mino time.
290
+ """
291
+ return self.base.minofrequencies
292
+
293
+ @property
294
+ def timefrequencies(self):
295
+ """
296
+ The orbital frequencies with respect to the time coordinate.
297
+ """
298
+ return self.base.timefrequencies
299
+
300
+ @property
301
+ def frequencies(self):
302
+ """
303
+ The (coordinate time) frequencies of the orbit.
304
+ """
305
+ return self.timefrequencies
306
+
307
+ @property
308
+ def carterfrequencies(self):
309
+ """
310
+ The frequencies for computing Carter constant fluxes.
311
+ """
312
+ return self.base.carterfrequencies
313
+
314
+ @property
315
+ def timeradialfourier(self):
316
+ """
317
+ The Fourier coefficients of coordinate time with respect to the radial Mino phase.
318
+ """
319
+ return self.base.get_time_coefficients(1)
320
+
321
+ @property
322
+ def timepolarfourier(self):
323
+ """
324
+ The Fourier coefficients of coordinate time with respect to the polar Mino phase.
325
+ """
326
+ return self.base.get_time_coefficients(2)
327
+
328
+ @property
329
+ def radialfourier(self):
330
+ """
331
+ The Fourier coefficients of radial position with respect to the radial Mino phase.
332
+ """
333
+ return self.base.get_radial_coefficients()
334
+
335
+ @property
336
+ def polarfourier(self):
337
+ """
338
+ The Fourier coefficients of polar position with respect to the polar Mino phase.
339
+ """
340
+ return self.base.get_polar_coefficients()
341
+
342
+ @property
343
+ def azimuthalradialfourier(self):
344
+ """
345
+ The Fourier coefficients of azimuthal position with respect to the radial Mino phase.
346
+ """
347
+ return self.base.get_azimuthal_coefficients(1)
348
+
349
+ @property
350
+ def azimuthalpolarfourier(self):
351
+ """
352
+ The Fourier coefficients of azimuthal position with respect to the polar Mino phase.
353
+ """
354
+ return self.base.get_azimuthal_coefficients(2)
355
+
356
+ def mode_frequency(self, m, k, n):
357
+ """
358
+ Returns the frequency of the mode with azimuthal number m, polar number k, and radial number n.
359
+
360
+ Parameters
361
+ ----------
362
+ m : int
363
+ The azimuthal number of the mode.
364
+ k : int
365
+ The polar number of the mode.
366
+ n : int
367
+ The radial number of the mode.
368
+
369
+ Returns
370
+ -------
371
+ float
372
+ The frequency of the mode with azimuthal number m, polar number k, and radial number n.
373
+ """
374
+ return np.dot(np.array([n, k, m]), (self.frequencies))
375
+
376
+ def minotime(self, t):
377
+ """
378
+ Function that returns the Mino time for a given Boyer-Lindquist time.
379
+
380
+ Parameters
381
+ ----------
382
+ t : float
383
+ The Boyer-Lindquist time.
384
+
385
+ Returns
386
+ -------
387
+ float
388
+ The Mino time for the given Boyer-Lindquist time.
389
+ """
390
+ return self.base.mino_time(t)
391
+
392
+ def __call__(self, la):
393
+ """
394
+ Function that returns the position vector for a given Mino time value.
395
+ Parameters
396
+ ----------
397
+ la : float or numpy.ndarray
398
+ The Mino time value(s). If a numpy array is provided, the function will return a numpy array of the same shape.
399
+ Returns
400
+ -------
401
+ numpy.ndarray
402
+ The position vector for the given Mino time value(s).
403
+ """
404
+ if isinstance(la, np.ndarray) or isinstance(la, list):
405
+ return self.base.position_vec(np.array(la))
406
+ else:
407
+ return self.base.position(la)