def test_time_interval_equivalence(): t1 = TimeInterval(10.523, 20.32) assert t1 == TimeInterval(10.523, 20.32) assert not t1 == None
def test_instrument_response_constructor(): # Make a fake test matrix matrix, mc_energies, ebounds = get_matrix_elements() rsp = InstrumentResponse(matrix, ebounds, mc_energies) assert np.all(rsp.matrix == matrix) assert np.all(rsp.ebounds == ebounds) assert np.all(rsp.monte_carlo_energies == mc_energies) # Now with coverage interval with pytest.raises(AssertionError): _ = InstrumentResponse(matrix, ebounds, mc_energies, "10-20") rsp = InstrumentResponse(matrix, ebounds, mc_energies, TimeInterval(10.0, 20.0)) assert rsp.rsp_filename is None assert rsp.arf_filename is None assert rsp.coverage_interval == TimeInterval(10.0, 20.0) # Check that we do not accept nans in the matrix matrix[2, 2] = np.nan with pytest.raises(AssertionError): _ = InstrumentResponse(matrix, ebounds, mc_energies, "10-20")
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)
def test_time_interval_constructor_set(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) ts = TimeIntervalSet([t1, t2]) assert ts[0] == t1 assert ts[1] == t2 # Use strings ts2 = TimeIntervalSet.from_strings("-10 - -5", "10 - 20", "20-30", "-10--5") assert ts2[0].start_time == -10 assert ts2[0].stop_time == -5 assert ts2[-1].start_time == -10 assert ts2[-1].stop_time == -5 assert ts2[1].start_time == 10 assert ts2[1].stop_time == 20 assert ts2[2].start_time == 20 assert ts2[2].stop_time == 30 # Use edges ts3 = TimeIntervalSet.from_list_of_edges([-2, -1, 0, 1, 2]) assert ts3[0].start_time == -2 assert ts3[0].stop_time == -1 assert ts3[-1].start_time == 1 assert ts3[-1].stop_time == 2 assert ts3[1].start_time == -1 assert ts3[1].stop_time == 0 assert ts3[2].start_time == 0 assert ts3[2].stop_time == 1 # Use start and stops ts5 = TimeIntervalSet.from_starts_and_stops([-2, -1, 0, 1], [-1, 0, 1, 2]) assert ts5[0].start_time == -2 assert ts5[0].stop_time == -1 assert ts5[-1].start_time == 1 assert ts5[-1].stop_time == 2 assert ts5[1].start_time == -1 assert ts5[1].stop_time == 0 assert ts5[2].start_time == 0 assert ts5[2].stop_time == 1 with pytest.raises(AssertionError): ts6 = TimeIntervalSet.from_starts_and_stops([-2, -1, 0, 1], [-1, 0, 1]) # test display ts5.display()
def from_rsp2_file(cls, rsp2_file, exposure_getter, counts_getter, reference_time=0.0, half_shifted=True): # This assumes the Fermi/GBM rsp2 file format # make the rsp file proper rsp_file = sanitize_filename(rsp2_file) assert file_existing_and_readable(rsp_file), "OGIPResponse file %s not existing or not readable" % rsp_file # Will fill up the list of matrices list_of_matrices = [] # Read the response with pyfits.open(rsp_file) as f: n_responses = f['PRIMARY'].header['DRM_NUM'] # we will read all the matrices and save them for rsp_number in range(1, n_responses + 1): this_response = OGIPResponse(rsp2_file + '{%i}' % rsp_number) list_of_matrices.append(this_response) if half_shifted: # Now the GBM format has a strange feature: the matrix, instead of covering from TSTART to TSTOP, covers # from (TSTART + TSTOP) / 2.0 of the previous matrix to the (TSTART + TSTOP) / 2.0 of itself. # So let's adjust the coverage intervals accordingly if len(list_of_matrices) > 1: for i, this_matrix in enumerate(list_of_matrices): if i == 0: # The first matrix covers from its TSTART to its half time this_matrix._coverage_interval = TimeInterval(this_matrix.coverage_interval.start_time, this_matrix.coverage_interval.half_time) else: # Any other matrix covers from the half time of the previous matrix to its half time # However, the previous matrix has been already processed, so we use its stop time which # has already begun the half time of what it was before processing prev_matrix = list_of_matrices[i-1] this_matrix._coverage_interval = TimeInterval(prev_matrix.coverage_interval.stop_time, this_matrix.coverage_interval.half_time) return InstrumentResponseSet(list_of_matrices, exposure_getter, counts_getter, reference_time)
def get_matrix_set_elements_with_coverage(reference_time=0.0): [rsp_a, rsp_b], exposure_getter, counts_getter = get_matrix_set_elements() # By making the coverage interval twice for the second matrix we restore parity with the first one, # so that the weighting by exposure should simply return the first matrix rsp_a._coverage_interval = TimeInterval(0.0, 10.0) + reference_time rsp_b._coverage_interval = TimeInterval(10.0, 30.0) + reference_time return [rsp_a, rsp_b], exposure_getter, counts_getter
def test_time_interval_set_pop(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) t3 = TimeInterval(-30.0, 50.0) ts = TimeIntervalSet([t1, t2, t3]) popped = ts.pop(1) assert popped == t2
def test_time_interval_argsort_set(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) t3 = TimeInterval(-30.0, 50.0) ts = TimeIntervalSet([t1, t2, t3]) idx = ts.argsort() assert idx == [2, 0, 1]
def test_time_interval_overlaps_with(): t1 = TimeInterval(-10.0, 10.0) t2 = TimeInterval(0.0, 30.0) t3 = TimeInterval(-100, 100.0) t4 = TimeInterval(-100, -10) t5 = TimeInterval(100.0, 200.0) assert t1.overlaps_with(t2) == True assert t1.overlaps_with(t3) == True assert t1.overlaps_with(t4) == False assert t1.overlaps_with(t5) == False
def test_time_interval_sort_set(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) t3 = TimeInterval(-30.0, 50.0) ts = TimeIntervalSet([t1, t2, t3]) ts2 = ts.sort() assert ts2[0] == t3 assert ts2[1] == t1 assert ts2[2] == t2
def test_time_interval_sets_starts_stops(): t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(5.0, 10.0) t3 = TimeInterval(15.0, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) for start, stop, interval in zip(ts1.start_times, ts1.stop_times, [t1, t2, t3]): assert interval.start_time == start assert interval.stop_time == stop
def test_time_interval_constructor(): t = TimeInterval(-10.0, 10.0) assert t.start_time == -10.0 assert t.stop_time == 10.0 assert t.duration == 20.0 assert t.half_time == 0.0 with pytest.raises(RuntimeError): _ = TimeInterval(10.0, -10.0, swap_if_inverted=False) _ = TimeInterval(-10.0, 10.0, swap_if_inverted=True)
def test_time_interval_merge(): t1 = TimeInterval(-10.0, 10.0) t2 = TimeInterval(0.0, 30.0) t = t1.merge(t2) assert t.start_time == -10.0 assert t.stop_time == 30.0 with pytest.raises(IntervalsDoNotOverlap): t1 = TimeInterval(-10.0, 10.0) t2 = TimeInterval(20.0, 30.0) _ = t1.merge(t2)
def test_time_interval_add_sub_set(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) ts = TimeIntervalSet([t1, t2]) ts2 = ts + 10.0 # type: TimeIntervalSet assert ts2[0].start_time == 0.0 assert ts2[1].stop_time == 40.0 ts3 = ts - 10.0 # type: TimeIntervalSet assert ts3[0].start_time == -20.0 assert ts3[1].stop_time == 20.0
def test_time_interval_iterator_set(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) ts = TimeIntervalSet([t1, t2]) for i, tt in enumerate(ts): if i == 0: assert tt == t1 else: assert tt == t2
def test_time_interval_sub(): t = TimeInterval(-10.0, 10.0) new_t = t - 10.0 # type: TimeInterval assert new_t.start_time == -20.0 assert new_t.stop_time == 0.0
def test_time_interval_extend_set(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) ts = TimeIntervalSet([t1, t2]) t3 = TimeInterval(30.0, 40.0) t4 = TimeInterval(40.0, 50.0) ts.extend([t3, t4]) assert len(ts) == 4 ts.extend(TimeIntervalSet([t3, t4])) assert len(ts) == 6
def test_time_interval_add(): t = TimeInterval(-10.0, 10.0) new_t = t + 10.0 # type: TimeInterval assert new_t.start_time == 0 assert new_t.stop_time == 20.0
def test_interval_set_to_string(): # also tests the time interval to string t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(5.0, 10.0) t3 = TimeInterval(15.0, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) strings = ts1.to_string() strings_split = strings.split(",") assert t1.to_string() == strings_split[0] assert t2.to_string() == strings_split[1] assert t3.to_string() == strings_split[2] ts2 = TimeIntervalSet.from_strings(t1.to_string()) assert ts2[0] == t1
def test_interval_set_to_string(): # also tests the time interval to string t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(5., 10.0) t3 = TimeInterval(15.0, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) strings = ts1.to_string() strings_split = strings.split(',') assert t1.to_string() == strings_split[0] assert t2.to_string() == strings_split[1] assert t3.to_string() == strings_split[2] ts2 = TimeIntervalSet.from_strings(t1.to_string()) assert ts2[0] == t1
def test_time_edges(): t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(0.0, 10.0) t3 = TimeInterval(10.0, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) assert ts1.time_edges[0] == -10.0 assert ts1.time_edges[1] == 0.0 assert ts1.time_edges[2] == 10.0 assert ts1.time_edges[3] == 20.0 with pytest.raises(IntervalsNotContiguous): t1 = TimeInterval(-10.0, -5.0) t2 = TimeInterval(0.0, 10.0) t3 = TimeInterval(10.0, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) _ = ts1.time_edges
def test_merging_set_intervals(): # test that non overlapping intervals # do not result in a merge t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(5.0, 10.0) t3 = TimeInterval(15.0, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) ts2 = ts1.merge_intersecting_intervals(in_place=False) assert len(ts2) == 3 assert t1 == ts2[0] assert t2 == ts2[1] assert t3 == ts2[2] # end merge works t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(5.0, 10.0) t3 = TimeInterval(7.0, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) ts2 = ts1.merge_intersecting_intervals(in_place=False) assert len(ts2) == 2 assert t1 == ts2[0] assert TimeInterval(5.0, 20.0) == ts2[1] # begin merge works t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(-5.0, 10.0) t3 = TimeInterval(15, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) ts2 = ts1.merge_intersecting_intervals(in_place=False) assert len(ts2) == 2 assert TimeInterval(-10.0, 10.0) == ts2[0] assert TimeInterval(15.0, 20.0) == ts2[1] # middle merge works t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(5.0, 10.0) t3 = TimeInterval(7.0, 20.0) t4 = TimeInterval(35.0, 40.0) ts1 = TimeIntervalSet([t1, t2, t3, t4]) ts2 = ts1.merge_intersecting_intervals(in_place=False) assert len(ts2) == 3 assert t1 == ts2[0] assert TimeInterval(5.0, 20.0) == ts2[1] assert t4 == ts2[2] # both end merge works t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(-5.0, 10.0) t3 = TimeInterval(15.0, 20.0) t4 = TimeInterval(35.0, 45.0) t5 = TimeInterval(40.0, 50.0) ts1 = TimeIntervalSet([t1, t2, t3, t4, t5]) ts2 = ts1.merge_intersecting_intervals(in_place=False) assert len(ts2) == 3 assert TimeInterval(-10.0, 10.0) == ts2[0] assert t3 == ts2[1] assert TimeInterval(35.0, 50.0) == ts2[2] # multi merge works t1 = TimeInterval(-10.0, 0.0) t2 = TimeInterval(-5.0, 10.0) t3 = TimeInterval(7, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) ts2 = ts1.merge_intersecting_intervals(in_place=False) assert len(ts2) == 1 assert TimeInterval(-10.0, 20.0) == ts2[0] # complete overlap merge works t1 = TimeInterval(-10.0, 25.0) t2 = TimeInterval(-5.0, 10.0) t3 = TimeInterval(7, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) ts2 = ts1.merge_intersecting_intervals(in_place=False) assert len(ts2) == 1 assert TimeInterval(-10.0, 25.0) == ts2[0] # tests the inplace operation t1 = TimeInterval(-10.0, 25.0) t2 = TimeInterval(-5.0, 10.0) t3 = TimeInterval(7, 20.0) ts1 = TimeIntervalSet([t1, t2, t3]) ts1.merge_intersecting_intervals(in_place=True) assert len(ts1) == 1 assert TimeInterval(-10.0, 25.0) == ts1[0]
def __init__(self, rsp_file: str, arf_file: Optional[str] = None) -> None: """ :param rsp_file: :param arf_file: """ # Now make sure that the response file exist rsp_file: Path = sanitize_filename(rsp_file) if not fits_file_existing_and_readable(rsp_file): log.error( f"OGIPResponse file {rsp_file} not existing or not readable") raise RuntimeError() # Check if we are dealing with a .rsp2 file (containing more than # one response). This is checked by looking for the syntax # [responseFile]{[responseNumber]} if "{" in str(rsp_file): tokens = str(rsp_file).split("{") rsp_file: Path = sanitize_filename(tokens[0]) rsp_number = int(tokens[-1].split("}")[0].replace(" ", "")) else: rsp_number = 1 self._rsp_file: Path = rsp_file # Read the response with pyfits.open(rsp_file) as f: try: # This is usually when the response file contains only the energy dispersion data = f["MATRIX", rsp_number].data header = f["MATRIX", rsp_number].header if arf_file is None: log.warning( "The response is in an extension called MATRIX, which usually means you also " "need an ancillary file (ARF) which you didn't provide. You should refer to the " "documentation of the instrument and make sure you don't need an ARF." ) except Exception as e: log.warning( "The default choice for MATRIX extension failed:" + repr(e) + "available: " + " ".join([repr(e.header.get("EXTNAME")) for e in f])) # Other detectors might use the SPECRESP MATRIX name instead, usually when the response has been # already convoluted with the effective area # Note that here we are not catching any exception, because # we have to fail if we cannot read the matrix data = f["SPECRESP MATRIX", rsp_number].data header = f["SPECRESP MATRIX", rsp_number].header # These 3 operations must be executed when the file is still open matrix = self._read_matrix(data, header) ebounds = self._read_ebounds(f["EBOUNDS"]) mc_channels = self._read_mc_channels(data) # Now, if there is information on the coverage interval, let's use it header_start = header.get("TSTART", None) header_stop = header.get("TSTOP", None) if header_start is not None and header_stop is not None: super(OGIPResponse, self).__init__( matrix=matrix, ebounds=ebounds, monte_carlo_energies=mc_channels, coverage_interval=TimeInterval(header_start, header_stop), ) else: super(OGIPResponse, self).__init__(matrix=matrix, ebounds=ebounds, monte_carlo_energies=mc_channels) # Read the ARF if there is any # NOTE: this has to happen *after* calling the parent constructor self._arf_file: Optional[str] = None if arf_file is not None and str(arf_file).lower() != "none": self._read_arf_file(arf_file)
def test_time_interval_repr(): t = TimeInterval(-10.0, 10.0) print(t)
def test_time_interval_set_is_contiguous(): t1 = TimeInterval(-10.0, 20.0) t2 = TimeInterval(10.0, 30.0) t3 = TimeInterval(-30.0, 50.0) ts = TimeIntervalSet([t1, t2, t3]) assert ts.is_contiguous() == False t1 = TimeInterval(0.0, 1.0) t2 = TimeInterval(1.0, 2.0) t3 = TimeInterval(2.0, 3.0) ts = TimeIntervalSet([t1, t2, t3]) assert ts.is_contiguous() == True t1 = TimeInterval(0.0, 1.0) t2 = TimeInterval(1.1, 2.0) t3 = TimeInterval(2.0, 3.0) ts = TimeIntervalSet([t1, t2, t3]) assert ts.is_contiguous() == False t1 = TimeInterval(0.0, 1.0) t2 = TimeInterval(2.0, 3.0) t3 = TimeInterval(1.0, 2.0) ts = TimeIntervalSet([t1, t2, t3]) assert ts.is_contiguous() == False new_ts = ts.sort() assert new_ts.is_contiguous() == True