Utility Introduction Page


The code modules described and referenced here are generic utilities used throughout a lot of other code available on this website.

Type Kinds Module

The Type_Kinds module is the most important Utility module since it is used in nearly every other module available on this site. Fortran 90/95 provides users with a new methodology to specify the precision of intrinsic data types, that is, specifying what "kind" of intrinsic type you want. This introduction will focus on the kinds of integer and real( floating point) data types, with emphasis on the latter.

What are kind types?

For each integer and real data type there is a default kind and a processor- and compiler-dependent number of other kinds. The kind type definitions available in the Type_Kinds module are shown below in table 1 for integers, and table 2 for reals.

Kind types are specified based upon how a user thinks a number will be used, typically in terms of the size and/precision of a number to be stored as a variable or parameter. For example, the following

  INTEGER, PARAMETER :: Double = SELECTED_REAL_KIND( 15 )
defines a real kind type, Double, for variables that require a precision of at least 15 decimal digits. (See, for example, pg176 in "Fortran 90/95 Explained", 2nd Ed. by M.Metcalf and J.Reid, for a description of the SELECTED_REAL_KIND() intrinsic function.)

The real variable definition is then simply,

  REAL( Double ) :: x

Table 1. Type_Kinds Integer Kind Types
Kind Type Parameter Description
Byte Kind type for a byte (1-byte) integer
Short Kind type for a short (2-byte) integer
Long Kind type for a long (4-byte) integer
LLong Kind type for a double long (8-byte) integer. If this kind type is not supported by a compiler, the value defaults to Long.
IP_Kind Kind type for a user specified default integer. The actual kind type this value corresponds to is determined by the PRIVATE IIP index.

Table 2. Type_Kinds Real Kind Types
Kind Type Parameter Description
Single Kind type for single precision (4-byte) real
Double Kind type for double precision (8-byte) real
Quad Kind type for quad precision (16-byte) real. If this kind type is not supported by a compiler, the value defaults to Double.
FP_Kind Kind type for a user specified default real. The actual kind type this value corresponds to is determined by the PRIVATE IFP index.

Generic kind types

Consider the following definition module for real numbers only, and a simple program that uses it,
  MODULE Type_Kinds
    IMPLICIT NONE
    INTEGER, PARAMETER :: Single = SELECTED_REAL_KIND( 6 )
    INTEGER, PARAMETER :: Double = SELECTED_REAL_KIND( 15 )
    INTEGER, PARAMETER :: fp_kind = Double
  END MODULE Type_Kinds
  PROGRAM Test_Kinds
    USE Type_Kinds
    REAL( fp_kind ) :: x, y
    x = 1.0_fp_kind
    y = x + 1.0_fp_kind
  END PROGRAM Test_Kinds
Note that a "generic" floating point kind type, fp_kind, has been defined. By using the generic kind type in the program, rather than the specific types Single or Double, the precision of the variables and literal constants used in the program can be changed simply by changing the definition of fp_kind in the Type_Kinds module and recompiling. This can be useful in identifying sections of an algorithm that are sensitive to the numerical precision of the variables it uses.

Magic numbers are Bad. Named parameters are Good.

Magic numbers are those literal constants that appear in expressions with no apparent explanation. As an example, consider the conversion of mass mixing ratio in units of g/kg to volume mixing ratio in units of ppmv,
  USE Type_Kinds
  REAL( fp_kind ) :: ppmv
  REAL( fp_kind ) :: Mixing_Ratio
  REAL( fp_kind ) :: Molecular_Weight
  ...
  ppmv = 1.0e+03 * Mixing_Ratio * 28.9648 / Molecular_Weight
What is 1.0e+03? What is 28.9648? The code this example is taken from actually looks more like,
  USE Type_Kinds
  REAL( fp_kind ), PARAMETER :: G_TO_KG      = 1.0e-03_fp_kind
  REAL( fp_kind ), PARAMETER :: PPV_TO_PPMV  = 1.0e+06_fp_kind
  REAL( fp_kind ), PARAMETER :: SCALE_FACTOR = G_TO_KG * PPV_TO_PPMV
  REAL( fp_kind ), PARAMETER :: MW_DRYAIR    = 28.9648_fp_kind
  ...
  REAL( fp_kind ) :: ppmv
  REAL( fp_kind ) :: Mixing_Ratio
  REAL( fp_kind ) :: Molecular_Weight
  ...
  ppmv = SCALE_FACTOR * Mixing_Ratio * MW_DRYAIR / Molecular_Weight
