Beispiel #1
0
    def test_image_prediction(self):
        pixel_x = np.array([0]) * u.deg
        pixel_y = np.array([0]) * u.deg

        image = np.array([1])
        pixel_area = np.array([1]) * u.deg * u.deg

        self.impact_reco.set_event_properties(
            {1: image}, {1: pixel_x}, {1: pixel_y}, {1: pixel_area},
            {1: "CHEC"}, {1: 0 * u.m}, {1: 0 * u.m},
            array_direction=[0 * u.deg, 0 * u.deg])
        """First check image prediction by directly accessing the function"""
        pred = self.impact_reco.image_prediction("CHEC",
                                                 zenith=0,
                                                 azimuth=0,
                                                 energy=1,
                                                 impact=50,
                                                 x_max=0,
                                                 pix_x=pixel_x,
                                                 pix_y=pixel_y)

        assert np.sum(pred) != 0
        """Then check helper function gives the same answer"""
        shower = ReconstructedShowerContainer()
        shower.is_valid = True
        shower.alt = 0 * u.deg
        shower.az = 0 * u.deg
        shower.core_x = 0 * u.m
        shower.core_y = 100 * u.m
        shower.h_max = 300 + 93 * np.log10(1)

        energy = ReconstructedEnergyContainer()
        energy.is_valid = True
        energy.energy = 1 * u.TeV
        pred2 = self.impact_reco.get_prediction(1,
                                                shower_reco=shower,
                                                energy_reco=energy)
        print(pred, pred2)
        assert pred.all() == pred2.all()
Beispiel #2
0
    def test_image_prediction(self):
        pixel_x = np.array([0]) * u.deg
        pixel_y = np.array([0]) * u.deg

        image = np.array([1])
        pixel_area = np.array([1]) * u.deg * u.deg

        self.impact_reco.set_event_properties({1: image}, {1: pixel_x},
                                              {1: pixel_y}, {1: pixel_area},
                                              {1: "CHEC"}, {1: 0 * u.m},
                                              {1: 0 * u.m},
                                              array_direction=[0 * u.deg,
                                                               0 * u.deg])

        """First check image prediction by directly accessing the function"""
        pred = self.impact_reco.image_prediction("CHEC", zenith=0, azimuth=0,
                                                 energy=1, impact=50, x_max=0,
                                                 pix_x=pixel_x, pix_y=pixel_y)

        assert np.sum(pred) != 0

        """Then check helper function gives the same answer"""
        shower = ReconstructedShowerContainer()
        shower.is_valid = True
        shower.alt = 0 * u.deg
        shower.az = 0 * u.deg
        shower.core_x = 0 * u.m
        shower.core_y = 100 * u.m
        shower.h_max = 300 + 93 * np.log10(1)

        energy = ReconstructedEnergyContainer()
        energy.is_valid = True
        energy.energy = 1 * u.TeV
        pred2 = self.impact_reco.get_prediction(1, shower_reco=shower,
                                                energy_reco=energy)
        print(pred, pred2)
        assert pred.all() == pred2.all()
