diff --git a/components/mpas-ocean/bld/build-namelist b/components/mpas-ocean/bld/build-namelist
index e2acfc35fce7..4cc2361104b4 100755
--- a/components/mpas-ocean/bld/build-namelist
+++ b/components/mpas-ocean/bld/build-namelist
@@ -1186,6 +1186,19 @@ if ($ice_bgc eq 'ice_bgc' ) {
}
add_default($nl, 'config_use_ecosysTracers_river_inputs_from_coupler');
+####################################################
+# Namelist group: tracer_forcing_freshwaterTracers #
+####################################################
+
+add_default($nl, 'config_use_freshwaterTracers');
+add_default($nl, 'config_use_freshwaterTracers_surface_bulk_forcing');
+add_default($nl, 'config_use_freshwaterTracers_surface_restoring');
+add_default($nl, 'config_use_freshwaterTracers_interior_restoring');
+add_default($nl, 'config_use_freshwaterTracers_exponential_decay');
+add_default($nl, 'config_use_freshwaterTracers_idealAge_forcing');
+add_default($nl, 'config_use_freshwaterTracers_ttd_forcing');
+add_default($nl, 'config_use_freshwaterTracers_surface_value');
+
#############################################
# Namelist group: tracer_forcing_DMSTracers #
#############################################
@@ -1855,6 +1868,7 @@ my @groups = qw(run_modes
tracer_forcing_dmstracers
tracer_forcing_macromoleculestracers
tracer_forcing_idealagetracers
+ tracer_forcing_freshwatertracers
tracer_forcing_cfctracers
am_globalstats
am_surfaceareaweightedaverages
diff --git a/components/mpas-ocean/bld/build-namelist-group-list b/components/mpas-ocean/bld/build-namelist-group-list
index c109ba9990e3..2adb0b92288b 100644
--- a/components/mpas-ocean/bld/build-namelist-group-list
+++ b/components/mpas-ocean/bld/build-namelist-group-list
@@ -44,6 +44,7 @@ my @groups = qw(run_modes
tracer_forcing_activetracers
tracer_forcing_debugtracers
tracer_forcing_ecosystracers
+ tracer_forcing_freshwatertracers
tracer_forcing_dmstracers
tracer_forcing_macromoleculestracers
tracer_forcing_idealagetracers
diff --git a/components/mpas-ocean/bld/build-namelist-section b/components/mpas-ocean/bld/build-namelist-section
index ef17ac9bc3d5..faa4b12d7e57 100644
--- a/components/mpas-ocean/bld/build-namelist-section
+++ b/components/mpas-ocean/bld/build-namelist-section
@@ -605,6 +605,19 @@ add_default($nl, 'config_ecosysTracers_diagnostic_fields_level3');
add_default($nl, 'config_ecosysTracers_diagnostic_fields_level4');
add_default($nl, 'config_ecosysTracers_diagnostic_fields_level5');
+####################################################
+# Namelist group: tracer_forcing_freshwaterTracers #
+####################################################
+
+add_default($nl, 'config_use_freshwaterTracers');
+add_default($nl, 'config_use_freshwaterTracers_surface_bulk_forcing');
+add_default($nl, 'config_use_freshwaterTracers_surface_restoring');
+add_default($nl, 'config_use_freshwaterTracers_interior_restoring');
+add_default($nl, 'config_use_freshwaterTracers_exponential_decay');
+add_default($nl, 'config_use_freshwaterTracers_idealAge_forcing');
+add_default($nl, 'config_use_freshwaterTracers_ttd_forcing');
+add_default($nl, 'config_use_freshwaterTracers_surface_value');
+
#############################################
# Namelist group: tracer_forcing_DMSTracers #
#############################################
diff --git a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml
index b21b012ba74a..57f43010610f 100644
--- a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml
+++ b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml
@@ -749,6 +749,16 @@
.false.
.false.
+
+.false.
+.true.
+.false.
+.false.
+.false.
+.false.
+.false.
+.false.
+
.false.
.false.
diff --git a/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml b/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml
index 53b30d5347a2..bfabf0aed9b1 100644
--- a/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml
+++ b/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml
@@ -3155,6 +3155,69 @@ Valid values: .true. or .false.
Default: Defined in namelist_defaults.xml
+
+if true, the 'freshwaterTracers' category is enabled for the run
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
+
+
+if true, surface bulk forcing from coupler is added to surfaceTracerFlux in 'freshwaterTracers' category. True by default because the main function of this tracer group is tracking freshwater fluxes
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
+
+
+if true, surface restoring source is applied to tracers in 'freshwaterTracers' category
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
+
+
+if true, interior restoring source is applied to tracers in 'freshwaterTracers' category
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
+
+
+if true, exponential decay source is applied to tracers in 'freshwaterTracers' category
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
+
+
+if true, idealAge forcing source is applied to tracers in 'freshwaterTracers' category
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
+
+
+if true, transit time distribution forcing source is applied to tracers in 'freshwaterTracers' category
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
+
+
+if true, surface value is computed for 'freshwaterTracers' category
+
+Valid Values: .true. or .false.
+Default: Defined in namelist_defaults.xml
+
diff --git a/components/mpas-ocean/src/shared/mpas_ocn_surface_bulk_forcing.F b/components/mpas-ocean/src/shared/mpas_ocn_surface_bulk_forcing.F
index d25e147c312b..89198f722130 100644
--- a/components/mpas-ocean/src/shared/mpas_ocn_surface_bulk_forcing.F
+++ b/components/mpas-ocean/src/shared/mpas_ocn_surface_bulk_forcing.F
@@ -127,6 +127,9 @@ subroutine ocn_surface_bulk_forcing_tracers(meshPool, groupName, forcingPool, tr
if ( trim(groupName) == 'activeTracers' ) then
call ocn_surface_bulk_forcing_active_tracers(meshPool, forcingPool, tracerGroup, &
tracersSurfaceFlux, tracersSurfaceFluxRunoff, tracersSurfaceFluxRemoved, layerThickness, dt, err)
+ elseif ( trim(groupName) == 'freshwaterTracers' ) then
+ call ocn_surface_bulk_forcing_freshwater_tracers(meshPool, forcingPool, tracerGroup, &
+ tracersSurfaceFlux, tracersSurfaceFluxRunoff, tracersSurfaceFluxRemoved, err)
end if
call mpas_timer_stop("bulk_" // trim(groupName))
@@ -184,6 +187,9 @@ subroutine ocn_surface_bulk_forcing_tracers_subglacial_runoff(meshPool, groupNam
if ( trim(groupName) == 'activeTracers' ) then
call ocn_surface_bulk_forcing_active_tracers_subglacial_runoff(meshPool, forcingPool, &
tracersSurfaceFluxSubglacialRunoff, err)
+ elseif ( trim(groupName) == 'freshwaterTracers' ) then
+ call ocn_surface_bulk_forcing_freshwater_tracers_subglacial_runoff(meshPool, forcingPool, &
+ tracersSurfaceFluxSubglacialRunoff, err)!{{{
end if
call mpas_timer_stop("bulk_" // trim(groupName))
@@ -880,6 +886,215 @@ subroutine ocn_surface_bulk_forcing_active_tracers_subglacial_runoff(meshPool, f
end subroutine ocn_surface_bulk_forcing_active_tracers_subglacial_runoff!}}}
+!***********************************************************************
+!
+! routine ocn_surface_bulk_forcing_freshwater_tracers
+!
+!> \brief computes a tracer tendency due to freshwater surface fluxes
+!> \author Carolyn Branecky Begeman
+!> \date June 2024
+!> \details
+!> This routine computes a tracer tendency due to freshwater surface fluxes
+!
+!-----------------------------------------------------------------------
+
+ subroutine ocn_surface_bulk_forcing_freshwater_tracers(meshPool, forcingPool, tracerGroup, &
+ freshwaterSurfaceFlux, freshwaterSurfaceFluxRunoff, freshwaterSurfaceFluxRemoved, err)!{{{
+
+ !-----------------------------------------------------------------
+ !
+ ! input variables
+ !
+ !-----------------------------------------------------------------
+ type (mpas_pool_type), intent(in) :: meshPool !< Input: mesh information
+
+ !-----------------------------------------------------------------
+ !
+ ! input/output variables
+ !
+ !-----------------------------------------------------------------
+
+ type (mpas_pool_type), intent(inout) :: forcingPool
+
+ ! two dimensional arrays
+ real (kind=RKIND), dimension(:,:), intent(inout) :: &
+ freshwaterSurfaceFlux, freshwaterSurfaceFluxRunoff, freshwaterSurfaceFluxRemoved
+ real (kind=RKIND), dimension(:,:,:), intent(inout) :: tracerGroup
+
+ !-----------------------------------------------------------------
+ !
+ ! output variables
+ !
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: Error flag
+
+ !-----------------------------------------------------------------
+ !
+ ! local variables
+ !
+ !-----------------------------------------------------------------
+
+ integer :: iCell, nCells
+ integer, dimension(:), pointer :: nCellsArray
+
+ type(mpas_pool_type),pointer :: tracersSurfaceFluxPool
+ integer, pointer :: indexRain, indexSnow, indexRiverRunoff, indexIceRunoff, indexSeaIceFreshWater, &
+ indexIcebergFreshWater, indexLandIceFreshwater
+ real (kind=RKIND), dimension(:), pointer :: &
+ rainFlux, snowFlux, riverRunoffFlux, iceRunoffFlux, seaIceFreshWaterFlux, &
+ icebergFreshWaterFlux, landIceFreshwaterFlux
+
+ err = 0
+
+ call mpas_pool_get_dimension(meshPool, 'nCellsArray', nCellsArray)
+
+ call mpas_pool_get_subpool(forcingPool, 'tracersSurfaceFlux',tracersSurfaceFluxPool)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_rainSurfaceFlux', indexRain)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_snowSurfaceFlux', indexSnow)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_riverRunoffFreshWaterSurfaceFlux', indexRiverRunoff)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_iceRunoffFreshWaterSurfaceFlux', indexIceRunoff)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_seaIceFreshWaterSurfaceFlux', indexSeaIceFreshWater)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_icebergFreshWaterSurfaceFlux', indexIcebergFreshWater)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_landIceFreshwaterSurfaceFlux', indexLandIceFreshwater)
+
+ call mpas_pool_get_array(forcingPool, 'rainFlux', rainFlux)
+ call mpas_pool_get_array(forcingPool, 'snowFlux', snowFlux)
+ call mpas_pool_get_array(forcingPool, 'riverRunoffFlux', riverRunoffFlux)
+ call mpas_pool_get_array(forcingPool, 'iceRunoffFlux', iceRunoffFlux)
+ call mpas_pool_get_array(forcingPool, 'seaIceFreshWaterFlux', seaIceFreshWaterFlux)
+ call mpas_pool_get_array(forcingPool, 'icebergFreshWaterFlux', icebergFreshWaterFlux)
+ call mpas_pool_get_array(forcingPool, 'landIceFreshwaterFlux', landIceFreshwaterFlux)
+
+ nCells = nCellsArray( 3 )
+ if (associated(indexRain) .and. associated(rainFlux)) then
+ do iCell=1,nCells
+ freshwaterSurfaceFlux(indexRain, iCell) = rainFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ call mpas_log_write('indexRain is not associated')
+ endif
+ if (associated(indexSnow) .and. associated(snowFlux)) then
+ do iCell=1,nCells
+ freshwaterSurfaceFlux(indexSnow, iCell) = snowFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ call mpas_log_write('indexSnow is not associated')
+ endif
+ if (associated(indexIceRunoff) .and. associated(iceRunoffFlux)) then
+ do iCell=1,nCells
+ freshwaterSurfaceFluxRunoff(indexIceRunoff, iCell) = iceRunoffFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ call mpas_log_write('indexIceRunoff is not associated')
+ endif
+ if (associated(indexRiverRunoff) .and. associated(riverRunoffFlux)) then
+ do iCell=1,nCells
+ freshwaterSurfaceFluxRunoff(indexRiverRunoff, iCell) = riverRunoffFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ if (.not. associated(indexRiverRunoff)) call mpas_log_write('indexRiverRunoff is not associated')
+ if (.not. associated(riverRunoffFlux)) call mpas_log_write('riverRunoffFlux is not associated')
+ endif
+ if (associated(indexSeaIceFreshWater) .and. associated(seaIceFreshWaterFlux)) then
+ do iCell=1,nCells
+ freshwaterSurfaceFlux(indexSeaIceFreshWater, iCell) = seaIceFreshWaterFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ call mpas_log_write('indexSeaIceFreshWater is not associated')
+ endif
+ if (associated(indexIcebergFreshWater) .and. associated(icebergFreshWaterFlux)) then
+ do iCell=1,nCells
+ freshwaterSurfaceFlux(indexIcebergFreshWater, iCell) = icebergFreshWaterFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ call mpas_log_write('indexIcebergFreshWater is not associated')
+ endif
+ if (associated(indexLandIceFreshwater) .and. associated(landIceFreshwaterFlux)) then
+ do iCell=1,nCells
+ freshwaterSurfaceFlux(indexLandIceFreshwater, iCell) = landIceFreshwaterFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ call mpas_log_write('indexLandIceFreshwater or landIceFreshwaterFlux is not associated')
+ endif
+ call mpas_log_write('end fw assign sflux')
+
+ end subroutine ocn_surface_bulk_forcing_freshwater_tracers!}}}
+
+!***********************************************************************
+!
+! routine ocn_surface_bulk_forcing_freshwater_tracers_subglacial_runoff
+!
+!> \brief computes a tracer tendency due to CFC surface fluxes
+!> \author Irena Vankova
+!> \date July 2024
+!> \details
+!> This routine computes a tracer tendency due to CFC surface fluxes
+!
+!-----------------------------------------------------------------------
+
+ subroutine ocn_surface_bulk_forcing_freshwater_tracers_subglacial_runoff(meshPool, forcingPool, &
+ tracersSurfaceFluxSubglacialRunoff, err)!{{{
+
+ !-----------------------------------------------------------------
+ !
+ ! input variables
+ !
+ !-----------------------------------------------------------------
+ type (mpas_pool_type), intent(in) :: meshPool !< Input: mesh information
+
+ !-----------------------------------------------------------------
+ !
+ ! input/output variables
+ !
+ !-----------------------------------------------------------------
+
+ type (mpas_pool_type), intent(inout) :: forcingPool
+
+ ! two dimensional arrays
+ real (kind=RKIND), dimension(:,:), intent(inout) :: tracersSurfaceFluxSubglacialRunoff
+
+ !-----------------------------------------------------------------
+ !
+ ! output variables
+ !
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: Error flag
+
+ !-----------------------------------------------------------------
+ !
+ ! local variables
+ !
+ !-----------------------------------------------------------------
+ integer :: iCell, nCells
+ integer, dimension(:), pointer :: nCellsArray
+
+ type(mpas_pool_type),pointer :: tracersSurfaceFluxPool
+ integer, pointer :: indexSubglacialRunoff
+ real (kind=RKIND), dimension(:), pointer :: subglacialRunoffFlux
+
+ err = 0
+
+ call mpas_pool_get_dimension(meshPool, 'nCellsArray', nCellsArray)
+
+ call mpas_pool_get_subpool(forcingPool, 'tracersSurfaceFlux',tracersSurfaceFluxPool)
+ call mpas_pool_get_dimension(tracersSurfaceFluxPool, 'index_subglacialRunoffFreshWaterSurfaceFlux', indexSubglacialRunoff)
+
+ call mpas_pool_get_array(forcingPool, 'subglacialRunoffFlux', subglacialRunoffFlux)
+
+ nCells = nCellsArray( 3 )
+ if (associated(indexSubglacialRunoff) .and. associated(subglacialRunoffFlux)) then
+ do iCell=1,nCells
+ tracersSurfaceFluxSubglacialRunoff(indexSubglacialRunoff, iCell) = subglacialRunoffFlux(iCell) / rho_sw
+ enddo ! iCell
+ else
+ call mpas_log_write('indexSubglacialRunoff or subglacialRunoffFlux is not associated')
+ tracersSurfaceFluxSubglacialRunoff(indexSubglacialRunoff, :) = 0.0_RKIND
+ endif
+
+ end subroutine ocn_surface_bulk_forcing_freshwater_tracers_subglacial_runoff!}}}
+
end module ocn_surface_bulk_forcing
diff --git a/components/mpas-ocean/src/shared/mpas_ocn_tendency.F b/components/mpas-ocean/src/shared/mpas_ocn_tendency.F
index 0d049d1eb422..4187db383dd6 100644
--- a/components/mpas-ocean/src/shared/mpas_ocn_tendency.F
+++ b/components/mpas-ocean/src/shared/mpas_ocn_tendency.F
@@ -800,7 +800,19 @@ subroutine ocn_tend_tracer(tendPool, statePool, forcingPool, &
modifiedConfigName = configBase // '_ttd_forcing'
call mpas_pool_get_config(ocnConfigs, modifiedConfigName, &
config_use_tracerGroup_ttd_forcing)
-
+ if ( groupName == 'freshwaterTracers' ) then
+ if (config_use_tracerGroup_surface_restoring) &
+ call mpas_log_write('surface restoring not supported for freshwaterTracers group')
+ if (config_use_tracerGroup_interior_restoring) &
+ call mpas_log_write('interior restoring not supported for freshwaterTracers group')
+ if (config_use_tracerGroup_exponential_decay) &
+ call mpas_log_write('exponential decay not supported for freshwaterTracers group')
+ if (config_use_tracerGroup_idealAge_forcing) &
+ ! TODO support this
+ call mpas_log_write('idealAge forcing not supported for freshwaterTracers group')
+ if (config_use_tracerGroup_ttd_forcing) &
+ call mpas_log_write('TTD forcing not supported for freshwaterTracers group')
+ endif
! Get tracers from pool, determine number of tracers in group
call mpas_pool_get_array(tracersPool, groupName, &
tracerGroup, timeLevel)
@@ -834,14 +846,14 @@ subroutine ocn_tend_tracer(tendPool, statePool, forcingPool, &
if (trim(config_subglacial_runoff_mode) == 'data') then
! Get surface flux due to subglacial runoff array
- ! only active tracers have subglacial runoff flux for now,
- ! but we still need to associate for ALL tracers
modifiedGroupName = groupName // "SurfaceFluxSubglacialRunoff"
call mpas_pool_get_array(tracersSurfaceFluxPool, &
modifiedGroupName, &
tracerGroupSurfaceFluxSubglacialRunoff)
end if
+ !call mpas_pool_print_summary(tracersSurfaceFluxPool, MPAS_POOL_FIELD, .true.)
+
! Get surface flux removed array to keep track of how much
! flux is ignored
modifiedGroupName = groupName // "SurfaceFluxRemoved"
@@ -890,7 +902,7 @@ subroutine ocn_tend_tracer(tendPool, statePool, forcingPool, &
! compute surface tracer flux from bulk forcing
!
if (config_use_tracerGroup_surface_bulk_forcing) then
-
+ ! This applies surface fluxes if groupName is activeTracers
call ocn_surface_bulk_forcing_tracers(meshPool, groupName, &
forcingPool, tracerGroup, &
tracerGroupSurfaceFlux, &
diff --git a/components/mpas-ocean/src/tracer_groups/Registry_freshwaterTracers.xml b/components/mpas-ocean/src/tracer_groups/Registry_freshwaterTracers.xml
new file mode 100644
index 000000000000..657486133a75
--- /dev/null
+++ b/components/mpas-ocean/src/tracer_groups/Registry_freshwaterTracers.xml
@@ -0,0 +1,215 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/mpas-ocean/src/tracer_groups/Registry_tracers.xml b/components/mpas-ocean/src/tracer_groups/Registry_tracers.xml
index b8f0d1f519f5..8dd20a59acac 100644
--- a/components/mpas-ocean/src/tracer_groups/Registry_tracers.xml
+++ b/components/mpas-ocean/src/tracer_groups/Registry_tracers.xml
@@ -1,6 +1,7 @@
#include "Registry_activeTracers.xml"
#include "Registry_debugTracers.xml"
#include "Registry_ecosys.xml"
+#include "Registry_freshwaterTracers.xml"
#include "Registry_DMS.xml"
#include "Registry_MacroMolecules.xml"
#include "Registry_idealAge.xml"