Source code for finesse.utilities.polyfit

"""Functions for fitting polynomials."""

import numpy as np


[docs]def polyfit2d_index(kx, a, b): """Returns index of polynomial from the result of :meth:`polyfit2d` for :math:`x^{a} y^{b}`. Parameters ---------- kx : int X polynomial order computed a, b : int x and y polynomial order """ return b + ((kx + 1) * a)
[docs]def polyfit2d_eval(x, y, soln, kx, ky): """Evaluate polynomial fit from :meth:`polyfit2d` Parameters ---------- x, y: array-like, 1d x and y coordinates. soln: np.ndarray Array of polynomial coefficients. kx, ky: int Polynomial order in x and y, respectively. """ return np.polynomial.polynomial.polygrid2d(x, y, soln.reshape((kx + 1, ky + 1)))
[docs]def polyfit2d_indices(kx, ky): """Get indicies of polynomials returned by :meth:`polyfit2d`. Parameters ---------- kx, ky: int Polynomial order in x and y, respectively. Returns ------- indices : array_like Array of x^a y^b powers """ coeffs = np.ones((kx + 1, ky + 1)) return np.array(tuple(np.ndindex(coeffs.shape)), dtype=int)
[docs]def polyfit2d(x, y, z, kx, ky, *, order=None, weights=None): """Two dimensional polynomial fitting by least squares. Fits the functional form f(x,y) = z. Parameters ---------- x, y: array-like, 1d x and y coordinates. z: np.ndarray, 2d Surface to fit. kx, ky: int Polynomial order in x and y, respectively. order: int or None If None, all coefficients up to maxiumum kx, ky, ie. up to and including x^kx*y^ky, are considered. If int, coefficients up to a maximum of kx+ky <= order are considered. weight: array_like, 2d Weighting to use for fit. Same dimenstions as z Returns ------- Return parameters from np.linalg.lstsq. soln: np.ndarray Array of polynomial coefficients. residuals: np.ndarray rank: int s: np.ndarray Notes ----- Resultant fit can be evaluated with :meth:`polyfit2d_eval`. Based on code from: https://stackoverflow.com/questions/33964913/equivalent-of-polyfit-for-a-2d-polynomial-in-python """ # grid coords x, y = np.meshgrid(x, y) # coefficient array, up to x^kx, y^ky coeffs = np.ones((kx + 1, ky + 1)) # solve array a = np.zeros((coeffs.size, x.size)) b = np.ravel(z) # for each coefficient produce array x^i, y^j for index, (j, i) in enumerate(np.ndindex(coeffs.shape)): # do not include powers greater than order if order is not None and i + j > order: arr = np.zeros_like(x) else: arr = coeffs[i, j] * x ** i * y ** j a[index] = arr.ravel() if weights is not None: W = np.sqrt(weights).ravel() a *= W b *= W # do leastsq fitting and return leastsq result return np.linalg.lstsq(a.T, b, rcond=None)