有限元方法数值计算项目

项目概述

这是一个基于有限元方法(Finite Element Method, FEM)的数值计算项目,用于求解偏微分方程,特别是在结构力学、热传导和电磁场分析等领域的应用。

理论基础

有限元方法的核心思想是将连续域离散化为有限个单元,通过变分原理建立代数方程组:

变分原理

对于边值问题: $$\mathcal{L}u = f \quad \text{in } \Omega$$ $$u = g \quad \text{on } \partial\Omega$$

其变分形式为: $$a(u,v) = (f,v) \quad \forall v \in V_0$$

其中: - $a(u,v)$ 是双线性形式 - $(f,v)$ 是线性泛函 - $V_0$ 是测试函数空间

离散化过程

  1. 网格生成: 将求解域划分为有限个单元
  2. 基函数构造: 在每个单元上定义形函数
  3. 刚度矩阵组装: 计算单元刚度矩阵并组装
  4. 边界条件处理: 施加本质边界条件
  5. 线性方程组求解: 求解 $Ku = F$

技术特点

核心算法

  • 网格生成: 自适应网格细化
  • 形函数: 拉格朗日、埃尔米特、B样条基函数
  • 数值积分: 高斯积分、辛普森积分
  • 求解器: 直接法(LU分解)、迭代法(CG、GMRES)

编程实现

  • 语言: C++、Python、Fortran
  • 并行计算: OpenMP、MPI、CUDA
  • 可视化: VTK、ParaView、Matplotlib
  • 后处理: 应力分析、位移场、温度场

应用领域

结构力学

  • 静力学分析: 应力、应变、位移计算
  • 动力学分析: 模态分析、瞬态响应
  • 非线性分析: 材料非线性、几何非线性
  • 接触问题: 摩擦接触、无摩擦接触

热传导

  • 稳态传热: 温度场分布
  • 瞬态传热: 时间相关的温度变化
  • 相变问题: 熔化、凝固过程
  • 对流换热: 流体-固体耦合

电磁场

  • 静电场: 电位分布、电场强度
  • 静磁场: 磁感应强度、磁通量
  • 时变场: 电磁波传播、涡流分析
  • 多物理场: 电磁-热耦合

代码示例

C++ 有限元求解器核心类

// 有限元求解器核心类
class FiniteElementSolver {
private:
    Mesh mesh;
    std::vector<double> solution;
    SparseMatrix<double> stiffness_matrix;
    VectorXd load_vector;

public:
    // 构造函数
    FiniteElementSolver(const Mesh& m) : mesh(m) {
        initialize_matrices();
    }

    // 组装刚度矩阵
    void assemble_stiffness_matrix() {
        for (auto& element : mesh.elements) {
            auto local_stiffness = compute_element_stiffness(element);
            assemble_global_matrix(local_stiffness, element);
        }
    }

    // 施加边界条件
    void apply_boundary_conditions() {
        for (auto& bc : boundary_conditions) {
            if (bc.type == "Dirichlet") {
                apply_dirichlet_bc(bc);
            } else if (bc.type == "Neumann") {
                apply_neumann_bc(bc);
            }
        }
    }

    // 求解线性方程组
    void solve() {
        // 使用共轭梯度法求解
        ConjugateGradient<SparseMatrix<double>> solver;
        solver.compute(stiffness_matrix);
        solution = solver.solve(load_vector);
    }

    // 计算单元刚度矩阵
    MatrixXd compute_element_stiffness(const Element& element) {
        MatrixXd ke = MatrixXd::Zero(element.n_nodes, element.n_nodes);

        // 数值积分
        for (int gp = 0; gp < element.n_gauss_points; ++gp) {
            auto [xi, eta, zeta, weight] = element.gauss_points[gp];

            // 计算形函数导数
            auto B_matrix = compute_B_matrix(element, xi, eta, zeta);

            // 计算雅可比矩阵
            auto J = compute_jacobian(element, xi, eta, zeta);
            double det_J = J.determinant();

            // 组装单元刚度矩阵
            ke += weight * det_J * B_matrix.transpose() * D_matrix * B_matrix;
        }

        return ke;
    }

    // 计算B矩阵(应变-位移关系)
    MatrixXd compute_B_matrix(const Element& element, double xi, double eta, double zeta) {
        MatrixXd B = MatrixXd::Zero(6, element.n_nodes * 3);

        // 计算形函数导数
        auto dN_dxi = compute_shape_function_derivatives(element, xi, eta, zeta);

        // 组装B矩阵
        for (int i = 0; i < element.n_nodes; ++i) {
            B(0, 3*i) = dN_dxi(i, 0);     // ∂N_i/∂x
            B(1, 3*i+1) = dN_dxi(i, 1);   // ∂N_i/∂y
            B(2, 3*i+2) = dN_dxi(i, 2);   // ∂N_i/∂z

            // 剪切应变项
            B(3, 3*i) = dN_dxi(i, 1);
            B(3, 3*i+1) = dN_dxi(i, 0);

            B(4, 3*i+1) = dN_dxi(i, 2);
            B(4, 3*i+2) = dN_dxi(i, 1);

            B(5, 3*i) = dN_dxi(i, 2);
            B(5, 3*i+2) = dN_dxi(i, 0);
        }

        return B;
    }
};

Python 有限元后处理

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

class FEMPostProcessor:
    def __init__(self, mesh, solution):
        self.mesh = mesh
        self.solution = solution

    def compute_stress(self):
        """计算应力场"""
        stress_field = np.zeros((self.mesh.n_elements, 6))

        for i, element in enumerate(self.mesh.elements):
            # 计算单元应力
            element_stress = self.compute_element_stress(element)
            stress_field[i] = element_stress

        return stress_field

    def compute_element_stress(self, element):
        """计算单元应力"""
        # 获取单元节点位移
        element_displacement = self.get_element_displacement(element)

        # 计算应变
        strain = self.compute_strain(element, element_displacement)

        # 计算应力(胡克定律)
        stress = self.material.D_matrix @ strain

        return stress

    def plot_displacement(self, scale_factor=1.0):
        """绘制位移场"""
        fig = plt.figure(figsize=(12, 8))
        ax = fig.add_subplot(111, projection='3d')

        # 获取节点坐标
        nodes = self.mesh.nodes
        displacement = self.solution.reshape(-1, 3)

        # 绘制变形后的网格
        for element in self.mesh.elements:
            element_nodes = nodes[element.node_indices]
            element_disp = displacement[element.node_indices]

            # 变形后的坐标
            deformed_nodes = element_nodes + scale_factor * element_disp

            # 绘制单元
            self.plot_element(ax, deformed_nodes)

        ax.set_xlabel('X')
        ax.set_ylabel('Y')
        ax.set_zlabel('Z')
        ax.set_title('位移场可视化')
        plt.show()

    def plot_stress_contour(self, stress_component='von_mises'):
        """绘制应力云图"""
        fig, ax = plt.subplots(figsize=(10, 8))

        # 计算应力
        stress_field = self.compute_stress()

        if stress_component == 'von_mises':
            # 计算等效应力
            von_mises = self.compute_von_mises_stress(stress_field)
            contour = ax.tricontourf(self.mesh.nodes[:, 0], 
                                   self.mesh.nodes[:, 1], 
                                   von_mises)
        else:
            # 绘制指定应力分量
            stress_component_idx = self.get_stress_component_index(stress_component)
            contour = ax.tricontourf(self.mesh.nodes[:, 0], 
                                   self.mesh.nodes[:, 1], 
                                   stress_field[:, stress_component_idx])

        plt.colorbar(contour, label=f'{stress_component} 应力')
        ax.set_xlabel('X 坐标')
        ax.set_ylabel('Y 坐标')
        ax.set_title(f'{stress_component} 应力云图')
        plt.show()

数值算例

悬臂梁分析

问题描述: 一端固定的悬臂梁,自由端受集中力作用

几何参数: - 长度: L = 1.0 m - 高度: h = 0.1 m - 宽度: b = 0.05 m - 弹性模量: E = 200 GPa - 泊松比: ν = 0.3

边界条件: - 固定端: u = v = w = 0 - 自由端: 集中力 F = 1000 N

理论解: 最大挠度: $w_{max} = \frac{FL^3}{3EI}$

其中 $I = \frac{bh^3}{12}$ 是截面惯性矩

结果对比

网格密度 节点数 单元数 最大挠度 (mm) 误差 (%)
粗网格 25 16 2.45 1.2
中等网格 81 64 2.48 0.4
细网格 289 256 2.49 0.1
理论解 - - 2.50 0.0

技术文档

项目模块

求解器类型

技术特点

  • 多物理场耦合: 流体-结构、流体-传热耦合分析
  • 自适应网格: 基于误差估计的网格自适应细化
  • 并行计算: 支持OpenMP和MPI的大规模并行计算
  • 高性能优化: 针对不同硬件平台的性能优化

相关链接


这个项目展示了我在数值计算、有限元方法和科学计算方面的专业能力。