def test_significance_map_estimator_map_dataset_on_off(simple_dataset_on_off): estimator = ExcessMapEstimator(0.11 * u.deg, selection_optional=None) result = estimator.run(simple_dataset_on_off) assert_allclose(result["counts"].data[0, 10, 10], 194) assert_allclose(result["excess"].data[0, 10, 10], 97) assert_allclose(result["background"].data[0, 10, 10], 97) assert_allclose(result["significance"].data[0, 10, 10], 5.741116, atol=1e-5) estimator_image = ExcessMapEstimator(0.11 * u.deg, return_image=True) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["significance"].data[0, 10, 10], 5.741116, atol=1e-3) mask_fit = Map.from_geom( simple_dataset_on_off._geom, data=np.ones(simple_dataset_on_off.counts.data.shape, dtype=bool), ) mask_fit.data[:, :, 10] = False mask_fit.data[:, 10, :] = False simple_dataset_on_off.mask_fit = mask_fit estimator_image = ExcessMapEstimator(0.11 * u.deg, apply_mask_fit=True, return_image=True) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["significance"].data[0, 10, 10], 5.08179, atol=1e-3)
def test_significance_map_estimator_map_dataset(simple_dataset): estimator = ExcessMapEstimator(0.1 * u.deg, selection_optional=["all"]) result = estimator.run(simple_dataset) assert_allclose(result["counts"].data[0, 10, 10], 162) assert_allclose(result["excess"].data[0, 10, 10], 81) assert_allclose(result["background"].data[0, 10, 10], 81) assert_allclose(result["sqrt_ts"].data[0, 10, 10], 7.910732, atol=1e-5) assert_allclose(result["err"].data[0, 10, 10], 12.727922, atol=1e-3) assert_allclose(result["errp"].data[0, 10, 10], 13.063328, atol=1e-3) assert_allclose(result["errn"].data[0, 10, 10], -12.396716, atol=1e-3) assert_allclose(result["ul"].data[0, 10, 10], 107.806275, atol=1e-3) simple_dataset.exposure += 1e10 * u.cm**2 * u.s axis = simple_dataset.exposure.geom.axes[0] simple_dataset.psf = PSFMap.from_gauss(axis, sigma="0.05 deg") model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1 TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) simple_dataset.models = [model] simple_dataset.npred() estimator = ExcessMapEstimator(0.1 * u.deg, selection_optional="all") result = estimator.run(simple_dataset) assert_allclose(result["excess"].data.sum(), 19733.602, rtol=1e-3) assert_allclose(result["background"].data.sum(), 31818.398, rtol=1e-3) assert_allclose(result["sqrt_ts"].data[0, 10, 10], 4.217129, rtol=1e-3)
def test_excess_map_estimator_map_dataset_on_off_with_correlation_model( simple_dataset_on_off, ): model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) simple_dataset_on_off.models = [model] estimator_mod = ExcessMapEstimator(0.11 * u.deg, correlate_off=True) result_mod = estimator_mod.run(simple_dataset_on_off) assert result_mod["npred"].data.shape == (1, 20, 20) assert_allclose(result_mod["sqrt_ts"].data[0, 10, 10], 6.240846, atol=1e-3) assert_allclose(result_mod["npred"].data[0, 10, 10], 388) assert_allclose(result_mod["npred_excess"].data[0, 10, 10], 148.68057) assert result_mod["flux"].unit == "cm-2s-1" assert_allclose(result_mod["flux"].data[0, 10, 10], 1.486806e-08, rtol=1e-3) assert_allclose(result_mod["flux"].data.sum(), 5.254442e-06, rtol=1e-3)
def run(dataset, correlation_radius, sigma, negative): estimator_excess = ExcessMapEstimator( correlation_radius=correlation_radius, n_sigma=1, n_sigma_ul=3, selection_optional=None, energy_edges=energy_edges, ) result = estimator_excess.run(dataset) sources = find_peaks( result["sqrt_ts"], threshold=sigma, min_distance=correlation_radius, ) if negative is True: result["sqrt_ts"].data = -result["sqrt_ts"].data sources.vstack( find_peaks( result["sqrt_ts"], threshold=sigma, min_distance=correlation_radius, ) ) regions = [] for source in sources: skydir = SkyCoord(source["ra"], source["dec"], unit="deg", frame="icrs") if dataset.counts.geom.to_image().contains(skydir): regions.append(CircleSkyRegion(skydir, 0.2 * u.deg)) return dataset.counts.geom.to_image().region_mask(regions=regions, inside=False), result
def test_excess_map_estimator_map_dataset_on_off_reco_exposure( simple_dataset_on_off, ): # TODO: this has never worked... model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) simple_dataset_on_off.models = [model] spectral_model = PowerLawSpectralModel(index=15) estimator_mod = ExcessMapEstimator( 0.11 * u.deg, correlate_off=True, spectral_model=spectral_model, ) result_mod = estimator_mod.run(simple_dataset_on_off) assert result_mod["flux"].unit == "cm-2s-1" assert_allclose(result_mod["flux"].data.sum(), 5.254442e-06, rtol=1e-3) reco_exposure = estimate_exposure_reco_energy( simple_dataset_on_off, spectral_model=spectral_model) assert_allclose(reco_exposure.data.sum(), 7.977796e12, rtol=0.001)
def compute_correlations(stacked_on_off): # Using a convolution radius of 0.1 degrees estimator = ExcessMapEstimator(0.1 * u.deg) lima_maps = estimator.run(stacked_on_off) significance_map = lima_maps["sqrt_ts"] excess_map = lima_maps.npred_excess return significance_map, excess_map
def test_significance_map_estimator_map_dataset(simple_dataset): estimator = ExcessMapEstimator(0.1 * u.deg) result = estimator.run(simple_dataset) assert_allclose(result["counts"].data[0, 10, 10], 162) assert_allclose(result["excess"].data[0, 10, 10], 81) assert_allclose(result["background"].data[0, 10, 10], 81) assert_allclose(result["significance"].data[0, 10, 10], 7.910732, atol=1e-5) assert_allclose(result["err"].data[0, 10, 10], 12.727922, atol=1e-3) assert_allclose(result["errp"].data[0, 10, 10], 13.063328, atol=1e-3) assert_allclose(result["errn"].data[0, 10, 10], -12.396716, atol=1e-3) assert_allclose(result["ul"].data[0, 10, 10], 122.240837, atol=1e-3) estimator_image = ExcessMapEstimator(0.1 * u.deg, return_image=True) result_image = estimator_image.run(simple_dataset) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["significance"].data[0, 10, 10], 7.910732, atol=1e-5)
def test_significance_map_estimator_map_dataset_on_off(simple_dataset_on_off): estimator = ExcessMapEstimator(0.11 * u.deg) result = estimator.run(simple_dataset_on_off, steps=["ts"]) assert_allclose(result["counts"].data[0, 10, 10], 194) assert_allclose(result["excess"].data[0, 10, 10], 97) assert_allclose(result["background"].data[0, 10, 10], 97) assert_allclose(result["significance"].data[0, 10, 10], 5.741116, atol=1e-5)
def test_excess_map_estimator_map_dataset_on_off_with_correlation_no_exposure( simple_dataset_on_off, ): # First without exposure simple_dataset_on_off.exposure = None estimator = ExcessMapEstimator(0.11 * u.deg, energy_edges=[0.1, 1, 10] * u.TeV, correlate_off=True) result = estimator.run(simple_dataset_on_off) assert result["npred"].data.shape == (2, 20, 20) assert_allclose(result["npred"].data[:, 10, 10], 194) assert_allclose(result["npred_excess"].data[:, 10, 10], 97) assert_allclose(result["sqrt_ts"].data[:, 10, 10], 5.741116, atol=1e-5)
def test_significance_map_estimator_map_dataset(simple_dataset): estimator = ExcessMapEstimator(0.1 * u.deg) result = estimator.run(simple_dataset, steps="all") assert_allclose(result["counts"].data[0, 10, 10], 162) assert_allclose(result["excess"].data[0, 10, 10], 81) assert_allclose(result["background"].data[0, 10, 10], 81) assert_allclose(result["significance"].data[0, 10, 10], 7.910732, atol=1e-5) assert_allclose(result["err"].data[0, 10, 10], 12.727922, atol=1e-3) assert_allclose(result["errp"].data[0, 10, 10], 13.063328, atol=1e-3) assert_allclose(result["errn"].data[0, 10, 10], -12.396716, atol=1e-3) assert_allclose(result["ul"].data[0, 10, 10], 122.240837, atol=1e-3)
def test_excess_map_estimator_map_dataset_on_off_no_correlation( simple_dataset_on_off, ): # Test with exposure estimator_image = ExcessMapEstimator(0.11 * u.deg, energy_edges=[0.1, 1] * u.TeV, correlate_off=False) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["npred"].data.shape == (1, 20, 20) assert_allclose(result_image["npred"].data[0, 10, 10], 194) assert_allclose(result_image["npred_excess"].data[0, 10, 10], 97) assert_allclose(result_image["sqrt_ts"].data[0, 10, 10], 0.780125, atol=1e-3) assert_allclose(result_image["flux"].data[:, 10, 10], 9.7e-9, atol=1e-5)
def test_compute_lima_on_off_image(): """ Test Li & Ma image with snippet from the H.E.S.S. survey data. """ filename = "$GAMMAPY_DATA/tests/unbundled/hess/survey/hess_survey_snippet.fits.gz" n_on = Map.read(filename, hdu="ON") counts = image_to_cube(n_on, "1 TeV", "100 TeV") n_off = Map.read(filename, hdu="OFF") counts_off = image_to_cube(n_off, "1 TeV", "100 TeV") a_on = Map.read(filename, hdu="ONEXPOSURE") acceptance = image_to_cube(a_on, "1 TeV", "100 TeV") a_off = Map.read(filename, hdu="OFFEXPOSURE") acceptance_off = image_to_cube(a_off, "1 TeV", "100 TeV") dataset = MapDatasetOnOff( counts=counts, counts_off=counts_off, acceptance=acceptance, acceptance_off=acceptance_off, ) significance = Map.read(filename, hdu="SIGNIFICANCE") significance = image_to_cube(significance, "1 TeV", "10 TeV") estimator = ExcessMapEstimator("0.1 deg", correlate_off=False) results = estimator.run(dataset) # Reproduce safe significance threshold from HESS software results["sqrt_ts"].data[results["npred"].data < 5] = 0 # crop the image at the boundaries, because the reference image # is cut out from a large map, there is no way to reproduce the # result with regular boundary handling actual = results["sqrt_ts"].crop((11, 11)).data desired = significance.crop((11, 11)).data # Set boundary to NaN in reference image # The absolute tolerance is low because the method used here is slightly different from the one used in HGPS # n_off is convolved as well to ensure the method applies to true ON-OFF datasets assert_allclose(actual, desired, atol=0.2, rtol=1e-5) actual = np.nan_to_num(results["npred_background"].crop((11, 11)).data) background_corr = image_to_cube( Map.read(filename, hdu="BACKGROUNDCORRELATED"), "1 TeV", "100 TeV") desired = background_corr.crop((11, 11)).data # Set boundary to NaN in reference image # The absolute tolerance is low because the method used here is slightly different from the one used in HGPS # n_off is convolved as well to ensure the method applies to true ON-OFF datasets assert_allclose(actual, desired, atol=0.2, rtol=1e-5)
def test_compute_lima_image(): """ Test Li & Ma image against TS image for Tophat kernel """ filename = "$GAMMAPY_DATA/tests/unbundled/poisson_stats_image/input_all.fits.gz" counts = Map.read(filename, hdu="counts") counts = image_to_cube(counts, "1 GeV", "100 GeV") background = Map.read(filename, hdu="background") background = image_to_cube(background, "1 GeV", "100 GeV") dataset = MapDataset(counts=counts, background=background) estimator = ExcessMapEstimator("0.1 deg") result_lima = estimator.run(dataset) assert_allclose(result_lima["sqrt_ts"].data[:, 100, 100], 30.814916, atol=1e-3) assert_allclose(result_lima["sqrt_ts"].data[:, 1, 1], 0.164, atol=1e-3)
def test_compute_lima_image(): """ Test Li & Ma image against TS image for Tophat kernel """ filename = "$GAMMAPY_DATA/tests/unbundled/poisson_stats_image/input_all.fits.gz" counts = Map.read(filename, hdu="counts") counts = image_to_cube(counts, "1 GeV", "100 GeV") background = Map.read(filename, hdu="background") background = image_to_cube(background, "1 GeV", "100 GeV") background_model = BackgroundModel(background) dataset = MapDataset(counts=counts) background_model.datasets_names = [dataset.name] dataset.models = background_model estimator = ExcessMapEstimator("0.1 deg", selection_optional=None) result_lima = estimator.run(dataset) assert_allclose(result_lima["significance"].data[:, 100, 100], 30.814916, atol=1e-3) assert_allclose(result_lima["significance"].data[:, 1, 1], 0.164, atol=1e-3)
def test_significance_map_estimator_map_dataset_on_off_no_correlation( simple_dataset_on_off): exposure = simple_dataset_on_off.exposure exposure.data += 1e6 # Test with exposure simple_dataset_on_off.exposure = exposure estimator_image = ExcessMapEstimator(0.11 * u.deg, energy_edges=[0.1, 1] * u.TeV, correlate_off=False) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["counts"].data[0, 10, 10], 194) assert_allclose(result_image["excess"].data[0, 10, 10], 97) assert_allclose(result_image["background"].data[0, 10, 10], 97) assert_allclose(result_image["sqrt_ts"].data[0, 10, 10], 0.780125, atol=1e-3) assert_allclose(result_image["flux"].data[:, 10, 10], 9.7e-9, atol=1e-5)
def plot_residual_distribution(dataset, obs_id, livetime): """Plot residual significance distribution""" model = dataset.models[1] estimator = ExcessMapEstimator(correlation_radius="0.1 deg") maps = estimator.run(dataset) valid = np.isfinite(maps["sqrt_ts"].data) sig_resid = maps["sqrt_ts"].data[valid] plt.hist( sig_resid, density=True, alpha=0.5, color="red", bins=100, ) mu, std = norm.fit(sig_resid) # replace with log.info() log.info("Fit results: mu = {:.2f}, std = {:.2f}".format(mu, std)) x = np.linspace(-8, 8, 50) p = norm.pdf(x, mu, std) plt.plot( x, p, lw=2, color="black", label="Fit results: mu = {:.2f}, std = {:.2f}".format(mu, std), ) plt.legend() plt.xlabel("Significance") plt.yscale("log") plt.ylim(1e-5, 1) xmin, xmax = np.min(sig_resid), np.max(sig_resid) plt.xlim(xmin, xmax) obs_id = int(obs_id) filename = f"residuals-distribution_{obs_id:04d}.png" filepath = f"results/models/{model.name}/plots_{livetime.value:.0f}{livetime.unit}/residuals-distribution/{filename}" save_figure(filepath)
def test_significance_map_estimator_map_dataset(simple_dataset): simple_dataset.exposure = None estimator = ExcessMapEstimator(0.1 * u.deg, selection_optional=["all"]) result = estimator.run(simple_dataset) assert_allclose(result["npred"].data[0, 10, 10], 162) assert_allclose(result["npred_excess"].data[0, 10, 10], 81) assert_allclose(result["npred_background"].data[0, 10, 10], 81) assert_allclose(result["sqrt_ts"].data[0, 10, 10], 7.910732, atol=1e-5) assert_allclose(result["npred_excess_err"].data[0, 10, 10], 12.727922, atol=1e-3) assert_allclose(result["npred_excess_errp"].data[0, 10, 10], 13.063328, atol=1e-3) assert_allclose(result["npred_excess_errn"].data[0, 10, 10], 12.396716, atol=1e-3) assert_allclose(result["npred_excess_ul"].data[0, 10, 10], 107.806275, atol=1e-3)
def get_excess_map(self): """Calculate excess map with respect to the current model.""" excess_settings = self.config.excess_map log.info("Computing excess maps.") if self.config.datasets.type == "1d": raise ValueError("Cannot compute excess map for 1D dataset") # Here we could possibly stack the datasets if needed. if len(self.datasets) > 1: raise ValueError( "Datasets must be stacked to compute the excess map") energy_edges = self._make_energy_axis(excess_settings.energy_edges) if energy_edges is not None: energy_edges = energy_edges.edges excess_map_estimator = ExcessMapEstimator( correlation_radius=excess_settings.correlation_radius, energy_edges=energy_edges, **excess_settings.parameters) self.excess_map = excess_map_estimator.run(self.datasets[0])
def test_significance_map_estimator_map_dataset_exposure(simple_dataset): simple_dataset.exposure += 1e10 * u.cm**2 * u.s axis = simple_dataset.exposure.geom.axes[0] simple_dataset.psf = PSFMap.from_gauss(axis, sigma="0.05 deg") model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1 TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) simple_dataset.models = [model] simple_dataset.npred() estimator = ExcessMapEstimator(0.1 * u.deg, selection_optional="all") result = estimator.run(simple_dataset) assert_allclose(result["npred_excess"].data.sum(), 19733.602, rtol=1e-3) assert_allclose(result["sqrt_ts"].data[0, 10, 10], 4.217129, rtol=1e-3)
def test_excess_map_estimator_map_dataset_on_off_with_correlation_mask_fit( simple_dataset_on_off, ): geom = simple_dataset_on_off.counts.geom mask_fit = Map.from_geom(geom, data=1, dtype=bool) mask_fit.data[:, :, 10] = False mask_fit.data[:, 10, :] = False simple_dataset_on_off.mask_fit = mask_fit estimator_image = ExcessMapEstimator(0.11 * u.deg, correlate_off=True) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["npred"].data.shape == (1, 20, 20) assert_allclose(result_image["sqrt_ts"].data[0, 10, 10], np.nan, atol=1e-3) assert_allclose(result_image["npred"].data[0, 10, 10], np.nan) assert_allclose(result_image["npred_excess"].data[0, 10, 10], np.nan) assert_allclose(result_image["sqrt_ts"].data[0, 9, 9], 7.186745, atol=1e-3) assert_allclose(result_image["npred"].data[0, 9, 9], 304) assert_allclose(result_image["npred_excess"].data[0, 9, 9], 152) assert result_image["flux"].unit == u.Unit("cm-2s-1") assert_allclose(result_image["flux"].data[0, 9, 9], 1.190928e-08, rtol=1e-3)
def test_significance_map_estimator_map_dataset_on_off_with_correlation( simple_dataset_on_off, ): exposure = simple_dataset_on_off.exposure exposure.data += 1e6 # First without exposure simple_dataset_on_off.exposure = None estimator = ExcessMapEstimator(0.11 * u.deg, energy_edges=[0.1, 1, 10] * u.TeV, correlate_off=True) result = estimator.run(simple_dataset_on_off) assert result["counts"].data.shape == (2, 20, 20) assert_allclose(result["counts"].data[:, 10, 10], 194) assert_allclose(result["excess"].data[:, 10, 10], 97) assert_allclose(result["background"].data[:, 10, 10], 97) assert_allclose(result["sqrt_ts"].data[:, 10, 10], 5.741116, atol=1e-5) assert_allclose(result["flux"].data[:, 10, 10], np.nan) # Test with exposure simple_dataset_on_off.exposure = exposure estimator_image = ExcessMapEstimator(0.11 * u.deg, energy_edges=[0.1, 1] * u.TeV, correlate_off=True) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["counts"].data[0, 10, 10], 194) assert_allclose(result_image["excess"].data[0, 10, 10], 97) assert_allclose(result_image["background"].data[0, 10, 10], 97) assert_allclose(result_image["sqrt_ts"].data[0, 10, 10], 5.741116, atol=1e-3) assert_allclose(result_image["flux"].data[:, 10, 10], 9.7e-9, atol=1e-5) # Test with mask fit mask_fit = Map.from_geom( simple_dataset_on_off._geom, data=np.ones(simple_dataset_on_off.counts.data.shape, dtype=bool), ) mask_fit.data[:, :, 10] = False mask_fit.data[:, 10, :] = False simple_dataset_on_off.mask_fit = mask_fit estimator_image = ExcessMapEstimator(0.11 * u.deg, apply_mask_fit=True, correlate_off=True) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["sqrt_ts"].data[0, 10, 10], np.nan, atol=1e-3) assert_allclose(result_image["counts"].data[0, 10, 10], np.nan) assert_allclose(result_image["excess"].data[0, 10, 10], np.nan) assert_allclose(result_image["background"].data[0, 10, 10], np.nan) assert_allclose(result_image["sqrt_ts"].data[0, 9, 9], 7.186745, atol=1e-3) assert_allclose(result_image["counts"].data[0, 9, 9], 304) assert_allclose(result_image["excess"].data[0, 9, 9], 152) assert_allclose(result_image["background"].data[0, 9, 9], 152) assert result_image["flux"].unit == u.Unit("cm-2s-1") assert_allclose(result_image["flux"].data[0, 9, 9], 1.52e-8, rtol=1e-3) simple_dataset_on_off.psf = None # TODO: this has never worked... model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) simple_dataset_on_off.models = [model] estimator_mod = ExcessMapEstimator(0.11 * u.deg, apply_mask_fit=False, correlate_off=True) result_mod = estimator_mod.run(simple_dataset_on_off) assert result_mod["counts"].data.shape == (1, 20, 20) assert_allclose(result_mod["sqrt_ts"].data[0, 10, 10], 8.899278, atol=1e-3) assert_allclose(result_mod["counts"].data[0, 10, 10], 388) assert_allclose(result_mod["excess"].data[0, 10, 10], 190.68057) assert_allclose(result_mod["background"].data[0, 10, 10], 197.31943) assert result_mod["flux"].unit == "cm-2s-1" assert_allclose(result_mod["flux"].data[0, 10, 10], 1.906806e-08, rtol=1e-3) assert_allclose(result_mod["flux"].data.sum(), 5.920642e-06, rtol=1e-3) spectral_model = PowerLawSpectralModel(index=15) estimator_mod = ExcessMapEstimator( 0.11 * u.deg, apply_mask_fit=False, correlate_off=True, spectral_model=spectral_model, ) result_mod = estimator_mod.run(simple_dataset_on_off) assert result_mod["flux"].unit == "cm-2s-1" assert_allclose(result_mod["flux"].data.sum(), 5.920642e-06, rtol=1e-3) reco_exposure = estimate_exposure_reco_energy( simple_dataset_on_off, spectral_model=spectral_model) assert_allclose(reco_exposure.data.sum(), 7.977796e+12, rtol=0.001)
def test_significance_map_estimator_map_dataset_on_off(simple_dataset_on_off): estimator = ExcessMapEstimator( 0.11 * u.deg, selection_optional=None, e_edges=[0.1 * u.TeV, 1 * u.TeV, 10 * u.TeV], ) result = estimator.run(simple_dataset_on_off) assert result["counts"].data.shape == (2, 20, 20) assert_allclose(result["counts"].data[:, 10, 10], 194) assert_allclose(result["excess"].data[:, 10, 10], 97) assert_allclose(result["background"].data[:, 10, 10], 97) assert_allclose(result["significance"].data[:, 10, 10], 5.741116, atol=1e-5) estimator_image = ExcessMapEstimator(0.11 * u.deg, e_edges=[0.1 * u.TeV, 1 * u.TeV]) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["significance"].data[0, 10, 10], 5.741116, atol=1e-3) mask_fit = Map.from_geom( simple_dataset_on_off._geom, data=np.ones(simple_dataset_on_off.counts.data.shape, dtype=bool), ) mask_fit.data[:, :, 10] = False mask_fit.data[:, 10, :] = False simple_dataset_on_off.mask_fit = mask_fit estimator_image = ExcessMapEstimator(0.11 * u.deg, apply_mask_fit=True) simple_dataset_on_off.exposure.data = ( np.ones(simple_dataset_on_off.exposure.data.shape) * 1e6 ) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["significance"].data[0, 10, 10], 7.186745, atol=1e-3) assert_allclose(result_image["counts"].data[0, 10, 10], 304) assert_allclose(result_image["excess"].data[0, 10, 10], 152) assert_allclose(result_image["background"].data[0, 10, 10], 152) assert result_image["flux"].unit == u.Unit("cm-2s-1") assert_allclose(result_image["flux"].data[0, 10, 10], 7.6e-9, rtol=1e-3) # test with an npred() simple_dataset_on_off.exposure.data = ( np.ones(simple_dataset_on_off.exposure.data.shape) * 1e10 ) simple_dataset_on_off.psf = None model = SkyModel( PowerLawSpectralModel(), GaussianSpatialModel( lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs" ), datasets_names=[simple_dataset_on_off.name], name="sky_model", ) simple_dataset_on_off.models.append(model) estimator_mod = ExcessMapEstimator(0.11 * u.deg, apply_mask_fit=False) result_mod = estimator_mod.run(simple_dataset_on_off) assert result_mod["counts"].data.shape == (1, 20, 20) assert_allclose(result_mod["significance"].data[0, 10, 10], 8.119164, atol=1e-3) assert_allclose(result_mod["counts"].data[0, 10, 10], 388) assert_allclose(result_mod["excess"].data[0, 10, 10], 194) assert_allclose(result_mod["background"].data[0, 10, 10], 194) assert result_mod["flux"].unit == u.Unit("cm-2s-1") assert_allclose(result_image["flux"].data[0, 10, 10], 7.6e-9, rtol=1e-3)
def test_significance_map_estimator_map_dataset_on_off(simple_dataset_on_off): exposure = simple_dataset_on_off.exposure exposure.data += 1e6 # First without exposure simple_dataset_on_off.exposure = None estimator = ExcessMapEstimator( 0.11 * u.deg, selection_optional=None, energy_edges=[0.1, 1, 10] * u.TeV, ) result = estimator.run(simple_dataset_on_off) assert result["counts"].data.shape == (2, 20, 20) assert_allclose(result["counts"].data[:, 10, 10], 194) assert_allclose(result["excess"].data[:, 10, 10], 97) assert_allclose(result["background"].data[:, 10, 10], 97) assert_allclose(result["sqrt_ts"].data[:, 10, 10], 5.741116, atol=1e-5) assert_allclose(result["flux"].data[:, 10, 10], np.nan) # Test with exposure simple_dataset_on_off.exposure = exposure estimator_image = ExcessMapEstimator(0.11 * u.deg, energy_edges=[0.1, 1] * u.TeV) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["counts"].data[0, 10, 10], 194) assert_allclose(result_image["excess"].data[0, 10, 10], 97) assert_allclose(result_image["background"].data[0, 10, 10], 97) assert_allclose(result_image["sqrt_ts"].data[0, 10, 10], 5.741116, atol=1e-3) assert_allclose(result_image["flux"].data[:, 10, 10], 9.7e-9, atol=1e-5) # Test with mask fit mask_fit = Map.from_geom( simple_dataset_on_off._geom, data=np.ones(simple_dataset_on_off.counts.data.shape, dtype=bool), ) mask_fit.data[:, :, 10] = False mask_fit.data[:, 10, :] = False simple_dataset_on_off.mask_fit = mask_fit estimator_image = ExcessMapEstimator(0.11 * u.deg, apply_mask_fit=True) result_image = estimator_image.run(simple_dataset_on_off) assert result_image["counts"].data.shape == (1, 20, 20) assert_allclose(result_image["sqrt_ts"].data[0, 10, 10], np.nan, atol=1e-3) assert_allclose(result_image["counts"].data[0, 10, 10], np.nan) assert_allclose(result_image["excess"].data[0, 10, 10], np.nan) assert_allclose(result_image["background"].data[0, 10, 10], np.nan) assert_allclose(result_image["sqrt_ts"].data[0, 9, 9], 7.186745, atol=1e-3) assert_allclose(result_image["counts"].data[0, 9, 9], 304) assert_allclose(result_image["excess"].data[0, 9, 9], 152) assert_allclose(result_image["background"].data[0, 9, 9], 152) assert result_image["flux"].unit == u.Unit("cm-2s-1") assert_allclose(result_image["flux"].data[0, 9, 9], 1.52e-8, rtol=1e-3) simple_dataset_on_off.psf = None # TODO: this has never worked... model = SkyModel( PowerLawSpectralModel(amplitude="1e-9 cm-2 s-1TeV-1"), GaussianSpatialModel(lat_0=0.0 * u.deg, lon_0=0.0 * u.deg, sigma=0.1 * u.deg, frame="icrs"), name="sky_model", ) # simple_dataset_on_off.models = [model] estimator_mod = ExcessMapEstimator(0.11 * u.deg, apply_mask_fit=False) result_mod = estimator_mod.run(simple_dataset_on_off) assert result_mod["counts"].data.shape == (1, 20, 20) assert_allclose(result_mod["sqrt_ts"].data[0, 10, 10], 6.240846, atol=1e-3) assert_allclose(result_mod["counts"].data[0, 10, 10], 388) assert_allclose(result_mod["excess"].data[0, 10, 10], 148.68057) assert_allclose(result_mod["background"].data[0, 10, 10], 239.31943) assert result_mod["flux"].unit == u.Unit("cm-2s-1") assert_allclose(result_mod["flux"].data[0, 10, 10], 1.486806e-08, rtol=1e-3)
def estimate_significance_luca( dataset, first_guess_exclusion, correlation_radii, energy_edgess, n_iter, low, high, negative=False ): for nn in range(n_iter): print(f"###########") print(nn) print(f"###########") results = [] for correlation_radius, energy_edges in zip(correlation_radii, energy_edgess): estimator_excess = ExcessMapEstimator( correlation_radius=correlation_radius, n_sigma=1, n_sigma_ul=3, selection_optional=None, energy_edges=energy_edges, ) results.append(estimator_excess.run(dataset)) def _reproject_exclusion_mask(geom, exclusion): """Reproject the exclusion on the dataset geometry""" mask_map = Map.from_geom(geom) coords = geom.get_coord() vals = exclusion.get_by_coord(coords) mask_map.data += vals return mask_map first_guess_exclusion = _reproject_exclusion_mask(dataset.counts.geom, first_guess_exclusion).slice_by_idx({"energy" : 0}) plt.figure(figsize=(8, 6)) for correlation_radius, energy_edges, result in zip(correlation_radii, energy_edgess, results): (result["sqrt_ts"].slice_by_idx({"energy" : 0})*first_guess_exclusion).plot(add_cbar=True, cmap="coolwarm", vmin=-5, vmax=5) plt.title(f"{correlation_radius} {energy_edges}") plt.show() plt.close() exclusion_enlarged = first_guess_exclusion.copy() # Enlarge exclusion mask for result, radius in zip(results, correlation_radii): mask_map_significance = result["sqrt_ts"].copy().slice_by_idx({"energy" : 0}) mask_map_significance.data = np.nan_to_num(mask_map_significance.data) mask_map = mask_map_significance.copy() mask_map.data = ~apply_hysteresis_threshold(mask_map_significance.data, low=low, high=high) if negative == True: mask_map.data *= ~apply_hysteresis_threshold(-mask_map_significance.data, low=low, high=high) exclusion_enlarged *= mask_map plt.figure(figsize=(8, 6)) first_guess_exclusion.plot() plt.contour(exclusion_enlarged.data, levels=1, colors="r", inewidths=2) plt.show() plt.close() for correlation_radius, energy_edges, result in zip(correlation_radii, energy_edgess, results): pretty_plot_1d_significance(result, correlation_radius, energy_edges, exclusion_enlarged) first_guess_exclusion = exclusion_enlarged print(f"###########") print("Final result") print(f"###########") for correlation_radius, energy_edges, result in zip(correlation_radii, energy_edgess, results): plt.figure(figsize=(8, 6)) final = (result["sqrt_ts"].slice_by_idx({"energy" : 0})) final.plot(add_cbar=True, cmap="coolwarm", vmin=-5, vmax=5) cs = plt.contour(final.data, levels=(-15, -10, -7, -5, -3, 3, 5, 7, 10, 15), colors="k") plt.clabel(cs, colors="k") plt.title(f"{correlation_radius} {energy_edges}") plt.show() plt.close()