Могу ли я передать переменную производному типу так, чтобы каждый экземпляр моего производного типа мог иметь массивы различной длины? - PullRequest
0 голосов
/ 13 октября 2018

Каков наилучший способ организовать в программе 11 одинаковых, но различающихся по размеру массивов без выделяемого свойства?

Я представляю что-то вроде этого:

TYPE MyType(i)
   integer, intent(in) :: i

   integer, dimension(i,i) :: A
   integer, dimension(2*i,i) :: B
   integer, dimension(i,2*i) :: C

end type MyType

Тогда вОсновная программа, которую я могу объявить примерно так:

type(mytype), dimension(N) :: Array

, где i-й элемент массива имеет доступ к трем массивам A, B и C, и каждый из этих трех массивов имеет разные размеры.

Проблема, с которой я столкнулся в настоящее время, заключается в том, что я решаю проблему QM, и у меня есть 11 различных массивов, которые различаются по размеру, но все зависят от одного и того же параметра (так как размеры A, B и C зависят от i).Фактические значения этих массивов также не меняются.

Моя программа рассматривает различные типы систем, каждая из которых имеет свои собственные A, B и C (просто для продолжения аналогии) и в каждой системе A,B и C имеют уникальный размер.

Если бы я знал, что смотрю на 6 различных типов систем, мне понадобилось бы 6 различных копий A, B и C.

В настоящее время AB и C не являются частью производного типа, а вместо этого могут быть выделены и пересчитаны на каждой итерации.Этот расчет занимает более одной десятой секунды для более крупных систем.Но я усредняю ​​свои результаты ~ 100 000 раз, что означает, что это может дать серьезную экономию времени.Кроме того, мне не хватает памяти.

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

Примечание: Вот как выглядят мои фактические массивы:

  integer, dimension(:,:), allocatable :: fock_states      
  integer, dimension(:,:), allocatable :: PES_down, PES_up  
  integer, dimension(:,:), allocatable :: IPES_down, IPES_up 
  integer, dimension(:,:), allocatable :: phase_PES_down, phase_PES_up    
  integer, dimension(:,:), allocatable :: phase_IPES_down, phase_IPES_up 
  integer, dimension(:,:), allocatable :: msize       
  integer, dimension(:,:), allocatable :: mblock      

Каждый массив имеет разный размер для каждой системы.

Редактировать:

Итак, что мне действительно нужно, это N копий массивов в списке чуть выше этого редактирования.Массивы, принадлежащие i-й копии, имеют размер, который масштабируется с i (например, PES_down имеет размерность (i, 4 ** i)).Насколько я понимаю, это означает, что мне нужно N различных объявлений переменных с типом «MyType».Обычно это нормально, но проблема в том, что N определяется во время компиляции, но может меняться между запусками.

N имеет определенный максимум, но кажется, что много потраченной памяти, когда я знаю, что не будуиспользовать массивы.

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

(обратитесь к этому ответу для более подробного объяснения).

Как сказал @roygvib в своем комментарии, да, использование параметризованных производных типов в этом случае не только возможно, этоэто идеальная параЭто одна из основных проблемных ситуаций, которые PDT стремится решить.

type :: MyType(i)
  integer, len :: i
  integer, dimension(i,i) :: A
  integer, dimension(2*i,i) :: B
  integer, dimension(i,2*i) :: C
  ! (...)
end type

Затем в основной программе вы объявите свой объект следующим образом (где i - известный параметр длины для текущеготип системы):

type(mytype(i)), dimension(N) :: Array

Но сначала проверьте доступность этой функции в вашем компиляторе.

0 голосов
/ 13 октября 2018

Полагаю, было бы проще всего использовать производный тип, содержащий A, B и C с переменной размера i, и распределить их для каждого i, используя некоторую процедуру инициализации (здесьMyType_init()).

module mytype_mod
    implicit none

    type MyType
        integer :: i
        integer, dimension(:,:), allocatable :: A, B, C
    end type
contains

    subroutine MyType_init( this, i )
        type(MyType), intent(inout) :: this
        integer, intent(in) :: i

        allocate( this % A( i,   i   ), &
                  this % B( 2*i, i   ), &
                  this % C( i,   2*i ) )

        this % A = 0  !! initial values
        this % B = 0
        this % C = 0
    end subroutine

end module

program main
    use mytype_mod
    implicit none
    integer, parameter :: N = 2
    type(MyType) :: array( N )
    integer i

    do i = 1, N
        call MyType_init( array( i ), i )

        array( i ) % A(:,:) = i * 10   !! dummy data for check
        array( i ) % B(:,:) = i * 20
        array( i ) % C(:,:) = i * 30
    enddo

    do i = 1, N
        print *
        print *, "i = ", i
        print *, "    A = ", array( i ) % A(:,:)
        print *, "    B = ", array( i ) % B(:,:)
        print *, "    C = ", array( i ) % C(:,:)
    enddo

end program

Результат (с gfortran 8.1):

 i =            1
     A =           10
     B =           20          20
     C =           30          30

 i =            2
     A =           20          20          20          20
     B =           40          40          40          40          40          40          40          40
     C =           60          60          60          60          60          60          60          60

array(:) в основной программе может быть выделен, например,

type(MyType), allocatable :: array(:)

N = 6
allocate( array( N ) )

, что может быть полезно, когда N считывается из входного файла.Кроме того, мы можем создать процедуру с привязкой по типу из MyType_init(), изменив строки на (*) ниже (для использования стиля OO).

module mytype_m
    implicit none

    type MyType
        integer :: i
        integer, dimension(:,:), allocatable :: A, B, C
    contains
        procedure :: init => MyType_init   ! (*) a type-bound procedure
    end type

contains

    subroutine MyType_init( this, i )
        class(MyType), intent(inout) :: this   ! (*) use "class" instead of "type"
        ...
    end subroutine
end module

program main
    ...
    do i = 1, N
        call array( i ) % init( i )  ! (*) use a type-bound procedure
        ...
    enddo
    ...
end program
...