Esempio n. 1
0
def augment_error_str(err_str, model, comp, par_names):
    """Append more stuff to an error string
    WARNING: model must be the same as for the original error string.

    This provides a crude mechanism to construct error strings for different
    components in a given model
    """
    assert model.name == err_str.split(':')[0]
    for p_name in par_names:
        par = comp.__getattribute__(p_name)
        # Does NOT modify string in calling scope
        err_str = err_str + ",{:d}".format(xs_utils.par_num(model, par))
    return err_str
Esempio n. 2
0
def augment_error_str(err_str, model, comp, par_names):
    """Append more stuff to an error string
    WARNING: model must be the same as for the original error string.

    This provides a crude mechanism to construct error strings for different
    components in a given model
    """
    assert model.name == err_str.split(':')[0]
    for p_name in par_names:
        par = comp.__getattribute__(p_name)
        # Does NOT modify string in calling scope
        err_str = err_str + ",{:d}".format(xs_utils.par_num(model, par))
    return err_str
Esempio n. 3
0
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")
Esempio n. 4
0
def error_str_all_free(model):
    """Construct error string for all free and unlinked parameters in an
    XSPEC model
    """
    # Alternative: we could just write 1--len(model.nParameters)
    # but this tends to generate warnings

    err_str = model.name + ":"

    for par in xs_utils.get_all_pars(model):
        if not par.frozen and par.link == '':
            err_str += ",{:d}".format(xs_utils.par_num(model, par))
    err_str = err_str.replace(":,", ":")

    return err_str
Esempio n. 5
0
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")
Esempio n. 6
0
def error_str_all_free(model):
    """Construct error string for all free and unlinked parameters in an
    XSPEC model
    """
    # Alternative: we could just write 1--len(model.nParameters)
    # but this tends to generate warnings

    err_str = model.name + ":"

    for par in xs_utils.get_all_pars(model):
        if not par.frozen and par.link == '':
            err_str += ",{:d}".format(xs_utils.par_num(model, par))
    err_str = err_str.replace(":,", ":")

    return err_str
Esempio n. 7
0
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")
Esempio n. 8
0
def error_str(model, comp, par_names):
    """Construct an error string"""
    pars = [comp.__getattribute__(par_name) for par_name in par_names]
    par_nums = ["{:d}".format(xs_utils.par_num(model, par)) for par in pars]
    err_str = model.name + ":" + ",".join(par_nums)
    return err_str
Esempio n. 9
0
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")
Esempio n. 10
0
def error_str(model, comp, par_names):
    """Construct an error string"""
    pars = [comp.__getattribute__(par_name) for par_name in par_names]
    par_nums = ["{:d}".format(xs_utils.par_num(model, par)) for par in pars]
    err_str = model.name + ":" + ",".join(par_nums)
    return err_str