I have this very small example of Fortran code which I would like to understand please.
subroutine test_iso_c
use ISO_C_BINDING
implicit real(c_double) (a-h,o-z)
real :: var, expression
interface
real(c_double) function test (y) bind( c )
use ISO_C_BINDING
real(c_double), value :: y
end
end interface
! call
var = test(expression) ! - expression is a real declared variable which is calculated using simple arithmetic operation.
end
Can you explain to me thee following (I assume c_double means double precision in a C code scope?)
1 - What does implicit real(c_double) (a-h,o-z)?
2 - what does value and bind(c) do in the function interface
3 - I saw this of code as part of a larger routine, can you say what this test function provide/do?
1 - What does implicit real(c_double) (a-h,o-z)?
The implied type of variables is an old Fortran feature where all variables starting with all characters except i, j, k, l,m, and n are considered to be of type REAL, so there is no need to declare them separately.
This property is considered harmful and therefore it is recommended to cancel it by specifying IMPLICIT NONE at the very beginning of the program.
This instruction specifies that all variables beginning with the characters a-h or o-z are of type REAL(c_double), which corresponds to the C double type.
The best solution is to use the IMPLICIT NONE directive and then declare all variables like this
REAL(c_double) :: x
2 - what does value and bind(c) do in the function interface
The bind(c) means that the function is C-function, so a compiler must formalize its call in the C language. This includes both the order in which arguments are placed on the stack and the formatting of the function name (for example, adding an underscore to the beginning).
The VALUE attribute means that the parameter is passed to the function by value (usually in Fortran, parameters are passed by reference)
Related
I have a question regarding calling Fortran routines within the objective function of an optimization problem set up using Julia Jump. I have found helpful information in multiple forums on how to call Fortran from Julia in general and managed to write a Julia program that successfully calls my Fortran Code outside of any optimization procedure:
ffreturn = zeros(Float64,1)
xx = 2.0
yy = 4.2
ccall((:FCN, "C:/Users/.../Subroutine.dll"),Cvoid, (Ref{Float64},Ref{Float64},Ptr{Array{Float64,1}}),xx,yy,ffreturn)
where the Fortran code evaluates the Rosenbrock function
module objective
implicit none
private
public :: FCN
contains
subroutine FCN(x,y,fvalue) bind(C,name="FCN")
use, intrinsic :: iso_c_binding, only: c_double
implicit none
real(c_double), intent(in) :: x
real(c_double), intent(in) :: y
real(c_double), intent(inout) :: fvalue(1)
fvalue(1) = 100.*(y-x**2)**2 + (x - 1.)**2
end subroutine FCN
end module objective
What changes now if this Fortran routine is called within a Julia Jump objective function is the type of the two input variables (xx and yy in the example above) on the "Julia side". They are no longer of type Float64 but of type Variable. So far I was unable to find out, what to replace the specifications Ref{Float64} for the input variables in the ccall with to get a working code. (Using Ref{Variable} produces running code, however, the Fortran routine always receives input values of 0 for a and y)
Any help is greatly appreciated!
Gfortran 8.1 and 9.1 give me an error about intrinsic assignment between two polymorphic components into a type variables. I don't have any problem using intel compiler but no in the case in gfortran. I'm asking if someone know any workaround.
Here an example that you can try to compile.
Program Check
implicit none
!> Type definitions
Type :: Atm_Type
End Type Atm_Type
Type, extends (Atm_type) :: Atm_Std_Type
End Type Atm_Std_Type
Type, extends (Atm_std_type) :: Atm_Ref_Type
End Type Atm_Ref_Type
Type :: AtList_Type
integer :: Natoms
class(Atm_Type), dimension(:), allocatable :: Atom
end Type AtList_Type
!> Variables
type(AtList_Type) :: list
call sub(list)
Contains
Subroutine Sub(List)
!---- Argument ----!
type (AtList_Type), intent(in out) :: List
!---- Local Variables ----!
integer :: i
type (AtList_Type), allocatable :: local
if (List%natoms <= 0 ) return
allocate(local%atom(List%natoms))
do i=1, List%natoms
local%atom(i)=list%atom(i)
end do
End Subroutine Sub
End Program Check
Here the workaround is very simple and appeared in one of the recent questions/answers. Just copy the whole array
local%atom = list%atom
However, it is not always possible to do that when you really need to access individual elements. If your real use case is like that, show the real use case.
If the number of possible types inside is limited, you can also use the select type type guard, but often that is not possible either.
I have a code as follows:
The function is declared in a module using an interface block
module my_subs
implicit none
interface
function cross(a,b)
integer, dimension(3) :: cross
integer, dimension(3), intent(in) :: a, b
end function cross
end interface
end module my_subs
program crosstest
use my_subs
implicit none
integer, dimension(3) :: m, n
integer, dimension(3) :: r
m = [1, 2, 3]
n = [4, 5, 6]
r = cross(m,n)
write(*,*) r
end program crosstest
function cross(a,b)
implicit none
integer, dimension(3) :: cross
integer, dimension(3), intent(in) :: a, b
cross(1) = a(2)*b(3) - a(3)*b(2)
cross(2) = a(3)*b(1) - a(1)*b(3)
cross(3) = a(1)*b(2) - a(2)*b(1)
end function cross
According to this website, the use of interface blocks allows main programs and external subprograms to interface appropriately. However, I tested different mismatch of array size scenarios, I got the following result:
Change dimension at line 6 to 2 and 4, the code cannot be compiled;
Change dimension at line 7 to 2, the code can be compiled and produce the correct output;
Change dimension at line 7 to 4, the code cannot be compiled;
Change dimension at line 27 to 2 and 4, the code can be compiled and produce the correct output;
Change dimension at line 28 to 2 and 4, the code can be compiled and produce the correct output;
I am confuse about the different scenarios I performed, because I suppose the use of interface can help me to detect any mismatch of array size. In this case, is it better for me to move the function cross(a,b) into the module my_subs using contains?
You can check the interface by putting some declarations in function cross that test whether the interface as declared in module my_subs matches what function cross thinks its interface should be:
interface in function cross:
module my_subs
implicit none
interface
function cross(a,b)
integer, dimension(3) :: cross
integer, dimension(3), intent(in) :: a, b
end function cross
end interface
end module my_subs
program crosstest
use my_subs
implicit none
integer, dimension(3) :: m, n
integer, dimension(3) :: r
m = [1, 2, 3]
n = [4, 5, 6]
r = cross(m,n)
write(*,*) r
end program crosstest
function cross(a,b) result(res)
use my_subs, only: check => cross
implicit none
integer, dimension(3) :: res
integer, dimension(3), intent(in) :: a, b
procedure(check), pointer :: test => cross
res(1) = a(2)*b(3) - a(3)*b(2)
res(2) = a(3)*b(1) - a(1)*b(3)
res(3) = a(1)*b(2) - a(2)*b(1)
end function cross
gfortran zaps this in all cases of mismatch you tested. I'm not sure that it should: if TKR of a dummy argument matches, shouldn't the rules of sequence association produce a correct invocation of the procedure? I haven't used submodules, but I think that they might do roughly the same thing as my example does.
When using an interface block to provide an explicit interface within a scope (in this case, in the module, which is then used by the main program) it is a requirement on the programmer that the specified interface matches the actual procedure.1
As given first, these things match happily. Changing the size of the function result or dummy arguments of one statement of the procedure but not the other creates a mismatch. Such code is a violation of the Fortran standard.
In general, a compiler isn't required to detect this violation. It may take your interface block on faith or it may do some extra work to see whether it should believe you. This latter is possible, especially if the external procedure is given in the same file as the interface block. You may see some error messages relating to this.
Further, if the interface block is given, the compiler will test the reference to the procedure against the interface, not the procedure's actual definition.
One failing, on the programmer's part, is if the actual argument isn't compatible with the dummy argument. Such a case is when the dummy argument is an explicit shape array but the actual argument is smaller than the dummy argument. [It isn't an error to have the actual argument larger.]
This problem is one of your cases:
interface
function cross(a,b)
integer, dimension(3) :: cross
integer, dimension(4), intent(in) :: a, b ! Dummy extent 4
end function cross
end interface
print*, cross([1,2,3], [4,5,6]) ! Actuals extent 3
end
Again, a compiler isn't obliged to notice this for you. It's being nice in the case where it can detect the problem.
Now, in another case you are stating that the function result is an array of shape [4] or [2]. But you are trying to assign that to an array of shape [3]. That won't work.
In conclusion, if you use an interface block to provide an explicit interface for an external procedure make sure it is correct. Turning the external procedure into a module procedure means it's the compiler's responsibility, not yours, to have the correct interface visible.
1 "Matching" here means that the characteristics of the procedure as stated by the interface block are consistent with the procedure's definition. The extents of the function result and dummy arguments are part of this. A procedure defined pure needn't have the interface block stating it is pure.
I am designing a module which works with the hdf5 Fortran library. This module contains subroutines to read and write arrays of different types and shapes to/from a file.
e.g. I wish to be able to call writeToHDF5(filepath, array) regardless of what the shape and type of array is. I realise that interfaces have to be used to achieve this with different types. I am however wondering if it is possible to have an assumed shape of the array.
e.g.
if an array was defined such as
integer(kind=4), dimension(*),intent(in) :: array
and a two dimensional array was passed this would work. Is there any way to do this without creating separate subroutines for each shape of the array?
As Vladimir F says, Fortran 2015 adds "assumed-rank" - this is useful Fortran-Fortran (it was requested by MPI for the Fortran bindings), but when you receive such an array, you can't do much with it directly without additional complications. Several compilers support this already, but few (if any?) support the newly added SELECT RANK construct that make this a bit more useful.
You can, however, use C_LOC and C_F_POINTER to "cast" the assumed-rank dummy to a pointer to an array of whatever rank you like, so that's a possibility.
The standard (even back to Fortran 90) does give you an out here. If you write:call writeToHDF5(filepath, array(1,1)) (assuming array is rank 2 here), the explicit interface of the called procedure can specify any rank for the dummy argument through the magic of "sequence association". There are some restrictions, though - in particular the array is not allowed to be assumed-shape or POINTER.
I know that this comes out late, but for any future readers - the answer is actually yes.
This is a simple example of a procedure to read a single data-set of integers with any given shape. The inputs needed were read from the HDF5 using a single routine which does not require any special specification and are the same for integer, real, string and so on.
I have tested it on a "0-D" array (so size of (/1/) ), 1-D, 2-D, 3-D and 4-D arrays.
In all cases, the data was retrieved properly.
(Note: I removed some checks regarding the Errorflag, as they are not critical for the example)
subroutine ReadSingleDataset_int(FileName,DataName,DataType,Data_dims,Errorflag,InputArray)
implicit none
character(len=*), intent(in) :: FileName,DataName
integer(HID_T), intent(in) :: DataType
integer(hsize_t), dimension(:), intent(in) :: Data_dims
logical, intent(out) :: ErrorFlag
integer, dimension(*), intent(inout) :: InputArray
integer :: hdferr
integer(HID_T) :: file_id,dset_id
ErrorFlag=.FALSE.
IF (.NOT.HDF5_initialized) THEN
CALL h5open_f(hdferr)
HDF5_initialized=.TRUE.
ENDIF
call h5fopen_f(trim(FileName),H5F_ACC_RDONLY_F, file_id, hdferr)
call h5dopen_f(file_id,trim(DataName),dset_id,hdferr)
call h5dread_f(dset_id,DataType,InputArray,Data_dims,hdferr)
call h5dclose_f(dset_id,hdferr)
call h5fclose_f(file_id,hdferr)
end subroutine ReadSingleDataset_int
My main interest in this now is - would it be possible to replace the type/class specific (integer/real/etc') with a generic one on the lines of:
class(*), dimension(*), intent(inout) :: InputArray
As I have several routines like that (for int, real, string) which only vary in that specification of the input type/class. If that limitation could be alleviated as well, that will be even more elegant.
(Just to point out the issue - the h5dread_f does not accept the buffer argument, InputArray in my case, to be unlimited polymorphic)
The goal:
Have a function work with configurable working precision.
When I try this:
program vierkantsvergelijking
implicit none
integer, parameter :: dp = kind(0.d0)
integer, parameter :: sp = kind(0.0)
print *, algoritme1(-5771.,2.,dp)
contains
function algoritme1(b,c,wp) result( solution)
integer :: wp ! working precision
real(kind=wp) :: b,c,D
real(kind=wp), dimension(2) :: solution
D = sqrt((b/2)**2 - c)
solution(1) = -b/2 + D
solution(2) = -b/2 - D
end function algoritme1
end program
I get:
Error: Type mismatch in argument 'b' at (1); passed REAL(4) to UNKNOWN
Why is this not working and how can I achieve my goal?
Yes, or rather no, that's not going to work, not no how. The Intel Fortran compiler complains, about this line:
real(kind=wp) :: b,c,D
that
A kind type parameter must be a compile-time constant. [WP]
It makes the same complaint about real(kind=wp), dimension(2) :: solution too. This is a deep-rooted feature of Fortran.
To do what you want you will have to define a generic interface, along these lines
interface algoritme1
procedure :: algoritme1_sp, algoritme1_dp
end interface
and write the code for both those procedures. The compiler can then determine which one is called by the function signature; presumably one would have sp arguments, the other dp arguments.
You might think that this all means that Fortran doesn't do generic procedures, I'll leave that question to the sophists and language nit-pickers. It would be worth your while to search around for generic programming in Fortran; even here on SO there are tricks and tips on how to better avoid writing multiple implementations of what the programmer believes (at odds with the compiler) to be the 'same' code.