import os import numpy as np import matplotlib.pyplot as plt import matplotlib.tri as mtri # 导入 build_graph 模块的函数和变量 from build_graph import ( scan_all_data, root_data_path, load_file_data, data_mapping ) # 从全局配置导入数据集配置,确保文件命名格式同步 from config import DATASET_TYPE, SCA_PREFIX # 注意:移除对save_test模块的导入以避免循环导入问题 # k值现在通过函数参数传递,而不是模块级变量 # 默认算例编号 DEFAULT_K = 8777 os.makedirs(root_data_path, exist_ok=True) def load_data(k, use_prediction=True): """ 加载数据用于可视化(使用与build_graph.py一致的文件读取方式) Args: k: 算例编号(全局索引) use_prediction: 如果True,加载预测结果,否则加载真实值(Esz) Returns: vertices: 节点坐标 [N, 2] triangles: 三角形索引 [M, 3] x_real: 实部 [N] x_imag: 虚部 [N] """ # 扫描数据并获取data_mapping data_mapping, n_total = scan_all_data(root_data_path) if k not in data_mapping: raise ValueError(f"索引 k={k} 超出范围 (总数据量: {n_total})") folder_path, folder_num, data_id = data_mapping[k] # 读取节点坐标(vertex文件) vertex_file = os.path.join(folder_path, f"vertex_{SCA_PREFIX}{folder_num}_{data_id}.txt") if not os.path.exists(vertex_file): raise FileNotFoundError(f"找不到节点坐标文件: {vertex_file}") vertices = np.loadtxt(vertex_file) # 读取三角形索引(tri文件) tri_file = os.path.join(folder_path, f"tri_{SCA_PREFIX}{folder_num}_{data_id}.txt") if not os.path.exists(tri_file): raise FileNotFoundError(f"找不到三角形索引文件: {tri_file}") triangles = np.loadtxt(tri_file, dtype=int) - 1 # MATLAB索引转Python索引 # 根据use_prediction选择加载预测结果或真实值 if use_prediction: # 加载预测结果 x_real_file = os.path.join(folder_path, f"Esz_pred_real_{SCA_PREFIX}{folder_num}_{data_id}.txt") x_imag_file = os.path.join(folder_path, f"Esz_pred_imag_{SCA_PREFIX}{folder_num}_{data_id}.txt") if not os.path.exists(x_real_file) or not os.path.exists(x_imag_file): raise FileNotFoundError(f"找不到预测结果文件: {x_real_file} 或 {x_imag_file}") x_real = np.loadtxt(x_real_file) x_imag = np.loadtxt(x_imag_file) else: # 加载真实值(使用build_graph的load_file_data函数) Esz_data = load_file_data(folder_path, "Esz", folder_num, data_id) x_real = Esz_data[:, 0] x_imag = Esz_data[:, 1] return vertices, triangles, x_real, x_imag def load_mesh_data(k): """ 只加载网格数据(节点坐标和三角形索引),不加载场数据 Args: k: 算例编号(全局索引) Returns: vertices: 节点坐标 [N, 2] triangles: 三角形索引 [M, 3] """ # 扫描数据并获取data_mapping data_mapping, n_total = scan_all_data(root_data_path) if k not in data_mapping: raise ValueError(f"索引 k={k} 超出范围 (总数据量: {n_total})") folder_path, folder_num, data_id = data_mapping[k] # 读取节点坐标(vertex文件) vertex_file = os.path.join(folder_path, f"vertex_{SCA_PREFIX}{folder_num}_{data_id}.txt") if not os.path.exists(vertex_file): raise FileNotFoundError(f"找不到节点坐标文件: {vertex_file}") vertices = np.loadtxt(vertex_file) # 读取三角形索引(tri文件) tri_file = os.path.join(folder_path, f"tri_{SCA_PREFIX}{folder_num}_{data_id}.txt") if not os.path.exists(tri_file): raise FileNotFoundError(f"找不到三角形索引文件: {tri_file}") triangles = np.loadtxt(tri_file, dtype=int) - 1 # MATLAB索引转Python索引 return vertices, triangles def visualize_solution(k, output_dir="/public/home/zzx/gnn/PhiSAGE/PhiSAGE/visualizations", use_prediction=True, save_combined=True, save_separate=False, custom_data=None, custom_filename=None): """ 可视化解的实部、虚部和模值场图 Args: k: 算例编号(全局索引) output_dir: 输出目录 use_prediction: 如果True,可视化预测结果,否则可视化真实值 save_combined: 是否保存包含三个子图的组合图 save_separate: 是否分别保存三个单独的图 custom_data: 自定义数据字典,包含'vertices', 'triangles', 'x_real', 'x_imag'键 custom_filename: 自定义文件名后缀,用于区分不同的迭代 """ if custom_data is not None: # 使用提供的自定义数据 vertices = custom_data['vertices'] triangles = custom_data['triangles'] x_real = custom_data['x_real'] x_imag = custom_data['x_imag'] else: # 从文件加载数据 vertices, triangles, x_real, x_imag = load_data(k, use_prediction=use_prediction) # 计算模值 x_complex = x_real + 1j * x_imag x_magnitude = np.abs(x_complex) # 创建输出目录 os.makedirs(output_dir, exist_ok=True) x_coord = vertices[:, 0] y_coord = vertices[:, 1] triang = mtri.Triangulation(x_coord, y_coord, triangles) # 确定数据标签(用于文件名和标题) if custom_filename is not None: data_label = custom_filename title_suffix = custom_filename else: data_label = "prediction" if use_prediction else "true" title_suffix = f"k={k}" # 方案1: 保存组合图(三个子图) if save_combined: fig, axes = plt.subplots(1, 3, figsize=(18, 6)) # 实部 tcf1 = axes[0].tricontourf(triang, x_real, levels=100, cmap='RdBu_r') cbar1 = fig.colorbar(tcf1, ax=axes[0]) cbar1.set_label('Re(u)', fontsize=12) axes[0].set_title(f'Real Part ({title_suffix})', fontsize=14, fontweight='bold') axes[0].set_aspect('equal') axes[0].set_xlim(x_coord.min(), x_coord.max()) axes[0].set_ylim(y_coord.min(), y_coord.max()) axes[0].set_xticks([]) axes[0].set_yticks([]) # 虚部 tcf2 = axes[1].tricontourf(triang, x_imag, levels=100, cmap='RdBu_r') cbar2 = fig.colorbar(tcf2, ax=axes[1]) cbar2.set_label('Im(u)', fontsize=12) axes[1].set_title(f'Imaginary Part ({title_suffix})', fontsize=14, fontweight='bold') axes[1].set_aspect('equal') axes[1].set_xlim(x_coord.min(), x_coord.max()) axes[1].set_ylim(y_coord.min(), y_coord.max()) axes[1].set_xticks([]) axes[1].set_yticks([]) # 模值 tcf3 = axes[2].tricontourf(triang, x_magnitude, levels=100, cmap='jet') cbar3 = fig.colorbar(tcf3, ax=axes[2]) cbar3.set_label('|u|', fontsize=12) axes[2].set_title(f'Magnitude ({title_suffix})', fontsize=14, fontweight='bold') axes[2].set_aspect('equal') axes[2].set_xlim(x_coord.min(), x_coord.max()) axes[2].set_ylim(y_coord.min(), y_coord.max()) axes[2].set_xticks([]) axes[2].set_yticks([]) plt.tight_layout() out_file_combined = os.path.join(output_dir, f"{data_label}_combined.png") plt.savefig(out_file_combined, dpi=300, bbox_inches='tight') plt.close() print(f"已保存组合图到: {out_file_combined}") # 方案2: 分别保存三个单独的图 if save_separate: # 实部 fig, ax = plt.subplots(figsize=(8, 8)) tcf = ax.tricontourf(triang, x_real, levels=100, cmap='RdBu_r') cbar = fig.colorbar(tcf, ax=ax) cbar.set_label('Re(u)', fontsize=14) ax.set_title(f'Real Part ({title_suffix})', fontsize=16, fontweight='bold') ax.set_aspect('equal') ax.set_xlim(x_coord.min(), x_coord.max()) ax.set_ylim(y_coord.min(), y_coord.max()) ax.set_xticks([]) ax.set_yticks([]) plt.tight_layout() out_file_real = os.path.join(output_dir, f"{data_label}_real.png") plt.savefig(out_file_real, dpi=300, bbox_inches='tight') plt.close() print(f"已保存实部图到: {out_file_real}") # 虚部 fig, ax = plt.subplots(figsize=(8, 8)) tcf = ax.tricontourf(triang, x_imag, levels=100, cmap='RdBu_r') cbar = fig.colorbar(tcf, ax=ax) cbar.set_label('Im(u)', fontsize=14) ax.set_title(f'Imaginary Part ({title_suffix})', fontsize=16, fontweight='bold') ax.set_aspect('equal') ax.set_xlim(x_coord.min(), x_coord.max()) ax.set_ylim(y_coord.min(), y_coord.max()) ax.set_xticks([]) ax.set_yticks([]) plt.tight_layout() out_file_imag = os.path.join(output_dir, f"{data_label}_imag.png") plt.savefig(out_file_imag, dpi=300, bbox_inches='tight') plt.close() print(f"已保存虚部图到: {out_file_imag}") # 模值 fig, ax = plt.subplots(figsize=(8, 8)) tcf = ax.tricontourf(triang, x_magnitude, levels=100, cmap='jet') cbar = fig.colorbar(tcf, ax=ax) cbar.set_label('|u|', fontsize=14) ax.set_title(f'Magnitude ({title_suffix})', fontsize=16, fontweight='bold') ax.set_aspect('equal') ax.set_xlim(x_coord.min(), x_coord.max()) ax.set_ylim(y_coord.min(), y_coord.max()) ax.set_xticks([]) ax.set_yticks([]) plt.tight_layout() out_file_mag = os.path.join(output_dir, f"{data_label}_magnitude.png") plt.savefig(out_file_mag, dpi=300, bbox_inches='tight') plt.close() print(f"已保存模值图到: {out_file_mag}") if __name__ == "__main__": # 可视化指定算例 # 尝试从 save_test 模块读取 k 值,避免循环导入 try: # 使用动态导入来避免启动时的循环导入问题 import sys if 'save_test' in sys.modules: save_test_module = sys.modules['save_test'] current_k = getattr(save_test_module, 'k', DEFAULT_K) print(f"从已加载的 save_test 模块读取到 k={current_k}") else: current_k = DEFAULT_K print(f"save_test 模块未加载,使用默认 k={current_k}") except Exception as e: current_k = DEFAULT_K print(f"读取 k 值失败: {e},使用默认 k={current_k}") # 可视化预测结果(默认) print(f"正在可视化算例 k={current_k} 的预测结果...") visualize_solution(k=current_k, use_prediction=True, save_combined=True, save_separate=False) # 可选:同时可视化真实值进行对比 print(f"正在可视化算例 k={current_k} 的真实值...") visualize_solution(k=current_k, use_prediction=False, save_combined=True, save_separate=False)