Exemple #1
0
def make_diffuse_background(bkg_events, event_params, rmf, prng=None):
    from xcs_soxs.instrument import perform_dither

    n_e = bkg_events["energy"].size

    bkg_events['time'] = prng.uniform(size=n_e,
                                      low=0.0,
                                      high=event_params["exposure_time"])

    x_offset, y_offset = perform_dither(bkg_events["time"],
                                        event_params["dither_params"])

    rot_mat = get_rot_mat(event_params["roll_angle"])

    det = np.array([
        bkg_events["detx"] + x_offset - event_params["aimpt_coords"][0],
        bkg_events["dety"] + y_offset - event_params["aimpt_coords"][1]
    ])
    pix = np.dot(rot_mat.T, det)

    bkg_events["xpix"] = pix[0, :] + event_params['pix_center'][0]
    bkg_events["ypix"] = pix[1, :] + event_params['pix_center'][1]

    mylog.info("Scattering energies with RMF %s." %
               os.path.split(rmf.filename)[-1])
    bkg_events = rmf.scatter_energies(bkg_events, prng=prng)

    return bkg_events
Exemple #2
0
def _generate_energies(spec, t_exp, rate, prng, quiet=False):
    cumspec = spec.cumspec
    n_ph = prng.poisson(t_exp * rate)
    if not quiet:
        mylog.info("Creating %d energies from this spectrum." % n_ph)
    randvec = prng.uniform(size=n_ph)
    randvec.sort()
    e = np.interp(randvec, cumspec, spec.ebins.value)
    if not quiet:
        mylog.info("Finished creating energies.")
    return e
Exemple #3
0
def make_foreground(event_params, arf, rmf, prng=None):
    import pyregion._region_filter as rfilter

    prng = parse_prng(prng)

    conv_frgnd_spec = ConvolvedBackgroundSpectrum(hm_astro_bkgnd, arf)

    energy = conv_frgnd_spec.generate_energies(event_params["exposure_time"],
                                               event_params["fov"],
                                               prng=prng,
                                               quiet=True).value

    prng = parse_prng(prng)

    bkg_events = {}

    n_events = energy.size

    nx = event_params["num_pixels"]
    bkg_events["detx"] = prng.uniform(low=-0.5 * nx,
                                      high=0.5 * nx,
                                      size=n_events)
    bkg_events["dety"] = prng.uniform(low=-0.5 * nx,
                                      high=0.5 * nx,
                                      size=n_events)
    bkg_events["energy"] = energy

    if event_params["chips"] is None:
        bkg_events["chip_id"] = np.zeros(n_events, dtype='int')
    else:
        bkg_events["chip_id"] = -np.ones(n_events, dtype='int')
        for i, chip in enumerate(event_params["chips"]):
            thisc = np.ones(n_events, dtype='bool')
            rtype = chip[0]
            args = chip[1:]
            r = getattr(rfilter, rtype)(*args)
            inside = r.inside(bkg_events["detx"], bkg_events["dety"])
            thisc = np.logical_and(thisc, inside)
            bkg_events["chip_id"][thisc] = i

    keep = bkg_events["chip_id"] > -1

    if keep.sum() == 0:
        raise RuntimeError(
            "No astrophysical foreground events were detected!!!")
    else:
        mylog.info("Making %d events from the astrophysical foreground." %
                   keep.sum())

    for key in bkg_events:
        bkg_events[key] = bkg_events[key][keep]

    return make_diffuse_background(bkg_events, event_params, rmf, prng=prng)
Exemple #4
0
    def write_catalog(self, overwrite=False):
        """
        Write the SIMPUT catalog and associated photon lists to disk.

        Parameters
        ----------
        overwrite : boolean, optional
            Whether or not to overwrite an existing file with 
            the same name. Default: False
        """
        for i, phlist in enumerate(self.photon_lists):
            if i == 0:
                append = False
                mylog.info("Writing SIMPUT catalog file %s_simput.fits." %
                           self.name)
            else:
                append = True
            mylog.info("Writing SIMPUT photon list file %s_phlist.fits." %
                       phlist.name)
            phlist.write_photon_list(self.name,
                                     append=append,
                                     overwrite=overwrite)
Exemple #5
0
def make_ptsrc_background(exp_time,
                          fov,
                          sky_center,
                          absorb_model="wabs",
                          nH=0.05,
                          area=40000.0,
                          input_sources=None,
                          output_sources=None,
                          prng=None):
    r"""
    Make a point-source background.

    Parameters
    ----------
    exp_time : float, (value, unit) tuple, or :class:`~astropy.units.Quantity`
        The exposure time of the observation in seconds.
    fov : float, (value, unit) tuple, or :class:`~astropy.units.Quantity`
        The field of view in arcminutes.
    sky_center : array-like
        The center RA, Dec of the field of view in degrees.
    absorb_model : string, optional
        The absorption model to use, "wabs" or "tbabs". Default: "wabs"
    nH : float, (value, unit) tuple, or :class:`~astropy.units.Quantity`, optional
        The hydrogen column in units of 10**22 atoms/cm**2. 
        Default: 0.05
    area : float, (value, unit) tuple, or :class:`~astropy.units.Quantity`, optional
        The effective area in cm**2. It must be large enough 
        so that a sufficiently large sample is drawn for the 
        ARF. Default: 40000.
    input_sources : string, optional
        If set to a filename, input the source positions, fluxes,
        and spectral indices from an ASCII table instead of generating
        them. Default: None
    output_sources : string, optional
        If set to a filename, output the properties of the sources
        within the field of view to a file. Default: None
    prng : :class:`~numpy.random.RandomState` object, integer, or None
        A pseudo-random number generator. Typically will only 
        be specified if you have a reason to generate the same 
        set of random numbers, such as for a test. Default is None, 
        which sets the seed based on the system time. 
    """
    prng = parse_prng(prng)

    exp_time = parse_value(exp_time, "s")
    fov = parse_value(fov, "arcmin")
    if nH is not None:
        nH = parse_value(nH, "1.0e22*cm**-2")
    area = parse_value(area, "cm**2")
    if input_sources is None:
        ra0, dec0, fluxes, ind = generate_sources(exp_time,
                                                  fov,
                                                  sky_center,
                                                  area=area,
                                                  prng=prng)
        num_sources = fluxes.size
    else:
        mylog.info("Reading in point-source properties from %s." %
                   input_sources)
        t = ascii.read(input_sources)
        ra0 = t["RA"].data
        dec0 = t["Dec"].data
        fluxes = t["flux_0.5_2.0_keV"].data
        ind = t["index"].data
        num_sources = fluxes.size

    mylog.debug("Generating spectra from %d sources." % num_sources)

    # If requested, output the source properties to a file
    if output_sources is not None:
        t = Table([ra0, dec0, fluxes, ind],
                  names=('RA', 'Dec', 'flux_0.5_2.0_keV', 'index'))
        t["RA"].unit = "deg"
        t["Dec"].unit = "deg"
        t["flux_0.5_2.0_keV"].unit = "erg/(cm**2*s)"
        t["index"].unit = ""
        t.write(output_sources, format='ascii.ecsv', overwrite=True)

    # Pre-calculate for optimization
    eratio = spec_emax / spec_emin
    oma = 1.0 - ind
    invoma = 1.0 / oma
    invoma[oma == 0.0] = 1.0
    fac1 = spec_emin**oma
    fac2 = spec_emax**oma - fac1

    fluxscale = get_flux_scale(ind, fb_emin, fb_emax, spec_emin, spec_emax)

    # Using the energy flux, determine the photon flux by simple scaling
    ref_ph_flux = fluxes * fluxscale * keV_per_erg
    # Now determine the number of photons we will generate
    n_photons = prng.poisson(ref_ph_flux * exp_time * area)

    all_energies = []
    all_ra = []
    all_dec = []

    for i, nph in enumerate(n_photons):
        if nph > 0:
            # Generate the energies in the source frame
            u = prng.uniform(size=nph)
            if ind[i] == 1.0:
                energies = spec_emin * (eratio**u)
            else:
                energies = fac1[i] + u * fac2[i]
                energies **= invoma[i]
            # Assign positions for this source
            ra = ra0[i] * np.ones(nph)
            dec = dec0[i] * np.ones(nph)

            all_energies.append(energies)
            all_ra.append(ra)
            all_dec.append(dec)

    mylog.debug("Finished generating spectra.")

    all_energies = np.concatenate(all_energies)
    all_ra = np.concatenate(all_ra)
    all_dec = np.concatenate(all_dec)

    all_nph = all_energies.size

    # Remove some of the photons due to Galactic foreground absorption.
    # We will throw a lot of stuff away, but this is more general and still
    # faster.
    if nH is not None:
        if absorb_model == "wabs":
            absorb = get_wabs_absorb(all_energies, nH)
        elif absorb_model == "tbabs":
            absorb = get_tbabs_absorb(all_energies, nH)
        randvec = prng.uniform(size=all_energies.size)
        all_energies = all_energies[randvec < absorb]
        all_ra = all_ra[randvec < absorb]
        all_dec = all_dec[randvec < absorb]
        all_nph = all_energies.size
    mylog.debug("%d photons remain after foreground galactic absorption." %
                all_nph)

    all_flux = np.sum(all_energies) * erg_per_keV / (exp_time * area)

    output_events = {
        "ra": all_ra,
        "dec": all_dec,
        "energy": all_energies,
        "flux": all_flux
    }

    return output_events
