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 EnergyOffsetArray #383
Changes from all commits
51e2588
f8e044b
84de374
e43c167
a268109
387aa3e
84de738
fde3b4e
cd4776f
5edf576
f3a8ade
3b6ea1c
7edb715
5905a85
afe6685
a0436b0
74af34f
f77ad2a
4d6ae05
92ccd44
6c4b677
557b132
a82b686
758309e
892e479
2658eeb
2a5ef0e
2c80988
108632c
4b26f69
e6c1c85
bec4795
e3fb853
93d806a
c88902e
753fded
9027d1e
27d6492
1ae0549
55bd62c
37c50eb
0fb5a7d
becc616
13bb8bd
114c27d
5a90ffa
0eb4005
915b48a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
.. _energyoffset_array: | ||
|
||
EnergyOffset Array | ||
================== | ||
|
||
The `~gammapy.background.EnergyOffsetArray` class represents a 2D array *(energy,offset)* that is filled with an eventlist. For a set of observations, by giving an energy binning and an offset binning, you fill the events in this histogram. | ||
|
||
|
||
Four Crab observations are located in the ``gammapy-extra`` repository as | ||
examples: | ||
`hess_events_simulated_023523.fits`_ , `hess_events_simulated_023526.fits`_ , `hess_events_simulated_023559.fits`_ and `hess_events_simulated_023592.fits`_ | ||
|
||
An example script of how to fill this Array from these four observations and plots the result is given in the ``examples`` directory: | ||
:download:`example_energy_offset_array.py <../../examples/example_energy_offset_array.py>` | ||
|
||
.. plot:: ../examples/example_energy_offset_array.py | ||
:include-source: | ||
|
||
|
||
|
||
.. _hess_events_simulated_023523.fits: https://github.com/gammapy/gammapy-extra/tree/master/datasets/hess-crab4/hess_events_simulated_023523.fits | ||
.. _hess_events_simulated_023526.fits: https://github.com/gammapy/gammapy-extra/tree/master/datasets/hess-crab4/hess_events_simulated_023526.fits | ||
.. _hess_events_simulated_023559.fits: https://github.com/gammapy/gammapy-extra/tree/master/datasets/hess-crab4/hess_events_simulated_023559.fits | ||
.. _hess_events_simulated_023592.fits: https://github.com/gammapy/gammapy-extra/tree/master/datasets/hess-crab4/hess_events_simulated_023592.fits |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
|
||
from gammapy.data import DataStore | ||
from gammapy.datasets import gammapy_extra | ||
from gammapy.background import EnergyOffsetArray | ||
from gammapy.utils.energy import EnergyBounds | ||
|
||
|
||
def make_counts_array(): | ||
"""Make an example counts array with energy and offset axes.""" | ||
data_store = DataStore.from_dir(gammapy_extra.dir / 'datasets/hess-crab4') | ||
|
||
event_lists = data_store.load_all('events') | ||
ebounds = EnergyBounds.equal_log_spacing(0.1, 100, 100, 'TeV') | ||
offset = np.linspace(0, 2.5, 100) | ||
array = EnergyOffsetArray(ebounds, offset) | ||
array.fill_events(event_lists) | ||
|
||
return array | ||
|
||
|
||
if __name__ == '__main__': | ||
array = make_counts_array() | ||
array.plot_image() | ||
plt.show() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
from __future__ import absolute_import, division, print_function, unicode_literals | ||
import numpy as np | ||
from astropy.coordinates import Angle | ||
from astropy.units import Quantity | ||
|
||
__all__ = [ | ||
'EnergyOffsetArray', | ||
] | ||
|
||
|
||
class EnergyOffsetArray(object): | ||
""" | ||
Energy offset dependent array. | ||
|
||
Parameters | ||
---------- | ||
energy : `~astropy.units.Quantity` | ||
energy bin vector | ||
offset : `~astropy.coordinates.Angle` | ||
offset bin vector | ||
data : `~numpy.ndarray` | ||
data array (2D) | ||
|
||
""" | ||
|
||
def __init__(self, energy, offset, data=None): | ||
self.energy = Quantity(energy, 'TeV') | ||
self.offset = Angle(offset, 'deg') | ||
if data is None: | ||
self.data = np.zeros((len(energy) - 1, len(offset) - 1)) | ||
else: | ||
self.data = data | ||
|
||
def fill_events(self, event_lists): | ||
"""Fill events histogram. | ||
|
||
This add the counts to the existing value array. | ||
|
||
Parameters | ||
------------- | ||
event_lists : list of `~gammapy.data.EventList` | ||
Python list of event list objects. | ||
|
||
|
||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this function could just be this, no? for event_list in events:
counts = self._fill_one_event_list(event_list)
self.data += counts |
||
# loop over the Lost of object EventList | ||
for event_list in event_lists: | ||
# Fill the events | ||
counts = self._fill_one_event_list(event_list) | ||
self.data += counts | ||
|
||
def _fill_one_event_list(self, events): | ||
""" | ||
histogram the counts of an EventList object in 2D (energy,offset) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here I don't understand why it doesn't appear on the documentation since I remote the _ for the methods... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try running:
This does a "clean" before running the docs build. I don't know all of the details about the Sphinx build, but I think it's common that you need to clean to make sure the API docs are re-generated. (you can also run "make clean"). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it useful to expose this method in the public API? You can add docstrings for private functions / methods, but it's not as important as for the public methods. |
||
|
||
Parameters | ||
------------- | ||
events :`~gammapy.data.EventList` | ||
Event list objects. | ||
|
||
""" | ||
|
||
offset = events.offset | ||
ev_energy = events.energy | ||
|
||
# stack the offset and energy array | ||
ev_cube_array = np.vstack([ev_energy, offset]).T | ||
|
||
# fill data cube into histogramdd | ||
ev_cube_hist, ev_cube_edges = np.histogramdd(ev_cube_array, | ||
[self.energy.value, | ||
self.offset.value]) | ||
return ev_cube_hist | ||
|
||
def plot_image(self, ax=None, offset=None, energy=None, **kwargs): | ||
""" | ||
Plot Energy_offset Array image (x=offset, y=energy). | ||
""" | ||
import matplotlib.pyplot as plt | ||
|
||
kwargs.setdefault('cmap', 'afmhot') | ||
kwargs.setdefault('origin', 'bottom') | ||
kwargs.setdefault('interpolation', 'nearest') | ||
|
||
ax = plt.gca() if ax is None else ax | ||
|
||
if offset is None: | ||
offset = self.offset | ||
|
||
if energy is None: | ||
energy = self.energy | ||
|
||
extent = [ | ||
offset.value.min(), offset.value.max(), | ||
energy.value.min(), energy.value.max(), | ||
] | ||
ax.imshow(self.data, extent=extent, **kwargs) | ||
ax.semilogy() | ||
ax.set_xlabel('Offset ({0})'.format(offset.unit)) | ||
ax.set_ylabel('Energy ({0})'.format(energy.unit)) | ||
ax.set_title('Energy_offset Array') | ||
ax.legend() | ||
image = ax.imshow(self.data, extent=extent, **kwargs) | ||
plt.colorbar(image) | ||
return ax |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
from __future__ import absolute_import, division, print_function, unicode_literals | ||
import numpy as np | ||
from ..energy_offset_array import EnergyOffsetArray | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add this boilerplate lines at the top of the new test file:
|
||
from ...data import DataStore | ||
from ...datasets import gammapy_extra | ||
from ...utils.testing import requires_dependency, requires_data | ||
from ...utils.energy import EnergyBounds | ||
|
||
|
||
@requires_dependency('matplotlib') | ||
@requires_data('gammapy-extra') | ||
def test_energy_offset_array(): | ||
dir = str(gammapy_extra.dir) + '/datasets/hess-crab4' | ||
data_store = DataStore.from_dir(dir) | ||
ev_list = data_store.load_all('events') | ||
ebounds = EnergyBounds.equal_log_spacing(0.1, 100, 100, 'TeV') | ||
offset = np.linspace(0, 2.5, 100) | ||
array = EnergyOffsetArray(ebounds, offset) | ||
array.fill_events(ev_list) | ||
array.plot_image() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,6 +133,14 @@ def altaz(self): | |
lon, lat = self['AZ'], self['ALT'] | ||
return SkyCoord(lon, lat, unit='deg', frame=altaz_frame) | ||
|
||
@property | ||
def offset(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for adding Compute the offset, and assert on the value for one or two items. This is the best one can do for things where no externally verified expected values are available. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better if you replace the implementation of the I.e. use the RADEC pointing and event position and angular separation on the sky.
Angular separation on the sky will be slower, but I don't think performance is an issue here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok so position will be self.radec and the center will be pointing_radec?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure to understand why DETX, DETY field of view coordinates aren't well-defined yet ? This is the coordinates relative to the pointing direction so exactly what we want? I spoke with bruno and at least is HAP-Fr this is well defined. If I want to use the radec of the events I need the pointing position for each event not the pointing position of the run given by self.target_radec and I don't think we have this pointing position for each event?
Le 21 janv. 2016 à 17:15, Christoph Deil notifications@github.com a écrit :
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The orientation of DETX / DETY isn't well-defined yet (axes aligned with ALT/AZ or RA/DEC). For HESS the pointing position in RADEC is fixed during the whole run. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will try to find out There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see roughly the same offset (differences at the 0.01 deg level), no matter if it's computed for RA/DEC or DETX/DETY: def print_offset(filename):
import numpy as np
from gammapy.datasets import gammapy_extra
from gammapy.data import EventList
filename = gammapy_extra.filename(filename)
event_list = EventList.read(filename, hdu='EVENTS')
theta1 = event_list.pointing_radec.separation(event_list.radec).deg
theta2 = np.sqrt(event_list['DETX'].data ** 2 + event_list['DETY'].data ** 2)
print(theta1[:5])
print(theta2[:5]) >>> print_offset('test_datasets/unbundled/hess/run_0023037_hard_eventlist.fits.gz')
[ 1.90449774 0.49800608 1.44632578 1.19342053 1.37034893]
[ 1.89962924 0.49339229 1.45202422 1.19860065 1.37333238]
>>> print_offset('datasets/hess-crab4/hess_events_simulated_023523.fits')
[ 0.54917634 0.50370294 0.55434477 0.52719957 0.62944549]
[ 0.54917902 0.50370306 0.55434608 0.52720046 0.62944645] I think it's OK if you just put the sky separation for this pull request to finish it up, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry it was my mistake I used the target_position instead of the pointing_radec...
|
||
"""Event offset (`~astropy.coordinates.Angle`)""" | ||
position = self.radec | ||
center = self.pointing_radec | ||
offset = center.separation(position) | ||
return Angle(offset, unit='deg') | ||
|
||
@property | ||
def energy(self): | ||
"""Event energies (`~astropy.units.Quantity`)""" | ||
|
@@ -620,14 +628,14 @@ class EventListDatasetChecker(object): | |
Logger to use (use module-level Gammapy logger by default) | ||
""" | ||
_AVAILABLE_CHECKS = OrderedDict( | ||
misc='check_misc', | ||
times='check_times', | ||
coordinates='check_coordinates', | ||
misc='check_misc', | ||
times='check_times', | ||
coordinates='check_coordinates', | ||
) | ||
|
||
accuracy = OrderedDict( | ||
angle=Angle('1 arcsec'), | ||
time=Quantity(1, 'microsecond'), | ||
angle=Angle('1 arcsec'), | ||
time=Quantity(1, 'microsecond'), | ||
|
||
) | ||
|
||
|
@@ -712,9 +720,9 @@ def check_times(self): | |
|
||
# http://fermi.gsfc.nasa.gov/ssc/data/analysis/documentation/Cicerone/Cicerone_Data/Time_in_ScienceTools.html | ||
telescope_met_refs = OrderedDict( | ||
FERMI=Time('2001-01-01T00:00:00'), | ||
HESS=Time('2000-01-01T12:00:00.000'), | ||
# TODO: Once CTA has specified their MET reference add check here | ||
FERMI=Time('2001-01-01T00:00:00'), | ||
HESS=Time('2000-01-01T12:00:00.000'), | ||
# TODO: Once CTA has specified their MET reference add check here | ||
) | ||
|
||
telescope = self.dset.event_list.meta['TELESCOP'] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add this boilerplate line:
This is to make simultaneous Python 2 / 3 codebase easier and we have it in every file.