123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- """
- Convergence regions of the expansions used in ``struve.c``
- Note that for v >> z both functions tend rapidly to 0,
- and for v << -z, they tend to infinity.
- The floating-point functions over/underflow in the lower left and right
- corners of the figure.
- Figure legend
- =============
- Red region
- Power series is close (1e-12) to the mpmath result
- Blue region
- Asymptotic series is close to the mpmath result
- Green region
- Bessel series is close to the mpmath result
- Dotted colored lines
- Boundaries of the regions
- Solid colored lines
- Boundaries estimated by the routine itself. These will be used
- for determining which of the results to use.
- Black dashed line
- The line z = 0.7*|v| + 12
- """
- import numpy as np
- import matplotlib.pyplot as plt
- import mpmath
- def err_metric(a, b, atol=1e-290):
- m = abs(a - b) / (atol + abs(b))
- m[np.isinf(b) & (a == b)] = 0
- return m
- def do_plot(is_h=True):
- from scipy.special._ufuncs import (_struve_power_series,
- _struve_asymp_large_z,
- _struve_bessel_series)
- vs = np.linspace(-1000, 1000, 91)
- zs = np.sort(np.r_[1e-5, 1.0, np.linspace(0, 700, 91)[1:]])
- rp = _struve_power_series(vs[:,None], zs[None,:], is_h)
- ra = _struve_asymp_large_z(vs[:,None], zs[None,:], is_h)
- rb = _struve_bessel_series(vs[:,None], zs[None,:], is_h)
- mpmath.mp.dps = 50
- if is_h:
- sh = lambda v, z: float(mpmath.struveh(mpmath.mpf(v), mpmath.mpf(z)))
- else:
- sh = lambda v, z: float(mpmath.struvel(mpmath.mpf(v), mpmath.mpf(z)))
- ex = np.vectorize(sh, otypes='d')(vs[:,None], zs[None,:])
- err_a = err_metric(ra[0], ex) + 1e-300
- err_p = err_metric(rp[0], ex) + 1e-300
- err_b = err_metric(rb[0], ex) + 1e-300
- err_est_a = abs(ra[1]/ra[0])
- err_est_p = abs(rp[1]/rp[0])
- err_est_b = abs(rb[1]/rb[0])
- z_cutoff = 0.7*abs(vs) + 12
- levels = [-1000, -12]
- plt.cla()
- plt.hold(1)
- plt.contourf(vs, zs, np.log10(err_p).T, levels=levels, colors=['r', 'r'], alpha=0.1)
- plt.contourf(vs, zs, np.log10(err_a).T, levels=levels, colors=['b', 'b'], alpha=0.1)
- plt.contourf(vs, zs, np.log10(err_b).T, levels=levels, colors=['g', 'g'], alpha=0.1)
- plt.contour(vs, zs, np.log10(err_p).T, levels=levels, colors=['r', 'r'], linestyles=[':', ':'])
- plt.contour(vs, zs, np.log10(err_a).T, levels=levels, colors=['b', 'b'], linestyles=[':', ':'])
- plt.contour(vs, zs, np.log10(err_b).T, levels=levels, colors=['g', 'g'], linestyles=[':', ':'])
- lp = plt.contour(vs, zs, np.log10(err_est_p).T, levels=levels, colors=['r', 'r'], linestyles=['-', '-'])
- la = plt.contour(vs, zs, np.log10(err_est_a).T, levels=levels, colors=['b', 'b'], linestyles=['-', '-'])
- lb = plt.contour(vs, zs, np.log10(err_est_b).T, levels=levels, colors=['g', 'g'], linestyles=['-', '-'])
- plt.clabel(lp, fmt={-1000: 'P', -12: 'P'})
- plt.clabel(la, fmt={-1000: 'A', -12: 'A'})
- plt.clabel(lb, fmt={-1000: 'B', -12: 'B'})
- plt.plot(vs, z_cutoff, 'k--')
- plt.xlim(vs.min(), vs.max())
- plt.ylim(zs.min(), zs.max())
- plt.xlabel('v')
- plt.ylabel('z')
- def main():
- plt.clf()
- plt.subplot(121)
- do_plot(True)
- plt.title('Struve H')
- plt.subplot(122)
- do_plot(False)
- plt.title('Struve L')
- plt.savefig('struve_convergence.png')
- plt.show()
- if __name__ == "__main__":
- main()
|