1+ ! This file is part of MOM6, the Modular Ocean Model version 6.
2+ ! See the LICENSE file for licensing information.
3+ ! SPDX-License-Identifier: Apache-2.0
4+
15! > Describes the decomposed MOM domain and has routines for communications across PEs
26module MOM_domain_infra
37
4- ! This file is part of MOM6. See LICENSE.md for the license.
5-
68use MOM_coms_infra, only : PE_here, root_PE, num_PEs
79use MOM_cpu_clock_infra, only : cpu_clock_begin, cpu_clock_end
810use MOM_error_infra, only : MOM_error= >MOM_err, NOTE, WARNING, FATAL
@@ -32,6 +34,7 @@ module MOM_domain_infra
3234
3335! The `group_pass_type` fields are never accessed, so we keep it as an FMS type
3436use mpp_domains_mod, only : group_pass_type = > mpp_group_update_type
37+ #define MAX_DSAMP_LEV 4
3538
3639implicit none ; private
3740
@@ -131,7 +134,7 @@ module MOM_domain_infra
131134 character (len= 64 ) :: name ! < The name of this domain
132135 type (domain2D), pointer :: mpp_domain = > NULL () ! < The FMS domain with halos
133136 ! ! on this processor, centered at h points.
134- type (domain2D), pointer :: mpp_domain_d2 = > NULL () ! < A coarse FMS domain with halos
137+ type (domain2D), pointer :: mpp_domain_d(:) = > NULL () ! < A coarse FMS domain with halos
135138 ! ! on this processor, centered at h points.
136139 integer :: niglobal ! < The total horizontal i-domain size.
137140 integer :: njglobal ! < The total horizontal j-domain size.
@@ -1212,7 +1215,7 @@ subroutine redistribute_array_2d(Domain1, array1, Domain2, array2, complete)
12121215 ! Local variables
12131216 logical :: do_complete
12141217
1215- do_complete= .true. ; if (PRESENT (complete)) do_complete = complete
1218+ do_complete= .true. ; if (PRESENT (complete)) do_complete = complete
12161219
12171220 call mpp_redistribute(Domain1, array1, Domain2, array2, do_complete)
12181221
@@ -1231,7 +1234,7 @@ subroutine redistribute_array_3d(Domain1, array1, Domain2, array2, complete)
12311234 ! Local variables
12321235 logical :: do_complete
12331236
1234- do_complete= .true. ; if (PRESENT (complete)) do_complete = complete
1237+ do_complete= .true. ; if (PRESENT (complete)) do_complete = complete
12351238
12361239 call mpp_redistribute(Domain1, array1, Domain2, array2, do_complete)
12371240
@@ -1250,61 +1253,97 @@ subroutine redistribute_array_4d(Domain1, array1, Domain2, array2, complete)
12501253 ! Local variables
12511254 logical :: do_complete
12521255
1253- do_complete= .true. ; if (PRESENT (complete)) do_complete = complete
1256+ do_complete= .true. ; if (PRESENT (complete)) do_complete = complete
12541257
12551258 call mpp_redistribute(Domain1, array1, Domain2, array2, do_complete)
12561259
12571260end subroutine redistribute_array_4d
12581261
12591262
12601263! > Rescale the values of a 4-D array in its computational domain by a constant factor
1261- subroutine rescale_comp_data_4d (domain , array , scale )
1264+ subroutine rescale_comp_data_4d (domain , array , scale , zero_zeros )
12621265 type (MOM_domain_type), intent (in ) :: domain ! < MOM domain from which to extract information
12631266 real , dimension (:,:,:,:), intent (inout ) :: array ! < The array which is having the data in its
12641267 ! ! computational domain rescaled
12651268 real , intent (in ) :: scale ! < A scaling factor by which to multiply the
12661269 ! ! values in the computational domain of array
1267- integer :: is, ie, js, je
1270+ logical , optional , intent (in ) :: zero_zeros ! < If present and true, convert negative zeros
1271+ ! ! into ordinary signless zeros.
1272+ logical :: unsign_zeros ! If true, convert negative zeros into ordinary signless zeros.
1273+ integer :: is, ie, js, je, i, j, k, m
12681274
1269- if (scale == 1.0 ) return
1275+ unsign_zeros = .false. ; if (present (zero_zeros)) unsign_zeros = zero_zeros
1276+
1277+ if ((scale == 1.0 ) .and. (.not. unsign_zeros)) return
12701278
12711279 call get_simple_array_i_ind(domain, size (array,1 ), is, ie)
12721280 call get_simple_array_j_ind(domain, size (array,2 ), js, je)
1273- array(is:ie,js:je,:,:) = scale* array(is:ie,js:je,:,:)
1281+ if (scale /= 1.0 ) &
1282+ array(is:ie,js:je,:,:) = scale* array(is:ie,js:je,:,:)
1283+
1284+ if (unsign_zeros) then ! Convert negative zeros into zeros
1285+ do m= 1 ,size (array,4 ) ; do k= 1 ,size (array,3 ) ; do j= js,je ; do i= is,ie
1286+ if (array(i,j,k,m) == 0.0 ) array(i,j,k,m) = 0.0
1287+ enddo ; enddo ; enddo ; enddo
1288+ endif
12741289
12751290end subroutine rescale_comp_data_4d
12761291
12771292! > Rescale the values of a 3-D array in its computational domain by a constant factor
1278- subroutine rescale_comp_data_3d (domain , array , scale )
1293+ subroutine rescale_comp_data_3d (domain , array , scale , zero_zeros )
12791294 type (MOM_domain_type), intent (in ) :: domain ! < MOM domain from which to extract information
12801295 real , dimension (:,:,:), intent (inout ) :: array ! < The array which is having the data in its
12811296 ! ! computational domain rescaled
12821297 real , intent (in ) :: scale ! < A scaling factor by which to multiply the
12831298 ! ! values in the computational domain of array
1284- integer :: is, ie, js, je
1299+ logical , optional , intent (in ) :: zero_zeros ! < If present and true, convert negative zeros
1300+ ! ! into ordinary signless zeros.
1301+ logical :: unsign_zeros ! If true, convert negative zeros into ordinary signless zeros.
1302+ integer :: is, ie, js, je, i, j, k
1303+
1304+ unsign_zeros = .false. ; if (present (zero_zeros)) unsign_zeros = zero_zeros
12851305
1286- if (scale == 1.0 ) return
1306+ if (( scale == 1.0 ) .and. ( .not. unsign_zeros) ) return
12871307
12881308 call get_simple_array_i_ind(domain, size (array,1 ), is, ie)
12891309 call get_simple_array_j_ind(domain, size (array,2 ), js, je)
1290- array(is:ie,js:je,:) = scale* array(is:ie,js:je,:)
1310+ if (scale /= 1.0 ) &
1311+ array(is:ie,js:je,:) = scale* array(is:ie,js:je,:)
1312+
1313+ if (unsign_zeros) then ! Convert negative zeros into zeros
1314+ do k= 1 ,size (array,3 ) ; do j= js,je ; do i= is,ie
1315+ if (array(i,j,k) == 0.0 ) array(i,j,k) = 0.0
1316+ enddo ; enddo ; enddo
1317+ endif
12911318
12921319end subroutine rescale_comp_data_3d
12931320
12941321! > Rescale the values of a 2-D array in its computational domain by a constant factor
1295- subroutine rescale_comp_data_2d (domain , array , scale )
1322+ subroutine rescale_comp_data_2d (domain , array , scale , zero_zeros )
12961323 type (MOM_domain_type), intent (in ) :: domain ! < MOM domain from which to extract information
12971324 real , dimension (:,:), intent (inout ) :: array ! < The array which is having the data in its
12981325 ! ! computational domain rescaled
12991326 real , intent (in ) :: scale ! < A scaling factor by which to multiply the
13001327 ! ! values in the computational domain of array
1301- integer :: is, ie, js, je
1328+ logical , optional , intent (in ) :: zero_zeros ! < If present and true, convert negative zeros
1329+ ! ! into ordinary signless zeros.
1330+ logical :: unsign_zeros ! If true, convert negative zeros into ordinary signless zeros.
1331+ integer :: is, ie, js, je, i, j
13021332
1303- if (scale == 1.0 ) return
1333+ unsign_zeros = .false. ; if (present (zero_zeros)) unsign_zeros = zero_zeros
1334+
1335+ if ((scale == 1.0 ) .and. (.not. unsign_zeros)) return
13041336
13051337 call get_simple_array_i_ind(domain, size (array,1 ), is, ie)
13061338 call get_simple_array_j_ind(domain, size (array,2 ), js, je)
1307- array(is:ie,js:je) = scale* array(is:ie,js:je)
1339+ if (scale /= 1.0 ) &
1340+ array(is:ie,js:je) = scale* array(is:ie,js:je)
1341+
1342+ if (unsign_zeros) then ! Convert negative zeros into zeros
1343+ do j= js,je ; do i= is,ie
1344+ if (array(i,j) == 0.0 ) array(i,j) = 0.0
1345+ enddo ; enddo
1346+ endif
13081347
13091348end subroutine rescale_comp_data_2d
13101349
@@ -1333,14 +1372,14 @@ subroutine create_MOM_domain(MOM_dom, n_global, n_halo, reentrant, tripolar_N, l
13331372 integer , dimension (4 ) :: global_indices ! The lower and upper global i- and j-index bounds
13341373 integer :: X_FLAGS ! A combination of integers encoding the x-direction grid connectivity.
13351374 integer :: Y_FLAGS ! A combination of integers encoding the y-direction grid connectivity.
1336- integer :: xhalo_d2, yhalo_d2
1375+ integer :: dl
13371376 character (len= 200 ) :: mesg ! A string for use in error messages
13381377 logical :: mask_table_exists ! Mask_table is present and the file it points to exists
13391378
13401379 if (.not. associated (MOM_dom)) then
13411380 allocate (MOM_dom)
13421381 allocate (MOM_dom% mpp_domain)
1343- allocate (MOM_dom% mpp_domain_d2)
1382+ do dl = 2 ,MAX_DSAMP_LEV ; allocate (MOM_dom% mpp_domain_d(dl)) ; enddo
13441383 endif
13451384
13461385 MOM_dom% name = " MOM" ; if (present (domain_name)) MOM_dom% name = trim (domain_name)
@@ -1354,8 +1393,10 @@ subroutine create_MOM_domain(MOM_dom, n_global, n_halo, reentrant, tripolar_N, l
13541393 " TRIPOLAR_N and REENTRANT_Y may not be used together." )
13551394 endif
13561395
1357- MOM_dom% nonblocking_updates = nonblocking
1358- MOM_dom% thin_halo_updates = thin_halos
1396+ MOM_dom% nonblocking_updates = .false.
1397+ if (present (nonblocking)) MOM_dom% nonblocking_updates = nonblocking
1398+ MOM_dom% thin_halo_updates = .false.
1399+ if (present (thin_halos)) MOM_dom% thin_halo_updates = thin_halos
13591400 MOM_dom% symmetric = .true. ; if (present (symmetric)) MOM_dom% symmetric = symmetric
13601401 MOM_dom% niglobal = n_global(1 ) ; MOM_dom% njglobal = n_global(2 )
13611402 MOM_dom% nihalo = n_halo(1 ) ; MOM_dom% njhalo = n_halo(2 )
@@ -1406,11 +1447,12 @@ subroutine create_MOM_domain(MOM_dom, n_global, n_halo, reentrant, tripolar_N, l
14061447
14071448 call clone_MD_to_d2D(MOM_dom, MOM_dom% mpp_domain)
14081449
1409- ! For downsampled domain, recommend a halo of 1 (or 0?) since we're not doing wide-stencil computations.
1410- ! But that does not work because the downsampled field would not have the correct size to pass the checks, e.g., we get
1411- ! error: downsample_diag_indices_get: peculiar size 28 in i-direction\ndoes not match one of 24 25 26 27
1412- ! call clone_MD_to_d2D(MOM_dom, MOM_dom%mpp_domain_d2, halo_size=(MOM_dom%nihalo/2), coarsen=2)
1413- call clone_MD_to_d2D(MOM_dom, MOM_dom% mpp_domain_d2, coarsen= 2 )
1450+ do dl= 2 ,MAX_DSAMP_LEV
1451+ ! Downsample diagnostics calculations do not need halos.
1452+ call clone_MD_to_d2D(MOM_dom, MOM_dom% mpp_domain_d(dl), coarsen= dl, halo_size= 0 , &
1453+ domain_name= " MOM_domain_d" // char (48 + dl))
1454+ enddo
1455+
14141456end subroutine create_MOM_domain
14151457
14161458! > dealloc_MOM_domain deallocates memory associated with a pointer to a MOM_domain_type
@@ -1420,6 +1462,7 @@ subroutine deallocate_MOM_domain(MOM_domain, cursory)
14201462 logical , optional , intent (in ) :: cursory ! < If true do not deallocate fields associated
14211463 ! ! with the underlying infrastructure
14221464 logical :: invasive ! If true, deallocate fields associated with the underlying infrastructure
1465+ integer :: dl
14231466
14241467 invasive = .true. ; if (present (cursory)) invasive = .not. cursory
14251468
@@ -1428,9 +1471,11 @@ subroutine deallocate_MOM_domain(MOM_domain, cursory)
14281471 if (invasive) call mpp_deallocate_domain(MOM_domain% mpp_domain)
14291472 deallocate (MOM_domain% mpp_domain)
14301473 endif
1431- if (associated (MOM_domain% mpp_domain_d2)) then
1432- if (invasive) call mpp_deallocate_domain(MOM_domain% mpp_domain_d2)
1433- deallocate (MOM_domain% mpp_domain_d2)
1474+ if (associated (MOM_domain% mpp_domain_d)) then
1475+ if (invasive) then
1476+ do dl= 2 ,MAX_DSAMP_LEV ; call mpp_deallocate_domain(MOM_domain% mpp_domain_d(dl)); enddo
1477+ endif
1478+ deallocate (MOM_domain% mpp_domain_d)
14341479 endif
14351480 if (associated (MOM_domain% maskmap)) deallocate (MOM_domain% maskmap)
14361481 deallocate (MOM_domain)
@@ -1527,7 +1572,7 @@ subroutine clone_MD_to_MD(MD_in, MOM_dom, min_halo, halo_size, symmetric, domain
15271572 integer , dimension (:), allocatable :: exnj ! The extents of the grid for each j-row of the layout.
15281573 ! The sum of exni must equal MOM_dom%niglobal.
15291574 integer :: qturns ! The number of quarter turns, restricted to the range of 0 to 3.
1530- integer :: i, j, nl1, nl2
1575+ integer :: i, j, nl1, nl2, dl
15311576 integer :: io_layout_in(2 )
15321577
15331578 qturns = 0
@@ -1542,7 +1587,7 @@ subroutine clone_MD_to_MD(MD_in, MOM_dom, min_halo, halo_size, symmetric, domain
15421587 if (.not. associated (MOM_dom)) then
15431588 allocate (MOM_dom)
15441589 allocate (MOM_dom% mpp_domain)
1545- allocate (MOM_dom% mpp_domain_d2)
1590+ do dl = 2 ,MAX_DSAMP_LEV ; allocate (MOM_dom% mpp_domain_d(dl)) ; enddo
15461591 endif
15471592
15481593! Save the extra data for creating other domains of different resolution that overlay this domain
@@ -1664,7 +1709,11 @@ subroutine clone_MD_to_MD(MD_in, MOM_dom, min_halo, halo_size, symmetric, domain
16641709 endif
16651710
16661711 call clone_MD_to_d2D(MOM_dom, MOM_dom% mpp_domain, xextent= exni, yextent= exnj)
1667- call clone_MD_to_d2D(MOM_dom, MOM_dom% mpp_domain_d2, domain_name= MOM_dom% name, coarsen= 2 )
1712+ do dl= 2 ,MAX_DSAMP_LEV
1713+ ! Downsample diagnostics calculations do not need halos.
1714+ call clone_MD_to_d2D(MOM_dom, MOM_dom% mpp_domain_d(dl), coarsen= dl, halo_size= 0 , &
1715+ domain_name= " MOM_domain_d" // char (48 + dl))
1716+ enddo
16681717
16691718end subroutine clone_MD_to_MD
16701719
@@ -1802,12 +1851,12 @@ subroutine get_domain_extent_MD(Domain, isc, iec, jsc, jec, isd, ied, jsd, jed,
18021851 call mpp_get_compute_domain(Domain% mpp_domain, isc, iec, jsc, jec)
18031852 call mpp_get_data_domain(Domain% mpp_domain, isd, ied, jsd, jed)
18041853 call mpp_get_global_domain(Domain% mpp_domain, isg_, ieg_, jsg_, jeg_)
1805- elseif (coarsen_lev == 2 ) then
1806- if (.not. associated (Domain% mpp_domain_d2 )) call MOM_error(FATAL, &
1807- " get_domain_extent called with coarsen=2 , but Domain%mpp_domain_d2 is not associated." )
1808- call mpp_get_compute_domain(Domain% mpp_domain_d2 , isc, iec, jsc, jec)
1809- call mpp_get_data_domain(Domain% mpp_domain_d2 , isd, ied, jsd, jed)
1810- call mpp_get_global_domain(Domain% mpp_domain_d2 , isg_, ieg_, jsg_, jeg_)
1854+ elseif (coarsen_lev < = MAX_DSAMP_LEV ) then
1855+ if (.not. associated (Domain% mpp_domain_d )) call MOM_error(FATAL, &
1856+ " get_domain_extent called with coarsen_lev , but Domain%mpp_domain_d(coarsen_lev) is not associated." )
1857+ call mpp_get_compute_domain(Domain% mpp_domain_d(coarsen_lev) , isc, iec, jsc, jec)
1858+ call mpp_get_data_domain(Domain% mpp_domain_d(coarsen_lev) , isd, ied, jsd, jed)
1859+ call mpp_get_global_domain(Domain% mpp_domain_d(coarsen_lev) , isg_, ieg_, jsg_, jeg_)
18111860 else
18121861 call MOM_error(FATAL, " get_domain_extent called with an unsupported level of coarsening." )
18131862 endif
0 commit comments