ras-commander 0.70.0__py3-none-any.whl → 0.72.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 CHANGED
@@ -99,23 +99,66 @@ class RasCmdr:
99
99
  overwrite_dest=False
100
100
  ):
101
101
  """
102
- Execute a HEC-RAS plan.
102
+ Execute a single HEC-RAS plan in a specified location.
103
+
104
+ This function runs a HEC-RAS plan by launching the HEC-RAS executable through command line,
105
+ allowing for destination folder specification, core count control, and geometry preprocessor management.
103
106
 
104
107
  Args:
105
108
  plan_number (str, Path): The plan number to execute (e.g., "01", "02") or the full path to the plan file.
109
+ Recommended to use two-digit strings for plan numbers for consistency (e.g., "01" instead of 1).
106
110
  dest_folder (str, Path, optional): Name of the folder or full path for computation.
107
111
  If a string is provided, it will be created in the same parent directory as the project folder.
108
112
  If a full path is provided, it will be used as is.
113
+ If None, computation occurs in the original project folder, modifying the original project.
109
114
  ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
115
+ Useful when working with multiple projects simultaneously.
110
116
  clear_geompre (bool, optional): Whether to clear geometry preprocessor files. Defaults to False.
111
- num_cores (int, optional): Number of cores to use for the plan execution. If None, the current setting is not changed.
117
+ Set to True when geometry has been modified to force recomputation of preprocessor files.
118
+ num_cores (int, optional): Number of cores to use for the plan execution.
119
+ If None, the current setting in the plan file is not changed.
120
+ Generally, 2-4 cores provides good performance for most models.
112
121
  overwrite_dest (bool, optional): If True, overwrite the destination folder if it exists. Defaults to False.
122
+ Set to True to replace an existing destination folder with the same name.
113
123
 
114
124
  Returns:
115
125
  bool: True if the execution was successful, False otherwise.
116
126
 
117
127
  Raises:
118
128
  ValueError: If the specified dest_folder already exists and is not empty, and overwrite_dest is False.
129
+ FileNotFoundError: If the plan file or project file cannot be found.
130
+ PermissionError: If there are issues accessing or writing to the destination folder.
131
+ subprocess.CalledProcessError: If the HEC-RAS execution fails.
132
+
133
+ Examples:
134
+ # Run a plan in the original project folder
135
+ RasCmdr.compute_plan("01")
136
+
137
+ # Run a plan in a separate folder
138
+ RasCmdr.compute_plan("01", dest_folder="computation_folder")
139
+
140
+ # Run a plan with a specific number of cores
141
+ RasCmdr.compute_plan("01", num_cores=4)
142
+
143
+ # Run a plan in a specific folder, overwriting if it exists
144
+ RasCmdr.compute_plan("01", dest_folder="computation_folder", overwrite_dest=True)
145
+
146
+ # Run a plan in a specific folder with multiple options
147
+ RasCmdr.compute_plan(
148
+ "01",
149
+ dest_folder="computation_folder",
150
+ num_cores=2,
151
+ clear_geompre=True,
152
+ overwrite_dest=True
153
+ )
154
+
155
+ Notes:
156
+ - For executing multiple plans, consider using compute_parallel() or compute_test_mode().
157
+ - Setting num_cores appropriately is important for performance:
158
+ * 1-2 cores: Highest efficiency per core, good for small models
159
+ * 3-8 cores: Good balance for most models
160
+ * >8 cores: May have diminishing returns due to overhead
161
+ - This function updates the RAS object's dataframes (plan_df, geom_df, etc.) after execution.
119
162
  """
120
163
  try:
121
164
  ras_obj = ras_object if ras_object is not None else ras
@@ -202,8 +245,6 @@ class RasCmdr:
202
245
 
203
246
 
204
247
 
205
- @staticmethod
206
- @log_call
207
248
  @staticmethod
208
249
  @log_call
209
250
  def compute_parallel(
@@ -216,19 +257,83 @@ class RasCmdr:
216
257
  overwrite_dest: bool = False
217
258
  ) -> Dict[str, bool]:
218
259
  """
219
- Compute multiple HEC-RAS plans in parallel.
260
+ Execute multiple HEC-RAS plans in parallel using multiple worker instances.
261
+
262
+ This method creates separate worker folders for each parallel process, runs plans
263
+ in those folders, and then consolidates results to a final destination folder.
264
+ It's ideal for running independent plans simultaneously to make better use of system resources.
220
265
 
221
266
  Args:
222
- plan_number (Union[str, List[str], None]): Plan number(s) to compute. If None, all plans are computed.
223
- max_workers (int): Maximum number of parallel workers.
267
+ plan_number (Union[str, List[str], None]): Plan number(s) to compute.
268
+ If None, all plans in the project are computed.
269
+ If string, only that plan will be computed.
270
+ If list, all specified plans will be computed.
271
+ Recommended to use two-digit strings for plan numbers for consistency (e.g., "01" instead of 1).
272
+ max_workers (int): Maximum number of parallel workers (separate HEC-RAS instances).
273
+ Each worker gets a separate folder with a copy of the project.
274
+ Optimal value depends on CPU cores and memory available.
275
+ A good starting point is: max_workers = floor(physical_cores / num_cores).
224
276
  num_cores (int): Number of cores to use per plan computation.
225
- clear_geompre (bool): Whether to clear geometry preprocessor files.
226
- ras_object (Optional[RasPrj]): RAS project object. If None, uses global instance.
277
+ Controls computational resources allocated to each individual HEC-RAS instance.
278
+ For parallel execution, 2-4 cores per worker often provides the best balance.
279
+ clear_geompre (bool): Whether to clear geometry preprocessor files before computation.
280
+ Set to True when geometry has been modified to force recomputation.
281
+ ras_object (Optional[RasPrj]): RAS project object. If None, uses global 'ras' instance.
282
+ Useful when working with multiple projects simultaneously.
227
283
  dest_folder (Union[str, Path, None]): Destination folder for computed results.
284
+ If None, creates a "[Computed]" folder adjacent to the project folder.
285
+ If string, creates folder in the project's parent directory.
286
+ If Path, uses the exact path provided.
228
287
  overwrite_dest (bool): Whether to overwrite existing destination folder.
288
+ Set to True to replace an existing destination folder with the same name.
229
289
 
230
290
  Returns:
231
291
  Dict[str, bool]: Dictionary of plan numbers and their execution success status.
292
+ Keys are plan numbers and values are boolean success indicators.
293
+
294
+ Raises:
295
+ ValueError: If the destination folder already exists, is not empty, and overwrite_dest is False.
296
+ FileNotFoundError: If project files cannot be found.
297
+ PermissionError: If there are issues accessing or writing to folders.
298
+ RuntimeError: If worker initialization fails.
299
+
300
+ Examples:
301
+ # Run all plans in parallel with default settings
302
+ RasCmdr.compute_parallel()
303
+
304
+ # Run all plans with 4 workers, 2 cores per worker
305
+ RasCmdr.compute_parallel(max_workers=4, num_cores=2)
306
+
307
+ # Run specific plans in parallel
308
+ RasCmdr.compute_parallel(plan_number=["01", "03"], max_workers=2)
309
+
310
+ # Run all plans with dynamic worker allocation based on system resources
311
+ import psutil
312
+ physical_cores = psutil.cpu_count(logical=False)
313
+ cores_per_worker = 2
314
+ max_workers = max(1, physical_cores // cores_per_worker)
315
+ RasCmdr.compute_parallel(max_workers=max_workers, num_cores=cores_per_worker)
316
+
317
+ # Run all plans in a specific destination folder
318
+ RasCmdr.compute_parallel(dest_folder="parallel_results", overwrite_dest=True)
319
+
320
+ Notes:
321
+ - Worker Assignment: Plans are assigned to workers in a round-robin fashion.
322
+ For example, with 3 workers and 5 plans, assignment would be:
323
+ Worker 1: Plans 1 & 4, Worker 2: Plans 2 & 5, Worker 3: Plan 3.
324
+
325
+ - Resource Management: Each HEC-RAS instance (worker) typically requires:
326
+ * 2-4 GB of RAM
327
+ * 2-4 cores for optimal performance
328
+
329
+ - When to use parallel vs. sequential:
330
+ * Parallel: For independent plans, faster overall completion
331
+ * Sequential: For dependent plans, consistent resource usage, easier debugging
332
+
333
+ - The function creates worker folders during execution and consolidates results
334
+ to the destination folder upon completion.
335
+
336
+ - This function updates the RAS object's dataframes (plan_df, geom_df, etc.) after execution.
232
337
  """
