Skip to content

Commit 3d2086e

Browse files
nickszapmgduda
authored andcommitted
Halo exchange inTropo in flood fill to find DT.
Originally, it was assumed that each (MPI) domain would have >0 cells with "right" DT found by flood filling w/in domain, and that would be sufficient to connect each domain's troposphere. However, for "small" domains over the Arctic say during winter w/ strong inversions, the entire surface can be capped by high PV. So, we need to communicate between domains during the flood fill or else we can find a wrong DT near the surface. Only in very rare edge cases should more than two halo exchanges occur.
1 parent ef684ba commit 3d2086e

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)