def sample_coord(self, map_coord, random_state=0): """Apply the energy dispersion corrections on the coordinates of a set of simulated events. Parameters ---------- map_coord : `~gammapy.maps.MapCoord` object. Sequence of coordinates and energies of sampled events. random_state : {int, 'random-seed', 'global-rng', `~numpy.random.RandomState`} Defines random number generator initialisation. Passed to `~gammapy.utils.random.get_random_state`. Returns ------- `~gammapy.maps.MapCoord`. Sequence of Edisp-corrected coordinates of the input map_coord map. """ random_state = get_random_state(random_state) migra_axis = self.edisp_map.geom.get_axis_by_name("migra") coord = { "skycoord": map_coord.skycoord.reshape(-1, 1), "energy_true": map_coord["energy_true"].reshape(-1, 1), "migra": migra_axis.center, } pdf_edisp = self.edisp_map.interp_by_coord(coord) sample_edisp = InverseCDFSampler(pdf_edisp, axis=1, random_state=random_state) pix_edisp = sample_edisp.sample_axis() migra = migra_axis.pix_to_coord(pix_edisp) energy_reco = map_coord["energy_true"] * migra return MapCoord.create({"skycoord": map_coord.skycoord, "energy": energy_reco})
def sample_coord(self, n_events, random_state=0): """Sample position and energy of events. Parameters ---------- n_events : int Number of events to sample. random_state : {int, 'random-seed', 'global-rng', `~numpy.random.RandomState`} Defines random number generator initialisation. Passed to `~gammapy.utils.random.get_random_state`. Returns ------- coords : `~gammapy.maps.MapCoord` object. Sequence of coordinates and energies of the sampled events. """ random_state = get_random_state(random_state) sampler = InverseCDFSampler(pdf=self.data, random_state=random_state) coords_pix = sampler.sample(n_events) coords = self.geom.pix_to_coord(coords_pix[::-1]) # TODO: pix_to_coord should return a MapCoord object axes_names = ["lon", "lat"] + self.geom.axes.names cdict = OrderedDict(zip(axes_names, coords)) return MapCoord.create(cdict, frame=self.geom.frame)
def test_norm_dist_sampling(): n_sampled = 1000 x = np.linspace(-2, 2, n_sampled) mu, sigma = 0, 0.1 pdf = gauss_dist(x=x, mu=mu, sigma=sigma) sampler = InverseCDFSampler(pdf=pdf, random_state=0) idx = sampler.sample(int(1e5)) x_sampled = np.interp(idx, np.arange(n_sampled), x) assert_allclose(np.mean(x_sampled), mu, atol=0.01) assert_allclose(np.std(x_sampled), sigma, atol=0.005)
def sample_time(self, n_events, t_min, t_max, t_delta="1 s", random_state=0): """Sample arrival times of events. Parameters ---------- n_events : int Number of events to sample. t_min : `~astropy.time.Time` Start time of the sampling. t_max : `~astropy.time.Time` Stop time of the sampling. t_delta : `~astropy.units.Quantity` Time step used for sampling of the temporal model. random_state : {int, 'random-seed', 'global-rng', `~numpy.random.RandomState`} Defines random number generator initialisation. Passed to `~gammapy.utils.random.get_random_state`. Returns ------- time : `~astropy.units.Quantity` Array with times of the sampled events. """ time_unit = getattr(u, self.table.meta["TIMEUNIT"]) t_min = Time(t_min) t_max = Time(t_max) t_delta = u.Quantity(t_delta) random_state = get_random_state(random_state) ontime = u.Quantity((t_max - t_min).sec, "s") t_stop = ontime.to_value(time_unit) # TODO: the separate time unit handling is unfortunate, but the quantity support for np.arange and np.interp # is still incomplete, refactor once we change to recent numpy and astropy versions t_step = t_delta.to_value(time_unit) t = np.arange(0, t_stop, t_step) pdf = self.evaluate(t) sampler = InverseCDFSampler(pdf=pdf, random_state=random_state) time_pix = sampler.sample(n_events)[0] time = np.interp(time_pix, np.arange(len(t)), t) * time_unit return t_min + time
def test_uniform_dist_sampling(): n_sampled = 1000 x = np.linspace(-2, 2, n_sampled) a, b = -1, 1 pdf = uniform_dist(x, a=a, b=b) sampler = InverseCDFSampler(pdf=pdf, random_state=0) idx = sampler.sample(int(1e4)) x_sampled = np.interp(idx, np.arange(n_sampled), x) assert_allclose(np.mean(x_sampled), 0.5 * (a + b), atol=0.01) assert_allclose(np.std(x_sampled), np.sqrt(1 / 3 * (a**2 + a * b + b**2)), rtol=0.01)
def test_axis_sampling(): n_sampled = 1000 x = np.linspace(-2, 2, n_sampled) a, b = -1, 1 pdf_uniform = uniform_dist(x, a=a, b=b) mu, sigma = 0, 0.1 pdf_gauss = gauss_dist(x=x, mu=mu, sigma=sigma) pdf = np.vstack([pdf_gauss, pdf_uniform]) sampler = InverseCDFSampler(pdf, random_state=0, axis=1) idx = sampler.sample_axis() x_sampled = np.interp(idx, np.arange(n_sampled), x) assert_allclose(x_sampled, [0.01042147, 0.43061014], rtol=1e-5)
def sample_coord(self, map_coord, random_state=0): """Apply PSF corrections on the coordinates of a set of simulated events. Parameters ---------- map_coord : `~gammapy.maps.MapCoord` object. Sequence of coordinates and energies of sampled events. random_state : {int, 'random-seed', 'global-rng', `~numpy.random.RandomState`} Defines random number generator initialisation. Passed to `~gammapy.utils.random.get_random_state`. Returns ------- corr_coord : `~gammapy.maps.MapCoord` object. Sequence of PSF-corrected coordinates of the input map_coord map. """ random_state = get_random_state(random_state) rad_axis = self.psf_map.geom.axes["rad"] coord = { "skycoord": map_coord.skycoord.reshape(-1, 1), "energy_true": map_coord["energy_true"].reshape(-1, 1), "rad": rad_axis.center, } pdf = ( self.psf_map.interp_by_coord(coord) * rad_axis.center.value * rad_axis.bin_width.value ) sample_pdf = InverseCDFSampler(pdf, axis=1, random_state=random_state) pix_coord = sample_pdf.sample_axis() separation = rad_axis.pix_to_coord(pix_coord) position_angle = random_state.uniform(360, size=len(map_coord.lon)) * u.deg event_positions = map_coord.skycoord.directional_offset_by( position_angle=position_angle, separation=separation ) return MapCoord.create( {"skycoord": event_positions, "energy_true": map_coord["energy_true"]} )