Exemple #1
0
    def flux_points(self):
        """Flux points (`~gammapy.spectrum.FluxPoints`)."""
        table = Table()
        table.meta["SED_TYPE"] = "flux"
        table["e_min"] = self._ebounds[:-1]
        table["e_max"] = self._ebounds[1:]

        flux = self.data["Flux_Band"]
        flux_err = self.data["Unc_Flux_Band"]
        e2dnde = self.data["nuFnu"]

        table["flux"] = flux
        table["flux_errn"] = np.abs(flux_err[:, 0])
        table["flux_errp"] = flux_err[:, 1]

        table["e2dnde"] = e2dnde
        table["e2dnde_errn"] = np.abs(e2dnde * flux_err[:, 0] / flux)
        table["e2dnde_errp"] = e2dnde * flux_err[:, 1] / flux

        is_ul = np.isnan(table["flux_errn"])
        table["is_ul"] = is_ul

        # handle upper limits
        table["flux_ul"] = np.nan * flux_err.unit
        flux_ul = compute_flux_points_ul(table["flux"], table["flux_errp"])
        table["flux_ul"][is_ul] = flux_ul[is_ul]

        table["e2dnde_ul"] = np.nan * e2dnde.unit
        e2dnde_ul = compute_flux_points_ul(table["e2dnde"],
                                           table["e2dnde_errp"])
        table["e2dnde_ul"][is_ul] = e2dnde_ul[is_ul]

        # Square root of test statistic
        table["sqrt_ts"] = self.data["Sqrt_TS_Band"]
        return FluxPoints(table)
Exemple #2
0
    def from_dict(cls, data, **kwargs):
        """Create flux point dataset from dict.

        Parameters
        ----------
        data : dict
            Dict containing data to create dataset from.

        Returns
        -------
        dataset : `FluxPointsDataset`
            Flux point datasets.
        """
        from gammapy.estimators import FluxPoints

        filename = make_path(data["filename"])
        table = Table.read(filename)
        mask_fit = table["mask_fit"].data.astype("bool")
        mask_safe = table["mask_safe"].data.astype("bool")
        table.remove_columns(["mask_fit", "mask_safe"])
        return cls(
            name=data["name"],
            data=FluxPoints(table),
            mask_fit=mask_fit,
            mask_safe=mask_safe,
        )
Exemple #3
0
    def from_dict(cls, data, models):
        """Create flux point dataset from dict.

        Parameters
        ----------
        data : dict
            Dict containing data to create dataset from.
        models : list of `SkyModel`
            List of model components.

        Returns
        -------
        dataset : `FluxPointsDataset`
            Flux point datasets.
        """
        from gammapy.estimators import FluxPoints

        table = Table.read(data["filename"])
        mask_fit = table["mask_fit"].data.astype("bool")
        mask_safe = table["mask_safe"].data.astype("bool")
        table.remove_columns(["mask_fit", "mask_safe"])
        return cls(
            models=models,
            name=data["name"],
            data=FluxPoints(table),
            mask_fit=mask_fit,
            mask_safe=mask_safe,
        )
Exemple #4
0
def flux_points_dnde(model):
    e_ref = [np.sqrt(10), np.sqrt(10 * 100)] * u.TeV
    table = Table()
    table.meta["SED_TYPE"] = "dnde"
    table["e_ref"] = e_ref
    table["dnde"] = model(e_ref)
    return FluxPoints(table)
Exemple #5
0
    def flux_points(self):
        """Differential flux points (`~gammapy.estimators.FluxPoints`)."""
        d = self.data
        table = Table()
        table.meta["SED_TYPE"] = "dnde"
        self._add_source_meta(table)

        valid = np.isfinite(d["sed_e_ref"].value)

        if valid.sum() == 0:
            return None

        table["e_ref"] = d["sed_e_ref"]
        table["e_min"] = d["sed_e_min"]
        table["e_max"] = d["sed_e_max"]

        table["dnde"] = d["sed_dnde"]
        table["dnde_err"] = d["sed_dnde_err"]
        table["dnde_errn"] = d["sed_dnde_errn"]
        table["dnde_errp"] = d["sed_dnde_errp"]
        table["dnde_ul"] = d["sed_dnde_ul"]

        # Only keep rows that actually contain information
        table = table[valid]

        # Only keep columns that actually contain information
        def _del_nan_col(table, colname):
            if np.isfinite(table[colname]).sum() == 0:
                del table[colname]

        for colname in table.colnames:
            _del_nan_col(table, colname)

        return FluxPoints(table)
Exemple #6
0
def flux_points_e2dnde(model):
    e_ref = [np.sqrt(10), np.sqrt(10 * 100)] * u.TeV
    table = Table()
    table.meta["SED_TYPE"] = "e2dnde"
    table["e_ref"] = e_ref
    table["e2dnde"] = (model(e_ref) * e_ref**2).to("erg cm-2 s-1")
    return FluxPoints(table)
