Ejemplo n.º 1
0
    def __call__(self, waveforms, telid, selected_gain_channel):
        if self.pixel_fraction.tel[telid] == 1.0:
            # average over pixels then argmax over samples
            peak_index = waveforms.mean(axis=-2).argmax()
        else:
            n_pixels = int(self.pixel_fraction.tel[telid] *
                           waveforms.shape[-2])
            brightest = np.argsort(waveforms.max(axis=-1))[..., -n_pixels:]

            # average over brightest pixels then argmax over samples
            peak_index = waveforms[brightest].mean(axis=-2).argmax()

        charge, peak_time = extract_around_peak(
            waveforms,
            peak_index,
            self.window_width.tel[telid],
            self.window_shift.tel[telid],
            self.sampling_rate_ghz[telid],
        )
        if self.apply_integration_correction.tel[telid]:
            charge *= self._calculate_correction(
                telid=telid)[selected_gain_channel]
        return DL1CameraContainer(image=charge,
                                  peak_time=peak_time,
                                  is_valid=True)
Ejemplo n.º 2
0
 def __call__(self, waveforms, telid, selected_gain_channel):
     charge, peak_time = extract_around_peak(waveforms, 0,
                                             waveforms.shape[-1], 0,
                                             self.sampling_rate_ghz[telid])
     return DL1CameraContainer(image=charge,
                               peak_time=peak_time,
                               is_valid=True)
Ejemplo n.º 3
0
    def _fill_container(self, container, data):
        """Fill container with data from files. Used for both __getitem__ and _generator."""
        event = container
        event_data = data

        event.index = EventIndexContainer(obs_id=self.obs_id,
                                          event_id=event_data["eventNum"])
        # no event.r0
        # no event.r1
        # no event.dl0

        if self.is_simulation:
            event.mcheader = self.mc_header
            event.mc.energy = u.Quantity(
                event_data["corsika_event_header_total_energy"], u.GeV)
            event.mc.core_x = u.Quantity(event_data["corsika_event_header_x"],
                                         u.cm)
            event.mc.core_y = u.Quantity(event_data["corsika_event_header_y"],
                                         u.cm)
            event.mc.h_first_int = u.Quantity(
                event_data["corsika_event_header_first_interaction_height"])
            # event.mc.xmax = u.Quantity(, u.g / u.cm ** 2)
            event.mc.shower_primary_id = 0
            event.mc.alt = u.Quantity(90 - event_data["source_position_zd"],
                                      u.deg)
            event.mc.az = u.Quantity(event_data["source_position_az"], u.deg)
            event.mc.tel[1] = DL1CameraContainer(
                image=event_data["photoncharge"],
                pulse_time=event_data["arrival_time"])
        else:
            event.trig.gps_time = Time(event_data["timestamp"], scale="utc")
            event.dl0.tel[1].trigger_time = Time(event_data["timestamp"],
                                                 scale="utc")

            event.dl1.tel[1] = DL1CameraContainer(
                image=event_data["photoncharge"],
                pulse_time=event_data["arrival_time"])

        az = u.Quantity(event_data["pointing_position_az"], u.deg)
        alt = u.Quantity(90 - event_data["pointing_position_zd"], u.deg)

        event.pointing.tel[1].azimuth = az
        event.pointing.tel[1].altitude = alt
        event.pointing.array_azimuth = az
        event.pointing.array_altitude = alt

        return event
Ejemplo n.º 4
0
    def _calibrate_dl1(self, event, telid):
        waveforms = event.dl0.tel[telid].waveform
        selected_gain_channel = event.dl0.tel[telid].selected_gain_channel
        dl1_calib = event.calibration.tel[telid].dl1

        if self._check_dl0_empty(waveforms):
            return

        selected_gain_channel = event.r1.tel[telid].selected_gain_channel
        time_shift = event.calibration.tel[telid].dl1.time_shift
        readout = self.subarray.tel[telid].camera.readout
        n_pixels, n_samples = waveforms.shape

        # subtract any remaining pedestal before extraction
        if dl1_calib.pedestal_offset is not None:
            # this copies intentionally, we don't want to modify the dl0 data
            # waveforms have shape (n_pixel, n_samples), pedestals (n_pixels, )
            waveforms = waveforms - dl1_calib.pedestal_offset[:, np.newaxis]

        if n_samples == 1:
            # To handle ASTRI and dst
            # TODO: Improved handling of ASTRI and dst
            #   - dst with custom EventSource?
            #   - Read into dl1 container directly?
            #   - Don't do anything if dl1 container already filled
            #   - Update on SST review decision
            dl1 = DL1CameraContainer(
                image=waveforms[..., 0].astype(np.float32),
                peak_time=np.zeros(n_pixels, dtype=np.float32),
                is_valid=True,
            )
        else:

            # shift waveforms if time_shift calibration is available
            if time_shift is not None:
                if self.apply_waveform_time_shift.tel[telid]:
                    sampling_rate = readout.sampling_rate.to_value(u.GHz)
                    time_shift_samples = time_shift * sampling_rate
                    waveforms, remaining_shift = shift_waveforms(
                        waveforms, time_shift_samples
                    )
                    remaining_shift /= sampling_rate
                else:
                    remaining_shift = time_shift

            extractor = self.image_extractors[self.image_extractor_type.tel[telid]]
            dl1 = extractor(
                waveforms, telid=telid, selected_gain_channel=selected_gain_channel
            )

            # correct non-integer remainder of the shift if given
            if self.apply_peak_time_shift.tel[telid] and time_shift is not None:
                dl1.peak_time -= remaining_shift

        # Calibrate extracted charge
        dl1.image *= dl1_calib.relative_factor / dl1_calib.absolute_factor

        # store the results in the event structure
        event.dl1.tel[telid] = dl1
Ejemplo n.º 5
0
 def __call__(self, waveforms, telid, selected_gain_channel):
     charge, peak_time = extract_sliding_window(
         waveforms, self.window_width.tel[telid],
         self.sampling_rate_ghz[telid])
     if self.apply_integration_correction.tel[telid]:
         charge *= self._calculate_correction(
             telid=telid)[selected_gain_channel]
     return DL1CameraContainer(image=charge,
                               peak_time=peak_time,
                               is_valid=True)
Ejemplo n.º 6
0
    def __call__(self, waveforms, telid, selected_gain_channel):
        charge1, pulse_time1, correction1 = self._apply_first_pass(
            waveforms, telid)

        # FIXME: properly make sure that output is 32Bit instead of downcasting here
        if self.disable_second_pass:
            return DL1CameraContainer(
                image=(charge1 *
                       correction1[selected_gain_channel]).astype("float32"),
                peak_time=pulse_time1.astype("float32"),
                is_valid=True,
            )

        charge2, pulse_time2, is_valid = self._apply_second_pass(
            waveforms, telid, selected_gain_channel, charge1, pulse_time1,
            correction1)
        # FIXME: properly make sure that output is 32Bit instead of downcasting here
        return DL1CameraContainer(
            image=charge2.astype("float32"),
            peak_time=pulse_time2.astype("float32"),
            is_valid=is_valid,
        )
Ejemplo n.º 7
0
 def __call__(self, waveforms, telid, selected_gain_channel):
     peak_index = waveforms.argmax(axis=-1).astype(np.int64)
     charge, peak_time = extract_around_peak(
         waveforms,
         peak_index,
         self.window_width.tel[telid],
         self.window_shift.tel[telid],
         self.sampling_rate_ghz[telid],
     )
     if self.apply_integration_correction.tel[telid]:
         charge *= self._calculate_correction(
             telid=telid)[selected_gain_channel]
     return DL1CameraContainer(image=charge,
                               peak_time=peak_time,
                               is_valid=True)
