You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

3D储层网格连通性与迂曲度计算代码运行过慢求助

问题分析与优化方案

核心性能瓶颈与逻辑问题

1. 迂曲度计算的性能与逻辑问题

  • 使用NetworkX构建79万+节点的大型3D图,Python级别的三重循环添加边,效率极低。
  • nx.all_pairs_shortest_path_length针对超大规模图的时间复杂度爆炸,完全无法完成计算。
  • 重复计算渗透率与孔隙度的乘积,浪费算力。
  • 逻辑错误:自身到自身的最短路径长度为0,原代码的比值计算无意义,不符合迂曲度的物理定义(实际路径长度与直线距离的比值)。

2. 连通性计算的逻辑错误

  • 原代码将3D网格重塑为2D矩阵后计算连通分量,仅实现了每层内部的2D连通,完全忽略了上下层之间的3D连通,不符合储层3D连通性的需求。

优化后的实现代码

修正连通性计算(3D空间连通)+ 大幅优化迂曲度计算

import numpy as np
from scipy.sparse import csr_matrix, lil_matrix
from scipy.sparse.csgraph import connected_components, dijkstra

connectivity_threshold = 0.125
tortuosity_threshold = 1

def calculate_connectivity(porosity, threshold=connectivity_threshold):
    n_layers, n_rows, n_columns = porosity.shape
    total_nodes = n_layers * n_rows * n_columns
    
    # 生成有效孔隙度的掩码
    mask = porosity > threshold
    mask_flat = mask.flatten()
    
    # 构建3D邻接矩阵(LIL格式方便构建,最后转CSR)
    adj_matrix = lil_matrix((total_nodes, total_nodes), dtype=bool)
    
    # 同一层内的左右相邻
    valid_left = mask[:, :, :-1] & mask[:, :, 1:]
    left_indices = np.where(valid_left.flatten())[0]
    adj_matrix[left_indices, left_indices + 1] = True
    adj_matrix[left_indices + 1, left_indices] = True
    
    # 同一层内的上下相邻
    valid_up = mask[:, :-1, :] & mask[:, 1:, :]
    up_indices = np.where(valid_up.flatten())[0]
    adj_matrix[up_indices, up_indices + n_columns] = True
    adj_matrix[up_indices + n_columns, up_indices] = True
    
    # 层间垂直相邻
    valid_layer = mask[:-1, :, :] & mask[1:, :, :]
    layer_indices = np.where(valid_layer.flatten())[0]
    adj_matrix[layer_indices, layer_indices + n_rows * n_columns] = True
    adj_matrix[layer_indices + n_rows * n_columns, layer_indices] = True
    
    # 转CSR格式用于连通分量计算
    adj_matrix = adj_matrix.tocsr()
    
    # 计算3D连通分量
    n_components, labels = connected_components(adj_matrix, directed=False)
    
    # 还原为3D格式,非有效网格标记为0
    connectivity = np.zeros_like(porosity, dtype=int)
    connectivity[mask] = labels[mask_flat] + 1  # 组件编号从1开始
    
    return connectivity

def calculate_tortuosity(permeability_field, porosity_field, threshold=tortuosity_threshold):
    n_layers, n_rows, n_columns = permeability_field.shape
    total_nodes = n_layers * n_rows * n_columns
    
    # 预计算有效渗透率掩码
    effective_perm = permeability_field * porosity_field
    mask = effective_perm > threshold
    mask_flat = mask.flatten()
    valid_indices = np.where(mask_flat)[0]
    
    if len(valid_indices) == 0:
        return np.zeros_like(permeability_field, dtype=float)
    
    # 建立全局索引与有效索引的映射
    global_to_valid = {g_idx: v_idx for v_idx, g_idx in enumerate(valid_indices)}
    valid_to_global = {v_idx: g_idx for v_idx, g_idx in enumerate(valid_indices)}
    n_valid = len(valid_indices)
    
    # 构建有效网格的邻接矩阵
    adj_matrix = lil_matrix((n_valid, n_valid), dtype=int)
    
    # 处理同一层内的左右相邻
    valid_left = mask[:, :, :-1] & mask[:, :, 1:]
    left_global = np.where(valid_left.flatten())[0]
    for g_idx in left_global:
        v1 = global_to_valid[g_idx]
        v2 = global_to_valid[g_idx + 1]
        adj_matrix[v1, v2] = 1
        adj_matrix[v2, v1] = 1
    
    # 处理同一层内的上下相邻
    valid_up = mask[:, :-1, :] & mask[:, 1:, :]
    up_global = np.where(valid_up.flatten())[0]
    for g_idx in up_global:
        v1 = global_to_valid[g_idx]
        v2 = global_to_valid[g_idx + n_columns]
        adj_matrix[v1, v2] = 1
        adj_matrix[v2, v1] = 1
    
    # 处理层间垂直相邻
    valid_layer = mask[:-1, :, :] & mask[1:, :, :]
    layer_global = np.where(valid_layer.flatten())[0]
    for g_idx in layer_global:
        v1 = global_to_valid[g_idx]
        v2 = global_to_valid[g_idx + n_rows * n_columns]
        adj_matrix[v1, v2] = 1
        adj_matrix[v2, v1] = 1
    
    adj_matrix = adj_matrix.tocsr()
    
    # 按连通分量拆分计算
    n_components, comp_labels = connected_components(adj_matrix, directed=False)
    tortuosity_values = np.zeros_like(permeability_field, dtype=float)
    
    # 预计算所有有效节点的3D坐标
    coords = np.array([(g_idx // (n_rows * n_columns), 
                        (g_idx % (n_rows * n_columns)) // n_columns, 
                        g_idx % n_columns) 
                       for g_idx in valid_indices])
    
    for comp in range(n_components):
        comp_valid_indices = np.where(comp_labels == comp)[0]
        comp_global_indices = [valid_to_global[v_idx] for v_idx in comp_valid_indices]
        comp_size = len(comp_valid_indices)
        
        if comp_size == 1:
            # 单个节点,迂曲度设为1
            g_idx = comp_global_indices[0]
            k, i, j = g_idx // (n_rows * n_columns), (g_idx % (n_rows * n_columns)) // n_columns, g_idx % n_columns
            tortuosity_values[k, i, j] = 1.0
            continue
        
        # 提取当前分量的子邻接矩阵
        sub_adj = adj_matrix[comp_valid_indices][:, comp_valid_indices]
        
        # 计算分量内所有节点对的最短路径长度
        dist_matrix = dijkstra(sub_adj, directed=False, unweighted=True)
        
        # 找到每个节点的最大最短路径长度及对应最远节点
        max_dist = np.max(dist_matrix, axis=1)
        farthest_idx = np.argmax(dist_matrix, axis=1)
        
        # 计算欧氏直线距离
        node_coords = coords[comp_valid_indices]
        farthest_coords = node_coords[farthest_idx]
        euclid_dist = np.linalg.norm(node_coords - farthest_coords, axis=1)
        
        # 计算迂曲度(避免除零)
        tortuosity = np.where(euclid_dist > 1e-6, max_dist / euclid_dist, 1.0)
        
        # 赋值回3D数组
        for v_idx, g_idx in enumerate(comp_global_indices):
            k = g_idx // (n_rows * n_columns)
            i = (g_idx % (n_rows * n_columns)) // n_columns
            j = g_idx % n_columns
            tortuosity_values[k, i, j] = tortuosity[v_idx]
    
    return tortuosity_values

def main():
    # 生成测试数据
    porosity = np.random.rand(51, 125, 125)
    permeability = np.random.rand(51, 125, 125)
    
    # 计算连通性和迂曲度
    connectivity = calculate_connectivity(porosity, threshold=connectivity_threshold)
    tortuosity = calculate_tortuosity(permeability, porosity, threshold=tortuosity_threshold)
    
    # 保存结果
    np.save("tortuosity.npy", tortuosity)
    np.save("connectivity.npy", connectivity)

if __name__ == "__main__":
    main()

优化关键点说明

  1. 连通性计算修正:

    • 构建真正的3D邻接矩阵,包含层内水平邻接和层间垂直邻接,实现符合需求的3D空间连通分量分析。
    • 使用稀疏矩阵存储邻接关系,大幅减少内存占用(避免79万节点稠密矩阵的600GB内存需求)。
    • 用numpy向量化操作替代三重循环,提升邻接矩阵构建效率。
  2. 迂曲度计算优化:

    • 仅处理有效网格,减少计算规模。
    • 按连通分量拆分计算,避免全局处理大型图,降低单次计算复杂度。
    • 使用scipy底层C实现的dijkstra替代NetworkX的Python实现,性能提升几个数量级。
    • 修正迂曲度计算逻辑:采用最短路径长度与欧氏直线距离的比值,符合储层迂曲度的物理定义,避免原代码的除零错误。
  3. 内存优化:

    • 仅保留有效节点的坐标和邻接关系,减少不必要的内存占用。
    • 使用LIL→CSR的稀疏矩阵转换,兼顾构建效率和计算效率。

内容的提问来源于stack exchange,提问作者Skylimit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 08:18:09