Where does this Fortran variable come from? - fortran

Can anyone tell me about the costh variable used in the following subroutine? From where is the subroutine obtaining the value of this variable? Is it some error or inbuilt function?
The complete subroutine is given below.
SUBROUTINE MOMENT(I,A,AP,MODE,EP,NCASC,ID)
COMMON/MOM/VY(99996),VZ(99996),VX(99996)
DIMENSION ERES(99996),FCT(99996)
COMMON/XQANG/SUM(300,10),MDIR,COSTH
EQUIVALENCE(ERES(1),VY(1)),(FCT(1),VZ(1))
IF(ID-2)10,30,40
C INITIALIZATION
10 N=1
NN=N+NCASC-1
DO 20 J=N,NN
VY(J)=EP*MDIR
VX(J)=0.
20 VZ(J)=EP*(1-MDIR)
GO TO 60
C
C CALCULATION OF MOMENT
C
CKM 30 RN4=RANF(0.)
30 RN4=RAN(ISEED) !KM
PHI=6.28318*RN4
SOX=2.*AP*EP/(A**2*931.5)
C BUG FIX A*(AP+A)REPLACED BY A**2 12/15/82
C IF(SOX.LT.0.)WRITE(*,943)AP,EP,A
VT=SQRT(SOX)
SOX=1.-COSTH**2
IF(SOX.LT.0.)SOX=0.
SINTH=SQRT(SOX)
VZSE=VT*COSTH
VYSE=VT*SINTH*SIN(PHI)
VXSE=VT*SINTH*COS(PHI)
VZ(I)=VZ(I)+VZSE
VY(I)=VY(I)+VYSE
VX(I)=VX(I)+VXSE
VZP=VZ(I)-VZSE*(A/AP+1.)
VYP=VY(I)-VYSE*(A/AP+1.)
VXP=VX(I)-VXSE*(A/AP+1.)
VPP2=VZP*VZP+VYP*VYP+VXP*VXP
EPART=AP*VPP2*469.
SOX=0.
IF(VPP2.GT.0.0)SOX=VZP/SQRT(VPP2)
C DO NOT USE QUICK FUNCTIONS HERE
ANG=ACOS(SOX)*180./3.1415927
CALL OUTEM(2,MODE,EPART,ANG)
GO TO 60
C
C END CALCULATION
C
40 VFTS=VX(I)**2+VY(I)**2+VZ(I)**2
ERES(I)=0.5*A*VFTS*931.5
IF(VFTS.NE.0.)GO TO 50
FCT(I)=0.0
GO TO 60
50 FCT(I)=ACOS(VZ(I)/SQRT(VFTS))*180./3.1415927
60 RETURN
END

This line
COMMON/XQANG/SUM(300,10),MDIR,COSTH
informs the subroutine about a common block called XQANG which has an element called COSTH. In the absence of other information, and in a code of that vintage, this is most likely to be a real variable.
Common blocks are an early-Fortran mechanism for sharing variables across program units, such as between a main program and a subroutine. In straightforward use the same common block declaration will be found in multiple locations, with the same list of variables. Each declaration refers to the same variables.
There is a twist though, and one to watch out for carefully. The common block is actually a shared block of memory, and there is no requirement that each instance of the declaration identify the same variables. One common use of common blocks was to declare, say, an array of 100 reals in one location, but to declare two arrays each of 50 reals elsewhere -- same memory, different variables.
Even better, they could also be used to change the types of variables (sort of). One usage of a common block might contain a real variable occupying 4 bytes, while another usage of the same block might contain a 4-byte integer variable at the same location - same bits, different interpretations.
These twists are among the reasons for common blocks being widely deprecated. Another reason for their deprecation is that they obscure the sharing of variables, these days most of us prefer to explicitly pass arguments into and out of subroutines through their argument lists.
I'd guess very few Fortran programmers under 50 are still writing new code using them. But Fortran programmers from 8 - 80 are still working on codes containing them.

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.

