Skip to content

Commit

Permalink
Merge pull request #226 from cta-observatory/pixel_table
Browse files Browse the repository at this point in the history
Add module_id, hardware_pixel_id, module_pixel_index to camera geometry table
  • Loading branch information
morcuended authored Aug 5, 2024
2 parents 43ee740 + cafaded commit 3eb573d
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 12 deletions.
6 changes: 3 additions & 3 deletions src/ctapipe_io_lst/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from .version import __version__
from .calibration import LSTR0Corrections
from .event_time import EventTimeCalculator, cta_high_res_to_time
from .pixels import get_pixel_table
from .pointing import PointingSource
from .anyarray_dtypes import (
CDTS_AFTER_37201_DTYPE,
Expand Down Expand Up @@ -100,9 +101,8 @@ def get_channel_info(pixel_status):

def load_camera_geometry():
''' Load camera geometry from bundled resources of this repo '''
with as_file(files("ctapipe_io_lst") / "resources/LSTCam.camgeom.fits.gz") as path:
Provenance().add_input_file(path, role="CameraGeometry")
cam = CameraGeometry.from_table(path)
pixel_table = get_pixel_table()
cam = CameraGeometry.from_table(pixel_table)
cam.frame = CameraFrame(focal_length=OPTICS.effective_focal_length)
return cam

Expand Down
12 changes: 3 additions & 9 deletions src/ctapipe_io_lst/calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,17 @@
N_GAINS, N_PIXELS, N_MODULES, N_SAMPLES, LOW_GAIN, HIGH_GAIN,
N_PIXELS_MODULE, N_CAPACITORS_PIXEL, N_CAPACITORS_CHANNEL,
CLOCK_FREQUENCY_KHZ,
CHANNEL_ORDER_LOW_GAIN, CHANNEL_ORDER_HIGH_GAIN, N_CHANNELS_MODULE,
N_CHANNELS_MODULE,
PIXEL_INDEX, PixelStatus
)

from .pixels import pixel_channel_indices

__all__ = [
'LSTR0Corrections',
]


@lru_cache()
def pixel_channel_indices(n_modules):
module_index = np.repeat(np.arange(n_modules), 7)
low_gain = module_index * N_CHANNELS_MODULE + np.tile(CHANNEL_ORDER_LOW_GAIN, n_modules)
high_gain = module_index * N_CHANNELS_MODULE + np.tile(CHANNEL_ORDER_HIGH_GAIN, n_modules)
return low_gain, high_gain


def get_first_capacitors_for_pixels(first_capacitor_id, expected_pixel_id=None):
'''
Get the first capacitor for each pixel / gain
Expand Down
70 changes: 70 additions & 0 deletions src/ctapipe_io_lst/pixels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import numpy as np
from functools import lru_cache
from astropy.table import Table
from importlib.resources import files, as_file

from ctapipe.core import Provenance

from .constants import N_PIXELS_MODULE, CHANNEL_ORDER_LOW_GAIN, CHANNEL_ORDER_HIGH_GAIN, N_CHANNELS_MODULE


@lru_cache()
def pixel_channel_indices(n_modules):
"""Get index into first_capacitor_id or each channel, pixel"""
return _pixel_channel_indices(np.arange(n_modules))


def _pixel_channel_indices(module_id_map):
module = np.repeat(module_id_map, N_PIXELS_MODULE)
n_modules = len(module_id_map)
low_gain = module * N_CHANNELS_MODULE + np.tile(CHANNEL_ORDER_LOW_GAIN, n_modules)
high_gain = module * N_CHANNELS_MODULE + np.tile(CHANNEL_ORDER_HIGH_GAIN, n_modules)
return low_gain, high_gain


def get_pixel_table_from_camera_config(config):
"""
Construct a table of pixel / module ids from the mappings in CameraConfiguration
"""
if hasattr(config, "pixel_id_map"):
# new R1v1.CameraConfiguration
pixel_id_map = config.pixel_id_map
module_id_map = config.module_id_map
else:
# old ProtoR1.CameraConfiguration
pixel_id_map = config.expected_pixels_id
module_id_map = config.lstcam.expected_modules_id

n_modules = len(module_id_map)
n_pixels = len(pixel_id_map)

chip_lg, chip_hg = _pixel_channel_indices(module_id_map)

pixel_index = np.arange(n_pixels)
# the pixel data arrives in module groups, the module id of each group
# is in module_id_map. Repeat to have the module_id of each pixel
module_id = np.repeat(module_id_map, N_PIXELS_MODULE)

# pixels inside one module are ordered by module_pixel_index
module_pixel_index = np.tile(np.arange(N_PIXELS_MODULE), n_modules)
hardware_pixel_id = module_id * N_PIXELS_MODULE + module_pixel_index

table = Table(dict(
pixel_id=pixel_id_map,
pixel_index=pixel_index,
module_id=module_id,
module_pixel_index=module_pixel_index,
hardware_pixel_id=hardware_pixel_id,
drs4_chip_hg=chip_hg,
drs4_chip_lg=chip_lg,
))

table.sort("pixel_id")
return table


def get_pixel_table():
"""Load pixel information from bundled camera geometry file"""
with as_file(files("ctapipe_io_lst") / "resources/LSTCam.camgeom.fits.gz") as path:
Provenance().add_input_file(path, role="CameraGeometry")
return Table.read(path)
Binary file modified src/ctapipe_io_lst/resources/LSTCam.camgeom.fits.gz
Binary file not shown.
31 changes: 31 additions & 0 deletions src/ctapipe_io_lst/tests/test_pixels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import os
from pathlib import Path

import numpy as np
import protozfits
import pytest

test_data = Path(os.getenv('LSTCHAIN_TEST_DATA', 'test_data')).absolute()
test_file_protor1 = test_data / "real/R0/20200218/LST-1.1.Run02008.0000_first50.fits.fz"
test_file_r1v1 = test_data / "real/R0/20231219/LST-1.1.Run16255.0000_first50.fits.fz"


@pytest.mark.parametrize("path", (test_file_protor1, test_file_r1v1))
def test_get_pixel_table_from_camera_config(path):
from ctapipe_io_lst.pixels import get_pixel_table_from_camera_config

with protozfits.File(str(path)) as f:
config = getattr(f, "CameraConfig", getattr(f, "CameraConfiguration", None))[0]

table = get_pixel_table_from_camera_config(config)

np.testing.assert_array_equal(np.unique(table["module_id"]), np.arange(265))

# check relationship between hardware_pixel_id and position in module
np.testing.assert_array_equal(
table["module_id"] * 7 + table["module_pixel_index"],
table["hardware_pixel_id"],
)

# check we have sorted by pixel id
np.testing.assert_array_equal(table["pixel_id"], np.arange(1855))

0 comments on commit 3eb573d

Please sign in to comment.