Hypre: MPI 并行求解器程序

在使用 Hypre 库的 IJ interface (IJDST) 编写 MPI 并行求解器程序时,主要流程包括:

  1. 初始化 Hypre;
  2. 创建并设置稀疏矩阵(HYPRE_IJMatrix);
  3. 创建并设置向量(HYPRE_IJVector);
  4. 选择和配置求解器(如 BoomerAMG、GMRES 等);
  5. 求解线性系统;
  6. 清理资源。

如果你的问题是迭代求解一个线性系统,其中稀疏结构不变,但数值每次变化,可以利用 Hypre 的特性进行优化,避免重复创建矩阵结构,只更新非零元素值。


🧩 一、基本结构:MPI 并行程序框架

#include <mpi.h>
#include "HYPRE_ij_mv.h"
#include "HYPRE_krylov.h"

int main(int argc, char *argv[]) {
    MPI_Init(&argc, &argv);

    int myid, num_procs;
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);

    // ... 定义变量

    HYPRE_IJMatrix A;
    HYPRE_IJVector b, x;

    // ... 初始化矩阵 A、右端项 b 和初始猜测 x

    HYPRE_Solver solver, precond;
    
    // ... 配置求解器与预条件子

    // 迭代求解循环
    for (int iter = 0; iter < max_iter; ++iter) {
        // 更新矩阵数值(结构不变)
        update_matrix_values(A, ...);

        // 更新 RHS 向量 b
        HYPRE_IJVectorSetValues(b, ...);

        // 重新组装矩阵和向量
        HYPRE_IJMatrixAssemble(A);
        HYPRE_IJVectorAssemble(b);

        // 求解
        HYPRE_ParCSRFactorize(A_par); // 如果使用直接求解器或需要 LU 分解
        HYPRE_Cycle(solver);          // 如 GMRES 或 AMG
    }

    // 清理
    HYPRE_IJMatrixDestroy(A);
    HYPRE_IJVectorDestroy(b);
    HYPRE_IJVectorDestroy(x);
    HYPRE_SolverDestroy(solver);

    MPI_Finalize();
    return 0;
}

🧱 二、如何设置 IJ Matrix(稀疏结构)

1. 创建 IJMatrix

HYPRE_Int ilower, iupper; // 当前进程负责的行范围
HYPRE_Int n_global;       // 全局自由度数
HYPRE_Int n_local;        // 当前进程的局部自由度数

// 假设为均匀分布
n_local = n_global / num_procs + ((myid < n_global % num_procs) ? 1 : 0);
ilower = 0;
for (int p = 0; p < myid; ++p)
    ilower += n_global / num_procs + ((p < n_global % num_procs) ? 1 : 0);
iupper = ilower + n_local - 1;

HYPRE_IJMatrixCreate(MPI_COMM_WORLD, ilower, iupper, ilower, iupper, &A);
HYPRE_IJMatrixSetObjectType(A, HYPRE_PARCSR); // 使用 ParCSR 格式
HYPRE_IJMatrixInitialize(A);

2. 设置矩阵结构(仅一次)

for (HYPRE_Int row = ilower; row <= iupper; ++row) {
    // 获取该行的列索引 cols[...]
    HYPRE_Int ncols = ...;
    HYPRE_Int cols[ncols] = {...};
    HYPRE_IJMatrixSetRowSizes(A, row, ncols);
}
HYPRE_IJMatrixSetDiagOffdSizes(A); // 可选,用于 ParCSR 性能优化

或者一次性设置所有行(如果已知每行非零个数):

HYPRE_Int *row_sizes = ...; // 每行非零元数量
HYPRE_IJMatrixSetRowSizes(A, row_sizes);

3. 第一次填充矩阵数值(初始化)

for (HYPRE_Int row = ilower; row <= iupper; ++row) {
    // 获取当前行的列索引 cols[...] 和系数 values[...]
    HYPRE_IJMatrixAddToEntries(A, row, ncols, cols, values);
}
HYPRE_IJMatrixAssemble(A);

🔁 三、如何在迭代中高效更新矩阵数值(结构不变)

✅ 方法:使用 HYPRE_IJMatrixSetValues()

