如何高效地assemble一个FEM稀疏矩阵
How to efficiently assemble a FEM sparse matrix
全部交易,
感谢您花时间阅读我的问题。
我正在使用 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 代码中,对于稀疏矩阵 assemble 部分,假设函数是:
FormFE(const Ref<VectorXd> &U,const Ref<VectorXd> &V,
Ref<SparseMatrix<double> > AMATRIX,Ref<VectorXd> RHS)
其中U代表位移,V代表速度项。 AMATRIX 是我的稀疏矩阵,RHS 是残差项。
然后我尝试在 assemble 之前先初始化我的 AMATRIX(我有一个包含所有非零元素及其值的 tripletList(我将值设置为零以进行初始化))
所以我尝试了:
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
其实我的问题是:
- 如何高效使用Eigen(尤其是FEM计算),我几乎在每个FEM相关函数中都使用了Eigen的VectorXd和MatrixXd。
- 如何高效地assemble一个稀疏矩阵?
- 是否可以为 FEM 做一些 OpenMP 并行化 assemble?
- 欢迎对基于 C++ 的 FEM 编码提出任何有用的建议(库推荐或任何有用的想法)!
谢谢。
最好的问候。
是的,传递 SparseMatrix<double> &
是正确的做法。 Ref<SparseMatrix>
的目的是传递类似于 SparseMatrix
的组装对象,例如子稀疏矩阵,Map<SparseMatrix>
...
使用 setFromTriplets 也是确保获得良好性能的正确做法。如果操作正确(即正确调用保留和正确的插入顺序),使用 mat.insert(i,j) = val;
直接插入元素可能会快 2 倍。但如果你弄错了,它也会慢 100 倍......请参阅文档。使用 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<double,RowMajor>
。当然,您可以调整此模式以处理 columns/rows 等块
如果您需要使用一些密集的程序集 matrix/vectors,那么我相信它们非常小且大小固定。那么不要使用 MatrixXd/VectorXd,最好使用静态分配的 Matrix<double,N,M>
和 Matrix<double,N,1>
类型。这将防止大量内存allocation/deallocation.
最后,最重要的建议:如果您关心性能,请不要忘记分析您的代码,然后再调查时间和优化代码的努力。此外,始终 bench/profile 编译器优化开启。
全部交易, 感谢您花时间阅读我的问题。 我正在使用 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 代码中,对于稀疏矩阵 assemble 部分,假设函数是:
FormFE(const Ref<VectorXd> &U,const Ref<VectorXd> &V,
Ref<SparseMatrix<double> > AMATRIX,Ref<VectorXd> RHS)
其中U代表位移,V代表速度项。 AMATRIX 是我的稀疏矩阵,RHS 是残差项。
然后我尝试在 assemble 之前先初始化我的 AMATRIX(我有一个包含所有非零元素及其值的 tripletList(我将值设置为零以进行初始化)) 所以我尝试了:
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
其实我的问题是:
- 如何高效使用Eigen(尤其是FEM计算),我几乎在每个FEM相关函数中都使用了Eigen的VectorXd和MatrixXd。
- 如何高效地assemble一个稀疏矩阵?
- 是否可以为 FEM 做一些 OpenMP 并行化 assemble?
- 欢迎对基于 C++ 的 FEM 编码提出任何有用的建议(库推荐或任何有用的想法)!
谢谢。 最好的问候。
是的,传递 SparseMatrix<double> &
是正确的做法。 Ref<SparseMatrix>
的目的是传递类似于 SparseMatrix
的组装对象,例如子稀疏矩阵,Map<SparseMatrix>
...
使用 setFromTriplets 也是确保获得良好性能的正确做法。如果操作正确(即正确调用保留和正确的插入顺序),使用 mat.insert(i,j) = val;
直接插入元素可能会快 2 倍。但如果你弄错了,它也会慢 100 倍......请参阅文档。使用 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<double,RowMajor>
。当然,您可以调整此模式以处理 columns/rows 等块
如果您需要使用一些密集的程序集 matrix/vectors,那么我相信它们非常小且大小固定。那么不要使用 MatrixXd/VectorXd,最好使用静态分配的 Matrix<double,N,M>
和 Matrix<double,N,1>
类型。这将防止大量内存allocation/deallocation.
最后,最重要的建议:如果您关心性能,请不要忘记分析您的代码,然后再调查时间和优化代码的努力。此外,始终 bench/profile 编译器优化开启。