Example #1
0
    def fit(self, conf = False):


        ui.ignore(None, None)
        ui.notice(self.start, self.stop)
        self.set_source()
        ui.fit(1)
        if conf:
            ui.conf()
        res = ui.get_fit_results()

        for line in (self.H2lines + self.nonH2lines):
            sourcename = line['source'].split('.')[1]
            print sourcename
            for p in ['pos', 'fwhm', 'ampl']:
                n = '{0}.{1}'.format(sourcename, p)
                _place_val(line, p, ui.get_par(n).val)

        self.const = ui.get_par('c1.c0').val
        self.redchi2 = res.rstat


        if conf:
            res = ui.get_conf_results()
            for line in (self.H2lines + self.nonH2lines):
                sourcename = line['source'].split('.')[1]
                for p in ['pos', 'fwhm', 'ampl']:
                    n = '{0}.{1}'.format(sourcename, p)
                    parmin, parmax = _parminmax(res, n)
                    line[p+'_max'] = parmax
                    line[p+'_min'] = parmin
            # deal with error on const
            parmin, parmax = _parminmax(res, 'c1.c0')
            self.const_min = parmin
            self.const_max = parmax
Example #2
0
def test_background():

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    kT_sim = 1.0
    Z_sim = 0.0
    norm_sim = 4.0e-2
    nH_sim = 0.04
    redshift = 0.01

    exp_time = (200., "ks")
    area = (1000., "cm**2")

    wcs = create_dummy_wcs()

    abs_model = WabsModel(nH_sim)

    events = EventList.create_empty_list(exp_time, area, wcs)

    spec_model = TableApecModel(0.05, 12.0, 5000, thermal_broad=False)
    spec = spec_model.return_spectrum(kT_sim, Z_sim, redshift, norm_sim)

    new_events = events.add_background(spec_model.ebins, spec, prng=prng,
                                       absorb_model=abs_model)

    new_events = ACIS_I(new_events, rebin=False, convolve_psf=False, prng=prng)

    new_events.write_spectrum("background_evt.pi", clobber=True)

    os.system("cp %s ." % new_events.parameters["ARF"])
    os.system("cp %s ." % new_events.parameters["RMF"])

    load_user_model(mymodel, "wapec")
    add_user_pars("wapec", ["nH", "kT", "metallicity", "redshift", "norm"],
                  [0.01, 4.0, 0.2, redshift, norm_sim*0.8],
                  parmins=[0.0, 0.1, 0.0, -20.0, 0.0],
                  parmaxs=[10.0, 20.0, 10.0, 20.0, 1.0e9],
                  parfrozen=[False, False, False, True, False])

    load_pha("background_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.5, 8.0:")
    set_model("wapec")
    fit()
    set_covar_opt("sigma", 1.6)
    covar()
    res = get_covar_results()

    assert np.abs(res.parvals[0]-nH_sim) < res.parmaxes[0]
    assert np.abs(res.parvals[1]-kT_sim) < res.parmaxes[1]
    assert np.abs(res.parvals[2]-Z_sim) < res.parmaxes[2]
    assert np.abs(res.parvals[3]-norm_sim) < res.parmaxes[3]

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #3
0
def test_background():

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    kT_sim = 1.0
    Z_sim = 0.0
    norm_sim = 4.0e-2
    nH_sim = 0.04
    redshift = 0.01

    exp_time = (200., "ks")
    area = (1000., "cm**2")
    fov = (10.0, "arcmin")

    prng = 24

    agen = ApecGenerator(0.05, 12.0, 5000, broadening=False)
    spec = agen.get_spectrum(kT_sim, Z_sim, redshift, norm_sim)
    spec.apply_foreground_absorption(norm_sim)

    events = make_background(area, exp_time, fov, (30.0, 45.0), spec, prng=prng)
    events.write_simput_file("bkgnd", overwrite=True)

    instrument_simulator("bkgnd_simput.fits", "bkgnd_evt.fits", 
                         exp_time, "sq_acisi_cy19", [30.0, 45.0],
                         overwrite=True, foreground=False, ptsrc_bkgnd=False,
                         instr_bkgnd=False,
                         prng=prng)

    write_spectrum("bkgnd_evt.fits", "background_evt.pi", overwrite=True)

    os.system("cp %s %s ." % (arf.filename, rmf.filename))

    load_user_model(mymodel, "wapec")
    add_user_pars("wapec", ["nH", "kT", "metallicity", "redshift", "norm"],
                  [0.01, 4.0, 0.2, redshift, norm_sim*0.8],
                  parmins=[0.0, 0.1, 0.0, -20.0, 0.0],
                  parmaxs=[10.0, 20.0, 10.0, 20.0, 1.0e9],
                  parfrozen=[False, False, False, True, False])

    load_pha("background_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.5, 8.0:")
    set_model("wapec")
    fit()
    res = get_fit_results()

    assert np.abs(res.parvals[0]-nH_sim)/nH_sim < 0.1
    assert np.abs(res.parvals[1]-kT_sim)/kT_sim < 0.05
    assert np.abs(res.parvals[2]-Z_sim) < 0.05
    assert np.abs(res.parvals[3]-norm_sim)/norm_sim < 0.05

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #4
0
def test_point_source():

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    nH_sim = 0.02
    norm_sim = 1.0e-4
    alpha_sim = 0.95
    redshift = 0.02

    exp_time = (100., "ks")
    area = (3000., "cm**2")

    spec = Spectrum.from_powerlaw(alpha_sim, redshift, norm_sim, 
                                  emin=0.1, emax=11.5, nbins=2000)

    spec.apply_foreground_absorption(nH_sim, model="tbabs")

    positions = [(30.01, 45.0)]

    events = make_point_sources(area, exp_time, positions, (30.0, 45.0),
                                spec, prng=prng)

    events.write_simput_file("ptsrc", overwrite=True)

    instrument_simulator("ptsrc_simput.fits", "ptsrc_evt.fits",
                         exp_time, "sq_aciss_cy20", [30.0, 45.0],
                         overwrite=True, foreground=False, ptsrc_bkgnd=False,
                         instr_bkgnd=False,
                         prng=prng)

    write_spectrum("ptsrc_evt.fits", "point_source_evt.pi", overwrite=True)

    os.system("cp %s %s ." % (arf.filename, rmf.filename))

    load_user_model(mymodel, "tplaw")
    add_user_pars("tplaw", ["nH", "norm", "redshift", "alpha"],
                  [0.02, norm_sim*0.8, redshift, 0.9],
                  parmins=[0.0, 0.0, 0.0, 0.1],
                  parmaxs=[10.0, 1.0e9, 10.0, 10.0],
                  parfrozen=[True, False, True, False])

    load_pha("point_source_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.4, 9.0:")
    set_model("tplaw")
    fit()
    res = get_fit_results()

    assert np.abs(res.parvals[0]-norm_sim)/norm_sim < 0.05
    assert np.abs(res.parvals[1]-alpha_sim)/alpha_sim < 0.05

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #5
0
def test_point_source():

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    nH_sim = 0.02
    norm_sim = 1.0e-4
    alpha_sim = 0.95
    redshift = 0.02

    exp_time = (100., "ks")
    area = (3000., "cm**2")

    spec = Spectrum.from_powerlaw(alpha_sim, redshift, norm_sim, 
                                  emin=0.1, emax=11.5, nbins=2000)

    spec.apply_foreground_absorption(nH_sim, model="tbabs")

    positions = [(30.01, 45.0)]

    events = make_point_sources(area, exp_time, positions, (30.0, 45.0),
                                spec, prng=prng)

    events.write_simput_file("ptsrc", overwrite=True)

    instrument_simulator("ptsrc_simput.fits", "ptsrc_evt.fits",
                         exp_time, "sq_aciss_cy19", [30.0, 45.0],
                         overwrite=True, foreground=False, ptsrc_bkgnd=False,
                         instr_bkgnd=False,
                         prng=prng)

    write_spectrum("ptsrc_evt.fits", "point_source_evt.pi", overwrite=True)

    os.system("cp %s %s ." % (arf.filename, rmf.filename))

    load_user_model(mymodel, "tplaw")
    add_user_pars("tplaw", ["nH", "norm", "redshift", "alpha"],
                  [0.02, norm_sim*0.8, redshift, 0.9],
                  parmins=[0.0, 0.0, 0.0, 0.1],
                  parmaxs=[10.0, 1.0e9, 10.0, 10.0],
                  parfrozen=[True, False, True, False])

    load_pha("point_source_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.4, 9.0:")
    set_model("tplaw")
    fit()
    res = get_fit_results()

    assert np.abs(res.parvals[0]-norm_sim)/norm_sim < 0.05
    assert np.abs(res.parvals[1]-alpha_sim)/alpha_sim < 0.05

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #6
0
def test_can_use_pspc_data(make_data_path):
    """A basic check that we can read in and use the ROSAT PSPC data.

    Unlike the previous tests, that directly access the io module,
    this uses the ui interface.
    """

    if not six.PY2 and (backend == "crates"):
        pytest.skip('Python3 and Crates: known to fail')

    # The PSPC PHA file does not have the ANCRFILE/RESPFILE keywords
    # set up, so the responses has to be manually added.
    #
    ui.load_pha(make_data_path(PHAFILE), use_errors=True)
    assert ui.get_analysis() == 'channel'

    ui.load_rmf(make_data_path(RMFFILE))
    assert ui.get_analysis() == 'energy'

    ui.set_source(ui.powlaw1d.pl)
    ui.set_par('pl.gamma', 1.7)
    ui.set_par('pl.ampl', 2e-6)

    s = ui.get_stat_info()[0]
    assert s.numpoints == 63
    assert s.dof == 61

    # Value obtained from XSPEC 12.9.1p; Sherpa returns
    # sexpected = 973.2270845920297
    sexpected = 973.23
    assert_allclose(s.statval, sexpected, rtol=0, atol=0.005)

    # apply an energy filter to remove the "bogus" points
    ui.ignore(None, 0.05)

    s = ui.get_stat_info()[0]
    assert s.numpoints == 62
    assert s.dof == 60
    assert_allclose(s.statval, sexpected, rtol=0, atol=0.005)

    ui.ignore(2.01, None)

    s = ui.get_stat_info()[0]
    assert s.numpoints == 7
    assert s.dof == 5

    assert_allclose(s.statval, sexpected, rtol=0, atol=0.005)
def test_save_filter_ignored(bid):
    """Does save_filter error out if everything is masked?

    We should be able to write out the filter in this case,
    as it's easy (all False).
    """

    ui.load_arrays(1, [1, 2, 3], [5, 4, 3], ui.DataPHA)
    bkg = ui.DataPHA('bkg', np.asarray([1, 2, 3]), [1, 1, 0])
    ui.set_bkg(bkg)

    ui.ignore(None, None)

    with pytest.raises(DataErr) as exc:
        ui.save_filter("temp-file-that-should-not-be-created", bkg_id=bid)

    assert str(exc.value) == "mask excludes all data"
def test_set_filter_mismatch_with_filter(f, bid):
    """Does set_filter error when there's a mis-match after a filter?

    test_set_filter_mismatch checks when .mask is a scalar,
    so now check when it's a NumPy array.
    """

    ui.load_arrays(1, [1, 2, 3], [5, 4, 3], ui.DataPHA)
    bkg = ui.DataPHA('bkg', np.asarray([1, 2, 3]), [1, 1, 0])
    ui.set_bkg(bkg)

    ui.ignore(3, None)  # set the .mask attribute to an array

    with pytest.raises(DataErr) as exc:
        ui.set_filter(f, bkg_id=bid)

    assert str(exc.value) == 'size mismatch between 3 and 2'
def test_can_use_pspc_data(make_data_path):
    """A basic check that we can read in and use the ROSAT PSPC data.

    Unlike the previous tests, that directly access the io module,
    this uses the ui interface.
    """

    # The PSPC PHA file does not have the ANCRFILE/RESPFILE keywords
    # set up, so the responses has to be manually added.
    #
    ui.load_pha(make_data_path(PHAFILE), use_errors=True)
    assert ui.get_analysis() == 'channel'

    ui.load_rmf(make_data_path(RMFFILE))
    assert ui.get_analysis() == 'energy'

    ui.set_source(ui.powlaw1d.pl)
    ui.set_par('pl.gamma', 1.7)
    ui.set_par('pl.ampl', 2e-6)

    s = ui.get_stat_info()[0]
    assert s.numpoints == 63
    assert s.dof == 61

    # Value obtained from XSPEC 12.9.1p; Sherpa returns
    # sexpected = 973.2270845920297
    sexpected = 973.23
    assert_allclose(s.statval, sexpected, rtol=0, atol=0.005)

    # apply an energy filter to remove the "bogus" points
    ui.ignore(None, 0.05)

    s = ui.get_stat_info()[0]
    assert s.numpoints == 62
    assert s.dof == 60
    assert_allclose(s.statval, sexpected, rtol=0, atol=0.005)

    ui.ignore(2.01, None)

    s = ui.get_stat_info()[0]
    assert s.numpoints == 7
    assert s.dof == 5

    assert_allclose(s.statval, sexpected, rtol=0, atol=0.005)
def test_filter_bad_ungrouped(make_data_path, clean_astro_ui):
    """Check behavior when the data is ungrouped.

    This is a test of the current behavior, to check that
    values still hold. It may be necessary to change this
    test if we change the quality handling.
    """

    infile = make_data_path('q1127_src1_grp30.pi')
    ui.load_pha(infile)
    pha = ui.get_data()
    assert pha.quality_filter is None
    assert pha.mask is True

    assert ui.get_dep().shape == (439, )
    ui.ungroup()
    assert ui.get_dep().shape == (1024, )
    assert pha.quality_filter is None
    assert pha.mask is True

    ui.ignore_bad()
    assert ui.get_dep().shape == (1024, )
    assert pha.quality_filter is None

    expected = np.ones(1024, dtype=bool)
    expected[996:1025] = False
    assert pha.mask == pytest.approx(expected)

    # At this point we've changed the mask array so Sherpa thinks
    # we've applied a filter, so a notice is not going to change
    # anything. See issue #1169
    #
    ui.notice(0.5, 7)
    assert pha.mask == pytest.approx(expected)

    # We need to ignore to change the mask.
    #
    ui.ignore(None, 0.5)
    ui.ignore(7, None)
    expected[0:35] = False
    expected[479:1025] = False
    assert pha.mask == pytest.approx(expected)
Example #11
0
def validate_xspec_result(l, h, npts, ndof, statval):
    """Check that the stat results match those from XSPEC.

    This assumes the first data set returned by get_stat_info
    should be used.
    """

    ui.notice(None, None)
    ui.ignore(None, l)
    ui.ignore(h, None)
    ui.ignore_bad()
    sinfo = ui.get_stat_info()[0]
    assert sinfo.numpoints == npts
    assert sinfo.dof == ndof

    # XSPEC displays results to ~ 2dp, so the tolerance
    # is quite forgiving here. Or I could use pyxspec to
    # calculate and display this.
    #
    assert_allclose(sinfo.statval, statval, rtol=0, atol=0.005)
Example #12
0
def validate_xspec_result(l, h, npts, ndof, statval):
    """Check that the stat results match those from XSPEC.

    This assumes the first data set returned by get_stat_info
    should be used.
    """

    ui.notice(None, None)
    ui.ignore(None, l)
    ui.ignore(h, None)
    ui.ignore_bad()
    sinfo = ui.get_stat_info()[0]
    assert sinfo.numpoints == npts
    assert sinfo.dof == ndof

    # XSPEC displays results to ~ 2dp, so the tolerance
    # is quite forgiving here. Or I could use pyxspec to
    # calculate and display this.
    #
    assert_allclose(sinfo.statval, statval, rtol=0, atol=0.005)
Example #13
0
def loadBkgPCA(id=1, readFrom='bkgPCA.json'):
    """
    load PCA background from
    """
    filter0 = ui.get_filter()

    with open(readFrom, 'r') as f:
        parDict = json.load(f)
        parDictRed = {
            k.split('.')[1]: v
            for k, v in parDict.items() if k.startswith('pca')
        }
    fitter = PCAFitter(id=id)
    bkgModel = PCAModel('pca{:d}'.format(id), data=fitter.pca)
    for p in bkgModel.pars:
        p.val = parDictRed[p.name]
    idrsp = get_identity_response(id)
    ui.set_bkg_full_model(id, idrsp(bkgModel))
    ui.ignore()
    ui.notice(filter0)
Example #14
0
    def load(self, filename):
        self.modelFile = filename
        with open(filename, 'r') as f:
            self.pca = json.load(f)
        for k, v in self.pca.items():
            self.pca[k] = np.array(v)
        nactivedata = self.pca['ihi'] - self.pca['ilo']
        assert self.pca['hi'].shape == (
            nactivedata,
        ), 'spectrum has different number of channels: %d vs %s' % (len(
            self.pca['hi']), self.ndata)
        assert self.pca['lo'].shape == self.pca['hi'].shape
        assert self.pca['mean'].shape == self.pca['hi'].shape
        assert len(self.pca['components']) == nactivedata
        assert nactivedata <= self.ndata
        ilo = int(self.pca['ilo'])
        ihi = int(self.pca['ihi'])
        self.cts = self.data[ilo:ihi]
        self.ncts = self.cts.sum(
        )  # 'have ncts background counts for deconvolution
        self.x = np.arange(ihi - ilo)
        self.ilo = ilo
        self.ihi = ihi

        # Only notice the channels between ilo + 1 and ihi (channel starts from 1, while index from 0).
        # The stat value will be affected, for assessment of goodness-of-fit for background.
        self.grouping0 = ui.get_grouping()
        ui.set_analysis('channel')
        # The channel filters, filter0 and filter_chan are all native channels.
        # ui.get_filter() will, instead, reture the binned channels if the spectrum is grouped.
        if self.grouping0 is not None:
            ui.ungroup()
        self.filter0 = ui.get_filter()
        ui.ignore()
        ui.notice(
            self.ilo + 1, self.ihi
        )  # ui.notice(a, b), from channel a to channel b, including channels a, b.
        self.filter_chan = ui.get_filter()
        ui.set_analysis('energy')
        if self.grouping0 is not None:
            ui.group()
