Source code for admit.util.continuumsubtraction.spectral.algorithms.SplineFit

""" .. _splinecontinuum:

    SplineFit --- Continuum subtraction using a spline fit.
    -------------------------------------------------------

    Module for doing spline fitting to the continuum of a 1D spectrum.

"""
import numpy as np

from admit.util.AdmitLogging import AdmitLogging as logging

try:
    from scipy.interpolate import UnivariateSpline
except:
    print "WARNING: No scipy; SplineFit fitter cannot function."


[docs]class SplineFit(object): """ Class which calculates the continuum of a 1D spectrum by fitting a spline to the continuum channels. The algorithm can be controlled by arguments to the run() method. Parameters ---------- x : numpy array An array containing the x coordinates. y : masked array A masked array containing the y coordinates with any strong emission masked. Attributes ---------- None """ def __init__(self, x, y): self.x = x self.y = y
[docs] def run(self,**keyval): """ Method to calculate the continuum from the given masked spectrum. If search=True is given as an argument then the algorithm will iterate through the different order splines to find the best fit, based on noise level. Parameters ---------- keyval : dictionary Dictionary containing the keyword value pair arguments Returns ------- numpy array containing the best fit continuum Notes ----- Arguments for the run method: - search : bool, whether or not to search for the best fit. Default: False - bbox : array_like, 2-sequence specifying the boundary of the approximation interval. If None (default), ``bbox=[x[0], x[-1]]``. - k : int 1 < k <= 5, the degree of spline smoothing to use, Defualt: 3 - s : float or None Positive smoothing factor used to choose the number of knots. Number of knots will be increased until the smoothing condition is satisfied:: sum((w[i] * (y[i]-spl(x[i])))**2, axis=0) <= s If None (default), ``s = len(w)`` which should be a good value if ``1/w[i]`` is an estimate of the standard deviation of ``y[i]``. If 0, spline will interpolate through all data points. - ext : int or str Controls the extrapolation mode for elements not in the interval defined by the knot sequence. * if ext=0 or 'extrapolate', return the extrapolated value. * if ext=1 or 'zeros', return 0 * if ext=2 or 'raise', raise a ValueError * if ext=3 of 'const', return the boundary value. The default value is 0. - check_finite : bool Whether to check that the input arrays contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination or non-sensical results) if the inputs do contain infinities or NaNs. Default is False. """ # set up the data elements args = {"x": self.x, "y" : self.y.data, # reverse the weights since a masked array uses True for good values # and UnivariateSpline needs a number. The reversal translates the # True values to False, which are then interpreted as 0.0 "w" : -self.y.mask} # get the given arguments search = False noise = None if "search" in keyval: search = keyval["search"] if "noise" in keyval: noise = keyval["noise"] if "chisq" in keyval: maxchisq = keyval["chisq"] for arg in ["bbox","k","s","ext","check_finite"]: if arg in keyval: args[arg] = keyval[arg] # if searching for the best fit # limited to 3rd order as 4th and 5th order could fit weak wide lines if search: chisq = {1:1000., 2:1000., 3:1000.} # iterate over each possible order for k in chisq: args["k"] = k spl = UnivariateSpline(**args) fit = spl(self.x) chisq[k] = stats.reducedchisquared(self.y, fit, k + 1, noise) # find the best fit, if chisq values are close (<20%), then prefer the lowest order mv = 1000. order = 0 for k in chisq: if chisq[k] < mv and (mv - chisq[k]) / mv > 0.2: mv = chisq[k] order = k # if we have a really poor fit then just give up if mv > maxchisq: logging.warning("No good fit for continuum found") return None args["k"] = order logging.info("Using fit of order %i with chi^2 of %f" % (order, mv)) # do the final fit spl = UnivariateSpline(**args) fit = spl(self.x) else: # do the fit with the given parameters spl = UnivariateSpline(**args) fit = spl(self.x) return fit