GremlinEq
FT.h
1 //---------------------------------------------------------------------------
2 //
3 // $Id: FT.h,v 1.2 2018/08/02 20:19:01 sahughes Exp $
4 //
5 //---------------------------------------------------------------------------
6 //
7 // A class for interacting with the Teukolsky equation solver described
8 // by Fujita and Tagoshi
9 //
10 
11 #ifndef FT_H_SEEN
12 #define FT_H_SEEN
13 
14 #include "teukolskydefs.h"
15 
16 #define FT_MAXDIVS 10
17 #define TEST_LENGTH 4
18 
19 #define FT_PRFX FT::
20 
22 
23 class FT {
24 public:
25  FT(const int l, const int m, const Real r, const Real a, const Real omega,
26  const Real lambda, const Real tolerance);
27  FT(const int l, const int m, const Real p, const Real ecc, const Real a,
28  const Real omega, const Real lambda, const Real tolerance);
29 
30  Complex Bin() { return b_inc; }
31  Complex Btrans() { return b_trans; }
32  Complex Ctrans() { return c_trans; }
34  void CalcRFields(const Real rad, const int DoH);
36  Complex TeukRin() { return rteuk_in; }
37  Complex TeukRup() { return rteuk_up; }
38  Complex dr_TeukRin() { return drteuk_in; }
39  Complex dr_TeukRup() { return drteuk_up; }
40  Complex ddr_TeukRin() { return ddrteuk_in; }
41  Complex ddr_TeukRup() { return ddrteuk_up; }
43  Real Accuracy_in() { return accuracy_in; }
44  Real Accuracy_up() { return accuracy_up; }
46  Real request_precision_in (const Real p) {
47  Real tmp = rin_request_precision;
48  rin_request_precision = Fmax(p,REAL_EPSILON);
49  return tmp;
50  }
52  Real request_precision_up(const Real p) {
53  Real tmp = rup_request_precision;
54  rup_request_precision = Fmax(p,REAL_EPSILON);
55  return tmp;
56  }
57  Real request_precision_in () { return rin_request_precision; }
58  Real request_precision_up() { return rup_request_precision; }
60  int terms_evaluated() {
61  int tmp = hypergeom_terms;
62  hypergeom_terms = 0;
63  return tmp;
64  }
65 
66  void set_gmp(int flag);
67  int get_gmp() { return gmp_on; }
68 
69 
70  inline Real K(const Real rad) {
71  return((rad*rad + a*a)*omega - m*a);
72  }
74  inline Real dr_K(const Real rad) {
75  return(2.*rad*omega);
76  }
78  inline Real ddr_K() {
79  return(2.*omega);
80  }
82  inline Complex teuk_potential(const Real rad) {
83  return - K(rad) / (rad*rad - 2*rad + a*a) * (K(rad) + 4*(rad-1)*I)
84  + 8 * omega * rad * I + lambda;
85  }
87  inline Complex get_ddrteuk(const Real rad,
88  const Complex rteuk, const Complex drteuk);
90  int choose_solvers(const Real low, const Real high,
91  const Real *lowerrs, const Real *higherrs,
92  const int isin, const int oldchoice,
93  Real **locptr, int **choiceptr, const int *maxchoiceptr);
95  void geterrs(const Real r, Real *errs, int isin);
96 
97  Complex callsolver(const int isin, const int which, const Real r,
98  const Real epsilon, const Complex nu,
99  const Real precision, Complex *deriv);
100 
101  Complex callin(const Real r, Complex *deriv);
102 
103  Complex callup(const Real r, Complex *deriv);
104 
105  void getlocs(const int isin);
106 
107  int l, m;
108  Real a, p, e, omega, lambda;
109  Real tolerance, accuracy_in, accuracy_up;
110  Real rin_request_precision, rup_request_precision;
111 
112  Complex nu;
113  Complex b_trans, b_inc, c_trans;
114 
115  Complex rteuk_in, rteuk_up;
116  Complex drteuk_in, drteuk_up;
117  Complex ddrteuk_in, ddrteuk_up;
118 
119  int up_choices[FT_MAXDIVS];
120  Real up_choice_locs[FT_MAXDIVS];
121  int in_choices[FT_MAXDIVS];
122  Real in_choice_locs[FT_MAXDIVS];
123 
124  Complex test_renangmoms[TEST_LENGTH];
125 
126  int gmp_on;
127  int hypergeom_terms;
128 
129 /* radialfrac.h
130  * evaluate the continued fraction */
131 
132 #ifndef RADIALFRAC_H_SEEN
133 #define RADIALFRAC_H_SEEN
134 
135 #include "teukolskydefs.h"
136 
137 /* estimate of the precision of the results of the fractions, as
138  * a multiple of their term sizes
139  * This is generally a very generous bound, because we want to catch outliers
140  */
141 #define TERM_NOISE 1e-14
142 
145 Real plusfrac(Real nu, Real epsilon, Real q, int m, Real lambda,
146  Real *term);
147 Complex cplusfrac(Complex nu, Real epsilon, Real q, int m, Real lambda,
148  Real *term);
149 
150 /* evaluate the fraction with decreasing n
151  * - a_-1 / (b_-1 - a_-2 / (... */
152 Real minusfrac(Real nu, Real epsilon, Real q, int m, Real lambda,
153  Real *term);
154 Complex cminusfrac(Complex nu, Real epsilon, Real q, int m, Real lambda,
155  Real *term);
156 
157 /* evaluate the whole thing */
158 Real radialfrac(Real nu, Real epsilon, Real q, int m, Real lambda,
159  Real *term);
160 Complex cradialfrac(Complex nu, Real epsilon, Real q, int m, Real lambda,
161  Real *term);
162 
163 /* Evaluate the continued fraction on the special line Re(nu) = -1/2
164  * It is guaranteed to be real there */
165 Real radialfrac_half(Real imnu, Real epsilon, Real q, int m, Real lambda,
166  Real *term);
167 
168 #endif /* RADIALFRAC_H_SEEN */
169 
170 /* renangmom.h
171  * compute the renormalized angular momentum nu by solving the radial
172  * continued fraction equation
173  */
174 
175 #ifndef RENANGMOM_H_SEEN
176 #define RENANGMOM_H_SEEN
177 
178 #include "teukolskydefs.h"
179 
180 /* calculates nu
181  * returns 1 if it suceeds, 0 else */
182 int renangmom(Real epsilon, Real q, int l, int m, Real lambda, Complex *nu);
183 
184 /* calculates the value of the fraction at -1/2 and the slope at 1.
185  * Returns 1 if the values appear to have the right sign */
186 int get_deciders(Real epsilon, Real q, int m, Real lambda,
187  Real *halfval, Real *oneslope);
188 
189 /* calculates nu assuming it is real by calling the other
190  * renangmom_real* functions. returns 1 on success, 0 else */
191 int renangmom_real_search_procedure(Real epsilon, Real q, int l,
192  int m, Real lambda, Complex *nu);
193 
194 /* assuming the root is near an integer or half integer, fit the two
195  * approaches to epsilon with polynomials and extrapolate.
196  * returns 1 on success, 0 else */
197 int singularity_fit(Real epsilon, Real q, int l, int m, Real lambda,
198  int guessint, int guessint2, Real spacing, Complex *nu);
199 
200 /* calulates nu assuming it is real. returns 1 if it suceeds, 0 else */
201 int renangmom_real(Real epsilon, Real q, int l, int m, Real lambda,
202  Real detect_limit, Real *nu);
203 
204 /* uses about the closest thing to a brute force root finder that I could
205  * come up with to search for real nu. Returns 1 if it succeeds */
206 int renangmom_real_divide_search(Real epsilon, Real q, int l, int m,
207  Real lambda, Real *nu);
208 
209 /* calulates nu assuming it is on the special line.
210  * Returns 1 if it suceeds, 0 else */
211 int renangmom_half(Real epsilon, Real q, int l, int m, Real lambda,
212  Real *imnu);
213 
214 /* calculates nu assuming it is on the line Re(nu) = 1 (so any int is
215  * then a solution)
216  * Returns 1 if it suceeds, 0 else */
217 int renangmom_iint(Real epsilon, Real q, int l, int m, Real lambda,
218  Real *imnu);
219 
220 /* Calculates nu when epsilon is too large for the region checks to work
221  * Assumes nu is complex */
222 int renangmom_far(Real epsilon, Real q, int l, int m, Real lambda,
223  Complex *nu);
224 
225 /* a very rough guess at Im(nu), used internally.
226  * returns the imaginary part of the nu such that beta(0) vanishes */
227 Real nu_predictor(Real epsilon,Real q,int m,Real lambda);
228 
229 /* search for the root assuming the function is well behaved near guess and
230  * that the root is closer to guess than to a half integer */
231 int renangmom_real_guess(Real epsilon, Real q, int m, Real lambda, Real guess,
232  Real *nu);
233 
234 /* approximate the root using a polynomial approximation in large nu */
235 Real fractions_poly_approx(Real epsilon, Real q, int m, Real lambda);
236 
237 #endif /* RENANGMOM_H_SEEN */
238 
239 /* specialradial.h
240  * Functions to calculate properties of the radial continued fraction
241  * at special points
242  */
243 
244 #ifndef SPECIALRADIAL_H_SEEN
245 #define SPECIALRADIAL_H_SEEN
246 
247 #include "teukolskydefs.h"
248 
249 /* estimate of the precision of the results of the special functions, as
250  * a multiple of their term sizes */
251 #define SPECIAL_TERM_NOISE 1e-12
252 
253 /* calculate the value of the function at nu = -1/2
254  * If term is not NULL, the address it points to will be set to the magnitude
255  * of one of the terms in the final addition */
256 Real radial_half_value(Real epsilon, Real q, int m, Real lambda, Real *term);
257 
258 /* calculate the slope of the function at nu = 1
259  * If term is not NULL, the address it points to will be set to the magnitude
260  * of one of the terms in the final addition */
261 Real radial_int_slope(Real epsilon, Real q, int m, Real lambda, Real *term);
262 
263 #endif /* SPECIALRADIAL_H_SEEN */
264 
265 /* fsum.h
266  * Perform sums of the expansion coefficients of the radial Teukolsky equation
267  */
268 
269 #ifndef FSUM_H_SEEN
270 #define FSUM_H_SEEN
271 
272 #include "teukolskydefs.h"
273 
274 /* Calculate the asymptitic amplitudes
275  * Any of the pointers can be null */
276 void asympt_amps(Complex nu, Real epsilon, Real q, int m, Real lambda,
277  Complex *b_trans, Complex *b_inc, Complex *b_ref,
278  Complex *c_trans);
279 
280 /* perform a straight sum of the f's from -\infty to \infty (to some
281  * approximation), normalizing f_0 = 1 */
282 Complex fsum(Complex nu, Real epsilon, Real q, int m, Real lambda);
283 
284 /* Compute the K_\nu factor */
285 Complex kfactor(Complex nu, Real epsilon, Real q, int m, Real lambda);
286 
287 /* compute A_{-}^\nu */
288 Complex aminus(Complex nu, Real epsilon, Real q, int m, Real lambda);
289 
290 /* compute R_0^\nu
291  * if deriv is non-NULL it will be set to d/dr R_0 */
292 Complex rzero(Complex nu, Real epsilon, Real q, int m, Real lambda, Real x,
293  Complex *deriv);
294 
295 /* compute R^{in}_{lmw} from hypergeometric functions
296  * if deriv is non-NULL it will be set to d/dr R^{in} */
297 Complex rin_hyper(Complex nu, Real epsilon, Real q, int m, Real lambda,
298  Real x, Real precision, Complex *deriv);
299 
300 /* compute R_C */
301 Complex rcoulomb(Complex nu, Real epsilon, Real q, int m, Real lambda, Real z,
302  Complex *deriv);
303 
304 /* compute R^{in}_{lmw} from Coulomb wave functions */
305 Complex rin_coulomb(Complex nu, Real epsilon, Real q, int m, Real lambda,
306  Real z, Real precision, Complex *deriv);
307 
308 /* compute R^{in}_{lmw}
309  * if deriv is non-NULL it will be set to d/dr R^{in} */
310 /*Complex rin(Complex nu, Real epsilon, Real q, int m, Real lambda, Real r,
311  Complex *deriv);*/
312 
313 /* compute R^{up}_{lmw} using Tricomi functions
314  * if deriv is non-NULL it will be set to d/dr R^{up} */
315 Complex rup_tricomi(Complex nu, Real epsilon, Real q, int m, Real lambda,
316  Real z, Real precision, Complex *deriv);
317 
318 /* compute R^{up}_{lmw}
319  * if deriv is non-NULL it will be set to d/dr R^{up} */
320 /*Complex rup(Complex nu, Real epsilon, Real q, int m, Real lambda, Real r,
321  Complex *deriv);*/
322 
323 /* compute R^{in}_{lmw} from hypergeometric functions optimized for
324  * the case where r is small
325  * if deriv is non-NULL it will be set to d/dr R^{in} */
326 Complex rin_small(Complex nu, Real epsilon, Real q, int m, Real lambda,
327  Real x, Real precision, Complex *deriv);
328 
329 /* compute R^{up}_{lmw} using Hypergeometric functions
330  * if deriv is non-NULL it will be set to d/dr R^{up} */
331 Complex rup_hyper(Complex nu, Real epsilon, Real q, int m, Real lambda,
332  Real x, Real precision, Complex *deriv);
333 
334 #endif /* !FSUM_H_SEEN */
335 
336 /* funcs.h
337  * headers for the special functions routines
338  */
339 
340 #ifndef FUNCS_H_SEEN
341 #define FUNCS_H_SEEN
342 
343 #include <complex>
344 
345 /* USE_GMP
346  * undef = gmp disabled at build time
347  * defined but false = gmp forced
348  * defined and true = gmp controlable at runtime
349  */
350 #ifndef NO_GMP
351 # define USE_GMP 1
352 #endif
353 
354 #define HYPERGEOM_REAL_TYPE long double
355 
356 /* These functions have been declared using the built in types because some
357  * of them (mainly gammln) will not give enough precision for a long double */
358 
359 /* logarithm of the gamma function */
360 std::complex<double> gammln(const std::complex<double> x);
361 
362 /* logarithm of the sine function */
363 std::complex<double> sinln(const std::complex<double> x);
364 
365 /* hypergeometric function 2F1(n1,n2;d1;x)
366  * only works for abs(x) < 1
367  * it has some issues for large magnitude n1,n2,d1, particularly near x = -1
368  */
369 std::complex<HYPERGEOM_REAL_TYPE>
370 hypergeom2F1(std::complex<double> n1, std::complex<double> n2,
371  std::complex<double> d1, std::complex<double> x);
372 
373 /* confluent hypergeometric function 1F1(n1;d1;x) */
374 std::complex<HYPERGEOM_REAL_TYPE>
375 hypergeom1F1(std::complex<double> n1, std::complex<double> d1,
376  std::complex<double> x);
377 
378 /* irregular Tricomi hypergeometric function U(a;b;x) */
379 std::complex<HYPERGEOM_REAL_TYPE>
380 hypergeomU(std::complex<double> a, std::complex<double> b,
381  std::complex<double> x);
382 
383 /* irregular Tricomi hypergeometric function U(a;b;x)*Gamma(a-b+1)/Gamma(1-b)
384  */
385 std::complex<HYPERGEOM_REAL_TYPE>
386 hypergeomU_reduced(std::complex<double> a, std::complex<double> b,
387  std::complex<double> x);
388 
389 #ifdef USE_GMP
390 std::complex<HYPERGEOM_REAL_TYPE>
391 hypergeom2F1_gmp(std::complex<double> n1, std::complex<double> n2,
392  std::complex<double> d1, std::complex<double> x,
393  int precision);
394 std::complex<HYPERGEOM_REAL_TYPE>
395 hypergeom1F1_gmp(std::complex<double> n1, std::complex<double> d1,
396  std::complex<double> x, int precision);
397 #endif /* USE_GMP */
398 
399 #endif /* !FUNCS_H_SEEN */
400 
401 };
402 
403 #endif /* !FT_H_SEEN */
Complex ddr_TeukRup()
Definition: FT.h:41
Complex TeukRup()
Definition: FT.h:37
void CalcRFields(const Real rad, const int DoH)
Definition: FT.cc:191
Real Accuracy_up()
Definition: FT.h:44
Complex rteuk_up
Radial Teukolsky function.
Definition: FT.h:115
Real K(const Real rad)
Definition: FT.h:70
Real dr_K(const Real rad)
Definition: FT.h:74
int choose_solvers(const Real low, const Real high, const Real *lowerrs, const Real *higherrs, const int isin, const int oldchoice, Real **locptr, int **choiceptr, const int *maxchoiceptr)
Definition: FT.cc:208
Complex get_ddrteuk(const Real rad, const Complex rteuk, const Complex drteuk)
Definition: FT.cc:201
Complex Ctrans()
Definition: FT.h:32
Complex Btrans()
Definition: FT.h:31
Real Accuracy_in()
Definition: FT.h:43
Complex ddr_TeukRin()
Definition: FT.h:40
Complex ddrteuk_up
Second derivatives of the radial Teukolsky function.
Definition: FT.h:117
Real request_precision_in(const Real p)
Definition: FT.h:46
Real request_precision_up()
Definition: FT.h:58
Complex nu
The renormalized angular momentum.
Definition: FT.h:112
Complex dr_TeukRin()
Definition: FT.h:38
Real request_precision_in()
Definition: FT.h:57
Complex drteuk_up
First derivatives of radial Teukolsky function.
Definition: FT.h:116
Real request_precision_up(const Real p)
Definition: FT.h:52
Complex Bin()
Definition: FT.h:30
Complex TeukRin()
Definition: FT.h:36
Complex dr_TeukRup()
Definition: FT.h:39
Complex teuk_potential(const Real rad)
Definition: FT.h:82
Real ddr_K()
Definition: FT.h:78