← back to index

src/framework/MOM_coms.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#include "do_concurrent_compat.h"
6
7!> Interfaces to non-domain-oriented communication subroutines, including the
8!! MOM6 reproducing sums facility
9module MOM_coms
10
11use, intrinsic :: iso_fortran_env, only : int64
12use MOM_coms_infra, only : PE_here, root_PE, num_PEs, set_rootPE, Set_PElist, Get_PElist
13use MOM_coms_infra, only : broadcast, field_chksum, MOM_infra_init, MOM_infra_end
14use MOM_coms_infra, only : sum_across_PEs, max_across_PEs, min_across_PEs
15use MOM_coms_infra, only : all_across_PEs, any_across_PEs
16use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING
17use MOM_coms_infra, only : sync_PEs
18
19implicit none ; private
20
21public :: PE_here, root_PE, num_PEs, MOM_infra_init, MOM_infra_end
22public :: sync_PEs
23public :: broadcast, sum_across_PEs, min_across_PEs, max_across_PEs, field_chksum
24public :: all_across_PEs, any_across_PEs
25public :: set_PElist, Get_PElist, Set_rootPE
26public :: reproducing_sum, reproducing_sum_EFP, EFP_sum_across_PEs, EFP_list_sum_across_PEs
27public :: EFP_plus, EFP_minus, EFP_to_real, real_to_EFP, EFP_real_diff
28public :: operator(+), operator(-), assignment(=)
29public :: query_EFP_overflow_error, reset_EFP_overflow_error
30
31integer, parameter :: accum_width = digits(1_int64)
32 !< Accumulator width; total available bits for summation (excluding sign bit)
33integer, parameter :: prec_width = 46
34 !< Precision width; total bits for computed results
35integer, parameter :: guard_width = accum_width - prec_width
36 !< Number of guard bits reserved for carry overflow
37
38! A sum of N points does N - 1 additions, which at most adds N - 1 carry bits.
39! For G guard bits, the maximum value is 2**G - 1. A summation of N values
40! therefore requires that N - 1 <= 2**G - 1, or simply N <= 2**G.
41
42integer, parameter :: max_summands = 2**guard_width
43 !< Maximum number of summable points that can guarantee no carry overflow.
44 !! Assumes that guard_bits is less than number of bits in a default integer.
45
46integer(kind=int64), parameter :: prec = (2_int64)**prec_width
47 !< EPF upper bound (exclusive). For each EPF bin e(i), 0 <= e(i) < prec.
48
49real, parameter :: r_prec = 2.**prec_width
50 !< Real-value of prec [nondim]
51real, parameter :: I_prec = 2.**(-prec_width)
52 !< Inverse real-value of prec [nondim]
53
54integer, parameter :: efp_digits = 6
55 !< The number of base `prec` digits used to represent an EFP value.
56real, parameter, dimension(efp_digits) :: &
57 pr = [r_prec**2, r_prec, 1., r_prec**(-1), r_prec**(-2), r_prec**(-3)]
58 !< An array of the real precision of each of the integers in arbitrary
59 !! units [a]
60real, parameter, dimension(efp_digits) :: &
61 I_pr = [r_prec**(-2), r_prec**(-1), 1., r_prec, r_prec**2, r_prec**3]
62 !< An array of the inverse of the real precision of each of the integers in
63 !! arbitrary units [a-1]
64real, parameter :: max_efp_float = pr(1) * real(huge(1_int64))
65 !< The largest float with an EFP representation in arbitrary units [a].
66 !! NOTE: Only the first bin can exceed precision, but is bounded by the
67 !! largest signed integer.
68
69!$omp declare target(pr, I_pr)
70
71logical :: overflow_error = .false.
72 !< This becomes true if an overflow is encountered.
73logical :: NaN_error = .false.
74 !< This becomes true if a NaN is encountered.
75logical :: debug = .false.
76 !< Making this true enables debugging output.
77
78! This module provides interfaces to the non-domain-oriented communication subroutines.
79
80!> Find an accurate and order-invariant sum of a distributed 2d or 3d field, in some cases after
81!! undoing the scaling of the input array and restoring that scaling in the returned value
82interface reproducing_sum
83 module procedure reproducing_sum_2d, reproducing_sum_3d
84end interface reproducing_sum
85
86!> Find an accurate and order-invariant sum of a distributed 2d field, returning the result
87!! in the form of an extended fixed point value that can be converted back with EFP_to_real.
88interface reproducing_sum_EFP
89 module procedure reproducing_EFP_sum_2d
90end interface reproducing_sum_EFP
91
92!> Sum a value or 1-d array of values across processors, returning the sums in place
93interface EFP_sum_across_PEs
94 module procedure EFP_list_sum_across_PEs, EFP_val_sum_across_PEs
95end interface EFP_sum_across_PEs
96
97!> The Extended Fixed Point (EFP) type provides a public interface for doing sums
98!! and taking differences with this type.
99!!
100!! The use of this type is documented in
101!! Hallberg, R. & A. Adcroft, 2014: An Order-invariant Real-to-Integer Conversion Sum.
102!! Parallel Computing, 40(5-6), doi:10.1016/j.parco.2014.04.007.
103type, public :: EFP_type ; private
104 integer(kind=int64), dimension(efp_digits) :: v !< The value in this type
105end type EFP_type
106
107!> Add two extended-fixed-point numbers
108interface operator (+) ; module procedure EFP_plus ; end interface
109!> Subtract one extended-fixed-point number from another
110interface operator (-) ; module procedure EFP_minus ; end interface
111!> Copy the value of one extended-fixed-point number into another
112interface assignment(=); module procedure EFP_assign ; end interface
113
114contains
115
116!> This subroutine uses a conversion to an integer representation of real numbers to give an
117!! order-invariant sum of distributed 2-D arrays that reproduces across domain decomposition, with
118!! the result returned as an extended fixed point type that can be converted back to a real number
119!! using EFP_to_real. This technique is described in Hallberg & Adcroft, 2014, Parallel Computing,
120!! doi:10.1016/j.parco.2014.04.007.
12110function reproducing_EFP_sum_2d(array, isr, ier, jsr, jer, overflow_check, err, only_on_PE, unscale) result(EFP_sum)
122 real, dimension(:,:), intent(in) :: array !< The array to be summed in arbitrary units [a], or in
123 !! arbitrary scaled units [A ~> a] if unscale is present
124 integer, optional, intent(in) :: isr !< The starting i-index of the sum, noting
125 !! that the array indices starts at 1
126 integer, optional, intent(in) :: ier !< The ending i-index of the sum, noting
127 !! that the array indices starts at 1
128 integer, optional, intent(in) :: jsr !< The starting j-index of the sum, noting
129 !! that the array indices starts at 1
130 integer, optional, intent(in) :: jer !< The ending j-index of the sum, noting
131 !! that the array indices starts at 1
132 logical, optional, intent(in) :: overflow_check !< If present and false, disable
133 !! checking for overflows in incremental results.
134 !! This can speed up calculations if the number
135 !! of values being summed is small enough
136 integer, optional, intent(out) :: err !< If present, return an error code instead of
137 !! triggering any fatal errors directly from
138 !! this routine.
139 logical, optional, intent(in) :: only_on_PE !< If present and true, do not do the sum
140 !! across processors, only reporting the local sum
141 real, optional, intent(in) :: unscale !< A factor that is used to undo scaling of array before it is
142 !! summed, often to compensate for the scaling in [a A-1 ~> 1]
143 type(EFP_type) :: EFP_sum !< The result in extended fixed point format
144
145 ! This subroutine uses a conversion to an integer representation
146 ! of real numbers to give order-invariant sums that will reproduce
147 ! across PE count. This idea comes from R. Hallberg and A. Adcroft.
148
149 integer(kind=int64), dimension(efp_digits) :: ints_sum
150 integer(kind=int64) :: ival, prec_error
151 real :: rs ! The remaining value to add, in arbitrary units [a]
152 real :: max_mag_term ! A running maximum magnitude of the values in arbitrary units [a]
153 real :: descale ! A local copy of unscale if it is present [a A-1 ~> 1] or 1
154 logical :: over_check, do_sum_across_PEs, do_unscale
155 character(len=256) :: mesg
156 integer :: i, j, n, is, ie, js, je, sgn
157
15810 if (num_PEs() > max_summands) call MOM_error(FATAL, &
159 "reproducing_sum: Too many processors are being used for the value of "//&
1600 "prec. Reduce prec to (2^63-1)/num_PEs.")
161
16210 prec_error = huge(1_int64) / num_PEs()
163
16410 is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2)
16510 if (present(isr)) then
1669 if (isr < is) call MOM_error(FATAL, "Value of isr too small in reproducing_EFP_sum_2d.")
1679 is = isr
168 endif
16910 if (present(ier)) then
1709 if (ier > ie) call MOM_error(FATAL, "Value of ier too large in reproducing_EFP_sum_2d.")
1719 ie = ier
172 endif
17310 if (present(jsr)) then
1749 if (jsr < js) call MOM_error(FATAL, "Value of jsr too small in reproducing_EFP_sum_2d.")
1759 js = jsr
176 endif
17710 if (present(jer)) then
1789 if (jer > je) call MOM_error(FATAL, "Value of jer too large in reproducing_EFP_sum_2d.")
1799 je = jer
180 endif
181
18210 over_check = .true. ; if (present(overflow_check)) over_check = overflow_check
18310 do_sum_across_PEs = .true. ; if (present(only_on_PE)) do_sum_across_PEs = .not.only_on_PE
18410 do_unscale = .false. ; if (present(unscale)) do_unscale = (unscale /= 1.0)
18510 descale = 1.0 ; if (do_unscale) descale = unscale
186
18710 overflow_error = .false. ; NaN_error = .false. ; max_mag_term = 0.0
188
18910 ints_sum(:) = 0
19010 if (over_check) then
191 call increment_block_ints(array, is, ie, js, je, descale, ints_sum, &
19210 max_mag_term, prec_error)
193 else
1940 do j=js,je ; do i=is,ie
1950 sgn = 1 ; if (array(i,j)<0.0) sgn = -1
1960 rs = abs(descale*array(i,j))
1970 do n=1,efp_digits
1980 ival = int(rs*I_pr(n), kind=int64)
1990 rs = rs - ival*pr(n)
2000 ints_sum(n) = ints_sum(n) + sgn*ival
201 enddo
202 enddo ; enddo
2030 call carry_overflow(ints_sum, prec_error)
204 endif
205
20610 if (present(err)) then
2070 err = 0
2080 if (overflow_error) &
2090 err = err+2
2100 if (NaN_error) &
2110 err = err+4
2120 if (err > 0) then ; do n=1,efp_digits ; ints_sum(n) = 0 ; enddo ; endif
213 else
21410 if (NaN_error) then
2150 call MOM_error(FATAL, "NaN in input field of reproducing_EFP_sum(_2d).")
216 endif
21710 if (abs(max_mag_term) >= prec_error*pr(1)) then
2180 write(mesg, '(ES13.5)') max_mag_term
2190 call MOM_error(FATAL,"Overflow in reproducing_EFP_sum(_2d) conversion of "//trim(mesg))
220 endif
22110 if (overflow_error) then
2220 call MOM_error(FATAL, "Overflow in reproducing_EFP_sum(_2d).")
223 endif
224 endif
225
22610 if (do_sum_across_PEs) call sum_across_PEs(ints_sum, efp_digits)
227
22810 call regularize_ints(ints_sum)
229
23070 EFP_sum%v(:) = ints_sum(:)
231
23210end function reproducing_EFP_sum_2d
233
234
235!> This subroutine uses a conversion to an integer representation of real numbers to give an
236!! order-invariant sum of distributed 2-D arrays that reproduces across domain decomposition.
237!! This technique is described in Hallberg & Adcroft, 2014, Parallel Computing,
238!! doi:10.1016/j.parco.2014.04.007.
2391function reproducing_sum_2d(array, isr, ier, jsr, jer, EFP_sum, reproducing, &
240 overflow_check, err, only_on_PE, unscale) result(sum)
241 real, dimension(:,:), intent(in) :: array !< The array to be summed in arbitrary units [a], or in
242 !! arbitrary scaled units [A ~> a] if unscale is present
243 integer, optional, intent(in) :: isr !< The starting i-index of the sum, noting
244 !! that the array indices starts at 1
245 integer, optional, intent(in) :: ier !< The ending i-index of the sum, noting
246 !! that the array indices starts at 1
247 integer, optional, intent(in) :: jsr !< The starting j-index of the sum, noting
248 !! that the array indices starts at 1
249 integer, optional, intent(in) :: jer !< The ending j-index of the sum, noting
250 !! that the array indices starts at 1
251 type(EFP_type), optional, intent(out) :: EFP_sum !< The result in extended fixed point format
252 logical, optional, intent(in) :: reproducing !< If present and false, do the sum
253 !! using the naive non-reproducing approach
254 logical, optional, intent(in) :: overflow_check !< If present and false, disable
255 !! checking for overflows in incremental results.
256 !! This can speed up calculations if the number
257 !! of values being summed is small enough
258 integer, optional, intent(out) :: err !< If present, return an error code instead of
259 !! triggering any fatal errors directly from
260 !! this routine.
261 logical, optional, intent(in) :: only_on_PE !< If present and true, do not do the sum
262 !! across processors, only reporting the local sum
263 real, optional, intent(in) :: unscale !< A factor that is used to undo scaling of array before it is
264 !! summed, often to compensate for the scaling in [a A-1 ~> 1]
265 real :: sum !< The sum of the values in array in the same
266 !! arbitrary units as array [a] or [A ~> a]
267
268 ! Local variables
269 integer(kind=int64), dimension(efp_digits) :: ints_sum
270 integer(kind=int64) :: prec_error
271 real :: rsum(1) ! The running sum, in arbitrary units [a]
272 real :: descale ! A local copy of unscale if it is present [a A-1 ~> 1] or 1
273 real :: I_unscale ! The reciprocal of unscale [A a-1 ~> 1]
274 logical :: repro, do_sum_across_PEs, do_unscale
275 character(len=256) :: mesg
276 type(EFP_type) :: EFP_val ! An extended fixed point version of the sum
277 integer :: i, j, is, ie, js, je
278
2791 if (num_PEs() > max_summands) call MOM_error(FATAL, &
280 "reproducing_sum: Too many processors are being used for the value of "//&
2810 "prec. Reduce prec to (2^63-1)/num_PEs.")
282
2831 prec_error = huge(1_int64) / num_PEs()
284
2851 is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2)
2861 if (present(isr)) then
2870 if (isr < is) call MOM_error(FATAL, "Value of isr too small in reproducing_sum_2d.")
2880 is = isr
289 endif
2901 if (present(ier)) then
2910 if (ier > ie) call MOM_error(FATAL, "Value of ier too large in reproducing_sum_2d.")
2920 ie = ier
293 endif
2941 if (present(jsr)) then
2950 if (jsr < js) call MOM_error(FATAL, "Value of jsr too small in reproducing_sum_2d.")
2960 js = jsr
297 endif
2981 if (present(jer)) then
2990 if (jer > je) call MOM_error(FATAL, "Value of jer too large in reproducing_sum_2d.")
3000 je = jer
301 endif
302
3031 repro = .true. ; if (present(reproducing)) repro = reproducing
3041 do_sum_across_PEs = .true. ; if (present(only_on_PE)) do_sum_across_PEs = .not.only_on_PE
3051 do_unscale = .false. ; if (present(unscale)) do_unscale = (unscale /= 1.0)
3061 descale = 1.0 ; I_unscale = 1.0
3071 if (do_unscale) then
3080 descale = unscale
3090 if (abs(unscale) > 0.0) I_unscale = 1.0 / unscale
310 endif
311
3121 if (repro) then
3131 EFP_val = reproducing_EFP_sum_2d(array, isr, ier, jsr, jer, overflow_check, err, only_on_PE, unscale)
3141 sum = ints_to_real(EFP_val%v) * I_unscale
3151 if (present(EFP_sum)) EFP_sum = EFP_val
3161 if (debug) ints_sum(:) = EFP_sum%v(:)
317 else
3180 rsum(1) = 0.0
3190 do j=js,je ; do i=is,ie
3200 rsum(1) = rsum(1) + descale*array(i,j)
321 enddo ; enddo
3220 if (do_sum_across_PEs) call sum_across_PEs(rsum,1)
3230 sum = rsum(1) * I_unscale
324
3250 if (present(err)) then ; err = 0 ; endif
326
3270 if (debug .or. present(EFP_sum)) then
3280 overflow_error = .false.
3290 ints_sum = real_to_ints(sum, prec_error, overflow_error)
3300 if (overflow_error) then
3310 if (present(err)) then
3320 err = err + 2
333 else
3340 write(mesg, '(ES13.5)') sum
3350 call MOM_error(FATAL,"Repro_sum_2d: Overflow in real_to_ints conversion of "//trim(mesg))
336 endif
337 endif
338 endif
3390 if (present(EFP_sum)) EFP_sum%v(:) = ints_sum(:)
340 endif
341
3421 if (debug) then
3430 write(mesg,'("2d RS: ", ES24.16, 6 Z17.16)') sum*descale, ints_sum(1:efp_digits)
3440 call MOM_mesg(mesg, 3)
345 endif
346
3471end function reproducing_sum_2d
348
349!> This subroutine uses a conversion to an integer representation of real numbers to give an
350!! order-invariant sum of distributed 3-D arrays that reproduces across domain decomposition.
351!! This technique is described in Hallberg & Adcroft, 2014, Parallel Computing,
352!! doi:10.1016/j.parco.2014.04.007.
3536function reproducing_sum_3d(array, isr, ier, jsr, jer, sums, EFP_sum, EFP_lay_sums, err, only_on_PE, unscale) &
354 result(sum)
355 real, dimension(:,:,:), intent(in) :: array !< The array to be summed in arbitrary units [a], or in
356 !! arbitrary scaled units [A ~> a] if unscale is present
357 integer, optional, intent(in) :: isr !< The starting i-index of the sum, noting
358 !! that the array indices starts at 1
359 integer, optional, intent(in) :: ier !< The ending i-index of the sum, noting
360 !! that the array indices starts at 1
361 integer, optional, intent(in) :: jsr !< The starting j-index of the sum, noting
362 !! that the array indices starts at 1
363 integer, optional, intent(in) :: jer !< The ending j-index of the sum, noting
364 !! that the array indices starts at 1
365 real, dimension(:), optional, intent(out) :: sums !< The sums by vertical layer in the same
366 !! arbitrary units as array [a] or [A ~> a]
367 type(EFP_type), optional, intent(out) :: EFP_sum !< The result in extended fixed point format
368 type(EFP_type), dimension(:), &
369 optional, intent(out) :: EFP_lay_sums !< The sums by vertical layer in EFP format
370 integer, optional, intent(out) :: err !< If present, return an error code instead of
371 !! triggering any fatal errors directly from
372 !! this routine.
373 logical, optional, intent(in) :: only_on_PE !< If present and true, do not do the sum
374 !! across processors, only reporting the local sum
375 real, optional, intent(in) :: unscale !< A factor that is used to undo scaling of array before it is
376 !! summed, often to compensate for the scaling in [a A-1 ~> 1]
377 real :: sum !< The sum of the values in array in the same
378 !! arbitrary units as array [a] or [A ~> a]
379
380 ! Local variables
381 real :: val ! The real number that is extracted in arbitrary units [a]
382 real :: max_mag_term ! A running maximum magnitude of the val's in arbitrary units [a]
383 real :: descale ! A local copy of unscale if it is present [a A-1 ~> 1] or 1
384 real :: I_unscale ! The Adcroft reciprocal of unscale [A a-1 ~> 1]
385 integer(kind=int64), dimension(efp_digits) :: ints_sum
38612 integer(kind=int64), dimension(efp_digits,size(array,3)) :: ints_sums
387 integer(kind=int64) :: prec_error
388 character(len=256) :: mesg
389 logical :: do_sum_across_PEs, do_unscale
390 integer :: i, j, k, is, ie, js, je, ke, isz, jsz, n
391
3926 if (num_PEs() > max_summands) call MOM_error(FATAL, &
393 "reproducing_sum: Too many processors are being used for the value of "//&
3940 "prec. Reduce prec to (2^63-1)/num_PEs.")
395
3966 prec_error = huge(1_int64) / num_PEs()
3976 max_mag_term = 0.0
398
3996 is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2) ; ke = size(array,3)
4006 if (present(isr)) then
4016 if (isr < is) call MOM_error(FATAL, "Value of isr too small in reproducing_sum(_3d).")
4026 is = isr
403 endif
4046 if (present(ier)) then
4056 if (ier > ie) call MOM_error(FATAL, "Value of ier too large in reproducing_sum(_3d).")
4066 ie = ier
407 endif
4086 if (present(jsr)) then
4096 if (jsr < js) call MOM_error(FATAL, "Value of jsr too small in reproducing_sum(_3d).")
4106 js = jsr
411 endif
4126 if (present(jer)) then
4136 if (jer > je) call MOM_error(FATAL, "Value of jer too large in reproducing_sum(_3d).")
4146 je = jer
415 endif
4166 jsz = je+1-js ; isz = ie+1-is
417
4186 do_sum_across_PEs = .true. ; if (present(only_on_PE)) do_sum_across_PEs = .not.only_on_PE
4196 do_unscale = .false. ; if (present(unscale)) do_unscale = (unscale /= 1.0)
4206 descale = 1.0 ; if (do_unscale) descale = unscale
421
4226 if (present(sums) .or. present(EFP_lay_sums)) then
4236 if (present(sums)) then ; if (size(sums) < ke) then
4240 call MOM_error(FATAL, "Sums is smaller than the vertical extent of array in reproducing_sum(_3d).")
425 endif ; endif
4266 if (present(EFP_lay_sums)) then ; if (size(EFP_lay_sums) < ke) then
4270 call MOM_error(FATAL, "Sums is smaller than the vertical extent of array in reproducing_sum(_3d).")
428 endif ; endif
429
4306 overflow_error = .false. ; NaN_error = .false. ; max_mag_term = 0.0
431
432944 ints_sums(:,:) = 0
433140 do k=1,ke
434 call increment_block_ints(array(:,:,k), is, ie, js, je, descale, &
435140 ints_sums(:,k), max_mag_term, prec_error)
436 enddo
437
4386 if (present(err)) then
4390 err = 0
4400 if (abs(max_mag_term) >= prec_error*pr(1)) err = err+1
4410 if (overflow_error) err = err+2
4420 if (NaN_error) err = err+2
4430 if (err > 0) then ; do k=1,ke ; do n=1,efp_digits ; ints_sums(n,k) = 0 ; enddo ; enddo ; endif
444 else
4456 if (NaN_error) call MOM_error(FATAL, "NaN in input field of reproducing_sum(_3d).")
4466 if (abs(max_mag_term) >= prec_error*pr(1)) then
4470 write(mesg, '(ES13.5)') max_mag_term
4480 call MOM_error(FATAL,"Overflow in reproducing_sum(_3d) conversion of "//trim(mesg))
449 endif
4506 if (overflow_error) call MOM_error(FATAL, "Overflow in reproducing_sum(_3d).")
451 endif
452
4536 if (do_sum_across_PEs) call sum_across_PEs(ints_sums(:,1:ke), efp_digits*ke)
454
4556 sum = 0.0
456140 do k=1,ke
457134 call regularize_ints(ints_sums(:,k))
458134 val = ints_to_real(ints_sums(:,k))
459134 if (present(sums)) sums(k) = val
460140 sum = sum + val
461 enddo
4626 if (present(EFP_lay_sums)) then ; do k=1,ke
4630 EFP_lay_sums(k)%v(:) = ints_sums(:,k)
464 enddo ; endif
465
4666 if (present(EFP_sum)) then
46714 EFP_sum%v(:) = 0
46846 do k=1,ke ; call increment_ints(EFP_sum%v(:), ints_sums(:,k)) ; enddo
469 endif
470
4716 if (debug) then
4720 do n=1,efp_digits ; ints_sum(n) = 0 ; enddo
4730 do k=1,ke ; do n=1,efp_digits ; ints_sum(n) = ints_sum(n) + ints_sums(n,k) ; enddo ; enddo
4740 write(mesg,'("3D RS: ", ES24.16, 6 Z17.16)') sum, ints_sum(1:efp_digits)
4750 call MOM_mesg(mesg, 3)
476 endif
477 else
4780 overflow_error = .false. ; NaN_error = .false. ; max_mag_term = 0.0
479
4800 ints_sum(:) = 0
4810 do k=1,ke
482 call increment_block_ints(array(:,:,k), is, ie, js, je, descale, &
4830 ints_sum, max_mag_term, prec_error)
484 enddo
485
4860 if (present(err)) then
4870 err = 0
4880 if (abs(max_mag_term) >= prec_error*pr(1)) err = err+1
4890 if (overflow_error) err = err+2
4900 if (NaN_error) err = err+2
4910 if (err > 0) then ; do n=1,efp_digits ; ints_sum(n) = 0 ; enddo ; endif
492 else
4930 if (NaN_error) call MOM_error(FATAL, "NaN in input field of reproducing_sum(_3d).")
4940 if (abs(max_mag_term) >= prec_error*pr(1)) then
4950 write(mesg, '(ES13.5)') max_mag_term
4960 call MOM_error(FATAL,"Overflow in reproducing_sum(_3d) conversion of "//trim(mesg))
497 endif
4980 if (overflow_error) call MOM_error(FATAL, "Overflow in reproducing_sum(_3d).")
499 endif
500
5010 if (do_sum_across_PEs) call sum_across_PEs(ints_sum, efp_digits)
502
5030 call regularize_ints(ints_sum)
5040 sum = ints_to_real(ints_sum)
505
5060 if (present(EFP_sum)) EFP_sum%v(:) = ints_sum(:)
507
5080 if (debug) then
5090 write(mesg,'("3d RS: ", ES24.16, 6 Z17.16)') sum, ints_sum(1:efp_digits)
5100 call MOM_mesg(mesg, 3)
511 endif
512 endif
513
5146 if (do_unscale) then
515 ! Revise the sum to restore the scaling of input array before it is returned
5160 I_unscale = 0.0 ; if (abs(unscale) > 0.0) I_unscale = 1.0 / unscale
5170 sum = sum * I_unscale
5180 if (present(sums)) then
5190 do k=1,ke ; sums(k) = sums(k) * I_unscale ; enddo
520 endif
521 endif
522
5236end function reproducing_sum_3d
524
525!> Convert a real number into the array of integers constitute its extended-fixed-point representation
5269function real_to_ints(r, prec_error, overflow) result(ints)
527 real, intent(in) :: r !< The real number being converted in arbitrary units [a]
528 integer(kind=int64), optional, intent(in) :: prec_error !< The PE-count dependent precision of the
529 !! integers that is safe from overflows during global
530 !! sums. This will be larger than the compile-time
531 !! precision parameter, and is used to detect overflows.
532 logical, optional, intent(inout) :: overflow !< Returns true if the conversion is being
533 !! done on a value that is too large to be represented
534 integer(kind=int64), dimension(efp_digits) :: ints
535
536 ! This subroutine converts a real number to an equivalent representation
537 ! using several long integers.
538
539 ! Local variables
540 real :: rs ! The remaining value to add, in arbitrary units [a]
541 character(len=80) :: mesg
542 integer(kind=int64) :: ival, prec_err
543 integer :: sgn, i
544
5459 prec_err = prec ; if (present(prec_error)) prec_err = prec_error
54663 ints(:) = 0
5479 if ((r >= 1e30) .eqv. (r < 1e30)) then ; NaN_error = .true. ; return ; endif
548
5499 sgn = 1 ; if (r<0.0) sgn = -1
5509 rs = abs(r)
551
5529 if (present(overflow)) then
5539 if (.not.(rs < prec_err*pr(1))) overflow = .true.
5549 if ((r >= 1e30) .eqv. (r < 1e30)) overflow = .true.
5550 elseif (.not.(rs < prec_err*pr(1))) then
5560 write(mesg, '(ES13.5)') r
5570 call MOM_error(FATAL,"Overflow in real_to_ints conversion of "//trim(mesg))
558 endif
559
56063 do i=1,efp_digits
56154 ival = int(rs*I_pr(i), kind=int64)
56254 rs = rs - ival*pr(i)
56363 ints(i) = sgn*ival
564 enddo
565
566end function real_to_ints
567
568!> Convert the array of integers that constitute an extended-fixed-point
569!! representation into a real number
570153function ints_to_real(ints) result(r)
571 integer(kind=int64), dimension(efp_digits), intent(in) :: ints !< The array of EFP integers
572 real :: r ! The real number that is extracted in arbitrary units [a]
573 ! This subroutine reverses the conversion in real_to_ints.
574
575 integer :: i
576
577153 r = 0.0
5781071 do i=1,efp_digits ; r = r + pr(i)*ints(i) ; enddo
579153end function ints_to_real
580
581!> Increment an array of integers that constitutes an extended-fixed-point
582!! representation with a another EFP number
58359subroutine increment_ints(int_sum, int2, prec_error)
584 integer(kind=int64), dimension(efp_digits), intent(inout) :: int_sum !< The array of EFP integers being incremented
585 integer(kind=int64), dimension(efp_digits), intent(in) :: int2 !< The array of EFP integers being added
586 integer(kind=int64), optional, intent(in) :: prec_error !< The PE-count dependent precision of the
587 !! integers that is safe from overflows during global
588 !! sums. This will be larger than the compile-time
589 !! precision parameter, and is used to detect overflows.
590
591 ! This subroutine increments a number with another, both using the integer
592 ! representation in real_to_ints.
593 integer :: i
594
595354 do i=efp_digits,2,-1
596295 int_sum(i) = int_sum(i) + int2(i)
597 ! Carry the local overflow.
598354 if (int_sum(i) > prec) then
59940 int_sum(i) = int_sum(i) - prec
60040 int_sum(i-1) = int_sum(i-1) + 1
601255 elseif (int_sum(i) < -prec) then
6020 int_sum(i) = int_sum(i) + prec
6030 int_sum(i-1) = int_sum(i-1) - 1
604 endif
605 enddo
60659 int_sum(1) = int_sum(1) + int2(1)
60759 if (present(prec_error)) then
6080 if (abs(int_sum(1)) > prec_error) overflow_error = .true.
609 else
61059 if (abs(int_sum(1)) > prec) overflow_error = .true.
611 endif
612
61359end subroutine increment_ints
614
615
616!> Sum the elements of an array in EFP form and append the result to an
617!! existing EFP array.
618144subroutine increment_block_ints(array, is, ie, js, je, descale, ints_sum, &
619 max_mag_term, prec_error)
620 real, intent(in) :: array(:,:)
621 !< The field being added, in arbitrary units [A ~> a]
622 integer, intent(in) :: is
623 !< Start i-index of the summed domain
624 integer, intent(in) :: ie
625 !< End i-index of the summed domain
626 integer, intent(in) :: js
627 !< Start j-index of the summed domain
628 integer, intent(in) :: je
629 !< End j-index of the summed domain
630 real, intent(in) :: descale
631 !< Factor to descale array to physical value [a A-1 ~> 1]
632 integer(kind=int64), intent(inout) :: ints_sum(efp_digits)
633 !< The array of EFP integers being incremented
634 real, intent(inout) :: max_mag_term
635 !< A running maximum magnitude of the r's, in arbitrary units [a]
636 integer(kind=int64), intent(in) :: prec_error
637 !< The maximum resolvable value for a given number of PEs
638
639 integer :: i, j, ib, jb, ibs, ibe, jbs, jbe
640 ! Loop indices
641 integer :: b
642 ! Block counter
643 integer :: ni, nj
644 ! Array summation domain size along each axis
645 integer :: isize_max
646 ! Largest block size in i. Typically equal to ni
647 integer :: jsize
648 ! Number of j-rows per block.
649 integer :: nblocks, niblocks, njblocks
650 ! Number of total blocks, and number of blocks in i and j
651 integer(kind=int64) :: e(efp_digits)
652 ! The EPF representation of each array element
653 integer(kind=int64) :: block_sum(efp_digits), array_sum(efp_digits)
654 ! The cumulant per-block and total array EFP sums
655 real :: r, rmag
656 ! Local array element value and its magnitude [a]
657 real :: max_pos, max_neg, block_max_pos, block_max_neg
658 ! Largest positive and negative values (whole array and per-block) used to
659 ! find the largest maximum magnitude of array in a thread-safe manner [a]
660 integer :: inan, iovf, lnan, lovf
661 ! Thread-safe tracking of NaN and overflow state
662 integer :: max_sum_count
663 ! The total number of local sum operations that ensures no carry overflow
664
665144 max_pos = max(0., max_mag_term)
666144 max_neg = max(0., -max_mag_term)
667144 inan = 0 ; iovf = 0
668
669 ! Reduce the maximum number of summations to account for the cumulant
670 ! summations of array_sum and ints_sum.
671144 max_sum_count = max_summands - 2
672
673 ! Get the compute domain size
674144 ni = ie - is + 1
675144 nj = je - js + 1
676
677 ! Partition in i so that the widest i-slice fits within max_sum_count.
678144 niblocks = (ni + max_sum_count - 1) / max_sum_count
679 ! = ⌈ni / max_sum_count⌉
680
681 ! NOTE: niblocks is typically one, since default max_sum_count is ~130k.
682
683 ! For a balanced i-partition, the number of i-points per block is either
684 ! ⌊ni / niblocks⌋ or ⌈ni / niblocks⌉. Use the upper bound to find jsize.
685
686144 isize_max = (ni + niblocks - 1) / niblocks
687 ! = ⌈ni / niblocks⌉
688
689 ! Set jsize so that the widest i-slice times the number of j-rows does not
690 ! exceed max_sum_count.
691144 jsize = max_sum_count / isize_max
692 ! = ⌊max_sum_count / isize_max⌋
693
694 ! Choose enough j-blocks so that no j-block has more than jsize rows.
695144 njblocks = (nj + jsize - 1) / jsize
696 ! = ⌈nj / jsize⌉
697
698144 nblocks = niblocks * njblocks
699
700 ! Abort if the number of blocks also exceeds the carry-bit summation limit.
701 ! For default settings, this would be over 17 billion points per PE.
702144 if (nblocks > max_sum_count) call MOM_error(FATAL, &
703 "reproducing sum: Number of blocks exceeds summmation carry limit." &
7040 )
705
706144 array_sum(:) = 0
707
708432 do jb=1,njblocks ; do ib=1,niblocks
709 ! Use evenly distributed blocks, either ⌊n / nblocks⌋ or ⌈n / nblocks⌉.
710144 jbs = js + ((jb - 1) * nj) / njblocks
711144 jbe = js + (jb * nj) / njblocks - 1
712
713144 ibs = is + ((ib - 1) * ni) / niblocks
714144 ibe = is + (ib * ni) / niblocks - 1
715
716144 block_sum(:) = 0
717144 block_max_pos = 0.
718144 block_max_neg = 0.
719
720 ! Compute the sum of each block
721 do concurrent (j=jbs:jbe, i=ibs:ibe) &
722 DO_LOCALITY(local(r, e, rmag, lnan, lovf)) &
723 DO_LOCALITY(reduce(+: block_sum)) &
724144 DO_LOCALITY(reduce(max: block_max_pos, block_max_neg, inan, iovf))
725
726 ! Convert array(i,j) to EFP form
7279331200 r = descale * array(i,j)
7289331200 call efp_decompose(r, e, rmag, lnan, lovf)
729
730 ! Verify that the conversion was completed
7319331200 inan = max(inan, lnan)
7329331200 iovf = max(iovf, lovf)
733
7349331200 if (r >= 0.) then
7359326530 if (rmag > block_max_pos) block_max_pos = rmag
736 else
7374670 if (rmag > block_max_neg) block_max_neg = rmag
738 endif
739
740 ! Add the EFP result (including potential carry bits)
74165370384 block_sum(:) = block_sum(:) + e(:)
742 enddo ; enddo
743
7441008 array_sum(:) = array_sum(:) + block_sum(:)
745
746 ! Redistribute carry bits across bins
747 ! For the final pass (or single pass) this is handled by ints_sum.
748144 b = (jb - 1) * niblocks + ib
749144 if (b < nblocks) call carry_overflow(array_sum, prec_error)
750
751 ! Update maximum magnitudes
752144 max_pos = max(max_pos, block_max_pos)
753288 max_neg = max(max_neg, block_max_neg)
754 enddo
755
756 ! Finally, apply the cumulant result
7571008 ints_sum(:) = ints_sum(:) + array_sum(:)
758
759 ! Redistribute carry bits to normalize the final result.
760144 call carry_overflow(ints_sum, prec_error)
761
762 ! Extract the maximum value while preserving sign (NOTE: ties to positive)
763144 if (max_pos >= max_neg) then
764144 max_mag_term = max_pos
765 else
7660 max_mag_term = -max_neg
767 endif
768
769 ! Transfer error/warning signals to module flags
770144 if (inan /= 0) NaN_error = .true.
771144 if (iovf /= 0) overflow_error = .true.
772144end subroutine increment_block_ints
773
774
775!> Decompose one real into its 6 signed EFP bin contributions. NaNs and
776!! overflows are reported by flags, rather than the module-level error
777!! logicals, so that the routine is free of side effects.
7789331200pure subroutine efp_decompose(r, e, rmag, is_nan, is_ovf)
779 !$omp declare target
780 real, intent(in) :: r
781 !< The real number being decomposed [a]
782 integer(kind=int64), intent(out) :: e(efp_digits)
783 !< Signed contribution to EFP bins
784 real, intent(out) :: rmag
785 !< Equals abs(r), or 0 if r is NaN/Inf [a]
786 integer, intent(out) :: is_nan
787 !< Equals 1 if r is a NaN or Inf, else 0
788 integer, intent(out) :: is_ovf
789 !< Equals 1 if abs(r) has no EFP representation, else 0
790
791 real :: rs
792 ! The remaining value to add, in arbitrary units [a]
793 integer(kind=int64) :: ival
794 integer :: sgn
795 integer :: n
796
7979331200 e(:) = 0
7989331200 rmag = 0.0 ; is_nan = 0 ; is_ovf = 0
799
8009331200 if ((r >= 1e30) .eqv. (r < 1e30)) then
8010 is_nan = 1
8020 return
803 endif
804
8059331200 sgn = 1
8069331200 if (r < 0.0) sgn = -1
807
8089331200 rs = abs(r) ; rmag = rs
809
810 ! Abort if the number has no EFP representation
8119331200 if (rs > max_efp_float) then
8120 is_ovf = 1
8130 return
814 endif
815
81665318400 do n=1,efp_digits
81755987200 ival = int(rs * I_pr(n), kind=int64)
81855987200 rs = rs - ival * pr(n)
81955987200 e(n) = sgn * ival
820 enddo
821end subroutine efp_decompose
822
823
824!> This subroutine handles carrying of the overflow.
825156subroutine carry_overflow(int_sum, prec_error)
826 integer(kind=int64), dimension(efp_digits), intent(inout) :: int_sum !< The array of EFP integers being
827 !! modified by carries, but without changing value.
828 integer(kind=int64), intent(in) :: prec_error !< The PE-count dependent precision of the
829 !! integers that is safe from overflows during global
830 !! sums. This will be larger than the compile-time
831 !! precision parameter, and is used to detect overflows.
832
833 ! This subroutine handles carrying of the overflow.
834 integer :: i, num_carry
835
836936 do i=efp_digits,2,-1 ; if (abs(int_sum(i)) >= prec) then
837320 num_carry = int(int_sum(i) * I_prec)
838320 int_sum(i) = int_sum(i) - num_carry*prec
839320 int_sum(i-1) = int_sum(i-1) + num_carry
840 endif ; enddo
841156 if (abs(int_sum(1)) > prec_error) then
8420 overflow_error = .true.
843 endif
844
845156end subroutine carry_overflow
846
847!> This subroutine carries the overflow, and then makes sure that
848!! all integers are of the same sign as the overall value.
849162subroutine regularize_ints(int_sum)
850 integer(kind=int64), dimension(efp_digits), &
851 intent(inout) :: int_sum !< The array of integers being modified to take a
852 !! regular form with all integers of the same sign,
853 !! but without changing value.
854
855 ! This subroutine carries the overflow, and then makes sure that
856 ! all integers are of the same sign as the overall value.
857 logical :: positive
858 integer :: i, num_carry
859
860972 do i=efp_digits,2,-1 ; if (abs(int_sum(i)) >= prec) then
8612 num_carry = int(int_sum(i) * I_prec)
8622 int_sum(i) = int_sum(i) - num_carry*prec
8632 int_sum(i-1) = int_sum(i-1) + num_carry
864 endif ; enddo
865
866 ! Determine the sign of the final number.
867162 positive = .true.
868526 do i=1,efp_digits
869526 if (abs(int_sum(i)) > 0) then
870128 if (int_sum(i) < 0) positive = .false.
871128 exit
872 endif
873 enddo
874
875162 if (positive) then
876960 do i=efp_digits,2,-1 ; if (int_sum(i) < 0) then
8774 int_sum(i) = int_sum(i) + prec
8784 int_sum(i-1) = int_sum(i-1) - 1
879 endif ; enddo
880 else
88112 do i=efp_digits,2,-1 ; if (int_sum(i) > 0) then
8821 int_sum(i) = int_sum(i) - prec
8831 int_sum(i-1) = int_sum(i-1) + 1
884 endif ; enddo
885 endif
886
887162end subroutine regularize_ints
888
889!> Returns the status of the module's error flag
8900function query_EFP_overflow_error()
891 logical :: query_EFP_overflow_error
8920 query_EFP_overflow_error = overflow_error
8930end function query_EFP_overflow_error
894
895!> Reset the module's error flag to false
8960subroutine reset_EFP_overflow_error()
8970 overflow_error = .false.
8980end subroutine reset_EFP_overflow_error
899
900!> Add two extended-fixed-point numbers
9013function EFP_plus(EFP1, EFP2)
902 type(EFP_type) :: EFP_plus !< The result in extended fixed point format
903 type(EFP_type), intent(in) :: EFP1 !< The first extended fixed point number
904 type(EFP_type), intent(in) :: EFP2 !< The second extended fixed point number
905
9063 EFP_plus = EFP1
907
9083 call increment_ints(EFP_plus%v(:), EFP2%v(:))
9093end function EFP_plus
910
911!> Subract one extended-fixed-point number from another
91212function EFP_minus(EFP1, EFP2)
913 type(EFP_type) :: EFP_minus !< The result in extended fixed point format
914 type(EFP_type), intent(in) :: EFP1 !< The first extended fixed point number
915 type(EFP_type), intent(in) :: EFP2 !< The extended fixed point number being
916 !! subtracted from the first extended fixed point number
917 integer :: i
918
91984 do i=1,efp_digits ; EFP_minus%v(i) = -1*EFP2%v(i) ; enddo
920
92112 call increment_ints(EFP_minus%v(:), EFP1%v(:))
92212end function EFP_minus
923
924!> Copy one extended-fixed-point number into another
92568subroutine EFP_assign(EFP1, EFP2)
926 type(EFP_type), intent(out) :: EFP1 !< The recipient extended fixed point number
927 type(EFP_type), intent(in) :: EFP2 !< The source extended fixed point number
928 integer i
929 ! This subroutine assigns all components of the extended fixed point type
930 ! variable on the RHS (EFP2) to the components of the variable on the LHS
931 ! (EFP1).
932
933476 do i=1,efp_digits ; EFP1%v(i) = EFP2%v(i) ; enddo
93468end subroutine EFP_assign
935
936!> Return the real number that an extended-fixed-point number corresponds with
93718function EFP_to_real(EFP1)
938 type(EFP_type), intent(inout) :: EFP1 !< The extended fixed point number being converted
939 real :: EFP_to_real !< The real version of the number in arbitrary units [a]
940
94118 call regularize_ints(EFP1%v)
94218 EFP_to_real = ints_to_real(EFP1%v)
94318end function EFP_to_real
944
945!> Take the difference between two extended-fixed-point numbers (EFP1 - EFP2)
946!! and return the result as a real number
9470function EFP_real_diff(EFP1, EFP2)
948 type(EFP_type), intent(in) :: EFP1 !< The first extended fixed point number
949 type(EFP_type), intent(in) :: EFP2 !< The extended fixed point number being
950 !! subtracted from the first extended fixed point number
951 real :: EFP_real_diff !< The real result in arbitrary units [a]
952
953 type(EFP_type) :: EFP_diff
954
9550 EFP_diff = EFP1 - EFP2
9560 EFP_real_diff = EFP_to_real(EFP_diff)
957
9580end function EFP_real_diff
959
960!> Return the extended-fixed-point number that a real number corresponds with
9619function real_to_EFP(val, overflow)
962 real, intent(in) :: val !< The real number being converted in arbitrary units [a]
963 logical, optional, intent(inout) :: overflow !< Returns true if the conversion is being
964 !! done on a value that is too large to be represented
965 type(EFP_type) :: real_to_EFP
966
967 logical :: over
968 character(len=80) :: mesg
969
9709 if (present(overflow)) then
9710 real_to_EFP%v(:) = real_to_ints(val, overflow=overflow)
972 else
9739 over = .false.
97463 real_to_EFP%v(:) = real_to_ints(val, overflow=over)
9759 if (over) then
9760 write(mesg, '(ES13.5)') val
9770 call MOM_error(FATAL,"Overflow in real_to_EFP conversion of "//trim(mesg))
978 endif
979 endif
980
9819end function real_to_EFP
982
983!> This subroutine does a sum across PEs of a list of EFP variables,
984!! returning the sums in place, with all overflows carried.
9854subroutine EFP_list_sum_across_PEs(EFPs, nval, errors)
986 type(EFP_type), dimension(:), &
987 intent(inout) :: EFPs !< The list of extended fixed point numbers
988 !! being summed across PEs.
989 integer, intent(in) :: nval !< The number of values being summed.
990 logical, dimension(:), &
991 optional, intent(out) :: errors !< A list of error flags for each sum
992
993 ! This subroutine does a sum across PEs of a list of EFP variables,
994 ! returning the sums in place, with all overflows carried.
995
9968 integer(kind=int64), dimension(efp_digits,nval) :: ints
997 integer(kind=int64) :: prec_error
998 logical :: error_found
999 character(len=256) :: mesg
1000 integer :: i, n
1001
10024 if (num_PEs() > max_summands) call MOM_error(FATAL, &
1003 "reproducing_sum: Too many processors are being used for the value of "//&
10040 "prec. Reduce prec to (2^63-1)/num_PEs.")
1005
10064 prec_error = huge(1_int64) / num_PEs()
1007
1008 ! overflow_error is an overflow error flag for the whole module.
10094 overflow_error = .false. ; error_found = .false.
1010
101188 do i=1,nval ; do n=1,efp_digits ; ints(n,i) = EFPs(i)%v(n) ; enddo ; enddo
1012
10134 call sum_across_PEs(ints(:,:), efp_digits*nval)
1014
10154 if (present(errors)) errors(:) = .false.
101616 do i=1,nval
101712 overflow_error = .false.
101812 call carry_overflow(ints(:,i), prec_error)
101984 do n=1,efp_digits ; EFPs(i)%v(n) = ints(n,i) ; enddo
102012 if (present(errors)) errors(i) = overflow_error
102112 if (overflow_error) then
1022 write (mesg,'("EFP_list_sum_across_PEs error at ",i0," val was ",ES12.6, ", prec_error = ",ES12.6)') &
10230 i, EFP_to_real(EFPs(i)), real(prec_error)
10240 call MOM_error(WARNING, mesg)
1025 endif
102616 error_found = error_found .or. overflow_error
1027 enddo
10284 if (error_found .and. .not.(present(errors))) then
10290 call MOM_error(FATAL, "Overflow in EFP_list_sum_across_PEs.")
1030 endif
1031
10324end subroutine EFP_list_sum_across_PEs
1033
1034!> This subroutine does a sum across PEs of an EFP variable,
1035!! returning the sums in place, with all overflows carried.
10360subroutine EFP_val_sum_across_PEs(EFP, error)
1037 type(EFP_type), intent(inout) :: EFP !< The extended fixed point numbers
1038 !! being summed across PEs.
1039 logical, optional, intent(out) :: error !< An error flag for this sum
1040
1041 ! This subroutine does a sum across PEs of a list of EFP variables,
1042 ! returning the sums in place, with all overflows carried.
1043
1044 integer(kind=int64), dimension(efp_digits) :: ints
1045 integer(kind=int64) :: prec_error
1046 logical :: error_found
1047 character(len=256) :: mesg
1048 integer :: n
1049
10500 if (num_PEs() > max_summands) call MOM_error(FATAL, &
1051 "reproducing_sum: Too many processors are being used for the value of "//&
10520 "prec. Reduce prec to (2^63-1)/num_PEs.")
1053
10540 prec_error = huge(1_int64) / num_PEs()
1055
1056 ! overflow_error is an overflow error flag for the whole module.
10570 overflow_error = .false. ; error_found = .false.
1058
10590 do n=1,efp_digits ; ints(n) = EFP%v(n) ; enddo
1060
10610 call sum_across_PEs(ints(:), efp_digits)
1062
10630 if (present(error)) error = .false.
1064
10650 overflow_error = .false.
10660 call carry_overflow(ints(:), prec_error)
10670 do n=1,efp_digits ; EFP%v(n) = ints(n) ; enddo
10680 if (present(error)) error = overflow_error
10690 if (overflow_error) then
1070 write (mesg,'("EFP_val_sum_across_PEs error val was ",ES12.6, ", prec_error = ",ES12.6)') &
10710 EFP_to_real(EFP), real(prec_error)
10720 call MOM_error(WARNING, mesg)
1073 endif
10740 error_found = error_found .or. overflow_error
1075
10760 if (error_found .and. .not.(present(error))) then
10770 call MOM_error(FATAL, "Overflow in EFP_val_sum_across_PEs.")
1078 endif
1079
10800end subroutine EFP_val_sum_across_PEs
1081
10820end module MOM_coms