2015-11-18 2 views
1

Я использую API в Fortran, который предоставляет рутину для записи данных. Скажем, его имя api_write_data. Эта процедура ожидает массив как аргумент, который может быть размером 1, 2 или 3.Pass 1D массив в 3D-массив

Я хочу написать подпрограмму, которая работает как оболочка для этой процедуры API. Но поэтому мне необходимо написать рутину, которая может обрабатывать массивы 1D, 2D или 3D и может корректно передавать их в процедуру API. Как я могу это сделать? Могу я вообще это сделать?

Мой подход был что-то вроде этого, но это не работает:

subroutine write_data(array) 
implicit none 
integer, dimension(:,:,:), intent(in):: array 

call api_write_data(array) 

end subroutine write_data 

Однако, когда я называю эту процедуру с например массива 1D, я получаю известную ошибку:

Error: Rank mismatch in argument 'array' at (1) (rank-3 and rank-1) 

Есть ли способ сделать такие вещи в Фортране? Для меня необходимо передать массив как 1D, 2D или 3D массив в процедуру write_data. Тем не менее, я мог бы передать массив как массив 1D в api_write_data.

Вы хоть представляете, как я мог это сделать?

ответ

1

Альтернативой функции reshape может быть иметь 1D указатель в сторону многомерного массива:

p(1:size(c)) => c(:,:,:) 

Вы можете передать указатель в виде одномерного массива, не создавая копии. Фактически, он должен быть таким же быстрым, как передача самого массива. Конечно, вам нужно каким-то образом говорить подпрограммы, которые формируют массив имеет:

module test_mod 
contains 
    subroutine print_arr(arr, dimX, dimY, dimZ) 
    integer,intent(in) :: arr(:) 
    integer,intent(in) :: dimX, dimY, dimZ 

    if (dimZ == 0) then 
     if (dimY == 0) then 
     ! 1D 
     print *, "1D array provided" 
     print *, "a(4) =", arr(4) 
     else 
     ! 2D 
     print *, "2D array provided" 
     print *, "a(1,2) =", arr((2-1)*dimX+1) 
     endif 
    else 
     ! 3D 
     print *, "3D array provided" 
     print *, "a(1,2,1) =", arr(((1-1)*dimY + (2-1))*dimX+1) 
    endif 
    end subroutine 
end module 

program test 
use test_mod 
    integer :: i 
    integer, target :: a(8) 
    integer, target :: b(4,2) 
    integer, target :: c(2,2,2) 
    integer, pointer :: p(:) 

    a = [ (i,i=1,8) ] 
    b = reshape(a, [4,2]) 
    c = reshape(a, [2,2,2]) 

    p(1:size(a)) => a(:) 
    call print_arr(p, 8, 0, 0) 

    p(1:size(b)) => b(:,:) 
    call print_arr(p, 4, 2, 0) 

    p(1:size(c)) => c(:,:,:) 
    call print_arr(p, 2, 2, 2) 
end program 

Это также работает наоборот ... Вы можете сопоставить 1D массив в 3D указатель:

integer, pointer :: p2(:,:,:) 
!... 
p2(1:4,1:2,1:1) => a 
+0

без ограничения на fortran 90, была бы еще одна возможность? Возможно, с новыми языковыми функциями, которые также могут быть скомпилированы ifort и gfort для файлов .f90 – Skyy2010

1

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

interface write_data 
    module procedure write_data_1d 
    module procedure write_data_2d 
    module procedure write_data_3d 
end interface write_data 

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

+0

'reshape', тем не менее, дает возможность копирования. – francescalus

+0

Это будет один из вариантов, но это приведет к большому количеству кода. Потому что у меня есть 6 различных версий этих подпрограмм, которые дали бы мне всего 18 подпрограмм. – Skyy2010

+0

@francescalus, что вы имеете в виду? – Skyy2010

Смежные вопросы