【问题标题】:How to efficiently assemble a FEM sparse matrix如何有效地组装 FEM 稀疏矩阵
【发布时间】:2017-11-03 10:43:38
【问题描述】:

全部成交, 感谢您花时间阅读我的问题。 我正在使用 Eigen3.3.4(http://eigen.tuxfamily.org/index.php?title=Main_Page) 编写一些 FEM 代码。

我阅读了 Eigen3.3.4 文档,在这个网站 (http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html) 中,它说 我们应该使用Ref<MatrixBase>来避免额外的副本并获得高性能。

所以在我的 FEM 代码中,对于稀疏矩阵组装部分,假设函数是:

FormFE(const Ref<VectorXd> &U,const Ref<VectorXd> &V,
Ref<SparseMatrix<double> > AMATRIX,Ref<VectorXd> RHS)

其中 U 代表位移,V 代表速度项。 AMATRIX 是我的稀疏矩阵,RHS 是残差项。

然后我尝试在组装之前首先初始化我的 AMATRIX(我有一个包含所有非零元素及其值的三元组列表(我将值设置为零以进行初始化)) 所以我尝试了:

AMATRIX.setFromTriplets(ZeroTripList.begin(),ZeroTripList.end());

但我有一个错误:

class Eigen::Ref<Eigen::SparseMatrix<double, 0, int> >’ has no member named ‘setFromTriplets

那么我该如何解决这个问题呢?

我的一个解决方案是使用:

FormFE(const Ref<VectorXd> &U,const Ref<VectorXd> &V,
SparseMatrix<double> &AMATRIX,Ref<VectorXd> RHS)

这工作得很好,但我不确定它是否有效。 我不太擅长 cpp :P

其实我的问题是:

  1. 如何有效地使用 Eigen(尤其是 FEM 计算),我几乎在每个 FEM 相关函数中都使用 Eigen 的 VectorXd 和 MatrixXd。
  2. 如何高效组装 SparseMatrix?
  3. 是否可以为 FEM 组装做一些 OpenMP 并行化?
  4. 欢迎对基于 C++ 的 FEM 编码提出任何有用的建议(库推荐或任何有用的想法)!

谢谢。 最好的问候。

【问题讨论】:

  • 这与汇编编程有什么关系?
  • 嗨,我所有当前元素的系数都存储在一个tripletList中,所以我可以通过setFromTriplist进行组装。
  • 那不是汇编编程。这个词有特定的含义。
  • 对不起,这里的“组装”是指FEM的组装。
  • 我明白这一点。但是,标签 [assembly] 是错误的,因为该标签是针对用汇编编写的程序的。

标签: c++ matrix sparse-matrix eigen eigen3


【解决方案1】:

是的,在这里传递SparseMatrix&lt;double&gt; &amp; 是正确的做法。 Ref&lt;SparseMatrix&gt; 的目的是传递与 SparseMatrix 相似的组装对象,例如子稀疏矩阵 Map&lt;SparseMatrix&gt;...

使用 setFromTriplets 也是确保获得良好性能的正确做法。如果操作正确(即正确调用保留和正确的插入顺序),使用 mat.insert(i,j) = val; 直接插入元素可能会快 2 倍。但是如果你弄错了,它也可能会慢 x100 倍......请参阅文档。使用SparseMatrix::insert 也可以使用 OpenMP 填充矩阵,但这需要更加小心和严格,这是一个典型的模式:

int n_cols = ??, n_rows = ??;
std::vector<int> nnz_per_col(n_cols);
// set each nnz_per_col[j] to the exact number
// of non-zero entries in the j-th column (or more, but NOT less)
SparseMatrix<double> mat(n_rows, n_cols);
#pragma omp parallel for
for(int j=0; j<cols; ++j) {
  for each non zero entry i in the j-th column {
    // preferably with increasing i
    double val_i_j = ...;
    mat.insert(i,j) = val_i_j;
  }
}

当然,如果这对您来说更容易,您也可以按行工作。在这种情况下,使用SparseMatrix&lt;double,RowMajor&gt;。当然,您可以调整此模式以处理列/行块等。

如果您需要使用一些密集的矩阵/向量进行组装,那么我相信它们非常小且大小固定。然后,与其使用 MatrixXd/VectorXd,不如使用静态分配的 Matrix&lt;double,N,M&gt;Matrix&lt;double,N,1&gt; 类型。这将防止大量内存分配/释放。

最后,最重要的建议:如果您关心性能,请不要忘记分析您的代码,然后再花时间和精力优化您的代码。此外,始终打开编译器优化的基准/配置文件。

【讨论】:

  • 您好 ggael,非常感谢您的回复。你的建议真的很有帮助。我有一个问题,大小如何属于“小”。例如,如果我有一个 (27*5,27*5) 的密集矩阵,我的 rhs 是 (27*5,1) 向量。对于这种情况,使用 Matrix 方法还是更好吗?
  • 这不小,所以你可以留在MatrixXd
猜你喜欢
  • 2020-12-07
  • 2013-03-03
  • 2019-05-26
  • 1970-01-01
  • 2012-05-18
  • 2021-04-14
  • 2018-08-07
  • 2013-06-16
  • 2021-11-18
相关资源
最近更新 更多