代码 | 程序员节,分享几个MPI+Fortran小代码

时间:2024-01-29 21:44:32

学习 MPI 过程中,写的几个小代码,现在分享一下

因为原文章已消失,此教程排版十分工整,便于学习,因此手动搬家过来~

 

编译:

$ make SC=01_mpi_hello_world.f90

运行: 

$ mpirun -n 4 ./a.out  

Makefile 

#!/usr/bin/bashFC = mpifort
FF = -g -O0 -fbacktrace 
#FF = -O2 SC = 

all:    
    $(FC) $(FF) -o a.out $(SC)clean:
    rm -rf a.out

 

例子1:

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! 第一个 MPI+Fortran 并行程序! program main 
    use mpi 
    implicit none 
    character(len=mpi_max_processor_name) :: p_name 
    integer :: myid, numProcs, nameLen, ierr 

    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作
    !                | 
    !                + ---- 返回代码,与 mpi_success 相等时表示成功(out) 
    call mpi_comm_rank( mpi_comm_world, myid, ierr ) ! 获取当前进程标识号 
    !                        |            |     | 
    !                        |            |     + ---- 返回代码(out) 
    !                        |            + ---------- 返回当前进程标识号(out) 
    !                        + ----------------------- 通信域(in) 
    call mpi_comm_size( mpi_comm_world, numProcs, ierr ) ! 获取通信域包含的进程数 
    !                        |            |         | 
    !                        |            |         + ---- 返回代码(out) 
    !                        |            + -------------- 返回通信域内进程数(out) 
    !                        + --------------------------- 通信域(in) 
    call mpi_get_processor_name( p_name, nameLen, ierr ) ! 获取运行当前进程的机器名 
    !                               |       |       | 
    !                               |       |       + ---- 返回代码(out) 
    !                               |       + ------------ 返回机器名长度(out) 
    !                               + -------------------- 返回机器名(out) 
    write(*,*) "Hello World! Processor ",myid," of ",numProcs," on ",p_name(1:nameLen) 
    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 end program

 

