ROMS
Loading...
Searching...
No Matches
ran_state.F
Go to the documentation of this file.
1 MODULE ran_state
2!
3!git $Id$
4!================================================== Hernan G. Arango ===
5! Copyright (c) 2002-2025 The ROMS Group !
6! Licensed under a MIT/X style license !
7! See License_ROMS.md !
8!=======================================================================
9! !
10! This module supports the random number generation routines. It !
11! provides each generator with five vectors integers, for use as !
12! internal random state space. The first three integers (iran, !
13! jran, kran) are maintained as nonnegative values, while the !
14! last two (mran, nran) have 32-bit nonzero values. This module !
15! also includes support for initializing or reinitializing the !
16! state to a desired sequence number, hashing the initial values !
17! to randon values, and allocating and deallocateing of internal !
18! workspace. !
19! !
20! Adapted from Numerical Recepies. !
21! !
22! Press, W.H., S.A. Teukolsky, W.T. Vetterling, and B.P. Flannery, !
23! 1996: Numerical Recipes in Fortran 90, The Art of Parallel !
24! Scientific Computing, 2nd Edition, Cambridge Univ. Press. !
25! !
26!=======================================================================
27!
28 USE mod_kinds
29
30 implicit none
31
32 PUBLIC
33
34 integer(i8b), parameter :: hg = huge(1_i8b)
35 integer(i8b), parameter :: hgm = -hg
36 integer(i8b), parameter :: hgng = hgm - 1
37
38 integer(i8b), save :: lenran = 0
39 integer(i8b), save :: seq = 0
40 integer(i8b), save :: iran0
41 integer(i8b), save :: jran0
42 integer(i8b), save :: kran0
43 integer(i8b), save :: nran0
44 integer(i8b), save :: mran0
45 integer(i8b), save :: rans
46
47 integer(i8b), pointer, save :: iran(:)
48 integer(i8b), pointer, save :: jran(:)
49 integer(i8b), pointer, save :: kran(:)
50 integer(i8b), pointer, save :: nran(:)
51 integer(i8b), pointer, save :: mran(:)
52 integer(i8b), pointer, save :: ranv(:)
53
54 integer(i8b), pointer, save :: ranseeds(:,:)
55
56 real(r8), save :: amm
57!
58 INTERFACE ran_hash
59 MODULE PROCEDURE ran_hash_s, ran_hash_v
60 END INTERFACE
61!
62 CONTAINS
63
64 SUBROUTINE ran_init (length)
65!
66!=======================================================================
67! !
68! This routine initializes or reinitializes the random generator !
69! state space to vectors of size LENGTH. The saved variable SEQ !
70! is hashed (via a call to RAN_HASH) to create unique starting !
71! seeds, different for each vector component. !
72! !
73!=======================================================================
74!
75 USE nrutil, ONLY : arth, nrerror, reallocate
76!
77! Imported variable declarations.
78!
79 integer(i8b), intent(in) :: length
80!
81! Local variable declarations.
82!
83 integer(i8b) :: hgt, j, new, sz
84!
85!-----------------------------------------------------------------------
86! Initialize randon number generator vectors.
87!-----------------------------------------------------------------------
88!
89 IF (length.lt.lenran) RETURN
90 hgt=hg
91!
92! Check that kind value I8B is in fact a 32-bit integer with the usual
93! properties that we expect it to have (under negation and wrap-around
94! addition). If all these test are satisfied, then the routines that
95! use this module are portable, even though they go beyond F90 integer
96! model.
97!
98 IF (hg.ne.2147483647) &
99 & CALL nrerror ('RAN_INIT: arith assump 1 fails')
100 IF (hgng.ge.0) &
101 & CALL nrerror ('RAN_INIT: arith assump 2 fails')
102 IF ((hgt+1).ne.hgng) &
103 & CALL nrerror ('RAN_INIT: arith assump 3 fails')
104 IF (not(hg).ge.0) &
105 & CALL nrerror ('RAN_INIT: arith assump 4 fails')
106 IF (not(hgng).lt.0) &
107 & CALL nrerror ('RAN_INIT: arith assump 5 fails')
108 IF ((hg+hgng).ge.0) &
109 & CALL nrerror ('RAN_INIT: arith assump 6 fails')
110 IF (not(-1_i8b).lt.0) &
111 & CALL nrerror ('RAN_INIT: arith assump 7 fails')
112 IF (not(0_i8b).ge.0) &
113 & CALL nrerror ('RAN_INIT: arith assump 8 fails')
114 IF (not(1_i8b).ge.0) &
115 & CALL nrerror ('RAN_INIT: arith assump 9 fails')
116!
117! Reallocate or allocate state space.
118!
119 IF (lenran.gt.0) THEN
120 ranseeds => reallocate(ranseeds, length, 5_i8b)
121 ranv => reallocate(ranv, length-1_i8b)
122 new=lenran+1
123 ELSE
124 ALLOCATE (ranseeds(length,5))
125 ALLOCATE (ranv(length-1))
126 new=1
127 amm=nearest(1.0_r8,-1.0_r8)/hgng
128 IF ((amm*hgng.ge.1.0_r8).or.(amm*hgng.le.0.0_r8)) &
129 & CALL nrerror ('RAN_INIT: arth assump 10 fails')
130 END IF
131!
132! Set starting values, unique by SEQ and vector component.
133!
134 ranseeds(new:,1)=seq
135 sz=SIZE(ranseeds(new:,1))
136 ranseeds(new:,2:5)=spread(arth(new,1_i8b,sz),2,4)
137!
138! Hash them.
139!
140 DO j=1,4
141 CALL ran_hash (ranseeds(new:,j), ranseeds(new:,j+1))
142 END DO
143!
144! Enforce nonnegativity.
145!
146 WHERE (ranseeds(new:,1:3).lt.0) &
147 & ranseeds(new:,1:3)=not(ranseeds(new:,1:3))
148!
149! Enforce nonzero.
150!
151 WHERE (ranseeds(new:,4:5).eq.0) &
152 & ranseeds(new:,4:5)=1
153!
154! Set scalar seeds.
155!
156 IF (new.eq.1) THEN
157 iran0=ranseeds(1,1)
158 jran0=ranseeds(1,2)
159 kran0=ranseeds(1,3)
160 mran0=ranseeds(1,4)
161 nran0=ranseeds(1,5)
162 rans=nran0
163 END IF
164!
165! Point to vector seeds.
166!
167 IF (length.gt.1) THEN
168 iran => ranseeds(2:,1)
169 jran => ranseeds(2:,2)
170 kran => ranseeds(2:,3)
171 mran => ranseeds(2:,4)
172 nran => ranseeds(2:,5)
173 ranv = nran
174 END IF
175 lenran=length
176
177 END SUBROUTINE ran_init
178
179 SUBROUTINE ran_deallocate
180!
181!=======================================================================
182! !
183! User interface to release the workspace used by random number !
184! routines. !
185! !
186!=======================================================================
187!
188 IF (lenran.gt.0) THEN
189 DEALLOCATE (ranseeds, ranv)
190 NULLIFY (ranseeds, ranv, iran, jran, kran, mran, nran)
191 lenran=0
192 END IF
193 END SUBROUTINE ran_deallocate
194
195 SUBROUTINE ran_seed (sequence, size, put, get)
196!
197!=======================================================================
198! !
199! User interface for seeding the random number routines. Syntax is !
200! exactly like Fortran 90 RANDOM_SEED, with one additional argument !
201! keyword: SEQUENCE, set to any integer value, causes an immediate !
202! new initialization, seeded by that integer. !
203! !
204!=======================================================================
205!
206! Imported variable declarations.
207!
208 integer, optional, intent(in) :: sequence
209 integer, optional, intent(out) :: size
210
211 integer, optional, intent(in) :: put(:)
212 integer, optional, intent(out) :: get(:)
213!
214!-----------------------------------------------------------------------
215! Set random number seeds.
216!-----------------------------------------------------------------------
217!
218 IF (PRESENT(size)) THEN
219 size=5*lenran
220 ELSE IF (PRESENT(put)) THEN
221 IF (lenran.eq.0) RETURN
222 ranseeds=reshape(put,shape(ranseeds))
223 WHERE (ranseeds(:,1:3).lt.0) &
224 & ranseeds(:,1:3)=not(ranseeds(:,1:3))
225 WHERE (ranseeds(:,4:5).eq.0) &
226 & ranseeds(:,4:5)=1
227 iran0=ranseeds(1,1)
228 jran0=ranseeds(1,2)
229 kran0=ranseeds(1,3)
230 mran0=ranseeds(1,4)
231 nran0=ranseeds(1,5)
232 ELSE IF (present(get)) THEN
233 IF (lenran.eq.0) RETURN
234 ranseeds(1,1:5)=(/ iran0,jran0,kran0,mran0,nran0 /)
235 get=reshape(ranseeds,shape(get))
236 ELSE IF (PRESENT(sequence)) THEN
237 CALL ran_deallocate
238 seq=sequence
239 END IF
240
241 RETURN
242 END SUBROUTINE ran_seed
243
244 SUBROUTINE ran_hash_s (il, ir)
245!
246!=======================================================================
247! !
248! DES-like hashing of 32-bit integer, using shifts, xor, and adds to !
249! make the interval nonlinear function. Scalar version. !
250! !
251!=======================================================================
252!
253! Imported variable declarations.
254!
255 integer(i8b), intent(inout) :: il, ir
256!
257! Local variable declarations.
258!
259 integer(i8b) :: is, j
260!
261!-----------------------------------------------------------------------
262! Bit mixing. The various constants should not be changed.
263!-----------------------------------------------------------------------
264!
265 DO j=1,4
266 is=ir
267 ir=ieor(ir,ishft(ir,5))+1422217823
268 ir=ieor(ir,ishft(ir,-16))+1842055030
269 ir=ieor(ir,ishft(ir,9))+80567781
270 ir=ieor(il,ir)
271 il=is
272 END DO
273
274 RETURN
275 END SUBROUTINE ran_hash_s
276
277 SUBROUTINE ran_hash_v (il, ir)
278!
279!=======================================================================
280! !
281! DES-like hashing of 32-bit integer, using shifts, xor, and adds to !
282! make the interval nonlinear function. Vector version. !
283! !
284!=======================================================================
285!
286! Imported variable declarations.
287!
288 integer(i8b), intent(inout) :: il(:)
289 integer(i8b), intent(inout) :: ir(:)
290!
291! Local variable declarations.
292!
293 integer(i8b) :: j
294 integer(i8b), dimension(SIZE(il)) :: is
295!
296!-----------------------------------------------------------------------
297! Bit mixing. The various constants should not be changed.
298!-----------------------------------------------------------------------
299!
300 DO j=1,4
301 is=ir
302 ir=ieor(ir,ishft(ir,5))+1422217823
303 ir=ieor(ir,ishft(ir,-16))+1842055030
304 ir=ieor(ir,ishft(ir,9))+80567781
305 ir=ieor(il,ir)
306 il=is
307 END DO
308
309 RETURN
310 END SUBROUTINE ran_hash_v
311
312 END MODULE ran_state
313
integer, parameter r8
Definition mod_kinds.F:28
Definition nrutil.F:1
subroutine nrerror(string)
Definition nrutil.F:292
integer(i8b), save seq
Definition ran_state.F:39
subroutine ran_init(length)
Definition ran_state.F:65
integer(i8b), dimension(:), pointer, save jran
Definition ran_state.F:48
subroutine ran_seed(sequence, size, put, get)
Definition ran_state.F:196
integer(i8b), dimension(:), pointer, save kran
Definition ran_state.F:49
integer(i8b), dimension(:), pointer, save ranv
Definition ran_state.F:52
integer(i8b), parameter hgng
Definition ran_state.F:36
integer(i8b), save lenran
Definition ran_state.F:38
integer(i8b), dimension(:), pointer, save iran
Definition ran_state.F:47
integer(i8b), dimension(:), pointer, save mran
Definition ran_state.F:51
integer(i8b), parameter hgm
Definition ran_state.F:35
integer(i8b), dimension(:,:), pointer, save ranseeds
Definition ran_state.F:54
integer(i8b), dimension(:), pointer, save nran
Definition ran_state.F:50
real(r8), save amm
Definition ran_state.F:56
integer(i8b), save kran0
Definition ran_state.F:42
integer(i8b), save jran0
Definition ran_state.F:41
subroutine ran_deallocate
Definition ran_state.F:180
subroutine ran_hash_s(il, ir)
Definition ran_state.F:245
integer(i8b), save mran0
Definition ran_state.F:44
integer(i8b), save nran0
Definition ran_state.F:43
integer(i8b), parameter hg
Definition ran_state.F:34
integer(i8b), save iran0
Definition ran_state.F:40
integer(i8b), save rans
Definition ran_state.F:45
subroutine ran_hash_v(il, ir)
Definition ran_state.F:278