Exemple #1
0
    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
Exemple #2
0
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)
Exemple #3
0
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)
Exemple #4
0
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")
Exemple #5
0
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
Exemple #6
0
        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})")