Author/s: Ramiro Checa-Garcia
Language: en | Translations:
computing
fortran

This notes were possible by reading from several sources, but the book Introduction to Programming with Fortran 1 was specifically useful because its large set of examples and progressive definitions. My first approach to Fortran 90 relies on the manual Physique Numérique2 that I recommend to those people interested in an introduction to Computational Physics based in Fortran.

General information

Fortran is one of the oldest computer programming languages that is still alive (together with Lisp). It is not a main language, but it has its niche in scientific computing applications. There are several blog entries that a I think useful to understand recent updates in the language itself. First in github j3-fortran there is a list of proposals that are related, as far as I understood, with LFortran new compiler.

Other important source of updates of fortran comunity is centralized in the fortran-lang github group. There you have a webpage fortran-lag.org where you can find news and information of the related projects. From them I highlight two: the fortran-package-manager fpm and the standard-lib. The last one relies on few python libraries to create an interesting tool.

For further information you can read two summaries at resurrecting-fortran and 1st-year of fortran-lang.

Useful Tools

Name Goal Licence Docs Link
findent Beautify f90, f2003 code Open-Source info sourceforge
tags (ctags) Syntax higlight Open-Source info sourceforge
f2c Fortran77 to C translator Open-Source info code
fortran-language-server support for editors MIT info github
fntcheck code checker F77
gdb gnu debugger GPL
fpm package manager MIT info github

IDE (Integrated Develpment Environments)

Here there is a list of text editors that I have tested myself. My main editor has been vim or neovim, now I am learning emacs (doom-emacs in particular). From time to time I use Geany which works well for many projects. For very large projects it might be worth to check Eclipse and Code-Blocks, as they have specific features of fortran. My recommendation if you are beginner is to try emacs or neovim.

Name Kind Licence Docs Link
Geany General IDE Open-Source
Code-Blocks Support Fortran and C Open-Source
Eclipse+Photran Fortran in Eclipse Open-Source
Kate / Gedit general IDE Open-Source
Atom general IDE (plugins) Open-Source
Emacs Fortran modes (f77 & f90) Open-Source
Visual Studio general IDE (plugins) Open-Source
Vim/Neovim with vim-fortran plugin Open-Source
kakoune Open-Source

Compilers (here only open-source)

There are several compilers, here I list only those that are open-source. I use mostly gfortran although it is generaly consider that the intel fortran is a bit faster.

Name Kind Licence Docs Link
gfortran GCC Open-Source info web
LFortran LLVM Open-Source web
Flang LLVM Open-Source web

Terminology

Fortran Arrays

  • explicit-shape array: declared with explicit values for the bounds in each dimension of the array. For this we can have automatic arrays, when the array is a local variable, and adjustable array when it is a dummy argument to a subprogram or procedure.
  • assumed-shape array: it is a non-pointer(!) dummy argument array that takes its shape from the associated actual argument array (by actual I mean the array that is introduced or demanded by the main program when it is called the subprogram or procedure). It is interesting to combine this approach with the size() instrinc procedure that gives the actual size of an array. We then can obtain within the procedure the size of the array and use this integer value inside the subprogram. For example to allocate an intent(out) array with the correct dimensions.
  • deferred-shape array: is an allocatable array (it has the ALLOCATABLE attribute and a specified rank but their bounds are set by allocation or argument association) or array pointer.
  • automatic array: it is explicit-shape and local. It is usually in subprograms and the bounds are set when the subprogram is called

Note here that how the arrays are implemented and defined in a specific programming language is crucial, as it is the main basic piece used to build all the scientific computations. It is illustrative to compare the evolution of the several arrays on the different languages: Fortran, Python, C. In particular, the several libraries on Haskell due to the central role that the type system has in this functional programming language.

Few Examples

An example with a subprogram (a subroutine) with arguments x and n will be:

subroutine example(x , n)
implicit none
integer     , intent(in)                     :: n
real        , intent(in)    , dimension(1:n) :: x

Here x is a dummy argument declared with specific bounds therefore it is a explicit-shape dummy array. However we could use an assumed-shape dummy array because in Fortran 90 and later versions the actual array size and the associated dummy arguments have the same rank and the same size in each dimension. In this situation a different approach will be:

  program example_main

  implicit none
  integer                         :: n
  real, allocatable, dimension(:) :: a

  ! The interface part is optional and not mandatory  
  ! it is useful when we have external subprograms
  ! and we can help the compiler to a full consistence
  ! checking. It is recomended its use.

  interface
     subroutine example(x)
        implicit none
        integer                           :: m
        real   , intent(in), dimension(:) :: x
    end subroutine example
  end interface

  ! n can be read from a file for example

  read *,n
  allocate(x(1:n))

  CALL example(x)

  end example_main


  subroutine example(x)
  implicit none
  integer                                    :: n
  real        , intent(in)    , dimension(:) :: x

  n = size(x)

Procedures in Fortran

They are very important for break the code in smaller problems, to don't repeat code within a program, to allow a better testing strategy.

