{ "cells": [ { "cell_type": "markdown", "id": "9ade0707", "metadata": {}, "source": [ "# Wolfresults_2D & wolfres2DGPU — 2D simulation results\n", "\n", "- **`Wolfresults_2D`** — base class for WOLF2D results (CPU multi-block)\n", "- **`wolfres2DGPU`** — GPU-specific subclass (single-block, `ResultsStore`-backed)\n", "- **`OneWolfResult`** — per-block container (waterdepth, qx, qy, topography, …)\n", "- **`views_2D`** — enum of available result views\n", "\n", "### Architecture\n", "\n", "```\n", "Wolfresults_2D (or wolfres2DGPU)\n", "├── myblocks: dict[str, OneWolfResult]\n", "│ └── 'block1' -> OneWolfResult\n", "│ ├── .waterdepth (WolfArray)\n", "│ ├── .qx (WolfArray) — discharge X [m²/s]\n", "│ ├── .qy (WolfArray) — discharge Y [m²/s]\n", "│ ├── .top (WolfArray) — topography\n", "│ └── .rough_n (WolfArray) — Manning coefficient\n", "├── head_blocks: dict[str, header_wolf]\n", "├── times: list[float] — real times [s]\n", "├── current_result: int — currently loaded step (0-based)\n", "├── epsilon: float — wet/dry threshold\n", "└── mypal: wolfpalette — color palette\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "id": "47124b07", "metadata": {}, "outputs": [], "source": [ "from wolfhece.wolfresults_2D import Wolfresults_2D, views_2D, OneWolfResult\n", "from wolfhece.Results2DGPU import wolfres2DGPU\n", "from wolfhece.wolf_array import WolfArray, getkeyblock" ] }, { "cell_type": "markdown", "id": "84579381", "metadata": {}, "source": [ "## views_2D — available result views\n", "\n", "The `views_2D` enum defines all possible computed views. The most\n", "commonly used are shown below." ] }, { "cell_type": "code", "execution_count": 2, "id": "79a49032", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WATERDEPTH Water depth [m]\n", "WATERLEVEL Water level [m]\n", "TOPOGRAPHY Bottom level [m]\n", "QX Discharge X [m2s-1]\n", "QY Discharge Y [m2s-1]\n", "QNORM Discharge norm [m2s-1]\n", "UX Velocity X [ms-1]\n", "UY Velocity Y [ms-1]\n", "UNORM Velocity norm [ms-1]\n", "HEAD Head [m]\n", "FROUDE Froude [-]\n", "KINETIC_ENERGY Kinetic energy k\n", "EPSILON Rate of dissipation e\n", "TURB_VISC_2D Turbulent viscosity 2D\n", "TURB_VISC_3D Turbulent viscosity 3D\n", "VECTOR_FIELD_Q Discharge vector field\n", "VECTOR_FIELD_U Velocity vector field\n", "U_SHEAR Shear velocity [ms-1]\n", "SHIELDS_NUMBER Shields number - Manning-Strickler\n", "CRITICAL_DIAMETER_SHIELDS Critical grain diameter - Shields\n", "CRITICAL_DIAMETER_IZBACH Critical grain diameter - Izbach\n", "CRITICAL_DIAMETER_SUSPENSION_50 Critical grain diameter - Suspension 50%\n", "CRITICAL_DIAMETER_SUSPENSION_100 Critical grain diameter - Suspension 100%\n", "QNORM_FIELD Q norm + Field\n", "UNORM_FIELD U norm + Field\n", "WL_Q WL + Q\n", "WD_Q WD + Q\n", "WL_U WL + U\n", "WD_U WD + U\n", "T_WL_Q Top + WL + Q\n", "T_WD_Q Top + WD + Q\n", "T_WD_U Top + WD + U\n" ] } ], "source": [ "# List all views\n", "for v in views_2D:\n", " print(f\"{v.name:40s} {v.value}\")" ] }, { "cell_type": "markdown", "id": "82f9e06d", "metadata": {}, "source": [ "## getkeyblock — block key convention\n", "\n", "`getkeyblock(i, addone=True)` converts a 0-based Python index to a\n", "block key string:\n", "- `getkeyblock(0)` → `'block1'`\n", "- `getkeyblock(1)` → `'block2'`\n", "\n", "With `addone=False`, the number is used as-is:\n", "- `getkeyblock(1, False)` → `'block1'`" ] }, { "cell_type": "code", "execution_count": 3, "id": "f00ddde4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "getkeyblock(0) = 'block1'\n", "getkeyblock(1) = 'block2'\n", "getkeyblock(1, False) = 'block1'\n" ] } ], "source": [ "print(f\"getkeyblock(0) = '{getkeyblock(0)}'\")\n", "print(f\"getkeyblock(1) = '{getkeyblock(1)}'\")\n", "print(f\"getkeyblock(1, False) = '{getkeyblock(1, False)}'\")" ] }, { "cell_type": "markdown", "id": "310c84a2", "metadata": {}, "source": [ "## Loading GPU results with wolfres2DGPU\n", "\n", "`wolfres2DGPU` can load results from:\n", "- A **local directory** containing `parameters.json` and `simul_gpu_results/`\n", "- An **HTTP(S) URL** (triggers automatic download via `download_gpu_simulation`)\n", "- A pre-built **`ResultsStore`** (via the `store` parameter)\n", "\n", "GPU simulations are always **single-block** (`'block1'`)." ] }, { "cell_type": "code", "execution_count": 4, "id": "905d4ea3", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\NAP.npy already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\bathymetry.npy already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\bridge_roof.npy already exists. Skipping download.\n", "ERROR:root:HTTP error occurred while downloading https://gitlab.uliege.be/HECE/wolfgpu_examples/-/raw/main/channel_w_archbridge_fully_man004/bridge_deck.npy: 404 Client Error: Not Found for url: https://gitlab.uliege.be/HECE/wolfgpu_examples/-/raw/main/channel_w_archbridge_fully_man004/bridge_deck.npy\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\h.npy already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\manning.npy already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\qx.npy already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\qy.npy already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\parameters.json already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\metadata.json already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\nap.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\nb_results.txt already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\sim_times.csv already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\h_0000001.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qx_0000001.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qy_0000001.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\h_0000002.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qx_0000002.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qy_0000002.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\h_0000003.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qx_0000003.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qy_0000003.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\h_0000004.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qx_0000004.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qy_0000004.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\h_0000005.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qx_0000005.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qy_0000005.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\h_0000006.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qx_0000006.npz already exists. Skipping download.\n", "INFO:root:File C:\\Users\\pierre\\Documents\\Gitlab\\HECEPython\\wolfhece\\data\\downloads\\channel_w_archbridge_fully_man004\\simul_gpu_results\\qy_0000006.npz already exists. Skipping download.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "ResultsStore: 6 saved time steps\n", "\n", "Blocks: ['block1']\n", "Epsilon (wet/dry threshold): 0.01\n" ] } ], "source": [ "from wolfhece.pydownloader import toys_gpu_dataset, DATADIR\n", "\n", "# Download a toy GPU simulation (cached)\n", "store = toys_gpu_dataset('channel_w_archbridge_fully_man004')\n", "print(f\"ResultsStore: {store.nb_results} saved time steps\")\n", "\n", "# Load into wolfres2DGPU\n", "sim_path = DATADIR / 'channel_w_archbridge_fully_man004'\n", "sim = wolfres2DGPU(str(sim_path), eps=0.01)\n", "\n", "print(f\"\\nBlocks: {list(sim.myblocks.keys())}\")\n", "print(f\"Epsilon (wet/dry threshold): {sim.epsilon}\")" ] }, { "cell_type": "markdown", "id": "a38b37c0", "metadata": {}, "source": [ "## Querying time steps" ] }, { "cell_type": "code", "execution_count": 5, "id": "d97cf259", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of saved time steps: 6\n", "\n", "First 5 times [s]: [0.0, 40.60536419227719, 81.21073305234313, 121.81609793752432, 162.4214591383934]\n", "Last time [s]: 203.02682216465473\n" ] } ], "source": [ "nb = sim.get_nbresults()\n", "print(f\"Number of saved time steps: {nb}\")\n", "\n", "# Get all real times and calculation step numbers\n", "times = sim.times\n", "print(f\"\\nFirst 5 times [s]: {times[:5]}\")\n", "print(f\"Last time [s]: {times[-1]}\")" ] }, { "cell_type": "markdown", "id": "c2ac6301", "metadata": {}, "source": [ "## Reading a single time step\n", "\n", "`read_oneresult(which)` loads a specific saved step (0-based) into\n", "the `myblocks` arrays. Pass `-1` for the last step." ] }, { "cell_type": "code", "execution_count": 6, "id": "15b5d913", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loaded step: 5\n", "\n", "Water depth array: 500 x 21\n", " max h = 8.042 m\n", " wet cells = 8466\n", "\n", "Max |qx| = 6.845 m²/s\n", "Max |qy| = 2.085 m²/s\n" ] } ], "source": [ "# Read the last time step\n", "sim.read_oneresult(-1)\n", "print(f\"Loaded step: {sim.current_result}\")\n", "\n", "# Access the block\n", "block = sim.myblocks[getkeyblock(1, False)]\n", "\n", "# Water depth statistics\n", "h = block.waterdepth\n", "print(f\"\\nWater depth array: {h.nbx} x {h.nby}\")\n", "print(f\" max h = {h.array.max():.3f} m\")\n", "print(f\" wet cells = {h.nbnotnull}\")\n", "\n", "# Discharges\n", "print(f\"\\nMax |qx| = {abs(block.qx.array).max():.3f} m\\u00b2/s\")\n", "print(f\"Max |qy| = {abs(block.qy.array).max():.3f} m\\u00b2/s\")" ] }, { "cell_type": "markdown", "id": "171b82f1", "metadata": {}, "source": [ "## Switching views\n", "\n", "`set_currentview(views_2D.XXX)` recomputes the active display array\n", "(e.g. velocity from h and q). The result is then accessible via\n", "`as_WolfArray()`." ] }, { "cell_type": "code", "execution_count": 7, "id": "b843a8f8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Velocity norm: max = 0.856 m/s\n", "Water level: max = 8.042 m\n" ] } ], "source": [ "# Switch to velocity norm\n", "sim.set_currentview(views_2D.UNORM)\n", "v_array = sim.as_WolfArray(copyarray=True)\n", "print(f\"Velocity norm: max = {v_array.array.max():.3f} m/s\")\n", "\n", "# Switch to water level (h + topography)\n", "sim.set_currentview(views_2D.WATERLEVEL)\n", "wl_array = sim.as_WolfArray(copyarray=True)\n", "print(f\"Water level: max = {wl_array.array.max():.3f} m\")\n", "\n", "# Switch back to water depth\n", "sim.set_currentview(views_2D.WATERDEPTH)" ] }, { "cell_type": "markdown", "id": "66f9671a", "metadata": {}, "source": [ "## Exporting as WolfArray\n", "\n", "`as_WolfArray(copyarray=True)` creates a standalone `WolfArray` from\n", "the current view. This is useful for saving, plotting, or further\n", "processing." ] }, { "cell_type": "code", "execution_count": 8, "id": "eb8194ae", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Exported WolfArray: 500 x 21\n", "dx=1.0, dy=1.0\n", "Origin: (0, 0)\n", "\n", "Saved to: C:\\Users\\pierre\\AppData\\Local\\Temp\\tmptth17b7q\\waterdepth_last.bin\n" ] } ], "source": [ "# Export current view as a WolfArray\n", "wa = sim.as_WolfArray(copyarray=True)\n", "print(f\"Exported WolfArray: {wa.nbx} x {wa.nby}\")\n", "print(f\"dx={wa.dx}, dy={wa.dy}\")\n", "print(f\"Origin: ({wa.origx:.0f}, {wa.origy:.0f})\")\n", "\n", "# Save to disk\n", "import tempfile\n", "from pathlib import Path\n", "tmpdir = Path(tempfile.mkdtemp())\n", "wa.write_all(str(tmpdir / 'waterdepth_last.bin'))\n", "print(f\"\\nSaved to: {tmpdir / 'waterdepth_last.bin'}\")" ] }, { "cell_type": "markdown", "id": "7c91bcb6", "metadata": {}, "source": [ "## Topography access" ] }, { "cell_type": "code", "execution_count": 9, "id": "d4f468c2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Topography: min = 0.00 m, max = 100.00 m\n" ] } ], "source": [ "# Topography for the block\n", "top = sim.get_top_for_block(getkeyblock(1, False))\n", "print(f\"Topography: min = {top.array.min():.2f} m, max = {top.array.max():.2f} m\")" ] }, { "cell_type": "markdown", "id": "a2544bff", "metadata": {}, "source": [ "## Epsilon — wet/dry threshold\n", "\n", "The `epsilon` attribute controls which cells are considered \\\"wet\\\":\n", "- `epsilon > 0`: cells with `h < epsilon` are masked\n", "- `epsilon == 0`: only cells with `h == 0` are masked\n", "\n", "Changing epsilon and re-reading updates the mask." ] }, { "cell_type": "code", "execution_count": 10, "id": "df880ad2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Current epsilon: 0.01\n", "Wet cells (eps=0.01): 8466\n", "Wet cells (eps=0.1): 8466\n" ] } ], "source": [ "# Default epsilon\n", "print(f\"Current epsilon: {sim.epsilon}\")\n", "sim.read_oneresult(-1)\n", "wet_default = sim.myblocks[getkeyblock(1, False)].waterdepth.nbnotnull\n", "print(f\"Wet cells (eps={sim.epsilon}): {wet_default}\")\n", "\n", "# Increase epsilon to filter thin water layers\n", "sim.epsilon = 0.1\n", "sim.read_oneresult(-1)\n", "wet_filtered = sim.myblocks[getkeyblock(1, False)].waterdepth.nbnotnull\n", "print(f\"Wet cells (eps={sim.epsilon}): {wet_filtered}\")\n", "\n", "# Reset\n", "sim.epsilon = 0.01" ] }, { "cell_type": "markdown", "id": "68ec5844", "metadata": {}, "source": [ "## Iterating over time steps" ] }, { "cell_type": "code", "execution_count": 11, "id": "5c06ef47", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Time [s] Max h [m]\n", "----------------------\n", " 0.0 8.042\n", " 40.6 8.042\n", " 81.2 8.042\n", " 121.8 8.042\n", " 162.4 8.042\n", " 203.0 8.042\n" ] } ], "source": [ "# Read every 10th step and track maximum water depth\n", "import numpy as np\n", "\n", "nb = sim.get_nbresults()\n", "step_indices = range(0, nb, max(1, nb // 10)) # ~10 samples\n", "max_depths = []\n", "\n", "for i in step_indices:\n", " sim.read_oneresult(i)\n", " h_max = sim.myblocks[getkeyblock(1, False)].waterdepth.array.max()\n", " max_depths.append((sim.times[i], float(h_max)))\n", "\n", "print(f\"{'Time [s]':>10s} {'Max h [m]':>10s}\")\n", "print('-' * 22)\n", "for t, hm in max_depths:\n", " print(f\"{t:10.1f} {hm:10.3f}\")" ] }, { "cell_type": "markdown", "id": "8825b657", "metadata": {}, "source": [ "## In-memory cache (GPU only)\n", "\n", "`setup_cache()` preloads a range of results into RAM for faster\n", "repeated access. Use `only_h=True` to load only water depth and\n", "save memory." ] }, { "cell_type": "code", "execution_count": 12, "id": "7352988b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:root:Estimated memory size for one result: 0.07 MB\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Step 5 from cache: max h = 8.042 m\n", "Cache cleared\n" ] } ], "source": [ "# Cache the first 20 steps\n", "sim.setup_cache(start_idx=0, end_idx=20, only_h=True)\n", "\n", "# Reads from cache (fast)\n", "sim.read_oneresult(5)\n", "print(f\"Step 5 from cache: max h = {sim.myblocks[getkeyblock(1, False)].waterdepth.array.max():.3f} m\")\n", "\n", "# Release cache\n", "sim.clear_cache()\n", "print(\"Cache cleared\")" ] }, { "cell_type": "markdown", "id": "acfa3edc", "metadata": {}, "source": [ "## Spatial sub-region reading (GPU only)\n", "\n", "`read_oneresult_subarray()` loads only a spatial sub-region, which\n", "is faster when the full domain is large and you only need a local area.\n", "\n", "Bounds can be:\n", "- `[[xmin, xmax], [ymin, ymax]]` — list of lists\n", "- A `vector` object (uses its bounding box)\n", "- A tuple `((xmin, xmax), (ymin, ymax))`\n", "\n", "**Important:** the actual loaded region may differ slightly from the\n", "requested bounds. A safety border (default `max(dx, dy)`) is added,\n", "and world coordinates are converted to cell indices via `floor()`,\n", "so the loaded footprint is always aligned to the grid and can be\n", "a few cells larger than requested. All cells outside the sub-region\n", "are set to the null value (or left untouched if `nullify_all_outside=False`)." ] }, { "cell_type": "code", "execution_count": null, "id": "344a2cdf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Wet cells in sub-region: 412\n" ] } ], "source": [ "# Read only a sub-region\n", "block = sim.myblocks[getkeyblock(1, False)]\n", "bounds = block.waterdepth.get_bounds()\n", "xmid = (bounds[0][0] + bounds[0][1]) / 2\n", "ymid = (bounds[1][0] + bounds[1][1]) / 2\n", "\n", "# Define a small window around the center.\n", "# Note: the actually loaded region may be slightly larger than the requested\n", "# bounds because coordinates are converted to cell indices via floor(), and a\n", "# safety border (default = max(dx, dy)) is added on each side.\n", "# The data outside the loaded sub-region is set to the null value.\n", "sub_bounds = [[xmid - 50, xmid + 50],\n", " [ymid - 50, ymid + 50]]\n", "\n", "sim.read_oneresult_subarray(which=-1, bounds=sub_bounds)\n", "wet = sim.myblocks[getkeyblock(1, False)].waterdepth.nbnotnull\n", "print(f\"Wet cells in sub-region: {wet}\")" ] }, { "cell_type": "markdown", "id": "4df2fc08", "metadata": {}, "source": [ "## Danger maps\n", "\n", "Danger maps iterate over all (or a subset of) time steps and compute\n", "**maximum envelopes** and **temporal indicators**.\n", "\n", "Returns a tuple of 9 `WolfArray`:\n", "\n", "| Index | Name | Description |\n", "|-------|------|-------------|\n", "| 0 | H | Maximum water depth [m] |\n", "| 1 | U | Maximum velocity norm [m/s] |\n", "| 2 | Q | Maximum momentum norm [m\\u00b2/s] |\n", "| 3 | Z | Maximum water level [m] |\n", "| 4 | Head | Maximum total head [m] |\n", "| 5 | ToA | Time of arrival [s] |\n", "| 6 | ToM | Time of maximum [s] |\n", "| 7 | DoI | Duration of inundation [s] |\n", "| 8 | ToE | Time of ending [s] |" ] }, { "cell_type": "code", "execution_count": 14, "id": "1a0064c4", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 2/2 [00:00<00:00, 116.29it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Max water depth: 8.042 m\n", "Max velocity: 0.856 m/s\n", "Max momentum: 6.846 m²/s\n", "Max water level: 8.042 m\n", "Time of arrival: min = 203 s (excluding dry)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# Compute danger maps (using every 5th step for speed)\n", "H, U, Q, Z, Head, ToA, ToM, DoI, ToE = sim.danger_map(\n", " start=0, end=-1, every=5, hmin=0.01\n", ")\n", "\n", "print(f\"Max water depth: {H.array.max():.3f} m\")\n", "print(f\"Max velocity: {U.array.max():.3f} m/s\")\n", "print(f\"Max momentum: {Q.array.max():.3f} m\\u00b2/s\")\n", "print(f\"Max water level: {Z.array.max():.3f} m\")\n", "print(f\"Time of arrival: min = {ToA.array.min():.0f} s (excluding dry)\")" ] }, { "cell_type": "markdown", "id": "0c9611d3", "metadata": {}, "source": [ "### GPU-optimized tiled danger maps\n", "\n", "`danger_map_gpu_tiled()` operates directly on tiled GPU arrays\n", "without per-step untiling, which is significantly faster for large\n", "domains. Same return format." ] }, { "cell_type": "code", "execution_count": 15, "id": "04d892a1", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 2/2 [00:00<00:00, 420.52it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Tiled max water depth: 8.042 m\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# Tiled version (GPU only, faster)\n", "try:\n", " H2, U2, Q2, Z2, Head2, ToA2, ToM2, DoI2, ToE2 = sim.danger_map_gpu_tiled(\n", " start=0, end=-1, every=5, hmin=0.01\n", " )\n", " if H2 is not None:\n", " print(f\"Tiled max water depth: {H2.array.max():.3f} m\")\n", " else:\n", " print(\"Tile packer not available (requires wolfgpu >= 1.4.0)\")\n", "except Exception as e:\n", " print(f\"Tiled danger map not available: {e}\")" ] }, { "cell_type": "markdown", "id": "864a7af5", "metadata": {}, "source": [ "## Loading CPU results\n", "\n", "CPU simulations use `Wolfresults_2D` directly and may have\n", "**multiple blocks** (multi-domain models).\n", "\n", "```python\n", "from wolfhece.wolfresults_2D import Wolfresults_2D\n", "\n", "res = Wolfresults_2D(fname='path/to/simul')\n", "\n", "nb = res.get_nbresults()\n", "res.read_oneresult(10) # 0-based\n", "\n", "# Access blocks\n", "for key, block in res.myblocks.items():\n", " print(f\"{key}: {block.waterdepth.nbx} x {block.waterdepth.nby}\")\n", "\n", "# Multi-block export\n", "wa_mb = res.as_WolfArray(copyarray=True, force_mb=True) # WolfArrayMB\n", "```" ] }, { "cell_type": "markdown", "id": "51e324d2", "metadata": {}, "source": [ "## Loading from a URL (GPU)\n", "\n", "`wolfres2DGPU` can download a simulation directly from a URL:\n", "\n", "```python\n", "sim = wolfres2DGPU('https://gitlab.uliege.be/.../my_simulation/')\n", "```\n", "\n", "This calls `download_gpu_simulation` internally, downloads all input\n", "maps and result files to `DATADIR`, and loads the simulation." ] }, { "cell_type": "markdown", "id": "7986f880", "metadata": {}, "source": [ "## GPU metadata properties" ] }, { "cell_type": "code", "execution_count": 16, "id": "8ad47bd9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Time step series length: 6\n", "First few dt values: [0.0, 1000.0, 2000.0, 3000.0, 4000.0]\n" ] } ], "source": [ "# Access time series metadata from ResultsStore\n", "try:\n", " dt_series = sim.all_dt\n", " print(f\"Time step series length: {len(dt_series)}\")\n", " print(f\"First few dt values: {dt_series[:5]}\")\n", "except Exception as e:\n", " print(f\"Metadata not available: {e}\")" ] }, { "cell_type": "markdown", "id": "d0db8731", "metadata": {}, "source": [ "## Independent zone filtering\n", "\n", "When `to_filter_independent = True`, each `read_oneresult` call\n", "automatically keeps only the largest connected wet zone(s),\n", "removing isolated puddles." ] }, { "cell_type": "code", "execution_count": 17, "id": "b91e08e2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Wet cells without filtering: 8466\n", "Wet cells with filtering: 8466\n" ] } ], "source": [ "# Enable independent zone filtering\n", "sim.to_filter_independent = True\n", "sim.read_oneresult(-1)\n", "wet_filtered = sim.myblocks[getkeyblock(1, False)].waterdepth.nbnotnull\n", "\n", "sim.to_filter_independent = False\n", "sim.read_oneresult(-1)\n", "wet_all = sim.myblocks[getkeyblock(1, False)].waterdepth.nbnotnull\n", "\n", "print(f\"Wet cells without filtering: {wet_all}\")\n", "print(f\"Wet cells with filtering: {wet_filtered}\")" ] }, { "cell_type": "markdown", "id": "5a019f49", "metadata": {}, "source": [ "## Summary\n", "\n", "| Task | Code |\n", "|------|------|\n", "| Load GPU results | `wolfres2DGPU(path, eps=0.01)` |\n", "| Load CPU results | `Wolfresults_2D(fname=path)` |\n", "| Number of steps | `sim.get_nbresults()` |\n", "| Read a step | `sim.read_oneresult(i)` (0-based, -1=last) |\n", "| Get times | `sim.times` |\n", "| Switch view | `sim.set_currentview(views_2D.UNORM)` |\n", "| Export to WolfArray | `sim.as_WolfArray(copyarray=True)` |\n", "| Get topography | `sim.get_top_for_block(getkeyblock(1, False))` |\n", "| Set threshold | `sim.epsilon = 0.01` |\n", "| Sub-region read | `sim.read_oneresult_subarray(which, bounds)` |\n", "| Danger map | `sim.danger_map(start, end, every, hmin)` |\n", "| Tiled danger map | `sim.danger_map_gpu_tiled(start, end, every, hmin)` |\n", "| Cache results | `sim.setup_cache(start, end, only_h)` |\n", "| Filter islands | `sim.to_filter_independent = True` |\n", "\n", "See also:\n", "- [toys_dataset](toys_dataset.ipynb) — downloading example simulations\n", "- [WolfArray](wolfarray.ipynb) — array manipulation\n", "- [Synthetic dike](synthetic_dike.ipynb) — generating dike geometry" ] } ], "metadata": { "kernelspec": { "display_name": "python311", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }