Skip to content

Commit 2205bca

Browse files
author
Rusty Holleman
committed
Basic reading of RAS output
1 parent 066462e commit 2205bca

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

stompy/model/ras/ras.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Created on Mon Aug 26 09:47:01 2024
4+
5+
@author: rusty
6+
"""
7+
import h5py
8+
import numpy as np
9+
from ...grid import unstructured_grid
10+
11+
def ras62d_to_dataset(ras6_out_fn,area_name=None,load_full=False):
12+
"""
13+
Load RAS6-esque model output into an xarray Dataset resembling ugrid
14+
output.
15+
16+
ras6_out_fn: path to HDF5 output in RAS6-esque format.
17+
area_name: 2D area name, defaults to first area and raises exception
18+
if there are multiple areas.
19+
load_full: when False, leave HDF data lazily loaded when possible.
20+
Otherwise load all data into memory and close the HDF handle.
21+
"""
22+
ras6_grid=unstructured_grid.UnstructuredGrid.read_ras2d(ras6_out_fn,
23+
twod_area_name=area_name)
24+
25+
# Come back and get some results:
26+
ras6_h5 = h5py.File(ras6_out_fn, 'r')
27+
area_name=ras6_grid.twod_area_name # in case we're using the default.
28+
29+
ras6_ds=ras6_grid.write_to_xarray()
30+
if 'cell_z_min' in ras6_grid.cells.dtype.names:
31+
ras6_ds['bed_elev'] = ('face',),ras6_grid.cells['cell_z_min']
32+
33+
# Is this RAS6 or RAS2025?
34+
unsteady_base=('/Results/Unsteady/Output/Output Blocks/'
35+
'Base Output/Unsteady Time Series')
36+
try:
37+
ras6_h5[unsteady_base]
38+
version="RAS6"
39+
except KeyError:
40+
version="RAS2025"
41+
42+
if version=='RAS6':
43+
area_base=(unsteady_base + f'/2D Flow Areas/{area_name}/')
44+
elif version=='RAS2025':
45+
unsteady_base = '/Results/Output Blocks/Base Output'
46+
# maybe "Mesh" is actually the twod_area_name
47+
area_base = unsteady_base + f'/2D Flow Areas/Mesh/'
48+
else:
49+
raise Exception("Bad version: "+version)
50+
51+
n_nonvirtual=ras6_grid.Ncells()
52+
53+
def LD(v):
54+
if load_full:
55+
return np.asarray(v) # I think this forces a load
56+
else:
57+
return v
58+
59+
# 2025 differences:
60+
# /Results/Output Blocks/Base Output/2D Flow Areas/Mesh
61+
# grid has 1809 faces, 3903 edges.
62+
# h5 has 2185 faces.
63+
u_face=None
64+
for var_name in ras6_h5[area_base]:
65+
v=ras6_h5[area_base+var_name]
66+
67+
# Appears that names are decoded, but attribute values are
68+
# left as bytestrings.
69+
if v.attrs.get('Can Plot','n/a') != b'True':
70+
continue
71+
if v.attrs.get('Columns','n/a')==b'Cells':
72+
ras6_ds[var_name]=('time','face'),np.asanyarray(LD(v))[:,:n_nonvirtual]
73+
elif v.attrs.get('Columns','n/a')==b'Faces':
74+
data = LD(v)
75+
if data.shape[1] > ras6_ds.dims['edge']:
76+
print(f"Truncating {var_name}")
77+
data = data[:,:ras6_ds.dims['edge']]
78+
ras6_ds[var_name]=('time','edge'),data
79+
if var_name=='Face Velocity':
80+
u_face=data
81+
else:
82+
import pdb
83+
pdb.set_trace()
84+
85+
# This isn't going to scale -- will need to make the visualization
86+
# smarter.
87+
# synthesize cell center velocity -- normals may be off, though.
88+
M=ras6_grid.interp_perot_matrix()
89+
# [3618 x 3903] * [3600 x 3903].T
90+
if u_face is not None:
91+
# u_face comes in as HDF dataset -- convert to numpy to get .T
92+
# That part won't scale very well.
93+
u_face_a=np.asanyarray(u_face)
94+
UVcell=M.dot(u_face_a.T).T.reshape( [-1,n_nonvirtual,2] )
95+
ras6_ds['ucx']=('time','face'), UVcell[:,:,0]
96+
ras6_ds['ucy']=('time','face'), UVcell[:,:,1]
97+
98+
time_days=ras6_h5[unsteady_base+'/Time']
99+
ras6_ds['time']=('time',), time_days
100+
ras6_ds['time'].attrs['units']='d'
101+
try:
102+
ras6_ds['time_step']=('time',), ras6_h5[unsteady_base+'/Time Step']
103+
except KeyError:
104+
pass
105+
106+
if load_full:
107+
ras6_h5.close()
108+
ras6_ds.attrs['grid'] = ras6_grid
109+
110+
return ras6_ds

0 commit comments

Comments
 (0)