LFRic Atmosphere Diagnostics#
This section describes changes required to add a new diagnostic to the LFRic atmosphere model. If a diagnostic is being added to an existing science scheme, it may be possible to copy and adapt code for an existing diagnostic. Excluding code to compute the new diagnostic, adding a diagnostic amounts to just three small changes.
Overview#
The diagnostic system for the LFRic atmosphere model uses the XIOS library.
XIOS inputs and outputs are configured using an iodef.xml file. An
iodef.xml file for a given LFRic atmosphere model setup includes
definitions of all possible prognostics and diagnostics and, separately, a set
of diagnostic output requests.
Field definitions are held in various files found in the lfric_atm/metadata
directory. Diagnostic requests are separate as they are part of a particular
application configuration. The iodef.xml file includes all these files by
specifying links to them.
Any field defined in the XML file can be selected for output to a diagnostic file. XIOS supports various post-processing operations that can be specified in the diagnostic request to generate, for example, a daily mean of a field. Field requests can be grouped to be output to different file streams.
XIOS is a highly complex and flexible parallel IO system with post-processing capabilites, including the ability to apply time and spatial processing as well as combine multiple fields. It is developed at IPSL.
Caution
While it would be possible to write a set of complex diagnostic requests using all the features of XIOS, people should be cautious because future developments of the LFRic atmosphere user environment may not support all the flexibility required to reconstruct the request. Furthermore, the underlying XIOS software is complex, and it is possible to create a complex diagnostic request that is unreliable or that imposes high computation costs on the application.
Permitted diagnostic fields#
Diagnostic fields can only be created for the following types of LFRic atmosphere fields:
A \(\mathbb{W}_{3}\) field representing data, typically scalar quantities, at the centre of each 3D model cell.
A \(\mathbb{W}_{theta}\) or \(\mathbb{W}_{2v}\) field both representing data at the centre of the bottom and top face of each 3D model cell (noting that a cell shares the data point on its top face with the cell above). The \(\mathbb{W}_{3}\) fields represent scalar quantities, and the \(\mathbb{W}_{2v}\) represent vectors or fluxes.
A \(\mathbb{W}_{2h}\) field representing data, typically vectors or fluxes, at the centre of the faces around the side of each cell(noting that neighbouring cells share these faces and data points).
A single-level field.
A “multidata” field. Some types of single level \(\mathbb{W}_{3}\) field store more than one quantity, such as a data point for each vegetation type or for different radiation bands. Supported multidata fields are defined in the
metadata/axis_def_main.xmlfile.
Detailed steps for adding a new diagnostic#
To add a diagnostic for potential output from the LFRic atmosphere model, follow these steps:
Create a
fieldrecord in the relevant XML file that is used to create the XIOSiodef.xmlfile.Add code to initialise a model field to hold the diagnostic. For existing science schemes it may be possible to add the field initialisation code to an existing module. This step is not required if the diagnostic is obtained from an existing field such as from a prognostic field passed into the algorithm.
Add code to write out the field.
Once the above steps are complete, code can be added to compute the diagnostic. It is possible to check whether a diagnostic has been requested for output. If a diagnostic has not been requested, and if it is not required for other purposes, then the model must avoid computing its value.
Several science schemes have dedicated modules to initialise and output
diagnostics (steps 2 and 3 of the above list). See the modules in
um_physics_interface/source/diagnostics/.
The following sections describe each of the steps in more detail.
Creating a field record#
Diagnostics that are computed every time-step should normally be defined in the
field_def_diags.xml file.
A field definition looks like this:
<field id="convection__shallow_dt" name="shallow_dt"
long_name="temperature_increment_from_shallow_convection" unit="K
s-1" grid_ref="full_level_face_grid" />
The components of this definition are:
The
idstring is used in the model code to identify the diagnostic. The naming convention used by the LFRic atmosphere is the section name followed by a double-understroke followed by a descriptive name.The name and long name are only seen in the diagnostic output. The names may be formally assigned such as by the CF naming convention. In this case, the name is the same as the suffix of the ID, but it is not always so.
The units should be SI units. Again, these are only seen in the diagnostic output file.
The
grid_refattribute of this definition describes the domain of the field. The example field above is represented in the model as a \(\mathbb{W}_{theta}\) field. Other field types have different attributes as shown in the following table.
Model field type |
Domain attributes |
|---|---|
\(\mathbb{W}_{3}\) |
|
\(\mathbb{W}_{theta}\) |
|
\(\mathbb{W}_{2v}\) |
|
\(\mathbb{W}_{2h}\) |
|
Single-level field |
|
Multi-data field |
|
A multi-data field is often called a tiled field, and contains more than one
related quantity. For multi-data fields, the <multidata type> text would
be replaced by one of the multidata field types used in the model and defined
in the axis_def_main.xml file in the lfric_atm/metadata directory. For
example the following field is on surface tiles.
<field id="surface__throughfall" name="throughfall_rate"
long_name="canopy_throughfall_flux" unit="kg m-2 s-1"
domain_ref="face" axis_ref="surface_tiles" />
The number of quantities in each type of multi-data field is defined within the application.
Initialising the field#
Initialising the field relates to defining the LFRic function space that the field lives on rather than initialising the values held in the field.
If a field is not available to hold the diagnostic data, then one must be declared local to the diagnostic routine and initialised to be the correct field type.
The following code is from an existing science scheme algorithm. It declares some fields and passes them to the scheme’s diagnostic initialisation procedure.
type( field_type ) :: soil_moisture_content
type( field_type ) :: grid_canopy_water
type( field_type ) :: throughfall
type( field_type ) :: grid_throughfall
call initialise_diags_for_jules_soil(soil_moisture_content, &
grid_canopy_water, &
throughfall, &
grid_throughfall)
The initialise_diags_for_jules_soil procedure calls the LFRic atmosphere
init_diag function:
soil_moisture_content_flag = init_diag(soil_moisture_content, &
'soil__soil_moisture_content')
grid_canopy_water_flag = init_diag(grid_canopy_water, &
'surface__grid_canopy_water')
grid_throughfall_flag = init_diag(grid_throughfall, &
'surface__grid_throughfall')
The init_diag function does the following steps:
Checks if the diagnostic needs to be computed this time-step.
If the diagnostic needs to be computed, the field is initialised to the right function space type. The function space type is determined from the domain information in the field record that was added to the
iodef.xmlfile according to the table above. The name of the field is set to the string value passed into the function.If the diagnostic does not need to be computed, it still initialises the field with metadata. But to save memory, instead of the field holding its own data array, its data array pointer is pointed to a dummy
empty_real_datafield provided by the application. Fields cannot be left uninitialised as they would cause model failures if passed through the PSy layer as the PSy layer will try to extract their metadata.The
init_diagfunction returns.true.if the diagnostic is needs to be output, and.false.otherwise.
Sometimes a diagnostic needs to be computed even when it is not required for
output because of dependencies on other diagnostics that are required. An
optional argument to init_diag can be used to ensure a field is properly
initialised even if there is no requirement to output the diagnostic. The
following code initialises the throughfall field if the diagnostic itself
is required or if the grid_throughfall diagnostic is required.
throughfall_flag = init_diag(throughfall, 'surface__throughfall', &
activate = grid_throughfall_flag)
although the throughfall field will be properly initialised if the
grid_throughfall diagnostic is required, the init_diag function will
still return .false. if the throughfall diagnostic is not requested.
The return value is used only for deciding whether to write the diagnostic to
the IO system.
Outputting a field#
If the init_diag function has returned .true. then the diagnostic needs
to be written to the IO system once it has been computed.
In the LFRic atmosphere model, the output procedure for a set of diagnostics is
usually in the same module as the initialisation procedure. The flag returned
by the init_diag function is available to both procedures so can be used
to determine whether the diagnostic needs to be written out.
if (throughfall_flag) call throughfall%write_field()
if (soil_moisture_content_flag) call soil_moisture_content%write_field()
Note that the write_field method takes no argument here. The name passed to
XIOS is the field name provided at initialisation time.
Computing a field#
Between calling the function to initialise fields and outputting the diagnostics they hold, the diagnostics are computed.
Typically, diagnostics are computed by passing them to PSyclone built-ins and kernels.
When using built-ins to compute a diagnostic, it is important to avoid calling
the built-in if the init_diag routine has not fully initialised the
field.
As noted above, the init_diag routine used by the LFRic atmosphere
associates the data in a field with an empty_real_data array if the
diagnostic is not required; all such fields are pointed to the same array held
in the application’s empty_data_mod module. Within a kernel, the data
array can be checked to ensure it is not associated with this dummy array
prior to attempting to compute the diagnostic:
use empty_data_mod, only : empty_real_data
! <snip>
if (.not. associated(throughfall, empty_real_data) ) then
do n = 1, n_land_tile
do l = 1, land_pts
throughfall(map_tile(1,ainfo%land_index(l))+n-1) = &
fluxes%tot_tfall_surft(l,n)
end do
end do
end if
Diagnostics from existing fields#
Sometimes, a science scheme will output a diagnostic from a field passed into the science algorithm. In this case, there is no need to declare and initialise a local field, but the field still needs to be sent to the diagnostic system.
Commonly, such fields are prognostics passed into the science scheme within a
field collection. Code like the following will obtain a pointer to the
canopy_water field from the surface_fields field collection so that
its value can be computed or updated:
type( field_collection_type ), intent(inout) :: surface_fields
type( field_type ), pointer :: canopy_water
call surface_fields%get_field('canopy_water', canopy_water)
By default, the write_field method passes the field name to XIOS which is
matched to the IDs in the iodef.xml file. For diagnostic output, the
field’s name needs to be overridden by passing the name of the diagnostic to
the write method:
! Prognostic fields
call canopy_water%write_field('surface__canopy_water')
Passing surface__canopy_water means the field will be identified as a
diagnostic rather than as the canopy_water prognostic. It will then be
written to files that include diagnostic requests with that ID.
Note that as there is no call to init_diag for an existing field, there is
no flag to determine whether or not the field needs to be sent to the IO
system. Calling the write method on a diagnostic that was not requested is not
a problem: the underlying IO system is capable of ignoring the request.
Initial diagnostics#
The LFRic atmosphere diagnostic definition includes a file called
field_def_initial_diags.xml that defines a set of “initial” diagnostics
which are essentially the prognostic fields before the model has started
running. If requested (by setting write_diag=.true in the namelist
configuration) these fields are written out as a group at the very start of a
run just after reading the starting conditions into the model prognostic
fields.
The initial diagnostics may be useful to analyse issues where it is believed one of the fields is wrong just after it is read in.
If a new field is added to the start dump, then a new record can be added to
the XML file which is a copy of the prognostic record(typically included in
the lfric_dictionary.xml file), but with its ID prefixed with init_.
Explicit code to write the prognostic field as a diagnostic is added to the
gungho_diagnostics_driver_mod module.