示例#1
0
def joebvpfit(wave,flux,sig,linepars,flags):

	xtol=1e-11
	gtol=1e-11
	# Only feed to the fitter the parameters that go into the model
	partofit=linepars[:5]
	parinfo=prepparinfo(partofit,flags)
	# Save the velocity windows to add back to the parameter array
	vlim1=linepars[5] ; vlim2=linepars[6]
	# Get atomic data
	lam,fosc,gam=atomicdata.setatomicdata(linepars[0])
	cfg.lams=lam ; cfg.fosc=fosc ; cfg.gam=gam
	# Set fit regions
	cfg.fitidx = fitpix(wave, linepars)
	# Prep parameters for fitter
	partofit=unfoldpars(partofit)
	modelvars={'x':wave,'y':flux,'err':sig}
	# Do the fit and translate the parameters back into the received format
	m=nmpfit.mpfit(voigterrfunc,partofit,functkw=modelvars,parinfo=parinfo,nprint=1,quiet=0,fastnorm=1,ftol=1e-10,xtol=xtol,gtol=gtol)
	if m.status <= 0: print('Fitting error:',m.errmsg)
	fitpars=foldpars(m.params)
	fiterrors = foldpars(m.perror)
	# Add velocity windows back to parameter array
	fitpars.append(vlim1) ; fitpars.append(vlim2)


	print('\nFit results: \n')
	for i in range(len(fitpars[0])):
		print(jbg.tabdelimrow([round(fitpars[0][i],2),jbg.decimalplaces(fitpars[3][i],5),jbg.roundto(fitpars[1][i],5),jbg.roundto(fitpars[2][i],5),jbg.roundto(fitpars[4][i],5)])[:-2])
		print(jbg.tabdelimrow([' ',' ',' ',round(fiterrors[1][i],3),round(fiterrors[2][i],3),round(fiterrors[4][i],3)]))

	return fitpars,fiterrors
示例#2
0
def joebvpfit(wave,flux,sig,linepars,flags):

	xtol=1e-11
	gtol=1e-11
	# Only feed to the fitter the parameters that go into the model
	partofit=linepars[:5]
	parinfo=prepparinfo(partofit,flags)
	# Save the velocity windows to add back to the parameter array
	vlim1=linepars[5] ; vlim2=linepars[6]
	# Get atomic data
	lam,fosc,gam=atomicdata.setatomicdata(linepars[0])
	cfg.lams=lam ; cfg.fosc=fosc ; cfg.gam=gam
	# Set fit regions
	cfg.fitidx = fitpix(wave, linepars)
	# Prep parameters for fitter
	partofit=unfoldpars(partofit)
	modelvars={'x':wave,'y':flux,'err':sig}
	# Do the fit and translate the parameters back into the received format
	m=nmpfit.mpfit(voigterrfunc,partofit,functkw=modelvars,parinfo=parinfo,nprint=1,quiet=0,fastnorm=1,ftol=1e-10,xtol=xtol,gtol=gtol)
	if m.status <= 0: print('Fitting error:',m.errmsg)
	fitpars=foldpars(m.params)
	fiterrors = foldpars(m.perror)
	# Add velocity windows back to parameter array
	fitpars.append(vlim1) ; fitpars.append(vlim2)


	print('\nFit results: \n')
	for i in range(len(fitpars[0])):
		print(jbg.tabdelimrow([round(fitpars[0][i],2),jbg.decimalplaces(fitpars[3][i],5),jbg.roundto(fitpars[1][i],5),jbg.roundto(fitpars[2][i],5),jbg.roundto(fitpars[4][i],5)])[:-2])
		print(jbg.tabdelimrow([' ',' ',' ',round(fiterrors[1][i],3),round(fiterrors[2][i],3),round(fiterrors[4][i],3)]))

	return fitpars,fiterrors
