Skip to content

Commit ef85e4b

Browse files
authored
Merge pull request #22 from fact-project/fixes
Improve units handling in gadf
2 parents 2718565 + 434827f commit ef85e4b

File tree

5 files changed

+63
-60
lines changed

5 files changed

+63
-60
lines changed

README.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
# FACT irf
22
Tools to calculate IRFs (instrument response functions) for the FACT telescope.
33

4-
Install pyeventio first `pip install eventio==0.3.0`.
5-
64
# Joint Crab Data and the FACT Open Data Release
75

8-
The FACT open data release contains 10.6 hours of Crab Nebula observations taken in October 2013 by the First G-APD Cherenkov Telescope (FACT)
6+
The FACT open data release contains 17.7 hours of Crab Nebula observations taken in October 2013 by the First G-APD Cherenkov Telescope (FACT)
97
FACT is located on the Roque des los Muchachos on the Canary island of La Palma off the west coast of Africa. It is an imaging atmospheric
108
cherenkov telescope protoyping silicon-photomultipliers.
119
FACT data is stored in FITS files from the raw data level up to higher levels containing the results of our analysis.
@@ -23,9 +21,10 @@ Or contact the fact-online mailing list at
2321
2422

2523
For the joint crab publication we manually selected a smaller dataset
26-
due to some runs having bad weather.
24+
due to some runs having bad weather and getting a dataset with roughly equal
25+
number of excess events for each experiment.
2726

2827
```
2928
python irf/scripts/fact_dl3_to_gadf.py -c 0.8 -t 0.03 ../gamma_diffuse_showers.hdf5 ../gamma_diffuse_precuts.hdf5 ../crab_dl3.hdf5 fact_dl3 --start '2013/11/04 00:00' --end '2013/11/07' -e 20131104_196 -e 20131105_175 -e 20131105_176 -e 20131105_199 -e 20131105_201
3029
31-
```
30+
```

irf/collection_area.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ def histograms(
1010
all_events,
1111
selected_events,
1212
bins,
13-
range=None,
1413
):
1514
'''
1615
Create histograms in the given bins for two vectors.
@@ -64,9 +63,6 @@ def collection_area(
6463
sample_fraction: float
6564
The fraction of `all_events` that was analysed
6665
to create `selected_events`
67-
sample_fraction: float
68-
The fraction of `all_events` that was analysed
69-
to create `selected_events`
7066
smoothing: float
7167
The amount of smoothing to apply to the resulting matrix
7268
'''
@@ -94,7 +90,6 @@ def collection_area(
9490
area = (hist_selected / hist_all) * np.pi * impact**2
9591

9692
if smoothing > 0:
97-
a = area.copy()
98-
area = gaussian_filter(a.value, sigma=smoothing, ) * area.unit
93+
area = gaussian_filter(area.value, sigma=smoothing) * area.unit
9994

10095
return area, bin_center, bin_width, lower_conf, upper_conf

irf/energy_dispersion.py

+38-32
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,27 @@
33
from scipy.ndimage.filters import gaussian_filter
44

55

6-
7-
def _make_energy_bins(energy_true, energy_prediction, bins):
6+
@u.quantity_input(energy_true=u.TeV, energy_prediction=u.TeV)
7+
def _make_energy_bins(energy_true, energy_prediction, bins, e_ref=1 * u.TeV):
88
e_min = min(
9-
min(energy_true),
10-
min(energy_prediction)
9+
np.min(energy_true),
10+
np.min(energy_prediction)
1111
)
1212

1313
e_max = max(
14-
max(energy_true),
15-
max(energy_prediction)
14+
np.max(energy_true),
15+
np.max(energy_prediction)
1616
)
1717

18-
low = np.log10(e_min.value)
19-
high = np.log10(e_max.value)
18+
low = np.log10(e_min / e_ref)
19+
high = np.log10(e_max / e_ref)
2020
bin_edges = np.logspace(low, high, endpoint=True, num=bins + 1)
2121

22-
return bin_edges
23-
22+
return bin_edges * e_ref
2423

2524

2625
@u.quantity_input(energy_true=u.TeV, energy_prediction=u.TeV)
27-
def energy_dispersion(energy_true, energy_prediction, bins=10, normalize=False, smoothing=0):
26+
def energy_dispersion(energy_true, energy_prediction, bins=10, normalize=False, smoothing=0, e_ref=1 * u.TeV):
2827
'''
2928
Creates energy dispersion matrix i.e. a histogram of e_reco vs e_true.
3029
@@ -43,6 +42,8 @@ def energy_dispersion(energy_true, energy_prediction, bins=10, normalize=False,
4342
Amount of smoothing to apply to the generated matrices.
4443
Equivalent to the sigma parameter in
4544
https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html
45+
e_ref: astropy.unit.Quantity[energy]
46+
Reference energy
4647
Returns
4748
-------
4849
@@ -55,28 +56,25 @@ def energy_dispersion(energy_true, energy_prediction, bins=10, normalize=False,
5556
5657
'''
5758
if np.isscalar(bins):
58-
bins = _make_energy_bins(energy_true, energy_prediction, bins)
59+
bins = _make_energy_bins(energy_true, energy_prediction, bins, e_ref=e_ref)
5960

6061
hist, bins_e_true, bins_e_prediction = np.histogram2d(
61-
energy_true.value,
62-
energy_prediction,
63-
bins=bins,
62+
(energy_true / e_ref).to_value(u.dimensionless_unscaled),
63+
(energy_prediction / e_ref).to_value(u.dimensionless_unscaled),
64+
bins=(bins / e_ref).to_value(u.dimensionless_unscaled),
6465
)
6566

6667
if smoothing > 0:
6768
hist = gaussian_filter(hist, sigma=smoothing)
6869

6970
if normalize:
70-
with np.errstate(invalid='ignore'):
71-
h = hist.T
72-
h = h / h.sum(axis=0)
73-
hist = np.nan_to_num(h).T
71+
hist = _normalize_hist(hist)
7472

75-
return hist, bins_e_true * energy_true.unit, bins_e_prediction * energy_true.unit
73+
return hist, bins_e_true, bins_e_prediction
7674

7775

7876
@u.quantity_input(energy_true=u.TeV, energy_prediction=u.TeV)
79-
def energy_migration(energy_true, energy_prediction, bins_energy=10, bins_mu=10, normalize=True, smoothing=0):
77+
def energy_migration(energy_true, energy_prediction, bins_energy=10, bins_mu=10, normalize=True, smoothing=0, e_ref=1 * u.TeV):
8078
'''
8179
Creates energy migration matrix i.e. a histogram of e_reco/e_true vs e_trueself.
8280
@@ -97,6 +95,8 @@ def energy_migration(energy_true, energy_prediction, bins_energy=10, bins_mu=10,
9795
Amount of smoothing to apply to the generated matrices.
9896
Equivalent to the sigma parameter in
9997
https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html
98+
e_ref: astropy.unit.Quantity[energy]
99+
Reference energy
100100
Returns
101101
-------
102102
@@ -109,26 +109,32 @@ def energy_migration(energy_true, energy_prediction, bins_energy=10, bins_mu=10,
109109
110110
'''
111111
if np.isscalar(bins_energy):
112-
bins_energy = _make_energy_bins(energy_true, energy_prediction, bins_energy)
112+
bins_energy = _make_energy_bins(
113+
energy_true, energy_prediction, bins_energy, e_ref=e_ref
114+
)
113115

114-
migra = (energy_prediction / energy_true).si.value
116+
migra = (energy_prediction / energy_true).to_value(u.dimensionless_unscaled)
115117

116118
if np.isscalar(bins_mu):
117-
bins_mu = np.linspace(0, 6, endpoint=True, num=bins_mu + 1)
119+
bins_mu = np.linspace(0, 6, bins_mu + 1)
118120

119121
hist, bins_e_true, bins_mu = np.histogram2d(
120-
energy_true.value,
122+
(energy_true / e_ref).to_value(u.dimensionless_unscaled),
121123
migra,
122-
bins=[bins_energy, bins_mu],
124+
bins=[(bins_energy / e_ref).to_value(u.dimensionless_unscaled), bins_mu],
123125
)
124126

125127
if smoothing > 0:
126-
hist = gaussian_filter(hist, sigma=smoothing, )
128+
hist = gaussian_filter(hist, sigma=smoothing)
127129

128130
if normalize:
129-
with np.errstate(invalid='ignore'):
130-
h = hist.T
131-
h = h / h.sum(axis=0)
132-
hist = np.nan_to_num(h).T
131+
hist = _normalize_hist(hist)
132+
133+
return hist, bins_energy, bins_mu
134+
133135

134-
return hist, bins_energy * energy_true.unit, bins_mu
136+
def _normalize_hist(hist):
137+
with np.errstate(invalid='ignore'):
138+
h = hist.T
139+
h = h / h.sum(axis=0)
140+
return np.nan_to_num(h).T

irf/gadf/hdus.py

+19-16
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from astropy.table import Table
1212
from astropy.time import Time
1313
import numpy as np
14-
import datetime
1514
from irf.gadf.time import timestamp_to_mjdref, ontime_info_from_runs, TIME_INFO
1615

1716

@@ -41,12 +40,11 @@ def create_primary_hdu():
4140
header['OBSERVER'] = 'The FACT collaboration'
4241
header['COMMENT'] = 'FACT OGA.'
4342
header['COMMENT'] = 'See https://gamma-astro-data-formats.readthedocs.io/en/latest/'
44-
header['COMMENT'] = 'This file was created by https://github.com/fact-project/irf'
45-
header['COMMENT'] = 'See our full analysis on GitHub'
43+
header['COMMENT'] = 'See our Open Crab analysis on GitHub'
4644
header['COMMENT'] = 'https://github.com/fact-project/open_crab_sample_analysis'
4745

48-
now = Time.now().iso
49-
header['COMMENT'] = f'This file was created on {now}'
46+
header['CREATOR'] = 'This file was created by https://github.com/fact-project/irf'
47+
header['DATE'] = Time.now().iso
5048

5149
return fits.PrimaryHDU(header=header)
5250

@@ -63,17 +61,23 @@ def create_events_hdu(dl3, run):
6361
event_id = dl3.index
6462

6563
# convert from hour angles to deg
66-
ra = dl3.ra_prediction.values * u.hourangle
64+
ra = u.Quantity(dl3.ra_prediction.values, u.hourangle, copy=False)
6765
ra = ra.to('deg')
6866

69-
dec = dl3.dec_prediction.values * u.deg
67+
dec = u.Quantity(dl3.dec_prediction.values, u.deg, copy=False)
7068

7169
# convert to TeV energy
72-
energy = dl3.gamma_energy_prediction.values * u.GeV
70+
energy = u.Quantity(dl3.gamma_energy_prediction.values, u.GeV, copy=False)
7371
energy = energy.to('TeV')
7472

7573
timestamp = timestamp_to_mjdref(dl3.timestamp)
76-
t = Table({'EVENT_ID': event_id, 'ENERGY': energy, 'DEC': dec, 'RA': ra, 'TIME': timestamp})
74+
t = Table({
75+
'EVENT_ID': event_id,
76+
'ENERGY': energy,
77+
'DEC': dec,
78+
'RA': ra,
79+
'TIME': timestamp
80+
})
7781
hdu = fits.table_to_hdu(t)
7882

7983
# add information to HDU header
@@ -146,14 +150,13 @@ def create_observation_index_hdu(runs):
146150
returns a fits hdu object
147151
'''
148152
obs_id = _observation_ids(runs)
149-
ra_pnt = runs.right_ascension.values * u.hourangle
153+
ra_pnt = u.Quantity(runs.right_ascension.values, u.hourangle, copy=False)
150154
ra_pnt = ra_pnt.to('deg')
151155

152-
dec_pnt = runs.declination.values * u.deg
153-
zen_pnt = runs.zenith.values * u.deg
154-
alt_pnt = (90 - runs.zenith.values) * u.deg
155-
az_pnt = runs.azimuth.values * u.deg
156-
156+
dec_pnt = u.Quantity(runs.declination.values, u.deg, copy=False)
157+
zen_pnt = u.Quantity(runs.zenith.values, u.deg, copy=False)
158+
alt_pnt = u.Quantity(90 - runs.zenith.values, u.deg, copy=False)
159+
az_pnt = u.Quantity(runs.azimuth.values, u.deg, copy=False)
157160

158161
n_tels = np.ones_like(obs_id)
159162
tellist = np.ones_like(obs_id).astype(np.str)
@@ -198,7 +201,7 @@ def add_meta_information_to_hdu(hdu, **kwargs):
198201
hdu.header['EQUINOX'] = '2000.0'
199202
hdu.header['RADECSYS'] = 'ICRS'
200203
hdu.header['EUNIT'] = 'TeV'
201-
hdu.header['DATE'] = datetime.datetime.now().replace(microsecond=0).isoformat()
204+
hdu.header['DATE'] = Time.now().iso
202205
_extend_hdu_header(hdu.header, TIME_INFO)
203206
if kwargs:
204207
_extend_hdu_header(hdu.header, kwargs)

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
setup(
55
name='irf',
6-
version='0.4.0',
6+
version='0.4.1',
77
description='Functions to do instrument response functions for FACT',
88
url='http://github.com/fact-project/irf',
99
author='Kai Brügge, Maximilian Nöthe',

0 commit comments

Comments
 (0)