Is there a way to check whether aliasing occurs in a Fortran subroutine, or at least to tell the compiler to issue a warning?
Consider this (rather simplistic) example:
module alias
contains
subroutine myAdd(a, b, c)
integer,intent(in) :: a, b
integer,intent(inout) :: c
c = 0
c = a + b
end subroutine
end module
program test
use alias
integer :: a, b
a = 1 ; b = 2
call myAdd(a, b, b)
print *, b, 'is not 3'
end program
Here, the result is set to zero in the subroutine. If the same variable is given as input and output, the result is (obviously) wrong. Is there a way to capture this kind of aliasing at run-time or at compile-time?
Yes, gfortran will detect some aliasing with the compiler option -Waliasing, however, the arguments must have intents in and out. It won't work with your example because you have declared argument c as intent(inout). In this example you can simply change the intent to out since the input value of c is not used. They try the compiler option! gfortran outputs:
alias.f90:17.16:
call myAdd(a, b, b)
1
Warning: Same actual argument associated with INTENT(IN) argument 'b' and INTENT(OUT) argument 'c' at (1)
I don't know of options in g95 or gfortran to detect the aliasing error at compile or run time. The programmer is responsible for avoiding such an error. You can pass the intent(in) arguments as expressions to ensure that they are not changed within the subroutine, as shown below.
module alias
contains
subroutine myAdd(a, b, c)
integer,intent(in) :: a, b
integer,intent(inout) :: c
c = 0
c = a + b
end subroutine myadd
end module alias
program test
use alias, only: myadd
integer :: a, b
a = 1 ; b = 2
call myAdd((a),(b),b) ! parentheses around arguments a and b
print*, b,"is 3"
call myAdd(a, b, b)
print*, b,"is not 3"
end program test
Related
I am a low level Fortran programmer. I am trying to make subroutines as generic as possible and I wonder if I can send an information of which subroutine another subroutine should acces from a given information in the main program. For instance, if I have:
program main
use test
implicit none
real(8) X
end program main
And:
module test
contains
subroutine A (X)
real(8) X
X = 2*X
end subroutine A
subroutine B (X)
real(8) X
X = 3*X
end subroutine B
end module test
I would like to, given the subroutine name 'A' or 'B' in the main program, transfer this to a third subroutine C inside the module test, which in turn would make some calculations and use the transferred name to choose between A and B in its calculations.
I know if I build the calculations of that subroutine C inside the main program, I can use a procedure pointer to access either A or B subroutines. However, I need to have the subroutine C. So I guess I will have a subroutine C with built in procedure pointer and it will take the name given in the main program as an argument. But I do not know how to do that. Neither if it is possible. If it is not, is there any other way? I do not know, maybe the subroutine C reading a txt file associating the read name to the procedure pointer. But, how?
Thank you, in advance!
I think that what you want is this: you first define subroutines A and B
module ab_m
implicit none
contains
subroutine A(X)
real, intent(inout) :: X
X = 2 * X
end subroutine A
subroutine B(X)
real, intent(inout) :: X
X = 3 * X
end subroutine B
end module ab_m
Then subroutine C uses a dummy procedure, specified by an interface,
module c_m
implicit none
contains
subroutine C(sub,y)
interface
subroutine sub(p)
implicit none
real, intent(inout) :: p
end subroutine sub
end interface
real, intent(inout) :: y
y = y + 1
call sub(y)
end subroutine C
end module c_m
and the main program chooses what procedure to use in C:
program p
use ab_m
use c_m
implicit none
real :: z(2)
z = 1.0
call C(B, z(1))
call C(A, z(2))
write(*,*) z ! writes 6.0, 4.0 [ (1+1)*3, (1+1)*2) ]
end program p
I would like to compute the cross product of two vectors in Fortran 90. For example, in words, the cross product of (1, 2, 3) and (4, 5, 6) turns out to be (-3, 6, -3) in Cartesian coordinates. I wrote the following code (main program followed by function definition):
PROGRAM crosstest
IMPLICIT NONE
INTEGER, DIMENSION(3) :: m, n
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3) :: r
m=(/1, 2, 3/)
n=(/4, 5, 6/)
r=cross(m,n)
END PROGRAM crosstest
FUNCTION cross(a, b)
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3), INTENT(IN) :: a, b
cross(1) = a(2) * b(3) - a(3) * b(2)
cross(2) = a(3) * b(1) - a(1) * b(3)
cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross
But, I get an error message:
crosstest.f90:10.9:
r=cross(m,n)
1
Error: Rank mismatch in array reference at (1) (2/1)
where line 10 is r=cross(m,n). It seems that I must be specifying a dimension incorrectly. Here are a few ideas I have:
Perhaps the declaration of the function cross in the main program should be simply an integer variable, rather than a 1by3 integer array. So I tried deleting the , DIMENSION(3) in the INTEGER, DIMENSION(3) :: cross line in the main program. But I get an error message:
crosstest.f90:10.4:
r=cross(m,n)
1
Error: The reference to function 'cross' at (1) either needs an
explicit INTERFACE or the rank is incorrect
so this is even worse, probably.
Some (but not all) Fortran function examples on the web place an EXTERNAL statement after the function declaration in the main program. So I tried placing a line EXTERNAL cross after the declaration block in the main program. I get an error message:
crosstest.f90:8.16:
EXTERNAL cross
1
Error: EXTERNAL attribute conflicts with DIMENSION attribute at (1)
So this seems incorrect also.
Some (but not all) Fortran function examples on the web place a RETURN statement on the second-to-last line of the function definition. I tried this, but I get the original rank mismatch error:
crosstest.f90:10.9:
r=cross(m,n)
1
Error: Rank mismatch in array reference at (1) (2/1)
So this does not fix the problem.
Can you please help me see my error?
The best practice is to place your procedures (subroutines and functions) in a module and then "use" that module from your main program or other procedures. You don't need to "use" the module from other procedures of the same module. This will make the interface of the procedure explicit so that the calling program or procedure "knows" the characteristics of the arguments ... it allows the compiler to check for consistency between the arguments on both sides ... caller and callee .. this eliminates a lot of bugs.
Outside of the language standard, but in practice necessary: if you use one file, place the module before the main program that uses it. Otherwise the compiler will be unaware of it. so:
module my_subs
implicit none
contains
FUNCTION cross(a, b)
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3), INTENT(IN) :: a, b
cross(1) = a(2) * b(3) - a(3) * b(2)
cross(2) = a(3) * b(1) - a(1) * b(3)
cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross
end module my_subs
PROGRAM crosstest
use my_subs
IMPLICIT NONE
INTEGER, DIMENSION(3) :: m, n
INTEGER, DIMENSION(3) :: r
m= [ 1, 2, 3 ]
n= [ 4, 5, 6 ]
r=cross(m,n)
write (*, *) r
END PROGRAM crosstest
This is kind of a late answer, but since I stumbled upon this and there is no real explanation yet for why your error occurred, I figured I'd add an explanation for everybody else who stumbles upon this question:
In your program, you define an array called cross, which is of rank 1. Then you call the cross function you define further down. Since the cross function does not have an explicit interface (see M.S.B.'s answer), the compiler does not know about it at this point. What it does know about is the array you declared. If you write r = cross(m, n), the compiler thinks you want to access the element at position (m, n) of the array cross. Since this array is of rank 1, but you supplied two arguments, you get the error
rank mismatch in array reference at (1) (2/1)
which means that you supplied two coordinates when the compiler was expecting one.
You can place the subroutines used in a program after a contains keyword within the program. This eliminates the need for creating a module or adding the interface definition.
PROGRAM crosstest
IMPLICIT NONE
INTEGER, DIMENSION(3) :: m, n
INTEGER, DIMENSION(3) :: r
m = (/1, 2, 3/)
n = (/4, 5, 6/)
r = cross(m,n)
print *, r
CONTAINS
PURE FUNCTION cross(a, b)
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3), INTENT(IN) :: a, b
cross(1) = a(2) * b(3) - a(3) * b(2)
cross(2) = a(3) * b(1) - a(1) * b(3)
cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross
END PROGRAM crosstest
The complier interpretes the cross in your main program as an array, rather than a function name. Therefore cross in your main program has nothing to do with the function you defined. To let the compiler know that cross is a function name, you can just define in your main program:
INTEGER :: cross
Then, when the compiler see the line r=cross(m,n), the compiler know that this is not array indexing since cross is not defined as an array in the main program. Then a remaining possiblity is that this is a function call, and Fortran compiler ususally adopt this possiblity.
For your case, the compiler finds out that the cross function returns an array rather than a scalar. For this case, the compiler insists that you provide an explicit interface for cross. So this workaround does not work for your case. As other anwsers suggest, you need to provide an explicit interface by either
containing the function definition in a module and use that module in your main program
or
containing the function definition in your main program.
Fortran uses parentheses for both function call and array indexing.
This design often causes confusion because a programmer can not figure out f(3) is a function call or array indexing without additional information.
I write a simple demonstration code to present my question in a quick way. Here's the code, which can not be successfully built.
Main.f90
PROGRAM test
IMPLICIT NONE
INTEGER :: a
a = 1
CALL sub(a)
END PROGRAM
sub.f90
SUBROUTINE sub(a)
IMPLICIT NONE
INTEGER :: a
SELECT CASE(a)
CASE(1)
INTEGER :: b,c
b = a
c = a*2
CASE(2)
INTEGER :: b(4),c(4)
b(:) = a
c(:) = a*2
END SELECT
END SUBROUTINE
I tried to compile, but the error shows 'Unexpected data declaration statement' occurs in the subroutine file. Does it mean that I cannot declare argument type inside SELECT CASE structure? The problem is that I want to define the value of a in the main program and pass it into subroutine sub(a). The argument type of b and c should be decided by a, thus I cannot determine in advance. I also want to pass the value of b and c back to the main program, which I don't know how to do that. So how can I achieve this? Thanks.
So you you are actually asking how to return scalar or array from some subroutine, not how to declare construct-local variables. In that case consider using two separate subroutines. One version for scalars and one for arrays. You can overload them as a generic procedure under one name if you want.
Also think about ELEMENTAL, but if you use scalar a it won't work with the arrays.
If you still want to know how to declare local variables:
Variables can only be declared at the beginning of the procedure or at the beginning of a block. That is a Fortran 2008 feature supported in recent versions of the most common compilers (from PC compilers at least GNU and Intel).
SELECT CASE(a)
CASE(1)
BLOCK
INTEGER :: b,c
b = a
c = a*2
END BLOCK
The code as you write it is illegal, as you found out. Now some people have pointed to the 2008 feature of BLOCK statements, and if that's what you need, you can try that. But I'd like to learn more about what you want to do with this.
The very fact that you give them the same name suggests to me that you want to treat them the same way later on, which makes things really tricky.
Here are a few alternatives:
1) Use separate variables:
INTEGER :: b_scalar, c_scalar, b_array(4), c_array(4)
select case(a)
case(1)
b_scalar = a
c_scalar = 2*b_scalar
case(2)
b_array = a
c_array = 2*b_array
end select
2) Use allocatable arrays:
integer, dimension(:), allocatable :: b, c
select case(a)
case(1)
allocate(b(1), c(1))
case(2)
allocate(b(4), c(4))
end select
b = a
c = 2 * b
Now you have to remember that b and c are arrays, possibly with length 1. You have to treat them that way.
All of these have advantages and disadvantages. Without knowing why you are doing what you're doing, I don't really know how to best advise you.
As to your second question: The simple way to return them is as an INTENT(OUT) dummy argument. Here's a working example:
module mod_allocatable
contains
subroutine my_sub(a, b, c)
implicit none
integer, intent(in) :: a
integer, dimension(:), allocatable, intent(out) :: b, c
if (allocated(b)) deallocate(b)
if (allocated(c)) deallocate(c)
select case(a)
case(1)
allocate(b(1), c(1))
case(2)
allocate(b(4), c(4))
end select
b = a
c = 2 * b
end subroutine my_sub
end module mod_allocatable
program test_alloc
use mod_allocatable
implicit none
integer :: a
integer, allocatable, dimension(:) :: b, c
a = 1
call my_sub(a, b, c)
print *, "b is ", b
print *, "c is ", c
end program test_alloc
This is not overly elegant...
SUBROUTINE sub(a)
IMPLICIT NONE
INTEGER, INTENT(IN) :: a
INTEGER, DIMENSION(:), ALLOCATABLE :: b, c
SELECT CASE(a)
CASE(1)
IF(ALLOCATED(B)) THEN
IF(UBOUND(B)) .NE. 1) THEN
DEALLOCATE(B)
ALLOCATE(B(1))
ENDIF
ELSE
ALLOCATE(B(1))
ENDIF
IF(ALLOCATED(C)) THEN
IF(UBOUND(C)) .NE. 1) THEN
DEALLOCATE(c)
ALLOCATE(C(1))
ENDIF
ELSE
ALLOCATE(C(1))
ENDIF
b = a
c = a*2
CASE(2)
IF(ALLOCATED(B)) THEN
IF(UBOUND(B)) .NE. 4) THEN
DEALLOCATE(B)
ALLOCATE(B(4))
ENDIF
ELSE
ALLOCATE(B(4))
ENDIF
IF(ALLOCATED(C)) THEN
IF(UBOUND(C)) .NE. 4) THEN
DEALLOCATE(C)
ALLOCATE(C(4))
ENDIF
ELSE
ALLOCATE(C(4))
ENDIF
b(:) = a
c(:) = a*2
CASE(DEFAULT)
WRITE(*,*)'how did we get here?... a=',a
END SELECT
END SUBROUTINE Sub
How do you check values in Fortran like in Matlab? For example in the little program under, why does it show c=0 in main when it is c=36 in the subroutine testing? How do you make it so c=36 in the main program?
Can you call on the value c in some sort of way? I understand that in the main program the variable c is either undefined or has value 0, but is there a way to save the value of c in the subroutine so you can use it again in other subroutines, without calculating it again?
When the program is quite large it is handy to check values as you go.
program main
use test
implicit none
integer :: a,b,c
call testing(a,b)
write(*,*)'Test of c in main program',c
end program main
module test
implicit none
contains
subroutine testing(a,b)
integer :: a,b,c
a=2
b=3
c=(a*b)**a
write(*,*)'Value of c in subroutine',c
end subroutine testing
end module test
It is important to learn about scope in programming languages.
Every name (identifier) has only a limited range of validity.
If you declare some variable inside a subroutine
subroutine s
integer :: i
end subroutine
than the i is valid only in that subroutine.
If you declare a variable in a module
module m
integer :: i
contains
subroutines and functions
end module
then the i is valid inside all those subroutines and functions and also in all program units that use that module.
However, that does not mean that you should declare the variable in the module and just share it. That would be more or less a global variable. This is reserved only for certain cases, where that is necessary, but not for getting results out of your subprograms.
If your subroutine just computes something and you want to get the result of that computation you have two possibilities:
1. pass it as an additional argument, which will be defined by the subroutine
subroutine testing(a, b, c)
integer, intent(in) :: a, b
integer, intent(out) :: c
c = (a*b) ** a
end subroutine
you then call it as
call testing(2, 3, c)
print *, "result is:" c
2. Make it a function
function testing(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = (a*b) ** a
end function
and then you can use directly
c = testing(2, 3)
print *, "result is:", c
or just
print *, "result is:", testing(2, 3)
This is the desired behaviour. Basically the calling routine should know nothing about the subroutine except for how to call it and what to get back. This is called encapsulation.
You can make variables accessible to the calling routine by declaring it in the module itself, and not in the subroutine:
module test
implicit none
integer :: c
contains
subroutine testing(a, b)
implicit none
integer :: a, b
a = 2
b = 3
c = (a*b) ** a
write(*, *) "Value of c in the subroutine: ", c
end subroutine testing
end module test
program main
use test
implicit none
integer :: a, b
call testing(a, b)
write(*, *) "Test of c in the main program: ", c
end program main
Note that you must not declare c in the main program, as it will get the variable from the module.
You could also use a COMMON block, but modules are far superior.
I try the following codes, and find the OPTIONAL keyword does not work. The compile is ok, but the runtime error will prompt.
I know usually the INTERFACE should be used in the module to provide enough information for the routines. I also try that, but failed to finish the compile no matter where I put the INTERFACE.
I have read some codes which use OPTIONAL in the TYPE declaration. https://www.pgroup.com/lit/articles/insider/v3n1a3.htm
Now I am using intel visual fortran, so is there any difference?
module testA_m
implicit none
type :: onion_c
contains
procedure :: testA
end type
contains
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
write(*,*) a,b
end subroutine
end module
program main
call testIt()
end program
subroutine testIt()
use testA_m
implicit none
type(onion_c) :: onion
real*8 :: c1
real*8 :: c2
c1 = 1.0d0
c2 = 2.0d0
call onion.testA(c1)
end subroutine
Well, you are trying to print b, which is not passed to the subroutine. Hence the access violation.
You should check for b first:
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
if ( present(b) ) then
write(*,*) a,b
else
write(*,*) a
endif
end subroutine
Maybe I need another variable for the real operation. Like the following.
I am still looking forward the better solution to use b directly.
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
real*8 :: bUsed
if ( present(b) ) then
bUsed = b
write(*,*) a,bUsed
else
bUsed = 2.00d0
write(*,*) a,bUsed
endif
end subroutine
Because Fortran does not support a program like
subroutine testA( this, a, b=10.0d0 )
I usually define a macro like the following in a common header file
#define _optval_(x,xopt,default) x = default; if (present(xopt)) x = xopt
and then use it at the top of a subroutine like
subroutine testA(this, a,b_)
class(onion_c) :: this
real*8 :: a
real*8, optional :: b_
real*8 b
_optval_( b, b_, 10.0d0 ) !! use only b from here on
Although this is not essentially different from writing several IF constructs, I feel it is a bit more convenient (at least for simple variables) because no need to worry about whether b is optional or not in the subsequent code. (But frankly, I hope Fortran2020 or so will support a syntax like the first example...)