DIMENSION statement in FORTRAN - c++

I am converting a FORTRAN code to C++. While understanding the FORTRAN code I came across the following code snippet in FORTRAN.
DIMENSION X(50),Y(50),PARA(6,9)
DIMENSION AMPA(12),FCUR(20),VER(20),AMPS(20)
I understand that DIMENSION do not need any data type in FORTRAN. But I am not able to understand what will be the default data types for X, Y, PARA etc. Is it integer by default?

Classically, Fortran variables with names starting [I-N] were INTEGER and everything else was REAL. So, the most likely type for those variables in C++ is float.
float X[50], Y[50], PARA[6][9];
float AMPA[12], FCUR[20], VER[20], AMPS[20];
However, with 2D arrays, Fortran uses column-major order where C and C++ use row-major order. You might need to worry about that for the 2D array. You might also decide to convert the names to lower-case.

In Fortran, variables whose names began with characters from I to N in the alphabet (remembering Fortran is not case sensitive) are implicitly integer, and everything else is implicitly real unless otherwise stated -- this will probably correspond to int and float in C++.
Even as far back as FORTRAN 77 this was seen as bad practice, and it's usual today to begin every Fortran program and module with the statement implicit none to require every variable to be declared wth an explicit type.

Related

Allocate Multiple Arrays with Single Shape

