class RSPModelPHA(RSPModel): """ RMF + ARF convolution model with associated PHA """ def __init__(self, arf, rmf, pha, model): self.pha = pha self._arf = arf self._rmf = rmf RSPModel.__init__(self, arf, rmf, model) def filter(self): RSPModel.filter(self) pha = self.pha # If PHA is a finer grid than RMF, evaluate model on PHA and # rebin down to the granularity that the RMF expects. if pha.bin_lo is not None and pha.bin_hi is not None: bin_lo, bin_hi = pha.bin_lo, pha.bin_hi # If PHA grid is in angstroms then convert to keV for # consistency if (bin_lo[0] > bin_lo[-1]) and (bin_hi[0] > bin_hi[-1]): bin_lo = DataPHA._hc / pha.bin_hi bin_hi = DataPHA._hc / pha.bin_lo # FIXME: What about filtered option?? bin_lo, bin_hi are # unfiltered?? # Compare disparate grids in energy space self.arfargs = ((self.elo, self.ehi), (bin_lo, bin_hi)) # FIXME: Assumes ARF grid is finest elo, ehi = self.rmf.get_indep() # self.elo, self.ehi are from ARF if len(elo) != len(self.elo) and len(ehi) != len(self.ehi): self.rmfargs = ((elo, ehi), (self.elo, self.ehi)) # 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 def startup(self): 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) def teardown(self): self.arf = self._arf # restore originals self.rmf = self._rmf self.filter() RSPModel.teardown(self) def calc(self, p, x, xhi=None, *args, **kwargs): # x could be channels or x, xhi could be energy|wave src = self.model.calc(p, self.xlo, self.xhi) src = self.arf.apply_arf(src, *self.arfargs) return self.rmf.apply_rmf(src, *self.rmfargs)
class RSPModelPHA(RSPModel): """RMF + ARF convolution model with associated PHA. Notes ----- Scaling by the AREASCAL setting (scalar or array) is included in this model. """ def __init__(self, arf, rmf, pha, model): self.pha = pha self._arf = arf self._rmf = rmf RSPModel.__init__(self, arf, rmf, model) def filter(self): RSPModel.filter(self) pha = self.pha # If PHA is a finer grid than RMF, evaluate model on PHA and # rebin down to the granularity that the RMF expects. if pha.bin_lo is not None and pha.bin_hi is not None: bin_lo, bin_hi = pha.bin_lo, pha.bin_hi # If PHA grid is in angstroms then convert to keV for # consistency if (bin_lo[0] > bin_lo[-1]) and (bin_hi[0] > bin_hi[-1]): bin_lo = DataPHA._hc / pha.bin_hi bin_hi = DataPHA._hc / pha.bin_lo # FIXME: What about filtered option?? bin_lo, bin_hi are # unfiltered?? # Compare disparate grids in energy space self.arfargs = ((self.elo, self.ehi), (bin_lo, bin_hi)) # FIXME: Assumes ARF grid is finest elo, ehi = self.rmf.get_indep() # self.elo, self.ehi are from ARF if len(elo) != len(self.elo) and len(ehi) != len(self.ehi): self.rmfargs = ((elo, ehi), (self.elo, self.ehi)) # 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 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) def teardown(self): self.arf = self._arf # restore originals self.rmf = self._rmf self.filter() RSPModel.teardown(self) def calc(self, p, x, xhi=None, *args, **kwargs): # x could be channels or x, xhi could be energy|wave src = self.model.calc(p, self.xlo, self.xhi) src = self.arf.apply_arf(src, *self.arfargs) src = self.rmf.apply_rmf(src, *self.rmfargs) # Assume any issues with the binning (between AREASCAL # and src) is related to the RMF rather than the ARF. return apply_areascal(src, self.pha, "RMF: {}".format(self.rmf.name))
class ARFModelPHA(ARFModel): """ ARF convolution model with associated PHA """ def __init__(self, arf, pha, model): self.pha = pha self._arf = arf # store a reference to original ARFModel.__init__(self, arf, model) def filter(self): ARFModel.filter(self) pha = self.pha # If PHA is a finer grid than ARF, evaluate model on PHA and # rebin down to the granularity that the ARF expects. if pha.bin_lo is not None and pha.bin_hi is not None: bin_lo, bin_hi = pha.bin_lo, pha.bin_hi # If PHA grid is in angstroms then convert to keV for # consistency if (bin_lo[0] > bin_lo[-1]) and (bin_hi[0] > bin_hi[-1]): bin_lo = DataPHA._hc / pha.bin_hi bin_hi = DataPHA._hc / pha.bin_lo # FIXME: What about filtered option?? bin_lo, bin_hi are # unfiltered?? # Compare disparate grids in energy space self.arfargs = ((self.elo, self.ehi), (bin_lo, bin_hi)) # FIXME: Assumes ARF grid is finest # 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 def startup(self): 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) def teardown(self): self.arf = self._arf # restore original self.filter() ARFModel.teardown(self) def calc(self, p, x, xhi=None, *args, **kwargs): # x could be channels or x, xhi could be energy|wave src = self.model.calc(p, self.xlo, self.xhi) return self.arf.apply_arf(src, *self.arfargs)
class ARFModelPHA(ARFModel): """ARF convolution model with associated PHA data set. Notes ----- Scaling by the AREASCAL setting (scalar or array) is included in this model. It is not yet clear if this is handled correctly. """ def __init__(self, arf, pha, model): self.pha = pha self._arf = arf # store a reference to original ARFModel.__init__(self, arf, model) def filter(self): ARFModel.filter(self) pha = self.pha # If PHA is a finer grid than ARF, evaluate model on PHA and # rebin down to the granularity that the ARF expects. if pha.bin_lo is not None and pha.bin_hi is not None: bin_lo, bin_hi = pha.bin_lo, pha.bin_hi # If PHA grid is in angstroms then convert to keV for # consistency if (bin_lo[0] > bin_lo[-1]) and (bin_hi[0] > bin_hi[-1]): bin_lo = DataPHA._hc / pha.bin_hi bin_hi = DataPHA._hc / pha.bin_lo # FIXME: What about filtered option?? bin_lo, bin_hi are # unfiltered?? # Compare disparate grids in energy space self.arfargs = ((self.elo, self.ehi), (bin_lo, bin_hi)) # FIXME: Assumes ARF grid is finest # 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 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 teardown(self): self.arf = self._arf # restore original self.filter() ARFModel.teardown(self) def calc(self, p, x, xhi=None, *args, **kwargs): # x could be channels or x, xhi could be energy|wave src = self.model.calc(p, self.xlo, self.xhi) src = self.arf.apply_arf(src, *self.arfargs) return apply_areascal(src, self.pha, "ARF: {}".format(self.arf.name))