Exemplo n.º 1
0
    def fit(self, current):
        self._fit.model.thawedpars = current

        # nm = NelderMead()
        # nm.config['iquad'] = 0
        # nm.config['finalsimplex'] = 1

        # lm = LevMar()
        # lm.config['maxfev'] = 5

        cv = Covariance()

        # Use the fit method defined before called get_draws().  This way
        # the user does not have to pass in the fitting method and method
        # options.
        fit = Fit(self._fit.data, self._fit.model, self._fit.stat,
                  self._fit.method, cv)

        # Note: there is no check that the fit has converged
        fit.fit()
        covar_result = fit.est_errors()
        sigma = np.array(covar_result.extra_output)

        if np.isnan(sigma).any():
            raise CovarError("NaNs found in covariance matrix")

        # cache the fitting scales
        self._sigma = sigma
Exemplo n.º 2
0
def test_regrid_binaryop_1d(reset_seed):
    """issue #762, Cannot regrid a composite model (BinaryOpModel)"""

    np.random.seed(0)
    leastsq = LeastSq()
    levmar = LevMar()
    mygauss = MyGauss()
    myconst = MyConst1D()
    mymodel = mygauss + myconst
    x = np.linspace(-5., 5., 5)
    err = 0.25
    y = mymodel(x) + np.random.normal(mygauss.pos.val, err, x.shape)
    mygauss.counter = 0
    myconst.counter = 0
    data = Data1D('one', x, y)
    fit = Fit(data, mymodel, leastsq, levmar)
    result = fit.fit()
    assert result.numpoints == x.size
    assert result.statval < 1.0
    assert mygauss.counter == myconst.counter
    assert (result.nfev + 4) * x.size == mygauss.counter

    mygauss.counter = 0
    myconst.counter = 0
    x_regrid = np.linspace(-5., 5., 25)
    mymodel_regrid = mymodel.regrid(x_regrid)
    fit = Fit(data, mymodel_regrid, leastsq, levmar)
    result = fit.fit()
    assert result.numpoints == x.size
    assert result.statval < 1.0
    assert mygauss.counter == myconst.counter
    assert (result.nfev + 4) * x_regrid.size == mygauss.counter
Exemplo n.º 3
0
def test_cache():
    """To make sure that the runtime fit(cache=???) works"""

    x = np.array([1.0, 2.0, 3.0])
    model = MyCacheTestModel()
    par = np.array([1.1, 2.0, 3.0])
    y = model.calc(par, x)

    data = Data1D('tmp', x, y)
    fit = Fit(data, model, LeastSq())
    fit.fit(cache=False)
Exemplo n.º 4
0
 def tst_low_level(self, thaw_c1):
     if thaw_c1:
         self.mdl.c1.thaw()
     self.mdl.c2.thaw()
     f = Fit(self.data, self.mdl, estmethod=Confidence())
     self.mdl.c2 = 1
     f.fit()
     if not thaw_c1:
         self.mdl.c1.thaw()
         f.fit()
     result = f.est_errors()
     self.cmp_results(result)
Exemplo n.º 5
0
def test_data2d_int_eval_model_to_fit(array_sizes_fixture):
    from sherpa.fit import Fit
    from sherpa.optmethods import LevMar
    from sherpa.stats import Chi2
    from sherpa.models import Gauss2D

    x0, x1, dx, y = array_sizes_fixture
    data2 = Data2DInt('name', x0.flatten(), x0.flatten() + dx, x1.flatten(), x1.flatten() + dx, y.flatten(),
                      staterror=numpy.sqrt(y).flatten())

    model2 = Gauss2D()
    fitter = Fit(data2, model2, Chi2(), LevMar())
    fitter.fit()  # Failed in Sherpa 4.11.0
