def powerfit(xax, data, err=None, alphaguess=-2.0, scaleguess=1.0, quiet=True): """ Fit a power law (a line in log-space) to data as a function of x differs from 'plfit' because plfit fits a power law distribution, this code simply fits a power law """ logdata = np.log10(data) if err is None: err = np.ones(data.shape, dtype='float') def mpfitfun(data, err): def f(p, fjac=None): return [ 0, np.ravel( ((np.log10(p[0]) + np.log10(xax) * p[1]) - data) / err) ] return f mp = mpfit.mpfit(mpfitfun(logdata, err), xall=[scaleguess, alphaguess], quiet=quiet) fitp = mp.params return fitp, mp
def fit_blackbody(xdata, flux, guesses=(0,0), err=None, blackbody_function=blackbody, quiet=True, **kwargs): """ Parameters ---------- xdata : array Array of the X-values (frequency, wavelength) of the data flux : array The fluxes corresponding to the xdata values guesses : (Temperature,Scale) or (Temperature,Beta,Scale) The input guesses. 3 parameters are used for greybody fitting, two for temperature fitting. blackbody_function: function Must take x-axis (e.g. frequency), temperature, scale, and then optionally beta args quiet : bool quiet flag passed to mpfit Returns ------- mp : mpfit structure An mpfit structure. Access parameters and errors via `mp.params` and `mp.perror`. The covariance matrix is in mp.covar. Examples -------- >>> wavelength = array([20,70,160,250,350,500,850,1100]) >>> flux = modified_blackbody_wavelength(wavelength, 15, beta=1.75, logN=22, wavelength_units='microns', normalize=False, logscale=16) >>> err = 0.1 * flux >>> np.random.seed(0) >>> flux += np.random.randn(len(wavelength)) * err >>> tguess, bguess, nguess = 20.,2.,21.5 >>> mp = fit_blackbody(wavelength, flux, err=err, blackbody_function=modified_blackbody_wavelength, logscale=16, guesses=(tguess, bguess, nguess), wavelength_units='microns') >>> print mp.params [ 14.99095224 1.78620237 22.05271119] >>> # T~14.9 K, beta ~1.79, column ~10^22 """ def mpfitfun(x,y,err): if err is None: def f(p,fjac=None): return [0,(y-blackbody_function(x, *p, normalize=False, **kwargs))] else: def f(p,fjac=None): return [0,(y-blackbody_function(x, *p, normalize=False, **kwargs))/err] return f err = err if err is not None else flux*0.0 + 1.0 mp = mpfit.mpfit(mpfitfun(xdata,flux,err), guesses, quiet=quiet) return mp
def mpfitter(xdata, ydata, params=None, error=None, model=gaussian, quiet=True, **kwargs): """ Find the least-squares fit using mpfit """ errfunc = error_function_generator(xdata,ydata,error=error,model=model,mpfit=True) mp = mpfit(errfunc, params, quiet=quiet, **kwargs) return mp.params,mp.perror
def brokenpowerfit(xax, data, err=None, alphaguess1=0.0, alphaguess2=-2.0, scaleguess=1.0, breakpoint=None, quiet=True): """ Fit a broken power law (a line in log-space) to data as a function of x differs from 'plfit' because plfit fits a power law distribution, this code simply fits a power law This is a lot more intricate than the simple power law fit, since it involves fitting two power laws with different slopes Parameters: p[0] - scale p[1] - breakpoint p[2] - power 1 (xax < breakpoint) p[3] - power 2 (xax >= breakpoint) There are 5 parameters (NOT 4) returned because there are two scales that are *NOT* independent returns: scale1,scale2,breakpoint,alpha1,alpha2 """ logdata = np.log10(data) if err is None: err = np.ones(data.shape,dtype='float') def brokenpowerlaw(p): lowerhalf = (np.log10(p[0]) + np.log10(xax)*p[2]) * (xax < p[1]) # find the location at which both functions must be equal scale2loc = np.argmin(np.abs(xax - p[1])) scale2 = np.log10(xax[scale2loc])*(p[2] - p[3]) + np.log10(p[0]) upperhalf = (scale2 + np.log10(xax)*p[3]) * (xax >= p[1]) # DEBUG print "scale1: %15g scale2: %15g xaxind: %5i xaxval: %15g lower: %15g upper: %15g" % (p[0],scale2,scale2loc,np.log10(xax[scale2loc]),lowerhalf[scale2loc-1],upperhalf[scale2loc]) return lowerhalf+upperhalf def mpfitfun(data,err): def f(p,fjac=None): return [0,np.ravel((brokenpowerlaw(p)-data)/err)] return f if breakpoint is None: breakpoint = np.median(xax) parinfo = [{}, {'mpminstep':xax.min(),'mpmaxstep':xax.max(),'step':xax.min()}, {}, {}] mp = mpfit.mpfit(mpfitfun(logdata,err),xall=[scaleguess,breakpoint,alphaguess1,alphaguess2],quiet=quiet,parinfo=parinfo) fitp = mp.params scale2loc = np.argmin(np.abs(xax - fitp[1])) scale2 = 10**( np.log10(xax[scale2loc])*(fitp[2] - fitp[3]) + np.log10(fitp[0]) ) fitp = np.array( [fitp[0],scale2] + fitp[1:].tolist() ) return fitp,mp
def emtau(freq,flux,err=None,EMguess=1e7,Te=8500,normfac=5e-6,quiet=1): """ Returns emission measure & optical depth given radio continuum data points at frequency freq with flux density flux. return bestEM,nu(tau=1),chi^2 """ mp = mpfit(mpfitfun(freq,flux,err),xall=[EMguess,normfac],quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm bestEM = mpp[0] normfac = mpp[1] nu_tau = ( Te**1.35 / bestEM / 8.235e-2 )**(-1/2.1) return bestEM,nu_tau,normfac,chi2
def powerfit(xax,data,err=None,alphaguess=-2.0,scaleguess=1.0,quiet=True): """ Fit a power law (a line in log-space) to data as a function of x differs from 'plfit' because plfit fits a power law distribution, this code simply fits a power law """ logdata = np.log10(data) if err is None: err = np.ones(data.shape,dtype='float') def mpfitfun(data,err): def f(p,fjac=None): return [0,np.ravel(((np.log10(p[0])+np.log10(xax)*p[1])-data)/err)] return f mp = mpfit.mpfit(mpfitfun(logdata,err),xall=[scaleguess,alphaguess],quiet=quiet) fitp = mp.params return fitp,mp
def mpfitter(xdata, ydata, params=None, error=None, model=gaussian, quiet=True, **kwargs): """ Find the least-squares fit using mpfit """ errfunc = error_function_generator(xdata, ydata, error=error, model=model, mpfit=True) mp = mpfit(errfunc, params, quiet=quiet, **kwargs) return mp.params, mp.perror
def fitspec(specsegments, aperture=None, modelspec=modelspec, outpars=False, vlsrcorr=0, extinction=False, parinfo=modelpars(), quiet=1, **kwargs): """ fit a model spectrum The model is defined internal to fitspec so that parameters can be fixed based on input parameters """ specsegments = copy(specsegments) # copy.deepcopy(specsegments) parinfo = copy(parinfo) # copy.deepcopy(parinfo) kwargs = {'extinction': extinction} if extinction: parinfo = modelpars(extinction=extinction) def fitfun(x, y, err): return lambda (p): (y - modelspec(x, *p, **kwargs)) / err def mpfitfun(x, y, err): def f(p, fjac=None): return [0, (y - modelspec(x, *p, **kwargs)) / err] return f if aperture is not None: miny, maxy = aperture fitdata = asarray([ ss['data'][miny:maxy, :].sum(axis=0) for ss in specsegments ]).ravel() fiterr = asarray([ ss['err'][:] * sqrt(maxy - miny) for ss in specsegments ]).ravel() # since it is a summed aperture, add in quadrature else: fitdata = asarray([ss['data'] for ss in specsegments]).ravel() fiterr = asarray([ss['err'] for ss in specsegments]).ravel() fitwl = asarray([ss['wavelength'] for ss in specsegments]).ravel() try: parinfo = parinfo.tolist() print "Parinfo was an array. No idea why, it was never set to one. Ever." except: pass mp = mpfit(mpfitfun(fitwl, fitdata, fiterr), parinfo=parinfo, quiet=quiet) mpp = mp.params mpperr = mp.perror for i, p in enumerate(mpp): parinfo[i]['value'] = p if parinfo[i]['parname'] == 'SHIFT': print parinfo[i]['parname'], p + vlsrcorr, " +/- ", mpperr[i] else: print parinfo[i]['parname'], p, " +/- ", mpperr[i] # print "Temperature: ",mpp[0]," Shift: ",mpp[3],mpp[3]*mean(fitwl)/3e5," Width: ",mpp[2],mpp[2]*mean(fitwl)/3e5," Ortho/Para: ",mpp[4] # print "ERRORS: Temperature: ",mpperr[0]," Shift: ",mpperr[3],mpperr[3]*mean(fitwl)/3e5," Width: ",mpperr[2],mpperr[2]*mean(fitwl)/3e5," Ortho/Para: ",mpperr[4] print "Chi2: ", mp.fnorm, " Reduced Chi2: ", mp.fnorm / len( fitdata), " DOF:", len(fitdata) - len(mpp) apfitd = { 'params': mpp, 'parerr': mpperr, 'parinfo': parinfo, 'wl': fitwl, 'data': fitdata, 'model': modelspec(fitwl, *mpp), 'err': fiterr } if aperture is not None: for ss in specsegments: ss['data'] = ss['data'][miny:maxy, :].sum(axis=0) for ss in specsegments: ss['model'] = modelspec(ss['wavelength'], *mpp) if outpars: return specsegments, apfitd, parinfo else: return specsegments, apfitd
def multigaussfit(xax, data, ngauss=1, err=None, params=[1,0,1], fixed=[False,False,False], limitedmin=[False,False,True], limitedmax=[False,False,False], minpars=[0,0,0], maxpars=[0,0,0], quiet=True, shh=True, veryverbose=False): """ An improvement on onedgaussfit. Lets you fit multiple gaussians. Inputs: xax - x axis data - y axis ngauss - How many gaussians to fit? Default 1 (this could supersede onedgaussfit) err - error corresponding to data These parameters need to have length = 3*ngauss. If ngauss > 1 and length = 3, they will be replicated ngauss times, otherwise they will be reset to defaults: params - Fit parameters: [amplitude, offset, width] * ngauss If len(params) % 3 == 0, ngauss will be set to len(params) / 3 fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? Returns: Fit parameters Model Fit errors chi2 """ if len(params) != ngauss and (len(params) / 3) > ngauss: ngauss = len(params) / 3 if isinstance(params,numpy.ndarray): params=params.tolist() # make sure all various things are the right length; if they're not, fix them using the defaults for parlist in (params,fixed,limitedmin,limitedmax,minpars,maxpars): if len(parlist) != 3*ngauss: # if you leave the defaults, or enter something that can be multiplied by 3 to get to the # right number of gaussians, it will just replicate if len(parlist) == 3: parlist *= ngauss elif parlist==params: parlist[:] = [1,0,1] * ngauss elif parlist==fixed or parlist==limitedmax: parlist[:] = [False,False,False] * ngauss elif parlist==limitedmin: parlist[:] = [False,False,True] * ngauss elif parlist==minpars or parlist==maxpars: parlist[:] = [0,0,0] * ngauss def mpfitfun(x,y,err): if err is None: def f(p,fjac=None): return [0,(y-n_gaussian(pars=p)(x))] else: def f(p,fjac=None): return [0,(y-n_gaussian(pars=p)(x))/err] return f if xax == None: xax = numpy.arange(len(data)) parnames = {0:"AMPLITUDE",1:"SHIFT",2:"WIDTH"} parinfo = [ {'n':ii, 'value':params[ii], 'limits':[minpars[ii],maxpars[ii]], 'limited':[limitedmin[ii],limitedmax[ii]], 'fixed':fixed[ii], 'parname':parnames[ii%3]+str(ii%3), 'error':ii} for ii in xrange(len(params)) ] if veryverbose: print "GUESSES: " print "\n".join(["%s: %s" % (p['parname'],p['value']) for p in parinfo]) mp = mpfit(mpfitfun(xax,data,err),parinfo=parinfo,quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if not shh: print "Final fit values: " for i,p in enumerate(mpp): parinfo[i]['value'] = p print parinfo[i]['parname'],p," +/- ",mpperr[i] print "Chi2: ",mp.fnorm," Reduced Chi2: ",mp.fnorm/len(data)," DOF:",len(data)-len(mpp) return mpp,n_gaussian(pars=mpp)(xax),mpperr,chi2
def onedgaussfit(xax, data, err=None, params=[0,1,0,1],fixed=[False,False,False,False], limitedmin=[False,False,False,True], limitedmax=[False,False,False,False], minpars=[0,0,0,0], maxpars=[0,0,0,0], quiet=True, shh=True, veryverbose=False, vheight=True, negamp=False, usemoments=False): """ Inputs: xax - x axis data - y axis err - error corresponding to data params - Fit parameters: Height of background, Amplitude, Shift, Width fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? usemoments - replace default parameters with moments Returns: Fit parameters Model Fit errors chi2 """ def mpfitfun(x,y,err): if err is None: def f(p,fjac=None): return [0,(y-onedgaussian(x,*p))] else: def f(p,fjac=None): return [0,(y-onedgaussian(x,*p))/err] return f if xax == None: xax = numpy.arange(len(data)) if vheight is False: height = params[0] fixed[0] = True if usemoments: params = onedmoments(xax,data,vheight=vheight,negamp=negamp, veryverbose=veryverbose) if vheight is False: params = [height]+params if veryverbose: print "OneD moments: h: %g a: %g c: %g w: %g" % tuple(params) parinfo = [ {'n':0,'value':params[0],'limits':[minpars[0],maxpars[0]],'limited':[limitedmin[0],limitedmax[0]],'fixed':fixed[0],'parname':"HEIGHT",'error':0} , {'n':1,'value':params[1],'limits':[minpars[1],maxpars[1]],'limited':[limitedmin[1],limitedmax[1]],'fixed':fixed[1],'parname':"AMPLITUDE",'error':0}, {'n':2,'value':params[2],'limits':[minpars[2],maxpars[2]],'limited':[limitedmin[2],limitedmax[2]],'fixed':fixed[2],'parname':"SHIFT",'error':0}, {'n':3,'value':params[3],'limits':[minpars[3],maxpars[3]],'limited':[limitedmin[3],limitedmax[3]],'fixed':fixed[3],'parname':"WIDTH",'error':0}] mp = mpfit(mpfitfun(xax,data,err),parinfo=parinfo,quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if (not shh) or veryverbose: print "Fit status: ",mp.status for i,p in enumerate(mpp): parinfo[i]['value'] = p print parinfo[i]['parname'],p," +/- ",mpperr[i] print "Chi2: ",mp.fnorm," Reduced Chi2: ",mp.fnorm/len(data)," DOF:",len(data)-len(mpp) return mpp,onedgaussian(xax,*mpp),mpperr,chi2
def gaussfit(data,err=None,params=(),autoderiv=True,return_all=False,circle=False, fixed=numpy.repeat(False,7),limitedmin=[False,False,False,False,True,True,True], limitedmax=[False,False,False,False,False,False,True], usemoment=numpy.array([],dtype='bool'), minpars=numpy.repeat(0,7),maxpars=[0,0,0,0,0,0,360], rotate=1,vheight=1,quiet=True,returnmp=False, returnfitimage=False,**kwargs): """ Gaussian fitter with the ability to fit a variety of different forms of 2-dimensional gaussian. Input Parameters: data - 2-dimensional data array err=None - error array with same size as data array params=[] - initial input parameters for Gaussian function. (height, amplitude, x, y, width_x, width_y, rota) if not input, these will be determined from the moments of the system, assuming no rotation autoderiv=1 - use the autoderiv provided in the lmder.f function (the alternative is to us an analytic derivative with lmdif.f: this method is less robust) return_all=0 - Default is to return only the Gaussian parameters. 1 - fit params, fit error returnfitimage - returns (best fit params,best fit image) returnmp - returns the full mpfit struct circle=0 - default is an elliptical gaussian (different x, y widths), but can reduce the input by one parameter if it's a circular gaussian rotate=1 - default allows rotation of the gaussian ellipse. Can remove last parameter by setting rotate=0. numpy.expects angle in DEGREES vheight=1 - default allows a variable height-above-zero, i.e. an additive constant for the Gaussian function. Can remove first parameter by setting this to 0 usemoment - can choose which parameters to use a moment estimation for. Other parameters will be taken from params. Needs to be a boolean array. Output: Default output is a set of Gaussian parameters with the same shape as the input parameters If returnfitimage=True returns a numpy array of a guassian contructed using the best fit parameters. If returnmp=True returns a `mpfit` object. This object contains a `covar` attribute which is the 7x7 covariance array generated by the pmfit class in the `mpfit_custom.py` module. It contains a `param` attribute that contains a list of the best fit parameters in the same order as the optional input parameter `params`. Warning: Does NOT necessarily output a rotation angle between 0 and 360 degrees. """ usemoment=numpy.array(usemoment,dtype='bool') params=numpy.array(params,dtype='float') if usemoment.any() and len(params)==len(usemoment): moment = numpy.array(moments(data,circle,rotate,vheight,**kwargs),dtype='float') params[usemoment] = moment[usemoment] elif params == [] or len(params)==0: params = (moments(data,circle,rotate,vheight,**kwargs)) if vheight==0: vheight=1 params = numpy.concatenate([[0],params]) fixed[0] = 1 # mpfit will fail if it is given a start parameter outside the allowed range: for i in xrange(len(params)): if params[i] > maxpars[i] and limitedmax[i]: params[i] = maxpars[i] if params[i] < minpars[i] and limitedmin[i]: params[i] = minpars[i] if err is None: errorfunction = lambda p: numpy.ravel((twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)) else: errorfunction = lambda p: numpy.ravel((twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)/err) def mpfitfun(data,err): if err is None: def f(p,fjac=None): return [0,numpy.ravel(data-twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))] else: def f(p,fjac=None): return [0,numpy.ravel((data-twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))/err)] return f parinfo = [ {'n':1,'value':params[1],'limits':[minpars[1],maxpars[1]],'limited':[limitedmin[1],limitedmax[1]],'fixed':fixed[1],'parname':"AMPLITUDE",'error':0}, {'n':2,'value':params[2],'limits':[minpars[2],maxpars[2]],'limited':[limitedmin[2],limitedmax[2]],'fixed':fixed[2],'parname':"XSHIFT",'error':0}, {'n':3,'value':params[3],'limits':[minpars[3],maxpars[3]],'limited':[limitedmin[3],limitedmax[3]],'fixed':fixed[3],'parname':"YSHIFT",'error':0}, {'n':4,'value':params[4],'limits':[minpars[4],maxpars[4]],'limited':[limitedmin[4],limitedmax[4]],'fixed':fixed[4],'parname':"XWIDTH",'error':0} ] if vheight == 1: parinfo.insert(0,{'n':0,'value':params[0],'limits':[minpars[0],maxpars[0]],'limited':[limitedmin[0],limitedmax[0]],'fixed':fixed[0],'parname':"HEIGHT",'error':0}) if circle == 0: parinfo.append({'n':5,'value':params[5],'limits':[minpars[5],maxpars[5]],'limited':[limitedmin[5],limitedmax[5]],'fixed':fixed[5],'parname':"YWIDTH",'error':0}) if rotate == 1: parinfo.append({'n':6,'value':params[6],'limits':[minpars[6],maxpars[6]],'limited':[limitedmin[6],limitedmax[6]],'fixed':fixed[6],'parname':"ROTATION",'error':0}) if autoderiv == 0: # the analytic derivative, while not terribly difficult, is less # efficient and useful. I only bothered putting it here because I was # instructed to do so for a class project - please ask if you would # like this feature implemented raise ValueError("I'm sorry, I haven't implemented this feature yet.") else: # p, cov, infodict, errmsg, success = optimize.leastsq(errorfunction,\ # params, full_output=1) mp = mpfit(mpfitfun(data,err),parinfo=parinfo,quiet=quiet) if returnmp: returns = (mp) elif return_all == 0: returns = mp.params elif return_all == 1: returns = mp.params,mp.perror if returnfitimage: fitimage = twodgaussian(mp.params,circle,rotate,vheight)(*numpy.indices(data.shape)) returns = (returns,fitimage) return returns
def psffit(data, err=None, params=[], autoderiv=True, return_all=False, circle=True, fixed=numpy.repeat(False, 7), limitedmin=[False, False, False, False, True, True, True], limitedmax=[False, False, False, False, False, False, True], usemoment=numpy.array([], dtype='bool'), minpars=numpy.repeat(0, 7), maxpars=[0, 0, 0, 0, 0, 0, 360], rotate=0, vheight=1, quiet=True, returnmp=False, returnfitimage=False, psffunction=airy, extra_pars=None, return_parinfo=False, **kwargs): """ PSF fitter with the ability to fit a variety of different forms of 2-dimensional gaussian OR an Airy. This code is mostly directly copied from gaussfitter.py and presents yet another argument for me turning this into a class... Input Parameters: data - 2-dimensional data array err=None - error array with same size as data array params=[] - initial input parameters for Gaussian function. (height, amplitude, x, y, width_x, width_y, rota) if not input, these will be determined from the moments of the system, assuming no rotation autoderiv=1 - use the autoderiv provided in the lmder.f function (the alternative is to us an analytic derivative with lmdif.f: this method is less robust) return_all=0 - Default is to return only the Gaussian parameters. 1 - fit params, fit error returnfitimage - returns (best fit params,best fit image) returnmp - returns the full mpfit struct circle=0 - default is an elliptical gaussian (different x, y widths), but can reduce the input by one parameter if it's a circular gaussian rotate=1 - default allows rotation of the gaussian ellipse. Can remove last parameter by setting rotate=0. numpy.expects angle in DEGREES vheight=1 - default allows a variable height-above-zero, i.e. an additive constant for the Gaussian function. Can remove first parameter by setting this to 0 usemoment - can choose which parameters to use a moment estimation for. Other parameters will be taken from params. Needs to be a boolean array. extra_pars - If your psffunction requires extra parameters, pass their parinfo dictionaries through this variable Output: Default output is a set of Gaussian parameters with the same shape as the input parameters Can also output the covariance matrix, 'infodict' that contains a lot more detail about the fit (see scipy.optimize.leastsq), and a message from leastsq telling what the exit status of the fitting routine was Warning: Does NOT necessarily output a rotation angle between 0 and 360 degrees. """ usemoment = numpy.array(usemoment, dtype='bool') params = numpy.array(params, dtype='float') if usemoment.any() and len(params) == len(usemoment): moment = numpy.array(moments(data, circle, rotate, vheight, **kwargs), dtype='float') params[usemoment] = moment[usemoment] elif params == [] or len(params) == 0: params = (moments(data, circle, rotate, vheight, **kwargs)) if vheight == 0: vheight = 1 params = numpy.concatenate([[0], params]) fixed[0] = 1 # mpfit will fail if it is given a start parameter outside the allowed range: for i in xrange(len(params)): if params[i] > maxpars[i] and limitedmax[i]: params[i] = maxpars[i] if params[i] < minpars[i] and limitedmin[i]: params[i] = minpars[i] if err is None: errorfunction = lambda p: numpy.ravel((psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)) else: errorfunction = lambda p: numpy.ravel((psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)/err) def mpfitfun(data, err): if err is None: def f(p, fjac=None): return [0,numpy.ravel(data-psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))] else: def f(p, fjac=None): return [0,numpy.ravel((data-psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))/err)] return f parinfo = [] if vheight: parinfo.insert( 0, { 'n': 0, 'value': params[0], 'limits': [minpars[0], maxpars[0]], 'limited': [limitedmin[0], limitedmax[0]], 'fixed': fixed[0], 'parname': "HEIGHT", 'error': 0 }) ind = 1 else: ind = 0 parinfo.append({ 'n': 0 + ind, 'value': params[0 + ind], 'limits': [minpars[0 + ind], maxpars[0 + ind]], 'limited': [limitedmin[0 + ind], limitedmax[0 + ind]], 'fixed': fixed[0 + ind], 'parname': "AMPLITUDE", 'error': 0 }) parinfo.append({ 'n': 1 + ind, 'value': params[1 + ind], 'limits': [minpars[1 + ind], maxpars[1 + ind]], 'limited': [limitedmin[1 + ind], limitedmax[1 + ind]], 'fixed': fixed[1 + ind], 'parname': "XSHIFT", 'error': 0 }) parinfo.append({ 'n': 2 + ind, 'value': params[2 + ind], 'limits': [minpars[2 + ind], maxpars[2 + ind]], 'limited': [limitedmin[2 + ind], limitedmax[2 + ind]], 'fixed': fixed[2 + ind], 'parname': "YSHIFT", 'error': 0 }) parinfo.append({ 'n': 3 + ind, 'value': params[3 + ind], 'limits': [minpars[3 + ind], maxpars[3 + ind]], 'limited': [limitedmin[3 + ind], limitedmax[3 + ind]], 'fixed': fixed[3 + ind], 'parname': "XWIDTH", 'error': 0 }) if not (circle): parinfo.append({ 'n': 4 + ind, 'value': params[4 + ind], 'limits': [minpars[4 + ind], maxpars[4 + ind]], 'limited': [limitedmin[4 + ind], limitedmax[4 + ind]], 'fixed': fixed[4 + ind], 'parname': "YWIDTH", 'error': 0 }) if rotate: parinfo.append({ 'n': 5 + ind, 'value': params[5 + ind], 'limits': [minpars[5 + ind], maxpars[5 + ind]], 'limited': [limitedmin[5 + ind], limitedmax[5 + ind]], 'fixed': fixed[5 + ind], 'parname': "ROTATION", 'error': 0 }) if extra_pars: for P in extra_pars: parinfo.append(P) if autoderiv is False: # the analytic derivative, while not terribly difficult, is less # efficient and useful. I only bothered putting it here because I was # instructed to do so for a class project - please ask if you would # like this feature implemented raise NotImplementedError( "I'm sorry, I haven't implemented this feature yet.") else: # p, cov, infodict, errmsg, success = optimize.leastsq(errorfunction,\ # params, full_output=1) mp = mpfit(mpfitfun(data, err), parinfo=parinfo, quiet=quiet) if returnmp: returns = (mp) elif return_parinfo: returns = (parinfo) elif return_all is False: returns = mp.params elif return_all: returns = mp.params, mp.perror if returnfitimage: fitimage = psffunction(mp.params, circle, rotate, vheight)(*numpy.indices(data.shape)) returns = (returns, fitimage) return returns
# p[5]:Omega_bh2 # p[6]:Omega_m # p[7]:Omega_r # p[8]:Omega_k # p[9]... other Cosmological parameters # initial conditions print 'Prepare and reading data ...' p0 = np.array([0.141, 3.099, -19.10, -0.07, 68.34, 0.0221, 0.305, ogh2, 0], dtype='float64') n = len(p0) parbase = {'value': 0., 'fixed': 0, 'limited': [0, 0], 'limits': [0., 0.]} parinfo = [] for i in range(n): parinfo.append(copy.deepcopy(parbase)) for i in range(n): parinfo[i]['value'] = p0[i] m = mpfit(residual, p0, parinfo=parinfo) if (m.status <= 0): print 'error message = ', m.errmsg chisq = (residual(m.params)[1]**2).sum() print m.params print m.perror
def fitspec(specsegments,aperture=None, modelspec=modelspec, outpars=False, vlsrcorr=0, extinction=False, parinfo=modelpars(), quiet=1, **kwargs): """ fit a model spectrum The model is defined internal to fitspec so that parameters can be fixed based on input parameters """ specsegments = copy(specsegments) # copy.deepcopy(specsegments) parinfo = copy(parinfo) # copy.deepcopy(parinfo) kwargs = {'extinction':extinction} if extinction: parinfo=modelpars(extinction=extinction) def fitfun(x,y,err): return lambda(p): (y-modelspec(x,*p,**kwargs))/err def mpfitfun(x,y,err): def f(p,fjac=None): return [0,(y-modelspec(x,*p,**kwargs))/err] return f if aperture is not None: miny,maxy = aperture fitdata = asarray([ss['data'][miny:maxy,:].sum(axis=0) for ss in specsegments]).ravel() fiterr = asarray([ss['err'][:]*sqrt(maxy-miny) for ss in specsegments]).ravel() # since it is a summed aperture, add in quadrature else: fitdata = asarray([ss['data'] for ss in specsegments]).ravel() fiterr = asarray([ss['err'] for ss in specsegments]).ravel() fitwl = asarray([ss['wavelength'] for ss in specsegments]).ravel() try: parinfo = parinfo.tolist() print "Parinfo was an array. No idea why, it was never set to one. Ever." except: pass mp = mpfit(mpfitfun(fitwl,fitdata,fiterr),parinfo=parinfo,quiet=quiet) mpp = mp.params mpperr = mp.perror for i,p in enumerate(mpp): parinfo[i]['value'] = p if parinfo[i]['parname'] == 'SHIFT': print parinfo[i]['parname'],p+vlsrcorr," +/- ",mpperr[i] else: print parinfo[i]['parname'],p," +/- ",mpperr[i] # print "Temperature: ",mpp[0]," Shift: ",mpp[3],mpp[3]*mean(fitwl)/3e5," Width: ",mpp[2],mpp[2]*mean(fitwl)/3e5," Ortho/Para: ",mpp[4] # print "ERRORS: Temperature: ",mpperr[0]," Shift: ",mpperr[3],mpperr[3]*mean(fitwl)/3e5," Width: ",mpperr[2],mpperr[2]*mean(fitwl)/3e5," Ortho/Para: ",mpperr[4] print "Chi2: ",mp.fnorm," Reduced Chi2: ",mp.fnorm/len(fitdata)," DOF:",len(fitdata)-len(mpp) apfitd = { 'params':mpp, 'parerr':mpperr, 'parinfo':parinfo, 'wl':fitwl, 'data':fitdata, 'model':modelspec(fitwl,*mpp), 'err':fiterr } if aperture is not None: for ss in specsegments: ss['data'] = ss['data'][miny:maxy,:].sum(axis=0) for ss in specsegments: ss['model'] = modelspec(ss['wavelength'],*mpp) if outpars: return specsegments,apfitd,parinfo else: return specsegments,apfitd
def brokenpowerfit(xax, data, err=None, alphaguess1=0.0, alphaguess2=-2.0, scaleguess=1.0, breakpoint=None, quiet=True): """ Fit a broken power law (a line in log-space) to data as a function of x differs from 'plfit' because plfit fits a power law distribution, this code simply fits a power law This is a lot more intricate than the simple power law fit, since it involves fitting two power laws with different slopes Parameters: p[0] - scale p[1] - breakpoint p[2] - power 1 (xax < breakpoint) p[3] - power 2 (xax >= breakpoint) There are 5 parameters (NOT 4) returned because there are two scales that are *NOT* independent returns: scale1,scale2,breakpoint,alpha1,alpha2 """ logdata = np.log10(data) if err is None: err = np.ones(data.shape, dtype='float') def brokenpowerlaw(p): lowerhalf = (np.log10(p[0]) + np.log10(xax) * p[2]) * (xax < p[1]) # find the location at which both functions must be equal scale2loc = np.argmin(np.abs(xax - p[1])) scale2 = np.log10(xax[scale2loc]) * (p[2] - p[3]) + np.log10(p[0]) upperhalf = (scale2 + np.log10(xax) * p[3]) * (xax >= p[1]) # DEBUG print "scale1: %15g scale2: %15g xaxind: %5i xaxval: %15g lower: %15g upper: %15g" % (p[0],scale2,scale2loc,np.log10(xax[scale2loc]),lowerhalf[scale2loc-1],upperhalf[scale2loc]) return lowerhalf + upperhalf def mpfitfun(data, err): def f(p, fjac=None): return [0, np.ravel((brokenpowerlaw(p) - data) / err)] return f if breakpoint is None: breakpoint = np.median(xax) parinfo = [{}, { 'mpminstep': xax.min(), 'mpmaxstep': xax.max(), 'step': xax.min() }, {}, {}] mp = mpfit.mpfit(mpfitfun(logdata, err), xall=[scaleguess, breakpoint, alphaguess1, alphaguess2], quiet=quiet, parinfo=parinfo) fitp = mp.params scale2loc = np.argmin(np.abs(xax - fitp[1])) scale2 = 10**(np.log10(xax[scale2loc]) * (fitp[2] - fitp[3]) + np.log10(fitp[0])) fitp = np.array([fitp[0], scale2] + fitp[1:].tolist()) return fitp, mp
def fit_sed_mpfit_hz(xdata, flux, guesses=(0, 0), err=None, blackbody_function='blackbody', quiet=True, sc=1e20, **kwargs): """ Parameters ---------- xdata : array Array of the frequencies of the data flux : array The fluxes corresponding to the xdata values. Should be in erg/s/cm^2/Hz guesses : (Temperature,Column) or (Temperature,Beta,Column) The input guesses. 3 parameters are used for modified blackbody fitting, two for temperature fitting. blackbody_function: str The blackbody function to fit, either 'blackbody', 'modified', or 'modified_blackbody' quiet : bool quiet flag passed to mpfit sc : float A numerical parameter to enable the fitter to function properly. It is unclear what values this needs to take, 1e20 seems to work by bringing the units from erg/s/cm^2/Hz to Jy, i.e. bringing them into the "of order 1" regime. This does NOT affect the output *units*, though it may affect the quality of the fit. Returns ------- mp : mpfit structure An mpfit structure. Access parameters and errors via `mp.params` and `mp.perror`. The covariance matrix is in mp.covar. Examples -------- >>> from astropy import units as u >>> import numpy as np >>> wavelengths = np.array([20,70,160,250,350,500,850,1100]) * u.um >>> frequencies = wavelengths.to(u.Hz, u.spectral()) >>> temperature = 15 * u.K >>> column = 1e22 * u.cm**-2 >>> flux = modified_blackbody(frequencies, temperature, beta=1.75, ... column=column) >>> err = 0.1 * flux >>> np.random.seed(0) >>> noise = np.random.randn(frequencies.size) * err >>> tguess, bguess, nguess = 20.,2.,21.5 >>> bbunit = u.erg/u.s/u.cm**2/u.Hz >>> mp = fit_sed_mpfit_hz(frequencies.to(u.Hz).value, ... (flux+noise).to(bbunit).value, err=err.to(bbunit).value, ... blackbody_function='modified', ... guesses=(tguess, bguess, nguess)) >>> print(mp.params) [ 14.99095224 1.78620237 22.05271119] >>> # T~14.9 K, beta ~1.79, column ~10^22 """ try: from agpy import mpfit except ImportError: print("Cannot import mpfit: cannot use mpfit-based fitter.") bbfd = { 'blackbody': _blackbody_hz, 'modified': _modified_blackbody_hz, 'modified_blackbody': _modified_blackbody_hz } bbf = bbfd[blackbody_function] def mpfitfun(x, y, err): if err is None: def f(p, fjac=None): return [0, (y * sc - bbf(x, *p, **kwargs) * sc)] else: def f(p, fjac=None): return [0, (y * sc - bbf(x, *p, **kwargs) * sc) / (err * sc)] return f err = err if err is not None else flux * 0.0 + 1.0 mp = mpfit.mpfit(mpfitfun(xdata, flux, err), guesses, quiet=quiet) return mp
def fit_sed_mpfit_hz(xdata, flux, guesses=(0,0), err=None, blackbody_function='blackbody', quiet=True, sc=1e20, **kwargs): """ Parameters ---------- xdata : array Array of the frequencies of the data flux : array The fluxes corresponding to the xdata values. Should be in erg/s/cm^2/Hz guesses : (Temperature,Column) or (Temperature,Beta,Column) The input guesses. 3 parameters are used for modified blackbody fitting, two for temperature fitting. blackbody_function: str The blackbody function to fit, either 'blackbody', 'modified', or 'modified_blackbody' quiet : bool quiet flag passed to mpfit sc : float A numerical parameter to enable the fitter to function properly. It is unclear what values this needs to take, 1e20 seems to work by bringing the units from erg/s/cm^2/Hz to Jy, i.e. bringing them into the "of order 1" regime. This does NOT affect the output *units*, though it may affect the quality of the fit. Returns ------- mp : mpfit structure An mpfit structure. Access parameters and errors via `mp.params` and `mp.perror`. The covariance matrix is in mp.covar. Examples -------- >>> from astropy import units as u >>> import numpy as np >>> wavelengths = np.array([20,70,160,250,350,500,850,1100]) * u.um >>> frequencies = wavelengths.to(u.Hz, u.spectral()) >>> temperature = 15 * u.K >>> column = 1e22 * u.cm**-2 >>> flux = modified_blackbody(frequencies, temperature, beta=1.75, ... column=column) >>> err = 0.1 * flux >>> np.random.seed(0) >>> noise = np.random.randn(frequencies.size) * err >>> tguess, bguess, nguess = 20.,2.,21.5 >>> bbunit = u.erg/u.s/u.cm**2/u.Hz >>> mp = fit_sed_mpfit_hz(frequencies.to(u.Hz).value, ... (flux+noise).to(bbunit).value, err=err.to(bbunit).value, ... blackbody_function='modified', ... guesses=(tguess, bguess, nguess)) >>> print(mp.params) [ 14.99095224 1.78620237 22.05271119] >>> # T~14.9 K, beta ~1.79, column ~10^22 """ try: from agpy import mpfit except ImportError: print("Cannot import mpfit: cannot use mpfit-based fitter.") bbfd = {'blackbody': _blackbody_hz, 'modified': _modified_blackbody_hz, 'modified_blackbody': _modified_blackbody_hz} bbf = bbfd[blackbody_function] def mpfitfun(x,y,err): if err is None: def f(p,fjac=None): return [0,(y*sc-bbf(x, *p, **kwargs)*sc)] else: def f(p,fjac=None): return [0,(y*sc-bbf(x, *p, **kwargs)*sc)/(err*sc)] return f err = err if err is not None else flux*0.0 + 1.0 mp = mpfit.mpfit(mpfitfun(xdata,flux,err), guesses, quiet=quiet) return mp
def multigaussfit(xax, data, ngauss=1, err=None, params=[1, 0, 1], fixed=[False, False, False], limitedmin=[False, False, True], limitedmax=[False, False, False], minpars=[0, 0, 0], maxpars=[0, 0, 0], quiet=True, shh=True, veryverbose=False): """ An improvement on onedgaussfit. Lets you fit multiple gaussians. Inputs: xax - x axis data - y axis ngauss - How many gaussians to fit? Default 1 (this could supersede onedgaussfit) err - error corresponding to data These parameters need to have length = 3*ngauss. If ngauss > 1 and length = 3, they will be replicated ngauss times, otherwise they will be reset to defaults: params - Fit parameters: [amplitude, offset, width] * ngauss If len(params) % 3 == 0, ngauss will be set to len(params) / 3 fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? Returns: Fit parameters Model Fit errors chi2 """ if len(params) != ngauss and (len(params) / 3) > ngauss: ngauss = len(params) / 3 if isinstance(params, numpy.ndarray): params = params.tolist() # make sure all various things are the right length; if they're not, fix them using the defaults for parlist in (params, fixed, limitedmin, limitedmax, minpars, maxpars): if len(parlist) != 3 * ngauss: # if you leave the defaults, or enter something that can be multiplied by 3 to get to the # right number of gaussians, it will just replicate if len(parlist) == 3: parlist *= ngauss elif parlist == params: parlist[:] = [1, 0, 1] * ngauss elif parlist == fixed or parlist == limitedmax: parlist[:] = [False, False, False] * ngauss elif parlist == limitedmin: parlist[:] = [False, False, True] * ngauss elif parlist == minpars or parlist == maxpars: parlist[:] = [0, 0, 0] * ngauss def mpfitfun(x, y, err): if err is None: def f(p, fjac=None): return [0, (y - n_gaussian(pars=p)(x))] else: def f(p, fjac=None): return [0, (y - n_gaussian(pars=p)(x)) / err] return f if xax == None: xax = numpy.arange(len(data)) parnames = {0: "AMPLITUDE", 1: "SHIFT", 2: "WIDTH"} parinfo = [{ 'n': ii, 'value': params[ii], 'limits': [minpars[ii], maxpars[ii]], 'limited': [limitedmin[ii], limitedmax[ii]], 'fixed': fixed[ii], 'parname': parnames[ii % 3] + str(ii % 3), 'error': ii } for ii in xrange(len(params))] if veryverbose: print "GUESSES: " print "\n".join( ["%s: %s" % (p['parname'], p['value']) for p in parinfo]) mp = mpfit(mpfitfun(xax, data, err), parinfo=parinfo, quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if not shh: print "Final fit values: " for i, p in enumerate(mpp): parinfo[i]['value'] = p print parinfo[i]['parname'], p, " +/- ", mpperr[i] print "Chi2: ", mp.fnorm, " Reduced Chi2: ", mp.fnorm / len( data), " DOF:", len(data) - len(mpp) return mpp, n_gaussian(pars=mpp)(xax), mpperr, chi2
# p[9]... other Cosmological parameters # initial conditions print 'Prepare and reading data ...' p0 = np.array([0.141 ,3.099 ,-19.10 ,-0.07 , 68.34 , 0.0221, 0.305,ogh2, 0],dtype='float64') n = len(p0) parbase={'value':0., 'fixed':0, 'limited':[0,0], 'limits':[0.,0.]} parinfo=[] for i in range(n): parinfo.append(copy.deepcopy(parbase)) for i in range(n): parinfo[i]['value']=p0[i] m = mpfit(residual, p0, parinfo=parinfo) if (m.status <= 0): print 'error message = ', m.errmsg chisq=(residual(m.params)[1]**2).sum() print m.params print m.perror
def psffit(data,err=None,params=[],autoderiv=True,return_all=False,circle=True, fixed=numpy.repeat(False,7),limitedmin=[False,False,False,False,True,True,True], limitedmax=[False,False,False,False,False,False,True], usemoment=numpy.array([],dtype='bool'), minpars=numpy.repeat(0,7),maxpars=[0,0,0,0,0,0,360], rotate=0,vheight=1,quiet=True,returnmp=False, returnfitimage=False, psffunction=airy, extra_pars=None, return_parinfo=False, **kwargs): """ PSF fitter with the ability to fit a variety of different forms of 2-dimensional gaussian OR an Airy. This code is mostly directly copied from gaussfitter.py and presents yet another argument for me turning this into a class... Input Parameters: data - 2-dimensional data array err=None - error array with same size as data array params=[] - initial input parameters for Gaussian function. (height, amplitude, x, y, width_x, width_y, rota) if not input, these will be determined from the moments of the system, assuming no rotation autoderiv=1 - use the autoderiv provided in the lmder.f function (the alternative is to us an analytic derivative with lmdif.f: this method is less robust) return_all=0 - Default is to return only the Gaussian parameters. 1 - fit params, fit error returnfitimage - returns (best fit params,best fit image) returnmp - returns the full mpfit struct circle=0 - default is an elliptical gaussian (different x, y widths), but can reduce the input by one parameter if it's a circular gaussian rotate=1 - default allows rotation of the gaussian ellipse. Can remove last parameter by setting rotate=0. numpy.expects angle in DEGREES vheight=1 - default allows a variable height-above-zero, i.e. an additive constant for the Gaussian function. Can remove first parameter by setting this to 0 usemoment - can choose which parameters to use a moment estimation for. Other parameters will be taken from params. Needs to be a boolean array. extra_pars - If your psffunction requires extra parameters, pass their parinfo dictionaries through this variable Output: Default output is a set of Gaussian parameters with the same shape as the input parameters Can also output the covariance matrix, 'infodict' that contains a lot more detail about the fit (see scipy.optimize.leastsq), and a message from leastsq telling what the exit status of the fitting routine was Warning: Does NOT necessarily output a rotation angle between 0 and 360 degrees. """ usemoment=numpy.array(usemoment,dtype='bool') params=numpy.array(params,dtype='float') if usemoment.any() and len(params)==len(usemoment): moment = numpy.array(moments(data,circle,rotate,vheight,**kwargs),dtype='float') params[usemoment] = moment[usemoment] elif params == [] or len(params)==0: params = (moments(data,circle,rotate,vheight,**kwargs)) if vheight==0: vheight=1 params = numpy.concatenate([[0],params]) fixed[0] = 1 # mpfit will fail if it is given a start parameter outside the allowed range: for i in xrange(len(params)): if params[i] > maxpars[i] and limitedmax[i]: params[i] = maxpars[i] if params[i] < minpars[i] and limitedmin[i]: params[i] = minpars[i] if err is None: errorfunction = lambda p: numpy.ravel((psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)) else: errorfunction = lambda p: numpy.ravel((psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)/err) def mpfitfun(data,err): if err is None: def f(p,fjac=None): return [0,numpy.ravel(data-psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))] else: def f(p,fjac=None): return [0,numpy.ravel((data-psffunction(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))/err)] return f parinfo = [ ] if vheight: parinfo.insert(0,{'n':0,'value':params[0],'limits':[minpars[0],maxpars[0]],'limited':[limitedmin[0],limitedmax[0]],'fixed':fixed[0],'parname':"HEIGHT",'error':0}) ind = 1 else: ind = 0 parinfo.append({'n':0+ind,'value':params[0+ind],'limits':[minpars[0+ind],maxpars[0+ind]],'limited':[limitedmin[0+ind],limitedmax[0+ind]],'fixed':fixed[0+ind],'parname':"AMPLITUDE",'error':0}) parinfo.append({'n':1+ind,'value':params[1+ind],'limits':[minpars[1+ind],maxpars[1+ind]],'limited':[limitedmin[1+ind],limitedmax[1+ind]],'fixed':fixed[1+ind],'parname':"XSHIFT",'error':0}) parinfo.append({'n':2+ind,'value':params[2+ind],'limits':[minpars[2+ind],maxpars[2+ind]],'limited':[limitedmin[2+ind],limitedmax[2+ind]],'fixed':fixed[2+ind],'parname':"YSHIFT",'error':0}) parinfo.append({'n':3+ind,'value':params[3+ind],'limits':[minpars[3+ind],maxpars[3+ind]],'limited':[limitedmin[3+ind],limitedmax[3+ind]],'fixed':fixed[3+ind],'parname':"XWIDTH",'error':0}) if not(circle): parinfo.append({'n':4+ind,'value':params[4+ind],'limits':[minpars[4+ind],maxpars[4+ind]],'limited':[limitedmin[4+ind],limitedmax[4+ind]],'fixed':fixed[4+ind],'parname':"YWIDTH",'error':0}) if rotate: parinfo.append({'n':5+ind,'value':params[5+ind],'limits':[minpars[5+ind],maxpars[5+ind]],'limited':[limitedmin[5+ind],limitedmax[5+ind]],'fixed':fixed[5+ind],'parname':"ROTATION",'error':0}) if extra_pars: for P in extra_pars: parinfo.append(P) if autoderiv is False: # the analytic derivative, while not terribly difficult, is less # efficient and useful. I only bothered putting it here because I was # instructed to do so for a class project - please ask if you would # like this feature implemented raise NotImplementedError("I'm sorry, I haven't implemented this feature yet.") else: # p, cov, infodict, errmsg, success = optimize.leastsq(errorfunction,\ # params, full_output=1) mp = mpfit(mpfitfun(data,err),parinfo=parinfo,quiet=quiet) if returnmp: returns = (mp) elif return_parinfo: returns = (parinfo) elif return_all is False: returns = mp.params elif return_all: returns = mp.params,mp.perror if returnfitimage: fitimage = psffunction(mp.params,circle,rotate,vheight)(*numpy.indices(data.shape)) returns = (returns,fitimage) return returns
def fit_blackbody(xdata, flux, guesses=(0, 0), err=None, blackbody_function=blackbody, quiet=True, **kwargs): """ Parameters ---------- xdata : array Array of the X-values (frequency, wavelength) of the data flux : array The fluxes corresponding to the xdata values guesses : (Temperature,Scale) or (Temperature,Beta,Scale) The input guesses. 3 parameters are used for greybody fitting, two for temperature fitting. blackbody_function: function Must take x-axis (e.g. frequency), temperature, scale, and then optionally beta args quiet : bool quiet flag passed to mpfit Returns ------- mp : mpfit structure An mpfit structure. Access parameters and errors via `mp.params` and `mp.perror`. The covariance matrix is in mp.covar. Examples -------- >>> wavelength = array([20,70,160,250,350,500,850,1100]) >>> flux = modified_blackbody_wavelength(wavelength, 15, beta=1.75, logN=22, wavelength_units='microns', normalize=False, logscale=16) >>> err = 0.1 * flux >>> np.random.seed(0) >>> flux += np.random.randn(len(wavelength)) * err >>> tguess, bguess, nguess = 20.,2.,21.5 >>> mp = fit_blackbody(wavelength, flux, err=err, blackbody_function=modified_blackbody_wavelength, logscale=16, guesses=(tguess, bguess, nguess), wavelength_units='microns') >>> print mp.params [ 14.99095224 1.78620237 22.05271119] >>> # T~14.9 K, beta ~1.79, column ~10^22 """ def mpfitfun(x, y, err): if err is None: def f(p, fjac=None): return [ 0, (y - blackbody_function(x, *p, normalize=False, **kwargs)) ] else: def f(p, fjac=None): return [ 0, (y - blackbody_function( x, *p, normalize=False, **kwargs)) / err ] return f err = err if err is not None else flux * 0.0 + 1.0 mp = mpfit.mpfit(mpfitfun(xdata, flux, err), guesses, quiet=quiet) return mp
def onedgaussfit(xax, data, err=None, params=[0, 1, 0, 1], fixed=[False, False, False, False], limitedmin=[False, False, False, True], limitedmax=[False, False, False, False], minpars=[0, 0, 0, 0], maxpars=[0, 0, 0, 0], quiet=True, shh=True, veryverbose=False, vheight=True, negamp=False, usemoments=False): """ Inputs: xax - x axis data - y axis err - error corresponding to data params - Fit parameters: Height of background, Amplitude, Shift, Width fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? usemoments - replace default parameters with moments Returns: Fit parameters Model Fit errors chi2 """ def mpfitfun(x, y, err): if err is None: def f(p, fjac=None): return [0, (y - onedgaussian(x, *p))] else: def f(p, fjac=None): return [0, (y - onedgaussian(x, *p)) / err] return f if xax == None: xax = numpy.arange(len(data)) if vheight is False: height = params[0] fixed[0] = True if usemoments: params = onedmoments(xax, data, vheight=vheight, negamp=negamp, veryverbose=veryverbose) if vheight is False: params = [height] + params if veryverbose: print "OneD moments: h: %g a: %g c: %g w: %g" % tuple(params) parinfo = [{ 'n': 0, 'value': params[0], 'limits': [minpars[0], maxpars[0]], 'limited': [limitedmin[0], limitedmax[0]], 'fixed': fixed[0], 'parname': "HEIGHT", 'error': 0 }, { 'n': 1, 'value': params[1], 'limits': [minpars[1], maxpars[1]], 'limited': [limitedmin[1], limitedmax[1]], 'fixed': fixed[1], 'parname': "AMPLITUDE", 'error': 0 }, { 'n': 2, 'value': params[2], 'limits': [minpars[2], maxpars[2]], 'limited': [limitedmin[2], limitedmax[2]], 'fixed': fixed[2], 'parname': "SHIFT", 'error': 0 }, { 'n': 3, 'value': params[3], 'limits': [minpars[3], maxpars[3]], 'limited': [limitedmin[3], limitedmax[3]], 'fixed': fixed[3], 'parname': "WIDTH", 'error': 0 }] mp = mpfit(mpfitfun(xax, data, err), parinfo=parinfo, quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if (not shh) or veryverbose: print "Fit status: ", mp.status for i, p in enumerate(mpp): parinfo[i]['value'] = p print parinfo[i]['parname'], p, " +/- ", mpperr[i] print "Chi2: ", mp.fnorm, " Reduced Chi2: ", mp.fnorm / len( data), " DOF:", len(data) - len(mpp) return mpp, onedgaussian(xax, *mpp), mpperr, chi2