MPI_Op_create и MPI_Reduce в Фортране 2008

Я пытался (без особого успеха) уменьшить MPI, используя специальную операцию в Fortran 2008. Мне удалось сделать это на C, но о Fortran 2008 информации немного меньше.

Этот код работает с включенной функцией сокращения MPI_SUM. Он просто суммирует каждое существующее значение ранга в глобальную сумму. Моей непосредственной целью было бы определить пользовательскую функцию, чтобы сделать то же самое. Любая помощь?

program main

    use mpi_f08
    implicit none

    integer :: ierror, isize, irank
    integer :: local_value, global_value

    call MPI_INIT(ierror)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, isize)
    call MPI_COMM_RANK(MPI_COMM_WORLD, irank)

    if (irank == 0) then

        local_value = irank
        global_value = 0
        call MPI_Reduce(local_value, global_value, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD, ierror)

        print *, "global_value", global_value

    else ! MPI if rank > 0

        local_value = irank
        call MPI_Reduce(local_value, global_value, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD, ierror)

    end if ! MPI if rank

    call MPI_FINALIZE(ierror)

end program main

Мне удалось написать функциональную реализацию на Фортране, но по какой-то причине результат с использованием 4 процессов MPI был 3 вместо 6. Непонятно, почему. Тем не менее, чтобы двигаться дальше, мне нужна (правильно) работающая реализация Fortran 2008.

РЕДАКТИРОВАТЬ - вот код Фортрана, который компилируется, но не работает должным образом.

    program main

    use mpi
    implicit none

    integer :: local_value, global_sum
    integer :: ierr, rank, size
    integer :: my_op

    call MPI_Init(ierr)
    call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
    call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)

    call MPI_Op_create(custom_sum_op, .true., my_op, ierr)

    if (rank == 0) then

        local_value = rank
        global_sum = 0
        call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)
        print *, "Global sum: ", global_sum

    else ! irank > 0

        local_value = rank
        call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)

    endif ! MPI if rank 0

    call MPI_Finalize(ierr)

contains

subroutine custom_sum_op(res, a)
    integer, intent(inout) :: res
    integer, intent(in) :: a
    res = a + res
end subroutine custom_sum_op

end program main

Добро пожаловать. Пожалуйста, используйте тег fortran для всех вопросов по Fortran. Вы можете добавить тег версии для вопросов, касающихся конкретной версии, но это не один из них. Современный MPI API также используется в более поздних версиях стандарта Фортрана.

Vladimir F Героям слава 06.05.2024 18:39

Не используйте MPI_INT для Фортрана, это тип данных C. Кроме того, аргументы ierror не являются обязательными, их можно избежать, если вы все равно их не проверяете.

Vladimir F Героям слава 06.05.2024 18:40

Вполне может помочь, если вы отредактируете вопрос, чтобы показать свою ошибочную реализацию Fortran. Проблема может быть не в том, о чем вы думаете.

Ian Bush 06.05.2024 20:07

Подпрограмма является внутренней. Указатель на него будет действителен только тогда, когда содержащий его код все еще выполняется. Для основной программы это должно быть нормально, но в MPI стеки иногда делают странные вещи. Это не вызывает проблемы здесь, но может вызвать проблемы в будущем.

Vladimir F Героям слава 07.05.2024 10:53

Спасибо всем, я обновил вопрос (неработающей) версией Фортрана.

Jay 07.05.2024 11:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот работающий пример с интерфейсом пользовательской функции, взятым из стандарта MPI. То, что у вас есть, определенно не соответствует тому, что говорит стандарт; у вас только 2 аргумента вместо 4, они не того типа для интерфейса mpi_f08, и вы возвращаете результат в первом аргументе, а не во втором.

ijb@ijb-Latitude-5410:~/work/stack$ cat op_create.f90
Module my_sum_module

  Implicit None

  Public :: my_sum
  
  Private
  
Contains

  Subroutine my_sum( invec, inoutvec, len, datatype )

    Use, Intrinsic :: iso_fortran_env, Only : stdout => output_unit
    Use, Intrinsic :: iso_C_binding  , Only : c_ptr

    Use mpi_f08
    
    Implicit None

    Type( c_ptr )       , Value :: invec
    Type( c_ptr )       , Value :: inoutvec
    Integer                     :: len
    Type( mpi_datatype )        :: datatype

    Integer, Dimension( : ), Pointer :: in_fptr
    Integer, Dimension( : ), Pointer :: inout_fptr

    If( datatype == mpi_integer ) Then
       Call c_f_pointer( invec   , in_fptr   , [ len ] )
       Call c_f_pointer( inoutvec, inout_fptr, [ len ] )
       inout_fptr = inout_fptr + in_fptr
    Else
       Write( stdout, * ) 'Unkown data type in my_sum'
       Call mpi_abort( mpi_comm_world, 5 )
    End If
    
  End Subroutine my_sum

End Module my_sum_module

Program test

  Use, Intrinsic :: iso_fortran_env, Only : stdout => output_unit

  Use mpi_f08, Only : mpi_comm_world
  Use mpi_f08, Only : mpi_integer
  Use mpi_f08, Only : mpi_sum
  Use mpi_f08, Only : mpi_op
  Use mpi_f08, Only : mpi_init, mpi_finalize
  Use mpi_f08, Only : mpi_comm_rank, mpi_comm_size
  Use mpi_f08, Only : mpi_reduce
  Use mpi_f08, Only : mpi_op_create
  
  Use my_sum_module, Only : my_sum

  Implicit None

  Type( mpi_op ) :: op

  Integer :: root
  Integer :: answer
  
  Integer :: me, nproc

  Call mpi_init()
  Call mpi_comm_rank( mpi_comm_world, me    )
  Call mpi_comm_size( mpi_comm_world, nproc )

  If( me == 0 ) Then
     Write( stdout, * ) 'Running on', nproc, ' processes'
  End If

  root = 0

  Call mpi_reduce( me, answer, 1, mpi_integer, mpi_sum, root, mpi_comm_world ) 
  If( me == root ) Then
     Write( stdout, * ) 'Answer to sum = ', answer
  End If

  Call mpi_op_create( my_sum, .True., op )
  Call mpi_reduce( me, answer, 1, mpi_integer, op, root, mpi_comm_world ) 
  If( me == root ) Then
     Write( stdout, * ) 'Answer to my_sum = ', answer
  End If

  Call mpi_finalize()
  
End Program test
ijb@ijb-Latitude-5410:~/work/stack$ mpif90 --version
GNU Fortran (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ijb@ijb-Latitude-5410:~/work/stack$ mpif90 -Wall -Wextra -fcheck=all -O -g -std=f2018 op_create.f90 
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 1 ./a.out
 Running on           1  processes
 Answer to sum =            0
 Answer to my_sum =            0
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 2 ./a.out
 Running on           2  processes
 Answer to sum =            1
 Answer to my_sum =            1
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
 Running on           3  processes
 Answer to sum =            3
 Answer to my_sum =            3
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 4 ./a.out
 Running on           4  processes
 Answer to sum =            6
 Answer to my_sum =            6
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 5 --oversubscribe ./a.out
 Running on           5  processes
 Answer to sum =           10
 Answer to my_sum =           10
ijb@ijb-Latitude-5410:~/work/stack$ 

Спасибо! Я вижу, что структура кода объявления пользовательской функции вместе с использованием указателей делает эту, казалось бы, простую задачу немного более сложной, чем я изначально ожидал. Ваше здоровье :)

Jay 07.05.2024 13:49

Другие вопросы по теме