Beispiel #3
0
    def predict(self, shower_seed, energy_seed):
        """
        Parameters
        ----------
        shower_seed: ReconstructedShowerContainer
            Seed shower geometry to be used in the fit
        energy_seed: ReconstructedEnergyContainer
            Seed energy to be used in fit

        Returns
        -------
        ReconstructedShowerContainer, ReconstructedEnergyContainer:
        Reconstructed ImPACT shower geometry and energy
        """

        horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt)
        nominal_seed = horizon_seed.transform_to(NominalFrame(
            array_direction=self.array_direction))

        source_x = nominal_seed.x.to(u.rad).value
        source_y = nominal_seed.y.to(u.rad).value
        ground = GroundFrame(x=shower_seed.core_x,
                             y=shower_seed.core_y, z=0 * u.m)
        tilted = ground.transform_to(
            TiltedGroundFrame(pointing_direction=self.array_direction)
        )
        tilt_x = tilted.x.to(u.m).value
        tilt_y = tilted.y.to(u.m).value
        zenith = 90 * u.deg - self.array_direction.alt

        if len(self.hillas_parameters) > 3:
            shift = [1]
        else:
            shift = [1.5, 1, 0.5, 0, -0.5, -1, -1.5]

        seed_list = spread_line_seed(self.hillas_parameters,
                                     self.tel_pos_x, self.tel_pos_y,
                                     source_x[0], source_y[0], tilt_x, tilt_y,
                                     energy_seed.energy.value,
                                     shift_frac = shift)

        chosen_seed = self.choose_seed(seed_list)
        # Perform maximum likelihood fit
        fit_params, errors, like = self.minimise(params=chosen_seed[0],
                                                 step=chosen_seed[1],
                                                 limits=chosen_seed[2],
                                                 minimiser_name=self.minimiser_name)

        # Create a container class for reconstructed shower
        shower_result = ReconstructedShowerContainer()

        # Convert the best fits direction and core to Horizon and ground systems and
        # copy to the shower container
        nominal = NominalFrame(x=fit_params[0] * u.rad,
                               y=fit_params[1] * u.rad,
                               array_direction=self.array_direction)
        horizon = nominal.transform_to(HorizonFrame())

        shower_result.alt, shower_result.az = horizon.alt, horizon.az
        tilted = TiltedGroundFrame(x=fit_params[2] * u.m,
                                   y=fit_params[3] * u.m,
                                   pointing_direction=self.array_direction)
        ground = project_to_ground(tilted)

        shower_result.core_x = ground.x
        shower_result.core_y = ground.y

        shower_result.is_valid = True

        # Currently no errors not availible to copy NaN
        shower_result.alt_uncert = np.nan
        shower_result.az_uncert = np.nan
        shower_result.core_uncert = np.nan

        # Copy reconstructed Xmax
        shower_result.h_max = fit_params[5] * self.get_shower_max(fit_params[0],
                                                                  fit_params[1],
                                                                  fit_params[2],
                                                                  fit_params[3],
                                                                  zenith.to(u.rad).value)

        shower_result.h_max *= np.cos(zenith)
        shower_result.h_max_uncert = errors[5] * shower_result.h_max

        shower_result.goodness_of_fit = like

        # Create a container class for reconstructed energy
        energy_result = ReconstructedEnergyContainer()
        # Fill with results
        energy_result.energy = fit_params[4] * u.TeV
        energy_result.energy_uncert = errors[4] * u.TeV
        energy_result.is_valid = True

        return shower_result, energy_result
Beispiel #4
0
    def predict(self, shower_seed, energy_seed):
        """
        Parameters
        ----------
        shower_seed: ReconstructedShowerContainer
            Seed shower geometry to be used in the fit
        energy_seed: ReconstructedEnergyContainer
            Seed energy to be used in fit

        Returns
        -------
        ReconstructedShowerContainer, ReconstructedEnergyContainer:
        Reconstructed ImPACT shower geometry and energy        
        """

        horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt)
        nominal_seed = horizon_seed.transform_to(
            NominalFrame(array_direction=self.array_direction))
        print(nominal_seed)
        print(horizon_seed)
        print(self.array_direction)

        source_x = nominal_seed.x[0].to(u.rad).value
        source_y = nominal_seed.y[0].to(u.rad).value

        ground = GroundFrame(x=shower_seed.core_x,
                             y=shower_seed.core_y,
                             z=0 * u.m)
        tilted = ground.transform_to(
            TiltedGroundFrame(pointing_direction=self.array_direction))
        tilt_x = tilted.x.to(u.m).value
        tilt_y = tilted.y.to(u.m).value

        lower_en_limit = energy_seed.energy * 0.5
        en_seed = energy_seed.energy
        if lower_en_limit < 0.04 * u.TeV:
            lower_en_limit = 0.04 * u.TeV
            en_seed = 0.041 * u.TeV

        seed = (source_x, source_y, tilt_x, tilt_y, en_seed.value, 0.8)
        step = (0.001, 0.001, 10, 10, en_seed.value * 0.1, 0.1)
        limits = ((source_x - 0.01, source_x + 0.01), (source_y - 0.01,
                                                       source_y + 0.01),
                  (tilt_x - 100, tilt_x + 100), (tilt_y - 100, tilt_y + 100),
                  (lower_en_limit.value, en_seed.value * 2), (0.5, 2))

        fit_params, errors = self.minimise(params=seed,
                                           step=step,
                                           limits=limits,
                                           minimiser_name=self.minimiser_name)

        # container class for reconstructed showers '''
        shower_result = ReconstructedShowerContainer()

        nominal = NominalFrame(x=fit_params[0] * u.rad,
                               y=fit_params[1] * u.rad,
                               array_direction=self.array_direction)
        horizon = nominal.transform_to(HorizonFrame())

        shower_result.alt, shower_result.az = horizon.alt, horizon.az
        tilted = TiltedGroundFrame(x=fit_params[2] * u.m,
                                   y=fit_params[3] * u.m,
                                   pointing_direction=self.array_direction)
        ground = project_to_ground(tilted)

        shower_result.core_x = ground.x
        shower_result.core_y = ground.y

        shower_result.is_valid = True

        shower_result.alt_uncert = np.nan
        shower_result.az_uncert = np.nan
        shower_result.core_uncert = np.nan

        zenith = 90 * u.deg - self.array_direction.alt
        shower_result.h_max = fit_params[5] * \
            self.get_shower_max(fit_params[0],
                                fit_params[1],
                                fit_params[2],
                                fit_params[3],
                                zenith.to(u.rad).value)

        shower_result.h_max_uncert = errors[5] * shower_result.h_max

        shower_result.goodness_of_fit = np.nan
        shower_result.tel_ids = list(self.image.keys())

        energy_result = ReconstructedEnergyContainer()
        energy_result.energy = fit_params[4] * u.TeV
        energy_result.energy_uncert = errors[4] * u.TeV
        energy_result.is_valid = True
        energy_result.tel_ids = list(self.image.keys())
        # Return interesting stuff

        return shower_result, energy_result
