Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions utu/spectrum/_lines.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""The emission lines of an optically thin plasma."""

import functools
import logging

import astropy.units as u
import fiasco
Expand Down Expand Up @@ -245,10 +246,14 @@ def contribution_function(

coupled = tuple(axis_density) == (axis_temperature,)

result = ion.contribution_function(
na.as_named_array(density).ndarray,
couple_density_to_temperature=coupled,
)
fiasco.log.addFilter(_not_single_ion)
try:
result = ion.contribution_function(
na.as_named_array(density).ndarray,
couple_density_to_temperature=coupled,
)
finally:
fiasco.log.removeFilter(_not_single_ion)

# the last axis of the result runs over the bound-bound transitions, so
# that is the wavelength which belongs to it
Expand All @@ -266,6 +271,20 @@ def contribution_function(
)


def _not_single_ion(record: logging.LogRecord) -> bool:
"""
Whether a record of the log of :mod:`fiasco` is anything but its warning
that an ion is solved with the single-ion model.

:mod:`fiasco` asks for the two-ion model by default, and solves an ion
without the data that model needs with the single-ion model instead,
which is the right model for it. It warns each time, and that is most
ions, while the only way to tell which ions they are beforehand is
private to :mod:`fiasco`.
"""
return "Using single-ion model" not in record.getMessage()


def lines(
temperature: na.AbstractScalar,
density: u.Quantity | na.AbstractScalar,
Expand Down
34 changes: 34 additions & 0 deletions utu/spectrum/_tests/test_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,40 @@ def test_contribution_function_grid(proton_electron_ratio: u.Quantity):
assert shape["_density"] == 2


@needs_database
def test_contribution_function_single_ion(
caplog: pytest.LogCaptureFixture,
proton_electron_ratio: u.Quantity,
):
"""
An ion without the data for the two-ion model, which fiasco solves with
the single-ion model and warns about, is solved the same way without
the warning.
"""
ion = fiasco.Ion("O 5", temperature.ndarray)

fiasco.log.addHandler(caplog.handler)
try:
result = utu.spectrum.contribution_function(
ion=ion,
density=density,
axis_temperature="temperature",
proton_electron_ratio=proton_electron_ratio,
)
assert not any("single-ion" in r.getMessage() for r in caplog.records)

# fiasco itself warns about this ion, once the call above is done
expected = ion.contribution_function(
density.ndarray,
couple_density_to_temperature=True,
)
assert any("single-ion" in r.getMessage() for r in caplog.records)
finally:
fiasco.log.removeHandler(caplog.handler)

assert np.all(result.outputs.ndarray == expected[:, 0, :])


@needs_database
def test_lines():
"""The whole of it, with nothing given that can be worked out."""
Expand Down
Loading