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_array_display(): from ctapipe.visualization.mpl_array import ArrayDisplay # 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=1.0 * u.m, phi=90 * u.deg), 2: HillasParametersContainer(length=200 * u.cm, phi="95deg"), } ad.set_vector_hillas(hillas_dict) ad.add_labels() ad.remove_labels()
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_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_array_display(): """ check that we can do basic array display functionality """ from ctapipe.visualization.mpl_array import ArrayDisplay from ctapipe.image.timing_parameters 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), pulse_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_array_display(): from ctapipe.visualization.mpl_array import ArrayDisplay from ctapipe.image.timing_parameters 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 rot_angle = 20 * u.deg timing_rot20 = timing_parameters(pix_x=arange(4) * u.deg, pix_y=zeros(4) * u.deg, image=ones(4), peak_time=intercept * u.ns + grad * arange(4) * u.ns, rotation_angle=rot_angle) gradient_dict = { 1: timing_rot20.gradient.value, 2: timing_rot20.gradient.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.delta_az, source_y=nom_pos_reco.delta_alt, 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)
class TelescopeParameterContainer(Container): container_prefix = '' telescope_id = Field(-1, 'telescope id') run_id = Field(-1, 'run id') array_event_id = Field(-1, 'array event id') leakage = Field(LeakageContainer(), 'Leakage container') hillas = Field(HillasParametersContainer(), 'HillasParametersContainer') concentration = Field(ConcentrationContainer(), 'ConcentrationContainer') timing = Field(TimingParametersContainer(), 'TimingParametersContainer') islands = Field(IslandContainer(), 'IslandContainer') num_pixel_in_shower = Field(np.nan, 'number of pixels after cleaning') pointing = Field(TelescopePointingContainer(), 'pointing information') distance_to_reconstructed_core_position = Field( np.nan, 'Distance from telescope to reconstructed impact position', unit=u.m) camera_type_id = Field( np.nan, 'An ID encoding the camera type (SCT, ASTRI, CHEC, ...)') telescope_type_id = Field( np.nan, 'An ID encoding the telescope type (MST, SST, LST)') mirror_area = Field(np.nan, 'Mirror Area', unit=u.m**2) focal_length = Field(np.nan, 'focal length', unit=u.m)
def test_psi_0(): """ 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) pulse_time = intercept + grad * geom.pix_x.value pulse_time += random.normal(0, deviation, geom.n_pixels) timing = timing_parameters(geom, image=np.ones(geom.n_pixels), pulse_time=pulse_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_ignore_negative(): 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) pulse_time = intercept + grad * geom.pix_x.value pulse_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, pulse_time=pulse_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_20(): # 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) pulse_time = intercept + grad * (np.cos(psi) * geom.pix_x.value + np.sin(psi) * geom.pix_y.value) pulse_time += random.normal(0, deviation, geom.n_pixels) timing = timing_parameters(geom, image=np.ones(geom.n_pixels), pulse_time=pulse_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 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']) geom = CameraGeometry.from_name('LSTCam-002') foclen = OpticsDescription.from_name('LST').equivalent_focal_length dl1_container = DL1ParametersContainer() parameters_to_update = list(HillasParametersContainer().keys()) parameters_to_update.extend(['wl', 'r', 'leakage', 'n_islands', 'intercept', 'time_gradient']) 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'] pulse_time = row['pulse_time'] signal_pixels = tailcuts_clean(geom, image, **config['tailcut']) if image[signal_pixels].shape[0] > 0: num_islands, island_labels = number_of_islands(geom, signal_pixels) hillas = hillas_parameters(geom[signal_pixels], image[signal_pixels]) dl1_container.fill_hillas(hillas) dl1_container.set_timing_features(geom[signal_pixels], image[signal_pixels], pulse_time[signal_pixels], hillas) dl1_container.set_leakage(geom, image, signal_pixels) dl1_container.n_islands = num_islands dl1_container.wl = dl1_container.width / dl1_container.length width = np.rad2deg(np.arctan2(dl1_container.width, foclen)) length = np.rad2deg(np.arctan2(dl1_container.length, foclen)) dl1_container.width = width.value dl1_container.length = length.value dl1_container.r = np.sqrt(dl1_container.x**2 + dl1_container.y**2) for p in parameters_to_update: params[ii][p] = Quantity(dl1_container[p]).value else: for p in parameters_to_update: params[ii][p] = 0 output.root[dl1_params_lstcam_key][:] = params
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_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( leakage1_pixel=0.1, leakage2_pixel=0.1, leakage1_intensity=0.1, leakage2_intensity=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 "leakage2_pixel" in df.columns
def test_ignore_negative(): grad = 2.0 intercept = 1.0 geom = CameraGeometry.from_name("LSTCam") hillas = HillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=0 * u.deg) image = np.ones(geom.n_pixels) image[5:10] = -1.0 timing = timing_parameters( geom, image, peakpos=intercept + grad * geom.pix_x.value, hillas_parameters=hillas, ) # Test we get the values we put in back out again assert_allclose(timing.slope, grad / geom.pix_x.unit) assert_allclose(timing.intercept, intercept)
def test_psi_0(): """ Simple test that gradient fitting gives expected answers for perfect gradient """ grad = 2.0 intercept = 1.0 geom = CameraGeometry.from_name("LSTCam") hillas = HillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=0 * u.deg) timing = timing_parameters( geom, image=np.ones(geom.n_pixels), peakpos=intercept + grad * geom.pix_x.value, hillas_parameters=hillas, ) # Test we get the values we put in back out again assert_allclose(timing.slope, grad / geom.pix_x.unit) assert_allclose(timing.intercept, intercept)
def test_psi_20(): # Then try a different rotation angle grad = 2 intercept = 1 geom = CameraGeometry.from_name("LSTCam") psi = 20 * u.deg hillas = HillasParametersContainer(x=0 * u.m, y=0 * u.m, psi=psi) timing = timing_parameters( geom, image=np.ones(geom.n_pixels), peakpos=intercept + grad * (np.cos(psi) * geom.pix_x.value + np.sin(psi) * geom.pix_y.value), hillas_parameters=hillas, ) # Test we get the values we put in back out again assert_allclose(timing.slope, grad / geom.pix_x.unit) assert_allclose(timing.intercept, intercept)
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( leakage1_pixel=0.1, leakage2_pixel=0.1, leakage1_intensity=0.1, leakage2_intensity=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 'leakage2_pixel' in df.columns
def get_hillas_container(row): h = HillasParametersContainer() h.x = row['x'] * 28 * u.m h.y = row['y'] * 28 * u.m h.r = row['r'] * 28 * u.m h.phi = Angle(row['phi'] * u.rad) h.width = row['width'] * u.m h.length = row['length'] * u.m h.psi = Angle(row['psi'] * u.rad) h.skewness = row['skewness'] h.kurtosis = row['kurtosis'] return h
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([ 'wl', 'r', 'leakage1_intensity', 'leakage2_intensity', 'leakage1_pixel', 'leakage2_pixel', 'concentration_cog', 'concentration_core', 'concentration_pixel', 'n_pixels', 'n_islands', 'intercept', 'time_gradient' ]) 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'] pulse_time = row['pulse_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], pulse_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.value dl1_container.length = length.value dl1_container.r = np.sqrt(dl1_container.x**2 + dl1_container.y**2) for p in parameters_to_update: params[ii][p] = Quantity(dl1_container[p]).value else: for p in parameters_to_update: params[ii][p] = 0 output.root[dl1_params_lstcam_key][:] = params