ras-commander 0.48.0__py3-none-any.whl → 0.50.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/HdfPipe.py CHANGED
@@ -1,3 +1,25 @@
1
+ """
2
+ Class: HdfPipe
3
+
4
+ All of the methods in this class are static and are designed to be used without instantiation.
5
+
6
+ List of Functions in HdfPipe:
7
+ Geometry Retrieval Functions:
8
+ - get_pipe_conduits() - Get pipe conduit geometries and attributes
9
+ - get_pipe_nodes() - Get pipe node geometries and attributes
10
+ - get_pipe_network() - Get complete pipe network data
11
+ - get_pipe_profile() - Get elevation profile for a specific conduit
12
+ - extract_pipe_network_data() - Extract both nodes and conduits data
13
+
14
+ Results Retrieval Functions:
15
+ - get_pipe_network_timeseries() - Get timeseries data for pipe network variables
16
+ - get_pipe_network_summary() - Get summary statistics for pipe networks
17
+ - get_pipe_node_timeseries() - Get timeseries data for a specific node
18
+ - get_pipe_conduit_timeseries() - Get timeseries data for a specific conduit
19
+
20
+ Note: All functions use the @standardize_input decorator to validate input paths
21
+ and the @log_call decorator for logging function calls.
22
+ """
1
23
  import h5py
2
24
  import numpy as np
3
25
  import pandas as pd
@@ -17,23 +39,33 @@ logger = get_logger(__name__)
17
39
 
18
40
  class HdfPipe:
19
41
  """
20
- A class for handling pipe network related data from HEC-RAS HDF files.
21
- """
42
+ Static methods for handling pipe network data from HEC-RAS HDF files.
43
+
44
+ Contains methods for:
45
+ - Geometry retrieval (nodes, conduits, networks, profiles)
46
+ - Results retrieval (timeseries and summary data)
22
47
 
48
+ All methods use @standardize_input for path validation and @log_call
49
+ """
23
50
 
51
+ # Geometry Retrieval Functions
52
+
24
53
  @staticmethod
25
54
  @log_call
26
55
  @standardize_input(file_type='plan_hdf')
27
56
  def get_pipe_conduits(hdf_path: Path, crs: Optional[str] = "EPSG:4326") -> gpd.GeoDataFrame:
28
57
  """
29
- Combines hdf5 datasets from /Geometry/Pipe Conduits/ into a single GeoDataFrame.
58
+ Extracts pipe conduit geometries and attributes from HDF5 file.
30
59
 
31
60
  Parameters:
32
- - hdf_path: Path to the HDF5 file.
33
- - crs: Coordinate Reference System for the GeoDataFrame. Default is "EPSG:4326".
61
+ hdf_path: Path to the HDF5 file
62
+ crs: Coordinate Reference System (default: "EPSG:4326")
34
63
 
35
64
  Returns:
36
- - A GeoDataFrame with attributes, Polyline geometries, and Terrain Profiles as separate columns.
65
+ GeoDataFrame with columns:
66
+ - Attributes from HDF5
67
+ - Polyline: LineString geometries
68
+ - Terrain_Profiles: List of (station, elevation) tuples
37
69
  """
38
70
  with h5py.File(hdf_path, 'r') as f:
39
71
  group = f['/Geometry/Pipe Conduits/']
@@ -136,15 +168,19 @@ class HdfPipe:
136
168
  @standardize_input(file_type='plan_hdf')
137
169
  def get_pipe_network(hdf_path: Path, pipe_network_name: Optional[str] = None, crs: Optional[str] = "EPSG:4326") -> gpd.GeoDataFrame:
138
170
  """
139
- Creates a GeoDataFrame for a specified pipe network from an HDF5 file.
140
-
171
+ Creates a GeoDataFrame for a pipe network's geometry.
172
+
141
173
  Parameters:
142
- - hdf_path: Path to the HDF5 file.
143
- - pipe_network_name: Name of the pipe network to extract. If None, the first network is used.
144
- - crs: Coordinate Reference System for the GeoDataFrame. Default is "EPSG:4326".
145
-
174
+ hdf_path: Path to the HDF5 file
175
+ pipe_network_name: Name of network (uses first if None)
176
+ crs: Coordinate Reference System (default: "EPSG:4326")
177
+
146
178
  Returns:
