首页 > 其他分享 >有限元仿真 有限体积仿真

有限元仿真 有限体积仿真

时间:2024-04-05 12:55:32浏览次数:17  
标签:仿真 有限元 int Tet Vector3 number 体积 new tet

0 前言

声明:此篇博客仅用于个人学习记录之用,并非是分享代码。Hornor the Code

本来想仔细学一下有限元再进行LAB3的制作,之前也是这么做的。问题是咱是做游戏的,不是做cae的,养家糊口之后真没有时间去研究那些东西。所以后面的像 张量分析 之类的也就没仔细去看。只是做了矩阵微积分的那一部分。

后面的流体模拟,也是一个深坑。泪目。

这次作业的Mesh可以看作是没有索引的顶点数组。

索引数组降低了内存占用,但是带来的负面效果就是,没法做顶点的删减增加。这个缺点在三角形细分和三角形裁剪的时候尤为恐怖。

感谢 Games103王华民老师的《Intro to Physics-Based Animation!》

1 拉格朗日模拟

先从能量说起。能量分为动能和势能。物理学有一大定律,名为能量守恒。我们知道动能和势能是可以转换的。动能和势能的转换依靠的就是力。

力总是希望快速的降低势能。想象一个静止的弹簧,抓着两个端点狠狠的一拉,不放手。这个时候动能为0,但是你的手已经为弹簧做了功。弹簧中充满了潜在的能量,势能。

这个时候弹簧就会自然的产生力,来减少这个势能。

牛顿定律三条,说了一堆。核心就是第三条,力是哪来的?两个物体。最后两个物体的合力是多少,零。但是对于每一个单独的物体,却是受到力的。

万物都尽量想保持原状,但是总会有外部的物体来给与你交互施加能量,由此万物开始运动。只不过因为大家碰到了,只不过因为大家想保持原状。这就是宇宙。宇宙的合力为0。

质点弹簧系统,一根弹簧,两个质点作用。中间都是空的,弹簧由能量定义。能量由位置定义。

有限元系统,一个三角形,三个质点作用。中间都是空的,面积由能量定义。能量由位置定义。

有限体积法, 一个四面体,四个质点的作用。中间都是空的,体积由能量定义。能量由位置定义。

仅此而已。
image

2 四面体数据格式

2.1 house2.ele

/*
First line: <# of tetrahedra> <nodes per tetrahedron> <# of attributes>
Remaining lines list of # of tetrahedra:
<tetrahedron #> <node> <node> <node> <node> ... [attributes]
*/
1389  4  0
0    1    75   175    52
1    1    75    52   360
0    1    11    46   174
0    1    11   174    57

https://wias-berlin.de/software/tetgen/fformats.ele.html

2.2 house2.node

/*
First line: <# of points> <dimension (must be 3)> <# of attributes> <# of boundary markers (0 or 1)>
Remaining lines list # of points:
<point #> <x> <y> <z> [attributes] [boundary marker]
*/
400  3  0  1
   1    6.5  1  7.5430812757201648    1
   2    4.4456243310934527  5.3728065092415962  8.3129834982130344    0
   3    4.1326492294372636  8.1243529245273844  4.2828387696230079    0
   4    4.75  7.7548808372563904  7.6928224992291403    0

https://wias-berlin.de/software/tetgen/fformats.node.html

3. Impl

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;

public class FVM : MonoBehaviour
{
    float dt = 0.003f;
    float mass = 1;
    float stiffness_0 = 20000.0f;
    float stiffness_1 = 5000.0f;
    float damp = 0.999f;

    int[] Tet;
    int tet_number;         //The number of tetrahedra

    Vector3[] Force;
    Vector3[] V;
    Vector3[] X;
    int number;             //The number of vertices

    Matrix4x4[] inv_Dm;

    //For Laplacian smoothing.
    Vector3[] V_sum;
    int[] V_num;

    SVD svd = new SVD();

    // Start is called before the first frame update
    void Start()
    {
        // FILO IO: Read the house model from files.
        // The model is from Jonathan Schewchuk's Stellar lib.
        {
            string fileContent = File.ReadAllText("Assets/house2.ele");
            string[] Strings = fileContent.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

             tet_number=int.Parse(Strings[0]);
            //tet_number = 1;
            Tet = new int[tet_number * 4];

            for (int tet = 0; tet < tet_number; tet++)
            {
                Tet[tet * 4 + 0] = int.Parse(Strings[tet * 5 + 4]) - 1;
                Tet[tet * 4 + 1] = int.Parse(Strings[tet * 5 + 5]) - 1;
                Tet[tet * 4 + 2] = int.Parse(Strings[tet * 5 + 6]) - 1;
                Tet[tet * 4 + 3] = int.Parse(Strings[tet * 5 + 7]) - 1;
            }
        }
        {
            string fileContent = File.ReadAllText("Assets/house2.node");
            string[] Strings = fileContent.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            number = int.Parse(Strings[0]);
            X = new Vector3[number];
            for (int i = 0; i < number; i++)
            {
                X[i].x = float.Parse(Strings[i * 5 + 5]) * 0.4f;
                X[i].y = float.Parse(Strings[i * 5 + 6]) * 0.4f;
                X[i].z = float.Parse(Strings[i * 5 + 7]) * 0.4f;
            }
            //Centralize the model.
            Vector3 center = Vector3.zero;
            for (int i = 0; i < number; i++) center += X[i];
            center = center / number;
            for (int i = 0; i < number; i++)
            {
                X[i] -= center;
                float temp = X[i].y;
                X[i].y = X[i].z;
                X[i].z = temp;
            }
        }
        /*tet_number=1;
        Tet = new int[tet_number*4];
        Tet[0]=0;
        Tet[1]=1;
        Tet[2]=2;
        Tet[3]=3;

        number=4;
        X = new Vector3[number];
        V = new Vector3[number];
        Force = new Vector3[number];
        X[0]= new Vector3(0, 0, 0);
        X[1]= new Vector3(1, 0, 0);
        X[2]= new Vector3(0, 1, 0);
        X[3]= new Vector3(0, 0, 1);*/


        //Create triangle mesh.
        Vector3[] vertices = new Vector3[tet_number * 12];
        int vertex_number = 0;
        for (int tet = 0; tet < tet_number; tet++)
        {
            vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 1]];

            vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 2]];

            vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 3]];

            vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
        }

        int[] triangles = new int[tet_number * 12];
        for (int t = 0; t < tet_number * 4; t++)
        {
            triangles[t * 3 + 0] = t * 3 + 0;
            triangles[t * 3 + 1] = t * 3 + 1;
            triangles[t * 3 + 2] = t * 3 + 2;
        }
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();


        V = new Vector3[number];
        Force = new Vector3[number];
        V_sum = new Vector3[number];
        V_num = new int[number];

        //TODO: Need to allocate and assign inv_Dm

        inv_Dm = new Matrix4x4[tet_number];
        for (int tet = 0; tet < tet_number; tet++)
        {
            inv_Dm[tet] = Build_Edge_Matrix(tet).inverse;
        }
    }

    Matrix4x4 Build_Edge_Matrix(int tet)
    {
        Matrix4x4 ret = Matrix4x4.zero;
        Vector3 X_10 = X[Tet[tet * 4 + 1]] - X[Tet[tet * 4 + 0]];
        Vector3 X_20 = X[Tet[tet * 4 + 2]] - X[Tet[tet * 4 + 0]];
        Vector3 X_30 = X[Tet[tet * 4 + 3]] - X[Tet[tet * 4 + 0]];
        //TODO: Need to build edge matrix here.
        ret.SetColumn(0, new Vector4(X_10.x, X_10.y, X_10.z, 0.0f));
        ret.SetColumn(1, new Vector4(X_20.x, X_20.y, X_20.z, 0.0f));
        ret.SetColumn(2, new Vector4(X_30.x, X_30.y, X_30.z, 0.0f));
        ret.SetColumn(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f));

        return ret;
    }


    void _Update()
    {
        // Jump up.
        if (Input.GetKeyDown(KeyCode.Space))
        {
            for (int i = 0; i < number; i++)
                V[i].y += 0.2f;
        }

        for (int i = 0; i < number; i++)
        {
            //TODO: Add gravity to Force.
            Force[i] = new Vector3(0, -9.8f, 0) * mass;
        }

        for (int tet = 0; tet < tet_number; tet++)
        {
            //TODO: Deformation Gradient
            Vector3 x_10 = X[Tet[tet * 4 + 1]] - X[Tet[tet * 4 + 0]];
            Vector3 x_20 = X[Tet[tet * 4 + 2]] - X[Tet[tet * 4 + 0]];
            Vector3 x_30 = X[Tet[tet * 4 + 3]] - X[Tet[tet * 4 + 0]];
            Matrix4x4 Dm = new Matrix4x4();
            Dm.SetColumn(0, new Vector4(x_10.x, x_10.y, x_10.z, 0.0f));
            Dm.SetColumn(1, new Vector4(x_20.x, x_20.y, x_20.z, 0.0f));
            Dm.SetColumn(2, new Vector4(x_30.x, x_30.y, x_30.z, 0.0f));
            Dm.SetColumn(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f));

            Matrix4x4 F = Dm * inv_Dm[tet];

            //TODO: Green Strain
            Matrix4x4 G = M_times_scalar(0.5f, M_minus_M(F.transpose * F, Matrix4x4.identity));

            //TODO: Second PK Stress
            Matrix4x4 SPS = M_plus_M(M_times_scalar(2 * stiffness_1, G), M_times_scalar(stiffness_0 * trace_M(G), Matrix4x4.identity));

            Matrix4x4 P = F * SPS;
            //TODO: Elastic Force
            Matrix4x4 EForce = M_times_scalar(-1.0f / (6.0f * inv_Dm[tet].determinant), P * inv_Dm[tet].transpose);


            Vector3 f1 = new Vector3(EForce.GetColumn(0).x, EForce.GetColumn(0).y, EForce.GetColumn(0).z);
            Vector3 f2 = new Vector3(EForce.GetColumn(1).x, EForce.GetColumn(1).y, EForce.GetColumn(1).z);
            Vector3 f3 = new Vector3(EForce.GetColumn(2).x, EForce.GetColumn(2).y, EForce.GetColumn(2).z);
            Vector3 f0 = -(f1 + f2 + f3);

            Force[Tet[tet * 4 + 0]] += f0;
            Force[Tet[tet * 4 + 1]] += f1;
            Force[Tet[tet * 4 + 2]] += f2;
            Force[Tet[tet * 4 + 3]] += f3;
        }

        for (int i = 0; i < number; i++)
        {
            //TODO: Update X and V here.
            
            V[i] = V[i] + Force[i] * dt / mass;
            V[i] = damp * V[i];
            X[i] = X[i] + V[i] * dt;


            //TODO: (Particle) collision with floor.
            if (X[i].y < -3)
            {
                X[i].y = -3;
                V[i] = V[i] * 0.5f;
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
        for(int l=0; l<10; l++)_Update();

        // Dump the vertex array for rendering.
        Vector3[] vertices = new Vector3[tet_number * 12];
        int vertex_number = 0;
        for (int tet = 0; tet < tet_number; tet++)
        {
            vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
            vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
        }
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.vertices = vertices;
        mesh.RecalculateNormals();
    }

    private Matrix4x4 M_minus_M(Matrix4x4 lhs, Matrix4x4 rhs)
    {
        Matrix4x4 A = Matrix4x4.zero;
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                A[i, j] = lhs[i, j] - rhs[i, j];
            }
        }
        // Metion here, if A[3,3] == 0 then the matrix is sigular, which doesn't have a inverse, 
        // however, in the singular case, the inverse is Matrix.zero;
        A[3, 3] = 1;
        return A;

    }

    private Matrix4x4 M_plus_M(Matrix4x4 lhs, Matrix4x4 rhs)
    {
        Matrix4x4 A = Matrix4x4.zero;
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                A[i, j] = lhs[i, j] + rhs[i, j];
            }
        }
        // Metion here, if A[3,3] == 0 then the matrix is sigular, which doesn't have a inverse, 
        // however, in the singular case, the inverse is Matrix.zero;
        A[3, 3] = 1;
        return A;
    }

    private Matrix4x4 M_times_scalar(float scalar, Matrix4x4 rhs)
    {
        Matrix4x4 A = Matrix4x4.zero;
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                A[i, j] = scalar * rhs[i, j];
            }
        }
        // Metion here, if A[3,3] == 0 then the matrix is sigular, which doesn't have a inverse, 
        // however, in the singular case, the inverse is Matrix.zero;
        A[3, 3] = 1;
        return A;

    }


    private float trace_M(Matrix4x4 lhs)
    {

        return lhs[0, 0] + lhs[1, 1] + lhs[2, 2];
    }

}