Beispiel #5
0
    def predict(self, shower_seed, energy_seed):
        """

        Parameters
        ----------
        source_x: float
            Initial guess of source position in the nominal frame
        source_y: float
            Initial guess of source position in the nominal frame
        core_x: float
            Initial guess of the core position in the tilted system
        core_y: float
            Initial guess of the core position in the tilted system
        energy: float
            Initial guess of energy

        Returns
        -------
        Shower object with fit results
        """
        horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt)
        nominal_seed = horizon_seed.transform_to(
            NominalFrame(array_direction=self.array_direction))

        source_x = nominal_seed.x.to(u.rad).value
        source_y = nominal_seed.y.to(u.rad).value

        ground = GroundFrame(x=shower_seed.core_x,
                             y=shower_seed.core_y,
                             z=0 * u.m)
        tilted = ground.transform_to(
            TiltedGroundFrame(pointing_direction=self.array_direction))
        tilt_x = tilted.x.to(u.m).value
        tilt_y = tilted.y.to(u.m).value

        lower_en_limit = energy_seed.energy * 0.1
        if lower_en_limit < 0.04 * u.TeV:
            lower_en_limit = 0.04 * u.TeV
        # Create Minuit object with first guesses at parameters, strip away the
        # units as Minuit doesnt like them
        min = Minuit(self.get_likelihood,
                     print_level=1,
                     source_x=source_x,
                     error_source_x=0.01 / 57.3,
                     fix_source_x=False,
                     limit_source_x=(source_x - 0.5 / 57.3,
                                     source_x + 0.5 / 57.3),
                     source_y=source_y,
                     error_source_y=0.01 / 57.3,
                     fix_source_y=False,
                     limit_source_y=(source_y - 0.5 / 57.3,
                                     source_y + 0.5 / 57.3),
                     core_x=tilt_x,
                     error_core_x=10,
                     limit_core_x=(tilt_x - 200, tilt_x + 200),
                     core_y=tilt_y,
                     error_core_y=10,
                     limit_core_y=(tilt_y - 200, tilt_y + 200),
                     energy=energy_seed.energy.value,
                     error_energy=energy_seed.energy.value * 0.05,
                     limit_energy=(lower_en_limit.value,
                                   energy_seed.energy.value * 10.),
                     x_max_scale=1,
                     error_x_max_scale=0.1,
                     limit_x_max_scale=(0.5, 2),
                     fix_x_max_scale=False,
                     errordef=1)

        min.tol *= 1000
        min.strategy = 0

        # Perform minimisation
        migrad = min.migrad()
        fit_params = min.values
        errors = min.errors
        #    print(migrad)
        #    print(min.minos())

        # container class for reconstructed showers '''
        shower_result = ReconstructedShowerContainer()

        nominal = NominalFrame(x=fit_params["source_x"] * u.rad,
                               y=fit_params["source_y"] * u.rad,
                               array_direction=self.array_direction)
        horizon = nominal.transform_to(HorizonFrame())

        shower_result.alt, shower_result.az = horizon.alt, horizon.az
        tilted = TiltedGroundFrame(x=fit_params["core_x"] * u.m,
                                   y=fit_params["core_y"] * u.m,
                                   pointing_direction=self.array_direction)
        ground = project_to_ground(tilted)

        shower_result.core_x = ground.x
        shower_result.core_y = ground.y

        shower_result.is_valid = True

        shower_result.alt_uncert = np.nan
        shower_result.az_uncert = np.nan
        shower_result.core_uncert = np.nan
        zenith = 90 * u.deg - self.array_direction[0]
        shower_result.h_max = fit_params["x_max_scale"] * \
            self.get_shower_max(fit_params["source_x"],
                                fit_params["source_y"],
                                fit_params["core_x"],
                                fit_params["core_y"],
                                zenith.to(u.rad).value)
        shower_result.h_max_uncert = errors["x_max_scale"] * shower_result.h_max
        shower_result.goodness_of_fit = np.nan
        shower_result.tel_ids = list(self.image.keys())

        energy_result = ReconstructedEnergyContainer()
        energy_result.energy = fit_params["energy"] * u.TeV
        energy_result.energy_uncert = errors["energy"] * u.TeV
        energy_result.is_valid = True
        energy_result.tel_ids = list(self.image.keys())
        # Return interesting stuff

        return shower_result, energy_result
