sunpy / sunkit-spex

:construction: Under Development :construction: A package for solar X-ray spectroscopy
BSD 3-Clause "New" or "Revised" License
22 stars 26 forks source link

Thick/thin-target bremsstrahlung integrals are slow #60

Open elastufka opened 2 years ago

elastufka commented 2 years ago

Describe the performance issue

Making the functions _emission.integratepart and _emission.split_andintegrate more pythonic only improve readability and not performance.

To Reproduce

from sunxspex import emission

p,q, eebrk, eelow, eehigh=4.0,6.0,150.0,20.0,3200.0
photon_energies=np.linspace(4,5000,8000)
z=1.2
maxfcn=2048
rerr=1e-4

%%timeit
thick_new,_=emission.split_and_integrate(model='thick-target', photon_energies=photon_energies, maxfcn=maxfcn, rerr=rerr,eelow=eelow, eebrk=eebrk, eehigh=eehigh,p=p, q=q, z=z, efd=False)

%%timeit
thick_original,_=emission.split_and_integrate0(model='thick-target', photon_energies=photon_energies, maxfcn=maxfcn, rerr=rerr,eelow=eelow, eebrk=eebrk, eehigh=eehigh,p=p, q=q, z=z, efd=False)

Proposed fix

I'll order these roughly by the amount of time (increasing) it would take [me] to try each approach. For reference, the integral is here and the equation for the bremsstrahlung cross-section is here.

elastufka commented 2 years ago

Short update:

samaloney commented 2 years ago

Great I think the main thing from my side is to not tie the package down to anyone of these instead allow them all through an API. Also adding new dependencies needs careful consideration in terms of future support etc.

So I'd suggest focusing on refactoring the current code into a function with similar api to scipy e.g. GuassLegendre(func, **kwargs) before starting to implement new methods.

ianan commented 2 years ago

Is the speed up here being tested just in calculating the model or also as part of the fitting?

As some of these approaches (multi-threaded and maybe PyTorch?) might speed up the integrals in isolation but when they are included as part of the fitting it might not actually help as other parts of the code are also using them (i.e. multi-thread already done by default in numpy matrix multiply with the srm? or the mcmc runs?).

elastufka commented 2 years ago

Right now just in calculating the model.

The slowest part of the model evaluation is the bremsstrahlung cross-section calculation:

1601 function calls (1573 primitive calls) in 0.033 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       38    0.000    0.000    0.000    0.000 constants.py:56(get_constant)
        6    0.003    0.000    0.004    0.001 emission.py:128(density)
        6    0.001    0.000    0.001    0.000 emission.py:166(collisional_loss)
        6    0.012    0.002    0.012    0.002 emission.py:197(bremsstrahlung_cross_section)
        6    0.003    0.000    0.032    0.005 emission.py:286(gauss_legendre_idl)
        6    0.004    0.001    0.005    0.001 emission.py:379(points_and_weights_idl)
        2    0.001    0.000    0.032    0.016 emission.py:438(integrate_part)
        6    0.005    0.001    0.023    0.004 emission.py:506(model_func)
        1    0.000    0.000    0.033    0.033 emission.py:548(split_and_integrate)
        6    0.000    0.000    0.000    0.000 emission.py:69(__init__)

Torch makes things slower due to overhead when initializing tensors. It could be useful for fitting with fixed-point quadrature rather than increasing the number of points until a relative error condition is met, because it wouldn't duplicate calculations. But otherwise it's way too slow even on a GPU unless you have 10^5 photon energies or so.

I might check on the accuracy of using a different (non-iterative) way of doing the integral, such as Simpson's rule.

ianan commented 2 years ago

Fair enough - sadly no magic solution. Probably needs the C to do a fast and accurate integral.