Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28499 Discussions

compilation error with multivariable functions and function array

yyxt11a
Beginner
691 Views
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:
[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]
0 Kudos
3 Replies
mecej4
Honored Contributor III
691 Views
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!
0 Kudos
yyxt11a
Beginner
691 Views
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:

[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.
0 Kudos
mecej4
Honored Contributor III
691 Views
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:

[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.
0 Kudos
Reply