Use Fortran subroutine in R? Undefined symbol

前端 未结 3 1748
暗喜
暗喜 2020-12-12 02:03

This is a follow up to my previous question. I wrapped my Fortran code in a module and now it compiles when I run:

R CMD SHLIB ./Fortran/Fpi.f90
相关标签:
3条回答
  • 2020-12-12 02:18

    Aparently I cannot wrap the subroutines in a module. This fortran code is working:

    subroutine dboard(darts, dartsscore)
      implicit none
      integer, intent(in)           :: darts
      double precision, intent(out) :: dartsscore
      double precision              :: x_coord, y_coord
      integer                       :: score, n
    
    score = 0
    do n = 1, darts
      call random_number(x_coord)
      call random_number(y_coord)
    
      if ((x_coord**2 + y_coord**2) <= 1.0d0) then
      score = score + 1
      end if
    end do
    
    dartsscore = 4.0d0*score/darts
    
    end subroutine dboard
    
    subroutine pi(avepi, DARTS, ROUNDS)
      implicit none
      double precision, intent(out)   ::  avepi
      integer, intent(in)             ::  DARTS, ROUNDS
      integer                         ::  MASTER, rank, i, n
      integer, allocatable            ::  seed(:)
      double precision                ::  pi_est, homepi, pirecv, pisum
    
    interface 
       subroutine dboard(darts, dartsscore)
          implicit none
          integer, intent(in)           :: darts
          double precision, intent(out) :: dartsscore
       end subroutine dboard
    end interface
    
    ! we set it to zero in the sequential run
    rank = 0
    ! initialize the random number generator
    ! we make sure the seed is different for each task
    call random_seed()
    call random_seed(size = n)
    allocate(seed(n))
    seed = 12 + rank*11
    call random_seed(put=seed(1:n))
    deallocate(seed)
    
    avepi = 0
    do i = 0, ROUNDS-1
      call dboard(darts, pi_est)
      ! calculate the average value of pi over all iterations
      avepi = ((avepi*i) + pi_est)/(i + 1)
    end do
    end subroutine pi    
    

    and this is the R code:

    system("R CMD SHLIB ./Fortran/Fpi.f90")
    
    mypi <- function(DARTS, ROUNDS) {
      dyn.load("./Fortran/Fpi.so")
      retvals <- .Fortran("pi", avepi = as.numeric(1), DARTS =  as.integer(DARTS), ROUNDS =  as.integer(ROUNDS))
      return(retvals$avepi)
    }
    
    mypi(DARTS = 50000, ROUNDS = 10)
    
    0 讨论(0)
  • 2020-12-12 02:22

    Your problem comes down to the declaration of dboard:

       double precision                ::  pi_est, homepi, pirecv, pisum, dboard
    

    Here you are saying that dboard is an external function, rather than a module procedure. This explains why there is a symbol dboard_ coming into play. You want to remove that:

    double precision                ::  pi_est, homepi, pirecv, pisum
    

    and instead rely, in pi on the module procedure-ness of dboard: pi already knows about it without this declaration.

    Now, beyond that, because pi is in a module there is going to be some name mangling going on for that subroutine itself. I'd solve this problem by making pi itself a (C) interoperable procedure.

    Module Fpi 
      IMPLICIT NONE
    contains 
      subroutine pi(avepi, DARTS, ROUNDS) bind(C)
        use, intrinsic :: iso_c_binding, only : c_double, c_int
        real(c_double), intent(out)   ::  avepi
        integer(c_int), intent(in)    ::  DARTS, ROUNDS
        ...
    

    and then using .C rather than .Fortran.

    You can keep pi and dboard in the module, and this latter needn't even be interoperable.

    0 讨论(0)
  • Try to fix the name of the fortran call inside the R function. You typed "pi" where it should be "Fpi". Also, why not bring the function to your path instead of passing a long path inside the function?

    mypi <- function(DARTS, ROUNDS) {
      dyn.load("./Fortran/Fpi.so")
      retvals <- .Fortran("Fpi", DARTS = as.integer(DARTS) , ROUNDS = as.integer(ROUNDS), answer = as.numeric(1))
      return(retvals$answer)
    }
    

    mypi(DARTS = 50000, ROUNDS = 10)

    0 讨论(0)
提交回复
热议问题