我正在和R一起工作,但需要做很多数字运算,我想在fortran做。 我是R的新手,也是fortran的新手......我已经有了一个有效的R程序,我想优化它。 我创建了一个Fortran程序来解决ODE系统,我将其保存在子程序中。 我还使用一个名为aux.f90的模块来存储参数和一个函数,该函数创建一个馈入方程的信号。 这按预期工作,数据保存在.txt文件中。

我现在要做的是创建一个R前端,向Fortran程序抛出参数,例如模拟的长度或解决方案中使用的步骤数。 然后Fortran完成繁重的工作,将结果保存在文件中,我可以使用R来显示文件中的数据。 请参阅下面的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调用。但是,我找不到创建这个的方法包装子程序首先。 甚至可以在子程序中调用实际程序吗? 我在网上找不到任何有用的东西。

===============>>#1 票数:4 已采纳

程序应该作为可执行文件链接,因此你不能从子程序中调用它 - 或者你调用可执行文件(在gfortran中使用SYSTEM ),但你可以直接从R中执行

从R调用Fortran的简单方法是.Fortran R函数,它调用Fortran subroutine (不是function ,也不是program )。

基本步骤是:

  • 编译一个Fortran DLL,导出你需要的子程序(当然它们可能是其他子程序或函数的包装器)
  • 将DLL放在系统路径的目录中
  • 从R,用dyn.load加载DLL
  • .Fortran调用你的子程序。

如果你使用gfortran,你可以安装Rtools,它拥有你需要的一切。 如果要使用其他编译器,可能会遇到一些问题,尤其是名称。

从您的评论到user2188538的答案,我看到您已经知道所有这些步骤,但要非常小心符号名称。 .Fortran帮助: 使用.Fortran谨慎编译Fortran 9x代码:如果使用的Fortran 9x编译器与配置R时使用的Fortran 77编译器不同,它可能不起作用,特别是如果子例程名称不是小写或包括一个下划线。 也可以使用.C并自己进行任何必要的符号名称翻译。

另外,我怀疑你的包装器子程序不应该驻留在一个模块中,否则你可能会遇到额外的名字问题。 但这只是包装函数的一个限制,它必须从R中可见。

您可以检查DLL中的导出名称(将objdump -x your.so发送到文件并查找导出的符号)。 在加载DLL之后,还可以使用is.loaded("your.symbol")检查R。 请注意,通常,gfortran会在名称中添加额外的下划线,而在从R调用.Fortran时则不需要。如上所述,您可以使用.C (但是请记住Fortran参数通过引用传递)。

为了检查你是否理解了整个过程,我建议你在一个简单的例子上进行测试,例如只有z=x+y的唯一子程序mysub(x,y,z) 当这个运行时,您可以详细说明它来调用更复杂的例程。

编辑当你将数组参数从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 (请参阅.CallR Internals的帮助)。

===============>>#2 票数:1

你确实可以使用R base包中的.Foreign函数从R调用Fortran(参见?.Foreign )。 有关如何执行此操作的一些明确示例,请参阅以下页面,了解如何从R调用Fortran(以及C): http//users.stat.umn.edu/~geyer/rc/

  ask by StefanF translate from so

未解决问题?本站智能推荐:

2回复

如何在Fortran界面中使用用户定义的类型

在一个Fortran 2003模块,我定义类型,称为t_savepoint ,后来,我想定义一个调用的子程序的接口fs_initializesavepoint ,这需要类型的对象t_savepoint作为唯一的参数。 这是整个模块的代码: 之所以需要这样的接口,是因为稍后我将使此f
1回复

Fortran中的接口

我在调试某些代码时偶然发现了接口的一个特定问题,其中一个被调用的子例程的伪参数为2级,而实际参数为1级。这些参数之间的差异导致读取无效。 为了重现,我创建了一个小程序(现在忽略注释! <> ): 和一个模块 据我了解,此子例程通过放置在模块中而获得自动(显式)接
1回复

如何使用Fortran接口调用包含用户定义类型的C函数

实际上,我想从fortran中调用岩浆。 因此,我添加magma.lib并创建一个接口来使用magma的C功能: 但是参数uplo是用户在C代码中定义的类型(magma_uplo_t uplo): magma_int_t = int,有人知道如何为其创建接口吗? 提前致谢
1回复

Fortran函数重载

有没有一种方法可以在Fortran中执行以下操作,而不必为每个维度数组都明确执行此操作? 为了明确起见,我希望能够调用arrayStuff函数,如果它是2x2数组,我希望它选择2x2,对于所有其他大小,选择NxN,而不必专门为3x3、4x4、5x5创建函数,等。
3回复

在R中使用Fortran子例程? 未定义的符号

这是我先前的问题的跟进。 我将Fortran代码包装在一个模块中,现在可以在运行时进行编译: 这是我的Fortran代码: 我正在尝试在R中运行此命令: 我得到这个错误:
2回复

重载Fortran中的子例程和函数

是否可以使用接口块重载子例程和功能? 因此,可以通过函数或子例程调用过程。 例如: 当我尝试编译与此类似的代码时,出现错误:错误:在(1)的通用接口'TestRoutine'中,过程必须是全部SUBROUTINES或所有FUNCTION。 提前致谢!
1回复

在fortran中编写特定接口的正确方法是什么?

我尝试了以下代码以使代码正常工作。 看来我需要编写一个接口以避免错误的结果。 我写了以下内容,但没有通过编译阶段。 错误如下:(使用gfortran编译器) 这是可编译的代码来说明此问题。
2回复

函数或子例程中的Fortran和接口块

我想编写一个模块,它将根据“user”在不同文件中提供的函数类型执行一些操作。 该函数将作为该模块的“execute(...)”子例程的参数传递。 这基本上是我想要获得的,但我不知道这是否可行,我该怎么做才能正确。 我知道这段代码不会编译,但这只是一个草图,它会是什么样子。 对于我
1回复

Fortran中的接口类型绑定过程

我试图将interface d过程定义为Fortran type定义中的类型绑定过程,但它似乎无法正常工作。 考虑以下模块: 以及使用该模块的相应程序: 我希望这可以编译,结果应该是4和11.但是,gfortran报告以下错误: 解决方法是使用generic类型绑定过程
2回复

如何在Fortran中访问PRIVATE PUBLIC接口?

我有以下代码: 问题是模块mp如下: 它是私有的,但接口是公共的。 我无法修改mp模块(属于我要连接的另一个软件)。 我使用以下Makefile: 这样,尽管我可以访问包含模块“ mp”的模块libmod.a中的公共接口。 它不起作用,并且出现此错误: