def fitter(self, xax, data, err=None, quiet=True, veryverbose=False, debug=False, parinfo=None, **kwargs): """ Run the fitter using mpfit. kwargs will be passed to _make_parinfo and mpfit. Parameters ---------- xax : SpectroscopicAxis The X-axis of the spectrum data : ndarray The data to fit err : ndarray (optional) The error on the data. If unspecified, will be uniform unity parinfo : ParinfoList The guesses, parameter limits, etc. See `pyspeckit.spectrum.parinfo` for details quiet : bool pass to mpfit. If False, will print out the parameter values for each iteration of the fitter veryverbose : bool print out a variety of mpfit output parameters debug : bool raise an exception (rather than a warning) if chi^2 is nan """ if parinfo is None: parinfo, kwargs = self._make_parinfo(debug=debug, **kwargs) else: log.debug("Using user-specified parinfo dict") # clean out disallowed kwargs (don't want to pass them to mpfit) #throwaway, kwargs = self._make_parinfo(debug=debug, **kwargs) self.xax = xax # the 'stored' xax is just a link to the original if hasattr(xax, 'as_unit') and self.fitunits is not None: # some models will depend on the input units. For these, pass in an X-axis in those units # (gaussian, voigt, lorentz profiles should not depend on units. Ammonia, formaldehyde, # H-alpha, etc. should) xax = copy.copy(xax) # xax.convert_to_unit(self.fitunits, quiet=quiet) xax = xax.as_unit(self.fitunits, quiet=quiet, **kwargs) elif self.fitunits is not None: raise TypeError("X axis does not have a convert method") if np.any(np.isnan(data)) or np.any(np.isinf(data)): err[np.isnan(data) + np.isinf(data)] = np.inf data[np.isnan(data) + np.isinf(data)] = 0 if np.any(np.isnan(err)): raise ValueError( "One or more of the error values is NaN." " This is not allowed. Errors can be infinite " "(which is equivalent to giving zero weight to " "a data point), but otherwise they must be positive " "floats.") elif np.any(err < 0): raise ValueError("At least one error value is negative, which is " "not allowed as negative errors are not " "meaningful in the optimization process.") for p in parinfo: log.debug(p) log.debug("\n".join([ "%s %i: tied: %s value: %s" % (p['parname'], p['n'], p['tied'], p['value']) for p in parinfo ])) mp = mpfit(self.mpfitfun(xax, data, err), parinfo=parinfo, quiet=quiet, debug=debug, **kwargs) mpp = mp.params if mp.perror is not None: mpperr = mp.perror else: mpperr = mpp * 0 chi2 = mp.fnorm if mp.status == 0: if "parameters are not within PARINFO limits" in mp.errmsg: log.warn(parinfo) raise mpfitException(mp.errmsg) for i, (p, e) in enumerate(zip(mpp, mpperr)): self.parinfo[i]['value'] = p self.parinfo[i]['error'] = e if veryverbose: log.info("Fit status: {0}".format(mp.status)) log.info("Fit error message: {0}".format(mp.errmsg)) log.info("Fit message: {0}".format(mpfit_messages[mp.status])) for i, p in enumerate(mpp): log.info("{0}: {1} +/- {2}".format(self.parinfo[i]['parname'], p, mpperr[i])) log.info("Chi2: {0} Reduced Chi2: {1} DOF:{2}".format( mp.fnorm, mp.fnorm / (len(data) - len(mpp)), len(data) - len(mpp))) self.mp = mp self.mpp = self.parinfo.values self.mpperr = self.parinfo.errors self.mppnames = self.parinfo.names self.model = self.n_modelfunc(self.parinfo, **self.modelfunc_kwargs)(xax) log.debug("Modelpars: {0}".format(self.mpp)) if np.isnan(chi2): if debug: raise ValueError("Error: chi^2 is nan") else: log.warn("Warning: chi^2 is nan") return mpp, self.model, mpperr, chi2
def fitter(self, xax, data, err=None, quiet=True, veryverbose=False, debug=False, parinfo=None, **kwargs): """ Run the fitter using mpfit. kwargs will be passed to _make_parinfo and mpfit. Parameters ---------- xax : SpectroscopicAxis The X-axis of the spectrum data : ndarray The data to fit err : ndarray (optional) The error on the data. If unspecified, will be uniform unity parinfo : ParinfoList The guesses, parameter limits, etc. See `pyspeckit.spectrum.parinfo` for details quiet : bool pass to mpfit. If False, will print out the parameter values for each iteration of the fitter veryverbose : bool print out a variety of mpfit output parameters debug : bool raise an exception (rather than a warning) if chi^2 is nan """ if parinfo is None: parinfo, kwargs = self._make_parinfo(debug=debug, **kwargs) else: log.debug("Using user-specified parinfo dict") # clean out disallowed kwargs (don't want to pass them to mpfit) #throwaway, kwargs = self._make_parinfo(debug=debug, **kwargs) self.xax = xax # the 'stored' xax is just a link to the original if hasattr(xax,'as_unit') and self.fitunits is not None: # some models will depend on the input units. For these, pass in an X-axis in those units # (gaussian, voigt, lorentz profiles should not depend on units. Ammonia, formaldehyde, # H-alpha, etc. should) xax = copy.copy(xax) # xax.convert_to_unit(self.fitunits, quiet=quiet) xax = xax.as_unit(self.fitunits, quiet=quiet, **kwargs) elif self.fitunits is not None: raise TypeError("X axis does not have a convert method") if np.any(np.isnan(data)) or np.any(np.isinf(data)): err[np.isnan(data) + np.isinf(data)] = np.inf data[np.isnan(data) + np.isinf(data)] = 0 if np.any(np.isnan(err)): raise ValueError("One or more of the error values is NaN." " This is not allowed. Errors can be infinite " "(which is equivalent to giving zero weight to " "a data point), but otherwise they must be positive " "floats.") elif np.any(err<0): raise ValueError("At least one error value is negative, which is " "not allowed as negative errors are not " "meaningful in the optimization process.") for p in parinfo: log.debug( p ) log.debug( "\n".join(["%s %i: tied: %s value: %s" % (p['parname'],p['n'],p['tied'],p['value']) for p in parinfo]) ) mp = mpfit(self.mpfitfun(xax,data,err),parinfo=parinfo,quiet=quiet,debug=debug,**kwargs) mpp = mp.params if mp.perror is not None: mpperr = mp.perror else: mpperr = mpp*0 chi2 = mp.fnorm if mp.status == 0: if "parameters are not within PARINFO limits" in mp.errmsg: log.warning( parinfo ) raise mpfitException(mp.errmsg) for i,(p,e) in enumerate(zip(mpp,mpperr)): self.parinfo[i]['value'] = p self.parinfo[i]['error'] = e if veryverbose: log.info("Fit status: {0}".format(mp.status)) log.info("Fit error message: {0}".format(mp.errmsg)) log.info("Fit message: {0}".format(mpfit_messages[mp.status])) for i,p in enumerate(mpp): log.info("{0}: {1} +/- {2}".format(self.parinfo[i]['parname'], p,mpperr[i])) log.info("Chi2: {0} Reduced Chi2: {1} DOF:{2}".format(mp.fnorm, mp.fnorm/(len(data)-len(mpp)), len(data)-len(mpp))) self.mp = mp self.mpp = self.parinfo.values self.mpperr = self.parinfo.errors self.mppnames = self.parinfo.names self.model = self.n_modelfunc(self.parinfo,**self.modelfunc_kwargs)(xax) log.debug("Modelpars: {0}".format(self.mpp)) if np.isnan(chi2): if debug: raise ValueError("Error: chi^2 is nan") else: log.warning("Warning: chi^2 is nan") return mpp,self.model,mpperr,chi2
def fitter(self, xax, data, err=None, quiet=True, veryverbose=False, debug=False, parinfo=None, **kwargs): """ Run the fitter using mpfit. kwargs will be passed to _make_parinfo and mpfit. Parameters ---------- xax : SpectroscopicAxis The X-axis of the spectrum data : ndarray The data to fit err : ndarray (optional) The error on the data. If unspecified, will be uniform unity parinfo : ParinfoList The guesses, parameter limits, etc. See `pyspeckit.spectrum.parinfo` for details quiet : bool pass to mpfit. If False, will print out the parameter values for each iteration of the fitter veryverbose : bool print out a variety of mpfit output parameters debug : bool raise an exception (rather than a warning) if chi^2 is nan """ if parinfo is None: parinfo, kwargs = self._make_parinfo(debug=debug, **kwargs) else: if debug: print "Using user-specified parinfo dict" # clean out disallowed kwargs (don't want to pass them to mpfit) #throwaway, kwargs = self._make_parinfo(debug=debug, **kwargs) self.xax = xax # the 'stored' xax is just a link to the original if hasattr(xax,'convert_to_unit') and self.fitunits is not None: # some models will depend on the input units. For these, pass in an X-axis in those units # (gaussian, voigt, lorentz profiles should not depend on units. Ammonia, formaldehyde, # H-alpha, etc. should) xax = copy.copy(xax) xax.convert_to_unit(self.fitunits, quiet=quiet) elif self.fitunits is not None: raise TypeError("X axis does not have a convert method") if np.any(np.isnan(data)) or np.any(np.isinf(data)): err[np.isnan(data) + np.isinf(data)] = np.inf data[np.isnan(data) + np.isinf(data)] = 0 if debug: for p in parinfo: print p print "\n".join(["%s %i: tied: %s value: %s" % (p['parname'],p['n'],p['tied'],p['value']) for p in parinfo]) mp = mpfit(self.mpfitfun(xax,data,err),parinfo=parinfo,quiet=quiet,**kwargs) mpp = mp.params if mp.perror is not None: mpperr = mp.perror else: mpperr = mpp*0 chi2 = mp.fnorm if mp.status == 0: if "parameters are not within PARINFO limits" in mp.errmsg: print parinfo raise mpfitException(mp.errmsg) for i,(p,e) in enumerate(zip(mpp,mpperr)): self.parinfo[i]['value'] = p self.parinfo[i]['error'] = e if veryverbose: print "Fit status: ",mp.status print "Fit error message: ",mp.errmsg print "Fit message: ",mpfit_messages[mp.status] for i,p in enumerate(mpp): print self.parinfo[i]['parname'],p," +/- ",mpperr[i] print "Chi2: ",mp.fnorm," Reduced Chi2: ",mp.fnorm/len(data)," DOF:",len(data)-len(mpp) self.mp = mp self.mpp = self.parinfo.values self.mpperr = self.parinfo.errors self.mppnames = self.parinfo.names self.model = self.n_modelfunc(self.parinfo,**self.modelfunc_kwargs)(xax) if debug: print "Modelpars: ",self.mpp if np.isnan(chi2): if debug: raise ValueError("Error: chi^2 is nan") else: print "Warning: chi^2 is nan" return mpp,self.model,mpperr,chi2