ras-commander 0.56.0__tar.gz → 0.58.0__tar.gz
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-0.56.0/ras_commander.egg-info → ras_commander-0.58.0}/PKG-INFO +7 -16
- {ras_commander-0.56.0 → ras_commander-0.58.0}/README.md +4 -14
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasExamples.py +423 -394
- {ras_commander-0.56.0 → ras_commander-0.58.0/ras_commander.egg-info}/PKG-INFO +7 -16
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander.egg-info/requires.txt +1 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/setup.py +3 -2
- {ras_commander-0.56.0 → ras_commander-0.58.0}/LICENSE +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/pyproject.toml +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/Decorators.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfBase.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfBndry.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfFluvialPluvial.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfInfiltration.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfMesh.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfPipe.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfPlan.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfPlot.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfPump.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfResultsMesh.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfResultsPlan.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfResultsPlot.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfResultsXsec.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfStruc.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfUtils.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/HdfXsec.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/LoggingConfig.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasCmdr.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasGeo.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasGpt.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasMapper.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasPlan.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasPrj.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasToGo.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasUnsteady.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/RasUtils.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander/__init__.py +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander.egg-info/SOURCES.txt +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander.egg-info/dependency_links.txt +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/ras_commander.egg-info/top_level.txt +0 -0
- {ras_commander-0.56.0 → ras_commander-0.58.0}/setup.cfg +0 -0
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: ras-commander
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.58.0
|
4
4
|
Summary: A Python library for automating HEC-RAS 6.x operations
|
5
5
|
Home-page: https://github.com/gpt-cmdr/ras-commander
|
6
|
-
Author: William M. Katzenmeyer
|
6
|
+
Author: William M. Katzenmeyer, P.E., C.F.M.
|
7
7
|
Author-email: heccommander@gmail.com
|
8
8
|
Requires-Python: >=3.10
|
9
9
|
Description-Content-Type: text/markdown
|
@@ -20,6 +20,7 @@ Requires-Dist: matplotlib
|
|
20
20
|
Requires-Dist: shapely
|
21
21
|
Requires-Dist: pathlib
|
22
22
|
Requires-Dist: rasterstats
|
23
|
+
Requires-Dist: rtree
|
23
24
|
Dynamic: author
|
24
25
|
Dynamic: author-email
|
25
26
|
Dynamic: description
|
@@ -33,16 +34,10 @@ Dynamic: summary
|
|
33
34
|
|
34
35
|
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 was initially conceptualized in the Australian Water School course "AI Tools for Modelling Innovation", and subsequently expanded to cover the basic functionality of the HECRASController COM32 interface using open-source python libraries. This library uses a Test Driven Development strategy, leveraging the publicly-available HEC-RAS Example projects to create repeatable demonstration examples. The "Commmander" moniker is inspired by the "Command Line is All You Need" approach to HEC-RAS automation that was first implemented in the HEC-Commander Tools repository.
|
35
36
|
|
36
|
-
##
|
37
|
-
William Katzenmeyer, P.E., C.F.M.
|
37
|
+
## Repository Author:
|
38
|
+
(William Katzenmeyer, P.E., C.F.M.)[https://engineeringwithllms.info]
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
Aaron Nichols, P.E., C.F.M.
|
42
|
-
|
43
|
-
(Additional Contributors Here)
|
44
|
-
|
45
|
-
## Don't Ask Me, Ask ChatGPT!
|
40
|
+
## Don't Ask Me, Ask GPT!
|
46
41
|
|
47
42
|
This repository has several methods of interaction with Large Language Models and LLM-Assisted Coding built right in:
|
48
43
|
|
@@ -159,8 +154,6 @@ results = RasCmdr.compute_parallel(
|
|
159
154
|
RasPlan.set_geom("01", "02")
|
160
155
|
```
|
161
156
|
|
162
|
-
Certainly! I'll provide you with an updated Key Components section and Project Organization diagram based on the current structure of the ras-commander library.
|
163
|
-
|
164
157
|
#### Key Components
|
165
158
|
|
166
159
|
- `RasPrj`: Manages HEC-RAS projects, handling initialization and data loading
|
@@ -254,7 +247,7 @@ ras_commander
|
|
254
247
|
|
255
248
|
### Accessing HEC Examples through RasExamples
|
256
249
|
|
257
|
-
The `RasExamples` class provides functionality for quickly loading and managing HEC-RAS example projects. This is particularly useful for testing and development purposes.
|
250
|
+
The `RasExamples` class provides functionality for quickly loading and managing HEC-RAS example projects. This is particularly useful for testing and development purposes. All examples in the ras-commander repository currently utilize HEC example projects to provide fully running scripts and notebooks for end user testing, demonstration and adaption.
|
258
251
|
|
259
252
|
Key features:
|
260
253
|
- Download and extract HEC-RAS example projects
|
@@ -266,8 +259,6 @@ Example usage:
|
|
266
259
|
from ras_commander import RasExamples
|
267
260
|
|
268
261
|
```
|
269
|
-
ras_examples = RasExamples()
|
270
|
-
ras_examples.get_example_projects() # Downloads example projects if not already present
|
271
262
|
categories = ras_examples.list_categories()
|
272
263
|
projects = ras_examples.list_projects("Steady Flow")
|
273
264
|
extracted_paths = ras_examples.extract_project(["Bald Eagle Creek", "Muncie"])
|
@@ -2,16 +2,10 @@
|
|
2
2
|
|
3
3
|
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 was initially conceptualized in the Australian Water School course "AI Tools for Modelling Innovation", and subsequently expanded to cover the basic functionality of the HECRASController COM32 interface using open-source python libraries. This library uses a Test Driven Development strategy, leveraging the publicly-available HEC-RAS Example projects to create repeatable demonstration examples. The "Commmander" moniker is inspired by the "Command Line is All You Need" approach to HEC-RAS automation that was first implemented in the HEC-Commander Tools repository.
|
4
4
|
|
5
|
-
##
|
6
|
-
William Katzenmeyer, P.E., C.F.M.
|
5
|
+
## Repository Author:
|
6
|
+
(William Katzenmeyer, P.E., C.F.M.)[https://engineeringwithllms.info]
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
Aaron Nichols, P.E., C.F.M.
|
11
|
-
|
12
|
-
(Additional Contributors Here)
|
13
|
-
|
14
|
-
## Don't Ask Me, Ask ChatGPT!
|
8
|
+
## Don't Ask Me, Ask GPT!
|
15
9
|
|
16
10
|
This repository has several methods of interaction with Large Language Models and LLM-Assisted Coding built right in:
|
17
11
|
|
@@ -128,8 +122,6 @@ results = RasCmdr.compute_parallel(
|
|
128
122
|
RasPlan.set_geom("01", "02")
|
129
123
|
```
|
130
124
|
|
131
|
-
Certainly! I'll provide you with an updated Key Components section and Project Organization diagram based on the current structure of the ras-commander library.
|
132
|
-
|
133
125
|
#### Key Components
|
134
126
|
|
135
127
|
- `RasPrj`: Manages HEC-RAS projects, handling initialization and data loading
|
@@ -223,7 +215,7 @@ ras_commander
|
|
223
215
|
|
224
216
|
### Accessing HEC Examples through RasExamples
|
225
217
|
|
226
|
-
The `RasExamples` class provides functionality for quickly loading and managing HEC-RAS example projects. This is particularly useful for testing and development purposes.
|
218
|
+
The `RasExamples` class provides functionality for quickly loading and managing HEC-RAS example projects. This is particularly useful for testing and development purposes. All examples in the ras-commander repository currently utilize HEC example projects to provide fully running scripts and notebooks for end user testing, demonstration and adaption.
|
227
219
|
|
228
220
|
Key features:
|
229
221
|
- Download and extract HEC-RAS example projects
|
@@ -235,8 +227,6 @@ Example usage:
|
|
235
227
|
from ras_commander import RasExamples
|
236
228
|
|
237
229
|
```
|
238
|
-
ras_examples = RasExamples()
|
239
|
-
ras_examples.get_example_projects() # Downloads example projects if not already present
|
240
230
|
categories = ras_examples.list_categories()
|
241
231
|
projects = ras_examples.list_projects("Steady Flow")
|
242
232
|
extracted_paths = ras_examples.extract_project(["Bald Eagle Creek", "Muncie"])
|
@@ -1,395 +1,424 @@
|
|
1
|
-
"""
|
2
|
-
RasExamples - Manage and load HEC-RAS example projects for testing and development
|
3
|
-
|
4
|
-
This module is part of the ras-commander library and uses a centralized logging configuration.
|
5
|
-
|
6
|
-
Logging Configuration:
|
7
|
-
- The logging is set up in the logging_config.py file.
|
8
|
-
- A @log_call decorator is available to automatically log function calls.
|
9
|
-
- Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
10
|
-
- Logs are written to both console and a rotating file handler.
|
11
|
-
- The default log file is 'ras_commander.log' in the 'logs' directory.
|
12
|
-
- The default log level is INFO.
|
13
|
-
|
14
|
-
To use logging in this module:
|
15
|
-
1. Use the @log_call decorator for automatic function call logging.
|
16
|
-
2. For additional logging, use logger.[level]() calls (e.g., logger.info(), logger.debug()).
|
17
|
-
3. Obtain the logger using: logger = logging.getLogger(__name__)
|
18
|
-
|
19
|
-
Example:
|
20
|
-
@log_call
|
21
|
-
def my_function():
|
22
|
-
logger = logging.getLogger(__name__)
|
23
|
-
logger.debug("Additional debug information")
|
24
|
-
# Function logic here
|
25
|
-
|
26
|
-
|
27
|
-
-----
|
28
|
-
|
29
|
-
All of the methods in this class are static and are designed to be used without instantiation.
|
30
|
-
|
31
|
-
List of Functions in RasExamples:
|
32
|
-
- get_example_projects()
|
33
|
-
- list_categories()
|
34
|
-
- list_projects()
|
35
|
-
- extract_project()
|
36
|
-
- is_project_extracted()
|
37
|
-
- clean_projects_directory()
|
38
|
-
|
39
|
-
"""
|
40
|
-
import os
|
41
|
-
import requests
|
42
|
-
import zipfile
|
43
|
-
import pandas as pd
|
44
|
-
from pathlib import Path
|
45
|
-
import shutil
|
46
|
-
from typing import Union, List
|
47
|
-
import csv
|
48
|
-
from datetime import datetime
|
49
|
-
import logging
|
50
|
-
import re
|
51
|
-
from tqdm import tqdm
|
52
|
-
from ras_commander import get_logger
|
53
|
-
from ras_commander.LoggingConfig import log_call
|
54
|
-
|
55
|
-
logger = get_logger(__name__)
|
56
|
-
|
57
|
-
class RasExamples:
|
58
|
-
"""
|
59
|
-
A class for quickly loading HEC-RAS example projects for testing and development of ras-commander.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
self.
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
self.
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
return
|
237
|
-
|
238
|
-
@
|
239
|
-
def
|
240
|
-
"""
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
except Exception as e:
|
259
|
-
logger.error(f"Failed to
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
logger.
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
"""
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
1
|
+
"""
|
2
|
+
RasExamples - Manage and load HEC-RAS example projects for testing and development
|
3
|
+
|
4
|
+
This module is part of the ras-commander library and uses a centralized logging configuration.
|
5
|
+
|
6
|
+
Logging Configuration:
|
7
|
+
- The logging is set up in the logging_config.py file.
|
8
|
+
- A @log_call decorator is available to automatically log function calls.
|
9
|
+
- Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
10
|
+
- Logs are written to both console and a rotating file handler.
|
11
|
+
- The default log file is 'ras_commander.log' in the 'logs' directory.
|
12
|
+
- The default log level is INFO.
|
13
|
+
|
14
|
+
To use logging in this module:
|
15
|
+
1. Use the @log_call decorator for automatic function call logging.
|
16
|
+
2. For additional logging, use logger.[level]() calls (e.g., logger.info(), logger.debug()).
|
17
|
+
3. Obtain the logger using: logger = logging.getLogger(__name__)
|
18
|
+
|
19
|
+
Example:
|
20
|
+
@log_call
|
21
|
+
def my_function():
|
22
|
+
logger = logging.getLogger(__name__)
|
23
|
+
logger.debug("Additional debug information")
|
24
|
+
# Function logic here
|
25
|
+
|
26
|
+
|
27
|
+
-----
|
28
|
+
|
29
|
+
All of the methods in this class are static and are designed to be used without instantiation.
|
30
|
+
|
31
|
+
List of Functions in RasExamples:
|
32
|
+
- get_example_projects()
|
33
|
+
- list_categories()
|
34
|
+
- list_projects()
|
35
|
+
- extract_project()
|
36
|
+
- is_project_extracted()
|
37
|
+
- clean_projects_directory()
|
38
|
+
|
39
|
+
"""
|
40
|
+
import os
|
41
|
+
import requests
|
42
|
+
import zipfile
|
43
|
+
import pandas as pd
|
44
|
+
from pathlib import Path
|
45
|
+
import shutil
|
46
|
+
from typing import Union, List
|
47
|
+
import csv
|
48
|
+
from datetime import datetime
|
49
|
+
import logging
|
50
|
+
import re
|
51
|
+
from tqdm import tqdm
|
52
|
+
from ras_commander import get_logger
|
53
|
+
from ras_commander.LoggingConfig import log_call
|
54
|
+
|
55
|
+
logger = get_logger(__name__)
|
56
|
+
|
57
|
+
class RasExamples:
|
58
|
+
"""
|
59
|
+
A class for quickly loading HEC-RAS example projects for testing and development of ras-commander.
|
60
|
+
All methods are class methods, so no initialization is required.
|
61
|
+
"""
|
62
|
+
base_url = 'https://github.com/HydrologicEngineeringCenter/hec-downloads/releases/download/'
|
63
|
+
valid_versions = [
|
64
|
+
"6.6", "6.5", "6.4.1", "6.3.1", "6.3", "6.2", "6.1", "6.0",
|
65
|
+
"5.0.7", "5.0.6", "5.0.5", "5.0.4", "5.0.3", "5.0.1", "5.0",
|
66
|
+
"4.1", "4.0", "3.1.3", "3.1.2", "3.1.1", "3.0", "2.2"
|
67
|
+
]
|
68
|
+
base_dir = Path.cwd()
|
69
|
+
examples_dir = base_dir
|
70
|
+
projects_dir = examples_dir / 'example_projects'
|
71
|
+
csv_file_path = examples_dir / 'example_projects.csv'
|
72
|
+
|
73
|
+
_folder_df = None
|
74
|
+
_zip_file_path = None
|
75
|
+
|
76
|
+
def __init__(self):
|
77
|
+
"""Initialize RasExamples and ensure data is loaded"""
|
78
|
+
self._ensure_initialized()
|
79
|
+
|
80
|
+
@property
|
81
|
+
def folder_df(self):
|
82
|
+
"""Access the folder DataFrame"""
|
83
|
+
self._ensure_initialized()
|
84
|
+
return self._folder_df
|
85
|
+
|
86
|
+
def _ensure_initialized(self):
|
87
|
+
"""Ensure the class is initialized with required data"""
|
88
|
+
self.projects_dir.mkdir(parents=True, exist_ok=True)
|
89
|
+
if self._folder_df is None:
|
90
|
+
self._load_project_data()
|
91
|
+
|
92
|
+
def _load_project_data(self):
|
93
|
+
"""Load project data from CSV if up-to-date, otherwise extract from zip."""
|
94
|
+
logger.debug("Loading project data")
|
95
|
+
self._find_zip_file()
|
96
|
+
|
97
|
+
if not self._zip_file_path:
|
98
|
+
logger.info("No example projects zip file found. Downloading...")
|
99
|
+
self.get_example_projects()
|
100
|
+
|
101
|
+
try:
|
102
|
+
zip_modified_time = os.path.getmtime(self._zip_file_path)
|
103
|
+
except FileNotFoundError:
|
104
|
+
logger.error(f"Zip file not found at {self._zip_file_path}.")
|
105
|
+
return
|
106
|
+
|
107
|
+
if self.csv_file_path.exists():
|
108
|
+
csv_modified_time = os.path.getmtime(self.csv_file_path)
|
109
|
+
|
110
|
+
if csv_modified_time >= zip_modified_time:
|
111
|
+
logger.info("Loading project data from CSV...")
|
112
|
+
try:
|
113
|
+
self._folder_df = pd.read_csv(self.csv_file_path)
|
114
|
+
logger.info(f"Loaded {len(self._folder_df)} projects from CSV.")
|
115
|
+
return
|
116
|
+
except Exception as e:
|
117
|
+
logger.error(f"Failed to read CSV file: {e}")
|
118
|
+
self._folder_df = None
|
119
|
+
|
120
|
+
logger.info("Extracting folder structure from zip file...")
|
121
|
+
self._extract_folder_structure()
|
122
|
+
self._save_to_csv()
|
123
|
+
|
124
|
+
@classmethod
|
125
|
+
def extract_project(cls, project_names: Union[str, List[str]]) -> Union[Path, List[Path]]:
|
126
|
+
"""Extract one or more specific HEC-RAS projects from the zip file.
|
127
|
+
|
128
|
+
Args:
|
129
|
+
project_names: Single project name as string or list of project names
|
130
|
+
|
131
|
+
Returns:
|
132
|
+
Path: Single Path object if one project extracted
|
133
|
+
List[Path]: List of Path objects if multiple projects extracted
|
134
|
+
"""
|
135
|
+
logger.debug(f"Extracting projects: {project_names}")
|
136
|
+
|
137
|
+
# Initialize if needed
|
138
|
+
if cls._folder_df is None:
|
139
|
+
cls._find_zip_file()
|
140
|
+
if not cls._zip_file_path:
|
141
|
+
logger.info("No example projects zip file found. Downloading...")
|
142
|
+
cls.get_example_projects()
|
143
|
+
cls._load_project_data()
|
144
|
+
|
145
|
+
if isinstance(project_names, str):
|
146
|
+
project_names = [project_names]
|
147
|
+
|
148
|
+
extracted_paths = []
|
149
|
+
|
150
|
+
for project_name in project_names:
|
151
|
+
logger.info("----- RasExamples Extracting Project -----")
|
152
|
+
logger.info(f"Extracting project '{project_name}'")
|
153
|
+
project_path = cls.projects_dir
|
154
|
+
|
155
|
+
if (project_path / project_name).exists():
|
156
|
+
logger.info(f"Project '{project_name}' already exists. Deleting existing folder...")
|
157
|
+
try:
|
158
|
+
shutil.rmtree(project_path / project_name)
|
159
|
+
logger.info(f"Existing folder for project '{project_name}' has been deleted.")
|
160
|
+
except Exception as e:
|
161
|
+
logger.error(f"Failed to delete existing project folder '{project_name}': {e}")
|
162
|
+
continue
|
163
|
+
|
164
|
+
project_info = cls._folder_df[cls._folder_df['Project'] == project_name]
|
165
|
+
if project_info.empty:
|
166
|
+
error_msg = f"Project '{project_name}' not found in the zip file."
|
167
|
+
logger.error(error_msg)
|
168
|
+
raise ValueError(error_msg)
|
169
|
+
|
170
|
+
try:
|
171
|
+
with zipfile.ZipFile(cls._zip_file_path, 'r') as zip_ref:
|
172
|
+
for file in zip_ref.namelist():
|
173
|
+
parts = Path(file).parts
|
174
|
+
if len(parts) > 1 and parts[1] == project_name:
|
175
|
+
relative_path = Path(*parts[1:])
|
176
|
+
extract_path = project_path / relative_path
|
177
|
+
if file.endswith('/'):
|
178
|
+
extract_path.mkdir(parents=True, exist_ok=True)
|
179
|
+
else:
|
180
|
+
extract_path.parent.mkdir(parents=True, exist_ok=True)
|
181
|
+
with zip_ref.open(file) as source, open(extract_path, "wb") as target:
|
182
|
+
shutil.copyfileobj(source, target)
|
183
|
+
|
184
|
+
logger.info(f"Successfully extracted project '{project_name}' to {project_path / project_name}")
|
185
|
+
extracted_paths.append(project_path / project_name)
|
186
|
+
except Exception as e:
|
187
|
+
logger.error(f"An error occurred while extracting project '{project_name}': {str(e)}")
|
188
|
+
|
189
|
+
# Return single path if only one project was extracted, otherwise return list
|
190
|
+
return extracted_paths[0] if len(project_names) == 1 else extracted_paths
|
191
|
+
|
192
|
+
@classmethod
|
193
|
+
def _find_zip_file(cls):
|
194
|
+
"""Locate the example projects zip file in the examples directory."""
|
195
|
+
for version in cls.valid_versions:
|
196
|
+
potential_zip = cls.examples_dir / f"Example_Projects_{version.replace('.', '_')}.zip"
|
197
|
+
if potential_zip.exists():
|
198
|
+
cls._zip_file_path = potential_zip
|
199
|
+
logger.info(f"Found zip file: {cls._zip_file_path}")
|
200
|
+
break
|
201
|
+
else:
|
202
|
+
logger.warning("No existing example projects zip file found.")
|
203
|
+
|
204
|
+
@classmethod
|
205
|
+
def get_example_projects(cls, version_number='6.6'):
|
206
|
+
"""
|
207
|
+
Download and extract HEC-RAS example projects for a specified version.
|
208
|
+
"""
|
209
|
+
logger.info(f"Getting example projects for version {version_number}")
|
210
|
+
if version_number not in cls.valid_versions:
|
211
|
+
error_msg = f"Invalid version number. Valid versions are: {', '.join(cls.valid_versions)}"
|
212
|
+
logger.error(error_msg)
|
213
|
+
raise ValueError(error_msg)
|
214
|
+
|
215
|
+
zip_url = f"{cls.base_url}1.0.33/Example_Projects_{version_number.replace('.', '_')}.zip"
|
216
|
+
|
217
|
+
cls.examples_dir.mkdir(parents=True, exist_ok=True)
|
218
|
+
|
219
|
+
cls._zip_file_path = cls.examples_dir / f"Example_Projects_{version_number.replace('.', '_')}.zip"
|
220
|
+
|
221
|
+
if not cls._zip_file_path.exists():
|
222
|
+
logger.info(f"Downloading HEC-RAS Example Projects from {zip_url}. \nThe file is over 400 MB, so it may take a few minutes to download....")
|
223
|
+
try:
|
224
|
+
response = requests.get(zip_url, stream=True)
|
225
|
+
response.raise_for_status()
|
226
|
+
with open(cls._zip_file_path, 'wb') as file:
|
227
|
+
shutil.copyfileobj(response.raw, file)
|
228
|
+
logger.info(f"Downloaded to {cls._zip_file_path}")
|
229
|
+
except requests.exceptions.RequestException as e:
|
230
|
+
logger.error(f"Failed to download the zip file: {e}")
|
231
|
+
raise
|
232
|
+
else:
|
233
|
+
logger.info("HEC-RAS Example Projects zip file already exists. Skipping download.")
|
234
|
+
|
235
|
+
cls._load_project_data()
|
236
|
+
return cls.projects_dir
|
237
|
+
|
238
|
+
@classmethod
|
239
|
+
def _load_project_data(cls):
|
240
|
+
"""Load project data from CSV if up-to-date, otherwise extract from zip."""
|
241
|
+
logger.debug("Loading project data")
|
242
|
+
|
243
|
+
try:
|
244
|
+
zip_modified_time = os.path.getmtime(cls._zip_file_path)
|
245
|
+
except FileNotFoundError:
|
246
|
+
logger.error(f"Zip file not found at {cls._zip_file_path}.")
|
247
|
+
return
|
248
|
+
|
249
|
+
if cls.csv_file_path.exists():
|
250
|
+
csv_modified_time = os.path.getmtime(cls.csv_file_path)
|
251
|
+
|
252
|
+
if csv_modified_time >= zip_modified_time:
|
253
|
+
logger.info("Loading project data from CSV...")
|
254
|
+
try:
|
255
|
+
cls._folder_df = pd.read_csv(cls.csv_file_path)
|
256
|
+
logger.info(f"Loaded {len(cls._folder_df)} projects from CSV.")
|
257
|
+
return
|
258
|
+
except Exception as e:
|
259
|
+
logger.error(f"Failed to read CSV file: {e}")
|
260
|
+
cls._folder_df = None
|
261
|
+
|
262
|
+
logger.info("Extracting folder structure from zip file...")
|
263
|
+
cls._extract_folder_structure()
|
264
|
+
cls._save_to_csv()
|
265
|
+
|
266
|
+
@classmethod
|
267
|
+
def _extract_folder_structure(cls):
|
268
|
+
"""
|
269
|
+
Extract folder structure from the zip file.
|
270
|
+
|
271
|
+
Populates folder_df with category and project information.
|
272
|
+
"""
|
273
|
+
folder_data = []
|
274
|
+
try:
|
275
|
+
with zipfile.ZipFile(cls._zip_file_path, 'r') as zip_ref:
|
276
|
+
for file in zip_ref.namelist():
|
277
|
+
parts = Path(file).parts
|
278
|
+
if len(parts) > 1:
|
279
|
+
folder_data.append({
|
280
|
+
'Category': parts[0],
|
281
|
+
'Project': parts[1]
|
282
|
+
})
|
283
|
+
|
284
|
+
cls._folder_df = pd.DataFrame(folder_data).drop_duplicates()
|
285
|
+
logger.info(f"Extracted {len(cls._folder_df)} projects.")
|
286
|
+
logger.debug(f"folder_df:\n{cls._folder_df}")
|
287
|
+
except zipfile.BadZipFile:
|
288
|
+
logger.error(f"The file {cls._zip_file_path} is not a valid zip file.")
|
289
|
+
cls._folder_df = pd.DataFrame(columns=['Category', 'Project'])
|
290
|
+
except Exception as e:
|
291
|
+
logger.error(f"An error occurred while extracting the folder structure: {str(e)}")
|
292
|
+
cls._folder_df = pd.DataFrame(columns=['Category', 'Project'])
|
293
|
+
|
294
|
+
@classmethod
|
295
|
+
def _save_to_csv(cls):
|
296
|
+
"""Save the extracted folder structure to CSV file."""
|
297
|
+
if cls._folder_df is not None and not cls._folder_df.empty:
|
298
|
+
try:
|
299
|
+
cls._folder_df.to_csv(cls.csv_file_path, index=False)
|
300
|
+
logger.info(f"Saved project data to {cls.csv_file_path}")
|
301
|
+
except Exception as e:
|
302
|
+
logger.error(f"Failed to save project data to CSV: {e}")
|
303
|
+
else:
|
304
|
+
logger.warning("No folder data to save to CSV.")
|
305
|
+
|
306
|
+
@classmethod
|
307
|
+
def list_categories(cls):
|
308
|
+
"""
|
309
|
+
List all categories of example projects.
|
310
|
+
"""
|
311
|
+
if cls._folder_df is None or 'Category' not in cls._folder_df.columns:
|
312
|
+
logger.warning("No categories available. Make sure the zip file is properly loaded.")
|
313
|
+
return []
|
314
|
+
categories = cls._folder_df['Category'].unique()
|
315
|
+
logger.info(f"Available categories: {', '.join(categories)}")
|
316
|
+
return categories.tolist()
|
317
|
+
|
318
|
+
@classmethod
|
319
|
+
def list_projects(cls, category=None):
|
320
|
+
"""
|
321
|
+
List all projects or projects in a specific category.
|
322
|
+
"""
|
323
|
+
if cls._folder_df is None:
|
324
|
+
logger.warning("No projects available. Make sure the zip file is properly loaded.")
|
325
|
+
return []
|
326
|
+
if category:
|
327
|
+
projects = cls._folder_df[cls._folder_df['Category'] == category]['Project'].unique()
|
328
|
+
logger.info(f"Projects in category '{category}': {', '.join(projects)}")
|
329
|
+
else:
|
330
|
+
projects = cls._folder_df['Project'].unique()
|
331
|
+
logger.info(f"All available projects: {', '.join(projects)}")
|
332
|
+
return projects.tolist()
|
333
|
+
|
334
|
+
@classmethod
|
335
|
+
def is_project_extracted(cls, project_name):
|
336
|
+
"""
|
337
|
+
Check if a specific project is already extracted.
|
338
|
+
"""
|
339
|
+
project_path = cls.projects_dir / project_name
|
340
|
+
is_extracted = project_path.exists()
|
341
|
+
logger.info(f"Project '{project_name}' extracted: {is_extracted}")
|
342
|
+
return is_extracted
|
343
|
+
|
344
|
+
@classmethod
|
345
|
+
def clean_projects_directory(cls):
|
346
|
+
"""Remove all extracted projects from the example_projects directory."""
|
347
|
+
logger.info(f"Cleaning projects directory: {cls.projects_dir}")
|
348
|
+
if cls.projects_dir.exists():
|
349
|
+
try:
|
350
|
+
shutil.rmtree(cls.projects_dir)
|
351
|
+
logger.info("All projects have been removed.")
|
352
|
+
except Exception as e:
|
353
|
+
logger.error(f"Failed to remove projects directory: {e}")
|
354
|
+
else:
|
355
|
+
logger.warning("Projects directory does not exist.")
|
356
|
+
cls.projects_dir.mkdir(parents=True, exist_ok=True)
|
357
|
+
logger.info("Projects directory cleaned and recreated.")
|
358
|
+
|
359
|
+
@classmethod
|
360
|
+
def download_fema_ble_model(cls, huc8, output_dir=None):
|
361
|
+
"""
|
362
|
+
Download a FEMA Base Level Engineering (BLE) model for a given HUC8.
|
363
|
+
|
364
|
+
Args:
|
365
|
+
huc8 (str): The 8-digit Hydrologic Unit Code (HUC) for the desired watershed.
|
366
|
+
output_dir (str, optional): The directory to save the downloaded files. If None, uses the current working directory.
|
367
|
+
|
368
|
+
Returns:
|
369
|
+
str: The path to the downloaded and extracted model directory.
|
370
|
+
|
371
|
+
Note:
|
372
|
+
This method downloads the BLE model from the FEMA website and extracts it to the specified directory.
|
373
|
+
"""
|
374
|
+
# Method implementation...
|
375
|
+
|
376
|
+
@classmethod
|
377
|
+
def _make_safe_folder_name(cls, name: str) -> str:
|
378
|
+
"""
|
379
|
+
Convert a string to a safe folder name by replacing unsafe characters with underscores.
|
380
|
+
"""
|
381
|
+
safe_name = re.sub(r'[^a-zA-Z0-9_\-]', '_', name)
|
382
|
+
logger.debug(f"Converted '{name}' to safe folder name '{safe_name}'")
|
383
|
+
return safe_name
|
384
|
+
|
385
|
+
@classmethod
|
386
|
+
def _download_file_with_progress(cls, url: str, dest_folder: Path, file_size: int) -> Path:
|
387
|
+
"""
|
388
|
+
Download a file from a URL to a specified destination folder with progress bar.
|
389
|
+
"""
|
390
|
+
local_filename = dest_folder / url.split('/')[-1]
|
391
|
+
try:
|
392
|
+
with requests.get(url, stream=True) as r:
|
393
|
+
r.raise_for_status()
|
394
|
+
with open(local_filename, 'wb') as f, tqdm(
|
395
|
+
desc=local_filename.name,
|
396
|
+
total=file_size,
|
397
|
+
unit='iB',
|
398
|
+
unit_scale=True,
|
399
|
+
unit_divisor=1024,
|
400
|
+
) as progress_bar:
|
401
|
+
for chunk in r.iter_content(chunk_size=8192):
|
402
|
+
size = f.write(chunk)
|
403
|
+
progress_bar.update(size)
|
404
|
+
logger.info(f"Successfully downloaded {url} to {local_filename}")
|
405
|
+
return local_filename
|
406
|
+
except requests.exceptions.RequestException as e:
|
407
|
+
logger.error(f"Request failed for {url}: {e}")
|
408
|
+
raise
|
409
|
+
except Exception as e:
|
410
|
+
logger.error(f"Failed to write file {local_filename}: {e}")
|
411
|
+
raise
|
412
|
+
|
413
|
+
@classmethod
|
414
|
+
def _convert_size_to_bytes(cls, size_str: str) -> int:
|
415
|
+
"""
|
416
|
+
Convert a human-readable file size to bytes.
|
417
|
+
"""
|
418
|
+
units = {'B': 1, 'KB': 1024, 'MB': 1024**2, 'GB': 1024**3, 'TB': 1024**4}
|
419
|
+
size_str = size_str.upper().replace(' ', '')
|
420
|
+
if not re.match(r'^\d+(\.\d+)?[BKMGT]B?$', size_str):
|
421
|
+
raise ValueError(f"Invalid size string: {size_str}")
|
422
|
+
|
423
|
+
number, unit = float(re.findall(r'[\d\.]+', size_str)[0]), re.findall(r'[BKMGT]B?', size_str)[0]
|
395
424
|
return int(number * units[unit])
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: ras-commander
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.58.0
|
4
4
|
Summary: A Python library for automating HEC-RAS 6.x operations
|
5
5
|
Home-page: https://github.com/gpt-cmdr/ras-commander
|
6
|
-
Author: William M. Katzenmeyer
|
6
|
+
Author: William M. Katzenmeyer, P.E., C.F.M.
|
7
7
|
Author-email: heccommander@gmail.com
|
8
8
|
Requires-Python: >=3.10
|
9
9
|
Description-Content-Type: text/markdown
|
@@ -20,6 +20,7 @@ Requires-Dist: matplotlib
|
|
20
20
|
Requires-Dist: shapely
|
21
21
|
Requires-Dist: pathlib
|
22
22
|
Requires-Dist: rasterstats
|
23
|
+
Requires-Dist: rtree
|
23
24
|
Dynamic: author
|
24
25
|
Dynamic: author-email
|
25
26
|
Dynamic: description
|
@@ -33,16 +34,10 @@ Dynamic: summary
|
|
33
34
|
|
34
35
|
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 was initially conceptualized in the Australian Water School course "AI Tools for Modelling Innovation", and subsequently expanded to cover the basic functionality of the HECRASController COM32 interface using open-source python libraries. This library uses a Test Driven Development strategy, leveraging the publicly-available HEC-RAS Example projects to create repeatable demonstration examples. The "Commmander" moniker is inspired by the "Command Line is All You Need" approach to HEC-RAS automation that was first implemented in the HEC-Commander Tools repository.
|
35
36
|
|
36
|
-
##
|
37
|
-
William Katzenmeyer, P.E., C.F.M.
|
37
|
+
## Repository Author:
|
38
|
+
(William Katzenmeyer, P.E., C.F.M.)[https://engineeringwithllms.info]
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
Aaron Nichols, P.E., C.F.M.
|
42
|
-
|
43
|
-
(Additional Contributors Here)
|
44
|
-
|
45
|
-
## Don't Ask Me, Ask ChatGPT!
|
40
|
+
## Don't Ask Me, Ask GPT!
|
46
41
|
|
47
42
|
This repository has several methods of interaction with Large Language Models and LLM-Assisted Coding built right in:
|
48
43
|
|
@@ -159,8 +154,6 @@ results = RasCmdr.compute_parallel(
|
|
159
154
|
RasPlan.set_geom("01", "02")
|
160
155
|
```
|
161
156
|
|
162
|
-
Certainly! I'll provide you with an updated Key Components section and Project Organization diagram based on the current structure of the ras-commander library.
|
163
|
-
|
164
157
|
#### Key Components
|
165
158
|
|
166
159
|
- `RasPrj`: Manages HEC-RAS projects, handling initialization and data loading
|
@@ -254,7 +247,7 @@ ras_commander
|
|
254
247
|
|
255
248
|
### Accessing HEC Examples through RasExamples
|
256
249
|
|
257
|
-
The `RasExamples` class provides functionality for quickly loading and managing HEC-RAS example projects. This is particularly useful for testing and development purposes.
|
250
|
+
The `RasExamples` class provides functionality for quickly loading and managing HEC-RAS example projects. This is particularly useful for testing and development purposes. All examples in the ras-commander repository currently utilize HEC example projects to provide fully running scripts and notebooks for end user testing, demonstration and adaption.
|
258
251
|
|
259
252
|
Key features:
|
260
253
|
- Download and extract HEC-RAS example projects
|
@@ -266,8 +259,6 @@ Example usage:
|
|
266
259
|
from ras_commander import RasExamples
|
267
260
|
|
268
261
|
```
|
269
|
-
ras_examples = RasExamples()
|
270
|
-
ras_examples.get_example_projects() # Downloads example projects if not already present
|
271
262
|
categories = ras_examples.list_categories()
|
272
263
|
projects = ras_examples.list_projects("Steady Flow")
|
273
264
|
extracted_paths = ras_examples.extract_project(["Bald Eagle Creek", "Muncie"])
|
@@ -28,11 +28,11 @@ class CustomBuildPy(build_py):
|
|
28
28
|
|
29
29
|
setup(
|
30
30
|
name="ras-commander",
|
31
|
-
version="0.
|
31
|
+
version="0.58.0",
|
32
32
|
packages=find_packages(),
|
33
33
|
include_package_data=True,
|
34
34
|
python_requires='>=3.10',
|
35
|
-
author="William M. Katzenmeyer",
|
35
|
+
author="William M. Katzenmeyer, P.E., C.F.M.",
|
36
36
|
author_email="heccommander@gmail.com",
|
37
37
|
description="A Python library for automating HEC-RAS 6.x operations",
|
38
38
|
long_description=open('README.md').read(),
|
@@ -54,6 +54,7 @@ setup(
|
|
54
54
|
'shapely',
|
55
55
|
'pathlib',
|
56
56
|
'rasterstats',
|
57
|
+
'rtree',
|
57
58
|
])
|
58
59
|
|
59
60
|
"""
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|