2015-07-19 94 views
1

我正在使用OpenMP和Fortran。我將我的用例簡化爲一個簡單的例子。我有一個具有自定義派生類型的對象數組,每個對象都包含一個具有不同大小的數組。我想,以確保在循環無論發生什麼事,我申請減少到矢量對象的所有values陣列組件:使用OpenMP減少數組數組的最佳方式是什麼?

program main 

    implicit none 

    integer :: i 

    type vector 
    real,allocatable :: values(:) 
    end type vector 

    type(vector) :: vectors(3) 

    allocate(vectors(1)%values(3)) 
    vectors(1)%values = 0 

    allocate(vectors(2)%values(6)) 
    vectors(2)%values = 0 

    allocate(vectors(3)%values(9)) 
    vectors(3)%values = 0 

    !$OMP PARALLEL REDUCTION(+:vectors%values) 

    !$OMP DO 

    do i=1,1000 
    vectors(1)%values = vectors(1)%values + 1 
    vectors(2)%values = vectors(2)%values + 2 
    vectors(3)%values = vectors(3)%values + 3 
    end do 

    !$OMP END DO 

    !$OMP END PARALLEL 

    print*,sum(vectors(1)%values) 
    print*,sum(vectors(2)%values) 
    print*,sum(vectors(3)%values) 

end program main 

在這種情況下,REDUCTION(+:vectors%values)不起作用,因爲我得到了以下錯誤:

test2.f90(22): error #6159: A component cannot be an array if the encompassing structure is an array. [VALUES] 
    !$OMP PARALLEL REDUCTION(+:vectors%values) 
-------------------------------------^ 
test2.f90(22): error #7656: Subobjects are not allowed in this OpenMP* clause; a named variable must be specified. [VECTORS] 
    !$OMP PARALLEL REDUCTION(+:vectors%values) 
-----------------------------^ 
compilation aborted for test2.f90 (code 1) 

我試圖超載+意義的載體類型,然後指定REDUCTION(+:vectors),但我仍然得到:

test.f90(43): error #7621: The data type of the variable is not defined for the operator or intrinsic specified on the OpenMP* REDUCTION clause. [VECTORS] 
    !$OMP PARALLEL REDUCTION(+:vectors) 
-----------------------------^ 

推薦的處理方式是什麼衍生出這些類型並使其減少工作?

僅供參考,不OpenMP的編譯時正確的輸出是

3000.000  
12000.00  
27000.00 

回答

3

這不僅僅是OpenMP的問題,你不能引用vectors%values作爲一個實體,如果values是可分配數組組件,因爲2003 Fortran語言的規則禁止這樣做。這是因爲這樣的數組在內存中不會有任何規則的步幅,可分配的組件會隨機存儲在地址中。

如果包含數組元素的數量少,你可以做

!$OMP PARALLEL REDUCTION(+:vectors(1)%values,vectors(2)%values,vectors(3)%values) 

    !$OMP DO 

    do i=1,1000 
    vectors(1)%values = vectors(1)%values + 1 
    vectors(2)%values = vectors(2)%values + 2 
    vectors(3)%values = vectors(3)%values + 3 
    end do 

    !$OMP END DO 

    !$OMP END PARALLEL 

否則你必須使另一個循環,假設j,使減少只是vectors(j)%values

如果編譯器不接受降低子句中的結構組件(有研究的最新標準,看它是否一直沒有放鬆),你可以做一個變通方法

!$OMP PARALLEL 
    do j = 1, size(vectors) 
    call aux(vectors(j)%values) 
    end do 
    !$OMP END PARALLEL 

contains 
    subroutine aux(v) 
    real :: v(:) 

    !$OMP DO REDUCTION(+:v) 
    do i=1,1000 
     v = v + j 
    end do 
    !$OMP END DO 
    end subroutine 

助理或指針會比較簡單,但也不允許。

+0

''vectors(1)%values''似乎不被認爲是有效的語法。如果我嘗試用gfortran 4.9.3進行編譯,我會在OpenMP變量列表中出現''語法錯誤''。這是否適合你,如果是這樣,你使用什麼編譯器? – astrofrog

+0

@astrofrog'gfortran' 5.1接受這個... –

+0

這是因爲語法檢查器需要一個變量名稱而不是表達式。你可以在gfortran-4.8中使用associate作爲解決方法,但後來的版本不喜歡它。 –

0

作爲替代Vladimir's answer,你可以隨時使用臨時陣列和關鍵部分實現自己的削減:

program main 

    implicit none 

    integer :: i 

    type vector 
    real,allocatable :: values(:) 
    end type vector 

    type(vector) :: vectors(3) 
    type(vector),allocatable :: tmp(:) 

    allocate(vectors(1)%values(3)) 
    vectors(1)%values = 0 

    allocate(vectors(2)%values(6)) 
    vectors(2)%values = 0 

    allocate(vectors(3)%values(9)) 
    vectors(3)%values = 0 

    !$OMP PARALLEL PRIVATE(TMP) 

    ! Use a temporary array to hold the local sum 
    allocate(tmp(size(vectors))) 
    do i=1,size(tmp) 
    allocate(tmp(i)%values(size(vectors(i)%values))) 
    tmp(i)%values = vectors(i)%values 
    enddo ! i 

    !$OMP DO 

    do i=1,1000 
    tmp(1)%values = tmp(1)%values + 1 
    tmp(2)%values = tmp(2)%values + 2 
    tmp(3)%values = tmp(3)%values + 3 
    end do 

    !$OMP END DO 

    ! Get the global sum one thread at a time 
    !$OMP CRITICAL 
    vectors(1)%values = vectors(1)%values + tmp(1)%values 
    vectors(2)%values = vectors(2)%values + tmp(2)%values 
    vectors(3)%values = vectors(3)%values + tmp(3)%values 
    !$OMP END CRITICAL 

    deallocate(tmp) 
    !$OMP END PARALLEL 

    print*,sum(vectors(1)%values) 
    print*,sum(vectors(2)%values) 
    print*,sum(vectors(3)%values) 

end program main 

這個片段可以通過遍歷的vectors所有元素更有效地安排。然後,tmp可能是一個標量。

相關問題