Classes and Configuration

This page describes the classes that are implemented in FV3-JEDI. It explains in broad terms what they are responsible for, how they are implemented and explains the configuration options that are available for controlling their behavior.

FieldMetadata

FV3-JEDI has default fields defined in the system. The fields are first set in the FieldMetadata class, then any field that has been set can be instantiated at any point in the system by adding the name of that field to the variable list. When selecting the variable the user can choose from one of the long name, short name or IO name described below.

Using the definition of the field ud as an example, the complete set of metadata for a field is as follows:

longName = "u_component_of_native_D_grid_wind";
shortName = "ud";
units = "ms-1";
kind = "double";
tracer = "false";
horizontalStaggerLocation = "northsouth";
levels = "full";
space = "vector";

longName is a string providing the long name for the variable, typically using the standard (CF) name. The main effect of this choice is how each field is named in the prints of State and Increment in the log files.

shortName is a string with the name that FV3-JEDI uses internally to interact with the Field. The Field class detailed below provides a number of methods for obtaining a field and this is value that is used to access the field. Note that you can also use the long name to interact with the field within the FV3-JEDI code.

units is a string representing the units of the field.

kind is a string giving the precision of the variable. It can be double or integer. If the field is integer it is not actually stored as an integer but the flag allows for special treatment where necessary. A special interpolation scheme is used for integer fields for example.

tracer is boolean flag that can be set to true or false.

horizontalStaggerLocation is a string representing the position within the horizontal grid cell that the field is stored. The options are center, northsouth, eastwest or corner.

levels is a string providing the number of layers for the field. Values can be full, meaning the field is stored at the mid-point of each layer, half meaning it stored at the model levels or halfplusone meaning it is stored also at an additional level above the top of the domain. Alternatively, it can be an integer representing the vertical dimension. Surface variables would be “1”.

space is a string representing the kind of data the field encompasses. Valid choices are magnitude, vector or direction. This choice is important when it comes to how a field gets interpolated. Fields that are vectors require special attention when doing interpolation and fields that are a direction are interpolated using nearest neighbor.

Users can add and overwrite part of these default fields metadata by setting field metadata override in the geometry subsection of the yaml. They do not have to make changes to the source code.

For example:

geometry:
  [...]
  field metadata override: Data/fieldmetadata/gfs-restart.yaml

With the content of gfs-restart.yaml being a list of fields to be modified:

field meta data:

- long name: u_component_of_native_D_grid_wind
  io name: u

- long name: smc
  io file: surface

The following fieldmetadata can be modified: long name is mandatory, to say which variable you are overriding the other metadata of. However long name itself cannot be overridden since it’s the anchor to everything else.

io name is a string giving the name of the field in the file from which it is being read and written to. This might take different values for different models or different kinds of files

units is a string to provide the units

io file is a string which provides some optional metadata that can be used to make decisions about which file a variable is read from and to.

interpolation type is a string whose values can be “integer”, “nearest” or “default”. The default is integer if “kind” is integer, nearest if “space” is “direction” and default in all other cases.

Geometry

The Geometry class is responsible for creating and storing the FV3 cubed-sphere grid structure. It accomplishes the generation of the FV3 grid by calling the routine fv_control_init that lives within the FV3 model. The code is provided with three interfaces to fv_control_init to cover the way it is handled in the current version of FV3, legacy versions of FV3 and GEOS. It will automatically build the correct version depending on the choice of model that FV3-JEDI is built with.

FV3 routines like fv_control_init expect there to be a file called input.nml present in the run directory. This file controls many aspects of the way in which FV3 behaves, from the resolution and processor layout to whether the dynamical core is hydrostatic. In forecasts involving FV3 this file is typically static and is placed into the directory ahead of time. For data assimilation applications, where there are often multiple resolutions involved, it is not possible to have a static input.nml file. Instead, the file is dynamically created or versions of it are moved in and out of the directory as needed during the runs. The source code will handle the placement and removal of input.nml but the user is responsible for which file is used or how it is created.

