我的并行程序需要调用 hypre 求解一个三维的 Poisson 方程。总体的感觉 hypre 还是挺方便的,当然 hypre 本身提供了结构网格(Struct)和半结构 (SStruct) 网格,以及有限元的界面,我只用到了结构网格。但我的程序和通常有点不同, 我自身的程序就是并行的, 已经将网格分片存储在各个进程上,而要求解的物理量是定义在结点上的,调用 hypre 时首先也要定义网格,而 hypre 只支持定义在网格中心的量的求解。这就导致我自身程序的网格和 hypre 的网格有区别(中心是结点,结点是中心),程序为了得到 Poisson 方程的解,我需要利用 hypre 解向量中影像区的值 …
我写了个简单的例子测试了一下,网格是2维 2×2 的网格,结点只有4个: (0,0), (0,1), (1,0), (1,1).
代码如下:
if (rank == 0) {
ilower[0] = 0; ilower[1] = 0;
iupper[0] = 0; iupper[1] = 0;
HYPRE_StructGridSetExtents(poisson_grid, ilower, iupper);
ilower[0] = 0; ilower[1] = 1;
iupper[0] = 0; iupper[1] = 1;
HYPRE_StructGridSetExtents(poisson_grid, ilower, iupper);
} else {
ilower[0] = 1; ilower[1] = 0;
iupper[0] = 1; iupper[1] = 0;
HYPRE_StructGridSetExtents(poisson_grid, ilower, iupper);
ilower[0] = 1; ilower[1] = 1;
iupper[0] = 1; iupper[1] = 1;
HYPRE_StructGridSetExtents(poisson_grid, ilower, iupper);
}
将网格分在两个进程上,每个上面两个结点,每个结点是一个 box. 计算发现对 (0,0) 这个box, hypre 会自动填充影像区中(0,1) 和 (1,0) 两个结点的值,而不会填充 (1,1) 的值。其他 box 也有类似的问题。
说清楚这个问题真不容易, 网上搜索也找不到有用的东西。就决定骚扰一下 hypre 作者,发信问他该如何填充影像区,可能是没表达清楚,对方回答成了另一个问题: 要打印影像区的值该如何如何 … 折腾了几天,突然想到可能 hypre 并不会填充影像区所有值,而只会填充需要的,而哪些是需要的是由用户由 hypre 中的 stencil 指定的。对上例, 我定义的 stencil 由五点组成,即每个点和周围的四个点有关:
int offsets[5][2] = {{-1,0}, {1,0}, {0,0},{0,-1},{0,1}};
HYPRE_StructStencil stencil;
HYPRE_StructStencilCreate(2, 5, &stencil);
for (s = 0; s < 5; s++)
{
HYPRE_StructStencilSetElement(stencil, s, offsets[s]);
}
(0,0) 和 (1,1) 并没有关系, 所以 hypre 不会填充影像区中 (1,1) 和这个点的值。于是把 stencil 改成和周围 8 个点有关(不知道为什么 stencil 并不能任意改, 改的不对程序就会报错),正像我想的一样,(1,1) 也被填充了。
虽然只是猜测,并不知道 hypre 内部具体怎么实现的, 但经测试和所想的一样,并且三维的也对,就先这么用了.