Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function in fortran, passing array in, receiving array out

I have this function, depicted below. It passes in two vectors with three values each, and should pass out one vector with three values as well. I call the function like this:

Fr       = Flux(W(:,i),W(:,i+1))

What I have realized through messing around with the code, trying pure functions, and modules, and researching the error statement (that I will include at the bottom), is that fortran is reading my function Flux, and thinks that the input vectors are an attempt to call an entry from the array. That is my best guess as to what is going on. I asked around the lab and most people suggested using subroutines, but that seemed clunky, and I figured there should probably be a more elegant way, but I have not yet found it. I tried to define a result by saying:

 DOUBLE PRECISION FUNCTION Flux(W1,W2) Result(FluxArray(3))

and then returning fluxarray but that does not work, as fortran cannot understand the syntax

The actual Function is this:

DOUBLE PRECISION FUNCTION Flux(W1,W2)
USE parameters
IMPLICIT NONE
DOUBLE PRECISION, DIMENSION(3), INTENT(IN)::W1, W2
DOUBLE PRECISION, DIMENSION(3), INTENT(OUT):: Flux
DOUBLE PRECISION, DIMENSION(3):: F1, F2
DOUBLE PRECISION::U1,U2,Rh1,Rh2,P1,P2,E1,E2,Rh,P,u,c,Lambda
INTEGER:: k
U1=W1(2)/W1(1)
U2=W2(2)/W2(1)

Rh1=W1(1)
Rh2=W2(1)

P1=(gamma_constant-1.d0)*(W1(3)-.5d0*Rh1*U1**2)
P2=(gamma_constant-1.d0)*(W2(3)-.5d0*Rh2*U2**2)

E1=W1(3)
E2=W2(3)

F1=[Rh1*U1,Rh1*U1**2+P1,(E1+P1)*U1]
F2=[Rh2*U2,Rh2*U2**2+P2,(E2+P2)*U2]

Rh=.5d0*(Rh1+Rh2)
P=.5d0*(P1+P2)
u=.5d0*(U1+U2)
c=sqrt(gamma_constant*P/Rh)

Lambda=max(u, u+c, u-c)
do k=1,3,1
    Flux(k)=.5d0*(F1(k)+F2(k))-.5d0*eps*Lambda*(W2(k)-W1(k))
end do
RETURN
END FUNCTION Flux

Here is the error statement:

Quasi1DEuler.f90:191.51:

DOUBLE PRECISION, DIMENSION(3), INTENT(OUT):: Flux
                                               1
Error: Symbol 'flux' at (1) already has basic type of REAL
Quasi1DEuler.f90:217.58:

Flux(k)=.5d0*(F1(k)+F2(k))-.5d0*eps*Lambda*(W2(k)-W1(k))
                                                      1
Error: Unexpected STATEMENT FUNCTION statement at (1)
Quasi1DEuler.f90:76.18:

Fr      = Flux(W(:,i),W(:,i+1))

The last error occurs for both Fr and Fl. Thank you for your time and any help or consideration you can give!

EDIT/Follow-up:: Thanks for the help, I don't know a better way to present this so I'm going to edit the initial question.

I did as you suggested and It solved that issue, now it says:

Fr      = Flux(W(:,i),W(:,i+1))
         1
Error: The reference to function 'flux' at (1) either needs an explicit INTERFACE or the rank is incorrect  

I saw a similar issue on SO at this link:

Computing the cross product of two vectors in Fortran 90

where they suggested that he put all his functions into modules. is there a better/simpler way for me to fix this error?

like image 955
EMP Avatar asked Jun 11 '14 18:06

EMP


1 Answers

With RESULT(FluxArray), fluxArray is the name of the result variable. As such, your attempt to declare the characteristics in the result clause are mis-placed.

Instead, the result variable should be specified within the function body:

function Flux(W1,W2) result(fluxArray)
  double precision, dimension(3), intent(in)::W1, W2
  double precision, dimension(3) :: fluxArray  ! Note, no intent for result.
end function Flux

Yes, one can declare the type of the result variable in the function statement, but the array-ness cannot be declared there. I wouldn't recommend having a distinct dimension statement in the function body for the result variable.

Note that, when referencing a function returning an array it is required that there be an explicit interface available to the caller. One way is to place the function in a module which is used. See elsewhere on SO, or language tutorials, for more details.

Coming to the errors from your question without the result.

DOUBLE PRECISION FUNCTION Flux(W1,W2)
  DOUBLE PRECISION, DIMENSION(3), INTENT(OUT):: Flux

Here the type of Flux has been declared twice. Also, it isn't a dummy argument to the function, so as above it need not have the intent attribute.

One could write

FUNCTION Flux(W1,W2)
  DOUBLE PRECISION, DIMENSION(3) :: Flux  ! Deleting intent

or (shudder)

DOUBLE PRECISION FUNCTION Flux(W1,W2)
  DIMENSION :: Flux(3)

The complaint about a statement function is unimportant here, following on from the bad declaration.

like image 107
francescalus Avatar answered Dec 06 '22 22:12

francescalus