Source code for ascat.array_utils

# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: Copyright (c) 2026 TU Wien
# SPDX-FileContributor: For a full list of authors, see the AUTHORS file.

"""
Lightweight, dependency-free array primitives.

These helpers depend only on :mod:`numpy` (no xarray, netCDF4 or shapely), so
they can be used by the CF layer (:mod:`ascat.cf_conversions`,
:mod:`ascat.ragged_array`) without pulling in heavier dependencies. The project
sentinel fill values live here and are recognised by
:func:`ascat.utils.mask_dtype_nans`.
"""

import numpy as np

int8_nan = np.iinfo(np.int8).min
uint8_nan = np.iinfo(np.uint8).max
int16_nan = np.iinfo(np.int16).min
uint16_nan = np.iinfo(np.uint16).max
int32_nan = np.iinfo(np.int32).min
uint32_nan = np.iinfo(np.uint32).max
int64_nan = np.iinfo(np.int64).min
uint64_nan = np.iinfo(np.uint64).max
float32_nan = -999999.
float64_nan = -999999.

dtype_to_nan = {
    np.dtype('int8'): int8_nan,
    np.dtype('uint8'): uint8_nan,
    np.dtype('int16'): int16_nan,
    np.dtype('uint16'): uint16_nan,
    np.dtype('int32'): int32_nan,
    np.dtype('uint32'): uint32_nan,
    np.dtype('int64'): int64_nan,
    np.dtype('uint64'): uint64_nan,
    np.dtype('float32'): float32_nan,
    np.dtype('float64'): float64_nan,
    np.dtype('<U1'): None,
    np.dtype('O'): None,
}


[docs] def fill_value(dtype): """ Return the fill value used to pad missing elements of a given dtype. Uses the project-wide sentinel fills from :data:`dtype_to_nan` (so they are recognised by :func:`ascat.utils.mask_dtype_nans`), and ``NaT`` for datetimes. Parameters ---------- dtype : numpy.dtype Data type. Returns ------- fill : scalar Fill value for the given dtype. """ if np.issubdtype(dtype, np.datetime64): return np.datetime64("NaT") return dtype_to_nan[dtype]
[docs] def vrange(starts, stops): """ Create concatenated ranges of integers for multiple start/stop values. Parameters ---------- starts : numpy.ndarray Starts for each range. stops : numpy.ndarray Stops for each range (same shape as starts). Returns ------- ranges : numpy.ndarray Concatenated ranges. Example ------- >>> vrange(np.array([1, 3, 4, 6]), np.array([1, 5, 7, 6])) array([3, 4, 4, 5, 6]) """ starts = np.asarray(starts) stops = np.asarray(stops) if starts.shape != stops.shape: raise ValueError("starts and stops must have the same shape") lengths = stops - starts # lengths of each range return np.repeat(stops - lengths.cumsum(), lengths) + np.arange(lengths.sum())
[docs] def pad_to_2d(var, x, y, shape): """ Scatter a 1d array into a padded 2d array. Parameters ---------- var : xarray.DataArray or numpy.ndarray 1d array to be placed into a 2d array. x : numpy.ndarray Row indices. y : numpy.ndarray Column indices. shape : tuple Shape of the output array. Returns ------- padded : numpy.ndarray 2d array, with missing elements set to the dtype fill value. """ values = getattr(var, "values", var) padded = np.full(shape, fill_value(values.dtype), dtype=values.dtype) padded[x, y] = values return padded