Esempio n. 1
0
class ImageSumDisplayerTool(Tool):
    description = Unicode(__doc__)
    name = "ctapipe-image-sum-display"

    infile = Unicode(
        help='input simtelarray file',
        default="/Users/kosack/Data/CTA/Prod3/gamma.simtel.gz").tag(
            config=True)
    telgroup = Integer(help='telescope group number',
                       default=1).tag(config=True)

    aliases = Dict({
        'infile': 'ImageSumDisplayerTool.infile',
        'telgroup': 'ImageSumDisplayerTool.telgroup'
    })

    def setup(self):
        # load up the telescope types table (need to first open a file, a bit of
        # a hack until a proper insturment module exists) and select only the
        # telescopes with the same camera type
        data = next(hessio_event_source(self.infile, max_events=1))
        camtypes = get_camera_types(data.inst)
        group = camtypes.groups[self.telgroup]
        self._selected_tels = group['tel_id'].data
        self._base_tel = self._selected_tels[0]
        self.log.info("Telescope group %d: %s with %s camera", self.telgroup,
                      group[0]['tel_type'], group[0]['cam_type'])
        self.log.info("SELECTED TELESCOPES:{}".format(self._selected_tels))

    def start(self):
        geom = None
        imsum = None
        disp = None

        for data in hessio_event_source(self.infile,
                                        allowed_tels=self._selected_tels,
                                        max_events=None):
            if geom is None:
                x, y = data.inst.pixel_pos[self._base_tel]
                flen = data.inst.optical_foclen[self._base_tel]
                geom = CameraGeometry.guess(x, y, flen)
                imsum = np.zeros(shape=x.shape, dtype=np.float)
                disp = CameraDisplay(geom, title=geom.cam_id)
                disp.add_colorbar()
                disp.cmap = 'viridis'

            if len(data.r0.tels_with_data) <= 2:
                continue

            imsum[:] = 0
            for telid in data.r0.tels_with_data:
                imsum += data.r0.tel[telid].adc_sums[0]

            self.log.info("event={} ntels={} energy={}" \
                          .format(data.r0.event_id,
                                  len(data.r0.tels_with_data),
                                  data.mc.energy))
            disp.image = imsum
            plt.pause(0.1)
class MakeHistFirstCap(Tool):
    name = "make-hist-first-cap"

    infile = Unicode(help='input LST file', default="").tag(config=True)

    max_events = Integer(help='stop after this many events if non-zero',
                         default_value=0,
                         min=0).tag(config=True)

    output_suffix = Unicode(help='suffix (file extension) of output '
                            'filenames to write images '
                            'to (no writing is done if blank). '
                            'Images will be named [EVENTID][suffix]',
                            default_value="").tag(config=True)

    aliases = Dict({
        'infile': 'MakeHistFirstCap.infile',
        'max-events': 'MakeHistFirstCap.max_events',
        'output-suffix': 'MakeHistFirstCap.output_suffix'
    })

    def setup(self):
        # load LST data
        self.log.info("Read file:{}".format(self.infile))
        self.reader = LSTEventSource(input_url=self.infile,
                                     max_events=self.max_events)

    def start(self):
        fc = []
        for event in self.reader:
            fc.extend(get_first_capacitor_array(event))

        plt.figure()
        plt.hist(fc, bins=4096)
        plt.ylabel("Number")
        plt.xlabel("Stop Cell")
        plt.show()
Esempio n. 3
0
class ImageSumDisplayerTool(Tool):
    description = Unicode(__doc__)
    name = "ctapipe-display-imagesum"

    infile = Path(
        help="input simtelarray file",
        default_value=get_dataset_path("gamma_test_large.simtel.gz"),
        exists=True,
        directory_ok=False,
    ).tag(config=True)

    telgroup = Integer(help="telescope group number", default_value=1).tag(config=True)

    max_events = Integer(
        help="stop after this many events if non-zero", default_value=0, min=0
    ).tag(config=True)

    output_suffix = Unicode(
        help="suffix (file extension) of output "
        "filenames to write images "
        "to (no writing is done if blank). "
        "Images will be named [EVENTID][suffix]",
        default_value="",
    ).tag(config=True)

    aliases = Dict(
        {
            "infile": "ImageSumDisplayerTool.infile",
            "telgroup": "ImageSumDisplayerTool.telgroup",
            "max-events": "ImageSumDisplayerTool.max_events",
            "output-suffix": "ImageSumDisplayerTool.output_suffix",
        }
    )

    classes = [CameraCalibrator, SimTelEventSource]

    def setup(self):
        # load up the telescope types table (need to first open a file, a bit of
        # a hack until a proper instrument module exists) and select only the
        # telescopes with the same camera type
        # make sure gzip files are seekable

        self.reader = SimTelEventSource(
            input_url=self.infile, max_events=self.max_events, back_seekable=True
        )

        camtypes = self.reader.subarray.to_table().group_by("camera_type")
        self.reader.subarray.info(printer=self.log.info)

        group = camtypes.groups[self.telgroup]
        self._selected_tels = list(group["tel_id"].data)
        self._base_tel = self._selected_tels[0]
        self.log.info(
            "Telescope group %d: %s",
            self.telgroup,
            str(self.reader.subarray.tel[self._selected_tels[0]]),
        )
        self.log.info(f"SELECTED TELESCOPES:{self._selected_tels}")

        self.calibrator = CameraCalibrator(parent=self, subarray=self.reader.subarray)
        self.reader = SimTelEventSource(
            input_url=self.infile,
            max_events=self.max_events,
            back_seekable=True,
            allowed_tels=set(self._selected_tels),
        )

    def start(self):
        geom = None
        imsum = None
        disp = None

        for event in self.reader:

            self.calibrator(event)

            if geom is None:
                geom = self.reader.subarray.tel[self._base_tel].camera.geometry
                imsum = np.zeros(shape=geom.pix_x.shape, dtype=np.float64)
                disp = CameraDisplay(geom, title=geom.camera_name)
                disp.add_colorbar()
                disp.cmap = "viridis"

            if len(event.dl0.tel.keys()) <= 2:
                continue

            imsum[:] = 0
            for telid in event.dl0.tel.keys():
                imsum += event.dl1.tel[telid].image

            self.log.info(
                "event={} ntels={} energy={}".format(
                    event.index.event_id,
                    len(event.dl0.tel.keys()),
                    event.simulation.shower.energy,
                )
            )
            disp.image = imsum
            plt.pause(0.1)

            if self.output_suffix != "":
                filename = "{:020d}{}".format(event.index.event_id, self.output_suffix)
                self.log.info(f"saving: '{filename}'")
                plt.savefig(filename)
class SingleTelEventDisplay(Tool):
    name = "ctapipe-display-televents"
    description = Unicode(__doc__)

    infile = Unicode(help="input file to read", default='').tag(config=True)
    tel = Int(help='Telescope ID to display', default=0).tag(config=True)
    channel = Integer(help="channel number to display", min=0,
                      max=1).tag(config=True)
    write = Bool(help="Write out images to PNG files",
                 default=False).tag(config=True)
    clean = Bool(help="Apply image cleaning", default=False).tag(config=True)
    hillas = Bool(help="Apply and display Hillas parametrization",
                  default=False).tag(config=True)
    samples = Bool(help="Show each sample", default=False).tag(config=True)
    display = Bool(help="Display results in interactive window",
                   default_value=True).tag(config=True)
    delay = Float(help='delay between events in s',
                  default_value=0.01,
                  min=0.001).tag(config=True)
    progress = Bool(help='display progress bar',
                    default_value=True).tag(config=True)

    aliases = Dict({
        'infile': 'SingleTelEventDisplay.infile',
        'tel': 'SingleTelEventDisplay.tel',
        'max-events': 'EventSource.max_events',
        'channel': 'SingleTelEventDisplay.channel',
        'write': 'SingleTelEventDisplay.write',
        'clean': 'SingleTelEventDisplay.clean',
        'hillas': 'SingleTelEventDisplay.hillas',
        'samples': 'SingleTelEventDisplay.samples',
        'display': 'SingleTelEventDisplay.display',
        'delay': 'SingleTelEventDisplay.delay',
        'progress': 'SingleTelEventDisplay.progress'
    })

    classes = List([EventSource, CameraCalibrator])

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def setup(self):
        print('TOLLES INFILE', self.infile)
        self.event_source = EventSource.from_url(self.infile, parent=self)
        self.event_source.allowed_tels = {
            self.tel,
        }

        self.calibrator = CameraCalibrator(parent=self)

        self.log.info(f'SELECTING EVENTS FROM TELESCOPE {self.tel}')

    def start(self):

        disp = None

        for event in tqdm(self.event_source,
                          desc=f'Tel{self.tel}',
                          total=self.event_source.max_events,
                          disable=~self.progress):

            self.log.debug(event.trig)
            self.log.debug(f"Energy: {event.mc.energy}")

            self.calibrator(event)

            if disp is None:
                geom = event.inst.subarray.tel[self.tel].camera
                self.log.info(geom)
                disp = CameraDisplay(geom)
                # disp.enable_pixel_picker()
                disp.add_colorbar()
                if self.display:
                    plt.show(block=False)

            # display the event
            disp.axes.set_title('CT{:03d} ({}), event {:06d}'.format(
                self.tel, geom.cam_id, event.r0.event_id))

            if self.samples:
                # display time-varying event
                data = event.dl0.tel[self.tel].waveform[self.channel]
                for ii in range(data.shape[1]):
                    disp.image = data[:, ii]
                    disp.set_limits_percent(70)
                    plt.suptitle(f"Sample {ii:03d}")
                    if self.display:
                        plt.pause(self.delay)
                    if self.write:
                        plt.savefig(
                            f'CT{self.tel:03d}_EV{event.r0.event_id:10d}'
                            f'_S{ii:02d}.png')
            else:
                # display integrated event:
                im = event.dl1.tel[self.tel].image[self.channel]

                if self.clean:
                    mask = tailcuts_clean(geom,
                                          im,
                                          picture_thresh=10,
                                          boundary_thresh=7)
                    im[~mask] = 0.0

                disp.image = im

                if self.hillas:
                    try:
                        ellipses = disp.axes.findobj(Ellipse)
                        if len(ellipses) > 0:
                            ellipses[0].remove()

                        params = hillas_parameters(geom, image=im)
                        disp.overlay_moments(params,
                                             color='pink',
                                             lw=3,
                                             with_label=False)
                    except HillasParameterizationError:
                        pass

                if self.display:
                    plt.pause(self.delay)
                if self.write:
                    plt.savefig(
                        f'CT{self.tel:03d}_EV{event.r0.event_id:010d}.png')

        self.log.info("FINISHED READING DATA FILE")

        if disp is None:
            self.log.warning(
                'No events for tel {} were found in {}. Try a '
                'different EventIO file or another telescope'.format(
                    self.tel, self.infile), )
Esempio n. 5
0
class ImageSumDisplayerTool(Tool):
    description = Unicode(__doc__)
    name = "ctapipe-display-imagesum"

    infile = Unicode(
        help='input simtelarray file',
        default="/Users/kosack/Data/CTA/Prod3/gamma.simtel.gz").tag(
            config=True)

    telgroup = Integer(help='telescope group number',
                       default=1).tag(config=True)

    max_events = Integer(help='stop after this many events if non-zero',
                         default_value=0,
                         min=0).tag(config=True)

    output_suffix = Unicode(help='suffix (file extension) of output '
                            'filenames to write images '
                            'to (no writing is done if blank). '
                            'Images will be named [EVENTID][suffix]',
                            default_value="").tag(config=True)

    aliases = Dict({
        'infile': 'ImageSumDisplayerTool.infile',
        'telgroup': 'ImageSumDisplayerTool.telgroup',
        'max-events': 'ImageSumDisplayerTool.max_events',
        'output-suffix': 'ImageSumDisplayerTool.output_suffix'
    })

    classes = List([CameraCalibrator, SimTelEventSource])

    def setup(self):
        # load up the telescope types table (need to first open a file, a bit of
        # a hack until a proper insturment module exists) and select only the
        # telescopes with the same camera type
        # make sure gzip files are seekable

        self.reader = SimTelEventSource(input_url=self.infile,
                                        max_events=self.max_events,
                                        back_seekable=True)

        for event in self.reader:
            camtypes = event.inst.subarray.to_table().group_by('camera_type')
            event.inst.subarray.info(printer=self.log.info)
            break

        group = camtypes.groups[self.telgroup]
        self._selected_tels = list(group['tel_id'].data)
        self._base_tel = self._selected_tels[0]
        self.log.info("Telescope group %d: %s", self.telgroup,
                      str(event.inst.subarray.tel[self._selected_tels[0]]))
        self.log.info(f"SELECTED TELESCOPES:{self._selected_tels}")

        self.calibrator = CameraCalibrator(parent=self)

        self.reader.allowed_tels = self._selected_tels

    def start(self):
        geom = None
        imsum = None
        disp = None

        for event in self.reader:

            self.calibrator(event)

            if geom is None:
                geom = event.inst.subarray.tel[self._base_tel].camera
                imsum = np.zeros(shape=geom.pix_x.shape, dtype=np.float)
                disp = CameraDisplay(geom, title=geom.cam_id)
                disp.add_colorbar()
                disp.cmap = 'viridis'

            if len(event.dl0.tels_with_data) <= 2:
                continue

            imsum[:] = 0
            for telid in event.dl0.tels_with_data:
                imsum += event.dl1.tel[telid].image

            self.log.info("event={} ntels={} energy={}".format(
                event.r0.event_id, len(event.dl0.tels_with_data),
                event.mc.energy))
            disp.image = imsum
            plt.pause(0.1)

            if self.output_suffix is not "":
                filename = "{:020d}{}".format(event.r0.event_id,
                                              self.output_suffix)
                self.log.info(f"saving: '{filename}'")
                plt.savefig(filename)
class DRS4PedestalAndSpikeHeight(Tool):
    name = 'lstchain_create_drs4_pedestal_file'

    output_path = Path(
        directory_ok=False,
        help=
        'Path for the output hdf5 file of pedestal baseline and spike heights',
    ).tag(config=True)
    skip_samples_front = Integer(
        default_value=10,
        help='Do not include first N samples in pedestal calculation').tag(
            config=True)
    skip_samples_end = Integer(
        default_value=1,
        help='Do not include last N samples in pedestal calculation').tag(
            config=True)

    progress_bar = Bool(help="Show progress bar during processing",
                        default_value=True).tag(config=True)

    full_statistics = Bool(help=(
        "If True, write spike{1,2,3} mean, count, std for each capacitor."
        " Otherwise, only mean spike height for each gain, pixel is written"),
                           default_value=False).tag(config=True)

    overwrite = Bool(help=("If true, overwrite output without asking,"
                           " else fail if output file already exists"),
                     default_value=False).tag(config=True)

    aliases = {
        ('i', 'input'): 'LSTEventSource.input_url',
        ('o', 'output'): 'DRS4PedestalAndSpikeHeight.output_path',
        ('m', 'max-events'): 'LSTEventSource.max_events',
    }

    flags = {
        **flag(
            "overwrite",
            "DRS4PedestalAndSpikeHeight.overwrite",
            "Overwrite output file if it exists",
            "Fail if output file already exists",
        ),
        **flag(
            "progress",
            "DRS4PedestalAndSpikeHeight.progress_bar",
            "Show a progress bar during event processing",
            "Do not show a progress bar during event processing",
        ),
        **flag(
            "full-statistics",
            "DRS4PedestalAndSpikeHeight.full_statistics",
            "Whether to write the full statistics about spikes or not",
        ),
    }

    classes = [LSTEventSource]

    def setup(self):
        self.output_path = self.output_path.expanduser().resolve()
        if self.output_path.exists():
            if self.overwrite:
                self.log.warning("Overwriting %s", self.output_path)
                self.output_path.unlink()
            else:
                raise ToolConfigurationError(
                    f"Output file {self.output_path} exists"
                    ", use the `overwrite` option or choose another `output_path` "
                )
        self.log.debug("output path: %s", self.output_path)
        Provenance().add_output_file(str(self.output_path), role="DL1/Event")

        self.source = LSTEventSource(
            parent=self,
            pointing_information=False,
            trigger_information=False,
        )

        # set some config options, these are necessary for this tool,
        # so we set them here and not via the config system
        self.source.r0_r1_calibrator.r1_sample_start = 0
        self.source.r0_r1_calibrator.r1_sample_end = N_SAMPLES

        self.source.r0_r1_calibrator.offset = 0
        self.source.r0_r1_calibrator.apply_spike_correction = False
        self.source.r0_r1_calibrator.apply_timelapse_correction = True
        self.source.r0_r1_calibrator.apply_drs4_pedestal_correction = False

        n_stats = N_GAINS * N_PIXELS * N_CAPACITORS_PIXEL
        self.baseline_stats = OnlineStats(n_stats)
        self.spike0_stats = OnlineStats(n_stats)
        self.spike1_stats = OnlineStats(n_stats)
        self.spike2_stats = OnlineStats(n_stats)

    def start(self):
        tel_id = self.source.tel_id

        for event in tqdm(self.source, disable=not self.progress_bar):
            fill_stats(
                event.r1.tel[tel_id].waveform,
                self.source.r0_r1_calibrator.first_cap[tel_id],
                self.source.r0_r1_calibrator.first_cap_old[tel_id],
                self.source.r0_r1_calibrator.last_readout_time[tel_id],
                self.baseline_stats,
                self.spike0_stats,
                self.spike1_stats,
                self.spike2_stats,
                skip_samples_front=self.skip_samples_front,
                skip_samples_end=self.skip_samples_end,
            )

    def mean_spike_height(self):
        '''Calculate mean spike height for each gain, pixel'''
        shape = (N_GAINS, N_PIXELS, N_CAPACITORS_PIXEL)
        mean_baseline = self.baseline_stats.mean.reshape(shape)
        spike_heights = np.full((N_GAINS, N_PIXELS, 3),
                                np.nan,
                                dtype=np.float32)

        for i in range(3):
            stats = getattr(self, f'spike{i}_stats')
            counts = stats.counts.reshape(shape)
            spike_height = stats.mean.reshape(shape) - mean_baseline
            spike_height[counts == 0] = 0

            # np.ma does not raise an error if the weights sum to 0
            mean_height = np.ma.average(spike_height, weights=counts, axis=2)
            # convert masked array to dense, replacing invalid values with nan
            spike_heights[:, :, i] = mean_height.filled(np.nan)

        unknown_spike_heights = np.isnan(spike_heights).any(axis=2)
        n_unknown_spike_heights = np.count_nonzero(unknown_spike_heights)

        if n_unknown_spike_heights > 0:
            self.log.warning(
                f'Could not determine spike height for {n_unknown_spike_heights} channels'
            )
            self.log.warning(
                f'Gain, pixel: {np.nonzero(unknown_spike_heights)}')

            # replace any unknown pixels with the mean over the camera
            camera_mean_spike_height = np.nanmean(spike_heights, axis=(0, 1))
            self.log.warning(
                f'Using camera mean of {camera_mean_spike_height} for these pixels'
            )
            spike_heights[unknown_spike_heights] = camera_mean_spike_height

        return spike_heights

    def finish(self):
        tel_id = self.source.tel_id
        self.log.info('Writing output to %s', self.output_path)
        key = f'r1/monitoring/drs4_baseline/tel_{tel_id:03d}'

        shape = (N_GAINS, N_PIXELS, N_CAPACITORS_PIXEL)
        baseline_mean = self.baseline_stats.mean.reshape(shape)
        baseline_std = self.baseline_stats.std.reshape(shape)
        baseline_counts = self.baseline_stats.counts.reshape(shape).astype(
            np.uint16)

        n_negative = np.count_nonzero(baseline_mean < 0)
        if n_negative > 0:
            gain, pixel, capacitor = np.nonzero(baseline_mean < 0)
            self.log.critical(
                f'{n_negative} baseline values are smaller than 0')
            self.log.info("Gain | Pixel | Capacitor | Baseline ")
            for g, p, c in zip(gain, pixel, capacitor):
                self.log.info(
                    f"{g:4d} | {p:4d} | {c:9d} | {baseline_mean[g][p][c]:6.1f}"
                )

        n_small = np.count_nonzero(baseline_mean < 25)
        if n_small > 0:
            gain, pixel, capacitor = np.nonzero(baseline_mean < 25)
            self.log.warning(f'{n_small} baseline values are smaller than 25')
            self.log.info("Gain | Pixel | Capacitor | Baseline ")
            for g, p, c in zip(gain, pixel, capacitor):
                self.log.info(
                    f"{g:4d} | {p:4d} | {c:9d} | {baseline_mean[g][p][c]:6.1f}"
                )

        # Convert baseline mean and spike heights to uint16, handle missing
        # values and values smaller 0, larger maxint
        baseline_mean = convert_to_uint16(baseline_mean)
        baseline_std = convert_to_uint16(baseline_std)
        spike_height = convert_to_uint16(self.mean_spike_height())

        with HDF5TableWriter(self.output_path) as writer:
            Provenance().add_output_file(str(self.output_path))

            drs4_calibration = DRS4CalibrationContainer(
                baseline_mean=baseline_mean,
                baseline_std=baseline_std,
                baseline_counts=baseline_counts,
                spike_height=spike_height,
            )

            writer.write(key, drs4_calibration)