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.
@@ -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
- raise ValueError(
331
- f"\nError: Destination folder already exists: '{dest_folder_path}'\n"
332
- f"To prevent accidental overwriting of results, this operation cannot proceed.\n"
333
- f"Please take one of the following actions:\n"
334
- f"1. Delete the folder manually and run the operation again.\n"
335
- f"2. Use a different destination folder name.\n"
336
- f"3. Programmatically delete the folder before calling compute_parallel, like this:\n"
337
- f" if Path('{dest_folder_path}').exists():\n"
338
- f" shutil.rmtree('{dest_folder_path}')\n"
339
- f"This safety measure ensures that you don't inadvertently overwrite existing results."
340
- )
341
- shutil.copytree(project_folder, dest_folder_path)
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
- print(f"Deleting geometry preprocessor file: {geom_preprocessor_file}")
65
- geom_preprocessor_file.unlink()
66
- print("File deletion completed successfully.")
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(self, new_geom: Union[str, int], ras_object=None) -> pd.DataFrame:
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 current plan.
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
- plan = RasPlan('path/to/plan.p01')
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
- geom_df = ras_obj.geom_df
41
-
42
- if new_geom not in geom_df['geom_number']:
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
- return geom_df
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
- RasPlan.update_plan_file(plan_file_path, 'Unsteady', new_unsteady_flow_number)
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') # Call the correct function to get updated geometry entries
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 the geometry entries in the ras object
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
@@ -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
- with open(unsteady_path, 'r') as f:
37
- lines = f.readlines()
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
- with open(unsteady_path, 'w') as f:
47
- f.writelines(lines)
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(current_plan_number: int, ras_object=None) -> 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
- current_plan_number (int): The plan number (1 to 99)
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 with the given plan number
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
- current_plan_number = f"{int(current_plan_number):02d}" # Ensure two-digit format
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(plan_number: int, file_type: str, entry_number: int, ras_object=None) -> None:
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
- plan_number (int): The plan number (1 to 99)
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 = RasUtils.get_plan_path(plan_number, ras_object)
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
- with plan_file_path.open('r') as file:
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.21.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
- ## RAS-Commander Library Organization
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 ras_commander
32
+ pip install ras-commander
190
33
  ```
191
34
 
192
35
  ## Requirements
193
36
 
194
37
  - Python 3.9+
195
- - HEC-RAS 6.5 (other versions may work but are not officially supported)
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,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.0.0)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
@@ -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,,