Exemple #6
0
def add_background_from_file(events, event_params, bkg_file):
    from xcs_soxs.instrument import perform_dither
    f = pyfits.open(bkg_file)

    hdu = f["EVENTS"]

    dither_params = {}
    if "DITHXAMP" in hdu.header:
        dither_params["x_amp"] = hdu.header["DITHXAMP"]
        dither_params["y_amp"] = hdu.header["DITHYAMP"]
        dither_params["x_period"] = hdu.header["DITHXPER"]
        dither_params["y_period"] = hdu.header["DITHYPER"]
        dither_params["plate_scale"] = hdu.header["TCDLT3"] * 3600.0
        dither_params["dither_on"] = True
    else:
        dither_params["dither_on"] = False

    sexp = event_params["exposure_time"]
    bexp = hdu.header["EXPOSURE"]

    if event_params["exposure_time"] > hdu.header["EXPOSURE"]:
        raise RuntimeError(
            "The background file does not have sufficient exposure! Source "
            "exposure time %g, background exposure time %g." % (sexp, bexp))

    for k1, k2 in key_map.items():
        if event_params[k1] != hdu.header[k2]:
            raise RuntimeError("'%s' keyword does not match! %s vs. %s" %
                               (k1, event_params[k1], hdu.header[k2]))
    rmf1 = os.path.split(event_params["rmf"])[-1]
    rmf2 = hdu.header["RESPFILE"]
    arf1 = os.path.split(event_params["arf"])[-1]
    arf2 = hdu.header["ANCRFILE"]
    if rmf1 != rmf2:
        raise RuntimeError("RMFs do not match! %s vs. %s" % (rmf1, rmf2))
    if arf1 != arf2:
        raise RuntimeError("ARFs do not match! %s vs. %s" % (arf1, arf2))

    idxs = hdu.data["TIME"] < sexp

    mylog.info("Adding %d background events from %s." % (idxs.sum(), bkg_file))

    if event_params["roll_angle"] == hdu.header["ROLL_PNT"]:
        xpix = hdu.data["X"][idxs]
        ypix = hdu.data["Y"][idxs]
    else:
        rot_mat = get_rot_mat(event_params["roll_angle"])
        if dither_params["dither_on"]:
            t = hdu.data["TIME"][idxs]
            x_off, y_off = perform_dither(t, dither_params)
        else:
            x_off = 0.0
            y_off = 0.0
        det = np.array([
            hdu.data["DETX"][idxs] + x_off - event_params["aimpt_coords"][0],
            hdu.data["DETY"][idxs] + y_off - event_params["aimpt_coords"][1]
        ])
        xpix, ypix = np.dot(rot_mat.T, det)

        xpix += hdu.header["TCRPX2"]
        ypix += hdu.header["TCRPX3"]

    all_events = {}
    for key in [
            "detx", "dety", "time", "ccd_id", event_params["channel_type"]
    ]:
        all_events[key] = np.concatenate(
            [events[key], hdu.data[key.upper()][idxs]])
    all_events["xpix"] = np.concatenate([events["xpix"], xpix])
    all_events["ypix"] = np.concatenate([events["ypix"], ypix])
    all_events["energy"] = np.concatenate(
        [events["energy"], hdu.data["ENERGY"][idxs] / 1000.0])

    f.close()

    return all_events
Exemple #7
0
def write_event_file(events, parameters, filename, overwrite=False):
    from astropy.time import Time, TimeDelta
    mylog.info("Writing events to file %s." % filename)

    t_begin = Time.now()
    dt = TimeDelta(parameters["exposure_time"], format='sec')
    t_end = t_begin + dt

    col_x = pyfits.Column(name='X',
                          format='D',
                          unit='pixel',
                          array=events["xpix"])
    col_y = pyfits.Column(name='Y',
                          format='D',
                          unit='pixel',
                          array=events["ypix"])
    col_e = pyfits.Column(name='ENERGY',
                          format='E',
                          unit='eV',
                          array=events["energy"] * 1000.)
    col_dx = pyfits.Column(name='DETX',
                           format='D',
                           unit='pixel',
                           array=events["detx"])
    col_dy = pyfits.Column(name='DETY',
                           format='D',
                           unit='pixel',
                           array=events["dety"])
    col_id = pyfits.Column(name='CCD_ID',
                           format='D',
                           unit='pixel',
                           array=events["ccd_id"])

    chantype = parameters["channel_type"]
    if chantype == "PHA":
        cunit = "adu"
    elif chantype == "PI":
        cunit = "Chan"
    col_ch = pyfits.Column(name=chantype.upper(),
                           format='1J',
                           unit=cunit,
                           array=events[chantype])

    col_t = pyfits.Column(name="TIME",
                          format='1D',
                          unit='s',
                          array=events['time'])

    cols = [col_e, col_x, col_y, col_ch, col_t, col_dx, col_dy, col_id]

    coldefs = pyfits.ColDefs(cols)
    tbhdu = pyfits.BinTableHDU.from_columns(coldefs)
    tbhdu.name = "EVENTS"

    tbhdu.header["MTYPE1"] = "sky"
    tbhdu.header["MFORM1"] = "x,y"
    tbhdu.header["MTYPE2"] = "EQPOS"
    tbhdu.header["MFORM2"] = "RA,DEC"
    tbhdu.header["TCTYP2"] = "RA---TAN"
    tbhdu.header["TCTYP3"] = "DEC--TAN"
    tbhdu.header["TCRVL2"] = parameters["sky_center"][0]
    tbhdu.header["TCRVL3"] = parameters["sky_center"][1]
    tbhdu.header["TCDLT2"] = -parameters["plate_scale"]
    tbhdu.header["TCDLT3"] = parameters["plate_scale"]
    tbhdu.header["TCRPX2"] = parameters["pix_center"][0]
    tbhdu.header["TCRPX3"] = parameters["pix_center"][1]
    tbhdu.header["TCUNI2"] = "deg"
    tbhdu.header["TCUNI3"] = "deg"
    tbhdu.header["TLMIN2"] = 0.5
    tbhdu.header["TLMIN3"] = 0.5
    tbhdu.header["TLMAX2"] = 2.0 * parameters["num_pixels"] + 0.5
    tbhdu.header["TLMAX3"] = 2.0 * parameters["num_pixels"] + 0.5
    tbhdu.header["TLMIN4"] = parameters["chan_lim"][0]
    tbhdu.header["TLMAX4"] = parameters["chan_lim"][1]
    tbhdu.header["TLMIN6"] = -0.5 * parameters["num_pixels"]
    tbhdu.header["TLMAX6"] = 0.5 * parameters["num_pixels"]
    tbhdu.header["TLMIN7"] = -0.5 * parameters["num_pixels"]
    tbhdu.header["TLMAX7"] = 0.5 * parameters["num_pixels"]
    tbhdu.header["EXPOSURE"] = parameters["exposure_time"]
    tbhdu.header["TSTART"] = 0.0
    tbhdu.header["TSTOP"] = parameters["exposure_time"]
    tbhdu.header["HDUVERS"] = "1.1.0"
    tbhdu.header["RADECSYS"] = "FK5"
    tbhdu.header["EQUINOX"] = 2000.0
    tbhdu.header["HDUCLASS"] = "OGIP"
    tbhdu.header["HDUCLAS1"] = "EVENTS"
    tbhdu.header["HDUCLAS2"] = "ACCEPTED"
    tbhdu.header["DATE"] = t_begin.tt.isot
    tbhdu.header["DATE-OBS"] = t_begin.tt.isot
    tbhdu.header["DATE-END"] = t_end.tt.isot
    tbhdu.header["RESPFILE"] = os.path.split(parameters["rmf"])[-1]
    tbhdu.header["PHA_BINS"] = parameters["nchan"]
    tbhdu.header["ANCRFILE"] = os.path.split(parameters["arf"])[-1]
    tbhdu.header["CHANTYPE"] = parameters["channel_type"]
    tbhdu.header["MISSION"] = parameters["mission"]
    tbhdu.header["TELESCOP"] = parameters["telescope"]
    tbhdu.header["INSTRUME"] = parameters["instrument"]
    tbhdu.header["RA_PNT"] = parameters["sky_center"][0]
    tbhdu.header["DEC_PNT"] = parameters["sky_center"][1]
    tbhdu.header["ROLL_PNT"] = parameters["roll_angle"]
    tbhdu.header["AIMPT_X"] = parameters["aimpt_coords"][0]
    tbhdu.header["AIMPT_Y"] = parameters["aimpt_coords"][1]
    if parameters["dither_params"]["dither_on"]:
        tbhdu.header["DITHXAMP"] = parameters["dither_params"]["x_amp"]
        tbhdu.header["DITHYAMP"] = parameters["dither_params"]["y_amp"]
        tbhdu.header["DITHXPER"] = parameters["dither_params"]["x_period"]
        tbhdu.header["DITHYPER"] = parameters["dither_params"]["y_period"]

    start = pyfits.Column(name='START',
                          format='1D',
                          unit='s',
                          array=np.array([0.0]))
    stop = pyfits.Column(name='STOP',
                         format='1D',
                         unit='s',
                         array=np.array([parameters["exposure_time"]]))

    tbhdu_gti = pyfits.BinTableHDU.from_columns([start, stop])
    tbhdu_gti.name = "STDGTI"
    tbhdu_gti.header["TSTART"] = 0.0
    tbhdu_gti.header["TSTOP"] = parameters["exposure_time"]
    tbhdu_gti.header["HDUCLASS"] = "OGIP"
    tbhdu_gti.header["HDUCLAS1"] = "GTI"
    tbhdu_gti.header["HDUCLAS2"] = "STANDARD"
    tbhdu_gti.header["RADECSYS"] = "FK5"
    tbhdu_gti.header["EQUINOX"] = 2000.0
    tbhdu_gti.header["DATE"] = t_begin.tt.isot
    tbhdu_gti.header["DATE-OBS"] = t_begin.tt.isot
    tbhdu_gti.header["DATE-END"] = t_end.tt.isot

    hdulist = [pyfits.PrimaryHDU(), tbhdu, tbhdu_gti]

    pyfits.HDUList(hdulist).writeto(filename, overwrite=overwrite)