147
- - A GeoDataFrame containing cell polygons, face polylines, node points, and their associated attributes.
179
+ GeoDataFrame containing:
180
+ - Cell polygons (primary geometry)
181
+ - Face polylines
182
+ - Node points
183
+ - Associated attributes
148
184
  """
149
185
  with h5py.File(hdf_path, 'r') as f:
150
186
  pipe_networks_group = f['/Geometry/Pipe Networks/']
@@ -451,63 +487,56 @@ class HdfPipe:
451
487
 
452
488
 
453
489
 
490
+
454
491
  @staticmethod
455
492
  @log_call
456
493
  @standardize_input(file_type='plan_hdf')
457
- def get_pipe_network_timeseries(hdf_path: Path, variable: str) -> xr.DataArray:
494
+ def get_pipe_profile(hdf_path: Path, conduit_id: int) -> pd.DataFrame:
458
495
  """
459
- Extract timeseries data for a specific variable in the pipe network.
496
+ Extract the profile data for a specific pipe conduit.
460
497
 
461
498
  Args:
462
499
  hdf_path (Path): Path to the HDF file.
463
- variable (str): Variable to extract (e.g., "Cell Courant", "Cell Water Surface").
500
+ conduit_id (int): ID of the conduit to extract profile for.
464
501
 
465
502
  Returns:
466
- xr.DataArray: DataArray containing the timeseries data.
503
+ pd.DataFrame: DataFrame containing the pipe profile data.
467
504
 
468
505
  Raises:
469
506
  KeyError: If the required datasets are not found in the HDF file.
470
- ValueError: If an invalid variable is specified.
507
+ IndexError: If the specified conduit_id is out of range.
471
508
  """
472
- valid_variables = [
473
- "Cell Courant", "Cell Water Surface", "Face Flow", "Face Velocity",
474
- "Face Water Surface", "Pipes/Pipe Flow DS", "Pipes/Pipe Flow US",
475
- "Pipes/Vel DS", "Pipes/Vel US", "Nodes/Depth", "Nodes/Drop Inlet Flow",
476
- "Nodes/Water Surface"
477
- ]
478
-
479
- if variable not in valid_variables:
480
- raise ValueError(f"Invalid variable. Must be one of: {', '.join(valid_variables)}")
481
-
482
509
  try:
483
510
  with h5py.File(hdf_path, 'r') as hdf:
484
- # Extract timeseries data
485
- data_path = f"/Results/Unsteady/Output/Output Blocks/DSS Hydrograph Output/Unsteady Time Series/Pipe Networks/Davis/{variable}"
486
- data = hdf[data_path][()]
511
+ # Get conduit info
512
+ terrain_profiles_info = hdf['/Geometry/Pipe Conduits/Terrain Profiles Info'][()]
513
+
514
+ if conduit_id >= len(terrain_profiles_info):
515
+ raise IndexError(f"conduit_id {conduit_id} is out of range")
487
516
 
488
- # Extract time information
489
- time = HdfBase._get_unsteady_datetimes(hdf)
517
+ start, count = terrain_profiles_info[conduit_id]
490
518
 
491
- # Create DataArray
492
- da = xr.DataArray(
493
- data=data,
494
- dims=['time', 'location'],
495
- coords={'time': time, 'location': range(data.shape[1])},
496
- name=variable
497
- )
519
+ # Extract profile data
520
+ profile_values = hdf['/Geometry/Pipe Conduits/Terrain Profiles Values'][start:start+count]
498
521
 
499
- # Add attributes
500
- da.attrs['units'] = hdf[data_path].attrs.get('Units', b'').decode('utf-8')
501
- da.attrs['variable'] = variable
522
+ # Create DataFrame
523
+ df = pd.DataFrame(profile_values, columns=['Station', 'Elevation'])
502
524
 
503
- return da
525
+ return df
504
526
 
505
527
  except KeyError as e:
506
528
  logger.error(f"Required dataset not found in HDF file: {e}")
507
529
  raise
530
+ except IndexError as e:
531
+ logger.error(f"Invalid conduit_id: {e}")
532
+ raise
508
533
  except Exception as e:
509
- logger.error(f"Error extracting pipe network timeseries data: {e}")
534
+ logger.error(f"Error extracting pipe profile data: {e}")
510
535
  raise
536
+
537
+
538
+
539
+
511
540
 
512
541
 
513
542
 
@@ -516,13 +545,14 @@ class HdfPipe:
516
545
 
517
546
 
518
547
 
548
+ # RESULTS FUNCTIONS:
519
549
 
520
550
  @staticmethod
521
551
  @log_call
522
552
  @standardize_input(file_type='plan_hdf')
523
553
  def get_pipe_network_summary(hdf_path: Path) -> pd.DataFrame:
524
554
  """
525
- Extract summary data for pipe networks from the HDF file.
555
+ Extract results summary data for pipe networks from the HDF file.
526
556
 
527
557
  Args:
528
558
  hdf_path (Path): Path to the HDF file.
@@ -558,123 +588,8 @@ class HdfPipe:
558
588
  logger.error(f"Error extracting pipe network summary data: {e}")
559
589
  raise
560
590
 
561
- @staticmethod
562
- @log_call
563
- @standardize_input(file_type='plan_hdf')
564
- def get_pipe_profile(hdf_path: Path, conduit_id: int) -> pd.DataFrame:
565
- """
566
- Extract the profile data for a specific pipe conduit.
567
591
 
568
- Args:
569
- hdf_path (Path): Path to the HDF file.
570
- conduit_id (int): ID of the conduit to extract profile for.
571
592
 
572
- Returns:
573
- pd.DataFrame: DataFrame containing the pipe profile data.
574
-
575
- Raises:
576
- KeyError: If the required datasets are not found in the HDF file.
577
- IndexError: If the specified conduit_id is out of range.
578
- """
579
- try:
580
- with h5py.File(hdf_path, 'r') as hdf:
581
- # Get conduit info
582
- terrain_profiles_info = hdf['/Geometry/Pipe Conduits/Terrain Profiles Info'][()]
583
-
584
- if conduit_id >= len(terrain_profiles_info):
585
- raise IndexError(f"conduit_id {conduit_id} is out of range")
586
-
587
- start, count = terrain_profiles_info[conduit_id]
588
-
589
- # Extract profile data
590
- profile_values = hdf['/Geometry/Pipe Conduits/Terrain Profiles Values'][start:start+count]
591
-
592
- # Create DataFrame
593
- df = pd.DataFrame(profile_values, columns=['Station', 'Elevation'])
594
-
595
- return df
596
-
597
- except KeyError as e:
598
- logger.error(f"Required dataset not found in HDF file: {e}")
599
- raise
600
- except IndexError as e:
601
- logger.error(f"Invalid conduit_id: {e}")
602
- raise
603
- except Exception as e:
604
- logger.error(f"Error extracting pipe profile data: {e}")
605
- raise
606
-
607
-
608
- # New functions from the AWS webinar where the code was developed
609
- # Some of these may be duplicative of the above, always use the above
610
-
611
- @staticmethod
612
- @log_call
613
- @standardize_input(file_type='plan_hdf')
614
- def extract_wsel_for_cell(plan_hdf_path: Path, cell_id: int) -> Dict[str, Any]:
615
- """
616
- Extract water surface elevation time series for a specific 2D cell.
617
-
618
- Parameters:
619
- -----------
620
- plan_hdf_path : Path
621
- Path to HEC-RAS results HDF file
622
- cell_id : int
623
- ID of the cell to extract data for
624
-
625
- Returns:
626
- --------
627
- Dict containing:
628
- 'time_values': array of time values
629
- 'wsel_timeseries': water surface elevation time series
630
- 'peak_value': maximum water surface elevation
631
- 'peak_time': time of maximum water surface elevation
632
- """
633
- try:
634
- cells_timeseries_ds = HdfResultsMesh.mesh_cells_timeseries_output(plan_hdf_path)
635
- water_surface = cells_timeseries_ds['area2']['Water Surface']
636
- time_values = water_surface.coords['time'].values
637
- wsel_timeseries = water_surface.sel(cell_id=cell_id)
638
-
639
- peak_value = wsel_timeseries.max().item()
640
- peak_index = wsel_timeseries.argmax().item()
641
-
642
- return {
643
- 'time_values': time_values,
644
- 'wsel_timeseries': wsel_timeseries,
645
- 'peak_value': peak_value,
646
- 'peak_time': time_values[peak_index]
647
- }
648
- except Exception as e:
649
- logger.error(f"Error extracting water surface elevation for cell {cell_id}: {str(e)}")
650
- raise
651
-
652
- @staticmethod
653
- @log_call
654
- @standardize_input(file_type='plan_hdf')
655
- def extract_pipe_network_data(plan_hdf_path: Path) -> Tuple[gpd.GeoDataFrame, gpd.GeoDataFrame]:
656
- """
657
- Extract pipe nodes and conduits data from HEC-RAS results.
658
-
659
- Parameters:
660
- -----------
661
- plan_hdf_path : Path
662
- Path to HEC-RAS results HDF file
663
-
664
- Returns:
665
- --------
666
- Tuple[GeoDataFrame, GeoDataFrame]:
667
- First GeoDataFrame contains pipe nodes data
668
- Second GeoDataFrame contains pipe conduits data
669
- """
670
- try:
671
- pipe_nodes_gdf = HdfPipe.get_pipe_nodes(plan_hdf_path)
672
- pipe_conduits_gdf = HdfPipe.get_pipe_conduits(plan_hdf_path)
673
-
674
- return pipe_nodes_gdf, pipe_conduits_gdf
675
- except Exception as e:
676
- logger.error(f"Error extracting pipe network data: {str(e)}")
677
- raise
678
593
 