233
338
  try:
234
339
  ras_obj = ras_object or ras
@@ -251,11 +356,17 @@ class RasCmdr:
251
356
  logger.info(f"Copied project folder to destination: {dest_folder_path}")
252
357
  project_folder = dest_folder_path
253
358
 
359
+ # Store filtered plan numbers separately to ensure only these are executed
360
+ filtered_plan_numbers = []
361
+
254
362
  if plan_number:
255
363
  if isinstance(plan_number, str):
256
364
  plan_number = [plan_number]
257
365
  ras_obj.plan_df = ras_obj.plan_df[ras_obj.plan_df['plan_number'].isin(plan_number)]
258
- logger.info(f"Filtered plans to execute: {plan_number}")
366
+ filtered_plan_numbers = list(ras_obj.plan_df['plan_number'])
367
+ logger.info(f"Filtered plans to execute: {filtered_plan_numbers}")
368
+ else:
369
+ filtered_plan_numbers = list(ras_obj.plan_df['plan_number'])
259
370
 
260
371
  num_plans = len(ras_obj.plan_df)
261
372
  max_workers = min(max_workers, num_plans) if num_plans > 0 else 1
@@ -282,8 +393,9 @@ class RasCmdr:
282
393
  logger.critical(f"Failed to initialize RAS project for worker {worker_id}: {str(e)}")
283
394
  worker_ras_objects[worker_id] = None
284
395
 
396
+ # Explicitly use the filtered plan numbers for assignments
285
397
  worker_cycle = cycle(range(1, max_workers + 1))
286
- plan_assignments = [(next(worker_cycle), plan_num) for plan_num in ras_obj.plan_df['plan_number']]
398
+ plan_assignments = [(next(worker_cycle), plan_num) for plan_num in filtered_plan_numbers]
287
399
 
288
400
  execution_results: Dict[str, bool] = {}
289
401
 
@@ -397,49 +509,86 @@ class RasCmdr:
397
509
  overwrite_dest=False
398
510
  ):
399
511
  """
400
- Execute HEC-RAS plans in test mode. This is a re-creation of the HEC-RAS command line -test flag,
401
- which does not work in recent versions of HEC-RAS.
402
-
403
- As a special-purpose function that emulates the original -test flag, it operates differently than the
404
- other two compute_ functions. Per the original HEC-RAS test flag, it creates a separate test folder,
405
- copies the project there, and executes the specified plans in sequential order.
406
-
407
- For most purposes, just copying the project folder, initing that new folder, then running each plan
408
- with compute_plan is a simpler and more flexible approach. This is shown in the examples provided
409
- in the ras-commander library.
512
+ Execute HEC-RAS plans sequentially in a separate test folder.
513
+
514
+ This function creates a separate test folder, copies the project there, and executes
515
+ the specified plans in sequential order. It's useful for batch processing plans that
516
+ need to be run in a specific order or when you want to ensure consistent resource usage.
410
517
 
411
518
  Args:
412
519
  plan_number (str, list[str], optional): Plan number or list of plan numbers to execute.
413
520
  If None, all plans will be executed. Default is None.
414
- dest_folder_suffix (str, optional): Suffix to append to the test folder name to create dest_folder.
521
+ Recommended to use two-digit strings for plan numbers for consistency (e.g., "01" instead of 1).
522
+ dest_folder_suffix (str, optional): Suffix to append to the test folder name.
415
523
  Defaults to "[Test]".
416
- dest_folder is always created in the project folder's parent directory.
524
+ The test folder is always created in the project folder's parent directory.
417
525
  clear_geompre (bool, optional): Whether to clear geometry preprocessor files.
418
526
  Defaults to False.
419
- num_cores (int, optional): Maximum number of cores to use for each plan.
420
- If None, the current setting is not changed. Default is None.
527
+ Set to True when geometry has been modified to force recomputation.
528
+ num_cores (int, optional): Number of cores to use for each plan.
529
+ If None, the current setting in the plan file is not changed. Default is None.
530
+ For sequential execution, 4-8 cores often provides good performance.
421
531
  ras_object (RasPrj, optional): Specific RAS object to use. If None, uses the global ras instance.
422
- overwrite_dest (bool, optional): If True, overwrite the destination folder if it exists. Defaults to False.
532
+ Useful when working with multiple projects simultaneously.
533
+ overwrite_dest (bool, optional): If True, overwrite the destination folder if it exists.
534
+ Defaults to False.
535
+ Set to True to replace an existing test folder with the same name.
423
536
 
424
537
  Returns:
425
538
  Dict[str, bool]: Dictionary of plan numbers and their execution success status.
539
+ Keys are plan numbers and values are boolean success indicators.
540
+
541
+ Raises:
542
+ ValueError: If the destination folder already exists, is not empty, and overwrite_dest is False.
543
+ FileNotFoundError: If project files cannot be found.
544
+ PermissionError: If there are issues accessing or writing to folders.
426
545
 
427
- Example:
428
- Run all plans: RasCommander.compute_test_mode()
429
- Run a specific plan: RasCommander.compute_test_mode(plan_number="01")
430
- Run multiple plans: RasCommander.compute_test_mode(plan_number=["01", "03", "05"])
431
- Run plans with a custom folder suffix: RasCommander.compute_test_mode(dest_folder_suffix="[TestRun]")
432
- Run plans and clear geometry preprocessor files: RasCommander.compute_test_mode(clear_geompre=True)
433
- Run plans with a specific number of cores: RasCommander.compute_test_mode(num_cores=4)
546
+ Examples:
547
+ # Run all plans sequentially
548
+ RasCmdr.compute_test_mode()
549
+
550
+ # Run a specific plan
551
+ RasCmdr.compute_test_mode(plan_number="01")
552
+
553
+ # Run multiple specific plans
554
+ RasCmdr.compute_test_mode(plan_number=["01", "03", "05"])
555
+
556
+ # Run plans with a custom folder suffix
557
+ RasCmdr.compute_test_mode(dest_folder_suffix="[SequentialRun]")
558
+
559
+ # Run plans with a specific number of cores
560
+ RasCmdr.compute_test_mode(num_cores=4)
434
561
 
562
+ # Run specific plans with multiple options
563
+ RasCmdr.compute_test_mode(
564
+ plan_number=["01", "02"],
565
+ dest_folder_suffix="[SpecificSequential]",
566
+ clear_geompre=True,
567
+ num_cores=6,
568
+ overwrite_dest=True
569
+ )
570
+
435
571
  Notes:
436
- - This function executes plans in a separate folder for isolated testing.
437
- - If plan_number is not provided, all plans in the project will be executed.
438
- - The function does not change the geometry preprocessor and IB tables settings.
439
- - To force recomputing of geometry preprocessor and IB tables, use the clear_geompre=True option.
440
- - Plans are executed sequentially.
441
- - Because copying the project is implicit, only a dest_folder_suffix option is provided.
442
- - For more flexible run management, use the compute_parallel or compute_sequential functions.
572
+ - This function was created to replicate the original HEC-RAS command line -test flag,
573
+ which does not work in recent versions of HEC-RAS.
574
+
575
+ - Key differences from other compute functions:
576
+ * compute_plan: Runs a single plan, with option for destination folder
577
+ * compute_parallel: Runs multiple plans simultaneously in worker folders
578
+ * compute_test_mode: Runs multiple plans sequentially in a single test folder
579
+
580
+ - Use cases:
581
+ * Running plans in a specific order
582
+ * Ensuring consistent resource usage
583
+ * Easier debugging (one plan at a time)
584
+ * Isolated test environment
585
+
586
+ - Performance considerations:
587
+ * Sequential execution is generally slower overall than parallel execution
588
+ * Each plan gets consistent resource usage
589
+ * Execution time scales linearly with the number of plans
590
+
591
+ - This function updates the RAS object's dataframes (plan_df, geom_df, etc.) after execution.
443
592
  """
444
593
  try:
445
594
  ras_obj = ras_object or ras