← 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.
12158function 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
15858 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
16258 prec_error = huge(1_int64) / num_PEs()
163
16458 is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2)
16558 if (present(isr)) then
16645 if (isr < is) call MOM_error(FATAL, "Value of isr too small in reproducing_EFP_sum_2d.")
16745 is = isr
168 endif
16958 if (present(ier)) then
17045 if (ier > ie) call MOM_error(FATAL, "Value of ier too large in reproducing_EFP_sum_2d.")
17145 ie = ier
172 endif
17358 if (present(jsr)) then
17445 if (jsr < js) call MOM_error(FATAL, "Value of jsr too small in reproducing_EFP_sum_2d.")
17545 js = jsr
176 endif
17758 if (present(jer)) then
17845 if (jer > je) call MOM_error(FATAL, "Value of jer too large in reproducing_EFP_sum_2d.")
17945 je = jer
180 endif
181
18258 over_check = .true. ; if (present(overflow_check)) over_check = overflow_check
18358 do_sum_across_PEs = .true. ; if (present(only_on_PE)) do_sum_across_PEs = .not.only_on_PE
18458 do_unscale = .false. ; if (present(unscale)) do_unscale = (unscale /= 1.0)
18558 descale = 1.0 ; if (do_unscale) descale = unscale
186
18758 overflow_error = .false. ; NaN_error = .false. ; max_mag_term = 0.0
188
18958 ints_sum(:) = 0
19058 if (over_check) then
191 call increment_block_ints(array, is, ie, js, je, descale, ints_sum, &
19258 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
20658 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
21458 if (NaN_error) then
2150 call MOM_error(FATAL, "NaN in input field of reproducing_EFP_sum(_2d).")
216 endif
21758 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
22158 if (overflow_error) then
2220 call MOM_error(FATAL, "Overflow in reproducing_EFP_sum(_2d).")
223 endif
224 endif
225
22658 if (do_sum_across_PEs) call sum_across_PEs(ints_sum, efp_digits)
227
22858 call regularize_ints(ints_sum)
229
230406 EFP_sum%v(:) = ints_sum(:)
231
23258end 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.
23913function 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
27913 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
28313 prec_error = huge(1_int64) / num_PEs()
284
28513 is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2)
28613 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
29013 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
29413 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
29813 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
30313 repro = .true. ; if (present(reproducing)) repro = reproducing
30413 do_sum_across_PEs = .true. ; if (present(only_on_PE)) do_sum_across_PEs = .not.only_on_PE
30513 do_unscale = .false. ; if (present(unscale)) do_unscale = (unscale /= 1.0)
30613 descale = 1.0 ; I_unscale = 1.0
30713 if (do_unscale) then
3080 descale = unscale
3090 if (abs(unscale) > 0.0) I_unscale = 1.0 / unscale
310 endif
311
31213 if (repro) then
31313 EFP_val = reproducing_EFP_sum_2d(array, isr, ier, jsr, jer, overflow_check, err, only_on_PE, unscale)
31413 sum = ints_to_real(EFP_val%v) * I_unscale
31513 if (present(EFP_sum)) EFP_sum = EFP_val
31613 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
34213 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
34713end 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.
3539function 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
38618 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
3929 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
3969 prec_error = huge(1_int64) / num_PEs()
3979 max_mag_term = 0.0
398
3999 is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2) ; ke = size(array,3)
4009 if (present(isr)) then
4019 if (isr < is) call MOM_error(FATAL, "Value of isr too small in reproducing_sum(_3d).")
4029 is = isr
403 endif
4049 if (present(ier)) then
4059 if (ier > ie) call MOM_error(FATAL, "Value of ier too large in reproducing_sum(_3d).")
4069 ie = ier
407 endif
4089 if (present(jsr)) then
4099 if (jsr < js) call MOM_error(FATAL, "Value of jsr too small in reproducing_sum(_3d).")
4109 js = jsr
411 endif
4129 if (present(jer)) then
4139 if (jer > je) call MOM_error(FATAL, "Value of jer too large in reproducing_sum(_3d).")
4149 je = jer
415 endif
4169 jsz = je+1-js ; isz = ie+1-is
417
4189 do_sum_across_PEs = .true. ; if (present(only_on_PE)) do_sum_across_PEs = .not.only_on_PE
4199 do_unscale = .false. ; if (present(unscale)) do_unscale = (unscale /= 1.0)
4209 descale = 1.0 ; if (do_unscale) descale = unscale
421
4229 if (present(sums) .or. present(EFP_lay_sums)) then
4239 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
4269 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
4309 overflow_error = .false. ; NaN_error = .false. ; max_mag_term = 0.0
431
4324755 ints_sums(:,:) = 0
433687 do k=1,ke
434 call increment_block_ints(array(:,:,k), is, ie, js, je, descale, &
435687 ints_sums(:,k), max_mag_term, prec_error)
436 enddo
437
4389 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
4459 if (NaN_error) call MOM_error(FATAL, "NaN in input field of reproducing_sum(_3d).")
4469 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
4509 if (overflow_error) call MOM_error(FATAL, "Overflow in reproducing_sum(_3d).")
451 endif
452
4539 if (do_sum_across_PEs) call sum_across_PEs(ints_sums(:,1:ke), efp_digits*ke)
454
4559 sum = 0.0
456687 do k=1,ke
457678 call regularize_ints(ints_sums(:,k))
458678 val = ints_to_real(ints_sums(:,k))
459678 if (present(sums)) sums(k) = val
460687 sum = sum + val
461 enddo
4629 if (present(EFP_lay_sums)) then ; do k=1,ke
4630 EFP_lay_sums(k)%v(:) = ints_sums(:,k)
464 enddo ; endif
465
4669 if (present(EFP_sum)) then
46721 EFP_sum%v(:) = 0
468228 do k=1,ke ; call increment_ints(EFP_sum%v(:), ints_sums(:,k)) ; enddo
469 endif
470
4719 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
5149 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
5239end function reproducing_sum_3d
524
525!> Convert a real number into the array of integers constitute its extended-fixed-point representation
52612function 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
54512 prec_err = prec ; if (present(prec_error)) prec_err = prec_error
54684 ints(:) = 0
54712 if ((r >= 1e30) .eqv. (r < 1e30)) then ; NaN_error = .true. ; return ; endif
548
54912 sgn = 1 ; if (r<0.0) sgn = -1
55012 rs = abs(r)
551
55212 if (present(overflow)) then
55312 if (.not.(rs < prec_err*pr(1))) overflow = .true.
55412 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
56084 do i=1,efp_digits
56172 ival = int(rs*I_pr(i), kind=int64)
56272 rs = rs - ival*pr(i)
56384 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
570718function 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
577718 r = 0.0
5785026 do i=1,efp_digits ; r = r + pr(i)*ints(i) ; enddo
579718end function ints_to_real
580
581!> Increment an array of integers that constitutes an extended-fixed-point
582!! representation with a another EFP number
583279subroutine 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
5951674 do i=efp_digits,2,-1
5961395 int_sum(i) = int_sum(i) + int2(i)
597 ! Carry the local overflow.
5981674 if (int_sum(i) > prec) then
599222 int_sum(i) = int_sum(i) - prec
600222 int_sum(i-1) = int_sum(i-1) + 1
6011173 elseif (int_sum(i) < -prec) then
60218 int_sum(i) = int_sum(i) + prec
60318 int_sum(i-1) = int_sum(i-1) - 1
604 endif
605 enddo
606279 int_sum(1) = int_sum(1) + int2(1)
607279 if (present(prec_error)) then
6080 if (abs(int_sum(1)) > prec_error) overflow_error = .true.
609 else
610279 if (abs(int_sum(1)) > prec) overflow_error = .true.
611 endif
612
613279end 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.
618736subroutine 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
665736 max_pos = max(0., max_mag_term)
666736 max_neg = max(0., -max_mag_term)
667736 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.
671736 max_sum_count = max_summands - 2
672
673 ! Get the compute domain size
674736 ni = ie - is + 1
675736 nj = je - js + 1
676
677 ! Partition in i so that the widest i-slice fits within max_sum_count.
678736 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
686736 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.
691736 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.
695736 njblocks = (nj + jsize - 1) / jsize
696 ! = ⌈nj / jsize⌉
697
698736 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.
702736 if (nblocks > max_sum_count) call MOM_error(FATAL, &
703 "reproducing sum: Number of blocks exceeds summmation carry limit." &
7040 )
705
706736 array_sum(:) = 0
707
7082208 do jb=1,njblocks ; do ib=1,niblocks
709 ! Use evenly distributed blocks, either ⌊n / nblocks⌋ or ⌈n / nblocks⌉.
710736 jbs = js + ((jb - 1) * nj) / njblocks
711736 jbe = js + (jb * nj) / njblocks - 1
712
713736 ibs = is + ((ib - 1) * ni) / niblocks
714736 ibe = is + (ib * ni) / niblocks - 1
715
716736 block_sum(:) = 0
717736 block_max_pos = 0.
718736 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)) &
724736 DO_LOCALITY(reduce(max: block_max_pos, block_max_neg, inan, iovf))
725
726 ! Convert array(i,j) to EFP form
7275317248 r = descale * array(i,j)
7285317248 call efp_decompose(r, e, rmag, lnan, lovf)
729
730 ! Verify that the conversion was completed
7315317248 inan = max(inan, lnan)
7325317248 iovf = max(iovf, lovf)
733
7345317248 if (r >= 0.) then
7355153185 if (rmag > block_max_pos) block_max_pos = rmag
736 else
737164063 if (rmag > block_max_neg) block_max_neg = rmag
738 endif
739
740 ! Add the EFP result (including potential carry bits)
74137309888 block_sum(:) = block_sum(:) + e(:)
742 enddo ; enddo
743
7445152 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.
748736 b = (jb - 1) * niblocks + ib
749736 if (b < nblocks) call carry_overflow(array_sum, prec_error)
750
751 ! Update maximum magnitudes
752736 max_pos = max(max_pos, block_max_pos)
7531472 max_neg = max(max_neg, block_max_neg)
754 enddo
755
756 ! Finally, apply the cumulant result
7575152 ints_sum(:) = ints_sum(:) + array_sum(:)
758
759 ! Redistribute carry bits to normalize the final result.
760736 call carry_overflow(ints_sum, prec_error)
761
762 ! Extract the maximum value while preserving sign (NOTE: ties to positive)
763736 if (max_pos >= max_neg) then
764711 max_mag_term = max_pos
765 else
76625 max_mag_term = -max_neg
767 endif
768
769 ! Transfer error/warning signals to module flags
770736 if (inan /= 0) NaN_error = .true.
771736 if (iovf /= 0) overflow_error = .true.
772736end 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.
7785317248pure 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
7975317248 e(:) = 0
7985317248 rmag = 0.0 ; is_nan = 0 ; is_ovf = 0
799
8005317248 if ((r >= 1e30) .eqv. (r < 1e30)) then
8010 is_nan = 1
8020 return
803 endif
804
8055317248 sgn = 1
8065317248 if (r < 0.0) sgn = -1
807
8085317248 rs = abs(r) ; rmag = rs
809
810 ! Abort if the number has no EFP representation
8115317248 if (rs > max_efp_float) then
8120 is_ovf = 1
8130 return
814 endif
815
81637220736 do n=1,efp_digits
81731903488 ival = int(rs * I_pr(n), kind=int64)
81831903488 rs = rs - ival * pr(n)
81931903488 e(n) = sgn * ival
820 enddo
821end subroutine efp_decompose
822
823
824!> This subroutine handles carrying of the overflow.
825754subroutine 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
8364524 do i=efp_digits,2,-1 ; if (abs(int_sum(i)) >= prec) then
837797 num_carry = int(int_sum(i) * I_prec)
838797 int_sum(i) = int_sum(i) - num_carry*prec
839797 int_sum(i-1) = int_sum(i-1) + num_carry
840 endif ; enddo
841754 if (abs(int_sum(1)) > prec_error) then
8420 overflow_error = .true.
843 endif
844
845754end 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.
849763subroutine 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
8604578 do i=efp_digits,2,-1 ; if (abs(int_sum(i)) >= prec) then
8610 num_carry = int(int_sum(i) * I_prec)
8620 int_sum(i) = int_sum(i) - num_carry*prec
8630 int_sum(i-1) = int_sum(i-1) + num_carry
864 endif ; enddo
865
866 ! Determine the sign of the final number.
867763 positive = .true.
8683307 do i=1,efp_digits
8693307 if (abs(int_sum(i)) > 0) then
870443 if (int_sum(i) < 0) positive = .false.
871443 exit
872 endif
873 enddo
874
875763 if (positive) then
8764302 do i=efp_digits,2,-1 ; if (int_sum(i) < 0) then
8770 int_sum(i) = int_sum(i) + prec
8780 int_sum(i-1) = int_sum(i-1) - 1
879 endif ; enddo
880 else
881276 do i=efp_digits,2,-1 ; if (int_sum(i) > 0) then
8825 int_sum(i) = int_sum(i) - prec
8835 int_sum(i-1) = int_sum(i-1) + 1
884 endif ; enddo
885 endif
886
887763end 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
90136function 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
90636 EFP_plus = EFP1
907
90836 call increment_ints(EFP_plus%v(:), EFP2%v(:))
90936end function EFP_plus
910
911!> Subract one extended-fixed-point number from another
91218function 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
919126 do i=1,efp_digits ; EFP_minus%v(i) = -1*EFP2%v(i) ; enddo
920
92118 call increment_ints(EFP_minus%v(:), EFP1%v(:))
92218end function EFP_minus
923
924!> Copy one extended-fixed-point number into another
925205subroutine 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
9331435 do i=1,efp_digits ; EFP1%v(i) = EFP2%v(i) ; enddo
934205end subroutine EFP_assign
935
936!> Return the real number that an extended-fixed-point number corresponds with
93727function 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
94127 call regularize_ints(EFP1%v)
94227 EFP_to_real = ints_to_real(EFP1%v)
94327end 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
96112function 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
97012 if (present(overflow)) then
9710 real_to_EFP%v(:) = real_to_ints(val, overflow=overflow)
972 else
97312 over = .false.
97484 real_to_EFP%v(:) = real_to_ints(val, overflow=over)
97512 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
98112end 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.
9856subroutine 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
99612 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
10026 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
10066 prec_error = huge(1_int64) / num_PEs()
1007
1008 ! overflow_error is an overflow error flag for the whole module.
10096 overflow_error = .false. ; error_found = .false.
1010
1011132 do i=1,nval ; do n=1,efp_digits ; ints(n,i) = EFPs(i)%v(n) ; enddo ; enddo
1012
10136 call sum_across_PEs(ints(:,:), efp_digits*nval)
1014
10156 if (present(errors)) errors(:) = .false.
101624 do i=1,nval
101718 overflow_error = .false.
101818 call carry_overflow(ints(:,i), prec_error)
1019126 do n=1,efp_digits ; EFPs(i)%v(n) = ints(n,i) ; enddo
102018 if (present(errors)) errors(i) = overflow_error
102118 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
102624 error_found = error_found .or. overflow_error
1027 enddo
10286 if (error_found .and. .not.(present(errors))) then
10290 call MOM_error(FATAL, "Overflow in EFP_list_sum_across_PEs.")
1030 endif
1031
10326end 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