从单元连接关系到节点邻接点-有限元中形成稀疏矩阵求解的前置工作

在有限元求解中,最终通常要求解的是一个关于场变量的线性方程组,在常见的位移场有限元中,要求解的是各个节点的位移,该线性方程组的系数矩阵通常称为刚度矩阵,方程组右边通常称为右端项或者荷载向量。一般情况下,由于网格划分后并不是所有节点都两两连接,因此实际上最终形成的整体刚度矩阵中大部分元素为0,这种矩阵称为稀疏矩阵。在有限元求解中,对于这种系数矩阵为稀疏矩阵的方程组,一种常见的方法是仅保存刚度矩阵的非0元素到内存中,0元素不保存,这样就可以以更小的内存保存大型结构的刚度矩阵。

那具体矩阵中有多少元素为0,就可以认为其是稀疏矩阵呢?这个界限实际上比较模糊,有文献给出如下定义:如果矩阵的A的非0元素数量为O(n),其中n是A的阶数,则矩阵为稀疏矩阵。

稀疏矩阵经常通过非0元素分布图表示其稀疏性质,以下是两个常见的稀疏矩阵的分布图:

从单元连接关系到节点邻接点-有限元中形成稀疏矩阵求解的前置工作的图1

从单元连接关系到节点邻接点-有限元中形成稀疏矩阵求解的前置工作的图2

在有限元分析中,非0元素的分布,实际上主要取决于单元的节点连接,以下图中的单元连接为例:

从单元连接关系到节点邻接点-有限元中形成稀疏矩阵求解的前置工作的图3

假设图中每个节点一个自由度,则整体刚度矩阵为16x16的矩阵,而具体非0元素的分布,可以通过单元连接得到邻接点得到,所谓邻接点,指的是相对于当前单元位于同一单元内的所有点的集合。以节点6为例,其邻接点是1,2,3,5,7,9,10,11。

获得上述邻接点后,刚度矩阵中第6行的非0元素的位置实际上就确定了:k(6,1),k(6,2),k(6,3),k(6,5),k(6,6),k(6,7),k(6,9),k(6,10),k(6,11)。

在实际采用稀疏矩阵求解有限元问题时,获得上述非0元素位置后,就可以对刚度矩阵采用稀疏矩阵存储,常见的存储方式有COO,CSR,CSC和DIA等。上面的网格数量较少,因此可以通过观察获得节点的邻接点,在实际有限元求解中,网格划分以后通常得到的是单元的节点连接信息,即各个单元分别有哪几个节点构成,并不能直接获得各个节点的邻接点,在上图中,网格划分后得到的单元的节点连接信息如下:

1    1    2    6    5

2    2    3    7    6

3    3    4    8    7

4    5    6   10    9

5    6    7   11   10

6    7    8   12   11

7    9   10   14   13

8   10   11   15   14

9   11   12   16   15

通过上述连接信息,就可以得到任一节点的邻接点,在这里,提供一个从上述节点连接获得节点邻接点的代码,节点连接信息按照上面的格式保存在element.txt中。

#include<iostream>
#include<vector>
#include <algorithm>
#include <fstream>
#include<map>
int main(int argc, char** argv)
{
     int nNode ;
     std::cout << "节点总数:" << std::endl;
     std::cin >> nNode;
    std::multimap<int,int> *nodeNear=new std::multimap<int,int>[nNode];
    int nElem;
    std::cout << "单元总数:" << std::endl;
    std::cin >> nElem;
    int elemNumber;
    std::vector<int> *elemConnect=new std::vector<int>[nElem];
    std::ifstream eFile("element.txt");
    if (!eFile) std::cerr << "open file failure" << std::endl;
    
    const int nNodePe=4;   
    int nodeN[nNodePe+1];
    for (int i = 0; i < nElem; i++)
    {
        for (int j = 0; j < nNodePe+1; j++)
        {
            eFile >> nodeN[j];
            elemConnect[i].push_back(nodeN[j]);
        }
        
    }
    for (int i = 0; i <nNode; ++i)
    {
        for (int j = 0; j<nElem; ++j)
        {
            auto a1 = std::find(elemConnect[j].begin()+1, elemConnect[j].end(), i);
            if (a1 != elemConnect[j].end())
            {
                for (auto it = elemConnect[j].begin()+1; it!= elemConnect[j].end(); it++)
                {
                    nodeNear[i].insert(std::pair<int,int>(*it,elemConnect[j][0]));
                }    
            }
        }    
    }
    std::cout << "输入节点号:" << std::endl;
    int nodeNumber;
    std::cin >> nodeNumber;
    std::cout << "邻近节点:" << std::endl;
    for (auto it:nodeNear[nodeNumber])
    {
        std::cout << "node  " << it.first <<"  in element  "<< it.second << std::endl;
    }
    delete[] nodeNear; delete[] elemConnect;
    return 0;
}



运行结果如下:

从单元连接关系到节点邻接点-有限元中形成稀疏矩阵求解的前置工作的图4


以上,就是从单元连接关系到节点邻接点的具体过程和代码,感谢您的阅读!

【完】

欢迎关注公众号  有限元术

从单元连接关系到节点邻接点-有限元中形成稀疏矩阵求解的前置工作的图5


默认 最新
当前暂无评论,小编等你评论哦!
点赞 评论 收藏
关注