From f64655b7cf0581b612c727e863483ca566c63623 Mon Sep 17 00:00:00 2001 From: TjarkMiener Date: Thu, 21 Aug 2025 13:50:43 +0200 Subject: [PATCH 1/5] add 'core' to reco tasks for the train model tool --- ctlearn/core/loader.py | 20 ++++++++++++++++++++ ctlearn/core/model.py | 8 +++++--- ctlearn/core/tests/test_loader.py | 3 ++- ctlearn/tools/train_model.py | 22 ++++++++++++++++++++-- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/ctlearn/core/loader.py b/ctlearn/core/loader.py index 5b723f9c..697f5055 100644 --- a/ctlearn/core/loader.py +++ b/ctlearn/core/loader.py @@ -170,6 +170,14 @@ def _get_mono_item(self, batch): ) if "energy" in self.tasks: labels["energy"] = batch["log_true_energy"].data + if "core" in self.tasks: + labels["core"] = np.stack( + ( + batch["true_core_x"].data, + batch["true_core_y"].data, + ), + axis=1, + ) if "skydirection" in self.tasks: labels["skydirection"] = np.stack( ( @@ -222,6 +230,7 @@ def _get_stereo_item(self, batch): features, mono_feature_vectors, stereo_feature_vectors = [], [], [] true_shower_primary_class = [] log_true_energy = [] + core_x, core_y = [], [] fov_lon, fov_lat, angular_separation = [], [], [] cam_coord_offset_x, cam_coord_offset_y, cam_coord_distance = [], [], [] for group_element in batch_grouped.groups: @@ -260,6 +269,9 @@ def _get_stereo_item(self, batch): ) if "energy" in self.tasks: log_true_energy.append(group_element["log_true_energy"].data[0]) + if "core" in self.tasks: + core_x = group_element["true_core_x"].data[0] + core_y = group_element["true_core_y"].data[0] if "skydirection" in self.tasks: fov_lon.append(group_element["fov_lon"].data[0]) fov_lat.append( @@ -285,6 +297,14 @@ def _get_stereo_item(self, batch): ) if "energy" in self.tasks: labels["energy"] = np.array(log_true_energy) + if "core" in self.tasks: + labels["core"] = np.stack( + ( + np.array(core_x), + np.array(core_y), + ), + axis=1, + ) if "skydirection" in self.tasks: labels["skydirection"] = np.stack( ( diff --git a/ctlearn/core/model.py b/ctlearn/core/model.py index 07c79d46..292c3d61 100644 --- a/ctlearn/core/model.py +++ b/ctlearn/core/model.py @@ -87,11 +87,12 @@ class CTLearnModel(Component): "energy": [512, 256, 1], "cameradirection": [512, 256, 2], "skydirection": [512, 256, 2], + "core": [512, 256, 2], }, allow_none=False, help=( "Dictionary containing the number of neurons in the fully connected head for each " - "task ('type', 'energy', 'cameradirection', 'skydirection'). Note: The number of neurons in the last layer " + "task ('type', 'energy', 'cameradirection', 'skydirection', 'core'). Note: The number of neurons in the last layer " "must match the number of classes or the number of reconstructed values." ), ).tag(config=True) @@ -102,12 +103,13 @@ class CTLearnModel(Component): "energy": "relu", "cameradirection": "tanh", "skydirection": "tanh", + "core": "tanh", }, allow_none=False, help=( "Dictionary containing the activation function for the fully connected head for each " - "task ('type', 'energy', 'cameradirection', 'skydirection'). Note: The default activation functions " - "are 'relu' for 'type' and 'energy' tasks, and 'tanh' for 'cameradirection' and 'skydirection' tasks. " + "task ('type', 'energy', 'cameradirection', 'skydirection', 'core'). Note: The default activation functions " + "are 'relu' for 'type' and 'energy' tasks, and 'tanh' for 'cameradirection', 'skydirection' and 'core' tasks. " "The 'type' task uses 'softmax' as the final activation function." ), ).tag(config=True) diff --git a/ctlearn/core/tests/test_loader.py b/ctlearn/core/tests/test_loader.py index 97f87172..ad354932 100644 --- a/ctlearn/core/tests/test_loader.py +++ b/ctlearn/core/tests/test_loader.py @@ -21,7 +21,7 @@ def test_data_loader(dl1_tmp_path, dl1_gamma_file): dl1_loader = DLDataLoader( DLDataReader=dl1_reader, indices=[0], - tasks=["type", "energy", "cameradirection", "skydirection"], + tasks=["type", "energy", "cameradirection", "skydirection", "core"], batch_size=1, ) # Get the features and labels fgrom the data loader for one batch @@ -32,6 +32,7 @@ def test_data_loader(dl1_tmp_path, dl1_gamma_file): and "energy" in labels and "cameradirection" in labels and "skydirection" in labels + and "core" in labels ) # Check the shape of the features assert features["input"].shape == (1, 110, 110, 2) diff --git a/ctlearn/tools/train_model.py b/ctlearn/tools/train_model.py index d3ed9f17..d57eec3f 100644 --- a/ctlearn/tools/train_model.py +++ b/ctlearn/tools/train_model.py @@ -41,6 +41,7 @@ class TrainCTLearnModel(Tool): - Regression of the primary particle energy - Regression of the primary particle arrival direction based on the offsets in camera coordinates - Regression of the primary particle arrival direction based on the offsets in sky coordinates + - Regression of the primary particle core position on the ground """ name = "ctlearn-train-model" @@ -66,6 +67,17 @@ class TrainCTLearnModel(Tool): --output /path/to/your/energy/ \\ --reco energy \\ + To train a CTLearn model for the regression of the primary particle + core position on the ground: + > ctlearn-train-model \\ + --signal /path/to/your/muons_dl1_dir/ \\ + --pattern-signal "muon_*_run1.dl1.h5" \\ + --pattern-signal "muon_*_run10.dl1.h5" \\ + --DLImageReader.channels=cleaned_image \\ + --DLImageReader.image_mapper_type=OversamplingMapper \\ + --output /path/to/your/core/ \\ + --reco core \\ + To train a CTLearn model for the regression of the primary particle arrival direction based on the offsets in camera coordinates: > ctlearn-train-model \\ @@ -150,7 +162,7 @@ class TrainCTLearnModel(Tool): ).tag(config=True) reco_tasks = List( - trait=CaselessStrEnum(["type", "energy", "cameradirection", "skydirection"]), + trait=CaselessStrEnum(["type", "energy", "cameradirection", "skydirection", "core"]), allow_none=False, help=( "List of reconstruction tasks to perform. " @@ -158,6 +170,7 @@ class TrainCTLearnModel(Tool): "'energy': regression of the primary particle energy " "'cameradirection': regression of the primary particle arrival direction in camera coordinates " "'skydirection': regression of the primary particle arrival direction in sky coordinates" + "'core': regression of the primary particle core position on the ground" ) ).tag(config=True) @@ -526,7 +539,12 @@ def _get_losses_and_mertics(self, tasks): losses["cameradirection"] = keras.losses.MeanAbsoluteError( reduction="sum_over_batch_size" ) - metrics["cameradirection"] = keras.metrics.MeanAbsoluteError(name="mae_cameradirection") + metrics["cameradirection"] = keras.metrics.MeanAbsoluteError(name="mae_core") + if "core" in self.reco_tasks: + losses["core"] = keras.losses.MeanAbsoluteError( + reduction="sum_over_batch_size" + ) + metrics["core"] = keras.metrics.MeanAbsoluteError(name="mae_core") if "skydirection" in self.reco_tasks: losses["skydirection"] = keras.losses.MeanAbsoluteError( reduction="sum_over_batch_size" From 3d392c460159febf5f901f5aacb9338b51661b54 Mon Sep 17 00:00:00 2001 From: TjarkMiener Date: Thu, 21 Aug 2025 14:07:29 +0200 Subject: [PATCH 2/5] rename task to impact --- ctlearn/core/loader.py | 10 +++++----- ctlearn/core/model.py | 10 +++++----- ctlearn/core/tests/test_loader.py | 4 ++-- ctlearn/tools/train_model.py | 20 ++++++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/ctlearn/core/loader.py b/ctlearn/core/loader.py index 697f5055..bdd81805 100644 --- a/ctlearn/core/loader.py +++ b/ctlearn/core/loader.py @@ -170,8 +170,8 @@ def _get_mono_item(self, batch): ) if "energy" in self.tasks: labels["energy"] = batch["log_true_energy"].data - if "core" in self.tasks: - labels["core"] = np.stack( + if "impact" in self.tasks: + labels["impact"] = np.stack( ( batch["true_core_x"].data, batch["true_core_y"].data, @@ -269,7 +269,7 @@ def _get_stereo_item(self, batch): ) if "energy" in self.tasks: log_true_energy.append(group_element["log_true_energy"].data[0]) - if "core" in self.tasks: + if "impact" in self.tasks: core_x = group_element["true_core_x"].data[0] core_y = group_element["true_core_y"].data[0] if "skydirection" in self.tasks: @@ -297,8 +297,8 @@ def _get_stereo_item(self, batch): ) if "energy" in self.tasks: labels["energy"] = np.array(log_true_energy) - if "core" in self.tasks: - labels["core"] = np.stack( + if "impact" in self.tasks: + labels["impact"] = np.stack( ( np.array(core_x), np.array(core_y), diff --git a/ctlearn/core/model.py b/ctlearn/core/model.py index 292c3d61..de2e9451 100644 --- a/ctlearn/core/model.py +++ b/ctlearn/core/model.py @@ -87,12 +87,12 @@ class CTLearnModel(Component): "energy": [512, 256, 1], "cameradirection": [512, 256, 2], "skydirection": [512, 256, 2], - "core": [512, 256, 2], + "impact": [512, 256, 2], }, allow_none=False, help=( "Dictionary containing the number of neurons in the fully connected head for each " - "task ('type', 'energy', 'cameradirection', 'skydirection', 'core'). Note: The number of neurons in the last layer " + "task ('type', 'energy', 'cameradirection', 'skydirection', 'impact'). Note: The number of neurons in the last layer " "must match the number of classes or the number of reconstructed values." ), ).tag(config=True) @@ -103,13 +103,13 @@ class CTLearnModel(Component): "energy": "relu", "cameradirection": "tanh", "skydirection": "tanh", - "core": "tanh", + "impact": "tanh", }, allow_none=False, help=( "Dictionary containing the activation function for the fully connected head for each " - "task ('type', 'energy', 'cameradirection', 'skydirection', 'core'). Note: The default activation functions " - "are 'relu' for 'type' and 'energy' tasks, and 'tanh' for 'cameradirection', 'skydirection' and 'core' tasks. " + "task ('type', 'energy', 'cameradirection', 'skydirection', 'impact'). Note: The default activation functions " + "are 'relu' for 'type' and 'energy' tasks, and 'tanh' for 'cameradirection', 'skydirection' and 'impact' tasks. " "The 'type' task uses 'softmax' as the final activation function." ), ).tag(config=True) diff --git a/ctlearn/core/tests/test_loader.py b/ctlearn/core/tests/test_loader.py index ad354932..3ece89a6 100644 --- a/ctlearn/core/tests/test_loader.py +++ b/ctlearn/core/tests/test_loader.py @@ -21,7 +21,7 @@ def test_data_loader(dl1_tmp_path, dl1_gamma_file): dl1_loader = DLDataLoader( DLDataReader=dl1_reader, indices=[0], - tasks=["type", "energy", "cameradirection", "skydirection", "core"], + tasks=["type", "energy", "cameradirection", "skydirection", "impact"], batch_size=1, ) # Get the features and labels fgrom the data loader for one batch @@ -32,7 +32,7 @@ def test_data_loader(dl1_tmp_path, dl1_gamma_file): and "energy" in labels and "cameradirection" in labels and "skydirection" in labels - and "core" in labels + and "impact" in labels ) # Check the shape of the features assert features["input"].shape == (1, 110, 110, 2) diff --git a/ctlearn/tools/train_model.py b/ctlearn/tools/train_model.py index d57eec3f..c561fb8b 100644 --- a/ctlearn/tools/train_model.py +++ b/ctlearn/tools/train_model.py @@ -68,15 +68,15 @@ class TrainCTLearnModel(Tool): --reco energy \\ To train a CTLearn model for the regression of the primary particle - core position on the ground: + core position on the ground (impact point): > ctlearn-train-model \\ --signal /path/to/your/muons_dl1_dir/ \\ --pattern-signal "muon_*_run1.dl1.h5" \\ --pattern-signal "muon_*_run10.dl1.h5" \\ --DLImageReader.channels=cleaned_image \\ --DLImageReader.image_mapper_type=OversamplingMapper \\ - --output /path/to/your/core/ \\ - --reco core \\ + --output /path/to/your/impact/ \\ + --reco impact \\ To train a CTLearn model for the regression of the primary particle arrival direction based on the offsets in camera coordinates: @@ -162,15 +162,15 @@ class TrainCTLearnModel(Tool): ).tag(config=True) reco_tasks = List( - trait=CaselessStrEnum(["type", "energy", "cameradirection", "skydirection", "core"]), - allow_none=False, + trait=CaselessStrEnum(["type", "energy", "cameradirection", "skydirection", "impact"]), + allow_none=False, help=( "List of reconstruction tasks to perform. " "'type': classification of the primary particle type " "'energy': regression of the primary particle energy " "'cameradirection': regression of the primary particle arrival direction in camera coordinates " "'skydirection': regression of the primary particle arrival direction in sky coordinates" - "'core': regression of the primary particle core position on the ground" + "'impact': regression of the primary particle core position on the ground (impact point)" ) ).tag(config=True) @@ -539,12 +539,12 @@ def _get_losses_and_mertics(self, tasks): losses["cameradirection"] = keras.losses.MeanAbsoluteError( reduction="sum_over_batch_size" ) - metrics["cameradirection"] = keras.metrics.MeanAbsoluteError(name="mae_core") - if "core" in self.reco_tasks: - losses["core"] = keras.losses.MeanAbsoluteError( + metrics["cameradirection"] = keras.metrics.MeanAbsoluteError(name="mae_cameradirection") + if "impact" in self.reco_tasks: + losses["impact"] = keras.losses.MeanAbsoluteError( reduction="sum_over_batch_size" ) - metrics["core"] = keras.metrics.MeanAbsoluteError(name="mae_core") + metrics["impact"] = keras.metrics.MeanAbsoluteError(name="mae_impact") if "skydirection" in self.reco_tasks: losses["skydirection"] = keras.losses.MeanAbsoluteError( reduction="sum_over_batch_size" From bfd5d8865f6965fa7b59c59dd040e4d3a9cc8bf0 Mon Sep 17 00:00:00 2001 From: TjarkMiener Date: Fri, 22 Aug 2025 14:28:26 +0200 Subject: [PATCH 3/5] include the impact for the prediction tool --- ctlearn/tools/predict_model.py | 148 +++++++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 5 deletions(-) diff --git a/ctlearn/tools/predict_model.py b/ctlearn/tools/predict_model.py index 4560ecf8..e88af82c 100644 --- a/ctlearn/tools/predict_model.py +++ b/ctlearn/tools/predict_model.py @@ -156,7 +156,7 @@ class PredictCTLearnModel(Tool): Create a table with NaNs for missing predictions. _store_pointing(all_identifiers) Store the telescope pointing table from to the output file. - _create_feature_vectors_table(example_identifiers, nonexample_identifiers, classification_feature_vectors, energy_feature_vectors, direction_feature_vectors) + _create_feature_vectors_table(example_identifiers, nonexample_identifiers, classification_feature_vectors, energy_feature_vectors, direction_feature_vectors, impact_feature_vectors) Create the table for the DL1 feature vectors. """ @@ -248,6 +248,18 @@ class PredictCTLearnModel(Tool): file_ok=True, ).tag(config=True) + load_impact_model_from = Path( + default_value=None, + help=( + "Path to a Keras model file (Keras3) or directory (Keras2) for the regression " + "of the primary particle impact point." + ), + allow_none=True, + exists=True, + directory_ok=True, + file_ok=True, + ).tag(config=True) + load_cameradirection_model_from = Path( default_value=None, help=( @@ -305,6 +317,7 @@ class PredictCTLearnModel(Tool): ("i", "input_url"): "PredictCTLearnModel.input_url", ("t", "type_model"): "PredictCTLearnModel.load_type_model_from", ("e", "energy_model"): "PredictCTLearnModel.load_energy_model_from", + ("p", "impact_model"): "PredictCTLearnModel.load_impact_model_from", ( "d", "cameradirection_model", @@ -603,6 +616,21 @@ def _predict_energy(self, example_identifiers): energy_table = example_identifiers.copy() energy_table.add_column(reco_energy, name=f"{self.prefix}_tel_energy") return energy_table, feature_vectors + + def _predict_impact(self, example_identifiers): + """ + Predict the impact point of the primary particle. + """ + self.log.info("Predicting for the regression of the primary particle impact point...") + # Predict the data using the loaded impact_model + predict_data, feature_vectors = self._predict_with_model( + self.load_impact_model_from + ) + # Create prediction table and add the predicted impact point + impact_table = example_identifiers.copy() + impact_table.add_column(predict_data["impact"].T[0], name=f"{self.prefix}_tel_impact_x") + impact_table.add_column(predict_data["impact"].T[1], name=f"{self.prefix}_tel_impact_y") + return impact_table, feature_vectors def _predict_cameradirection(self, example_identifiers): """ @@ -945,6 +973,7 @@ def _create_feature_vectors_table( classification_feature_vectors=None, energy_feature_vectors=None, direction_feature_vectors=None, + impact_feature_vectors=None, ): """ Create the table for the DL1 feature vectors. @@ -965,6 +994,8 @@ def _create_feature_vectors_table( Array containing the energy feature vectors. direction_feature_vectors : np.ndarray or None Array containing the direction feature vectors. + impact_feature_vectors : np.ndarray or None + Array containing the impact feature vectors. Returns: -------- @@ -1022,6 +1053,19 @@ def _create_feature_vectors_table( direction_feature_vectors.shape[1], ) ) + if impact_feature_vectors is not None: + is_valid_col = ~np.isnan(np.min(impact_feature_vectors, axis=1), dtype=bool) + feature_vector_table.add_column( + impact_feature_vectors, name=f"{self.prefix}_tel_impact_feature_vectors" + ) + if nonexample_identifiers is not None: + columns_list.append(f"{self.prefix}_tel_impact_feature_vectors") + shapes_list.append( + ( + len(nonexample_identifiers), + impact_feature_vectors.shape[1], + ) + ) # Produce output table with NaNs for missing predictions if nonexample_identifiers is not None: if len(nonexample_identifiers) > 0: @@ -1141,7 +1185,7 @@ def start(self): property=ReconstructionProperty.PARTICLE_TYPE, parent=self, ) - # Predict the energy of the primary particle + # Predict the particle type of the primary particle classification_table, classification_feature_vectors = ( super()._predict_classification(example_identifiers) ) @@ -1154,7 +1198,7 @@ def start(self): shapes=[(len(nonexample_identifiers),)], ) classification_table = vstack([classification_table, nan_table]) - # Add is_valid column to the energy table + # Add is_valid column to the particle type table classification_table.add_column( ~np.isnan( classification_table[f"{self.prefix}_tel_prediction"].data, @@ -1328,6 +1372,52 @@ def start(self): self.output_path, f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", ) + + impact_feature_vectors = None + if self.load_impact_model_from is not None: + # Predict the impact of the primary particle + impact_table, impact_feature_vectors = super()._predict_impact( + example_identifiers + ) + if self.dl2_telescope: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_impact"], + shapes=[(len(nonexample_identifiers),)], + ) + impact_table = vstack([impact_table, nan_table]) + # Add is_valid column to the impact table + impact_table.add_column( + ~np.isnan( + impact_table[f"{self.prefix}_tel_impact"].data, dtype=bool + ), + name=f"{self.prefix}_tel_is_valid", + ) + for tel_id in self.dl1dh_reader.selected_telescopes[ + self.dl1dh_reader.tel_type + ]: + # Retrieve the example identifiers for the selected telescope + telescope_mask = impact_table["tel_id"] == tel_id + impact_tel_table = impact_table[telescope_mask] + impact_tel_table.sort(TELESCOPE_EVENT_KEYS) + # Save the prediction to the output file + write_table( + impact_tel_table, + self.output_path, + f"{DL2_TELESCOPE_GROUP}/impact/{self.prefix}/tel_{tel_id:03d}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_TELESCOPE_GROUP}/impact/{self.prefix}/tel_{tel_id:03d}", + ) + + if self.dl2_subarray: + raise NotImplementedError("No impact reconstruction property in ctapipe defined. No stereo combiner available.") + direction_feature_vectors = None if self.load_cameradirection_model_from is not None: self.geometry_stereo_combiner = StereoCombiner.from_name( @@ -1459,6 +1549,7 @@ def start(self): classification_feature_vectors, energy_feature_vectors, direction_feature_vectors, + impact_feature_vectors, ) # Loop over the selected telescopes and store the feature vectors # for each telescope in the output file. The feature vectors are stored @@ -1616,7 +1707,7 @@ def start(self): self.log.info("Starting the prediction...") classification_feature_vectors = None if self.load_type_model_from is not None: - # Predict the energy of the primary particle + # Predict the particle type of the primary particle classification_table, classification_feature_vectors = ( super()._predict_classification(example_identifiers) ) @@ -1629,7 +1720,7 @@ def start(self): shapes=[(len(nonexample_identifiers),)], ) classification_table = vstack([classification_table, nan_table]) - # Add is_valid column to the energy table + # Add is_valid column to the particle type table classification_table.add_column( ~np.isnan( classification_table[f"{self.prefix}_tel_prediction"].data, @@ -1711,6 +1802,48 @@ def start(self): self.output_path, f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", ) + impact_feature_vectors = None + if self.load_impact_model_from is not None: + # Predict the impact of the primary particle + impact_table, impact_feature_vectors = super()._predict_impact( + example_identifiers + ) + if self.dl2_subarray: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_impact"], + shapes=[(len(nonexample_identifiers),)], + ) + impact_table = vstack([impact_table, nan_table]) + # Add is_valid column to the impact table + impact_table.add_column( + ~np.isnan( + impact_table[f"{self.prefix}_tel_impact"].data, dtype=bool + ), + name=f"{self.prefix}_tel_is_valid", + ) + # Rename the columns for the stereo mode + impact_table.rename_column( + f"{self.prefix}_tel_impact", f"{self.prefix}_impact" + ) + impact_table.rename_column( + f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" + ) + impact_table.sort(SUBARRAY_EVENT_KEYS) + # Save the prediction to the output file + write_table( + impact_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/impact/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/impact/{self.prefix}", + ) direction_feature_vectors = None if self.load_skydirection_model_from is not None: # Join the prediction table with the telescope pointing table @@ -1773,6 +1906,7 @@ def start(self): classification_feature_vectors, energy_feature_vectors, direction_feature_vectors, + impact_feature_vectors, ) # Loop over the selected telescopes and store the feature vectors # for each telescope in the output file. The feature vectors are stored @@ -1786,6 +1920,10 @@ def start(self): f"{self.prefix}_tel_energy_feature_vectors", f"{self.prefix}_energy_feature_vectors", ) + feature_vector_table.rename_column( + f"{self.prefix}_tel_impact_feature_vectors", + f"{self.prefix}_impact_feature_vectors", + ) feature_vector_table.rename_column( f"{self.prefix}_tel_geometry_feature_vectors", f"{self.prefix}_geometry_feature_vectors", From 8088947693ae3941aeb9b2f746ca9245d8ae1b59 Mon Sep 17 00:00:00 2001 From: TjarkMiener Date: Thu, 28 Aug 2025 17:23:17 +0200 Subject: [PATCH 4/5] move predict tools into separate files add notebook for muon reco --- ctlearn/tools/predict_model.py | 955 +---------------------- ctlearn/tools/predict_mono_model.py | 586 ++++++++++++++ ctlearn/tools/predict_stereo_model.py | 414 ++++++++++ notebooks/Muon_impact_reco_CTLearn.ipynb | 379 +++++++++ pyproject.toml | 4 +- 5 files changed, 1384 insertions(+), 954 deletions(-) create mode 100644 ctlearn/tools/predict_mono_model.py create mode 100644 ctlearn/tools/predict_stereo_model.py create mode 100644 notebooks/Muon_impact_reco_CTLearn.ipynb diff --git a/ctlearn/tools/predict_model.py b/ctlearn/tools/predict_model.py index e88af82c..983d9881 100644 --- a/ctlearn/tools/predict_model.py +++ b/ctlearn/tools/predict_model.py @@ -1,30 +1,21 @@ """ -Tools to predict the gammaness, energy and arrival direction in monoscopic and stereoscopic mode using ``CTLearnModel`` on R1/DL1 data using the ``DLDataReader`` and ``DLDataLoader``. +Abstract tool to predict the gammaness, energy and arrival direction using ``CTLearnModel`` on R1/DL1 data using the ``DLDataReader`` and ``DLDataLoader``. """ import atexit -import pathlib import numpy as np import os import tensorflow as tf import keras from astropy import units as u -from astropy.coordinates.earth import EarthLocation from astropy.coordinates import AltAz, SkyCoord from astropy.table import ( Table, - hstack, vstack, join, - setdiff, ) -from ctapipe.containers import ( - ParticleClassificationContainer, - ReconstructedGeometryContainer, - ReconstructedEnergyContainer, -) from ctapipe.coordinates import CameraFrame, NominalFrame from ctapipe.core import Tool from ctapipe.core.tool import ToolConfigurationError @@ -33,19 +24,12 @@ Int, Path, flag, - Set, - Dict, - List, - CaselessStrEnum, ComponentName, Unicode, classes_with_traits, ) from ctapipe.monitoring.interpolation import PointingInterpolator -from ctapipe.io import read_table, write_table, HDF5Merger -from ctapipe.reco.reconstructor import ReconstructionProperty -from ctapipe.reco.stereo_combination import StereoCombiner -from ctapipe.reco.utils import add_defaults_and_meta +from ctapipe.io import write_table, HDF5Merger from dl1_data_handler.reader import ( DLDataReader, ProcessType, @@ -64,11 +48,7 @@ SUBARRAY_EVENT_KEYS = ["obs_id", "event_id"] TELESCOPE_EVENT_KEYS = ["obs_id", "event_id", "tel_id"] -__all__ = [ - "PredictCTLearnModel", - "MonoPredictCTLearnModel", - "StereoPredictCTLearnModel", -] +__all__ = ["PredictCTLearnModel"] class PredictCTLearnModel(Tool): @@ -1084,932 +1064,3 @@ def _create_feature_vectors_table( name=f"{self.prefix}_tel_is_valid", ) return feature_vector_table - - -class MonoPredictCTLearnModel(PredictCTLearnModel): - """ - Tool to predict the gammaness, energy and arrival direction from monoscopic R1/DL1 data using CTLearn models. - - This tool extends the ``PredictCTLearnModel`` to specifically handle monoscopic R1/DL1 data. The prediction - is performed using the CTLearn models. The data is stored in the output file following the ctapipe DL2 data format. - It also stores the telescope pointing monitoring and DL1 feature vectors (if selected) in the output file. - - Attributes - ---------- - name : str - Name of the tool. - description : str - Description of the tool. - examples : str - Examples of how to use the tool. - - Methods - ------- - start() - Start the tool. - _store_mc_telescope_pointing(all_identifiers) - Store the telescope pointing table for the mono mode for MC simulation. - """ - - name = "ctlearn-predict-mono-model" - description = __doc__ - - examples = """ - To predict from pixel-wise image data in mono mode using trained CTLearn models: - > ctlearn-predict-mono-model \\ - --input_url input.dl1.h5 \\ - --PredictCTLearnModel.batch_size=64 \\ - --PredictCTLearnModel.dl1dh_reader_type=DLImageReader \\ - --DLImageReader.channels=cleaned_image \\ - --DLImageReader.channels=cleaned_relative_peak_time \\ - --DLImageReader.image_mapper_type=BilinearMapper \\ - --type_model="/path/to/your/mono/type/ctlearn_model.cpk" \\ - --energy_model="/path/to/your/mono/energy/ctlearn_model.cpk" \\ - --cameradirection_model="/path/to/your/mono/cameradirection/ctlearn_model.cpk" \\ - --dl1-features \\ - --use-HDF5Merger \\ - --no-dl1-images \\ - --no-true-images \\ - --output output.dl2.h5 \\ - --PredictCTLearnModel.overwrite_tables=True \\ - - To predict from pixel-wise waveform data in mono mode using trained CTLearn models: - > ctlearn-predict-mono-model \\ - --input_url input.r1.h5 \\ - --PredictCTLearnModel.dl1dh_reader_type=DLWaveformReader \\ - --DLWaveformReader.sequnce_length=20 \\ - --DLWaveformReader.image_mapper_type=BilinearMapper \\ - --type_model="/path/to/your/mono_waveform/type/ctlearn_model.cpk" \\ - --energy_model="/path/to/your/mono_waveform/energy/ctlearn_model.cpk" \\ - --cameradirection_model="/path/to/your/mono_waveform/cameradirection/ctlearn_model.cpk" \\ - --use-HDF5Merger \\ - --no-r0-waveforms \\ - --no-r1-waveforms \\ - --no-dl1-images \\ - --no-true-images \\ - --output output.dl2.h5 \\ - --PredictCTLearnModel.overwrite_tables=True \\ - """ - - stereo_combiner_cls = ComponentName( - StereoCombiner, - default_value="StereoMeanCombiner", - help="Which stereo combination method to use after the monoscopic reconstruction.", - ).tag(config=True) - - def start(self): - self.log.info("Processing the telescope pointings...") - # Retrieve the IDs from the dl1dh for the prediction tables - example_identifiers = self.dl1dh_reader.example_identifiers.copy() - example_identifiers.keep_columns(TELESCOPE_EVENT_KEYS) - all_identifiers = self.dl1dh_reader.tel_trigger_table.copy() - all_identifiers.keep_columns(TELESCOPE_EVENT_KEYS + ["time"]) - nonexample_identifiers = setdiff( - all_identifiers, example_identifiers, keys=TELESCOPE_EVENT_KEYS - ) - nonexample_identifiers.remove_column("time") - # Pointing table for the mono mode for MC simulation - if self.dl1dh_reader.process_type == ProcessType.Simulation: - pointing_info = self._store_mc_telescope_pointing(all_identifiers) - - # Pointing table for the observation mode - if self.dl1dh_reader.process_type == ProcessType.Observation: - pointing_info = super()._store_pointing(all_identifiers) - - self.log.info("Starting the prediction...") - classification_feature_vectors = None - if self.load_type_model_from is not None: - self.type_stereo_combiner = StereoCombiner.from_name( - self.stereo_combiner_cls, - prefix=self.prefix, - property=ReconstructionProperty.PARTICLE_TYPE, - parent=self, - ) - # Predict the particle type of the primary particle - classification_table, classification_feature_vectors = ( - super()._predict_classification(example_identifiers) - ) - if self.dl2_telescope: - # Produce output table with NaNs for missing predictions - if len(nonexample_identifiers) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers, - columns=[f"{self.prefix}_tel_prediction"], - shapes=[(len(nonexample_identifiers),)], - ) - classification_table = vstack([classification_table, nan_table]) - # Add is_valid column to the particle type table - classification_table.add_column( - ~np.isnan( - classification_table[f"{self.prefix}_tel_prediction"].data, - dtype=bool, - ), - name=f"{self.prefix}_tel_is_valid", - ) - # Add the default values and meta data to the table - add_defaults_and_meta( - classification_table, - ParticleClassificationContainer, - prefix=self.prefix, - add_tel_prefix=True, - ) - for tel_id in self.dl1dh_reader.selected_telescopes[ - self.dl1dh_reader.tel_type - ]: - # Retrieve the example identifiers for the selected telescope - telescope_mask = classification_table["tel_id"] == tel_id - classification_tel_table = classification_table[telescope_mask] - classification_tel_table.sort(TELESCOPE_EVENT_KEYS) - # Save the prediction to the output file for the selected telescope - write_table( - classification_tel_table, - self.output_path, - f"{DL2_TELESCOPE_GROUP}/classification/{self.prefix}/tel_{tel_id:03d}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_TELESCOPE_GROUP}/classification/{self.prefix}/tel_{tel_id:03d}", - ) - if self.dl2_subarray: - self.log.info("Processing and storing the subarray type prediction...") - # Combine the telescope predictions to the subarray prediction using the stereo combiner - subarray_classification_table = self.type_stereo_combiner.predict_table( - classification_table - ) - # TODO: Remove temporary fix once the stereo combiner returns correct table - # Check if the table has to be converted to a boolean mask - if ( - subarray_classification_table[f"{self.prefix}_telescopes"].dtype - != np.bool_ - ): - # Create boolean mask for telescopes that participate in the stereo reconstruction combination - reco_telescopes = np.zeros( - ( - len(subarray_classification_table), - len(self.dl1dh_reader.tel_ids), - ), - dtype=bool, - ) - # Loop over the table and set the boolean mask for the telescopes - for index, tel_id_mask in enumerate( - subarray_classification_table[f"{self.prefix}_telescopes"] - ): - if not tel_id_mask: - continue - for tel_id in tel_id_mask: - reco_telescopes[index][ - self.dl1dh_reader.subarray.tel_ids_to_indices(tel_id) - ] = True - # Overwrite the column with the boolean mask with fix length - subarray_classification_table[f"{self.prefix}_telescopes"] = ( - reco_telescopes - ) - # Save the prediction to the output file - write_table( - subarray_classification_table, - self.output_path, - f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", - ) - energy_feature_vectors = None - if self.load_energy_model_from is not None: - self.energy_stereo_combiner = StereoCombiner.from_name( - self.stereo_combiner_cls, - prefix=self.prefix, - property=ReconstructionProperty.ENERGY, - parent=self, - ) - # Predict the energy of the primary particle - energy_table, energy_feature_vectors = super()._predict_energy( - example_identifiers - ) - if self.dl2_telescope: - # Produce output table with NaNs for missing predictions - if len(nonexample_identifiers) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers, - columns=[f"{self.prefix}_tel_energy"], - shapes=[(len(nonexample_identifiers),)], - ) - energy_table = vstack([energy_table, nan_table]) - # Add is_valid column to the energy table - energy_table.add_column( - ~np.isnan( - energy_table[f"{self.prefix}_tel_energy"].data, dtype=bool - ), - name=f"{self.prefix}_tel_is_valid", - ) - # Add the default values and meta data to the table - add_defaults_and_meta( - energy_table, - ReconstructedEnergyContainer, - prefix=self.prefix, - add_tel_prefix=True, - ) - for tel_id in self.dl1dh_reader.selected_telescopes[ - self.dl1dh_reader.tel_type - ]: - # Retrieve the example identifiers for the selected telescope - telescope_mask = energy_table["tel_id"] == tel_id - energy_tel_table = energy_table[telescope_mask] - energy_tel_table.sort(TELESCOPE_EVENT_KEYS) - # Save the prediction to the output file - write_table( - energy_tel_table, - self.output_path, - f"{DL2_TELESCOPE_GROUP}/energy/{self.prefix}/tel_{tel_id:03d}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_TELESCOPE_GROUP}/energy/{self.prefix}/tel_{tel_id:03d}", - ) - if self.dl2_subarray: - self.log.info( - "Processing and storing the subarray energy prediction..." - ) - # Combine the telescope predictions to the subarray prediction using the stereo combiner - subarray_energy_table = self.energy_stereo_combiner.predict_table( - energy_table - ) - # TODO: Remove temporary fix once the stereo combiner returns correct table - # Check if the table has to be converted to a boolean mask - if subarray_energy_table[f"{self.prefix}_telescopes"].dtype != np.bool_: - # Create boolean mask for telescopes that participate in the stereo reconstruction combination - reco_telescopes = np.zeros( - (len(subarray_energy_table), len(self.dl1dh_reader.tel_ids)), - dtype=bool, - ) - # Loop over the table and set the boolean mask for the telescopes - for index, tel_id_mask in enumerate( - subarray_energy_table[f"{self.prefix}_telescopes"] - ): - if not tel_id_mask: - continue - for tel_id in tel_id_mask: - reco_telescopes[index][ - self.dl1dh_reader.subarray.tel_ids_to_indices(tel_id) - ] = True - # Overwrite the column with the boolean mask with fix length - subarray_energy_table[f"{self.prefix}_telescopes"] = reco_telescopes - # Save the prediction to the output file - write_table( - subarray_energy_table, - self.output_path, - f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", - ) - - impact_feature_vectors = None - if self.load_impact_model_from is not None: - # Predict the impact of the primary particle - impact_table, impact_feature_vectors = super()._predict_impact( - example_identifiers - ) - if self.dl2_telescope: - # Produce output table with NaNs for missing predictions - if len(nonexample_identifiers) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers, - columns=[f"{self.prefix}_tel_impact"], - shapes=[(len(nonexample_identifiers),)], - ) - impact_table = vstack([impact_table, nan_table]) - # Add is_valid column to the impact table - impact_table.add_column( - ~np.isnan( - impact_table[f"{self.prefix}_tel_impact"].data, dtype=bool - ), - name=f"{self.prefix}_tel_is_valid", - ) - for tel_id in self.dl1dh_reader.selected_telescopes[ - self.dl1dh_reader.tel_type - ]: - # Retrieve the example identifiers for the selected telescope - telescope_mask = impact_table["tel_id"] == tel_id - impact_tel_table = impact_table[telescope_mask] - impact_tel_table.sort(TELESCOPE_EVENT_KEYS) - # Save the prediction to the output file - write_table( - impact_tel_table, - self.output_path, - f"{DL2_TELESCOPE_GROUP}/impact/{self.prefix}/tel_{tel_id:03d}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_TELESCOPE_GROUP}/impact/{self.prefix}/tel_{tel_id:03d}", - ) - - if self.dl2_subarray: - raise NotImplementedError("No impact reconstruction property in ctapipe defined. No stereo combiner available.") - - direction_feature_vectors = None - if self.load_cameradirection_model_from is not None: - self.geometry_stereo_combiner = StereoCombiner.from_name( - self.stereo_combiner_cls, - prefix=self.prefix, - property=ReconstructionProperty.GEOMETRY, - parent=self, - ) - # Join the prediction table with the telescope pointing table - example_identifiers = join( - left=example_identifiers, - right=pointing_info, - keys=TELESCOPE_EVENT_KEYS, - ) - # Predict the arrival direction of the primary particle - direction_table, direction_feature_vectors = ( - super()._predict_cameradirection(example_identifiers) - ) - direction_tel_tables = [] - if self.dl2_telescope: - for tel_id in self.dl1dh_reader.selected_telescopes[ - self.dl1dh_reader.tel_type - ]: - # Retrieve the example identifiers for the selected telescope - telescope_mask = direction_table["tel_id"] == tel_id - direction_tel_table = direction_table[telescope_mask] - direction_tel_table = super()._transform_cam_coord_offsets_to_sky( - direction_tel_table - ) - # Produce output table with NaNs for missing predictions - nan_telescope_mask = nonexample_identifiers["tel_id"] == tel_id - nonexample_identifiers_tel = nonexample_identifiers[ - nan_telescope_mask - ] - if len(nonexample_identifiers_tel) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers_tel, - columns=[f"{self.prefix}_tel_alt", f"{self.prefix}_tel_az"], - shapes=[ - (len(nonexample_identifiers_tel),), - (len(nonexample_identifiers_tel),), - ], - ) - direction_tel_table = vstack([direction_tel_table, nan_table]) - direction_tel_table.sort(TELESCOPE_EVENT_KEYS) - # Add is_valid column to the direction table - direction_tel_table.add_column( - ~np.isnan( - direction_tel_table[f"{self.prefix}_tel_alt"].data, - dtype=bool, - ), - name=f"{self.prefix}_tel_is_valid", - ) - # Add the default values and meta data to the table - add_defaults_and_meta( - direction_tel_table, - ReconstructedGeometryContainer, - prefix=self.prefix, - add_tel_prefix=True, - ) - direction_tel_tables.append(direction_tel_table) - # Save the prediction to the output file - write_table( - direction_tel_table, - self.output_path, - f"{DL2_TELESCOPE_GROUP}/geometry/{self.prefix}/tel_{tel_id:03d}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_TELESCOPE_GROUP}/geometry/{self.prefix}/tel_{tel_id:03d}", - ) - if self.dl2_subarray: - self.log.info( - "Processing and storing the subarray geometry prediction..." - ) - # Stack the telescope tables to the subarray table - direction_tel_tables = vstack(direction_tel_tables) - # Sort the table by the telescope event keys - direction_tel_tables.sort(TELESCOPE_EVENT_KEYS) - # Combine the telescope predictions to the subarray prediction using the stereo combiner - subarray_direction_table = self.geometry_stereo_combiner.predict_table( - direction_tel_tables - ) - # TODO: Remove temporary fix once the stereo combiner returns correct table - # Check if the table has to be converted to a boolean mask - if ( - subarray_direction_table[f"{self.prefix}_telescopes"].dtype - != np.bool_ - ): - # Create boolean mask for telescopes that participate in the stereo reconstruction combination - reco_telescopes = np.zeros( - (len(subarray_direction_table), len(self.dl1dh_reader.tel_ids)), - dtype=bool, - ) - # Loop over the table and set the boolean mask for the telescopes - for index, tel_id_mask in enumerate( - subarray_direction_table[f"{self.prefix}_telescopes"] - ): - if not tel_id_mask: - continue - for tel_id in tel_id_mask: - reco_telescopes[index][ - self.dl1dh_reader.subarray.tel_ids_to_indices(tel_id) - ] = True - # Overwrite the column with the boolean mask with fix length - subarray_direction_table[f"{self.prefix}_telescopes"] = ( - reco_telescopes - ) - # Save the prediction to the output file - write_table( - subarray_direction_table, - self.output_path, - f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", - ) - # Create the feature vector table if the DL1 features are enabled - if self.dl1_features: - self.log.info("Processing and storing dl1 feature vectors...") - feature_vector_table = super()._create_feature_vectors_table( - example_identifiers, - nonexample_identifiers, - classification_feature_vectors, - energy_feature_vectors, - direction_feature_vectors, - impact_feature_vectors, - ) - # Loop over the selected telescopes and store the feature vectors - # for each telescope in the output file. The feature vectors are stored - # in the DL1_TELESCOPE_GROUP/features/{prefix}/tel_{tel_id:03d} table. - for tel_id in self.dl1dh_reader.selected_telescopes[ - self.dl1dh_reader.tel_type - ]: - # Retrieve the example identifiers for the selected telescope - telescope_mask = feature_vector_table["tel_id"] == tel_id - feature_vectors_tel_table = feature_vector_table[telescope_mask] - feature_vectors_tel_table.sort(TELESCOPE_EVENT_KEYS) - # Save the prediction to the output file - write_table( - feature_vectors_tel_table, - self.output_path, - f"{DL1_TELESCOPE_GROUP}/features/{self.prefix}/tel_{tel_id:03d}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL1 feature vectors was stored in '%s' under '%s'", - self.output_path, - f"{DL1_TELESCOPE_GROUP}/features/{self.prefix}/tel_{tel_id:03d}", - ) - - def _store_mc_telescope_pointing(self, all_identifiers): - """ - Store the telescope pointing table from MC simulation to the output file. - - Parameters: - ----------- - all_identifiers : astropy.table.Table - Table containing the telescope pointing information. - """ - # Create the pointing table for each telescope - pointing_info = [] - for tel_id in self.dl1dh_reader.selected_telescopes[self.dl1dh_reader.tel_type]: - # Pointing table for the mono mode - tel_pointing = self.dl1dh_reader.get_tel_pointing(self.input_url, tel_id) - tel_pointing.rename_column("telescope_pointing_azimuth", "pointing_azimuth") - tel_pointing.rename_column( - "telescope_pointing_altitude", "pointing_altitude" - ) - # Join the prediction table with the telescope pointing table - tel_pointing = join( - left=tel_pointing, - right=all_identifiers, - keys=["obs_id", "tel_id"], - ) - # TODO: use keep_order for astropy v7.0.0 - tel_pointing.sort(TELESCOPE_EVENT_KEYS) - # Retrieve the example identifiers for the selected telescope - tel_pointing_table = Table( - { - "time": tel_pointing["time"], - "azimuth": tel_pointing["pointing_azimuth"], - "altitude": tel_pointing["pointing_altitude"], - } - ) - write_table( - tel_pointing_table, - self.output_path, - f"{POINTING_GROUP}/tel_{tel_id:03d}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL1 telescope pointing table was stored in '%s' under '%s'", - self.output_path, - f"{POINTING_GROUP}/tel_{tel_id:03d}", - ) - pointing_info.append(tel_pointing) - pointing_info = vstack(pointing_info) - return pointing_info - - -class StereoPredictCTLearnModel(PredictCTLearnModel): - """ - Tool to predict the gammaness, energy and arrival direction from R1/DL1 stereoscopic data using CTLearn models. - - This tool extends the ``PredictCTLearnModel`` to specifically handle stereoscopic R1/DL1 data. The prediction - is performed using the CTLearn models. The data is stored in the output file following the ctapipe DL2 data format. - It also stores the telescope/subarray pointing monitoring and DL1 feature vectors (if selected) in the output file. - - Attributes - ---------- - name : str - Name of the tool. - description : str - Description of the tool. - examples : str - Examples of how to use the tool. - - Methods - ------- - start() - Start the tool. - _store_mc_subarray_pointing(all_identifiers) - Store the subarray pointing table for the stereo mode for MC simulation. - """ - - name = "ctlearn-predict-stereo-model" - description = __doc__ - - examples = """ - To predict from pixel-wise image data in stereo mode using trained CTLearn models: - > ctlearn-predict-stereo-model \\ - --input_url input.dl1.h5 \\ - --PredictCTLearnModel.batch_size=16 \\ - --PredictCTLearnModel.dl1dh_reader_type=DLImageReader \\ - --DLImageReader.channels=cleaned_image \\ - --DLImageReader.channels=cleaned_relative_peak_time \\ - --DLImageReader.image_mapper_type=BilinearMapper \\ - --DLImageReader.mode=stereo \\ - --DLImageReader.min_telescopes=2 \\ - --PredictCTLearnModel.stack_telescope_images=True \\ - --type_model="/path/to/your/stereo/type/ctlearn_model.cpk" \\ - --energy_model="/path/to/your/stereo/energy/ctlearn_model.cpk" \\ - --skydirection_model="/path/to/your/stereo/skydirection/ctlearn_model.cpk" \\ - --output output.dl2.h5 \\ - --PredictCTLearnModel.overwrite_tables=True \\ - """ - - def start(self): - self.log.info("Processing the telescope pointings...") - # Retrieve the IDs from the dl1dh for the prediction tables - example_identifiers = self.dl1dh_reader.unique_example_identifiers.copy() - example_identifiers.keep_columns(SUBARRAY_EVENT_KEYS) - all_identifiers = self.dl1dh_reader.subarray_trigger_table.copy() - all_identifiers.keep_columns(SUBARRAY_EVENT_KEYS + ["time"]) - nonexample_identifiers = setdiff( - all_identifiers, example_identifiers, keys=SUBARRAY_EVENT_KEYS - ) - nonexample_identifiers.remove_column("time") - # Construct the survival telescopes for each event of the example_identifiers - survival_telescopes = [] - for subarray_event in self.dl1dh_reader.example_identifiers_grouped.groups: - survival_mask = np.zeros(len(self.dl1dh_reader.tel_ids), dtype=bool) - survival_tels = [ - self.dl1dh_reader.subarray.tel_indices[tel_id] - for tel_id in subarray_event["tel_id"].data - ] - survival_mask[survival_tels] = True - survival_telescopes.append(survival_mask) - # Add the survival telescopes to the example_identifiers - example_identifiers.add_column( - survival_telescopes, name=f"{self.prefix}_telescopes" - ) - # Pointing table for the stereo mode for MC simulation - if self.dl1dh_reader.process_type == ProcessType.Simulation: - pointing_info = self._store_mc_subarray_pointing(all_identifiers) - - # Pointing table for the observation mode - if self.dl1dh_reader.process_type == ProcessType.Observation: - pointing_info = super()._store_pointing(all_identifiers) - - self.log.info("Starting the prediction...") - classification_feature_vectors = None - if self.load_type_model_from is not None: - # Predict the particle type of the primary particle - classification_table, classification_feature_vectors = ( - super()._predict_classification(example_identifiers) - ) - if self.dl2_subarray: - # Produce output table with NaNs for missing predictions - if len(nonexample_identifiers) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers, - columns=[f"{self.prefix}_tel_prediction"], - shapes=[(len(nonexample_identifiers),)], - ) - classification_table = vstack([classification_table, nan_table]) - # Add is_valid column to the particle type table - classification_table.add_column( - ~np.isnan( - classification_table[f"{self.prefix}_tel_prediction"].data, - dtype=bool, - ), - name=f"{self.prefix}_tel_is_valid", - ) - # Rename the columns for the stereo mode - classification_table.rename_column( - f"{self.prefix}_tel_prediction", f"{self.prefix}_prediction" - ) - classification_table.rename_column( - f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" - ) - classification_table.sort(SUBARRAY_EVENT_KEYS) - # Add the default values and meta data to the table - add_defaults_and_meta( - classification_table, - ParticleClassificationContainer, - prefix=self.prefix, - ) - # Save the prediction to the output file - write_table( - classification_table, - self.output_path, - f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", - ) - energy_feature_vectors = None - if self.load_energy_model_from is not None: - # Predict the energy of the primary particle - energy_table, energy_feature_vectors = super()._predict_energy( - example_identifiers - ) - if self.dl2_subarray: - # Produce output table with NaNs for missing predictions - if len(nonexample_identifiers) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers, - columns=[f"{self.prefix}_tel_energy"], - shapes=[(len(nonexample_identifiers),)], - ) - energy_table = vstack([energy_table, nan_table]) - # Add is_valid column to the energy table - energy_table.add_column( - ~np.isnan( - energy_table[f"{self.prefix}_tel_energy"].data, dtype=bool - ), - name=f"{self.prefix}_tel_is_valid", - ) - # Rename the columns for the stereo mode - energy_table.rename_column( - f"{self.prefix}_tel_energy", f"{self.prefix}_energy" - ) - energy_table.rename_column( - f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" - ) - energy_table.sort(SUBARRAY_EVENT_KEYS) - # Add the default values and meta data to the table - add_defaults_and_meta( - energy_table, - ReconstructedEnergyContainer, - prefix=self.prefix, - ) - # Save the prediction to the output file - write_table( - energy_table, - self.output_path, - f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", - ) - impact_feature_vectors = None - if self.load_impact_model_from is not None: - # Predict the impact of the primary particle - impact_table, impact_feature_vectors = super()._predict_impact( - example_identifiers - ) - if self.dl2_subarray: - # Produce output table with NaNs for missing predictions - if len(nonexample_identifiers) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers, - columns=[f"{self.prefix}_tel_impact"], - shapes=[(len(nonexample_identifiers),)], - ) - impact_table = vstack([impact_table, nan_table]) - # Add is_valid column to the impact table - impact_table.add_column( - ~np.isnan( - impact_table[f"{self.prefix}_tel_impact"].data, dtype=bool - ), - name=f"{self.prefix}_tel_is_valid", - ) - # Rename the columns for the stereo mode - impact_table.rename_column( - f"{self.prefix}_tel_impact", f"{self.prefix}_impact" - ) - impact_table.rename_column( - f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" - ) - impact_table.sort(SUBARRAY_EVENT_KEYS) - # Save the prediction to the output file - write_table( - impact_table, - self.output_path, - f"{DL2_SUBARRAY_GROUP}/impact/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_SUBARRAY_GROUP}/impact/{self.prefix}", - ) - direction_feature_vectors = None - if self.load_skydirection_model_from is not None: - # Join the prediction table with the telescope pointing table - example_identifiers = join( - left=example_identifiers, - right=pointing_info, - keys=SUBARRAY_EVENT_KEYS, - ) - # Predict the arrival direction of the primary particle - direction_table, direction_feature_vectors = super()._predict_skydirection( - example_identifiers - ) - if self.dl2_subarray: - # Transform the spherical coordinate offsets to sky coordinates - direction_table = super()._transform_spher_coord_offsets_to_sky( - direction_table - ) - # Produce output table with NaNs for missing predictions - if len(nonexample_identifiers) > 0: - nan_table = super()._create_nan_table( - nonexample_identifiers, - columns=[f"{self.prefix}_alt", f"{self.prefix}_az"], - shapes=[ - (len(nonexample_identifiers),), - (len(nonexample_identifiers),), - ], - ) - direction_table = vstack([direction_table, nan_table]) - # Add is_valid column to the direction table - direction_table.add_column( - ~np.isnan(direction_table[f"{self.prefix}_alt"].data, dtype=bool), - name=f"{self.prefix}_is_valid", - ) - direction_table.sort(SUBARRAY_EVENT_KEYS) - # Add the default values and meta data to the table - add_defaults_and_meta( - direction_table, - ReconstructedGeometryContainer, - prefix=self.prefix, - ) - # Save the prediction to the output file - write_table( - direction_table, - self.output_path, - f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL2 prediction data was stored in '%s' under '%s'", - self.output_path, - f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", - ) - - # Create the feature vector table if the DL1 features are enabled - if self.dl1_features: - self.log.info("Processing and storing dl1 feature vectors...") - feature_vector_table = super()._create_feature_vectors_table( - example_identifiers, - nonexample_identifiers, - classification_feature_vectors, - energy_feature_vectors, - direction_feature_vectors, - impact_feature_vectors, - ) - # Loop over the selected telescopes and store the feature vectors - # for each telescope in the output file. The feature vectors are stored - # in the DL1_TELESCOPE_GROUP/features/{prefix}/tel_{tel_id:03d} table. - # Rename the columns for the stereo mode - feature_vector_table.rename_column( - f"{self.prefix}_tel_classification_feature_vectors", - f"{self.prefix}_classification_feature_vectors", - ) - feature_vector_table.rename_column( - f"{self.prefix}_tel_energy_feature_vectors", - f"{self.prefix}_energy_feature_vectors", - ) - feature_vector_table.rename_column( - f"{self.prefix}_tel_impact_feature_vectors", - f"{self.prefix}_impact_feature_vectors", - ) - feature_vector_table.rename_column( - f"{self.prefix}_tel_geometry_feature_vectors", - f"{self.prefix}_geometry_feature_vectors", - ) - feature_vector_table.rename_column( - f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" - ) - feature_vector_table.sort(SUBARRAY_EVENT_KEYS) - # Save the prediction to the output file - write_table( - feature_vector_table, - self.output_path, - f"{DL1_SUBARRAY_GROUP}/features/{self.prefix}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL1 feature vectors was stored in '%s' under '%s'", - self.output_path, - f"{DL1_SUBARRAY_GROUP}/features/{self.prefix}", - ) - - def _store_mc_subarray_pointing(self, all_identifiers): - """ - Store the subarray pointing table from MC simulation to the output file. - - Parameters: - ----------- - all_identifiers : astropy.table.Table - Table containing the subarray pointing information. - """ - # Read the subarray pointing table - pointing_info = read_table( - self.input_url, - f"{SIMULATION_CONFIG_TABLE}", - ) - # Assuming min_az = max_az and min_alt = max_alt - pointing_info.keep_columns(["obs_id", "min_az", "min_alt"]) - pointing_info.rename_column("min_az", "pointing_azimuth") - pointing_info.rename_column("min_alt", "pointing_altitude") - # Join the prediction table with the telescope pointing table - pointing_info = join( - left=pointing_info, - right=all_identifiers, - keys=["obs_id"], - ) - # TODO: use keep_order for astropy v7.0.0 - pointing_info.sort(SUBARRAY_EVENT_KEYS) - # Create the pointing table - pointing_table = Table( - { - "time": pointing_info["time"], - "array_azimuth": pointing_info["pointing_azimuth"], - "array_altitude": pointing_info["pointing_altitude"], - "array_ra": np.nan * np.ones(len(pointing_info)), - "array_dec": np.nan * np.ones(len(pointing_info)), - } - ) - # Save the pointing table to the output file - write_table( - pointing_table, - self.output_path, - f"{SUBARRAY_POINTING_GROUP}", - overwrite=self.overwrite_tables, - ) - self.log.info( - "DL1 subarray pointing table was stored in '%s' under '%s'", - self.output_path, - f"{SUBARRAY_POINTING_GROUP}", - ) - return pointing_info - - -def mono_tool(): - # Run the tool - mono_tool = MonoPredictCTLearnModel() - mono_tool.run() - - -def stereo_tool(): - # Run the tool - stereo_tool = StereoPredictCTLearnModel() - stereo_tool.run() - - -if __name__ == "mono_tool": - mono_tool() - -if __name__ == "stereo_tool": - stereo_tool() diff --git a/ctlearn/tools/predict_mono_model.py b/ctlearn/tools/predict_mono_model.py new file mode 100644 index 00000000..5f74ac64 --- /dev/null +++ b/ctlearn/tools/predict_mono_model.py @@ -0,0 +1,586 @@ +""" +Tools to predict the gammaness, energy and arrival direction in monoscopic mode using ``CTLearnModel`` on R1/DL1 data using the ``DLDataReader`` and ``DLDataLoader``. +""" + +import numpy as np + +from astropy.table import ( + Table, + vstack, + join, + setdiff, +) + +from ctapipe.containers import ( + ParticleClassificationContainer, + ReconstructedGeometryContainer, + ReconstructedEnergyContainer, +) +from ctapipe.core.traits import ComponentName + +from ctapipe.io import write_table +from ctapipe.reco.reconstructor import ReconstructionProperty +from ctapipe.reco.stereo_combination import StereoCombiner +from ctapipe.reco.utils import add_defaults_and_meta +from dl1_data_handler.reader import ProcessType +from ctlearn.tools.predict_model import PredictCTLearnModel + +SIMULATION_CONFIG_TABLE = "/configuration/simulation/run" +FIXED_POINTING_GROUP = "/configuration/telescope/pointing" +POINTING_GROUP = "/dl1/monitoring/telescope/pointing" +SUBARRAY_POINTING_GROUP = "/dl1/monitoring/subarray/pointing" +DL1_TELESCOPE_GROUP = "/dl1/event/telescope" +DL1_SUBARRAY_GROUP = "/dl1/event/subarray" +DL2_SUBARRAY_GROUP = "/dl2/event/subarray" +DL2_TELESCOPE_GROUP = "/dl2/event/telescope" +SUBARRAY_EVENT_KEYS = ["obs_id", "event_id"] +TELESCOPE_EVENT_KEYS = ["obs_id", "event_id", "tel_id"] + +__all__ = ["MonoPredictCTLearnModel"] + + +class MonoPredictCTLearnModel(PredictCTLearnModel): + """ + Tool to predict the gammaness, energy and arrival direction from monoscopic R1/DL1 data using CTLearn models. + + This tool extends the ``PredictCTLearnModel`` to specifically handle monoscopic R1/DL1 data. The prediction + is performed using the CTLearn models. The data is stored in the output file following the ctapipe DL2 data format. + It also stores the telescope pointing monitoring and DL1 feature vectors (if selected) in the output file. + + Attributes + ---------- + name : str + Name of the tool. + description : str + Description of the tool. + examples : str + Examples of how to use the tool. + + Methods + ------- + start() + Start the tool. + _store_mc_telescope_pointing(all_identifiers) + Store the telescope pointing table for the mono mode for MC simulation. + """ + + name = "ctlearn-predict-mono-model" + description = __doc__ + + examples = """ + To predict from pixel-wise image data in mono mode using trained CTLearn models: + > ctlearn-predict-mono-model \\ + --input_url input.dl1.h5 \\ + --PredictCTLearnModel.batch_size=64 \\ + --PredictCTLearnModel.dl1dh_reader_type=DLImageReader \\ + --DLImageReader.channels=cleaned_image \\ + --DLImageReader.channels=cleaned_relative_peak_time \\ + --DLImageReader.image_mapper_type=BilinearMapper \\ + --type_model="/path/to/your/mono/type/ctlearn_model.cpk" \\ + --energy_model="/path/to/your/mono/energy/ctlearn_model.cpk" \\ + --cameradirection_model="/path/to/your/mono/cameradirection/ctlearn_model.cpk" \\ + --dl1-features \\ + --use-HDF5Merger \\ + --no-dl1-images \\ + --no-true-images \\ + --output output.dl2.h5 \\ + --PredictCTLearnModel.overwrite_tables=True \\ + + To predict from pixel-wise waveform data in mono mode using trained CTLearn models: + > ctlearn-predict-mono-model \\ + --input_url input.r1.h5 \\ + --PredictCTLearnModel.dl1dh_reader_type=DLWaveformReader \\ + --DLWaveformReader.sequnce_length=20 \\ + --DLWaveformReader.image_mapper_type=BilinearMapper \\ + --type_model="/path/to/your/mono_waveform/type/ctlearn_model.cpk" \\ + --energy_model="/path/to/your/mono_waveform/energy/ctlearn_model.cpk" \\ + --cameradirection_model="/path/to/your/mono_waveform/cameradirection/ctlearn_model.cpk" \\ + --use-HDF5Merger \\ + --no-r0-waveforms \\ + --no-r1-waveforms \\ + --no-dl1-images \\ + --no-true-images \\ + --output output.dl2.h5 \\ + --PredictCTLearnModel.overwrite_tables=True \\ + """ + + stereo_combiner_cls = ComponentName( + StereoCombiner, + default_value="StereoMeanCombiner", + help="Which stereo combination method to use after the monoscopic reconstruction.", + ).tag(config=True) + + def start(self): + self.log.info("Processing the telescope pointings...") + # Retrieve the IDs from the dl1dh for the prediction tables + example_identifiers = self.dl1dh_reader.example_identifiers.copy() + example_identifiers.keep_columns(TELESCOPE_EVENT_KEYS) + all_identifiers = self.dl1dh_reader.tel_trigger_table.copy() + all_identifiers.keep_columns(TELESCOPE_EVENT_KEYS + ["time"]) + nonexample_identifiers = setdiff( + all_identifiers, example_identifiers, keys=TELESCOPE_EVENT_KEYS + ) + nonexample_identifiers.remove_column("time") + # Pointing table for the mono mode for MC simulation + if self.dl1dh_reader.process_type == ProcessType.Simulation: + pointing_info = self._store_mc_telescope_pointing(all_identifiers) + + # Pointing table for the observation mode + if self.dl1dh_reader.process_type == ProcessType.Observation: + pointing_info = super()._store_pointing(all_identifiers) + + self.log.info("Starting the prediction...") + classification_feature_vectors = None + if self.load_type_model_from is not None: + self.type_stereo_combiner = StereoCombiner.from_name( + self.stereo_combiner_cls, + prefix=self.prefix, + property=ReconstructionProperty.PARTICLE_TYPE, + parent=self, + ) + # Predict the particle type of the primary particle + classification_table, classification_feature_vectors = ( + super()._predict_classification(example_identifiers) + ) + if self.dl2_telescope: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_prediction"], + shapes=[(len(nonexample_identifiers),)], + ) + classification_table = vstack([classification_table, nan_table]) + # Add is_valid column to the particle type table + classification_table.add_column( + ~np.isnan( + classification_table[f"{self.prefix}_tel_prediction"].data, + dtype=bool, + ), + name=f"{self.prefix}_tel_is_valid", + ) + # Add the default values and meta data to the table + add_defaults_and_meta( + classification_table, + ParticleClassificationContainer, + prefix=self.prefix, + add_tel_prefix=True, + ) + for tel_id in self.dl1dh_reader.selected_telescopes[ + self.dl1dh_reader.tel_type + ]: + # Retrieve the example identifiers for the selected telescope + telescope_mask = classification_table["tel_id"] == tel_id + classification_tel_table = classification_table[telescope_mask] + classification_tel_table.sort(TELESCOPE_EVENT_KEYS) + # Save the prediction to the output file for the selected telescope + write_table( + classification_tel_table, + self.output_path, + f"{DL2_TELESCOPE_GROUP}/classification/{self.prefix}/tel_{tel_id:03d}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_TELESCOPE_GROUP}/classification/{self.prefix}/tel_{tel_id:03d}", + ) + if self.dl2_subarray: + self.log.info("Processing and storing the subarray type prediction...") + # Combine the telescope predictions to the subarray prediction using the stereo combiner + subarray_classification_table = self.type_stereo_combiner.predict_table( + classification_table + ) + # TODO: Remove temporary fix once the stereo combiner returns correct table + # Check if the table has to be converted to a boolean mask + if ( + subarray_classification_table[f"{self.prefix}_telescopes"].dtype + != np.bool_ + ): + # Create boolean mask for telescopes that participate in the stereo reconstruction combination + reco_telescopes = np.zeros( + ( + len(subarray_classification_table), + len(self.dl1dh_reader.tel_ids), + ), + dtype=bool, + ) + # Loop over the table and set the boolean mask for the telescopes + for index, tel_id_mask in enumerate( + subarray_classification_table[f"{self.prefix}_telescopes"] + ): + if not tel_id_mask: + continue + for tel_id in tel_id_mask: + reco_telescopes[index][ + self.dl1dh_reader.subarray.tel_ids_to_indices(tel_id) + ] = True + # Overwrite the column with the boolean mask with fix length + subarray_classification_table[f"{self.prefix}_telescopes"] = ( + reco_telescopes + ) + # Save the prediction to the output file + write_table( + subarray_classification_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", + ) + energy_feature_vectors = None + if self.load_energy_model_from is not None: + self.energy_stereo_combiner = StereoCombiner.from_name( + self.stereo_combiner_cls, + prefix=self.prefix, + property=ReconstructionProperty.ENERGY, + parent=self, + ) + # Predict the energy of the primary particle + energy_table, energy_feature_vectors = super()._predict_energy( + example_identifiers + ) + if self.dl2_telescope: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_energy"], + shapes=[(len(nonexample_identifiers),)], + ) + energy_table = vstack([energy_table, nan_table]) + # Add is_valid column to the energy table + energy_table.add_column( + ~np.isnan( + energy_table[f"{self.prefix}_tel_energy"].data, dtype=bool + ), + name=f"{self.prefix}_tel_is_valid", + ) + # Add the default values and meta data to the table + add_defaults_and_meta( + energy_table, + ReconstructedEnergyContainer, + prefix=self.prefix, + add_tel_prefix=True, + ) + for tel_id in self.dl1dh_reader.selected_telescopes[ + self.dl1dh_reader.tel_type + ]: + # Retrieve the example identifiers for the selected telescope + telescope_mask = energy_table["tel_id"] == tel_id + energy_tel_table = energy_table[telescope_mask] + energy_tel_table.sort(TELESCOPE_EVENT_KEYS) + # Save the prediction to the output file + write_table( + energy_tel_table, + self.output_path, + f"{DL2_TELESCOPE_GROUP}/energy/{self.prefix}/tel_{tel_id:03d}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_TELESCOPE_GROUP}/energy/{self.prefix}/tel_{tel_id:03d}", + ) + if self.dl2_subarray: + self.log.info( + "Processing and storing the subarray energy prediction..." + ) + # Combine the telescope predictions to the subarray prediction using the stereo combiner + subarray_energy_table = self.energy_stereo_combiner.predict_table( + energy_table + ) + # TODO: Remove temporary fix once the stereo combiner returns correct table + # Check if the table has to be converted to a boolean mask + if subarray_energy_table[f"{self.prefix}_telescopes"].dtype != np.bool_: + # Create boolean mask for telescopes that participate in the stereo reconstruction combination + reco_telescopes = np.zeros( + (len(subarray_energy_table), len(self.dl1dh_reader.tel_ids)), + dtype=bool, + ) + # Loop over the table and set the boolean mask for the telescopes + for index, tel_id_mask in enumerate( + subarray_energy_table[f"{self.prefix}_telescopes"] + ): + if not tel_id_mask: + continue + for tel_id in tel_id_mask: + reco_telescopes[index][ + self.dl1dh_reader.subarray.tel_ids_to_indices(tel_id) + ] = True + # Overwrite the column with the boolean mask with fix length + subarray_energy_table[f"{self.prefix}_telescopes"] = reco_telescopes + # Save the prediction to the output file + write_table( + subarray_energy_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", + ) + + impact_feature_vectors = None + if self.load_impact_model_from is not None: + # Predict the impact of the primary particle + impact_table, impact_feature_vectors = super()._predict_impact( + example_identifiers + ) + if self.dl2_telescope: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_impact"], + shapes=[(len(nonexample_identifiers),)], + ) + impact_table = vstack([impact_table, nan_table]) + # Add is_valid column to the impact table + impact_table.add_column( + ~np.isnan( + impact_table[f"{self.prefix}_tel_impact"].data, dtype=bool + ), + name=f"{self.prefix}_tel_is_valid", + ) + for tel_id in self.dl1dh_reader.selected_telescopes[ + self.dl1dh_reader.tel_type + ]: + # Retrieve the example identifiers for the selected telescope + telescope_mask = impact_table["tel_id"] == tel_id + impact_tel_table = impact_table[telescope_mask] + impact_tel_table.sort(TELESCOPE_EVENT_KEYS) + # Save the prediction to the output file + write_table( + impact_tel_table, + self.output_path, + f"{DL2_TELESCOPE_GROUP}/impact/{self.prefix}/tel_{tel_id:03d}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_TELESCOPE_GROUP}/impact/{self.prefix}/tel_{tel_id:03d}", + ) + + if self.dl2_subarray: + raise NotImplementedError("No impact reconstruction property in ctapipe defined. No stereo combiner available.") + + direction_feature_vectors = None + if self.load_cameradirection_model_from is not None: + self.geometry_stereo_combiner = StereoCombiner.from_name( + self.stereo_combiner_cls, + prefix=self.prefix, + property=ReconstructionProperty.GEOMETRY, + parent=self, + ) + # Join the prediction table with the telescope pointing table + example_identifiers = join( + left=example_identifiers, + right=pointing_info, + keys=TELESCOPE_EVENT_KEYS, + ) + # Predict the arrival direction of the primary particle + direction_table, direction_feature_vectors = ( + super()._predict_cameradirection(example_identifiers) + ) + direction_tel_tables = [] + if self.dl2_telescope: + for tel_id in self.dl1dh_reader.selected_telescopes[ + self.dl1dh_reader.tel_type + ]: + # Retrieve the example identifiers for the selected telescope + telescope_mask = direction_table["tel_id"] == tel_id + direction_tel_table = direction_table[telescope_mask] + direction_tel_table = super()._transform_cam_coord_offsets_to_sky( + direction_tel_table + ) + # Produce output table with NaNs for missing predictions + nan_telescope_mask = nonexample_identifiers["tel_id"] == tel_id + nonexample_identifiers_tel = nonexample_identifiers[ + nan_telescope_mask + ] + if len(nonexample_identifiers_tel) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers_tel, + columns=[f"{self.prefix}_tel_alt", f"{self.prefix}_tel_az"], + shapes=[ + (len(nonexample_identifiers_tel),), + (len(nonexample_identifiers_tel),), + ], + ) + direction_tel_table = vstack([direction_tel_table, nan_table]) + direction_tel_table.sort(TELESCOPE_EVENT_KEYS) + # Add is_valid column to the direction table + direction_tel_table.add_column( + ~np.isnan( + direction_tel_table[f"{self.prefix}_tel_alt"].data, + dtype=bool, + ), + name=f"{self.prefix}_tel_is_valid", + ) + # Add the default values and meta data to the table + add_defaults_and_meta( + direction_tel_table, + ReconstructedGeometryContainer, + prefix=self.prefix, + add_tel_prefix=True, + ) + direction_tel_tables.append(direction_tel_table) + # Save the prediction to the output file + write_table( + direction_tel_table, + self.output_path, + f"{DL2_TELESCOPE_GROUP}/geometry/{self.prefix}/tel_{tel_id:03d}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_TELESCOPE_GROUP}/geometry/{self.prefix}/tel_{tel_id:03d}", + ) + if self.dl2_subarray: + self.log.info( + "Processing and storing the subarray geometry prediction..." + ) + # Stack the telescope tables to the subarray table + direction_tel_tables = vstack(direction_tel_tables) + # Sort the table by the telescope event keys + direction_tel_tables.sort(TELESCOPE_EVENT_KEYS) + # Combine the telescope predictions to the subarray prediction using the stereo combiner + subarray_direction_table = self.geometry_stereo_combiner.predict_table( + direction_tel_tables + ) + # TODO: Remove temporary fix once the stereo combiner returns correct table + # Check if the table has to be converted to a boolean mask + if ( + subarray_direction_table[f"{self.prefix}_telescopes"].dtype + != np.bool_ + ): + # Create boolean mask for telescopes that participate in the stereo reconstruction combination + reco_telescopes = np.zeros( + (len(subarray_direction_table), len(self.dl1dh_reader.tel_ids)), + dtype=bool, + ) + # Loop over the table and set the boolean mask for the telescopes + for index, tel_id_mask in enumerate( + subarray_direction_table[f"{self.prefix}_telescopes"] + ): + if not tel_id_mask: + continue + for tel_id in tel_id_mask: + reco_telescopes[index][ + self.dl1dh_reader.subarray.tel_ids_to_indices(tel_id) + ] = True + # Overwrite the column with the boolean mask with fix length + subarray_direction_table[f"{self.prefix}_telescopes"] = ( + reco_telescopes + ) + # Save the prediction to the output file + write_table( + subarray_direction_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", + ) + # Create the feature vector table if the DL1 features are enabled + if self.dl1_features: + self.log.info("Processing and storing dl1 feature vectors...") + feature_vector_table = super()._create_feature_vectors_table( + example_identifiers, + nonexample_identifiers, + classification_feature_vectors, + energy_feature_vectors, + direction_feature_vectors, + impact_feature_vectors, + ) + # Loop over the selected telescopes and store the feature vectors + # for each telescope in the output file. The feature vectors are stored + # in the DL1_TELESCOPE_GROUP/features/{prefix}/tel_{tel_id:03d} table. + for tel_id in self.dl1dh_reader.selected_telescopes[ + self.dl1dh_reader.tel_type + ]: + # Retrieve the example identifiers for the selected telescope + telescope_mask = feature_vector_table["tel_id"] == tel_id + feature_vectors_tel_table = feature_vector_table[telescope_mask] + feature_vectors_tel_table.sort(TELESCOPE_EVENT_KEYS) + # Save the prediction to the output file + write_table( + feature_vectors_tel_table, + self.output_path, + f"{DL1_TELESCOPE_GROUP}/features/{self.prefix}/tel_{tel_id:03d}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL1 feature vectors was stored in '%s' under '%s'", + self.output_path, + f"{DL1_TELESCOPE_GROUP}/features/{self.prefix}/tel_{tel_id:03d}", + ) + + def _store_mc_telescope_pointing(self, all_identifiers): + """ + Store the telescope pointing table from MC simulation to the output file. + + Parameters: + ----------- + all_identifiers : astropy.table.Table + Table containing the telescope pointing information. + """ + # Create the pointing table for each telescope + pointing_info = [] + for tel_id in self.dl1dh_reader.selected_telescopes[self.dl1dh_reader.tel_type]: + # Pointing table for the mono mode + tel_pointing = self.dl1dh_reader.get_tel_pointing(self.input_url, tel_id) + tel_pointing.rename_column("telescope_pointing_azimuth", "pointing_azimuth") + tel_pointing.rename_column( + "telescope_pointing_altitude", "pointing_altitude" + ) + # Join the prediction table with the telescope pointing table + tel_pointing = join( + left=tel_pointing, + right=all_identifiers, + keys=["obs_id", "tel_id"], + ) + # TODO: use keep_order for astropy v7.0.0 + tel_pointing.sort(TELESCOPE_EVENT_KEYS) + # Retrieve the example identifiers for the selected telescope + tel_pointing_table = Table( + { + "time": tel_pointing["time"], + "azimuth": tel_pointing["pointing_azimuth"], + "altitude": tel_pointing["pointing_altitude"], + } + ) + write_table( + tel_pointing_table, + self.output_path, + f"{POINTING_GROUP}/tel_{tel_id:03d}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL1 telescope pointing table was stored in '%s' under '%s'", + self.output_path, + f"{POINTING_GROUP}/tel_{tel_id:03d}", + ) + pointing_info.append(tel_pointing) + pointing_info = vstack(pointing_info) + return pointing_info + +def main(): + # Run the tool + tool = MonoPredictCTLearnModel() + tool.run() + + +if __name__ == "main": + main() diff --git a/ctlearn/tools/predict_stereo_model.py b/ctlearn/tools/predict_stereo_model.py new file mode 100644 index 00000000..641daacf --- /dev/null +++ b/ctlearn/tools/predict_stereo_model.py @@ -0,0 +1,414 @@ +""" +Tools to predict the gammaness, energy and arrival direction in stereoscopic mode using ``CTLearnModel`` on R1/DL1 data using the ``DLDataReader`` and ``DLDataLoader``. +""" + +import numpy as np +from astropy.table import ( + Table, + vstack, + join, + setdiff, +) + +from ctapipe.containers import ( + ParticleClassificationContainer, + ReconstructedGeometryContainer, + ReconstructedEnergyContainer, +) +from ctapipe.reco.utils import add_defaults_and_meta +from dl1_data_handler.reader import ProcessType +from ctlearn.tools.predict_model import PredictCTLearnModel + +SIMULATION_CONFIG_TABLE = "/configuration/simulation/run" +FIXED_POINTING_GROUP = "/configuration/telescope/pointing" +POINTING_GROUP = "/dl1/monitoring/telescope/pointing" +SUBARRAY_POINTING_GROUP = "/dl1/monitoring/subarray/pointing" +DL1_TELESCOPE_GROUP = "/dl1/event/telescope" +DL1_SUBARRAY_GROUP = "/dl1/event/subarray" +DL2_SUBARRAY_GROUP = "/dl2/event/subarray" +DL2_TELESCOPE_GROUP = "/dl2/event/telescope" +SUBARRAY_EVENT_KEYS = ["obs_id", "event_id"] +TELESCOPE_EVENT_KEYS = ["obs_id", "event_id", "tel_id"] + +__all__ = ["StereoPredictCTLearnModel"] + + +class StereoPredictCTLearnModel(PredictCTLearnModel): + """ + Tool to predict the gammaness, energy and arrival direction from R1/DL1 stereoscopic data using CTLearn models. + + This tool extends the ``PredictCTLearnModel`` to specifically handle stereoscopic R1/DL1 data. The prediction + is performed using the CTLearn models. The data is stored in the output file following the ctapipe DL2 data format. + It also stores the telescope/subarray pointing monitoring and DL1 feature vectors (if selected) in the output file. + + Attributes + ---------- + name : str + Name of the tool. + description : str + Description of the tool. + examples : str + Examples of how to use the tool. + + Methods + ------- + start() + Start the tool. + _store_mc_subarray_pointing(all_identifiers) + Store the subarray pointing table for the stereo mode for MC simulation. + """ + + name = "ctlearn-predict-stereo-model" + description = __doc__ + + examples = """ + To predict from pixel-wise image data in stereo mode using trained CTLearn models: + > ctlearn-predict-stereo-model \\ + --input_url input.dl1.h5 \\ + --PredictCTLearnModel.batch_size=16 \\ + --PredictCTLearnModel.dl1dh_reader_type=DLImageReader \\ + --DLImageReader.channels=cleaned_image \\ + --DLImageReader.channels=cleaned_relative_peak_time \\ + --DLImageReader.image_mapper_type=BilinearMapper \\ + --DLImageReader.mode=stereo \\ + --DLImageReader.min_telescopes=2 \\ + --PredictCTLearnModel.stack_telescope_images=True \\ + --type_model="/path/to/your/stereo/type/ctlearn_model.cpk" \\ + --energy_model="/path/to/your/stereo/energy/ctlearn_model.cpk" \\ + --skydirection_model="/path/to/your/stereo/skydirection/ctlearn_model.cpk" \\ + --output output.dl2.h5 \\ + --PredictCTLearnModel.overwrite_tables=True \\ + """ + + def start(self): + self.log.info("Processing the telescope pointings...") + # Retrieve the IDs from the dl1dh for the prediction tables + example_identifiers = self.dl1dh_reader.unique_example_identifiers.copy() + example_identifiers.keep_columns(SUBARRAY_EVENT_KEYS) + all_identifiers = self.dl1dh_reader.subarray_trigger_table.copy() + all_identifiers.keep_columns(SUBARRAY_EVENT_KEYS + ["time"]) + nonexample_identifiers = setdiff( + all_identifiers, example_identifiers, keys=SUBARRAY_EVENT_KEYS + ) + nonexample_identifiers.remove_column("time") + # Construct the survival telescopes for each event of the example_identifiers + survival_telescopes = [] + for subarray_event in self.dl1dh_reader.example_identifiers_grouped.groups: + survival_mask = np.zeros(len(self.dl1dh_reader.tel_ids), dtype=bool) + survival_tels = [ + self.dl1dh_reader.subarray.tel_indices[tel_id] + for tel_id in subarray_event["tel_id"].data + ] + survival_mask[survival_tels] = True + survival_telescopes.append(survival_mask) + # Add the survival telescopes to the example_identifiers + example_identifiers.add_column( + survival_telescopes, name=f"{self.prefix}_telescopes" + ) + # Pointing table for the stereo mode for MC simulation + if self.dl1dh_reader.process_type == ProcessType.Simulation: + pointing_info = self._store_mc_subarray_pointing(all_identifiers) + + # Pointing table for the observation mode + if self.dl1dh_reader.process_type == ProcessType.Observation: + pointing_info = super()._store_pointing(all_identifiers) + + self.log.info("Starting the prediction...") + classification_feature_vectors = None + if self.load_type_model_from is not None: + # Predict the particle type of the primary particle + classification_table, classification_feature_vectors = ( + super()._predict_classification(example_identifiers) + ) + if self.dl2_subarray: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_prediction"], + shapes=[(len(nonexample_identifiers),)], + ) + classification_table = vstack([classification_table, nan_table]) + # Add is_valid column to the particle type table + classification_table.add_column( + ~np.isnan( + classification_table[f"{self.prefix}_tel_prediction"].data, + dtype=bool, + ), + name=f"{self.prefix}_tel_is_valid", + ) + # Rename the columns for the stereo mode + classification_table.rename_column( + f"{self.prefix}_tel_prediction", f"{self.prefix}_prediction" + ) + classification_table.rename_column( + f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" + ) + classification_table.sort(SUBARRAY_EVENT_KEYS) + # Add the default values and meta data to the table + add_defaults_and_meta( + classification_table, + ParticleClassificationContainer, + prefix=self.prefix, + ) + # Save the prediction to the output file + write_table( + classification_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/classification/{self.prefix}", + ) + energy_feature_vectors = None + if self.load_energy_model_from is not None: + # Predict the energy of the primary particle + energy_table, energy_feature_vectors = super()._predict_energy( + example_identifiers + ) + if self.dl2_subarray: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_energy"], + shapes=[(len(nonexample_identifiers),)], + ) + energy_table = vstack([energy_table, nan_table]) + # Add is_valid column to the energy table + energy_table.add_column( + ~np.isnan( + energy_table[f"{self.prefix}_tel_energy"].data, dtype=bool + ), + name=f"{self.prefix}_tel_is_valid", + ) + # Rename the columns for the stereo mode + energy_table.rename_column( + f"{self.prefix}_tel_energy", f"{self.prefix}_energy" + ) + energy_table.rename_column( + f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" + ) + energy_table.sort(SUBARRAY_EVENT_KEYS) + # Add the default values and meta data to the table + add_defaults_and_meta( + energy_table, + ReconstructedEnergyContainer, + prefix=self.prefix, + ) + # Save the prediction to the output file + write_table( + energy_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/energy/{self.prefix}", + ) + impact_feature_vectors = None + if self.load_impact_model_from is not None: + # Predict the impact of the primary particle + impact_table, impact_feature_vectors = super()._predict_impact( + example_identifiers + ) + if self.dl2_subarray: + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_tel_impact"], + shapes=[(len(nonexample_identifiers),)], + ) + impact_table = vstack([impact_table, nan_table]) + # Add is_valid column to the impact table + impact_table.add_column( + ~np.isnan( + impact_table[f"{self.prefix}_tel_impact"].data, dtype=bool + ), + name=f"{self.prefix}_tel_is_valid", + ) + # Rename the columns for the stereo mode + impact_table.rename_column( + f"{self.prefix}_tel_impact", f"{self.prefix}_impact" + ) + impact_table.rename_column( + f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" + ) + impact_table.sort(SUBARRAY_EVENT_KEYS) + # Save the prediction to the output file + write_table( + impact_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/impact/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/impact/{self.prefix}", + ) + direction_feature_vectors = None + if self.load_skydirection_model_from is not None: + # Join the prediction table with the telescope pointing table + example_identifiers = join( + left=example_identifiers, + right=pointing_info, + keys=SUBARRAY_EVENT_KEYS, + ) + # Predict the arrival direction of the primary particle + direction_table, direction_feature_vectors = super()._predict_skydirection( + example_identifiers + ) + if self.dl2_subarray: + # Transform the spherical coordinate offsets to sky coordinates + direction_table = super()._transform_spher_coord_offsets_to_sky( + direction_table + ) + # Produce output table with NaNs for missing predictions + if len(nonexample_identifiers) > 0: + nan_table = super()._create_nan_table( + nonexample_identifiers, + columns=[f"{self.prefix}_alt", f"{self.prefix}_az"], + shapes=[ + (len(nonexample_identifiers),), + (len(nonexample_identifiers),), + ], + ) + direction_table = vstack([direction_table, nan_table]) + # Add is_valid column to the direction table + direction_table.add_column( + ~np.isnan(direction_table[f"{self.prefix}_alt"].data, dtype=bool), + name=f"{self.prefix}_is_valid", + ) + direction_table.sort(SUBARRAY_EVENT_KEYS) + # Add the default values and meta data to the table + add_defaults_and_meta( + direction_table, + ReconstructedGeometryContainer, + prefix=self.prefix, + ) + # Save the prediction to the output file + write_table( + direction_table, + self.output_path, + f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL2 prediction data was stored in '%s' under '%s'", + self.output_path, + f"{DL2_SUBARRAY_GROUP}/geometry/{self.prefix}", + ) + + # Create the feature vector table if the DL1 features are enabled + if self.dl1_features: + self.log.info("Processing and storing dl1 feature vectors...") + feature_vector_table = super()._create_feature_vectors_table( + example_identifiers, + nonexample_identifiers, + classification_feature_vectors, + energy_feature_vectors, + direction_feature_vectors, + impact_feature_vectors, + ) + # Loop over the selected telescopes and store the feature vectors + # for each telescope in the output file. The feature vectors are stored + # in the DL1_TELESCOPE_GROUP/features/{prefix}/tel_{tel_id:03d} table. + # Rename the columns for the stereo mode + feature_vector_table.rename_column( + f"{self.prefix}_tel_classification_feature_vectors", + f"{self.prefix}_classification_feature_vectors", + ) + feature_vector_table.rename_column( + f"{self.prefix}_tel_energy_feature_vectors", + f"{self.prefix}_energy_feature_vectors", + ) + feature_vector_table.rename_column( + f"{self.prefix}_tel_impact_feature_vectors", + f"{self.prefix}_impact_feature_vectors", + ) + feature_vector_table.rename_column( + f"{self.prefix}_tel_geometry_feature_vectors", + f"{self.prefix}_geometry_feature_vectors", + ) + feature_vector_table.rename_column( + f"{self.prefix}_tel_is_valid", f"{self.prefix}_is_valid" + ) + feature_vector_table.sort(SUBARRAY_EVENT_KEYS) + # Save the prediction to the output file + write_table( + feature_vector_table, + self.output_path, + f"{DL1_SUBARRAY_GROUP}/features/{self.prefix}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL1 feature vectors was stored in '%s' under '%s'", + self.output_path, + f"{DL1_SUBARRAY_GROUP}/features/{self.prefix}", + ) + + def _store_mc_subarray_pointing(self, all_identifiers): + """ + Store the subarray pointing table from MC simulation to the output file. + + Parameters: + ----------- + all_identifiers : astropy.table.Table + Table containing the subarray pointing information. + """ + # Read the subarray pointing table + pointing_info = read_table( + self.input_url, + f"{SIMULATION_CONFIG_TABLE}", + ) + # Assuming min_az = max_az and min_alt = max_alt + pointing_info.keep_columns(["obs_id", "min_az", "min_alt"]) + pointing_info.rename_column("min_az", "pointing_azimuth") + pointing_info.rename_column("min_alt", "pointing_altitude") + # Join the prediction table with the telescope pointing table + pointing_info = join( + left=pointing_info, + right=all_identifiers, + keys=["obs_id"], + ) + # TODO: use keep_order for astropy v7.0.0 + pointing_info.sort(SUBARRAY_EVENT_KEYS) + # Create the pointing table + pointing_table = Table( + { + "time": pointing_info["time"], + "array_azimuth": pointing_info["pointing_azimuth"], + "array_altitude": pointing_info["pointing_altitude"], + "array_ra": np.nan * np.ones(len(pointing_info)), + "array_dec": np.nan * np.ones(len(pointing_info)), + } + ) + # Save the pointing table to the output file + write_table( + pointing_table, + self.output_path, + f"{SUBARRAY_POINTING_GROUP}", + overwrite=self.overwrite_tables, + ) + self.log.info( + "DL1 subarray pointing table was stored in '%s' under '%s'", + self.output_path, + f"{SUBARRAY_POINTING_GROUP}", + ) + return pointing_info + +def main(): + # Run the tool + tool = StereoPredictCTLearnModel() + tool.run() + + +if __name__ == "main": + main() diff --git a/notebooks/Muon_impact_reco_CTLearn.ipynb b/notebooks/Muon_impact_reco_CTLearn.ipynb new file mode 100644 index 00000000..666c9f9b --- /dev/null +++ b/notebooks/Muon_impact_reco_CTLearn.ipynb @@ -0,0 +1,379 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualization of the CTLearn impact\n", + "The output of CTLearn are stored in HDF5 format " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import libraries\n", + "First, we need to import some libraries. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# Data handling with numpy\n", + "import numpy as np\n", + "#np.set_printoptions(threshold=np.inf)\n", + "\n", + "import os\n", + "import astropy.units as u\n", + "\n", + "# Plotting libraries\n", + "import ctaplot\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib\n", + "%matplotlib inline\n", + "# (Default ctaplot) energy binning \n", + "E_bin = np.logspace(np.log10(2.51e-02), 2, 19)\n", + "E = ctaplot.ana.logbin_mean(E_bin)\n", + "from ctapipe.io import read_table\n", + "from astropy.table import Table, vstack, join\n", + "\n", + "run008 = \"/Users/tjarkmiener/muon/data/dl2/dl2_muon_ctapipe_run008.h5\"\n", + "run009 = \"/Users/tjarkmiener/muon/data/dl2/dl2_muon_ctapipe_run009.h5\"" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "energy_dl2_table = vstack([read_table(run008, \"/dl2/event/telescope/energy/CTLearn/tel_001\"), read_table(run009, \"/dl2/event/telescope/energy/CTLearn/tel_001\")])\n", + "energy_dl2_table = energy_dl2_table[energy_dl2_table[\"CTLearn_tel_is_valid\"]]\n", + "impact_dl2_table = vstack([read_table(run008, \"/dl2/event/telescope/impact/CTLearn/tel_001\"), read_table(run009, \"/dl2/event/telescope/impact/CTLearn/tel_001\")])\n", + "impact_dl2_table = impact_dl2_table[impact_dl2_table[\"CTLearn_tel_is_valid\"]]\n", + "simulation_table = vstack([read_table(run008, \"/simulation/event/subarray/shower\"), read_table(run009, \"/simulation/event/subarray/shower\")])\n", + "\n", + "joined_table = join(energy_dl2_table, impact_dl2_table, keys=[\"obs_id\", \"event_id\", \"tel_id\"])\n", + "joined_table = join(joined_table, simulation_table, keys=[\"obs_id\", \"event_id\"])\n", + "joined_table.keep_columns([\"obs_id\", \"event_id\", \"CTLearn_tel_energy\", \"CTLearn_tel_impact_x\", \"CTLearn_tel_impact_y\", \"true_energy\", \"true_alt\", \"true_az\", \"true_core_x\", \"true_core_y\", \"true_h_first_int\", \"true_x_max\", \"true_starting_grammage\", \"true_shower_primary_id\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Impact regression" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True impact map\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.close('all')\n", + "print(\"True impact map\")\n", + "ax1 = ctaplot.plots.plot_impact_point_heatmap(joined_table[\"true_core_x\"].data * u.m, joined_table[\"true_core_y\"].data * u.m)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CTLearn impact map\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"CTLearn impact map\")\n", + "ax2 = ctaplot.plots.plot_impact_point_heatmap(joined_table[\"CTLearn_tel_impact_x\"] * u.m, joined_table[\"CTLearn_tel_impact_y\"] * u.m)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Migration core_x\n" + ] + }, + { + "data": { + "image/png": "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X6y8vDzo5RS0RCJhw4cPD3oZA6qzs9O2b99u8+bN63H7vHnz7I033ghoVYUpkUiYmQ2650hflixZYjfccINdc801QS+lYDz//PM2ffp0mz9/vtXW1tq0adPs8ccfD3pZMoqagO3fv9/MzFatWmX33XefvfDCC1ZVVWVXX321nThxIuDVBcv3fbvlllts8eLFNn369KCXU9D27dtnDz/8sC1evDjopQyo48ePWyaTsZEjR/a4feTIkXbkyJGAVlV4fN+3FStW2OzZs23q1KlBL6cgPPPMM7Zjxw5rbGwMeikFZf/+/bZu3TqbPHmyvfTSS7Z48WK788477cknnwx6aRKKmn6yatUq8zyvz6+3337bstmsmZnde++99vWvf90aGhpsw4YN5nme/fjHPw74XvQP9dg8/PDDlkwmbeXKlUEvecCox+a/a25utuuuu87mz59vt99+e0ArD5bneT2+933/nNsGs6VLl9q7775rTz/9dNBLKQhNTU1211132Y9+9CMrKysLejkFJZvN2hVXXGGrV6+2adOm2V//9V/bokWLbN26dUEvTRIJegGuWrp0qd188819ZiZMmGBtbW1mZnbppZd23x6NRm3ixInOftBRPTYPPvigbdu27Zxrj0yfPt0WLFhgTzzxRH8uMxDqsflIc3OzzZ0716688kpbv359P6+u8NTU1Fg4HD7nrExLS8s5Z28Gq2XLltnzzz9vr732mo0dOzbo5RSE7du3W0tLizU0NHTflslk7LXXXrNHHnnEUqmUhcPhAFcYnNGjR/f4fWRmdskll9izzz4b0IrOD0VNP6mpqbGampqcuYaGBotGo7Znzx6bPXu2mZl1dXXZgQMHbPz48f29zECox+af/umf7MEHH+z+vrm52a699lrbuHGjzZw5sz+XGBj12Jj9vu1y7ty53Wf3QqHBd+K1tLTUGhoabMuWLfa1r32t+/YtW7bYV77ylQBXFjzf923ZsmW2adMm27p1q9XX1we9pILxhS98wXbu3NnjtltvvdWmTJlid99996AtaMzMZs2adU7r//vvv180v48oagJWUVFhixcvtvvvv9/q6ups/PjxtmbNGjMzmz9/fsCrC9a4ceN6fD906FAzM5s0adKg/xdnc3OzzZkzx8aNG2dr1661Y8eOdf+/UaNGBbiygbdixQpbuHChTZ8+vfuM1cGDBwfd54v+0JIlS+ypp56y5557zuLxePfZrMrKSovFYgGvLljxePyczxYNGTLEqqurB/1njr71rW/ZVVddZatXr7a/+Iu/sDfffNPWr19fNGeCKWoKwJo1aywSidjChQutvb3dZs6caa+88opVVVUFvTQUqJdfftn27t1re/fuPafA830/oFUF46abbrLW1lZ74IEH7PDhwzZ16lR78cUXi+Zflv3lo89AzJkzp8ftGzZssFtuuWXgF4SiMGPGDNu0aZOtXLnSHnjgAauvr7eHHnrIFixYEPTSJJ4/2N4BAQCAkwbfH+EBAICTKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAFKU5c+bYsmXLbPny5VZVVWUjR4609evX25kzZ+zWW2+1eDxukyZNss2bNwe9VAADhKIGQNF64oknrKamxt58801btmyZ/c3f/I3Nnz/frrrqKtuxY4dde+21tnDhQjt79mzQSwUwALhKN4CiNGfOHMtkMvb666+bmVkmk7HKykq78cYb7cknnzQzsyNHjtjo0aPt3//93+2zn/1skMsFMAA4UwOgaF122WXd/x0Oh626uto+/elPd982cuRIMzNraWkZ8LUBGHgUNQCKVklJSY/vPc/rcZvneWZmls1mB3RdAIJBUQMAAJxAUQMAAJxAUQMAAJxA9xMAAHACZ2oAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIATKGoAAIAT/h+vR40l7Zj1twAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"Migration core_x\")\n", + "ax2 = ctaplot.plots.plot_migration_matrix(joined_table[\"true_core_x\"].data * u.m, joined_table[\"CTLearn_tel_impact_x\"] * u.m)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Migration core_y\n" + ] + }, + { + "data": { + "image/png": "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e+yxoJclo6gJ2IEDB8zMbN26dXbPPffYT3/6U6uqqrKrr77aTp48GfDqguX7vt18883W3Nxsc+fODXo5OW3//v32yCOPWHNzc9BLGVPHjx+3VCpl9fX1Q75eX19vR44cCWhVucf3fVuzZo0tWLDAZs2aFfRycsIPf/hD27Vrl7W0tAS9lJxy4MAB27hxo11wwQX2wgsvWHNzs91+++32xBNPBL00CUXNKFm3bp15njfix44dOyydTpuZ2d13321f+tKXrKmpyTZv3mye59mPfvSjgG/F6FCPzSOPPGLxeNzWrl0b9JLHjHps/lRbW5tde+21tmTJErvtttsCWnmwPM8b8rnv+2d9bTxbuXKlvf322/aDH/wg6KXkhNbWVrvjjjvs3//9362oqCjo5eSUdDptH//4x+2BBx6wOXPm2N///d/b8uXLbePGjUEvTRIJegGuWrlypd14440jZqZNm2ZdXV1mZnbJJZcMfj0ajdr06dOdfaOjemzuv/9+e/3118+69sjcuXNt6dKl9vjjj4/mMgOhHps/amtrs0WLFtkVV1xhmzZtGuXV5Z7a2loLh8NnnZXp6Og46+zNeLVq1Sp75plnbPv27TZ58uSgl5MTdu7caR0dHdbU1DT4tVQqZdu3b7dHH33UEomEhcPhAFcYnIkTJw75eWRmdvHFF9tTTz0V0IrODUXNKKmtrbXa2tqMuaamJotGo7Z3715bsGCBmZkNDAzYwYMHberUqaO9zECox+bb3/623X///YOft7W12TXXXGNbtmyxefPmjeYSA6MeG7M/tF0uWrRo8OxeKDT+TrwWFhZaU1OTbd261f76r/968Otbt261L3zhCwGuLHi+79uqVavs6aeftm3btlljY2PQS8oZn/70p2337t1DvnbLLbfYzJkz7a677hq3BY2Z2ZVXXnlW6/9vfvObvPl5RFETsPLycmtubrZ7773XGhoabOrUqbZ+/XozM1uyZEnAqwvWlClThnxeWlpqZmYzZswY979xtrW12cKFC23KlCm2YcMGO3bs2OD/nXfeeQGubOytWbPGli1bZnPnzh08Y3Xo0KFx9/6iP7dixQp78skn7Sc/+YmVlZUNns2qqKiwWCwW8OqCVVZWdtZ7i0pKSqympmbcv+fozjvvtPnz59sDDzxgX/7yl+2NN96wTZs25c2ZYIqaHLB+/XqLRCK2bNky6+3ttXnz5tlLL71kVVVVQS8NOerFF1+0ffv22b59+84q8HzfD2hVwbjhhhvsxIkTdt9991l7e7vNmjXLnn322bz5zXK0/PE9EAsXLhzy9c2bN9vNN9889gtCXrj88svt6aeftrVr19p9991njY2N9vDDD9vSpUuDXprE88fbKyAAAHDS+PsjPAAAcBJFDQAAcAJFDQAAcAJFDQAAcAJFDQAAcAJFDQAAcAJFDQAAcAJFDQAAcAJFDQAAcAJFDQAAcAJFDQAAcAJFDYC8tHDhQlu1apWtXr3aqqqqrL6+3jZt2mQ9PT12yy23WFlZmc2YMcOee+65oJcKYIxQ1ADIW48//rjV1tbaG2+8YatWrbJ/+Id/sCVLltj8+fNt165dds0119iyZcvszJkzQS8VwBjgKt0A8tLChQstlUrZK6+8YmZmqVTKKioq7Prrr7cnnnjCzMyOHDliEydOtNdee80++clPBrlcAGOAMzUA8tbs2bMH/x0Oh62mpsYuvfTSwa/V19ebmVlHR8eYrw3A2KOoAZC3CgoKhnzued6Qr3meZ2Zm6XR6TNcFIBgUNQAAwAkUNQAAwAkUNQAAwAl0PwEAACdwpgYAADiBogYAADiBogYAADiBogYAADiBogYAADiBogYAADiBogYAADiBogYAADiBogYAADiBogYAADiBogYAADjh/wIX2Hp8p9PfygAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"Migration core_y\")\n", + "ax2 = ctaplot.plots.plot_migration_matrix(joined_table[\"true_core_y\"].data * u.m, joined_table[\"CTLearn_tel_impact_y\"] * u.m)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "impact radius\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1sAAAIhCAYAAAC48qAWAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAVj9JREFUeJzt3X18zfX/x/HnsevNLmzsimFlSUZkEslFmEi+UlHKRU1f5SqNlFRGNUUuiiSS9SVJ35D6Stu6UFoytOQiKnPRN2ultbmY7dg+vz/67vw6tjHss3Nmj/vtthvnc96fz+f1OS/bztP78/kci2EYhgAAAAAAlaqWowsAAAAAgEsRYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAcJCkpSRaLRVu3bnV0KRdt9+7dSkhI0IEDByo0vuTYS75cXV0VFhamO++8Uz/88EOl12exWJSQkFBq/xWttzIcOHDA7pjd3NwUFBSktm3b6uGHH9auXbtKrfPZZ5/JYrHos88+O699LViwQElJSee1Tln7GjZsmGrXrn1e2zmXtLQ0JSQk6M8//yz1XJcuXdSlS5dK3R8AOBJhCwBw0Xbv3q2pU6eed3hZunSpvvrqK6Wmpmr06NFat26dOnbsqJycHHMK/Z+bb75ZX331lcLCwkzdT1nGjBmjr776Shs3btSyZcvUr18/rVu3TldffbVmzpxpN/aaa67RV199pWuuuea89nEhYetC93W+0tLSNHXq1DLD1oIFC7RgwQJT9w8AVcnV0QUAAGqu6OhoxcTESPprVqOoqEhTpkzR2rVrde+995q233r16qlevXqmbf9sGjZsqOuuu872uHfv3oqPj1f//v01ceJERUdHq1evXpIkPz8/u7FmsFqtslgsVbKvc7nqqqscun8AqGzMbAGAEyk5bev7779Xz5495ePjo7CwMD333HOSpM2bN6tjx47y8fHRFVdcoTfeeMNu/ZLT41JSUnTvvfcqMDBQPj4+uuWWW7R//367sSkpKfrHP/6hBg0ayNPTU02aNNGIESP0+++/l6rr+++/11133aWQkBB5eHioYcOGGjJkiAoKCpSUlKQ77rhDktS1a1fbaXLnO7MiyRa8fv31V9uyU6dOafz48WrVqpX8/f0VGBio9u3b67333iu1fl5enu6//34FBQWpdu3auummm7Rv375S48o6jbBx48YaNmxYqbFnntpWXFysZ555Rk2bNpWXl5cCAgLUsmVLvfjii+d9vCW8vLy0ZMkSubm52c1ulXVq3/79+3XnnXcqPDxcHh4eCgkJUbdu3ZSRkWE7jl27dmnjxo22XjRu3Nhue8uWLdP48eNVv359eXh46McffzzrKYu7du1St27d5OPjo3r16mn06NE6efKk7fmSUyTL6vnfT+FMSEjQI488IkmKjIy01Veyz7JOI/zjjz80cuRI1a9fX+7u7rrssss0efJkFRQUlNrP6NGjtWzZMjVr1kze3t66+uqr9cEHH5y7AQBgEma2AMDJWK1W9e/fXw888IAeeeQRrVixQpMmTVJeXp7effddPfroo2rQoIHmzZunYcOGKTo6Wm3atLHbRlxcnHr06KEVK1bo8OHDeuKJJ9SlSxft2LFDAQEBkqSffvpJ7du31/Dhw+Xv768DBw5o9uzZ6tixo7777ju5ublJkr799lt17NhRdevW1bRp0xQVFaUjR45o3bp1Kiws1M0336zExEQ9/vjjevnll22noV1++eXnfeyZmZmSpCuuuMK2rKCgQH/88YcmTJig+vXrq7CwUKmpqerfv7+WLl2qIUOGSJIMw1C/fv2Ulpamp556Sm3bttWXX35pmyWqLDNmzFBCQoKeeOIJderUSVarVd9//32Zp8Wdj/DwcLVp00ZpaWk6ffq0XF3L/hXdu3dvFRUVacaMGWrYsKF+//13paWl2fa/Zs0a3X777fL397edkufh4WG3jUmTJql9+/ZauHChatWqpeDgYGVlZZW5P6vVqt69e2vEiBF67LHHlJaWpmeeeUYHDx7U+++/f17HOHz4cP3xxx+aN2+eVq9ebTuNs7wZrVOnTqlr16766aefNHXqVLVs2VJffPGFpk+froyMDP3nP/+xG/+f//xH6enpmjZtmmrXrq0ZM2bo1ltv1d69e3XZZZedV60AUCkMAIBDLF261JBkpKen25YNHTrUkGS8++67tmVWq9WoV6+eIcnYvn27bfnRo0cNFxcXIz4+vtQ2b731Vrt9ffnll4Yk45lnnimzluLiYsNqtRoHDx40JBnvvfee7bkbb7zRCAgIMLKzs8s9lnfeeceQZHz66afndeybN282rFarcezYMWPDhg1GaGio0alTJ8NqtZa77unTpw2r1WrExcUZrVu3ti3/8MMPDUnGiy++aDf+2WefNSQZU6ZMKbX/zMxM27JGjRoZQ4cOLbW/zp07G507d7Y97tOnj9GqVasKHeffZWZmGpKMmTNnljtm4MCBhiTj119/NQzDMD799FO71/X33383JBlz5849676aN29uV3OJku116tSp3Of+3sOSf4/lvaabNm2yO7alS5eW2u6Zr/3MmTNLvfYlznytFy5caEgyVq1aZTfu+eefNyQZycnJdvsJCQkx8vLybMuysrKMWrVqGdOnTy+1LwCoCpxGCABOxmKxqHfv3rbHrq6uatKkicLCwtS6dWvb8sDAQAUHB+vgwYOltnH33XfbPe7QoYMaNWqkTz/91LYsOztbDzzwgCIiIuTq6io3Nzc1atRIkrRnzx5J0smTJ7Vx40YNGDDAlGucrrvuOrm5ucnX11c33XST6tSpo/fee6/UrM4777yj66+/XrVr17bVumTJEludkmzHduaxDxo0qFJrvvbaa/Xtt99q5MiR+uijj5SXl1dp2zYM46zPBwYG6vLLL9fMmTM1e/ZsffPNNyouLj7v/dx2223nNb681/Tv/57M8Mknn8jHx0e333673fKS0z0//vhju+Vdu3aVr6+v7XFISEi53yMAUBUIWwDgZLy9veXp6Wm3zN3dXYGBgaXGuru769SpU6WWh4aGlrns6NGjkv667ig2NlarV6/WxIkT9fHHH2vLli3avHmzJCk/P1+SlJOTo6KiIjVo0OCij6ss//rXv5Senq5PPvlEI0aM0J49e3TXXXfZjVm9erUGDBig+vXra/ny5frqq6+Unp6u++67z+7Yjx49KldXVwUFBZU67so0adIkvfDCC9q8ebN69eqloKAgdevWrVJu4X/w4EF5eHiU2WvpryD+8ccfq2fPnpoxY4auueYa1atXT2PHjtWxY8cqvJ/zuQvj2V7Tkn9PZjl69KhCQ0NlsVjslgcHB8vV1bXU/s+sU/rrFMqSf88AUNW4ZgsALkFlXX+TlZWlJk2aSJJ27typb7/9VklJSRo6dKhtzI8//mi3TmBgoFxcXPTzzz+bUmezZs1sN8Xo2rWrioqK9Nprr+nf//63bTZj+fLlioyM1Ntvv233pvvMGyQEBQXp9OnTOnr0qN2b7vKuRTqTp6dnqW1K0u+//666deva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uxb27du3zM/2AgAAAIDK4tCw1aVLl7PeIr0it0/39PTUvHnzNG/evHLHBAYGavny5RdU48WIS0qv1O0ZMnTaelqubq6yqPSNGJYMa1up+4O5EhIStHbtWmVkZFT5vg8cOKDIyEh98803atWqlT777DN17dpVOTk5to9WAAAAwMXhQooabNiwYbJYLLJYLHJ1dVXDhg314IMPKicnx9GlVdiBAwdksViqLLAkJCSUmmk1S8mxlXz5+/vruuuu0/vvv1/p++rQoYOOHDkif3//St82AABATUXYquFuuukmHTlyRAcOHNBrr72m999/XyNHjnR0WZWusLDQ0SVcsNTUVB05ckRff/21rr32Wt12223auXNnpe7D3d1doaGh3LoeAACgEhG2ajgPDw+FhoaqQYMGio2N1cCBA5WcnGw3ZunSpWrWrJk8PT115ZVXlvqss59//ll33nmnAgMD5ePjo5iYGH399de251955RVdfvnlcnd3V9OmTbVs2TK79S0Wi1577TXdeuut8vb2VlRUlO16PUnKycnR3XffrXr16snLy0tRUVFaunSpJCkyMlKS1Lp1a1ksFtu1fMOGDVO/fv00ffp0hYeH64orrrDta+3atXb7DwgIUFJS0jmPJykpSVOnTtW3335rm20qWS83N1cjRoxQcHCw/Pz8dOONN+rbb7+1289zzz2nkJAQ+fr6Ki4uTqdOnapAh6SgoCCFhobqyiuv1LPPPiur1apPP/3U9vyGDRvUsWNHBQQEKCgoSH369NFPP/1kt40tW7aodevW8vT0VExMjL755hu75z/77DNZLBb9+eefksqewZs7d64aN25st861114rHx8fBQQE6Prrr9fBgwcrdEwAAAA1gdN/zhaqzv79+7Vhwwa7zw1YvHixpkyZovnz56t169b65ptvdP/998vHx0dDhw7V8ePH1blzZ9WvX1/r1q1TaGiotm/fruLiYknSmjVr9NBDD2nu3Lnq3r27PvjgA917771q0KCB3c1Rpk6dqhkzZmjmzJmaN2+e7r77bh08eFCBgYF68skntXv3bn344YeqW7eufvzxR+Xn50v6K0Rce+21Sk1NVfPmzeXu7m7b5scffyw/Pz+lpKRU6Po/SWc9noEDB2rnzp3asGGDUlNTJUn+/v4yDEMDBw5UvXr1tH79evn7++vVV19Vt27dtG/fPgUGBmrVqlWaMmWKXn75Zd1www1atmyZXnrpJV122WUV7o/VatXixYsl2X+2w4kTJxQfH68WLVroxIkTeuqpp3TrrbcqIyNDtWrV0okTJ9SnTx/deOONWr58uTIzM/XQQw9VeL9lOX36tPr166f7779fb731lgoLC7VlyxZmxgAAAP6GsFXDffDBB6pdu7aKiopsMy2zZ8+2Pf/0009r1qxZ6t+/v6S/ZpJ2796tV199VUOHDtWKFSv022+/KT09XYGBgZKkJk2a2NZ/4YUXNGzYMNupifHx8dq8ebNeeOEFu7A1bNgw3XXXXZKkxMREzZs3T1u2bNFNN92kQ4cOqXXr1oqJiZEku9mVevXqSfr/2Z+/8/Hx0WuvvWYXwM7lXMdTu3Ztubq62u0rNTVVu3fv1q+//iovLy/bca9du1b//ve/9c9//lNz587Vfffdp+HDh0uSnnnmGaWmplZodqtDhw6qVauW8vPzVVxcrMaNG2vAgAG252+77Ta78UuWLFFwcLB2796t6OhovfnmmyoqKtLrr78ub29vNW/eXD///LMefPDBCr8uZ8rLy1Nubq769Omjyy+/XNJfH7MAAACA/8dphDVc165dlZGRoa+//lpjxoxRz549NWbMGEnSb7/9psOHDysuLk61a9e2fT3zzDO209QyMjLUunVrWzA50549e3T99dfbLbv++uu1Z88eu2UtW7a0/d3Hx0e+vr7Kzs6WJD344INauXKlWrVqpYkTJyotLa1Cx9aiRYvzClrSuY+nLNu3b9eJEydUr149u9cpMzPT9jrt2bNH7du3t1vvzMflefvtt/XNN99o3bp1atKkiV577TW7+n766ScNGjRIl112mfz8/GynVh46dMi276uvvlre3t7nve/yBAYGatiwYerZs6duueUWvfjiizpy5MhFbRMAAOBSw8xWDefj42ObuXnppZfUtWtXTZ06VU8//bTtVMDFixerXbt2duuVfI5ZyUzO2Zx5aplhGKWW/f20uJJ1Svbfq1cvHTx4UP/5z3+Umpqqbt26adSoUXrhhRfOeWxl1XLmKYVWq9X294ocz5mKi4sVGhqqTz/9VLVq2f//RWXcRj0iIkJRUVGKiopS7dq1ddttt2n37t0KDg6WJN1yyy2KiIjQ4sWLFR4eruLiYkVHR9tuClLRUyj/rlatWmd9naS/ruUbO3asNmzYoLfffltPPPGEUlJSdN11113gkQIAAFxamNmCnSlTpuiFF17QL7/8opCQENWvX1/79+9XkyZN7L5KZk9atmypjIwM/fHHH2Vur1mzZtq0aZPdsrS0tPM+5axevXoaNmyYli9frrlz52rRokWSZJu5KioqqvB2/j4D88MPP+jkyZO2x+c6Hnd391L7at26tX799Ve5urqWep3q1q0r6a/XYfPmzXbrnfm4Ijp37qzo6Gg9++yzkqSjR49qz549euKJJ9StWzc1a9as1K37r7rqKn377be269wqsu969eopKyvLLnCVdXv91q1ba9KkSUpLS1N0dLRWrFhx3scEAABwqWJmC3a6dOmi5s2bKzExUfPnz1dCQoLGjh0rPz8/9erVSwUFBdq6datycnIUHx+vu+66S4mJibY7/4WFhembb75ReHi42rdvr0ceeUQDBgzQNddco27duun999/X6tWrbTeYqIinnnpKbdq0UfPmzVVQUKAPPvjAFtaCg4Pl5eWlDRs2qEGDBvL09DzrZ0XdeOONmj9/vq677joVFxfr0UcftZtVO9fxNG7cWJmZmcrIyFCDBg3k6+ur7t27q23bturfv7+ef/55NW3aVL/88ovWr1+vfv36KSYmRg899JCGDh2qmJgYdezYUW+++aZ27dp1XjfIKDF+/HjdcccdmjhxosLCwhQUFKRFixYpLCxMhw4d0mOPPWY3ftCgQZo8ebLi4uL0xBNP6MCBA+ecFezSpYt+++03zZgxQ7fffrs2bNigDz/8UH5+fpKkzMxMLVq0SH379lV4eLj27t2rffv2aciQIed9PABwqYtLSr+o9V1VrN51pNFvbtfpKv5/8iXD2lbp/oBLDWHLRJX9A6q4uFh5eXny8/MrdbpaZYqPj9e9996rRx99VMOHD5e3t7dmzpypiRMnysfHRy1atNC4ceMk/TXTk5ycrPHjx6t37946ffq0rrrqKr388suSpH79+unFF1/UzJkzNXbsWEVGRmrp0qW2W7RXhLu7uyZNmqQDBw7Iy8tLN9xwg1auXClJcnV11UsvvaRp06bpqaee0g033KDPPvus3G3NmjVL9957rzp16qTw8HC9+OKL2rZtm92+znY8t912m1avXq2uXbvqzz//1NKlSzVkyBCtWrVKM2bM0H333afffvtNoaGh6tSpk0JCQiRJAwcO1E8//aRH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148//mh7nJmZqYyMDAUGBqphw4YaN26cEhMTFRUVpaioKCUmJsrb21uDBg2SJPn7+ysuLk7jx49XUFCQAgMDNWHCBLVo0cJ2d8JmzZrppptu0v33369XX31VkvTPf/5Tffr04U6EAAAAAEzj0LC1detWde3a1fa45BqpoUOHKikpSRMnTlR+fr5Gjhxp+1Dj5ORk+fr62taZM2eOXF1dNWDAANuHGiclJcnFxcU25s0339TYsWNtdy3s27dvuZ/tBQAAAACVwaFhq0uXLjIMo9znLRaLEhISlJCQUO4YT09PzZs3T/PmzSt3TGBgoJYvX34xpQIAUCXiktIdXQIAoJI47TVbAAAAAFCdEbYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABO4OroAAACqk7ikdEeXAACoJpjZAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADCBq6MLAACgssUlpTu6BAAAmNkCAAAAADMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwgaujCwAAAAAqW1xSuqnbX3h3K1O3j0sDM1sAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACbhBBgDAIUa/uV2n+T8/AMAljN9yAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJjAqcPW6dOn9cQTTygyMlJeXl667LLLNG3aNBUXF9vGGIahhIQEhYeHy8vLS126dNGuXbvstlNQUKAxY8aobt268vHxUd++ffXzzz9X9eEAAAAAqEGcOmw9//zzWrhwoebPn689e/ZoxowZmjlzpubNm2cbM2PGDM2ePVvz589Xenq6QkND1aNHDx07dsw2Zty4cVqzZo1WrlypTZs26fjx4+rTp4+KiooccVgAAAAAagCn/lDjr776Sv/4xz908803S5IaN26st956S1u3bpX016zW3LlzNXnyZPXv31+S9MYbbygkJEQrVqzQiBEjlJubqyVLlmjZsmXq3r27JGn58uWKiIhQamqqevbs6ZiDAwAAAHBJc+qw1bFjRy1cuFD79u3TFVdcoW+//VabNm3S3LlzJUmZmZnKyspSbGysbR0PDw917txZaWlpGjFihLZt2yar1Wo3Jjw8XNHR0UpLSys3bBUUFKigoMD2OC8vT5JktVpltVpNONpzK9mvo/aPstEX50VvnFNJP1xVfI6RqEol/aAvzofeOCd+xzivquhNRbft1GHr0UcfVW5urq688kq5uLioqKhIzz77rO666y5JUlZWliQpJCTEbr2QkBAdPHjQNsbd3V116tQpNaZk/bJMnz5dU6dOLbU8OTlZ3t7eF3VcFyslJcWh+0fZ6IvzojfOKbZOtqNLQBnoi/OiN84lJSXrf3/yO8ZZmdmbkydPVmicU4ett99+W8uXL9eKFSvUvHlzZWRkaNy4cQoPD9fQoUNt4ywWi916hmGUWnamc42ZNGmS4uPjbY/z8vIUERGh2NhY+fn5XeARXRyr1aqUlBT16NFDbm5uDqkBpdEX50VvnFNJX5JzgnXauS8drlFcVazYOtn0xQnRG+c0Z0ALfsc4qar4/V9y1tu5OHXYeuSRR/TYY4/pzjvvlCS1aNFCBw8e1PTp0zV06FCFhoZK+mv2KiwszLZedna2bbYrNDRUhYWFysnJsZvdys7OVocOHcrdt4eHhzw8PEotd3Nzc/g3lDPUgNLoi/OiN87ptGrxxtEJ0RfnRW+cS8nvFX7HOC8ze1PR7Tr1d+zJkydVq5Z9iS4uLrZbv0dGRio0NNRuirCwsFAbN260Bak2bdrIzc3NbsyRI0e0c+fOs4YtAAAAALgYTj2zdcstt+jZZ59Vw4YN1bx5c33zzTeaPXu27rvvPkl/nT44btw4JSYmKioqSlFRUUpMTJS3t7cGDRokSfL391dcXJzGjx+voKAgBQYGasKECWrRooXt7oQAgNLiktJN2a6ritW7zrnHAQBQ3Tl12Jo3b56efPJJjRw5UtnZ2QoPD9eIESP01FNP2cZMnDhR+fn5GjlypHJyctSuXTslJyfL19fXNmbOnDlydXXVgAEDlJ+fr27duikpKUkuLi6OOCwAAAAANYBThy1fX1/NnTvXdqv3slgsFiUkJCghIaHcMZ6enpo3b57dhyEDAAAAgJmc+potAAAAAKiuCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAldHFwAAuDBxSemOLgEAAJwFM1sAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmMDV0QUAwKUsLind0SUAAAAHYWYLAAAAAExA2AIAAAAAE1xQ2Nq+fbu+++472+P33ntP/fr10+OPP67CwsJKKw4AAAAAqqsLClsjRozQvn37JEn79+/XnXfeKW9vb73zzjuaOHFipRYIAAAAANXRBYWtffv2qVWrVpKkd955R506ddKKFSuUlJSkd999tzLrAwAAAIBq6YLClmEYKi4uliSlpqaqd+/ekqSIiAj9/vvvlVcdAAAAAFRTFxS2YmJi9Mwzz2jZsmXauHGjbr75ZklSZmamQkJCKrVAAAAAAKiOLihszZkzR9u3b9fo0aM1efJkNWnSRJL073//Wx06dKjUAgEAAACgOrqgDzW++uqr7e5GWGLmzJlydeVzkgEAAADggma2LrvsMh09erTU8lOnTumKK6646KIAAAAAoLq7oLB14MABFRUVlVpeUFCgn3/++aKLAgAAAIDq7rzO+Vu3bp3t7x999JH8/f1tj4uKivTxxx8rMjKy8qoDAAAAgGrqvMJWv379JEkWi0VDhw61e87NzU2NGzfWrFmzKq04AAAAAKiuzitslXy2VmRkpNLT01W3bl1TigIAAACA6u6Cbh2YmZlZ2XUAAAAAwCXlgu/T/vHHH+vjjz9Wdna2bcarxOuvv37RhQEAAABAdXZBYWvq1KmaNm2aYmJiFBYWJovFUtl1AQAAAEC1dkFha+HChUpKStLgwYMrux4AAAAAuCRc0OdsFRYWqkOHDpVdCwAAAABcMi4obA0fPlwrVqyo7FoAAAAA4JJxQacRnjp1SosWLVJqaqpatmwpNzc3u+dnz55dKcUBAAAAQHV1QWFrx44datWqlSRp586dds9xswwAAAAAuMDTCD/99NNyvz755JNKLfC///2v7rnnHgUFBcnb21utWrXStm3bbM8bhqGEhASFh4fLy8tLXbp00a5du+y2UVBQoDFjxqhu3bry8fFR37599fPPP1dqnQAAAADwdxcUtqpKTk6Orr/+erm5uenDDz/U7t27NWvWLAUEBNjGzJgxQ7Nnz9b8+fOVnp6u0NBQ9ejRQ8eOHbONGTdunNasWaOVK1dq06ZNOn78uPr06aOioiIHHBUAAACAmuCCTiPs2rXrWU8XrKzZreeff14RERFaunSpbVnjxo1tfzcMQ3PnztXkyZPVv39/SdIbb7yhkJAQrVixQiNGjFBubq6WLFmiZcuWqXv37pKk5cuXKyIiQqmpqerZs2el1AoAAAAAf3dBYavkeq0SVqtVGRkZ2rlzp4YOHVoZdUmS1q1bp549e+qOO+7Qxo0bVb9+fY0cOVL333+/JCkzM1NZWVmKjY21rePh4aHOnTsrLS1NI0aM0LZt22S1Wu3GhIeHKzo6WmlpaeWGrYKCAhUUFNge5+Xl2Y7VarVW2jGej5L9Omr/KBt9cV7O0BtXFTts386q5DXhtXEu9MV50Rvn5Ay/Y1C2quhNRbd9QWFrzpw5ZS5PSEjQ8ePHL2STZdq/f79eeeUVxcfH6/HHH9eWLVs0duxYeXh4aMiQIcrKypIkhYSE2K0XEhKigwcPSpKysrLk7u6uOnXqlBpTsn5Zpk+frqlTp5ZanpycLG9v74s9tIuSkpLi0P2jbPTFeTmyN73rnHtMTRVbJ9vRJaAM9MV50RvnkpKS9b8/+f3vrMzszcmTJys07oLCVnnuueceXXvttXrhhRcqZXvFxcWKiYlRYmKiJKl169batWuXXnnlFQ0ZMsQ27sxTGg3DOOddEc81ZtKkSYqPj7c9zsvLU0REhGJjY+Xn53chh3PRrFarUlJS1KNHj1K324fj0Bfn5Qy9Gf3mdofs15m5qlixdbKVnBOs08596XCNQl+cF71xTnMGtHD47xiUrSp+/5ec9XYulRq2vvrqK3l6elba9sLCwnTVVVfZLWvWrJneffddSVJoaKikv2avwsLCbGOys7Nts12hoaEqLCxUTk6O3exWdna2OnToUO6+PTw85OHhUWq5m5ubw7+hnKEGlEZfnJcje8Mbo/KdVi1eHydEX5wXvXEuJb9X+P3vvMzsTUW3e0Fhq+RmFCUMw9CRI0e0detWPfnkkxeyyTJdf/312rt3r92yffv2qVGjRpKkyMhIhYaGKiUlRa1bt5YkFRYWauPGjXr++eclSW3atJGbm5tSUlI0YMAASdKRI0e0c+dOzZgxo9JqBQAAAIC/u6Cw5e/vb/e4Vq1aatq0qaZNm2Z3I4qL9fDDD6tDhw5KTEzUgAEDtGXLFi1atEiLFi2S9Nfpg+PGjVNiYqKioqIUFRWlxMREeXt7a9CgQbZa4+LiNH78eAUFBSkwMFATJkxQixYtbHcnBAAAAIDKdkFh6++3YjdT27ZttWbNGk2aNEnTpk1TZGSk5s6dq7vvvts2ZuLEicrPz9fIkSOVk5Ojdu3aKTk5Wb6+vrYxc+bMkaurqwYMGKD8/Hx169ZNSUlJcnFxqZLjAAAAwKVl9Jvb1bvOX39W9umdS4a1rdTtwXEu6pqtbdu2ac+ePbJYLLrqqqtsp/JVpj59+qhPnz7lPm+xWJSQkKCEhIRyx3h6emrevHmaN29epdcHAAAAAGW5oLCVnZ2tO++8U5999pkCAgJkGIZyc3PVtWtXrVy5UvXq1avsOgEAAACgWrmgOc8xY8YoLy9Pu3bt0h9//KGcnBzt3LlTeXl5Gjt2bGXXCAAAAADVzgXNbG3YsEGpqalq1qyZbdlVV12ll19+uVJvkAEAAAAA1dUFha3i4uIy7y3v5uam4uLiiy4KAP4uLin9gtZzVfE5L17mImQAAGCWCzqN8MYbb9RDDz2kX375xbbsv//9rx5++GF169at0ooDAAAAgOrqgsLW/PnzdezYMTVu3FiXX365mjRposjISB07dow7/gEAAACALvA0woiICG3fvl0pKSn6/vvvZRiGrrrqKj4kGAAAAAD+57zC1ieffKLRo0dr8+bN8vPzU48ePdSjRw9JUm5urpo3b66FCxfqhhtuMKVYAKhsF3o9GAAAwLmc12mEc+fO1f333y8/P79Sz/n7+2vEiBGaPXt2pRUHAAAAANXVeYWtb7/9VjfddFO5z8fGxmrbtm0XXRQAAAAAVHfnFbZ+/fXXMm/5XsLV1VW//fbbRRcFAAAAANXdeYWt+vXr67vvviv3+R07digsLOyiiwIAAACA6u68wlbv3r311FNP6dSpU6Wey8/P15QpU9SnT59KKw4AAAAAqqvzuhvhE088odWrV+uKK67Q6NGj1bRpU1ksFu3Zs0cvv/yyioqKNHnyZLNqBQAAAIBq47zCVkhIiNLS0vTggw9q0qRJMgxDkmSxWNSzZ08tWLBAISEhphQKAAAAANXJeX+ocaNGjbR+/Xrl5OToxx9/lGEYioqKUp06dcyoDwAAAACqpfMOWyXq1Kmjtm3bVmYtAAAAAHDJOK8bZAAAAAAAKoawBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmMDV0QUAqP7iktIdXQIAAIDTYWYLAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATODq6AIAVI24pHRHlwAAAFCjVKuZrenTp8tisWjcuHG2ZYZhKCEhQeHh4fLy8lKXLl20a9cuu/UKCgo0ZswY1a1bVz4+Purbt69+/vnnKq4eAAAAQE1SbcJWenq6Fi1apJYtW9otnzFjhmbPnq358+crPT1doaGh6tGjh44dO2YbM27cOK1Zs0YrV67Upk2bdPz4cfXp00dFRUVVfRgAAAAAaohqEbaOHz+uu+++W4sXL1adOnVsyw3D0Ny5czV58mT1799f0dHReuONN3Ty5EmtWLFCkpSbm6slS5Zo1qxZ6t69u1q3bq3ly5fru+++U2pqqqMOCQAAAMAlrlpcszVq1CjdfPPN6t69u5555hnb8szMTGVlZSk2Nta2zMPDQ507d1ZaWppGjBihbdu2yWq12o0JDw9XdHS00tLS1LNnzzL3WVBQoIKCAtvjvLw8SZLVapXVaq3sQ6yQkv06av8oW3Xpi6uKHV1ClSs55pp47M6Mvjgn+uK86I1zMrMvzv6ewtlVxXuzim7b6cPWypUrtX37dqWnl764PysrS5IUEhJitzwkJEQHDx60jXF3d7ebESsZU7J+WaZPn66pU6eWWp6cnCxvb+/zPo7KlJKS4tD9o2zO3pfedc495lIVWyfb0SWgDPTFOdEX50VvnJMZfVm/fn2lb7MmMvO92cmTJys0zqnD1uHDh/XQQw8pOTlZnp6e5Y6zWCx2jw3DKLXsTOcaM2nSJMXHx9se5+XlKSIiQrGxsfLz86vgEVQuq9WqlJQU9ejRQ25ubg6pAaVVl76MfnO7o0uocq4qVmydbCXnBOt09ThrukagL86JvjgveuOczOzL/LuvqdTt1TRV8d6s5Ky3c3HqsLVt2zZlZ2erTZs2tmVFRUX6/PPPNX/+fO3du1fSX7NXYWFhtjHZ2dm22a7Q0FAVFhYqJyfHbnYrOztbHTp0KHffHh4e8vDwKLXczc3N4W+onaEGlObsfanJv6BPq1aNPn5nRV+cE31xXvTGOZnRF2d+P1GdmPnerKLbderv2G7duum7775TRkaG7SsmJkZ33323MjIydNlllyk0NNRuirCwsFAbN260Bak2bdrIzc3NbsyRI0e0c+fOs4YtAAAAALgYTj2z5evrq+joaLtlPj4+CgoKsi0fN26cEhMTFRUVpaioKCUmJsrb21uDBg2SJPn7+ysuLk7jx49XUFCQAgMDNWHCBLVo0ULdu3ev8mMCAAAAUDM4ddiqiIkTJyo/P18jR45UTk6O2rVrp+TkZPn6+trGzJkzR66urhowYIDy8/PVrVs3JSUlycXFxYGVA/bikkrfBAYAAADVV7ULW5999pndY4vFooSEBCUkJJS7jqenp+bNm6d58+aZWxwAAAAA/I9TX7MFAAAAANUVYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAE7g6ugAAAAAA/y8uKd3U7S8Z1tbU7eP/MbMFAAAAACYgbAEAAACACQhbAAAAAGACrtkCzkNZ51C7qli960ij39yu0/z/BQAAAP6Hd4YAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJnB1dAFAZYpLSnd0CQAAAIAkZrYAAAAAwBSELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAETh22pk+frrZt28rX11fBwcHq16+f9u7dazfGMAwlJCQoPDxcXl5e6tKli3bt2mU3pqCgQGPGjFHdunXl4+Ojvn376ueff67KQwEAAABQwzh12Nq4caNGjRqlzZs3KyUlRadPn1ZsbKxOnDhhGzNjxgzNnj1b8+fPV3p6ukJDQ9WjRw8dO3bMNmbcuHFas2aNVq5cqU2bNun48ePq06ePioqKHHFYAAAAAGoAV0cXcDYbNmywe7x06VIFBwdr27Zt6tSpkwzD0Ny5czV58mT1799fkvTGG28oJCREK1as0IgRI5Sbm6slS5Zo2bJl6t69uyRp+fLlioiIUGpqqnr27FnlxwUAAADg0ufUYetMubm5kqTAwEBJUmZmprKyshQbG2sb4+Hhoc6dOystLU0jRozQtm3bZLVa7caEh4crOjpaaWlp5YatgoICFRQU2B7n5eVJkqxWq6xWa6UfW0WU7NdR+68OXFXssH06Yt84O3rjnOiLc6IvzoveOKfq3JdL/b1kVbxnrui2q03YMgxD8fHx6tixo6KjoyVJWVlZkqSQkBC7sSEhITp48KBtjLu7u+rUqVNqTMn6ZZk+fbqmTp1aanlycrK8vb0v6lguVkpKikP378x61zn3GLPE1sl23M5xVvTGOdEX50RfnBe9cU7VsS/r1693dAlVwsz3zCdPnqzQuGoTtkaPHq0dO3Zo06ZNpZ6zWCx2jw3DKLXsTOcaM2nSJMXHx9se5+XlKSIiQrGxsfLz8zvP6iuH1WpVSkqKevToITc3N4fU4OxGv7m9yvfpqmLF1slWck6wTjv3ZZA1Dr1xTvTFOdEX50VvnFN17sv8u69xdAmmqor3zCVnvZ1LtQhbY8aM0bp16/T555+rQYMGtuWhoaGS/pq9CgsLsy3Pzs62zXaFhoaqsLBQOTk5drNb2dnZ6tChQ7n79PDwkIeHR6nlbm5uDg86zlCDs3LkD7vTqlXtftjWFPTGOdEX50RfnBe9cU7VsS815X2kme+ZK7pdpw5bhmFozJgxWrNmjT777DNFRkbaPR8ZGanQ0FClpKSodevWkqTCwkJt3LhRzz//vCSpTZs2cnNzU0pKigYMGCBJOnLkiHbu3KkZM2ZU7QFBkhSXlO7oEgAAAADTOXXYGjVqlFasWKH33ntPvr6+tmus/P395eXlJYvFonHjxikxMVFRUVGKiopSYmKivL29NWjQINvYuLg4jR8/XkFBQQoMDNSECRPUokUL290JAQAAAKCyOXXYeuWVVyRJXbp0sVu+dOlSDRs2TJI0ceJE5efna+TIkcrJyVG7du2UnJwsX19f2/g5c+bI1dVVAwYMUH5+vrp166akpCS5uLhU1aEAAAAAqGGcOmwZhnHOMRaLRQkJCUpISCh3jKenp+bNm6d58+ZVYnUAAAAAUL7qdTUfAAAAAFQThC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASuji4AzicuKd3RJQAAAADVHjNbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAm4QQYAAABQg5h5M7Qlw9qatu3qiJktAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADCBq6MLwIWJS0p3dAkAAAAAzoKZLQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADCBq6MLAAAAAHBpiEtKN3X7S4a1NXX7lY2ZLQAAAAAwAWELAAAAAExQo8LWggULFBkZKU9PT7Vp00ZffPGFo0sCAAAAcImqMWHr7bff1rhx4zR58mR98803uuGGG9SrVy8dOnTI0aUBAAAAuATVmLA1e/ZsxcXFafjw4WrWrJnmzp2riIgIvfLKK44uDQAAAMAlqEbcjbCwsFDbtm3TY489Zrc8NjZWaWlpZa5TUFCggoIC2+Pc3FxJ0h9//CGr1WpesWdhtVp18uRJHT16VMX5xxxSA0orVrFOepxUcf4xFdec/7+oFuiNc6Ivzom+OC9645zoi2McPXr0nGP+/p7Zzc3NlDqOHfvrvbhhGGcdVyPC1u+//66ioiKFhITYLQ8JCVFWVlaZ60yfPl1Tp04ttTwyMtKUGlG9veboAlAueuOc6Itzoi/Oi944J/pS9ZJGOroCe8eOHZO/v3+5z9eIsFXCYrHYPTYMo9SyEpMmTVJ8fLztcXFxsf744w8FBQWVu47Z8vLyFBERocOHD8vPz88hNaA0+uK86I1zoi/Oib44L3rjnOiL86qK3hiGoWPHjik8PPys42pE2Kpbt65cXFxKzWJlZ2eXmu0q4eHhIQ8PD7tlAQEBZpV4Xvz8/PimdkL0xXnRG+dEX5wTfXFe9MY50RfnZXZvzjajVaJGnGDq7u6uNm3aKCUlxW55SkqKOnTo4KCqAAAAAFzKasTMliTFx8dr8ODBiomJUfv27bVo0SIdOnRIDzzwgKNLAwAAAHAJqjFha+DAgTp69KimTZumI0eOKDo6WuvXr1ejRo0cXVqFeXh4aMqUKaVOb4Rj0RfnRW+cE31xTvTFedEb50RfnJcz9cZinOt+hQAAAACA81YjrtkCAAAAgKpG2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhq5pYsGCBIiMj5enpqTZt2uiLL75wdEk13ueff65bbrlF4eHhslgsWrt2raNLgqTp06erbdu28vX1VXBwsPr166e9e/c6uixIeuWVV9SyZUvbh0y2b99eH374oaPLwhmmT58ui8WicePGObqUGi0hIUEWi8XuKzQ01NFl4X/++9//6p577lFQUJC8vb3VqlUrbdu2zdFl1WiNGzcu9T1jsVg0atQoh9ZF2KoG3n77bY0bN06TJ0/WN998oxtuuEG9evXSoUOHHF1ajXbixAldffXVmj9/vqNLwd9s3LhRo0aN0ubNm5WSkqLTp08rNjZWJ06ccHRpNV6DBg303HPPaevWrdq6datuvPFG/eMf/9CuXbscXRr+Jz09XYsWLVLLli0dXQokNW/eXEeOHLF9fffdd44uCZJycnJ0/fXXy83NTR9++KF2796tWbNmKSAgwNGl1Wjp6el23y8pKSmSpDvuuMOhdXHr92qgXbt2uuaaa/TKK6/YljVr1kz9+vXT9OnTHVgZSlgsFq1Zs0b9+vVzdCk4w2+//abg4GBt3LhRnTp1cnQ5OENgYKBmzpypuLg4R5dS4x0/flzXXHONFixYoGeeeUatWrXS3LlzHV1WjZWQkKC1a9cqIyPD0aXgDI899pi+/PJLzjJycuPGjdMHH3ygH374QRaLxWF1MLPl5AoLC7Vt2zbFxsbaLY+NjVVaWpqDqgKqj9zcXEl/vamH8ygqKtLKlSt14sQJtW/f3tHlQNKoUaN08803q3v37o4uBf/zww8/KDw8XJGRkbrzzju1f/9+R5cESevWrVNMTIzuuOMOBQcHq3Xr1lq8eLGjy8LfFBYWavny5brvvvscGrQkwpbT+/3331VUVKSQkBC75SEhIcrKynJQVUD1YBiG4uPj1bFjR0VHRzu6HEj67rvvVLt2bXl4eOiBBx7QmjVrdNVVVzm6rBpv5cqV2r59O2dLOJF27drpX//6lz766CMtXrxYWVlZ6tChg44ePero0mq8/fv365VXXlFUVJQ++ugjPfDAAxo7dqz+9a9/Obo0/M/atWv1559/atiwYY4uRa6OLgAVc2YqNwzD4UkdcHajR4/Wjh07tGnTJkeXgv9p2rSpMjIy9Oeff+rdd9/V0KFDtXHjRgKXAx0+fFgPPfSQkpOT5enp6ehy8D+9evWy/b1FixZq3769Lr/8cr3xxhuKj493YGUoLi5WTEyMEhMTJUmtW7fWrl279Morr2jIkCEOrg6StGTJEvXq1Uvh4eGOLoWZLWdXt25dubi4lJrFys7OLjXbBeD/jRkzRuvWrdOnn36qBg0aOLoc/I+7u7uaNGmimJgYTZ8+XVdffbVefPFFR5dVo23btk3Z2dlq06aNXF1d5erqqo0bN+qll16Sq6urioqKHF0iJPn4+KhFixb64YcfHF1KjRcWFlbqP4iaNWvGjcucxMGDB5Wamqrhw4c7uhRJhC2n5+7urjZt2tjuqFIiJSVFHTp0cFBVgPMyDEOjR4/W6tWr9cknnygyMtLRJeEsDMNQQUGBo8uo0bp166bvvvtOGRkZtq+YmBjdfffdysjIkIuLi6NLhKSCggLt2bNHYWFhji6lxrv++utLfaTIvn371KhRIwdVhL9bunSpgoODdfPNNzu6FEmcRlgtxMfHa/DgwYqJiVH79u21aNEiHTp0SA888ICjS6vRjh8/rh9//NH2ODMzUxkZGQoMDFTDhg0dWFnNNmrUKK1YsULvvfeefH19bbPC/v7+8vLycnB1Ndvjjz+uXr16KSIiQseOHdPKlSv12WefacOGDY4urUbz9fUtdU2jj4+PgoKCuNbRgSZMmKBbbrlFDRs2VHZ2tp555hnl5eVp6NChji6txnv44YfVoUMHJSYmasCAAdqyZYsWLVqkRYsWObq0Gq+4uFhLly7V0KFD5erqHDHHOarAWQ0cOFBHjx7VtGnTdOTIEUVHR2v9+vX8D4qDbd26VV27drU9LjmHfujQoUpKSnJQVSj5iIQuXbrYLV+6dKlTXChbk/36668aPHiwjhw5In9/f7Vs2VIbNmxQjx49HF0a4HR+/vln3XXXXfr9999Vr149XXfdddq8eTO/+51A27ZttWbNGk2aNEnTpk1TZGSk5s6dq7vvvtvRpdV4qampOnTokO677z5Hl2LD52wBAAAAgAm4ZgsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwBQYw0bNkz9+vWzPe7SpYvGjRtn6j4LCwvVpEkTffnllxe1nQkTJmjs2LGVVBUAwAyELQCAUxs2bJgsFossFotcXV3VsGFDPfjgg8rJyan0fa1evVpPP/10pW/37xYtWqRGjRrp+uuvv6jtTJw4UUuXLlVmZmYlVQYAqGyELQCA07vpppt05MgRHThwQK+99pref/99jRw5stL3ExgYKF9f30rf7t/NmzdPw4cPv+jtBAcHKzY2VgsXLqyEqgAAZiBsAQCcnoeHh0JDQ9WgQQPFxsZq4MCBSk5Otj1fVFSkuLg4RUZGysvLS02bNtWLL75ot42ioiLFx8crICBAQUFBmjhxogzDsBtz5mmEFotFa9eutRsTEBCgpKQkSX+dEjh69GiFhYXJ09NTjRs31vTp08s9ju3bt+vHH3/UzTffbFt24MABWSwWrVq1SjfccIO8vLzUtm1b7du3T+np6YqJiVHt2rV100036bfffrPbXt++ffXWW29V5CUEADgAYQsAUK3s379fGzZskJubm21ZcXGxGjRooFWrVmn37t166qmn9Pjjj2vVqlW2MbNmzdLrr7+uJUuWaNOmTfrjjz+0Zs2ai6rlpZde0rp167Rq1Srt3btXy5cvV+PGjcsd//nnn+uKK66Qn59fqeemTJmiJ554Qtu3b5erq6vuuusuTZw4US+++KK++OIL/fTTT3rqqafs1rn22mt1+PBhHTx48KKOAwBgDldHFwAAwLl88MEHql27toqKinTq1ClJ0uzZs23Pu7m5aerUqbbHkZGRSktL06pVqzRgwABJ0ty5czVp0iTddtttkqSFCxfqo48+uqi6Dh06pKioKHXs2FEWi0WNGjU66/gDBw4oPDy8zOcmTJignj17SpIeeugh3XXXXfr4449t13bFxcXZZtRK1K9f37bdc+0bAFD1mNkCADi9rl27KiMjQ19//bXGjBmjnj17asyYMXZjFi5cqJiYGNWrV0+1a9fW4sWLdejQIUlSbm6ujhw5ovbt29vGu7q6KiYm5qLqGjZsmDIyMtS0aVONHTvW7tTGsuTn58vT07PM51q2bGn7e0hIiCSpRYsWdsuys7Pt1vHy8pIknTx58oLqBwCYi7AFAHB6Pj4+atKkiVq2bKmXXnpJBQUFdjNZq1at0sMPP6z77rtPycnJysjI0L333qvCwsKL2q/FYil1XZfVarX9/ZprrlFmZqaefvpp5efna8CAAbr99tvL3V7dunXLvYvi30+LtFgsZS4rLi62W+ePP/6QJNWrV6+CRwQAqEqELQBAtTNlyhS98MIL+uWXXyRJX3zxhTp06KCRI0eqdevWatKkiX766SfbeH9/f4WFhWnz5s22ZadPn9a2bdvOup969erpyJEjtsc//PBDqVkkPz8/DRw4UIsXL9bbb7+td9991xaCztS6dWt9//33pQLchdq5c6fc3NzUvHnzStkeAKByEbYAANVOly5d1Lx5cyUmJkqSmjRpoq1bt+qjjz7Svn379OSTTyo9Pd1unYceekjPPfec1qxZo++//14jR47Un3/+edb93HjjjZo/f762b9+urVu36oEHHrCbbZozZ45Wrlyp77//Xvv27dM777yj0NBQBQQElLm9rl276sSJE9q1a9dFHX+JL774wnYHQwCA8yFsAQCqpfj4eC1evFiHDx/WAw88oP79+2vgwIFq166djh49WupzuMaPH68hQ4Zo2LBhat++vXx9fXXrrbeedR+zZs1SRESEOnXqpEGDBmnChAny9va2PV+7dm09//zziomJUdu2bXXgwAGtX79etWqV/es1KChI/fv315tvvnnxL4Ckt956S/fff3+lbAsAUPksRmWdywAAAM7pu+++U/fu3fXjjz9e1Aco/+c//9EjjzyiHTt2yNWVmwsDgDNiZgsAgCrUokULzZgxQwcOHLio7Zw4cUJLly4laAGAE2NmCwAAAABMwMwWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmOD/AJ2wrv//Yw/7AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"impact radius\")\n", + "reco_radius = np.sqrt(joined_table[\"CTLearn_tel_impact_x\"] **2 + joined_table[\"CTLearn_tel_impact_y\"] **2)\n", + "\n", + "plt.figure(figsize=(10,6))\n", + "plt.hist(reco_radius, bins=30, alpha=0.7, label='Reconstructed Radius')\n", + "plt.xlabel('Radius (m)')\n", + "plt.ylabel('Counts')\n", + "plt.title('Impact Radius Distribution')\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Migration impact radius\n" + ] + }, + { + "data": { + "image/png": "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wYIFMc3KPYODg3bPPffY5s2b7Stf+Urc03FKKpXiKcoFfP3rX7e2tjbbsmXL2X+76qqr4pvQFMATFVwx+vv/cxno+vr6mGfiFt/3bdu2bTY0NGTLli2LezpOWbt2rX34wx+2u+66K+6pOOfw4cPW2tpqc+bMsc985jN29OjRuKfkhOeee86WLl1qq1evtubmZluyZIlt3rw57mlNaiQquCKEYWjr16+3973vfbZw4cK4p+OEgwcPWnV1tWUyGXvggQds+/btNn/+/Lin5Yxt27bZyy+/bO3t7XFPxTnvec97bOvWrbZr1y7bvHmzdXV12fLly+306dNxTy12R48etY0bN9q1115ru3btsgceeMAeeugh27p1a9xTm7T40w+uCA8++KC9+uqr9pOf/CTuqThj3rx59sorr1hfX599//vftzVr1tiePXtIVsyso6PDHn74YfvhD39o5eXlcU/HOb/95+ZFixbZsmXLbO7cufbkk0/a+vXrY5xZ/IIgsKVLl9rjjz9uZmZLliyx1157zTZu3Gj33XdfzLObnHiigilv3bp19txzz9kLL7xgM2fOjHs6zigrK7NrrrnGli5dau3t7XbjjTfat7/97bin5YQDBw5Yd3e33XLLLZZKpSyVStmePXvsH//xHy2VSpnv+3FP0SlVVVW2aNEiO3z4cNxTiV1LS8t5yf4NN9xgb7/9dkwzmvx4ooIpKwxDW7dunW3fvt12795tc+bMiXtKTgvD0AqFQtzTcMKdd955XhXL/fffb9dff709+uijlkwmY5qZmwqFgr3xxhv2/ve/P+6pxO622247rw3Cm2++abNnz45pRpMficokNzg4aEeOHDn787Fjx+yVV16x+vp6mzVrVowzi9/atWvtqaeesmeffday2ax1dXWZmVkul7OKioqYZxevxx57zFauXGltbW02MDBg27Zts927d59XKXWlymaz532XqaqqyhoaGviOk5l98YtftFWrVtmsWbOsu7vbvvKVr1g+n7c1a9bEPbXYfeELX7Dly5fb448/bp/61KfsxRdftE2bNtmmTZvintrkFWJSe+GFF0IzO++1Zs2auKcWuwsdFzMLt2zZEvfUYvcXf/EX4ezZs8OysrKwqakpvPPOO8Mf/vCHcU/LaX/0R38UPvzww3FPwwmf/vSnw5aWljCdToetra3hJz7xifC1116Le1rO+Ld/+7dw4cKFYSaTCa+//vpw06ZNcU9pUvPCMAxjypEAAAAmxJdpAQCAs0hUAACAs0hUAACAs0hUAACAs0hUAACAs0hUAACAs0hUAACAs0hUAACAs0hUAACAs0hUAEwaHR0dtmLFCps/f74tXrzYvve978U9JQCXGC30AUwaJ06csJMnT9pNN91k3d3ddvPNN9uhQ4esqqoq7qkBuERYPRnApNHS0mItLS1mZtbc3Gz19fV25swZEhVgCuNPPwAmpZdeesmCILC2tra4pwLgEuKJCoBJ5/Tp03bffffZP/3TP8U9FQCXGE9UAMRmxYoVtm7dOnvkkUesrq7Opk2bZps2bbKhoSG7//77LZvN2ty5c23Hjh1n/59CoWAf//jHbcOGDbZ8+fIYZw/gciBRARCrJ5980hobG+3FF1+0devW2ec//3lbvXq1LV++3F5++WX70Ic+ZPfee68NDw9bGIb22c9+1j7wgQ/YvffeG/fUAVwGVP0AiM2KFSvM93378Y9/bGZmvu9bLpezT3ziE7Z161YzM+vq6rKWlhb76U9/asVi0W6//XZbvHjx2TH+5V/+xRYtWhTL/AFcenxHBUCsfjvpSCaT1tDQcE7iMW3aNDMz6+7uto9+9KMWBMFlnyOA+PCnHwCxSqfT5/zsed45/+Z5npkZCQpwhSJRAQAAziJRAQAAziJRAQAAzqLqBwAAOIsnKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFkkKgAAwFn/DxlfH0C5HH6eAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"Migration impact radius\")\n", + "reco_radius = np.sqrt(joined_table[\"CTLearn_tel_impact_x\"] **2 + joined_table[\"CTLearn_tel_impact_y\"] **2)\n", + "true_radius = np.sqrt(joined_table[\"true_core_x\"] **2 + joined_table[\"true_core_y\"] **2)\n", + "\n", + "ax2 = ctaplot.plots.plot_migration_matrix(true_radius * u.m, reco_radius * u.m)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Impact resolution per energy\n" + ] + }, + { + "data": { + "image/png": "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KkmKiorSjh079Ne//lVPPfWUfvnlF8XFxenRRx/V9OnTFRwcrHPnzql69eoOhZzFYrF7L/zp3LlzuuWWWxzaGzRoYOu/Vp06dexel5ziK1kfoKqjIAJQLjk5OaW2NW/eXJL09ddf69ChQ0pPT9eoUaNsMceOHbMbEx0draCgILsLlb3JYrHYva5bt64sFot27dpV6vU917a1bdtWa9eulWEY+vLLL5Wenq7Zs2crPDxc06ZNU506dVRYWKj//Oc/dkWRYRjKyclRly5dysyrpCDNz8+3ay/tgnN31KlTR9nZ2Q7tp0+flnR1/wH8H06ZASiX//mf/7F7/fHHH+vEiRO2hw+WFCLXFx2vvvqq3evw8HD17t1bb731ltNiwFtHLn73u9/JMAydOnVKnTt3dvhp27atwxiLxaL27dtr/vz5uummm7R//35J0h133CFJevPNN+3i161bp8uXL9v6S1NyFOfLL7+0a9+4caNDrDv7fscdd+jw4cO2HEusWrVKFotFffv2veEcgJlwhAhAuezbt0/jxo3TkCFDdPLkST399NNq2LChJkyYIElq1aqVmjVrpmnTpskwDEVHR+vdd99VZmamw1wld55169ZN06ZNU/PmzfXTTz9p48aNevXVV1WrVi21adNGkrRs2TLVqlVLYWFhio+PdzjlcyO33Xab/vCHP2jMmDHat2+fevXqpRo1aig7O1u7d+9W27Zt9dhjj+m9997T4sWLdd9996lp06YyDENvv/22zp8/r+TkZElScnKy+vfvryeffFK5ubm67bbbbHeZJSYmasSIEWXmERsbqzvvvFNz585V7dq11aRJE3344Yd6++23HWJLirQXXnhBAwYMUFBQkNq1a6eQkBCH2MmTJ2vVqlW6++67NXv2bDVp0kTvv/++Fi9erMcee0y/+c1v3Hq/gCovgBd0A/CTsu4yq1GjhkNs7969jdatWzu0N2nSxLj77rsd5ty6dasxYsQI46abbjLCw8ONgQMHGt99953d2MOHDxvJyclGrVq1jNq1axtDhgwxsrKyDEnGs88+6xA7ZMgQo06dOkZISIjRuHFjY/To0UZeXp4tJi0tzYiPjzeCgoIc7sS6XsldZv/5z39K7V+xYoXRrVs3o0aNGkZ4eLjRrFkzY+TIkca+ffsMwzCMb7/91nj44YeNZs2aGeHh4UZUVJTRtWtXIz093W6eX3/91XjyySeNJk2aGMHBwUZcXJzx2GOPGb/88ovD+3vtXWaGYRjZ2dnG4MGDjejoaCMqKsoYPny47e62a/ctPz/fGDdunFGvXj3DYrEYkozjx48bhuF4l5lhGMaJEyeMYcOGGXXq1DGCg4ONli1bGn/729+MoqIiW0zJXWZ/+9vfHN6b0tYHqKoshmEYAavGAFRa6enpGjNmjD7//HN17tw50OkAQLlwDREAADA9CiIAAGB6nDIDAACmxxEiAABgehREAADA9CiIAACA6fFgRhcUFxfr9OnTqlWrlsPj/wEAQMVkGIYuXryoBg0aqFo158eAKIhccPr0aTVq1CjQaQAAAA+cPHnyhl8cTUHkglq1akm6+oZGRkaWGWe1WrV161b169dPwcHBXs2hPHO7O9bVeFfinMWU1edue6D5Ki9/rrmrY3y15mX1sea+He+tzzprHrh5K+KaO+v399/33NxcNWrUyPbvuDMURC4oOU0WGRl5w4IoIiJCkZGRPimIPJ3b3bGuxrsS5yymrD532wPNV3n5c81dHeOrNS+rjzX37XhvfdZZ88DNWxHX3Fl/oP6+u3K5CxdVAwAA06MgAgAApkdBBAAATI+CCAAAmB4FEQAAMD0KIgAAYHoURAAAwPQoiAAAgOlREAEAANOjIAIAAKZHQQQAAEyPgggAAJgeX+5aCRUVG/rs+M86czFP9WuFqWt8tIKq3fiL6wAAQOkoiCqZLd/8pDmbvtVPufm2trioMD07KEF3tYkLYGYAAFRenDKrRA6ds+jPaw/ZFUOSlHMhT4+9uV+bv84OUGYAAFRuHCGqAK4UFN4wJi/fqnU/VpNRSp8hySJp5sbDuq15XYfTZ1brjecHAMDMKIgqgIRntrgYWfZ1QoaknNw8tZ25tdT+BUnu5wUAgFlwygwAAJgeR4gqgMOz+98w5uPvzmjcGwduGJc+pou6xkfbtVmtVm3/oPQjRwAAgIKoQogIufEy3N68rm4KMXShwFLqdUQWSbFRYerZop7jNUSW0kYAAIASnDKrJIKqWfTALcWSHK8kKnn97KAEnkcEAIAHKIgqkfZ1DP399+0VGxVm1x4bFaYlwzvyHCIAADzEKbNKpn/rGA1o15AnVQMA4EUURJVQUDWLkprVCXQaAABUGZwyAwAApkdBBAAATI+CCAAAmB4FEQAAMD0KIgAAYHoURAAAwPQoiAAAgOlREAEAANOjIAIAAKZHQQQAAEyPgggAAJgeBREAADA9CiIAAGB6FEQAAMD0KIgAAIDpURABAADToyACAACmV6EKop07d2rQoEFq0KCBLBaL3nnnHafx27dvl8Vicfj59ttv7eLWrVunhIQEhYaGKiEhQevXr/fhXgAAgMqmQhVEly9fVvv27fXKK6+4Ne7o0aPKzs62/bRo0cLWt3fvXg0dOlQjRozQoUOHNGLECD300EP69NNPvZ0+AACopKoHOoFrDRgwQAMGDHB7XP369XXTTTeV2peWlqbk5GSlpqZKklJTU7Vjxw6lpaVpzZo15UkXAABUERWqIPJUYmKi8vLylJCQoOnTp6tv3762vr1792ry5Ml28f3791daWlqZ8+Xn5ys/P9/2Ojc3V5JktVpltVrLHFfS5yzGU+WZ292xrsa7Eucspqw+d9sDzVd5+XPNXR3jqzUvq4819+14b33WWfPAzVsR19xZv7//vrszn8UwDMOrW/cSi8Wi9evX67777isz5ujRo9q5c6c6deqk/Px8vfHGG1q6dKm2b9+uXr16SZJCQkKUnp6uYcOG2catXr1aY8aMsSt6rjVz5kzNmjXLoX316tWKiIgo344BAAC/uHLlioYNG6YLFy4oMjLSaWylPkLUsmVLtWzZ0vY6KSlJJ0+e1EsvvWQriKSrxdW1DMNwaLtWamqqUlJSbK9zc3PVqFEj9evXz+kbarValZmZqeTkZAUHB3uySz6Z292xrsa7Eucspqw+d9sDzVd5+XPNXR3jqzUvq4819+14b33WWfPAzVsR19xZv7//vpec4XFFpS6IStO9e3e9+eabttexsbHKycmxizlz5oxiYmLKnCM0NFShoaEO7cHBwS4tlKtxnijP3O6O9eb+Oospq8/d9kDzVV7+XHNXx/hqzcvqY819O95bn3XWPHDzVsQ1d9bvr7/v7sxVoe4y84YDBw4oLi7O9jopKUmZmZl2MVu3blWPHj38nRoAAKigKtQRokuXLunYsWO218ePH9fBgwcVHR2txo0bKzU1VadOndKqVaskXb2D7JZbblHr1q1VUFCgN998U+vWrdO6detsc0ycOFG9evXSCy+8oHvvvVcbNmzQBx98oN27d/t9/wAAQMVUoQqiffv22d0hVnIdz6hRo5Senq7s7GxlZWXZ+gsKCjRl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ffakamfvV8mpsYqoQhVEQ4cO1blz5zR79mxlZ2erTZs22rRpk5o0aSJJys7OVlZWli0+Pj5emzZt0uTJk7Vo0SI1aNBACxcutD2DSJJ69OihtWvXavr06ZoxY4aaNWumjIwMnkFkEkHVLEpqVsfn22gRZWhguzifXTtWlfaD98r1bVSV/eC9cm87vt6XahapW3y0z/fDH++XN1WogkiSJkyYoAkTJpTal56e7tDWu3dv7d+/3+mcgwcP1uDBg72RHgAAqIIqzDVEAAAAgUJBBAAATI+CCAAAmB4FEQAAMD0KIgAAYHoURAAAwPQoiAAAgOlREAEAANOrcA9mrIgM4+oX4eXm5jqNs1qtunLlinJzc73+ZM7yzO3uWFfjXYlzFlNWn7vtgearvPy55q6O8dWal9XHmvt2vLc+66x54OatiGvurN/ff99L/t0u+XfcGQoiF1y8eFGS1KhRowBnAgAA3HXx4kVFRUU5jbEYrpRNJldcXKzTp0+rVq1aslicfwFely5d9Pnnn/skj/LM7e5YV+NdiXMWU1Zfae25ublq1KiRTp48qcjIyBvm5k++Wnd/rrmrY3y15qX1sea+H++tzzprHrh5K+KaO+v35993wzB08eJFNWjQQNWqOb9KiCNELqhWrZpuvvlml2KDgoJ89iEuz9zujnU13pU4ZzFl9TkbExkZWeH+UPpq3f255q6O8dWaO+tjzX033lufddY8cPNWxDV31u/vv+83OjJUgouqvezxxx+vkHO7O9bVeFfinMWU1efL99EXfJWvP9fc1TG+WnNX564oKuKaezLeW5911jxw81bENXfWX1HXnFNmqDRyc3MVFRWlCxcuVLj/5wjfYM3NhzU3p4qw7hwhQqURGhqqZ599VqGhoYFOBX7CmpsPa25OFWHdOUIEAABMjyNEAADA9CiIAACA6VEQAQAA06MgAgAApkdBBAAATI+CCFXS/fffr9q1a2vw4MGBTgU+9N5776lly5Zq0aKF/vGPfwQ6HfgBn21zOXnypPr06aOEhAS1a9dOb731ls+2xW33qJK2bdumS5cu6fXXX9c///nPQKcDHygsLFRCQoK2bdumyMhIdezYUZ9++qmio6MDnRp8iM+2uWRnZ+unn35Shw4ddObMGXXs2FFHjx5VjRo1vL4tjhChSurbt69q1aoV6DTgQ5999plat26thg0b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V6pJkya64447vJ4PgNJREAGokBISEhQaGqqsrCz17t3b5XHNmjVTcHCwPvvsMzVq1EiSlJubq++++85hnnHjxmn+/Pk6deqU7rzzTlu8N7m6Hw899JAmTpyo1atX6/XXX9ejjz7q9aNVAMpGQQTAZ/Lz85WTk2PXVr16ddWtW/eGY2vVqqUpU6Zo8uTJKi4u1u23367c3Fx9/PHHqlmzpkaNGlXmuFGjRum///u/FR0drfr16+vZZ59VtWrVHAqMRx55RFOmTNFrr72mVatWeb6jXtiPmjVraujQoXrqqad04cIFl55hBMB7KIgA+MzmzZsVFxdn19ayZUt9++23Lo2fM2eO6tevr7lz5+qHH37QTTfdpI4dO+qpp55yOm7evHkaP368fve73ykyMlJTp07VyZMnFRYWZhcXGRmpBx98UO+//77uu+8+t/bNHa7ux9ixY7V8+XL169dPjRs39lk+ABxZjOtPrANAFXP58mU1bNhQL7/8ssNzfZKTk3Xrrbdq4cKFN5ynT58+6tChg9LS0nyUqWssFovWr1/v0yIOMBueQwSgyjlw4IDWrFmj77//Xvv377c9y+fee++1xfz8889au3atPvroIz3++OMuz7148WLVrFlTX331ldfzvpHx48erZs2aft8uYAYcIQJQ5Rw4cEDjxo3T0aNHFRISok6dOmnevHlq27atLeaWW27RL7/8ohkzZmjKlCkuzXvq1Cn9+uuvkqTGjRv79CtCSnPmzBnl5uZKuvqIgmvvrgNQPhREAADA9DhlBgAATI+CCAAAmB4FEQAAMD0KIgAAYHoURAAAwPQoiAAAgOlREAEAANOjIAIAAKZHQQQAAEyPgggAAJje/wdYfGDnC9TqsgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"Impact resolution per energy\")\n", + "ax2 = ctaplot.plots.plot_impact_resolution_per_energy(\n", + " true_x = joined_table[\"true_core_x\"].data * u.m, \n", + " reco_x = joined_table[\"CTLearn_tel_impact_x\"] * u.m, \n", + " true_y = joined_table[\"true_core_y\"].data * u.m, \n", + " reco_y = joined_table[\"CTLearn_tel_impact_y\"] * u.m, \n", + " true_energy = joined_table[\"true_energy\"].data * u.TeV,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Impact parameter error \n" + ] + }, + { + "data": { + "image/png": "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AAC4hqPO45IuViAgy+UXWYy0jnEFs3rw+I9m0kirPEVsumZQRRtnnu3Y7zvam4r8nISuxRM849TI9wfPSuw6PwHP0XFf9MpQMOqs517Z2t6L/ASOXQPt84uMgib536tWHb9OV0m26dP881rbvFGv9HlHFQzerrAnbENV9dcm80CjPVZG1Cf9o7Ouu/gtRTyhtM79UKvNaZ2vsZUfjCjRSws7610JAAAgDoILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDYILAABwDUcFl7Vr12ro0KFq27atLMvSCy+8YHdJAADAQRwVXA4fPqzevXvr8ccft7sUAADgQF67CzjRkCFDNGTIELvLAAAADuWo4FJfwWBQwWCw+ufy8nJJkjczQz5Phl1lpYXHn9pimO/Y/X0pzpMKv89RC3rV/F7rhO8nr9EcG+92AU9iz+P4uETHNyZj2fuaCljWCd+Tr8Vv3P3+JEneaO0/H8e3xbrNqTKivkZ7LM+xvngaoD+hcCDtczamUDiS8FjLGGMasJakWZalpUuX6tprr61zzPTp0zVjxoxa20tLS5Wdnd2A1QEAgHSpqKjQiBEjdODAAeXl5cUd6+rgEmvFJT8/Xz9qd4d8Hn8jVNlwIh3apHR/n9+jUfd006LH31OoKpqmqurnyJlZtjzuyfi9lu76aScV/89Hqgqf/OUfbOq8lYdkHGqX+IrLL3t20INbPlYw6qy3h8pW9ryWjwtYlmad2UnTPvtIwRTeOlu2/yaNVdnj3Gb7am3zRr36ly+u1EstVyrsCdtQVf2dmVneaI/liXpVsPt6bcz/o6Jp7s+vvrM1rfM1tvKDEbXqtj2h4OKe9bwYAoGAAoHay2PhyojkSXzZyYkiaQoboaqobcGlKmTvH5m6HV3irwqbhGqsCjvzI6/6CtbznyMYNY4LLkFj92vKc6wOk1ItVZa7358kxQ0mYU/YNcEl4gk1+mNGPeG0P67PGzz5IAfzeRP/nTg13pEBAMBpwVErLocOHdKHH35Y/fOuXbv07rvvqnnz5jrrrLNsrAwAADiBo4LLxo0bdemll1b/PGnSJElSYWGhnn76aZuqAgAATuGo4DJw4EClY1/h6OHDilqN/7llOmV8eTC1+weOHm6Z8dUhRYP2fJ7eJOTMz/GPHyKevfuQfAns/+OJNGnokhqFJ5TYIbh+r6TeUt4uk9DOy43Jd8jew4gDGZbURsrd5ZE/kvxO2wf3tkxjVfb4W5PazyHgsTTse9L617o6bv+oujTmLi4Bj6UfdJdefOnCtPfnlV390jpfY4tUVUr6ZUJj2ccFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4BsEFAAC4htfuAtLJGCNJCpuQzZWkzhMNpjZBJEMVFRUKRYIKRyPpKaqeopEMWx73pMLW0d6EKxWOmJMPDzn0edRTpCqx5xGOHu1PuKpSkfDJ+9OYIkHL3sfPONqbSLBSkQReO3XPk8aibBKN8RwinmP9qaxUNOqs105dGvPPxYn9iaS5P5Eqd/S7LpGqSkn//Dsej2USGeUSn3zyifLz8+0uAwAAJGH37t1q165d3DGnVHCJRqPas2ePcnNzZVn2/p+Z3crLy5Wfn6/du3crLy/P7nIchd7ER3/qRm/ioz/x0Z+6GWN08OBBtW3bVh5P/L1YTqmPijwez0mT2ukmLy+PX5A60Jv46E/d6E189Cc++hNb06ZNExrHzrkAAMA1CC4AAMA1CC6nqEAgoF//+tcKBAJ2l+I49CY++lM3ehMf/YmP/qTHKbVzLgAAOLWx4gIAAFyD4AIAAFyD4AIAAFyD4AIAAFyD4HKKWbt2rYYOHaq2bdvKsiy98MILdpfkGEVFRbrggguUm5urVq1a6dprr9X7779vd1mOUFxcrF69elWfGKtv375atmyZ3WU5VlFRkSzL0oQJE+wuxRGmT58uy7JqfJ155pl2l+UYn376qW6++Wa1aNFC2dnZ6tOnj95++227y3Itgssp5vDhw+rdu7cef/xxu0txnDVr1mjMmDFav369Xn75ZYXDYV155ZU6fPiw3aXZrl27dpozZ442btyojRs36rLLLtM111yjbdu22V2a47z11lsqKSlRr1697C7FUbp37669e/dWf23ZssXukhzhm2++Uf/+/eXz+bRs2TK99957+u1vf6szzjjD7tJc65Q65T+kIUOGaMiQIXaX4UjLly+v8fOiRYvUqlUrvf3227rkkktsqsoZhg4dWuPnBx98UMXFxVq/fr26d+9uU1XOc+jQId10001asGCBZs+ebXc5juL1elllieHhhx9Wfn6+Fi1aVL2tQ4cO9hV0CmDFBaetAwcOSJKaN29ucyXOEolEtHjxYh0+fFh9+/a1uxxHGTNmjK666ipdfvnldpfiOB988IHatm2rjh076mc/+5k++ugju0tyhBdffFEFBQUaPny4WrVqpfPOO08LFiywuyxXI7jgtGSM0aRJk3TxxRerR48edpfjCFu2bFFOTo4CgYDuvPNOLV26VN26dbO7LMdYvHix3nnnHRUVFdldiuNceOGFevbZZ7VixQotWLBAn332mfr166evvvrK7tJs99FHH6m4uFjnnHOOVqxYoTvvvFPjxo3Ts88+a3dprsVHRTgt3XPPPdq8ebPWrVtndymOce655+rdd9/V/v37tWTJEhUWFmrNmjWEF0m7d+/W+PHjtXLlSmVmZtpdjuOc+PF0z5491bdvX3Xu3FnPPPOMJk2aZGNl9otGoyooKNBDDz0kSTrvvPO0bds2FRcXa+TIkTZX506suOC0M3bsWL344otatWqV2rVrZ3c5juH3+3X22WeroKBARUVF6t27tx599FG7y3KEt99+W/v27dP3v/99eb1eeb1erVmzRo899pi8Xq8ikYjdJTpKkyZN1LNnT33wwQd2l2K7Nm3a1Ar/Xbt2VVlZmU0VuR8rLjhtGGM0duxYLV26VKtXr1bHjh3tLsnRjDEKBoN2l+EIgwYNqnWUzKhRo9SlSxfde++9ysjIsKkyZwoGg9q+fbt++MMf2l2K7fr371/rtAs7duxQ+/btbarI/Qgup5hDhw7pww8/rP55165devfdd9W8eXOdddZZNlZmvzFjxqi0tFR//vOflZubq88++0yS1LRpU2VlZdlcnb3uv/9+DRkyRPn5+Tp48KAWL16s1atX1zoS63SVm5tba1+oJk2aqEWLFuwj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rbRhwwZ98cUX1X/UO3TooA0bNujjjz9WTk6OmjdvrmbNmqlFixYqKSlRmzZtVFZWpvvuu69edWZmZuree+/V1KlT5ff71b9/f33xxRfatm2bRo8erdzcXE2ePFkTJ05UNBrVxRdfrPLycr3++uvKyclRYWFhzHlj1XvXXXdpypQpat68uc466yw98sgjqqio0OjRo2POcbKeJPKYydR/sp4k04+GqhXAUQQXIEXLly9XmzZt5PV61axZM/Xu3VuPPfaYCgsL5fHUXtTMy8vT2rVrNX/+fJWXl6t9+/b67W9/qyFDhkiSJk+erMLCQnXr1k1HjhzRrl271KFDBy1evFjjxo1Tjx49dO655+qxxx7TwIED61XrtGnT5PV69atf/Up79uxRmzZtdOedd1bfPmvWLLVq1UpFRUX66KOPdMYZZ+j888/X/fffX+ecseqdM2eOotGobrnlFh08eFAFBQVasWJFnfusnKwniTxmhw4dkqo/Xk+Sma8hawUgWeb4B9IAAFcaOHCg+vTpo/nz56dtTsuytHTpUl177bVpmxNIB/ZxAYBTwH/8x38oJydHW7ZsSWmeO++8Uzk5OWmqCkg/VlwAwOU+/fRTHTlyRJJ01llnye/3Jz3Xvn37VF5eLunoYd2pHtkEpBvBBQAAuAYfFQEAANcguAAAANcguAAAANcguAAAANcguAAAANcguAAAANcguAAAANcguAAAANcguAAAANcguAAAANf4/wFvTAI1nJnKXwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"Impact parameter error \")\n", + "ax2 = ctaplot.plots.plot_impact_parameter_error_site_center(\n", + " true_x = joined_table[\"true_core_x\"].data * u.m, \n", + " reco_x = joined_table[\"CTLearn_tel_impact_x\"] * u.m, \n", + " true_y = joined_table[\"true_core_y\"].data * u.m, \n", + " reco_y = joined_table[\"CTLearn_tel_impact_y\"] * u.m, \n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Energy regression" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Energy resolution per energy\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAj4AAAHMCAYAAADVgKIjAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAARkVJREFUeJzt3Xl0FGX+/v2rydIhkIQdAoSwBUhE1rBqWCKERUHEhTPIJkEHARHj8hMchKCCX0SFmTHgBrjhYXDU0RGVOCBicGQNyiIDwxKEBAaUJBgICdTzB09amoTQqe5OJ9T7dU6O6bvuuutTnZvqy6rqbpthGIYAAAAsoIqvCwAAACgvBB8AAGAZBB8AAGAZBB8AAGAZBB8AAGAZBB8AAGAZBB8AAGAZBB8AAGAZBB8AAGAZBB+gklu+fLlsNttVf77++mtfl2gZX3/9tennPC8vT7Nnzy5x3aK/8aFDh9yuEbA6f18XAMAzli1bpjZt2hRrj4mJ8UE1KKu8vDwlJydLkvr06eO07NZbb9V3332n8PBwH1QGXF8IPsB1om3btoqNjfV1GSooKJDNZpO/v28OL4Zh6Ny5c6patapPtu8NdevWVd26dX1dBnBd4FIXYCE2m01TpkzRO++8o+joaAUHB6t9+/b65z//Wazvvn37NHLkSNWrV092u13R0dF65ZVXnPoUXdp555139Oijj6pRo0ay2+3av3+/JOn1119Xq1atZLfbFRMToxUrVmjcuHFq2rSppEshJSoqSgMGDCi2/TNnzigsLEyTJ092aZ+WLFmi6Oho2e12vfXWWy7vw8WLF/Xss8+qdevWqlq1qmrUqKF27dpp0aJFTv2+/fZb3XLLLQoJCVFwcLB69uypzz77rPQnXJfO3lx5BkeS0/Nw6NAhR7BJTk52XKYcN26cpKtf6lq6dKnat2+voKAg1apVS3fccYf27NlTbDvVq1fX/v37NXjwYFWvXl0RERF69NFHlZ+ff836gesNZ3yA68SFCxdUWFjo1Gaz2eTn5+fU9tlnn2nz5s2aM2eOqlevrvnz5+uOO+7Q3r171bx5c0nS7t271bNnTzVp0kQvvviiGjRooC+//FJTp07VyZMnNWvWLKcxp0+frh49emjJkiWqUqWK6tWrp9dee01//OMfdeedd+rll19Wdna2kpOTnV5sbTabHnroIU2bNk379u1TVFSUY9nbb7+tnJycawYfSfr444+1YcMGPf3002rQoIHq1avn8j7Mnz9fs2fP1p/+9Cf16tVLBQUF+umnn3T69GnH+OvXr1f//v3Vrl07vfnmm7Lb7UpJSdGQIUP0/vvva8SIEa79ka4iPDxcX3zxhQYOHKjExERNmDBBkko9yzNv3jzNmDFDf/jDHzRv3jydOnVKs2fPVo8ePbR582an57KgoEBDhw5VYmKiHn30UX3zzTd65plnFBYWpqefftqt2oFKxwBQqS1btsyQVOKPn5+fU19JRv369Y2cnBxHW1ZWllGlShVj3rx5jrYBAwYYjRs3NrKzs53WnzJlihEUFGT88ssvhmEYxrp16wxJRq9evZz6XbhwwWjQoIHRrVs3p/bDhw8bAQEBRmRkpKMtJyfHCAkJMR5++GGnvjExMUbfvn2vuf+SjLCwMEdNZd2H2267zejQoUOp2+jevbtRr149Izc319FWWFhotG3b1mjcuLFx8eJFwzB+fz7WrVvn6Ne7d2+jd+/excYcO3as0/Pwv//9z5BkzJo1q1jfor/xwYMHDcMwjF9//dWoWrWqMXjwYKd+GRkZht1uN0aOHOm0HUnG3/72N6e+gwcPNlq3bl3qfgPXIy51AdeJt99+W5s3b3b6+f7774v169u3r0JCQhyP69evr3r16unw4cOSpHPnzulf//qX7rjjDgUHB6uwsNDxM3jwYJ07d07//ve/nca88847nR7v3btXWVlZuueee5zamzRpoptuusmpLSQkRPfdd5+WL1+u3377TZK0du1a7d69W1OmTHFp3+Pj41WzZk3H47LsQ9euXbVjxw5NmjRJX375pXJycpzG/u233/T999/rrrvuUvXq1R3tfn5+Gj16tH7++Wft3bvXpTo95bvvvtPZs2cdl8KKREREKD4+Xv/617+c2m02m4YMGeLU1q5dO8ffHLASgg9wnYiOjlZsbKzTT+fOnYv1q127drE2u92us2fPSpJOnTqlwsJC/eUvf1FAQIDTz+DBgyVJJ0+edFr/yncbnTp1StKlUHWlktoeeugh5ebm6r333pMk/fWvf1Xjxo11++23u7LrJW7f1X2YPn26FixYoH//+98aNGiQateurVtuuUVbtmyRJP36668yDKPEd1Q1bNjQaX/LS9H2rlbTlfUEBwcrKCjIqc1ut+vcuXPeKxKooLjHB4CTmjVrOs5mXO3+mmbNmjk9ttlsTo+LwtXx48eLrZuVlVWsrWXLlho0aJBeeeUVDRo0SJ988omSk5OL3Z90NVduvyz74O/vr6SkJCUlJen06dP66quvNGPGDA0YMEBHjhxRzZo1VaVKFWVmZhYb49ixY5KkOnXqXLW2oKAgZWdnF2u/MjyWRdHze7WaSqsHsDqCDwAnwcHB6tu3r7Zv36527dopMDCwzGO0bt1aDRo00N/+9jclJSU52jMyMrRx40bHmZLLPfzww0pISNDYsWPl5+en+++/v9z3oUaNGrrrrrt09OhRTZs2TYcOHVJMTIy6deumDz/8UAsWLHC8Tf7ixYt699131bhxY7Vq1eqqYzZt2lSrVq1Sfn6+7Ha7pEtnbDZu3KjQ0FBHv6JlRWfeStOjRw9VrVpV7777ru6++25H+88//6y1a9fqrrvucml/ASsi+ADXiZ07dxZ7V5cktWjRosyfAbNo0SLdfPPNiouL04MPPqimTZsqNzdX+/fv16effqq1a9eWun6VKlWUnJysP/7xj7rrrrs0fvx4nT59WsnJyQoPD1eVKsWvsvfv318xMTFat26dRo0apXr16pWpZrP7MGTIEMdnINWtW1eHDx/WwoULFRkZ6Xhn1Lx589S/f3/17dtXjz32mAIDA5WSkqKdO3fq/fffL3bG6XKjR4/Wq6++qlGjRun+++/XqVOnNH/+fKfQI1261ykyMlL/+Mc/dMstt6hWrVqqU6eO4y3vl6tRo4ZmzpypGTNmaMyYMfrDH/6gU6dOKTk5WUFBQcXedQfgMr6+uxqAe0p7V5ck4/XXX3f0lWRMnjy52BiRkZHG2LFjndoOHjxojB8/3mjUqJEREBBg1K1b1+jZs6fx7LPPOvoUvYtp1apVJdb22muvGS1btjQCAwONVq1aGUuXLjVuv/12o2PHjiX2nz17tiHJ+Pe//+3y/l9tn1zdhxdffNHo2bOnUadOHSMwMNBo0qSJkZiYaBw6dMhprA0bNhjx8fFGtWrVjKpVqxrdu3c3Pv30U6c+Jb2ryzAM46233jKio6ONoKAgIyYmxli5cmWxd3UZhmF89dVXRseOHQ273W5IcvxNrnxXV5E33njDaNeunREYGGiEhYUZt99+u7Fr1y6nPmPHjjWqVatW7LmZNWuWwUsArMhmGIbhg7wFwIJOnz6tVq1aadiwYXrttdeKLY+NjZXNZtPmzZt9UB0AK+BSFwCvyMrK0nPPPae+ffuqdu3aOnz4sF5++WXl5ubq4YcfdvTLycnRzp079c9//lNbt27VRx995MOqAVzvCD4AvMJut+vQoUOaNGmSfvnlFwUHB6t79+5asmSJbrjhBke/bdu2OcLRrFmzNGzYMN8VDeC6x6UuAABgGXyAIQAAsAyCDwAAsAyCDwAAsAzL39x88eJFHTt2TCEhIaV+CBkAAKg4DMNQbm6uGjZsWOKHol6N5YPPsWPHFBER4esyAACACUeOHFHjxo1d7m/54BMSEiLp0hN35UfIm1FQUKA1a9YoISFBAQEB5TJGWfq70re0PmaWeeI58SZv1+fu+GbWd3Udd+fDtZYzJ7wzdmWdE2aPLb5m5WOEq3198bqRk5OjiIgIx+u4qywffIoub4WGhnos+AQHBys0NNStg1pZxihLf1f6ltbHzDJPPCfe5O363B3fzPquruPufLjWcuaEd8aurHPC7LHF16x8jHC1ry9fN8p6mwo3NwMAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMsg+AAAAMvw93UBcE/e+ULFPL1Gkr/69CtUWECAr0sCAKDC4owPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwDIIPAACwjAoVfL755hsNGTJEDRs2lM1m08cff3zNddavX6/OnTsrKChIzZs315IlS7xfKAAAqJQqVPD57bff1L59e/31r391qf/Bgwc1ePBgxcXFafv27ZoxY4amTp2qv//9716uFAAAVEb+vi7gcoMGDdKgQYNc7r9kyRI1adJECxculCRFR0dry5YtWrBgge68804vVQkAACqrChV8yuq7775TQkKCU9uAAQP05ptvqqCgQAEBAcXWyc/PV35+vuNxTk6OJKmgoEAFBQVu11Q0hjtjlWWM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GjUUHx+v//u///PVLgAAgAqsQgUfSZo0aZImTZpU4rLly5cXa3vooYf00EMPebkqAABwPfDIpa7vv/9eBw8elHTp05QXLFigTz/91BNDAwAAeIzbZ3ymTZumLVu2qLCwUP369VNaWppuvfVWvfrqq1q7dq1efvllT9QJAADgNreDz1dffaUff/xR+fn5aty4sY4ePSq73a5HHnlEHTp08ECJAAAAnuGRS12FhYXKz89XQUGBzp07J0m6cOGCLly44InhAQAAPMLtMz6JiYmKjo7WhQsX9Nxzz2nEiBGKiorSxo0bdeedd3qiRgAAAI9wO/g88sgjGj16tKRLn748atQoffXVVxo1apS6devmdoEAAACe4nbwOXv2rGrVquX4BOWtW7fq8OHDlfILPwEAwPXN7Xt8unfv7viisHnz5um5556TYRhasmSJHnvsMbcLBAAA8BS3z/gUFhaqRo0akqS///3v2rhxowIDA5WUlMS7ugAAQIXi9hmf+vXra+PGjZKkRo0a6eTJk5Kk3Nxcd4cGAADwKLfP+CxdulTjxo1TYGCgqlWrpvbt26tLly46fvy4XnjhBU/UCAAA4BFuB5+mTZvq66+/1u7du7Vv3z7de++9aty4sbp06SI/Pz9P1AgAAOARHvuS0piYGMXExHhqOAAAAI9zK/gUFBQoKytLeXl5qlu3rmrVquWpugAAADyuzDc3nzlzRq+++qr69OmjsLAwNW3aVDExMapbt64iIyN1//33a/Pmzd6oFQAAwC1lCj4vv/yymjZtqtdff13x8fH68MMPlZ6err179+q7777TrFmzVFhYqP79+2vgwIHat2+ft+oGAAAoszJd6tq4caPWrVunG2+8scTlXbt21fjx47VkyRK9+eabWr9+vaKiojxSKAAAgLvKFHxWrVrl+P3IkSOKiIgosZ/dbtekSZPcqwwAAMDDTH+AYZs2bTRz5kz99ttvnqwHAADAa0wHn9TUVK1Zs0ZRUVFatmyZJ2sCAADwCtPBp2fPnvr+++/1/PPP6+mnn1bHjh319ddfe7A0AAAAz3L7u7rGjBmj//znPxoyZIhuvfVW3XHHHdq/f78nagMAAPAot4OPJBmGoYSEBD3wwAP65JNP1LZtWz366KN8USkAAKhQTH9y85IlS7R582Zt3rxZe/bskZ+fn9q1a6fJkyerQ4cOeu+99xQT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Pq1atUqTJ0/W6dOn9fzzz6t79+4KCQlRu3btyjxeYGCgOnfurNTUVKf21NRUp0tfl7vpppt07NgxnTlzxtH2n//8R1WqVFHjxo3LXAMAALi+mT7j06JFC7Vo0ULDhw93tOXk5Cg9PV0//PCDqTGTkpI0evRoxcbGqkePHnrttdeUkZGhiRMnSrp0mero0aN6++23JUkjR47UM888o/vuu0/Jyck6efKkHn/8cY0fP/6qNzcDAADrMh18srOz9fjjj2vt2rUKCAjQ2rVrFR4erl69eqlXr16mxhwxYoROnTqlOXPmKDMzU23bttXq1asVGRkpScrMzFRGRoajf/Xq1ZWamqqHHnpIsbGxql27tu655x49++yzZncLAABcx0wHn0mTJunAgQOaP3++Ro0apbNnz0qSpk2bpmbNmunhhx82Pe6kSZNKXLZ8+fJibW3atCl2eQwAAKAkpu/x+fzzz5WSkqLhw4fLz+/391APHDhQ77zzjkeKAwAA8CS3vqurevXqxdqioqK0f/9+d4YFAADwCtPBZ/DgwVqxYkWx9jNnzlz1c3cAAAB8yfQ9PvPmzVNsbKyk3z9k8OzZs5ozZ446derksQIBAAA8xXTwiYiIUFpamh588EHl5eWpa9euys3NVWhoqFavXu3JGgEAADzCdPCRpJYtWyo1NVUZGRnasWOHAgIC1K1bN9WsWdNT9VVaeecL1X7mGknS7jkDFBzo1lMNAAA8oMyvxjNmzNCwYcPUtWtXR1uTJk3UpEkTjxYGAADgaWW+uTkzM1O33XabwsPD9cADD+izzz5Tfn6+N2oDAADwqDIHn2XLlun48eP629/+pho1aujRRx9VnTp1NHz4cC1fvlwnT570Rp0AAABuM/V2dpvNpri4OM2fP18//fSTNm3apO7du+v1119Xo0aN1KtXLy1YsEBHjx71dL0AAACmmf4cnyNHjjh+j46O1hNPPKG0tDT9/PPPGjt2rDZs2KD333/fI0UCAAB4gung06ZNG82cOVO//fabU3vdunWVmJiof/zjH3rsscfcLhAAAMBTTAef1NRUrVmzRlFRUVq2bJknawIAAPAK08GnZ8+e+v777/X888/r6aefVseOHfX11197sDQAAADPcutLSiVpzJgx+s9//qMhQ4bo1ltv1R133MGXlAIAgArJ7eAjXfquroSEBD3wwAP65JNP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AAB4G8EHAABYBsEHAABYBsEHAABYBsGnkgsO9Ne+ZxK0qEehggMr3L3qAABUKAQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfAABgGQQfuOzCRUPfH/xFW0/a9P3BX3ThouHVbX3331P6R/pRffffU17bFvtUObZVXs9d0bbYJ/Pb+e6/p/TpD5nal23j35OJbV2P+1Re23KVv68LuFJKSopeeOEFZWZm6oYbbtDChQsVFxd31f7r169XUlKSdu3apYYNG+qJJ57QxIkTy7Fia/hiZ6aSP92tzOxzkvz09r4tCg8L0qwhMRrYNtyL27rEG9sqz33accqmeS9+o6ycfEdbZd+n8tpWec2H4tvy3j6V13yQfPl38tMHL36j2UNv4BjhAo4R5adCnfFZuXKlpk2bpqeeekrbt29XXFycBg0apIyMjBL7Hzx4UIMHD1ZcXJy2b9+uGTNmaOrUqfr73/9ezpVf377YmakH393mdJCRpKzsc3rw3W36YmdmpdtWee7Tl7uOa+l/qjgd0LyxLf5OlWNb5TUfJN//nY7n5F93+8QxouJtq6wq1Bmfl156SYmJiZowYYIkaeHChfryyy+1ePFizZs3r1j/JUuWqEmTJlq4cKEkKTo6Wlu2bNGCBQt05513lmfplVbe+cJibQUFhcq/cGlZlQvSrE92qaSTk4Ykm6TZn+zWTS3r6OKF39cLMGwljnd5+5UuXDRc3pZflauPcy3ltZ2ibT3z2U8lLnN1W648f2b3yZWxr+xTlm25MyfK++9UXnPP3fkgVaw54YljhLf3qaw4RpT9b+ON1w1vsRmG4fsLbpLOnz+v4OBgrVq1SnfccYej/eGHH1Z6errWr19fbJ1evXqpY8eOWrRokaPto48+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"Energy resolution per energy\")\n", + "ax2 = ctaplot.plots.plot_energy_resolution(\n", + " true_energy = joined_table[\"true_energy\"].data * u.TeV,\n", + " reco_energy = joined_table[\"CTLearn_tel_energy\"].data * u.TeV, \n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ctlearn", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/pyproject.toml b/pyproject.toml index 434bd27a..3cc0a7ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,8 +62,8 @@ documentation = "https://ctlearn.readthedocs.io/en/latest/" [project.scripts] ctlearn-train-model = "ctlearn.tools.train_model:main" -ctlearn-predict-mono-model = "ctlearn.tools.predict_model:mono_tool" -ctlearn-predict-stereo-model = "ctlearn.tools.predict_model:stereo_tool" +ctlearn-predict-mono-model = "ctlearn.tools.predict_mono_model:main" +ctlearn-predict-stereo-model = "ctlearn.tools.predict_stereo_model:main" ctlearn-predict-LST1= "ctlearn.tools.predict_LST1:main" [tool.setuptools_scm] From e29217b5b45187dbd6cf6a14723233369aec73a0 Mon Sep 17 00:00:00 2001 From: TjarkMiener Date: Thu, 28 Aug 2025 17:25:31 +0200 Subject: [PATCH 5/5] fix imports --- ctlearn/tools/predict_stereo_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ctlearn/tools/predict_stereo_model.py b/ctlearn/tools/predict_stereo_model.py index 641daacf..a9e61bb4 100644 --- a/ctlearn/tools/predict_stereo_model.py +++ b/ctlearn/tools/predict_stereo_model.py @@ -15,6 +15,7 @@ ReconstructedGeometryContainer, ReconstructedEnergyContainer, ) +from ctapipe.io import read_table, write_table from ctapipe.reco.utils import add_defaults_and_meta from dl1_data_handler.reader import ProcessType from ctlearn.tools.predict_model import PredictCTLearnModel