variable length array in derived type - fortran

I am mostly doing scientific programming in Python and do not have a whole lot of Fortran (90/95) experience. For one of my projects I want to define a derived type and overload a bunch of operators for that type. Critically, I'd like one of the variables of the derived type to an array of variable length; at least, I need two different lengths in different parts of the code. How can I best achieve this efficiently and avoiding code duplication?
My first approach was to use an allocatable array but that involved several allocate statements throughout the code including the overloaded operators. It also led to difficulties when using the code in an MPI application.
My current approach is two define a type of the same name in two separate modules and use one or the other in different parts of the code. The overloaded operators can be shared using a header file (mytype_operators.h in the example below).
module mod1
type mytype
real :: x1
real,dimension(1) :: x2
end type mytype
#include "mytype_operators.h"
end module mod1
module mod2
type mytype
real :: x1
real,dimension(10) :: x2
end type mytype
#include "mytype_operators.h"
end module mod2
Unfortunately, there is one module in the code with subroutines that I would like to use for both types. Currently I have two copies of that code; one with "use mod1", the other with "use mod2". Can I improve this and avoid the code duplication?

Your case is very suitable for using a Fortran feature introduced in the 2003 standard (and adopted much later by compilers) named parameterized derived types. First of all, you should check the compliance status of your compiler to know if it's fully supported.
This feature allows you to pass custom parameters when declaring or constructing a derived-type, so internal functionality will be adjusted accordingly. They are good for having different behaviour alternatives grouped in a single type name, possibly with considerable coding or storage differences. There are 2 types of parameters:
kind parameters behave much like the kind specifier of intrinsic types. Kind parameters of all variables must be known at compile time and are treated practically as constant values. The convenience is that you could change it easily (in code time) by altering just a value in the declaration or construction. This is commonly used for specializing the kind of components of intrinsic type.
len parameters behave much like the len specifier of intrinsic character type. You can define len parameters at compile time or runtime, and a len parameter of a variable cannot change unless you declared it allocatable. Moreover, you can have arguments with assumed len-parameters in procedures, and avoid code verbosity. This is commonly used as a "length" or "dimension" parameter for a derived type, because you can use them in the declaration of array bounds and character length.
In general, type parameters are used to mimic the functionality of intrinsic types in derived types, but you could also get "creative" and use it for other things, like the dimension-space of a transformation-matrix type; for a custom "union type" (like an enumeration); as the nature of a physical quantity in a "units of measurement" data-type (a real value annotated with "mass" unity is not directly compatible with a "temperature" one, but they can be handled pretty much the same way in the code); the "arity" of a tuple type...
module mod1
type :: mytype(n)
integer, len :: n
real :: x1
real, dimension(n) :: x2
end type mytype
contains
! your operations here...
end module mod1
And use it like this:
program test_pdt
use mod1
implicit none
type(mytype(10)) :: mt10
type(mytype(1)) :: mt1
integer :: i
mt10%x1 = 40.0
mt10%x2 = [(0.5 * i, i = 1, 10)]
mt1 = mytype(1)(20.0, [30.0])
call sub(mt10)
call sub1(mt1)
contains
subroutine sub(m)
! accepts values with any "n" parameter
type(mytype(*)) :: m
! you can also use them in declarations
integer, dimension(m%n + 1) :: y
type(mytype(m%n)) :: w
print *, m%n, w%n, size(y)
end
subroutine sub1(m)
type(mytype(1)) :: m ! only accepts values with n=1
print *, m%x1, m%x2, m%n
end
end
Warning:
This is feature, despite of having been announced many years ago, was just recently added to most compilers, and you should be aware that there are still some bugs in implementation. You should probably be fine with regular use, but I often face false syntax errors in some corner cases, and even ICE sometimes.

Related

Why don't I have to specify that the result of a fortran function is being passed by value to my C++ program?

I am learning about fortran C++ interoperability. In this case I was trying to write a 'wrapper' function (f_mult_wrapper) to interface between my 'pure' fortran function (f_mult) and C++. The function is defined in my C code as
double f_mult_by_wrapper(double i, double j);
and called like
double u=f_mult_by_wrapper(w,r);
I know I must specify that the input arguments in f_mult_wrapper are being passed by value from C, and that fortran usually passes by reference. But the compiler gives me an error when I try to specify that the result is being passed by value: A dummy argument name is required in this context. The code works together as written, but I don't exactly understand why.
module type_example
use :: iso_c_binding
function f_mult(i,j) result(k)
! use fortran intrinsic types
real:: i,j,k
k = i*j;
end function
function f_mult_wrapper(aw,bw) result(cw) bind(c,name="f_mult_by_wrapper");
real(c_double), VALUE :: aw ! use c binding types. passed by value
real(c_double), VALUE :: bw
real(c_double) :: cw
real :: a,b,c
a = aw
b = bw
c = cw
c = f_mult(a,b)
cw = c
end function
end module
Function results are simply not function arguments/parameters. They are passed differently and the exact mechanism depends on the ABI (calling conventions) and their type.
In some ABIs, results are passed on the stack. In other ABIs, they are passed using registers. That concerns simple types that can actually fit into registers. More complex objects may be passed using pointers (on the stack or in registers).
The by value/by reference distinction distinguishes, whether the value of the argument is passed on the stack/in the register directly, or indirectly using a pointer. It does not concern function return values.
There are simpler functions that can be C-interoperable and other Fortran functions that cannot be interoperable, e.g. functions returning arrays. Such Fortran-specific functions are implemented in a compiler-specific way. Often, a hidden argument is being passed. Such a hidden argument may contain a pointer and may be passed using a register or using the stack. The details are again dependent on the specific ABI.
For the calling conventions to the most common x86 architecture, see https://en.wikipedia.org/wiki/X86_calling_conventions There are several different variations for 32 bit and for 64 bit.

