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
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
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)
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)
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
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)
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
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)
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)
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)
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
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
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)
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
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)
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)
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
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)
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)
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)
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)
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
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)
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)
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)
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)
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
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
def test_wstat(self): fit = Fit(self.data, self.model, WStat(), NelderMead()) results = fit.fit() self.compare_results(self._fit_wstat_results_bench, results)
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)
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)
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)
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)
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"
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)
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)
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
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)
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)
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)
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)
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)
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)
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)
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