注意:每次调用 HYPRE_IJMatrixSetValues() 前必须先调用 HYPRE_IJMatrixZeroValues() 来清空旧数据,否则会叠加!

HYPRE_IJMatrixZeroEntries(A); // 只清除数值,保留结构

for (HYPRE_Int row = ilower; row <= iupper; ++row) {
    // 获取当前行的列索引 cols[...] 和新的系数 new_values[...]
    HYPRE_IJMatrixSetValues(A, row, ncols, cols, new_values);
}

HYPRE_IJMatrixAssemble(A); // 必须再次 assemble

💡 提示:SetValues() 是覆盖写入,而 AddToValues() 是加法操作。


⚙️ 四、如何设置求解器(以 BoomerAMG + GMRES 为例)

HYPRE_BoomerAMGCreate(&precond);
HYPRE_BoomerAMGSetMaxLevels(precond, 20);
HYPRE_BoomerAMGSetStrongThreshold(precond, 0.25);
// 更多参数...

HYPRE_GMRESCreate(MPI_COMM_WORLD, &solver);
HYPRE_GMRESSetKDim(solver, 100);
HYPRE_GMRESSetTol(solver, 1e-8);
HYPRE_GMRESSetMaxIter(solver, 1000);
HYPRE_GMRESSetPrecond(solver,
                      HYPRE_BoomerAMGSolve,
                      HYPRE_BoomerAMGSetup,
                      precond);

// 将矩阵 A 转换为 ParCSRMatrix 类型供求解器使用
HYPRE_IJMatrixGetObject(A, (void**) &A_par);
HYPRE_GMRESSetup(solver, A_par, b_par, x_par);

🚀 五、性能优化建议

✅ 结构不变时避免重建矩阵

  • 只在第一次初始化时调用 HYPRE_IJMatrixCreate()HYPRE_IJMatrixInitialize()
  • 在后续迭代中,仅调用 HYPRE_IJMatrixZeroEntries()HYPRE_IJMatrixSetValues()

✅ 使用 ParCSR 格式提高效率

  • 设置 HYPRE_IJMatrixSetObjectType(A, HYPRE_PARCSR);
  • 若你知道每行的 diagonal/off-diagonal 非零元数目,可以调用:
    HYPRE_IJMatrixSetDiagOffdSizes(A);
    

✅ 预处理只在必要时重新 Setup

  • 如果系数变化不大,可跳过 HYPRE_GMRESSetup(),只调用 HYPRE_GMRESolve()
  • 或者每隔几次迭代才重新 setup 预条件子。

📌 六、完整参考代码片段(简化版)

HYPRE_IJMatrixCreate(MPI_COMM_WORLD, ilower, iupper, jlower, jupper, &A);
HYPRE_IJMatrixSetObjectType(A, HYPRE_PARCSR);
HYPRE_IJMatrixInitialize(A);

// 初始设置结构
for (row = ilower; row <= iupper; row++) {
    HYPRE_IJMatrixSetRowSizes(A, row, ncols);
}
HYPRE_IJMatrixSetDiagOffdSizes(A);

// 初始填充数值
for (row = ilower; row <= iupper; row++) {
    HYPRE_IJMatrixAddToEntries(A, row, ncols, cols, values);
}
HYPRE_IJMatrixAssemble(A);

// 创建求解器
HYPRE_BoomerAMGCreate(&precond);
HYPRE_GMRESCreate(MPI_COMM_WORLD, &solver);
HYPRE_GMRESSetPrecond(...);
HYPRE_GMRESSetup(...);

// 循环迭代
for (iter = 0; iter < max_iter; iter++) {
    HYPRE_IJMatrixZeroEntries(A);
    for (row = ilower; row <= iupper; row++) {
        compute_new_row_values(values);
        HYPRE_IJMatrixSetValues(A, row, ncols, cols, values);
    }
    HYPRE_IJMatrixAssemble(A);

    HYPRE_GMRESSolve(solver, A_par, b_par, x_par);
}

📘 参考文档

  • Hypre User Manual
  • examples/ij/ 目录下的官方示例程序(如 ij.c, parcsr_amgij.c
  • HYPRE_IJMatrix API 文档

如需我提供完整的可编译示例代码(比如 Poisson 方程求解),也可以告诉我!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值