python实现简单的二维有限元计算

有限元算法依据常见的有限元法教材,简单复现悬臂梁在重力作用下的形变(为了变形更明显,重力大小扩大了10倍),还没来得及写注释。【卧槽快跑,没注释!】

节点是随机函数撒的点,完全没有优化;

meshpy库中的Delauny优化算法计算得到三角单元;

pygame实现图形绘制,图形如下(文字是自己后来写上去的):

import numpy as np
import copy
import pygame,sys
from pygame.locals import *
import meshpy.triangle as triangle
import json

class Node:

    def __init__(self):
        self.id = -1
        self.type = -1
        self.coord = -1


class Material:

    def __init__(self):
        self.id = -1
        self.E = -1
        self.h = -1
        self.miu = -1
        self.mass = -1
        self.thickness = -1


class Element:

    def __init__(self):
        self.id = -1
        self.type = -1
        self.nodes = []
        self.material = -1
        self.C = -1
        self.S = -1
        self.k = -1
        self.runType = 0
        self.A = -1
        self.G = -1


    def get_k(self,nodes):
        material = self.material
        if material == -1:
            return
        if self.type == 0:
            E = material.E
            miu = material.miu
        else :
            E = material.E/(1-material.miu**2)
            miu = material.miu/(1-material.miu)
        D = np.mat([[1,miu,0],[miu,1,0],[0,0,(1-miu)/2]])*E/(1-miu**2)
        A = np.mat([[1,nodes[self.nodes[0]].coord[0],nodes[self.nodes[0]].coord[1]],
                    [1,nodes[self.nodes[1]].coord[0],nodes[self.nodes[1]].coord[1]],
                    [1,nodes[self.nodes[2]].coord[0],nodes[self.nodes[2]].coord[1]],])
        A = 0.5*np.abs(np.linalg.det(A))
        node_abc = [[],[],[]]
        B = np.zeros((3,6))
        for i in range(3):
            if i == 0:
                j = 1
                m = 2
            elif i == 1:
                j = 2
                m = 0
            else:
                j = 0
                m = 1
            a = nodes[self.nodes[j]].coord[0]*nodes[self.nodes[m]].coord[1] - nodes[self.nodes[m]].coord[0]*nodes[self.nodes[j]].coord[1]
            b = nodes[self.nodes[j]].coord[1] - nodes[self.nodes[m]].coord[1]
            c = -nodes[self.nodes[j]].coord[0] + nodes[self.nodes[m]].coord[0]
            node_abc[i] = [a,b,c]
            Bi = np.mat([[b,0],[0,c],[c,b]])/2/A
            B[:,i*2:i*2+2] = Bi
        self.k = B.T*D*B*material.h*A
        self.G = np.mat([0,1,0,1,0,1]).T*-1/3*material.mass*material.h*A
        return self.k

class Main:

    def __init__(self):

        self.nodes = []
        self.elements = []
        self.structureHeight = -1
        self.structureWidth = -1
        self.structureThickness = -1

        self.material = Material()
        self.material.id = 1
        self.material.E = 100000000 #材料弹性模量
        self.material.mass = 100 #材料密度
        self.material.miu = 0.2 #材料泊松比
        self.material.h = 0.2 #忘了是啥了

        self.meshSize = -1
        self.runType = 0
        self.g = -9.806*10 #为了使形变更明显,将重力大小扩大10倍
        self.X = -1

    def run(self):
        self.structureHeight = 0.5
        self.structureWidth = 4
        self.structureThickness = 1
        self.meshSize = [3,3]
        node_row = int(np.ceil(self.structureHeight/self.meshSize[1]))+1
        node_col = int(np.ceil(self.structureWidth / self.meshSize[0]))+1
        node_count = 0
        np.set_printoptions(precision=2)
        mesh_info = triangle.MeshInfo()
        points = [[0, 0], [0, self.structureHeight], [self.structureWidth, self.structureHeight], [self.structureWidth, 0]]
        random_points = np.random.rand(300, 2)
        random_points = np.mat(random_points)
        random_points[:, 0] = random_points[:, 0] * self.structureWidth
        random_points[:, 1] = random_points[:, 1] * self.structureHeight
        points.extend(random_points.tolist())

        # 将节点存储到json,可供第三方软件读取节点信息
        # with open('data_random12172.json', 'w') as json_file:
        #     json_file.write(json.dumps(points))

        mesh_info.set_points(points)
        facets = [[0,1],[1,2],[2,3],[3,0]]
        mesh_info.set_facets(facets)
        mesh = triangle.build(mesh_info)
        node_count = 0
        for i, p in enumerate(mesh.points):
            node = Node()
            node.id = node_count
            node.type = 1
            node.coord = p
            self.nodes.append(node)
            node_count = node_count + 1

        element_count = 0
        K = np.zeros((node_count*2,node_count*2))
        F = np.zeros((2 * node_count, 1))

        for i,element_item in enumerate(mesh.elements):
            element = Element()
            element.id = element_count
            element.nodes = element_item
            element.material = self.material
            k = element.get_k(self.nodes)
            for j in range(3):
                F[2*element_item[j]:2*element_item[j]+2,:] = F[2*element_item[j]:2*element_item[j]+2,:]+element.G[2*j:2*j+2,:]*self.g
                for m in range(3):
                    K[2*element_item[j]:2*element_item[j]+2,2*element_item[m]:2*element_item[m]+2] = \
                        K[2 * element_item[j]:2 * element_item[j] + 2, 2 * element_item[m]:2 * element_item[m] + 2] + k[2*j:2*j+2,2*m:2*m+2]
            self.elements.append(element)
            element_count = element_count + 1
        for i in range(node_count):
            if np.abs(self.nodes[i].coord[0] - 0) < 1e-5:
                K[:,2*i:2*i+2] = 0
                K[2 * i:2 * i + 2,:] = 0
                K[2 * i:2 * i + 2,2 * i:2 * i + 2] = np.eye(2)
                F[2*i:2*i+2,:] = 0
        self.X = np.mat(K).I*np.mat(F)
        a = 0


if __name__ == '__main__':
    main = Main()
    main.run()

    pygame.init()

    geo_scale = [300,300]
    geo_offset_mixed = [55,50]
    geo_offset_origin = [55,300]
    geo_offset_onload = [55,550]

    screen = pygame.display.set_mode((1400, 800))
    screen.fill(pygame.Color(255, 255, 255))

    line_color_orogin = (50, 50, 255)
    line_color_onload = (50, 50, 255)
    flag = 0
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
        my_font = pygame.font.SysFont('arial', 16)
        ### 无荷载图形与带荷载图形重叠绘制
        pygame.draw
        for i in range(len(main.nodes)):
            if flag == 1:
                break
            pointpos_origin = (np.multiply(np.mat(main.nodes[i].coord),np.mat(geo_scale))+np.mat(geo_offset_mixed)).tolist()[0]
            pointpos_onload = (np.multiply(np.mat(main.nodes[i].coord+main.X[2*i:2*i+2,:].T),np.mat(geo_scale))+np.mat(geo_offset_mixed)).tolist()[0]
            pygame.draw.circle(screen, [255, 0, 0], [int(pointpos_origin[0]), int(pointpos_origin[1])], 3, 2)
            pygame.draw.circle(screen, [50, 200, 50], [int(pointpos_onload[0]), int(pointpos_onload[1])], 3, 2)

        for i in range(len(main.elements)):
            if flag == 1:
                break
            node1 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[0]].coord),np.mat(geo_scale))
                     +np.mat(geo_offset_mixed)).tolist()[0]
            node2 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[1]].coord),np.mat(geo_scale))
                     +np.mat(geo_offset_mixed)).tolist()[0]
            node3 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[2]].coord),np.mat(geo_scale))
                     +np.mat(geo_offset_mixed)).tolist()[0]
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node2], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node3], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node2, node3], 1)

            node1 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[0]].coord)+main.X[2*main.elements[i].nodes[0]:2*main.elements[i].nodes[0]+2,:].T, np.mat(geo_scale)) 
                     + np.mat(geo_offset_mixed)).tolist()[0]
            node2 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[1]].coord)+main.X[2*main.elements[i].nodes[1]:2*main.elements[i].nodes[1]+2,:].T, np.mat(geo_scale)) 
                     + np.mat(geo_offset_mixed)).tolist()[0]
            node3 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[2]].coord)+main.X[2*main.elements[i].nodes[2]:2*main.elements[i].nodes[2]+2,:].T, np.mat(geo_scale)) 
                     + np.mat(geo_offset_mixed)).tolist()[0]
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node2], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node3], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node2, node3], 1)

        ### 无荷载图形与带荷载图形分开绘制
        for i in range(len(main.nodes)):
            if flag == 1:
                break
            pointpos_origin = (np.multiply(np.mat(main.nodes[i].coord),np.mat(geo_scale))+np.mat(geo_offset_origin)).tolist()[0]
            pointpos_onload = (np.multiply(np.mat(main.nodes[i].coord+main.X[2*i:2*i+2,:].T),np.mat(geo_scale))+np.mat(geo_offset_onload)).tolist()[0]
            pygame.draw.circle(screen, [255, 0, 0], [int(pointpos_origin[0]), int(pointpos_origin[1])], 3, 2)
            pygame.draw.circle(screen, [50, 200, 50], [int(pointpos_onload[0]), int(pointpos_onload[1])], 3, 2)

        for i in range(len(main.elements)):
            if flag == 1:
                break
            node1 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[0]].coord),np.mat(geo_scale))
                     +np.mat(geo_offset_origin)).tolist()[0]
            node2 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[1]].coord),np.mat(geo_scale))
                     +np.mat(geo_offset_origin)).tolist()[0]
            node3 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[2]].coord),np.mat(geo_scale))
                     +np.mat(geo_offset_origin)).tolist()[0]
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node2], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node3], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node2, node3], 1)

            node1 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[0]].coord)+main.X[2*main.elements[i].nodes[0]:2*main.elements[i].nodes[0]+2,:].T, np.mat(geo_scale)) 
                     + np.mat(geo_offset_onload)).tolist()[0]
            node2 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[1]].coord)+main.X[2*main.elements[i].nodes[1]:2*main.elements[i].nodes[1]+2,:].T, np.mat(geo_scale)) 
                     + np.mat(geo_offset_onload)).tolist()[0]
            node3 = (np.multiply(np.mat(main.nodes[main.elements[i].nodes[2]].coord)+main.X[2*main.elements[i].nodes[2]:2*main.elements[i].nodes[2]+2,:].T, np.mat(geo_scale)) 
                     + np.mat(geo_offset_onload)).tolist()[0]
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node2], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node1, node3], 1)
            pygame.draw.lines(screen, line_color_orogin, False, [node2, node3], 1)
        flag = 1

        pygame.display.update()

