Skip to content

Add IonCollection.build_line_list - #472

Merged
wtbarnes merged 12 commits into
wtbarnes:mainfrom
jacobdparker:line-list
Oct 23, 2026
Merged

wtbarnes merged 12 commits into
wtbarnes:mainfrom
jacobdparker:line-list

Conversation

@jacobdparker

Copy link
Copy Markdown
Collaborator

Closes #464

Adds IonCollection.build_line_list(density, minimum_abundance=0, wavelength_range=None, emission_measure=None, **kwargs), following the mock-up in #464. It loops over the ions in the collection, skips those below the abundance cutoff or with no bound-bound transition in the wavelength range (and, with a warning, those missing the data to compute a contribution function), and returns a QTable with one row per transition.

Columns: element, atomic_number, ion_name (roman), abundance, ionization_potential, wavelength, energy, A, upper_level, lower_level, upper_label, lower_label, is_observed, contribution_function, and intensity when a DEM is given. The contribution_function entry of each row has shape (l, m) over temperature and density, so a row is one line and its G(n, T). kwargs pass through to contribution_function, so couple_density_to_temperature works as usual.

Two choices worth a look:

  • The temperature and density are stored in table.meta rather than as columns, since they are the same for every row. Easy to change if you would rather have them as columns.
  • emission_measure takes the table returned by get_dem_model. The intensity is the sum over the model's temperature bins of em times the contribution function interpolated (in log T) to the bin centers, divided by 4π sr. Bins outside the temperature range of the collection contribute nothing.

Example, seven ions over 550–680 Å with the quiet-Sun DEM at constant pressure, brightest first:

ion_name wavelength upper_label  lower_label  is_observed    intensity
          Angstrom                                        erg / (s sr cm2)
-------- ---------- ------------ ------------ ----------- ----------------
     O V    629.732    2s 2p 1P1      2s2 1S0        True              418
    He I    584.334    1s 2p 1P1      1s2 1S0        True              196
    O IV    554.514 2s 2p2 2P3/2 2s2 2p 2P3/2        True              142
    Mg X    609.793 1s2 2p 2P3/2 1s2 2s 2S1/2        True              104
    O IV    554.076 2s 2p2 2P1/2 2s2 2p 2P1/2        True             55.2
    Mg X    624.941 1s2 2p 2P1/2 1s2 2s 2S1/2        True             51.3
   O III    599.590   2s 2p3 1D2  2s2 2p2 1D2        True             51.2
    O IV    609.830 2s 2p2 2S1/2 2s2 2p 2P3/2        True             44.6

I also checked it against the line-list builder in the MUSE pipeline that #464 links to, run on the same fiasco checkout: four ions over 170–185 Å at two pressures. Same lines in the same order and bit-identical G(n, T), apart from one theoretical Fe X line at exactly 185.0 Å which the inclusive bounds here keep and MUSE's strict bounds drop.

Tests cover the row count and contribution function against Ion.contribution_function, the abundance and wavelength filters, the intensity column with a DEM model, and the error when no ion has lines. The full test_collections.py module passes against the full CHIANTI database.

🤖 Generated with Claude Code

A table of the bound-bound transitions of every ion in a collection, one
row per line, with the contribution function of each line as a function of
temperature and density. Ions can be excluded by a minimum abundance or by
having no line in a wavelength range, and if a DEM model in the form
returned by `get_dem_model` is given the intensity of each line is included.

Closes wtbarnes#464

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jacobdparker

Copy link
Copy Markdown
Collaborator Author

For context on the consumer side: I have rewritten the MUSE pipeline's fiasco_gofnt_linelist on top of this method, on the branch feature/fiasco-line-list in the MUSE repo (https://gitlab.com/LMSAL_HUB/muse_hub/muse/-/tree/feature/fiasco-line-list, commit e93d9bbf). That function is now just grid preparation, building the IonCollection, and reshaping the table into the xarray layout the pipeline expects. On the same fiasco checkout it reproduces the previous MUSE implementation exactly: same lines in the same order and bit-identical G(n, T) for four ions over 170–185 Å at two pressures. The only fields MUSE needed beyond the mock-up in #464 were the level indices, which is why upper_level and lower_level are in the table.

Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/collections.py Resolved
Comment thread fiasco/collections.py Resolved
Comment thread fiasco/collections.py Resolved
Comment thread fiasco/collections.py Resolved
Comment thread fiasco/collections.py Resolved
- One `line_list` fixture and a separate test for each concern
- Document that any kwarg of `contribution_function` passes through,
  and stop listing every column
- No guard on the ionization potential
- `energy` from the level energies rather than the wavelength
- Dataset names, CHIANTI version and fiasco version in `meta`

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SPbZHPLHsKKTtmMueYx5RM

@wtbarnes wtbarnes left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly minor nitpicks around some of the logging in creating the table. Overall, this is great. Thanks for getting this together and sorry it has taken too long to review.

Comment thread fiasco/collections.py Resolved
Comment thread fiasco/collections.py Resolved
Comment thread fiasco/collections.py Resolved
Comment thread changelog/472.feature.rst Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Ions dropped by `minimum_abundance` or `wavelength_range` are now logged at
info level, with a test. Comments explain how the dataset names in `meta` are
collected and why H II never appears in the line list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@wtbarnes wtbarnes left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, realized at the last minute I prefer more human-readable column names. Since they are not variables themselves, no need for them to be underscored.

Comment thread fiasco/collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
Comment thread fiasco/tests/test_collections.py Resolved
@wtbarnes
wtbarnes merged commit a3445e0 into wtbarnes:main Oct 23, 2026
19 checks passed
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.

Add convenience method to IonCollection for generating a line list

2 participants