TreeMig Code
Loading...
Searching...
No Matches
DrawFromDistri.f90
Go to the documentation of this file.
1!==============================================================================
2!
3! Name : DrawFromDistri
4!
5! Purpose: draws random value from binomial, poisson or normal distribution
6!
7! Remarks: contains the SUBROUTINEs
8!
9! DrawFromDistri (<SeedsDispFromThisCellAndSpec<SeedsDispersedFromThisCell<
10! LocalDynOneTimeStep<SpatialDynOneTimeStep<TimeLoop<TreeMig)
11!
12! DrawFromPoissonDist } (<GetVariate<GetBioclim<GetEnvFactors<
13! DrawFromBinomDist } SpatialDynOneTimeStep<TimeLoop<TreeMig AND/OR
14! DrawFromNormalDist } DrawFromDistri<SeedsDispFromThisCellAndSpec<
15! SeedsDispersedFromThisCell<LocalDynOneTimeStep<
16! SpatialDynOneTimeStep<TimeLoop<TreeMig)
17!
18!==============================================================================
19! design : H. Lischke, N. Zimmermann
20! author(s) : H. Lischke, N. Zimmermann
21! implementation : H. Lischke, N. Zimmermann
22! cleaner : T.J. Loeffler
23! copyright : (c) 1999, 03 by H. Lischke
24!==============================================================================
25
26!=====================================================================
49!===============================================================
50SUBROUTINE drawfromdistri(n, p, ix)
51
52 ! <CALL modules for TYPE definitions and +- fixed variables>---------------------------------------------------------------
53 IMPLICIT NONE
54
55 ! <Passed variables>--------------------------------------------------------------------------------
56 INTEGER, INTENT(in) :: n ! parameter
57 REAL, INTENT(in) :: p ! parameter
58 INTEGER, INTENT(out) :: ix ! drawn value
59
60 ! <Local variables>---------------------------------------------------------------------------------
61 REAL :: randomvalue, & ! [0,1] random value
62 startdist, mu, sigma, rx
63
64 ! <Here the SUBROUTINE starts>**********************************************************************
65 if (p .ge. 1.0) then
66 ix = n
67 return
68 end if
69 if ((p <= 0.0) .or. (n <= 0)) then
70 ix = 0.0
71 return
72 end if
73
74 call random_number(randomvalue)
75 startdist = (1.0 - p)**n
76 if ((startdist == 0.0) .or. (startdist == 1.0) .or. (n .gt. 50)) then
77 ! for n->infinity, the binomial distribution is approximated by a poisson or normal distribution
78 mu = p*n
79 if (mu < 20) then ! for small p, the Binomial Distribution is approximated by a Poisson distribution
80 call drawfrompoissondist(mu, ix, randomvalue)
81 else ! otherwise by a normal distribution
82 sigma = sqrt(mu)
83 call drawfromnormaldist(mu, sigma, rx, randomvalue)
84 ix = rx
85 end if
86 else
87 call drawfrombinomdist(n, p, ix, randomvalue)
88 end if
89end SUBROUTINE drawfromdistri
90
91! -------------------------------------------------------------------------------------------------
92!=====================================================================
109!===============================================================
110SUBROUTINE drawfrompoissondist(mu, x, randomvalue)
111
112 ! <CALL modules for TYPE definitions and +- fixed variables>---------------------------------------------------------------
113 IMPLICIT NONE
114
115 ! <Passed variables>--------------------------------------------------------------------------------
116 REAL, INTENT(in) :: mu, & ! parameter [=..]
117 randomvalue ! [0,1] random value [=..]
118 INTEGER, INTENT(out) :: x
119
120 ! <Local variables>---------------------------------------------------------------------------------
121 double precision :: distrival, distrisum, ri, fak, mud
122 INTEGER :: i
123
124 ! <Here the SUBROUTINE starts>**********************************************************************
125 x = 0
126 mud = mu
127 distrival = exp(-mud)
128 distrisum = distrival
129
130 do i = 1, 10000
131 ri = i
132 if ((distrisum .ge. randomvalue) .or. (distrisum .ge. 1.0)) exit
133 fak = mu/ri
134 distrival = distrival*fak
135 distrisum = distrisum + distrival
136 end do
137
138 x = ri - 1
139end SUBROUTINE drawfrompoissondist
140! ****<Here the SUBROUTINE ends>*******************************************************************
141
142!=====================================================================
159!===============================================================
160SUBROUTINE drawfrombinomdist(n, p, x, randomvalue)
161
162 ! <CALL modules for TYPE definitions and +- fixed variables>---------------------------------------------------------------
163 IMPLICIT NONE
164
165 ! <Passed variables>--------------------------------------------------------------------------------
166 INTEGER, INTENT(in) :: n ! number of species
167 REAL, INTENT(in) :: p, & ! probability [=..]
168 randomvalue ! [0,1] random value [=..]
169 INTEGER, INTENT(out) :: x
170
171 ! <Local variables>---------------------------------------------------------------------------------
172 INTEGER :: i
173 REAL :: pTq
174 double precision :: distrival, distrisum, rn, ri, fak, fak1, fak2
175
176 ! <Here the SUBROUTINE starts>**********************************************************************
177 x = 0
178 distrival = (1.0 - p)**n
179 distrisum = distrival
180 rn = n
181 ptq = p/(1.0 - p)
182 do i = 1, n
183 if (distrisum .ge. randomvalue) exit
184 ri = i
185 fak1 = (rn - ri + 1.0)
186 fak2 = fak1/ri ! this gives a product, from which the binomial coefficient n!/(i!(n-i)!) can be calculated, with (n-i+1)! = n! / (n-i)!
187 fak = ptq * fak2 ! by multiplying the product over all pTq, i.e. pTq**i with the first distrival, i.e. (1.0 - p)**n, gives the second part of the binomial distribution density
188 distrival = distrival*fak
189 distrisum = distrisum + distrival
190 x = i ! this is the sampled value
191 end do
192end SUBROUTINE drawfrombinomdist
193!****<Here the SUBROUTINE ends>********************************************************************
194
195!=====================================================================
213!===============================================================
214SUBROUTINE drawfromnormaldist(mu, s, rx, randomvalue)
215
216 ! <CALL modules for TYPE definitions and +- fixed variables>---------------------------------------------------------------
217 IMPLICIT NONE
218
219 ! <Passed variables>--------------------------------------------------------------------------------
220 REAL, INTENT(in) :: mu, & ! mean [=..]
221 s, & ! standard deviation [=..]
222 randomvalue ! [0,1] random value [=..]
223 REAL, INTENT(out) :: rx ! REAL output value [=..]
224
225 ! <Local variables>---------------------------------------------------------------------------------
226 INTEGER :: i, index, istart
227 REAL :: xtransf, &
228 v1, f1, &
229 v2, f2, &
230 nd(0:201) ! [=NormDistFuncArr(index)]
231
232 ! <Here the SUBROUTINE starts>*********************************************************************
233 ! <First, initialize the Standard Normal Distribution (mu=0, sigma=1) array nd(..), in the range of -5 to +5 >------------
234 ! it has 202 (0:201) elements, element 100 corresponds to the median and mean, namely 0. 0 and 201 correspond to -5, 5 respectively.
235 nd = (/0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0000106885, 0.0000133457, &
236 0.0000166238, 0.0000206575, 0.0000256088, 0.0000316712, 0.0000390756, 0.0000480963, 0.0000590589, &
237 0.000072348, 0.0000884173, 0.0001078, 0.00013112, 0.000159109, 0.000192616, 0.000232629, &
238 0.000280293, 0.000336929, 0.000404058, 0.000483424, 0.000577025, 0.000687138, 0.000816352, &
239 0.000967603, 0.00114421, 0.0013499, 0.00158887, 0.00186581, 0.00218596, 0.00255513, 0.00297976, &
240 0.00346697, 0.00402459, 0.00466119, 0.00538615, 0.00620967, 0.00714281, 0.00819754, 0.00938671, &
241 0.0107241, 0.0122245, 0.0139034, 0.0157776, 0.0178644, 0.0201822, 0.0227501, 0.0255881, 0.0287166, &
242 0.0321568, 0.0359303, 0.0400592, 0.0445655, 0.0494715, 0.0547993, 0.0605708, 0.0668072, 0.0735293, &
243 0.0807567, 0.088508, 0.0968005, 0.10565, 0.11507, 0.125072, 0.135666, 0.146859, 0.158655, 0.171056, &
244 0.18406, 0.197663, 0.211855, 0.226627, 0.241964, 0.257846, 0.274253, 0.29116, 0.308538, 0.326355, &
245 0.344578, 0.363169, 0.382089, 0.401294, 0.42074, 0.440382, 0.460172, 0.480061, 0.5, 0.519939, &
246 0.539828, 0.559618, 0.57926, 0.598706, 0.617911, 0.636831, 0.655422, 0.673645, 0.691462, 0.70884, &
247 0.725747, 0.742154, 0.758036, 0.773373, 0.788145, 0.802337, 0.81594, 0.828944, 0.841345, 0.853141, &
248 0.864334, 0.874928, 0.88493, 0.89435, 0.9032, 0.911492, 0.919243, 0.926471, 0.933193, 0.939429, &
249 0.945201, 0.950529, 0.955435, 0.959941, 0.96407, 0.967843, 0.971283, 0.974412, 0.97725, 0.979818, &
250 0.982136, 0.984222, 0.986097, 0.987776, 0.989276, 0.990613, 0.991802, 0.992857, 0.99379, 0.994614, &
251 0.995339, 0.995975, 0.996533, 0.99702, 0.997445, 0.997814, 0.998134, 0.998411, 0.99865, 0.998856, &
252 0.999032, 0.999184, 0.999313, 0.999423, 0.999517, 0.999596, 0.999663, 0.99972, 0.999767, 0.999807, &
253 0.999841, 0.999869, 0.999892, 0.999912, 0.999928, 0.999941, 0.999952, 0.999961, 0.999968, 0.999974, &
254 0.999979, 0.999983, 0.999987, 0.999989, 0.999991, 0.999993, 0.999995, 0.999996, 0.999997, 0.999997, &
255 0.999998, 0.999998, 0.999999, 0.999999, 0.999999, 0.999999, 1.0, 1.0, 1.0, 1.0/)
256 rx = 0
257 ! if random value == 0 then a value at the very left tail of the distribution is chosen
258 if (randomvalue == 0.0) then
259 rx = -5.0 * s + mu
260 return
261 end if
262 ! 0.5 is the median of the distribution. therefore for smaller random values the first half, for larger random values the second half of the array can be searched
263 if (randomvalue .gt. 0.5) then
264 istart = 100
265 else
266 istart = 0
267 end if
268 ! search in the table where the random value belongs to
269 do i = istart, istart + 101
270 if (nd(i) .ge. randomvalue) then
271 index = i
272 exit
273 end if
274 end do
275 ! interpolate
276 f1 = nd(index - 1)
277 f2 = nd(index)
278 ! transform the indices from 1 to 200 to (0,1) normal distribution.
279 v1 = (index - 1)/20.0 - 5.0
280 v2 = (index) /20.0 - 5.0
281 xtransf = v1 + (v2 - v1)*(randomvalue - f1)/(f1 - f2)
282 ! transform the (0,1) normal distribution to the (mu,sigma) normal distribution
283 rx = xtransf*s + mu
284
285end SUBROUTINE drawfromnormaldist
286!done
subroutine drawfromdistri(n, p, ix)
DrawFromDistri
subroutine drawfromnormaldist(mu, s, rx, randomvalue)
DrawFromNormalDist
subroutine drawfrompoissondist(mu, x, randomvalue)
DrawFromPoissonDist
subroutine drawfrombinomdist(n, p, x, randomvalue)
DrawFromBinomDist