Skip to content

Modify ion.n_levels#426

Merged
wtbarnes merged 21 commits intomainfrom
bug/n-levels
Feb 10, 2026
Merged

Modify ion.n_levels#426
wtbarnes merged 21 commits intomainfrom
bug/n-levels

Conversation

@jacobdparker
Copy link
Collaborator

@jacobdparker jacobdparker commented Jan 8, 2026

Fixes #425
Fixes #345

The main purpose of this PR is to fix the definition of the number of levels used by the CHIANTI atomic model. Previously, it was assumed that this was just equal to the number of energy levels in the elvlc file. However, this logic fails in certain cases (e.g. N IV) where there are not radiative decay rates available for all levels given in the elvlc file.

As such, the number of levels is now calculated as the minimum across the highest level available in the elvlc, wgfa, and scups files. This ensures that there is enough information to fully describe the atomic model. This is consistent with what is done in CHIANTI IDL. There is an additional correction if auto files are present to ensure that a sufficient number of levels are included to capture the autoionization rates.

As part of this refactor, the number of transitions in Ion.transitions is now truncated to include only those transitions between levels in the atomic model. Ion.levels still includes all information in the elvlc file, i.e. even those levels which are not included in the atomic model.

This also includes a minor fix to the two-photon calculation which takes advantage of the label/configuration properties added in #427.

Other misc. changes:

  • Added all auto files to test database to ensure the number of levels is always calculated appropriately.
  • The two-photon continuum comparison now uses the single-ion model to avoid memory consumption limits on RtD. This has no impact on the two-photon calculation itself.
  • Several of the other gallery examples are also adjusted to avoid hitting RtD memory limits
  • Ruff configuration moved to separate file (from pyproject.toml)

…evels are described in the database than are populated in the model
@jacobdparker jacobdparker requested a review from wtbarnes January 8, 2026 00:48
@wtbarnes
Copy link
Owner

wtbarnes commented Jan 8, 2026

I find this logic a bit confusing. Is it not sufficient to just take the min between n_levels_elvlc and both the max level from the wgfa file and the max level from the scups file?

@wtbarnes
Copy link
Owner

wtbarnes commented Jan 8, 2026

Two additional requests:

  1. Could you also add a test using "N 4" that checks that n_levels correctly returns the maximum number of levels in the wgfa file and not the number of levels in the elvlc file?
  2. Could you add a note in the docstring saying that this property may not necessarily be equal to the number of levels in the elvlc file?

@jacobdparker
Copy link
Collaborator Author

jacobdparker commented Jan 8, 2026

I took the max between n_levels_scups and n_levels_wgfa assuming that if at least one file refered to an energy level, it should be included in the model. This only really matters for Ar 18, where if you took the minimum, level 25 would be excluded. Maybe it should be ...

I find two cases (updated from original post) where n_levels_elvlc is > n_levels_scups and n_levels_wgfa:

N 4
n_levels_elvlc=238
n_levels_wgfa=np.int64(136)
n_levels_scups=np.int64(136)

Ar 6
n_levels_elvlc=202
n_levels_wgfa=np.int64(155)
n_levels_scups=np.int64(155)

I find one case where n_levels_scups > n_levels_wgfa:
Ar 18
n_levels_elvlc=25
n_levels_wgfa=np.int64(24)
n_levels_scups=np.int64(25)

And a few cases where there is now scups or wgfa file:
Ti 22
n_levels_elvlc=64
n_levels_wgfa=0
n_levels_scups=0

Cr 24
n_levels_elvlc=64
n_levels_wgfa=0
n_levels_scups=0

Zn 30
n_levels_elvlc=64
n_levels_wgfa=0
n_levels_scups=0

@wtbarnes
Copy link
Owner

wtbarnes commented Jan 8, 2026

The cases where there are no scups or wgfa files are fine. In those cases, there is effectively no model and so you can't compute a contribution function anyway.

@wtbarnes
Copy link
Owner

Ok I'm now confused again about what the logic behind choosing the number of levels for the model is. This is what is in the IDL code:

https://github.com/chianti-atomic/chianti-idl/blob/121fd3caa160622ef08e1b9d13d3f930a76e1cfc/level_population/ch_load_ion_rates.pro#L308-L313

which is consistent with what we wrote above except for the inclusion of the autoionization rates. I think this is included to make sure that in the case of the two-ion model, those rates don't get cut off.

In practice, I don't find any ions where the max scups level is less than the autoionizing levels and the max autoionizing level isn't also equal to the max elvlc or wgfa level. In other words, However, I'm guessing we should still safeguard against this possibility and just implement the IDL logic here.

I'll push a commit to make this change.

@wtbarnes wtbarnes added the Run v8 tests Run the test suite using CHIANTI database version 8 label Jan 26, 2026
@wtbarnes
Copy link
Owner

wtbarnes commented Jan 27, 2026

Oh no. Something has gone horribly wrong. The example gallery is failing because not enough levels are getting included to account for the necessary rates.

The contribution function example works fine locally. I think this may be due to the fact that some of the auto files are missing from the database and so the model was truncated.

@wtbarnes
Copy link
Owner

Ok the Ar XVIII case you flagged earlier is now the latest problem.

By the logic that is now implemented, the number of levels in the model can be less than the number of levels in the scups. In v11, this happens in the case of Ar XVIII. Because the rate matrix is not big enough to include the 25th level, when it tries to add that rate it throws an IndexError.

I'm not quite sure how to deal with this yet.

@wtbarnes
Copy link
Owner

I went through and did some additional checks on the number of levels included in each ion. Here are some useful findings broken down by ion and version:

v8.0.7
==============================

Ions with more scups levels than all other levels
-------------------------------------------------
N-like N I has n_scups=50 > n_levels=47
H-like Ar XVIII has n_scups=25 > n_levels=24

Ions with more auto levels than scups levels
--------------------------------------------


v9.0.1
==============================

Ions with more scups levels than all other levels
-------------------------------------------------
N-like N I has n_scups=50 > n_levels=47
H-like Ar XVIII has n_scups=25 > n_levels=24

Ions with more auto levels than scups levels
--------------------------------------------
Li-like C IV has n_auto=923 > n_scups=331 (n_elvlc=923, n_wgfa=923)
Li-like N V has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
Li-like O VI has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
Li-like Ne VIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Mg X has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Al XI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Si XII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like S XIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Ar XVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Ca XVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Fe XXIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Ni XXVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
Li-like Zn XXVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)


v10.0.2
==============================

Ions with more scups levels than all other levels
-------------------------------------------------
N-like N I has n_scups=50 > n_levels=47
H-like Ar XVIII has n_scups=25 > n_levels=24

Ions with more auto levels than scups levels
--------------------------------------------
Li-like C IV has n_auto=923 > n_scups=331 (n_elvlc=923, n_wgfa=923)
He-like C V has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like N V has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
He-like N VI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like O VI has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
He-like O VII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ne VIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ne IX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Mg X has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Mg XI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Al XI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Al XII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Si XII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Si XIII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like S XIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like S XV has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ar XVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ar XVII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ca XVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ca XIX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
He-like Ti XXI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
He-like Cr XXIII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Fe XXIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Fe XXV has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ni XXVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ni XXVII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Zn XXVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Zn XXIX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)


v10.1
==============================

Ions with more scups levels than all other levels
-------------------------------------------------
N-like N I has n_scups=50 > n_levels=47
H-like Ar XVIII has n_scups=25 > n_levels=24

Ions with more auto levels than scups levels
--------------------------------------------
Li-like C IV has n_auto=923 > n_scups=331 (n_elvlc=923, n_wgfa=923)
He-like C V has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like N V has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
He-like N VI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like O VI has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
He-like O VII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ne VIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ne IX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Mg X has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Mg XI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Al XI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Al XII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Si XII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Si XIII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like S XIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like S XV has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ar XVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ar XVII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ca XVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ca XIX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
He-like Ti XXI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
He-like Cr XXIII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Fe XXIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Fe XXV has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ni XXVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ni XXVII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Zn XXVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Zn XXIX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)


v11.0.2
==============================

Ions with more scups levels than all other levels
-------------------------------------------------
H-like Ar XVIII has n_scups=25 > n_levels=24

Ions with more auto levels than scups levels
--------------------------------------------
Li-like C IV has n_auto=923 > n_scups=331 (n_elvlc=923, n_wgfa=923)
He-like C V has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like N V has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
He-like N VI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like O VI has n_auto=923 > n_scups=268 (n_elvlc=923, n_wgfa=923)
He-like O VII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ne VIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ne IX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Mg X has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Mg XI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Al XI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Al XII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Si XII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Si XIII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like S XIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like S XV has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ar XVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ar XVII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ca XVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ca XIX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
He-like Ti XXI has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
He-like Cr XXIII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Fe XXIV has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Fe XXV has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Ni XXVI has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Ni XXVII has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)
Li-like Zn XXVIII has n_auto=923 > n_scups=243 (n_elvlc=923, n_wgfa=923)
He-like Zn XXIX has n_auto=577 > n_scups=49 (n_elvlc=577, n_wgfa=577)

@wtbarnes
Copy link
Owner

wtbarnes commented Feb 2, 2026

Ok this has become way more complex than I thought. I think only a few remaining fixes though (which I'm documenting here for myself):

  • In some cases, the _elvlc property is being used directly which for some ions may have more levels than the model has. Make sure this isn't a problem where it is being used.
  • Should we just replace all usage of elvlc with levels and then truncate levels to always have the same number of levels as n_levels?
  • The two-photon calculation indexes the level populations matrix using elvlc which is potentially wrong for some ions. The way the configuration indexing is done is also potentially wrong. Both need fixing
  • In the two-photon comparison example, limit to the single-ion model to avoid memory limitations on RTD.

@wtbarnes wtbarnes merged commit 2ec62af into main Feb 10, 2026
17 checks passed
@wtbarnes wtbarnes deleted the bug/n-levels branch February 10, 2026 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Run v8 tests Run the test suite using CHIANTI database version 8

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Too many levels for N 4 starting at Chianti Database 10 Replace all usage of _wgfa with self.transitions

2 participants