如何有效地从我的代码中获取稀疏复杂矩阵到 PETSc

计算科学 矩阵 宠物 表现 正则 稀疏矩阵
2021-11-29 11:08:22

从我的 Fortran 代码到 PETSc 获取复杂稀疏矩阵的最有效方法是什么?我知道这取决于问题,所以我试图在下面提供尽可能多的相关细节。

我一直在使用 FEAST 特征值求解器 [1] 来解决此类问题Ax=λBx, 矩阵的维数ABN, 几乎所有的时间都花在解决问题上N×NM0 右手边的复线性系统。N 很大(FE 基函数的数量,在 3D 中),M0 很小(在我的情况下,我对 M0 ~ 20 感兴趣)。矩阵AB是真实的、对称的和稀疏的,需要解决的复杂问题是zAB, 在哪里z是一个复数。FEAST 的作者似乎建议,为了获得高精度的特征值和特征向量,该线性系统的解的精度不必非常高,因此一些快速迭代求解器可能是一个很好的解决方案。

到目前为止,我一直只是将 Lapack 用于复杂系统,这对N<1500在我的电脑上。对于较大的N,我还不知道最好的求解器是什么,所以我只想使用 PETSc 并在那里使用迭代求解器。

我编写了一个简单的 C 驱动程序,并从 Fortran 调用它,所有代码请参见 [2],但问题仅在于这部分(更新:我已将所有行都放在此处以创建矩阵,正如我刚刚意识到的那样这是相关的):

ierr = MatCreate(PETSC_COMM_WORLD,&A);CHKERRQ(ierr);
ierr = MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,n,n);CHKERRQ(ierr);
ierr = MatSetFromOptions(A);CHKERRQ(ierr);
ierr = MatSetOption(A,MAT_IGNORE_ZERO_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
ierr = MatSetUp(A);CHKERRQ(ierr);
for (i=0; i<n; i++) col[i] = i;
ierr = MatSetValues(A,n,col,n,col,A_,INSERT_VALUES);CHKERRQ(ierr);

这非常慢(即对于 N~1500,这可能需要 2 秒,而实际上解决它是立即的),实际上这MatSetValues条线几乎花费了整个特征值计算的 100% 时间......矩阵 A_ 是来自 Fortran 的二维矩阵。我试图禁用它,MAT_IGNORE_ZERO_ENTRIES但它没有任何区别。所以我认为问题很简单,即使对于像 1500 这样的中等 N,我也需要使用一些稀疏矩阵格式,对吗?

所以我在我的 Fortran 代码中实现了 CSR 格式AB矩阵(或对于zAB) 现在我正试图弄清楚如何有效地将其提供给 PETSc。现在,我只想让一些东西按顺序工作,这比 Lapack 好。我应该MatCreateSeqAIJWithArrays为此使用该功能吗?

这是最有效的方法吗?由于矩阵AB不要改变,只有复数zFEAST 算法和 FE 计算中的变化,我认为两者AB具有相同的稀疏结构,可以通过预先分配稀疏结构然后快速评估来进一步改进zAxBx在每次 FEAST 迭代中(Ax,Bx是 CSR 格式的值数组),我可以在 Fortran 中轻松做到这一点,但可能总是调用很慢MatCreateSeqAIJWithArrays,所以一旦矩阵在 PETSc 中完成所有这些可能会更快AB被转移过来。

我想知道这种 CSR 解决这个问题的方法是否正确,或者我做错了(显然我最初的方法MatSetValues不是最优的)。感谢您的任何提示。

[1] http://www.ecs.umass.edu/~polizzi/feast/

[2] https://github.com/certik/hfsolver/pull/14

[3] http://www.mcs.anl.gov/petsc/petsc-3.1/docs/manualpages/Mat/MatCreateSeqAIJWithArrays.html

1个回答

正确预分配很重要。这几乎可以肯定是您的组装速度缓慢的原因。如果您从密集矩阵表示开始,只需扫描一次,计算每行的非零数,然后调用MatSeqAIJSetPreallocation(). 请参阅此常见问题解答MAT_IGNORE_ZERO_ENTRIES当那些原本密集的块中存在一些轻微的稀疏性而不是从密集矩阵一次调用中构建整个矩阵时,实际上打算使用该选项。出于这个原因,它不会根据那个块的稀疏性自动进行预分配。

创建一个密集的中间矩阵不是内存可扩展的,所以你最终会想要避免它。MatSetValues()实际上是用于稀疏矩阵中的逻辑密集块。您通常每行调用一次(或行组,典型的 FD 方法)或每个元素调用一次(典型的 FEM 方法)。如果您正在翻译现有的组装稀疏矩阵,只需MatSetValues()每行调用一次。如果您希望跳过中间矩阵(更好的性能和更低的内存),只需MatSetValues()每个元素调用一次。

请注意,您可以直接从 Fortran 调用 PETSc,尽管在基本 Fortran 77 和最新版本之间的每种 Fortran 方言都有用户。作为对最新功能的热切采用者,这些界面对您来说看起来相当粗糙。我们将不胜感激有关改进对最新方言支持的可维护方法的建议。