def test_waveform_extractor_factory_args(): """ Config is supposed to be created by a `Tool` """ from traitlets.config.loader import Config config = Config( { 'ImageExtractor': { 'window_width': 20, 'window_shift': 3, } } ) extractor = ImageExtractor.from_name( 'LocalPeakWindowSum', config=config, ) assert extractor.window_width == 20 assert extractor.window_shift == 3 with pytest.warns(UserWarning): ImageExtractor.from_name( 'FullWaveformSum', config=config, )
def test_extractor_tel_param(camera_waveforms): waveforms, subarray = camera_waveforms _, n_samples = waveforms.shape config = Config({ 'ImageExtractor': { 'window_width': [("type", "*", n_samples), ("id", "2", n_samples // 2)], 'window_start': 0, } }) waveforms, subarray = camera_waveforms n_pixels, n_samples = waveforms.shape extractor = ImageExtractor.from_name("FixedWindowSum", config=config) with pytest.raises(KeyError): assert extractor.window_width[1] == n_samples with pytest.raises(KeyError): assert extractor.window_width[2] == n_samples // 2 assert extractor.window_start[None] == 0 assert extractor.window_width[None] == n_samples extractor = ImageExtractor.from_name("FixedWindowSum", config=config, subarray=subarray) assert extractor.window_start[1] == 0 assert extractor.window_start[2] == 0 assert extractor.window_width[None] == n_samples assert extractor.window_width[1] == n_samples assert extractor.window_width[2] == n_samples // 2
def test_waveform_extractor_factory_args(subarray): """ Config is supposed to be created by a `Tool` """ config = Config({"ImageExtractor": {"window_width": 20, "window_shift": 3}}) extractor = ImageExtractor.from_name( "LocalPeakWindowSum", subarray=subarray, config=config ) assert extractor.window_width.tel[None] == 20 assert extractor.window_shift.tel[None] == 3 with pytest.warns(UserWarning): ImageExtractor.from_name("FullWaveformSum", config=config, subarray=subarray)
def __init__( self, subarray, config=None, parent=None, cleaner=None, image_extractor=None, **kwargs, ): """ Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription Description of the subarray config: traitlets.loader.Config Configuration specified by config file or cmdline arguments. Used to set traitlet values. Set to None if no configuration to pass. kwargs """ super().__init__(config=config, parent=parent, subarray=subarray, **kwargs) if cleaner is None: self.cleaner = TailcutsImageCleaner(parent=self, subarray=self.subarray) else: self.cleaner = cleaner if image_extractor is None: self.image_extractor = ImageExtractor.from_name( self.image_extractor_type, subarray=self.subarray, parent=self ) else: self.image_extractor = image_extractor
def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" self.reader = EventSource.from_config(parent=self) self.seeker = EventSeeker(self.reader, parent=self) self.extractor = ImageExtractor.from_name(self.extractor_product, parent=self) self.dl0 = CameraDL0Reducer(parent=self) self.dl1 = CameraDL1Calibrator(extractor=self.extractor, parent=self) self.viewer = BokehEventViewer(parent=self) # Setup widgets self.viewer.create() self.viewer.enable_automatic_index_increment() self.create_previous_event_widget() self.create_next_event_widget() self.create_event_index_widget() self.create_goto_event_index_widget() self.create_event_id_widget() self.create_goto_event_id_widget() self.create_telid_widget() self.create_channel_widget() self.create_dl1_widgets() self.update_dl1_widget_values() # Setup layout self.layout = layout([[self.viewer.layout], [ self.w_previous_event, self.w_next_event, self.w_goto_event_index, self.w_goto_event_id ], [self.w_event_index, self.w_event_id], [self.w_telid, self.w_channel], [self.wb_extractor]])
def test_waveform_extractor_factory(toymodel): waveforms, subarray, telid, selected_gain_channel, true_charge, true_time = toymodel extractor = ImageExtractor.from_name("LocalPeakWindowSum", subarray=subarray) charge, pulse_time = extractor(waveforms, telid, selected_gain_channel) assert_allclose(charge, true_charge, rtol=0.1) assert_allclose(pulse_time, true_time, rtol=0.1)
def __init__(self, subarray, **kwargs): """ The TimeCorrectionCalculate class to create h5py file with coefficients for time correction curve of chip DRS4. Description of this method: "Analysis techniques and performance of the Domino Ring Sampler version 4 based readout for the MAGIC telescopes [arxiv:1305.1007] Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription Description of the subarray. Provides information about the camera which are useful in charge extraction, such as reference pulse shape, sampling rate, neighboring pixels. Also required for configuring the TelescopeParameter traitlets. kwargs """ super().__init__(**kwargs) self.n_bins = int(self.n_capacitors / self.n_combine) self.mean_values_per_bin = np.zeros((n_gain, n_pixels, self.n_bins)) self.entries_per_bin = np.zeros((n_gain, n_pixels, self.n_bins)) self.first_cap_array = np.zeros((n_modules, n_gain, n_channel)) # load the waveform charge extractor self.extractor = ImageExtractor.from_name(self.charge_product, config=self.config, subarray=subarray) self.log.info(f"extractor {self.extractor}") self.sum_events = 0
def test_extractor_tel_param(toymodel): waveforms, subarray, _, _, _, _ = toymodel _, n_samples = waveforms.shape config = Config({ "ImageExtractor": { "window_width": [("type", "*", n_samples), ("id", "2", n_samples // 2)], "window_start": 0, } }) waveforms, subarray, _, _, _, _ = toymodel n_pixels, n_samples = waveforms.shape extractor = ImageExtractor.from_name( "FixedWindowSum", subarray=subarray, config=config, ) assert extractor.window_start.tel[None] == 0 assert extractor.window_start.tel[1] == 0 assert extractor.window_start.tel[2] == 0 assert extractor.window_width.tel[None] == n_samples assert extractor.window_width.tel[1] == n_samples assert extractor.window_width.tel[2] == n_samples // 2
def __init__( self, subarray, config=None, parent=None, image_extractor=None, data_volume_reducer=None, **kwargs, ): """ Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription Description of the subarray. Provides information about the camera which are useful in calibration. Also required for configuring the TelescopeParameter traitlets. config: traitlets.loader.Config Configuration specified by config file or cmdline arguments. Used to set traitlet values. This is mutually exclusive with passing a ``parent``. parent: ctapipe.core.Component or ctapipe.core.Tool Parent of this component in the configuration hierarchy, this is mutually exclusive with passing ``config`` data_volume_reducer: ctapipe.image.reducer.DataVolumeReducer The DataVolumeReducer to use. This is used to override the options from the config system and to enable passing a preconfigured reducer. image_extractor: ctapipe.image.extractor.ImageExtractor The ImageExtractor to use. If None, the default via the configuration system will be constructed. """ super().__init__(subarray=subarray, config=config, parent=parent, **kwargs) self.subarray = subarray self._r1_empty_warn = False self._dl0_empty_warn = False self.image_extractors = {} if image_extractor is None: for (_, _, name) in self.image_extractor_type: self.image_extractors[name] = ImageExtractor.from_name( name, subarray=self.subarray, parent=self) else: name = image_extractor.__class__.__name__ self.image_extractor_type = [("type", "*", name)] self.image_extractors[name] = image_extractor if data_volume_reducer is None: self.data_volume_reducer = DataVolumeReducer.from_name( self.data_volume_reducer_type, subarray=self.subarray, parent=self) else: self.data_volume_reducer = data_volume_reducer
def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" event_source = self.add_component(EventSource.from_config(parent=self)) self.eventseeker = self.add_component( EventSeeker(event_source, parent=self)) self.extractor = self.add_component( ImageExtractor.from_name(self.extractor_product, parent=self)) self.calibrate = self.add_component( CameraCalibrator(parent=self, image_extractor=self.extractor))
def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" self.eventsource = self.add_component(SimTelEventSource(parent=self)) extractor = self.add_component( ImageExtractor.from_name(self.extractor_product, parent=self)) self.calibrator = self.add_component( CameraCalibrator(parent=self, image_extractor=extractor)) self.calculator = ChargeResolutionCalculator()
def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" event_source = EventSource.from_config(parent=self) self.eventseeker = EventSeeker(event_source, parent=self) self.extractor = ImageExtractor.from_name( self.extractor_product, parent=self, ) self.dl0 = CameraDL0Reducer(parent=self) self.dl1 = CameraDL1Calibrator(extractor=self.extractor, parent=self)
def __init__(self, subarray, **kwargs): """ Parameters ---------- reducer_product : ctapipe.image.reducer.DataVolumeReducer The DataVolumeReducer to use. If None, then NullDataVolumeReducer will be used by default, and waveforms will not be reduced. extractor_product : ctapipe.image.extractor.ImageExtractor The ImageExtractor to use. If None, then LocalPeakWindowSum will be used by default. calibration_path : Path to LST calibration file to get the pedestal and flat-field corrections kwargs """ super().__init__(subarray, **kwargs) # load the waveform charge extractor self.image_extractor = ImageExtractor.from_name(self.extractor_product, subarray=self.subarray, config=self.config) self.log.info(f"extractor {self.extractor_product}") print("EXTRACTOR", self.image_extractor) self.data_volume_reducer = DataVolumeReducer.from_name( self.reducer_product, subarray=self.subarray, config=self.config) self.log.info(f" {self.reducer_product}") # declare gain selector if the threshold is defined if self.gain_threshold: self.gain_selector = gainselection.ThresholdGainSelector( threshold=self.gain_threshold) # declare time calibrator if correction file exist if os.path.exists(self.time_calibration_path): self.time_corrector = PulseTimeCorrection( calib_file_path=self.time_calibration_path) else: raise IOError( f"Time calibration file {self.time_calibration_path} not found!" ) # calibration data container self.mon_data = MonitoringContainer() # initialize the MonitoringContainer() for the moment it reads it from a hdf5 file self._initialize_correction() self.log.info(f"Global charge scale {self.charge_scale}")
def test_waveform_extractor_factory_args(): """ Config is supposed to be created by a `Tool` """ config = Config( {'ImageExtractor': { 'window_width': 20, 'window_shift': 3, }}) extractor = ImageExtractor.from_name( 'LocalPeakWindowSum', config=config, ) assert extractor.window_width[None] == 20 assert extractor.window_shift[None] == 3 with pytest.warns(UserWarning): ImageExtractor.from_name( 'FullWaveformSum', config=config, )
def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" self.eventsource = SimTelEventSource(parent=self) extractor = ImageExtractor.from_name(self.extractor_product, parent=self) self.dl0 = CameraDL0Reducer(parent=self) self.dl1 = CameraDL1Calibrator(extractor=extractor, parent=self) self.calculator = ChargeResolutionCalculator()
def test_waveform_extractor_factory_args(subarray): """ Config is supposed to be created by a `Tool` """ config = Config( {"ImageExtractor": { "window_width": 20, "window_shift": 3 }}) extractor = ImageExtractor.from_name("LocalPeakWindowSum", subarray=subarray, config=config) assert extractor.window_width.tel[None] == 20 assert extractor.window_shift.tel[None] == 3 # this basically tests that traitlets do not accept unknown traits, # which is tested for all traitlets in the core tests already with pytest.raises(TraitError): ImageExtractor.from_name("FullWaveformSum", config=config, subarray=subarray)
def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" self.reader = EventSource.from_config(parent=self) self.seeker = EventSeeker(self.reader, parent=self) self.extractor = ImageExtractor.from_name( self.extractor_product, parent=self ) self.r1 = CameraR1Calibrator.from_eventsource( eventsource=self.reader, parent=self ) self.dl0 = CameraDL0Reducer(parent=self) self.dl1 = CameraDL1Calibrator( extractor=self.extractor, parent=self ) self.viewer = BokehEventViewer(parent=self) # Setup widgets self.viewer.create() self.viewer.enable_automatic_index_increment() self.create_previous_event_widget() self.create_next_event_widget() self.create_event_index_widget() self.create_goto_event_index_widget() self.create_event_id_widget() self.create_goto_event_id_widget() self.create_telid_widget() self.create_channel_widget() self.create_dl1_widgets() self.update_dl1_widget_values() # Setup layout self.layout = layout([ [self.viewer.layout], [ self.w_previous_event, self.w_next_event, self.w_goto_event_index, self.w_goto_event_id ], [self.w_event_index, self.w_event_id], [self.w_telid, self.w_channel], [self.wb_extractor] ])
def on_dl1_widget_change(self, _, __, ___): if self.event: if not self._updating_dl1: self._updating_dl1 = True cmdline = [] for key, val in self.w_dl1_dict.items(): k = key.replace("extractor_", "ImageExtractor.") if val.value: cmdline.append(f'--{k}={val.value}') self.parse_command_line(cmdline) extractor = ImageExtractor.from_name(self.extractor_product, parent=self) self.update_dl1_calibrator(extractor) self.update_dl1_widget_values() self._updating_dl1 = False
def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" self.eventsource = SimTelEventSource(parent=self) extractor = ImageExtractor.from_name( self.extractor_product, parent=self ) self.dl0 = CameraDL0Reducer(parent=self) self.dl1 = CameraDL1Calibrator(extractor=extractor, parent=self) self.calculator = ChargeResolutionCalculator()
def __init__(self, **kwargs): super().__init__(**kwargs) self.n_bins = int(self.n_capacitors / self.n_combine) self.mean_values_per_bin = np.zeros((n_gain, n_pixels, self.n_bins)) self.entries_per_bin = np.zeros((n_gain, n_pixels, self.n_bins)) self.first_cap_array = np.zeros((n_modules, n_gain, n_channel)) # load the waveform charge extractor self.extractor = ImageExtractor.from_name(self.charge_product, config=self.config) self.log.info(f"extractor {self.extractor}") self.sum_events = 0
def on_dl1_widget_change(self, _, __, ___): if self.event: if not self._updating_dl1: self._updating_dl1 = True cmdline = [] for key, val in self.w_dl1_dict.items(): k = key.replace("extractor_", "ImageExtractor.") if val.value: cmdline.append(f'--{k}={val.value}') self.parse_command_line(cmdline) extractor = ImageExtractor.from_name( self.extractor_product, parent=self) self.update_dl1_calibrator(extractor) self.update_dl1_widget_values() self._updating_dl1 = False
def test_sw_pulse_lst(): """ Test function of sliding window extractor for LST camera pulse shape with the correction for the integration window completeness """ # prepare array with 1 LST subarray = SubarrayDescription( "LST1", tel_positions={1: np.zeros(3) * u.m}, tel_descriptions={ 1: TelescopeDescription.from_name(optics_name="LST", camera_name="LSTCam") }, ) telid = list(subarray.tel.keys())[0] n_pixels = subarray.tel[telid].camera.geometry.n_pixels n_samples = 40 readout = subarray.tel[telid].camera.readout random = np.random.RandomState(1) min_charge = 100 max_charge = 1000 charge_true = random.uniform(min_charge, max_charge, n_pixels) time_true = random.uniform(n_samples // 2 - 1, n_samples // 2 + 1, n_pixels) / readout.sampling_rate.to_value( u.GHz) waveform_model = WaveformModel.from_camera_readout(readout) waveform = waveform_model.get_waveform(charge_true, time_true, n_samples) selected_gain_channel = np.zeros(charge_true.size, dtype=np.int8) # define extractor config = Config({"SlidingWindowMaxSum": {"window_width": 8}}) extractor = SlidingWindowMaxSum(subarray=subarray) extractor = ImageExtractor.from_name("SlidingWindowMaxSum", subarray=subarray, config=config) dl1: DL1CameraContainer = extractor(waveform, telid, selected_gain_channel) print(dl1.image / charge_true) assert_allclose(dl1.image, charge_true, rtol=0.02) assert dl1.is_valid
def __init__(self, subarray, **kwargs): """Calculates flat-field parameters from flasher data based on the best algorithm described by S. Fegan in MST-CAM-TN-0060 (eq. 19) Pixels are defined as outliers on the base of a cut on the pixel charge median over the full sample distribution and the pixel signal time inside the waveform time Parameters: ---------- charge_cut_outliers : List[2] Interval of accepted charge values (fraction with respect to camera median value) time_cut_outliers : List[2] Interval (in waveform samples) of accepted time values """ super().__init__(subarray, **kwargs) self.log.info("Used events statistics : %d", self.sample_size) # members to keep state in calculate_relative_gain() self.num_events_seen = 0 self.time_start = None # trigger time of first event in sample self.trigger_time = None # trigger time of present event self.charge_medians = None # med. charge in camera per event in sample self.charges = None # charge per event in sample self.arrival_times = None # arrival time per event in sample self.sample_masked_pixels = None # masked pixels per event in sample # declare the charge sampling corrector if self.time_sampling_correction_path is not None: self.time_sampling_corrector = TimeSamplingCorrection( time_sampling_correction_path=self.time_sampling_correction_path ) else: self.time_sampling_corrector = None # fix for broken extractor setup in ctapipe baseclass self.extractor = ImageExtractor.from_name( self.charge_product, parent=self, subarray=subarray )
def __init__(self, subarray, **kwargs): """ Parent class for the flat-field calculators. Fills the MonitoringCameraContainer.FlatfieldContainer on the base of a given flat-field event sample. The sample is defined by a maximal interval of time (sample_duration) or a minimal number of events (sample_duration). The calculator is supposed to be called in an event loop, extract and collect the event charge and fill the PedestalContainer Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription Description of the subarray tel_id : int id of the telescope (default 0) sample_duration : int interval of time (s) used to gather the pedestal statistics sample_size : int number of pedestal events requested for the statistics n_channels : int number of waveform channel to be considered charge_product : str Name of the charge extractor to be used config : traitlets.loader.Config Configuration specified by config file or cmdline arguments. Used to set traitlet values. Set to None if no configuration to pass. kwargs """ super().__init__(**kwargs) # load the waveform charge extractor self.extractor = ImageExtractor.from_name( self.charge_product, config=self.config, subarray=subarray, ) self.log.info(f"extractor {self.extractor}")
def __init__(self, subarray, **kwargs): """Calculates pedestal parameters integrating the charge of pedestal events: the pedestal value corresponds to the charge estimated with the selected charge extractor The pixels are set as outliers on the base of a cut on the pixel charge median over the pedestal sample and the pixel charge standard deviation over the pedestal sample with respect to the camera median values Parameters: ---------- charge_median_cut_outliers : List[2] Interval (number of std) of accepted charge values around camera median value charge_std_cut_outliers : List[2] Interval (number of std) of accepted charge standard deviation around camera median value """ super().__init__(subarray, **kwargs) self.log.info("Used events statistics : %d", self.sample_size) # members to keep state in calculate_relative_gain() self.num_events_seen = 0 self.time_start = None # trigger time of first event in sample self.trigger_time = None # trigger time of present event self.charge_medians = None # med. charge in camera per event in sample self.charges = None # charge per event in sample self.sample_masked_pixels = None # pixels tp be masked per event in sample # declare the charge sampling corrector if self.time_sampling_correction_path is not None: self.time_sampling_corrector = TimeSamplingCorrection( time_sampling_correction_path=self. time_sampling_correction_path) else: self.time_sampling_corrector = None # fix for broken extractor setup in ctapipe baseclass self.extractor = ImageExtractor.from_name(self.charge_product, parent=self, subarray=subarray)
def __init__(self, **kwargs): """ Parent class for the flat field calculators. Fills the flatfield container. Parameters ---------- config : traitlets.loader.Config Configuration specified by config file or cmdline arguments. Used to set traitlet values. Set to None if no configuration to pass. tool : ctapipe.core.Tool Tool executable that is calling this component. Passes the correct logger to the component. Set to None if no Tool to pass. kwargs """ super().__init__(**kwargs) # load the waveform charge extractor self.extractor = ImageExtractor.from_name(self.charge_product, config=self.config) self.log.info(f"extractor {self.extractor}")
def test_waveform_extractor_factory(camera_waveforms): waveforms, _ = camera_waveforms extractor = ImageExtractor.from_name('LocalPeakWindowSum') extractor(waveforms)