Now all of the "magic numbers" in the expression have been replaced with named parameter constants. Simply looking at the code tells us what the scaling factor is for and that the other number is actually the molecular weight of dry air. More importantly, note the suffix "_fp_kind" on all the literal constants in the parameter definitions. This ensures that the literal constant has the same precision as its data type. Remember that,
  REAL( fp_kind ) :: x
  x = 35.6748
assigns the default single precision value 35.6748 to the variable x regardless of the kind type of the actual variable. To ensure that literal constants of the correct precisions are assigned, the following is required,
  REAL( fp_kind ) :: x
  x = 35.6748_fp_kind
This becomes particular important when variables are summed over many iterations. Assigning a single precision literal constant increases the possibilities of inaccuracies due to numerical precision errors accumulating.

Kind type byte sizes

When using integer and/or real variables in Fortran code, particularly in file I/O, we may be concerned with the byte sizes of our defined variables. The Fortran 90/95 standards contain no information about this apart from requiring that the default integer and real types consist of the same number of numeric storage units. On most computing platforms nowadays, a numeric storage unit is considered to be an 8-bit byte (or some multiple thereof), but that hasn't always been the case and may change in the future.

Despite this, most of us still think in terms of 8-bit bytes (or 4-byte words) when we consider the "size" of an integer or real variable. For this reason, the Type_Kinds module contains defined parameters of the expected sizes of the various kinds of integers and reals in units of 8-bit bytes. These definitions are listed below in table 3 for integers and table 4 for reals.

Table 3. Type_Kinds Expected Integer Byte Sizes
Byte Size Parameter Description
n_Bytes_Byte The expected size of a Byte kind integer in units of 8-bit bytes.
n_Bytes_Short The expected size of a Short kind integer in units of 8-bit bytes.
n_Bytes_Long The expected size of a Long kind integer in units of 8-bit bytes.
n_Bytes_LLong The expected size of a LLong kind integer in units of 8-bit bytes.
n_Bytes_IP_Kind The expected size of the user specified default integer kind in units of 8-bit bytes. The actual kind type size this value corresponds to is determined by the PRIVATE IIP index.

Table 4. Type_Kinds Expected Real Byte Sizes
Byte Size Parameter Description
n_Bytes_Single The expected size of a Single kind real variable in units of 8-bit bytes.
n_Bytes_Double The expected size of a Double kind real variable in units of 8-bit bytes.
n_Bytes_Quad The expected size of a Quad kind real variable in units of 8-bit bytes.
n_Bytes_FP_Kind The expected size of the user specified default real kind in units of 8-bit bytes. The actual kind type size this value corresponds to is determined by the PRIVATE IFP index.

Compare Float Numbers Module

This module defines elemental relational operators and functions for comparing floating point numbers. We all know that floating point numbers can be problematical beasties, particularly when we compare two real numbers. With apologies to everyone who is already familiar with the concept, the following is how not to do it,
  USE Type_Kinds
  REAL( fp_kind ) :: x, y
  IF ( x == y ) THEN
    ! -- x equals y, so perform some operation
    ....
  END IF
Most people realise that real numbers should be compared within some tolerance value. However, a simple tolerance value will vary depending on the magnitudes of the numbers being compared. Without delving too much into the details, a better floating point comparison algorithm is,
  IF ( ABS( x < y ) < ( ULP * SPACING( MAX(ABS(x),ABS(y)) ) ) ) THEN
    ! -- x equals y, so perform some operation
    ....
  END IF
The Fortran 90/95 intrinsic function SPACING(x) returns the absolute spacing of numbers near the value of x. The ULP value, the "unit in the last place", is the smallest possible increment or decrement that can be made using a machine's floating point arithmetic. A 0.5 ULP maximum error is the best you could hope for, since this corresponds to always rounding to the nearest representable floating point number. The ULP value can be used to scale the comparison based on knowledge of the "numerical quality" of the two numbers being compared.

This floating point comparison capability is provided in the Compare_Float_Numbers module via the logical Compare_Float() function. In addition, simple relational operators .EqualTo., .GreaterThan., and .LessThan. are also available. Both single and double precision numbers can be compared, as can arrays from rank-1 to rank-7. Using the previous example, the floating point number comparison for a particular ULP scaling becomes,

  USE Type_Kinds
  USE Compare_Float_Numbers
  REAL( fp_kind ) :: x, y
  IF ( Compare_Float( x, y, ULP=5 ) ) ) THEN
    ! -- x effectively equals y, so perform some operation
    ....
  END IF
