Usage¶
Single-channel AIA wavelength response¶
from astropy.time import Time
from pyeuvtools.response.aia import build_aia_wavelength_response
response = build_aia_wavelength_response(171, Time("2020-11-26T19:58:31"))
table = response.to_table()
print(response.channel)
print(response.response.unit)
print(table.colnames)
The returned object is a stable container with explicit metadata and a quantity-aware table export path suitable for downstream use.
Multi-channel AIA wavelength response set¶
from astropy.time import Time
from pyeuvtools.response.aia import build_aia_wavelength_response_set
responses = build_aia_wavelength_response_set(Time("2020-11-26T19:58:31"))
table = responses.to_table()
print(responses.instrument)
print(responses.channels)
print(responses.wavelength.shape)
print(responses.responses["171"].shape)
print(table.colnames[:3])
Current limitation¶
The package now exposes a compact public AIA temperature-response path through
aia_get_response(...) and the downstream bridge helper
build_aia_temperature_response_gx_payload(...).
The remaining limitations for 0.1.0 are the broader SSW branches that are
still intentionally deferred:
fullstructuresallchannel mode beyond the standard thin-filter EUV setuvchannel support- non-
dntemperature-response branches
Compact aia_get_response correction states¶
from pyeuvtools.response import aia_get_response
response = aia_get_response(
temperature=True,
correction="evenorm_chiantifix",
timedepend_date="2025-11-26T15:34:31",
)
print(response.metadata["correction_state"])
print(response.metadata["evenorm"])
print(response.metadata["chiantifix"])
The compact Python aia_get_response surface is intentionally non-interactive.
It only exposes scientifically valid correction states via correction=:
rawevenormevenorm_chiantifix
The legacy evenorm= and chiantifix= keywords remain as a temporary
compatibility layer, but they are deprecated and chiantifix-only requests are
rejected rather than silently coerced.
Generate and quick-plot from the exposed API¶
To generate a compact AIA response artifact through the public
aia_get_response API and quick-plot all channel curves on one panel, run:
PYTHONPATH=src python scripts/run_aia_get_response.py \
--response-type temperature \
--correction evenorm_chiantifix \
--obstime 2025-11-26T15:34:31
By default this writes under:
~/.pyeuvtools/aia-get-response/temperature/evenorm_chiantifix/
with both:
aia_temperature_evenorm_chiantifix.npzaia_temperature_evenorm_chiantifix.png
The same CLI also supports compact area products:
PYTHONPATH=src python scripts/run_aia_get_response.py \
--response-type effective_area \
--correction evenorm \
--obstime 2025-11-26T15:34:31
For emissivity, the CLI saves the compact .npz artifact but currently skips
the quick-plot step.
Compare against the canonical IDL AIA fixture¶
from pyeuvtools.response import canonical_aia_benchmark_path, compare_aia_response_to_idl
comparison = compare_aia_response_to_idl(
canonical_aia_benchmark_path(),
"2025-11-26T15:34:31",
)
print(comparison.channel_match)
print(comparison.idl_temperature_shape)
print(comparison.python_wavelength_samples)
print(comparison.blocking_gaps)
This helper is intended to make the current scientific gap explicit. Today the canonical IDL fixture is a temperature-response structure, while the shipped Python API still exposes wavelength responses.
Compare a folded temperature-response candidate against the raw IDL benchmark¶
import astropy.units as u
import numpy as np
from pyeuvtools.response import canonical_aia_benchmark_path, compare_aia_temperature_response_to_idl
comparison = compare_aia_temperature_response_to_idl(
canonical_aia_benchmark_path(),
emissivity_wavelength=u.Quantity([90.0, 95.0, 100.0], u.angstrom),
emissivity_logte=np.linspace(4.0, 9.0, 101),
emissivity=u.Quantity(np.ones((3, 101)), u.dimensionless_unscaled),
obstime="2025-11-26T15:34:31",
)
print(comparison.logte_match)
print(comparison.max_absolute_difference)
print(comparison.max_relative_difference)
This comparison path expects an already chosen emissivity grid. It does not yet construct the CHIANTI emissivity surface itself, but it removes the current package-level blocker where the benchmark comparison stopped at the wavelength-response abstraction boundary.
Screen ions and try a broader CHIANTI-backed comparison¶
import astropy.units as u
import numpy as np
from pyeuvtools.response import (
build_fiasco_ion_spectrum_grid,
canonical_aia_benchmark_path,
compare_aia_temperature_response_to_idl,
load_idl_aia_response,
screen_fiasco_ions_for_temperature_grid,
)
idl = load_idl_aia_response(canonical_aia_benchmark_path())
full_logte = idl.logte
supported_mask = full_logte <= 8.55
supported_temperature = (10 ** full_logte[supported_mask]) * u.K
candidates = [
"He 2", "C 4", "C 5", "C 6", "N 5", "N 6", "N 7", "O 4", "O 5", "O 6", "O 7", "O 8",
"Ne 6", "Ne 7", "Ne 8", "Ne 9", "Mg 5", "Mg 6", "Mg 7", "Mg 8", "Mg 9", "Mg 10", "Mg 11", "Mg 12",
"Si 7", "Si 8", "Si 9", "Si 10", "Si 11", "Si 12", "Si 13", "Si 14",
"S 8", "S 9", "S 10", "S 11", "S 12", "S 13", "S 14", "S 15", "S 16",
"Fe 8", "Fe 9", "Fe 10", "Fe 11", "Fe 12", "Fe 13", "Fe 14", "Fe 15", "Fe 16", "Fe 17", "Fe 18",
]
report = screen_fiasco_ions_for_temperature_grid(
candidates,
temperature=supported_temperature,
density=1e9 / u.cm**3,
use_two_ion_model=False,
include_protons=False,
)
grid = build_fiasco_ion_spectrum_grid(
report.supported_ions,
temperature=supported_temperature,
density=1e9 / u.cm**3,
wavelength_range=u.Quantity([50.0, 400.0], u.angstrom),
bin_width=1 * u.angstrom,
use_two_ion_model=False,
include_protons=False,
)
full_intensity = u.Quantity(
np.zeros((grid.wavelength.size, full_logte.size)),
grid.intensity.unit,
)
full_intensity[:, supported_mask] = grid.intensity
comparison = compare_aia_temperature_response_to_idl(
canonical_aia_benchmark_path(),
emissivity_wavelength=grid.wavelength,
emissivity_logte=full_logte,
emissivity=full_intensity,
obstime="2025-11-26T15:34:31",
)
print(report.supported_ions)
print(comparison.max_absolute_difference)
print(comparison.max_relative_difference)
This is not yet a parity workflow. It is an exploratory bridge for checking how a broader screened ion subset behaves against the raw benchmark over the currently supported CHIANTI temperature range.
If you want to try the current broader-ion bridge directly from the command line, run:
PYTHONPATH=src python scripts/run_screened_raw_compare.py
That command now saves its comparison and cache artifacts outside the repository by default, typically under:
~/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/
The default outputs include:
~/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_compare.png
~/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_compare_data.npz
~/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_spectrum_grid.npz
~/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_screening.npz
The default path is still backend-aware, so the current fiasco prototype does
not silently reuse the same generic artifact location that a future hybrid
backend run would use, but it also no longer dirties the repository by default.
To preserve a historical snapshot instead of writing to the rolling latest
location, set a custom run tag:
PYTHONPATH=src python scripts/run_screened_raw_compare.py --artifact-tag 2026-05-03-fiasco-reference
You can choose an explicit user-local artifact directory with:
PYTHONPATH=src python scripts/run_screened_raw_compare.py \
--artifact-dir "$HOME/.pyeuvtools/benchmark-results/aia/fiasco-screened/my-run/screened_raw_compare"
For contributor or release work where the result is intentionally meant to live inside the repository, pass an explicit repo-local artifact directory. You can also choose a single explicit output path with:
PYTHONPATH=src python scripts/run_screened_raw_compare.py --plot-output benchmark-results/aia/custom/my_compare.png
Once that data artifact exists, you can regenerate a fresh plot without rerunning the CHIANTI computation:
PYTHONPATH=src python scripts/run_screened_raw_compare.py \
--plot-from-data "$HOME/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_compare_data.npz" \
--plot-output "$HOME/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_compare_rerendered.png"
To skip the expensive CHIANTI spectrum build on repeated runs, save and reuse the spectrum-grid cache:
PYTHONPATH=src python scripts/run_screened_raw_compare.py \
--spectrum-cache "$HOME/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_spectrum_grid.npz"
PYTHONPATH=src python scripts/run_screened_raw_compare.py \
--reuse-spectrum-cache \
--spectrum-cache "$HOME/.pyeuvtools/benchmark-results/aia/fiasco-screened/latest/screened_raw_compare/aia_screened_raw_spectrum_grid.npz"
The current comparison workflow keeps AIA 335 in the reports and plots, but treats it as a lower-confidence validation channel. Public literature reports passband inconsistencies, higher-order contamination, and incomplete spectral content near 335 A, so mismatches there should be interpreted more cautiously than in channels such as 171, 193, or 211. Relevant references include Boerner et al. 2013 (Sol. Phys. 289, 2377; arXiv:1307.8045) and Trabert and Beiersdorfer 2018 (A&A 617, A8; DOI 10.1051/0004-6361/201833256).
Generate the normalized hybrid export¶
The published aia_V9 hybrid export should be generated with an explicit output
directory and an explicit .genx source pair, even when those values match the
current defaults. That keeps the provenance statement simple: the artifact in
benchmark-data/aia/genx-exports/aia_V9/ came from the command below.
From the repository root:
REPO_ROOT=$PWD
SSWIDL=/path/to/sswidl
cat <<EOF | "$SSWIDL"
.compile ${REPO_ROOT}/scripts/idl/ExportAIAHybridGenx.pro
ExportAIAHybridGenx, outdir='${REPO_ROOT}/benchmark-data/aia/genx-exports/aia_V9', response_dir='${SSW}/sdo/aia/response', fullinst_name='aia_V9_all_fullinst.genx', fullemiss_name='aia_V9_fullemiss.genx'
exit
EOF
The exporter still defaults to the current aia_V9 source pair, but advanced
users do not need to edit the IDL script to work with a future response
release. Re-run the same command with a different fullinst_name and
fullemiss_name, or pass explicit fullinst_file and fullemiss_file paths.
If outdir is omitted, the exporter now writes outside the repository under a
user-local directory such as ~/.pyeuvtools/aia/genx-exports/aia_V10/ and only
uses a repository path when outdir is passed explicitly. That keeps the
cloned tree clean for normal users while still allowing contributors to
regenerate the committed repo artifact with an explicit repo-local outdir.
Hybrid genx comparison¶
Once a normalized hybrid export exists, you can compare it directly against the canonical raw IDL benchmark with:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py
With no explicit output arguments, the comparison artifacts now go to a user-local directory outside the repository, typically:
~/.pyeuvtools/benchmark-results/aia/hybrid-genx/latest/hybrid_raw_compare/
That default is intentionally safe for distributed clones: the repository can
ship reference benchmark artifacts and the committed aia_V9 export, while a
user's own runs do not dirty the working tree unless they explicitly choose a
repo-local path.
With no explicit export arguments, the Python side now resolves the highest
packaged exported version under src/pyeuvtools/data/aia/genx-exports/,
mirroring the usual AIA-version preference that favors the newest installed
response.
To pin an older exported emissivity version for comparison work, pass an emissivity-version selector:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--emversion V9
You can also split the selectors the same way SSW does:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--version V10 \
--emversion V9 \
--respversion V9
That means:
--version: choose the instrument response version--emversion: choose the exported emissivity artifact version--respversion: choose the degradation response table version or path
You can still override the default lookup completely with an explicit path:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--hybrid-export benchmark-data/aia/genx-exports/aia_V9/aia_hybrid_genx_export_v1.sav
For user-local custom artifacts, pass an explicit artifact directory:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--artifact-dir "$HOME/.pyeuvtools/benchmark-results/aia/hybrid-genx/my-run/hybrid_raw_compare"
For contributor or release work where the result is intentionally meant to live inside the repository, pass an explicit repo-local artifact directory:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--artifact-dir benchmark-results/aia/hybrid-genx/2026-05-04-raw-reference/hybrid_raw_compare \
--hybrid-export benchmark-data/aia/genx-exports/aia_V9/aia_hybrid_genx_export_v1.sav
That published 2026-05-04-raw-reference snapshot is the current raw baseline:
no evenorm, no chiantifix.
Without that explicit override, the workflow no longer writes backend-specific outputs into the repository.
The explicit repo-local developer workflow writes under:
benchmark-results/aia/hybrid-genx/latest/hybrid_raw_compare/
To preserve a historical snapshot instead of writing to the rolling latest
location, set a custom run tag:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--emversion V9 \
--artifact-dir benchmark-results/aia/hybrid-genx/2026-05-03-hybrid-reference/hybrid_raw_compare \
--artifact-tag 2026-05-03-hybrid-reference
Once the saved comparison data exists, you can regenerate a plot without rerunning the hybrid fold:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--plot-from-data "$HOME/.pyeuvtools/benchmark-results/aia/hybrid-genx/latest/hybrid_raw_compare/aia_hybrid_raw_compare_data.npz" \
--plot-output "$HOME/.pyeuvtools/benchmark-results/aia/hybrid-genx/latest/hybrid_raw_compare/aia_hybrid_raw_compare_rerendered.png"
Correction-layer naming for contributor snapshots¶
Use distinct repo-local directories for each scientific state instead of reusing the raw baseline path.
Recommended names:
- raw:
benchmark-results/aia/hybrid-genx/<date>-raw-reference/hybrid_raw_compare/ - evenorm:
benchmark-results/aia/hybrid-genx/<date>-evenorm-reference/hybrid_raw_compare/ - evenorm_chiantifix:
benchmark-results/aia/hybrid-genx/<date>-evenorm-chiantifix-reference/hybrid_raw_compare/
To generate a local evenorm IDL reference artifact for a matching comparison,
run the IDL benchmark generator with evenorm=1 and chiantifix=0:
GenerateCanonicalAIABenchmark, evenorm=1L, chiantifix=0L, outdir=file_expand_path(filepath('20251126T153431-evenorm', root_dir=filepath('aia', root_dir=filepath('benchmark-data', root_dir=filepath('.pyeuvtools', root_dir=getenv('HOME'))))))
Then compare the hybrid path against that explicit evenorm fixture:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--evenorm \
--benchmark-path "$HOME/.pyeuvtools/benchmark-data/aia/20251126T153431-evenorm/aia_raw_response_20251126T153431_evenorm.sav" \
--artifact-dir benchmark-results/aia/hybrid-genx/2026-05-04-evenorm-reference/hybrid_raw_compare \
--artifact-tag 2026-05-04-evenorm-reference \
--hybrid-export benchmark-data/aia/genx-exports/aia_V9/aia_hybrid_genx_export_v1.sav
The evenorm_chiantifix IDL fixture can already be generated and preserved with
its own name:
GenerateCanonicalAIABenchmark, evenorm=1L, chiantifix=1L, outdir=file_expand_path(filepath('20251126T153431-evenorm-chiantifix', root_dir=filepath('aia', root_dir=filepath('benchmark-data', root_dir=filepath('.pyeuvtools', root_dir=getenv('HOME'))))))
Then compare the hybrid path against that explicit evenorm_chiantifix fixture:
PYTHONPATH=src python scripts/run_hybrid_raw_compare.py \
--evenorm \
--chiantifix \
--benchmark-path benchmark-data/aia/20251126T153431/aia_raw_response_20251126T153431.sav \
--artifact-dir benchmark-results/aia/hybrid-genx/2026-05-04-evenorm-chiantifix-reference/hybrid_raw_compare \
--artifact-tag 2026-05-04-evenorm-chiantifix-reference \
--hybrid-export src/pyeuvtools/data/aia/genx-exports/aia_V9/aia_hybrid_genx_export_v1.sav
To regenerate both published comparison snapshots with one command, run:
PYTHONPATH=src python scripts/run_hybrid_reference_compare_pair.py
By default that wrapper writes the two repo-local reference outputs under:
benchmark-results/aia/hybrid-genx/2026-05-04-raw-reference/hybrid_raw_compare/benchmark-results/aia/hybrid-genx/2026-05-04-evenorm-chiantifix-reference/hybrid_raw_compare/
The published reference layout is documented alongside the artifacts so it is self-describing from the repository tree:
benchmark-results/aia/hybrid-genx/README.md- top-level index for the retained hybrid reference snapshots
benchmark-results/aia/hybrid-genx/2026-05-04-raw-reference/README.md- provenance and scope for the raw published snapshot
benchmark-results/aia/hybrid-genx/2026-05-04-evenorm-chiantifix-reference/README.md- provenance and scope for the corrected published snapshot
benchmark-results/aia/hybrid-genx/reference_compare_pair_summary.json- machine-readable summary emitted by the wrapper after refreshing both published comparisons
For 0.1.0, the Python chiantifix path works out of the box because the
required Python-readable correction export is shipped under
src/pyeuvtools/data/aia/chiantifix-exports/.
Contributors can refresh that packaged asset from the SSW correction .genx
with:
printf '.compile /Users/gelu/code/SUNCAST-ORG/pyEUVTools/scripts/idl/ExportAIAChiantifix.pro\nExportAIAChiantifix\nexit\n' | sswidl
By default this writes:
~/.pyeuvtools/aia/chiantifix-exports/aia_V9/aia_chiantifix_export_v1.sav~/.pyeuvtools/aia/chiantifix-exports/aia_V9/aia_chiantifix_export_v1.metadata.txt
To refresh the packaged runtime asset in the repository, pass an explicit
repo-local outdir. Pass chiantifix_export=... to the Python
aia_get_response(...) wrapper when you want to pin a non-default export path
explicitly.