def setup_order_plot(make_data_path):
    """Set up a faked dataset with multiple orders."""

    pha = make_data_path('3c273.pi')
    ui.load_pha(pha)

    # It has already loaded in one response
    arf = ui.get_arf(resp_id=1)
    arf.specresp *= 0.5

    for order, scale in enumerate([0.4, 0.25], 2):
        ui.load_arf(make_data_path('3c273.arf'), resp_id=order)
        ui.load_rmf(make_data_path('3c273.rmf'), resp_id=order)

        arf = ui.get_arf(resp_id=order)
        arf.specresp *= scale

    ui.set_source(ui.powlaw1d.pl)

    ui.notice(0.5, 7)
    ui.ignore(3, 4)
Example #16
0
def assert_staterr(use_errors):
    assert np.all(
        ui.get_data("phacounts").counts == pytest.approx(
            ui.get_data("pharate").counts))
    if use_errors is True:
        assert np.all(
            ui.get_data("phacounts").staterror == pytest.approx(
                ui.get_data("pharate").staterror))
    else:
        assert ui.get_data("phacounts").staterror is None
        assert ui.get_data("pharate").staterror is None

    for n in ['phacounts', 'pharate']:
        ui.group_bins(n, 16)
    ui.set_analysis('energy')
    ui.ignore(None, 3.)
    if use_errors is True:
        assert np.all(
            ui.get_data("phacounts").get_error() == pytest.approx(
                ui.get_data("pharate").get_error()))
    else:
        assert ui.get_data("phacounts").get_error() is None
        assert ui.get_data("pharate").get_error() is None
Example #17
0
def fit_lines(linelist, id = None, delta_lam = .2, plot = False, outfile = None):
    mymodel = filili.multilinemanager.GaussLines('const1d', id = id, baseline = baseline)
    linelist['fililiname'] = [''] * len(linelist['linename'])
    for i in range(len(linelist['linename'])):
        lname = linelist['linename'][i]
        lwave = linelist['wave'][i]
        previouslines = set(mymodel.line_name_list())
        mymodel.add_line(linename = filter(lambda x: x.isalnum(), lname), pos = lwave)
        linenamelist = mymodel.line_name_list()
        newline = (set(linenamelist) - previouslines).pop()
        linelist['fililiname'][i] = newline
        if i ==0:
            firstline = linenamelist[0]
            ui.get_model_component(firstline).pos.max = lwave + delta_lam/10.
            ui.get_model_component(firstline).pos.min = lwave - delta_lam/10.
        else:
            dl = lwave - linelist['wave'][0]
            ui.link(ui.get_model_component(newline).pos, ui.get_model_component(firstline).pos + dl)
    
    #ui.set_analysis("wave")
    ui.ignore(None, None) #ignores all data
    ui.notice(min(linelist['wave'])-delta_lam, max(linelist['wave']) + delta_lam)
    ui.fit(id)
    if plot:
        ui.plot_fit(id)
        if has_chips:
            pychips.set_curve("crv1",["err.*","true"])
            pychips.set_plot_title(linelist['name'])
            if outfile is not None:
                pychips.print_window(outfile, ['clobber','true'])
        elif has_mpl:
            plt.title(linelist['name'])
            if outfile is not None:
                plt.savefig(outfile)
        else:
            raise NoPlottingSystemError("Neither pychips nor matplotlib are found.")
Example #18
0
def fitBkgPCA(id=1):
    """
    The source model should be specified.

    Known Issues:
        While the photon indexes resulting from Wstat and PCA-based background fitting are consistent
        for MOS1 and MOS2, the photon index resulting from PCA-based background fitting for pn
        seems to be biased (steeper) by 0.04-0.05. The PCA-based model overestimates
        the background in the hard band.
    """
    bkgmodel = PCAFitter(id=id)  # An id has to be assigned.
    bkgmodel.fit()
    ui.set_analysis('channel')
    ui.ignore()
    ui.notice(bkgmodel.filter_chan)
    ui.set_analysis('energy')
    m, sig = cstatDist(id=id, bkg_id=1)
    bkgmodel.cstatM = m
    bkgmodel.cstatS = sig
    ui.set_analysis('channel')
    ui.ignore()
    ui.notice(bkgmodel.filter0)
    ui.set_analysis('energy')
    return bkgmodel
Example #19
0
    def _filter_data(self):
        """Filter the data.

        Use a slightly-complex filter - e.g. not just the
        end points - to exercise the system.
        """

        ui.ignore(None, 0.5)
        ui.ignore(3, 4)
        ui.ignore(7, None)
Example #20
0
    def _filter_data(self):
        """Filter the data.

        Use a slightly-complex filter - e.g. not just the
        end points - to exercise the system.
        """

        ui.ignore(None, 0.5)
        ui.ignore(3, 4)
        ui.ignore(7, None)
Example #21
0
load_pha(id, filename)
try:
    assert get_rmf(id).energ_lo[0] > 0
    assert get_arf(id).energ_lo[0] > 0
    assert (get_bkg(id).counts > 0).sum() > 0
except:
    traceback.print_exc()
    sys.exit(0)

set_xlog()
set_ylog()
set_stat('cstat')
set_xsabund('wilm')
set_xsxsect('vern')
set_analysis(id, 'ener', 'counts')
ignore(None, elo)
ignore(ehi, None)
notice(elo, ehi)

prefix = filename + '_xagnfitter_out_'

#import json
#z = float(open(filename + '.z').read())
#galnh_value = float(open(filename + '.nh').read())

galabso = auto_galactic_absorption()
galabso.nH.freeze()

if args.backgroundmodel == 'chandra':
    print('calling singlefitter...')
    fitter = SingleFitter(id, filename, ChandraBackground)
Example #22
0
def plaw_fit(alpha_sim):

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    bms = BetaModelSource()
    ds = bms.ds

    def _hard_emission(field, data):
        return YTQuantity(1.0e-18, "s**-1*keV**-1")*data["density"]*data["cell_volume"]/mp
    ds.add_field(("gas", "hard_emission"), function=_hard_emission, units="keV**-1*s**-1")

    nH_sim = 0.02
    abs_model = WabsModel(nH_sim)

    A = YTQuantity(2000., "cm**2")
    exp_time = YTQuantity(2.0e5, "s")
    redshift = 0.01

    sphere = ds.sphere("c", (100.,"kpc"))

    plaw_model = PowerLawSourceModel(1.0, 0.01, 11.0, "hard_emission", 
                                     alpha_sim, prng=prng)

    photons = PhotonList.from_data_source(sphere, redshift, A, exp_time,
                                          plaw_model)

    D_A = photons.parameters["FiducialAngularDiameterDistance"]
    dist_fac = 1.0/(4.*np.pi*D_A*D_A*(1.+redshift)**3).in_cgs()
    norm_sim = float((sphere["hard_emission"]).sum()*dist_fac.in_cgs())*(1.+redshift)

    events = photons.project_photons("z", absorb_model=abs_model,
                                     prng=bms.prng,
                                     no_shifting=True)
    events = ACIS_I(events, rebin=False, convolve_psf=False, prng=bms.prng)
    events.write_spectrum("plaw_model_evt.pi", clobber=True)

    os.system("cp %s ." % events.parameters["ARF"])
    os.system("cp %s ." % events.parameters["RMF"])

    load_user_model(mymodel, "wplaw")
    add_user_pars("wplaw", ["nH", "norm", "redshift", "alpha"],
                  [0.01, norm_sim*1.1, redshift, 0.9], 
                  parmins=[0.0, 0.0, 0.0, 0.1],
                  parmaxs=[10.0, 1.0e9, 10.0, 10.0],
                  parfrozen=[False, False, True, False])

    load_pha("plaw_model_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.6, 7.0:")
    set_model("wplaw")
    fit()
    set_covar_opt("sigma", 1.645)
    covar()
    res = get_covar_results()

    assert np.abs(res.parvals[0]-nH_sim) < res.parmaxes[0]
    assert np.abs(res.parvals[1]-norm_sim) < res.parmaxes[1]
    assert np.abs(res.parvals[2]-alpha_sim) < res.parmaxes[2]

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #23
0
def plaw_fit(alpha_sim, prng=None):

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    bms = BetaModelSource()
    ds = bms.ds

    if prng is None:
        prng = bms.prng

    def _hard_emission(field, data):
        return YTQuantity(
            1.0e-18,
            "s**-1*keV**-1") * data["density"] * data["cell_volume"] / mp

    ds.add_field(("gas", "hard_emission"),
                 function=_hard_emission,
                 units="keV**-1*s**-1")

    nH_sim = 0.02

    A = YTQuantity(2000., "cm**2")
    exp_time = YTQuantity(2.0e5, "s")
    redshift = 0.01

    sphere = ds.sphere("c", (100., "kpc"))

    plaw_model = PowerLawSourceModel(1.0,
                                     0.01,
                                     11.0,
                                     "hard_emission",
                                     alpha_sim,
                                     prng=prng)

    photons = PhotonList.from_data_source(sphere, redshift, A, exp_time,
                                          plaw_model)

    D_A = photons.parameters["fid_d_a"]
    dist_fac = 1.0 / (4. * np.pi * D_A * D_A * (1. + redshift)**3).in_cgs()
    norm_sim = float(
        (sphere["hard_emission"]).sum() * dist_fac.in_cgs()) * (1. + redshift)

    events = photons.project_photons("z", [30., 45.],
                                     absorb_model="wabs",
                                     nH=nH_sim,
                                     prng=bms.prng,
                                     no_shifting=True)

    events.write_simput_file("plaw", overwrite=True)

    instrument_simulator("plaw_simput.fits",
                         "plaw_evt.fits",
                         exp_time,
                         "sq_acisi_cy19", [30.0, 45.0],
                         overwrite=True,
                         foreground=False,
                         ptsrc_bkgnd=False,
                         instr_bkgnd=False,
                         prng=prng)

    write_spectrum("plaw_evt.fits", "plaw_model_evt.pi", overwrite=True)

    os.system("cp %s %s ." % (arf.filename, rmf.filename))

    load_user_model(mymodel, "wplaw")
    add_user_pars("wplaw", ["nH", "norm", "redshift", "alpha"],
                  [0.01, norm_sim * 1.1, redshift, 0.9],
                  parmins=[0.0, 0.0, 0.0, 0.1],
                  parmaxs=[10.0, 1.0e9, 10.0, 10.0],
                  parfrozen=[False, False, True, False])

    load_pha("plaw_model_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.6, 7.0:")
    set_model("wplaw")
    fit()
    res = get_fit_results()

    assert np.abs(res.parvals[0] - nH_sim) / nH_sim < 0.1
    assert np.abs(res.parvals[1] - norm_sim) / norm_sim < 0.05
    assert np.abs(res.parvals[2] - alpha_sim) / alpha_sim < 0.05

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #24
0
def test_plot_order_multi(make_data_path, clean_astro_ui):
    """Rather than fake data, use a known dataset.

    Here we pretend we have three orders but with the same
    response (except that the ARF is 0.5, 0.4, 0.25 of the
    normal ARF).
    """

    pha = make_data_path('3c273.pi')
    ui.load_pha(pha)

    # It has already loaded in one response
    arf = ui.get_arf(resp_id=1)
    arf.specresp *= 0.5

    for order, scale in enumerate([0.4, 0.25], 2):
        ui.load_arf(make_data_path('3c273.arf'), resp_id=order)
        ui.load_rmf(make_data_path('3c273.rmf'), resp_id=order)

        arf = ui.get_arf(resp_id=order)
        arf.specresp *= scale

    ui.set_source(ui.powlaw1d.pl)

    ui.notice(0.5, 7)
    ui.ignore(3, 4)

    fplot = ui.get_fit_plot()
    oplot = ui.get_order_plot()

    # The idea is to compare the X range of plot_fit to plot_order
    # (but accessed just using the plot objects rather than creating
    # an actual plot).
    #
    # First some safety checks
    assert fplot.dataplot.xlo == pytest.approx(fplot.modelplot.xlo)
    assert fplot.dataplot.xhi == pytest.approx(fplot.modelplot.xhi)

    assert len(oplot.xlo) == 3
    assert len(oplot.xhi) == 3
    assert len(oplot.y) == 3

    assert oplot.xlo[1] == pytest.approx(oplot.xlo[0])
    assert oplot.xlo[2] == pytest.approx(oplot.xlo[0])

    assert oplot.xhi[1] == pytest.approx(oplot.xhi[0])
    assert oplot.xhi[2] == pytest.approx(oplot.xhi[0])

    # We know the y values are 0.5, 0.4, 0.25 times the original arf
    # so we can compare them.
    #
    assert oplot.y[1] == pytest.approx(oplot.y[0] * 0.4 / 0.5)
    assert oplot.y[2] == pytest.approx(oplot.y[0] * 0.25 / 0.5)

    xlo = oplot.xlo[0]
    xhi = oplot.xhi[0]
    assert len(xlo) == 564
    assert xlo[0] == pytest.approx(0.46720001101493835)
    assert xhi[-1] == pytest.approx(9.869600296020508)

    # The model plot is technically drawn the same way as the order plot
    # (ungrouped) but it uses different code (sherpa.astro.plot.ModelHistogram)
    # so let's compare.
    #
    mplot = ui.get_model_plot()
    assert mplot.xlo[0] == pytest.approx(0.46720001101493835)
    assert mplot.xhi[-1] == pytest.approx(9.869600296020508)

    # Also compare to the fit plot (which is grouped)
    #
    assert fplot.modelplot.xlo[0] == pytest.approx(0.46720001101493835)
    assert fplot.modelplot.xhi[-1] == pytest.approx(9.869600296020508)
def test_xspec_con_ui_cflux(make_data_path, clean_astro_ui, restore_xspec_settings):
    """Check cflux from the UI layer with a response."""

    from sherpa.astro import xspec

    infile = make_data_path('3c273.pi')
    ui.load_pha('random', infile)
    ui.subtract('random')
    ui.ignore(None, 0.5)
    ui.ignore(7, None)

    ui.set_source('random', 'xsphabs.gal * xscflux.sflux(powlaw1d.pl)')
    mdl = ui.get_source('random')

    assert mdl.name == '(xsphabs.gal * xscflux.sflux(powlaw1d.pl))'
    assert len(mdl.pars) == 7
    assert mdl.pars[0].fullname == 'gal.nH'
    assert mdl.pars[1].fullname == 'sflux.Emin'
    assert mdl.pars[2].fullname == 'sflux.Emax'
    assert mdl.pars[3].fullname == 'sflux.lg10Flux'
    assert mdl.pars[4].fullname == 'pl.gamma'
    assert mdl.pars[5].fullname == 'pl.ref'
    assert mdl.pars[6].fullname == 'pl.ampl'

    assert isinstance(mdl.lhs, xspec.XSphabs)
    assert isinstance(mdl.rhs, xspec.XSConvolutionModel)

    gal = ui.get_model_component('gal')
    sflux = ui.get_model_component('sflux')
    pl = ui.get_model_component('pl')
    assert isinstance(gal, xspec.XSphabs)
    assert isinstance(sflux, xspec.XScflux)
    assert isinstance(pl, PowLaw1D)

    # the convolution model needs the normalization to be fixed
    # (not for this example, as we are not fitting, but do this
    # anyway for reference)
    pl.ampl.frozen = True

    sflux.emin = 1
    sflux.emax = 5
    sflux.lg10Flux = -12.3027

    pl.gamma = 2.03
    gal.nh = 0.039

    ui.set_xsabund('angr')
    ui.set_xsxsect('vern')

    # check we get the "expected" statistic (so this is a regression
    # test).
    #
    ui.set_stat('chi2gehrels')
    sinfo = ui.get_stat_info()

    assert len(sinfo) == 1
    sinfo = sinfo[0]
    assert sinfo.numpoints == 40
    assert sinfo.dof == 37
    assert sinfo.statval == pytest.approx(21.25762265234619)

    # Do we get the same flux from Sherpa's calc_energy_flux?
    #
    cflux = ui.calc_energy_flux(id='random', model=sflux(pl), lo=1, hi=5)
    lcflux = np.log10(cflux)
    assert lcflux == pytest.approx(sflux.lg10Flux.val)
