Esempio n. 1
0
def fit_draws(draws, parname, nbins=50, params=None, plot=True, verbose=True):
    """Fit a gaussian to the histogram of the given parameter.

    Before using this routine you should use get_parameter_info()
    to extract the parameter info for use by get_draws(). This is
    because using this routine will invalidate the internal
    data structures that get_draws() uses when its params argument
    is None.

    If params is not None then it should be the return value of
    get_parameter_info().

    If plot is True then a plot of the histogram and fit will be
    made.

    If verbose is True then a quick comparison of the fit
    results will be displayed.
    """

    if parname not in draws["parnames"]:
        raise RuntimeError, "Unknown parameter '%s'" % parname

    # Exclude any point with an iteration number of 0
    #
    idx = draws["iteration"] > 0
    parvals = draws[parname][idx]

    (hy, hx) = np.histogram(parvals, bins=nbins, new=True)
    xlo = hx[:-1]
    xhi = hx[1:]

    id = parname
    ui.load_arrays(id, 0.5 * (xlo + xhi), hy)

    # We can guess the amplitude and position fairly reliably;
    # for the FWHM we just use the inter-quartile range of the
    # X axis.
    #
    ui.set_source(id, ui.gauss1d.gparam)
    gparam.pos = xlo[xlo.size // 2]
    gparam.ampl = hy[xlo.size // 2]
    gparam.fwhm = xlo[xlo.size * 3 // 4] - xlo[xlo.size // 4]

    # Get the best-fit value if available
    if params != None:
        p0 = dict(zip(params["parnames"], params["parvals"]))[parname]

    logger = logging.getLogger("sherpa")
    olvl = logger.level
    logger.setLevel(40)

    ostat = ui.get_stat_name()
    ui.set_stat("leastsq")
    ui.fit(id)
    ui.set_stat(ostat)

    logger.setLevel(olvl)

    if plot:
        # We manually create the plot since we want to use a histogram for the
        # data and the Sherpa plots use curves.
        #
        ##dplot = ui.get_data_plot(id)
        mplot = ui.get_model_plot(id)

        chips.lock()
        try:
            chips.open_undo_buffer()
            chips.erase()
            chips.add_histogram(xlo, xhi, hy)
            ##chips.add_histogram(xlo, xhi, mplot.y, ["line.color", "red", "line.style", "dot"])
            chips.add_curve(mplot.x, mplot.y, ["line.color", "red", "symbol.style", "none"])

            if params != None:
                chips.add_vline(p0, ["line.color", "green", "line.style", "longdash"])

            chips.set_plot_xlabel(parname)
        except:
            chips.discard_undo_buffer()
            chips.unlock()
            raise
        chips.close_undo_buffer()
        chips.unlock()

    sigma = gparam.fwhm.val / (2.0 * np.sqrt(2 * np.log(2)))

    if verbose:
        print ""
        print "Fit to histogram of draws for parameter %s gives" % parname
        print "     mean     = %g" % gparam.pos.val
        print "     sigma    = %g" % sigma
        print ""

        if params != None:
            idx = params["parnames"] == parname
            print "     best fit = %g" % p0
            print "  covar sigma = %g" % params["parmaxes"][idx][0]
            print ""

    return (gparam.pos.val, sigma, gparam.ampl.val)
Esempio n. 2
0
def mht(parnames, mu, sigma, niter=1000, id=None,
        file=None, verbose=True, normalize=True,
        draw=draw_t, accept=accept_tcash, **kwargs):
    """Metropolis-Hastings.

    The default distribution is the t distribution, and the statistic is
    assumed to be the Cash statistic.

    The kwargs are passed through to the draw and accept routines.

    The draw routine is used to create a new proposal.
    The accept routine is used to determine whether to accept the proposal.

    If verbose is True then the iteration results are printed to STDOUT
    after each iteration. If file is not None then the iteration results
    are printed to the given file wach iteration. If normalize is True
    then the displayed results (whether to STDOUT or file) are relative
    to the best-fit values rather than absolute ones (so the values for
    the xpos parameter are written out as xpos-xpos_0 where xpos_0 is
    the value from the input mu argument). This also holds for the
    statistic value (so the results are statistic-statistic_0). The
    reason for normalize is to try and avoid lose of information
    without having to display numbers to 15 decimal places.
    """

    # Should we just change to cash here instead of throwing an error?
    #
    if ui.get_stat_name() != "cash":
        raise RuntimeError, "Statistic must be cash, not %s" % ui.get_stat_name()

    if id == None:
        idval = ui.get_default_id()
    else:
        idval = id

    # Output storage
    #
    nelem = niter + 1
    npars = mu.size
    if npars != len(parnames):
        raise RuntimeError, "mu.size = %d  len(parnames) = %d!" % (npars, len(parnames))

    params = np.zeros((nelem,npars))
    stats  = np.zeros(nelem)
    alphas = np.zeros(nelem)

    # Using a bool is technically nicer, but stick with an int8 here for easier processing
    # of the output.
    #
    ##acceptflag = np.zeros(nelem, dtype=np.bool)
    acceptflag = np.zeros(nelem, dtype=np.int8)

    params[0] = mu.copy()
    current = mu.copy()
    alphas[0] = 0

    _set_par_vals(parnames, current)
    stats[0] = ui.calc_stat(id=idval)

    if normalize:
        outstr = "# iteration accept d_statistic %s" % " d_".join(parnames)
    else:
        outstr = "# iteration accept statistic %s" % " ".join(parnames)
    if verbose:
        print outstr
    if file != None:
	fout = open(file, "w")
    	fout.write(outstr)
        fout.write("\n")

    def draw_to_string(idx):
        "Return the given draw as a string for display/output"
        if normalize:
            outstr = "%-6d %1d %g %s" % (idx, acceptflag[idx], stats[idx]-stats[0], " ".join(["%g" % (v-v0) for (v,v0) in zip(params[idx],params[0])]))
        else:
            outstr = "%-6d %1d %g %s" % (idx, acceptflag[idx], stats[idx], alphas[idx], " ".join(["%g" % v for v in params[idx]]))
        return outstr

    # Iterations
    # - no burn in at present
    # - the 0th element of the params array is the input value
    # - we loop until all parameters are within the allowable
    #   range; should there be some check to ensure we are not
    #   rejecting a huge number of proposals, which would indicate
    #   that the limits need increasing or very low s/n data?
    #
    for i in range(1,nelem,1):

        current = params[i-1]

        # Create a proposal and set the parameter values. If any lie
        # outside the allowed range then catch this (ParameterError)
        # and create a new proposal.
        #
        while True:
            try:
                proposal = draw(mu, current, sigma, **kwargs)
                _set_par_vals(parnames, proposal)
                break
            except ParameterErr:
                pass

        # Do we accept this proposal?
        #
        stat_temp = ui.calc_stat(id=idval)
        alphas[i] = np.exp( -0.5*stat_temp + dmvt(current, mu, sigma, 4) + 0.5*stats[i-1] - dmvt(proposal, mu, sigma, 4) )

        if accept(current, stats[i-1], proposal, stat_temp,
                  mu, sigma, **kwargs):
            params[i] = proposal.copy()
            stats[i]  = stat_temp
            acceptflag[i] = 1
        else:
            params[i] = params[i-1]
            stats[i]  = stats[i-1]
            acceptflag[i] = 0

        outstr = draw_to_string(i)
    if verbose:
        print outstr
    if file != None:
            fout.write(outstr)
            fout.write("\n")

    if file != None:
	fout.close()
        print "Created: %s" % file

    # Return a dictionary containing the draws
    #
    out = { "parnames": parnames, "statistic": stats, "accept": acceptflag, "alphas": alphas, "iteration": np.arange(0,nelem,1) }
    for (idx,name) in zip(range(npars),parnames):
    	if out.has_key(name):
            raise RuntimeError, "Unexpected name clash: parameter '%s'" % name
        out[name] = params[:,idx]
    return out
Esempio n. 3
0
def fit_draws(draws, parname, nbins=50, params=None, plot=True, verbose=True):
    """Fit a gaussian to the histogram of the given parameter.

    Before using this routine you should use get_parameter_info()
    to extract the parameter info for use by get_draws(). This is
    because using this routine will invalidate the internal
    data structures that get_draws() uses when its params argument
    is None.

    If params is not None then it should be the return value of
    get_parameter_info().

    If plot is True then a plot of the histogram and fit will be
    made.

    If verbose is True then a quick comparison of the fit
    results will be displayed.
    """

    if parname not in draws["parnames"]:
        raise RuntimeError, "Unknown parameter '%s'" % parname

    # Exclude any point with an iteration number of 0
    #
    idx = draws["iteration"] > 0
    parvals = draws[parname][idx]

    (hy, hx) = np.histogram(parvals, bins=nbins, new=True)
    xlo = hx[:-1]
    xhi = hx[1:]

    id = parname
    ui.load_arrays(id, 0.5 * (xlo + xhi), hy)

    # We can guess the amplitude and position fairly reliably;
    # for the FWHM we just use the inter-quartile range of the
    # X axis.
    #
    ui.set_source(id, ui.gauss1d.gparam)
    gparam.pos = xlo[xlo.size // 2]
    gparam.ampl = hy[xlo.size // 2]
    gparam.fwhm = xlo[xlo.size * 3 // 4] - xlo[xlo.size // 4]

    # Get the best-fit value if available
    if params != None:
        p0 = dict(zip(params["parnames"], params["parvals"]))[parname]

    logger = logging.getLogger("sherpa")
    olvl = logger.level
    logger.setLevel(40)

    ostat = ui.get_stat_name()
    ui.set_stat("leastsq")
    ui.fit(id)
    ui.set_stat(ostat)

    logger.setLevel(olvl)

    if plot:
        # We manually create the plot since we want to use a histogram for the
        # data and the Sherpa plots use curves.
        #
        ##dplot = ui.get_data_plot(id)
        mplot = ui.get_model_plot(id)

        chips.lock()
        try:
            chips.open_undo_buffer()
            chips.erase()
            chips.add_histogram(xlo, xhi, hy)
            ##chips.add_histogram(xlo, xhi, mplot.y, ["line.color", "red", "line.style", "dot"])
            chips.add_curve(mplot.x, mplot.y,
                            ["line.color", "red", "symbol.style", "none"])

            if params != None:
                chips.add_vline(
                    p0, ["line.color", "green", "line.style", "longdash"])

            chips.set_plot_xlabel(parname)
        except:
            chips.discard_undo_buffer()
            chips.unlock()
            raise
        chips.close_undo_buffer()
        chips.unlock()

    sigma = gparam.fwhm.val / (2.0 * np.sqrt(2 * np.log(2)))

    if verbose:
        print ""
        print "Fit to histogram of draws for parameter %s gives" % parname
        print "     mean     = %g" % gparam.pos.val
        print "     sigma    = %g" % sigma
        print ""

        if params != None:
            idx = params["parnames"] == parname
            print "     best fit = %g" % p0
            print "  covar sigma = %g" % params["parmaxes"][idx][0]
            print ""

    return (gparam.pos.val, sigma, gparam.ampl.val)