ras-commander 0.45.0__py3-none-any.whl → 0.46.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ras_commander/HdfFluvialPluvial.py +317 -0
- ras_commander/HdfMesh.py +62 -15
- ras_commander/HdfPipe.py +587 -78
- ras_commander/HdfPlan.py +5 -0
- ras_commander/HdfPump.py +25 -11
- ras_commander/HdfResultsMesh.py +135 -62
- ras_commander/HdfResultsXsec.py +126 -297
- ras_commander/HdfStruc.py +148 -50
- ras_commander/HdfUtils.py +51 -0
- ras_commander/HdfXsec.py +467 -136
- ras_commander/RasPlan.py +298 -45
- ras_commander/RasToGo.py +21 -0
- ras_commander/RasUnsteady.py +615 -14
- ras_commander/__init__.py +3 -1
- {ras_commander-0.45.0.dist-info → ras_commander-0.46.0.dist-info}/METADATA +1 -1
- ras_commander-0.46.0.dist-info/RECORD +30 -0
- {ras_commander-0.45.0.dist-info → ras_commander-0.46.0.dist-info}/WHEEL +1 -1
- ras_commander-0.45.0.dist-info/RECORD +0 -28
- {ras_commander-0.45.0.dist-info → ras_commander-0.46.0.dist-info}/LICENSE +0 -0
- {ras_commander-0.45.0.dist-info → ras_commander-0.46.0.dist-info}/top_level.txt +0 -0
ras_commander/RasUnsteady.py
CHANGED
@@ -27,6 +27,12 @@ from pathlib import Path
|
|
27
27
|
from .RasPrj import ras
|
28
28
|
from .LoggingConfig import get_logger
|
29
29
|
from .Decorators import log_call
|
30
|
+
import pandas as pd
|
31
|
+
import numpy as np
|
32
|
+
import re
|
33
|
+
from typing import Union, Optional, Any, Tuple, Dict, List
|
34
|
+
|
35
|
+
|
30
36
|
|
31
37
|
logger = get_logger(__name__)
|
32
38
|
|
@@ -36,16 +42,89 @@ class RasUnsteady:
|
|
36
42
|
"""
|
37
43
|
Class for all operations related to HEC-RAS unsteady flow files.
|
38
44
|
"""
|
45
|
+
@staticmethod
|
46
|
+
@log_call
|
47
|
+
def update_flow_title(unsteady_file: str, new_title: str, ras_object: Optional[Any] = None) -> None:
|
48
|
+
"""
|
49
|
+
Update the Flow Title in an unsteady flow file.
|
50
|
+
|
51
|
+
Parameters:
|
52
|
+
unsteady_file (str): Full path to the unsteady flow file
|
53
|
+
new_title (str): New flow title (max 24 characters)
|
54
|
+
ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
None
|
58
|
+
|
59
|
+
Note:
|
60
|
+
This function updates the ras object's unsteady dataframe after modifying the unsteady flow file.
|
61
|
+
|
62
|
+
Example:
|
63
|
+
from ras_commander import RasCmdr
|
64
|
+
|
65
|
+
# Initialize RAS project
|
66
|
+
ras_cmdr = RasCmdr()
|
67
|
+
ras_cmdr.init_ras_project(project_folder, ras_version)
|
68
|
+
|
69
|
+
# Update flow title
|
70
|
+
unsteady_file = r"path/to/unsteady_file.u01"
|
71
|
+
new_title = "New Flow Title"
|
72
|
+
RasUnsteady.update_flow_title(unsteady_file, new_title, ras_object=ras_cmdr.ras)
|
73
|
+
"""
|
74
|
+
ras_obj = ras_object or ras
|
75
|
+
ras_obj.check_initialized()
|
76
|
+
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
77
|
+
|
78
|
+
unsteady_path = Path(unsteady_file)
|
79
|
+
new_title = new_title[:24] # Truncate to 24 characters if longer
|
80
|
+
|
81
|
+
try:
|
82
|
+
with open(unsteady_path, 'r') as f:
|
83
|
+
lines = f.readlines()
|
84
|
+
logger.debug(f"Successfully read unsteady flow file: {unsteady_path}")
|
85
|
+
except FileNotFoundError:
|
86
|
+
logger.error(f"Unsteady flow file not found: {unsteady_path}")
|
87
|
+
raise FileNotFoundError(f"Unsteady flow file not found: {unsteady_path}")
|
88
|
+
except PermissionError:
|
89
|
+
logger.error(f"Permission denied when reading unsteady flow file: {unsteady_path}")
|
90
|
+
raise PermissionError(f"Permission denied when reading unsteady flow file: {unsteady_path}")
|
91
|
+
|
92
|
+
updated = False
|
93
|
+
for i, line in enumerate(lines):
|
94
|
+
if line.startswith("Flow Title="):
|
95
|
+
old_title = line.strip().split('=')[1]
|
96
|
+
lines[i] = f"Flow Title={new_title}\n"
|
97
|
+
updated = True
|
98
|
+
logger.info(f"Updated Flow Title from '{old_title}' to '{new_title}'")
|
99
|
+
break
|
100
|
+
|
101
|
+
if updated:
|
102
|
+
try:
|
103
|
+
with open(unsteady_path, 'w') as f:
|
104
|
+
f.writelines(lines)
|
105
|
+
logger.debug(f"Successfully wrote modifications to unsteady flow file: {unsteady_path}")
|
106
|
+
except PermissionError:
|
107
|
+
logger.error(f"Permission denied when writing to unsteady flow file: {unsteady_path}")
|
108
|
+
raise PermissionError(f"Permission denied when writing to unsteady flow file: {unsteady_path}")
|
109
|
+
except IOError as e:
|
110
|
+
logger.error(f"Error writing to unsteady flow file: {unsteady_path}. {str(e)}")
|
111
|
+
raise IOError(f"Error writing to unsteady flow file: {unsteady_path}. {str(e)}")
|
112
|
+
logger.info(f"Applied Flow Title modification to {unsteady_file}")
|
113
|
+
else:
|
114
|
+
logger.warning(f"Flow Title not found in {unsteady_file}")
|
39
115
|
|
116
|
+
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
117
|
+
|
40
118
|
@staticmethod
|
41
119
|
@log_call
|
42
|
-
def
|
120
|
+
def update_restart_settings(unsteady_file: str, use_restart: bool, restart_filename: Optional[str] = None, ras_object: Optional[Any] = None) -> None:
|
43
121
|
"""
|
44
|
-
|
122
|
+
Update the Use Restart settings in an unsteady flow file.
|
45
123
|
|
46
124
|
Parameters:
|
47
125
|
unsteady_file (str): Full path to the unsteady flow file
|
48
|
-
|
126
|
+
use_restart (bool): Whether to use restart (True) or not (False)
|
127
|
+
restart_filename (str, optional): Name of the restart file (required if use_restart is True)
|
49
128
|
ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
|
50
129
|
|
51
130
|
Returns:
|
@@ -61,16 +140,16 @@ class RasUnsteady:
|
|
61
140
|
ras_cmdr = RasCmdr()
|
62
141
|
ras_cmdr.init_ras_project(project_folder, ras_version)
|
63
142
|
|
64
|
-
# Update
|
143
|
+
# Update restart settings
|
65
144
|
unsteady_file = r"path/to/unsteady_file.u01"
|
66
|
-
|
67
|
-
RasUnsteady.update_unsteady_parameters(unsteady_file, modifications, ras_object=ras_cmdr.ras)
|
145
|
+
RasUnsteady.update_restart_settings(unsteady_file, True, "restartfile.rst", ras_object=ras_cmdr.ras)
|
68
146
|
"""
|
69
147
|
ras_obj = ras_object or ras
|
70
148
|
ras_obj.check_initialized()
|
71
149
|
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
72
150
|
|
73
151
|
unsteady_path = Path(unsteady_file)
|
152
|
+
|
74
153
|
try:
|
75
154
|
with open(unsteady_path, 'r') as f:
|
76
155
|
lines = f.readlines()
|
@@ -83,13 +162,26 @@ class RasUnsteady:
|
|
83
162
|
raise PermissionError(f"Permission denied when reading unsteady flow file: {unsteady_path}")
|
84
163
|
|
85
164
|
updated = False
|
165
|
+
restart_line_index = None
|
86
166
|
for i, line in enumerate(lines):
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
167
|
+
if line.startswith("Use Restart="):
|
168
|
+
restart_line_index = i
|
169
|
+
old_value = line.strip().split('=')[1]
|
170
|
+
new_value = "-1" if use_restart else "0"
|
171
|
+
lines[i] = f"Use Restart={new_value}\n"
|
172
|
+
updated = True
|
173
|
+
logger.info(f"Updated Use Restart from {old_value} to {new_value}")
|
174
|
+
break
|
175
|
+
|
176
|
+
if use_restart:
|
177
|
+
if not restart_filename:
|
178
|
+
logger.error("Restart filename must be specified when enabling restart.")
|
179
|
+
raise ValueError("Restart filename must be specified when enabling restart.")
|
180
|
+
if restart_line_index is not None:
|
181
|
+
lines.insert(restart_line_index + 1, f"Restart Filename={restart_filename}\n")
|
182
|
+
logger.info(f"Added Restart Filename: {restart_filename}")
|
183
|
+
else:
|
184
|
+
logger.warning("Could not find 'Use Restart' line to insert 'Restart Filename'")
|
93
185
|
|
94
186
|
if updated:
|
95
187
|
try:
|
@@ -102,8 +194,517 @@ class RasUnsteady:
|
|
102
194
|
except IOError as e:
|
103
195
|
logger.error(f"Error writing to unsteady flow file: {unsteady_path}. {str(e)}")
|
104
196
|
raise IOError(f"Error writing to unsteady flow file: {unsteady_path}. {str(e)}")
|
105
|
-
logger.info(f"Applied
|
197
|
+
logger.info(f"Applied restart settings modification to {unsteady_file}")
|
106
198
|
else:
|
107
|
-
logger.warning(f"
|
199
|
+
logger.warning(f"Use Restart setting not found in {unsteady_file}")
|
108
200
|
|
109
201
|
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
202
|
+
|
203
|
+
@staticmethod
|
204
|
+
@log_call
|
205
|
+
def extract_boundary_and_tables(unsteady_file: str, ras_object: Optional[Any] = None) -> pd.DataFrame:
|
206
|
+
"""
|
207
|
+
Extracts Boundary Location blocks, DSS File entries, and their associated
|
208
|
+
fixed-width tables from the specified unsteady file.
|
209
|
+
"""
|
210
|
+
ras_obj = ras_object or ras
|
211
|
+
ras_obj.check_initialized()
|
212
|
+
|
213
|
+
unsteady_path = Path(unsteady_file)
|
214
|
+
table_types = [
|
215
|
+
'Flow Hydrograph=',
|
216
|
+
'Gate Openings=',
|
217
|
+
'Stage Hydrograph=',
|
218
|
+
'Uniform Lateral Inflow=',
|
219
|
+
'Lateral Inflow Hydrograph='
|
220
|
+
]
|
221
|
+
|
222
|
+
try:
|
223
|
+
with open(unsteady_path, 'r') as file:
|
224
|
+
lines = file.readlines()
|
225
|
+
logger.debug(f"Successfully read unsteady flow file: {unsteady_path}")
|
226
|
+
except FileNotFoundError:
|
227
|
+
logger.error(f"Unsteady flow file not found: {unsteady_path}")
|
228
|
+
raise
|
229
|
+
except PermissionError:
|
230
|
+
logger.error(f"Permission denied when reading unsteady flow file: {unsteady_path}")
|
231
|
+
raise
|
232
|
+
|
233
|
+
# Initialize variables
|
234
|
+
boundary_data = []
|
235
|
+
current_boundary = None
|
236
|
+
current_tables = {}
|
237
|
+
current_table = None
|
238
|
+
table_values = []
|
239
|
+
|
240
|
+
i = 0
|
241
|
+
while i < len(lines):
|
242
|
+
line = lines[i].strip()
|
243
|
+
|
244
|
+
# Check for Boundary Location line
|
245
|
+
if line.startswith("Boundary Location="):
|
246
|
+
# Save previous boundary if it exists
|
247
|
+
if current_boundary is not None:
|
248
|
+
if current_table and table_values:
|
249
|
+
# Process any remaining table
|
250
|
+
try:
|
251
|
+
df = pd.DataFrame({'Value': table_values})
|
252
|
+
current_tables[current_table_name] = df
|
253
|
+
except Exception as e:
|
254
|
+
logger.warning(f"Error processing table {current_table_name}: {e}")
|
255
|
+
current_boundary['Tables'] = current_tables
|
256
|
+
boundary_data.append(current_boundary)
|
257
|
+
|
258
|
+
# Start new boundary
|
259
|
+
current_boundary = {
|
260
|
+
'Boundary Location': line.split('=', 1)[1].strip(),
|
261
|
+
'DSS File': '',
|
262
|
+
'Tables': {}
|
263
|
+
}
|
264
|
+
current_tables = {}
|
265
|
+
current_table = None
|
266
|
+
table_values = []
|
267
|
+
|
268
|
+
# Check for DSS File line
|
269
|
+
elif line.startswith("DSS File=") and current_boundary is not None:
|
270
|
+
current_boundary['DSS File'] = line.split('=', 1)[1].strip()
|
271
|
+
|
272
|
+
# Check for table headers
|
273
|
+
elif any(line.startswith(t) for t in table_types) and current_boundary is not None:
|
274
|
+
# If we were processing a table, save it
|
275
|
+
if current_table and table_values:
|
276
|
+
try:
|
277
|
+
df = pd.DataFrame({'Value': table_values})
|
278
|
+
current_tables[current_table_name] = df
|
279
|
+
except Exception as e:
|
280
|
+
logger.warning(f"Error processing previous table: {e}")
|
281
|
+
|
282
|
+
# Start new table
|
283
|
+
try:
|
284
|
+
current_table = line.split('=')
|
285
|
+
current_table_name = current_table[0].strip()
|
286
|
+
num_values = int(current_table[1])
|
287
|
+
table_values = []
|
288
|
+
|
289
|
+
# Read the table values
|
290
|
+
rows_needed = (num_values + 9) // 10 # Round up division
|
291
|
+
for _ in range(rows_needed):
|
292
|
+
i += 1
|
293
|
+
if i >= len(lines):
|
294
|
+
break
|
295
|
+
row = lines[i].strip()
|
296
|
+
# Parse fixed-width values (8 characters each)
|
297
|
+
j = 0
|
298
|
+
while j < len(row):
|
299
|
+
value_str = row[j:j+8].strip()
|
300
|
+
if value_str:
|
301
|
+
try:
|
302
|
+
value = float(value_str)
|
303
|
+
table_values.append(value)
|
304
|
+
except ValueError:
|
305
|
+
# Try splitting merged values
|
306
|
+
parts = re.findall(r'-?\d+\.?\d*', value_str)
|
307
|
+
table_values.extend([float(p) for p in parts])
|
308
|
+
j += 8
|
309
|
+
|
310
|
+
except (ValueError, IndexError) as e:
|
311
|
+
logger.error(f"Error processing table at line {i}: {e}")
|
312
|
+
current_table = None
|
313
|
+
|
314
|
+
i += 1
|
315
|
+
|
316
|
+
# Add the last boundary if it exists
|
317
|
+
if current_boundary is not None:
|
318
|
+
if current_table and table_values:
|
319
|
+
try:
|
320
|
+
df = pd.DataFrame({'Value': table_values})
|
321
|
+
current_tables[current_table_name] = df
|
322
|
+
except Exception as e:
|
323
|
+
logger.warning(f"Error processing final table: {e}")
|
324
|
+
current_boundary['Tables'] = current_tables
|
325
|
+
boundary_data.append(current_boundary)
|
326
|
+
|
327
|
+
# Create DataFrame
|
328
|
+
boundaries_df = pd.DataFrame(boundary_data)
|
329
|
+
if not boundaries_df.empty:
|
330
|
+
# Split boundary location into components
|
331
|
+
location_columns = ['River Name', 'Reach Name', 'River Station',
|
332
|
+
'Downstream River Station', 'Storage Area Connection',
|
333
|
+
'Storage Area Name', 'Pump Station Name',
|
334
|
+
'Blank 1', 'Blank 2']
|
335
|
+
split_locations = boundaries_df['Boundary Location'].str.split(',', expand=True)
|
336
|
+
# Ensure we have the right number of columns
|
337
|
+
for i, col in enumerate(location_columns):
|
338
|
+
if i < split_locations.shape[1]:
|
339
|
+
boundaries_df[col] = split_locations[i].str.strip()
|
340
|
+
else:
|
341
|
+
boundaries_df[col] = ''
|
342
|
+
boundaries_df = boundaries_df.drop(columns=['Boundary Location'])
|
343
|
+
|
344
|
+
logger.info(f"Successfully extracted boundaries and tables from {unsteady_path}")
|
345
|
+
return boundaries_df
|
346
|
+
|
347
|
+
@staticmethod
|
348
|
+
@log_call
|
349
|
+
def print_boundaries_and_tables(boundaries_df: pd.DataFrame) -> None:
|
350
|
+
"""
|
351
|
+
Prints the boundaries and their associated tables from the extracted DataFrame.
|
352
|
+
|
353
|
+
Parameters:
|
354
|
+
- boundaries_df: DataFrame containing boundary information and nested tables data
|
355
|
+
"""
|
356
|
+
pd.set_option('display.max_columns', None)
|
357
|
+
pd.set_option('display.max_rows', None)
|
358
|
+
print("\nBoundaries and Tablesin boundaries_df:")
|
359
|
+
for idx, row in boundaries_df.iterrows():
|
360
|
+
print(f"\nBoundary {idx+1}:")
|
361
|
+
print(f"River Name: {row['River Name']}")
|
362
|
+
print(f"Reach Name: {row['Reach Name']}")
|
363
|
+
print(f"River Station: {row['River Station']}")
|
364
|
+
print(f"DSS File: {row['DSS File']}")
|
365
|
+
|
366
|
+
if row['Tables']:
|
367
|
+
print("\nTables for this boundary:")
|
368
|
+
for table_name, table_df in row['Tables'].items():
|
369
|
+
print(f"\n{table_name}:")
|
370
|
+
print(table_df.to_string())
|
371
|
+
print("-" * 80)
|
372
|
+
|
373
|
+
|
374
|
+
|
375
|
+
|
376
|
+
|
377
|
+
# Additional functions from the AWS webinar where the code was developed
|
378
|
+
# Need to add examples
|
379
|
+
|
380
|
+
@staticmethod
|
381
|
+
@log_call
|
382
|
+
def identify_tables(lines: List[str]) -> List[Tuple[str, int, int]]:
|
383
|
+
"""
|
384
|
+
Identify the start and end of each table in the unsteady flow file.
|
385
|
+
|
386
|
+
Parameters:
|
387
|
+
lines (List[str]): List of file lines
|
388
|
+
|
389
|
+
Returns:
|
390
|
+
List[Tuple[str, int, int]]: List of tuples containing (table_name, start_line, end_line)
|
391
|
+
"""
|
392
|
+
table_types = [
|
393
|
+
'Flow Hydrograph=',
|
394
|
+
'Gate Openings=',
|
395
|
+
'Stage Hydrograph=',
|
396
|
+
'Uniform Lateral Inflow=',
|
397
|
+
'Lateral Inflow Hydrograph='
|
398
|
+
]
|
399
|
+
tables = []
|
400
|
+
current_table = None
|
401
|
+
|
402
|
+
for i, line in enumerate(lines):
|
403
|
+
if any(table_type in line for table_type in table_types):
|
404
|
+
if current_table:
|
405
|
+
tables.append((current_table[0], current_table[1], i-1))
|
406
|
+
table_name = line.strip().split('=')[0] + '='
|
407
|
+
try:
|
408
|
+
num_values = int(line.strip().split('=')[1])
|
409
|
+
current_table = (table_name, i+1, num_values)
|
410
|
+
except (ValueError, IndexError) as e:
|
411
|
+
logger.error(f"Error parsing table header at line {i}: {e}")
|
412
|
+
continue
|
413
|
+
|
414
|
+
if current_table:
|
415
|
+
tables.append((current_table[0], current_table[1],
|
416
|
+
current_table[1] + (current_table[2] + 9) // 10))
|
417
|
+
|
418
|
+
logger.debug(f"Identified {len(tables)} tables in the file")
|
419
|
+
return tables
|
420
|
+
|
421
|
+
@staticmethod
|
422
|
+
@log_call
|
423
|
+
def parse_fixed_width_table(lines: List[str], start: int, end: int) -> pd.DataFrame:
|
424
|
+
"""
|
425
|
+
Parse a fixed-width table into a pandas DataFrame.
|
426
|
+
|
427
|
+
Parameters:
|
428
|
+
lines (List[str]): List of file lines
|
429
|
+
start (int): Starting line number for table
|
430
|
+
end (int): Ending line number for table
|
431
|
+
|
432
|
+
Returns:
|
433
|
+
pd.DataFrame: DataFrame containing parsed table values
|
434
|
+
"""
|
435
|
+
data = []
|
436
|
+
for line in lines[start:end]:
|
437
|
+
# Split the line into 8-character columns
|
438
|
+
values = [line[i:i+8].strip() for i in range(0, len(line), 8)]
|
439
|
+
# Convert to float and handle cases where values are run together
|
440
|
+
parsed_values = []
|
441
|
+
for value in values:
|
442
|
+
try:
|
443
|
+
if len(value) > 8: # If values are run together
|
444
|
+
parts = re.findall(r'-?\d+\.?\d*', value)
|
445
|
+
parsed_values.extend([float(p) for p in parts])
|
446
|
+
elif value: # Only add non-empty values
|
447
|
+
parsed_values.append(float(value))
|
448
|
+
except ValueError as e:
|
449
|
+
logger.warning(f"Could not parse value '{value}': {e}")
|
450
|
+
continue
|
451
|
+
data.extend(parsed_values)
|
452
|
+
|
453
|
+
return pd.DataFrame(data, columns=['Value'])
|
454
|
+
|
455
|
+
@staticmethod
|
456
|
+
@log_call
|
457
|
+
def extract_tables(unsteady_file: str, ras_object: Optional[Any] = None) -> Dict[str, pd.DataFrame]:
|
458
|
+
"""
|
459
|
+
Extract all tables from the unsteady file and return them as DataFrames.
|
460
|
+
|
461
|
+
Parameters:
|
462
|
+
unsteady_file (str): Path to the unsteady flow file
|
463
|
+
ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
|
464
|
+
|
465
|
+
Returns:
|
466
|
+
Dict[str, pd.DataFrame]: Dictionary of table names to DataFrames
|
467
|
+
"""
|
468
|
+
ras_obj = ras_object or ras
|
469
|
+
ras_obj.check_initialized()
|
470
|
+
|
471
|
+
unsteady_path = Path(unsteady_file)
|
472
|
+
try:
|
473
|
+
with open(unsteady_path, 'r') as file:
|
474
|
+
lines = file.readlines()
|
475
|
+
logger.debug(f"Successfully read unsteady flow file: {unsteady_path}")
|
476
|
+
except FileNotFoundError:
|
477
|
+
logger.error(f"Unsteady flow file not found: {unsteady_path}")
|
478
|
+
raise
|
479
|
+
except PermissionError:
|
480
|
+
logger.error(f"Permission denied when reading unsteady flow file: {unsteady_path}")
|
481
|
+
raise
|
482
|
+
|
483
|
+
tables = RasBndry.identify_tables(lines)
|
484
|
+
extracted_tables = {}
|
485
|
+
|
486
|
+
for table_name, start, end in tables:
|
487
|
+
df = RasBndry.parse_fixed_width_table(lines, start, end)
|
488
|
+
extracted_tables[table_name] = df
|
489
|
+
logger.debug(f"Extracted table '{table_name}' with {len(df)} values")
|
490
|
+
|
491
|
+
return extracted_tables
|
492
|
+
|
493
|
+
@staticmethod
|
494
|
+
@log_call
|
495
|
+
def write_table_to_file(unsteady_file: str, table_name: str, df: pd.DataFrame,
|
496
|
+
start_line: int, ras_object: Optional[Any] = None) -> None:
|
497
|
+
"""
|
498
|
+
Write updated table back to file in fixed-width format.
|
499
|
+
|
500
|
+
Parameters:
|
501
|
+
unsteady_file (str): Path to the unsteady flow file
|
502
|
+
table_name (str): Name of the table to update
|
503
|
+
df (pd.DataFrame): DataFrame containing the updated values
|
504
|
+
start_line (int): Line number where the table starts
|
505
|
+
ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
|
506
|
+
"""
|
507
|
+
ras_obj = ras_object or ras
|
508
|
+
ras_obj.check_initialized()
|
509
|
+
|
510
|
+
unsteady_path = Path(unsteady_file)
|
511
|
+
try:
|
512
|
+
with open(unsteady_path, 'r') as file:
|
513
|
+
lines = file.readlines()
|
514
|
+
logger.debug(f"Successfully read unsteady flow file: {unsteady_path}")
|
515
|
+
except FileNotFoundError:
|
516
|
+
logger.error(f"Unsteady flow file not found: {unsteady_path}")
|
517
|
+
raise
|
518
|
+
except PermissionError:
|
519
|
+
logger.error(f"Permission denied when reading unsteady flow file: {unsteady_path}")
|
520
|
+
raise
|
521
|
+
|
522
|
+
# Format values into fixed-width strings
|
523
|
+
formatted_values = []
|
524
|
+
for i in range(0, len(df), 10):
|
525
|
+
row = df['Value'].iloc[i:i+10]
|
526
|
+
formatted_row = ''.join(f'{value:8.0f}' for value in row)
|
527
|
+
formatted_values.append(formatted_row + '\n')
|
528
|
+
|
529
|
+
# Replace old table with new formatted values
|
530
|
+
lines[start_line:start_line+len(formatted_values)] = formatted_values
|
531
|
+
|
532
|
+
try:
|
533
|
+
with open(unsteady_path, 'w') as file:
|
534
|
+
file.writelines(lines)
|
535
|
+
logger.info(f"Successfully updated table '{table_name}' in {unsteady_path}")
|
536
|
+
except PermissionError:
|
537
|
+
logger.error(f"Permission denied when writing to unsteady flow file: {unsteady_path}")
|
538
|
+
raise
|
539
|
+
except IOError as e:
|
540
|
+
logger.error(f"Error writing to unsteady flow file: {unsteady_path}. {str(e)}")
|
541
|
+
raise
|
542
|
+
|
543
|
+
|
544
|
+
|
545
|
+
|
546
|
+
|
547
|
+
|
548
|
+
|
549
|
+
|
550
|
+
'''
|
551
|
+
|
552
|
+
|
553
|
+
|
554
|
+
Flow Title=Single 2D Area with Bridges
|
555
|
+
Program Version=6.60
|
556
|
+
Use Restart= 0
|
557
|
+
Boundary Location= , , , , ,BaldEagleCr , ,DSNormalDepth ,
|
558
|
+
Friction Slope=0.0003,0
|
559
|
+
Boundary Location= , , , , ,BaldEagleCr , ,DS2NormalD ,
|
560
|
+
Friction Slope=0.0003,0
|
561
|
+
Boundary Location= , , , , ,BaldEagleCr , ,Upstream Inflow ,
|
562
|
+
Interval=1HOUR
|
563
|
+
Flow Hydrograph= 200
|
564
|
+
1000 3000 6500 8000 9500 11000 12500 14000 15500 17000
|
565
|
+
18500 20000 22000 24000 26000 28000 30000 34000 38000 42000
|
566
|
+
46000 50000 54000 58000 62000 66000 70000 73000 76000 79000
|
567
|
+
82000 85000 87200 89400 91600 93800 96000 96800 97600 98400
|
568
|
+
99200 100000 99600 99200 98800 98400 98000 96400 94800 93200
|
569
|
+
91600 90000 88500 87000 85500 84000 82500 81000 79500 78000
|
570
|
+
76500 75000 73500 7200070666.6669333.34 6800066666.6665333.33 64000
|
571
|
+
62666.6761333.33 6000058666.6757333.33 5600054666.6753333.33 5200050666.67
|
572
|
+
49333.33 4800046666.6745333.33 4400042666.6741333.33 4000039166.6738333.33
|
573
|
+
3750036666.6735833.33 3500034166.6733333.33 3250031666.6730833.33 30000
|
574
|
+
29166.6728333.33 2750026666.6725833.33 2500024166.6723333.33 2250021666.67
|
575
|
+
20833.33 2000019655.1719310.3518965.5218620.6918275.8617931.0417586.2117241.38
|
576
|
+
16896.5516551.72 16206.915862.0715517.2415172.4114827.5914482.7614137.93 13793.1
|
577
|
+
13448.2813103.4512758.6212413.7912068.9711724.1411379.3111034.4810689.6610344.83
|
578
|
+
10000 9915.25 9830.51 9745.76 9661.02 9576.27 9491.53 9406.78 9322.03 9237.29
|
579
|
+
9152.54 9067.8 8983.05 8898.31 8813.56 8728.81 8644.07 8559.32 8474.58 8389.83
|
580
|
+
8305.09 8220.34 8135.59 8050.85 7966.1 7881.36 7796.61 7711.86 7627.12 7542.37
|
581
|
+
7457.63 7372.88 7288.14 7203.39 7118.64 7033.9 6949.15 6864.41 6779.66 6694.92
|
582
|
+
6610.17 6525.42 6440.68 6355.93 6271.19 6186.44 6101.7 6016.95 5932.2 5847.46
|
583
|
+
5762.71 5677.97 5593.22 5508.48 5423.73 5338.98 5254.24 5169.49 5084.75 5000
|
584
|
+
Stage Hydrograph TW Check=0
|
585
|
+
Flow Hydrograph QMult= 0.5
|
586
|
+
Flow Hydrograph Slope= 0.0005
|
587
|
+
DSS Path=
|
588
|
+
Use DSS=False
|
589
|
+
Use Fixed Start Time=False
|
590
|
+
Fixed Start Date/Time=,
|
591
|
+
Is Critical Boundary=False
|
592
|
+
Critical Boundary Flow=
|
593
|
+
Boundary Location= , , , ,Sayers Dam , , , ,
|
594
|
+
Gate Name=Gate #1
|
595
|
+
Gate DSS Path=
|
596
|
+
Gate Use DSS=False
|
597
|
+
Gate Time Interval=1HOUR
|
598
|
+
Gate Use Fixed Start Time=False
|
599
|
+
Gate Fixed Start Date/Time=,
|
600
|
+
Gate Openings= 100
|
601
|
+
2 2 2 2 2 2 2 2 2 2
|
602
|
+
2 2 2 2 2 2 2 2 2 2
|
603
|
+
2 2 2 2 2 2 2 2 2 2
|
604
|
+
2 2 2 2 2 2 2 2 2 2
|
605
|
+
2 2 2 2 2 2 2 2 2 2
|
606
|
+
2 2 2 2 2 2 2 2 2 2
|
607
|
+
2 2 2 2 2 2 2 2 2 2
|
608
|
+
2 2 2 2 2 2 2 2 2 2
|
609
|
+
2 2 2 2 2 2 2 2 2 2
|
610
|
+
2 2 2 2 2 2 2 2 2 2
|
611
|
+
Boundary Location= , , , , ,BaldEagleCr , ,DS2NormalDepth ,
|
612
|
+
Friction Slope=0.0003,0
|
613
|
+
Met Point Raster Parameters=,,,,
|
614
|
+
Precipitation Mode=Disable
|
615
|
+
Wind Mode=No Wind Forces
|
616
|
+
Air Density Mode=
|
617
|
+
Wave Mode=No Wave Forcing
|
618
|
+
Met BC=Precipitation|Expanded View=0
|
619
|
+
Met BC=Precipitation|Point Interpolation=Nearest
|
620
|
+
Met BC=Precipitation|Gridded Source=DSS
|
621
|
+
Met BC=Precipitation|Gridded Interpolation=
|
622
|
+
Met BC=Evapotranspiration|Expanded View=0
|
623
|
+
Met BC=Evapotranspiration|Point Interpolation=Nearest
|
624
|
+
Met BC=Evapotranspiration|Gridded Source=DSS
|
625
|
+
Met BC=Evapotranspiration|Gridded Interpolation=
|
626
|
+
Met BC=Wind Speed|Expanded View=0
|
627
|
+
Met BC=Wind Speed|Constant Units=ft/s
|
628
|
+
Met BC=Wind Speed|Point Interpolation=Nearest
|
629
|
+
Met BC=Wind Speed|Gridded Source=DSS
|
630
|
+
Met BC=Wind Speed|Gridded Interpolation=
|
631
|
+
Met BC=Wind Direction|Expanded View=0
|
632
|
+
Met BC=Wind Direction|Point Interpolation=Nearest
|
633
|
+
Met BC=Wind Direction|Gridded Source=DSS
|
634
|
+
Met BC=Wind Direction|Gridded Interpolation=
|
635
|
+
Met BC=Wind Velocity X|Expanded View=0
|
636
|
+
Met BC=Wind Velocity X|Constant Units=ft/s
|
637
|
+
Met BC=Wind Velocity X|Point Interpolation=Nearest
|
638
|
+
Met BC=Wind Velocity X|Gridded Source=DSS
|
639
|
+
Met BC=Wind Velocity X|Gridded Interpolation=
|
640
|
+
Met BC=Wind Velocity Y|Expanded View=0
|
641
|
+
Met BC=Wind Velocity Y|Constant Units=ft/s
|
642
|
+
Met BC=Wind Velocity Y|Point Interpolation=Nearest
|
643
|
+
Met BC=Wind Velocity Y|Gridded Source=DSS
|
644
|
+
Met BC=Wind Velocity Y|Gridded Interpolation=
|
645
|
+
Met BC=Wave Forcing X|Expanded View=0
|
646
|
+
Met BC=Wave Forcing X|Point Interpolation=Nearest
|
647
|
+
Met BC=Wave Forcing X|Gridded Source=DSS
|
648
|
+
Met BC=Wave Forcing X|Gridded Interpolation=
|
649
|
+
Met BC=Wave Forcing Y|Expanded View=0
|
650
|
+
Met BC=Wave Forcing Y|Point Interpolation=Nearest
|
651
|
+
Met BC=Wave Forcing Y|Gridded Source=DSS
|
652
|
+
Met BC=Wave Forcing Y|Gridded Interpolation=
|
653
|
+
Met BC=Air Density|Mode=Constant
|
654
|
+
Met BC=Air Density|Expanded View=0
|
655
|
+
Met BC=Air Density|Constant Value=1.225
|
656
|
+
Met BC=Air Density|Constant Units=kg/m3
|
657
|
+
Met BC=Air Density|Point Interpolation=Nearest
|
658
|
+
Met BC=Air Density|Gridded Source=DSS
|
659
|
+
Met BC=Air Density|Gridded Interpolation=
|
660
|
+
Met BC=Air Temperature|Expanded View=0
|
661
|
+
Met BC=Air Temperature|Point Interpolation=Nearest
|
662
|
+
Met BC=Air Temperature|Gridded Source=DSS
|
663
|
+
Met BC=Air Temperature|Gridded Interpolation=
|
664
|
+
Met BC=Humidity|Expanded View=0
|
665
|
+
Met BC=Humidity|Point Interpolation=Nearest
|
666
|
+
Met BC=Humidity|Gridded Source=DSS
|
667
|
+
Met BC=Humidity|Gridded Interpolation=
|
668
|
+
Met BC=Air Pressure|Mode=Constant
|
669
|
+
Met BC=Air Pressure|Expanded View=0
|
670
|
+
Met BC=Air Pressure|Constant Value=1013.2
|
671
|
+
Met BC=Air Pressure|Constant Units=mb
|
672
|
+
Met BC=Air Pressure|Point Interpolation=Nearest
|
673
|
+
Met BC=Air Pressure|Gridded Source=DSS
|
674
|
+
Met BC=Air Pressure|Gridded Interpolation=
|
675
|
+
Non-Newtonian Method= 0 ,
|
676
|
+
Non-Newtonian Constant Vol Conc=0
|
677
|
+
Non-Newtonian Yield Method= 0 ,
|
678
|
+
Non-Newtonian Yield Coef=0, 0
|
679
|
+
User Yeild= 0
|
680
|
+
Non-Newtonian Sed Visc= 0 ,
|
681
|
+
Non-Newtonian Obrian B=0
|
682
|
+
User Viscosity=0
|
683
|
+
User Viscosity Ratio=0
|
684
|
+
Herschel-Bulkley Coef=0, 0
|
685
|
+
Clastic Method= 0 ,
|
686
|
+
Coulomb Phi=0
|
687
|
+
Voellmy X=0
|
688
|
+
Non-Newtonian Hindered FV= 0
|
689
|
+
Non-Newtonian FV K=0
|
690
|
+
Non-Newtonian ds=0
|
691
|
+
Non-Newtonian Max Cv=0
|
692
|
+
Non-Newtonian Bulking Method= 0 ,
|
693
|
+
Non-Newtonian High C Transport= 0 ,
|
694
|
+
Lava Activation= 0
|
695
|
+
Temperature=1300,15,,15,14,980
|
696
|
+
Heat Ballance=1,1200,0.5,1,70,0.95
|
697
|
+
Viscosity=1000,,,
|
698
|
+
Yield Strength=,,,
|
699
|
+
Consistency Factor=,,,
|
700
|
+
Profile Coefficient=4,1.3,
|
701
|
+
Lava Param=,2500,
|
702
|
+
|
703
|
+
|
704
|
+
|
705
|
+
|
706
|
+
'''
|
707
|
+
|
708
|
+
|
709
|
+
|
710
|
+
|
ras_commander/__init__.py
CHANGED
@@ -19,7 +19,9 @@ from .RasUnsteady import RasUnsteady
|
|
19
19
|
from .RasUtils import RasUtils
|
20
20
|
from .RasExamples import RasExamples
|
21
21
|
from .RasCmdr import RasCmdr
|
22
|
-
from .RasGpt import RasGpt
|
22
|
+
from .RasGpt import RasGpt
|
23
|
+
from .RasToGo import RasToGo
|
24
|
+
from .HdfFluvialPluvial import HdfFluvialPluvial
|
23
25
|
|
24
26
|
# Import the Hdf* classes
|
25
27
|
from .HdfBase import HdfBase
|