How do variable declarations within types work in Fortran?

I'm trying to learn Fortran, and I've found that there aren't very many tutorials out there (probably due to it being an old language). The ones I have found are vague and undescriptive, and as I've gone into more complex things it has become harder and harder to guess what said tutorials are saying.My current issue is with creating types. The tutorial contains examples such as:
module m_shapes
implicit none
private
public t_square
type :: t_square
real :: side
contains
procedure :: area ! procedure declaration
end type
contains
! Procedure definition
real function area(self) result(res)
class(t_square), intent(in) :: self
res = self%side**2
end function
end module m_shapes
This compiles fine, so I know it works.
When I try to do something similar like this:
program type_test
implicit none
type :: thingy(a)
real :: a
end type
end program
It doesn't compile with errors like "The component at (1) that appears in the type parameter list at (2) has neither the KIND nor LEN attribute"
The tutorial I found does not explain types well enough, and I've tried things like real,kind :: a = kind(0.0), but to no avail. Does anybody know what's wrong?
Thanks in advance.
You did not explain, what you actually want to do. Or your words are not nearly clear enough. We can tell you why your attempt produces the error, but I have no idea what you actually want to do.
Perhaps you just wanted
program type_test
implicit none
type :: thingy
real :: a
end type
end program
without the (a)? That declares a simple type with one component. But hard to guess if this is what you wanted and what you tried with the (a).
It does not declare any variable with that type. That is done using
type(thingy) :: var
The syntax
type :: thingy(a)
real :: a
end type
attempts to declare a parametrized derived type. These types can depend on a kind or length parameter. These parameters must be integers. If it is a kind parameter, it allows to declare variables of the type with varying values of these parameters. Then the kind of some components of the type (you know what kind is, right? Fortran 90 kind parameter ) get their kind according to the value of the parameter. If it is a length parameter, it allows the length of some array or string components of the derived type to be parametrized - set during the variable declaration.
These parameters that appear in the parenthesis must be integer components and must have the kind or len attribute.
For example
type :: param_type(k,l)
integer, kind :: k
integer, len :: l
real(kind=k), dimension(l) :: array
end type param_type
type(param_type(kind(1.), 10)) :: o_sp_10
type(param_type(kind(1.d0), 20)) :: o_dp_20
The values of the parameters are set during the declaration of those o_sp_10 and o_dp_20 objects. I do not want to go into more details.

Can Fortran PURE functions use global parameters?

It seems to me the what is called a pure function in Fortran is not considered pure enough for those who use functional programming. So here is my question. Suppose I have the following code:
MODULE basics
IMPLICIT NONE
INTEGER, PARAMETER :: dp = kind(1.0d0)
REAL(dp), PARAMETER :: PI=3.1415926535897932_dp
REAL(dp), PARAMETER :: earthEquatorialRadius=6378.137_dp
END MODULE basics
MODULE myFunctions
USE basics
IMPLICIT NONE
PURE REAL(dp) FUNCTION sphericalArc(angleInRadians)
REAL(dp),INTENT(IN) :: angleInRadians
sphericalArc= 2.0*PI*earthEquatorialRadius*angleInRadians
END FUNCTION sphericalArc
END MODULE myFunctions
The function sphericalArc has no side effects, so it's pure in that sense, but it uses global constants. It's true that the parameters PI and earthEquatorialRadius can be defined inside the function but this is undesirable since I would like to use these in other functions and subroutines. It's going to be even more tedious to make the dp type defined in each function or procedure.
So from Fortran's perspective is a function that uses global parameters defined outside of the function still considered pure and can be called from a do concurrent loop?
If a Fortran procedure (function or subroutine) has the pure prefix in its definition then it is a pure procedure in the sense that Fortran uses it. It can then be used in places where there is a restriction of purity. A procedure with prefix elemental and without the prefix impure is also pure.
To be allowed to be specified as pure, the procedure is subject to a number of constraints, but it is necessary for the compiler to diagnose any violation of these constraints when pure is given.
There is no constraint that a named constant from another module (or other scope) may not be referenced.
As motivation for purity in Fortran, the standard (F2008, Note 12.49) offers:
The above constraints are designed to guarantee that a pure procedure is free from side effects (modifications of data visible outside the procedure)
Referencing a named constant is not modification of data visible outside the procedure.
From this documentation it should be okay to use a global variable as long as it is a parameter (so the value does not change).
The execution_part and internal_subprogram_part of a pure procedure
cannot refer to a dummy argument with an INTENT(IN), a global variable
(or any object that is storage associated with one), or any subobject
thereof, in contexts that may cause its value to change: that is, in
contexts that produce side effects.

