ras-commander 0.35.0__py3-none-any.whl → 0.36.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 +360 -332
 - ras_commander/RasExamples.py +113 -80
 - ras_commander/RasGeo.py +38 -28
 - ras_commander/RasGpt.py +142 -0
 - ras_commander/RasHdf.py +170 -253
 - ras_commander/RasPlan.py +115 -166
 - ras_commander/RasPrj.py +212 -141
 - ras_commander/RasUnsteady.py +37 -22
 - ras_commander/RasUtils.py +98 -82
 - ras_commander/__init__.py +11 -13
 - ras_commander/logging_config.py +80 -0
 - {ras_commander-0.35.0.dist-info → ras_commander-0.36.0.dist-info}/METADATA +15 -11
 - ras_commander-0.36.0.dist-info/RECORD +17 -0
 - ras_commander-0.35.0.dist-info/RECORD +0 -15
 - {ras_commander-0.35.0.dist-info → ras_commander-0.36.0.dist-info}/LICENSE +0 -0
 - {ras_commander-0.35.0.dist-info → ras_commander-0.36.0.dist-info}/WHEEL +0 -0
 - {ras_commander-0.35.0.dist-info → ras_commander-0.36.0.dist-info}/top_level.txt +0 -0
 
    
        ras_commander/RasHdf.py
    CHANGED
    
    | 
         @@ -24,7 +24,27 @@ Example: 
     | 
|
| 
       24 
24 
     | 
    
         
             
                def example_method(cls, hdf_file: h5py.File, other_args):
         
     | 
| 
       25 
25 
     | 
    
         
             
                    # Method implementation using hdf_file
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
            This module is part of the ras-commander library and uses a centralized logging configuration.
         
     | 
| 
       27 
28 
     | 
    
         | 
| 
      
 29 
     | 
    
         
            +
            Logging Configuration:
         
     | 
| 
      
 30 
     | 
    
         
            +
            - The logging is set up in the logging_config.py file.
         
     | 
| 
      
 31 
     | 
    
         
            +
            - A @log_call decorator is available to automatically log function calls.
         
     | 
| 
      
 32 
     | 
    
         
            +
            - Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
         
     | 
| 
      
 33 
     | 
    
         
            +
            - Logs are written to both console and a rotating file handler.
         
     | 
| 
      
 34 
     | 
    
         
            +
            - The default log file is 'ras_commander.log' in the 'logs' directory.
         
     | 
| 
      
 35 
     | 
    
         
            +
            - The default log level is INFO.
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            To use logging in this module:
         
     | 
| 
      
 38 
     | 
    
         
            +
            1. Use the @log_call decorator for automatic function call logging.
         
     | 
| 
      
 39 
     | 
    
         
            +
            2. For additional logging, use logger.[level]() calls (e.g., logger.info(), logger.debug()).
         
     | 
| 
      
 40 
     | 
    
         
            +
            3. Obtain the logger using: logger = logging.getLogger(__name__)
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            Example:
         
     | 
| 
      
 43 
     | 
    
         
            +
                @log_call
         
     | 
| 
      
 44 
     | 
    
         
            +
                def my_function():
         
     | 
| 
      
 45 
     | 
    
         
            +
                    logger = logging.getLogger(__name__)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    logger.debug("Additional debug information")
         
     | 
| 
      
 47 
     | 
    
         
            +
                    # Function logic here
         
     | 
| 
       28 
48 
     | 
    
         
             
            """
         
     | 
| 
       29 
49 
     | 
    
         
             
            import h5py
         
     | 
| 
       30 
50 
     | 
    
         
             
            import numpy as np
         
     | 
| 
         @@ -41,14 +61,10 @@ from .RasPrj import RasPrj, ras, init_ras_project 
     | 
|
| 
       41 
61 
     | 
    
         
             
            from typing import TYPE_CHECKING
         
     | 
| 
       42 
62 
     | 
    
         
             
            if TYPE_CHECKING:
         
     | 
| 
       43 
63 
     | 
    
         
             
                from .RasPrj import RasPrj
         
     | 
| 
      
 64 
     | 
    
         
            +
            from ras_commander import get_logger
         
     | 
| 
      
 65 
     | 
    
         
            +
            from ras_commander.logging_config import log_call
         
     | 
| 
       44 
66 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            logging.basicConfig(
         
     | 
| 
       47 
     | 
    
         
            -
                level=logging.INFO,
         
     | 
| 
       48 
     | 
    
         
            -
                format='%(asctime)s - %(levelname)s - %(message)s',
         
     | 
| 
       49 
     | 
    
         
            -
                handlers=[
         
     | 
| 
       50 
     | 
    
         
            -
                    logging.StreamHandler()
         
     | 
| 
       51 
     | 
    
         
            -
                ])
         
     | 
| 
      
 67 
     | 
    
         
            +
            logger = get_logger(__name__)
         
     | 
| 
       52 
68 
     | 
    
         | 
| 
       53 
69 
     | 
    
         
             
            class RasHdf:
         
     | 
| 
       54 
70 
     | 
    
         
             
                """
         
     | 
| 
         @@ -58,53 +74,51 @@ class RasHdf: 
     | 
|
| 
       58 
74 
     | 
    
         
             
                including listing paths, extracting data, and performing analyses on
         
     | 
| 
       59 
75 
     | 
    
         
             
                HEC-RAS project data stored in HDF format.
         
     | 
| 
       60 
76 
     | 
    
         
             
                """
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
      
 77 
     | 
    
         
            +
                
         
     | 
| 
      
 78 
     | 
    
         
            +
                
         
     | 
| 
       62 
79 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       63 
80 
     | 
    
         
             
                def hdf_operation(func):
         
     | 
| 
      
 81 
     | 
    
         
            +
                    """
         
     | 
| 
      
 82 
     | 
    
         
            +
                    A decorator for HDF file operations in the RasHdf class.
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    This decorator wraps methods that perform operations on HDF files. It handles:
         
     | 
| 
      
 85 
     | 
    
         
            +
                    1. Resolving the HDF filename from various input types.
         
     | 
| 
      
 86 
     | 
    
         
            +
                    2. Opening and closing the HDF file.
         
     | 
| 
      
 87 
     | 
    
         
            +
                    3. Error handling and logging.
         
     | 
| 
      
 88 
     | 
    
         
            +
                    4. Applying the decorated function as a class method.
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 91 
     | 
    
         
            +
                        func (Callable): The function to be decorated.
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 94 
     | 
    
         
            +
                        Callable: A wrapped version of the input function as a class method.
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    Raises:
         
     | 
| 
      
 97 
     | 
    
         
            +
                        ValueError: If the HDF file is not found.
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                    Usage:
         
     | 
| 
      
 100 
     | 
    
         
            +
                        @RasHdf.hdf_operation
         
     | 
| 
      
 101 
     | 
    
         
            +
                        def some_hdf_method(cls, hdf_file, ...):
         
     | 
| 
      
 102 
     | 
    
         
            +
                            # Method implementation
         
     | 
| 
      
 103 
     | 
    
         
            +
                    """
         
     | 
| 
       64 
104 
     | 
    
         
             
                    @wraps(func)
         
     | 
| 
       65 
105 
     | 
    
         
             
                    def wrapper(cls, hdf_input: Union[str, Path], *args: Any, **kwargs: Any) -> Any:
         
     | 
| 
       66 
106 
     | 
    
         
             
                        from ras_commander import ras  # Import here to avoid circular import
         
     | 
| 
       67 
107 
     | 
    
         
             
                        ras_obj = kwargs.pop('ras_object', None) or ras
         
     | 
| 
       68 
108 
     | 
    
         
             
                        try:
         
     | 
| 
       69 
109 
     | 
    
         
             
                            hdf_filename = cls._get_hdf_filename(hdf_input, ras_obj)
         
     | 
| 
      
 110 
     | 
    
         
            +
                            if hdf_filename is None:
         
     | 
| 
      
 111 
     | 
    
         
            +
                                raise ValueError(f"HDF file {hdf_input} not found. Use a try-except block to catch this error.")
         
     | 
| 
       70 
112 
     | 
    
         
             
                            with h5py.File(hdf_filename, 'r') as hdf_file:
         
     | 
| 
       71 
113 
     | 
    
         
             
                                return func(cls, hdf_file, *args, **kwargs)
         
     | 
| 
       72 
114 
     | 
    
         
             
                        except Exception as e:
         
     | 
| 
       73 
     | 
    
         
            -
                             
     | 
| 
      
 115 
     | 
    
         
            +
                            logger.error(f"Error in {func.__name__}: {e}")
         
     | 
| 
       74 
116 
     | 
    
         
             
                            return None
         
     | 
| 
       75 
117 
     | 
    
         
             
                    return classmethod(wrapper)
         
     | 
| 
       76 
     | 
    
         
            -
                
         
     | 
| 
       77 
     | 
    
         
            -
                @classmethod
         
     | 
| 
       78 
     | 
    
         
            -
                def get_hdf_paths_with_properties(cls, hdf_input: Union[str, Path], ras_object=None) -> pd.DataFrame:
         
     | 
| 
       79 
     | 
    
         
            -
                    """
         
     | 
| 
       80 
     | 
    
         
            -
                    List all paths in the HDF file with their properties.
         
     | 
| 
       81 
118 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                    Args:
         
     | 
| 
       83 
     | 
    
         
            -
                        hdf_input (Union[str, Path]): The plan number or full path to the HDF file.
         
     | 
| 
       84 
     | 
    
         
            -
                        ras_object (RasPrj, optional): The RAS project object. If None, uses the global ras instance.
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       87 
     | 
    
         
            -
                        pd.DataFrame: DataFrame of all paths and their properties in the HDF file.
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                    Example:
         
     | 
| 
       90 
     | 
    
         
            -
                        >>> paths_df = RasHdf.get_hdf_paths_with_properties("path/to/file.hdf")
         
     | 
| 
       91 
     | 
    
         
            -
                        >>> print(paths_df.head())
         
     | 
| 
       92 
     | 
    
         
            -
                    """
         
     | 
| 
       93 
     | 
    
         
            -
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       94 
     | 
    
         
            -
                        paths = []
         
     | 
| 
       95 
     | 
    
         
            -
                        def visitor_func(name: str, node: h5py.Group) -> None:
         
     | 
| 
       96 
     | 
    
         
            -
                            path_info = {
         
     | 
| 
       97 
     | 
    
         
            -
                                "HDF_Path": name,
         
     | 
| 
       98 
     | 
    
         
            -
                                "Type": type(node).__name__,
         
     | 
| 
       99 
     | 
    
         
            -
                                "Shape": getattr(node, "shape", None),
         
     | 
| 
       100 
     | 
    
         
            -
                                "Size": getattr(node, "size", None),
         
     | 
| 
       101 
     | 
    
         
            -
                                "Dtype": getattr(node, "dtype", None)
         
     | 
| 
       102 
     | 
    
         
            -
                            }
         
     | 
| 
       103 
     | 
    
         
            -
                            paths.append(path_info)
         
     | 
| 
       104 
     | 
    
         
            -
                        hdf_file.visititems(visitor_func)
         
     | 
| 
       105 
     | 
    
         
            -
                        return pd.DataFrame(paths)
         
     | 
| 
       106 
119 
     | 
    
         | 
| 
       107 
120 
     | 
    
         
             
                @classmethod
         
     | 
| 
      
 121 
     | 
    
         
            +
                @log_call
         
     | 
| 
       108 
122 
     | 
    
         
             
                def get_runtime_data(cls, hdf_input: Union[str, Path], ras_object=None) -> Optional[pd.DataFrame]:
         
     | 
| 
       109 
123 
     | 
    
         
             
                    """
         
     | 
| 
       110 
124 
     | 
    
         
             
                    Extract runtime and compute time data from a single HDF file.
         
     | 
| 
         @@ -122,15 +136,15 @@ class RasHdf: 
     | 
|
| 
       122 
136 
     | 
    
         
             
                        ...     print(runtime_df.head())
         
     | 
| 
       123 
