ras-commander 0.48.0__py3-none-any.whl → 0.49.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ras_commander/HdfMesh.py CHANGED
@@ -1,11 +1,26 @@
1
1
  """
2
- Class: HdfMesh
3
-
4
- Attribution: A substantial amount of code in this file is sourced or derived
5
- from the https://github.com/fema-ffrd/rashdf library,
6
- released under MIT license and Copyright (c) 2024 fema-ffrd
7
-
8
- The file has been forked and modified for use in RAS Commander.
2
+ A static class for handling mesh-related operations on HEC-RAS HDF files.
3
+
4
+ This class provides static methods to extract and analyze mesh data from HEC-RAS HDF files,
5
+ including mesh area names, mesh areas, cell polygons, cell points, cell faces, and
6
+ 2D flow area attributes. No instantiation is required to use these methods.
7
+
8
+ All methods are designed to work with the mesh geometry data stored in
9
+ HEC-RAS HDF files, providing functionality to retrieve and process various aspects
10
+ of the 2D flow areas and their associated mesh structures.
11
+
12
+ List of Functions:
13
+ -----------------
14
+ get_mesh_area_names()
15
+ Returns list of 2D mesh area names
16
+ get_mesh_areas()
17
+ Returns 2D flow area perimeter polygons
18
+ mesh_cell_polygons()
19
+ Returns 2D flow mesh cell polygons
20
+ [etc...]
21
+
22
+ Each function is decorated with @standardize_input and @log_call for consistent
23
+ input handling and logging functionality.
9
24
  """
10
25
  from pathlib import Path
11
26
  import h5py
@@ -44,9 +59,9 @@ class HdfMesh:
44
59
 
45
60
  @staticmethod
46
61
  @standardize_input(file_type='plan_hdf')
47
- def mesh_area_names(hdf_path: Path) -> List[str]:
62
+ def get_mesh_area_names(hdf_path: Path) -> List[str]:
48
63
  """
49
- Return a list of the 2D mesh area names of the RAS geometry.
64
+ Return a list of the 2D mesh area names from the RAS geometry.
50
65
 
51
66
  Parameters
52
67
  ----------
@@ -56,7 +71,8 @@ class HdfMesh:
56
71
  Returns
57
72
  -------
58
73
  List[str]
59
- A list of the 2D mesh area names (str) within the RAS geometry if 2D areas exist.
74
+ A list of the 2D mesh area names within the RAS geometry.
75
+ Returns an empty list if no 2D areas exist or if there's an error.
60
76
  """
61
77
  try:
62
78
  with h5py.File(hdf_path, 'r') as hdf_file:
@@ -64,7 +80,7 @@ class HdfMesh:
64
80
  return list()
65
81
  return list(
66
82
  [
67
- HdfUtils.convert_ras_hdf_string(n.decode('utf-8')) # Decode as UTF-8
83
+ HdfUtils.convert_ras_string(n.decode('utf-8'))
68
84
  for n in hdf_file["Geometry/2D Flow Areas/Attributes"][()]["Name"]
69
85
  ]
70
86
  )
@@ -74,7 +90,7 @@ class HdfMesh:
74
90
 
75
91
  @staticmethod
76
92
  @standardize_input(file_type='geom_hdf')
77
- def mesh_areas(hdf_path: Path) -> GeoDataFrame:
93
+ def get_mesh_areas(hdf_path: Path) -> GeoDataFrame:
78
94
  """
79
95
  Return 2D flow area perimeter polygons.
80
96
 
@@ -90,7 +106,7 @@ class HdfMesh:
90
106
  """
91
107
  try:
92
108
  with h5py.File(hdf_path, 'r') as hdf_file:
93
- mesh_area_names = HdfMesh.mesh_area_names(hdf_path)
109
+ mesh_area_names = HdfMesh.get_mesh_area_names(hdf_path)
94
110
  if not mesh_area_names:
