Fortran scalapack中的行分配不一致
考虑以下简单的fortran程序Fortran scalapack中的行分配不一致,fortran,mpi,lapack,scalapack,Fortran,Mpi,Lapack,Scalapack,考虑以下简单的fortran程序 program test_vec_allocation use mpi implicit none integer(kind=8) :: N ! =========================BLACS and MPI======================= integer :: ierr, size, rank,dims(2) ! ----
program test_vec_allocation
use mpi
implicit none
integer(kind=8) :: N
! =========================BLACS and MPI=======================
integer :: ierr, size, rank,dims(2)
! -------------------------------------------------------------
integer, parameter :: block_size = 100
integer :: context, nprow, npcol, local_nprow, local_npcol
integer :: numroc, indxl2g, descmat(9),descvec(9)
integer :: mloc_mat ,nloc_mat ,mloc_vec ,nloc_vec
call blacs_pinfo(rank,size)
dims=0
call MPI_Dims_create(size, 2, dims, ierr)
nprow = dims(1);npcol = dims(2)
call blacs_get(0,0,context)
call blacs_gridinit(context, 'R', nprow, npcol)
call blacs_gridinfo(context, nprow, npcol, local_nprow,local_npcol)
N = 700
mloc_vec = numroc(N,block_size,local_nprow,0, nprow)
nloc_vec = numroc(1,block_size,local_npcol,0, npcol)
print *,"Rank", rank, mloc_vec, nloc_vec
call blacs_gridexit(context)
call blacs_exit(0)
end program test_vec_allocation
当我用11个mpi等级运行它时,我得到
Rank 0 100 1
Rank 4 100 1
Rank 2 100 1
Rank 1 100 1
Rank 3 100 1
Rank 10 0 1
Rank 6 100 1
Rank 5 100 1
Rank 9 0 1
Rank 8 0 1
Rank 7 0 1
这就是我希望scalapack将这个数组除以偶数个列的方式:
Rank 0 200 1
Rank 8 200 0
Rank 9 100 1
Rank 10 100 0
Rank 1 200 0
Rank 6 200 1
Rank 11 100 0
Rank 3 200 1
Rank 4 200 0
Rank 2 200 0
Rank 7 200 0
Rank 5 200 0
这是毫无意义的,为什么排名0的块大小为100,而排名*的块大小>N,会得到200个元素。
因此,我的程序适用于mpi等级1、2、3、5、7、11,但不适用于等级4、6、8、9、10、12等(我不知道为什么不适用于等级9!)。谁能解释一下我的方法有什么不对吗
GFortran版本:6.1.0
头皮包版本:2.1.0
MacOS版本:10.11您的代码有许多问题 1) 首先,不要使用整数(8)。正如弗拉基米尔所说,请忘记这一点。它不仅不可移植,因此是非常糟糕的做法(请参见此处的许多示例,例如)。这里它是错误的,因为
numroc
期望默认类型的整数作为其第一个参数(参见示例)
2) 在调用MPI_Init之前调用一个MPI例程,其中包含大量异常(这不是一个),这会导致未定义的行为。注意,处的描述没有提及实际调用MPI_Init。因此,我也更喜欢称MPI_为Finalize
3) 您误解了MPI\u Dims\u创建。你似乎假设你会得到一维分布,但实际上你要求得到二维分布。从标准中引用
数组DIM中的条目被设置为描述笛卡尔网格
具有ndims维度,共有nnodes节点。尺寸是
设置为尽可能靠近彼此,使用适当的
整除算法。调用者可以进一步约束调用
通过指定数组DIM的元素来操作此例程。如果
dims[i]设置为正数时,例程不会修改
维度i中的节点数;仅限dims[i]=0的条目
由调用修改
将dims设置为零,因此例程可以自由设置两个尺寸。因此,对于11个进程,您将得到一个1x11或11x1网格,这似乎是您所期望的。但是,对于12个过程,由于
尺寸设置为尽可能彼此接近
您将获得3x4或4x3网格,而不是12x1。如果每行的值为3x4,您希望numroc
返回3个进程,包含200个元素(2个块),1个进程包含100个元素。由于有3行,因此您希望3x3=9个进程返回200,3x1=3个进程返回100。这就是你看到的。也可以尝试15个进程-你会看到奇数个进程,根据你的说法“不起作用”,这是因为(高等数学警报)15=3x5。顺便说一句,在我的机器上,9进程没有返回3x3-在我看来,这就像openmpi中的一个错误。您的代码有很多地方出错
1) 首先,不要使用整数(8)。正如弗拉基米尔所说,请忘记这一点。它不仅不可移植,因此是非常糟糕的做法(请参见此处的许多示例,例如)。这里它是错误的,因为numroc
期望默认类型的整数作为其第一个参数(参见示例)
2) 在调用MPI_Init之前调用一个MPI例程,其中包含大量异常(这不是一个),这会导致未定义的行为。注意,处的描述没有提及实际调用MPI_Init。因此,我也更喜欢称MPI_为Finalize
3) 您误解了MPI\u Dims\u创建。你似乎假设你会得到一维分布,但实际上你要求得到二维分布。从标准中引用
数组DIM中的条目被设置为描述笛卡尔网格
具有ndims维度,共有nnodes节点。尺寸是
设置为尽可能靠近彼此,使用适当的
整除算法。调用者可以进一步约束调用
通过指定数组DIM的元素来操作此例程。如果
dims[i]设置为正数时,例程不会修改
维度i中的节点数;仅限dims[i]=0的条目
由调用修改
将dims设置为零,因此例程可以自由设置两个尺寸。因此,对于11个进程,您将得到一个1x11或11x1网格,这似乎是您所期望的。但是,对于12个过程,由于
尺寸设置为尽可能彼此接近
您将获得3x4或4x3网格,而不是12x1。如果每行的值为3x4,您希望numroc
返回3个进程,包含200个元素(2个块),1个进程包含100个元素。由于有3行,因此您希望3x3=9个进程返回200,3x1=3个进程返回100。这就是你看到的。也可以尝试15个进程-你会看到奇数个进程,根据你的说法“不起作用”,这是因为(高等数学警报)15=3x5。顺便说一句,在我的机器上,9进程没有返回3x3-这在我看来像openmpi中的一个错误。感谢您的见解,我使用MPI_Dims_create获取blacs_gridinit的nprow和npcol。你能指出一个我能以正确的方式实现相同功能的来源吗?这也为我的第二个问题铺平了道路,我想做一个矩阵向量乘法,然后计算范数并确定它,问题是那些没有分配向量元素的节点的范数为0.0000,因此测试失败。我应该修改当前问题还是询问其他问题?请您也提供意见好吗?请致电pdnrm2(N,norm,tmp_vec,1,1,descvec,1);如果(标准基本上在上述对pdnrm2的调用中,将0.000分配给其他行中的非参与进程。但是,在11个等级等情况下,norm被正确分配给非参与节点。如果您有单独的问题,请将其放在单独的问题中。如果您想要1*nproc网格,为什么需要调用mpi_dims_create?创建的所有mpi dims都会找到合适的f