137 
     | 
    
         
             
                    """
         
     | 
| 
       124 
138 
     | 
    
         
             
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       125 
     | 
    
         
            -
                         
     | 
| 
      
 139 
     | 
    
         
            +
                        logger.info(f"Extracting Plan Information from: {Path(hdf_file.filename).name}")
         
     | 
| 
       126 
140 
     | 
    
         
             
                        plan_info = hdf_file.get('/Plan Data/Plan Information')
         
     | 
| 
       127 
141 
     | 
    
         
             
                        if plan_info is None:
         
     | 
| 
       128 
     | 
    
         
            -
                             
     | 
| 
      
 142 
     | 
    
         
            +
                            logger.warning("Group '/Plan Data/Plan Information' not found.")
         
     | 
| 
       129 
143 
     | 
    
         
             
                            return None
         
     | 
| 
       130 
144 
     | 
    
         | 
| 
       131 
145 
     | 
    
         
             
                        plan_name = plan_info.attrs.get('Plan Name', 'Unknown')
         
     | 
| 
       132 
146 
     | 
    
         
             
                        plan_name = plan_name.decode('utf-8') if isinstance(plan_name, bytes) else plan_name
         
     | 
| 
       133 
     | 
    
         
            -
                         
     | 
| 
      
 147 
     | 
    
         
            +
                        logger.info(f"Plan Name: {plan_name}")
         
     | 
| 
       134 
148 
     | 
    
         | 
| 
       135 
149 
     | 
    
         
             
                        start_time_str = plan_info.attrs.get('Simulation Start Time', 'Unknown')
         
     | 
| 
       136 
150 
     | 
    
         
             
                        end_time_str = plan_info.attrs.get('Simulation End Time', 'Unknown')
         
     | 
| 
         @@ -142,13 +156,13 @@ class RasHdf: 
     | 
|
| 
       142 
156 
     | 
    
         
             
                        simulation_duration = end_time - start_time
         
     | 
| 
       143 
157 
     | 
    
         
             
                        simulation_hours = simulation_duration.total_seconds() / 3600
         
     | 
| 
       144 
158 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
                         
     | 
| 
       146 
     | 
    
         
            -
                         
     | 
| 
       147 
     | 
    
         
            -
                         
     | 
| 
      
 159 
     | 
    
         
            +
                        logger.info(f"Simulation Start Time: {start_time_str}")
         
     | 
| 
      
 160 
     | 
    
         
            +
                        logger.info(f"Simulation End Time: {end_time_str}")
         
     | 
| 
      
 161 
     | 
    
         
            +
                        logger.info(f"Simulation Duration (hours): {simulation_hours}")
         
     | 
| 
       148 
162 
     | 
    
         | 
| 
       149 
163 
     | 
    
         
             
                        compute_processes = hdf_file.get('/Results/Summary/Compute Processes')
         
     | 
| 
       150 
164 
     | 
    
         
             
                        if compute_processes is None:
         
     | 
| 
       151 
     | 
    
         
            -
                             
     | 
| 
      
 165 
     | 
    
         
            +
                            logger.warning("Dataset '/Results/Summary/Compute Processes' not found.")
         
     | 
| 
       152 
166 
     | 
    
         
             
                            return None
         
     | 
| 
       153 
167 
     | 
    
         | 
| 
       154 
168 
     | 
    
         
             
                        process_names = [name.decode('utf-8') for name in compute_processes['Process'][:]]
         
     | 
| 
         @@ -163,8 +177,8 @@ class RasHdf: 
     | 
|
| 
       163 
177 
     | 
    
         
             
                            'Compute Time (hours)': completion_times / (1000 * 3600)
         
     | 
| 
       164 
178 
     | 
    
         
             
                        })
         
     | 
| 
       165 
179 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
                         
     | 
| 
       167 
     | 
    
         
            -
                         
     | 
| 
      
 180 
     | 
    
         
            +
                        logger.debug("Compute processes DataFrame:")
         
     | 
| 
      
 181 
     | 
    
         
            +
                        logger.debug(compute_processes_df)
         
     | 
| 
       168 
182 
     | 
    
         | 
| 
       169 
183 
     | 
    
         
             
                        compute_processes_summary = {
         
     | 
| 
       170 
184 
     | 
    
         
             
                            'Plan Name': [plan_name],
         
     | 
| 
         @@ -184,15 +198,15 @@ class RasHdf: 
     | 
|
| 
       184 
198 
     | 
    
         
             
                        compute_processes_summary['Complete Process Speed (hr/hr)'] = [simulation_hours / compute_processes_summary['Complete Process (hr)'][0] if compute_processes_summary['Complete Process (hr)'][0] != 'N/A' else 'N/A']
         
     | 
| 
       185 
199 
     | 
    
         | 
| 
       186 
200 
     | 
    
         
             
                        compute_summary_df = pd.DataFrame(compute_processes_summary)
         
     | 
| 
       187 
     | 
    
         
            -
                         
     | 
| 
       188 
     | 
    
         
            -
                         
     | 
| 
      
 201 
     | 
    
         
            +
                        logger.debug("Compute summary DataFrame:")
         
     | 
| 
      
 202 
     | 
    
         
            +
                        logger.debug(compute_summary_df)
         
     | 
| 
       189 
203 
     | 
    
         | 
| 
       190 
204 
     | 
    
         
             
                        return compute_summary_df
         
     | 
| 
       191 
205 
     | 
    
         | 
| 
       192 
206 
     | 
    
         
             
                # List 2D Flow Area Groups (needed for later functions that extract specific datasets)
         
     | 
| 
       193 
207 
     | 
    
         | 
| 
       194 
208 
     | 
    
         
             
                @classmethod
         
     | 
| 
       195 
     | 
    
         
            -
                @ 
     | 
| 
      
 209 
     | 
    
         
            +
                @log_call
         
     | 
| 
       196 
210 
     | 
    
         
             
                def get_2d_flow_area_names(cls, hdf_input: Union[str, Path], ras_object=None) -> Optional[List[str]]:
         
     | 
| 
       197 
211 
     | 
    
         
             
                    """
         
     | 
| 
       198 
212 
     | 
    
         
             
                    List 2D Flow Area names from the HDF file.
         
     | 
| 
         @@ -212,16 +226,15 @@ class RasHdf: 
     | 
|
| 
       212 
226 
     | 
    
         
             
                            group = hdf_file['Geometry/2D Flow Areas']
         
     | 
| 
       213 
227 
     | 
    
         
             
                            group_names = [name for name in group.keys() if isinstance(group[name], h5py.Group)]
         
     | 
| 
       214 
228 
     | 
    
         
             
                            if not group_names:
         
     | 
| 
       215 
     | 
    
         
            -
                                 
     | 
| 
      
 229 
     | 
    
         
            +
                                logger.warning("No 2D Flow Areas found in the HDF file")
         
     | 
| 
       216 
230 
     | 
    
         
             
                                return None
         
     | 
| 
       217 
     | 
    
         
            -
                             
     | 
| 
      
 231 
     | 
    
         
            +
                            logger.info(f"Found {len(group_names)} 2D Flow Areas")
         
     | 
| 
       218 
232 
     | 
    
         
             
                            return group_names
         
     | 
| 
       219 
233 
     | 
    
         
             
                        else:
         
     | 
| 
       220 
     | 
    
         
            -
                             
     | 
| 
      
 234 
     | 
    
         
            +
                            logger.warning("No 2D Flow Areas found in the HDF file")
         
     | 
| 
       221 
235 
     | 
    
         
             
                            return None
         
     | 
| 
       222 
     | 
    
         
            -
                        
         
     | 
| 
       223 
236 
     | 
    
         
             
                @classmethod
         
     | 
| 
       224 
     | 
    
         
            -
                @ 
     | 
| 
      
 237 
     | 
    
         
            +
                @log_call
         
     | 
| 
       225 
238 
     | 
    
         
             
                def get_2d_flow_area_attributes(cls, hdf_input: Union[str, Path], ras_object=None) -> Optional[pd.DataFrame]:
         
     | 
| 
       226 
239 
     | 
    
         
             
                    """
         
     | 
| 
       227 
240 
     | 
    
         
             
                    Extract 2D Flow Area Attributes from the HDF file.
         
     | 
| 
         @@ -244,14 +257,12 @@ class RasHdf: 
     | 
|
| 
       244 
257 
     | 
    
         
             
                        if 'Geometry/2D Flow Areas/Attributes' in hdf_file:
         
     | 
| 
       245 
258 
     | 
    
         
             
                            attributes = hdf_file['Geometry/2D Flow Areas/Attributes'][()]
         
     | 
| 
       246 
259 
     | 
    
         
             
                            attributes_df = pd.DataFrame(attributes)
         
     | 
| 
       247 
     | 
    
         
            -
                            logging.info(f"Extracted 2D Flow Area attributes: {attributes_df.shape[0]} rows, {attributes_df.shape[1]} columns")
         
     | 
| 
       248 
260 
     | 
    
         
             
                            return attributes_df
         
     | 
| 
       249 
261 
     | 
    
         
             
                        else:
         
     | 
| 
       250 
     | 
    
         
            -
                            logging.warning("No 2D Flow Area attributes found in the HDF file")
         
     | 
| 
       251 
262 
     | 
    
         
             
                            return None
         
     | 
| 
       252 
263 
     | 
    
         | 
| 
       253 
264 
     | 
    
         
             
                @classmethod
         
     | 
| 
       254 
     | 
    
         
            -
                @ 
     | 
| 
      
 265 
     | 
    
         
            +
                @log_call
         
     | 
| 
       255 
266 
     | 
    
         
             
                def get_cell_info(cls, hdf_input: Union[str, Path], ras_object=None) -> Optional[pd.DataFrame]:
         
     | 
| 
       256 
267 
     | 
    
         
             
                    """
         
     | 
| 
       257 
268 
     | 
    
         
             
                    Extract Cell Info from the HDF file.
         
     | 
| 
         @@ -272,14 +283,10 @@ class RasHdf: 
     | 
|
| 
       272 
283 
     | 
    
         
             
                    """
         
     | 
| 
       273 
284 
     | 
    
         
             
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       274 
285 
     | 
    
         
             
                        cell_info_df = cls._extract_dataset(hdf_file, 'Geometry/2D Flow Areas/Cell Info', ['Start', 'End'])
         
     | 
| 
       275 
     | 
    
         
            -
                        if cell_info_df is not None:
         
     | 
| 
       276 
     | 
    
         
            -
                            logging.info(f"Extracted Cell Info: {cell_info_df.shape[0]} rows, {cell_info_df.shape[1]} columns")
         
     | 
| 
       277 
     | 
    
         
            -
                        else:
         
     | 
| 
       278 
     | 
    
         
            -
                            logging.warning("No Cell Info found in the HDF file")
         
     | 
| 
       279 
286 
     | 
    
         
             
                        return cell_info_df
         
     | 
| 
       280 
287 
     | 
    
         | 
| 
       281 
288 
     | 
    
         
             
                @classmethod
         
     | 
| 
       282 
     | 
    
         
            -
                @ 
     | 
| 
      
 289 
     | 
    
         
            +
                @log_call
         
     | 
| 
       283 
290 
     | 
    
         
             
                def get_cell_points(cls, hdf_input: Union[str, Path], ras_object=None) -> Optional[pd.DataFrame]:
         
     | 
| 
       284 
291 
     | 
    
         
             
                    """
         
     | 
| 
       285 
292 
     | 
    
         
             
                    Extract Cell Points from the HDF file.
         
     | 
| 
         @@ -300,14 +307,10 @@ class RasHdf: 
     | 
|
| 
       300 
307 
     | 
    
         
             
                    """
         
     | 
| 
       301 
308 
     | 
    
         
             
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       302 
309 
     | 
    
         
             
                        cell_points_df = cls._extract_dataset(hdf_file, 'Geometry/2D Flow Areas/Cell Points', ['X', 'Y'])
         
     | 
| 
       303 
     | 
    
         
            -
                        if cell_points_df is not None:
         
     | 
| 
       304 
     | 
    
         
            -
                            logging.info(f"Extracted Cell Points: {cell_points_df.shape[0]} rows, {cell_points_df.shape[1]} columns")
         
     | 
| 
       305 
     | 
    
         
            -
                        else:
         
     | 
| 
       306 
     | 
    
         
            -
                            logging.warning("No Cell Points found in the HDF file")
         
     | 
| 
       307 
310 
     | 
    
         
             
                        return cell_points_df
         
     | 
| 
       308 
311 
     | 
    
         | 
| 
       309 
312 
     | 
    
         
             
                @classmethod
         
     | 
| 
       310 
     | 
    
         
            -
                @ 
     | 
| 
      
 313 
     | 
    
         
            +
                @log_call
         
     | 
| 
       311 
314 
     | 
    
         
             
                def get_polygon_info_and_parts(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]]:
         
     | 
| 
       312 
315 
     | 
    
         
             
                    """
         
     | 
| 
       313 
316 
     | 
    
         
             
                    Extract Polygon Info and Parts from the HDF file.
         
     | 
| 
         @@ -334,24 +337,14 @@ class RasHdf: 
     | 
|
| 
       334 
337 
     | 
    
         
             
                        ...     print("Polygon data not found")
         
     | 
| 
       335 