标签:仿真,有限元,int,Tet,Vector3,number,体积,new,tet
From: https://www.cnblogs.com/asmurmur/p/18077522

相关文章

  • 基于Volterra级数的DFE判决反馈均衡器可见光通信系统误码率matlab仿真
    1.算法运行效果图预览   2.算法运行软件版本matlab2022a 3.算法理论概述      Volterra级数是一种描述非线性系统行为的强大工具。在一个非线性系统中,输出信号y(t)可以通过输入信号x(t)的多个卷积和来表示,形成所谓的Volterra级数。第一阶Volterra核(线性部......
  • m基于深度学习的肉类新鲜度检测系统matlab仿真,带GUI操作界面
    1.算法仿真效果matlab2022a仿真结果如下:  2.算法涉及理论知识概要       数据采集:获取肉类样品在不同新鲜度阶段的图像数据,通常使用高分辨率相机拍摄并标注对应的新鲜度等级。       GoogleNet模型因其独特的“inception”模块而得名,这种模块设计......
  • ANSYS HFSS WIFI 2.4G&5.8G双频板载天线仿真
    1.设计信息板材DR:4.4板厚:1.6mm天线频段:2.4GHz、5.8GHz 2.计算出2.4GHz、5.8GHz对应的介质波长、空间波长,利用公式:λ=c/f计算2.45GHz:58~122mm1/4介质波长~1/4空间波长:14.5~31.5mm 5.8GHz:25~52mm1/4介质波长~1/4空间波长:6~13mm 3. 天线初步规划设计参数 4.打......
  • 智能交通系统设计:基于MATLAB的智能交通系统设计和仿真,包括交通流仿真、交通信号控制和
    鱼弦:公众号【红尘灯塔】,CSDN内容合伙人、CSDN新星导师、全栈领域优质创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen)基于MATLAB的智能交通系统设计:原理、应用、实现与分析1.智能交通系统概述1.1......
  • 基于51单片机的锅炉控制【热电偶,数码管,PID】(仿真)
    1、使用N型热电偶测量锅炉内部温度2、设置温度值,温度低于设定值则启动加热3、加热过程使用PID控制,PID参数固定4、数码管显示温度5、温度过限报警#include"lcd1602.h"voiddelay_uint(uinti){ while(i--);}/**************************************************......
  • 基于51单片机的波形发生器【矩形波,三角波,锯齿波,固定频率,】(仿真)
    #include"lcd1602.h"voiddelay_uint(uinti){ while(i--);}/*********************************************************************名称:write_com(ucharcom)*功能:1602命令函数*输入:输入的命令值*输出:无*********************************......
  • NX mcd和Matlab通过opc服务器通讯仿真
    1,先在KEPServerEX6Configuration中建立simulator,搭建opc服务器。2,在这个通道下建立一个设备。3,建立一个节点,设置数据类型以及地址。(扫描速率最低可以调节到10)4.在matlab中建立opc的客户端,用于发送数据。5,在matlab中找到opc服务器并连接,并和节点建立连接。6,向KEPServerE......
  • Matlab Simulink 电力电子仿真-三相桥式全控整流电路分析
     一、三相桥式全控整流电路仿真模型1.电路模型    三相桥式全控整流电路是一种常见的整流电路,用于将三相交流电转换为直流电。电路通常由六个晶闸管(SCR)组成,以实现对电流的控制。 在三相桥式全控整流电路中,每个相都包含两个可控硅器件,分别连接在桥式整流电路的......
  • 0080-基于单片机的智能水杯仿真设计
    功能描述1、采用51单片机作为主控芯片;2、采用1602液晶显示:当前时间、喝水定时、水温、水量(水余量/喝水量);4、采用DS1302时钟芯片;5、采用PCF8591作为水量检测ADC;6、能够自动计算单次喝水量;7、采用18B20传感器检测水温;8、到喝水定时的时间,声光报警提醒;9、可通过按键随时......
  • 【雷达】基于Matlab模拟固定雷达LFM信号的仿真与压缩,建立了对移动目标的回波模型
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......