def test_intersection_weighting_spoiled_parameters(): """ Test that the weighting scheme is useful especially when a telescope is 90 deg with respect to the other two """ hill_inter = HillasIntersection() delta = 100 * u.m tel_x_dict = {1: delta, 2: -delta, 3: -delta} tel_y_dict = {1: delta, 2: delta, 3: -delta} # telescope 2 have a spoiled reconstruction (45 instead of -45) hillas_dict = { 1: HillasParametersContainer(intensity=10000, psi=-90 * u.deg), 2: HillasParametersContainer(intensity=1, psi=45 * u.deg), 3: HillasParametersContainer(intensity=10000, psi=0 * u.deg), } reco_konrad_spoiled = hill_inter.reconstruct_tilted( hillas_parameters=hillas_dict, tel_x=tel_x_dict, tel_y=tel_y_dict) np.testing.assert_allclose(reco_konrad_spoiled[0], delta.to_value(u.m), atol=1e-1) np.testing.assert_allclose(reco_konrad_spoiled[1], -delta.to_value(u.m), atol=1e-1)
def test_intersection_reco_impact_point_tilted(): """ Function to test the reconstruction of the impact point in the tilted frame. This is done using a squared configuration, of which the impact point occupies a vertex, ad the three telescopes the other three vertices. """ hill_inter = HillasIntersection() delta = 100 * u.m tel_x_dict = {1: delta, 2: -delta, 3: -delta} tel_y_dict = {1: delta, 2: delta, 3: -delta} hillas_dict = { 1: HillasParametersContainer(intensity=100, psi=-90 * u.deg), 2: HillasParametersContainer(intensity=100, psi=-45 * u.deg), 3: HillasParametersContainer(intensity=100, psi=0 * u.deg) } reco_konrad = hill_inter.reconstruct_tilted( hillas_parameters=hillas_dict, tel_x=tel_x_dict, tel_y=tel_y_dict ) np.testing.assert_allclose(reco_konrad[0], delta.to_value(u.m), atol=1e-8) np.testing.assert_allclose(reco_konrad[1], -delta.to_value(u.m), atol=1e-8)
def test_intersection_nominal_reconstruction(): """ Testing the reconstruction of the position in the nominal frame with a three-telescopes system. This is done using a squared configuration, of which the impact point occupies a vertex, ad the three telescopes the other three vertices. """ hill_inter = HillasIntersection() delta = 1.0 * u.m horizon_frame = AltAz() altitude = 70 * u.deg azimuth = 10 * u.deg array_direction = SkyCoord(alt=altitude, az=azimuth, frame=horizon_frame) nominal_frame = NominalFrame(origin=array_direction) focal_length = 28 * u.m camera_frame = CameraFrame(focal_length=focal_length, telescope_pointing=array_direction) cog_coords_camera_1 = SkyCoord(x=delta, y=0 * u.m, frame=camera_frame) cog_coords_camera_2 = SkyCoord(x=delta / 0.7, y=delta / 0.7, frame=camera_frame) cog_coords_camera_3 = SkyCoord(x=0 * u.m, y=delta, frame=camera_frame) cog_coords_nom_1 = cog_coords_camera_1.transform_to(nominal_frame) cog_coords_nom_2 = cog_coords_camera_2.transform_to(nominal_frame) cog_coords_nom_3 = cog_coords_camera_3.transform_to(nominal_frame) # x-axis is along the altitude and y-axis is along the azimuth hillas_1 = HillasParametersContainer(x=cog_coords_nom_1.delta_alt, y=cog_coords_nom_1.delta_az, intensity=100, psi=0 * u.deg) hillas_2 = HillasParametersContainer(x=cog_coords_nom_2.delta_alt, y=cog_coords_nom_2.delta_az, intensity=100, psi=45 * u.deg) hillas_3 = HillasParametersContainer(x=cog_coords_nom_3.delta_alt, y=cog_coords_nom_3.delta_az, intensity=100, psi=90 * u.deg) hillas_dict = {1: hillas_1, 2: hillas_2, 3: hillas_3} reco_nominal = hill_inter.reconstruct_nominal(hillas_parameters=hillas_dict) nominal_pos = SkyCoord( delta_az=u.Quantity(reco_nominal[0], u.rad), delta_alt=u.Quantity(reco_nominal[1], u.rad), frame=nominal_frame ) np.testing.assert_allclose(nominal_pos.altaz.az.to_value(u.deg), azimuth.to_value(u.deg), atol=1e-8) np.testing.assert_allclose(nominal_pos.altaz.alt.to_value(u.deg), altitude.to_value(u.deg), atol=1e-8)
def test_array_display(): """ check that we can do basic array display functionality """ from ctapipe.visualization.mpl_array import ArrayDisplay from ctapipe.image import timing_parameters # build a test subarray: tels = dict() tel_pos = dict() for ii, pos in enumerate([[0, 0, 0], [100, 0, 0], [-100, 0, 0]] * u.m): tels[ii + 1] = TelescopeDescription.from_name("MST", "NectarCam") tel_pos[ii + 1] = pos sub = SubarrayDescription(name="TestSubarray", tel_positions=tel_pos, tel_descriptions=tels) ad = ArrayDisplay(sub) ad.set_vector_rho_phi(1 * u.m, 90 * u.deg) # try setting a value vals = ones(sub.num_tels) ad.values = vals assert (vals == ad.values).all() # test using hillas params: hillas_dict = { 1: HillasParametersContainer(length=100.0 * u.m, psi=90 * u.deg), 2: HillasParametersContainer(length=20000 * u.cm, psi="95deg"), } grad = 2 intercept = 1 geom = CameraGeometry.from_name("LSTCam") rot_angle = 20 * u.deg hillas = HillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=rot_angle) timing_rot20 = timing_parameters( geom, image=ones(geom.n_pixels), peak_time=intercept + grad * geom.pix_x.value, hillas_parameters=hillas, cleaning_mask=ones(geom.n_pixels, dtype=bool), ) gradient_dict = { 1: timing_rot20.slope.value, 2: timing_rot20.slope.value, } ad.set_vector_hillas( hillas_dict=hillas_dict, length=500, time_gradient=gradient_dict, angle_offset=0 * u.deg, ) ad.set_line_hillas(hillas_dict, range=300) ad.add_labels() ad.remove_labels()
def test_intersection_xmax_reco(): """ Test the reconstruction of xmax with two LSTs that are pointing at zenith = 0. The telescopes are places along the x and y axis at the same distance from the center. The impact point is hard-coded to be happening in the center of this cartesian system. """ hill_inter = HillasIntersection() horizon_frame = AltAz() zen_pointing = 10 * u.deg array_direction = SkyCoord(alt=90 * u.deg - zen_pointing, az=0 * u.deg, frame=horizon_frame) nom_frame = NominalFrame(origin=array_direction) source_sky_pos_reco = SkyCoord(alt=90 * u.deg - zen_pointing, az=0 * u.deg, frame=horizon_frame) nom_pos_reco = source_sky_pos_reco.transform_to(nom_frame) delta = 1.0 * u.m # LST focal length focal_length = 28 * u.m hillas_dict = { 1: HillasParametersContainer( x=-(delta / focal_length) * u.rad, y=((0 * u.m) / focal_length) * u.rad, intensity=1, ), 2: HillasParametersContainer( x=((0 * u.m) / focal_length) * u.rad, y=-(delta / focal_length) * u.rad, intensity=1, ), } x_max = hill_inter.reconstruct_xmax( source_x=nom_pos_reco.fov_lon, source_y=nom_pos_reco.fov_lat, core_x=0 * u.m, core_y=0 * u.m, hillas_parameters=hillas_dict, tel_x={ 1: (150 * u.m), 2: (0 * u.m) }, tel_y={ 1: (0 * u.m), 2: (150 * u.m) }, zen=zen_pointing, ) print(x_max)
def test_read_without_prefixes(tmp_path): path = tmp_path / "test.h5" hillas_parameter_container = HillasParametersContainer(fov_lon=1 * u.deg, fov_lat=1 * u.deg, length=1 * u.deg, width=1 * u.deg) leakage_container = LeakageContainer( pixels_width_1=0.1, pixels_width_2=0.1, intensity_width_1=0.1, intensity_width_2=0.1, ) with HDF5TableWriter(path, group_name="dl1", add_prefix=False) as writer: writer.write("params", (hillas_parameter_container, leakage_container)) df = pd.read_hdf(path, key="/dl1/params") assert "fov_lon" in df.columns assert "pixels_width_1" in df.columns # call with prefixes=False with HDF5TableReader(path) as reader: generator = reader.read( "/dl1/params", (HillasParametersContainer, LeakageContainer), prefixes=False, ) hillas_, leakage_ = next(generator) for value, read_value in zip(leakage_container.as_dict().values(), leakage_.as_dict().values()): np.testing.assert_equal(value, read_value) for value, read_value in zip(hillas_parameter_container.as_dict().values(), hillas_.as_dict().values()): np.testing.assert_equal(value, read_value) # call with manually removed prefixes with HDF5TableReader(path) as reader: generator = reader.read( "/dl1/params", (HillasParametersContainer, LeakageContainer), prefixes=["", ""], ) hillas_, leakage_ = next(generator) for value, read_value in zip(leakage_container.as_dict().values(), leakage_.as_dict().values()): np.testing.assert_equal(value, read_value) for value, read_value in zip(hillas_parameter_container.as_dict().values(), hillas_.as_dict().values()): np.testing.assert_equal(value, read_value)
def test_read_multiple_containers(tmp_path): path = tmp_path / "test_append.h5" hillas_parameter_container = HillasParametersContainer(fov_lon=1 * u.deg, fov_lat=1 * u.deg, length=1 * u.deg, width=1 * u.deg) leakage_container = LeakageContainer( pixels_width_1=0.1, pixels_width_2=0.1, intensity_width_1=0.1, intensity_width_2=0.1, ) with HDF5TableWriter(path, group_name="dl1", add_prefix=True) as writer: writer.write("params", [hillas_parameter_container, leakage_container]) df = pd.read_hdf(path, key="/dl1/params") assert "hillas_fov_lon" in df.columns assert "leakage_pixels_width_1" in df.columns # test reading both containers separately with HDF5TableReader(path) as reader: generator = reader.read("/dl1/params", HillasParametersContainer, prefixes=True) hillas = next(generator) for value, read_value in zip(hillas_parameter_container.as_dict().values(), hillas.as_dict().values()): np.testing.assert_equal(value, read_value) with HDF5TableReader(path) as reader: generator = reader.read("/dl1/params", LeakageContainer, prefixes=True) leakage = next(generator) for value, read_value in zip(leakage_container.as_dict().values(), leakage.as_dict().values()): np.testing.assert_equal(value, read_value) # test reading both containers simultaneously with HDF5TableReader(path) as reader: generator = reader.read( "/dl1/params", (HillasParametersContainer, LeakageContainer), prefixes=True, ) hillas_, leakage_ = next(generator) for value, read_value in zip(leakage_container.as_dict().values(), leakage_.as_dict().values()): np.testing.assert_equal(value, read_value) for value, read_value in zip(hillas_parameter_container.as_dict().values(), hillas_.as_dict().values()): np.testing.assert_equal(value, read_value)
def test_read_duplicated_container_types(tmp_path): path = tmp_path / "test.h5" hillas_config_1 = HillasParametersContainer( x=1 * u.m, y=2 * u.m, length=3 * u.m, width=4 * u.m, prefix="hillas_1" ) hillas_config_2 = HillasParametersContainer( x=2 * u.m, y=3 * u.m, length=4 * u.m, width=5 * u.m, prefix="hillas_2" ) with HDF5TableWriter(path, group_name="dl1", add_prefix=True) as writer: writer.write("params", [hillas_config_1, hillas_config_2]) df = pd.read_hdf(path, key="/dl1/params") assert "hillas_1_x" in df.columns assert "hillas_2_x" in df.columns with HDF5TableReader(path) as reader: generator = reader.read( "/dl1/params", [HillasParametersContainer(), HillasParametersContainer()], prefixes=["hillas_1", "hillas_2"], ) hillas_1, hillas_2 = next(generator) for value, read_value in zip( hillas_config_1.as_dict().values(), hillas_1.as_dict().values() ): np.testing.assert_equal(value, read_value) for value, read_value in zip( hillas_config_2.as_dict().values(), hillas_2.as_dict().values() ): np.testing.assert_equal(value, read_value)
def test_ignore_negative(): from ctapipe.image import timing_parameters grad = 2.0 intercept = 1.0 deviation = 0.1 geom = CameraGeometry.from_name("LSTCam") hillas = HillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=0 * u.deg) random = np.random.RandomState(1) peak_time = intercept + grad * geom.pix_x.value peak_time += random.normal(0, deviation, geom.n_pixels) image = np.ones(geom.n_pixels) image[5:10] = -1.0 cleaning_mask = image >= 0 timing = timing_parameters( geom, image, peak_time=peak_time, hillas_parameters=hillas, cleaning_mask=cleaning_mask, ) # Test we get the values we put in back out again assert_allclose(timing.slope, grad / geom.pix_x.unit, rtol=1e-2) assert_allclose(timing.intercept, intercept, rtol=1e-2) assert_allclose(timing.deviation, deviation, rtol=1e-2)
def test_psi_0(): from ctapipe.image import timing_parameters """ Simple test that gradient fitting gives expected answers for perfect gradient """ grad = 2.0 intercept = 1.0 deviation = 0.1 geom = CameraGeometry.from_name("LSTCam") hillas = HillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=0 * u.deg) random = np.random.RandomState(1) peak_time = intercept + grad * geom.pix_x.value peak_time += random.normal(0, deviation, geom.n_pixels) timing = timing_parameters( geom, image=np.ones(geom.n_pixels), peak_time=peak_time, hillas_parameters=hillas, cleaning_mask=np.ones(geom.n_pixels, dtype=bool) ) # Test we get the values we put in back out again assert_allclose(timing.slope, grad / geom.pix_x.unit, rtol=1e-2) assert_allclose(timing.intercept, intercept, rtol=1e-2) assert_allclose(timing.deviation, deviation, rtol=1e-2)
def test_psi_20(): from ctapipe.image import timing_parameters # Then try a different rotation angle grad = 2 intercept = 1 deviation = 0.1 geom = CameraGeometry.from_name("LSTCam") psi = 20 * u.deg hillas = HillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=psi) random = np.random.RandomState(1) peak_time = intercept + grad * (np.cos(psi) * geom.pix_x.value + np.sin(psi) * geom.pix_y.value) peak_time += random.normal(0, deviation, geom.n_pixels) timing = timing_parameters( geom, image=np.ones(geom.n_pixels), peak_time=peak_time, hillas_parameters=hillas, cleaning_mask=np.ones(geom.n_pixels, dtype=bool) ) # Test we get the values we put in back out again assert_allclose(timing.slope, grad / geom.pix_x.unit, rtol=1e-2) assert_allclose(timing.intercept, intercept, rtol=1e-2) assert_allclose(timing.deviation, deviation, rtol=1e-2)
def test_append_container(tmp_path): path = tmp_path / "test_append.h5" with HDF5TableWriter(path, mode="w") as writer: for event_id in range(10): hillas = HillasParametersContainer() index = TelEventIndexContainer(obs_id=1, event_id=event_id, tel_id=1) writer.write("data", [index, hillas]) with HDF5TableWriter(path, mode="a") as writer: for event_id in range(10): index = TelEventIndexContainer(obs_id=2, event_id=event_id, tel_id=1) hillas = HillasParametersContainer() writer.write("data", [index, hillas]) table = read_table(path, "/data") assert len(table) == 20 assert np.all(table["obs_id"] == np.repeat([1, 2], 10)) assert np.all(table["event_id"] == np.tile(np.arange(10), 2))
def test_custom_prefix(): container = HillasParametersContainer( x=1 * u.m, y=1 * u.m, length=1 * u.m, width=1 * u.m ) container.prefix = "custom" with tempfile.NamedTemporaryFile() as f: with HDF5TableWriter(f.name, group_name="dl1", add_prefix=True) as writer: writer.write("params", container) with HDF5TableReader(f.name) as reader: generator = reader.read( "/dl1/params", HillasParametersContainer(), prefixes="custom" ) read_container = next(generator) assert isinstance(read_container, HillasParametersContainer) for value, read_value in zip( container.as_dict().values(), read_container.as_dict().values() ): np.testing.assert_equal(value, read_value)
def test_invalid_events(subarray_and_event_gamma_off_axis_500_gev): """ The HillasReconstructor is supposed to fail in these cases: - less than two teleskopes - any width is NaN - any width is 0 This test takes 1 shower from a test simtel file and modifies a-posteriori some hillas dictionaries to make it non-reconstructable. It is supposed to fail if no Exception or another Exception gets thrown. """ # 4-LST bright event already calibrated # we'll clean it and parametrize it again in the TelescopeFrame subarray, event = subarray_and_event_gamma_off_axis_500_gev calib = CameraCalibrator(subarray) image_processor = ImageProcessor(subarray) # perform no quality cuts, so we can see if our additional checks on valid # input work config = Config({"StereoQualityQuery": { "quality_criteria": [], }}) hillas_reconstructor = HillasReconstructor(subarray, config=config) calib(event) image_processor(event) result = hillas_reconstructor(event) assert result.is_valid # copy event container to modify it invalid_event = deepcopy(event) # overwrite all image parameters but the last one with dummy ones for tel_id in list(invalid_event.dl1.tel.keys())[:-1]: invalid_event.dl1.tel[ tel_id].parameters.hillas = HillasParametersContainer() result = hillas_reconstructor(invalid_event) assert not result.is_valid tel_id = list(invalid_event.dl1.tel.keys())[-1] # Now use the original event, but overwrite the last width to 0 invalid_event = deepcopy(event) invalid_event.dl1.tel[tel_id].parameters.hillas.width = 0 * u.m result = hillas_reconstructor(invalid_event) assert not result.is_valid # Now use the original event, but overwrite the last width to NaN invalid_event = deepcopy(event) invalid_event.dl1.tel[tel_id].parameters.hillas.width = np.nan * u.m result = hillas_reconstructor(invalid_event) assert not result.is_valid
def test_custom_prefix(tmp_path): path = tmp_path / "test.h5" container = HillasParametersContainer(fov_lon=1 * u.deg, fov_lat=1 * u.deg, length=1 * u.deg, width=1 * u.deg) container.prefix = "custom" with HDF5TableWriter(path, group_name="dl1", add_prefix=True) as writer: writer.write("params", container) with HDF5TableReader(path) as reader: generator = reader.read("/dl1/params", HillasParametersContainer(), prefixes="custom") read_container = next(generator) assert isinstance(read_container, HillasParametersContainer) for value, read_value in zip(container.as_dict().values(), read_container.as_dict().values()): np.testing.assert_equal(value, read_value)
def test_hillas_overlay(): from ctapipe.visualization import CameraDisplay disp = CameraDisplay(CameraGeometry.from_name("LSTCam")) hillas = HillasParametersContainer(x=0.1 * u.m, y=-0.1 * u.m, length=0.5 * u.m, width=0.2 * u.m, psi=90 * u.deg) disp.overlay_moments(hillas)
def test_read_multiple_containers(): hillas_parameter_container = HillasParametersContainer(x=1 * u.m, y=1 * u.m, length=1 * u.m, width=1 * u.m) leakage_container = LeakageContainer( pixels_width_1=0.1, pixels_width_2=0.1, intensity_width_1=0.1, intensity_width_2=0.1, ) with tempfile.NamedTemporaryFile() as f: with HDF5TableWriter(f.name, group_name="dl1", add_prefix=True) as writer: writer.write("params", [hillas_parameter_container, leakage_container]) df = pd.read_hdf(f.name, key="/dl1/params") assert "hillas_x" in df.columns assert "leakage_pixels_width_1" in df.columns # test reading both containers separately with HDF5TableReader(f.name) as reader: generator = reader.read("/dl1/params", HillasParametersContainer(), prefixes=True) hillas = next(generator) for value, read_value in zip( hillas_parameter_container.as_dict().values(), hillas.as_dict().values()): np.testing.assert_equal(value, read_value) with HDF5TableReader(f.name) as reader: generator = reader.read("/dl1/params", LeakageContainer(), prefixes=True) leakage = next(generator) for value, read_value in zip(leakage_container.as_dict().values(), leakage.as_dict().values()): np.testing.assert_equal(value, read_value) # test reading both containers simultaneously with HDF5TableReader(f.name) as reader: generator = reader.read( "/dl1/params", [HillasParametersContainer(), LeakageContainer()], prefixes=True, ) hillas_, leakage_ = next(generator) for value, read_value in zip(leakage_container.as_dict().values(), leakage_.as_dict().values()): np.testing.assert_equal(value, read_value) for value, read_value in zip( hillas_parameter_container.as_dict().values(), hillas_.as_dict().values()): np.testing.assert_equal(value, read_value)
def test_prefix(tmp_path): tmp_file = tmp_path / "test_prefix.hdf5" hillas_parameter_container = HillasParametersContainer(x=1 * u.m, y=1 * u.m, length=1 * u.m, width=1 * u.m) leakage_container = LeakageContainer( pixels_width_1=0.1, pixels_width_2=0.1, intensity_width_1=0.1, intensity_width_2=0.1, ) with HDF5TableWriter(tmp_file.name, group_name="blabla", add_prefix=True) as writer: writer.write("events", [hillas_parameter_container, leakage_container]) df = pd.read_hdf(tmp_file.name, key="/blabla/events") assert "hillas_x" in df.columns assert "leakage_pixels_width_1" in df.columns with HDF5TableReader(tmp_file.name) as reader: generator = reader.read("/blabla/events", HillasParametersContainer(), prefix=True) hillas = next(generator) for value, read_value in zip(hillas_parameter_container.as_dict().values(), hillas.as_dict().values()): np.testing.assert_equal(value, read_value) with HDF5TableReader(tmp_file.name) as reader: generator = reader.read("/blabla/events", LeakageContainer(), prefix=True) leakage = next(generator) for value, read_value in zip(leakage_container.as_dict().values(), leakage.as_dict().values()): np.testing.assert_equal(value, read_value)
def setup_class(self): self.impact_reco = ImPACTReconstructor(root_dir=".") self.horizon_frame = AltAz() self.h1 = HillasParametersContainer(x=1 * u.deg, y=1 * u.deg, r=1 * u.deg, phi=Angle(0 * u.rad), intensity=100, length=0.4 * u.deg, width=0.4 * u.deg, psi=Angle(0 * u.rad), skewness=0, kurtosis=0)
def test_read_without_prefixes(): hillas_parameter_container = HillasParametersContainer( x=1 * u.m, y=1 * u.m, length=1 * u.m, width=1 * u.m ) leakage_container = LeakageContainer( pixels_width_1=0.1, pixels_width_2=0.1, intensity_width_1=0.1, intensity_width_2=0.1, ) with tempfile.NamedTemporaryFile() as f: with HDF5TableWriter(f.name, group_name="dl1", add_prefix=False) as writer: writer.write("params", [hillas_parameter_container, leakage_container]) df = pd.read_hdf(f.name, key="/dl1/params") assert "x" in df.columns assert "pixels_width_1" in df.columns # call with prefixes=False with HDF5TableReader(f.name) as reader: generator = reader.read( "/dl1/params", [HillasParametersContainer(), LeakageContainer()], prefixes=False, ) hillas_, leakage_ = next(generator) for value, read_value in zip( leakage_container.as_dict().values(), leakage_.as_dict().values() ): np.testing.assert_equal(value, read_value) for value, read_value in zip( hillas_parameter_container.as_dict().values(), hillas_.as_dict().values() ): np.testing.assert_equal(value, read_value) # call with manually removed prefixes with HDF5TableReader(f.name) as reader: generator = reader.read( "/dl1/params", [HillasParametersContainer(prefix=""), LeakageContainer(prefix="")], prefixes=True, ) hillas_, leakage_ = next(generator) for value, read_value in zip( leakage_container.as_dict().values(), leakage_.as_dict().values() ): np.testing.assert_equal(value, read_value) for value, read_value in zip( hillas_parameter_container.as_dict().values(), hillas_.as_dict().values() ): np.testing.assert_equal(value, read_value)
def test_prefix(tmp_path): tmp_file = tmp_path / "test_prefix.hdf5" hillas_parameter_container = HillasParametersContainer( x=1 * u.m, y=1 * u.m, length=1 * u.m, width=1 * u.m ) leakage_container = LeakageContainer( pixels_width_1=0.1, pixels_width_2=0.1, intensity_width_1=0.1, intensity_width_2=0.1, ) with HDF5TableWriter(tmp_file.name, group_name="blabla", add_prefix=True) as writer: writer.write("events", [hillas_parameter_container, leakage_container]) df = pd.read_hdf(tmp_file.name, key="/blabla/events") assert "hillas_x" in df.columns assert "leakage_pixels_width_1" in df.columns
def test_read_duplicated_container_types(): hillas_config_1 = HillasParametersContainer( x=1 * u.m, y=2 * u.m, length=3 * u.m, width=4 * u.m, prefix='hillas_1', ) hillas_config_2 = HillasParametersContainer( x=2 * u.m, y=3 * u.m, length=4 * u.m, width=5 * u.m, prefix='hillas_2', ) with tempfile.NamedTemporaryFile() as f: with HDF5TableWriter(f.name, group_name="dl1", add_prefix=True) as writer: writer.write("params", [hillas_config_1, hillas_config_2]) df = pd.read_hdf(f.name, key="/dl1/params") assert "hillas_1_x" in df.columns assert "hillas_2_x" in df.columns with HDF5TableReader(f.name) as reader: generator = reader.read( "/dl1/params", [HillasParametersContainer(), HillasParametersContainer()], prefixes=['hillas_1', 'hillas_2']) hillas_1, hillas_2 = next(generator) for value, read_value in zip(hillas_config_1.as_dict().values(), hillas_1.as_dict().values()): np.testing.assert_equal(value, read_value) for value, read_value in zip(hillas_config_2.as_dict().values(), hillas_2.as_dict().values()): np.testing.assert_equal(value, read_value)
def _generator(self): """ Stereo event generator. Yields DataContainer instances, filled with the read event data. Returns ------- """ counter = 0 data = DataContainer() data.meta['origin'] = "MAGIC" data.meta['input_url'] = self.input_url data.meta['is_simulation'] = True data.mcheader = self._mc_header if self.calib_M1 is not None and self.calib_M2 is not None: #Reading data from root file for Events table eventid_M1 = np.asarray( self.calib_M1["MRawEvtHeader.fStereoEvtNumber"].array()) eventid_M2 = np.asarray( self.calib_M2["MRawEvtHeader.fStereoEvtNumber"].array()) zenith = np.asarray(self.calib_M1["MMcEvt.fTheta"].array()) pointing_altitude = np.asarray( self.calib_M1["MPointingPos.fZd"].array()) azimuth = np.asarray(self.calib_M1["MMcEvt.fPhi"].array()) pointing_azimuth = np.asarray( self.calib_M1["MPointingPos.fAz"].array()) core_x = np.asarray(self.calib_M1["MMcEvt.fCoreX"].array()) core_y = np.asarray(self.calib_M1["MMcEvt.fCoreY"].array()) mc_energy = np.asarray( self.calib_M1["MMcEvt.fEnergy"].array()) / 1000.0 h_first_int = np.asarray( self.calib_M1["MMcEvt.fZFirstInteraction"].array()) #Reading data from root file for Image table charge_M1 = np.asarray( self.calib_M1["MCerPhotEvt.fPixels.fPhot"].array()) peak_time_M1 = np.asarray( self.calib_M1["MArrivalTime.fData"].array()) charge_M2 = np.asarray( self.calib_M2["MCerPhotEvt.fPixels.fPhot"].array()) peak_time_M2 = np.asarray( self.calib_M2["MArrivalTime.fData"].array()) if self.superstar is not None: #Reading data from root file for Events table eventid_M1 = np.asarray( self.superstar["MRawEvtHeader_1.fStereoEvtNumber"].array()) eventid_M2 = np.asarray( self.superstar["MRawEvtHeader_2.fStereoEvtNumber"].array()) zenith = np.asarray(self.superstar["MMcEvt_1.fTheta"].array()) pointing_altitude = np.asarray( self.superstar["MPointingPos_1.fZd"].array()) azimuth = np.asarray(self.superstar["MMcEvt_1.fPhi"].array()) pointing_azimuth = np.asarray( self.superstar["MPointingPos_1.fAz"].array()) core_x = np.asarray(self.superstar["MMcEvt_1.fCoreX"].array()) core_y = np.asarray(self.superstar["MMcEvt_1.fCoreY"].array()) mc_energy = np.asarray( self.superstar["MMcEvt_1.fEnergy"].array()) / 1000.0 h_first_int = np.asarray( self.superstar["MMcEvt_1.fZFirstInteraction"].array()) #Reading data from root file for Parameter table hillas_intensity_M1 = np.asarray( self.superstar["MHillas_1.fSize"].array()) hillas_intensity_M2 = np.asarray( self.superstar["MHillas_2.fSize"].array()) hillas_x_M1 = np.asarray( self.superstar["MHillas_1.fMeanX"].array()) hillas_x_M2 = np.asarray( self.superstar["MHillas_2.fMeanX"].array()) hillas_y_M1 = np.asarray( self.superstar["MHillas_1.fMeanY"].array()) hillas_y_M2 = np.asarray( self.superstar["MHillas_2.fMeanY"].array()) hillas_r_M1 = np.sqrt( np.power(hillas_x_M1, 2) + np.power(hillas_y_M1, 2)) hillas_r_M2 = np.sqrt( np.power(hillas_x_M2, 2) + np.power(hillas_y_M2, 2)) hillas_phi_M1 = np.arctan2(hillas_y_M1, hillas_x_M1) hillas_phi_M2 = np.arctan2(hillas_y_M2, hillas_x_M2) hillas_length_M1 = np.asarray( self.superstar["MHillas_1.fLength"].array()) hillas_length_M2 = np.asarray( self.superstar["MHillas_2.fLength"].array()) hillas_width_M1 = np.asarray( self.superstar["MHillas_1.fWidth"].array()) hillas_width_M2 = np.asarray( self.superstar["MHillas_2.fWidth"].array()) hillas_psi_M1 = np.asarray( self.superstar["MHillas_1.fDelta"].array()) hillas_psi_M2 = np.asarray( self.superstar["MHillas_2.fDelta"].array()) hillas_skewness_M1 = np.asarray( self.superstar["MHillasExt_1.fM3Long"].array()) hillas_skewness_M2 = np.asarray( self.superstar["MHillasExt_2.fM3Long"].array()) leakage_intensity_1_M1 = np.asarray( self.superstar["MNewImagePar_1.fLeakage1"].array()) leakage_intensity_1_M2 = np.asarray( self.superstar["MNewImagePar_2.fLeakage1"].array()) leakage_intensity_2_M1 = np.asarray( self.superstar["MNewImagePar_1.fLeakage2"].array()) leakage_intensity_2_M2 = np.asarray( self.superstar["MNewImagePar_2.fLeakage2"].array()) num_islands_M1 = np.asarray( self.superstar["MCerPhotEvt_1.fNumIslands"].array()) num_islands_M2 = np.asarray( self.superstar["MCerPhotEvt_2.fNumIslands"].array()) #Reading data from root file for Image table (peak time and image mask not ) charge_M1 = np.asarray( self.superstar["MCerPhotEvt_1.fPixels.fPhot"].array()) peak_time_M1 = np.zeros((charge_M1.shape[0], 1039)) image_mask_M1 = np.zeros((charge_M1.shape[0], 1039), dtype=bool) charge_M2 = np.asarray( self.superstar["MCerPhotEvt_2.fPixels.fPhot"].array()) peak_time_M2 = np.zeros((charge_M2.shape[0], 1039)) image_mask_M2 = np.zeros((charge_M2.shape[0], 1039), dtype=bool) # Get the shower primary id shower_primary_id = 1 if self.file_list[0].split("/")[-1].startswith("GA"): shower_primary_id = 1 #Iterating over all events, and saving only stereo ones total_events = min(len(charge_M1), len(charge_M2)) tels_with_data = {1, 2} for i in range(0, total_events): if eventid_M1[i] != 0: obs_id = self.run_number event_id = eventid_M1[i] i2 = np.where(eventid_M2 == eventid_M1[i]) i2 = i2[0].astype(int) data.count = counter # Setting up the Data container data.index.obs_id = obs_id data.index.event_id = event_id data.r0.tel.clear() data.r1.tel.clear() data.dl0.tel.clear() # Adding the array pointing in the pointing container data.pointing.array_altitude = u.Quantity( np.deg2rad(90.0 - pointing_altitude[i]), u.rad) data.pointing.array_azimuth = u.Quantity( np.deg2rad(pointing_azimuth[i]), u.rad) # Filling the DL1 container with the event data for tel_id in tels_with_data: #Adding telescope pointing container data.pointing.tel[tel_id].azimuth = u.Quantity( np.deg2rad(pointing_azimuth[i]), u.rad) data.pointing.tel[tel_id].altitude = u.Quantity( np.deg2rad(90.0 - pointing_altitude[i]), u.rad) #Adding MC data data.mc.alt = Angle(np.pi / 2.0 - zenith[i], u.rad) data.mc.az = Angle( np.deg2rad(180.0 - 7.0) - azimuth[i], u.rad) data.mc.x_max = u.Quantity(0, X_MAX_UNIT) data.mc.h_first_int = u.Quantity(h_first_int[i], u.m) data.mc.core_x = u.Quantity(core_x[i], u.m) data.mc.core_y = u.Quantity(core_y[i], u.m) data.mc.energy = u.Quantity(mc_energy[i], u.TeV) data.mc.shower_primary_id = shower_primary_id if self.superstar is not None: leakage_values = LeakageContainer() hillas_parameters_values = HillasParametersContainer() concentration_values = ConcentrationContainer() timing_values = TimingParametersContainer() morphology_values = MorphologyContainer() # Adding charge, peak time and parameters if tel_id == 1: data.dl1.tel[tel_id].image = charge_M1[i][:1039] data.dl1.tel[tel_id].peak_time = peak_time_M1[i][:1039] if self.superstar is not None: data.dl1.tel[tel_id].image_mask = image_mask_M1[ i][:1039] hillas_parameters_values[ "intensity"] = hillas_intensity_M1[i] hillas_parameters_values["x"] = u.Quantity( hillas_x_M1[i], unit=u.mm) hillas_parameters_values["y"] = u.Quantity( hillas_y_M1[i], unit=u.mm) hillas_parameters_values["r"] = u.Quantity( hillas_r_M1[i], unit=u.mm) hillas_parameters_values["phi"] = u.Quantity( hillas_phi_M1[i], unit=u.rad) hillas_parameters_values["length"] = u.Quantity( hillas_length_M1[i], unit=u.mm) hillas_parameters_values["width"] = u.Quantity( hillas_width_M1[i], unit=u.mm) hillas_parameters_values["psi"] = u.Quantity( hillas_psi_M1[i], unit=u.rad) hillas_parameters_values[ "skewness"] = hillas_skewness_M1[i] leakage_values[ "intensity_width_1"] = leakage_intensity_1_M1[ i] leakage_values[ "intensity_width_2"] = leakage_intensity_2_M1[ i] morphology_values["num_pixels"] = 1039 morphology_values["num_islands"] = num_islands_M1[ i] else: data.dl1.tel[tel_id].image = charge_M2[i][:1039] data.dl1.tel[tel_id].peak_time = peak_time_M2[i][:1039] if self.superstar is not None: data.dl1.tel[tel_id].image_mask = image_mask_M2[ i][:1039] hillas_parameters_values[ "intensity"] = hillas_intensity_M2[i] hillas_parameters_values["x"] = u.Quantity( hillas_x_M2[i], unit=u.mm) hillas_parameters_values["y"] = u.Quantity( hillas_y_M2[i], unit=u.mm) hillas_parameters_values["r"] = u.Quantity( hillas_r_M2[i], unit=u.mm) hillas_parameters_values["phi"] = u.Quantity( hillas_phi_M2[i], unit=u.rad) hillas_parameters_values["length"] = u.Quantity( hillas_length_M2[i], unit=u.mm) hillas_parameters_values["width"] = u.Quantity( hillas_width_M2[i], unit=u.mm) hillas_parameters_values["psi"] = u.Quantity( hillas_psi_M2[i], unit=u.rad) hillas_parameters_values[ "skewness"] = hillas_skewness_M2[i] leakage_values[ "intensity_width_1"] = leakage_intensity_1_M2[ i] leakage_values[ "intensity_width_2"] = leakage_intensity_2_M2[ i] morphology_values["num_pixels"] = 1039 morphology_values["num_islands"] = num_islands_M2[ i] if self.superstar is not None: data.dl1.tel[ tel_id].parameters.leakage = leakage_values data.dl1.tel[ tel_id].parameters.hillas = hillas_parameters_values data.dl1.tel[ tel_id].parameters.concentration = concentration_values data.dl1.tel[tel_id].parameters.timing = timing_values data.dl1.tel[ tel_id].parameters.morphology = morphology_values # Setting the telescopes with data data.r0.tels_with_data = tels_with_data data.r1.tels_with_data = tels_with_data data.dl0.tels_with_data = tels_with_data yield data counter += 1 return
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
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
def test_array_display(): """ check that we can do basic array display functionality """ from ctapipe.visualization.mpl_array import ArrayDisplay from ctapipe.image import timing_parameters from ctapipe.containers import ( ArrayEventContainer, DL1Container, DL1CameraContainer, ImageParametersContainer, CoreParametersContainer, ) # build a test subarray: tels = dict() tel_pos = dict() for ii, pos in enumerate([[0, 0, 0], [100, 0, 0], [-100, 0, 0]] * u.m): tels[ii + 1] = TelescopeDescription.from_name("MST", "NectarCam") tel_pos[ii + 1] = pos sub = SubarrayDescription(name="TestSubarray", tel_positions=tel_pos, tel_descriptions=tels) # Create a fake event containing telescope-wise information about # the image directions projected on the ground event = ArrayEventContainer() event.dl1 = DL1Container() event.dl1.tel = {1: DL1CameraContainer(), 2: DL1CameraContainer()} event.dl1.tel[1].parameters = ImageParametersContainer() event.dl1.tel[2].parameters = ImageParametersContainer() event.dl1.tel[2].parameters.core = CoreParametersContainer() event.dl1.tel[1].parameters.core = CoreParametersContainer() event.dl1.tel[1].parameters.core.psi = u.Quantity(2.0, unit=u.deg) event.dl1.tel[2].parameters.core.psi = u.Quantity(1.0, unit=u.deg) ad = ArrayDisplay(subarray=sub) ad.set_vector_rho_phi(1 * u.m, 90 * u.deg) # try setting a value vals = np.ones(sub.num_tels) ad.values = vals assert (vals == ad.values).all() # test UV field ... # ...with colors by telescope type ad.set_vector_uv(np.array([1, 2, 3]) * u.m, np.array([1, 2, 3]) * u.m) # ...with scalar color ad.set_vector_uv(np.array([1, 2, 3]) * u.m, np.array([1, 2, 3]) * u.m, c=3) geom = CameraGeometry.from_name("LSTCam") rot_angle = 20 * u.deg hillas = CameraHillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=rot_angle) # test using hillas params CameraFrame: hillas_dict = { 1: CameraHillasParametersContainer(length=100.0 * u.m, psi=90 * u.deg), 2: CameraHillasParametersContainer(length=20000 * u.cm, psi="95deg"), } grad = 2 intercept = 1 timing_rot20 = timing_parameters( geom, image=np.ones(geom.n_pixels), peak_time=intercept + grad * geom.pix_x.value, hillas_parameters=hillas, cleaning_mask=np.ones(geom.n_pixels, dtype=bool), ) gradient_dict = {1: timing_rot20.slope.value, 2: timing_rot20.slope.value} core_dict = { tel_id: dl1.parameters.core.psi for tel_id, dl1 in event.dl1.tel.items() } ad.set_vector_hillas( hillas_dict=hillas_dict, core_dict=core_dict, length=500, time_gradient=gradient_dict, angle_offset=0 * u.deg, ) ad.set_line_hillas(hillas_dict=hillas_dict, core_dict=core_dict, range=300) # test using hillas params for divergent pointing in telescopeframe: hillas_dict = { 1: HillasParametersContainer(fov_lon=1.0 * u.deg, fov_lat=1.0 * u.deg, length=1.0 * u.deg, psi=90 * u.deg), 2: HillasParametersContainer(fov_lon=1.0 * u.deg, fov_lat=1.0 * u.deg, length=1.0 * u.deg, psi=95 * u.deg), } ad.set_vector_hillas( hillas_dict=hillas_dict, core_dict=core_dict, length=500, time_gradient=gradient_dict, angle_offset=0 * u.deg, ) ad.set_line_hillas(hillas_dict=hillas_dict, core_dict=core_dict, range=300) # test using hillas params for parallel pointing in telescopeframe: hillas_dict = { 1: HillasParametersContainer(fov_lon=1.0 * u.deg, fov_lat=1.0 * u.deg, length=1.0 * u.deg, psi=90 * u.deg), 2: HillasParametersContainer(fov_lon=1.0 * u.deg, fov_lat=1.0 * u.deg, length=1.0 * u.deg, psi=95 * u.deg), } ad.set_vector_hillas( hillas_dict=hillas_dict, core_dict=core_dict, length=500, time_gradient=gradient_dict, angle_offset=0 * u.deg, ) # test negative time_gradients gradient_dict = {1: -0.03, 2: -0.02} ad.set_vector_hillas( hillas_dict=hillas_dict, core_dict=core_dict, length=500, time_gradient=gradient_dict, angle_offset=0 * u.deg, ) # and very small gradient_dict = {1: 0.003, 2: 0.002} ad.set_vector_hillas( hillas_dict=hillas_dict, core_dict=core_dict, length=500, time_gradient=gradient_dict, angle_offset=0 * u.deg, ) # Test background contour ad.background_contour( x=np.array([0, 1, 2]), y=np.array([0, 1, 2]), background=np.array([[0, 1, 2], [0, 1, 2], [0, 1, 2]]), ) ad.set_line_hillas(hillas_dict=hillas_dict, core_dict=core_dict, range=300) ad.add_labels() ad.remove_labels()
def _generator(self): """ Stereo event generator. Yields DataContainer instances, filled with the read event data. Returns ------- """ counter = 0 data = DataContainer() data.meta["origin"] = "MAGIC" data.meta["input_url"] = self.input_url data.meta["is_simulation"] = self.mc data.mcheader = self._header if self.calib_M1 is not None and self.calib_M2 is not None: # Reading data from root file for Events table shower_primary_id = self.magic_to_cta_shower_primary_id[int( self.superstar["MMcEvt_1.fPartId"].array()[0])] eventid_M1 = np.asarray( self.calib_M1["MRawEvtHeader.fStereoEvtNumber"].array()) eventid_M2 = np.asarray( self.calib_M2["MRawEvtHeader.fStereoEvtNumber"].array()) zenith = np.asarray(self.calib_M1["MMcEvt.fTheta"].array()) pointing_altitude = np.asarray( self.calib_M1["MPointingPos.fZd"].array()) azimuth = np.asarray(self.calib_M1["MMcEvt.fPhi"].array()) pointing_azimuth = np.asarray( self.calib_M1["MPointingPos.fAz"].array()) core_x = np.asarray(self.calib_M1["MMcEvt.fCoreX"].array()) core_y = np.asarray(self.calib_M1["MMcEvt.fCoreY"].array()) mc_energy = np.asarray( self.calib_M1["MMcEvt.fEnergy"].array()) / 1000.0 h_first_int = np.asarray( self.calib_M1["MMcEvt.fZFirstInteraction"].array()) # Reading data from root file for Image table charge_M1 = np.asarray( self.calib_M1["MCerPhotEvt.fPixels.fPhot"].array()) peak_time_M1 = np.asarray( self.calib_M1["MArrivalTime.fData"].array()) image_mask_M1 = np.asarray(self.calib_M1["CleanCharge"].array()) for i, mask in enumerate(image_mask_M1): image_mask_M1[i] = np.array(mask) != 0 charge_M2 = np.asarray( self.calib_M2["MCerPhotEvt.fPixels.fPhot"].array()) peak_time_M2 = np.asarray( self.calib_M2["MArrivalTime.fData"].array()) image_mask_M2 = np.asarray(self.calib_M2["CleanCharge"].array()) for i, mask in enumerate(image_mask_M2): image_mask_M2[i] = np.array(mask) != 0 if self.superstar is not None: # Reading data from root file for Events table # only read MC information if it exists if self.is_simulation: shower_primary_id = self.magic_to_cta_shower_primary_id[int( self.superstar["MMcEvt_1.fPartId"].array()[0])] src_pos_cam_Y = np.asarray( self.superstar["MSrcPosCam_1.fY"].array()) src_pos_cam_X = np.asarray( self.superstar["MSrcPosCam_1.fX"].array()) core_x = np.asarray(self.superstar["MMcEvt_1.fCoreX"].array()) core_y = np.asarray(self.superstar["MMcEvt_1.fCoreY"].array()) mc_energy = ( np.asarray(self.superstar["MMcEvt_1.fEnergy"].array()) / 1000.0) h_first_int = np.asarray( self.superstar["MMcEvt_1.fZFirstInteraction"].array()) eventid_M1 = np.asarray( self.superstar["MRawEvtHeader_1.fStereoEvtNumber"].array()) eventid_M2 = np.asarray( self.superstar["MRawEvtHeader_2.fStereoEvtNumber"].array()) pointing_altitude = np.asarray( self.superstar["MPointingPos_1.fZd"].array()) pointing_azimuth = np.asarray( self.superstar["MPointingPos_1.fAz"].array()) # Reading data from root file for Parameter table hillas_intensity_M1 = np.asarray( self.superstar["MHillas_1.fSize"].array()) hillas_intensity_M2 = np.asarray( self.superstar["MHillas_2.fSize"].array()) hillas_x_M1 = np.asarray( self.superstar["MHillas_1.fMeanX"].array()) hillas_x_M2 = np.asarray( self.superstar["MHillas_2.fMeanX"].array()) hillas_y_M1 = np.asarray( self.superstar["MHillas_1.fMeanY"].array()) hillas_y_M2 = np.asarray( self.superstar["MHillas_2.fMeanY"].array()) hillas_r_M1 = np.sqrt( np.power(hillas_x_M1, 2) + np.power(hillas_y_M1, 2)) hillas_r_M2 = np.sqrt( np.power(hillas_x_M2, 2) + np.power(hillas_y_M2, 2)) hillas_phi_M1 = np.arctan2(hillas_y_M1, hillas_x_M1) hillas_phi_M2 = np.arctan2(hillas_y_M2, hillas_x_M2) hillas_length_M1 = np.asarray( self.superstar["MHillas_1.fLength"].array()) hillas_length_M2 = np.asarray( self.superstar["MHillas_2.fLength"].array()) hillas_width_M1 = np.asarray( self.superstar["MHillas_1.fWidth"].array()) hillas_width_M2 = np.asarray( self.superstar["MHillas_2.fWidth"].array()) hillas_psi_M1 = np.asarray( self.superstar["MHillas_1.fDelta"].array()) hillas_psi_M2 = np.asarray( self.superstar["MHillas_2.fDelta"].array()) hillas_skewness_M1 = np.asarray( self.superstar["MHillasExt_1.fM3Long"].array()) hillas_skewness_M2 = np.asarray( self.superstar["MHillasExt_2.fM3Long"].array()) leakage_intensity_1_M1 = np.asarray( self.superstar["MNewImagePar_1.fLeakage1"].array()) leakage_intensity_1_M2 = np.asarray( self.superstar["MNewImagePar_2.fLeakage1"].array()) leakage_intensity_2_M1 = np.asarray( self.superstar["MNewImagePar_1.fLeakage2"].array()) leakage_intensity_2_M2 = np.asarray( self.superstar["MNewImagePar_2.fLeakage2"].array()) num_islands_M1 = np.asarray( self.superstar["MImagePar_1.fNumIslands"].array()) num_islands_M2 = np.asarray( self.superstar["MImagePar_2.fNumIslands"].array()) x_max = np.asarray(self.superstar["MStereoPar.fXMax"].array()) # Reading data from root file for Image table (charge, peak time and image mask) charge_M1 = np.asarray(self.superstar["UprootImageOrig_1"].array()) for i, charge in enumerate(charge_M1): charge_M1[i] = np.array(charge) peak_time_M1 = np.asarray( self.superstar["MArrivalTime_1.fData"].array()) image_mask_M1 = np.asarray( self.superstar["UprootImageOrigClean_1"].array()) for i, mask in enumerate(image_mask_M1): image_mask_M1[i] = np.array(mask) != 0 charge_M2 = np.asarray(self.superstar["UprootImageOrig_2"].array()) for i, charge in enumerate(charge_M2): charge_M2[i] = np.array(charge) charge_M2 = np.asarray( self.superstar["MCerPhotEvt_2.fPixels.fPhot"].array()) peak_time_M2 = np.asarray( self.superstar["MArrivalTime_2.fData"].array()) image_mask_M2 = np.asarray( self.superstar["UprootImageOrigClean_2"].array()) for i, mask in enumerate(image_mask_M2): image_mask_M2[i] = np.array(mask) != 0 # Iterating over all events, and saving only stereo ones total_events = min(len(charge_M1), len(charge_M2)) tels_with_data = {1, 2} for i in range(0, total_events): if eventid_M1[i] != 0: obs_id = self.run_number event_id = eventid_M1[i] i2 = np.where(eventid_M2 == eventid_M1[i]) i2 = i2[0].astype(int) data.count = counter # Setting up the Data container data.index.obs_id = obs_id data.index.event_id = event_id data.r0.tel.clear() data.r1.tel.clear() data.dl0.tel.clear() # Adding the array pointing in the pointing container data.pointing.array_altitude = u.Quantity( np.deg2rad(90.0 - pointing_altitude[i]), u.rad) data.pointing.array_azimuth = u.Quantity( np.deg2rad(pointing_azimuth[i]), u.rad) # Filling the DL1 container with the event data for tel_id in tels_with_data: # Adding telescope pointing container data.pointing.tel[tel_id].azimuth = u.Quantity( np.deg2rad(pointing_azimuth[i]), u.rad) data.pointing.tel[tel_id].altitude = u.Quantity( np.deg2rad(90.0 - pointing_altitude[i]), u.rad) # Adding MC data if self.is_simulation: data.mc.alt = Angle( np.deg2rad(src_pos_cam_Y[i] * 0.00337), u.rad) data.mc.az = Angle( np.deg2rad(src_pos_cam_X[i] * 0.00337), u.rad) data.mc.x_max = u.Quantity(x_max[i], X_MAX_UNIT) data.mc.h_first_int = u.Quantity(h_first_int[i], u.m) data.mc.core_x = u.Quantity(core_x[i], u.m) data.mc.core_y = u.Quantity(core_y[i], u.m) data.mc.energy = u.Quantity(mc_energy[i], u.TeV) data.mc.shower_primary_id = shower_primary_id if self.superstar is not None: leakage_values = LeakageContainer() hillas_parameters_values = HillasParametersContainer() concentration_values = ConcentrationContainer() timing_values = TimingParametersContainer() morphology_values = MorphologyContainer() # Adding charge, peak time and parameters if tel_id == 1: data.dl1.tel[tel_id].image = charge_M1[i][:1039] data.dl1.tel[tel_id].peak_time = peak_time_M1[i][:1039] data.dl1.tel[tel_id].image_mask = image_mask_M1[ i][:1039] if self.superstar is not None: hillas_parameters_values[ "intensity"] = hillas_intensity_M1[i] hillas_parameters_values["x"] = u.Quantity( hillas_x_M1[i], unit=u.mm) hillas_parameters_values["y"] = u.Quantity( hillas_y_M1[i], unit=u.mm) hillas_parameters_values["r"] = u.Quantity( hillas_r_M1[i], unit=u.mm) hillas_parameters_values["phi"] = u.Quantity( hillas_phi_M1[i], unit=u.rad) hillas_parameters_values["length"] = u.Quantity( hillas_length_M1[i], unit=u.mm) hillas_parameters_values["width"] = u.Quantity( hillas_width_M1[i], unit=u.mm) hillas_parameters_values["psi"] = u.Quantity( hillas_psi_M1[i], unit=u.rad) hillas_parameters_values[ "skewness"] = hillas_skewness_M1[i] leakage_values[ "intensity_width_1"] = leakage_intensity_1_M1[ i] leakage_values[ "intensity_width_2"] = leakage_intensity_2_M1[ i] morphology_values["num_islands"] = num_islands_M1[ i] else: data.dl1.tel[tel_id].image = charge_M2[i][:1039] data.dl1.tel[tel_id].peak_time = peak_time_M2[i][:1039] data.dl1.tel[tel_id].image_mask = image_mask_M2[ i][:1039] if self.superstar is not None: hillas_parameters_values[ "intensity"] = hillas_intensity_M2[i] hillas_parameters_values["x"] = u.Quantity( hillas_x_M2[i], unit=u.mm) hillas_parameters_values["y"] = u.Quantity( hillas_y_M2[i], unit=u.mm) hillas_parameters_values["r"] = u.Quantity( hillas_r_M2[i], unit=u.mm) hillas_parameters_values["phi"] = u.Quantity( hillas_phi_M2[i], unit=u.rad) hillas_parameters_values["length"] = u.Quantity( hillas_length_M2[i], unit=u.mm) hillas_parameters_values["width"] = u.Quantity( hillas_width_M2[i], unit=u.mm) hillas_parameters_values["psi"] = u.Quantity( hillas_psi_M2[i], unit=u.rad) hillas_parameters_values[ "skewness"] = hillas_skewness_M2[i] leakage_values[ "intensity_width_1"] = leakage_intensity_1_M2[ i] leakage_values[ "intensity_width_2"] = leakage_intensity_2_M2[ i] morphology_values["num_islands"] = num_islands_M2[ i] if self.superstar is not None: data.dl1.tel[ tel_id].parameters.leakage = leakage_values data.dl1.tel[ tel_id].parameters.hillas = hillas_parameters_values data.dl1.tel[ tel_id].parameters.concentration = concentration_values data.dl1.tel[tel_id].parameters.timing = timing_values data.dl1.tel[ tel_id].parameters.morphology = morphology_values # Setting the telescopes with data data.r0.tels_with_data = tels_with_data data.r1.tels_with_data = tels_with_data data.dl0.tels_with_data = tels_with_data yield data counter += 1 return
def _generate_events(self): """ Yield ArrayEventContainer to iterate through events. """ data = ArrayEventContainer() # Maybe take some other metadata, but there are still some 'unknown' # written out by the stage1 tool data.meta["origin"] = self.file_.root._v_attrs["CTA PROCESS TYPE"] data.meta["input_url"] = self.input_url data.meta["max_events"] = self.max_events if DataLevel.DL1_IMAGES in self.datalevels: image_iterators = { tel.name: self.file_.root.dl1.event.telescope.images[ tel.name ].iterrows() for tel in self.file_.root.dl1.event.telescope.images } if self.has_simulated_dl1: simulated_image_iterators = { tel.name: self.file_.root.simulation.event.telescope.images[ tel.name ].iterrows() for tel in self.file_.root.simulation.event.telescope.images } if DataLevel.DL1_PARAMETERS in self.datalevels: param_readers = { tel.name: HDF5TableReader(self.file_).read( f"/dl1/event/telescope/parameters/{tel.name}", containers=[ HillasParametersContainer(), TimingParametersContainer(), LeakageContainer(), ConcentrationContainer(), MorphologyContainer(), IntensityStatisticsContainer(), PeakTimeStatisticsContainer(), ], prefixes=True, ) for tel in self.file_.root.dl1.event.telescope.parameters } if self.has_simulated_dl1: simulated_param_readers = { tel.name: HDF5TableReader(self.file_).read( f"/simulation/event/telescope/parameters/{tel.name}", containers=[ HillasParametersContainer(), LeakageContainer(), ConcentrationContainer(), MorphologyContainer(), IntensityStatisticsContainer(), ], prefixes=True, ) for tel in self.file_.root.dl1.event.telescope.parameters } if self.is_simulation: # simulated shower wide information mc_shower_reader = HDF5TableReader(self.file_).read( "/simulation/event/subarray/shower", SimulatedShowerContainer(), prefixes="true", ) # Setup iterators for the array events events = HDF5TableReader(self.file_).read( "/dl1/event/subarray/trigger", [TriggerContainer(), EventIndexContainer()] ) array_pointing_finder = IndexFinder( self.file_.root.dl1.monitoring.subarray.pointing.col("time") ) tel_pointing_finder = { tel.name: IndexFinder(tel.col("time")) for tel in self.file_.root.dl1.monitoring.telescope.pointing } for counter, array_event in enumerate(events): data.dl1.tel.clear() data.simulation.tel.clear() data.pointing.tel.clear() data.trigger.tel.clear() data.count = counter data.trigger, data.index = next(events) data.trigger.tels_with_trigger = ( np.where(data.trigger.tels_with_trigger)[0] + 1 ) # +1 to match array index to telescope id # Maybe there is a simpler way to do this # Beware: tels_with_trigger contains all triggered telescopes whereas # the telescope trigger table contains only the subset of # allowed_tels given during the creation of the dl1 file for i in self.file_.root.dl1.event.telescope.trigger.where( f"(obs_id=={data.index.obs_id}) & (event_id=={data.index.event_id})" ): if self.allowed_tels and i["tel_id"] not in self.allowed_tels: continue if self.datamodel_version == "v1.0.0": data.trigger.tel[i["tel_id"]].time = i["telescopetrigger_time"] else: data.trigger.tel[i["tel_id"]].time = i["time"] self._fill_array_pointing(data, array_pointing_finder) self._fill_telescope_pointing(data, tel_pointing_finder) if self.is_simulation: data.simulation.shower = next(mc_shower_reader) for tel in data.trigger.tel.keys(): if self.allowed_tels and tel not in self.allowed_tels: continue if self.has_simulated_dl1: simulated = data.simulation.tel[tel] dl1 = data.dl1.tel[tel] if DataLevel.DL1_IMAGES in self.datalevels: if f"tel_{tel:03d}" not in image_iterators.keys(): logger.debug( f"Triggered telescope {tel} is missing " "from the image table." ) continue image_row = next(image_iterators[f"tel_{tel:03d}"]) dl1.image = image_row["image"] dl1.peak_time = image_row["peak_time"] dl1.image_mask = image_row["image_mask"] if self.has_simulated_dl1: if f"tel_{tel:03d}" not in simulated_image_iterators.keys(): logger.warning( f"Triggered telescope {tel} is missing " "from the simulated image table, but was present at the " "reconstructed image table." ) continue simulated_image_row = next( simulated_image_iterators[f"tel_{tel:03d}"] ) simulated.true_image = simulated_image_row["true_image"] if DataLevel.DL1_PARAMETERS in self.datalevels: if f"tel_{tel:03d}" not in param_readers.keys(): logger.debug( f"Triggered telescope {tel} is missing " "from the parameters table." ) continue # Is there a smarter way to unpack this? # Best would probbaly be if we could directly read # into the ImageParametersContainer params = next(param_readers[f"tel_{tel:03d}"]) dl1.parameters.hillas = params[0] dl1.parameters.timing = params[1] dl1.parameters.leakage = params[2] dl1.parameters.concentration = params[3] dl1.parameters.morphology = params[4] dl1.parameters.intensity_statistics = params[5] dl1.parameters.peak_time_statistics = params[6] if self.has_simulated_dl1: if f"tel_{tel:03d}" not in param_readers.keys(): logger.debug( f"Triggered telescope {tel} is missing " "from the simulated parameters table, but was " "present at the reconstructed parameters table." ) continue simulated_params = next( simulated_param_readers[f"tel_{tel:03d}"] ) simulated.true_parameters.hillas = simulated_params[0] simulated.true_parameters.leakage = simulated_params[1] simulated.true_parameters.concentration = simulated_params[2] simulated.true_parameters.morphology = simulated_params[3] simulated.true_parameters.intensity_statistics = simulated_params[ 4 ] yield data
def predict(self, hillas_dict, subarray, array_pointing, telescopes_pointings=None): """ Parameters ---------- hillas_dict: dict Dictionary containing Hillas parameters for all telescopes in reconstruction inst : ctapipe.io.InstrumentContainer instrumental description array_pointing: SkyCoord[AltAz] pointing direction of the array telescopes_pointings: dict[SkyCoord[AltAz]] dictionary of pointing direction per each telescope Returns ------- ReconstructedShowerContainer: """ # filter warnings for missing obs time. this is needed because MC data has no obs time warnings.filterwarnings(action="ignore", category=MissingFrameAttributeWarning) # stereoscopy needs at least two telescopes if len(hillas_dict) < 2: raise TooFewTelescopesException( "need at least two telescopes, have {}".format(len(hillas_dict)) ) # check for np.nan or 0 width's as these screw up weights if any([np.isnan(hillas_dict[tel]["width"].value) for tel in hillas_dict]): raise InvalidWidthException( "A HillasContainer contains an ellipse of width==np.nan" ) if any([hillas_dict[tel]["width"].value == 0 for tel in hillas_dict]): raise InvalidWidthException( "A HillasContainer contains an ellipse of width==0" ) if telescopes_pointings is None: telescopes_pointings = { tel_id: array_pointing for tel_id in hillas_dict.keys() } tilted_frame = TiltedGroundFrame(pointing_direction=array_pointing) grd_coord = subarray.tel_coords tilt_coord = grd_coord.transform_to(tilted_frame) tel_ids = list(hillas_dict.keys()) tel_indices = subarray.tel_ids_to_indices(tel_ids) tel_x = { tel_id: tilt_coord.x[tel_index] for tel_id, tel_index in zip(tel_ids, tel_indices) } tel_y = { tel_id: tilt_coord.y[tel_index] for tel_id, tel_index in zip(tel_ids, tel_indices) } nom_frame = NominalFrame(origin=array_pointing) hillas_dict_mod = {} for tel_id, hillas in hillas_dict.items(): if isinstance(hillas, CameraHillasParametersContainer): focal_length = subarray.tel[tel_id].optics.equivalent_focal_length camera_frame = CameraFrame( telescope_pointing=telescopes_pointings[tel_id], focal_length=focal_length, ) cog_coords = SkyCoord(x=hillas.x, y=hillas.y, frame=camera_frame) cog_coords_nom = cog_coords.transform_to(nom_frame) else: telescope_frame = TelescopeFrame( telescope_pointing=telescopes_pointings[tel_id] ) cog_coords = SkyCoord( fov_lon=hillas.fov_lon, fov_lat=hillas.fov_lat, frame=telescope_frame, ) cog_coords_nom = cog_coords.transform_to(nom_frame) hillas_dict_mod[tel_id] = HillasParametersContainer( fov_lon=cog_coords_nom.fov_lon, fov_lat=cog_coords_nom.fov_lat, psi=hillas.psi, width=hillas.width, length=hillas.length, intensity=hillas.intensity, ) src_fov_lon, src_fov_lat, err_fov_lon, err_fov_lat = self.reconstruct_nominal( hillas_dict_mod ) core_x, core_y, core_err_x, core_err_y = self.reconstruct_tilted( hillas_dict_mod, tel_x, tel_y ) err_fov_lon *= u.rad err_fov_lat *= u.rad nom = SkyCoord( fov_lon=src_fov_lon * u.rad, fov_lat=src_fov_lat * u.rad, frame=nom_frame ) sky_pos = nom.transform_to(array_pointing.frame) tilt = SkyCoord(x=core_x * u.m, y=core_y * u.m, frame=tilted_frame) grd = project_to_ground(tilt) x_max = self.reconstruct_xmax( nom.fov_lon, nom.fov_lat, tilt.x, tilt.y, hillas_dict_mod, tel_x, tel_y, 90 * u.deg - array_pointing.alt, ) src_error = np.sqrt(err_fov_lon ** 2 + err_fov_lat ** 2) result = ReconstructedGeometryContainer( alt=sky_pos.altaz.alt.to(u.rad), az=sky_pos.altaz.az.to(u.rad), core_x=grd.x, core_y=grd.y, core_uncert=u.Quantity(np.sqrt(core_err_x ** 2 + core_err_y ** 2), u.m), tel_ids=[h for h in hillas_dict_mod.keys()], average_intensity=np.mean([h.intensity for h in hillas_dict_mod.values()]), is_valid=True, alt_uncert=src_error.to(u.rad), az_uncert=src_error.to(u.rad), h_max=x_max, h_max_uncert=u.Quantity(np.nan * x_max.unit), goodness_of_fit=np.nan, ) return result
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