def test_pha_get_filter_checks_ungrouped(chtype, expected, args): """Check we get the filter we expect chtype is channel, energy, or wavelength expected is the expected response args is a list of 3-tuples of (flag, loval, hival) where flag is True for notice and False for ignore; they define the filter to apply """ chans = np.arange(1, 11, dtype=int) counts = np.ones(10, dtype=int) pha = DataPHA('data', chans, counts) # Use an ARF to create a channel to energy mapping # The 0.2-2.2 keV range maps to 5.636-61.992 Angstrom # egrid = 0.2 * np.arange(1, 12) arf = DataARF('arf', egrid[:-1], egrid[1:], np.ones(10)) pha.set_arf(arf) pha.units = chtype for (flag, lo, hi) in args: if flag: pha.notice(lo, hi) else: pha.ignore(lo, hi) assert pha.get_filter(format='%.1f') == expected
def create_arf(elo, ehi, specresp=None, exposure=None, ethresh=None): """Create an ARF. Parameters ---------- elo, ehi : array The energy bins (low and high, in keV) for the ARF. It is assumed that ehi_i > elo_i, elo_j > 0, the energy bins are either ascending - so elo_i+1 > elo_i - or descending (elo_i+1 < elo_i), and that there are no overlaps. specresp : None or array, optional The spectral response (in cm^2) for the ARF. It is assumed to be >= 0. If not given a flat response of 1.0 is used. exposure : number or None, optional If not None, the exposure of the ARF in seconds. ethresh : number or None, optional Passed through to the DataARF call. It controls whether zero-energy bins are replaced. Returns ------- arf : DataARF instance """ assert elo.size == ehi.size assert (exposure is None) or (exposure > 0.0) if specresp is None: specresp = np.ones(elo.size, dtype=np.float32) return DataARF('test-arf', energ_lo=elo, energ_hi=ehi, specresp=specresp, exposure=exposure, ethresh=ethresh)
def derive_identity_arf(name, arf): """Create an "identity" ARF that has uniform sensitivity. *name* The name of the ARF object to be created; passed to Sherpa. *arf* An existing ARF object on which to base this one. Returns: A new ARF1D object that has a uniform spectral response vector. In many X-ray observations, the relevant background signal does not behave like an astrophysical source that is filtered through the telescope's response functions. However, I have been unable to get current Sherpa (version 4.9) to behave how I want when working with backround models that are *not* filtered through these response functions. This function constructs an "identity" ARF response function that has uniform sensitivity as a function of detector channel. """ from sherpa.astro.data import DataARF from sherpa.astro.instrument import ARF1D darf = DataARF( name, arf.energ_lo, arf.energ_hi, np.ones(arf.specresp.shape), arf.bin_lo, arf.bin_hi, arf.exposure, header=None, ) return ARF1D(darf, pha=arf._pha)
def example_pha_data(): """Create an example data set.""" etime = 1201.0 d = DataPHA('example', _data_chan.copy(), _data_counts.copy(), exposure=etime, backscal=0.2) a = DataARF('example-arf', _energies_lo.copy(), _energies_hi.copy(), _arf.copy(), exposure=etime) r = create_delta_rmf(_energies_lo.copy(), _energies_hi.copy(), e_min=_energies_lo.copy(), e_max=_energies_hi.copy(), offset=1, name='example-rmf') d.set_arf(a) d.set_rmf(r) return d
def read_arf(arg): """ read_arf( filename ) read_arf( ARFCrate ) """ data, filename = backend.get_arf_data(arg) return DataARF(filename, **data)
def setUp(self): ui.dataspace1d(0.2, 10, 0.01, id=1) ui.dataspace1d(2, 5, 0.1, id="tst") ui.dataspace1d(0.1, 1, 0.1, id="not-used") ui.dataspace1d(0.1, 1, 0.1, id="no-arf") ui.dataspace1d(0.1, 11, 0.01, id='arf1', dstype=DataPHA) ui.dataspace1d(0.2, 10, 0.01, id='flatarf', dstype=DataPHA) # self.nbins = {} # for idval in [1, 'tst']: # self.nbins[idval] = ui.get_data(1).xlo.size self.nbins = {1: 980, 'tst': 30, 'arf1': 1090, 'arf1-arf': 489} self.grid = { 1: (0.2, 10, 0.01), 'tst': (2.0, 5.0, 0.1), 'arf1': (0.1, 11, 0.01), 'arf1-arf': (0.2, 9.98, 0.02) # note: ehigh is not 10.0 } ui.set_source(1, ui.powlaw1d.pl1) ui.set_source("tst", ui.powlaw1d.pltst) ui.set_source('no-arf', pl1) ui.set_source('arf1', pltst) ui.set_source('flatarf', pltst) ui.set_source('no-arf-flat', ui.const1d.c1) pl1.gamma = 0.0 pl1.ampl = 1.2 pltst.gamma = -1.0 pltst.ampl = 2.1 arfgrid = np.arange(0.2, 10, 0.02) arflo = arfgrid[:-1] arfhi = arfgrid[1:] amid = (arflo + arfhi) / 2.0 flatarf = DataARF('flat', energ_lo=arflo, energ_hi=arfhi, specresp=arflo * 0 + 10.1) arf = DataARF('arf', energ_lo=arflo, energ_hi=arfhi, specresp=20 - (4.5 - amid)**2) ui.set_arf('arf1', arf) ui.set_arf('flatarf', flatarf)
def test_arf_checks_energy_length(): """Just check we error out""" elo = np.arange(1, 5) ehi = np.arange(2, 9) dummy = [] with pytest.raises(ValueError) as ve: DataARF("dummy", elo, ehi, dummy) assert str(ve.value) == "The energy arrays must have the same size, not 4 and 7"
def create_arf(elo, ehi, specresp=None, exposure=None, ethresh=None, name='user-arf', header=None): """Create an ARF. .. versionadded:: 4.10.1 Parameters ---------- elo, ehi : numpy.ndarray The energy bins (low and high, in keV) for the ARF. It is assumed that ehi_i > elo_i, elo_j > 0, the energy bins are either ascending - so elo_i+1 > elo_i - or descending (elo_i+1 < elo_i), and that there are no overlaps. specresp : None or array, optional The spectral response (in cm^2) for the ARF. It is assumed to be >= 0. If not given a flat response of 1.0 is used. exposure : number or None, optional If not None, the exposure of the ARF in seconds. ethresh : number or None, optional Passed through to the DataARF call. It controls whether zero-energy bins are replaced. name : str, optional The name of the ARF data set header : dict Header for the created ARF Returns ------- arf : sherpa.astro.data.DataARF instance See Also -------- create_delta_rmf, create_non_delta_rmf """ if specresp is None: specresp = numpy.ones(elo.size, dtype=numpy.float32) return DataARF(name, energ_lo=elo, energ_hi=ehi, specresp=specresp, exposure=exposure, ethresh=ethresh, header=header)
def to_sherpa(self, name): """Convert to `~sherpa.astro.data.DataARF` Parameters ---------- name : str Instance name """ from sherpa.astro.data import DataARF table = self.to_table() return DataARF( name=name, energ_lo=table['ENERG_LO'].quantity.to('keV').value, energ_hi=table['ENERG_HI'].quantity.to('keV').value, specresp=table['SPECRESP'].quantity.to('cm2').value, )
def to_sherpa(self, name): """Convert to `~sherpa.astro.data.DataARF` Parameters ---------- name : str Instance name """ from sherpa.astro.data import DataARF table = self.to_table() return DataARF( name=name, energ_lo=table["ENERG_LO"].quantity.to_value("keV"), energ_hi=table["ENERG_HI"].quantity.to_value("keV"), specresp=table["SPECRESP"].quantity.to_value("cm2"), )
def read_arf(arg): """Create a DataARF object. Parameters ---------- arg The name of the file or a representation of the file (the type depends on the I/O backend) containing the ARF data. Returns ------- data : sherpa.astro.data.DataARF """ data, filename = backend.get_arf_data(arg) return DataARF(filename, **data)
def make_arf(energ_lo, energ_hi, specresp=None, exposure=1.0, name='arf'): """A simple in-memory representation of an ARF. Parameters ---------- energ_lo, energ_hi : array The energy grid over which the ARF is defined. The units are keV and each bin has energ_hi > energ_lo. The arrays are assumed to be ordered, but it is not clear yet whether they have to be in ascending order. specresp : array or None, optional The spectral response (effective area) for each bin, in cm^2. If not given then a value of 1.0 per bin is used. exposure : number, optional The exposure time, in seconds. It must be positive. name : str, optional The name to give to the ARF instance. Returns ------- arf : sherpa.astro.data.DataARF The ARF. """ elo = np.asarray(energ_lo) ehi = np.asarray(energ_hi) if elo.size != ehi.size: raise DataErr('mismatch', 'energ_lo', 'energ_hi') if specresp is None: specresp = np.ones(elo.size, dtype=np.float32) else: specresp = np.asarray(specresp) if specresp.size != elo.size: raise DataErr('mismatch', 'energy grid', 'effarea') if exposure <= 0.0: raise ArgumentErr('bad', 'exposure', 'value must be positive') return DataARF(name=name, energ_lo=elo, energ_hi=ehi, specresp=specresp, exposure=exposure)
def startup(self, cache): arf = self._arf # original pha = self.pha # Create a view of original ARF self.arf = DataARF(arf.name, arf.energ_lo, arf.energ_hi, arf.specresp, arf.bin_lo, arf.bin_hi, arf.exposure, arf.header) # Filter the view for current fitting session if numpy.iterable(pha.mask): mask = pha.get_mask() if len(mask) == len(self.arf.specresp): self.arf.notice(mask) self.filter() # Assume energy as default spectral coordinates self.xlo, self.xhi = self.elo, self.ehi if pha.units == 'wavelength': self.xlo, self.xhi = self.lo, self.hi ARFModel.startup(self, cache)
def read_arf(arg): """Create a DataARF object. Parameters ---------- arg The name of the file or a representation of the file (the type depends on the I/O backend) containing the ARF data. Returns ------- data : sherpa.astro.data.DataARF """ data, filename = backend.get_arf_data(arg) # It is unlikely that the backend will set this, but allow # it to override the config setting. # if 'emin' not in data: data['ethresh'] = ogip_emin return DataARF(filename, **data)
def startup(self, cache): arf = self._arf rmf = self._rmf # Create a view of original RMF self.rmf = DataRMF(rmf.name, rmf.detchans, rmf.energ_lo, rmf.energ_hi, rmf.n_grp, rmf.f_chan, rmf.n_chan, rmf.matrix, rmf.offset, rmf.e_min, rmf.e_max, rmf.header) # Create a view of original ARF self.arf = DataARF(arf.name, arf.energ_lo, arf.energ_hi, arf.specresp, arf.bin_lo, arf.bin_hi, arf.exposure, arf.header) # Filter the view for current fitting session _notice_resp(self.pha.get_noticed_channels(), self.arf, self.rmf) self.filter() # Assume energy as default spectral coordinates self.xlo, self.xhi = self.elo, self.ehi if self.pha.units == 'wavelength': self.xlo, self.xhi = self.lo, self.hi RSPModel.startup(self, cache)