Skip to content

[WIP] Add Multigrid support - #788

Open
erwanp wants to merge 1 commit into
radis:developfrom
erwanp:add/multigrid
Open

[WIP] Add Multigrid support #788
erwanp wants to merge 1 commit into
radis:developfrom
erwanp:add/multigrid

Conversation

@erwanp

@erwanp erwanp commented Mar 29, 2025

Copy link
Copy Markdown
Member

New clean implementation of #606

Multigrid support in RADIS

tl;dr

  • First proof-of-concept of multiple wavenumber grids (different wstep) without DIT (optimisation=None) & regular grid output : 4x speed-up in CO HITRAN example
  • Some accuracy issues at the junction between grids needs to be fixed
  • Same with irregular grid output (saves memory and shall be even faster than the regular grid)
  • First proof-of-concept of multiple wavenumber grids with [sparse or not] DIT/DCS (optimization=simple)
  • add non-equilibrium version
  • Refactor all code using proper parameters (for instance, remove self._multisparsegrid and other hidden variables)
  • Optimize the (wstep, truncation) parameters of each grid (and the number of grids. Maybe 2 are enough)
  • add compiled (Cython/numba) versions of legacy convolve & aggregate method (optimization=None)
  • Make sure it works with neigbour-lines>0

This will be particularly useful for "isolated-lines" spectra, i.e. :

👉 Combined with DIT (for "dense spectra") and sparse-DIT (for "dense-by-part spectra") it should make RADIS the ultimate, fastest code for every kind of spectra.


Other changes:

  • do not generate all spectral quantities by-default . Only abscoeff is computed. Saves 1-2s on very large spectra.
  • vectorize get_overlapping_ranges

(nice)

  • re-add a PRECOMPUTE_ALL_QUANTITIES parameter to disallow the calculation of other-than-abscoeff parametesr erwanp@47bc348
  • re-add 2nd axis behavior erwanp@307feb2

Old Benchmark in #606

Case 1. Full-range calculations, low number of lines

1.1 With Optimization=None (no LDM) (HITRAN) : x4

CO-HITRAN, 500 - 10,000 cm-1

Code : see at the bottom


  • From afar, we get a good accuracy and 4x speed-up in this example (Fig 0.)

image

Here are the performance details :

s_single.print_perf_profile()
1 grid : 4.1s profiler :
    spectrum_calculation      4.210s ████████████████
        check_line_databank              0.000s 
        reinitialize                     0.002s 
            copy_database                    0.000s 
            memory_usage_warning             0.002s 
            reset_population                 0.000s 
        scaled_eq_linestrength           0.003s 
        applied_linestrength_cutoff      0.001s 
        calc_lineshift                   0.001s 
        calc_hwhm                        0.005s 
        generate_wavenumber_arrays       0.012s 
        calc_line_broadening             3.830s ██████████████
            init_vectors                     0.090s 
            voigt_broadening                 3.317s ████████████
            init_vectors_apply               0.059s 
            get_matching_line                0.000s 
            aggregate__lines                 0.300s █
            others                           0.063s 
        calc_other_spectral_quan         0.267s █
        generate_spectrum_obj            0.073s 
        others                           0.079s 
s_multi.print_perf_profile()
Multi grid : 1.1s profiler :
    spectrum_calculation      1.183s ████████████████
        check_line_databank              0.000s 
        reinitialize                     0.002s 
            copy_database                    0.000s 
            memory_usage_warning             0.002s 
            reset_population                 0.000s 
        scaled_eq_linestrength           0.002s 
        applied_linestrength_cutoff      0.002s 
        calc_lineshift                   0.001s 
        calc_hwhm                        0.005s 
        generate_wavenumber_arrays       0.037s 
        calc_line_broadening             0.858s ███████████
            init_vectors                      0.098s █
            voigt_broadening                  0.125s █
            init_vectors_apply_multigrid      0.014s 
            get_matching_line_multigrid       0.027s 
            aggregate__lines_multigrid        0.405s █████
            interpolate_multigrids            0.076s █
            others                            0.113s █
        calc_other_spectral_quan         0.209s ██
        generate_spectrum_obj            0.060s 
        others                           0.121s █

