diff --git a/components/mpas-ocean/src/Registry.xml b/components/mpas-ocean/src/Registry.xml
index 2091c51429e2..a21d1de90a15 100644
--- a/components/mpas-ocean/src/Registry.xml
+++ b/components/mpas-ocean/src/Registry.xml
@@ -326,6 +326,14 @@
description="If true, the N2 limiting is applied to the horizontal diffusion term"
possible_values=".true. or .false."
/>
+
+
maximumBnd(iTr, k, iCell))) then
- do i = 1, nEdgesOnCell(iCell)
- iEdge = edgesOnCell(i, iCell)
- redi_term2_edge(iTr, k, iEdge) = 0.0_RKIND
- end do
+ ! scale cross-fluxes down relative to size of bnds violation
+ over = max(tempTracer - maximumBnd(iTr, k, iCell), &
+ minimumBnd(iTr, k, iCell) - tempTracer)
+
+ diff = abs(tempTracer - tracers(iTr, k, iCell))
+
+ scal = min(1.0_RKIND, max(0.0_RKIND, &
+ limiter_safety_factor * ( &
+ 1.0_RKIND - over / (diff + 1.0E-16_RKIND))))
+
+ ! scale to zero if not using monotone limiter
+ if (.not. use_quasi_monotone) scal = 0.0_RKIND
+
+ ! cell flux scalings, to be interp. onto edge/levs next pass
+ redi_flux_scale(iTr, k, iCell) = scal
- redi_term3_topOfCell(iTr, k, iCell) = 0.0_RKIND
- redi_term3_topOfCell(iTr, k + 1, iCell) = 0.0_RKIND
if (isActiveTracer) then
rediLimiterCount(k, iCell) = rediLimiterCount(k, iCell) + 1
- endif
- endif
+ end if
+ end if
end do
end do
end do ! iCell
@@ -422,7 +499,8 @@ subroutine ocn_tracer_hmix_Redi_tend(meshPool, layerThickness, layerThickEdgeMea
!now go back and reapply all tendencies
!$omp parallel
- !$omp do schedule(runtime) private(invAreaCell, k, iTr, i, iEdge)
+ !$omp do schedule(runtime) &
+ !$omp private(invAreaCell, k, kUp, kDn, iTr, i, iEdge, jCell, scal, scalUp, scalDn)
do iCell = 1, nCells
invAreaCell = 1.0_RKIND/areaCell(iCell)
do k = minLevelCell(iCell), maxLevelCell(iCell)
@@ -432,21 +510,48 @@ subroutine ocn_tracer_hmix_Redi_tend(meshPool, layerThickness, layerThickEdgeMea
end do
if (maxLevelCell(iCell) .ge. config_Redi_min_layers_diag_terms) then
+ ! term 3: d/dz div( S grad psi )
do k = minLevelCell(iCell), maxLevelCell(iCell)
+ kUp = max(minLevelCell(iCell), k - 1)
+ kDn = min(maxLevelCell(iCell), k + 1)
do iTr = 1, ntracers
- tend(iTr, k, iCell) = tend(iTr, k, iCell) + rediKappaCell(iCell)*2.0_RKIND* &
- (RediKappaScaling(k, iCell)* &
- redi_term3_topOfCell(iTr, k, iCell) - &
- RediKappaScaling(k + 1, iCell)*redi_term3_topOfCell(iTr, k + 1, iCell))
+ ! harmonic-mean; not strictly monotone, but smooth
+ scalUp = 2.0_RKIND * &
+ redi_flux_scale(iTr, kUp, iCell) * &
+ redi_flux_scale(iTr, k, iCell) / ( &
+ redi_flux_scale(iTr, kUp, iCell) + &
+ redi_flux_scale(iTr, k, iCell) + 1.0E-16_RKIND)
+
+ scalDn = 2.0_RKIND * &
+ redi_flux_scale(iTr, kDn, iCell) * &
+ redi_flux_scale(iTr, k, iCell) / ( &
+ redi_flux_scale(iTr, kDn, iCell) + &
+ redi_flux_scale(iTr, k, iCell) + 1.0E-16_RKIND)
+
+ tend(iTr, k, iCell) = tend(iTr, k, iCell) + &
+ rediKappaCell(iCell) * ( &
+ RediKappaScaling(k, iCell)* &
+ scalUp*redi_term3_topOfCell(iTr, k, iCell) - &
+ RediKappaScaling(k + 1, iCell)* &
+ scalDn*redi_term3_topOfCell(iTr, k + 1, iCell))
end do
end do
+ ! term 2: div( h S d/dz psi )
do i = 1, nEdgesOnCell(iCell)
if (cellsOnCell(i, iCell) .eq. nCellsP1) cycle
iEdge = edgesOnCell(i, iCell)
+ jCell = cellsOnCell(i, iCell)
do k = minLevelEdgeBot(iEdge), maxLevelEdgeTop(iEdge)
do iTr = 1, ntracers
- tend(iTr, k, iCell) = tend(iTr, k, iCell) + edgeSignOnCell(i, iCell)*invAreaCell*redi_term2_edge(iTr, k, iEdge)
+ scal = 2.0_RKIND * &
+ redi_flux_scale(iTr, k, iCell) * &
+ redi_flux_scale(iTr, k, jCell) / ( &
+ redi_flux_scale(iTr, k, iCell) + &
+ redi_flux_scale(iTr, k, jCell) + 1.0E-16_RKIND)
+
+ tend(iTr, k, iCell) = tend(iTr, k, iCell) + &
+ scal*edgeSignOnCell(i, iCell)*invAreaCell*redi_term2_edge(iTr, k, iEdge)
end do
end do
end do
@@ -463,6 +568,9 @@ subroutine ocn_tracer_hmix_Redi_tend(meshPool, layerThickness, layerThickEdgeMea
deallocate (redi_term3)
deallocate (redi_term2_edge)
deallocate (redi_term3_topOfCell)
+ deallocate (minimumBnd)
+ deallocate (maximumBnd)
+ deallocate (redi_flux_scale)
call mpas_timer_stop("tracer redi")
@@ -545,6 +653,12 @@ subroutine ocn_tracer_hmix_Redi_init(domain, err)!{{{
call mpas_dmpar_finalize(domain%dminfo)
end if
+ ! quasi bounds-preserving limiter
+ use_quasi_monotone = config_Redi_use_quasi_monotone_limiter
+
+ ! safety factor for limiter: 0 <= fac <= 1
+ limiter_safety_factor = config_Redi_quasi_monotone_safety_factor
+
! Initialize horizontal taper
if (config_Redi_horizontal_taper == 'none' .or. &
config_Redi_horizontal_taper == 'RossbyRadius') then