是否可以使用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可执行文件)。