In order to use an already constructed input.nml file the user can provide namelist filename in the geometry config as follows:

geometry:
  namelist filename: Data/fv3files/input_gfs_c12_p12.nml

Note that the file can be located somewhere other than the run directory.

In order to dynamically generate input.nml the user can input the separate parts of the file as follows:

geometry:
  layout: [1,1]     # optional, default values are [1,1]
  io_layout: [1,1]  # optional, default values are [1,1]
  npx: 13
  npy: 13
  npz: 127
  ntiles: 6         # optional, default value is 6

The table below describes the role of each entry in the above Yaml

Configuration

Description

layout: [1,1]

The processor layout on each face of the cube

io_layout: [1,1]

The processor layout for doing IO

npx

The number of grid vertices in east-west direction

npy

The number of grid vertices in north-south direction

npz

The number of vertical layers

niles

The number of faces of the cube (6 for global domain)

The above example will generate a cubed sphere grid with 13 grid points along each face of the cube sphere; in FV3 nomenclature this would be referred to as a ‘C12’ grid, i.e., with 12 cells along each side of the cube face. Most fields live at grid centers and these would have 12x12x6 values. The processor layout on each face is [1,1] meaning a total of 1x1x6 processors are needed. Note that 6 is the minimum number of processors that FV3 can be used with. If the layout was changed to layout: [1,2] then the number of required processors would be 12.

The variable io_layout tells the system how many ‘tile’ files to write when using FSM restarts. In almost all cases this is set to io_layout: [1,1], which is the default. This choice results in 6 files being written or read, one per face of the cube. Note that the choice must match any restart files being read. If there are 6 files they cannot be read by 12 processors.

Above is the minimal information that needs to be inside input.nml in order to properly generate the geometry. After fv_control_init has been called there exists a much larger data structure that also contains model fields. The relevant geometry fields are extracted and it is deallocated. Later on when the model is initialized a more extensive version of input.nml is required in order to run the forecast.

The geometry configuration needs to contain a number of other things in addition to what is required to generate input.nml. These are shown below:

geometry:
  fms initialization:
    namelist filename: Data/fv3files/fmsmpp.nml
    field table filename: Data/fv3files/field_table_gfdl
  akbk: Data/fv3files/akbk127.nc4
  field metadata override: Data/fieldmetadata/gfs-restart.yaml  # optional
  interpolation method: 'bump'  # optional, default value is 'barycent'
  write geom: true              # optional, default value is 'false'

Since the Geometry needs to call FV3, which in turn calls methods in the FMS library, it is necessary to initialize the FMS library. This is done only once and during the first call to Geometry. The initialize of FMS requires an input.nml file like the initialize of FV3 needs. The configuration fms initialization.namelist filename is where this file is provided, an example of which is available in the repository.

The field table filename provides a list of tracers that the model will use. Though this is not explicitly part of the Geometry this needs to be provided for FV3 and FMS to run. Inside these libraries the tracer variables are set as global variables and so have to be selected during the first call to the initialize steps, which occurs in the Geometry class rather than the Model class.

The akbk variable provides a path to a file containing the coefficients which define the hybrid sigma-pressure vertical coordinate used in FV3. Files are provided with the repository containing ak and bk for some common choices of vertical resolution for GEOS and GFS.

The optional argument write geom tells the code to write the longitude and latitude values to a netCDF file. This file can be ingested in the multi-grid Poisson solver or used to plot the grid points.

The argument interpolation method determines the interpolation method to be used in the system. The options are ‘bump’ to use the interpolation method provided with BUMP/SABER or ‘barycent’ to use the unstructured interpolation method from OOPS.

The field metadata override optionally provides a yaml file overwriting some defaults fields that the system will be able to allocate. The contents of these files are described in FieldMetadata. This process is undertaken in the Geometry because it involves things like the number of model levels when setting the metadata. Further, the constructors for States and Increments do not necessarily receive configuration so setting the FieldMetadata there would not be straightforward.

FV3-JEDI does not only support the global FV3 Geometry. It can also be used to generate nested and regional domains. The regional domain cannot be generated on the fly and has to be read from files. Users need to provide the geometry.fms initialization.field table filename as follow:

geometry:
  fms initialization:
    namelist filename: Data/fv3files/fmsmpp.nml
    field table filename: Data/fv3files/field_table_lam_cmaq
  namelist filename: Data/fv3files/input_lam_cmaq.nml
  akbk: Data/fv3files/akbk64.nc4
  field metadata override: Data/fieldmetadata/gfs-aerosol.yaml

Nested grids can be constructed by providing an input.nml that sets up a nested grid through the geometry.namelist filename or by dynamically generating the input.nml with the following additional options:

geometry:
  layout: [1,1]
  io_layout: [1,1]
  npx: 13
  npy: 13
  npz: 127
  ntiles: 6
  nested: true
  do_schmidt: true
  target_lat: 39.50
  target_lon: -98.35
  stretch_fac: 2.0

In the above nested tells the system to setup a nested grid. Quantities do_schmidt, target_lat, target_lon and stretch_fac tell FV3 to do a stretching and where to center the higher resolution region.

State / Increment / Fields

The State and Increment classes in FV3-JEDI have a fair amount of overlap between them. The constructors are largely the same and they share a number of methods, such as read and write and computing of norms. In order to simplify the code FV3-JEDI implements a Fields class at the Fortran level, and both State and Increment inherit from this Fields base class.

The main data structure in the Fields class is an array of type Field (no ‘s’):

type :: fv3jedi_fields

  type(fv3jedi_field), allocatable :: fields(:)             ! Array of fields

endtype fv3jedi_fields

The only specialization the State and Increment add to the Fields class are methods specific to each.

The user interaction with the State and Increment classes extends to choosing which fields will actually be allocated and to provide paths to files that must be read or written to. The configuration as it relates to IO is discussed below in the IO section.

As an example for creating a State, the variables are chosen in the configuration as:

state variables: [u,v,T,DELP]

The strings in the list of variables are the names of the Fields as they are in the file that is going to be read. The below example shows how the list of fields are allocated in the Fields class:

! Allocate fields structure
! -------------------------
self%nf = vars%nvars()
allocate(self%fields(self%nf))

! Loop through and allocate actual fields
! ---------------------------------------
fc = 0
do var = 1, vars%nvars()

  ! Uptick counter
  fc=fc+1;

  ! Set this fields meta data
  call create_field(self%fields(fc), geom%fields%get_field(trim(vars%variable(var))), geom%f_comm)

enddo

And the content of create_field:

subroutine create_field(self, fmd, comm)

  ! Copy metadata
  ! -------------
  self%long_name = fmd%long_name
  self%short_name = fmd%short_name
  self%units = fmd%units
  self%kind = fmd%kind
  self%tracer = fmd%tracer
  self%horizontal_stagger_location = fmd%horizontal_stagger_location
  self%npz = fmd%levels
  self%space = fmd%space
  self%io_name = fmd%io_name
  self%io_file = fmd%io_file
  self%interpolation_type = fmd%interpolation_type

end subroutine create_field

In this example the loop traverses the four variables in the list of state variables. The first thing that is done is to call the FieldMetadata Fortran API and collect the metadata based on the variable name string, which can be either longName, shortName or be overwritten by the user in io name (see FieldMetadata).

Field accessor functions

The Fields and Field classes provide a number of accessor functions in order to obtain actual field data that can be used or manipulated.

Whenever using these accessor functions the string used to reference the field is the shortName or longName but not the io name. This it to ensure there is a consistent and predictable way of getting the field regardless of the way a variable is named in whatever file is being read. For example, the file being read may have temperature stored as ‘t’ while another file from a different model may have ‘T’. In the yaml configuration file the user would choose either ‘t’ or ‘T’ depending on which is in the file. In the source code this particular variable would only ever be accessed using ‘t’, which is the shortName for temperature. It could also be accessed with ‘air_temperature’, which is the longName.

There are three accessor functions, has_field, get_field and put_field and each function has several interfaces.

The function has_field queries whether a field with a particular shortName or longName is present. An example of the interface is show below. This code snippet shows two possible interfaces to has_field, where the array of fields is passed explicitly and where it is called from the class. Optionally the index in the array can be returned from the method.

! Check whether state fields contain temperature
have_temp = has_field(state%fields, 't', t_index)

! Check whether state fields contain temperature
have_temp = state%has_field('t')

The subroutine get_field can be used to return the field data with a particular shortName or longName, aborting if the field is not present. The method can return the field in three different formats, as a pointer to the array, a copy of the array or as a pointer to the entire field type. The below shows these three ways of using the method:

! Get a pointer to the field data
real(kind=kind_real), pointer :: t(:,:,:)
call state%get_field('t', t)

! Get a copy of the field data
real(kind=kind_real), allocatable :: t(:,:,:)
call state%get_field('t', t)

! Get a pointer to the field structure
type(fv3jedi_field), pointer :: t
call state%get_field('t', t)

Like the has_field method, the get_field method can be used by passing the array of field, call get_field(state%fields, 't', t).

The third accessor function is put_field, which has the exact same interfaces as get_field except it overwrites the internal field data with the input data.

Note that FV3-JEDI only supports rank 3 fields. Fields that are surface quantities simply have size 1 in the third dimension. Quantities such as tracers are stored as individual rank 3 arrays and not in one large array. Performing processes on tracers, for example to remove negative values, can be achieved using the tracer flag in the FieldMetadata.

IO

Input/Output (IO) in FV3-JEDI appears in its own directory, although it is not technically its own interface class. The methods read and write are part of State and Increment (Fields) but are also designed to be accessible from other parts of the code. The IO methods do not interact with the State and Increment objects, only the Fields base class.

There are three IO classes provided: The CubeSphereHistory is for interacting with cube sphere history files and restarts as output by the GEOS model. The FV3Restart is for interacting with restarts for the GFS/UFS model. The LatLon is for use with the latlon grid.

Which class to use is controlled by the configuration as follows:

# Read a GEOS file
statefile:
  filetype: cube sphere history

# Read a GFS file
statefile:
  filetype: fms restart

# Read a latlon file
statefile:
  filetype: latlon

The below shows all the potential configuration for reading or writing a GEOS file.

statefile:
  datetime: 2020-12-15T00:00:00Z
  # Use GEOS IO
  filetype: cube sphere history
  provider: geos
  # Path where file is located
  datapath: Data/input/geos_c12/
  # Filenames for the different groups
  filenames: [geos.bkg.20201215_000000z.nc4, geos.bkg.crtmsrf.20201215_000000z.nc4]
  state variables: [ua,va,t,ps,q,qi,ql,qr,qs,o3ppmv,phis,vtype,stype,vfrac]
  tile is a dimension: [true, true]       # Optional, default is 'true'
  clobber existing files: [false, false]  # Optional, default is 'true'
  psinfile: false                         # Optional, default is 'false'

For GEOS the code writes all fields into a single file. During read the code will search for the field across the list of input files provided by the user.

GEOS can write cube sphere files in two ways, one is with a dimension of the variables being the tile number, where tile is synonymous with cube face. The other is to write with the 6 tiles concatenated to give dimensions of nx by 6*nx. FV3-JEDI assumes that the files include the tile dimension but it can also work with files with concatenated tiles, by setting tile is a dimension: [false]. Note that if you provided a list of files in filenames you will need to provide a list of booleans in tile is a dimension.

The default behavior for all the IO is to clobber the file being written to, that is to say that any existing file is completely overwritten. By setting clobber existing files: [false] this can be overridden so that and fields in the file that FV3-JEDI is not attempting to write remain intact. Note that if you provided a list of files in filenames you will need to provide a list of booleans in clobber existing files.

The code below shows all the potential configuration for reading a GFS restart file:

statefile:
  # Use GFS IO
  filetype: fms restart
  # Path where file is located
  datapath: Data/inputs/gfs_c12/bkg/
  # GFS restart files that can be read/written
  filename_core: fv_core.res.nc
  filename_trcr: fv_tracer.res.nc
  filename_sfcd: sfc_data.nc
  filename_sfcw: fv_srf_wnd.res.nc
  filename_cplr: coupler.res
  filename_spec: gridspec.nc
  filename_phys: phy_data.nc
  filename_orog: oro_data.nc
  filename_cold: gfs_data.nc
  psinfile: false                         # Optional, default is 'false'
  skip coupler file: false                # Optional, default is 'false'
  prepend files with date: true           # Optional, default is 'true'

For GFS restarts certain fields are expected to be in certain files. The mapping between file and field name is hardcoded but can be overridden using IOFile: core in the FieldMetadata override. The restarts include one text file filename_cplr: coupler.res that contains metadata for the restart. Note that reading this coupler file can be disabled with skip coupler file: false when it is not available and FV3-JEDI does not need the date and time information. The keys filename_cold, filename_orog and filename_phys are included for completeness but are used infrequently. The files referenced by these keys files do not contain fields the data assimilation system would normally interact with.

The fields more typically used are contained in the files referenced with: filename_core, which contains the main dynamics fields; filename_trcr, which contains the tracers; filename_sfcd, which contains the surface fields; filename_sfcw, which contains the surface winds.

GFS offers the ability to convert from pressure thickness to surface pressure automatically during the read. The behavior can be turned off and surface pressure read directly from the file using the flag psinfile: true.

By default, when the output for GFS is written the files are prepended with the date so they might look like, for example, “20200101_00000.fv_core.res.tile1.nc”. This can be turned off with prepend files with date: false.

Model

The Model class is where FV3-JEDI interacts with the actual forecast model. FV3-JEDI is capable of using the forecast models in-core with data assimilation applications as well as interacting with the models through files. The choice whether to interact with the model in-core depends on the application being run. For example, there can be much benefit to being in-core for a multiple outer loop 4DVar data assimilation system or when running H(x) calculations. However, there is no benefit to including the model for a 3DVar application and indeed the model is never instantiated in those kinds of applications.

Other than in the IO routines, the code in the other classes is identical regardless of the underlying FV3-based model, whether it be GEOS or GFS. In the Model class the code depends heavily on the underlying model. Although all the models use FV3, they have differing infrastructure around them.

Instantiation of Model objects is controlled through a factory. The only thing limiting which can be compiled is the presence of the model itself and making sure that there are not multiple versions of FV3 being linked to. Which models can be built with is described in the Choosing an FV3-based model to build with section. At run time the model that is used is chosen through the configuration key name as follows:

# Instantiate the GEOS model object
model:
  name: GEOS
# Instantiate the UFS model object
model:
  name: UFS

The current options are GEOS, UFS, FV3LM and Pseudo

GEOS

The configuration for the GEOS model needs to include the time step for the model, a path to a directory where GEOS can be run from and the variables, which contains a list of fields within GEOS that need to be accessed. The geos_run_directory is a directory that contains restarts, boundary conditions, configurations and any other files that are needed in order to run GEOS. This directory is created ahead of making any forecasts involving GEOS. During the run the system will change directory to the the geos_run_directory.

model:
  name: GEOS
  tstep: PT30M
  geos_run_directory: Data/ModelRunDirs/GEOS/
  model variables: [U,V,PT,PKZ,PE,Q,QILS,QLLS,QICN,QLCN]

GFS/UFS

Interfacing FV3-JEDI to the UFS model through the NUOPC driver is an ongoing effort and all the features are not fully supported yet.

