From 5065aeeb76c66e5ed98d7ac158ae147015800774 Mon Sep 17 00:00:00 2001 From: joyvelasquez Date: Wed, 22 Apr 2026 16:51:45 -0400 Subject: [PATCH 01/12] Exclude xrt_dem_iterative from pytest collection until v0.6.0 --- pytest.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/pytest.ini b/pytest.ini index 984a006cd..e46ab3237 100644 --- a/pytest.ini +++ b/pytest.ini @@ -9,6 +9,7 @@ norecursedirs = docs/_build examples auto_examples + xrtpy/xrt_dem_iterative doctest_plus = enabled doctest_optionflags = NORMALIZE_WHITESPACE From bcf1cb3945a0b04f9231ec9aebaa593ce3ae4e53 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:30:33 -0400 Subject: [PATCH 02/12] [pre-commit.ci] pre-commit autoupdate (#388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/python-jsonschema/check-jsonschema: 0.37.0 → 0.37.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.37.0...0.37.1) - [github.com/codespell-project/codespell: v2.4.1 → v2.4.2](https://github.com/codespell-project/codespell/compare/v2.4.1...v2.4.2) - [github.com/astral-sh/ruff-pre-commit: v0.15.4 → v0.15.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.4...v0.15.9) - [github.com/tox-dev/pyproject-fmt: v2.16.2 → v2.21.0](https://github.com/tox-dev/pyproject-fmt/compare/v2.16.2...v2.21.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Joy <74623359+joyvelasquez@users.noreply.github.com> --- .pre-commit-config.yaml | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0a4a222fb..84bfb721d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,7 +23,7 @@ repos: - id: check-yaml - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.37.0 + rev: 0.37.1 hooks: - id: check-github-workflows @@ -57,7 +57,7 @@ repos: - id: text-unicode-replacement-char - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 + rev: v2.4.2 hooks: - id: codespell name: codespell (add false positives to pyproject.toml) @@ -67,7 +67,7 @@ repos: exclude: .*\.fits - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.4 + rev: v0.15.9 hooks: - id: ruff name: ruff @@ -90,6 +90,6 @@ repos: additional_dependencies: ['validate-pyproject-schema-store[all]'] - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.16.2 + rev: v2.21.0 hooks: - id: pyproject-fmt diff --git a/pyproject.toml b/pyproject.toml index 4b31add2e..91c1474b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ urls.Repository = "https://github.com/HinodeXRT/xrtpy" [tool.setuptools] packages = [ "xrtpy" ] -package-data."xrtpy" = [ "data/*" ] +package-data.xrtpy = [ "data/*" ] package-data."xrtpy.response" = [ "data/*.txt", "data/*.geny" ] package-data."xrtpy.response.tests" = [ "data/*/*/*.txt" ] From 354f943dcb4965a2603975d88373c84572d50c2b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 09:52:13 -0400 Subject: [PATCH 03/12] [pre-commit.ci] pre-commit autoupdate (#391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/python-jsonschema/check-jsonschema: 0.37.1 → 0.37.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.37.1...0.37.2) - [github.com/astral-sh/ruff-pre-commit: v0.15.9 → v0.15.12](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.9...v0.15.12) - [github.com/tox-dev/pyproject-fmt: v2.21.0 → v2.21.1](https://github.com/tox-dev/pyproject-fmt/compare/v2.21.0...v2.21.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 84bfb721d..b42cce6d6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,7 +23,7 @@ repos: - id: check-yaml - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.37.1 + rev: 0.37.2 hooks: - id: check-github-workflows @@ -67,7 +67,7 @@ repos: exclude: .*\.fits - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.9 + rev: v0.15.12 hooks: - id: ruff name: ruff @@ -90,6 +90,6 @@ repos: additional_dependencies: ['validate-pyproject-schema-store[all]'] - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.21.0 + rev: v2.21.1 hooks: - id: pyproject-fmt From c145bf114a2275718061dcfff5446d888aa3123c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 16:28:33 -0400 Subject: [PATCH 04/12] [pre-commit.ci] pre-commit autoupdate (#392) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: v0.15.12 → v0.15.15](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.12...v0.15.15) - [github.com/tox-dev/pyproject-fmt: v2.21.1 → v2.23.0](https://github.com/tox-dev/pyproject-fmt/compare/v2.21.1...v2.23.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- pyproject.toml | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b42cce6d6..b0faaaf94 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -67,7 +67,7 @@ repos: exclude: .*\.fits - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.12 + rev: v0.15.15 hooks: - id: ruff name: ruff @@ -90,6 +90,6 @@ repos: additional_dependencies: ['validate-pyproject-schema-store[all]'] - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.21.1 + rev: v2.23.0 hooks: - id: pyproject-fmt diff --git a/pyproject.toml b/pyproject.toml index 91c1474b6..bec01e955 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,15 +78,14 @@ urls.Repository = "https://github.com/HinodeXRT/xrtpy" [tool.setuptools] packages = [ "xrtpy" ] -package-data.xrtpy = [ "data/*" ] -package-data."xrtpy.response" = [ "data/*.txt", "data/*.geny" ] +package-data."xrtpy.response" = [ "data/*.geny", "data/*.txt" ] package-data."xrtpy.response.tests" = [ "data/*/*/*.txt" ] +package-data.xrtpy = [ "data/*" ] [tool.setuptools_scm] write_to = "xrtpy/version.py" [tool.codespell] -skip = "*.genx,*.geny,*.png,*egg*,.git,.hypothesis,.nox,.tox,.idea,__pycache__,_build" ignore-words-list = """ 4rd, aas, @@ -102,10 +101,10 @@ te, tne, ue """ +skip = "*.genx,*.geny,*.png,*egg*,.git,.hypothesis,.nox,.tox,.idea,__pycache__,_build" [tool.pytest] ini_options.testpaths = [ "." ] -ini_options.xfail_strict = true ini_options.norecursedirs = [ "*egg-info*", ".*cache*", @@ -116,6 +115,7 @@ ini_options.norecursedirs = [ ".hypothesis", ".idea", ".jupyter", + ".venv", ".vscode", "__pycache__", "_dev", @@ -128,8 +128,8 @@ ini_options.norecursedirs = [ "node_modules", "tools", "venv", - ".venv", ] +ini_options.xfail_strict = true [tool.coverage] run.branch = true From bd0d419ccaa9502cf080b6e9f9c61fab92c148d6 Mon Sep 17 00:00:00 2001 From: Joy <74623359+joyvelasquez@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:40:49 -0400 Subject: [PATCH 05/12] Update XRT CCD contamination files (geny, sav) - DB covers through 2026/06/07 (#395) Co-authored-by: joyvelasquez --- xrtpy/response/data/xrt_contam_on_ccd.geny | Bin 11912 -> 12040 bytes xrtpy/response/data/xrt_contam_on_ccd.sav | Bin 11912 -> 12040 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/xrtpy/response/data/xrt_contam_on_ccd.geny b/xrtpy/response/data/xrt_contam_on_ccd.geny index 5cd0dc0e462535a6810781e67329155595804e31..44a0bf02b4275364ad3f82b50e075e634f2c814a 100644 GIT binary patch delta 290 zcmeB(?TFhT!6F<|nyTPcnx|lBreI)cWoTw)XfauvWir#B`I8T@OcXcM^$PXVH8Lt2zT2;TV7~je8x0_JzE5W`fC11xy&sdmNaC??vw@U{NPt7< zgMW>#eE%GJ7fyZoa6^|v=LZ{u%WR7sdN*uW7tV5U==@*Z=iR=~q5G1lR*MCvLznOw XRd$6ohwkJvtdj&RfVQzgtb~vNN)Ay_ delta 162 zcmeB(>xkVT!6NKdl&RpGSfpTR3`AB&mR5$AleJkUGd-%Ge1K)5xUsIUW00XJ1_sA# zW>?$~fN1jz6=1&Y{$F6e-Ck)h-|g2vFyH;#jRuf9-={MezyN5U-jB&&Br)s*%YyCO zY#`+!65!DJ;9sLF-#>@mg;QTX+|cFF`N78EGTUN@-VNK;g|i$SI{#PqdAIL#=)PpC f)ndWv&?S6Em0h9Dp*#5u>m&gSpm}T%DxkVT!6NKdl&RpGSfpTR3`AB&mR5$AleJkUvi$%5sDAPRmWkrVy1tG@ zW(-ik#K0i=W^x9rvZMwB15+zdlo2Kcq&YxhlMAF2HXmWt5CQTSfa>)sCYwlMsMi#L Rsoz{6mn0005cl8?*ob From 6acd11bc0b9f1a4bcfe7190329d477a51c60ac0a Mon Sep 17 00:00:00 2001 From: Joy <74623359+joyvelasquez@users.noreply.github.com> Date: Mon, 29 Jun 2026 16:43:36 -0400 Subject: [PATCH 06/12] Update XRT CCD contamination files (geny, sav) - DB covers through 20260621 (#397) Co-authored-by: joyvelasquez --- xrtpy/response/data/xrt_contam_on_ccd.geny | Bin 12040 -> 12072 bytes xrtpy/response/data/xrt_contam_on_ccd.sav | Bin 12040 -> 12072 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/xrtpy/response/data/xrt_contam_on_ccd.geny b/xrtpy/response/data/xrt_contam_on_ccd.geny index 44a0bf02b4275364ad3f82b50e075e634f2c814a..565ea0b7807c4c9985a3447846c4c4b6a0b1a8a1 100644 GIT binary patch delta 196 zcmeB(TM@TGf<@RjKTpA{G*7|EQo+E|%E-jZ)O@lw%S2`dhQP`DStd#tS?YR)`so@O z7@09Z0TTm*l+EM}R%OWw1_q{npeQ3mCU8EG<^YLJE|5~#e1tVaM8ff!-=iH33=EFf zf?7KdfYkx@>q|^Fk;2dqmIdqITp-mUqTtY_%z0(1gtkN1hwn?CuPz13vw_t>2>^NP BDDMCO delta 164 zcmZ1x*Acftf<-u_G*!W?G*7|MOu@j?%FxWp&|o QH%N7e2msZxA(_Mg0KRD)r2qf` diff --git a/xrtpy/response/data/xrt_contam_on_ccd.sav b/xrtpy/response/data/xrt_contam_on_ccd.sav index 7aab219af054bffa0966d9c06760e44c4b47c13b..3a82509d94654fea7980424297c765a129648252 100644 GIT binary patch delta 195 zcmeB(TM@TGf<@RjKTpA{G*7|EQo+E|%E-jZ)O@lw%Veg&`I8T@Opq|L)b$GW(={?M zGGl-OCI$v6o5>lh%90ff3{3q%QAU^)kmdl1O)ij9*nEUFLqx*yn%|=x4Gav9*MeF* y4}jGH_3KMaHj%>6uPz1CzqvrFLqx%$OPTY^R0(Z|t`FarJYQW3lw|{(03`r=L@3|@ delta 163 zcmZ1x*Acftf<-u_G*!W?G*7|MOu@j?%FxWp&|3W6w=^7ar znK3{C69a>k&g2YMWyuT%2Bu!1C?iCMeLj%p0Eta*kW$!ugf&A1$YTJi*ZVQqMG8Yb USQl9R<_4(_5dk2d4J-yF0F^Zwv;Y7A From 75c1860eee080e4f59fea4a6948f6addae61824d Mon Sep 17 00:00:00 2001 From: Joy <74623359+joyvelasquez@users.noreply.github.com> Date: Thu, 2 Jul 2026 11:52:09 -0400 Subject: [PATCH 07/12] Update gallery docs for data processing and instrument response examples (#396) * Update gallery docs for data processing and instrument response examples * Add missing __init__.py files for gallery subpackages * Force the Agg backend and fix the coverage target * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Check the Fido.search calls in temperature_from_filter_ratios.py * Check the Fido.search calls in deconvolving.py --------- Co-authored-by: joyvelasquez Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/gallery/data_processing/__init__.py | 0 docs/gallery/data_processing/deconvolving.py | 45 +++++++++++ .../data_processing/remove_lightleak.py | 68 +++++++++++++++++ .../temperature_from_filter_ratios.py | 70 +++++++++++++++++ docs/gallery/instrument_response/__init__.py | 0 .../instrument_response/effective_area.py | 75 +++++++++++++++++++ examples/deconvolving.py | 13 ++++ examples/temperature_from_filter_ratios.py | 14 ++++ noxfile.py | 4 +- 9 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 docs/gallery/data_processing/__init__.py create mode 100644 docs/gallery/data_processing/deconvolving.py create mode 100644 docs/gallery/data_processing/remove_lightleak.py create mode 100644 docs/gallery/data_processing/temperature_from_filter_ratios.py create mode 100644 docs/gallery/instrument_response/__init__.py create mode 100644 docs/gallery/instrument_response/effective_area.py diff --git a/docs/gallery/data_processing/__init__.py b/docs/gallery/data_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/gallery/data_processing/deconvolving.py b/docs/gallery/data_processing/deconvolving.py new file mode 100644 index 000000000..503a36e03 --- /dev/null +++ b/docs/gallery/data_processing/deconvolving.py @@ -0,0 +1,45 @@ +""" +======================= +Deconvolving XRT Images +======================= + +This example demonstrates deconvolvoing X-Ray Telescope (XRT) images using the +`xrtpy.image_correction.deconvolve` function in XRTpy. +""" + +import matplotlib.pyplot as plt +import sunpy.map +from sunpy.net import Fido +from sunpy.net import attrs as a + +from xrtpy.image_correction import deconvolve + +############################################################################## +# We will search for XRT data from the Virtual Solar Observatory (VSO) and fetch the first result. + +result = Fido.search( + a.Time("2012-06-05 21:58:39", "2012-06-05 21:59:00"), a.Instrument("xrt") +) +data_file = Fido.fetch(result[0]) + +############################################################################## +# Typically most deconvolve routines use the Richardson-Lucy deconvolution algorithm. + +xrt_map = sunpy.map.Map(data_file) +deconv_map = deconvolve(xrt_map) + +############################################################################## +# To see the effects of the deconvolution we plot both the before and after images. + +fig = plt.figure(figsize=(15, 10)) + +ax = fig.add_subplot(121, projection=xrt_map) +xrt_map.plot(axes=ax, title="Original") +ax1 = fig.add_subplot(122, projection=deconv_map) +deconv_map.plot(axes=ax1, title="Deconvolved") + +ax1.coords[1].set_ticks_visible(False) +ax1.coords[1].set_ticklabel_visible(False) +fig.tight_layout() + +plt.show() diff --git a/docs/gallery/data_processing/remove_lightleak.py b/docs/gallery/data_processing/remove_lightleak.py new file mode 100644 index 000000000..51e5c6f4f --- /dev/null +++ b/docs/gallery/data_processing/remove_lightleak.py @@ -0,0 +1,68 @@ +""" +=================== +Removing Light Leak +=================== + +In this example, we show how to remove the light leak (visible stray light) +from XRT synoptic composite images. +""" + +from pathlib import Path + +import matplotlib.pyplot as plt +import sunpy.map +from astropy.utils.data import get_pkg_data_path +from astropy.visualization import ImageNormalize, SqrtStretch + +from xrtpy.image_correction import remove_lightleak + +############################################################################## +# This example will be using XRT synoptic data from the first day of summer of 2015. +# This is stored in the ``example_data`` directory of the `xrtpy` package. + +directory = get_pkg_data_path("data/example_data", package="xrtpy.image_correction") +data_file = Path(directory) / "comp_XRT20150621_055911.7.fits" +xrt_map = sunpy.map.Map(data_file) + +############################################################################## +# Removing the light leak from the composite image is done using the `xrtpy.image_correction.remove_lightleak` function. + +lightleak_map = remove_lightleak(xrt_map) + +############################################################################## +# Finally, we plot the original and light leak subtracted images side by side. + +fig = plt.figure(figsize=(12, 6)) + +ax = fig.add_subplot(121, projection=xrt_map) +xrt_map.plot( + axes=ax, + title="Original", + norm=ImageNormalize(vmin=0, vmax=7e3, stretch=SqrtStretch()), +) +ax1 = fig.add_subplot(122, projection=lightleak_map) +lightleak_map.plot( + axes=ax1, + title="Light Leak Subtracted", + norm=ImageNormalize(vmin=0, vmax=7e3, stretch=SqrtStretch()), +) + +ax1.coords[1].set_ticks_visible(False) +ax1.coords[1].set_ticklabel_visible(False) +fig.tight_layout() + +############################################################################## +# They look almost identical, but the light leak has been removed from the second image. +# To confirm this we can plot the difference between the two images. + +diff_data = xrt_map.data - lightleak_map.data +# For this image, the difference is very small. +print(diff_data.min(), diff_data.max()) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.set_title("Lightleak Difference") +im = ax.imshow(diff_data, origin="lower") +fig.colorbar(im) + +plt.show() diff --git a/docs/gallery/data_processing/temperature_from_filter_ratios.py b/docs/gallery/data_processing/temperature_from_filter_ratios.py new file mode 100644 index 000000000..04d1aa9f0 --- /dev/null +++ b/docs/gallery/data_processing/temperature_from_filter_ratios.py @@ -0,0 +1,70 @@ +""" +================================================ +Calculating the temperature and emission measure +================================================ + +In this example, we will showcase how to use the filter method to calculate +the temperature and emission measure of the X-ray Telescope (XRT) on Hinode. +""" + +import matplotlib.pyplot as plt +import sunpy.map +from astropy.visualization import ImageNormalize, LogStretch +from sunpy.net import Fido +from sunpy.net import attrs as a + +from xrtpy.response import temperature_from_filter_ratio + +############################################################################## +# To start, we will get XRT data via ``sunpy``. +# +# It is important to use images that same size and with the smallest time separation. +# Note that not all filter ratios produce good results. + +query = Fido.search( + a.Time("2011-01-28 01:31:55", "2011-01-28 01:32:05"), a.Instrument("xrt") +) +data_files = Fido.fetch(query) +xrt_map_1 = sunpy.map.Map(data_files[0]) +xrt_map_2 = sunpy.map.Map(data_files[1]) + +############################################################################## +# The `xrtpy.response.temperature_from_filter_ratio` function has several options, mirroring +# the IDL routine xrt_teem.pro in SolarSoft in most respects.A simple call with +# no extra parameters calculates the temperature and (volume) emission measure +# for the two images without any binning or masking of the data. + +T_EM = temperature_from_filter_ratio(xrt_map_1, xrt_map_2) + +############################################################################## +# The output is a namedtuple with attributes ``Tmap``, ``EMmap``, ``Terrmap``, and ``EMerrmap``. +# As with the SolarSoft IDL routine xrt_teem.pro, the output images are logs of the quantities. +# +# ``Tmap`` is the electron temperature, ``EMmap`` is the volume emission measure, ``Terrmap`` +# is a measure of the uncertainties in the temperature determined for each pixel and ``EMerrmap`` +# is the same for the emission measure. + +T_e = T_EM.Tmap + +fig = plt.figure() + +ax = plt.subplot(projection=T_e) +T_e.plot( + title="Derived Temperature", + cmap="inferno", + norm=ImageNormalize(vmin=6, vmax=7, stretch=LogStretch(10)), +) +T_e.draw_limb() +T_e.draw_grid() +plt.colorbar(label="T (K)") +plt.tight_layout() + +plt.show() + +############################################################################## +# If you want to do the same for Level 2 synoptic composite images, you have to use +# `~.make_exposure_map` to generate the exposure maps for the composite images. +# This is then passed to `xrtpy.response.temperature_from_filter_ratio` as the +# ``expmap1`` and ``expmap2`` arguments. +# Otherwise without accounting for the different exposure time per pixel, +# the temperature and emission measure will be incorrect. diff --git a/docs/gallery/instrument_response/__init__.py b/docs/gallery/instrument_response/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/gallery/instrument_response/effective_area.py b/docs/gallery/instrument_response/effective_area.py new file mode 100644 index 000000000..f2052cfd4 --- /dev/null +++ b/docs/gallery/instrument_response/effective_area.py @@ -0,0 +1,75 @@ +""" +======================= +Effective Area Analysis +======================= + +In this example, we will explore the effective areas for different XRT filter channels. +Understanding the effective areas is important for accurately interpreting and quantifying the data. +""" + +import matplotlib.pyplot as plt + +import xrtpy + +############################################################################## +# Let us begin by defining a filter channel using its abbreviation. +# For example, if we want to explore the effective area for an aluminum-on-polyimide filter +# channel, we need to specify the relevant abbreviation. + +xrt_filter = "Al-poly" + +############################################################################## +# `~.EffectiveAreaFundamental` allows us to accurately determine the effective area +# based on the specified filter channel, date, and time. + +date_time = "2023-09-22T22:59:59" +eaf = xrtpy.response.EffectiveAreaFundamental(xrt_filter, date_time) + +############################################################################## +# To actually calculate the effective area function we can call :meth:`~xrtpy.response.EffectiveAreaFundamental.effective_area`. + +effective_area = eaf.effective_area() +print("Effective Area:\n", effective_area) + +############################################################################## +# Differences overtime arise from an increase of the contamination layer on the +# CCD which blocks some of the X-rays thus reducing the effective area. +# For detailed information about the calculation of the XRT CCD contaminant layer thickness, +# you can refer to +# `Montana State University `__. +# +# Additional information is provided by +# `Narukage et. al. (2011) `__. + +relative_launch_date_time = "2006-09-22T22:59:59" +eaf_launch = xrtpy.response.EffectiveAreaFundamental( + xrt_filter, relative_launch_date_time +) +launch_effective_area = eaf_launch.effective_area() + +############################################################################## +# Finally, we can plot how the effective area has changed over time. + +plt.figure() + +plt.plot( + eaf.wavelength, + effective_area, + label=f"{date_time}", +) +plt.plot( + eaf.wavelength, + launch_effective_area, + label=f"{relative_launch_date_time}", +) + +plt.title("XRT Effective Area - Al-Poly") +plt.xlabel("Wavelength (Å)") +plt.ylabel("Effective Area ($cm^{2}$)") +plt.legend() +plt.xlim(0, 60) + +plt.grid(color="lightgrey") +plt.tight_layout() + +plt.show() diff --git a/examples/deconvolving.py b/examples/deconvolving.py index 503a36e03..c2647098c 100644 --- a/examples/deconvolving.py +++ b/examples/deconvolving.py @@ -22,6 +22,19 @@ ) data_file = Fido.fetch(result[0]) +# Retry any downloads that failed transiently (e.g., VSO/SDAC hiccups). +# Calling fetch on the previous result only re-attempts missing files. +for _ in range(3): + if not data_file.errors: + break + data_file = Fido.fetch(data_file) + +if len(data_file) < 1: + raise RuntimeError( + f"Expected 1 XRT file from VSO, got {len(data_file)}. " + f"Download errors: {data_file.errors}" + ) + ############################################################################## # Typically most deconvolve routines use the Richardson-Lucy deconvolution algorithm. diff --git a/examples/temperature_from_filter_ratios.py b/examples/temperature_from_filter_ratios.py index 04d1aa9f0..02d232dde 100644 --- a/examples/temperature_from_filter_ratios.py +++ b/examples/temperature_from_filter_ratios.py @@ -25,6 +25,20 @@ a.Time("2011-01-28 01:31:55", "2011-01-28 01:32:05"), a.Instrument("xrt") ) data_files = Fido.fetch(query) + +# Retry any downloads that failed transiently (e.g., VSO/SDAC hiccups). +# Calling fetch on the previous result only re-attempts missing files. +for _ in range(3): + if not data_files.errors: + break + data_files = Fido.fetch(data_files) + +if len(data_files) < 2: + raise RuntimeError( + f"Expected 2 XRT files from VSO, got {len(data_files)}. " + f"Download errors: {data_files.errors}" + ) + xrt_map_1 = sunpy.map.Map(data_files[0]) xrt_map_2 = sunpy.map.Map(data_files[1]) diff --git a/noxfile.py b/noxfile.py index 5b82b2c87..fdfe80f6f 100644 --- a/noxfile.py +++ b/noxfile.py @@ -24,7 +24,7 @@ ) with_coverage: tuple[str, ...] = ( - "--cov=plasmapy", + "--cov=xrtpy", "--cov-report=xml", "--cov-config=pyproject.toml", "--cov-append", @@ -55,6 +55,8 @@ def tests(session, test_specifier: nox._parametrize.Param) -> None: session.install("uv") session.install(".[tests]", *install_options) + session.env["MPLBACKEND"] = "Agg" + session.run("pytest", *pytest_options, *session.posargs) From a858c8062fd996529428e6140bc6bc73301d7d2c Mon Sep 17 00:00:00 2001 From: Joy <74623359+joyvelasquez@users.noreply.github.com> Date: Thu, 2 Jul 2026 12:31:06 -0400 Subject: [PATCH 08/12] Update general documentation files (#398) * Update general documentation files * Revert index.rst and glossary.rst - depend on DEM content not yet in main * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: joyvelasquez Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/about_xrt.rst | 20 +++++++++--------- docs/getting_started.rst | 44 +++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/docs/about_xrt.rst b/docs/about_xrt.rst index c9848a872..575c6901b 100644 --- a/docs/about_xrt.rst +++ b/docs/about_xrt.rst @@ -8,8 +8,8 @@ Hinode ====== .. image:: _static/images/hinode_satellite.png - :alt: Hinode Satellite - :align: center + :alt: Hinode Satellite + :align: center Hinode is a joint mission involving the space agencies of Japan, the United States, Europe, and the United Kingdom. It is depicted in the *illustration shown above*. @@ -25,9 +25,9 @@ The X-Ray Telescope =================== .. image:: _static/images/XRT_composite_image_full_disk_14February2015.png - :alt: XRT Composite Image - :align: center - :scale: 50% + :alt: XRT Composite Image + :align: center + :scale: 50% The X-Ray Telescope (XRT), depicted as a long linear black tube on the Hinode spacecraft is a crucial instrument for observing the solar corona's most intense regions, with temperatures ranging from 1,000,000 to 10,000,000 Kelvin. The image below is a synoptic composite from February 14, 2015, created using the Al-Mesh/Be-Thin/Al-Med filters. @@ -36,7 +36,7 @@ For a comprehensive overview of XRT's mission and capabilities, please visit the .. tip:: - Visit the `XRT Picture of the Week`_ and the `Hinode-XRT YouTube`_ page for captivating visual content showcasing the XRT's solar observations. + Visit the `XRT Picture of the Week`_ and the `Hinode-XRT YouTube`_ page for captivating visual content showcasing the XRT's solar observations. XRT uses two sequentially positioned filter wheels, as shown in the diagram below, where each wheel houses a variety of filters. By rotating these wheels, scientists can select different filters to study the Sun in different wavelengths, thereby enhancing the resolution and quality of solar images. @@ -73,8 +73,8 @@ The existing filters are structured as follows: The process is the same for all XRT filter channels. .. image:: _static/images/XRT_filter_wheels_Sun_View_Diagram.png - :alt: Diagram of the XRT Filter Wheels - :align: center + :alt: Diagram of the XRT Filter Wheels + :align: center Data Products ************* @@ -99,8 +99,8 @@ The XRT software was originally created in the Interactive Data Language (IDL). .. note:: - Please note that the `SolarSoft XRT Analysis Guide`_ does not serve as a guide for using XRTpy. - It focuses solely on the analysis of XRT data using the IDL software. + Please note that the `SolarSoft XRT Analysis Guide`_ does not serve as a guide for using XRTpy. + It focuses solely on the analysis of XRT data using the IDL software. .. _Hinode-XRT YouTube: https://www.youtube.com/user/xrtpow .. _Interactive Data Language: https://www.l3harrisgeospatial.com/Software-Technology/IDL diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 8f3cae3cf..6e1fef6e9 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -7,7 +7,7 @@ on board the Hinode spacecraft. This page is intended for new users of XRTpy. Fo please refer to the `SolarSoft XRT Analysis Guide`_. XRTpy Objects -************* +------------- XRTpy currently provides access to the following core classes: @@ -24,41 +24,41 @@ It also includes functionality to: Visit our Examples page for step-by-step Jupyter notebook guides on how to use each feature. Channel -------- +^^^^^^^ The ``Channel`` class describes the configuration of a specific XRT filter channel. It includes details for the Charge-Coupled Device (CCD), Entrance Filter, Focal Plane Filters, Geometry, and Mirrors. Effective Area --------------- +^^^^^^^^^^^^^^ XRTpy calculates the effective area for each XRT filter channel, accounting for time-dependent contamination on the CCD. For more details, refer to the `SolarSoft XRT Analysis Guide`_. Temperature Response --------------------- +^^^^^^^^^^^^^^^^^^^^ XRTpy calculates the temperature response of XRT filter channels using the CHIANTI_ atomic database (version 10.0) and coronal abundances (:cite:t:`feldman:1992`). This produces a response function as a function of temperature, using an assumed emission model (:cite:t:`narukage:2011`, :cite:t:`narukage:2014`). Deriving Temperature and Emission Measure ------------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``temperature_from_filter_ratio`` function allows you to derive plasma temperature and emission measure from a pair of XRT images using the filter-ratio method. This mirrors the logic in the SolarSoft IDL routine of the same name. A usage example is available in the Examples section. Image Deconvolution with the PSF --------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``deconvolve`` function applies image deconvolution using the instrument's Point Spread Function (PSF) to sharpen XRT images. This is especially useful for recovering detail around bright or sharp solar structures. Light Leak Correction ---------------------- +^^^^^^^^^^^^^^^^^^^^^ The ``remove_lightleak`` function subtracts visible stray light from XRT synoptic composite images. This correction improves the quality of long-term coronal evolution studies. See our Examples section for how to use this function. Abundance Model Options ------------------------ +^^^^^^^^^^^^^^^^^^^^^^^ By default, XRTpy uses CHIANTI coronal abundances (:cite:t:`feldman:1992`). You may also choose: @@ -83,12 +83,12 @@ You may also pass the ``abundance_model`` keyword to ``temperature_from_filter_r Tools -***** +----- The ``xrtpy.response.tools`` module includes helpful utility functions to streamline workflows. It includes the following: Generate Temperature Responses ------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the ``generate_temperature_responses`` tool to compute the temperature response for one or more filters — including combinations like ``"Al-poly/Ti-poly"`` — with a single command. @@ -117,16 +117,16 @@ This function returns a list of ``TemperatureResponseFundamental`` objects, one .. code-block:: text Filter: Al-poly - Temperatures: [100000. 112201.9 125892.516] K - Response: [8.34e-31 1.07e-30 1.53e-30] cm5 DN / (pix s) + Temperatures: [100000. 112201.9 125892.516] K + Response: [8.34e-31 1.07e-30 1.53e-30] cm5 DN / (pix s) Filter: Be-thick - Temperatures: [100000. 112201.9 125892.516] K - Response: [0.00e+00 1.73e-94 2.43e-84] cm5 DN / (pix s) + Temperatures: [100000. 112201.9 125892.516] K + Response: [0.00e+00 1.73e-94 2.43e-84] cm5 DN / (pix s) Filter: Al-poly/Ti-poly - Temperatures: [100000. 112201.9 125892.516] K - Response: [5.34e-34 7.24e-34 1.11e-33] cm5 DN / (pix s) + Temperatures: [100000. 112201.9 125892.516] K + Response: [5.34e-34 7.24e-34 1.11e-33] cm5 DN / (pix s) Each response object has the following attributes: @@ -138,7 +138,7 @@ This tool is useful on its own, but it also serves as a foundation for upcoming Data Products -************* +------------- XRT data products are available through the XRT website. These include: @@ -148,7 +148,7 @@ XRT data products are available through the XRT website. These include: For more information, visit the `XRT data products`_ page. Double Filter Combinations -************************** +-------------------------- XRTpy now supports double filter combinations such as ``"Al-poly/Ti-poly"`` in both the :obj:`EffectiveAreaFundamental ` and :obj:`TemperatureResponseFundamental ` classes. @@ -178,7 +178,7 @@ The following combinations are currently supported: X-Ray Filter Channels -********************* +--------------------- XRT uses two filter wheels to configure the imaging filter channel. Each wheel includes several filters and an open slot: @@ -204,12 +204,6 @@ Filter Wheel 2: Filter names in XRTpy are passed as strings like ``'Ti-poly'``. -References -********** - -Velasquez, J., Murphy, N., Reeves, K. K., Slavin, J., Weber, M., & Barnes, W. (2024). -*XRTpy: A Hinode-X-Ray Telescope Python Package*. JOSS, 9(100), 6396. -https://doi.org/10.21105/joss.06396 .. _CHIANTI: https://www.chiantidatabase.org/chianti_database_history.html .. _SolarSoft XRT Analysis Guide: https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf From 8f652dfc494dbb8671e1b57ae8bbe3339eef9cbf Mon Sep 17 00:00:00 2001 From: Joy <74623359+joyvelasquez@users.noreply.github.com> Date: Thu, 2 Jul 2026 12:41:47 -0400 Subject: [PATCH 09/12] Update conftest, pyproject, and response __init__ with cleanup changes (#399) Co-authored-by: joyvelasquez --- conftest.py | 3 +++ pyproject.toml | 1 + xrtpy/response/__init__.py | 3 +++ 3 files changed, 7 insertions(+) create mode 100644 conftest.py diff --git a/conftest.py b/conftest.py new file mode 100644 index 000000000..d29ed8113 --- /dev/null +++ b/conftest.py @@ -0,0 +1,3 @@ +import matplotlib as mpl + +mpl.use("Agg") diff --git a/pyproject.toml b/pyproject.toml index bec01e955..5f7d1956b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ classifiers = [ dynamic = [ "version" ] dependencies = [ "astropy>=6", + "lmfit>=1.2.2", "matplotlib>=3.7", "numpy>=1.24", "scikit-image>=0.21", diff --git a/xrtpy/response/__init__.py b/xrtpy/response/__init__.py index 1e863714d..09c577109 100644 --- a/xrtpy/response/__init__.py +++ b/xrtpy/response/__init__.py @@ -13,6 +13,8 @@ from xrtpy.response.temperature_from_filter_ratio import temperature_from_filter_ratio from xrtpy.response.temperature_response import TemperatureResponseFundamental +from . import tools + __all__ = [ "Geometry", "EntranceFilter", @@ -24,4 +26,5 @@ "EffectiveAreaFundamental", "TemperatureResponseFundamental", "temperature_from_filter_ratio", + "tools", ] From 0cbe0b6ff9a1a8635d119ae7f98e5def20a78099 Mon Sep 17 00:00:00 2001 From: Joy <74623359+joyvelasquez@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:35:17 -0400 Subject: [PATCH 10/12] Enable parallel test execution in noxfile (#400) * Enable parallel test execution in noxfile * Ignore sphinx-gallery scripts in pytest --------- Co-authored-by: joyvelasquez --- noxfile.py | 3 +-- pytest.ini | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/noxfile.py b/noxfile.py index fdfe80f6f..2205d7ab5 100644 --- a/noxfile.py +++ b/noxfile.py @@ -16,7 +16,6 @@ pytest_command: tuple[str, ...] = ( "pytest", - "--pyargs", "--durations=5", "--tb=short", "-n=auto", @@ -57,7 +56,7 @@ def tests(session, test_specifier: nox._parametrize.Param) -> None: session.env["MPLBACKEND"] = "Agg" - session.run("pytest", *pytest_options, *session.posargs) + session.run(*pytest_command, *pytest_options, *session.posargs) @nox.session diff --git a/pytest.ini b/pytest.ini index e46ab3237..89b9ba580 100644 --- a/pytest.ini +++ b/pytest.ini @@ -23,3 +23,4 @@ addopts = --arraydiff --doctest-ignore-import-errors --doctest-continue-on-failure + --ignore=docs/gallery From 8bd0398e82f5e0362e655908b77642e244c670a8 Mon Sep 17 00:00:00 2001 From: joyvelasquez Date: Mon, 6 Jul 2026 13:23:09 -0400 Subject: [PATCH 11/12] Add Python 3.14 to the test matrix --- .github/workflows/ci.yml | 5 +++++ noxfile.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 759bf6813..304f5286e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,11 @@ jobs: matrix: include: + - name: Tests, Python 3.14, Ubuntu + os: ubuntu-latest + nox_session: tests-3.14(all) + python: '3.14' + - name: Tests, Python 3.13, Ubuntu os: ubuntu-latest nox_session: tests-3.13(all) diff --git a/noxfile.py b/noxfile.py index 2205d7ab5..8dd9179e5 100644 --- a/noxfile.py +++ b/noxfile.py @@ -4,7 +4,7 @@ nox.options.default_venv_backend = "uv" -supported_python_versions = ("3.11", "3.12", "3.13") +supported_python_versions = ("3.11", "3.12", "3.13", "3.14") maxpython = max(supported_python_versions) minpython = min(supported_python_versions) From edb826673413ac58897f12cb84b9858629ab35a7 Mon Sep 17 00:00:00 2001 From: joyvelasquez Date: Mon, 6 Jul 2026 13:56:39 -0400 Subject: [PATCH 12/12] Add changelog entry for Python 3.14 support --- changelog/401.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/401.feature.rst diff --git a/changelog/401.feature.rst b/changelog/401.feature.rst new file mode 100644 index 000000000..6c0754987 --- /dev/null +++ b/changelog/401.feature.rst @@ -0,0 +1 @@ +Added support for Python 3.14.