def test_plot_pvalue(make_data_path, clean_astro_ui, hide_log_output): fname = make_data_path("qso.pi") ui.load_pha(fname) ui.set_stat('cstat') ui.set_method("neldermead") ui.group_counts(10) ui.notice(0.3, 8) ui.set_model("xsphabs.abs1*xspowerlaw.p1") ui.set_model("abs1*(p1+gauss1d.g1)") # move the fit close to the best fit to save a small amount # of time. abs1.nh = 0.05 p1.phoindex = 1.28 p1.norm = 2e-4 g1.ampl = 1.8e-5 g1.pos = 3. ui.freeze(g1.pos) g1.fwhm = 0.1 ui.freeze(g1.fwhm) ui.fit() ui.plot_pvalue(p1, p1 + g1, num=100) tmp = ui.get_pvalue_results() assert tmp.null == pytest.approx(210.34566845619273) assert tmp.alt == pytest.approx(207.66618095925094) assert tmp.lr == pytest.approx(2.679487496941789)
def test_eqwith_err1(make_data_path, restore_xspec_settings): def check1(e0, e1, e2): assert e0 == pytest.approx(0.028335201547206704, rel=1.0e-3) assert e1 == pytest.approx(-0.00744118799274448756, rel=1.0e-3) assert e2 == pytest.approx(0.0706249544851336, rel=1.0e-3) ui.set_xsabund('angr') ui.set_xsxsect('bcmc') ui.load_pha(make_data_path('3c273.pi')) ui.notice(0.5, 7.0) ui.set_stat("chi2datavar") ui.set_method("simplex") ui.set_model('powlaw1d.p1+gauss1d.g1') g1.fwhm = 0.1 g1.pos = 2.0 ui.freeze(g1.pos, g1.fwhm) ui.fit() np.random.seed(2345) e = ui.eqwidth(p1, p1 + g1, error=True, niter=100) check1(e[0], e[1], e[2]) params = e[3] np.random.seed(2345) e = ui.eqwidth(p1, p1 + g1, error=True, params=params, niter=100) check1(e[0], e[1], e[2]) parvals = ui.get_fit_results().parvals assert parvals[0] == pytest.approx(1.9055272902160334, rel=1.0e-3) assert parvals[1] == pytest.approx(0.00017387966749772638, rel=1.0e-3) assert parvals[2] == pytest.approx(1.279415076070516e-05, rel=1.0e-3)
def test_eqwith_err1(make_data_path, restore_xspec_settings): def check1(e0, e1, e2): assert e0 == approx(0.028335201547206704, rel=1.0e-3) assert e1 == approx(-0.00744118799274448756, rel=1.0e-3) assert e2 == approx(0.0706249544851336, rel=1.0e-3) ui.set_xsabund('angr') ui.set_xsxsect('bcmc') ui.load_pha(make_data_path('3c273.pi')) ui.notice(0.5, 7.0) ui.set_stat("chi2datavar") ui.set_method("simplex") ui.set_model('powlaw1d.p1+gauss1d.g1') g1.fwhm = 0.1 g1.pos = 2.0 ui.freeze(g1.pos, g1.fwhm) ui.fit() numpy.random.seed(2345) e = ui.eqwidth(p1, p1 + g1, error=True, niter=100) check1(e[0], e[1], e[2]) params = e[3] numpy.random.seed(2345) e = ui.eqwidth(p1, p1 + g1, error=True, params=params, niter=100) check1(e[0], e[1], e[2]) parvals = ui.get_fit_results().parvals assert parvals[0] == approx(1.9055272902160334, rel=1.0e-3) assert parvals[1] == approx(0.00017387966749772638, rel=1.0e-3) assert parvals[2] == approx(1.279415076070516e-05, rel=1.0e-3)
def fit(self): """ Do a fit of the model parameters using the "onion-peeling" method: - First fit the outside shell model using the outer annulus spectrum - Freeze the model parameters for the outside shell - Fit the next inward shell / annulus and freeze those parameters - Repeat until all datasets have been fit and all shell parameters determined. - Return model parameters to original thawed/frozen status :rtype: None """ thawed = [] # Parameter objects that are not already frozen for annulus in reversed(range(self.nshell)): dataids = [x['id'] for x in self.datasets if x['annulus'] == annulus] print 'Fitting', dataids SherpaUI.fit(*dataids) for model_comp in self.model_comps: name = model_comp['name'] if model_comp['shell'] == annulus: # Remember parameters that are currently thawed for par in [SherpaUI.get_par('%s.%s'%(name, x)) for x in SherpaUI.get_model_pars(name)]: if not par.frozen: thawed.append(par) print 'Freezing', model_comp['name'] SherpaUI.freeze(model_comp['name']) # Unfreeze parameters for par in thawed: print 'Thawing', par.fullname par.thaw()
def loadPars(amodel, readFrom): """ """ with open(readFrom, 'r') as f: parDict = json.load(f) for p in amodel.pars: val, frozen = parDict[p.name] p.val = val if frozen: ui.freeze(p)
def setup(imgfile, emapfile): shp.load_data(imgfile) shp.load_table_model('emap', emapfile) shp.freeze(emap.ampl) # we're using an on axis psf provided in # /packages/CALDB/data/nustar/fpm/bcf/psf/ shp.load_psf('psf', 'nuA2dpsf20100101v003_onaxis.fits') shp.set_psf(psf) psf.center = (500.0, 500.0) psf.size = (200, 200)
def run_hspec_fit(self, model, thres_low, thres_high): """Run the gammapy.hspec fit Parameters ---------- model : str Sherpa model thres_high : `~gammapy.spectrum.Energy` Upper threshold of the spectral fit thres_low : `~gammapy.spectrum.Energy` Lower threshold of the spectral fit """ log.info("Starting HSPEC") import sherpa.astro.ui as sau from ..hspec import wstat from sherpa.models import PowLaw1D if model == 'PL': p1 = PowLaw1D('p1') p1.gamma = 2.2 p1.ref = 1e9 p1.ampl = 6e-19 else: raise ValueError('Desired Model is not defined') thres = thres_low.to('keV').value emax = thres_high.to('keV').value sau.freeze(p1.ref) sau.set_conf_opt("max_rstat", 100) list_data = [] for obs in self.observations: datid = obs.phafile.parts[-1][7:12] sau.load_data(datid, str(obs.phafile)) sau.notice_id(datid, thres, emax) sau.set_source(datid, p1) list_data.append(datid) wstat.wfit(list_data) sau.covar() fit_val = sau.get_covar_results() fit_attrs = ('parnames', 'parvals', 'parmins', 'parmaxes') fit = dict((attr, getattr(fit_val, attr)) for attr in fit_attrs) fit = self.apply_containment(fit) sau.clean() self.fit = fit
def fixBkgModel(id=1, freeNorm=True): """ Fix the background model Paramaters: freeNorm = True If freeNorm is True, leave the overall background normalization free. """ bk = ui.get_bkg_model(id=id) if freeNorm: pars = bk.pars c0 = pars[0] for p in pars[1:]: if p.val != 0 and p.fullname.startswith('pca'): ui.link(p, p.val / c0.val * c0) else: ui.freeze(p) else: ui.freeze(bk)
def test_rsp(self): fname = self.make_path("qso.pi") ui.load_pha(fname) ui.set_stat("chi2xspecvar") ui.set_method("neldermead") ui.group_counts(10) ui.notice(0.3, 8) ui.set_model("xsphabs.abs1*xspowerlaw.p1") ui.set_model("abs1*(p1+gauss1d.g1)") g1.pos = 3. ui.freeze(g1.pos) g1.fwhm = 0.1 ui.freeze(g1.fwhm) ui.set_stat('cstat') ui.fit() ui.plot_pvalue(p1, p1 + g1, num=100) tmp = ui.get_pvalue_results() expected = [210.34566845619273, 207.66618095925094, 2.679487496941789] self.compare_results(expected, [tmp.null, tmp.alt, tmp.lr])
def test_eqwith_err(make_data_path, restore_xspec_settings): def check(a0, a1, a2): assert a0 == pytest.approx(0.16443033244310976, rel=1e-3) assert a1 == pytest.approx(0.09205564216156815, rel=1e-3) assert a2 == pytest.approx(0.23933118287470895, rel=1e-3) ui.set_method('neldermead') ui.set_stat('cstat') ui.set_xsabund('angr') ui.set_xsxsect('bcmc') ui.load_data(make_data_path('12845.pi')) ui.notice(0.5, 7) ui.set_model("xsphabs.gal*xszphabs.zabs*(powlaw1d.p1+xszgauss.g1)") ui.set_par(gal.nh, 0.08) ui.freeze(gal) ui.set_par(zabs.redshift, 0.518) ui.set_par(g1.redshift, 0.518) ui.set_par(g1.Sigma, 0.01) ui.freeze(g1.Sigma) ui.set_par(g1.LineE, min=6.0, max=7.0) ui.fit() np.random.seed(12345) result = ui.eqwidth(p1, p1 + g1, error=True, niter=100) check(result[0], result[1], result[2]) params = result[3] np.random.seed(12345) result = ui.eqwidth(p1, p1 + g1, error=True, params=params, niter=100) check(result[0], result[1], result[2]) parvals = ui.get_fit_results().parvals assert parvals[0] == pytest.approx(0.6111340686157877, rel=1.0e-3) assert parvals[1] == pytest.approx(1.6409785803466297, rel=1.0e-3) assert parvals[2] == pytest.approx(8.960926761312153e-05, rel=1.0e-3) assert parvals[3] == pytest.approx(6.620017726014523, rel=1.0e-3) assert parvals[4] == pytest.approx(1.9279114810359657e-06, rel=1.0e-3)
def test_eqwith_err(make_data_path, restore_xspec_settings): def check(a0, a1, a2): assert a0 == approx(0.16443033244310976, rel=1e-3) assert a1 == approx(0.09205564216156815, rel=1e-3) assert a2 == approx(0.23933118287470895, rel=1e-3) ui.set_method('neldermead') ui.set_stat('cstat') ui.set_xsabund('angr') ui.set_xsxsect('bcmc') ui.load_data(make_data_path('12845.pi')) ui.notice(0.5, 7) ui.set_model("xsphabs.gal*xszphabs.zabs*(powlaw1d.p1+xszgauss.g1)") ui.set_par(gal.nh, 0.08) ui.freeze(gal) ui.set_par(zabs.redshift, 0.518) ui.set_par(g1.redshift, 0.518) ui.set_par(g1.Sigma, 0.01) ui.freeze(g1.Sigma) ui.set_par(g1.LineE, min=6.0, max=7.0) ui.fit() numpy.random.seed(12345) result = ui.eqwidth(p1, p1 + g1, error=True, niter=100) check(result[0], result[1], result[2]) params = result[3] numpy.random.seed(12345) result = ui.eqwidth(p1, p1 + g1, error=True, params=params, niter=100) check(result[0], result[1], result[2]) parvals = ui.get_fit_results().parvals assert parvals[0] == approx(0.6111340686157877, rel=1.0e-3) assert parvals[1] == approx(1.6409785803466297, rel=1.0e-3) assert parvals[2] == approx(8.960926761312153e-05, rel=1.0e-3) assert parvals[3] == approx(6.620017726014523, rel=1.0e-3) assert parvals[4] == approx(1.9279114810359657e-06, rel=1.0e-3)
def conf(self): """ Run conf on each of the model parameters using the "onion-peeling" method: - First conf the outside shell model using the outer annulus spectrum - Freeze the model parameters for the outside shell - get confidences for the next inward shell / annulus and freeze those parameters - Repeat until all datasets have been conf()-ed and all shell-by-shell error parameters determined. - Return model parameters to original thawed/frozen status - WARNING: This ignores the correlations between parameters :rtype: None """ thawed = [] # Parameter objects that are not already frozen conf_results = [] this_conf_result = [] for annulus in reversed(range(self.nshell)): dataids = [x['id'] for x in self.datasets if x['annulus'] == annulus] print 'Getting shell-by-shell confidence for dataset ', dataids SherpaUI.conf(*dataids) this_conf_result = SherpaUI.get_conf_results() conf_results.insert(0, this_conf_result) for model_comp in self.model_comps: name = model_comp['name'] if model_comp['shell'] == annulus: # Remember parameters that are currently thawed for par in [SherpaUI.get_par('%s.%s'%(name, x)) for x in SherpaUI.get_model_pars(name)]: if not par.frozen: thawed.append(par) print 'Freezing', model_comp['name'] SherpaUI.freeze(model_comp['name']) # Unfreeze parameters for par in thawed: print 'Thawing', par.fullname par.thaw() return conf_results
def make_fixed_temp_multi_apec(kTs, name_template='apec%d', norm=None): """Create a model summing multiple APEC components at fixed temperatures. *kTs* An iterable of temperatures for the components, in keV. *name_template* = 'apec%d' A template to use for the names of each component; it is string-formatted with the 0-based component number as an argument. *norm* = None An initial normalization to be used for every component, or None to use the Sherpa default. Returns: A tuple ``(total_model, sub_models)``, where *total_model* is a Sherpa model representing the sum of the APEC components and *sub_models* is a list of the individual models. This function creates a vector of APEC model components and sums them. Their *kT* parameters are set and then frozen (using :func:`sherpa.astro.ui.freeze`), so that upon exit from this function, the amplitude of each component is the only free parameter. """ total_model = None sub_models = [] for i, kT in enumerate(kTs): component = ui.xsapec(name_template % i) component.kT = kT ui.freeze(component.kT) if norm is not None: component.norm = norm sub_models.append(component) if total_model is None: total_model = component else: total_model = total_model + component return total_model, sub_models
def _run_hspec_fit(self): """Run the gammapy.hspec fit """ log.info("Starting HSPEC") import sherpa.astro.ui as sau from ..hspec import wstat sau.set_conf_opt("max_rstat", 100) thres_lo = self.energy_threshold_low.to('keV').value thres_hi = self.energy_threshold_high.to('keV').value sau.freeze(self.model.ref) list_data = [] for pha in self.pha: datid = pha.parts[-1][7:12] sau.load_data(datid, str(pha)) sau.notice_id(datid, thres_lo, thres_hi) sau.set_source(datid, self.model) list_data.append(datid) wstat.wfit(list_data)
def test_plot_pvalue(make_data_path, clean_astro_ui, hide_logging): """Check plot_pvalue with PHA data.""" fname = make_data_path("qso.pi") ui.load_pha(fname) ui.set_stat('cstat') ui.set_method("neldermead") ui.group_counts(10) ui.notice(0.3, 8) ui.set_model("xsphabs.abs1*(xspowerlaw.p1 +gauss1d.g1)") # move the fit close to the best fit to save a small amount # of time. abs1.nh = 0.05 p1.phoindex = 1.28 p1.norm = 2e-4 g1.ampl = 1.8e-5 g1.pos = 3. ui.freeze(g1.pos) g1.fwhm = 0.1 ui.freeze(g1.fwhm) # Could we reduce the number of bins to save evaluation time? # We do want a non-default num value when checking the shapes # of the output attributes. # ui.fit() ui.plot_pvalue(p1, p1 + g1, num=100, bins=20) tmp = ui.get_pvalue_results() assert tmp.null == pytest.approx(210.34566845619273) assert tmp.alt == pytest.approx(207.66618095925094) assert tmp.lr == pytest.approx(2.679487496941789) # Have we returned the correct info? # # Is it worth checking the stored data (aka how randomised is this # output)? # assert tmp.samples.shape == (100, 2) assert tmp.stats.shape == (100, 2) assert tmp.ratios.shape == (100, ) # Check the plot # tmp = ui.get_pvalue_plot() assert tmp.lr == pytest.approx(2.679487496941789) assert tmp.xlabel == 'Likelihood Ratio' assert tmp.ylabel == 'Frequency' assert tmp.title == 'Likelihood Ratio Distribution' # It would be nice to check the values here # assert tmp.ratios.shape == (100, ) assert tmp.xlo.shape == (21, ) assert tmp.xhi.shape == (21, ) assert tmp.y.shape == (21, )
def assign_model(model_name, i): """Dedicated set up for the most common models.""" if model_name == 'powlaw1d': from sherpa.models import PowLaw1D p1 = PowLaw1D('PowLaw' + str(i)) p1.gamma = 2.6 p1.ampl = 1e-20 p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'logparabola': p1 = logparabola('LogPar' + str(i)) p1.ampl = 1e-20 p1.c1 = 2. p1.c2 = 1. p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'plexpcutoff': # all parameters in TeV here from .models.plexpcutoff import MyPLExpCutoff p1 = MyPLExpCutoff('PLexpCutoff' + str(i)) p1.gamma = 2. p1.No = 1e-11 p1.beta = 1e-1 # 1/Ecutoff p1.Eo = 1 sau.freeze(p1.Eo) elif model_name == 'Finke': # EBL model from Finke et al. 2010 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename('datasets/ebl/frd_abs.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'Franceschini': # EBL model from Franceschini et al. 2012 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename( 'datasets/ebl/ebl_franceschini.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'synchro': # print('Synchrotron model not available yet, sorry.') # quit() # Stops with an error: ValueError: slice step cannot be zero from naima.sherpamod import Synchrotron p1 = Synchrotron('Synchro' + str(i)) p1.index = 2. p1.ampl = 1. elif model_name == 'ic': # Inverse Compton peak # Weird, it returns the fit results twice (actually, it seems to do everything twice) # Returns error except if --noplot: TypeError: calc() takes exactly 4 arguments (3 given) from naima.sherpamod import InverseCompton p1 = InverseCompton('IC' + str(i)) p1.index = 2. p1.ampl = 1e-7 # Not sure if the units are OK elif model_name == 'pion': # Pion-decay gamma-ray spectrum # Veeery slow convergence # also doubled operations and problems for plotting, like in ic. from naima.sherpamod import PionDecay p1 = PionDecay('Pion' + str(i)) p1.index = 2. p1.ampl = 10. else: # set initial parameter values manually # (user-defined models and models that need some extra import will not work) p1 = globals()[model_name](model_name + str(i)) set_manual_model(p1) return p1
def fit_sherpa(obsid_list, redshift, nH_Gal, energy, min_counts=25, kT_guess=3, Ab_guess=1, fix_nH_Gal=True, fix_abund=False, find_errors=True): spectra = [] for obs in obsid_list: temp = glob.glob('xaf_*_' + obs + '.pi') # get spectra of regions spectra.append( temp ) # spectra will be made of lists which have xaf_*_obs.pi filenames - access with spectra[i][j] spectra.sort() num_obs = len(obsid_list) num_reg = len(temp) filename = 'spectra_wabs_mekal.dat' results_file = open(filename, "w") results_file.write( '# Fit results for wabs*mekal (zeros indicate that no fitting was performed)\n' ) results_file.write( '# Reg_no. kT kT_loerr kT_hierr Z Z_loerr Z_hierr norm norm_loerr norm_hierr nH_Gal nH_loerr nH_hierr red_chisq total_counts num_bins\n' ) for i in range(num_reg): sherpa.clean() # clean everything cnts = numpy.zeros( num_obs ) # make array of zeros with index length same as num_obs to store counts max_rate = numpy.zeros(num_obs) # max count rate [counts/s/keV] data_set = 0 # data set number good_src_ids = numpy.zeros(num_obs, dtype=int) - 1 for j in range(num_obs): sherpa.load_pha( data_set, spectra[j] [i]) # load xaf_#_obs_####.pi and .arf and .rmf files. sherpa.ignore_id(data_set, 0.0, energy[0]) sherpa.ignore_id(data_set, energy[1], None) cnts[j] = sherpa.calc_data_sum(energy[0], energy[1], data_set) cnt_rate = sherpa.get_rate(data_set, filter=True) if len(cnt_rate) == 0: max_rate[ j] = 0.0 # when few counts (<50), get_rate can return zero-length array else: max_rate[j] = numpy.max(cnt_rate) sherpa.subtract(data_set) # subtract background sherpa.set_source( data_set, sherpa.xswabs.abs1 * sherpa.xsmekal.plsm1) # 1 temperature mekal model fit good_src_ids[j] = data_set data_set += 1 # same run for region but different obs # Filter out ignored obs good_src_ids_indx = numpy.where(good_src_ids >= 0) good_src_ids = good_src_ids[good_src_ids_indx] max_rate = max_rate[good_src_ids_indx] cnts = cnts[good_src_ids_indx] totcnts = numpy.sum(cnts) if totcnts >= min_counts: print('Fitting spectra in region: ' + str(i)) abs1.nH = nH_Gal abs1.cache = 0 if fix_nH_Gal: sherpa.freeze(abs1.nH) else: sherpa.thaw(abs1.nH) plsm1.kt = kT_guess sherpa.thaw(plsm1.kt) plsm1.Abundanc = Ab_guess if fix_abund: sherpa.freeze(plsm1.Abundanc) else: sherpa.thaw(plsm1.Abundanc) plsm1.redshift = redshift sherpa.freeze(plsm1.redshift) plsm1.cache = 0 sherpa.fit() fit_result = sherpa.get_fit_results() red_chi2 = fit_result.rstat num_bins = fit_result.numpoints if fix_nH_Gal: nH = nH_Gal kT = fit_result.parvals[0] if fix_abund: Z = Ab_guess norm = fit_result.parvals[1] else: Z = fit_result.parvals[1] norm = fit_result.parvals[2] else: nH = fit_result.parvals[0] kT = fit_result.parvals[1] if fix_abund: Z = Ab_guess norm = fit_result.parvals[2] else: Z = fit_result.parvals[2] norm = fit_result.parvals[3] del fit_result if find_errors: sherpa.covar() covar_result = sherpa.get_covar_results() if fix_nH_Gal: nH_loerr = 0.0 nH_hierr = 0.0 kT_loerr = covar_result.parmins[0] kT_hierr = covar_result.parmaxes[0] if fix_abund: Z_loerr = 0.0 Z_hierr = 0.0 norm_loerr = covar_result.parmins[1] norm_hierr = covar_result.parmaxes[1] else: Z_loerr = covar_result.parmins[1] Z_hierr = covar_result.parmaxes[1] norm_loerr = covar_result.parmins[2] norm_hierr = covar_result.parmaxes[2] else: nH_loerr = covar_result.parmins[0] nH_hierr = covar_result.parmaxes[0] kT_loerr = covar_result.parmins[1] kT_hierr = covar_result.parmaxes[1] if fix_abund: Z_loerr = 0.0 Z_hierr = 0.0 norm_loerr = covar_result.parmins[2] norm_hierr = covar_result.parmaxes[2] else: Z_loerr = covar_result.parmins[2] Z_hierr = covar_result.parmaxes[2] norm_loerr = covar_result.parmins[3] norm_hierr = covar_result.parmaxes[3] del covar_result # Check for failed errors (= None) and set them to +/- best-fit value if not fix_nH_Gal: if nH_loerr is None: nH_loerr = -nH # is was == if nH_hierr is None: nH_hierr = nH if kT_loerr is None: kT_loerr = -kT if kT_hierr is None: kT_hierr = kT if not fix_abund: if Z_loerr is None: Z_loerr = -Z if Z_hierr is None: Z_hierr = Z if norm_loerr is None: norm_loerr = -norm if norm_hierr is None: norm_hierr = norm else: kT_loerr = 0.0 Z_loerr = 0.0 nH_loerr = 0.0 norm_loerr = 0.0 kT_hierr = 0.0 Z_hierr = 0.0 nH_hierr = 0.0 norm_hierr = 0.0 else: # if total counts < min_counts, just write zeros print('\n Warning: no fit performed for for region: ' + str(i)) print( '\n Spectra have insufficient counts after filtering or do not exist.' ) print('\n --> All parameters for this region set to 0.0.') kT = 0.0 Z = 0.0 nH = 0.0 norm = 0.0 kT_loerr = 0.0 Z_loerr = 0.0 nH_loerr = 0.0 norm_loerr = 0.0 kT_hierr = 0.0 Z_hierr = 0.0 nH_hierr = 0.0 norm_hierr = 0.0 red_chi2 = 0.0 num_bins = 0 reg_id = spectra[0][i].split( '_' ) # Splits string after every underscore so that region number can be accessed. reg_id[1] is accessed because that is the region number after 'xaf' results_file.write( '%7r %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %6.4e %6.4e %6.4e %7.4f %7.4f %7.4f %7.4f %8.1f %8r\n' % (int(reg_id[1]), kT, kT_loerr, kT_hierr, Z, Z_loerr, Z_hierr, norm, norm_loerr, norm_hierr, nH, nH_loerr, nH_hierr, red_chi2, totcnts, num_bins)) # Write all data to a file results_file.close()
def test_beta_model_flux(): tmpdir = tempfile.mkdtemp() curdir = os.getcwd() os.chdir(tmpdir) r_c = 20.0 beta = 1.0 prng = 34 e = spec.generate_energies(exp_time, area, prng=prng) beta_src = BetaModel(ra0, dec0, r_c, beta, e.size, prng=prng) write_photon_list("beta", "beta", e.flux, beta_src.ra, beta_src.dec, e, overwrite=True) instrument_simulator("beta_simput.fits", "beta_evt.fits", exp_time, "acisi_cy0", [ra0, dec0], ptsrc_bkgnd=False, instr_bkgnd=False, foreground=False, roll_angle=37.0, prng=prng) ph_flux = spec.get_flux_in_band(0.5, 7.0)[0].value S0 = 3.0 * ph_flux / (2.0 * np.pi * r_c * r_c) wspec = spec.new_spec_from_band(0.5, 7.0) make_exposure_map("beta_evt.fits", "beta_expmap.fits", wspec.emid.value, weights=wspec.flux.value, overwrite=True) write_radial_profile("beta_evt.fits", "beta_evt_profile.fits", [ra0, dec0], 0.0, 100.0, 200, ctr_type="celestial", emin=0.5, emax=7.0, expmap_file="beta_expmap.fits", overwrite=True) load_data(1, "beta_evt_profile.fits", 3, ["RMID", "SUR_FLUX", "SUR_FLUX_ERR"]) set_stat("chi2") set_method("levmar") set_source("beta1d.src") src.beta = 1.0 src.r0 = 10.0 src.ampl = 0.8 * S0 freeze(src.xpos) fit() set_covar_opt("sigma", 1.645) covar() res = get_covar_results() assert np.abs(res.parvals[0] - r_c) < res.parmaxes[0] assert np.abs(res.parvals[1] - beta) < res.parmaxes[1] assert np.abs(res.parvals[2] - S0) < res.parmaxes[2] os.chdir(curdir) shutil.rmtree(tmpdir)
def test_beta_model(): tmpdir = tempfile.mkdtemp() curdir = os.getcwd() os.chdir(tmpdir) r_c = 20.0 beta = 1.0 exp_time = Quantity(500.0, "ks") e = spec.generate_energies(exp_time, area, prng=prng) beta_src = BetaModel(ra0, dec0, r_c, beta, e.size, prng=prng) write_photon_list("beta", "beta", e.flux, beta_src.ra, beta_src.dec, e, overwrite=True) instrument_simulator("beta_simput.fits", "beta_evt.fits", exp_time, "hdxi", [ra0, dec0], ptsrc_bkgnd=False, instr_bkgnd=False, foreground=False, prng=prng) inst = get_instrument_from_registry("hdxi") arf = AuxiliaryResponseFile(inst["arf"]) cspec = ConvolvedSpectrum(spec, arf) ph_flux = cspec.get_flux_in_band(0.5, 7.0)[0].value S0 = 3.0 * ph_flux / (2.0 * np.pi * r_c * r_c) write_radial_profile("beta_evt.fits", "beta_evt_profile.fits", [ra0, dec0], 0.0, 100.0, 200, ctr_type="celestial", emin=0.5, emax=7.0, overwrite=True) load_data(1, "beta_evt_profile.fits", 3, ["RMID", "SUR_BRI", "SUR_BRI_ERR"]) set_stat("chi2") set_method("levmar") set_source("beta1d.src") src.beta = 1.0 src.r0 = 10.0 src.ampl = 0.8 * S0 freeze(src.xpos) fit() set_covar_opt("sigma", 1.645) covar() res = get_covar_results() assert np.abs(res.parvals[0] - r_c) < res.parmaxes[0] assert np.abs(res.parvals[1] - beta) < res.parmaxes[1] assert np.abs(res.parvals[2] - S0) < res.parmaxes[2] os.chdir(curdir) shutil.rmtree(tmpdir)
import sherpa.astro.ui as shp shp.restore('20-40 keV/fits/chxepwnblob.sav') shp.set_conf_opt('numcores', 3) shp.set_conf_opt('maxiters', 50) shp.set_conf_opt('fast', True) shp.set_conf_opt('remin', 10000.0) shp.set_conf_opt('soft_limits', True) shp.set_conf_opt('verbose', True) shp.freeze(chxe) shp.thaw(chxe.ampl) print(shp.get_model()) shp.conf(blob.xpos, blob.ypos, blob.ellip, blob.fwhm, blob.theta, blob.ampl) shp.save('20-40 keV/fits/chxepwnblobconf.sav')
sh.load_image("analysis_3d/counts_2D.fits") sh.set_coord("logical") sh.load_table_model("expo", "analysis_3d/exposure_2D.fits") sh.load_table_model("bkg", "analysis_3d/background_2D.fits") sh.load_psf("psf", "analysis_3d/psf_2D.fits") # In principle one might first want to fit the background amplitude. However the background estimation method already yields the correct normalization, so we freeze the background amplitude to unity instead of adjusting it. The (smoothed) residuals from this background model are then computed and shown. # In[ ]: sh.set_full_model(bkg) bkg.ampl = 1 sh.freeze(bkg) # In[ ]: resid = Map.read("analysis_3d/counts_2D.fits") resid.data = sh.get_data_image().y - sh.get_model_image().y resid_smooth = resid.smooth(width=4) resid_smooth.plot(add_cbar=True); # ### Find and fit the brightest source # We then find the position of the maximum in the (smoothed) residuals map, and fit a (symmetrical) Gaussian source with that initial position: # In[ ]:
src_models = [src_model1, src_model1 * ui.const1d.ratio_12] vals_iter = izip(count(1), src_models, ds.get_response(), bkg_models, ds.get_bkg_scale()) for i, src_model, rsp, bkg_model, bkg_scale in vals_iter: ds[i].set_full_model(rsp(src_model) + bkg_scale * bkg_model) ds[i].set_bkg_full_model(bkg_model) ## Fit background ds.notice(0.5, 8.0) ui.set_method("neldermead") ui.set_stat("cash") ui.thaw(c1.c0) ui.thaw(c2.c0) ui.fit_bkg() ui.freeze(c1.c0) ui.freeze(c2.c0) ui.set_par(abs1.nh, 0.0398) ui.freeze(abs1) ui.fit() ds.plot_fit() # ds.plot_bkg_fit() # FIT OUTPUT: # # Datasets = 1, 2 # Method = neldermead # Statistic = cash # Initial fit statistic = -11105.6 # Final fit statistic = -11105.6 at function evaluation 64
def prepare_spectra(nH: float, group: int = 1, add_gal: bool = False, redshift: Optional[float] = None, **kwargs) -> float: """ Fit the spectra using an absorbed powerlaw model using the Wstat statistic. The function also returns a p-value for the gof. :param nH: The galactic absorption column density in units of 10^22 /cm3 :param group: The number of counts per energy bin :param add_gal: Setting this to True would add an intrinsic abrosption column density along side the galactic one :param redshift: The redshift to use in the fit. Only takes effect if add_gal is set to True ... :return: Returns the p-value of the gof. The null hypothesis states that the model and the observation differ while alternate says that the model explains the data """ pha = read_pha("core_spectrum.pi") pha.set_analysis("energy") pha.notice(0.5, 7.0) tabs = ~pha.mask pha.group_counts(group, tabStops=tabs) x = pha.get_x() x = pha.apply_filter(x, pha._middle) y = pha.get_y(filter=True) pha.set_analysis("energy") model = xsphabs.abs1 * powlaw1d.srcp1 print("Fitting the spectrum") zFlag = False if (nH is not None) and (nH > 0.0): if add_gal == 1: model = xsphabs.gal * xszphabs.abs1 * powlaw1d.srcp gal.nH = nH freeze(gal.nH) zFlag = True else: model = xsphabs.abs1 * powlaw1d.srcp1 abs1.nH = nH freeze(abs1.nH) else: model = xszphabs.abs1 * powlaw1d.srcp1 zFlag = True if zFlag is True and add_gal == 1: # print('REDSHIFT',redshift) abs1.redshift = redshift freeze(abs1.redshift) full_model = RSPModelPHA(pha.get_arf(), pha.get_rmf(), pha, pha.exposure * model) print(full_model) fit = Fit(pha, full_model, method=MonCar(), stat=WStat()) res = fit.fit() print(res.format()) print(fit.est_errors()) # calculate the p-value for wstat mplot2 = ModelPlot() mplot2.prepare(pha, full_model) miu = mplot2.y * pha.exposure * 0.0146 obs = y * pha.exposure * 0.0146 c, ce, cv = SpecUtils.estimate_gof_cstat(miu, obs) #print(f"C0={c},C_e={ce},C_v={cv}") zval = (fit.calc_stat() - ce) / np.sqrt(cv) if zval > 0: pval = special.erfc(zval / np.sqrt(2)) else: pval = special.erf(abs(zval) / np.sqrt(2)) print(f"p-value for wstat = {pval}") set_data(pha) set_model(model) save_chart_spectrum("core_flux_chart.dat", elow=0.5, ehigh=7.0) # save_chart_spectrum("core_flux_chart.rdb",format='text/tsv', elow=0.5, ehigh=7.0) SAOTraceUtils.save_spectrum_rdb("core_flux_chart.dat") return pval
def acis_bkg_model(detnam, root='bkg_', as_str=False): """Empirically derived background model for the ACIS detector, based on fitting a broken powerlaw plus 6 gaussians to ACIS background data. These models *require* that the corresponding ARF be set to a constant value of 100 and that the RMF be the correct RMF for the source and detector. The model is only calibrated between 0.5 and 9 keV. The following code is an example:: from acis_bkg_model import acis_bkg_model load_pha(1, 'acisf04938_000N002_r0043_pha3.fits') arf = get_arf() rmf = get_rmf() # Load the background ARF/RMF. This must be done in addition # to load_pha, otherwise the source and background arfs are # always identical. load_bkg_arf(1, arf.name) load_bkg_rmf(1, rmf.name) bkg_arf = get_bkg_arf(1) bkg_rmf = get_bkg_rmf(1) # Stub the bkg_arf to be a constant. This is required for use # of the acis_bkg_model models. bkg_arf.specresp = bkg_arf.specresp * 0 + 100. # Set scaling between background and source apertures # Roughly equivalent to # bkg_scale = get_exposure() * get_backscal() / (get_exposure(bkg_id=1) * get_backscal(bkg_id=1)) bkg_scale = get_data(1).sum_background_data(lambda x,y: 1) # Set source and background models. This source is on ACIS-I CCDID = 2 (acis2i). bkg_model = const1d.c1 * acis_bkg_model('acis2i') set_full_model(rsp(powlaw1d.pow1) + bkg_scale * bkg_rsp(bkg_model)) set_bkg_full_model(bkg_rmf(bkg(arf(bkg_model)))) set_full_model(powlaw1d.pow1) set_bkg_full_model(bkg_rmf(bkg_arf( const1d.c1 * acis_bkg_model('acis2i')))) fit() # or fit_bkg() to only fit the background :param detnam: detector name 'acis<CCD_ID><aimpoint det: i or s>' :returns: sherpa model for background """ comps = (('powlaw1d', 'pow1'), ('powlaw1d', 'pow2'), ('gauss1d', 'g1'), ('gauss1d', 'g2'), ('gauss1d', 'g3'), ('gauss1d', 'g4'), ('gauss1d', 'g5'), ('gauss1d', 'g6')) model_comps = dict() for mtype, name in comps: ui.create_model_component(mtype, root + name) model_comp = model_comps[name] = eval(root + name) if mtype == 'gauss1d': model_comp.ampl.min = 0.0 ui.freeze(model_comp) model_comp.integrate = True if detnam in pars: for parname, parval in pars[detnam].items(): name, attr = parname.split('.') setattr(model_comps[name], attr, parval) else: raise ValueError('No background model available for "{0}". Must be one of {1}'.format( detnam, sorted(pars.keys()))) if as_str: out = ' + '.join([root + name for mtype, name in comps]) else: mc = model_comps out = mc['pow1'] + mc['pow2'] + mc['g1'] + mc['g2'] + mc['g3'] + mc['g4'] + mc['g5'] + mc['g6'] return out
def assign_model(model_name, i): """Dedicated set up for the most common models.""" if model_name == 'powlaw1d': from sherpa.models import PowLaw1D p1 = PowLaw1D('PowLaw' + str(i)) p1.gamma = 2.6 p1.ampl = 1e-20 p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'logparabola': p1 = logparabola('LogPar' + str(i)) p1.ampl = 1e-20 p1.c1 = 2. p1.c2 = 1. p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'plexpcutoff': # all parameters in TeV here from .models.plexpcutoff import MyPLExpCutoff p1 = MyPLExpCutoff('PLexpCutoff' + str(i)) p1.gamma = 2. p1.No = 1e-11 p1.beta = 1e-1 # 1/Ecutoff p1.Eo = 1 sau.freeze(p1.Eo) elif model_name == 'Finke': # EBL model from Finke et al. 2010 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename('datasets/ebl/frd_abs.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'Franceschini': # EBL model from Franceschini et al. 2012 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename('datasets/ebl/ebl_franceschini.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'synchro': # print('Synchrotron model not available yet, sorry.') # quit() # Stops with an error: ValueError: slice step cannot be zero from naima.sherpamod import Synchrotron p1 = Synchrotron('Synchro' + str(i)) p1.index = 2. p1.ampl = 1. elif model_name == 'ic': # Inverse Compton peak # Weird, it returns the fit results twice (actually, it seems to do everything twice) # Returns error except if --noplot: TypeError: calc() takes exactly 4 arguments (3 given) from naima.sherpamod import InverseCompton p1 = InverseCompton('IC' + str(i)) p1.index = 2. p1.ampl = 1e-7 # Not sure if the units are OK elif model_name == 'pion': # Pion-decay gamma-ray spectrum # Veeery slow convergence # also doubled operations and problems for plotting, like in ic. from naima.sherpamod import PionDecay p1 = PionDecay('Pion' + str(i)) p1.index = 2. p1.ampl = 10. else: # set initial parameter values manually # (user-defined models and models that need some extra import will not work) p1 = globals()[model_name](model_name + str(i)) set_manual_model(p1) return p1
def fit(self): # try a PCA decomposition of this spectrum initial = self.decompose() ui.set_method('neldermead') bkgmodel = PCAModel('pca%s' % self.id, data=self.pca) self.bkgmodel = bkgmodel response = get_identity_response(self.id) convbkgmodel = response(bkgmodel) ui.set_bkg_full_model(self.id, convbkgmodel) for p, v in zip(bkgmodel.pars, initial): p.val = v srcmodel = ui.get_model(self.id) ui.set_full_model(self.id, srcmodel) initial_v = self.calc_bkg_stat() # print('before fit: stat: %s' % (initial_v)) ui.fit_bkg(id=self.id) # print('fit: first full fit done') final = [p.val for p in ui.get_bkg_model(self.id).pars] # print('fit: parameters: %s' % (final)) initial_v = self.calc_bkg_stat() # print('fit: stat: %s' % (initial_v)) # lets try from zero # logf.info('fit: second full fit from zero') for p in bkgmodel.pars: p.val = 0 ui.fit_bkg(id=self.id) initial_v0 = self.calc_bkg_stat() # logf.info('fit: parameters: %s' % (final)) # logf.info('fit: stat: %s' % (initial_v0)) # pick the better starting point if initial_v0 < initial_v: # logf.info('fit: using zero-fit') initial_v = initial_v0 final = [p.val for p in ui.get_bkg_model(self.id).pars] else: # logf.info('fit: using decomposed-fit') for p, v in zip(bkgmodel.pars, final): p.val = v # start with the full fit and remove(freeze) parameters print('%d parameters, stat=%.2f' % (len(initial), initial_v)) results = [(2 * len(final) + initial_v, final, len(final), initial_v)] for i in range(len(initial) - 1, 0, -1): bkgmodel.pars[i].val = 0 bkgmodel.pars[i].freeze() ui.fit_bkg(id=self.id) final = [p.val for p in ui.get_bkg_model(self.id).pars] v = self.calc_bkg_stat() print('--> %d parameters, stat=%.2f' % (i, v)) results.insert(0, (v + 2 * i, final, i, v)) print() print('Background PCA fitting AIC results:') print('-----------------------------------') print() print('stat Ncomp AIC') for aic, params, nparams, val in results: print('%-05.1f %2d %-05.1f' % (val, nparams, aic)) aic, final, nparams, val = min(results) for p, v in zip(bkgmodel.pars, final): p.val = v for i in range(nparams): bkgmodel.pars[i].thaw() print() print('Increasing parameters again...') # now increase the number of parameters again # results = [(aic, final, nparams, val)] last_aic, last_final, last_nparams, last_val = aic, final, nparams, val for i in range(last_nparams, len(bkgmodel.pars)): next_nparams = i + 1 bkgmodel.pars[i].thaw() for p, v in zip(bkgmodel.pars, last_final): p.val = v ui.fit_bkg(id=self.id) next_final = [p.val for p in ui.get_bkg_model(self.id).pars] v = self.calc_bkg_stat() next_aic = v + 2 * next_nparams if next_aic < last_aic: # accept print('%d parameters, aic=%.2f ** accepting' % (next_nparams, next_aic)) last_aic, last_final, last_nparams, last_val = next_aic, next_final, next_nparams, v else: print('%d parameters, aic=%.2f' % (next_nparams, next_aic)) # stop if we are 3 parameters ahead what we needed if next_nparams >= last_nparams + 3: break print('Final choice: %d parameters, aic=%.2f' % (last_nparams, last_aic)) # reset to the last good solution for p, v in zip(bkgmodel.pars, last_final): p.val = v last_model = convbkgmodel for i in range(10): print('Adding Gaussian#%d' % (i + 1)) # find largest discrepancy ui.set_analysis(self.id, "ener", "rate") m = ui.get_bkg_fit_plot(self.id) y = m.dataplot.y.cumsum() z = m.modelplot.y.cumsum() diff_rate = np.abs(y - z) ui.set_analysis(self.id, "ener", "counts") m = ui.get_bkg_fit_plot(self.id) x = m.dataplot.x y = m.dataplot.y.cumsum() z = m.modelplot.y.cumsum() diff = np.abs(y - z) i = np.argmax(diff) energies = x e = x[i] print( 'largest remaining discrepancy at %.3fkeV[%d], need %d counts' % (x[i], i, diff[i])) # e = x[i] power = diff_rate[i] # lets try to inject a gaussian there g = ui.xsgaussian('g_%d_%d' % (self.id, i)) print('placing gaussian at %.2fkeV, with power %s' % (e, power)) # we work in energy bins, not energy g.LineE.min = energies[0] g.LineE.max = energies[-1] g.LineE.val = e if i > len(diff) - 2: i = len(diff) - 2 if i < 2: i = 2 g.Sigma = (x[i + 1] - x[i - 1]) g.Sigma.min = (x[i + 1] - x[i - 1]) / 3 g.Sigma.max = x[-1] - x[0] g.norm.min = power * 1e-6 g.norm.val = power convbkgmodel2 = response(g) next_model = last_model + convbkgmodel2 ui.set_bkg_full_model(self.id, next_model) ui.fit_bkg(id=self.id) next_final = [p.val for p in ui.get_bkg_model(self.id).pars] next_nparams = len(next_final) v = self.calc_bkg_stat() next_aic = v + 2 * next_nparams print('with Gaussian:', next_aic, '; change: %.1f (negative is good)' % (next_aic - last_aic)) if next_aic < last_aic: print('accepting') last_model = next_model last_aic, last_final, last_nparams, last_val = next_aic, next_final, next_nparams, v else: print('not significant, rejecting') ui.set_bkg_full_model(self.id, last_model) for p, v in zip(last_model.pars, last_final): p.val = v if v == 0: # the parameter was frozen. ui.freeze(p) break self.cstat, self.dof = self.calc_bkg_stat( dof=True) # Save the final cstat and dof (dof = ihi - ilo) self.filter_energy = ui.get_filter( ) # Save the filter for background fitting. ui.set_analysis('channel') ui.ignore() ui.notice(self.filter0) # restore filter ui.set_analysis('energy')
def acis_bkg_model(detnam, root='bkg_', as_str=False): """Empirically derived background model for the ACIS detector, based on fitting a broken powerlaw plus 6 gaussians to ACIS background data. These models *require* that the corresponding ARF be set to a constant value of 100 and that the RMF be the correct RMF for the source and detector. The model is only calibrated between 0.5 and 9 keV. The following code is an example:: from acis_bkg_model import acis_bkg_model load_pha(1, 'acisf04938_000N002_r0043_pha3.fits') arf = get_arf() rmf = get_rmf() # Load the background ARF/RMF. This must be done in addition # to load_pha, otherwise the source and background arfs are # always identical. load_bkg_arf(1, arf.name) load_bkg_rmf(1, rmf.name) bkg_arf = get_bkg_arf(1) bkg_rmf = get_bkg_rmf(1) # Stub the bkg_arf to be a constant. This is required for use # of the acis_bkg_model models. bkg_arf.specresp = bkg_arf.specresp * 0 + 100. # Set scaling between background and source apertures # Roughly equivalent to # bkg_scale = get_exposure() * get_backscal() / (get_exposure(bkg_id=1) * get_backscal(bkg_id=1)) bkg_scale = get_data(1).sum_background_data(lambda x,y: 1) # Set source and background models. This source is on ACIS-I CCDID = 2 (acis2i). bkg_model = const1d.c1 * acis_bkg_model('acis2i') set_full_model(rsp(powlaw1d.pow1) + bkg_scale * bkg_rsp(bkg_model)) set_bkg_full_model(bkg_rmf(bkg(arf(bkg_model)))) set_full_model(powlaw1d.pow1) set_bkg_full_model(bkg_rmf(bkg_arf( const1d.c1 * acis_bkg_model('acis2i')))) fit() # or fit_bkg() to only fit the background :param detnam: detector name 'acis<CCD_ID><aimpoint det: i or s>' :returns: sherpa model for background """ from sherpa.astro import ui global pars comps = (('powlaw1d', 'pow1'), ('powlaw1d', 'pow2'), ('gauss1d', 'g1'), ('gauss1d', 'g2'), ('gauss1d', 'g3'), ('gauss1d', 'g4'), ('gauss1d', 'g5'), ('gauss1d', 'g6')) model_comps = dict() for mtype, name in comps: ui.create_model_component(mtype, root + name) model_comp = model_comps[name] = ui.get_model_component(root + name) if mtype == 'gauss1d': model_comp.ampl.min = 0.0 ui.freeze(model_comp) model_comp.integrate = True if detnam in pars: for parname, parval in pars[detnam].items(): name, attr = parname.split('.') setattr(model_comps[name], attr, parval) else: raise ValueError( 'No background model available for "{0}". Must be one of {1}'. format(detnam, sorted(pars.keys()))) if as_str: out = ' + '.join([root + name for mtype, name in comps]) else: mc = model_comps out = mc['pow1'] + mc['pow2'] + mc['g1'] + mc['g2'] + mc['g3'] + mc[ 'g4'] + mc['g5'] + mc['g6'] return out
import sherpa.astro.ui as sh sh.set_stat("cash") sh.set_method("simplex") sh.load_image('../datasets/images/MSH15-52_counts.fits.gz') sh.set_coord("logical") sh.load_table_model("expo", "../datasets/images/MSH15-52_exposure.fits.gz") sh.load_table_model("bkg", "../datasets/images/MSH15-52_background.fits.gz") sh.load_psf("psf", "../datasets/images/MSH15-52_psf.fits.gz") # In[54]: sh.set_full_model(bkg) bkg.ampl = 1 sh.freeze(bkg) data = sh.get_data_image().y - sh.get_model_image().y resid = SkyImage(data=data, wcs=ref_image.wcs) resid_table = [] #Keep residual images in a list to show them later resid_smo6 = resid.smooth(radius=6) resid_smo6.plot(vmax=5, add_cbar=True) resid_table.append(resid_smo6) # In[55]: maxcoord = resid_smo6.lookup_max() maxpix = resid_smo6.wcs_skycoord_to_pixel(maxcoord[0]) print(maxcoord) print(maxpix)
# theta = 57 deg (from positive north) shp.set_par(chxe.xpos, 497.4, 497.4 - 4, 497.4 + 4) shp.set_par(chxe.ypos, 499.1, 499.1 - 4, 499.1 + 4) shp.set_par(chxe.fwhm, 30, 1, 200) shp.set_par(chxe.ellip, .5) shp.set_par(chxe.theta, -.9948) shp.set_par(chxe.ampl, 1e-5) shp.thaw(chxe.ellip, chxe.xpos, chxe.ypos) print(shp.get_model()) shp.ignore2d('circle(500,500,1000)') shp.notice2d('circle(500,500,60)') shp.ignore2d('circle(500,500,' + str(r) + ')') shp.fit() print(shp.get_model()) shp.set_conf_opt('numcores', 3) shp.set_conf_opt('maxiters', 50) shp.set_conf_opt('fast', True) shp.set_conf_opt('remin', 10000.0) shp.set_conf_opt('soft_limits', True) shp.freeze(chxe.xpos, chxe.ypos) #shp.conf(chxe.ellip, chxe.fwhm) utils.save_components('40-50 keV/chxe' + str(int(r * 2.5)) + '.model', ['chxe']) shp.save('40-50 keV/fits/chxe150/chxe' + str(int(r * 2.5)) + 'fit.sav')
def fit_sherpa(obsid_list, redshift, nH_Gal, energy, min_counts=25, kT_guess=3, Ab_guess=1, fix_nH_Gal=True, fix_abund=False, find_errors=True): spectra = [] for obs in obsid_list: temp = glob.glob('xaf_*_' + obs + '.pi') # get spectra of regions spectra.append(temp) # spectra will be made of lists which have xaf_*_obs.pi filenames - access with spectra[i][j] spectra.sort() num_obs = len(obsid_list) num_reg = len(temp) filename = 'spectra_wabs_mekal.dat' results_file = open(filename, "w") results_file.write('# Fit results for wabs*mekal (zeros indicate that no fitting was performed)\n') results_file.write('# Reg_no. kT kT_loerr kT_hierr Z Z_loerr Z_hierr norm norm_loerr norm_hierr nH_Gal nH_loerr nH_hierr red_chisq total_counts num_bins\n') for i in range(num_reg): sherpa.clean() # clean everything cnts = numpy.zeros(num_obs) # make array of zeros with index length same as num_obs to store counts max_rate = numpy.zeros(num_obs) # max count rate [counts/s/keV] data_set = 0 # data set number good_src_ids = numpy.zeros(num_obs, dtype=int) - 1 for j in range(num_obs): sherpa.load_pha(data_set, spectra[j][i]) # load xaf_#_obs_####.pi and .arf and .rmf files. sherpa.ignore_id(data_set, 0.0, energy[0]) sherpa.ignore_id(data_set, energy[1], None) cnts[j] = sherpa.calc_data_sum(energy[0], energy[1], data_set) cnt_rate = sherpa.get_rate(data_set, filter=True) if len(cnt_rate) == 0: max_rate[j] = 0.0 # when few counts (<50), get_rate can return zero-length array else: max_rate[j] = numpy.max(cnt_rate) sherpa.subtract(data_set) # subtract background sherpa.set_source(data_set, sherpa.xswabs.abs1 * sherpa.xsmekal.plsm1) # 1 temperature mekal model fit good_src_ids[j] = data_set data_set += 1 # same run for region but different obs # Filter out ignored obs good_src_ids_indx = numpy.where(good_src_ids >= 0) good_src_ids = good_src_ids[good_src_ids_indx] max_rate = max_rate[good_src_ids_indx] cnts = cnts[good_src_ids_indx] totcnts = numpy.sum(cnts) if totcnts >= min_counts: print('Fitting spectra in region: ' + str(i)) abs1.nH = nH_Gal abs1.cache = 0 if fix_nH_Gal: sherpa.freeze(abs1.nH) else: sherpa.thaw(abs1.nH) plsm1.kt = kT_guess sherpa.thaw(plsm1.kt) plsm1.Abundanc = Ab_guess if fix_abund: sherpa.freeze(plsm1.Abundanc) else: sherpa.thaw(plsm1.Abundanc) plsm1.redshift = redshift sherpa.freeze(plsm1.redshift) plsm1.cache = 0 sherpa.fit() fit_result = sherpa.get_fit_results() red_chi2 = fit_result.rstat num_bins = fit_result.numpoints if fix_nH_Gal: nH = nH_Gal kT = fit_result.parvals[0] if fix_abund: Z = Ab_guess norm = fit_result.parvals[1] else: Z = fit_result.parvals[1] norm = fit_result.parvals[2] else: nH = fit_result.parvals[0] kT = fit_result.parvals[1] if fix_abund: Z = Ab_guess norm = fit_result.parvals[2] else: Z = fit_result.parvals[2] norm = fit_result.parvals[3] del fit_result if find_errors: sherpa.covar() covar_result = sherpa.get_covar_results() if fix_nH_Gal: nH_loerr = 0.0 nH_hierr = 0.0 kT_loerr = covar_result.parmins[0] kT_hierr = covar_result.parmaxes[0] if fix_abund: Z_loerr = 0.0 Z_hierr = 0.0 norm_loerr = covar_result.parmins[1] norm_hierr = covar_result.parmaxes[1] else: Z_loerr = covar_result.parmins[1] Z_hierr = covar_result.parmaxes[1] norm_loerr = covar_result.parmins[2] norm_hierr = covar_result.parmaxes[2] else: nH_loerr = covar_result.parmins[0] nH_hierr = covar_result.parmaxes[0] kT_loerr = covar_result.parmins[1] kT_hierr = covar_result.parmaxes[1] if fix_abund: Z_loerr = 0.0 Z_hierr = 0.0 norm_loerr = covar_result.parmins[2] norm_hierr = covar_result.parmaxes[2] else: Z_loerr = covar_result.parmins[2] Z_hierr = covar_result.parmaxes[2] norm_loerr = covar_result.parmins[3] norm_hierr = covar_result.parmaxes[3] del covar_result # Check for failed errors (= None) and set them to +/- best-fit value if not fix_nH_Gal: if nH_loerr is None: nH_loerr = -nH # is was == if nH_hierr is None: nH_hierr = nH if kT_loerr is None: kT_loerr = -kT if kT_hierr is None: kT_hierr = kT if not fix_abund: if Z_loerr is None: Z_loerr = -Z if Z_hierr is None: Z_hierr = Z if norm_loerr is None: norm_loerr = -norm if norm_hierr is None: norm_hierr = norm else: kT_loerr = 0.0 Z_loerr = 0.0 nH_loerr = 0.0 norm_loerr = 0.0 kT_hierr = 0.0 Z_hierr = 0.0 nH_hierr = 0.0 norm_hierr = 0.0 else: # if total counts < min_counts, just write zeros print('\n Warning: no fit performed for for region: ' + str(i)) print('\n Spectra have insufficient counts after filtering or do not exist.') print('\n --> All parameters for this region set to 0.0.') kT = 0.0 Z = 0.0 nH = 0.0 norm = 0.0 kT_loerr = 0.0 Z_loerr = 0.0 nH_loerr = 0.0 norm_loerr = 0.0 kT_hierr = 0.0 Z_hierr = 0.0 nH_hierr = 0.0 norm_hierr = 0.0 red_chi2 = 0.0 num_bins = 0 reg_id = spectra[0][i].split('_') # Splits string after every underscore so that region number can be accessed. reg_id[1] is accessed because that is the region number after 'xaf' results_file.write('%7r %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %6.4e %6.4e %6.4e %7.4f %7.4f %7.4f %7.4f %8.1f %8r\n' % (int(reg_id[1]), kT, kT_loerr, kT_hierr, Z, Z_loerr, Z_hierr, norm, norm_loerr, norm_hierr, nH, nH_loerr, nH_hierr, red_chi2, totcnts, num_bins)) # Write all data to a file results_file.close()