COMMON block shared variables - fortran

Let's say I have two subroutines
SUBROUTINE S2909
COMMON X,Y
X =2;
Y =3;
END
SUBROUTINE S2900
COMMON X,Y
//display X and Y
END
A COMMON block is used for sharing variables so does this mean if the value of X, Y that is updated in the subroutine S2909 will be same as in subroutine S2900?

From my understanding, yes, the variables are shared throughout the program. Their values will depend on the order with which the subroutines are called.
The following program
program test
real x,y
common x,y
x = 1
y = 2
write(*,*) x,y
call changevals
write(*,*) x,y
end program test
subroutine changevals
real x,y
common x,y
x = 12
y = 13
end subroutine changevals
outputs
1.00000 2.00000
12.00000 13.00000

This sharing is indeed the point of common blocks. In particular, the common statement allows so-called storage association between various entities throughout a program.
So, the entities X and Y in the subroutine S2909 are storage associated with the entities X and Y in the subroutine S2900. Changes to the value in one entity X are reflected by the other entity X.
There are a few things worth noting about this, though.
In the common statements of the question this is relying on what is known as blank common. This is what happens when there is no name specified for a common block, such as in the statement
common /named/ x, y
This is noteworthy because attempting to generalize the behaviour in this question to named common blocks may be troublesome.
The entities in the various places where the common blocks are referenced are associated not by name, but by order in the storage sequence. This means that care must be made with say
SUBROUTINE S2909
COMMON X,Y
END
SUBROUTINE S2900
COMMON Y,X
END
But my answer really has two points to make, and the above was just a preamble to make it more answer-like.
First, I'll mention a pathological case which I wouldn't expect to see in the wild.
The question is relying on implicit typing. Consider the following
subroutine S2909
common x, y
x = 2.
y = 3.
end subroutine S2909
implicit integer (a-z)
call S2909
call S2900
contains
subroutine S2900
common x, y
print*, x, y
end subroutine
end
This is an example of uncivil code writing, but it illustrates an important thing. Because the entities x in the S2909 and x in the subroutine S2900 are of different types defining one of them causes the other to become undefined. That is: updating the value of one doesn't update the value of the other. With explicit typing one could see the same thing, or if there was implicit typing with default rules and entities i and j, say, in one subroutine.
And the final thing I want to say is: there are much better ways of sharing data "globally" without common blocks.

Related

Incorrect values from common block

