Inspecting Results and Generating Hydraulic Product Packages¶
# True uses this checkout; False uses the installed package.
import sys
from hashlib import sha256
import os
from pathlib import Path
from tempfile import mkdtemp
import pandas as pd
import pyarrow.parquet as pq
USE_LOCAL_SOURCE = False
REPO_ROOT = Path.cwd().resolve()
if REPO_ROOT.name.lower() == "examples":
REPO_ROOT = REPO_ROOT.parent
if USE_LOCAL_SOURCE:
local_path = str(REPO_ROOT)
if local_path not in sys.path:
sys.path.insert(0, local_path)
print("LOCAL SOURCE MODE")
else:
print("PIP PACKAGE MODE")
from ras_commander import HdfResultsProducts # noqa: E402
def sha256_file(path, chunk_size=1024 * 1024):
digest = sha256()
with Path(path).open("rb") as stream:
for chunk in iter(lambda: stream.read(chunk_size), b""):
digest.update(chunk)
return digest.hexdigest()
Two different operations¶
This notebook keeps reading and generation explicit:
HdfResultsProducts.inspect_result()reads an existing HEC-RAS producer HDF without changing it. Inspection checks mechanical completion and product readiness; it is not hydraulic acceptance.HdfResultsProducts.export()generates a new ras-commander derivative package containing COG, Arrow/Parquet, GeoJSON, JSON, and optional PNG assets. Those files are not HEC-RAS model output.
No HEC-RAS execution or preprocessing occurs here. The source result HDF remains read-only and is protected with before/after SHA-256 checks.
1. Select an existing producer HDF¶
Set RAS_COMMANDER_RESULT_HDF to a completed, reviewed unsteady HEC-RAS plan-result HDF with a 2D flow area. This example deliberately does not synthesize or compute a model result. Generated package files are written only under the ignored working/ folder.
result_hdf_setting = os.environ.get("RAS_COMMANDER_RESULT_HDF")
if not result_hdf_setting:
raise RuntimeError(
"Set RAS_COMMANDER_RESULT_HDF to an existing completed HEC-RAS result HDF; "
"this notebook will not generate model output."
)
RESULT_HDF = Path(result_hdf_setting).expanduser().resolve()
if not RESULT_HDF.is_file():
raise FileNotFoundError(f"Existing producer HDF not found: {RESULT_HDF}")
WORK_ROOT = REPO_ROOT / "working" / "example_417_hydraulic_products"
WORK_ROOT.mkdir(parents=True, exist_ok=True)
RUN_ROOT = Path(mkdtemp(prefix="run_", dir=WORK_ROOT))
PRODUCT_DIRECTORY = RUN_ROOT / "hydraulic-products"
source_sha_before = sha256_file(RESULT_HDF)
print(f"READING existing HEC-RAS producer HDF: {RESULT_HDF}")
print(f"GENERATED derivatives will be written under: {PRODUCT_DIRECTORY}")
2. Read and inspect the existing result¶
Inspection validates completion evidence, time axes, CRS, units, topology, and required arrays. The returned hydraulic_qaqc value remains not_evaluated; successful inspection does not approve the model or its results.
print("READING and inspecting the existing producer HDF (no files generated)...")
inspection = HdfResultsProducts.inspect_result(RESULT_HDF)
assert inspection["source"]["access"] == "read_only"
assert inspection["hydraulic_qaqc"] == "not_evaluated"
inspection_summary = pd.Series(
{
"completed successfully": inspection["completed_successfully"],
"completion evidence": ", ".join(inspection["completion_evidence"]["accepted_sources"]),
"time start": inspection["time"]["start"],
"time end": inspection["time"]["end"],
"mesh names": ", ".join(inspection["mesh_names"]),
"hydraulic QA/QC": inspection["hydraulic_qaqc"],
},
name="read-only result inspection",
)
display(inspection_summary.to_frame())
3. Generate a new derivative package¶
The output directory must not exist. export() generates bounded COG rasters, an Arrow/Parquet boundary-hydrograph table, JSON metadata and numerical evidence, a WGS84 GeoJSON footprint, and a depth preview. It publishes hydraulic-products.json last; consumers should treat a package without that manifest as incomplete.
print(f"GENERATING new ras-commander derivative products: {PRODUCT_DIRECTORY}")
manifest = HdfResultsProducts.export(
RESULT_HDF,
PRODUCT_DIRECTORY,
max_dimension=2048,
include_preview=True,
)
manifest_path = PRODUCT_DIRECTORY / HdfResultsProducts.MANIFEST_FILENAME
assert manifest_path.is_file()
assert manifest["source"]["sha256"] == source_sha_before
assert manifest["product_package"]["hec_ras_model_output_generated"] is False
assert manifest["status"]["hydraulic_qaqc"] == "not_evaluated"
print(f"Generated package-complete manifest: {manifest_path}")
4. Verify checksums and read the generated Parquet asset¶
Every manifest asset is checked independently. The boundary-hydrograph asset is then read with required pyarrow, consistent with the core Arrow/Parquet product contract.
asset_rows = []
for asset_name, asset in manifest["assets"].items():
asset_path = PRODUCT_DIRECTORY / asset["href"]
assert asset_path.is_file()
actual_sha = sha256_file(asset_path)
assert actual_sha == asset["sha256"]
asset_rows.append(
{
"asset": asset_name,
"filename": asset_path.name,
"bytes": asset_path.stat().st_size,
"sha256 verified": True,
}
)
hydrograph_asset = manifest["assets"]["hydraulic-hydrographs"]
hydrograph_table = pq.read_table(PRODUCT_DIRECTORY / hydrograph_asset["href"])
print(f"READING generated Arrow/Parquet asset: {hydrograph_asset['href']}")
print(hydrograph_table.schema)
display(pd.DataFrame(asset_rows))
5. Verify source immutability¶
The final source hash proves that inspection and derivative generation did not alter the producer HDF. This point-in-time check is an audit assertion, not a continuous file lock.
source_sha_after = sha256_file(RESULT_HDF)
assert source_sha_after == source_sha_before
print("READ-ONLY verification passed: producer HDF SHA-256 is unchanged.")
print("GENERATED package is a ras-commander derivative, not HEC-RAS model output.")
Scope and next steps¶
This core ras-commander contract is intentionally narrow: deterministic inspection and a checksum-pinned hydraulic product package. For broader cloud-native project archives, geometry/result joins, DuckDB workflows, and PMTiles publishing, see 961_cloud_native_results_export.ipynb and the external ras2cng project.
Before publishing or relying on these products, independently review completion messages, numerical evidence, units, CRS, raster resolution, source provenance, and hydraulic suitability. Mechanical readiness is not engineering acceptance.