예제 #1
0
def plot_background(bg_rate, rad_max, ax=None, label=None):
    # pyirf data
    reco_bins = np.append(bg_rate["ENERG_LO"], bg_rate["ENERG_HI"][-1])

    # first fov bin, [0, 1] deg
    fov_bin = 0
    rate_bin = bg_rate["BKG"].T[:, fov_bin]

    # interpolate theta cut for given e reco bin
    e_center_bg = 0.5 * (bg_rate["ENERG_LO"] + bg_rate["ENERG_HI"])
    e_center_theta = 0.5 * (rad_max["ENERG_LO"] + rad_max["ENERG_HI"])
    theta_cut = np.interp(e_center_bg, e_center_theta, rad_max["RAD_MAX"].T[:,
                                                                            0])

    # undo normalization
    rate_bin *= cone_solid_angle(theta_cut)
    rate_bin *= np.diff(reco_bins)

    ax.errorbar(
        0.5 *
        (bg_rate["ENERG_LO"] + bg_rate["ENERG_HI"]).to_value(u.TeV)[1:-1],
        rate_bin.to_value(1 / u.s)[1:-1],
        xerr=np.diff(reco_bins).to_value(u.TeV)[1:-1] / 2,
        ls="",
        label=label,
    )
    ax.set_xscale("log")
    ax.set_yscale("log")
    ax.set_xlabel("True energy / TeV")
    ax.set_ylabel("Background rate [1/s]")
    return 0
예제 #2
0
def test_background():
    from pyirf.irf import background_2d
    from pyirf.utils import cone_solid_angle

    np.random.seed(0)

    N1 = 1000
    N2 = 100
    N = N1 + N2

    # toy event data set with just two energies
    # and a psf per energy bin, point-like
    events = QTable(
        {
            "reco_energy": np.append(np.full(N1, 1), np.full(N2, 2)) * u.TeV,
            "source_fov_offset": np.zeros(N) * u.deg,
            "weight": np.ones(N),
        }
    )

    energy_bins = [0, 1.5, 3] * u.TeV
    fov_bins = [0, 1] * u.deg

    # We return a table with one row as needed for gadf
    bg = background_2d(events, energy_bins, fov_bins, t_obs=1 * u.s)

    # 2 energy bins, 1 fov bin, 200 source distance bins
    assert bg.shape == (2, 1)
    assert bg.unit == u.Unit("TeV-1 s-1 sr-1")

    # check that psf is normalized
    bin_solid_angle = np.diff(cone_solid_angle(fov_bins))
    e_width = np.diff(energy_bins)
    assert np.allclose(np.sum((bg.T * e_width).T * bin_solid_angle, axis=1), [1000, 100] / u.s)
예제 #3
0
def test_psf():
    from pyirf.irf import psf_table
    from pyirf.utils import cone_solid_angle

    np.random.seed(0)

    N = 1000

    TRUE_SIGMA_1 = 0.2
    TRUE_SIGMA_2 = 0.1
    TRUE_SIGMA = np.append(np.full(N, TRUE_SIGMA_1), np.full(N, TRUE_SIGMA_2))

    # toy event data set with just two energies
    # and a psf per energy bin, point-like
    events = QTable({
        "true_energy":
        np.append(np.full(N, 1), np.full(N, 2)) * u.TeV,
        "source_fov_offset":
        np.zeros(2 * N) * u.deg,
        "theta":
        np.random.normal(0, TRUE_SIGMA) * u.deg,
    })

    energy_bins = [0, 1.5, 3] * u.TeV
    fov_bins = [0, 1] * u.deg
    source_bins = np.linspace(0, 1, 201) * u.deg

    # We return a table with one row as needed for gadf
    psf = psf_table(events, energy_bins, source_bins, fov_bins)

    # 2 energy bins, 1 fov bin, 200 source distance bins
    assert psf.shape == (2, 1, 200)
    assert psf.unit == u.Unit("sr-1")

    # check that psf is normalized
    bin_solid_angle = np.diff(cone_solid_angle(source_bins))
    assert np.allclose(np.sum(psf * bin_solid_angle, axis=2), 1.0)

    cumulated = np.cumsum(psf * bin_solid_angle, axis=2)

    # first energy and only fov bin
    bin_centers = 0.5 * (source_bins[1:] + source_bins[:-1])
    assert u.isclose(
        bin_centers[np.where(cumulated[0, 0, :] >= 0.68)[0][0]],
        TRUE_SIGMA_1 * u.deg,
        rtol=0.1,
    )

    # second energy and only fov bin
    assert u.isclose(
        bin_centers[np.where(cumulated[1, 0, :] >= 0.68)[0][0]],
        TRUE_SIGMA_2 * u.deg,
        rtol=0.1,
    )
예제 #4
0
def psf_hdu():
    from pyirf.io import create_psf_table_hdu
    from pyirf.utils import cone_solid_angle

    psf = np.zeros((len(e_bins) - 1, len(source_bins) - 1, len(fov_bins) - 1))
    psf[:, 0, :] = 1
    psf = psf / cone_solid_angle(source_bins[1])

    hdu = create_psf_table_hdu(psf,
                               e_bins,
                               source_bins,
                               fov_bins,
                               point_like=False)
    return psf, hdu
예제 #5
0
def plot_background_rate_from_file(filename, ax=None, **kwargs):

    ax = plt.gca() if ax is None else ax

    rad_max = QTable.read(filename, hdu="RAD_MAX")[0]
    bg_rate = QTable.read(filename, hdu="BACKGROUND")[0]

    reco_bins = np.append(bg_rate["ENERG_LO"], bg_rate["ENERG_HI"][-1])

    # first fov bin, [0, 1] deg
    fov_bin = 0
    rate_bin = bg_rate["BKG"].T[:, fov_bin]

    # interpolate theta cut for given e reco bin
    e_center_bg = 0.5 * (bg_rate["ENERG_LO"] + bg_rate["ENERG_HI"])
    e_center_theta = 0.5 * (rad_max["ENERG_LO"] + rad_max["ENERG_HI"])
    theta_cut = np.interp(e_center_bg, e_center_theta, rad_max["RAD_MAX"].T[:, 0])

    # undo normalization
    rate_bin *= cone_solid_angle(theta_cut)
    rate_bin *= np.diff(reco_bins)

    if "ls" not in kwargs and "linestyle" not in kwargs:
        kwargs["ls"] = ""

    ax.errorbar(
        e_center_bg.to_value(u.TeV)[1:-1],
        rate_bin.to_value(1 / u.s)[1:-1],
        xerr=np.diff(reco_bins).to_value(u.TeV)[1:-1] / 2,
        **kwargs,
    )

    # Style settings
    ax.set_xscale("log")
    ax.set_xlabel(r"$E_\mathrm{Reco} [\mathrm{TeV}]$")
    ax.set_ylabel("Background rate [Hz]")
    ax.grid(True, which="both")
    ax.legend()
    ax.set_yscale("log")

    return ax