Пример #1
0
def test_FitGammaHillas():
    '''
    a test of the complete fit procedure on one event including:
    • tailcut cleaning
    • hillas parametrisation
    • GreatCircle creation
    • direction fit
    • position fit

    in the end, proper units in the output are asserted '''

    filename = get_dataset("gamma_test.simtel.gz")

    fit = HillasReconstructor()

    cam_geom = {}
    tel_phi = {}
    tel_theta = {}

    source = hessio_event_source(filename)

    for event in source:

        hillas_dict = {}
        for tel_id in event.dl0.tels_with_data:

            if tel_id not in cam_geom:
                cam_geom[tel_id] = CameraGeometry.guess(
                                        event.inst.pixel_pos[tel_id][0],
                                        event.inst.pixel_pos[tel_id][1],
                                        event.inst.optical_foclen[tel_id])

                tel_phi[tel_id] = event.mc.tel[tel_id].azimuth_raw * u.rad
                tel_theta[tel_id] = (np.pi/2-event.mc.tel[tel_id].altitude_raw)*u.rad

            pmt_signal = event.r0.tel[tel_id].adc_sums[0]

            mask = tailcuts_clean(cam_geom[tel_id], pmt_signal,
                                  picture_thresh=10., boundary_thresh=5.)
            pmt_signal[mask == 0] = 0

            try:
                moments = hillas_parameters(event.inst.pixel_pos[tel_id][0],
                                            event.inst.pixel_pos[tel_id][1],
                                            pmt_signal)
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2: continue

        fit_result = fit.predict(hillas_dict, event.inst, tel_phi, tel_theta)

        print(fit_result)
        fit_result.alt.to(u.deg)
        fit_result.az.to(u.deg)
        fit_result.core_x.to(u.m)
        assert fit_result.is_valid
        return
Пример #2
0
def test_tailcuts_clean_min_neighbors_1():
    """
    requiring that picture pixels have at least one neighbor above picture_thres:
    """

    # start with simple 3-pixel camera
    geom = CameraGeometry.make_rectangular(3, 1, (-1, 1))

    p = 15  # picture value
    b = 7  # boundary value

    testcases = {(p, p, 0): [True, True, False],
                 (p, 0, p): [False, False, False],
                 (p, b, p): [False, False, False],
                 (p, b, 0): [False, False, False],
                 (b, b, 0): [False, False, False],
                 (0, p, 0): [False, False, False],
                 (p, p, p): [True, True, True]}

    for image, mask in testcases.items():
        result = cleaning.tailcuts_clean(geom, np.array(image),
                                         picture_thresh=15,
                                         boundary_thresh=5,
                                         min_number_picture_neighbors=1,
                                         keep_isolated_pixels=False)
        assert (result == mask).all()
Пример #3
0
        def update(frame):

            centroid = np.random.uniform(-0.5, 0.5, size=2)
            width = np.random.uniform(0, 0.01)
            length = np.random.uniform(0, 0.03) + width
            angle = np.random.uniform(0, 360)
            intens = np.random.exponential(2) * 50
            model = toymodel.generate_2d_shower_model(centroid=centroid,
                                                      width=width,
                                                      length=length,
                                                      psi=angle * u.deg)
            image, sig, bg = toymodel.make_toymodel_shower_image(geom, model.pdf,
                                                                 intensity=intens,
                                                                 nsb_level_pe=5000)

            # alternate between cleaned and raw images
            if self._counter > 20:
                plt.suptitle("Image Cleaning ON")
                cleanmask = cleaning.tailcuts_clean(geom, image, pedvars=80)
                for ii in range(3):
                    cleaning.dilate(geom, cleanmask)
                image[cleanmask == 0] = 0  # zero noise pixels
            if self._counter >= 40:
                plt.suptitle("Image Cleaning OFF")
                self._counter = 0

            disp.image = image
            disp.set_limits_percent(100)
            self._counter += 1
Пример #4
0
def test_array_draw():
    filename = get_dataset("gamma_test.simtel.gz")
    cam_geom = {}

    source = hessio_event_source(filename, max_events=2)
    r1 = HessioR1Calibrator(None, None)
    dl0 = CameraDL0Reducer(None, None)

    calibrator = CameraDL1Calibrator(None, None)

    for event in source:
        array_pointing = SkyCoord(event.mcheader.run_array_direction[1] * u.rad,
                                  event.mcheader.run_array_direction[0] * u.rad,
                                  frame=AltAz)
        # array_view = ArrayPlotter(instrument=event.inst,
        #                          system=TiltedGroundFrame(
        # pointing_direction=array_pointing))

        hillas_dict = {}
        r1.calibrate(event)
        dl0.reduce(event)
        calibrator.calibrate(event)  # calibrate the events

        # store MC pointing direction for the array

        for tel_id in event.dl0.tels_with_data:

            pmt_signal = event.dl1.tel[tel_id].image[0]
            geom = event.inst.subarray.tel[tel_id].camera
            fl = event.inst.subarray.tel[tel_id].optics.effective_focal_length

            # Transform the pixels positions into nominal coordinates
            camera_coord = CameraFrame(x=geom.pix_x, y=geom.pix_y,
                                       z=np.zeros(geom.pix_x.shape) * u.m,
                                       focal_length=fl,
                                       rotation=90 * u.deg - geom.cam_rotation)

            nom_coord = camera_coord.transform_to(
                NominalFrame(array_direction=array_pointing,
                             pointing_direction=array_pointing))

            mask = tailcuts_clean(geom, pmt_signal,
                                  picture_thresh=10., boundary_thresh=5.)

            try:
                moments = hillas_parameters(nom_coord.x,
                                            nom_coord.y,
                                            pmt_signal * mask)
                hillas_dict[tel_id] = moments
                nom_coord = NominalPlotter(hillas_parameters=hillas_dict,
                                           draw_axes=True)
                nom_coord.draw_array()

            except HillasParameterizationError as e:
                print(e)
                continue
    def run(self, list_of_file, max_events):

        signal_place_after_clean = np.zeros(1855)
        sum_ped_ev = 0
        alive_ped_ev = 0

        for input_file in list_of_file:
            print(input_file)

            r0_r1_calibrator = LSTR0Corrections(pedestal_path=None,
                                                r1_sample_start=3,
                                                r1_sample_end=39)
            reader = LSTEventSource(input_url=input_file,
                                    max_events=max_events)
            for i, ev in enumerate(reader):
                r0_r1_calibrator.calibrate(ev)
                if i % 10000 == 0:
                    print(ev.r0.event_id)

                if ev.lst.tel[1].evt.tib_masked_trigger == 32:
                    sum_ped_ev += 1
                    self.r1_dl1_calibrator(ev)

                    img = ev.dl1.tel[1].image

                    geom = ev.inst.subarray.tel[1].camera
                    clean = tailcuts_clean(geom, img,
                                           **self.cleaning_parameters)

                    cleaned = img.copy()
                    cleaned[~clean] = 0.0

                    signal_place_after_clean[np.where(clean == True)] += 1

                    if np.sum(cleaned > 0) > 0:
                        alive_ped_ev += 1

        fig, ax = plt.subplots(figsize=(10, 8))
        geom = ev.inst.subarray.tel[1].camera

        disp0 = CameraDisplay(geom, ax=ax)
        disp0.image = signal_place_after_clean / sum_ped_ev
        disp0.add_colorbar(ax=ax,
                           label="N times signal remain after cleaning [%]")
        disp0.cmap = 'gnuplot2'
        ax.set_title("{} \n {}/{}".format(
            input_file.split("/")[-1][8:21], alive_ped_ev, sum_ped_ev),
                     fontsize=25)

        print("{}/{}".format(alive_ped_ev, sum_ped_ev))

        ax.set_xlabel(" ")
        ax.set_ylabel(" ")
        plt.tight_layout()
        plt.show()
Пример #6
0
def test_reconstruction():
    """
    a test of the complete fit procedure on one event including:
    • tailcut cleaning
    • hillas parametrisation
    • HillasPlane creation
    • direction fit
    • position fit

    in the end, proper units in the output are asserted """

    filename = get_dataset_path("gamma_test.simtel.gz")

    fit = HillasReconstructor()

    tel_azimuth = {}
    tel_altitude = {}

    source = event_source(filename)

    for event in source:

        hillas_dict = {}
        for tel_id in event.dl0.tels_with_data:

            geom = event.inst.subarray.tel[tel_id].camera
            tel_azimuth[tel_id] = event.mc.tel[tel_id].azimuth_raw * u.rad
            tel_altitude[tel_id] = event.mc.tel[tel_id].altitude_raw * u.rad

            pmt_signal = event.r0.tel[tel_id].image[0]

            mask = tailcuts_clean(geom,
                                  pmt_signal,
                                  picture_thresh=10.,
                                  boundary_thresh=5.)
            pmt_signal[mask == 0] = 0

            try:
                moments = hillas_parameters(geom, pmt_signal)
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2:
            continue

        fit_result = fit.predict(hillas_dict, event.inst, tel_azimuth,
                                 tel_altitude)

        print(fit_result)
        fit_result.alt.to(u.deg)
        fit_result.az.to(u.deg)
        fit_result.core_x.to(u.m)
        assert fit_result.is_valid
Пример #7
0
def test_tailcuts_clean_threshold_array():
    """Tests that tailcuts can also work with individual thresholds per pixel"""
    rng = np.random.default_rng(1337)
    geom = CameraGeometry.from_name("LSTCam")

    # artifical event having a "shower" and a "star" at these locations
    star_x = 0.5 * u.m
    star_y = 0.5 * u.m
    shower_x = -0.5 * u.m
    shower_y = -0.5 * u.m

    star_pixels = (
        np.sqrt((geom.pix_x - star_x) ** 2 + (geom.pix_y - star_y) ** 2) < 0.1 * u.m
    )
    shower = (
        np.sqrt((geom.pix_x - shower_x) ** 2 + (geom.pix_y - shower_y) ** 2) < 0.2 * u.m
    )

    # noise level at the star cluster is much higher than normal camera
    noise = rng.normal(3, 0.2, len(geom))
    noise[star_pixels] = rng.normal(10, 1, np.count_nonzero(star_pixels))

    # large signal at the signal location
    image = rng.poisson(noise).astype(float)
    signal = rng.normal(20, 2, np.count_nonzero(shower))
    image[shower] += signal

    picture_threshold = 3 * noise
    boundary_threshold = 1.5 * noise

    # test that normal cleaning also contains star cluster
    # and that cleaning with pixel wise values removes star cluster
    normal_cleaning = cleaning.tailcuts_clean(
        geom, image, picture_threshold.mean(), boundary_threshold.mean()
    )
    pixel_cleaning = cleaning.tailcuts_clean(
        geom, image, picture_threshold, boundary_threshold
    )

    assert np.count_nonzero(normal_cleaning & star_pixels) > 0
    assert np.count_nonzero(pixel_cleaning & star_pixels) == 0
Пример #8
0
def fit_muon(x, y, image, geom, tailcuts):
    """
    Fit the muon ring

    Parameters
    ----------
    x, y : `floats`
        Coordinates in  the TelescopeFrame
    image : `np.ndarray`
        Number of photoelectrons in each pixel
    geom : CameraGeometry
    tailcuts :`list`
        Tail cuts for image cleaning

    Returns
    -------
    muonringparam
    clean_mask: `np.ndarray`
        Mask after cleaning
    dist: `np.ndarray`
        Distance of every pixel to the center of the muon ring
    image_clean: `np.ndarray`
        Image after cleaning
    """

    fitter = MuonRingFitter(fit_method='kundu_chaudhuri')

    clean_mask = tailcuts_clean(
        geom,
        image,
        picture_thresh=tailcuts[0],
        boundary_thresh=tailcuts[1],
    )

    ring = fitter(x, y, image, clean_mask)

    max_allowed_outliers_distance = 0.4

    # Do an iterative fit removing pixels which are beyond
    # max_allowed_outliers_distance * radius of the ring
    # (along the radial direction)
    # The goal is to improve fit for good rings
    # with very few additional non-ring bright pixels.
    for _ in (0, 0):  # just to iterate the fit twice more
        dist = np.sqrt((x - ring.center_x)**2 + (y - ring.center_y)**2)
        ring_dist = np.abs(dist - ring.radius)

        clean_mask *= (ring_dist < ring.radius * max_allowed_outliers_distance)
        ring = fitter(x, y, image, clean_mask)

    image_clean = image * clean_mask
    return ring, clean_mask, dist, image_clean
Пример #9
0
def test_reconstruction():
    """
    a test of the complete fit procedure on one event including:
    • tailcut cleaning
    • hillas parametrisation
    • HillasPlane creation
    • direction fit
    • position fit

    in the end, proper units in the output are asserted """

    filename = get_dataset_path("gamma_test.simtel.gz")

    fit = HillasReconstructor()

    tel_azimuth = {}
    tel_altitude = {}

    source = EventSourceFactory.produce(input_url=filename)

    for event in source:

        hillas_dict = {}
        for tel_id in event.dl0.tels_with_data:

            geom = event.inst.subarray.tel[tel_id].camera
            tel_azimuth[tel_id] = event.mc.tel[tel_id].azimuth_raw * u.rad
            tel_altitude[tel_id] = event.mc.tel[tel_id].altitude_raw * u.rad

            pmt_signal = event.r0.tel[tel_id].image[0]

            mask = tailcuts_clean(geom, pmt_signal,
                                  picture_thresh=10., boundary_thresh=5.)
            pmt_signal[mask == 0] = 0

            try:
                moments = hillas_parameters(geom, pmt_signal)
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2:
            continue

        fit_result = fit.predict(hillas_dict, event.inst, tel_azimuth, tel_altitude)

        print(fit_result)
        fit_result.alt.to(u.deg)
        fit_result.az.to(u.deg)
        fit_result.core_x.to(u.m)
        assert fit_result.is_valid
Пример #10
0
def zero_suppression_tailcut_dilation(geom,
                                      image,
                                      number_of_dilation=3,
                                      **kwargs):
    """
    Zero suppression and tailcut cleaning with dilation.

    Parameters
    ----------
    geom: `ctapipe.instrument.CameraGeometry`
        Camera geometry information
    image: object - ndarray
        Pixel values. A `event.inst.subarray.tel[telescope_id].camera` object.
    kwargs: dict
        A dictionary containing the parameters of the selected volume reducer algorithm.
    number_of_dilation: int
        The number of times dilation will be applied to `pixel_mask`. Set by default to 3.

    Returns
    -------
    mask_0_suppression: object - ndarray
        A boolean mask (array) that contains the zero suppressed pixels.

    Notes
    -----
    `tailcut_clean` + 3 * `dilate` volume reducer method.
    Default parameters for the tailcut_clean:

        >>> 'picture_thresh': 8
        >>> 'boundary_thresh': 4
        >>> 'keep_isolated_pixels': True
        >>> 'min_number_picture_neighbors': 0
    """
    kwargs.setdefault('picture_thresh', 8)
    kwargs.setdefault('boundary_thresh', 4)
    kwargs.setdefault('keep_isolated_pixels', True)
    kwargs.setdefault('min_number_picture_neighbors', 0)

    mask_0_suppression = tailcuts_clean(
        geom,
        image,
        picture_thresh=kwargs['picture_thresh'],
        boundary_thresh=kwargs['boundary_thresh'],
        keep_isolated_pixels=kwargs['keep_isolated_pixels'],
        min_number_picture_neighbors=kwargs['min_number_picture_neighbors'])

    # Dilate pixel mask. 3 times by default
    for i in range(number_of_dilation):
        mask_0_suppression = dilate(geom, mask_0_suppression)

    return mask_0_suppression
Пример #11
0
def test_FitGammaHillas():

    filename = get_path("gamma_test.simtel.gz")

    fit = FitGammaHillas()
    fit.setup_geometry(*load_hessio(filename),
                       phi=180 * u.deg,
                       theta=20 * u.deg)

    tel_geom = {}

    source = hessio_event_source(filename)

    for event in source:

        hillas_dict = {}
        for tel_id in set(event.trig.tels_with_trigger) & set(
                event.dl0.tels_with_data):

            if tel_id not in tel_geom:
                tel_geom[tel_id] = CameraGeometry.guess(
                    fit.cameras(tel_id)['PixX'].to(u.m),
                    fit.cameras(tel_id)['PixY'].to(u.m),
                    fit.telescopes['FL'][tel_id - 1] * u.m)

            pmt_signal = event.dl0.tel[tel_id].adc_sums[0]

            mask = tailcuts_clean(tel_geom[tel_id],
                                  pmt_signal,
                                  1,
                                  picture_thresh=10.,
                                  boundary_thresh=5.)
            pmt_signal[mask is False] = 0

            try:
                moments, moms2 = hillas_parameters(
                    fit.cameras(tel_id)['PixX'],
                    fit.cameras(tel_id)['PixY'], pmt_signal)
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2: continue

        fit_result = fit.predict(hillas_dict)

        print(fit_result)
        assert fit_result
        return
    def clean_image(self,
                    input_img,
                    high_threshold=10.,
                    low_threshold=8.,
                    kill_isolated_pixels=False,
                    verbose=False,
                    cam_id=None,
                    output_data_dict=None,
                    **kwargs):
        """Apply ctapipe's tail-cut image cleaning on ``.

        """

        if cam_id is None:
            raise Exception("cam_id have to be defined")    # TODO

        # 2D ARRAY (FITS IMAGE) TO CTAPIPE IMAGE ###############

        geom_1d = geometry_converter.get_geom1d(cam_id)
        img_1d = geometry_converter.image_2d_to_1d(input_img, cam_id)

        # APPLY TAILCUT CLEANING ##############################

        mask = tailcuts_clean(geom_1d,
                              img_1d,
                              picture_thresh=high_threshold,
                              boundary_thresh=low_threshold)
        img_1d[mask == False] = 0

        # CTAPIPE IMAGE TO 2D ARRAY (FITS IMAGE) ###############

        cleaned_img_2d = geometry_converter.image_1d_to_2d(img_1d, cam_id)

        # KILL ISOLATED PIXELS #################################

        img_cleaned_islands_delta_pe, img_cleaned_islands_delta_abs_pe, img_cleaned_islands_delta_num_pixels = kill_isolated_pixels_stats(cleaned_img_2d)
        img_cleaned_num_islands = number_of_islands(cleaned_img_2d)

        if output_data_dict is not None:
            output_data_dict["img_cleaned_islands_delta_pe"] = img_cleaned_islands_delta_pe
            output_data_dict["img_cleaned_islands_delta_abs_pe"] = img_cleaned_islands_delta_abs_pe
            output_data_dict["img_cleaned_islands_delta_num_pixels"] = img_cleaned_islands_delta_num_pixels
            output_data_dict["img_cleaned_num_islands"] = img_cleaned_num_islands

        if kill_isolated_pixels:
            if verbose:
                print("Kill isolated pixels")
            cleaned_img_2d = scipy_kill_isolated_pixels(cleaned_img_2d)

        return cleaned_img_2d
Пример #13
0
 def leak(img):
     cleanmask = cleaning.tailcuts_clean(geom, img, **opts)
     mask = False
     if any(cleanmask):
         leakage_values = leakage(geom, img, cleanmask)
         if hasattr(leakage_values,
                    'leakage{}_intensity'.format(leakage_number)):
             mask = leakage_values['leakage{}_intensity'.format(
                 leakage_number)] <= leakage_value
         elif hasattr(leakage_values,
                      'intensity_width_{}'.format(leakage_number)):
             mask = leakage_values['intensity_width_{}'.format(
                 leakage_number)] <= leakage_value
     return mask
Пример #14
0
def test_tailcuts_clean():

    # start with simple 3-pixel camera
    geom = CameraGeometry.make_rectangular(3, 1, (-1, 1))

    p = 15  #picture value
    b = 7   # boundary value

    # for no isolated pixels:
    testcases = {(p, p, 0): [True, True, False],
                 (p, 0, p): [False, False, False],
                 (p, b, p): [True, True, True],
                 (p, b, 0): [True, True, False],
                 (b, b, 0): [False, False, False],
                 (0, p ,0): [False, False, False]}

    for image, mask in testcases.items():
        result = cleaning.tailcuts_clean(geom, np.array(image),
                                         picture_thresh=15,
                                         boundary_thresh=5,
                                         keep_isolated_pixels=False)
        assert (result == mask).all()

    # allowing isolated pixels
    testcases = {(p, p, 0): [True, True, False],
                 (p, 0, p): [True, False, True],
                 (p, b, p): [True, True, True],
                 (p, b, 0): [True, True, False],
                 (b, b, 0): [False, False, False],
                 (0, p, 0): [False, True, False]}

    for image, mask in testcases.items():
        result = cleaning.tailcuts_clean(geom, np.array(image),
                                         picture_thresh=15,
                                         boundary_thresh=5,
                                         keep_isolated_pixels=True)
        assert (result == mask).all()
Пример #15
0
def test_tailcuts_clean_simple():
    geom = CameraGeometry.from_name("LSTCam")
    image = np.zeros_like(geom.pix_id, dtype=np.float64)

    num_pix = 40
    some_neighs = geom.neighbors[num_pix][0:3]  # pick 3 neighbors
    image[num_pix] = 5.0  # set a single image pixel
    image[some_neighs] = 3.0  # make some boundaries that are neighbors
    image[10] = 3.0  # a boundary that is not a neighbor

    mask = cleaning.tailcuts_clean(geom, image, picture_thresh=4.5, boundary_thresh=2.5)

    assert 10 not in geom.pix_id[mask]
    assert set(some_neighs).union({num_pix}) == set(geom.pix_id[mask])
    assert np.count_nonzero(mask) == 4
Пример #16
0
def fit_muon(x, y, image, geom, tailcuts):
    """
    Fit the muon ring

    Paramenters
    ---------
    x, y:    `floats` coordinates in  the NominalFrame
    image:   `np.ndarray` number of photoelectrons in each pixel
    geom:    CameraGeometry
    image:   `list` tail cuts for image cleaning

    Returns
    ---------
    muonringparam: ``
    clean_mask:    `np.ndarray` mask after cleaning
    dist:          `np.ndarray` distance of every pixel 
                    to the center of the muon ring
    image_clean:   `np.ndarray` image after cleaning
    """

    muonring = ChaudhuriKunduRingFitter(None)
    clean_mask = tailcuts_clean(geom,
                                image,
                                picture_thresh=tailcuts[0],
                                boundary_thresh=tailcuts[1])
    image_clean = image * clean_mask
    muonringparam = muonring.fit(x, y, image_clean)

    dist = np.sqrt(
        np.power(x - muonringparam.ring_center_x, 2) +
        np.power(y - muonringparam.ring_center_y, 2))
    ring_dist = np.abs(dist - muonringparam.ring_radius)
    muonringparam = muonring.fit(
        x, y, image_clean * (ring_dist < muonringparam.ring_radius * 0.4))

    dist = np.sqrt(
        np.power(x - muonringparam.ring_center_x, 2) +
        np.power(y - muonringparam.ring_center_y, 2))
    ring_dist = np.abs(dist - muonringparam.ring_radius)

    muonringparam = muonring.fit(
        x, y, image_clean * (ring_dist < muonringparam.ring_radius * 0.4))

    return muonringparam, clean_mask, dist, image_clean
Пример #17
0
def test_tailcuts_clean_simple():
    geom = CameraGeometry.from_name("LSTCam")
    image = np.zeros_like(geom.pix_id, dtype=np.float)

    num_pix = 40
    some_neighs = geom.neighbors[num_pix][0:3]  # pick 4 neighbors
    image[num_pix] = 5.0  # set a single image pixel
    image[some_neighs] = 3.0  # make some boundaries that are neighbors
    image[10] = 3.0  # a boundary that is not a neighbor

    mask = cleaning.tailcuts_clean(geom, image, picture_thresh=4.5,
                                   boundary_thresh=2.5)

    print((mask > 0).sum(), "clean pixels")
    print(geom.pix_id[mask])

    assert 10 not in geom.pix_id[mask]
    assert set(some_neighs).union({num_pix}) == set(geom.pix_id[mask])
    assert (mask > 0).sum() == 4
Пример #18
0
def fit_muon(x, y, image, geom, tailcuts):
    """
    Fit the muon ring

    Paramenters
    ---------
    x, y:    `floats` coordinates in  the NominalFrame
    image:   `np.ndarray` number of photoelectrons in each pixel
    geom:    CameraGeometry
    image:   `list` tail cuts for image cleaning

    Returns
    ---------
    muonringparam: ``
    clean_mask:    `np.ndarray` mask after cleaning
    dist:          `np.ndarray` distance of every pixel 
                    to the center of the muon ring
    image_clean:   `np.ndarray` image after cleaning
    """

    muonring = ChaudhuriKunduRingFitter(None)
    clean_mask = tailcuts_clean(geom,
                                image,
                                picture_thresh=tailcuts[0],
                                boundary_thresh=tailcuts[1])
    image_clean = image * clean_mask
    muonringparam = muonring.fit(x, y, image_clean)

    max_allowed_outliers_distance = 0.4
    # Do an iterative fit removing pixels which are beyond max_allowed_outliers_distance*ring_radius
    # of the ring (along the radial direction):
    # The goal is to improve fit for good rings with very few additional non-ring bright pixels.

    for _ in [0] * 2:  # just to iterate the fit twice more
        dist = np.sqrt((x - muonringparam.ring_center_x)**2 +
                       (y - muonringparam.ring_center_y)**2)
        ring_dist = np.abs(dist - muonringparam.ring_radius)
        muonringparam = muonring.fit(
            x, y,
            image_clean * (ring_dist < muonringparam.ring_radius *
                           max_allowed_outliers_distance))

    return muonringparam, clean_mask, dist, image_clean
Пример #19
0
def test_FitGammaHillas():

    filename = get_path("gamma_test.simtel.gz")

    fit = FitGammaHillas()
    fit.setup_geometry(*load_hessio(filename), phi=180 * u.deg, theta=20 * u.deg)

    tel_geom = {}

    source = hessio_event_source(filename)

    for event in source:

        hillas_dict = {}
        for tel_id in set(event.trig.tels_with_trigger) & set(event.dl0.tels_with_data):

            if tel_id not in tel_geom:
                tel_geom[tel_id] = CameraGeometry.guess(
                    fit.cameras(tel_id)["PixX"].to(u.m),
                    fit.cameras(tel_id)["PixY"].to(u.m),
                    fit.telescopes["FL"][tel_id - 1] * u.m,
                )

            pmt_signal = event.dl0.tel[tel_id].adc_sums[0]

            mask = tailcuts_clean(tel_geom[tel_id], pmt_signal, 1, picture_thresh=10.0, boundary_thresh=5.0)
            pmt_signal[mask is False] = 0

            try:
                moments, moms2 = hillas_parameters(fit.cameras(tel_id)["PixX"], fit.cameras(tel_id)["PixY"], pmt_signal)
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2:
            continue

        fit_result = fit.predict(hillas_dict)

        print(fit_result)
        assert fit_result
        return
Пример #20
0
        def update(frame):

            centroid = np.random.uniform(-0.5, 0.5, size=2)
            width = np.random.uniform(0, 0.01)
            length = np.random.uniform(0, 0.03) + width
            angle = np.random.uniform(0, 360)
            intens = np.random.exponential(2) * 50
            model = toymodel.generate_2d_shower_model(centroid=centroid,
                                                      width=width,
                                                      length=length,
                                                      psi=angle * u.deg)
            image, sig, bg = toymodel.make_toymodel_shower_image(geom, model.pdf,
                                                                 intensity=intens,
                                                                 nsb_level_pe=5000)

            # alternate between cleaned and raw images
            if self._counter == self.cleanframes:
                plt.suptitle("Image Cleaning ON")
                self.imclean = True
            if self._counter == self.cleanframes*2:
                plt.suptitle("Image Cleaning OFF")
                self.imclean = False
                self._counter = 0

            if self.imclean:
                cleanmask = cleaning.tailcuts_clean(geom, image, pedvars=80)
                for ii in range(3):
                    cleaning.dilate(geom, cleanmask)
                image[cleanmask == 0] = 0  # zero noise pixels

            self.log.debug("count = {}, image sum={} max={}"
                .format(self._counter, image.sum(), image.max()))
            disp.image = image

            if self.autoscale:
                disp.set_limits_percent(95)
            else:
                disp.set_limits_minmax(-100, 4000)

            disp.axes.figure.canvas.draw()
            self._counter += 1
            return [ax,]
Пример #21
0
    def clean_tail(self, img, cam_geom):
        mask = tailcuts_clean(
            cam_geom, img,
            picture_thresh=self.tail_thresholds[cam_geom.cam_id][1],
            boundary_thresh=self.tail_thresholds[cam_geom.cam_id][0])
        if self.dilate:
            dilate(cam_geom, mask)
        img[~mask] = 0

        self.cutflow.count("tailcut cleaning")

        if "ASTRI" in cam_geom.cam_id:
            # turn into 2d to apply island cleaning
            img = astri_to_2d_array(img)

            # if set, remove all signal patches but the biggest one
            new_img = self.island_cleaning(img)

            # turn back into 1d array
            new_img = array_2d_to_astri(new_img)
            new_geom = cam_geom

        else:
            # turn into 2d to apply island cleaning
            rot_geom, rot_img = convert_geometry_hex1d_to_rect2d(
                cam_geom, img, cam_geom.cam_id)

            # if set, remove all signal patches but the biggest one
            cleaned_img = self.island_cleaning(rot_img, self.hex_neighbours_1ring)

            # turn back into 1d array
            unrot_geom, unrot_img = convert_geometry_rect2d_back_to_hexe1d(
                rot_geom, cleaned_img, cam_geom.cam_id)

            new_img = unrot_img
            new_geom = unrot_geom

        if self.cutflow.cut("edge event",
                            img=new_img, geom=new_geom):
            raise EdgeEvent

        return new_img, new_geom
Пример #22
0
    def clean_tail(self, img, cam_geom):
        mask = tailcuts_clean(
                cam_geom, img,
                picture_thresh=self.tail_thresholds[cam_geom.cam_id][1],
                boundary_thresh=self.tail_thresholds[cam_geom.cam_id][0])
        if self.dilate:
            dilate(cam_geom, mask)
        img[~mask] = 0

        self.cutflow.count("tailcut cleaning")

        if "ASTRI" in cam_geom.cam_id:
            # turn into 2d to apply island cleaning
            img = astri_to_2d_array(img)

            # if set, remove all signal patches but the biggest one
            new_img = self.island_cleaning(img)

            # turn back into 1d array
            new_img = array_2d_to_astri(new_img)
            new_geom = cam_geom

        else:
            # turn into 2d to apply island cleaning
            rot_geom, rot_img = convert_geometry_hex1d_to_rect2d(
                                    cam_geom, img, cam_geom.cam_id)

            # if set, remove all signal patches but the biggest one
            cleaned_img = self.island_cleaning(rot_img, self.hex_neighbours_1ring)

            # turn back into 1d array
            unrot_geom, unrot_img = convert_geometry_rect2d_back_to_hexe1d(
                rot_geom, cleaned_img, cam_geom.cam_id)

            new_img = unrot_img
            new_geom = unrot_geom

        if self.cutflow.cut("edge event",
                            img=new_img, geom=new_geom, rows=self.edge_width):
            raise EdgeEvent

        return new_img, new_geom
Пример #23
0
def test_tailcuts_clean():

    geom = io.CameraGeometry.from_name("HESS", 1)
    image = np.zeros_like(geom.pix_id, dtype=np.float)
    pedvar = np.ones_like(geom.pix_id, dtype=np.float)

    N = 40
    some_neighs = geom.neighbors[N][0:3]  # pick 4 neighbors
    image[N] = 5.0              # set a single image pixel
    image[some_neighs] = 3.0    # make some boundaries that are neighbors
    image[10] = 3.0             # a boundary that is not a neighbor

    mask = cleaning.tailcuts_clean(geom, image, pedvar,
                                   picture_thresh=4.5,
                                   boundary_thresh=2.5)

    print((mask > 0).sum(), "clean pixels")
    print(geom.pix_id[mask])

    assert 10 not in geom.pix_id[mask]
    assert set(some_neighs).union({N}) == set(geom.pix_id[mask])
    assert (mask > 0).sum() == 4
Пример #24
0
def test_tailcuts_clean_with_isolated_pixels():
    # start with simple 3-pixel camera
    geom = CameraGeometry.make_rectangular(3, 1, (-1, 1))

    p = 15  # picture value
    b = 7  # boundary value

    testcases = {
        (p, p, 0): [True, True, False],
        (p, 0, p): [True, False, True],
        (p, b, p): [True, True, True],
        (p, b, 0): [True, True, False],
        (0, p, 0): [False, True, False],
        (b, b, 0): [False, False, False]
    }

    for image, mask in testcases.items():
        result = cleaning.tailcuts_clean(geom,
                                         np.array(image),
                                         picture_thresh=15,
                                         boundary_thresh=5,
                                         keep_isolated_pixels=True)
        assert (result == mask).all()
Пример #25
0
def test_convert_geometry():
    filename = get_path("gamma_test.simtel.gz")

    cam_geom = {}

    source = hessio_event_source(filename)

    # testing a few images just for the sake of being thorough
    counter = 5

    for event in source:

        for tel_id in event.dl0.tels_with_data:
            if tel_id not in cam_geom:
                cam_geom[tel_id] = CameraGeometry.guess(
                    event.inst.pixel_pos[tel_id][0],
                    event.inst.pixel_pos[tel_id][1],
                    event.inst.optical_foclen[tel_id])

            # we want to test conversion of hex to rectangular pixel grid
            if cam_geom[tel_id].pix_type is not "hexagonal":
                continue

            print(tel_id, cam_geom[tel_id].pix_type)

            pmt_signal = apply_mc_calibration(
                #event.dl0.tel[tel_id].adc_samples[0],
                event.dl0.tel[tel_id].adc_sums[0],
                event.mc.tel[tel_id].dc_to_pe[0],
                event.mc.tel[tel_id].pedestal[0])

            new_geom, new_signal = convert_geometry_1d_to_2d(
                cam_geom[tel_id],
                pmt_signal,
                cam_geom[tel_id].cam_id,
                add_rot=-2)

            unrot_geom, unrot_signal = convert_geometry_back(
                new_geom,
                new_signal,
                cam_geom[tel_id].cam_id,
                event.inst.optical_foclen[tel_id],
                add_rot=4)

            # if run as main, do some plotting
            if __name__ == "__main__":
                fig = plt.figure()
                plt.style.use('seaborn-talk')

                ax1 = fig.add_subplot(131)
                disp1 = CameraDisplay(
                    cam_geom[tel_id],
                    image=np.sum(pmt_signal, axis=1)
                    if pmt_signal.shape[-1] == 25 else pmt_signal,
                    ax=ax1)
                disp1.cmap = plt.cm.hot
                disp1.add_colorbar()
                plt.title("original geometry")

                ax2 = fig.add_subplot(132)
                disp2 = CameraDisplay(
                    new_geom,
                    image=np.sum(new_signal, axis=2)
                    if new_signal.shape[-1] == 25 else new_signal,
                    ax=ax2)
                disp2.cmap = plt.cm.hot
                disp2.add_colorbar()
                plt.title("slanted geometry")

                ax3 = fig.add_subplot(133)
                disp3 = CameraDisplay(
                    unrot_geom,
                    image=np.sum(unrot_signal, axis=1)
                    if unrot_signal.shape[-1] == 25 else unrot_signal,
                    ax=ax3)
                disp3.cmap = plt.cm.hot
                disp3.add_colorbar()
                plt.title("geometry converted back to hex")

                plt.show()

            # do some tailcuts cleaning
            mask1 = tailcuts_clean(cam_geom[tel_id],
                                   pmt_signal,
                                   1,
                                   picture_thresh=10.,
                                   boundary_thresh=5.)

            mask2 = tailcuts_clean(unrot_geom,
                                   unrot_signal,
                                   1,
                                   picture_thresh=10.,
                                   boundary_thresh=5.)
            pmt_signal[mask1 == False] = 0
            unrot_signal[mask2 == False] = 0
            '''
            testing back and forth conversion on hillas parameters... '''
            try:
                moments1 = hillas_parameters(cam_geom[tel_id].pix_x,
                                             cam_geom[tel_id].pix_y,
                                             pmt_signal)

                moments2 = hillas_parameters(unrot_geom.pix_x,
                                             unrot_geom.pix_y, unrot_signal)
            except (HillasParameterizationError, AssertionError) as e:
                '''
                we don't want this test to fail because the hillas code
                threw an error '''
                print(e)
                counter -= 1
                if counter < 0:
                    return
                else:
                    continue
            '''
            test if the hillas parameters from the original geometry and the
            forth-and-back rotated geometry are close '''
            assert np.allclose([
                moments1.length.value, moments1.width.value, moments1.phi.value
            ], [
                moments2.length.value, moments2.width.value, moments2.phi.value
            ],
                               rtol=1e-2,
                               atol=1e-2)
            counter -= 1
            if counter < 0:
                return