We see a x25 speed-up in the Voigt broadening part, and an overall x4 speedup in the full Lineshape broadening step (including aggregation of lines & interpolation of grids).

  • (WIP) Looking up close, there are still some accuracy problems at the junction between the different grids . Working on it !

(Fig.1 13/08/23):
image

  • the different grids for the points above:
    Grids are automatically refined around the line centers . Each grid is regular (i.e. constant wstep) which (will) allow the use of the DIT Algorithm. (Fig 2.)

image

Same, zoomed-out to see the multiple (3) and discontinued (multi-groups) grids (Fig 3.)

image

  • a last image showing the component of the absorption coefficient from each wavenumber grid (Fig 4.) :

image


Code:

import numpy as np

import radis
radis.config["DEBUG_MODE"] = True

from radis import calc_spectrum
s, sf = calc_spectrum(
                # wavenum_min=3800,
                wavenum_min=500,
                # wavenum_max=4500,
                wavenum_max=10000,
                Tgas=300,
                path_length=0.1,
                molecule='CO',
                mole_fraction=0.2,
                isotope=1,
                pressure=1e-5,
                wstep=0.004,
                databank='hitran'  , # or 'hitemp'
                optimization=None,  
                # also measure interpolation time
                return_factory=True,
                save_memory=False,
                )
self = sf

#%%

# #Test:
import matplotlib.pyplot as plt 


# %%  
# keep only few lines
# sf.df0= sf.df0.iloc[150:153]
# keep only so many lines
# sf.df0 = sf.df0.iloc[np.arange(len(sf.df0))[::10]]

#%% 


# NOW compute a Spectrum
import radis
radis.config["MULTI_SPARSE_GRID"] = False
s_single = sf.eq_spectrum(700)
s_single.plot('abscoeff', yscale='log', lw=4, nfig=10)


# %%

# NOW compute a Spectrum
import radis
radis.config["MULTI_SPARSE_GRID"] = True
s_multi = sf.eq_spectrum(700)


s_multi.plot('abscoeff', yscale='log', nfig=10, lw=2)

# %% Plot the graphs


from radis.lbl.factory import _generate_wavenumber_range_sparse
wstep_calc_narrow = self.params.wstep
truncation = self.params.truncation
neighbour_lines = self.params.neighbour_lines

plt.figure()
plt.xlabel("Wavenumber (cm-1)")
plt.ylabel("Wstep")
plt.yscale("log")
wavenumber_arrays = []

for i, (wstep, lineshape_half_width) in enumerate(zip(self._wstep_multigrid, 
                                                      self._truncation_multigrid)):
    print("wstep", wstep)
    print("lineshape_half_width", lineshape_half_width)
    (
        wavenumber,
        wavenumber_calc,
        woutrange,
        ix_ranges,
    ) = _generate_wavenumber_range_sparse(
        self.input.wavenum_min,
        self.input.wavenum_max,
        wstep,
        neighbour_lines,
        self.df1.wav,
        lineshape_half_width,
    )    
    wavenumber_arrays.append(wavenumber)
    
    from publib import keep_color
    for wavenumber_group in wavenumber: # iterate over all wavenumber groups : 
        plt.plot(wavenumber_group, np.ones_like(wavenumber_group)*wstep, "-o", ms=3)
        if wavenumber_group[-1] != wavenumber[-1][-1]: # not the last element : 
            keep_color()
    # Plot line centers :
    for line in self.df1.wav:
        plt.axvline(line,color='k', alpha=0.05, zorder=-1)
plt.title("3 grids & Line centers\n")



# %% plot diff
s_multi.name = f"Multi grid : {s_multi.c['calculation_time']:.1f}s"
s.name = f"{s.c['calculation_time']:.1f}s"
s_single.name = f"1 grid : {s_single.c['calculation_time']:.1f}s"

from radis import plot_diff
plot_diff(s_single, s_multi, "abscoeff", yscale="log", method="diff")

1.2 With Sparse LDM (HITRAN) : x4

@dcmvdbekerom same calculations with LDM now : x6 speed-up ; and x10 if looking only at the line broadening part (Fig 5.)

image

Code : same as above, with the following changes:

radis.config["SPARSE_WAVERANGE"] = True
(...)

s, sf = calc_spectrum( ...
                optimization="simple")
sf.params.broadening_method = "voigt"
s_single.print_perf_profile()
1 grid, LDM : 3.4s profiler :
    spectrum_calculation      3.423s ████████████████
        check_line_databank              0.000s 
        reinitialize                     0.002s 
            copy_database                    0.000s 
            memory_usage_warning             0.001s 
            reset_population                 0.000s 
        scaled_eq_linestrength           0.003s 
        applied_linestrength_cutoff      0.002s 
        calc_lineshift                   0.002s 
        calc_hwhm                        0.004s 
        generate_wavenumber_arrays       0.012s 
        calc_line_broadening             3.148s ██████████████
            precompute_LDM_lineshapes        1.224s █████
            LDM_Initialized_vectors          0.000s 
            LDM_closest_matching_line        0.009s 
            LDM_Distribute_lines             1.484s ██████
            LDM_convolve                     0.427s █
            others                           0.006s 
        calc_other_spectral_quan         0.185s 
        generate_spectrum_obj            0.053s 
        others                           0.017s 
s_multi.print_perf_profile()
Multi grid, LDM : 0.6s profiler :
    spectrum_calculation      0.641s ████████████████
        check_line_databank              0.000s 
        reinitialize                     0.002s 
            copy_database                    0.000s 
            memory_usage_warning             0.001s 
            reset_population                 0.000s 
        scaled_eq_linestrength           0.003s 
        applied_linestrength_cutoff      0.002s 
        calc_lineshift                   0.001s 
        calc_hwhm                        0.005s 
        generate_wavenumber_arrays       0.026s 
        calc_line_broadening             0.326s ████████
            precompute_LDM_lineshapes        0.039s 
            LDM_Initialized_vectors          0.001s 
            LDM_closest_matching_line        0.002s 
            LDM_Distribute_lines             0.108s ██
            LDM_convolve                     0.049s █
            interpolate_multigrids           0.125s ███
            others                           0.002s 
        calc_other_spectral_quan         0.206s █████
        generate_spectrum_obj            0.059s █
        others                           0.015s 

  • still a few accuracy problems, will be fixed later !

1.3 With Sparse LDM (HITEMP) : x4

Note : the example above was ran with CO HITRAN, with limited number of lines. For CO HITEMP below we see that the multigrid accelerates the LDM_convolve step, but does not change the LDM_Distribute_lines step (obviously)

s, sf = calc_spectrum(...
                databank='hitemp'  , 
                ) 
# ... 
s_single.print_perf_profile()
1 grid, LDM : 9.0s profiler :
    spectrum_calculation      9.040s ████████████████
        check_line_databank             0.000s 
        reinitialize                    0.003s 
            copy_database                   0.002s 
            memory_usage_warning            0.001s 
            reset_population                0.000s 
        scaled_eq_linestrength          0.004s 
        calc_lineshift                  0.006s 
        calc_hwhm                       0.013s 
        generate_wavenumber_arrays      0.011s 
        calc_line_broadening            8.750s ███████████████
            precompute_LDM_lineshapes       2.259s ███
            LDM_Initialized_vectors         0.000s 
            LDM_closest_matching_line       0.037s 
            LDM_Distribute_lines            3.857s ██████
            LDM_convolve                    2.551s ████
            others                          0.047s 
        calc_other_spectral_quan        0.186s 
        generate_spectrum_obj           0.055s 
        others                          0.057s 
