从 R 调用并行 Fortran MPI 子例程

Call parallel fortran MPI subroutine from R

我想在 R 可以调用的子例程中编写一些并行 Fortran 代码(我想从 R 读取数据并将其发送到并行 Fortran MPI)。然而,我注意到,当我 运行 以下程序作为子例程时(即用 "subroutine" 代替 "program"),代码不再编译(当它是一个程序时它会编译).我正在使用 Linux 中的 MPICH 中的 mpif90 编译代码。

是否可以在 Fortran 的子程序中初始化和完成 MPI?如果不是,是否仍然可以从 R 中以某种方式调用并行 Fortran MPI?如果不是在 Fortran 中,是否可以在 C 中完成?

代码如下:

module global
  integer numnodes,myid,mpi_err
  integer, parameter :: my_root=0
end module global

module fmpi
  include 'mpif.h'
end module fmpi

subroutine init
  use fmpi
  use global
  implicit none
  call MPI_INIT( mpi_err )
  call MPI_COMM_SIZE( MPI_COMM_WORLD, numnodes, mpi_err )
  call MPI_Comm_rank(MPI_COMM_WORLD, myid, mpi_err)
end subroutine init

program test
  use global
  use fmpi
  implicit none
  real*8:: dat(10)
  integer*4:: i
  call init
  if(myid == my_root) then
    do i=1,10
      dat(i) = i
    enddo
    print *,dat(1)
  endif
  call mpi_finalize(mpi_err)
end program test

这样做应该可以安装,但这不是最简单的事情。该过程通常涉及以下步骤。但首先,一些注意事项:R 只能调用 subroutines,因此您必须将主程序修改为子例程并传递上述参数。 此外,我会尝试首先使用 Fortran 处理非并行案例,然后尝试处理并行案例。

  • 安装 gfortran。 我的 R (3.1.2) 版本专门针对 gfortran-4.8。我安装了 gfortran-4.9,所以我创建了一个从 4.9 到 4.9 的符号 link,它似乎可以工作(例如 ln -s gfortran-4.9 gfortran-4.8)

  • 安装 Rmpi​​ 库。有一些说明 here 可以在命令行上执行此操作,但仅适用于 Linux。因此,您可能需要单独下载并安装。你可以试试:

    > r 命令安装 Rmpi_0.6-5.tar.gz

  • 创建程序的共享对象库。如果你上面的代码是name test.f90,在命令行运行:

    $ r CMD SHLIB 测试.f90

  • 加载共享对象到R:

    > dyn.load('test.so')

  • 根据这个 page,假设你要调用一个子程序(不是并行的),实际调用 运行 子程序应该是类似于:

    > .Fortran("test", n=as.integer(5), x=as.double(rnorm(5)))

  • 从 R 中启动 MPI 作业。您将不得不使用 Rmpi​​ 接口从 R 中执行所有 MPI 初始化操作(mpi_init()、mpi_comm_size()、mpi_comm_rank())。有个不错的教程here

    > 图书馆(Rmpi)

    > mpi.spawn.Rslaves(nslaves=4)

这是我想从 R 调用的一个简单 Fortran/MPI 子程序:

subroutine test(id, ierr)
  use mpi
  implicit none
  integer*4 id, ierr
  call MPI_Comm_rank(MPI_COMM_WORLD, id, ierr)
end subroutine test

为了在 Linux 机器上从 R 调用它,我使用 Open MPI wrapper 命令构建了一个共享 object 文件 "mpif90":

$ mpif90 -fpic -shared -o test.so test.f90

我尝试使用 "R CMD SHLIB",但最终决定让 "mpif90" 创建共享 object 比让 "R CMD SHLIB" 处理 MPI 更容易.缺点是该命令是特定于 gfortran 的。对于不同的编译器,您可能会通过使用 "SHLIB" --dry-run 选项获得一些帮助:

$ R CMD SHLIB --dry-run test.f90

这将显示用于使用您的编译器创建共享 object 的命令。然后您可以修改命令以使用 "mpif90" 以处理 MPI headers 和库。

这是一个调用 Fortran test 子例程的 R 脚本。它加载 Rmpi(自动调用 MPI_Init),加载包含我的 Fortran 子例程的共享 object,然后调用它:

# SPMD-style program: start all workers via mpirun
library(Rmpi)
dyn.load("test.so")

# This Fortran subroutine will use MPI functions
r <- .Fortran("test", as.integer(0), as.integer(0))

# Each worker displays the results
id <- r[[1]]
ierr <- r[[2]]
if (ierr == 0) {
  cat(sprintf("worker %d: hello\n", id))
} else {
  cat(sprintf("ierr = %d\n", ierr))
}

# Finalize MPI and quit
mpi.quit()

因为它是一个 SPMD-style 程序,所以它不像许多 Rmpi 示例那样产生工人。相反,所有 worker 都是通过 mpirun 启动的,这是执行 C 和 Fortran MPI 程序的典型方式:

$ mpirun -n 3 R --slave -f test.R

这会运行我的 R 脚本的三个实例,因此输出为:

worker 0: hello
worker 1: hello
worker 2: hello

我认为以这种方式构建代码可以轻松地从 R 和任意数量的 Fortran 子例程中使用 MPI。