FORTRAN и MPI: выделить и инициализировать массив пользовательского типа, используя входной файл - PullRequest
1 голос
/ 24 мая 2019

У меня есть размещаемый массив определенного пользователем типа.Размер массива и значения элементов массива должны быть считаны из файла.У меня есть серийный код, который выглядит примерно так:

MODULE read_and_allocate
  IMPLICIT NONE

  TYPE my_type
     INTEGER :: my_number
     CHARACTER(10) :: my_string

   CONTAINS
     PROCEDURE :: read_my_type_from_string_array
     PROCEDURE :: write_my_type
     GENERIC :: WRITE(formatted) => write_my_type
  END TYPE my_type

  TYPE(my_type), ALLOCATABLE :: my_array(:)

  CONTAINS
    SUBROUTINE read_my_type_from_string_array(var, string_array)
      CLASS(my_type), INTENT(INOUT) :: var
      CHARACTER(*), INTENT(IN) :: string_array(:)

       !code omitted
    END SUBROUTINE read_my_type_from_string_array


    SUBROUTINE write_my_type(var, funit, iotype, v_list, iostat, iomsg)
       !code omitted
    END SUBROUTINE write_my_type


    SUBROUTINE read_my_array(var, funit)!, iotype, v_list, iostat, iomsg)
      TYPE(my_type), ALLOCATABLE, INTENT(INOUT) :: var(:)
      INTEGER, INTENT(IN) :: funit

      CHARACTER(200) :: line
      INTEGER :: rec_count, rec_len, max_rec_len
      LOGICAL :: in_rec
      INTEGER :: pos
      CHARACTER(200),ALLOCATABLE :: rec(:)
      INTEGER :: ii, jj
      INTEGER :: status

      ! calling read_my_array deallocates var
      IF (ALLOCATED(var)) DEALLOCATE(var)

      max_rec_len = 0
      rec_count = 0
      in_rec = .FALSE.
      DO
         READ(funit, '(a)', iostat=status) line
         IF (status < 0) EXIT

         IF (in_rec .AND. TRIM(ADJUSTL(line)) == ']') THEN
            in_rec = .FALSE.
         END IF

         IF (in_rec) THEN
            rec_len = rec_len+1
         END IF


         IF (.NOT. in_rec .AND. TRIM(ADJUSTL(line)) == '[my_type') THEN
            in_rec = .TRUE.
            max_rec_len = MAX(max_rec_len, rec_len)
            rec_len = 0
            rec_count = rec_count + 1
         END IF
      END DO

      ALLOCATE(rec(max_rec_len))
      ALLOCATE(var(rec_count))
      REWIND(funit)

      in_rec = .FALSE.
      jj = 1
      DO
         READ(funit, '(a)', iostat=status) line
         IF (status < 0) EXIT

         IF (in_rec .AND. TRIM(ADJUSTL(line)) == ']') THEN
            CALL var(jj)%read_my_type_from_string_array(rec)
            jj = jj + 1
            in_rec = .FALSE.
         END IF

         IF (in_rec) THEN
            rec(ii) = line
            ii = ii+1
         END IF


         IF (.NOT. in_rec .AND. TRIM(ADJUSTL(line)) == '[my_type') THEN
            in_rec = .TRUE.
            rec(:) = ''
            ii = 1
         END IF
      END DO

      DEALLOCATE(rec)

    END SUBROUTINE read_my_array


    SUBROUTINE write_my_array(var, funit)
       !code omitted
    END SUBROUTINE write_my_array


END MODULE read_and_allocate

PROGRAM my_test

  USE read_and_allocate

  IMPLICIT NONE

  INTEGER :: funit

  OPEN(newunit=funit, file='input.txt')

  CALL read_my_array(my_array, funit) !this routine allocates my_array

  CALL write_my_array(my_array, 6)


END PROGRAM my_test

Это работает, как и ожидалось (протестировано с gfortran на Mac).Короче говоря, read_my_array обрабатывает данный входной файл, выводит необходимый размер (N) my_array, выделяет 'my_array', а затем вызывает read_my_type_from_string_array N раз, чтобы заполнить каждый элемент my_array данными.

Теперь я хочу перенести этот код в существующую параллельную программу, но я не совсем уверен, как это сделать правильно.Я думаю, что у меня есть два варианта, но у меня есть опасения по поводу обоих:

1) Я мог читать текстовый файл только в основном процессе, но после прочтения это , яЯ не уверен, что могу так легко транслировать выделяемый массив.

2) Я мог бы заставить каждый процесс читать текстовый файл отдельно, но я боюсь, что смогу создать какое-то условие гонки (функция read_my_array использует REWIND и BACKSPACE), где разные процессы будут получать разные результаты для my_array.Я нашел эту ветку форума Intel , где упоминается опция SHARE для открытия файла - я не совсем уверен, что это то, что я ищу.

Есть лилучший способ, как делать такие вещи?

EDIT :

Пример входного файла будет выглядеть примерно так:

[my_type
  my_string = 'one'
  my_number = 1
]
[my_type
  my_string = 'two'
  my_number = 4
]
[my_type
  my_string = 'alfred'
  my_number = 7
]
...