pybhpt 0.9.4__cp314-cp314t-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.
pybhpt/redshift.py ADDED
@@ -0,0 +1,20 @@
1
+ from cybhpt_full import RedshiftCoefficients as RedshiftCoefficientsCython
2
+ from cybhpt_full import SphericalHarmonicCoupling as SphericalHarmonicCouplingCython
3
+
4
+ class RedshiftCoefficients:
5
+ def __init__(self, gauge, geo):
6
+ self.base = RedshiftCoefficientsCython(gauge, geo.base)
7
+
8
+ def __call__(self, Ni, ai, bi, ci, di, jr = 0, jz = 0):
9
+ return self.base(Ni, ai, bi, ci, di, jr, jz)
10
+
11
+ class SphericalHarmonicCoupling:
12
+ def __init__(self, lmax, m):
13
+ self.base = SphericalHarmonicCouplingCython(lmax, m)
14
+ self.azimuthalmode = self.base.azimuthalmode
15
+
16
+ def zcouplingcoefficient(self, n, i, l):
17
+ return self.base.zcouplingcoefficient(n, i, l)
18
+
19
+ def dzcouplingcoefficient(self, n, i, l):
20
+ return self.base.dzcouplingcoefficient(n, i, l)
pybhpt/swsh.py ADDED
@@ -0,0 +1,347 @@
1
+ import scipy.sparse
2
+ import scipy.sparse.linalg
3
+ from scipy.special import sph_harm
4
+ from scipy.special import binom
5
+ from scipy.special import factorial
6
+ import numpy as np
7
+
8
+ """
9
+ Wigner 3j-symbol and Clebsch-Gordon coefficients
10
+ """
11
+
12
+ def fac(n):
13
+ if n < 0:
14
+ return 0
15
+ return float(np.math.factorial(n))
16
+
17
+ def Yslm(s, l, m, th):
18
+ if np.abs(s) > l:
19
+ return 0.*th
20
+ if s == 0:
21
+ return np.real(sph_harm(m, l, 0., th))
22
+ elif s + m < 0:
23
+ return (-1.)**(s+m)*YslmBase(-s, l, -m, np.cos(th))
24
+ # elif th > np.pi/2.:
25
+ # return (-1.)**(l + m)*YslmBase(-s, l, m, -np.cos(th))
26
+ else:
27
+ return YslmBase(s, l, m, np.cos(th))
28
+
29
+ def YslmBase(s, l, m, z):
30
+ rmax = l - s
31
+ pref = (0.5)**(l)*(-1.)**m*np.sqrt(factorial(l+m)/factorial(l+s)*factorial(l-m)/factorial(l-s)*(2*l+1)/(4.*np.pi))*np.sqrt(1. - z)**(s + m)*np.sqrt(1. + z)**(s - m)
32
+
33
+ yslm = 0.*pref
34
+ for r in range(0, rmax + 1):
35
+ yslm += binom(l - s, r)*binom(l + s, r + s - m)*(z - 1.)**(rmax - r)*(z + 1.)**(r)
36
+
37
+ return pref*yslm
38
+
39
+ def clebsch(l1, l2, l3, m1, m2, m3):
40
+ return (-1)**(l1 - l2 + m3)*np.sqrt(2*l3 + 1)*w3j(l1, l2, l3, m1, m2, -m3);
41
+
42
+ def w3j(l1, l2, l3, m1, m2, m3):
43
+ if m1 + m2 + m3 != 0:
44
+ return 0
45
+ elif abs(l1 - l2) > l3:
46
+ return 0
47
+ elif l1 + l2 < l3:
48
+ return 0
49
+
50
+ if abs(m1) > l1:
51
+ return 0
52
+ elif abs(m2) > l2:
53
+ return 0
54
+ elif abs(m3) > l3:
55
+ return 0
56
+
57
+ sumTerm = w3j_tsum(l1, l2, l3, m1, m2, m3)
58
+ if sumTerm == 0:
59
+ return 0
60
+ sumSign = np.sign(sumTerm)
61
+ tempLog = 0.5*(np.log(fac(l1 + m1)) + np.log(fac(l2 + m2)) + np.log(fac(l3 + m3)))
62
+ tempLog += 0.5*(np.log(fac(l1 - m1)) + np.log(fac(l2 - m2)) + np.log(fac(l3 - m3)))
63
+ tempLog += np.log(triangle_coeff(l1, l2, l3))
64
+ tempLog += np.log(abs(sumTerm))
65
+
66
+ temp = sumSign*np.exp(tempLog)
67
+ temp *= (-1)**(l1-l2-m3)
68
+
69
+ return temp
70
+
71
+ def w3j_tsum(l1, l2, l3, m1, m2, m3):
72
+ t_min_num = w3j_t_min(l1, l2, l3, m1, m2, m3)
73
+ t_max_num = w3j_t_max(l1, l2, l3, m1, m2, m3)
74
+ x = 0
75
+ if t_max_num < t_min_num:
76
+ t_max_num = t_min_num
77
+
78
+ for t in range(t_min_num - 1, t_max_num + 2):
79
+ term = (fac(t)*fac(l3 - l2 + m1 + t)*fac(l3 - l1 - m2 + t)
80
+ *fac(l1 + l2 - l3 - t)*fac(l1 - t - m1)*fac(l2 - t + m2))
81
+ if term > 0:
82
+ x += (-1)**t/term
83
+
84
+ return x
85
+
86
+ def w3j_t_min(l1, l2, l3, m1, m2, m3):
87
+ temp = 0
88
+
89
+ comp = l3 - l2 + m1
90
+ if temp + comp < 0:
91
+ temp = -comp
92
+ comp = l3 - l1 - m2
93
+ if temp + comp < 0:
94
+ temp = -comp
95
+
96
+ return temp
97
+
98
+ def w3j_t_max(l1, l2, l3, m1, m2, m3):
99
+ temp = 1
100
+ comp = l1 + l2 - l3
101
+ if comp - temp > 0:
102
+ temp = comp
103
+ comp = l1 - m1
104
+ if comp - temp > 0:
105
+ temp = comp
106
+ comp = l2 + m2
107
+ if comp - temp > 0:
108
+ temp = comp
109
+
110
+ return temp;
111
+
112
+ def triangle_coeff(l1, l2, l3):
113
+ return np.sqrt(fac(l1 + l2 - l3)*fac(l3 + l1 - l2)*fac(l2 + l3 - l1)/fac(l1 + l2 + l3 + 1))
114
+
115
+ """
116
+ SWSH Eigenvalue Functions
117
+ """
118
+
119
+ def k1(s, l, j, m):
120
+ return np.sqrt((2*l + 1)/(2*j + 1))*clebsch(l, 1, j, m, 0, m)*clebsch(l, 1, j, -s, 0, -s);
121
+
122
+ def k2(s, l, j, m):
123
+ ktemp = 2./3.*np.sqrt((2*l + 1)/(2*j + 1))*clebsch(l, 2, j, m, 0, m)*clebsch(l, 2, j, -s, 0, -s);
124
+ if j == l:
125
+ ktemp += 1/3.
126
+ return ktemp
127
+
128
+ def k2m2(s, l, m):
129
+ temp = (l - m - 1.)/(l - 1.)
130
+ temp *= (l + m - 1.)/(l - 1.)
131
+ temp *= np.float64(l - m)/l
132
+ temp *= np.float64(l + m)/l
133
+ temp *= (l - s)/(2.*l - 1.)
134
+ temp *= (l + s)/(2.*l - 1.)
135
+ temp *= (l - s - 1.)/(2.*l + 1.)
136
+ temp *= (l + s - 1.)/(2.*l - 3.)
137
+ return np.sqrt(temp)
138
+
139
+ def k2m1(s, l, m):
140
+ temp = np.float64(l - m)*np.float64(l + m)/(2.*l - 1.)
141
+ temp *= np.float64(l - s)*np.float64(l + s)/(2.*l + 1.)
142
+ return -2.*m*s*np.sqrt(temp)/l/(l - 1.)/(l + 1.)
143
+
144
+ def k2p0(s, l, m):
145
+ temp = np.float64(l*(l + 1.) - 3.*m*m)/(2.*l - 1.)/l
146
+ temp *= np.float64(l*(l + 1.) - 3.*s*s)/(2.*l + 3.)/(l + 1.)
147
+ return 1./3.*(1. + 2.*temp)
148
+
149
+ def k2p1(s, l, m):
150
+ temp = np.float64(l - m + 1.)*np.float64(l + m + 1.)/(2.*l + 1.)
151
+ temp *= np.float64(l - s + 1.)*np.float64(l + s + 1.)/(2.*l + 3.)
152
+ return -2.*m*s*np.sqrt(temp)/l/(l + 1.)/(l + 2.)
153
+
154
+ def k2p2(s, l, m):
155
+ temp = (l - m + 1.)/(l + 1.)
156
+ temp *= (l + m + 1.)/(l + 1.)
157
+ temp *= (l - m + 2.)/(l + 2.)
158
+ temp *= (l + m + 2.)/(l + 2.)
159
+ temp *= (l - s + 2.)/(2.*l + 3.)
160
+ temp *= (l + s + 2.)/(2.*l + 3.)
161
+ temp *= (l - s + 1.)/(2.*l + 1.)
162
+ temp *= (l + s + 1.)/(2.*l + 5.)
163
+ return np.sqrt(temp)
164
+
165
+ def k1m1(s, l, m):
166
+ temp = np.float64(l - m)*np.float64(l + m)/(2.*l - 1.)
167
+ temp *= np.float64(l - s)*np.float64(l + s)/(2.*l + 1.)
168
+ return np.sqrt(temp)/l
169
+
170
+ def k1p0(s, l, m):
171
+ return -np.float64(m*s)/l/(l + 1.)
172
+
173
+ def k1p1(s, l, m):
174
+ temp = np.float64(l - m + 1.)*np.float64(l + m + 1.)/(2.*l + 3.)
175
+ temp *= np.float64(l - s + 1.)*np.float64(l + s + 1.)/(2.*l + 1.)
176
+ return np.sqrt(temp)/(l + 1.)
177
+
178
+ def akm2(s, l, m, g):
179
+ return -g*g*k2m2(s, l, m)
180
+
181
+ def akm1(s, l, m, g):
182
+ return -g*g*k2m1(s, l, m) + 2.*s*g*k1m1(s, l, m)
183
+
184
+ def akp0(s, l, m, g):
185
+ return -g*g*k2p0(s, l, m) + 2.*s*g*k1p0(s, l, m) + l*(l + 1.) - s*(s + 1.) - 2.*m*g + g*g
186
+
187
+ def akp1(s, l, m, g):
188
+ return -g*g*k2p1(s, l, m) + 2.*s*g*k1p1(s, l, m)
189
+
190
+ def akp2(s, l, m, g):
191
+ return -g*g*k2p2(s, l, m)
192
+
193
+ def spectral_sparse_matrix(s, m, g, nmax):
194
+ lmin = max(abs(s), abs(m))
195
+ larray = np.arange(lmin, lmin + nmax)
196
+ return scipy.sparse.diags([akm2(s, larray[2:], m, g), akm1(s, larray[1:], m, g), akp0(s, larray, m, g), akp1(s, larray[:-1], m, g), akp2(s, larray[:-2], m, g)], [-2, -1, 0, 1, 2])
197
+
198
+ def swsh_eigs(s, l, m, g, nmax=None, return_eigenvectors=True):
199
+ lmin = max(abs(s), abs(m))
200
+ kval = l - lmin
201
+
202
+ if nmax is None:
203
+ buffer = round(20 + 2*g)
204
+ Nmax = kval + buffer + 2
205
+ else:
206
+ if nmax < kval:
207
+ Nmax = kval + 5
208
+ else:
209
+ Nmax = nmax
210
+
211
+ mat = spectral_sparse_matrix(s, m, g, Nmax)
212
+ out = scipy.sparse.linalg.eigs(mat, k=Nmax-2, which='SM', return_eigenvectors=return_eigenvectors)
213
+
214
+ return out
215
+
216
+ def Yslm_eigenvalue(s, l, *args):
217
+ return l*(l + 1.) - s*(s + 1.)
218
+
219
+ def swsh_eigenvalue(s, l, m, g, nmax=None):
220
+ if g == 0.:
221
+ return Yslm_eigenvalue(s, l)
222
+
223
+ las = swsh_eigs(s, l, m, g, nmax=nmax, return_eigenvectors=False)
224
+
225
+ return np.real(las[::-1][l - max(abs(s), abs(m))])
226
+
227
+ def swsh_coeffs(s, l, m, g, th):
228
+ if g == 0.:
229
+ return Yslm(s, l, m, th)
230
+
231
+ _, eig = swsh_eigs(s, l, m, g, nmax=None, return_eigenvectors=True)
232
+ coeffs = np.real(eig[l - max(abs(s), abs(m))])
233
+
234
+ return np.real(eig[l - max(abs(s), abs(m))])
235
+
236
+ class SWSHBase:
237
+ def __init__(self, *args):
238
+ arg_num = np.array(args).shape[0]
239
+ if arg_num < 3:
240
+ print('Error. Not enough arguments to create class')
241
+ pass
242
+
243
+ self.s = args[0]
244
+ self.l = args[1]
245
+ self.m = args[2]
246
+ self.lmin = max(abs(self.s), abs(self.m))
247
+
248
+ if arg_num > 3:
249
+ self.spheroidicity = args[3]
250
+
251
+ class SWSHSeriesBase(SWSHBase):
252
+ def __init__(self, s, l, m, g):
253
+ SWSHBase.__init__(self, s, l, m, g)
254
+
255
+ def sparse_matrix(self, nmax):
256
+ return spectral_sparse_matrix(self.s, self.m, self.spheroidicity, nmax)
257
+
258
+ def eigs(self, nmax = None, **kwargs):
259
+ kval = self.l - self.lmin
260
+
261
+ if nmax is None:
262
+ buffer = round(20 + 2*self.spheroidicity)
263
+ Nmax = kval + buffer + 2
264
+ else:
265
+ if nmax < kval:
266
+ Nmax = kval + 5
267
+ else:
268
+ Nmax = nmax
269
+
270
+ if "k" not in kwargs.keys():
271
+ kwargs["k"] = Nmax - 2
272
+
273
+ if "which" not in kwargs.keys():
274
+ kwargs["which"] = 'SM'
275
+
276
+ # if "sigma" not in kwargs.keys():
277
+ # kwargs["sigma"] = (self.l + Nmax)*(self.l + Nmax + 1) - self.s*(self.s + 1)
278
+
279
+ if "return_eigenvectors" not in kwargs.keys():
280
+ kwargs["return_eigenvectors"] = True
281
+
282
+ mat = self.sparse_matrix(Nmax)
283
+ return scipy.sparse.linalg.eigs(mat, **kwargs)
284
+
285
+ def generate_eigenvalue(self):
286
+ las = np.real(self.eigs(return_eigenvectors=False))
287
+ pos = np.argsort(las)[self.l - self.lmin]
288
+ return las[pos]
289
+
290
+ def generate_eigs(self):
291
+ las, eigs = self.eigs()
292
+ pos = np.argsort(np.real(las))[self.l - self.lmin]
293
+ eigs_temp = np.real(eigs[:, pos])
294
+ eigs_return = np.sign(eigs_temp[self.l - self.lmin])*eigs_temp
295
+ return (np.real(las[pos]), eigs_return)
296
+
297
+ class SWSH(SWSHSeriesBase):
298
+ def __init__(self, s, l, m, g):
299
+ SWSHSeriesBase.__init__(self, s, l, m, g)
300
+ if self.spheroidicity == 0.:
301
+ self.eval = self.Yslm
302
+ self.eigenvalue = Yslm_eigenvalue(self.s, self.l)
303
+ self.coeffs = np.zeros(self.l - self.lmin)
304
+ self.coeffs[-1] = 1.
305
+ else:
306
+ self.eval = self.Sslm
307
+ self.eigenvalue, self.coeffs = self.generate_eigs()
308
+
309
+ def Yslm(self, l, th):
310
+ return Yslm(self.s, l, self.m, th)
311
+
312
+ def Sslm(self, *args):
313
+ th = args[-1]
314
+ term_num = self.coeffs.shape[0]
315
+ pts_num = th.shape[0]
316
+ Yslm_array = np.empty((term_num, pts_num))
317
+ for i in range(term_num):
318
+ Yslm_array[i] = self.Yslm(self.lmin + i, th)
319
+
320
+ return np.dot(self.coeffs, Yslm_array)
321
+
322
+ def __call__(self, th):
323
+ return self.eval(self.l, th)
324
+
325
+ def muCoupling(s, l):
326
+ """
327
+ Eigenvalue for the spin-weighted spherical harmonic lowering operator
328
+ Setting s -> -s gives the negative of the eigenvalue for the raising operator
329
+ """
330
+ if l + s < 0 or l - s + 1. < 0:
331
+ return 0
332
+ return np.sqrt((l - s + 1.)*(l + s))
333
+
334
+ def Asjlm(s, j, l, m):
335
+ if s >= 0:
336
+ return (-1.)**(m + s)*np.sqrt(4**s*fac(s)**2*(2*l + 1)*(2*j + 1)/fac(2*s))*w3j(s, l, j, 0, m, -m)*w3j(s, l, j, s, -s, 0)
337
+ else:
338
+ return (-1.)**(m)*np.sqrt(4**(-s)*fac(-s)**2*(2*l + 1)*(2*j + 1)/fac(-2*s))*w3j(-s, l, j, 0, m, -m)*w3j(-s, l, j, s, -s, 0)
339
+
340
+ def spin_operator_normalization(s, ns, l):
341
+ s_sgn = np.sign(s)
342
+ nmax1 = np.abs(s) + 1
343
+ Jterm = 1.
344
+ for ni in range(1, ns + 1):
345
+ Jterm *= -s_sgn*muCoupling((nmax1-ni), l)
346
+ return Jterm
347
+
pybhpt/teuk.py ADDED
@@ -0,0 +1,245 @@
1
+ from cybhpt_full import TeukolskyMode as TeukolskyModeCython
2
+
3
+ class TeukolskyMode:
4
+ """A class for computing Teukolsky modes sourced by a point-particle orbiting in a Kerr background.
5
+
6
+ Parameters
7
+ ----------
8
+ s : int
9
+ The spin weight of the Teukolsky mode.
10
+ j : int
11
+ The spheroidal harmonic mode number.
12
+ m : int
13
+ The azimuthal harmonic mode number.
14
+ k : int
15
+ The polar harmonic mode number.
16
+ n : int
17
+ The radial harmonic mode number.
18
+ geo : KerrGeodesic class instance
19
+ KerrGeodesic object containing the background motion of the point-particle source.
20
+ auto_solve : bool, optional
21
+ If True, the Teukolsky equation is automatically solved upon initialization. Default is False
22
+
23
+ Attributes
24
+ ----------
25
+ spinweight : int
26
+ The spin weight of the Teukolsky mode.
27
+ spheroidalmode : int
28
+ The spheroidal harmonic mode number.
29
+ azimuthalmode : int
30
+ The azimuthal harmonic mode number.
31
+ radialmode : int
32
+ The radial harmonic mode number.
33
+ polarmode : int
34
+ The polar harmonic mode number.
35
+ blackholespin : float
36
+ The spin of the black hole in the Kerr background.
37
+ frequency : float
38
+ The frequency of the Teukolsky mode.
39
+ horizonfrequency : float
40
+ The frequency of the mode at the horizon.
41
+ eigenvalue : float
42
+ The spheroidal eigenvalue of the Teukolsky mode.
43
+ mincouplingmode : int
44
+ The minimum l-mode used for coupling the spherical and spheroidal harmonics
45
+ maxcouplingmode : int
46
+ The maximum l-mode used for coupling the spherical and spheroidal harmonics
47
+ j : int
48
+ Alias for spheroidalmode.
49
+ m : int
50
+ Alias for azimuthalmode.
51
+ k : int
52
+ Alias for polarmode.
53
+ n : int
54
+ Alias for radialmode.
55
+ omega : float
56
+ Alias for frequency.
57
+ a : float
58
+ Alias for blackholespin.
59
+
60
+ Methods
61
+ -------
62
+ solve(geo, method = "AUTO", nsamples = 256, teuk = None, swsh = None)
63
+ Solve the Teukolsky equation for the given mode and geodesic.
64
+ flipspinweight()
65
+ Flip the spin weight of the Teukolsky mode.
66
+ flipspinweightandfrequency()
67
+ Flip the spin weight and frequency of the Teukolsky mode.
68
+ couplingcoefficient(l)
69
+ Compute the coupling coefficient for the given l-mode.
70
+ radialpoint(pos)
71
+ Compute the radial point for the given position.
72
+ radialsolution(bc, pos)
73
+ Compute the radial solution for the given boundary condition and position.
74
+ radialderivative(bc, pos)
75
+ Compute the radial derivative for the given boundary condition and position.
76
+ radialderivative2(bc, pos)
77
+ Compute the second radial derivative for the given boundary condition and position.
78
+ homogeneousradialsolution(bc, pos)
79
+ Compute the homogeneous radial solution for the given boundary condition and position.
80
+ homogeneousradialderivative(bc, pos)
81
+ Compute the homogeneous radial derivative for the given boundary condition and position.
82
+ homogeneousradialderivative2(bc, pos)
83
+ Compute the second homogeneous radial derivative for the given boundary condition and position.
84
+ polarpoint(pos)
85
+ Compute the polar point for the given position.
86
+ polarsolution(pos)
87
+ Compute the polar solution for the given position.
88
+ polarderivative(pos)
89
+ Compute the polar derivative for the given position.
90
+ polarderivative2(pos)
91
+ Compute the second polar derivative for the given position.
92
+ amplitude(bc)
93
+ Compute the Teukolsky amplitude for the given boundary condition.
94
+ precision(bc)
95
+ Compute the precision of the Teukolsky amplitude for the given boundary condition.
96
+ """
97
+ def __init__(self, s, j, m, k, n, geo, auto_solve = False):
98
+ self.base = TeukolskyModeCython(s, j, m, k, n, geo.base)
99
+ if auto_solve:
100
+ self.solve(geo)
101
+
102
+ @property
103
+ def spinweight(self):
104
+ return self.base.spinweight
105
+
106
+ @property
107
+ def spheroidalmode(self):
108
+ return self.base.spheroidalmode
109
+
110
+ @property
111
+ def azimuthalmode(self):
112
+ return self.base.azimuthalmode
113
+
114
+ @property
115
+ def radialmode(self):
116
+ return self.base.radialmode
117
+
118
+ @property
119
+ def polarmode(self):
120
+ return self.base.polarmode
121
+
122
+ @property
123
+ def blackholespin(self):
124
+ return self.base.blackholespin
125
+
126
+ @property
127
+ def frequency(self):
128
+ return self.base.frequency
129
+
130
+ @property
131
+ def horizonfrequency(self):
132
+ return self.base.horizonfrequency
133
+
134
+ @property
135
+ def eigenvalue(self):
136
+ return self.base.eigenvalue
137
+
138
+ @property
139
+ def mincouplingmode(self):
140
+ return self.base.mincouplingmode
141
+
142
+ @property
143
+ def maxcouplingmode(self):
144
+ return self.base.maxcouplingmode
145
+
146
+ # some useful aliases
147
+ @property
148
+ def j(self):
149
+ return self.spheroidalmode
150
+ @property
151
+ def m(self):
152
+ return self.azimuthalmode
153
+ @property
154
+ def k(self):
155
+ return self.polarmode
156
+ @property
157
+ def n(self):
158
+ return self.radialmode
159
+ @property
160
+ def omega(self):
161
+ return self.frequency
162
+ @property
163
+ def a(self):
164
+ return self.blackholespin
165
+
166
+ def solve(self, geo, method = "AUTO", nsamples = 256, teuk = None, swsh = None):
167
+ """Solve the Teukolsky equation for the given mode and geodesic.
168
+ Parameters
169
+ ----------
170
+ geo : KerrGeodesic class instance
171
+ KerrGeodesic object containing the background motion of the point-particle source.
172
+ method : str, optional
173
+ The method to use for solving the Teukolsky equation. Default is "AUTO".
174
+ nsamples : int, optional
175
+ The number of samples to use for the solution. Default is 256.
176
+ teuk : RadialTeukolsky, optional
177
+ RadialTeukolsky object to use for constructing the radial Green function. Default is None.
178
+ swsh : SpheroidalHarmonicMode, optional
179
+ SpheroidalHarmonic object to use for coupling with spheroidal harmonics. Default is None.
180
+
181
+ """
182
+ if teuk is None or swsh is None:
183
+ self.base.solve(geo.base, method, nsamples)
184
+ else:
185
+ self.base.solve(geo.base, method, nsamples, teuk.base, swsh.base)
186
+
187
+ """
188
+ Flips the spin-weight of the Teukolsky solutions from :math:`s \rightarrow -s`
189
+ """
190
+ def flipspinweight(self):
191
+ self.base.flip_spinweight()
192
+
193
+ """
194
+ Flips the spin-weight and frequency of the Teukolsky solutions from :math:`s \rightarrow -s` and :math:`\omega \rightarrow -\omega`
195
+ """
196
+ def flipspinweightandfrequency(self):
197
+ self.base.flip_spinweight_frequency()
198
+
199
+ """
200
+ Spherical-spheroidal mixing coefficient between a spherical harmonic :math:`l` mode with a spheroidal :math:`j` mode
201
+
202
+ :param l: spherical harmonic mode
203
+ :type l: int
204
+ """
205
+ def couplingcoefficient(self, l):
206
+ return self.base.couplingcoefficient(l)
207
+
208
+ def radialpoint(self, pos):
209
+ return self.base.radialpoint(pos)
210
+
211
+ def radialsolution(self, bc, pos):
212
+ return self.base.radialsolution(bc, pos)
213
+
214
+ def radialderivative(self, bc, pos):
215
+ return self.base.radialderivative(bc, pos)
216
+
217
+ def radialderivative2(self, bc, pos):
218
+ return self.base.radialderivative2(bc, pos)
219
+
220
+ def homogeneousradialsolution(self, bc, pos):
221
+ return self.base.homogeneousradialsolution(bc, pos)
222
+
223
+ def homogeneousradialderivative(self, bc, pos):
224
+ return self.base.homogeneousradialderivative(bc, pos)
225
+
226
+ def homogeneousradialderivative2(self, bc, pos):
227
+ return self.base.homogeneousradialderivative2(bc, pos)
228
+
229
+ def polarpoint(self, pos):
230
+ return self.base.polarpoint(pos)
231
+
232
+ def polarsolution(self, pos):
233
+ return self.base.polarsolution(pos)
234
+
235
+ def polarderivative(self, pos):
236
+ return self.base.polarderivative(pos)
237
+
238
+ def polarderivative2(self, pos):
239
+ return self.base.polarderivative2(pos)
240
+
241
+ def amplitude(self, bc):
242
+ return self.base.teukolsky_amplitude(bc)
243
+
244
+ def precision(self, bc):
245
+ return self.base.teukolsky_amplitude_precision(bc)