コード例 #1
0
def test_calc_flux_pha_unabsorbed(make_data_path, clean_astro_ui):
    """Can we calculate an unabsorbed flux?"""

    # The idea is that with a model expression of
    #    const1d.scale * powlaw1d.pl
    # when scale is not 1 (and not integrated) then we can
    # just look to see if the "absorbed" flux is scale * the
    # "unabsorbed" flux.
    #
    infile = make_data_path('3c273.pi')
    ui.load_pha(infile)

    scale = ui.create_model_component('const1d', 'scale')
    pl = ui.create_model_component('powlaw1d', 'pl')

    scale.c0 = 0.8
    scale.integrate = False
    pl.gamma = 1.5
    pl.ampl = 1e-4

    ui.set_source(scale * pl)

    pflux_abs = ui.calc_photon_flux(0.5, 7)
    pflux_unabs = ui.calc_photon_flux(0.5, 7, model=pl)

    eflux_abs = ui.calc_energy_flux(0.5, 7)
    eflux_unabs = ui.calc_energy_flux(0.5, 7, model=pl)

    pflux_scale = pflux_abs / pflux_unabs
    eflux_scale = eflux_abs / eflux_unabs

    assert pflux_scale == pytest.approx(0.8)
    assert eflux_scale == pytest.approx(0.8)
コード例 #2
0
def test_calc_flux_pha_analysis(elo, ehi, setting, lo, hi, make_data_path,
                                clean_astro_ui):
    """Do calc_photon/energy_flux return the expected results: fluxes + analysis setting

    Basic test for different analysis settings: the
    same range (modulo precision of conversion) gives the
    same results.
    """

    infile = make_data_path('3c273.pi')
    pl = ui.create_model_component('powlaw1d', 'pl')

    ui.load_pha(infile)
    ui.set_source(pl)

    pflux = ui.calc_photon_flux(elo, ehi)
    eflux = ui.calc_energy_flux(elo, ehi)

    ui.set_analysis(setting)
    pflux2 = ui.calc_photon_flux(lo, hi)
    eflux2 = ui.calc_energy_flux(lo, hi)

    # use approx here since the bin edges are not guaranteed
    # to line up, and use a large tolerance.
    #
    assert pflux2 == pytest.approx(pflux, rel=1e-2)

    eflux = np.log10(eflux)
    eflux2 = np.log10(eflux2)
    assert eflux2 == pytest.approx(eflux, rel=1e-3)
コード例 #3
0
ファイル: test_astro.py プロジェクト: mirca/sherpa
    def test_pha_intro(self):
        self.run_thread('pha_intro')
        # astro.ui imported as ui, instead of
        # being in global namespace
        self.assertEqualWithinTol(ui.get_fit_results().statval, 37.9079, 1e-4)
        self.assertEqualWithinTol(ui.get_fit_results().rstat, 0.902569, 1e-4)
        self.assertEqualWithinTol(ui.get_fit_results().qval, 0.651155, 1e-4)
        self.assertEqualWithinTol(self.locals['p1'].gamma.val, 2.15852, 1e-4)
        self.assertEqualWithinTol(self.locals['p1'].ampl.val, 0.00022484, 1e-4)

        self.assertEqualWithinTol(ui.calc_photon_flux(), 0.000469964, 1e-4)
        self.assertEqualWithinTol(ui.calc_energy_flux(), 9.614847e-13, 1e-4)
        self.assertEqualWithinTol(ui.calc_data_sum(), 706.85714092, 1e-4)
        self.assertEqualWithinTol(ui.calc_model_sum(), 638.45693377, 1e-4)
        self.assertEqualWithinTol(ui.calc_source_sum(), 0.046996409, 1e-4)
        self.assertEqualWithinTol(
            ui.eqwidth(self.locals['p1'], ui.get_source()), -0.57731725, 1e-4)
        self.assertEqualWithinTol(
            ui.calc_kcorr([1, 1.2, 1.4, 1.6, 1.8, 2], 0.5, 2), [
                0.93341286, 0.93752836, 0.94325233, 0.94990140, 0.95678054,
                0.96393515
            ], 1e-4)

        self.assertEqual(ui.get_fit_results().nfev, 22)
        self.assertEqual(ui.get_fit_results().numpoints, 44)
        self.assertEqual(ui.get_fit_results().dof, 42)
コード例 #4
0
ファイル: test_astro.py プロジェクト: JBris/sherpa
        def cmp_pha_intro(fit_result, p1, covarerr):
            assert fit_result.statval == approx(37.9079, rel=1e-4)
            assert fit_result.rstat == approx(0.902569, rel=1e-4)
            assert fit_result.qval == approx(0.651155, rel=1e-4)
            self.assertEqual(fit_result.nfev, 22)
            self.assertEqual(fit_result.numpoints, 44)
            self.assertEqual(fit_result.dof, 42)
            p1.gamma.val == approx(2.15852, rel=1e-4)
            p1.ampl.val == approx(0.00022484, rel=1e-4)

            assert ui.calc_photon_flux() == approx(0.000469964, rel=1e-4)
            assert ui.calc_energy_flux() == approx(9.614847e-13, rel=1e-4)
            assert ui.calc_data_sum() == approx(706.85714092, rel=1e-4)
            assert ui.calc_model_sum() == approx(638.45693377, rel=1e-4)
            assert ui.calc_source_sum() == approx(0.046996409, rel=1e-4)

            calc = ui.eqwidth(self.locals['p1'], ui.get_source())
            assert calc == approx(-0.57731725, rel=1e-4)

            calc = ui.calc_kcorr([1, 1.2, 1.4, 1.6, 1.8, 2], 0.5, 2)
            # Prior to fixing #619 the expected values were
            # expected = [0.93341286, 0.93752836, 0.94325233,
            #             0.94990140, 0.95678054, 0.96393515]
            expected = [0.93132747, 0.9352768, 0.94085917,
                        0.94738472, 0.95415463, 0.96121113]
            assert calc == approx(expected, rel=1e-4)
コード例 #5
0
ファイル: test_astro.py プロジェクト: linearregression/sherpa
    def test_pha_intro(self):
        self.run_thread("pha_intro")
        # astro.ui imported as ui, instead of
        # being in global namespace
        self.assertEqualWithinTol(ui.get_fit_results().statval, 37.9079, 1e-4)
        self.assertEqualWithinTol(ui.get_fit_results().rstat, 0.902569, 1e-4)
        self.assertEqualWithinTol(ui.get_fit_results().qval, 0.651155, 1e-4)
        self.assertEqualWithinTol(self.locals["p1"].gamma.val, 2.15852, 1e-4)
        self.assertEqualWithinTol(self.locals["p1"].ampl.val, 0.00022484, 1e-4)

        self.assertEqualWithinTol(ui.calc_photon_flux(), 0.000469964, 1e-4)
        self.assertEqualWithinTol(ui.calc_energy_flux(), 9.614847e-13, 1e-4)
        self.assertEqualWithinTol(ui.calc_data_sum(), 706.85714092, 1e-4)
        self.assertEqualWithinTol(ui.calc_model_sum(), 638.45693377, 1e-4)
        self.assertEqualWithinTol(ui.calc_source_sum(), 0.046996409, 1e-4)
        self.assertEqualWithinTol(ui.eqwidth(self.locals["p1"], ui.get_source()), -0.57731725, 1e-4)
        self.assertEqualWithinTol(
            ui.calc_kcorr([1, 1.2, 1.4, 1.6, 1.8, 2], 0.5, 2),
            [0.93341286, 0.93752836, 0.94325233, 0.94990140, 0.95678054, 0.96393515],
            1e-4,
        )

        self.assertEqual(ui.get_fit_results().nfev, 22)
        self.assertEqual(ui.get_fit_results().numpoints, 44)
        self.assertEqual(ui.get_fit_results().dof, 42)
コード例 #6
0
    def cmp_thread(fit_result, p1, covarerr):
        assert fit_result.statval == approx(37.9079, rel=1e-4)
        assert fit_result.rstat == approx(0.902569, rel=1e-4)
        assert fit_result.qval == approx(0.651155, rel=1e-4)
        assert fit_result.nfev == 22
        assert fit_result.numpoints == 44
        assert fit_result.dof == 42
        p1.gamma.val == approx(2.15852, rel=1e-4)
        p1.ampl.val == approx(0.00022484, rel=1e-4)

        assert ui.calc_photon_flux() == approx(0.000469964, rel=1e-4)
        assert ui.calc_energy_flux() == approx(9.614847e-13, rel=1e-4)
        assert ui.calc_data_sum() == approx(706.85714092, rel=1e-4)
        assert ui.calc_model_sum() == approx(638.45693377, rel=1e-4)
        assert ui.calc_source_sum() == approx(0.046996409, rel=1e-4)

        calc = ui.eqwidth(p1, ui.get_source())
        assert calc == approx(-0.57731725, rel=1e-4)

        calc = ui.calc_kcorr([1, 1.2, 1.4, 1.6, 1.8, 2], 0.5, 2)
        expected = [
            0.93132747, 0.9352768, 0.94085917, 0.94738472, 0.95415463,
            0.96121113
        ]
        assert calc == approx(expected, rel=1e-4)