Exemple #7
0
def test_compute_flux_points_dnde_exp(method):
    """
    Tests against analytical result or result from gammapy.spectrum.powerlaw.
    """
    model = ExpTestModel()

    e_min = [1.0, 10.0] * u.TeV
    e_max = [10.0, 100.0] * u.TeV

    table = Table()
    table.meta["SED_TYPE"] = "flux"
    table["e_min"] = e_min
    table["e_max"] = e_max

    flux = model.integral(e_min, e_max)
    table["flux"] = flux

    if method == "log_center":
        e_ref = np.sqrt(e_min * e_max)
    elif method == "table":
        e_ref = [2.0, 20.0] * u.TeV
        table["e_ref"] = e_ref
    elif method == "lafferty":
        e_ref = FluxPoints._e_ref_lafferty(model, e_min, e_max)

    result = FluxPoints(table).to_sed_type("dnde", model=model, method=method)

    # Test energy
    actual = result.e_ref
    assert_quantity_allclose(actual, e_ref, rtol=1e-8)

    # Test flux
    actual = result.table["dnde"].quantity
    desired = model(e_ref)
    assert_quantity_allclose(actual, desired, rtol=1e-8)
Exemple #8
0
    def flux_points(self):
        """Flux points (`~gammapy.estimators.FluxPoints`)."""
        table = Table()
        table.meta["SED_TYPE"] = "flux"

        table["e_min"] = self._energy_edges[:-1]
        table["e_max"] = self._energy_edges[1:]

        flux = self._get_flux_values("Flux")
        flux_err = self._get_flux_values("Unc_Flux")
        table["flux"] = flux
        table["flux_errn"] = np.abs(flux_err[:, 0])
        table["flux_errp"] = flux_err[:, 1]

        nuFnu = self._get_flux_values("nuFnu", "erg cm-2 s-1")
        table["e2dnde"] = nuFnu
        table["e2dnde_errn"] = np.abs(nuFnu * flux_err[:, 0] / flux)
        table["e2dnde_errp"] = nuFnu * flux_err[:, 1] / flux

        is_ul = np.isnan(table["flux_errn"])
        table["is_ul"] = is_ul

        # handle upper limits
        table["flux_ul"] = np.nan * flux_err.unit
        flux_ul = compute_flux_points_ul(table["flux"], table["flux_errp"])
        table["flux_ul"][is_ul] = flux_ul[is_ul]

        # handle upper limits
        table["e2dnde_ul"] = np.nan * nuFnu.unit
        e2dnde_ul = compute_flux_points_ul(table["e2dnde"], table["e2dnde_errp"])
        table["e2dnde_ul"][is_ul] = e2dnde_ul[is_ul]

        # Square root of test statistic
        table["sqrt_TS"] = [self.data["Sqrt_TS" + _] for _ in self._energy_edges_suffix]
        return FluxPoints(table)
Exemple #9
0
    def get_flux_points(self, position=None):
        """Extract flux point at a given position.

        Parameters
        ---------
        position : `~astropy.coordinates.SkyCoord`
            Position where the flux points are extracted.

        Returns
        -------
        flux_points : `~gammapy.estimators.FluxPoints`
            Flux points object
        """
        from gammapy.estimators import FluxPoints

        if position is None:
            position = self.geom.center_skydir

        data = {}

        for name in self._data:
            m = getattr(self, name)
            data[name] = m.to_region_nd_map(region=position, method="nearest")

        return FluxPoints(data,
                          reference_model=self.reference_model,
                          meta=self.meta.copy(),
                          gti=self.gti)
Exemple #10
0
def flux_points_flux(model):
    e_min = [1, 10] * u.TeV
    e_max = [10, 100] * u.TeV

    table = Table()
    table.meta["SED_TYPE"] = "flux"
    table["e_min"] = e_min
    table["e_max"] = e_max
    table["flux"] = model.integral(e_min, e_max)
    return FluxPoints(table)
Exemple #11
0
    def flux_points(self):
        """Flux points (`~gammapy.spectrum.FluxPoints`)."""
        table = Table()
        table.meta["SED_TYPE"] = "dnde"
        mask = ~np.isnan(self.data["Flux_Points_Energy"])

        table["e_ref"] = self.data["Flux_Points_Energy"][mask]
        table["e_min"] = self.data["Flux_Points_Energy_Min"][mask]
        table["e_max"] = self.data["Flux_Points_Energy_Max"][mask]

        table["dnde"] = self.data["Flux_Points_Flux"][mask]
        table["dnde_errn"] = self.data["Flux_Points_Flux_Err_Lo"][mask]
        table["dnde_errp"] = self.data["Flux_Points_Flux_Err_Hi"][mask]
        table["dnde_ul"] = self.data["Flux_Points_Flux_UL"][mask]
        table["is_ul"] = self.data["Flux_Points_Flux_Is_UL"][mask].astype("bool")

        return FluxPoints(table)
Exemple #12
0
    def flux_points(self):
        """Integral flux points (`~gammapy.spectrum.FluxPoints`)."""
        table = Table()
        table.meta["SED_TYPE"] = "flux"
        table["e_min"] = self._ebounds[:-1]
        table["e_max"] = self._ebounds[1:]
        table["flux"] = self._get_flux_values("Flux")
        flux_err = self._get_flux_values("Unc_Flux")
        table["flux_errn"] = np.abs(flux_err[:, 0])
        table["flux_errp"] = flux_err[:, 1]

        # handle upper limits
        is_ul = np.isnan(table["flux_errn"])
        table["is_ul"] = is_ul
        table["flux_ul"] = np.nan * flux_err.unit
        flux_ul = compute_flux_points_ul(table["flux"], table["flux_errp"])
        table["flux_ul"][is_ul] = flux_ul[is_ul]
        return FluxPoints(table)
Exemple #13
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