Beispiel #6
0
    def predict(self, shower_seed, energy_seed):
        """
        
        Parameters
        ----------
        shower_seed: ReconstructedShowerContainer
            Seed shower geometry to be used in the fit
        energy_seed: ReconstructedEnergyContainer
            Seed energy to be used in fit

        Returns
        -------
        ReconstructedShowerContainer, ReconstructedEnergyContainer:
        Reconstructed ImPACT shower geometry and energy
        
        """
        horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt)
        nominal_seed = horizon_seed.transform_to(NominalFrame(array_direction=self.array_direction))
        print(nominal_seed)
        print(horizon_seed)
        print(self.array_direction)

        source_x = nominal_seed.x[0].to(u.rad).value
        source_y = nominal_seed.y[0].to(u.rad).value

        ground = GroundFrame(x=shower_seed.core_x,
                             y=shower_seed.core_y, z=0 * u.m)
        tilted = ground.transform_to(
            TiltedGroundFrame(pointing_direction=self.array_direction)
        )
        tilt_x = tilted.x.to(u.m).value
        tilt_y = tilted.y.to(u.m).value

        lower_en_limit = energy_seed.energy * 0.5
        en_seed =  energy_seed.energy
        if lower_en_limit < 0.04 * u.TeV:
            lower_en_limit = 0.04 * u.TeV
            en_seed = 0.041 * u.TeV

        seed = (source_x, source_y, tilt_x,
                tilt_y, en_seed.value, 0.8)
        step = (0.001, 0.001, 10, 10, en_seed.value*0.1, 0.1)
        limits = ((source_x-0.01, source_x+0.01),
                  (source_y-0.01, source_y+0.01),
                  (tilt_x-100, tilt_x+100),
                  (tilt_y-100, tilt_y+100),
                  (lower_en_limit.value, en_seed.value*2),
                  (0.5,2))

        fit_params, errors = self.minimise(params=seed, step=step, limits=limits,
                                             minimiser_name=self.minimiser_name)

        # container class for reconstructed showers '''
        shower_result = ReconstructedShowerContainer()

        nominal = NominalFrame(x=fit_params[0] * u.rad,
                               y=fit_params[1] * u.rad,
                               array_direction=self.array_direction)
        horizon = nominal.transform_to(HorizonFrame())

        shower_result.alt, shower_result.az = horizon.alt, horizon.az
        tilted = TiltedGroundFrame(x=fit_params[2] * u.m,
                                   y=fit_params[3] * u.m,
                                   pointing_direction=self.array_direction)
        ground = project_to_ground(tilted)

        shower_result.core_x = ground.x
        shower_result.core_y = ground.y

        shower_result.is_valid = True

        shower_result.alt_uncert = np.nan
        shower_result.az_uncert = np.nan
        shower_result.core_uncert = np.nan

        zenith = 90*u.deg - self.array_direction.alt
        shower_result.h_max = fit_params[5] * \
                              self.get_shower_max(fit_params[0],
                                                  fit_params[1],
                                                  fit_params[2],
                                                  fit_params[3],
                                                  zenith.to(u.rad).value)

        shower_result.h_max_uncert = errors[5] * shower_result.h_max

        shower_result.goodness_of_fit = np.nan
        shower_result.tel_ids = list(self.image.keys())

        energy_result = ReconstructedEnergyContainer()
        energy_result.energy = fit_params[4] * u.TeV
        energy_result.energy_uncert = errors[4] * u.TeV
        energy_result.is_valid = True
        energy_result.tel_ids = list(self.image.keys())
        # Return interesting stuff

        return shower_result, energy_result