338 
     | 
    
         
             
                    """
         
     | 
| 
       336 
339 
     | 
    
         
             
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       337 
     | 
    
         
            -
                        # Retrieve the area name, defaulting to the first found if not provided
         
     | 
| 
       338 
340 
     | 
    
         
             
                        area_name = cls._get_area_name(hdf_file, area_name, hdf_file.filename)
         
     | 
| 
       339 
     | 
    
         
            -
             
     | 
| 
       340 
     | 
    
         
            -
                        # Construct the base path for dataset extraction
         
     | 
| 
       341 
341 
     | 
    
         
             
                        base_path = f'Geometry/2D Flow Areas'
         
     | 
| 
       342 
     | 
    
         
            -
                        
         
     | 
| 
       343 
     | 
    
         
            -
                        # Extract Polygon Info and Parts datasets
         
     | 
| 
       344 
342 
     | 
    
         
             
                        polygon_info_df = cls._extract_dataset(hdf_file, f'{base_path}/Polygon Info', ['Column1', 'Column2', 'Column3', 'Column4'])
         
     | 
| 
       345 
343 
     | 
    
         
             
                        polygon_parts_df = cls._extract_dataset(hdf_file, f'{base_path}/Polygon Parts', ['Start', 'Count'])
         
     | 
| 
       346 
     | 
    
         
            -
             
     | 
| 
       347 
     | 
    
         
            -
                        # Log warnings if no data is found
         
     | 
| 
       348 
     | 
    
         
            -
                        if polygon_info_df is None and polygon_parts_df is None:
         
     | 
| 
       349 
     | 
    
         
            -
                            logging.warning(f"No Polygon Info or Parts found for 2D Flow Area: {area_name}")
         
     | 
| 
       350 
     | 
    
         
            -
             
     | 
| 
       351 
344 
     | 
    
         
             
                        return polygon_info_df, polygon_parts_df
         
     | 
| 
       352 
345 
     | 
    
         | 
| 
       353 
346 
     | 
    
         
             
                @classmethod
         
     | 
| 
       354 
     | 
    
         
            -
                @ 
     | 
| 
      
 347 
     | 
    
         
            +
                @log_call
         
     | 
| 
       355 
348 
     | 
    
         
             
                def get_polygon_points(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Optional[pd.DataFrame]:
         
     | 
| 
       356 
349 
     | 
    
         
             
                    """
         
     | 
| 
       357 
350 
     | 
    
         
             
                    Extract Polygon Points from the HDF file.
         
     | 
| 
         @@ -367,19 +360,16 @@ class RasHdf: 
     | 
|
| 
       367 
360 
     | 
    
         
             
                    """
         
     | 
| 
       368 
361 
     | 
    
         
             
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       369 
362 
     | 
    
         
             
                        area_name = cls._get_area_name(hdf_file, area_name, hdf_file.filename)
         
     | 
| 
       370 
     | 
    
         
            -
                        # This path does not include the area name
         
     | 
| 
       371 
363 
     | 
    
         
             
                        polygon_points_path = f'Geometry/2D Flow Areas/Polygon Points'
         
     | 
| 
       372 
364 
     | 
    
         
             
                        if polygon_points_path in hdf_file:
         
     | 
| 
       373 
365 
     | 
    
         
             
                            polygon_points = hdf_file[polygon_points_path][()]
         
     | 
| 
       374 
366 
     | 
    
         
             
                            polygon_points_df = pd.DataFrame(polygon_points, columns=['X', 'Y'])
         
     | 
| 
       375 
     | 
    
         
            -
                            logging.info(f"Extracted Polygon Points for 2D Flow Area {area_name}: {polygon_points_df.shape[0]} rows, {polygon_points_df.shape[1]} columns")
         
     | 
| 
       376 
367 
     | 
    
         
             
                            return polygon_points_df
         
     | 
| 
       377 
368 
     | 
    
         
             
                        else:
         
     | 
| 
       378 
     | 
    
         
            -
                            logging.warning(f"No Polygon Points found for 2D Flow Area: {area_name}")
         
     | 
| 
       379 
369 
     | 
    
         
             
                            return None
         
     | 
| 
       380 
370 
     | 
    
         | 
| 
       381 
371 
     | 
    
         
             
                @classmethod
         
     | 
| 
       382 
     | 
    
         
            -
                @ 
     | 
| 
      
 372 
     | 
    
         
            +
                @log_call
         
     | 
| 
       383 
373 
     | 
    
         
             
                def get_cells_center_data(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]]:
         
     | 
| 
       384 
374 
     | 
    
         
             
                    """
         
     | 
| 
       385 
375 
     | 
    
         
             
                    Extract Cells Center Coordinates and Manning's n from the HDF file.
         
     | 
| 
         @@ -405,45 +395,21 @@ class RasHdf: 
     | 
|
| 
       405 
395 
     | 
    
         
             
                        ... else:
         
     | 
| 
       406 
396 
     | 
    
         
             
                        ...     print("Cell center data not found")
         
     | 
| 
       407 
397 
     | 
    
         
             
                    """
         
     | 
| 
       408 
     | 
    
         
            -
                    logging.info(f"Entering get_cells_center_data method")
         
     | 
| 
       409 
     | 
    
         
            -
                    logging.info(f"Input parameters: hdf_input={hdf_input}, area_name={area_name}")
         
     | 
| 
       410 
     | 
    
         
            -
                    
         
     | 
| 
       411 
398 
     | 
    
         
             
                    try:
         
     | 
| 
       412 
399 
     | 
    
         
             
                        hdf_filename = cls._get_hdf_filename(hdf_input, ras_object)
         
     | 
| 
       413 
     | 
    
         
            -
                        logging.info(f"HDF filename: {hdf_filename}")
         
     | 
| 
       414 
     | 
    
         
            -
                        
         
     | 
| 
       415 
400 
     | 
    
         
             
                        with h5py.File(hdf_filename, 'r') as hdf_file:
         
     | 
| 
       416 
     | 
    
         
            -
                            logging.info(f"Successfully opened HDF file: {hdf_filename}")
         
     | 
| 
       417 
     | 
    
         
            -
                            
         
     | 
| 
       418 
     | 
    
         
            -
                            logging.info(f"Getting Cells Center Data for 2D Flow Area: {area_name}")
         
     | 
| 
       419 
401 
     | 
    
         
             
                            area_name = cls._get_area_name(hdf_file, area_name, hdf_file.filename)
         
     | 
| 
       420 
     | 
    
         
            -
                            logging.info(f"Area Name: {area_name}")
         
     | 
| 
       421 
     | 
    
         
            -
                            
         
     | 
| 
       422 
402 
     | 
    
         
             
                            base_path = f'Geometry/2D Flow Areas/{area_name}'
         
     | 
| 
       423 
403 
     | 
    
         
             
                            cells_center_coord_path = f'{base_path}/Cells Center Coordinate'
         
     | 
| 
       424 
404 
     | 
    
         
             
                            cells_manning_n_path = f'{base_path}/Cells Center Manning\'s n'
         
     | 
| 
       425 
     | 
    
         
            -
                            
         
     | 
| 
       426 
     | 
    
         
            -
                            logging.info(f"Extracting dataset from path: {cells_center_coord_path}")
         
     | 
| 
       427 
405 
     | 
    
         
             
                            cells_center_coord_df = cls._extract_dataset(hdf_file, cells_center_coord_path, ['X', 'Y'])
         
     | 
| 
       428 
     | 
    
         
            -
                            
         
     | 
| 
       429 
     | 
    
         
            -
                            logging.info(f"Extracting dataset from path: {cells_manning_n_path}")
         
     | 
| 
       430 
406 
     | 
    
         
             
                            cells_manning_n_df = cls._extract_dataset(hdf_file, cells_manning_n_path, ['Manning\'s n'])
         
     | 
| 
       431 
     | 
    
         
            -
             
     | 
| 
       432 
     | 
    
         
            -
                            if cells_center_coord_df is not None and cells_manning_n_df is not None:
         
     | 
| 
       433 
     | 
    
         
            -
                                logging.info(f"Extracted Cells Center Data for 2D Flow Area: {area_name}")
         
     | 
| 
       434 
     | 
    
         
            -
                                logging.info(f"Cells Center Coordinates shape: {cells_center_coord_df.shape}, dtype: {cells_center_coord_df.dtypes}")
         
     | 
| 
       435 
     | 
    
         
            -
                                logging.info(f"Cells Manning's n shape: {cells_manning_n_df.shape}, dtype: {cells_manning_n_df.dtypes}")
         
     | 
| 
       436 
     | 
    
         
            -
                            else:
         
     | 
| 
       437 
     | 
    
         
            -
                                logging.warning(f"Cells Center Data not found for 2D Flow Area: {area_name}")
         
     | 
| 
       438 
     | 
    
         
            -
             
     | 
| 
       439 
407 
     | 
    
         
             
                            return cells_center_coord_df, cells_manning_n_df
         
     | 
| 
       440 
     | 
    
         
            -
                    
         
     | 
| 
       441 
408 
     | 
    
         
             
                    except Exception as e:
         
     | 
| 
       442 
     | 
    
         
            -
                        logging.error(f"Error in get_cells_center_data: {str(e)}", exc_info=True)
         
     | 
| 
       443 
409 
     | 
    
         
             
                        return None, None
         
     | 
| 
       444 
410 
     | 
    
         | 
| 
       445 
411 
     | 
    
         
             
                @classmethod
         
     | 
| 
       446 
     | 
    
         
            -
                @ 
     | 
| 
      
 412 
     | 
    
         
            +
                @log_call
         
     | 
| 
       447 
413 
     | 
    
         
             
                def get_faces_area_elevation_data(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Optional[pd.DataFrame]:
         
     | 
| 
       448 
414 
     | 
    
         
             
                    """
         
     | 
| 
       449 
415 
     | 
    
         
             
                    Extract Faces Area Elevation Values from the HDF file.
         
     | 
| 
         @@ -472,17 +438,12 @@ class RasHdf: 
     | 
|
| 
       472 
438 
     | 
    
         
             
                        if area_elev_values_path in hdf_file:
         
     | 
| 
       473 
439 
     | 
    
         
             
                            area_elev_values = hdf_file[area_elev_values_path][()]
         
     | 
| 
       474 
440 
     | 
    
         
             
                            area_elev_values_df = pd.DataFrame(area_elev_values, columns=['Elevation', 'Area', 'Wetted Perimeter', 'Manning\'s n'])
         
     | 
| 
       475 
     | 
    
         
            -
                            
         
     | 
| 
       476 
     | 
    
         
            -
                            logging.info(f"Extracted Faces Area Elevation Values for 2D Flow Area: {area_name}")
         
     | 
| 
       477 
     | 
    
         
            -
                            logging.info(f"Faces Area Elevation Values shape: {area_elev_values.shape}, dtype: {area_elev_values.dtype}")
         
     | 
| 
       478 
     | 
    
         
            -
                            
         
     | 
| 
       479 
441 
     | 
    
         
             
                            return area_elev_values_df
         
     | 
| 
       480 
442 
     | 
    
         
             
                        else:
         
     | 
| 
       481 
     | 
    
         
            -
                            logging.warning(f"Faces Area Elevation Values not found for 2D Flow Area: {area_name}")
         
     | 
| 
       482 
443 
     | 
    
         
             
                            return None
         
     | 
| 
       483 
444 
     | 
    
         | 
| 
       484 
445 
     | 
    
         
             
                @classmethod
         
     | 
| 
       485 
     | 
    
         
            -
                @ 
     | 
| 
      
 446 
     | 
    
         
            +
                @log_call
         
     | 
| 
       486 
447 
     | 
    
         
             
                def get_faces_indexes(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]]:
         
     | 
| 
       487 
448 
     | 
    
         
             
                    """
         
     | 
| 
       488 
449 
     | 
    
         
             
                    Extract Faces Cell and FacePoint Indexes from the HDF file.
         
     | 
| 
         @@ -518,17 +479,10 @@ class RasHdf: 
     | 
|
| 
       518 
479 
     | 
    
         
             
                        cell_indexes_df = cls._extract_dataset(hdf_file, cell_indexes_path, ['Left Cell', 'Right Cell'])
         
     | 
| 
       519 
480 
     | 
    
         
             
                        facepoint_indexes_df = cls._extract_dataset(hdf_file, facepoint_indexes_path, ['Start FacePoint', 'End FacePoint'])
         
     | 
| 
       520 
481 
     | 
    
         | 
| 
       521 
     | 
    
         
            -
                        if cell_indexes_df is not None and facepoint_indexes_df is not None:
         
     | 
| 
       522 
     | 
    
         
            -
                            logging.info(f"Extracted Faces Indexes for 2D Flow Area: {area_name}")
         
     | 
| 
       523 
     | 
    
         
            -
                        else:
         
     | 
| 
       524 
     | 
    
         
            -
                            logging.warning(f"Faces Indexes not found for 2D Flow Area: {area_name}")
         
     | 
| 
       525 
     | 
    
         
            -
             
     | 
| 
       526 
482 
     | 
    
         
             
                        return cell_indexes_df, facepoint_indexes_df
         
     | 
| 
       527 
483 
     | 
    
         | 
| 
       528 
     | 
    
         
            -
                    
         
     | 
| 
       529 
     | 
    
         
            -
                    
         
     | 
| 
       530 
484 
     | 
    
         
             
                @classmethod
         
     | 
| 
       531 
     | 
    
         
            -
                @ 
     | 
| 
      
 485 
     | 
    
         
            +
                @log_call
         
     | 
| 
       532 
486 
     | 
    
         
             
                def get_faces_elevation_data(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]]:
         
     | 
| 
       533 
487 
     | 
    
         
             
                    """
         
     | 