Example #26
0
def test_background():

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    kT_sim = 1.0
    Z_sim = 0.0
    norm_sim = 4.0e-2
    nH_sim = 0.04
    redshift = 0.01

    exp_time = (200., "ks")
    area = (1000., "cm**2")
    fov = (10.0, "arcmin")

    prng = 24

    agen = ApecGenerator(0.05, 12.0, 5000, broadening=False)
    spec = agen.get_spectrum(kT_sim, Z_sim, redshift, norm_sim)
    spec.apply_foreground_absorption(norm_sim)

    events = make_background(area,
                             exp_time,
                             fov, (30.0, 45.0),
                             spec,
                             prng=prng)
    events.write_simput_file("bkgnd", overwrite=True)

    instrument_simulator("bkgnd_simput.fits",
                         "bkgnd_evt.fits",
                         exp_time,
                         "sq_acisi_cy19", [30.0, 45.0],
                         overwrite=True,
                         foreground=False,
                         ptsrc_bkgnd=False,
                         instr_bkgnd=False,
                         prng=prng)

    write_spectrum("bkgnd_evt.fits", "background_evt.pi", overwrite=True)

    os.system("cp %s %s ." % (arf.filename, rmf.filename))

    load_user_model(mymodel, "wapec")
    add_user_pars("wapec", ["nH", "kT", "metallicity", "redshift", "norm"],
                  [0.01, 4.0, 0.2, redshift, norm_sim * 0.8],
                  parmins=[0.0, 0.1, 0.0, -20.0, 0.0],
                  parmaxs=[10.0, 20.0, 10.0, 20.0, 1.0e9],
                  parfrozen=[False, False, False, True, False])

    load_pha("background_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.5, 8.0:")
    set_model("wapec")
    fit()
    res = get_fit_results()

    assert np.abs(res.parvals[0] - nH_sim) / nH_sim < 0.1
    assert np.abs(res.parvals[1] - kT_sim) / kT_sim < 0.05
    assert np.abs(res.parvals[2] - Z_sim) < 0.05
    assert np.abs(res.parvals[3] - norm_sim) / norm_sim < 0.05

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #27
0
def test_vapec_beta_model():

    bms = BetaModelSource()

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    prng = 45

    ds = bms.ds

    A = 30000.
    exp_time = 1.0e4
    redshift = 0.05
    nH_sim = 0.02

    sphere = ds.sphere("c", (0.5, "Mpc"))

    kT_sim = bms.kT
    Z_sim = bms.Z
    O_sim = bms.O
    Ca_sim = bms.Ca

    var_elem = {"O": ("stream", "oxygen"),
                "Ca": ("stream", "calcium")}

    thermal_model = ThermalSourceModel("apec", 0.1, 11.5, 20000,
                                       var_elem=var_elem,
                                       Zmet=("gas","metallicity"), 
                                       prng=prng)

    photons = PhotonList.from_data_source(sphere, redshift, A, exp_time,
                                          thermal_model)

    D_A = photons.parameters["fid_d_a"]

    norm_sim = sphere.quantities.total_quantity("emission_measure")
    norm_sim *= 1.0e-14/(4*np.pi*D_A*D_A*(1.+redshift)*(1.+redshift))
    norm_sim = float(norm_sim.in_cgs())

    events = photons.project_photons("z", [30.0, 45.0], absorb_model="tbabs",
                                     nH=nH_sim, prng=prng, no_shifting=True)

    new_events = Lynx_Calorimeter(events, prng=prng)

    os.system("cp %s %s ." % (arf.filename, rmf.filename))

    new_events.write_channel_spectrum("var_abund_beta_model_evt.pha", overwrite=True)

    load_user_model(mymodel_var, "tbapec")
    add_user_pars("tbapec", ["nH", "kT", "abund", "redshift", "norm", "O", "Ca"],
                  [nH_sim, 4.0, Z_sim, redshift, norm_sim*0.8, 0.3, 0.5],
                  parmins=[0.0, 0.1, 0.0, -20.0, 0.0, 0.0, 0.0],
                  parmaxs=[10.0, 20.0, 10.0, 20.0, 1.0e9, 10.0, 10.0],
                  parfrozen=[True, False, True, True, False, False, False])

    load_pha("var_abund_beta_model_evt.pha")
    set_stat("cstat")
    set_method("levmar")
    ignore(":0.6, 8.0:")
    set_model("tbapec")
    fit()
    res = get_fit_results()

    assert np.abs(res.parvals[0]-kT_sim)/kT_sim < 0.05
    assert np.abs(res.parvals[1]-norm_sim)/norm_sim < 0.05
    assert np.abs(res.parvals[2]-O_sim)/O_sim < 0.05
    assert np.abs(res.parvals[3]-Ca_sim)/Ca_sim < 0.15

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #28
0
def do_beta_model(source, v_field, em_field, axis="z", 
                  prng=None):

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    if prng is None:
        prng = source.prng

    ds = source.ds

    A = 30000.
    exp_time = 1.0e4
    redshift = 0.05
    nH_sim = 0.02

    sphere = ds.sphere("c", (0.5, "Mpc"))

    kT_sim = source.kT
    Z_sim = source.Z

    thermal_model = ThermalSourceModel("apec", 0.1, 11.5, 20000,
                                       Zmet=Z_sim, prng=prng)
    photons = PhotonList.from_data_source(sphere, redshift, A, exp_time,
                                          thermal_model)

    D_A = photons.parameters["fid_d_a"]

    norm_sim = sphere.quantities.total_quantity(em_field)
    norm_sim *= 1.0e-14/(4*np.pi*D_A*D_A*(1.+redshift)*(1.+redshift))
    norm_sim = float(norm_sim.in_cgs())

    v1, v2 = sphere.quantities.weighted_variance(v_field, em_field)

    if isinstance(axis, string_types):
        if axis == "z":
            fac = 1.0
        else:
            fac = 0.0
    else:
        axis /= np.sqrt(np.dot(axis, axis))
        fac = np.dot(axis, [0.0, 0.0, 1.0])

    sigma_sim = fac*float(v1.in_units("km/s"))
    mu_sim = -fac*float(v2.in_units("km/s"))

    events = photons.project_photons(axis, [30.0, 45.0], absorb_model="tbabs",
                                     nH=nH_sim, prng=prng)

    events.write_simput_file("beta_model", overwrite=True)

    instrument_simulator("beta_model_simput.fits", "beta_model_evt.fits",
                         exp_time, "mucal", [30.0, 45.0],
                         overwrite=True, foreground=False, ptsrc_bkgnd=False,
                         instr_bkgnd=False, 
                         prng=prng)

    write_spectrum("beta_model_evt.fits", "beta_model_evt.pi", overwrite=True)

    os.system("cp %s %s ." % (arf.filename, rmf.filename))

    load_user_model(mymodel, "tbapec")
    add_user_pars("tbapec", ["nH", "kT", "metallicity", "redshift", "norm", "velocity"],
                  [0.02, 4.0, 0.2, 0.04, norm_sim*0.8, 300.0],
                  parmins=[0.0, 0.1, 0.0, -200.0, 0.0, 0.0],
                  parmaxs=[10.0, 20.0, 10.0, 200.0, 1.0e9, 20000.0],
                  parfrozen=[True, False, False, False, False, False])

    load_pha("beta_model_evt.pi")
    set_stat("cstat")
    set_method("levmar")
    ignore(":0.6, 8.0:")
    set_model("tbapec")
    fit()
    res = get_fit_results()

    redshift_sim = (1.0+mu_sim/ckms)*(1.0+redshift) - 1.0

    assert np.abs(res.parvals[0]-kT_sim)/kT_sim < 0.05
    assert np.abs(res.parvals[1]-Z_sim)/Z_sim < 0.05
    assert np.abs(res.parvals[2]-redshift_sim)/redshift_sim < 0.05
    assert np.abs(res.parvals[3]-norm_sim) < 0.05
    assert np.abs(res.parvals[4]-sigma_sim) < 30.0

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #29
0
def test_calc_flux_density_pha(id, energy, make_data_path, clean_astro_ui):
    """Do calc_photon/energy_flux return the expected results: densities

    The answer should be the same when lo is set and hi
    is None or vice versa. The flux densities are going to
    be in units of <value>/cm^2/s/keV  {value=photon, erg}

    Note: this tests the "edge" condition when lo=hi; this
    is not documented, but left in as a check (and perhaps
    it should be documented).

    """

    infile = make_data_path('3c273.pi')

    # The 3c273 RMF was generated over the range 0.1 to 11 keV
    # (inclusive). By picking gamma = 1 the photon flux
    # density is ampl / e and the energy flux is scale * ampl.
    # However, this is the exact calculation, but the one done by
    # Sherpa involves calculating the model over a bin and then
    # dividing by that bin width, which is different enough to
    # the analytic formula that we use this approach here when
    # calculating the expected values. The bin width is 0.01 keV,
    # with bins starting at 0.1.
    #
    ampl = 1e-4

    # flux densities: exact
    # pflux_exp = ampl / energy
    # eflux_exp = 1.602e-9 * ampl

    # Note that you can calculate an answer at the left edge of the grid, but
    # not at the right (this is either a < vs <= comparison, or numeric
    # issues with the maximum grid value).
    #
    # Note that the RMF emin is just above 0.1 keV, ie
    # 0.10000000149011612, which is why an energy of 0.1 gives
    # an answer of 0. Now, sao_fcmp(0.1, 0.10000000149011612, sherpa.utils.eps)
    # returns 0, so we could consider these two values equal, but
    # that would complicate the flux calculation so is (currently) not
    # done.
    #
    de = 0.01
    if energy <= 0.1 or energy >= 11:
        pflux_exp = 0.0
        eflux_exp = 0.0
    else:
        # assuming a bin centered on the energy; the actual grid
        # is not this, but this should be close
        hwidth = de / 2
        pflux_exp = ampl * (np.log(energy + hwidth) -
                            np.log(energy - hwidth)) / de
        eflux_exp = 1.602e-9 * energy * pflux_exp

    pl = ui.create_model_component('powlaw1d', 'pl')
    pl.ampl = ampl
    pl.gamma = 1

    if id is None:
        ui.load_pha(infile)
        ui.set_source(pl)
    else:
        ui.load_pha(id, infile)
        ui.set_source(id, pl)

    # Use a subset of the data range (to check that the calc routines
    # ignores them, ie uses the full 0.1 to 11 keV range.
    #
    ui.ignore(None, 0.5)
    ui.ignore(7, None)

    # Do not use named arguments, but assume positional arguments
    if id is None:
        pflux1 = ui.calc_photon_flux(energy)
        pflux2 = ui.calc_photon_flux(None, energy)
        pflux3 = ui.calc_photon_flux(energy, energy)

        eflux1 = ui.calc_energy_flux(energy)
        eflux2 = ui.calc_energy_flux(None, energy)
        eflux3 = ui.calc_energy_flux(energy, energy)
    else:
        pflux1 = ui.calc_photon_flux(energy, None, id)
        pflux2 = ui.calc_photon_flux(None, energy, id)
        pflux3 = ui.calc_photon_flux(energy, energy, id)

        eflux1 = ui.calc_energy_flux(energy, None, id)
        eflux2 = ui.calc_energy_flux(None, energy, id)
        eflux3 = ui.calc_energy_flux(energy, energy, id)

    eflux1 = np.log10(eflux1)
    eflux2 = np.log10(eflux2)
    eflux3 = np.log10(eflux3)

    # Use equality here since the numbers should be the same
    assert pflux1 == pflux2
    assert pflux1 == pflux3
    assert eflux1 == eflux2
    assert eflux1 == eflux3

    # Note the "large" tolerance here
    eflux_exp = np.log10(eflux_exp)
    assert pflux1 == pytest.approx(pflux_exp, rel=5e-2)
    assert eflux1 == pytest.approx(eflux_exp, rel=1e-3)
Example #30
0
def check_bad_grouping(exp_xlo, exp_xhi, exp_counts, lo1, hi1, lo2, hi2):
    """Common tests from test_grouped_pha_all_badXXX

    Sending in two ranges is a bit excessive but easiest
    thing to implement
    """

    cts = ui.get_counts()
    assert cts == pytest.approx([exp_counts])

    dplot = ui.get_data_plot()
    assert dplot.xlo == pytest.approx([exp_xlo])
    assert dplot.xhi == pytest.approx([exp_xhi])
    assert dplot.y == pytest.approx([exp_counts])

    # ignore all the data
    ui.ignore(lo1, hi1)

    # can still plot
    cts = ui.get_counts()
    assert cts == pytest.approx([exp_counts])

    cts = ui.get_counts(filter=True)
    assert len(cts) == 0

    dplot = ui.get_data_plot()
    assert len(dplot.xlo) == 0
    assert len(dplot.xhi) == 0
    assert len(dplot.y) == 0

    # ignore does not fail
    #
    ui.ignore(lo2, hi2)

    # we can restore the data
    ui.notice(None, None)

    cts = ui.get_counts()
    assert cts == pytest.approx([exp_counts])

    dplot = ui.get_data_plot()
    assert dplot.xlo == pytest.approx([exp_xlo])
    assert dplot.xhi == pytest.approx([exp_xhi])
    assert dplot.y == pytest.approx([exp_counts])

    # now ignore the bad channels (ie everything)
    #
    ui.ignore_bad()

    cts = ui.get_counts()
    assert len(cts) == 0

    dplot = ui.get_data_plot()
    assert len(dplot.xlo) == 0
    assert len(dplot.xhi) == 0
    assert len(dplot.y) == 0

    # there's nothing to notice (this line is an example of #790)
    ui.notice(lo1, hi1)

    cts = ui.get_counts()
    assert len(cts) == 0

    dplot = ui.get_data_plot()
    assert len(dplot.xlo) == 0
    assert len(dplot.xhi) == 0
    assert len(dplot.y) == 0
Example #31
0
def do_beta_model(source, v_field, em_field):

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    ds = source.ds

    A = 3000.
    exp_time = 1.0e5
    redshift = 0.05
    nH_sim = 0.02

    apec_model = TableApecModel(0.1, 11.5, 20000, thermal_broad=False)
    abs_model = TBabsModel(nH_sim)

    sphere = ds.sphere("c", (0.5, "Mpc"))

    kT_sim = source.kT
    Z_sim = source.Z

    thermal_model = ThermalSourceModel(apec_model,
                                       Zmet=Z_sim,
                                       prng=source.prng)
    photons = PhotonList.from_data_source(sphere, redshift, A, exp_time,
                                          thermal_model)

    D_A = photons.parameters["FiducialAngularDiameterDistance"]

    norm_sim = sphere.quantities.total_quantity(em_field)
    norm_sim *= 1.0e-14 / (4 * np.pi * D_A * D_A * (1. + redshift) *
                           (1. + redshift))
    norm_sim = float(norm_sim.in_cgs())

    v1, v2 = sphere.quantities.weighted_variance(v_field, em_field)
    sigma_sim = float(v1.in_units("km/s"))
    mu_sim = -float(v2.in_units("km/s"))

    events = photons.project_photons("z",
                                     absorb_model=abs_model,
                                     prng=source.prng)
    events = ACIS_I(events, rebin=False, convolve_psf=False, prng=source.prng)

    events.write_spectrum("beta_model_evt.pi", clobber=True)

    os.system("cp %s ." % events.parameters["ARF"])
    os.system("cp %s ." % events.parameters["RMF"])

    load_user_model(mymodel, "tbapec")
    add_user_pars("tbapec", ["nH", "kT", "metallicity", "redshift", "norm"],
                  [0.01, 4.0, 0.2, redshift, norm_sim * 0.8],
                  parmins=[0.0, 0.1, 0.0, -20.0, 0.0],
                  parmaxs=[10.0, 20.0, 10.0, 20.0, 1.0e9],
                  parfrozen=[False, False, False, True, False])

    load_pha("beta_model_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.5, 8.0:")
    set_model("tbapec")
    fit()
    set_covar_opt("sigma", 1.645)
    covar()
    res = get_covar_results()

    assert np.abs(res.parvals[0] - nH_sim) < res.parmaxes[0]
    assert np.abs(res.parvals[1] - kT_sim) < res.parmaxes[1]
    assert np.abs(res.parvals[2] - Z_sim) < res.parmaxes[2]
    assert np.abs(res.parvals[3] - norm_sim) < res.parmaxes[3]

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #32
0
    def fit(self):
        # try a PCA decomposition of this spectrum
        initial = self.decompose()
        ui.set_method('neldermead')
        bkgmodel = PCAModel('pca%s' % self.id, data=self.pca)
        self.bkgmodel = bkgmodel
        response = get_identity_response(self.id)
        convbkgmodel = response(bkgmodel)
        ui.set_bkg_full_model(self.id, convbkgmodel)
        for p, v in zip(bkgmodel.pars, initial):
            p.val = v
        srcmodel = ui.get_model(self.id)
        ui.set_full_model(self.id, srcmodel)
        initial_v = self.calc_bkg_stat()
        # print('before fit: stat: %s' % (initial_v))
        ui.fit_bkg(id=self.id)
        # print('fit: first full fit done')
        final = [p.val for p in ui.get_bkg_model(self.id).pars]
        # print('fit: parameters: %s' % (final))
        initial_v = self.calc_bkg_stat()
        # print('fit: stat: %s' % (initial_v))

        # lets try from zero
        # logf.info('fit: second full fit from zero')
        for p in bkgmodel.pars:
            p.val = 0
        ui.fit_bkg(id=self.id)
        initial_v0 = self.calc_bkg_stat()
        # logf.info('fit: parameters: %s' % (final))
        # logf.info('fit: stat: %s' % (initial_v0))

        # pick the better starting point
        if initial_v0 < initial_v:
            # logf.info('fit: using zero-fit')
            initial_v = initial_v0
            final = [p.val for p in ui.get_bkg_model(self.id).pars]
        else:
            # logf.info('fit: using decomposed-fit')
            for p, v in zip(bkgmodel.pars, final):
                p.val = v

        # start with the full fit and remove(freeze) parameters
        print('%d parameters, stat=%.2f' % (len(initial), initial_v))
        results = [(2 * len(final) + initial_v, final, len(final), initial_v)]
        for i in range(len(initial) - 1, 0, -1):
            bkgmodel.pars[i].val = 0
            bkgmodel.pars[i].freeze()
            ui.fit_bkg(id=self.id)
            final = [p.val for p in ui.get_bkg_model(self.id).pars]
            v = self.calc_bkg_stat()
            print('--> %d parameters, stat=%.2f' % (i, v))
            results.insert(0, (v + 2 * i, final, i, v))

        print()
        print('Background PCA fitting AIC results:')
        print('-----------------------------------')
        print()
        print('stat Ncomp AIC')
        for aic, params, nparams, val in results:
            print('%-05.1f %2d %-05.1f' % (val, nparams, aic))
        aic, final, nparams, val = min(results)
        for p, v in zip(bkgmodel.pars, final):
            p.val = v
        for i in range(nparams):
            bkgmodel.pars[i].thaw()

        print()
        print('Increasing parameters again...')
        # now increase the number of parameters again
        # results = [(aic, final, nparams, val)]
        last_aic, last_final, last_nparams, last_val = aic, final, nparams, val
        for i in range(last_nparams, len(bkgmodel.pars)):
            next_nparams = i + 1
            bkgmodel.pars[i].thaw()
            for p, v in zip(bkgmodel.pars, last_final):
                p.val = v
            ui.fit_bkg(id=self.id)
            next_final = [p.val for p in ui.get_bkg_model(self.id).pars]
            v = self.calc_bkg_stat()
            next_aic = v + 2 * next_nparams
            if next_aic < last_aic:  # accept
                print('%d parameters, aic=%.2f ** accepting' %
                      (next_nparams, next_aic))
                last_aic, last_final, last_nparams, last_val = next_aic, next_final, next_nparams, v
            else:
                print('%d parameters, aic=%.2f' % (next_nparams, next_aic))
            # stop if we are 3 parameters ahead what we needed
            if next_nparams >= last_nparams + 3:
                break

        print('Final choice: %d parameters, aic=%.2f' %
              (last_nparams, last_aic))
        # reset to the last good solution
        for p, v in zip(bkgmodel.pars, last_final):
            p.val = v

        last_model = convbkgmodel
        for i in range(10):
            print('Adding Gaussian#%d' % (i + 1))
            # find largest discrepancy
            ui.set_analysis(self.id, "ener", "rate")
            m = ui.get_bkg_fit_plot(self.id)
            y = m.dataplot.y.cumsum()
            z = m.modelplot.y.cumsum()
            diff_rate = np.abs(y - z)
            ui.set_analysis(self.id, "ener", "counts")
            m = ui.get_bkg_fit_plot(self.id)
            x = m.dataplot.x
            y = m.dataplot.y.cumsum()
            z = m.modelplot.y.cumsum()
            diff = np.abs(y - z)
            i = np.argmax(diff)
            energies = x
            e = x[i]
            print(
                'largest remaining discrepancy at %.3fkeV[%d], need %d counts'
                % (x[i], i, diff[i]))
            # e = x[i]
            power = diff_rate[i]
            # lets try to inject a gaussian there

            g = ui.xsgaussian('g_%d_%d' % (self.id, i))
            print('placing gaussian at %.2fkeV, with power %s' % (e, power))
            # we work in energy bins, not energy
            g.LineE.min = energies[0]
            g.LineE.max = energies[-1]
            g.LineE.val = e
            if i > len(diff) - 2:
                i = len(diff) - 2
            if i < 2:
                i = 2
            g.Sigma = (x[i + 1] - x[i - 1])
            g.Sigma.min = (x[i + 1] - x[i - 1]) / 3
            g.Sigma.max = x[-1] - x[0]
            g.norm.min = power * 1e-6
            g.norm.val = power
            convbkgmodel2 = response(g)
            next_model = last_model + convbkgmodel2
            ui.set_bkg_full_model(self.id, next_model)
            ui.fit_bkg(id=self.id)
            next_final = [p.val for p in ui.get_bkg_model(self.id).pars]
            next_nparams = len(next_final)
            v = self.calc_bkg_stat()
            next_aic = v + 2 * next_nparams
            print('with Gaussian:', next_aic,
                  '; change: %.1f (negative is good)' % (next_aic - last_aic))
            if next_aic < last_aic:
                print('accepting')
                last_model = next_model
                last_aic, last_final, last_nparams, last_val = next_aic, next_final, next_nparams, v
            else:
                print('not significant, rejecting')
                ui.set_bkg_full_model(self.id, last_model)
                for p, v in zip(last_model.pars, last_final):
                    p.val = v
                    if v == 0:  # the parameter was frozen.
                        ui.freeze(p)
                break

        self.cstat, self.dof = self.calc_bkg_stat(
            dof=True)  # Save the final cstat and dof (dof = ihi - ilo)
        self.filter_energy = ui.get_filter(
        )  # Save the filter for background fitting.
        ui.set_analysis('channel')
        ui.ignore()
        ui.notice(self.filter0)  # restore filter
        ui.set_analysis('energy')
