Linux/Wine Setup for Result Mapping¶
The ras2cng map command uses RasStoreMapHelper.exe (bundled with
ras-commander) to generate result rasters. Terrain HDF creation uses
RasProcess.exe from HEC-RAS. Both Windows components run under
Wine on Linux.
Do not substitute RasProcess.exe StoreAllMaps for the bundled map helper.
RasProcess does not preserve the required stored-map interpolation/render mode.
The helper sets that mode through RASMapper before generating maps.
This guide covers setting up Wine + RasProcess.exe on Ubuntu Linux.
Tested Configuration¶
| Component | Version |
|---|---|
| Linux | Debian 13 (Trixie), isolated Proxmox LXC |
| Wine | 11.0 (winehq-stable) |
| .NET Framework | 4.8 (via winetricks) |
| Python | 3.12 |
| Windows HEC-RAS payload | 7.0.1 |
| Qualification fixture | Muncie p03, EPSG:2965 |
The qualified Muncie WSE, depth, and velocity rasters matched the Windows HEC-RAS 7.0.1 golden pixel-for-pixel, including dimensions, CRS, transform, nodata, and source pixel hashes.
Prerequisites¶
- Ubuntu 22.04+ or Debian 12+
- x86_64 architecture
- Access to the complete Windows HEC-RAS installation for the exact version being qualified
- One writable Wine prefix and one writable project copy per task
Step 1: Install Wine¶
# Enable 32-bit architecture (required for Wine)
sudo dpkg --add-architecture i386
sudo apt-get update
# Install dependencies
sudo apt-get install -y wget gnupg2 software-properties-common
# Add WineHQ repository (Ubuntu 24.04 / Noble)
sudo wget -qO- https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add -
sudo add-apt-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ noble main'
sudo apt-get update
# Install Wine stable
sudo apt-get install -y --install-recommends winehq-stable winetricks
Verify:
Step 2: Initialize Wine Prefix¶
Build a read-only template prefix once, then copy it to node-local storage for every task. Never initialize or share one writable prefix concurrently.
Wine needs a one-time initialization to create its prefix. On headless servers, suppress GUI dialogs:
On a desktop Ubuntu installation with a display server, you can simply run:
Headless flags explained
DISPLAY=(empty) — prevents Wine from trying to open X11 windowsWINEDEBUG=-all— suppresses verbose debug outputWINEDLLOVERRIDES="mscoree,mshtml="— skips Mono/Gecko install prompts that would hang
If wineboot hangs, use a timeout:
Step 3: Install .NET Framework 4.8¶
RasProcess.exe is a .NET Framework 4.x application:
This downloads and installs .NET Framework 4.8 inside the Wine prefix. It takes several minutes and may produce warning messages — these are generally safe to ignore as long as the process completes.
Step 4: Copy HEC-RAS Files¶
From a Windows machine with HEC-RAS installed, copy the complete installation directory. Do not mix DLLs or executables from different versions. For HEC-RAS 7.0.1, the source is normally:
Required files and directories¶
| Path | Contents | Why needed |
|---|---|---|
*.dll |
Managed .NET assemblies (RasMapperLib.dll, etc.) | Core application dependencies |
*.exe |
RasProcess.exe, Ras.exe, etc. | The executables |
GDAL/ |
GDAL native binaries | Raster I/O and spatial operations |
bin32/ |
32-bit native DLLs (hdf5.dll, szip.dll, zlib.dll) | HDF5 file access (32-bit) |
bin64/ |
64-bit native DLLs (hdf5.dll, szip.dll, zlib.dll) | HDF5 file access (64-bit) |
x64/ |
64-bit HDF5 native libraries | HDF5 PInvoke bindings |
Missing native DLLs cause silent crashes
If you only copy the managed .dll files without the bin32/, bin64/, and x64/ directories, RasProcess will crash with:
These directories contain the native HDF5 C libraries that the .NET wrapper (HDF.PInvoke.dll) loads at runtime via P/Invoke.
Copying via SCP¶
# Create destination directory
sudo mkdir -p /opt/ras2cng-data/ras701
# Copy the contents, not a nested 7.0.1 directory
scp -r user@windows-host:"C:/Program Files (x86)/HEC/HEC-RAS/7.0.1/." /opt/ras2cng-data/ras701/
# Verify that GDAL, x64, bin64, and bin32 were preserved when present.
Expected directory layout¶
/opt/ras2cng-data/ras701/
├── RasProcess.exe
├── Ras.exe
├── RasMapperLib.dll
├── HDF.PInvoke.dll
├── ... (all other .dll/.exe files)
├── GDAL/
├── bin32/
├── bin64/
└── x64/
Step 5: Reject Unsafe CPU Topology¶
Run this check inside the scheduler/container namespace that will launch Wine:
import os
reported = int(os.sysconf("SC_NPROCESSORS_ONLN"))
allowed = sorted(os.sched_getaffinity(0))
invalid = [cpu for cpu in allowed if cpu >= reported]
if invalid:
raise SystemExit(
f"Unsafe Wine CPU namespace: reported={reported}, "
f"allowed={allowed}, invalid={invalid}"
)
Wine can report a processor count while returning raw Linux CPU IDs. A sparse
cpuset such as 2,5-7 with a reported count of four can therefore produce CLR
0x80131506, access violations, or non-returning RASMapper calls.
Prefer a coherent zero-based visible CPU namespace and apply a CPU-time quota.
If the scheduler cannot provide that topology, pin the complete Wine process
tree to one allowed CPU whose ID is lower than reported. taskset cannot
renumber CPU IDs. Do not widen the scheduler allocation.
The ras-commander source distribution includes the full JSON preflight at
.claude/skills/hecras-setup-linux-wine-ras2cng/scripts/headless_wine_preflight.py.
Step 6: Verify the Wine Runtime¶
# Basic test — should print a usage message:
DISPLAY= WINEDEBUG=-all wine /opt/ras2cng-data/ras701/RasProcess.exe
# Expected: "We really need a usage dialogue once this gets to be more solid."
# CreateTerrain — shows usage for terrain HDF creation:
DISPLAY= WINEDEBUG=-all wine /opt/ras2cng-data/ras701/RasProcess.exe CreateTerrain
# Expected: Usage text showing CreateTerrain arguments
# Verify ras-commander sees the prefix, .NET, RasProcess, and HDF libraries:
python - <<'PY'
from ras_commander import RasProcess
RasProcess.configure_wine(
wine_prefix="/opt/hecras-prefix-template",
ras_install_dir="/opt/ras2cng-data/ras701",
)
print(RasProcess.check_wine_environment())
PY
Step 7: Provision TCU State Safely¶
Never let a generic dialog watchdog click the first button on an unknown modal.
RasTcu.status() is read-only. If the operator already accepted the same
installed HEC-RAS version and authorizes reuse, run Windows Python inside the
target Wine prefix and use the donor-based RasTcu.accept() flow, or initialize
with accept_tcu=True. If no accepted donor state exists, stop and report it.
Step 8: Install ras2cng¶
# Install uv (Python package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone and install ras2cng
git clone https://github.com/gpt-cmdr/ras2cng.git
cd ras2cng
uv sync --all-extras
# Verify
uv run ras2cng --help
uv run pytest tests/ -v
Usage¶
Generate result rasters¶
# Generate depth, WSE, and velocity rasters for all plans
ras2cng map /path/to/project /output/maps \
--rasprocess /opt/ras2cng-data/ras701 \
--map-workers 1 --depth --wse --velocity --fail-fast
# Generate only depth rasters for a specific plan
ras2cng map /path/to/project /output/maps \
--rasprocess /opt/ras2cng-data/ras701 \
--map-workers 1 \
--depth --no-wse --no-velocity \
--plans p01
# Specify render mode (horizontal, sloping, or slopingPretty)
ras2cng map /path/to/project /output/maps \
--rasprocess /opt/ras2cng-data/ras701 \
--map-workers 1 \
--render-mode sloping
# Custom timeout (default: 3 hours)
ras2cng map /path/to/project /output/maps \
--rasprocess /opt/ras2cng-data/ras701 \
--map-workers 1 \
--timeout 7200
Consolidate terrain¶
# Merge all terrain TIFFs into a single file
ras2cng terrain /path/to/project /output/terrain \
--ras-version 6.6 \
--tiff-only
# With downsampling (half resolution)
ras2cng terrain /path/to/project /output/terrain \
--ras-version 6.6 \
--downsample 2.0 \
--tiff-only
Full-project archive with mapping¶
ras2cng archive /path/to/project /output/archive \
--results \
--terrain \
--map \
--consolidate-terrain \
--rasprocess /opt/ras2cng-data/ras701 \
--render-mode horizontal
Python API¶
from ras2cng.mapping import generate_result_maps
from ras2cng.terrain import consolidate_terrain, discover_terrains
# Generate result rasters
results = generate_result_maps(
"/path/to/project",
"/output/maps",
rasprocess_path="/opt/ras2cng-data/ras701",
depth=True, wse=True, velocity=True,
render_mode="horizontal", # or "sloping", "slopingPretty"
)
# Discover terrains in a project
terrains = discover_terrains("/path/to/project")
for t in terrains:
print(f"{t.name}: {len(t.tif_files)} TIFs, HDF exists: {t.hdf_exists}")
# Consolidate terrain TIFFs
merged = consolidate_terrain(
"/path/to/project",
"/output/terrain",
terrain_name="Consolidated",
create_hdf=False,
)
configure_wine expects a directory
When using the Python API directly, RasProcess.configure_wine() takes ras_install_dir= (the directory containing RasProcess.exe), not the full path to the executable. The CLI --rasprocess flag accepts either and extracts the parent directory automatically.
Prefix and Project Isolation¶
Keep one active RASMapper helper per Wine prefix. A controlled same-prefix
parallel test stalled, while separate prefixes completed concurrently with
exact golden raster hashes. ras2cng therefore uses --map-workers 1 under
Wine. Scale with scheduler arrays that each receive:
- one copied writable prefix;
- one node-local writable project copy;
- one output directory;
- no shared active HDF files.
Qualification Before Production¶
Do not qualify a runner from process exit codes alone. Compare a representative fixture to the same HEC-RAS version on Windows and record raster CRS, transform, dimensions, nodata, overlap, values, and pixel hashes. For geometry work, also record exact cell/face counts, boundary assignments, property-table completeness, and geometry/terrain fingerprints. Critical integration tests may not be skipped.
See ras-commander notebook
examples/511_headless_linux_wine_ras2cng.ipynb for the complete operational
workflow.
Timeout Considerations¶
RasProcess.exe mapping operations can be slow under Wine, especially for large models. The default timeout is 3 hours (10800 seconds) per plan. Adjust with --timeout:
# 6 hours for very large models
ras2cng map /path/to/project /output --timeout 21600
# 30 minutes for quick test runs
ras2cng map /path/to/project /output --timeout 1800
Troubleshooting¶
| Symptom | Solution |
|---|---|
wineboot hangs |
Set DISPLAY= and WINEDLLOVERRIDES="mscoree,mshtml=" |
| "Could not load assembly 'RasMapperLib'" | Copy all DLLs from HEC-RAS directory, not just RasProcess.exe |
| "HDF.PInvoke.H5F threw an exception" | Copy bin32/, bin64/, and x64/ directories from HEC-RAS install |
| Wine crashes with mmap error in LXC | Set vm.mmap_min_addr=0 on the container host |
| .NET install fails | Ensure both wine-stable-i386 and wine-stable-amd64 packages are installed |
CLR 0x80131506, 0xc0000005, or nondeterministic hang |
Run the CPU-topology preflight; repair the visible CPU namespace or use the safe single-CPU fallback |
| One of two helpers stalls | They share a writable prefix; use one prefix and project copy per task |
| Map command exits but raster differs | Use RasStoreMapHelper, not RasProcess.exe StoreAllMaps; match HEC-RAS version and render mode |
| Mapping times out | Keep --map-workers 1, verify the plan HDF, then increase --timeout |
| CRS mismatch in terrain merge | ras2cng auto-reprojects mismatched TIFs. Install pyproj for best CRS comparison |
| HEC-RAS version warnings | Non-fatal warnings from ras-commander version detection. The pipeline works if --rasprocess points to a valid RasProcess.exe |