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

Leakage #783

Merged
merged 4 commits into from
Sep 21, 2018
Merged
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
1 change: 1 addition & 0 deletions ctapipe/image/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
from .reducers import *
from .muon import *
from .geometry_converter import *
from .leakage import *
50 changes: 50 additions & 0 deletions ctapipe/image/leakage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Leakage calculation
"""

import numpy as np
from ..io.containers import LeakageContainer


__all__ = ['leakage']


def leakage(geom, image, cleaning_mask):
'''
Calculating the leakage-values for a given image.
Image must be cleaned for example with tailcuts_clean.
Leakage describes how strong a shower is on the edge of a telescope.

Parameters
----------
geom: ctapipe.instrument.CameraGeometry
Camera geometry information
image: array
pixel values
cleaning_mask: array, dtype=bool
The pixel that survived cleaning, e.g. tailcuts_clean

Returns
-------
LeakageContainer
'''
border1 = geom.get_border_pixel_mask(1)
border2 = geom.get_border_pixel_mask(2)

mask1 = border1 & cleaning_mask
mask2 = border2 & cleaning_mask

leakage_pixel1 = np.sum(mask1)
leakage_pixel2 = np.sum(mask2)

leakage_intensity1 = np.sum(image[mask1])
leakage_intensity2 = np.sum(image[mask2])

size = np.sum(image[cleaning_mask])

return LeakageContainer(
leakage1_pixel=leakage_pixel1 / geom.n_pixels,
leakage2_pixel=leakage_pixel2 / geom.n_pixels,
leakage1_intensity=leakage_intensity1 / size,
leakage2_intensity=leakage_intensity2 / size,
)
21 changes: 21 additions & 0 deletions ctapipe/image/tests/test_leakage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from ctapipe.instrument.camera import CameraGeometry
import numpy as np


def test_leakage():
from ctapipe.image.leakage import leakage

geom = CameraGeometry.from_name('LSTCam')

img = np.ones(geom.n_pixels)
mask = np.ones(len(geom), dtype=bool)

l = leakage(geom, img, mask)

ratio1 = np.sum(geom.get_border_pixel_mask(1)) / geom.n_pixels
ratio2 = np.sum(geom.get_border_pixel_mask(2)) / geom.n_pixels

assert l.leakage1_intensity == ratio1
assert l.leakage2_intensity == ratio2
assert l.leakage1_pixel == ratio1
assert l.leakage2_pixel == ratio2
37 changes: 37 additions & 0 deletions ctapipe/instrument/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from ctapipe.utils import get_table_dataset, find_all_matching_datasets
from ctapipe.utils.linalg import rotation_matrix_2d


__all__ = ['CameraGeometry']

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -90,6 +91,8 @@ def __init__(self, cam_id, pix_id, pix_x, pix_y, pix_area, pix_type,
pix_rotation="0d", cam_rotation="0d",
neighbors=None, apply_derotation=True):

assert len(pix_x) == len(pix_y), 'pix_x and pix_y must have same length'
self.n_pixels = len(pix_x)
self.cam_id = cam_id
self.pix_id = pix_id
self.pix_x = pix_x
Expand All @@ -110,6 +113,9 @@ def __init__(self, cam_id, pix_id, pix_x, pix_y, pix_area, pix_type,
if len(pix_x.shape) == 1:
self.rotate(cam_rotation)

# cache border pixel mask per instance
self.border_cache = {}

def __eq__(self, other):
return ((self.cam_id == other.cam_id)
and (self.pix_x == other.pix_x).all()
Expand All @@ -119,6 +125,9 @@ def __eq__(self, other):
and (self.pix_type == other.pix_type)
)

def __len__(self):
return self.n_pixels

def __getitem__(self, slice_):
return CameraGeometry(cam_id=" ".join([self.cam_id, " sliced"]),
pix_id=self.pix_id[slice_],
Expand Down Expand Up @@ -450,6 +459,34 @@ def make_rectangular(cls, npix_x=40, npix_y=40, range_x=(-0.5, 0.5),
neighbors=None,
pix_type='rectangular')

def get_border_pixel_mask(self, width=1):
'''
Get a mask for pixels at the border of the camera of arbitrary width

Parameters
----------
width: int
The width of the border in pixels

Returns
-------
mask: array
A boolean mask, True if pixel is in the border of the specified width
'''
if width in self.border_cache:
return self.border_cache[width]

if width == 1:
n_neighbors = self.neighbor_matrix_sparse.sum(axis=1).A1
max_neighbors = n_neighbors.max()
mask = n_neighbors < max_neighbors
else:
n = self.neighbor_matrix
mask = (n & self.get_border_pixel_mask(width - 1)).any(axis=1)

self.border_cache[width] = mask
return mask


# ======================================================================
# utility functions:
Expand Down
17 changes: 17 additions & 0 deletions ctapipe/instrument/tests/test_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,20 @@ def test_slicing():
assert sliced2.pix_id[0] == 5
assert sliced2.pix_id[1] == 7
assert len(sliced2.pix_x) == 5


def test_border_pixels():
from ctapipe.instrument.camera import CameraGeometry

cam = CameraGeometry.from_name("LSTCam")

assert np.sum(cam.get_border_pixel_mask(1)) == 168
assert np.sum(cam.get_border_pixel_mask(2)) == 330

cam = CameraGeometry.from_name("ASTRICam")
assert np.sum(cam.get_border_pixel_mask(1)) == 212
assert np.sum(cam.get_border_pixel_mask(2)) == 408

assert cam.get_border_pixel_mask(1)[0]
assert cam.get_border_pixel_mask(1)[2351]
assert not cam.get_border_pixel_mask(1)[521]
29 changes: 28 additions & 1 deletion ctapipe/io/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
'DataContainer',
'TargetIODataContainer',
'SST1MDataContainer',
'HillasParametersContainer']
'HillasParametersContainer',
'LeakageContainer']


class SST1MCameraContainer(Container):
Expand Down Expand Up @@ -669,3 +670,29 @@ class HillasParametersContainer(Container):

skewness = Field(nan, 'measure of the asymmetry')
kurtosis = Field(nan, 'measure of the tailedness')


class LeakageContainer(Container):
"""
Leakage
"""
leakage1_pixel = Field(
nan,
'Percentage of pixels after cleaning'
' that are in camera border of width=1'
)
leakage2_pixel = Field(
nan,
'Percentage of pixels after cleaning'
' that are in camera border of width=2'
)
leakage1_intensity = Field(
nan,
'Percentage of photo-electrons after cleaning'
' that are in the camera border of width=1'
)
leakage2_intensity = Field(
nan,
'Percentage of photo-electrons after cleaning'
' that are in the camera border of width=2'
)