首页/文章/ 详情

Windows下可用!开源高性能稀疏矩阵迭代法C++求解库amgcl

3小时前浏览3
在之前的文章中已经指出,直接法和迭代法是求解大型稀疏矩阵的两种常见方法。
对于千万自由度的求解,以krylov子空间为基础的共轭梯度法,广义最小残差法等方法十分具有吸引力,其相对于直接法需要的内存空间显著减小,在合适的预处理条件下,需要的迭代次数也并不多,求解效率明显高于直接法。
在实践中,对于Krylov子空间这一系列的迭代法选取合适的预处理条件是一个影响效率的关键性问题。
合理的预处理条件使得迭代次数明显减少,求解效率大幅提高,然而实际上目前并没有一个通用的预处理方法使得所有的偏微分方程问题对应的稀疏矩阵都能够高效求解,选取何种预处理条件方法往往十分依赖经验。
常见的预处理条件包括雅克比预处理,高斯赛德尔预处理,不完全LU分解预处理,多重网格预处理等。
其中,多重网格预处理的适应性是很强的,其能够针对粗网格和细网格对于残差的不同影响在粗网格上和细网格上进行处理,从而显著减少迭代次数。在知名非线性有限元软件Abaqus中,其采用迭代法时,对应的预处理方式是一种叫AMG的多重网格预处理,这种方法叫代数多重网格预处理:

多重网格预处理的具体思路是对于一个稀疏矩阵线性方程组系统,常规的雅克比预处理,高斯赛德尔预处理等方法能够对残差的“高频”部分进行有效地衰减,这里衰减指的是随着迭代次数的增加值迅速减小,但是对于低频部分衰减很慢,因此需要更多的迭代次数才能使得残差满足要求,在多重网格法里面,这种迭代被称为光滑。对于衰减缓慢的低频部分,我们可以通过将其放到粗网格上进行迭代,从而在粗网格上迭代衰减这些低频部分,这个过程叫做校正。
通过光滑-校正的多次使用,从而使得残差迅速的收敛。对于代数多重网格AMG来说,在实际操作中并不需要多次对几何划分多层次的网格,而是以代数矩阵的形式来表征粗网格,因此使用上较为方便。有研究表明,对于椭圆型偏微分方程,多重网格预处理方法效果很好。
上面仅仅是一个多重网格的粗略介绍,实际上,这种方法在编程上极为复杂,需要非常繁杂的脑力劳动才能编写出多重网格的代码。本文主要是介绍一个开源的多重网格预处理C++库amgcl,通过使用该库,我们可以方便地实现预处理共轭梯度法等方法求解大型稀疏矩阵线性方程组。
Amgcl的源码链接如下:
https://github.com/ddemidov/amgcl
这是一个head-only开源库,使用起来也很简单,不需要编译即可使用,这相比于petsc在windows下的复杂操作要方便许多,其主要组件包括Backends,Matrix Adapters,Iterative Solvers,Preconditioners等。通过这些组件,amgcl可以实现多种并行类型/矩阵数据结构的稀疏矩阵线性方程组求解。
下面以官方的第一个例子为例,说明Amgcl中各个组件是具体怎么用的:



































































































#include <vector>#include <iostream>

#include <amgcl/backend/builtin.hpp>#include <amgcl/adapter/crs_tuple.hpp>#include <amgcl/make_solver.hpp>#include <amgcl/amg.hpp>#include <amgcl/coarsening/smoothed_aggregation.hpp>#include <amgcl/relaxation/spai0.hpp>#include <amgcl/solver/bicgstab.hpp>

#include <amgcl/io/mm.hpp>#include <amgcl/profiler.hpp>

