コード例 #1
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)
コード例 #2
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)
コード例 #3
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)
コード例 #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 test_fake_pha_multi_file(make_data_path, clean_astro_ui, reset_seed):
    '''Test fake_pha using multiple real input files.

    Note that HEG orders -1 and +1 should really be treated spearately,
    but for this test we just need two files to load.
    '''

    np.random.seed(22349)

    ui.set_source("gauss1d.g1")
    g1 = ui.get_source()
    g1.pos = 3
    g1.FWHM = .5

    ui.fake_pha(None, [
        make_data_path('3c120_heg_-1.arf.gz'),
        make_data_path('3c120_heg_1.arf.gz')
    ], [
        make_data_path('3c120_heg_-1.rmf.gz'),
        make_data_path('3c120_heg_1.rmf.gz')
    ], 500.)
    data = ui.get_data()
    # Even with noise, maximum should be close to 3 keV
    assert np.isclose(data.get_x()[np.argmax(data.counts)], 3., atol=.2)

    # This is not a test from first principles, but at least a check of
    # the current behaviour
    assert data.counts.sum() > 5000
    assert data.counts.sum() < 10000
コード例 #7
0
ファイル: utils.py プロジェクト: nplee/ciao-contrib
    def __init__(self, id=None, fluxtype="photon"):
        "If id is None the default id will be used."

        if id is None:
            self.id = ui.get_default_id()
        else:
            self.id = id

        if fluxtype in self._valid_fluxtypes:
            self.fluxtype = fluxtype
        else:
            emsg = "fluxtype set to {} but must be one of: {}".format(
                fluxtype, " ".join(self._valid_fluxtypes))
            raise ValueError(emsg)

        # Set up the xlo/xhi/xmid arrays
        d = ui.get_data(self.id)
        self._calc_bins(d)
        self._apply_mask(d)

        # Important to use get_source and not get_model as we do not
        # want to apply any instrument model to the evaluation.
        #
        # Note that we do not hold onto the model expression object,
        # which is probably not an issue here.
        #
        mdl = ui.get_source(id)
        self.modelexpr = mdl.name

        # We do not use xlo/xhi but the _xlo/_xhi attributes which
        # contain an extra bin, in case of X-Spec models
        #
        src = mdl(self._xlo, self._xhi)[:-1]
        if np.any(src < 0.0):
            emsg = "There are negative values in your source " + \
                "model (id={0})!".format(self.id)
            raise RuntimeError(emsg)
        if np.all(src <= 0.0):
            emsg = "The source model for id={0} ".format(self.id) + \
                "evaluates to 0!"
            raise RuntimeError(emsg)

        # Conversion to a single datatype is a bit excessive here.
        #
        dtype = src.dtype

        if self.fluxtype == "erg":
            norm = _charge_e * np.sum(src * self.xmid)
        else:
            norm = np.sum(src)

        self.weight = src / norm

        self.weight = self.weight.astype(dtype)
        self.xlo = self.xlo.astype(dtype)
        self.xhi = self.xhi.astype(dtype)
        self.xmid = self.xmid.astype(dtype)
コード例 #8
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
コード例 #9
0
def image_model_sherpa(exposure,
                       psf,
                       sources,
                       model_image,
                       overwrite):
    """Compute source model image with Sherpa.

    Inputs:

    * Source list (JSON file)
    * PSF (JSON file)
    * Exposure image (FITS file)

    Outputs:

    * Source model flux image (FITS file)
    * Source model excess image (FITS file)
    """
    import sherpa.astro.ui as sau
    from ..image.models.psf import Sherpa
    from ..image.models.utils import read_json

    log.info('Reading exposure: {0}'.format(exposure))
    # Note: We don't really need the exposure as data,
    # but this is a simple way to init the dataspace to the correct shape
    sau.load_data(exposure)
    sau.load_table_model('exposure', exposure)

    log.info('Reading PSF: {0}'.format(psf))
    Sherpa(psf).set()

    log.info('Reading sources: {0}'.format(sources))
    read_json(sources, sau.set_source)

    name = sau.get_source().name
    full_model = 'exposure * psf({})'.format(name)
    sau.set_full_model(full_model)

    log.info('Computing and writing model_image: {0}'.format(model_image))
    sau.save_model(model_image, clobber=overwrite)
    sau.clean()
    sau.delete_psf()
コード例 #10
0
ファイル: test_wstat.py プロジェクト: DougBurke/sherpa
    def setUp(self):

        self._old_logger_level = logger.getEffectiveLevel()
        logger.setLevel(logging.ERROR)

        ui.set_stat('wstat')

        infile1 = self.make_path('3c273.pi')
        infile2 = self.make_path('9774.pi')
        ui.load_pha(1, infile1)
        ui.load_pha(2, infile2)

        # Since 9774.pi isn't grouped, group it. Note that this
        # call groups the background to 20 counts per bin. In this
        # case we do not want that; instead we want to use the same
        # grouping scheme as the source file.
        #
        # Note: this is related to issue 227
        #
        ui.group_counts(2, 20)
        ui.set_grouping(2, bkg_id=1, val=ui.get_grouping(2))

        # There's no need to have the same model in both datasets,
        # but assume the same source model can be used, with a
        # normalization difference.
        #
        ui.set_source(1, ui.powlaw1d.pl1)
        ui.set_source(2, ui.const1d.c2 * ui.get_source(1))

        # The powerlaw slope and normalization are
        # intended to be "a reasonable approximation"
        # to the data, just to make sure that any statistic
        # calculation doesn't blow-up too much.
        #
        # Note: the model values for 3c273 are slighly different
        #       to the single-PHA-file case, so stat results are
        #       slightly different
        #
        ui.set_par("pl1.gamma", 1.7)
        ui.set_par("pl1.ampl", 1.6e-4)
        ui.set_par("c2.c0", 45)
コード例 #11
0
ファイル: test_wstat.py プロジェクト: wsf1990/sherpa
    def setUp(self):

        self._old_logger_level = logger.getEffectiveLevel()
        logger.setLevel(logging.ERROR)

        ui.set_stat('wstat')

        infile1 = self.make_path('3c273.pi')
        infile2 = self.make_path('9774.pi')
        ui.load_pha(1, infile1)
        ui.load_pha(2, infile2)

        # Since 9774.pi isn't grouped, group it. Note that this
        # call groups the background to 20 counts per bin. In this
        # case we do not want that; instead we want to use the same
        # grouping scheme as the source file.
        #
        # Note: this is related to issue 227
        #
        ui.group_counts(2, 20)
        ui.set_grouping(2, bkg_id=1, val=ui.get_grouping(2))

        # There's no need to have the same model in both datasets,
        # but assume the same source model can be used, with a
        # normalization difference.
        #
        ui.set_source(1, ui.powlaw1d.pl1)
        ui.set_source(2, ui.const1d.c2 * ui.get_source(1))

        # The powerlaw slope and normalization are
        # intended to be "a reasonable approximation"
        # to the data, just to make sure that any statistic
        # calculation doesn't blow-up too much.
        #
        # Note: the model values for 3c273 are slighly different
        #       to the single-PHA-file case, so stat results are
        #       slightly different
        #
        ui.set_par("pl1.gamma", 1.7)
        ui.set_par("pl1.ampl", 1.6e-4)
        ui.set_par("c2.c0", 45)
コード例 #12
0
ファイル: sherpa_model_image.py プロジェクト: klepser/gammapy
def sherpa_model_image(exposure, psf, sources, model_image, overwrite):
    """Compute source model image with Sherpa.

    Inputs:

    * Source list (JSON file)
    * PSF (JSON file)
    * Exposure image (FITS file)

    Outputs:

    * Source model flux image (FITS file)
    * Source model excess image (FITS file)
    """
    import logging
    logging.basicConfig(level=logging.DEBUG,
                        format='%(levelname)s - %(message)s')
    import sherpa.astro.ui as sau  # @UnresolvedImport
    from ..morphology.psf import Sherpa
    from ..morphology.utils import read_json

    logging.info('Reading exposure: {0}'.format(exposure))
    # Note: We don't really need the exposure as data,
    # but this is a simple way to init the dataspace to the correct shape
    sau.load_data(exposure)
    sau.load_table_model('exposure', exposure)

    logging.info('Reading PSF: {0}'.format(psf))
    Sherpa(psf).set()

    logging.info('Reading sources: {0}'.format(sources))
    read_json(sources, sau.set_source)

    name = sau.get_source().name
    full_model = 'exposure * psf({})'.format(name)
    sau.set_full_model(full_model)

    logging.info('Computing and writing model_image: {0}'.format(model_image))
    sau.save_model(model_image, clobber=overwrite)