The configuration needs to include the time step for the model, a path to a directory where UFS can be run from and the variables, which contains a list of fields within UFS that need to be accessed. The ufs_run_directory is a directory that contains restarts, boundary conditions, configurations and any other files that are needed in order to run UFS. This directory is created ahead of making any forecasts involving UFS. During the run the system will change directory to the the ufs_run_directory.

model:
  name: UFS
  tstep: PT1H
  ufs_run_directory: Data/ModelDirs/ufs/stc
  model variables: [u,v,ua,va,t,delp,q,qi,ql,o3mr,phis,
                    qls,qcn,cfcn,frocean,frland,varflt,ustar,bstar,
                    zpbl,cm,ct,cq,kcbl,tsm,khl,khu]

Pseudo model

The pseudo model can be used with GFS or GEOS. All this model does is read states from disk that are valid at the end of the time step being ‘propagated’. The configuration for pseudo model is very similar to that described in IO. However, when referring to a file instead of using, for example, filename_core: 20200101_000000.fv_core.res.nc the correct syntax would be filename_core: %yyyy%mm%dd.%hh%MM%ss.fv_core.res.nc. The system will pick the correct date for the file based on the time of the model.

Note that OOPS provides a generic pseudo model, which is demonstrated in the hofx_nomodel test. The advantage of using the FV3-JEDI pseudo model is that the yaml only requires a single entry with templated date and time; in the OOPS pseudo model a list of states to read is provided. Another advantage is that in data assimilation applications involving the model, such as 4DVar, the application propagates the model through the window after the analysis in order to compute ‘o minus a’. This second propagation of the model is not useful with any pseudo model and can be turned off in the FV3-JEDI pseudo model by specifying run stage check: true as shown in this example:

model:
  name: PSEUDO
  filetype: cube sphere history
  provider: geos
  datapath: Data/inputs/geos_c12
  filenames: [geos.bkg.%yyyy%mm%dd_%hh%MM%ssz.nc4, geos.bkg.crtmsrf.%yyyy%mm%dd_%hh%MM%ssz.nc4]
  run stage check: true
  tstep: PT1H
  model variables: [u,v,ua,va,t,delp,q,qi,ql,o3ppmv,phis,
                    qls,qcn,cfcn,frocean,frland,varflt,ustar,bstar,
                    zpbl,cm,ct,cq,kcbl,tsm,khl,khu,frlake,frseaice,vtype,
                    stype,vfrac,sheleg,ts,soilt,soilm,u10m,v10m]

FV3 core model

FV3-JEDI interfaces to the standalone version of the FV3 dynamical core. This is used primarily for testing purposes and particularly to test applications that need an evolving and rewindable model without the long run times and complexity of the model with full physics and complex infrastructure. Below shows an example configuration for the standalone model:

model:
  name: FV3LM
  use internal namelist: true
  tstep: PT15M
  lm_do_dyn: 1     # Run the dynamical core component
  lm_do_trb: 0     # Run the turbulence core component
  lm_do_mst: 0     # Run the convection and microphysics components
  model variables: [u,v,T,DELP,sphum,ice_wat,liq_wat,o3mr,phis]

Similar to the Geometry, the Model needs an input.nml and field_table file to be provided so these are passed in through the model configuration. Setting use internal namelist: true makes the Model use the same files as the geometry. The user needs to set a value for the different lm_do_ settings, and it is also necessary to provide the time step and list of variables that the model will provide.

TLM

FV3-JEDI ships with a linearized version of the FV3 dynamical core named FV3-JEDI-LINEARMODEL. Note that the linear model comes in a separate repository though it builds only as part of FV3-JEDI. The linear model is a global model only and does not currently support regional and nested domains.

An example of the configuration is shown below.

linear model:
  name: FV3JEDITLM   # Name of the LinearModel in the factory
  # FV3 required files
  namelist filename: Data/fv3files/input_gfs_c12.nml
  linear model namelist filename: Data/fv3files/inputpert_4dvar.nml
  tstep: PT15M     # Time step
  lm_do_dyn: 1     # Run the dynamical core component
  lm_do_trb: 0     # Run the turbulence core component
  lm_do_mst: 0     # Run the convection and microphysics components
  # Variables in the linear model
  tlm variables: [u,v,T,DELP,sphum,ice_wat,liq_wat,o3mr]
  trajectory:
    model variables: [u,v,T,DELP,sphum,ice_wat,liq_wat,o3mr]

