How to handle Fortran global allocatable variables in a module across subroutines - module

I have the following module with an allocatable variable which is defined in the module, allocated in a subroutine, and then also used in a second subroutine called by the first subroutine. In this situation do I have to pass the variable to the second subroutine and declare INTENT(inout)? Or since it's a global variable it doesn't need to be passed as an argument?
MODULE test
IMPLICIT NONE
SAVE
REAL,ALLOCATABLE,DIMENSION(:,:,:) :: total
CONTAINS
!--- 1st subroutine
SUBROUTINE my_subr1(n,m,z)
IMPLICIT NONE
INTEGER,INTENT(in) :: n,m,z
ALLOCATE(total (n,m,z))
total=.9
CALL my_subr2(n)
END SUBROUTINE my_subr1
!-- 2nd subroutine
SUBROUTINE my_subr2(n)
IMPLICIT NONE
INTEGER,INTENT(in) :: n
total(n,:,:)=total(n-1,:,:)
END SUBROUTINE my_subr2
END MODULE test

do I have to pass the variable to the second subroutine and declare INTENT(inout)?
No, you don't. Any variable decalred in the body of the module has the save attribute by default. You must, though, ensure that the second subroutine is only called after the first was executed, or else the program will fail because total would not be initialized yet.
All functions and subroutines declared in the module will have access to total by host association.
By the way, there are some issues you should address in your code, as mentioned by #PierredeBuyl in the comments:
Variables declared in the module body are saved by default; you should remove the SAVE statement.
Procedures declared in a module inherit the IMPLICIT directive from the module scope, there is no need to redeclare it in the subroutine if you won't change it.
You are missing the declaration of the arguments in my_subr1.

Related

When using module variables as input variables, is there a way to specify intent(in) property as we do for a subroutine variable?

To remind me that a variable from a module used in a subroutine is an input rather than an output, I usually add comments to indicate this, which provides nothing to compilers.
There is no such thing in Fortran that would import a module variable as a constant. As roygvib mentioned, you can declare a variable protected inside the module to make it read only for all other modules. But you cannot import a non-protected variable as read-only in Fortran.
I recommend not to treat module variables, which are really just better global variables, as input or output. If something is clearly an input or output of your subroutine, make it an argument explicitly and call it in such a way that is clear what you are doing - with the global variable as an actual argument.

Is "intent" guaranteed for contained subroutines inside a module contained subroutine?

I am wondering if the following code is legal:
module my_mod
contains
subroutine my_outer_sub(a)
integer, intent(in) :: a
call my_inner_sub()
contains
subroutine my_inner_sub()
a=3 ! this compiles and runs!
end subroutine my_inner_sub
end subroutine my_outer_sub
end module my_mod
I compiled the code with PGI 17.4. I have been using contained subroutines inside module subroutines and now I wonder if this scheme is a suitable one?
No, the code is illegal. You cannot modify an intent(in) argument. This is an error in the compiler and should be reported to your vendor.
Gfortran identifies it correctly
Error: Dummy argument 'a' with INTENT(IN) in variable definition context (assignment) at (1)
and so does Intel Fortran
intent3.f90(11): error #6780: A dummy argument with the INTENT(IN) attribute shall not be defined nor become undefined. [A]
a=3 ! this compiles and runs!
------^
compilation aborted for intent3.f90 (code 1)

Private, Save attributes for variables in Fortran 90 modules

I am trying to add access restrictions to some of the variables (using private attribute) in a module but I need to use those variables in subsequent invocations of routines within that module:
module MyMod
private
integer,allocatable :: A(:)
public :: init,calc
contains
subroutine init()
! allocating and initializing A
end subroutine init
subroutine calc()
! Using A
end subroutine
end module
Questions:
Is this true that the private variable will not be in the scope of the program which uses this module.
If the answer to 1 is yes, then I would think that I can use save attribute for this variable. Please correct me if I am wrong?
Is this the proper way to perform this task?
Yes, if you put a private statement into your module without any further specification, you set the default accessibility to private.
For the first question, the Fortran 2008 Standard (Cl. 4.5.2.2 §3) states that:
If a type definition is private, then the type name, and thus the structure constructor (4.5.10) for the type, are accessible only within the module containing the definition, and within its descendants.
So A will not be accessible from anywhere outside the module or submodule (descendant).
For the second question, yes - you can use save here. (This is not related to the accessibility attribute). In fact, starting with Fortran 2008, this is implied for module variables, see for the Fortran 2008 Standard (Cl. 5.3.16 §4) [thanks #francescalus]:
A variable, common block, or procedure pointer declared in the scoping unit of a main program, module, or submodule implicitly has the SAVE attribute, which may be confirmed by explicit specification [...]
If I understood your third question correctly, it is related to the initialization. You could realize this with a function/subroutine to which you pass an array for initialization:
module MyMod
! ...
contains
! ...
subroutine init( A_in )
implicit none
integer, intent(in) :: A_in(:)
! allocating and initializing A
allocate( A(size(A_in)) )
A = A_in
end subroutine
end module
Inside init() you create a copy of A_in which is only accessible within the module. As long as calc() is part of the module (or a submodule thereof), it has full access to A.
To add to the answer by Alexander Vogt an implication of the save attribute.
This attribute gives precisely the effect you seem to be after (from F2008 5.3.16):
The SAVE attribute specifies that a local variable of a program unit or subprogram retains its association status, allocation status, definition status, and value after execution of a RETURN or END statement unless [something not applicable here]
In your example, A is a local variable of the module (and so a program unit) MyMod.
This means that, after the call to init which, presumably, allocates A and sets values that status is retained after the subroutine returns. Those values are then available come the call to calc. Both init and calc, of course, refer to the same A through host association.
You mention Fortran 90, so there is a subtle change (again as mentioned in that other answer). Before Fortran 2008 module variables would require the save attribute explicitly giving in some circumstances for this effect to come about. There's no harm in giving the save attribute explicitly if you aren't sure how your compiler treats the code (and some would say it's good practice, anyway).
This is another way of accomplishing what you want to do while avoiding the 'save'.
module MyMod
private
public :: myType, init
type myType
private
integer, allocatable :: A(:)
end type myType
contains
subroutine init(obj, n)
type(myType), intent(inout) :: obj
integer, intent(in) :: n
allocate(obj%A(n), source=-9999999)
end subroutine init
end module MyMod
program test
use MyMod, only: myType, init
type(myType) :: m ! m is an opaque object
call init(m, 10)
end program test
In this example, m is an opaque object - I can create the object, pass it around, but not access its contents (the array A in this case). This way, I am hiding my data. As long as my object m is in scope, I can operate on the data hidden in the object through routines contained in the module myMod.
If you have access to a modern compiler that supports Fortran 2003, you can rewrite the module as
module MyMod
private
public :: myType
type myType
private
integer, allocatable :: A(:)
contains
procedure, public :: init
end type myType
contains
subroutine init(obj, n)
class(myType), intent(inout) :: obj
integer, intent(in) :: n
allocate(obj%A(n), source=-9999999)
end subroutine init
end module MyMod
program test
use MyMod, only: myType
type(myType) :: m ! m is an opaque object
call m%init(10)
end program test

Externally declared (global) variable in Fortran

I want to know if it's possible to declare a variable and have declaration carry over to another subroutine or program (hence become global)
For example
program main
implicit none
call mysub
print *, x
end program main
subroutine mysub
implicit none
integer, parameter :: x = 1
end subroutine mysub
Would print "1"
Is this possible? I want to do this because a program I'm working on has large sets of variables that I would rather avoid copying unless necessary.
The most straightforward way to do this in modern Fortran is with modules.
Consider
module globals
implicit none
integer :: x
end module globals
program main
use globals
implicit none
call mysub
print *,x
end program main
subroutine mysub
use globals
implicit none
x = 1
end subroutine mysub
In this paradigm you specify your "global" variables within the module and use that module everywhere you want access to them.
If you are just using this to declare contants (parameters) you can simplify this to:
module globals
implicit none
integer, parameter :: x=1
end module globals
program main
use globals
implicit none
print *,x
end program main
The older method to accomplish this involved common blocks and includeing files that declared them every procedure that accessed them. If you find a tutorial dealing with the common block method I advise you to ignore them and avoid their use in new code.

Why is my Fortran module not making my index variable available?

This question is about Fortran. I need to pass an index i from the main program (i.e. do i = 1,30 ...) to a subroutine. I had created a module that gets the index, but somehow it is not available to the rest of the subroutines. In the program below I would like to use the index in the subroutine vals4interp, which I thought should be available since index is public. However it is not in fact available.
program main_prog
...
do i = 1, timesteps
...
call getindex(i)
enddo
end main_prog
module myindex
!
implicit none
public
integer,public ::index
contains
! get index of loop
subroutine getindex(index)
integer, intent(inout)::index
print*,'in getindex', index
end subroutine getindex
!
subroutine vals4interp(ti,this,tvar)
...
! Here I need 'index', but it's 0 !
call getindex(ti) !! this doesn't help... dunno why I thought it would ...
end vals4interp
In the routine getindex(), a variable index is used as a dummy argument. But this variable is actually a local variable in the subroutine and a different thing from the module variable index, although they have the same name.
subroutine getindex(index)
integer :: index ! <--- this is a local variable different from the module variable "index"
print*,'in getindex', index
end subroutine getindex
More specifically, if the same variable name (here index) is used both for a module variable and a dummy argument, then the local variable takes precedence and "hides" the module variable; i.e., we cannot change the module variable index from inside the routine (*). To avoid this behavior, simply change the name of the dummy argument from index to anything different and make the module variable index visible (accessible) from inside the routine. For example,
subroutine getindex( idx )
integer, intent(in) :: idx ! <--- a local variable
print*,'in getindex', idx
index = idx ! <--- set module variable "index"
end subroutine getindex
With this modification the subroutine vals4interp should print the expected value.
(*) As a related page, please see Use variable from fortran subroutine argument list to set module variable of the same name