0.1.8
Loading...
Searching...
No Matches
BoundaryLayerConductance.py
Go to the documentation of this file.
1"""
2High-level BoundaryLayerConductanceModel interface for PyHelios.
3
4This module provides a user-friendly interface to the boundary layer conductance modeling
5capabilities with graceful plugin handling and informative error messages.
6"""
7
8import logging
9from typing import List, Optional
10
11from .plugins.registry import get_plugin_registry
12from .wrappers import UBoundaryLayerConductanceWrapper as bl_wrapper
13from .Context import Context
14from .exceptions import HeliosError
15
16logger = logging.getLogger(__name__)
17
18
20 """Exception raised for BoundaryLayerConductanceModel-specific errors."""
21 pass
22
23
25 """
26 High-level interface for boundary layer conductance modeling and heat/mass transfer calculations.
27
28 This class provides a user-friendly wrapper around the native Helios
29 boundary layer conductance plugin with automatic plugin availability checking and
30 graceful error handling.
31
32 The boundary layer conductance model implements four different boundary-layer models:
33 - Pohlhausen: Laminar flat plate, forced convection (default)
34 - InclinedPlate: Mixed free-forced convection for inclined plates
35 - Sphere: Laminar flow around a sphere
36 - Ground: Flow over bare ground surface
37
38 System requirements:
39 - Cross-platform support (Windows, Linux, macOS)
40 - No GPU required
41 - No special dependencies
42 - Boundary layer conductance plugin compiled into PyHelios
43
44 Example:
45 >>> from pyhelios import Context, BoundaryLayerConductanceModel
46 >>>
47 >>> with Context() as context:
48 ... # Add leaf geometry
49 ... leaf_uuid = context.addPatch(center=[0, 0, 1], size=[0.1, 0.1])
50 ...
51 ... with BoundaryLayerConductanceModel(context) as bl_model:
52 ... # Set model for all primitives (default is Pohlhausen)
53 ... bl_model.setBoundaryLayerModel("InclinedPlate")
54 ...
55 ... # Run calculation
56 ... bl_model.run()
57 ...
58 ... # Or set different models for different primitives
59 ... bl_model.setBoundaryLayerModel("Sphere", uuids=[leaf_uuid])
60 ... bl_model.run(uuids=[leaf_uuid])
61 """
62
63 def __init__(self, context: Context):
64 """
65 Initialize BoundaryLayerConductanceModel with graceful plugin handling.
66
67 Args:
68 context: Helios Context instance
69
70 Raises:
71 TypeError: If context is not a Context instance
72 BoundaryLayerConductanceModelError: If boundary layer conductance plugin is not available
73 """
74 # Validate context type - use duck typing to handle import state issues during testing
75 if not (hasattr(context, '__class__') and
76 (isinstance(context, Context) or
77 context.__class__.__name__ == 'Context')):
78 raise TypeError(f"BoundaryLayerConductanceModel requires a Context instance, got {type(context).__name__}")
79
80 self.context = context
81 self.bl_model = None
83 # Check plugin availability using registry
84 registry = get_plugin_registry()
85
86 if not registry.is_plugin_available('boundarylayerconductance'):
87 # Get helpful information about the missing plugin
88 available_plugins = registry.get_available_plugins()
89
90 error_msg = (
91 "BoundaryLayerConductanceModel requires the 'boundarylayerconductance' plugin which is not available.\n\n"
92 "The boundary layer conductance plugin provides heat and mass transfer calculations using four validated models:\n"
93 "- Pohlhausen: Laminar flat plate, forced convection\n"
94 "- InclinedPlate: Mixed free-forced convection for inclined surfaces\n"
95 "- Sphere: Laminar flow around spherical objects\n"
96 "- Ground: Convective transfer over bare ground\n\n"
97 "Features:\n"
98 "- Cross-platform support (Windows, Linux, macOS)\n"
99 "- No GPU or special dependencies required\n"
100 "- Applicable to plant leaves, fruits, and soil surfaces\n\n"
101 "To enable boundary layer conductance modeling:\n"
102 "1. Build PyHelios with boundary layer conductance plugin:\n"
103 " build_scripts/build_helios --plugins boundarylayerconductance\n"
104 "2. Or build with multiple physics plugins:\n"
105 " build_scripts/build_helios --plugins boundarylayerconductance,energybalance,stomatalconductance\n"
106 f"\nCurrently available plugins: {available_plugins}"
107 )
108
109 # Suggest alternatives if available
110 alternatives = registry.suggest_alternatives('boundarylayerconductance')
111 if alternatives:
112 error_msg += f"\n\nAlternative plugins available: {alternatives}"
113 error_msg += "\nConsider using energybalance or stomatalconductance for related plant physiology modeling."
114
116
117 # Plugin is available - create boundary layer conductance model
118 try:
119 self.bl_model = bl_wrapper.createBoundaryLayerConductanceModel(context.getNativePtr())
120 if self.bl_model is None:
122 "Failed to create BoundaryLayerConductanceModel instance. "
123 "This may indicate a problem with the native library."
124 )
125 logger.info("BoundaryLayerConductanceModel created successfully")
126
127 except Exception as e:
128 raise BoundaryLayerConductanceModelError(f"Failed to initialize BoundaryLayerConductanceModel: {e}")
129
130 def __enter__(self):
131 """Context manager entry."""
132 return self
134 def __exit__(self, exc_type, exc_value, traceback):
135 """Context manager exit with proper cleanup."""
136 if self.bl_model is not None:
137 try:
138 bl_wrapper.destroyBoundaryLayerConductanceModel(self.bl_model)
139 logger.debug("BoundaryLayerConductanceModel destroyed successfully")
140 except Exception as e:
141 logger.warning(f"Error destroying BoundaryLayerConductanceModel: {e}")
142 finally:
143 self.bl_model = None
144
145 def getNativePtr(self):
146 """Get the native pointer for advanced operations."""
147 return self.bl_model
149 def enableMessages(self) -> None:
150 """
151 Enable console output messages from the boundary layer conductance model.
152
153 Raises:
154 BoundaryLayerConductanceModelError: If operation fails
155 """
156 try:
157 bl_wrapper.enableMessages(self.bl_model)
158 except Exception as e:
159 raise BoundaryLayerConductanceModelError(f"Failed to enable messages: {e}")
160
161 def disableMessages(self) -> None:
162 """
163 Disable console output messages from the boundary layer conductance model.
164
165 Raises:
166 BoundaryLayerConductanceModelError: If operation fails
167 """
168 try:
169 bl_wrapper.disableMessages(self.bl_model)
170 except Exception as e:
171 raise BoundaryLayerConductanceModelError(f"Failed to disable messages: {e}")
172
173 def setBoundaryLayerModel(self, model_name: str, uuids: Optional[List[int]] = None) -> None:
174 """
175 Set the boundary layer conductance model to be used.
176
177 Four models are available:
178 - "Pohlhausen": Laminar flat plate, forced convection (default)
179 - "InclinedPlate": Mixed free-forced convection for inclined plates
180 - "Sphere": Laminar flow around a sphere
181 - "Ground": Flow over bare ground surface
182
183 Args:
184 model_name: Name of the boundary layer model to use.
185 Must be one of: "Pohlhausen", "InclinedPlate", "Sphere", "Ground"
186 uuids: Optional list of primitive UUIDs to apply the model to.
187 If None, applies to all primitives in the Context.
188
189 Raises:
190 ValueError: If model_name is not valid
191 BoundaryLayerConductanceModelError: If operation fails
192
193 Example:
194 >>> # Set Pohlhausen model for all primitives
195 >>> bl_model.setBoundaryLayerModel("Pohlhausen")
196
197 >>> # Set InclinedPlate model for specific leaves
198 >>> bl_model.setBoundaryLayerModel("InclinedPlate", uuids=[uuid1, uuid2])
199
200 >>> # Set Sphere model for fruit geometry
201 >>> bl_model.setBoundaryLayerModel("Sphere", uuids=[fruit_uuid])
202
203 >>> # Set Ground model for soil patches
204 >>> bl_model.setBoundaryLayerModel("Ground", uuids=[ground_uuids])
205 """
206 # Validate model name
207 valid_models = ["Pohlhausen", "InclinedPlate", "Sphere", "Ground"]
208 if model_name not in valid_models:
209 raise ValueError(
210 f"Invalid boundary layer model '{model_name}'. "
211 f"Must be one of: {', '.join(valid_models)}"
212 )
213
214 try:
215 if uuids is None:
216 # Apply to all primitives
217 bl_wrapper.setBoundaryLayerModel(self.bl_model, model_name)
218 elif len(uuids) == 1:
219 # Single UUID - use UUID-specific function
220 bl_wrapper.setBoundaryLayerModelForUUID(self.bl_model, uuids[0], model_name)
221 else:
222 # Multiple UUIDs
223 bl_wrapper.setBoundaryLayerModelForUUIDs(self.bl_model, uuids, model_name)
224
225 except Exception as e:
226 raise BoundaryLayerConductanceModelError(f"Failed to set boundary layer model: {e}")
227
228 def run(self, uuids: Optional[List[int]] = None) -> None:
229 """
230 Run the boundary layer conductance calculations.
231
232 Calculates boundary-layer conductance values and stores results as
233 primitive data "boundarylayer_conductance" (mol air/m²/s).
234
235 Args:
236 uuids: Optional list of primitive UUIDs to process.
237 If None, processes all primitives in the Context.
238
239 Raises:
240 BoundaryLayerConductanceModelError: If calculation fails
241
242 Example:
243 >>> # Calculate for all primitives
244 >>> bl_model.run()
245
246 >>> # Calculate for specific primitives
247 >>> bl_model.run(uuids=[leaf1_uuid, leaf2_uuid])
248 """
249 try:
250 if uuids is None:
251 # Run for all primitives
252 bl_wrapper.runBoundaryLayerModel(self.bl_model)
253 else:
254 # Run for specific UUIDs
255 bl_wrapper.runBoundaryLayerModelForUUIDs(self.bl_model, uuids)
256
257 except Exception as e:
258 raise BoundaryLayerConductanceModelError(f"Failed to run boundary layer conductance calculation: {e}")
259
260 @staticmethod
261 def is_available() -> bool:
262 """
263 Check if BoundaryLayerConductanceModel plugin is available in current build.
264
265 Returns:
266 True if plugin is available, False otherwise
267
268 Example:
269 >>> if BoundaryLayerConductanceModel.is_available():
270 ... print("Boundary layer conductance modeling is available!")
271 """
272 registry = get_plugin_registry()
273 return registry.is_plugin_available('boundarylayerconductance')
Exception raised for BoundaryLayerConductanceModel-specific errors.
High-level interface for boundary layer conductance modeling and heat/mass transfer calculations.
__exit__(self, exc_type, exc_value, traceback)
Context manager exit with proper cleanup.
getNativePtr(self)
Get the native pointer for advanced operations.
None disableMessages(self)
Disable console output messages from the boundary layer conductance model.
None run(self, Optional[List[int]] uuids=None)
Run the boundary layer conductance calculations.
bool is_available()
Check if BoundaryLayerConductanceModel plugin is available in current build.
None setBoundaryLayerModel(self, str model_name, Optional[List[int]] uuids=None)
Set the boundary layer conductance model to be used.
__init__(self, Context context)
Initialize BoundaryLayerConductanceModel with graceful plugin handling.
None enableMessages(self)
Enable console output messages from the boundary layer conductance model.
Exception classes for PyHelios library.
Definition exceptions.py:10