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

Add basic facilities for 3D background irfs #276

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8042e5b
Add basic facilities for 3D background irfs
Tobychev Jan 16, 2024
5c5bded
:x
Tobychev Feb 6, 2024
7c6d158
Should now support rectangular arrays
Tobychev Feb 6, 2024
2990605
Remove compatibility pins
maxnoe Apr 2, 2024
c7db045
Merge pull request #283 from cta-observatory/gammapy_pin
maxnoe Apr 3, 2024
17a7514
Add 2023 ICRC paper to README
RuneDominik Apr 8, 2024
8c48951
Merge pull request #284 from cta-observatory/Readme
maxnoe Apr 8, 2024
ec66690
Add basic facilities for 3D background irfs
Tobychev Jan 16, 2024
6d41197
Should now support rectangular arrays
Tobychev Feb 6, 2024
084a2b8
Merge remote-tracking branch 'refs/remotes/origin/background3d' into …
Tobychev Nov 6, 2024
7fc4c74
Fixes requested by Max, added test
Tobychev Nov 8, 2024
a3325f3
Add tests for more correct handling of fill-values in RadMaxEstimator
RuneDominik Feb 16, 2024
0b3e177
Add more correct handling of fill-values in RadMaxEstimator
RuneDominik Feb 16, 2024
7d8f79f
Add newsfragment
RuneDominik Mar 21, 2024
211f712
adress comments
RuneDominik Apr 8, 2024
a46b73a
Render changelog for 0.11
maxnoe May 14, 2024
1682914
Make things compatible with numpy 2.0; replace deprecated logging.warn()
LukasBeiske Sep 30, 2024
dd68f06
Add changelog entry
LukasBeiske Sep 30, 2024
fa5af1f
Update .mailmap
HealthyPear May 28, 2024
0803c77
Add option of multiple quantiles to angular_resolution
LukasBeiske Sep 30, 2024
254c4c1
No mutable default argument; check for sequence, not list and np.ndarray
LukasBeiske Oct 1, 2024
592c4c6
Do not change column naming based on number of quantiles
LukasBeiske Oct 8, 2024
38fff11
Fix docs warning
maxnoe Oct 21, 2024
b80d8fb
Address comments
LukasBeiske Oct 21, 2024
fe9e478
Call np.nanquantile with multiple quantiles
LukasBeiske Oct 21, 2024
01fb541
Rename and update changelog
LukasBeiske Nov 6, 2024
84fda49
Add 2 methods to calculate effective area in energy and 2 spacial dim…
Feb 12, 2024
68c3fa6
Add methods to calculate n_showers in energy and 2 spacial dimensions
Feb 12, 2024
242ecab
Add util for calculating FOV position angle
Feb 13, 2024
50d8002
Fix effective_area_3d and poition angle util
Feb 13, 2024
6547e22
Fix missing comma
Feb 13, 2024
b43c0aa
Fix typos causing error when calling calculate_n_showers_3d_*
Feb 15, 2024
a7c5a9a
Remove redundant argument breaking calculate_n_showers_3d call
Feb 15, 2024
e033135
Fix formatting and issues from pull request Effective Area 3D (no. 28…
Feb 15, 2024
cb58e41
Add functions to transform from sky coordinates to FOV coordinates
Mar 1, 2024
2ec0a19
Update calculate_n_showers_3d functions and add tests
Mar 1, 2024
4674679
Fix position angle function, add rectangle solid angle function and t…
Mar 1, 2024
5e38254
Update effective area 3D functions and add corresponding tests
Mar 1, 2024
8e017c5
Fix code review issues
Apr 15, 2024
2a91a87
Update function names in __all__
Apr 18, 2024
b516419
Fix all changed occurences of gadf coordinate function calls
Apr 18, 2024
e18e1ae
Change az/alt to lon/lat due to support of both AltAz and ICRS
Apr 30, 2024
3162c4a
Add newsfragment
Apr 30, 2024
8cd0e75
Properly handle viewcone_min > 0, add docstring
May 2, 2024
82b60b3
Add missing condition to all_outside check
May 14, 2024
a63a56b
Update energy_dispersion_to_migration
HealthyPear Dec 12, 2023
f3b4d04
Add function to compute energy migration matrix from events
HealthyPear Dec 12, 2023
7f2d45d
Add unit test for energy migration matrix from events
HealthyPear Dec 12, 2023
2bd128c
Update test_energy_dispersion_to_migration
HealthyPear Dec 12, 2023
4bc8f57
fix: docstring irf.energy_dispersion.energy_migration_matrix
HealthyPear Nov 7, 2024
82e2035
Add basic facilities for 3D background irfs
Tobychev Jan 16, 2024
03b9626
Fixes
Tobychev Nov 8, 2024
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: 1 addition & 2 deletions .mailmap
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
Maximilian Linhoff <[email protected]> <[email protected]>

Michele Peresano <[email protected]> Michele Peresano <[email protected]>
Michele Peresano <[email protected]> Michele Peresano <[email protected]>
Michele Peresano <[email protected]> Michele Peresano <[email protected]>

Thomas Vuillaume <[email protected]> vuillaut <[email protected]>
Thomas Vuillaume <[email protected]> Thomas Vuillaume <[email protected]>
Expand Down
37 changes: 37 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
pyirf v0.11.0 (2024-05-14)
==========================

Bug Fixes
---------

- Fix ``pyirf.benchmarks.energy_bias_resolution_from_energy_dispersion``.
This function was not adapted to the now correct normalization of the
energy dispersion matrix, resulting in wrong results on the now correct
matrices. [`#268 <https://github.com/cta-observatory/pyirf/pull/268>`__]


New Features
------------

- Adds an extrapolator for parametrized compontents utilizing blending over visible edges, resulting
in a smooth extrapolation compared to the NearestSimplexExtrapolator. [`#253 <https://github.com/cta-observatory/pyirf/pull/253>`__]

- Ignore warnings about invalid floating point operations when calculating `n_signal` and `n_signal_weigthed` because the relative sensitivty is frequently NaN. [`#264 <https://github.com/cta-observatory/pyirf/pull/264>`__]

- Add basic combinatoric fill-value handling for RAD_MAX estimation. [`#282 <https://github.com/cta-observatory/pyirf/pull/282>`__]


Maintenance
-----------

- Clarified some documentation. [`#266 <https://github.com/cta-observatory/pyirf/pull/266>`__]

- Add support for astropy 6.0. [`#271 <https://github.com/cta-observatory/pyirf/pull/271>`__]

- Added filling of CREF keyword (IRF axis order) in the output files [`#275 <https://github.com/cta-observatory/pyirf/pull/275>`__]



Refactoring and Optimization
----------------------------

pyirf v0.10.1 (2023-09-15)
==========================

Expand Down
17 changes: 17 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,20 @@ please cite it by using the corresponding DOI:

- latest : |doilatest|
- all versions: `Please visit Zenodo <https://zenodo.org/record/5833284>`_ and select the correct version

At this point, our latest publication is the `2023 ICRC proceeding <https://doi.org/10.22323/1.444.0618>`_, which you can
cite using the following bibtex entry, especially if using functionalities from ``pyirf.interpolation``:

.. code::

@inproceedings{pyirf-icrc-2023,
author = {Dominik, Rune Michael and Linhoff, Maximilian and Sitarek, Julian},
title = {Interpolation of Instrument Response Functions for the Cherenkov Telescope Array in the Context of pyirf},
usera = {for the CTA Consortium},
doi = {10.22323/1.444.0703},
booktitle = {Proceedings, 38th International Cosmic Ray Conference},
year=2023,
volume={444},
number={618},
location={Nagoya, Japan},
}
2 changes: 0 additions & 2 deletions docs/changes/253.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/changes/264.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/changes/266.maintenance.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/changes/271.maintenance.rst

This file was deleted.

4 changes: 2 additions & 2 deletions docs/changes/268.bugfix.rst → docs/changes/273.bugfix.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Fix ``pyirf.benchmarks.energy_bias_resolution_from_energy_dispersion``.
Fix ``pyirf.irfs.energy_dispersion.energy_dispersion_to_migration``.
This function was not adapted to the now correct normalization of the
energy dispersion matrix, resulting in wrong results on the now correct
matrices.
matrices.
1 change: 0 additions & 1 deletion docs/changes/275.maintenance.rst

This file was deleted.

1 change: 1 addition & 0 deletions docs/changes/276.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add function to make 3d background for lon/lat coordinates.
1 change: 0 additions & 1 deletion docs/changes/279.maintenance.rst

This file was deleted.

2 changes: 2 additions & 0 deletions docs/changes/281.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

Add 3D effective area functions for lon/lat and theta/phi coordinates and some necessary utiliy functions.
3 changes: 3 additions & 0 deletions docs/changes/289.maintenance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Make pyirf compatible with numpy 2.0.

Replace deprecated ``logging.warn`` with ``logging.warning``.
3 changes: 3 additions & 0 deletions docs/changes/290.api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Make it possible to pass multiple quantiles to ``pyirf.benchmarks.angular_resolution``, calculating all of them.

The column name(s) in the output now include(s) the percentage value of the calculated quantile, e.g. ``angular_resolution_68``.
3 changes: 1 addition & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@
html_theme = "sphinx_rtd_theme"

html_theme_options = {
'canonical_url': 'https://cta-observatory.github.io/pyirf',
'display_version': True,
'canonical_url': 'https://pyirf.readthedocs.io/',
}

intersphinx_mapping = {
Expand Down
2 changes: 1 addition & 1 deletion examples/comparison_with_EventDisplay.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@
"\n",
"plt.errorbar(\n",
" 0.5 * (ang_res['reco_energy_low'] + ang_res['reco_energy_high']).to_value(u.TeV),\n",
" ang_res['angular_resolution'].to_value(u.deg),\n",
" ang_res['angular_resolution_68'].to_value(u.deg),\n",
" xerr=0.5 * (ang_res['reco_energy_high'] - ang_res['reco_energy_low']).to_value(u.TeV),\n",
" ls='',\n",
" label='pyirf'\n",
Expand Down
24 changes: 18 additions & 6 deletions pyirf/benchmarks/angular_resolution.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections.abc import Sequence
import numpy as np
from astropy.table import QTable
from scipy.stats import norm
Expand All @@ -10,7 +11,8 @@


def angular_resolution(
events, energy_bins,
events,
energy_bins,
energy_type="true",
quantile=ONE_SIGMA_QUANTILE,
):
Expand All @@ -20,6 +22,8 @@ def angular_resolution(
This implementation corresponds to the 68% containment of the angular
distance distribution.

Passing a list of quantiles results in all the quantiles being calculated.

Parameters
----------
events : astropy.table.QTable
Expand All @@ -29,8 +33,8 @@ def angular_resolution(
energy_type: str
Either "true" or "reco" energy.
Default is "true".
quantile : float
Which quantile to use for the angular resolution,
quantile : list(float)
Which quantile(s) to use for the angular resolution,
by default, the containment of the 1-sigma region
of the normal distribution (~68%) is used.

Expand All @@ -52,8 +56,13 @@ def angular_resolution(
result[f"{energy_key}_center"] = 0.5 * (energy_bins[:-1] + energy_bins[1:])
result["n_events"] = 0

key = "angular_resolution"
result[key] = u.Quantity(np.nan, table["theta"].unit)
if not isinstance(quantile, Sequence):
quantile = [quantile]

keys = [f"angular_resolution_{value * 100:.0f}" for value in quantile]

for key in keys:
result[key] = u.Quantity(np.nan, table["theta"].unit)

# if we get an empty input (no selected events available)
# we return the table filled with NaNs
Expand All @@ -63,6 +72,9 @@ def angular_resolution(
# use groupby operations to calculate the percentile in each bin
by_bin = table[valid].group_by(bin_index[valid])
for bin_idx, group in zip(by_bin.groups.keys, by_bin.groups):
result[key][bin_idx] = np.nanquantile(group["theta"], quantile)
result["n_events"][bin_idx] = len(group)
quantile_values = np.nanquantile(group["theta"], quantile)
for key, value in zip(keys, quantile_values):
result[key][bin_idx] = value

return result
11 changes: 7 additions & 4 deletions pyirf/benchmarks/energy_bias_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import astropy.units as u

from ..binning import calculate_bin_indices, UNDERFLOW_INDEX, OVERFLOW_INDEX
from ..compat import COPY_IF_NEEDED


NORM_LOWER_SIGMA, NORM_UPPER_SIGMA = norm(0, 1).cdf([-1, 1])
Expand Down Expand Up @@ -83,8 +84,10 @@ def energy_bias_resolution(
"""

# create a table to make use of groupby operations
table = QTable(events[["true_energy", "reco_energy"]], copy=False)
table["rel_error"] = (events["reco_energy"] / events["true_energy"]).to_value(u.one) - 1
table = QTable(events[["true_energy", "reco_energy"]], copy=COPY_IF_NEEDED)
table["rel_error"] = (events["reco_energy"] / events["true_energy"]).to_value(
u.one
) - 1

energy_key = f"{energy_type}_energy"

Expand All @@ -102,7 +105,6 @@ def energy_bias_resolution(
# we return the table filled with NaNs
return result


# use groupby operations to calculate the percentile in each bin
bin_index, valid = calculate_bin_indices(table[energy_key], energy_bins)
by_bin = table.group_by(bin_index)
Expand All @@ -115,6 +117,7 @@ def energy_bias_resolution(
result["resolution"][bin_idx] = resolution_function(group["rel_error"])
return result


def energy_bias_resolution_from_energy_dispersion(
energy_dispersion,
migration_bins,
Expand Down Expand Up @@ -147,7 +150,7 @@ def energy_bias_resolution_from_energy_dispersion(
low, median, high = np.interp(
[NORM_LOWER_SIGMA, MEDIAN, NORM_UPPER_SIGMA],
cdf[energy_bin, :, fov_bin],
migration_bins[1:] # cdf is defined at upper bin edge
migration_bins[1:], # cdf is defined at upper bin edge
)
bias[energy_bin, fov_bin] = median - 1
resolution[energy_bin, fov_bin] = 0.5 * (high - low)
Expand Down
69 changes: 45 additions & 24 deletions pyirf/benchmarks/tests/test_angular_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
def test_empty_angular_resolution():
from pyirf.benchmarks import angular_resolution

events = QTable({
'true_energy': [] * u.TeV,
'theta': [] * u.deg,
})

table = angular_resolution(
events,
[1, 10, 100] * u.TeV
events = QTable(
{
"true_energy": [] * u.TeV,
"theta": [] * u.deg,
}
)

assert np.all(np.isnan(table["angular_resolution"]))
table = angular_resolution(events, [1, 10, 100] * u.TeV)

assert np.all(np.isnan(table["angular_resolution_68"]))


@pytest.mark.parametrize("unit", (u.deg, u.rad))
def test_angular_resolution(unit):
Expand All @@ -32,28 +32,32 @@ def test_angular_resolution(unit):

true_resolution = np.append(np.full(N, TRUE_RES_1), np.full(N, TRUE_RES_2))


rng = np.random.default_rng(0)

events = QTable({
'true_energy': np.concatenate([
[0.5], # below bin 1 to test with underflow
np.full(N - 1, 5.0),
np.full(N - 1, 50.0),
[500], # above bin 2 to test with overflow
]) * u.TeV,
'theta': np.abs(rng.normal(0, true_resolution)) * u.deg
})
events = QTable(
{
"true_energy": np.concatenate(
[
[0.5], # below bin 1 to test with underflow
np.full(N - 1, 5.0),
np.full(N - 1, 50.0),
[500], # above bin 2 to test with overflow
]
)
* u.TeV,
"theta": np.abs(rng.normal(0, true_resolution)) * u.deg,
}
)

events['theta'] = events['theta'].to(unit)
events["theta"] = events["theta"].to(unit)

# add nans to test if nans are ignored
events["true_energy"].value[N // 2] = np.nan
events["true_energy"].value[(2 * N) // 2] = np.nan

bins = [1, 10, 100] * u.TeV
table = angular_resolution(events, bins)
ang_res = table['angular_resolution'].to(u.deg)
ang_res = table["angular_resolution_68"].to(u.deg)
assert len(ang_res) == 2
assert u.isclose(ang_res[0], TRUE_RES_1 * u.deg, rtol=0.05)
assert u.isclose(ang_res[1], TRUE_RES_2 * u.deg, rtol=0.05)
Expand All @@ -64,9 +68,26 @@ def test_angular_resolution(unit):
# 2 sigma coverage interval
quantile = norm(0, 1).cdf(2) - norm(0, 1).cdf(-2)
table = angular_resolution(events, bins, quantile=quantile)
ang_res = table['angular_resolution'].to(u.deg)

ang_res = table["angular_resolution_95"].to(u.deg)
assert len(ang_res) == 2

assert u.isclose(ang_res[0], 2 * TRUE_RES_1 * u.deg, rtol=0.05)
assert u.isclose(ang_res[1], 2 * TRUE_RES_2 * u.deg, rtol=0.05)

# 25%, 50%, 90% coverage interval
table = angular_resolution(events, bins, quantile=[0.25, 0.5, 0.9])
cov_25 = table["angular_resolution_25"].to(u.deg)
assert len(cov_25) == 2
assert u.isclose(
cov_25[0], norm(0, TRUE_RES_1).interval(0.25)[1] * u.deg, rtol=0.05
)
assert u.isclose(
cov_25[1], norm(0, TRUE_RES_2).interval(0.25)[1] * u.deg, rtol=0.05
)

cov_50 = table["angular_resolution_50"].to(u.deg)
assert u.isclose(cov_50[0], norm(0, TRUE_RES_1).interval(0.5)[1] * u.deg, rtol=0.05)
assert u.isclose(cov_50[1], norm(0, TRUE_RES_2).interval(0.5)[1] * u.deg, rtol=0.05)

cov_90 = table["angular_resolution_90"].to(u.deg)
assert u.isclose(cov_90[0], norm(0, TRUE_RES_1).interval(0.9)[1] * u.deg, rtol=0.05)
assert u.isclose(cov_90[1], norm(0, TRUE_RES_2).interval(0.9)[1] * u.deg, rtol=0.05)
Loading
Loading