Untitled

 avatar
unknown
python
2 months ago
7.2 kB
3
Indexable
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

class HeatConduction3D:
    def __init__(self, nx=20, ny=20, nz=20, dx=0.01, dy=0.01, dz=0.01, 
                 k=0.5, density=1000, specific_heat=4186, 
                 T_hot=100, T_init=20):
        self.nx, self.ny, self.nz = nx, ny, nz
        self.dx, self.dy, self.dz = dx, dy, dz
        
        # 材料物理参数
        self.k = k                  # 热导率 (W/(m·K))
        self.density = density      # 密度 (kg/m³)
        self.specific_heat = specific_heat  # 比热容 (J/(kg·K))
        
        # 计算热扩散系数
        self.alpha = k / (density * specific_heat)
        
        # 根据热导率调整时间步长
        dx_min = min(dx, dy, dz)
        if k > 100:
            self.dt = 0.15 * dx_min**2 / (6 * self.alpha)  # 高导热材料
        elif k > 10:
            self.dt = 0.25 * dx_min**2 / (6 * self.alpha)  # 中等导热材料
        else:
            self.dt = 0.35 * dx_min**2 / (6 * self.alpha)  # 低导热材料
        
        self.T_hot = T_hot
        self.T_init = T_init
        self.current_step = 0
        
        # 初始化温度场
        self.T = np.ones((nx, ny, nz)) * T_init
        self.T[0, :, :] = T_hot  # 左面加热
        
        # 创建3D图形
        self.fig = plt.figure(figsize=(8, 6))
        self.ax = self.fig.add_subplot(111, projection='3d')
        
        # 预先创建体素网格
        self.voxel_grid = np.ones((nx-1, ny-1, nz-1), dtype=bool)
        
        # 设置初始视角
        self.ax.view_init(elev=20, azim=45)
        
        # 创建颜色映射
        self.cmap = plt.cm.plasma
        self.norm = mpl.colors.Normalize(vmin=self.T_init, vmax=self.T_hot)
        
        # 添加实际时间计数器
        self.real_time = 0.0  # 实际时间(秒)

    def step(self):
        """使用向量化运算计算温度场演化"""
        T_new = np.copy(self.T)
        T_new[1:-1, 1:-1, 1:-1] += self.alpha * self.dt * (
            (self.T[2:, 1:-1, 1:-1] + self.T[:-2, 1:-1, 1:-1] +
             self.T[1:-1, 2:, 1:-1] + self.T[1:-1, :-2, 1:-1] +
             self.T[1:-1, 1:-1, 2:] + self.T[1:-1, 1:-1, :-2] -
             6 * self.T[1:-1, 1:-1, 1:-1]) / (self.dx**2)
        )
        
        # 应用边界条件
        T_new[0, :, :] = self.T_hot
        T_new[-1, :, :] = T_new[-2, :, :]
        T_new[:, 0, :] = T_new[:, 1, :]
        T_new[:, -1, :] = T_new[:, -2, :]
        T_new[:, :, 0] = T_new[:, :, 1]
        T_new[:, :, -1] = T_new[:, :, -2]
        
        self.T = T_new
        self.real_time += self.dt  # 更新实际时间
        self.current_step += 1

    def update(self, frame):
        """更新动画帧"""
        # 增加每帧的计算步数
        for _ in range(5):  # 从2增加到5
            self.step()
        
        # 清除之前的图像
        self.ax.clear()
        
        # 创建颜色数组
        colors = self.cmap(self.norm(self.T[:-1, :-1, :-1]))
        
        # 绘制体素(降低透明度以提高性能)
        self.ax.voxels(self.voxel_grid,
                      facecolors=colors,
                      alpha=0.6)
        
        # 设置坐标轴范围和标签
        self.ax.set_xlim(0, self.nx-1)
        self.ax.set_ylim(0, self.ny-1)
        self.ax.set_zlim(0, self.nz-1)
        self.ax.set_xlabel('X 方向')
        self.ax.set_ylabel('Y 方向')
        self.ax.set_zlabel('Z 方向')
        self.ax.set_title(f'三维温度分布 (时间步:{self.current_step})\n热导率:{self.k} W/(m·K)')
        
        # 添加颜色条
        if not hasattr(self, 'cbar'):
            sm = plt.cm.ScalarMappable(cmap=self.cmap, norm=self.norm)
            self.cbar = self.fig.colorbar(sm, ax=self.ax, label='温度 (°C)')
        
        return []