例子2:

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! 演示简单的消息发送与接收! program main 
    use mpi 
    implicit none  
    integer       :: myid, numProcs, nameLen, ierr 
    integer       :: istat( mpi_status_size )    integer       :: iid 
    character(19) :: message 

    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作 
    call mpi_comm_rank( mpi_comm_world, myid, ierr ) ! 获取当前进程标识号  
    call mpi_comm_size( mpi_comm_world, numProcs, ierr ) ! 获取通信域包含的进程数 
    if( myid .eq. 0 ) then 
        message = "Hello, Processor "
        do iid = 1, numProcs -1 
            write(message(18:19),"(I2)") iid  
            call mpi_send( message, len(message), mpi_character, iid, 666, mpi_comm_world, ierr ) ! 消息发送
            !                 |            |             |        |    |          |          | 
            !                 |            |             |        |    |          |          + ---- 返回代码(out) 
            !                 |            |             |        |    |          + --------------- 通信域(in)
            !                 |            |             |        |    + -------------------------- 消息标志,用于区分发送到同一进程的消息(in)
            !                 |            |             |        + ------------------------------- 目的进程标识号(in) 
            !                 |            |             + ---------------------------------------- 消息类型(in) 
            !                 |            + ------------------------------------------------------ 消息数量(in) 
            !                 + ------------------------------------------------------------------- 发送缓冲区(in) 
        end do  
    else 
        call mpi_recv( message, len(message), mpi_character, 0, 666, mpi_comm_world, istat, ierr ) ! 消息接收
        !                 |          |              |        |   |          |          |      | 
        !                 |          |              |        |   |          |          |      + ---- 返回代码(out) 
        !                 |          |              |        |   |          |          + ----------- 返回状态(out),包含发送进程标识号、消息标志、发送操作的错误代码
        !                 |          |              |        |   |          + ---------------------- 通信域(in) 
        !                 |          |              |        |   + --------------------------------- 消息标志(in) 
        !                 |          |              |        + ------------------------------------- 源进程标识号(in) 
        !                 |          |              + ---------------------------------------------- 消息类型(in) 
        !                 |          + ------------------------------------------------------------- 消息数量(in) 
        !                 + ------------------------------------------------------------------------ 接收缓冲区(in) 
        write(*,*) "Processor ",myid," received """,message,""" from Processor 0."
    end if 
    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 end program

例子3:

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! 用 MPI 实现计时功能! program main 
    use mpi 
    implicit none  
    integer       :: myid, numProcs, nameLen, ierr  
    real(8)       :: startTime, endTime, tick    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作 
    call mpi_comm_rank( mpi_comm_world, myid, ierr ) ! 获取当前进程标识号  
    call mpi_comm_size( mpi_comm_world, numProcs, ierr ) ! 获取通信域包含的进程数 
    startTime = mpi_wtime() ! 获取当前时间
    call sleep(2)
    endTime   = mpi_wtime() ! 获取当前时间
    tick = mpi_wtick() ! 获取一个始终周期时间
    write(*,"(a,f15.10,a)") \'It took        \',endTime - startTime, \' s\'
    write(*,"(a,f15.10,a)") \'Time accuracy: \',tick ,               \' s\'
    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 
  end program main

例子4:

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! 获取 MPI 主/次版本号! program main 
    use mpi 
    implicit none 
    character(len=mpi_max_processor_name) :: p_name 
    integer :: version, subversion, nameLen, ierr 

    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作 
    call mpi_get_processor_name( p_name, nameLen, ierr ) ! 获取运行当前进程的机器名 
    call mpi_get_version( version, subversion, ierr ) ! 获取 MPI 版本号
    !                        |          |        |  
    !                        |          |        +---- 返回代码(out) 
    !                        |          + ------------ 主版本号(out)
    !                        + ----------------------- 次版本号(out)
    write(*,"(2a,2(a,i1))") "Host name: ",p_name(1:nameLen),&                            ", MPI version: ",version,\'.\',subversion    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 

  end program

例子5

 

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! 演示 mpi_initialized 和 mpi_abort(主动退出)! program main 
    use mpi 
    implicit none 
    character(len=mpi_max_processor_name) :: p_name 
    logical :: init_flag    integer :: myid, numProcs, ierr 
    integer,parameter :: masterNode = 0
 
    call mpi_initialized( init_flag, ierr ) ! 判断mpi_init是否被调用,唯一一个可以在mpi_init之前调用的子程序
    !                         |        | 
    !                         |        + ---- 返回代码(out)
    !                         + ------------- mpi_init 是否已执行标志(out)
    if ( .not.init_flag ) then
        write(*,*) "The subroutine mpi_init() has not been executed." 
    end if 
    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作 
    call mpi_comm_rank( mpi_comm_world, myid, ierr ) ! 获取当前进程标识号  
    call mpi_comm_size( mpi_comm_world, numProcs, ierr ) ! 获取通信域包含的进程数 
    if( myid .eq. masterNode ) then 
        write(*,*) "myid = ",myid," is masternode. Abort!"
        call sleep(1)        call mpi_abort( mpi_comm_world, 99, ierr ) ! 使通信域中所有进程退出,并返回给调用环境一个错误码 
        !                     |          |    | 
        !                     |          |    + ---- 返回代码(out)
        !                     |          + --------- 错误码(in)
        !                     + -------------------- 通信域(in)
    else 
        write(*,*) "myid = ",myid," is not masternode. Barrier!"
        call mpi_barrier( mpi_comm_world, ierr ) ! 同步进程
        !                     |             | 
        !                     |             + ---- 返回代码(out)
        !                     + ------------------ 通信域(in)
    end if 
    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 end program

例子6:

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! MPI 实现数据接力传送! program main    use mpi 
    implicit none
    integer :: myid, numProcs, nameLen, ierr 
    integer :: istat( mpi_status_size )    integer :: var 

    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作 
    call mpi_comm_rank( mpi_comm_world, myid, ierr ) ! 获取当前进程标识号  
    call mpi_comm_size( mpi_comm_world, numProcs, ierr ) ! 获取通信域包含的进程数   
    do while( var .ge. 0 )        if( myid .eq. 0 ) then 
            write(*,"(a)" ) "Please input new value:"
            read(*,*) var  
            write(*,"(a,i3,a,i8,a)" ) "proc ",myid," read               <-<- (",var,"   )"
            if( numProcs .gt. 1 ) then 
                call mpi_send( var, 1, mpi_integer, myid+1, 0, mpi_comm_world, ierr ) ! 消息发送
                write(*,"(a,i3,a,i8,a,i8)" ) "proc ",myid," send   (",var," ) ->-> proc ",myid+1
            end if 
        else 
            call mpi_recv( var, 1, mpi_integer, myid-1, 0, mpi_comm_world, istat, ierr ) ! 消息接收
            write(*,"(a,i3,a,i8,a,i8)" ) "proc ",myid," recive (",var," ) <-<- proc ",myid-1
            if( myid .lt. numProcs-1 ) then 
                write(*,"(a,i3,a,i8,a,i8)" ) "proc ",myid," send   (",var," ) ->-> proc ",myid+1
                call mpi_send( var, 1, mpi_integer, myid+1, 0, mpi_comm_world, ierr ) ! 消息发送
            end if 
        end if 
        call mpi_barrier( mpi_comm_world, ierr )    end do  
    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 end program main

例子7:

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! 任意进程间相互问候! program main    use mpi 
    implicit none
    integer :: myid, numProcs, nameLen, ierr  
    character(len=mpi_max_processor_name) :: p_name  

    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作 
    call mpi_comm_rank( mpi_comm_world, myid, ierr ) ! 获取当前进程标识号  
    call mpi_comm_size( mpi_comm_world, numProcs, ierr ) ! 获取通信域包含的进程数  
    
    if( numProcs .lt. 2 ) then 
        write(*,*) "System requires at least 2 processors."
        call mpi_abort( mpi_comm_world, 1, ierr )    end if  

    call mpi_get_processor_name( p_name, nameLen, ierr ) ! 获取运行当前进程的机器名 
    write(*,*) "Processor ",myid," is alive on ",p_name(1:nameLen),"."
    call sleep(1)    call mpi_barrier( mpi_comm_world, ierr )    call hello()    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 end program main! ############################################################################## ! !   任意两个进程间交换信息,问候信息由发送进程标识和接收进程标识组成!! ############################################################################## subroutine hello()    use mpi 
    implicit none 
    integer :: nproc, me, type = 1
    integer :: buffer(2), node 
    integer :: istat( mpi_status_size ), ierr 
    call mpi_comm_rank( mpi_comm_world, me, ierr ) 
    call mpi_comm_size( mpi_comm_world, nproc, ierr ) 

    if( me .eq. 0 ) then 
        write(*,*) "Hello test from all to all." 
    end if 

    do node = 0, nproc-1 
        if( node .ne. me ) then 
            buffer(1) = me 
            buffer(2) = node 
            ! 首先将问候信息发出
            call mpi_send( buffer, 2, mpi_integer, node, type, mpi_comm_world, ierr ) ! 消息发送
            ! 然后接收被问候进程对自己发送的问候信息
            call mpi_recv( buffer, 2, mpi_integer, node, type, mpi_comm_world, istat, ierr ) ! 消息接收
            if( buffer(1) .ne. node .or. buffer(2) .ne. me ) then 
                write(*,*) "Hello: ",buffer(1)," = ",node," or ",buffer(2)," = ",me                write(*,*) "Mismatch on hello processors; node = ",node 
            end if 
            write(*,*) "Hello from ",me," to ",node,"."
        end if 
    end do end subroutine

例子8:

! 简单的 MPI 并行程序 Fortran 实现示例! !        -- by Jackdaw !        -- QQ 群 Fortran Coder(2338021)!        -- 2018 10 24 ! ! 任意源和任意标志的使用! program main    use mpi 
    implicit none
    integer :: myid, numProcs, ierr 
    integer :: istat( mpi_status_size )    integer :: i,var 

    call mpi_init( ierr ) ! 完成 MPI程序 的初始化工作 
    call mpi_comm_rank( mpi_comm_world, myid, ierr ) ! 获取当前进程标识号  
    call mpi_comm_size( mpi_comm_world, numProcs, ierr ) ! 获取通信域包含的进程数  
    if( myid .eq. 0 ) then 
        do i = 1, 10
            call mpi_recv( var, 1, mpi_integer, mpi_any_source, mpi_any_tag, mpi_comm_world, istat, ierr ) ! 消息接收
            write(*,*) "Msg = ",var," from ",istat(mpi_source)," with tag ",istat(mpi_tag)        end do 
    else 
        do i = 1, 10
            var = myid + i 
            call mpi_send( var, 1, mpi_integer, 0, i, mpi_comm_world, ierr ) ! 消息发送 
        end do 
    end if 

    call mpi_finalize( ierr ) ! 完成 MPI程序 的结束工作 end program main