95
111
  return GeoDataFrame()
96
112
  mesh_area_polygons = [
@@ -100,7 +116,7 @@ class HdfMesh:
100
116
  return GeoDataFrame(
101
117
  {"mesh_name": mesh_area_names, "geometry": mesh_area_polygons},
102
118
  geometry="geometry",
103
- crs=HdfUtils.projection(hdf_file), # Pass the h5py.File object instead of the path
119
+ crs=HdfBase.get_projection(hdf_file),
104
120
  )
105
121
  except Exception as e:
106
122
  logger.error(f"Error reading mesh areas from {hdf_path}: {str(e)}")
@@ -108,7 +124,7 @@ class HdfMesh:
108
124
 
109
125
  @staticmethod
110
126
  @standardize_input(file_type='geom_hdf')
111
- def mesh_cell_polygons(hdf_path: Path) -> GeoDataFrame:
127
+ def get_mesh_cell_polygons(hdf_path: Path) -> GeoDataFrame:
112
128
  """
113
129
  Return 2D flow mesh cell polygons.
114
130
 
@@ -120,15 +136,19 @@ class HdfMesh:
120
136
  Returns
121
137
  -------
122
138
  GeoDataFrame
123
- A GeoDataFrame containing the 2D flow mesh cell polygons.
139
+ A GeoDataFrame containing the 2D flow mesh cell polygons with columns:
140
+ - mesh_name: name of the mesh area
141
+ - cell_id: unique identifier for each cell
142
+ - geometry: polygon geometry of the cell
143
+ Returns an empty GeoDataFrame if no 2D areas exist or if there's an error.
124
144
  """
125
145
  try:
126
146
  with h5py.File(hdf_path, 'r') as hdf_file:
127
- mesh_area_names = HdfMesh.mesh_area_names(hdf_path)
147
+ mesh_area_names = HdfMesh.get_mesh_area_names(hdf_path)
128
148
  if not mesh_area_names:
129
149
  return GeoDataFrame()
130
150
 
131
- face_gdf = HdfMesh.mesh_cell_faces(hdf_path)
151
+ face_gdf = HdfMesh.get_mesh_cell_faces(hdf_path)
132
152
 
133
153
  cell_dict = {"mesh_name": [], "cell_id": [], "geometry": []}
134
154
  for i, mesh_name in enumerate(mesh_area_names):
@@ -170,13 +190,14 @@ class HdfMesh:
170
190
  )
171
191
  )(face_id_lists)
172
192
  )
173
- return GeoDataFrame(cell_dict, geometry="geometry", crs=HdfUtils.projection(hdf_file))
193
+ return GeoDataFrame(cell_dict, geometry="geometry", crs=HdfBase.get_projection(hdf_file))
174
194
  except Exception as e:
175
195
  logger.error(f"Error reading mesh cell polygons from {hdf_path}: {str(e)}")
176
196
  return GeoDataFrame()
197
+
177
198
  @staticmethod
178
199
  @standardize_input(file_type='plan_hdf')
179
- def mesh_cell_points(hdf_path: Path) -> GeoDataFrame:
200
+ def get_mesh_cell_points(hdf_path: Path) -> GeoDataFrame:
180
201
  """
181
202
  Return 2D flow mesh cell center points.
182
203
 
@@ -192,7 +213,7 @@ class HdfMesh:
192
213
  """
193
214
  try:
194
215
  with h5py.File(hdf_path, 'r') as hdf_file:
195
- mesh_area_names = HdfMesh.mesh_area_names(hdf_path)
216
+ mesh_area_names = HdfMesh.get_mesh_area_names(hdf_path)
196
217
  if not mesh_area_names:
197
218
  return GeoDataFrame()
198
219
 
@@ -208,14 +229,14 @@ class HdfMesh:
208
229
  cell_center_coords
209
230
  )
210
231
  )
