Skip to content

Commit 8a2b5d7

Browse files
authored
Merge branch 'dev/gfdl' into makedep_cleanup
2 parents 117f16b + d234bce commit 8a2b5d7

File tree

6 files changed

+353
-234
lines changed

6 files changed

+353
-234
lines changed

src/core/MOM_barotropic.F90

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module MOM_barotropic
1818
use MOM_grid, only : ocean_grid_type
1919
use MOM_harmonic_analysis, only : HA_accum_FtSSH, harmonic_analysis_CS
2020
use MOM_hor_index, only : hor_index_type
21-
use MOM_io, only : vardesc, var_desc, MOM_read_data, slasher
21+
use MOM_io, only : vardesc, var_desc, MOM_read_data, slasher, NORTH_FACE, EAST_FACE
2222
use MOM_open_boundary, only : ocean_OBC_type, OBC_NONE, open_boundary_query
2323
use MOM_open_boundary, only : OBC_DIRECTION_E, OBC_DIRECTION_W
2424
use MOM_open_boundary, only : OBC_DIRECTION_N, OBC_DIRECTION_S, OBC_segment_type
@@ -4459,6 +4459,10 @@ subroutine barotropic_init(u, v, h, eta, Time, G, GV, US, param_file, diag, CS,
44594459
! drag piston velocity.
44604460
character(len=80) :: wave_drag_var ! The wave drag piston velocity variable
44614461
! name in wave_drag_file.
4462+
character(len=80) :: wave_drag_u ! The wave drag piston velocity variable
4463+
! name in wave_drag_file.
4464+
character(len=80) :: wave_drag_v ! The wave drag piston velocity variable
4465+
! name in wave_drag_file.
44624466
real :: mean_SL ! The mean sea level that is used along with the bathymetry to estimate the
44634467
! geometry when LINEARIZED_BT_CORIOLIS is true or BT_NONLIN_STRESS is false [Z ~> m].
44644468
real :: Z_to_H ! A local unit conversion factor [H Z-1 ~> nondim or kg m-3]
@@ -4703,8 +4707,17 @@ subroutine barotropic_init(u, v, h, eta, Time, G, GV, US, param_file, diag, CS,
47034707
"piston velocities.", default="", do_not_log=.not.CS%linear_wave_drag)
47044708
call get_param(param_file, mdl, "BT_WAVE_DRAG_VAR", wave_drag_var, &
47054709
"The name of the variable in BT_WAVE_DRAG_FILE with the "//&
4706-
"barotropic linear wave drag piston velocities at h points.", &
4710+
"barotropic linear wave drag piston velocities at h points. "//&
4711+
"It will not be used if both BT_WAVE_DRAG_U and BT_WAVE_DRAG_V are defined.", &
47074712
default="rH", do_not_log=.not.CS%linear_wave_drag)
4713+
call get_param(param_file, mdl, "BT_WAVE_DRAG_U", wave_drag_u, &
4714+
"The name of the variable in BT_WAVE_DRAG_FILE with the "//&
4715+
"barotropic linear wave drag piston velocities at u points.", &
4716+
default="", do_not_log=.not.CS%linear_wave_drag)
4717+
call get_param(param_file, mdl, "BT_WAVE_DRAG_V", wave_drag_v, &
4718+
"The name of the variable in BT_WAVE_DRAG_FILE with the "//&
4719+
"barotropic linear wave drag piston velocities at v points.", &
4720+
default="", do_not_log=.not.CS%linear_wave_drag)
47084721
call get_param(param_file, mdl, "BT_WAVE_DRAG_SCALE", wave_drag_scale, &
47094722
"A scaling factor for the barotropic linear wave drag "//&
47104723
"piston velocities.", default=1.0, units="nondim", &
@@ -4924,19 +4937,32 @@ subroutine barotropic_init(u, v, h, eta, Time, G, GV, US, param_file, diag, CS,
49244937
wave_drag_file = trim(slasher(inputdir))//trim(wave_drag_file)
49254938
call log_param(param_file, mdl, "INPUTDIR/BT_WAVE_DRAG_FILE", wave_drag_file)
49264939

4927-
allocate(lin_drag_h(isd:ied,jsd:jed), source=0.0)
4940+
if (len_trim(wave_drag_u) > 0 .and. len_trim(wave_drag_v) > 0) then
4941+
call MOM_read_data(wave_drag_file, wave_drag_u, CS%lin_drag_u, G%Domain, &
4942+
position=EAST_FACE, scale=GV%m_to_H*US%T_to_s)
4943+
call pass_var(CS%lin_drag_u, G%Domain)
4944+
CS%lin_drag_u(:,:) = wave_drag_scale * CS%lin_drag_u(:,:)
49284945

4929-
call MOM_read_data(wave_drag_file, wave_drag_var, lin_drag_h, G%Domain, scale=GV%m_to_H*US%T_to_s)
4930-
call pass_var(lin_drag_h, G%Domain)
4931-
do j=js,je ; do I=is-1,ie
4932-
CS%lin_drag_u(I,j) = wave_drag_scale * 0.5 * (lin_drag_h(i,j) + lin_drag_h(i+1,j))
4933-
enddo ; enddo
4934-
do J=js-1,je ; do i=is,ie
4935-
CS%lin_drag_v(i,J) = wave_drag_scale * 0.5 * (lin_drag_h(i,j) + lin_drag_h(i,j+1))
4936-
enddo ; enddo
4937-
deallocate(lin_drag_h)
4938-
endif
4939-
endif
4946+
call MOM_read_data(wave_drag_file, wave_drag_v, CS%lin_drag_v, G%Domain, &
4947+
position=NORTH_FACE, scale=GV%m_to_H*US%T_to_s)
4948+
call pass_var(CS%lin_drag_v, G%Domain)
4949+
CS%lin_drag_v(:,:) = wave_drag_scale * CS%lin_drag_v(:,:)
4950+
4951+
else
4952+
allocate(lin_drag_h(isd:ied,jsd:jed), source=0.0)
4953+
4954+
call MOM_read_data(wave_drag_file, wave_drag_var, lin_drag_h, G%Domain, scale=GV%m_to_H*US%T_to_s)
4955+
call pass_var(lin_drag_h, G%Domain)
4956+
do j=js,je ; do I=is-1,ie
4957+
CS%lin_drag_u(I,j) = wave_drag_scale * 0.5 * (lin_drag_h(i,j) + lin_drag_h(i+1,j))
4958+
enddo ; enddo
4959+
do J=js-1,je ; do i=is,ie
4960+
CS%lin_drag_v(i,J) = wave_drag_scale * 0.5 * (lin_drag_h(i,j) + lin_drag_h(i,j+1))
4961+
enddo ; enddo
4962+
deallocate(lin_drag_h)
4963+
endif ! len_trim(wave_drag_u) > 0 .and. len_trim(wave_drag_v) > 0
4964+
endif ! len_trim(wave_drag_file) > 0
4965+
endif ! CS%linear_wave_drag
49404966

49414967
CS%dtbt_fraction = 0.98 ; if (dtbt_input < 0.0) CS%dtbt_fraction = -dtbt_input
49424968

src/diagnostics/MOM_spatial_means.F90

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ module MOM_spatial_means
77
use MOM_coms, only : EFP_to_real, real_to_EFP, EFP_sum_across_PEs
88
use MOM_coms, only : reproducing_sum, reproducing_sum_EFP, EFP_to_real
99
use MOM_coms, only : query_EFP_overflow_error, reset_EFP_overflow_error
10+
use MOM_coms, only : max_across_PEs, min_across_PEs
1011
use MOM_error_handler, only : MOM_error, NOTE, WARNING, FATAL, is_root_pe
1112
use MOM_file_parser, only : get_param, log_version, param_file_type
1213
use MOM_grid, only : ocean_grid_type
14+
use MOM_hor_index, only : hor_index_type
1315
use MOM_verticalGrid, only : verticalGrid_type
1416

1517
implicit none ; private
@@ -21,6 +23,7 @@ module MOM_spatial_means
2123
public :: global_area_integral
2224
public :: global_volume_mean, global_mass_integral, global_mass_int_EFP
2325
public :: adjust_area_mean_to_zero
26+
public :: array_global_min_max
2427

2528
! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
2629
! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
@@ -701,4 +704,192 @@ subroutine adjust_area_mean_to_zero(array, G, scaling, unit_scale, unscale)
701704

702705
end subroutine adjust_area_mean_to_zero
703706

707+
708+
!> Find the global maximum and minimum of a tracer array and return the locations of the extrema.
709+
!! When there multiple cells with the same extreme values, the reported locations are from the
710+
!! uppermost layer where they occur, and then from the logically northernmost and then eastermost
711+
!! such location on the unrotated version of the grid within that layer. Only ocean points (as
712+
!! indicated by a positive value of G%mask2dT) are evaluated, and if there are no ocean points
713+
!! anywhere in the domain, the reported extrema and their locations are all returned as 0.
714+
subroutine array_global_min_max(tr_array, G, nk, g_min, g_max, &
715+
xgmin, ygmin, zgmin, xgmax, ygmax, zgmax, unscale)
716+
integer, intent(in) :: nk !< The number of vertical levels
717+
type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
718+
real, dimension(SZI_(G),SZJ_(G),nk), intent(in) :: tr_array !< The tracer array to search for
719+
!! extrema in arbitrary concentration units [CU ~> conc]
720+
real, intent(out) :: g_min !< The global minimum of tr_array, either in
721+
!! the same units as tr_array [CU ~> conc] or in
722+
!! unscaled units if unscale is present [conc]
723+
real, intent(out) :: g_max !< The global maximum of tr_array, either in
724+
!! the same units as tr_array [CU ~> conc] or in
725+
!! unscaled units if unscale is present [conc]
726+
real, optional, intent(out) :: xgmin !< The x-position of the global minimum in the
727+
!! units of G%geoLonT, often [degrees_E] or [km] or [m]
728+
real, optional, intent(out) :: ygmin !< The y-position of the global minimum in the
729+
!! units of G%geoLatT, often [degrees_N] or [km] or [m]
730+
real, optional, intent(out) :: zgmin !< The z-position of the global minimum [layer]
731+
real, optional, intent(out) :: xgmax !< The x-position of the global maximum in the
732+
!! units of G%geoLonT, often [degrees_E] or [km] or [m]
733+
real, optional, intent(out) :: ygmax !< The y-position of the global maximum in the
734+
!! units of G%geoLatT, often [degrees_N] or [km] or [m]
735+
real, optional, intent(out) :: zgmax !< The z-position of the global maximum [layer]
736+
real, optional, intent(in) :: unscale !< A factor to use to undo any scaling of
737+
!! the input tracer array [conc CU-1 ~> 1]
738+
739+
! Local variables
740+
real :: tmax, tmin ! Maximum and minimum tracer values, in the same units as tr_array [CU ~> conc]
741+
integer :: ijk_min_max(2) ! Integers encoding the global grid positions of the global minimum and maximum values
742+
real :: xyz_min_max(6) ! A single array with the x-, y- and z-positions of the minimum and
743+
! maximum values in units that vary between the array elements [various]
744+
logical :: valid_PE ! True if there are any valid points on the local PE.
745+
logical :: find_location ! If true, report the locations of the extrema
746+
integer :: ijk_loc_max ! An integer encoding the global grid position of the maximum tracer value on this PE
747+
integer :: ijk_loc_min ! An integer encoding the global grid position of the minimum tracer value on this PE
748+
integer :: ijk_loc_here ! An integer encoding the global grid position of the current grid point
749+
integer :: itmax, jtmax, ktmax, itmin, jtmin, ktmin
750+
integer :: i, j, k, isc, iec, jsc, jec
751+
752+
isc = G%isc ; iec = G%iec ; jsc = G%jsc ; jec = G%jec
753+
754+
find_location = (present(xgmin) .or. present(ygmin) .or. present(zgmin) .or. &
755+
present(xgmax) .or. present(ygmax) .or. present(zgmax))
756+
757+
! The initial values set here are never used if there are any valid points.
758+
tmax = -huge(tmax) ; tmin = huge(tmin)
759+
760+
if (find_location) then
761+
! Find the maximum and minimum tracer values on this PE and their locations.
762+
valid_PE = .false.
763+
itmax = 0 ; jtmax = 0 ; ktmax = 0 ; ijk_loc_max = 0
764+
itmin = 0 ; jtmin = 0 ; ktmin = 0 ; ijk_loc_min = 0
765+
do k=1,nk ; do j=jsc,jec ; do i=isc,iec ; if (G%mask2dT(i,j) > 0.0) then
766+
valid_PE = .true.
767+
if (tr_array(i,j,k) > tmax) then
768+
tmax = tr_array(i,j,k)
769+
itmax = i ; jtmax = j ; ktmax = k
770+
ijk_loc_max = ijk_loc(i, j, k, nk, G%HI)
771+
elseif ((tr_array(i,j,k) == tmax) .and. (k <= ktmax)) then
772+
ijk_loc_here = ijk_loc(i, j, k, nk, G%HI)
773+
if (ijk_loc_here > ijk_loc_max) then
774+
itmax = i ; jtmax = j ; ktmax = k
775+
ijk_loc_max = ijk_loc_here
776+
endif
777+
endif
778+
if (tr_array(i,j,k) < tmin) then
779+
tmin = tr_array(i,j,k)
780+
itmin = i ; jtmin = j ; ktmin = k
781+
ijk_loc_min = ijk_loc(i, j, k, nk, G%HI)
782+
elseif ((tr_array(i,j,k) == tmin) .and. (k <= ktmin)) then
783+
ijk_loc_here = ijk_loc(i, j, k, nk, G%HI)
784+
if (ijk_loc_here > ijk_loc_min) then
785+
itmin = i ; jtmin = j ; ktmin = k
786+
ijk_loc_min = ijk_loc_here
787+
endif
788+
endif
789+
endif ; enddo ; enddo ; enddo
790+
else
791+
! Only the maximum and minimum values are needed, and not their positions.
792+
do k=1,nk ; do j=jsc,jec ; do i=isc,iec ; if (G%mask2dT(i,j) > 0.0) then
793+
if (tr_array(i,j,k) > tmax) tmax = tr_array(i,j,k)
794+
if (tr_array(i,j,k) < tmin) tmin = tr_array(i,j,k)
795+
endif ; enddo ; enddo ; enddo
796+
endif
797+
798+
! Find the global maximum and minimum tracer values.
799+
g_max = tmax ; g_min = tmin
800+
call max_across_PEs(g_max)
801+
call min_across_PEs(g_min)
802+
803+
if (find_location) then
804+
if (g_max < g_min) then
805+
! This only occurs if there are no unmasked points anywhere in the domain.
806+
xyz_min_max(:) = 0.0
807+
else
808+
! Find the global indices of the maximum and minimum locations. This can
809+
! occur on multiple PEs.
810+
ijk_min_max(1:2) = 0
811+
if (valid_PE) then
812+
if (g_min == tmin) ijk_min_max(1) = ijk_loc_min
813+
if (g_max == tmax) ijk_min_max(2) = ijk_loc_max
814+
endif
815+
! If MOM6 supported taking maxima on arrays of integers, these could be combined as:
816+
! call max_across_PEs(ijk_min_max, 2)
817+
call max_across_PEs(ijk_min_max(1))
818+
call max_across_PEs(ijk_min_max(2))
819+
820+
! Set the positions of the extrema if they occur on this PE. This will only
821+
! occur on a single PE.
822+
xyz_min_max(1:6) = -huge(xyz_min_max) ! These huge negative values are never selected by max_across_PEs.
823+
if (valid_PE) then
824+
if (ijk_min_max(1) == ijk_loc_min) then
825+
xyz_min_max(1) = G%geoLonT(itmin,jtmin)
826+
xyz_min_max(2) = G%geoLatT(itmin,jtmin)
827+
xyz_min_max(3) = real(ktmin)
828+
endif
829+
if (ijk_min_max(2) == ijk_loc_max) then
830+
xyz_min_max(4) = G%geoLonT(itmax,jtmax)
831+
xyz_min_max(5) = G%geoLatT(itmax,jtmax)
832+
xyz_min_max(6) = real(ktmax)
833+
endif
834+
endif
835+
836+
call max_across_PEs(xyz_min_max, 6)
837+
endif
838+
839+
if (present(xgmin)) xgmin = xyz_min_max(1)
840+
if (present(ygmin)) ygmin = xyz_min_max(2)
841+
if (present(zgmin)) zgmin = xyz_min_max(3)
842+
if (present(xgmax)) xgmax = xyz_min_max(4)
843+
if (present(ygmax)) ygmax = xyz_min_max(5)
844+
if (present(zgmax)) zgmax = xyz_min_max(6)
845+
endif
846+
847+
if (g_max < g_min) then
848+
! There are no unmasked points anywhere in the domain.
849+
g_max = 0.0 ; g_min = 0.0
850+
endif
851+
852+
if (present(unscale)) then
853+
! Rescale g_min and g_max, perhaps changing their units from [CU ~> conc] to [conc]
854+
g_max = unscale * g_max
855+
g_min = unscale * g_min
856+
endif
857+
858+
end subroutine array_global_min_max
859+
860+
! Return a positive integer encoding the rotationally invariant global position of a tracer cell
861+
function ijk_loc(i, j, k, nk, HI)
862+
integer, intent(in) :: i !< Local i-index
863+
integer, intent(in) :: j !< Local j-index
864+
integer, intent(in) :: k !< Local k-index
865+
integer, intent(in) :: nk !< Range of k-index, used to pick out a low-k position.
866+
type(hor_index_type), intent(in) :: HI !< Horizontal index ranges
867+
integer :: ijk_loc ! An integer encoding the cell position in the global grid.
868+
869+
! Local variables
870+
integer :: ig, jg ! Global index values with a global computational domain start value of 1.
871+
integer :: ij_loc ! The encoding of the horizontal position
872+
integer :: qturns ! The number of counter-clockwise quarter turns of the grid that have to be undone
873+
874+
! These global i-grid positions run from 1 to HI%niglobal, and analogously for jg.
875+
ig = i + HI%idg_offset + (1 - HI%isg)
876+
jg = j + HI%jdg_offset + (1 - HI%jsg)
877+
878+
! Compensate for the rotation of the model grid to give a rotationally invariant encoding.
879+
qturns = modulo(HI%turns, 4)
880+
if (qturns == 0) then
881+
ij_loc = ig + HI%niglobal * jg
882+
elseif (qturns == 1) then
883+
ij_loc = jg + HI%njglobal * ((HI%niglobal+1)-ig)
884+
elseif (qturns == 2) then
885+
ij_loc = ((HI%niglobal+1)-ig) + HI%niglobal * ((HI%njglobal+1)-jg)
886+
elseif (qturns == 3) then
887+
ij_loc = ((HI%njglobal+1)-jg) + HI%njglobal * ig
888+
endif
889+
890+
ijk_loc = ij_loc + (HI%niglobal*HI%njglobal) * (nk-k)
891+
892+
end function ijk_loc
893+
894+
704895
end module MOM_spatial_means

0 commit comments

Comments
 (0)