def create_sample_image( psi='-30d', x=0.2 * u.m, y=0.3 * u.m, width=0.05 * u.m, length=0.15 * u.m, intensity=1500 ): seed(10) geom = CameraGeometry.from_name('LSTCam') # make a toymodel shower model model = toymodel.Gaussian(x=x, y=y, width=width, length=length, psi=psi) # generate toymodel image in camera for this shower model. image, _, _ = model.generate_image( geom, intensity=1500, nsb_level_pe=3, ) # calculate pixels likely containing signal clean_mask = tailcuts_clean(geom, image, 10, 5) return geom, image, clean_mask
def create_sample_image( psi="-30d", x=0.2 * u.m, y=0.3 * u.m, width=0.05 * u.m, length=0.15 * u.m, intensity=1500, ): geom = CameraGeometry.from_name("LSTCam") # make a toymodel shower model model = toymodel.Gaussian(x=x, y=y, width=width, length=length, psi=psi) # generate toymodel image in camera for this shower model. rng = np.random.default_rng(0) image, _, _ = model.generate_image(geom, intensity=1500, nsb_level_pe=3, rng=rng) # calculate pixels likely containing signal clean_mask = tailcuts_clean(geom, image, 10, 5) return geom, image, clean_mask
def test_intensity(seed, monkeypatch): """ Test generation of the toymodel roughly follows the given intensity. Tests once with passing a custom rng instance, once with relying on the modules rng. """ from ctapipe.image import toymodel geom = CameraGeometry.from_name("LSTCam") x, y = u.Quantity([0.2, 0.3], u.m) width = 0.05 * u.m length = 0.15 * u.m intensity = 200 psi = "30d" # make sure we set a fixed seed for this test even when testing the # API without giving the rng monkeypatch.setattr(toymodel, "TOYMODEL_RNG", np.random.default_rng(0)) # make a toymodel shower model model = toymodel.Gaussian(x=x, y=y, width=width, length=length, psi=psi) if seed is None: _, signal, _ = model.generate_image(geom, intensity=intensity, nsb_level_pe=5) else: rng = np.random.default_rng(seed) _, signal, _ = model.generate_image(geom, intensity=intensity, nsb_level_pe=5, rng=rng) # test if signal reproduces given cog values assert np.average(geom.pix_x.to_value(u.m), weights=signal) == approx(0.2, rel=0.15) assert np.average(geom.pix_y.to_value(u.m), weights=signal) == approx(0.3, rel=0.15) # test if signal reproduces given width/length values cov = np.cov(geom.pix_x.value, geom.pix_y.value, aweights=signal) eigvals, _ = np.linalg.eigh(cov) assert np.sqrt(eigvals[0]) == approx(width.to_value(u.m), rel=0.15) assert np.sqrt(eigvals[1]) == approx(length.to_value(u.m), rel=0.15) # test if total intensity is inside in 99 percent confidence interval assert poisson(intensity).ppf(0.05) <= signal.sum() <= poisson( intensity).ppf(0.95)
def test_with_toy(): np.random.seed(42) geom = CameraGeometry.from_name("LSTCam") width = 0.03 * u.m length = 0.15 * u.m width_uncertainty = 0.00094 * u.m length_uncertainty = 0.00465 * u.m intensity = 500 xs = u.Quantity([0.5, 0.5, -0.5, -0.5], u.m) ys = u.Quantity([0.5, -0.5, 0.5, -0.5], u.m) psis = Angle([-90, -45, 0, 45, 90], unit="deg") for x, y in zip(xs, ys): for psi in psis: # make a toymodel shower model model = toymodel.Gaussian( x=x, y=y, width=width, length=length, psi=psi, ) image, signal, noise = model.generate_image( geom, intensity=intensity, nsb_level_pe=5, ) result = hillas_parameters(geom, signal) assert u.isclose(result.x, x, rtol=0.1) assert u.isclose(result.y, y, rtol=0.1) assert u.isclose(result.width, width, rtol=0.1) assert u.isclose(result.width_uncertainty, width_uncertainty, rtol=0.4) assert u.isclose(result.length, length, rtol=0.1) assert u.isclose(result.length_uncertainty, length_uncertainty, rtol=0.4) assert (result.psi.to_value(u.deg) == approx( psi.deg, abs=2)) or abs(result.psi.to_value(u.deg) - psi.deg) == approx(180.0, abs=2) assert signal.sum() == result.intensity
def draw_several_cams(geom, ncams=4): cmaps = ["jet", "afmhot", "terrain", "autumn"] fig, axs = plt.subplots( 1, ncams, figsize=(15, 4), ) for ii in range(ncams): disp = CameraDisplay( geom, ax=axs[ii], title="CT{}".format(ii + 1), ) disp.cmap = cmaps[ii] model = toymodel.Gaussian( x=(0.2 - ii * 0.1) * u.m, y=(-ii * 0.05) * u.m, width=(0.05 + 0.001 * ii) * u.m, length=(0.15 + 0.05 * ii) * u.m, psi=ii * 20 * u.deg, ) image, _, _ = model.generate_image( geom, intensity=1500, nsb_level_pe=5, ) mask = tailcuts_clean( geom, image, picture_thresh=6 * image.mean(), boundary_thresh=4 * image.mean(), ) cleaned = image.copy() cleaned[~mask] = 0 hillas = hillas_parameters(geom, cleaned) disp.image = image disp.add_colorbar(ax=axs[ii]) disp.set_limits_percent(95) disp.overlay_moments(hillas, linewidth=3, color="blue")
def update(frame): x, y = np.random.uniform(-fov, fov, size=2) width = np.random.uniform(0.01, maxwid) length = np.random.uniform(width, maxlen) angle = np.random.uniform(0, 180) intens = width * length * (5e4 + 1e5 * np.random.exponential(2)) model = toymodel.Gaussian( x=x * u.m, y=y * u.m, width=width * u.m, length=length * u.m, psi=angle * u.deg, ) image, _, _ = model.generate_image( geom, intensity=intens, nsb_level_pe=5, ) disp.image = image
from ctapipe.image import toymodel, hillas_parameters, tailcuts_clean from ctapipe.instrument import CameraGeometry from ctapipe.visualization import CameraDisplay if __name__ == "__main__": # Load the camera geom = CameraGeometry.from_name("LSTCam") disp = CameraDisplay(geom) disp.add_colorbar() # Create a fake camera image to display: model = toymodel.Gaussian( x=0.2 * u.m, y=0.0 * u.m, width=0.05 * u.m, length=0.15 * u.m, psi="35d" ) image, sig, bg = model.generate_image(geom, intensity=1500, nsb_level_pe=2) # Apply image cleaning cleanmask = tailcuts_clean(geom, image, picture_thresh=10, boundary_thresh=5) clean = image.copy() clean[~cleanmask] = 0.0 # Calculate image parameters hillas = hillas_parameters(geom, clean) print(hillas) # Show the camera image and overlay Hillas ellipse and clean pixels disp.image = image
def update(frame): x, y = np.random.uniform(-fov, fov, size=2) * scale width = np.random.uniform(0, maxwid - minwid) * scale + minwid length = np.random.uniform(0, maxlen) * scale + width angle = np.random.uniform(0, 360) intens = np.random.exponential(2) * 500 model = toymodel.Gaussian( x=x * u.m, y=y * u.m, width=width * u.m, length=length * u.m, psi=angle * u.deg, ) self.log.debug( "Frame=%d width=%03f length=%03f intens=%03d", frame, width, length, intens ) image, _, _ = model.generate_image( geom, intensity=intens, nsb_level_pe=3, ) # alternate between cleaned and raw images if self._counter == self.cleanframes: plt.suptitle("Image Cleaning ON") self.imclean = True if self._counter == self.cleanframes * 2: plt.suptitle("Image Cleaning OFF") self.imclean = False self._counter = 0 disp.clear_overlays() if self.imclean: cleanmask = tailcuts_clean(geom, image, picture_thresh=10.0, boundary_thresh=5.0) for ii in range(2): dilate(geom, cleanmask) image[cleanmask == 0] = 0 # zero noise pixels try: hillas = hillas_parameters(geom, image) disp.overlay_moments(hillas, with_label=False, color='red', alpha=0.7, linewidth=2, linestyle='dashed') except HillasParameterizationError: disp.clear_overlays() pass self.log.debug("Frame=%d image_sum=%.3f max=%.3f", self._counter, image.sum(), image.max()) disp.image = image if self.autoscale: disp.set_limits_percent(95) else: disp.set_limits_minmax(-5, 200) disp.axes.figure.canvas.draw() self._counter += 1 return [ax, ]
camgeoms = ('HESS-I', 'HESS-II', 'VERITAS', 'Whipple109', 'Whipple151') camgeoms_len = len(camgeoms) for camgeom_index, camgeom in enumerate(camgeoms): print( f'> ({camgeom_index + 1:{len(str(camgeoms_len))}}/{camgeoms_len}) camgeom={camgeom}' ) geom = CameraGeometry.from_name(camgeom) image = np.zeros(geom.n_pixels) for i in range(5): model = toymodel.Gaussian(x=np.random.uniform(-0.8, 0.8) * u.m, y=np.random.uniform(-0.8, 0.8) * u.m, width=np.random.uniform(0.05, 0.075) * u.m, length=np.random.uniform(0.1, 0.15) * u.m, psi=np.random.uniform(0, 2 * np.pi) * u.rad) new_image, sig, bg = model.generate_image(geom, intensity=np.random.uniform( 1000, 3000), nsb_level_pe=5) image += new_image disp = CameraDisplay(geom, image=image) plt.show(disp)
def test_reconstruction_in_telescope_frame(): """ Compare the reconstruction in the telescope and camera frame. """ np.random.seed(42) telescope_frame = TelescopeFrame() camera_frame = CameraFrame(focal_length=28 * u.m) geom = CameraGeometry.from_name("LSTCam") geom.frame = camera_frame geom_nom = geom.transform_to(telescope_frame) width = 0.03 * u.m length = 0.15 * u.m intensity = 500 xs = u.Quantity([0.5, 0.5, -0.5, -0.5], u.m) ys = u.Quantity([0.5, -0.5, 0.5, -0.5], u.m) psis = Angle([-90, -45, 0, 45, 90], unit="deg") def distance(coord): return np.sqrt(np.diff(coord.x)**2 + np.diff(coord.y)**2) / 2 def get_transformed_length(telescope_hillas, telescope_frame, camera_frame): main_edges = u.Quantity( [-telescope_hillas.length, telescope_hillas.length]) main_lon = main_edges * np.cos( telescope_hillas.psi) + telescope_hillas.fov_lon main_lat = main_edges * np.sin( telescope_hillas.psi) + telescope_hillas.fov_lat cam_main_axis = SkyCoord( fov_lon=main_lon, fov_lat=main_lat, frame=telescope_frame).transform_to(camera_frame) transformed_length = distance(cam_main_axis) return transformed_length def get_transformed_width(telescope_hillas, telescope_frame, camera_frame): secondary_edges = u.Quantity( [-telescope_hillas.width, telescope_hillas.width]) secondary_lon = (secondary_edges * np.cos(telescope_hillas.psi) + telescope_result.fov_lon) secondary_lat = (secondary_edges * np.sin(telescope_hillas.psi) + telescope_result.fov_lat) cam_secondary_edges = SkyCoord( fov_lon=secondary_lon, fov_lat=secondary_lat, frame=telescope_frame).transform_to(camera_frame) transformed_width = distance(cam_secondary_edges) return transformed_width for x, y in zip(xs, ys): for psi in psis: # generate a toy image model = toymodel.Gaussian(x=x, y=y, width=width, length=length, psi=psi) image, signal, noise = model.generate_image(geom, intensity=intensity, nsb_level_pe=5) telescope_result = hillas_parameters(geom_nom, signal) camera_result = hillas_parameters(geom, signal) assert camera_result.intensity == telescope_result.intensity # Compare results in both frames transformed_cog = SkyCoord( fov_lon=telescope_result.fov_lon, fov_lat=telescope_result.fov_lat, frame=telescope_frame, ).transform_to(camera_frame) assert u.isclose(transformed_cog.x, camera_result.x, rtol=0.01) assert u.isclose(transformed_cog.y, camera_result.y, rtol=0.01) transformed_length = get_transformed_length( telescope_result, telescope_frame, camera_frame) assert u.isclose(transformed_length, camera_result.length, rtol=0.01) transformed_width = get_transformed_width(telescope_result, telescope_frame, camera_frame) assert u.isclose(transformed_width, camera_result.width, rtol=0.01)
from ctapipe.image import toymodel from ctapipe.instrument import CameraGeometry from ctapipe.visualization import CameraDisplay if __name__ == '__main__': plt.style.use('ggplot') fig = plt.figure(figsize=(12, 8)) ax = fig.add_subplot(1, 1, 1) geom = CameraGeometry.from_name('NectarCam') disp = CameraDisplay(geom, ax=ax) disp.add_colorbar() model = toymodel.Gaussian(x=0.05 * u.m, y=0 * u.m, width=0.05 * u.m, length=0.15 * u.m, psi='35d') image, sig, bg = model.generate_image(geom, intensity=1500, nsb_level_pe=5) disp.image = image mask = disp.image > 10 disp.highlight_pixels(mask, linewidth=2, color='crimson') plt.show()
def toymodel_event_source(geoms, max_events=100, single_tel=False, n_channels=1, n_samples=25, p_trigger=0.3): """ An event source that produces array Parameters ---------- geoms : list of CameraGeometry instances Geometries for the telescopes to simulate max_events : int, default: 100 maximum number of events to create n_channels : int how many channels per telescope n_samples : int how many adc samples per pixel p_trigger : float mean trigger probability for the telescopes """ n_telescopes = len(geoms) container = DataContainer() container.meta['toymodel__max_events'] = max_events container.meta['source'] = "toymodel" tel_ids = np.arange(n_telescopes) for event_id in range(max_events): n_triggered = np.random.poisson(n_telescopes * 0.3) if n_triggered > n_telescopes: n_triggered = n_telescopes triggered_tels = np.random.choice(tel_ids, n_triggered, replace=False) container.r0.event_id = event_id container.r0.tels_with_data = triggered_tels container.count = event_id # handle single-telescope case (ignore others: if single_tel: if single_tel not in container.r0.tels_with_data: continue container.r0.tels_with_data = [ single_tel, ] container.r0.tel.reset() # clear the previous telescopes t = np.arange(n_samples) for tel_id in container.r0.tels_with_data: geom = geoms[tel_id] # fill pixel position dictionary, if not already done: if tel_id not in container.inst.pixel_pos: container.inst.pixel_pos[tel_id] = ( geom.pix_x.value, geom.pix_y.value, ) x, y = np.random.uniform(geom.pix_x.min(), geom.pix_y.max(), 2) length = np.random.uniform(0.02, 0.2) width = np.random.uniform(0.01, length) psi = np.random.randint(0, 360) intensity = np.random.poisson(int(10000 * width * length)) model = toymodel.Gaussian( x=x * u.m, y=y * u.m, length=length * u.m, width=width * u.m, psi=f'{psi}d', ) image, _, _ = model.generate_image( geom, intensity, ) # container.r0.tel[tel_id] = R0CameraContainer() container.inst.num_channels[tel_id] = n_channels n_pix = len(geom.pix_id) means = np.random.normal(15, 1, (n_pix, 1)) stds = np.random.uniform(3, 6, (n_pix, 1)) samples = image[:, np.newaxis] * norm.pdf(t, means, stds) for chan in range(n_channels): container.r0.tel[tel_id].waveform[chan] = samples container.r0.tel[tel_id].image[chan] = image yield container