def main():
    # 创建不同材料的模拟实例
    # 示例材料的热导率(W/(m·K)):
    # 铜: 385
    # 铝: 237
    # 铁: 80.2
    # 不锈钢: 16.2
    # 水: 0.6
    # 空气: 0.026
    
    # 选择材料的热导率
    k = float(input("请输入材料的热导率 (W/(m·K)): "))
    
    # 统一网格大小
    nx, ny, nz = 20, 20, 20  # 统一使用20x20x20的网格
    
    # 根据热导率仅调整计算参数
    if k > 100:
        frames = 50
        interval = 20
        steps_per_frame = 12
    elif k > 10:
        frames = 80
        interval = 25
        steps_per_frame = 8
    else:
        frames = 120
        interval = 30
        steps_per_frame = 4
    
    heat_model = HeatConduction3D(
        nx=nx,
        ny=ny,
        nz=nz,
        dx=0.005,
        dy=0.005,
        dz=0.005,
        k=k,
        density=1000,
        specific_heat=4186
    )
    
    # 修改custom_update函数中的视角设置
    def custom_update(frame):
        # 根据热导率使用不同的计算步数
        for _ in range(steps_per_frame):
            heat_model.step()
        
        # 清除之前的图像
        heat_model.ax.clear()
        
        # 创建颜色数组
        colors = heat_model.cmap(heat_model.norm(heat_model.T[:-1, :-1, :-1]))
        
        # 绘制体素
        heat_model.ax.voxels(heat_model.voxel_grid,
                          facecolors=colors,
                          alpha=0.6)
        
        # 设置坐标轴范围和标签
        heat_model.ax.set_xlim(0, heat_model.nx-1)
        heat_model.ax.set_ylim(0, heat_model.ny-1)
        heat_model.ax.set_zlim(0, heat_model.nz-1)
        heat_model.ax.set_xlabel('X 方向')
        heat_model.ax.set_ylabel('Y 方向')
        heat_model.ax.set_zlabel('Z 方向')
        
        # 更新标题,添加实际时间信息
        heat_model.ax.set_title(
            f'三维温度分布\n'
            f'热导率:{heat_model.k:.1f} W/(m·K)\n'
            f'模拟时间:{heat_model.real_time:.3f} 秒'
        )
        
        # 添加颜色条
        if not hasattr(heat_model, 'cbar'):
            sm = plt.cm.ScalarMappable(cmap=heat_model.cmap, norm=heat_model.norm)
            heat_model.cbar = heat_model.fig.colorbar(sm, ax=heat_model.ax, label='温度 (°C)')
        
        # 保持固定视角
        heat_model.ax.view_init(elev=20, azim=45)
        
        # 添加计时器文本(在图形右上角)
        plt.figtext(
            0.98, 0.98,
            f'计算步数:{heat_model.current_step}\n'
            f'每帧步数:{steps_per_frame}\n'
            f'时间步长:{heat_model.dt:.2e} 秒',
            ha='right', va='top',
            bbox=dict(facecolor='white', alpha=0.8, edgecolor='none')
        )
        
        return []
    
    # 创建动画
    anim = FuncAnimation(
        heat_model.fig, 
        custom_update,
        frames=frames,
        interval=interval,
        blit=False
    )
    
    # 启用鼠标交互
    plt.rcParams['axes.prop_cycle'] = plt.cycler('color', ['r'])
    heat_model.ax.mouse_init()
    
    plt.show()

if __name__ == "__main__":
    main() 
Leave a Comment