Scope and dealing with subroutines with many inputs - fortran

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.

Related

Is the storage of COMPLEX in fortran guaranteed to be two REALs?

Many FFT algorithms take advantage of complex numbers stored with alternating real and imaginary part in the array. By creating a COMPLEX array and passing it to a FFT routine, is it guaranteed that it can be cast to a REAL array (of twice the size) with alternating real and imaginary components?
subroutine fft (data, n, isign)
dimension data(2*n)
do 1 i=1,2*n,2
data(i) = ..
data(i+1) = ..
1 continue
return
end
...
complex s(n)
call fft (s, n, 1)
...
(and, btw, is dimension data(2*n) the same as saying it is a REAL?)
I'm only writing this answer because experience has taught me that as soon as I do write this sort of answer one of the real Fortran experts hereabouts piles in to correct me.
I don't think that the current standard, nor any of its predecessors, states explicitly that a complex is to be implemented as two neighbouring-in-memory reals. However, I think that this implementation is a necessary consequence of the standard's definitions of equivalence and of common. I don't think I have ever encountered an implementation in which a complex was not implemented as a pair of reals.
The standard does guarantee, though that a complex can be converted into a pair of reals. So, given some definitions:
complex :: z
complex, dimension(4) :: zarr
real :: r1, r2
real, dimension(8) :: rarr
the following will do what you might expect
r1 = real(z)
r2 = aimag(z)
Both those functions are elemental and here comes a wrinkle:
real(zarr)
returns a 4-element array of reals, as does
aimag(zarr)
while
[real(zarr), aimag(zarr)]
is an 8-element array of reals with the real parts of zarr followed by the complex parts. Perhaps
rarr(1:8:2) = real(zarr)
rarr(2:8:2) = aimag(zarr)
will be OK for you. I'm not sure of any neater way to do this though.
Alexander's not the only one able to quote the standard ! The part he quotes left me wondering about non-default complex scalars. So I read on, and I think that para 6 of the section he points us towards is germane
a nonpointer scalar object of any type not specified in items (1)-(5)
occupies a single unspecified storage unit that is different for each
case and each set of type parameter values, and that is different from
the unspecified storage units of item (4),
I don't think that this has any impact at all on any of the answers here.
To append to Mark's answer this is indeed stated in the Standard: Clause 16.5.3.2 "Storage sequence":
2 In a storage association context
[...]
(2) a nonpointer scalar object that is double precision real or
default complex occupies two contiguous numeric storage units,
emphasis mine.
As for storage association context: Clause 16.5.3.1 "General" reads
1 Storage sequences are used to describe relationships that exist
among variables, common blocks, and result variables. Storage
association is the association of two or more data objects that occurs
when two or more storage sequences share or are aligned with one or
more storage units.
So this occurs for common blocks, explicit equivalence, and result variables. As Mark's said, there is no explicit statement for the general case.
My guess is, that it is most convenient to follow this always to ensure compatibility.
Thanks to IanH to pointing this out!
No, as far as I know.
You can have storage association between a real single precision array and a complex single precision array by EQUIVALENCE, COMMON, and ENTRY statement.
But in general you cannot pass a complex array to a subroutine that expects a real array.

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.

passing a noncontiguous array section in Fortran