Exemple #8
0
 def __init__(self,
              emin,
              emax,
              nbins,
              var_elem=None,
              apec_root=None,
              apec_vers=None,
              broadening=True,
              nolines=False,
              abund_table=None,
              nei=False):
     if apec_vers is None:
         filedir = os.path.join(os.path.dirname(__file__), 'files')
         cfile = glob.glob("%s/apec_*_coco.fits" % filedir)[0]
         apec_vers = cfile.split("/")[-1].split("_")[1][1:]
     mylog.info("Using APEC version %s." % apec_vers)
     if nei and apec_root is None:
         raise RuntimeError(
             "The NEI APEC tables are not supplied with "
             "SOXS! Download them from http://www.atomdb.org "
             "and set 'apec_root' to their location.")
     if nei and var_elem is None:
         raise RuntimeError(
             "For NEI spectra, you must specify which elements "
             "you want to vary using the 'var_elem' argument!")
     self.nei = nei
     emin = parse_value(emin, "keV")
     emax = parse_value(emax, 'keV')
     self.emin = emin
     self.emax = emax
     self.nbins = nbins
     self.ebins = np.linspace(self.emin, self.emax, nbins + 1)
     self.de = np.diff(self.ebins)
     self.emid = 0.5 * (self.ebins[1:] + self.ebins[:-1])
     if apec_root is None:
         apec_root = soxs_files_path
     if nei:
         neistr = "_nei"
         ftype = "comp"
     else:
         neistr = ""
         ftype = "coco"
     self.cocofile = os.path.join(
         apec_root, "apec_v%s%s_%s.fits" % (apec_vers, neistr, ftype))
     self.linefile = os.path.join(
         apec_root, "apec_v%s%s_line.fits" % (apec_vers, neistr))
     if not os.path.exists(self.cocofile) or not os.path.exists(
             self.linefile):
         raise IOError("Cannot find the APEC files!\n %s\n, %s" %
                       (self.cocofile, self.linefile))
     mylog.info("Using %s for generating spectral lines." %
                os.path.split(self.linefile)[-1])
     mylog.info("Using %s for generating the continuum." %
                os.path.split(self.cocofile)[-1])
     self.nolines = nolines
     self.wvbins = hc / self.ebins[::-1]
     self.broadening = broadening
     try:
         self.line_handle = pyfits.open(self.linefile)
     except IOError:
         raise IOError("Line file %s does not exist" % self.linefile)
     try:
         self.coco_handle = pyfits.open(self.cocofile)
     except IOError:
         raise IOError("Continuum file %s does not exist" % self.cocofile)
     self.Tvals = self.line_handle[1].data.field("kT")
     self.nT = len(self.Tvals)
     self.dTvals = np.diff(self.Tvals)
     self.minlam = self.wvbins.min()
     self.maxlam = self.wvbins.max()
     self.var_elem_names = []
     self.var_ion_names = []
     if var_elem is None:
         self.var_elem = np.empty((0, 1), dtype='int')
     else:
         self.var_elem = []
         if len(var_elem) != len(set(var_elem)):
             raise RuntimeError(
                 "Duplicates were found in the \"var_elem\" list! %s" %
                 var_elem)
         for elem in var_elem:
             if "^" in elem:
                 if not self.nei:
                     raise RuntimeError(
                         "Cannot use different ionization states with a "
                         "CIE plasma!")
                 el = elem.split("^")
                 e = el[0]
                 ion = int(el[1])
             else:
                 if self.nei:
                     raise RuntimeError(
                         "Variable elements must include the ionization "
                         "state for NEI plasmas!")
                 e = elem
                 ion = 0
             self.var_elem.append([elem_names.index(e), ion])
         self.var_elem.sort(key=lambda x: (x[0], x[1]))
         self.var_elem = np.array(self.var_elem, dtype='int')
         self.var_elem_names = [elem_names[e[0]] for e in self.var_elem]
         self.var_ion_names = [
             "%s^%d" % (elem_names[e[0]], e[1]) for e in self.var_elem
         ]
     self.num_var_elem = len(self.var_elem)
     if self.nei:
         self.cosmic_elem = [
             elem for elem in [1, 2] if elem not in self.var_elem[:, 0]
         ]
         self.metal_elem = []
     else:
         self.cosmic_elem = [
             elem for elem in cosmic_elem if elem not in self.var_elem[:, 0]
         ]
         self.metal_elem = [
             elem for elem in metal_elem if elem not in self.var_elem[:, 0]
         ]
     if abund_table is None:
         abund_table = soxs_cfg.get("xcs_soxs", "abund_table")
     if not isinstance(abund_table, string_types):
         if len(abund_table) != 30:
             raise RuntimeError("User-supplied abundance tables "
                                "must be 30 elements long!")
         self.atable = np.concatenate([[0.0], np.array(abund_table)])
     else:
         self.atable = abund_tables[abund_table].copy()
     self._atable = self.atable.copy()
     self._atable[1:] /= abund_tables["angr"][1:]
