ras-commander 0.68.0__py3-none-any.whl → 0.71.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/RasPlan.py CHANGED
@@ -87,7 +87,7 @@ class RasPlan:
87
87
  @log_call
88
88
  def set_geom(plan_number: Union[str, int], new_geom: Union[str, int], ras_object=None) -> pd.DataFrame:
89
89
  """
90
- Set the geometry for the specified plan.
90
+ Set the geometry for the specified plan by updating only the plan file.
91
91
 
92
92
  Parameters:
93
93
  plan_number (Union[str, int]): The plan number to update.
@@ -101,7 +101,8 @@ class RasPlan:
101
101
  updated_geom_df = RasPlan.set_geom('02', '03')
102
102
 
103
103
  Note:
104
- This function updates the ras object's dataframes after modifying the project structure.
104
+ This function updates the Geom File= line in the plan file and
105
+ updates the ras object's dataframes without modifying the PRJ file.
105
106
  """
106
107
  ras_obj = ras_object or ras
107
108
  ras_obj.check_initialized()
@@ -112,16 +113,37 @@ class RasPlan:
112
113
  # Update all dataframes
113
114
  ras_obj.plan_df = ras_obj.get_plan_entries()
114
115
  ras_obj.geom_df = ras_obj.get_geom_entries()
115
- ras_obj.flow_df = ras_obj.get_flow_entries()
116
- ras_obj.unsteady_df = ras_obj.get_unsteady_entries()
117
116
 
118
117
  if new_geom not in ras_obj.geom_df['geom_number'].values:
119
118
  logger.error(f"Geometry {new_geom} not found in project.")
120
119
  raise ValueError(f"Geometry {new_geom} not found in project.")
121
120
 
122
- # Update all geometry-related columns
121
+ # Get the plan file path
122
+ plan_file_path = ras_obj.project_folder / f"{ras_obj.project_name}.p{plan_number}"
123
+ if not plan_file_path.exists():
124
+ logger.error(f"Plan file not found: {plan_file_path}")
125
+ raise ValueError(f"Plan file not found: {plan_file_path}")
126
+
127
+ # Read the plan file and update the Geom File line
128
+ try:
129
+ with open(plan_file_path, 'r') as file:
130
+ lines = file.readlines()
131
+
132
+ for i, line in enumerate(lines):
133
+ if line.startswith("Geom File="):
134
+ lines[i] = f"Geom File=g{new_geom}\n"
135
+ logger.info(f"Updated Geom File in plan file to g{new_geom} for plan {plan_number}")
136
+ break
137
+
138
+ with open(plan_file_path, 'w') as file:
139
+ file.writelines(lines)
140
+ except Exception as e:
141
+ logger.error(f"Error updating plan file: {e}")
142
+ raise
143
+ # Update the plan_df without reinitializing
123
144
  mask = ras_obj.plan_df['plan_number'] == plan_number
124
145
  ras_obj.plan_df.loc[mask, 'geom_number'] = new_geom
146
+ ras_obj.plan_df.loc[mask, 'geometry_number'] = new_geom # Update geometry_number column
125
147
  ras_obj.plan_df.loc[mask, 'Geom File'] = f"g{new_geom}"
126
148
  geom_path = ras_obj.project_folder / f"{ras_obj.project_name}.g{new_geom}"
127
149
  ras_obj.plan_df.loc[mask, 'Geom Path'] = str(geom_path)
@@ -130,27 +152,8 @@ class RasPlan:
130
152
  logger.debug("Updated plan DataFrame:")
131
153
  logger.debug(ras_obj.plan_df)
132
154
 
133
- # Update project file and reinitialize
134
- RasUtils.update_file(ras_obj.prj_file, RasPlan._update_geom_in_file, plan_number, new_geom)
135
- ras_obj.initialize(ras_obj.project_folder, ras_obj.ras_exe_path)
136
-
137
155
  return ras_obj.plan_df
138
156
 