コード例 #13
0
def write_all(filename='results.json'):
    """Dump source, fit results and conf results to a JSON file.

    http://www.astropython.org/snippet/2010/7/Save-sherpa-fit-and-conf-results-to-a-JSON-file
    """
    import sherpa.astro.ui as sau
    out = dict()

    if 0:
        src = sau.get_source()
        src_par_attrs = ('name', 'frozen', 'modelname', 'units', 'val',
                         'fullname')
        out['src'] = dict(name=src.name,
                          pars=[
                              dict((attr, getattr(par, attr))
                                   for attr in src_par_attrs)
                              for par in src.pars
                          ])

    try:
        fit_attrs = ('methodname', 'statname', 'succeeded', 'statval',
                     'numpoints', 'dof', 'rstat', 'qval', 'nfev', 'message',
                     'parnames', 'parvals')
        fit = sau.get_fit_results()
        out['fit'] = dict((attr, getattr(fit, attr)) for attr in fit_attrs)
    except Exception as err:
        print(err)

    try:
        conf_attrs = ('datasets', 'methodname', 'fitname', 'statname', 'sigma',
                      'percent', 'parnames', 'parvals', 'parmins', 'parmaxes',
                      'nfits')
        conf = sau.get_conf_results()
        out['conf'] = dict((attr, getattr(conf, attr)) for attr in conf_attrs)
    except Exception as err:
        print(err)

    try:
        covar_attrs = ('datasets', 'methodname', 'fitname', 'statname',
                       'sigma', 'percent', 'parnames', 'parvals', 'parmins',
                       'parmaxes', 'nfits')
        covar = sau.get_covar_results()
        out['covar'] = dict(
            (attr, getattr(covar, attr)) for attr in covar_attrs)
    except Exception as err:
        print(err)

    if 0:
        out['pars'] = []
        for par in src.pars:
            fullname = par.fullname
            if any(fullname == x['name'] for x in out['pars']):
                continue  # Parameter was already processed
            outpar = dict(name=fullname, kind=par.name)

            # None implies no calculated confidence interval for Measurement
            parmin = None
            parmax = None
            try:
                if fullname in conf.parnames:  # Confidence limits available from conf
                    i = conf.parnames.index(fullname)
                    parval = conf.parvals[i]
                    parmin = conf.parmins[i]
                    parmax = conf.parmaxes[i]
                if parmin is None:
                    parmin = -float(
                        'inf'
                    )  # None from conf means infinity, so set accordingly
                if parmax is None:
                    parmax = float('inf')
                elif fullname in fit.parnames:  # Conf failed or par is uninteresting and wasn't sent to conf
                    i = fit.parnames.index(fullname)
                    parval = fit.parvals[i]
                else:  # No fit or conf value (maybe frozen)
                    parval = par.val
            except Exception as err:
                print(err)

            out['pars'].append(outpar)
    if filename is None:
        return out
    else:
        json.dump(out, open(filename, 'w'), sort_keys=True, indent=4)
コード例 #14
0
ファイル: chart.py プロジェクト: nplee/ciao-contrib
def _get_chart_spectrum(id=None,
                        elow=None,
                        ehigh=None,
                        ewidth=None,
                        norm=None):
    """Helper routine for *_chart_spectrum."""

    # What source expression are we using?
    # get_model/source will throw an IdentifierErr if the expression
    # is not defined; we do not, at present catch/re-throw this
    #
    if id is None:
        id = s.get_default_id()

    mdl = s.get_source(id)

    # What energy grid to use?  Since we do not want to restrict users
    # to only using PHA datasets (i.e. if I just want to create
    # something simple) then we have to look for a range of errors
    # from get_arf
    #
    if elow is None or ehigh is None or ewidth is None:
        try:
            arf = s.get_arf(id)
        except (IdentifierErr, ArgumentErr):
            # a) PHA dataset, no ARF
            # b) Assume this means the dataset is not derived from the
            #    PHA class
            arf = None

        if arf is None:
            emsg = "No ARF found for dataset {} ".format(repr(id)) + \
                "so unable to create energy grid"
            raise TypeError(emsg)

        if elow is None:
            elow = arf.energ_lo[0]
        if ehigh is None:
            ehigh = arf.energ_hi[-1]
        if ewidth is None:
            # Assume constant grid spacing in the ARF
            de = arf.energ_hi[-1] - arf.energ_lo[0]
            nelem = np.size(arf.energ_lo)
            ewidth = de * 1.0 / nelem

    if elow >= ehigh:
        emsg = "elow is >= ehigh: " + \
            "elow={}  ehigh={}".format(elow, ehigh)
        raise TypeError(emsg)
    if ewidth <= 0.0:
        raise TypeError("ewidth is <= 0.0: ewidth={0}".format(ewidth))

    # The following is wasteful if we have an ARF and the user
    # supplies no elow, ehigh, or ewidth arguments.
    #
    # Should I check that nbins is a sensible number (e.g. >= 2)?
    #
    nbins = 1 + np.rint((ehigh - elow) / ewidth)
    erange = elow + ewidth * np.arange(nbins)
    elo = erange[:-1]
    ehi = erange[1:]

    flux = mdl(elo, ehi)
    emid = 0.5 * (ehi + elo)

    # do we want to renormalize?
    if norm is not None:
        flux *= norm
    return {
        "x": emid,
        "xlo": elo,
        "xhi": ehi,
        "y": flux,
        "id": id,
        "model": mdl.name
    }
