Skip to content

Adding a namelist variable

goldy edited this page Oct 8, 2024 · 16 revisions

A namelist variable is a quantity set at run time in some Fortran module. To add a new namelist variable, first you should find the module where similar (e.g., same physical process) namelist variables are defined. Once you find this, the key information is the name of the namelist containing that variable. For instance, in this Fortran statement:

namelist /feature_nl/ feat_on, feat_configfile, feat_param,

the namelist is feature_nl. Below, we refer to this as a namelist group while feat_on, feat_param, and feat_configfile are namelist variables.

  1. Define the variable
    • The namelist variable is defined in <CAM root>/bld/namelist_files/namelist_definition.xml
    • Find the appropriate group (see above for an example of what to look for in the code)
    • Add a new entry at the end of that section. Two examples:
    <entry id="feat_on" type="logical" category="microphys"
           group="feature_nl" valid_values="" >
      If .true., compute the new feature using the foobar method.
      Default: .true.
    </entry>

    <entry id="feat_configfile" type="char*256" input_pathname="abs" category="microphys"
           group="feature_nl" valid_values="" >
      ML parameter file for foobar feature method.
      Dunning, D., &amp; Kruger, J. (2024).
      foobar: Convincing ice particles to behave in clouds. Annals of Improbable Research, 30,
      314.
      https://doi.org/12.3456/7890123
      Default: None
    </entry>

    <entry id="feat_param" type="integer(2)" category="microphys"
           group="feature_nl" valid_values="2,3,4,5" >
      Tuning parameters for foobar feature method.
      feat_param(1) is the number of foo rounds
      feat_param(2) is the number of bar rounds
      Dunning, D., &amp; Kruger, J. (2024).
      foobar: Convincing ice particles to behave in clouds. Annals of Improbable Research, 30,
      314.
      https://doi.org/12.3456/7890123
      Default: None
    </entry>
Some notes on these entries:
* The `id` must be unique across all namelist entries in the namelist_definition.xml file. It also must match the variable in the associated Fortran `namelist` statement.
* The `type` field can be "integer", "logical", "real", or "char".
    * "char" fields are defined with a length, e.g., "char*16" or "char*256".
    * A namelist variable that is an array also has a array-length specifier in parenthesis, e.g., integer(10), char*256(2).
* If a namelist variable represents the path to a file, it should include the `input_pathname="abs"` entry.
* The `category` field is a logical grouping that can be useful when searching for namelist entries.
* The `group` field is the name of the namelist that will be read. This _must_ match the Fortran namelist entry.
* `valid_values` is a comma-separated list of valid values for namelist entries with a limited set of valid entries.
  • Good documentation really helps users understand a namelist variable so be sure to fill in this section.
  1. Set at least one default value

    • Default values for namelist variables are in <CAM root>/bld/namelist_files/namelist_defaults_cam.xml
    • Find a section in the file which has other defaults from the same namelist group and add at least one entry.
    • If the namelist variable is foo and the default value is bar, the entry would be of the form:

    <foo>bar</foo>

    • If the variable is an array, the values are a comma-separated list:

    <foo>bar,bar,baz,qux</foo>

  2. Make sure the variable shows up in atm_in when appropriate

    • This is done by adding some perl code to <CAM root>/bld/build-namelist
    • If you are adding a new namelist variable, you should be able to find the section where the current variables in the namelist are located.
    • If there is at least one entry in namelist_defaults_cam.xml, you should be able to simply add:

    add_default($nl, '<variable_name>');

  3. Add variable to a module

    • The desired Fortran variable name can match the namelist variable, however, it does not have to. The sample code below includes examples of both cases.
    • Namelist module variables should be protected so that other routines can not modify them.
    • If possible, namelist module variables should be set to an invalid value. Otherwise, they should be set to the default value.
    • See lines 12-14 below for an example
  4. Add the variable to the namelist reading routine

    1. Add the variable to the namelist: line 35 below
    2. Set a default value in the code: lines 39 - 41 below
    3. Broadcast the variable's value to all MPI tasks: lines 55 - 73 below
      • Note there is an error check and endrun call for each broadcast call.
    4. Set module variable if different: line 76 below
    5. Check for any inconsistency in the variable value: lines 79 - 83 below
    6. Log the variable's value: lines 86 - 94 below
01: module feature
02:
03:    use shr_kind_mod, only: cl => shr_kind_cl
04:
05:    implicit none
06:    private
07:
08:    !! Public interfaces
09:    public feature_readnl
10:
11:    !! Namelist variables (public)
12:    logical,           public, protected :: feat_on = .false.
13:    integer,           public, protected :: foobar_rounds(2) = -1
14:    character(len=CL), public, protected :: feat_configfile = 'None'
15:
16: contains
17:
18:    subroutine feature_readnl(nlfile)
19:       use mpi,            only: mpi_character, mpi_logical, mpi_integer
20:       use mpi,            only: mpi_bcast, MPI_SUCCESS
21:       use spmd_utils,     only: masterproc, mstrid=>masterprocid, mpicom
22:       use string_utils,   only: int2str
23:       use namelist_utils, only: find_group_name
24:       use cam_abortutils, only: endrun
25:       use cam_logfile,    only: iulog
26:
27:       ! path to file containing namelist input
28:       character(len=*), intent(in) :: nlfile
29:
30:       ! Local variables
31:       integer                     :: unitn, ierr
32:       integer                     :: feat_param(2)
33:       character(len=*), parameter :: subname = 'sec_ice_readnl: '
34:
35:       ! Define the namelist
36:       namelist /feature_nl/ feat_on, feat_param, feat_configfile
37:
38:       ! Initialize all namelist variables
39:       feat_on = .false.
40:       feat_configfile = 'None'
41:       feat_param(:) = foobar_rounds(:)
42:
43:       ! Read the namelist
44:       if (masterproc) then
45:          open(newunit=unitn, file=trim(nlfile), status='old' )
46:          call find_group_name(unitn, 'feature_nl', status=ierr)
47:          if (ierr == 0) then
48:             read(unitn, feature_nl, iostat=ierr)
49:             if (ierr /= 0) then
50:                call endrun(subname//'ERROR reading namelist')
51:             end if
52:          end if
53:          close(unitn)
54:       end if
55:
56:       ! Broadcast values to all MPI tasks
57:       call MPI_Bcast(feat_on, 1, mpi_logical, mstrid, mpicom, ierr)
58:       if (ierr /= MPI_SUCCESS) then
59:          call endrun(subname//"Error "//int2str(ierr)//                       &
60:               " broadcasting 'feat_on'")
61:       end if
62:       call MPI_Bcast(feat_configfile, len(feat_configfile), mpi_character,    &
63:            mstrid, mpicom, ierr)
64:       if (ierr /= MPI_SUCCESS) then
65:          call endrun(subname//"Error "//int2str(ierr)//                       &
66:               " broadcasting 'feat_configfile'")
67:       end if
68:       call MPI_Bcast(feat_param,      size(feat_param),     mpi_integer,      &
69:            mstrid, mpicom, ierr)
70:       if (ierr /= MPI_SUCCESS) then
71:          call endrun(subname//"Error "//int2str(ierr)//                       &
72:               " broadcasting 'feat_param'")
73:       end if
74: 
75:       ! Set module variables (if different)
76:       foobar_rounds(:) = feat_param(:)
77: 
78:       ! Check for inconsistent settings
79:       if (ANY(foobar_rounds /= -1)) then
80:          if (masterproc) then
81:             write(iulog, *) "WARNING: feat_param is set but feat_on is .false."
82:          end if
83:       end if
84: 
85:       ! Report the settings
86:       if (masterproc) then
87:          write(iulog ,*) 'Microphysics feature namelist:'
88:          write(iulog ,*) '  feat_on         = ', feat_on
89:          if (feat_on) then
90:             write(iulog, *) '  foo rounds      = ', foobar_rounds(1)
91:             write(iulog, *) '  bar rounds      = ', foobar_rounds(2)
92:             write(iulog, *) '  feat_configfile = ', trim(feat_configfile)
93:          end if
94:       end if
95: 
96:    end subroutine feature_readnl
97: 
98: end module feature
Clone this wiki locally