geone 1.3.0__py313-none-manylinux_2_35_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geone/__init__.py +32 -0
- geone/_version.py +6 -0
- geone/blockdata.py +250 -0
- geone/covModel.py +15529 -0
- geone/customcolors.py +508 -0
- geone/deesse_core/__init__.py +5 -0
- geone/deesse_core/_deesse.so +0 -0
- geone/deesse_core/deesse.py +2450 -0
- geone/deesseinterface.py +11323 -0
- geone/geosclassic_core/__init__.py +5 -0
- geone/geosclassic_core/_geosclassic.so +0 -0
- geone/geosclassic_core/geosclassic.py +1429 -0
- geone/geosclassicinterface.py +20092 -0
- geone/grf.py +5927 -0
- geone/img.py +7152 -0
- geone/imgplot.py +1464 -0
- geone/imgplot3d.py +1918 -0
- geone/markovChain.py +666 -0
- geone/multiGaussian.py +388 -0
- geone/pgs.py +1258 -0
- geone/randProcess.py +1258 -0
- geone/srf.py +3661 -0
- geone/tools.py +861 -0
- geone-1.3.0.dist-info/METADATA +207 -0
- geone-1.3.0.dist-info/RECORD +28 -0
- geone-1.3.0.dist-info/WHEEL +5 -0
- geone-1.3.0.dist-info/licenses/LICENSE +58 -0
- geone-1.3.0.dist-info/top_level.txt +1 -0
geone/randProcess.py
ADDED
|
@@ -0,0 +1,1258 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# -------------------------------------------------------------------------
|
|
5
|
+
# Python module: 'randProcess.py'
|
|
6
|
+
# author: Julien Straubhaar
|
|
7
|
+
# date: may-2022
|
|
8
|
+
# -------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Module for miscellaneous algorithms based on random processes.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import scipy
|
|
16
|
+
|
|
17
|
+
# ============================================================================
|
|
18
|
+
class RandProcessError(Exception):
|
|
19
|
+
"""
|
|
20
|
+
Custom exception related to `randProcess` module.
|
|
21
|
+
"""
|
|
22
|
+
pass
|
|
23
|
+
# ============================================================================
|
|
24
|
+
|
|
25
|
+
# ----------------------------------------------------------------------------
|
|
26
|
+
def acceptRejectSampler(
|
|
27
|
+
n, xmin, xmax, f,
|
|
28
|
+
c=None,
|
|
29
|
+
g=None, g_rvs=None,
|
|
30
|
+
return_accept_ratio=False,
|
|
31
|
+
max_trial=None,
|
|
32
|
+
verbose=0,
|
|
33
|
+
show_progress=None,
|
|
34
|
+
opt_kwargs=None,
|
|
35
|
+
logger=None):
|
|
36
|
+
"""
|
|
37
|
+
Generates samples according to a given density function.
|
|
38
|
+
|
|
39
|
+
This function generates `n` points (which can be multi-variate) in a
|
|
40
|
+
box-shape domain of lower bound(s) `xmin` and upper bound(s) `xmax`,
|
|
41
|
+
according to a density proportional to the function `f`, based on the
|
|
42
|
+
accept-reject algorithm.
|
|
43
|
+
|
|
44
|
+
Let `g_rvs` a function returning random variates sample(s) from an
|
|
45
|
+
instrumental distribution with density proportional to `g`, and `c` a
|
|
46
|
+
constant such that `c*g(x) >= f(x)` for any `x` (in `[xmin, xmax[` (can be
|
|
47
|
+
multi-dimensional), i.e. `x[i]` in `[xmin[i], xmax[i][` for any i). Let `fd`
|
|
48
|
+
(resp. `gd`) the density function proportional to `f` (resp. `g`); the
|
|
49
|
+
alogrithm consists in the following steps to generate samples `x ~ fd`:
|
|
50
|
+
|
|
51
|
+
- generate `y ~ gd` (using `g_rvs`)
|
|
52
|
+
- generate `u ~ Unif([0,1])`
|
|
53
|
+
- if `u < f(y)/c*g(y)`, then accept `x` (reject `x` otherwise)
|
|
54
|
+
|
|
55
|
+
The default instrumental distribution (if both `g` and `g_rvs` set to `None`)
|
|
56
|
+
is the uniform distribution (`g=1`). If the domain (`[xmin, xmax[`) is
|
|
57
|
+
infinite, the instrumental distribution (`g`, and `g_rvs`) and `c` must be
|
|
58
|
+
specified.
|
|
59
|
+
|
|
60
|
+
Parameters
|
|
61
|
+
----------
|
|
62
|
+
n : int
|
|
63
|
+
number of sample points
|
|
64
|
+
|
|
65
|
+
xmin : float (or int), or array-like of shape(m,)
|
|
66
|
+
lower bound of each coordinate (m is the space dimension);
|
|
67
|
+
note: component(s) can be set to `-np.inf`
|
|
68
|
+
|
|
69
|
+
xmax : float (or int), or array-like of shape(m,)
|
|
70
|
+
upper bound of each coordinate (m is the space dimension)
|
|
71
|
+
note: component(s) can be set to `np.inf`
|
|
72
|
+
|
|
73
|
+
f : function (`callable`)
|
|
74
|
+
function proportional to target density, `f(x)` returns the target
|
|
75
|
+
density (times a constant) at `x`; with `x` array_like, the last
|
|
76
|
+
axis of `x` denotes the components of the points where the function is
|
|
77
|
+
evaluated
|
|
78
|
+
|
|
79
|
+
c : float (or int), optional
|
|
80
|
+
constant such that (not checked)) `c*g(x) >= f(x)` for all x in
|
|
81
|
+
[xmin, xmax[, with `g(x)=1` if `g` is not specified (`g=None`);
|
|
82
|
+
by default (`c=None`), the domain (`[xmin, xmax[`) must be finite and
|
|
83
|
+
`c` is automatically computed (using the function
|
|
84
|
+
`scipy.optimize.differential_evolution`)
|
|
85
|
+
|
|
86
|
+
g : function (callable), optional
|
|
87
|
+
function proportional to the instrumental density on `[xmin, xmax[`,
|
|
88
|
+
`g(x)` returns the instrumental density (times a constant) at `x`;
|
|
89
|
+
with `x` array_like, the last axis of `x` denotes the components of the
|
|
90
|
+
points where the function is evaluated;
|
|
91
|
+
by default (`g=None`), the domain (`[xmin, xmax[`) must be finite and
|
|
92
|
+
the instrumental distribution considered is uniform (constant
|
|
93
|
+
function `g=1` is considered)
|
|
94
|
+
|
|
95
|
+
g_rvs : function (`callable`), optional
|
|
96
|
+
function returning samples from the instrumental distribution with
|
|
97
|
+
density proportional to `g` on `[xmin, xmax[` (restricted on this
|
|
98
|
+
domain if needed); `g_rvs` must have the keyword arguments `size`
|
|
99
|
+
(the number of sample(s) to draw);
|
|
100
|
+
by default (`None`), uniform instrumental distribution is considered
|
|
101
|
+
(see `g`);
|
|
102
|
+
note: both `g` and `g_rvs` must be specified (or both set to `None`)
|
|
103
|
+
|
|
104
|
+
return_accept_ratio : bool, default: False
|
|
105
|
+
indicates if the acceptance ratio is returned
|
|
106
|
+
|
|
107
|
+
verbose : int, default: 0
|
|
108
|
+
verbose mode, higher implies more printing (info)
|
|
109
|
+
|
|
110
|
+
show_progress : bool, optional
|
|
111
|
+
deprecated, use `verbose` instead;
|
|
112
|
+
|
|
113
|
+
- if `show_progress=False`, `verbose` is set to 1 (overwritten)
|
|
114
|
+
- if `show_progress=True`, `verbose` is set to 2 (overwritten)
|
|
115
|
+
- if `show_progress=None` (default): not used
|
|
116
|
+
|
|
117
|
+
opt_kwargs : dict, optional
|
|
118
|
+
keyword arguments to be passed to `scipy.optimize.differential_evolution`
|
|
119
|
+
(do not set `'bounds'` key, bounds are set according to `xmin`, `xmax`)
|
|
120
|
+
|
|
121
|
+
logger : :class:`logging.Logger`, optional
|
|
122
|
+
logger (see package `logging`)
|
|
123
|
+
if specified, messages are written via `logger` (no print)
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
x : 2d-array of shape (n, m), or 1d-array of shape (n,)
|
|
128
|
+
samples according to the target density proportional to `f on the
|
|
129
|
+
domain `[xmin, max[`, `x[i]` is the i-th sample point;
|
|
130
|
+
notes:
|
|
131
|
+
|
|
132
|
+
- if dimension m >= 2: `x` is a 2d-array of shape (n, m)
|
|
133
|
+
- if diemnsion is 1: `x` is an array of shape (n,)
|
|
134
|
+
|
|
135
|
+
t : float, optional
|
|
136
|
+
acceptance ratio, returned if `return_accept_ratio=True`, i.e.
|
|
137
|
+
`t = n/ntot` where `ntot` is the number of points draws in the
|
|
138
|
+
instrumental distribution
|
|
139
|
+
"""
|
|
140
|
+
fname = 'acceptRejectSampler'
|
|
141
|
+
|
|
142
|
+
# Set verbose mode according to show_progress (if given)
|
|
143
|
+
if show_progress is not None:
|
|
144
|
+
if show_progress:
|
|
145
|
+
verbose = 2
|
|
146
|
+
else:
|
|
147
|
+
verbose = 1
|
|
148
|
+
|
|
149
|
+
xmin = np.atleast_1d(xmin)
|
|
150
|
+
xmax = np.atleast_1d(xmax)
|
|
151
|
+
|
|
152
|
+
if xmin.ndim != xmax.ndim or np.any(np.isnan(xmin)) or np.any(np.isnan(xmax)) or np.any(xmin >= xmax):
|
|
153
|
+
err_msg = f'{fname}: `xmin`, `xmax` invalid'
|
|
154
|
+
if logger: logger.error(err_msg)
|
|
155
|
+
raise RandProcessError(err_msg)
|
|
156
|
+
|
|
157
|
+
lx = xmax - xmin
|
|
158
|
+
dim = len(xmin)
|
|
159
|
+
|
|
160
|
+
if np.any(np.isinf(lx)):
|
|
161
|
+
dom_finite = False
|
|
162
|
+
else:
|
|
163
|
+
dom_finite = True
|
|
164
|
+
|
|
165
|
+
if n <= 0:
|
|
166
|
+
x = np.zeros((n, dim))
|
|
167
|
+
if dim == 1:
|
|
168
|
+
x = x.reshape(-1)
|
|
169
|
+
if return_accept_ratio:
|
|
170
|
+
return x, 1.0
|
|
171
|
+
else:
|
|
172
|
+
return x
|
|
173
|
+
|
|
174
|
+
# Set g, g_rvs
|
|
175
|
+
if (g is None and g_rvs is not None) or (g is not None and g_rvs is None):
|
|
176
|
+
err_msg = f'{fname}: `g` and `g_rvs` should both be specified'
|
|
177
|
+
if logger: logger.error(err_msg)
|
|
178
|
+
raise RandProcessError(err_msg)
|
|
179
|
+
|
|
180
|
+
if g is None:
|
|
181
|
+
if not dom_finite:
|
|
182
|
+
err_msg = f'{fname}: `g` and `g_rvs` must be specified when infinite domain is considered'
|
|
183
|
+
if logger: logger.error(err_msg)
|
|
184
|
+
raise RandProcessError(err_msg)
|
|
185
|
+
|
|
186
|
+
# g
|
|
187
|
+
g = lambda x: 1.0
|
|
188
|
+
# g_rvs
|
|
189
|
+
if dim == 1:
|
|
190
|
+
def g_rvs(size=1):
|
|
191
|
+
return xmin[0] + scipy.stats.uniform.rvs(size=size) * lx[0]
|
|
192
|
+
else:
|
|
193
|
+
def g_rvs(size=1):
|
|
194
|
+
return xmin + scipy.stats.uniform.rvs(size=(size,dim)) * lx
|
|
195
|
+
|
|
196
|
+
if c is None:
|
|
197
|
+
if not dom_finite:
|
|
198
|
+
err_msg = f'{fname}: `c` must be specified when infinite domain is considered'
|
|
199
|
+
if logger: logger.error(err_msg)
|
|
200
|
+
raise RandProcessError(err_msg)
|
|
201
|
+
|
|
202
|
+
h = lambda x: -f(x)/g(x)
|
|
203
|
+
# Compute the min of h(x) with the function scipy.optimize.differential_evolution
|
|
204
|
+
if opt_kwargs is None:
|
|
205
|
+
opt_kwargs = {}
|
|
206
|
+
res = scipy.optimize.differential_evolution(h, bounds=list(zip(xmin, xmax)), **opt_kwargs)
|
|
207
|
+
if not res.success:
|
|
208
|
+
err_msg = f'{fname}: `scipy.optimize.differential_evolution` failed {res.message})'
|
|
209
|
+
if logger: logger.error(err_msg)
|
|
210
|
+
raise RandProcessError(err_msg)
|
|
211
|
+
|
|
212
|
+
# -> res.x realizes the minimum of h(x)
|
|
213
|
+
# -> res.fun is the minimum of h(x)
|
|
214
|
+
# Set c such that c > f(x)/g(x) for all x in the domain
|
|
215
|
+
c = -res.fun + 1.e-3 # add small number to ensure the inequality
|
|
216
|
+
|
|
217
|
+
# Apply accept-reject algo
|
|
218
|
+
naccept = 0
|
|
219
|
+
ntot = 0
|
|
220
|
+
x = []
|
|
221
|
+
if max_trial is None:
|
|
222
|
+
max_trial = np.inf
|
|
223
|
+
if verbose > 1:
|
|
224
|
+
progress = 0
|
|
225
|
+
progressOld = -1
|
|
226
|
+
while naccept < n:
|
|
227
|
+
nn = n - naccept
|
|
228
|
+
ntot = ntot+nn
|
|
229
|
+
xnew = g_rvs(size=nn)
|
|
230
|
+
ind = np.all((xnew >= xmin, xnew < xmax), axis=0)
|
|
231
|
+
if dim > 1:
|
|
232
|
+
ind = np.all(ind, axis=-1)
|
|
233
|
+
xnew = xnew[ind]
|
|
234
|
+
nn = len(xnew)
|
|
235
|
+
if nn == 0:
|
|
236
|
+
continue
|
|
237
|
+
u = np.random.random(size=nn)
|
|
238
|
+
xnew = xnew[u < (f(xnew)/(c*g(xnew))).reshape(nn)]
|
|
239
|
+
nn = len(xnew)
|
|
240
|
+
if nn == 0:
|
|
241
|
+
continue
|
|
242
|
+
x.extend(xnew)
|
|
243
|
+
naccept = naccept+nn
|
|
244
|
+
if verbose > 1:
|
|
245
|
+
progress = int(100*naccept/n)
|
|
246
|
+
if progress > progressOld:
|
|
247
|
+
if logger:
|
|
248
|
+
logger.info(f'{fname}: A-R algo, progress: {progress:3d} %')
|
|
249
|
+
else:
|
|
250
|
+
print(f'{fname}: A-R algo, progress: {progress:3d} %')
|
|
251
|
+
progressOld = progress
|
|
252
|
+
if ntot >= max_trial:
|
|
253
|
+
break
|
|
254
|
+
|
|
255
|
+
x = np.asarray(x)
|
|
256
|
+
|
|
257
|
+
if naccept < n and verbose > 0:
|
|
258
|
+
if logger:
|
|
259
|
+
logger.warning(f'{fname}: sample size is only {naccept}! (increase `max_trial`)')
|
|
260
|
+
else:
|
|
261
|
+
print(f'{fname}: WARNING: sample size is only {naccept}! (increase `max_trial`)')
|
|
262
|
+
|
|
263
|
+
if return_accept_ratio:
|
|
264
|
+
accept_ratio = naccept/ntot
|
|
265
|
+
return x, accept_ratio
|
|
266
|
+
else:
|
|
267
|
+
return x
|
|
268
|
+
# ----------------------------------------------------------------------------
|
|
269
|
+
|
|
270
|
+
# ----------------------------------------------------------------------------
|
|
271
|
+
def poissonPointProcess(mu, xmin=0.0, xmax=1.0, ninterval=None, logger=None):
|
|
272
|
+
"""
|
|
273
|
+
Generates random points following a Poisson point process.
|
|
274
|
+
|
|
275
|
+
Random points are in `[xmin, xmax[` (can be multi-dimensional).
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
mu : function (`callable`), or ndarray of floats, or float
|
|
280
|
+
intensity of the Poisson process, i.e. the mean number of points per
|
|
281
|
+
unitary volume:
|
|
282
|
+
|
|
283
|
+
- if a function: (non-homogeneous Poisson point process) \
|
|
284
|
+
`mu(x)` returns the intensity at `x`; with `x` array_like, the last \
|
|
285
|
+
axis of `x` denotes the components of the points where the function is \
|
|
286
|
+
evaluated
|
|
287
|
+
- if a ndarray: (non-homogeneous Poisson point process) \
|
|
288
|
+
`mu[i_n, ..., i_0]` is the intensity on the box \
|
|
289
|
+
`[xmin[j]+i_j*(xmax[j]-xmin[j])/mu.shape[n-j]]`, j = 0,..., n
|
|
290
|
+
- if a float: homogeneous Poisson point process
|
|
291
|
+
|
|
292
|
+
xmin : float (or int), or array-like of shape(m,)
|
|
293
|
+
lower bound of each coordinate
|
|
294
|
+
|
|
295
|
+
xmax : float (or int), or array-like of shape(m,)
|
|
296
|
+
upper bound of each coordinate
|
|
297
|
+
|
|
298
|
+
ninterval : int, or array-like of ints of shape (m,), optional
|
|
299
|
+
used only if `mu` is a function (callable);
|
|
300
|
+
`ninterval` contains the number of interval(s) in which the domain
|
|
301
|
+
`[xmin, xmax[` is subdivided along each axis
|
|
302
|
+
|
|
303
|
+
logger : :class:`logging.Logger`, optional
|
|
304
|
+
logger (see package `logging`)
|
|
305
|
+
if specified, messages are written via `logger` (no print)
|
|
306
|
+
|
|
307
|
+
Returns
|
|
308
|
+
-------
|
|
309
|
+
pts : 2D array of shape (npts, m)
|
|
310
|
+
each row is a random point in the domain `[xmin, xmax[`, the number of
|
|
311
|
+
points (`npts`) follows a Poisson law of the given intensity (`mu`) and
|
|
312
|
+
m is the dimension of the domain
|
|
313
|
+
"""
|
|
314
|
+
fname = 'poissonPointProcess'
|
|
315
|
+
|
|
316
|
+
xmin = np.atleast_1d(xmin)
|
|
317
|
+
xmax = np.atleast_1d(xmax)
|
|
318
|
+
|
|
319
|
+
if xmin.ndim != xmax.ndim or xmin.ndim != 1:
|
|
320
|
+
err_msg = f'{fname}: `xmin`, `xmax` not valid (dimension or shape)'
|
|
321
|
+
if logger: logger.error(err_msg)
|
|
322
|
+
raise RandProcessError(err_msg)
|
|
323
|
+
|
|
324
|
+
if np.any(xmin >= xmax):
|
|
325
|
+
err_msg = f'{fname}: `xmin`, `xmax` not valid ((component of) xmin less than or equal to xmax)'
|
|
326
|
+
if logger: logger.error(err_msg)
|
|
327
|
+
raise RandProcessError(err_msg)
|
|
328
|
+
|
|
329
|
+
# dimension
|
|
330
|
+
dim = len(xmin)
|
|
331
|
+
|
|
332
|
+
if callable(mu):
|
|
333
|
+
if ninterval is None:
|
|
334
|
+
err_msg = f'{fname}: `ninterval` must be specified when a function is passed for the intensity (`mu`)'
|
|
335
|
+
if logger: logger.error(err_msg)
|
|
336
|
+
raise RandProcessError(err_msg)
|
|
337
|
+
|
|
338
|
+
ninterval = np.asarray(ninterval, dtype=int) # possibly 0-dimensional
|
|
339
|
+
if ninterval.size == 1:
|
|
340
|
+
ninterval = ninterval.flat[0] * np.ones(dim)
|
|
341
|
+
elif ninterval.size != dim:
|
|
342
|
+
err_msg = f'{fname}: `ninterval` does not have an acceptable size'
|
|
343
|
+
if logger: logger.error(err_msg)
|
|
344
|
+
raise RandProcessError(err_msg)
|
|
345
|
+
|
|
346
|
+
if np.any(ninterval < 1):
|
|
347
|
+
err_msg = f'{fname}: `ninterval` has negative or zero value'
|
|
348
|
+
if logger: logger.error(err_msg)
|
|
349
|
+
raise RandProcessError(err_msg)
|
|
350
|
+
|
|
351
|
+
elif isinstance(mu, np.ndarray):
|
|
352
|
+
if mu.ndim != dim:
|
|
353
|
+
err_msg = f'{fname}: inconsistent number of dimension for the ndarray `mu`'
|
|
354
|
+
if logger: logger.error(err_msg)
|
|
355
|
+
raise RandProcessError(err_msg)
|
|
356
|
+
|
|
357
|
+
ninterval = mu.shape[::-1]
|
|
358
|
+
|
|
359
|
+
else: # mu is a float
|
|
360
|
+
mu = np.atleast_1d(mu)
|
|
361
|
+
for i in range(dim-1):
|
|
362
|
+
mu = mu[np.newaxis,...]
|
|
363
|
+
# mu is a ndarray with dim dimension of shape (1,...,1) --> grid with one cell
|
|
364
|
+
|
|
365
|
+
ninterval = mu.shape
|
|
366
|
+
|
|
367
|
+
# spacing of the grid cell along each axis
|
|
368
|
+
spa = [(b-a)/n for a, b, n in zip(xmin, xmax, ninterval)]
|
|
369
|
+
# cell volume
|
|
370
|
+
vol_cell = np.prod(spa)
|
|
371
|
+
# cell center along each axis
|
|
372
|
+
x_cell_center = [a + (0.5 + np.arange(n)) * s for a, n, s in zip(xmin, ninterval, spa)]
|
|
373
|
+
# center of each grid cell
|
|
374
|
+
xx_cell_center = np.meshgrid(*x_cell_center[::-1], indexing='ij')[::-1]
|
|
375
|
+
xx_cell_center = np.array([xx.reshape(-1) for xx in xx_cell_center]).T # shape: ncell x dim
|
|
376
|
+
|
|
377
|
+
# Poisson parameter (intensity) for each grid cell
|
|
378
|
+
if callable(mu):
|
|
379
|
+
mu_cell = mu(xx_cell_center)*vol_cell
|
|
380
|
+
else:
|
|
381
|
+
mu_cell = mu.reshape(-1) * vol_cell
|
|
382
|
+
|
|
383
|
+
# Generate number of points in each grid cell (Poisson)
|
|
384
|
+
npts_cell = np.array([scipy.stats.poisson.rvs(m) for m in mu_cell])
|
|
385
|
+
|
|
386
|
+
# Generate random points (uniformly) in each cell
|
|
387
|
+
pts = np.array([np.hstack(
|
|
388
|
+
[a + spa[i] * (np.random.random(size=npts) - 0.5) for a, npts in zip(xx_cell_center[:,i], npts_cell)]
|
|
389
|
+
) for i in range(dim)]).T
|
|
390
|
+
|
|
391
|
+
return pts
|
|
392
|
+
# ----------------------------------------------------------------------------
|
|
393
|
+
|
|
394
|
+
# ----------------------------------------------------------------------------
|
|
395
|
+
def chentsov1D(
|
|
396
|
+
n_mean,
|
|
397
|
+
dimension,
|
|
398
|
+
spacing=1.0,
|
|
399
|
+
origin=0.0,
|
|
400
|
+
direction_origin=None,
|
|
401
|
+
p_min=None,
|
|
402
|
+
p_max=None,
|
|
403
|
+
nreal=1,
|
|
404
|
+
verbose=0,
|
|
405
|
+
logger=None):
|
|
406
|
+
"""
|
|
407
|
+
Generates a Chentsov's simulation in 1D.
|
|
408
|
+
|
|
409
|
+
The domain of simulation is `[xmin, xmax]`, with `nx` cells along x axis,
|
|
410
|
+
each cell having a length of `dx`, the left side is the origin:
|
|
411
|
+
|
|
412
|
+
- along x axis:
|
|
413
|
+
- `nx = dimension`
|
|
414
|
+
- `dx = spacing`
|
|
415
|
+
- `xmin = origin`
|
|
416
|
+
- `xmax = origin + nx*dx`
|
|
417
|
+
|
|
418
|
+
The simulation consists in:
|
|
419
|
+
|
|
420
|
+
1. Drawing random hyper-plane (i.e. points in 1D) in the space
|
|
421
|
+
[`p_min`, `p_max`] following a Poisson point process with intensity:
|
|
422
|
+
|
|
423
|
+
* mu = `n_mean` / vol([`p_min`, `p_max`]);
|
|
424
|
+
|
|
425
|
+
the points are given in the parametrized form: p;
|
|
426
|
+
then, for each point p, and with direction_origin = x0
|
|
427
|
+
(the center of the simulation domain by default), the hyper-plane
|
|
428
|
+
(point)
|
|
429
|
+
|
|
430
|
+
* {x : x-x0 = p} (i.e. the point x0 + p)
|
|
431
|
+
|
|
432
|
+
is considered
|
|
433
|
+
|
|
434
|
+
2. Each hyper-plane (point x0+p) splits the space (R) in two parts
|
|
435
|
+
(two half lines); the value = +1 is set to one part (chosen
|
|
436
|
+
randomly) and the value -1 is set to the other part. Denoting V_i
|
|
437
|
+
the value over the space (R) associated to the i-th hyper-plane
|
|
438
|
+
(point), the value assigned to a grid cell of center x is set to
|
|
439
|
+
|
|
440
|
+
* Z(x) = 0.5 * sum_{i} (V_i(x) - V_i(x0))
|
|
441
|
+
|
|
442
|
+
It corresponds to the number of hyper-planes (points) cut by the
|
|
443
|
+
segment [x0, x].
|
|
444
|
+
|
|
445
|
+
Parameters
|
|
446
|
+
----------
|
|
447
|
+
n_mean : float
|
|
448
|
+
mean number of hyper-plane drawn (via Poisson process)
|
|
449
|
+
|
|
450
|
+
dimension : int
|
|
451
|
+
`dimension=nx`, number of cells in the 1D simulation grid
|
|
452
|
+
|
|
453
|
+
spacing : float, default: 1.0
|
|
454
|
+
`spacing=dx`, cell size
|
|
455
|
+
|
|
456
|
+
origin : float, default: 0.0
|
|
457
|
+
`origin=ox`, origin of the 1D simulation grid (left border)
|
|
458
|
+
|
|
459
|
+
direction_origin : float, optional
|
|
460
|
+
origin from which the "points" are drawn in the Poisson process
|
|
461
|
+
(see above);
|
|
462
|
+
by default (`None`): the center of the 1D simulation domain is used
|
|
463
|
+
|
|
464
|
+
p_min : float, optional
|
|
465
|
+
minimal value for p (see above);
|
|
466
|
+
by default (`None`): `p_min` is set automatically to "minus half of the
|
|
467
|
+
length of the 1D simulation domain"
|
|
468
|
+
|
|
469
|
+
p_max : float, optional
|
|
470
|
+
maximal value for p (see above);
|
|
471
|
+
by default (`None`): `p_max` is set automatically to "plus half of the
|
|
472
|
+
length of the 1D simulation domain
|
|
473
|
+
|
|
474
|
+
nreal : int, default: 1
|
|
475
|
+
number of realization(s)
|
|
476
|
+
|
|
477
|
+
verbose : int, default: 0
|
|
478
|
+
verbose mode, higher implies more printing (info)
|
|
479
|
+
|
|
480
|
+
logger : :class:`logging.Logger`, optional
|
|
481
|
+
logger (see package `logging`)
|
|
482
|
+
if specified, messages are written via `logger` (no print)
|
|
483
|
+
|
|
484
|
+
Returns
|
|
485
|
+
-------
|
|
486
|
+
sim : 2D array of floats of shape (nreal, nx)
|
|
487
|
+
simulations of Z (see above);
|
|
488
|
+
`sim[i, j]`: value of the i-th realisation at grid cell of index j
|
|
489
|
+
|
|
490
|
+
n : 1D array of shape (nreal,)
|
|
491
|
+
numbers of hyper-planes (points) drawn, `n[i]` is the number of
|
|
492
|
+
hyper-planes for the i-th realization
|
|
493
|
+
"""
|
|
494
|
+
fname = 'chentsov1D'
|
|
495
|
+
|
|
496
|
+
# Number of realization(s)
|
|
497
|
+
nreal = int(nreal) # cast to int if needed
|
|
498
|
+
|
|
499
|
+
if nreal <= 0:
|
|
500
|
+
if verbose > 0:
|
|
501
|
+
if logger:
|
|
502
|
+
logger.warning(f'{fname}: `nreal` <= 0: `None`, `None` is returned')
|
|
503
|
+
else:
|
|
504
|
+
print(f'{fname}: WARNING: `nreal` <= 0: `None`, `None` is returned')
|
|
505
|
+
return None, None
|
|
506
|
+
|
|
507
|
+
nx = dimension
|
|
508
|
+
dx = spacing
|
|
509
|
+
ox = origin
|
|
510
|
+
|
|
511
|
+
if direction_origin is None:
|
|
512
|
+
direction_origin = ox+0.5*nx*dx
|
|
513
|
+
|
|
514
|
+
if p_min is None or p_max is None:
|
|
515
|
+
d = 0.5*nx*dx
|
|
516
|
+
if p_min is None:
|
|
517
|
+
p_min = -d
|
|
518
|
+
if p_max is None:
|
|
519
|
+
p_max = d
|
|
520
|
+
|
|
521
|
+
if p_min >= p_max:
|
|
522
|
+
err_msg = f'{fname}: `p_min` is greater than or equal to `p_max`'
|
|
523
|
+
if logger: logger.error(err_msg)
|
|
524
|
+
raise RandProcessError(err_msg)
|
|
525
|
+
|
|
526
|
+
# center of each grid cell of the simulation domain
|
|
527
|
+
xc = ox + (0.5 + np.arange(nx)) * dx
|
|
528
|
+
|
|
529
|
+
# Volume of [p_min, p_max]
|
|
530
|
+
vol_poisson_domain = (p_max - p_min)
|
|
531
|
+
|
|
532
|
+
# Set intensity of Poisson process
|
|
533
|
+
mu = n_mean / vol_poisson_domain
|
|
534
|
+
|
|
535
|
+
# Initialization
|
|
536
|
+
z = np.zeros((nreal, nx))
|
|
537
|
+
n = np.zeros(nreal, dtype='int')
|
|
538
|
+
|
|
539
|
+
for k in range(nreal):
|
|
540
|
+
# Draw points via Poisson process
|
|
541
|
+
try:
|
|
542
|
+
pts = poissonPointProcess(mu, p_min, p_max, logger=logger)
|
|
543
|
+
except Exception as exc:
|
|
544
|
+
err_msg = f'{fname}: Poisson point process failed'
|
|
545
|
+
if logger: logger.error(err_msg)
|
|
546
|
+
raise RandProcessError(err_msg) from exc
|
|
547
|
+
|
|
548
|
+
n[k] = pts.shape[0]
|
|
549
|
+
|
|
550
|
+
# Defines values of Z in each grid cell
|
|
551
|
+
random_sign = (-1)**np.random.randint(2, size=n[k])
|
|
552
|
+
for i in range(n[k]):
|
|
553
|
+
z[k] = z[k] + (np.sign((xc-direction_origin)-pts[i])+np.sign(pts[i]))*random_sign[i]
|
|
554
|
+
|
|
555
|
+
z = 0.5*z
|
|
556
|
+
|
|
557
|
+
return z, n
|
|
558
|
+
# ----------------------------------------------------------------------------
|
|
559
|
+
|
|
560
|
+
# ----------------------------------------------------------------------------
|
|
561
|
+
def chentsov2D(
|
|
562
|
+
n_mean,
|
|
563
|
+
dimension,
|
|
564
|
+
spacing=(1.0, 1.0),
|
|
565
|
+
origin=(0.0, 0.0),
|
|
566
|
+
direction_origin=None,
|
|
567
|
+
phi_min=0.0,
|
|
568
|
+
phi_max=np.pi,
|
|
569
|
+
p_min=None,
|
|
570
|
+
p_max=None,
|
|
571
|
+
nreal=1,
|
|
572
|
+
verbose=0,
|
|
573
|
+
logger=None):
|
|
574
|
+
"""
|
|
575
|
+
Generates a Chentsov's simulation in 2D.
|
|
576
|
+
|
|
577
|
+
The domain of simulation is `[xmin, xmax]` x `[ymin x ymax]`,
|
|
578
|
+
with `nx` and `ny` cells along x axis and y axis respectively, each cell
|
|
579
|
+
being a box of size `dx` x `dy`, the lower-left corner is the origin:
|
|
580
|
+
|
|
581
|
+
- along x axis:
|
|
582
|
+
- `nx = dimension[0]`
|
|
583
|
+
- `dx = spacing[0]`
|
|
584
|
+
- `xmin = origin[0]`
|
|
585
|
+
- `xmax = origin[0] + nx*dx`
|
|
586
|
+
|
|
587
|
+
- along y axis:
|
|
588
|
+
- `ny = dimension[1]`
|
|
589
|
+
- `dy = spacing[1]`
|
|
590
|
+
- `ymin = origin[1]`
|
|
591
|
+
- `ymax = origin[1] + ny*dy`
|
|
592
|
+
|
|
593
|
+
The simulation consists in:
|
|
594
|
+
|
|
595
|
+
1. Drawing random hyper-plane (i.e. lines in 2D):
|
|
596
|
+
considering the space S x [`p_min`, `p_max`], where S is a part of
|
|
597
|
+
the circle of radius 1 in the plane (by default: half circle),
|
|
598
|
+
parametrized via
|
|
599
|
+
|
|
600
|
+
* phi -> (cos(phi), sin(phi)), with phi in [`phi_min`, `phi_max`],
|
|
601
|
+
|
|
602
|
+
some points are drawn randomly in S x [`p_min`, `p_max`] following a
|
|
603
|
+
Poisson point process with intensity
|
|
604
|
+
|
|
605
|
+
* mu = `n_mean` / vol(S x [`p_min`, `p_max`])
|
|
606
|
+
|
|
607
|
+
the points are given in the parametrized form: (phi, p);
|
|
608
|
+
then, for each point (phi, p), and with direction_origin = (x0, y0)
|
|
609
|
+
(the center of the simulation domain by default), the hyper-plane
|
|
610
|
+
(line)
|
|
611
|
+
|
|
612
|
+
* {(x, y) : dot([x-x0, y-y0], [cos(phi), sin(phi)]) = p}
|
|
613
|
+
|
|
614
|
+
(i.e. point (x, y) s.t. the orthogonal projection of (x-x0, y-y0)
|
|
615
|
+
onto the direction (cos(phi), sin(phi)) is equal to p) is considered
|
|
616
|
+
|
|
617
|
+
2. Each hyper-plane (line) splits the space (R^2) in two parts (two half
|
|
618
|
+
planes); the value = +1 is set to one part (chosen randomly) and the
|
|
619
|
+
value -1 is set to the other part. Denoting V_i the value over the
|
|
620
|
+
space (R^2) associated to the i-th hyper-plane (line), the value
|
|
621
|
+
assigned to a grid cell of center (x, y) is set to
|
|
622
|
+
|
|
623
|
+
* Z(x, y) = 0.5 * sum_{i} (V_i(x, y) - V_i(x0, y0))
|
|
624
|
+
|
|
625
|
+
It corresponds to the number of hyper-planes cut by the segment
|
|
626
|
+
[(x0, y0), (x, y)].
|
|
627
|
+
|
|
628
|
+
Parameters
|
|
629
|
+
----------
|
|
630
|
+
n_mean : float
|
|
631
|
+
mean number of hyper-plane drawn (via Poisson process)
|
|
632
|
+
|
|
633
|
+
dimension : 2-tuple of ints
|
|
634
|
+
`dimension=(nx, ny)`, number of cells in the 2D simulation grid along
|
|
635
|
+
each axis
|
|
636
|
+
|
|
637
|
+
spacing : 2-tuple of floats, default: (1.0, 1.0)
|
|
638
|
+
`spacing=(dx, dy)`, cell size along each axis
|
|
639
|
+
|
|
640
|
+
origin : 2-tuple of floats, default: (0.0, 0.0)
|
|
641
|
+
`origin=(ox, oy)`, origin of the 2D simulation grid (lower-left corner)
|
|
642
|
+
|
|
643
|
+
direction_origin : sequence of 2 floats, optional
|
|
644
|
+
origin from which the directions are drawn in the Poisson process
|
|
645
|
+
(see above);
|
|
646
|
+
by default (`None`): the center of the 2D simulation domain is used
|
|
647
|
+
|
|
648
|
+
phi_min : float, default: 0.0
|
|
649
|
+
minimal angle for the parametrization of S (part of circle) defining
|
|
650
|
+
the direction (see above)
|
|
651
|
+
|
|
652
|
+
phi_max : float, default: `numpy.pi`
|
|
653
|
+
maximal angle for the parametrization of S (part of circle) defining
|
|
654
|
+
the direction (see above)
|
|
655
|
+
|
|
656
|
+
p_min : float, optional
|
|
657
|
+
minimal value for orthogonal projection (see above);
|
|
658
|
+
by default (`None`): `p_min` is set automatically to "minus half of the
|
|
659
|
+
diagonal of the 2D simulation domain"
|
|
660
|
+
|
|
661
|
+
p_max : float, optional
|
|
662
|
+
maximal value for orthogonal projection (see above);
|
|
663
|
+
by default (`None`): `p_min` is set automatically to "plus half of the
|
|
664
|
+
diagonal of the 2D simulation domain"
|
|
665
|
+
|
|
666
|
+
nreal : int, default: 1
|
|
667
|
+
number of realization(s)
|
|
668
|
+
|
|
669
|
+
verbose : int, default: 0
|
|
670
|
+
verbose mode, higher implies more printing (info)
|
|
671
|
+
|
|
672
|
+
logger : :class:`logging.Logger`, optional
|
|
673
|
+
logger (see package `logging`)
|
|
674
|
+
if specified, messages are written via `logger` (no print)
|
|
675
|
+
|
|
676
|
+
Returns
|
|
677
|
+
-------
|
|
678
|
+
sim : 3D array of floats of shape (nreal, ny, nx)
|
|
679
|
+
simulations of Z (see above);
|
|
680
|
+
`sim[i, iy, ix]`: value of the i-th realisation at grid cell of index ix
|
|
681
|
+
(resp. iy) along x (resp. y) axis
|
|
682
|
+
|
|
683
|
+
n : 1D array of shape (nreal,)
|
|
684
|
+
numbers of hyper-planes (lines) drawn, `n[i]` is the number of
|
|
685
|
+
hyper-planes for the i-th realization
|
|
686
|
+
"""
|
|
687
|
+
fname = 'chentsov2D'
|
|
688
|
+
|
|
689
|
+
# Number of realization(s)
|
|
690
|
+
nreal = int(nreal) # cast to int if needed
|
|
691
|
+
|
|
692
|
+
if nreal <= 0:
|
|
693
|
+
if verbose > 0:
|
|
694
|
+
if logger:
|
|
695
|
+
logger.warning(f'{fname}: `nreal` <= 0: `None`, `None` is returned')
|
|
696
|
+
else:
|
|
697
|
+
print(f'{fname}: WARNING: `nreal` <= 0: `None`, `None` is returned')
|
|
698
|
+
return None, None
|
|
699
|
+
|
|
700
|
+
nx, ny = dimension
|
|
701
|
+
dx, dy = spacing
|
|
702
|
+
ox, oy = origin
|
|
703
|
+
|
|
704
|
+
if direction_origin is None:
|
|
705
|
+
direction_origin = [ox+0.5*nx*dx, oy+0.5*ny*dy]
|
|
706
|
+
|
|
707
|
+
if p_min is None or p_max is None:
|
|
708
|
+
d = 0.5*np.sqrt((nx*dx)**2+(ny*dy)**2)
|
|
709
|
+
if p_min is None:
|
|
710
|
+
p_min = -d
|
|
711
|
+
if p_max is None:
|
|
712
|
+
p_max = d
|
|
713
|
+
|
|
714
|
+
if p_min >= p_max:
|
|
715
|
+
err_msg = f'{fname}: `p_min` is greater than or equal to `p_max`'
|
|
716
|
+
if logger: logger.error(err_msg)
|
|
717
|
+
raise RandProcessError(err_msg)
|
|
718
|
+
|
|
719
|
+
if phi_min >= phi_max:
|
|
720
|
+
err_msg = f'{fname}: `phi_min` is greater than or equal to `phi_max`'
|
|
721
|
+
if logger: logger.error(err_msg)
|
|
722
|
+
raise RandProcessError(err_msg)
|
|
723
|
+
|
|
724
|
+
# center of each grid cell of the simulation domain
|
|
725
|
+
yc, xc = np.meshgrid(oy + (0.5 + np.arange(ny)) * dy, ox + (0.5 + np.arange(nx)) * dx, indexing='ij')
|
|
726
|
+
xyc = np.array([xc.reshape(-1), yc.reshape(-1)]).T # shape: ncell x 2
|
|
727
|
+
|
|
728
|
+
# Volume of S x [p_min, p_max], (S being parametrized by phi in [phi_min, phi_max])
|
|
729
|
+
vol_poisson_domain = (phi_max - phi_min) * (p_max - p_min)
|
|
730
|
+
|
|
731
|
+
# Defines lines by random points in [phi_min, phi_max] x [p_min, p_max]
|
|
732
|
+
# if callable(mu):
|
|
733
|
+
# def mu_intensity(x):
|
|
734
|
+
# return mu(x) / vol_poisson_domain
|
|
735
|
+
# else:
|
|
736
|
+
# mu_intensity = mu / vol_poisson_domain
|
|
737
|
+
|
|
738
|
+
# Set intensity of Poisson process
|
|
739
|
+
mu = n_mean / vol_poisson_domain
|
|
740
|
+
|
|
741
|
+
# Initialization
|
|
742
|
+
z = np.zeros((nreal, nx*ny))
|
|
743
|
+
n = np.zeros(nreal, dtype='int')
|
|
744
|
+
|
|
745
|
+
for k in range(nreal):
|
|
746
|
+
# Draw points via Poisson process
|
|
747
|
+
try:
|
|
748
|
+
pts = poissonPointProcess(mu, [phi_min, p_min], [phi_max, p_max], logger=logger)
|
|
749
|
+
except Exception as exc:
|
|
750
|
+
err_msg = f'{fname}: Poisson point process failed'
|
|
751
|
+
if logger: logger.error(err_msg)
|
|
752
|
+
raise RandProcessError(err_msg) from exc
|
|
753
|
+
|
|
754
|
+
n[k] = pts.shape[0]
|
|
755
|
+
|
|
756
|
+
# Defines values of Z in each grid cell
|
|
757
|
+
random_sign = (-1)**np.random.randint(2, size=n[k])
|
|
758
|
+
# Equivalent method below (4/ is better!)
|
|
759
|
+
# 1/
|
|
760
|
+
# vp = np.sum([np.sign((xyc-direction_origin).dot(np.array([np.cos(a), np.sin(a)]))-p)*rs for a, p, rs in zip(pts[:,0], pts[:,1], random_sign)], axis=0)
|
|
761
|
+
# v0 = np.sum([np.sign(-p)*rs for p, rs in zip(pts[:,1], random_sign)])
|
|
762
|
+
# z = 0.5 *(vp - v0)
|
|
763
|
+
# 2/
|
|
764
|
+
# z = 0.5*np.sum([(np.sign((xyc-direction_origin).dot(np.array([np.cos(a), np.sin(a)]))-p)+np.sign(p))*rs for a, p, rs in zip(pts[:,0], pts[:,1], random_sign)], axis=0)
|
|
765
|
+
# 3/
|
|
766
|
+
# z = 0.5*np.sum([(np.sign((xyc-direction_origin).dot(np.array([np.cos(pts[i,0]), np.sin(pts[i,0])]))-pts[i,1])+np.sign(pts[i,1]))*random_sign[i] for i in range(n[k])], axis=0)
|
|
767
|
+
# 4/
|
|
768
|
+
for i in range(n[k]):
|
|
769
|
+
z[k] = z[k] + (np.sign((xyc-direction_origin).dot(np.array([np.cos(pts[i,0]), np.sin(pts[i,0])]))-pts[i,1])+np.sign(pts[i,1]))*random_sign[i]
|
|
770
|
+
|
|
771
|
+
z = 0.5*z
|
|
772
|
+
|
|
773
|
+
return z.reshape(nreal, ny, nx), n
|
|
774
|
+
# ----------------------------------------------------------------------------
|
|
775
|
+
|
|
776
|
+
# ----------------------------------------------------------------------------
|
|
777
|
+
def chentsov3D(
|
|
778
|
+
n_mean,
|
|
779
|
+
dimension,
|
|
780
|
+
spacing=(1.0, 1.0, 1.0),
|
|
781
|
+
origin=(0.0, 0.0, 0.0),
|
|
782
|
+
direction_origin=None,
|
|
783
|
+
phi_min=0.0,
|
|
784
|
+
phi_max=2.0*np.pi,
|
|
785
|
+
theta_min=0.0,
|
|
786
|
+
theta_max=0.5*np.pi,
|
|
787
|
+
p_min=None,
|
|
788
|
+
p_max=None,
|
|
789
|
+
ninterval_theta=100,
|
|
790
|
+
nreal=1,
|
|
791
|
+
verbose=0,
|
|
792
|
+
logger=None):
|
|
793
|
+
"""
|
|
794
|
+
Generates a Chentsov's simulation in 3D.
|
|
795
|
+
|
|
796
|
+
The domain of simulation is
|
|
797
|
+
`[xmin, xmax]` x `[ymin x ymax]` x `[zmin x zmax]`,
|
|
798
|
+
with `nx`, `ny`, `nz` cells along x axis, y axis, z axis respectively, each
|
|
799
|
+
cell being a box of size `dx` x `dy` x `dy`, the bottom-lower-left corner is
|
|
800
|
+
the origin:
|
|
801
|
+
|
|
802
|
+
- along x axis:
|
|
803
|
+
- `nx = dimension[0]`
|
|
804
|
+
- `dx = spacing[0]`
|
|
805
|
+
- `xmin = origin[0]`
|
|
806
|
+
- `xmax = origin[0] + nx*dx`
|
|
807
|
+
|
|
808
|
+
- along y axis:
|
|
809
|
+
- `ny = dimension[1]`
|
|
810
|
+
- `dy = spacing[1]`
|
|
811
|
+
- `ymin = origin[1]`
|
|
812
|
+
- `ymax = origin[1] + ny*dy`
|
|
813
|
+
|
|
814
|
+
- along z axis:
|
|
815
|
+
- `nz = dimension[0]`
|
|
816
|
+
- `dz = spacing[0]`
|
|
817
|
+
- `zmin = origin[0]`
|
|
818
|
+
- `zmax = origin[0] + nz*dz`.
|
|
819
|
+
|
|
820
|
+
The simulation consists in:
|
|
821
|
+
|
|
822
|
+
1. Drawing random hyper-plane (i.e. planes in 3D):
|
|
823
|
+
considering the space S x [`p_min`, `p_max`], where S is a part of
|
|
824
|
+
the sphere of radius 1 in the 3D space (by default: half sphere),
|
|
825
|
+
parametrized via
|
|
826
|
+
|
|
827
|
+
* (phi, theta) -> (cos(phi)cos(theta), sin(phi)cos(theta), sin(theta)), \
|
|
828
|
+
with phi in [`phi_min`, `phi_max`], theta in [`theta_min`, `theta_max`]
|
|
829
|
+
|
|
830
|
+
some points are drawn randomly in S x [`p_min`, `p_max`] following a
|
|
831
|
+
Poisson point process with intensity
|
|
832
|
+
|
|
833
|
+
* mu = `n_mean` / vol(S x [`p_min`, `p_max`]);
|
|
834
|
+
|
|
835
|
+
the points are given in the parametrized form: (phi, theta, p);
|
|
836
|
+
then, for each point (phi, theta, p), and with
|
|
837
|
+
direction_origin = (x0, y0, z0) (the center of the simulation domain
|
|
838
|
+
by default), the hyper-plane (plane)
|
|
839
|
+
|
|
840
|
+
* {(x, y, z) : dot([x-x0, y-y0, z-z0], [cos(phi)cos(theta), sin(phi)cos(theta), sin(theta)]) = p}
|
|
841
|
+
|
|
842
|
+
(i.e. point (x, y, z) s.t. the orthogonal projection of
|
|
843
|
+
(x-x0, y-y0, z-z0) onto the direction
|
|
844
|
+
(cos(phi)cos(theta), sin(phi)cos(theta), sin(theta)) is equal to p)
|
|
845
|
+
is considered;
|
|
846
|
+
|
|
847
|
+
2. Each hyper-plane (plane) splits the space (R^3) in two parts;
|
|
848
|
+
the value = +1 is set to one part (chosen randomly) and the value -1
|
|
849
|
+
is set to the other part. Denoting V_i the value over the space (R^3)
|
|
850
|
+
associated to the i-th hyper-plane (plane), the value assigned to a
|
|
851
|
+
grid cell of center (x, y) is set to
|
|
852
|
+
|
|
853
|
+
* Z(x, y) = 0.5 * sum_{i} (V_i(x, y) - V_i(x0, y0))
|
|
854
|
+
|
|
855
|
+
It corresponds to the number of hyper-planes (planes) cut by the
|
|
856
|
+
segment [(x0, y0, z0), (x, y, z)].
|
|
857
|
+
|
|
858
|
+
Parameters
|
|
859
|
+
----------
|
|
860
|
+
n_mean : float
|
|
861
|
+
mean number of hyper-plane drawn (via Poisson process)
|
|
862
|
+
|
|
863
|
+
dimension : 3-tuple of ints
|
|
864
|
+
`dimension=(nx, ny, nz)`, number of cells in the 3D simulation grid along
|
|
865
|
+
each axis
|
|
866
|
+
|
|
867
|
+
spacing : 3-tuple of floats, default: (1.0,1.0, 1.0)
|
|
868
|
+
`spacing=(dx, dy, dz)`, cell size along each axis
|
|
869
|
+
|
|
870
|
+
origin : 3-tuple of floats, default: (0.0, 0.0, 0.0)
|
|
871
|
+
`origin=(ox, oy, oz)`, origin of the 3D simulation grid (bottom-lower-left
|
|
872
|
+
corner)
|
|
873
|
+
|
|
874
|
+
direction_origin : sequence of 3 floats, optional
|
|
875
|
+
origin from which the directions are drawn in the Poisson process
|
|
876
|
+
(see above);
|
|
877
|
+
by default (`None`): the center of the 3D simulation domain is used
|
|
878
|
+
|
|
879
|
+
phi_min : float, default: 0.0
|
|
880
|
+
minimal angle for the parametrization of S (part of circle) defining
|
|
881
|
+
the direction (see above)
|
|
882
|
+
|
|
883
|
+
phi_max : float, default: `numpy.pi`
|
|
884
|
+
maximal angle for the parametrization of S (part of circle) defining
|
|
885
|
+
the direction (see above)
|
|
886
|
+
|
|
887
|
+
theta_min : float, default: 0.0
|
|
888
|
+
minimal angle for the parametrization of S (part of circle) defining
|
|
889
|
+
the direction (see above)
|
|
890
|
+
|
|
891
|
+
theta_max : float, default: `0.5*numpy.pi`
|
|
892
|
+
maximal angle for the parametrization of S (part of circle) defining
|
|
893
|
+
the direction (see above)
|
|
894
|
+
|
|
895
|
+
p_min : float, optional
|
|
896
|
+
minimal value for orthogonal projection (see above);
|
|
897
|
+
by default (`None`): `p_min` is set automatically to "minus half of the
|
|
898
|
+
diagonal of the 3D simulation domain"
|
|
899
|
+
|
|
900
|
+
p_max : float, optional
|
|
901
|
+
maximal value for orthogonal projection (see above);
|
|
902
|
+
by default (`None`): `p_min` is set automatically to "plus half of the
|
|
903
|
+
diagonal of the 3D simulation domain"
|
|
904
|
+
|
|
905
|
+
ninterval_theta : int, default: 100
|
|
906
|
+
number of sub-intervals in which the interval `[theta_min, theta_max]`
|
|
907
|
+
is subdivided for applying the Poisson process
|
|
908
|
+
|
|
909
|
+
nreal : int, default: 1
|
|
910
|
+
number of realization(s)
|
|
911
|
+
|
|
912
|
+
verbose : int, default: 0
|
|
913
|
+
verbose mode, higher implies more printing (info)
|
|
914
|
+
|
|
915
|
+
logger : :class:`logging.Logger`, optional
|
|
916
|
+
logger (see package `logging`)
|
|
917
|
+
if specified, messages are written via `logger` (no print)
|
|
918
|
+
|
|
919
|
+
Returns
|
|
920
|
+
-------
|
|
921
|
+
sim : 4D array of floats of shape (nreal, nz, ny, nx)
|
|
922
|
+
simulations of Z (see above);
|
|
923
|
+
`sim[i, iz, iy, ix]`: value of the i-th realisation at grid cell of
|
|
924
|
+
index ix (resp. iy, iz) along x (resp. y, z) axis
|
|
925
|
+
|
|
926
|
+
n : 1D array of shape (nreal,)
|
|
927
|
+
numbers of hyper-planes (planes) drawn, `n[i]` is the number of
|
|
928
|
+
hyper-planes for the i-th realization
|
|
929
|
+
"""
|
|
930
|
+
fname = 'chentsov3D'
|
|
931
|
+
|
|
932
|
+
# Number of realization(s)
|
|
933
|
+
nreal = int(nreal) # cast to int if needed
|
|
934
|
+
|
|
935
|
+
if nreal <= 0:
|
|
936
|
+
if verbose > 0:
|
|
937
|
+
if logger:
|
|
938
|
+
logger.warning(f'{fname}: `nreal` <= 0: `None`, `None` is returned')
|
|
939
|
+
else:
|
|
940
|
+
print(f'{fname}: WARNING: `nreal` <= 0: `None`, `None` is returned')
|
|
941
|
+
return None, None
|
|
942
|
+
|
|
943
|
+
nx, ny, nz = dimension
|
|
944
|
+
dx, dy, dz = spacing
|
|
945
|
+
ox, oy, oz = origin
|
|
946
|
+
|
|
947
|
+
if direction_origin is None:
|
|
948
|
+
direction_origin = [ox+0.5*nx*dx, oy+0.5*ny*dy, oz+0.5*nz*dz]
|
|
949
|
+
|
|
950
|
+
if p_min is None or p_max is None:
|
|
951
|
+
d = 0.5*np.sqrt((nx*dx)**2+(ny*dy)**2+(nz*dz)**2)
|
|
952
|
+
if p_min is None:
|
|
953
|
+
p_min = -d
|
|
954
|
+
if p_max is None:
|
|
955
|
+
p_max = d
|
|
956
|
+
|
|
957
|
+
if p_min >= p_max:
|
|
958
|
+
err_msg = f'{fname}: `p_min` is greater than or equal to `p_max`'
|
|
959
|
+
if logger: logger.error(err_msg)
|
|
960
|
+
raise RandProcessError(err_msg)
|
|
961
|
+
|
|
962
|
+
if phi_min >= phi_max:
|
|
963
|
+
err_msg = f'{fname}: `phi_min` is greater than or equal to `phi_max`'
|
|
964
|
+
if logger: logger.error(err_msg)
|
|
965
|
+
raise RandProcessError(err_msg)
|
|
966
|
+
|
|
967
|
+
if theta_min >= theta_max:
|
|
968
|
+
err_msg = f'{fname}: `theta_min` is greater than or equal to `theta_max`'
|
|
969
|
+
if logger: logger.error(err_msg)
|
|
970
|
+
raise RandProcessError(err_msg)
|
|
971
|
+
|
|
972
|
+
# center of each grid cell of the simulation domain
|
|
973
|
+
zc, yc, xc = np.meshgrid(oz + (0.5 + np.arange(nz)) * dz, oy + (0.5 + np.arange(ny)) * dy, ox + (0.5 + np.arange(nx)) * dx, indexing='ij')
|
|
974
|
+
xyzc = np.array([xc.reshape(-1), yc.reshape(-1), zc.reshape(-1)]).T # shape: ncell x 3
|
|
975
|
+
|
|
976
|
+
# Volume of S x [p_min, p_max], (S being parametrized by phi in [phi_min, phi_max], and theta in [theta_min, theta_max])
|
|
977
|
+
vol_poisson_domain = (phi_max - phi_min) * (np.sin(theta_max) - np.sin(theta_min)) * (p_max - p_min)
|
|
978
|
+
|
|
979
|
+
# Set intensity of Poisson process as a function accounting for jacobian of the parametrization of S
|
|
980
|
+
def mu(x):
|
|
981
|
+
return n_mean * np.cos(x[:, 1])/ vol_poisson_domain # x = (phi, theta), cos(x[:, 1] = cos(theta)
|
|
982
|
+
|
|
983
|
+
# Initialization
|
|
984
|
+
z = np.zeros((nreal, nx*ny*nz))
|
|
985
|
+
n = np.zeros(nreal, dtype='int')
|
|
986
|
+
|
|
987
|
+
for k in range(nreal):
|
|
988
|
+
# Draw points via Poisson process
|
|
989
|
+
try:
|
|
990
|
+
pts = poissonPointProcess(mu, [phi_min, theta_min, p_min], [phi_max, theta_max, p_max], ninterval=[1, ninterval_theta, 1], logger=logger)
|
|
991
|
+
except Exception as exc:
|
|
992
|
+
err_msg = f'{fname}: Poisson point process failed'
|
|
993
|
+
if logger: logger.error(err_msg)
|
|
994
|
+
raise RandProcessError(err_msg) from exc
|
|
995
|
+
|
|
996
|
+
n[k] = pts.shape[0]
|
|
997
|
+
|
|
998
|
+
# Defines values of Z in each grid cell
|
|
999
|
+
random_sign = (-1)**np.random.randint(2, size=n[k])
|
|
1000
|
+
# 4/
|
|
1001
|
+
for i in range(n[k]):
|
|
1002
|
+
z[k] = z[k] + (np.sign((xyzc-direction_origin).dot(np.array([np.cos(pts[i,0])*np.cos(pts[i,1]), np.sin(pts[i,0])*np.cos(pts[i,1]), np.sin(pts[i,1])]))-pts[i,2])+np.sign(pts[i,2]))*random_sign[i]
|
|
1003
|
+
z = 0.5*z
|
|
1004
|
+
|
|
1005
|
+
return z.reshape(nreal, nz, ny, nx), n
|
|
1006
|
+
# ----------------------------------------------------------------------------
|
|
1007
|
+
|
|
1008
|
+
if __name__ == "__main__":
|
|
1009
|
+
print("Module 'geone.randProcess'.")
|
|
1010
|
+
|
|
1011
|
+
##### OLD BELOW #####
|
|
1012
|
+
# # ----------------------------------------------------------------------------
|
|
1013
|
+
# def acceptRejectSampler(n, xmin, xmax, f, c=None, g=None, g_rvs=None,
|
|
1014
|
+
# return_accept_ratio=False,
|
|
1015
|
+
# max_trial=None, show_progress=False):
|
|
1016
|
+
# """
|
|
1017
|
+
# Generates samples according to a given density function.
|
|
1018
|
+
#
|
|
1019
|
+
# This function generates `n` points in a box-shape domain of lower bound(s)
|
|
1020
|
+
# `xmin` and upper bound(s) `xmax`, according to a density proportional to the
|
|
1021
|
+
# function `f` are generated, based on the accept-reject algorithm.
|
|
1022
|
+
#
|
|
1023
|
+
# Let `g_rvs` a function returning random variates sample(s) from an
|
|
1024
|
+
# instrumental distribution with density proportional to `g`, and `c` a
|
|
1025
|
+
# constant such that `c*g(x) >= f(x)` for any `x` (in `[xmin, xmax[` (can be
|
|
1026
|
+
# multi-dimensional), i.e. `x[i]` in `[xmin[i], xmax[i][` for any i). Let `fd`
|
|
1027
|
+
# (resp. `gd`) the density function proportional to `f` (resp. `g`); the
|
|
1028
|
+
# alogrithm consists in the following steps to generate samples `x ~ fd`:
|
|
1029
|
+
# - generate `y ~ gd` (using `g_rvs`)
|
|
1030
|
+
# - generate `u ~ Unif([0,1])`
|
|
1031
|
+
# - if `u < f(y)/c*g(y)`, then accept `x` (reject `x` otherwise)
|
|
1032
|
+
#
|
|
1033
|
+
# If the instrumental distribution is not specified (both `g` and `g_rvs` set
|
|
1034
|
+
# to `None`), then:
|
|
1035
|
+
# - the uniform distribution if the domain `[xmin, xmax[` is finite
|
|
1036
|
+
# - the multi-normal distribution, centered at a point maximizing `f`, with
|
|
1037
|
+
# a variance 1 (covariance matrix I), if the domain `[xmin, xmax[` is infinite
|
|
1038
|
+
#
|
|
1039
|
+
# Parameters
|
|
1040
|
+
# ----------
|
|
1041
|
+
# n : int
|
|
1042
|
+
# number of sample points
|
|
1043
|
+
# xmin : float (or int), or array-like of shape(m,)
|
|
1044
|
+
# lower bound of each coordinate (m is the space dimension);
|
|
1045
|
+
# note: component(s) can be set to `-np.inf`
|
|
1046
|
+
# xmax : float (or int), or array-like of shape(m,)
|
|
1047
|
+
# upper bound of each coordinate (m is the space dimension)
|
|
1048
|
+
# note: component(s) can be set to `np.inf`
|
|
1049
|
+
# f : function (callable)
|
|
1050
|
+
# function proportional to target density, `f(x)` returns the target
|
|
1051
|
+
# density (times a constant) at `x`; with `x` array_like, the last
|
|
1052
|
+
# axis of `x` denotes the components of the points where the function is
|
|
1053
|
+
# evaluated
|
|
1054
|
+
# c : float (or int), optional
|
|
1055
|
+
# constant such that (not checked)) `c*g(x) >= f(x)` for all x in
|
|
1056
|
+
# [xmin, xmax[, with `g(x)=1` if `g` is not specified (`g=None`);
|
|
1057
|
+
# by default (`c=None`), `c` is automatically computed (using the function
|
|
1058
|
+
# `scipy.optimize.minimize`)
|
|
1059
|
+
# g : function (callable), optional
|
|
1060
|
+
# function proportional to the instrumental density on `[xmin, xmax[`,
|
|
1061
|
+
# `g(x)` returns the instrumental density (times a constant) at `x`;
|
|
1062
|
+
# with `x` array_like, the last axis of `x` denotes the components of the
|
|
1063
|
+
# points where the function is evaluated;
|
|
1064
|
+
# by default (`g=None`): the instrumental distribution considered is
|
|
1065
|
+
# - uniform (constant function `g=1` is considered), if the domain
|
|
1066
|
+
# `[xmin, xmax[` is finite
|
|
1067
|
+
# - (multi-)normal density of variance 1 (covariance matrix I), centered
|
|
1068
|
+
# at a point maximizing `f`, otherwise;
|
|
1069
|
+
# g_rvs : function (callable), optional
|
|
1070
|
+
# function returning samples from the instrumental distribution with
|
|
1071
|
+
# density proportional to `g` on `[xmin, xmax[` (restricted on this
|
|
1072
|
+
# domain if needed); `g_rvs` must have the keyword arguments `size`
|
|
1073
|
+
# (the number of sample(s) to draw)
|
|
1074
|
+
# by default: uniform or non-correlated multi-normal instrumental
|
|
1075
|
+
# distribution is considered (see `g`);
|
|
1076
|
+
# note: both `g` and `g_rvs` must be specified (or both set to `None`)
|
|
1077
|
+
# return_accept_ratio : bool, default: False
|
|
1078
|
+
# indicates if the acceptance ratio is returned
|
|
1079
|
+
# show_progress : bool, default: False
|
|
1080
|
+
# indicates if progress is displayed (True) or not (False)
|
|
1081
|
+
#
|
|
1082
|
+
# Returns
|
|
1083
|
+
# -------
|
|
1084
|
+
# x : 2d-array of shape (n, m), or 1d-array of shape (n,)
|
|
1085
|
+
# samples according to the target density proportional to `f on the
|
|
1086
|
+
# domain `[xmin, max[`, `x[i]` is the i-th sample point;
|
|
1087
|
+
# notes:
|
|
1088
|
+
# - if dimension m >= 2: `x` is a 2d-array of shape (n, m)
|
|
1089
|
+
# - if diemnsion is 1: `x` is an array of shape (n,)
|
|
1090
|
+
# t : float, optional
|
|
1091
|
+
# acceptance ratio, returned if `return_accept_ratio=True`, i.e.
|
|
1092
|
+
# `t = n/ntot` where `ntot` is the number of points draws in the
|
|
1093
|
+
# instrumental distribution
|
|
1094
|
+
# """
|
|
1095
|
+
# fname = 'acceptRejectSampler'
|
|
1096
|
+
#
|
|
1097
|
+
# xmin = np.atleast_1d(xmin)
|
|
1098
|
+
# xmax = np.atleast_1d(xmax)
|
|
1099
|
+
#
|
|
1100
|
+
# if xmin.ndim != xmax.ndim or np.any(np.isnan(xmin)) or np.any(np.isnan(xmax)) or np.any(xmin >= xmax):
|
|
1101
|
+
# print(f'ERROR ({fname}): `xmin`, `xmax` not valid')
|
|
1102
|
+
# return None
|
|
1103
|
+
#
|
|
1104
|
+
# lx = xmax - xmin
|
|
1105
|
+
# dim = len(xmin)
|
|
1106
|
+
#
|
|
1107
|
+
# x = np.zeros((n, dim)) # initialize random samples (one sample by row)
|
|
1108
|
+
# if n <= 0:
|
|
1109
|
+
# if return_accept_ratio:
|
|
1110
|
+
# return x, 1.0
|
|
1111
|
+
# else:
|
|
1112
|
+
# return x
|
|
1113
|
+
#
|
|
1114
|
+
# # Set g, g_rvs, and c
|
|
1115
|
+
# if (g is None and g_rvs is not None) or (g is not None and g_rvs is None):
|
|
1116
|
+
# print(f'ERROR ({fname}): `g` and `g_rvs` should be both specified')
|
|
1117
|
+
# return None
|
|
1118
|
+
#
|
|
1119
|
+
# mu = None # not necessarily used
|
|
1120
|
+
# if c is None:
|
|
1121
|
+
# if g is None:
|
|
1122
|
+
# h = lambda x: -f(x)
|
|
1123
|
+
# else:
|
|
1124
|
+
# h = lambda x: -f(x)/g(x)
|
|
1125
|
+
# # Compute the min of h(x) with the function scipy.optimize.minimize
|
|
1126
|
+
# # x0: initial guess (random)
|
|
1127
|
+
# x0 = xmin + np.random.random(size=dim)*lx
|
|
1128
|
+
# for i, binf in enumerate(np.isinf(x0)):
|
|
1129
|
+
# if binf:
|
|
1130
|
+
# x0[i] = min(xmax[i], max(xmin[i], 0.0))
|
|
1131
|
+
# res = scipy.optimize.minimize(h, x0, bounds=list(zip(xmin, xmax)))
|
|
1132
|
+
# if not res.success:
|
|
1133
|
+
# print(f'ERROR ({fname}): `scipy.optimize.minimize` failed {res.message})')
|
|
1134
|
+
# return None
|
|
1135
|
+
# # -> res.x realizes the minimum of h(x)
|
|
1136
|
+
# # -> res.fun is the minimum of h(x)
|
|
1137
|
+
# mu = res.x
|
|
1138
|
+
# # Set c such that c > f(x)/g(x) for all x in the domain
|
|
1139
|
+
# c = -res.fun + 1.e-3 # add small number to ensure the inequality
|
|
1140
|
+
#
|
|
1141
|
+
# if g is None:
|
|
1142
|
+
# if np.any((np.isinf(xmin), np.isinf(xmax))):
|
|
1143
|
+
# if mu is None:
|
|
1144
|
+
# # Compute the min of h(x) = (f(x)-c)**2 with the function scipy.optimize.minimize
|
|
1145
|
+
# h = lambda x: (f(x)-c)**2
|
|
1146
|
+
# # x0: initial guess (random)
|
|
1147
|
+
# x0 = xmin + np.random.random(size=dim)*lx
|
|
1148
|
+
# for i, binf in enumerate(np.isinf(x0)):
|
|
1149
|
+
# if binf:
|
|
1150
|
+
# x0[i] = min(xmax[i], max(xmin[i], 0.0))
|
|
1151
|
+
# res = scipy.optimize.minimize(h, x0, bounds=list(zip(xmin, xmax)))
|
|
1152
|
+
# if not res.success:
|
|
1153
|
+
# print(f'ERROR ({fname}): `scipy.optimize.minimize` failed {res.message})')
|
|
1154
|
+
# return None
|
|
1155
|
+
# # -> res.x is the minimum of h(x)
|
|
1156
|
+
# mu = res.x
|
|
1157
|
+
# # Set instrumental pdf proportional to: g = exp(-1/2 sum_i((x[i]-mu[i])**2))
|
|
1158
|
+
# # Set g, g_rvs
|
|
1159
|
+
# g = lambda x: np.exp(-0.5*np.sum((np.atleast_2d(x)-mu)**2), axis=1)
|
|
1160
|
+
# g_rvs = scipy.stats.multivariate_normal(mean=mu).rvs
|
|
1161
|
+
#
|
|
1162
|
+
# # Update c
|
|
1163
|
+
# # Compute the min of h(x) = -f(x)/g(x) with the function scipy.optimize.minimize
|
|
1164
|
+
# h = lambda x: -f(x)/g(x)
|
|
1165
|
+
# # x0: initial guess
|
|
1166
|
+
# x0 = mu
|
|
1167
|
+
# res = scipy.optimize.minimize(h, x0, bounds=list(zip(xmin, xmax)))
|
|
1168
|
+
# if not res.success:
|
|
1169
|
+
# print(f'ERROR ({fname}): `scipy.optimize.minimize` failed {res.message})')
|
|
1170
|
+
# return None
|
|
1171
|
+
# # -> res.fun is the minimum of h(x)
|
|
1172
|
+
#
|
|
1173
|
+
# # Set c such that c > f(x)/g(x) for all x in the domain
|
|
1174
|
+
# c = -res.fun + 1.e-3 # add small number to ensure the inequality
|
|
1175
|
+
#
|
|
1176
|
+
# else:
|
|
1177
|
+
# # Set instrumental pdf proportional to: g = 1 (uniform distribution)
|
|
1178
|
+
# # Set g, g_rvs
|
|
1179
|
+
# g = lambda x: 1.0
|
|
1180
|
+
# def g_rvs(size=1):
|
|
1181
|
+
# return xmin + scipy.stats.uniform.rvs(size=(size,dim)) * lx
|
|
1182
|
+
#
|
|
1183
|
+
# # Apply accept-reject algo
|
|
1184
|
+
# naccept = 0
|
|
1185
|
+
# ntot = 0
|
|
1186
|
+
# x = []
|
|
1187
|
+
# if max_trial is None:
|
|
1188
|
+
# max_trial = np.inf
|
|
1189
|
+
# if show_progress:
|
|
1190
|
+
# progress = 0
|
|
1191
|
+
# progressOld = -1
|
|
1192
|
+
# while naccept < n:
|
|
1193
|
+
# nn = n - naccept
|
|
1194
|
+
# ntot = ntot+nn
|
|
1195
|
+
# xnew = g_rvs(size=nn)
|
|
1196
|
+
# # print('1', xnew)
|
|
1197
|
+
# # print('1b', np.all(np.all((xnew >= xmin, xnew < xmax), axis=0), axis=-1))
|
|
1198
|
+
# xnew = xnew[np.all(np.all((xnew >= xmin, xnew < xmax), axis=0), axis=-1)]
|
|
1199
|
+
# # print('2', xnew)
|
|
1200
|
+
# nn = len(xnew)
|
|
1201
|
+
# if nn == 0:
|
|
1202
|
+
# continue
|
|
1203
|
+
# u = np.random.random(size=nn)
|
|
1204
|
+
# xnew = xnew[u < (f(xnew)/(c*g(xnew))).reshape(nn)]
|
|
1205
|
+
# # print('3', xnew)
|
|
1206
|
+
# nn = len(xnew)
|
|
1207
|
+
# if nn == 0:
|
|
1208
|
+
# continue
|
|
1209
|
+
# x.extend(xnew)
|
|
1210
|
+
# naccept = naccept+nn
|
|
1211
|
+
# if show_progress:
|
|
1212
|
+
# progress = int(100*naccept/n)
|
|
1213
|
+
# if progress > progressOld:
|
|
1214
|
+
# print(f'A-R algo, progress: {progress:3d} %')
|
|
1215
|
+
# progressOld = progress
|
|
1216
|
+
# if ntot >= max_trial:
|
|
1217
|
+
# ok = False
|
|
1218
|
+
# break
|
|
1219
|
+
#
|
|
1220
|
+
# x = np.asarray(x)
|
|
1221
|
+
# if dim == 1:
|
|
1222
|
+
# x = x.reshape(-1)
|
|
1223
|
+
#
|
|
1224
|
+
# # # Apply accept-reject algo
|
|
1225
|
+
# # naccept = 0
|
|
1226
|
+
# # ntot = 0
|
|
1227
|
+
# # if max_trial is None:
|
|
1228
|
+
# # max_trial = np.inf
|
|
1229
|
+
# # if show_progress:
|
|
1230
|
+
# # progress = 0
|
|
1231
|
+
# # progressOld = -1
|
|
1232
|
+
# # while naccept < n:
|
|
1233
|
+
# # ntot = ntot+1
|
|
1234
|
+
# # xnew = g_rvs()
|
|
1235
|
+
# # if np.any((xnew < xmin, xnew >= xmax)):
|
|
1236
|
+
# # continue
|
|
1237
|
+
# # u = np.random.random()
|
|
1238
|
+
# # if u < f(xnew)/(c*g(xnew)):
|
|
1239
|
+
# # x[naccept] = xnew
|
|
1240
|
+
# # naccept = naccept+1
|
|
1241
|
+
# # if show_progress:
|
|
1242
|
+
# # progress = int(100*naccept/n)
|
|
1243
|
+
# # if progress > progressOld:
|
|
1244
|
+
# # print(f'A-R algo, progress: {progress:3d} %')
|
|
1245
|
+
# # progressOld = progress
|
|
1246
|
+
# # if ntot >= max_trial:
|
|
1247
|
+
# # ok = False
|
|
1248
|
+
# # break
|
|
1249
|
+
#
|
|
1250
|
+
# if naccept < n:
|
|
1251
|
+
# print(f'WARNING: sample size is only {naccept}! (increase `max_trial`)')
|
|
1252
|
+
#
|
|
1253
|
+
# if return_accept_ratio:
|
|
1254
|
+
# accept_ratio = naccept/ntot
|
|
1255
|
+
# return x, accept_ratio
|
|
1256
|
+
# else:
|
|
1257
|
+
# return x
|
|
1258
|
+
# # ----------------------------------------------------------------------------
|