← back to index

src/diagnostics/MOM_spatial_means.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

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
5!> Functions and routines to take area, volume, mass-weighted, layerwise, zonal or meridional means
6module MOM_spatial_means
7
8use MOM_coms, only : EFP_type, operator(+), operator(-), assignment(=)
9use MOM_coms, only : EFP_to_real, real_to_EFP, EFP_sum_across_PEs
10use MOM_coms, only : reproducing_sum, reproducing_sum_EFP, EFP_to_real
11use MOM_coms, only : query_EFP_overflow_error, reset_EFP_overflow_error
12use MOM_coms, only : max_across_PEs, min_across_PEs
13use MOM_error_handler, only : MOM_error, NOTE, WARNING, FATAL, is_root_pe
14use MOM_file_parser, only : get_param, log_version, param_file_type
15use MOM_grid, only : ocean_grid_type
16use MOM_hor_index, only : hor_index_type
17use MOM_verticalGrid, only : verticalGrid_type
18
19implicit none ; private
20
21#include <MOM_memory.h>
22
23public :: global_i_mean, global_j_mean
24public :: global_area_mean, global_area_mean_u, global_area_mean_v, global_layer_mean
25public :: global_area_integral
26public :: global_volume_mean, global_mass_integral, global_mass_int_EFP
27public :: adjust_area_mean_to_zero
28public :: array_global_min_max
29
30! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
31! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
32! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
33! vary with the Boussinesq approximation, the Boussinesq variant is given first.
34! The functions in this module work with variables with arbitrary units, in which case the
35! arbitrary rescaled units are indicated with [A ~> a], while the unscaled units are just [a].
36
37contains
38
39!> Return the global area mean of a variable, perhaps with a change of units. This uses reproducing sums.
4012function global_area_mean(var, G, scale, tmp_scale, unscale)
41 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
42 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: var !< The variable to average in arbitrary units [a],
43 !! or arbitrary rescaled units [A ~> a] if unscale
44 !! or tmp_scale is present
45 !! arbitrary, possibly rescaled units [A ~> a]
46 real, optional, intent(in) :: scale !< A rescaling factor for the variable [a A-1 ~> 1]
47 !! that converts it back to unscaled (e.g., mks)
48 !! units to enable the use of the reproducing sums
49 real, optional, intent(in) :: tmp_scale !< A temporary rescaling factor for the variable
50 !! that is reversed in the return value [a A-1 ~> 1],
51 !! or [b B-1 ~> 1] if unscale is also present.
52 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
53 !! that converts it back to unscaled (e.g., mks)
54 !! units to enable the use of the reproducing sums, or
55 !! a factor converting between rescaled units if
56 !! tmp_scale is also present [B A-1 ~> b a-1].
57 !! Here scale and unscale are synonymous, but unscale
58 !! is preferred and takes precedence.
59 real :: global_area_mean ! The mean of the variable in arbitrary unscaled units [a] or scaled units [A ~> a]
60 ! or [B ~> b], depending on which optional arguments are provided
61
62 ! Local variables
63 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
64 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums.
65 ! [A ~> a] and [B ~> b] are the same units unless tmp_scale and unscale are both present.
6624 real :: tmpForSumming(SZI_(G),SZJ_(G)) ! An unscaled cell integral in [a L2 ~> a m2] or a
67 ! scaled cell integral in [A L2 ~> a m2] or [B L2 ~> b m2]
68 real :: scalefac ! A scaling factor for the variable that is not reversed [a A-1 ~> 1] or [B A-1 ~> b a-1] or [1]
69 real :: temp_scale ! A temporary scaling factor [a A-1 ~> 1] or [b B-1 ~> 1] or [1]
70 integer :: i, j, is, ie, js, je
7112 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
72
7312 temp_scale = 1.0 ; if (present(tmp_scale)) temp_scale = tmp_scale
74
7512 scalefac = 1.0
7612 if (present(unscale)) then ; scalefac = unscale
7712 elseif (present(scale)) then ; scalefac = scale ; endif
78
79105276 tmpForSumming(:,:) = 0.
8087132 do j=js,je ; do i=is,ie
8187120 tmpForSumming(i,j) = var(i,j) * (scalefac * G%areaT(i,j) * G%mask2dT(i,j))
82 enddo ; enddo
83
8412 global_area_mean = reproducing_sum(tmpForSumming, unscale=temp_scale*G%US%L_to_m**2) * G%IareaT_global
85
8612end function global_area_mean
87
88!> Return the global area mean of a variable. This uses reproducing sums.
890function global_area_mean_v(var, G, tmp_scale)
90 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
91 real, dimension(SZI_(G),SZJB_(G)), intent(in) :: var !< The variable to average in arbitrary
92 !! units [a], or arbitrary rescaled units
93 !! [A ~> a] if tmp_scale is present
94 real, optional, intent(in) :: tmp_scale !< A temporary rescaling factor for the
95 !! variable that converts it back to unscaled
96 !! (e.g., mks) units to enable the use of the
97 !! reproducing sums [a A-1 ~> 1], but is reversed
98 !! before output so that the return value has
99 !! the same units as var
100
101 real :: global_area_mean_v ! The mean of the variable in the same arbitrary units as var [A ~> a]
102
103 ! Local variables
104 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
105 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
106 ! [A ~> a] and [B ~> b] are the same unless tmp_scale and unscale are both present.
1070 real, dimension(SZI_(G),SZJ_(G)) :: tmpForSumming ! An unscaled cell integral [A L2 ~> a m2]
108 real :: temp_scale ! A temporary scaling factor [a A-1 ~> 1] or [1]
109 integer :: i, j, is, ie, js, je, isB, ieB, jsB, jeB
110
1110 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
1120 isB = G%iscB ; ieB = G%iecB ; jsB = G%jscB ; jeB = G%jecB
113
1140 temp_scale = 1.0 ; if (present(tmp_scale)) temp_scale = tmp_scale
115
1160 tmpForSumming(:,:) = 0.
1170 do j=js,je ; do i=is,ie
118 tmpForSumming(i,j) = G%areaT(i,j) * &
119 (var(i,J) * G%mask2dCv(i,J) + var(i,J-1) * G%mask2dCv(i,J-1)) / &
1200 max(1.e-20, G%mask2dCv(i,J)+G%mask2dCv(i,J-1))
121 enddo ; enddo
1220 global_area_mean_v = reproducing_sum(tmpForSumming, unscale=G%US%L_to_m**2*temp_scale) * G%IareaT_global
123
1240end function global_area_mean_v
125
126!> Return the global area mean of a variable on U grid. This uses reproducing sums.
1270function global_area_mean_u(var, G, tmp_scale)
128 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
129 real, dimension(SZIB_(G),SZJ_(G)), intent(in) :: var !< The variable to average in arbitrary
130 !! units [a], or arbitrary rescaled units
131 !! [A ~> a] if tmp_scale is present
132 real, optional, intent(in) :: tmp_scale !< A temporary rescaling factor for the
133 !! variable that converts it back to unscaled
134 !! (e.g., mks) units to enable the use of the
135 !! reproducing sums [a A-1 ~> 1], but is reversed
136 !! before output so that the return value has
137 !! the same units as var
138 real :: global_area_mean_u ! The mean of the variable in the same arbitrary units as var [A ~> a]
139
140 ! Local variables
141 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
142 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
1430 real, dimension(SZI_(G),SZJ_(G)) :: tmpForSumming ! An unscaled cell integral [A L2 ~> a m2]
144 real :: temp_scale ! A temporary scaling factor [a A-1 ~> 1] or [1]
145 integer :: i, j, is, ie, js, je, isB, ieB, jsB, jeB
146
1470 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
1480 isB = G%iscB ; ieB = G%iecB ; jsB = G%jscB ; jeB = G%jecB
149
1500 temp_scale = 1.0 ; if (present(tmp_scale)) temp_scale = tmp_scale
151
1520 tmpForSumming(:,:) = 0.
1530 do j=js,je ; do i=is,ie
154 tmpForSumming(i,j) = G%areaT(i,j) * &
155 (var(I,j) * G%mask2dCu(I,j) + var(I-1,j) * G%mask2dCu(I-1,j)) / &
1560 max(1.e-20, G%mask2dCu(I,j)+G%mask2dCu(I-1,j))
157 enddo ; enddo
1580 global_area_mean_u = reproducing_sum(tmpForSumming, unscale=G%US%L_to_m**2*temp_scale) * G%IareaT_global
159
1600end function global_area_mean_u
161
162!> Return the global area integral of a variable using reproducing sums, perhaps with a change of units.
163!! By default the integral uses the masked area from the grid, but an alternate could be used instead.
164!! The presence of the optional tmp_scale argument determines whether the returned value is in scaled
165!! (if it is present) or unscaled units for both the variable itself and for the area in the integral.
1660function global_area_integral(var, G, scale, area, tmp_scale, unscale)
167 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
168 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: var !< The variable to integrate in arbitrary units [a],
169 !! or arbitrary rescaled units [A ~> a] if unscale
170 !! or tmp_scale is present
171 real, optional, intent(in) :: scale !< A rescaling factor for the variable [a A-1 ~> 1]
172 !! that converts it back to unscaled (e.g., mks)
173 !! units to enable the use of the reproducing sums
174 real, dimension(SZI_(G),SZJ_(G)), optional, intent(in) :: area !< The alternate area to use, including
175 !! any required masking [L2 ~> m2].
176 real, optional, intent(in) :: tmp_scale !< A temporary rescaling factor for the variable
177 !! that is reversed in the return value [a A-1 ~> 1],
178 !! or [b B-1 ~> 1] if unscale is also present.
179 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
180 !! that converts it back to unscaled (e.g., mks)
181 !! units to enable the use of the reproducing sums, or
182 !! a factor converting between rescaled units if
183 !! tmp_scale is also present [B A-1 ~> b a-1].
184 !! Here scale and unscale are synonymous, but unscale
185 !! is preferred and takes precedence if both are present.
186 real :: global_area_integral !< The returned area integral, usually in the units of var times an area,
187 !! [a m2] or [A L2 ~> a m2] or [B L2 ~> b m2], depending on which optional
188 !! arguments are provided
189
190 ! Local variables
191 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
192 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums.
193 ! [A ~> a] and [B ~> b] are the same units unless tmp_scale and unscale are both present.
1940 real, dimension(SZI_(G),SZJ_(G)) :: tmpForSumming ! An unscaled cell integral in [a m2] or
195 ! a scaled cell integral in [B L2 ~> b m2] or other units as indicated below
196 real :: scalefac ! An overall scaling factor for the areas and variable, in units of [a m2 A-1 L-2 ~> 1]
197 ! or [1] or [B m2 A-1 L-2 ~> b a-1] or [B A-1 ~> b a-1] depending on which
198 ! optional arguments are present.
199 !_______________________________________________________________________________________________
200 ! Table of units of scalefac and tmpForSumming, depending on the presence of optional arguments |
201 !_______________________________________________________________________________________________|
202 ! present(tmp_scale) | present(unscale) | scalefac units | tmpForSumming units |
203 !____________________|__________________|_________________________|_____________________________!
204 ! True | True | [B A-1 ~> b a-1] | [B L2 ~> b m2] |
205 ! True | False | [1] | [A L2 ~> a m2] |
206 ! False | True | [a m2 A-1 L-2 ~> b a-1] | [a m2] |
207 ! False | False | [m2 L-2 ~> 1] | [a m2] |
208 !____________________|__________________|_________________________|_____________________________!
209 real :: temp_scale ! A temporary scaling factor [a m2 L-2 A-1 ~> 1] or [b m2 L-2 B-1 ~> 1] or [1]
210 integer :: i, j, is, ie, js, je
2110 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
212
2130 if (present(tmp_scale)) then
2140 temp_scale = G%US%L_to_m**2 * tmp_scale ! Units of [a m2 A-1 L-2 ~> 1] or [b m2 B-1 L-2 ~> 1]
2150 scalefac = 1.0
216 else
2170 temp_scale = 1.0
2180 scalefac = G%US%L_to_m**2
219 endif
2200 if (present(unscale)) then ; scalefac = scalefac * unscale
2210 elseif (present(scale)) then ; scalefac = scalefac * scale ; endif
222
2230 tmpForSumming(:,:) = 0.
2240 if (present(area)) then
2250 do j=js,je ; do i=is,ie
2260 tmpForSumming(i,j) = var(i,j) * (scalefac * area(i,j))
227 enddo ; enddo
228 else
2290 do j=js,je ; do i=is,ie
2300 tmpForSumming(i,j) = var(i,j) * (scalefac * G%areaT(i,j) * G%mask2dT(i,j))
231 enddo ; enddo
232 endif
233
2340 global_area_integral = reproducing_sum(tmpForSumming, unscale=temp_scale)
235
2360end function global_area_integral
237
238!> Return the layerwise global thickness-weighted mean of a variable. This uses reproducing sums.
2390function global_layer_mean(var, h, G, GV, scale, tmp_scale, unscale)
240 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
241 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
242 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: var !< The variable to average in arbitrary units [a],
243 !! or arbitrary rescaled units [A ~> a] if unscale
244 !! or tmp_scale is present
245 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
246 real, optional, intent(in) :: scale !< A rescaling factor for the variable [a A-1 ~> 1]
247 !! that converts it back to unscaled (e.g., mks)
248 !! units to enable the use of the reproducing sums
249 real, optional, intent(in) :: tmp_scale !< A temporary rescaling factor for the
250 !! variable for use in the reproducing sums
251 !! that is reversed in the return value [a A-1 ~> 1],
252 !! or [b B-1 ~> 1] if unscale is also present.
253 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
254 !! that converts it back to unscaled (e.g., mks)
255 !! units to enable the use of the reproducing sums, or
256 !! a factor converting between rescaled units if
257 !! tmp_scale is also present [B A-1 ~> b a-1].
258 !! Here scale and unscale are synonymous, but unscale
259 !! is preferred and takes precedence.
260 real, dimension(SZK_(GV)) :: global_layer_mean !< The mean of the variable in the arbitrary scaled [A ~> a]
261 !! or [B ~> b] or unscaled [a] units of var, depending on which
262 !! optional arguments are provided
263
264 ! Local variables
265 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
266 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
2670 real :: tmpForSumming(G%isc:G%iec,G%jsc:G%jec,SZK_(GV)) ! An unscaled cell integral in [L2 a m ~> a m3] or
268 ! [L2 a kg m-2 ~> a kg] or a scaled cell integral in
269 ! [L2 B m ~> b m3] or [L2 B m ~> b m3] or other units
270 ! as indicated the table below.
2710 real :: weight(G%isc:G%iec,G%jsc:G%jec,SZK_(GV)) ! The volume or mass of each cell, depending on whether
272 ! the model is Boussinesq, used as a weight [L2 m ~> m3]
273 ! or [L2 kg m-2 ~> kg]
274 real :: scalefac ! A scaling factor for the variable [a A-1 ~> 1] or [B A-1 ~> b a-1] or [1]
275 !__________________________________________________________________________________________________
276 ! Units of weight, scalefac and tmpForSumming, depending on the presence of optional arguments |
277 !_________________________________________________________________________________________________|
278 ! Boussinesq | tmp_scale | unscale | weight units | scalefac units | tmpForSumming units |
279 ! | present | present | | | |
280 !____________|___________|_________|___________________|__________________|_______________________!
281 ! True | True | True | [L2 m ~> m3] | [B A-1 ~> b a-1] | [B L2 m ~> b m3] |
282 ! True | True | False | [L2 m ~> m3] | [1] | [A L2 m ~> a m3] |
283 ! True | False | True | [L2 m ~> m3] | [a A-1 ~> 1] | [L2 a m ~> a m3] |
284 ! True | False | False | [L2 m ~> m3] | [1] | [L2 a m ~> a m3] |
285 ! False | True | True | [L2 kg m-2 ~> kg] | [B A-1 ~> b a-1] | [B L2 kg m-2 ~> b kg] |
286 ! False | True | False | [L2 kg m-2 ~> kg] | [1] | [A L2 kg m-2 ~> a kg] |
287 ! False | False | True | [L2 kg m-2 ~> kg] | [a A-1 ~> 1] | [L2 a kg m-2 ~> a kg] |
288 ! False | False | False | [L2 kg m-2 ~> kg] | [1] | [L2 a kg m-2 ~> a kg] |
289 !____________|___________|_________|___________________|__________________|_______________________!
2900 type(EFP_type) :: laysums(2*SZK_(GV)) ! A vector of sums with heterogeneous meanings, with the first
291 ! half being the tracer integrals in [b m3] or [b kg] and the
292 ! second half being the summed weights in [m3] or [kg]
293 real :: global_temp_scalar ! The global integral of the tracer over all
294 ! layers [L2 a m ~> a m3] or [L2 a kg m-2 ~> a kg]
295 real :: global_weight_scalar ! The global integral of the volume or mass over all
296 ! layers [L2 m ~> m3] or [L2 kg m-2 ~> kg]
297 real :: temp_scale ! A temporary scaling factor [a A-1 ~> 1] or [b B-1 ~> 1] or [1]
298 integer :: i, j, k, is, ie, js, je, nz
2990 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
300
3010 temp_scale = 1.0 ; if (present(tmp_scale)) temp_scale = tmp_scale
302
3030 scalefac = 1.0
3040 if (present(unscale)) then ; scalefac = unscale
3050 elseif (present(scale)) then ; scalefac = scale ; endif
3060 tmpForSumming(:,:,:) = 0. ; weight(:,:,:) = 0.
307
3080 do k=1,nz ; do j=js,je ; do i=is,ie
3090 weight(i,j,k) = (GV%H_to_MKS * h(i,j,k)) * (G%areaT(i,j) * G%mask2dT(i,j))
3100 tmpForSumming(i,j,k) = scalefac * var(i,j,k) * weight(i,j,k)
311 enddo ; enddo ; enddo
312
313 global_temp_scalar = reproducing_sum(tmpForSumming, EFP_lay_sums=laysums(1:nz), only_on_PE=.true., &
3140 unscale=temp_scale*G%US%L_to_m**2)
315 global_weight_scalar = reproducing_sum(weight, EFP_lay_sums=laysums(nz+1:2*nz), only_on_PE=.true., &
3160 unscale=G%US%L_to_m**2)
3170 call EFP_sum_across_PEs(laysums, 2*nz)
318
319 ! Note that temp_scale appears in the denominator here because the variables returned via the
320 ! EFP_lay_sums arguments to reproducing sums stay in unscaled mks units.
3210 do k=1,nz
3220 global_layer_mean(k) = EFP_to_real(laysums(k)) / (temp_scale*EFP_to_real(laysums(nz+k)))
323 enddo
324
325end function global_layer_mean
326
327!> Find the global thickness-weighted mean of a variable. This uses reproducing sums.
3280function global_volume_mean(var, h, G, GV, scale, tmp_scale, unscale)
329 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
330 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
331 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
332 intent(in) :: var !< The variable to average in arbitrary units [a],
333 !! or arbitrary rescaled units [A ~> a] if unscale
334 !! or tmp_scale is present
335 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
336 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
337 real, optional, intent(in) :: scale !< A rescaling factor for the variable [a A-1 ~> 1]
338 !! that converts it back to unscaled (e.g., mks)
339 !! units to enable the use of the reproducing sums
340 real, optional, intent(in) :: tmp_scale !< A temporary rescaling factor for the
341 !! variable that is reversed in the return value [a A-1 ~> 1],
342 !! or [b B-1 ~> 1] if unscale is also present.
343 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
344 !! that converts it back to unscaled (e.g., mks)
345 !! units to enable the use of the reproducing sums, or
346 !! a factor converting between rescaled units if
347 !! tmp_scale is also present [B A-1 ~> b a-1].
348 !! Here scale and unscale are synonymous, but unscale
349 !! is preferred and takes precedence if both are present.
350 real :: global_volume_mean !< The thickness-weighted average of var in the arbitrary scaled [A ~> a] or [B ~> b] or
351 !! unscaled [a] units of var, depending on which optional arguments are provided
352
353 ! Local variables
354 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
355 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
356 ! [A ~> a] and [B ~> b] are the same units unless tmp_scale and unscale are both present.
357 real :: temp_scale ! A temporary scaling factor [a A-1 ~> 1] or [b B-1 ~> 1] or [1]
358 real :: scalefac ! A scaling factor for the variable [a A-1 ~> 1] or [B A-1 ~> b a-1] or [1]
359 real :: weight_here ! The volume or mass of a grid cell [L2 m ~> m3] or [L2 kg m-2 ~> kg]
3600 real, dimension(SZI_(G),SZJ_(G)) :: tmpForSumming ! The volume or mass integral of the variable in a column
361 ! [B L2 m ~> b m3] or [B L2 kg m-2 ~> b kg] or
362 ! [L2 a m ~> a m3] or [L2 a kg m-2 ~> a kg]
3630 real, dimension(SZI_(G),SZJ_(G)) :: sum_weight ! The volume or mass of each column of water
364 ! [L2 m ~> m3] or [L2 kg m-2 ~> kg]
365 integer :: i, j, k, is, ie, js, je, nz
3660 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
367
3680 temp_scale = 1.0 ; if (present(tmp_scale)) temp_scale = tmp_scale
369
3700 scalefac = 1.0
3710 if (present(unscale)) then ; scalefac = unscale
3720 elseif (present(scale)) then ; scalefac = scale ; endif
3730 tmpForSumming(:,:) = 0. ; sum_weight(:,:) = 0.
374
3750 do k=1,nz ; do j=js,je ; do i=is,ie
3760 weight_here = (GV%H_to_MKS * h(i,j,k)) * (G%areaT(i,j) * G%mask2dT(i,j))
3770 tmpForSumming(i,j) = tmpForSumming(i,j) + scalefac * var(i,j,k) * weight_here
3780 sum_weight(i,j) = sum_weight(i,j) + weight_here
379 enddo ; enddo ; enddo
380 global_volume_mean = (reproducing_sum(tmpForSumming, unscale=temp_scale*G%US%L_to_m**2)) / &
3810 (reproducing_sum(sum_weight, unscale=G%US%L_to_m**2))
382
3830end function global_volume_mean
384
385
386!> Find the global mass-weighted integral of a variable. The presence of the optional tmp_scale
387!! argument determines whether the returned value is in scaled (if it is present) or unscaled units
388!! for both the variable itself and for the mass in the integral. This function uses reproducing sums.
3890function global_mass_integral(h, G, GV, var, on_PE_only, scale, tmp_scale, unscale)
390 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
391 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
392 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
393 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
394 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
395 optional, intent(in) :: var !< The variable to integrate in arbitrary units [a],
396 !! or arbitrary rescaled units [A ~> a] if unscale
397 !! or tmp_scale is present
398 logical, optional, intent(in) :: on_PE_only !< If present and true, the sum is only done
399 !! on the local PE, and it is _not_ order invariant.
400 real, optional, intent(in) :: scale !< A rescaling factor for the variable [a A-1 ~> 1]
401 !! that converts it back to unscaled (e.g., mks)
402 !! units to enable the use of the reproducing sums
403 real, optional, intent(in) :: tmp_scale !< A temporary rescaling factor for the variable
404 !! that is reversed in the return value [a A-1 ~> 1],
405 !! or [b B-1 ~> 1] if unscale is also present.
406 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
407 !! that converts it back to unscaled (e.g., mks)
408 !! units to enable the use of the reproducing sums, or
409 !! a factor converting between rescaled units if
410 !! tmp_scale is also present [B A-1 ~> b a-1].
411 !! Here scale and unscale are synonymous, but unscale
412 !! is preferred and takes precedence if both are present.
413 real :: global_mass_integral !< The mass-weighted integral of var (or 1) in kg times the arbitrary
414 !! units of var [kg a] or in [R Z L2 A ~> kg a] if tmp_scale is present
415 !! or [R Z L2 B ~> kg b] if both unscale and tmp_scale are present
416
417 ! Local variables
418 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
419 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
420 ! [A ~> a] and [B ~> b] are the same units unless tmp_scale and unscale are both present.
4210 real :: tmpForSumming(SZI_(G),SZJ_(G)) ! The mass-weighted integral of the variable in a column in
422 ! [kg a] or [kg] or if tmp_scale is present in [B R Z L2 ~> kg b] or
423 ! [A R Z L2 !> kg m] or [R Z L2 ~> kg]
424 real :: scalefac ! An overall scaling factor for the cell mass and variable in [a kg A-1 R-1 Z-1 L-2 ~> 1]
425 ! or [kg R-1 Z-1 L-2 ~> 1] or [1] or [B A-1 ~> b a-1] if tmp_scale is present.
426 real :: temp_scale ! A temporary scaling factor [1] or if tmp_scale is present this could be in
427 ! [kg a R-1 Z-1 L-2 A-1 ~> 1] or [kg b R-1 Z-1 L-2 B-1 ~> 1] or [kg R-1 Z-1 L-2 ~> 1]
428 !_______________________________________________________________________________________
429 ! Units of scalefac and tmpForSumming, depending on the presence of optional arguments |
430 !______________________________________________________________________________________|
431 ! var | tmp_scale | unscale | scalefac units | tmpForSumming units |
432 ! present | present | present | | |
433 !_________|___________|_________|_____________________________|________________________!
434 ! True | True | True | [B A-1 ~> b a-1] | [B R Z L2 ~> b kg] |
435 ! True | True | False | [1] | [A R Z L2 ~> a kg] |
436 ! True | False | True | [a kg A-1 R-1 Z-1 L-2 ~> 1] | [a kg] |
437 ! True | False | False | [kg R-1 Z-1 L-2 ~> 1] | [a kg] |
438 ! False | True | either | [1] | [R Z L2 ~> kg] |
439 ! False | False | either | [kg R-1 Z-1 L-2 ~> 1] | [kg] |
440 !_________|___________|_________|_____________________________|________________________!
441 logical :: global_sum ! If true do the sum globally, but if false only do the sum on the current PE.
442 integer :: i, j, k, is, ie, js, je, nz
4430 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
444
4450 if (present(tmp_scale)) then
4460 temp_scale = G%US%RZL2_to_kg * tmp_scale
4470 if (.not.present(var)) temp_scale = G%US%RZL2_to_kg
4480 scalefac = 1.0
449 else
4500 temp_scale = 1.0
4510 scalefac = G%US%RZL2_to_kg
452 endif
4530 if (present(var)) then
4540 if (present(unscale)) then ; scalefac = scalefac * unscale
4550 elseif (present(scale)) then ; scalefac = scalefac * scale ; endif
456 endif
457
4580 tmpForSumming(:,:) = 0.0
4590 if (present(var)) then
4600 do k=1,nz ; do j=js,je ; do i=is,ie
461 tmpForSumming(i,j) = tmpForSumming(i,j) + var(i,j,k) * &
4620 ((GV%H_to_RZ * h(i,j,k)) * (scalefac*G%areaT(i,j) * G%mask2dT(i,j)))
463 enddo ; enddo ; enddo
464 else
4650 do k=1,nz ; do j=js,je ; do i=is,ie
466 tmpForSumming(i,j) = tmpForSumming(i,j) + &
4670 ((GV%H_to_RZ * h(i,j,k)) * (scalefac*G%areaT(i,j) * G%mask2dT(i,j)))
468 enddo ; enddo ; enddo
469 endif
4700 global_sum = .true. ; if (present(on_PE_only)) global_sum = .not.on_PE_only
4710 if (global_sum) then
4720 global_mass_integral = reproducing_sum(tmpForSumming, unscale=temp_scale)
473 else
4740 global_mass_integral = 0.0
4750 do j=js,je ; do i=is,ie
4760 global_mass_integral = global_mass_integral + tmpForSumming(i,j)
477 enddo ; enddo
478 endif
479
4800end function global_mass_integral
481
482!> Find the global mass-weighted order invariant integral of a variable in mks units,
483!! returning the value as an EFP_type. This uses reproducing sums.
4843function global_mass_int_EFP(h, G, GV, var, on_PE_only, scale, unscale)
485 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
486 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
487 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
488 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
489 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
490 optional, intent(in) :: var !< The variable to integrate in arbitrary units [a],
491 !! or arbitrary rescaled units [A ~> a] if unscale
492 !! is present
493 logical, optional, intent(in) :: on_PE_only !< If present and true, the sum is only done
494 !! on the local PE, but it is still order invariant.
495 real, optional, intent(in) :: scale !< A rescaling factor for the variable [a A-1 ~> 1]
496 !! that converts it back to unscaled (e.g., mks)
497 !! units to enable the use of the reproducing sums
498 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
499 !! that converts it back to unscaled (e.g., mks)
500 !! units to enable the use of the reproducing sums.
501 !! Here scale and unscale are synonymous, but unscale
502 !! is preferred and takes precedence if both are present.
503 type(EFP_type) :: global_mass_int_EFP !< The mass-weighted integral of var (or 1) in
504 !! kg times the arbitrary units of var [kg a]
505
506 ! Local variables
507 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
508 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
5096 real :: tmpForSum(SZI_(G),SZJ_(G)) ! The mass-weighted integral of the variable in a column [kg a] or [kg]
510 real :: scalefac ! An overall scaling factor for the cell mass and variable [a kg A-1 H-1 L-2 ~> kg m-3 or 1]
511 integer :: i, j, k, is, ie, js, je, nz, isr, ier, jsr, jer
512
5133 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
5143 isr = is - (G%isd-1) ; ier = ie - (G%isd-1) ; jsr = js - (G%jsd-1) ; jer = je - (G%jsd-1)
515
5163 scalefac = GV%H_to_kg_m2 * G%US%L_to_m**2
5173 if (present(unscale)) then ; scalefac = unscale * scalefac
5183 elseif (present(scale)) then ; scalefac = scale * scalefac ; endif
519
52026319 tmpForSum(:,:) = 0.0
5213 if (present(var)) then
5221633728 do k=1,nz ; do j=js,je ; do i=is,ie
523 tmpForSum(i,j) = tmpForSum(i,j) + var(i,j,k) * &
5241633500 ((scalefac * h(i,j,k)) * (G%areaT(i,j) * G%mask2dT(i,j)))
525 enddo ; enddo ; enddo
526 else
5270 do k=1,nz ; do j=js,je ; do i=is,ie
528 tmpForSum(i,j) = tmpForSum(i,j) + &
5290 ((scalefac * h(i,j,k)) * (G%areaT(i,j) * G%mask2dT(i,j)))
530 enddo ; enddo ; enddo
531 endif
532
5333 global_mass_int_EFP = reproducing_sum_EFP(tmpForSum, isr, ier, jsr, jer, only_on_PE=on_PE_only)
534
5356end function global_mass_int_EFP
536
537
538!> Determine the global mean of a field along rows of constant i, returning it
539!! in a 1-d array using the local indexing. This uses reproducing sums.
5400subroutine global_i_mean(array, i_mean, G, mask, scale, tmp_scale, unscale)
541 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
542 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: array !< The variable to integrate in arbitrary units [a],
543 !! or arbitrary rescaled units [A ~> a] if unscale
544 !! is present
545 real, dimension(SZJ_(G)), intent(out) :: i_mean !< Global mean of array along its i-axis [a] or [A ~> a]
546 real, dimension(SZI_(G),SZJ_(G)), &
547 optional, intent(in) :: mask !< An array used for weighting the i-mean [nondim]
548 real, optional, intent(in) :: scale !< A rescaling factor for the output variable [a A-1 ~> 1]
549 !! that converts it back to unscaled (e.g., mks)
550 !! units to enable the use of the reproducing sums
551 real, optional, intent(in) :: tmp_scale !< A rescaling factor for the internal
552 !! calculations that is removed from the output [a A-1 ~> 1]
553 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
554 !! that converts it back to unscaled (e.g., mks)
555 !! units to enable the use of the reproducing sums.
556 !! Here scale and unscale are synonymous, but unscale
557 !! is preferred and takes precedence if both are present.
558
559 ! Local variables
560 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
561 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
5620 type(EFP_type), allocatable, dimension(:) :: asum ! The masked sum of the variable in each row [a]
5630 type(EFP_type), allocatable, dimension(:) :: mask_sum ! The sum of the mask values in each row [nondim]
564 real :: scalefac ! A scaling factor for the variable [a A-1 ~> 1]
565 real :: rescale ! A factor for redoing any internal rescaling before output [A a-1 ~> 1]
566 real :: mask_sum_r ! The sum of the mask values in a row [nondim]
567 integer :: is, ie, js, je, idg_off, jdg_off
568 integer :: i, j
569
5700 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
5710 idg_off = G%idg_offset ; jdg_off = G%jdg_offset
572
5730 scalefac = 1.0
5740 if (present(unscale)) then ; scalefac = unscale
5750 elseif (present(scale)) then ; scalefac = scale ; endif
576
5770 rescale = 1.0
5780 if (present(tmp_scale)) then ; if (tmp_scale /= 0.0) then
5790 scalefac = scalefac * tmp_scale ; rescale = 1.0 / tmp_scale
580 endif ; endif
5810 call reset_EFP_overflow_error()
582
5830 allocate(asum(G%jsg:G%jeg))
5840 if (present(mask)) then
5850 allocate(mask_sum(G%jsg:G%jeg))
586
5870 do j=G%jsg,G%jeg
5880 asum(j) = real_to_EFP(0.0) ; mask_sum(j) = real_to_EFP(0.0)
589 enddo
590
5910 do j=js,je ; do i=is,ie
5920 asum(j+jdg_off) = asum(j+jdg_off) + real_to_EFP(scalefac*array(i,j)*mask(i,j))
5930 mask_sum(j+jdg_off) = mask_sum(j+jdg_off) + real_to_EFP(mask(i,j))
594 enddo ; enddo
595
5960 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
5970 "global_i_mean overflow error occurred before sums across PEs.")
598
5990 call EFP_sum_across_PEs(asum(G%jsg:G%jeg), G%jeg-G%jsg+1)
6000 call EFP_sum_across_PEs(mask_sum(G%jsg:G%jeg), G%jeg-G%jsg+1)
601
6020 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
6030 "global_i_mean overflow error occurred during sums across PEs.")
604
6050 do j=js,je
6060 mask_sum_r = EFP_to_real(mask_sum(j+jdg_off))
6070 if (mask_sum_r == 0.0 ) then ; i_mean(j) = 0.0 ; else
6080 i_mean(j) = EFP_to_real(asum(j+jdg_off)) / mask_sum_r
609 endif
610 enddo
611
6120 deallocate(mask_sum)
613 else
6140 do j=G%jsg,G%jeg ; asum(j) = real_to_EFP(0.0) ; enddo
615
6160 do j=js,je ; do i=is,ie
6170 asum(j+jdg_off) = asum(j+jdg_off) + real_to_EFP(scalefac*array(i,j))
618 enddo ; enddo
619
6200 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
6210 "global_i_mean overflow error occurred before sum across PEs.")
622
6230 call EFP_sum_across_PEs(asum(G%jsg:G%jeg), G%jeg-G%jsg+1)
624
6250 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
6260 "global_i_mean overflow error occurred during sum across PEs.")
627
6280 do j=js,je
6290 i_mean(j) = EFP_to_real(asum(j+jdg_off)) / real(G%ieg-G%isg+1)
630 enddo
631 endif
632
6330 if (rescale /= 1.0) then ; do j=js,je ; i_mean(j) = rescale*i_mean(j) ; enddo ; endif
634
6350 deallocate(asum)
636
6370end subroutine global_i_mean
638
639!> Determine the global mean of a field along rows of constant j, returning it
640!! in a 1-d array using the local indexing. This uses reproducing sums.
6410subroutine global_j_mean(array, j_mean, G, mask, scale, tmp_scale, unscale)
642 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
643 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: array !< The variable to integrate in arbitrary units [a],
644 !! or arbitrary rescaled units [A ~> a] if unscale
645 !! is present
646 real, dimension(SZI_(G)), intent(out) :: j_mean !< Global mean of array along its j-axis [a] or [A ~> a]
647 real, dimension(SZI_(G),SZJ_(G)), &
648 optional, intent(in) :: mask !< An array used for weighting the j-mean [nondim]
649 real, optional, intent(in) :: scale !< A rescaling factor for the output variable [a A-1 ~> 1]
650 !! that converts it back to unscaled (e.g., mks)
651 !! units to enable the use of the reproducing sums
652 real, optional, intent(in) :: tmp_scale !< A rescaling factor for the internal
653 !! calculations that is removed from the output [a A-1 ~> 1]
654 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
655 !! that converts it back to unscaled (e.g., mks)
656 !! units to enable the use of the reproducing sums.
657 !! Here scale and unscale are synonymous, but unscale
658 !! is preferred and takes precedence if both are present.
659
660 ! Local variables
661 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
662 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
6630 type(EFP_type), allocatable, dimension(:) :: asum ! The masked sum of the variable in each row [a]
6640 type(EFP_type), allocatable, dimension(:) :: mask_sum ! The sum of the mask values in each row [nondim]
665 real :: mask_sum_r ! The sum of the mask values in a row [nondim]
666 real :: scalefac ! A scaling factor for the variable [a A-1 ~> 1]
667 real :: rescale ! A factor for redoing any internal rescaling before output [A a-1 ~> 1]
668 integer :: is, ie, js, je, idg_off, jdg_off
669 integer :: i, j
670
6710 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
6720 idg_off = G%idg_offset ; jdg_off = G%jdg_offset
673
6740 scalefac = 1.0
6750 if (present(unscale)) then ; scalefac = unscale
6760 elseif (present(scale)) then ; scalefac = scale ; endif
677
6780 rescale = 1.0
6790 if (present(tmp_scale)) then ; if (tmp_scale /= 0.0) then
6800 scalefac = scalefac * tmp_scale ; rescale = 1.0 / tmp_scale
681 endif ; endif
6820 call reset_EFP_overflow_error()
683
6840 allocate(asum(G%isg:G%ieg))
6850 if (present(mask)) then
6860 allocate (mask_sum(G%isg:G%ieg))
687
6880 do i=G%isg,G%ieg
6890 asum(i) = real_to_EFP(0.0) ; mask_sum(i) = real_to_EFP(0.0)
690 enddo
691
6920 do i=is,ie ; do j=js,je
6930 asum(i+idg_off) = asum(i+idg_off) + real_to_EFP(scalefac*array(i,j)*mask(i,j))
6940 mask_sum(i+idg_off) = mask_sum(i+idg_off) + real_to_EFP(mask(i,j))
695 enddo ; enddo
696
6970 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
6980 "global_j_mean overflow error occurred before sums across PEs.")
699
7000 call EFP_sum_across_PEs(asum(G%isg:G%ieg), G%ieg-G%isg+1)
7010 call EFP_sum_across_PEs(mask_sum(G%isg:G%ieg), G%ieg-G%isg+1)
702
7030 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
7040 "global_j_mean overflow error occurred during sums across PEs.")
705
7060 do i=is,ie
7070 mask_sum_r = EFP_to_real(mask_sum(i+idg_off))
7080 if (mask_sum_r == 0.0 ) then ; j_mean(i) = 0.0 ; else
7090 j_mean(i) = EFP_to_real(asum(i+idg_off)) / mask_sum_r
710 endif
711 enddo
712
7130 deallocate(mask_sum)
714 else
7150 do i=G%isg,G%ieg ; asum(i) = real_to_EFP(0.0) ; enddo
716
7170 do i=is,ie ; do j=js,je
7180 asum(i+idg_off) = asum(i+idg_off) + real_to_EFP(scalefac*array(i,j))
719 enddo ; enddo
720
7210 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
7220 "global_j_mean overflow error occurred before sum across PEs.")
723
7240 call EFP_sum_across_PEs(asum(G%isg:G%ieg), G%ieg-G%isg+1)
725
7260 if (query_EFP_overflow_error()) call MOM_error(FATAL, &
7270 "global_j_mean overflow error occurred during sum across PEs.")
728
7290 do i=is,ie
7300 j_mean(i) = EFP_to_real(asum(i+idg_off)) / real(G%jeg-G%jsg+1)
731 enddo
732 endif
733
7340 if (rescale /= 1.0) then ; do i=is,ie ; j_mean(i) = rescale*j_mean(i) ; enddo ; endif
735
7360 deallocate(asum)
737
7380end subroutine global_j_mean
739
740!> Adjust 2d array such that area mean is zero without moving the zero contour
7410subroutine adjust_area_mean_to_zero(array, G, scaling, unit_scale, unscale)
742 type(ocean_grid_type), intent(in) :: G !< Grid structure
743 real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: array !< 2D array to be adjusted in arbitrary units [a],
744 !! or arbitrary rescaled units [A ~> a] if unscale
745 !! is present
746 real, optional, intent(out) :: scaling !< The scaling factor used [nondim]
747 real, optional, intent(in) :: unit_scale !< A rescaling factor for the variable [a A-1 ~> 1]
748 !! that converts it back to unscaled (e.g., mks)
749 !! units to enable the use of the reproducing sums
750 real, optional, intent(in) :: unscale !< A rescaling factor for the variable [a A-1 ~> 1]
751 !! that converts it back to unscaled (e.g., mks)
752 !! units to enable the use of the reproducing sums.
753 !! Here unit_scale and unscale are synonymous, but unscale
754 !! is preferred and takes precedence if both are present.
755 ! Local variables
756 ! In the following comments, [A ~> a] is used to indicate the arbitrary, possibly rescaled units of the
757 ! input array while [a] indicates the unscaled (e.g., mks) units that can be used with the reproducing sums
7580 real :: posVals(G%isc:G%iec, G%jsc:G%jec) ! The positive values in a cell or 0 [A ~> a]
7590 real :: negVals(G%isc:G%iec, G%jsc:G%jec) ! The negative values in a cell or 0 [A ~> a]
7600 real :: areaXposVals(G%isc:G%iec, G%jsc:G%jec) ! The cell area integral of the positive values [L2 A ~> m2 a]
7610 real :: areaXnegVals(G%isc:G%iec, G%jsc:G%jec) ! The cell area integral of the negative values [L2 A ~> m2 a]
762 type(EFP_type), dimension(2) :: areaInt_EFP ! An EFP version integral of the values on the current PE [m2 a]
763 real :: scalefac ! A scaling factor for the variable [a A-1 ~> 1]
764 real :: areaIntPosVals, areaIntNegVals ! The global area integral of the positive and negative values [m2 a]
765 real :: posScale, negScale ! The scaling factor to apply to positive or negative values [nondim]
766 integer :: i,j
767
7680 scalefac = 1.0
7690 if (present(unscale)) then ; scalefac = unscale
7700 elseif (present(unit_scale)) then ; scalefac = unit_scale ; endif
771
772 ! areaXposVals(:,:) = 0. ! This zeros out halo points.
773 ! areaXnegVals(:,:) = 0. ! This zeros out halo points.
774
7750 do j=G%jsc,G%jec ; do i=G%isc,G%iec
7760 posVals(i,j) = max(0., array(i,j))
7770 areaXposVals(i,j) = G%areaT(i,j) * posVals(i,j)
7780 negVals(i,j) = min(0., array(i,j))
7790 areaXnegVals(i,j) = G%areaT(i,j) * negVals(i,j)
780 enddo ; enddo
781
782 ! Combining the sums like this avoids separate blocking global sums.
7830 areaInt_EFP(1) = reproducing_sum_EFP( areaXposVals, only_on_PE=.true., unscale=scalefac*G%US%L_to_m**2 )
7840 areaInt_EFP(2) = reproducing_sum_EFP( areaXnegVals, only_on_PE=.true., unscale=scalefac*G%US%L_to_m**2 )
7850 call EFP_sum_across_PEs(areaInt_EFP, 2)
7860 areaIntPosVals = EFP_to_real( areaInt_EFP(1) )
7870 areaIntNegVals = EFP_to_real( areaInt_EFP(2) )
788
7890 posScale = 0.0 ; negScale = 0.0
7900 if ((areaIntPosVals>0.).and.(areaIntNegVals<0.)) then ! Only adjust if possible
7910 if (areaIntPosVals>-areaIntNegVals) then ! Scale down positive values
7920 posScale = - areaIntNegVals / areaIntPosVals
7930 do j=G%jsc,G%jec ; do i=G%isc,G%iec
7940 array(i,j) = (posScale * posVals(i,j)) + negVals(i,j)
795 enddo ; enddo
7960 elseif (areaIntPosVals<-areaIntNegVals) then ! Scale down negative values
7970 negScale = - areaIntPosVals / areaIntNegVals
7980 do j=G%jsc,G%jec ; do i=G%isc,G%iec
7990 array(i,j) = posVals(i,j) + (negScale * negVals(i,j))
800 enddo ; enddo
801 endif
802 endif
8030 if (present(scaling)) scaling = posScale - negScale
804
8050end subroutine adjust_area_mean_to_zero
806
807
808!> Find the global maximum and minimum of a tracer array and return the locations of the extrema.
809!! When there multiple cells with the same extreme values, the reported locations are from the
810!! uppermost layer where they occur, and then from the logically northernmost and then eastermost
811!! such location on the unrotated version of the grid within that layer. Only ocean points (as
812!! indicated by a positive value of G%mask2dT) are evaluated, and if there are no ocean points
813!! anywhere in the domain, the reported extrema and their locations are all returned as 0.
8146subroutine array_global_min_max(tr_array, G, nk, g_min, g_max, &
815 xgmin, ygmin, zgmin, xgmax, ygmax, zgmax, unscale)
816 integer, intent(in) :: nk !< The number of vertical levels
817 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
818 real, dimension(SZI_(G),SZJ_(G),nk), intent(in) :: tr_array !< The tracer array to search for
819 !! extrema in arbitrary concentration units [CU ~> conc]
820 real, intent(out) :: g_min !< The global minimum of tr_array, either in
821 !! the same units as tr_array [CU ~> conc] or in
822 !! unscaled units if unscale is present [conc]
823 real, intent(out) :: g_max !< The global maximum of tr_array, either in
824 !! the same units as tr_array [CU ~> conc] or in
825 !! unscaled units if unscale is present [conc]
826 real, optional, intent(out) :: xgmin !< The x-position of the global minimum in the
827 !! units of G%geoLonT, often [degrees_E] or [km] or [m]
828 real, optional, intent(out) :: ygmin !< The y-position of the global minimum in the
829 !! units of G%geoLatT, often [degrees_N] or [km] or [m]
830 real, optional, intent(out) :: zgmin !< The z-position of the global minimum [layer]
831 real, optional, intent(out) :: xgmax !< The x-position of the global maximum in the
832 !! units of G%geoLonT, often [degrees_E] or [km] or [m]
833 real, optional, intent(out) :: ygmax !< The y-position of the global maximum in the
834 !! units of G%geoLatT, often [degrees_N] or [km] or [m]
835 real, optional, intent(out) :: zgmax !< The z-position of the global maximum [layer]
836 real, optional, intent(in) :: unscale !< A factor to use to undo any scaling of
837 !! the input tracer array [conc CU-1 ~> 1]
838
839 ! Local variables
840 real :: tmax, tmin ! Maximum and minimum tracer values, in the same units as tr_array [CU ~> conc]
841 integer :: ijk_min_max(2) ! Integers encoding the global grid positions of the global minimum and maximum values
842 real :: xyz_min_max(6) ! A single array with the x-, y- and z-positions of the minimum and
843 ! maximum values in units that vary between the array elements [various]
844 logical :: valid_PE ! True if there are any valid points on the local PE.
845 logical :: find_location ! If true, report the locations of the extrema
846 integer :: ijk_loc_max ! An integer encoding the global grid position of the maximum tracer value on this PE
847 integer :: ijk_loc_min ! An integer encoding the global grid position of the minimum tracer value on this PE
848 integer :: ijk_loc_here ! An integer encoding the global grid position of the current grid point
849 integer :: itmax, jtmax, ktmax, itmin, jtmin, ktmin
850 integer :: i, j, k, isc, iec, jsc, jec
851
8526 isc = G%isc ; iec = G%iec ; jsc = G%jsc ; jec = G%jec
853
854 find_location = (present(xgmin) .or. present(ygmin) .or. present(zgmin) .or. &
8556 present(xgmax) .or. present(ygmax) .or. present(zgmax))
856
857 ! The initial values set here are never used if there are any valid points.
8586 tmax = -huge(tmax) ; tmin = huge(tmin)
859
8606 if (find_location) then
861 ! Find the maximum and minimum tracer values on this PE and their locations.
8626 valid_PE = .false.
8636 itmax = 0 ; jtmax = 0 ; ktmax = 0 ; ijk_loc_max = 0
8646 itmin = 0 ; jtmin = 0 ; ktmin = 0 ; ijk_loc_min = 0
8653267456 do k=1,nk ; do j=jsc,jec ; do i=isc,iec ; if (G%mask2dT(i,j) > 0.0) then
8662256300 valid_PE = .true.
8672256300 if (tr_array(i,j,k) > tmax) then
8682071 tmax = tr_array(i,j,k)
8692071 itmax = i ; jtmax = j ; ktmax = k
8702071 ijk_loc_max = ijk_loc(i, j, k, nk, G%HI)
8712254229 elseif ((tr_array(i,j,k) == tmax) .and. (k <= ktmax)) then
8725587 ijk_loc_here = ijk_loc(i, j, k, nk, G%HI)
8735587 if (ijk_loc_here > ijk_loc_max) then
8745587 itmax = i ; jtmax = j ; ktmax = k
8755587 ijk_loc_max = ijk_loc_here
876 endif
877 endif
8782256300 if (tr_array(i,j,k) < tmin) then
8791596 tmin = tr_array(i,j,k)
8801596 itmin = i ; jtmin = j ; ktmin = k
8811596 ijk_loc_min = ijk_loc(i, j, k, nk, G%HI)
8822254704 elseif ((tr_array(i,j,k) == tmin) .and. (k <= ktmin)) then
8835571 ijk_loc_here = ijk_loc(i, j, k, nk, G%HI)
8845571 if (ijk_loc_here > ijk_loc_min) then
8855571 itmin = i ; jtmin = j ; ktmin = k
8865571 ijk_loc_min = ijk_loc_here
887 endif
888 endif
889 endif ; enddo ; enddo ; enddo
890 else
891 ! Only the maximum and minimum values are needed, and not their positions.
8920 do k=1,nk ; do j=jsc,jec ; do i=isc,iec ; if (G%mask2dT(i,j) > 0.0) then
8930 if (tr_array(i,j,k) > tmax) tmax = tr_array(i,j,k)
8940 if (tr_array(i,j,k) < tmin) tmin = tr_array(i,j,k)
895 endif ; enddo ; enddo ; enddo
896 endif
897
898 ! Find the global maximum and minimum tracer values.
8996 g_max = tmax ; g_min = tmin
9006 call max_across_PEs(g_max)
9016 call min_across_PEs(g_min)
902
9036 if (find_location) then
9046 if (g_max < g_min) then
905 ! This only occurs if there are no unmasked points anywhere in the domain.
9060 xyz_min_max(:) = 0.0
907 else
908 ! Find the global indices of the maximum and minimum locations. This can
909 ! occur on multiple PEs.
9106 ijk_min_max(1:2) = 0
9116 if (valid_PE) then
9126 if (g_min == tmin) ijk_min_max(1) = ijk_loc_min
9136 if (g_max == tmax) ijk_min_max(2) = ijk_loc_max
914 endif
915 ! If MOM6 supported taking maxima on arrays of integers, these could be combined as:
916 ! call max_across_PEs(ijk_min_max, 2)
9176 call max_across_PEs(ijk_min_max(1))
9186 call max_across_PEs(ijk_min_max(2))
919
920 ! Set the positions of the extrema if they occur on this PE. This will only
921 ! occur on a single PE.
92242 xyz_min_max(1:6) = -huge(xyz_min_max) ! These huge negative values are never selected by max_across_PEs.
9236 if (valid_PE) then
9246 if (ijk_min_max(1) == ijk_loc_min) then
9256 xyz_min_max(1) = G%geoLonT(itmin,jtmin)
9266 xyz_min_max(2) = G%geoLatT(itmin,jtmin)
9276 xyz_min_max(3) = real(ktmin)
928 endif
9296 if (ijk_min_max(2) == ijk_loc_max) then
9306 xyz_min_max(4) = G%geoLonT(itmax,jtmax)
9316 xyz_min_max(5) = G%geoLatT(itmax,jtmax)
9326 xyz_min_max(6) = real(ktmax)
933 endif
934 endif
935
9366 call max_across_PEs(xyz_min_max, 6)
937 endif
938
9396 if (present(xgmin)) xgmin = xyz_min_max(1)
9406 if (present(ygmin)) ygmin = xyz_min_max(2)
9416 if (present(zgmin)) zgmin = xyz_min_max(3)
9426 if (present(xgmax)) xgmax = xyz_min_max(4)
9436 if (present(ygmax)) ygmax = xyz_min_max(5)
9446 if (present(zgmax)) zgmax = xyz_min_max(6)
945 endif
946
9476 if (g_max < g_min) then
948 ! There are no unmasked points anywhere in the domain.
9490 g_max = 0.0 ; g_min = 0.0
950 endif
951
9526 if (present(unscale)) then
953 ! Rescale g_min and g_max, perhaps changing their units from [CU ~> conc] to [conc]
9546 g_max = unscale * g_max
9556 g_min = unscale * g_min
956 endif
957
9586end subroutine array_global_min_max
959
960! Return a positive integer encoding the rotationally invariant global position of a tracer cell
96114825function ijk_loc(i, j, k, nk, HI)
962 integer, intent(in) :: i !< Local i-index
963 integer, intent(in) :: j !< Local j-index
964 integer, intent(in) :: k !< Local k-index
965 integer, intent(in) :: nk !< Range of k-index, used to pick out a low-k position.
966 type(hor_index_type), intent(in) :: HI !< Horizontal index ranges
967 integer :: ijk_loc ! An integer encoding the cell position in the global grid.
968
969 ! Local variables
970 integer :: ig, jg ! Global index values with a global computational domain start value of 1.
971 integer :: ij_loc ! The encoding of the horizontal position
972 integer :: qturns ! The number of counter-clockwise quarter turns of the grid that have to be undone
973
974 ! These global i-grid positions run from 1 to HI%niglobal, and analogously for jg.
97514825 ig = i + HI%idg_offset + (1 - HI%isg)
97614825 jg = j + HI%jdg_offset + (1 - HI%jsg)
977
978 ! Compensate for the rotation of the model grid to give a rotationally invariant encoding.
97914825 qturns = modulo(HI%turns, 4)
98014825 if (qturns == 0) then
98114825 ij_loc = ig + HI%niglobal * jg
9820 elseif (qturns == 1) then
9830 ij_loc = jg + HI%njglobal * ((HI%niglobal+1)-ig)
9840 elseif (qturns == 2) then
9850 ij_loc = ((HI%niglobal+1)-ig) + HI%niglobal * ((HI%njglobal+1)-jg)
9860 elseif (qturns == 3) then
9870 ij_loc = ((HI%njglobal+1)-jg) + HI%njglobal * ig
988 endif
989
99014825 ijk_loc = ij_loc + (HI%niglobal*HI%njglobal) * (nk-k)
991
99214825end function ijk_loc
993
994
995end module MOM_spatial_means