int main(int argc, char *argv[]) {// The matrix and the RHS file names should be in the command line options:if (argc < 3) {std::cerr << "Usage: " << argv[0] << " <matrix.mtx> <rhs.mtx>" << std::endl;return 1;}

// The profiler:amgcl::profiler<> prof("poisson3Db");

// Read the system matrix and the RHS:ptrdiff_t rows, cols;std::vector<ptrdiff_t> ptr, col;std::vector<double> val, rhs;

prof.tic("read");std::tie(rows, cols) = amgcl::io::mm_reader(argv[1])(ptr, col, val);std::cout << "Matrix " << argv[1] << ": " << rows << "x" << cols << std::endl;

std::tie(rows, cols) = amgcl::io::mm_reader(argv[2])(rhs);std::cout << "RHS " << argv[2] << ": " << rows << "x" << cols << std::endl;prof.toc("read");

// We use the tuple of CRS arrays to represent the system matrix.// Note that std::tie creates a tuple of references, so no data is actually// copied here:auto A = std::tie(rows, ptr, col, val);

// Compose the solver type//   the solver backend:typedef amgcl::backend::builtin<double> SBackend;//   the preconditioner backend:#ifdef MIXED_PRECISIONtypedef amgcl::backend::builtin<float> PBackend;#elsetypedef amgcl::backend::builtin<double> PBackend;#endif

typedef amgcl::make_solver<amgcl::amg<PBackend,amgcl::coarsening::smoothed_aggregation,amgcl::relaxation::spai0>,amgcl::solver::bicgstab<SBackend>> Solver;

// Initialize the solver with the system matrix:prof.tic("setup");Solver solve(A);prof.toc("setup");

// Show the mini-report on the constructed solver:std::cout << solve << std::endl;

// Solve the system with the zero initial approximation:int iters;double error;std::vector<double> x(rows, 0.0);

prof.tic("solve");std::tie(iters, error) = solve(A, rhs, x);prof.toc("solve");

// Output the number of iterations, the relative error,// and the profiling data:std::cout << "Iters: " << iters << std::endl<< "Error: " << error << std::endl<< prof << std::endl;}
上面是一个求解三维泊松偏微分方程的例子,其数据是通过从文件中读取获得。我们主要关注中间的设置求解的部分:























typedef amgcl::backend::builtin<double> SBackend;//   the preconditioner backend:#ifdef MIXED_PRECISIONtypedef amgcl::backend::builtin<float> PBackend;#elsetypedef amgcl::backend::builtin<double> PBackend;#endif

typedef amgcl::make_solver<amgcl::amg<PBackend,amgcl::coarsening::smoothed_aggregation,amgcl::relaxation::spai0>,amgcl::solver::bicgstab<SBackend>> Solver;

// Initialize the solver with the system matrix:prof.tic("setup");Solver solve(A);prof.toc("setup");
这里,typedef amgcl::backend::builtin<double> SBackend定义了一个名为Sbackend的backends组件,这个组件的类型是amgcl::backend::builtin<double>,在amgcl里这种类型适配的是openmp并行,这表明,绑定到Sbackend这个组件类型的求解方法(即后面的Solver)在求解时可以进行openmp并行求解。在这里,在后面的代码中可以看到这个Sbackend被用于
“amgcl::solver::bicgstab<SBackend>”
中,表明Solver的迭代过程可以使用openmp并行求解。
类似,代码中还定义了PBackend,那这个Pbackend是表明Solver在预处理时可以使用openmp并行求解。
通过Backend这种绑定的方式,我们可以实现各种类型的数据结构与预处理,迭代求解并行方式的适配。除了builtin外,其他的Backend包括例如cuda,eigen等。
在性能上,根据官网提供的对比,其与其他知名的大型稀疏矩阵求解库petsc,trilinos等求解效率基本在同一梯队,甚至超过petsc和trilinos。

因此,在windows下,如果想使用迭代求解器求解大型稀疏矩阵线性方程组,amgcl实际上是一个不错的选择。在开源协议方面,这个库使用的是MIT这种宽松的协议,即使是商用也很方便。
以上,即是本文的全部内容,感谢阅读!

来源:有限元术
ACTSystemAbaqus非线性通用UMProfili
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2024-12-13
最近编辑:3小时前
寒江雪_123
硕士 | cae工程师 签名征集中
获赞 49粉丝 108文章 59课程 9
点赞
收藏
作者推荐

¥30 5.0
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