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

""" .. _polycontinuum:

    PolyFit --- Continuum subtraction using a polynomial fit.
    ---------------------------------------------------------

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

"""

import numpy as np
import numpy.ma as ma

from admit.util import stats
from admit.util.AdmitLogging import AdmitLogging as logging


[docs]class PolyFit(object): """ Class which calculates the continuum of a 1D spectrum by fitting a polynomial 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 - deg : int, the degree of polynomial to use, Defualt: 1 """ # set up the data elements args = {"x": self.x, "y" : ma.fix_invalid(self.y,fill_value=0.0), # 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 chisq = 3.0 if "search" in keyval: search = keyval["search"] if "noise" in keyval: noise = keyval["noise"] if "chisq" in keyval: maxchisq = keyval["chisq"] for arg in ["deg"]: 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 = {0:1000., 1:1000., 2:1000., 3:1000.} # iterate over each possible order for order in chisq: args["deg"] = order pfit = np.polyfit(**args) if len(pfit) == 1: numpar = 1 else: # find the number of free parameters # note that if a coefficient is << the max coefficient # it is not considered a free parameter as it has very little affect on the fit numpar = 0 mxpar = max(abs(pfit)) for i in range(len(pfit)): if abs(mxpar/pfit[i]) < 1000.: numpar += 1 fit = np.polyval(pfit,self.x) chisq[order] = (stats.reducedchisquared(self.y, fit, numpar, noise), numpar) # find the base fit, based on number of free parameters and chisq mv = 1000. order = 0 for k in chisq: if chisq[k][0] < mv and (mv - chisq[k][0]) / mv > 0.2: mv = chisq[k][0] order = k if mv > maxchisq: logging.warning("No good fit for continuum found") return None args["deg"] = mv logging.info("Using polynomial fit of order %i with chi^2 of %f" % (order, mv)) # do the final fit pfit = np.polyfit(**args) fit = np.polyval(pfit,self.x) else: # do the fit with the given parameters pfit = ma.polyfit(**args) fit = np.polyval(pfit,self.x) return fit