コード例 #15
0
ファイル: fitlinelist.py プロジェクト: hamogu/filili
def set_all_val(name, val, id = None):
    'e.g. set_all_val("ampl", 0)'
    source = ui.get_source(id)
    for par in source.pars:
        if par.name == name:
            par.val = val
コード例 #16
0
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)
コード例 #17
0
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)
コード例 #18
0
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)
コード例 #19
0
ファイル: utils.py プロジェクト: nplee/ciao-contrib
def estimate_weighted_expmap(id=None,
                             arf=None,
                             elo=None,
                             ehi=None,
                             specresp=None,
                             fluxtype="photon",
                             par=None,
                             pvals=None):
    """Estimate the weighted exposure map value for an ARF.

    Parameters
    ----------
    id : int, string, or None
        The Sherpa dataset to use. If ``None`` then the default
        dataset is used.
    arf : string, TABLECrate, or None
        The ARF to use. It must contain the following columns:
        ``energ_lo``, ``energ_hi``, and ``specresp``.
    elo, ehi, specresp : array of numbers or None
        The ARF, where the bin edges are in KeV and the response is
        in cm^2. These are only checked if arf is None, in which
        case all three must be given and have the same size
        (one dimensional).
    fluxtype : 'photon' or 'erg'
        The units of the exposure map are
        cm^2 count / ``fluxtype``. The default is ``photon``.
    par : Sherpa parameter object or None
        If not given then the exposure map is calculated at the
        current parameter settings. If given, it is the Sherpa
        parameter to loop over, using pvals (which must be set).
    pvals : array of numbers or None
        If par is set, calcualte the exposure map at the current
        parameter settings whilst setting the par parameter to
        each of the values in pvals. The parameter value is reset
        to its original value when the routine exits.

    Return
    ------
    expmap : scalar or array of numbers
        When par is None then a scalar, otherwise an array the same
        size as pvals.

    See Also
    --------
    get_instmap_weights
    plot_instmap_weights
    save_instmap_weights

    Notes
    -----
    The ARF is interpolated onto the energy grid of the dataspace.

    Examples
    --------

    Calculate the exposure map over the range gamma = 0.1 to 5,
    with 0.1 step increments, for an absorbed power-law model and
    with the ARF in the file "arf.fits".

    >>> dataspace1d(0.3, 8.0, 0.1)
    >>> set_source(xsphabs.gal * powlaw1d.pl)
    >>> gal.nh = 0.087
    >>> pl.gamma = 1.2
    >>> gvals = np.arange(0.5,5,0.1)
    >>> evals = estimate_weighted_expmap(arf="arf.fits", par=pl.gamma,
                                         pvals=gvals)

    """

    # Usage errors. We can not catch them all before doing actual
    # work.
    #
    if arf is None and \
       (elo is not None or ehi is not None or specresp is not None):
        # we only worry about elo/ehi/specresp if arf is NOT given
        if elo is None or ehi is None or specresp is None:
            emsg = "Missing one or more of elo, ehi, and specresp."
            raise TypeError(emsg)

    if id is None:
        id = ui.get_default_id()

    if par is not None or pvals is not None:

        if par is None or pvals is None:
            emsg = "Either both par and pvals are set or they " + \
                "are both None."
            raise TypeError(emsg)

        if not isinstance(par, Parameter):
            emsg = "par argument must be a Sherpa model parameter."
            raise TypeError(emsg)

        if not hasattr(pvals, "__iter__"):
            emsg = "pvals argument must be an iterable (array/list)."
            raise TypeError(emsg)

        smdl = ui.get_source(id)
        if par not in smdl.pars:
            emsg = "par argument is not a parameter of the " + \
                "source model"
            raise TypeError(emsg)

    wgts = get_instmap_weights(id, fluxtype=fluxtype)
    if isinstance(wgts, InstMapWeights1DInt) and arf is None and \
            elo is None:
        emsg = "The arf parameter or the elo,ehi,specresp " + \
            "parameters must be given."
        raise TypeError(emsg)

    if arf is None:
        if elo is None:
            args = []
        else:
            args = [elo, ehi, specresp]
    else:
        args = [arf]

    if par is None:
        return wgts.estimate_expmap(*args)

    else:
        # Ugh: we have to create an object for each evaluation, which
        # is rather wasteful.
        #
        orig = par.val
        out = []
        try:
            for pval in pvals:
                par.val = pval
                wgts = get_instmap_weights(id, fluxtype=fluxtype)
                out.append(wgts.estimate_expmap(*args))

        finally:
            par.val = orig

        return np.asarray(out)
コード例 #20
0
ファイル: _utils_old.py プロジェクト: cdeil/gammapy
def write_all(filename='results.json'):
    """Dump source, fit results and conf results to a JSON file.
    http://www.astropython.org/snippet/2010/7/Save-sherpa-fit-and-conf-results-to-a-JSON-file
    """
    import sherpa.astro.ui as sau
    out = dict()

    if 0:
        src = sau.get_source()
        src_par_attrs = ('name', 'frozen', 'modelname', 'units', 'val', 'fullname')
        out['src'] = dict(name=src.name,
                          pars=[dict((attr, getattr(par, attr)) for attr in src_par_attrs)
                                for par in src.pars])

    try:
        fit_attrs = ('methodname', 'statname', 'succeeded', 'statval', 'numpoints', 'dof',
                     'rstat', 'qval', 'nfev', 'message', 'parnames', 'parvals')
        fit = sau.get_fit_results()
        out['fit'] = dict((attr, getattr(fit, attr)) for attr in fit_attrs)
    except Exception as err:
        print(err)

    try:
        conf_attrs = ('datasets', 'methodname', 'fitname', 'statname', 'sigma', 'percent',
                      'parnames', 'parvals', 'parmins', 'parmaxes', 'nfits')
        conf = sau.get_conf_results()
        out['conf'] = dict((attr, getattr(conf, attr)) for attr in conf_attrs)
    except Exception as err:
        print(err)

    try:
        covar_attrs = ('datasets', 'methodname', 'fitname', 'statname', 'sigma', 'percent',
                       'parnames', 'parvals', 'parmins', 'parmaxes', 'nfits')
        covar = sau.get_covar_results()
        out['covar'] = dict((attr, getattr(covar, attr)) for attr in covar_attrs)
    except Exception as err:
        print(err)

    if 0:
        out['pars'] = []
        for par in src.pars:
            fullname = par.fullname
            if any(fullname == x['name'] for x in out['pars']):
                continue  # Parameter was already processed
            outpar = dict(name=fullname, kind=par.name)

            # None implies no calculated confidence interval for Measurement
            parmin = None
            parmax = None
            try:
                if fullname in conf.parnames:  # Confidence limits available from conf
                    i = conf.parnames.index(fullname)
                    parval = conf.parvals[i]
                    parmin = conf.parmins[i]
                    parmax = conf.parmaxes[i]
                if parmin is None:
                    parmin = -float('inf')  # None from conf means infinity, so set accordingly
                if parmax is None:
                    parmax = float('inf')
                elif fullname in fit.parnames:  # Conf failed or par is uninteresting and wasn't sent to conf
                    i = fit.parnames.index(fullname)
                    parval = fit.parvals[i]
                else:  # No fit or conf value (maybe frozen)
                    parval = par.val
            except Exception as err:
                print(err)

            out['pars'].append(outpar)
    if filename is None:
        return out
    else:
        json.dump(out, open(filename, 'w'), sort_keys=True, indent=4)