Ejemplo n.º 8
0
def generate_dl1_container(dataset: DataFrame,
                           event_id: str,
                           version="ML2") -> DL1CameraContainer:
    tels = dict()
    event_group: DataFrame = dataset.groupby("event_unique_id").get_group(
        event_id)
    for idx, tel in event_group.iterrows():
        tel_id = tel["telescope_id"]

        dl1 = DL1CameraContainer()
        charge, peakpos = load_camera(tel["source"],
                                      tel["folder"],
                                      tel["type"],
                                      tel_id,
                                      version=version)
        dl1.image = charge
        dl1.peak_time = peakpos

        tels[tel_id] = dl1
    return tels
Ejemplo n.º 9
0
    def _extract_charge(self, event) -> DL1CameraContainer:
        """
        Extract the charge and the time from a pedestal event

        Parameters
        ----------
        event: ArrayEventContainer
            general event container

        Returns
        -------
        DL1CameraContainer
        """
        waveforms = event.r1.tel[self.tel_id].waveform
        selected_gain_channel = event.r1.tel[self.tel_id].selected_gain_channel

        # Extract charge and time
        if self.extractor:
            return self.extractor(waveforms, self.tel_id,
                                  selected_gain_channel)
        else:
            return DL1CameraContainer(image=0, peak_pos=0, is_valid=False)
Ejemplo n.º 10
0
 def __call__(self, waveforms, telid, selected_gain_channel):
     neighbors = self.subarray.tel[
         telid].camera.geometry.neighbor_matrix_sparse
     peak_index = neighbor_average_maximum(
         waveforms,
         neighbors_indices=neighbors.indices,
         neighbors_indptr=neighbors.indptr,
         lwt=self.lwt.tel[telid],
     )
     charge, peak_time = extract_around_peak(
         waveforms,
         peak_index,
         self.window_width.tel[telid],
         self.window_shift.tel[telid],
         self.sampling_rate_ghz[telid],
     )
     if self.apply_integration_correction.tel[telid]:
         charge *= self._calculate_correction(
             telid=telid)[selected_gain_channel]
     return DL1CameraContainer(image=charge,
                               peak_time=peak_time,
                               is_valid=True)
Ejemplo n.º 11
0
def test_array_display():
    """ check that we can do basic array display functionality """
    from ctapipe.visualization.mpl_array import ArrayDisplay
    from ctapipe.image import timing_parameters

    from ctapipe.containers import (
        ArrayEventContainer,
        DL1Container,
        DL1CameraContainer,
        ImageParametersContainer,
        CoreParametersContainer,
    )

    # build a test subarray:
    tels = dict()
    tel_pos = dict()
    for ii, pos in enumerate([[0, 0, 0], [100, 0, 0], [-100, 0, 0]] * u.m):
        tels[ii + 1] = TelescopeDescription.from_name("MST", "NectarCam")
        tel_pos[ii + 1] = pos

    sub = SubarrayDescription(name="TestSubarray",
                              tel_positions=tel_pos,
                              tel_descriptions=tels)

    # Create a fake event containing telescope-wise information about
    # the image directions projected on the ground
    event = ArrayEventContainer()
    event.dl1 = DL1Container()
    event.dl1.tel = {1: DL1CameraContainer(), 2: DL1CameraContainer()}
    event.dl1.tel[1].parameters = ImageParametersContainer()
    event.dl1.tel[2].parameters = ImageParametersContainer()
    event.dl1.tel[2].parameters.core = CoreParametersContainer()
    event.dl1.tel[1].parameters.core = CoreParametersContainer()
    event.dl1.tel[1].parameters.core.psi = u.Quantity(2.0, unit=u.deg)
    event.dl1.tel[2].parameters.core.psi = u.Quantity(1.0, unit=u.deg)

    ad = ArrayDisplay(subarray=sub)
    ad.set_vector_rho_phi(1 * u.m, 90 * u.deg)

    # try setting a value
    vals = np.ones(sub.num_tels)
    ad.values = vals

    assert (vals == ad.values).all()

    # test UV field ...

    # ...with colors by telescope type
    ad.set_vector_uv(np.array([1, 2, 3]) * u.m, np.array([1, 2, 3]) * u.m)
    # ...with scalar color
    ad.set_vector_uv(np.array([1, 2, 3]) * u.m, np.array([1, 2, 3]) * u.m, c=3)

    geom = CameraGeometry.from_name("LSTCam")
    rot_angle = 20 * u.deg
    hillas = CameraHillasParametersContainer(x=0 * u.m,
                                             y=0 * u.m,
                                             psi=rot_angle)

    # test using hillas params CameraFrame:
    hillas_dict = {
        1: CameraHillasParametersContainer(length=100.0 * u.m, psi=90 * u.deg),
        2: CameraHillasParametersContainer(length=20000 * u.cm, psi="95deg"),
    }

    grad = 2
    intercept = 1

    timing_rot20 = timing_parameters(
        geom,
        image=np.ones(geom.n_pixels),
        peak_time=intercept + grad * geom.pix_x.value,
        hillas_parameters=hillas,
        cleaning_mask=np.ones(geom.n_pixels, dtype=bool),
    )
    gradient_dict = {1: timing_rot20.slope.value, 2: timing_rot20.slope.value}
    core_dict = {
        tel_id: dl1.parameters.core.psi
        for tel_id, dl1 in event.dl1.tel.items()
    }
    ad.set_vector_hillas(
        hillas_dict=hillas_dict,
        core_dict=core_dict,
        length=500,
        time_gradient=gradient_dict,
        angle_offset=0 * u.deg,
    )
    ad.set_line_hillas(hillas_dict=hillas_dict, core_dict=core_dict, range=300)

    # test using hillas params for divergent pointing in telescopeframe:
    hillas_dict = {
        1:
        HillasParametersContainer(fov_lon=1.0 * u.deg,
                                  fov_lat=1.0 * u.deg,
                                  length=1.0 * u.deg,
                                  psi=90 * u.deg),
        2:
        HillasParametersContainer(fov_lon=1.0 * u.deg,
                                  fov_lat=1.0 * u.deg,
                                  length=1.0 * u.deg,
                                  psi=95 * u.deg),
    }
    ad.set_vector_hillas(
        hillas_dict=hillas_dict,
        core_dict=core_dict,
        length=500,
        time_gradient=gradient_dict,
        angle_offset=0 * u.deg,
    )
    ad.set_line_hillas(hillas_dict=hillas_dict, core_dict=core_dict, range=300)

    # test using hillas params for parallel pointing in telescopeframe:
    hillas_dict = {
        1:
        HillasParametersContainer(fov_lon=1.0 * u.deg,
                                  fov_lat=1.0 * u.deg,
                                  length=1.0 * u.deg,
                                  psi=90 * u.deg),
        2:
        HillasParametersContainer(fov_lon=1.0 * u.deg,
                                  fov_lat=1.0 * u.deg,
                                  length=1.0 * u.deg,
                                  psi=95 * u.deg),
    }
    ad.set_vector_hillas(
        hillas_dict=hillas_dict,
        core_dict=core_dict,
        length=500,
        time_gradient=gradient_dict,
        angle_offset=0 * u.deg,
    )

    # test negative time_gradients
    gradient_dict = {1: -0.03, 2: -0.02}
    ad.set_vector_hillas(
        hillas_dict=hillas_dict,
        core_dict=core_dict,
        length=500,
        time_gradient=gradient_dict,
        angle_offset=0 * u.deg,
    )
    # and very small
    gradient_dict = {1: 0.003, 2: 0.002}
    ad.set_vector_hillas(
        hillas_dict=hillas_dict,
        core_dict=core_dict,
        length=500,
        time_gradient=gradient_dict,
        angle_offset=0 * u.deg,
    )

    # Test background contour
    ad.background_contour(
        x=np.array([0, 1, 2]),
        y=np.array([0, 1, 2]),
        background=np.array([[0, 1, 2], [0, 1, 2], [0, 1, 2]]),
    )

    ad.set_line_hillas(hillas_dict=hillas_dict, core_dict=core_dict, range=300)
    ad.add_labels()
    ad.remove_labels()