s_multi.print_perf_profile()
Multi grid, LDM : 5.0s profiler :
    spectrum_calculation      5.039s ████████████████
        check_line_databank             0.000s 
        reinitialize                    0.003s 
            copy_database                   0.002s 
            memory_usage_warning            0.001s 
            reset_population                0.000s 
        scaled_eq_linestrength          0.004s 
        calc_lineshift                  0.007s 
        calc_hwhm                       0.014s 
        generate_wavenumber_arrays      0.151s 
        calc_line_broadening            4.603s ██████████████
            precompute_LDM_lineshapes       0.079s 
            LDM_Initialized_vectors         0.017s 
            LDM_closest_matching_line       0.045s 
            LDM_Distribute_lines            3.581s ███████████
            LDM_convolve                    0.697s ██
            interpolate_multigrids          0.148s 
            others                          0.035s 
        calc_other_spectral_quan        0.184s 
        generate_spectrum_obj           0.053s 
        others                          0.054s 

1.4 With (non-sparse) LDM (HITEMP) : x4

CO HITEMP version (same as above)

1 grid, LDM : 229.1s profiler :
    spectrum_calculation      229.241s ████████████████
        check_line_databank             0.043s 
        reinitialize                    0.105s 
            copy_database                   0.049s 
            memory_usage_warning            0.056s 
            reset_population                0.000s 
        scaled_eq_linestrength          0.036s 
        calc_lineshift                  0.022s 
        calc_hwhm                       0.043s 
        generate_wavenumber_arrays      0.023s 
        calc_line_broadening            228.314s ███████████████
            precompute_LDM_lineshapes       2.570s 
            LDM_Initialized_vectors         0.000s 
            LDM_closest_matching_line       0.041s 
            LDM_Distribute_lines            0.714s 
            LDM_convolve                    222.757s ███████████████
            others                          2.232s 
        calc_other_spectral_quan        0.500s 
        generate_spectrum_obj           0.096s 
        others                          2.290s 
Multi grid, LDM : 56.5s profiler :
    spectrum_calculation      56.593s ████████████████
        check_line_databank             0.004s 
        reinitialize                    0.081s 
            copy_database                   0.053s 
            memory_usage_warning            0.028s 
            reset_population                0.000s 
        scaled_eq_linestrength          0.026s 
        calc_lineshift                  0.034s 
        calc_hwhm                       0.039s 
        generate_wavenumber_arrays      0.694s 
        calc_line_broadening            55.458s ███████████████
            precompute_LDM_lineshapes         9.239s ██
            LDM_Initialized_vectors           0.050s 
            LDM_closest_matching_line         0.320s 
            LDM_Distribute_lines              0.471s 
            LDM_convolve                      43.955s ████████████
            interpolate_multisparsegrids      0.218s 
            others                            1.204s 
        calc_other_spectral_quan        0.189s 
        generate_spectrum_obj           0.058s 
        others                          1.215s 

Acceleration by a factor of 5 (but non-sparse LDM is still very slow for such a large range)


Case 2 (Appendix) - Adaptative grid in worse conditions

2.1 (non-sparse) LDM in dense regions : x1

Adaptative grid is developed for isolated-lines spectra. Below we deal with a very dense spectral region, i.E. the 4.2 µm (2300 cm-1) band of CO2

import radis
radis.config["SPARSE_WAVERANGE"] = False

# First calculation also makes sure everything is properly calculated & cached
from radis import calc_spectrum
s, sf = calc_spectrum(
                wavenum_min=1700,
                wavenum_max=2500,
                Tgas=2000,
                cutoff=0,
                path_length=0.1,
                molecule='CO2',
                isotope="all",
                pressure=1e-5,
                wstep=0.004,
                databank='hitemp'  , 
                optimization="simple",
                return_factory=True,
                save_memory=False,
                warnings={"AccuracyError":"ignore"}
                )
self = sf
self.params.broadening_method = "voigt"

#%%
# NOW compute Spectra
radis.config["MULTI_SPARSE_GRID"] = False
s_single = sf.eq_spectrum(2000)