Exemplo n.º 6
0
 def test_mycash_nobkgdata_modelhasbkg(self):
     data = self.bkg
     fit = Fit(data, self.model, MyCashWithBkg(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_mycashnobkg_results_bench,
                          results,
                          tol=1.0e-3)
Exemplo n.º 7
0
def setup():
    data = Data1D('fake', _x, _y, _err)

    g1 = Gauss1D('g1')
    g1.fwhm.set(1.0, _tiny, _max, frozen=False)
    g1.pos.set(1.0, -_max, _max, frozen=False)
    g1.ampl.set(1.0, -_max, _max, frozen=False)
    p1 = PowLaw1D('p1')
    p1.gamma.set(1.0, -10, 10, frozen=False)
    p1.ampl.set(1.0, 0.0, _max, frozen=False)
    p1.ref.set(1.0, -_max, _max, frozen=True)
    model = p1 + g1

    method = LevMar()
    method.config['maxfev'] = 10000
    method.config['ftol'] = float(_eps)
    method.config['epsfcn'] = float(_eps)
    method.config['gtol'] = float(_eps)
    method.config['xtol'] = float(_eps)
    method.config['factor'] = float(100)

    fit = Fit(data, model, Chi2DataVar(), method, Covariance())
    results = fit.fit()

    for key in ["succeeded", "numpoints", "nfev"]:
        assert _fit_results_bench[key] == int(getattr(results, key))

    for key in ["rstat", "qval", "statval", "dof"]:
        # used rel and abs tol of 1e-7 with numpy allclose
        assert float(getattr(results,
                             key)) == pytest.approx(_fit_results_bench[key])

    for key in ["parvals"]:
        try:
            # used rel and abs tol of 1e-4 with numpy allclose
            assert getattr(results,
                           key) == pytest.approx(_fit_results_bench[key])
        except AssertionError:
            print('parvals bench: ', _fit_results_bench[key])
            print('parvals fit:   ', getattr(results, key))
            print('results', results)
            raise

    fields = [
        'data', 'model', 'method', 'fit', 'results', 'covresults', 'dof', 'mu',
        'num'
    ]
    out = namedtuple('Results', fields)

    out.data = data
    out.model = model
    out.method = method
    out.fit = fit
    out.results = results
    out.covresults = fit.est_errors()
    out.dof = results.dof
    out.mu = numpy.array(results.parvals)
    out.cov = numpy.array(out.covresults.extra_output)
    out.num = 10
    return out
Exemplo n.º 8
0
def test_simul_stat_fit(stat, hide_logging, reset_xspec, setup_two):
    data1 = setup_two['data_pi2278']
    data2 = setup_two['data_pi2286']
    model1 = setup_two['model_pi2278']
    model2 = setup_two['model_pi2286']
    data = DataSimulFit(name='data1data2', datasets=[data1, data2])
    model = SimulFitModel(name='model1model2', parts=[model1, model2])
    fit = Fit(data=data, model=model, stat=stat(), method=NelderMead())
    result = fit.fit()

    _fit_simul_datavarstat_results_bench = {
        'succeeded':
        1,
        'numpoints':
        18,
        'dof':
        15,
        'istatval':
        56609.70689926489,
        'statval':
        126.1509268988255,
        'parvals':
        numpy.array(
            [0.8417576197443695, 1.6496933246579941, 0.2383939869443424])
    }

    compare_results(_fit_simul_datavarstat_results_bench, result)
Exemplo n.º 9
0
def test_low_level(thaw_c1, setUp):
    data, mdl = setUp
    if thaw_c1:
        mdl.c1.thaw()

    mdl.c2.thaw()
    f = Fit(data, mdl, estmethod=Confidence())
    mdl.c2 = 1
    f.fit()

    if not thaw_c1:
        mdl.c1.thaw()
        f.fit()

    result = f.est_errors()
    cmp_results(result)
Exemplo n.º 10
0
def mwl_fit_low_level():
    """Use high-level Sherpa API.

    Low-level = no session, classes.

    Example: http://python4astronomers.github.io/fitting/low-level.html
    """
    fermi_data = FermiData().sherpa_data
    hess_data = IACTData().sherpa_data

    # spec_model = PowLaw1D('spec_model')
    spec_model = LogParabola('spec_model')
    spec_model.c1 = 0.5
    spec_model.c2 = 0.2
    spec_model.ampl = 5e-11

    data = DataSimulFit(name='global_data', datasets=[fermi_data, hess_data])
    # TODO: Figure out how to notice using the low-level API
    # data.notice(mins=1e-3, maxes=None, axislist=None)
    model = SimulFitModel(name='global_model', parts=[spec_model, spec_model])
    stat = FermiStat()
    method = LevMar()
    fit = Fit(data=data, model=model, stat=stat, method=method)
    result = fit.fit()

    # IPython.embed()
    return Bunch(results=result, model=spec_model)
Exemplo n.º 11
0
    def fit(self, current):
        self._fit.model.thawedpars = current

        # nm = NelderMead()
        # nm.config['iquad'] = 0
        # nm.config['finalsimplex'] = 1

        #lm = LevMar()
        #lm.config['maxfev'] = 5

        cv = Covariance()

        # Use the fit method defined before called get_draws().  This way the user
        # does not have to pass in the fitting method and method options.
        fit = Fit(self._fit.data, self._fit.model, self._fit.stat, self._fit.method,
                  cv)

        fit_result = fit.fit()
        covar_result = fit.est_errors()
        sigma = np.array(covar_result.extra_output)

        if np.isnan(sigma).any():
            raise CovarError("NaNs found in covariance matrix")

        # cache the fitting scales
        self._sigma = sigma
Exemplo n.º 12
0
def test_intproj(old_numpy_printing, override_plot_backend):
    p = plot.IntervalProjection()
    r = p._repr_html_()

    check_empty(r, 'IntervalProjection', nsummary=8)

    x = np.arange(5, 8, 0.5)
    y = np.asarray([2, 3, 4, 5, 4, 3])
    dy = y / 2
    d = Data1D('n n', x, y, staterror=dy)

    m = Const1D()

    fit = Fit(d, m, stat=Chi2())
    fr = fit.fit()
    assert fr.succeeded

    p.prepare(min=1, max=6, nloop=10)
    p.calc(fit, m.c0)

    r = p._repr_html_()
    assert r is not None

    if plot.backend.name == 'pylab':
        assert '<summary>IntervalProjection</summary>' in r
        assert '<svg ' in r
        return

    assert '<summary>IntervalProjection (8)</summary>' in r

    assert '<div class="dataname">x</div><div class="dataval">[ 1.        1.555556  2.111111  2.666667  3.222222  3.777778  4.333333  4.888889\n  5.444444  6.      ]</div>' in r
    assert '<div class="dataname">nloop</div><div class="dataval">10</div>' in r
Exemplo n.º 13
0
 def test_mycash_data_and_model_donothave_bkg(self):
     data = self.bkg
     fit = Fit(data, self.model, MyCashNoBkg(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_mycashnobkg_results_bench,
                          results,
                          tol=1.0e-3)
Exemplo n.º 14
0
    def call(self, niter, seed):

        pars = {}
        pars_index = {}
        index = 0
        for par in self.model.pars:
            if par.frozen is False:
                name = '%s.%s' % (par.modelname, par.name)
                pars_index[index] = name
                pars[name] = []
                index += 1

        data = self.data
        y = data.y
        x = data.x
        if type(data) == Data1DAsymmetricErrs:
            y_l = y - data.elo
            y_h = y + data.ehi
        elif isinstance(data, (Data1D,)):
            y_l = data.staterror
            y_h = data.staterror
        else:
            msg ="{0} {1}".format(ReSampleData.__name__, type(data))
            raise NotImplementedError(msg)

        numpy.random.seed(seed)
        for j in range(niter):
            ry = []
            for i in range(len(y_l)): 
                a = y_l[i]
                b = y_h[i]
                r = -1
                while r < a or r > b:
                    sigma = b - y[i]
                    u = numpy.random.random_sample()
                    if u < 0.5:
                        sigma=y[i]-a
                    r = numpy.random.normal(loc=y[i],scale=sigma,size=None)
                    if u < 0.5 and r > y[i]:
                        r = -1
                    if u > 0.5 and r < y[i]:
                        r = -1
                ry.append(r)

            # fit is performed for each simulated data point
            fit = Fit(Data1D('tmp', x, ry), self.model, LeastSq( ), LevMar())
            fit_result = fit.fit()

            for index, val in enumerate(fit_result.parvals):
                name = pars_index[index]
                pars[name].append(val)

        result = {}
        for index, name in pars_index.items():
            avg = numpy.average(pars[name])
            std = numpy.std(pars[name])
            print(name, ': avg =', avg, ', std =', std)
            result[name] = pars[name]

        return result
Exemplo n.º 15
0
 def test_same_cache(self):
     poly = Polynom1D()
     poly.pars[1].thaw()
     sdata = DataSimulFit('d1d2d3', (self.d1, self.d2, self.d3))
     smodel = SimulFitModel('same', (poly, poly, poly))
     sfit = Fit(sdata, smodel, method=NelderMead(), stat=Cash())
     result = sfit.fit()
     self.compare_results(self._fit_same_poly_bench, result)
Exemplo n.º 16
0
 def test_same_cache(self):
     poly = Polynom1D()
     poly.pars[1].thaw()
     sdata = DataSimulFit('d1d2d3', (self.d1, self.d2, self.d3))
     smodel = SimulFitModel('same', (poly, poly, poly))
     sfit = Fit(sdata, smodel, method=NelderMead(), stat=Cash())
     result = sfit.fit()
     self.compare_results(self._fit_same_poly_bench, result)
Exemplo n.º 17
0
    def fit(self):
        """Fit spectrum"""
        from sherpa.fit import Fit
        from sherpa.models import ArithmeticModel, SimulFitModel
        from sherpa.astro.instrument import Response1D
        from sherpa.data import DataSimulFit

        # Translate model to sherpa model if necessary
        if isinstance(self.model, models.SpectralModel):
            model = self.model.to_sherpa()
        else:
            model = self.model

        if not isinstance(model, ArithmeticModel):
            raise ValueError('Model not understood: {}'.format(model))

        # Make model amplitude O(1e0)
        val = model.ampl.val * self.FLUX_FACTOR ** (-1)
        model.ampl = val

        if self.fit_range is not None:
            log.info('Restricting fit range to {}'.format(self.fit_range))
            fitmin = self.fit_range[0].to('keV').value
            fitmax = self.fit_range[1].to('keV').value

        # Loop over observations
        pha = list()
        folded_model = list()
        nobs = len(self.obs_list)
        for ii in range(nobs):
            temp = self.obs_list[ii].to_sherpa()
            if self.fit_range is not None:
                temp.notice(fitmin, fitmax)
                if temp.get_background() is not None:
                    temp.get_background().notice(fitmin, fitmax)
            temp.ignore_bad()
            if temp.get_background() is not None:
                temp.get_background().ignore_bad()
            pha.append(temp)
            # Forward folding
            resp = Response1D(pha[ii])
            folded_model.append(resp(model) * self.FLUX_FACTOR)

        data = DataSimulFit('simul fit data', pha)
        fitmodel = SimulFitModel('simul fit model', folded_model)

        log.debug(fitmodel)
        fit = Fit(data, fitmodel, self.statistic)
        fitresult = fit.fit()
        log.debug(fitresult)
        # The model instance passed to the Fit now holds the best fit values
        covar = fit.est_errors()
        log.debug(covar)

        for ii in range(nobs):
            efilter = pha[ii].get_filter()
            shmodel = fitmodel.parts[ii]
            self.result[ii].fit = _sherpa_to_fitresult(shmodel, covar, efilter, fitresult)
Exemplo n.º 18
0
 def test_warning(self):
     ui.load_ascii_with_errors(1, self.gro_fname)
     data = ui.get_data(1)
     powlaw1d = PowLaw1D('p1')
     ui.set_model(powlaw1d)
     fit = Fit(data, powlaw1d)
     results = fit.fit()
     with warnings.catch_warnings(record=True) as w:
         warnings.simplefilter("always")
         ui.resample_data(1, 3)
         assert len(w) == 0
Exemplo n.º 19
0
 def test_gauss_gauss(self):
     g1, g2 = Gauss1D(), Gauss1D()
     g1.fwhm = 1.3
     g1.pos = 1.5
     g2.fwhm = 4.
     g2.pos = -2.0
     sdata = DataSimulFit('d4d5', (self.d4, self.d5))
     smodel = SimulFitModel('g1g2', (g1, g2))
     sfit = Fit(sdata, smodel, method=LevMar(), stat=LeastSq())
     result = sfit.fit()
     self.compare_results(self._fit_g2g2_bench, result)
Exemplo n.º 20
0
 def test_wstat(self):
     fit = Fit(self.data, self.model, WStat(), LevMar())
     results = fit.fit()
     # On a local linux machine I have to bump the tolerance to
     # 3e-4, but this isn't seen on Travis. The fit isn't
     # "great", so it may be that the results are sensitive to
     # numerical differences (e.g. as introduced with updated
     # compilers).
     # tol = 3e-4
     tol = 1e-6  # TODO: investigate difference
     self.compare_results(self._fit_wstat_results_bench, results, tol=tol)
Exemplo n.º 21
0
 def test_gauss_gauss(self):
     g1, g2 = Gauss1D(), Gauss1D()
     g1.fwhm = 1.3
     g1.pos = 1.5
     g2.fwhm = 4.
     g2.pos = -2.0
     sdata = DataSimulFit('d4d5', (self.d4, self.d5))
     smodel = SimulFitModel('g1g2', (g1, g2))
     sfit = Fit(sdata, smodel, method=LevMar(), stat=LeastSq())
     result = sfit.fit()
     self.compare_results(self._fit_g2g2_bench, result)
Exemplo n.º 22
0
 def test_simul_stat_fit(self):
     data1 = self.data_pi2278
     data2 = self.data_pi2286
     model1 = self.model_mult
     model2 = self.model_mult
     data = DataSimulFit(name='data1data2', datasets=[data1, data2])
     model = SimulFitModel(name='model1model2', parts=[model1, model2])
     fit = Fit(data=data, model=model, stat=MyChiNoBkg(),
               method=NelderMead())
     result = fit.fit()
     self.compare_results(self._fit_simul_datavarstat_results_bench,
                          result)
Exemplo n.º 23
0
 def test_diff_cache(self):
     poly1 = Polynom1D()
     poly2 = Polynom1D()
     poly3 = Polynom1D()
     poly1.pars[1].thaw()
     poly2.pars[1].thaw()
     poly3.pars[1].thaw()
     sdata = DataSimulFit('d123', (self.d1, self.d2, self.d3))
     smodel = SimulFitModel('diff', (poly1, poly2, poly3))
     sfit = Fit(sdata, smodel, method=NelderMead(), stat=Cash())
     result = sfit.fit()
     self.compare_results(self._fit_diff_poly_bench, result)
Exemplo n.º 24
0
 def test_simul_stat_fit(self):
     data1 = self.data_pi2278
     data2 = self.data_pi2286
     model1 = self.model_mult
     model2 = self.model_mult
     data = DataSimulFit(name='data1data2', datasets=[data1, data2])
     model = SimulFitModel(name='model1model2', parts=[model1, model2])
     fit = Fit(data=data, model=model, stat=MyChiNoBkg(),
               method=NelderMead())
     result = fit.fit()
     self.compare_results(self._fit_simul_datavarstat_results_bench,
                          result)
Exemplo n.º 25
0
 def test_diff_cache(self):
     poly1 = Polynom1D()
     poly2 = Polynom1D()
     poly3 = Polynom1D()
     poly1.pars[1].thaw()
     poly2.pars[1].thaw()
     poly3.pars[1].thaw()
     sdata = DataSimulFit('d123', (self.d1, self.d2, self.d3))
     smodel = SimulFitModel('diff', (poly1, poly2, poly3))
     sfit = Fit(sdata, smodel, method=NelderMead(), stat=Cash())
     result = sfit.fit()
     self.compare_results(self._fit_diff_poly_bench, result)
Exemplo n.º 26
0
def test_regproj(old_numpy_printing, override_plot_backend):
    p = plot.RegionProjection()
    r = p._repr_html_()

    check_empty(r, 'RegionProjection', nsummary=13)

    x = np.arange(5, 8, 0.5)
    y = np.asarray([2, 3, 4, 5, 4, 3])
    dy = y / 2
    d = Data1D('n n', x, y, staterror=dy)

    m = Polynom1D()
    m.c1.thaw()

    fit = Fit(d, m, stat=Chi2())
    fr = fit.fit()
    assert fr.succeeded

    p.prepare(min=(-2, -1), max=(2, 2), nloop=(10, 20))
    p.calc(fit, m.c0, m.c1)

    r = p._repr_html_()
    assert r is not None

    if plot_backend_is("pylab"):
        assert "<summary>RegionProjection</summary>" in r
        assert "<svg " in r
        return

    assert "<summary>RegionProjection (13)</summary>" in r

    # Issue #1372 shows that the numbers here can depend on the platform; as
    # this test is not about whether the fit converged to the same solution
    # the tests are very basic. An alternative would be to just place
    # the values from the fit object into the strings, but then there is
    # the problem that this test currently requires old_numpy_printing,
    # so the results would not necessarily match.
    #
    assert '<div class="dataname">parval0</div><div class="dataval">-0.5' in r
    assert '<div class="dataname">parval1</div><div class="dataval">0.5' in r
    assert '<div class="dataname">sigma</div><div class="dataval">(1, 2, 3)</div>' in r

    # These values may depend on the platform so only very-limited check.
    #
    assert '<div class="dataname">y</div><div class="dataval">[ 30' in r
    assert '<div class="dataname">levels</div><div class="dataval">[  3.6' in r

    assert '<div class="dataname">min</div><div class="dataval">[-2, -1]</div>' in r
    assert '<div class="dataname">max</div><div class="dataval">[2, 2]</div>' in r

    assert '<div class="dataname">nloop</div><div class="dataval">(10, 20)</div>' in r
Exemplo n.º 27
0
def test_sherpa_crab_fit():
    from sherpa.models import NormGauss2D, PowLaw1D, TableModel, Const2D
    from sherpa.stats import Chi2ConstVar
    from sherpa.optmethods import LevMar
    from sherpa.fit import Fit
    from ..sherpa_ import CombinedModel3D

    filename = gammapy_extra.filename('experiments/sherpa_cube_analysis/counts.fits.gz')
    # Note: The cube is stored in incorrect format
    counts = SkyCube.read(filename, format='fermi-counts')
    cube = counts.to_sherpa_data3d()

    # Set up exposure table model
    filename = gammapy_extra.filename('experiments/sherpa_cube_analysis/exposure.fits.gz')
    exposure_data = fits.getdata(filename)
    exposure = TableModel('exposure')
    exposure.load(None, exposure_data.ravel())

    # Freeze exposure amplitude
    exposure.ampl.freeze()

    # Setup combined spatial and spectral model
    spatial_model = NormGauss2D('spatial-model')
    spectral_model = PowLaw1D('spectral-model')
    source_model = CombinedModel3D(spatial_model=spatial_model, spectral_model=spectral_model)

    # Set starting values
    source_model.gamma = 2.2
    source_model.xpos = 83.6
    source_model.ypos = 22.01
    source_model.fwhm = 0.12
    source_model.ampl = 0.05

    model = 1E-9 * exposure * source_model  # 1E-9 flux factor

    # Fit
    fit = Fit(data=cube, model=model, stat=Chi2ConstVar(), method=LevMar())
    result = fit.fit()

    reference = [0.121556,
                 83.625627,
                 22.015564,
                 0.096903,
                 2.240989]

    assert_allclose(result.parvals, reference, rtol=1E-3)
Exemplo n.º 28
0
def test_sherpa_crab_fit():
    from sherpa.models import NormGauss2D, PowLaw1D, TableModel, Const2D
    from sherpa.stats import Chi2ConstVar
    from sherpa.optmethods import LevMar
    from sherpa.fit import Fit
    from ..sherpa_ import Data3D, CombinedModel3D

    filename = gammapy_extra.filename(
        'experiments/sherpa_cube_analysis/counts.fits.gz')
    counts = SkyCube.read(filename)
    cube = counts.to_sherpa_data3d()

    # Set up exposure table model
    filename = gammapy_extra.filename(
        'experiments/sherpa_cube_analysis/exposure.fits.gz')
    exposure_data = fits.getdata(filename)
    exposure = TableModel('exposure')
    exposure.load(None, exposure_data.ravel())

    # Freeze exposure amplitude
    exposure.ampl.freeze()

    # Setup combined spatial and spectral model
    spatial_model = NormGauss2D('spatial-model')
    spectral_model = PowLaw1D('spectral-model')
    source_model = CombinedModel3D(spatial_model=spatial_model,
                                   spectral_model=spectral_model)

    # Set starting values
    source_model.gamma = 2.2
    source_model.xpos = 83.6
    source_model.ypos = 22.01
    source_model.fwhm = 0.12
    source_model.ampl = 0.05

    model = 1E-9 * exposure * (source_model)  # 1E-9 flux factor

    # Fit
    fit = Fit(data=cube, model=model, stat=Chi2ConstVar(), method=LevMar())
    result = fit.fit()

    reference = (0.11925401159500593, 83.640630749333056, 22.020525848447541,
                 0.036353759774770608, 1.1900312815970555)

    assert_allclose(result.parvals, reference, rtol=1E-8)
Exemplo n.º 29
0
def test_sherpa_crab_fit():
    from sherpa.models import NormGauss2D, PowLaw1D, TableModel, Const2D
    from sherpa.stats import Chi2ConstVar
    from sherpa.optmethods import LevMar
    from sherpa.fit import Fit
    from ..sherpa_ import CombinedModel3D

    filename = gammapy_extra.filename(
        'experiments/sherpa_cube_analysis/counts.fits.gz')
    # Note: The cube is stored in incorrect format
    counts = SkyCube.read(filename, format='fermi-counts')
    cube = counts.to_sherpa_data3d()

    # Set up exposure table model
    filename = gammapy_extra.filename(
        'experiments/sherpa_cube_analysis/exposure.fits.gz')
    exposure_data = fits.getdata(filename)
    exposure = TableModel('exposure')
    exposure.load(None, exposure_data.ravel())

    # Freeze exposure amplitude
    exposure.ampl.freeze()

    # Setup combined spatial and spectral model
    spatial_model = NormGauss2D('spatial-model')
    spectral_model = PowLaw1D('spectral-model')
    source_model = CombinedModel3D(spatial_model=spatial_model,
                                   spectral_model=spectral_model)

    # Set starting values
    source_model.gamma = 2.2
    source_model.xpos = 83.6
    source_model.ypos = 22.01
    source_model.fwhm = 0.12
    source_model.ampl = 0.05

    model = 1E-9 * exposure * source_model  # 1E-9 flux factor

    # Fit
    fit = Fit(data=cube, model=model, stat=Chi2ConstVar(), method=LevMar())
    result = fit.fit()

    reference = [0.121556, 83.625627, 22.015564, 0.096903, 2.240989]

    assert_allclose(result.parvals, reference, rtol=1E-5)
Exemplo n.º 30
0
def test_sherpa_crab_fit():
    from sherpa.models import NormGauss2D, PowLaw1D, TableModel, Const2D
    from sherpa.stats import Chi2ConstVar
    from sherpa.optmethods import LevMar
    from sherpa.fit import Fit
    from ..sherpa_ import Data3D, CombinedModel3D

    filename = gammapy_extra.filename('experiments/sherpa_cube_analysis/counts.fits.gz')
    counts = SkyCube.read(filename)
    cube = counts.to_sherpa_data3d()

    # Set up exposure table model
    filename = gammapy_extra.filename('experiments/sherpa_cube_analysis/exposure.fits.gz')
    exposure_data = fits.getdata(filename)
    exposure = TableModel('exposure')
    exposure.load(None, exposure_data.ravel())

    # Freeze exposure amplitude
    exposure.ampl.freeze()

    # Setup combined spatial and spectral model
    spatial_model = NormGauss2D('spatial-model')
    spectral_model = PowLaw1D('spectral-model')
    source_model = CombinedModel3D(spatial_model=spatial_model, spectral_model=spectral_model)

    # Set starting values
    source_model.gamma = 2.2
    source_model.xpos = 83.6
    source_model.ypos = 22.01
    source_model.fwhm = 0.12
    source_model.ampl = 0.05

    model = 1E-9 * exposure * (source_model) # 1E-9 flux factor

    # Fit
    fit = Fit(data=cube, model=model, stat=Chi2ConstVar(), method=LevMar())
    result = fit.fit()

    reference = (0.11925401159500593,
                 83.640630749333056,
                 22.020525848447541,
                 0.036353759774770608,
                 1.1900312815970555)

    assert_allclose(result.parvals, reference, rtol=1E-8)
Exemplo n.º 31
0
def test_regproj(old_numpy_printing, override_plot_backend):
    p = plot.RegionProjection()
    r = p._repr_html_()

    check_empty(r, 'RegionProjection', nsummary=13)

    x = np.arange(5, 8, 0.5)
    y = np.asarray([2, 3, 4, 5, 4, 3])
    dy = y / 2
    d = Data1D('n n', x, y, staterror=dy)

    m = Polynom1D()
    m.c1.thaw()

    fit = Fit(d, m, stat=Chi2())
    fr = fit.fit()
    assert fr.succeeded

    p.prepare(min=(-2, -1), max=(2, 2), nloop=(10, 20))
    p.calc(fit, m.c0, m.c1)

    r = p._repr_html_()
    assert r is not None

    if plot.backend.name == 'pylab':
        assert '<summary>RegionProjection</summary>' in r
        assert '<svg ' in r
        return

    print(r)
    assert '<summary>RegionProjection (13)</summary>' in r

    assert '<div class="dataname">parval0</div><div class="dataval">-0.5315772076542427</div>' in r
    assert '<div class="dataname">parval1</div><div class="dataval">0.5854611101216837</div>' in r
    assert '<div class="dataname">sigma</div><div class="dataval">(1, 2, 3)</div>' in r

    assert '<div class="dataname">y</div><div class="dataval">[ 306.854444  282.795953  259.744431  237.699877  216.662291  196.631674\n' in r

    assert '<div class="dataname">levels</div><div class="dataval">[  3.606863   7.491188  13.140272]</div>' in r
    assert '<div class="dataname">min</div><div class="dataval">[-2, -1]</div>' in r
    assert '<div class="dataname">max</div><div class="dataval">[2, 2]</div>' in r

    assert '<div class="dataname">nloop</div><div class="dataval">(10, 20)</div>' in r
Exemplo n.º 32
0
def test_cstat_stat(hide_logging, reset_xspec, setup):
    fit = Fit(setup['data'], setup['model'], CStat(), NelderMead())
    results = fit.fit()

    _fit_cstat_results_bench = {
        'succeeded':
        1,
        'numpoints':
        460,
        'dof':
        457,
        'istatval':
        21647.62293983995,
        'statval':
        472.6585691450068,
        'parvals':
        numpy.array([1.75021021282262, 5.474614304244775, -1.9985761873334102])
    }

    compare_results(_fit_cstat_results_bench, results)
Exemplo n.º 33
0
def test_leastsq_stat(hide_logging, reset_xspec, setup_group):
    fit = Fit(setup_group['data'], setup_group['model'], LeastSq(), LevMar())
    results = fit.fit()

    _fit_leastsq_results_bench = {
        'succeeded':
        1,
        'numpoints':
        143,
        'dof':
        140,
        'istatval':
        117067.64900554597,
        'statval':
        4203.173180288109,
        'parvals':
        numpy.array([1.808142494916457, 5.461611041944977, -1.907736527635154])
    }

    compare_results(_fit_leastsq_results_bench, results, tol=2e-4)
Exemplo n.º 34
0
def mwl_fit_low_level_calling_fermi():
    """Example how to do a Sherpa model fit,
    but use the Fermi ScienceTools to evaluate
    the likelihood for the Fermi dataset.
    """

    spec_model = LogParabola('spec_model')
    spec_model.c1 = 0.5
    spec_model.c2 = 0.2
    spec_model.ampl = 5e-11

    model = spec_model

    data = FermiDataShim()
    stat = FermiStatShim()
    method = LevMar()
    fit = Fit(data=data, model=model, stat=stat, method=method)
    result = fit.fit()

    return dict(results=result, model=spec_model)
Exemplo n.º 35
0
def test_mychi_data(stat, hide_logging, reset_xspec, setup_group):
    fit = Fit(setup_group['data'], setup_group['model'], stat(), LevMar())
    results = fit.fit()

    _fit_mychi_results_bench = {
        'succeeded':
        1,
        'numpoints':
        143,
        'dof':
        140,
        'istatval':
        117067.64900554594,
        'statval':
        4211.349359724583,
        'parvals':
        numpy.array(
            [1.8177747886737923, 5.448440759203273, -1.8728780046411722])
    }

    compare_results(_fit_mychi_results_bench, results, tol=2e-4)
Exemplo n.º 36
0
def test_wstat(hide_logging, reset_xspec, setup):

    fit = Fit(setup['data'], setup['model'], WStat(), LevMar())
    results = fit.fit()

    _fit_wstat_results_bench = {
        'succeeded':
        1,
        'numpoints':
        460,
        'dof':
        457,
        'istatval':
        21647.48285025895,
        'statval':
        472.6585709918982,
        'parvals':
        numpy.array([1.750204250228727, 5.47466040324842, -1.9983562007031974])
    }

    compare_results(_fit_wstat_results_bench, results, tol=2e-4)
Exemplo n.º 37
0
def mwl_fit_low_level_calling_fermi():
    """Example how to do a Sherpa model fit,
    but use the Fermi ScienceTools to evaluate
    the likelihood for the Fermi dataset.
    """

    spec_model = LogParabola('spec_model')
    spec_model.c1 = 0.5
    spec_model.c2 = 0.2
    spec_model.ampl = 5e-11

    model = spec_model

    data = FermiDataShim()
    stat = FermiStatShim()
    method = LevMar()
    fit = Fit(data=data, model=model, stat=stat, method=method)
    result = fit.fit()

    # IPython.embed()
    return Bunch(results=result, model=spec_model)
Exemplo n.º 38
0
def test_mychi_bkg(stat, hide_logging, reset_xspec, setup_bkg_group):
    fit = Fit(setup_bkg_group['bkg'], setup_bkg_group['model'], stat(),
              LevMar())
    results = fit.fit()

    _fit_mychinobkg_results_bench = {
        'succeeded':
        1,
        'numpoints':
        70,
        'dof':
        67,
        'istatval':
        12368.806484278228,
        'statval':
        799.9399745311307,
        'parvals':
        numpy.array([0.1904013138796835, 2.497496167887353, 2.111511871780941])
    }

    compare_results(_fit_mychinobkg_results_bench, results, tol=2e-6)
Exemplo n.º 39
0
 def test_mychi_data_and_model_have_bkg(self):
     fit = Fit(self.data, self.model, MyChiWithBkg(), LevMar())
     results = fit.fit()
     self.compare_results(self._fit_mychi_results_bench, results)
Exemplo n.º 40
0
 def test_mycash_data_and_model_have_bkg(self):
     fit = Fit(self.data, self.model, MyCashWithBkg(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_mycash_results_bench, results)
Exemplo n.º 41
0
 def test_cash_stat(self):
     fit = Fit(self.data, self.model, Cash(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_mycash_results_bench, results)
Exemplo n.º 42
0
 def test_wstat(self):
     fit = Fit(self.data, self.model, WStat(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_wstat_results_bench, results)
Exemplo n.º 43
0
 def test_mychi_datahasbkg_modelhasnobkg(self):
     fit = Fit(self.data, self.model, MyChiNoBkg(), LevMar())
     results = fit.fit()
     self.compare_results(self._fit_mychi_results_bench, results)
Exemplo n.º 44
0
 def test_mycash_datahasbkg_modelhasnobkg(self):
     fit = Fit(self.data, self.model, MyCashNoBkg(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_mycash_results_bench, results)
Exemplo n.º 45
0
 def test_mycash_data_and_model_donothave_bkg(self):
     data = self.bkg
     fit = Fit(data, self.model, MyCashNoBkg(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_mycashnobkg_results_bench, results)
Exemplo n.º 46
0
class SpectrumFit(object):
    """Orchestrate a 1D counts spectrum fit.

    For usage examples see :ref:`spectral_fitting`

    Parameters
    ----------
    obs_list : `~gammapy.spectrum.SpectrumObservationList`, `~gammapy.spectrum.SpectrumObservation`
        Observation(s) to fit
    model : `~gammapy.spectrum.models.SpectralModel`
        Source model. Should return counts if ``forward_folded`` is False and a flux otherwise
    stat : {'wstat', 'cash'}
        Fit statistic
    forward_folded : bool, default: True
        Fold ``model`` with the IRFs given in ``obs_list``
    fit_range : tuple of `~astropy.units.Quantity`
        Fit range, will be convolved with observation thresholds. If you want to
        control which bins are taken into account in the fit for each
        observations, use :func:`~gammapy.spectrum.SpectrumObservation.qualitiy`
    background_model : `~gammapy.spectrum.models.SpectralModel`, optional
        Background model to be used in cash fits
    method : {'sherpa'}
        Optimization backend for the fit
    err_method : {'sherpa'}
        Optimization backend for error estimation
    """

    def __init__(self, obs_list, model, stat='wstat', forward_folded=True,
                 fit_range=None, background_model=None,
                 method='sherpa', err_method='sherpa'):
        self.obs_list = self._convert_obs_list(obs_list)
        self.model = model
        self.stat = stat
        self.forward_folded = forward_folded
        self.fit_range = fit_range
        self.background_model = background_model
        self.method = method
        self.err_method = err_method

        self._predicted_counts = None
        self._statval = None

        self.covar_axis = None
        self.covariance = None
        self.result = None

        self._check_valid_fit()
        self._apply_fit_range()

    def __str__(self):
        ss = self.__class__.__name__
        ss += '\nSource model {}'.format(self.model)
        ss += '\nStat {}'.format(self.stat)
        ss += '\nForward Folded {}'.format(self.forward_folded)
        ss += '\nFit range {}'.format(self.fit_range)
        if self.background_model is not None:
            ss += '\nBackground model {}'.format(self.background_model)
        ss += '\nBackend {}'.format(self.method)
        ss += '\nError Backend {}'.format(self.err_method)

        return ss

    @staticmethod
    def _convert_obs_list(obs_list):
        """Helper function to accept different inputs for obs_list."""
        if isinstance(obs_list, SpectrumObservation):
            obs_list = SpectrumObservationList([obs_list])
        if not isinstance(obs_list, SpectrumObservationList):
            raise ValueError('Invalid input {} for parameter obs_list'.format(
                type(obs_list)))
        return obs_list

    @property
    def bins_in_fit_range(self):
        """Bins participating in the fit for each observation."""
        return self._bins_in_fit_range

    @property
    def predicted_counts(self):
        """Current value of predicted counts.

        For each observation a tuple to counts for the on and off region is
        returned.
        """
        return self._predicted_counts

    @property
    def statval(self):
        """Current value of statval.

        For each observation the statval per bin is returned.
        """
        return self._statval

    @property
    def fit_range(self):
        """Fit range."""
        return self._fit_range

    @fit_range.setter
    def fit_range(self, fit_range):
        self._fit_range = fit_range
        self._apply_fit_range()

    @property
    def true_fit_range(self):
        """True fit range for each observation.

        True fit range is the fit range set in the
        `~gammapy.spectrum.SpectrumFit` with observation threshold taken into
        account.
        """
        true_range = []
        for binrange, obs in zip(self.bins_in_fit_range, self.obs_list):
            idx = np.where(binrange)[0]
            e_min = obs.e_reco[idx[0]]
            e_max = obs.e_reco[idx[-1] + 1]
            fit_range = u.Quantity((e_min, e_max))
            true_range.append(fit_range)
        return true_range

    def _apply_fit_range(self):
        """Mark bins within desired fit range for each observation."""
        self._bins_in_fit_range = []
        for obs in self.obs_list:
            # Take into account fit range
            energy = obs.e_reco
            valid_range = np.zeros(energy.nbins)

            if self.fit_range is not None:

                precision = 1e-3  # to avoid floating round precision
                idx_lo = np.where(energy * (1 + precision) < self.fit_range[0])[0]
                valid_range[idx_lo] = 1

                
                idx_hi = np.where(energy[:-1] * (1 - precision) > self.fit_range[1])[0]
                if len(idx_hi) != 0:
                    idx_hi = np.insert(idx_hi, 0, idx_hi[0] - 1)
                valid_range[idx_hi] = 1

            # Take into account thresholds
            try:
                quality = obs.on_vector.quality
            except AttributeError:
                quality = np.zeros(obs.e_reco.nbins)

            convolved = np.logical_and(1 - quality, 1 - valid_range)

            self._bins_in_fit_range.append(convolved)

    def predict_counts(self):
        """Predict counts for all observations.

        The result is stored as ``predicted_counts`` attribute.
        """
        predicted_counts = []
        for obs in self.obs_list:
            mu_sig = self._predict_counts_helper(obs,
                                                 self.model,
                                                 self.forward_folded)
            mu_bkg = None
            if self.background_model is not None:
                # For now, never fold background model with IRFs
                mu_bkg = self._predict_counts_helper(obs,
                                                     self.background_model,
                                                     False)
            counts = [mu_sig, mu_bkg]
            predicted_counts.append(counts)
        self._predicted_counts = predicted_counts

    def _predict_counts_helper(self, obs, model, forward_folded=True):
        """Predict counts for one observation.

        Parameters
        ----------
        obs : `~gammapy.spectrum.SpectrumObservation`
            Response functions
        model : `~gammapy.spectrum.SpectralModel`
            Source or background model
        forward_folded : bool, default: True
            Fold model with IRFs

        Returns
        ------
        predicted_counts: `np.array`
            Predicted counts for one observation
        """
        predictor = CountsPredictor(model=model)
        if forward_folded:
            predictor.livetime = obs.livetime
            predictor.aeff = obs.aeff
            predictor.edisp = obs.edisp
        else:
            predictor.e_true = obs.e_reco

        predictor.run()
        counts = predictor.npred.data.data

        # Check count unit (~unit of model amplitude)
        cond = counts.unit.is_equivalent('ct') or counts.unit.is_equivalent('')
        if cond:
            counts = counts.value
        else:
            raise ValueError('Predicted counts {}'.format(counts))

        # Apply AREASCAL column
        counts *= obs.on_vector.areascal

        return counts

    def calc_statval(self):
        """Calc statistic for all observations.

        The result is stored as attribute ``statval``, bin outside the fit
        range are set to 0.
        """
        statval = []
        for obs, npred in zip(self.obs_list, self.predicted_counts):
            on_stat, off_stat = self._calc_statval_helper(obs, npred)
            statvals = (on_stat, off_stat)
            statval.append(statvals)
        self._statval = statval
        self._restrict_statval()

    def _calc_statval_helper(self, obs, prediction):
        """Calculate ``statval`` for one observation.

        Parameters
        ----------
        obs : `~gammapy.spectrum.SpectrumObservation`
            Measured counts
        prediction : tuple of `~numpy.ndarray`
            Predicted (on counts, off counts)

        Returns
        ------
        statsval : tuple of `~numpy.ndarray`
            Statval for (on, off)
        """
        stats_func = getattr(stats, self.stat)

        # Off stat = 0 by default
        off_stat = np.zeros(obs.e_reco.nbins)
        if self.stat == 'cash' or self.stat == 'cstat':
            if self.background_model is not None:
                mu_on = prediction[0] + prediction[1]
                on_stat = stats_func(n_on=obs.on_vector.data.data.value,
                                     mu_on=mu_on)
                mu_off = prediction[1] / obs.alpha
                off_stat = stats_func(n_on=obs.off_vector.data.data.value,
                                      mu_on=mu_off)
            else:
                mu_on = prediction[0]
                on_stat = stats_func(n_on=obs.on_vector.data.data.value,
                                     mu_on=mu_on)
                off_stat = np.zeros_like(on_stat)

        elif self.stat == 'wstat':
            kwargs = dict(n_on=obs.on_vector.data.data.value,
                          n_off=obs.off_vector.data.data.value,
                          alpha=obs.alpha,
                          mu_sig=prediction[0])
            # Store the result of the profile likelihood as bkg prediction
            mu_bkg = stats.get_wstat_mu_bkg(**kwargs)
            prediction[1] = mu_bkg * obs.alpha
            on_stat_ = stats_func(**kwargs)
            # The on_stat sometime contains nan values
            # TODO: Handle properly
            on_stat = np.nan_to_num(on_stat_)
            off_stat = np.zeros_like(on_stat)
        else:
            raise NotImplementedError('{}'.format(self.stat))

        return on_stat, off_stat

    @property
    def total_stat(self):
        """Statistic summed over all bins and all observations.

        This is what is used for the fit.
        """
        total_stat = np.sum(self.statval, dtype=np.float64)
        return total_stat

    def _restrict_statval(self):
        """Apply valid fit range to statval.
        """
        for statval, valid_range in zip(self.statval, self.bins_in_fit_range):
            # Find bins outside safe range
            idx = np.where(np.invert(valid_range))[0]
            statval[0][idx] = 0
            statval[1][idx] = 0

    def _check_valid_fit(self):
        """Helper function to give useful error messages."""
        # Assume that settings are the same for all observations
        test_obs = self.obs_list[0]
        irfs_exist = test_obs.aeff is not None or test_obs.edisp is not None
        if self.forward_folded and not irfs_exist:
            raise ValueError('IRFs required for forward folded fit')
        if self.stat == 'wstat' and self.obs_list[0].off_vector is None:
            raise ValueError('Off vector required for WStat fit')

    def likelihood_1d(self, model, parname, parvals):
        """Compute likelihood profile.

        Parameters
        ----------
        model : `~gammapy.spectrum.models.SpectralModel`
            Model to draw likelihood profile for
        parname : str
            Parameter to calculate profile for
        parvals : `~astropy.units.Quantity`
            Parameter values
        """
        likelihood = []
        self.model = model
        for val in parvals:
            self.model.parameters[parname].value = val
            self.predict_counts()
            self.calc_statval()
            likelihood.append(self.total_stat)
        return np.array(likelihood)

    def plot_likelihood_1d(self, ax=None, **kwargs):
        """Plot 1-dim likelihood profile.

        See :func:`~gammapy.spectrum.SpectrumFit.likelihood_1d`
        """
        import matplotlib.pyplot as plt
        ax = plt.gca() if ax is None else ax

        yy = self.likelihood_1d(**kwargs)
        ax.plot(kwargs['parvals'], yy)
        ax.set_xlabel(kwargs['parname'])

        return ax

    def fit(self):
        """Run the fit."""
        if self.method == 'sherpa':
            self._fit_sherpa()
        else:
            raise NotImplementedError('method: {}'.format(self.method))

    def _fit_sherpa(self):
        """Wrapper around sherpa minimizer."""
        from sherpa.fit import Fit
        from sherpa.data import Data1DInt
        from sherpa.optmethods import NelderMead
        from .sherpa_utils import SherpaModel, SherpaStat

        binning = self.obs_list[0].e_reco
        # The sherpa data object is not usued in the fit. It is set to the
        # first observation for debugging purposes, see below
        data = self.obs_list[0].on_vector.data.data.value
        data = Data1DInt('Dummy data', binning[:-1].value,
                         binning[1:].value, data)
        # DEBUG
        # from sherpa.models import PowLaw1D
        # from sherpa.stats import Cash
        # model = PowLaw1D('sherpa')
        # model.ref = 0.1
        # fit = Fit(data, model, Cash(), NelderMead())

        # NOTE: We cannot use the Levenbergr-Marquart optimizer in Sherpa
        # because it relies on the fvec return value of the fit statistic (we
        # return None). The computation of fvec is not straightforwad, not just
        # stats per bin. E.g. for a cash fit the sherpa stat computes it
        # according to cstat
        # see https://github.com/sherpa/sherpa/blob/master/sherpa/include/sherpa/stats.hh#L122

        self._sherpa_fit = Fit(data,
                               SherpaModel(self),
                               SherpaStat(self),
                               NelderMead())
        fitresult = self._sherpa_fit.fit()
        log.debug(fitresult)
        self._make_fit_result()

    def _make_fit_result(self):
        """Bundle fit results into `~gammapy.spectrum.SpectrumFitResult`.

        It is important to copy best fit values, because the error estimation
        will change the model parameters and statval again
        """
        from . import SpectrumFitResult

        model = self.model.copy()
        if self.background_model is not None:

            bkg_model = self.background_model.copy()
        else:
            bkg_model = None

        statname = self.stat

        results = []
        for idx, obs in enumerate(self.obs_list):
            fit_range = self.true_fit_range[idx]
            statval = np.sum(self.statval[idx])
            stat_per_bin = self.statval[idx]
            npred_src = copy.deepcopy(self.predicted_counts[idx][0])
            npred_bkg = copy.deepcopy(self.predicted_counts[idx][1])

            results.append(SpectrumFitResult(
                model=model,
                fit_range=fit_range,
                statname=statname,
                statval=statval,
                stat_per_bin=stat_per_bin,
                npred_src=npred_src,
                npred_bkg=npred_bkg,
                background_model=bkg_model,
                obs=obs
            ))

        self.result = results

    def est_errors(self):
        """Estimate parameter errors."""
        if self.err_method == 'sherpa':
            self._est_errors_sherpa()
        else:
            raise NotImplementedError('{}'.format(self.err_method))

        for res in self.result:
            res.covar_axis = self.covar_axis
            res.covariance = self.covariance
            res.model.parameters.set_parameter_covariance(self.covariance, self.covar_axis)

    def _est_errors_sherpa(self):
        """Wrapper around Sherpa error estimator."""
        covar = self._sherpa_fit.est_errors()
        self.covar_axis = [par.split('.')[-1] for par in covar.parnames]
        self.covariance = copy.deepcopy(covar.extra_output)

    def run(self, outdir=None):
        """Run all steps and write result to disk.

        Parameters
        ----------
        outdir : Path, str
            directory to write results files to (if given)
        """
        log.info('Running {}'.format(self))

        self.fit()
        self.est_errors()

        if outdir is not None:
            self._write_result(outdir)

    def _write_result(self, outdir):
        outdir = make_path(outdir)
        outdir.mkdir(exist_ok=True, parents=True)

        # Assume only one model is fit to all data
        modelname = self.result[0].model.__class__.__name__
        filename = outdir / 'fit_result_{}.yaml'.format(modelname)
        log.info('Writing {}'.format(filename))
        self.result[0].to_yaml(filename)
Exemplo n.º 47
0
g3 = Gauss1D("g3")
g4 = Gauss1D("g4")

g1.pos = 3250
g2.pos = 5000
g3.pos = 5260
g4.pos = 5600

# for p in [g1, g2, g3, g4]:
#     p.fwhm = 50

parameters = pl + g1 + g2 + g3 + g4

pl.ref = 4000.0

print g1
print type(g1)

g1broad = Gauss1D("g1broad")
g1broad.pos = g1.pos
g1broad.fwhm = g1.fwhm * 4

parameters = parameters + g1broad

f = Fit(data, parameters, Chi2DataVar(), LevMar())
result = f.fit()

plot_data(data.x, parameters(data.x), fmt="-", clear=False)
plt.show()
print "hola"
Exemplo n.º 48
0
    def run(fit, null_comp, alt_comp, conv_mdl=None,
	    stat=None, method=None,
	    niter=500, numcores=None):
	    
        if stat is None:   stat = CStat()
	if method is None: method = NelderMead()

	if not isinstance(stat, (Cash, CStat)):
		raise TypeError("Sherpa fit statistic must be Cash or CStat" +
                                " for likelihood ratio test")

        niter = int(niter)

	alt  = alt_comp
	null = null_comp
	
	oldaltvals = numpy.array(alt.thawedpars)
	oldnullvals = numpy.array(null.thawedpars)

        data = fit.data
	
	if conv_mdl is not None:
            # Copy the PSF
            null_conv_mdl = deepcopy(conv_mdl)

	    alt = conv_mdl(alt_comp)
	    if hasattr(conv_mdl, 'fold'):
                conv_mdl.fold(data)
		
            # Convolve the null model
	    null = null_conv_mdl(null_comp)
	    if hasattr(null_conv_mdl, 'fold'):
                null_conv_mdl.fold(data)

	nullfit = Fit(data, null, stat, method, Covariance())

	# Fit with null model
	nullfit_results = nullfit.fit()
	debug(nullfit_results.format())
	    
	null_stat = nullfit_results.statval
	null_vals = nullfit_results.parvals
	    
	# Calculate niter samples using null best-fit and covariance
	sampler = NormalParameterSampleFromScaleMatrix()
	samples = sampler.get_sample(nullfit, None, niter)
	   
	# Fit with alt model, null component starts at null's best fit params.
	altfit = Fit(data, alt, stat, method, Covariance())
	altfit_results = altfit.fit()
	debug(altfit_results.format())
	
	alt_stat = altfit_results.statval
	alt_vals = altfit_results.parvals
	
	LR = -(alt_stat - null_stat)
	
	def worker(proposal, *args, **kwargs):
            return LikelihoodRatioTest.calculate(nullfit, altfit, proposal,
                                                 null_vals, alt_vals)

	olddep = data.get_dep(filter=False)
	try:
            #statistics = map(worker, samples)
            statistics = parallel_map(worker, samples, numcores)
        finally:
            data.set_dep(olddep)
            alt.thawedpars = list(oldaltvals)
            null.thawedpars = list(oldnullvals)

        debug("statistic null = " + repr(null_stat))
        debug("statistic alt = " + repr(alt_stat))
        debug("LR = " + repr(LR))

        statistics = numpy.asarray(statistics)

        pppvalue = numpy.sum( statistics[:,2] > LR ) / (1.0*niter)

        debug('ppp value = '+str(pppvalue))

        return LikelihoodRatioResults(statistics[:,2], statistics[:,0:2],
                                      samples, LR, pppvalue, null_stat,
                                      alt_stat)
Exemplo n.º 49
0
 def test_mychi_data_and_model_donothave_bkg(self):
     data = self.bkg
     fit = Fit(data, self.model, MyChiNoBkg(), LevMar())
     results = fit.fit()
     self.compare_results(self._fit_mychinobkg_results_bench, results, 1e-5)
Exemplo n.º 50
0
class test_sim(SherpaTestCase):

    _fit_results_bench = {
        'rstat': 89.29503933428586,
        'qval': 0.0,
        'succeeded': 1,
        'numpoints': 100,
        'dof': 95,
        'nfev': 93,
        'statval': 8483.0287367571564,
        'parnames': ['p1.gamma', 'p1.ampl', 'g1.fwhm',
                     'g1.pos', 'g1.ampl'], 
        'parvals': numpy.array(
            [1.0701938169914813,
             9.1826254677279469,
             2.5862083052721028,
             2.601619746022207,
             47.262657692418749])
        }

    _x = numpy.arange(0.1, 10.1, 0.1)
    _y = numpy.array(
        [ 114, 47, 35, 30, 40, 27, 30, 26, 24, 20, 26, 35,
          29, 28, 34, 36, 43, 39, 33, 47, 44, 46, 53, 56,
          52, 53, 49, 57, 49, 36, 33, 42, 49, 45, 42, 32,
          31, 34, 18, 24, 25, 11, 17, 17, 11,  9,  8,  5,
           4, 10,  3,  4,  6,  3,  0,  2,  4,  4,  0,  1,
           2,  0,  3,  3,  0,  2,  1,  2,  3,  0,  1,  0,
           1,  0,  0,  1,  3,  3,  0,  2,  0,  0,  1,  2,
           0,  1,  0,  1,  1,  0,  1,  1,  1,  1,  1,  1,
           1,  0,  1,  0
          ]
        )
    _err = numpy.ones(100)*0.4


    def setUp(self):
        data = Data1D('fake', self._x, self._y, self._err)

        g1 = Gauss1D('g1')
        g1.fwhm.set(1.0, _tiny, _max, frozen=False)
        g1.pos.set(1.0, -_max, _max, frozen=False)
        g1.ampl.set(1.0, -_max, _max, frozen=False)
        p1 = PowLaw1D('p1')
        p1.gamma.set(1.0, -10, 10, frozen=False)
        p1.ampl.set(1.0, 0.0, _max, frozen=False)
        p1.ref.set(1.0, -_max, _max, frozen=True)      
        model = p1 + g1

        method = LevMar()
        method.config['maxfev'] = 10000
        method.config['ftol'] = float(_eps)
        method.config['epsfcn'] = float(_eps)
        method.config['gtol'] = float(_eps)
        method.config['xtol'] = float(_eps)
        method.config['factor'] = float(100)

        self.fit = Fit(data, model, Chi2DataVar(), method, Covariance())
        results = self.fit.fit()

        for key in ["succeeded", "numpoints", "nfev"]:
            assert self._fit_results_bench[key] == int(getattr(results, key))

        for key in ["rstat", "qval", "statval", "dof"]:
            assert numpy.allclose(float(self._fit_results_bench[key]),
                                  float(getattr(results, key)),
                                  1.e-7, 1.e-7)

        for key in ["parvals"]:
            try:
                assert numpy.allclose(self._fit_results_bench[key],
                                      getattr(results, key),
                                      1.e-4, 1.e-4)
            except AssertionError:
                print 'parvals bench: ', self._fit_results_bench[key]
                print 'parvals fit:   ', getattr(results, key)
                print 'results', results
                raise

        covresults = self.fit.est_errors()
        self.dof = results.dof
        self.mu = numpy.array(results.parvals)
        self.cov = numpy.array(covresults.extra_output)
        self.num = 10


    def test_student_t(self):
        multivariate_t(self.mu, self.cov, self.dof, self.num)
        
    def test_cauchy(self):
        multivariate_cauchy(self.mu, self.cov, self.num)       

    def test_parameter_scale_vector(self):
        ps = ParameterScaleVector()
        ps.get_scales(self.fit)

    def test_parameter_scale_matrix(self):
        ps = ParameterScaleMatrix()
        ps.get_scales(self.fit)

    def test_uniform_parameter_sample(self):
        up = UniformParameterSampleFromScaleVector()
        up.get_sample(self.fit, num=self.num)
        
    def test_normal_parameter_sample_vector(self):
        np = NormalParameterSampleFromScaleVector()
        np.get_sample(self.fit, num=self.num)

    def test_normal_parameter_sample_matrix(self):
        np = NormalParameterSampleFromScaleMatrix()
        np.get_sample(self.fit, num=self.num)

    def test_t_parameter_sample_matrix(self):
        np = StudentTParameterSampleFromScaleMatrix()
        np.get_sample(self.fit, self.dof, num=self.num)

    def test_uniform_sample(self):
        up = UniformSampleFromScaleVector()
        up.get_sample(self.fit, num=self.num)
        
    def test_normal_sample_vector(self):
        np = NormalSampleFromScaleVector()
        np.get_sample(self.fit, num=self.num)

    def test_normal_sample_matrix(self):
        np = NormalSampleFromScaleMatrix()
        np.get_sample(self.fit, num=self.num)

    def test_t_sample_matrix(self):
        np = StudentTSampleFromScaleMatrix()
        np.get_sample(self.fit, self.num, self.dof)

    def test_uniform_sample(self):
        uniform_sample(self.fit, num=self.num)

    def test_normal_sample(self):
        normal_sample(self.fit, num=self.num, correlate=False)

    def test_normal_sample_correlated(self):
        normal_sample(self.fit, num=self.num, correlate=True)

    def test_t_sample(self):
        t_sample(self.fit, self.num, self.dof)

    def test_lrt(self):
        results = LikelihoodRatioTest.run(self.fit, self.fit.model.lhs,
                                          self.fit.model, niter=25)


    def test_mh(self):

        self.fit.method = NelderMead()
        self.fit.stat = Cash()
        results = self.fit.fit()
        results = self.fit.est_errors()
        cov = results.extra_output

        mcmc = MCMC()
        
        samplers = mcmc.list_samplers()
        priors = mcmc.list_priors()
        for par in self.fit.model.pars:
            mcmc.set_prior(par, flat)
            prior = mcmc.get_prior(par)

        sampler = mcmc.get_sampler()
        name = mcmc.get_sampler_name()

        mcmc.set_sampler('MH')

        opt = mcmc.get_sampler_opt('defaultprior')
        mcmc.set_sampler_opt('defaultprior', opt)
        #mcmc.set_sampler_opt('verbose', True)

        log = logging.getLogger("sherpa")
        level = log.level
        log.setLevel(logging.ERROR)
        stats, accept, params = mcmc.get_draws(self.fit, cov, niter=1e2)
        log.setLevel(level)


    def test_metropolisMH(self):

        self.fit.method = NelderMead()
        self.fit.stat = CStat()
        results = self.fit.fit()
        results = self.fit.est_errors()
        cov = results.extra_output

        mcmc = MCMC()
        mcmc.set_sampler('MetropolisMH')
        #mcmc.set_sampler_opt('verbose', True)
        
        log = logging.getLogger("sherpa")
        level = log.level
        log.setLevel(logging.ERROR)
        stats, accept, params = mcmc.get_draws(self.fit, cov, niter=1e2)
        log.setLevel(level)
 

    def tearDown(self):
        pass
Exemplo n.º 51
0
 def test_mycash_nobkgdata_modelhasbkg(self):
     data = self.bkg
     fit = Fit(data, self.model, MyCashWithBkg(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_mycashnobkg_results_bench, results)
Exemplo n.º 52
0
 def test_chi2constvar_stat(self):
     fit = Fit(self.data, self.model, Chi2ConstVar(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_chi2constvar_results_bench, results)
Exemplo n.º 53
0
 def test_mychi_nobkgdata_modelhasbkg(self):
     data = self.bkg
     fit = Fit(data, self.model, MyChiWithBkg(), LevMar())
     results = fit.fit()
     self.compare_results(self._fit_mychinobkg_results_bench, results, 1e-5)
Exemplo n.º 54
0
 def test_chi2gehrels_stat(self):
     fit = Fit(self.data, self.model, Chi2Gehrels(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_chi2gehrels_results_bench, results)
Exemplo n.º 55
0
class SherpaFitter(Fitter):
    __doc__ = """
    Sherpa Fitter for astropy models.

    Parameters
    ----------
    optimizer : string
        the name of a sherpa optimizer.
        posible options include
        {opt}
    statistic : string
        the name of a sherpa statistic.
        posible options include
        {stat}
    estmethod : string
        the name of a sherpa estmethod.
        possible options include
        {est}

    """.format(opt=", ".join(OptMethod._sherpa_values.keys()),
               stat=", ".join(Stat._sherpa_values.keys()),
               est=", ".join(EstMethod._sherpa_values.keys()))  # is this evil?


    def __init__(self, optimizer="levmar", statistic="leastsq", estmethod="covariance"):
        try:
            optimizer = optimizer.value
        except AttributeError:
            optimizer = OptMethod(optimizer).value

        try:
            statistic = statistic.value
        except AttributeError:
            statistic = Stat(statistic).value

        super(SherpaFitter, self).__init__(optimizer=optimizer, statistic=statistic)

        try:
            self._est_method = estmethod.value()
        except AttributeError:
            self._est_method = EstMethod(estmethod).value()

        self.fit_info = {}
        self._fitter = None  # a handle for sherpa fit function
        self._fitmodel = None  # a handle for sherpa fit model
        self._data = None  # a handle for sherpa dataset
        self.error_info = {}

        setattr(self.__class__, 'opt_config', property(lambda s: s._opt_config, doc=self._opt_method.__doc__))
        # sherpa doesn't currently have a docstring for est_method but maybe the future
        setattr(self.__class__, 'est_config', property(lambda s: s._est_config, doc=self._est_method.__doc__))  


    def __call__(self, models, x, y, z=None, xbinsize=None, ybinsize=None, err=None, bkg=None, bkg_scale=1, **kwargs):
        """
        Fit the astropy model with a the sherpa fit routines.


        Parameters
        ----------
        models : `astropy.modeling.FittableModel` or list of `astropy.modeling.FittableModel`
            model to fit to x, y, z
        x : array or list of arrays
            input coordinates (independent for 1D & 2D fits)
        y : array or list of arrays
            input coordinates (dependent for 1D fits or independent for 2D fits)
        z : array or list of arrays (optional)
            input coordinates (dependent for 2D fits)
        xbinsize : array or list of arrays (optional)
            an array of xbinsizes in x  - this will be x -/+ (binsize  / 2.0)
        ybinsize : array or list of arrays (optional)
            an array of xbinsizes in y  - this will be y -/+ (ybinsize / 2.0)
        err : array or list of arrays (optional)
            an array of errors in dependent variable
        bkg : array or list of arrays (optional)
            this will act as background data
        bkg_sale : float or list of floats (optional)
            the scaling factor for the dataset if a single value
            is supplied it will be copied for each dataset
        **kwargs :
            keyword arguments will be passed on to sherpa fit routine

        Returns
        -------
        model_copy : `astropy.modeling.FittableModel` or a list of models.
            a copy of the input model with parameters set by the fitter
        """

        tie_list = []
        try:
            n_inputs = models[0].n_inputs
        except TypeError:
            n_inputs = models.n_inputs

        self._data = Dataset(n_inputs, x, y, z, xbinsize, ybinsize, err, bkg, bkg_scale)

        if self._data.ndata > 1:

            if len(models) == 1:
                self._fitmodel = ConvertedModel([models.copy() for _ in xrange(self._data.ndata)], tie_list)
                # Copy the model so each data set has the same model!
            elif len(models) == self._data.ndata:
                self._fitmodel = ConvertedModel(models, tie_list)
            else:
                raise Exception("Don't know how to handle multiple models "
                                "unless there is one foreach dataset")
        else:
            if len(models) > 1:
                self._data.make_simfit(len(models))
                self._fitmodel = ConvertedModel(models, tie_list)
            else:
                self._fitmodel = ConvertedModel(models)

        self._fitter = Fit(self._data.data, self._fitmodel.sherpa_model, self._stat_method, self._opt_method, self._est_method, **kwargs)
        self.fit_info = self._fitter.fit()

        return self._fitmodel.get_astropy_model()

    def est_errors(self, sigma=None, maxiters=None, numcores=1, methoddict=None, parlist=None):
        """
        Use sherpa error estimators based on the last fit.

        Parameters
        ----------
        sigma: float
            this will be set as the confidance interval for which the errors are found too.
        maxiters: int
            the maximum number of iterations the error estimator will run before giving up.
        methoddict: dict
            !not quite sure couldn't figure this one out yet!
        parlist: list
            a list of parameters to find the confidance interval of if none are provided all free
            parameters will be estimated.
        """
        if self._fitter is None:
            ValueError("Must complete a valid fit before errors can be calculated")
        if sigma is not None:
            self._fitter.estmethod.config['sigma'] = sigma
        if maxiters is not None:
            self._fitter.estmethod.config['maxiters'] = maxiters
        if 'numcores' in self._fitter.estmethod.config:
            if not numcores == self._fitter.estmethod.config['numcores']:
                self._fitter.estmethod.config['numcores'] = numcores

        self.error_info = self._fitter.est_errors(methoddict=methoddict, parlist=parlist)
        pnames = [p.split(".", 1)[-1] for p in self.error_info.parnames]  # this is to remove the model name
        return pnames, self.error_info.parvals, self.error_info.parmins, self.error_info.parmaxes

    @property
    def _est_config(self):
        """This returns the est.config property"""
        return self._est_method.config

    @property
    def _opt_config(self):
        """This returns the opt.config property"""
        return self._opt_method.config

    # Here is the MCMC wrapper!
    @format_doc("{__doc__}\n{mcmc_doc}",mcmc_doc=SherpaMCMC.__doc__)
    def get_sampler(self, *args, **kwargs):
        """
        This returns and instance of `SherpaMCMC` with it's self as the fitter
        """
        return SherpaMCMC(self, *args, **kwargs)
Exemplo n.º 56
0
 def test_leastsq_stat(self):
     fit = Fit(self.data, self.model, LeastSq(), NelderMead())
     results = fit.fit()
     self.compare_results(self._fit_leastsq_results_bench, results)
Exemplo n.º 57
0
def testCombinedModel3DInt():
    from sherpa.models import PowLaw1D, TableModel
    from sherpa.estmethods import Covariance
    from sherpa.optmethods import NelderMead
    from sherpa.stats import Cash
    from sherpa.fit import Fit
    from ..sherpa_ import CombinedModel3DInt, NormGauss2DInt

    # Set the counts
    filename = gammapy_extra.filename('test_datasets/cube/counts_cube.fits')
    counts_3d = SkyCube.read(filename)
    cube = counts_3d.to_sherpa_data3d(dstype='Data3DInt')

    # Set the bkg
    filename = gammapy_extra.filename('test_datasets/cube/bkg_cube.fits')
    bkg_3d = SkyCube.read(filename)
    bkg = TableModel('bkg')
    bkg.load(None, bkg_3d.data.value.ravel())
    bkg.ampl = 1
    bkg.ampl.freeze()

    # Set the exposure
    filename = gammapy_extra.filename('test_datasets/cube/exposure_cube.fits')
    exposure_3d = SkyCube.read(filename)
    i_nan = np.where(np.isnan(exposure_3d.data))
    exposure_3d.data[i_nan] = 0
    # In order to have the exposure in cm2 s
    exposure_3d.data = exposure_3d.data * 1e4

    # Set the mean psf model
    filename = gammapy_extra.filename('test_datasets/cube/psf_cube.fits')
    psf_3d = SkyCube.read(filename)

    # Setup combined spatial and spectral model
    spatial_model = NormGauss2DInt('spatial-model')
    spectral_model = PowLaw1D('spectral-model')

    coord = counts_3d.sky_image_ref.coordinates(mode="edges")
    energies = counts_3d.energies(mode='edges').to("TeV")
    source_model = CombinedModel3DInt(coord=coord, energies=energies, use_psf=True, exposure=exposure_3d, psf=psf_3d,
                                      spatial_model=spatial_model, spectral_model=spectral_model)

    # Set starting values
    center = SkyCoord(83.633083, 22.0145, unit="deg").galactic
    source_model.gamma = 2.2
    source_model.xpos = center.l.value
    source_model.ypos = center.b.value
    source_model.fwhm = 0.12
    source_model.ampl = 1.0

    # Fit
    model = bkg + 1E-11 * (source_model)
    fit = Fit(data=cube, model=model, stat=Cash(), method=NelderMead(), estmethod=Covariance())
    result = fit.fit()

    # TODO: The fact that it doesn't converge to the right Crab postion is due to the dummy psf
    reference = [1.841954e+02,
                 -6.169173e+00,
                 6.166281e+00,
                 7.656752e-02,
                 2.306480e+00]

    assert_allclose(result.parvals, reference, rtol=1E-3)

    # Add a region to exclude in the fit: Here we will exclude some events from the Crab since there is no region to
    # exclude in the FOV for this example. It's just an example to show how it works and how to proceed in the fit.
    # Read the mask for the exclude region
    filename_mask = gammapy_extra.filename('test_datasets/cube/mask.fits')
    cube_mask = SkyCube.read(filename_mask)
    index_region_selected_3d = np.where(cube_mask.data.value == 1)

    # Set the counts and create a gammapy Data3DInt object on which we apply a mask for the region we don't want to use in the fit
    cube = counts_3d.to_sherpa_data3d(dstype='Data3DInt')
    cube.mask = cube_mask.data.value.ravel()

    # Set the bkg and select only the data points of the selected region
    bkg = TableModel('bkg')
    bkg.load(None, bkg_3d.data.value[index_region_selected_3d].ravel())
    bkg.ampl = 1
    bkg.ampl.freeze()

    # The model is evaluated on all the points then it is compared with the data only on the selected_region
    source_model = CombinedModel3DInt(coord=coord, energies=energies, use_psf=True, exposure=exposure_3d, psf=psf_3d,
                                      spatial_model=spatial_model, spectral_model=spectral_model, select_region=True,
                                      index_selected_region=index_region_selected_3d)
    # Set starting values
    source_model.gamma = 2.2
    source_model.xpos = center.l.value
    source_model.ypos = center.b.value
    source_model.fwhm = 0.12
    source_model.ampl = 1.0

    # Fit
    model = bkg + 1E-11 * (source_model)
    fit = Fit(data=cube, model=model, stat=Cash(), method=NelderMead(), estmethod=Covariance())
    result2 = fit.fit()

    # TODO: The fact that it doesn't converge to the right Crab postion is due to the dummy psf
    reference2 = [1.842016e+02,
                  -6.159901e+00,
                  5.419152e+00,
                  8.658486e-02,
                  2.298557e+00]
    assert_allclose(result2.parvals, reference2, rtol=1E-3)
Exemplo n.º 58
0
    def fit(self):
        """Fit spectrum"""
        from sherpa.fit import Fit
        from sherpa.models import ArithmeticModel, SimulFitModel
        from sherpa.astro.instrument import Response1D
        from sherpa.data import DataSimulFit

        # Reset results
        self._result = list()

        # Translate model to sherpa model if necessary
        if isinstance(self.model, models.SpectralModel):
            model = self.model.to_sherpa()
        else:
            model = self.model

        if not isinstance(model, ArithmeticModel):
            raise ValueError('Model not understood: {}'.format(model))

        # Make model amplitude O(1e0)
        val = model.ampl.val * self.FLUX_FACTOR ** (-1)
        model.ampl = val

        if self.fit_range is not None:
            log.info('Restricting fit range to {}'.format(self.fit_range))
            fitmin = self.fit_range[0].to('keV').value
            fitmax = self.fit_range[1].to('keV').value

        # Loop over observations
        pha = list()
        folded_model = list()
        nobs = len(self.obs_list)
        for ii in range(nobs):
            temp = self.obs_list[ii].to_sherpa()
            if self.fit_range is not None:
                temp.notice(fitmin, fitmax)
                if temp.get_background() is not None:
                    temp.get_background().notice(fitmin, fitmax)
            temp.ignore_bad()
            if temp.get_background() is not None:
                temp.get_background().ignore_bad()
            pha.append(temp)
            log.debug('Noticed channels obs {}: {}'.format(
                ii, temp.get_noticed_channels()))
            # Forward folding
            resp = Response1D(pha[ii])
            folded_model.append(resp(model) * self.FLUX_FACTOR)

        if (len(pha) == 1 and len(pha[0].get_noticed_channels()) == 1):
            raise ValueError('You are trying to fit one observation in only '
                             'one bin, error estimation will fail')

        data = DataSimulFit('simul fit data', pha)
        log.debug(data)
        fitmodel = SimulFitModel('simul fit model', folded_model)
        log.debug(fitmodel)

        fit = Fit(data, fitmodel, self.statistic, method=self.method_fit)

        fitresult = fit.fit()
        log.debug(fitresult)
        # The model instance passed to the Fit now holds the best fit values
        covar = fit.est_errors()
        log.debug(covar)

        for ii in range(nobs):
            efilter = pha[ii].get_filter()
            # Skip observations not participating in the fit
            if efilter != '':
                shmodel = fitmodel.parts[ii]
                result = _sherpa_to_fitresult(shmodel, covar, efilter, fitresult)
                result.obs = self.obs_list[ii]
            else:
                result = None
            self._result.append(result)

        valid_result = np.nonzero(self.result)[0][0]
        global_result = copy.deepcopy(self.result[valid_result])
        global_result.npred = None
        global_result.obs = None
        all_fitranges = [_.fit_range for _ in self._result if _ is not None]
        fit_range_min = min([_[0] for _ in all_fitranges])
        fit_range_max = max([_[1] for _ in all_fitranges])
        global_result.fit_range = u.Quantity((fit_range_min, fit_range_max))
        self._global_result = global_result