links from Programing Guide
We briefly explain hereafter features of Fortran90 that are used in BIEF. For more detailed explanations please refer to a proper Fortran 90 book, such as ref.[5].
Fortran 77 only recognises integers, real numbers, boolean and character strings.
Fortran 90 can be used to create structures. The following is an example of the creation of a point
type structure composed of two real numbers, and a circle
structure, composed of a centre
and a radius
:
TYPE point REAL :: x,y END TYPE TYPE circle TYPE(point) :: centre REAL :: radius END TYPE
It can be observed that the centre
is itself a structure of a type previously defined. Once the structure has been defined, objects of this type can be declared:
TYPE(circle) :: ROND
ROND
will be a circle
with its centre
and radius
; the latter are obtained thanks to the %“component selector”. Thus the radius of ROND will be the real ROND%radius
.
Pointers are well known in C language, but are notably different in Fortran 90. Pointers in Fortran 90 may be used as pointers as in C but also as aliases. Unlike C, they are not mere addresses pointing to somewhere in the computer memory. The target must be defined precisely, for example the line:
REAL, POINTER, DIMENSION(:) :: X
will define a pointer to a one-dimensional real array, and it will be impossible to have it pointing to an integer nor even to a 2-dimensional array. This pointer X
will have then to be pointed to a target by the statement:
X => Y
were Y
is an already existing one-dimensional real array. Then X
can be used as if it were Y
, it is thus an alias.
X
can be also directly allocated as a normal array by the statement:
ALLOCATE(X(100))
to have (for example) an array of 100 values. In this case X
and its target have the same name.
A well known problem in Fortran 90 is the fact that arrays of pointers do not exist. To overcome this problem, one has to create a new structure which is itself a pointer, and to declare an array of this new structure. This is done for blocks, which are lists of pointers to BIEF_OBJ
structures.
Modules are like INCLUDE
statements, but are more clever, so that INCLUDE
should now always be avoided. As a matter of fact, modules can be used to define global variables that will be accessible to all routines. With the following module:
MODULE EXAMPLE INTEGER EX1,EX2,EX3,EX4 END MODULE EXAMPLE
all the subroutines beginning with the statement USE EXAMPLE
will have access to the same numbers EX1
, … EX4
. With INCLUDE
statements, it would be only local variables without link to EX1
,… declared in other subroutines.
Modules will thus be used to define global variables that will be accessed via a USE
statement. If only one or several objects must be accessed, the ONLY
statement may be used, as in the example below:
USE EXAMPLE, ONLY : EX1,EX2
This will enable to avoid name conflicts and secures programming.
Modules are also used to store interfaces that will be shared between several subroutines (see paragraph below).
Interfaces are a mean given to the compiler to check arguments of subroutines even if it has no access to them. For example, the following interface:
INTERFACE LOGICAL FUNCTION EOF(LUNIT) INTEGER, INTENT(IN) :: LUNIT END FUNCTION END INTERFACE
says that function EOF
has one integer argument. INTENT(IN)
indicates that argument LUNIT
is not changed. Interfaces of all BIEF subroutines have been put in a single module called BIEF
. A USE BIEF
statement at the beginning of a subroutine will prompt the compiler to check the arguments and also do some optimisations in view of the INTENT
information (which can be IN
, OUT
, or INOUT
depending on the use of the argument). If a function is declared in an interface, it must not be declared as an EXTERNAL FUNCTION
.
New operations on structures could also be defined with the INTERFACE OPERATOR
statement. For example a sum of two vectors as stored in BIEF could be defined so that the line:
CALL OS('X=Y ',U,V,V,0.D0)
could be replaced by:
U=V
Such interface operators have not been done in version 6.0, because operations like U = A+B+C
would probably not be optimised and would trigger a number of unnecessary copies.
Subroutines may now have optional parameters. Thanks to this new feature, subroutines OS
and OSD
of previous releases have been grouped in a single one. Hereafter is given the interface of new subroutine OS
:
INTERFACE SUBROUTINE OS( OP, X , Y , Z , C , IOPT , INFINI , ZERO ) USE BIEF_DEF INTEGER, INTENT(IN), OPTIONAL :: IOPT DOUBLE PRECISION, INTENT(IN), OPTIONAL, INFINI, ZERO TYPE(BIEF_OBJ), INTENT(INOUT), OPTIONAL :: X TYPE(BIEF_OBJ), INTENT(IN), OPTIONAL :: Y,Z DOUBLE PRECISION, INTENT(IN), OPTIONAL :: C CHARACTER(LEN=8), INTENT(IN) :: OP END SUBROUTINE END INTERFACE
Subroutine OS
performs on structure X
the operation given in OP
, e.g.
CALL OS('X=0 ',X=TRA01)
or:
CALL OS('X=Y ',X=TAB1,Y=TAB2)
Parameters Y
,Z
and C
are used only for specific operations and otherwise are not necessary.
When a parameter is missing and to avoid ambiguity, the parameters must be named, hence the X=TRA01 in the example above.
Parameters IOPT
, INFINI
and ZERO
stem from the old subroutine OSD
and are used only when a division is implied in the operation asked, for example if ””“OP = 'X=Y/Z '”””. These 3
parameters are now optional. When they are present, it is better to name them as is done in the following line:
CALL OS('X=Y/Z ',U,V,W,0.D0,IOPT=2,INFINI=1.D0,ZERO=1.D-10)
The use of optional parameters will enable a better compatibility between different versions because it will be possible to add a new parameter as an optional one.
Optional arguments will be written between brackets [] in argument lists in the rest of the document.