示例#3
0
def stevebvpfit(wave, flux, sig, flags, linepars=None, xall=None):

    if linepars is None:
        raise ValueError("Must pass parameters in linepars.")
        return

    # Only feed to the fitter the parameters that go into the model
    partofit = linepars[:5]

    parinfo = prepparinfo(linepars, flags)

    npar = len(parinfo)

    ## Be sure that PARINFO is of the right type
    if parinfo is not None:
        if type(parinfo) != list:
            raise ValueError("PARINFO must be a list of dictionaries.")
            return

        else:
            if type(parinfo[0]) != dict:
                raise ValueError("PARINFO must be a list of dictionaries.")
                return

    ## If the parameters were not specified at the command line, then
    ## extract them from PARINFO

    if xall is None:

        xall = parameterInformationFunction(parinfo, "value")
        if xall is None:
            raise ValueError(
                'either xall or PARINFO(*)["value"] must be supplied.')
    xall = np.ravel(np.array(xall).T)

    # function that deals with tied and fixed parameters and creates
    # indices list to go from non-redundant to redundant array:

    indices_and_friends = various_indices(parinfo)

    pfixed, ptied, ifree, indices = indices_and_friends

    indices = indices.astype(np.int)
    ifree = np.squeeze(ifree)
    ## Compose only VARYING parameters
    x = np.squeeze(xall)[np.squeeze(
        pfixed == 0)]  ## x is the set of free parameters

    ## LIMITED parameters ?
    limited = parameterInformationFunction(parinfo,
                                           "limited",
                                           default=[0, 0],
                                           n=npar)
    limits = parameterInformationFunction(parinfo,
                                          "limits",
                                          default=[0.0, 0.0],
                                          n=npar)

    if (limited is not None) and (limits is not None):

        ## Error checking on limits in parinfo
        wh = np.nonzero((limited[:, 0] & (xall < limits[:, 0]))
                        | (limited[:, 1] & (xall > limits[:, 1])))

        if len(wh[0]) > 0:
            raise ValueError("parameters are not within PARINFO limits")
            return

        wh = np.nonzero((limited[:, 0] & limited[:, 1])
                        & (limits[:, 0] >= limits[:, 1])
                        & (pfixed == 0))
        if len(wh[0]) > 0:
            raise ValueError("PARINFO parameter limits are not consistent")
            return
        freeanduntied = np.where(np.squeeze(pfixed == 0))[0]
        ## Transfer structure values to local variables
        qulim = np.take(limited[:, 1], freeanduntied)
        ulim = np.take(limits[:, 1], freeanduntied)
        qllim = np.take(limited[:, 0], freeanduntied)
        llim = np.take(limits[:, 0], freeanduntied)

    # Save the velocity windows to add back to the parameter array
    vlim1 = linepars[5]
    vlim2 = linepars[6]
    # Get atomic data
    lam, fosc, gam = atomicdata.setatomicdata(linepars[0])
    cfg.lams = lam
    cfg.fosc = fosc
    cfg.gam = gam
    # Set fit regions
    cfg.fitidx = fitpix(wave, linepars)

    # Prep parameters for fitter

    partofit = unfoldpars(partofit)

    modelvars = {"l": wave, "y": flux, "err": sig}

    bnds = (
        np.squeeze(np.where(qllim == 1, llim, -np.inf)),
        np.squeeze(np.where(qulim == 1, ulim, np.inf)),
    )

    arg = [
        xall, ifree, indices, modelvars["l"], modelvars["y"], modelvars["err"]
    ]

    # here is where fitting happens:
    cache = {"x": np.nan, "resid": np.nan, "jac": np.nan}

    def cached_resid(x, cache):
        if np.all(x == cache["x"]):
            return cache["resid"]
        cache["x"] = x.copy()
        resid, jac = stevevoigterrfunc_w_jac(x, *arg)
        cache["resid"] = resid
        cache["jac"] = jac.T
        return resid

    def cached_jac(x, cache):
        if np.all(x == cache["x"]):
            return cache["jac"]
        cache["x"] = x.copy()
        resid, jac = stevevoigterrfunc_w_jac(x, *arg)
        cache["resid"] = resid
        cache["jac"] = jac.T
        return jac.T

    m = least_squares(
        cached_resid,
        x,
        bounds=bnds,
        args=(cache, ),
        kwargs={},
        verbose=True,
        jac=cached_jac,
    )

    if m.status < 0:
        print("Fitting error:", m.message)
        done = True
    elif m.status == 0:
        done = False
    else:
        done = True

    xall_fitted = xall.copy()

    xall_fitted[ifree] = m["x"][indices]

    fitpars = foldpars(xall_fitted)

    # This is a super-hacky fix to the issue of parameters having Jacobians of 0.
    # It could obscure other problems and so it would make sense to replace it
    # at some point.
    badvarmask = np.all(np.isclose(m.jac, 1e-10), axis=0)
    if np.any(badvarmask):
        try:
            (bad_var_ind, ) = np.where(badvarmask)
            # Replacing bad columns with value near 0.
            m.jac[:, bad_var_ind] = 1e-5
            # Giving rest wavelength and redshift of bad lines. Also really janky in and
            # of itself so that's fun.
            bad_var_indices_mask = np.in1d(indices, bad_var_ind)
            bad_ifree = ifree[bad_var_indices_mask]
            bad_comp_inds = np.unique(bad_ifree // 5)
            for comp in bad_comp_inds:
                bad_wav = fitpars[0][comp]
                bad_red = fitpars[3][comp]
                print("Bad component of {0:.5f} at {1:.5f}.".format(
                    np.float(bad_wav), np.float(bad_red)))
        except IndexError:
            pass

    perr = calc_perrors(m.jac, freeanduntied, numpars=xall.size)

    fitperr = foldpars(perr)

    for par in perr:
        par = np.ravel(np.array(par))

    # Adding in reduced chi-squared bit:
    rchi2 = 2 * m.cost / (len(cfg.fitidx) - len(freeanduntied))
    # Add velocity windows back to parameter array
    fitpars.append(vlim1)
    fitpars.append(vlim2)

    # prints results in terminal/notebook/whatever thing you have python running from
    print("\nFit results: \n")
    for i in range(len(fitpars[0])):
        print(
            jbg.tabdelimrow([
                round(fitpars[0][i], 2),
                jbg.decimalplaces(fitpars[3][i], 5),
                jbg.roundto(fitpars[1][i], 5),
                jbg.roundto(fitpars[2][i], 5),
                jbg.roundto(fitpars[4][i], 5),
            ])[:-2])
        print(
            jbg.tabdelimrow([
                " ",
                " ",
                " ",
                round(fitperr[1][i], 3),
                round(fitperr[2][i], 3),
                round(fitperr[4][i], 3),
            ]))
    print("\nReduced chi-squared: {0:f}".format(rchi2))
    return fitpars, fitperr, rchi2, done