Source code for spatial_interpolators.barnes_objective

#!/usr/bin/env python
u"""
barnes_objective.py
Written by Tyler Sutterley (05/2022)

Barnes objective analysis for the optimal interpolation
of an input grid using a successive corrections scheme

CALLING SEQUENCE:
    ZI = barnes_objective(xs, ys, zs, XI, YI, XR, YR)
    ZI = barnes_objective(xs, ys, zs, XI, YI, XR, YR, RUNS=3)

INPUTS:
    xs: input X data
    ys: input Y data
    zs: input data
    XI: grid X for output ZI
    YI: grid Y for output ZI
    XR: x component of Barnes smoothing length scale
        Remains fixed throughout the iterations
    YR: y component of Barnes smoothing length scale
        Remains fixed throughout the iterations

OUTPUTS:
    ZI: interpolated grid

OPTIONS:
    runs: number of iterations

PYTHON DEPENDENCIES:
    numpy: Scientific Computing Tools For Python
        https://numpy.org

REFERENCES:
    S. L. Barnes, Applications of the Barnes objective analysis scheme.
        Part I: effects of undersampling, wave position, and station
        randomness. J. of Atmos. and Oceanic Tech., 11, 1433-1448. (1994)
    S. L. Barnes, Applications of the Barnes objective analysis scheme.
        Part II: Improving derivative estimates. J. of Atmos. and
        Oceanic Tech., 11, 1449-1458. (1994_
    S. L. Barnes, Applications of the Barnes objective analysis scheme.
        Part III: Tuning for minimum error. J. of Atmos. and Oceanic
        Tech., 11, 1459-1479. (1994)
    R. Daley, Atmospheric data analysis, Cambridge Press, New York.
        Section 3.6. (1991)

UPDATE HISTORY:
    Updated 05/2022: updated docstrings to numpy documentation format
    Updated 01/2022: added function docstrings
    Written 08/2016
"""
import numpy as np

[docs]def barnes_objective(xs, ys, zs, XI, YI, XR, YR, runs=3): """ Barnes objective analysis for the optimal interpolation of an input grid using a successive corrections scheme Parameters ---------- xs: float input x-coordinates ys: float input y-coordinates zs: float input data XI: float output x-coordinates for data grid YI: float output y-coordinates for data grid XR: float x-component of Barnes smoothing length scale YR: float y-component of Barnes smoothing length scale runs: int, default 3 number of iterations Returns ------- ZI: float interpolated data grid References ---------- .. [Barnes1994a] S. L. Barnes, "Applications of the Barnes objective analysis scheme. Part I: Effects of undersampling, wave position, and station randomness," *Journal of Atmospheric and Oceanic Technology*, 11(6), 1433--1448, (1994). .. [Barnes1994b] S. L. Barnes, "Applications of the Barnes objective analysis scheme. Part II: Improving derivative estimates," *Journal of Atmospheric and Oceanic Technology*, 11(6), 1449--1458, (1994). .. [Barnes1994c] S. L. Barnes, "Applications of the Barnes objective analysis scheme. Part III: Tuning for minimum error," *Journal of Atmospheric and Oceanic Technology*, 11(6), 1459--1479, (1994). .. [Daley1991] R. Daley, *Atmospheric data analysis*, Cambridge Press, New York. (1991). """ #-- remove singleton dimensions xs = np.squeeze(xs) ys = np.squeeze(ys) zs = np.squeeze(zs) XI = np.squeeze(XI) YI = np.squeeze(YI) #-- size of new matrix if (np.ndim(XI) == 1): nx = len(XI) else: nx,ny = np.shape(XI) #-- Check to make sure sizes of input arguments are correct and consistent if (len(zs) != len(xs)) | (len(zs) != len(ys)): raise Exception('Length of X, Y, and Z must be equal') if (np.shape(XI) != np.shape(YI)): raise Exception('Size of XI and YI must be equal') #-- square of Barnes smoothing lengths scale xr2 = XR**2 yr2 = YR**2 #-- allocate for output zp array zp = np.zeros_like(XI.flatten()) #-- first analysis for i,XY in enumerate(zip(XI.flatten(),YI.flatten())): dx = np.abs(xs - XY[0]) dy = np.abs(ys - XY[1]) #-- calculate weights w = np.exp(-dx**2/xr2 - dy**2/yr2) zp[i] = np.sum(zs*w)/sum(w) #-- allocate for even and odd zp arrays if iterating if (runs > 0): zpEven = np.zeros_like(zs) zpOdd = np.zeros_like(zs) #-- for each run for n in range(runs): #-- calculate even and odd zp arrays for j,xy in enumerate(zip(xs,ys)): dx = np.abs(xs - xy[0]) dy = np.abs(ys - xy[1]) #-- calculate weights w = np.exp(-dx**2/xr2 - dy**2/yr2) if ((n % 2) == 0):#-- even (% = modulus) zpEven[j] = zpOdd[j] + np.sum((zs - zpOdd)*w)/np.sum(w) else:#-- odd zpOdd[j] = zpEven[j] + np.sum((zs - zpEven)*w)/np.sum(w) #-- calculate zp for run n for i,XY in enumerate(zip(XI.flatten(),YI.flatten())): dx = np.abs(xs - XY[0]) dy = np.abs(ys - XY[1]) w = np.exp(-dx**2/xr2 - dy**2/yr2) if ((n % 2) == 0):#-- even (% = modulus) zp[i] = zp[i] + np.sum((zs - zpEven)*w)/np.sum(w) else:#-- odd zp[i] = zp[i] + np.sum((zs - zpOdd)*w)/np.sum(w) #-- reshape to original dimensions if (np.ndim(XI) != 1): ZI = zp.reshape(nx,ny) else: ZI = zp.copy() #-- return output matrix/array return ZI