def Roughfit_PL(obsname, Sourcename, obs_suffix='xwtw2po_cl_seporb.pha', NH=1.0, PL=2., outfile='Roughfit'): '''Given the observation number file of an observation, the Sourcename, and the name of an output file, this will preform a rough spectral fit to get a handle on the sources flux.''' spec = obsname + '/sw' + obsname + obs_suffix fits = pyfits.open(spec) xspec.AllData(spec) xspec.AllData.ignore("bad") xspec.AllData.ignore("**-0.5 10.0-**") model = xspec.Model("tbabs(po)") errorstr = '1.6 2 3' model.TBabs.nH = NH model.TBabs.nH.frozen = True model.powerlaw.PhoIndex.values = [PL, 0.01, -3.0, -2.0, 9.0, 10.0] xspec.Fit.query = 'yes' xspec.Fit.perform() xspec.Fit.perform() xspec.Plot.xAxis = "keV" xspec.Plot.device = "/xw" xspec.Plot("data", "resid") xspec.Plot() xspec.Fit.error(errorstr) try: xspec.AllModels.calcFlux("0.5 10. err 1000 90") except (RuntimeError, TypeError, NameError, 'Flux Command Error'): pass outf = open(outfile + '.spec', 'w') nH = xspec.AllModels(1)(1) outf.write('# nH: %f (%f - %f)\tChisq: %f\tDOF: %f\n' % (nH.values[0], nH.error[0], nH.error[1], xspec.Fit.statistic, xspec.Fit.dof)) outf.write( '# obsid\tflux\tflux_low\tflux_high\tgamma\tgamma_low\tgamma_high\tkT\tkT_low\tkT_high\tPLnorm/kTnorm\n' ) flux = xspec.AllData(1).flux output = '%s\t%E\t%E\t%E\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n' %\ ( spec, flux[0], flux[1], flux[2],xspec.AllModels(1)(2).values[0], xspec.AllModels(1)(2).error[0], xspec.AllModels(1)(2).error[1], 0, 0, 0, xspec.AllModels(1)(3).values[0] ) outf.write(output) outf.close() xspec.AllData.clear() xspec.AllModels.clear()
def grid_fe_k_flux(base_nH=1, base_fe=1, out=None): """Make a grid """ # Make it shut up xs.Xset.chatter = 9 # Ensure "standard" normalization snr = xs.AllModels(1, 'snr_src') snr.tbnew_gas.nH = base_nH snr.vnei.Fe = base_fe snr.vnei.norm = 1 # Temporarily unshutup to affirm baseline parameters xs.Xset.chatter = 10 snr.show() xs.Xset.chatter = 9 # First compute flux w/ "standard" norm (effectively, fix mass & distance) range_Tau = np.logspace(9, 13, 100) # Spans 1e9 to 1e13 range_kT = np.logspace(-1, 1, 100) # Spans 0.1 to 10 keV # Outputs erg_fluxes = np.zeros((len(range_Tau), len(range_kT))) phot_fluxes = np.zeros((len(range_Tau), len(range_kT))) # Time: ~50 minutes for 100x100 pts (1e9 to 1e13 s cm^{-3}, 0.1 to 10 keV) # for only one spectrum (0087940201 MOS merged) for i in range(len(range_Tau)): print "Tau = {:g}".format(range_Tau[i]), datetime.now() snr.vnei.Tau = range_Tau[i] for j in range(len(range_kT)): if j % 5 == 0: print " kT = {:g} ...".format(range_kT[j]) snr.vnei.kT = range_kT[j] snr.vnei.Fe = 0 xs.AllModels.calcFlux("6 7") continuum_erg = xs.AllData(1).flux[0] continuum_phot = xs.AllData(1).flux[3] snr.vnei.Fe = base_fe xs.AllModels.calcFlux("6 7") erg_fluxes[i,j] = (xs.AllData(1).flux[0] - continuum_erg) / snr.constant.factor.values[0] phot_fluxes[i,j] = (xs.AllData(1).flux[3] - continuum_phot) / snr.constant.factor.values[0] # Reset xs.Xset.chatter = 10 if out is None: out = "fe-k_flux_data/grid_nH{:g}_fe{:g}.npz".format(base_nH * 1e22, base_fe) np.savez(out, Tau=range_Tau, kT=range_kT, erg_fluxes=erg_fluxes, phot_fluxes=phot_fluxes)
def bkg_only_fit(output, steppar=False, error=False): """ Fit bkg region alone to XRB model """ out = g309.load_data_and_models(["bkg"], snr_model=None) set_energy_range(out['bkg']) xs.AllData.ignore("bad") # Reset XRB to "typical" values # As usual, fit is pretty sensitive to initial values # (initial kT values that are too small drive fit to a bad local minimum) xrb = xs.AllModels(1, 'xrb') xrb.setPars({xrb.apec.kT.index : "0.2, , 0, 0, 0.5, 1"}, # Unabsorped apec (local bubble) {xrb.tbnew_gas.nH.index : "1.5, , 0.01, 0.1, 5, 10"}, # Galactic absorption {xrb.apec_6.kT.index : "0.7, , 0, 0, 2, 4"}, # Absorbed apec (galactic halo) {xrb.apec.norm.index : 1e-3}, {xrb.apec_6.norm.index : 1e-3} ) xrb.apec.kT.frozen = False xrb.tbnew_gas.nH.frozen = False xrb.apec_6.kT.frozen = False xrb.apec.norm.frozen = False xrb.apec_6.norm.frozen = False xs.Fit.perform() if xs.Plot.device == "/xs": xs.Plot("ldata delchi") if steppar: xs.Fit.steppar("xrb:{:d} 0.1 0.5 20".format(xs_utils.par_num(xrb, xrb.apec.kT))) xs.Fit.steppar("xrb:{:d} 0.4 0.8 20".format(xs_utils.par_num(xrb, xrb.apec_6.kT))) if xs.Plot.device == "/xs": xs.Plot("ldata delchi") if error: xs.Xset.openLog(output + "_error.log") print "Error run started:", datetime.now() xs.Fit.error("xrb:{:d}".format(xs_utils.par_num(xrb, xrb.apec.kT)) + " xrb:{:d}".format(xs_utils.par_num(xrb, xrb.apec.norm)) + " xrb:{:d}".format(xs_utils.par_num(xrb, xrb.tbnew_gas.nH)) + " xrb:{:d}".format(xs_utils.par_num(xrb, xrb.apec_6.kT)) + " xrb:{:d}".format(xs_utils.par_num(xrb, xrb.apec_6.norm))) print "Error run complete:", datetime.now() xs.Xset.closeLog() # Dump useful things here... products(output) print_model(xrb, output + "_xrb.txt")
def xspec_flux(x): Temperature, z_, ind_file, El_, Eh_, Z_ = x L_factor, norm, abundance = 1e44, 1.0, Z_ E_norm = [El_, Eh_] xspec.Model("apec") m1 = xspec.AllModels(1) m1.setPars(Temperature, abundance, z_, norm) filename = mydirectory+"/parameter_files/xspec/" + str(ind_file) + ".fak" fs1 = xspec.FakeitSettings(response, ancillary, fileName = filename, \ exposure = 100000.0) xspec.AllData.fakeit(1,fs1,applyStats=False, noWrite = True) spec1 = xspec.AllData(1) xspec.AllModels.setEnergies(".01 100. 1000 log") xspec.AllModels.calcLumin("%f %f %f" %(E_norm[0],E_norm[1],z_)) L = spec1.lumin[0] xspec.AllModels.calcFlux("%f %f" %(E_norm[0],E_norm[1])) F = spec1.flux[0] new_norm = L_factor / (L * 1e44) m1.setPars({4:new_norm}) xspec.AllModels.calcLumin("%f %f %f" %(E_norm[0],E_norm[1],z_)) L_new = spec1.lumin[0] xspec.AllModels.calcFlux("%f %f" %(E_norm[0],E_norm[1])) F_new = spec1.flux[0] spec1.ignore("**-%f %f-**" %(E_norm[0],E_norm[1])) rate = spec1.rate[3] xspec.AllData.clear() return [F_new, rate]
def get_models_for_spec(spectrum): """Get all active XSPEC models for a given spectrum object's data group In practice, my spectra usually have data group == index (i.e., ignore data group entirely because each spectrum has some independent parameter... different XMM instrumental lines, SP contamination model) WARNING: not tested on models with no names (i.e. really simple fit cases). This should be an easy fix (TODO). Input: XSPEC spectrum object Output: list of `xspec.Model` objects, ordered by source number """ # Suppress "Spectrum X has no response for source Y" console warnings # that appear at chattiness >= 10 old_chatter = xs.Xset.chatter old_logChatter = xs.Xset.logChatter xs.Xset.chatter = 9 xs.Xset.logChatter = 9 models = [] for idx in sorted(xs.AllModels.sources): # Hack: if spectrum has no response for source number idx, # XSPEC throws a generic Exception (hence the generic "except") # This is the only way I know of to get a spectrum's source #s try: spectrum.multiresponse[idx - 1] # convert to 0-based index except: continue model_name = xs.AllModels.sources[idx] models.append(xs.AllModels(spectrum.dataGroup, model_name)) xs.Xset.chatter = old_chatter xs.Xset.logChatter = old_logChatter return models
def single_fit(output, region='src', with_bkg=True, free_elements=None, error=False, error_rerun=False, tau_scan=False, tau_freeze=None, nH_freeze=None, snr_model='vnei', **kwargs): """Fit any region to an arbitrary remnant model, possibly fitting XRB with background region as well. Arguments output: file stem string Keyword arguments region: region spectrum to be fitted with_bkg: fit to X-ray background region (bkg) simultaneously snr_model: snr model expression (and parameter setup) to use free_elements: (default) is [Si,S] if [], use solar abundances error: perform single error run tau_scan: steppar over plausible Tau values to ensure convergence to "correct" best fit tau_freeze: freeze ionization timescale to provided value nH_freeze: freeze SNR absorption to provided value kwargs - passed to g309_models.load_data_and_models (suffix, mosmerge, marfrmf) """ if free_elements is None: free_elements = ['Si', 'S'] # Set up spectra and models in XSPEC if with_bkg: out = g309.load_data_and_models([region, 'bkg'], snr_model=snr_model, **kwargs) set_energy_range(out['bkg']) else: out = g309.load_data_and_models([region], snr_model=snr_model, **kwargs) set_energy_range(out[region]) xs.AllData.ignore("bad") if snr_model == 'gauss': for extr in out[region]: extr.spec.ignore("**-5.0, 8.0-**") xrb = xs.AllModels(1, 'xrb') snr = xs.AllModels(1, 'snr_' + region) # Reset XRB to "typical" values, do NOT vary yet if with_bkg: xrb.setPars({xrb.apec.kT.index : "0.1, , 0, 0, 0.5, 1"}, # Unabsorped apec (local bubble) {xrb.tbnew_gas.nH.index : "1, , 0.1, 0.5, 5, 10"}, # Extragalactic absorption {xrb.tbnew_gas_5.nH.index : "1, , 0.1, 0.5, 5, 10"}, # Ridge absorption {xrb.apec_6.kT.index : "0.5, , 0, 0, 2, 4"}, # Galactic ridge (+ minimal halo maybe) {xrb.apec.norm.index : 1e-3}, {xrb.apec_6.norm.index : 1e-3} ) xs_utils.freeze_model(xrb) # Try floating norms to help initial fit xrb.apec.norm.frozen = False xrb.apec_6.norm.frozen = False def thaw_bkg(): for c in [xrb.apec.kT, xrb.tbnew_gas.nH, xrb.tbnew_gas_5.nH, xrb.apec_6.kT]: c.frozen = False xs.Fit.renorm() # Let SNR model vary (NOTE: this assumes default to be vnei...) if snr_model.startswith('vnei'): xs_utils.freeze_model(snr) # Configure initial SNR parameters if nH_freeze: snr.tbnew_gas.nH = nH_freeze else: snr.tbnew_gas.nH.frozen=False snr.vnei.kT.frozen=False snr.vnei.norm.frozen=False if tau_freeze: snr.vnei.Tau = tau_freeze else: snr.vnei.Tau.frozen = False for elem in free_elements: comp = snr.vnei.__getattribute__(elem) comp.frozen = False if snr_model == 'vnei+nei': snr.nei.norm = 0 elif snr_model == 'vnei+powerlaw': snr.powerlaw.PhoIndex = 2 snr.powerlaw.norm = 0 # zero elif snr_model == 'vnei+srcutlog': # srcutlog, w/ one free parameter, behaves better than powerlaw snr.srcutlog.__getattribute__('break').frozen = False # Run initial fit if with_bkg: # Fit has enormous trouble converging if tau_freeze: thaw_bkg() xs.Fit.perform() else: snr.vnei.Tau = 2e10 snr.vnei.Tau.frozen = True xs.Fit.perform() thaw_bkg() xs.Fit.perform() snr.vnei.Tau.frozen = False xs.Fit.perform() else: xs.Fit.perform() # Post-processing on initial fit if tau_scan: xs.Fit.steppar("log {:s}:{:d} 1e9 5e13 15".format(snr.name, xs_utils.par_num(snr, snr.vnei.Tau))) if snr_model == 'vnei+nei': snr.nei.kT.frozen = False snr.nei.Tau.frozen = False snr.nei.norm.frozen = False xs.Fit.perform() elif snr_model == 'vnei+powerlaw': snr.powerlaw.PhoIndex = 2 snr.powerlaw.norm = 0 # zero snr.powerlaw.norm.frozen = False xs.Fit.perform() snr.powerlaw.PhoIndex.frozen = False xs.Fit.perform() # Because powerlaw norm generally runs to zero, traverse moderately # strong power law cases xs.Fit.steppar("log {:s}:{:d} 1e-5 1e-2 30".format(snr.name, xs_utils.par_num(snr, snr.powerlaw.norm))) elif snr_model == 'vnei+srcutlog': # Check reasonably high break values: 15 -- 17 xs.Fit.steppar("{:s}:{:d} 15 17 20".format(snr.name, xs_utils.par_num(snr, snr.srcutlog.__getattribute__('break')) )) elif snr_model == 'vpshock': xs_utils.freeze_model(snr) snr.tbnew_gas.nH.frozen=False snr.vpshock.kT.frozen=False snr.vpshock.norm.frozen=False if tau_freeze: raise Exception("ERROR: vpshock not configured for fixed Tau") for elem in free_elements: comp = snr.vpshock.__getattribute__(elem) comp.frozen = False # vpshock fits are very ill behaved, must coerce into best fit snr.vpshock.Tau_l = 1e8 snr.vpshock.Tau_u = 5e10 xs.Fit.perform() if with_bkg: thaw_bkg() xs.Fit.perform() snr.vpshock.Tau_l.frozen = False snr.vpshock.Tau_u.frozen = False xs.Fit.perform() if tau_scan: # Since Tau_u is constrained to be greater than Tau_l (?) this # should ensure that both Tau_u and Tau_l traverse a range of # values. But I haven't checked it yet... xs.Fit.steppar("log {:s}:{:d} 1e9 5e13 15".format(snr.name, xs_utils.par_num(snr, snr.vpshock.Tau_u))) elif snr_model == 'gauss': # Not supported! Not at all constrained . . . assert not with_bkg xs_utils.freeze_model(snr) # Coupling between code is too tight, abstractions keep leaking. # Because models must be addressed by NUMBER in XSPEC # commands to tweak model parameters necessarily break # abstraction interface between "load models" and "fit models" # Possible solutions: (1) give up and let interfaces merge # (monolithic "g309_models_fits"), or . . . (2) stop whining if 'mosmerge' not in kwargs or kwargs['mosmerge']: instr_1 = xs.AllModels(1, 'instr_1') #instr_2 = xs.AllModels(2, 'instr_2') # Let PN instr lines fit instr_3 = xs.AllModels(3, 'instr_3') for instr in [instr_1, instr_3]: # Must update parameter lower limits instr.constant.factor.values = "0, , 0, 0, , " instr.constant.factor.frozen = True else: # No MOS merging instr_1 = xs.AllModels(1, 'instr_1') instr_2 = xs.AllModels(2, 'instr_2') #instr_3 = xs.AllModels(3, 'instr_3') # Let PN instr lines fit instr_4 = xs.AllModels(4, 'instr_4') instr_5 = xs.AllModels(5, 'instr_5') for instr in [instr_1, instr_2, instr_4, instr_5]: # Must update parameter lower limits instr.constant.factor.values = "0, , 0, 0, , " instr.constant.factor.frozen = True snr.tbnew_gas.nH = 0 snr.tbnew_gas.nH.frozen = True # LineE: lower/upper bounds set from Yamaguchi+ 2014 # Sigma: prevent line from over-widening to fit as "constant" addition # norm: no bounds snr.setPars({snr.gaussian.LineE.index : "6.55, , 6.2, 6.3, 6.8, 6.9", snr.gaussian.Sigma.index : "0.1, , 0, 0, 0.2, 0.5"} ) snr.gaussian.LineE.frozen=False snr.gaussian.Sigma.frozen=False snr.gaussian.norm.frozen=False xs.Fit.perform() else: raise Exception("Invalid SNR model - please add branch") # Compute standard 90% errors if error: xs.Xset.openLog(output + "_error.log") if with_bkg: xs.Fit.error(error_str_all_free(xrb)) xs.Fit.error(error_str_all_free(snr)) if error_rerun: if with_bkg: xs.Fit.error(error_str_all_free(xrb)) xs.Fit.error(error_str_all_free(snr)) xs.Xset.closeLog() # Dump standard outputs products(output) print_model(snr, output + "_{:s}.txt".format(snr.name)) if with_bkg: print_model(xrb, output + "_xrb.txt")
def load_cxrb(model_n, model_name, extracted_spectra): """Load cosmic X-ray background for each spectrum in extracted_spectra. Set appropriate RMF & ARF files, initialize XRB model and parameter values, apply BACKSCAL ratio scaling. ExtractedSpectrum objects additionally _must_ have an attached xs.Spectrum object, referenced via .spec attribute. Arguments model_n: XSPEC model number, 1-based model_name: XSPEC model name, string (no spaces) extracted_spectra: list of ExtractedSpectrum objects Output: None. Global XSPEC objects configured for XRB model. """ # Set responses of <xs.Spectrum> objects for extr in extracted_spectra: extr.spec.multiresponse[model_n - 1] = extr.rmf_flat() extr.spec.multiresponse[model_n - 1].arf = extr.arf_flat() # Initialize XRB model with reasonable "global" parameters xrb = xs.Model("constant * (apec + tbnew_gas*powerlaw + tbnew_gas*apec)", model_name, model_n) # Hickox and Markevitch (2006) norm # convert 10.9 photons cm^-2 s^-1 sr^-1 keV^-1 to photons cm^-2 s^-1 keV^-1 # sr^-1 --> XMM detector pixels (backscal unit, 0.05 arcsec^2) # # The prefactor 0.61 comes from removing point sources brighter than # 1e-14 erg cm^-2 s^-1 in 0.4-7.2 keV band. After accounting for # absorption + rescaling to 2-10 keV band, the point source threshold is # ~1.46e-14 erg cm^-2 sec^-1 in 2-10 keV band. # I integrate the distribution of Moretti+ (2003) to get the excluded # surface brightness, which is 39% of the total EXRB surf. brightness # in 2-10 keV, based on Hickox/Markevitch (2006) model. # Therefore, scale down EXRB normalization from 10.9 --> (1-0.39)*10.9 exrb_norm = 0.61 * 10.9 * (180 / pi)**-2 * 60**-4 * ( 1 / 0.05)**-2 * ExtractedSpectrum.FIDUCIAL_BACKSCAL # NOTE HARDCODED -- best fit values from src/bkg combined fit # after error runs on some parameters of interest # Corresponds to: 20161015_src_bkg_mg.log outputs xrb.setPars({ xrb.powerlaw.PhoIndex.index: 1.4, xrb.powerlaw.norm.index: exrb_norm, xrb.apec.kT.index: 0.265, # Unabsorped apec (local bubble) xrb.apec.norm.index: 2.36e-4, xrb.tbnew_gas.nH.index: 1.12, # Galactic absorption (for extragal background) xrb.tbnew_gas_5.nH.index: 1.39, # Halo absorption xrb.apec_6.kT.index: 0.744, # Absorbed apec (galactic halo) xrb.apec_6.norm.index: 1.94e-3 }) xs_utils.freeze_model(xrb) # Set individal spectrum parameters for extr in extracted_spectra: xrb_curr = xs.AllModels(extr.spec.index, model_name) # Apply backscal ratio scalings # Re-freeze because changing value from link thaws by default xrb_curr.constant.factor = extr.backscal( ) / ExtractedSpectrum.FIDUCIAL_BACKSCAL xrb_curr.constant.factor.frozen = True
def load_soft_proton(model_n, model_name, extracted_spectra, broken=True): """Set soft proton contamination power laws for each spectrum in extracted_spectra. Set appropriate RMF & ARF files, initialize parameters and parameter bounds, apply BACKSCAL ratio scaling. Ties power-law indices between MOS1 and MOS2 exposures in same obsid. Requires that each obsid has only one MOS1 and one MOS2 exposure. ExtractedSpectrum objects additionally _must_ have an attached xs.Spectrum object, referenced via .spec attribute. Arguments model_n: XSPEC model number, 1-based model_name: XSPEC model name, string (no spaces) extracted_spectra: list of ExtractedSpectrum objects broken: use broken power law? Output: None. Global XSPEC objects configured for soft proton model. """ # Set responses of <xs.Spectrum> objects for extr in extracted_spectra: extr.spec.multiresponse[model_n - 1] = extr.rmf_diag() extr.spec.multiresponse[model_n - 1].arf = "none" # Initialize sp model if broken: sp = xs.Model("constant * bknpower", model_name, model_n) else: sp = xs.Model("constant * powerlaw", model_name, model_n) # Set individal spectrum parameters for extr in extracted_spectra: sp_curr = xs.AllModels(extr.spec.index, model_name) # Let power law indices, norms vary independently # Must set index limits for each model; parameter limits do not # propagate through links if broken: if extr.obsid == '0551000201': sp_curr.bknpower.PhoIndx1.link = "" sp_curr.bknpower.PhoIndx1.values = "0.3, , 0, 0.1, 1, 2" sp_curr.bknpower.PhoIndx1.frozen = False sp_curr.bknpower.PhoIndx2.link = "" sp_curr.bknpower.PhoIndx2.values = "0.6, , 0, 0.1, 2, 3" sp_curr.bknpower.PhoIndx2.frozen = False sp_curr.bknpower.BreakE.link = "" sp_curr.bknpower.BreakE.values = "2.0, , 0, 0.5, 10, 20" sp_curr.bknpower.BreakE.frozen = False sp_curr.bknpower.norm.link = "" sp_curr.bknpower.norm.frozen = False elif extr.obsid == '0087940201': sp_curr.bknpower.PhoIndx1.link = "" sp_curr.bknpower.PhoIndx1.values = "0.4, , 0, 0.1, 1, 2" sp_curr.bknpower.PhoIndx1.frozen = False sp_curr.bknpower.PhoIndx2.link = xs_utils.link_name( sp_curr, sp_curr.bknpower.PhoIndx1) sp_curr.bknpower.PhoIndx2.frozen = False sp_curr.bknpower.BreakE.link = "" sp_curr.bknpower.BreakE.values = 20 sp_curr.bknpower.BreakE.frozen = True sp_curr.bknpower.norm.link = "" sp_curr.bknpower.norm.frozen = False else: raise Exception("sp model not set for {:s}".format(extr.obsid)) else: sp_curr.powerlaw.PhoIndex.link = "" sp_curr.powerlaw.PhoIndex.values = "0.4, , 0, 0.1, 1, 2" # Hard/soft limits sp_curr.powerlaw.PhoIndex.frozen = False sp_curr.powerlaw.norm.link = "" sp_curr.powerlaw.norm.frozen = False # Apply backscal ratio scalings to make comparing norms easier sp_curr.constant.factor = extr.backscal( ) / ExtractedSpectrum.FIDUCIAL_BACKSCAL sp_curr.constant.factor.frozen = True # Tie MOS1/MOS2 photon indices together for x in extracted_spectra: if x.instr != 'mos1': continue sp_mos1 = xs.AllModels(x.spec.index, model_name) sp_mos2 = None # Find matching MOS2 observation for y in extracted_spectra: if y.instr == 'mos2' and y.reg == x.reg and y.obsid == x.obsid: if sp_mos2: # May occur in complex XMM pointings raise Exception("Extra mos2 spectrum!") sp_mos2 = xs.AllModels(y.spec.index, model_name) # Tie photon indices if broken: sp_mos2.bknpower.PhoIndx1.link = xs_utils.link_name( sp_mos1, sp_mos1.bknpower.PhoIndx1) sp_mos2.bknpower.PhoIndx2.link = xs_utils.link_name( sp_mos1, sp_mos1.bknpower.PhoIndx2) else: sp_mos2.powerlaw.PhoIndex.link = xs_utils.link_name( sp_mos1, sp_mos1.powerlaw.PhoIndex)
def load_data_and_models(regs, snr_model='vnei', suffix='grp01', mosmerge=True, marfrmf=True, sp_bknpower=False): """ Load G309.2-0.6 data and initialize responses and models. After successful load (~1-10 minutes), global XSPEC session has 5*len(regs) spectra loaded (for the five XMM exposures we're using) and ready to be simultaneously fit to a model with sources: cosmic x-ray background source model (set by snr_model kwarg) soft proton power laws instrumental lines fixed from FWC data fits The returned hash is used to manipulate individual spectra or models Input: region stems for extracted XMM ESAS spectra; duplicates disallowed Keyword arguments: snr_model = vnei, vpshock None suffix = grp01, grp50 Output: hash keying each region to 5 ExtractedSpectrum objects, one per XMM exposure in use """ if len(set(regs)) != len(regs): raise Exception("Duplicate regions not allowed") # ExtractedSpectrum objects allow script to easily resolve pipeline outputs # order of regs sets the order of XSPEC datagroup assignment extrs_from = {} all_extrs = [] # Keep regs ordering for XSPEC datagroup assignment for reg in regs: if mosmerge: extrs = [ ExtractedSpectrum("0087940201", "mosmerge", reg, suffix=suffix, marfrmf=marfrmf), ExtractedSpectrum("0087940201", "pnS003", reg, suffix=suffix, marfrmf=marfrmf), ExtractedSpectrum("0551000201", "mosmerge", reg, suffix=suffix, marfrmf=marfrmf) ] else: extrs = [ ExtractedSpectrum("0087940201", "mos1S001", reg, suffix=suffix), ExtractedSpectrum("0087940201", "mos2S002", reg, suffix=suffix), ExtractedSpectrum("0087940201", "pnS003", reg, suffix=suffix), ExtractedSpectrum("0551000201", "mos1S001", reg, suffix=suffix), ExtractedSpectrum("0551000201", "mos2S002", reg, suffix=suffix) ] extrs_from[reg] = extrs all_extrs.extend(extrs) # Spectrum and response assignment # -------------------------------- for i, extr in enumerate(all_extrs, start=1): spec = xs_utils.load_spec(i, extr.pha(), background=extr.qpb(), default_dir=extr.repro_dir()) extr.spec = spec # Load models # ----------- # 1: x-ray background # 2: instrumental lines # 3, ... (3+n_reg-1): SNR plasma model # (3+n_reg), ..., (3+n_reg+n_spec): soft proton background # NOTE: loader methods below require that ExtractedSpectrum objects have # xs.Spectrum objects attached in .spec attribute # Attach xs.Model objects to ExtractedSpectrum for convenience # no need to address by: xs.AllModels(extr.spec.index, model_name) for extr in all_extrs: extr.models = {} load_cxrb(1, 'xrb', all_extrs) load_soft_proton(2, 'sp', all_extrs, broken=sp_bknpower) for extr in all_extrs: extr.models['sp'] = xs.AllModels(extr.spec.index, 'sp') extr.models['xrb'] = xs.AllModels(extr.spec.index, 'xrb') # SNR model -- distinct source model for each region # if "bkg" in regs, source numbering will be discontinuous for n_reg, reg in enumerate(regs): if reg == "bkg" or snr_model is None: continue model_n = 3 + n_reg load_remnant_model(model_n, "snr_" + reg, extrs_from[reg], case=snr_model) for extr in extrs_from[reg]: extr.models['snr'] = xs.AllModels(extr.spec.index, "snr_" + reg) # One instrumental line model per spectrum for n_extr, extr in enumerate(all_extrs): model_n = 3 + len(regs) + n_extr load_instr(model_n, "instr_{:d}".format(n_extr + 1), extr) extr.models['instr'] = xs.AllModels(extr.spec.index, "instr_{:d}".format(n_extr + 1)) return extrs_from
src.setPars({src.gaussian.Sigma.index: "0"}) src.gaussian.LineE.frozen = False src.gaussian.Sigma.frozen = True src.gaussian.norm.frozen = False elif case == 'vsedov': raise Exception("Need to test vsedov further, doesn't work") #src = xs.Model("constant * tbnew_gas * vsedov", model_name, model_n) #snr.vsedov.kT = 2 #snr.vsedov.kT_i = 1 else: print "Warning: case {} not pre-configured, please freeze and set parameters manually" # Set individal spectrum parameters for extr in extracted_spectra: src_curr = xs.AllModels(extr.spec.index, model_name) # Apply backscal ratio scalings src_curr.constant.factor = extr.backscal( ) / ExtractedSpectrum.FIDUCIAL_BACKSCAL src_curr.constant.factor.frozen = True # Save model for this spectrum def load_soft_proton(model_n, model_name, extracted_spectra, broken=True): """Set soft proton contamination power laws for each spectrum in extracted_spectra. Set appropriate RMF & ARF files, initialize parameters and parameter bounds, apply BACKSCAL ratio scaling. Ties power-law indices between MOS1 and MOS2 exposures in same obsid. Requires that each obsid has only one MOS1 and one MOS2 exposure.
'7.11 -0.0711 7 7 10 10', '1.9 -0.019 0 0 3 3', '95 -0.95 0.01 1 100 200', '300 -3 1 1 1e+06 1e+06', '1 -0.01 0 0 1 1', '0', '0.5 -0.005 -0.999 -0.999 10 10', '1 -0.01 0 0 1e+20 1e+24', '6.4 -0.064 0 0 1e+06 1e+06', '0.05 -0.0005 0 0 10 20', '= p11', '0.01 2.6316e-11 0 0 1e+20 1e+24', '0.02 -0.0002 0 0 0.1 0.1', '= p6', '= p12/(1. + p11)/(1./(1. + p11))^( - p6)', '= p6', '300 -3 1 1 1e+06 1e+06', '-1 -0.01 -3 -3 -1e-09 -1e-09', '= p11', '1 -0.01 0 0 1e+06 1e+06', '1 -0.01 0 0 1e+06 1e+06', '0.45 -0.0045 0.05 0.05 0.95 0.95', '= p19', '1 -0.01 0.01 0.01 100 100' ] XS.AllModels(1).setPars(pars) for nH in n.arange(20, 26.2, 0.2): XS.AllModels(1).plcabs.nH = 10**(nH - 22) for z in n.arange(6.0, 6.2, 0.1): XS.AllModels(1).plcabs.Redshift = z for nb in 2**n.arange(2, 11): filename = 'NH' + str(n.round(nH, 1)) + '_Z' + \ str(n.round(z, 1)) + '_N' + str(int(nb)) + '.fits' print(filename) saveintofile(filename, nb)
xcm.append('arf ' + src.response.arf) xcm.append('ignore ' + src.ignoredString()) xcm.append('model ' + m.expression) for i in np.arange(m.nParameters) + 1: p = m(i).values parvals = str(p[0]) for k in np.arange(len(p) - 1) + 1: parvals = parvals + ', ' + str(p[k]) xcm.append(parvals) xcm.append('statistic ' + xspec.Fit.statMethod) nh = m.wabs.nH.values[0] kt = m.apec.kT.values[0] norm = m.apec.norm.values[0] nh3 = m.wabs_3.nH.values[0] xspec.Fit.error("2.706 6") # param 6 is nh3 p6 = xspec.AllModels(1)(6) nhmin = p6.error[0] nhmax = p6.error[1] kt4 = m.apec_4.kT.values[0] norm4 = m.apec_4.norm.values[0] gnorm = m.gaussian.norm.values[0] """ now add cflux component, set the values to the previous best fit, freeze apec norms, and refit to get the cflux and its errors """ mostring2 = "wabs*apec + cflux*wabs*(apec + gaussian)" m2 = xspec.Model(mostring2) m2.wabs.nH = [nh, -0.1] m2.apec.kT = [kt, -0.1] m2.apec.norm = [norm, -0.1] m2.wabs_4.nH = [nh3, -0.1]
def calculate_hi(low_e=3.0, high_e=16.0, soft=(6.4, 9.7), hard=(9.7, 16.)): ''' Function to calculate hardness & intensity values. Arguments: Energy ranges in keV - low_e (float): Lower energy boundary for selection - high_e (float): Higher energy boundary for selection - soft (tuple of floats): Energy range between which to integrate the soft range - hard (tuple of floats): Energy range between which to integrate the hard range ''' purpose = 'Calculating hardness & intensity values' print len(purpose) * '=' + '\n' + purpose + '\n' + len(purpose) * '=' print 'Soft:', soft, 'Hard:', hard, '\n' + len(purpose) * '-' import os import pandas as pd import glob import xspec from collections import defaultdict from math import isnan from numpy import genfromtxt import paths import logs import execute_shell_commands as shell import database # Set log file filename = __file__.split('/')[-1].split('.')[0] logs.output(filename) # Import data os.chdir(paths.data) db = pd.read_csv(paths.database) # Compile Fortran code for later use cmpl = [ 'gfortran', paths.subscripts + 'integflux.f', '-o', paths.subscripts + 'integflux.xf' ] shell.execute(cmpl) # Only want spectra from std2 d = defaultdict(list) for sp, group in db[(db.modes == 'std2')].groupby('spectra'): # Determine variables obsid = group.obsids.values[0] path_obsid = group.paths_obsid.values[0] bkg_sp = group.spectra_bkg.values[0] rsp = group.rsp.values[0] fltr = group.filters.values[0] print obsid # Check whether response file is there if not os.path.isfile(rsp): print 'ERROR: No response file' continue # XSPEC Commands to unfold spectrum around flat powerlaw # Reason as per Heil et al. (see doi:10.1093/mnras/stv240): # "In order to measure the energy spectral hardness independantly of # long term changes in the PCA instrument response, fluxes are # generated in a model-independant way by dividing the PCA standard # 2 mode spectrum by the effective area of the intstrument response # in each spectral channel. This is carried out by unfolding the # spectrum with respect to a zero-slope power law (i.e. a constant) # in the XSPEC spectral-fitting software, and measuring the unfolded # flux over the specified energy range (interpolating where the # specified energy does not fall neatly at the each of a spectral # channel)." #xspec.Plot.device = '/xs' s1 = xspec.Spectrum(sp) s1.background = bkg_sp s1.response = os.path.join(paths.data, rsp) # Not really sure why you need to do ignore, and then notice s1.ignore('**-' + str(low_e + 1.) + ' ' + str(high_e - 1) + '-**') s1.notice(str(low_e) + '-' + str(high_e)) xspec.Model('powerlaw') xspec.AllModels(1).setPars(0.0, 1.0) # Index, Norm xspec.AllModels(1)(1).frozen = True xspec.AllModels(1)(2).frozen = True xspec.Plot('eufspec') # Output unfolded spectrum to lists e = xspec.Plot.x() e_err = xspec.Plot.xErr() ef = xspec.Plot.y() ef_err = xspec.Plot.yErr() model = xspec.Plot.model() # Pipe output to file eufspec = path_obsid + 'eufspec.dat' with open(eufspec, 'w') as f: #Give header of file - must be three lines h = [ '#Unfolded spectrum', '#', '#Energy EnergyError Energy*Flux Energy*FluxError ModelValues' ] f.write('\n'.join(h) + '\n') for i in range(len(e)): data = [e[i], e_err[i], ef[i], ef_err[i], model[i]] line = [str(j) for j in data] f.write(' '.join(line) + '\n') # Create a file to input into integflux integflux = path_obsid + 'integflux.in' with open(integflux, 'w') as f: #intgr_low, intgr_high, soft_low, soft_high, hard_low, hard_high line = [ 'eufspec.dat', str(low_e), str(high_e), str(soft[0]), str(soft[-1]), str(hard[0]), str(hard[-1]) ] line = [str(e) for e in line] f.write(' '.join(line) + '\n') # Remove previous versions of the output if os.path.isfile(path_obsid + 'hardint.out'): os.remove(path_obsid + 'hardint.out') # Run fortran script to create calculate hardness-intensity values # Will output a file with the columns (with flux in Photons*ergs/cm^2/s) # flux flux_err ratio ratio_error os.chdir(path_obsid) shell.execute(paths.subscripts + 'integflux.xf') os.chdir(paths.data) # Get ouput of the fortran script txt = genfromtxt(path_obsid + 'hardint.out') flux = float(txt[0]) flux_err = float(txt[1]) ratio = float(txt[2]) ratio_err = float(txt[3]) d['spectra'].append(sp) d['flux_i3t16_s6p4t9p7_h9p7t16'].append(flux) d['flux_err_i3t16_s6p4t9p7_h9p7t16'].append(flux_err) d['hardness_i3t16_s6p4t9p7_h9p7t16'].append(ratio) d['hardness_err_i3t16_s6p4t9p7_h9p7t16'].append(ratio_err) # Clear xspec spectrum xspec.AllData.clear() # Update database and save df = pd.DataFrame(d) cols = [ 'flux_i3t16_s6p4t9p7_h9p7t16', 'flux_err_i3t16_s6p4t9p7_h9p7t16', 'hardness_i3t16_s6p4t9p7_h9p7t16', 'hardness_err_i3t16_s6p4t9p7_h9p7t16' ] db = database.merge(db, df, cols) print 'Number of unique elements in database' print '=======================' print db.apply(pd.Series.nunique) print '=======================' print 'Pipeline completed' database.save(db) logs.stop_logging()
def fit_ecsrcbin10( obsid, WorkDir="/Users/corcoran/Dropbox/Eta_Car/swift/quicklook/work", emin=2.0, emax=10.0, rmfdir='/caldb/data/swift/xrt/cpf/rmf', chatter=0): import xspec import glob import pyfits import numpy as np from astropy.time import Time xspec.AllData.clear() xspec.Xset.chatter = chatter xspec.FitManager.query = "yes" xspec.Fit.query = "yes" xspec.Fit.nIterations = 100 xspecdir = WorkDir + "/" + obsid.strip() + "/xspec" cwd = os.getcwd() print "\n" os.chdir(xspecdir) src = xspec.Spectrum("ec_srcbin10.pha") try: hdu = pyfits.open("ec_srcbin10.arf") except: print "ARF ec_srcbin10.arf not found; Returning" return arfhd = hdu[1].header try: respfile = arfhd['RESPFILE'] except: print "RESPFILE keyword in ec_srcbin10.arf not found; Returning" return try: rmffile = glob.glob(rmfdir + '/' + respfile)[0] except: print "Response file %s does not exist; Returning" % (rmfdir + '/' + respfile) return src.response = rmffile src.response.arf = "ec_srcbin10.arf" src.background = "ec_bkg.pha" src.ignore("0.0-1.0 7.9-**") hdulist = pyfits.open("ec_srcbin10.pha") prihdr = hdulist[0].header """ dateobs=prihdr['DATE-OBS'] dateend=prihdr['DATE-END'] t=Time(dateobs,scale='utc', format='isot') te=Time(dateend,scale='utc',format='isot') """ mjds = prihdr['MJD-OBS'] mjde = prihdr['MJD-OBS'] + (prihdr['TSTOP'] - prihdr['TSTART']) / 86400.0 t = Time(mjds, scale='utc', format='mjd') dateobs = t.iso.replace(' ', 'T') te = Time(mjde, scale='utc', format='mjd') tmid = (te.jd - t.jd) / 2.0 + t.jd xspec.AllData.ignore("bad") """ first fit without the cflux component """ mostring = "wabs*apec + wabs*(apec + gaussian)" m = xspec.Model(mostring) m.wabs.nH = [1.1, 0.1, 0, 0, 5, 5] m.apec.kT = [1.0, 0.1, 0.1, 0.1, 2, 2] m.apec.norm = [0.1, 0.1, 0.0, 0.0, 2, 2] m.wabs_3.nH = [10, 0.1, 0, 0, 100, 100] m.apec_4.kT = [4.5, -0.1, 2.0, 2.0, 6.0, 6.0] m.apec_4.norm = [0.1, 0.1, 0.0, 0.0, 2, 2] m.apec_4.Abundanc = 0.4 m.gaussian.LineE = [6.4, -0.1] m.gaussian.Sigma = [0.01, -0.01] m.gaussian.norm = [1e-4, 1e-5, 0, 0, 0.1, 0.1] m.show() xspec.Fit.perform() m.show() xspec.Plot.xAxis = "KeV" xspec.Plot.device = "/xw" xspec.Plot("ldata") xspec.AllModels.calcFlux(str(emin) + " " + str(emax)) oflux = src.flux[0] """ Create XCM output """ xcm = ['data ' + src.fileName] xcm.append('back ' + src.background.fileName) xcm.append('resp ' + src.response.rmf) xcm.append('arf ' + src.response.arf) xcm.append('ignore ' + src.ignoredString()) xcm.append('model ' + m.expression) for i in np.arange(m.nParameters) + 1: p = m(i).values parvals = str(p[0]) for k in np.arange(len(p) - 1) + 1: parvals = parvals + ', ' + str(p[k]) xcm.append(parvals) xcm.append('statistic ' + xspec.Fit.statMethod) nh = m.wabs.nH.values[0] kt = m.apec.kT.values[0] norm = m.apec.norm.values[0] nh3 = m.wabs_3.nH.values[0] xspec.Fit.error("2.706 6") # param 6 is nh3 p6 = xspec.AllModels(1)(6) nhmin = p6.error[0] nhmax = p6.error[1] kt4 = m.apec_4.kT.values[0] norm4 = m.apec_4.norm.values[0] gnorm = m.gaussian.norm.values[0] """ now add cflux component, set the values to the previous best fit, freeze apec norms, and refit to get the cflux and its errors """ mostring2 = "wabs*apec + cflux*wabs*(apec + gaussian)" m2 = xspec.Model(mostring2) m2.wabs.nH = [nh, -0.1] m2.apec.kT = [kt, -0.1] m2.apec.norm = [norm, -0.1] m2.wabs_4.nH = [nh3, -0.1] m2.apec_5.kT = [kt4, -0.1] m2.apec_5.norm = [norm4, -0.0001] m2.apec_5.Abundanc = 0.4 m2.gaussian.LineE = [6.4, -0.1] m2.gaussian.Sigma = [0.01, -0.01] m2.gaussian.norm = [gnorm, -0.0001] m2.cflux.Emin = emin m2.cflux.Emax = emax xspec.Fit.perform() m2.show() cf = m2.cflux.lg10Flux.values[0] print "%5.1f - %5.1f keV flux from cflux = %10.4e" % (emin, emax, 10**cf) xspec.Fit.error("2.706 8") # param 8 is cflux p8 = xspec.AllModels(1)(8) cfmin = p8.error[0] cfmax = p8.error[1] duration = te.jd - t.jd nhpluserr = nhmax - nh3 nhminerr = nh3 - nhmin output = { 'obsid': obsid, 't_start': t.jd, 't_end': te.jd, 't_mid': tmid, 'duration': duration, 'exposure': src.exposure, 'flux': oflux, 'fluxplus': 10**cfmax - 10**cf, 'fluxmin': 10**cf - 10**cfmin, 'dateobs': dateobs, 'nh': nh3, 'nhplus': nhpluserr, 'nhmin': nhminerr, 'emin': emin, 'emax': emax } """ Write xcm file; warn user if it exists and give option to overwrite """ filename = xspecdir + '/ec_srcbin10.xcm' if os.path.isfile(filename): print "File %s exists" % filename ans = raw_input('Overwrite [y]/n? ') if ans.strip().lower() == 'n': print "File %s not overwritten; Returning" % filename return output, xcm print "Writing file %s" % filename f = open(filename, 'w') for i in xcm: f.write(i + "\n") f.close() #print "Changing directory back to %s" % cwd print "\n" os.chdir(cwd) return output, xcm
def deneme(self): xspec.AllData.clear() xspec.Fit.statMethod = str(self.statistic) xspec.Fit.query = "yes" os.chdir(self.path) xspec.AllData("1:1 {} 2:2 {} 3:3 {} 4:4 {}".format( self.spectrum_files["mos1"], self.spectrum_files["mos2"], self.spectrum_files["pn"], self.spectrum_files["rass"])) self.spec_mos1 = xspec.AllData(1) self.spec_mos1.ignore(self.energy_range["mos1"]) self.spec_mos2 = xspec.AllData(2) self.spec_mos2.ignore(self.energy_range["mos2"]) xspec.AllModels += "apec+gau+gau" self.m1 = xspec.AllModels(1) self.m2 = xspec.AllModels(2) self.m3 = xspec.AllModels(3) self.m4 = xspec.AllModels(4) m1_apec1 = Apec(1, 3, 0.3, 0.233) m1_gau1 = Gaussian(1, 1.48) m1_gau2 = Gaussian(1, 1.74) m2_apec1 = Apec(1, 3, 0.3, 0.233) m2_gau1 = Gaussian(1, 1.48) m2_gau2 = Gaussian(1, 1.74) m3_apec1 = Apec(1, 3, 0.3, 0.233) m3_gau1 = Gaussian(1, 1.48) m3_gau2 = Gaussian(1, 1.74) m4_apec1 = Apec(1, 3, 0.3, 0.233) m4_gau1 = Gaussian(1, 1.48) m4_gau2 = Gaussian(1, 1.74) m1_comp1 = self.m1.apec m1_comp2 = self.m1.gaussian m1_comp3 = self.m1.gaussian_3 m2_comp1 = self.m2.apec m2_comp2 = self.m2.gaussian m2_comp3 = self.m2.gaussian_3 m3_comp1 = self.m3.apec m3_comp2 = self.m3.gaussian m3_comp3 = self.m3.gaussian_3 m4_comp1 = self.m4.apec m4_comp2 = self.m4.gaussian m4_comp3 = self.m4.gaussian_3 Apec.set_params(m1_comp1, m1_apec1) Gaussian.set_params(m1_comp2, m1_gau1) Gaussian.set_params(m1_comp3, m1_gau2) Apec.set_params(m2_comp1, m2_apec1) Gaussian.set_params(m2_comp2, m2_gau1) Gaussian.set_params(m2_comp3, m2_gau2) Apec.set_params(m3_comp1, m3_apec1) Gaussian.set_params(m3_comp2, m3_gau1) Gaussian.set_params(m3_comp3, m3_gau2) Apec.set_params(m4_comp1, m4_apec1) Gaussian.set_params(m4_comp2, m4_gau1) Gaussian.set_params(m4_comp3, m4_gau2) MyModel.freeze_parameter(m1_comp1.norm) MyModel.set_norm_zero(m4_comp1) xspec.AllModels.show()
def fit(data, reference_instrument, model_setter, emin_values, fn_prefix="", systematic_fraction=0): importlib.reload(xspec) fit_by_lt = {} fn_by_lt={} xspec.AllModels.systematic=systematic_fraction for c_emin in emin_values: xspec.AllData.clear() xspec.AllModels.clear() isgri, ref_ind = model_setter(data, reference_instrument, c_emin) max_chi=np.ceil(xspec.Fit.statistic / xspec.Fit.dof) m1=xspec.AllModels(1) if ref_ind is not None: n_spec = 2 if isinstance(ref_ind, list): n_spec = len(ref_ind) + 1 xspec.Fit.error("1.0 max %.1f 1-%d"%(max_chi, n_spec*m1.nParameters)) ref = ref_ind[0] else: xspec.Fit.error("1.0 max %.1f 1-%d" % (max_chi,m1.nParameters)) models={} lt_key='%.10lg'%c_emin fit_by_lt[lt_key]=dict( emin=c_emin, chi2_red=xspec.Fit.statistic/xspec.Fit.dof, chi2=xspec.Fit.statistic, ndof=xspec.Fit.dof, models=models, ) for m, ss in (isgri, 'isgri'), (ref, 'ref'): if m is None: continue #initialize dictionaries models[ss]={} #models[ss]['flux']={} #fills dictionaries for i in range(1,m.nParameters+1): if (not m(i).frozen) and (not bool(m(i).link)): #use the name plus position because there could be parameters with same name from multiple #model components (e.g., several gaussians) print(m(i).name, "%.2f"%(m(i).values[0]), m(i).frozen,bool(m(i).link) ) models[ss][m(i).name+"_%02d"%(i)]=[ m(i).values[0], m(i).error[0], m(i).error[1] ] # for flux_e1, flux_e2 in [(30,80), (80,200)]: # xspec.AllModels.calcFlux("{} {} err".format(flux_e1, flux_e2)) # #print ( xspec.AllData(1).flux) # models['isgri']['flux'][(flux_e1, flux_e2)] = xspec.AllData(1).flux # models['ref']['flux'][(flux_e1, flux_e2)] = xspec.AllData(2).flux xcmfile="saved"+fn_prefix+"_"+reference_instrument+".xcm" if os.path.exists(xcmfile): os.remove(xcmfile) xspec.XspecSettings.save(xspec.XspecSettings, xcmfile, info='a') xspec.Plot.device="/png" #xspec.Plot.addCommand("setplot en") xspec.Plot.xAxis="keV" xspec.Plot("ldata del") xspec.Plot.device="/png" fn="fit_lt%.5lg.png"%c_emin fn_by_lt[lt_key] = fn shutil.move("pgplot.png_2", fn) _=display(Image(filename=fn,format="png")) return fit_by_lt, fn_by_lt
) spectrum1 = xspec.AllData(1) spectrum1.background = f"bgspecRGS1_gti{i}.fits" spectrum1.response = f"../{pairs_respli[0][0]}" spectrum2 = xspec.AllData(2) spectrum2.background = f"bgspecRGS2_gti{i}.fits" spectrum2.response = f"../{pairs_respli[0][1]}" xspec.AllData.ignore("bad") xspec.AllData.ignore('**-0.331 2.001-**') for model in model_list: m1 = xspec.Model(model) m2 = xspec.AllModels( 2) #Retrieve the model object assigned to data group 2 #Freeze constant of RGS1 to 1 to account for calibration m1.constant.factor = 1 m1.constant.factor.frozen = True #Freeze redshift for both RGS1 and RGS2 if m1.expression == 'constant*TBabs*zpowerlw': m1.zpowerlw.Redshift = target_redshift m1.zpowerlw.Redshift.frozen = True m2.zpowerlw.Redshift = target_redshift m2.zpowerlw.Redshift.frozen = True if m1.expression == 'constant*TBabs*zlogpar': m1.zlogpar.Redshift = target_redshift