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 annulus_fit(output, error=False, error_rerun=False, free_center_elements=None, free_all_elements=None, four_ann=False, **kwargs): """ Fit radial annuli simultaneously Arguments: output = output products file stem error = run error commands? error_rerun = run error commands 2nd time? four_ann = fit only 4 instead of 5 annuli? free_all_elements = (case-sensitive) elements to free in all annuli. Element names much match XSPEC parameter names. Default: Si, S free free_center_elements = (case-sensitive) additional elements to free in central circle (0-100 arcsec) Element names much match XSPEC parameter names. kwargs - passed to g309_models.load_data_and_models (suffix, mosmerge, marfrmf) Output: n/a loads of stuff dumped to output* XSPEC session left in fitted state """ if free_center_elements is None: free_center_elements = [] if free_all_elements is None: free_all_elements = ['Si', 'S'] regs = ["ann_000_100", "ann_100_200", "ann_200_300", "ann_300_400", "ann_400_500"] if four_ann: regs = ["ann_000_100", "ann_100_200", "ann_200_300", "ann_300_400"] out = g309.load_data_and_models(regs, snr_model='vnei', **kwargs) for reg in regs: set_energy_range(out[reg]) xs.AllData.ignore("bad") # Link nH across annuli # Each region has n spectra (n exposures) # [0] gets 1st of n ExtractedSpectra objects # .models['...'] gets corresponding 1st of n XSPEC models rings = [out[reg][0].models['snr'] for reg in regs] for ring in rings[1:]: # Exclude center ring.tbnew_gas.nH.link = xs_utils.link_name(rings[0], rings[0].tbnew_gas.nH) # Start fit process xs.Fit.renorm() xs.Fit.perform() for ring in rings: ring.tbnew_gas.nH.frozen = False ring.vnei.kT.frozen = False ring.vnei.Tau.frozen = False xs.Fit.perform() for ring in rings: for elem in free_all_elements: comp = ring.vnei.__getattribute__(elem) comp.frozen = False for elem in free_center_elements: comp = rings[0].vnei.__getattribute__(elem) comp.frozen = False xs.Fit.perform() if xs.Plot.device == "/xs": xs.Plot("ldata delchi") # Error runs if error: xs.Xset.openLog(output + "_error.log") print "First error run:", datetime.now() for reg, ring in zip(regs, rings): print "Running", reg, "errors:", datetime.now() xs.Fit.error(error_str_all_free(ring)) print reg, "errors complete:", datetime.now() # Will not appear in error log if error_rerun: print "Second error run:", datetime.now() for reg, ring in zip(regs, rings): print "Running", reg, "errors:", datetime.now() xs.Fit.error(error_str_all_free(ring)) print reg, "errors complete:", datetime.now() # Will not appear in error log xs.Xset.closeLog() print "Error runs complete:", datetime.now() # Output products products(output) for ring in rings: model_log = output + "_{}.txt".format(ring.name) print_model(ring, model_log)
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], **kwargs) set_energy_range(out[region]) xs.AllData.ignore("bad") 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))) 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 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")