# NOW compute a Spectrum
radis.config["MULTI_SPARSE_GRID"] = True
s_multi = sf.eq_spectrum(2000)


# %% plot diff
s_multi.name = f"Multi grid, LDM : {s_multi.c['calculation_time']:.1f}s"
s.name = f"{s.c['calculation_time']:.1f}s"
s_single.name = f"1 grid, LDM : {s_single.c['calculation_time']:.1f}s"
from radis import plot_diff
plot_diff(s_single, s_multi, "abscoeff", yscale="log", method="diff")

#%%
s_single.print_perf_profile()
s_multi.print_perf_profile()

image

Adaptative grid doesn't accelerate the calculations, but it doesn't slow it down neither

1 grid, LDM : 5.8s profiler :
    spectrum_calculation      5.854s ████████████████
        check_line_databank             0.002s 
        reinitialize                    0.082s 
            copy_database                   0.080s 
            memory_usage_warning            0.002s 
            reset_population                0.000s 
        scaled_eq_linestrength          0.209s 
        calc_lineshift                  0.264s 
        calc_hwhm                       0.467s █
        generate_wavenumber_arrays      0.005s 
        calc_line_broadening            4.776s █████████████
            precompute_LDM_lineshapes       0.627s █
            LDM_Initialized_vectors         0.000s 
            LDM_closest_matching_line       0.321s 
            LDM_Distribute_lines            0.247s 
            LDM_convolve                    3.528s █████████
            others                          0.052s 
        calc_other_spectral_quan        0.025s 
        generate_spectrum_obj           0.014s 
        others                          0.061s 
Multi grid, LDM : 5.5s profiler :
    spectrum_calculation      5.522s ████████████████
        check_line_databank             0.003s 
        reinitialize                    0.102s 
            copy_database                   0.099s 
            memory_usage_warning            0.003s 
            reset_population                0.000s 
        scaled_eq_linestrength          0.246s 
        calc_lineshift                  0.323s 
        calc_hwhm                       0.465s █
        generate_wavenumber_arrays      0.505s █
        calc_line_broadening            3.837s ███████████
            precompute_LDM_lineshapes         0.086s 
            LDM_Initialized_vectors           0.000s 
            LDM_closest_matching_line         1.046s ███
            LDM_Distribute_lines              0.545s █
            LDM_convolve                      2.027s █████
            interpolate_multisparsegrids      0.020s 
            others                            0.112s 
        calc_other_spectral_quan        0.021s 
        generate_spectrum_obj           0.013s 
        others                          0.119s 

@erwanp erwanp mentioned this pull request Mar 29, 2025
18 tasks
@erwanp erwanp added this to the 0.17 milestone Apr 6, 2025
@minouHub minouHub modified the milestones: 0.17, 0.18 Mar 7, 2026
@github-actions github-actions Bot added the inactive-notice Inactivity notice posted label May 25, 2026
@github-actions

Copy link
Copy Markdown

⚠️ Inactivity Notice

This pull request has been inactive for 60 days. To keep the project's workflow efficient, it may be closed by an admin if no further updates (commits, comments, or reviews) are made soon.

If you're still working on this:

  • Push new commits or address feedback.
  • Leave a comment with an update or timeline.

If this PR is no longer needed, feel free to close it yourself. Thanks for your contribution!

@github-actions github-actions Bot removed the inactive-notice Inactivity notice posted label Jun 1, 2026
@github-actions github-actions Bot added the inactive-notice Inactivity notice posted label Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ Inactivity Notice

This pull request has been inactive for 60 days. To keep the project's workflow efficient, it may be closed by an admin if no further updates (commits, comments, or reviews) are made soon.

If you're still working on this:

  • Push new commits or address feedback.
  • Leave a comment with an update or timeline.

If this PR is no longer needed, feel free to close it yourself. Thanks for your contribution!

@github-actions github-actions Bot removed the inactive-notice Inactivity notice posted label Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants