Example #1
0
def test_response_set_weighting_with_reference_time():

    # Now repeat the same tests but using a reference time
    ref_time = 123.456

    (
        [rsp_a, rsp_b],
        exposure_getter,
        counts_getter,
    ) = get_matrix_set_elements_with_coverage(reference_time=ref_time)

    rsp_set = InstrumentResponseSet([rsp_a, rsp_b],
                                    exposure_getter,
                                    counts_getter,
                                    reference_time=ref_time)

    assert rsp_set.reference_time == ref_time

    weighted_matrix = rsp_set.weight_by_exposure("5.0 - 25.0")

    assert np.allclose(weighted_matrix.matrix, 0.625 * rsp_a.matrix)

    weighted_matrix = rsp_set.weight_by_counts("0.0 - 30.0")

    assert np.allclose(weighted_matrix.matrix,
                       0.5555555555555555 * rsp_a.matrix)

    weighted_matrix = rsp_set.weight_by_counts("5.0 - 25.0")

    assert np.allclose(weighted_matrix.matrix,
                       0.5625000000000001 * rsp_a.matrix)
Example #2
0
def test_response_set_constructor():

    [rsp_aw,
     rsp_bw], exposure_getter, counts_getter = get_matrix_set_elements()

    with pytest.raises(RuntimeError):

        # This should raise because there is no time information for the matrices

        _ = InstrumentResponseSet([rsp_aw, rsp_bw], exposure_getter,
                                  counts_getter)

    # Add the time information

    (
        [rsp_a, rsp_b],
        exposure_getter,
        counts_getter,
    ) = get_matrix_set_elements_with_coverage()

    # This should work now
    rsp_set = InstrumentResponseSet([rsp_a, rsp_b], exposure_getter,
                                    counts_getter)

    assert rsp_set[0] == rsp_a
    assert rsp_set[1] == rsp_b

    # Check that the constructor order the matrices by time when needed
    # This should work now
    rsp_set = InstrumentResponseSet([rsp_b, rsp_a], exposure_getter,
                                    counts_getter)

    assert rsp_set[0] == rsp_a
    assert rsp_set[1] == rsp_b

    # Now test construction from the .from_rsp2 method
    rsp2_file = get_path_of_data_file("ogip_test_gbm_b0.rsp2")

    with warnings.catch_warnings():

        warnings.simplefilter("error", np.VisibleDeprecationWarning)

        rsp_set = InstrumentResponseSet.from_rsp2_file(rsp2_file,
                                                       exposure_getter,
                                                       counts_getter)

    assert len(rsp_set) == 3

    # Now test that we cannot initialize a response set with matrices which have non-contiguous coverage intervals
    matrix, mc_energies, ebounds = get_matrix_elements()

    rsp_c = InstrumentResponse(matrix, ebounds, mc_energies,
                               TimeInterval(0.0, 10.0))
    rsp_d = InstrumentResponse(matrix, ebounds, mc_energies,
                               TimeInterval(20.0, 30.0))

    with pytest.raises(RuntimeError):

        _ = InstrumentResponseSet([rsp_c, rsp_d], exposure_getter,
                                  counts_getter)
Example #3
0
def test_response_set_weighting():

    (
        [rsp_a, rsp_b],
        exposure_getter,
        counts_getter,
    ) = get_matrix_set_elements_with_coverage()

    rsp_set = InstrumentResponseSet([rsp_a, rsp_b], exposure_getter,
                                    counts_getter)

    # here we are waiting by exposure. We have:

    # weight1 = (0.9 * 5.0) = 4.5
    # weight2 = (0.9 * 15.0) = 13.5
    # sum = weight1 + weight2 = 18.0
    # new_matrix = rsp_a * weight1/sum + rsp_b * weight2 / sum

    # but rsp_b = rsp_a / 2.0, so:

    # new_matrix = rsp_a * weight1 / sum + rsp_a / 2.0 * weight2 / sum = 1 / sum * rsp_a * (weight1 + weight2 / 2.0)

    # so in the end:

    # new_matrix = 0.625 * rsp_a

    weighted_matrix = rsp_set.weight_by_exposure("5.0 - 25.0")

    assert np.allclose(weighted_matrix.matrix, 0.625 * rsp_a.matrix)

    # here we are waiting by exposure. We have:

    # weight1 = 55.35
    # weight2 = 442.8

    # so:

    # new_matrix = 1 / sum * rsp_a * (weight1 + weight2 / 2.0) = 0.5555555555555555 * rsp_a

    weighted_matrix = rsp_set.weight_by_counts("0.0 - 30.0")

    assert np.allclose(weighted_matrix.matrix,
                       0.5555555555555555 * rsp_a.matrix)

    # Here we weight by counts in the interval 5.0 - 25.0
    # With the same math as before:

    weighted_matrix = rsp_set.weight_by_counts("5.0 - 25.0")

    assert np.allclose(weighted_matrix.matrix,
                       0.5625000000000001 * rsp_a.matrix)
Example #4
0
def test_response_set_weighting_with_disjoint_intervals():

    ref_time = 123.456

    (
        [rsp_a, rsp_b],
        exposure_getter,
        counts_getter,
    ) = get_matrix_set_elements_with_coverage(reference_time=ref_time)

    rsp_set = InstrumentResponseSet([rsp_a, rsp_b],
                                    exposure_getter,
                                    counts_getter,
                                    reference_time=ref_time)

    assert rsp_set.reference_time == ref_time

    weighted_matrix = rsp_set.weight_by_exposure("5.0 - 12.0", "25.0-28.0")

    # weight1 = (0.9 * 5.0) = 4.5
    # weight2 = (0.9 * 2.0) = 1.8
    # weight3 = (0.9 * 3.0) = 2.7
    # sum = weight1 + weight2 + weight3 = 8.2
    # new_matrix = rsp_a * weight1/sum + rsp_b * weight2 / sum + rsp_b * weight3 / sum

    # but rsp_b = rsp_a / 2.0, so:

    # new_matrix = rsp_a * weight1 / sum + rsp_a / 2.0 * weight2 / sum + rsp_a / 2.0 * weight3 / sum

    # so in the end:

    # new_matrix = 1.0 / (w1 + w2 + w3) * (w1 + w2 / 2.0 + w3 / 2.0) * rsp_a = 0.75 * rsp_a

    assert np.allclose(weighted_matrix.matrix, 0.75 * rsp_a.matrix)

    # Now the same with counts

    weighted_matrix = rsp_set.weight_by_counts("5.0 - 12.0", "25.0-28.0")

    w1 = counts_getter(5.0, 10.0)
    w2 = counts_getter(10.0, 12.0)
    w3 = counts_getter(25.0, 28.0)

    factor = 1.0 / (w1 + w2 + w3) * (w1 + w2 / 2.0 + w3 / 2.0)

    assert np.allclose(weighted_matrix.matrix, factor * rsp_a.matrix)