I am allocating several rank-3 arrays to be exactly the same shape, and I wonder whether it's possible to specify the shape only once. For example, I'm currently doing:
program main
implicit none
integer :: long_name_dimension_1 = 3
integer :: long_name_dimension_2 = 5
integer :: long_name_dimension_3 = 8
real, allocatable, dimension(:,:,:) :: A, B, C
allocate(A(long_name_dimension_1,long_name_dimension_2,long_name_dimension_3), &
B(long_name_dimension_1,long_name_dimension_2,long_name_dimension_3), &
C(long_name_dimension_1,long_name_dimension_2,long_name_dimension_3))
end program main
This is annoying to type, and it's difficult to immediately see that these arrays have the same shape. I could use mold or source, after allocating the first array, such as:
allocate(A(long_name_dimension_1,long_name_dimension_2,long_name_dimension_3))
allocate(B, source=A)
allocate(C, mold=A)
but I don't really like this either - perhaps because, in my mind, it should be one allocate statement.
I'm looking for syntax such as:
allocate( SHAPE :: (long_name_dimension_1,long_name_dimension_2,long_name_dimension_3), &
A, B, C)
which I've been unable to find. Does such a syntax (or something similar) exist?
Well, there is the syntax for the allocate statement in the last (2015) Fortran Standard:
The shape must follow each allocation term in allocation-list, so there isn't any syntax structure for declaring one common shape for all the variables, except with the SOURCE or MOLD options.
I could use mold or source, after allocating the first array, but I
don't really like this either - perhaps because, in my mind, it should
be one allocate statement.
Actually, you cannot define the shape of an array and reference it in the same statement. Later in this same chapter, it says:
source-expr shall not be allocated within the ALLOCATE statement in
which it appears; nor shall it depend on the value, bounds, deferred
type parameters, allocation status, or association status of any
allocate-object in that statement.
So, summing up, the closest thing to what you want is exactly what you don't like:
allocate(A(long_name_dimension_1,long_name_dimension_2,long_name_dimension_3))
allocate(B, C, mold=A)
Or source=A, if you want the contents of A to be copied on.
Edit:
What about this:
allocate(A, B, C, mold=reshape([integer ::], &
[long_name_dimension_1,long_name_dimension_2,long_name_dimension_3])
I just checked in Intel Fortran and confirmed it works. It seems strange that a zero-sized array can have any shape. I strongly believe it's not standard, though.
Fortran doesn't support allocating multiple arrays as you would like it to. You're just about stuck with the mold and source options to the allocate statement. You could write
allocate(A(long_name_dimension_1,long_name_dimension_2,long_name_dimension_3))
allocate(B,C,mold=A)
which saves a few keystrokes. You could save a few more by writing
allocate(A(long_name_dimension_1,long_name_dimension_2,long_name_dimension_3))
A = 1
B = A
C = A
albeit that this sets the values of the elements of B and C as well as their shapes.
I edited the code to deal with the issue #evets raised in a comment.

Convert FORTRAN DEC UNION/MAP extensions to anything else

Edit: Gfortran 6 now supports these extensions :)
I have some old f77 code that extensively uses UNIONs and MAPs. I need to compile this using gfortran, which does not support these extensions. I have figured out how to convert all non-supported extensions except for these and I am at a loss. I have had several thoughts on possible approaches, but haven't been able to successfully implement anything. I need for the existing UDTs to be accessed in the same way that they currently are; I can reimplement the UDTs but their interfaces must not change.
Example of what I have:
TYPE TEST
UNION
MAP
INTEGER*4 test1
INTEGER*4 test2
END MAP
MAP
INTEGER*8 test3
END MAP
END UNION
END TYPE
Access to the elements has to be available in the following manners: TEST%test1, TEST%test2, TEST%test3
My thoughts thusfar:
Replace somehow with fortran EQUIVALENCE.
Define the structs in C/C++ and somehow make them visible to the FORTRAN code (doubt that this is possible)
I imagine that there must have been lots of refactoring of f77 to f90/95 when the UNION and MAP were excluded from the standard. How if at all was/is this handled?
EDIT: The accepted answer has a workaround to allow memory overlap, but as far as preserving the API, it is not possible.
UNION and MAP were never part of any FORTRAN standard, they are vendor extensions. (See, e.g., http://fortranwiki.org/fortran/show/Modernizing+Old+Fortran). So they weren't really excluded from the Fortran 90/95 standard. They cause variables to overlap in memory. If the code actually uses this feature, then you will need to use equivalence. The preferred way to move data between variables of different types without conversion is the transfer intrinsic, but to you that you would have to identify every place where a conversion is necessary, while with equivalence it is taking place implicitly. Of course, that makes the code less understandable. If the memory overlays are just to save space and the equivalence of the variables is not used, then you could get rid of this "feature". If the code is like your example, with small integers, then I'd guess that the memory overlay is being used. If the overlays are large arrays, it might have been done to conserve memory. If these declarations were also creating new types, you could use user defined types, which are definitely part of Fortran >=90.
If the code is using memory equivalence of variables of different types, this might not be portable, e.g., the internal representation of integers and reals are probably different between the machine on which this code originally ran and the current machine. Or perhaps the variables are just being used to store bits. There is a lot to figure out.
P.S. In response to the question in the comment, here is a code sample. But .... to be clear ... I do not think that using equivalence is good coding pratice. With the compiler options that I normally use with gfortran to debug code, gfortran rejects this code. With looser options, gfortran will compile it. So will ifort.
module my_types
use ISO_FORTRAN_ENV
type test_p1_type
sequence
integer (int32) :: int1
integer (int32) :: int2
end type test_p1_type
type test_p2_type
sequence
integer (int64) :: int3
end type test_p2_type
end module my_types
program test
use my_types
type (test_p1_type) :: test_p1
type (test_p2_type) :: test_p2
equivalence (test_p1, test_p2)
test_p1 % int1 = 2
test_p1 % int1 = 4
write (*, *) test_p1 % int1, test_p1 % int2, test_p2 % int3
end program test
The question is whether the union was used to save space or to have alternative representations of the same data. If you are porting, see how it is used. Maybe, because the space was limited, it was written in a way where the variables had to be shared. Nowadays with larger amounts of memory, maybe this is not necessary and the union may not be required. In which case, it is just two separate types
For those just wanting to compile the code with these extensions: Gfortran now supports UNION, MAP and STRUCTURE in version 6. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56226

Determining type of variables not declared at top of Fortran subroutine

I am working with a legacy Fortran 77 code subroutine where the parameter types are not declared at the top of the code block.
Here is a snippet showing the very top of the subroutine.
SUBROUTINE BPASS(F1,F2,F3,F4,SI,N,A,IERR)
REAL * 4 A( N ),FV( 4 )
From the above, I think that A is an array of length N with type REAL *4, equivalent in size to a C float. Alternately, FV(4) is an array of length 4 with type REAL *4.
However, what are the types of F1,F2,F3,F4,SI,N,IERR, if the types are not listed? It appears that N should be an integer.
I need to know the types so that I can call the subroutine from C++ code. Is there a Fortran convention for the types that are not declared?
By default Fortran will assign the type integer to variables whose names begin with the letters I,J,K,L,M,N and type real to all other undeclared variables.
I agree with your parsing of the definitions of A and FV.
Modern Fortran provides the expression implicit none for ensuring that the default rules are not applied, but when working with old codes it's sometimes not possible to avoid familiarity with the old dark ways.
In FORTRAN77, by default variables starting with I, J, K, L, M, or N are INTEGER, otherwise they are REAL. FORTRAN90, and some variants of FORTRAN77, provide a mechanism to disable this by using IMPLICIT NONE.

Implicit real error

I have written program with implicit real*8. The program is working fine but as soon as i inserted another data file that contains the data of long and double precision digits than the results i found were not appropriate. Experts and the program developers adviced me to change implicit real*16. But it is not working in my fortran power station 4.0 and giving implicit error. How to convert or upgrade the power station so that it can work with implicit real*16 or more?
Powerstation is too old. Not every compiler supports real*16 even now. Consider to obtain a new compiler. I suggest to begin with gfortran, that does support quad precision for sure.
Also I am worried that with that implicit things there might be many other problems hidden. Consider also explicit typing for your variables and using implicit none.
What are the values in your file? integers and double precision floating point values? Then it seems very unlikely that the problem is caused by your not reading them into quad-precision real variables. Only rarely do calculations need quad-precision. Are you reading the integer values into integer variables and the floats into Fortran reals? As the others have written, implicit typing is the worst approach ... it is still part of Fortran only to support legacy code. Best practice is to use "implicit none" and explicitly type all of your variables. This will allow the compiler to catch mistakes such as typos in variable names. For more about variable typing see Fortran: integer*4 vs integer(4) vs integer(kind=4) and Extended double precision

Fortran 90 kind parameter

I am having trouble understanding Fortran 90's kind parameter. As far as I can tell, it does not determine the precision (i.e., float or double) of a variable, nor does it determine the type of a variable.
So, what does it determine and what exactly is it for?
The KIND of a variable is an integer label which tells the compiler which of its supported kinds it should use.
Beware that although it is common for the KIND parameter to be the same as the number of bytes stored in a variable of that KIND, it is not required by the Fortran standard.
That is, on a lot of systems,
REAl(KIND=4) :: xs ! 4 byte ieee float
REAl(KIND=8) :: xd ! 8 byte ieee float
REAl(KIND=16) :: xq ! 16 byte ieee float
but there may be compilers for example with:
REAL(KIND=1) :: XS ! 4 BYTE FLOAT
REAL(KIND=2) :: XD ! 8 BYTE FLOAT
REAL(KIND=3) :: XQ ! 16 BYTE FLOAT
Similarly for integer and logical types.
(If I went digging, I could probably find examples. Search the usenet group comp.lang.fortran for kind to find examples. The most informed discussion of Fortran occurs there, with some highly experienced people contributing.)
So, if you can't count on a particular kind value giving you the same data representation on different platforms, what do you do? That's what the intrinsic functions SELECTED_REAL_KIND and SELECTED_INT_KIND are for. Basically, you tell the function what sort of numbers you need to be able to represent, and it will return the kind you need to use.
I usually use these kinds, as they usually give me 4 byte and 8 byte reals:
!--! specific precisions, usually same as real and double precision
integer, parameter :: r6 = selected_real_kind(6)
integer, parameter :: r15 = selected_real_kind(15)
So I might subsequently declare a variable as:
real(kind=r15) :: xd
Note that this may cause problems where you use mixed language programs, and you need to absolutely specify the number of bytes that variables occupy. If you need to make sure, there are enquiry intrinsics that will tell you about each kind, from which you can deduce the memory footprint of a variable, its precision, exponent range and so on. Or, you can revert to the non-standard but commonplace real*4, real*8 etc declaration style.
When you start with a new compiler, it's worth looking at the compiler specific kind values so you know what you're dealing with. Search the net for kindfinder.f90 for a handy program that will tell you about the kinds available for a compiler.
I suggest using the Fortran 2008 and later; INT8, INT16, INT32, INT64, REAL32, REAL64, REAL128. This is done by calling ISO_FORTRAN_ENV in Fortran 2003 and later. Kind parameters provides inconsistent way to ensure you always get the appropriate number of bit representation
Just expanding the other (very good) answers, specially Andrej Panjkov's answer:
The KIND of a variable is an integer label which tells the compiler
which of its supported kinds it should use.
Exactly. Even though, for all the numeric intrinsic types, the KIND parameter is used to specify the "model for the representation and behavior of numbers on a processor" (words from the Section 16.5 of the standard), that in practice means their bit model, that's not the only thing a KIND parameter may represent.
A KIND parameter for a type is any variation in its nature, model or behavior that is avaliable for the programmer to choose at compile time. For example, for the intrinsic character type, the kind parameter represents the character sets avaliable on the processor (ASCII, UCS-4,...).
You can even define your own model/behaviour variations on you defined Derived Types (from Fortran 2003 afterwards). You can create a Transform Matrix type and have a version with KIND=2 for 2D space (in which the underlying array would be 3x3) and KIND=3 for 3D space (with a 4x4 underlying array). Just remember that there is no automatic kind conversion for non-intrinsic types.
From the Portland Group Fortran Reference, the KIND parameter "specifies a precision for intrinsic data types." Thus, in the declaration
real(kind=4) :: float32
real(kind=8) :: float64
the variable float64 declared as an 8-byte real (the old Fortran DOUBLE PRECISION) and the variable float32 is declared as a 4-byte real (the old Fortran REAL).
This is nice because it allows you to fix the precision for your variables independent of the compiler and machine you are running on. If you are running a computation that requires more precision that the traditional IEEE-single-precision real (which, if you're taking a numerical analysis class, is very probable), but declare your variable as real :: myVar, you'll be fine if the compiler is set to default all real values to double-precision, but changing the compiler options or moving your code to a different machine with different default sizes for real and integer variables will lead to some possibly nasty surprises (e.g. your iterative matrix solver blows up).
Fortran also includes some functions that will help pick a KIND parameter to be what you need - SELECTED_INT_KIND and SELECTED_REAL_KIND - but if you are just learning I wouldn't worry about those at this point.
Since you mentioned that you're learning Fortran as part of a class, you should also see this question on Fortran resources and maybe look at the reference manuals from the compiler suite that you are using (e.g. Portland Group or Intel) - these are usually freely available.
One of the uses of kind could be to make sure that for different machine or OS, they truly use the same precision and the result should be the same. So the code is portable. E.g.,
integer, parameter :: r8 = selected_real_kind(15,9)
real(kind=r8) :: a
Now this variable a is always r8 type, which is a true "double precision" (so it occupies 64 bits of memory on the electronic computer), no matter what machine/OS the code is running on.
Also, therefore you can write things like,
a = 1.0_r8
and this _r8 make sure that 1.0 is converted to r8 type.
To summarize other answers: the kind parameter specifies storage size (and thus indirectly, the precision) for intrinsic data types, such as integer and real.
However, the recommended way now is NOT to specify the kind value of variables in source code, instead, use compiler options to specify the precision we want. For example, we write in the code: real :: abc and then compile the code by using the compiling option -fdefault-real-8 (for gfortran) to specify a 8 byte float number. For ifort, the corresponding option is -r8.
Update:
It seems Fortran experts here strongly object to the recommended way stated above. In spite of this, I still think the above way is a good practice that helps reduce the chance of introducing bugs in Fortran codes because it guarantees that you are using the same kind-value throughout your program (the chance that you do need use different kind-values in different parts of a code is rare) and thus avoids the frequently encountered bugs of kind-value mismatch between dummy and actual arguments in a function call.