def _get_weighted_matrix(self, switch, *intervals): assert len(intervals) > 0, "You have to provide at least one interval" intervals_set = TimeIntervalSet.from_strings(*intervals) # Compute a set of weights for each interval weights = np.zeros(len(self._matrix_list)) for interval in intervals_set: weights += self._weight_response(interval, switch) # Normalize to 1 weights /= np.sum(weights) # Weight matrices matrix = np.dot(np.array(map(attrgetter("matrix"), self._matrix_list)).T, weights.T).T # Now generate the instance of the response # get EBOUNDS from the first matrix ebounds = self._matrix_list[0].ebounds # Get mc channels from the first matrix mc_channels = self._matrix_list[0].monte_carlo_energies matrix_instance = InstrumentResponse(matrix, ebounds, mc_channels) return matrix_instance
def _get_weighted_matrix(self, switch, *intervals): assert len(intervals) > 0, "You have to provide at least one interval" intervals_set = TimeIntervalSet.from_strings(*intervals) # Compute a set of weights for each interval weights = np.zeros(len(self._matrix_list)) for interval in intervals_set: weights += self._weight_response(interval, switch) # Normalize to 1 weights /= np.sum(weights) # Weight matrices matrix = np.dot( np.array(list(map(attrgetter("matrix"), self._matrix_list))).T, weights.T).T # Now generate the instance of the response # get EBOUNDS from the first matrix ebounds = self._matrix_list[0].ebounds # Get mc channels from the first matrix mc_channels = self._matrix_list[0].monte_carlo_energies matrix_instance = InstrumentResponse(matrix, ebounds, mc_channels) return matrix_instance
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 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 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 set_polynomial_fit_interval(self, *time_intervals, **options): """Set the time interval to fit the background. Multiple intervals can be input as separate arguments Specified as 'tmin-tmax'. Intervals are in seconds. Example: set_polynomial_fit_interval("-10.0-0.0","10.-15.") :param time_intervals: intervals to fit on :param options: """ # Find out if we want to binned or unbinned. # TODO: add the option to config file if 'unbinned' in options: unbinned = options.pop('unbinned') assert type( unbinned) == bool, 'unbinned option must be True or False' else: # assuming unbinned # could use config file here # unbinned = threeML_config['ogip']['use-unbinned-poly-fitting'] unbinned = True # we create some time intervals poly_intervals = TimeIntervalSet.from_strings(*time_intervals) # adjust the selections to the data new_intervals = [] self._poly_selected_counts = [] self._poly_exposure = 0. for i, time_interval in enumerate(poly_intervals): t1 = time_interval.start_time t2 = time_interval.stop_time if (self._stop_time <= t1) or (t2 <= self._start_time): custom_warnings.warn( "The time interval %f-%f is out side of the arrival times and will be dropped" % (t1, t2)) else: if t1 < self._start_time: custom_warnings.warn( "The time interval %f-%f started before the first arrival time (%f), so we are changing the intervals to %f-%f" % (t1, t2, self._start_time, self._start_time, t2)) t1 = self._start_time # + 1 if t2 > self._stop_time: custom_warnings.warn( "The time interval %f-%f ended after the last arrival time (%f), so we are changing the intervals to %f-%f" % (t1, t2, self._stop_time, t1, self._stop_time)) t2 = self._stop_time # - 1. new_intervals.append('%f-%f' % (t1, t2)) self._poly_selected_counts.append( self.count_per_channel_over_interval(t1, t2)) self._poly_exposure += self.exposure_over_interval(t1, t2) # make new intervals after checks poly_intervals = TimeIntervalSet.from_strings(*new_intervals) self._poly_selected_counts = np.sum(self._poly_selected_counts, axis=0) # set the poly intervals as an attribute self._poly_intervals = poly_intervals # Fit the events with the given intervals if unbinned: self._unbinned = True # keep track! self._unbinned_fit_polynomials() else: self._unbinned = False self._fit_polynomials() # we have a fit now self._poly_fit_exists = True if self._verbose: print("%s %d-order polynomial fit with the %s method" % (self._fit_method_info['bin type'], self._optimal_polynomial_grade, self._fit_method_info['fit method'])) print('\n') # recalculate the selected counts if self._time_selection_exists: self.set_active_time_intervals( *self._time_intervals.to_string().split(','))
def set_active_time_intervals(self, *args): """ Set the time interval(s) to be used during the analysis. Specified as 'tmin-tmax'. Intervals are in seconds. Example: set_active_time_intervals("0.0-10.0") which will set the time range 0-10. seconds. """ # mark that we now have a time selection self._time_selection_exists = True # lets build a time interval set from the selections # and then merge intersecting intervals time_intervals = TimeIntervalSet.from_strings(*args) time_intervals.merge_intersecting_intervals(in_place=True) # lets adjust the time intervals to the actual ones since they are prebinned time_intervals = self._adjust_to_true_intervals(time_intervals) # start out with no time bins selection all_idx = np.zeros( len(self._binned_spectrum_set.time_intervals), dtype=bool) # now we need to sum up the counts and total time total_time = 0 for interval in time_intervals: # the select bins method is called. # since we are sure that the interval bounds # are aligned with the true ones, we do not care if # it is inner or outer all_idx = np.logical_or( all_idx, self._select_bins( interval.start_time, interval.stop_time) ) total_time += interval.duration # sum along the time axis self._counts = self._binned_spectrum_set.counts_per_bin[all_idx].sum( axis=0) # the selected time intervals self._time_intervals = time_intervals tmp_counts = [] tmp_err = [] # Temporary list to hold the err counts per chan if self._poly_fit_exists: if not self._poly_fit_exists: raise RuntimeError( "A polynomial fit to the channels does not exist!") for chan in range(self._n_channels): total_counts = 0 counts_err = 0 for tmin, tmax in zip( self._time_intervals.start_times, self._time_intervals.stop_times ): # Now integrate the appropriate background polynomial total_counts += self._polynomials[chan].integral( tmin, tmax) counts_err += ( self._polynomials[chan].integral_error(tmin, tmax) ) ** 2 tmp_counts.append(total_counts) tmp_err.append(np.sqrt(counts_err)) self._poly_counts = np.array(tmp_counts) self._poly_count_err = np.array(tmp_err) self._exposure = self._binned_spectrum_set.exposure_per_bin[all_idx].sum( ) self._active_dead_time = total_time - self._exposure
def set_active_time_intervals(self, *args): '''Set the time interval(s) to be used during the analysis. Specified as 'tmin-tmax'. Intervals are in seconds. Example: set_active_time_intervals("0.0-10.0") which will set the energy range 0-10. seconds. ''' self._time_selection_exists = True interval_masks = [] time_intervals = TimeIntervalSet.from_strings(*args) time_intervals.merge_intersecting_intervals(in_place=True) for interval in time_intervals: tmin = interval.start_time tmax = interval.stop_time mask = self._select_events(tmin, tmax) interval_masks.append(mask) self._time_intervals = time_intervals time_mask = interval_masks[0] if len(interval_masks) > 1: for mask in interval_masks[1:]: time_mask = np.logical_or(time_mask, mask) tmp_counts = [] # Temporary list to hold the total counts per chan for chan in range(self._first_channel, self._n_channels + self._first_channel): channel_mask = self._measurement == chan counts_mask = np.logical_and(channel_mask, time_mask) total_counts = len(self._arrival_times[counts_mask]) tmp_counts.append(total_counts) self._counts = np.array(tmp_counts) tmp_counts = [] tmp_err = [] # Temporary list to hold the err counts per chan if self._poly_fit_exists: if not self._poly_fit_exists: raise RuntimeError( 'A polynomial fit to the channels does not exist!') for chan in range(self._n_channels): total_counts = 0 counts_err = 0 for tmin, tmax in zip(self._time_intervals.start_times, self._time_intervals.stop_times): # Now integrate the appropriate background polynomial total_counts += self._polynomials[chan].integral( tmin, tmax) counts_err += (self._polynomials[chan].integral_error( tmin, tmax))**2 tmp_counts.append(total_counts) tmp_err.append(np.sqrt(counts_err)) self._poly_counts = np.array(tmp_counts) self._poly_count_err = np.array(tmp_err) # Dead time correction exposure = 0. total_dead_time = 0. for interval, imask in zip(self._time_intervals, interval_masks): exposure += interval.duration if self._dead_time_fraction is not None: total_dead_time += interval.duration * self._dead_time_fraction[ imask].mean() self._exposure = exposure - total_dead_time self._active_dead_time = total_dead_time
def set_active_time_intervals(self, *args): """ Set the time interval(s) to be used during the analysis. Specified as 'tmin-tmax'. Intervals are in seconds. Example: set_active_time_intervals("0.0-10.0") which will set the time range 0-10. seconds. """ # mark that we now have a time selection self._time_selection_exists = True # lets build a time interval set from the selections # and then merge intersecting intervals time_intervals = TimeIntervalSet.from_strings(*args) time_intervals.merge_intersecting_intervals(in_place=True) # lets adjust the time intervals to the actual ones since they are prebinned time_intervals = self._adjust_to_true_intervals(time_intervals) # start out with no time bins selection all_idx = np.zeros(len(self._binned_spectrum_set.time_intervals),dtype=bool) # now we need to sum up the counts and total time total_time = 0 for interval in time_intervals: # the select bins method is called. # since we are sure that the interval bounds # are aligned with the true ones, we do not care if # it is inner or outer all_idx = np.logical_or(all_idx,self._select_bins(interval.start_time,interval.stop_time)) total_time += interval.duration # sum along the time axis self._counts = self._binned_spectrum_set.counts_per_bin[all_idx].sum(axis=0) # the selected time intervals self._time_intervals = time_intervals tmp_counts = [] tmp_err = [] # Temporary list to hold the err counts per chan if self._poly_fit_exists: if not self._poly_fit_exists: raise RuntimeError('A polynomial fit to the channels does not exist!') for chan in range(self._n_channels): total_counts = 0 counts_err = 0 for tmin, tmax in zip(self._time_intervals.start_times, self._time_intervals.stop_times): # Now integrate the appropriate background polynomial total_counts += self._polynomials[chan].integral(tmin, tmax) counts_err += (self._polynomials[chan].integral_error(tmin, tmax)) ** 2 tmp_counts.append(total_counts) tmp_err.append(np.sqrt(counts_err)) self._poly_counts = np.array(tmp_counts) self._poly_count_err = np.array(tmp_err) self._exposure = self._binned_spectrum_set.exposure_per_bin[all_idx].sum() self._active_dead_time = total_time - self._exposure
def set_polynomial_fit_interval(self, *time_intervals, **options): """Set the time interval to fit the background. Multiple intervals can be input as separate arguments Specified as 'tmin-tmax'. Intervals are in seconds. Example: set_polynomial_fit_interval("-10.0-0.0","10.-15.") :param time_intervals: intervals to fit on :param options: """ # Find out if we want to binned or unbinned. # TODO: add the option to config file if 'unbinned' in options: unbinned = options.pop('unbinned') assert type(unbinned) == bool, 'unbinned option must be True or False' else: # assuming unbinned # could use config file here # unbinned = threeML_config['ogip']['use-unbinned-poly-fitting'] unbinned = True # we create some time intervals poly_intervals = TimeIntervalSet.from_strings(*time_intervals) # adjust the selections to the data new_intervals = [] self._poly_selected_counts = [] self._poly_exposure = 0. for i, time_interval in enumerate(poly_intervals): t1 = time_interval.start_time t2 = time_interval.stop_time if (self._stop_time <= t1) or (t2 <= self._start_time): custom_warnings.warn( "The time interval %f-%f is out side of the arrival times and will be dropped" % ( t1, t2)) else: if t1 < self._start_time: custom_warnings.warn( "The time interval %f-%f started before the first arrival time (%f), so we are changing the intervals to %f-%f" % ( t1, t2, self._start_time, self._start_time, t2)) t1 = self._start_time # + 1 if t2 > self._stop_time: custom_warnings.warn( "The time interval %f-%f ended after the last arrival time (%f), so we are changing the intervals to %f-%f" % ( t1, t2, self._stop_time, t1, self._stop_time)) t2 = self._stop_time # - 1. new_intervals.append('%f-%f' % (t1, t2)) self._poly_selected_counts.append(self.count_per_channel_over_interval(t1,t2)) self._poly_exposure += self.exposure_over_interval(t1,t2) # make new intervals after checks poly_intervals = TimeIntervalSet.from_strings(*new_intervals) self._poly_selected_counts = np.sum(self._poly_selected_counts, axis=0) # set the poly intervals as an attribute self._poly_intervals = poly_intervals # Fit the events with the given intervals if unbinned: self._unbinned = True # keep track! self._unbinned_fit_polynomials() else: self._unbinned = False self._fit_polynomials() # we have a fit now self._poly_fit_exists = True if self._verbose: print("%s %d-order polynomial fit with the %s method" % ( self._fit_method_info['bin type'], self._optimal_polynomial_grade, self._fit_method_info['fit method'])) print('\n') # recalculate the selected counts if self._time_selection_exists: self.set_active_time_intervals(*self._time_intervals.to_string().split(','))
def set_polynomial_fit_interval(self, *time_intervals, **kwargs) -> None: """Set the time interval to fit the background. Multiple intervals can be input as separate arguments Specified as 'tmin-tmax'. Intervals are in seconds. Example: set_polynomial_fit_interval("-10.0-0.0","10.-15.") :param time_intervals: intervals to fit on :param unbinned: :param bayes: :param kwargs: """ # Find out if we want to binned or unbinned. # TODO: add the option to config file if "unbinned" in kwargs: unbinned = kwargs.pop("unbinned") assert type( unbinned) == bool, "unbinned option must be True or False" else: # assuming unbinned # could use config file here # unbinned = threeML_config['ogip']['use-unbinned-poly-fitting'] unbinned = True # check if we are doing a bayesian # fit and record this info if "bayes" in kwargs: bayes = kwargs.pop("bayes") else: bayes = False if bayes: self._fit_method_info["fit method"] = "bayes" else: self._fit_method_info["fit method"] = "bayes" # we create some time intervals poly_intervals = TimeIntervalSet.from_strings(*time_intervals) # adjust the selections to the data new_intervals = [] self._poly_selected_counts = [] self._poly_exposure = 0.0 for i, time_interval in enumerate(poly_intervals): t1 = time_interval.start_time t2 = time_interval.stop_time if (self._stop_time <= t1) or (t2 <= self._start_time): log.warning( "The time interval %f-%f is out side of the arrival times and will be dropped" % (t1, t2)) else: if t1 < self._start_time: log.warning( "The time interval %f-%f started before the first arrival time (%f), so we are changing the intervals to %f-%f" % (t1, t2, self._start_time, self._start_time, t2)) t1 = self._start_time # + 1 if t2 > self._stop_time: log.warning( "The time interval %f-%f ended after the last arrival time (%f), so we are changing the intervals to %f-%f" % (t1, t2, self._stop_time, t1, self._stop_time)) t2 = self._stop_time # - 1. new_intervals.append("%f-%f" % (t1, t2)) self._poly_selected_counts.append( self.count_per_channel_over_interval(t1, t2)) self._poly_exposure += self.exposure_over_interval(t1, t2) # make new intervals after checks poly_intervals = TimeIntervalSet.from_strings(*new_intervals) self._poly_selected_counts = np.sum(self._poly_selected_counts, axis=0) # set the poly intervals as an attribute self._poly_intervals = poly_intervals # Fit the events with the given intervals if unbinned: self._unbinned = True # keep track! self._unbinned_fit_polynomials(bayes=bayes) else: self._unbinned = False self._fit_polynomials(bayes=bayes) # we have a fit now self._poly_fit_exists = True log.info( f"{self._fit_method_info['bin type']} {self._optimal_polynomial_grade}-order polynomial fit with the {self._fit_method_info['fit method']} method" ) # recalculate the selected counts if self._time_selection_exists: self.set_active_time_intervals( *self._time_intervals.to_string().split(","))
def set_active_time_intervals(self, *args): """Set the time interval(s) to be used during the analysis. Specified as 'tmin-tmax'. Intervals are in seconds. Example: set_active_time_intervals("0.0-10.0") which will set the energy range 0-10. seconds. """ self._time_selection_exists = True interval_masks = [] time_intervals = TimeIntervalSet.from_strings(*args) time_intervals.merge_intersecting_intervals(in_place=True) for interval in time_intervals: tmin = interval.start_time tmax = interval.stop_time mask = self._select_events(tmin, tmax) interval_masks.append(mask) self._time_intervals = time_intervals time_mask = interval_masks[0] if len(interval_masks) > 1: for mask in interval_masks[1:]: time_mask = np.logical_or(time_mask, mask) # calulate exposure and deadtime exposure = 0 dead_time = 0 for interval in time_intervals: tmin = interval.start_time tmax = interval.stop_time this_exposure = self.exposure_over_interval(tmin, tmax) # check that the exposure is not larger than the total time if this_exposure > (tmax - tmin): log.error("The exposure in the active time bin is larger " "than the total active time. " "Something must be wrong!") raise RuntimeError() exposure += this_exposure dead_time += (tmax - tmin) - this_exposure self._exposure = exposure self._active_dead_time = dead_time tmp_counts = [] # Temporary list to hold the total counts per chan for chan in range(self._first_channel, self._n_channels + self._first_channel): channel_mask = self._measurement == chan counts_mask = np.logical_and(channel_mask, time_mask) total_counts = len(self._arrival_times[counts_mask]) tmp_counts.append(total_counts) self._counts = np.array(tmp_counts) tmp_counts = [] tmp_err = [] # Temporary list to hold the err counts per chan if self._poly_fit_exists: if not self._poly_fit_exists: raise RuntimeError( "A polynomial fit to the channels does not exist!") for chan in range(self._n_channels): total_counts = 0 counts_err = 0 for tmin, tmax in zip(self._time_intervals.start_times, self._time_intervals.stop_times): # Now integrate the appropriate background polynomial total_counts += self._polynomials[chan].integral( tmin, tmax) counts_err += (self._polynomials[chan].integral_error( tmin, tmax))**2 tmp_counts.append(total_counts) tmp_err.append(np.sqrt(counts_err)) self._poly_counts = np.array(tmp_counts) self._poly_count_err = np.array(tmp_err) # apply the dead time correction to the background counts # and errors corr = self._exposure / (self._active_dead_time + self._exposure) self._poly_counts *= corr self._poly_count_err *= corr