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

Last change on this file since 4076 was 4076, checked in by jbclement, 8 days ago

PEM:
Fallback for 128-bit integers since this type is not supported by Intel Fortran.
JBC

File size: 6.3 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 :: tol = 100._wp*minieps
77
78! Minimum number of significant decimal digits
79integer, parameter :: prec_sp = precision(1._sp)
80integer, parameter :: prec_dp = precision(1._dp)
81integer, parameter :: prec_qp = precision(1._qp)
82integer, parameter :: prec = precision(1._wp)
83
84!~ contains
85!~ !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
86
87!~ !=======================================================================
88!~ FUNCTION is_finite(var) RESULT(flag)
89!~ !-----------------------------------------------------------------------
90!~ ! NAME
91!~ !     is_finite
92!~ !
93!~ ! DESCRIPTION
94!~ !     Returns whether array values are finite.
95!~ !
96!~ ! AUTHORS & DATE
97!~ !     JB Clement, 01/2026
98!~ !
99!~ ! NOTES
100!~ !     Finite values are neither NaN nor Infinite.
101!~ !-----------------------------------------------------------------------
102
103!~ ! DECLARATION
104!~ ! -----------
105!~ implicit none
106
107!~ ! ARGUMENTS
108!~ ! ---------
109!~ real(dp), dimension(..), intent(in)  :: var
110
111!~ ! LOCAL VARIABLES
112!~ ! ---------------
113!~ logical(k4) :: flag
114
115!~ ! CODE
116!~ ! ----
117!~ flag = .false.
118!~ if (all(ieee_is_finite(var))) flag = .true.
119
120!~ END FUNCTION is_finite
121!~ !=======================================================================
122
123!~ !=======================================================================
124!~ FUNCTION is_nan(var) RESULT(flag)
125!~ !-----------------------------------------------------------------------
126!~ ! NAME
127!~ !     is_nan
128!~ !
129!~ ! DESCRIPTION
130!~ !     Returns whether array values has a Not-a-Number (NaN).
131!~ !
132!~ ! AUTHORS & DATE
133!~ !     JB Clement, 01/2026
134!~ !
135!~ ! NOTES
136!~ !
137!~ !-----------------------------------------------------------------------
138
139!~ ! DECLARATION
140!~ ! -----------
141!~ implicit none
142
143!~ ! ARGUMENTS
144!~ ! ---------
145!~ real(dp), dimension(..), intent(in)  :: var
146
147!~ ! LOCAL VARIABLES
148!~ ! ---------------
149!~ logical(k4) :: flag
150
151!~ ! CODE
152!~ ! ----
153!~ flag = .false.
154!~ if (any(ieee_is_nan(var))) flag = .true.
155
156!~ END FUNCTION is_nan
157!~ !=======================================================================
158
159!~ !=======================================================================
160!~ FUNCTION is_normal(var) RESULT(flag)
161!~ !-----------------------------------------------------------------------
162!~ ! NAME
163!~ !     is_normal
164!~ !
165!~ ! DESCRIPTION
166!~ !     Returns whether array values is normal.
167!~ !
168!~ ! AUTHORS & DATE
169!~ !     JB Clement, 01/2026
170!~ !
171!~ ! NOTES
172!~ !     A normal value is finite, non-zero and not subnormal/denormal (very
173!~ !     small finite number with reduced precision).
174!~ !-----------------------------------------------------------------------
175
176!~ ! DECLARATION
177!~ ! -----------
178!~ implicit none
179
180!~ ! ARGUMENTS
181!~ ! ---------
182!~ real(dp), dimension(..), intent(in)  :: var
183
184!~ ! LOCAL VARIABLES
185!~ ! ---------------
186!~ logical(k4) :: flag
187
188!~ ! CODE
189!~ ! ----
190!~ flag = .false.
191!~ if (all(ieee_is_normal(var))) flag = .true.
192
193!~ END FUNCTION is_normal
194!~ !=======================================================================
195
196END MODULE numerics
197
Note: See TracBrowser for help on using the repository browser.