211
- return GeoDataFrame(pnt_dict, geometry="geometry", crs=HdfUtils.projection(hdf_path))
232
+ return GeoDataFrame(pnt_dict, geometry="geometry", crs=HdfBase.get_projection(hdf_path))
212
233
  except Exception as e:
213
234
  logger.error(f"Error reading mesh cell points from {hdf_path}: {str(e)}")
214
235
  return GeoDataFrame()
215
236
 
216
237
  @staticmethod
217
238
  @standardize_input(file_type='plan_hdf')
218
- def mesh_cell_faces(hdf_path: Path) -> GeoDataFrame:
239
+ def get_mesh_cell_faces(hdf_path: Path) -> GeoDataFrame:
219
240
  """
220
241
  Return 2D flow mesh cell faces.
221
242
 
@@ -231,7 +252,7 @@ class HdfMesh:
231
252
  """
232
253
  try:
233
254
  with h5py.File(hdf_path, 'r') as hdf_file:
234
- mesh_area_names = HdfMesh.mesh_area_names(hdf_path)
255
+ mesh_area_names = HdfMesh.get_mesh_area_names(hdf_path)
235
256
  if not mesh_area_names:
236
257
  return GeoDataFrame()
237
258
  face_dict = {"mesh_name": [], "face_id": [], "geometry": []}
@@ -262,14 +283,14 @@ class HdfMesh:
262
283
  )
263
284
  coordinates.append(facepoints_coordinates[pnt_b_index])
264
285
  face_dict["geometry"].append(LineString(coordinates))
265
- return GeoDataFrame(face_dict, geometry="geometry", crs=HdfUtils.projection(hdf_path))
286
+ return GeoDataFrame(face_dict, geometry="geometry", crs=HdfBase.get_projection(hdf_path))
266
287
  except Exception as e:
267
288
  self.logger.error(f"Error reading mesh cell faces from {hdf_path}: {str(e)}")
268
289
  return GeoDataFrame()
269
290
 
270
291
  @staticmethod
271
292
  @standardize_input(file_type='geom_hdf')
272
- def get_geom_2d_flow_area_attrs(hdf_path: Path) -> Dict[str, Any]:
293
+ def get_mesh_area_attributes(hdf_path: Path) -> pd.DataFrame:
273
294
  """
274
295
  Return geometry 2D flow area attributes from a HEC-RAS HDF file.
275
296
 
@@ -280,8 +301,8 @@ class HdfMesh:
280
301
 
281
302
  Returns
282
303
  -------
283
- Dict[str, Any]
284
- A dictionary containing the 2D flow area attributes.
304
+ pd.DataFrame
305
+ A DataFrame containing the 2D flow area attributes.
285
306
  """
286
307
  try:
287
308
  with h5py.File(hdf_path, 'r') as hdf_file:
@@ -293,20 +314,20 @@ class HdfMesh:
293
314
  value = d2_flow_area[name][()]
294
315
  if isinstance(value, bytes):
295
316
  value = value.decode('utf-8') # Decode as UTF-8
296
- result[name] = value
317
+ result[name] = value if not isinstance(value, bytes) else value.decode('utf-8')
297
318
  except Exception as e:
298
319
  logger.warning(f"Error converting attribute '{name}': {str(e)}")
299
- return result
320
+ return pd.DataFrame.from_dict(result, orient='index', columns=['Value'])
300
321
  else:
301
322
  logger.info("No 2D Flow Area attributes found or invalid dataset.")
302
- return {}
323
+ return pd.DataFrame() # Return an empty DataFrame
303
324
  except Exception as e:
304
325
  logger.error(f"Error reading 2D flow area attributes from {hdf_path}: {str(e)}")
305
- return {}
326
+ return pd.DataFrame() # Return an empty DataFrame
306
327
 
307
328
  @staticmethod
308
329
  @standardize_input(file_type='geom_hdf')
