Deepseek手把手教学编写有限元代码
用deepseek直接从造轮子开始实现一个有限元的全过程的分析。学过有限元或者弹性力学的朋友肯定对带开孔的矩形板的受力分析并不陌生,这一次我们以这个问题来进行测试。
图1 有限元模型示意图
一、提问问题如下:
二、deepseek的思考过程
deepseek经过了391秒的思考,(这里省去复杂的中间思考过程),得出了如下主要步骤:
- 现在,我需要将这些步骤组织成一个类结构,类名为fea,包含各个方法。例如:
- - __init__方法初始化参数,如几何尺寸、材料属性、网格划分参数等。
- - generate_nodes方法生成节点,并处理孔的存在,排除孔内的节点。
- - generate_elements方法生成单元,排除那些包含孔内节点的单元。
- - 或者,另一种方式,先生成所有可能的节点,然后生成单元时检查单元是否在孔内,如果在则排除。
- - 然后,计算每个单元的刚度矩阵,并组装到总刚度矩阵。
- - 处理边界条件,如固定左端的x方向位移。
- - 组装载荷向量,施加均布力到右端节点。
- - 求解方程组得到位移。
- - 计算应力。
- - 绘制变形和应力云图。
再次进一步思考每个方法的实现细节,主要技术特征包括了:
- 将整个板划分为细小的四边形单元
- 移除中心孔区域的单元,
- x方向从0到10,y方向从0到5,步长dx和 dy根据划分的数目确定
- 如此使用若干个四边形来近似模拟开孔圆形再次省略deepseek的分析过程,直接给出生成的代码:
import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.collections import PolyCollectionclass FEA: def __init__(self): # 几何参数 self.L = 10.0 # 长度 (mm) self.W = 5.0 # 宽度 (mm) self.thickness = 1 # 厚度 (mm) self.hole_r = 0.5 # 孔半径 (mm) # 材料参数 self.E = 1e10 # 弹性模量 (Pa) self.nu = 0.2 # 泊松比 # 载荷参数 self.pressure = 10 # 均布载荷 (N/mm) # 网格参数 self.nx = 41 # X方向网格数 self.ny = 21 # Y方向网格数 # 初始化数据结构 self.nodes = [] self.elements = [] self.dofs = 2 # 每个节点自由度 self.K = None # 全局刚度矩阵 self.F = None # 载荷向量 self.U = None # 位移向量 def generate_mesh(self): """生成带孔的网格""" # 生成原始网格 x = np.linspace(0, self.L, self.nx) y = np.linspace(0, self.W, self.ny) nodes = np.array(np.meshgrid(x, y)).T.reshape(-1, 2) # 过滤孔区域节点 center = np.array([self.L/2, self.W/2]) distances = np.linalg.norm(nodes - center, axis=1) valid_nodes = nodes[distances > self.hole_r] self.node_indices = {tuple(pos):i for i, pos in enumerate(valid_nodes)} # 生成四边形单元 elements = [] for j in range(self.ny-1): for i in range(self.nx-1): n1 = (x[i], y[j]) n2 = (x[i+1], y[j]) n3 = (x[i+1], y[j+1]) n4 = (x[i], y[j+1]) try: e = [self.node_indices[tuple(n1)], self.node_indices[tuple(n2)], self.node_indices[tuple(n3)], self.node_indices[tuple(n4)]] elements.append(e) except KeyError: continue self.nodes = valid_nodes self.elements = np.array(elements) self.num_nodes = len(self.nodes) def create_D_matrix(self): """创建弹性矩阵""" E = self.E nu = self.nu self.D = E/(1-nu**2) * np.array([ [1, nu, 0], [nu, 1, 0], [0, 0, (1-nu)/2] ]) def quad_shape_func(self, xi, eta): """四边形单元形函数""" return 0.25*np.array([ (1-xi)*(1-eta), (1+xi)*(1-eta), (1+xi)*(1+eta), (1-xi)*(1+eta) ]) def quad_B_matrix(self, xi, eta, coord): """计算B矩阵""" dN = np.array([ [eta-1, 1-eta, 1+eta, -eta-1], [xi-1, -xi-1, xi+1, 1-xi] ]) / 4 J = dN @ coord invJ = np.linalg.inv(J) dN_dx = invJ @ dN B = np.zeros((3, 8)) for i in range(4): B[0, 2*i] = dN_dx[0, i] B[1, 2*i+1] = dN_dx[1, i] B[2, 2*i] = dN_dx[1, i] B[2, 2*i+1] = dN_dx[0, i] return B, np.linalg.det(J) def element_stiffness(self, element): """计算单元刚度矩阵""" ke = np.zeros((8, 8)) coord = self.nodes[element] gauss_points = [(-1/np.sqrt(3), -1/np.sqrt(3), 1), (1/np.sqrt(3), -1/np.sqrt(3), 1), (1/np.sqrt(3), 1/np.sqrt(3), 1), (-1/np.sqrt(3), 1/np.sqrt(3), 1)] for gp in gauss_points: B, detJ = self.quad_B_matrix(gp[0], gp[1], coord) ke += B.T @ self.D @ B * detJ * gp[2] * self.thickness return ke def assemble_global_stiffness(self): """组装全局刚度矩阵""" n_dof = self.num_nodes * self.dofs self.K = np.zeros((n_dof, n_dof)) for e in self.elements: ke = self.element_stiffness(e) for i in range(4): ni = e[i] for j in range(4): nj = e[j] for di in range(2): for dj in range(2): row = 2*ni + di col = 2*nj + dj self.K[row, col] += ke[2*i+di, 2*j+dj] def apply_boundary_conditions(self): """施加边界条件""" # 找到左侧边界节点 left_nodes = [i for i, n in enumerate(self.nodes) if n[0] == 0] for n in left_nodes: dof = 2*n self.K[dof, :] = 0 self.K[:, dof] = 0 self.K[dof, dof] = 1 def apply_loads(self): """施加载荷""" self.F = np.zeros(self.num_nodes*2) right_nodes = [i for i, n in enumerate(self.nodes) if n[0] == self.L] dx = self.L / (self.nx-1) for n in right_nodes: self.F[2*n] = self.pressure * dx def solve(self): """求解系统方程""" self.U = np.linalg.solve(self.K, self.F) def plot_results(self): """结果可视化""" # 变形云图 plt.figure(figsize=(12, 5)) plt.subplot(121) disp = np.linalg.norm(self.U.reshape(-1, 2), axis=1) plt.tricontourf(self.nodes[:,0], self.nodes[:,1], disp, levels=20) plt.axis("equal") # X和Y轴缩放比例一致 plt.colorbar(label='Displacement Magnitude (mm)') plt.title('Deformation Cloud Map') # 应力云图 plt.subplot(122) stress = [] for e in self.elements: coord = self.nodes[e] B, _ = self.quad_B_matrix(0, 0, coord) # 单元中心 u = self.U[[2*e[i]+j for i in range(4) for j in [0,1]]] stress.append(np.linalg.norm(self.D @ B @ u)) poly = PolyCollection([self.nodes[e][:,[0,1]] for e in self.elements], array=stress, cmap='jet') plt.gca().add_collection(poly) plt.colorbar(poly, label='Stress (Pa)') plt.xlim(0, self.L) plt.ylim(0, self.W) plt.title('Stress Cloud Map') plt.tight_layout() plt.axis("equal") # X和Y轴缩放比例一致 plt.show()def main(): model = FEA() model.generate_mesh() model.create_D_matrix() model.assemble_global_stiffness() model.apply_loads() model.apply_boundary_conditions() model.solve() model.plot_results()if __name__ == "__main__": main()
代码经过运行,仅174行缺少“]”,补充该括弧后,代码可直接运行。那么结果如何?我们看看:
图2 deepseek提供代码生成的位移云图
图3 deepseek提供代码生成的应力云图
可以看出代码得出了结果,并且趋势上也比较熟悉。那么这个代码可以将网格划分加密么?当然可以,仅需调整网格密度,我们提高一下__init__()函数中的变量即可,比如加密4倍:
# 网格参数 self.nx = 161 # X方向网格数 self.ny = 81 # Y方向网格数
同时在云图输出的时候,控制x与y轴比例一致,即增加如下代码:
plt.axis("equal") # X和Y轴缩放比例一致
接下来看改进代码后的输出结果:
图4 deepseek提供代码生成的位移云图(加密网格)
图5 deepseek提供代码生成的应力云图(加密网格)
三、关于此次测评的点评
deepseek能够给出详细的分析过程,包括了比较完整的有限元求解步骤,可以根据这一步骤理解有限元求解的基本思想和过程;能够根据提问的要求,将代码进行了封装,代码模块分工清晰;对于复杂的几何形状,采用了矩形网格去无穷逼近外形的思路。当然也有相对不足之处,比如位移云图中开孔变形未能处理等等。
那么这个计算结果靠谱么?感兴趣的朋友可以拿起你的工具来验证一下吧。
评论
活着

干货推荐

计算机材料设计Materials-Studio教程5
活着
32 2

分子轨道理论简介与计算示例
天玑智研
769 6

计算机材料设计Materials-Studio教程11
活着
35 1

有髓神经纤维超微结构
Mr弘🔬
56 5

如何用ABAQUS输出局部坐标系上的投影力值?
小刀
90 9

lammps中文教程5
春风得意马蹄疾
47 2