I am using intel fortran compiler and intel mkl for a performance check. I am passing some array sections to Fortran 77 interface with calls like
call dgemm( transa,transb,sz_s,P,P,&
a, Ts_tilde,&
sz_s,R_alpha,P,b,tr(:sz_s,:),sz_s)
as evident, tr(:sz_s,:) is not contiguous in memory and the Fortran 77 interface is expecting a continuous block and creating a temporary for this.
What I was wondering is that will there be a difference if I create my temporary array explicitly in the code for tr and copy information from that temporary back and forth before and after the operation, or will that be the same as compiler itself creating the temporary from a performance point of view? I guess compiler will always be more efficient.
And of course any more suggestions to eliminate these temporaries are welcome.
One more point, If I use the Fortran 95 interface of the library apparently, with a similar call on a simpler test problem, no warning is issued for the creation of a temporary. Then I read in the manual of mkl that Fortran 95 interface uses assumed shape arrays which explains why temporaries are not created.
However at that point, I can not seem to use some support functions like timing routines.
Namely, intel mkl has some timing support functions but if I use them with the mkl_service routine like below then I get 'This name does not have a type, and must have an explicit type' error for dsecnd. Any idea for this problem is also welcome. A simple example for this is given as
program dgemm95_test
! some modules for Fortran 95 interface
use mkl_service
use mkl95_precision
use mkl95_blas
!
implicit none
!
double precision, dimension(4,3) :: a
double precision, dimension(6,4) :: b
double precision, dimension(5,5) :: r ! result array
double precision, dimension(3,2) :: dummy_b
!
character(len=1) :: transa
character(len=1) :: transb
!
double precision :: alpha, beta, t1, t2, t
integer :: sz1, sz2
! initialize some variables
alpha = 1.0
beta = 0.0
a = 2.3
b = 4.5
r = 0.0
transa = 'n'
transb = 'n'
dummy_b = 0.0
! Fortran 95 interface
t1 = dsecnd()
call gemm( a, b(4:6,1:3:2), r(2:5,3:4),&
transa, transb, alpha, beta )
t2 = dsecnd()
!
write(*,*) r
dummy_b = r(2:4,4:5)
!
end program dgemm95_test
The temporary is absolutely necessary when passing your array section to an assumed size array dummy argument, which the old routines use, because the array section is not contiguous in memory.
You can of course make your own temporary arrays. Whether it will be faster or not depends on many factors. Among others the important thing is whether the temporary is allocated on the stack or on the heap. The Intel Fortran compiler is capable of both, there are compiler switches to control the behavior (-heap-arrays n) and it can depend on the array size. Stack allocation is much faster and it is usually the default. Automatic arrays, which you might use for your own temporary are allocated on the stack by default too. Be careful with large arrays on the stack, you can easily overflow it and cause a crash.
I would suggest you to make a performance test and use the simpler variant if it is not too slow. Probably it will be the Fortran 95 interface, but you should measure the times, really.
As for the timing, MKL manual page for second()/dsecnd() states you must includemkl_lapack.fi and doesn't speak about any Fortran95 interface. You could get away declaring it external double precision too, but I would use the include. Or use system_clock() as a portable standard Fortran 95.

FFTW: Trouble with real to complex and complex to real 2D tranfsorms

As the title states I'm using FFTW (version 3.2.2) with Fortran 90/95 to perform a 2D FFT of real data (actually a field of random numbers). I think the forward step is working (at least I am getting some ouput). However I wanted to check everything by doing the IFFT to see if I can re-construct the original input. Unfortunately when I call the complex to real routine, nothing happens and I obtain no error output, so I'm a bit confused. Here are some code snippets:
implicit none
include "fftw3.f"
! - im=501, jm=401, and lm=60
real*8 :: u(im,jm,lm),recov(im,jm,lm)
complex*8 :: cu(1+im/2,jm)
integer*8 :: planf,planb
real*8 :: dv
! - Generate array of random numbers
dv=4.0
call random_number(u)
u=u*dv
recov=0.0
k=30
! - Forward step (FFT)
call dfftw_plan_dft_r2c_2d(planf,im,jm,u(:,:,k),cu,FFTW_ESTIMATE)
call dfftw_execute_dft_r2c(planf,u(:,:,k),cu)
call dfftw_destroy_plan(planf)
! - Backward step (IFFT)
call dfftw_plan_dft_c2r_2d(planb,im,jm,cu,recov(:,:,k),FFTW_ESTIMATE)
call dfftw_execute_dft_c2r(planb,cu,recov(:,:,k))
call dfftw_destroy_plan(planb)
The above forward step seems to work (r2c) but the backward step does not seem to work. I checked this by differencing the u and recov arrays - which ended up not being zero. Additionally the max and min values of the recov array were both zero, which seems to indicate that nothing was changed.
I've looked around the FFTW documentation and based my implementation on the following page http://www.fftw.org/fftw3_doc/Fortran-Examples.html#Fortran-Examples . I am wondering if the problem is related to indexing, at least that's the direction I am leaning. Anyway, if any one could offer some help, that would be wonderful!
Thanks!
Not sure if this is the root of all troubles here, but the way you declare variables may be the culprit.
For most compilers (this is apparently not even a standard), Complex*8 is an old syntax for single precision: the complex variable occupies a total of 8 bytes, shared between the real and the imaginary part (4+4 bytes).
[Edit 1 following Vladimir F comment to my answer, see his link for details:] In my experience (i.e. the systems/compiler I ever used), Complex(Kind=8) corresponds to the declaration of a double precision complex number (a real and an imaginary part, both of which occupy 8 bytes).
On any system/compiler, Complex(Kind=Kind(0.d0)) should declare a double precision complex.
In short, your complex array does not have the right size. Replace occurences of Real*8 and Complex*8 by Real(kind=8) and Complex(Kind=8) (or Complex(Kind=kind(0.d0)) for a better portability), respectively.

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.