ras-commander 0.52.0__py3-none-any.whl → 0.53.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 +137 -127
- ras_commander/HdfBase.py +21 -6
- ras_commander/HdfFluvialPluvial.py +553 -553
- ras_commander/HdfResultsPlan.py +192 -84
- ras_commander/HdfStruc.py +1 -1
- ras_commander/HdfXsec.py +2 -2
- ras_commander/LoggingConfig.py +2 -1
- ras_commander/RasCmdr.py +45 -20
- ras_commander/RasPlan.py +74 -65
- ras_commander/RasPrj.py +934 -917
- ras_commander/RasUnsteady.py +38 -19
- {ras_commander-0.52.0.dist-info → ras_commander-0.53.0.dist-info}/METADATA +92 -49
- {ras_commander-0.52.0.dist-info → ras_commander-0.53.0.dist-info}/RECORD +16 -16
- {ras_commander-0.52.0.dist-info → ras_commander-0.53.0.dist-info}/WHEEL +1 -1
- {ras_commander-0.52.0.dist-info → ras_commander-0.53.0.dist-info}/LICENSE +0 -0
- {ras_commander-0.52.0.dist-info → ras_commander-0.53.0.dist-info}/top_level.txt +0 -0
ras_commander/RasPlan.py
CHANGED
@@ -249,7 +249,6 @@ class RasPlan:
|
|
249
249
|
def _update_unsteady_in_file(lines, new_unsteady_flow_number):
|
250
250
|
return [f"Unsteady File=u{new_unsteady_flow_number}\n" if line.startswith("Unsteady File=u") else line for line in lines]
|
251
251
|
|
252
|
-
|
253
252
|
@staticmethod
|
254
253
|
@log_call
|
255
254
|
def set_num_cores(plan_number, num_cores, ras_object=None):
|
@@ -264,6 +263,16 @@ class RasPlan:
|
|
264
263
|
Returns:
|
265
264
|
None
|
266
265
|
|
266
|
+
Number of cores is controlled by the following parameters in the plan file corresponding to 1D, 2D, Pipe Systems and Pump Stations:
|
267
|
+
UNET D1 Cores=
|
268
|
+
UNET D2 Cores=
|
269
|
+
PS Cores=
|
270
|
+
|
271
|
+
Where a value of "0" is used for "All Available" cores, and values of 1 or more are used to specify the number of cores to use.
|
272
|
+
For complex 1D/2D models with pipe systems, a more complex approach may be needed to optimize performance. (Suggest writing a custom function based on this code).
|
273
|
+
This function simply sets the "num_cores" parameter for ALL instances of the above parameters in the plan file.
|
274
|
+
|
275
|
+
|
267
276
|
Notes on setting num_cores in HEC-RAS:
|
268
277
|
The recommended setting for num_cores is 2 (most efficient) to 8 (most performant)
|
269
278
|
More details in the HEC-Commander Repository Blog "Benchmarking is All You Need"
|
@@ -290,9 +299,9 @@ class RasPlan:
|
|
290
299
|
def update_num_cores(lines):
|
291
300
|
updated_lines = []
|
292
301
|
for line in lines:
|
293
|
-
if "UNET D1 Cores="
|
294
|
-
|
295
|
-
updated_lines.append(f"{
|
302
|
+
if any(param in line for param in ["UNET D1 Cores=", "UNET D2 Cores=", "PS Cores="]):
|
303
|
+
param_name = line.split("=")[0]
|
304
|
+
updated_lines.append(f"{param_name}= {num_cores}\n")
|
296
305
|
else:
|
297
306
|
updated_lines.append(line)
|
298
307
|
return updated_lines
|
@@ -840,7 +849,7 @@ class RasPlan:
|
|
840
849
|
- 'Plan File' (str): Name of the plan file
|
841
850
|
- 'Plan Title' (str): Title of the simulation plan
|
842
851
|
- 'Program Version' (str): Version number of HEC-RAS
|
843
|
-
- 'Run
|
852
|
+
- 'Run HTab' (int): Flag to run HTab module (-1 or 1)
|
844
853
|
- 'Run Post Process' (int): Flag to run post-processing (-1 or 1)
|
845
854
|
- 'Run Sediment' (int): Flag to run sediment transport module (0 or 1)
|
846
855
|
- 'Run UNET' (int): Flag to run unsteady network module (-1 or 1)
|
@@ -848,13 +857,14 @@ class RasPlan:
|
|
848
857
|
- 'Short Identifier' (str): Short name or ID for the plan
|
849
858
|
- 'Simulation Date' (str): Start and end dates/times for simulation
|
850
859
|
- 'UNET D1 Cores' (int): Number of cores used in 1D calculations
|
860
|
+
- 'UNET D2 Cores' (int): Number of cores used in 2D calculations
|
861
|
+
- 'PS Cores' (int): Number of cores used in parallel simulation
|
851
862
|
- 'UNET Use Existing IB Tables' (int): Flag for using existing internal boundary tables (-1, 0, or 1)
|
852
863
|
- 'UNET 1D Methodology' (str): 1D calculation methodology
|
853
864
|
- 'UNET D2 Solver Type' (str): 2D solver type
|
854
865
|
- 'UNET D2 Name' (str): Name of the 2D area
|
855
866
|
- 'Run RASMapper' (int): Flag to run RASMapper for floodplain mapping (-1 for off, 0 for on)
|
856
867
|
|
857
|
-
|
858
868
|
Note:
|
859
869
|
Writing Multi line keys like 'Description' are not supported by this function.
|
860
870
|
|
@@ -868,9 +878,10 @@ class RasPlan:
|
|
868
878
|
supported_plan_keys = {
|
869
879
|
'Description', 'Computation Interval', 'DSS File', 'Flow File', 'Friction Slope Method',
|
870
880
|
'Geom File', 'Mapping Interval', 'Plan File', 'Plan Title', 'Program Version',
|
871
|
-
'Run
|
872
|
-
'Short Identifier', 'Simulation Date', 'UNET D1 Cores', 'UNET
|
873
|
-
'UNET
|
881
|
+
'Run HTab', 'Run Post Process', 'Run Sediment', 'Run UNET', 'Run WQNET',
|
882
|
+
'Short Identifier', 'Simulation Date', 'UNET D1 Cores', 'UNET D2 Cores', 'PS Cores',
|
883
|
+
'UNET Use Existing IB Tables', 'UNET 1D Methodology', 'UNET D2 Solver Type',
|
884
|
+
'UNET D2 Name', 'Run RASMapper', 'Run HTab', 'Run UNET'
|
874
885
|
}
|
875
886
|
|
876
887
|
if key not in supported_plan_keys:
|
@@ -891,7 +902,23 @@ class RasPlan:
|
|
891
902
|
logger.error(f"Error reading plan file {plan_file_path}: {e}")
|
892
903
|
raise
|
893
904
|
|
894
|
-
|
905
|
+
# Handle core settings specially to convert to integers
|
906
|
+
core_keys = {'UNET D1 Cores', 'UNET D2 Cores', 'PS Cores'}
|
907
|
+
if key in core_keys:
|
908
|
+
pattern = f"{key}=(.*)"
|
909
|
+
match = re.search(pattern, content)
|
910
|
+
if match:
|
911
|
+
try:
|
912
|
+
return int(match.group(1).strip())
|
913
|
+
except ValueError:
|
914
|
+
logger = logging.getLogger(__name__)
|
915
|
+
logger.error(f"Could not convert {key} value to integer")
|
916
|
+
return None
|
917
|
+
else:
|
918
|
+
logger = logging.getLogger(__name__)
|
919
|
+
logger.error(f"Key '{key}' not found in the plan file.")
|
920
|
+
return None
|
921
|
+
elif key == 'Description':
|
895
922
|
match = re.search(r'Begin DESCRIPTION(.*?)END DESCRIPTION', content, re.DOTALL)
|
896
923
|
return match.group(1).strip() if match else None
|
897
924
|
else:
|
@@ -1060,81 +1087,63 @@ class RasPlan:
|
|
1060
1087
|
@log_call
|
1061
1088
|
def update_plan_description(plan_number_or_path: Union[str, Path], description: str, ras_object: Optional['RasPrj'] = None) -> None:
|
1062
1089
|
"""
|
1063
|
-
Update the description in
|
1090
|
+
Update the description block in a HEC-RAS plan file.
|
1064
1091
|
|
1065
1092
|
Args:
|
1066
|
-
plan_number_or_path (Union[str, Path]): The plan number or path to the plan file
|
1067
|
-
description (str): The new description
|
1068
|
-
ras_object (Optional[RasPrj]):
|
1093
|
+
plan_number_or_path (Union[str, Path]): The plan number or full path to the plan file
|
1094
|
+
description (str): The new description text to set
|
1095
|
+
ras_object (Optional[RasPrj]): Specific RAS object to use. If None, uses the global ras instance.
|
1069
1096
|
|
1070
1097
|
Raises:
|
1071
|
-
ValueError: If the plan file is not found
|
1072
|
-
IOError: If there's an error reading
|
1098
|
+
ValueError: If the plan file is not found
|
1099
|
+
IOError: If there's an error reading or writing the plan file
|
1073
1100
|
"""
|
1074
|
-
logger =
|
1101
|
+
logger = get_logger(__name__)
|
1102
|
+
ras_obj = ras_object or ras
|
1103
|
+
ras_obj.check_initialized()
|
1075
1104
|
|
1076
1105
|
plan_file_path = Path(plan_number_or_path)
|
1077
1106
|
if not plan_file_path.is_file():
|
1078
|
-
plan_file_path =
|
1079
|
-
if
|
1107
|
+
plan_file_path = RasUtils.get_plan_path(plan_number_or_path, ras_object)
|
1108
|
+
if not plan_file_path.exists():
|
1109
|
+
logger.error(f"Plan file not found: {plan_file_path}")
|
1080
1110
|
raise ValueError(f"Plan file not found: {plan_file_path}")
|
1081
1111
|
|
1082
1112
|
try:
|
1083
1113
|
with open(plan_file_path, 'r') as file:
|
1084
|
-
|
1085
|
-
except IOError as e:
|
1086
|
-
logger.error(f"Error reading plan file {plan_file_path}: {e}")
|
1087
|
-
raise
|
1114
|
+
content = file.read()
|
1088
1115
|
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
if
|
1094
|
-
|
1095
|
-
|
1096
|
-
end_index = i
|
1097
|
-
elif line.strip().startswith("Computation Interval="):
|
1098
|
-
comp_interval_index = i
|
1099
|
-
|
1100
|
-
if start_index is not None and end_index is not None:
|
1101
|
-
# Description exists, update it
|
1102
|
-
new_lines = lines[:start_index + 1]
|
1103
|
-
if description:
|
1104
|
-
new_lines.extend(description.split('\n'))
|
1105
|
-
else:
|
1106
|
-
new_lines.append('\n')
|
1107
|
-
new_lines.extend(lines[end_index:])
|
1108
|
-
else:
|
1109
|
-
# Description doesn't exist, insert before Computation Interval
|
1110
|
-
if comp_interval_index is None:
|
1111
|
-
logger.warning("Neither description tags nor Computation Interval found in plan file. Appending to end of file.")
|
1112
|
-
comp_interval_index = len(lines)
|
1113
|
-
|
1114
|
-
new_lines = lines[:comp_interval_index]
|
1115
|
-
new_lines.append("BEGIN DESCRIPTION:\n")
|
1116
|
-
if description:
|
1117
|
-
new_lines.extend(f"{line}\n" for line in description.split('\n'))
|
1116
|
+
# Find the description block
|
1117
|
+
desc_pattern = r'Begin DESCRIPTION.*?END DESCRIPTION'
|
1118
|
+
new_desc_block = f'Begin DESCRIPTION\n{description}\nEND DESCRIPTION'
|
1119
|
+
|
1120
|
+
if re.search(desc_pattern, content, re.DOTALL):
|
1121
|
+
# Replace existing description block
|
1122
|
+
new_content = re.sub(desc_pattern, new_desc_block, content, flags=re.DOTALL)
|
1118
1123
|
else:
|
1119
|
-
|
1120
|
-
|
1121
|
-
new_lines.extend(lines[comp_interval_index:])
|
1124
|
+
# Add new description block at the start of the file
|
1125
|
+
new_content = new_desc_block + '\n' + content
|
1122
1126
|
|
1123
|
-
|
1127
|
+
# Write the updated content back to the file
|
1124
1128
|
with open(plan_file_path, 'w') as file:
|
1125
|
-
file.
|
1129
|
+
file.write(new_content)
|
1130
|
+
|
1126
1131
|
logger.info(f"Updated description in plan file: {plan_file_path}")
|
1132
|
+
|
1133
|
+
# Update the dataframes in the RAS object to reflect changes
|
1134
|
+
if ras_object:
|
1135
|
+
ras_object.plan_df = ras_object.get_plan_entries()
|
1136
|
+
ras_object.geom_df = ras_object.get_geom_entries()
|
1137
|
+
ras_object.flow_df = ras_object.get_flow_entries()
|
1138
|
+
ras_object.unsteady_df = ras_object.get_unsteady_entries()
|
1139
|
+
|
1127
1140
|
except IOError as e:
|
1128
|
-
logger.error(f"Error
|
1141
|
+
logger.error(f"Error updating plan description in {plan_file_path}: {e}")
|
1142
|
+
raise
|
1143
|
+
except Exception as e:
|
1144
|
+
logger.error(f"Unexpected error updating plan description: {e}")
|
1129
1145
|
raise
|
1130
1146
|
|
1131
|
-
# Refresh RasPrj dataframes
|
1132
|
-
if ras_object:
|
1133
|
-
ras_object.plan_df = ras_object.get_plan_entries()
|
1134
|
-
ras_object.geom_df = ras_object.get_geom_entries()
|
1135
|
-
ras_object.flow_df = ras_object.get_flow_entries()
|
1136
|
-
ras_object.unsteady_df = ras_object.get_unsteady_entries()
|
1137
|
-
|
1138
1147
|
@staticmethod
|
1139
1148
|
@log_call
|
1140
1149
|
def read_plan_description(plan_number_or_path: Union[str, Path], ras_object: Optional['RasPrj'] = None) -> str:
|