TransitionListener 2.0.0__py3-none-any.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.
Files changed (95) hide show
  1. transitionlistener/__init__.py +21 -0
  2. transitionlistener/bubbledynamics.py +2250 -0
  3. transitionlistener/bubbledynamics_fixedstep.py +2929 -0
  4. transitionlistener/check_installation.py +309 -0
  5. transitionlistener/ckm.py +91 -0
  6. transitionlistener/colors.py +288 -0
  7. transitionlistener/config.py +185 -0
  8. transitionlistener/constants.py +64 -0
  9. transitionlistener/counterterms/__init__.py +230 -0
  10. transitionlistener/counterterms/cw.py +298 -0
  11. transitionlistener/counterterms/tensors.py +343 -0
  12. transitionlistener/counterterms/twohdm.py +520 -0
  13. transitionlistener/counterterms/twohdm_solver.py +374 -0
  14. transitionlistener/errors.py +315 -0
  15. transitionlistener/examples/bp_et.yaml +64 -0
  16. transitionlistener/examples/bp_lisa.yaml +70 -0
  17. transitionlistener/examples/bp_muares.yaml +69 -0
  18. transitionlistener/examples/bp_pta.yaml +64 -0
  19. transitionlistener/examples/example_dark_photon.yaml +73 -0
  20. transitionlistener/examples/example_grid.yaml +55 -0
  21. transitionlistener/examples/example_line.yaml +51 -0
  22. transitionlistener/examples/example_point.yaml +73 -0
  23. transitionlistener/examples/example_random_conformal.yaml +42 -0
  24. transitionlistener/examples/example_ultranest.yaml +39 -0
  25. transitionlistener/finiteT.py +468 -0
  26. transitionlistener/generic_potential.py +1521 -0
  27. transitionlistener/gridplots.py +592 -0
  28. transitionlistener/gwfopt.py +604 -0
  29. transitionlistener/helper_functions.py +843 -0
  30. transitionlistener/hydrodynamics.py +647 -0
  31. transitionlistener/interface/__init__.py +95 -0
  32. transitionlistener/interface/check.py +51 -0
  33. transitionlistener/interface/cli.py +211 -0
  34. transitionlistener/interface/config_loader.py +264 -0
  35. transitionlistener/interface/logging_utils.py +30 -0
  36. transitionlistener/interface/output_schema.py +296 -0
  37. transitionlistener/interface/pipeline.py +300 -0
  38. transitionlistener/interface/samplers.py +565 -0
  39. transitionlistener/interface/scans.py +468 -0
  40. transitionlistener/interface/single_point.py +581 -0
  41. transitionlistener/interface/state.py +61 -0
  42. transitionlistener/lineplots.py +597 -0
  43. transitionlistener/logo/TL-logo_large.png +0 -0
  44. transitionlistener/logo/TL-logo_small.png +0 -0
  45. transitionlistener/models/TL_2HDM.py +512 -0
  46. transitionlistener/models/TL_conformal_dark_u1.py +202 -0
  47. transitionlistener/models/TL_dark_U1.py +198 -0
  48. transitionlistener/models/TL_dark_U1_g_parameterization.py +198 -0
  49. transitionlistener/models/TL_dark_flipflop.py +274 -0
  50. transitionlistener/models/templatePotential.py +260 -0
  51. transitionlistener/nucleation.py +412 -0
  52. transitionlistener/observability.py +790 -0
  53. transitionlistener/particles.py +436 -0
  54. transitionlistener/pathDeformation.py +1462 -0
  55. transitionlistener/percolation_adaptive_gridbuilders.py +1385 -0
  56. transitionlistener/percolation_adaptive_rate.py +1049 -0
  57. transitionlistener/percolation_adaptivestepsize.py +1632 -0
  58. transitionlistener/percolation_fixedstepsize.py +618 -0
  59. transitionlistener/phases.py +1499 -0
  60. transitionlistener/plot_settings.py +121 -0
  61. transitionlistener/plots.py +1781 -0
  62. transitionlistener/runtime_options.py +278 -0
  63. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/bandwidths.npy +0 -0
  64. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/density.npy +0 -0
  65. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/freqs.npy +0 -0
  66. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log.txt +16 -0
  67. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rhogrid.npy +0 -0
  68. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rholabels.txt +30 -0
  69. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/pulsar_list.txt +1 -0
  70. transitionlistener/tab_data/HLV-O2-PLI.csv +82 -0
  71. transitionlistener/tab_data/HLV-O2-noise.csv +83 -0
  72. transitionlistener/tab_data/HLVK-design-PLI.csv +61 -0
  73. transitionlistener/tab_data/HLVK-design-noise.csv +83 -0
  74. transitionlistener/tab_data/NG15_PLI_hc.csv +31 -0
  75. transitionlistener/tab_data/NG15_noise_hc.csv +56 -0
  76. transitionlistener/tab_data/PLI-dataset.csv +327 -0
  77. transitionlistener/tab_data/energydensities.dat +1001 -0
  78. transitionlistener/tab_data/finiteT_b.dat.txt +1999 -0
  79. transitionlistener/tab_data/finiteT_f.dat.txt +1000 -0
  80. transitionlistener/tab_data/geff_SM.dat +10009 -0
  81. transitionlistener/tab_data/muAres_f_Hz_PLI_h2OmegaGW.csv +131 -0
  82. transitionlistener/tab_data/muAres_f_Hz_h2Omega_noise.csv +99 -0
  83. transitionlistener/tab_data/noise-dataset.csv +327 -0
  84. transitionlistener/tab_data/numberdensities.dat +1001 -0
  85. transitionlistener/tab_data/pressures.dat +1001 -0
  86. transitionlistener/thermodynamics.py +686 -0
  87. transitionlistener/transitionObservables.py +1199 -0
  88. transitionlistener/transitionObservables_fixedstep.py +976 -0
  89. transitionlistener/transitions.py +1000 -0
  90. transitionlistener/tunneling1D.py +910 -0
  91. transitionlistener-2.0.0.dist-info/METADATA +817 -0
  92. transitionlistener-2.0.0.dist-info/RECORD +95 -0
  93. transitionlistener-2.0.0.dist-info/WHEEL +4 -0
  94. transitionlistener-2.0.0.dist-info/entry_points.txt +2 -0
  95. transitionlistener-2.0.0.dist-info/licenses/LICENSE.txt +674 -0
@@ -0,0 +1,468 @@
1
+ """
2
+ This module provides the functions for the one-loop finite
3
+ temperature corrections to a potential in QFT. The two basic
4
+ functions are:
5
+
6
+ Jb(x) = int[0->inf] dy +y^2 log( 1 - exp(-sqrt(x^2 + y^2)) )
7
+
8
+ Jf(x) = int[0->inf] dy -y^2 log( 1 + exp(-sqrt(x^2 + y^2)) )
9
+
10
+ Call them by:
11
+
12
+ Jb(x, approx='high', deriv=0, n = 8)
13
+
14
+ Here, approx can either be 'exact', 'spline', 'high', or 'low'.
15
+ ``Exact`` calculates the integral numerically, while ``high``
16
+ and ``low`` calculate the high and low x expansions of J to order n.
17
+ Specify the derivative with the ``deriv`` parameter.
18
+
19
+ Part of TransitionListener v2.0
20
+ Documentation: https://tasillo.de/TransitionListener/
21
+
22
+ Authors:
23
+ Jonas Matuszak <jonas.matuszak@kit.edu>
24
+ Carlo Tasillo <carlo.tasillo@ific.uv.es>
25
+ """
26
+
27
+ import os
28
+ from typing import Callable
29
+
30
+ import numpy
31
+ from scipy import integrate, interpolate
32
+ from scipy import special
33
+ from scipy.special import factorial as fac
34
+
35
+ pi = numpy.pi
36
+ euler_gamma = 0.577215661901532
37
+ log, exp, sqrt = numpy.log, numpy.exp, numpy.sqrt
38
+ array = numpy.array
39
+
40
+ spline_data_path = os.path.dirname(__file__) + "/tab_data"
41
+
42
+
43
+ # The following are the exact integrals:
44
+
45
+ def _Jf_exact(x : complex | float) -> complex:
46
+ """Evaluate the fermionic thermal integral for a single scalar argument.
47
+
48
+ Parameters
49
+ ----------
50
+ x : complex | float
51
+ Dimensionless mass-to-temperature ratio. Complex values are handled via
52
+ analytic continuation as described in the original CosmoTransitions
53
+ implementation.
54
+
55
+ Returns
56
+ -------
57
+ complex
58
+ Exact value of the integral ``J_f(x)``.
59
+ """
60
+ f = lambda y: -y*y*log(1+exp(-sqrt(y*y+x*x)))
61
+ if(x.imag == 0):
62
+ x = abs(x)
63
+ return integrate.quad(f, 0, numpy.inf)[0]
64
+ else:
65
+ f1 = lambda y: -y*y*log(2*abs(numpy.cos(sqrt(abs(x*x)-y*y)/2)))
66
+ return (
67
+ integrate.quad(f1,0,abs(x))[0] +
68
+ integrate.quad(f,abs(x),numpy.inf)[0]
69
+ )
70
+
71
+
72
+ def _Jf_exact2(theta : float) -> float:
73
+ """Evaluate the fermionic thermal integral as a function of ``theta = x^2``.
74
+
75
+ Parameters
76
+ ----------
77
+ theta : float
78
+ Squared mass-to-temperature ratio. Negative values are supported through
79
+ analytic continuation.
80
+
81
+ Returns
82
+ -------
83
+ float
84
+ Exact value of the integral ``J_f(x)`` with ``x^2 = theta``.
85
+ """
86
+ # Note that this is a function of theta so that you can get negative values
87
+ f = lambda y: -y*y*log(1+exp(-sqrt(y*y+theta))).real
88
+ if theta >= 0:
89
+ return integrate.quad(f, 0, numpy.inf)[0]
90
+ else:
91
+ f1 = lambda y: -y*y*log(2*abs(numpy.cos(sqrt(-theta-y*y)/2)))
92
+ return (
93
+ integrate.quad(f, abs(theta)**.5, numpy.inf)[0] +
94
+ integrate.quad(f1, 0, abs(theta)**.5)[0]
95
+ )
96
+
97
+
98
+ def _Jb_exact(x : complex | float) -> complex:
99
+ """Evaluate the bosonic thermal integral for a single scalar argument.
100
+
101
+ Parameters
102
+ ----------
103
+ x : complex | float
104
+ Dimensionless mass-to-temperature ratio. Complex values are handled via
105
+ analytic continuation.
106
+
107
+ Returns
108
+ -------
109
+ complex
110
+ Exact value of the integral ``J_b(x)``.
111
+ """
112
+ f = lambda y: y*y*log(1-exp(-sqrt(y*y+x*x)))
113
+ if(x.imag == 0):
114
+ x = abs(x)
115
+ return integrate.quad(f, 0, numpy.inf)[0]
116
+ else:
117
+ f1 = lambda y: y*y*log(2*abs(numpy.sin(sqrt(abs(x*x)-y*y)/2)))
118
+ return (
119
+ integrate.quad(f1,0,abs(x))[0] +
120
+ integrate.quad(f,abs(x),numpy.inf)[0]
121
+ )
122
+
123
+
124
+ def _Jb_exact2(theta : float) -> float:
125
+ """Evaluate the bosonic thermal integral as a function of ``theta = x^2``.
126
+
127
+ Parameters
128
+ ----------
129
+ theta : float
130
+ Squared mass-to-temperature ratio. Negative values are supported through
131
+ analytic continuation.
132
+
133
+ Returns
134
+ -------
135
+ float
136
+ Exact value of the integral ``J_b(x)`` with ``x^2 = theta``.
137
+ """
138
+ # Note that this is a function of theta so that you can get negative values
139
+ f = lambda y: y*y*log(1-exp(-sqrt(y*y+theta))).real
140
+ if theta >= 0:
141
+ return integrate.quad(f, 0, numpy.inf)[0]
142
+ else:
143
+ f1 = lambda y: y*y*log(2*abs(numpy.sin(sqrt(-theta-y*y)/2)))
144
+ return (
145
+ integrate.quad(f, abs(theta)**.5, numpy.inf)[0] +
146
+ integrate.quad(f1, 0, abs(theta)**.5)[0]
147
+ )
148
+
149
+
150
+ def _dJf_exact(x : complex | float) -> complex:
151
+ """Derivative of the fermionic thermal integral with respect to ``x``."""
152
+ f = lambda y: y*y*(exp(sqrt(y*y+x*x))+1)**-1*x/sqrt(y*y+x*x)
153
+ return integrate.quad(f, 0, numpy.inf)[0]
154
+
155
+
156
+ def _dJb_exact(x : complex | float) -> complex:
157
+ """Derivative of the bosonic thermal integral with respect to ``x``."""
158
+ f = lambda y: y*y*(exp(sqrt(y*y+x*x))-1)**-1*x/sqrt(y*y+x*x)
159
+ return integrate.quad(f, 0, numpy.inf)[0]
160
+
161
+
162
+ def arrayFunc(f : Callable[[float], float], x : float | numpy.ndarray, typ=float) -> numpy.ndarray | float:
163
+ """Vectorise a scalar integrand helper so it accepts scalar or 1D arrays.
164
+
165
+ Parameters
166
+ ----------
167
+ f : Callable[[float], float]
168
+ Function that accepts and returns scalar values.
169
+ x : float | array-like
170
+ Input argument. Arrays are handled element-wise, scalars are forwarded
171
+ directly.
172
+ typ : type, optional
173
+ Data type of the output array. Defaults to ``float``.
174
+
175
+ Returns
176
+ -------
177
+ numpy.ndarray | float
178
+ Array of evaluated values or the scalar return of ``f(x)``.
179
+ """
180
+ i = 0
181
+ try:
182
+ n = len(x)
183
+ except:
184
+ return f(x) # x isn't an array
185
+ s = numpy.empty(n, typ)
186
+ while(i < n):
187
+ try:
188
+ s[i] = f(x[i])
189
+ except:
190
+ s[i] = numpy.NaN
191
+ i += 1
192
+ return s
193
+
194
+
195
+ def Jf_exact(x : complex | float) -> complex | float:
196
+ """Jf calculated directly from the integral."""
197
+ return arrayFunc(_Jf_exact, x, complex)
198
+
199
+
200
+ def Jf_exact2(theta : float) -> float:
201
+ """Jf calculated directly from the integral; input is theta = x^2."""
202
+ return arrayFunc(_Jf_exact2, theta)
203
+
204
+
205
+ def Jb_exact(x : complex | float) -> complex | float:
206
+ """Jb calculated directly from the integral."""
207
+ return arrayFunc(_Jb_exact, x)
208
+
209
+
210
+ def Jb_exact2(theta : float) -> float:
211
+ """Jb calculated directly from the integral; input is theta = x^2."""
212
+ return arrayFunc(_Jb_exact2, theta)
213
+
214
+
215
+ def dJf_exact(x : complex | float) -> complex | float:
216
+ """dJf/dx calculated directly from the integral."""
217
+ return arrayFunc(_dJf_exact, x)
218
+
219
+
220
+ def dJb_exact(x : complex | float) -> complex | float:
221
+ """dJb/dx calculated directly from the integral."""
222
+ return arrayFunc(_dJb_exact, x)
223
+
224
+
225
+ # Spline fitting, Jf
226
+ _xfmin = -6.82200203 # -11.2403168
227
+ _xfmax = 1.35e3
228
+ _Jf_dat_path = spline_data_path+"/finiteT_f.dat.txt"
229
+ if os.path.exists(_Jf_dat_path):
230
+ _xf, _yf = numpy.loadtxt(_Jf_dat_path).T
231
+ else:
232
+ # x = |xmin|*sinh(y), where y in linear
233
+ # (so that we're not overpopulating the uniteresting region)
234
+ _xf = numpy.linspace(numpy.arcsinh(-1.3*20),
235
+ numpy.arcsinh(-20*_xfmax/_xfmin), 1000)
236
+ _xf = abs(_xfmin)*numpy.sinh(_xf)/20
237
+ _yf = Jf_exact2(_xf)
238
+ numpy.savetxt(_Jf_dat_path, numpy.array([_xf, _yf]).T)
239
+
240
+
241
+ _tckf = interpolate.splrep(_xf, _yf)
242
+ def Jf_spline(X,n=0):
243
+ """Jf interpolated from a saved spline. Input is (m/T)^2."""
244
+ X = numpy.array(X, copy=False)
245
+ x = X.ravel()
246
+ y = interpolate.splev(x,_tckf, der=n).ravel()
247
+ y[x < _xfmin] = interpolate.splev(_xfmin,_tckf, der=n)
248
+ y[x > _xfmax] = 0
249
+ return y.reshape(X.shape)
250
+
251
+
252
+ # Spline fitting, Jb
253
+ _xbmin = -2999.9999999999995 # This is new, see BSMPTv3 appendix
254
+ # We're setting the lower acceptable bound as the point where it's a minimum
255
+ # This guarantees that it's a monatonically increasing function, and the first
256
+ # deriv is continuous.
257
+ _xbmax = 1.41e3
258
+ _Jb_dat_path = spline_data_path+"/finiteT_b.dat.txt"
259
+ if os.path.exists(_Jb_dat_path):
260
+ _xb, _yb = numpy.loadtxt(_Jb_dat_path).T
261
+ else:
262
+ # x = |xmin|*sinh(y), where y in linear
263
+ # (so that we're not overpopulating the uniteresting region)
264
+ _xb = numpy.linspace(numpy.arcsinh(-1.3*20),
265
+ numpy.arcsinh(-20*_xbmax/_xbmin), 1000)
266
+ _xb = abs(_xbmin)*numpy.sinh(_xb)/20
267
+ _yb = Jb_exact2(_xb)
268
+ numpy.savetxt(_Jb_dat_path, numpy.array([_xb, _yb]).T)
269
+
270
+
271
+ _tckb = interpolate.splrep(_xb, _yb)
272
+ def Jb_spline(X : float | numpy.ndarray, n : int = 0) -> float | numpy.ndarray:
273
+ """Jb interpolated from a saved spline. Input is (m/T)^2."""
274
+ X = numpy.array(X, copy=False)
275
+ x = X.ravel()
276
+ y = interpolate.splev(x,_tckb, der=n).ravel()
277
+ y[x < _xbmin] = interpolate.splev(_xbmin,_tckb, der=n)
278
+ y[x > _xbmax] = 0
279
+ return y.reshape(X.shape)
280
+
281
+
282
+ # Now for the low x expansion (require that n <= 50)
283
+ a,b,c,d = -pi**4/45, pi*pi/12, -pi/6, -1/32.
284
+ logab = 1.5 - 2*euler_gamma + 2*log(4*pi)
285
+ l = numpy.arange(50)+1
286
+ g = (-2*pi**3.5 * (-1)**l*(1+special.zetac(2*l+1)) *
287
+ special.gamma(l+.5)/(fac(l+2)*(2*pi)**(2*l+4)))
288
+ lowCoef_b = (a,b,c,d,logab,l,g)
289
+ del (a,b,c,d,logab,l,g) # clean up name space
290
+
291
+ a,b,d = -7*pi**4/360, pi*pi/24, 1/32.
292
+ logaf = 1.5 - 2*euler_gamma + 2*log(pi)
293
+ l = numpy.arange(50)+1
294
+ g = (.25*pi**3.5 * (-1)**l*(1+special.zetac(2*l+1)) *
295
+ special.gamma(l+.5)*(1-.5**(2*l+1))/(fac(l+2)*pi**(2*l+4)))
296
+ lowCoef_f = (a,b,d,logaf,l,g)
297
+ del (a,b,d,logaf,l,g) # clean up name space
298
+
299
+
300
+ def Jb_low(x : complex | float, n : int = 20) -> complex | float:
301
+ """Jb calculated using the low-x (high-T) expansion."""
302
+ (a,b,c,d,logab,l,g) = lowCoef_b
303
+ y = a + x*x*(b + x*(c + d*x*(numpy.nan_to_num(log(x*x)) - logab)))
304
+ i = 1
305
+ while i <= n:
306
+ y += g[i-1]*x**(2*i+4)
307
+ i += 1
308
+ return y
309
+
310
+
311
+ def Jf_low(x : complex | float, n : int = 20) -> complex | float:
312
+ """Jf calculated using the low-x (high-T) expansion."""
313
+ (a,b,d,logaf,l,g) = lowCoef_f
314
+ y = a + x*x*(b + d*x*x*(numpy.nan_to_num(log(x*x)) - logaf))
315
+ i = 1
316
+ while i <= n:
317
+ y += g[i-1]*x**(2*i+4)
318
+ i += 1
319
+ return y
320
+
321
+
322
+ # The next few functions are all for the high-T approximation
323
+
324
+ def x2K2(k : int, x : float | numpy.ndarray) -> float | numpy.ndarray:
325
+ """Return ``-x^2 K_2(k x) / k^2`` with analytic behaviour enforced at the origin,
326
+ where ``K_2`` is the modified Bessel function of the second kind.
327
+
328
+ Parameters
329
+ ----------
330
+ k : int
331
+ Positive integer
332
+ x : float | numpy.ndarray
333
+ Dimensionless argument. Arrays are handled element-wise.
334
+
335
+ Returns
336
+ -------
337
+ float | numpy.ndarray
338
+ Evaluated expression with the ``x -> 0`` limit patched in.
339
+ """
340
+ y = -x*x*special.kn(2, k*x)/(k*k)
341
+ if(isinstance(x, numpy.ndarray)):
342
+ y[x == 0] = numpy.ones(len(y[x == 0]))*-2.0/k**4
343
+ elif(x == 0):
344
+ return -2.0/k**4
345
+ return y
346
+
347
+
348
+ def dx2K2(k : int, x : float | numpy.ndarray) -> float | numpy.ndarray:
349
+ """Return the first derivative of :func:`x2K2` with respect to ``x``."""
350
+ y = abs(x)
351
+ return numpy.nan_to_num(x*y*special.kn(1,k*y)/k)
352
+
353
+
354
+ def d2x2K2(k : int, x : float | numpy.ndarray) -> float | numpy.ndarray:
355
+ """Return the second derivative of :func:`x2K2` with respect to ``x``."""
356
+ x = abs(x)
357
+ y = numpy.nan_to_num(x*(special.kn(1,k*x)/k - x*special.kn(0,k*x)))
358
+ if(isinstance(x, numpy.ndarray)):
359
+ y[x == 0] = numpy.ones(len(y[x == 0]))*1.0/k**2
360
+ elif(x == 0):
361
+ return 1.0/k**2
362
+ return y
363
+
364
+
365
+ def d3x2K2(k : int, x : float | numpy.ndarray) -> float | numpy.ndarray:
366
+ """Return the third derivative of :func:`x2K2` with respect to ``x``."""
367
+ y = abs(x)
368
+ return numpy.nan_to_num(x*(y*k*special.kn(1,k*y) - 3*special.kn(0,k*y)))
369
+
370
+
371
+ def Jb_high(x : float | numpy.ndarray, deriv=0, n=8) -> float | numpy.ndarray:
372
+ """Jb calculated using the high-x (low-T) expansion."""
373
+ K = (x2K2, dx2K2, d2x2K2, d3x2K2)[deriv]
374
+ y, k = 0.0, 1
375
+ while k <= n:
376
+ y += K(k,x)
377
+ k += 1
378
+ return y
379
+
380
+
381
+ def Jf_high(x : float | numpy.ndarray, deriv=0, n=8) -> float | numpy.ndarray:
382
+ """Jf calculated using the high-x (low-T) expansion."""
383
+ K = (x2K2, dx2K2, d2x2K2, d3x2K2)[deriv]
384
+ y, k, i = 0.0, 1, 1
385
+ while k <= n:
386
+ y += i*K(k,x)
387
+ i *= -1
388
+ k += 1
389
+ return y
390
+
391
+
392
+ # And here are the final functions:
393
+ # Note that if approx = 'spline', the function called is
394
+ # J(theta) (x^2 -> theta so you can get negative mass squared)
395
+ def Jb(x : float | numpy.ndarray, approx : str ='high', deriv : int =0, n : int =8) -> float | numpy.ndarray:
396
+ """
397
+ A shorthand for calling one of the Jb functions above.
398
+
399
+ Parameters
400
+ ----------
401
+ approx : str, optional
402
+ One of 'exact', 'high', 'low', or 'spline'.
403
+ deriv : int, optional
404
+ The order of the derivative (0 for no derivative).
405
+ Must be <= (1, 3, 0, 3) for approx = (exact, high, low, spline).
406
+ n : int, optional
407
+ Number of terms to use in the low and high-T approximations.
408
+ """
409
+ if(approx == 'exact'):
410
+ if(deriv == 0):
411
+ return Jb_exact(x)
412
+ elif(deriv == 1):
413
+ return dJb_exact(x)
414
+ else:
415
+ raise ValueError("For approx=='exact', deriv must be 0 or 1.")
416
+ elif(approx == 'spline'):
417
+ return Jb_spline(x, deriv)
418
+ elif(approx == 'low'):
419
+ if(n > 100):
420
+ raise ValueError("Must have n <= 100")
421
+ if(deriv == 0):
422
+ return Jb_low(x,n)
423
+ else:
424
+ raise ValueError("For approx=='low', deriv must be 0.")
425
+ elif(approx == 'high'):
426
+ if(deriv > 3):
427
+ raise ValueError("For approx=='high', deriv must be 3 or less.")
428
+ else:
429
+ return Jb_high(x, deriv, n)
430
+ raise ValueError("Unexpected value for 'approx'.")
431
+
432
+
433
+ def Jf(x : float | numpy.ndarray, approx : str ='high', deriv : int =0, n : int =8) -> float | numpy.ndarray:
434
+ """
435
+ A shorthand for calling one of the Jf functions above.
436
+
437
+ Parameters
438
+ ----------
439
+ approx : str, optional
440
+ One of 'exact', 'high', 'low', or 'spline'.
441
+ deriv : int, optional
442
+ The order of the derivative (0 for no derivative).
443
+ Must be <= (1, 3, 0, 3) for approx = (exact, high, low, spline).
444
+ n : int, optional
445
+ Number of terms to use in the low and high-T approximations.
446
+ """
447
+ if(approx == 'exact'):
448
+ if(deriv == 0):
449
+ return Jf_exact(x)
450
+ elif(deriv == 1):
451
+ return dJf_exact(x)
452
+ else:
453
+ raise ValueError("For approx=='exact', deriv must be 0 or 1.")
454
+ elif(approx == 'spline'):
455
+ return Jf_spline(x, deriv)
456
+ elif(approx == 'low'):
457
+ if(n > 100):
458
+ raise ValueError("Must have n <= 100")
459
+ if(deriv == 0):
460
+ return Jf_low(x,n)
461
+ else:
462
+ raise ValueError("For approx=='low', deriv must be 0.")
463
+ elif(approx == 'high'):
464
+ if(deriv > 3):
465
+ raise ValueError("For approx=='high', deriv must be 3 or less.")
466
+ else:
467
+ return Jf_high(x, deriv, n)
468
+ raise ValueError("Unexpected value for 'approx'.")