| 
       534 
488 
     | 
    
         
             
                    Extract Faces Low Elevation Centroid and Minimum Elevation from the HDF file.
         
     | 
| 
         @@ -550,15 +504,10 @@ class RasHdf: 
     | 
|
| 
       550 
504 
     | 
    
         
             
                        low_elev_centroid = cls._extract_dataset(hdf_file, f'{base_path}/Faces Low Elevation Centroid', ['Low Elevation Centroid'])
         
     | 
| 
       551 
505 
     | 
    
         
             
                        min_elevation = cls._extract_dataset(hdf_file, f'{base_path}/Faces Minimum Elevation', ['Minimum Elevation'])
         
     | 
| 
       552 
506 
     | 
    
         | 
| 
       553 
     | 
    
         
            -
                        if low_elev_centroid is not None and min_elevation is not None:
         
     | 
| 
       554 
     | 
    
         
            -
                            logging.info(f"Extracted Faces Elevation Data for 2D Flow Area: {area_name}")
         
     | 
| 
       555 
     | 
    
         
            -
                        else:
         
     | 
| 
       556 
     | 
    
         
            -
                            logging.warning(f"Faces Elevation Data not found for 2D Flow Area: {area_name}")
         
     | 
| 
       557 
     | 
    
         
            -
             
     | 
| 
       558 
507 
     | 
    
         
             
                        return low_elev_centroid, min_elevation
         
     | 
| 
       559 
508 
     | 
    
         | 
| 
       560 
509 
     | 
    
         
             
                @classmethod
         
     | 
| 
       561 
     | 
    
         
            -
                @ 
     | 
| 
      
 510 
     | 
    
         
            +
                @log_call
         
     | 
| 
       562 
511 
     | 
    
         
             
                def get_faces_vector_data(
         
     | 
| 
       563 
512 
     | 
    
         
             
                    cls,
         
     | 
| 
       564 
513 
     | 
    
         
             
                    hdf_input: Union[str, Path],
         
     | 
| 
         @@ -583,15 +532,10 @@ class RasHdf: 
     | 
|
| 
       583 
532 
     | 
    
         
             
                        base_path = f'Geometry/2D Flow Areas/{area_name}'
         
     | 
| 
       584 
533 
     | 
    
         
             
                        vector_data = cls._extract_dataset(hdf_file, f'{base_path}/Faces NormalUnitVector and Length', ['NormalX', 'NormalY', 'Length'])
         
     | 
| 
       585 
534 
     | 
    
         | 
| 
       586 
     | 
    
         
            -
                        if vector_data is not None:
         
     | 
| 
       587 
     | 
    
         
            -
                            logging.info(f"Extracted Faces Vector Data for 2D Flow Area: {area_name}")
         
     | 
| 
       588 
     | 
    
         
            -
                        else:
         
     | 
| 
       589 
     | 
    
         
            -
                            logging.warning(f"Faces Vector Data not found for 2D Flow Area: {area_name}")
         
     | 
| 
       590 
     | 
    
         
            -
             
     | 
| 
       591 
535 
     | 
    
         
             
                        return vector_data
         
     | 
| 
       592 
536 
     | 
    
         | 
| 
       593 
537 
     | 
    
         
             
                @classmethod
         
     | 
| 
       594 
     | 
    
         
            -
                @ 
     | 
| 
      
 538 
     | 
    
         
            +
                @log_call
         
     | 
| 
       595 
539 
     | 
    
         
             
                def get_faces_perimeter_data(
         
     | 
| 
       596 
540 
     | 
    
         
             
                    cls,
         
     | 
| 
       597 
541 
     | 
    
         
             
                    hdf_input: Union[str, Path],
         
     | 
| 
         @@ -632,15 +576,10 @@ class RasHdf: 
     | 
|
| 
       632 
576 
     | 
    
         
             
                        perimeter_info = cls._extract_dataset(hdf_file, f'{base_path}/Faces Perimeter Info', ['Start', 'Count'])
         
     | 
| 
       633 
577 
     | 
    
         
             
                        perimeter_values = cls._extract_dataset(hdf_file, f'{base_path}/Faces Perimeter Values', ['X', 'Y'])
         
     | 
| 
       634 
578 
     | 
    
         | 
| 
       635 
     | 
    
         
            -
                        if perimeter_info is not None and perimeter_values is not None:
         
     | 
| 
       636 
     | 
    
         
            -
                            logging.info(f"Extracted Faces Perimeter Data for 2D Flow Area: {area_name}")
         
     | 
| 
       637 
     | 
    
         
            -
                        else:
         
     | 
| 
       638 
     | 
    
         
            -
                            logging.warning(f"Faces Perimeter Data not found for 2D Flow Area: {area_name}")
         
     | 
| 
       639 
     | 
    
         
            -
             
     | 
| 
       640 
579 
     | 
    
         
             
                        return perimeter_info, perimeter_values
         
     | 
| 
       641 
580 
     | 
    
         | 
| 
       642 
581 
     | 
    
         
             
                @classmethod
         
     | 
| 
       643 
     | 
    
         
            -
                @ 
     | 
| 
      
 582 
     | 
    
         
            +
                @log_call
         
     | 
| 
       644 
583 
     | 
    
         
             
                def get_infiltration_data(
         
     | 
| 
       645 
584 
     | 
    
         
             
                    cls,
         
     | 
| 
       646 
585 
     | 
    
         
             
                    hdf_input: Union[str, Path],
         
     | 
| 
         @@ -661,29 +600,20 @@ class RasHdf: 
     | 
|
| 
       661 
600 
     | 
    
         
             
                            DataFrames containing various Infiltration Data
         
     | 
| 
       662 
601 
     | 
    
         
             
                    """
         
     | 
| 
       663 
602 
     | 
    
         
             
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       664 
     | 
    
         
            -
                        # Retrieve the area name from the HDF file or use the first found
         
     | 
| 
       665 
603 
     | 
    
         
             
                        area_name = cls._get_area_name(hdf_file, area_name, hdf_file.filename)
         
     | 
| 
       666 
604 
     | 
    
         | 
| 
       667 
     | 
    
         
            -
                        # Define the base path for the Infiltration data
         
     | 
| 
       668 
605 
     | 
    
         
             
                        base_path = f'Geometry/2D Flow Areas/{area_name}/Infiltration'
         
     | 
| 
       669 
606 
     | 
    
         | 
| 
       670 
     | 
    
         
            -
                        # Extract various datasets related to infiltration
         
     | 
| 
       671 
607 
     | 
    
         
             
                        cell_classifications = cls._extract_dataset(hdf_file, f'{base_path}/Cell Center Classifications', ['Cell Classification'])
         
     | 
| 
       672 
608 
     | 
    
         
             
                        face_classifications = cls._extract_dataset(hdf_file, f'{base_path}/Face Center Classifications', ['Face Classification'])
         
     | 
| 
       673 
609 
     | 
    
         
             
                        initial_deficit = cls._extract_dataset(hdf_file, f'{base_path}/Initial Deficit', ['Initial Deficit'])
         
     | 
| 
       674 
610 
     | 
    
         
             
                        maximum_deficit = cls._extract_dataset(hdf_file, f'{base_path}/Maximum Deficit', ['Maximum Deficit'])
         
     | 
| 
       675 
611 
     | 
    
         
             
                        potential_percolation_rate = cls._extract_dataset(hdf_file, f'{base_path}/Potential Percolation Rate', ['Potential Percolation Rate'])
         
     | 
| 
       676 
612 
     | 
    
         | 
| 
       677 
     | 
    
         
            -
                        # Log the extraction status
         
     | 
| 
       678 
     | 
    
         
            -
                        if all(df is not None for df in [cell_classifications, face_classifications, initial_deficit, maximum_deficit, potential_percolation_rate]):
         
     | 
| 
       679 
     | 
    
         
            -
                            logging.info(f"Extracted Infiltration Data for 2D Flow Area: {area_name}")
         
     | 
| 
       680 
     | 
    
         
            -
                        else:
         
     | 
| 
       681 
     | 
    
         
            -
                            logging.warning(f"Some or all Infiltration Data not found for 2D Flow Area: {area_name}")
         
     | 
| 
       682 
     | 
    
         
            -
             
     | 
| 
       683 
613 
     | 
    
         
             
                        return cell_classifications, face_classifications, initial_deficit, maximum_deficit, potential_percolation_rate
         
     | 
| 
       684 
614 
     | 
    
         | 
| 
       685 
615 
     | 
    
         
             
                @classmethod
         
     | 
| 
       686 
     | 
    
         
            -
                @ 
     | 
| 
      
 616 
     | 
    
         
            +
                @log_call
         
     | 
| 
       687 
617 
     | 
    
         
             
                def get_percent_impervious_data(
         
     | 
| 
       688 
618 
     | 
    
         
             
                    cls,
         
     | 
| 
       689 
619 
     | 
    
         
             
                    hdf_input: Union[str, Path],
         
     | 
| 
         @@ -711,15 +641,10 @@ class RasHdf: 
     | 
|
| 
       711 
641 
     | 
    
         
             
                        face_classifications = cls._extract_dataset(hdf_file, f'{base_path}/Face Center Classifications', ['Face Classification'])
         
     | 
| 
       712 
642 
     | 
    
         
             
                        percent_impervious = cls._extract_dataset(hdf_file, f'{base_path}/Percent Impervious', ['Percent Impervious'])
         
     | 
| 
       713 
643 
     | 
    
         | 
| 
       714 
     | 
    
         
            -
                        if all([df is not None for df in [cell_classifications, face_classifications, percent_impervious]]):
         
     | 
| 
       715 
     | 
    
         
            -
                            logging.info(f"Extracted Percent Impervious Data for 2D Flow Area: {area_name}")
         
     | 
| 
       716 
     | 
    
         
            -
                        else:
         
     | 
| 
       717 
     | 
    
         
            -
                            logging.warning(f"Some or all Percent Impervious Data not found for 2D Flow Area: {area_name}")
         
     | 
| 
       718 
     | 
    
         
            -
             
     | 
| 
       719 
644 
     | 
    
         
             
                        return cell_classifications, face_classifications, percent_impervious
         
     | 
| 
       720 
645 
     | 
    
         | 
| 
       721 
646 
     | 
    
         
             
                @classmethod
         
     | 
| 
       722 
     | 
    
         
            -
                @ 
     | 
| 
      
 647 
     | 
    
         
            +
                @log_call
         
     | 
| 
       723 
648 
     | 
    
         
             
                def get_perimeter_data(
         
     | 
| 
       724 
649 
     | 
    
         
             
                    cls,
         
     | 
| 
       725 
650 
     | 
    
         
             
                    hdf_input: Union[str, Path],
         
     | 
| 
         @@ -751,17 +676,10 @@ class RasHdf: 
     | 
|
| 
       751 
676 
     | 
    
         
             
                        perimeter_path = f'Geometry/2D Flow Areas/{area_name}/Perimeter'
         
     | 
| 
       752 
677 
     | 
    
         
             
                        perimeter_df = cls._extract_dataset(hdf_file, perimeter_path, ['X', 'Y'])
         
     | 
| 
       753 
678 
     | 
    
         | 
| 
       754 
     | 
    
         
            -
                        if perimeter_df is not None:
         
     | 
| 
       755 
     | 
    
         
            -
                            logging.info(f"Extracted Perimeter Data for 2D Flow Area: {area_name}")
         
     | 
| 
       756 
     | 
    
         
            -
                        else:
         
     | 
| 
       757 
     | 
    
         
            -
                            logging.warning(f"Perimeter Data not found for 2D Flow Area: {area_name}")
         
     | 
| 
       758 
     | 
    
         
            -
             
     | 
| 
       759 
679 
     | 
    
         
             
                        return perimeter_df
         
     | 
| 
       760 
680 
     | 
    
         | 
| 
       761 
     | 
    
         
            -
            # Private Class Methods (to save code duplication)
         
     | 
| 
       762 
     | 
    
         
            -
             
     | 
| 
       763 
     | 
    
         
            -
             
     | 
| 
       764 
681 
     | 
    
         
             
                @classmethod
         
     | 
| 
      
 682 
     | 
    
         
            +
                @log_call
         
     | 
| 
       765 
683 
     | 
    
         
             
                def _get_area_name(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> str:
         
     | 
| 
       766 
684 
     | 
    
         
             
                    """
         
     | 
| 
       767 
685 
     | 
    
         
             
                    Get the 2D Flow Area name from the HDF file.
         
     | 
| 
         @@ -783,14 +701,13 @@ class RasHdf: 
     | 
|
| 
       783 
701 
     | 
    
         
             
                            if not area_names:
         
     | 
| 
       784 
702 
     | 
    
         
             
                                raise ValueError("No 2D Flow Areas found in the HDF file")
         
     | 
| 
       785 
703 
     | 
    
         
             
                            area_name = area_names[0]
         
     | 
| 
       786 
     | 
    
         
            -
                            logging.info(f"Using first 2D Flow Area found: {area_name}")
         
     | 
| 
       787 
704 
     | 
    
         
             
                        else:
         
     | 
| 
       788 
705 
     | 
    
         
             
                            if area_name not in hdf_file['Geometry/2D Flow Areas']:
         
     | 
| 
       789 
706 
     | 
    
         
             
                                raise ValueError(f"2D Flow Area '{area_name}' not found in the HDF file")
         
     | 
| 
       790 
     | 
    
         
            -
                            logging.info(f"Using 2D Flow Area provided by user: {area_name}")
         
     | 
| 
       791 
707 
     | 
    
         
             
                    return area_name
         
     | 
| 
       792 
708 
     | 
    
         | 
| 
       793 
709 
     | 
    
         
             
                @classmethod
         
     | 
| 
      
 710 
     | 
    
         
            +
                @log_call
         
     | 
| 
       794 
711 
     | 
    
         
             
                def _extract_dataset(cls, hdf_input: Union[str, Path], dataset_path: str, column_names: List[str], ras_object=None) -> Optional[pd.DataFrame]:
         
     | 
| 
       795 
712 
     | 
    
         
             
                    """
         
     | 
| 
       796 
713 
     | 
    
         
             
                    Extract a dataset from the HDF file and convert it to a DataFrame.
         
     | 
| 
         @@ -808,13 +725,12 @@ class RasHdf: 
     | 
|
| 
       808 
725 
     | 
    
         
             
                        try:
         
     | 
| 
       809 
726 
     | 
    
         
             
                            dataset = hdf_file[dataset_path][()]
         
     | 
| 
       810 
727 
     | 
    
         
             
                            df = pd.DataFrame(dataset, columns=column_names)
         
     | 
| 
       811 
     | 
    
         
            -
                            logging.info(f"Extracted dataset: {dataset_path}")
         
     | 
| 
       812 
728 
     | 
    
         
             
                            return df
         
     | 
| 
       813 
729 
     | 
    
         
             
                        except KeyError:
         
     | 
| 
       814 
     | 
    
         
            -
                            logging.warning(f"Dataset not found: {dataset_path}")
         
     | 
| 
       815 
730 
     | 
    
         
             
                            return None
         
     | 
| 
      
 731 
     | 
    
         
            +
             
     | 
| 
       816 
732 
     | 
    
         
             
                @classmethod
         
     | 
| 
       817 
     | 
    
         
            -
                @ 
     | 
| 
      
 733 
     | 
    
         
            +
                @log_call
         
     | 
| 
       818 
734 
     | 
    
         
             
                def read_hdf_to_dataframe(cls, hdf_input: Union[str, Path], dataset_path: str, fill_value: Union[int, float, str] = -9999, ras_object=None) -> pd.DataFrame:
         
     | 
| 
       819 
735 
     | 
    
         
             
                    """
         
     | 
| 
       820 
736 
     | 
    
         
             
                    Reads an HDF5 dataset and converts it into a pandas DataFrame, handling byte strings and missing values.
         
     | 
| 
         @@ -840,14 +756,12 @@ class RasHdf: 
     | 
|
| 
       840 
756 
     | 
    
         
             
                            hdf_dataframe[byte_columns] = hdf_dataframe[byte_columns].applymap(lambda x: x.decode('utf-8') if isinstance(x, (bytes, bytearray)) else x)
         
     | 
| 
       841 
757 
     | 
    
         
             
                            hdf_dataframe = hdf_dataframe.replace({fill_value: np.NaN})
         
     | 
| 
       842 
758 
     | 
    
         | 
| 
       843 
     | 
    
         
            -
                            logging.info(f"Successfully read dataset: {dataset_path}")
         
     | 
| 
       844 
759 
     | 
    
         
             
                            return hdf_dataframe
         
     | 
| 
       845 
760 
     | 
    
         
             
                        except KeyError:
         
     | 
| 
       846 
     | 
    
         
            -
                            logging.error(f"Dataset not found: {dataset_path}")
         
     | 
| 
       847 
761 
     | 
    
         
             
                            raise
         
     | 
| 
       848 
762 
     | 
    
         | 
| 
       849 
763 
     | 
    
         
             
                @classmethod
         
     | 
| 
       850 
     | 
    
         
            -
                @ 
     | 
| 
      
 764 
     | 
    
         
            +
                @log_call
         
     | 
| 
       851 
765 
     | 
    
         
             
                def get_group_attributes_as_df(cls, hdf_input: Union[str, Path], group_path: str, ras_object=None) -> pd.DataFrame:
         
     | 
| 
       852 
766 
     | 
    
         
             
                    """
         
     | 
| 
       853 
767 
     | 
    
         
             
                    Convert attributes inside a given HDF group to a DataFrame.
         
     | 
| 
         @@ -894,14 +808,14 @@ class RasHdf: 
     | 
|
| 
       894 
808 
     | 
    
         | 
| 
       895 
809 
     | 
    
         
             
                            return pd.DataFrame(attributes)
         
     | 
| 
       896 
810 
     | 
    
         
             
                        except KeyError:
         
     | 
| 
       897 
     | 
    
         
            -
                             
     | 
| 
       898 
     | 
    
         
            -
                            raise
         
     | 
| 
      
 811 
     | 
    
         
            +
                            logger.critical(f"Group path '{group_path}' not found in HDF file '{hdf_filename}'")
         
     | 
| 
       899 
812 
     | 
    
         | 
| 
       900 
813 
     | 
    
         
             
                # Last functions from PyHMT2D:
         
     | 
| 
       901 
814 
     | 
    
         | 
| 
      
 815 
     | 
    
         
            +
                from ras_commander.logging_config import log_call
         
     | 
| 
       902 
816 
     | 
    
         | 
| 
       903 
817 
     | 
    
         
             
                @classmethod
         
     | 
| 
       904 
     | 
    
         
            -
                @ 
     | 
| 
      
 818 
     | 
    
         
            +
                @log_call
         
     | 
| 
       905 
819 
     | 
    
         
             
                def get_2d_area_solution_times(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Optional[np.ndarray]:
         
     | 
| 
       906 
820 
     | 
    
         
             
                    """
         
     | 
| 
       907 
821 
     | 
    
         
             
                    Retrieve solution times for a specified 2D Flow Area.
         
     | 
| 
         @@ -925,13 +839,12 @@ class RasHdf: 
     | 
|
| 
       925 
839 
     | 
    
         
             
                                hdf_file['Results']['Unsteady']['Output']['Output Blocks']
         
     | 
| 
       926 
840 
     | 
    
         
             
                                ['Base Output']['Unsteady Time Series']['Time']
         
     | 
| 
       927 
841 
     | 
    
         
             
                            )
         
     | 
| 
       928 
     | 
    
         
            -
                            logging.info(f"Retrieved {len(solution_times)} solution times for 2D Flow Area: {area_name}")
         
     | 
| 
       929 
842 
     | 
    
         
             
                            return solution_times
         
     | 
| 
       930 
843 
     | 
    
         
             
                        except KeyError:
         
     | 
| 
       931 
     | 
    
         
            -
                            logging.warning(f"Solution times not found for 2D Flow Area: {area_name}")
         
     | 
| 
       932 
844 
     | 
    
         
             
                            return None
         
     | 
| 
      
 845 
     | 
    
         
            +
             
     | 
| 
       933 
846 
     | 
    
         
             
                @classmethod
         
     | 
| 
       934 
     | 
    
         
            -
                @ 
     | 
| 
      
 847 
     | 
    
         
            +
                @log_call
         
     | 
| 
       935 
848 
     | 
    
         
             
                def get_2d_area_solution_time_dates(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Optional[np.ndarray]:
         
     | 
| 
       936 
849 
     | 
    
         
             
                    """
         
     | 
| 
       937 
850 
     | 
    
         
             
                    Retrieve solution time dates for a specified 2D Flow Area.
         
     | 
| 
         @@ -955,14 +868,12 @@ class RasHdf: 
     | 
|
| 
       955 
868 
     | 
    
         
             
                                hdf_file['Results']['Unsteady']['Output']['Output Blocks']
         
     | 
| 
       956 
869 
     | 
    
         
             
                                ['Base Output']['Unsteady Time Series']['Time Date Stamp']
         
     | 
| 
       957 
870 
     | 
    
         
             
                            )
         
     | 
| 
       958 
     | 
    
         
            -
                            logging.info(f"Retrieved {len(solution_time_dates)} solution time dates for 2D Flow Area: {area_name}")
         
     | 
| 
       959 
871 
     | 
    
         
             
                            return solution_time_dates
         
     | 
| 
       960 
872 
     | 
    
         
             
                        except KeyError:
         
     | 
| 
       961 
     | 
    
         
            -
                            logging.warning(f"Solution time dates not found for 2D Flow Area: {area_name}")
         
     | 
| 
       962 
873 
     | 
    
         
             
                            return None
         
     | 
| 
       963 
874 
     | 
    
         | 
| 
       964 
875 
     | 
    
         
             
                @classmethod
         
     | 
| 
       965 
     | 
    
         
            -
                @ 
     | 
| 
      
 876 
     | 
    
         
            +
                @log_call
         
     | 
| 
       966 
877 
     | 
    
         
             
                def load_2d_area_solutions(
         
     | 
| 
       967 
878 
     | 
    
         
             
                    cls,
         
     | 
| 
       968 
879 
     | 
    
         
             
                    hdf_file: h5py.File,
         
     | 
| 
         @@ -988,51 +899,37 @@ class RasHdf: 
     | 
|
| 
       988 
899 
     | 
    
         
             
                                - '{Area_Name}_Face_Velocity': Face Normal Velocity DataFrame.
         
     | 
| 
       989 
900 
     | 
    
         
             
                    """
         
     | 
| 
       990 
901 
     | 
    
         
             
                    try:
         
     | 
| 
       991 
     | 
    
         
            -
                        # Extract solution times
         
     | 
| 
       992 
902 
     | 
    
         
             
                        solution_times_path = '/Results/Unsteady/Output/Output Blocks/Base Output/Unsteady Time Series/Time'
         
     | 
| 
       993 
903 
     | 
    
         
             
                        if solution_times_path not in hdf_file:
         
     | 
| 
       994 
     | 
    
         
            -
                            logging.error(f"Solution times dataset not found at path: {solution_times_path}")
         
     | 
| 
       995 
904 
     | 
    
         
             
                            return None
         
     | 
| 
       996 
905 
     | 
    
         | 
| 
       997 
906 
     | 
    
         
             
                        solution_times = hdf_file[solution_times_path][()]
         
     | 
| 
       998 
907 
     | 
    
         
             
                        solution_times_df = pd.DataFrame({
         
     | 
| 
       999 
908 
     | 
    
         
             
                            'Time_Step': solution_times
         
     | 
| 
       1000 
909 
     | 
    
         
             
                        })
         
     | 
| 
       1001 
     | 
    
         
            -
                        logging.info(f"Extracted Solution Times: {solution_times_df.shape[0]} time steps")
         
     | 
| 
       1002 
910 
     | 
    
         | 
| 
       1003 
     | 
    
         
            -
                        # Initialize dictionary to hold all dataframes
         
     | 
| 
       1004 
911 
     | 
    
         
             
                        solutions_dict = {
         
     | 
| 
       1005 
912 
     | 
    
         
             
                            'solution_times': solution_times_df
         
     | 
| 
       1006 
913 
     | 
    
         
             
                        }
         
     | 
| 
       1007 
914 
     | 
    
         | 
| 
       1008 
     | 
    
         
            -
                        # Get list of 2D Flow Areas
         
     | 
| 
       1009 
915 
     | 
    
         
             
                        two_d_area_names = cls.get_2d_flow_area_names(hdf_file, ras_object=ras_object)
         
     | 
| 
       1010 
916 
     | 
    
         
             
                        if not two_d_area_names:
         
     | 
| 
       1011 
     | 
    
         
            -
                            logging.error("No 2D Flow Areas found in the HDF file.")
         
     | 
| 
       1012 
917 
     | 
    
         
             
                            return solutions_dict
         
     | 
| 
       1013 
918 
     | 
    
         | 
| 
       1014 
919 
     | 
    
         
             
                        for area in two_d_area_names:
         
     | 
| 
       1015 
     | 
    
         
            -
                            logging.info(f"Processing 2D Flow Area: {area}")
         
     | 
| 
       1016 
     | 
    
         
            -
             
     | 
| 
       1017 
     | 
    
         
            -
                            # Paths for WSE and Face Velocity datasets
         
     | 
| 
       1018 
920 
     | 
    
         
             
                            wse_path = f'/Results/Unsteady/Output/Output Blocks/Base Output/Unsteady Time Series/2D Flow Areas/{area}/Water Surface'
         
     | 
| 
       1019 
921 
     | 
    
         
             
                            face_velocity_path = f'/Results/Unsteady/Output/Output Blocks/Base Output/Unsteady Time Series/2D Flow Areas/{area}/Face Velocity'
         
     | 
| 
       1020 
922 
     | 
    
         | 
| 
       1021 
     | 
    
         
            -
                            # Extract Water Surface Elevation (WSE)
         
     | 
| 
       1022 
923 
     | 
    
         
             
                            if wse_path not in hdf_file:
         
     | 
| 
       1023 
     | 
    
         
            -
                                logging.warning(f"WSE dataset not found for area '{area}' at path: {wse_path}")
         
     | 
| 
       1024 
924 
     | 
    
         
             
                                continue
         
     | 
| 
       1025 
925 
     | 
    
         | 
| 
       1026 
926 
     | 
    
         
             
                            wse_data = hdf_file[wse_path][()]
         
     | 
| 
       1027 
     | 
    
         
            -
                            # Assuming cell center coordinates are required for WSE
         
     | 
| 
       1028 
927 
     | 
    
         
             
                            cell_center_coords_path = f'/Geometry/2D Flow Areas/{area}/Cell Center Coordinate'
         
     | 
| 
       1029 
928 
     | 
    
         
             
                            if cell_center_coords_path not in hdf_file:
         
     | 
| 
       1030 
     | 
    
         
            -
                                logging.warning(f"Cell Center Coordinate dataset not found for area '{area}' at path: {cell_center_coords_path}")
         
     | 
| 
       1031 
929 
     | 
    
         
             
                                continue
         
     | 
| 
       1032 
930 
     | 
    
         | 
| 
       1033 
931 
     | 
    
         
             
                            cell_center_coords = hdf_file[cell_center_coords_path][()]
         
     | 
| 
       1034 
932 
     | 
    
         
             
                            if cell_center_coords.shape[0] != wse_data.shape[1]:
         
     | 
| 
       1035 
     | 
    
         
            -
                                logging.warning(f"Mismatch between Cell Center Coordinates and WSE data for area '{area}'.")
         
     | 
| 
       1036 
933 
     | 
    
         
             
                                continue
         
     | 
| 
       1037 
934 
     | 
    
         | 
| 
       1038 
935 
     | 
    
         
             
                            wse_df = pd.DataFrame({
         
     | 
| 
         @@ -1043,23 +940,17 @@ class RasHdf: 
     | 
|
| 
       1043 
940 
     | 
    
         
             
                                'WSE': wse_data.flatten()
         
     | 
| 
       1044 
941 
     | 
    
         
             
                            })
         
     | 
| 
       1045 
942 
     | 
    
         
             
                            solutions_dict[f'{area}_WSE'] = wse_df
         
     | 
| 
       1046 
     | 
    
         
            -
                            logging.info(f"Extracted WSE for area '{area}': {wse_df.shape[0]} records")
         
     | 
| 
       1047 
943 
     | 
    
         | 
| 
       1048 
     | 
    
         
            -
                            # Extract Face Normal Velocity
         
     | 
| 
       1049 
944 
     | 
    
         
             
                            if face_velocity_path not in hdf_file:
         
     | 
| 
       1050 
     | 
    
         
            -
                                logging.warning(f"Face Velocity dataset not found for area '{area}' at path: {face_velocity_path}")
         
     | 
| 
       1051 
945 
     | 
    
         
             
                                continue
         
     | 
| 
       1052 
946 
     | 
    
         | 
| 
       1053 
947 
     | 
    
         
             
                            face_velocity_data = hdf_file[face_velocity_path][()]
         
     | 
| 
       1054 
     | 
    
         
            -
                            # Assuming face center points are required for velocities
         
     | 
| 
       1055 
948 
     | 
    
         
             
                            face_center_coords_path = f'/Geometry/2D Flow Areas/{area}/Face Points Coordinates'
         
     | 
| 
       1056 
949 
     | 
    
         
             
                            if face_center_coords_path not in hdf_file:
         
     | 
| 
       1057 
     | 
    
         
            -
                                logging.warning(f"Face Points Coordinates dataset not found for area '{area}' at path: {face_center_coords_path}")
         
     | 
| 
       1058 
950 
     | 
    
         
             
                                continue
         
     | 
| 
       1059 
951 
     | 
    
         | 
| 
       1060 
952 
     | 
    
         
             
                            face_center_coords = hdf_file[face_center_coords_path][()]
         
     | 
| 
       1061 
953 
     | 
    
         
             
                            if face_center_coords.shape[0] != face_velocity_data.shape[1]:
         
     | 
| 
       1062 
     | 
    
         
            -
                                logging.warning(f"Mismatch between Face Center Coordinates and Face Velocity data for area '{area}'.")
         
     | 
| 
       1063 
954 
     | 
    
         
             
                                continue
         
     | 
| 
       1064 
955 
     | 
    
         | 
| 
       1065 
956 
     | 
    
         
             
                            face_velocity_df = pd.DataFrame({
         
     | 
| 
         @@ -1070,17 +961,45 @@ class RasHdf: 
     | 
|
| 
       1070 
961 
     | 
    
         
             
                                'Normal_Velocity_ft_s': face_velocity_data.flatten()
         
     | 
| 
       1071 
962 
     | 
    
         
             
                            })
         
     | 
| 
       1072 
963 
     | 
    
         
             
                            solutions_dict[f'{area}_Face_Velocity'] = face_velocity_df
         
     | 
| 
       1073 
     | 
    
         
            -
                            logging.info(f"Extracted Face Velocity for area '{area}': {face_velocity_df.shape[0]} records")
         
     | 
| 
       1074 
964 
     | 
    
         | 
| 
       1075 
965 
     | 
    
         
             
                        return solutions_dict
         
     | 
| 
       1076 
966 
     | 
    
         | 
| 
       1077 
967 
     | 
    
         
             
                    except Exception as e:
         
     | 
| 
       1078 
     | 
    
         
            -
                        logging.error(f"An error occurred while loading 2D area solutions: {e}", exc_info=True)
         
     | 
| 
       1079 
968 
     | 
    
         
             
                        return None
         
     | 
| 
       1080 
969 
     | 
    
         | 
| 
      
 970 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 971 
     | 
    
         
            +
                @log_call
         
     | 
| 
      
 972 
     | 
    
         
            +
                def get_hdf_paths_with_properties(cls, hdf_input: Union[str, Path], ras_object=None) -> pd.DataFrame:
         
     | 
| 
      
 973 
     | 
    
         
            +
                    """
         
     | 
| 
      
 974 
     | 
    
         
            +
                    List all paths in the HDF file with their properties.
         
     | 
| 
      
 975 
     | 
    
         
            +
             
     | 
| 
      
 976 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 977 
     | 
    
         
            +
                        hdf_input (Union[str, Path]): The plan number or full path to the HDF file.
         
     | 
| 
      
 978 
     | 
    
         
            +
                        ras_object (RasPrj, optional): The RAS project object. If None, uses the global ras instance.
         
     | 
| 
      
 979 
     | 
    
         
            +
             
     | 
| 
      
 980 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 981 
     | 
    
         
            +
                        pd.DataFrame: DataFrame of all paths and their properties in the HDF file.
         
     | 
| 
       1081 
982 
     | 
    
         | 
| 
      
 983 
     | 
    
         
            +
                    Example:
         
     | 
| 
      
 984 
     | 
    
         
            +
                        >>> paths_df = RasHdf.get_hdf_paths_with_properties("path/to/file.hdf")
         
     | 
| 
      
 985 
     | 
    
         
            +
                        >>> print(paths_df.head())
         
     | 
| 
      
 986 
     | 
    
         
            +
                    """
         
     | 
| 
      
 987 
     | 
    
         
            +
                    with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
      
 988 
     | 
    
         
            +
                        paths = []
         
     | 
| 
      
 989 
     | 
    
         
            +
                        def visitor_func(name: str, node: h5py.Group) -> None:
         
     | 
| 
      
 990 
     | 
    
         
            +
                            path_info = {
         
     | 
| 
      
 991 
     | 
    
         
            +
                                "HDF_Path": name,
         
     | 
| 
      
 992 
     | 
    
         
            +
                                "Type": type(node).__name__,
         
     | 
| 
      
 993 
     | 
    
         
            +
                                "Shape": getattr(node, "shape", None),
         
     | 
| 
      
 994 
     | 
    
         
            +
                                "Size": getattr(node, "size", None),
         
     | 
| 
      
 995 
     | 
    
         
            +
                                "Dtype": getattr(node, "dtype", None)
         
     | 
| 
      
 996 
     | 
    
         
            +
                            }
         
     | 
| 
      
 997 
     | 
    
         
            +
                            paths.append(path_info)
         
     | 
| 
      
 998 
     | 
    
         
            +
                        hdf_file.visititems(visitor_func)
         
     | 
| 
      
 999 
     | 
    
         
            +
                        return pd.DataFrame(paths)
         
     | 
| 
      
 1000 
     | 
    
         
            +
                    
         
     | 
| 
       1082 
1001 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1083 
     | 
    
         
            -
                @ 
     | 
| 
      
 1002 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1084 
1003 
     | 
    
         
             
                def build_2d_area_face_hydraulic_information(cls, hdf_input: Union[str, Path, h5py.File], area_name: Optional[str] = None, ras_object=None) -> Optional[List[List[np.ndarray]]]:
         
     | 
| 
       1085 
1004 
     | 
    
         
             
                    """
         
     | 
| 
       1086 
1005 
     | 
    
         
             
                    Build face hydraulic information tables (elevation, area, wetted perimeter, Manning's n) for each face in 2D Flow Areas.
         
     | 
| 
         @@ -1115,18 +1034,16 @@ class RasHdf: 
     | 
|
| 
       1115 
1034 
     | 
    
         
             
                                    start_row, count = face
         
     | 
| 
       1116 
1035 
     | 
    
         
             
                                    face_data = face_elev_values[start_row:start_row + count].copy()
         
     | 
| 
       1117 
1036 
     | 
    
         
             
                                    area_hydraulic_info.append(face_data)
         
     | 
| 
       1118 
     | 
    
         
            -
                                    logging.info(f"Processed hydraulic information for face {face} in 2D Flow Area: {area}")
         
     | 
| 
       1119 
1037 
     | 
    
         | 
| 
       1120 
1038 
     | 
    
         
             
                                hydraulic_info_table.append(area_hydraulic_info)
         
     | 
| 
       1121 
1039 
     | 
    
         | 
| 
       1122 
1040 
     | 
    
         
             
                            return hydraulic_info_table
         
     | 
| 
       1123 
1041 
     | 
    
         | 
| 
       1124 
     | 
    
         
            -
                    except KeyError 
     | 
| 
       1125 
     | 
    
         
            -
                        logging.error(f"Error building face hydraulic information: {e}")
         
     | 
| 
      
 1042 
     | 
    
         
            +
                    except KeyError:
         
     | 
| 
       1126 
1043 
     | 
    
         
             
                        return None
         
     | 
| 
       1127 
1044 
     | 
    
         | 
| 
       1128 
1045 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1129 
     | 
    
         
            -
                @ 
     | 
| 
      
 1046 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1130 
1047 
     | 
    
         
             
                def build_2d_area_face_point_coordinates_list(cls, hdf_input: Union[str, Path, h5py.File], area_name: Optional[str] = None, ras_object=None) -> Optional[List[np.ndarray]]:
         
     | 
| 
       1131 
1048 
     | 
    
         
             
                    """
         
     | 
| 
       1132 
1049 
     | 
    
         
             
                    Build a list of face point coordinates for each 2D Flow Area.
         
     | 
| 
         @@ -1152,16 +1069,14 @@ class RasHdf: 
     | 
|
| 
       1152 
1069 
     | 
    
         
             
                            for area in two_d_area_names:
         
     | 
| 
       1153 
1070 
     | 
    
         
             
                                face_points = np.array(hdf_file[f'Geometry/2D Flow Areas/{area}/Face Points Coordinates'])
         
     | 
| 
       1154 
1071 
     | 
    
         
             
                                face_point_coords_list.append(face_points)
         
     | 
| 
       1155 
     | 
    
         
            -
                                logging.info(f"Built face point coordinates list for 2D Flow Area: {area}")
         
     | 
| 
       1156 
1072 
     | 
    
         | 
| 
       1157 
1073 
     | 
    
         
             
                            return face_point_coords_list
         
     | 
| 
       1158 
1074 
     | 
    
         | 
| 
       1159 
     | 
    
         
            -
                    except KeyError 
     | 
| 
       1160 
     | 
    
         
            -
                        logging.error(f"Error building face point coordinates list: {e}")
         
     | 
| 
      
 1075 
     | 
    
         
            +
                    except KeyError:
         
     | 
| 
       1161 
1076 
     | 
    
         
             
                        return None
         
     | 
| 
       1162 
1077 
     | 
    
         | 
| 
       1163 
1078 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1164 
     | 
    
         
            -
                @ 
     | 
| 
      
 1079 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1165 
1080 
     | 
    
         
             
                def build_2d_area_face_profile(cls, hdf_input: Union[str, Path, h5py.File], area_name: Optional[str] = None, ras_object=None, n_face_profile_points: int = 10) -> Optional[List[np.ndarray]]:
         
     | 
| 
       1166 
1081 
     | 
    
         
             
                    """
         
     | 
| 
       1167 
1082 
     | 
    
         
             
                    Build face profiles representing sub-grid terrain for each face in 2D Flow Areas.
         
     | 
| 
         @@ -1183,8 +1098,6 @@ class RasHdf: 
     | 
|
| 
       1183 
1098 
     | 
    
         
             
                    try:
         
     | 
| 
       1184 
1099 
     | 
    
         
             
                        with h5py.File(cls._get_hdf_filename(hdf_input, ras_object), 'r') as hdf_file:
         
     | 
| 
       1185 
1100 
     | 
    
         
             
                            two_d_area_names = cls.get_2d_flow_area_names(hdf_file, ras_object=ras_object)
         
     | 
| 
       1186 
     | 
    
         
            -
                            print(f"Building face profiles for {len(two_d_area_names)} 2D Flow Areas")
         
     | 
| 
       1187 
     | 
    
         
            -
                            print(f"Area names: {two_d_area_names}")
         
     | 
| 
       1188 
1101 
     | 
    
         
             
                            face_profiles = []
         
     | 
| 
       1189 
1102 
     | 
    
         | 
| 
       1190 
1103 
     | 
    
         
             
                            for area in two_d_area_names:
         
     | 
| 
         @@ -1205,11 +1118,9 @@ class RasHdf: 
     | 
|
| 
       1205 
1118 
     | 
    
         
             
                                        for i in range(n_face_profile_points)
         
     | 
| 
       1206 
1119 
     | 
    
         
             
                                    ])
         
     | 
| 
       1207 
1120 
     | 
    
         | 
| 
       1208 
     | 
    
         
            -
                                    # Interpolate Z coordinates (assuming a method exists)
         
     | 
| 
       1209 
1121 
     | 
    
         
             
                                    interpolated_points = cls.interpolate_z_coords(interpolated_points)
         
     | 
| 
       1210 
1122 
     | 
    
         | 
| 
       1211 
1123 
     | 
    
         
             
                                    profile_points_all_faces.append(interpolated_points)
         
     | 
| 
       1212 
     | 
    
         
            -
                                    logging.info(f"Built face profile for face {face} in 2D Flow Area: {area}")
         
     | 
| 
       1213 
1124 
     | 
    
         | 
| 
       1214 
1125 
     | 
    
         
             
                                face_profiles.append(profile_points_all_faces)
         
     | 
| 
       1215 
1126 
     | 
    
         | 
| 
         @@ -1220,7 +1131,7 @@ class RasHdf: 
     | 
|
| 
       1220 
1131 
     | 
    
         
             
                        return None
         
     | 
| 
       1221 
1132 
     | 
    
         | 
| 
       1222 
1133 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1223 
     | 
    
         
            -
                @ 
     | 
| 
      
 1134 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1224 
1135 
     | 
    
         
             
                def build_face_facepoints(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Optional[List[np.ndarray]]:
         
     | 
| 
       1225 
1136 
     | 
    
         
             
                    """
         
     | 
| 
       1226 
1137 
     | 
    
         
             
                    Build face's facepoint list for each 2D Flow Area.
         
     | 
| 
         @@ -1246,16 +1157,16 @@ class RasHdf: 
     | 
|
| 
       1246 
1157 
     | 
    
         
             
                            for area in two_d_area_names:
         
     | 
| 
       1247 
1158 
     | 
    
         
             
                                face_facepoints = np.array(hdf_file[f'Geometry/2D Flow Areas/{area}/Faces FacePoint Indexes'])
         
     | 
| 
       1248 
1159 
     | 
    
         
             
                                face_facepoints_list.append(face_facepoints)
         
     | 
| 
       1249 
     | 
    
         
            -
                                logging.info(f"Built face facepoints list for 2D Flow Area: {area}")
         
     | 
| 
       1250 
1160 
     | 
    
         | 
| 
       1251 
1161 
     | 
    
         
             
                            return face_facepoints_list
         
     | 
| 
       1252 
1162 
     | 
    
         | 
| 
       1253 
1163 
     | 
    
         
             
                    except KeyError as e:
         
     | 
| 
       1254 
     | 
    
         
            -
                        logging. 
     | 
| 
      
 1164 
     | 
    
         
            +
                        logger = logging.getLogger(__name__)
         
     | 
| 
      
 1165 
     | 
    
         
            +
                        logger.error(f"Error building face facepoints list: {e}")
         
     | 
| 
       1255 
1166 
     | 
    
         
             
                        return None
         
     | 
| 
       1256 
1167 
     | 
    
         | 
| 
       1257 
1168 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1258 
     | 
    
         
            -
                @ 
     | 
| 
      
 1169 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1259 
1170 
     | 
    
         
             
                def build_2d_area_boundaries(cls, hdf_input: Union[str, Path], area_name: Optional[str] = None, ras_object=None) -> Optional[Tuple[int, np.ndarray, List[str], List[str], List[str], np.ndarray, np.ndarray]]:
         
     | 
| 
       1260 
1171 
     | 
    
         
             
                    """
         
     | 
| 
       1261 
1172 
     | 
    
         
             
                    Build boundaries with their point lists for each 2D Flow Area.
         
     | 
| 
         @@ -1289,7 +1200,8 @@ class RasHdf: 
     | 
|
| 
       1289 
1200 
     | 
    
         
             
                            for area in two_d_area_names:
         
     | 
| 
       1290 
1201 
     | 
    
         
             
                                boundary_points = np.array(hdf_file[f'Geometry/2D Flow Areas/{area}/Boundary Points'])
         
     | 
| 
       1291 
1202 
     | 
    
         
             
                                if boundary_points.size == 0:
         
     | 
| 
       1292 
     | 
    
         
            -
                                    logging. 
     | 
| 
      
 1203 
     | 
    
         
            +
                                    logger = logging.getLogger(__name__)
         
     | 
| 
      
 1204 
     | 
    
         
            +
                                    logger.warning(f"No boundary points found for 2D Flow Area: {area}")
         
     | 
| 
       1293 
1205 
     | 
    
         
             
                                    continue
         
     | 
| 
       1294 
1206 
     | 
    
         | 
| 
       1295 
1207 
     | 
    
         
             
                                current_boundary_id = boundary_points[0][0]
         
     | 
| 
         @@ -1322,18 +1234,17 @@ class RasHdf: 
     | 
|
| 
       1322 
1234 
     | 
    
         
             
                                boundary_points_list.append(np.array(current_boundary_points))
         
     | 
| 
       1323 
1235 
     | 
    
         
             
                                total_boundaries += 1
         
     | 
| 
       1324 
1236 
     | 
    
         | 
| 
       1325 
     | 
    
         
            -
                                logging.info(f"Built boundaries for 2D Flow Area: {area}, Total Boundaries: {total_boundaries}")
         
     | 
| 
       1326 
     | 
    
         
            -
             
     | 
| 
       1327 
1237 
     | 
    
         
             
                            return (total_boundaries, np.array(boundary_ids), boundary_names, flow_area_names, boundary_types, np.array(total_points_per_boundary), np.array(boundary_points_list))
         
     | 
| 
       1328 
1238 
     | 
    
         | 
| 
       1329 
1239 
     | 
    
         
             
                    except KeyError as e:
         
     | 
| 
       1330 
     | 
    
         
            -
                        logging. 
     | 
| 
      
 1240 
     | 
    
         
            +
                        logger = logging.getLogger(__name__)
         
     | 
| 
      
 1241 
     | 
    
         
            +
                        logger.error(f"Error building boundaries: {e}")
         
     | 
| 
       1331 
1242 
     | 
    
         
             
                        return None
         
     | 
| 
       1332 
1243 
     | 
    
         | 
| 
       1333 
1244 
     | 
    
         
             
                # Helper Methods for New Functionalities
         
     | 
| 
       1334 
1245 
     | 
    
         | 
| 
       1335 
     | 
    
         
            -
             
     | 
| 
       1336 
1246 
     | 
    
         
             
                @classmethod
         
     | 
| 
      
 1247 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1337 
1248 
     | 
    
         
             
                def horizontal_distance(cls, coord1: np.ndarray, coord2: np.ndarray) -> float:
         
     | 
| 
       1338 
1249 
     | 
    
         
             
                    """
         
     | 
| 
       1339 
1250 
     | 
    
         
             
                    Calculate the horizontal distance between two coordinate points.
         
     | 
| 
         @@ -1353,6 +1264,7 @@ class RasHdf: 
     | 
|
| 
       1353 
1264 
     | 
    
         
             
                    return np.linalg.norm(coord2 - coord1)
         
     | 
| 
       1354 
1265 
     | 
    
         | 
| 
       1355 
1266 
     | 
    
         
             
                @classmethod
         
     | 
| 
      
 1267 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1356 
1268 
     | 
    
         
             
                def interpolate_z_coords(cls, points: np.ndarray) -> np.ndarray:
         
     | 
| 
       1357 
1269 
     | 
    
         
             
                    """
         
     | 
| 
       1358 
1270 
     | 
    
         
             
                    Interpolate Z coordinates for a set of points.
         
     | 
| 
         @@ -1373,16 +1285,9 @@ class RasHdf: 
     | 
|
| 
       1373 
1285 
     | 
    
         
             
                    # This should be replaced with the appropriate interpolation method
         
     | 
| 
       1374 
1286 
     | 
    
         
             
                    z_coords = np.zeros((points.shape[0], 1))  # Assuming Z=0 for simplicity
         
     | 
| 
       1375 
1287 
     | 
    
         
             
                    return np.hstack((points, z_coords))
         
     | 
| 
       1376 
     | 
    
         
            -
               
         
     | 
| 
       1377 
     | 
    
         
            -
             
     | 
| 
       1378 
     | 
    
         
            -
             
     | 
| 
       1379 
     | 
    
         
            -
             
     | 
| 
       1380 
     | 
    
         
            -
             
     | 
| 
       1381 
     | 
    
         
            -
             
     | 
| 
       1382 
     | 
    
         
            -
             
     | 
| 
       1383 
1288 
     | 
    
         | 
| 
       1384 
1289 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1385 
     | 
    
         
            -
                @ 
     | 
| 
      
 1290 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1386 
1291 
     | 
    
         
             
                def extract_string_from_hdf(
         
     | 
| 
       1387 
1292 
     | 
    
         
             
                    cls,
         
     | 
| 
       1388 
1293 
     | 
    
         
             
                    hdf_input: Union[str, Path],
         
     | 
| 
         @@ -1425,10 +1330,12 @@ class RasHdf: 
     | 
|
| 
       1425 
1330 
     | 
    
         
             
                            else:
         
     | 
| 
       1426 
1331 
     | 
    
         
             
                                return f"Unsupported object type: {type(hdf_object)}"
         
     | 
| 
       1427 
1332 
     | 
    
         
             
                        except KeyError:
         
     | 
| 
      
 1333 
     | 
    
         
            +
                            logger = logging.getLogger(__name__)
         
     | 
| 
      
 1334 
     | 
    
         
            +
                            logger.error(f"Path not found: {hdf_path}")
         
     | 
| 
       1428 
1335 
     | 
    
         
             
                            raise KeyError(f"Path not found: {hdf_path}")
         
     | 
| 
       1429 
1336 
     | 
    
         | 
| 
       1430 
1337 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1431 
     | 
    
         
            -
                @ 
     | 
| 
      
 1338 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1432 
1339 
     | 
    
         
             
                def decode_byte_strings(dataframe: pd.DataFrame) -> pd.DataFrame:
         
     | 
| 
       1433 
1340 
     | 
    
         
             
                    """
         
     | 
| 
       1434 
1341 
     | 
    
         
             
                    Decodes byte strings in a DataFrame to regular string objects.
         
     | 
| 
         @@ -1456,7 +1363,7 @@ class RasHdf: 
     | 
|
| 
       1456 
1363 
     | 
    
         
             
                    return dataframe
         
     | 
| 
       1457 
1364 
     | 
    
         | 
| 
       1458 
1365 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1459 
     | 
    
         
            -
                @ 
     | 
| 
      
 1366 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1460 
1367 
     | 
    
         
             
                def perform_kdtree_query(
         
     | 
| 
       1461 
1368 
     | 
    
         
             
                    reference_points: np.ndarray,
         
     | 
| 
       1462 
1369 
     | 
    
         
             
                    query_points: np.ndarray,
         
     | 
| 
         @@ -1486,7 +1393,7 @@ class RasHdf: 
     | 
|
| 
       1486 
1393 
     | 
    
         
             
                    return snap
         
     | 
| 
       1487 
1394 
     | 
    
         | 
| 
       1488 
1395 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1489 
     | 
    
         
            -
                @ 
     | 
| 
      
 1396 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1490 
1397 
     | 
    
         
             
                def find_nearest_neighbors(points: np.ndarray, max_distance: float = 2.0) -> np.ndarray:
         
     | 
| 
       1491 
1398 
     | 
    
         
             
                    """
         
     | 
| 
       1492 
1399 
     | 
    
         
             
                    Creates a self KDTree for dataset points and finds nearest neighbors excluding self, 
         
     | 
| 
         @@ -1519,7 +1426,7 @@ class RasHdf: 
     | 
|
| 
       1519 
1426 
     | 
    
         
             
                    return snapped
         
     | 
| 
       1520 
1427 
     | 
    
         | 
| 
       1521 
1428 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1522 
     | 
    
         
            -
                @ 
     | 
| 
      
 1429 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1523 
1430 
     | 
    
         
             
                def consolidate_dataframe(
         
     | 
| 
       1524 
1431 
     | 
    
         
             
                    dataframe: pd.DataFrame,
         
     | 
| 
       1525 
1432 
     | 
    
         
             
                    group_by: Optional[Union[str, List[str]]] = None,
         
     | 
| 
         @@ -1564,7 +1471,7 @@ class RasHdf: 
     | 
|
| 
       1564 
1471 
     | 
    
         
             
                    return result
         
     | 
| 
       1565 
1472 
     | 
    
         | 
| 
       1566 
1473 
     | 
    
         
             
                @classmethod
         
     | 
| 
       1567 
     | 
    
         
            -
                @ 
     | 
| 
      
 1474 
     | 
    
         
            +
                @log_call
         
     | 
| 
       1568 
1475 
     | 
    
         
             
                def find_nearest_value(array: Union[list, np.ndarray], target_value: Union[int, float]) -> Union[int, float]:
         
     | 
| 
       1569 
1476 
     | 
    
         
             
                    """
         
     | 
| 
       1570 
1477 
     | 
    
         
             
                    Finds the nearest value in a NumPy array to the specified target value.
         
     | 
| 
         @@ -1587,7 +1494,8 @@ class RasHdf: 
     | 
|
| 
       1587 
1494 
     | 
    
         
             
                    return array[idx]
         
     | 
| 
       1588 
1495 
     | 
    
         | 
| 
       1589 
1496 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       1590 
     | 
    
         
            -
                 
     | 
| 
      
 1497 
     | 
    
         
            +
                @log_call
         
     | 
| 
      
 1498 
     | 
    
         
            +
                def _get_hdf_filename(hdf_input: Union[str, Path, h5py.File], ras_object=None) -> Optional[Path]:
         
     | 
| 
       1591 
1499 
     | 
    
         
             
                    """
         
     | 
| 
       1592 
1500 
     | 
    
         
             
                    Get the HDF filename from the input.
         
     | 
| 
       1593 
1501 
     | 
    
         | 
| 
         @@ -1596,11 +1504,10 @@ class RasHdf: 
     | 
|
| 
       1596 
1504 
     | 
    
         
             
                        ras_object (RasPrj, optional): The RAS project object. If None, uses the global ras instance.
         
     | 
| 
       1597 
1505 
     | 
    
         | 
| 
       1598 
1506 
     | 
    
         
             
                    Returns:
         
     | 
| 
       1599 
     | 
    
         
            -
                        Path: The full path to the HDF file as a Path object.
         
     | 
| 
      
 1507 
     | 
    
         
            +
                        Optional[Path]: The full path to the HDF file as a Path object, or None if an error occurs.
         
     | 
| 
       1600 
1508 
     | 
    
         | 
| 
       1601 
     | 
    
         
            -
                     
     | 
| 
       1602 
     | 
    
         
            -
                         
     | 
| 
       1603 
     | 
    
         
            -
                        FileNotFoundError: If the specified HDF file does not exist.
         
     | 
| 
      
 1509 
     | 
    
         
            +
                    Note:
         
     | 
| 
      
 1510 
     | 
    
         
            +
                        This method logs critical errors instead of raising exceptions.
         
     | 
| 
       1604 
1511 
     | 
    
         
             
                    """
         
     | 
| 
       1605 
1512 
     | 
    
         | 
| 
       1606 
1513 
     | 
    
         
             
                    # If hdf_input is already an h5py.File object, return its filename
         
     | 
| 
         @@ -1608,30 +1515,39 @@ class RasHdf: 
     | 
|
| 
       1608 
1515 
     | 
    
         
             
                        return Path(hdf_input.filename)
         
     | 
| 
       1609 
1516 
     | 
    
         | 
| 
       1610 
1517 
     | 
    
         
             
                    # Convert to Path object if it's a string
         
     | 
| 
       1611 
     | 
    
         
            -
                     
     | 
| 
      
 1518 
     | 
    
         
            +
                    if isinstance(hdf_input, str):
         
     | 
| 
      
 1519 
     | 
    
         
            +
                        hdf_input = Path(hdf_input)
         
     | 
| 
       1612 
1520 
     | 
    
         | 
| 
       1613 
1521 
     | 
    
         
             
                    # If hdf_input is a file path, return it directly
         
     | 
| 
       1614 
     | 
    
         
            -
                    if hdf_input.is_file():
         
     | 
| 
      
 1522 
     | 
    
         
            +
                    if isinstance(hdf_input, Path) and hdf_input.is_file():
         
     | 
| 
       1615 
1523 
     | 
    
         
             
                        return hdf_input
         
     | 
| 
       1616 
1524 
     | 
    
         | 
| 
       1617 
1525 
     | 
    
         
             
                    # If hdf_input is not a file path, assume it's a plan number and require ras_object
         
     | 
| 
       1618 
1526 
     | 
    
         
             
                    ras_obj = ras_object or ras
         
     | 
| 
       1619 
1527 
     | 
    
         
             
                    if not ras_obj.initialized:
         
     | 
| 
       1620 
     | 
    
         
            -
                         
     | 
| 
      
 1528 
     | 
    
         
            +
                        logger.critical("ras_object is not initialized. ras_object is required when hdf_input is not a direct file path.")
         
     | 
| 
      
 1529 
     | 
    
         
            +
                        return None
         
     | 
| 
       1621 
1530 
     | 
    
         | 
| 
       1622 
1531 
     | 
    
         
             
                    plan_info = ras_obj.plan_df[ras_obj.plan_df['plan_number'] == str(hdf_input)]
         
     | 
| 
       1623 
1532 
     | 
    
         
             
                    if plan_info.empty:
         
     | 
| 
       1624 
     | 
    
         
            -
                         
     | 
| 
      
 1533 
     | 
    
         
            +
                        logger.critical(f"No HDF file found for plan number {hdf_input}")
         
     | 
| 
      
 1534 
     | 
    
         
            +
                        return None
         
     | 
| 
       1625 
1535 
     | 
    
         | 
| 
       1626 
     | 
    
         
            -
                    hdf_filename =  
     | 
| 
       1627 
     | 
    
         
            -
                    if  
     | 
| 
       1628 
     | 
    
         
            -
                         
     | 
| 
      
 1536 
     | 
    
         
            +
                    hdf_filename = plan_info.iloc[0]['HDF_Results_Path']
         
     | 
| 
      
 1537 
     | 
    
         
            +
                    if hdf_filename is None:
         
     | 
| 
      
 1538 
     | 
    
         
            +
                        logger.critical(f"HDF_Results_Path is None for plan number {hdf_input}")
         
     | 
| 
      
 1539 
     | 
    
         
            +
                        return None
         
     | 
| 
       1629 
1540 
     | 
    
         | 
| 
       1630 
     | 
    
         
            -
                     
     | 
| 
      
 1541 
     | 
    
         
            +
                    hdf_path = Path(hdf_filename)
         
     | 
| 
      
 1542 
     | 
    
         
            +
                    if not hdf_path.is_file():
         
     | 
| 
      
 1543 
     | 
    
         
            +
                        logger.critical(f"HDF file not found: {hdf_path}")
         
     | 
| 
      
 1544 
     | 
    
         
            +
                        return None
         
     | 
| 
       1631 
1545 
     | 
    
         | 
| 
      
 1546 
     | 
    
         
            +
                    return hdf_path
         
     | 
| 
       1632 
1547 
     | 
    
         | 
| 
       1633 
1548 
     | 
    
         | 
| 
       1634 
1549 
     | 
    
         | 
| 
      
 1550 
     | 
    
         
            +
            @log_call
         
     | 
| 
       1635 
1551 
     | 
    
         
             
            def save_dataframe_to_hdf(
         
     | 
| 
       1636 
1552 
     | 
    
         
             
                dataframe: pd.DataFrame,
         
     | 
| 
       1637 
1553 
     | 
    
         
             
                hdf_parent_group: h5py.Group,
         
     | 
| 
         @@ -1678,6 +1594,7 @@ def save_dataframe_to_hdf( 
     | 
|
| 
       1678 
1594 
     | 
    
         
             
                # Identify string columns and ensure consistency
         
     | 
| 
       1679 
1595 
     | 
    
         
             
                string_cols = df.select_dtypes(include=['object']).columns
         
     | 
| 
       1680 
1596 
     | 
    
         
             
                if not string_cols.equals(df.select_dtypes(include=['object']).columns):
         
     | 
| 
      
 1597 
     | 
    
         
            +
                    logger.error("Inconsistent string columns detected")
         
     | 
| 
       1681 
1598 
     | 
    
         
             
                    raise ValueError("Inconsistent string columns detected")
         
     | 
| 
       1682 
1599 
     | 
    
         | 
| 
       1683 
1600 
     | 
    
         
             
                # Encode string columns to bytes
         
     | 
| 
         @@ -1688,6 +1605,7 @@ def save_dataframe_to_hdf( 
     | 
|
| 
       1688 
1605 
     | 
    
         | 
| 
       1689 
1606 
     | 
    
         
             
                # Remove existing dataset if it exists
         
     | 
| 
       1690 
1607 
     | 
    
         
             
                if dataset_name in hdf_parent_group:
         
     | 
| 
      
 1608 
     | 
    
         
            +
                    logger.warning(f"Existing dataset {dataset_name} will be overwritten")
         
     | 
| 
       1691 
1609 
     | 
    
         
             
                    del hdf_parent_group[dataset_name]
         
     | 
| 
       1692 
1610 
     | 
    
         | 
| 
       1693 
1611 
     | 
    
         
             
                # Create the dataset in the HDF5 file
         
     | 
| 
         @@ -1697,6 +1615,5 @@ def save_dataframe_to_hdf( 
     | 
|
| 
       1697 
1615 
     | 
    
         
             
                if attributes:
         
     | 
| 
       1698 
1616 
     | 
    
         
             
                    dataset.attrs.update(attributes)
         
     | 
| 
       1699 
1617 
     | 
    
         | 
| 
       1700 
     | 
    
         
            -
                 
     | 
| 
      
 1618 
     | 
    
         
            +
                logger.info(f"Successfully saved DataFrame to dataset: {dataset_name}")
         
     | 
| 
       1701 
1619 
     | 
    
         
             
                return dataset
         
     | 
| 
       1702 
     | 
    
         
            -
             
     |