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/Decorators.py +18 -1
- ras_commander/HdfBase.py +307 -197
- ras_commander/HdfBndry.py +94 -287
- ras_commander/HdfFluvialPluvial.py +155 -247
- ras_commander/HdfInfiltration.py +410 -0
- ras_commander/HdfMesh.py +117 -36
- ras_commander/HdfPipe.py +127 -175
- ras_commander/HdfPlan.py +144 -58
- ras_commander/HdfPlot.py +104 -0
- ras_commander/HdfPump.py +76 -28
- ras_commander/HdfResultsMesh.py +186 -167
- ras_commander/HdfResultsPlan.py +76 -220
- ras_commander/HdfResultsPlot.py +182 -0
- ras_commander/HdfResultsXsec.py +185 -145
- ras_commander/HdfStruc.py +65 -35
- ras_commander/HdfUtils.py +435 -518
- ras_commander/HdfXsec.py +137 -127
- ras_commander/RasCmdr.py +13 -0
- ras_commander/RasExamples.py +14 -0
- ras_commander/RasGeo.py +11 -0
- ras_commander/RasGpt.py +8 -0
- ras_commander/RasMapper.py +105 -0
- ras_commander/RasPlan.py +30 -0
- ras_commander/RasPrj.py +34 -0
- ras_commander/RasToGo.py +16 -0
- ras_commander/RasUnsteady.py +15 -0
- ras_commander/RasUtils.py +31 -0
- ras_commander/__init__.py +10 -0
- {ras_commander-0.48.0.dist-info → ras_commander-0.49.0.dist-info}/METADATA +73 -8
- ras_commander-0.49.0.dist-info/RECORD +34 -0
- ras_commander-0.48.0.dist-info/RECORD +0 -30
- {ras_commander-0.48.0.dist-info → ras_commander-0.49.0.dist-info}/LICENSE +0 -0
- {ras_commander-0.48.0.dist-info → ras_commander-0.49.0.dist-info}/WHEEL +0 -0
- {ras_commander-0.48.0.dist-info → ras_commander-0.49.0.dist-info}/top_level.txt +0 -0
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
|
-
|
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
|
-
|
58
|
+
Extracts pipe conduit geometries and attributes from HDF5 file.
|
30
59
|
|
31
60
|
Parameters:
|
32
|
-
|
33
|
-
|
61
|
+
hdf_path: Path to the HDF5 file
|
62
|
+
crs: Coordinate Reference System (default: "EPSG:4326")
|
34
63
|
|
35
64
|
Returns:
|
36
|
-
|
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
|
140
|
-
|
171
|
+
Creates a GeoDataFrame for a pipe network's geometry.
|
172
|
+
|
141
173
|
Parameters:
|
142
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
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
|
494
|
+
def get_pipe_profile(hdf_path: Path, conduit_id: int) -> pd.DataFrame:
|
458
495
|
"""
|
459
|
-
Extract
|
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
|
-
|
500
|
+
conduit_id (int): ID of the conduit to extract profile for.
|
464
501
|
|
465
502
|
Returns:
|
466
|
-
|
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
|
-
|
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
|
-
#
|
485
|
-
|
486
|
-
|
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
|
-
|
489
|
-
time = HdfBase._get_unsteady_datetimes(hdf)
|
517
|
+
start, count = terrain_profiles_info[conduit_id]
|
490
518
|
|
491
|
-
#
|
492
|
-
|
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
|
-
#
|
500
|
-
|
501
|
-
da.attrs['variable'] = variable
|
522
|
+
# Create DataFrame
|
523
|
+
df = pd.DataFrame(profile_values, columns=['Station', 'Elevation'])
|
502
524
|
|
503
|
-
return
|
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
|
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
|
666
|
+
def get_pipe_network_timeseries(hdf_path: Path, variable: str) -> xr.DataArray:
|
751
667
|
"""
|
752
|
-
|
753
|
-
|
668
|
+
Extracts timeseries data for a pipe network variable.
|
669
|
+
|
754
670
|
Parameters:
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
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
|
-
|
767
|
-
|
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
|
718
|
+
logger.error(f"Error extracting pipe network timeseries data: {e}")
|
770
719
|
raise
|
771
720
|
|
721
|
+
|
722
|
+
|
723
|
+
|