How can I create a link between routine and sub-program using Fortran?
Program Example
common a,b,c,d,e
print*,"Enter a"
read*,a
print*,"Enter coefficient of x in f1(x)"
read*,b
print*,"Enter intercept in f1(x)"
read*,c
print*,"Enter coefficient of x in f2(x)"
read*,d
print*,"Enter intercept in f2(x)"
read*,e
Print*,f1(2.),f2(3.)
pause
end
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function f1(x)
common a,b,c
f1=a*x**2+b*x+c
return
end
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function f2(y)
common d,e
f2=d*y+e
return
end
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
this was an example.
when I print the f1(2.) and f2(3.) I get true result for the first one and false results for the second one.
There are two very different questions in your post.
How do we share data between subprograms? In modern Fortran use modules. We have many questions and answers about that. Common blocks are obsolete (and since Fortran 2018 officially obsolescent - Thanks #steve).
Why are the results using common incorrect?
You are using an unnamed common block. In comon blocks the variable names are irrelevant. They can differ arbitrarily between compilation units (main program, subprograms). The order is important.
Therefore your
common d,e
is the same as doing
common a,b
To get access to the fifth element of the common block you must have all five variables
common a,b,c,d,e
(or as francescalus points out, one has to reference the right numerical storage unit. Ome could also have one array instead.)
Finally, I would like the stress the importance of implicit none. You should really use it.

Scope and dealing with subroutines with many inputs

Some of my fortran subroutines have a gigantic amount of inputs passed to them, sometimes even 30 or 40. The reason for this is twofold, first, those subroutines have many clearly directly related subroutines which need some of those variables as input, and second, to avoid defining global variables, and the solution for this seems to be to pass every variable to a subroutine explicitly every time.
This seems unacceptable to me, but I don't really have a solution for it, and I am not 100% sure that it is a problem in the first place, perhaps this is the right way to do things in this language.
My question is then: is this a problem? If it is, is there a better way to manage scope in this language, without necessarily introducing objects?
I can see why the designers want to avoid global variables. I have to work with a code that took the opposite approach, almost no arguments and everything is in the global state in various modules and it is terrible, no matter how much they use the only clause in the use statements.
We can safely say that this amount of arguments (say 30) is way too large. All code style guidelines will probably agree with that. It is often a bit unpleasant to work with the many arguments libraries like LAPACK require, and that is nowhere close to 30.
There are several ways Fortran 90 and more recent can reduce the number of arguments.
Firstly, you can couple logically related variables into a derived type
type particle
integer :: species
real :: mass
real :: x, y, z
real :: vx, vy, vz
...
end type
Secondly, by using assumed shape arrays you can avoid passing the array dimensions. This allows modern LAPACK interfaces to have significantly smaller number of arguments, for example (both the Netlib and the MKL interfaces).
subroutine sub(A, NX, NY, NZ)
integer :: NZ, NY, NZ
real :: A(NX, NY, NZ)
vs.
subroutine sub(A)
real :: A(:,:,:)
This change requires explicit interface for the procedure so in practise the procedures have to be moved into modules.
Both these changes are rather significant changes and require significant refactoring efforts for large legacy codes.

Fortran 90 logical kind mismatch

I'm trying to pass an argument declared simply as logical :: invar
to a function where the receiving variable is declared as
logical(x) :: invar
Now x is defined as
INTEGER, PARAMETER :: x = KIND(.TRUE.)
What does that definition of x mean? I did a search for kind(.true.) but all results kind of brush this aspect aside. Would appreciate some clarification for an expert.
I'm using the Intel compiler, if this has something to do with the compiler.
Variables such as real numbers, integers, and even logicals can be different kinds. Typically, this is important to distinguish between single precision and double precision reals, for example. In my experience, there's no reason to fiddle with the kind of a logical.
Whoever wrote this code, obviously, thinks otherwise. When you declare a logical in the usual way, with
logical :: L1
the variable my_logical is of the default kind. When you declare it using
integer, parameter :: x = KIND(.TRUE.)
integer(x) :: L2
it has the kind of x, which is defined to be the kind of .true.. The tricky part is that .true. is almost certainly also of the default kind. (The standard requires that the default kind is the kind of .FALSE.)
So, in the examples above, L1 and L2 are of the same kind. I don't know why somebody would bother with defining the default logical kind as x, but you shouldn't worry about it.

Fortran function to overload multiplication between derived types with allocatable components

Foreword
In order to store banded matrices whose full counterparts can have both rows and columns indexed from indices other than 1, I defined a derived data type as
TYPE CDS
REAL, DIMENSION(:,:), ALLOCATABLE :: matrix
INTEGER, DIMENSION(2) :: lb, ub
INTEGER :: ld, ud
END TYPE CDS
where CDS stands for compressed diagonal storage.
Given the declaration TYPE(CDS) :: A,
The rank-2 component matrix is supposed to contain, as columns, the diagonals of the actual full matrix (like here, except that I store the diagonals as columns and not as rows).
The components ld and ud are supposed to contain the number of lower and upper diagonals respectively, that is -lbound(A%matrix,2) and +ubound(A%matrix,2).
The 2-elements components lb and ub are supposed to contain the lower bounds and upper bounds of the actual full matrix along the two dimensions. In particular lb(1) and ub(1) should be the same as lbound(A%matrix,1) and lbound(A%matrix,2).
As you can see in points 2. and 3., the derived type contains some redundant information, but I don't care, since they are just 3 couples of integers. Furthermore, in the code that I'm writing, the information about the bounds and the band of the actual full matrix is know before the matrix can be filled. So I first assign the values to the components ld, ud, lb and ub, and then I used these components to ALLOCATE the matrix component (then I can fill it properly).
The problem
I have to perform matrix multiplication between such sparse matrices, so I wrote a FUNCTION to perform such product and used it to overload the * operator.
At the moment the function is as follows,
FUNCTION CDS_mat_x_CDS_mat(A, B)
IMPLICIT NONE
TYPE(CDS), INTENT(IN) :: A, B
TYPE(CDS) :: cds_mat_x_cds_mat
! determine the lower and upper bounds and band of the result based on those of the operands
CDS_mat_x_CDS_mat%lb(1) = A%lb(1)
CDS_mat_x_CDS_mat%ub(1) = A%ub(1)
CDS_mat_x_CDS_mat%lb(2) = B%lb(2)
CDS_mat_x_CDS_mat%ub(2) = B%ub(2)
CDS_mat_x_CDS_mat%ld = A%ld + B%ld
CDS_mat_x_CDS_mat%ud = A%ud + B%ud
! allocate the matrix component
ALLOCATE(CDS_mat_x_CDS_mat%matrix(CDS_mat_x_CDS_mat%lb(1):CDS_mat_x_CDS_mat%ub(1),&
& -CDS_mat_x_CDS_mat%ld:+CDS_mat_x_CDS_mat%ud))
! perform the product
:
:
END FUNCTION
This means that, if I have to do the product multiple times the allocation is done multiple times inside the function. I think this is not good from a performance point of view.
I ask for suggestions on how to accomplish the task of banded sparse matrix times banded sparse matrix. I would like to use the type the I defined because I need it to be as general, in terms of bounds, as it is at the moment. But I could change the procedure to perform the product (from FUNCTION to SUBROUTINE, if necessary).
Ideas
I could rewrite the procedure as a SUBROUTINE in order to declare CDS_mat_x_CDS_mat with INTENT(INOUT) do the assignment of components other than matrix, as well as the allocation, outside the SUBROUTINE. The drawback would be that I could not overload the * operator.
I noticed the intrinsic function MATMUL can operate on any rank-2 operands, whichever the upper and lower bounds along the two dimensions. This means that the allocation is performed inside the function. I suppose it's efficient (since it is an intrinsic). The difference with respect to my function is that it accepts rank-2 arrays of any shape, wheres mine accept derived data types objects with a rank-2 array component of any shape.
The intrinsic function MATMUL has the equivalent of an automatic (F2008 5.2.2) result - the shape of the result is expressed in such a way that it becomes a characteristic of the function (F2008 12.3.3) - the shape of the function result is determined in the specification part of the function and (in terms of implementation) the compiler therefore knows how to calculate the shape of the function result ahead of actually executing the function proper.
As a consequence there are no Fortran language ALLOCATABLE variables associated with the equivalent of the intrinsic MATMUL function result. This is not the same thing as there being "no memory allocation" - the compiler may still need to allocate memory behind the scenes for its own purposes - for things like expressions temporaries and the like.
(I say "equivalent of" above, because intrinsic procedures are inherently special - but pretend for a moment that MATMUL was just a user function.)
The equivalent of that sort of automatic result for your case can be achieved by using length type parameters. This is Fortran 2003 feature - the same base language standard that introduced allocatable components - but it is not one that has yet been implemented by all actively maintained compilers.
MODULE xyz
IMPLICIT NONE
TYPE CDS(lb1, ub1, ld, ud)
INTEGER, LEN :: lb1, ub1, ld, ud
REAL :: matrix(lb1:ub1, ld:ud)
INTEGER :: lb2, ub2
END TYPE CDS
INTERFACE OPERATOR(*)
MODULE PROCEDURE CDS_mat_x_CDS_mat
END INTERFACE OPERATOR(*)
CONTAINS
FUNCTION CDS_mat_x_CDS_mat(A, B) RESULT(C)
TYPE(CDS(*,*,*,*)), INTENT(IN) :: A, B
TYPE(CDS(A%lb1, A%ub1, A%ld+B%ld, A%ud+B%ud)) :: C
C%lb2 = B%lb2
C%ub2 = B%ub2
! perform the product.
! :
END FUNCTION CDS_mat_x_CDS_mat
END MODULE xyz
Theoretically this gives the compiler more opportunity for optimisation, because it has more insight ahead of the call to the function for the storage required for the function result. Whether this actually results in better real world performance depends on the implementation of the compiler and the nature of the function references.

Fortran SAVE statement

I've read about the save statement in the (Intel's) language reference document, but I cannot quite grasp what it does. Could someone explain to me in simple language what it means when the save statement is included in a module ?
In principal when a module goes out-of-scope, the variables of that module become undefined -- unless they are declared with the SAVE attribute, or a SAVE statement is used. "Undefined" means that you are not allowed to rely on the variable having the previous value if you again use the module -- it might have the previous value when you re-access the module, or it might not -- there is no guarantee. But many compilers don't do this for module variables -- the variables probably retain their values -- it isn't worth the effort for the compiler to figure out whether a module remains in scope or not and probably module variables are treated as global variables -- but don't rely on that! To be safe, either use "save" or "use" the module from the main program so that it never goes out of scope.
"save" is also important in procedures, to store "state" across invocations of the subroutine or function (as written by #ire_and_curses) -- "first invocation" initializations, counters, etc.
subroutine my_sub (y)
integer :: var
integer, save :: counter = 0
logical, save :: FirstCall = .TRUE.
counter = counter + 1
write (*, *) counter
if (FirstCall) then
FirstCall = .FALSE.
....
end if
var = ....
etc.
In this code fragment, "counter" will report the number of invocations of subroutine x. Though actually in Fortran >=90 one can omit the "save" because the initialization in the declaration implies "save".
In contrast to the module case, with modern compilers, without the save attribute or initialization-on-a-declaration, it is normal for local variables of procedures to lose their values across invocations. So if you attempt to use "var" on an later call before redefining it in that call, the value is undefined and probably won't be the value calculated on a previous invocation of the procedure.
This is different from the behavior of many FORTRAN 77 compilers, some of which retained the values of all local variables, even though this wasn't required by the language standard. Some old programs were written relying on this non-standard behavior -- these programs will fail on the newer compilers. Many compilers have an option to use the non-standard behavior and "save" all local variables.
LATER EDIT: update with a code example that shows incorrect usage of a local variable that should have the save attribute but doesn't:
module subs
contains
subroutine asub (i, control)
implicit none
integer, intent (in) :: i
logical, intent (in) :: control
integer, save :: j = 0
integer :: k
j = j + i
if ( control ) k = 0
k = k + i
write (*, *) 'i, j, k=', i, j, k
end subroutine asub
end module subs
program test_saves
use subs
implicit none
call asub ( 3, .TRUE. )
call asub ( 4, .FALSE. )
end program test_saves
Local variable k of the subroutine is intentionally misused -- in this program it is initialized in the first call since control is TRUE, but on the second call control is FALSE, so k is not redefined. But without the save attribute k is undefined, so the using its value is illegal.
Compiling the program with gfortran, I found that k retained its value anyway:
i, j, k= 3 3 3
i, j, k= 4 7 7
Compiling the program with ifort and aggressive optimization options, k lost its value:
i, j, k= 3 3 3
i, j, k= 4 7 4
Using ifort with debugging options, the problems was detected at runtime!
i, j, k= 3 3 3
forrtl: severe (193): Run-Time Check Failure. The variable 'subs_mp_asub_$K' is being used without being defined
Normally, local variables go out of scope once execution leaves the current procedure, and so have no 'memory' of their value on previous invocations. SAVE is a way of specifying that a variable in a procedure should maintain its value from one call to the next. It's useful when you want to store state in a procedure, for example to keep a running total or maintain a variable's configuration.
There's a good explanation here, with an example.
A short explanation could be: the attribute save says that the value of a variable must be preserved across different calls to the same subroutine/function. Otherwise normally when you return from a subroutine/function, "local" variables lose their values since the memory where those vars were stored is released. It is like static in C, if you know this language.