изменение формы массива fortran без временного массива

Я передаю некоторые данные, считанные функцией C, в процедуру Fortran, которая будет выполнять всю работу с числами. Массив, естественно, рассматривается как имеющий форму (2, nn) в Фортране. Поскольку в C нет многомерных массивов, массив выделяется и используется в C с длиной 2 * nn.

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

subroutine fortran_glue_code(n, array) bind(c)
    use iso_c_binding, only: c_int
    integer(c_int), intent(in) :: n, array(2 * n)
    real(double_precision) :: result

    call do_the_number_crunching(result, reshape(array, [2, n]))
    { do stuff with the result... }
end subroutine

subroutine do_the_number_crunching(result, array)    ! not C-interoperable
    real(double_precision), intent(out) :: result
    integer, intent(in) :: array(:,:)

    if (size(array, 1) /= 2) then
        print *, "Wrong size!"
        call exit(1)
    end if

    { crunch crunch crunch... }
end subroutine

Что меня не устраивает, так это то, что reshape без необходимости создает временный массив, и с данными, которые я буду использовать, причем очень большим.

Рассматриваемая процедура обрабатывает array как доступную только для чтения, поэтому я думаю, что вместо создания копии массива компилятор может просто создать новый заголовок массива Fortran, который ссылается на то же место в памяти для содержимого массива, только с другими Габаритные размеры. Есть ли способ избежать копирования массива с изменением формы?


person korrok    schedule 21.11.2014    source источник


Ответы (2)


Я не понимаю твоей проблемы, почему бы тебе просто не сделать

subroutine fortran_glue_code(n, array) bind(c)
    use iso_c_binding, only: c_int
    integer(c_int), intent(in) :: n, array(2, n)
    real(double_precision) :: result

    call do_the_number_crunching(result, array)
    { do stuff with the result... }
end subroutine

?

В качестве альтернативы вы также можете использовать ассоциацию последовательностей

subroutine fortran_glue_code(n, array) bind(c)
    use iso_c_binding, only: c_int
    integer(c_int), intent(in) :: n, array(2 * n)
    real(double_precision) :: result

    call do_the_number_crunching(result, array, n)
    { do stuff with the result... }
end subroutine

subroutine do_the_number_crunching(result, array, n)    ! not C-interoperable
    real(double_precision), intent(out) :: result
    integer, intent(in) :: array(2,n)
    integer, intent(in) :: n

    if (size(array, 1) /= 2) then
        print *, "Wrong size!"
        call exit(1)
    end if

    { crunch crunch crunch... }
end subroutine

но это ненужное усложнение.

person Vladimir F    schedule 22.11.2014
comment
Ах, я думал, что array может иметь размер только 2*n в коде клея по какой-то глупой причине или по другой, но это имеет смысл. - person korrok; 23.11.2014

Если вы использовали int ** в коде C, а затем type (c_ptr) в Fortran, вы могли бы использовать встроенную подпрограмму c_f_pointer, чтобы связать C-указатель с массивом Fortran с атрибутом указателя, обозначая размерность массива Fortran третьим аргументом c_f_pointer. Предположительно, мне кажется, что компилятору не нужно будет выполнять копирование, а вместо этого он создаст указатель/структуру Fortran, используя адрес C-указателя для поиска данных.

person M. S. B.    schedule 22.11.2014