wolfhece.wolf_array._mb_model ============================= .. py:module:: wolfhece.wolf_array._mb_model .. autoapi-nested-parse:: WolfArrayMBModel - Data-only multi-block array class (no GUI/OpenGL dependency). For GUI support (OpenGL rendering, wx dialogs), use :class:`WolfArrayMB` from ``_mb.py``. Extracted from ``_mb.py`` to follow the same Model/GUI separation pattern as :class:`WolfArrayModel` / :class:`WolfArray`. Author: HECE - University of Liege, Pierre Archambeau Date: 2024 Copyright (c) 2024 University of Liege. All rights reserved. This script and its content are protected by copyright law. Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. Module Contents --------------- .. py:class:: WolfArrayMBModel(fname=None, mold=None, masknull=True, crop=None, whichtype=WOLF_ARRAY_MB_SINGLE, preload=True, nullvalue=0.0, srcheader=None, idx: str = '') Bases: :py:obj:`wolfhece.wolf_array._base.WolfArrayModel` .. autoapi-inheritance-diagram:: wolfhece.wolf_array._mb_model.WolfArrayMBModel :parts: 1 :private-bases: Data-only multi-block array class (no GUI/OpenGL dependency). A multi-block array is composed of several independent rectangular blocks (each a :class:`WolfArrayModel`) stored in the :attr:`myblocks` dictionary, keyed by block identifiers produced by :func:`getkeyblock`. The global header (:class:`header_wolf`) describes the bounding box that encloses all blocks. Individual block headers are kept in :attr:`head_blocks` (inherited from :class:`header_wolf`). For GUI support (OpenGL rendering, wx dialogs, palette management), use :class:`WolfArrayMB` from ``_mb.py``. :ivar myblocks: Dictionary mapping block keys to :class:`WolfArrayModel` instances. Keys are produced by :func:`getkeyblock`. :ivar _active_blocks: Number of currently active blocks (0 = all). :ivar mngselection: Selection manager (:class:`SelectionDataMB`). .. py:attribute:: myblocks :type: dict[str, wolfhece.wolf_array._base.WolfArrayModel] .. py:attribute:: mngselection .. py:attribute:: _active_blocks :value: 0 .. py:method:: make_multiblocks(others: list, abs: bool = True, copy: bool = True) -> WolfArrayMBModel :classmethod: Merge several single-block arrays into a new multi-block array. The global header is recomputed from the bounding box of all blocks. :param others: List of :class:`WolfArrayModel` instances to merge. :param abs: If ``True``, use global (absolute) world coordinates. :param copy: If ``True``, copy data from each source array. Set to ``False`` only if the source headers **can** be modified in place (saves memory). :return: A new :class:`WolfArrayMBModel` containing all blocks. .. py:property:: zmin :type: float Minimum unmasked value across all blocks. .. py:property:: zmax :type: float Maximum unmasked value across all blocks. .. py:property:: zmin_global :type: float Minimum value across all blocks (including masked cells). .. py:property:: zmax_global :type: float Maximum value across all blocks (including masked cells). .. py:property:: nullvalue :type: float No-data / null value shared by all blocks. .. py:method:: add_block(arr: wolfhece.wolf_array._base.WolfArrayModel, force_idx: bool = False, copyarray=False) Add a block to this multi-block array. After adding all blocks, call :meth:`set_header_from_added_blocks` to recompute the global header. :param arr: The block to add. :param force_idx: If ``True``, the block key is set automatically based on the current number of blocks. If ``False``, the key must already be set on *arr*. :param copyarray: If ``True``, a deep copy of *arr* is stored instead of the original reference. :raises AssertionError: If *force_idx* is ``False`` and the key on *arr* is missing, duplicated, or out of sequence. .. py:method:: count() Count the number of unmasked (non-null) cells across all blocks. The result is stored in :attr:`nbnotnull` (total) and in each block's ``nbnotnull`` attribute. .. py:method:: check_consistency(other) Check that *other* has the same block structure as *self*. Two multi-block arrays are consistent if they have the same number of blocks and each pair of corresponding blocks has identical spatial headers. :param other: Another :class:`WolfArrayMBModel` to compare. :return: ``True`` if the structures match. :rtype: bool .. py:method:: allocate_ressources() Allocate memory for every block defined in :attr:`head_blocks`. Creates :class:`WolfArrayModel` instances for each block header if :attr:`myblocks` is empty. Does nothing if blocks are already populated. .. py:method:: set_header_from_added_blocks() Recompute the global header from the bounding box of all blocks. Must be called after the last :meth:`add_block` call. Updates :attr:`origx`, :attr:`origy`, :attr:`dx`, :attr:`dy` and the per-block sub-headers in :attr:`head_blocks`. .. py:method:: reset() Reset every block's data to its null value. .. py:method:: read_data() Read binary block data from :attr:`filename`. One :class:`WolfArrayModel` is created per block header and its binary payload is read sequentially from the file. .. py:method:: write_array() Write the raw binary data of every block to :attr:`filename`. Blocks are written sequentially in index order. .. py:method:: check_bounds_ij(i: int, j: int, which_block: int = 1) Check whether indices *(i, j)* fall inside the global bounds. Converts indices to world coordinates via :meth:`get_xy_from_ij` and delegates to :meth:`check_bounds_xy`. :param i: Column index (0-based). :param j: Row index (0-based). :param which_block: 1-based block index used for the coordinate conversion. :return: ``True`` if the resulting coordinates are inside the global bounding box. :rtype: bool .. py:method:: check_bounds_xy(x: float, y: float) Check whether world coordinates *(x, y)* are inside the global bounding box. :param x: X world coordinate. :param y: Y world coordinate. :return: ``True`` if inside bounds. :rtype: bool .. py:method:: get_ij_from_xy(x: float, y: float, z: float = 0.0, scale: float = 1.0, aswolf: bool = False, abs: bool = True, which_block: int = 1) Return cell indices *(i, j)* for the given world coordinates. Delegates to the single-block :meth:`WolfArrayModel.get_ij_from_xy` of block *which_block*. :param x: X world coordinate. :param y: Y world coordinate. :param z: Z coordinate (unused, kept for compatibility). :param scale: Scale factor applied before conversion. :param aswolf: If ``True``, return 1-based (Fortran) indices. :param abs: If ``True``, account for translation. :param which_block: 1-based block index. :return: Tuple *(i, j)*. .. py:method:: get_xy_from_ij(i: int, j: int, which_block: int = 1, aswolf: bool = False, abs: bool = True) Return world coordinates *(x, y)* for cell indices *(i, j)*. Delegates to the single-block :meth:`WolfArrayModel.get_xy_from_ij` of block *which_block*. :param i: Column index. :param j: Row index. :param which_block: 1-based block index. :param aswolf: If ``True``, indices are 1-based (Fortran). :param abs: If ``True``, account for translation. :return: Tuple *(x, y)*. .. py:method:: get_value(x: float, y: float, abs: bool = True, nullvalue: float = -99999, convert_to_float: bool = True) Read the value at world coordinate *(x, y)*. Iterates through all blocks and returns the first unmasked value found. If no block covers the coordinate, *nullvalue* is returned. :param x: X world coordinate. :param y: Y world coordinate. :param abs: If ``True``, account for translation. :param nullvalue: Value returned when no block covers *(x, y)*. :param convert_to_float: If ``True``, cast the result to Python ``float`` before returning. :return: Cell value, or *nullvalue* if not found. .. py:method:: get_values_as_wolf(i: int, j: int, which_block: int = 1) Return the value at 1-based Fortran indices *(i, j)*. :param i: 1-based column index. :param j: 1-based row index. :param which_block: 1-based block index. :return: Cell value or ``np.nan`` if out of bounds. .. py:method:: get_blockij_from_xy(x: float, y: float, abs: bool = True) Find which block covers the world coordinate *(x, y)*. :param x: X world coordinate. :param y: Y world coordinate. :param abs: If ``True``, account for translation. :return: Tuple *(i, j, k)* where *i* and *j* are the 0-based cell indices within block *k* (1-based block index). Returns ``(-1, -1, -1)`` if no block covers the coordinate. .. py:method:: _make_result_array() Create an empty result array of the same type. Subclasses override to return their own type (e.g. :class:`WolfArrayMB`). :return: A new :class:`WolfArrayMBModel` with the same header. .. py:method:: _make_block_op(op, curblock, other_block) Apply a binary operator between two blocks (or a block and a scalar). :param op: Operator string: ``'+'``, ``'-'``, ``'*'``, ``'/'``, or ``'**'``. :param curblock: Left operand (:class:`WolfArrayModel`). :param other_block: Right operand (:class:`WolfArrayModel` or scalar). :return: A new :class:`WolfArrayModel` with the result. .. py:method:: _apply_op(other, op: str) Generic element-wise arithmetic on multi-block arrays. Handles both *WolfArrayMBModel + WolfArrayMBModel* and *WolfArrayMBModel + scalar* cases. :param other: Another :class:`WolfArrayMBModel` (same structure) or a ``float`` scalar. :param op: Operator string (``'+'``, ``'-'``, etc.). :return: A new multi-block array with the result, or ``None`` on inconsistency. .. py:method:: mask_data(value) Mask cells whose data equals *value* in every block. For integer array types the value is cast to ``int`` first. Handles ``NaN`` comparisons correctly. :param value: The value to mask. ``None`` is a no-op. .. py:method:: mask_reset() Reset the mask of every block to ``False`` (all cells unmasked). .. py:method:: mask_lower(value) Mask cells whose value is strictly less than *value*. :param value: Threshold value. .. py:method:: mask_lowerequal(value) Mask cells whose value is less than or equal to *value*. :param value: Threshold value. .. py:method:: mask_greater(value) Mask cells whose value is strictly greater than *value*. :param value: Threshold value. .. py:method:: mask_greaterequal(value) Mask cells whose value is greater than or equal to *value*. :param value: Threshold value. .. py:method:: mask_union(source: WolfArrayMBModel) Compute the mask union (logical AND) with another multi-block array. The intersection of masked regions is applied block by block. :param source: Another :class:`WolfArrayMBModel` with the same block structure. .. py:method:: copy_mask(source: WolfArrayMBModel, forcenullvalue: bool = False) Copy the mask from *source* to *self*, block by block. :param source: Source :class:`WolfArrayMBModel` whose mask is copied. :param forcenullvalue: If ``True``, also set masked cells to the null value. .. py:method:: interpolate_on_polygon(working_vector: wolfhece.PyVertexvectors.vector, method: Literal['nearest', 'linear', 'cubic'] = 'linear', keep: Literal['all', 'below', 'above'] = 'all') Interpolate elevation values under a polygon for every block. For each block, cells inside the polygon (or the current selection if one exists) are filled with values interpolated from the 3-D vertices of *working_vector* using :func:`scipy.interpolate.griddata`. :param working_vector: Polygon whose 3-D vertices provide the interpolation source. :param method: Interpolation method (``'nearest'``, ``'linear'``, or ``'cubic'``). :param keep: Which interpolated values to keep: ``'all'``, ``'below'`` (only values lower than existing), or ``'above'``. .. py:method:: interpolate_on_polygons(working_zone: wolfhece.PyVertexvectors.zone, method: Literal['nearest', 'linear', 'cubic'] = 'linear', keep: Literal['all', 'below', 'above'] = 'all') Interpolate elevation values under every polygon in a zone. Calls :meth:`interpolate_on_polygon` for each vector in *working_zone*. :param working_zone: Zone containing one or more polygon vectors. :param method: Interpolation method. :param keep: Which interpolated values to keep. .. py:method:: interpolate_on_polyline(working_vector: wolfhece.PyVertexvectors.vector, usemask=True) Interpolate elevation values under a polyline for every block. Cells under the polyline are filled with values interpolated along the 3-D vertices of *working_vector* using Shapely's ``line.interpolate()``. :param working_vector: Polyline whose 3-D vertices provide the interpolation source. :param usemask: If ``True``, only consider unmasked cells. .. py:method:: interpolate_on_polylines(working_zone: wolfhece.PyVertexvectors.zone, usemask=True) Interpolate elevation values under every polyline in a zone. Calls :meth:`interpolate_on_polyline` for each vector in *working_zone*. :param working_zone: Zone containing one or more polyline vectors. :param usemask: If ``True``, only consider unmasked cells. .. py:method:: filter_zone(set_null: bool = False) Filter zones, keeping only those that contain selected cells. Applied independently to every block. :param set_null: If ``True``, set filtered-out cells to the null value instead of just masking them. .. py:method:: labelling() Label connected components in every block using SciPy. Each block is labelled independently via :func:`scipy.ndimage.label`. .. py:method:: as_WolfArray(abs: bool = True, forced_header: wolfhece.wolf_array._header_wolf.header_wolf = None) -> wolfhece.wolf_array._base.WolfArrayModel Convert to a single-block :class:`WolfArrayModel`. When blocks have different resolutions, the finer blocks are preserved and coarser blocks are rebinned to match the finest resolution. :param abs: If ``True``, use absolute coordinates (translation included). :param forced_header: If provided, override the target header instead of computing it from blocks. :return: A new single-block :class:`WolfArrayModel`.