Configuration code generation#

Applications that use the extended Rose metadata can run the LFRic Configurator as part of the application build process. The Configurator generates all the code required to read namelist configuration files. The code also makes the configuration information available to application coders in a user-friendly format.

This section describes how to load an application configuration into the application, and how code can use the various types of application configuration.

Loading the configuration#

The Configurator generates a procedure (read_configuration) to read a configuration file based on an application’s metadata file (.json). The configuration entails one or more Fortran namelists, which are each read and stored in a namelist specific type (<namelist_name>_nml_type). These namelist objects are in turn stored in a configuration object (config_type).

This allows for multiple configurations to be loaded into a given application.

use config_loader_mod, only: read_configuration

type(config_type) :: config_A, config_B
...

call config_A%initialise( 'ConfigurationName_A' )
call config_B%initialise( 'ConfigurationName_B' )

call read_configuration( namelist_file_A, config=config_A )
call read_configuration( namelist_file_B, config=config_B )

The LFRic infrastructure provides a driver configuration component that orchestrates both reading of the namelist configuration file and cross-checking the contents to ensure all required namelists are present. The driver configuration component can be used instead of directly calling the above procedure.

Using the Config Object#

The term “config object” refers to an object of type config_type. It holds a number of extended namelist_type objects each of which holds the configuration choices for one of the namelists. To access a configuration value, simply reference the configuration hirarchy in the config_type, e.g.

use config_mod, only: config_type

type(config_type)  :: config
character(str_def) :: name

name = config%base_mesh%mesh_name()

Enumerations#

An enumeration is a variable that can take one of a small number of fixed values. In the namelist, the permitted values are strings, but within the code, the option and each of the permitted values are converted into integers.

To get, and to use, an enumeration, one has to get the value representing the choice, but also one or more of the enumeration list to check against. Enumerations are stored as i_def integers. The enumeration options are parameters that can be obtained directly from Configurator-generated _config_mod modules.

To illustrate, Rose metadata specifies that the value of the namelist variable geometry can be either the string “spherical” or the string “planar”. In the following code, the namelist entry is checked against two allowed choices of geometry: spherical and planar, referenced by the two integer parameters in the base_mesh_config_mod module. The names of the parameters are prefixed with the name of the variable to ensure there is no duplication of parameter names with other enumeration variables:

use base_mesh_config_mod, only: geometry_spherical, geometry_planar

integer(i_def) :: geometry_choice
real(r_def)    :: domain_bottom

geometry_choice = config%base_mesh%geometry()

select case (geometry_choice)
case (geometry_planar)
  domain_bottom = 0.0_r_def
case (geometry_spherical)
  domain_bottom = earth_radius
case default
  call log_event("Invalid geometry", LOG_LEVEL_ERROR)
end select

Hidden values

Use of enumerations can be better than using numerical options or string variables.

A parameter name is more meaningful and memorable than a numerical option, making code more readable. There is also a clearer link between the name and the metadata, as the metadata can be easily searched to find information about the option.

Code that compares integer options and parameters is safer than code that compares string options and parameters. If there are spelling errors in the names in the code, the former will fail at compile time whereas problems with the latter only arise at run-time.

Duplicate namelists#

When a defined namelist is allowed to have multiple instances in a namelist input file, the namelist is said to allow duplicates (with a given configuration). This is indicated by the Rose metadata as duplicate=true. These namelist instances have the same variable names, though those varibles may contain different values.

Instances of a duplicate namelist may be differentiated using one of the namelists members as a key. The extended Rose metadata, !instance_key_member indicates to the configurator tool which namelist variable to use as the instance key. For example, consider a partitioning namelist, with the variable, mesh_choice used as the instance key member, the relevant parts of the Rose metadata may look as follows:

[namelist:partitioning]
duplicate=true
!instance_key_member=mesh_choice

[namelist:partitioning=mesh_choice]
!enumeration=true
values='source', 'destination'

As the instance key is mesh_choice, there may be two copies of the namelist each with a different mesh_choice:

&partitioning
mesh_choice           = 'destination',
partitioner           = 'cubedsphere',
panel_decomposition   = 'auto',
/

&partitioning
mesh_choice           = 'source',
partitioner           = 'planar',
panel_decomposition   = 'auto',
/

To extract a specific instance, the possible mesh_choice string must be known:

type(partitioning_nml_iterator_type) :: iter
type(partitioning_nml_type), pointer :: partitioning_nml

call iter%initialise(config%partitioning)
do while (iter%has_next())

  partitioning_nml => iter%next()
  mesh_choice = partitioning_nml%get_profile_name()

  select case (trim(mesh_choice))

  case('source')
      srce_partitioner = partitioning_nml%partitioner()

  case('destination')
      dest_partitioner = partitioning_nml%partitioner()

  end select

end do

Using configuration module files#

In the examples above, the config_mod modules were used only to obtain the parameters that represent the options of an enumeration variable. The preferred practice is to only use global scope config_mod modules to access fixed runtime parameters.

Configuration access via use statements.

While existing code will allow access to any variables direct from the config_mod files, this legacy practice is strongly discouraged. Access via use statements cannot work where namelists may have multiple instances or when an application wishes to load multiple configuration files. It is recommended that access to configuration namelists be limited to usage of the modeldb%config item described above.

Direct access from *_config_mod modules will be restricted to enumeration parameter values only by April 2026.