2016-10-03 2 views
4

Я могу назвать скомпилировать этот код FORtran '' test.f90Вызов Fortran подпрограммы с аргументами массива от Джулии

subroutine test(g,o) 
double precision, intent(in):: g 
double precision, intent(out):: o 
o=g*g 
end subroutine 

с

gfortran -shared -fPIC test.f90 -o test.so 

и создать эту функцию wraper test.jl для Julia:

function test(s) 
    res=Float64[1] 
    ccall((:test_, "./test.so"), Ptr{Float64}, (Ptr{Float64}, Ptr{Float64}), &s,res); 
    return res[1] 
end 

и выполнить эту команду с помощью искомого выхода:

julia> include("./test.jl")  
julia> test(3.4) 
11.559999999999999 

Но я хочу вернуть массив вместо скаляра. Я думаю, что я пробовал все, включая использование iso_c_binding, в ответе this. Но все, что я пытаюсь кидает ошибки у меня глядя, как это:

ERROR: MethodError: `convert` has no method matching convert(::Type{Ptr{Array{Int32,2}}}, ::Array{Int32,2}) 
This may have arisen from a call to the constructor Ptr{Array{Int32,2}}(...), 
since type constructors fall back to convert methods. 
Closest candidates are: 
    call{T}(::Type{T}, ::Any) 
    convert{T}(::Type{Ptr{T}}, ::UInt64) 
    convert{T}(::Type{Ptr{T}}, ::Int64) 
    ... 
[inlined code] from ./deprecated.jl:417 
in unsafe_convert at ./no file:429496729 

В качестве примера, я хотел бы, чтобы вызвать следующий код Джулии:

subroutine arr(array) ! or arr(n,array) 
implicit none 
integer*8, intent(inout) :: array(:,:) 
!integer*8, intent(in) :: n 
!integer*8, intent(out) :: array(n,n) 
integer :: i, j 

do i=1,size(array,2) !n 
    do j=1,size(array,1) !n 
     array(i,j)= j+i 
    enddo 
enddo 
end subroutine 

Использование закомментирована вариант также является альтернатива, так как изменение аргумента не представляется полезным при вызове из julia.

Как я могу вызвать fortran подпрограммы с массивами от Julia?

+1

Вы говорите, что вы пробовали 'iso_c_binding', ты имеешь в виду что на самом деле 'bind (C)' или вы просто использовали модуль 'iso_c_binding'? В каком смысле именно? Какой именно код соответствует сообщению об ошибке в вопросе? –

+0

'integer * 8' не соответствует стандарту и никогда не был частью стандарта ISO FORTRAN/Fortran. Вы можете использовать именованную константу 'INT64' из встроенного модуля' ISO_Fortran_env' или 'C_INT64_T' из' ISO_C_binding' или 'selected_int_kind', чтобы использовать большие целые числа в безопасном переносном режиме. – jlokimlin

+0

Почему ваш ccall для _test описывает функцию, возвращающую указатель, когда процедура Fortran является подпрограммой? –

ответ

4

При использовании ccall массивы Julia должны передаваться как указатели типа элемента, а также дополнительный аргумент, описывающий размер.

Ваш пример test.f90 должен быть:

subroutine arr(n,array) 
implicit none 
integer*8, intent(in) :: n 
integer*8, intent(out) :: array(n,n) 
integer :: i, j 

do i=1,size(array,2) !n 
    do j=1,size(array,1) !n 
     array(i,j)= j+i 
    enddo 
enddo 
end subroutine 

Составитель, как и раньше с

gfortran -shared -fPIC test.f90 -o test.so 

Тогда в Джулии:

n = 10 
X = zeros(Int64,n,n) # 8-byte integers 
ccall((:arr_, "./test.so"), Void, (Ptr{Int64}, Ptr{Int64}), &n, X) 
+0

Это отлично работает, спасибо! Я думаю, что самая последовательная ошибка, которую я совершил, которая мешала мне полностью исполнить этот точный код, заключалась в том, что я в основном пытался с помощью 'Ptr {Array {Int64,2}}' в качестве спецификатора выходной переменной и/или возвращаемого типа в 'ccall'. –

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