Well, I recently fell in love with Fortran (f90) and have been trying to understand the "kung-fu" of R and Fortran. I found several relevant and helpful questions here (e.g. this and this).
What I am trying to do:
I am (probably, trying to do something crazy) trying to call the following .f90 subroutines in R (x64) using .Fortran() function. Here is the test.f90 code:
! Computes the square of a number
Subroutine sr1(a,b)
!DEC$ ATTRIBUTES DLLEXPORT::sr1
!DEC$ ATTRIBUTES C, REFERENCE, ALIAS:'sr1' :: sr1
implicit none
integer a,b
b = a*a
End Subroutine sr1
! Computes the cube of a number
Subroutine sr2(x,y)
!DEC$ ATTRIBUTES DLLEXPORT::sr2
!DEC$ ATTRIBUTES C, REFERENCE, ALIAS:'sr2' :: sr2
implicit none
integer x,y
y = x*x*x
End Subroutine sr2
I am compiling the above test.f90 code via gfortran on my Windows 10 machine by:
gfortran -shared -o test.dll test.f90
The compilation works and I get the test.dll. Now, in R. I try to load it:
dyn.load("path_to_file/test.dll")
It works. But, it fails here:
> is.loaded("test")
[1] False
I already found a relevant question here. But, I could not get the clue to fix my problem. Can someone suggest some workaround to fix the issue?
I am not a big user of R, but my tests show that while
is.loaded("test_R")
indeed returns FALSE, both
is.loaded("sr1")
and
is.loaded("sr2")
return TRUE. But I did my tests on Linux and GCC which may interpret the extrnally visible subroutine names differently.
Related
On my Windonws 10 (x64) machine, I have been trying to call Fortran subroutines in R using .Fortran() function via gfortran. The following example code (test.f90) works fine:
The Example code:
! Computes the square of a number
Subroutine sr1(a,b)
!DEC$ ATTRIBUTES DLLEXPORT::sr1
!DEC$ ATTRIBUTES C, REFERENCE, ALIAS:'sr1' :: sr1
implicit none
integer a,b
b = a*a
End Subroutine sr1
I compiled code in gfortran, which worked fine:
gfortran -shared -o test.dll test.f90
and then calling this subroutine in R:
dyn.load("path_to_file/test.dll")
is.loaded("sr1") #Returns TRUE
.Fortran("sr1", a=as.integer(12), b=as.integer(10))
What I would like to do:
I also have Intel Fortran (iFORT) and Lahay Fortran compilers installed at my machine. Now, I would like to add pre-processor directives in the above code for these multiple Fortran compilers (so that same test.f90 file can be used for all compilers).
What I have tried:
I found a relevant question here, and tried to modify the code (test_mod.f90) like follows:
! Computes the square of a number
Subroutine sr1(a,b)
#ifdef COMPILER_GF
!DEC$ ATTRIBUTES DLLEXPORT::sr1
!DEC$ ATTRIBUTES C, REFERENCE, ALIAS:'sr1' :: sr1
#endif
#ifdef COMPILER_IF
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL ::sr1
!DEC$ ATTRIBUTES DECORATE, ALIAS : 'sr1' :: sr1
!DEC$ ATTRIBUTES REFERENCE :: a,b
#endif
#ifdef COMPILER_LF
dll_export sr1
#endif
implicit none
integer a,b
b = a*a
End Subroutine sr1
I tried to compile the code using:
gfortran -shared -o test_mod.dll test_mod.f90 -DCOMPILER_GF
and got this errors:
Warning: test_mod.f90:5: Illegal preprocessor directive
Warning: test_mod.f90:8: Illegal preprocessor directive
Warning: test_mod.f90:10: Illegal preprocessor directive
Warning: test_mod.f90:14: Illegal preprocessor directive
Warning: test_mod.f90:16: Illegal preprocessor directive
Warning: test_mod.f90:18: Illegal preprocessor directive
test_mod.f90:17.1:
dll_export sr1
1
Error: Unclassifiable statement at (1)
I am new to Fortran and most probably, made a mess in compilation or adding pre-processor directives in incorrect way. Can someone suggest me how can I fix this issue?
Okay, I figured out the thing. I fixed the problem and the full credits goes to the comment of #francescalus above :).
The following line at Windows CMD created DLL without errors and warnings and I am able to read and execute Fortran subroutine in R.
gfortran -shared -o test_mod.dll test_mod.f90 -DCOMPILER_GFORTRAN -cpp
Based on #Vladimir's comment, I would like to add that if code file is renamed to .F90. Then, it can also be compiled without -cpp flag, like follows:
gfortran -shared -o test_mod.dll test_mod.F90 -DCOMPILER_GFORTRAN
What is the best way to make unit testing with testthat on functions that read and write files?
Apologies for asking a complicated question, but I am not sure what is wrong here.
I have implemented a number of functions in Fortran, that reads and writes files. They are compiled in an R package cf. Writing R Extension manual. My unit testing with testthat generates random content that is written to temporary files with tempfile(). Running R CMD check on the R package works on my local Windows machine.
Running with R-devel fails however because it cannot detect Rtools for R-3.5.0 (devel). So I submitted to win-builder.
http://win-builder.r-project.org/ however fails with the following error:
At line 9 of file auxil.f95
Fortran runtime error: Actual string length is shorter than the declared one for dummy argument 'fn' (96/255)
with corresponding Fortran source:
subroutine get_nlines(fn, nlines, stat) !line 9
implicit none
!! Arguments
character(255), intent(in) :: fn
integer, intent(out) :: nlines, stat
!! Local variables
character(len=1) :: one
nlines = 0
open(40, file=fn, status='OLD')
do
read(40, *, iostat=stat) one
if (stat /= 0) exit
nlines = nlines + 1
end do
close(40)
end subroutine
The Fortran code is stored in the src subdirectory of the R package, and is called with
get_nlines <- function(fn) {
stopifnot(file.exists(fn))
res <- .Fortran('get_nlines', fn=as.character(fn), nlines=integer(1), stat=integer(1))
if (res$nlines == 0 & res$stat != 0) {
warning(paste0('get_nlines did not read lines; IOSTAT error ', res$stat, '.'))
return(structure(NA, code=res$stat))
}
res$nlines
}
So there it is.
I don't know if my Fortran code is wrong, or if it's something that occurs on the win-builder server.
"I don't know if my Fortran code is wrong" I still simply don't understand from your question if the code you have shown is "the" your code or if it is inside some R package you are using.
If it is the Fortran code you are speaking about (you didn't show anything else), then you should try character(*) instead of character(255), because there is no apparent reason for the exact fixed length 255. That is exactly what the error message complains about, that fn is not exactly 255 chars long as you require in get_nlines().
This is my first attempt at library assembly, so please have mercy!
I am trying to link an external library (written in .f90 and compiled with IVF on VS2012) to my Qt application (32bit based on Qt 5.5.0- MinGW 4.9.2).
I have a few questions:
1) Is this futile? Some of the research I have found suggests that IVF and MinGW are ABI incompatible. I really want to stay with the MinGW compiler in Qt because basically everything else we are doing with the software uses this.
2) It would be of advantage to be able to load the library only when called upon (which would only represent a fraction of cases). For this reason I have been attempting to use QLibrary but keep getting Segmentation faults when I try to call SUBROUTINES defined in my DLL (with resolve("my_function")):
I have defined my external subroutine as (just a simple test at this stage, not actually important for what I wanted to do!)
Although the actual code I need to access is much more complicated (baby steps!), I wrote a simple subroutine to return the square of an integer:
SUBROUTINE SQ(a,asquare)
!DEC$ ATTRIBUTES C, REFERENCE, MIXED_STR_LEN_ARG, DLLEXPORT, ALIAS:"SQ" :: SQ
integer, intent(in) :: a ! input
integer, intent(out) :: asquare ! output
asquare = a**2
END SUBROUTINE SQ
I import the library and call it within Qt with:
typedef int (*MyPrototype)(int i);
MyPrototype Square = (MyPrototype) FAST.resolve("SQ");
int K = 4;
int J = Square(K);
This results in a segregation error
3) Is there any way to check if the library has, in fact, loaded? Of course calling a subroutine would accomplish this, but that isn't working, and when I import the library DLLname.load() returns a positive result. and resolve.("sub_name") has a memoryaddress allocated to it. Does this suggest a type fault? Ie. passing the wrong identifier in to the fortran code.
Once again, thanks for reading and please feel free to take apart any flaws in logic I have, I'm not a programmer!
I am working with R, but need to do a lot of number crunching, which I want to do in fortran. I am relatively new to R and a newbie to fortran... I already have a working R program, which I would like to optimize. I created a Fortran program solving a system of ODE's, which I keep in a subroutine. I additionally use a module called aux.f90 to store the parameters and a function which creates a signal that is fed into the equations. This works as intended and the data is saved in a .txt file.
What I would like to do now is to create an R front-end that tosses the Fortran program the parameters, such as the length of the simulation or the number of steps used in the solution. Then Fortran does the heavy lifting, saves the results in the file and I can use R to visualize the data from the file. See the Fortran code below:
! 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))
end subroutine derivate
I have read the "Writing R extensions" document, but did not find it very helpful...
NOW to the questions: Since R needs a Fortran subroutine, i would like to create a wrapper subroutine in fortran that makes use of my existing files, which I can then call from R. However, i can't find a way to create this wrapper subroutine in the first place. Is it even possible to call an actual program in a subroutine? I couldn't find anything helpful online.
A program is supposed to be linked as an executable, so you can't call it from a subroutine - or you call the executable (with SYSTEM in gfortran), but you could do that directly from R.
The easy way to call Fortran from R is the .Fortran R function, which calls a Fortran subroutine (not a function, nor a program).
The basic steps are :
compile a Fortran DLL, exporting the subroutines you need (of course they may be wrappers for other subroutines or functions)
put the DLL in a directory in your system path
from R, load the DLL with dyn.load
call your subroutine with .Fortran.
If you use gfortran, you may just install Rtools, which has everything you need. If you want to use another compiler, you may have some trouble, especially with names.
From your comment to user2188538's answer, I see you already know all these steps, but be very careful with symbol names. From the .Fortran help: Use .Fortran with care for compiled Fortran 9x code: it may not work if the Fortran 9x compiler used differs from the Fortran 77 compiler used when configuring R, especially if the subroutine name is not lower-case or includes an underscore. It is also possible to use .C and do any necessary symbol-name translation yourself.
Also, I suspect your wrapper subroutine should not reside inside a module, or you may have extra trouble with names. But this is only a limitation for the wrapper function, which must be visible from R.
You can check the exported names in your DLL (send objdump -x your.so to a file and look for exported symbols). And check also in R, with is.loaded("your.symbol"), after loading the DLL. Be aware that usually, gfortran appends an extra underscore to names, whereas it's not needed when you call .Fortran from R. As described above, you may use .C instead (but then, remember Fortran arguments are passed by reference).
To check that you understand the whole process, I suggest you test it on a trivial example, such as a unique subroutine mysub(x,y,z) that does only z=x+y. When this one runs, you can elaborate on it to call more complex routines.
edit
You should not use assumed-shape or deferred-shape arrays, when you pass arrays arguments from R to Fortran, but only assumed-size arrays, that is, the usual array passing in Fortran 77. This is because R knows only how to pass a pointer to raw data, whereas assumed-shape and deferred-shape need more information, and R does not know the data structure to do that.
For example, you can do that:
subroutine mysub(n, a)
real :: a(n, n)
...
end subroutine
But this will amost certainly fail:
subroutine mysub(a)
real :: a(:, :)
...
end subroutine
Also, you can't pass function arguments from R to Fortran, as that would need a special data structure for the callback (under the hood, R is a Scheme dialect, and it uses S-expressions). You may do that in C, through .C or .Call (see help for .Call and R Internals).
You can indeed call Fortran from R using the .Foreign function in the R base package (see ?.Foreign). For some clear examples on how to do this, see the following page on how to call Fortran (as well as C) from R: http://users.stat.umn.edu/~geyer/rc/
I am trying to build a Fortran DLL with Absoft Pro Fortran 13.0.3, 64 bits, for use within R, on Windows 7 64 bits.
Here is my file mycalc.f (it's a dumb example, just to test functionality):
subroutine mycalcf(a,b,c)
real*8 a,b,c
dll_export mycalcf
c=a+b*b
end
The statement dll_export is not standard, but is found in some Fortran compilers (AFAIK it's also found in Lahey and CVF and Intel Fortran has a compiler directive instead). It just tells the compiler which symbols are to be exported.
I compile successfuly with:
af90 -m64 -dll -YDLL_NAMES=LCS mycalc.f -o mycalc.dll
The option -YDLL_NAMES=LCS tells the compiler to build a library with lowercase symbols, which seems better for R.
If I run dumpbin /exports mycalc.dll, I can find mycalcf in exported symbols, in lowercase, without any underscore before or after.
Now, from R (64 bit version), the following works:
dyn.load("mycalc.dll")
is.loaded("mycalcf")
.Fortran("mycalcf", a=4, b=5, c=0)
I get c=29 on return, as expected.
BUT, if I restart R, the following does not work (notice I only removed the is.loaded test):
dyn.load("mycalc.dll")
.Fortran("mycalcf", a=4, b=5, c=0)
I get the error: Fortran symbol name "mycalcf" not in load table.
Now my question is: why is this test so important?
For comparison, when I try the same with gfortran instead of Absoft, I have no problem at all. I compile with: gfortran -m64 -shared -o mycalc2.dll mycalc.f (after commenting out the dll_export statement, which is not needed, nor even recognized, by gfortran).
Then in R:
dyn.load("mycalc2.dll")
.Fortran("mycalcf", a=4, b=5, c=0)
And I get c=29, no error.
Now, I suspect there is something the gcc linker does that is not done automatically by the Absoft linker (actually it's Microsoft's link.exe). But I have no hint what it can be.
Any idea is welcome!
Ok, solution after a good question from Vladimir F (see comments).
Actually, one must append underscores to symbol names. Since there is no way to do it by compiler option, one needs CDEC$ directives (see HP or Intel documentation).
Here it's simply:
subroutine mycalcf(a,b,c)
CDEC$ attributes alias:'mycalcf_' :: mycalcf
real*8 a,b,c
dll_export mycalcf
c=a+b*b
end
Second solution, from Absoft forum: actually I was wrong from the very beginning. Contrary to what I thought, one need not use the dll_export statement, and it even introduced the problem: without it, the compiler appends underscores. All symbols are exported by default, as in gfortran. So the correct code is simply:
subroutine mycalcf(a,b,c)
real*8 a,b,c
c=a+b*b
end
There is even no need for any option to get lowercase symbols, it's also the defaults.
However, one question remains: does the R function .Fortran always add underscore (is there a way to tell it not to?), and if it's always added, why does the call work when is.loaded is called beforehand? R seems to be doing something weird here.
I tried to track is.loaded in R source code (up to do_isloaded in src\main\dotcode.c), to no avail.