Beispiel #7
0
    def predict(self, shower_seed, energy_seed):
        """Predict method for the ImPACT reconstructor.
        Used to calculate the reconstructed ImPACT shower geometry and energy.

        Parameters
        ----------
        shower_seed: ReconstructedShowerContainer
            Seed shower geometry to be used in the fit
        energy_seed: ReconstructedEnergyContainer
            Seed energy to be used in fit

        Returns
        -------
        ReconstructedShowerContainer, ReconstructedEnergyContainer:
        """
        self.reset_interpolator()

        horizon_seed = SkyCoord(az=shower_seed.az,
                                alt=shower_seed.alt,
                                frame=AltAz())
        nominal_seed = horizon_seed.transform_to(self.nominal_frame)

        source_x = nominal_seed.delta_az.to_value(u.rad)
        source_y = nominal_seed.delta_alt.to_value(u.rad)
        ground = GroundFrame(x=shower_seed.core_x,
                             y=shower_seed.core_y,
                             z=0 * u.m)
        tilted = ground.transform_to(
            TiltedGroundFrame(pointing_direction=self.array_direction))
        tilt_x = tilted.x.to(u.m).value
        tilt_y = tilted.y.to(u.m).value
        zenith = 90 * u.deg - self.array_direction.alt

        seeds = spread_line_seed(self.hillas_parameters,
                                 self.tel_pos_x,
                                 self.tel_pos_y,
                                 source_x,
                                 source_y,
                                 tilt_x,
                                 tilt_y,
                                 energy_seed.energy.value,
                                 shift_frac=[1])[0]

        # Perform maximum likelihood fit
        fit_params, errors, like = self.minimise(
            params=seeds[0],
            step=seeds[1],
            limits=seeds[2],
            minimiser_name=self.minimiser_name)

        # Create a container class for reconstructed shower
        shower_result = ReconstructedShowerContainer()

        # Convert the best fits direction and core to Horizon and ground systems and
        # copy to the shower container
        nominal = SkyCoord(delta_az=fit_params[0] * u.rad,
                           delta_alt=fit_params[1] * u.rad,
                           frame=self.nominal_frame)
        horizon = nominal.transform_to(AltAz())

        shower_result.alt, shower_result.az = horizon.alt, horizon.az
        tilted = TiltedGroundFrame(x=fit_params[2] * u.m,
                                   y=fit_params[3] * u.m,
                                   pointing_direction=self.array_direction)
        ground = project_to_ground(tilted)

        shower_result.core_x = ground.x
        shower_result.core_y = ground.y

        shower_result.is_valid = True

        # Currently no errors not available to copy NaN
        shower_result.alt_uncert = np.nan
        shower_result.az_uncert = np.nan
        shower_result.core_uncert = np.nan

        # Copy reconstructed Xmax
        shower_result.h_max = fit_params[5] * self.get_shower_max(
            fit_params[0], fit_params[1], fit_params[2], fit_params[3],
            zenith.to(u.rad).value)

        shower_result.h_max *= np.cos(zenith)
        shower_result.h_max_uncert = errors[5] * shower_result.h_max

        shower_result.goodness_of_fit = like

        # Create a container class for reconstructed energy
        energy_result = ReconstructedEnergyContainer()
        # Fill with results
        energy_result.energy = fit_params[4] * u.TeV
        energy_result.energy_uncert = errors[4] * u.TeV
        energy_result.is_valid = True

        return shower_result, energy_result
