Skip to content

Commit 0206851

Browse files
committed
Merge branch 'atmosphere/floodFillDT_haloInTropo' into hotfix-v7.2 (PR #953)
This merge corrects the parallel computation of the iLev_DT field by adding a halo exchange for a new flag field, inTropo, in the flood-fill algorithm employed by the PV diagnostics module. Originally, it was assumed that each MPI domain would have at least one cell with the "correct" DT found by flood filling within the domain, and that would be sufficient to connect each domain's troposphere. However, for sufficiently small domains, say, over the Arctic during winter with strong inversions, the entire surface can be capped by high PV. So, it is necessary to communicate between domains during the flood fill to avoid finding an incorrect DT near the surface. Only in very rare cases should more than two halo exchanges be needed. With a correction to the computation of the lowest vertical layer at or above the dynamic tropopause, other diagnostic fields at the tropopause level will be affected: u_pv, v_pv, theta_pv, vort_pv, depv_dt_diab_pv, and depv_dt_fric_pv. * atmosphere/floodFillDT_haloInTropo: Halo exchange inTropo in flood fill to find DT.
2 parents 3cd4daa + 3d2086e commit 0206851

2 files changed

Lines changed: 79 additions & 49 deletions

File tree

src/core_atmosphere/diagnostics/Registry_pv.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,8 @@
6262
<var name="iLev_DT" type="integer" dimensions="nCells Time" units="-"
6363
description="Lowest vertical level at or above dynamic tropopause (.lt.1 if 2 PVU below column; .gt.nLevels if 2PVU above column)"/>
6464

65+
<var name="inTropo" type="integer" dimensions="nVertLevels nCells Time" units="0/1"
66+
description="1 if within troposphere based on EPV flood fill"/>
67+
6568
</var_struct>
6669

src/core_atmosphere/diagnostics/pv_diagnostics.F

Lines changed: 76 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -591,29 +591,41 @@ subroutine floodFill_tropo(mesh, diag, pvuVal)
591591
! (2) flood fill troposphere (<2pvu) from troposphere seeds near surface.
592592
!Somewhat paradoxically, the bottom of the stratosphere is lower than the top of the troposphere.
593593
594+
!Originally, it was assumed that each (MPI) domain would have >0 cells with "right" DT found by flood filling.
595+
!However, for "small" domains over the Arctic say during winter, the entire surface can be capped by high PV.
596+
!So, we need to communicate between domains during the flood fill or else we find the DT at the surface.
597+
!The extreme limiting case is if we had every cell as its own domain; then, it's clear that there has to be communication.
598+
594599
!The "output" is iLev_DT, which is the vertical index for the level >= pvuVal. If >nVertLevels, pvuVal above column. If <2, pvuVal below column.
595600
!Communication between blocks during the flood fill may be needed to treat some edge cases appropriately.
596601

597-
use mpas_pool_routines, only : mpas_pool_get_dimension, mpas_pool_get_array
602+
use mpas_pool_routines, only : mpas_pool_get_dimension, mpas_pool_get_array, mpas_pool_get_field
603+
use mpas_dmpar, only : mpas_dmpar_max_int,mpas_dmpar_exch_halo_field
604+
use mpas_derived_types, only : dm_info, field2DInteger
598605

599606
implicit none
600607

601608
type (mpas_pool_type), intent(in) :: mesh
602609
type (mpas_pool_type), intent(inout) :: diag
603610
real(kind=RKIND), intent(in) :: pvuVal
604-
605-
integer :: iCell, k, nChanged, iNbr, iCellNbr, levInd
606-
integer, pointer :: nCells, nVertLevels
611+
612+
integer :: iCell, k, nChanged, iNbr, iCellNbr, levInd, haloChanged, global_haloChanged
613+
integer, pointer :: nCells, nVertLevels, nCellsSolve
607614
integer, dimension(:), pointer :: nEdgesOnCell, iLev_DT
608-
integer, dimension(:,:), pointer :: cellsOnCell
609-
615+
integer, dimension(:,:), pointer :: cellsOnCell, inTropo
616+
617+
type (field2DInteger), pointer :: inTropo_f
618+
610619
real(kind=RKIND) :: sgnHemi, sgn
611620
real(kind=RKIND),dimension(:),pointer:: latCell
612621
real(kind=RKIND), dimension(:,:), pointer :: ertel_pv
613622

614-
integer, dimension(:,:), allocatable :: candInTropo, inTropo !whether in troposphere
623+
type (dm_info), pointer :: dminfo
624+
625+
integer, dimension(:,:), allocatable :: candInTropo !whether in troposphere
615626

616627
call mpas_pool_get_dimension(mesh, 'nCells', nCells)
628+
call mpas_pool_get_dimension(mesh, 'nCellsSolve', nCellsSolve)
617629
call mpas_pool_get_dimension(mesh, 'nVertLevels', nVertLevels)
618630
call mpas_pool_get_array(mesh, 'nEdgesOnCell', nEdgesOnCell)
619631
call mpas_pool_get_array(mesh, 'cellsOnCell', cellsOnCell)
@@ -622,9 +634,9 @@ subroutine floodFill_tropo(mesh, diag, pvuVal)
622634
call mpas_pool_get_array(diag, 'ertel_pv', ertel_pv)
623635
!call mpas_pool_get_array(diag, 'iLev_DT_trop', iLev_DT)
624636
call mpas_pool_get_array(diag, 'iLev_DT', iLev_DT)
637+
call mpas_pool_get_array(diag, 'inTropo', inTropo)
625638

626639
allocate(candInTropo(nVertLevels, nCells+1))
627-
allocate(inTropo(nVertLevels, nCells+1))
628640
candInTropo(:,:) = 0
629641
inTropo(:,:) = 0
630642
!store whether each level above DT to avoid repeating logic. we'll use cand as a isVisited marker further below.
@@ -645,56 +657,71 @@ subroutine floodFill_tropo(mesh, diag, pvuVal)
645657
do k=1,levInd
646658
if (candInTropo(k,iCell) .GT. 0) then
647659
inTropo(k,iCell) = 1
648-
candInTropo(k,iCell) = 0
660+
!candInTropo(k,iCell) = 0
649661
nChanged = nChanged+1
650662
end if
651663
end do
652664
end do
653665

654666
!flood fill from the given seeds. since I don't know enough fortran,
655667
!we'll just brute force a continuing loop rather than queue.
656-
do while(nChanged .GT. 0)
657-
nChanged = 0
658-
do iCell=1,nCells
659-
do k=1,nVertLevels
660-
!update if candidate and neighbor in troposphere
661-
if (candInTropo(k,iCell) .GT. 0) then
662-
!nbr below
663-
if (k .GT. 1) then
664-
if (inTropo(k-1,iCell) .GT. 0) then
665-
inTropo(k,iCell) = 1
666-
candInTropo(k,iCell) = 0
667-
nChanged = nChanged+1
668-
cycle
668+
call mpas_pool_get_field(diag, 'inTropo', inTropo_f)
669+
dminfo => inTropo_f % block % domain % dminfo
670+
global_haloChanged = 1
671+
do while(global_haloChanged .GT. 0) !any cell in a halo has changed, to propagate to other domains
672+
global_haloChanged = 0 !aggregate the number of changed cells w/in the loop below
673+
do while(nChanged .GT. 0)
674+
nChanged = 0
675+
do iCell=1,nCells !should we look for neighbors of hallo cells?
676+
!do iCell=1,nCellsSolve !should we look for neighbors of hallo cells?
677+
do k=1,nVertLevels
678+
!update if candidate and neighbor in troposphere
679+
if ((candInTropo(k,iCell) .GT. 0) .AND. (inTropo(k,iCell).LT.1) ) then
680+
!nbr below
681+
if (k .GT. 1) then
682+
if (inTropo(k-1,iCell) .GT. 0) then
683+
inTropo(k,iCell) = 1
684+
!candInTropo(k,iCell) = 0
685+
nChanged = nChanged+1
686+
cycle
687+
end if
669688
end if
670-
end if
671-
672-
!side nbrs
673-
do iNbr = 1, nEdgesOnCell(iCell)
674-
iCellNbr = cellsOnCell(iNbr,iCell)
675-
if (inTropo(k,iCellNbr) .GT. 0) then
676-
inTropo(k,iCell) = 1
677-
candInTropo(k,iCell) = 0
678-
nChanged = nChanged+1
679-
cycle
680-
end if
681-
end do
682-
683-
!nbr above
684-
if (k .LT. nVertLevels) then
685-
if (inTropo(k+1,iCell) .GT. 0) then
686-
inTropo(k,iCell) = 1
687-
candInTropo(k,iCell) = 0
688-
nChanged = nChanged+1
689-
cycle
689+
690+
!side nbrs
691+
do iNbr = 1, nEdgesOnCell(iCell)
692+
iCellNbr = cellsOnCell(iNbr,iCell)
693+
if (inTropo(k,iCellNbr) .GT. 0) then
694+
inTropo(k,iCell) = 1
695+
!candInTropo(k,iCell) = 0
696+
nChanged = nChanged+1
697+
exit
698+
end if
699+
end do
700+
701+
!nbr above
702+
if (k .LT. nVertLevels) then
703+
if (inTropo(k+1,iCell) .GT. 0) then
704+
inTropo(k,iCell) = 1
705+
!candInTropo(k,iCell) = 0
706+
nChanged = nChanged+1
707+
cycle
708+
end if
690709
end if
691-
end if
692-
693-
end if !candIn
694-
end do !levels
695-
end do !cells
696-
!here's where a communication would be needed for edge cases !!!
697-
end do !while
710+
711+
end if !candIn
712+
end do !levels
713+
end do !cells
714+
global_haloChanged = global_haloChanged+nChanged
715+
end do !while w/in domain
716+
!communicate to other domains for edge case where a chunk of a block hasn't gotten to fill
717+
nChanged = global_haloChanged
718+
call mpas_dmpar_max_int(dminfo, nChanged, global_haloChanged)
719+
if (global_haloChanged .GT. 0) then !communicate inTropo everywhere
720+
call mpas_dmpar_exch_halo_field(inTropo_f)
721+
end if
722+
nChanged = global_haloChanged !so each block will iterate again if anything changed
723+
end do !while haloChanged
724+
deallocate(candInTropo)
698725
699726
!Fill iLev_DT with the lowest level above the tropopause (If DT above column, iLev>nVertLevels. If DT below column, iLev=0.
700727
do iCell=1,nCells

0 commit comments

Comments
 (0)