Exemple #9
0
def make_instrument_background(bkgnd_name, event_params, rmf, prng=None):
    import pyregion._region_filter as rfilter

    prng = parse_prng(prng)

    if event_params["chips"] is None:
        bkgnd_spec = [instrument_backgrounds[bkgnd_name]]
    else:
        if isinstance(bkgnd_name, string_types):
            nchips = len(event_params["chips"])
            bkgnd_names = [bkgnd_name] * nchips
        else:
            bkgnd_names = bkgnd_name
        bkgnd_spec = []
        for name in bkgnd_names:
            spec = instrument_backgrounds[name].new_spec_from_band(
                rmf.elo[0], rmf.ehi[-1])
            bkgnd_spec.append(spec)

    bkg_events = {}

    nx = event_params["num_pixels"]

    if event_params["chips"] is None:
        bkg_events["energy"] = bkgnd_spec[0].generate_energies(
            event_params["exposure_time"],
            event_params["fov"],
            prng=prng,
            quiet=True).value
        n_events = bkg_events["energy"].size
        bkg_events["chip_id"] = np.zeros(n_events, dtype='int')
        bkg_events["detx"] = prng.uniform(low=-0.5 * nx,
                                          high=0.5 * nx,
                                          size=n_events)
        bkg_events["dety"] = prng.uniform(low=-0.5 * nx,
                                          high=0.5 * nx,
                                          size=n_events)
    else:
        bkg_events["energy"] = []
        bkg_events["detx"] = []
        bkg_events["dety"] = []
        bkg_events["chip_id"] = []
        for i, chip in enumerate(event_params["chips"]):
            e = bkgnd_spec[i].generate_energies(event_params["exposure_time"],
                                                event_params["fov"],
                                                prng=prng,
                                                quiet=True).value
            n_events = e.size
            detx = prng.uniform(low=-0.5 * nx, high=0.5 * nx, size=n_events)
            dety = prng.uniform(low=-0.5 * nx, high=0.5 * nx, size=n_events)
            thisc = np.ones(n_events, dtype='bool')
            rtype = chip[0]
            args = chip[1:]
            r = getattr(rfilter, rtype)(*args)
            inside = r.inside(detx, dety)
            thisc = np.logical_and(thisc, inside)
            bkg_events["energy"].append(e[thisc])
            bkg_events["detx"].append(detx[thisc])
            bkg_events["dety"].append(dety[thisc])
            bkg_events["chip_id"].append(i * np.ones(thisc.sum()))
        for key in bkg_events:
            bkg_events[key] = np.concatenate(bkg_events[key])

    if bkg_events["energy"].size == 0:
        raise RuntimeError(
            "No instrumental background events were detected!!!")
    else:
        mylog.info("Making %d events from the instrumental background." %
                   bkg_events["energy"].size)

    return make_diffuse_background(bkg_events, event_params, rmf, prng=prng)