Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding xrt_teem #89

Merged
merged 50 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c442075
Added xrt_teem.py
jslavin Sep 20, 2022
045ae37
small tweaks to xrt_teem.py
jslavin Sep 20, 2022
05be3f6
Delete xrt_teem.py
jslavin Sep 21, 2022
f2b4210
Add files via upload
jslavin Sep 21, 2022
5d8fb21
Delete xrt_teem.py
jslavin Nov 29, 2022
21856d7
improved version of xrt_teem
jslavin Nov 29, 2022
ca0c2f6
fixes to xrt_teem.py
jslavin Nov 30, 2022
2749141
Merge branch 'HinodeXRT:main' into jslavin-patch-2
jslavin Dec 1, 2022
79727c0
Added tests for xrt_teem. Also edited setup.cfg to remove line that w…
jslavin Dec 9, 2022
16e1df8
edited setup.cfg
jslavin Dec 9, 2022
fe0a769
Merge branch 'jslavin-patch-2' of https://github.com/jslavin/xrtpy in…
jslavin Dec 9, 2022
6cc2d94
Added notebook on usage of xrt_teem
jslavin Dec 9, 2022
b07863d
Fixed header for xrt_teem so as to pass flake8 rst checks
jslavin Dec 12, 2022
d03c5ce
fixed file reference and tolerances in test_xrt_teem.py
jslavin Dec 12, 2022
75f8c2f
Merge branch 'HinodeXRT:main' into jslavin-patch-2
jslavin Dec 12, 2022
6307e40
Update xrtpy/response/xrt_teem.py
jslavin Dec 14, 2022
31362a8
Update xrtpy/response/xrt_teem.py
jslavin Dec 14, 2022
40cfc5d
Update xrtpy/response/xrt_teem.py
jslavin Dec 14, 2022
e80f8d9
Changed variable Te to T_e and also Terror to T_error to avoid issues…
jslavin Dec 15, 2022
c87c151
Removed reference to variable name Te which slipped through in merge
jslavin Dec 15, 2022
bbe1132
Merge branch 'HinodeXRT:main' into jslavin-patch-2
jslavin Jan 25, 2023
cb3da6d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 25, 2023
be6df43
updated .gitignore
jslavin Jan 25, 2023
7b870d8
Merge branch 'jslavin-patch-2' of https://github.com/jslavin/xrtpy in…
jslavin Jan 26, 2023
44f9e85
Changed from headers and data array inputs to using SunPy maps
jslavin Jan 26, 2023
30761b8
Update getting_started.rst
jslavin Jan 26, 2023
bb81bfa
Merge branch 'HinodeXRT:main' into jslavin-patch-2
jslavin Jan 31, 2023
3579b9f
Split off parts of the main routine into functions derive_temperature…
jslavin Jan 31, 2023
5d51116
Merge branch 'HinodeXRT:main' into jslavin-patch-2
jslavin Feb 2, 2023
39b0956
Merge branch 'jslavin-patch-2' of https://github.com/jslavin/xrtpy in…
jslavin Feb 2, 2023
6269dfd
Changed output from xrt_teem to be SunPy maps. Updated tests and note…
jslavin Feb 7, 2023
baab3e3
Fixed typos in test_xrt_teem.py
jslavin Feb 7, 2023
d9a7aaa
Change header doc section to note
jslavin Feb 9, 2023
55a965f
reStructured quoting added
jslavin Feb 9, 2023
31722b7
more rst quoting
jslavin Feb 9, 2023
6393b23
include __all__ definition
jslavin Feb 9, 2023
62823d4
Merge branch 'HinodeXRT:main' into jslavin-patch-2
jslavin Feb 13, 2023
fb94fb0
Another substitution of reStructuredText |Map| for map
jslavin Feb 13, 2023
f3b7e74
reStructuredText substitution of |Map| for map
jslavin Feb 13, 2023
792f6d4
Removed comments on units of effective area
jslavin Feb 13, 2023
e415cf2
Created measurement_to_filtername function for converting SunPy Map m…
jslavin Feb 13, 2023
9bd8c1f
Merge branch 'jslavin-patch-2' of https://github.com/jslavin/xrtpy in…
jslavin Feb 13, 2023
ef4e499
Fixed error in variable name in measurement_to_filtername
jslavin Feb 13, 2023
51b38f5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 13, 2023
d8fee3a
Add api_static stub file for xrt_teem
namurphy Feb 13, 2023
6a08fdf
Add notebook to example TOC
namurphy Feb 13, 2023
9ee5289
Merge branch 'main' of github.com:HinodeXRT/xrtpy into jslavin-patch-2
namurphy Feb 13, 2023
071a9ac
Ignore 'missing substitutions' flake8 extension error
namurphy Feb 13, 2023
60cc5b2
Merge branch 'main' of github.com:HinodeXRT/xrtpy into jslavin-patch-2
namurphy Feb 13, 2023
9db5b49
Fix TOC for example gallery
namurphy Feb 13, 2023
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,6 @@ version.py
#ignore mac files
.DS_store
.DS_Store

# local directory
idl_routines/
8 changes: 8 additions & 0 deletions docs/api_static/xrtpy.response.xrt_teem.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
:orphan:

`xrtpy.response.xrt_teem`
=========================

.. currentmodule:: xrtpy.response.xrt_teem

.. automodapi:: xrtpy.response.xrt_teem
Comment on lines +1 to +8
Copy link
Contributor

Choose a reason for hiding this comment

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

When we add a new module, we often need to add a stub documentation file so that the docstrings from the module show up in the online documentation.

8 changes: 8 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,11 @@ Computing response functions
:glob:

notebooks/computing_functions/*

Data analysis
-------------

.. nbgallery::
:glob:

Using_xrt_teem
4 changes: 4 additions & 0 deletions docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ The default model assumes coronal abundances :cite:t:`feldman:1992`.
.. note::
XRTpy has future plans to accept other plasma emission spectra models.

Deriving Temperature and Emission Measure for a Pair of Images
--------------------------------------------------------------
XRTpy provides a routine, xrt_teem, that employs the objects listed above to derive the temperature and emission measure in for a given pair of images using the filter ratio method. This uses the same methods as in the SolarSoft IDL routine of the same name.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
XRTpy provides a routine, xrt_teem, that employs the objects listed above to derive the temperature and emission measure in for a given pair of images using the filter ratio method. This uses the same methods as in the SolarSoft IDL routine of the same name.
XRTpy provides a routine, `~xrtpy.response.xrt_teem.xrt_teem`, that
employs the objects listed above to derive the temperature and emission
measure in for a given pair of images using the filter ratio method.
This uses the same methods as in the SolarSoft IDL routine of the same
name.

The single backticks are for generating a link to the object in the documentation build, and the tilde indicates that the namespace prefixes should be hidden.

There's also a convention to limit lines in documentation to 72 characters (from PEP 8, I think?).



X-Ray Filter Channel
*********************
Expand Down
191 changes: 191 additions & 0 deletions docs/notebooks/data_analysis/Using_xrt_teem.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "642ac1b3",
"metadata": {},
"source": [
"# Using xrt_teem to analyze XRT data"
]
},
{
"cell_type": "markdown",
"id": "22b53fce",
"metadata": {},
"source": [
"This example demonstrates how to use xrt_teem to calculate the temperature and emission measure in an image using the filter ratio method."
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"This example demonstrates how to use xrt_teem to calculate the temperature and emission measure in an image using the filter ratio method."
"This example demonstrates how to use `xrt_teem` to calculate the temperature and emission measure in an image using the filter ratio method."

...so it shows up as literal text in Markdown.

]
},
{
"cell_type": "markdown",
"id": "f5f04496",
"metadata": {},
"source": [
"First we need to import xrt_teem."
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"First we need to import xrt_teem."
"First we need to import `xrt_teem`."

]
},
{
"cell_type": "code",
"execution_count": null,
"id": "58758bf1",
"metadata": {},
"outputs": [],
"source": [
"from xrtpy.response.xrt_teem import xrt_teem"
]
},
{
"cell_type": "markdown",
"id": "8aee2bae",
"metadata": {},
"source": [
"As an example we will use the test data included in XRTpy, though data with the right characteristics in the XRT archive could also be used. It's necessary to use two images that are the same size and use different filters. To get good results the images should have been taken close in time as well, ideally adjacent in time. Note that not all filter ratios produce good results. \n",
"\n",
"This data was generated using the IDL routine xrt_prep.pro from SolarSoft and is unnormalized. Data in the Level 1 archive are normalized, which is also okay to use, though the IDL routine xrt_teem.pro did not allow that. For normalized data the image data is multiplied by the exposure time before analysis. "
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"This data was generated using the IDL routine xrt_prep.pro from SolarSoft and is unnormalized. Data in the Level 1 archive are normalized, which is also okay to use, though the IDL routine xrt_teem.pro did not allow that. For normalized data the image data is multiplied by the exposure time before analysis. "
"This data was generated using the IDL routine `xrt_prep.pro` from SolarSoft and is unnormalized. Data in the Level 1 archive are normalized, which is also okay to use, though the IDL routine `xrt_teem.pro` did not allow that. For normalized data the image data is multiplied by the exposure time before analysis. "

The explanations in this notebook are very well written.

]
},
{
"cell_type": "code",
"execution_count": null,
"id": "da83268f",
"metadata": {},
"outputs": [],
"source": [
"import pkg_resources\n",
"import sunpy.map\n",
"\n",
"from pathlib import Path\n",
"\n",
"directory = pkg_resources.resource_filename(\n",
" \"xrtpy\", \"response/tests/data/xrt_teem_testing_files\"\n",
")\n",
"data_files = sorted(Path(directory).glob(\"L1_XRT20110128_*.*.fits\"))\n",
"file1 = data_files[1]\n",
"file2 = data_files[0]"
]
},
{
"cell_type": "markdown",
"id": "35dd0c83",
"metadata": {},
"source": [
"xrt_teem uses SunPy maps as input. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "48ac4220",
"metadata": {},
"outputs": [],
"source": [
"map1 = sunpy.map.Map(file1)\n",
"map2 = sunpy.map.Map(file2)"
]
},
{
"cell_type": "markdown",
"id": "905f4e11",
"metadata": {},
"source": [
"xrt_teem has several options, mirroring the IDL routine 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."
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"xrt_teem has several options, mirroring the IDL routine 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."
"`xrt_teem` has several options, mirroring the IDL routine 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."

]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ddc9862b",
"metadata": {},
"outputs": [],
"source": [
"T_e, EM, Terr, EMerr = xrt_teem(map1, map2)"
]
},
{
"cell_type": "markdown",
"id": "d0ef85f3",
"metadata": {},
"source": [
"The outputs of xrt_teem are also SunPy maps. T_e is the electron temperature, EM is the volume emission measure, Terr is a measure of the uncertainties in the temperature determined for each pixel and EMerr is the same for the emission measure. Each map has data and associated metadata. To examine the results one can use matplotlib and sunpy:"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"The outputs of xrt_teem are also SunPy maps. T_e is the electron temperature, EM is the volume emission measure, Terr is a measure of the uncertainties in the temperature determined for each pixel and EMerr is the same for the emission measure. Each map has data and associated metadata. To examine the results one can use matplotlib and sunpy:"
"The outputs of `xrt_teem` are also SunPy `Map` objects. `T_e` is the electron temperature, `EM` is the volume emission measure, `Terr` is a measure of the uncertainties in the temperature determined for each pixel and `EMerr` is the same for the emission measure. Each map has data and associated metadata. To examine the results one can use matplotlib and sunpy:"

]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3ae1f53b",
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
"from sunpy.coordinates.sun import angular_radius, B0\n",
"from sunpy.map import Map\n",
"\n",
"# To avoid error messages from sunpy we add metadata to the header:\n",
"rsun_ref = 6.95700e08\n",
"hdr1 = map1.meta\n",
"rsun_obs = angular_radius(hdr1[\"DATE_OBS\"]).value\n",
"dsun = rsun_ref / np.sin(rsun_obs * np.pi / 6.48e5)\n",
"solarb0 = B0(hdr1[\"DATE_OBS\"]).value\n",
"hdr1[\"DSUN_OBS\"] = dsun\n",
"hdr1[\"RSUN_REF\"] = rsun_ref\n",
"hdr1[\"RSUN_OBS\"] = rsun_obs\n",
"hdr1[\"SOLAR_B0\"] = solarb0\n",
"\n",
"fig = plt.figure()\n",
"# We could create a plot simply by doing T_e.plot(), but here we choose to make a linear plot of T_e\n",
"m = Map((10.0**T_e.data, T_e.meta))\n",
"m.plot(title=\"Derived Temperature\", vmin=2.0e6, vmax=1.2e7, cmap=\"turbo\")\n",
"m.draw_limb()\n",
"m.draw_grid(linewidth=2)\n",
"cb = plt.colorbar(label=\"T (K)\")"
]
},
{
"cell_type": "markdown",
"id": "4e069966",
"metadata": {},
"source": [
"See the xrt_teem.py code for more information. Among the options are verbose output, binning the data by an integer factor (to increase the signal to noise), specifying a temperature range to examine, providing a mask for excluding regions of the images from the analysis, and setting error thresholds on the temperature and photon noise that differ from the default values."
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"See the xrt_teem.py code for more information. Among the options are verbose output, binning the data by an integer factor (to increase the signal to noise), specifying a temperature range to examine, providing a mask for excluding regions of the images from the analysis, and setting error thresholds on the temperature and photon noise that differ from the default values."
"See the `xrt_teem.py` code for more information. Among the options are verbose output, binning the data by an integer factor (to increase the signal to noise), specifying a temperature range to examine, providing a mask for excluding regions of the images from the analysis, and setting error thresholds on the temperature and photon noise that differ from the default values."

]
},
{
"cell_type": "markdown",
"id": "94df8fee",
"metadata": {},
"source": [
"These data were analyzed by Guidoni et al. (2015, ApJ 800, 54). See also Narukage et al. (2014, Solar Phys. 289, 1029). The filters for these two images are Ti poly and Be thin. "
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think it might be worth putting in a DOI hyperlink to these articles?

]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2807a18e",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ extend-ignore =
W605,
RST210,
RST213,
RST305,
Copy link
Contributor

Choose a reason for hiding this comment

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

I forgot to add this error code as one of the linter checks to ignore. This one checks for undefined substitutions, but isn't smart enough to check for our globally defined substitutions.

RST306

exclude =
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

141 changes: 141 additions & 0 deletions xrtpy/response/tests/test_xrt_teem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import numpy as np
import pkg_resources
import pytest
import sunpy.map

from astropy.io import fits
from pathlib import Path
from scipy.io import readsav

from xrtpy.response.xrt_teem import xrt_teem


def get_observed_data():
directory = pkg_resources.resource_filename(
"xrtpy", "response/tests/data/xrt_teem_testing_files"
)
data_files = sorted(Path(directory).glob("L1_XRT20110128_*.*.fits"))

return data_files
Comment on lines +17 to +19
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
data_files = sorted(Path(directory).glob("L1_XRT20110128_*.*.fits"))
return data_files
return sorted(Path(directory).glob("L1_XRT20110128_*.*.fits"))

...although sometimes an intermediate variable name can make code more readable.



def get_IDL_results_data():
directory = pkg_resources.resource_filename(
"xrtpy", "response/tests/data/xrt_teem_testing_files"
)
results_files = sorted(Path(directory).glob("IDL_results_*.sav"))

return results_files
Comment on lines +26 to +28
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
results_files = sorted(Path(directory).glob("IDL_results_*.sav"))
return results_files
return sorted(Path(directory).glob("IDL_results_*.sav"))



def rebin_image(data, binfac=1):
"""
Given a data array and a binning factor return the data array rebinned by
the binning factor.
"""

s = data.shape
ns = (s[0] // binfac, s[1] // binfac)
rbs = (ns[0], binfac, ns[1], binfac)
# sums the data in binfac x binfac sized regions
drbin = data.reshape(rbs).mean(-1).mean(1)
# for a boolean mask, this makes a pixel masked if any of the summed
# pixels is masked. If we want to mask only if all the pixels are masked
# then we could use prod in place of sum above

if data.dtype == bool:
# need to convert back to bool after summing
drbin = drbin.astype(bool)
return drbin
Comment on lines +46 to +49
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if data.dtype == bool:
# need to convert back to bool after summing
drbin = drbin.astype(bool)
return drbin
return drbin.astype(bool) if data.dtype == bool else drbin

[optional]



def test_standard_case():
"""
Test case with all default values:
no binning, no masking, no temperature range, standard thresholds
"""

data_files = get_observed_data()
# it turns out that the IDL test data was generated with the inverse order
# of the files
file1 = data_files[1]
file2 = data_files[0]
map1 = sunpy.map.Map(file1)
map2 = sunpy.map.Map(file2)

T_e, EM, Terr, EMerr = xrt_teem(map1, map2)

testdata = get_IDL_results_data()

# This is needed because there are multiple test data sets, though so far
# only a test written for the standard case
fnames = [td.name for td in testdata]
idata1 = fnames.index("IDL_results_bin1.sav")
testdata1 = testdata[idata1]

idldata = readsav(testdata1)
goodT = (T_e.data > 0.0) & (idldata.te > 0.0)
goodE = (EM.data > 0.0) & (idldata.em > 0.0)
assert np.allclose(
10.0 ** T_e.data[goodT], 10.0 ** idldata.te[goodT], atol=2.0e5, rtol=0.02
)
assert np.allclose(
10.0 ** EM.data[goodE], 10.0 ** idldata.em[goodE], atol=4.0e44, rtol=0.03
)
assert np.allclose(
10.0 ** Terr.data[goodT], 10.0 ** idldata.et[goodT], atol=1.0e4, rtol=0.08
)
assert np.allclose(
10.0 ** EMerr.data[goodE], 10.0 ** idldata.ee[goodE], atol=4.0e43, rtol=0.02
)


def test_binning_case():
"""
Test case with following parameters:
binning by a factor of 2
no masking
no temperature range
standard thresholds
"""

data_files = get_observed_data()
# it turns out that the IDL test data was generated with the inverse order
# of the files
file1 = data_files[1]
file2 = data_files[0]
map1 = sunpy.map.Map(file1)
map2 = sunpy.map.Map(file2)

T_e, EM, Terr, EMerr = xrt_teem(map1, map2, binfac=2)

testdata = get_IDL_results_data()

# This is needed because there are multiple test data sets
fnames = [td.name for td in testdata]
idata1 = fnames.index("IDL_results_bin2.sav")
testdata1 = testdata[idata1]

idldata = readsav(testdata1)
idlTe = rebin_image(idldata.te, 2)
idlEM = rebin_image(idldata.em, 2)
idlTerr = rebin_image(idldata.et, 2)
idlEMerr = rebin_image(idldata.ee, 2)
goodT = (T_e.data > 0.0) & (idlTe > 0.0)
goodE = (EM.data > 0.0) & (idlEM > 0.0)

delta = 10.0 ** T_e.data[goodT] - 10.0 ** idlTe[goodT]
x = 10.0 ** idlTe[goodT]

assert np.allclose(
10.0 ** T_e.data[goodT], 10.0 ** idlTe[goodT], atol=2.0e5, rtol=0.02
)
assert np.allclose(
10.0 ** EM.data[goodE], 10.0 ** idlEM[goodE], atol=1.0e44, rtol=0.05
)
assert np.allclose(
10.0 ** Terr.data[goodT], 10.0 ** idlTerr[goodT], atol=1.0e4, rtol=0.1
)
assert np.allclose(
10.0 ** EMerr.data[goodE], 10.0 ** idlEMerr[goodE], atol=2.0e43, rtol=0.03
)
Loading