### 回答1: 下面是一个简单Python 有限元程序的例子,求解二维梯形单元内的本构方程。 ``` import numpy as np # 定义梯形单元的长和宽 L = 1.0 B = 0.5 # 定义单元内的节点编号和节点位置 nodes = np.array([[0, 0], [L, 0], [L, B], [0, B]]) # 定义单元内的本构方程系数矩阵 k_elem = np.array([[4, 2, -2, -4], [2, 4, -4, -2], [-2, -4, 4, 2], [-4, -2, 2, 4]]) / (6 * L * B) # 计算单元内的刚度矩阵 k_global = np.zeros((4, 4)) for i in range(4): for j in range(4): k_global[i, j] = k_global[i, j] + k_elem[i, j] print("单元内的刚度矩阵为:\n", k_global) ``` 该程序的输出结果为: ``` 单元内的刚度矩阵为: [[ 1.33333333 -0.33333333 -0.33333333 0.66666667] [-0.33333333 1.33333333 0.66666667 -0.33333333] [-0.33333333 0.66666667 1.33333333 -0.33333333] [ 0.66666667 -0.33333333 -0.33333333 1.33333333]] ``` 这是一个简单有限元程序,通过定义梯形单元的形状、节点位置、本构方程系数矩阵等参数,计算出单元内的刚度矩阵,表示了单元内的力学特性。 ### 回答2: 有限元方法是一种数值分析方法,用来求解连续介质的力学问题。在这个简单有限元程序中,我们将使用Python编写一个二维弹性力学问题的有限元求解程序。 首先,我们需要定义输入参数,如材料的弹性系数(弹性模量和泊松比)、加载条件(边界条件和荷载)、几何参数(网格的节点和单元信息)等。 然后,我们需要定义一个函数来计算和组装全局刚度矩阵和载荷向量。这个函数将根据每个单元的局部刚度矩阵和载荷来计算和组装全局矩阵和载荷。 接下来,我们需要求解线性方程组。这个方程组的形式为[K]{u}={F},其中[K]是全局刚度矩阵,{u}是节点位移向量,{F}是载荷向量。我们可以使用Python中的线性方程组求解函数来解决这个方程组。 最后,我们可以绘制出节点的位移和应力分布图。这可以通过将节点坐标和位移向量结合起来,并根据材料的应力应变关系计算出节点的应力值。 这个简单有限元程序可以用来解决二维弹性力学问题,如悬臂梁的弯曲问题。通过改变输入参数和几何参数,我们可以用这个程序来解决其他不同的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值