def test_grad_fit(): """ Simple test that gradient fitting gives expected answers for perfect gradient """ grad = 2 intercept = 1 timing = timing_parameters(pix_x=np.zeros(4)*u.deg, pix_y=np.arange(4)*u.deg, image=np.ones(4), peak_time=intercept*u.ns +grad*np.arange(4)*u.ns, rotation_angle=0*u.deg) # Test we get the values we put in back out again assert_allclose(timing.gradient,grad*u.ns/u.deg) assert_allclose(timing.intercept,intercept*u.deg) # Then try a different rotation angle rot_angle = 20*u.deg timing_rot20 = timing_parameters(pix_x=np.zeros(4)*u.deg, pix_y=np.arange(4)*u.deg, image=np.ones(4), peak_time=intercept*u.ns +grad*np.arange(4)*u.ns, rotation_angle=rot_angle) # Test the output again makes sense assert_allclose(timing_rot20.gradient, timing.gradient/np.cos(rot_angle)) assert_allclose(timing_rot20.intercept, timing.intercept)
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_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_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_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 set_timing_features(self, geom, image, peak_time, hillas): try: # if np.polyfit fails (e.g. len(image) < deg + 1) timepars = timing_parameters(geom, image, peak_time, hillas) self.time_gradient = timepars.slope.value self.intercept = timepars.intercept except ValueError: self.time_gradient = np.nan self.intercept = np.nan
def get_observation_parameters(charge: np.array, peak: np.array, cam_name: str, cutflow: CutFlow, boundary_threshold: float = None, picture_threshold: float = None, min_neighbours: float = None, plot: bool = False, cut: bool = True): """ :param charge: Charge image :param peak: Peak time image :param cam_name: Camera name. e.g. FlashCam, ASTRICam, etc. :param cutflow: Cutflow for selection :param boundary_threshold: (Optional) Cleaning parameter: boundary threshold :param picture_threshold: (Optional) Cleaning parameter: picture threshold :param min_neighbours: (Optional) Cleaning parameter: minimum neighbours :param plot: If True, for each observation a plot will be shown (Default: False) :param cut: If true, tight else loose :return: hillas containers, leakage container, number of islands, island IDs, timing container, timing gradient """ charge_biggest, mask = clean_charge(charge, cam_name, boundary_threshold, picture_threshold, min_neighbours) camera = get_camera(cam_name) geometry = camera.geometry charge_biggest, camera_biggest, n_islands = mask_from_biggest_island( charge, geometry, mask) if cut: if cutflow.cut(CFO_MIN_PIXEL, charge_biggest): return if cutflow.cut(CFO_MIN_CHARGE, np.sum(charge_biggest)): return if cutflow.cut(CFO_NEGATIVE_CHARGE, charge_biggest): return leakage_c = leakage(geometry, charge, mask) if plot: _, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) CameraDisplay(geometry, charge, ax=ax1).add_colorbar() CameraDisplay(camera_biggest, charge_biggest, ax=ax2).add_colorbar() plt.show() moments = hillas_parameters(camera_biggest, charge_biggest) if cut: if cutflow.cut(CFO_CLOSE_EDGE, moments, camera.camera_name): return if cutflow.cut(CFO_BAD_ELLIP, moments): return if cutflow.cut(CFO_POOR_MOMENTS, moments): return timing_c = timing_parameters(geometry, charge, peak, moments, mask) time_gradient = timing_c.slope.value if geometry.camera_name != 'ASTRICam' else moments.skewness return moments, leakage_c, timing_c, time_gradient, n_islands
# create a clean mask of pixels above the threshold cleanmask = tailcuts_clean(camgeom, image, picture_thresh=10, boundary_thresh=5) if np.count_nonzero(cleanmask) < 10: continue # set all rejected pixels to zero cleaned_image[~cleanmask] = 0 # Calculate hillas parameters try: hillas_dict[tel_id] = hillas_parameters(camgeom, cleaned_image) except HillasParameterizationError: continue # skip failed parameterization (normally no signal) timing_dict[tel_id] = timing_parameters(camgeom, image, time, hillas_dict[tel_id], cleanmask).slope.value array_disp.set_vector_hillas(hillas_dict, 500, timing_dict, angle_offset=0 * u.deg) plt.pause(0.1) # allow matplotlib to redraw the display if len(hillas_dict) < 2: continue
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 process_telescope(tel, dl1, stereo): geom = tel.camera.geometry camera_name = tel.camera.camera_name image = dl1.image peak_time = dl1.peak_time # Cleaning using CHEC method clean = obtain_cleaning_mask(geom, image, peak_time, camera_name) # Skipping inadequate events if clean.sum() == 0: return None, None, None if stereo and clean.sum() < 5: return None, None, None # Get hillas parameters hillas_c = hillas_parameters(geom[clean], image[clean]) if hillas_c.width == 0 or np.isnan(hillas_c.width.value): return None, None, None # Get leakage and islands leakage_c = leakage(geom, image, clean) n_islands, island_ids = number_of_islands(geom, clean) # Get time gradient tgrad = np.nan try: timing_c = timing_parameters(geom, image, peak_time, hillas_c, clean) tgrad = timing_c.slope.value except BaseException: print("Timing parameters didn't work. clean.sum() = " + str(clean.sum()), "\n") # Grab info for telescope_events tel_data_dict = { 'nislands': n_islands, 'telescope_type': tel.type, 'camera_type': tel.camera.camera_name, 'focal_length': tel.optics.equivalent_focal_length.value, 'n_survived_pixels': clean.sum(), 'tgradient': tgrad, 'x': hillas_c.x.value, 'y': hillas_c.y.value, 'r': hillas_c.r.value, 'phi': hillas_c.phi.value, 'intensity': hillas_c.intensity, 'length': hillas_c.length.value, 'width': hillas_c.width.value, 'psi': hillas_c.psi.value, 'skewness': hillas_c.skewness, 'kurtosis': hillas_c.kurtosis, 'pixels_width_1': leakage_c.pixels_width_1, 'pixels_width_2': leakage_c.pixels_width_2, 'intensity_width_1': leakage_c.intensity_width_1, 'intensity_width_2': leakage_c.intensity_width_2} return tel.type, tel_data_dict, hillas_c