MOM6
MOM_coms.F90
Go to the documentation of this file.
1 module mom_coms
2 
3 !***********************************************************************
4 !* GNU General Public License *
5 !* This file is a part of MOM. *
6 !* *
7 !* MOM is free software; you can redistribute it and/or modify it and *
8 !* are expected to follow the terms of the GNU General Public License *
9 !* as published by the Free Software Foundation; either version 2 of *
10 !* the License, or (at your option) any later version. *
11 !* *
12 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
13 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
14 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
15 !* License for more details. *
16 !* *
17 !* For the full text of the GNU General Public License, *
18 !* write to: Free Software Foundation, Inc., *
19 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
20 !* or see: http://www.gnu.org/licenses/gpl.html *
21 !***********************************************************************
22 
23 use mom_error_handler, only : mom_error, mom_mesg, fatal, warning
24 use fms_mod, only : fms_end, mom_infra_init => fms_init
25 use memutils_mod, only : print_memuse_stats
26 use mpp_mod, only : pe_here => mpp_pe, root_pe => mpp_root_pe, num_pes => mpp_npes
27 use mpp_mod, only : set_pelist => mpp_set_current_pelist, get_pelist => mpp_get_current_pelist
28 use mpp_mod, only : broadcast => mpp_broadcast
29 use mpp_mod, only : sum_across_pes => mpp_sum, min_across_pes => mpp_min
30 use mpp_mod, only : max_across_pes => mpp_max
31 
32 implicit none ; private
33 
34 public :: pe_here, root_pe, num_pes, mom_infra_init, mom_infra_end
35 public :: broadcast, sum_across_pes, min_across_pes, max_across_pes
38 public :: operator(+), operator(-), assignment(=)
40 public :: set_pelist, get_pelist
41 ! This module provides interfaces to the non-domain-oriented communication
42 ! subroutines.
43 
44 integer(kind=8), parameter :: prec=2_8**46 ! The precision of each integer.
45 real, parameter :: r_prec=2.0**46 ! A real version of prec.
46 real, parameter :: i_prec=1.0/(2.0**46) ! The inverse of prec.
47 integer, parameter :: max_count_prec=2**(63-46)-1
48  ! The number of values that can be added together
49  ! with the current value of prec before there will
50  ! be roundoff problems.
51 
52 integer, parameter :: ni=6 ! The number of long integers to use to represent
53  ! a real number.
54 real, parameter, dimension(ni) :: &
55  pr = (/ r_prec**2, r_prec, 1.0, 1.0/r_prec, 1.0/r_prec**2, 1.0/r_prec**3 /)
56 real, parameter, dimension(ni) :: &
57  i_pr = (/ 1.0/r_prec**2, 1.0/r_prec, 1.0, r_prec, r_prec**2, r_prec**3 /)
58 
59 logical :: overflow_error = .false., nan_error = .false.
60 logical :: debug = .false. ! Making this true enables debugging output.
61 
62 interface reproducing_sum
63  module procedure reproducing_sum_2d, reproducing_sum_3d
64 end interface reproducing_sum
65 
66 ! The Extended Fixed Point (EFP) type provides a public interface for doing
67 ! sums and taking differences with this type.
68 type, public :: efp_type ; private
69  integer(kind=8), dimension(ni) :: v
70 end type efp_type
71 
72 interface operator (+); module procedure efp_plus ; end interface
73 interface operator (-); module procedure efp_minus ; end interface
74 interface assignment(=); module procedure efp_assign ; end interface
75 
76 contains
77 
78 function reproducing_sum_2d(array, isr, ier, jsr, jer, EFP_sum, reproducing, &
79  overflow_check, err) result(sum)
80  real, dimension(:,:), intent(in) :: array
81  integer, optional, intent(in) :: isr, ier, jsr, jer
82  type(efp_type), optional, intent(out) :: EFP_sum
83  logical, optional, intent(in) :: reproducing
84  logical, optional, intent(in) :: overflow_check
85  integer, optional, intent(out) :: err
86  real :: sum ! Result
87 
88  ! This subroutine uses a conversion to an integer representation
89  ! of real numbers to give order-invariant sums that will reproduce
90  ! across PE count. This idea comes from R. Hallberg and A. Adcroft.
91 
92  integer(kind=8), dimension(ni) :: ints_sum
93  integer(kind=8) :: ival, prec_error
94  real :: rsum(1), rs
95  real :: max_mag_term
96  logical :: repro, over_check
97  character(len=256) :: mesg
98  integer :: i, j, n, is, ie, js, je, sgn
99 
100  if (num_pes() > max_count_prec) call mom_error(fatal, &
101  "reproducing_sum: Too many processors are being used for the value of "//&
102  "prec. Reduce prec to (2^63-1)/num_PEs.")
103 
104  prec_error = (2_8**62 + (2_8**62 - 1)) / num_pes()
105 
106  is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2 )
107  if (present(isr)) then
108  if (isr < is) call mom_error(fatal, &
109  "Value of isr too small in reproducing_sum_2d.")
110  is = isr
111  endif
112  if (present(ier)) then
113  if (ier > ie) call mom_error(fatal, &
114  "Value of ier too large in reproducing_sum_2d.")
115  ie = ier
116  endif
117  if (present(jsr)) then
118  if (jsr < js) call mom_error(fatal, &
119  "Value of jsr too small in reproducing_sum_2d.")
120  js = jsr
121  endif
122  if (present(jer)) then
123  if (jer > je) call mom_error(fatal, &
124  "Value of jer too large in reproducing_sum_2d.")
125  je = jer
126  endif
127 
128  repro = .true. ; if (present(reproducing)) repro = reproducing
129  over_check = .true. ; if (present(overflow_check)) over_check = overflow_check
130 
131  if (repro) then
132  overflow_error = .false. ; nan_error = .false. ; max_mag_term = 0.0
133  ints_sum(:) = 0
134  if (over_check) then
135  if ((je+1-js)*(ie+1-is) < max_count_prec) then
136  do j=js,je ; do i=is,ie
137  call increment_ints_faster(ints_sum, array(i,j), max_mag_term);
138  enddo ; enddo
139  call carry_overflow(ints_sum, prec_error)
140  elseif ((ie+1-is) < max_count_prec) then
141  do j=js,je
142  do i=is,ie
143  call increment_ints_faster(ints_sum, array(i,j), max_mag_term);
144  enddo
145  call carry_overflow(ints_sum, prec_error)
146  enddo
147  else
148  do j=js,je ; do i=is,ie
149  call increment_ints(ints_sum, real_to_ints(array(i,j), prec_error), &
150  prec_error);
151  enddo ; enddo
152  endif
153  else
154  do j=js,je ; do i=is,ie
155  sgn = 1 ; if (array(i,j)<0.0) sgn = -1
156  rs = abs(array(i,j))
157  do n=1,ni
158  ival = int(rs*i_pr(n), 8)
159  rs = rs - ival*pr(n)
160  ints_sum(n) = ints_sum(n) + sgn*ival
161  enddo
162  enddo ; enddo
163  call carry_overflow(ints_sum, prec_error)
164  endif
165 
166  if (present(err)) then
167  err = 0
168  if (overflow_error) &
169  err = err+2
170  if (nan_error) &
171  err = err+4
172  if (err > 0) then ; do n=1,ni ; ints_sum(n) = 0 ; enddo ; endif
173  else
174  if (nan_error) then
175  call mom_error(fatal, "NaN in input field of reproducing_sum(_2d).")
176  endif
177  if (abs(max_mag_term) >= prec_error*pr(1)) then
178  write(mesg, '(ES13.5)') max_mag_term
179  call mom_error(fatal,"Overflow in reproducing_sum(_2d) conversion of "//trim(mesg))
180  endif
181  if (overflow_error) then
182  call mom_error(fatal, "Overflow in reproducing_sum(_2d).")
183  endif
184  endif
185 
186  call sum_across_pes(ints_sum, ni)
187 
188  call regularize_ints(ints_sum)
189  sum = ints_to_real(ints_sum)
190  else
191  rsum(1) = 0.0
192  do j=js,je ; do i=is,ie
193  rsum(1) = rsum(1) + array(i,j);
194  enddo ; enddo
195  call sum_across_pes(rsum,1)
196  sum = rsum(1)
197 
198  if (present(err)) then ; err = 0 ; endif
199 
200  if (debug .or. present(efp_sum)) then
201  overflow_error = .false.
202  ints_sum = real_to_ints(sum, prec_error, overflow_error)
203  if (overflow_error) then
204  if (present(err)) then
205  err = err + 2
206  else
207  write(mesg, '(ES13.5)') sum
208  call mom_error(fatal,"Repro_sum_2d: Overflow in real_to_ints conversion of "//trim(mesg))
209  endif
210  endif
211  endif
212  endif
213 
214  if (present(efp_sum)) efp_sum%v(:) = ints_sum(:)
215 
216  if (debug) then
217  write(mesg,'("2d RS: ", ES24.16, 6 Z17.16)') sum, ints_sum(1:ni)
218  call mom_mesg(mesg, 3)
219  endif
220 
221 end function reproducing_sum_2d
222 
223 function reproducing_sum_3d(array, isr, ier, jsr, jer, sums, EFP_sum, err) &
224  result(sum)
225  real, dimension(:,:,:), intent(in) :: array
226  integer, optional, intent(in) :: isr, ier, jsr, jer
227  real, dimension(:), optional, intent(out) :: sums
228  type(efp_type), optional, intent(out) :: EFP_sum
229  integer, optional, intent(out) :: err
230  real :: sum ! Result
231 
232  ! This subroutine uses a conversion to an integer representation
233  ! of real numbers to give order-invariant sums that will reproduce
234  ! across PE count. This idea comes from R. Hallberg and A. Adcroft.
235 
236  real :: max_mag_term
237  integer(kind=8), dimension(ni) :: ints_sum
238  integer(kind=8), dimension(ni,size(array,3)) :: ints_sums
239  integer(kind=8) :: prec_error
240  character(len=256) :: mesg
241  integer :: i, j, k, is, ie, js, je, ke, isz, jsz, n
242 
243  if (num_pes() > max_count_prec) call mom_error(fatal, &
244  "reproducing_sum: Too many processors are being used for the value of "//&
245  "prec. Reduce prec to (2^63-1)/num_PEs.")
246 
247  prec_error = (2_8**62 + (2_8**62 - 1)) / num_pes()
248  max_mag_term = 0.0
249 
250  is = 1 ; ie = size(array,1) ; js = 1 ; je = size(array,2) ; ke = size(array,3)
251  if (present(isr)) then
252  if (isr < is) call mom_error(fatal, &
253  "Value of isr too small in reproducing_sum(_3d).")
254  is = isr
255  endif
256  if (present(ier)) then
257  if (ier > ie) call mom_error(fatal, &
258  "Value of ier too large in reproducing_sum(_3d).")
259  ie = ier
260  endif
261  if (present(jsr)) then
262  if (jsr < js) call mom_error(fatal, &
263  "Value of jsr too small in reproducing_sum(_3d).")
264  js = jsr
265  endif
266  if (present(jer)) then
267  if (jer > je) call mom_error(fatal, &
268  "Value of jer too large in reproducing_sum(_3d).")
269  je = jer
270  endif
271  jsz = je+1-js; isz = ie+1-is
272 
273  if (present(sums)) then
274  if (size(sums) > ke) call mom_error(fatal, "Sums is smaller than "//&
275  "the vertical extent of array in reproducing_sum(_3d).")
276  ints_sums(:,:) = 0
277  overflow_error = .false. ; nan_error = .false. ; max_mag_term = 0.0
278  if (jsz*isz < max_count_prec) then
279  do k=1,ke
280  do j=js,je ; do i=is,ie
281  call increment_ints_faster(ints_sums(:,k), array(i,j,k), max_mag_term);
282  enddo ; enddo
283  call carry_overflow(ints_sums(:,k), prec_error)
284  enddo
285  elseif (isz < max_count_prec) then
286  do k=1,ke ; do j=js,je
287  do i=is,ie
288  call increment_ints_faster(ints_sums(:,k), array(i,j,k), max_mag_term);
289  enddo
290  call carry_overflow(ints_sums(:,k), prec_error)
291  enddo ; enddo
292  else
293  do k=1,ke ; do j=js,je ; do i=is,ie
294  call increment_ints(ints_sums(:,k), &
295  real_to_ints(array(i,j,k), prec_error), prec_error);
296  enddo ; enddo ; enddo
297  endif
298  if (present(err)) then
299  err = 0
300  if (abs(max_mag_term) >= prec_error*pr(1)) err = err+1
301  if (overflow_error) err = err+2
302  if (nan_error) err = err+2
303  if (err > 0) then ; do k=1,ke ; do n=1,ni ; ints_sums(n,k) = 0 ; enddo ; enddo ; endif
304  else
305  if (nan_error) call mom_error(fatal, "NaN in input field of reproducing_sum(_3d).")
306  if (abs(max_mag_term) >= prec_error*pr(1)) then
307  write(mesg, '(ES13.5)') max_mag_term
308  call mom_error(fatal,"Overflow in reproducing_sum(_3d) conversion of "//trim(mesg))
309  endif
310  if (overflow_error) call mom_error(fatal, "Overflow in reproducing_sum(_3d).")
311  endif
312 
313  call sum_across_pes(ints_sums(:,1:ke), ni*ke)
314 
315  sum = 0.0
316  do k=1,ke
317  call regularize_ints(ints_sums(:,k))
318  sums(k) = ints_to_real(ints_sums(:,k))
319  sum = sum + sums(k)
320  enddo
321 
322  if (present(efp_sum)) then
323  efp_sum%v(:) = 0
324  do k=1,ke ; call increment_ints(efp_sum%v(:), ints_sums(:,k)) ; enddo
325  endif
326 
327  if (debug) then
328  do n=1,ni ; ints_sum(n) = 0 ; enddo
329  do k=1,ke ; do n=1,ni ; ints_sum(n) = ints_sum(n) + ints_sums(n,k) ; enddo ; enddo
330  write(mesg,'("3D RS: ", ES24.16, 6 Z17.16)') sum, ints_sum(1:ni)
331  call mom_mesg(mesg, 3)
332  endif
333  else
334  ints_sum(:) = 0
335  overflow_error = .false. ; nan_error = .false. ; max_mag_term = 0.0
336  if (jsz*isz < max_count_prec) then
337  do k=1,ke
338  do j=js,je ; do i=is,ie
339  call increment_ints_faster(ints_sum, array(i,j,k), max_mag_term);
340  enddo ; enddo
341  call carry_overflow(ints_sum, prec_error)
342  enddo
343  elseif (isz < max_count_prec) then
344  do k=1,ke ; do j=js,je
345  do i=is,ie
346  call increment_ints_faster(ints_sum, array(i,j,k), max_mag_term);
347  enddo
348  call carry_overflow(ints_sum, prec_error)
349  enddo ; enddo
350  else
351  do k=1,ke ; do j=js,je ; do i=is,ie
352  call increment_ints(ints_sum, real_to_ints(array(i,j,k), prec_error), &
353  prec_error);
354  enddo ; enddo ; enddo
355  endif
356  if (present(err)) then
357  err = 0
358  if (abs(max_mag_term) >= prec_error*pr(1)) err = err+1
359  if (overflow_error) err = err+2
360  if (nan_error) err = err+2
361  if (err > 0) then ; do n=1,ni ; ints_sum(n) = 0 ; enddo ; endif
362  else
363  if (nan_error) call mom_error(fatal, "NaN in input field of reproducing_sum(_3d).")
364  if (abs(max_mag_term) >= prec_error*pr(1)) then
365  write(mesg, '(ES13.5)') max_mag_term
366  call mom_error(fatal,"Overflow in reproducing_sum(_3d) conversion of "//trim(mesg))
367  endif
368  if (overflow_error) call mom_error(fatal, "Overflow in reproducing_sum(_3d).")
369  endif
370 
371  call sum_across_pes(ints_sum, ni)
372 
373  call regularize_ints(ints_sum)
374  sum = ints_to_real(ints_sum)
375 
376  if (present(efp_sum)) efp_sum%v(:) = ints_sum(:)
377 
378  if (debug) then
379  write(mesg,'("3d RS: ", ES24.16, 6 Z17.16)') sum, ints_sum(1:ni)
380  call mom_mesg(mesg, 3)
381  endif
382  endif
383 
384 end function reproducing_sum_3d
385 
386 function real_to_ints(r, prec_error, overflow) result(ints)
387  real, intent(in) :: r
388  integer(kind=8), optional, intent(in) :: prec_error
389  logical, optional, intent(inout) :: overflow
390  integer(kind=8), dimension(ni) :: ints
391  ! This subroutine converts a real number to an equivalent representation
392  ! using several long integers.
393 
394  real :: rs
395  character(len=80) :: mesg
396  integer(kind=8) :: ival, prec_err
397  integer :: sgn, i
398 
399  prec_err = prec ; if (present(prec_error)) prec_err = prec_error
400  ints(:) = 0_8
401  if ((r >= 1e30) .eqv. (r < 1e30)) then ; nan_error = .true. ; return ; endif
402 
403  sgn = 1 ; if (r<0.0) sgn = -1
404  rs = abs(r)
405 
406  if (present(overflow)) then
407  if (.not.(rs < prec_err*pr(1))) overflow = .true.
408  if ((r >= 1e30) .eqv. (r < 1e30)) overflow = .true.
409  elseif (.not.(rs < prec_err*pr(1))) then
410  write(mesg, '(ES13.5)') r
411  call mom_error(fatal,"Overflow in real_to_ints conversion of "//trim(mesg))
412  endif
413 
414  do i=1,ni
415  ival = int(rs*i_pr(i), 8)
416  rs = rs - ival*pr(i)
417  ints(i) = sgn*ival
418  enddo
419 
420 end function real_to_ints
421 
422 function ints_to_real(ints) result(r)
423  integer(kind=8), dimension(ni), intent(in) :: ints
424  real :: r
425  ! This subroutine reverses the conversion in real_to_ints.
426 
427  integer :: i
428 
429  r = 0.0
430  do i=1,ni ; r = r + pr(i)*ints(i) ; enddo
431 end function ints_to_real
432 
433 subroutine increment_ints(int_sum, int2, prec_error)
434  integer(kind=8), dimension(ni), intent(inout) :: int_sum
435  integer(kind=8), dimension(ni), intent(in) :: int2
436  integer(kind=8), optional, intent(in) :: prec_error
437 
438  ! This subroutine increments a number with another, both using the integer
439  ! representation in real_to_ints.
440  integer :: i
441 
442  do i=ni,2,-1
443  int_sum(i) = int_sum(i) + int2(i)
444  ! Carry the local overflow.
445  if (int_sum(i) > prec) then
446  int_sum(i) = int_sum(i) - prec
447  int_sum(i-1) = int_sum(i-1) + 1
448  elseif (int_sum(i) < -prec) then
449  int_sum(i) = int_sum(i) + prec
450  int_sum(i-1) = int_sum(i-1) - 1
451  endif
452  enddo
453  int_sum(1) = int_sum(1) + int2(1)
454  if (present(prec_error)) then
455  if (abs(int_sum(1)) > prec_error) overflow_error = .true.
456  else
457  if (abs(int_sum(1)) > prec) overflow_error = .true.
458  endif
459 
460 end subroutine increment_ints
461 
462 subroutine increment_ints_faster(int_sum, r, max_mag_term)
463  integer(kind=8), dimension(ni), intent(inout) :: int_sum
464  real, intent(in) :: r
465  real, intent(inout) :: max_mag_term
466 
467  ! This subroutine increments a number with another, both using the integer
468  ! representation in real_to_ints, but without doing any carrying of overflow.
469  ! The entire operation is embedded in a single call for greater speed.
470  real :: rs
471  integer(kind=8) :: ival
472  integer :: sgn, i
473 
474  if ((r >= 1e30) .eqv. (r < 1e30)) then ; nan_error = .true. ; return ; endif
475  sgn = 1 ; if (r<0.0) sgn = -1
476  rs = abs(r)
477  if (rs > abs(max_mag_term)) max_mag_term = r
478 
479  do i=1,ni
480  ival = int(rs*i_pr(i), 8)
481  rs = rs - ival*pr(i)
482  int_sum(i) = int_sum(i) + sgn*ival
483  enddo
484 
485 end subroutine increment_ints_faster
486 
487 subroutine carry_overflow(int_sum, prec_error)
488  integer(kind=8), dimension(ni), intent(inout) :: int_sum
489  integer(kind=8), intent(in) :: prec_error
490 
491  ! This subroutine handles carrying of the overflow.
492  integer :: i, num_carry
493 
494  do i=ni,2,-1 ; if (abs(int_sum(i)) > prec) then
495  num_carry = int(int_sum(i) * i_prec)
496  int_sum(i) = int_sum(i) - num_carry*prec
497  int_sum(i-1) = int_sum(i-1) + num_carry
498  endif ; enddo
499  if (abs(int_sum(1)) > prec_error) then
500  overflow_error = .true.
501  endif
502 
503 end subroutine carry_overflow
504 
505 subroutine regularize_ints(int_sum)
506  integer(kind=8), dimension(ni), intent(inout) :: int_sum
507 
508  ! This subroutine carries the overflow, and then makes sure that
509  ! all integers are of the same sign as the overall value.
510  logical :: positive
511  integer :: i, num_carry
512 
513  do i=ni,2,-1 ; if (abs(int_sum(i)) > prec) then
514  num_carry = int(int_sum(i) * i_prec)
515  int_sum(i) = int_sum(i) - num_carry*prec
516  int_sum(i-1) = int_sum(i-1) + num_carry
517  endif ; enddo
518 
519  ! Determine the sign of the final number.
520  positive = .true.
521  do i=1,ni
522  if (abs(int_sum(i)) > 0) then
523  if (int_sum(i) < 0) positive = .false.
524  exit
525  endif
526  enddo
527 
528  if (positive) then
529  do i=ni,2,-1 ; if (int_sum(i) < 0) then
530  int_sum(i) = int_sum(i) + prec
531  int_sum(i-1) = int_sum(i-1) - 1
532  endif ; enddo
533  else
534  do i=ni,2,-1 ; if (int_sum(i) > 0) then
535  int_sum(i) = int_sum(i) - prec
536  int_sum(i-1) = int_sum(i-1) + 1
537  endif ; enddo
538  endif
539 
540 end subroutine regularize_ints
541 
542 function query_efp_overflow_error()
543  logical :: query_EFP_overflow_error
544  query_efp_overflow_error = overflow_error
545 end function query_efp_overflow_error
546 
547 subroutine reset_efp_overflow_error()
548  overflow_error = .false.
549 end subroutine reset_efp_overflow_error
550 
551 function efp_plus(EFP1, EFP2)
552  type(efp_type) :: EFP_plus
553  type(efp_type), intent(in) :: EFP1, EFP2
554 
555  efp_plus = efp1
556 
557  call increment_ints(efp_plus%v(:), efp2%v(:))
558 end function efp_plus
559 
560 function efp_minus(EFP1, EFP2)
561  type(efp_type) :: EFP_minus
562  type(efp_type), intent(in) :: EFP1, EFP2
563  integer :: i
564 
565  do i=1,ni ; efp_minus%v(i) = -1*efp2%v(i) ; enddo
566 
567  call increment_ints(efp_minus%v(:), efp1%v(:))
568 end function efp_minus
569 
570 subroutine efp_assign(EFP1, EFP2)
571  type(efp_type), intent(out) :: EFP1
572  type(efp_type), intent(in) :: EFP2
573  integer i
574  ! This subroutine assigns all components of the extended fixed point type
575  ! variable on the RHS (EFP2) to the components of the variable on the LHS
576  ! (EFP1).
577 
578  do i=1,ni ; efp1%v(i) = efp2%v(i) ; enddo
579 end subroutine efp_assign
580 
581 function efp_to_real(EFP1)
582  type(efp_type), intent(inout) :: EFP1
583  real :: EFP_to_real
584 
585  call regularize_ints(efp1%v)
586  efp_to_real = ints_to_real(efp1%v)
587 end function efp_to_real
588 
589 function efp_real_diff(EFP1, EFP2)
590  type(efp_type), intent(in) :: EFP1, EFP2
591  real :: EFP_real_diff
592 
593  type(efp_type) :: EFP_diff
594 
595  efp_diff = efp1 - efp2
596  efp_real_diff = efp_to_real(efp_diff)
597 
598 end function efp_real_diff
599 
600 function real_to_efp(val, overflow)
601  real, intent(in) :: val
602  logical, optional, intent(inout) :: overflow
603  type(efp_type) :: real_to_EFP
604 
605  logical :: over
606  character(len=80) :: mesg
607 
608  if (present(overflow)) then
609  real_to_efp%v(:) = real_to_ints(val, overflow=overflow)
610  else
611  over = .false.
612  real_to_efp%v(:) = real_to_ints(val, overflow=over)
613  if (over) then
614  write(mesg, '(ES13.5)') val
615  call mom_error(fatal,"Overflow in real_to_EFP conversion of "//trim(mesg))
616  endif
617  endif
618 
619 end function real_to_efp
620 
621 subroutine efp_list_sum_across_pes(EFPs, nval, errors)
622  type(efp_type), dimension(:), intent(inout) :: EFPs
623  integer, intent(in) :: nval
624  logical, dimension(:), optional, intent(out) :: errors
625 
626  ! This subroutine does a sum across PEs of a list of EFP variables,
627  ! returning the sums in place, with all overflows carried.
628 
629  integer(kind=8), dimension(ni,nval) :: ints
630  integer(kind=8) :: prec_error
631  logical :: error_found
632  character(len=256) :: mesg
633  integer :: i, n
634 
635  if (num_pes() > max_count_prec) call mom_error(fatal, &
636  "reproducing_sum: Too many processors are being used for the value of "//&
637  "prec. Reduce prec to (2^63-1)/num_PEs.")
638 
639  prec_error = (2_8**62 + (2_8**62 - 1)) / num_pes()
640  ! overflow_error is an overflow error flag for the whole module.
641  overflow_error = .false. ; error_found = .false.
642 
643  do i=1,nval ; do n=1,ni ; ints(n,i) = efps(i)%v(n) ; enddo ; enddo
644 
645  call sum_across_pes(ints(:,:), ni*nval)
646 
647  if (present(errors)) errors(:) = .false.
648  do i=1,nval
649  overflow_error = .false.
650  call carry_overflow(ints(:,i), prec_error)
651  do n=1,ni ; efps(i)%v(n) = ints(n,i) ; enddo
652  if (present(errors)) errors(i) = overflow_error
653  if (overflow_error) then
654  write (mesg,'("EFP_list_sum_across_PEs error at ",i6," val was ",ES12.6, ", prec_error = ",ES12.6)') &
655  i, efp_to_real(efps(i)), real(prec_error)
656  call mom_error(warning, mesg)
657  endif
658  error_found = error_found .or. overflow_error
659  enddo
660  if (error_found .and. .not.(present(errors))) then
661  call mom_error(fatal, "Overflow in EFP_list_sum_across_PEs.")
662  endif
663 
664 end subroutine efp_list_sum_across_pes
665 
666 subroutine mom_infra_end
667  ! This subroutine should contain all of the calls that are required
668  ! to close out the infrastructure cleanly. This should only be called
669  ! in ocean-only runs, as the coupler takes care of this in coupled runs.
670  call print_memuse_stats( 'Memory HiWaterMark', always=.true. )
671  call fms_end
672 end subroutine mom_infra_end
673 
674 end module mom_coms
logical nan_error
Definition: MOM_coms.F90:59
subroutine, public efp_list_sum_across_pes(EFPs, nval, errors)
Definition: MOM_coms.F90:622
real, dimension(ni), parameter pr
Definition: MOM_coms.F90:54
real function reproducing_sum_2d(array, isr, ier, jsr, jer, EFP_sum, reproducing, overflow_check, err)
Definition: MOM_coms.F90:80
logical overflow_error
Definition: MOM_coms.F90:59
subroutine, public reset_efp_overflow_error()
Definition: MOM_coms.F90:548
type(efp_type) function, public real_to_efp(val, overflow)
Definition: MOM_coms.F90:601
integer, parameter ni
Definition: MOM_coms.F90:52
type(efp_type) function, public efp_minus(EFP1, EFP2)
Definition: MOM_coms.F90:561
subroutine efp_assign(EFP1, EFP2)
Definition: MOM_coms.F90:571
logical function, public query_efp_overflow_error()
Definition: MOM_coms.F90:543
real, parameter i_prec
Definition: MOM_coms.F90:46
real, parameter r_prec
Definition: MOM_coms.F90:45
real function reproducing_sum_3d(array, isr, ier, jsr, jer, sums, EFP_sum, err)
Definition: MOM_coms.F90:225
subroutine increment_ints(int_sum, int2, prec_error)
Definition: MOM_coms.F90:434
subroutine increment_ints_faster(int_sum, r, max_mag_term)
Definition: MOM_coms.F90:463
real function ints_to_real(ints)
Definition: MOM_coms.F90:423
subroutine carry_overflow(int_sum, prec_error)
Definition: MOM_coms.F90:488
integer, parameter max_count_prec
Definition: MOM_coms.F90:47
subroutine, public mom_mesg(message, verb, all_print)
real, dimension(ni), parameter i_pr
Definition: MOM_coms.F90:56
integer(kind=8) function, dimension(ni) real_to_ints(r, prec_error, overflow)
Definition: MOM_coms.F90:387
integer(kind=8), parameter prec
Definition: MOM_coms.F90:44
subroutine regularize_ints(int_sum)
Definition: MOM_coms.F90:506
logical debug
Definition: MOM_coms.F90:60
real function, public efp_to_real(EFP1)
Definition: MOM_coms.F90:582
subroutine, public mom_infra_end
Definition: MOM_coms.F90:667
subroutine, public mom_error(level, message, all_print)
real function, public efp_real_diff(EFP1, EFP2)
Definition: MOM_coms.F90:590
type(efp_type) function, public efp_plus(EFP1, EFP2)
Definition: MOM_coms.F90:552