pybhpt 0.9.10__cp312-cp312-macosx_15_0_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.
pybhpt/hertz.py ADDED
@@ -0,0 +1,402 @@
1
+ from cybhpt_full import _HertzMode as _HertzModeCython
2
+ from cybhpt_full import _test_hertz_mode_cython
3
+ from cybhpt_full import _teuk_to_hertz_ORG, _teuk_to_hertz_IRG, _teuk_to_hertz_SRG, _teuk_to_hertz_ARG
4
+ from pybhpt.radial import RadialTeukolsky
5
+ import numpy as np
6
+
7
+ available_gauges = [
8
+ "IRG",
9
+ "ORG",
10
+ "SRG0",
11
+ "SRG4",
12
+ "ARG0",
13
+ "ARG4",
14
+ ]
15
+
16
+ def hertz_IRG(Zin, Zup, j, m, k, a, omega, lambdaCH):
17
+ """
18
+ Convert Teukolsky amplitudes to Hertz potential in the IRG gauge.
19
+ """
20
+ return _teuk_to_hertz_IRG(Zin, Zup, j, m, k, a, omega, lambdaCH)
21
+
22
+ def hertz_ORG(Zin, Zup, j, m, k, a, omega, lambdaCH):
23
+ """Convert Teukolsky amplitudes to Hertz potential in the ORG gauge.
24
+ """
25
+ return _teuk_to_hertz_ORG(Zin, Zup, j, m, k, a, omega, lambdaCH)
26
+
27
+ def hertz_SRG(Zin, Zup, j, m, k, a, omega, lambdaCH):
28
+ """Convert Teukolsky amplitudes to Hertz potential in the SRG gauge.
29
+ """
30
+ return _teuk_to_hertz_SRG(Zin, Zup, j, m, k, a, omega, lambdaCH)
31
+
32
+ def hertz_ARG(Zin, Zup, j, m, k, a, omega, lambdaCH):
33
+ """Convert Teukolsky amplitudes to Hertz potential in the ARG gauge.
34
+ """
35
+ return _teuk_to_hertz_ARG(Zin, Zup, j, m, k, a, omega, lambdaCH)
36
+
37
+ def teuk_to_hertz_amplitude(gauge, Zin, Zup, j, m, k, a, omega, lambdaCH):
38
+ if gauge == "IRG":
39
+ return hertz_IRG(Zin, Zup, j, m, k, a, omega, lambdaCH)
40
+ elif gauge == "ORG":
41
+ return hertz_ORG(Zin, Zup, j, m, k, a, omega, lambdaCH)
42
+ elif gauge == "SRG0" or gauge == "SRG4":
43
+ return hertz_SRG(Zin, Zup, j, m, k, a, omega, lambdaCH)
44
+ elif gauge == "ARG0" or gauge == "ARG4":
45
+ return hertz_ARG(Zin, Zup, j, m, k, a, omega, lambdaCH)
46
+ else:
47
+ return (0.j, 0.j)
48
+
49
+ def test_hertz_mode(j, m, k, n, geo):
50
+ return _test_hertz_mode_cython(j, m, k, n, geo.base)
51
+
52
+ def gauge_check(gauge):
53
+ """ Check if the provided gauge is supported.
54
+ Raises a TypeError if the gauge is not supported.
55
+ """
56
+ if gauge not in available_gauges:
57
+ TypeError("{} is not a supported gauge.".format(gauge))
58
+
59
+
60
+ class HertzMode:
61
+ """
62
+ Class that produces a Hertz potential mode given a Teukolsky object and a gauge.
63
+ This class is a wrapper around the Cython implementation of the Hertz potential
64
+ and provides a Python interface to the underlying C++ code.
65
+
66
+ Parameters
67
+ ----------
68
+ teuk : Teukolsky
69
+ The Teukolsky object to be used for the Hertz potential.
70
+ gauge : str
71
+ The gauge to be used for the Hertz potential. Must be one of the following:
72
+ - "IRG"
73
+ - "ORG"
74
+ - "SRG0"
75
+ - "SRG4"
76
+ - "ARG0"
77
+ - "ARG4"
78
+
79
+ Attributes
80
+ ----------
81
+ base : HertzModeCython
82
+ The underlying Cython implementation of the Hertz potential mode.
83
+ gauge : str
84
+ The gauge used for the Hertz potential.
85
+ sampleR : int
86
+ The number of radial samples used in the Hertz potential mode solutions
87
+ sampleTh : int
88
+ The number of polar samples used in the Hertz potential mode solutions
89
+ spinweight : int
90
+ The spin weight of the Hertz potential mode.
91
+ spheroidalmode : int
92
+ The spheroidal mode number of the Hertz potential mode.
93
+ azimuthalmode : int
94
+ The azimuthal mode number of the Hertz potential mode.
95
+ radialmode : int
96
+ The radial mode number of the Hertz potential mode.
97
+ polarmode : int
98
+ The polar mode number of the Hertz potential mode.
99
+ blackholespin : float
100
+ The spin of the black hole associated with the background spacetime.
101
+ frequency : float
102
+ The frequency of the Hertz potential mode.
103
+ horizonfrequency : float
104
+ The frequency of the Hertz potential mode at the horizon.
105
+ eigenvalue : complex
106
+ The spheroidal eigenvalue associated with the Hertz potential mode.
107
+ mincouplingmode : int
108
+ The minimum l-mode used for coupling the spherical and spheroidal harmonics
109
+ maxcouplingmode : int
110
+ The maximum l-mode used for coupling the spherical and spheroidal harmonics
111
+ minscalarcouplingmode : int
112
+ The minimum l-mode used for coupling the scalar harmonics
113
+ maxscalarcouplingmode : int
114
+ The maximum l-mode used for coupling the scalar harmonics
115
+ j : int
116
+ Alias for spheroidalmode.
117
+ m : int
118
+ Alias for azimuthalmode.
119
+ k : int
120
+ Alias for polarmode.
121
+ n : int
122
+ Alias for radialmode.
123
+ omega : float
124
+ Alias for frequency.
125
+ a : float
126
+ Alias for blackholespin.
127
+
128
+ Properties
129
+ ----------
130
+ couplingcoefficients : np.ndarray
131
+ The coupling coefficients for the Hertz potential mode.
132
+ scalarcouplingcoefficients : np.ndarray
133
+ The scalar coupling coefficients for the Hertz potential mode.
134
+ polarpoints : np.ndarray
135
+ The polar points used in the Hertz potential mode solutions.
136
+ polarsolutions : np.ndarray
137
+ The polar mode solutions of the Hertz potential.
138
+ polarderivatives : np.ndarray
139
+ Derivatives of the polar mode solutions of the Hertz potential.
140
+ polarderivatives2 : np.ndarray
141
+ Second derivatives of the polar mode solutions of the Hertz potential.
142
+ radialpoints : np.ndarray
143
+ The radial points used in the Hertz potential mode solutions.
144
+ radialsolutions : np.ndarray
145
+ The radial mode solutions of the Hertz potential.
146
+ radialderivatives : np.ndarray
147
+ Derivatives of the radial mode solutions of the Hertz potential.
148
+ radialderivatives2 : np.ndarray
149
+ Second derivatives of the radial mode solutions of the Hertz potential.
150
+
151
+ Methods
152
+ -------
153
+ solve()
154
+ Solve the Hertz potential mode equations.
155
+ couplingcoefficient(l)
156
+ Returns the coupling coefficient for the given l-mode.
157
+ scalarcouplingcoefficient(l)
158
+ Returns the scalar coupling coefficient for the given l-mode.
159
+ radialpoint(pos)
160
+ Returns the radial point corresponding to the given position.
161
+ radialsolution(bc, pos)
162
+ Returns the radial solution for the given boundary condition and position.
163
+ radialderivative(bc, pos)
164
+ Returns the radial derivative for the given boundary condition and position.
165
+ radialderivative2(bc, pos)
166
+ Returns the second radial derivative for the given boundary condition and position.
167
+ homogeneousradialsolution(bc, pos)
168
+ Returns the homogeneous radial solution for the given boundary condition and position.
169
+ homogeneousradialderivative(bc, pos)
170
+ Returns the homogeneous radial derivative for the given boundary condition and position.
171
+ homogeneousradialderivative2(bc, pos)
172
+ Returns the second homogeneous radial derivative for the given boundary condition and position.
173
+ polarpoint(pos)
174
+ Returns the polar point corresponding to the given position.
175
+ polarsolution(pos)
176
+ Returns the polar solution for the given position.
177
+ polarderivative(pos)
178
+ Returns the polar derivative for the given position.
179
+ polarderivative2(pos)
180
+ Returns the second polar derivative for the given position.
181
+ amplitude(bc)
182
+ Returns the Hertz amplitude for the given boundary condition.
183
+ __call__(r, deriv=0)
184
+ Returns the radial Hertz potential mode evaluated at the given radial values `r`.
185
+ Alternatively, it can return the radial derivative if `deriv` is set to 1 or 2.
186
+ The radial values `r` must lie outside the source region defined by the radial points.
187
+ If r contains values inside the source region, a ValueError is raised.
188
+ """
189
+ def __init__(self, teuk, gauge):
190
+ self.base = _HertzModeCython(teuk.base, gauge)
191
+ self.gauge = gauge
192
+ self.sampleR = self.base.radialsamplenumber
193
+ self.sampleTh = self.base.polarsamplenumber
194
+
195
+ @property
196
+ def spinweight(self):
197
+ return self.base.spinweight
198
+
199
+ @property
200
+ def spheroidalmode(self):
201
+ return self.base.spheroidalmode
202
+
203
+ @property
204
+ def azimuthalmode(self):
205
+ return self.base.azimuthalmode
206
+
207
+ @property
208
+ def radialmode(self):
209
+ return self.base.radialmode
210
+
211
+ @property
212
+ def polarmode(self):
213
+ return self.base.spipolarmodenweight
214
+
215
+ @property
216
+ def blackholespin(self):
217
+ return self.base.blackholespin
218
+
219
+ @property
220
+ def frequency(self):
221
+ return self.base.frequency
222
+
223
+ @property
224
+ def horizonfrequency(self):
225
+ return self.base.horizonfrequency
226
+
227
+ @property
228
+ def eigenvalue(self):
229
+ return self.base.eigenvalue
230
+
231
+ @property
232
+ def mincouplingmode(self):
233
+ return self.base.mincouplingmode
234
+
235
+ @property
236
+ def maxcouplingmode(self):
237
+ return self.base.maxcouplingmode
238
+
239
+ @property
240
+ def minscalarcouplingmode(self):
241
+ return self.base.minscalarcouplingmode
242
+
243
+ @property
244
+ def maxscalarcouplingmode(self):
245
+ return self.base.maxscalarcouplingmode
246
+
247
+ # some useful aliases
248
+ @property
249
+ def j(self):
250
+ return self.spheroidalmode
251
+ @property
252
+ def m(self):
253
+ return self.azimuthalmode
254
+ @property
255
+ def k(self):
256
+ return self.polarmode
257
+ @property
258
+ def n(self):
259
+ return self.radialmode
260
+ @property
261
+ def omega(self):
262
+ return self.frequency
263
+ @property
264
+ def a(self):
265
+ return self.blackholespin
266
+
267
+ @property
268
+ def couplingcoefficients(self):
269
+ return self.base.couplingcoefficients
270
+
271
+ @property
272
+ def scalarcouplingcoefficients(self):
273
+ return self.base.scalarcouplingcoefficients
274
+
275
+ @property
276
+ def polarpoints(self):
277
+ return self.base.polarpoints
278
+
279
+ @property
280
+ def polarsolutions(self):
281
+ return self.base.polarsolutions
282
+
283
+ @property
284
+ def polarderivatives(self):
285
+ return self.base.polarderivatives
286
+
287
+ @property
288
+ def polarderivatives2(self):
289
+ return self.base.polarderivatives2
290
+
291
+ @property
292
+ def radialpoints(self):
293
+ return self.base.radialpoints
294
+
295
+ @property
296
+ def radialsolutions(self):
297
+ return self.base.radialsolutions
298
+
299
+ @property
300
+ def radialderivatives(self):
301
+ return self.base.radialderivatives
302
+
303
+ @property
304
+ def radialderivatives2(self):
305
+ return self.base.radialderivatives2
306
+
307
+ @property
308
+ def amplitudes(self):
309
+ return {"In": self.amplitude('In'), "Up": self.amplitude('Up')}
310
+
311
+ def solve(self):
312
+ self.base.solve()
313
+
314
+ def couplingcoefficient(self, l):
315
+ return self.base.couplingcoefficient(l)
316
+
317
+ def scalarcouplingcoefficient(self, l):
318
+ return self.base.scalarcouplingcoefficient(l)
319
+
320
+ def radialpoint(self, pos):
321
+ return self.base.radialpoint(pos)
322
+
323
+ def radialsolution(self, bc, pos):
324
+ return self.base.radialsolution(bc, pos)
325
+
326
+ def radialderivative(self, bc, pos):
327
+ return self.base.radialderivative(bc, pos)
328
+
329
+ def radialderivative2(self, bc, pos):
330
+ return self.base.radialderivative2(bc, pos)
331
+
332
+ def homogeneousradialsolution(self, bc, pos):
333
+ return self.base.homogeneousradialsolution(bc, pos)
334
+
335
+ def homogeneousradialderivative(self, bc, pos):
336
+ return self.base.homogeneousradialderivative(bc, pos)
337
+
338
+ def homogeneousradialderivative2(self, bc, pos):
339
+ return self.base.homogeneousradialderivative2(bc, pos)
340
+
341
+ def polarpoint(self, pos):
342
+ return self.base.polarpoint(pos)
343
+
344
+ def polarsolution(self, pos):
345
+ return self.base.polarsolution(pos)
346
+
347
+ def polarderivative(self, pos):
348
+ return self.base.polarderivative(pos)
349
+
350
+ def polarderivative2(self, pos):
351
+ return self.base.polarderivative2(pos)
352
+
353
+ def amplitude(self, bc):
354
+ return self.base.hertz_amplitude(bc)
355
+
356
+ def __call__(self, r, deriv = 0):
357
+ """
358
+ Evaluate the radial Hertz potential mode at the given radial values `r`.
359
+ If `deriv` is set to 0, it returns the Hertz potential mode.
360
+ If `deriv` is set to 1, it returns the first radial derivative.
361
+ If `deriv` is set to 2, it returns the second radial derivative.
362
+
363
+ Parameters
364
+ ----------
365
+ r : array-like
366
+ The radial values at which to evaluate the Hertz potential mode.
367
+ deriv : int, optional
368
+ The order of the radial derivative to compute. Default is 0 (no derivative).
369
+ Returns
370
+ -------
371
+ numpy.ndarray
372
+ The evaluated Hertz potential mode or its radial derivative at the given radial values `r`.
373
+ Raises
374
+ ------
375
+ ValueError
376
+ If any of the radial values `r` lie within the source region defined by the radialpoints.
377
+ """
378
+ rmin = self.radialpoints[0]
379
+ rmax = self.radialpoints[-1]
380
+ rinner = r[r < rmin]
381
+ router = r[r > rmax]
382
+ if np.any((r >= rmin) & (r <= rmax)):
383
+ raise ValueError("Radial points must lie outside the source region")
384
+
385
+ if rinner.shape[0] > 0:
386
+ Rt = RadialTeukolsky(self.spinweight, self.spheroidalmode, self.azimuthalmode, self.blackholespin, self.frequency, rinner)
387
+ Rt.solve(bc='In')
388
+ Rin = Rt('In', deriv=deriv)
389
+ else:
390
+ Rin = np.array([])
391
+
392
+ if router.shape[0] > 0:
393
+ Rt = RadialTeukolsky(self.spinweight, self.spheroidalmode, self.azimuthalmode, self.blackholespin, self.frequency, router)
394
+ Rt.solve(bc='Up')
395
+ Rup = Rt('Up', deriv=deriv)
396
+ else:
397
+ Rup = np.array([])
398
+
399
+ PsiIn = self.amplitude('In')
400
+ PsiUp = self.amplitude('Up')
401
+
402
+ return np.concatenate((PsiIn*Rin, PsiUp*Rup))