Flexible precision in GEOS-Chem

From Geos-chem
Revision as of 20:01, 7 November 2014 by Bmy (talk | contribs)
Jump to navigation Jump to search

Overview

Flexible precision was introduced in Fortran 90

In most existing Fortran codes (including GEOS-Chem) you will see declarations such as:

! Integers
INTEGER   :: I, J   ! 4-byte integer  
INTEGER*4 :: K, L   ! 4-byte integer
INTEGER*8 :: M, N   ! 8-byte integer

! Floating point
REAL      :: A, B   ! 4-byte floating point
REAL*4    :: C, D   ! 4-byte floating point
REAL*8    :: E, F   ! 8-byte floating point 

etc. Note that

  1. On most compilers, INTEGER refers to a 4-byte integer. You can make this default to an 8-byte integer by compiling with -i8. In most circumstances it is OK to use 4-byte integers, unless you need to point to a memory location or are reading an 8-byte integer from a netCDF file.
  2. On most compilers, REAL refers to a 4-byte floating-point. You can make this default to an 8-byte floating point by compiling with -r8.
  3. In some older Fortran codes, you will see the term DOUBLE PRECISION. This is the same as REAL*8 -- it is an 8-byte floating point.

Fortran 90 introduced a new precision concept. You can replace these fixed data type with declarations of arbitrary precision. This is done with the SELECTED_REAL_KIND and SELECTED_INT_KIND functions, which are described in more detail here.

--Bob Y. 15:01, 7 November 2014 (EST)

Why are we implementing flexible precision in GEOS-Chem

This will

What is often more useful is not to define an arbitrary precision, but to have the ability to declare the same variable with 4-byte precision under some circumstances and 8-byte precision under other circumstances. An example of this is that the traditional "serial" GEOS-Chem has always used 8-byte floating point variables, but we would need to make these 4-byte floating points when running GEOS-Chem within the GEOS-5 GCM.

Methodologoy

Here is an example of how you can do this:

1. Define a module named precision_mod.F. You can place this in the Headers directory. This will define a parameter that will be used to specify the precision of variables in other parts of the code.

MODULE PRECISION_MOD

  IMPLICIT NONE
  PRIVATE

#if defined( USE_REAL8 )

  ! Use 8-byte floating point precision when asked for it
  INTEGER, PARAMETER, PUBLIC :: fp = KIND( 0.d0 )

#else

  ! Use 4-byte floating point precision by default
  INTEGER, PARAMETER, PUBLIC :: fp = KIND( 0.0  )

#endif

END MODULE PRECISION_MOD

Instead of having to figure out the proper settings with SELECTED_REAL_KIND, we can just use the KIND command to return that for us. KIND( 0.d0 ) returns the proper "kind" value to define an 8-byte floating point, and KIND( 0.0 ) returns the proper "kind" value for us to define a 4-byte floating point. This value is saved in the constant named fp.

Also note that we have used an #if defined block to define the value of FP. If we compile with -DUSE_REAL8, then the fp can be used to declare 8-byte floating-point variables. Otherwise, fp can be used to declare 4-byte variables by default.

2. In the Makefille_header.mk, we need to add the -DUSE_REAL8 flag to the FFLAGS variable. FFLAGS contains the set of compiler switches and preprocessor statements used to compile GEOS-Chem. This can be done by looking for the following ifeq statement. Add the following lines in RED. This has to be done in both the IFORT section and in the PGI section of Makefile_header.mk

  1. Add include options for ESMF & MAPL

ifeq ($(HPC),yes) INCLUDE += $(MAPL_INC) $(ESMF_MOD) $(ESMF_INC) else FFLAGS += -DUSE_REAL8 endif

3. Add precision_mod.F to the dependencies listing in the Headers/Makefile. Add this line:

precision_mod.o: precision_mod.F90

4. At the top of each GEOS-Chem module or routine (typically in the !USES: comment section), you can place a reference to precision_mod.F. For example, at the top of GeosCore/carbon_mod.F, you would add the line in RED:

!------------------------------------------------------------------------------ ! GEOS-Chem Global Chemical Transport Model  ! !------------------------------------------------------------------------------ !BOP ! ! !MODULE: carbon_mod ! ! !DESCRIPTION: Module CARBON\_MOD contains arrays and routines for performing ! a carbonaceous aerosol simulation. Original code taken from Mian Chin's ! GOCART model and modified accordingly. (rjp, bmy, 4/2/04, 6/30/10) !\\ !\\ ! !INTERFACE: !

     MODULE CARBON_MOD

! ! !USES: ! !

     USE HCO_ERROR_MOD       ! For real precisions (hp)
     USE PRECISION_MOD       ! For GEOS-Chem precision (fp)
     IMPLICIT NONE
     PRIVATE

Note that HEMCO has its own precision parameters. We'll leave those alone, because HEMCO ships as a separate package as well.

5. Look for all variables in the module that are declared as REAL*8. Replace the REAL*8 text with REAL(fp) instead. So these lines:

     REAL*8, ALLOCATABLE :: ANTH_BLKC(:,:,:)
     REAL*8, ALLOCATABLE :: ANTH_ORGC(:,:,:)
     REAL*8, ALLOCATABLE :: BIOB_BLKC(:,:,:)

would become

     REAL(fp), ALLOCATABLE :: ANTH_BLKC(:,:,:)
     REAL(fp), ALLOCATABLE :: ANTH_ORGC(:,:,:)
     REAL(fp), ALLOCATABLE :: BIOB_BLKC(:,:,:)


6. IMPORTANT NOTE! Any literal constants in scientific notation made with the Fortran "d" exponents have to be changed to "e". Also, the text _fp has to be appended to the exponent. This tells Fortran that we are using a customized precision definition. For example, the code:

     ! Molecules OH  per kg OH [molec/kg]
     REAL*8,  PARAMETER  :: XNUMOL_OH  = 6.022d23 / 17d-3
     REAL*8,  PARAMETER  :: CM3PERM3   = 1.d6

would become instead:

     ! Molecules OH  per kg OH [molec/kg]
     REAL(fp),  PARAMETER  :: XNUMOL_OH  = 6.022e+23_fp / 17e-3_fp
     REAL(fp),  PARAMETER  :: CM3PERM3   = 1.e+6_fp

Also, probably for good style, we should use a + sign to denote a positive exponent. The + sign is optional for positive numbers, but it is good style to add it.

7. Repeat the process in steps 4-6 for each GEOS-Chem source code file. It is good practice to modify one module or file at a time, and the run a GEOS-Chem difference test. Then continue.