For no ULP scaling (ULP=1), the relational operator can be used instead,
  USE Type_Kinds
  USE Compare_Float_Numbers
  REAL( fp_kind ) :: x, y
  IF ( x .EqualTo. y ) THEN
    ! -- x effectively equals y, so perform some operation
    ....
  END IF
For more detail on the subprograms, you can view the Compare_Float_Numbers module documentation.

Error Handler Module

In an effort to introduce some form of graceful error traceback utility, the Error_Handler module is provided. This module defines simple error codes and contains a routine to output messages. The available error code parameters are shown in Table 5. The Error_Handler module also contains the Display_Message subroutine. This routine allows messages to be displayed on standard output (screen, the default), or written to a user specified log file. An example of its usage is shown below,
  USE Error_Handler
  CHARACTER( * ), PARAMETER :: ROUTINE_NAME = 'My_Routine'
  INTEGER :: Error_Status

  Error_Status = calculate_widget_size()
  IF ( Error_Status /= SUCCESS ) THEN
    CALL Display_Message( ROUTINE_NAME, &
                          'Error calculating widget size.', &
                          Error_Status, &
                          Message_Log = 'error_log.txt' )
    RETURN
  END IF
The output message format is,

"routine name"("state description") : "message"

For example, if an error occurs in the Display_Message routine attempting to write to the log file, the output is,

  DISPLAY_MESSAGE(FAILURE) : Error opening message log file
For more detail on the subprograms, you can view the Error_Handler module documentation.

Table 5. Error_Handler Error Codes
Error Code Parameter Description
SUCCESS Code specifying successful completion.
INFORMATION Code specifying information output.
WARNING Code specifying a warning state. Execution can continue but results may be incorrect.
FAILURE Code specifying severe error. Execution cannot continue.
UNDEFINED Code specifying undefined completion status.

File Utility Module

This module contains generic file utility routines allowing users to obtain unused logical unit numbers for file access, and to easily test if a particular file exists or has already been opened. For more detail on the available subprograms, you can view the File_Utility module documentation.

Endian Module

This module contains an elemental function, Swap_Endian, to byte-swap data - both scalars and arrays. The process followed is shown in figure 1. An atomic data object that is N-bytes in size (Fig.1a) is treated like an N-element byte array (Fig.1b). Each element of this figurative byte array is then mirrored (Fig.1c) to complete the byte swap of the original data object. For arrays, each element is treated individually.

Figure 1. Endian_Utility data object byte swap

The byte swapping is performed by using the TRANSFER intrinsic to rearrange the bytes of a data object by accessing the data with a subscript triplet having a negative stride. For example, for 4-byte integer swapping,

  USE Type_Kinds
  INTEGER( Long ) :: Input
  INTEGER( Long ) :: Output
  INTEGER, PARAMETER :: N = n_Bytes_Long
  INTEGER( Byte ), DIMENSION( N ) :: Byte_Equivalent

  Byte_Equivalent = TRANSFER( Input, Byte_Equivalent )
  Byte_Equivalent = Byte_Equivalent( N:1:-1 )
  Output          = TRANSFER( Byte_Equivalent, Output )

This method can be slow, not because of the TRANSFER function itself, but the negative stride of the array access. It depends on the quality of implementation of a compiler. Regardless, it is most definitely not recommended that the Swap_Endian function be used to byte-swap large quantities of data -- say if you're reading a big-endian file on a little-endian system. That sort of thing is better handled by appropriate compiler switches that access the requisite run time libraries.

Other methods tried included

For more detail on the available subprograms, you can view the Endian_Utility module documentation.

Binary File Utility Module

This module contains the Open_Binary_File function that is used to open the Binary format data files used by other software (in particular the Radiative Transfer and Infrared Sea Surface Emissivity models) available on this website. This open function performs an "endian-ness" check on existing files to ensure that the data file can be read on the platform being used. For more detail on the available subprograms, you can view the Binary_File_Utility module documentation.

List File Utility Module