Beispiel #8
0
    def predict(self, shower_seed, energy_seed):
        """
        Parameters
        ----------
        shower_seed: ReconstructedShowerContainer
            Seed shower geometry to be used in the fit
        energy_seed: ReconstructedEnergyContainer
            Seed energy to be used in fit

        Returns
        -------
        ReconstructedShowerContainer, ReconstructedEnergyContainer:
        Reconstructed ImPACT shower geometry and energy
        """

        horizon_seed = SkyCoord(
            az=shower_seed.az, alt=shower_seed.alt, frame=HorizonFrame()
        )
        nominal_seed = horizon_seed.transform_to(
            NominalFrame(origin=self.array_direction)
        )

        source_x = nominal_seed.delta_az.to_value(u.rad)
        source_y = nominal_seed.delta_alt.to_value(u.rad)
        ground = GroundFrame(x=shower_seed.core_x,
                             y=shower_seed.core_y, z=0 * u.m)
        tilted = ground.transform_to(
            TiltedGroundFrame(pointing_direction=self.array_direction)
        )
        tilt_x = tilted.x.to(u.m).value
        tilt_y = tilted.y.to(u.m).value
        zenith = 90 * u.deg - self.array_direction.alt

        if len(self.hillas_parameters) > 3:
            shift = [1]
        else:
            shift = [1.5, 1, 0.5, 0, -0.5, -1, -1.5]

        seed_list = spread_line_seed(self.hillas_parameters,
                                     self.tel_pos_x, self.tel_pos_y,
                                     source_x[0], source_y[0], tilt_x, tilt_y,
                                     energy_seed.energy.value,
                                     shift_frac = shift)

        chosen_seed = self.choose_seed(seed_list)
        # Perform maximum likelihood fit
        fit_params, errors, like = self.minimise(params=chosen_seed[0],
                                                 step=chosen_seed[1],
                                                 limits=chosen_seed[2],
                                                 minimiser_name=self.minimiser_name)

        # Create a container class for reconstructed shower
        shower_result = ReconstructedShowerContainer()

        # Convert the best fits direction and core to Horizon and ground systems and
        # copy to the shower container
        nominal = SkyCoord(
            x=fit_params[0] * u.rad,
            y=fit_params[1] * u.rad,
            frame=NominalFrame(origin=self.array_direction)
        )
        horizon = nominal.transform_to(HorizonFrame())

        shower_result.alt, shower_result.az = horizon.alt, horizon.az
        tilted = TiltedGroundFrame(
            x=fit_params[2] * u.m,
            y=fit_params[3] * u.m,
            pointing_direction=self.array_direction
        )
        ground = project_to_ground(tilted)

        shower_result.core_x = ground.x
        shower_result.core_y = ground.y

        shower_result.is_valid = True

        # Currently no errors not availible to copy NaN
        shower_result.alt_uncert = np.nan
        shower_result.az_uncert = np.nan
        shower_result.core_uncert = np.nan

        # Copy reconstructed Xmax
        shower_result.h_max = fit_params[5] * self.get_shower_max(fit_params[0],
                                                                  fit_params[1],
                                                                  fit_params[2],
                                                                  fit_params[3],
                                                                  zenith.to(u.rad).value)

        shower_result.h_max *= np.cos(zenith)
        shower_result.h_max_uncert = errors[5] * shower_result.h_max

        shower_result.goodness_of_fit = like

        # Create a container class for reconstructed energy
        energy_result = ReconstructedEnergyContainer()
        # Fill with results
        energy_result.energy = fit_params[4] * u.TeV
        energy_result.energy_uncert = errors[4] * u.TeV
        energy_result.is_valid = True

        return shower_result, energy_result
Beispiel #9
0
    def predict(self, shower_seed, energy_seed):
        """

        Parameters
        ----------
        source_x: float
            Initial guess of source position in the nominal frame
        source_y: float
            Initial guess of source position in the nominal frame
        core_x: float
            Initial guess of the core position in the tilted system
        core_y: float
            Initial guess of the core position in the tilted system
        energy: float
            Initial guess of energy

        Returns
        -------
        Shower object with fit results
        """
        horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt)
        nominal_seed = horizon_seed.transform_to(
            NominalFrame(array_direction=self.array_direction)
        )

        source_x = nominal_seed.x.to(u.rad).value
        source_y = nominal_seed.y.to(u.rad).value

        ground = GroundFrame(x=shower_seed.core_x,
                             y=shower_seed.core_y, z=0 * u.m)
        tilted = ground.transform_to(
            TiltedGroundFrame(pointing_direction=self.array_direction)
        )
        tilt_x = tilted.x.to(u.m).value
        tilt_y = tilted.y.to(u.m).value

        lower_en_limit = energy_seed.energy * 0.1
        if lower_en_limit < 0.04 * u.TeV:
            lower_en_limit = 0.04 * u.TeV
        # Create Minuit object with first guesses at parameters, strip away the
        # units as Minuit doesnt like them
        min = Minuit(self.get_likelihood,
                     print_level=1,
                     source_x=source_x,
                     error_source_x=0.01 / 57.3,
                     fix_source_x=False,
                     limit_source_x=(source_x - 0.5 / 57.3,
                                     source_x + 0.5 / 57.3),
                     source_y=source_y,
                     error_source_y=0.01 / 57.3,
                     fix_source_y=False,
                     limit_source_y=(source_y - 0.5 / 57.3,
                                     source_y + 0.5 / 57.3),
                     core_x=tilt_x,
                     error_core_x=10,
                     limit_core_x=(tilt_x - 200, tilt_x + 200),
                     core_y=tilt_y,
                     error_core_y=10,
                     limit_core_y=(tilt_y - 200, tilt_y + 200),
                     energy=energy_seed.energy.value,
                     error_energy=energy_seed.energy.value * 0.05,
                     limit_energy=(lower_en_limit.value,
                                   energy_seed.energy.value * 10.),
                     x_max_scale=1, error_x_max_scale=0.1,
                     limit_x_max_scale=(0.5, 2),
                     fix_x_max_scale=False,
                     errordef=1)

        min.tol *= 1000
        min.strategy = 0

        # Perform minimisation
        migrad = min.migrad()
        fit_params = min.values
        errors = min.errors
    #    print(migrad)
    #    print(min.minos())

        # container class for reconstructed showers '''
        shower_result = ReconstructedShowerContainer()

        nominal = NominalFrame(x=fit_params["source_x"] * u.rad,
                               y=fit_params["source_y"] * u.rad,
                               array_direction=self.array_direction)
        horizon = nominal.transform_to(HorizonFrame())

        shower_result.alt, shower_result.az = horizon.alt, horizon.az
        tilted = TiltedGroundFrame(x=fit_params["core_x"] * u.m,
                                   y=fit_params["core_y"] * u.m,
                                   pointing_direction=self.array_direction)
        ground = project_to_ground(tilted)

        shower_result.core_x = ground.x
        shower_result.core_y = ground.y

        shower_result.is_valid = True

        shower_result.alt_uncert = np.nan
        shower_result.az_uncert = np.nan
        shower_result.core_uncert = np.nan
        zenith = 90 * u.deg - self.array_direction[0]
        shower_result.h_max = fit_params["x_max_scale"] * \
            self.get_shower_max(fit_params["source_x"],
                                fit_params["source_y"],
                                fit_params["core_x"],
                                fit_params["core_y"],
                                zenith.to(u.rad).value)
        shower_result.h_max_uncert = errors["x_max_scale"] * shower_result.h_max
        shower_result.goodness_of_fit = np.nan
        shower_result.tel_ids = list(self.image.keys())

        energy_result = ReconstructedEnergyContainer()
        energy_result.energy = fit_params["energy"] * u.TeV
        energy_result.energy_uncert = errors["energy"] * u.TeV
        energy_result.is_valid = True
        energy_result.tel_ids = list(self.image.keys())
        # Return interesting stuff

        return shower_result, energy_result