In general the procedures communicate with the main program or other procedure by the arguments, inside the procedure they are named dummy arguments.Because Fortran is an strongly type code, we have to define the type of each argument both in the main program and in the procedures and they have to be consistent (this is for instance ensured by the definition of an interface).

Inside the procedures, specifically in the subroutines, we have the possibility of define if the dummy argument is an input, an output or both, by the intent sentence in the type definition block at the beginning of the sentence. The internal local variables are simple not included in the list of arguments of the procedure and they are destroyed once the procedure end.

The interface block is mandatory in several cases:

  1. A procedure with optional or keywords arguments
  2. Function returning an array or a pointer
  3. Procedure with assumed-shape dummy arguments
  4. Procedure with dummy arguments with pointer or target attribute
  5. Procedure generic (this allow overloading)
  6. Procedure defining a user operator
  7. Procedure with a user defined assignment

Functions

Subroutines

A very interesting case is when the subroutine is including a procedure as argument this means that we have to define an interface for the function that is consistent with the actual procedure argument

subroutine my_own(a, ext_sub, b, c, d)
implicit none
real, intent(in),  dimension(:) :: a
real, intent(out), dimension(:) :: b
integer                         :: c,d

interface 
    subroutine ext_sub(a,b,c)
    implicit none
    real, intent(in),  dimension(:) :: a
    real, intent(out), dimension(:) :: b
    integer, intent(inout)          :: c
    real                            :: parm1, parm2
    end subroutine ext_sub
end interface

! now we have operations including call ext_sub(a,b,c) and using the arguments b and c 
! ..

end subroutine my_own

In this situation we have to include information on a main program using this subroutine as

program main
implicit none
real     :: parmx, parmy
integer  :: i,j,k
real, allocatable, dimension(:)  :: x,y,z

interface
    subroutine my_own()

    interface
        subroutine ext_sub()


        end subroutine ext_sub
    end interface
    end subroutine my_own
end interface

interface
    subroutine ext_sub1()

    end subroutine ext_sub1
end interface
interface
    subroutine ext_sub2()

    end subroutine ext_sub2()
end interface

Pointers

In general all the most common multi-dimensional data types are static, which means that the size has to be clearly defined before any possible operation with the them. In Fortran as commented in my previous Fortran Notes there are several "kind" of arrays concerning how it is determined the shape, but even with allocated arrays its shape has to be defined on execution time. Pointers aims to be a flexible tool when the problems to be solved are more complex or not totally defined a-priori. The general idea is that a pointer can be associated to the values of another variable, this association can be changed during runtime, but also the pointer can "point" to a "target" that is a sub-array for another array-variable. Alse these kind of associations give to pointers a lot of flexibility to the programer. The pointers are not present in Fortran 77.

Derived Types

Other tool not present in Fortran 77 are the derived types. The provide a similar functionality to the "objects" that we can find in other languages, but it is possible just to consider them a kind of encapsulation of several data types on a single entity.

Examples

subroutine date_type(dtime)
    implicit none

    type date_time
      integer :: year
      integer :: month
      integer :: day
      integer :: hour
      integer :: minute
      real(8) :: second
    end type date

    type (date_time), intent(out) :: dtime

    dtime%year = 2016
    dtime%month = 1
    dtime%day = 21
    dtime%hour = 11
    dtime%minute = 15
    dtime%second = 20.345

end subroutine

In this subroutine is defined a typical date and time derived type. We can see that in the object dtime is included all the information. We can access to the different date-time parts simply as dtime%day, dtime%time etc... but also we can potentially define an operation like: dsum(dtime1, dtime2) that will give a new date_time derived type, or even override the intrinsic sum '+' to deal with date_time types.

Combining C and Fortran

Common terminology

The global framework to call methods/functions from one language in other is named: foreign function interface (FFI), and the process named binding. Nowadays, this is a common procedure to use libraries that we need but are not yet developed for our preferred language.

The interoperability is possible in Fortran 2003 as it incorporates an specific module called ISO_C_BINDING that ensures a correct use of the C intrinsic types. Even more, we can have a interoperability of derived types,

use iso_c_binding
...
type, bind(c) :: my_own_type
    integer (c_init) :: a,b,c
    real (c_float)   :: o,p
end type my_own_type
...

by using the above code we can inter-operate with a typical C code,

typedef struct {
   int i,j,k;
   float  r,s;
} my_c_type;

However, we can also have a procedure inter-operations. For example in Fortran we can make,

use iso_c_binding
...
function func(a,b,c,d) bind(c, name='c_func')
...

This feature of Fortran 2003 is useful not only to like between C and Fortran. Other quite common case is a language that can talk with C (Haskell, Go, Rust, Julia ...), so they can talk with Fortran if we are able to provide a wrapper based on ISO_C_BINDING in such way that the other language thinks that is talking to a C procedure/code.


  1. Introduction to Programming with Fortran, Ian Chivers and Jane Sleightholme, Springer 2006. 

  2. Physique Numérique, Ph. Depondt, INSP and CNRS Université Pierre et Marie Curie, 2006.