В моем коде я использую выделяемый производный тип данных (скажем, тип данных), в котором я храню многомерные размещаемые массивы (x и y). В том же модуле я также определяю подпрограммы для выделения / освобождения всего объекта, оператор присваивания (=) и дополнительные операторы перегрузки (*) и (+). Теперь я выделяю data1 (типа data), а также data1% x и data1% y в моей основной программе, инициализирую их и выполняю простую операцию с использованием операторов перегрузки (скажем, простого умножения всех элементов данных1). % x и data1% y константой). Вот минимальный код, который компилирует и воспроизводит то, что я только что описал:
program minimal
USE dimensions
USE typedef
IMPLICIT NONE
integer :: i, k
type(data), dimension(:), allocatable :: data1, data2
call alloc ( data1 )
call alloc ( data2 )
do k = 1 , ndat
data1(k)%x = real(k)
data1(k)%y = -real(k)
data2(k)%x = 0.
data2(k)%y = 0.
enddo
do i = 1, 10
data2 = data2 + 2.*data1
enddo
do k = 1, ndat
print*, k, maxval(data2(k)%x), maxval(data2(k)%y)
enddo
call dealloc ( data1 )
call dealloc ( data2 )
end program
и модули:
module dimensions
integer :: ndat=2
integer :: m1=10, m2=50
integer :: n1=10, n2=50
end module dimensions
module typedef
USE dimensions
type :: data
real, dimension(:,:), allocatable :: x
real, dimension(:,:), allocatable :: y
end type data
interface alloc
module procedure alloc_data
end interface alloc
interface dealloc
module procedure dealloc_data
end interface dealloc
interface assignment (=)
module procedure data_to_data
end interface
interface operator (*)
module procedure const_times_data
end interface
interface operator (+)
module procedure data_plus_data
end interface
CONTAINS
subroutine alloc_data (data1)
type(data), dimension(:), allocatable, intent(inout) :: data1
integer :: i
allocate ( data1(1:ndat) )
do i = 1, ndat
allocate ( data1(i)%x(m1:m2,n1:n2) )
allocate ( data1(i)%y(m1:m2,n1:n2) )
enddo
end subroutine alloc_data
subroutine dealloc_data (data1)
type(data), dimension(:), allocatable, intent(inout) :: data1
integer :: i
do i = 1, ndat
deallocate ( data1(i)%x )
deallocate ( data1(i)%y )
enddo
deallocate ( data1 )
end subroutine dealloc_data
subroutine data_to_data (data2,data1)
type(data), dimension(:), intent(in) :: data1
type(data), dimension(1:ndat), intent(out) :: data2
integer :: i
do i = 1, ndat
data2(i)%x = data1(i)%x
data2(i)%y = data1(i)%y
enddo
end subroutine data_to_data
function const_times_data (c,data1) result(data2)
type(data), dimension(:), intent(in) :: data1
real, intent(in) :: c
type(data), dimension(1:ndat) :: data2
integer :: i
do i = 1, ndat
data2(i)%x = c*data1(i)%x
data2(i)%y = c*data1(i)%y
enddo
end function const_times_data
function data_plus_data (data1,data2) result(data3)
type(data), dimension(:), intent(in) :: data1, data2
type(data), dimension(1:ndat) :: data3
integer :: i
do i = 1, ndat
data3(i)%x = data1(i)%x + data2(i)%x
data3(i)%y = data1(i)%y + data2(i)%y
enddo
end function data_plus_data
end module typedef
Компиляция кода с помощью ifort 17.0 (рекомендуемая версия на нашем компьютере) и опция -O0 для отладки не возвращают никаких проблем. Однако использование уровней оптимизации -O2 или -O3 приводит к ошибке сегментации. Я пробовал ту же процедуру с ifort 18.0 с тем же результатом, тогда как ifort 19.0, кажется, работает.
Я также немного поиграл с этим минимальным кодом и обнаружил, что, например, он работает с оптимизированным ifort 17, если структура данных «data» содержит один элемент x, или если он сам не является выделяемым массивом .
Вопрос очень прост: была ли проблема в более ранних версиях компилятора ifort или я что-то не так делаю? На данный момент я нашел очень простой обходной путь (который состоит в переопределении оператора (*) для работы с отдельными элементами данных, т.е. без какого-либо цикла в function data_times_data
), но мне было бы интересно узнать чистый способ переписать код выше, чтобы избежать текущей проблемы при полном использовании функциональных возможностей оператора перегрузки.
Большое спасибо.