679
594
  @staticmethod
680
595
  @log_call
@@ -744,28 +659,65 @@ class HdfPipe:
744
659
  logger.error(f"Error extracting time series data for conduit {conduit_id}: {str(e)}")
745
660
  raise
746
661
 
662
+
747
663
  @staticmethod
748
664
  @log_call
749
665
  @standardize_input(file_type='plan_hdf')
750
- def get_pipe_profile(plan_hdf_path: Path, conduit_id: int) -> pd.DataFrame:
666
+ def get_pipe_network_timeseries(hdf_path: Path, variable: str) -> xr.DataArray:
751
667
  """
752
- Get profile data for a specific pipe conduit.
753
-
668
+ Extracts timeseries data for a pipe network variable.
669
+
754
670
  Parameters:
755
- -----------
756
- plan_hdf_path : Path
757
- Path to HEC-RAS results HDF file
758
- conduit_id : int
759
- ID of the conduit to get profile for
760
-
671
+ hdf_path: Path to the HDF5 file
672
+ variable: Variable name to extract. Valid options:
673
+ - Cell: Courant, Water Surface
674
+ - Face: Flow, Velocity, Water Surface
675
+ - Pipes: Pipe Flow (DS/US), Vel (DS/US)
676
+ - Nodes: Depth, Drop Inlet Flow, Water Surface
677
+
761
678
  Returns:
762
- --------
763
- pd.DataFrame: DataFrame containing station and elevation data
679
+ xarray.DataArray with dimensions (time, location)
764
680
  """
681
+ valid_variables = [
682
+ "Cell Courant", "Cell Water Surface", "Face Flow", "Face Velocity",
683
+ "Face Water Surface", "Pipes/Pipe Flow DS", "Pipes/Pipe Flow US",
684
+ "Pipes/Vel DS", "Pipes/Vel US", "Nodes/Depth", "Nodes/Drop Inlet Flow",
685
+ "Nodes/Water Surface"
686
+ ]
687
+
688
+ if variable not in valid_variables:
689
+ raise ValueError(f"Invalid variable. Must be one of: {', '.join(valid_variables)}")
690
+
765
691
  try:
766
- pipe_profile_df = HdfPipe.get_pipe_profile(plan_hdf_path, conduit_id)
767
- return pipe_profile_df
692
+ with h5py.File(hdf_path, 'r') as hdf:
693
+ # Extract timeseries data
694
+ data_path = f"/Results/Unsteady/Output/Output Blocks/DSS Hydrograph Output/Unsteady Time Series/Pipe Networks/Davis/{variable}"
695
+ data = hdf[data_path][()]
696
+
697
+ # Extract time information using the correct method name
698
+ time = HdfBase.get_unsteady_timestamps(hdf)
699
+
700
+ # Create DataArray
701
+ da = xr.DataArray(
702
+ data=data,
703
+ dims=['time', 'location'],
704
+ coords={'time': time, 'location': range(data.shape[1])},
705
+ name=variable
706
+ )
707
+
708
+ # Add attributes
709
+ da.attrs['units'] = hdf[data_path].attrs.get('Units', b'').decode('utf-8')
710
+ da.attrs['variable'] = variable
711
+
712
+ return da
713
+
714
+ except KeyError as e:
715
+ logger.error(f"Required dataset not found in HDF file: {e}")
716
+ raise
768
717
  except Exception as e:
769
- logger.error(f"Error getting pipe profile for conduit {conduit_id}: {str(e)}")
718
+ logger.error(f"Error extracting pipe network timeseries data: {e}")
770
719
  raise
771
720
 
721
+
722
+
723
+