Example #1
0
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)
Example #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")
Example #4
0
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]
Example #5
0
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
Example #6
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")
Example #7
0
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
Example #8
0
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)
Example #9
0
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
Example #10
0
        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.
Example #11
0
    '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)
Example #12
0
 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]
Example #13
0
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()
Example #14
0
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
Example #15
0
    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()
Example #16
0
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