CCPP SciDoc v7.0.0  v7.0.0
Common Community Physics Package Developed at DTC
 
Loading...
Searching...
No Matches
mersenne_twister.f
1
4
5! Module: mersenne_twister Modern random number generator
6!\author Iredell Org: W/NX23 date: 2005-06-14
25!
26! Program History Log:
27! 2005-06-14 Mark Iredell
28!
29! Usage:
30! The module can be compiled with 4-byte reals or with 8-byte reals, but
31! 4-byte integers are required. The module should be endian-independent.
32! The Fortran 90 interfaces random_seed and random_number are overloaded
33! and can be used as in the standard by adding the appropriate use statement
34! use mersenne_twister
35! In the below use cases, harvest is a real array of arbitrary size,
36! and iharvest is an integer array of arbitrary size.
37! To generate uniformly distributed random numbers between 0 and 1,
38! call random_number(harvest)
39! To generate Gaussian distributed random numbers with 0 mean and 1 sigma,
40! call random_gauss(harvest)
41! To generate uniformly distributed random integer indices between 0 and n,
42! call random_index(n,iharvest)
43! In standard "saved" mode, the random number generator can be used without
44! setting a seed. But to set a seed, only 1 non-zero integer is required, e.g.
45! call random_setseed(4357) ! set default seed
46! The full generator state can be set via the standard interface random_seed,
47! but it is recommended to use this method only to restore saved states, e.g.
48! call random_seed(size=lsave) ! get size of generator state seed array
49! allocate isave(lsave) ! allocate seed array
50! call random_seed(get=isave) ! fill seed array (then maybe save to disk)
51! call random_seed(put=isave) ! restore state (after read from disk maybe)
52! Locally kept generator states can also be saved in a seed array, e.g.
53! type(random_stat):: stat
54! call random_seed(get=isave,stat=stat) ! fill seed array
55! call random_seed(put=isave,stat=stat) ! restore state
56! To generate random numbers in a threaded region, the "thread-safe" mode
57! must be used where generator states of type random_state are passed, e.g.
58! type(random_stat):: stat(8)
59! do i=1,8 ! threadable loop
60! call random_setseed(7171*i,stat(i)) ! thread-safe call
61! enddo
62! do i=1,8 ! threadable loop
63! call random_number(harvest,stat(i)) ! thread-safe call
64! enddo
65! do i=1,8 ! threadable loop
66! call random_gauss(harvest,stat(i)) ! thread-safe call
67! enddo
68! do i=1,8 ! threadable loop
69! call random_index(n,iharvest,stat(i))! thread-safe call
70! enddo
71! There is also a relatively inefficient "interactive" mode available, where
72! setting seeds and generating random numbers are done in the same call.
73! There is also a functional mode available, returning one value at a time.
74!
75! Public Defined Types:
76! random_stat Generator state (private contents)
77!
78! Public Subprograms:
79! random_seed determine size or put or get state
80! size optional integer output size of seed array
81! put optional integer(:) input seed array
82! get optional integer(:) output seed array
83! stat optional type(random_stat) (thread-safe mode)
84! random_setseed set seed (thread-safe mode)
85! inseed integer seed input
86! stat type(random_stat) output
87! random_setseed set seed (saved mode)
88! inseed integer seed input
89! random_number get mersenne twister random numbers (thread-safe mode)
90! harvest real(:) numbers output
91! stat type(random_stat) input
92! random_number get mersenne twister random numbers (saved mode)
93! harvest real(:) numbers output
94! random_number get mersenne twister random numbers (interactive mode)
95! harvest real(:) numbers output
96! inseed integer seed input
97! random_number_f get mersenne twister random number (functional mode)
98! harvest real number output
99! random_gauss get gaussian random numbers (thread-safe mode)
100! harvest real(:) numbers output
101! stat type(random_stat) input
102! random_gauss get gaussian random numbers (saved mode)
103! harvest real(:) numbers output
104! random_gauss get gaussian random numbers (interactive mode)
105! harvest real(:) numbers output
106! inseed integer seed input
107! random_gauss_f get gaussian random number (functional mode)
108! harvest real number output
109! random_index get random indices (thread-safe mode)
110! imax integer maximum index input
111! iharvest integer(:) numbers output
112! stat type(random_stat) input
113! random_index get random indices (saved mode)
114! imax integer maximum index input
115! iharvest integer(:) numbers output
116! random_index get random indices (interactive mode)
117! imax integer maximum index input
118! iharvest integer(:) numbers output
119! inseed integer seed input
120! random_index_f get random index (functional mode)
121! imax integer maximum index input
122! iharvest integer number output
123!
124! Remarks:
125! (1) Here are the comments in the original open source code:
126! A C-program for MT19937: Real number version
127! genrand() generates one pseudorandom real number (double)
128! which is uniformly distributed on [0,1]-interval, for each
129! call. sgenrand(seed) set initial values to the working area
130! of 624 words. Before genrand(), sgenrand(seed) must be
131! called once. (seed is any 32-bit integer except for 0).
132! Integer generator is obtained by modifying two lines.
133! Coded by Takuji Nishimura, considering the suggestions by
134! Topher Cooper and Marc Rieffel in July-Aug. 1997.
135! This library is free software; you can redistribute it and/or
136! modify it under the terms of the GNU Library General Public
137! License as published by the Free Software Foundation; either
138! version 2 of the License, or (at your option) any later
139! version.
140! This library is distributed in the hope that it will be useful,
141! but WITHOUT ANY WARRANTY; without even the implied warranty of
142! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
143! See the GNU Library General Public License for more details.
144! You should have received a copy of the GNU Library General
145! Public License along with this library; if not, write to the
146! Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
147! 02111-1307 USA
148! Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura.
149! When you use this, send an email to: matumoto@math.keio.ac.jp
150! with an appropriate reference to your work.
151! Fortran translation by Hiroshi Takano. Jan. 13, 1999.
152!
153! (2) On a single IBM Power4 processor on the NCEP operational cluster (2005)
154! each Mersenne twister random number takes less than 30 ns, about 3 times
155! slower than the default random number generator, and each random number
156! from a Gaussian distribution takes less than 150 ns.
157!
158! Attributes:
159! Language: Fortran 90
160!
161!$$$
163 use machine, only: kind_dbl_prec
164 private
165! Public declarations
166 public random_stat
167 public random_seed
168 public random_setseed
169 public random_number
170 public random_number_f
171 public random_gauss
172 public random_gauss_f
173 public random_index
174 public random_index_f
175! Parameters
176 integer,parameter:: n=624
177 integer,parameter:: m=397
178 integer,parameter:: mata=-1727483681
179 integer,parameter:: umask=-2147483648
180 integer,parameter:: lmask =2147483647
181 integer,parameter:: tmaskb=-1658038656
182 integer,parameter:: tmaskc=-272236544
183 integer,parameter:: mag01(0:1)=(/0,mata/)
184 integer,parameter:: iseed=4357
185 integer,parameter:: nrest=n+6
186! Defined types
188 private
189 integer:: mti=n+1
190 integer:: mt(0:n-1)
191 integer:: iset
192 real(kind_dbl_prec):: gset
193 end type
194! Saved data
195 type(random_stat),save:: sstat
196! Overloaded interfaces
198 module procedure random_setseed_s
199 module procedure random_setseed_t
200 end interface
202 module procedure random_number_i
203 module procedure random_number_s
204 module procedure random_number_t
205 end interface
206 interface random_gauss
207 module procedure random_gauss_i
208 module procedure random_gauss_s
209 module procedure random_gauss_t
210 end interface
211 interface random_index
212 module procedure random_index_i
213 module procedure random_index_s
214 module procedure random_index_t
215 end interface
216! All the subprograms
217 contains
218! Subprogram random_seed
220 subroutine random_seed(size,put,get,stat)
221 implicit none
222 integer,intent(out),optional:: size
223 integer,intent(in),optional:: put(nrest)
224 integer,intent(out),optional:: get(nrest)
225 type(random_stat),intent(inout),optional:: stat
226 if(present(size)) then ! return size of seed array
227! if(present(put).or.present(get))&
228! call errmsg('RANDOM_SEED: more than one option set - some ignored')
229 size=nrest
230 elseif(present(put)) then ! restore from seed array
231! if(present(get))&
232! call errmsg('RANDOM_SEED: more than one option set - some ignored')
233 if(present(stat)) then
234 stat%mti=put(1)
235 stat%mt=put(2:n+1)
236 stat%iset=put(n+2)
237 stat%gset=transfer(put(n+3:nrest),stat%gset)
238 if(stat%mti.lt.0.or.stat%mti.gt.n.or.any(stat%mt.eq.0).or.
239 & stat%iset.lt.0.or.stat%iset.gt.1) then
240 call random_setseed_t(iseed,stat)
241! call errmsg('RANDOM_SEED: invalid seeds put - default seeds used')
242 endif
243 else
244 sstat%mti=put(1)
245 sstat%mt=put(2:n+1)
246 sstat%iset=put(n+2)
247 sstat%gset=transfer(put(n+3:nrest),sstat%gset)
248 if(sstat%mti.lt.0.or.sstat%mti.gt.n.or.any(sstat%mt.eq.0)
249 & .or.sstat%iset.lt.0.or.sstat%iset.gt.1) then
250 call random_setseed_t(iseed,sstat)
251! call errmsg('RANDOM_SEED: invalid seeds put - default seeds used')
252 endif
253 endif
254 elseif(present(get)) then ! save to seed array
255 if(present(stat)) then
256 if(stat%mti.eq.n+1) call random_setseed_t(iseed,stat)
257 get(1)=stat%mti
258 get(2:n+1)=stat%mt
259 get(n+2)=stat%iset
260 get(n+3:nrest)=transfer(stat%gset,get,nrest-(n+3)+1)
261 else
262 if(sstat%mti.eq.n+1) call random_setseed_t(iseed,sstat)
263 get(1)=sstat%mti
264 get(2:n+1)=sstat%mt
265 get(n+2)=sstat%iset
266 get(n+3:nrest)=transfer(sstat%gset,get,nrest-(n+3)+1)
267 endif
268 else ! reset default seed
269 if(present(stat)) then
270 call random_setseed_t(iseed,stat)
271 else
272 call random_setseed_t(iseed,sstat)
273 endif
274 endif
275 end subroutine
276! Subprogram random_setseed_s
278 subroutine random_setseed_s(inseed)
279 implicit none
280 integer,intent(in):: inseed
281 call random_setseed_t(inseed,sstat)
282 end subroutine
283! Subprogram random_setseed_t
285 subroutine random_setseed_t(inseed,stat)
286 implicit none
287 integer,intent(in):: inseed
288 type(random_stat),intent(out):: stat
289 integer ii,mti
290 ii=inseed
291 if(ii.eq.0) ii=iseed
292 stat%mti=n
293 stat%mt(0)=iand(ii,-1)
294 do mti=1,n-1
295 stat%mt(mti)=iand(69069*stat%mt(mti-1),-1)
296 enddo
297 stat%iset=0
298 stat%gset=0.
299 end subroutine
300! Subprogram random_number_f
302 function random_number_f() result(harvest)
303 implicit none
304 real(kind_dbl_prec):: harvest
305 real(kind_dbl_prec) :: h(1)
306 if(sstat%mti.eq.n+1) call random_setseed_t(iseed,sstat)
307 call random_number_t(h,sstat)
308 harvest=h(1)
309 end function
310! Subprogram random_number_i
312 subroutine random_number_i(harvest,inseed)
313 implicit none
314 real(kind_dbl_prec),intent(out):: harvest(:)
315 integer,intent(in):: inseed
316 type(random_stat) stat
317 call random_setseed_t(inseed,stat)
318 call random_number_t(harvest,stat)
319 end subroutine
320! Subprogram random_number_s
322 subroutine random_number_s(harvest)
323 implicit none
324 real(kind_dbl_prec),intent(out):: harvest(:)
325 if(sstat%mti.eq.n+1) call random_setseed_t(iseed,sstat)
326 call random_number_t(harvest,sstat)
327 end subroutine
328! Subprogram random_number_t
330 subroutine random_number_t(harvest,stat)
331 implicit none
332 real(kind_dbl_prec),intent(out):: harvest(:)
333 type(random_stat),intent(inout):: stat
334 integer j,kk,y
335 integer tshftu,tshfts,tshftt,tshftl
336 tshftu(y)=ishft(y,-11)
337 tshfts(y)=ishft(y,7)
338 tshftt(y)=ishft(y,15)
339 tshftl(y)=ishft(y,-18)
340 do j=1,size(harvest)
341 if(stat%mti.ge.n) then
342 do kk=0,n-m-1
343 y=ior(iand(stat%mt(kk),umask),iand(stat%mt(kk+1),lmask))
344 stat%mt(kk)=ieor(ieor(stat%mt(kk+m),ishft(y,-1)),
345 & mag01(iand(y,1)))
346 enddo
347 do kk=n-m,n-2
348 y=ior(iand(stat%mt(kk),umask),iand(stat%mt(kk+1),lmask))
349 stat%mt(kk)=ieor(ieor(stat%mt(kk+(m-n)),ishft(y,-1)),
350 & mag01(iand(y,1)))
351 enddo
352 y=ior(iand(stat%mt(n-1),umask),iand(stat%mt(0),lmask))
353 stat%mt(n-1)=ieor(ieor(stat%mt(m-1),ishft(y,-1)),
354 & mag01(iand(y,1)))
355 stat%mti=0
356 endif
357 y=stat%mt(stat%mti)
358 y=ieor(y,tshftu(y))
359 y=ieor(y,iand(tshfts(y),tmaskb))
360 y=ieor(y,iand(tshftt(y),tmaskc))
361 y=ieor(y,tshftl(y))
362 if(y.lt.0) then
363 harvest(j)=(real(y,kind=kind_dbl_prec)+ &
364 & 2.0_kind_dbl_prec**32)/ &
365 & (2.0_kind_dbl_prec**32-1.0_kind_dbl_prec)
366 else
367 harvest(j)=real(y)/(2.0_kind_dbl_prec**32- &
368 & 1.0_kind_dbl_prec)
369 endif
370 stat%mti=stat%mti+1
371 enddo
372 end subroutine
373! Subprogram random_gauss_f
375 function random_gauss_f() result(harvest)
376 implicit none
377 real(kind_dbl_prec):: harvest
378 real(kind_dbl_prec) :: h(1)
379 if(sstat%mti.eq.n+1) call random_setseed_t(iseed,sstat)
380 call random_gauss_t(h,sstat)
381 harvest=h(1)
382 end function
383! Subprogram random_gauss_i
385 subroutine random_gauss_i(harvest,inseed)
386 implicit none
387 real(kind_dbl_prec),intent(out):: harvest(:)
388 integer,intent(in):: inseed
389 type(random_stat) stat
390 call random_setseed_t(inseed,stat)
391 call random_gauss_t(harvest,stat)
392 end subroutine
393! Subprogram random_gauss_s
395 subroutine random_gauss_s(harvest)
396 implicit none
397 real(kind_dbl_prec),intent(out):: harvest(:)
398 if(sstat%mti.eq.n+1) call random_setseed_t(iseed,sstat)
399 call random_gauss_t(harvest,sstat)
400 end subroutine
401! Subprogram random_gauss_t
403 subroutine random_gauss_t(harvest,stat)
404 implicit none
405 real(kind_dbl_prec),intent(out):: harvest(:)
406 type(random_stat),intent(inout):: stat
407 integer mx,my,mz,j
408 real(kind_dbl_prec) :: r2(2),r,g1,g2
409 mz=size(harvest)
410 if(mz.le.0) return
411 mx=0
412 if(stat%iset.eq.1) then
413 mx=1
414 harvest(1)=stat%gset
415 stat%iset=0
416 endif
417 my=(mz-mx)/2*2+mx
418 do
419 call random_number_t(harvest(mx+1:my),stat)
420 do j=mx,my-2,2
421 call rgauss(harvest(j+1),harvest(j+2),r,g1,g2)
422 if(r.lt.1.) then
423 harvest(mx+1)=g1
424 harvest(mx+2)=g2
425 mx=mx+2
426 endif
427 enddo
428 if(mx.eq.my) exit
429 enddo
430 if(my.lt.mz) then
431 do
432 call random_number_t(r2,stat)
433 call rgauss(r2(1),r2(2),r,g1,g2)
434 if(r.lt.1.) exit
435 enddo
436 harvest(mz)=g1
437 stat%gset=g2
438 stat%iset=1
439 endif
440 contains
442 subroutine rgauss(r1,r2,r,g1,g2)
443 real(kind_dbl_prec),intent(in):: r1,r2
444 real(kind_dbl_prec),intent(out):: r,g1,g2
445 real(kind_dbl_prec) :: v1,v2,fac
446 v1=2._kind_dbl_prec*r1-1._kind_dbl_prec
447 v2=2._kind_dbl_prec*r2-1._kind_dbl_prec
448 r=v1**2+v2**2
449 if(r.lt.1.) then
450 fac=sqrt(-2._kind_dbl_prec*log(r)/r)
451 g1=v1*fac
452 g2=v2*fac
453 endif
454 end subroutine
455 end subroutine
456! Subprogram random_index_f
458 function random_index_f(imax) result(iharvest)
459 implicit none
460 integer,intent(in):: imax
461 integer:: iharvest
462 integer ih(1)
463 if(sstat%mti.eq.n+1) call random_setseed_t(iseed,sstat)
464 call random_index_t(imax,ih,sstat)
465 iharvest=ih(1)
466 end function
467! Subprogram random_index_i
469 subroutine random_index_i(imax,iharvest,inseed)
470 implicit none
471 integer,intent(in):: imax
472 integer,intent(out):: iharvest(:)
473 integer,intent(in):: inseed
474 type(random_stat) stat
475 call random_setseed_t(inseed,stat)
476 call random_index_t(imax,iharvest,stat)
477 end subroutine
478! Subprogram random_index_s
480 subroutine random_index_s(imax,iharvest)
481 implicit none
482 integer,intent(in):: imax
483 integer,intent(out):: iharvest(:)
484 if(sstat%mti.eq.n+1) call random_setseed_t(iseed,sstat)
485 call random_index_t(imax,iharvest,sstat)
486 end subroutine
487! Subprogram random_index_t
489 subroutine random_index_t(imax,iharvest,stat)
490 implicit none
491 integer,intent(in):: imax
492 integer,intent(out):: iharvest(:)
493 type(random_stat),intent(inout):: stat
494 integer,parameter:: mh=n
495 integer i1,i2,mz
496 real(kind_dbl_prec) :: h(mh)
497 mz=size(iharvest)
498 do i1=1,mz,mh
499 i2=min((i1-1)+mh,mz)
500 call random_number_t(h(:i2-(i1-1)),stat)
501 iharvest(i1:i2)=max(ceiling(h(:i2-(i1-1))*imax),1)
502 enddo
503 end subroutine
504 end module
This module calculates random numbers using the Mersenne twister.