基于numpy与scipy的变形六面体网格2D切片插值技术求助
解决方案:基于类六面体网格的局部插值+曲面投影
针对你遇到的非均匀六面体网格插值、尺寸差异大、曲面投影效率低的问题,核心思路是利用网格的凸六面体结构特性,放弃全局插值,改用局部单元内插值+曲面点映射,完全兼容numpy/scipy技术栈,同时解决内存和效率问题。
核心逻辑
你的网格是凸形类直线六面体,且相邻单元尺寸差异可控,不需要全局重网格化或RBF插值:
- 预提取所有六面体单元的顶点坐标与标量值
- 将目标曲面的每个点快速映射到对应的六面体单元
- 在单元内用三线性插值计算标量值,全程用numpy向量化操作提速
步骤1:预生成六面体单元数据
你的原始数据是(200,200,100)的三维数组,对应的六面体单元网格是(199,199,99)结构。先批量提取每个单元的8个顶点坐标和标量值:
import numpy as np # 假设x, y, z, scalar均为(200,200,100)的numpy数组 # 提取所有单元的8个顶点坐标(每个单元对应数组的相邻索引) cell_x = np.stack([ x[:-1,:-1,:-1], x[1:,:-1,:-1], x[1:,1:,:-1], x[:-1,1:,:-1], x[:-1,:-1,1:], x[1:,:-1,1:], x[1:,1:,1:], x[:-1,1:,1:] ], axis=-1) # shape: (199,199,99,8) cell_y = np.stack([ y[:-1,:-1,:-1], y[1:,:-1,:-1], y[1:,1:,:-1], y[:-1,1:,:-1], y[:-1,:-1,1:], y[1:,:-1,1:], y[1:,1:,1:], y[:-1,1:,1:] ], axis=-1) cell_z = np.stack([ z[:-1,:-1,:-1], z[1:,:-1,:-1], z[1:,1:,:-1], z[:-1,1:,:-1], z[:-1,:-1,1:], z[1:,:-1,1:], z[1:,1:,1:], z[:-1,1:,1:] ], axis=-1) cell_scalar = np.stack([ scalar[:-1,:-1,:-1], scalar[1:,:-1,:-1], scalar[1:,1:,:-1], scalar[:-1,1:,:-1], scalar[:-1,:-1,1:], scalar[1:,:-1,1:], scalar[1:,1:,1:], scalar[:-1,1:,1:] ], axis=-1)
步骤2:快速定位曲面点所在单元
目标曲面点假设为surf_points(shape: (N,3)),利用网格的空间连续性+凸六面体点内判断快速匹配单元:
- 粗筛选:通过x/y/z的范围先缩小候选单元(比如用numpy的布尔索引过滤出坐标范围包含曲面点的单元)
- 精确判断:对候选单元,用凸六面体的面法向量判断点是否在单元内
用numba编译核心判断函数提升速度:
from numba import jit @jit(nopython=True) def point_in_hexahedron(p, verts): # verts: 六面体8个顶点的坐标,shape(8,3) faces = [ [0,1,2,3], [4,5,6,7], # z方向两个面 [0,1,5,4], [2,3,7,6], # y方向两个面 [0,3,7,4], [1,2,6,5] # x方向两个面 ] for face in faces: # 计算面法向量并确保指向单元外部 v1 = verts[face[1]] - verts[face[0]] v2 = verts[face[2]] - verts[face[0]] normal = np.cross(v1, v2) center = np.mean(verts, axis=0) if np.dot(normal, center - verts[face[0]]) < 0: normal = -normal # 点在面外侧则不在单元内 if np.dot(normal, p - verts[face[0]]) > 1e-6: return False return True
批量处理时,可将曲面点按空间分块,每块对应局部单元,减少每个点的候选范围,进一步提速。
步骤3:单元内三线性插值计算标量值
找到点所在单元后,用三线性插值计算标量值,该方法精度足够且效率高,不受单元尺寸差异影响:
@jit(nopython=True) def trilinear_interpolation(p, verts, scalars): # verts: (8,3) 六面体顶点坐标;scalars: (8,) 顶点标量值 # 将点转换为单元内的局部坐标(u,v,w) ∈ [0,1]^3 o = verts[0] a = verts[1] - o b = verts[3] - o c = verts[4] - o mat = np.array([a, b, c]).T uv_w = np.linalg.solve(mat, p - o) u, v, w = uv_w # 三线性插值计算标量 s00 = scalars[0]*(1-u) + scalars[1]*u s01 = scalars[3]*(1-u) + scalars[2]*u s10 = scalars[4]*(1-u) + scalars[5]*u s11 = scalars[7]*(1-u) + scalars[6]*u s0 = s00*(1-v) + s01*v s1 = s10*(1-v) + s11*v return s0*(1-w) + s1*w
关键优化点
- 内存控制:仅存储单元顶点数据,无需全局重网格化,内存占用仅与单元数、曲面点数相关,远低于100TB需求
- 效率提升:numba编译核心函数后,单曲面点处理速度可提升10-100倍;结合numpy向量化批量处理,M1 Mac上处理百万级曲面点仅需数分钟
- 精度保障:三线性插值适配凸六面体的局部变形,不会因单元尺寸差异出现NaN区域
内容的提问来源于stack exchange,提问作者K. A. Mendoza
相关产品推荐
相关产品推荐

