Skip to content

Commit

Permalink
Update documentation to include output_for_GCM
Browse files Browse the repository at this point in the history
A new page explains what additional output is available from the GCM, and a
second page shows how to add a new output. The new available_output test is
also documented on the regression tests page.
  • Loading branch information
mnlevy1981 committed Feb 26, 2024
1 parent ef58f3b commit 1c59f37
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 3 deletions.
145 changes: 145 additions & 0 deletions docs/src/dev-guide/add-ofg.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
.. _add-ofg:

============================
Adding an Output for the GCM
============================

In addition to surface fluxes and interior tendencies, MARBL can provide :ref:`additional output <additional_output>` as well.
These might be fluxes that feed back to the atmosphere, or tracer sums used for other physical properties.
Adding a new output is a straightforward process.

-------------------------------------------------
Step 1. Add to MARBL output for GCM indexing type
-------------------------------------------------

MARBL tracks the internal index of each output for the GCM in the ``output_for_GCM_type`` components of the interface
(``surface_flux_output`` and ``interior_tendency_output``).
There is a module variable in ``marbl_interface_public_types.F90`` of type ``marbl_output_for_GCM_indexing_type``:

.. code block from marbl_interface_public_types
.. code-block:: fortran
type, public :: marbl_output_for_GCM_indexing_type
integer(int_kind) :: flux_o2_id = 0
integer(int_kind) :: flux_co2_id = 0
integer(int_kind) :: flux_nhx_id = 0
integer(int_kind) :: total_surfChl_id = 0
integer(int_kind) :: total_Chl_id = 0
end type marbl_output_for_GCM_indexing_type
type(marbl_output_for_GCM_indexing_type), target, public :: ofg_ind
``ofg_ind`` is a target because there is a registry of all defined outputs for the GCM that use pointers to
make sure the correct index is updated.
Any new outputs for the GCM must have an index added to this indexing type.

---------------------------------------------------
Step 2. Add to MARBL output for GCM output registry
---------------------------------------------------

MARBL tracks what outputs are available via the ``marbl_output_for_GCM_registry_type``.
When a GCM calls ``marbl_instance%add_output_for_GCM()``,
MARBL checks the registry to see if it can provide the output.

.. code block from marbl_interface_public_types
.. code-block:: fortran
type, public :: marbl_output_for_GCM_linked_list_type
character(len=char_len) :: short_name
character(len=char_len) :: long_name
character(len=char_len) :: units
character(len=char_len) :: field_source
character(len=char_len) :: err_message
integer(int_kind), pointer :: id
type(marbl_output_for_GCM_linked_list_type), pointer :: next => NULL()
end type marbl_output_for_GCM_linked_list_type
!*****************************************************************************
type, public :: marbl_output_for_GCM_registry_type
type(marbl_output_for_GCM_linked_list_type), pointer :: registered_outputs
contains
procedure, public :: create_registry
procedure, private :: add_registry_entry
end type marbl_output_for_GCM_registry_type
``create_registry()`` is called during MARBL initialization,
and it makes repeated use of the ``add_registry_entry()`` subroutine.
To add a new output to the registry, copy an existing block and modify appropriately:

.. code block from marbl_interface_public_types
.. code-block:: fortran
! Surface Chlorophyll
err_message = ""
if (.not. base_bio_on) &
err_message = "requires base biotic tracers"
call this%add_registry_entry(short_name = "total_surfChl", &
long_name = "Total Surface Chlorophyll Concentration", &
units = "mg/m^3", &
field_source = "surface_flux", &
id = ofg_ind%total_surfChl_id, &
err_message = err_message)
! Full Depth Chlorophyll
err_message = ""
if (.not. base_bio_on) &
err_message = "requires base biotic tracers"
call this%add_registry_entry(short_name = "total_Chl", &
long_name = "Total Chlorophyll Concentration", &
units = "mg/m^3", &
field_source = "interior_tendency", &
id = ofg_ind%total_Chl_id, &
err_message = err_message)
* ``field_source`` will tell the GCM whether to look for updated values of this output
after calls to ``surface_flux_compute()`` or ``interior_tendency_compute()``.
* If ``err_message`` is an empty string, then this output is available for the GCM.
If MARBL is configured in a way such that this output will not be computed,
``err_message`` should give a concise explanation of why it is unavailable.
MARBL will return the error ``{short_name} {err_message}`` -- for example,
if ``base_bio_on = .false.`` and a GCM requests ``total_Chl`` then MARBL will abort with the message
``total_Chl requires base biotic tracers``.

------------------------------------------------
Step 3. Copy Output into ``output_for_GCM_type``
------------------------------------------------

If ``field_source = "surface_flux"`` you need something like this inside ``surface_flux_compute()``:

.. code block from marbl_surface_flux_mod
.. code-block:: fortran
!-----------------------------------------------------------------------
! Compute surface chlorophyll (if requested by GCM)
!-----------------------------------------------------------------------
if (ofg_ind%total_surfChl_id.ne.0) then
totalChl_loc = c0
do auto_ind = 1,autotroph_cnt
totalChl_loc = totalChl_loc + &
max(c0, tracers_at_surface(:,marbl_tracer_indices%auto_inds(auto_ind)%Chl_ind))
end do
surface_flux_output%outputs_for_GCM(ofg_ind%total_surfChl_id)%forcing_field_0d(:) = totalChl_loc
end if
Otherwise, ``field_source = "interior_tendency"`` and you need something like this inside ``interior_tendency_compute()``:

.. code block from marbl_interior_tendency_mod
.. code-block:: fortran
!-----------------------------------------------------------------------
! Compute Chlorophyll (if requested by GCM)
!-----------------------------------------------------------------------
if (ofg_ind%total_Chl_id.ne.0) then
interior_tendency_output%outputs_for_GCM(ofg_ind%total_Chl_id)%forcing_field_1d(1,:) = c0
do auto_ind = 1,autotroph_cnt
interior_tendency_output%outputs_for_GCM(ofg_ind%total_Chl_id)%forcing_field_1d(1,:) = &
interior_tendency_output%outputs_for_GCM(ofg_ind%total_Chl_id)%forcing_field_1d(1,:) &
+ tracer_local(marbl_tracer_indices%auto_inds(auto_ind)%Chl_ind,:)
end do
end if
Note that, in both examples, the output is only computed and stored if the index is positive.
If the GCM did not request this output,
memory will not be allocated to store it and MARBL won't spend time computing it.
1 change: 1 addition & 0 deletions docs/src/dev-guide/development-examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ Examples of common development tasks.
add-diagnostic.rst
add-settings-parameter.rst
add-tracer.rst
add-ofg.rst

3 changes: 3 additions & 0 deletions docs/src/implementations/pop/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
MARBL examples in POP
=====================

NOTE: POP is no longer being developed, and therefore is no longer keeping up with MARBL developments.
All examples in this section refer to the `marbl0.43.0` tag of MARBL, from May 2023.

.. toctree::
:maxdepth: 1
:caption: Contents:
Expand Down
4 changes: 3 additions & 1 deletion docs/src/implementations/standalone/regression_tests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ to 0 may have relative errors that are O(1).
Other Examples
--------------

There are five subdirectories that provide information on how MARBL is configured, and three are documented elsewhere on
There are six subdirectories that provide information on how MARBL is configured, and three are documented elsewhere on
on this site:

#. ``gen_settings_file/`` generates a :ref:`settings file <marbl_settings.gen>` for a later MARBL run.
#. ``requested_forcings/`` lists the :ref:`forcing fields MARBL needs <forcing_fields>` in a given configuration.
#. ``requested_tracers/`` lists the :ref:`tracer tendencies computed <tracer_state>` in a given configuration.
#. ``available_output/`` lists all the :ref:`additional output fields <additional_output>` available,
and also shows what is unavailable due to configuration settings.

The stand-alone driver can also report what tracers are being restored
(without :ref:`looking at the rest of the forcing fields <restoring_as_forcing>`)
Expand Down
125 changes: 125 additions & 0 deletions docs/src/usr-guide/GCM-interface/additional_output.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
.. _additional_output:

=================
Additional Output
=================

MARBL can provide more output than just surface fluxes and interior tendencies.
For example, MARBL can return the total chlorophyll concentration to the GCM,
which can then be used to compute shortwave absorption.
(MARBL can provide both surface chlorophyll and the full depth chlorophyll field,
since difference shortwave absorption algorithms have different inputs.)
MARBL can also provide the O2, CO2, and NHx fluxes at the surface if the GCM wants those to feedback to the atmosphere.

----------------
Available Fields
----------------

The full list of outputs is available from the ``available_output`` regression test.
In the default configuration, the complete list is