コード例 #7
0
    def test_pha_intro(self):
        self.run_thread('pha_intro')
        # astro.ui imported as ui, instead of
        # being in global namespace
        fit_results = ui.get_fit_results()
        covarerr = sqrt(fit_results.extra_output['covar'].diagonal())
        assert covarerr[0] == approx(0.0790393, rel=1e-4)
        assert covarerr[1] == approx(1.4564e-05, rel=1e-4)
        assert fit_results.statval == approx(37.9079, rel=1e-4)
        assert fit_results.rstat == approx(0.902569, rel=1e-4)
        assert fit_results.qval == approx(0.651155, rel=1e-4)
        assert self.locals['p1'].gamma.val == approx(2.15852, rel=1e-4)
        assert self.locals['p1'].ampl.val == approx(0.00022484, rel=1e-4)

        assert ui.calc_photon_flux() == approx(0.000469964, rel=1e-4)
        assert ui.calc_energy_flux() == approx(9.614847e-13, rel=1e-4)
        assert ui.calc_data_sum() == approx(706.85714092, rel=1e-4)
        assert ui.calc_model_sum() == approx(638.45693377, rel=1e-4)
        assert ui.calc_source_sum() == approx(0.046996409, rel=1e-4)

        calc = ui.eqwidth(self.locals['p1'], ui.get_source())
        assert calc == approx(-0.57731725, rel=1e-4)

        calc = ui.calc_kcorr([1, 1.2, 1.4, 1.6, 1.8, 2], 0.5, 2)
        expected = [0.93341286, 0.93752836, 0.94325233,
                    0.94990140, 0.95678054, 0.96393515]
        assert calc == approx(expected, rel=1e-4)

        self.assertEqual(ui.get_fit_results().nfev, 22)
        self.assertEqual(ui.get_fit_results().numpoints, 44)
        self.assertEqual(ui.get_fit_results().dof, 42)
コード例 #8
0
def test_calc_flux_pha_density_bin_edges(clean_astro_ui):
    """What happens when filter edges partially overlap bins? flux density

    Later tests may also cover this condition, but here we use
    faked data that is made to make the behavior "obvious".
    """

    chans = np.arange(1, 11, 1, dtype=np.int)
    counts = np.zeros(chans.size, dtype=np.int)

    # "perfect" response
    energies = np.arange(1, 12, 1)
    elo, ehi = energies[:-1], energies[1:]
    flat = np.ones(chans.size, dtype=np.int)

    d = ui.DataPHA('example', chans, counts)
    arf = ui.create_arf(elo, ehi, flat)
    rmf = ui.create_rmf(elo,
                        ehi,
                        e_min=elo,
                        e_max=elo,
                        startchan=1,
                        fname=None)

    d.set_arf(arf)
    d.set_rmf(rmf)
    ui.set_data(1, d)

    ui.set_source(ui.powlaw1d.pl)
    pl.ampl = 1e-4
    pl.gamma = 1.7

    # choose an energy that is not equal to the center of the bin
    # just to check how this is handled
    #
    pdens = ui.calc_photon_flux(2.6)
    edens = ui.calc_energy_flux(2.6)

    enscale = sherpa.astro.utils._charge_e

    # Evaluate the model over the bin 2-3 keV; since the grid
    # has a width of 1 keV we do not need to divide by the bin
    # width when calculating the density.
    #
    ymdl = pl([2], [3])
    expected_pdens = ymdl.sum()
    expected_edens = enscale * 2.5 * expected_pdens

    # Prior to fixing #619, Sherpa returns 0 for both densities
    #
    assert pdens == pytest.approx(expected_pdens)

    # check against log as values ~ 5e-13
    edens = np.log10(edens)
    expected_edens = np.log10(expected_edens)
    assert edens == pytest.approx(expected_edens)
