ras-commander 0.21.0__py2.py3-none-any.whl → 0.22.0.dev0__py2.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/RasCommander.py +21 -12
- ras_commander/RasGeo.py +8 -3
- ras_commander/RasPlan.py +73 -23
- ras_commander/RasUnsteady.py +15 -4
- ras_commander/RasUtils.py +36 -9
- ras_commander/_version.py +16 -0
- {ras_commander-0.21.0.dist-info → ras_commander-0.22.0.dev0.dist-info}/METADATA +40 -164
- ras_commander-0.22.0.dev0.dist-info/RECORD +15 -0
- {ras_commander-0.21.0.dist-info → ras_commander-0.22.0.dev0.dist-info}/WHEEL +1 -1
- ras_commander-0.21.0.dist-info/RECORD +0 -14
- {ras_commander-0.21.0.dist-info → ras_commander-0.22.0.dev0.dist-info}/LICENSE +0 -0
- {ras_commander-0.21.0.dist-info → ras_commander-0.22.0.dev0.dist-info}/top_level.txt +0 -0
ras_commander/RasCommander.py
CHANGED
@@ -327,18 +327,27 @@ class RasCommander:
|
|
327
327
|
if dest_folder is not None:
|
328
328
|
dest_folder_path = Path(dest_folder)
|
329
329
|
if dest_folder_path.exists():
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
330
|
+
if any(dest_folder_path.iterdir()):
|
331
|
+
raise ValueError(
|
332
|
+
f"\nError: Destination folder already exists: '{dest_folder_path}'\n"
|
333
|
+
f"To prevent accidental overwriting of results, this operation cannot proceed.\n"
|
334
|
+
f"Please take one of the following actions:\n"
|
335
|
+
f"1. Delete the folder manually and run the operation again.\n"
|
336
|
+
f"2. Use a different destination folder name.\n"
|
337
|
+
f"3. Programmatically delete the folder before calling compute_parallel, like this:\n"
|
338
|
+
f" if Path('{dest_folder_path}').exists():\n"
|
339
|
+
f" shutil.rmtree('{dest_folder_path}')\n"
|
340
|
+
f"This safety measure ensures that you don't inadvertently overwrite existing results."
|
341
|
+
)
|
342
|
+
else:
|
343
|
+
try:
|
344
|
+
dest_folder_path.mkdir(parents=True, exist_ok=True)
|
345
|
+
except PermissionError:
|
346
|
+
raise PermissionError(f"Unable to create destination folder '{dest_folder_path}'. Permission denied.")
|
347
|
+
try:
|
348
|
+
shutil.copytree(project_folder, dest_folder_path, dirs_exist_ok=True)
|
349
|
+
except shutil.Error as e:
|
350
|
+
raise IOError(f"Error copying project to destination folder: {str(e)}")
|
342
351
|
project_folder = dest_folder_path # Update project_folder to the new destination
|
343
352
|
|
344
353
|
if plan_numbers:
|
ras_commander/RasGeo.py
CHANGED
@@ -61,9 +61,14 @@ class RasGeo:
|
|
61
61
|
geom_preprocessor_suffix = '.c' + ''.join(plan_path.suffixes[1:]) if plan_path.suffixes else '.c'
|
62
62
|
geom_preprocessor_file = plan_path.with_suffix(geom_preprocessor_suffix)
|
63
63
|
if geom_preprocessor_file.exists():
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
try:
|
65
|
+
print(f"Deleting geometry preprocessor file: {geom_preprocessor_file}")
|
66
|
+
geom_preprocessor_file.unlink()
|
67
|
+
print("File deletion completed successfully.")
|
68
|
+
except PermissionError:
|
69
|
+
raise PermissionError(f"Unable to delete geometry preprocessor file: {geom_preprocessor_file}. Permission denied.")
|
70
|
+
except OSError as e:
|
71
|
+
raise OSError(f"Error deleting geometry preprocessor file: {geom_preprocessor_file}. {str(e)}")
|
67
72
|
else:
|
68
73
|
print(f"No geometry preprocessor file found for: {plan_file}")
|
69
74
|
|
ras_commander/RasPlan.py
CHANGED
@@ -16,11 +16,12 @@ class RasPlan:
|
|
16
16
|
"""
|
17
17
|
|
18
18
|
@staticmethod
|
19
|
-
def set_geom(
|
19
|
+
def set_geom(plan_number: Union[str, int], new_geom: Union[str, int], ras_object=None) -> pd.DataFrame:
|
20
20
|
"""
|
21
|
-
Set the geometry for the
|
21
|
+
Set the geometry for the specified plan.
|
22
22
|
|
23
23
|
Parameters:
|
24
|
+
plan_number (Union[str, int]): The plan number to update.
|
24
25
|
new_geom (Union[str, int]): The new geometry number to set.
|
25
26
|
ras_object: An optional RAS object instance.
|
26
27
|
|
@@ -28,8 +29,7 @@ class RasPlan:
|
|
28
29
|
pd.DataFrame: The updated geometry DataFrame.
|
29
30
|
|
30
31
|
Example:
|
31
|
-
|
32
|
-
updated_geom_df = plan.set_geom('G01')
|
32
|
+
updated_geom_df = RasPlan.set_geom('02', '03')
|
33
33
|
|
34
34
|
Note:
|
35
35
|
This function updates the ras object's dataframes after modifying the project structure.
|
@@ -37,25 +37,56 @@ class RasPlan:
|
|
37
37
|
ras_obj = ras_object or ras
|
38
38
|
ras_obj.check_initialized()
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
raise ValueError(f"Geometry {new_geom} not found in project.")
|
44
|
-
|
45
|
-
self.geom = new_geom
|
46
|
-
geom_df.loc[geom_df['plan_number'] == self.plan_number, 'geom_number'] = new_geom
|
47
|
-
|
48
|
-
print(f"Geometry for plan {self.plan_number} set to {new_geom}")
|
49
|
-
print("Updated geometry DataFrame:")
|
50
|
-
display(geom_df)
|
40
|
+
# Ensure plan_number and new_geom are strings
|
41
|
+
plan_number = str(plan_number).zfill(2)
|
42
|
+
new_geom = str(new_geom).zfill(2)
|
51
43
|
|
44
|
+
# Before doing anything, make sure the plan, geom, flow, and unsteady dataframes are current
|
52
45
|
ras_obj.plan_df = ras_obj.get_plan_entries()
|
53
46
|
ras_obj.geom_df = ras_obj.get_geom_entries()
|
54
47
|
ras_obj.flow_df = ras_obj.get_flow_entries()
|
55
48
|
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
49
|
+
|
50
|
+
# List the geom_df for debugging
|
51
|
+
print("Current geometry DataFrame within the function:")
|
52
|
+
print(ras_obj.geom_df)
|
53
|
+
|
54
|
+
if new_geom not in ras_obj.geom_df['geom_number'].values:
|
55
|
+
raise ValueError(f"Geometry {new_geom} not found in project.")
|
56
|
+
|
57
|
+
# Update the geometry for the specified plan
|
58
|
+
ras_obj.plan_df.loc[ras_obj.plan_df['plan_number'] == plan_number, 'geom_number'] = new_geom
|
56
59
|
|
57
|
-
|
60
|
+
print(f"Geometry for plan {plan_number} set to {new_geom}")
|
61
|
+
print("Updated plan DataFrame:")
|
62
|
+
display(ras_obj.plan_df)
|
63
|
+
|
64
|
+
# Update the project file
|
65
|
+
prj_file_path = ras_obj.prj_file
|
66
|
+
with open(prj_file_path, 'r') as f:
|
67
|
+
lines = f.readlines()
|
68
|
+
|
69
|
+
plan_pattern = re.compile(rf"^Plan File=p{plan_number}", re.IGNORECASE)
|
70
|
+
geom_pattern = re.compile(r"^Geom File=g\d+", re.IGNORECASE)
|
58
71
|
|
72
|
+
for i, line in enumerate(lines):
|
73
|
+
if plan_pattern.match(line):
|
74
|
+
for j in range(i+1, len(lines)):
|
75
|
+
if geom_pattern.match(lines[j]):
|
76
|
+
lines[j] = f"Geom File=g{new_geom}\n"
|
77
|
+
break
|
78
|
+
break
|
79
|
+
|
80
|
+
with open(prj_file_path, 'w') as f:
|
81
|
+
f.writelines(lines)
|
82
|
+
|
83
|
+
print(f"Updated project file with new geometry for plan {plan_number}")
|
84
|
+
|
85
|
+
# Re-initialize the ras object to reflect changes
|
86
|
+
ras_obj.initialize(ras_obj.project_folder, ras_obj.ras_exe_path)
|
87
|
+
|
88
|
+
return ras_obj.plan_df
|
89
|
+
|
59
90
|
@staticmethod
|
60
91
|
def set_steady(plan_number: str, new_steady_flow_number: str, ras_object=None):
|
61
92
|
"""
|
@@ -148,7 +179,11 @@ class RasPlan:
|
|
148
179
|
if not plan_file_path:
|
149
180
|
raise FileNotFoundError(f"Plan file not found: {plan_number}")
|
150
181
|
|
151
|
-
|
182
|
+
|
183
|
+
# DEV NOTE: THIS WORKS HERE, BUT IN OTHER FUNCTIONS WE DO THIS MANUALLY.
|
184
|
+
# UPDATE OTHER FUNCTIONS TO USE RasUtils.update_plan_file INSTEAD OF REPLICATING THIS CODE.
|
185
|
+
|
186
|
+
RasUtils.update_plan_file(plan_file_path, 'Unsteady', new_unsteady_flow_number)
|
152
187
|
print(f"Updated unsteady flow file in {plan_file_path} to u{new_unsteady_flow_number}")
|
153
188
|
|
154
189
|
ras_obj.plan_df = ras_obj.get_plan_entries()
|
@@ -316,6 +351,16 @@ class RasPlan:
|
|
316
351
|
# Update the plan dataframe in the ras instance to ensure it is current
|
317
352
|
ras_obj.plan_df = ras_obj.get_plan_entries()
|
318
353
|
|
354
|
+
# Ensure plan_number is a string
|
355
|
+
plan_number = str(plan_number)
|
356
|
+
|
357
|
+
# Ensure plan_number is formatted as '01', '02', etc.
|
358
|
+
plan_number = plan_number.zfill(2)
|
359
|
+
|
360
|
+
# print the ras_obj.plan_df dataframe
|
361
|
+
print("Plan DataFrame:")
|
362
|
+
display(ras_obj.plan_df)
|
363
|
+
|
319
364
|
plan_entry = ras_obj.plan_df[ras_obj.plan_df['plan_number'] == plan_number]
|
320
365
|
if not plan_entry.empty:
|
321
366
|
results_path = plan_entry['HDF_Results_Path'].iloc[0]
|
@@ -1096,7 +1141,6 @@ class RasPlan:
|
|
1096
1141
|
|
1097
1142
|
return new_steady
|
1098
1143
|
|
1099
|
-
|
1100
1144
|
@staticmethod
|
1101
1145
|
def clone_geom(template_geom, ras_object=None):
|
1102
1146
|
"""
|
@@ -1109,13 +1153,15 @@ class RasPlan:
|
|
1109
1153
|
|
1110
1154
|
Returns:
|
1111
1155
|
str: New geometry number (e.g., '03')
|
1156
|
+
|
1157
|
+
Note:
|
1158
|
+
This function updates the ras object's dataframes after modifying the project structure.
|
1112
1159
|
"""
|
1113
1160
|
ras_obj = ras_object or ras
|
1114
1161
|
ras_obj.check_initialized()
|
1115
1162
|
|
1116
1163
|
# Update geometry entries without reinitializing the entire project
|
1117
|
-
ras_obj.geom_df = ras_obj.get_prj_entries('Geom')
|
1118
|
-
#print(f"Updated geometry entries:\n{ras_obj.geom_df}")
|
1164
|
+
ras_obj.geom_df = ras_obj.get_prj_entries('Geom')
|
1119
1165
|
|
1120
1166
|
template_geom_filename = f"{ras_obj.project_name}.g{template_geom}"
|
1121
1167
|
template_geom_path = ras_obj.project_folder / template_geom_filename
|
@@ -1178,13 +1224,17 @@ class RasPlan:
|
|
1178
1224
|
print(f"Updated {ras_obj.prj_file} with new geometry file g{next_geom_number}")
|
1179
1225
|
new_geom = next_geom_number
|
1180
1226
|
|
1181
|
-
# Update
|
1227
|
+
# Update all dataframes in the ras object
|
1228
|
+
ras_obj.plan_df = ras_obj.get_plan_entries()
|
1182
1229
|
ras_obj.geom_df = ras_obj.get_geom_entries()
|
1230
|
+
ras_obj.flow_df = ras_obj.get_flow_entries()
|
1231
|
+
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
1232
|
+
|
1183
1233
|
print(f"Updated geometry entries:\n{ras_obj.geom_df}")
|
1184
1234
|
|
1185
1235
|
return new_geom
|
1186
|
-
|
1187
|
-
|
1236
|
+
|
1237
|
+
|
1188
1238
|
|
1189
1239
|
|
1190
1240
|
@staticmethod
|
ras_commander/RasUnsteady.py
CHANGED
@@ -33,8 +33,14 @@ class RasUnsteady:
|
|
33
33
|
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
34
34
|
|
35
35
|
unsteady_path = Path(unsteady_file)
|
36
|
-
|
37
|
-
|
36
|
+
try:
|
37
|
+
with open(unsteady_path, 'r') as f:
|
38
|
+
lines = f.readlines()
|
39
|
+
except FileNotFoundError:
|
40
|
+
raise FileNotFoundError(f"Unsteady flow file not found: {unsteady_path}")
|
41
|
+
except PermissionError:
|
42
|
+
raise PermissionError(f"Permission denied when reading unsteady flow file: {unsteady_path}")
|
43
|
+
|
38
44
|
updated = False
|
39
45
|
for i, line in enumerate(lines):
|
40
46
|
for param, new_value in modifications.items():
|
@@ -43,8 +49,13 @@ class RasUnsteady:
|
|
43
49
|
updated = True
|
44
50
|
print(f"Updated {param} to {new_value}")
|
45
51
|
if updated:
|
46
|
-
|
47
|
-
|
52
|
+
try:
|
53
|
+
with open(unsteady_path, 'w') as f:
|
54
|
+
f.writelines(lines)
|
55
|
+
except PermissionError:
|
56
|
+
raise PermissionError(f"Permission denied when writing to unsteady flow file: {unsteady_path}")
|
57
|
+
except IOError as e:
|
58
|
+
raise IOError(f"Error writing to unsteady flow file: {unsteady_path}. {str(e)}")
|
48
59
|
print(f"Applied modifications to {unsteady_file}")
|
49
60
|
else:
|
50
61
|
print(f"No matching parameters found in {unsteady_file}")
|
ras_commander/RasUtils.py
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
"""
|
2
2
|
Utility functions for the ras_commander library.
|
3
3
|
"""
|
4
|
+
import os
|
4
5
|
import shutil
|
5
6
|
import logging
|
6
7
|
import time
|
7
8
|
from pathlib import Path
|
8
9
|
from .RasPrj import ras
|
10
|
+
from typing import Union
|
9
11
|
|
10
12
|
class RasUtils:
|
11
13
|
"""
|
@@ -167,25 +169,35 @@ class RasUtils:
|
|
167
169
|
return None
|
168
170
|
|
169
171
|
@staticmethod
|
170
|
-
def get_plan_path(
|
172
|
+
def get_plan_path(current_plan_number_or_path: Union[str, Path], ras_object=None) -> Path:
|
171
173
|
"""
|
172
|
-
Get the path for a plan file with a given plan number.
|
174
|
+
Get the path for a plan file with a given plan number or path.
|
173
175
|
|
174
176
|
Parameters:
|
175
|
-
|
177
|
+
current_plan_number_or_path (Union[str, Path]): The plan number (1 to 99) or full path to the plan file
|
176
178
|
ras_object (RasPrj, optional): RAS object to use. If None, uses the default ras object.
|
177
179
|
|
178
180
|
Returns:
|
179
|
-
Path: Full path to the plan file
|
181
|
+
Path: Full path to the plan file
|
180
182
|
|
181
183
|
Example:
|
182
184
|
>>> plan_path = RasUtils.get_plan_path(1)
|
183
185
|
>>> print(f"Plan file path: {plan_path}")
|
186
|
+
>>> plan_path = RasUtils.get_plan_path("path/to/plan.p01")
|
187
|
+
>>> print(f"Plan file path: {plan_path}")
|
184
188
|
"""
|
185
189
|
ras_obj = ras_object or ras
|
186
190
|
ras_obj.check_initialized()
|
187
191
|
|
188
|
-
|
192
|
+
plan_path = Path(current_plan_number_or_path)
|
193
|
+
if plan_path.is_file():
|
194
|
+
return plan_path
|
195
|
+
|
196
|
+
try:
|
197
|
+
current_plan_number = f"{int(current_plan_number_or_path):02d}" # Ensure two-digit format
|
198
|
+
except ValueError:
|
199
|
+
raise ValueError(f"Invalid plan number: {current_plan_number_or_path}. Expected a number from 1 to 99.")
|
200
|
+
|
189
201
|
plan_name = f"{ras_obj.project_name}.p{current_plan_number}"
|
190
202
|
return ras_obj.project_folder / plan_name
|
191
203
|
|
@@ -231,12 +243,12 @@ class RasUtils:
|
|
231
243
|
return False
|
232
244
|
|
233
245
|
@staticmethod
|
234
|
-
def update_plan_file(
|
246
|
+
def update_plan_file(plan_number_or_path: Union[str, Path], file_type: str, entry_number: int, ras_object=None) -> None:
|
235
247
|
"""
|
236
248
|
Update a plan file with a new file reference.
|
237
249
|
|
238
250
|
Parameters:
|
239
|
-
|
251
|
+
plan_number_or_path (Union[str, Path]): The plan number (1 to 99) or full path to the plan file
|
240
252
|
file_type (str): Type of file to update ('Geom', 'Flow', or 'Unsteady')
|
241
253
|
entry_number (int): Number (from 1 to 99) to set
|
242
254
|
ras_object (RasPrj, optional): RAS object to use. If None, uses the default ras object.
|
@@ -247,6 +259,7 @@ class RasUtils:
|
|
247
259
|
|
248
260
|
Example:
|
249
261
|
>>> update_plan_entries(1, "Geom", 2)
|
262
|
+
>>> update_plan_entries("path/to/plan.p01", "Geom", 2)
|
250
263
|
"""
|
251
264
|
ras_obj = ras_object or ras
|
252
265
|
ras_obj.check_initialized()
|
@@ -255,7 +268,10 @@ class RasUtils:
|
|
255
268
|
if file_type not in valid_file_types:
|
256
269
|
raise ValueError(f"Invalid file_type. Expected one of: {', '.join(valid_file_types.keys())}")
|
257
270
|
|
258
|
-
plan_file_path =
|
271
|
+
plan_file_path = Path(plan_number_or_path)
|
272
|
+
if not plan_file_path.is_file():
|
273
|
+
plan_file_path = RasUtils.get_plan_path(plan_number_or_path, ras_object)
|
274
|
+
|
259
275
|
if not plan_file_path.exists():
|
260
276
|
raise FileNotFoundError(f"Plan file not found: {plan_file_path}")
|
261
277
|
|
@@ -263,7 +279,8 @@ class RasUtils:
|
|
263
279
|
search_pattern = f"{file_type} File="
|
264
280
|
entry_number = f"{int(entry_number):02d}" # Ensure two-digit format
|
265
281
|
|
266
|
-
|
282
|
+
RasUtils.check_file_access(plan_file_path, 'r')
|
283
|
+
with open(plan_file_path, 'r') as file:
|
267
284
|
lines = file.readlines()
|
268
285
|
|
269
286
|
for i, line in enumerate(lines):
|
@@ -281,3 +298,13 @@ class RasUtils:
|
|
281
298
|
ras_obj.flow_df = ras_obj.get_flow_entries()
|
282
299
|
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
283
300
|
|
301
|
+
@staticmethod
|
302
|
+
def check_file_access(file_path, mode='r'):
|
303
|
+
path = Path(file_path)
|
304
|
+
if not path.exists():
|
305
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
306
|
+
if mode in ('r', 'rb') and not os.access(path, os.R_OK):
|
307
|
+
raise PermissionError(f"Read permission denied for file: {file_path}")
|
308
|
+
if mode in ('w', 'wb', 'a', 'ab') and not os.access(path.parent, os.W_OK):
|
309
|
+
raise PermissionError(f"Write permission denied for directory: {path.parent}")
|
310
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# file generated by setuptools_scm
|
2
|
+
# don't change, don't track in version control
|
3
|
+
TYPE_CHECKING = False
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from typing import Tuple, Union
|
6
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
7
|
+
else:
|
8
|
+
VERSION_TUPLE = object
|
9
|
+
|
10
|
+
version: str
|
11
|
+
__version__: str
|
12
|
+
__version_tuple__: VERSION_TUPLE
|
13
|
+
version_tuple: VERSION_TUPLE
|
14
|
+
|
15
|
+
__version__ = version = '0.22.0.dev0'
|
16
|
+
__version_tuple__ = version_tuple = (0, 22, 0, 'dev0')
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ras_commander
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.22.0.dev0
|
4
4
|
Summary: A library for automating HEC-RAS operations using python functions.
|
5
5
|
Author-email: "William Katzenmeyer, P.E., C.F.M." <heccommander@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/yourusername/ras_commander
|
@@ -11,164 +11,7 @@ Requires-Python: >=3.9
|
|
11
11
|
Description-Content-Type: text/markdown
|
12
12
|
License-File: LICENSE
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
| Directory/File | Purpose |
|
17
|
-
|---|---|
|
18
|
-
| ras_commander/__init__.py | Initializes the library and defines the public API. |
|
19
|
-
| ras_commander/RasCommander.py | Handles execution of HEC-RAS simulations. |
|
20
|
-
| ras_commander/RasFileOps.py | Provides functions for reading and parsing HEC-RAS project files. |
|
21
|
-
| ras_commander/RasGeo.py | Provides functions for manipulating geometry files. |
|
22
|
-
| ras_commander/RasPlan.py | Provides functions for modifying and updating plan files. |
|
23
|
-
| ras_commander/RasPrj.py | Defines the RasPrj class for managing project-level information. |
|
24
|
-
| ras_commander/rasinit.py | Provides the `init_ras_project` function to initialize a project. |
|
25
|
-
| ras_commander/RasPrj.py | Provides functions for managing HEC-RAS projects (e.g., copying files, updating project file). |
|
26
|
-
| ras_commander/RasUnsteady.py | Provides functions for manipulating unsteady flow files. |
|
27
|
-
| ras_commander/RasUtils.py | Provides general utility functions (e.g., file backup, directory creation). |
|
28
|
-
|
29
|
-
## Project Organization Diagram
|
30
|
-
|
31
|
-
```
|
32
|
-
ras_commander
|
33
|
-
├── .github
|
34
|
-
│ └── workflows
|
35
|
-
│ └── python-package.yml
|
36
|
-
├── ras_commander
|
37
|
-
│ ├── __init__.py
|
38
|
-
│ ├── RasCommander.py
|
39
|
-
│ ├── RasFileOps.py
|
40
|
-
│ ├── RasGeo.py
|
41
|
-
│ ├── RasPlan.py
|
42
|
-
│ ├── RasPrj.py
|
43
|
-
│ ├── rasinit.py
|
44
|
-
│ ├── RasPrj.py
|
45
|
-
│ ├── RasUnsteady.py
|
46
|
-
│ └── RasUtils.py
|
47
|
-
├── tests
|
48
|
-
│ └── ... (test files)
|
49
|
-
├── .gitignore
|
50
|
-
├── LICENSE
|
51
|
-
├── README.md
|
52
|
-
├── pyproject.toml
|
53
|
-
├── setup.cfg
|
54
|
-
└── setup.py
|
55
|
-
```
|
56
|
-
|
57
|
-
## Functions Overview
|
58
|
-
|
59
|
-
| Function | Arguments | Purpose |
|
60
|
-
|---|---|---|
|
61
|
-
| `init_ras_project` | `ras_project_folder`, `ras_exe_path` | Initializes a HEC-RAS project by setting up the `RasPrj` with project details. |
|
62
|
-
| `compute_plan` | `plan_file` | Executes a HEC-RAS plan file. |
|
63
|
-
| `compute_plan_from_folder` | `test_plan_file`, `test_folder_path` | Execute a single HEC-RAS plan from a folder other than the project path. |
|
64
|
-
| `compute_test_mode` | `project_folder` | Recreates the -test function from the HEC-RAS interface, primarily by copying the project directory, forcing recomputation, and running each plan. |
|
65
|
-
| `compute_parallel` | `config`, `max_workers`, `cores_per_run` | Run HEC-RAS plans in parallel. |
|
66
|
-
| `compute_parallel_all` | `project_folder`, `ras_exe_path` | Run all HEC-RAS plans in parallel from a project folder path. |
|
67
|
-
|
68
|
-
[The rest of the function list remains the same, just ensure the class names are updated to their new lowercase versions]
|
69
|
-
|
70
|
-
## Potential Uses of RAS-Commander Functions
|
71
|
-
|
72
|
-
[This section remains unchanged]
|
73
|
-
|
74
|
-
## GitHub Actions
|
75
|
-
|
76
|
-
[This section remains unchanged]
|
77
|
-
|
78
|
-
## Basic Usage Instructions
|
79
|
-
|
80
|
-
To get started with RAS-Commander, follow these steps:
|
81
|
-
|
82
|
-
1. Install the library:
|
83
|
-
```
|
84
|
-
pip install ras-commander
|
85
|
-
```
|
86
|
-
|
87
|
-
2. Import the necessary modules:
|
88
|
-
```python
|
89
|
-
from ras_commander import rasinit, RasFileOps, RasPrj, RasPlan, RasGeo, RasUnsteady, RasCommander, RasUtils
|
90
|
-
```
|
91
|
-
|
92
|
-
3. Initialize a HEC-RAS project:
|
93
|
-
```python
|
94
|
-
project_folder = r"C:\path\to\your\project"
|
95
|
-
ras_exe_path = r"C:\Program Files (x86)\HEC\HEC-RAS\6.5\Ras.exe"
|
96
|
-
config = rasinit(project_folder, ras_exe_path)
|
97
|
-
```
|
98
|
-
|
99
|
-
4. Perform operations on your HEC-RAS project. For example:
|
100
|
-
|
101
|
-
- Execute a single plan:
|
102
|
-
```python
|
103
|
-
plan_file = RasPlan.get_plan_path("01")
|
104
|
-
RasCommander.compute_plan(plan_file)
|
105
|
-
```
|
106
|
-
|
107
|
-
- Run multiple plans in parallel:
|
108
|
-
```python
|
109
|
-
max_workers = 2
|
110
|
-
cores_per_run = 1
|
111
|
-
results = RasCommander.compute_parallel(config, max_workers, cores_per_run)
|
112
|
-
```
|
113
|
-
|
114
|
-
- Copy and modify geometry files:
|
115
|
-
```python
|
116
|
-
RasGeo.clone_geom(config.project_folder, "01")
|
117
|
-
plan_file = RasPlan.get_plan_path("01")
|
118
|
-
RasGeo.set_geom(plan_file, "02")
|
119
|
-
```
|
120
|
-
|
121
|
-
- Work with unsteady flow files:
|
122
|
-
```python
|
123
|
-
new_unsteady_number = RasUnsteady.clone_unsteady(config.project_folder, "01")
|
124
|
-
plan_file = RasPlan.get_plan_path("01")
|
125
|
-
RasUnsteady.set_unsteady(plan_file, new_unsteady_number)
|
126
|
-
```
|
127
|
-
|
128
|
-
5. Access project information:
|
129
|
-
```python
|
130
|
-
print(f"Project name: {config.project_name}")
|
131
|
-
print(f"Project file: {config.prj_file}")
|
132
|
-
print(f"Project folder: {config.project_folder}")
|
133
|
-
```
|
134
|
-
|
135
|
-
For more detailed examples and advanced usage, refer to the function documentation and the examples provided in the repository.
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
NOTES: INCORPORATE INTO THE README.MD FILE ABOVE UNDER A NEW SECTION FOR CURRENT USES AND ROADMAP ITEMS, THEN DELETE THIS NOTE
|
141
|
-
|
142
|
-
|
143
|
-
Potential Uses of HEC-RAS Automation Functions
|
144
|
-
This set of functions provides a powerful foundation for automating various aspects of HEC-RAS modeling workflows. Here are some potential applications:
|
145
|
-
1. Calibration and Sensitivity Analysis:
|
146
|
-
Automated Parameter Variation: Users can create multiple simulation scenarios with varying parameters (e.g., Manning's n values, boundary conditions, initial conditions) to calibrate their model against observed data.
|
147
|
-
Sensitivity Testing: Evaluate the impact of different input parameters on model outputs by generating a range of scenarios and analyzing the results. This helps identify critical parameters that require more attention during calibration.
|
148
|
-
2. Real-time Forecasting:
|
149
|
-
Dynamic Model Updates: Integrate with external data sources (e.g., weather forecasts, streamflow observations) to automatically update boundary conditions and initial conditions in unsteady flow files before running the simulation.
|
150
|
-
Ensemble Forecasting: Generate multiple forecasts by incorporating uncertainty in input data and model parameters. This provides a more comprehensive understanding of potential future flow conditions.
|
151
|
-
3. Scenario Analysis:
|
152
|
-
Land Use Change Impacts: Evaluate the effects of land use changes on flood risk by modifying Manning's n values using extract_2d_mannings_tables, modify_2d_mannings_table, and write_2d_mannings_tables and running simulations with updated geometry files.
|
153
|
-
Climate Change Impacts: Analyze the potential impacts of projected climate changes on flood risk by adjusting precipitation patterns and other relevant parameters in unsteady flow files.
|
154
|
-
4. Batch Processing and High-Performance Computing:
|
155
|
-
Large-scale Model Runs: Utilize run_plans_parallel to execute multiple simulations concurrently on a multi-core system, significantly reducing processing time for large-scale models or complex scenarios.
|
156
|
-
Automated Report Generation: Integrate with Python libraries like matplotlib and bokeh to automatically generate customized reports summarizing simulation results, including tables, figures, and maps.
|
157
|
-
5. Model Development and Testing:
|
158
|
-
Rapid Prototyping: Quickly set up and run new model configurations using template files and automated workflows, facilitating rapid model development and testing.
|
159
|
-
Regression Testing: Ensure model integrity and consistency after code changes or updates by automatically running a predefined set of simulations and comparing results with expected outputs.
|
160
|
-
6. User-Friendly Interfaces:
|
161
|
-
GUI Development: Integrate with Python GUI libraries like Tkinter or PyQt to create user-friendly interfaces for automating HEC-RAS workflows, allowing non-programmers to access the power of automation.
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
Certainly! I'll create an updated README.md for the ras_commander library, incorporating the information you've provided and the context from the previous HEC-Commander tools. Here's the updated README.md:
|
169
|
-
|
170
|
-
```markdown
|
171
|
-
# ras_commander
|
14
|
+
# RAS-Commander (ras_commander)
|
172
15
|
|
173
16
|
ras_commander is a Python library for automating HEC-RAS operations, providing a set of tools to interact with HEC-RAS project files, execute simulations, and manage project data. This library is an evolution of the RAS-Commander 1.0 Python Notebook Application previously released under the HEC-Commander tools.
|
174
17
|
|
@@ -186,13 +29,13 @@ ras_commander is a Python library for automating HEC-RAS operations, providing a
|
|
186
29
|
Install ras_commander using pip:
|
187
30
|
|
188
31
|
```bash
|
189
|
-
pip install
|
32
|
+
pip install ras-commander
|
190
33
|
```
|
191
34
|
|
192
35
|
## Requirements
|
193
36
|
|
194
37
|
- Python 3.9+
|
195
|
-
- HEC-RAS 6.
|
38
|
+
- HEC-RAS 6.2 or later (other versions may work, all testing was done with version 6.2 and above)
|
196
39
|
|
197
40
|
For a full list of dependencies, see the `requirements.txt` file.
|
198
41
|
|
@@ -297,9 +140,10 @@ ras_commander
|
|
297
140
|
├── setup.cfg
|
298
141
|
├── setup.py
|
299
142
|
└── requirements.txt
|
143
|
+
```
|
300
144
|
|
301
145
|
|
302
|
-
## Inclusion of .cursorrules for AI-driven Coding Experience
|
146
|
+
## Inclusion of .cursorrules and ai_tools for AI-driven Coding Experience
|
303
147
|
|
304
148
|
Open the ras_commander folder in the Cursor IDE, and it will automatically include the .cursorrules file in your instructions. Additionally, two other provided methods for interacting with the library though your current AI subscriptions:
|
305
149
|
|
@@ -308,6 +152,7 @@ Open the ras_commander folder in the Cursor IDE, and it will automatically inclu
|
|
308
152
|
- Entire code base: LINK HERE (TOKEN COUNT) (for Claude or Gemini)
|
309
153
|
- Examples and Function Docstrings Only: LINK HERE (TOKEN COUNT) (for GPT-4o, o1 or Llama 3.1 405b)
|
310
154
|
- Cursor IDE through .cursorrules file
|
155
|
+
- 'rascommander_code_assistant.ipynb' notebook in the ras_commander folder, which allows for dynamic summarization of the code base and API chatting directly through the notebook.
|
311
156
|
|
312
157
|
There are a series of scripts provided in the "llm_summaries" folder that provide summaries of the code base, and the docstrings of the functions. They can be run in your local environment, or provided to ChatGPT's code interpreter for execution.
|
313
158
|
|
@@ -324,8 +169,6 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
|
324
169
|
This project follows a specific style guide to maintain consistency across the codebase. Please refer to the [Style Guide](STYLE_GUIDE.md) for details on coding conventions, documentation standards, and best practices.
|
325
170
|
|
326
171
|
|
327
|
-
|
328
|
-
|
329
172
|
## License
|
330
173
|
|
331
174
|
ras_commander is released under the MIT License. See the license file for details.
|
@@ -340,3 +183,36 @@ ras_commander is based on the HEC-Commander project's "Command Line is All You N
|
|
340
183
|
|
341
184
|
For questions, suggestions, or support, please contact:
|
342
185
|
William Katzenmeyer, P.E., C.F.M. - billk@fenstermaker.com
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
NOTES: INCORPORATE INTO THE README.MD FILE ABOVE UNDER A NEW SECTION FOR CURRENT USES AND ROADMAP ITEMS, THEN DELETE THIS NOTE
|
196
|
+
|
197
|
+
|
198
|
+
Potential Uses of HEC-RAS Automation Functions
|
199
|
+
This set of functions provides a powerful foundation for automating various aspects of HEC-RAS modeling workflows. Here are some potential applications:
|
200
|
+
1. Calibration and Sensitivity Analysis:
|
201
|
+
Automated Parameter Variation: Users can create multiple simulation scenarios with varying parameters (e.g., Manning's n values, boundary conditions, initial conditions) to calibrate their model against observed data.
|
202
|
+
Sensitivity Testing: Evaluate the impact of different input parameters on model outputs by generating a range of scenarios and analyzing the results. This helps identify critical parameters that require more attention during calibration.
|
203
|
+
2. Real-time Forecasting:
|
204
|
+
Dynamic Model Updates: Integrate with external data sources (e.g., weather forecasts, streamflow observations) to automatically update boundary conditions and initial conditions in unsteady flow files before running the simulation.
|
205
|
+
Ensemble Forecasting: Generate multiple forecasts by incorporating uncertainty in input data and model parameters. This provides a more comprehensive understanding of potential future flow conditions.
|
206
|
+
3. Scenario Analysis:
|
207
|
+
Land Use Change Impacts: Evaluate the effects of land use changes on flood risk by modifying Manning's n values using extract_2d_mannings_tables, modify_2d_mannings_table, and write_2d_mannings_tables and running simulations with updated geometry files.
|
208
|
+
Climate Change Impacts: Analyze the potential impacts of projected climate changes on flood risk by adjusting precipitation patterns and other relevant parameters in unsteady flow files.
|
209
|
+
4. Batch Processing and High-Performance Computing:
|
210
|
+
Large-scale Model Runs: Utilize run_plans_parallel to execute multiple simulations concurrently on a multi-core system, significantly reducing processing time for large-scale models or complex scenarios.
|
211
|
+
Automated Report Generation: Integrate with Python libraries like matplotlib and bokeh to automatically generate customized reports summarizing simulation results, including tables, figures, and maps.
|
212
|
+
5. Model Development and Testing:
|
213
|
+
Rapid Prototyping: Quickly set up and run new model configurations using template files and automated workflows, facilitating rapid model development and testing.
|
214
|
+
Regression Testing: Ensure model integrity and consistency after code changes or updates by automatically running a predefined set of simulations and comparing results with expected outputs.
|
215
|
+
6. User-Friendly Interfaces:
|
216
|
+
GUI Development: Integrate with Python GUI libraries like Tkinter or PyQt to create user-friendly interfaces for automating HEC-RAS workflows, allowing non-programmers to access the power of automation.
|
217
|
+
|
218
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
ras_commander/README.md,sha256=MNWyvD9-MA3m3_HRZCk4uzrtIjyyYhhFs5CZ9M8ZNEo,5936
|
2
|
+
ras_commander/RasCommander.py,sha256=tpi_RqFLxrV08eFhcVoaf1e_j9539lMpyPKIT0EjHT0,21814
|
3
|
+
ras_commander/RasExamples.py,sha256=qNV1KK42S0TllyQ3wWnahQT2GEW1R-_39XI-fOYQemQ,13548
|
4
|
+
ras_commander/RasGeo.py,sha256=0yNqnjEWh4KcItI9hUPczJ3AhPjld4rFY-W-gNUrnUI,3933
|
5
|
+
ras_commander/RasPlan.py,sha256=FU2o9nagq6UXv04WRY6gG01Ef0wOEsJJdqVqMjZ45O0,51789
|
6
|
+
ras_commander/RasPrj.py,sha256=LhlMR6qP9xvLMiPFuwRhRM5yosyLH2h1EyZbnhKgxE8,15163
|
7
|
+
ras_commander/RasUnsteady.py,sha256=rsJH45WQU_30lytEgKY2Uxb4LYyHjgJ82UhA2rWzHOM,2442
|
8
|
+
ras_commander/RasUtils.py,sha256=aSPkqhbfxomEhNZVL9MAZ_Lf0IF3y5L89tcC5WJAkXs,11732
|
9
|
+
ras_commander/__init__.py,sha256=eoOVbWnLH-e405O6ADkO6qhx45a0n60CFgFl7mj4HYs,1089
|
10
|
+
ras_commander/_version.py,sha256=Ss5vVtwnG84xro0FVNRmQeuiMm2EPPdx1J-Vny18ryM,426
|
11
|
+
ras_commander-0.22.0.dev0.dist-info/LICENSE,sha256=_pbd6qHnlsz1iQ-ozDW_49r86BZT6CRwO2iBtw0iN6M,457
|
12
|
+
ras_commander-0.22.0.dev0.dist-info/METADATA,sha256=8nFhNB_dSh_OY_tt2pkqNMiPQJELc4mifgoMJks4ao4,10057
|
13
|
+
ras_commander-0.22.0.dev0.dist-info/WHEEL,sha256=AHX6tWk3qWuce7vKLrj7lnulVHEdWoltgauo8bgCXgU,109
|
14
|
+
ras_commander-0.22.0.dev0.dist-info/top_level.txt,sha256=i76S7eKLFC8doKcXDl3aiOr9RwT06G8adI6YuKbQDaA,14
|
15
|
+
ras_commander-0.22.0.dev0.dist-info/RECORD,,
|
@@ -1,14 +0,0 @@
|
|
1
|
-
ras_commander/README.md,sha256=MNWyvD9-MA3m3_HRZCk4uzrtIjyyYhhFs5CZ9M8ZNEo,5936
|
2
|
-
ras_commander/RasCommander.py,sha256=tsCsvHdjbB28_tqJhy4h5iyYfgd5aLCcI0IfsN_GUqM,21277
|
3
|
-
ras_commander/RasExamples.py,sha256=qNV1KK42S0TllyQ3wWnahQT2GEW1R-_39XI-fOYQemQ,13548
|
4
|
-
ras_commander/RasGeo.py,sha256=VY7-Ksw2iclH9C9mY7unQ_a11aCkCLiyhmFgJmSNdsk,3571
|
5
|
-
ras_commander/RasPlan.py,sha256=02agZMG29C8Ra50LSd9JF4SpomABRDJXCwNBK6dJCqM,49731
|
6
|
-
ras_commander/RasPrj.py,sha256=LhlMR6qP9xvLMiPFuwRhRM5yosyLH2h1EyZbnhKgxE8,15163
|
7
|
-
ras_commander/RasUnsteady.py,sha256=cOpFAZrXrxBBdoi-i3iWboQzrtCUb_sPGQ05dZnadF4,1852
|
8
|
-
ras_commander/RasUtils.py,sha256=dkeh7k1yvrViNQ0NzG4jB4hiEvmsWZJu-_w04ccrpdI,10402
|
9
|
-
ras_commander/__init__.py,sha256=eoOVbWnLH-e405O6ADkO6qhx45a0n60CFgFl7mj4HYs,1089
|
10
|
-
ras_commander-0.21.0.dist-info/LICENSE,sha256=_pbd6qHnlsz1iQ-ozDW_49r86BZT6CRwO2iBtw0iN6M,457
|
11
|
-
ras_commander-0.21.0.dist-info/METADATA,sha256=F_Og5eixNK5qhCfKff4WcRWKGYX6sjKO4PrM62wf7rw,14478
|
12
|
-
ras_commander-0.21.0.dist-info/WHEEL,sha256=muXAwoPanksrVvf9Mcykr8l6Q0JyBrGUVYr50kE4bxo,109
|
13
|
-
ras_commander-0.21.0.dist-info/top_level.txt,sha256=i76S7eKLFC8doKcXDl3aiOr9RwT06G8adI6YuKbQDaA,14
|
14
|
-
ras_commander-0.21.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|