I'm trying to use routines in QUADPACK to perform numerical integration. The routines expect functions to be passed as REAL,EXTERNAL, so I don't have the liberty of using pointers or whatever else.
Is it possible to alias a function f(x,a,b,...) as being a function f(x) for the routine that expects a function of x only? Much like what one would accomplish in MATLAB with #(x)f(x,a,b,...).
You cannot make similar tricks with functions in Fortran directly. You also cannot return a closure in Fortran. Just write a wrapper.
function wrap_f(x) result(res)
...
res = f(a,b,...)
end function
It can be an internal or module function and get a and b by the host association or it can use the module containing a and b.
If you want to pass the function as an actual argument, it cannot be an internal procedure in up to Fortran 2003, but only in Fortran 2008. But it works in recent versions of gfortran and ifort. For better portability use a module.
I can show a nice solution for this problem. I am also a former MATLAB user and when switching to FORTRAN you miss function handles haha. I solved your problem in this way:
module
private
public :: f , g
real(kind=RP) :: a0,b0,c0,...
contains
function f(x,a,b,c,d,...)
implicit none
real(kind=RP) :: x,a,b,c,d,...
real(kind=RP) :: f
! Here you define your function
f = ...
end function f
function g(x)
implicit none
real(kind=RP) :: x , g
! Here you call "f" function with the frozen variables *0
g = f(x,a0,b0,c0,...)
end function g
! We said that parameters were private
! (to avoid to be modified from the outside, which can be dangerous,
! so we define functions to set their values
subroutine setValues(a,b,c,...)
implicit none
real(kind=RP) :: a,b,c,...
a0 = a
b0 = b
c0 = c
end subroutine setValues
end module
Related
Let's assume I have the following code:
module eval_mod
implicit none(type, external)
private
public :: eval
abstract interface
real pure function real_function_t(x)
real, intent(in) :: x
end function
end interface
contains
pure function eval(f, x) result(res)
procedure(real_function_t) :: f
real, intent(in) :: x
real :: res
res = f(x)
end function
end module
program main
use iso_fortran_env, only: stdout => output_unit
use eval_mod, only: eval
implicit none(type, external)
write(stdout, *) eval(double, 2.)
write(stdout, *) eval(triple, 2.)
contains
pure real function double(x)
real, intent(in) :: x
double = 2. * x
end function
pure real function triple(x)
real, intent(in) :: x
triple = 3. * x
end function
end program
and compile it with gfortran -Wall -Wextra -Werror -g -fbounds-check.
If I set a breakpoint to eval_mod::eval, I would like to see with which function argument eval was called.
What I actually see is
Breakpoint 2, eval_mod::eval (f=0x7fffffffced8, x=2) at main.F90:17
If I take the address and follow this question, I should be able to see the function name in the symbol table by doing:
info symbol 0x7fffffffced8
Unfortunately I get an error
No symbol matches 0x7fffffffced8.
How can I see the function name of a function passed as argument?
PS: I use gfortran 7.5.0 and gdb 11.1.
double and triple are internal functions (inside the main program). Passing internal functions is tricky due to the host association of the variables from the parent scope. Therefore they are often implemented using trampolines. The address you see is the address of the trampoline, in other words, a so called thunk. The trampoline than calls the actual function.
The address most likely points somewhere on the stack where the trampoline code is placed. In that code you will likely find a jump instruction with the address of the actual function.
See also this great article by Steve Lionel Doctor Fortran in “Think, Thank, Thunk”
I wrote a fortran function to call a blas level 3 function sgemm. I'm passing the matrices to be multiplied to this function and returning the result. The code works and the result is also correct. But there is a print statement inside which won't print anything. Why is that happening?
function matmul(A,B) result(C)
real,dimension(:,:),allocatable::A
real,dimension(:,:),allocatable::B
real,dimension(:,:),allocatable::C
integer::m,n,k
m = size(A,1)
n = size(A,2)
k = size(B,2)
print *,"INSIDE FN"
call sgemm ('N','N',m,k,n,1.0,A,n,B,k,0.0,C,k)
end function matmul
The function name you chose, MATMUL, is a fortran intrinsic function (see section 13.7.105 of the fortran standard or here). The function you implemented tries to 'overload/shadow' this intrinsic with the same name. This is possible in Fortran, but you have to explicitly inform the compiler about it. When compiling the following code :
function matmul(A,B) result(C)
real,dimension(:,:),allocatable::A,B,C
print *,"matmul overloaded"
C=A
end function matmul
program test
real, dimension(:,:), allocatable :: A,B,C
allocate(A(1,1),B(1,1),C(1,1))
C = matmul(A,B)
end program test
The program test has no knowledge about the existence and/or interface of your own matmul subroutine. Both the program test and the subroutine matmul live in two unconnected program units, and as a consequence, the compiler will assume that the intrinsic MATMUL function is to be called.
EXTERNAL attribute: (see STDF2003::5.3.9)
As the compiler has no mechanism to access the users matmul code from the program unit test, it's interface is implicit. If you want to specify that the name matmul is the one of an external or dummy procedure, we can use the external statement :
program test
external :: matmul
real, dimension(:,:), allocatable :: A,B,C
allocate(A(1,1),B(1,1),C(1,1))
C = matmul(A,B)
end program test
INTERFACE block : (See STDF2003::12.4)
With the external attribute, you just specify that matmul is an external or dummy procedure. It does not specify the interface, which remains implicit. The interface, however, can be defined by means of an interface block as
program test
real, dimension(:,:), allocatable :: A,B,C
allocate(A(1,1),B(1,1),C(1,1))
interface
function matmul(A,B) result(C)
real,dimension(:,:),allocatable::A,B,C
end function matmul
end interface
C = matmul(A,B)
end program test
The latter is automatically achieved when placing the function matmul in a module and using that module.
note: information loosely adopted from Modern Fortran Explained, M. Metcalf, J. Reid and M. Cohen, (Oxford, 2013)
I'm just beginning with Fortran, and I've got a program and a function
PROGRAM multiplication
implicit none
real :: A1
!A1 = mult(2, 3)
!write(*,1) A1
1 format(f8.8)
END PROGRAM multiplication
REAL FUNCTION mult(a, b) BIND(C, name='foomult')
real,value :: a,b
mult = a * b
END FUNCTION
I've got the function working in java through JNA, but when I try to call mult from within the fortran main program, I get a ton of compiling errors (I can provide them if you want). I have a feeling it must be something obvious but I can't find a solution anywhere. Are bound functions not intended to be called from within non-external code? Or do I just have a poor understanding of function syntax?
For the main program, the compiler doesn't "know" the properties of the function, i.e., the types of the function and its arguments. Your function uses an "advanced" argument property, value, so it is necessary to declare the properties in some way to the caller. The easiest way to make those properties known to the caller is to put the function into a module and use that module from a program or procedure that uses it:
module MyModule
contains
FUNCTION mult(a, b) BIND(C, name='foomult')
use iso_c_binding
real (c_float) ,value :: a,b
real (c_float) :: mult
mult = a * b
END FUNCTION
end module MyModule
PROGRAM multiplication
use MyModule
implicit none
real :: A1
A1 = mult(2.0, 3.0)
write(*,*) A1
END PROGRAM multiplication
I've also declared the variables in the function to be compatible with C. It happens, at least with gfortran on my computer, that those are the same as plain real, so they are compatible with the call in the main program. Compatibility could be guaranteed by writing the call as mult (2.0_c_float, 3.0_c_float).
Well, this is the issue I've today...
I'm writing a module procedure that has, as an argument, a function. This module looks something like this:
module Integ
implicit none
<variables declaration>
contains
function Integral(a,b,f) result(res)
real, intent(in) ::a, b
real ::res
interface
pure function f(x)
real, intent(in) :: x
real :: f
endfunction
endinterface
<more code of function Integral>
endfunction Integral
endmodule Integ
Well, up to here, everything is great. The issue appears when I try to use this function with a Fortran intrinsic function. I.e., in this code:
program main
use Integ
implicit none
real ::res,a,b
a=3.0; b=4.0
res=Integral(a,b,sin) !<- This line does not work
!res=Integral(a,b,sen) !<- This line does work
contains
function sen(x)
real, intent(in) :: x
real :: sen
sen=sin(x)
endfunction
endprogram
The first line does not work, giving the error message:
main.f90(17): error #6404: This name does not have a type, and must have an explicit type. [SIN]
r=Int1DMonteCarlo(0.0,1.0,sin,10000)
--------------------------^
main.f90(17): error #6637: This actual argument must be the name of an external user function or the name of an intrinsic function. [SIN]
r=Int1DMonteCarlo(0.0,1.0,sin,10000)
--------------------------^
But the second line (comented in the snipplet) does.
Those errors are quite disorienting for me, because sin is a Fortran intrinsic function (thing that contradicts error nr 2), and in consequence explicit in every scope (thing that contradicts the error nr 1).
Obviously I'm doing something wrong but I don't know what.
So I would like to ask:
It is possible to call a module procedure with an intrinsic function as an actual argument?
I'm loosing something aside from declaring the interface inside the procedure?
If you are interested this is the complete source of the module and this is the source of the main
Sorry if I'm asking a stupid question. I think I am doing things the way the books I'm reading now (Metcalf, Numerical recipes for Fortran V:II) are telling me.
Thank you for your time!
Use an intrinsic statement in the main program to declare that the actual argument sin is the intrinsic. This requirement is spelled out in the description of the intrinsic attribute in the Fortran standard.
With an eye to the future, you may be better off writing your own wrapper function around the intrinsic - create a function mysin that simply calls sin.
Thanks for the help in advance..
Kindly I want to print data in an output file of the main FORTRAN program and these data defined in a module and I already declare using that module in the main program. but I couldn't get the write statements neither in the main program nor in the module.
MODULE model
IMPLICIT NONE
SUBROUTINE model_initialize
IMPLICIT NONE
INTEGER a,dim REAL(float) :: E,nu
REAL(float) :: lambda,mu
E=5000 lambda = E*nu/(1.d0+nu)/(1.d0-2.d0*nu)
mu = E/2.d0/(1.d0+nu)
RETURN
END SUBROUTINE model_initialize
Write (6,)'Lambda',lambda
Write (6,)'mu',mu
END MODULE model
SUBROUTINE XXXX
USE model
IMPLICIT NONE
CALL model_initialize
Write (6,)'Lambda',lambda
Write (6,)'mu',mu
END SUBROUTINE XXX
When I put the write statements in the module or in the main subroutine , I cant see them in the output.
Many thanks for the help
Msekh
Mgilson has already provided you with an example that should work, but the code you posted will not compile. This is why:
Your subroutine model_initialize is in the "specification part" of your module. It should either be external (like xxxx) or internal to the module (in which case you have to provide a contains statement).
The variables in model_initialize are local to the subroutine and will not be accessible outside it.
You cannot have executable code (like write) in the specification part of a module, only in internal procedures.
float is not a native Fortran kind, you have to use the numerical parameters (usually 4, 8, 16), define your own, or use the definitions in the iso_fortran_env module.
That said, if you only need to define some data you want to make accessible, you can simply put that directly in the module like this:
module model
use iso_fortran_env
implicit none
integer :: A, dim
real(real32) :: E, nu, lambda, mu
E = 5000
lambda = E*nu/(1.d0+nu)/(1.d0-2.d0*nu) ! <-- nu is undefined
mu = E/2.d0/(1.d0+nu)
contains
subroutine xxxx
write (6,*) 'lambda', lambda
write (6,*) 'mu', mu
end subroutine xxxx
end module model
do you mean something like:
module material
real :: stress = 6.0
save
end module material
subroutine xxx()
use material, only: stress
write(6,*) stress
end subroutine
program main
call xxx()
end program main
This will write the value of stress to the file-like object connected with unit 6 (usually this is stdout, but it might create a new file called fort.6 depending on compiler and environment settings).