第一种方法:使用稀疏矩阵的模式
您说的是二阶三角拉格朗日有限元,所以我想您熟悉一阶的“”-您知道如何使用线性元素组装由拉普拉斯或泊松方程产生的系统。
对于生成的矩阵,我们通常使用压缩的稀疏(下三角)列格式 CSlC(有关详细信息,请参阅SPARSKIT 文档或Harwell-Boeing 稀疏矩阵集合的用户指南)。
首先我们构建矩阵的模式(向量colptr
和rowind
),然后我们组装我们的系统。当一个有矩阵模式时,一个也有中间节点(或肋骨)的编号!
考虑以下网格和生成的矩阵模式:

我们有
colptr={1,3,6,10,11,11,12,12},rowind={1,7,3,4,7,4,5,6,7,5,7}.
为了得到元素(i,j)我们做的CSlC矩阵
for k = colptr[j], colptr[j] + 1, ..., colptr[j+1] - 1
if (i == rowind[k]) return values[k]
通常三角剖分中的任何顶点的度数约为 6,所以这个操作是O(1).
因此,如果您想获得多个连接顶点的肋骨i和j, 只需使用k从上面的算法。在我的图片中,连接顶点 3 和 7 的肋骨的编号为 9。
第二种方法:使用元素的邻居
你说的是相当结构化的网格。实际上,为了处理更复杂的几何图形,我们通常将网格表示为顶点向量 + 元素向量(顶点索引的三元组)。有时存储邻居向量(相邻元素索引的三元组)也很方便。一方面,Mathematica 在其网格抽象中这样做(参见 Scope > “ElementConnectivity”)。我敢打赌,所有流行的网格生成软件工具(例如gmsh)也可以做到这一点。
显然,如果您有邻居,则很容易枚举遍历元素的 ribs。我倾向于在我的项目中使用这种方法,因为我可以接触到邻居。
更新:
但我可以想象编号的选择会以一种关键的方式影响线性方程组
实际上,不同的自由度数对应于不同的矩阵模式。但是,如果要使用迭代求解器,则根本不应该关心这一点。
相反,如果想要使用某种基于 LU 分解的稀疏直接求解器,则应该关心自由度的计算,因为它对带宽(因此,内存)有至关重要的影响:CSC 型矩阵的 LU 分解可能是密集的;Skyline 矩阵的 LU 分解保留了稀疏模式。
然而,正如@BillGreene 和@anton-menshov 提到的,有一些算法可以最小化矩阵的带宽(即重新编号自由度)。在组装/选择 DOF 计数时,您不应该关心这一点。