Determining variable type in Fortran

14,875

Solution 1

Well you might be able to do what you want if you mess about with the KIND intrinsic and POINTERs, but if you are only concerned with the signature of functions and subroutines, leave it to Fortran. If you define

function calc8(arg1)
    real(8), intent(in) :: arg1
    ...

and

function calc4(arg1)
    real(4), intent(in) :: arg1
    ...

in a module, and declare an interface like this

interface calc
    module procedure calc8
    module procedure calc4
end interface

(Warning, I haven't checked the syntax in detail, that's your responsibility.)

then Fortran will match the call to the right version of the function. Sure, you have to write both versions of the function, but that's really the Fortran 95 way of doing it. This can be quite tedious, I tend to write a generic version and run a sed script to specialise it. It's a bit of a kludge but it works.

If the code of the function is identical apart from the kind of the arguments I sometimes write the function for real(8) (or whatever) and write a version for real(4) which calls the real(8) version wrapped in type conversions.

In Fortran 2003 there are improved ways of defining polymorphic and generic functions, but I haven't really got my head around them yet.

Solution 2

Yes, there are two ways.

The first way does requires you to write separate functions or subroutines for each variable type, but you don't have to call different functions. This may or may not be close enough to what you want. You write the separate routines, then to write an interface to create a generic function or subroutine wrapping these specific subroutines. You don't have to pass the variable type, or do anything special in your call -- it is all done via the declaration and automatically by the compiler from the variable itself, as long as the variables are different enough that the compiler can distinguish them (there are rules about what is required). This is similar to how intrinsic functions work -- you can call sin with a real argument, a double precision real argument or a complex argument and the compiler calls the correct actual function and returns the matching result. High Performance Mark sketched a solution along these lines. For another question, I posted a working example, where the distinguishing feature of the variables was array rank: how to write wrapper for 'allocate'. An advantage of this method is that it is widely support by Fortran compilers.

In Fortran 2003/2008 there are extensive object oriented features. Quoting "Fortran 95/2003 explained" by Metcalf, Reid and Cohen, "To execute alternative code depending on the dynamic type of a polymorphic entity and to gain access to the dynamic parts, the select type construct is provided." The select type statement is a bit similar to a select case statement. This is support by fewer compilers. Again, you don't have to pass the type, since the compiler can figure it you from the variable itself. But it has to be a polymorphic type... Both Intel ifort and gfortran list select type and polymorphic datatypes as supported -- the later with some experimental aspects in gfortran (http://gcc.gnu.org/wiki/Fortran2003). These are recent additions to these compilers.

Solution 3

Here is a piece of code that determines what the type of something is. The action is trivial but you should be able to extend it to your use case.

module element_to_datatype
    use iso_fortran_env
    use mpi_f08
    implicit none

    contains

        function get_element_datatype(element) result(datatype)
            class(*), intent(in) :: element
            type(MPI_Datatype) :: datatype
            select type(element)
                ! REAL types
                type is ( real(kind=REAL32) )
                    datatype = MPI_REAL4
                type is ( real(kind=REAL64) )
                    datatype = MPI_REAL8
                ! COMPLEX types
                type is ( complex(kind=REAL32) )
                    datatype = MPI_COMPLEX8
                type is ( complex(kind=REAL64) )
                    datatype = MPI_COMPLEX16
                ! INTEGER types
                type is ( integer(kind=INT8) )
                    datatype = MPI_INTEGER1
                type is ( integer(kind=INT16) )
                    datatype = MPI_INTEGER2
                type is ( integer(kind=INT32) )
                    datatype = MPI_INTEGER4
                type is ( integer(kind=INT64) )
                    datatype = MPI_INTEGER8
                ! OTHER types
                type is ( logical )
                    datatype = MPI_LOGICAL
            end select
        end function

end module element_to_datatype

A previous answer shows how to do this with interfaces, so I won't repeat that.

Share:
14,875

Related videos on Youtube

tibbs
Author by

tibbs

Updated on December 03, 2021

Comments

  • tibbs
    tibbs over 2 years

    In Fortran, is there a way to determine the type of a variable?

    A possible use case where the type of a variable would be needed is the following. We pass a variable's type as an argument to a function, to be able to call type-specific code with that function, thus eliminating the need to have separate similar functions for each data type.

    • Peter.Ladanyi
      Peter.Ladanyi about 14 years
      What vintage of fortran? 77? 9x? 200x?
  • M. S. B.
    M. S. B. about 14 years
    There is a code example of "select type" with a polymorphic type at software.intel.com/en-us/forums/showthread.php?t=73454

Related