コード例 #9
0
ファイル: fitlinelist.py プロジェクト: hamogu/filili
def fit_multiplets(multipletlist, id = None, outpath = None, plot = False, delta_lam = .2):
    #
    n_lines =  np.sum([len(mult['wave']) for mult in multipletlist])
    result = np.zeros(n_lines, dtype = {'names': ['multname', 'linename', 'wave', 'flux', 'errup', 'errdown', 'photons', 'photonflux'], 'formats': ['S30', 'S30', 'f4', 'f4', 'f4', 'f4', 'f4', 'f4']})
    currentline = 0
    #
    for mult in multipletlist:
        if outpath is not None:
            outfile = os.path.join(outpath, filter(lambda x: x.isalnum(), mult['name']))
        else:
            outfile = None
        fit_lines(mult, id, delta_lam = delta_lam, plot = plot, outfile = outfile)
        #    
        ui.conf(id)
        conf_res = ui.get_conf_results()
        source = ui.get_source(id)
        #set all ampl to 0 and only for 1 line to real value
        set_all_val('c0', 0., id)
        for lname, lfili, lwave in zip(mult['linename'], mult['fililiname'], mult['wave']):
            print 'Fitting line '+str(currentline+1)+'/'+str(n_lines)
            par = ui.get_model_component(lfili)
            indconf_res = ( np.array(conf_res.parnames) == lfili+'.ampl').nonzero()[0]
            set_all_val('ampl', 0., id)
            
            par.ampl.val = conf_res.parvals[indconf_res]
            counts = ui.calc_model_sum(None, None, id)
            #
            print(lname, counts)
            photonflux = ui.calc_photon_flux(None, None, id)
            # determine scaling between ampl and flux
            par.ampl.val = 1
            amp2flux = ui.calc_energy_flux(None, None, id)

            par.ampl.val = conf_res.parvals[indconf_res]
            #
            val = conf_res.parvals[indconf_res] * amp2flux
            errdown = conf_res.parmins[indconf_res] * amp2flux if conf_res.parmins[indconf_res] else np.nan
            errup  = conf_res.parmaxes[indconf_res] * amp2flux if conf_res.parmaxes[indconf_res] else np.nan
            #
            result[currentline] = (mult['name'], lname, lwave, val, errup, errdown, counts, photonflux)
            #
            currentline +=1
    return result
コード例 #10
0
def test_calc_flux_pha_bin_edges(clean_astro_ui):
    """What happens when filter edges partially overlap bins?

    Later tests may also cover this condition, but here we use
    faked data that is made to make the behavior "obvious".
    """

    chans = np.arange(1, 11, 1, dtype=np.int)
    counts = np.zeros(chans.size, dtype=np.int)

    # "perfect" response
    energies = np.arange(1, 12, 1)
    elo, ehi = energies[:-1], energies[1:]
    flat = np.ones(chans.size, dtype=np.int)

    d = ui.DataPHA('example', chans, counts)
    arf = ui.create_arf(elo, ehi, flat)
    rmf = ui.create_rmf(elo,
                        ehi,
                        e_min=elo,
                        e_max=elo,
                        startchan=1,
                        fname=None)

    d.set_arf(arf)
    d.set_rmf(rmf)
    ui.set_data(1, d)

    ui.set_source(ui.powlaw1d.pl)
    pl.ampl = 1e-4
    pl.gamma = 1.7

    # Evaluate the model on the energy grid
    ymdl = pl(elo, ehi)

    pflux = ui.calc_photon_flux(2.6, 7.8)
    eflux = ui.calc_energy_flux(2.6, 7.8)

    enscale = sherpa.astro.utils._charge_e

    # Left in as notes:
    #
    # This are the true values. Given that the edge bins (should be)
    # using linear interpolation, how close do we get to this?
    #
    # gterm1 = 1.0 - 1.7
    # gterm2 = 2.0 - 1.7
    # true_pflux = 1e-4 * (7.8**gterm1 - 2.6**gterm1) / gterm1
    # true_eflux = enscale * 1e-4 * (7.8**gterm2 - 2.6**gterm2) / gterm2
    #
    # Comparing the linear interpolation scheme to that used by
    # Sherpa prior to fixing #619, I find
    #
    # Photon fluxes:
    #     linear_interp / true_pflux = 1.042251
    #     sherpa        / true_pflux = 0.837522
    #
    # Energy fluxes:
    #     linear_interp / true_eflux = 1.017872
    #     sherpa        / true_eflux = 0.920759
    #
    scale = np.asarray([0.0, 0.4, 1.0, 1.0, 1.0, 1.0, 0.8, 0, 0.0, 0.0])
    expected_pflux = (ymdl * scale).sum()

    emid = enscale * (elo + ehi) / 2
    expected_eflux = (emid * ymdl * scale).sum()

    assert pflux == pytest.approx(expected_pflux)

    # check against log as values ~ 3e-13
    eflux = np.log10(eflux)
    expected_eflux = np.log10(expected_eflux)
    assert eflux == pytest.approx(expected_eflux)
コード例 #11
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)
コード例 #12
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)