Example #5
0
    def from_gbm_cspec_or_ctime(cls, name, cspec_or_ctime_file, rsp_file, restore_background=None,
                                trigger_time=None,
                                poly_order=-1, verbose=True):
        """
               A plugin to natively bin, view, and handle Fermi GBM TTE data.
               A TTE event file are required as well as the associated response



               Background selections are specified as
               a comma separated string e.g. "-10-0,10-20"

               Initial source selection is input as a string e.g. "0-5"

               One can choose a background polynomial order by hand (up to 4th order)
               or leave it as the default polyorder=-1 to decide by LRT test

               :param name: name for your choosing
               :param tte_file: GBM tte event file
               :param rsp_file: Associated TTE CSPEC response file
               :param trigger_time: trigger time if needed
               :param poly_order: 0-4 or -1 for auto
               :param unbinned: unbinned likelihood fit (bool)
               :param verbose: verbose (bool)



               """

        # self._default_unbinned = unbinned

        # Load the relevant information from the TTE file

        cdata = GBMCdata(cspec_or_ctime_file, rsp_file)

        # Set a trigger time if one has not been set

        if trigger_time is not None:
            cdata.trigger_time = trigger_time

        # Create the the event list

        event_list = BinnedSpectrumSeries(cdata.spectrum_set,
                                          first_channel=0,
                                          mission='Fermi',
                                          instrument=cdata.det_name,
                                          verbose=verbose)

        # we need to see if this is an RSP2


        if isinstance(rsp_file,str) or isinstance(rsp_file,unicode):


            test = re.match('^.*\.rsp2$', rsp_file)

            # some GBM RSPs that are not marked RSP2 are in fact RSP2s
            # we need to check

            if test is None:

                with fits.open(rsp_file) as f:

                    # there should only be a header, ebounds and one spec rsp extension

                    if len(f) > 3:
                        # make test a dummy value to trigger the nest loop

                        test = -1

                        custom_warnings.warn(
                            'The RSP file is marked as a single response but in fact has multiple matrices. We will treat it as an RSP2')

            if test is not None:

                rsp = InstrumentResponseSet.from_rsp2_file(rsp2_file=rsp_file,
                                                           counts_getter=event_list.counts_over_interval,
                                                           exposure_getter=event_list.exposure_over_interval,
                                                           reference_time=cdata.trigger_time)





            else:

                rsp = OGIPResponse(rsp_file)

        else:

            assert isinstance(rsp_file, InstrumentResponse), 'The provided response is not a 3ML InstrumentResponse'
            rsp = rsp_file

        # pass to the super class

        return cls(name,
                   event_list,
                   response=rsp,
                   poly_order=poly_order,
                   unbinned=False,
                   verbose=verbose,
                   restore_poly_fit=restore_background,
                   container_type=BinnedSpectrumWithDispersion
                   )
    def from_gbm_cspec_or_ctime(cls,
                                name,
                                cspec_or_ctime_file,
                                rsp_file,
                                restore_background=None,
                                trigger_time=None,
                                poly_order=-1,
                                verbose=True):
        """
               A plugin to natively bin, view, and handle Fermi GBM TTE data.
               A TTE event file are required as well as the associated response



               Background selections are specified as
               a comma separated string e.g. "-10-0,10-20"

               Initial source selection is input as a string e.g. "0-5"

               One can choose a background polynomial order by hand (up to 4th order)
               or leave it as the default polyorder=-1 to decide by LRT test

               :param name: name for your choosing
               :param tte_file: GBM tte event file
               :param rsp_file: Associated TTE CSPEC response file
               :param trigger_time: trigger time if needed
               :param poly_order: 0-4 or -1 for auto
               :param unbinned: unbinned likelihood fit (bool)
               :param verbose: verbose (bool)



               """

        # self._default_unbinned = unbinned

        # Load the relevant information from the TTE file

        cdata = GBMCdata(cspec_or_ctime_file, rsp_file)

        # Set a trigger time if one has not been set

        if trigger_time is not None:
            cdata.trigger_time = trigger_time

        # Create the the event list

        event_list = BinnedSpectrumSeries(cdata.spectrum_set,
                                          first_channel=0,
                                          mission='Fermi',
                                          instrument=cdata.det_name,
                                          verbose=verbose)

        # we need to see if this is an RSP2

        if isinstance(rsp_file, str) or isinstance(rsp_file, unicode):

            test = re.match('^.*\.rsp2$', rsp_file)

            # some GBM RSPs that are not marked RSP2 are in fact RSP2s
            # we need to check

            if test is None:

                with fits.open(rsp_file) as f:

                    # there should only be a header, ebounds and one spec rsp extension

                    if len(f) > 3:
                        # make test a dummy value to trigger the nest loop

                        test = -1

                        custom_warnings.warn(
                            'The RSP file is marked as a single response but in fact has multiple matrices. We will treat it as an RSP2'
                        )

            if test is not None:

                rsp = InstrumentResponseSet.from_rsp2_file(
                    rsp2_file=rsp_file,
                    counts_getter=event_list.counts_over_interval,
                    exposure_getter=event_list.exposure_over_interval,
                    reference_time=cdata.trigger_time)

            else:

                rsp = OGIPResponse(rsp_file)

        else:

            assert isinstance(
                rsp_file, InstrumentResponse
            ), 'The provided response is not a 3ML InstrumentResponse'
            rsp = rsp_file

        # pass to the super class

        return cls(name,
                   event_list,
                   response=rsp,
                   poly_order=poly_order,
                   unbinned=False,
                   verbose=verbose,
                   restore_poly_fit=restore_background,
                   container_type=BinnedSpectrumWithDispersion)
    def from_gbm_tte(
        cls,
        name,
        tte_file,
        rsp_file=None,
        restore_background=None,
        trigger_time=None,
        poly_order=-1,
        unbinned=True,
        verbose=True,
        use_balrog=False,
        trigdat_file=None,
        poshist_file=None,
        cspec_file=None,
    ):
        """
        A plugin to natively bin, view, and handle Fermi GBM TTE data.
        A TTE event file are required as well as the associated response

        Background selections are specified as
        a comma separated string e.g. "-10-0,10-20"

        Initial source selection is input as a string e.g. "0-5"

        One can choose a background polynomial order by hand (up to 4th order)
        or leave it as the default polyorder=-1 to decide by LRT test

        :param name: name for your choosing
        :param tte_file: GBM tte event file
        :param rsp_file: Associated TTE CSPEC response file
        :param trigger_time: trigger time if needed
        :param poly_order: 0-4 or -1 for auto
        :param unbinned: unbinned likelihood fit (bool)
        :param verbose: verbose (bool)
        :param use_balrog:  (bool) if you have gbm_drm_gen installed, will build BALROGlike 
        :param trigdat_file: the trigdat file to use for location 
        :param poshist_file: the poshist file to use for location 
        :param cspec_file: the cspec file to use for location 


               """

        # self._default_unbinned = unbinned

        # Load the relevant information from the TTE file

        gbm_tte_file = GBMTTEFile(tte_file)

        # Set a trigger time if one has not been set

        if trigger_time is not None:
            gbm_tte_file.trigger_time = trigger_time

        # Create the the event list

        event_list = EventListWithDeadTime(
            arrival_times=gbm_tte_file.arrival_times -
            gbm_tte_file.trigger_time,
            measurement=gbm_tte_file.energies,
            n_channels=gbm_tte_file.n_channels,
            start_time=gbm_tte_file.tstart - gbm_tte_file.trigger_time,
            stop_time=gbm_tte_file.tstop - gbm_tte_file.trigger_time,
            dead_time=gbm_tte_file.deadtime,
            first_channel=0,
            instrument=gbm_tte_file.det_name,
            mission=gbm_tte_file.mission,
            verbose=verbose,
        )

        if use_balrog:

            assert has_balrog, "you must install the gbm_drm_gen package to use balrog"

            assert cspec_file is not None, "must include a cspecfile"

            if poshist_file is not None:

                drm_gen = gbm_drm_gen.DRMGenTTE(
                    tte_file,
                    poshist=poshist_file,
                    cspecfile=cspec_file,
                    T0=trigger_time,
                    mat_type=2,
                    occult=True,
                )

            elif trigdat_file is not None:

                drm_gen = gbm_drm_gen.DRMGenTTE(
                    tte_file,
                    trigdat=trigdat_file,
                    cspecfile=cspec_file,
                    mat_type=2,
                    occult=True,
                )

            else:

                RuntimeError("No poshist or trigdat file supplied")

            rsp = gbm_drm_gen.BALROG_DRM(drm_gen, 0, 0)

        elif isinstance(rsp_file, str) or isinstance(rsp_file, unicode):

            # we need to see if this is an RSP2

            test = re.match("^.*\.rsp2$", rsp_file)

            # some GBM RSPs that are not marked RSP2 are in fact RSP2s
            # we need to check

            if test is None:

                with fits.open(rsp_file) as f:

                    # there should only be a header, ebounds and one spec rsp extension

                    if len(f) > 3:

                        # make test a dummy value to trigger the nest loop

                        test = -1

                        custom_warnings.warn(
                            "The RSP file is marked as a single response but in fact has multiple matrices. We will treat it as an RSP2"
                        )

            if test is not None:

                rsp = InstrumentResponseSet.from_rsp2_file(
                    rsp2_file=rsp_file,
                    counts_getter=event_list.counts_over_interval,
                    exposure_getter=event_list.exposure_over_interval,
                    reference_time=gbm_tte_file.trigger_time,
                )

            else:

                rsp = OGIPResponse(rsp_file)

        else:

            assert isinstance(
                rsp_file, InstrumentResponse
            ), "The provided response is not a 3ML InstrumentResponse"
            rsp = rsp_file

        # pass to the super class

        return cls(
            name,
            event_list,
            response=rsp,
            poly_order=poly_order,
            unbinned=unbinned,
            verbose=verbose,
            restore_poly_fit=restore_background,
            container_type=BinnedSpectrumWithDispersion,
            use_balrog=use_balrog,
        )