def test_xspec_con_ui_shift(make_data_path, clean_astro_ui, restore_xspec_settings):
    """Check shifted models from the UI layer with a response.

    There is no regrid here, so we see the issue with the upper edge of the
    RMF cutting off the source.
    """

    from sherpa.astro import xspec

    infile = make_data_path('3c273.pi')
    ui.load_pha(infile)
    ui.subtract()
    ui.ignore(None, 0.5)
    ui.ignore(7, None)

    msource = ui.box1d.box + ui.const1d.bgnd
    ui.set_source(ui.xsphabs.gal * ui.xszashift.zsh(msource))
    mdl = ui.get_source()

    assert mdl.name == '(xsphabs.gal * xszashift.zsh((box1d.box + const1d.bgnd)))'
    assert len(mdl.pars) == 6
    assert mdl.pars[0].fullname == 'gal.nH'
    assert mdl.pars[1].fullname == 'zsh.Redshift'
    assert mdl.pars[2].fullname == 'box.xlow'
    assert mdl.pars[3].fullname == 'box.xhi'
    assert mdl.pars[4].fullname == 'box.ampl'
    assert mdl.pars[5].fullname == 'bgnd.c0'

    assert isinstance(mdl.lhs, xspec.XSphabs)
    assert isinstance(mdl.rhs, xspec.XSConvolutionModel)

    gal = ui.get_model_component('gal')
    zsh = ui.get_model_component('zsh')
    box = ui.get_model_component('box')
    bgnd = ui.get_model_component('bgnd')
    assert isinstance(gal, xspec.XSphabs)
    assert isinstance(zsh, xspec.XSzashift)
    assert isinstance(box, Box1D)
    assert isinstance(bgnd, Const1D)

    zsh.redshift = 1

    # turn off the absorption to make the comparison easier
    gal.nh = 0

    # pick an energy range that exceeds the RMF maximum energy (11 keV)
    box.xlow = 10
    box.xhi = 13
    box.ampl = 0.5

    bgnd.c0 = 0.001
    bgnd.integrate = False

    mplot = ui.get_source_plot()

    # Expect, as z = 1
    #
    #    0.1 for E < 5 keV     (10 / (1+z))
    #    0       E > 5.5 keV   (11 / (1+z))  due to RMF cut off
    #    0.6     5 - 5.5 keV
    #
    idx1 = mplot.xhi <= 5
    idx2 = mplot.xlo >= 5.5

    # ensure we pick the "expected" range
    assert idx1.sum() == 490
    assert idx2.sum() == 550

    assert mplot.xhi[idx1].max() == pytest.approx(5)
    assert mplot.xlo[idx2].min() == pytest.approx(5.5)

    # use the inverse of the two index arrays to ensure we are not
    # missing any bins.
    #
    idx3 = ~(idx1 | idx2)

    # The tolerance has to be relatively large otherwise things fail
    assert mplot.y[idx1] == pytest.approx(0.1, rel=3e-5)
    assert mplot.y[idx2] == pytest.approx(0)
    assert mplot.y[idx3] == pytest.approx(0.6, rel=1e-5)