Пример #26
0
def plot_muon_event(event, muonparams, args=None):

    if muonparams['MuonRingParams'] is not None:

        # Plot the muon event and overlay muon parameters
        fig = plt.figure(figsize=(16, 7))

        colorbar = None
        colorbar2 = None

        #for tel_id in event.dl0.tels_with_data:
        for tel_id in muonparams['TelIds']:
            idx = muonparams['TelIds'].index(tel_id)

            if not muonparams['MuonRingParams'][idx]:
                continue

            #otherwise...
            npads = 2
            # Only create two pads if there is timing information extracted
            # from the calibration
            ax1 = fig.add_subplot(1, npads, 1)
            plotter = CameraPlotter(event)
            image = event.dl1.tel[tel_id].image[0]
            geom = event.inst.subarray.tel[tel_id].camera

            tailcuts = (5., 7.)
            # Try a higher threshold for
            if geom.cam_id == 'FlashCam':
                tailcuts = (10., 12.)

            clean_mask = tailcuts_clean(geom, image,
                                        picture_thresh=tailcuts[0],
                                        boundary_thresh=tailcuts[1])

            signals = image * clean_mask

            #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y)
            muon_incl = np.sqrt(muonparams['MuonRingParams'][idx].ring_center_x**2. +
                                muonparams['MuonRingParams'][idx].ring_center_y**2.)

            muon_phi = np.arctan(muonparams['MuonRingParams'][idx].ring_center_y /
                                 muonparams['MuonRingParams'][idx].ring_center_x)

            rotr_angle = geom.pix_rotation
            # if event.inst.optical_foclen[tel_id] > 10.*u.m and
            # event.dl0.tel[tel_id].num_pixels != 1764:
            if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam':
                #print("Resetting the rotation angle")
                rotr_angle = 0. * u.deg

            # Convert to camera frame (centre & radius)
            altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az)

            ring_nominal = NominalFrame(x=muonparams['MuonRingParams'][idx].ring_center_x,
                                        y=muonparams['MuonRingParams'][idx].ring_center_y,
                                        array_direction=altaz,
                                        pointing_direction=altaz)

            # embed()
            ring_camcoord = ring_nominal.transform_to(CameraFrame(
                pointing_direction=altaz,
                focal_length=event.inst.optical_foclen[tel_id],
                rotation=rotr_angle))

            centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2)
            centroid = (ring_camcoord.x.value, ring_camcoord.y.value)

            ringrad_camcoord = muonparams['MuonRingParams'][idx].ring_radius.to(u.rad) \
                               * event.inst.optical_foclen[tel_id] * 2.  # But not FC?

            px, py = event.inst.pixel_pos[tel_id]
            flen = event.inst.optical_foclen[tel_id]
            camera_coord = CameraFrame(x=px, y=py,
                                       z=np.zeros(px.shape) * u.m,
                                       focal_length=flen,
                                       rotation=geom.pix_rotation)

            nom_coord = camera_coord.transform_to(
                NominalFrame(array_direction=altaz,
                             pointing_direction=altaz)
            )

            px = nom_coord.x.to(u.deg)
            py = nom_coord.y.to(u.deg)

            dist = np.sqrt(np.power( px - muonparams['MuonRingParams'][idx].ring_center_x, 2)
                           + np.power(py - muonparams['MuonRingParams'][idx].ring_center_y, 2))
            ring_dist = np.abs(dist - muonparams['MuonRingParams'][idx].ring_radius)
            pixRmask = ring_dist < muonparams['MuonRingParams'][idx].ring_radius * 0.4

            #if muonparams[1] is not None:
            if muonparams['MuonIntensityParams'][idx] is not None:
                signals *= muonparams['MuonIntensityParams'][idx].mask

            camera1 = plotter.draw_camera(tel_id, signals, ax1)

            cmaxmin = (max(signals) - min(signals))
            cmin = min(signals)
            if not cmin:
                cmin = 1.
            if not cmaxmin:
                cmaxmin = 1.

            cmap_charge = colors.LinearSegmentedColormap.from_list(
                'cmap_c', [(0 / cmaxmin, 'darkblue'),
                           (np.abs(cmin) / cmaxmin, 'black'),
                           (2.0 * np.abs(cmin) / cmaxmin, 'blue'),
                           (2.5 * np.abs(cmin) / cmaxmin, 'green'),
                           (1, 'yellow')]
            )
            camera1.pixels.set_cmap(cmap_charge)
            if not colorbar:
                camera1.add_colorbar(ax=ax1, label=" [photo-electrons]")
                colorbar = camera1.colorbar
            else:
                camera1.colorbar = colorbar
            camera1.update(True)

            camera1.add_ellipse(centroid, ringrad_camcoord.value,
                                ringrad_camcoord.value, 0., 0., color="red")


            if muonparams['MuonIntensityParams'][idx] is not None:
                # continue #Comment this...(should ringwidthfrac also be *0.5?)

                ringwidthfrac = muonparams['MuonIntensityParams'][idx].ring_width / muonparams['MuonRingParams'][idx].ring_radius
                ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac)
                ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac)
                camera1.add_ellipse(centroid, ringrad_inner.value,
                                     ringrad_inner.value, 0., 0.,
                                     color="magenta")
                camera1.add_ellipse(centroid, ringrad_outer.value,
                                    ringrad_outer.value, 0., 0., color="magenta")
                npads = 2
                ax2 = fig.add_subplot(1, npads, npads)
                pred = muonparams['MuonIntensityParams'][idx].prediction


                if len(pred) != np.sum(muonparams['MuonIntensityParams'][idx].mask):
                    print("Warning! Lengths do not match...len(pred)=",
                          len(pred), "len(mask)=", np.sum(muonparams['MuonIntensityParams'][idx].mask))

                # Numpy broadcasting - fill in the shape
                plotpred = np.zeros(image.shape)
                plotpred[muonparams['MuonIntensityParams'][idx].mask == True] = pred

                camera2 = plotter.draw_camera(tel_id, plotpred, ax2)

                if np.isnan(max(plotpred)) or np.isnan(min(plotpred)):
                    print("nan prediction, skipping...")
                    continue

                c2maxmin = (max(plotpred) - min(plotpred))
                if not c2maxmin:
                    c2maxmin = 1.

                c2map_charge = colors.LinearSegmentedColormap.from_list(
                    'c2map_c', [(0 / c2maxmin, 'darkblue'),
                                (np.abs(min(plotpred)) / c2maxmin, 'black'),
                                (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'),
                                (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'),
                                (1, 'yellow')]
                )
                camera2.pixels.set_cmap(c2map_charge)
                if not colorbar2:
                    camera2.add_colorbar(ax=ax2, label=" [photo-electrons]")
                    colorbar2 = camera2.colorbar
                else:
                    camera2.colorbar = colorbar2
                camera2.update(True)
                plt.pause(1.)  # make shorter


            # plt.pause(0.1)
            # if pp is not None:
            #    pp.savefig(fig)
            #fig.savefig(str(args.output_path) + "_" +
            #            str(event.dl0.event_id) + '.png')


            plt.close()
Пример #27
0
if __name__ == '__main__':

  # Prepare the camera geometry
  geom = io.CameraGeometry.from_name('hess', 1)
  disp = visualization.CameraDisplay(geom)
  disp.set_limits_minmax(0, 350)
  disp.add_colorbar()

  # make a mock shower model
  model = mock.generate_2d_shower_model(centroid=(0.2, 0.2), width=0.01, length=0.1, psi='45d')

  # generate mock image in camera for this shower model.
  image, signal, noise = mock.make_mock_shower_image(geom, model.pdf, intensity=50, nsb_level_pe=100)

  #Image cleaning
  clean_mask = tailcuts_clean(geom, image, 1, 10, 5)      #pedvars = 1 and core and boundary threshold in pe
  image[~clean_mask] = 0


  #Pixel values in the camera
  pix_x = geom.pix_x.value
  pix_y = geom.pix_y.value

  # Hillas parameters
  hillas1, hillas2 = hillas_parameters(pix_x, pix_y, image)
  print(hillas1, hillas2)

  #Overlay moments
  disp.image = image
  disp.overlay_moments(hillas1, color = 'seagreen', linewidth = 2)
  plt.show()
Пример #28
0
    pointing_azimuth = {}
    pointing_altitude = {}
    time_gradients = {}

    for telescope_id, dl1 in event.dl1.tel.items():
        camera = event.inst.subarray.tels[telescope_id].camera

        image = dl1.image[0]
        peakpos = dl1.peakpos[0]

        # cleaning
        boundary, picture, min_neighbors = cleaning_level[camera.cam_id]
        clean = tailcuts_clean(
            camera,
            image,
            boundary_thresh=boundary,
            picture_thresh=picture,
            min_number_picture_neighbors=min_neighbors
        )

        # ignore images with less than 5 pixels after cleaning
        if clean.sum() < 5:
            continue

        # image parameters
        hillas_c = hillas_parameters(camera[clean], image[clean])
        leakage_c = leakage(camera, image, clean)
        n_islands, island_ids = number_of_islands(camera, clean)

        timing_c = timing_parameters(
            camera[clean], image[clean], peakpos[clean], hillas_c
def iterate_param(possible_cleaning_levels,
                  event,
                  camera,
                  image,
                  telescope_id,
                  quality_param_list,
                  hillas_containers,
                  index=0):
    """

    iteration of the possible cleaning levels and research of the optimal through quality parameters

    Parameters
    ----------

    possible_cleaning_levels:
        array with all the possible cleaning levels chosen

    event:
        calibrated event

    camera:
        Camera geometry information

    image:
        pixel array that has to be cleaned

    telescope_id:
        unique number for the identification of a telescope

    quality_param_list:
        list of all the quality parameters of a cleaned image for all the possible cleaning levels chosen

    hillas_containers:
        dictionary with telescope IDs as key and
        HillasParametersContainer instances as values

    index:
        index of the current cleaning level chosen for the comparision

    Returns
    -------

    new_param:
        the better parameters for the given image

    """
    while index < len(possible_cleaning_levels):

        picture, boundary, min_neighbors = possible_cleaning_levels[index]

        clean = tailcuts_clean(camera,
                               image,
                               boundary_thresh=boundary,
                               picture_thresh=picture,
                               min_number_picture_neighbors=min_neighbors)

        # if the size of the clean mask is too little, we can't have a good ellipse reconstruction
        flag = verify_size_clean_mask(clean, 6)
        if flag:
            break

        cleaned_image = event.dl1.tel[telescope_id].image.copy()
        cleaned_image[~clean] = 0.0

        hillas_c = hillas_parameters(camera[clean], image[clean])
        hillas_containers[telescope_id] = hillas_c

        closest_approach = closest_approach_distance(
            hillas_containers[telescope_id])

        likelihood = likelihood_function(event, cleaned_image, telescope_id)

        num_diff_pixels = numbers_of_different_pixels(camera, event,
                                                      cleaned_image,
                                                      telescope_id, picture,
                                                      boundary, min_neighbors)

        quality_param_list.append(
            [closest_approach, likelihood, num_diff_pixels])

        index_best_parameters = optimize_param(quality_param_list, index)

        index = index + 1

    new_param = possible_cleaning_levels[index_best_parameters]

    return new_param
Пример #30
0
def test_reconstructors(reconstructors):
    """
    a test of the complete fit procedure on one event including:
    • tailcut cleaning
    • hillas parametrisation
    • HillasPlane creation
    • direction fit
    • position fit

    in the end, proper units in the output are asserted """

    filename = get_dataset_path("gamma_test_large.simtel.gz")

    source = event_source(filename, max_events=10)
    horizon_frame = AltAz()

    # record how many events were reconstructed by each reconstructor
    reconstructed_events = np.zeros((len(reconstructors)))

    for event in source:
        array_pointing = SkyCoord(az=event.mc.az,
                                  alt=event.mc.alt,
                                  frame=horizon_frame)

        hillas_dict = {}
        telescope_pointings = {}

        for tel_id in event.dl0.tels_with_data:

            geom = source.subarray.tel[tel_id].camera.geometry

            telescope_pointings[tel_id] = SkyCoord(
                alt=event.pointing.tel[tel_id].altitude,
                az=event.pointing.tel[tel_id].azimuth,
                frame=horizon_frame)
            pmt_signal = event.r0.tel[tel_id].waveform[0].sum(axis=1)

            mask = tailcuts_clean(geom,
                                  pmt_signal,
                                  picture_thresh=10.,
                                  boundary_thresh=5.)
            pmt_signal[mask == 0] = 0

            try:
                moments = hillas_parameters(geom, pmt_signal)
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2:
            continue

        for count, reco_method in enumerate(reconstructors):
            reconstructed_events[count] += 1
            reconstructor = reco_method()
            reconstructor_out = reconstructor.predict(hillas_dict,
                                                      source.subarray,
                                                      array_pointing,
                                                      telescope_pointings)

            reconstructor_out.alt.to(u.deg)
            reconstructor_out.az.to(u.deg)
            reconstructor_out.core_x.to(u.m)
            assert reconstructor_out.is_valid

    np.testing.assert_array_less(np.zeros_like(reconstructed_events),
                                 reconstructed_events)
def main():
    std_config = get_standard_config()

    if args.config_file is not None:
        config = replace_config(std_config,
                                read_configuration_file(args.config_file))
    else:
        config = std_config

    print(config['tailcut'])

    foclen = OpticsDescription.from_name('LST').equivalent_focal_length
    cam_table = Table.read(args.input_file,
                           path="instrument/telescope/camera/LSTCam")
    camera_geom = CameraGeometry.from_table(cam_table)

    dl1_container = DL1ParametersContainer()
    parameters_to_update = list(HillasParametersContainer().keys())
    parameters_to_update.extend([
        'concentration_cog',
        'concentration_core',
        'concentration_pixel',
        'leakage_intensity_width_1',
        'leakage_intensity_width_2',
        'leakage_pixels_width_1',
        'leakage_pixels_width_2',
        'n_islands',
        'intercept',
        'time_gradient',
        'n_pixels',
        'wl',
        'r',
    ])

    nodes_keys = get_dataset_keys(args.input_file)
    if args.noimage:
        nodes_keys.remove(dl1_images_lstcam_key)

    auto_merge_h5files([args.input_file],
                       args.output_file,
                       nodes_keys=nodes_keys)

    with tables.open_file(args.input_file, mode='r') as input:
        image_table = input.root[dl1_images_lstcam_key]
        with tables.open_file(args.output_file, mode='a') as output:

            params = output.root[dl1_params_lstcam_key].read()

            for ii, row in enumerate(image_table):
                if ii % 10000 == 0:
                    print(ii)
                image = row['image']
                peak_time = row['peak_time']

                signal_pixels = tailcuts_clean(camera_geom, image,
                                               **config['tailcut'])
                n_pixels = np.count_nonzero(signal_pixels)
                if n_pixels > 0:
                    num_islands, island_labels = number_of_islands(
                        camera_geom, signal_pixels)
                    n_pixels_on_island = np.bincount(
                        island_labels.astype(np.int))
                    n_pixels_on_island[
                        0] = 0  # first island is no-island and should not be considered
                    max_island_label = np.argmax(n_pixels_on_island)
                    signal_pixels[island_labels != max_island_label] = False

                    hillas = hillas_parameters(camera_geom[signal_pixels],
                                               image[signal_pixels])

                    dl1_container.fill_hillas(hillas)
                    dl1_container.set_timing_features(
                        camera_geom[signal_pixels], image[signal_pixels],
                        peak_time[signal_pixels], hillas)

                    dl1_container.set_leakage(camera_geom, image,
                                              signal_pixels)
                    dl1_container.set_concentration(camera_geom, image, hillas)
                    dl1_container.n_islands = num_islands
                    dl1_container.wl = dl1_container.width / dl1_container.length
                    dl1_container.n_pixels = n_pixels
                    width = np.rad2deg(np.arctan2(dl1_container.width, foclen))
                    length = np.rad2deg(
                        np.arctan2(dl1_container.length, foclen))
                    dl1_container.width = width
                    dl1_container.length = length
                    dl1_container.r = np.sqrt(dl1_container.x**2 +
                                              dl1_container.y**2)

                else:
                    # for consistency with r0_to_dl1.py:
                    for key in dl1_container.keys():
                        dl1_container[key] = \
                            u.Quantity(0, dl1_container.fields[key].unit)

                    dl1_container.width = u.Quantity(np.nan, u.m)
                    dl1_container.length = u.Quantity(np.nan, u.m)
                    dl1_container.wl = u.Quantity(np.nan, u.m)

            for p in parameters_to_update:
                params[ii][p] = u.Quantity(dl1_container[p]).value

            output.root[dl1_params_lstcam_key][:] = params
Пример #32
0
def analyze_muon_event(event, params=None, geom_dict=None):
    """
    Generic muon event analyzer. 

    Parameters
    ----------
    event : ctapipe dl1 event container


    Returns
    -------
    muonringparam, muonintensityparam : MuonRingParameter and MuonIntensityParameter container event

    """
    # Declare a dict to define the muon cuts (ASTRI and SCT missing)
    muon_cuts = {}

    names = ['LST:LSTCam','MST:NectarCam','MST:FlashCam','MST-SCT:SCTCam','SST-1M:DigiCam','SST-GCT:CHEC','SST-ASTRI:ASTRICam']
    TailCuts = [(5,7),(5,7),(10,12),(5,7),(5,7),(5,7),(5,7)] #10,12?
    impact = [(0.2,0.9),(0.1,0.95),(0.2,0.9),(0.2,0.9),(0.1,0.95),(0.1,0.95),(0.1,0.95)]
    ringwidth = [(0.04,0.08),(0.02,0.1),(0.01,0.1),(0.02,0.1),(0.01,0.5),(0.02,0.2),(0.02,0.2)]
    TotalPix = [1855.,1855.,1764.,11328.,1296.,2048.,2368.]#8% (or 6%) as limit
    MinPix = [148.,148.,141.,680.,104.,164.,142.]
    #Need to either convert from the pixel area in m^2 or check the camera specs
    AngPixelWidth = [0.1,0.2,0.18,0.067,0.24,0.2,0.17] #Found from TDRs (or the pixel area)
    hole_rad = []#Need to check and implement
    cam_rad = [2.26,3.96,3.87,4.,4.45,2.86,5.25]#Found from the field of view calculation
    sec_rad = [0.*u.m,0.*u.m,0.*u.m,2.7*u.m,0.*u.m,1.*u.m,1.8*u.m]
    sct = [False,False,False,True,False,True,True]


    muon_cuts = {'Name':names,'TailCuts':TailCuts,'Impact':impact,'RingWidth':ringwidth,'TotalPix':TotalPix,'MinPix':MinPix,'CamRad':cam_rad,'SecRad':sec_rad,'SCT':sct,'AngPixW':AngPixelWidth}
    #print(muon_cuts)

    muonringlist = []#[None] * len(event.dl0.tels_with_data)
    muonintensitylist = []#[None] * len(event.dl0.tels_with_data)
    tellist = []
    #for tid in event.dl0.tels_with_data:
    #    tellist.append(tid)
    muon_event_param = {'TelIds':tellist,'MuonRingParams':muonringlist,'MuonIntensityParams':muonintensitylist}
    #muonringparam = None
    #muonintensityparam = None

    for telid in event.dl0.tels_with_data:

        #print("Analysing muon event for tel",telid)
        muonringparam = None
        muonintensityparam = None
        #idx = muon_event_param['TelIds'].index(telid)

        x, y = event.inst.pixel_pos[telid]

        #image = event.dl1.tel[telid].calibrated_image
        image = event.dl1.tel[telid].image[0]

        # Get geometry
        geom = None
        if geom_dict is not None and telid in geom_dict:
            geom = geom_dict[telid]
        else:
            log.debug("[calib] Guessing camera geometry")
            geom = CameraGeometry.guess(*event.inst.pixel_pos[telid],
                                        event.inst.optical_foclen[telid])
            log.debug("[calib] Camera geometry found")
            if geom_dict is not None:
                geom_dict[telid] = geom


        teldes = event.inst.subarray.tel[telid]
        dict_index = muon_cuts['Name'].index(str(teldes))
        #print('found an index of',dict_index,'for camera',geom.cam_id)

        #tailcuts = (5.,7.)
        tailcuts = muon_cuts['TailCuts'][dict_index]

        #print("Tailcuts are",tailcuts[0],tailcuts[1])

        #rot_angle = 0.*u.deg
        #if event.inst.optical_foclen[telid] > 10.*u.m and event.dl0.tel[telid].num_pixels != 1764:
            #rot_angle = -100.14*u.deg

        clean_mask = tailcuts_clean(geom,image,picture_thresh=tailcuts[0],boundary_thresh=tailcuts[1])
        camera_coord = CameraFrame(x=x,y=y,z=np.zeros(x.shape)*u.m, focal_length = event.inst.optical_foclen[telid], rotation=geom.pix_rotation)

        #print("Camera",geom.cam_id,"focal length",event.inst.optical_foclen[telid],"rotation",geom.pix_rotation)
        #TODO: correct this hack for values over 90
        altval = event.mcheader.run_array_direction[1]
        if (altval > np.pi/2.):
            altval = np.pi/2.

        altaz = HorizonFrame(alt=altval*u.rad,az=event.mcheader.run_array_direction[0]*u.rad)
        nom_coord = camera_coord.transform_to(NominalFrame(array_direction=altaz,pointing_direction=altaz))

        
        x = nom_coord.x.to(u.deg)
        y = nom_coord.y.to(u.deg)

        img = image*clean_mask
        noise = 5.
        weight = img / (img+noise)

        muonring = ChaudhuriKunduRingFitter(None)

        #print("img:",np.sum(image),"mask:",np.sum(clean_mask), "x=",x,"y=",y)
        if not sum(img):#Nothing left after tail cuts
            continue
        muonringparam = muonring.fit(x,y,image*clean_mask)
        #muonringparam = muonring.fit(x,y,weight)
        dist = np.sqrt(np.power(x-muonringparam.ring_center_x,2) + np.power(y-muonringparam.ring_center_y,2))
        ring_dist = np.abs(dist-muonringparam.ring_radius)
        muonringparam = muonring.fit(x,y,img*(ring_dist<muonringparam.ring_radius*0.4))

        dist = np.sqrt(np.power(x-muonringparam.ring_center_x,2) + np.power(y-muonringparam.ring_center_y,2))
        ring_dist = np.abs(dist-muonringparam.ring_radius)

        #print("1: x",muonringparam.ring_center_x,"y",muonringparam.ring_center_y,"radius",muonringparam.ring_radius)
        muonringparam = muonring.fit(x,y,img*(ring_dist<muonringparam.ring_radius*0.4))
        #print("2: x",muonringparam.ring_center_x,"y",muonringparam.ring_center_y,"radius",muonringparam.ring_radius)
        muonringparam.tel_id = telid
        muonringparam.run_id = event.dl0.run_id
        muonringparam.event_id = event.dl0.event_id
        dist_mask = np.abs(dist-muonringparam.ring_radius)<muonringparam.ring_radius*0.4

        rad = list()
        cx = list()
        cy = list()
        
        mc_x = event.mc.core_x
        mc_y = event.mc.core_y
        pix_im = image*dist_mask
        nom_dist = np.sqrt(np.power(muonringparam.ring_center_x,2)+np.power(muonringparam.ring_center_y,2))
        #numpix = event.dl0.tel[telid].num_pixels

        minpix = muon_cuts['MinPix'][dict_index]#0.06*numpix #or 8%

        mir_rad = np.sqrt(event.inst.mirror_dish_area[telid]/(np.pi))#need to consider units? (what about hole? Area is then less...)


        #Camera containment radius -  better than nothing - guess pixel diameter of 0.11, all cameras are perfectly circular   cam_rad = np.sqrt(numpix*0.11/(2.*np.pi))

        if(np.sum(pix_im>tailcuts[0])>0.1*minpix and np.sum(pix_im)>minpix and nom_dist < muon_cuts['CamRad'][dict_index]*u.deg and muonringparam.ring_radius<1.5*u.deg and muonringparam.ring_radius>1.*u.deg):

            #Guess HESS is 0.16 
            #sec_rad = 0.*u.m
            #sct = False
            #if numpix == 2048 and mir_rad > 2.*u.m and mir_rad < 2.1*u.m:
            #    sec_rad = 1.*u.m
            #    sct = True

            #Store muon ring parameters (passing cuts stage 1)
            #muonringlist[idx] = muonringparam
            tellist.append(telid)
            muonringlist.append(muonringparam)
            muonintensitylist.append(None)
            #embed()

            ctel = MuonLineIntegrate(mir_rad,0.2*u.m,pixel_width=muon_cuts['AngPixW'][dict_index]*u.deg,sct_flag=muon_cuts['SCT'][dict_index], secondary_radius=muon_cuts['SecRad'][dict_index])
          
            if (image.shape[0] == muon_cuts['TotalPix'][dict_index]):
                muonintensityoutput = ctel.fit_muon(muonringparam.ring_center_x,muonringparam.ring_center_y,muonringparam.ring_radius,x[dist_mask],y[dist_mask],image[dist_mask])

                muonintensityoutput.tel_id = telid
                muonintensityoutput.run_id = event.dl0.run_id
                muonintensityoutput.event_id = event.dl0.event_id
                muonintensityoutput.mask = dist_mask

                print("Tel",telid,"Impact parameter = ",muonintensityoutput.impact_parameter,"mir_rad",mir_rad,"ring_width=",muonintensityoutput.ring_width)

                #if(muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][1]*mir_rad or muonintensityoutput.impact_parameter < muon_cuts['Impact'][dict_index][0]*mir_rad):
                #    print("Failed on impact parameter low cut",muon_cuts['Impact'][dict_index][0]*mir_rad,"high cut",muon_cuts['Impact'][dict_index][1]*mir_rad,"for",geom.cam_id)
                #if(muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][1]*u.deg or muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][0]*u.deg):
                #    print("Failed on ring width low cut",muon_cuts['RingWidth'][dict_index][0]*u.deg,"high cut",muon_cuts['RingWidth'][dict_index][1]*u.deg,"for ",geom.cam_id)

                #print("Cuts <",muon_cuts["Impact"][dict_index][1]*mir_rad,"cuts >",muon_cuts['Impact'][dict_index][0]*u.m,'ring_width < ',muon_cuts['RingWidth'][dict_index][1]*u.deg,'ring_width >',muon_cuts['RingWidth'][dict_index][0]*u.deg)
                if( muonintensityoutput.impact_parameter < muon_cuts['Impact'][dict_index][1]*mir_rad and muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][0]*u.m and muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][1]*u.deg and muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][0]*u.deg ):
                    muonintensityparam = muonintensityoutput
                    idx = tellist.index(telid)
                    muonintensitylist[idx] = muonintensityparam
                    print("Muon in tel",telid,"# tels in event=",len(event.dl0.tels_with_data))
                else:
                    continue

        #print("Fitted ring centre (2):",muonringparam.ring_center_x,muonringparam.ring_center_y)

    #return muonringparam, muonintensityparam
    return muon_event_param
def process_event(event, config):
    '''
    Processes
    '''

    reco_algorithm = config.reco_algorithm
    features = {}
    params = {}

    pointing_azimuth = {}
    pointing_altitude = {}

    tel_x = {}
    tel_y = {}
    tel_focal_lengths = {}
    cleaning_method = config.cleaning_method
    valid_cleaning_methods = ['tailcuts_clean', 'fact_image_cleaning']
    if cleaning_method not in valid_cleaning_methods:
        print('Cleaning Method not implemented')
        print('Please use one of ', valid_cleaning_methods)
        return None

    for telescope_id, dl1 in event.dl1.tel.items():
        camera = event.inst.subarray.tels[telescope_id].camera
        if camera.cam_id not in config.allowed_cameras:
            continue

        telescope_type_name = event.inst.subarray.tels[
            telescope_id].optics.tel_type

        if cleaning_method == 'tailcuts_clean':
            boundary_thresh, picture_thresh, min_number_picture_neighbors = config.cleaning_level[
                camera.cam_id]
            mask = tailcuts_clean(camera, dl1.image[0],
                                  *config.cleaning_level[camera.cam_id])

        elif cleaning_method == 'fact_image_cleaning':
            mask = fact_image_cleaning(
                camera, dl1.image[0],
                *config.cleaning_level_fact[camera.cam_id])

        try:
            cleaned = dl1.image[0].copy()
            cleaned[~mask] = 0
            hillas_container = hillas_parameters(
                camera,
                cleaned,
            )
            params[telescope_id] = hillas_container
        except HillasParameterizationError:
            continue
        # probably wise to add try...except blocks here as well
        # Add more Features here (look what ctapipe can do, timing?)
        num_islands, island_labels = number_of_islands(camera, mask)
        island_dict = {
            'num_islands': num_islands,
            'island_labels': island_labels
        }
        leakage_container = leakage(camera, dl1.image[0], mask)
        timing_container = timing_parameters(camera, dl1.image[0],
                                             dl1.peakpos[0], hillas_container)

        pointing_azimuth[
            telescope_id] = event.mc.tel[telescope_id].azimuth_raw * u.rad
        pointing_altitude[
            telescope_id] = event.mc.tel[telescope_id].altitude_raw * u.rad
        tel_x[telescope_id] = event.inst.subarray.positions[telescope_id][0]
        tel_y[telescope_id] = event.inst.subarray.positions[telescope_id][1]

        telescope_description = event.inst.subarray.tel[telescope_id]
        tel_focal_lengths[
            telescope_id] = telescope_description.optics.equivalent_focal_length

        d = {
            'array_event_id': event.dl0.event_id,
            'telescope_id': int(telescope_id),
            'camera_name': camera.cam_id,
            'camera_id': config.names_to_id[camera.cam_id],
            'run_id': event.r0.obs_id,
            'telescope_type_name': telescope_type_name,
            'telescope_type_id': config.types_to_id[telescope_type_name],
            'pointing_azimuth': event.mc.tel[telescope_id].azimuth_raw,
            'pointing_altitude': event.mc.tel[telescope_id].altitude_raw,
            'mirror_area': telescope_description.optics.mirror_area,
            'focal_length':
            telescope_description.optics.equivalent_focal_length,
        }

        d.update(hillas_container.as_dict())
        d.update(leakage_container.as_dict())
        d.update(island_dict)
        d.update(timing_container.as_dict())

        features[telescope_id] = ({k: strip_unit(v) for k, v in d.items()})

    if reco_algorithm == 'intersection':
        reco = HillasIntersection()
        array_direction = SkyCoord(alt=event.mcheader.run_array_direction[1],
                                   az=event.mcheader.run_array_direction[0],
                                   frame='altaz')
        reconstruction = reco.predict(params, tel_x, tel_y, tel_focal_lengths,
                                      array_direction)
    elif reco_algorithm == 'planes':
        reco = HillasReconstructor()
        reconstruction = reco.predict(params, event.inst, pointing_altitude,
                                      pointing_azimuth)

    for telescope_id in event.dl1.tel.keys():
        if telescope_id not in params:
            continue
        camera = event.inst.subarray.tels[telescope_id].camera
        if camera.cam_id not in config.allowed_cameras:
            continue

        pos = event.inst.subarray.positions[telescope_id]
        x, y = pos[0], pos[1]
        core_x = reconstruction.core_x
        core_y = reconstruction.core_y
        d = np.sqrt((core_x - x)**2 + (core_y - y)**2)
        features[telescope_id]['distance_to_core'] = d.value

    return pd.DataFrame(list(features.values())), reconstruction, params
def test_reconstruction():
    """
    a test of the complete fit procedure on one event including:
    • tailcut cleaning
    • hillas parametrisation
    • HillasPlane creation
    • direction fit
    • position fit

    in the end, proper units in the output are asserted """
    filename = get_dataset_path("gamma_test_large.simtel.gz")

    source = EventSource(filename, max_events=10)
    calib = CameraCalibrator(subarray=source.subarray)

    horizon_frame = AltAz()

    reconstructed_events = 0

    for event in source:
        calib(event)

        mc = event.simulation.shower
        array_pointing = SkyCoord(az=mc.az, alt=mc.alt, frame=horizon_frame)
        hillas_dict = {}
        telescope_pointings = {}
        for tel_id, dl1 in event.dl1.tel.items():

            geom = source.subarray.tel[tel_id].camera.geometry

            telescope_pointings[tel_id] = SkyCoord(
                alt=event.pointing.tel[tel_id].altitude,
                az=event.pointing.tel[tel_id].azimuth,
                frame=horizon_frame,
            )
            mask = tailcuts_clean(geom,
                                  dl1.image,
                                  picture_thresh=10.0,
                                  boundary_thresh=5.0)

            try:
                moments = hillas_parameters(geom[mask], dl1.image[mask])
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2:
            continue
        else:
            reconstructed_events += 1

        # The three reconstructions below gives the same results
        fit = HillasReconstructor()
        fit_result_parall = fit.predict(hillas_dict, source.subarray,
                                        array_pointing)

        fit = HillasReconstructor()
        fit_result_tel_point = fit.predict(hillas_dict, source.subarray,
                                           array_pointing, telescope_pointings)

        for key in fit_result_parall.keys():
            print(key, fit_result_parall[key], fit_result_tel_point[key])

        fit_result_parall.alt.to(u.deg)
        fit_result_parall.az.to(u.deg)
        fit_result_parall.core_x.to(u.m)
        assert fit_result_parall.is_valid

    assert reconstructed_events > 0
def test_invalid_events():
    """
    The HillasReconstructor is supposed to fail
    in these cases:
    - less than two teleskopes
    - any width is NaN
    - any width is 0

    This test uses the same sample simtel file as 
    test_reconstruction(). As there are no invalid events in this
    file, multiple hillas_dicts are constructed to make sure 
    Exceptions get thrown in the mentioned edge cases.

    Test will fail if no Exception or another Exception gets thrown."""

    filename = get_dataset_path("gamma_test_large.simtel.gz")

    fit = HillasReconstructor()

    tel_azimuth = {}
    tel_altitude = {}

    source = EventSource(filename, max_events=10)
    subarray = source.subarray
    calib = CameraCalibrator(subarray)

    for event in source:
        calib(event)

        hillas_dict = {}
        for tel_id, dl1 in event.dl1.tel.items():

            geom = source.subarray.tel[tel_id].camera.geometry
            tel_azimuth[tel_id] = event.pointing.tel[tel_id].azimuth
            tel_altitude[tel_id] = event.pointing.tel[tel_id].altitude

            mask = tailcuts_clean(geom,
                                  dl1.image,
                                  picture_thresh=10.0,
                                  boundary_thresh=5.0)

            try:
                moments = hillas_parameters(geom[mask], dl1.image[mask])
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                continue

        # construct a dict only containing the last telescope events
        # (#telescopes < 2)
        hillas_dict_only_one_tel = dict()
        hillas_dict_only_one_tel[tel_id] = hillas_dict[tel_id]
        with pytest.raises(TooFewTelescopesException):
            fit.predict(hillas_dict_only_one_tel, subarray, tel_azimuth,
                        tel_altitude)

        # construct a hillas dict with the width of the last event set to 0
        # (any width == 0)
        hillas_dict_zero_width = hillas_dict.copy()
        hillas_dict_zero_width[tel_id]["width"] = 0 * u.m
        with pytest.raises(InvalidWidthException):
            fit.predict(hillas_dict_zero_width, subarray, tel_azimuth,
                        tel_altitude)

        # construct a hillas dict with the width of the last event set to np.nan
        # (any width == nan)
        hillas_dict_nan_width = hillas_dict.copy()
        hillas_dict_zero_width[tel_id]["width"] = np.nan * u.m
        with pytest.raises(InvalidWidthException):
            fit.predict(hillas_dict_nan_width, subarray, tel_azimuth,
                        tel_altitude)
Пример #36
0
def test_reconstructors(reconstructors):
    """
    a test of the complete fit procedure on one event including:
    • tailcut cleaning
    • hillas parametrisation
    • HillasPlane creation
    • direction fit
    • position fit

    in the end, proper units in the output are asserted"""

    filename = get_dataset_path(
        "gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz")

    source = EventSource(filename, max_events=10)
    subarray = source.subarray
    calib = CameraCalibrator(source.subarray)
    horizon_frame = AltAz()

    for event in source:
        calib(event)
        sim_shower = event.simulation.shower
        array_pointing = SkyCoord(az=sim_shower.az,
                                  alt=sim_shower.alt,
                                  frame=horizon_frame)

        telescope_pointings = {}

        for tel_id, dl1 in event.dl1.tel.items():

            geom = source.subarray.tel[tel_id].camera.geometry

            telescope_pointings[tel_id] = SkyCoord(
                alt=event.pointing.tel[tel_id].altitude,
                az=event.pointing.tel[tel_id].azimuth,
                frame=horizon_frame,
            )
            mask = tailcuts_clean(geom,
                                  dl1.image,
                                  picture_thresh=10.0,
                                  boundary_thresh=5.0)

            dl1.parameters = ImageParametersContainer()

            try:
                moments = hillas_parameters(geom[mask], dl1.image[mask])
            except HillasParameterizationError:
                dl1.parameters.hillas = HillasParametersContainer()
                continue

            # Make sure we provide only good images for the test
            if np.isnan(moments.width.value) or (moments.width.value == 0):
                dl1.parameters.hillas = HillasParametersContainer()
            else:
                dl1.parameters.hillas = moments

        hillas_dict = {
            tel_id: dl1.parameters.hillas
            for tel_id, dl1 in event.dl1.tel.items()
            if np.isfinite(dl1.parameters.hillas.intensity)
        }
        if len(hillas_dict) < 2:
            continue

        for count, reco_method in enumerate(reconstructors):
            if reco_method is HillasReconstructor:
                reconstructor = HillasReconstructor(subarray)

                reconstructor(event)

                event.dl2.stereo.geometry["HillasReconstructor"].alt.to(u.deg)
                event.dl2.stereo.geometry["HillasReconstructor"].az.to(u.deg)
                event.dl2.stereo.geometry["HillasReconstructor"].core_x.to(u.m)
                assert event.dl2.stereo.geometry[
                    "HillasReconstructor"].is_valid

            else:
                reconstructor = reco_method()

                try:
                    reconstructor_out = reconstructor.predict(
                        hillas_dict,
                        source.subarray,
                        array_pointing,
                        telescope_pointings,
                    )
                except InvalidWidthException:
                    continue

                reconstructor_out.alt.to(u.deg)
                reconstructor_out.az.to(u.deg)
                reconstructor_out.core_x.to(u.m)
                assert reconstructor_out.is_valid
Пример #37
0
def display_event(event, calibrate = 0, max_tel = 4, cleaning=None):
    """an extremely inefficient display. It creates new instances of
    CameraDisplay for every event and every camera, and also new axes
    for each event. It's hacked, but it works
    """
    print("Displaying... please wait (this is an inefficient implementation)")
    global fig
    ntels = min(max_tel, len(event.dl0.tels_with_data))
    fig.clear()

    plt.suptitle("EVENT {}".format(event.dl0.event_id))

    disps = []

    mc_sum = None
    all_moments = []

    for ii, tel_id in enumerate(event.dl0.tels_with_data):
        if ii >= max_tel: break
        print("\t draw cam {}...".format(tel_id))
        nn = int(ceil((ntels)**.5))
        ax = plt.subplot(nn, 2*nn, 2*(ii+1)-1)

        x, y = event.inst.pixel_pos[tel_id]
        geom = io.CameraGeometry.guess(x, y, event.inst.optical_foclen[tel_id])
        disp = visualization.CameraDisplay(geom, ax=ax,
                                           title="CT{0} DetectorResponse".format(tel_id))

        disp.pixels.set_antialiaseds(False)
        disp.autoupdate = False
        disp.cmap = plt.cm.hot
        chan = 0
        signals = event.dl0.tel[tel_id].adc_sums[chan].astype(float)[:]
        if calibrate:
            signals = apply_mc_calibration_ASTRI(event.dl0.tel[tel_id].adc_sums, tel_id)
        if cleaning == 'tailcut':
            mask = tailcuts_clean(geom, signals, 1,picture_thresh=10.,boundary_thresh=8.)
            dilate(geom, mask)
            signals[mask==False] = 0

        moments = hillas_parameters_2(geom.pix_x,
                                      geom.pix_y,
                                      signals)

        disp.image = signals
        disp.overlay_moments(moments, color='seagreen', linewidth=3)
        disp.set_limits_percent(95)
        disp.add_colorbar()
        disps.append(disp)


        ax = plt.subplot(nn, 2*nn, 2*(ii+1))

        geom = io.CameraGeometry.guess(x, y, event.inst.optical_foclen[tel_id])
        disp = visualization.CameraDisplay(geom, ax=ax,
                                           title="CT{0} PhotoElectrons".format(tel_id))
        disp.pixels.set_antialiaseds(False)
        disp.autoupdate = False
        disp.cmap = plt.cm.hot
        chan = 0


        #print (event.mc.tel[tel_id].photo_electrons)
        for jj in range(len(event.mc.tel[tel_id].photo_electron_image)):
            event.dl0.tel[tel_id].adc_sums[chan][jj] = event.mc.tel[tel_id].photo_electron_image[jj]
        signals2 = event.dl0.tel[tel_id].adc_sums[chan].astype(float)
        moments2 = hillas_parameters_2(geom.pix_x,
                                       geom.pix_y,
                                       signals2)
        all_moments.append(moments2)
        if mc_sum is None:
            mc_sum = signals2
        else:
            scale = 3 if tel_id == 37 else 1
            for i, val in enumerate(signals2):
                mc_sum[i] += val/scale

        disp.image = mc_sum
        for moments2 in all_moments:
            disp.overlay_moments(moments2, color='seagreen', linewidth=2)
        disp.set_limits_percent(95)
        disp.add_colorbar()
        disps.append(disp)


    return disps
Пример #38
0
def analyze_muon_event(event):
    """
    Generic muon event analyzer.

    Parameters
    ----------
    event : ctapipe dl1 event container


    Returns
    -------
    muonringparam, muonintensityparam : MuonRingParameter
    and MuonIntensityParameter container event

    """

    names = ['LST:LSTCam', 'MST:NectarCam', 'MST:FlashCam', 'MST-SCT:SCTCam',
             'SST-1M:DigiCam', 'SST-GCT:CHEC', 'SST-ASTRI:ASTRICam', 'SST-ASTRI:CHEC']
    tail_cuts = [(5, 7), (5, 7), (10, 12), (5, 7),
                (5, 7), (5, 7), (5, 7), (5, 7)]  # 10, 12?
    impact = [(0.2, 0.9), (0.1, 0.95), (0.2, 0.9), (0.2, 0.9),
              (0.1, 0.95), (0.1, 0.95), (0.1, 0.95), (0.1, 0.95)] * u.m
    ringwidth = [(0.04, 0.08), (0.02, 0.1), (0.01, 0.1), (0.02, 0.1),
                 (0.01, 0.5), (0.02, 0.2), (0.02, 0.2), (0.02, 0.2)] * u.deg
    total_pix = [1855., 1855., 1764., 11328., 1296., 2048., 2368., 2048]
    # 8% (or 6%) as limit
    min_pix = [148., 148., 141., 680., 104., 164., 142., 164]
    # Need to either convert from the pixel area in m^2 or check the camera specs
    ang_pixel_width = [0.1, 0.2, 0.18, 0.067, 0.24, 0.2, 0.17, 0.2, 0.163] * u.deg
    # Found from TDRs (or the pixel area)
    hole_rad = [0.308 * u.m, 0.244 * u.m, 0.244 * u.m,
                4.3866 * u.m, 0.160 * u.m, 0.130 * u.m,
                0.171 * u.m, 0.171 * u.m]  # Assuming approximately spherical hole
    cam_rad = [2.26, 3.96, 3.87, 4., 4.45, 2.86, 5.25, 2.86] * u.deg
    # Above found from the field of view calculation
    sec_rad = [0. * u.m, 0. * u.m, 0. * u.m, 2.7 * u.m,
               0. * u.m, 1. * u.m, 1.8 * u.m, 1.8 * u.m]
    sct = [False, False, False, True, False, True, True, True]
    # Added cleaning here. All these options should go to an input card
    cleaning = True

    muon_cuts = {'Name': names, 'tail_cuts': tail_cuts, 'Impact': impact,
                 'RingWidth': ringwidth, 'total_pix': total_pix,
                 'min_pix': min_pix, 'CamRad': cam_rad, 'SecRad': sec_rad,
                 'SCT': sct, 'AngPixW': ang_pixel_width, 'HoleRad': hole_rad}
    logger.debug(muon_cuts)

    muonringlist = []  # [None] * len(event.dl0.tels_with_data)
    muonintensitylist = []  # [None] * len(event.dl0.tels_with_data)
    tellist = []
    muon_event_param = {'TelIds': tellist,
                        'MuonRingParams': muonringlist,
                        'MuonIntensityParams': muonintensitylist}

    for telid in event.dl0.tels_with_data:

        logger.debug("Analysing muon event for tel %d", telid)
        image = event.dl1.tel[telid].image[0]

        # Get geometry
        teldes = event.inst.subarray.tel[telid]
        geom = teldes.camera
        x, y = geom.pix_x, geom.pix_y

        dict_index = muon_cuts['Name'].index(str(teldes))
        logger.debug('found an index of %d for camera %d',
                     dict_index, geom.cam_id)

        tailcuts = muon_cuts['tail_cuts'][dict_index]
        logger.debug("Tailcuts are %s", tailcuts)

        clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0],
                                    boundary_thresh=tailcuts[1])

        # TODO: correct this hack for values over 90
        altval = event.mcheader.run_array_direction[1]
        if altval > Angle(90, unit=u.deg):
            warnings.warn('Altitude over 90 degrees')
            altval = Angle(90, unit=u.deg)

        telescope_pointing = SkyCoord(
            alt=altval,
            az=event.mcheader.run_array_direction[0],
            frame=HorizonFrame()
        )
        camera_coord = SkyCoord(
            x=x, y=y,
            frame=CameraFrame(
                focal_length=teldes.optics.equivalent_focal_length,
                rotation=geom.pix_rotation,
                telescope_pointing=telescope_pointing,
            )
        )

        nom_coord = camera_coord.transform_to(
            NominalFrame(origin=telescope_pointing)
        )
        x = nom_coord.delta_az.to(u.deg)
        y = nom_coord.delta_alt.to(u.deg)

        if(cleaning):
            img = image * clean_mask
        else:
            img = image

        muonring = ChaudhuriKunduRingFitter(None)

        logger.debug("img: %s mask: %s, x=%s y= %s", np.sum(image),
                     np.sum(clean_mask), x, y)

        if not sum(img):  # Nothing left after tail cuts
            continue

        muonringparam = muonring.fit(x, y, image * clean_mask)

        dist = np.sqrt(np.power(x - muonringparam. ring_center_x, 2)
                       + np.power(y - muonringparam.ring_center_y, 2))
        ring_dist = np.abs(dist - muonringparam.ring_radius)

        muonringparam = muonring.fit(
            x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)
        )

        dist = np.sqrt(np.power(x - muonringparam.ring_center_x, 2) +
                       np.power(y - muonringparam.ring_center_y, 2))
        ring_dist = np.abs(dist - muonringparam.ring_radius)

        muonringparam = muonring.fit(
            x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)
        )

        muonringparam.tel_id = telid
        muonringparam.obs_id = event.dl0.obs_id
        muonringparam.event_id = event.dl0.event_id
        dist_mask = np.abs(dist - muonringparam.
                           ring_radius) < muonringparam.ring_radius * 0.4
        pix_im = image * dist_mask
        nom_dist = np.sqrt(np.power(muonringparam.ring_center_x,
                                    2) + np.power(muonringparam.ring_center_y, 2))

        minpix = muon_cuts['min_pix'][dict_index]  # 0.06*numpix #or 8%

        mir_rad = np.sqrt(teldes.optics.mirror_area.to("m2") / np.pi)

        # Camera containment radius -  better than nothing - guess pixel
        # diameter of 0.11, all cameras are perfectly circular   cam_rad =
        # np.sqrt(numpix*0.11/(2.*np.pi))

        if(npix_above_threshold(pix_im, tailcuts[0]) > 0.1 * minpix
           and npix_composing_ring(pix_im) > minpix
           and nom_dist < muon_cuts['CamRad'][dict_index]
           and muonringparam.ring_radius < 1.5 * u.deg
           and muonringparam.ring_radius > 1. * u.deg):
            muonringparam.ring_containment = ring_containment(
                muonringparam.ring_radius,
                muon_cuts['CamRad'][dict_index],
                muonringparam.ring_center_x,
                muonringparam.ring_center_y)

            # Guess HESS is 0.16
            # sec_rad = 0.*u.m
            # sct = False
            # if numpix == 2048 and mir_rad > 2.*u.m and mir_rad < 2.1*u.m:
            #     sec_rad = 1.*u.m
            #     sct = True
            #
            # Store muon ring parameters (passing cuts stage 1)
            # muonringlist[idx] = muonringparam

            tellist.append(telid)
            muonringlist.append(muonringparam)
            muonintensitylist.append(None)

            ctel = MuonLineIntegrate(
                mir_rad, hole_radius=muon_cuts['HoleRad'][dict_index],
                pixel_width=muon_cuts['AngPixW'][dict_index],
                sct_flag=muon_cuts['SCT'][dict_index],
                secondary_radius=muon_cuts['SecRad'][dict_index]
            )

            if image.shape[0] == muon_cuts['total_pix'][dict_index]:
                muonintensityoutput = ctel.fit_muon(muonringparam.ring_center_x,
                                                    muonringparam.ring_center_y,
                                                    muonringparam.ring_radius,
                                                    x[dist_mask], y[dist_mask],
                                                    image[dist_mask])

                muonintensityoutput.tel_id = telid
                muonintensityoutput.obs_id = event.dl0.obs_id
                muonintensityoutput.event_id = event.dl0.event_id
                muonintensityoutput.mask = dist_mask

                idx_ring = np.nonzero(pix_im)
                muonintensityoutput.ring_completeness = ring_completeness(
                    x[idx_ring], y[idx_ring], pix_im[idx_ring],
                    muonringparam.ring_radius,
                    muonringparam.ring_center_x,
                    muonringparam.ring_center_y,
                    threshold=30,
                    bins=30)
                muonintensityoutput.ring_size = np.sum(pix_im)

                dist_ringwidth_mask = np.abs(dist - muonringparam.ring_radius
                                             ) < (muonintensityoutput.ring_width)
                pix_ringwidth_im = image * dist_ringwidth_mask
                idx_ringwidth = np.nonzero(pix_ringwidth_im)

                muonintensityoutput.ring_pix_completeness = npix_above_threshold(
                    pix_ringwidth_im[idx_ringwidth], tailcuts[0]) / len(
                    pix_im[idx_ringwidth])

                logger.debug("Tel %d Impact parameter = %s mir_rad=%s "
                             "ring_width=%s", telid,
                             muonintensityoutput.impact_parameter, mir_rad,
                             muonintensityoutput.ring_width)
                conditions = [
                    muonintensityoutput.impact_parameter * u.m <
                    muon_cuts['Impact'][dict_index][1] * mir_rad,

                    muonintensityoutput.impact_parameter
                    > muon_cuts['Impact'][dict_index][0],

                    muonintensityoutput.ring_width
                    < muon_cuts['RingWidth'][dict_index][1],

                    muonintensityoutput.ring_width
                    > muon_cuts['RingWidth'][dict_index][0]
                ]

                if all(conditions):
                    muonintensityparam = muonintensityoutput
                    idx = tellist.index(telid)
                    muonintensitylist[idx] = muonintensityparam
                    logger.debug("Muon found in tel %d,  tels in event=%d",
                                 telid, len(event.dl0.tels_with_data))
                else:
                    continue

    return muon_event_param
Пример #39
0
def func(paths, outpath, ro, rc, rn):

    # iterate on each proton file & concatenate charge arrays
    for n, f in enumerate(paths):
        # get the data from the file
        try:
            print("Opening file #{}...".format(n))
            data_p = tables.open_file(f)
            _, LST_event_index, LST_image_charge, LST_image_peak_times = get_LST_data(data_p)
            _, ei_alt, ei_az, ei_mc_energy = get_event_data(data_p)

            # Excluding the 0th element - it's the empty one!!
            LST_event_index = LST_event_index[1:]
            LST_image_charge = LST_image_charge[1:]
            LST_image_peak_times = LST_image_peak_times[1:]

            # get camera geometry & camera pixels coordinates
            camera = CameraGeometry.from_name("LSTCam")
            points = np.array([np.array(camera.pix_x / u.m), np.array(camera.pix_y / u.m)]).T

            # original choice by Nicola: 100x100 points in 2.5m x 2.5m
            #grid_x, grid_y = np.mgrid[-1.25:1.25:100j, -1.25:1.25:100j]
            # I choose instead 96x88 px in 2.40m x 2.20m: same spatial separation, less points
            grid_x, grid_y = np.mgrid[-1.20:1.20:96j, -1.10:1.10:88j]

            '''
            was probably useless and wrong even with the old simulations
            if alt_array > 90:
                alt_array = 90
            '''

            # LST coordinates (pointing position)
            #point = AltAz(alt=alt_array * u.deg, az=az_array * u.deg)


            lst_image_charge_interp = []
            lst_image_peak_times_interp = []
            # alt az of the array [deg]
            #az_array = 180.  # before was ai_run_array_direction[0][0], now it is hardcoded as it's not present in new files
            #alt_array = 70.  # ai_run_array_direction[0][1]
            #delta_az = []
            #delta_alt = []
            intensities = []
            intensities_width_2 = []
            acc_idxs = []  # accepted indexes    # in principle it can be removed when cuts (line AAA) are not used here

            cleaning_level = {'LSTCam': (3.5, 7.5, 2)}
            count = 0
            #rejected = open(f[:-3] + "_rejected.txt", "w")
            for i in trange(0, len(LST_image_charge), desc="Images interpolation"):

                image = LST_image_charge[i]
                time = LST_image_peak_times[i]

                boundary, picture, min_neighbors = cleaning_level['LSTCam']
                clean = tailcuts_clean(
                    camera,
                    image,
                    boundary_thresh=boundary,
                    picture_thresh=picture,
                    min_number_picture_neighbors=min_neighbors
                )

                if len(np.where(clean > 0)[0]) != 0:
                    hillas = hillas_parameters(camera[clean], image[clean])

                    intensity = hillas['intensity']

                    l = leakage(camera, image, clean)
                    # print(l)
                    leakage2_intensity = l['intensity_width_2']

                    # if intensity > 50 and leakage2_intensity < 0.2:  # ------>AAA --- CUT DIRECTLY DURING INTERP
                    # cubic interpolation
                    interp_img = griddata(points, image, (grid_x, grid_y), fill_value=0, method='cubic')
                    interp_time = griddata(points, time, (grid_x, grid_y), fill_value=0, method='cubic')

                    # delta az, delta alt computation
                    #az = ei_az[LST_event_index[i]]
                    #alt = ei_alt[LST_event_index[i]]
                    #src = AltAz(alt=alt * u.rad, az=az * u.rad)
                    #source_direction = src.transform_to(NominalFrame(origin=point))

                    # appending to arrays
                    lst_image_charge_interp.append(interp_img)
                    lst_image_peak_times_interp.append(interp_time)
                    #delta_az.append(source_direction.delta_az.deg)
                    #delta_alt.append(source_direction.delta_alt.deg)

                    intensities.append(intensity)
                    intensities_width_2.append(leakage2_intensity)

                    acc_idxs += [i]  # also this one can be removed when no cuts here

                else:
                    count += 1
                #    #rejected.write("{}.\tImage #{} rejected (no islands)!\n".format(count, i))
                #    print("No islands: image #{} rejected! (cumulative: {})\n".format(i, count), end='\r')
            # lst_image_charge_interp = np.array(lst_image_charge_interp)
            print("Number of rejected images: {} ({:.1f}%)".format(count, count / len(intensities) *100))
            data_p.close()
            #rejected.close()
            fpath = Path(f)
            newname = fpath.name[:-3] + '_interp.h5'
            filename = str(PurePath(outpath, newname))
            print("Writing file: " + filename + "\n")
            data_file = h5py.File(filename, 'w')
            data_file.create_dataset('Event_Info/ei_alt', data=np.array(ei_alt))
            data_file.create_dataset('Event_Info/ei_az', data=np.array(ei_az))
            data_file.create_dataset('Event_Info/ei_mc_energy', data=np.array(ei_mc_energy))

            data_file.create_dataset('LST/LST_event_index', data=np.array(LST_event_index)[acc_idxs])
            data_file.create_dataset('LST/LST_image_charge', data=np.array(LST_image_charge)[acc_idxs])
            data_file.create_dataset('LST/LST_image_peak_times', data=np.array(LST_image_peak_times)[acc_idxs])
            # data_file.create_dataset('LST/LST_event_index', data=np.array(LST_event_index))
            # data_file.create_dataset('LST/LST_image_charge', data=np.array(LST_image_charge))
            # data_file.create_dataset('LST/LST_image_peak_times', data=np.array(LST_image_peak_times))
            data_file.create_dataset('LST/LST_image_charge_interp', data=np.array(lst_image_charge_interp))
            data_file.create_dataset('LST/LST_image_peak_times_interp', data=np.array(lst_image_peak_times_interp))
            #data_file.create_dataset('LST/delta_alt', data=np.array(delta_alt))
            #data_file.create_dataset('LST/delta_az', data=np.array(delta_az))

            data_file.create_dataset('LST/intensities', data=np.array(intensities))
            data_file.create_dataset('LST/intensities_width_2', data=np.array(intensities_width_2))

            data_file.close()

            # in the interpolated files there will be all the original events
            # but for the LST only the ones actually see at least from one LST (as in the original files)
            # and that are above thresholds cuts

            if ro == '1':
                remove(f)
                print('Removing original file')

        except HDF5ExtError:

            print('\nUnable to open file' + f)

            if rc == '1':
                print('Removing it...')
                remove(f)

        except NoSuchNodeError:

            print('This file has a problem with the data structure: ' + f)

            if rn == '1':
                print('Removing it...')
                remove(f)
Пример #40
0
def plot_muon_event(event, muonparams, geom_dict=None, args=None):

    if muonparams[0] is not None:

        # Plot the muon event and overlay muon parameters
        fig = plt.figure(figsize=(16, 7))
        # if args.display:
        #    plt.show(block=False)
        #pp = PdfPages(args.output_path) if args.output_path is not None else None
        # pp = None #For now, need to correct this

        colorbar = None
        colorbar2 = None

        for tel_id in event.dl0.tels_with_data:
            npads = 2
            # Only create two pads if there is timing information extracted
            # from the calibration
            ax1 = fig.add_subplot(1, npads, 1)
            plotter = CameraPlotter(event, geom_dict)
            #image = event.dl1.tel[tel_id].calibrated_image
            image = event.dl1.tel[tel_id].image[0]
            # Get geometry
            geom = None
            if geom_dict is not None and tel_id in geom_dict:
                geom = geom_dict[tel_id]
            else:
                #log.debug("[calib] Guessing camera geometry")
                geom = CameraGeometry.guess(*event.inst.pixel_pos[tel_id],
                                            event.inst.optical_foclen[tel_id])
                #log.debug("[calib] Camera geometry found")
                if geom_dict is not None:
                    geom_dict[tel_id] = geom

            tailcuts = (5., 7.)
            # Try a higher threshold for
            if geom.cam_id == 'FlashCam':
                tailcuts = (10., 12.)

            #print("Using Tail Cuts:",tailcuts)
            clean_mask = tailcuts_clean(geom, image,
                                        picture_thresh=tailcuts[0],
                                        boundary_thresh=tailcuts[1])

            signals = image * clean_mask

            #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y)
            muon_incl = np.sqrt(muonparams[0].ring_center_x**2. +
                                muonparams[0].ring_center_y**2.)

            muon_phi = np.arctan(muonparams[0].ring_center_y /
                                 muonparams[0].ring_center_x)

            rotr_angle = geom.pix_rotation
            # if event.inst.optical_foclen[tel_id] > 10.*u.m and
            # event.dl0.tel[tel_id].num_pixels != 1764:
            if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam':
                #print("Resetting the rotation angle")
                rotr_angle = 0. * u.deg

            # Convert to camera frame (centre & radius)
            altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az)

            ring_nominal = NominalFrame(x=muonparams[0].ring_center_x,
                                        y=muonparams[0].ring_center_y,
                                        array_direction=altaz,
                                        pointing_direction=altaz)

            # embed()
            ring_camcoord = ring_nominal.transform_to(CameraFrame(
                pointing_direction=altaz,
                focal_length=event.inst.optical_foclen[tel_id],
                rotation=rotr_angle))

            centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2)
            centroid = (ring_camcoord.x.value, ring_camcoord.y.value)

            ringrad_camcoord = muonparams[0].ring_radius.to(u.rad) \
                               * event.inst.optical_foclen[tel_id] * 2.  # But not FC?

            #rot_angle = 0.*u.deg
            # if event.inst.optical_foclen[tel_id] > 10.*u.m and event.dl0.tel[tel_id].num_pixels != 1764:
            #rot_angle = -100.14*u.deg

            px, py = event.inst.pixel_pos[tel_id]
            flen = event.inst.optical_foclen[tel_id]
            camera_coord = CameraFrame(x=px, y=py,
                                       z=np.zeros(px.shape) * u.m,
                                       focal_length=flen,
                                       rotation=geom.pix_rotation)

            nom_coord = camera_coord.transform_to(
                NominalFrame(array_direction=altaz,
                             pointing_direction=altaz)
            )
            #,focal_length = event.inst.optical_foclen[tel_id])) # tel['TelescopeTable_VersionFeb2016'][tel['TelescopeTable_VersionFeb2016']['TelID']==telid]['FL'][0]*u.m))

            px = nom_coord.x.to(u.deg)
            py = nom_coord.y.to(u.deg)

            dist = np.sqrt(np.power( px - muonparams[0].ring_center_x, 2)
                           + np.power(py - muonparams[0].ring_center_y, 2))
            ring_dist = np.abs(dist - muonparams[0].ring_radius)
            pixRmask = ring_dist < muonparams[0].ring_radius * 0.4

            if muonparams[1] is not None:
                signals *= muonparams[1].mask

            camera1 = plotter.draw_camera(tel_id, signals, ax1)

            cmaxmin = (max(signals) - min(signals))
            if not cmaxmin:
                cmaxmin = 1.
            cmap_charge = colors.LinearSegmentedColormap.from_list(
                'cmap_c', [(0 / cmaxmin, 'darkblue'),
                           (np.abs(min(signals)) / cmaxmin, 'black'),
                           (2.0 * np.abs(min(signals)) / cmaxmin, 'blue'),
                           (2.5 * np.abs(min(signals)) / cmaxmin, 'green'),
                           (1, 'yellow')]
            )
            camera1.pixels.set_cmap(cmap_charge)
            if not colorbar:
                camera1.add_colorbar(ax=ax1, label=" [photo-electrons]")
                colorbar = camera1.colorbar
            else:
                camera1.colorbar = colorbar
            camera1.update(True)

            camera1.add_ellipse(centroid, ringrad_camcoord.value,
                                ringrad_camcoord.value, 0., 0., color="red")

