ROMS
Loading...
Searching...
No Matches
get_hash.F
Go to the documentation of this file.
1#include "cppdefs.h"
2#undef ADLER32_CHECKSUM
3#undef CRC32_CHECKSUM
4
6!
7!git $Id$
8!================================================== Hernan G. Arango ===
9! Copyright (c) 2002-2025 The ROMS Group !
10! Licensed under a MIT/X style license !
11! See License_ROMS.md !
12!=======================================================================
13! !
14! This module includes several routines to compute the "checksum" of !
15! a floating-point array using one of the following methods: !
16! !
17#ifdef ADLER32_CHECKSUM
18! adler32 Fortran, 32-bit Adler algorithm !
19#endif
20! bitsum Simple bit-by-bit order-invariant sum algorithm !
21#ifdef CRC32_CHECKSUM
22! crc32 Fortran, 32-bit Cyclic Redundancy Check algorithm !
23#endif
24! !
25! The available methods compute the "checksum" from characters and !
26! integers. For floating-point data, its values are interpreted as !
27! unsigned bytes. Here, we have the problem that Fortran does not !
28! support unsigned integers. Therefore, the intrinsic function !
29! TRANSFER is used to convert for 32-bit reals to 32-bit integers. !
30! !
31! The "checksum" value can be used during debugging to compare !
32! input data solutions from different versions of ROMS when !
33! implementing new algorithms. It is only available for reading !
34! and writting data in input/output NetCDF files. !
35! !
36! The function "bitsum" is the default method in ROMS since it !
37! allows tiled I/O data when the PIO library is used. Notice that !
38! reduction communications are not required with the standard NetCDF !
39! library since all the data is processed by the master. !
40! !
41!=======================================================================
42!
43 USE mod_kinds
44!
45#if defined DISTRIBUTE && (defined JEDI || defined PIO_LIB)
46 USE distribute_mod, ONLY : mp_reduce
47#endif
49 USE mod_iounits, ONLY : stdout
50 USE strings_mod, ONLY : uppercase
51!
52 implicit none
53!
54 PUBLIC :: get_hash
55#ifdef ADLER32_CHECKSUM
56 PRIVATE :: adler32
57#endif
58 PRIVATE :: bitsum
59#ifdef CRC32_CHECKSUM
60 PRIVATE :: crc32
61 PRIVATE :: crc32_ini
62!
63! Declare module internal parameters.
64!
65 integer(i8b) :: crc32_table(0:255)
66#endif
67!
68 CONTAINS
69!
70!***********************************************************************
71 SUBROUTINE get_hash (A, Asize, hash, Lreduce)
72!***********************************************************************
73!
74!
75! Imported variable declarations.
76!
77 logical, intent(in), optional :: lreduce
78!
79 integer, intent(in) :: asize
80 integer(i8b), intent(out) :: hash
81!
82 real(r8), intent(in) :: a(:)
83!
84! Local variable declarations.
85!
86 logical, save :: first = .true.
87!
88!-----------------------------------------------------------------------
89! Compute checksum for the requested floating point vector.
90!-----------------------------------------------------------------------
91!
92 hash=0_i8b
93!
94 SELECT CASE (uppercase(trim(hashmethod)))
95#ifdef ADLER32_CHECKSUM
96 CASE ('ADLER32')
97 CALL adler32 (a, asize, hash)
98#endif
99 CASE ('BITSUM')
100 CALL bitsum (a, asize, hash, lreduce)
101#ifdef CRC32_CHECKSUM
102 CASE ('CRC32')
103 IF (first) THEN
104 first=.false.
105 CALL crc32_ini ! compute CRC-32 look table
106 END IF
107 CALL crc32 (a, asize, hash)
108#endif
109 CASE DEFAULT
110 WRITE (stdout,10) trim(hashmethod)
111 exit_flag=5
112 END SELECT
113!
114 10 FORMAT (/,' GET_HASH - Illegal checksum method: ',a)
115!
116 RETURN
117 END SUBROUTINE get_hash
118
119#ifdef ADLER32_CHECKSUM
120!
121!***********************************************************************
122 SUBROUTINE adler32 (A, Asize, hash)
123!***********************************************************************
124! !
125! Computes the checksum of a 1D array using the 32-bit algorithm from !
126! Mark Adler (Adler-32). !
127! !
128!***********************************************************************
129!
130! Imported variable declarations.
131!
132 integer, intent(in) :: asize
133
134 integer(i8b) :: hash
135!
136 real(r8), intent(in) :: a(:)
137!
138! Local variable declarations.
139!
140 integer :: alpha, beta, i, j
141!
142 integer(i8b), parameter :: mod_adler = 65521_i8b
143
144 integer(i8b), allocatable :: awrk(:)
145!
146!-----------------------------------------------------------------------
147! Compute ADLER-32 checksum.
148!-----------------------------------------------------------------------
149!
150 alpha=1_i8b
151 beta=0_i8b
152!
153! Awrk will be an integer array sufficient to hold A(i).
154!
155 DO i=1,asize
156 awrk=transfer(a(i), [0])
157 DO j=1,SIZE(awrk)
158 alpha=mod(alpha+awrk(j), mod_adler)
159 beta=mod(beta+alpha, mod_adler)
160 END DO
161 END DO
162 hash=ior(beta*65536_i8b, alpha)
163!
164 RETURN
165 END SUBROUTINE adler32
166#endif
167!
168!***********************************************************************
169 SUBROUTINE bitsum (A, Asize, hash, Lreduce)
170!***********************************************************************
171! !
172! Computes the checksum of a 1D floating-point by casting each value !
173! to an integer to faciliate the invariant order of the sum in tiled !
174! parallel applications. A real number can be represented with a set !
175! 64-bit integers (Hallberg and Adcroft, 2014). !
176! !
177! Reference: !
178! !
179! Hallberg, R. and A. Adcroft, 2014: An order-invariant real-to- !
180! integer conversion sum, Parallel Computing, 40, 140-143, !
181! doi:10.1016/j.parco.2014.04.007. !
182! !
183!***********************************************************************
184!
185! Imported variable declarations.
186!
187 logical, intent(in), optional :: lreduce
188!
189 integer, intent(in) :: asize
190
191 integer(i8b) :: hash
192!
193 real(r8), intent(in) :: a(:)
194!
195! Local variable declarations.
196!
197 integer, parameter :: ak = kind(a)
198 integer :: i, j
199!
200 integer(i8b) :: ac, asum
201#if defined DISTRIBUTE && (defined JEDI || defined PIO_LIB)
202 integer(i8b) :: ibuffer(1)
203!
204 character (len=3) :: op_handle(1)
205#endif
206!
207!-----------------------------------------------------------------------
208! Compute checksum by counting bit-by-bit and summing.
209!-----------------------------------------------------------------------
210!
211! Here, the "POPCNT" function counts the number of set bits in a
212! machine instruction. For example, for two 8-bit words operated
213! with XOR, we get
214!
215! 00100110
216! 01100000
217! ----------
218! 01000110
219!
220! POPCNT(01000110) = 3 'counts the number of bits set to 1'
221!
222! The POPCNT is available in all modern Fortran compilers and CPU
223! architectures.
224!
225 asum=0_i8b
226 DO i=1,asize
227 ac=popcnt(transfer(abs(a(i)), 1_ak))
228 asum=asum+ac
229 END DO
230 hash=asum
231
232#if defined DISTRIBUTE && (defined JEDI || defined PIO_LIB)
233!
234! If PIO library data processing, sum across all processes. Recall that
235! one or several PETs are reading and or writing data, so we need a
236! global reduction of the checksum, which is order invariant for parallel
237! tiles. The integer arithmetic has no truncation errors. Notice that
238! such reduction is not required in I/0 processed by the master node
239! and Lreduce=.FALSE in such cases.
240!
241 IF (PRESENT(lreduce)) THEN
242 IF (lreduce) THEN
243 ibuffer(1)=asum
244 op_handle(1)='SUM'
245 CALL mp_reduce (1, 1, 1, ibuffer, op_handle)
246 hash=ibuffer(1)
247 END IF
248 END IF
249#endif
250!
251 RETURN
252 END SUBROUTINE bitsum
253
254#ifdef CRC32_CHECKSUM
255!
256!***********************************************************************
257 SUBROUTINE crc32 (A, Asize, hash)
258!***********************************************************************
259! !
260! Computes the checksum of a 1D array using the 32-bits (8 bytes) !
261! cyclic redundancy check (CRC-32) algorithm. !
262! !
263!***********************************************************************
264!
265! Imported variable declarations.
266!
267 integer, intent(in) :: asize
268 integer(i8b), intent(inout) :: hash
269!
270 real(r8), intent(in) :: a(:)
271!
272! Local variable declarations.
273!
274 integer :: i
275 integer(i8b) :: ai
276!
277!-----------------------------------------------------------------------
278! Compute CRC-32 checksum.
279!-----------------------------------------------------------------------
280!
281 hash=not(hash)
282 DO i=1,asize
283 ai=transfer(a(i), 1_i8b) ! 32-bit reals to 32-bit integers
284 hash=ieor(shiftr(hash, 8_i8b), &
285 & crc32_table(iand(ieor(hash, ai), 255_i8b)))
286 END DO
287 hash=not(hash)
288!
289 RETURN
290 END SUBROUTINE crc32
291!
292!***********************************************************************
293 SUBROUTINE crc32_ini
294!***********************************************************************
295!
296! Local variable declarations.
297!
298 integer :: i, j
299 integer(i8b) :: k
300!
301!-----------------------------------------------------------------------
302! Compute CRC-32 look table.
303!-----------------------------------------------------------------------
304!
305 DO i=0,255
306 k=i
307 DO j=1,8
308 IF (btest(k, 0)) THEN
309 k=ieor(shiftr(k, 1), -306674912_i8b)
310 ELSE
311 k=shiftr(k, 1_i8b)
312 END IF
313 END DO
314 crc32_table(i)=k
315 END DO
316!
317 RETURN
318 END SUBROUTINE crc32_ini
319#endif
320!
321 END MODULE get_hash_mod
subroutine, private bitsum(a, asize, hash, lreduce)
Definition get_hash.F:170
subroutine, public get_hash(a, asize, hash, lreduce)
Definition get_hash.F:72
integer stdout
integer, parameter r8
Definition mod_kinds.F:28
character(len= *), parameter hashmethod
integer exit_flag
character(len(sinp)) function, public uppercase(sinp)
Definition strings.F:582