def EBLabsorbed(self, tab, model, debug=False): """ Return the EBL-absorbed model. Absorption data are either obtained from the Gammapy datasets or form external proprietary files. Parameters ---------- tab : TemplateSpectralModel A flux versus energy as an interpolated table. model : String An EBL model name among those available. debug : Boolean, optional If True let's talk a bit. The default is False. Returns ------- attflux : TemplateSpectralModel An attenuated flux versus energy as an interpolated table. """ attflux = tab if (model == "gilmore"): from ebl import EBL_from_file eblabs = EBL_from_file("EBL/data/ebl_gilmore12-10GeV.dat") attflux.values = tab.values * eblabs(self.Eval, self.z) if debug: print(" EBL : Gilmore") elif model != None and model != 'in-file': eblabs = EBLAbsorptionNormSpectralModel.read_builtin( model, redshift=self.z) attflux = tab * eblabs if debug: print(" EBL : ", model) return attflux
def test_absorbed_extrapolate(): ebl_model = "dominguez" z = 0.0001 alpha_norm = 1 absorption = EBLAbsorptionNormSpectralModel.read_builtin(ebl_model) values = absorption.evaluate(1 * u.TeV, z, alpha_norm) assert_allclose(values, 1)
def test_absorption(): # absorption values for given redshift redshift = 0.117 absorption = EBLAbsorptionNormSpectralModel.read_builtin("dominguez", redshift=redshift) # Spectral model corresponding to PKS 2155-304 (quiescent state) index = 3.53 amplitude = 1.81 * 1e-12 * u.Unit("cm-2 s-1 TeV-1") reference = 1 * u.TeV pwl = PowerLawSpectralModel(index=index, amplitude=amplitude, reference=reference) # EBL + PWL model model = pwl * absorption desired = u.Quantity(5.140765e-13, "TeV-1 s-1 cm-2") assert_quantity_allclose(model(1 * u.TeV), desired, rtol=1e-3) assert model.model2.alpha_norm.value == 1.0 # EBL + PWL model: test if norm of EBL=0: it mean model =pwl model.parameters["alpha_norm"].value = 0 assert_quantity_allclose(model(1 * u.TeV), pwl(1 * u.TeV), rtol=1e-3) # EBL + PWL model: Test with a norm different of 1 absorption = EBLAbsorptionNormSpectralModel.read_builtin("dominguez", redshift=redshift, alpha_norm=1.5) model = pwl * absorption desired = u.Quantity(2.739695e-13, "TeV-1 s-1 cm-2") assert model.model2.alpha_norm.value == 1.5 assert_quantity_allclose(model(1 * u.TeV), desired, rtol=1e-3) # Test error propagation model.model1.amplitude.error = 0.1 * model.model1.amplitude.value dnde, dnde_err = model.evaluate_error(1 * u.TeV) assert_allclose(dnde_err / dnde, 0.1)
def test_absorption_io(tmp_path): dominguez = EBLAbsorptionNormSpectralModel.read_builtin("dominguez", redshift=0.5) assert len(dominguez.parameters) == 2 model_dict = dominguez.to_dict() parnames = [_["name"] for _ in model_dict["parameters"]] assert parnames == [ "alpha_norm", "redshift", ] new_model = EBLAbsorptionNormSpectralModel.from_dict(model_dict) assert new_model.redshift.value == 0.5 assert new_model.alpha_norm.name == "alpha_norm" assert new_model.alpha_norm.value == 1 assert_allclose(new_model.energy, dominguez.energy) assert_allclose(new_model.param, dominguez.param) assert len(new_model.parameters) == 2 model = EBLAbsorptionNormSpectralModel( u.Quantity(range(3), "keV"), u.Quantity(range(2), ""), u.Quantity(np.ones((2, 3)), ""), redshift=0.5, alpha_norm=1, ) model_dict = model.to_dict() new_model = EBLAbsorptionNormSpectralModel.from_dict(model_dict) assert_allclose(new_model.energy, model.energy) assert_allclose(new_model.param, model.param) assert_allclose(new_model.data, model.data) write_yaml(model_dict, tmp_path / "tmp.yaml") read_yaml(tmp_path / "tmp.yaml")
def perform_casc_fit(config, geom, ps_model, llh, dataset, on_radius=Angle("0.07 deg"), B=1e-16, plot=False): """ Perform the combined cascade fit Parameters ---------- config: dict Configuration dictionary B: float B-field strength geom:`~gammapy.maps.WcsGeom` object geometry of the dataset on_radius: `~astropy.coordinates.Angle` object Radius of ON region of IACT analysis ps_model: `gammapy.model.modeling.models` object Assumed point source model llh: `simCRpropa.fermiinterp.LogLikeCubeFermi` Interpolated Fermi likelihood cube dataset: `~gammapy.datasets.SpectrumOnOffDataset` The IACT data set plot: bool If true, generate diagnostic plots Returns ------- Tuple containing -2 * ln (likelihood values) for fit on Fermi-LAT data only and combined fit """ logging.info(f" ------ B = {B:.2e} ------- ") # Load the cascade # generate a casc map with low # spatial resolution to speed up calculations ebl = EBLAbsorptionNormSpectralModel.read( filename=config['global']['gammapy_ebl_file'], redshift=config[src]['z_src']) casc_file = config['global']['casc_file'].replace( "*", "{0:.3f}".format(config[src]['z_casc']), 1) casc_file = casc_file.replace("*", "{0:.2e}".format(B)) casc_1d = CascMap.gen_from_hd5f( casc_file, skycoord=geom.center_skydir, width=2 * np.round(on_radius.value / geom.pixel_scales[0].value, 0) * geom.pixel_scales[0].value, binsz=geom.pixel_scales[0].value, ebins=21, id_detection=22, smooth_kwargs={ 'kernel': Gaussian2DKernel, 'threshold': 2., 'steps': 50 }) # Initialize the cascade model # use the best fit model for the intrinsic spectrum logging.info("Initializing cascade model ...") casc_spec = CascadeSpectralModel(casc_1d, ps_model.spectral_model.model1.copy(), ebl, on_region, rotation=config['global']['rotation'] * u.deg, tmax=config['global']['tmax'] * u.yr, bias=0. * u.dimensionless_unscaled, energy_unit_spectral_model="TeV", use_gammapy_interp=False) # Plot the total model if plot: energy_power = 2 fig = plt.figure(dpi=150) ax = fig.add_subplot(111) e_range = [1e-3, 10.] * u.TeV casc_spec.add_primary = True casc_spec.plot(ax=ax, energy_range=e_range, energy_power=energy_power) ps_model.spectral_model.plot(ax=ax, energy_range=e_range, energy_power=energy_power) casc_spec.add_primary = False casc_spec.plot(ax=ax, energy_range=e_range, energy_power=energy_power) casc_spec.add_primary = True plt.ylim(1e-15, 3e-12) ax.grid() fig.savefig(f"plots/{src:s}_B{B}_casc+ps_models.png") plt.close("all") # Perform the fit with the cascade casc_model = SkyModel(spectral_model=casc_spec, name='casc') # limit the parameter ranges and change the tolerance # index casc_model.parameters['index'].min = llh.params['Index'].min() casc_model.parameters['index'].max = llh.params['Index'].max() # amplitude casc_model.parameters[ 'amplitude'].min = casc_model.parameters['amplitude'].value / 10. casc_model.parameters[ 'amplitude'].max = casc_model.parameters['amplitude'].value * 10. # cutoff casc_model.parameters['lambda_'].min = 1. / llh.params['Cutoff'].max() casc_model.parameters['lambda_'].max = 1. / llh.params['Cutoff'].min() casc_model.parameters['lambda_'].frozen = config['global']['fix_cutoff'] # bias between Fermi and HESS casc_model.parameters['bias'].value = 0. casc_model.parameters['bias'].frozen = config['global']['fix_bias'] logging.info(f"Initial parameters:\n{casc_model.parameters.to_table()}") # interpolate the fermi likelihood for the right B field # TODO: changes necessary if more than one coherence length or theta jet used idb = np.where(llh.params["B"] == B)[0][0] llh.interp_llh( llh.params["B"][idb], # choose a B field - should match casc file llh.params["maxTurbScale"] [0], # choose a turb scale - should match casc file llh.params["th_jet"] [0], # choose a jet opening angle - should match casc file method='linear', ) # plot the interpolation if plot: fig = plt.figure(dpi=150) ax = fig.add_subplot(111) # plot a likelihood surface # choose a slice in cut off energy cut_id = 0 # build a grid of indices and norms ii, nn = np.meshgrid(llh._params["Index"], llh.log_norm_array, indexing='ij') # plot the log likehood grid dlogl = 2. * (llh._llh_grid[cut_id] - llh._llh_grid[cut_id].max()) vmin = -100. # check if most points have higher dlogl, # and if so, adjust color scaling if dlogl[dlogl > vmin].size < 10: vmin = 3. * dlogl[dlogl < 0].max() im = ax.pcolormesh(ii, nn, dlogl, cmap=cmap_name, vmin=vmin, vmax=0) ax.annotate("$E_\mathrm{{cut}} = {0:.0f}$TeV".format( llh.params["Cutoff"][cut_id]), xy=(0.05, 0.95), xycoords='axes fraction', color='w', va='top', fontsize='x-large') plt.colorbar(im, label='$\ln\mathcal{L}$') ax.tick_params(direction='out') plt.xlabel("$\Gamma$") plt.ylabel("$\log_{10}(N)$") plt.grid(color='0.7', ls=':') plt.subplots_adjust(bottom=0.2, left=0.2) fig.savefig( "plots/{1:s}_lnl_fermi_grid_Ecut{0:.0f}TeV_B{2}.png".format( llh.params["Cutoff"][cut_id], src, B)) plt.close("all") # initialize prior data set logging.info("Initializing data set with priors") prior_stack = PriorSpectrumDatasetOnOff.from_spectrum_dataset_fermi_interp( dataset, llh_fermi_interp=None) # add the interpolator to the data set prior_stack.llh_fermi_interp = llh.interp # add the reference energy at which interpolation was performed (in MeV) prior_stack.ref_energy = src_dict['spectral_pars']['Scale']['value'] prior_stack.models = casc_model logging.info("Performing combined fit") fit_casc = Fit([prior_stack]) fit_result_casc = fit_casc.run(optimize_opts=dict( print_level=2, tol=10., migrad_opts=dict(ncall=1000))) logging.info(f"Parameters after fit:\n{casc_model.parameters.to_table()}") logging.info(f"Total stat after fit {fit_result_casc.total_stat}") logging.info(f"Fermi logl after fit {prior_stack.llh_fermi}") # plot the flux points if plot: fig = plt.figure(dpi=150) ax = flux_points.plot(energy_power=2., label='data', marker='o') if not casc_model.parameters['bias'].value == 0.: fp = flux_points.table.copy() fp['e_ref'] *= 1. + casc_model.parameters['bias'].value fp['e_min'] *= 1. + casc_model.parameters['bias'].value fp['e_max'] *= 1. + casc_model.parameters['bias'].value fp_rescale = FluxPoints(fp) fp_rescale.plot(ax=ax, energy_power=2., label='data rescaled', marker='o', color='green') # plot the final model e_range = [1e-3, 10.] * u.TeV # total model casc_model.spectral_model.add_primary = True casc_model.spectral_model.plot(ax=ax, energy_range=e_range, energy_power=2, label='Total', color='k') casc_model.spectral_model.plot_error(ax=ax, energy_range=e_range, energy_power=2) # point source obs_model = casc_model.spectral_model.intrinsic_spectral_model * casc_model.spectral_model.ebl # cascade casc_model.spectral_model.add_primary = False casc_model.spectral_model.plot(ax=ax, energy_range=e_range, energy_power=2, label='Cascade', color='k', ls='-.') casc_model.spectral_model.add_primary = True if casc_model.parameters['bias'].value == 0.: obs_model.plot(ax=ax, energy_range=e_range, energy_power=2, label='Point source', color='k', ls='--') else: casc_model.parameters['bias'].value = 0. obs_model.plot(ax=ax, energy_range=e_range, energy_power=2, label='Point source', color='green', ls='--') casc_model.spectral_model.plot(ax=ax, energy_range=e_range, energy_power=2, label='Total, bias = 0', color='green', ls=':') # cascade casc_model.spectral_model.add_primary = False casc_model.spectral_model.plot(ax=ax, energy_range=e_range, energy_power=2, label='Cascade', color='green', ls='-.') casc_model.spectral_model.add_primary = True pass # fermi SED SEDPlotter.plot_sed( sed, ax=ax, ms=6., marker='.', color='C1', mec='C1', alpha=1., noline=False, band_alpha=0.2, line_alpha=0.5, band_linestyle='-', label="Fermi", flux_unit='TeV cm-2 s-1', energy_unit='TeV', print_name=False, # apply bias to fermi data, in fit it's the other way around #bias=casc_model.parameters['bias'].value ) ax.legend(loc='lower center') plt.ylim(3e-15, 2e-10) plt.xlim(1e-3, 2e1) fig.savefig(f"plots/final_fits_{src:s}_b{B}.png") plt.close("all") # plot a likelihood surface for best cut value if plot: par_amp = prior_stack.models['casc'].parameters['amplitude'] amp = np.logspace( np.log10(par_amp.value) - 1., np.log10(par_amp.value) + .5, 100) amp *= par_amp.unit par_idx = prior_stack.models['casc'].parameters['index'] idx = np.linspace(par_idx.value - .5, par_idx.value + 1., 120) idx *= par_idx.unit ii, aa = np.meshgrid(idx, amp, indexing='ij') c_stat = prior_stack.get_llh_fermi(amplitude=aa.reshape(-1), index=ii.reshape(-1), set_attribute=False).reshape( aa.shape) #ii, nn = np.meshgrid(idx, llh.log_norm_array, indexing='ij') #c_stat = np.zeros((idx.shape[0], amp.shape[0])) #for i, iidx in enumerate(idx): #for j, a in enumerate(amp): #c_stat[i,j] = prior_stack.get_llh_fermi(amplitude=a, index=iidx, set_attribute=False) #c_stat = np.zeros((idx.shape[0], llh.log_norm_array.shape[0])) #for i, iidx in enumerate(idx.value): # for j, log_norm in enumerate(llh.log_norm_array): # c_stat[i,j] = prior_stack.get_llh_fermi(amplitude=10.**log_norm * u.Unit('MeV-1 s-1 cm-2'), # index=iidx * u.dimensionless_unscaled, # set_attribute=False, # reference=prior_stack._ref_energy * u.MeV) d_cstat = 2. * (c_stat - c_stat.min()) fig = plt.figure(dpi=150) ax = fig.add_subplot(111) vmin = 0. vmax = 300. im = ax.pcolormesh(ii.value, np.log10(aa.value), d_cstat, cmap=cmap_name, vmin=vmin, vmax=vmax) #im = ax.pcolormesh(ii, nn, d_cstat, cmap=cmap_name, vmin=vmin, vmax=vmax) ax.annotate("$E_\mathrm{{cut}} = {0:.2f}$TeV, $B={1:.2e}$G".format( 1. / prior_stack.models['casc'].parameters['lambda_'].value, B), xy=(0.05, 0.95), xycoords='axes fraction', color='k', va='top', fontsize='x-large') plt.colorbar(im, label='$-2\Delta\ln\mathcal{L}$') ax.plot(par_idx.value, np.log10(par_amp.value), ms=10., marker='*', mec='k') ax.tick_params(direction='out') plt.xlabel("$\Gamma$") plt.ylabel( "$\log_{10}(N_\mathrm{H.E.S.S.}) = \log_{10}((E_{0,{Fermi}} / E_{0,\mathrm{H.E.S.S.}})^{-\Gamma}N_{Fermi})$", fontsize='medium') plt.grid(color='0.7', ls=':') plt.subplots_adjust(bottom=0.2, left=0.2) fig.savefig("plots/{0:s}_lnl_fermi_interp_B{1}.png".format(src, B)) plt.close("all") return prior_stack, prior_stack.llh_fermi, fit_result_casc.total_stat
llh.get_llh_one_source(src, norm_key='dnde_src') # Define the model for the intrinsic / observed blazar spectrum epl = ExpCutoffPowerLawSpectralModel( amplitude=1e-12 * u.Unit("cm-2 s-1 TeV-1"), index=1.6 * u.dimensionless_unscaled, lambda_=0.1 * u.Unit("TeV-1"), reference=1 * u.TeV, ) #epl.parameters['lambda_'].min = 0. #epl.parameters['lambda_'].max = 1. epl.parameters['lambda_'].min = 1. / llh.params['Cutoff'].max() epl.parameters['lambda_'].max = 1. / llh.params['Cutoff'].min() ebl = EBLAbsorptionNormSpectralModel.read( filename=config['global']['gammapy_ebl_file'], redshift=config[src]['z_src']) obs = epl * ebl # fit the point source model # without the cascade logging.info("Fitting IACT data with point source") ps_model = SkyModel(spectral_model=obs.copy(), name='ps') dataset_stack[0].models = ps_model fit_1d = Fit(dataset_stack) fit_result_ps = fit_1d.run(optimize_opts=dict( print_level=1, tol=0.1, migrad_opts=dict(ncall=1000))) ps_model.parameters.to_table() ps_model_table = ps_model.spectral_model.model1.parameters.to_table()
# Here is an example plot of the model: from astropy import units as u import matplotlib.pyplot as plt from gammapy.modeling.models import ( EBLAbsorptionNormSpectralModel, Models, PowerLawSpectralModel, SkyModel, ) # Here we illustrate how to create and plot EBL absorption models for a redshift of 0.5 # sphinx_gallery_thumbnail_number = 1 redshift = 0.5 dominguez = EBLAbsorptionNormSpectralModel.read_builtin("dominguez", redshift=redshift) franceschini = EBLAbsorptionNormSpectralModel.read_builtin("franceschini", redshift=redshift) finke = EBLAbsorptionNormSpectralModel.read_builtin("finke", redshift=redshift) plt.figure() energy_bounds = [0.08, 3] * u.TeV opts = dict(energy_bounds=energy_bounds, xunits=u.TeV) franceschini.plot(label="Franceschini 2008", **opts) finke.plot(label="Finke 2010", **opts) dominguez.plot(label="Dominguez 2011", **opts) plt.ylabel(r"Absorption coefficient [$\exp{(-\tau(E))}$]") plt.xlim(energy_bounds.value) plt.ylim(1e-4, 2) plt.title(f"EBL models (z={redshift})")