包装fortran程序用于R
我正在使用R,但需要做大量的数字运算,这是我想用fortran做的。我对R比较陌生,对fortran也是个新手。。。我已经有一个工作的R程序,我想优化。我创建了一个Fortran程序来解决一个ODE系统,我把它保存在一个子程序中。此外,我还使用了一个名为aux.f90的模块来存储参数和一个函数,该函数创建一个信号,并将其输入到方程中。这将按预期工作,数据保存在.txt文件中 我现在想做的是创建一个R前端,它向Fortran程序抛出参数,例如模拟的长度或解决方案中使用的步骤数。然后Fortran完成了繁重的工作,将结果保存在文件中,我可以使用R可视化文件中的数据。请参见下面的Fortran代码:包装fortran程序用于R,r,interface,fortran,R,Interface,Fortran,我正在使用R,但需要做大量的数字运算,这是我想用fortran做的。我对R比较陌生,对fortran也是个新手。。。我已经有一个工作的R程序,我想优化。我创建了一个Fortran程序来解决一个ODE系统,我把它保存在一个子程序中。此外,我还使用了一个名为aux.f90的模块来存储参数和一个函数,该函数创建一个信号,并将其输入到方程中。这将按预期工作,数据保存在.txt文件中 我现在想做的是创建一个R前端,它向Fortran程序抛出参数,例如模拟的长度或解决方案中使用的步骤数。然后Fortran完
! The auxiliary module contains all parameters
module aux
implicit none
integer,parameter :: n = 2**8 ! number of steps
real(kind=4) :: jout = 0.5 ! for normal metabolism
real(kind=4) :: alp = 4.0 ! factor for growth
real(kind=4) :: bet = 1.0 ! benefit value
real(kind=4) :: etay = 0.1 ! cost value y
real(kind=4) :: etaz = 0.10 ! cost value z
real(kind=4) :: h = 3.0 ! Hill coefficient
real(kind=4) :: Kx = 0.07 ! saturation coefficient
real(kind=4) :: t1 = 0.0, t2 = 30.0 ! start and end point of the simulation
contains ! function f(t) to create a step signal
real(kind=4) function f(t)
implicit none
real(kind=4), intent(in) :: t ! taking time value
real(kind=4) :: tt
!real(kind=4), intent(out) :: s ! giving out the signal
real(kind=4) :: period = 5 ! defining the period length
tt = MODULO(t,period)
! Signal function
if (tt > 0.5*period) then
f = 1
else
f = 0
endif
end function
end module aux
! The program solving the ODE system and giving the output as a fileprogram ffl
program ffl
use aux ! Use module aux
implicit none
integer :: m,j ! iteration variable
real(kind=4), dimension(6) :: b =(/0.0, 0.2, 0.4, 0.6, 0.8, 1.0/) ! expression
real(kind=4) :: dt ! time resolution
real(kind=4), dimension(n) :: t ! time vector
real(kind=4), dimension(4) :: x_new, x_aux, y_new, y_aux, q0 ! vectors
! computing the time vector
dt=(t2-t1)/real(n) ! calculating time resolution
t(1) = t1 ! setting first time value to t1 = 0
do m = 1,n ! filling the time vector
t(m) = t(m-1)+dt
end do
open(unit = 10,file = 'ffl.txt', status = 'unknown')
do j=1,6
k = b(j)
! initial conditions
q0(1) = 0 ! x
q0(2) = k ! y
q0(3) = 0 ! z
q0(4) = 0 ! w
!open(unit = 10,file = 'ffl.txt', status = 'unknown')
x_new = q0 ! set initial conditions
write(10,*)t(1),x_new(1),x_new(2),x_new(3),x_new(4) ! saving data
do m = 2,n
! Solving with a second order method
call derivate(t(m-1),x_new,y_new) ! call the derivate routine
x_aux = x_new + dt*y_new
call derivate(t(m),x_aux,y_aux)
x_new = x_new + 0.5*dt*(y_new+y_aux)
write(10,*)t(m),x_new(1),x_new(2),x_new(3),x_new(4) ! saving data
end do
end do
close(10)
end program ffl
! The subroutine derivate gives the system of ODE's to be solved
subroutine derivate(time,y,z)
use aux ! Use module aux
implicit none
real(kind=4), intent(in) :: time ! input: time vector
real(kind=4), dimension(4), intent(in) :: y ! input: initial conditions vector
real(kind=4), dimension(4), intent(out):: z ! output: results vector
z(1) = f(time)-y(1) !dx/dt
z(2) = k+(1-k)*((1+Kx)*(y(1)**h))/((y(1)**h)+Kx)-y(2) !dy/dt
z(3) = ((1+Kx)*(y(1)**h)/((y(1)**h)+Kx)*((1+Kx)*(y(2)**h))/((y(2)**h)+Kx)-y(3)) !dz/dt
z(4) = f(time)*y(3)-etay*(k+(1-k)*((1+Kx)*(y(1)**h))/((y(1)**h)+Kx)) & !dw/dt
-etaz*(((1+Kx)*(y(1)**h))/((y(1)**h)+Kx)*((1+Kx)*(y(2)**h))/((y(2)**h)+Kx))
结束子程序派生
我已经阅读了“编写R扩展”文档,但没有发现它有什么帮助
现在来回答问题:因为R需要一个Fortran子例程,我想用Fortran创建一个包装器子例程,它利用我现有的文件,然后我可以从R调用它。但是,我首先找不到创建这个包装器子例程的方法。甚至可以在子例程中调用实际程序吗?我在网上找不到任何有用的东西。您确实可以使用R基本包中的
.Foreign
函数从R调用Fortran(请参见?.Foreign
)。有关如何执行此操作的一些明确示例,请参见下面关于如何从R调用Fortran(以及C)的页面:程序应该链接为可执行文件,因此您不能从子例程调用它-或者调用可执行文件(使用gfortran),但您可以这样做
从R调用Fortran的简单方法是R函数,它调用Fortran子例程(不是函数,也不是程序)
基本步骤是:
- 编译Fortran DLL,导出所需的子例程(当然,它们可能是其他子例程或函数的包装器)
- 将DLL放在系统路径的目录中
- 从R中,用
- 使用
.Fortran
调用子例程
如果您使用gfortran,您可以只安装Rtools,它拥有您所需要的一切。如果要使用另一个编译器,可能会遇到一些问题,尤其是在名称方面
从您对user2188538的回答的评论中,我看到您已经知道了所有这些步骤,但是要非常小心使用符号名称。从.Fortran
帮助:小心使用.Fortran编译的Fortran 9x代码:如果在配置R时使用的Fortran 9x编译器与使用的Fortran 77编译器不同,则可能无法工作,尤其是如果子例程名称不是小写或包含下划线。也可以使用.C并自己翻译任何必要的符号名
此外,我怀疑您的包装子例程不应该驻留在模块内,否则您可能会在名称方面遇到额外的问题。但这只是包装器函数的一个限制,它必须从R可见
您可以检查DLL中导出的名称(将objdump-x your.so
发送到文件并查找导出的符号)。并在加载DLL后,用is.loaded(“your.symbol”)
在R中进行检查。请注意,gfortran通常会在名称后附加一个下划线,而当您从R调用.Fortran
时,则不需要附加下划线。如上所述,您可以使用.C
(但请记住,Fortran参数是通过引用传递的)
为了检查您是否理解整个过程,我建议您在一个简单的示例上测试它,例如一个唯一的子例程mysub(x,y,z)
,它只执行z=x+y
。当这个程序运行时,您可以详细说明它以调用更复杂的例程
编辑
将数组参数从R传递到Fortran时,不应使用假定形状或延迟形状数组,而应仅使用假定大小的数组,即在Fortran 77中传递的常用数组。这是因为R只知道如何向原始数据传递指针,而假定形状和延迟形状需要更多信息,而R不知道这样做的数据结构
例如,您可以这样做:
subroutine mysub(n, a)
real :: a(n, n)
...
end subroutine
但这肯定会失败:
subroutine mysub(a)
real :: a(:, :)
...
end subroutine
此外,您不能将函数参数从R传递到Fortran,因为这需要回调的特殊数据结构(在后台,R是Scheme方言,它使用S表达式)。您可以在C语言中通过.C
或.Call
(请参阅和的帮助)。谢谢您的回答。我已经尝试使用以下命令创建一个.so文件:gfortran-c-fPIC ffl.f90、gfortran-c-fPIC aux.f90,然后是gfortran-shared-o ffl.so ffl.o aux.o。然后,我使用dynload(“ffl.so”)和.Fortran(“ffl”)创建了一个.R程序,但没有成功,并导致了错误:未定义的符号:aux_MOD_k正如我所说的,我曾考虑创建一个包含上述所有部分的包装子例程,但找不到这样做的方法。任何进一步的帮助都将不胜感激。也许我只是错过了一件简单的事情:为什么不试试下面的方法?(1) 编写Fortran代码和包装Fortran函数(如果需要);(2) 将Fortran代码编译到共享库中;(3) 编写一个简单的R包装函数(在R中,使用dyn.load
和.Fortran
函数);(4) 使用R包装器函数(在R中使用源代码函数)。感谢您的回答!下划线确实有问题,解决方案是使用gfortran-fno second-underline-shared-o ffl.so aux.o ffl.o并使用-fno second-underline语句进行编译。