Source code for torx.analysis.csr_linear_interpolation_m

"""Linear interpolation with CSR matrices."""
import numpy as np
from scipy.sparse import csr_matrix

def _ij_to_l_index(
    x_unstructured: np.ndarray, y_unstructured: np.ndarray, x_index: int, y_index: int
) -> int:
    """Convert (i, j) x/y indices to (l) grid indices."""
    grid_index = np.where(
        np.logical_and(
            x_unstructured[x_index] == x_unstructured,
            y_unstructured[y_index] == y_unstructured,
        )
    )[0]

    if len(grid_index) == 1:
        return grid_index[0]
    elif len(grid_index) == 0:
        return -1
    else:
        raise ValueError(
            "Multiple grid_indices cannot match a single (x_index, y_index)"
        )


def _find_nearest_neighbor(
    x_unstructured: np.ndarray,
    y_unstructured: np.ndarray,
    x_query: float,
    y_query: float,
) -> int:
    """Find the nearest point to a given query point."""
    cartesian_distance = np.sqrt(
        (x_unstructured - x_query) ** 2 + (y_unstructured - y_query) ** 2
    )

    return np.argmin(cartesian_distance)


def _weightings_interpolate(
    x_unstructured: np.ndarray,
    y_unstructured: np.ndarray,
    x_query: float,
    y_query: float,
) -> tuple:
    """Return indices and weights for linear interp. on unstructured data."""
    assert x_unstructured.ndim == 1
    assert y_unstructured.ndim == 1
    assert x_unstructured.size == y_unstructured.size

    if np.any(
        [
            x_query < x_unstructured.min(),
            x_query > x_unstructured.max(),
            y_query < y_unstructured.min(),
            y_query > y_unstructured.max(),
        ]
    ):
        return 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0

    diff_x = x_query - x_unstructured
    diff_y = y_query - y_unstructured

    ix0 = np.nanargmin(np.where(diff_x >= 0, diff_x, np.nan))
    ix1 = np.nanargmax(np.where(diff_x <= 0, diff_x, np.nan))

    iy0 = np.nanargmin(np.where(diff_y >= 0, diff_y, np.nan))
    iy1 = np.nanargmax(np.where(diff_y <= 0, diff_y, np.nan))

    i00 = _ij_to_l_index(x_unstructured, y_unstructured, ix0, iy0)
    i01 = _ij_to_l_index(x_unstructured, y_unstructured, ix0, iy1)
    i10 = _ij_to_l_index(x_unstructured, y_unstructured, ix1, iy0)
    i11 = _ij_to_l_index(x_unstructured, y_unstructured, ix1, iy1)

    # If any points not found
    if np.any(np.array([i00, i01, i10, i11]) < 0):
        nearest_neighbor = _find_nearest_neighbor(
            x_unstructured, y_unstructured, x_query, y_query
        )
        # Set the interpolation weighting to take a single point value
        return nearest_neighbor, 0, 0, 0, 1.0, 0.0, 0.0, 0.0

    # Find the distance from the cell edges to the query point
    dx0 = x_query - x_unstructured[ix0]
    dy0 = y_query - y_unstructured[iy0]
    dx1 = x_unstructured[ix1] - x_query
    dy1 = y_unstructured[iy1] - y_query

    # If edge-of-grid in x-direction, collapse to nearest neighbor in x
    if ix0 == ix1:
        wx0 = 1.0
        wx1 = 0.0
    else:
        wx0 = dx1 / (dx0 + dx1)
        wx1 = dx0 / (dx0 + dx1)

    # If edge-of-grid in y-direction, collapse to nearest neighbor in y
    if iy0 == iy1:
        wy0 = 1.0
        wy1 = 0.0
    else:
        wy0 = dy1 / (dy0 + dy1)
        wy1 = dy0 / (dy0 + dy1)

    return i00, i10, i01, i11, wx0 * wy0, wx1 * wy0, wx0 * wy1, wx1 * wy1


[docs] def make_matrix_interp(x_unstructured: np.ndarray, y_unstructured: np.ndarray, x_queries: np.ndarray, y_queries: np.ndarray) -> csr_matrix: """ Return a CSR matrix for interpolation. Makes a CSR matrix which extracts the values at points defined by x_queries, y_queries. With that, matrix * unstructured_data = values at queries. """ assert x_unstructured.ndim == 1 assert y_unstructured.ndim == 1 assert x_unstructured.size == y_unstructured.size assert x_queries.ndim == 1 assert y_queries.ndim == 1 assert x_queries.size == y_queries.size nz = 0 indi = [] indj = [] val = [] # For each query, find the bilinear interpolation stencil for l in range(x_queries.size): indi.append(nz) i00, i10, i01, i11, w00, w10, w01, w11 = _weightings_interpolate( x_unstructured, y_unstructured, x_queries[l], y_queries[l] ) for index, weight in zip([i00, i10, i01, i11], [w00, w10, w01, w11]): if weight > 0.0: nz += 1 indj.append(index) val.append(weight) indi.append(nz) return csr_matrix((val, indj, indi), shape=(x_queries.size, x_unstructured.size))