Example #1
0
    def make_rsp(self, wave):
        '''Interpolate the COS LSF for all wavelengths
        
        Parameters
        ----------
        wave : ndarray
            wavelength (assumed to be in Ang)
        '''
        # test if delta_lambda in wavelengths is as expected for this grating 
        for disp in self.disp:
            if max(abs(np.diff(wave) - disp)) < (disp / 100.):
                break
        else:
            print('LSF convolution requires x to be binned in pixels.')
            print('delta(x) differs from value given in COS IHB.')
        # first line of table is header values
        wavelen = self.lsf_tab[0, 1:]
        if ((min(wave) < 0.9 * min(wavelen)) or (max(wave) > 1.1 * max(wavelen))):
            raise ValueError('COS LSF in this model is only tabulated {0:4.0f} to  {1:0.0f}'.format(min(wavelen), max(wavelen)))

        # rest of table is data values
        # 1. Interpolation: Get lsf_tab on pixel grid
        # interpolate to full pixels, if given in fractional pixels
        lsftab = np.zeros((self.m, len(wavelen)))
        for i in range(len(wavelen)):
            lsftab[:,i] = interpolate(np.arange(-(self.m/2), self.m/2+0.1, dtype = np.int), self.shift, self.lsf_tab[1:,i+1])

        # 2. Interpolation: make lsf for each lambda
        n = len(wave)
        self._rsp = np.zeros((n, self.m))
        for i in np.arange(-(self.m/2), self.m/2+0.1, dtype = np.int):
            pix = interpolate(wave, wavelen, lsftab[self.m/2+i,:])
            self._rsp[:, self.m/2 + i] = pix
        
        if np.isfinite(self._rsp).sum() != self._rsp.size:
            raise ValueError('Response matrix holds nan or inf values!')
        # 3. Reformat: Bring matix in same shape as Sherpa would do for RMFs
        # I use the same naming convention here as in Sherpa `DataRMF` objects
        self._grp = np.ones(n)
        self._fch = np.clip(np.arange(1,n+1)-(self.m/2),1, np.inf)
        
        # set unused matix elements to nan - that allows a very simple
        # way to flatten the array
        for i in range(self.m/2):
            self._rsp[i,0:self.m/2-i] = np.nan
            self._rsp[-(i+1),-(self.m/2)+i:self.m] = np.nan
        self._nch = np.sum(np.isfinite(self._rsp),axis = 1)
        self._rsp = self._rsp[np.isfinite(self._rsp)].flatten()

        self.cache_x = wave
Example #2
0
    def _evaluate(self, data_space, pars, modelfunc, **kwargs):
        # Evaluate the model on the user-defined grid and then interpolate/rebin
        # onto the desired grid. This is based on sherpa.models.TableModel
        # but is simplified as we do not provide a fold method.
        kwargs[
            'integrate'] = self.integrate  # Not really sure I need this, but let's be safe

        evaluation_space = self.evaluation_space

        if not data_space in evaluation_space:
            warnings.warn(
                "evaluation space does not contain the requested space. Sherpa will join the two spaces."
            )
            evaluation_space = evaluation_space.join(data_space)

        # I don't like the string of IFs, but it might be more expressive this way in this specific case.
        # If the data space is integrated and the model's integrate flag is set to True, then evaluate the model
        # on the evaluation space and then rebin onto the data space.
        # If the data space is integrated but the model's integrate flas is set to False, then evaluate the model
        # on the midpoint grid (note: we are passing the midpoint grid to force Sherpa to treat this as not integrated.
        # If we passed two arrays we'd fall in a edge case and Sherpa would evaluate the model at the edge of the bin.
        # If the data space is not integrated then simply evaluate the model on the grid and then interpolate
        # to match the data space.
        if data_space.is_integrated:
            if self.integrate:
                # This should be the most common case
                y = modelfunc(pars, evaluation_space.grid[0],
                              evaluation_space.grid[1], **kwargs)
                return rebin(y, evaluation_space.grid[0],
                             evaluation_space.grid[1], data_space.grid[0],
                             data_space.grid[1])
            else:
                # The integrate flag is set to false, so just evaluate the model
                # and then interpolate using the grids midpoints.
                y = modelfunc(pars, evaluation_space.midpoint_grid, **kwargs)
                return interpolate(data_space.midpoint_grid,
                                   evaluation_space.midpoint_grid,
                                   y,
                                   function=self.method)
        else:
            y = modelfunc(pars, evaluation_space.grid[0], **kwargs)
            return interpolate(data_space.midpoint_grid,
                               evaluation_space.midpoint_grid,
                               y,
                               function=self.method)
Example #3
0
    def calc(self, pl, pr, rhs, *args, **kwargs):

        args = list(args)    # tuples are immutable!
        # add m/2 elements to the wavelength array on each side
        # to avoid edge effects when folding with the LSF
        args[0] = interpolate(np.arange(-(self.m/2), len(args[0]) + self.m/2-0.1), np.arange(len(args[0])), args[0])

        flux = rhs(pr, *args, **kwargs)

        return self.convolve(args[0], flux)[self.m/2 : -(self.m/2)]
Example #4
0
    def _evaluate(self, data_space, pars, modelfunc, **kwargs):
        # Evaluate the model on the user-defined grid and then interpolate/rebin
        # onto the desired grid. This is based on sherpa.models.TableModel
        # but is simplified as we do not provide a fold method.
        kwargs['integrate'] = self.integrate  # Not really sure I need this, but let's be safe

        evaluation_space = self.evaluation_space

        if not data_space in evaluation_space:
            warnings.warn("evaluation space does not contain the requested space. Sherpa will join the two spaces.")
            evaluation_space = evaluation_space.join(data_space)

        # I don't like the string of IFs, but it might be more expressive this way in this specific case.
        # If the data space is integrated and the model's integrate flag is set to True, then evaluate the model
        # on the evaluation space and then rebin onto the data space.
        # If the data space is integrated but the model's integrate flas is set to False, then evaluate the model
        # on the midpoint grid (note: we are passing the midpoint grid to force Sherpa to treat this as not integrated.
        # If we passed two arrays we'd fall in a edge case and Sherpa would evaluate the model at the edge of the bin.
        # If the data space is not integrated then simply evaluate the model on the grid and then interpolate
        # to match the data space.
        if data_space.is_integrated:
            if self.integrate:
                # This should be the most common case
                y = modelfunc(pars, evaluation_space.grid[0], evaluation_space.grid[1],
                              **kwargs)
                return rebin(y,
                             evaluation_space.grid[0], evaluation_space.grid[1],
                             data_space.grid[0], data_space.grid[1])
            else:
                # The integrate flag is set to false, so just evaluate the model
                # and then interpolate using the grids midpoints.
                y = modelfunc(pars, evaluation_space.midpoint_grid, **kwargs)
                return interpolate(data_space.midpoint_grid, evaluation_space.midpoint_grid, y,
                                   function=self.method)
        else:
            y = modelfunc(pars, evaluation_space.grid, **kwargs)
            return interpolate(data_space.midpoint_grid, evaluation_space.midpoint_grid, y,
                               function=self.method)
Example #5
0
    def _estimate_expmap(self, *args):
        """Estimate the exposure map given an ARF.

        Although the arguments are listed with parameter names
        below, the function **does not** accept named arguments.
        It uses positional arguments and type checks to determine
        the parameters.

        Parameters
        ----------
        crate
            A TABLECrate, containing ``energ_lo``, ``energ_hi``,
            and ``specresp`` columns.
        filename : string
            The name of an ARF file
        xlo, xhi, y : arrays of numbers
            The arrays taken to be the ``energ_lo``, ``energ_hi``, and
            ``specresp`` columns

        Return
        ------
        expmap : number
            An estimate of the exposure map at the position
            of the source, and has units of cm^2 count / self.fluxtype

        Notes
        -----
        The ARF is linearly interpolated onto the energy grid
        of the dataset and the weighted sum calculated. The
        ARF is assumed to have units of cm^2 count / photon, and
        be defined on a grid given in keV.

        The ``estimate_instmap()`` method should be called in
        preference to this routine.
        """

        nargs = len(args)
        if nargs == 3:
            elo = args[0]
            ehi = args[1]
            specresp = args[2]

            if len(elo) == 1 or len(ehi) == 1 or len(specresp) == 1:
                emsg = "Expected three arrays of the same " + \
                    "length, with more than one element in"
                raise TypeError(emsg)
            if len(elo) != len(ehi) or len(elo) != len(specresp):
                emsg = "Expected three arrays of the same length"
                raise ValueError(emsg)

        elif nargs != 1:
            emsg = "_estimate_expmap() takes 2 or 4 arguments " + \
                "({} given)".format(nargs + 1)
            raise TypeError(emsg)

        else:
            if isinstance(args[0], pycrates.TABLECrate):
                cr = args[0]
            else:
                cr = pycrates.TABLECrate(args[0], mode="r")

            try:
                elo = cr.get_column("ENERG_LO").values.copy()
                ehi = cr.get_column("ENERG_HI").values.copy()
                specresp = cr.get_column("SPECRESP").values.copy()
            except ValueError as e:
                fname = cr.get_filename()
                raise ValueError("Crate {} - {}".format(fname, e))

        # Interpolate using the mid-point of the ARF
        # onto the mid-point of the grid if necessary.
        #
        emid = 0.5 * (elo + ehi)
        if emid.shape == self.xmid.shape and \
                np.all(emid == self.xmid):
            arf = specresp
        else:
            arf = su.interpolate(self.xmid, emid, specresp)
            arf = np.asarray(arf, dtype=self.weight.dtype)
            arf[arf < 0] = 0.0

        return np.sum(self.weight * arf)