309
- def get_face_property_tables(hdf_path: Path) -> Dict[str, pd.DataFrame]:
330
+ def get_mesh_face_property_tables(hdf_path: Path) -> Dict[str, pd.DataFrame]:
310
331
  """
311
332
  Extract Face Property Tables for each Face in all 2D Flow Areas.
312
333
 
@@ -318,12 +339,19 @@ class HdfMesh:
318
339
  Returns
319
340
  -------
320
341
  Dict[str, pd.DataFrame]
321
- A dictionary where keys are mesh names and values are DataFrames
322
- containing the Face Property Tables for all faces in that mesh.
342
+ A dictionary where:
343
+ - keys: mesh area names (str)
344
+ - values: DataFrames with columns:
345
+ - Face ID: unique identifier for each face
346
+ - Z: elevation
347
+ - Area: face area
348
+ - Wetted Perimeter: wetted perimeter length
349
+ - Manning's n: Manning's roughness coefficient
350
+ Returns an empty dictionary if no 2D areas exist or if there's an error.
323
351
  """
324
352
  try:
325
353
  with h5py.File(hdf_path, 'r') as hdf_file:
326
- mesh_area_names = HdfMesh.mesh_area_names(hdf_path)
354
+ mesh_area_names = HdfMesh.get_mesh_area_names(hdf_path)
327
355
  if not mesh_area_names:
328
356
  return {}
329
357
 
@@ -351,3 +379,56 @@ class HdfMesh:
351
379
  except Exception as e:
352
380
  logger.error(f"Error extracting face property tables from {hdf_path}: {str(e)}")
353
381
  return {}
382
+
383
+ @staticmethod
384
+ @standardize_input(file_type='geom_hdf')
385
+ def get_mesh_cell_property_tables(hdf_path: Path) -> Dict[str, pd.DataFrame]:
386
+ """
387
+ Extract Cell Property Tables for each Cell in all 2D Flow Areas.
388
+
389
+ Parameters
390
+ ----------
391
+ hdf_path : Path
392
+ Path to the HEC-RAS geometry HDF file.
393
+
394
+ Returns
395
+ -------
396
+ Dict[str, pd.DataFrame]
397
+ A dictionary where:
398
+ - keys: mesh area names (str)
399
+ - values: DataFrames with columns:
400
+ - Cell ID: unique identifier for each cell
401
+ - Z: elevation
402
+ - Volume: cell volume
403
+ - Surface Area: cell surface area
404
+ Returns an empty dictionary if no 2D areas exist or if there's an error.
405
+ """
406
+ try:
407
+ with h5py.File(hdf_path, 'r') as hdf_file:
408
+ mesh_area_names = HdfMesh.get_mesh_area_names(hdf_path)
409
+ if not mesh_area_names:
410
+ return {}
411
+
412
+ result = {}
413
+ for mesh_name in mesh_area_names:
414
+ cell_elevation_info = hdf_file[f"Geometry/2D Flow Areas/{mesh_name}/Cells Elevation Volume Info"][()]
415
+ cell_elevation_values = hdf_file[f"Geometry/2D Flow Areas/{mesh_name}/Cells Elevation Volume Values"][()]
416
+
417
+ cell_data = []
418
+ for cell_id, (start_index, count) in enumerate(cell_elevation_info):
419
+ cell_values = cell_elevation_values[start_index:start_index+count]
420
+ for z, volume, surface_area in cell_values:
421
+ cell_data.append({
422
+ 'Cell ID': cell_id,
423
+ 'Z': str(z),
424
+ 'Volume': str(volume),
425
+ 'Surface Area': str(surface_area)
426
+ })
427
+
428
+ result[mesh_name] = pd.DataFrame(cell_data)
429
+
430
+ return result
431
+
432
+ except Exception as e:
433
+ logger.error(f"Error extracting cell property tables from {hdf_path}: {str(e)}")
434
+ return {}