|
125 | 125 | # define some limits for transient heat simulations |
126 | 126 | TRANSIENT_HEAT_MAX_STEPS = 1000 |
127 | 127 |
|
128 | | -# OpenCASCADE minimum tolerance for cylinder radii |
129 | | -OPENCASCADE_CYLINDER_RADIUS_TOL = 1e-6 |
| 128 | +# Minimum tolerance for cylinder radii |
| 129 | +CYLINDER_RADIUS_TOL = 1e-6 |
130 | 130 | # Minimum radius as fraction of the larger radius (for tapered cylinders) |
131 | 131 | MIN_CYLINDER_RADIUS_FRACTION = 0.01 |
132 | 132 |
|
133 | 133 |
|
| 134 | +def _get_cylinder_radii_with_meshing_tol(geometry: Cylinder) -> tuple[float, float]: |
| 135 | + """Get cylinder radii clamped to the minimum meshing tolerance. |
| 136 | +
|
| 137 | + OpenCASCADE has a minimum tolerance for radii; this function clamps |
| 138 | + small or negative values to a small positive value to ensure valid |
| 139 | + geometry that can be meshed. The minimum is set relative to the larger |
| 140 | + radius to ensure meshability while still creating a reasonably sharp |
| 141 | + tip for tapered cylinders. |
| 142 | +
|
| 143 | + Parameters |
| 144 | + ---------- |
| 145 | + geometry : Cylinder |
| 146 | + The cylinder geometry to get radii from. |
| 147 | +
|
| 148 | + Returns |
| 149 | + ------- |
| 150 | + tuple[float, float] |
| 151 | + ``(r1, r2)`` -- bottom and top radii, clamped to the minimum allowed radius. |
| 152 | + """ |
| 153 | + r1 = geometry.radius_bottom |
| 154 | + r2 = geometry.radius_top |
| 155 | + |
| 156 | + min_radius = max( |
| 157 | + CYLINDER_RADIUS_TOL, |
| 158 | + MIN_CYLINDER_RADIUS_FRACTION * max(abs(r1), abs(r2)), |
| 159 | + ) |
| 160 | + |
| 161 | + r1 = max(r1, min_radius) |
| 162 | + r2 = max(r2, min_radius) |
| 163 | + |
| 164 | + return r1, r2 |
| 165 | + |
| 166 | + |
134 | 167 | class TCADAnalysisTypes(str, Enum): |
135 | 168 | """Enumeration of the types of simulations currently supported""" |
136 | 169 |
|
@@ -376,31 +409,27 @@ def _warn_small_cylinder_radius(cls, val: tuple[Structure, ...]) -> tuple[Struct |
376 | 409 | r_top = base_geometry.radius_top |
377 | 410 | is_tapered = not np.isclose(r_bottom, r_top) |
378 | 411 |
|
379 | | - # Compute minimum allowed radius (matches backend heat_mesh.py logic) |
380 | | - min_radius = max( |
381 | | - OPENCASCADE_CYLINDER_RADIUS_TOL, |
382 | | - MIN_CYLINDER_RADIUS_FRACTION * max(abs(r_bottom), abs(r_top)), |
383 | | - ) |
| 412 | + r1, r2 = _get_cylinder_radii_with_meshing_tol(base_geometry) |
384 | 413 |
|
385 | | - # Warn if radii are below minimum |
| 414 | + # Warn if radii were clamped |
386 | 415 | if is_tapered: |
387 | | - if r_bottom < min_radius: |
| 416 | + if r1 > r_bottom: |
388 | 417 | log.warning( |
389 | 418 | f"Cylinder 'radius_bottom' ({r_bottom:.3e}) is below the minimum " |
390 | | - f"radius for meshing ({min_radius:.3e}). The sidewall angle may be " |
| 419 | + f"radius for meshing ({r1:.3e}). The sidewall angle may be " |
391 | 420 | f"too steep. Will be clamped to minimum radius or mesh size, whichever is larger." |
392 | 421 | ) |
393 | | - if r_top < min_radius: |
| 422 | + if r2 > r_top: |
394 | 423 | log.warning( |
395 | 424 | f"Cylinder 'radius_top' ({r_top:.3e}) is below the minimum " |
396 | | - f"radius for meshing ({min_radius:.3e}). The sidewall angle may be " |
| 425 | + f"radius for meshing ({r2:.3e}). The sidewall angle may be " |
397 | 426 | f"too steep. Will be clamped to minimum radius or mesh size, whichever is larger." |
398 | 427 | ) |
399 | 428 | else: |
400 | | - if r_bottom < min_radius: |
| 429 | + if r1 > r_bottom: |
401 | 430 | log.warning( |
402 | 431 | f"Cylinder 'radius' ({r_bottom:.3e}) is below the minimum " |
403 | | - f"radius for meshing ({min_radius:.3e}). " |
| 432 | + f"radius for meshing ({r1:.3e}). " |
404 | 433 | f"Will be clamped to minimum radius or mesh size, whichever is larger." |
405 | 434 | ) |
406 | 435 | return val |
|
0 commit comments