source: trunk/LMDZ.COMMON/libf/evolution/numerics.F90

Last change on this file was 4180, checked in by jbclement, 6 hours ago

PEM:

  • Rework layering-related logic, especially clarify interactions between surface and subsurface water tendencies and disable CO2 lag resistance (inconsistent without updating pressure and mass balance + PCM).
  • Prevent simultaneous activation of layering and ice flows.
  • Add warning when flux_geo /= 0 while soil is disabled.
  • Add new utility function "is_lvl_enabled" for displaying.
  • Replace deprecated 'minieps' with 'eps'/'tol'.

JBC

File size: 6.5 KB
Line 
1MODULE numerics
2!-----------------------------------------------------------------------
3! NAME
4!     numerics
5!
6! DESCRIPTION
7!     Management of numerical precision and special values (NaN and Inf)
8!     throughout the code.
9!
10! AUTHORS & DATE
11!     JB Clement, 01/2026
12!
13! NOTES
14!     The intrinsic function storage_size() returns the storage size of
15!     argument in bits.
16!-----------------------------------------------------------------------
17
18! DEPENDENCIES
19! ------------
20use, intrinsic :: iso_fortran_env, only : int8, int16, int32, int64, real32, real64, real128
21!~ use, intrinsic :: ieee_arithmetic
22
23! DECLARATION
24! -----------
25implicit none
26
27! PARAMETERS
28! ----------
29! Integers
30integer, parameter :: lli_candidate = selected_int_kind(38)
31logical, parameter :: has_int128 = (lli_candidate > 0)
32integer, parameter :: ti = int8                                ! Tiny integer      = 8 bits
33integer, parameter :: si = int16                               ! Short integer     = 16 bits
34integer, parameter :: di = int32                               ! Standard integer  = 32 bits (default)
35integer, parameter :: li = int64                               ! Long integer      = 64 bits
36integer, parameter :: lli = merge(lli_candidate,li,has_int128) ! Long long integer = 128 bits (if available, otherwise fallback to int64)
37integer, parameter :: wi = di                                  ! Working integer
38
39! Reals
40integer, parameter :: sp = real32  ! Simple precision    = 32  bits = 1-bit sign + 8-bit  exponent + 23-bit  significand
41integer, parameter :: dp = real64  ! Double precision    = 64  bits = 1-bit sign + 11-bit exponent + 52-bit  significand
42integer, parameter :: qp = real128 ! Quadruple precision = 128 bits = 1-bit sign + 15-bit exponent + 112-bit significand
43integer, parameter :: wp = dp      ! Working precision
44
45! Logicals
46! The precision is given by the compiler to be the same as the standard integer precision (32 bits) for memory reasons.
47! It can be interesting to have smaller logical to reduce memory load.
48! But be careful: definition is compiler-dependent and processor-dependent! So the following kinds are not guaranteed for logicals!
49integer, parameter :: k1 = 1 ! kind = 1 should be 8  bits
50integer, parameter :: k2 = 2 ! kind = 2 should be 16 bits
51integer, parameter :: k4 = 4 ! kind = 4 should be 32 bits (default)
52
53! Smallest strictly positive representable real number
54real(sp), parameter :: smallest_sp = tiny(1._sp)
55real(dp), parameter :: smallest_dp = tiny(1._dp)
56real(qp), parameter :: smallest_qp = tiny(1._qp)
57real(wp), parameter :: smallest_nb = tiny(1._wp)
58
59! Largest representable number
60integer(ti),  parameter :: largest_ti = huge(1_ti)
61integer(si),  parameter :: largest_si = huge(1_si)
62integer(di),  parameter :: largest_di = huge(1_di)
63integer(li),  parameter :: largest_li = huge(1_li)
64integer(lli), parameter :: largest_lli = huge(1_lli)
65integer(wi),  parameter :: largest_wi = huge(1_wi)
66real(sp),     parameter :: largest_sp = huge(1._sp)
67real(dp),     parameter :: largest_dp = huge(1._dp)
68real(qp),     parameter :: largest_qp = huge(1._qp)
69real(wp),     parameter :: largest_nb = huge(1._wp)
70
71! Machine epsilon: smallest positive real number such that 1 + epsilon > 1
72real(sp), parameter :: minieps_sp = epsilon(1._sp)
73real(dp), parameter :: minieps_dp = epsilon(1._dp)
74real(qp), parameter :: minieps_qp = epsilon(1._qp)
75real(wp), parameter :: minieps = epsilon(1._wp)
76real(wp), parameter :: eps    = 100._wp*minieps    ! ~ 10^(-14)
77real(wp), parameter :: eps_qp = 100._wp*minieps_qp ! ~ 10^(-14)
78real(wp), parameter :: tol    = 100._wp*eps        ! ~ 10^(-12)
79
80! Minimum number of significant decimal digits
81integer, parameter :: prec_sp = precision(1._sp)
82integer, parameter :: prec_dp = precision(1._dp)
83integer, parameter :: prec_qp = precision(1._qp)
84integer, parameter :: prec = precision(1._wp)
85
86!~ contains
87!~ !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
88
89!~ !=======================================================================
90!~ FUNCTION is_finite(var) RESULT(flag)
91!~ !-----------------------------------------------------------------------
92!~ ! NAME
93!~ !     is_finite
94!~ !
95!~ ! DESCRIPTION
96!~ !     Returns whether array values are finite.
97!~ !
98!~ ! AUTHORS & DATE
99!~ !     JB Clement, 01/2026
100!~ !
101!~ ! NOTES
102!~ !     Finite values are neither NaN nor Infinite.
103!~ !-----------------------------------------------------------------------
104
105!~ ! DECLARATION
106!~ ! -----------
107!~ implicit none
108
109!~ ! ARGUMENTS
110!~ ! ---------
111!~ real(dp), dimension(..), intent(in)  :: var
112
113!~ ! LOCAL VARIABLES
114!~ ! ---------------
115!~ logical(k4) :: flag
116
117!~ ! CODE
118!~ ! ----
119!~ flag = .false.
120!~ if (all(ieee_is_finite(var))) flag = .true.
121
122!~ END FUNCTION is_finite
123!~ !=======================================================================
124
125!~ !=======================================================================
126!~ FUNCTION is_nan(var) RESULT(flag)
127!~ !-----------------------------------------------------------------------
128!~ ! NAME
129!~ !     is_nan
130!~ !
131!~ ! DESCRIPTION
132!~ !     Returns whether array values has a Not-a-Number (NaN).
133!~ !
134!~ ! AUTHORS & DATE
135!~ !     JB Clement, 01/2026
136!~ !
137!~ ! NOTES
138!~ !
139!~ !-----------------------------------------------------------------------
140
141!~ ! DECLARATION
142!~ ! -----------
143!~ implicit none
144
145!~ ! ARGUMENTS
146!~ ! ---------
147!~ real(dp), dimension(..), intent(in)  :: var
148
149!~ ! LOCAL VARIABLES
150!~ ! ---------------
151!~ logical(k4) :: flag
152
153!~ ! CODE
154!~ ! ----
155!~ flag = .false.
156!~ if (any(ieee_is_nan(var))) flag = .true.
157
158!~ END FUNCTION is_nan
159!~ !=======================================================================
160
161!~ !=======================================================================
162!~ FUNCTION is_normal(var) RESULT(flag)
163!~ !-----------------------------------------------------------------------
164!~ ! NAME
165!~ !     is_normal
166!~ !
167!~ ! DESCRIPTION
168!~ !     Returns whether array values is normal.
169!~ !
170!~ ! AUTHORS & DATE
171!~ !     JB Clement, 01/2026
172!~ !
173!~ ! NOTES
174!~ !     A normal value is finite, non-zero and not subnormal/denormal (very
175!~ !     small finite number with reduced precision).
176!~ !-----------------------------------------------------------------------
177
178!~ ! DECLARATION
179!~ ! -----------
180!~ implicit none
181
182!~ ! ARGUMENTS
183!~ ! ---------
184!~ real(dp), dimension(..), intent(in)  :: var
185
186!~ ! LOCAL VARIABLES
187!~ ! ---------------
188!~ logical(k4) :: flag
189
190!~ ! CODE
191!~ ! ----
192!~ flag = .false.
193!~ if (all(ieee_is_normal(var))) flag = .true.
194
195!~ END FUNCTION is_normal
196!~ !=======================================================================
197
198END MODULE numerics
199
Note: See TracBrowser for help on using the repository browser.