Beispiel #1
0
def make_srcmap_old(psf,
                    spatial_model,
                    sigma,
                    npix=500,
                    xpix=0.0,
                    ypix=0.0,
                    cdelt=0.01,
                    rebin=1,
                    psf_scale_fn=None):
    """Compute the source map for a given spatial model.

    Parameters
    ----------
    psf : `~fermipy.irfs.PSFModel`
    spatial_model : str
        Spatial model.
    sigma : float
        Spatial size parameter for extended models.
    xpix : float
        Source position in pixel coordinates in X dimension.
    ypix : float
        Source position in pixel coordinates in Y dimension.
    rebin : int    
        Factor by which the original map will be oversampled in the
        spatial dimension when computing the model.
    psf_scale_fn : callable        
        Function that evaluates the PSF scaling function.
        Argument is energy in MeV.
    """
    if rebin > 1:
        npix = npix * rebin
        xpix = xpix * rebin + (rebin - 1.0) / 2.
        ypix = ypix * rebin + (rebin - 1.0) / 2.
        cdelt = cdelt / rebin

    if spatial_model == 'RadialGaussian':
        k = utils.make_cgauss_kernel(psf, sigma, npix, cdelt, xpix, ypix,
                                     psf_scale_fn)
    elif spatial_model == 'RadialDisk':
        k = utils.make_cdisk_kernel(psf, sigma, npix, cdelt, xpix, ypix,
                                    psf_scale_fn)
    elif spatial_model == 'PointSource':
        k = utils.make_psf_kernel(psf, npix, cdelt, xpix, ypix, psf_scale_fn)
    else:
        raise Exception('Unsupported spatial model: %s', spatial_model)

    if rebin > 1:
        k = utils.sum_bins(k, 1, rebin)
        k = utils.sum_bins(k, 2, rebin)

    k *= psf.exp[:, np.newaxis, np.newaxis] * np.radians(cdelt)**2
    return k
Beispiel #2
0
def calc_counts(skydir, ltc, event_class, event_types,
                egy_bins, cth_bins, fn, npts=1):
    """Calculate the expected counts vs. true energy and incidence angle
    for a source with spectral parameterization ``fn``.

    Parameters
    ----------
    skydir : `~astropy.coordinate.SkyCoord`

    ltc : `~fermipy.irfs.LTCube`

    egy_bins : `~numpy.ndarray`
        Bin edges in observed energy in MeV.

    cth_bins : `~numpy.ndarray`
        Bin edges in cosine of the true incidence angle.

    npts : int
        Number of points by which to oversample each energy bin.
    """
    #npts = int(np.ceil(32. / bins_per_dec(egy_bins)))
    egy_bins = np.exp(utils.split_bin_edges(np.log(egy_bins), npts))
    exp = calc_exp(skydir, ltc, event_class, event_types,
                   egy_bins, cth_bins)
    dnde = fn.dnde(egy_bins)
    cnts = loglog_quad(egy_bins, exp * dnde[:, None], 0)
    cnts = sum_bins(cnts, 0, npts)
    return cnts
Beispiel #3
0
    def shift_to_coords(self, pix, fill_value=np.nan):
        """Create a new map that is shifted to the pixel coordinates
        ``pix``."""

        pix_offset = self.get_offsets(pix)
        dpix = np.zeros(len(self.shape) - 1)
        for i in range(len(self.shape) - 1):
            x = self.rebin * (pix[i] - pix_offset[i + 1]) + (self.rebin -
                                                             1.0) / 2.
            dpix[i] = x - self._pix_ref[i]

        pos = [
            pix_offset[i] + self.shape[i] // 2 for i in range(self.data.ndim)
        ]
        s0, s1 = utils.overlap_slices(self.shape_out, self.shape, pos)

        k = np.zeros(self.data.shape)
        for i in range(k.shape[0]):
            k[i] = shift(self._data_spline[i],
                         dpix,
                         cval=np.nan,
                         order=2,
                         prefilter=False)

        for i in range(1, len(self.shape)):
            k = utils.sum_bins(k, i, self.rebin)

        k0 = np.ones(self.shape_out) * fill_value

        if k[s1].size == 0 or k0[s0].size == 0:
            return k0
        k0[s0] = k[s1]
        return k0
Beispiel #4
0
def calc_counts(skydir,
                ltc,
                event_class,
                event_types,
                egy_bins,
                cth_bins,
                fn,
                npts=1):
    """Calculate the expected counts vs. true energy and incidence angle
    for a source with spectral parameterization ``fn``.

    Parameters
    ----------
    skydir : `~astropy.coordinate.SkyCoord`

    ltc : `~fermipy.irfs.LTCube`

    egy_bins : `~numpy.ndarray`
        Bin edges in observed energy in MeV.

    cth_bins : `~numpy.ndarray`
        Bin edges in cosine of the true incidence angle.

    npts : int
        Number of points by which to oversample each energy bin.
    """
    #npts = int(np.ceil(32. / bins_per_dec(egy_bins)))
    egy_bins = np.exp(utils.split_bin_edges(np.log(egy_bins), npts))
    exp = calc_exp(skydir, ltc, event_class, event_types, egy_bins, cth_bins)
    dnde = fn.dnde(egy_bins)
    cnts = loglog_quad(egy_bins, exp * dnde[:, None], 0)
    cnts = sum_bins(cnts, 0, npts)
    return cnts
Beispiel #5
0
    def shift_to_coords(self, pix, fill_value=np.nan):
        """Create a new map that is shifted to the pixel coordinates
        ``pix``."""

        pix_offset = self.get_offsets(pix)
        dpix = np.zeros(len(self.shape) - 1)
        for i in range(len(self.shape) - 1):
            x = self.rebin * (pix[i] - pix_offset[i + 1]
                              ) + (self.rebin - 1.0) / 2.
            dpix[i] = x - self._pix_ref[i]

        pos = [pix_offset[i] + self.shape[i] // 2
               for i in range(self.data.ndim)]
        s0, s1 = utils.overlap_slices(self.shape_out, self.shape, pos)

        k = np.zeros(self.data.shape)
        for i in range(k.shape[0]):
            k[i] = shift(self._data_spline[i], dpix, cval=np.nan,
                         order=2, prefilter=False)

        for i in range(1, len(self.shape)):
            k = utils.sum_bins(k, i, self.rebin)

        k0 = np.ones(self.shape_out) * fill_value

        if k[s1].size == 0 or k0[s0].size == 0:
            return k0
        k0[s0] = k[s1]
        return k0
Beispiel #6
0
def calc_counts_edisp(skydir, ltc, event_class, event_types,
                      egy_bins, cth_bins, fn, nbin=64, npts=1):
    """Calculate the expected counts vs. observed energy and true
    incidence angle for a source with spectral parameterization ``fn``.

    Parameters
    ----------
    skydir : `~astropy.coordinate.SkyCoord`

    ltc : `~fermipy.irfs.LTCube`

    egy_bins : `~numpy.ndarray`
        Bin edges in observed energy in MeV.

    cth_bins : `~numpy.ndarray`
        Bin edges in cosine of the true incidence angle.

    npts : int
        Number of points by which to oversample each energy bin.

    """
    #npts = int(np.ceil(32. / bins_per_dec(egy_bins)))

    # Split energy bins
    egy_bins = np.exp(utils.split_bin_edges(np.log(egy_bins), npts))
    etrue_bins = 10**np.linspace(1.0, 6.5, nbin * 5.5 + 1)
    drm = calc_drm(skydir, ltc, event_class, event_types,
                   egy_bins, cth_bins, nbin=nbin)
    cnts_etrue = calc_counts(skydir, ltc, event_class, event_types,
                             etrue_bins, cth_bins, fn)

    cnts = np.sum(cnts_etrue[None, :, :] * drm[:, :, :], axis=1)
    cnts = sum_bins(cnts, 0, npts)
    return cnts
Beispiel #7
0
def make_srcmap_old(psf, spatial_model, sigma, npix=500, xpix=0.0, ypix=0.0,
                    cdelt=0.01, rebin=1, psf_scale_fn=None):
    """Compute the source map for a given spatial model.

    Parameters
    ----------
    psf : `~fermipy.irfs.PSFModel`
    spatial_model : str
        Spatial model.
    sigma : float
        Spatial size parameter for extended models.
    xpix : float
        Source position in pixel coordinates in X dimension.
    ypix : float
        Source position in pixel coordinates in Y dimension.
    rebin : int    
        Factor by which the original map will be oversampled in the
        spatial dimension when computing the model.
    psf_scale_fn : callable        
        Function that evaluates the PSF scaling function.
        Argument is energy in MeV.
    """
    if rebin > 1:
        npix = npix * rebin
        xpix = xpix * rebin + (rebin - 1.0) / 2.
        ypix = ypix * rebin + (rebin - 1.0) / 2.
        cdelt = cdelt / rebin

    if spatial_model == 'RadialGaussian':
        k = utils.make_cgauss_kernel(psf, sigma, npix, cdelt,
                                     xpix, ypix, psf_scale_fn)
    elif spatial_model == 'RadialDisk':
        k = utils.make_cdisk_kernel(psf, sigma, npix, cdelt,
                                    xpix, ypix, psf_scale_fn)
    elif spatial_model == 'PointSource':
        k = utils.make_psf_kernel(psf, npix, cdelt,
                                  xpix, ypix, psf_scale_fn)
    else:
        raise Exception('Unsupported spatial model: %s', spatial_model)

    if rebin > 1:
        k = utils.sum_bins(k, 1, rebin)
        k = utils.sum_bins(k, 2, rebin)

    k *= psf.exp[:, np.newaxis, np.newaxis] * np.radians(cdelt) ** 2
    return k
Beispiel #8
0
def calc_counts_edisp(skydir,
                      ltc,
                      event_class,
                      event_types,
                      egy_bins,
                      cth_bins,
                      fn,
                      nbin=16,
                      npts=1):
    """Calculate the expected counts vs. observed energy and true
    incidence angle for a source with spectral parameterization ``fn``.

    Parameters
    ----------
    skydir : `~astropy.coordinate.SkyCoord`

    ltc : `~fermipy.irfs.LTCube`

    egy_bins : `~numpy.ndarray`
        Bin edges in observed energy in MeV.

    cth_bins : `~numpy.ndarray`
        Bin edges in cosine of the true incidence angle.

    nbin : int    
        Number of points per decade with which to sample true energy.
        
    npts : int
        Number of points by which to oversample each reconstructed energy bin.

    """
    #npts = int(np.ceil(32. / bins_per_dec(egy_bins)))

    # Split energy bins
    egy_bins = np.exp(utils.split_bin_edges(np.log(egy_bins), npts))
    etrue_bins = 10**np.linspace(1.0, 6.5, np.int(np.ceil(nbin * 5.5 + 1)))
    drm = calc_drm(skydir,
                   ltc,
                   event_class,
                   event_types,
                   egy_bins,
                   cth_bins,
                   nbin=nbin)
    cnts_etrue = calc_counts(skydir, ltc, event_class, event_types, etrue_bins,
                             cth_bins, fn)

    cnts = np.sum(cnts_etrue[None, :, :] * drm[:, :, :], axis=1)
    cnts = sum_bins(cnts, 0, npts)
    return cnts
Beispiel #9
0
def calc_drm(skydir, ltc, event_class, event_types,
             egy_bins, cth_bins, nbin=64):
    """Calculate the detector response matrix."""
    npts = int(np.ceil(128. / bins_per_dec(egy_bins)))
    egy_bins = np.exp(utils.split_bin_edges(np.log(egy_bins), npts))

    etrue_bins = 10**np.linspace(1.0, 6.5, nbin * 5.5 + 1)
    egy = 10**utils.edge_to_center(np.log10(egy_bins))
    egy_width = utils.edge_to_width(egy_bins)
    etrue = 10**utils.edge_to_center(np.log10(etrue_bins))
    edisp = create_avg_edisp(skydir, ltc, event_class, event_types,
                             egy, etrue, cth_bins)
    edisp = edisp * egy_width[:, None, None]
    edisp = sum_bins(edisp, 0, npts)
    return edisp
Beispiel #10
0
def calc_drm(skydir,
             ltc,
             event_class,
             event_types,
             egy_bins,
             cth_bins,
             nbin=64):
    """Calculate the detector response matrix."""
    npts = int(np.ceil(128. / bins_per_dec(egy_bins)))
    egy_bins = np.exp(utils.split_bin_edges(np.log(egy_bins), npts))

    etrue_bins = 10**np.linspace(1.0, 6.5, np.int(np.ceil(nbin * 5.5 + 1)))
    egy = 10**utils.edge_to_center(np.log10(egy_bins))
    egy_width = utils.edge_to_width(egy_bins)
    etrue = 10**utils.edge_to_center(np.log10(etrue_bins))
    edisp = create_avg_edisp(skydir, ltc, event_class, event_types, egy, etrue,
                             cth_bins)
    edisp = edisp * egy_width[:, None, None]
    edisp = sum_bins(edisp, 0, npts)
    return edisp
Beispiel #11
0
def compute_norm(sig, bkg, ts_thresh, min_counts, sum_axes=None, bkg_fit=None,
                 rebin_axes=None):
    """Solve for the normalization of the signal distribution at which the
    detection test statistic (twice delta-loglikelihood ratio) is >=
    ``ts_thresh`` AND the number of signal counts >= ``min_counts``.
    This function uses the Asimov method to calculate the median
    expected TS when the model for the background is fixed (no
    uncertainty on the background amplitude).

    Parameters
    ----------
    sig : `~numpy.ndarray`
        Array of signal amplitudes in counts.

    bkg : `~numpy.ndarray`
        Array of background amplitudes in counts.

    ts_thresh : float
        Test statistic threshold.

    min_counts : float
        Counts threshold.

    sum_axes : list
        Axes over which the source test statistic should be summed.
        By default the summation will be performed over all
        dimensions.

    bkg_fit : `~numpy.ndarray`
        Array of background amplitudes in counts for the fitting
        model.  If None then the fit model will be equal to the data
        model.

    """

    if sum_axes is None:
        sum_axes = np.arange(sig.ndim)

    sig = np.expand_dims(sig, -1)
    bkg = np.expand_dims(bkg, -1)
    sig_sum = np.apply_over_axes(np.sum, sig, sum_axes)
    bkg_sum = np.apply_over_axes(np.sum, bkg, sum_axes)
    bkg_fit_sum = None

    if bkg_fit is not None:
        bkg_fit = np.expand_dims(bkg_fit, -1)
        bkg_fit_sum = np.apply_over_axes(np.sum, bkg_fit, sum_axes)

    sig_rebin = sig
    bkg_rebin = bkg
    bkg_fit_rebin = bkg_fit

    if rebin_axes:
        sig_rebin = sig.copy()
        bkg_rebin = bkg.copy()
        if bkg_fit is not None:
            bkg_fit_rebin = bkg_fit.copy()

        for dim, rebin in zip(sum_axes, rebin_axes):
            sig_rebin = sum_bins(sig_rebin, dim, rebin)
            bkg_rebin = sum_bins(bkg_rebin, dim, rebin)
            if bkg_fit is not None:
                bkg_fit_rebin = sum_bins(bkg_fit_rebin, dim, rebin)

    # Find approx solution using coarse binning and summed arrays
    sig_scale = 10**np.linspace(0.0, 10.0, 51) * (min_counts / sig_sum)
    vals_approx = _solve_norm(sig_rebin, bkg_rebin, ts_thresh, min_counts,
                              sig_scale, sum_axes, bkg_fit_rebin)

    # Refine solution using an interval (0.1,10) around approx
    # solution
    sig_scale = (10**np.linspace(0.0, 1.0, 21) *
                 np.fmax(0.333 * vals_approx[..., None],
                         min_counts / sig_sum))

    vals = _solve_norm(sig, bkg, ts_thresh, min_counts, sig_scale,
                       sum_axes, bkg_fit)

    #sig_scale = 10**np.linspace(0.0, 10.0, 101)*(min_counts / sig_sum)
    # vals = _solve_norm(sig, bkg, ts_thresh, min_counts, sig_scale2,
    #                   sum_axes, bkg_fit)

    return vals
Beispiel #12
0
def compute_norm(sig,
                 bkg,
                 ts_thresh,
                 min_counts,
                 sum_axes=None,
                 bkg_fit=None,
                 rebin_axes=None):
    """Solve for the normalization of the signal distribution at which the
    detection test statistic (twice delta-loglikelihood ratio) is >=
    ``ts_thresh`` AND the number of signal counts >= ``min_counts``.
    This function uses the Asimov method to calculate the median
    expected TS when the model for the background is fixed (no
    uncertainty on the background amplitude).

    Parameters
    ----------
    sig : `~numpy.ndarray`
        Array of signal amplitudes in counts.

    bkg : `~numpy.ndarray`
        Array of background amplitudes in counts.

    ts_thresh : float
        Test statistic threshold.

    min_counts : float
        Counts threshold.

    sum_axes : list
        Axes over which the source test statistic should be summed.
        By default the summation will be performed over all
        dimensions.

    bkg_fit : `~numpy.ndarray`
        Array of background amplitudes in counts for the fitting
        model.  If None then the fit model will be equal to the data
        model.

    """

    if sum_axes is None:
        sum_axes = np.arange(sig.ndim)

    sig = np.expand_dims(sig, -1)
    bkg = np.expand_dims(bkg, -1)
    sig_sum = np.apply_over_axes(np.sum, sig, sum_axes)
    bkg_sum = np.apply_over_axes(np.sum, bkg, sum_axes)
    bkg_fit_sum = None

    if bkg_fit is not None:
        bkg_fit = np.expand_dims(bkg_fit, -1)
        bkg_fit_sum = np.apply_over_axes(np.sum, bkg_fit, sum_axes)

    sig_rebin = sig
    bkg_rebin = bkg
    bkg_fit_rebin = bkg_fit

    if rebin_axes:
        sig_rebin = sig.copy()
        bkg_rebin = bkg.copy()
        if bkg_fit is not None:
            bkg_fit_rebin = bkg_fit.copy()

        for dim, rebin in zip(sum_axes, rebin_axes):
            sig_rebin = sum_bins(sig_rebin, dim, rebin)
            bkg_rebin = sum_bins(bkg_rebin, dim, rebin)
            if bkg_fit is not None:
                bkg_fit_rebin = sum_bins(bkg_fit_rebin, dim, rebin)

    # Find approx solution using coarse binning and summed arrays
    sig_scale = 10**np.linspace(0.0, 10.0, 51) * (min_counts / sig_sum)
    vals_approx = _solve_norm(sig_rebin, bkg_rebin, ts_thresh, min_counts,
                              sig_scale, sum_axes, bkg_fit_rebin)

    # Refine solution using an interval (0.1,10) around approx
    # solution
    sig_scale = (10**np.linspace(0.0, 1.0, 21) *
                 np.fmax(0.333 * vals_approx[..., None], min_counts / sig_sum))

    vals = _solve_norm(sig, bkg, ts_thresh, min_counts, sig_scale, sum_axes,
                       bkg_fit)

    #sig_scale = 10**np.linspace(0.0, 10.0, 101)*(min_counts / sig_sum)
    # vals = _solve_norm(sig, bkg, ts_thresh, min_counts, sig_scale2,
    #                   sum_axes, bkg_fit)

    return vals