- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi all,
I want to calculate a multivariable function func(x) and its gradient dfunc(x), where x is a vector. The gradient dfunc(x) is calculated with finite difference method. I defined two modules and a calling program as follows:
1. Mod_func: module to calculate the function values at x
2. Mod_dfunc: module to calculate the gradient at x. Since numerical finite difference formula are used to obtain dfunc(x), dfunc(x) needs to call func(x).
3. drive: calling program
Problems:
1. Compilation error:
$ ifort -c mod_func.f90 mod_dfunc.f90 drive.f90
drive.f90(7): error #6401: The attributes of this name conflict with those made accessible by a USE statement. [FUNC]
real ::func
---------^
drive.f90(8): error #6401: The attributes of this name conflict with those made accessible by a USE statement. [DFUNC]
real ::dfunc(ndim)
---------^
compilation aborted for drive.f90 (code 1)
2. If I get rid of dfunc(x) and correspondingly omit it in the calling program (so that I only calculate the function values, not its gradient), it still shows compilation error with ifort. However, if I use gfortran, it was OK. But, if I tried to put the dfunc back on, both compilers fail.
The codes:
I want to calculate a multivariable function func(x) and its gradient dfunc(x), where x is a vector. The gradient dfunc(x) is calculated with finite difference method. I defined two modules and a calling program as follows:
1. Mod_func: module to calculate the function values at x
2. Mod_dfunc: module to calculate the gradient at x. Since numerical finite difference formula are used to obtain dfunc(x), dfunc(x) needs to call func(x).
3. drive: calling program
Problems:
1. Compilation error:
$ ifort -c mod_func.f90 mod_dfunc.f90 drive.f90
drive.f90(7): error #6401: The attributes of this name conflict with those made accessible by a USE statement. [FUNC]
real ::func
---------^
drive.f90(8): error #6401: The attributes of this name conflict with those made accessible by a USE statement. [DFUNC]
real ::dfunc(ndim)
---------^
compilation aborted for drive.f90 (code 1)
2. If I get rid of dfunc(x) and correspondingly omit it in the calling program (so that I only calculate the function values, not its gradient), it still shows compilation error with ifort. However, if I use gfortran, it was OK. But, if I tried to put the dfunc back on, both compilers fail.
The codes:
[fortran]Module mod_func
! Purpose: To calculate multivariable function func(x), x is a vector
Contains
FUNCTION func(x)
IMPLICIT NONE
REAL, DIMENSION(:), INTENT(IN) :: x
REAL :: func
integer::i,n
n=size(x)
func=0
do i=1,n ! a simple multivariable function: func(x) = x1**2 + x2**2 + ...
func= func+ x(i)**2
end do
END FUNCTION func
End module mod_func[/fortran]
[fortran]Module mod_dfunc
! Purpose: To calculate gradient at x by finite difference, where x is a vector
Contains
FUNCTION dfunc(x)
use mod_func ! To calculate dfunc(x), we need
! function values func(x) and func(x+x)
! is a small scalar
implicit none
REAL, DIMENSION(:), INTENT(IN) :: x
REAL, DIMENSION(size(x)) :: dfunc
real, dimension(:),allocatable:: e ! e is the unit vector
real :: del ! del ==>
integer:: i,n
del=sqrt(epsilon(x(1)))
n=size(x)
allocate(e(n))
do i=1,n
e=0.
e(i)=1.
!central difference formula
dfunc(i)=(func(x+del*e) - func(x-del*e))/(2.*del)
end do
deallocate(e)
END FUNCTION dfunc
End module mod_dfunc[/fortran]
[fortran]program drive
use mod_func
use mod_dfunc
implicit none
integer,parameter::ndim=2
real :: x(ndim) ! 2 variables, (x1,x2)
real ::func
real ::dfunc(ndim)
x=(/1.0,3./)
write(*,*) 'x:',x
write(*,*) 'function value:',func(x)
write(*,*) 'function gradiet:',dfunc(x)
end program drive[/fortran]
Link Copied
3 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Remove or comment out lines 7 and 8 of your main program -- func and dfunc are already defined in the USEd modules in the main program.
Furthermore, your redefinition dfunc(ndim) is inconsistent with the prior definition dfunc(x(ndim)).
Perhaps, saying that the compiler(s) reported errors in the code would be more correct than saying that they "failed", since what the compilers did (reporting the lines with syntax errors, and refusing to produce an object file when the input source code has errors) is exactly what they are expected to do!
Furthermore, your redefinition dfunc(ndim) is inconsistent with the prior definition dfunc(x(ndim)).
Perhaps, saying that the compiler(s) reported errors in the code would be more correct than saying that they "failed", since what the compilers did (reporting the lines with syntax errors, and refusing to produce an object file when the input source code has errors) is exactly what they are expected to do!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Many thanks to mecej4. Spot on! I did as you said, and the problem was resolved. However, my real intention is to create a subroutine that does some calculations with function values func(x) and its gradient dfunc(x). The subroutine should look like this:
Where should I define the subroutine? Should I define it in a module or define it as a stand alone subroutine? How do I call it from the main program? Basically, I need a subroutine that needs functions (func and dfunc), one of which needs the other (dfunc needs func). I am not sure how to pass the arrays.
[fortran]SUBROUTINE func_sum(x,func,dfunc,result)
IMPLICIT NONE
REAL, DIMENSION(:), INTENT(IN) :: x
REAL, INTENTION(OUT) :: result
real,external::func
real,external::dfunc(size(x))
result=func(x) + dfunc(x)
end SUBROUTINE func_sum [/fortran]
Where should I define the subroutine? Should I define it in a module or define it as a stand alone subroutine? How do I call it from the main program? Basically, I need a subroutine that needs functions (func and dfunc), one of which needs the other (dfunc needs func). I am not sure how to pass the arrays.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is it your intention to pass different procedure arguments func and dfunc in multiple calls to func_sum in a single run? If so, you may consult, for example, Section 5.12 of Metcalf, Reid and Cohen, "Fortran 95/2003 explained". You will also benefit from reading about explicit and implicit interfaces.
If, on the other hand, you will only employ one function func in a single run, the coding can be much simpler. For example:
Note that a step proportional to sqrt(machine_eps) is appropriate only for one-sided difference approximations.
If, on the other hand, you will only employ one function func in a single run, the coding can be much simpler. For example:
[fortran]Module mod_func CONTAINS FUNCTION func(x) IMPLICIT NONE REAL, DIMENSION(:), INTENT(IN) :: x REAL :: func integer::i,n n=size(x) func=0 do i=1,n func= func+ x(i)**2 end do END FUNCTION func FUNCTION dfunc(x) implicit none REAL, DIMENSION(:), INTENT(IN) :: x REAL, DIMENSION(size(x)) :: dfunc real, dimension(size(x)):: e ! e is the unit vector real :: del ! del ==> integer:: i del=epsilon(x(1))**(1.0/3.0) ! for Central-Diff. e=0. do i=1,size(x) e(i)=1. !central difference formula dfunc(i)=(func(x+del*e) - func(x-del*e))/(2.*del) e(i)=0. end do END FUNCTION dfunc SUBROUTINE func_sum(x,result) IMPLICIT NONE real, dimension(:) :: x real, dimension(size(x)) :: df real :: result df=1e-3 result=func(x) + dot_product(dfunc(x),df) end SUBROUTINE func_sum end module mod_func program usemod use mod_func real :: x(3)=(/1.0,2.0,3.0/), res call func_sum(x,res) write(*,'(2x,"Res = ",G12.3)')res end program usemod[/fortran]
Note that a step proportional to sqrt(machine_eps) is appropriate only for one-sided difference approximations.
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page