707 lines
22 KiB
Python
707 lines
22 KiB
Python
"""
|
|
流体动力学模块
|
|
负责实现流体的基本物理模拟和动力学计算
|
|
"""
|
|
|
|
import time
|
|
from typing import Dict, Any, List, Optional, Tuple
|
|
import math
|
|
import numpy as np
|
|
|
|
class FluidDynamics:
|
|
"""
|
|
流体动力学模拟器
|
|
负责实现流体的基本物理模拟和动力学计算
|
|
"""
|
|
|
|
def __init__(self, plugin):
|
|
"""
|
|
初始化流体动力学模拟器
|
|
|
|
Args:
|
|
plugin: 水体和流体模拟插件实例
|
|
"""
|
|
self.plugin = plugin
|
|
self.enabled = False
|
|
self.initialized = False
|
|
|
|
# 流体网格配置
|
|
self.grid_config = {
|
|
'resolution_x': 64,
|
|
'resolution_y': 64,
|
|
'resolution_z': 64,
|
|
'cell_size': 1.0, # 网格单元大小
|
|
'boundary_condition': 'closed' # 边界条件
|
|
}
|
|
|
|
# 物理参数
|
|
self.physics_params = {
|
|
'gravity': 9.81, # 重力加速度 (m/s²)
|
|
'viscosity': 0.001, # 动力粘度 (Pa·s)
|
|
'density': 1000.0, # 密度 (kg/m³)
|
|
'time_step': 0.016, # 时间步长 (秒)
|
|
'solver_iterations': 10 # 求解器迭代次数
|
|
}
|
|
|
|
# 流体状态场
|
|
self.velocity_field = None # 速度场
|
|
self.pressure_field = None # 压力场
|
|
self.density_field = None # 密度场
|
|
self.temperature_field = None # 温度场
|
|
|
|
# 粒子系统
|
|
self.fluid_particles = []
|
|
self.particle_counter = 0
|
|
self.max_particles = 10000
|
|
|
|
# 边界条件
|
|
self.boundary_conditions = {
|
|
'left': 'closed',
|
|
'right': 'closed',
|
|
'top': 'closed',
|
|
'bottom': 'closed',
|
|
'front': 'closed',
|
|
'back': 'closed'
|
|
}
|
|
|
|
# 外力影响
|
|
self.external_forces = {
|
|
'gravity': (0.0, -9.81, 0.0),
|
|
'wind': (0.0, 0.0, 0.0),
|
|
'buoyancy': (0.0, 0.0, 0.0)
|
|
}
|
|
|
|
# 模拟统计
|
|
self.simulation_stats = {
|
|
'steps_completed': 0,
|
|
'particles_updated': 0,
|
|
'solver_iterations': 0,
|
|
'collision_count': 0
|
|
}
|
|
|
|
# 性能优化
|
|
self.optimization_settings = {
|
|
'adaptive_timestep': True,
|
|
'spatial_partitioning': True,
|
|
'particle_culling': True,
|
|
'lod_simulation': True
|
|
}
|
|
|
|
print("✓ 流体动力学模拟器已创建")
|
|
|
|
def initialize(self) -> bool:
|
|
"""
|
|
初始化流体动力学模拟器
|
|
|
|
Returns:
|
|
是否初始化成功
|
|
"""
|
|
try:
|
|
# 初始化流体场
|
|
self._initialize_fluid_fields()
|
|
|
|
# 初始化粒子系统
|
|
self._initialize_particle_system()
|
|
|
|
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._clear_fluid_fields()
|
|
self.fluid_particles.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
|
|
|
|
# 根据实际时间步长调整模拟步长
|
|
actual_dt = dt * self.plugin.fluid_manager.simulation_config['simulation_speed']
|
|
|
|
# 执行流体模拟步骤
|
|
self._simulate_fluid_dynamics(actual_dt)
|
|
|
|
# 更新统计信息
|
|
self.simulation_stats['steps_completed'] += 1
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体动力学模拟器更新失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
def _initialize_fluid_fields(self):
|
|
"""初始化流体场"""
|
|
try:
|
|
res_x = self.grid_config['resolution_x']
|
|
res_y = self.grid_config['resolution_y']
|
|
res_z = self.grid_config['resolution_z']
|
|
|
|
# 初始化速度场 (每个维度一个分量)
|
|
self.velocity_field = {
|
|
'u': np.zeros((res_x, res_y, res_z)), # x方向速度
|
|
'v': np.zeros((res_x, res_y, res_z)), # y方向速度
|
|
'w': np.zeros((res_x, res_y, res_z)) # z方向速度
|
|
}
|
|
|
|
# 初始化压力场
|
|
self.pressure_field = np.zeros((res_x, res_y, res_z))
|
|
|
|
# 初始化密度场
|
|
self.density_field = np.full((res_x, res_y, res_z), self.physics_params['density'])
|
|
|
|
# 初始化温度场
|
|
self.temperature_field = np.full((res_x, res_y, res_z), 20.0) # 20°C
|
|
|
|
print("✓ 流体场初始化完成")
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体场初始化失败: {e}")
|
|
raise
|
|
|
|
def _clear_fluid_fields(self):
|
|
"""清理流体场"""
|
|
try:
|
|
if self.velocity_field:
|
|
for component in self.velocity_field.values():
|
|
component.fill(0)
|
|
self.velocity_field = None
|
|
|
|
if self.pressure_field is not None:
|
|
self.pressure_field.fill(0)
|
|
self.pressure_field = None
|
|
|
|
if self.density_field is not None:
|
|
self.density_field.fill(0)
|
|
self.density_field = None
|
|
|
|
if self.temperature_field is not None:
|
|
self.temperature_field.fill(0)
|
|
self.temperature_field = None
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体场清理失败: {e}")
|
|
|
|
def _initialize_particle_system(self):
|
|
"""初始化粒子系统"""
|
|
try:
|
|
# 预分配粒子数组
|
|
self.fluid_particles = []
|
|
self.particle_counter = 0
|
|
|
|
print("✓ 粒子系统初始化完成")
|
|
|
|
except Exception as e:
|
|
print(f"✗ 粒子系统初始化失败: {e}")
|
|
raise
|
|
|
|
def _simulate_fluid_dynamics(self, dt: float):
|
|
"""
|
|
执行流体动力学模拟
|
|
|
|
Args:
|
|
dt: 时间步长
|
|
"""
|
|
try:
|
|
# 应用外力
|
|
self._apply_external_forces(dt)
|
|
|
|
# 更新速度场
|
|
self._update_velocity_field(dt)
|
|
|
|
# 求解压力场 (确保不可压缩性)
|
|
self._solve_pressure_field()
|
|
|
|
# 更新粒子
|
|
self._update_fluid_particles(dt)
|
|
|
|
# 处理边界条件
|
|
self._apply_boundary_conditions()
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体动力学模拟失败: {e}")
|
|
|
|
def _apply_external_forces(self, dt: float):
|
|
"""
|
|
应用外力到流体
|
|
|
|
Args:
|
|
dt: 时间步长
|
|
"""
|
|
try:
|
|
if not self.velocity_field:
|
|
return
|
|
|
|
res_x, res_y, res_z = self.velocity_field['u'].shape
|
|
|
|
# 应用重力
|
|
gravity = self.external_forces['gravity']
|
|
self.velocity_field['v'] += gravity[1] * dt
|
|
|
|
# 应用风力
|
|
wind = self.external_forces['wind']
|
|
self.velocity_field['u'] += wind[0] * dt
|
|
self.velocity_field['w'] += wind[2] * dt
|
|
|
|
# 应用浮力 (基于温度和密度差异)
|
|
buoyancy = self.external_forces['buoyancy']
|
|
self.velocity_field['v'] += buoyancy[1] * dt
|
|
|
|
except Exception as e:
|
|
print(f"✗ 外力应用失败: {e}")
|
|
|
|
def _update_velocity_field(self, dt: float):
|
|
"""
|
|
更新速度场
|
|
|
|
Args:
|
|
dt: 时间步长
|
|
"""
|
|
try:
|
|
if not self.velocity_field:
|
|
return
|
|
|
|
# 添加粘性扩散项
|
|
self._apply_viscosity(dt)
|
|
|
|
# 添加对流项
|
|
self._apply_advection(dt)
|
|
|
|
except Exception as e:
|
|
print(f"✗ 速度场更新失败: {e}")
|
|
|
|
def _apply_viscosity(self, dt: float):
|
|
"""
|
|
应用粘性扩散
|
|
|
|
Args:
|
|
dt: 时间步长
|
|
"""
|
|
try:
|
|
if not self.velocity_field:
|
|
return
|
|
|
|
viscosity = self.physics_params['viscosity']
|
|
cell_size = self.grid_config['cell_size']
|
|
|
|
# 简化的粘性扩散计算 (拉普拉斯算子)
|
|
# 在实际实现中,这会是一个更复杂的计算
|
|
pass # 简化处理,实际实现中会计算粘性扩散
|
|
|
|
except Exception as e:
|
|
print(f"✗ 粘性扩散应用失败: {e}")
|
|
|
|
def _apply_advection(self, dt: float):
|
|
"""
|
|
应用对流项
|
|
|
|
Args:
|
|
dt: 时间步长
|
|
"""
|
|
try:
|
|
if not self.velocity_field:
|
|
return
|
|
|
|
# 简化的对流计算
|
|
# 在实际实现中,这会使用半拉格朗日方法追踪粒子轨迹
|
|
pass # 简化处理,实际实现中会计算对流
|
|
|
|
except Exception as e:
|
|
print(f"✗ 对流项应用失败: {e}")
|
|
|
|
def _solve_pressure_field(self):
|
|
"""求解压力场"""
|
|
try:
|
|
# 使用投影方法确保不可压缩性
|
|
# 在实际实现中,这会使用泊松方程求解器
|
|
self.simulation_stats['solver_iterations'] += self.physics_params['solver_iterations']
|
|
|
|
except Exception as e:
|
|
print(f"✗ 压力场求解失败: {e}")
|
|
|
|
def _update_fluid_particles(self, dt: float):
|
|
"""
|
|
更新流体粒子
|
|
|
|
Args:
|
|
dt: 时间步长
|
|
"""
|
|
try:
|
|
updated_count = 0
|
|
for particle in self.fluid_particles:
|
|
if particle['active']:
|
|
# 更新粒子位置
|
|
velocity = particle['velocity']
|
|
particle['position'] = (
|
|
particle['position'][0] + velocity[0] * dt,
|
|
particle['position'][1] + velocity[1] * dt,
|
|
particle['position'][2] + velocity[2] * dt
|
|
)
|
|
|
|
# 应用重力
|
|
particle['velocity'] = (
|
|
velocity[0],
|
|
velocity[1] - self.physics_params['gravity'] * dt,
|
|
velocity[2]
|
|
)
|
|
|
|
updated_count += 1
|
|
|
|
self.simulation_stats['particles_updated'] += updated_count
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体粒子更新失败: {e}")
|
|
|
|
def _apply_boundary_conditions(self):
|
|
"""应用边界条件"""
|
|
try:
|
|
# 根据边界条件设置边界值
|
|
# 在实际实现中,这会处理各种边界条件
|
|
pass
|
|
|
|
except Exception as e:
|
|
print(f"✗ 边界条件应用失败: {e}")
|
|
|
|
def add_fluid_particle(self, position: Tuple[float, float, float],
|
|
velocity: Tuple[float, float, float] = (0.0, 0.0, 0.0),
|
|
density: float = None) -> int:
|
|
"""
|
|
添加流体粒子
|
|
|
|
Args:
|
|
position: 粒子位置 (x, y, z)
|
|
velocity: 粒子速度 (vx, vy, vz)
|
|
density: 粒子密度
|
|
|
|
Returns:
|
|
粒子ID
|
|
"""
|
|
try:
|
|
if len(self.fluid_particles) >= self.max_particles:
|
|
print("✗ 粒子数量已达上限")
|
|
return -1
|
|
|
|
if density is None:
|
|
density = self.physics_params['density']
|
|
|
|
particle_id = self.particle_counter
|
|
self.particle_counter += 1
|
|
|
|
particle = {
|
|
'id': particle_id,
|
|
'position': position,
|
|
'velocity': velocity,
|
|
'density': density,
|
|
'temperature': 20.0,
|
|
'active': True,
|
|
'creation_time': time.time()
|
|
}
|
|
|
|
self.fluid_particles.append(particle)
|
|
|
|
return particle_id
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体粒子添加失败: {e}")
|
|
return -1
|
|
|
|
def remove_fluid_particle(self, particle_id: int) -> bool:
|
|
"""
|
|
移除流体粒子
|
|
|
|
Args:
|
|
particle_id: 粒子ID
|
|
|
|
Returns:
|
|
是否移除成功
|
|
"""
|
|
try:
|
|
for i, particle in enumerate(self.fluid_particles):
|
|
if particle['id'] == particle_id:
|
|
self.fluid_particles.pop(i)
|
|
return True
|
|
|
|
print(f"✗ 粒子不存在: {particle_id}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体粒子移除失败: {e}")
|
|
return False
|
|
|
|
def get_fluid_particle(self, particle_id: int) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
获取流体粒子信息
|
|
|
|
Args:
|
|
particle_id: 粒子ID
|
|
|
|
Returns:
|
|
粒子信息或None
|
|
"""
|
|
try:
|
|
for particle in self.fluid_particles:
|
|
if particle['id'] == particle_id:
|
|
return particle.copy()
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"✗ 流体粒子获取失败: {e}")
|
|
return None
|
|
|
|
def set_external_force(self, force_name: str, force_vector: Tuple[float, float, float]):
|
|
"""
|
|
设置外力
|
|
|
|
Args:
|
|
force_name: 力的名称
|
|
force_vector: 力向量 (fx, fy, fz)
|
|
"""
|
|
try:
|
|
if force_name in self.external_forces:
|
|
self.external_forces[force_name] = force_vector
|
|
print(f"✓ 外力 '{force_name}' 已设置: {force_vector}")
|
|
else:
|
|
print(f"✗ 无效的外力名称: {force_name}")
|
|
|
|
except Exception as e:
|
|
print(f"✗ 外力设置失败: {e}")
|
|
|
|
def get_external_forces(self) -> Dict[str, Tuple[float, float, float]]:
|
|
"""
|
|
获取所有外力
|
|
|
|
Returns:
|
|
外力字典
|
|
"""
|
|
return self.external_forces.copy()
|
|
|
|
def set_physics_parameters(self, params: Dict[str, float]):
|
|
"""
|
|
设置物理参数
|
|
|
|
Args:
|
|
params: 物理参数字典
|
|
"""
|
|
try:
|
|
self.physics_params.update(params)
|
|
print(f"✓ 物理参数已更新: {self.physics_params}")
|
|
except Exception as e:
|
|
print(f"✗ 物理参数设置失败: {e}")
|
|
|
|
def get_physics_parameters(self) -> Dict[str, float]:
|
|
"""
|
|
获取物理参数
|
|
|
|
Returns:
|
|
物理参数字典
|
|
"""
|
|
return self.physics_params.copy()
|
|
|
|
def set_grid_configuration(self, config: Dict[str, Any]):
|
|
"""
|
|
设置网格配置
|
|
|
|
Args:
|
|
config: 网格配置字典
|
|
"""
|
|
try:
|
|
old_resolution = (
|
|
self.grid_config['resolution_x'],
|
|
self.grid_config['resolution_y'],
|
|
self.grid_config['resolution_z']
|
|
)
|
|
|
|
self.grid_config.update(config)
|
|
|
|
new_resolution = (
|
|
self.grid_config['resolution_x'],
|
|
self.grid_config['resolution_y'],
|
|
self.grid_config['resolution_z']
|
|
)
|
|
|
|
# 如果分辨率改变,重新初始化流体场
|
|
if old_resolution != new_resolution:
|
|
self._initialize_fluid_fields()
|
|
|
|
print(f"✓ 网格配置已更新: {self.grid_config}")
|
|
except Exception as e:
|
|
print(f"✗ 网格配置设置失败: {e}")
|
|
|
|
def get_grid_configuration(self) -> Dict[str, Any]:
|
|
"""
|
|
获取网格配置
|
|
|
|
Returns:
|
|
网格配置字典
|
|
"""
|
|
return self.grid_config.copy()
|
|
|
|
def get_simulation_stats(self) -> Dict[str, int]:
|
|
"""
|
|
获取模拟统计信息
|
|
|
|
Returns:
|
|
统计信息字典
|
|
"""
|
|
return self.simulation_stats.copy()
|
|
|
|
def reset_simulation_stats(self):
|
|
"""重置模拟统计信息"""
|
|
try:
|
|
self.simulation_stats = {
|
|
'steps_completed': 0,
|
|
'particles_updated': 0,
|
|
'solver_iterations': 0,
|
|
'collision_count': 0
|
|
}
|
|
print("✓ 模拟统计信息已重置")
|
|
except Exception as e:
|
|
print(f"✗ 模拟统计信息重置失败: {e}")
|
|
|
|
def get_fluid_velocity_at(self, x: int, y: int, z: int) -> Optional[Tuple[float, float, float]]:
|
|
"""
|
|
获取指定位置的流体速度
|
|
|
|
Args:
|
|
x, y, z: 网格坐标
|
|
|
|
Returns:
|
|
速度向量 (vx, vy, vz) 或 None
|
|
"""
|
|
try:
|
|
if not self.velocity_field:
|
|
return None
|
|
|
|
shape = self.velocity_field['u'].shape
|
|
if 0 <= x < shape[0] and 0 <= y < shape[1] and 0 <= z < shape[2]:
|
|
vx = self.velocity_field['u'][x, y, z]
|
|
vy = self.velocity_field['v'][x, y, z]
|
|
vz = self.velocity_field['w'][x, y, z]
|
|
return (float(vx), float(vy), float(vz))
|
|
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"✗ 速度获取失败: {e}")
|
|
return None
|
|
|
|
def set_fluid_velocity_at(self, x: int, y: int, z: int, velocity: Tuple[float, float, float]):
|
|
"""
|
|
设置指定位置的流体速度
|
|
|
|
Args:
|
|
x, y, z: 网格坐标
|
|
velocity: 速度向量 (vx, vy, vz)
|
|
"""
|
|
try:
|
|
if not self.velocity_field:
|
|
return
|
|
|
|
shape = self.velocity_field['u'].shape
|
|
if 0 <= x < shape[0] and 0 <= y < shape[1] and 0 <= z < shape[2]:
|
|
self.velocity_field['u'][x, y, z] = velocity[0]
|
|
self.velocity_field['v'][x, y, z] = velocity[1]
|
|
self.velocity_field['w'][x, y, z] = velocity[2]
|
|
|
|
except Exception as e:
|
|
print(f"✗ 速度设置失败: {e}")
|
|
|
|
def calculate_cfl_condition(self) -> float:
|
|
"""
|
|
计算CFL条件(柯朗-弗里德里希-李维条件)
|
|
|
|
Returns:
|
|
CFL数
|
|
"""
|
|
try:
|
|
if not self.velocity_field:
|
|
return 0.0
|
|
|
|
max_velocity = 0.0
|
|
# 计算最大速度
|
|
u_max = np.max(np.abs(self.velocity_field['u']))
|
|
v_max = np.max(np.abs(self.velocity_field['v']))
|
|
w_max = np.max(np.abs(self.velocity_field['w']))
|
|
max_velocity = max(u_max, v_max, w_max)
|
|
|
|
cell_size = self.grid_config['cell_size']
|
|
dt = self.physics_params['time_step']
|
|
|
|
# CFL = (v * dt) / dx
|
|
cfl = (max_velocity * dt) / cell_size if cell_size > 0 else 0.0
|
|
return cfl
|
|
|
|
except Exception as e:
|
|
print(f"✗ CFL条件计算失败: {e}")
|
|
return 0.0
|
|
|
|
def is_stable(self) -> bool:
|
|
"""
|
|
检查模拟是否稳定
|
|
|
|
Returns:
|
|
是否稳定
|
|
"""
|
|
try:
|
|
# CFL条件应小于等于1以保证稳定性
|
|
cfl = self.calculate_cfl_condition()
|
|
return cfl <= 1.0
|
|
|
|
except Exception as e:
|
|
print(f"✗ 稳定性检查失败: {e}")
|
|
return False |