Fortran 90 logical kind mismatch - fortran

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.

Related

Reinterpret a Fortran array as bytes

I would like to interpret a Fortran (real*8, say) array as an array of bytes, so that it can be sent to a function to process things on the byte level. What's a simple (preferably no-copy) way to accomplish this?
First, it is not clear what is a function working on byte level. Does it use Fortran characters? Or 1-byte integers? They are different beasts in Fortran.
You could try to lie about the signature of your function and just pass the array as it is. Likely to work, not strictly standard conforming.
Transfer() is the best modern tool for similar purposes, but it may indeed involve temporaries.
If the size of the array is fixed (it is not allocatable or pointer or dummy argument) you could use equivalence which is quite similar to union in C.
But you must be careful about what is allowed, this is a notoriously dodgy area. Even the C union rules differ from the C++ rules. Fortran equivalence has its own rules and more strict, I am afraid. Type punning is not allowed, but a lot of code in the wild does it.
Doing tricks with C pointers and pointing to the same array from different pointers with different types is definitely not standard conforming and may give you expected results in some cases and wrong results in others (undefined behaviour as they call it in C and C++).
A "NO_COPY" way...but relies on DEC extensions:
USE ISO_C_BINDING
IMPLICIT NONE
UNION
MAP
REAL(KIND=C_DOUBLE) , DIMENSION(N) :: R8_Data
END MAP
MAP
BTYE , DIMENSION(N*8) :: B_Data
END MAP
MAP
CHARACTER(LEN=1) , DIMENSION(N*8) :: C_Data
END MAP
MAP
INTEGER(KIND=C_Int16_T), DIMENSION(N*4) :: I2_Data
END MAP
MAP
INTEGER(KIND=C_Int32_T), DIMENSION(N*2) :: I4_Data
END MAP
END UNION
#Valdimir equivalence also works if one does not have access to the DEC extensions.
There is a slated upgrade to gfortran to add in the MAP and UNION DEC extensions, so in time it will be there too.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56226
My appreciation of the difference is back on track...
One can use UNION/MAP inside of a structure. Outside a structure/TYPE then EQUIVALENCE does all one needs.
So As Vladimir mentioned this also is a "no copy"...
REAL(KIND=C_DOUBLE) , DIMENSION(N) :: R8_Data
BTYE , DIMENSION(N*8) :: B_Data
CHARACTER(LEN=1) , DIMENSION(N*8) :: C_Data
INTEGER(KIND=C_Int16_T), DIMENSION(N*4) :: I2_Data
INTEGER(KIND=C_Int32_T), DIMENSION(N*2) :: I4_Data
EQUIVALENCE(R8_Data, I4_Data)
It is almost more dangerous than it is worth, unless one has a specific problem.

Undefined components of a derived type in Fortran

This is more a software design question than a technical problem.
I planned to use a derived type to define atomic configurations. These might have a number of properties, but not every type of configuration would have them all defined.
Here's my definition at the moment:
type config
double precision :: potential_energy
double precision :: free_energy
double precision, dimension(:), allocatable :: coords
integer :: config_type
end type config
So, in this example, we may or may not define the free energy (because it's expensive to calculate). Is it safe to still use this derived type, which would be a superset of sensible cases I can think of? Should I set some sort of default values, which mean undefined (like Python None or a null pointer)?
I know about the extends F2003 feature, but I can't guarantee that all of our compilers will be F2003-compliant. Is there another better way to do this?
Formally, operations that require the value of the object as a whole when one of its components are undefined, are prohibited (see 16.6.1p4 of the F2008 standard).
Practically you may not run into issues, but it is certainly conceivable that a compiler with appropriate debugging support might flag the undefined nature of the component when operations that require the entire value of the derived type object are carried out.
High Performance Mark's suggestion is a workaround for that, because a derived type scalar still has an "overall" value even if one of its allocatable components is not allocated (see 4.5.8). This suggestion might be useful in cases where the component is heavy in terms of memory use or similar.
But a single double precision component isn't particularly heavy - depending on the platform the descriptor for an allocatable scalar component may be of similar size. An even simpler workaround is to just give the component an arbitrary value. You could even use default initialization to do just that.
(Presumably you have some independent way of indicating whether that component contains a useful value.)
These days Fortran comprehends the concept of allocatable scalars. Like this:
type config
double precision :: potential_energy
double precision, allocatable :: free_energy
double precision, dimension(:), allocatable :: coords
integer :: config_type
end type config
If, however, you can't rely on having a Fortran 2003 compiler available this won't work. But such compilers (or rather versions) are becoming very scarce indeed.
But do go the whole hog, and drop double precision in favour of real(real64) or some other 21st century way of specifying the kind of real numbers. Using the predefined, and standard, constant real64 requires the inclusion of use iso_fortran_env in the scoping unit.

Calling function with configurable real precision

The goal:
Have a function work with configurable working precision.
When I try this:
program vierkantsvergelijking
implicit none
integer, parameter :: dp = kind(0.d0)
integer, parameter :: sp = kind(0.0)
print *, algoritme1(-5771.,2.,dp)
contains
function algoritme1(b,c,wp) result( solution)
integer :: wp ! working precision
real(kind=wp) :: b,c,D
real(kind=wp), dimension(2) :: solution
D = sqrt((b/2)**2 - c)
solution(1) = -b/2 + D
solution(2) = -b/2 - D
end function algoritme1
end program
I get:
Error: Type mismatch in argument 'b' at (1); passed REAL(4) to UNKNOWN
Why is this not working and how can I achieve my goal?
Yes, or rather no, that's not going to work, not no how. The Intel Fortran compiler complains, about this line:
real(kind=wp) :: b,c,D
that
A kind type parameter must be a compile-time constant. [WP]
It makes the same complaint about real(kind=wp), dimension(2) :: solution too. This is a deep-rooted feature of Fortran.
To do what you want you will have to define a generic interface, along these lines
interface algoritme1
procedure :: algoritme1_sp, algoritme1_dp
end interface
and write the code for both those procedures. The compiler can then determine which one is called by the function signature; presumably one would have sp arguments, the other dp arguments.
You might think that this all means that Fortran doesn't do generic procedures, I'll leave that question to the sophists and language nit-pickers. It would be worth your while to search around for generic programming in Fortran; even here on SO there are tricks and tips on how to better avoid writing multiple implementations of what the programmer believes (at odds with the compiler) to be the 'same' code.

Convert logical type to double in Fortran

I'm looking for a bulletproof way of converting logical type variables to real type that will work in both ifort and gfortran. The following works in ifort, but not in gfortran:
logical :: a
real :: b
a = .true.
b = dble(a)
The error thrown in gfortran is
b = dble(a)
1
Error: 'a' argument of 'dble' intrinsic at (1) must be a numeric type
Obviously, .true. should map to 1.d0, and .false. to 0.d0. What's the best way of doing this?
In addition to writing a function to handle this, you could also directly use the intrinsic merge function: b = merge(1.d0, 0.d0, a). Or you could write a defined assignment subroutine that does this, so that you can just type b = a.
I am not sure if there is an intrinsic tool that does this. I do not know why ifort accepts this, and my guess would be that it is a compiler specific functionality.
Edit: As pointed out in https://stackoverflow.com/a/15057846/1624033 below, there is the intrinsic merge function which is exactly what is needed here.
an option to to this, specifically since you want this to be bullet proof, is to create your own function.
I have not tested this, but the following might work:
elemental pure double precision function logic2dbl(a)
logical, intent(in) :: a
if (a) then
logic2dbl = 1.d0
else
logic2dbl = 0.d0
end if
end function logic2dbl
Edit: I added elemental to the function declaration based on advice below. I also added pure to this function as it adds the extra ability to use this in parallel situations and it is good documentation. This however is just my opinion and it is not necessary.
In gfortran, I am using the TRANSFER intrinsic for that type of job.
Assuming a integer variable my_int then:
my_int = transfer(.false.,my_int)
the result of my_int is 0 as expected.
Just a note, TRANSFER(.true.,1) correctly returns the value of 1 with Gfortran and (incorrectly?) values of -1 with the current versions of Intel and Portland compilers. Interestingly, TRANSFER(-1,logical) returns TRUE with the latter two compilers while throws a syntax error with Gfortran.

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.