Can overindexing in FORTRAN 77 modify the program itself?

Here is a little program in FORTRAN 77
dimension totlev(20)
do 100 i=1,24
totlev(i)=0.0
write(0,*) 'totlev i=',i, totlev(i)
100 continue
end
I compile it using MinGW by typing gfortran test.f and I do get a warning (not an error):
test.f:4:14:
do 100 i=1,25
2
totlev(i)=0.0
1
Warning: Array reference at (1) out of bounds (25 > 20) in loop beginning at (2)
test.f:5:40:
test.f:3:72:
do 100 i=1,25
2
test.f:5:40:
write(0,*) 'totlev i=',i, totlev(i)
1
Warning: Array reference at (1) out of bounds (25 > 20) in loop beginning at (2)
However, not always such a warning would be produced if it was a longer program. An executable is created. When I run it it behaves like an infinite loop.
And this is my problem: How is an infinite loop even possible with the DO iteration? Isn't it a logical impossibility? My only explanation is that overindexing in this case reaches to the program code itself and changes it. Is that possible?
I use Windows 7 OS if that's relevant.
It's not changing the code, it's changing the variable i. Both the array totlev(20) and the scalar i are local variables, and thus typically stored in the program's stack frame (though the standard leaves this choice to the 'processor', Fortran-speak for implementation). In this case the compiler apparently put i 4 'real's (probably 16 bytes) after the end of totlev, so assigning to totlev(24) actually changes i. Fortran basically requires that an integer and single/default-precision real variable be the same size, and while it doesn't require any particular relationship between the representations for integers and reals, most machines today use 'IEEE 754' floating-point and in that system a real 0.0 has the same representation as an integer 0.
On many though not all computer architectures it is possible to address code by indexing an array out of range, but this almost always requires indexes far out of range: millions or billions or more, not one or two. On older architectures it was often possible both to read and write code this way, but most systems since about 1980 have memory protection so that you can't write to code. In particular all Windows NT-series systems do this, which includes Windows 7.

Is there a setting or workaround in gFortran to the Microsoft Fortran 5.1 $STORAGE Metacommand

We have some (a huge libray or 40+ modules) old Fortran code than needs updating and compiling with a more recent compiler.
Is there anyway to set gFortran to allow for the $STORAGE:2 metacommand as used by old MS Fortran 5.1?
According to: https://support.microsoft.com/en-us/kb/51471
The $STORAGE:n metacommand allocates "n" bytes of memory for all INTEGER and LOGICAL variables. For example, when an application specifies the $STORAGE:2 metacommand and declares an INTEGER variable B, the compiler allocates two bytes for B instead of four. The $STORAGE metacommand does not affect memory allocation when a declaration includes an explicit length specification, such as an INTEGER*2 or INTEGER*4.
I wish it was a simple matter of rewriting the variable declarations to use integer*2. However the programmer who wrote it, uses tons of implicit variable declarations and many EQUIVALENCE statements everywhere that are troublesome to deal with:
$STORAGE:2
CHARACTER*2 ABC
EQUIVALENCE (ABC,ITT)
There is no way I know in modern compilers to do this for 16 bit integers.
Compilers usually allow promoting integer kinds by a command line switch, but I don't recall any modern free compiler to allow a change to 16 bit ones.
I would suggest rewriting the variable declarations to use integer*2 instead instead of the directive.

Why would common block variables not preserve their values?

