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

Add tracers for freshwater sources to MPAS-Ocean #7087

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions cime_config/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@
"SMS_D_Ld1.T62_oQU240wLI.GMPAS-IAF-PISMF.mpaso-impl_top_drag",
"SMS_D_Ld1.T62_oQU240.GMPAS-IAF.mpaso-harmonic_mean_drag",
"SMS_D_Ld1.T62_oQU240.GMPAS-IAF.mpaso-upwind_advection",
"SMS_D_Ld1.T62_oQU240.GMPAS-IAF.mpaso-freshwater_tracers",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth considering:

Suggested change
"SMS_D_Ld1.T62_oQU240.GMPAS-IAF.mpaso-freshwater_tracers",
"SMS_D_Ld1.T62_oQU240wLI.GMPAS-IAF-PISMF.mpaso-freshwater_tracers",

to also test the ice-shelf-melt freshwater tracer. What do you think?

"ERS_Ld5_D.T62_oQU240.GMPAS-IAF.mpaso-conservation_check",
"ERS_Ld5_PS.ne30pg2_r05_IcoswISC30E3r5.CRYO1850-DISMF.mpaso-scaled_dib_dismf",
"ERS_Ld5.TL319_oQU240wLI_gis20.MPAS_LISIO_JRA1p5.mpaso-ocn_glc_tf_coupling",
Expand Down
14 changes: 14 additions & 0 deletions components/mpas-ocean/bld/build-namelist
Original file line number Diff line number Diff line change
Expand Up @@ -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 #
#############################################
Expand Down Expand Up @@ -1852,6 +1865,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
Expand Down
1 change: 1 addition & 0 deletions components/mpas-ocean/bld/build-namelist-group-list
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions components/mpas-ocean/bld/build-namelist-section
Original file line number Diff line number Diff line change
Expand Up @@ -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 #
#############################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,16 @@
<config_ecosysTracers_diagnostic_fields_level4>.false.</config_ecosysTracers_diagnostic_fields_level4>
<config_ecosysTracers_diagnostic_fields_level5>.false.</config_ecosysTracers_diagnostic_fields_level5>

<!-- tracer_forcing_freshwaterTracers -->
<config_use_freshwaterTracers>.false.</config_use_freshwaterTracers>
<config_use_freshwaterTracers_surface_bulk_forcing>.true.</config_use_freshwaterTracers_surface_bulk_forcing>
<config_use_freshwaterTracers_surface_restoring>.false.</config_use_freshwaterTracers_surface_restoring>
<config_use_freshwaterTracers_interior_restoring>.false.</config_use_freshwaterTracers_interior_restoring>
<config_use_freshwaterTracers_exponential_decay>.false.</config_use_freshwaterTracers_exponential_decay>
<config_use_freshwaterTracers_idealAge_forcing>.false.</config_use_freshwaterTracers_idealAge_forcing>
<config_use_freshwaterTracers_ttd_forcing>.false.</config_use_freshwaterTracers_ttd_forcing>
<config_use_freshwaterTracers_surface_value>.false.</config_use_freshwaterTracers_surface_value>

<!-- tracer_forcing_DMSTracers -->
<config_use_DMSTracers>.false.</config_use_DMSTracers>
<config_use_DMSTracers_surface_bulk_forcing>.false.</config_use_DMSTracers_surface_bulk_forcing>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3156,6 +3156,73 @@ Default: Defined in namelist_defaults.xml
</entry>


<!-- tracer_forcing_freshwaterTracers -->

<entry id="config_use_freshwaterTracers" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
if true, the 'freshwaterTracers' category is enabled for the run

Valid values: .true. or .false.
Default: Defined in namelist_defaults.xml
</entry>

<entry id="config_use_freshwaterTracers_surface_bulk_forcing" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
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
</entry>

<entry id="config_use_freshwaterTracers_surface_restoring" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
if true, surface restoring source is applied to tracers in 'freshwaterTracers' category

Valid values: .true. or .false.
Default: Defined in namelist_defaults.xml
</entry>

<entry id="config_use_freshwaterTracers_interior_restoring" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
if true, interior restoring source is applied to tracers in 'freshwaterTracers' category

Valid values: .true. or .false.
Default: Defined in namelist_defaults.xml
</entry>

<entry id="config_use_freshwaterTracers_exponential_decay" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
if true, exponential decay source is applied to tracers in 'freshwaterTracers' category

Valid values: .true. or .false.
Default: Defined in namelist_defaults.xml
</entry>

<entry id="config_use_freshwaterTracers_idealAge_forcing" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
if true, idealAge forcing source is applied to tracers in 'freshwaterTracers' category

Valid values: .true. or .false.
Default: Defined in namelist_defaults.xml
</entry>

<entry id="config_use_freshwaterTracers_ttd_forcing" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
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
</entry>

<entry id="config_use_freshwaterTracers_surface_value" type="logical"
category="tracer_forcing_freshwaterTracers" group="tracer_forcing_freshwaterTracers">
if true, surface value is computed for 'freshwaterTracers' category

Valid values: .true. or .false.
Default: Defined in namelist_defaults.xml
</entry>


<!-- tracer_forcing_DMSTracers -->

<entry id="config_use_DMSTracers" type="logical"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This testdef is used to test a stealth feature in mpaso introduced by
PR #7087. It simplies changes one mpaso namelist variable,
config_use_freshwaterTracers
from its default value of .false. to .true..
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
config_use_freshwaterTracers = .true.
215 changes: 215 additions & 0 deletions components/mpas-ocean/src/shared/mpas_ocn_surface_bulk_forcing.F
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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')
Comment on lines +981 to +982
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this output (here and elsewhere in this file) would happen at every time step or at least every coupling time step and would be confusing to users. I think we probably want to remove it.

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')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should probably also be removed.


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


Expand Down
Loading