Reputation: 193
I am writing a n-dimensional numerical solver in Fortran. I created a module for the same which is called from the main program. I used external
for calling the unknown function when I wrote for first order ode. However on replicating the result for more than one dimension using external
I get the following error
Error: EXTERNAL attribute conflicts with DIMENSION attribute in 'f_x'
This means my compiler cannot process an external function with array output.
I tried using an interface block to predefine the function parameters with fixed dimensions and I end up with this error
Error: PROCEDURE attribute conflicts with INTENT attribute in 'f_x'
Is there any way in Fortran to have an external function returning an array being initialized using a dummy function in a subroutine.
Here is the code that I used.
module int_adaptive
implicit none
contains
subroutine RK4nd(f_x, norder, nvar, x_0, t_0, t_f, x_out, t_out)
INTERFACE
FUNCTION f_x (x_0, t_0)
integer, parameter :: dp=kind(0.d0)
REAL(dp), INTENT(IN) :: x_0(2, 3), t_0
REAL, intent(out) :: f_x(2,3)
END FUNCTION f_x
END INTERFACE
integer, parameter :: dp=kind(0.d0)
integer :: norder, i, nvar
external :: f_x
real(dp), intent(in):: x_0(norder, nvar), t_0, t_f
real(dp) :: x_out(norder, nvar), t_out, k1(norder, nvar), y1(norder, nvar), y(norder, nvar)
real(dp) :: k2(norder, nvar), k3(norder, nvar), k4(norder, nvar),&
y2(norder, nvar), y3(norder, nvar), y4(norder, nvar)!, f_x(norder, nvar)
real(dp) :: h_min, h_0, h_max, tol, err_est, h, t
if (h_0<h) then
h = h_0
end if
if ((t_f - t_0) < 0.0) then
h = -h
end if
t = t_0
y = x_0
do while (t .NE. t_f)
k1 = f_x(y, t)
y1 = y + k1*h/2.0
k2 = f_x(y1, t+h/2.0)
y2 = y + k2*h/2.0
k3 = f_x(y2, t+h/2.0)
y3 = y + k3*h
k4 = f_x(y3, t+h)
y4 = y + (k1+ 2*k2 + 2*k3 +k4)*h/6.0
t = t + h
y = y4
end do
x_out = y
t_out = t
end subroutine
end module
I could define a standard integrator with fixed function input inside a module and call it by name directly, but since I deal with ODE's of various orders it will be complicated each time I am changing the order I'll need to update this module as well.
Upvotes: 2
Views: 3543
Reputation: 458
As francescalus already pointed out, a function should be either explicitly INTERFACEd, or declared as EXTERNAL - not both. Using EXTERNAL is old-fashion Fortran, since function interfacing was introduced in Fortran 90 to replace the need of EXTERNAL, which is a rather obsolete feature, still valid for backwards compatibility.
In addition, a function result cannot have an INTENT attribute. A function is meant to return a result by "its own name", as in y=f_x(...)
. Therefore, you should either declare f_x
itself as REAL (without any INTENT attribute), or, even better, use the RESULT attribute, both in function declaration and its interface. Using the RESULT attribute is actually necessary in recursive functions, but it is a good practice to do so even if the function is not recursive. So, the interface for your function should be written as
INTERFACE
FUNCTION f_x (x_0, t_0) RESULT(res)
INTEGER, PARAMETER :: dp=kind(0.d0)
REAL(kind=dp), DIMENSION(2,3), INTENT(IN) :: x_0
REAL(kind=dp), INTENT(IN) :: t_0
REAL, DIMENSION(2,3) :: res
END FUNCTION f_x
END INTERFACE
In your actual f_x
implementation, you should use res
(or whatever you want to call the RESULT) as the variable holding the result this function should return.
Note that I also did a few modifications which are not strictly necessary, but highly recommended: declaring x_0
as you do, REAL(dp), INTENT(IN) :: x_0(2, 3)
is also old-fashion Fortran (the DIMENSION attribute was introduced to make things clearer). Also some Fortran implementations, especially the F-standard, do not accept REAL(dp)
and need REAL(kind=dp)
instead.
Upvotes: 2
Reputation: 32366
You have two distinct problems here.
The first is that your specification of the explicit interface for the function f_x
is incorrect: the function result f_x
must not have the intent(out)
attribute. This covers the second error message.
The first error message is related to the later use of
external f_x
This external
statement gives f_x
the external
attribute. Which is fine, because the dummy procedure is an external function. However, you've also given that procedure an explicit interface with the (now corrected) interface block. This interface block also states that the procedure has the external
attribute.
Doing this, you've violated a constraint that an entity not be explicitly given the same attribute twice in one scoping block. To resolve this issue, you should remove one of the specifications. Because the function returns an array result, its interface must be explicit in the subroutine where it is referenced, so the interface block must be retained. That is, remove the external
statement.
For clarity, you should also remove the commented out real(dp) f_x(norder, nvar)
declaration. Such a declaration is erroneous for a function.
Upvotes: 5