我有一项任务,我将在一起拥有多种数据类型;字符,几个整数和双精度值,它们代表问题的解决方案。
目前,我有一个玩具" F90程序,它使用带有随机数的MPI和每个处理器的人为字符串。我想要一个具有字符和双精度随机数的数据类型。
我将使用MPI_REDUCE来获得双精度值的最小值。我将通过MPI_GATHERV函数将每个进程的数据类型汇总到根(rank = 0)。
我的目标是将随机值中的最小值与数据类型相匹配。那将是最终的答案。到目前为止,我已尝试过各种各样的想法,但无济于事。我最终得到了" forrtl:严重的SIGSEGV,发生了分段错误"。
现在我也看了几个其他帖子。例如,我不能使用"使用mpif.h"关于这个特定系统的声明。
但是,最后,这是代码:
program fredtype
implicit none
include '/opt/apps/intel15/mvapich2/2.1/include/mpif.h'
integer rank,size,ierror,tag,status(MPI_STATUS_SIZE),i,np,irank
integer blocklen(2),type(2),num,rcount(4)
double precision :: x,aout
character(len=4) :: y
type, BIND(C) :: mytype
double precision :: x,aout,test
character :: y
end type mytype
type(mytype) :: foo,foobag(4)
integer(KIND=MPI_ADDRESS_KIND) :: disp(2),base
call MPI_INIT(ierror)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror)
aout = 99999999999.99
call random_seed()
call random_number(x)
if(rank.eq.0)y="dogs"
if(rank.eq.1)y="cats"
if(rank.eq.2)y="tree"
if(rank.eq.3)y="woof"
print *,rank,x,y
call MPI_GET_ADDRESS(foo%x,disp(1),ierror)
call MPI_GET_ADDRESS(foo%y,disp(2),ierror)
base = disp(1)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror)
aout = 99999999999.99
call random_seed()
call random_number(x)
if(rank.eq.0)y="dogs"
if(rank.eq.1)y="cats"
if(rank.eq.2)y="tree"
if(rank.eq.3)y="woof"
print *,rank,x,y
call MPI_GET_ADDRESS(foo%x,disp(1),ierror)
call MPI_GET_ADDRESS(foo%y,disp(2),ierror)
base = disp(1)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror)
aout = 99999999999.99
call random_seed()
call random_number(x)
if(rank.eq.0)y="dogs"
if(rank.eq.1)y="cats"
if(rank.eq.2)y="tree"
if(rank.eq.3)y="woof"
print *,rank,x,y
call MPI_GET_ADDRESS(foo%x,disp(1),ierror)
call MPI_GET_ADDRESS(foo%y,disp(2),ierror)
base = disp(1)
disp(2) = disp(2) - base
blocklen(1) = 1
blocklen(2) = 1
type(1) = MPI_DOUBLE_PRECISION
type(2) = MPI_CHARACTER
call MPI_TYPE_CREATE_STRUCT(2,blocklen,disp,type,foo,ierror)
call MPI_TYPE_COMMIT(foo,ierror)
call MPI_REDUCE(x,aout,1,MPI_DOUBLE_PRECISION,MPI_MIN,0,MPI_COMM_WORLD,i\
error)
call MPI_GATHER(num,1,MPI_INT,rcount,1,MPI_INT,0,MPI_COMM_WORLD)
call MPI_GATHERV(foo,num,type,foobag,rcount,disp,type,0,MPI_COMM_WORLD)
if(rank.eq.0)then
print *,'fin ',aout
end if
end program fredtype
感谢您的帮助。 此致 埃林
答案 0 :(得分:1)
对于我来说,尝试完全修复它的代码肯定太令人困惑了。因此,我们假设您将类型mytype
定义如下:
type, bind(C) :: mytype
double precision :: x, aout, test
character(len=4) :: y
end type mytype
(Rk:我已将len=4
添加到y
的定义中,因为它似乎在原始代码中缺失。我可能错了,如果是这样,只需调整{{1在相应的后续代码中)
现在让我们假设您只想转移blocklen(2)
类型变量的x
和y
字段。为此,您需要使用第一个mytype
创建一个适当的派生MPI类型,以定义基本类型及其在结构中的位置,然后MPI_Type_create_struct()
来定义真实范围和下限。类型,包括洞。
棘手的部分通常是评估Fortran类型的下限和范围。在这里,当您包含转移第一个和最后一个字段的字段时,以及添加MPI_Type_create_resized()
时,您可以使用bind(C)
来获取这些信息。但是,如果您未将MPI_Type_get_extend()
或x
(这是该类型的第一个和最后一个字段)包含在MPI数据类型中,y
将无法返回您所拥有的内容需要。因此,我会建议您采用另一种(稍微繁琐)的方法,我相信这种方法始终有效:
MPI_Type_get_extent()
正如您所看到的,integer :: ierror, typefoo, tmptypefoo
integer :: blocklen(2), types(2)
type(mytype) :: foobag(4)
integer(kind=MPI_ADDRESS_KIND) :: disp(2), lb, extent
call MPI_Get_address( foobag(1), lb, ierror )
call MPI_Get_address( foobag(1)%x, disp(1), ierror )
call MPI_Get_address( foobag(1)%y, disp(2), ierror )
call MPI_Get_address( foobag(2), extent, ierror )
disp(1) = MPI_Aint_diff( disp(1), lb )
disp(2) = MPI_Aint_diff( disp(2), lb )
extent = MPI_Aint_diff( extent, lb )
lb = 0
blocklen(1) = 1
blocklen(2) = 4
types(1) = MPI_DOUBLE_PRECISION
types(2) = MPI_CHARACTER
call MPI_Type_create_struct( 2, blocklen, disp, types, tmptypefoo, ierror )
call MPI_Type_create_resized( tmptypefoo, lb, extent, typefoo, ierror )
call MPI_Type_commit( typefoo, ierror )
用作结构中位移的基址,类型范围是使用类型为lb
的数组的两个连续元素的相对地址计算的。 。
然后,我们创建一个中间MPI数据类型mytype
,它只包含有关我们将要传输的实际数据的信息,并将有关Fortran类型的实际下限和范围的信息扩展到tmptypefoo
。最后,只需要提交最后一个,因为它只用于数据传输。