.. block comes from available_output test
.. code-block:: none
------------------------
Available output for GCM
------------------------
1. Total Chlorophyll Concentration
short name: total_Chl
units: mg/m^3
field_source: interior_tendency
2. Total Surface Chlorophyll Concentration
short name: total_surfChl
units: mg/m^3
field_source: surface_flux
3. NHx Surface Emissions
short name: flux_nhx
units: nmol/cm^2/s
field_source: surface_flux
4. Carbon Dioxide Flux
short name: flux_co2
units: nmol/cm^2/s
field_source: surface_flux
5. Oxygen Flux
short name: flux_o2
units: nmol/cm^2/s
field_source: surface_flux
-----------------
Requesting Output
-----------------

By default, MARBL will not return any of the additional output.
To request one or more of these fields,
use the ``add_output_for_GCM()`` function on the MARBL interface:

.. block comes from marbl_interface
.. code-block:: fortran
subroutine add_output_for_GCM(this, num_elements, field_name, output_id, field_source, num_levels)
! Check the registry to see if field_name is provided from surface_flux_compute() or interior_tendency_compute()
! add it to the proper output_for_GCM type, or log a useful error message
use marbl_interface_public_types, only : marbl_output_for_GCM_linked_list_type
class (marbl_interface_class), intent(inout) :: this
character(len=*), intent(in) :: field_name
integer(int_kind), intent(in) :: num_elements
integer(int_kind), intent(out) :: output_id
character(len=*), intent(out) :: field_source
integer(int_kind), optional, intent(in) :: num_levels
The output field ``field_source`` will be ``interior_tendency_output`` or ``surface_flux_output``
component of the MARBL interface type.
The following block of code from the stand-alone driver shows how to request both surface and total chlorophyll.
Note that the driver tracks how many outputs are coming from ``field_source = "surface_flux"``
and how many come from ``field_source = "interior_tendency"``.

.. block comes from marbl_call_compute_subroutines_drv.F90
.. code-block:: fortran
if (base_bio_on) then
do n=1, size(marbl_instances)
call marbl_instances(n)%add_output_for_GCM(num_elements=col_cnt(n), &
field_name="total_surfChl", &
output_id=total_surfChl_id, &
field_source=field_source)
if (marbl_instances(n)%StatusLog%labort_marbl) then
call marbl_instances(n)%StatusLog%log_error_trace('marbl%add_output_for_GCM(total_surfChl)', subname)
return
end if
end do
if (trim(field_source) == "surface_flux") then
sfo_cnt = sfo_cnt+1
else if (trim(field_source) == "interior_tendency") then
ito_cnt = ito_cnt+1
else
write(log_message, "(3A)") "'", trim(field_source), "' is not a recognized field source (total_surfChl)"
call driver_status_log%log_error(log_message, subname)
return
end if
end if
if (base_bio_on) then
do n=1, size(marbl_instances)
call marbl_instances(n)%add_output_for_GCM(num_elements=col_cnt(n), &
field_name="total_Chl", &
output_id=total_Chl_id, &
num_levels=num_levels, &
field_source=field_source)
if (marbl_instances(n)%StatusLog%labort_marbl) then
call marbl_instances(n)%StatusLog%log_error_trace('marbl%add_output_for_GCM(total_Chl)', subname)
return
end if
end do
if (trim(field_source) == "surface_flux") then
sfo_cnt = sfo_cnt+1
else if (trim(field_source) == "interior_tendency") then
ito_cnt = ito_cnt+1
else
write(log_message, "(3A)") "'", trim(field_source), "' is not a recognized field source (total_Chl)"
call driver_status_log%log_error(log_message, subname)
return
end if
end if
1 change: 1 addition & 0 deletions docs/src/usr-guide/GCM-interface/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ How to Use MARBL in a GCM
GCM_requirements/index.rst
surface_flux.rst
interior_tend.rst
additional_output.rst
shutdown.rst
2 changes: 0 additions & 2 deletions src/marbl_interface_public_types.F90
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ module marbl_interface_public_types
! NOTE: when adding a new surface flux or interior tendency output field
! (a field that the GCM may need to pass to flux coupler), remember
! to add a new index for it as well.
! * There are no interior tendency outputs at this time, so the type
! and ito_ind will need to be created when the first is added
type, public :: marbl_output_for_GCM_indexing_type
integer(int_kind) :: flux_o2_id = 0
integer(int_kind) :: flux_co2_id = 0
Expand Down

0 comments on commit 1c59f37

Please sign in to comment.