Chapter 10. Fortran Language

The new implemention of the Fortran binding of PLplot takes full advantage of the ISO_C_BINDING feature of the Fortran 2003 standard, which is supported by all current compilers. The advantage of this approach is that the entire binding is now written in Fortran, so that there is only one library that calling programs need to link against. Furthermore, the binding defines overloaded routines for the case of either single- or double-precision arguments supplied by the calling programme regardless of the floating-point precision of the underlying C library. That makes this binding much easier to use than our previous implementation of the Fortran binding where calling routines were forced to use the same floating-point precision that was configured for the underlying PLplot C library.

Note: in this chapter Fortran stands for Fortran as defined by the Fortran 2003 standard. Older versions of PLplot supported FORTRAN 77, but the binding for this 40 years old version has been abandoned for quite a few years now. As we now use features from the Fortran 2003 standard, it is no longer appropriate to refer to the language as Fortran 95.

We illustrate the implementation of our Fortran binding using the plstring API as an example. The summary of the C API for that routine which best serves our purposes here is

void plstring( PLINT n, const PLFLT *x, const PLFLT *y, const char *string );

The arguments n, x, y, and string represent the number of times the string is plotted, the arrays of length n which contain the x, y values where that string is plotted, and the NULL-terminated C string that contains the ordinary (not wide) characters in the UTF-8 encoding of a unicode glyph to be plotted. The PLplot PLINT type is normally defined as the C fundamental type int32_t, and the PLplot PLFLT type is defined to be one of the two C fundamental types float or double depending on how the C PLplot library is configured.

Here is an example of one fairly typical Fortran call of plstring.

program test_plplot
    use plplot
    implicit none
    integer, parameter :: my_real  = kind(1.0)
    real(kind=my_real), dimension(6) :: x, y
    ...
    x = ...
    y = ...
    ...
    call plstring(x,y,"+")
    ...
end program test_plplot

where for this particular case x and y are arrays with 6 elements defined and the points are to be plotted using the ascii "+" symbol (although if you are using a unicode-aware PLplot device, then you can try many other unicode possibilities for the symbol such as the U+22C5 DOT OPERATOR, "⋅"). Note that our Fortran binding implementation below allows use of the kind(1.0d0) choice of my_real precision as well.

The plstring-relevant parts of the plplot module used above are

module plplot
    ...
    use plplot_single
    use plplot_double
    ...
end module plplot

The redacted part of the plplot module implements the interfaces to the PLplot C library routines that happen to have no floating-point arguments very similarly to the way that the plplot_single and plplot_double modules interface the PLplot C routines like plstring that do include floating-point arguments. The plstring-relevant parts of the plplot_single module are

module plplot_single
    ...
    integer, parameter :: wp = private_single
    ...
    interface plstring
        module procedure plstring_impl
    end interface plstring
    private :: plstring_impl
    ...
contains
    ...
    subroutine plstring_impl( x, y, string )

       real(kind=wp), dimension (:), intent(in) :: x, y
       character(len=*), intent(in) :: string

       integer(kind=private_plint) :: n_local

       interface
           subroutine interface_plstring( n, x, y, string ) bind(c,name='c_plstring')
               import :: private_plint, private_plflt
               implicit none
               integer(kind=private_plint), value, intent(in) :: n
               real(kind=private_plflt), dimension(*), intent(in) :: x, y
               character(len=1), dimension(*), intent(in) :: string
           end subroutine interface_plstring
       end interface

       n_local = size(x, kind=private_plint)
       if(n_local /= size(y, kind=private_plint) ) then
           write(error_unit,"(a)") "Plplot Fortran Warning: plstring: inconsistent sizes for x and y"
       end if

       call interface_plstring( n_local, real(x,kind=private_plflt), real(y,kind=private_plflt), &
           trim(string)//c_null_char )
    end subroutine plstring_impl
    ...
end module plplot_single

The plstring-relevant parts of the plplot_double module are defined identically (in fact that identicality is guaranteed by using the same included file to define the identical parts) except for

    integer, parameter :: wp = private_double

Here are some notes on the above implementation of our Fortran binding for plstring. The plplot_single and plplot_double modules implement two versions of the Fortran plstring subroutine which are identical except one subroutine has floating-point arguments with a kind value of wp = private_single = kind(1.0) and one subroutine has floating-point arguments with kind value of wp = private_double = kind(1.0d0). The result is the Fortran compiler automatically chooses the correct overloaded version of plstring that corresponds to the precision of the floating-point arguments used by the program (e.g., like test_plplot above) that is being compiled. The intrinsic function size() is used to determine the size of arrays and allows checking that their dimensions are consistent with each other when the C implementation uses a common size for the arrays as in the plstring case. (See also, bindings/fortran/README_array_sizes.) The intrinsic function real() is used to convert floating-point data between the type used by the calling routine and the type used by the underlying PLplot C library, and the intrinsic function int() (not used in the above example) is used for similarly converting integer data. The intrinsic function trim() and the ISO_C_BINDING parameter c_null_char are used to help convert a Fortran character string into a NULL-terminated C string. Also note the above interface block defining subroutine interface_plstring is the Fortran representation of the exact C API of plstring.

Here is a table summarizing how C data types correspond to Fortran data types in the arguments of functions defined by our Fortran binding. Consult the Fortran code in bindings/fortran/* for further details of how the conversion is done between our private Fortran types that are equivalent to the corresponding C types, and the public Fortran types that are available for Fortran function arguments in our Fortran binding. Note the my_flt kind value used in this table is not provided by our Fortran binding. Instead it merely indicates that the calling routine (e.g., the test_plplot example routine above) has the choice of either kind(1.0) or kind(1.0d0) for the kind values of the floating-point arguments of the PLplot functions defined by our Fortran binding.

C typePrivate Fortran typePublic Fortran type
PLFLTreal(kind=private_plflt)real(kind=my_flt)
PLFLT *real(kind=private_plflt), dimension(*)real(kind=my_flt), dimension(:)
PLFLT **type(c_ptr), dimension(*)real(kind=my_flt), dimension(:, :)
PLINTinteger(kind=private_plint)integer
PLINT *integer(kind=private_plint), dimension(*)integer, dimension(:)
PLBOOLinteger(kind=private_plbool)logical
char *character(len=1), dimension(*)character(len=*)

In C there are two ways to pass a variable --- by value (the default) or by reference (pointer), whereas in Fortran this difference is not visible in the call, only in the interface definition via the value attribute. Therefore when you see references in the documentation of our C API to either an ordinary argument or a pointer argument (e.g. *data), you simply use an ordinary Fortran variable or array name. The new Fortran binding automatically takes care of any conversion that may be necessary.

In sum, the plstring example above illustrates the way our Fortran binding makes the PLplot C API conveniently accessible from Fortran while letting the C binding and overloading features of the Fortran compiler hide the complexities of the name mangling that occurs.

Users should be aware that there are a few cases with our new Fortran binding where we provide double-precision floating-point entities but no equivalent single-precision floating-point alternative.

Users should be aware that the new Fortran binding for PLplot enforces the following interfacing rules:

For more information on calling PLplot from Fortran, please consult the example Fortran programs in examples/fortran that are distributed with PLplot. For more information on building your own PLplot-related Fortran routines, please consult either the traditional (Makefile + pkg-config) or CMake-based build systems that are created as part of the install step for our Fortran (and other language) examples.