Example #34
0
def plaw_fit(alpha_sim):

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    nH_sim = 0.02
    norm_sim = 1.0e-4
    redshift = 0.01

    exp_time = 5.0e4
    area = 40000.0
    inst_name = "hdxi"

    spec = Spectrum.from_powerlaw(alpha_sim, redshift, norm_sim)
    spec.apply_foreground_absorption(nH_sim)
    e = spec.generate_energies(exp_time, area)

    pt_src = PointSourceModel(30.0, 45.0, e.size)

    write_photon_list("plaw_model",
                      "plaw_model",
                      e.flux,
                      pt_src.ra,
                      pt_src.dec,
                      e,
                      clobber=True)

    instrument_simulator("plaw_model_simput.fits",
                         "plaw_model_evt.fits",
                         exp_time,
                         inst_name, [30.0, 45.0],
                         astro_bkgnd=None,
                         instr_bkgnd_scale=0.0)

    inst = get_instrument_from_registry(inst_name)
    arf = AuxiliaryResponseFile(inst["arf"])
    rmf = RedistributionMatrixFile(inst["rmf"])
    os.system("cp %s ." % arf.filename)
    os.system("cp %s ." % rmf.filename)

    write_spectrum("plaw_model_evt.fits", "plaw_model_evt.pha", clobber=True)

    load_user_model(mymodel, "wplaw")
    add_user_pars("wplaw", ["nH", "norm", "redshift", "alpha"],
                  [0.01, norm_sim * 0.8, redshift, 0.9],
                  parmins=[0.0, 0.0, 0.0, 0.1],
                  parmaxs=[10.0, 1.0e9, 10.0, 10.0],
                  parfrozen=[False, False, True, False])

    load_pha("plaw_model_evt.pha")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.5, 9.0:")
    set_model("wplaw")
    fit()
    set_covar_opt("sigma", 1.645)
    covar()
    res = get_covar_results()

    assert np.abs(res.parvals[0] - nH_sim) < res.parmaxes[0]
    assert np.abs(res.parvals[1] - norm_sim) < res.parmaxes[1]
    assert np.abs(res.parvals[2] - alpha_sim) < res.parmaxes[2]

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
def test_xspec_con_ui_shift_regrid(make_data_path, clean_astro_ui, restore_xspec_settings):
    """Check shifted models from the UI layer with a response and regrid.

    Unlike test_xspec_con_ui_shift, the convolution model is run on an extended
    grid compared to the RMF.
    """

    from sherpa.astro import xspec

    infile = make_data_path('3c273.pi')
    ui.load_pha(infile)
    ui.subtract()
    ui.ignore(None, 0.5)
    ui.ignore(7, None)

    # Ensure the grid contains the RMF grid (0.1-11 keV).
    # Really we should have emax to be > 11 * (1+z) but
    # I purposefully pick a smaller maximum to check we
    # get 0 values in the output
    #
    rgrid = np.arange(0.1, 20, 0.01)
    rlo = rgrid[:-1]
    rhi = rgrid[1:]

    msource = ui.box1d.box + ui.const1d.bgnd
    csource = ui.xszashift.zsh(msource)
    ui.set_source(ui.xsphabs.gal * csource.regrid(rlo, rhi))
    mdl = ui.get_source()

    # What should the string representation be?
    #
    assert mdl.name == '(xsphabs.gal * regrid1d(xszashift.zsh((box1d.box + const1d.bgnd))))'

    assert len(mdl.pars) == 6
    assert mdl.pars[0].fullname == 'gal.nH'
    assert mdl.pars[1].fullname == 'zsh.Redshift'
    assert mdl.pars[2].fullname == 'box.xlow'
    assert mdl.pars[3].fullname == 'box.xhi'
    assert mdl.pars[4].fullname == 'box.ampl'
    assert mdl.pars[5].fullname == 'bgnd.c0'

    assert isinstance(mdl.lhs, xspec.XSphabs)
    assert isinstance(mdl.rhs, RegridWrappedModel)

    gal = ui.get_model_component('gal')
    zsh = ui.get_model_component('zsh')
    box = ui.get_model_component('box')
    bgnd = ui.get_model_component('bgnd')
    assert isinstance(gal, xspec.XSphabs)
    assert isinstance(zsh, xspec.XSzashift)
    assert isinstance(box, Box1D)
    assert isinstance(bgnd, Const1D)

    zsh.redshift = 1

    # turn off the absorption to make the comparison easier
    gal.nh = 0

    # pick an energy range that exceeds the RMF maximum energy (11 keV)
    box.xlow = 10
    box.xhi = 13
    box.ampl = 0.5

    bgnd.c0 = 0.001
    bgnd.integrate = False

    mplot = ui.get_source_plot()

    # Expect, as z = 1
    #
    #    0.1 for E < 5 keV  or  6.5 - 10 keV
    #    0.6     5 - 6.5 keV
    #    0       > 10 keV
    #
    idx1 = (mplot.xhi <= 5) | ((mplot.xlo >= 6.5) & (mplot.xhi <= 10))
    idx2 = (mplot.xlo >= 5) & (mplot.xhi <= 6.5)
    idx3 = mplot.xlo >= 10

    # ensure we pick the "expected" range (there are 1090 bins in the
    # RMF energy grid)
    assert idx1.sum() == 840
    assert idx2.sum() == 150
    assert idx3.sum() == 100

    # The tolerance has to be relatively large otherwise things fail
    #
    # It appears that the very-last bin of idx1 is actually ~ 0.05,
    # so separate that out here. It is the last bin of the "valid"
    # array, and so at z=1 may only have been half-filled by the
    # convolution.
    #
    assert mplot.y[idx1][:-1] == pytest.approx(0.1, rel=1e-5)
    assert mplot.y[idx1][-1] == pytest.approx(0.05, rel=3e-5)

    assert mplot.y[idx2] == pytest.approx(0.6, rel=3e-5)
    assert mplot.y[idx3] == pytest.approx(0)
Example #36
0
def test_point_source():

    tmpdir = tempfile.mkdtemp()
    curdir = os.getcwd()
    os.chdir(tmpdir)

    nH_sim = 0.02
    norm_sim = 1.0e-4
    alpha_sim = 0.95
    redshift = 0.02

    exp_time = (100., "ks")
    area = (3000., "cm**2")

    wcs = create_dummy_wcs()

    ebins = np.linspace(0.1, 11.5, 2001)
    emid = 0.5*(ebins[1:]+ebins[:-1])
    spec = norm_sim*(emid*(1.0+redshift))**(-alpha_sim)
    de = np.diff(ebins)[0]

    abs_model = TBabsModel(nH_sim)

    events = EventList.create_empty_list(exp_time, area, wcs)

    positions = [(30.01, 45.0)]

    new_events = events.add_point_sources(positions, ebins, spec, prng=prng,
                                          absorb_model=abs_model)

    new_events = ACIS_S(new_events, prng=prng)

    scalex = float(np.std(new_events['xpix'])*sigma_to_fwhm*new_events.parameters["dtheta"])
    scaley = float(np.std(new_events['ypix'])*sigma_to_fwhm*new_events.parameters["dtheta"])

    psf_scale = ACIS_S.psf_scale

    assert (scalex - psf_scale)/psf_scale < 0.01
    assert (scaley - psf_scale)/psf_scale < 0.01

    new_events.write_spectrum("point_source_evt.pi", clobber=True)

    os.system("cp %s ." % new_events.parameters["ARF"])
    os.system("cp %s ." % new_events.parameters["RMF"])

    load_user_model(mymodel, "tplaw")
    add_user_pars("tplaw", ["nH", "norm", "redshift", "alpha"],
                  [0.01, norm_sim*0.8, redshift, 0.9],
                  parmins=[0.0, 0.0, 0.0, 0.1],
                  parmaxs=[10.0, 1.0e9, 10.0, 10.0],
                  parfrozen=[False, False, True, False])

    load_pha("point_source_evt.pi")
    set_stat("cstat")
    set_method("simplex")
    ignore(":0.5, 9.0:")
    set_model("tplaw")
    fit()
    set_covar_opt("sigma", 1.6)
    covar()
    res = get_covar_results()

    assert np.abs(res.parvals[0]-nH_sim) < res.parmaxes[0]
    assert np.abs(res.parvals[1]-norm_sim/de) < res.parmaxes[1]
    assert np.abs(res.parvals[2]-alpha_sim) < res.parmaxes[2]

    os.chdir(curdir)
    shutil.rmtree(tmpdir)
Example #37
0
def test_calc_flux_pha(id, lo, hi, make_data_path, clean_astro_ui):
    """Do calc_photon/energy_flux return the expected results: fluxes?

    This skips those combinations where only one of lo or hi
    is None, since this is handle by test_calc_flux_density_pha.

    Flues are in units of <value>/cm^2/s  {value=photon, erg}

    The checks are made against ranges that are chosen to cover
    matching the grid, a subset of the grid (with and without
    matching the start/end), partial overlaps, and no overlap.
    """

    infile = make_data_path('3c273.pi')

    # The 3c273 RMF was generated over the range 0.1 to 11 keV
    # (inclusive). By picking gamma = 1 the photon-flux
    # integral is just ampl * (log(ehi) - log(elo))
    # and the energy-flux ampl is ampl * (ehi - elo) * scale
    # where scale converts 1 keV to erg.
    #
    ampl = 1e-4

    if lo is None:
        loval = 0.1
    elif lo < 0.1:
        loval = 0.1
    else:
        loval = lo

    if hi is None:
        hival = 11.0
    elif hi > 11.0:
        hival = 11.0
    else:
        hival = hi

    # expected fluxes; special case the handling of there being no
    # overlap between the user grid and the data grid.
    #
    if lo is not None and (lo > 11.0 or hi < 0.1):
        pflux_exp = 0.0
        eflux_exp = 0.0
    else:
        pflux_exp = ampl * (np.log(hival) - np.log(loval))
        eflux_exp = 1.602e-9 * ampl * (hival - loval)

    pl = ui.create_model_component('powlaw1d', 'pl')
    pl.ampl = ampl
    pl.gamma = 1

    if id is None:
        ui.load_pha(infile)
        ui.set_source(pl)
    else:
        ui.load_pha(id, infile)
        ui.set_source(id, pl)

    # Use a subset of the data range (to check that the calc routines
    # ignores them, ie uses the full 0.1 to 11 keV range.
    #
    ui.ignore(None, 0.5)
    ui.ignore(7, None)

    # Do not use named arguments, but assume positional arguments
    if id is None:
        pflux = ui.calc_photon_flux(lo, hi)
        eflux = ui.calc_energy_flux(lo, hi)
    else:
        pflux = ui.calc_photon_flux(lo, hi, id)
        eflux = ui.calc_energy_flux(lo, hi, id)

    # Since the energy fluxes are ~1e-12 we want to rescale the
    # value before comparison. Here we use a log transform.
    #
    eflux_exp = np.log10(eflux_exp)
    eflux = np.log10(eflux)

    assert pflux == pytest.approx(pflux_exp, rel=1e-3)
    assert eflux == pytest.approx(eflux_exp, rel=1e-4)