First, I know that using common blocks is a bad idea in fortran (and programming in general). However, I'm updating someone else's code and I don't want to mess up things that are known to work.
Second, I know I should post something more specific then this. If I knew how to reduce this into something small, I would. However, since I know, and I don't think you'll appreciate 2500 lines of code, I can't post a specific example.
With that in mind, I can't describe my problem.
I'm updating someone else's fortran code. The guy used several (4) common blocks to set up global variables. For some reason when I call a function that use such a block, all it's value are 0. Has anyone encountered that before? Does anyone know why this might happen? How to reproduce this? Any starting point to check this would be helpful.
For what it worth, the said common block is declared as
common /set/ block,x,y,z,llx,lly,llz,ilx,ily,ilz,third,third2
block is a 4D array. x, y, and z are 1D array. llx,lly, and llz, are double precision types. The rest are integer types.
The common block(s) is (are) declared and initialized at the main program before any function is called.
Some compilers do initialize common variables to zero, so if you first invoke the function with the common block, you might find zeros everywhere (although you should not rely on that). But once you set some values for the common block variables in the program, those values should appear whenever you use the common block.
As of the variables in the common block: They can be of arbitrary type, as long as they are consistently defined at all places, where the common block is used.
Can you compare your code with this tiny example? I think you might be missing something, like the "common" declaration inside the subroutine.
Note that you don't need to use the same name for the variable inside the subroutine (AA) as you have for main (GB). Just the common block name (myarray) has to be the same. However, nothing bad will happen if you replace AA by GB, and the final result would be a little bit cleaner to read.
program main
real GB(4)
common /myarray/ GB
integer i
real B(4)
GB=0
write(*,*) 'GB',GB
do i=1,4
call AddSubR()
write(*,*) 'GB',GB
enddo
end program main
subroutine AddSubR()
real AA(4)
common /myarray/ AA
integer i
do i=1,4
AA(i) = AA(i)+1
enddo
end subroutine AddSubR

Common block usage in Fortran

I'm new to Fortran and just doing some simple things for work. And as a new programmer in general, not sure exactly how this works, so excuse me if my explanation or notation is not the best. At the top of the .F file there are common declarations. The person explaining it to me said think of it like a struct in C, and that they are global. Also in that same .F file, they have it declared with what type. So it's something like:
COMMON SOMEVAR
INTEGER*2 SOMEVAR
And then when I actually see it being used in some other file, they declare local variables, (e.g. SOMEVAR_LOCAL) and depending on the condition, they set SOMEVAR_LOCAL = 1 or 0.
Then there is another conditional later down the line that will say something like
IF (SOMEVAR_LOCAL. eq. 1)
SOMEVAR(PARAM) = 1;
(Again I apologize if this is not proper Fortran, but I don't have access to the code right now). So it seems to me that there is a "struct" like variable called SOMEVAR that is of some length (2 bytes of data?), then there is a local variable that is used as a flag so that later down the line, the global struct SOMEVAR can be set to that value. But because there is (PARAM), it's like an array for that particular instance? Thanks. Sorry for my bad explanation, but hopefully you will understand what I am asking.
Just to amplify something #MSB already mentioned: COMMON blocks tell a compiler how to lay variables out in memory. There is almost no reason to use them with modern Fortran, ie with any compiler which can cope with Fortran 90 or later, and there are good reasons to avoid them.
And to add one thing: in modern Fortran you can do approximately what C structs do with user defined types. Check your documentation for TYPE.
The first declaration has SOMEVAR as a scalar integer of two bytes. The usage you show has SOMEVAR has an array -- based on it being indexed. This is possible to do in Fortran via "sequence association" but it is poor practice. In one file you could declare SOMEVAR as INTEGER*2 and two bytes are allocated to this scalar. In another file you could declare it as INTEGER*1 SOMEVAR(2), and two bytes are reserved, this time for an array of two elements, each of one byte. Using the same common block in both files can cause these two variables to overlap, byte by byte -- sequence association. Many years ago, when memory was very small, programmers did this to reduce memory usage, knowing that different subroutines were using variables at different times. The reasons to do this today are very, very limited. Mostly one shouldn't because it is liable to be confusing.
You can also setup sequence association with the EQUIVALENCE statement. Again, best avoided. The modern replacement for the times that one must do "tricky" things that needed the EQUIVALENCE statement is the TRANSFER function.