Fortran derived type in common: initialization?

I got troubles with this common:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
& REDVAR,MOCDER(2)
COMMON /REDCO1/ CTEXT
C
type(double_st) :: DPREC
INTEGER :: NITMA,INDIC,NBERR,NCAR,KMOTLU,REDVAR,MOCDER
CHARACTER(72) :: CTEXT
CHARACTER(4) :: CTEXT4
C
EQUIVALENCE (CTEXT,CTEXT4)
The double_st derived type is:
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
Trying to compile some code including this common, I get:
ifort:
./REDCOM.INC(1): error #6005: A derived type object in a COMMON block shall not have default initialization [DPREC]
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
----------------------^
gfortran:
REDCOM.INC:1.27:
Included at m_abaq4.f:90:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
1
Error: Derived type variable 'dprec' in COMMON at (1) may not have default initializer
Being not very familiar with Fortran, I don't understand what the problem is, or how to solve it (I tried googling with no success). If I use a REAL(8) instead of a double_st, everything works fine.
Could someone help me on this?
From the line
integer :: acc = -1
strip off the trailing
= -1
to leave
integer :: acc
recompile, and see what happens. The error message suggests that a program can't initialise a derived type component and use variables of that derived type in common statements. 'Initialize' is used in the Fortran standards to mean, precisely, the setting of a variable (or element) 's value in its declaration.
In my (draft) version of the Fortran 2008 standard constraint 506 on rule 503 prohibits initialization of components of variables of derived type used in common blocks. This prohibition doesn't seem to apply to initialization of variables of intrinsic types, hence the compiler's acceptance of the code when the variable is of type real(8).
As for using derived types in common blocks, that's mixed-paradigm programming if ever there was such a thing !
I'm saying much the same as in High Performance Mark's answer, but hopefully with a little more elaboration. After that answer's edit I actually diverge a little.
Having the type declaration
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
involves default initialization. That's the acc=1 part: see Fortran 2008 4.5.4.6. It isn't just the component that is default initialized but the whole type.
There is a constraint (C5105, in 5.7.2.1) which says that
If a common-block-object is of a derived type, the type shall have the BIND attribute or the SEQUENCE attribute and it shall have no default initialization.
This is what the compilers complain about. Using a real(kind(0d0)) (or real(8)) doesn't violate this constraint. Intrinsic types (such as that real) cannot have default initialization, but they can have explicit initialization (such as real :: hello = 1.). There are some restrictions on the use of an explicitly initialized object (such as C506 mentioned in the other answer), but the question isn't clear enough on that point for me to comment further.

FORTRAN implicit cast when argument association happens in procedures

I am using fortran for a while, but I didn't check the implicit cast issue when using subroutines in fortran.
For example
subroutine printa(a)
double precision :: a
...
endsubroutine printa
When I called the subroutine
call printa(1)
I saw error #6633: The type of the actual argument differs from the type of the dummy argument. [1]
I know it is because I use an integer instead of a double precision as an input parameter. But I just realized that there is no implicit cast when using subroutines.
If I want a subroutine which handles integer and double precision data, it seems I have to define 2 subroutines for doing these things. Is there a way to make the implicit cast happen (just like the function calling in c)? Or there is another way to make it?
Thanks.
It is fundamental in Fortran that reals (including different precisions) and integers are different and that you need different subroutines to handle them. If you want the convenience of having a single call, similar to Fortran intrinsics such as sin which are implicitly several different functions, you can write the several different procedures and then create a generic interface to select between them. Fortran will then select the correct actual procedure based on the actual arguments, to match the dummy arguments. Here is an example that does it by rank of the array argument: how to write wrapper for 'allocate'. It can also be done, as you wish, by type of the argument.
You can overload a subroutine name so that when the "wrong" type of argument is supplied it is converted to right type and used to call the subroutine, as shown below.
module foo
implicit none
interface printa
module procedure print_int,print_real
end interface printa
contains
!
subroutine print_real(x)
real, intent(in) :: x
print*,"number is ",x
end subroutine print_real
!
subroutine print_int(i)
integer, intent(in) :: i
call print_real(real(i))
end subroutine print_int
!
end module foo
program main
use foo, only: printa
implicit none
call printa(1)
call printa(1.0)
end program main
Output:
number is 1.
number is 1.