Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only allow GCM to request certain output fields if base_bio_on is True #453

Merged
merged 14 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions MARBL_tools/run_test_suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,12 @@ if [ "${STATUS}" == "PASS" ]; then
STATUS=$(check_return $?)
print_status "requested_tracers.py" >> ${RESULTS_CACHE}

# Print all output_for_GCM variables
cd ${MARBL_ROOT}/tests/regression_tests/available_output
(set -x ; ./available_output.py)
STATUS=$(check_return $?)
print_status "available_output.py" >> ${RESULTS_CACHE}

# Initialize MARBL (with MPI)
cd ${MARBL_ROOT}/tests/regression_tests/init
(set -x ; ./init.py --mpitasks 2)
Expand Down
1 change: 1 addition & 0 deletions docs/py_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pylint==2.10.2
Sphinx==1.7.5
alabaster==0.7.13
sphinxcontrib-bibtex==0.4.0
pybtex==0.22
jinja2<3
Expand Down
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

23 changes: 12 additions & 11 deletions docs/src/dev-guide/marbl-interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The class definition is shown below:
type(marbl_forcing_fields_type), allocatable , public :: interior_tendency_forcings(:) ! input
real (r8), allocatable , public :: interior_tendencies(:,:) ! output
type(marbl_interior_tendency_forcing_indexing_type), public :: interior_tendency_forcing_ind ! FIXME #311: should be private
type(marbl_output_for_GCM_type) , public :: interior_tendency_output ! output
type(marbl_diagnostics_type) , public :: interior_tendency_diags ! output

! public data related to computing surface fluxes
Expand All @@ -43,20 +44,20 @@ The class definition is shown below:
type(marbl_diagnostics_type) , public :: surface_flux_diags ! output

! public data - global averages
real (r8) , public, allocatable :: glo_avg_fields_interior_tendency(:) ! output (nfields)
real (r8) , public, allocatable :: glo_avg_averages_interior_tendency(:) ! input (nfields)
real (r8) , public, allocatable :: glo_avg_fields_surface_flux(:,:) ! output (num_elements,nfields)
real (r8) , public, allocatable :: glo_avg_averages_surface_flux(:) ! input (nfields)
real (r8), public, allocatable :: glo_avg_fields_interior_tendency(:) ! output (nfields)
real (r8), public, allocatable :: glo_avg_averages_interior_tendency(:) ! input (nfields)
real (r8), public, allocatable :: glo_avg_fields_surface_flux(:,:) ! output (num_elements,nfields)
real (r8), public, allocatable :: glo_avg_averages_surface_flux(:) ! input (nfields)

! FIXME #77: for now, running means are being computed in the driver
! they will eventually be moved from the interface to inside MARBL
real (r8) , public, allocatable :: glo_scalar_interior_tendency(:)
real (r8) , public, allocatable :: glo_scalar_surface_flux(:)
real (r8), public, allocatable :: glo_scalar_interior_tendency(:)
real (r8), public, allocatable :: glo_scalar_surface_flux(:)

type(marbl_running_mean_0d_type) , public, allocatable :: glo_avg_rmean_interior_tendency(:)
type(marbl_running_mean_0d_type) , public, allocatable :: glo_avg_rmean_surface_flux(:)
type(marbl_running_mean_0d_type) , public, allocatable :: glo_scalar_rmean_interior_tendency(:)
type(marbl_running_mean_0d_type) , public, allocatable :: glo_scalar_rmean_surface_flux(:)
type(marbl_running_mean_0d_type), public, allocatable :: glo_avg_rmean_interior_tendency(:)
type(marbl_running_mean_0d_type), public, allocatable :: glo_avg_rmean_surface_flux(:)
type(marbl_running_mean_0d_type), public, allocatable :: glo_scalar_rmean_interior_tendency(:)
type(marbl_running_mean_0d_type), public, allocatable :: glo_scalar_rmean_surface_flux(:)

! private data
type(unit_system_type), private :: unit_system
Expand All @@ -80,6 +81,7 @@ The class definition is shown below:
type(marbl_internal_timers_type), private :: timers
type(marbl_timer_indexing_type), private :: timer_ids
type(marbl_settings_type), private :: settings
type(marbl_output_for_GCM_registry_type), private :: output_for_gcm_registry

contains

Expand All @@ -106,7 +108,6 @@ The class definition is shown below:
get_string
procedure, public :: get_settings_var_cnt
procedure, public :: add_output_for_GCM
procedure, public :: get_output_for_GCM
procedure, private :: inquire_settings_metadata_by_name
procedure, private :: inquire_settings_metadata_by_id
procedure, private :: put_real
Expand Down
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
Loading
Loading