This module contains routines to read list files, i.e. ASCII files that contain lists of character or integer data, one item per line. These routines do all the necessary line counting and place the data in structures containing variable length arrays. The character and integer list file data types are defined as follows,
  TYPE, PUBLIC :: Character_List_File_type
    PRIVATE
    INTEGER :: String_Length = STRLEN
    INTEGER :: n_Entries = 0
    CHARACTER( STRLEN ), DIMENSION(:), POINTER :: Entry => NULL()
  END TYPE Character_List_File_type
                                                                                                                                 
  TYPE, PUBLIC :: Integer_List_File_type
    PRIVATE
    INTEGER :: n_Entries = 0
    INTEGER, DIMENSION(:), POINTER :: Entry => NULL()
  END TYPE Integer_List_File_type
Note that while the data types themselves are decalred PUBLIC, their contents are PRIVATE and can only be obtained via the module functions.

For more detail on the available subprograms, you can view the List_File_Utility module documentation.

String Utility Module

This module contains simple string processing routines that perform case conversion and string compression (i.e. whitespace removal). For more detail on the available subprograms, you can view the String_Utility module documentation.

Date Utility Module

This module contains routines that perform some rudimentary date conversions. For more detail on the available subprograms, you can view the Date_Utility module documentation.

Fundamental Constants Module

The Fundamental_Constants module contains definitions for a number of fundamental constants used in various software that is available on this site. The constants are declared using the generic floating point kind type, fp_kind and are grouped into four categories:

Table 6. Fundamental_Constants Irrational Constants
Parameter Name Description
PI Value of π
PI_RECIPROCAL Reciprocal value of π, 1/π
PI_SQUARED Squared value of π, π2
PI_SQUARE_ROOT Square root value of π, √π
PI_LN Natural logarithm of π, LN(π)
PI_LOG10 Base-10 logarithm of π, LOG(π)
E Value of e, base of the natural logarithm
E_RECIPROCAL Reciprocal value of e, 1/e
E_SQUARED Squared value of e, e2
E_LOG10 Base-10 logarithm of e, LOG(e)

Table 7. Fundamental_Constants Universal Constants
Parameter Name Description Units
SPEED_OF_LIGHT Speed of light in a vacuum, c metres/second, m/s
PERMEABILITY Permeability of free space, μ0 Newton/Ampere2, N/A2
PERMITTIVITY Permittivity of free space, ε0 Farad/metre, F/m
PLANCK_CONSTANT Planck's constant, h Joule.seconds, Js
GRAVITATIONAL_CONSTANT Universal, or Newtonian, gravitation constant, G m3/(kg.s2)

Table 8. Fundamental_Constants Conversion Factors
Parameter Name Description Units
ELECTRON_VOLT Electron volt, the work required to move one electron through a potential difference of one volt. Joules, J
UNIFIED_ATOMIC_MASS_UNIT Unified atomic mass unit, u. This is a unit of mass equal to the mass of 1/12 of a mole of Carbon-12 atoms kg
STANDARD_ATMOSPHERE Standard atmospheric pressure, P0. Pascals, Pa
STANDARD_TEMPERATURE Standard atmospheric temperature, T0. Note that the unit of thermodynamic temperature, the Kelvin, is the fraction 1/273.16 of the thermodynamic temperature of the triple point of water. The standard temperature is the ice point of water, 273.15, not the triple point. Kelvin, K
STANDARD_GRAVITY Standard acceleration of gravity, g m/s2

Table 9. Fundamental_Constants Physicochemical Constants
Parameter Name Description Units
AVOGADRO_CONSTANT Avogadro's number, N(A). The number of atoms or molecules required such that the number of grams of a substance equals its atomic mass. This number of atoms or molecules is a mole. mol-1
MOLAR_GAS_CONSTANT Universal gas constant, R J/(mol.K)
BOLTZMANN_CONSTANT Boltzmann's constant, k, where k=R/N(A) J/K
STEFAN_BOLTZMANN_CONSTANT Stefan-Boltzmann constant, σ W/(m2.K4)
C_1 First radiation constant for spectral radiance, c1, where c1=2.h.c2 W.m2.sr-1
C_2 Second radiation constant, c2, where c2=h.c/k K.m
STP_MOLAR_VOLUME Molar volume, Vm, of an ideal gas at standard temperature and pressure m3/mol
LOSCHMIDT_CONSTANT The number density, n0, of one mole of an ideal gas at standard temperature and pressure m-3


This page maintained by Paul van Delst

Last updated December 1, 2004