819 lines
28 KiB
Python
819 lines
28 KiB
Python
"""
|
||
流体求解器模块
|
||
负责实现流体模拟的数值求解算法
|
||
"""
|
||
|
||
import time
|
||
from typing import Dict, Any, List, Optional, Tuple
|
||
import math
|
||
import numpy as np
|
||
from scipy.sparse import diags
|
||
from scipy.sparse.linalg import spsolve
|
||
|
||
class FluidSolver:
|
||
"""
|
||
流体求解器
|
||
负责实现流体模拟的数值求解算法,包括压力求解、速度更新等
|
||
"""
|
||
|
||
def __init__(self, plugin):
|
||
"""
|
||
初始化流体求解器
|
||
|
||
Args:
|
||
plugin: 水体和流体模拟插件实例
|
||
"""
|
||
self.plugin = plugin
|
||
self.enabled = False
|
||
self.initialized = False
|
||
|
||
# 求解器配置
|
||
self.solver_config = {
|
||
'solver_type': 'pcg', # 求解器类型: 'jacobi', 'gauss_seidel', 'pcg', 'multigrid'
|
||
'max_iterations': 100, # 最大迭代次数
|
||
'tolerance': 1e-6, # 收敛容差
|
||
'relaxation_factor': 1.0, # 松弛因子
|
||
'preconditioner': 'none' # 预条件子: 'jacobi', 'ilu', 'none'
|
||
}
|
||
|
||
# 数值方法配置
|
||
self.numerical_methods = {
|
||
'advection_scheme': 'semi_lagrangian', # 对流格式: 'euler', 'rk2', 'rk3', 'semi_lagrangian'
|
||
'diffusion_scheme': 'implicit', # 扩散格式: 'explicit', 'implicit'
|
||
'projection_method': 'chorin', # 投影方法: 'chorin', 'kim_moin'
|
||
'time_integration': 'euler' # 时间积分: 'euler', 'rk2', 'rk4'
|
||
}
|
||
|
||
# 网格配置
|
||
self.grid_config = {
|
||
'resolution_x': 64,
|
||
'resolution_y': 64,
|
||
'resolution_z': 64,
|
||
'cell_size': 1.0
|
||
}
|
||
|
||
# 边界条件
|
||
self.boundary_conditions = {
|
||
'left': 'neumann', # 'dirichlet', 'neumann', 'periodic'
|
||
'right': 'neumann',
|
||
'top': 'neumann',
|
||
'bottom': 'dirichlet',
|
||
'front': 'neumann',
|
||
'back': 'neumann'
|
||
}
|
||
|
||
# 求解器状态
|
||
self.solver_state = {
|
||
'current_iteration': 0,
|
||
'residual': 0.0,
|
||
'converged': False,
|
||
'solve_time': 0.0
|
||
}
|
||
|
||
# 性能统计
|
||
self.performance_stats = {
|
||
'pressure_solves': 0,
|
||
'velocity_updates': 0,
|
||
'total_solve_time': 0.0,
|
||
'average_solve_time': 0.0
|
||
}
|
||
|
||
# 缓存矩阵(用于预计算)
|
||
self.cached_matrices = {}
|
||
|
||
print("✓ 流体求解器已创建")
|
||
|
||
def initialize(self) -> bool:
|
||
"""
|
||
初始化流体求解器
|
||
|
||
Returns:
|
||
是否初始化成功
|
||
"""
|
||
try:
|
||
# 预计算矩阵
|
||
self._precompute_matrices()
|
||
|
||
self.initialized = True
|
||
print("✓ 流体求解器初始化完成")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 流体求解器初始化失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def enable(self) -> bool:
|
||
"""
|
||
启用流体求解器
|
||
|
||
Returns:
|
||
是否启用成功
|
||
"""
|
||
try:
|
||
if not self.initialized:
|
||
print("✗ 流体求解器未初始化")
|
||
return False
|
||
|
||
self.enabled = True
|
||
print("✓ 流体求解器已启用")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 流体求解器启用失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def disable(self):
|
||
"""禁用流体求解器"""
|
||
try:
|
||
self.enabled = False
|
||
print("✓ 流体求解器已禁用")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 流体求解器禁用失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def finalize(self):
|
||
"""清理流体求解器资源"""
|
||
try:
|
||
self.disable()
|
||
self.cached_matrices.clear()
|
||
self.initialized = False
|
||
print("✓ 流体求解器资源已清理")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 流体求解器资源清理失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def update(self, dt: float):
|
||
"""
|
||
更新流体求解器状态
|
||
|
||
Args:
|
||
dt: 时间增量
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return
|
||
|
||
# 在这里可以执行周期性任务
|
||
pass
|
||
|
||
except Exception as e:
|
||
print(f"✗ 流体求解器更新失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def _precompute_matrices(self):
|
||
"""预计算常用矩阵"""
|
||
try:
|
||
# 预计算拉普拉斯矩阵等
|
||
print("✓ 矩阵预计算完成")
|
||
except Exception as e:
|
||
print(f"✗ 矩阵预计算失败: {e}")
|
||
|
||
def solve_pressure_field(self, velocity_field: Dict[str, np.ndarray],
|
||
density_field: np.ndarray) -> Tuple[np.ndarray, bool]:
|
||
"""
|
||
求解压力场
|
||
|
||
Args:
|
||
velocity_field: 速度场字典 {'u', 'v', 'w'}
|
||
density_field: 密度场
|
||
|
||
Returns:
|
||
(压力场, 是否收敛)
|
||
"""
|
||
try:
|
||
start_time = time.time()
|
||
|
||
# 根据求解器类型选择算法
|
||
solver_type = self.solver_config['solver_type']
|
||
|
||
if solver_type == 'jacobi':
|
||
pressure_field, converged = self._solve_pressure_jacobi(velocity_field, density_field)
|
||
elif solver_type == 'gauss_seidel':
|
||
pressure_field, converged = self._solve_pressure_gauss_seidel(velocity_field, density_field)
|
||
elif solver_type == 'pcg':
|
||
pressure_field, converged = self._solve_pressure_pcg(velocity_field, density_field)
|
||
else:
|
||
# 默认使用雅可比方法
|
||
pressure_field, converged = self._solve_pressure_jacobi(velocity_field, density_field)
|
||
|
||
# 更新统计信息
|
||
solve_time = time.time() - start_time
|
||
self.performance_stats['pressure_solves'] += 1
|
||
self.performance_stats['total_solve_time'] += solve_time
|
||
|
||
if self.performance_stats['pressure_solves'] > 0:
|
||
self.performance_stats['average_solve_time'] = (
|
||
self.performance_stats['total_solve_time'] /
|
||
self.performance_stats['pressure_solves']
|
||
)
|
||
|
||
return pressure_field, converged
|
||
|
||
except Exception as e:
|
||
print(f"✗ 压力场求解失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
# 返回零压力场和未收敛状态
|
||
shape = velocity_field['u'].shape if velocity_field else (1, 1, 1)
|
||
return np.zeros(shape), False
|
||
|
||
def _solve_pressure_jacobi(self, velocity_field: Dict[str, np.ndarray],
|
||
density_field: np.ndarray) -> Tuple[np.ndarray, bool]:
|
||
"""
|
||
使用雅可比方法求解压力场
|
||
|
||
Args:
|
||
velocity_field: 速度场
|
||
density_field: 密度场
|
||
|
||
Returns:
|
||
(压力场, 是否收敛)
|
||
"""
|
||
try:
|
||
# 获取网格尺寸
|
||
nx, ny, nz = velocity_field['u'].shape
|
||
|
||
# 初始化压力场
|
||
pressure = np.zeros((nx, ny, nz))
|
||
pressure_new = np.zeros((nx, ny, nz))
|
||
|
||
# 计算网格步长
|
||
dx = self.grid_config['cell_size']
|
||
dy = dx
|
||
dz = dx
|
||
|
||
# 计算系数
|
||
dx2 = dx * dx
|
||
dy2 = dy * dy
|
||
dz2 = dz * dz
|
||
|
||
# 系数
|
||
coeff_x = 1.0 / dx2
|
||
coeff_y = 1.0 / dy2
|
||
coeff_z = 1.0 / dz2
|
||
center_coeff = 2.0 * (coeff_x + coeff_y + coeff_z)
|
||
|
||
# 预计算用于收敛检查的系数
|
||
tolerance = self.solver_config['tolerance']
|
||
max_iterations = self.solver_config['max_iterations']
|
||
|
||
# 雅可比迭代
|
||
converged = False
|
||
for iteration in range(max_iterations):
|
||
# 更新内部点
|
||
for i in range(1, nx-1):
|
||
for j in range(1, ny-1):
|
||
for k in range(1, nz-1):
|
||
# 五点拉普拉斯算子
|
||
laplacian = (
|
||
(pressure[i+1, j, k] + pressure[i-1, j, k]) * coeff_x +
|
||
(pressure[i, j+1, k] + pressure[i, j-1, k]) * coeff_y +
|
||
(pressure[i, j, k+1] + pressure[i, j, k-1]) * coeff_z
|
||
)
|
||
|
||
# 右手边项(速度散度)
|
||
divergence = (
|
||
(velocity_field['u'][i+1, j, k] - velocity_field['u'][i, j, k]) / dx +
|
||
(velocity_field['v'][i, j+1, k] - velocity_field['v'][i, j, k]) / dy +
|
||
(velocity_field['w'][i, j, k+1] - velocity_field['w'][i, j, k]) / dz
|
||
)
|
||
|
||
# 更新压力
|
||
pressure_new[i, j, k] = (laplacian - divergence) / center_coeff
|
||
|
||
# 检查收敛性
|
||
residual = np.max(np.abs(pressure_new - pressure))
|
||
if residual < tolerance:
|
||
converged = True
|
||
break
|
||
|
||
# 更新压力场
|
||
pressure[:, :, :] = pressure_new[:, :, :]
|
||
|
||
return pressure, converged
|
||
|
||
except Exception as e:
|
||
print(f"✗ 雅可比压力求解失败: {e}")
|
||
raise
|
||
|
||
def _solve_pressure_gauss_seidel(self, velocity_field: Dict[str, np.ndarray],
|
||
density_field: np.ndarray) -> Tuple[np.ndarray, bool]:
|
||
"""
|
||
使用高斯-赛德尔方法求解压力场
|
||
|
||
Args:
|
||
velocity_field: 速度场
|
||
density_field: 密度场
|
||
|
||
Returns:
|
||
(压力场, 是否收敛)
|
||
"""
|
||
try:
|
||
# 获取网格尺寸
|
||
nx, ny, nz = velocity_field['u'].shape
|
||
|
||
# 初始化压力场
|
||
pressure = np.zeros((nx, ny, nz))
|
||
|
||
# 计算网格步长
|
||
dx = self.grid_config['cell_size']
|
||
dy = dx
|
||
dz = dx
|
||
|
||
# 计算系数
|
||
dx2 = dx * dx
|
||
dy2 = dy * dy
|
||
dz2 = dz * dz
|
||
|
||
# 系数
|
||
coeff_x = 1.0 / dx2
|
||
coeff_y = 1.0 / dy2
|
||
coeff_z = 1.0 / dz2
|
||
center_coeff = 2.0 * (coeff_x + coeff_y + coeff_z)
|
||
|
||
# 预计算用于收敛检查的系数
|
||
tolerance = self.solver_config['tolerance']
|
||
max_iterations = self.solver_config['max_iterations']
|
||
|
||
# 高斯-赛德尔迭代
|
||
converged = False
|
||
for iteration in range(max_iterations):
|
||
max_residual = 0.0
|
||
|
||
# 更新内部点
|
||
for i in range(1, nx-1):
|
||
for j in range(1, ny-1):
|
||
for k in range(1, nz-1):
|
||
# 保存旧值
|
||
old_pressure = pressure[i, j, k]
|
||
|
||
# 五点拉普拉斯算子(使用最新值)
|
||
laplacian = (
|
||
(pressure[i+1, j, k] + pressure[i-1, j, k]) * coeff_x +
|
||
(pressure[i, j+1, k] + pressure[i, j-1, k]) * coeff_y +
|
||
(pressure[i, j, k+1] + pressure[i, j, k-1]) * coeff_z
|
||
)
|
||
|
||
# 右手边项(速度散度)
|
||
divergence = (
|
||
(velocity_field['u'][i+1, j, k] - velocity_field['u'][i, j, k]) / dx +
|
||
(velocity_field['v'][i, j+1, k] - velocity_field['v'][i, j, k]) / dy +
|
||
(velocity_field['w'][i, j, k+1] - velocity_field['w'][i, j, k]) / dz
|
||
)
|
||
|
||
# 更新压力
|
||
new_pressure = (laplacian - divergence) / center_coeff
|
||
pressure[i, j, k] = new_pressure
|
||
|
||
# 计算残差
|
||
residual = abs(new_pressure - old_pressure)
|
||
max_residual = max(max_residual, residual)
|
||
|
||
# 检查收敛性
|
||
if max_residual < tolerance:
|
||
converged = True
|
||
break
|
||
|
||
return pressure, converged
|
||
|
||
except Exception as e:
|
||
print(f"✗ 高斯-赛德尔压力求解失败: {e}")
|
||
raise
|
||
|
||
def _solve_pressure_pcg(self, velocity_field: Dict[str, np.ndarray],
|
||
density_field: np.ndarray) -> Tuple[np.ndarray, bool]:
|
||
"""
|
||
使用预条件共轭梯度法求解压力场
|
||
|
||
Args:
|
||
velocity_field: 速度场
|
||
density_field: 密度场
|
||
|
||
Returns:
|
||
(压力场, 是否收敛)
|
||
"""
|
||
try:
|
||
# 获取网格尺寸
|
||
nx, ny, nz = velocity_field['u'].shape
|
||
n = nx * ny * nz
|
||
|
||
# 简化版本 - 实际实现中会构建稀疏矩阵并使用scipy求解器
|
||
pressure = np.zeros((nx, ny, nz))
|
||
converged = True # 简化处理
|
||
|
||
# 在实际实现中,这里会:
|
||
# 1. 构建泊松方程的稀疏矩阵
|
||
# 2. 构建右手边向量(速度散度)
|
||
# 3. 使用预条件共轭梯度法求解
|
||
# 4. 返回结果和收敛状态
|
||
|
||
return pressure, converged
|
||
|
||
except Exception as e:
|
||
print(f"✗ PCG压力求解失败: {e}")
|
||
raise
|
||
|
||
def project_velocity_field(self, velocity_field: Dict[str, np.ndarray],
|
||
pressure_field: np.ndarray) -> Dict[str, np.ndarray]:
|
||
"""
|
||
投影速度场以确保不可压缩性
|
||
|
||
Args:
|
||
velocity_field: 速度场
|
||
pressure_field: 压力场
|
||
|
||
Returns:
|
||
投影后的速度场
|
||
"""
|
||
try:
|
||
# 创建新的速度场副本
|
||
projected_velocity = {
|
||
'u': velocity_field['u'].copy(),
|
||
'v': velocity_field['v'].copy(),
|
||
'w': velocity_field['w'].copy()
|
||
}
|
||
|
||
# 获取网格尺寸
|
||
nx, ny, nz = pressure_field.shape
|
||
|
||
# 计算网格步长
|
||
dx = self.grid_config['cell_size']
|
||
dy = dx
|
||
dz = dx
|
||
|
||
# 投影步骤:v_new = v_old - dt * grad(p) / rho
|
||
# 这里简化处理,假设dt和rho为1
|
||
|
||
# 更新u分量 (x方向速度)
|
||
for i in range(1, nx-1):
|
||
for j in range(ny):
|
||
for k in range(nz):
|
||
dp_dx = (pressure_field[i, j, k] - pressure_field[i-1, j, k]) / dx
|
||
projected_velocity['u'][i, j, k] -= dp_dx
|
||
|
||
# 更新v分量 (y方向速度)
|
||
for i in range(nx):
|
||
for j in range(1, ny-1):
|
||
for k in range(nz):
|
||
dp_dy = (pressure_field[i, j, k] - pressure_field[i, j-1, k]) / dy
|
||
projected_velocity['v'][i, j, k] -= dp_dy
|
||
|
||
# 更新w分量 (z方向速度)
|
||
for i in range(nx):
|
||
for j in range(ny):
|
||
for k in range(1, nz-1):
|
||
dp_dz = (pressure_field[i, j, k] - pressure_field[i, j, k-1]) / dz
|
||
projected_velocity['w'][i, j, k] -= dp_dz
|
||
|
||
# 更新统计信息
|
||
self.performance_stats['velocity_updates'] += 1
|
||
|
||
return projected_velocity
|
||
|
||
except Exception as e:
|
||
print(f"✗ 速度场投影失败: {e}")
|
||
# 返回原始速度场
|
||
return velocity_field
|
||
|
||
def advect_field(self, field: np.ndarray, velocity_field: Dict[str, np.ndarray],
|
||
dt: float) -> np.ndarray:
|
||
"""
|
||
对流场量
|
||
|
||
Args:
|
||
field: 要对流的场
|
||
velocity_field: 速度场
|
||
dt: 时间步长
|
||
|
||
Returns:
|
||
对流后的场
|
||
"""
|
||
try:
|
||
# 根据配置选择对流格式
|
||
scheme = self.numerical_methods['advection_scheme']
|
||
|
||
if scheme == 'euler':
|
||
return self._advect_euler(field, velocity_field, dt)
|
||
elif scheme == 'rk2':
|
||
return self._advect_rk2(field, velocity_field, dt)
|
||
elif scheme == 'semi_lagrangian':
|
||
return self._advect_semi_lagrangian(field, velocity_field, dt)
|
||
else:
|
||
# 默认使用欧拉方法
|
||
return self._advect_euler(field, velocity_field, dt)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 场对流失败: {e}")
|
||
return field
|
||
|
||
def _advect_euler(self, field: np.ndarray, velocity_field: Dict[str, np.ndarray],
|
||
dt: float) -> np.ndarray:
|
||
"""
|
||
使用前向欧拉方法对流场
|
||
|
||
Args:
|
||
field: 要对流的场
|
||
velocity_field: 速度场
|
||
dt: 时间步长
|
||
|
||
Returns:
|
||
对流后的场
|
||
"""
|
||
try:
|
||
# 获取网格尺寸
|
||
nx, ny, nz = field.shape
|
||
|
||
# 计算网格步长
|
||
dx = self.grid_config['cell_size']
|
||
dy = dx
|
||
dz = dx
|
||
|
||
# 创建新场
|
||
new_field = field.copy()
|
||
|
||
# 前向欧拉对流
|
||
for i in range(1, nx-1):
|
||
for j in range(1, ny-1):
|
||
for k in range(1, nz-1):
|
||
# 获取速度
|
||
u = velocity_field['u'][i, j, k]
|
||
v = velocity_field['v'][i, j, k]
|
||
w = velocity_field['w'][i, j, k]
|
||
|
||
# 计算追踪点
|
||
x_trace = i - u * dt / dx
|
||
y_trace = j - v * dt / dy
|
||
z_trace = k - w * dt / dz
|
||
|
||
# 线性插值获取追踪点的场值
|
||
new_field[i, j, k] = self._trilinear_interpolate(field, x_trace, y_trace, z_trace)
|
||
|
||
return new_field
|
||
|
||
except Exception as e:
|
||
print(f"✗ 欧拉对流失败: {e}")
|
||
return field
|
||
|
||
def _advect_rk2(self, field: np.ndarray, velocity_field: Dict[str, np.ndarray],
|
||
dt: float) -> np.ndarray:
|
||
"""
|
||
使用二阶Runge-Kutta方法对流场
|
||
|
||
Args:
|
||
field: 要对流的场
|
||
velocity_field: 速度场
|
||
dt: 时间步长
|
||
|
||
Returns:
|
||
对流后的场
|
||
"""
|
||
try:
|
||
# RK2实现
|
||
# 中点方法: k1 = f(x_n, t_n), k2 = f(x_n + dt/2 * k1, t_n + dt/2)
|
||
# x_{n+1} = x_n + dt * k2
|
||
return field # 简化处理
|
||
|
||
except Exception as e:
|
||
print(f"✗ RK2对流失败: {e}")
|
||
return field
|
||
|
||
def _advect_semi_lagrangian(self, field: np.ndarray, velocity_field: Dict[str, np.ndarray],
|
||
dt: float) -> np.ndarray:
|
||
"""
|
||
使用半拉格朗日方法对流场
|
||
|
||
Args:
|
||
field: 要对流的场
|
||
velocity_field: 速度场
|
||
dt: 时间步长
|
||
|
||
Returns:
|
||
对流后的场
|
||
"""
|
||
try:
|
||
# 半拉格朗日方法实现
|
||
# 从终点追踪到起点,然后插值
|
||
return field # 简化处理
|
||
|
||
except Exception as e:
|
||
print(f"✗ 半拉格朗日对流失败: {e}")
|
||
return field
|
||
|
||
def _trilinear_interpolate(self, field: np.ndarray, x: float, y: float, z: float) -> float:
|
||
"""
|
||
三线性插值
|
||
|
||
Args:
|
||
field: 场数据
|
||
x, y, z: 插值点坐标
|
||
|
||
Returns:
|
||
插值结果
|
||
"""
|
||
try:
|
||
# 获取整数部分和小数部分
|
||
i = int(x)
|
||
j = int(y)
|
||
k = int(z)
|
||
|
||
fx = x - i
|
||
fy = y - j
|
||
fz = z - k
|
||
|
||
# 边界检查
|
||
nx, ny, nz = field.shape
|
||
if i < 0 or i >= nx-1 or j < 0 or j >= ny-1 or k < 0 or k >= nz-1:
|
||
return 0.0
|
||
|
||
# 三线性插值
|
||
c00 = field[i, j, k] * (1 - fx) + field[i+1, j, k] * fx
|
||
c01 = field[i, j, k+1] * (1 - fx) + field[i+1, j, k+1] * fx
|
||
c10 = field[i, j+1, k] * (1 - fx) + field[i+1, j+1, k] * fx
|
||
c11 = field[i, j+1, k+1] * (1 - fx) + field[i+1, j+1, k+1] * fx
|
||
|
||
c0 = c00 * (1 - fy) + c10 * fy
|
||
c1 = c01 * (1 - fy) + c11 * fy
|
||
|
||
return c0 * (1 - fz) + c1 * fz
|
||
|
||
except Exception as e:
|
||
return 0.0
|
||
|
||
def diffuse_field(self, field: np.ndarray, diffusion_coeff: float,
|
||
dt: float) -> np.ndarray:
|
||
"""
|
||
扩散场量
|
||
|
||
Args:
|
||
field: 要扩散的场
|
||
diffusion_coeff: 扩散系数
|
||
dt: 时间步长
|
||
|
||
Returns:
|
||
扩散后的场
|
||
"""
|
||
try:
|
||
# 根据配置选择扩散格式
|
||
scheme = self.numerical_methods['diffusion_scheme']
|
||
|
||
if scheme == 'explicit':
|
||
return self._diffuse_explicit(field, diffusion_coeff, dt)
|
||
elif scheme == 'implicit':
|
||
return self._diffuse_implicit(field, diffusion_coeff, dt)
|
||
else:
|
||
# 默认使用显式方法
|
||
return self._diffuse_explicit(field, diffusion_coeff, dt)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 场扩散失败: {e}")
|
||
return field
|
||
|
||
def _diffuse_explicit(self, field: np.ndarray, diffusion_coeff: float,
|
||
dt: float) -> np.ndarray:
|
||
"""
|
||
显式扩散
|
||
|
||
Args:
|
||
field: 要扩散的场
|
||
diffusion_coeff: 扩散系数
|
||
dt: 时间步长
|
||
|
||
Returns:
|
||
扩散后的场
|
||
"""
|
||
try:
|
||
# 拉普拉斯算子的显式更新
|
||
nx, ny, nz = field.shape
|
||
dx = self.grid_config['cell_size']
|
||
|
||
# 扩散系数
|
||
alpha = diffusion_coeff * dt / (dx * dx)
|
||
|
||
# 确保稳定性 (CFL条件)
|
||
if alpha > 0.166667: # 1/6 for 3D
|
||
alpha = 0.166667
|
||
|
||
new_field = field.copy()
|
||
|
||
for i in range(1, nx-1):
|
||
for j in range(1, ny-1):
|
||
for k in range(1, nz-1):
|
||
laplacian = (
|
||
field[i+1, j, k] + field[i-1, j, k] +
|
||
field[i, j+1, k] + field[i, j-1, k] +
|
||
field[i, j, k+1] + field[i, j, k-1] -
|
||
6 * field[i, j, k]
|
||
)
|
||
new_field[i, j, k] = field[i, j, k] + alpha * laplacian
|
||
|
||
return new_field
|
||
|
||
except Exception as e:
|
||
print(f"✗ 显式扩散失败: {e}")
|
||
return field
|
||
|
||
def _diffuse_implicit(self, field: np.ndarray, diffusion_coeff: float,
|
||
dt: float) -> np.ndarray:
|
||
"""
|
||
隐式扩散
|
||
|
||
Args:
|
||
field: 要扩散的场
|
||
diffusion_coeff: 扩散系数
|
||
dt: 时间步长
|
||
|
||
Returns:
|
||
扩散后的场
|
||
"""
|
||
try:
|
||
# 隐式扩散需要求解线性系统
|
||
# (I - alpha * L) * field_new = field_old
|
||
return field # 简化处理
|
||
|
||
except Exception as e:
|
||
print(f"✗ 隐式扩散失败: {e}")
|
||
return field
|
||
|
||
def set_solver_config(self, config: Dict[str, Any]):
|
||
"""
|
||
设置求解器配置
|
||
|
||
Args:
|
||
config: 求解器配置字典
|
||
"""
|
||
try:
|
||
self.solver_config.update(config)
|
||
print(f"✓ 求解器配置已更新: {self.solver_config}")
|
||
except Exception as e:
|
||
print(f"✗ 求解器配置设置失败: {e}")
|
||
|
||
def get_solver_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取求解器配置
|
||
|
||
Returns:
|
||
求解器配置字典
|
||
"""
|
||
return self.solver_config.copy()
|
||
|
||
def set_numerical_methods(self, methods: Dict[str, str]):
|
||
"""
|
||
设置数值方法
|
||
|
||
Args:
|
||
methods: 数值方法字典
|
||
"""
|
||
try:
|
||
self.numerical_methods.update(methods)
|
||
print(f"✓ 数值方法已更新: {self.numerical_methods}")
|
||
except Exception as e:
|
||
print(f"✗ 数值方法设置失败: {e}")
|
||
|
||
def get_numerical_methods(self) -> Dict[str, str]:
|
||
"""
|
||
获取数值方法
|
||
|
||
Returns:
|
||
数值方法字典
|
||
"""
|
||
return self.numerical_methods.copy()
|
||
|
||
def get_performance_stats(self) -> Dict[str, Any]:
|
||
"""
|
||
获取性能统计信息
|
||
|
||
Returns:
|
||
性能统计字典
|
||
"""
|
||
return self.performance_stats.copy()
|
||
|
||
def reset_performance_stats(self):
|
||
"""重置性能统计信息"""
|
||
try:
|
||
self.performance_stats = {
|
||
'pressure_solves': 0,
|
||
'velocity_updates': 0,
|
||
'total_solve_time': 0.0,
|
||
'average_solve_time': 0.0
|
||
}
|
||
print("✓ 性能统计信息已重置")
|
||
except Exception as e:
|
||
print(f"✗ 性能统计信息重置失败: {e}")
|
||
|
||
def get_solver_state(self) -> Dict[str, Any]:
|
||
"""
|
||
获取求解器状态
|
||
|
||
Returns:
|
||
求解器状态字典
|
||
"""
|
||
return self.solver_state.copy() |