#            ax1.set_title("CT {} ({}) - Mean pixel charge"
#                          .format(tel_id, geom_dict[tel_id].cam_id))

            if muonparams[1] is not None:
                # continue #Comment this...(should ringwidthfrac also be *0.5?)
                ringwidthfrac = muonparams[
                    1].ring_width / muonparams[0].ring_radius
                ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac)
                ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac)
                camera1.add_ellipse(centroid, ringrad_inner.value,
                                     ringrad_inner.value, 0., 0.,
                                     color="magenta")
                camera1.add_ellipse(centroid, ringrad_outer.value,
                                    ringrad_outer.value, 0., 0., color="magenta")
                npads = 2
                ax2 = fig.add_subplot(1, npads, npads)
                pred = muonparams[1].prediction

                if len(pred) != np.sum(muonparams[1].mask):
                    print("Warning! Lengths do not match...len(pred)=",
                          len(pred), "len(mask)=", np.sum(muonparams[1].mask))

                # Numpy broadcasting - fill in the shape
                plotpred = np.zeros(image.shape)
                plotpred[muonparams[1].mask == True] = pred

                camera2 = plotter.draw_camera(tel_id, plotpred, ax2)

                c2maxmin = (max(plotpred) - min(plotpred))
                if not c2maxmin:
                    c2maxmin = 1.
                c2map_charge = colors.LinearSegmentedColormap.from_list(
                    'c2map_c', [(0 / c2maxmin, 'darkblue'),
                                (np.abs(min(plotpred)) / c2maxmin, 'black'),
                                (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'),
                                (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'),
                                (1, 'yellow')]
                )
                camera2.pixels.set_cmap(c2map_charge)
                if not colorbar2:
                    camera2.add_colorbar(ax=ax2, label=" [photo-electrons]")
                    colorbar2 = camera2.colorbar
                else:
                    camera2.colorbar = colorbar2
                camera2.update(True)
                plt.pause(1.)  # make shorter

            # plt.pause(0.1)
            # if pp is not None:
            #    pp.savefig(fig)
            fig.savefig(str(args.output_path) + "_" +
                        str(event.dl0.event_id) + '.png')

            plt.close()
def main():
    args = parser.parse_args()
    event_generator = fact_event_generator(
        args.inputfile,
        args.drsfile,
        allowed_triggers={4},
    )

    fig = plt.figure(figsize=(12, 6))
    ax1 = fig.add_axes([0, 0, 0.4, 1])
    ax1.set_axis_off()
    divider = make_axes_locatable(ax1)
    cax1 = divider.append_axes('right', size="5%", pad=0.05)

    ax2 = fig.add_axes([0.5, 0.0, 0.4, 1])
    ax2.set_axis_off()
    divider = make_axes_locatable(ax2)
    cax2 = divider.append_axes('right', size="5%", pad=0.05)

    geom = CameraGeometry.from_name('FACT')

    disp1 = CameraDisplay(geom, ax=ax1)
    disp1.add_colorbar(cax=cax1, label='Photons')
    disp2 = CameraDisplay(geom, ax=ax2)
    disp2.add_colorbar(cax=cax2, label='ArrivalTime')

    ax1.set_title('Photons')
    ax2.set_title('Peak Position')

    for e in event_generator:

        dl1_calibrator.calibrate(e)

        image = e.dl1.tel[0].image[0]
        cleaning_mask = tailcuts_clean(geom, image, 5, 3.5)

        if sum(cleaning_mask) < 15:
            continue

        hillas_container = hillas_parameters(
            geom.pix_x[cleaning_mask],
            geom.pix_y[cleaning_mask],
            image[cleaning_mask],
        )

        disp1.overlay_moments(hillas_container,
                              linewidth=1.5,
                              color='c',
                              with_label=False)
        disp1.highlight_pixels(cleaning_mask)

        disp1.image = e.dl1.tel[0].image[0]
        disp2.image = e.dl1.tel[0].peakpos[0]

        for disp in (disp1, disp2):
            disp.highlight_pixels(cleaning_mask, color='r', linewidth=1.5)

        fig.suptitle('FACT Event {}'.format(e.trig.gps_time.iso))

        plt.pause(0.01)
        input('Press enter for next event')
Пример #42
0
def main():
    std_config = get_standard_config()

    log.setLevel(logging.INFO)
    handler = logging.StreamHandler()
    logging.getLogger().addHandler(handler)

    if args.config_file is not None:
        config = replace_config(std_config, read_configuration_file(args.config_file))
    else:
        config = std_config

    log.info(f"Tailcut config used: {config['tailcut']}")

    foclen = OpticsDescription.from_name('LST').equivalent_focal_length
    cam_table = Table.read(args.input_file, path="instrument/telescope/camera/LSTCam")
    camera_geom = CameraGeometry.from_table(cam_table)

    dl1_container = DL1ParametersContainer()
    parameters_to_update = list(HillasParametersContainer().keys())
    parameters_to_update.extend([
        'concentration_cog',
        'concentration_core',
        'concentration_pixel',
        'leakage_intensity_width_1',
        'leakage_intensity_width_2',
        'leakage_pixels_width_1',
        'leakage_pixels_width_2',
        'n_islands',
        'intercept',
        'time_gradient',
        'n_pixels',
        'wl',
        'log_intensity'
    ])

    nodes_keys = get_dataset_keys(args.input_file)
    if args.noimage:
        nodes_keys.remove(dl1_images_lstcam_key)

    auto_merge_h5files([args.input_file], args.output_file, nodes_keys=nodes_keys)

    with tables.open_file(args.input_file, mode='r') as input:
        image_table = input.root[dl1_images_lstcam_key]
        dl1_params_input = input.root[dl1_params_lstcam_key].colnames
        disp_params = {'disp_dx', 'disp_dy', 'disp_norm', 'disp_angle', 'disp_sign'}
        if set(dl1_params_input).intersection(disp_params):
            parameters_to_update.extend(disp_params)

        with tables.open_file(args.output_file, mode='a') as output:
            params = output.root[dl1_params_lstcam_key].read()
            for ii, row in enumerate(image_table):

                dl1_container.reset()

                image = row['image']
                peak_time = row['peak_time']

                signal_pixels = tailcuts_clean(camera_geom, image, **config['tailcut'])

                n_pixels = np.count_nonzero(signal_pixels)
                if n_pixels > 0:
                    num_islands, island_labels = number_of_islands(camera_geom, signal_pixels)
                    n_pixels_on_island = np.bincount(island_labels.astype(np.int))
                    n_pixels_on_island[0] = 0  # first island is no-island and should not be considered
                    max_island_label = np.argmax(n_pixels_on_island)
                    signal_pixels[island_labels != max_island_label] = False

                    hillas = hillas_parameters(camera_geom[signal_pixels], image[signal_pixels])

                    dl1_container.fill_hillas(hillas)
                    dl1_container.set_timing_features(camera_geom[signal_pixels],
                                                      image[signal_pixels],
                                                      peak_time[signal_pixels],
                                                      hillas)

                    dl1_container.set_leakage(camera_geom, image, signal_pixels)
                    dl1_container.set_concentration(camera_geom, image, hillas)
                    dl1_container.n_islands = num_islands
                    dl1_container.wl = dl1_container.width / dl1_container.length
                    dl1_container.n_pixels = n_pixels
                    width = np.rad2deg(np.arctan2(dl1_container.width, foclen))
                    length = np.rad2deg(np.arctan2(dl1_container.length, foclen))
                    dl1_container.width = width
                    dl1_container.length = length
                    dl1_container.log_intensity = np.log10(dl1_container.intensity)

                if set(dl1_params_input).intersection(disp_params):
                    disp_dx, disp_dy, disp_norm, disp_angle, disp_sign = disp(
                        dl1_container['x'].to_value(u.m),
                        dl1_container['y'].to_value(u.m),
                        params['src_x'][ii],
                        params['src_y'][ii]
                    )

                    dl1_container['disp_dx'] = disp_dx
                    dl1_container['disp_dy'] = disp_dy
                    dl1_container['disp_norm'] = disp_norm
                    dl1_container['disp_angle'] = disp_angle
                    dl1_container['disp_sign'] = disp_sign

                for p in parameters_to_update:
                    params[ii][p] = u.Quantity(dl1_container[p]).value

            output.root[dl1_params_lstcam_key][:] = params
Пример #43
0
def test_FitGammaHillas():
    '''
    a test of the complete fit procedure on one event including:
    • tailcut cleaning
    • hillas parametrisation
    • GreatCircle creation
    • direction fit
    • position fit

    in the end, proper units in the output are asserted '''

    filename = get_dataset("gamma_test.simtel.gz")

    fit = HillasReconstructor()

    cam_geom = {}
    tel_phi = {}
    tel_theta = {}

    source = hessio_event_source(filename)

    for event in source:

        hillas_dict = {}
        for tel_id in event.dl0.tels_with_data:

            if tel_id not in cam_geom:
                cam_geom[tel_id] = CameraGeometry.guess(
                    event.inst.pixel_pos[tel_id][0],
                    event.inst.pixel_pos[tel_id][1],
                    event.inst.optical_foclen[tel_id])

                tel_phi[tel_id] = event.mc.tel[tel_id].azimuth_raw * u.rad
                tel_theta[tel_id] = (np.pi / 2 -
                                     event.mc.tel[tel_id].altitude_raw) * u.rad

            pmt_signal = event.r0.tel[tel_id].adc_sums[0]

            mask = tailcuts_clean(cam_geom[tel_id],
                                  pmt_signal,
                                  picture_thresh=10.,
                                  boundary_thresh=5.)
            pmt_signal[mask == 0] = 0

            try:
                moments = hillas_parameters(event.inst.pixel_pos[tel_id][0],
                                            event.inst.pixel_pos[tel_id][1],
                                            pmt_signal)
                hillas_dict[tel_id] = moments
            except HillasParameterizationError as e:
                print(e)
                continue

        if len(hillas_dict) < 2: continue

        fit_result = fit.predict(hillas_dict, event.inst, tel_phi, tel_theta)

        print(fit_result)
        fit_result.alt.to(u.deg)
        fit_result.az.to(u.deg)
        fit_result.core_x.to(u.m)
        assert fit_result.is_valid
        return
Пример #44
0
def check_interleave_pedestal_cleaning(path_list, calib_time_file, calib_file, max_events=10000):

    signal_place_after_clean = np.zeros(1855)
    sum_ped_ev = 0
    alive_ped_ev = 0

    for path in path_list:
        print(path)
        r0_r1_calibrator = LSTR0Corrections(pedestal_path=None,
                                            r1_sample_start=3,
                                            r1_sample_end=39)

        r1_dl1_calibrator = LSTCameraCalibrator(calibration_path=calib_file,
                                                time_calibration_path=calib_time_file,
                                                extractor_product="LocalPeakWindowSum",
                                                config=charge_config,
                                                allowed_tels=[1])

        reader = LSTEventSource(input_url=path, max_events=max_events)


        for i, ev in enumerate(reader):
            r0_r1_calibrator.calibrate(ev)
            if i%10000 == 0:
                print(ev.r0.event_id)

            if ev.lst.tel[1].evt.tib_masked_trigger == 32:
                sum_ped_ev += 1

                r1_dl1_calibrator(ev)

                img = ev.dl1.tel[1].image

                geom = ev.inst.subarray.tel[1].camera
                clean = tailcuts_clean(
                                    geom,
                                    img,
                                    picture_thresh=6,
                                    boundary_thresh=3,
                                    min_number_picture_neighbors=1,
                                    keep_isolated_pixels=False
                                    )

                cleaned = img.copy()
                cleaned[~clean] = 0.0

                signal_place_after_clean[np.where(clean == True)] += 1

                if np.sum(cleaned>0) > 0:
                    alive_ped_ev += 1

    fig, ax = plt.subplots(figsize=(8, 8))
    geom = ev.inst.subarray.tel[1].camera

    disp0 = CameraDisplay(geom, ax=ax)
    disp0.image = signal_place_after_clean/sum_ped_ev
    disp0.add_colorbar(ax=ax, label="N times signal remain after cleaning")
    disp0.cmap = 'gnuplot2'
    ax.set_title("{} \n {}/{}".format(path.split("/")[-1][8:21], alive_ped_ev, sum_ped_ev))

    print(path.split("/")[-1][8:21])
    print("{}/{}".format(alive_ped_ev, sum_ped_ev))

    ax.set_xlabel(" ")
    ax.set_ylabel(" ")
    plt.tight_layout()
    plt.show()

    return signal_place_after_clean, sum_ped_ev
Пример #45
0
def test_convert_geometry():
    filename = get_path("gamma_test.simtel.gz")

    cam_geom = {}

    source = hessio_event_source(filename)

    # testing a few images just for the sake of being thorough
    counter = 5

    for event in source:

        for tel_id in event.dl0.tels_with_data:
            if tel_id not in cam_geom:
                cam_geom[tel_id] = CameraGeometry.guess(
                                        event.inst.pixel_pos[tel_id][0],
                                        event.inst.pixel_pos[tel_id][1],
                                        event.inst.optical_foclen[tel_id])


            # we want to test conversion of hex to rectangular pixel grid
            if cam_geom[tel_id].pix_type is not "hexagonal":
                continue

            print(tel_id, cam_geom[tel_id].pix_type)

            pmt_signal = apply_mc_calibration(
                        #event.dl0.tel[tel_id].adc_samples[0],
                        event.dl0.tel[tel_id].adc_sums[0],
                        event.mc.tel[tel_id].dc_to_pe[0],
                        event.mc.tel[tel_id].pedestal[0])

            new_geom, new_signal = convert_geometry_1d_to_2d(
                cam_geom[tel_id], pmt_signal, cam_geom[tel_id].cam_id, add_rot=-2)

            unrot_geom, unrot_signal = convert_geometry_back(
                new_geom, new_signal, cam_geom[tel_id].cam_id,
                event.inst.optical_foclen[tel_id], add_rot=4)

            # if run as main, do some plotting
            if __name__ == "__main__":
                fig = plt.figure()
                plt.style.use('seaborn-talk')

                ax1 = fig.add_subplot(131)
                disp1 = CameraDisplay(cam_geom[tel_id],
                                      image=np.sum(pmt_signal, axis=1)
                                      if pmt_signal.shape[-1] == 25 else pmt_signal,
                                      ax=ax1)
                disp1.cmap = plt.cm.hot
                disp1.add_colorbar()
                plt.title("original geometry")

                ax2 = fig.add_subplot(132)
                disp2 = CameraDisplay(new_geom,
                                      image=np.sum(new_signal, axis=2)
                                      if new_signal.shape[-1] == 25 else new_signal,
                                      ax=ax2)
                disp2.cmap = plt.cm.hot
                disp2.add_colorbar()
                plt.title("slanted geometry")

                ax3 = fig.add_subplot(133)
                disp3 = CameraDisplay(unrot_geom, image=np.sum(unrot_signal, axis=1)
                                      if unrot_signal.shape[-1] == 25 else unrot_signal,
                                      ax=ax3)
                disp3.cmap = plt.cm.hot
                disp3.add_colorbar()
                plt.title("geometry converted back to hex")

                plt.show()


            # do some tailcuts cleaning
            mask1 = tailcuts_clean(cam_geom[tel_id], pmt_signal, 1,
                                   picture_thresh=10.,
                                   boundary_thresh=5.)

            mask2 = tailcuts_clean(unrot_geom, unrot_signal, 1,
                                   picture_thresh=10.,
                                   boundary_thresh=5.)
            pmt_signal[mask1==False] = 0
            unrot_signal[mask2==False] = 0

            '''
            testing back and forth conversion on hillas parameters... '''
            try:
                moments1 = hillas_parameters(cam_geom[tel_id].pix_x,
                                             cam_geom[tel_id].pix_y,
                                             pmt_signal)

                moments2 = hillas_parameters(unrot_geom.pix_x,
                                             unrot_geom.pix_y,
                                             unrot_signal)
            except (HillasParameterizationError, AssertionError) as e:
                '''
                we don't want this test to fail because the hillas code
                threw an error '''
                print(e)
                counter -= 1
                if counter < 0:
                    return
                else:
                    continue

            '''
            test if the hillas parameters from the original geometry and the
            forth-and-back rotated geometry are close '''
            assert np.allclose(
                [moments1.length.value, moments1.width.value,
                 moments1.phi.value],
                [moments2.length.value, moments2.width.value,
                 moments2.phi.value],
                rtol=1e-2, atol=1e-2)
            counter -= 1
            if counter < 0:
                return
Пример #46
0
def plot_muon_event(event, muonparams, args=None):

    if muonparams['MuonRingParams'] is not None:

        # Plot the muon event and overlay muon parameters
        fig = plt.figure(figsize=(16, 7))

        colorbar = None
        colorbar2 = None

        #for tel_id in event.dl0.tels_with_data:
        for tel_id in muonparams['TelIds']:
            idx = muonparams['TelIds'].index(tel_id)

            if not muonparams['MuonRingParams'][idx]:
                continue

            #otherwise...
            npads = 2
            # Only create two pads if there is timing information extracted
            # from the calibration
            ax1 = fig.add_subplot(1, npads, 1)
            plotter = CameraPlotter(event)
            image = event.dl1.tel[tel_id].image[0]
            geom = event.inst.subarray.tel[tel_id].camera

            tailcuts = (5., 7.)
            # Try a higher threshold for
            if geom.cam_id == 'FlashCam':
                tailcuts = (10., 12.)

            clean_mask = tailcuts_clean(geom,
                                        image,
                                        picture_thresh=tailcuts[0],
                                        boundary_thresh=tailcuts[1])

            signals = image * clean_mask

            #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y)
            muon_incl = np.sqrt(
                muonparams['MuonRingParams'][idx].ring_center_x**2. +
                muonparams['MuonRingParams'][idx].ring_center_y**2.)

            muon_phi = np.arctan(
                muonparams['MuonRingParams'][idx].ring_center_y /
                muonparams['MuonRingParams'][idx].ring_center_x)

            rotr_angle = geom.pix_rotation
            # if event.inst.optical_foclen[tel_id] > 10.*u.m and
            # event.dl0.tel[tel_id].num_pixels != 1764:
            if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam':
                #print("Resetting the rotation angle")
                rotr_angle = 0. * u.deg

            # Convert to camera frame (centre & radius)
            altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az)

            ring_nominal = NominalFrame(
                x=muonparams['MuonRingParams'][idx].ring_center_x,
                y=muonparams['MuonRingParams'][idx].ring_center_y,
                array_direction=altaz,
                pointing_direction=altaz)

            # embed()
            ring_camcoord = ring_nominal.transform_to(
                CameraFrame(pointing_direction=altaz,
                            focal_length=event.inst.optical_foclen[tel_id],
                            rotation=rotr_angle))

            centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2)
            centroid = (ring_camcoord.x.value, ring_camcoord.y.value)

            ringrad_camcoord = muonparams['MuonRingParams'][idx].ring_radius.to(u.rad) \
                               * event.inst.optical_foclen[tel_id] * 2.  # But not FC?

            px, py = event.inst.pixel_pos[tel_id]
            flen = event.inst.optical_foclen[tel_id]
            camera_coord = CameraFrame(x=px,
                                       y=py,
                                       focal_length=flen,
                                       rotation=geom.pix_rotation)

            nom_coord = camera_coord.transform_to(
                NominalFrame(array_direction=altaz, pointing_direction=altaz))

            px = nom_coord.x.to(u.deg)
            py = nom_coord.y.to(u.deg)

            dist = np.sqrt(
                np.power(px -
                         muonparams['MuonRingParams'][idx].ring_center_x, 2) +
                np.power(py -
                         muonparams['MuonRingParams'][idx].ring_center_y, 2))
            ring_dist = np.abs(dist -
                               muonparams['MuonRingParams'][idx].ring_radius)
            pixRmask = ring_dist < muonparams['MuonRingParams'][
                idx].ring_radius * 0.4

            #if muonparams[1] is not None:
            if muonparams['MuonIntensityParams'][idx] is not None:
                signals *= muonparams['MuonIntensityParams'][idx].mask

            camera1 = plotter.draw_camera(tel_id, signals, ax1)

            cmaxmin = (max(signals) - min(signals))
            cmin = min(signals)
            if not cmin:
                cmin = 1.
            if not cmaxmin:
                cmaxmin = 1.

            cmap_charge = colors.LinearSegmentedColormap.from_list(
                'cmap_c', [(0 / cmaxmin, 'darkblue'),
                           (np.abs(cmin) / cmaxmin, 'black'),
                           (2.0 * np.abs(cmin) / cmaxmin, 'blue'),
                           (2.5 * np.abs(cmin) / cmaxmin, 'green'),
                           (1, 'yellow')])
            camera1.pixels.set_cmap(cmap_charge)
            if not colorbar:
                camera1.add_colorbar(ax=ax1, label=" [photo-electrons]")
                colorbar = camera1.colorbar
            else:
                camera1.colorbar = colorbar
            camera1.update(True)

            camera1.add_ellipse(centroid,
                                ringrad_camcoord.value,
                                ringrad_camcoord.value,
                                0.,
                                0.,
                                color="red")

            if muonparams['MuonIntensityParams'][idx] is not None:
                # continue #Comment this...(should ringwidthfrac also be *0.5?)

                ringwidthfrac = muonparams['MuonIntensityParams'][
                    idx].ring_width / muonparams['MuonRingParams'][
                        idx].ring_radius
                ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac)
                ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac)
                camera1.add_ellipse(centroid,
                                    ringrad_inner.value,
                                    ringrad_inner.value,
                                    0.,
                                    0.,
                                    color="magenta")
                camera1.add_ellipse(centroid,
                                    ringrad_outer.value,
                                    ringrad_outer.value,
                                    0.,
                                    0.,
                                    color="magenta")
                npads = 2
                ax2 = fig.add_subplot(1, npads, npads)
                pred = muonparams['MuonIntensityParams'][idx].prediction

                if len(pred) != np.sum(
                        muonparams['MuonIntensityParams'][idx].mask):
                    print("Warning! Lengths do not match...len(pred)=",
                          len(pred), "len(mask)=",
                          np.sum(muonparams['MuonIntensityParams'][idx].mask))

                # Numpy broadcasting - fill in the shape
                plotpred = np.zeros(image.shape)
                plotpred[muonparams['MuonIntensityParams'][idx].mask ==
                         True] = pred

                camera2 = plotter.draw_camera(tel_id, plotpred, ax2)

                if np.isnan(max(plotpred)) or np.isnan(min(plotpred)):
                    print("nan prediction, skipping...")
                    continue

                c2maxmin = (max(plotpred) - min(plotpred))
                if not c2maxmin:
                    c2maxmin = 1.

                c2map_charge = colors.LinearSegmentedColormap.from_list(
                    'c2map_c',
                    [(0 / c2maxmin, 'darkblue'),
                     (np.abs(min(plotpred)) / c2maxmin, 'black'),
                     (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'),
                     (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'),
                     (1, 'yellow')])
                camera2.pixels.set_cmap(c2map_charge)
                if not colorbar2:
                    camera2.add_colorbar(ax=ax2, label=" [photo-electrons]")
                    colorbar2 = camera2.colorbar
                else:
                    camera2.colorbar = colorbar2
                camera2.update(True)
                plt.pause(1.)  # make shorter

            # plt.pause(0.1)
            # if pp is not None:
            #    pp.savefig(fig)
            #fig.savefig(str(args.output_path) + "_" +
            #            str(event.dl0.event_id) + '.png')

            plt.close()
Пример #47
0
def analyze_muon_event(event):
    """
    Generic muon event analyzer.

    Parameters
    ----------
    event : ctapipe dl1 event container


    Returns
    -------
    muonringparam, muonintensityparam : MuonRingParameter
    and MuonIntensityParameter container event

    """

    names = [
        'LST_LST_LSTCam', 'MST_MST_NectarCam', 'MST_MST_FlashCam',
        'MST_SCT_SCTCam', 'SST_1M_DigiCam', 'SST_GCT_CHEC',
        'SST_ASTRI_ASTRICam', 'SST_ASTRI_CHEC'
    ]
    tail_cuts = [(5, 7), (5, 7), (10, 12), (5, 7), (5, 7), (5, 7), (5, 7),
                 (5, 7)]  # 10, 12?
    impact = [(0.2, 0.9), (0.1, 0.95), (0.2, 0.9), (0.2, 0.9), (0.1, 0.95),
              (0.1, 0.95), (0.1, 0.95), (0.1, 0.95)] * u.m
    ringwidth = [(0.04, 0.08), (0.02, 0.1), (0.01, 0.1), (0.02, 0.1),
                 (0.01, 0.5), (0.02, 0.2), (0.02, 0.2), (0.02, 0.2)] * u.deg
    total_pix = [1855., 1855., 1764., 11328., 1296., 2048., 2368., 2048]
    # 8% (or 6%) as limit
    min_pix = [148., 148., 141., 680., 104., 164., 142., 164]
    # Need to either convert from the pixel area in m^2 or check the camera specs
    ang_pixel_width = [0.1, 0.2, 0.18, 0.067, 0.24, 0.2, 0.17, 0.2, 0.163
                       ] * u.deg
    # Found from TDRs (or the pixel area)
    hole_rad = [
        0.308 * u.m, 0.244 * u.m, 0.244 * u.m, 4.3866 * u.m, 0.160 * u.m,
        0.130 * u.m, 0.171 * u.m, 0.171 * u.m
    ]  # Assuming approximately spherical hole
    cam_rad = [2.26, 3.96, 3.87, 4., 4.45, 2.86, 5.25, 2.86] * u.deg
    # Above found from the field of view calculation
    sec_rad = [
        0. * u.m, 0. * u.m, 0. * u.m, 2.7 * u.m, 0. * u.m, 1. * u.m, 1.8 * u.m,
        1.8 * u.m
    ]
    sct = [False, False, False, True, False, True, True, True]
    # Added cleaning here. All these options should go to an input card
    cleaning = True

    muon_cuts = {
        'Name': names,
        'tail_cuts': tail_cuts,
        'Impact': impact,
        'RingWidth': ringwidth,
        'total_pix': total_pix,
        'min_pix': min_pix,
        'CamRad': cam_rad,
        'SecRad': sec_rad,
        'SCT': sct,
        'AngPixW': ang_pixel_width,
        'HoleRad': hole_rad
    }
    logger.debug(muon_cuts)

    muonringlist = []  # [None] * len(event.dl0.tels_with_data)
    muonintensitylist = []  # [None] * len(event.dl0.tels_with_data)
    tellist = []
    muon_event_param = {
        'TelIds': tellist,
        'MuonRingParams': muonringlist,
        'MuonIntensityParams': muonintensitylist
    }

    for telid in event.dl0.tels_with_data:

        logger.debug("Analysing muon event for tel %d", telid)
        image = event.dl1.tel[telid].image

        # Get geometry
        teldes = event.inst.subarray.tel[telid]
        geom = teldes.camera
        x, y = geom.pix_x, geom.pix_y

        dict_index = muon_cuts['Name'].index(str(teldes))
        logger.debug('found an index of %d for camera %d', dict_index,
                     geom.cam_id)

        tailcuts = muon_cuts['tail_cuts'][dict_index]
        logger.debug("Tailcuts are %s", tailcuts)

        clean_mask = tailcuts_clean(geom,
                                    image,
                                    picture_thresh=tailcuts[0],
                                    boundary_thresh=tailcuts[1])

        # TODO: correct this hack for values over 90
        altval = event.mcheader.run_array_direction[1]
        if altval > Angle(90, unit=u.deg):
            warnings.warn('Altitude over 90 degrees')
            altval = Angle(90, unit=u.deg)

        telescope_pointing = SkyCoord(alt=altval,
                                      az=event.mcheader.run_array_direction[0],
                                      frame=AltAz())
        camera_coord = SkyCoord(
            x=x,
            y=y,
            frame=CameraFrame(
                focal_length=teldes.optics.equivalent_focal_length,
                rotation=geom.pix_rotation,
                telescope_pointing=telescope_pointing,
            ))

        nom_coord = camera_coord.transform_to(
            NominalFrame(origin=telescope_pointing))
        x = nom_coord.delta_az.to(u.deg)
        y = nom_coord.delta_alt.to(u.deg)

        if (cleaning):
            img = image * clean_mask
        else:
            img = image

        muonring = ChaudhuriKunduRingFitter(None)

        logger.debug("img: %s mask: %s, x=%s y= %s", np.sum(image),
                     np.sum(clean_mask), x, y)

        if not sum(img):  # Nothing left after tail cuts
            continue

        muonringparam = muonring.fit(x, y, image * clean_mask)

        dist = np.sqrt(
            np.power(x - muonringparam.ring_center_x, 2) +
            np.power(y - muonringparam.ring_center_y, 2))
        ring_dist = np.abs(dist - muonringparam.ring_radius)

        muonringparam = muonring.fit(
            x, y, img * (ring_dist < muonringparam.ring_radius * 0.4))

        dist = np.sqrt(
            np.power(x - muonringparam.ring_center_x, 2) +
            np.power(y - muonringparam.ring_center_y, 2))
        ring_dist = np.abs(dist - muonringparam.ring_radius)

        muonringparam = muonring.fit(
            x, y, img * (ring_dist < muonringparam.ring_radius * 0.4))

        muonringparam.tel_id = telid
        muonringparam.obs_id = event.dl0.obs_id
        muonringparam.event_id = event.dl0.event_id
        dist_mask = np.abs(
            dist - muonringparam.ring_radius) < muonringparam.ring_radius * 0.4
        pix_im = image * dist_mask
        nom_dist = np.sqrt(
            np.power(muonringparam.ring_center_x, 2) +
            np.power(muonringparam.ring_center_y, 2))

        minpix = muon_cuts['min_pix'][dict_index]  # 0.06*numpix #or 8%

        mir_rad = np.sqrt(teldes.optics.mirror_area.to("m2") / np.pi)

        # Camera containment radius -  better than nothing - guess pixel
        # diameter of 0.11, all cameras are perfectly circular   cam_rad =
        # np.sqrt(numpix*0.11/(2.*np.pi))

        if (npix_above_threshold(pix_im, tailcuts[0]) > 0.1 * minpix
                and npix_composing_ring(pix_im) > minpix
                and nom_dist < muon_cuts['CamRad'][dict_index]
                and muonringparam.ring_radius < 1.5 * u.deg
                and muonringparam.ring_radius > 1. * u.deg):
            muonringparam.ring_containment = ring_containment(
                muonringparam.ring_radius, muon_cuts['CamRad'][dict_index],
                muonringparam.ring_center_x, muonringparam.ring_center_y)

            # Guess HESS is 0.16
            # sec_rad = 0.*u.m
            # sct = False
            # if numpix == 2048 and mir_rad > 2.*u.m and mir_rad < 2.1*u.m:
            #     sec_rad = 1.*u.m
            #     sct = True
            #
            # Store muon ring parameters (passing cuts stage 1)
            # muonringlist[idx] = muonringparam

            tellist.append(telid)
            muonringlist.append(muonringparam)
            muonintensitylist.append(None)

            ctel = MuonLineIntegrate(
                mir_rad,
                hole_radius=muon_cuts['HoleRad'][dict_index],
                pixel_width=muon_cuts['AngPixW'][dict_index],
                sct_flag=muon_cuts['SCT'][dict_index],
                secondary_radius=muon_cuts['SecRad'][dict_index])

            if image.shape[0] == muon_cuts['total_pix'][dict_index]:
                muonintensityoutput = ctel.fit_muon(
                    muonringparam.ring_center_x, muonringparam.ring_center_y,
                    muonringparam.ring_radius, x[dist_mask], y[dist_mask],
                    image[dist_mask])

                muonintensityoutput.tel_id = telid
                muonintensityoutput.obs_id = event.dl0.obs_id
                muonintensityoutput.event_id = event.dl0.event_id
                muonintensityoutput.mask = dist_mask

                idx_ring = np.nonzero(pix_im)
                muonintensityoutput.ring_completeness = ring_completeness(
                    x[idx_ring],
                    y[idx_ring],
                    pix_im[idx_ring],
                    muonringparam.ring_radius,
                    muonringparam.ring_center_x,
                    muonringparam.ring_center_y,
                    threshold=30,
                    bins=30)
                muonintensityoutput.ring_size = np.sum(pix_im)

                dist_ringwidth_mask = np.abs(
                    dist - muonringparam.ring_radius) < (
                        muonintensityoutput.ring_width)
                pix_ringwidth_im = image * dist_ringwidth_mask
                idx_ringwidth = np.nonzero(pix_ringwidth_im)

                muonintensityoutput.ring_pix_completeness = npix_above_threshold(
                    pix_ringwidth_im[idx_ringwidth], tailcuts[0]) / len(
                        pix_im[idx_ringwidth])

                logger.debug(
                    "Tel %d Impact parameter = %s mir_rad=%s "
                    "ring_width=%s", telid,
                    muonintensityoutput.impact_parameter, mir_rad,
                    muonintensityoutput.ring_width)
                conditions = [
                    muonintensityoutput.impact_parameter * u.m <
                    muon_cuts['Impact'][dict_index][1] * mir_rad,
                    muonintensityoutput.impact_parameter >
                    muon_cuts['Impact'][dict_index][0],
                    muonintensityoutput.ring_width <
                    muon_cuts['RingWidth'][dict_index][1],
                    muonintensityoutput.ring_width >
                    muon_cuts['RingWidth'][dict_index][0]
                ]

                if all(conditions):
                    muonintensityparam = muonintensityoutput
                    idx = tellist.index(telid)
                    muonintensitylist[idx] = muonintensityparam
                    logger.debug("Muon found in tel %d,  tels in event=%d",
                                 telid, len(event.dl0.tels_with_data))
                else:
                    continue

    return muon_event_param
Пример #48
0
        """
        fig, axs = plt.subplots(1, 1, figsize=(6, 3))
        d1 = CameraDisplay(camera, ax=axs)

        axs.set_title('Cleaned_Image(fact_cleaning) ' + camera.cam_id)
        d1.image = cleaned1
        plt.show()
        plt.close(fig)
        """
        print("\n time spent in cycle(fact_cleaning)->", finish - start)

        start = datetime.datetime.now()

        clean2 = tailcuts_clean(camera,
                                image,
                                boundary_thresh=boundary,
                                picture_thresh=picture,
                                min_number_picture_neighbors=min_neighbors)

        finish = datetime.datetime.now()

        # display dl1 cleaned images
        cleaned2 = dl1.image.copy()
        cleaned2[~clean2] = 0.0
        """
        fig, axs = plt.subplots(1, 1, figsize=(6, 3))
        d1 = CameraDisplay(camera, ax=axs)

        axs.set_title('Cleaned_Image(tailcuts_cleaning) ' + camera.cam_id)
        d1.image = cleaned2
        plt.show()
Пример #49
0
def plot_muon_event(event, muonparams):
    if muonparams['MuonRingParams'] is not None:

        # Plot the muon event and overlay muon parameters
        fig = plt.figure(figsize=(16, 7))

        colorbar = None
        colorbar2 = None

        subarray = event.inst.subarray

        # for tel_id in event.dl0.tels_with_data:
        for tel_id in muonparams['TelIds']:
            idx = muonparams['TelIds'].index(tel_id)

            if not muonparams['MuonRingParams'][idx]:
                continue

            # otherwise...
            npads = 2
            # Only create two pads if there is timing information extracted
            # from the calibration
            ax1 = fig.add_subplot(1, npads, 1)
            plotter = CameraPlotter(event)
            image = event.dl1.tel[tel_id].image[0]
            geom = event.inst.subarray.tel[tel_id].camera

            tailcuts = (5., 7.)
            # Try a higher threshold for
            if geom.cam_id == 'FlashCam':
                tailcuts = (10., 12.)

            clean_mask = tailcuts_clean(geom, image,
                                        picture_thresh=tailcuts[0],
                                        boundary_thresh=tailcuts[1])

            signals = image * clean_mask

            rotr_angle = geom.pix_rotation
# The following two lines have been commented out to avoid a rotation error.
#            if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam':

#                rotr_angle = 0. * u.deg

            # Convert to camera frame (centre & radius)
            altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az)

            ring_nominal = SkyCoord(
                delta_az=muonparams['MuonRingParams'][idx].ring_center_x,
                delta_alt=muonparams['MuonRingParams'][idx].ring_center_y,
                frame=NominalFrame(origin=altaz)
            )

            flen = subarray.tel[tel_id].optics.equivalent_focal_length
            ring_camcoord = ring_nominal.transform_to(CameraFrame(
                pointing_direction=altaz,
                focal_length=flen,
                rotation=rotr_angle))

            centroid = (ring_camcoord.x.value, ring_camcoord.y.value)

            radius = muonparams['MuonRingParams'][idx].ring_radius
            ringrad_camcoord = 2 * radius.to(u.rad) * flen  # But not FC?

            px = subarray.tel[tel_id].camera.pix_x
            py = subarray.tel[tel_id].camera.pix_y
            camera_coord = SkyCoord(
                x=px,
                y=py,
                frame=CameraFrame(
                    focal_length=flen,
                    rotation=geom.pix_rotation,
                )
            )

            nom_coord = camera_coord.transform_to(
                NominalFrame(origin=altaz)
            )

            px = nom_coord.delta_az.to(u.deg)
            py = nom_coord.delta_alt.to(u.deg)
            dist = np.sqrt(np.power(px - muonparams['MuonRingParams'][idx].ring_center_x,
                                    2) + np.power(py - muonparams['MuonRingParams'][idx].
                                                  ring_center_y, 2))
            ring_dist = np.abs(dist - muonparams['MuonRingParams'][idx].ring_radius)
            pix_rmask = ring_dist < muonparams['MuonRingParams'][idx].ring_radius * 0.4

            if muonparams['MuonIntensityParams'][idx] is not None:
                signals *= muonparams['MuonIntensityParams'][idx].mask
            elif muonparams['MuonIntensityParams'][idx] is None:
                signals *= pix_rmask

            camera1 = plotter.draw_camera(tel_id, signals, ax1)

            cmaxmin = (max(signals) - min(signals))
            cmin = min(signals)
            if not cmin:
                cmin = 1.
            if not cmaxmin:
                cmaxmin = 1.

            cmap_charge = colors.LinearSegmentedColormap.from_list(
                'cmap_c', [(0 / cmaxmin, 'darkblue'),
                           (np.abs(cmin) / cmaxmin, 'black'),
                           (2.0 * np.abs(cmin) / cmaxmin, 'blue'),
                           (2.5 * np.abs(cmin) / cmaxmin, 'green'),
                           (1, 'yellow')]
            )
            camera1.pixels.set_cmap(cmap_charge)
            if not colorbar:
                camera1.add_colorbar(ax=ax1, label=" [photo-electrons]")
                colorbar = camera1.colorbar
            else:
                camera1.colorbar = colorbar
            camera1.update(True)

            camera1.add_ellipse(centroid, ringrad_camcoord.value,
                                ringrad_camcoord.value, 0., 0., color="red")

            if muonparams['MuonIntensityParams'][idx] is not None:

                ringwidthfrac = muonparams['MuonIntensityParams'][idx].ring_width / \
                    muonparams['MuonRingParams'][idx].ring_radius
                ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac)
                ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac)
                camera1.add_ellipse(centroid, ringrad_inner.value,
                                    ringrad_inner.value, 0., 0.,
                                    color="magenta")
                camera1.add_ellipse(centroid, ringrad_outer.value,
                                    ringrad_outer.value, 0., 0.,
                                    color="magenta")
                npads = 2
                ax2 = fig.add_subplot(1, npads, npads)
                pred = muonparams['MuonIntensityParams'][idx].prediction

                if len(pred) != np.sum(
                        muonparams['MuonIntensityParams'][idx].mask):
                    logger.warning("Lengths do not match...len(pred)=%s len("
                                   "mask)=", len(pred),
                                   np.sum(muonparams['MuonIntensityParams'][idx].mask))

                # Numpy broadcasting - fill in the shape
                plotpred = np.zeros(image.shape)
                truelocs = np.where(muonparams['MuonIntensityParams'][idx].mask == True)
                plotpred[truelocs] = pred

                camera2 = plotter.draw_camera(tel_id, plotpred, ax2)

                if np.isnan(max(plotpred)) or np.isnan(min(plotpred)):
                    logger.debug("nan prediction, skipping...")
                    continue

                c2maxmin = (max(plotpred) - min(plotpred))
                if not c2maxmin:
                    c2maxmin = 1.

                c2map_charge = colors.LinearSegmentedColormap.from_list(
                    'c2map_c', [(0 / c2maxmin, 'darkblue'),
                                (np.abs(min(plotpred)) / c2maxmin, 'black'),
                                (
                                2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'),
                                (2.5 * np.abs(min(plotpred)) / c2maxmin,
                                 'green'),
                                (1, 'yellow')]
                )
                camera2.pixels.set_cmap(c2map_charge)
                if not colorbar2:
                    camera2.add_colorbar(ax=ax2, label=" [photo-electrons]")
                    colorbar2 = camera2.colorbar
                else:
                    camera2.colorbar = colorbar2
                camera2.update(True)
                plt.pause(1.)  # make shorter

            # plt.pause(0.1)
            # if pp is not None:
            #    pp.savefig(fig)
            # fig.savefig(str(args.output_path) + "_" +
            #            str(event.dl0.event_id) + '.png')


            plt.close()