是否可以使用MPI将数据从Fortran程序发送到Python?


问题内容

我正在开发一种用于对波能转换器建模的工具,在这里我需要将两个软件包彼此耦合。一个程序是用Fortran编写的,另一个是C
编写的。我需要在每个时间步骤中将信息从Fortran程序发送到C 程序。但是,在将数据发送到C
++程序之前,首先需要在Python中对其进行处理。我收到了使用MPI在程序之间传输数据的提示。

我现在正在尝试将一个简单的字符串从Fortran代码发送到Python,但是Python代码卡在了receive命令上。

我的Fortran代码如下所示:

      USE GlobalVariables
      USE MPI
      IMPLICIT NONE

      CHARACTER(LEN=10):: astring
      INTEGER :: comm, rank, size, mpierr

      ! Initialize MPI on first timestep
      IF(tstep .LT. 2) THEN
        call MPI_INIT(mpierr)
      ENDIF

      ! make string to send to python
      astring = "TEST"

      ! MPI Test
      call MPI_Comm_size(MPI_COMM_WORLD, size, mpierr)
      call MPI_Comm_rank(MPI_COMM_WORLD, rank, mpierr)

      ! Send message to python
      CALL MPI_SEND(astring, len(astring), MPI_CHARACTER, 0, 22, MPI_COMM_WORLD, mpierr)
      print *, 'MPI MESSAGE SENT  ', mpierr

      ! Initialize MPI on first timestep
      IF(tstep .EQ. Nsteps-1) THEN
        call MPI_FINALIZE(mpierr)
        print *, 'MPI FINALIZED!'
      ENDIF

我的Python代码如下:

    from mpi4py import MPI
    import numpy as np
    import subprocess as sp
    import os

    # Start OW3D_SPH in the background and send MPI message
    os.chdir('OW3D_run')
    args = ['OceanWave3D_SPH','OW3D.inp']
    pid = sp.Popen(args,shell=False)
    os.chdir('..')

    # Check if MPI is initialized
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()

    # Receive message from fortran
    test = comm.recv(source=0, tag=22)

    # Let the program end
    output = pid.communicate()

    with open('test.txt','w') as f:
        f.write(test)

Python代码永远不会超过MPI receive命令并且不会完成。Fortran代码确实完成并正确打印“ MPI FINALIZED”消息。

我看不到我在哪里做错什么,消息从进程0发送到带有标签22的进程0,并且MPI_COMM_WORLD在两个代码中都使用。


问题答案:

如果要在同一MPI作业中同时启动Fortran程序和Python程序,则必须使用以下方法:

mpiexec -n 1 fortran_program : -n 1 python main.py

Fortran程序将变为MPI等级0,而Python程序将变为MPI等级1。您还可以启动每个可执行文件中的多个,例如:

mpiexec -n 2 fortran_program : -n 4 python main.py

排名0和1来自Fortran程序,排名2至5-来自Python。

还要注意,comm.recv()在mpi4py其他通信方式,与小写字母(启动comm.send()comm.irecv()等),引擎盖下使用泡菜和实际上序列化Python对象进行操作。这与Fortran代码发送的字符数组不兼容。你必须要使用以大写字母(启动通信方式comm.Send()comm.Recv()等等)上与NumPy阵列操作和接收显式类型信息。不幸的是,我的Python功能很弱,我现在无法提供完整的工作示例,但是MPI部分应该是这样的(未经验证的代码):

# Create an MPI status object
status = MPI.Status()
# Wait for a message without receiving it
comm.Probe(source=0, tag=22, status=status)
# Check the length of the message
nchars = status.Get_count(MPI.CHARACTER)
# Allocate a big enough data array of characters
data = np.empty(nchars, dtype='S')
# Receive the message
comm.Recv([data, MPI.CHARACTER], source=0, tag=22)
# Construct somehow the string out of the individual chars in "data"

在Fortran代码中,您必须指定目标等级1(如果您正在运行一个Fortran可执行文件和一个Python可执行文件)。