ras-commander 0.33.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/RasCmdr.py +449 -0
- ras_commander/RasExamples.py +304 -0
- ras_commander/RasGeo.py +88 -0
- ras_commander/RasPlan.py +1266 -0
- ras_commander/RasPrj.py +400 -0
- ras_commander/RasUnsteady.py +73 -0
- ras_commander/RasUtils.py +310 -0
- ras_commander/__init__.py +40 -0
- ras_commander/_version.py +16 -0
- ras_commander-0.33.0.dist-info/LICENSE +5 -0
- ras_commander-0.33.0.dist-info/METADATA +5 -0
- ras_commander-0.33.0.dist-info/RECORD +14 -0
- ras_commander-0.33.0.dist-info/WHEEL +5 -0
- ras_commander-0.33.0.dist-info/top_level.txt +1 -0
ras_commander/RasCmdr.py
ADDED
@@ -0,0 +1,449 @@
|
|
1
|
+
"""
|
2
|
+
Execution operations for running HEC-RAS simulations using subprocess.
|
3
|
+
Based on the HEC-Commander project's "Command Line is All You Need" approach, leveraging the -c compute flag to run HEC-RAS and orchestrating changes directly in the RAS input files to achieve automation outcomes.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import os
|
7
|
+
import subprocess
|
8
|
+
import shutil
|
9
|
+
from pathlib import Path
|
10
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
11
|
+
from .RasPrj import ras, RasPrj, init_ras_project, get_ras_exe
|
12
|
+
from .RasPlan import RasPlan
|
13
|
+
from .RasGeo import RasGeo
|
14
|
+
from .RasUtils import RasUtils
|
15
|
+
import subprocess
|
16
|
+
import os
|
17
|
+
import logging
|
18
|
+
import time
|
19
|
+
import pandas as pd
|
20
|
+
from threading import Thread, Lock
|
21
|
+
import queue
|
22
|
+
from pathlib import Path
|
23
|
+
import shutil
|
24
|
+
import queue
|
25
|
+
from threading import Thread, Lock
|
26
|
+
import time
|
27
|
+
|
28
|
+
# TO DO:
|
29
|
+
# 1. Alternate Run Mode for compute_plan and compute_parallel: Using Powershell to execute the HEC-RAS command and hide the RAS window and all child windows.
|
30
|
+
# If this is implemented, and the plan has a popup, then the plan will not execute. This is a deal breaker for many scenarios, and should only be used
|
31
|
+
# as a special option for those who don't want to deal with the popups, or want to run in the background. This option should be limited to non-commercial use.
|
32
|
+
# 2. Implment compute_plan_remote to go along with compute_plan. This will be a compute_plan that is run on a remote machine via a psexec command.
|
33
|
+
# First, we will use the keyring package to securely store the remote machine username and password.
|
34
|
+
# Second, we will implement the psexec command to execute the HEC-RAS command on the remote machine.
|
35
|
+
# Each machine will need to be initialized as a remote_worker object, which will store the machine name, username, password, ras_exe_path, local folder path and other relevant info.
|
36
|
+
# A separate RasRemote class will be created to handle the creation of the remote_worker objects and the necessary abstractions.
|
37
|
+
# The compute_plan_remote function will live in RasCmdr, and will be a thin abstraction above the RasRemote class, since the functions will be simliar to the existing compute_plan functions, but specific to remote execution.
|
38
|
+
|
39
|
+
|
40
|
+
class RasCmdr:
|
41
|
+
@staticmethod
|
42
|
+
def compute_plan(
|
43
|
+
plan_number,
|
44
|
+
dest_folder=None,
|
45
|
+
ras_object=None,
|
46
|
+
clear_geompre=False,
|
47
|
+
num_cores=None,
|
48
|
+
overwrite_dest=False
|
49
|
+
):
|
50
|
+
"""
|
51
|
+
Execute a HEC-RAS plan.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
plan_number (str, Path): The plan number to execute (e.g., "01", "02") or the full path to the plan file.
|
55
|
+
dest_folder (str, Path, optional): Name of the folder or full path for computation.
|
56
|
+
If a string is provided, it will be created in the same parent directory as the project folder.
|
57
|
+
If a full path is provided, it will be used as is.
|
58
|
+
ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
|
59
|
+
clear_geompre (bool, optional): Whether to clear geometry preprocessor files. Defaults to False.
|
60
|
+
num_cores (int, optional): Number of cores to use for the plan execution. If None, the current setting is not changed.
|
61
|
+
overwrite_dest (bool, optional): If True, overwrite the destination folder if it exists. Defaults to False.
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
bool: True if the execution was successful, False otherwise.
|
65
|
+
|
66
|
+
Raises:
|
67
|
+
ValueError: If the specified dest_folder already exists and is not empty, and overwrite_dest is False.
|
68
|
+
"""
|
69
|
+
ras_obj = ras_object or ras
|
70
|
+
ras_obj.check_initialized()
|
71
|
+
|
72
|
+
if dest_folder is not None:
|
73
|
+
dest_folder = Path(ras_obj.project_folder).parent / dest_folder if isinstance(dest_folder, str) else Path(dest_folder)
|
74
|
+
|
75
|
+
if dest_folder.exists():
|
76
|
+
if overwrite_dest:
|
77
|
+
shutil.rmtree(dest_folder)
|
78
|
+
elif any(dest_folder.iterdir()):
|
79
|
+
raise ValueError(f"Destination folder '{dest_folder}' exists and is not empty. Use overwrite_dest=True to overwrite.")
|
80
|
+
|
81
|
+
dest_folder.mkdir(parents=True, exist_ok=True)
|
82
|
+
shutil.copytree(ras_obj.project_folder, dest_folder, dirs_exist_ok=True)
|
83
|
+
|
84
|
+
compute_ras = RasPrj()
|
85
|
+
compute_ras.initialize(dest_folder, ras_obj.ras_exe_path)
|
86
|
+
compute_prj_path = compute_ras.prj_file
|
87
|
+
else:
|
88
|
+
compute_ras = ras_obj
|
89
|
+
compute_prj_path = ras_obj.prj_file
|
90
|
+
|
91
|
+
# Determine the plan path
|
92
|
+
compute_plan_path = Path(plan_number) if isinstance(plan_number, (str, Path)) and Path(plan_number).is_file() else RasPlan.get_plan_path(plan_number, compute_ras)
|
93
|
+
|
94
|
+
if not compute_prj_path or not compute_plan_path:
|
95
|
+
print(f"Error: Could not find project file or plan file for plan {plan_number}")
|
96
|
+
return False
|
97
|
+
|
98
|
+
# Clear geometry preprocessor files if requested
|
99
|
+
if clear_geompre:
|
100
|
+
try:
|
101
|
+
RasGeo.clear_geompre_files(compute_plan_path, ras_object=compute_ras)
|
102
|
+
print(f"Cleared geometry preprocessor files for plan: {plan_number}")
|
103
|
+
except Exception as e:
|
104
|
+
print(f"Error clearing geometry preprocessor files for plan {plan_number}: {str(e)}")
|
105
|
+
|
106
|
+
# Set the number of cores if specified
|
107
|
+
if num_cores is not None:
|
108
|
+
try:
|
109
|
+
RasPlan.set_num_cores(compute_plan_path, num_cores=num_cores, ras_object=compute_ras)
|
110
|
+
print(f"Set number of cores to {num_cores} for plan: {plan_number}")
|
111
|
+
except Exception as e:
|
112
|
+
print(f"Error setting number of cores for plan {plan_number}: {str(e)}")
|
113
|
+
|
114
|
+
# Prepare the command for HEC-RAS execution
|
115
|
+
cmd = f'"{compute_ras.ras_exe_path}" -c "{compute_prj_path}" "{compute_plan_path}"'
|
116
|
+
print("Running HEC-RAS from the Command Line:")
|
117
|
+
print(f"Running command: {cmd}")
|
118
|
+
|
119
|
+
# Execute the HEC-RAS command
|
120
|
+
start_time = time.time()
|
121
|
+
try:
|
122
|
+
subprocess.run(cmd, check=True, shell=True, capture_output=True, text=True)
|
123
|
+
end_time = time.time()
|
124
|
+
run_time = end_time - start_time
|
125
|
+
print(f"HEC-RAS execution completed for plan: {plan_number}")
|
126
|
+
print(f"Total run time for plan {plan_number}: {run_time:.2f} seconds")
|
127
|
+
return True
|
128
|
+
except subprocess.CalledProcessError as e:
|
129
|
+
end_time = time.time()
|
130
|
+
run_time = end_time - start_time
|
131
|
+
print(f"Error running plan: {plan_number}")
|
132
|
+
print(f"Error message: {e.output}")
|
133
|
+
print(f"Total run time for plan {plan_number}: {run_time:.2f} seconds")
|
134
|
+
return False
|
135
|
+
|
136
|
+
ras_obj = ras_object or ras
|
137
|
+
ras_obj.plan_df = ras_obj.get_plan_entries()
|
138
|
+
ras_obj.geom_df = ras_obj.get_geom_entries()
|
139
|
+
ras_obj.flow_df = ras_obj.get_flow_entries()
|
140
|
+
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
@staticmethod
|
145
|
+
def compute_parallel(
|
146
|
+
plan_number: str | list[str] | None = None,
|
147
|
+
max_workers: int = 2,
|
148
|
+
num_cores: int = 2,
|
149
|
+
clear_geompre: bool = False,
|
150
|
+
ras_object: RasPrj | None = None,
|
151
|
+
dest_folder: str | Path | None = None,
|
152
|
+
overwrite_dest: bool = False
|
153
|
+
) -> dict[str, bool]:
|
154
|
+
"""
|
155
|
+
Execute HEC-RAS plans in parallel using multiple worker threads.
|
156
|
+
|
157
|
+
This function creates separate worker folders, copies the project to each, and executes the specified plans
|
158
|
+
in parallel. It allows for isolated and concurrent execution of multiple plans.
|
159
|
+
|
160
|
+
Args:
|
161
|
+
plan_number (str | list[str] | None): Plan number, list of plan numbers, or None to execute all plans.
|
162
|
+
max_workers (int, optional): Maximum number of worker threads to use. Default is 2.
|
163
|
+
num_cores (int, optional): Number of cores to use for each plan execution. Default is 2.
|
164
|
+
clear_geompre (bool, optional): Whether to clear geometry preprocessor files. Defaults to False.
|
165
|
+
ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
|
166
|
+
dest_folder (str | Path, optional): Destination folder for the final computed results.
|
167
|
+
If None, results will be stored in a "[Computed]" folder next to the original project.
|
168
|
+
overwrite_dest (bool, optional): If True, overwrite the destination folder if it exists. Defaults to False.
|
169
|
+
|
170
|
+
Returns:
|
171
|
+
dict[str, bool]: A dictionary with plan numbers as keys and boolean values indicating success (True) or failure (False).
|
172
|
+
|
173
|
+
Raises:
|
174
|
+
ValueError: If the destination folder exists and is not empty, and overwrite_dest is False.
|
175
|
+
FileNotFoundError: If a plan file is not found.
|
176
|
+
|
177
|
+
Notes:
|
178
|
+
- This function creates separate folders for each worker to ensure isolated execution.
|
179
|
+
- Each worker uses its own RAS object to prevent conflicts.
|
180
|
+
- Plans are distributed among workers using a queue to ensure efficient parallel processing.
|
181
|
+
- The function automatically handles cleanup and consolidation of results after execution.
|
182
|
+
|
183
|
+
Revision Notes:
|
184
|
+
- Added support for clear_geompre flag as a pass-through to compute_plan.
|
185
|
+
- Simplified worker thread logic by removing redundant operations.
|
186
|
+
- Removed duplicate RAS object initialization in worker threads.
|
187
|
+
"""
|
188
|
+
ras_obj = ras_object or ras
|
189
|
+
ras_obj.check_initialized()
|
190
|
+
|
191
|
+
project_folder = ras_obj.project_folder
|
192
|
+
|
193
|
+
if dest_folder is not None:
|
194
|
+
dest_folder_path = Path(dest_folder)
|
195
|
+
if dest_folder_path.exists():
|
196
|
+
if overwrite_dest:
|
197
|
+
shutil.rmtree(dest_folder_path)
|
198
|
+
elif any(dest_folder_path.iterdir()):
|
199
|
+
raise ValueError(f"Destination folder '{dest_folder_path}' exists and is not empty. Use overwrite_dest=True to overwrite.")
|
200
|
+
dest_folder_path.mkdir(parents=True, exist_ok=True)
|
201
|
+
shutil.copytree(project_folder, dest_folder_path, dirs_exist_ok=True)
|
202
|
+
project_folder = dest_folder_path
|
203
|
+
|
204
|
+
if plan_number:
|
205
|
+
if isinstance(plan_number, str):
|
206
|
+
plan_number = [plan_number]
|
207
|
+
ras_obj.plan_df = ras_obj.plan_df[ras_obj.plan_df['plan_number'].isin(plan_number)]
|
208
|
+
|
209
|
+
num_plans = len(ras_obj.plan_df)
|
210
|
+
max_workers = min(max_workers, num_plans) if num_plans > 0 else 1
|
211
|
+
print(f"Adjusted max_workers to {max_workers} based on the number of plans: {num_plans}")
|
212
|
+
|
213
|
+
# Clean up existing worker folders and create new ones
|
214
|
+
worker_ras_objects = {}
|
215
|
+
for worker_id in range(1, max_workers + 1):
|
216
|
+
worker_folder = project_folder.parent / f"{project_folder.name} [Worker {worker_id}]"
|
217
|
+
if worker_folder.exists():
|
218
|
+
shutil.rmtree(worker_folder)
|
219
|
+
shutil.copytree(project_folder, worker_folder)
|
220
|
+
|
221
|
+
worker_ras_instance = init_ras_project(
|
222
|
+
ras_project_folder=worker_folder,
|
223
|
+
ras_version=ras_obj.ras_exe_path,
|
224
|
+
ras_instance=RasPrj()
|
225
|
+
)
|
226
|
+
worker_ras_objects[worker_id] = worker_ras_instance
|
227
|
+
|
228
|
+
plan_queue = queue.Queue()
|
229
|
+
for plan_number in ras_obj.plan_df['plan_number']:
|
230
|
+
plan_queue.put(plan_number)
|
231
|
+
|
232
|
+
execution_results: dict[str, bool] = {}
|
233
|
+
results_lock = Lock()
|
234
|
+
queue_lock = Lock()
|
235
|
+
|
236
|
+
def worker_thread(worker_id: int):
|
237
|
+
worker_ras_obj = worker_ras_objects[worker_id]
|
238
|
+
while True:
|
239
|
+
with queue_lock:
|
240
|
+
if plan_queue.empty():
|
241
|
+
break
|
242
|
+
plan_number = plan_queue.get()
|
243
|
+
|
244
|
+
try:
|
245
|
+
print(f"Worker {worker_id} executing plan {plan_number}")
|
246
|
+
success = RasCmdr.compute_plan(
|
247
|
+
plan_number,
|
248
|
+
ras_object=worker_ras_obj,
|
249
|
+
clear_geompre=clear_geompre,
|
250
|
+
num_cores=num_cores
|
251
|
+
)
|
252
|
+
with results_lock:
|
253
|
+
execution_results[plan_number] = success
|
254
|
+
print(f"Completed: Plan {plan_number} in worker {worker_id}")
|
255
|
+
except Exception as e:
|
256
|
+
with results_lock:
|
257
|
+
execution_results[plan_number] = False
|
258
|
+
print(f"Failed: Plan {plan_number} in worker {worker_id}. Error: {str(e)}")
|
259
|
+
|
260
|
+
# Start worker threads
|
261
|
+
worker_threads = [Thread(target=worker_thread, args=(worker_id,)) for worker_id in range(1, max_workers + 1)]
|
262
|
+
for thread in worker_threads:
|
263
|
+
thread.start()
|
264
|
+
|
265
|
+
# Wait for all threads to complete
|
266
|
+
for thread in worker_threads:
|
267
|
+
thread.join()
|
268
|
+
|
269
|
+
# Consolidate results
|
270
|
+
final_dest_folder = dest_folder_path if dest_folder is not None else project_folder.parent / f"{project_folder.name} [Computed]"
|
271
|
+
final_dest_folder.mkdir(exist_ok=True)
|
272
|
+
print(f"Final destination for computed results: {final_dest_folder}")
|
273
|
+
|
274
|
+
for worker_ras in worker_ras_objects.values():
|
275
|
+
worker_folder = worker_ras.project_folder
|
276
|
+
try:
|
277
|
+
for item in worker_folder.iterdir():
|
278
|
+
dest_path = final_dest_folder / item.name
|
279
|
+
if dest_path.exists():
|
280
|
+
if dest_path.is_dir():
|
281
|
+
shutil.rmtree(dest_path)
|
282
|
+
else:
|
283
|
+
dest_path.unlink()
|
284
|
+
shutil.move(str(item), final_dest_folder)
|
285
|
+
shutil.rmtree(worker_folder)
|
286
|
+
except Exception as e:
|
287
|
+
print(f"Error moving results from {worker_folder} to {final_dest_folder}: {str(e)}")
|
288
|
+
|
289
|
+
# Print execution results for each plan
|
290
|
+
print("\nExecution Results:")
|
291
|
+
for plan_number, success in execution_results.items():
|
292
|
+
print(f"Plan {plan_number}: {'Successful' if success else 'Failed'}")
|
293
|
+
|
294
|
+
return execution_results
|
295
|
+
|
296
|
+
|
297
|
+
|
298
|
+
@staticmethod
|
299
|
+
def compute_test_mode(
|
300
|
+
plan_number=None,
|
301
|
+
dest_folder_suffix="[Test]",
|
302
|
+
clear_geompre=False,
|
303
|
+
num_cores=None,
|
304
|
+
ras_object=None,
|
305
|
+
overwrite_dest=False
|
306
|
+
):
|
307
|
+
"""
|
308
|
+
Execute HEC-RAS plans in test mode. This is a re-creation of the HEC-RAS command line -test flag,
|
309
|
+
which does not work in recent versions of HEC-RAS.
|
310
|
+
|
311
|
+
As a special-purpose function that emulates the original -test flag, it operates differently than the
|
312
|
+
other two compute_ functions. Per the original HEC-RAS test flag, it creates a separate test folder,
|
313
|
+
copies the project there, and executes the specified plans in sequential order.
|
314
|
+
|
315
|
+
For most purposes, just copying a the project folder, initing that new folder, then running each plan
|
316
|
+
with compute_plan is a simpler and more flexible approach. This is shown in the examples provided
|
317
|
+
in the ras-commander library.
|
318
|
+
|
319
|
+
Args:
|
320
|
+
plan_number (str, list[str], optional): Plan number or list of plan numbers to execute.
|
321
|
+
If None, all plans will be executed. Default is None.
|
322
|
+
dest_folder_suffix (str, optional): Suffix to append to the test folder name to create dest_folder.
|
323
|
+
Defaults to "[Test]".
|
324
|
+
dest_folder is always created in the project folder's parent directory.
|
325
|
+
clear_geompre (bool, optional): Whether to clear geometry preprocessor files.
|
326
|
+
Defaults to False.
|
327
|
+
num_cores (int, optional): Maximum number of cores to use for each plan.
|
328
|
+
If None, the current setting is not changed. Default is None.
|
329
|
+
ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
|
330
|
+
overwrite_dest (bool, optional): If True, overwrite the destination folder if it exists. Defaults to False.
|
331
|
+
|
332
|
+
Returns:
|
333
|
+
None
|
334
|
+
|
335
|
+
Example:
|
336
|
+
Run all plans: RasCommander.compute_test_mode()
|
337
|
+
Run a specific plan: RasCommander.compute_test_mode(plan_number="01")
|
338
|
+
Run multiple plans: RasCommander.compute_test_mode(plan_number=["01", "03", "05"])
|
339
|
+
Run plans with a custom folder suffix: RasCommander.compute_test_mode(dest_folder_suffix="[TestRun]")
|
340
|
+
Run plans and clear geometry preprocessor files: RasCommander.compute_test_mode(clear_geompre=True)
|
341
|
+
Run plans with a specific number of cores: RasCommander.compute_test_mode(num_cores=4)
|
342
|
+
|
343
|
+
Notes:
|
344
|
+
- This function executes plans in a separate folder for isolated testing.
|
345
|
+
- If plan_number is not provided, all plans in the project will be executed.
|
346
|
+
- The function does not change the geometry preprocessor and IB tables settings.
|
347
|
+
- To force recomputing of geometry preprocessor and IB tables, use the clear_geompre=True option.
|
348
|
+
- Plans are executed sequentially.
|
349
|
+
- Because copying the project is implicit, only a dest_folder_suffix option is provided.
|
350
|
+
- For more flexible run management, use the compute_parallel or compute_sequential functions.
|
351
|
+
"""
|
352
|
+
|
353
|
+
# This line of code is used to initialize the RasPrj object with the default "ras" object if no specific object is provided.
|
354
|
+
ras_obj = ras_object or ras
|
355
|
+
# This line of code is used to check if the RasPrj object is initialized.
|
356
|
+
ras_obj.check_initialized()
|
357
|
+
|
358
|
+
print("Starting the compute_test_mode...")
|
359
|
+
|
360
|
+
# Use the project folder from the ras object
|
361
|
+
project_folder = ras_obj.project_folder
|
362
|
+
|
363
|
+
# Check if the project folder exists
|
364
|
+
if not project_folder.exists():
|
365
|
+
print(f"Error: Project folder '{project_folder}' does not exist.")
|
366
|
+
return
|
367
|
+
|
368
|
+
# Create test folder with the specified suffix in the same directory as the project folder
|
369
|
+
compute_folder = project_folder.parent / f"{project_folder.name} {dest_folder_suffix}"
|
370
|
+
print(f"Creating the test folder: {compute_folder}...")
|
371
|
+
|
372
|
+
# Check if the compute folder exists and is empty
|
373
|
+
if compute_folder.exists():
|
374
|
+
if overwrite_dest:
|
375
|
+
shutil.rmtree(compute_folder)
|
376
|
+
elif any(compute_folder.iterdir()):
|
377
|
+
raise ValueError(
|
378
|
+
f"Compute folder '{compute_folder}' exists and is not empty. "
|
379
|
+
"Use overwrite_dest=True to overwrite."
|
380
|
+
)
|
381
|
+
else:
|
382
|
+
try:
|
383
|
+
shutil.copytree(project_folder, compute_folder)
|
384
|
+
except FileNotFoundError:
|
385
|
+
print(f"Error: Unable to copy project folder. Source folder '{project_folder}' not found.")
|
386
|
+
return
|
387
|
+
except PermissionError:
|
388
|
+
print(f"Error: Permission denied when trying to create or copy to '{compute_folder}'.")
|
389
|
+
return
|
390
|
+
except Exception as e:
|
391
|
+
print(f"Error occurred while copying project folder: {str(e)}")
|
392
|
+
return
|
393
|
+
|
394
|
+
# Initialize a new RAS project in the compute folder
|
395
|
+
try:
|
396
|
+
compute_ras = RasPrj()
|
397
|
+
compute_ras.initialize(compute_folder, ras_obj.ras_exe_path)
|
398
|
+
compute_prj_path = compute_ras.prj_file
|
399
|
+
except Exception as e:
|
400
|
+
print(f"Error initializing RAS project in compute folder: {str(e)}")
|
401
|
+
return
|
402
|
+
|
403
|
+
if not compute_prj_path:
|
404
|
+
print("Project file not found.")
|
405
|
+
return
|
406
|
+
|
407
|
+
|
408
|
+
# Get plan entries
|
409
|
+
print("Getting plan entries...")
|
410
|
+
try:
|
411
|
+
ras_compute_plan_entries = compute_ras.plan_df
|
412
|
+
print("Retrieved plan entries successfully.")
|
413
|
+
except Exception as e:
|
414
|
+
print(f"Error retrieving plan entries: {str(e)}")
|
415
|
+
return
|
416
|
+
|
417
|
+
if plan_number:
|
418
|
+
if isinstance(plan_number, str):
|
419
|
+
plan_number = [plan_number]
|
420
|
+
ras_compute_plan_entries = ras_compute_plan_entries[
|
421
|
+
ras_compute_plan_entries['plan_number'].isin(plan_number)
|
422
|
+
]
|
423
|
+
print(f"Filtered plans to execute: {plan_number}")
|
424
|
+
|
425
|
+
print("Running selected plans sequentially...")
|
426
|
+
for _, plan in ras_compute_plan_entries.iterrows():
|
427
|
+
plan_number = plan["plan_number"]
|
428
|
+
start_time = time.time()
|
429
|
+
try:
|
430
|
+
RasCommander.compute_plan(
|
431
|
+
plan_number,
|
432
|
+
ras_object=compute_ras,
|
433
|
+
clear_geompre=clear_geompre,
|
434
|
+
num_cores=num_cores
|
435
|
+
)
|
436
|
+
except Exception as e:
|
437
|
+
print(f"Error computing plan {plan_number}: {str(e)}")
|
438
|
+
end_time = time.time()
|
439
|
+
run_time = end_time - start_time
|
440
|
+
print(f"Total run time for plan {plan_number}: {run_time:.2f} seconds")
|
441
|
+
|
442
|
+
print("All selected plans have been executed.")
|
443
|
+
print("compute_test_mode completed.")
|
444
|
+
|
445
|
+
ras_obj = ras_object or ras
|
446
|
+
ras_obj.plan_df = ras_obj.get_plan_entries()
|
447
|
+
ras_obj.geom_df = ras_obj.get_geom_entries()
|
448
|
+
ras_obj.flow_df = ras_obj.get_flow_entries()
|
449
|
+
ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
|