Beispiel #10
0
    def reconstruct_event(self, event):
        """
        Perform full event reconstruction, including Hillas and ImPACT analysis.
        
        Parameters
        ----------
        event: ctapipe event container

        Returns
        -------
            None
        """
        # store MC pointing direction for the array
        array_pointing = HorizonFrame(alt = event.mcheader.run_array_direction[1]*u.rad,
                                      az = event.mcheader.run_array_direction[0]*u.rad)
        tilted_system = TiltedGroundFrame(pointing_direction=array_pointing)

        image = {}
        pixel_x = {}
        pixel_y = {}
        pixel_area = {}
        tel_type = {}
        tel_x = {}
        tel_y = {}

        hillas = {}
        hillas_nom = {}
        image_pred = {}
        mask_dict = {}
        

        Gate_dict = {}
        Nectar_dict = {}
        LST_dict ={}
        dict_list=[]

        for tel_id in event.dl0.tels_with_data:
            # Get calibrated image (low gain channel only)
            pmt_signal = event.dl1.tel[tel_id].image[0]

            # Create nominal system for the telescope (this should later used 
            #telescope pointing)
            nom_system = NominalFrame(array_direction=array_pointing,
                                      pointing_direction=array_pointing)

            # Create camera system of all pixels
            pix_x, pix_y = event.inst.pixel_pos[tel_id]
            fl = event.inst.optical_foclen[tel_id]
            if tel_id not in self.geoms:
                self.geoms[tel_id] = CameraGeometry.guess(pix_x, pix_y,
                                                          event.inst.optical_foclen[ tel_id],
                                                          apply_derotation=False)


            # Transform the pixels positions into nominal coordinates
            camera_coord = CameraFrame(x=pix_x, y=pix_y,
                                       z=np.zeros(pix_x.shape) * u.m,
                                       focal_length=fl,
                                       rotation= -1* self.geoms[tel_id].cam_rotation)

            nom_coord = camera_coord.transform_to(nom_system)
            tx, ty, tz = event.inst.tel_pos[tel_id]

            # ImPACT reconstruction is performed in the tilted system,
            # so we need to transform tel positions
            grd_tel = GroundFrame(x=tx, y=ty, z=tz)
            tilt_tel = grd_tel.transform_to(tilted_system)

            # Clean image using split level cleaning
            mask = tailcuts_clean(self.geoms[tel_id], pmt_signal,
                                  picture_thresh=self.tail_cut[self.geoms[
                                      tel_id].cam_id][1],
                                  boundary_thresh=self.tail_cut[self.geoms[
                                      tel_id].cam_id][0])

            # Perform Hillas parameterisation
            moments = None
            try:
                moments_cam = hillas_parameters(event.inst.pixel_pos[tel_id][0],
                                            event.inst.pixel_pos[tel_id][1],
                                            pmt_signal*mask)

                moments = hillas_parameters(nom_coord.x, nom_coord.y,pmt_signal*mask)

            except HillasParameterizationError as e:
                print(e)
                continue

            # Make cut based on Hillas parameters
            if self.preselect(moments, np.sum(mask), tel_id):

                # Dialte around edges of image
                for i in range(3):
                    mask = dilate(self.geoms[tel_id], mask)

                # Save everything in dicts for reconstruction later
                pixel_area[tel_id] = self.geoms[tel_id].pix_area/(fl*fl)
                pixel_area[tel_id] *= u.rad*u.rad
                pixel_x[tel_id] = nom_coord.x[mask]
                pixel_y[tel_id] = nom_coord.y[mask]

                tel_x[tel_id] = tilt_tel.x
                tel_y[tel_id] = tilt_tel.y

                tel_type[tel_id] = self.geoms[tel_id].cam_id
                image[tel_id] = pmt_signal[mask]
                image_pred[tel_id] = np.zeros(pmt_signal.shape)

                hillas[tel_id] = moments_cam
                hillas_nom[tel_id] = moments
                mask_dict[tel_id] = mask
                
            
                cam_id = self.geoms[tel_id].cam_id
                print (cam_id)

                mom=[moments.size, tilt_tel, moments.width/u.rad,
                     moments.length/u.rad]
                
                if (cam_id == 'LSTCam'):
                    try:
                        LST_dict[cam_id].append(mom)
                    except:
                        LST_dict.update({'LSTCam':[mom]})
                elif (cam_id =='NectarCam'):
                    try:
                        Nectar_dict['NectarCam'].append(mom)
                    except:
                        Nectar_dict.update({'NectarCam':[mom]})
                elif (cam_id =='CHEC'):
                    try:
                        Gate_dict[cam_id].append(mom)
                    except:
                        Gate_dict.update({'CHEC':[mom]})
                else:
                    print (cam_id +': Type not known')

        #################################################
        # Cut on number of telescopes remaining
        if len(image)>1:
            fit_result = self.fit.predict(hillas_nom, tel_x, 
                                          tel_y, array_pointing)
            
            core_pos_grd = GroundFrame(x=fit_result.core_x,y=fit_result.core_y,
                                       z=0*u.m)
            core_pos_tilt = core_pos_grd.transform_to(tilted_system)

            coredist=np.sqrt(core_pos_grd.x**2+core_pos_grd.y**2)
            
            dict_list=np.array([])
            if len(LST_dict) != 0:
                for i in range (0,len(LST_dict['LSTCam'])):
                    LST_dict['LSTCam'][i][1]= LST_dict['LSTCam'][i][1].separation_3d(core_pos_tilt).to(u.m)/u.m
                dict_list=np.append(dict_list,LST_dict)
            if len(Nectar_dict) != 0:
                for i in range(0,len(Nectar_dict['NectarCam'])):
                    Nectar_dict['NectarCam'][i][1]= Nectar_dict['NectarCam'][i][1].separation_3d(core_pos_tilt).to(u.m) /u.m
                dict_list=np.append(dict_list,Nectar_dict)
            if len(Gate_dict) !=0:
                for i in range(0, len(Gate_dict['CHEC'])):
                    Gate_dict['CHEC'][i][1]= Gate_dict['CHEC'][i][1].separation_3d(core_pos_tilt).to(u.m) /u.m
                dict_list=np.append(dict_list,Gate_dict)

            energy_result = self.energy_reco.predict_by_event(dict_list)

            print('Fit results and Energy results')
            print(energy_result)
            print ('__________________________')

            # Perform ImPACT reconstruction
            self.ImPACT.set_event_properties(image, pixel_x, pixel_y, 
                                             pixel_area, tel_type, tel_x, 
                                             tel_y, array_pointing, hillas_nom)

            energy_seed=ReconstructedEnergyContainer()
            
            energy_seed.energy=np.mean(np.power(10,energy_result['mean'].value)) * u.TeV
            energy_seed.energy_uncert=np.mean(energy_result['std'])
            energy_seed.is_valid = True
            energy_seed.tel_ids= event.dl0.tels_with_data



            ImPACT_shower, ImPACT_energy = self.ImPACT.predict(fit_result, energy_seed)

            print(ImPACT_energy)
            # insert the row into the table
            self.output.add_row((event.dl0.event_id, ImPACT_shower.alt,
                                 ImPACT_shower.az, ImPACT_energy.energy, 
                                 fit_result.alt, fit_result.az, 
                                 np.mean(np.power(10,energy_result['mean'].value)),  
                                 ImPACT_shower.goodness_of_fit,
                                 event.mc.alt, event.mc.az, event.mc.energy, 
                                 len(image),coredist))