139
- @staticmethod
140
- def _update_geom_in_file(lines, plan_number, new_geom):
141
- plan_pattern = re.compile(rf"^Plan File=p{plan_number}", re.IGNORECASE)
142
- geom_pattern = re.compile(r"^Geom File=g\d+", re.IGNORECASE)
143
-
144
- for i, line in enumerate(lines):
145
- if plan_pattern.match(line):
146
- for j in range(i+1, len(lines)):
147
- if geom_pattern.match(lines[j]):
148
- lines[j] = f"Geom File=g{new_geom}\n"
149
- logger.info(f"Updated Geom File in project file to g{new_geom} for plan {plan_number}")
150
- break
151
- break
152
- return lines
153
-
154
157
  @staticmethod
155
158
  @log_call
156
159
  def set_steady(plan_number: str, new_steady_flow_number: str, ras_object=None):
@@ -249,7 +252,19 @@ class RasPlan:
249
252
  raise FileNotFoundError(f"Plan file not found: {plan_number}")
250
253
 
251
254
  try:
252
- RasUtils.update_file(plan_file_path, RasPlan._update_unsteady_in_file, new_unsteady_flow_number)
255
+ # Read the plan file
256
+ with open(plan_file_path, 'r') as f:
257
+ lines = f.readlines()
258
+
259
+ # Update the Flow File line
260
+ for i, line in enumerate(lines):
261
+ if line.startswith("Flow File="):
262
+ lines[i] = f"Flow File=u{new_unsteady_flow_number}\n"
263
+ break
264
+
265
+ # Write back to the plan file
266
+ with open(plan_file_path, 'w') as f:
267
+ f.writelines(lines)
253
268
 
254
269
  # Update all dataframes
255
270
  ras_obj.plan_df = ras_obj.get_plan_entries()
@@ -957,7 +972,7 @@ class RasPlan:
957
972
  return None
958
973
 
959
974
 
960
- # NEW FUNCTIONS THAT NEED TESTING AND EXAMPLES
975
+
961
976
 
962
977
 
963
978
  @staticmethod
ras_commander/RasPrj.py CHANGED
@@ -118,22 +118,25 @@ class RasPrj:
118
118
  @log_call
119
119
  def initialize(self, project_folder, ras_exe_path, suppress_logging=True):
120
120
  """
121
- Initialize a RasPrj instance.
121
+ Initialize a RasPrj instance with project folder and RAS executable path.
122
122
 
123
- This method sets up the RasPrj instance with the given project folder and RAS executable path.
124
- It finds the project file, loads project data, sets the initialization flag, and now also
125
- extracts boundary conditions.
123
+ IMPORTANT: External users should use init_ras_project() function instead of this method.
124
+ This method is intended for internal use only.
126
125
 
127
126
  Args:
128
127
  project_folder (str or Path): Path to the HEC-RAS project folder.
129
128
  ras_exe_path (str or Path): Path to the HEC-RAS executable.
130
- suppress_logging (bool): If True, suppresses initialization logging messages.
129
+ suppress_logging (bool, default=True): If True, suppresses initialization logging messages.
131
130
 
132
131
  Raises:
133
132
  ValueError: If no HEC-RAS project file is found in the specified folder.
134
133
 
135
134
  Note:
136
- This method is intended for internal use. External users should use the init_ras_project function instead.
135
+ This method sets up the RasPrj instance by:
136
+ 1. Finding the project file (.prj)
137
+ 2. Loading project data (plans, geometries, flows)
138
+ 3. Extracting boundary conditions
139
+ 4. Setting the initialization flag
137
140
  """
138
141
  self.suppress_logging = suppress_logging # Store suppress_logging state
139
142
  self.project_folder = Path(project_folder)
@@ -143,10 +146,14 @@ class RasPrj:
143
146
  raise ValueError(f"No HEC-RAS project file found in {self.project_folder}")
144
147
  self.project_name = Path(self.prj_file).stem
145
148
  self.ras_exe_path = ras_exe_path
146
- self._load_project_data()
147
- self.boundaries_df = self.get_boundary_conditions() # Extract boundary conditions
149
+
150
+ # Set initialized to True before loading project data
148
151
  self.initialized = True
