Skip to content
Draft
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
2 changes: 2 additions & 0 deletions src/ctapipe/coordinates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from .nominal_frame import NominalFrame
from .telescope_frame import TelescopeFrame
from .utils import (
altaz_to_icrs,
altaz_to_nominal,
altaz_to_righthanded_cartesian,
get_point_on_shower_axis,
Expand All @@ -42,6 +43,7 @@
"shower_impact_distance",
"get_point_on_shower_axis",
"altaz_to_nominal",
"altaz_to_icrs",
]


Expand Down
21 changes: 21 additions & 0 deletions src/ctapipe/coordinates/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"altaz_to_righthanded_cartesian",
"get_point_on_shower_axis",
"altaz_to_nominal",
"altaz_to_icrs",
]


Expand Down Expand Up @@ -103,3 +104,23 @@ def altaz_to_nominal(az, alt, pointing_az, pointing_alt) -> u.Quantity:
return u.Quantity(
np.column_stack((nominal_coord.fov_lon.deg, nominal_coord.fov_lat.deg)), u.deg
)


def altaz_to_icrs(az, alt, obstime, location) -> u.Quantity:
"""
Compute nominal (FOV) coordinates from alt/az coordinates.

This can be used in a FeatureGenerator or ExpressionEngine to get a single
column with fov_lon, fov_lat coordinates.

Returns
-------
u.Quantity:
2D array of coordinates with 2 columns: ra, dec
"""
event_coord = SkyCoord(
az=az, alt=alt, frame="altaz", obstime=obstime, location=location
)
icrs_coord = event_coord.transform_to("icrs")

return u.Quantity(np.column_stack((icrs_coord.ra.deg, icrs_coord.dec.deg)), u.deg)
57 changes: 54 additions & 3 deletions src/ctapipe/io/event_preprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from astropy.coordinates import angular_separation

from ..coordinates import altaz_to_nominal
from ..coordinates import altaz_to_icrs, altaz_to_nominal
from ..core import (
Component,
FeatureGenerator,
Expand Down Expand Up @@ -123,6 +123,45 @@ def _dl2_irf_config(preprocessor):
}


@FeatureSetRegistry.register("dl2_to_dl3")
def _dl2_to_dl3_config(preprocessor: "EventPreprocessor"):
return {
"features_to_generate": [
("ENERGY", f"{preprocessor.energy_reconstructor}_energy"),
("ALT", f"{preprocessor.geometry_reconstructor}_alt"),
("AZ", f"{preprocessor.geometry_reconstructor}_az"),
("TIME", "time"),
("EVENT_ID", "event_id"),
("GAMMANESS", f"{preprocessor.gammaness_reconstructor}_prediction"),
(
"reco_fov_coord",
"altaz_to_nominal(AZ, ALT, subarray_pointing_lon, subarray_pointing_lat)",
),
("FOV_LON", "reco_fov_coord[:,0]"),
("FOV_LAT", "reco_fov_coord[:,1]"),
(
"reco_icrs_coord",
"altaz_to_icrs(AZ, ALT, TIME, LOCATION)",
),
("RA", "reco_icrs_coord[:,0]"),
("DEC", "reco_icrs_coord[:,1]"),
],
"quality_criteria": [],
"output_features": [
"EVENT_ID",
"TIME",
"RA",
"DEC",
"ENERGY",
"ALT",
"AZ",
"FOV_LON",
"FOV_LAT",
"GAMMANESS",
],
}


class EventPreprocessor(Component):
"""
Selects or generates features and filters tables of events.
Expand Down Expand Up @@ -198,14 +237,26 @@ def __init__(self, config=None, parent=None, **kwargs):
"of features in the configuration (DL2EventPreprocessor.features)."
)

def __call__(self, table):
"""Return new table with only the columns in features."""
def __call__(self, table, **other_attributes):
"""
Return new table with only the columns in features.

Parameters
----------
table: Table
Table to process
**other_attributes: Any
Other functions or objects that the FeatureGenerator should have
access to, in addition to the default ones.
"""

# generate new features, which includes renaming columns:
generated = self.feature_generator(
table,
angular_separation=angular_separation,
altaz_to_nominal=altaz_to_nominal,
altaz_to_icrs=altaz_to_icrs,
**other_attributes,
)

# apply event selection on the resulting table
Expand Down
Loading