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

Check PSF and deconvol with IDL #325

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
47 changes: 0 additions & 47 deletions aiapy/calibrate/tests/test_uncertainty.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from pathlib import Path
from contextlib import nullcontext

import astropy.units as u
Expand Down Expand Up @@ -68,49 +67,3 @@ def test_flags(include_preflight, include_eve, include_chianti, expectation):
include_chianti=include_chianti,
)
assert isinstance(errors, u.Quantity)


@pytest.mark.parametrize(
("channel", "counts", "include_eve", "include_preflight", "include_chianti"),
[[c, 10 * u.ct / u.pixel] + 3 * [False] for c in CHANNELS]
+ [
[171 * u.angstrom, 1000 * u.ct / u.pix, True, False, False],
[171 * u.angstrom, 1000 * u.ct / u.pix, False, False, True],
],
)
def test_error_consistent(idl_environment, channel, counts, include_eve, include_preflight, include_chianti):
idl = """
common aia_bp_error_common,common_errtable
common_errtable=aia_bp_read_error_table('{{ error_table }}')
data = {{ data }}
channel = {{ channel }}
error=aia_bp_estimate_error(data,channel,n_sample=1{{ include_eve }}{{ include_preflight }}{{ include_chianti }})
"""
error_table = Path(idl_environment.ssw_home) / "sdo" / "aia" / "response" / "aia_V3_error_table.txt"
ssw = idl_environment.run(
idl,
save_vars=["error"],
args={
"channel": channel.to("angstrom").value,
"data": counts.to("ct pixel-1").value,
"error_table": error_table,
"include_eve": ",/evenorm" if include_eve else "",
# NOTE: use of this keyword is actually broken in SSW so these
# tests only set it to False until it works, but consistency with
# these results has been verified
"include_preflight": ",/cal" if include_preflight else "",
"include_chianti": ",/temperature" if include_chianti else "",
},
verbose=False,
)
error_ssw = ssw["error"] * counts.unit
error = estimate_error(
counts,
channel,
include_eve=include_eve,
include_preflight=include_preflight,
include_chianti=include_chianti,
error_table=error_table,
compare_idl=True,
)
assert u.allclose(error, error_ssw, rtol=1e-4)
39 changes: 6 additions & 33 deletions aiapy/conftest.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import contextlib

import astropy.units as u
import pytest
import sunpy.data.test
import sunpy.map

# Force MPL to use non-gui backends for testing.
try:
with contextlib.suppress(ImportError):
import matplotlib
except ImportError:
pass
else:
matplotlib.use("Agg")

# Do not require hissw for tests
try:
import hissw
except ImportError:
pass
matplotlib.use("Agg")


@pytest.fixture()
Expand All @@ -26,26 +20,5 @@ def aia_171_map():


@pytest.fixture(scope="session")
def idl_environment():
if idl_available():
return hissw.Environment(ssw_packages=["sdo/aia"], ssw_paths=["aia"])
pytest.skip(
"A working IDL installation is not available. You will not be able to run portions of the test suite.",
)


@pytest.fixture(scope="session")
def ssw_home():
if idl_available():
return hissw.Environment().ssw_home
return None


def idl_available():
try:
import hissw

hissw.Environment().run("")
return True
except Exception: # NOQA
return False
def channels():
return [94, 131, 171, 193, 211, 304, 335] * u.angstrom
6 changes: 0 additions & 6 deletions aiapy/psf/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
"""
Shared fixtures for PSF tests.
"""
import astropy.units as u
import pytest

import aiapy.psf


@pytest.fixture(scope="module")
def channels():
return [94, 131, 171, 193, 211, 304, 335] * u.angstrom


@pytest.fixture()
def psf(channels):
return aiapy.psf.psf(channels[0], use_preflightcore=True, diffraction_orders=[-1, 0, 1])
34 changes: 0 additions & 34 deletions aiapy/psf/tests/test_psf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,6 @@
]


@pytest.fixture()
def psf_full(channels):
return aiapy.psf.psf(channels[0], use_preflightcore=True)


@pytest.fixture(scope="module")
def psf_idl(idl_environment, channels):
"""
The point spread function as calculated by aia_calc_psf.pro.
"""
r = idl_environment.run(
"psf = aia_calc_psf({{channel}},/use_preflightcore)",
args={"channel": f"{channels[0].value:.0f}"},
save_vars=["psf"],
verbose=False,
)
return r["psf"]


@pytest.mark.parametrize("use_preflightcore", [True, False])
def test_filter_mesh_parameters(use_preflightcore, channels):
params = aiapy.psf.filter_mesh_parameters(use_preflightcore=use_preflightcore)
Expand All @@ -44,18 +25,3 @@ def test_filter_mesh_parameters(use_preflightcore, channels):
def test_psf(psf):
assert isinstance(psf, np.ndarray)
assert psf.shape == (4096, 4096)


def test_psf_consistent(psf_full, psf_idl):
"""
Check whether PSF is consistent with IDL calculation.

.. note:: This test will take a very long time to run.
"""
# NOTE: The IDL and Python PSF functions have been found to
# agree within 0.2% for all points along the PSF arms for
# both the preflight and non-preflight cases.
# NOTE: Only compare values above some threshold as the
# rest of the PSF is essentially noise
i_valid = np.where(psf_idl > 1e-10)
assert np.allclose(psf_full[i_valid], psf_idl[i_valid], atol=0.0, rtol=2e-3)
125 changes: 125 additions & 0 deletions aiapy/tests/test_idl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""
Contains all the the IDL specific tests for aiapy.
"""
from pathlib import Path

import astropy.units as u
import numpy as np
import pytest
from sunpy import log

import aiapy.psf
from aiapy.calibrate import estimate_error

CHANNELS = [94, 131, 171, 193, 211, 304, 335, 1600, 1700, 4500] * u.angstrom


def idl_available():
try:
import hissw

hissw.Environment().run("")
return True

Check warning on line 22 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L22

Added line #L22 was not covered by tests
except Exception as e: # NOQA
log.waring(e)
return False

Check warning on line 25 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L25

Added line #L25 was not covered by tests


@pytest.fixture(scope="session")
def idl_environment():
if idl_available():
import hissw

Check warning on line 31 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L31

Added line #L31 was not covered by tests

return hissw.Environment(

Check warning on line 33 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L33

Added line #L33 was not covered by tests
ssw_packages=["sdo/aia"],
ssw_paths=["aia"],
)
pytest.skip(

Check warning on line 37 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L37

Added line #L37 was not covered by tests
"A working IDL installation is not available. You will not be able to run portions of the test suite.",
)


@pytest.fixture(scope="session")
def ssw_home(idl_environment):
return idl_environment.ssw_home if idl_available() else None

Check warning on line 44 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L44

Added line #L44 was not covered by tests


@pytest.mark.parametrize(
("channel", "counts", "include_eve", "include_preflight", "include_chianti"),
[[c, 10 * u.ct / u.pixel] + 3 * [False] for c in CHANNELS]
+ [
[171 * u.angstrom, 1000 * u.ct / u.pix, True, False, False],
[171 * u.angstrom, 1000 * u.ct / u.pix, False, False, True],
],
)
def test_error_consistent(idl_environment, channel, counts, include_eve, include_preflight, include_chianti):
idl = """

Check warning on line 56 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L56

Added line #L56 was not covered by tests
common aia_bp_error_common,common_errtable
common_errtable=aia_bp_read_error_table('{{ error_table }}')
data = {{ data }}
channel = {{ channel }}
error=aia_bp_estimate_error(data,channel,n_sample=1{{ include_eve }}{{ include_preflight }}{{ include_chianti }})
"""
error_table = Path(idl_environment.ssw_home) / "sdo" / "aia" / "response" / "aia_V3_error_table.txt"
ssw = idl_environment.run(

Check warning on line 64 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L63-L64

Added lines #L63 - L64 were not covered by tests
idl,
save_vars=["error"],
args={
"channel": channel.to("angstrom").value,
"data": counts.to("ct pixel-1").value,
"error_table": error_table,
"include_eve": ",/evenorm" if include_eve else "",
# NOTE: use of this keyword is actually broken in SSW so these
# tests only set it to False until it works, but consistency with
# these results has been verified
"include_preflight": ",/cal" if include_preflight else "",
"include_chianti": ",/temperature" if include_chianti else "",
},
verbose=False,
)
error_ssw = ssw["error"] * counts.unit
error = estimate_error(

Check warning on line 81 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L80-L81

Added lines #L80 - L81 were not covered by tests
counts,
channel,
include_eve=include_eve,
include_preflight=include_preflight,
include_chianti=include_chianti,
error_table=error_table,
compare_idl=True,
)
assert u.allclose(error, error_ssw, rtol=1e-4)

Check warning on line 90 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L90

Added line #L90 was not covered by tests


@pytest.fixture(scope="session")
def psf_full(channels):
return aiapy.psf.psf(channels[0], use_preflightcore=True)


@pytest.fixture(scope="module")
@pytest.mark.parametrize("channel", CHANNELS)
def psf_idl(idl_environment, channels):
"""
The point spread function as calculated by aia_calc_psf.pro.
"""
r = idl_environment.run(

Check warning on line 104 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L104

Added line #L104 was not covered by tests
"psf = aia_calc_psf({{channel}},/use_preflightcore)",
args={"channel": f"{channels[0].value:.0f}"},
save_vars=["psf"],
verbose=False,
)
return r["psf"]

Check warning on line 110 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L110

Added line #L110 was not covered by tests


def test_psf_consistent(psf_full, psf_idl):
"""
Check whether PSF is consistent with IDL calculation.

.. note:: This test will take a very long time to run.
"""
# NOTE: The IDL and Python PSF functions have been found to
# agree within 0.2% for all points along the PSF arms for
# both the preflight and non-preflight cases.
# NOTE: Only compare values above some threshold as the
# rest of the PSF is essentially noise
i_valid = np.where(psf_idl > 1e-10)
assert np.allclose(psf_full[i_valid], psf_idl[i_valid], atol=0.0, rtol=2e-3)

Check warning on line 125 in aiapy/tests/test_idl.py

View check run for this annotation

Codecov / codecov/patch

aiapy/tests/test_idl.py#L124-L125

Added lines #L124 - L125 were not covered by tests
Loading