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"