pybhpt 0.9.4__cp310-cp310-musllinux_1_2_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/metric.py ADDED
@@ -0,0 +1,327 @@
1
+ from cybhpt_full import metric_coefficients_cython_S4dagger, metric_coefficients_cython_S0dagger
2
+ import numpy as np
3
+ from pybhpt.hertz import available_gauges
4
+ from pybhpt.swsh import Yslm, spin_operator_normalization
5
+
6
+ def gauge_check(gauge):
7
+ if gauge not in available_gauges:
8
+ TypeError("{} is not a supported gauge.".format(gauge))
9
+
10
+ S0_gauges = ["IRG", "ARG0", "SRG0"]
11
+ S4_gauges = ["ORG", "ARG4", "SRG4"]
12
+
13
+ def metric_coefficients_S4dagger_ab(ai, bi, nt, nr, nz, nph, a, r, z):
14
+ """Compute the metric coefficients for the reconstructed perturbation associated with the
15
+ S4dagger reconstruction operator.
16
+
17
+ Parameters
18
+ ----------
19
+ ai, bi : int
20
+ The indices of the tetrad-projected components of the metric perturbation.
21
+ nt, nr, nz, nph : int
22
+ The indices associated with the time, radial, spin, and azimuthal derivative operators.
23
+ a : float
24
+ The black hole spin parameter.
25
+ r : float
26
+ The radial coordinate.
27
+ z : float
28
+ The polar coordinate (cosine of the polar angle).
29
+
30
+ Returns
31
+ -------
32
+ float
33
+ The computed metric coefficient."""
34
+ return metric_coefficients_cython_S4dagger(ai, bi, nt, nr, nz, nph, a, r, z)
35
+
36
+ def metric_coefficients_S0dagger_ab(ai, bi, nt, nr, nz, nph, a, r, z):
37
+ """Compute the metric coefficients for the reconstructed perturbation associated with the
38
+ S0dagger reconstruction operator.
39
+
40
+ Parameters
41
+ ----------
42
+ ai, bi : int
43
+ The indices of the tetrad-projected components of the metric perturbation.
44
+ nt, nr, nz, nph : int
45
+ The indices associated with the time, radial, spin, and azimuthal derivative operators.
46
+ a : float
47
+ The black hole spin parameter.
48
+ r : float
49
+ The radial coordinate.
50
+ z : float
51
+ The polar coordinate (cosine of the polar angle).
52
+
53
+ Returns
54
+ -------
55
+ float
56
+ The computed metric coefficient."""
57
+ return metric_coefficients_cython_S0dagger(ai, bi, nt, nr, nz, nph, a, r, z)
58
+
59
+ def metric_coefficients_S0dagger(a, b, c, d, q, rvals, zvals):
60
+ """Compute the metric coefficients for the reconstructed perturbation associated with the
61
+ S0dagger reconstruction operator.
62
+
63
+ Parameters
64
+ ----------
65
+ a, b, c, d : int
66
+ The indices associated with the time, radial, spin, and azimuthal derivative operators.
67
+ q : float
68
+ The black hole spin parameter.
69
+ rvals : numpy.ndarray
70
+ The radial coordinate.
71
+ zvals : np.ndarray
72
+ The polar coordinate (cosine of the polar angle).
73
+
74
+ Returns
75
+ -------
76
+ numpy.ndarray
77
+ A 3D array containing the computed metric coefficients for the S0dagger operator."""
78
+ h22 = np.array([[metric_coefficients_S0dagger_ab(2, 2, a, b, c, d, q, r, z) for z in zvals] for r in rvals])
79
+ h24 = np.array([[metric_coefficients_S0dagger_ab(2, 4, a, b, c, d, q, r, z) for z in zvals] for r in rvals])
80
+ h44 = np.array([[metric_coefficients_S0dagger_ab(4, 4, a, b, c, d, q, r, z) for z in zvals] for r in rvals])
81
+ return np.array([2.*h22, h24, h44])
82
+
83
+ def metric_coefficients_S4dagger(a, b, c, d, q, rvals, zvals):
84
+ """Compute the metric coefficients for the reconstructed perturbation associated with the
85
+ S4dagger reconstruction operator.
86
+
87
+ Parameters
88
+ ----------
89
+ a, b, c, d : int
90
+ The indices associated with the time, radial, spin, and azimuthal derivative operators.
91
+ q : float
92
+ The black hole spin parameter.
93
+ rvals : numpy.ndarray
94
+ The radial coordinate.
95
+ zvals : np.ndarray
96
+ The polar coordinate (cosine of the polar angle).
97
+
98
+ Returns
99
+ -------
100
+ numpy.ndarray
101
+ A 3D array containing the computed metric coefficients for the S0dagger operator."""
102
+ h11 = np.array([[metric_coefficients_S4dagger_ab(1, 1, a, b, c, d, q, r, z) for z in zvals] for r in rvals])
103
+ h13 = np.array([[metric_coefficients_S4dagger_ab(1, 3, a, b, c, d, q, r, z) for z in zvals] for r in rvals])
104
+ h33 = np.array([[metric_coefficients_S4dagger_ab(3, 3, a, b, c, d, q, r, z) for z in zvals] for r in rvals])
105
+ return np.array([2.*h11, h13, h33])
106
+
107
+ def metric_coefficients(gauge, a, b, c, d, q, rvals, zvals):
108
+ """Compute the metric coefficients for the reconstructed perturbation associated with the
109
+ specified gauge.
110
+
111
+ Parameters
112
+ ----------
113
+ gauge : str
114
+ The gauge to use for the reconstruction. Must be one of the available gauges.
115
+ a, b, c, d : int
116
+ The indices associated with the time, radial, spin, and azimuthal derivative operators.
117
+ q : float
118
+ The black hole spin parameter.
119
+ rvals : numpy.ndarray
120
+ The radial coordinate.
121
+ zvals : np.ndarray
122
+ The polar coordinate (cosine of the polar angle).
123
+
124
+ Returns
125
+ -------
126
+ numpy.ndarray
127
+ A 3D array containing the computed metric coefficients for the specified gauge.
128
+ """
129
+ gauge_check(gauge)
130
+ if gauge in S0_gauges:
131
+ return metric_coefficients_S0dagger(a, b, c, d, q, rvals, zvals)
132
+ else:
133
+ return metric_coefficients_S4dagger(a, b, c, d, q, rvals, zvals)
134
+
135
+ class MetricCoefficients:
136
+ """
137
+ A class for computing the metric coefficients of the reconstructed perturbation
138
+ associated with the S0dagger or S4dagger reconstruction operator based on the specified gauge.
139
+
140
+ Parameters
141
+ ----------
142
+ gauge : str
143
+ The gauge to use for the reconstruction. Must be one of the available gauges.
144
+ q : float
145
+ The black hole spin parameter.
146
+ r : numpy.ndarray
147
+ The radial coordinate values.
148
+ th : numpy.ndarray
149
+ The polar coordinate values (cosine of the polar angle).
150
+
151
+ Attributes
152
+ ----------
153
+ gauge : str
154
+ The gauge used for the reconstruction.
155
+ blackholespin : float
156
+ The black hole spin parameter.
157
+ radialpoints : numpy.ndarray
158
+ The radial coordinate values.
159
+ polarpoints : numpy.ndarray
160
+ The polar coordinate values (cosine of the polar angle).
161
+ storedcomponents : dict
162
+ A dictionary mapping pairs of indices (a, b) to the index of the stored component
163
+ in the coefficients array.
164
+ conjugatecomponents : dict
165
+ A dictionary mapping pairs of indices (a, b) to the index of the conjugate component
166
+ in the coefficients array.
167
+ coeffs : numpy.ndarray
168
+ A 7D array containing the computed metric coefficients for the specified gauge.
169
+ zeros : numpy.ndarray
170
+ A 2D array of zeros with the same shape as the radial and polar coordinate arrays.
171
+
172
+ Methods
173
+ -------
174
+ hab(a, b, nt, nr, ns, nphi):
175
+ Returns the metric coefficient for the specified indices (a, b) and derivative orders
176
+ (nt, nr, ns, nphi). If the indices are not found in the stored or conjugate components,
177
+ it returns a zero array.
178
+ __call__(a, b, nt, nr, ns, nphi):
179
+ Calls the `hab` method to retrieve the metric coefficient for the specified indices
180
+ and derivative orders.
181
+ """
182
+ def __init__(self, gauge, q, r, th):
183
+ gauge_check(gauge)
184
+ self.gauge = gauge
185
+ rsamples = r.shape[0]
186
+ zsamples = th.shape[0]
187
+ self.blackholespin = q
188
+ self.radialpoints = r
189
+ self.polarpoints = th
190
+ if gauge in S0_gauges:
191
+ self.storedcomponents = {(2, 2): 0, (2, 4): 1, (4, 4): 2}
192
+ self.conjugatecomponents = {(2, 3): 1, (3, 3): 2}
193
+ else:
194
+ self.storedcomponents = {(1, 1): 0, (1, 3): 1, (3, 3): 2}
195
+ self.conjugatecomponents = {(1, 4): 1, (4, 4): 2}
196
+ z = np.cos(th)
197
+ z[np.abs(z) < 1.e-15] = 0.
198
+ self.coeffs = np.zeros((3, 3, 3, 3, 3, rsamples, zsamples), dtype=np.complex128)
199
+ self.zeros = np.zeros((rsamples, zsamples), dtype=np.complex128)
200
+ for ai in range(3):
201
+ for bi in range(3):
202
+ for ci in range(3):
203
+ for di in range(3):
204
+ self.coeffs[ai, bi, ci, di] = metric_coefficients(self.gauge, ai, bi, ci, di, q, r, z)
205
+
206
+ def hab(self, a, b, nt, nr, ns, nphi):
207
+ """
208
+ Returns the metric coefficient for the specified indices (a, b) and derivative orders
209
+ (nt, nr, ns, nphi). If the indices are not found in the stored or conjugate components,
210
+ it returns a zero array.
211
+
212
+ Parameters
213
+ ----------
214
+ a, b : int
215
+ The indices of the tetrad-projected components of the metric perturbation.
216
+ nt, nr, ns, nphi : int
217
+ The indices associated with the time, radial, spin, and azimuthal derivative operators.
218
+
219
+ Returns
220
+ -------
221
+ numpy.ndarray
222
+ The computed metric coefficient for the specified indices and derivative orders.
223
+ """
224
+ if b < a:
225
+ atemp = a
226
+ a = b
227
+ b = atemp
228
+ if (a, b) in self.storedcomponents.keys():
229
+ return self.coeffs[nt, nr, ns, nphi][self.storedcomponents[(a, b)]]
230
+ elif (a, b) in self.conjugatecomponents.keys():
231
+ return np.conj(self.coeffs[nt, nr, ns, nphi][self.conjugatecomponents[(a, b)]])
232
+ else:
233
+ return self.zeros
234
+
235
+ def __call__(self, a, b, nt, nr, ns, nphi):
236
+ """ Calls the `hab` method to retrieve the metric coefficient for the specified indices
237
+ and derivative orders.
238
+
239
+ Parameters
240
+ ----------
241
+ a, b : int
242
+ The indices of the tetrad-projected components of the metric perturbation.
243
+ nt, nr, ns, nphi : int
244
+ The indices associated with the time, radial, spin, and azimuthal derivative operators.
245
+
246
+ Returns
247
+ -------
248
+ numpy.ndarray
249
+ The computed metric coefficient for the specified indices and derivative orders.
250
+ """
251
+ return self.hab(a, b, nt, nr, ns, nphi)
252
+
253
+ def tetrad_project_l(a, r, z, mu):
254
+ if mu == 0:
255
+ return -1
256
+ elif mu == 1:
257
+ sigma = r**2 + a**2*z**2
258
+ delta = r**2 - 2.*r + a**2
259
+ return sigma/delta
260
+ elif mu == 2:
261
+ return 0.
262
+ elif mu == 3:
263
+ return a*(1. - z**2)
264
+ else:
265
+ return 0.
266
+
267
+ def tetrad_project_n(a, r, z, mu):
268
+ sigma = r**2 + a**2*z**2
269
+ delta = r**2 - 2.*r + a**2
270
+ if mu == 0:
271
+ return -0.5*delta/sigma
272
+ elif mu == 1:
273
+ return -0.5
274
+ elif mu == 2:
275
+ return 0.
276
+ elif mu == 3:
277
+ return 0.5*delta/sigma*a*(1. - z**2)
278
+ else:
279
+ return 0.
280
+
281
+ def tetrad_project_m(a, r, z, mu):
282
+ rhobar = -1./(r + 1j*a*z)
283
+ sigma = r**2 + a**2*z**2
284
+ pref = - rhobar*np.sqrt(0.5*(1. - z**2))
285
+ if mu == 0:
286
+ return -1j*pref*a
287
+ elif mu == 1:
288
+ return 0.
289
+ elif mu == 2:
290
+ return -pref*sigma/(1. - z**2)
291
+ elif mu == 3:
292
+ return 1j*pref*(r**2 + a**2)
293
+ else:
294
+ return 0.
295
+
296
+ def kinnersley_tetrad_covector(b, q, r, z, mu):
297
+ if b == 1:
298
+ return tetrad_project_l(q, r, z, mu)
299
+ elif b == 2:
300
+ return tetrad_project_n(q, r, z, mu)
301
+ elif b == 3:
302
+ return tetrad_project_m(q, r, z, mu)
303
+ elif b == 4:
304
+ return np.conj(tetrad_project_m(q, r, z, mu))
305
+ else:
306
+ return 0.
307
+
308
+ def hmunu_BL(gauge, mu, nu, q, r, hab):
309
+ gauge_check(gauge)
310
+ if gauge in S0_gauges:
311
+ e1mu = kinnersley_tetrad_covector(1, q, r, 0, mu)
312
+ e1nu = kinnersley_tetrad_covector(1, q, r, 0, nu)
313
+ e3mu = kinnersley_tetrad_covector(3, q, r, 0, mu)
314
+ e3nu = kinnersley_tetrad_covector(3, q, r, 0, nu)
315
+ h22 = e1mu*e1nu*hab[0]
316
+ h24 = -e1mu*e3nu*hab[1] - e1nu*e3mu*hab[1]
317
+ h44 = e3mu*e3nu*hab[2]
318
+ return (h22.real + 2.*h24.real + 2.*h44.real)
319
+ else:
320
+ e1mu = kinnersley_tetrad_covector(2, q, r, 0, mu)
321
+ e1nu = kinnersley_tetrad_covector(2, q, r, 0, nu)
322
+ e3mu = kinnersley_tetrad_covector(4, q, r, 0, mu)
323
+ e3nu = kinnersley_tetrad_covector(4, q, r, 0, nu)
324
+ h11 = e1mu*e1nu*hab[0]
325
+ h13 = -e1mu*e3nu*hab[1] - e1nu*e3mu*hab[1]
326
+ h33 = e3mu*e3nu*hab[2]
327
+ return (h11.real + 2.*h13.real + 2.*h33.real)
pybhpt/radial.py ADDED
@@ -0,0 +1,381 @@
1
+ from cybhpt_full import RadialTeukolsky as RadialTeukolskyCython
2
+ from cybhpt_full import available_methods as available_methods_cython
3
+ from cybhpt_full import renormalized_angular_momentum as nu_cython
4
+ from cybhpt_full import renormalized_angular_momentum_monodromy as nu_2_cython
5
+ from cybhpt_full import hypergeo_2F1 as hypergeo_2F1_cython
6
+ import numpy as np
7
+
8
+ def available_methods():
9
+ """
10
+ Returns a list of available solution methods.
11
+ """
12
+ return available_methods_cython()
13
+
14
+ def renormalized_angular_momentum(s, l, m, a, omega):
15
+ return nu_cython(s, l, m, a, omega)
16
+
17
+ def renormalized_angular_momentum_monodromy(s, l, m, a, omega, la):
18
+ return nu_2_cython(s, l, m, a, omega, la)
19
+
20
+ def hypergeo_2F1(a, b, c, x):
21
+ return hypergeo_2F1_cython(a, b, c, x)
22
+
23
+ class RadialTeukolsky:
24
+ """A class for solving the homogeneous radial Teukolsky equation.
25
+
26
+ Parameters
27
+ ----------
28
+ s : int
29
+ The spin weight of the field
30
+ j : int
31
+ The spheroidal harmonic mode number
32
+ m : int
33
+ The azimuthal harmonic mode number
34
+ a : float
35
+ The black hole spin parameter
36
+ omega : float
37
+ The frequency of the mode
38
+ r : numpy.ndarray
39
+ A numpy array of radial points at which to evaluate the solution
40
+
41
+ Attributes
42
+ ----------
43
+ radialpoints : numpy.ndarray
44
+ A numpy array of radial points at which the solution is evaluated.
45
+ base : RadialTeukolskyCython
46
+ The underlying Cython object that performs the computations.
47
+ nsamples : int
48
+ The number of radial points in the radialpoints array.
49
+
50
+ Properties
51
+ ----------
52
+ blackholespin : float
53
+ The black hole spin parameter.
54
+ spinweight : int
55
+ The spin weight of the field.
56
+ s : int
57
+ Alias for spinweight.
58
+ spheroidalmode : int
59
+ The spheroidal harmonic mode number.
60
+ j : int
61
+ Alias for spheroidalmode.
62
+ azimuthalmode : int
63
+ The azimuthal harmonic mode number.
64
+ m : int
65
+ Alias for azimuthalmode.
66
+ frequency : float
67
+ The frequency of the mode.
68
+ mode_frequency : float
69
+ Alias for frequency.
70
+ omega : float
71
+ Alias for frequency.
72
+ eigenvalue : float
73
+ The spheroidal eigenvalue of the radial Teukolsky equation.
74
+
75
+ Methods
76
+ -------
77
+ solveboundarycondition(method)
78
+ Solves the boundary condition for the radial Teukolsky equation.
79
+ setboundarycondition(bc, R, Rp, r)
80
+ Sets the boundary condition for the radial Teukolsky equation.
81
+ solve(method="AUTO", bc=None)
82
+ Solves the radial Teukolsky equation.
83
+ flipspinweight()
84
+ Flips the spin weight of the field.
85
+ radialpoint(pos)
86
+ Returns the radial point at the given position.
87
+ boundarypoint(bc)
88
+ Returns the boundary point for the given boundary condition.
89
+ boundarysolution(bc)
90
+ Returns the solution at the boundary for the given boundary condition.
91
+ boundaryderivative(bc)
92
+ Returns the derivative at the boundary for the given boundary condition.
93
+ radialsolution(bc, pos)
94
+ Returns the solution at the radial point for the given boundary condition and position.
95
+ radialderivative(bc, pos)
96
+ Returns the derivative at the radial point for the given boundary condition and position.
97
+ radialderivative2(bc, pos)
98
+ Returns the second derivative at the radial point for the given boundary condition and position.
99
+ radialsolutions(bc)
100
+ Returns the solutions at all radial points for the given boundary condition.
101
+ radialderivatives(bc)
102
+ Returns the derivatives at all radial points for the given boundary condition.
103
+ radialderivatives2(bc)
104
+ Returns the second derivatives at all radial points for the given boundary condition.
105
+ __call__(bc, deriv=0)
106
+ Returns the solutions, first derivatives, or second derivatives at all radial points for the given boundary condition.
107
+ The `deriv` parameter specifies which derivative to return: 0 for solutions,
108
+ 1 for first derivatives, and 2 for second derivatives. If `deriv` is not 0, 1, or 2, a ValueError is raised.
109
+ """
110
+ def __init__(self, s, j, m, a, omega, r):
111
+ if a < 0 or a > 1:
112
+ raise ValueError(f"Black hole spin parameter {a} must be in the range [0, 1].")
113
+ if j < np.abs(m):
114
+ raise ValueError(f"Spheroidal harmonic mode number {j} must be greater than or equal to the absolute value of azimuthal harmonic mode number {m}.")
115
+ if np.any(r <= 1 + np.sqrt(1 - a**2)):
116
+ raise ValueError(f"Radial point {r} must be greater than horizon radius r_+ = {1 + np.sqrt(1 - a**2)}.")
117
+ if isinstance(r, list) or (isinstance(r, np.ndarray) and r.ndim > 0):
118
+ self.radialpoints = np.asarray(r)
119
+ self.nsamples = self.radialpoints.shape[0]
120
+ else:
121
+ raise AttributeError("Radial points must be a list or a numpy array.")
122
+
123
+ if self.nsamples == 0:
124
+ raise ValueError("Radial points array is empty.")
125
+ self.base = RadialTeukolskyCython(a, s, j, m, omega, self.radialpoints)
126
+
127
+
128
+ @property
129
+ def blackholespin(self):
130
+ return self.base.blackholespin
131
+
132
+ @property
133
+ def spinweight(self):
134
+ return self.base.spinweight
135
+
136
+ @property
137
+ def s(self):
138
+ return self.spinweight
139
+
140
+ @property
141
+ def spheroidalmode(self):
142
+ return self.base.spheroidalmode
143
+
144
+ @property
145
+ def j(self):
146
+ return self.spheroidalmode
147
+
148
+ @property
149
+ def azimuthalmode(self):
150
+ return self.base.azimuthalmode
151
+
152
+ @property
153
+ def m(self):
154
+ return self.azimuthalmode
155
+
156
+ @property
157
+ def frequency(self):
158
+ return self.base.frequency
159
+
160
+ @property
161
+ def mode_frequency(self):
162
+ return self.frequency
163
+
164
+ @property
165
+ def omega(self):
166
+ return self.frequency
167
+
168
+ @property
169
+ def eigenvalue(self):
170
+ return self.base.eigenvalue
171
+
172
+ def solveboundarycondition(self, method):
173
+ """Solves the boundary condition for the radial Teukolsky equation.
174
+
175
+ Parameters
176
+ ----------
177
+ method : str
178
+ The method to use for solving the boundary condition. Default is "AUTO".
179
+ """
180
+ self.base.solve_bc(method)
181
+
182
+ def setboundarycondition(self, bc, R, Rp, r):
183
+ """Sets the boundary condition for the radial Teukolsky equation.
184
+
185
+ Parameters
186
+ ----------
187
+ bc : str
188
+ The boundary condition to set. Can be "In" for horizon or "Up" for infinity.
189
+ R : float
190
+ The boundary condition function value at the radial point.
191
+ Rp : float
192
+ The derivative of the boundary condition function at the radial point.
193
+ r : float
194
+ The radial point at which the boundary condition is defined.
195
+ """
196
+ self.base.set_bc(bc, R, Rp, r)
197
+
198
+ def solve(self, method = "AUTO", bc = None):
199
+ """Solves the radial Teukolsky equation.
200
+
201
+ Parameters
202
+ ----------
203
+ method : str, optional
204
+ The method to use for solving the equation. Default is "AUTO".
205
+ bc : str, optional
206
+ Specifies which homogeneous solutions to compute. If None, both "In" (horizon) and "Up" (infinity) solutions are computed.
207
+ If "In", only the horizon solution is computed. If "Up", only the infinity solution is computed.
208
+ """
209
+ if bc is None:
210
+ self.base.solve(method, "None")
211
+ else:
212
+ self.base.solve(method, bc)
213
+
214
+ def flipspinweight(self):
215
+ """Flips the sign of the spin weight of the field."""
216
+ self.base.flip_spinweight()
217
+
218
+ def radialpoint(self, pos):
219
+ """Returns the radial point at the given position.
220
+ Parameters
221
+ ----------
222
+ pos : float
223
+ The position at which to evaluate the radial point.
224
+ Returns
225
+ -------
226
+ float
227
+ The radial point at the given position.
228
+ """
229
+ return self.base.radialpoint(pos)
230
+
231
+ def boundarypoint(self, bc):
232
+ """
233
+ Returns the boundary point for the given boundary condition.
234
+ Parameters
235
+ ----------
236
+ bc : str
237
+ The boundary condition to evaluate. Can be "In" for horizon or "Up" for infinity.
238
+ Returns
239
+ -------
240
+ float
241
+ The boundary point corresponding to the specified boundary condition.
242
+ """
243
+ return self.base.boundarypoint(bc)
244
+
245
+ def boundarysolution(self, bc):
246
+ """Returns the solution at the boundary for the given boundary condition.
247
+ Parameters
248
+ ----------
249
+ bc : str
250
+ The boundary condition to evaluate. Can be "In" for horizon or "Up" for infinity.
251
+ Returns
252
+ -------
253
+ float
254
+ The solution at the boundary corresponding to the specified boundary condition.
255
+ """
256
+ return self.base.boundarysolution(bc)
257
+
258
+ def boundaryderivative(self, bc):
259
+ """Returns the derivative at the boundary for the given boundary condition.
260
+ Parameters
261
+ ----------
262
+ bc : str
263
+ The boundary condition to evaluate. Can be "In" for horizon or "Up" for infinity.
264
+ Returns
265
+ -------
266
+ float
267
+ The derivative at the boundary corresponding to the specified boundary condition.
268
+ """
269
+ return self.base.boundaryderivative(bc)
270
+
271
+ def radialsolution(self, bc, pos):
272
+ """Returns the solution at the radial point for the given homogeneous solution and position.
273
+ Parameters
274
+ ----------
275
+ bc : str
276
+ The homogeneous solution to evaluate. Can be "In" for horizon solution or "Up" for infinity solution.
277
+ pos : float
278
+ The position at which to evaluate the solution.
279
+ Returns
280
+ -------
281
+ float
282
+ The solution at the radial point corresponding to the specified boundary condition and position.
283
+ """
284
+ return self.base.solution(bc, pos)
285
+
286
+ def radialderivative(self, bc, pos):
287
+ """Returns the derivative at the radial point for the given homogeneous solution and position.
288
+ Parameters
289
+ ----------
290
+ bc : str
291
+ The homogeneous solution to evaluate. Can be "In" for horizon solution or "Up" for infinity solution.
292
+ pos : float
293
+ The position at which to evaluate the solution.
294
+ Returns
295
+ -------
296
+ float
297
+ The solution at the radial point corresponding to the specified boundary condition and position.
298
+ """
299
+ return self.base.derivative(bc, pos)
300
+
301
+ def radialderivative2(self, bc, pos):
302
+ """Returns the second derivative at the radial point for the given homogeneous solution and position.
303
+ Parameters
304
+ ----------
305
+ bc : str
306
+ The homogeneous solution to evaluate. Can be "In" for horizon solution or "Up" for infinity solution.
307
+ pos : float
308
+ The position at which to evaluate the solution.
309
+ Returns
310
+ -------
311
+ float
312
+ The solution at the radial point corresponding to the specified boundary condition and position.
313
+ """
314
+ return self.base.derivative2(bc, pos)
315
+
316
+ def radialsolutions(self, bc):
317
+ """Returns a homogeneous solution at all radial points.
318
+ Parameters
319
+ ----------
320
+ bc : str
321
+ The homogeneous solution to evaluate. Can be "In" for horizon solution or "Up" for infinity solution.
322
+ Returns
323
+ -------
324
+ numpy.ndarray
325
+ A numpy array of solutions at all radial points corresponding to the specified boundary condition.
326
+ """
327
+ return np.array([self.base.solution(bc, i) for i in range(self.nsamples)])
328
+
329
+ def radialderivatives(self, bc):
330
+ """Returns the radial derivative at all radial points.
331
+ Parameters
332
+ ----------
333
+ bc : str
334
+ The homogeneous solution to evaluate. Can be "In" for horizon solution or "Up" for infinity solution.
335
+ Returns
336
+ -------
337
+ numpy.ndarray
338
+ A numpy array of solutions at all radial points corresponding to the specified boundary condition.
339
+ """
340
+ return np.array([self.base.derivative(bc, i) for i in range(self.nsamples)])
341
+
342
+ def radialderivatives2(self, bc):
343
+ """Returns the second radial derivative at all radial points.
344
+ Parameters
345
+ ----------
346
+ bc : str
347
+ The homogeneous solution to evaluate. Can be "In" for horizon solution or "Up" for infinity solution.
348
+ Returns
349
+ -------
350
+ numpy.ndarray
351
+ A numpy array of solutions at all radial points corresponding to the specified boundary condition.
352
+ """
353
+ return np.array([self.base.derivative2(bc, i) for i in range(self.nsamples)])
354
+
355
+ def __call__(self, bc, deriv = 0):
356
+ """Returns the solutions, first derivatives, or second derivatives at all radial points for the given boundary condition.
357
+
358
+ Parameters
359
+ ----------
360
+ bc : str
361
+ The homogeneous solution to evaluate. Can be "In" for horizon solution or "Up" for infinity solution.
362
+ deriv : int, optional
363
+ Specifies which derivative to return: 0 for solutions, 1 for first derivatives, and 2 for second derivatives.
364
+ Default is 0 (solutions).
365
+ Returns
366
+ -------
367
+ numpy.ndarray
368
+ A numpy array of solutions, first derivatives, or second derivatives at all radial points corresponding to the specified boundary condition.
369
+ Raises
370
+ ------
371
+ ValueError
372
+ If `deriv` is not 0, 1, or 2.
373
+ """
374
+ if deriv == 0:
375
+ return self.radialsolutions(bc)
376
+ elif deriv == 1:
377
+ return self.radialderivatives(bc)
378
+ elif deriv == 2:
379
+ return self.radialderivatives2(bc)
380
+ else:
381
+ raise ValueError("RadialTeukolsky only solves up to the second derivative")