Как использовать пользовательские типы данных OpenMPI после их объявления?

Я хочу транслировать непрерывные переменные, не связанные с памятью (INTEGERS и REAL(8)) из моего основного процесса во все остальные процессы в реализации MPI FORTRAN90, но поскольку это моя первая попытка как на FORTRAN, так и на MPI (я привык только к C/ C++), у меня есть несколько вопросов:

  • В настоящий момент я использую вызов MPI_TYPE_CREATE_STRUCT, но знаю, что могу также использовать вызовы MPI_PACK/MPI_UNPACK, которые требуют дополнительных операций копирования из памяти в память. Поскольку объем передаваемых данных в этом случае невелик, какое решение предлагает наилучшие характеристики? Есть ли какое-либо другое решение, которое я не знаю и которое быстрее/проще реализовать (может быть, один вызов MPI_BCAST для каждой переменной?)?

  • В случае пользовательского типа данных MPI, как мне объявить переменную (или здесь группу переменных известного типа данных) только одной переменной нового типа данных? Я имею в виду, что теперь, когда моя структура MPI PARAMETER_READ создана (см. код ниже), как мне сообщить компилятору, что я хочу, чтобы все мои переменные (nmin, dout, nmax, ncellsmax, ncells, ns, dt, del) хранились в памяти сгруппироваться все вместе, чтобы стать только одной новой переменной типа PARAMETER_READ?

  • Где я могу объявить свои пользовательские типы данных? Должен ли я объявить их внутри a:

    ЕСЛИ(ранг==0) ТО

    объявление нового типа данных

    КОНЕЦ

петля или снаружи?

Вот мой код (я сохранил только интересные части):

PROGRAM SIM_3D
USE IO
USE MPI_MOD

IMPLICIT NONE

INTEGER :: nmin, dout, nmax, ncellsmax
INTEGER, DIMENSION(3) :: ncells, ns
REAL(8) :: dt,
REAL(8), DIMENSION(3) :: del

CALL init_MPI

IF(rank == master) THEN
  CALL readParams(ncells, del, nmin, dout, nmax, dt, ns, ncellsmax) ! All these values are read by the master process in an external *.txt file using a custom subroutine readParams in the IO module.
  CALL BCAST_PARAM
ENDIF

END PROGRAM SIM_3D

Где MPI_MOD:

MODULE MPI_MOD

USE MPI

INTEGER, PARAMETER :: master = 0
INTEGER :: ierror, rank, num_proc
INTEGER, DIMENSION( MPI_STATUS_SIZE ) :: status

INTEGER :: NUMBER_OF_BLOCKS = 2
INTEGER, DIMENSION(2) :: ARRAY_OF_BLOCKLENGTHS = (/ 10, 4/)
INTEGER, DIMENSION(2) :: ARRAY_OF_DISPLACEMENTS = (/ 40, 32/)
INTEGER, DIMENSION(2) :: ARRAY_OF_TYPES = (/ MPI_INTEGER, MPI_REAL/)

CONTAINS

SUBROUTINE init_MPI
  IMPLICIT NONE
  CALL MPI_INIT(ierror)
  CALL MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror)
  CALL MPI_COMM_SIZE(MPI_COMM_WORLD,num_proc,ierror)
END SUBROUTINE init_MPI

SUBROUTINE BCAST_PARAM
  IMPLICIT NONE
  CALL MPI_TYPE_CREATE_STRUCT(NUMBER_OF_BLOCKS, ARRAY_OF_BLOCKLENGTHS, ARRAY_OF_DISPLACEMENTS, ARRAY_OF_TYPES, PARAMETER_READ, IERROR)
  CALL MPI_TYPE_COMMIT (PARAMETER_READ, IERROR)
  *I would like to put all the variables to be sent in a PARAMETER_READ type variable called BUFFER*
  CALL MPI_BCAST(BUFFER,1,PARAMETER_READ,master,MPI_COMM_WORLD,IERROR)
END SUBROUTINE BCAST_PARAM

END MODULE MPI_MOD

Я даже не уверен, что мое собственное объявление типа данных правильное... Большое спасибо за то, что прочитали меня, ваша помощь будет очень признательна. С наилучшими пожеланиями.