149
152
 
153
+ # Now load the project data
154
+ self._load_project_data()
155
+ self.boundaries_df = self.get_boundary_conditions()
156
+
150
157
  if not suppress_logging:
151
158
  logger.info(f"Initialization complete for project: {self.project_name}")
152
159
  logger.info(f"Plan entries: {len(self.plan_df)}, Flow entries: {len(self.flow_df)}, "
@@ -159,8 +166,13 @@ class RasPrj:
159
166
  """
160
167
  Load project data from the HEC-RAS project file.
161
168
 
162
- This method initializes DataFrames for plan, flow, unsteady, and geometry entries
163
- and ensures all required columns are present with appropriate paths.
169
+ This internal method:
170
+ 1. Initializes DataFrames for plan, flow, unsteady, and geometry entries
171
+ 2. Ensures all required columns are present with appropriate default values
172
+ 3. Sets file paths for all components (geometries, flows, plans)
173
+
174
+ Raises:
175
+ Exception: If there's an error loading or processing project data.
164
176
  """
165
177
  try:
166
178
  # Load data frames
@@ -632,10 +644,14 @@ class RasPrj:
632
644
  @log_call
633
645
  def check_initialized(self):
634
646
  """
635
- Ensure that the RasPrj instance has been initialized.
647
+ Ensure that the RasPrj instance has been initialized before operations.
636
648
 
637
649
  Raises:
638
- RuntimeError: If the project has not been initialized.
650
+ RuntimeError: If the project has not been initialized with init_ras_project().
651
+
652
+ Note:
653
+ This method is called by other methods to validate the project state before
654
+ performing operations. Users typically don't need to call this directly.
639
655
  """
640
656
  if not self.initialized:
641
657
  raise RuntimeError("Project not initialized. Call init_ras_project() first.")
@@ -646,11 +662,23 @@ class RasPrj:
646
662
  """
647
663
  Find the appropriate HEC-RAS project file (.prj) in the given folder.
648
664
 
649
- Parameters:
650
- folder_path (str or Path): Path to the folder containing HEC-RAS files.
665
+ This method uses several strategies to locate the correct project file:
666
+ 1. If only one .prj file exists, it is selected
667
+ 2. If multiple .prj files exist, it tries to match with .rasmap file names
668
+ 3. As a last resort, it scans files for "Proj Title=" content
669
+
670
+ Args:
671
+ folder_path (str or Path): Path to the folder containing HEC-RAS files.
651
672
 
652
673
  Returns:
653
- Path: The full path of the selected .prj file or None if no suitable file is found.
674
+ Path: The full path of the selected .prj file or None if no suitable file is found.
675
+
676
+ Example:
677
+ >>> project_file = RasPrj.find_ras_prj("/path/to/ras_project")
678
+ >>> if project_file:
679
+ ... print(f"Found project file: {project_file}")
680
+ ... else:
681
+ ... print("No project file found")
654
682
  """
655
683
  folder_path = Path(folder_path)
656
684
  prj_files = list(folder_path.glob("*.prj"))
@@ -677,13 +705,17 @@ class RasPrj:
677
705
  @log_call
678
706
  def get_project_name(self):
679
707
  """
680
- Get the name of the HEC-RAS project.
708
+ Get the name of the HEC-RAS project (without file extension).
681
709
 
682
710
  Returns:
683
711
  str: The name of the project.
684
712
 
685
713
  Raises:
686
714
  RuntimeError: If the project has not been initialized.
715
+
716
+ Example:
717
+ >>> project_name = ras.get_project_name()
718
+ >>> print(f"Working with project: {project_name}")
687
719
  """
688
720
  self.check_initialized()
689
721
  return self.project_name
@@ -693,14 +725,26 @@ class RasPrj:
693
725
  """
694
726
  Get entries of a specific type from the HEC-RAS project.
695
727
 
728
+ This method extracts files of the specified type from the project file,
729
+ parses their content, and returns a structured DataFrame.
730
+
696
731
  Args:
697
- entry_type (str): The type of entry to retrieve (e.g., 'Plan', 'Flow', 'Unsteady', 'Geom').
732
+ entry_type (str): The type of entry to retrieve ('Plan', 'Flow', 'Unsteady', or 'Geom').
698
733
 
699
734
  Returns:
700
- pd.DataFrame: A DataFrame containing the requested entries.
735
+ pd.DataFrame: A DataFrame containing the requested entries with appropriate columns.
701
736
 
702
737
  Raises:
703
738
  RuntimeError: If the project has not been initialized.
739
+
740
+ Example:
741
+ >>> # Get all geometry files in the project
742
+ >>> geom_entries = ras.get_prj_entries('Geom')
743
+ >>> print(f"Project contains {len(geom_entries)} geometry files")
744
+
745
+ Note:
746
+ This is a generic method. For specific file types, use the dedicated methods:
747
+ get_plan_entries(), get_flow_entries(), get_unsteady_entries(), get_geom_entries()
704
748
  """
705
749
  self.check_initialized()
706
750
  return self._get_prj_entries(entry_type)
@@ -709,12 +753,23 @@ class RasPrj:
709
753
  def get_plan_entries(self):
710
754
  """
711
755
  Get all plan entries from the HEC-RAS project.
756
+
757
+ Returns a DataFrame containing all plan files (.p*) in the project
758
+ with their associated properties, paths and settings.
712
759
 
713
760
  Returns:
714
- pd.DataFrame: A DataFrame containing all plan entries.
761
+ pd.DataFrame: A DataFrame with columns including 'plan_number', 'full_path',
762
+ 'unsteady_number', 'geometry_number', etc.
715
763
 
716
764
  Raises:
717
765
  RuntimeError: If the project has not been initialized.
766
+
767
+ Example:
768
+ >>> plan_entries = ras.get_plan_entries()
769
+ >>> print(f"Project contains {len(plan_entries)} plan files")
770
+ >>> # Display the first plan's properties
771
+ >>> if not plan_entries.empty:
772
+ ... print(plan_entries.iloc[0])
718
773
  """
719
774
  self.check_initialized()
720
775
  return self._get_prj_entries('Plan')
@@ -723,12 +778,22 @@ class RasPrj:
723
778
  def get_flow_entries(self):
724
779
  """
725
780
  Get all flow entries from the HEC-RAS project.
781
+
782
+ Returns a DataFrame containing all flow files (.f*) in the project
783
+ with their associated properties and paths.
726
784
 
727
785
  Returns:
728
- pd.DataFrame: A DataFrame containing all flow entries.
786
+ pd.DataFrame: A DataFrame with columns including 'flow_number', 'full_path', etc.
729
787
 
730
788
  Raises:
731
789
  RuntimeError: If the project has not been initialized.
790
+
791
+ Example:
792
+ >>> flow_entries = ras.get_flow_entries()
793
+ >>> print(f"Project contains {len(flow_entries)} flow files")
794
+ >>> # Display the first flow file's properties
795
+ >>> if not flow_entries.empty:
796
+ ... print(flow_entries.iloc[0])
732
797
  """
733
798
  self.check_initialized()
734
799
  return self._get_prj_entries('Flow')
@@ -737,12 +802,22 @@ class RasPrj:
737
802
  def get_unsteady_entries(self):
738
803
  """
739
804
  Get all unsteady flow entries from the HEC-RAS project.
805
+
806
+ Returns a DataFrame containing all unsteady flow files (.u*) in the project
807
+ with their associated properties and paths.
740
808
 
741
809
  Returns:
742
- pd.DataFrame: A DataFrame containing all unsteady flow entries.
810
+ pd.DataFrame: A DataFrame with columns including 'unsteady_number', 'full_path', etc.
743
811
 
744
812
  Raises:
745
813
  RuntimeError: If the project has not been initialized.
814
+
815
+ Example:
816
+ >>> unsteady_entries = ras.get_unsteady_entries()
817
+ >>> print(f"Project contains {len(unsteady_entries)} unsteady flow files")
818
+ >>> # Display the first unsteady file's properties
819
+ >>> if not unsteady_entries.empty:
820
+ ... print(unsteady_entries.iloc[0])
746
821
  """
747
822
  self.check_initialized()
748
823
  return self._get_prj_entries('Unsteady')
@@ -750,11 +825,26 @@ class RasPrj:
750
825
  @log_call
751
826
  def get_geom_entries(self):
752
827
  """
753
- Get geometry entries from the project file.
828
+ Get all geometry entries from the HEC-RAS project.
829
+
830
+ Returns a DataFrame containing all geometry files (.g*) in the project
831
+ with their associated properties, paths and HDF links.
754
832
 
755
833
  Returns:
756
- pd.DataFrame: DataFrame containing geometry entries.
834
+ pd.DataFrame: A DataFrame with columns including 'geom_number', 'full_path',
835
+ 'hdf_path', etc.
836
+
837
+ Raises:
838
+ RuntimeError: If the project has not been initialized.
839
+
840
+ Example:
841
+ >>> geom_entries = ras.get_geom_entries()
842
+ >>> print(f"Project contains {len(geom_entries)} geometry files")
843
+ >>> # Display the first geometry file's properties
844
+ >>> if not geom_entries.empty:
845
+ ... print(geom_entries.iloc[0])
757
846
  """
847
+ self.check_initialized()
758
848
  geom_pattern = re.compile(r'Geom File=(\w+)')
759
849
  geom_entries = []
760
850
 
@@ -780,11 +870,28 @@ class RasPrj:
780
870
  @log_call
781
871
  def get_hdf_entries(self):
782
872
  """
783
- Get HDF entries for plans that have results.
873
+ Get all plan entries that have associated HDF results files.
874
+
875
+ This method identifies which plans have been successfully computed
876
+ and have HDF results available for further analysis.
784
877
 
785
878
  Returns:
786
879
  pd.DataFrame: A DataFrame containing plan entries with HDF results.
787
- Returns an empty DataFrame if no HDF entries are found.
880
+ Returns an empty DataFrame if no results are found.
881
+
882
+ Raises:
883
+ RuntimeError: If the project has not been initialized.
884
+
885
+ Example:
886
+ >>> hdf_entries = ras.get_hdf_entries()
887
+ >>> if hdf_entries.empty:
888
+ ... print("No computed results found. Run simulations first.")
889
+ ... else:
890
+ ... print(f"Found results for {len(hdf_entries)} plans")
891
+
892
+ Note:
893
+ This is useful for identifying which plans have been successfully computed
894
+ and can be used for further results analysis.
788
895
  """
789
896
  self.check_initialized()
790
897
 
@@ -798,7 +905,23 @@ class RasPrj:
798
905
 
799
906
  @log_call
800
907
  def print_data(self):
801
- """Print all RAS Object data for this instance."""
908
+ """
909
+ Print a comprehensive summary of all RAS Object data for this instance.
910
+
911
+ This method outputs:
912
+ - Project information (name, folder, file paths)
913
+ - Summary of plans, flows, geometries, and unsteady files
914
+ - HDF results availability
915
+ - Boundary conditions
916
+
917
+ Useful for debugging, validation, and exploring project structure.
918
+
919
+ Raises:
920
+ RuntimeError: If the project has not been initialized.
921
+
922
+ Example:
923
+ >>> ras.print_data() # Displays complete project overview
924
+ """
802
925
  self.check_initialized()
803
926
  logger.info(f"--- Data for {self.project_name} ---")
804
927
  logger.info(f"Project folder: {self.project_folder}")
@@ -821,33 +944,37 @@ class RasPrj:
821
944
  @log_call
822
945
  def get_boundary_conditions(self) -> pd.DataFrame:
823
946
  """
824
- Extract boundary conditions from unsteady flow files and create a DataFrame.
947
+ Extract boundary conditions from unsteady flow files into a structured DataFrame.
825
948
 
826
- This method parses unsteady flow files to extract boundary condition information.
827
- It creates a DataFrame with structured data for known boundary condition types
828
- and parameters, and associates this information with the corresponding unsteady flow file.
949
+ This method:
950
+ 1. Parses all unsteady flow files to extract boundary condition information
951
+ 2. Creates a structured DataFrame with boundary locations, types and parameters
952
+ 3. Links boundary conditions to their respective unsteady flow files
829
953
 
830
- Note:
831
- Any lines in the boundary condition blocks that are not explicitly parsed and
832
- incorporated into the DataFrame are captured in a multi-line string. This string
833
- is logged at the DEBUG level for each boundary condition. This feature is crucial
834
- for developers incorporating new boundary condition types or parameters, as it
835
- allows them to see what information might be missing from the current parsing logic.
836
- If no unsteady flow files are present, it returns an empty DataFrame.
954
+ Supported boundary condition types include:
955
+ - Flow Hydrograph
956
+ - Stage Hydrograph
957
+ - Normal Depth
958
+ - Lateral Inflow Hydrograph
959
+ - Uniform Lateral Inflow Hydrograph
960
+ - Gate Opening
837
961
 
838
962
  Returns:
839
- pd.DataFrame: A DataFrame containing detailed boundary condition information,
840
- linked to the unsteady flow files.
841
-
842
- Usage:
843
- To see the unparsed lines, set the logging level to DEBUG before calling this method:
844
-
963
+ pd.DataFrame: A DataFrame containing detailed boundary condition information.
964
+ Returns an empty DataFrame if no unsteady flow files are present.
965
+
966
+ Example:
967
+ >>> boundaries = ras.get_boundary_conditions()
968
+ >>> if not boundaries.empty:
969
+ ... print(f"Found {len(boundaries)} boundary conditions")
970
+ ... # Show flow hydrographs only
971
+ ... flow_hydrographs = boundaries[boundaries['bc_type'] == 'Flow Hydrograph']
972
+ ... print(f"Project has {len(flow_hydrographs)} flow hydrographs")
973
+
974
+ Note:
975
+ To see unparsed boundary condition lines for debugging, set logging to DEBUG:
845
976
  import logging
846
- getLogger().setLevel(logging.DEBUG)
847
-
848
- boundaries_df = ras_project.get_boundary_conditions()
849
- linked to the unsteady flow files. Returns an empty DataFrame if
850
- no unsteady flow files are present.
977
+ logging.getLogger().setLevel(logging.DEBUG)
851
978
  """
852
979
  boundary_data = []
853
980
 
@@ -1117,27 +1244,38 @@ ras = RasPrj()
1117
1244
  @log_call
1118
1245
  def init_ras_project(ras_project_folder, ras_version=None, ras_object=None):
1119
1246
  """
1120
- Initialize a RAS project.
1121
-
1122
- USE THIS FUNCTION TO INITIALIZE A RAS PROJECT, NOT THE INITIALIZE METHOD OF THE RasPrj CLASS.
1123
-
1124
- Parameters:
1125
- -----------
1126
- ras_project_folder : str
1127
- The path to the RAS project folder.
1128
- ras_version : str, optional
1129
- The version of RAS to use (e.g., "6.6").
1130
- The version can also be a full path to the Ras.exe file.
1131
- If None, the function will attempt to use the version from the global 'ras' object or a default path.
1132
- ras_object : RasPrj or str, optional
1133
- If None, the global 'ras' object is updated.
1134
- If a RasPrj instance, that instance is updated.
1135
- If any other value is provided, a new RasPrj instance is created and returned.
1247
+ Initialize a RAS project for use with the ras-commander library.
1248
+
1249
+ This is the primary function for setting up a HEC-RAS project. It:
1250
+ 1. Finds the project file (.prj) in the specified folder
1251
+ 2. Identifies the appropriate HEC-RAS executable
1252
+ 3. Loads project data (plans, geometries, flows)
1253
+ 4. Creates dataframes containing project components
1254
+
1255
+ Args:
1256
+ ras_project_folder (str or Path): The path to the RAS project folder.
1257
+ ras_version (str, optional): The version of RAS to use (e.g., "6.6").
1258
+ Can also be a full path to the Ras.exe file.
1259
+ If None, will attempt to use a default path.
1260
+ ras_object (RasPrj, optional): If None, updates the global 'ras' object.
1261
+ If a RasPrj instance, updates that instance.
1262
+ If any other value, creates and returns a new RasPrj instance.
1136
1263
 
1137
1264
  Returns:
1138
- --------
1139
- RasPrj
1140
- An initialized RasPrj instance.
1265
+ RasPrj: An initialized RasPrj instance.
1266
+
1267
+ Raises:
1268
+ FileNotFoundError: If the specified project folder doesn't exist.
1269
+ ValueError: If no HEC-RAS project file is found in the folder.
1270
+
1271
+ Example:
1272
+ >>> # Initialize using the global 'ras' object (most common)
1273
+ >>> init_ras_project("/path/to/project", "6.6")
1274
+ >>> print(f"Initialized project: {ras.project_name}")
1275
+ >>>
1276
+ >>> # Create a new RasPrj instance
1277
+ >>> my_project = init_ras_project("/path/to/project", "6.6", "new")
1278
+ >>> print(f"Created project instance: {my_project.project_name}")
1141
1279
  """
1142
1280
  if not Path(ras_project_folder).exists():
1143
1281
  logger.error(f"The specified RAS project folder does not exist: {ras_project_folder}")
@@ -1171,23 +1309,31 @@ def get_ras_exe(ras_version=None):
1171
1309
  """
1172
1310
  Determine the HEC-RAS executable path based on the input.
1173
1311
 
1312
+ This function attempts to find the HEC-RAS executable in the following order:
1313
+ 1. If ras_version is a valid file path to an .exe file, use that path
1314
+ 2. If ras_version is a known version number, use default installation path
1315
+ 3. If global 'ras' object has ras_exe_path, use that
1316
+ 4. As a fallback, return a default path (which may not exist)
1317
+
1174
1318
  Args:
1175
1319
  ras_version (str, optional): Either a version number or a full path to the HEC-RAS executable.
1176
- If None, the function will first check the global 'ras' object for a path.
1177
- or a default path.
1178
1320
 
1179
1321
  Returns:
1180
1322
  str: The full path to the HEC-RAS executable.
1181
1323
 
1182
- Raises:
1183
- ValueError: If the input is neither a valid version number nor a valid file path.
1184
-
1185
- Notes:
1186
- - If ras_version is not provided, the function will first check the global 'ras' object for a path.
1187
- - If the global 'ras' object is not initialized or doesn't have a path, a default path will be used.
1188
- - The default path allows the library to function in environments without HEC-RAS installed.
1189
- - This enables the HEC-Commander GPT to operate without stopping, even if HEC-RAS is not present.
1190
- - End users MUST use logging to check for operational errors, as full code stops prevent the GPT from running.
1324
+ Note:
1325
+ - HEC-RAS version numbers include: "6.6", "6.5", "6.4.1", "6.3", etc.
1326
+ - The default installation path follows: C:/Program Files (x86)/HEC/HEC-RAS/{version}/Ras.exe
1327
+ - Returns a default path ("Ras.exe") if no valid path is found
1328
+ - This allows the library to function even without HEC-RAS installed
1329
+
1330
+ Example:
1331
+ >>> # Get path for specific version
1332
+ >>> ras_path = get_ras_exe("6.6")
1333
+ >>> print(f"HEC-RAS 6.6 executable: {ras_path}")
1334
+ >>>
1335
+ >>> # Provide direct path to executable
1336
+ >>> custom_path = get_ras_exe("C:/My_Programs/HEC-RAS/Ras.exe")
1191
1337
  """
1192
1338
  if ras_version is None:
1193
1339
  if hasattr(ras, 'ras_exe_path') and ras.ras_exe_path: