diff --git a/lidar_pipeline/visualizations.py b/lidar_pipeline/visualizations.py index a06dcd3..041dffd 100644 --- a/lidar_pipeline/visualizations.py +++ b/lidar_pipeline/visualizations.py @@ -298,6 +298,11 @@ def _ray_trace_horizons(dem, rows, cols, res, n_dirs, max_dist, radii_m=None): recording the max upward angle (positive openness) and max downward angle (negative openness) reached at each radius checkpoint. + Padding is done on CPU (numpy) to avoid GPU memory pressure and + pre-compiled kernel mismatches (CUDA_ERROR_NO_BINARY_FOR_GPU on sm_89). + The padded array is transferred to GPU once, then each direction is + processed and results are streamed back to CPU. + Args: dem: GPU or CPU filled DEM array (rows, cols). rows, cols: dimensions. @@ -322,7 +327,15 @@ def _ray_trace_horizons(dem, rows, cols, res, n_dirs, max_dist, radii_m=None): radii_steps = [max_dist] n_radii = 1 - padded = xp.pad(dem, max_dist, mode='constant', constant_values=xp.nan) + # Pad on CPU (numpy) — avoids GPU memory pressure and + # pre-compiled kernel issues (NO_BINARY_FOR_GPU on sm_89). + dem_np = to_cpu(dem) + padded_np = np.pad(dem_np, max_dist, mode='constant', constant_values=np.nan) + + # Transfer padded DEM to GPU for computation + padded = to_gpu(padded_np) + # Free the CPU copy — we don't need it anymore + del dem_np, padded_np # Process one direction at a time to limit GPU memory. # Store results as flat CPU arrays — transfer back to GPU at the end. @@ -349,13 +362,17 @@ def _ray_trace_horizons(dem, rows, cols, res, n_dirs, max_dist, radii_m=None): radii_remaining = set(range(n_radii)) for step, px, py, dist_m in valid_steps: - elev_diff = padded[max_dist + py:max_dist + py + rows, - max_dist + px:max_dist + px + cols] - dem + # Slice from padded array, subtract original dem + view = padded[max_dist + py:max_dist + py + rows, + max_dist + px:max_dist + px + cols] + elev_diff = view - dem + del view # free slice reference # Positive: angle to terrain above viewer pos_angle = xp.arctan2(xp.maximum(elev_diff, 0), dist_m) # Negative: angle to terrain below viewer neg_angle = xp.arctan2(xp.maximum(-elev_diff, 0), dist_m) + del elev_diff # free intermediate # Update running max for all radius checkpoints still active for r_idx in radii_remaining: