Adding new namelist options

In this writeup I will add a namelist parameter to control the Brunt Vaisala frequency in the Jablonowski-Williamson 2006 dry baroclinic wave test case.

definitions

I use ${SRCROOT} to denote the root of your CAM source.

how I figured out how to do this

In order to figure out how to set up this namelist parameter I first found one that should be available in the similar routines to the ones where I want to get this parameter. I used analytic_ic_type.

In order to figure out where this is used in the code run

grep -r "analytic_ic_type" ${SRCROOT}

actually adding my own namelist doohickey

step 1:

In the file ${SRCROOT}/bld/namelist_files/namelist_definition.xml add the following text

namelist_definition.xml changes
<entry id="jw_06_BV_factor" type="real" category="dyn_test"
       group="analytic_ic_nl"
       valid_values="">
Factor by which to modify Brunt-Vaisala frequency in the moist baroclinic wave test case. Floating point.
May introduce static instability and rapid onset of turbuluence. Use with caution.
</entry>

the id field is what you will put e.g. in your user_nl_cam file e.g. jw_06_BV_factor = 2.0. type is the Fortran type. Look around the namelist_definition.xml to find other types and how to specify them.

Important: the group field will be used to get this parameter into Fortran. I think that the category is used for generating documentation. It doesn't appear to be used in the code.

valid values is used primarily for char variables, but look elsewhere in the file for how to use it.

If you don't add a good description, I'm judging you.

step 2:

In the file ${SRCROOT}/bld/namelist_files/namelist_defaults_cam.xml add namelist defaults. I figured out how to do this by using analytic_ic_type as a reference in order to find the conditions under which different defaults should be set.

I added the following defaults:

namelist_defaults_cam.xml changes
<jw_06_BV_factor > 1.0 </jw_06_BV_factor>
<jw_06_BV_factor phys="adiabatic"> 1.0 </jw_06_BV_factor>
<jw_06_BV_factor phys="kessler"> 1.0 </jw_06_BV_factor>

Chains of different CIME variables can be used e.g.

<jw_06_BV_factor phys="kessler" hgrid="C24"> 1.0 </jw_06_BV_factor>

step 3:

This is going to vary based on which module you want to read your namelist variable from. In order to figure out where this was done in my case I used grep to find a F90 file that contained analytic_ic_nl. In my case this is ${SRCROOT}/src/dynamics/tests/inic_analytic_utils.F90. Where private module variables are declared, add e.g.

real                                         :: jw_06_BV_factor

There should be a line such as this where it actually reads in the variable:

namelist /analytic_ic_nl/ analytic_ic_type, jw_06_BV_factor

add your variable to this line, as I already did.

Next find the part of the file where the namelist is broadcast to all MPI ranks:

call mpi_bcast(jw_06_BV_factor, 1, mpi_real8, masterprocid, mpicom, ierr)

I followed the conventions of the inic_analytic_utils and created an getter function. At the top where public interfaces are declared, add:

public :: jw_06_brunt_vaisala ! accessor

and add the definition of this function below the contains statement


real function jw_06_brunt_vaisala()
  jw_06_brunt_vaisala = jw_06_BV_factor
end function jw_06_brunt_vaisala

Another potential alternative to using a private variable with a getter function is using the public, protected keyword, in which subroutines within the module are allowed to modify this variable but not modules that use the module in which it is defined. This keyword was introduced in Fortran 2003, so I don't know how well it will play with different compilers.

Within the subroutine in which you call mpi_bcast before this is called, you can modify or validate the value of your namelist variable. You can report issues using write(iulog, *) msg with use cam_logfile, only: iulog at the top of your module.

step 4:

In the case directory, I make the following definitions:

  • In user_nl_cam I add jw_06_BV_factor = 2.0.
  • In SourceMods/src.cam/ic_baro_dry_jw06.F90 I add use inic_analytic_utils, only: jw_06_brunt_vaisala and gamma = jw_06_brunt_vaisala() * gamma_0

If you use the public, protected style of accessor then you could, I think, just do gamma = jw_06_BV_factor * gamma_0