Skip to content

BeginnersGuide

Paul Leopardi edited this page Oct 8, 2024 · 97 revisions

Beginner's guide to CABLE development

Please read the Guidelines for use and development of CABLE first. This page provides more specific technical details.

General tips

  • The Linux/UNIX grep command is very useful when doing model development. For example, you want to add a namelist switch. The easiest way would be to find out how existing switches are defined. Doing a recursive grep for an existing switch name would give you this information, for example:
grep -ri 'cable_user%FWSOIL_SWITCH' .
  • If the project involves several people, it is generally easier to have the code under share rather than your own user branch, as only you have write permission on your user branch, although this can be changed. Under share, anyone can write, which is easier (remember that any change can be un-done, so this is not an issue)
  • After modifying CABLE, it is worth doing a compile with both Intel (ifort) and GNU (gfortran). Intel generally has better performance, but lets you get away with being a bit slack, whereas GNU genrally is a bit more strict.
  • Un-initialized variables in Fortran will result in head-aches, be careful to Not introduce any!

Modifying build.ksh and build_mpi.ksh if your machine option is not already there

The build scripts starts near the end of the script and gets the first 4 characters of the hostname:

HOST_MACH=`uname -n | cut -c 1-4`

If your machine is not already defined, let's say it's called monsoon, then you would need to add at the top:

known_hosts()
{
   set -A kh cher burn shin raij mons
}

And then define the various environment variables as per existing examples:

host_mons()
{
   export NCDIR='/share/apps/netcdf/intel/4.2.1/lib'
   export NCMOD='/share/apps/netcdf/intel/4.2.1/include'
   export FC=ifort
   export CFLAGS='-O2 -fp-model precise'
   export LD='-lnetcdf -lnetcdff'
   export LDFLAGS='-L'$NCDIR' -O2'
   build_build
   cd ../
   build_status
}

To find out the path to NCDIR and NCMOD, you may try something like:

which ncdump

Also note that there is a clean option within the build script, which will do a clean re-compile:

./build_mpi.ksh clean

When debugging, one should usually compile without optimization and inlucde the traceback:

export CFLAGS='-O0 -traceback -g -fp-model precise -ftz -fpe0'

Some differences between git and svn

For users who use git but have never used svn, most command are the same, e.g., the equivalent of "git status" is simply "svn status". Note that while "git status" can be run anywhere within the repo, "svn status" should be run at the root of the repo or given full path.

I want to:

  • Add a new switch Suppose we want to add a new cable_user switch called cable_user%GS_SWITCH which is either set to 'leuning' or 'medlyn'. This would be defined in core/biogeophys/cable_common.F90 under TYPE kbl_user_switches as:
CHARACTER(LEN=20) ::                                                     &
GS_SWITCH
Switches can also be logicals.  
To use the switch somewhere else, you would need something like:
USE cable_common_module

IF (cable_user%GS_SWITCH == 'leuning') THEN
   ! do something
ELSEIF(cable_user%GS_SWITCH == 'medlyn') THEN
   ! do something else
ELSE
   STOP 'gs_model_switch failed.'
ENDIF
  • Add new vegetation parameters to vegetation parameter file Suppose we need to read two new PFT parameters we have added to the vegetation parameter file defined by filename%veg. We call these two new parameters, g0 and g1.

    In offline/cable_initialise.F90, we would need at the right spot:

   CALL readpar(ncid_rin,'g0',dummy,veg%g0,filename%restart_in,            &
                max_vegpatches,'def',from_restart,mp) 
   CALL readpar(ncid_rin,'g1',dummy,veg%g1,filename%restart_in,            &
                max_vegpatches,'def',from_restart,mp) 
In offline/cable_input.F90, we would need at the right spot:
   CALL readpar(ncid_met,'g0',completeSet,veg%g0,filename%met,            &
                nmetpatches,'def') 
   CALL readpar(ncid_met,'g1',completeSet,veg%g1,filename%met,             &
                nmetpatches,'def') 
In offline/cable_checks.F90, define a reasonable max and min range:
           g0 = (/-0.5,0.5/),                  
           g1 = (/0.0,20.0/),                 
Since the veg parameters are read in for both offline and online runs, changes are required in core/biogeophys/cable_common.F90, under TYPE vegin_type, add the new parameters to the list under the correct dimension
      REAL, DIMENSION(:),ALLOCATABLE ::           &
         g0,       &
         g1,       &
and further down in the ALLOCATE block:
         vegin%g0( mvtype ), vegin%g1( mvtype ),             &
and further down in the READ statements, add this at the right spot:
         READ(40,*) vegin%g0(jveg), vegin%g1(jveg)
In offline/cable_iovars.F90, for parameter IDs for writing the parameters to netcdf file, under TYPE parID_type
INTEGER :: g0,g1
and further down at the right spot:
        g0   = .FALSE.,           
        g1   = .FALSE.,     
In offline/cable_parameters.F90, inside the DO loop:
          veg%g0(h)       = vegin%g0(veg%iveg(h)) 
          veg%g1(h)       = vegin%g1(veg%iveg(h)) 

and these should be deallocated later:
DEALLOCATE(vegin%g0, vegin%g1)
In offline/cable_mpicommon.F90, you must update nparam to the new total number of input fields, in this case, nparam was 293, we added 2 new params, so we now need to change it to 295:
  INTEGER, PARAMETER :: nparam = 295
In offline/cable_mpimaster.F90, at the right spot:
  bidx = bidx + 1
  CALL MPI_Get_address (veg%g0(off), displs(bidx), ierr)
  blen(bidx) = r1len

  bidx = bidx + 1
  CALL MPI_Get_address (veg%g1(off), displs(bidx), ierr)
  blen(bidx) = r1len
In offline/cable_mpiworker.F90, at the right spot:
  bidx = bidx + 1
  CALL MPI_Get_address (veg%g0, displs(bidx), ierr)
  blen(bidx) = r1len

  bidx = bidx + 1
  CALL MPI_Get_address (veg%g1, displs(bidx), ierr)
  blen(bidx) = r1len
In offline/cable_output.F90, at the right spots:
    IF(output%params .OR. output%g0) CALL define_ovar(ncid_out, opid%g0,   &
                          'g0', '-', 'g0 term in Medlyn Stom Cond. Param', &
                          patchout%g0, 'real', xID, yID, zID, landID, patchID)
    IF(output%params .OR. output%g1) CALL define_ovar(ncid_out, opid%g1,   &
                          'g1', '-', 'g1 term in Medlyn Stom Cond. Param', &
                          patchout%g1, 'real', xID, yID, zID, landID, patchID)
Further down:
    IF(output%params .OR. output%g0) CALL write_ovar(ncid_out, opid%g0,    &
                   'g0', REAL(veg%g0, 4),ranges%g0, patchout%g0, 'real')
    IF(output%params .OR. output%g1) CALL write_ovar(ncid_out, opid%g1,    &
                   'g1', REAL(veg%g1, 4),ranges%g1, patchout%g1, 'real')
Further down:
    CALL define_ovar(ncid_restart, rpid%g0, 'g0', '-',                     &
                     'g0 term in Medlyn Stomatal Cond. Param', .TRUE.,'real',&
                     0, 0, 0, mpID, dummy, .TRUE.) 
    CALL define_ovar(ncid_restart, rpid%g1, 'g1', '-',                     &
                     'g1 term in Medlyn Stomatal Cond. Param', .TRUE.,'real',&
                     0, 0, 0, mpID, dummy, .TRUE.)  
Further down:
    CALL write_ovar (ncid_restart, rpid%g0, 'g0', REAL(veg%g0, 4),       &
                     ranges%g0, .TRUE., 'real', .TRUE.)
    CALL write_ovar (ncid_restart, rpid%g1, 'g1', REAL(veg%g1, 4),       &
                     ranges%g1, .TRUE., 'real', .TRUE.) 

For coupled ACCESS simulations, you need to add to UM/cable_um_init_subrs.F90:

    veg%g0 = vegin%g0(veg%iveg)
    veg%g1 = vegin%g1(veg%iveg)

and to UM/cable_um_tech.F90:

      DEALLOCATE(vegin%g0)
      DEALLOCATE(vegin%g1)

Now, to use these parameters in the code elsewhere, for example, add these lines to core/biogeophys/cable_canopy.F90:

gswmin = veg%g0(i)
g1 = veg%g1(i)
  • Read a new 2D static parameter from a netcdf file
  • Read a new 2D time-varying parameter from a netcdf file (e.g., a daily varying LAI)
  • Add a new prognostic variable
  • Output something which is not output by default
Clone this wiki locally