The linear model requires the same input.nml file that the nonlinear version of FV3 needs. In addition is needs an inputpert.nml file, which is provided through the linear model namelist filename keyword. The different components of the linearized model can be turned on and off with the lm_do_ keywords. The three components are the dynamical core, the turbulence scheme and the linearized moist physics.

The forecast model outputs a lot of variables and not all of them are required in the trajectory of the linear model. The trajectory.model variables contains the list of variables output from the model that are passed to the linear model for it to populate its trajectory.

ObsLocalization

The different ObsLocalization methods are controlled through a factory.

For now there is one in the fv3-jedi repository: the vertical Brasnett 99 observation space localization for snow DA.

LinearVariableChange and nonlinear VariableChange

FV3-JEDI has a number of linear and nonlinear variable changes which are used to transform between increments or states with different sets of variables. These variable changes are used to go between different components of the system where different variables might be required.

Variable changes are constructed using factories, so are chosen through the configuration. Some variable changes require additional configuration and some require nothing additional. The details of each configuration is outlined below.

Many of the variable changes take on the same general format structure, outlined in the following steps.

  1. The first step is to copy all the variables that are present in both input and output states and increments.

! Array of variables that cannot be obtained from input
character(len=field_clen), allocatable :: fields_to_do(:)

! Copy fields that are the same in both
call copy_subset(xin%fields, xout%fields, fields_to_do)

The copy_subset routine identifies the variables in both and copies the data from input to output. Optionally it returns a list of variables that are in the output that are not in the input, i.e., the list of variables that need to be derived from the inputs.

  1. The second step is to prepare all the potential output variables that might be needed. The below provides an example of how temperature could be prepared from various inputs:

! Temperature
logical :: have_temp
real(kind=kind_real), pointer     ::    pt(:,:,:)     ! Potential temperature
real(kind=kind_real), allocatable ::   pkz(:,:,:)     ! Pressure ^ kappa
real(kind=kind_real), allocatable ::     t(:,:,:)     ! Temperature

have_temp = .false.
if (xana%has_field('pt')) then
  allocate(t(geom%isc:geom%iec,geom%jsc:geom%jec,1:geom%npz))
  call xana%get_field('pt', pt)
  if (xana%has_field('pkz')) then
    call xana%get_field('pkz', pkz)
    have_temp = .true.
  elseif (have_pres) then
    allocate( pkz(geom%isc:geom%iec,geom%jsc:geom%jec,1:geom%npz))
    call ps_to_pkz(geom, ps, pkz)
    have_temp = .true.
  endif
  if (have_temp) call pt_to_t(geom, pkz, pt, t)
endif

Note that variables that are not necessarily needed to provide another variable are typically pointers. Variables that are obtained one of multiple ways are typically allocatable arrays. The boolean variable have_temp determines that a variable, in this case temperature, is now available.

  1. The third step is to loop through the output variables that could not be copied and attempt to get them from the prepared variables.

! Loop over the fields not found in the input state and work through cases
! ------------------------------------------------------------------------
do f = 1, size(fields_to_do)

  call xctl%get_field(trim(fields_to_do(f)),  field_ptr)

  select case (trim(fields_to_do(f)))

  ! Temperature case
  case ("t")

    if (.not. have_temp) call field_fail(fields_to_do(f))
    field_ptr = t

  end select

end do

If the variable has not been prepared the variable change will fail, otherwise the field_ptr = t will overwrite the field data with the prepared variable.

Base

All the different Variable Change expand the VariableChangeBase class. The base class holds the variable change name key and initiates the Variable Change factory.

Analysis2Model

The analysis to model variable change is used to transform between the background variables (the variables that will be analyzed) and the variables used to drive the model.

variable change:
  variable change name: Analysis2Model

The linear analysis to model variable change is used to transform between the analysis increment and the linear model. The linear version does not require any configuration.

ColdStartWinds

The cold start winds variable change is specific to the GFS model. GFS cold starts are obtained when re-gridding from different grids or resolutions. In this variable transform the cold start winds are converted to the D-Grid winds needed to drive the FV3 model. There is no configuration for this variable change, except to choose to use it through the factory. There is only a nonlinear version of the variable change.

variable change:
  variable change name: ColdStartWinds

Control2Analysis

The control to analysis variable change converts from the control variables (here the variables used in the B matrix) to the analysis variables. In the variational assimilation algorithm only the linear version of this variable change is needed but a nonlinear version is provided to the purpose of training the covariance model.

For the NWP applications the control variables are typically stream function and velocity potential while the analysis variables are winds. To transform between stream function and wind requires a straightforward derivative operator but the inverse transforms require the use of a Poisson solver to solve the inverse Laplacian after transforming from winds to vorticity and divergence. A Finite Element Mesh Poisson Solver (FEMPS) is provided as part of FV3-BUNDLE and is linked to in the variable transform. When converting without using FEMPS no configuration is required. When using FEMPS the configuration options are show below:

variable change:
  variable change name: Control2Analysis
  femps_iterations: 50      # Number of iterations of the Poisson solver
  femps_ngrids: 2           # Number of grids in the multigrid heirachy
  femps_levelprocs: -1      # Number of levels per processor (-1 to automatically distribute)
  femps_path2fv3gridfiles: Data/femps   # Path containing geometry files for the multigrid

GEOSRstToBkg

The GEOSRstToBkg variable change is specific to the GEOS model and is used to convert from GEOS restart file like variables to so-called background like variables. Restart variables include D-Grid winds, potential temperature and pressure the to the kappa while background variables are A-Grid winds, temperature and surface pressure.

Currently this variable change works slightly differently to the others in that you need to specify, through the configuration, which variables need to be transformed. The choices are made with the key do_ as show below:

variable change:
  variable change name: GeosRst2Bkg
  do_clouds: true
  do_wind: true
  do_temperature: true
  do_pressure: true
  pres_var: delp

The keyword pres_var controls which pressure variable in the background is used to determine the pressure variables in the restart.

Model2GeoVaLs

The Model2GeoVaLs variable change is used between running the model and calling the observation operator. It transforms between the model variables and the variables called for by each observation operator.

There is also a linear version of this variable change that is used before and after calling the linearized observation operators.

The user does not interact with the Model2GeoVaLs through the configuration. However, it is often necessary to modify the source code in this variable change when adding a new variable to the UFO or starting to use an observation operator that has not been used in FV3-JEDI before and requires a variable not previously prepared.

VertRemap

The vertical remapping variable change is used primarily in conjunction with the ColdStartWinds variable change in order to convert from cold start variables to warm start variables. It can also be used to do a straightforward remapping when necessary, for example when the surface pressure has changed.

The configuration for the transform is quite extensive but most is related to initializing the FV3 data structure and is similar to what is used in the Geometry. Since the methods make calls into FV3, it is necessary to initialize an FV3 structure to pass in. In addition, the user can specify whether the inputs are cold starts, which have specific variable names. This would be set to false in the case where the variable change is not being used for cold starts and is being used as part of some other applications. The final thing that needs to be specified is the source of inputs, which is a string controlling how the transform behaves internally in FV3; this is unlikely to be changed from the default values.

# Name of variable change in the factory
variable change:
  variable change name: VertRemap
  # Is the variable change being used in the context of remapping cold starts?
  input is cold starts: true
  # Configuration needed to initialize FV3
  npx: 13
  npy: 13
  npz: 127
  nwat: 6
  hydrostatic: false
  source of inputs: FV3GFS GAUSSIAN NETCDF FILE # Type of inputs to the variable change