Example #1
0
def _non_linear_legendre(wcs_dict):
    """Returns a legendre model

    Constructs a Legendre1D mathematical model

    Parameters
    ----------

    wcs_dict : dict
        Dictionary containing all the wcs information decoded from the header and
        necessary for constructing the Legendre1D model.

    Returns
    -------

        `~astropy.modeling.Model`

    """
    model = models.Legendre1D(degree=wcs_dict['order'] - 1,
                              domain=[wcs_dict['pmin'], wcs_dict['pmax']], )

    new_params = [wcs_dict['fpar'][i] for i in range(wcs_dict['order'])]
    model.parameters = new_params

    return model
Example #2
0
 def _non_linear_legendre(self):
     """Set model to Legendre1D
     """
     """Returns a legendre model"""
     self.model = models.Legendre1D(degree=self.wcs_dict['order'] - 1,
                                    domain=[self.wcs_dict['pmin'],
                                            self.wcs_dict['pmax']], )
     # self.model.parameters[0] = self.wcs_dict['pmin']
     for param_index in range(self.wcs_dict['order']):
         self.model.parameters[param_index] = self.wcs_dict['fpar'][
             param_index]
def test_iraf_non_linear_legendre(remote_data_path):

    legendre_model = models.Legendre1D(degree=3, domain=[21, 4048])
    legendre_model.c0.value = 5468.67555891
    legendre_model.c1.value = 835.332144466
    legendre_model.c2.value = -6.02202094803
    legendre_model.c3.value = -1.13142953897

    wavelength_axis = legendre_model(range(1, 4143)) * u.angstrom

    spectrum_1d = Spectrum1D.read(remote_data_path, format='iraf')

    assert isinstance(spectrum_1d, Spectrum1D)
    assert_allclose(wavelength_axis, spectrum_1d.wavelength)
Example #4
0
    def test_linear_fitter_1dlegend(self):
        """
        1 pset, 1 set 1D x, 1 set 1D y, Legendre 1D polynomial
        """

        expected = np.array([[
            1925.5000000000011, 3444.7500000000005, 1883.2500000000014,
            364.4999999999996
        ]]).T
        leg1 = models.Legendre1D(3)
        leg1.parameters = [1, 2, 3, 4]
        y1 = leg1(self.x1)
        pfit = fitting.LinearLSQFitter()
        model = pfit(leg1, self.x1, y1)
        assert_allclose(model.param_sets, expected, atol=10**(-12))
Example #5
0
    p2 = astmodels.Polynomial1D(1)
    p3 = astmodels.Polynomial1D(1)
    p4 = astmodels.Polynomial1D(1)
    m1 = p1 & p2
    m2 = p3 & p4
    m1.inverse = m2
    return m1


test_models = [
    astmodels.Identity(2),
    astmodels.Polynomial1D(2, c0=1, c1=2, c2=3),
    astmodels.Polynomial2D(1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Shift(2.),
    astmodels.Hermite1D(2, c0=2, c1=3, c2=0.5),
    astmodels.Legendre1D(2, c0=2, c1=3, c2=0.5),
    astmodels.Chebyshev1D(2, c0=2, c1=3, c2=0.5),
    astmodels.Chebyshev2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Legendre2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Hermite2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Scale(3.4),
    astmodels.RotateNative2Celestial(5.63, -72.5, 180),
    astmodels.Multiply(3),
    astmodels.Multiply(10 * u.m),
    astmodels.RotateCelestial2Native(5.63, -72.5, 180),
    astmodels.EulerAngleRotation(23, 14, 2.3, axes_order='xzx'),
    astmodels.Mapping((0, 1), n_inputs=3),
    astmodels.Shift(2. * u.deg),
    astmodels.Scale(3.4 * u.deg),
    astmodels.RotateNative2Celestial(5.63 * u.deg, -72.5 * u.deg, 180 * u.deg),
    astmodels.RotateCelestial2Native(5.63 * u.deg, -72.5 * u.deg, 180 * u.deg),
Example #6
0
    'Linear1D':
    models.Linear1D(1.0, 0.0),
    'Const1D':
    models.Const1D(0.0),
    'Redshift':
    models.Redshift(0.0),
    'Scale':
    models.Scale(1.0),
    'Shift':
    models.Shift(0.0),
    'Sine1D':
    models.Sine1D(1.0, 1.0),
    'Chebyshev1D':
    models.Chebyshev1D(1),
    'Legendre1D':
    models.Legendre1D(1),
    'Polynomial1D':
    models.Polynomial1D(1),
}


# this nightmarish way of getting the function name results from the way
# astropy functional models store them. Both their '_name' and 'name'
# attributes are set to None, and a plain, easy to use name is nowhere
# to be seen. And worse, the name coding changed  dramatically from
# astropy 0.4 to 1.0.
def getComponentName(function):
    if issubclass(function.__class__, Fittable1DModel):
        name = function.__class__()
        return _getName(name)
    elif issubclass(function.__class__, PolynomialModel):
Example #7
0
def continuum(x,
              y,
              output='ratio',
              degree=6,
              n_iterate=5,
              lower_threshold=2,
              upper_threshold=3,
              verbose=False,
              weights=None) -> Union[Iterable, tuple, Callable]:
    """
    Builds a polynomial continuum from segments of a spectrum,
    given in the form of wl and flux arrays.

    Parameters
    ----------
    x : array-like
        Independent variable
    y : array-like
        y = f(x)
    output: string
        Specifies what will be returned by the function

        'ratio'      = ratio between fitted continuum and the spectrum
        'difference' = difference between fitted continuum and the spectrum
        'function'   = continuum function evaluated at x

    degree : integer
        Degree of polynomial for the fit
    n_iterate : integer
        Number of rejection iterations
    lower_threshold : float
        Lower threshold for point rejection in units of standard
        deviation of the residuals
    upper_threshold : float
        Upper threshold for point rejection in units of standard
        deviation of the residuals
    verbose : boolean
        Prints information about the fitting
    weights : array-like
        Weights for continuum fitting. Must be the shape of x and y.

    Returns
    -------
    c : tuple

        c[0]: numpy.ndarray
            Input x coordinates
        c[1]: numpy.ndarray
            See parameter "output".

    """

    assert not np.isnan(x).all(), 'All x values are NaN.'
    assert not np.isnan(y).all(), 'All y values are NaN.'

    x_full = copy.deepcopy(x)
    # NOTE: For now, interp1d skips interpolation of NaNs.
    s = interp1d(x, y)

    if weights is None:
        weights = np.ones_like(x)

    if np.isnan(y).any():
        nan_mask = np.isnan(s(x))
        x = x[~nan_mask]
        weights = copy.deepcopy(weights)[~nan_mask]
        warnings.warn(
            'NaN values found in data! Removed {:d} out of {:d} data points.'.
            format(np.count_nonzero(nan_mask), len(x_full)),
            category=RuntimeWarning,
        )

    model = models.Legendre1D(degree=degree)
    fitter = fitting.LinearLSQFitter()

    for i in range(n_iterate):

        f = fitter(model, x, s(x), weights=weights)
        res = s(x) - f(x)
        sig = np.std(res)
        rej_cond = ((res < upper_threshold * sig) &
                    (res > -lower_threshold * sig))

        if np.sum(rej_cond) <= degree:
            if verbose:
                warnings.warn(
                    'Not enough fitting points. Stopped at iteration {:d}. sig={:.2e}'
                    .format(i, sig))
            break

        if np.sum(weights == 0.0) >= degree:
            if verbose:
                warnings.warn(
                    'Number of non-zero values in weights vector is lower than the polynomial degree. '
                    'Stopped at iteration {:d}. sig={:.2e}'.format(i, sig))
            break

        x = x[rej_cond]
        weights = weights[rej_cond]

    if verbose:
        print('Final number of points used in the fit: {:d}'.format(len(x)))
        print('Rejection ratio: {:.2f}'.format(1. - float(len(x)) /
                                               float(len(x_full))))

    p = fitter(model, x, s(x), weights=weights)

    out = dict(
        ratio=(x_full, s(x_full) / p(x_full)),
        difference=(x_full, s(x_full) - p(x_full)),
        function=(x_full, p(x_full)),
        polynomial=p,
    )

    return out[output]
Example #8
0
def rb_iter_contfit(wave, flux, error, **kwargs):
    '''
    Iterative continuum fitter using Legendre polynomials
    Input:  -
                wavelength array
                flux array 
                error array
        optional input:
                maxiter :-  maximum iteration [25 default]
                order   :-  polynomial order of fit [4 default]

    output: -
               fit_final : Final fitted continuum array
               resid_final : residual error array
               fit_error  : error on the fit [standard deviation of the residual]

    Written by:  Rongmon Bordoloi
    Tested on Python 3.7  Sep 4 2019
    --------------------------

    example :
        from IGM import rb_iter_contfit as r
        out= r.rb_iter_contfit(wave,flux,error,order=5)

        out[0] = fitted continuum
    '''

    if 'maxiter' in kwargs:
        maxiter = kwargs['maxiter']
    else:
        maxiter = 25
    if 'order' in kwargs:
        order = kwargs['order']
    else:
        order = 4

    #Initialize a mask
    mask = np.ones((np.size(wave), ))

    # Looking for chip gaps
    chip_gap = np.where(((error == 0) & (flux == 0)) | (error - flux == 0))
    if (np.size(chip_gap) > 0):
        #error[chip_gap]=1;
        #flux[chip_gap]=1;
        mask[chip_gap] = 0

    # Now get rid of negative error values
    qq = np.where(error <= 0)
    if (np.size(qq) > 0):
        error[qq] = np.median(error)

    #Do a sanity check to avoid bad flux values
    q = np.where(flux <= 0)
    if (np.size(q) > 0):
        flux[q] = error[q]

    w = 1 / error**2.  # Weight

    index = 0  #Initialize the counter
    outside_chip_gap = np.where(((error != 0) & (flux != 0))
                                | (error - flux != 0))
    med_err = np.median(error[outside_chip_gap])
    med_flux = np.median(flux[outside_chip_gap])

    # Now take out any possible emission or absorption features
    #%Flux values less than the median error are 1sigma within zero, so should be masked
    #%Try to exclude emission. anything above 2sigma over the median flux should be masked
    bd = np.where((flux < med_err))  #| (flux > (med_flux+3*med_err)))
    nbd = len(bd[0])
    if (nbd > 0):
        mask[bd] = 0
    mask = np.array(mask)
    qq = np.where(mask == 1)
    #Here I'm cutting out any chip gap or any other absorption feature. These are permanently excluded from the fit
    flux_new = flux[qq]
    wave_new = wave[qq]
    weights = np.array(w[qq])
    # Fit the data using Legedre Polynomials
    g_init = models.Legendre1D(order)
    # initialize fitters
    fit = fitting.LevMarLSQFitter()
    with warnings.catch_warnings():
        # Ignore model linearity warning from the fitter
        warnings.simplefilter('ignore')
        new_fit = fitting.FittingWithOutlierRemoval(fit,
                                                    sigma_clip,
                                                    niter=maxiter,
                                                    sigma=3.0)
        filtered_fit, filtered_data = new_fit(g_init, wave_new,
                                              flux_new)  #,weights=weights)
    ''''
    while (index < maxiter):
        print("Index="+np.str(index))
        index=index+1
        oldmask=mask
        # Fit the data using Legedre Polynomials
        g_init = models.Legendre1D(order)
        # initialize fitters
        fit = fitting.LevMarLSQFitter()
        new_fit = fitting.FittingWithOutlierRemoval(fit, sigma_clip,niter=maxiter, sigma=3.0)
        filtered_data, new_fit = new_fit(g_init, wave_new,flux_new,weights=weights)


        #fit_g = fitting.LevMarLSQFitter()
        #new_fit = fit_g(g_init, wave_new,flux_new) # Learn how to use the weights....
        cont=new_fit(wave_new)
        resid=flux_new/np.double(cont)
        #mederr=np.sqrt(scipy.stats.moment(resid,2)) #;;Use the median error to set "sigma" for the clipping. If you median is skewed, i think you're pretty much hosed
        mederr=np.std(resid)
        # Do some sigma clipping here
        median_val=np.median(resid)
        kappa=3.;  # 3 sigma clipping
        bd = np.where( (resid > (median_val+kappa*mederr)) | (resid < (median_val - mederr*kappa))) 
        gd= np.where( (resid <= (median_val+kappa*mederr)) & (resid >= (median_val - mederr*kappa))) 
        print np.size(gd)
        print np.size(bd)
        if (np.size(gd) > 0):
            mask[gd] = 1  # Allowing previously rejected points to reenter
        if (np.size(bd) > 0):
            mask[bd] = 0
 
        
        if (index >0):
            diff=oldmask-mask
            qq = np.where(diff != 0.)
            if (np.size(qq)==0):
                print index
                print "No more Clipping"
                index=maxiter # ;;mask and oldmask are identical if all elements match
        
        # Updating everything
        qq=np.where(mask==1)
        flux_new=flux[qq]
        wave_new=wave[qq]
        weights=w[qq]

    '''
    #pdb.set_trace()
    fit_final = filtered_fit(wave)
    resid_final = flux / fit_final
    fit_error = np.std(
        resid_final)  #np.sqrt(scipy.stats.moment(resid_final,2))

    return fit_final, resid_final, fit_error
Example #9
0
        # Get aperture lines
        linecat = None
        for ap in gdap:
            linecat1 = getaplines(idlines,apinfo,ap,diag=diag)
            print(ap,len(linecat1))
            if linecat is None:
                linecat = linecat1
            else:
                linecat = np.hstack((linecat,linecat1))
        nlinecat = len(linecat)
        
        # Fit 4th or 5th order polynomial plus a separate offset for each aperture

        # 1) Initial polynomial fit to all lines in all fibers
        gline, = np.where(linecat['match']==1)
        func_init = models.Legendre1D(degree=order,domain=[0,npix])
        fitter = fitting.LinearLSQFitter()
        func1 = fitter(func_init,linecat['center'][gline],linecat['wave'][gline])
        dwave1 = func1(linecat['center'][gline]) - linecat['wave'][gline]
        #coef1 = dln.poly_fit(linecat['center'][gline],linecat['wave'][gline],4)
        #dwave1 = dln.poly(linecat['center'][gline],coef1) - linecat['wave'][gline]
        sigwave1 = dln.mad(dwave1)
        print('Initial fit coefficients ',func1.parameters)
        #print('Initial fit coefficients ',coef1)        
        print('Initial sigma = %f6.2' % sigwave1)

        #xx = linecat['center'][gline]
        #yy = linecat['wave'][gline]
        #si = np.argsort(xx)
        #spl = UnivariateSpline(xx[si],yy[si],k=3,s=10)
        #dwave1 = spl(xx) - linecat['wave'][gline]