是否可以使用MPI从Fortran程序向Python发送数据?
我正在开发一种建模波浪能转换器的工具,我需要将两个软件包相互耦合。一个程序用FORTRAN编写,另一个程序用C++编写。我需要在每个时间步把FORTRAN程序的信息发送给C++程序。然而,数据首先需要在Python中处理,然后才被发送到C++程序。我收到了一个使用MPI在程序之间传输数据的提示 我现在试图将一个简单的字符串从Fortran代码发送到Python,但是Python代码在receive命令处卡住了 我的Fortran代码如下所示:是否可以使用MPI从Fortran程序向Python发送数据?,python,fortran,mpi,openmpi,Python,Fortran,Mpi,Openmpi,我正在开发一种建模波浪能转换器的工具,我需要将两个软件包相互耦合。一个程序用FORTRAN编写,另一个程序用C++编写。我需要在每个时间步把FORTRAN程序的信息发送给C++程序。然而,数据首先需要在Python中处理,然后才被发送到C++程序。我收到了一个使用MPI在程序之间传输数据的提示 我现在试图将一个简单的字符串从Fortran代码发送到Python,但是Python代码在receive命令处卡住了 我的Fortran代码如下所示: USE GlobalVariables
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发送到进程0,带有标记22,并在两个代码中使用
MPI\u COMM\u WORLD
。我不会为此使用MPI(除非明确要求并行执行代码)。如果你的目标是连接在Fortran、C++和Python中编写的例程,那么我建议在Python中编写(main)连接部分,同时为FORTRAN和C++例程创建适配器,以便将它们导入Python。然后,您可以管理主Python程序中的所有函数调用,并根据需要发送数据
查看以下链接:
在Python中运行Fortran代码
- :
现在附带了f2py
,允许您将Fortran源代码编译成Python字节码numpy
mpirun
命令,因此很难说哪个是哪个
澄清:MPI_COM_WORLD是在MPI运行或等效程序中执行的所有进程的通信器。你必须离开简单的心灵图景,第一个Python进程是等级0,第一个FORTRAN进程是等级0,第一个C++是等级0…< /P>
如果你这样做
mpirun -n 1 python main.py : -n 1 ./fortran_main : -n 1 ./c++_main
在MPIYCOMSOLL世界中,Python程序将为秩0,FORTRAN过程将为秩1,C++将为秩2。您可以创建仅在Python子集或FORTRAN子集或C++一个本地通信器,并且每个级别都有0级,但这将在不同的通信器中编号,而不是在MPIYCOMLWord中。
< P>如果您要在同一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()
,等等)在后台使用Pickle,并实际操作序列化Python对象。这与Fortran代码发送的字符数组不兼容。您必须使用以大写字母开头的通信方法(comm.Send()
,comm.Recv()
,等等),这些方法在NumPy数组上运行并接收显式类型信息。不幸的是,我的Python fu很弱,现在无法提供完整的工作示例,但MPI部分应该是这样的(未经验证的代码):
在Fortran代码中,您必须指定目标秩为1(在运行一个Fortran可执行文件和一个Python可执行文件的情况下)。MPI进程可以使用此函数生成进程。在Python程序中,此函数是通信器的一种方法:
comm.spawn()
。有关示例,请参见生成的进程根据可执行文件运行,该可执行文件可以是另一个python程序、c/c++/fortran程序或任何您想要的程序。然后,内部通信程序可以定义主进程和生成进程之间的内部通信程序,如中所执行,主进程和派生进程可以自由通信而不受任何限制。
让我们介绍一个Python/c示例。Python代码生成进程并接收一个字符:
从MPI4p导入MPI
导入系统
进口numpy
'''
slavec是从slave.c开始构建的可执行文件
'''
#Spawing运行可执行文件的进程
#sub_comm是MPI内部通讯器
sub_comm=MPI.comm_SELF.Spawn('slavec',args=[],maxprocs=1)
#common_comm是一个跨python进程和派生进程的内部通信程序。python进程和c进程之间现在可以进行所有类型的集体通信(Bcast…)
公共通信=子通信合并(假)
#打印“公共通信中的父级”,公共通信获取等级(),“of”,公共通信获取大小()
data=numpy.arange(1,dtype='int8')
公共通信记录([数据,MPI.CHAR],源=1,标记=0)
打印“Python从C:收到的消息”,数据
#需要断开共享通讯器才能完成生成的进程。
公共通信断开()
子通信断开()
由mpicc slave.C-o slavec-Wall编译的C代码使用合并的通信器发送字符:
#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
int等级、大小;
MPI_Comm parentcomm、intracomm;
MPI_Init(&argc,&argv);
//MPI通信等级(MPI通信世界和等级);
MPI_Comm_get_parent(&parentcomm);
if(parentcomm==MPI_COMM_NULL){fprintf(stderr,“模块1:我应该是生成的进程!”);退出(1);}
MPI\U内部通信合并(pa)
# 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"