Rationale for custom functions
If you have used RFortran a while you will notice that only the basics have been implemented and that there are certain combinations of commands you may use with high frequency. The best practice is to combine the often repeated command sequences into a function, for example: Rput('x',x),Rput('y',y),Rput('plot(x,y)') could be put into a single function such as this:
function Rplot(x,y) result(ok)
implicit none
real, intent(in) :: x(:) ! input x-axis data
real, intent(in) :: y(:) ! input y-axis data
logical :: ok ! error flag
ok = Rput('x',x)
ok = Rput('y',y)
ok = Rput('plot(x,y)')
end functionWhere to include custom functions
As R is becoming larger by the minute, it is not possible for us to anticipate all of the ways in which a user would use RFortran. If you have extensions to RFortran they can be included in any of the files 'Rfortran_Rfuncs.f90', 'Rfortran_Robjects.f90', 'Rfortran_Rplots.f90'. The above example would be appropriate for the Rplots file. The Robjects file will be discussed in the next section, and all other routines should go into Rfuncs.
Custom Objects
A common scenario is when R produces some kind of object that has multiple parts. Using the base-functionality the only way to transfer them is to use multiple commands on the individual parts. Consider for example an object called 'ks' which is the result from a Kolmogrov-Smirnov test using R: 'ks<-ks.test(x,y)'. The resultant object has several components and to transfer it back to Fortran we would need to transfer each part separately. If this is an object you commonly use, then why not create a corresponding data object in Fortran and a function to transfer this object? An example is given below (note that the same naming convention of the objects between R and Fortran has been maintained and where R uses a period in the variable name, an undersocre has been used in Fortran):
module custom
type ks_type ! definition of an object that matches the ks object within R
real :: statistic
real :: p_value
character(len = 32) :: alternative
character(len = 32) :: method
character(len = 32) :: data_name
end type
contains
function Rget_ks(var,ks) result(ok)
implicit none
character(*), intent(in) :: var ! R variable name/symbol
type(ks_type), intent(inout) :: ks ! object as defined above
integer :: ok ! error flag
ok = Rget(var//"$statistic", ks%statistic)
ok = Rget(var//"$p.value", ks%p_value)
ok = Rget(var//"$alternative",ks%alternative)
ok = Rget(var//"$method", ks%method)
ok = Rget(var//"$data.name", ks%data_name)
end function
end moduleStyle guide
We have tried to keep a convention of using the letter 'R' at the start of the function name if the routine interacts with R or if it is a wrapper for an R function of the same name. This helps avoid potential collisions amongst routines with common names such as 'plot' and also makes it clear which routines in your code are those that depend upon R. We have implemented the functions so that they return a single integer value as an error code (0 is good, anything else is bad). Please stick to the structure: 'ok = Rrandomfunc()' where ok is the variable name to store the returned error code. If you make several calls inside a function, you should check all of the error flags to see if they were okay, otherwise if the last one is okay (but others failed) it will give the appearance that the whole function was successful. This mechanism does not provide an error message, but you can use the message_log facilities to output messages. If there are numerous R commands that belong together, it is highly recommended that the the commands are stored as separate R-scripts and that RFortran is merely used for putting/getting data into/from R. The reasoning behind this comes from experience: if your code looks like this:
ok = Rput('command1')
ok = Rput('command2')
ok = Rput('command3')
ok = Rput('command4')then it is harder to debug than if they were stored as a script. Secondly, if they are stored as an Rscript it is possible to change the script without needing to recompile the program. If there are commonly used tools then these can be preloaded into R via the RFortran_scriptpathIn argument when Rinit() is called. Otherwise if it is program specific it could be stored elsewhere and called via Rput('source(MySpecialScript.R)').