MARBL does not yet have a stand-alone test to provide a list of requested saved state fields, but marbl_saved_state_init()
shows that there are four saved state fields - two for the surface and two for the interior.
The two surface fields are surface pH
and surface pH (alternate CO2)
:
call surface_state%construct(num_elements_surface_flux, num_levels)
lname = 'surface pH'
sname = 'PH_SURF'
units = 'pH'
vgrid = 'none'
rank = 2
call surface_state%add_state(lname, sname, units, vgrid, rank, &
surf_ind%ph_surf, marbl_status_log)
if (marbl_status_log%labort_marbl) then
call marbl_status_log%log_error_trace("add_state(PH_SURF)", subname)
return
end if
lname = 'surface pH (alternate CO2)'
sname = 'PH_SURF_ALT_CO2'
units = 'pH'
vgrid = 'none'
rank = 2
call surface_state%add_state(lname, sname, units, vgrid, rank, &
surf_ind%ph_alt_co2_surf, marbl_status_log)
if (marbl_status_log%labort_marbl) then
call marbl_status_log%log_error_trace("add_state(PH_SURF_ALT_CO2)", subname)
return
end if
The two interior state fields are 3D pH
and 3D pH (alternate CO2)
call interior_state%construct(num_elements_interior_tendency, num_levels)
lname = '3D pH'
sname = 'PH_3D'
units = 'pH'
vgrid = 'layer_avg'
rank = 3
call interior_state%add_state(lname, sname, units, vgrid, rank, &
interior_ind%ph_col, marbl_status_log)
if (marbl_status_log%labort_marbl) then
call marbl_status_log%log_error_trace("add_state(PH_3D)", subname)
return
end if
lname = '3D pH (alternate CO2)'
sname = 'PH_3D_ALT_CO2'
units = 'pH'
vgrid = 'layer_avg'
rank = 3
call interior_state%add_state(lname, sname, units, vgrid, rank, &
interior_ind%ph_alt_co2_col, marbl_status_log)
if (marbl_status_log%labort_marbl) then
call marbl_status_log%log_error_trace("add_state(PH_3D_ALT_CO2)", subname)
return
end if
The pH computation is an iterative solver, and it has proven useful to use the pH at timestep t
as an initial value when solving for time t+1
.
MARBL splits the saved state fields between those needed for computing surface fluxes and those needed for computing interior tendencies, so on the interface we have
type, public :: marbl_interface_class
.
.
.
type(marbl_saved_state_type) , public :: surface_flux_saved_state ! input/output
type(marbl_saved_state_type) , public :: interior_tendency_saved_state ! input/output
.
.
.
end type marbl_interface_class
The marbl_saved_state_type
is a wrapper for marbl_single_saved_state_type
:
type, public :: marbl_single_saved_state_type
integer :: rank
character(len=char_len) :: long_name
character(len=char_len) :: short_name
character(len=char_len) :: units
character(len=char_len) :: vertical_grid ! 'none', 'layer_avg', 'layer_iface'
real(r8), allocatable, dimension(:) :: field_2d ! num_elements
real(r8), allocatable, dimension(:,:) :: field_3d ! num_levels, num_elements
contains
procedure :: construct => marbl_single_saved_state_construct
end type marbl_single_saved_state_type
!*****************************************************************************
type, public :: marbl_saved_state_type
integer :: saved_state_cnt
integer :: num_elements
integer :: num_levels
type(marbl_single_saved_state_type), dimension(:), pointer :: state => NULL()
contains
procedure, public :: construct => marbl_saved_state_constructor
procedure, public :: add_state => marbl_saved_state_add
end type marbl_saved_state_type
After marbl_instance%surface_flux_compute()
returns, the GCM needs to process marbl_instance%surface_flux_saved_state
.
That means looping through each element in the marbl_instance%surface_flux_saved_state%state(:)
array, checking state(n)%rank
,
and then storing either state(n)%field_2d
or state(n)%field_3d
in a global array.
Before calling surface_flux_compute()
in the next time step, these saved values should be copied back into marbl_intance%surface_flux_saved_state
.
Similar actions must be taken with marbl_instance%interior_tendency_saved_state
before / after calls to marbl_instance%interior_tendency_compute()
.