[e6f1410] | 1 | r""" |
---|
| 2 | Show numerical precision of $2 J_1(x)/x$. |
---|
| 3 | """ |
---|
| 4 | |
---|
| 5 | import numpy as np |
---|
| 6 | from sympy.mpmath import mp |
---|
| 7 | #import matplotlib; matplotlib.use('TkAgg') |
---|
| 8 | import pylab |
---|
| 9 | |
---|
| 10 | |
---|
[cbd37a7] | 11 | SHOW_DIFF = True # True if show diff rather than function value |
---|
| 12 | #SHOW_DIFF = False # True if show diff rather than function value |
---|
[e6f1410] | 13 | LINEAR_X = False # True if q is linearly spaced instead of log spaced |
---|
[cbd37a7] | 14 | #LINEAR_X = True # True if q is linearly spaced instead of log spaced |
---|
| 15 | FUNCTION = "2*J1(x)/x" |
---|
[e6f1410] | 16 | |
---|
[cbd37a7] | 17 | def mp_fn(vec, bits=500): |
---|
[e6f1410] | 18 | """ |
---|
| 19 | Direct calculation using sympy multiprecision library. |
---|
| 20 | """ |
---|
[0a6da3c] | 21 | with mp.workprec(bits): |
---|
[cbd37a7] | 22 | return [_mp_fn(mp.mpf(x)) for x in vec] |
---|
[e6f1410] | 23 | |
---|
[cbd37a7] | 24 | def _mp_fn(x): |
---|
[e6f1410] | 25 | """ |
---|
[cbd37a7] | 26 | Actual function that gets evaluated. The caller just vectorizes. |
---|
[e6f1410] | 27 | """ |
---|
| 28 | return mp.mpf(2)*mp.j1(x)/x |
---|
| 29 | |
---|
[cbd37a7] | 30 | def np_fn(x, dtype): |
---|
[e6f1410] | 31 | """ |
---|
| 32 | Direct calculation using scipy. |
---|
| 33 | """ |
---|
[0a6da3c] | 34 | from scipy.special import j1 as J1 |
---|
[e6f1410] | 35 | x = np.asarray(x, dtype) |
---|
[0a6da3c] | 36 | return np.asarray(2, dtype)*J1(x)/x |
---|
[e6f1410] | 37 | |
---|
[cbd37a7] | 38 | def sasmodels_fn(x, dtype, platform='ocl'): |
---|
[e6f1410] | 39 | """ |
---|
| 40 | Calculation using pade approximant. |
---|
| 41 | """ |
---|
[cbd37a7] | 42 | from sasmodels import core, data, direct_model |
---|
| 43 | model = core.load_model('bessel', dtype=dtype) |
---|
| 44 | calculator = direct_model.DirectModel(data.empty_data1D(x), model) |
---|
| 45 | return calculator(background=0) |
---|
[0a6da3c] | 46 | |
---|
[e6f1410] | 47 | def plotdiff(x, target, actual, label): |
---|
| 48 | """ |
---|
| 49 | Plot the computed value. |
---|
| 50 | |
---|
| 51 | Use relative error if SHOW_DIFF, otherwise just plot the value directly. |
---|
| 52 | """ |
---|
| 53 | if SHOW_DIFF: |
---|
[cbd37a7] | 54 | err = abs((target-actual)/target) |
---|
| 55 | #err = np.clip(err, 0, 1) |
---|
[e6f1410] | 56 | pylab.loglog(x, err, '-', label=label) |
---|
| 57 | else: |
---|
| 58 | limits = np.min(target), np.max(target) |
---|
| 59 | pylab.semilogx(x, np.clip(actual,*limits), '-', label=label) |
---|
| 60 | |
---|
[cbd37a7] | 61 | def compare(x, precision, target): |
---|
[e6f1410] | 62 | r""" |
---|
| 63 | Compare the different computation methods using the given precision. |
---|
| 64 | """ |
---|
[cbd37a7] | 65 | #plotdiff(x, target, mp_fn(x, 11), 'mp 11 bits') |
---|
| 66 | plotdiff(x, target, np_fn(x, precision), 'numpy '+precision) |
---|
| 67 | plotdiff(x, target, sasmodels_fn(x, precision, 0), 'sasmodels '+precision) |
---|
[e6f1410] | 68 | pylab.xlabel("qr (1/Ang)") |
---|
| 69 | if SHOW_DIFF: |
---|
| 70 | pylab.ylabel("relative error") |
---|
| 71 | else: |
---|
[cbd37a7] | 72 | pylab.ylabel(FUNCTION) |
---|
[e6f1410] | 73 | pylab.semilogx(x, target, '-', label="true value") |
---|
| 74 | if LINEAR_X: |
---|
| 75 | pylab.xscale('linear') |
---|
| 76 | |
---|
| 77 | def main(): |
---|
| 78 | r""" |
---|
| 79 | Compare accuracy of different methods for computing $3 j_1(x)/x$. |
---|
| 80 | :return: |
---|
| 81 | """ |
---|
| 82 | if LINEAR_X: |
---|
| 83 | qr = np.linspace(1,1000,2000) |
---|
| 84 | else: |
---|
| 85 | qr = np.logspace(-3,5,400) |
---|
[cbd37a7] | 86 | target = np.asarray(mp_fn(qr), 'double') |
---|
[e6f1410] | 87 | pylab.subplot(121) |
---|
[cbd37a7] | 88 | compare(qr, 'single', target) |
---|
[e6f1410] | 89 | pylab.legend(loc='best') |
---|
| 90 | pylab.subplot(122) |
---|
[cbd37a7] | 91 | compare(qr, 'double', target) |
---|
[e6f1410] | 92 | pylab.legend(loc='best') |
---|
[cbd37a7] | 93 | pylab.suptitle(FUNCTION) |
---|
[e6f1410] | 94 | |
---|
| 95 | if __name__ == "__main__": |
---|
[0a6da3c] | 96 | #print "\n".join(str(x) for x in mp_J1c([1e-6,1e-5,1e-4,1e-3])) |
---|
[e6f1410] | 97 | main() |
---|
| 98 | pylab.show() |
---|