person Pierre Renard    schedule 20.08.2014    source источник
comment
Не могли бы вы уточнить, что вы имеете в виду под вторым пунктом? Будете ли вы сообщать эти переменные несколько раз в своем коде?   -  person Yossarian    schedule 20.08.2014
comment
Привет, Йоссариан, и спасибо за быстрый ответ. Я старался быть как можно более ясным со своим вторым пунктом, надеюсь, вам будет достаточно, чтобы понять мою проблему. Спасибо за помощь!   -  person Pierre Renard    schedule 21.08.2014
comment
То, что вам нужно, это производные типы Fortran. я добавил это в свой ответ   -  person Yossarian    schedule 21.08.2014
comment
Спасибо за ваш ответ и за время, которое вы посвятили этой теме. Боюсь, я недостаточно ясно выразился. На самом деле я хочу передать все ранее упомянутые переменные всем узлам кластера с помощью процедуры MPI, но я хотел бы использовать только один вызов MPI_BCAST, поэтому я хочу «упаковать» — или что-то эквивалентное — данные только в одном переменная, которую можно использовать в MPI_BCAST. В таком случае, почему вы не рекомендуете использовать пользовательский тип данных MPI с MPI_TYPE_CREATE_STRUCT?   -  person Pierre Renard    schedule 22.08.2014
comment
У меня есть еще один похожий вопрос: поскольку я использую декартову топологию в своем коде, я хотел бы использовать MPI_CREATE_DARRAY для передачи каждому узлу трехмерного массива, созданного из части большего исходного трехмерного массива, который содержит данные, которые он должен обращаться. Как только мой пользовательский тип данных MPI создан, как мне его использовать и объявить все мои подмассивы? На самом деле я не знаю, как использовать пользовательские типы данных MPI после их создания, как воздействовать на значения переменных этого нового типа.   -  person Pierre Renard    schedule 22.08.2014
comment
Чтобы было ясно, чтобы использовать тип данных MPI PARAMETER_READ в вашем вопросе, вам также необходимо создать эквивалентный производный тип Fortran - это parameter_read_type в моем ответе. Fortran не знает о типе данных MPI, а MPI не знает о типе Fortran, поэтому вы должны использовать их вместе. Вы объявляете переменную Fortran как parameter_read_type, присваиваете свои данные ее компонентам, затем можете использовать MPI_BCAST с PARAMETER_READ для передачи ее остальным процессам.   -  person Yossarian    schedule 22.08.2014
comment
Я также заметил ошибку в вашем коде: ARRAY_OF_DISPLACEMENTS = (/ 40, 32/) должно быть ARRAY_OF_DISPLACEMENTS = (/ 0, 40/).   -  person Yossarian    schedule 22.08.2014
comment
Хорошо, большое спасибо, теперь я понимаю. Я думаю, что это был момент, которого мне не хватало до сих пор. Итак: типы данных Fortran и типы данных MPI неразделимы и работают вместе. Нельзя использовать одно без использования другого. Следовательно, для моего распределения массивов мне нужно создать тип данных массива в MPI с вызовом MPI_TYPE_CREATE_DARRAY, например, «подмассив», И объявить стандартный массив Fortran, например, «буфер», того же размера? Тогда я смогу MPI_BCAST(buffer,1,subarray,master,cartesian_comm,ierror)   -  person Pierre Renard    schedule 25.08.2014
comment
Как насчет доступа к данным, содержащимся в «буфере», из одного процесса? Должен ли я использовать буфер (i, j, k) или original_array (i, j, k)? Какой из них работает?   -  person Pierre Renard    schedule 25.08.2014
comment
Если я могу задать вопрос еще раз (извините, но я немного потерялся). Я искал ответ в течение нескольких часов, но я продолжаю находить разные результаты: (1,1,1) или (0,0,0): какова начальная координата в декартовой топологии? Я знаю, что существуют способы получить его, используя ранг рассматриваемого процесса, например MPI_CART_COORD, но я пока не могу скомпилировать свой код, потому что он все еще неполный и содержит некоторые ошибки. Спасибо за помощь. Кстати, спасибо, что заметили ошибку.   -  person Pierre Renard    schedule 25.08.2014
comment
Если вы считаете, что я ответил на ваш вопрос, вы можете отметить его как принятый. Вероятно, будет лучше, если вы откроете новые вопросы для своих других вопросов, это становится немного не по теме. Может кто ответит быстрее.   -  person Yossarian    schedule 25.08.2014


Ответы (1)


В ответ на ваш последний вопрос: пользовательские типы данных MPI должны быть объявлены всеми процессами, а не только главным узлом. Это также относится к коллективным коммуникациям, таким как ваш MPI_BCAST, поэтому вам следует переместить вызов на BCAST_PARAM за пределы блока if(rank == master).

Что касается вашего первого вопроса, лучше всего провести эмпирическое тестирование. Трудно сказать, что будет быстрее для вашего фактического варианта использования, так как это также будет зависеть от того, сколько раз вы передаете данные и от сведений о машинах, на которых вы работаете.

Типы данных MPI используются только в подпрограммах MPI для передачи данных. Если вы хотите упаковать несколько переменных Фортрана вместе, самый простой способ — создать тип, производный от Фортрана, который соответствует типу данных MPI. Вот как это будет выглядеть для вашего случая:

! For kind=REAL64, more portable than kind=8
use, intrinsic :: iso_fortran_env

type parameter_read_type
   integer                    :: nmin
   integer                    :: dout
   integer                    :: nmax
   integer                    :: ncellsmax
   integer, dimension(3)      :: ncells
   integer, dimension(3)      :: ns
   real(REAL64)               :: dt
   real(REAL64), dimension(3) :: del
end type parameter_read_type

Затем вы можете объявить новые переменные этого типа и получить доступ к компонентам с помощью оператора %:

type(parameter_read_type) :: buffer

if (rank == master) call readParams(buffer)

call MPI_BCAST(buffer, 1, PARAMETER_READ, master, MPI_COMM_WORLD, ierror)

...

subroutine readParams(read_parameters)
  type(parameter_read_type), intent(out) :: read_parameters

  read_parameters%nmin = ...
  read_parameters%ncells(1) = ...

  ...

end subroutine readParams

Создание такого типа Fortran также позволит вам передавать массивы parameter_read_type:

type(parameter_read_type), dimension(2) :: buffer2

call readParams(buffer2(1))
call readParams(buffer2(2))

call MPI_BCAST(buffer2, 2, PARAMETER_READ, master, MPI_COMM_WORLD, ierror)
person Yossarian    schedule 20.08.2014