这是my previous Fortran question的后续问题。
我有一个有效的Fortran程序,它有一个过滤数组的子程序。这是该计划:
program test
integer, parameter :: n = 3
integer, parameter :: m = 4
double precision, dimension(n,m) :: A
double precision, dimension(:,:), allocatable :: B
A(1,:) = [11, 22, 43, 55]
A(2,:) = [15, 56, 65, 63]
A(3,:) = [54, 56, 32, 78]
print*, 'A :'
print*, int(A)
CALL extractB(A, B)
print*, 'B'
print*, int(B)
contains
subroutine extractB(A, B)
implicit none
double precision, dimension(:,:), intent(in) :: A
double precision, dimension(:,:), allocatable :: B
integer :: nrowB, i, pos
nrowB = count( A(:,2)==56)
allocate( B(nrowB, size(A,2)-1 ) )
pos = 1
do i = 1, size(A,1)
if(A(i,2)==56)then
B(pos,1) = A(i,1)
B(pos,2:) = A(i,3:)
pos = pos+1
end if
end do
end subroutine extractB
end program
程序编译,运行,并且它完成了它必须做的非常好的事情。
我想用R调用extractB
子例程。我已经问过similar questions并且发现它能够使它们工作,但是这个有点不同而且不起作用。
我的fortran subrutine位于mytest.f90文件中,并且有以下代码:
subroutine extractB(A, B)
implicit none
double precision, dimension(:,:), intent(in) :: A
double precision, dimension(:,:), allocatable :: B
integer :: nrowB, i, pos
nrowB = count( A(:,2)==56)
allocate( B(nrowB, size(A,2)-1 ) )
pos = 1
do i = 1, size(A,1)
if(A(i,2)==56)then
B(pos,1) = A(i,1)
B(pos,2:) = A(i,3:)
pos = pos+1
end if
end do
end subroutine extractB
我在R中编译它并使用以下命令加载库:
system("R CMD SHLIB ./Fortran/mytest.f90")
dyn.load("./Fortran/mytest.so")
然后,在R中,我创建数据帧并将其传递给子例程
A = data.frame(c(11,15,54),c(22,56,56),c(43,45,32),c(54,63,78)) X< - .Fortran(“extractB”,A = unlist(A),B =数字(6))
之后R崩溃
*** caught segfault ***
address (nil), cause 'unknown'
Traceback:
1: .Fortran("extractB", A = unlist(A), B = numeric(6))
Possible actions:
1: abort (with core dump, if enabled)
2: normal R exit
3: exit R without saving workspace
4: exit R saving workspace
Selection:
如果我通过手动删除尺寸来更改子程序:
subroutine extract(A, B)
implicit none
double precision, dimension(3,4), intent(in) :: A
double precision, dimension(2,3) :: B
integer :: i, pos
pos = 1
do i = 1, size(A,1)
if(A(i,2)==56)then
B(pos,1) = A(i,1)
B(pos,2:) = A(i,3:)
pos = pos+1
end if
end do
end subroutine extract
重新编译库,然后重新加载它。我可以跑
X< - .Fortran(“提取”,A =未列出(A),B =数字(6))
昏暗(X $ A)< - 昏暗(A) 昏暗(X $ B)< - c(2,3)
得到我想要的东西
> X
$A
[,1] [,2] [,3] [,4]
[1,] 11 22 43 55
[2,] 15 56 65 63
[3,] 54 56 32 78
$B
[,1] [,2] [,3]
[1,] 15 65 63
[2,] 54 32 78
有什么方法可以解决这个问题?
非常感谢您的帮助!
答案 0 :(得分:0)
尽管正如Vladimir F所指出的那样,这对于像这样的allocatable不起作用,你可以分配内存,可以被Fortran中的另一种语言使用。但是在这种情况下你应该使用指针属性。但是,您也无法使用假定的形状数组。您应该明确地传递它,而不是推断A的大小。
如果您愿意为此更改界面,可以使用以下内容获取您的功能,(see also M. S. B.s answer to a related question):
subroutine extractB(A_ptr, lenX, lenY, B_ptr, nrowB) bind(c,name=extractB)
use iso_c_binding
implicit none
type(c_ptr), value :: A_ptr
integer(kind=c_int), value :: lenX, lenY
type(c_ptr) :: B_ptr
integer(kind=c_int) :: nrowB
real(kind=c_double), pointer :: A(:,:)
real(kind=c_double), pointer :: B(:,:)
integer :: i, pos
c_f_pointer(A_ptr, A, [lenX, lenY])
nrowB = count( A(:,2)==56)
allocate( B(nrowB, size(A,2)-1 ) )
!...
B_ptr = c_loc(B)
end subroutine extractB