geone 1.3.1__py3-none-any.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 +15704 -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 +20353 -0
- geone/grf.py +5927 -0
- geone/img.py +7264 -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 +1025 -0
- geone-1.3.1.dist-info/METADATA +207 -0
- geone-1.3.1.dist-info/RECORD +28 -0
- geone-1.3.1.dist-info/WHEEL +5 -0
- geone-1.3.1.dist-info/licenses/LICENSE +58 -0
- geone-1.3.1.dist-info/top_level.txt +1 -0
geone/pgs.py
ADDED
|
@@ -0,0 +1,1258 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# -------------------------------------------------------------------------
|
|
5
|
+
# Python module: 'pgs.py'
|
|
6
|
+
# author: Julien Straubhaar
|
|
7
|
+
# date: may-2022
|
|
8
|
+
# -------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Module for plurig-Gaussian simulations in 1D, 2D and 3D.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from geone import covModel as gcm
|
|
16
|
+
from geone import multiGaussian
|
|
17
|
+
|
|
18
|
+
# ============================================================================
|
|
19
|
+
class PgsError(Exception):
|
|
20
|
+
"""
|
|
21
|
+
Custom exception related to `pgs` module.
|
|
22
|
+
"""
|
|
23
|
+
pass
|
|
24
|
+
# ============================================================================
|
|
25
|
+
|
|
26
|
+
# ----------------------------------------------------------------------------
|
|
27
|
+
def pluriGaussianSim_unconditional(
|
|
28
|
+
cov_model_T1, cov_model_T2, flag_value,
|
|
29
|
+
dimension, spacing=None, origin=None,
|
|
30
|
+
algo_T1='fft', params_T1={},
|
|
31
|
+
algo_T2='fft', params_T2={},
|
|
32
|
+
nreal=1,
|
|
33
|
+
full_output=True,
|
|
34
|
+
verbose=1,
|
|
35
|
+
logger=None):
|
|
36
|
+
"""
|
|
37
|
+
Generates unconditional pluri-Gaussian simulations.
|
|
38
|
+
|
|
39
|
+
The simulated variable Z at a point x is defined as
|
|
40
|
+
|
|
41
|
+
* Z(x) = flag_value(T1(x), T2(x))
|
|
42
|
+
|
|
43
|
+
where
|
|
44
|
+
|
|
45
|
+
* T1, T2 are two multi-Gaussian random fields (latent fields)
|
|
46
|
+
* `flag_value` is a function of two variables defining the final value \
|
|
47
|
+
(given as a "flag")
|
|
48
|
+
|
|
49
|
+
Z and T1, T2 are fields in 1D, 2D or 3D.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
cov_model_T1 : :class:`geone.covModel.CovModel<d>D`
|
|
54
|
+
covariance model for T1, in 1D or 2D or 3D (same space dimension for T1 and T2);
|
|
55
|
+
note: if `algo_T1='deterministic'`, `cov_model_T1` can be `None` (unused)
|
|
56
|
+
|
|
57
|
+
cov_model_T2 : :class:`geone.covModel.CovModel<d>D`
|
|
58
|
+
covariance model for T2, in 1D or 2D or 3D (same space dimension for T1 and T2);
|
|
59
|
+
note: if `algo_T2='deterministic'`, `cov_model_T2` can be `None` (unused)
|
|
60
|
+
|
|
61
|
+
flag_value : function (`callable`)
|
|
62
|
+
function of tow arguments (xi, yi) that returns the "flag_value" at
|
|
63
|
+
location (xi, yi)
|
|
64
|
+
|
|
65
|
+
dimension : [sequence of] int(s)
|
|
66
|
+
number of cells along each axis, for simulation in:
|
|
67
|
+
|
|
68
|
+
- 1D: `dimension=nx`
|
|
69
|
+
- 2D: `dimension=(nx, ny)`
|
|
70
|
+
- 3D: `dimension=(nx, ny, nz)`
|
|
71
|
+
|
|
72
|
+
spacing : [sequence of] float(s), optional
|
|
73
|
+
cell size along each axis, for simulation in:
|
|
74
|
+
|
|
75
|
+
- 1D: `spacing=sx`
|
|
76
|
+
- 2D: `spacing=(sx, sy)`
|
|
77
|
+
- 3D: `spacing=(sx, sy, sz)`
|
|
78
|
+
|
|
79
|
+
by default (`None`): 1.0 along each axis
|
|
80
|
+
|
|
81
|
+
origin : [sequence of] float(s), optional
|
|
82
|
+
origin of the grid ("corner of the first cell"), for simulation in:
|
|
83
|
+
|
|
84
|
+
- 1D: `origin=ox`
|
|
85
|
+
- 2D: `origin=(ox, oy)`
|
|
86
|
+
- 3D: `origin=(ox, oy, oz)`
|
|
87
|
+
|
|
88
|
+
by default (`None`): 0.0 along each axis
|
|
89
|
+
|
|
90
|
+
algo_T1 : str {'fft', 'classic', 'deterministic'}, default: 'fft'
|
|
91
|
+
defines the algorithm used for T1:
|
|
92
|
+
|
|
93
|
+
- 'fft': algorithm based on circulant embedding and FFT, function \
|
|
94
|
+
called for <d>D (d = 1, 2, or 3): 'geone.grf.grf<d>D'
|
|
95
|
+
- 'classic': "classic" algorithm, based on the resolution of \
|
|
96
|
+
kriging system considered points in a search ellipsoid, function called \
|
|
97
|
+
for <d>D (d = 1, 2, or 3): \
|
|
98
|
+
'geone.geoscalassicinterface.simulate<d>D'
|
|
99
|
+
- 'deterministic': use a deterministic field, given by `param_T1['mean']`
|
|
100
|
+
|
|
101
|
+
algo_T2 : str {'fft', 'classic', 'deterministic'}, default: 'fft'
|
|
102
|
+
defines the algorithm used for T2 (see `algo_T1` for detail)
|
|
103
|
+
|
|
104
|
+
params_T1 : dict
|
|
105
|
+
keyword arguments (additional parameters) to be passed to the function
|
|
106
|
+
that is called (according to `algo_T1` and space dimension) for simulation
|
|
107
|
+
of T1
|
|
108
|
+
|
|
109
|
+
params_T2 : dict
|
|
110
|
+
keyword arguments (additional parameters) to be passed to the function
|
|
111
|
+
that is called (according to `algo_T2` and space dimension) for simulation
|
|
112
|
+
of T2
|
|
113
|
+
|
|
114
|
+
nreal : int, default: 1
|
|
115
|
+
number of realization(s)
|
|
116
|
+
|
|
117
|
+
full_output : bool, default: True
|
|
118
|
+
- if `True`: simulation(s) of Z, T1, and T2 are retrieved in output
|
|
119
|
+
- if `False`: simulation(s) of Z only is retrieved in output
|
|
120
|
+
|
|
121
|
+
verbose : int, default: 1
|
|
122
|
+
verbose mode, higher implies more printing (info)
|
|
123
|
+
|
|
124
|
+
logger : :class:`logging.Logger`, optional
|
|
125
|
+
logger (see package `logging`)
|
|
126
|
+
if specified, messages are written via `logger` (no print)
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
Z : ndarray
|
|
131
|
+
array of shape
|
|
132
|
+
|
|
133
|
+
- for 1D: (nreal, nx)
|
|
134
|
+
- for 2D: (nreal, ny, nx)
|
|
135
|
+
- for 3D: (nreal, nz, ny, nx)
|
|
136
|
+
|
|
137
|
+
Z[k] is the k-th realization of Z
|
|
138
|
+
|
|
139
|
+
T1 : ndarray, optional
|
|
140
|
+
array of shape
|
|
141
|
+
|
|
142
|
+
- for 1D: (nreal, nx)
|
|
143
|
+
- for 2D: (nreal, ny, nx)
|
|
144
|
+
- for 3D: (nreal, nz, ny, nx)
|
|
145
|
+
|
|
146
|
+
T1[k] is the k-th realization of T1;
|
|
147
|
+
returned if `full_output=True`
|
|
148
|
+
|
|
149
|
+
T2 : ndarray, optional
|
|
150
|
+
array of shape
|
|
151
|
+
|
|
152
|
+
- for 1D: (nreal, nx)
|
|
153
|
+
- for 2D: (nreal, ny, nx)
|
|
154
|
+
- for 3D: (nreal, nz, ny, nx)
|
|
155
|
+
|
|
156
|
+
T2[k] is the k-th realization of T2;
|
|
157
|
+
returned if `full_output=True`
|
|
158
|
+
"""
|
|
159
|
+
fname = 'pluriGaussianSim_unconditional'
|
|
160
|
+
|
|
161
|
+
if not callable(flag_value):
|
|
162
|
+
err_msg = f'{fname}: `flag_value` invalid, should be a function (callable) of two arguments'
|
|
163
|
+
if logger: logger.error(err_msg)
|
|
164
|
+
raise PgsError(err_msg)
|
|
165
|
+
|
|
166
|
+
if algo_T1 not in ('fft', 'FFT', 'classic', 'CLASSIC', 'deterministic', 'DETERMINISTIC'):
|
|
167
|
+
err_msg = f"{fname}: `algo_T1` invalid, should be 'fft' (default) or 'classic' or 'deterministic'"
|
|
168
|
+
if logger: logger.error(err_msg)
|
|
169
|
+
raise PgsError(err_msg)
|
|
170
|
+
|
|
171
|
+
if algo_T2 not in ('fft', 'FFT', 'classic', 'CLASSIC', 'deterministic', 'DETERMINISTIC'):
|
|
172
|
+
err_msg = f"{fname}: `algo_T2` invalid, should be 'fft' (default) or 'classic' or 'deterministic'"
|
|
173
|
+
if logger: logger.error(err_msg)
|
|
174
|
+
raise PgsError(err_msg)
|
|
175
|
+
|
|
176
|
+
# Ignore covariance model if 'algo' is deterministic for T1, T2
|
|
177
|
+
if algo_T1 in ('deterministic', 'DETERMINISTIC'):
|
|
178
|
+
cov_model_T1 = None
|
|
179
|
+
|
|
180
|
+
if algo_T2 in ('deterministic', 'DETERMINISTIC'):
|
|
181
|
+
cov_model_T2 = None
|
|
182
|
+
|
|
183
|
+
# Set space dimension (of grid) according to covariance model for T1
|
|
184
|
+
d = 0
|
|
185
|
+
if cov_model_T1 is None:
|
|
186
|
+
if algo_T1 not in ('deterministic', 'DETERMINISTIC'):
|
|
187
|
+
err_msg = f"{fname}: `cov_model_T1` is `None`, then `algo_T1` must be 'deterministic'"
|
|
188
|
+
if logger: logger.error(err_msg)
|
|
189
|
+
raise PgsError(err_msg)
|
|
190
|
+
|
|
191
|
+
elif isinstance(cov_model_T1, gcm.CovModel1D):
|
|
192
|
+
d = 1
|
|
193
|
+
elif isinstance(cov_model_T1, gcm.CovModel2D):
|
|
194
|
+
d = 2
|
|
195
|
+
elif isinstance(cov_model_T1, gcm.CovModel3D):
|
|
196
|
+
d = 3
|
|
197
|
+
else:
|
|
198
|
+
err_msg = f'{fname}: `cov_model_T1` invalid, should be a class `geone.covModel.CovModel1D`, `geone.covModel.CovModel2D` or `geone.covModel.CovModel3D`'
|
|
199
|
+
if logger: logger.error(err_msg)
|
|
200
|
+
raise PgsError(err_msg)
|
|
201
|
+
|
|
202
|
+
if cov_model_T2 is None:
|
|
203
|
+
if algo_T2 not in ('deterministic', 'DETERMINISTIC'):
|
|
204
|
+
err_msg = f"{fname}: `cov_model_T2` is `None`, then `algo_T2` must be 'deterministic'"
|
|
205
|
+
if logger: logger.error(err_msg)
|
|
206
|
+
raise PgsError(err_msg)
|
|
207
|
+
|
|
208
|
+
# if d == 0:
|
|
209
|
+
# err_msg = f'{fname}: `cov_model_T1` and `cov_model_T2` are `None`, at least one covariance model is required'
|
|
210
|
+
# if logger: logger.error(err_msg)
|
|
211
|
+
# raise PgsError(err_msg)
|
|
212
|
+
|
|
213
|
+
elif (d == 1 and not isinstance(cov_model_T2, gcm.CovModel1D)) or (d == 2 and not isinstance(cov_model_T2, gcm.CovModel2D)) or (d == 3 and not isinstance(cov_model_T2, gcm.CovModel3D)):
|
|
214
|
+
err_msg = f'{fname}: `cov_model_T1` and `cov_model_T2` not compatible (dimensions differ)'
|
|
215
|
+
if logger: logger.error(err_msg)
|
|
216
|
+
raise PgsError(err_msg)
|
|
217
|
+
|
|
218
|
+
if d == 0:
|
|
219
|
+
# Set space dimension (of grid) according to 'dimension'
|
|
220
|
+
if hasattr(dimension, '__len__'):
|
|
221
|
+
d = len(dimension)
|
|
222
|
+
else:
|
|
223
|
+
d = 1
|
|
224
|
+
|
|
225
|
+
# Check argument 'dimension'
|
|
226
|
+
if hasattr(dimension, '__len__') and len(dimension) != d:
|
|
227
|
+
err_msg = f'{fname}: `dimension` of incompatible length'
|
|
228
|
+
if logger: logger.error(err_msg)
|
|
229
|
+
raise PgsError(err_msg)
|
|
230
|
+
|
|
231
|
+
# Check (or set) argument 'spacing'
|
|
232
|
+
if spacing is None:
|
|
233
|
+
if d == 1:
|
|
234
|
+
spacing = 1.0
|
|
235
|
+
else:
|
|
236
|
+
spacing = tuple(np.ones(d))
|
|
237
|
+
else:
|
|
238
|
+
if hasattr(spacing, '__len__') and len(spacing) != d:
|
|
239
|
+
err_msg = f'{fname}: `spacing` of incompatible length'
|
|
240
|
+
if logger: logger.error(err_msg)
|
|
241
|
+
raise PgsError(err_msg)
|
|
242
|
+
|
|
243
|
+
# Check (or set) argument 'origin'
|
|
244
|
+
if origin is None:
|
|
245
|
+
if d == 1:
|
|
246
|
+
origin = 0.0
|
|
247
|
+
else:
|
|
248
|
+
origin = tuple(np.zeros(d))
|
|
249
|
+
else:
|
|
250
|
+
if hasattr(origin, '__len__') and len(origin) != d:
|
|
251
|
+
err_msg = f'{fname}: `origin` of incompatible length'
|
|
252
|
+
if logger: logger.error(err_msg)
|
|
253
|
+
raise PgsError(err_msg)
|
|
254
|
+
|
|
255
|
+
# if not cov_model_T1.is_stationary(): # prevent calculation if covariance model is not stationary
|
|
256
|
+
# if verbose > 0:
|
|
257
|
+
# print(f"ERROR ({fname}): `cov_model_T1` is not stationary")
|
|
258
|
+
|
|
259
|
+
# if not cov_model_T2.is_stationary(): # prevent calculation if covariance model is not stationary
|
|
260
|
+
# if verbose > 0:
|
|
261
|
+
# print(f"ERROR ({fname}): `cov_model_T2` is not stationary")
|
|
262
|
+
|
|
263
|
+
# Set default parameter 'verbose' for params_T1, params_T2
|
|
264
|
+
if 'verbose' not in params_T1.keys():
|
|
265
|
+
params_T1['verbose'] = 0
|
|
266
|
+
# params_T1['verbose'] = verbose
|
|
267
|
+
if 'verbose' not in params_T2.keys():
|
|
268
|
+
params_T2['verbose'] = 0
|
|
269
|
+
# params_T2['verbose'] = verbose
|
|
270
|
+
|
|
271
|
+
# Generate T1
|
|
272
|
+
if cov_model_T1 is not None:
|
|
273
|
+
try:
|
|
274
|
+
sim_T1 = multiGaussian.multiGaussianRun(
|
|
275
|
+
cov_model_T1, dimension, spacing, origin,
|
|
276
|
+
mode='simulation', algo=algo_T1, output_mode='array',
|
|
277
|
+
**params_T1, nreal=nreal)
|
|
278
|
+
except Exception as exc:
|
|
279
|
+
err_msg = f'{fname}: simulation of T1 failed'
|
|
280
|
+
if logger: logger.error(err_msg)
|
|
281
|
+
raise PgsError(err_msg) from exc
|
|
282
|
+
|
|
283
|
+
else:
|
|
284
|
+
sim_T1 = np.array([params_T1['mean'].reshape(1,*dimension[::-1]) for _ in range(nreal)])
|
|
285
|
+
# -> sim_T1: nd-array of shape
|
|
286
|
+
# (nreal_T, dimension) (for T1 in 1D)
|
|
287
|
+
# (nreal_T, dimension[1], dimension[0]) (for T1 in 2D)
|
|
288
|
+
# (nreal_T, dimension[2], dimension[1], dimension[0]) (for T1 in 3D)
|
|
289
|
+
#
|
|
290
|
+
# Generate T2
|
|
291
|
+
if cov_model_T2 is not None:
|
|
292
|
+
try:
|
|
293
|
+
sim_T2 = multiGaussian.multiGaussianRun(
|
|
294
|
+
cov_model_T2, dimension, spacing, origin,
|
|
295
|
+
mode='simulation', algo=algo_T2, output_mode='array',
|
|
296
|
+
**params_T2, nreal=nreal)
|
|
297
|
+
except Exception as exc:
|
|
298
|
+
err_msg = f'{fname}: simulation of T2 failed'
|
|
299
|
+
if logger: logger.error(err_msg)
|
|
300
|
+
raise PgsError(err_msg) from exc
|
|
301
|
+
else:
|
|
302
|
+
sim_T2 = np.array([params_T2['mean'].reshape(1,*dimension[::-1]) for _ in range(nreal)])
|
|
303
|
+
# -> sim_T2: nd-array of shape
|
|
304
|
+
# (nreal_T, dimension) (for T2 in 1D)
|
|
305
|
+
# (nreal_T, dimension[1], dimension[0]) (for T2 in 2D)
|
|
306
|
+
# (nreal_T, dimension[2], dimension[1], dimension[0]) (for T2 in 3D)
|
|
307
|
+
|
|
308
|
+
# Generate Z
|
|
309
|
+
if verbose > 1:
|
|
310
|
+
if logger:
|
|
311
|
+
logger.info(f'{fname}: retrieving Z...')
|
|
312
|
+
else:
|
|
313
|
+
print(f'{fname}: retrieving Z...')
|
|
314
|
+
Z = flag_value(sim_T1, sim_T2)
|
|
315
|
+
# Z = np.asarray(Z).reshape(len(Z), *np.atleast_1d(dimension)[::-1])
|
|
316
|
+
|
|
317
|
+
if full_output:
|
|
318
|
+
return Z, sim_T1, sim_T2
|
|
319
|
+
else:
|
|
320
|
+
return Z
|
|
321
|
+
# ----------------------------------------------------------------------------
|
|
322
|
+
|
|
323
|
+
# ----------------------------------------------------------------------------
|
|
324
|
+
def pluriGaussianSim(
|
|
325
|
+
cov_model_T1, cov_model_T2, flag_value,
|
|
326
|
+
dimension, spacing=None, origin=None,
|
|
327
|
+
x=None, v=None,
|
|
328
|
+
algo_T1='fft', params_T1={},
|
|
329
|
+
algo_T2='fft', params_T2={},
|
|
330
|
+
accept_init=0.25, accept_pow=2.0,
|
|
331
|
+
mh_iter_min=100, mh_iter_max=200,
|
|
332
|
+
ntry_max=1,
|
|
333
|
+
retrieve_real_anyway=False,
|
|
334
|
+
nreal=1,
|
|
335
|
+
full_output=True,
|
|
336
|
+
verbose=1,
|
|
337
|
+
logger=None):
|
|
338
|
+
"""
|
|
339
|
+
Generates (conditional) pluri-Gaussian simulations.
|
|
340
|
+
|
|
341
|
+
The simulated variable Z at a point x is defined as
|
|
342
|
+
|
|
343
|
+
* Z(x) = flag_value(T1(x), T2(x))
|
|
344
|
+
|
|
345
|
+
where
|
|
346
|
+
|
|
347
|
+
* T1, T2 are two multi-Gaussian random fields (latent fields)
|
|
348
|
+
* `flag_value` is a function of two variables defining the final value \
|
|
349
|
+
(given as a "flag")
|
|
350
|
+
|
|
351
|
+
Z and T1, T2 are fields in 1D, 2D or 3D.
|
|
352
|
+
|
|
353
|
+
Parameters
|
|
354
|
+
----------
|
|
355
|
+
cov_model_T1 : :class:`geone.covModel.CovModel<d>D`
|
|
356
|
+
covariance model for T1, in 1D or 2D or 3D (same space dimension for T1 and T2);
|
|
357
|
+
note: if `algo_T1='deterministic'`, `cov_model_T1` can be `None` (unused)
|
|
358
|
+
|
|
359
|
+
cov_model_T2 : :class:`geone.covModel.CovModel<d>D`
|
|
360
|
+
covariance model for T2, in 1D or 2D or 3D (same space dimension for T1 and T2);
|
|
361
|
+
note: if `algo_T2='deterministic'`, `cov_model_T2` can be `None` (unused)
|
|
362
|
+
|
|
363
|
+
flag_value : function (`callable`)
|
|
364
|
+
function of tow arguments (xi, yi) that returns the "flag_value" at
|
|
365
|
+
location (xi, yi)
|
|
366
|
+
|
|
367
|
+
dimension : [sequence of] int(s)
|
|
368
|
+
number of cells along each axis, for simulation in:
|
|
369
|
+
|
|
370
|
+
- 1D: `dimension=nx`
|
|
371
|
+
- 2D: `dimension=(nx, ny)`
|
|
372
|
+
- 3D: `dimension=(nx, ny, nz)`
|
|
373
|
+
|
|
374
|
+
spacing : [sequence of] float(s), optional
|
|
375
|
+
cell size along each axis, for simulation in:
|
|
376
|
+
|
|
377
|
+
- 1D: `spacing=sx`
|
|
378
|
+
- 2D: `spacing=(sx, sy)`
|
|
379
|
+
- 3D: `spacing=(sx, sy, sz)`
|
|
380
|
+
|
|
381
|
+
by default (`None`): 1.0 along each axis
|
|
382
|
+
|
|
383
|
+
origin : [sequence of] float(s), optional
|
|
384
|
+
origin of the grid ("corner of the first cell"), for simulation in:
|
|
385
|
+
|
|
386
|
+
- 1D: `origin=ox`
|
|
387
|
+
- 2D: `origin=(ox, oy)`
|
|
388
|
+
- 3D: `origin=(ox, oy, oz)`
|
|
389
|
+
|
|
390
|
+
by default (`None`): 0.0 along each axis
|
|
391
|
+
|
|
392
|
+
x : array-like of floats, optional
|
|
393
|
+
data points locations (float coordinates), for simulation in:
|
|
394
|
+
|
|
395
|
+
- 1D: 1D array-like of floats
|
|
396
|
+
- 2D: 2D array-like of floats of shape (n, 2)
|
|
397
|
+
- 3D: 2D array-like of floats of shape (n, 3)
|
|
398
|
+
|
|
399
|
+
note: if one point (n=1), a float in 1D, a 1D array of shape (2,) in 2D,
|
|
400
|
+
a 1D array of shape (3,) in 3D, is accepted
|
|
401
|
+
|
|
402
|
+
v : 1D array-like of floats, optional
|
|
403
|
+
data values at `x` (`v[i]` is the data value at `x[i]`)
|
|
404
|
+
|
|
405
|
+
algo_T1 : str {'fft', 'classic', 'deterministic'}, default: 'fft'
|
|
406
|
+
defines the algorithm used for T1:
|
|
407
|
+
|
|
408
|
+
- 'fft': algorithm based on circulant embedding and FFT, function \
|
|
409
|
+
called for <d>D (d = 1, 2, or 3): 'geone.grf.grf<d>D'
|
|
410
|
+
- 'classic': "classic" algorithm, based on the resolution of \
|
|
411
|
+
kriging system considered points in a search ellipsoid, function called \
|
|
412
|
+
for <d>D (d = 1, 2, or 3): \
|
|
413
|
+
'geone.geoscalassicinterface.simulate<d>D'
|
|
414
|
+
- 'deterministic': use a deterministic field, given by `param_T1['mean']`
|
|
415
|
+
|
|
416
|
+
algo_T2 : str {'fft', 'classic', 'deterministic'}, default: 'fft'
|
|
417
|
+
defines the algorithm used for T2 (see `algo_T1` for detail)
|
|
418
|
+
|
|
419
|
+
params_T1 : dict
|
|
420
|
+
keyword arguments (additional parameters) to be passed to the function
|
|
421
|
+
that is called (according to `algo_T1` and space dimension) for simulation
|
|
422
|
+
of T1
|
|
423
|
+
|
|
424
|
+
params_T2 : dict
|
|
425
|
+
keyword arguments (additional parameters) to be passed to the function
|
|
426
|
+
that is called (according to `algo_T2` and space dimension) for simulation
|
|
427
|
+
of T2
|
|
428
|
+
|
|
429
|
+
accept_init : float, default: 0.25
|
|
430
|
+
initial acceptation probability
|
|
431
|
+
(see parameters `mh_iter_min`, `mh_iter_max`)
|
|
432
|
+
|
|
433
|
+
accept_pow : float, default: 2.0
|
|
434
|
+
power for computing acceptation probability
|
|
435
|
+
(see parameters `mh_iter_min`, `mh_iter_max`)
|
|
436
|
+
|
|
437
|
+
mh_iter_min : int, default: 100
|
|
438
|
+
see parameter `mh_iter_max`
|
|
439
|
+
|
|
440
|
+
mh_iter_max : int, default: 200
|
|
441
|
+
`mh_iter_min` and `mh_iter_max` are the number of iterations
|
|
442
|
+
(min and max) for Metropolis-Hasting algorithm
|
|
443
|
+
(for conditional simulation) when updating T1 and T2 at conditioning
|
|
444
|
+
locations at iteration `nit` (in 0, ..., `mh_iter_max-1`):
|
|
445
|
+
|
|
446
|
+
* if `nit < mh_iter_min`: for any k:
|
|
447
|
+
- simulate new candidate at `x[k]`: `(T1(x[k]), T2(x[k]))`
|
|
448
|
+
- if `flag_value(T1(x[k]), T2(x[k])=v[k]` (conditioning ok): \
|
|
449
|
+
accept the new candidate
|
|
450
|
+
- else (conditioning not ok): \
|
|
451
|
+
accept the new candidate with probability
|
|
452
|
+
* p = `accept_init * (1 - 1/mh_iter_min)**accept_pow`
|
|
453
|
+
|
|
454
|
+
* if nit >= mh_iter_min:
|
|
455
|
+
- if conditioning ok at every `x[k]`: stop and exit the loop,
|
|
456
|
+
- else: for any k:
|
|
457
|
+
- if conditioning ok at `x[k]`: skip
|
|
458
|
+
- else:
|
|
459
|
+
* simulate new candidate at `x[k]`: `(T1(x[k]), T2(x[k]))`
|
|
460
|
+
* if `flag_value(T1(x[k]), T2(x[k])=v[k]` (conditioning ok): \
|
|
461
|
+
accept the new candidate
|
|
462
|
+
* else (conditioning not ok): \
|
|
463
|
+
reject the new candidate
|
|
464
|
+
|
|
465
|
+
ntry_max : int, default: 1
|
|
466
|
+
number of trial(s) per realization before giving up if something goes
|
|
467
|
+
wrong
|
|
468
|
+
|
|
469
|
+
retrieve_real_anyway : bool, default: False
|
|
470
|
+
if after `ntry_max` trial(s) a conditioning data is not honoured, then
|
|
471
|
+
the realization is:
|
|
472
|
+
|
|
473
|
+
- retrieved, if `retrieve_real_anyway=True`
|
|
474
|
+
- not retrieved (missing realization), if `retrieve_real_anyway=False`
|
|
475
|
+
|
|
476
|
+
nreal : int, default: 1
|
|
477
|
+
number of realization(s)
|
|
478
|
+
|
|
479
|
+
full_output : bool, default: True
|
|
480
|
+
- if `True`: simulation(s) of Z, T1, T2, and `n_cond_ok` are \
|
|
481
|
+
retrieved in output
|
|
482
|
+
- if `False`: simulation(s) of Z only is retrieved in output
|
|
483
|
+
|
|
484
|
+
verbose : int, default: 1
|
|
485
|
+
verbose mode, higher implies more printing (info)
|
|
486
|
+
|
|
487
|
+
logger : :class:`logging.Logger`, optional
|
|
488
|
+
logger (see package `logging`)
|
|
489
|
+
if specified, messages are written via `logger` (no print)
|
|
490
|
+
|
|
491
|
+
Returns
|
|
492
|
+
-------
|
|
493
|
+
Z : ndarray
|
|
494
|
+
array of shape
|
|
495
|
+
|
|
496
|
+
- for 1D: (nreal, nx)
|
|
497
|
+
- for 2D: (nreal, ny, nx)
|
|
498
|
+
- for 3D: (nreal, nz, ny, nx)
|
|
499
|
+
|
|
500
|
+
Z[k] is the k-th realization of Z
|
|
501
|
+
|
|
502
|
+
T1 : ndarray, optional
|
|
503
|
+
array of shape
|
|
504
|
+
|
|
505
|
+
- for 1D: (nreal, nx)
|
|
506
|
+
- for 2D: (nreal, ny, nx)
|
|
507
|
+
- for 3D: (nreal, nz, ny, nx)
|
|
508
|
+
|
|
509
|
+
T1[k] is the k-th realization of T1;
|
|
510
|
+
returned if `full_output=True`
|
|
511
|
+
|
|
512
|
+
T2 : ndarray, optional
|
|
513
|
+
array of shape
|
|
514
|
+
|
|
515
|
+
- for 1D: (nreal, nx)
|
|
516
|
+
- for 2D: (nreal, ny, nx)
|
|
517
|
+
- for 3D: (nreal, nz, ny, nx)
|
|
518
|
+
|
|
519
|
+
T2[k] is the k-th realization of T2;
|
|
520
|
+
returned if `full_output=True`
|
|
521
|
+
|
|
522
|
+
n_cond_ok : list of 1D array
|
|
523
|
+
list of length `nreal`
|
|
524
|
+
|
|
525
|
+
- n_cond_ok[k]: 1D array of ints
|
|
526
|
+
number of conditioning locations honoured at each iteration of the
|
|
527
|
+
Metropolis-Hasting algorithm for the k-th realization, in particular
|
|
528
|
+
`len(n_cond_ok[k])` is the number of iteration done,
|
|
529
|
+
`n_cond_ok[k][-1]` is the number of conditioning locations honoured
|
|
530
|
+
at the end;
|
|
531
|
+
|
|
532
|
+
returned if `full_output=True`
|
|
533
|
+
"""
|
|
534
|
+
fname = 'pluriGaussianSim'
|
|
535
|
+
|
|
536
|
+
if not callable(flag_value):
|
|
537
|
+
err_msg = f'{fname}: `flag_value` invalid, should be a function (callable) of two arguments'
|
|
538
|
+
if logger: logger.error(err_msg)
|
|
539
|
+
raise PgsError(err_msg)
|
|
540
|
+
|
|
541
|
+
if algo_T1 not in ('fft', 'FFT', 'classic', 'CLASSIC', 'deterministic', 'DETERMINISTIC'):
|
|
542
|
+
err_msg = f"{fname}: `algo_T1` invalid, should be 'fft' (default) or 'classic' or 'deterministic'"
|
|
543
|
+
if logger: logger.error(err_msg)
|
|
544
|
+
raise PgsError(err_msg)
|
|
545
|
+
|
|
546
|
+
if algo_T2 not in ('fft', 'FFT', 'classic', 'CLASSIC', 'deterministic', 'DETERMINISTIC'):
|
|
547
|
+
err_msg = f"{fname}: `algo_T2` invalid, should be 'fft' (default) or 'classic' or 'deterministic'"
|
|
548
|
+
if logger: logger.error(err_msg)
|
|
549
|
+
raise PgsError(err_msg)
|
|
550
|
+
|
|
551
|
+
# Ignore covariance model if 'algo' is deterministic for T1, T2
|
|
552
|
+
if algo_T1 in ('deterministic', 'DETERMINISTIC'):
|
|
553
|
+
cov_model_T1 = None
|
|
554
|
+
|
|
555
|
+
if algo_T2 in ('deterministic', 'DETERMINISTIC'):
|
|
556
|
+
cov_model_T2 = None
|
|
557
|
+
|
|
558
|
+
# Set space dimension (of grid) according to covariance model for T1
|
|
559
|
+
d = 0
|
|
560
|
+
if cov_model_T1 is None:
|
|
561
|
+
if algo_T1 not in ('deterministic', 'DETERMINISTIC'):
|
|
562
|
+
err_msg = f"{fname}: `cov_model_T1` is `None`, then `algo_T1` must be 'deterministic'"
|
|
563
|
+
if logger: logger.error(err_msg)
|
|
564
|
+
raise PgsError(err_msg)
|
|
565
|
+
|
|
566
|
+
elif isinstance(cov_model_T1, gcm.CovModel1D):
|
|
567
|
+
d = 1
|
|
568
|
+
elif isinstance(cov_model_T1, gcm.CovModel2D):
|
|
569
|
+
d = 2
|
|
570
|
+
elif isinstance(cov_model_T1, gcm.CovModel3D):
|
|
571
|
+
d = 3
|
|
572
|
+
else:
|
|
573
|
+
err_msg = f'{fname}: `cov_model_T1` invalid, should be a class `geone.covModel.CovModel1D`, `geone.covModel.CovModel2D` or `geone.covModel.CovModel3D`'
|
|
574
|
+
if logger: logger.error(err_msg)
|
|
575
|
+
raise PgsError(err_msg)
|
|
576
|
+
|
|
577
|
+
if cov_model_T2 is None:
|
|
578
|
+
if algo_T2 not in ('deterministic', 'DETERMINISTIC'):
|
|
579
|
+
err_msg = f"{fname}: `cov_model_T2` is `None`, then `algo_T2` must be 'deterministic'"
|
|
580
|
+
if logger: logger.error(err_msg)
|
|
581
|
+
raise PgsError(err_msg)
|
|
582
|
+
|
|
583
|
+
# if d == 0:
|
|
584
|
+
# err_msg = f'{fname}: `cov_model_T1` and `cov_model_T2` are `None`, at least one covariance model is required'
|
|
585
|
+
# if logger: logger.error(err_msg)
|
|
586
|
+
# raise PgsError(err_msg)
|
|
587
|
+
|
|
588
|
+
elif (d == 1 and not isinstance(cov_model_T2, gcm.CovModel1D)) or (d == 2 and not isinstance(cov_model_T2, gcm.CovModel2D)) or (d == 3 and not isinstance(cov_model_T2, gcm.CovModel3D)):
|
|
589
|
+
err_msg = f'{fname}: `cov_model_T1` and `cov_model_T2` not compatible (dimensions differ)'
|
|
590
|
+
if logger: logger.error(err_msg)
|
|
591
|
+
raise PgsError(err_msg)
|
|
592
|
+
|
|
593
|
+
if d == 0:
|
|
594
|
+
# Set space dimension (of grid) according to 'dimension'
|
|
595
|
+
if hasattr(dimension, '__len__'):
|
|
596
|
+
d = len(dimension)
|
|
597
|
+
else:
|
|
598
|
+
d = 1
|
|
599
|
+
|
|
600
|
+
# Check argument 'dimension'
|
|
601
|
+
if hasattr(dimension, '__len__') and len(dimension) != d:
|
|
602
|
+
err_msg = f'{fname}: `dimension` of incompatible length'
|
|
603
|
+
if logger: logger.error(err_msg)
|
|
604
|
+
raise PgsError(err_msg)
|
|
605
|
+
|
|
606
|
+
if d == 1:
|
|
607
|
+
grid_size = dimension
|
|
608
|
+
else:
|
|
609
|
+
grid_size = np.prod(dimension)
|
|
610
|
+
|
|
611
|
+
# Check (or set) argument 'spacing'
|
|
612
|
+
if spacing is None:
|
|
613
|
+
if d == 1:
|
|
614
|
+
spacing = 1.0
|
|
615
|
+
else:
|
|
616
|
+
spacing = tuple(np.ones(d))
|
|
617
|
+
else:
|
|
618
|
+
if hasattr(spacing, '__len__') and len(spacing) != d:
|
|
619
|
+
err_msg = f'{fname}: `spacing` of incompatible length'
|
|
620
|
+
if logger: logger.error(err_msg)
|
|
621
|
+
raise PgsError(err_msg)
|
|
622
|
+
|
|
623
|
+
# Check (or set) argument 'origin'
|
|
624
|
+
if origin is None:
|
|
625
|
+
if d == 1:
|
|
626
|
+
origin = 0.0
|
|
627
|
+
else:
|
|
628
|
+
origin = tuple(np.zeros(d))
|
|
629
|
+
else:
|
|
630
|
+
if hasattr(origin, '__len__') and len(origin) != d:
|
|
631
|
+
err_msg = f'{fname}: `origin` of incompatible length'
|
|
632
|
+
if logger: logger.error(err_msg)
|
|
633
|
+
raise PgsError(err_msg)
|
|
634
|
+
|
|
635
|
+
# if not cov_model_T1.is_stationary(): # prevent calculation if covariance model is not stationary
|
|
636
|
+
# if verbose > 0:
|
|
637
|
+
# print(f"ERROR ({fname}): `cov_model_T1` is not stationary")
|
|
638
|
+
|
|
639
|
+
# if not cov_model_T2.is_stationary(): # prevent calculation if covariance model is not stationary
|
|
640
|
+
# if verbose > 0:
|
|
641
|
+
# print(f"ERROR ({fname}): `cov_model_T2` is not stationary")
|
|
642
|
+
|
|
643
|
+
# Compute meshgrid over simulation domain if needed (see below)
|
|
644
|
+
if ('mean' in params_T1.keys() and callable(params_T1['mean'])) or ('var' in params_T1.keys() and callable(params_T1['var'])) \
|
|
645
|
+
or ('mean' in params_T2.keys() and callable(params_T2['mean'])) or ('var' in params_T2.keys() and callable(params_T2['var'])):
|
|
646
|
+
if d == 1:
|
|
647
|
+
xi = origin + spacing*(0.5+np.arange(dimension)) # x-coordinate of cell center
|
|
648
|
+
elif d == 2:
|
|
649
|
+
xi = origin[0] + spacing[0]*(0.5+np.arange(dimension[0])) # x-coordinate of cell center
|
|
650
|
+
yi = origin[1] + spacing[1]*(0.5+np.arange(dimension[1])) # y-coordinate of cell center
|
|
651
|
+
yyi, xxi = np.meshgrid(yi, xi, indexing='ij')
|
|
652
|
+
elif d == 3:
|
|
653
|
+
xi = origin[0] + spacing[0]*(0.5+np.arange(dimension[0])) # x-coordinate of cell center
|
|
654
|
+
yi = origin[1] + spacing[1]*(0.5+np.arange(dimension[1])) # y-coordinate of cell center
|
|
655
|
+
zi = origin[2] + spacing[2]*(0.5+np.arange(dimension[2])) # z-coordinate of cell center
|
|
656
|
+
zzi, yyi, xxi = np.meshgrid(zi, yi, xi, indexing='ij')
|
|
657
|
+
|
|
658
|
+
# Set mean_T1 (as array) from params_T1
|
|
659
|
+
if 'mean' not in params_T1.keys():
|
|
660
|
+
mean_T1 = np.array([0.0])
|
|
661
|
+
else:
|
|
662
|
+
mean_T1 = params_T1['mean']
|
|
663
|
+
if mean_T1 is None:
|
|
664
|
+
mean_T1 = np.array([0.0])
|
|
665
|
+
elif callable(mean_T1):
|
|
666
|
+
if d == 1:
|
|
667
|
+
mean_T1 = mean_T1(xi).reshape(-1) # replace function 'mean_T1' by its evaluation on the grid
|
|
668
|
+
elif d == 2:
|
|
669
|
+
mean_T1 = mean_T1(xxi, yyi).reshape(-1) # replace function 'mean_T1' by its evaluation on the grid
|
|
670
|
+
elif d == 3:
|
|
671
|
+
mean_T1 = mean_T1(xxi, yyi, zzi).reshape(-1) # replace function 'mean_T1' by its evaluation on the grid
|
|
672
|
+
else:
|
|
673
|
+
mean_T1 = np.asarray(mean_T1).reshape(-1)
|
|
674
|
+
if mean_T1.size not in (1, grid_size):
|
|
675
|
+
err_msg = f"{fname}: 'mean' parameter for T1 (in `params_T1`) has incompatible size"
|
|
676
|
+
if logger: logger.error(err_msg)
|
|
677
|
+
raise PgsError(err_msg)
|
|
678
|
+
|
|
679
|
+
# Set var_T1 (as array) from params_T1, if given
|
|
680
|
+
var_T1 = None
|
|
681
|
+
if 'var' in params_T1.keys():
|
|
682
|
+
var_T1 = params_T1['var']
|
|
683
|
+
if var_T1 is not None:
|
|
684
|
+
if callable(var_T1):
|
|
685
|
+
if d == 1:
|
|
686
|
+
var_T1 = var_T1(xi).reshape(-1) # replace function 'var_T1' by its evaluation on the grid
|
|
687
|
+
elif d == 2:
|
|
688
|
+
var_T1 = var_T1(xxi, yyi).reshape(-1) # replace function 'var_T1' by its evaluation on the grid
|
|
689
|
+
elif d == 3:
|
|
690
|
+
var_T1 = var_T1(xxi, yyi, zzi).reshape(-1) # replace function 'var_T1' by its evaluation on the grid
|
|
691
|
+
else:
|
|
692
|
+
var_T1 = np.asarray(var_T1).reshape(-1)
|
|
693
|
+
if var_T1.size not in (1, grid_size):
|
|
694
|
+
err_msg = f"{fname}: 'var' parameter for T1 (in `params_T1`) has incompatible size"
|
|
695
|
+
if logger: logger.error(err_msg)
|
|
696
|
+
raise PgsError(err_msg)
|
|
697
|
+
|
|
698
|
+
# Set mean_T2 (as array) from params_T2
|
|
699
|
+
if 'mean' not in params_T2.keys():
|
|
700
|
+
mean_T2 = np.array([0.0])
|
|
701
|
+
else:
|
|
702
|
+
mean_T2 = params_T2['mean']
|
|
703
|
+
if mean_T2 is None:
|
|
704
|
+
mean_T2 = np.array([0.0])
|
|
705
|
+
elif callable(mean_T2):
|
|
706
|
+
if d == 1:
|
|
707
|
+
mean_T2 = mean_T2(xi).reshape(-1) # replace function 'mean_T2' by its evaluation on the grid
|
|
708
|
+
elif d == 2:
|
|
709
|
+
mean_T2 = mean_T2(xxi, yyi).reshape(-1) # replace function 'mean_T2' by its evaluation on the grid
|
|
710
|
+
elif d == 3:
|
|
711
|
+
mean_T2 = mean_T2(xxi, yyi, zzi).reshape(-1) # replace function 'mean_T2' by its evaluation on the grid
|
|
712
|
+
else:
|
|
713
|
+
mean_T2 = np.asarray(mean_T2).reshape(-1)
|
|
714
|
+
if mean_T2.size not in (1, grid_size):
|
|
715
|
+
err_msg = f"{fname}: 'mean' parameter for T2 (in `params_T2`) has incompatible size"
|
|
716
|
+
if logger: logger.error(err_msg)
|
|
717
|
+
raise PgsError(err_msg)
|
|
718
|
+
|
|
719
|
+
# Set var_T2 (as array) from params_T2, if given
|
|
720
|
+
var_T2 = None
|
|
721
|
+
if 'var' in params_T2.keys():
|
|
722
|
+
var_T2 = params_T2['var']
|
|
723
|
+
if var_T2 is not None:
|
|
724
|
+
if callable(var_T2):
|
|
725
|
+
if d == 1:
|
|
726
|
+
var_T2 = var_T2(xi).reshape(-1) # replace function 'var_T2' by its evaluation on the grid
|
|
727
|
+
elif d == 2:
|
|
728
|
+
var_T2 = var_T2(xxi, yyi).reshape(-1) # replace function 'var_T2' by its evaluation on the grid
|
|
729
|
+
elif d == 3:
|
|
730
|
+
var_T2 = var_T2(xxi, yyi, zzi).reshape(-1) # replace function 'var_T2' by its evaluation on the grid
|
|
731
|
+
else:
|
|
732
|
+
var_T2 = np.asarray(var_T2).reshape(-1)
|
|
733
|
+
if var_T2.size not in (1, grid_size):
|
|
734
|
+
err_msg = f"{fname}: 'var' parameter for T2 (in `params_T2`) has incompatible size"
|
|
735
|
+
if logger: logger.error(err_msg)
|
|
736
|
+
raise PgsError(err_msg)
|
|
737
|
+
|
|
738
|
+
# Note: format of data (x, v) not checked !
|
|
739
|
+
|
|
740
|
+
if x is None:
|
|
741
|
+
if v is not None:
|
|
742
|
+
err_msg = f'{fname}: `x` is not given (`None`) but `v` is given (not `None`)'
|
|
743
|
+
if logger: logger.error(err_msg)
|
|
744
|
+
raise PgsError(err_msg)
|
|
745
|
+
|
|
746
|
+
else:
|
|
747
|
+
# Preparation for conditional case
|
|
748
|
+
if v is None:
|
|
749
|
+
err_msg = f'{fname}: `x` is given (not `None`) but `v` is not given (`None`)'
|
|
750
|
+
if logger: logger.error(err_msg)
|
|
751
|
+
raise PgsError(err_msg)
|
|
752
|
+
|
|
753
|
+
x = np.asarray(x, dtype='float').reshape(-1, d) # cast in d-dimensional array if needed
|
|
754
|
+
v = np.asarray(v, dtype='float').reshape(-1) # cast in 1-dimensional array if needed
|
|
755
|
+
if len(v) != x.shape[0]:
|
|
756
|
+
err_msg = f'{fname}: length of `v` is not valid'
|
|
757
|
+
if logger: logger.error(err_msg)
|
|
758
|
+
raise PgsError(err_msg)
|
|
759
|
+
|
|
760
|
+
# Compute
|
|
761
|
+
# indc: node index of conditioning node (nearest node),
|
|
762
|
+
# rounded to lower index if between two grid node and index is positive
|
|
763
|
+
indc_f = (x-origin)/spacing
|
|
764
|
+
indc = indc_f.astype(int)
|
|
765
|
+
indc = indc - 1 * np.all((indc == indc_f, indc > 0), axis=0)
|
|
766
|
+
if d == 1:
|
|
767
|
+
indc = 1 * indc[:, 0] # multiply by 1.0 makes a copy of the array !
|
|
768
|
+
elif d == 2:
|
|
769
|
+
indc = indc[:, 0] + dimension[0] * indc[:, 1]
|
|
770
|
+
elif d == 3:
|
|
771
|
+
indc = indc[:, 0] + dimension[0] * (indc[:, 1] + dimension[1] * indc[:, 2])
|
|
772
|
+
indc_unique, indc_inv = np.unique(indc, return_inverse=True)
|
|
773
|
+
if len(indc_unique) != len(x):
|
|
774
|
+
if np.any([len(np.unique(v[indc_inv==j])) > 1 for j in range(len(indc_unique))]):
|
|
775
|
+
err_msg = f'{fname}: more than one conditioning point fall in a same grid cell and have different conditioning values'
|
|
776
|
+
if logger: logger.error(err_msg)
|
|
777
|
+
raise PgsError(err_msg)
|
|
778
|
+
|
|
779
|
+
else:
|
|
780
|
+
if verbose > 0:
|
|
781
|
+
if logger:
|
|
782
|
+
logger.warning(f'{fname}: more than one conditioning point fall in a same grid cell with same conditioning value (consistent)')
|
|
783
|
+
else:
|
|
784
|
+
print(f'{fname}: WARNING: more than one conditioning point fall in a same grid cell with same conditioning value (consistent)')
|
|
785
|
+
x = np.array([x[indc_inv==j][0] for j in range(len(indc_unique))])
|
|
786
|
+
v = np.array([v[indc_inv==j][0] for j in range(len(indc_unique))])
|
|
787
|
+
|
|
788
|
+
# Number of conditioning points
|
|
789
|
+
npt = x.shape[0]
|
|
790
|
+
#
|
|
791
|
+
# Get index in mean_T1 for each conditioning point
|
|
792
|
+
x_mean_T1_grid_ind = None
|
|
793
|
+
if mean_T1.size == 1:
|
|
794
|
+
x_mean_T1_grid_ind = np.zeros(npt, dtype='int')
|
|
795
|
+
else:
|
|
796
|
+
indc_f = (x-origin)/spacing
|
|
797
|
+
indc = indc_f.astype(int)
|
|
798
|
+
indc = indc - 1 * np.all((indc == indc_f, indc > 0), axis=0)
|
|
799
|
+
if d == 1:
|
|
800
|
+
x_mean_T1_grid_ind = 1 * indc[:, 0] # multiply by 1.0 makes a copy of the array !
|
|
801
|
+
elif d == 2:
|
|
802
|
+
x_mean_T1_grid_ind = indc[:, 0] + dimension[0] * indc[:, 1]
|
|
803
|
+
elif d == 3:
|
|
804
|
+
x_mean_T1_grid_ind = indc[:, 0] + dimension[0] * (indc[:, 1] + dimension[1] * indc[:, 2])
|
|
805
|
+
|
|
806
|
+
# Get index in var_T1 (if not None) for each conditioning point
|
|
807
|
+
if var_T1 is not None:
|
|
808
|
+
if var_T1.size == 1:
|
|
809
|
+
x_var_T1_grid_ind = np.zeros(npt, dtype='int')
|
|
810
|
+
else:
|
|
811
|
+
if x_mean_T1_grid_ind is not None:
|
|
812
|
+
x_var_T1_grid_ind = x_mean_T1_grid_ind
|
|
813
|
+
else:
|
|
814
|
+
indc_f = (x-origin)/spacing
|
|
815
|
+
indc = indc_f.astype(int)
|
|
816
|
+
indc = indc - 1 * np.all((indc == indc_f, indc > 0), axis=0)
|
|
817
|
+
if d == 1:
|
|
818
|
+
x_var_T1_grid_ind = 1 * indc[:, 0] # multiply by 1.0 makes a copy of the array !
|
|
819
|
+
elif d == 2:
|
|
820
|
+
x_var_T1_grid_ind = indc[:, 0] + dimension[0] * indc[:, 1]
|
|
821
|
+
elif d == 3:
|
|
822
|
+
x_var_T1_grid_ind = indc[:, 0] + dimension[0] * (indc[:, 1] + dimension[1] * indc[:, 2])
|
|
823
|
+
|
|
824
|
+
# Get index in mean_T2 for each conditioning point
|
|
825
|
+
x_mean_T2_grid_ind = None
|
|
826
|
+
if mean_T2.size == 1:
|
|
827
|
+
x_mean_T2_grid_ind = np.zeros(npt, dtype='int')
|
|
828
|
+
else:
|
|
829
|
+
indc_f = (x-origin)/spacing
|
|
830
|
+
indc = indc_f.astype(int)
|
|
831
|
+
indc = indc - 1 * np.all((indc == indc_f, indc > 0), axis=0)
|
|
832
|
+
if d == 1:
|
|
833
|
+
x_mean_T2_grid_ind = 1 * indc[:, 0] # multiply by 1.0 makes a copy of the array !
|
|
834
|
+
elif d == 2:
|
|
835
|
+
x_mean_T2_grid_ind = indc[:, 0] + dimension[0] * indc[:, 1]
|
|
836
|
+
elif d == 3:
|
|
837
|
+
x_mean_T2_grid_ind = indc[:, 0] + dimension[0] * (indc[:, 1] + dimension[1] * indc[:, 2])
|
|
838
|
+
|
|
839
|
+
# Get index in var_T2 (if not None) for each conditioning point
|
|
840
|
+
if var_T2 is not None:
|
|
841
|
+
if var_T2.size == 1:
|
|
842
|
+
x_var_T2_grid_ind = np.zeros(npt, dtype='int')
|
|
843
|
+
else:
|
|
844
|
+
if x_mean_T2_grid_ind is not None:
|
|
845
|
+
x_var_T2_grid_ind = x_mean_T2_grid_ind
|
|
846
|
+
else:
|
|
847
|
+
indc_f = (x-origin)/spacing
|
|
848
|
+
indc = indc_f.astype(int)
|
|
849
|
+
indc = indc - 1 * np.all((indc == indc_f, indc > 0), axis=0)
|
|
850
|
+
if d == 1:
|
|
851
|
+
x_var_T2_grid_ind = 1 * indc[:, 0] # multiply by 1.0 makes a copy of the array !
|
|
852
|
+
elif d == 2:
|
|
853
|
+
x_var_T2_grid_ind = indc[:, 0] + dimension[0] * indc[:, 1]
|
|
854
|
+
elif d == 3:
|
|
855
|
+
x_var_T2_grid_ind = indc[:, 0] + dimension[0] * (indc[:, 1] + dimension[1] * indc[:, 2])
|
|
856
|
+
|
|
857
|
+
# Get covariance function for T1, T2 and Y, and their evaluation at 0
|
|
858
|
+
if cov_model_T1 is not None:
|
|
859
|
+
cov_func_T1 = cov_model_T1.func() # covariance function
|
|
860
|
+
cov0_T1 = cov_func_T1(np.zeros(d))
|
|
861
|
+
if cov_model_T2 is not None:
|
|
862
|
+
cov_func_T2 = cov_model_T2.func() # covariance function
|
|
863
|
+
cov0_T2 = cov_func_T2(np.zeros(d))
|
|
864
|
+
|
|
865
|
+
if cov_model_T1 is not None:
|
|
866
|
+
# Set kriging matrix for T1 (mat_T1) of order npt, "over every conditioining point"
|
|
867
|
+
mat_T1 = np.ones((npt, npt))
|
|
868
|
+
for i in range(npt-1):
|
|
869
|
+
# lag between x[i] and x[j], j=i+1, ..., npt-1
|
|
870
|
+
h = x[(i+1):] - x[i]
|
|
871
|
+
cov_h_T1 = cov_func_T1(h)
|
|
872
|
+
mat_T1[i, (i+1):npt] = cov_h_T1
|
|
873
|
+
mat_T1[(i+1):npt, i] = cov_h_T1
|
|
874
|
+
mat_T1[i, i] = cov0_T1
|
|
875
|
+
|
|
876
|
+
mat_T1[-1,-1] = cov0_T1
|
|
877
|
+
|
|
878
|
+
if var_T1 is not None:
|
|
879
|
+
varUpdate = np.sqrt(var_T1[x_var_T1_grid_ind]/cov0_T1)
|
|
880
|
+
mat_T1 = varUpdate*(mat_T1.T*varUpdate).T
|
|
881
|
+
|
|
882
|
+
if cov_model_T2 is not None:
|
|
883
|
+
# Set kriging matrix for T2 (mat_T2) of order npt, "over every conditioining point"
|
|
884
|
+
mat_T2 = np.ones((npt, npt))
|
|
885
|
+
for i in range(npt-1):
|
|
886
|
+
# lag between x[i] and x[j], j=i+1, ..., npt-1
|
|
887
|
+
h = x[(i+1):] - x[i]
|
|
888
|
+
cov_h_T2 = cov_func_T2(h)
|
|
889
|
+
mat_T2[i, (i+1):npt] = cov_h_T2
|
|
890
|
+
mat_T2[(i+1):npt, i] = cov_h_T2
|
|
891
|
+
mat_T2[i, i] = cov0_T2
|
|
892
|
+
|
|
893
|
+
mat_T2[-1,-1] = cov0_T2
|
|
894
|
+
|
|
895
|
+
if var_T2 is not None:
|
|
896
|
+
varUpdate = np.sqrt(var_T2[x_var_T2_grid_ind]/cov0_T2)
|
|
897
|
+
mat_T2 = varUpdate*(mat_T2.T*varUpdate).T
|
|
898
|
+
|
|
899
|
+
# Set (again if given) default parameter 'mean' and 'var' for T1, T2
|
|
900
|
+
if cov_model_T1 is not None:
|
|
901
|
+
params_T1['mean'] = mean_T1
|
|
902
|
+
params_T1['var'] = var_T1
|
|
903
|
+
else:
|
|
904
|
+
if mean_T1.size == grid_size:
|
|
905
|
+
params_T1['mean'] = mean_T1.reshape(*dimension[::-1])
|
|
906
|
+
else:
|
|
907
|
+
params_T1['mean'] = mean_T1 * np.ones(dimension[::-1])
|
|
908
|
+
if cov_model_T2 is not None:
|
|
909
|
+
params_T2['mean'] = mean_T2
|
|
910
|
+
params_T2['var'] = var_T2
|
|
911
|
+
else:
|
|
912
|
+
if mean_T2.size == grid_size:
|
|
913
|
+
params_T2['mean'] = mean_T2.reshape(*dimension[::-1])
|
|
914
|
+
else:
|
|
915
|
+
params_T2['mean'] = mean_T2 * np.ones(dimension[::-1])
|
|
916
|
+
|
|
917
|
+
# Set default parameter 'verbose' for params_T1, params_T2
|
|
918
|
+
if 'verbose' not in params_T1.keys():
|
|
919
|
+
params_T1['verbose'] = 0
|
|
920
|
+
# params_T1['verbose'] = verbose
|
|
921
|
+
if 'verbose' not in params_T2.keys():
|
|
922
|
+
params_T2['verbose'] = 0
|
|
923
|
+
# params_T2['verbose'] = verbose
|
|
924
|
+
|
|
925
|
+
# Initialization for output
|
|
926
|
+
Z = []
|
|
927
|
+
if full_output:
|
|
928
|
+
T1 = []
|
|
929
|
+
T2 = []
|
|
930
|
+
n_cond_ok = []
|
|
931
|
+
|
|
932
|
+
for ireal in range(nreal):
|
|
933
|
+
# Generate ireal-th realization
|
|
934
|
+
if verbose > 1:
|
|
935
|
+
if logger:
|
|
936
|
+
logger.info(f'{fname}: simulation {ireal+1} of {nreal}...')
|
|
937
|
+
else:
|
|
938
|
+
print(f'{fname}: simulation {ireal+1} of {nreal}...')
|
|
939
|
+
for ntry in range(ntry_max):
|
|
940
|
+
sim_ok = True
|
|
941
|
+
nhd_ok = [] # to be appended for full output...
|
|
942
|
+
if verbose > 2 and ntry > 0:
|
|
943
|
+
if logger:
|
|
944
|
+
logger.info(f'{fname}: ... new trial ({ntry+1} of {ntry_max}) for simulation {ireal+1} of {nreal}...')
|
|
945
|
+
else:
|
|
946
|
+
print(f'{fname}: ... new trial ({ntry+1} of {ntry_max}) for simulation {ireal+1} of {nreal}...')
|
|
947
|
+
if x is None:
|
|
948
|
+
# Unconditional case
|
|
949
|
+
# ------------------
|
|
950
|
+
# Generate T1 (one real)
|
|
951
|
+
if cov_model_T1 is not None:
|
|
952
|
+
try:
|
|
953
|
+
sim_T1 = multiGaussian.multiGaussianRun(
|
|
954
|
+
cov_model_T1, dimension, spacing, origin,
|
|
955
|
+
mode='simulation', algo=algo_T1, output_mode='array',
|
|
956
|
+
**params_T1, nreal=1)
|
|
957
|
+
except:
|
|
958
|
+
sim_ok = False
|
|
959
|
+
if verbose > 2:
|
|
960
|
+
if logger:
|
|
961
|
+
logger.info(f'{fname}: ... simulation of T1 failed')
|
|
962
|
+
else:
|
|
963
|
+
print(f'{fname}: ... simulation of T1 failed')
|
|
964
|
+
continue
|
|
965
|
+
# except Exception as exc:
|
|
966
|
+
# err_msg = f'{fname}: simulation of T1 failed'
|
|
967
|
+
# if logger: logger.error(err_msg)
|
|
968
|
+
# raise PgsError(err_msg) from exc
|
|
969
|
+
|
|
970
|
+
else:
|
|
971
|
+
sim_T1 = params_T1['mean'].reshape(1,*dimension[::-1])
|
|
972
|
+
# -> sim_T1: nd-array of shape
|
|
973
|
+
# (1, dimension) (for T1 in 1D)
|
|
974
|
+
# (1, dimension[1], dimension[0]) (for T1 in 2D)
|
|
975
|
+
# (1, dimension[2], dimension[1], dimension[0]) (for T1 in 3D)
|
|
976
|
+
|
|
977
|
+
# Generate T2 (one real)
|
|
978
|
+
if cov_model_T2 is not None:
|
|
979
|
+
try:
|
|
980
|
+
sim_T2 = multiGaussian.multiGaussianRun(
|
|
981
|
+
cov_model_T2, dimension, spacing, origin,
|
|
982
|
+
mode='simulation', algo=algo_T2, output_mode='array',
|
|
983
|
+
**params_T2, nreal=1)
|
|
984
|
+
except:
|
|
985
|
+
sim_ok = False
|
|
986
|
+
if verbose > 2:
|
|
987
|
+
if logger:
|
|
988
|
+
logger.info(f'{fname}: ... simulation of T2 failed')
|
|
989
|
+
else:
|
|
990
|
+
print(f'{fname}: ... simulation of T2 failed')
|
|
991
|
+
continue
|
|
992
|
+
# except Exception as exc:
|
|
993
|
+
# err_msg = f'{fname}: simulation of T2 failed'
|
|
994
|
+
# if logger: logger.error(err_msg)
|
|
995
|
+
# raise PgsError(err_msg) from exc
|
|
996
|
+
|
|
997
|
+
else:
|
|
998
|
+
sim_T2 = params_T2['mean'].reshape(1,*dimension[::-1])
|
|
999
|
+
# -> sim_T2: nd-array of shape
|
|
1000
|
+
# (1, dimension) (for T2 in 1D)
|
|
1001
|
+
# (1, dimension[1], dimension[0]) (for T2 in 2D)
|
|
1002
|
+
# (1, dimension[2], dimension[1], dimension[0]) (for T2 in 3D)
|
|
1003
|
+
|
|
1004
|
+
else:
|
|
1005
|
+
# Conditional case
|
|
1006
|
+
# ----------------
|
|
1007
|
+
v_T = np.zeros((npt, 2))
|
|
1008
|
+
# Initialize: unconditional simulation of T1 at x (values in v_T[:,0])
|
|
1009
|
+
ind = np.random.permutation(npt)
|
|
1010
|
+
for j, k in enumerate(ind):
|
|
1011
|
+
if cov_model_T1 is not None:
|
|
1012
|
+
# Simulate value at x[k] (= x[ind[j]]), conditionally to the previous ones
|
|
1013
|
+
# Solve the kriging system (for T1)
|
|
1014
|
+
try:
|
|
1015
|
+
w = np.linalg.solve(
|
|
1016
|
+
mat_T1[ind[:j], :][:, ind[:j]], # kriging matrix
|
|
1017
|
+
mat_T1[ind[:j], ind[j]], # second member
|
|
1018
|
+
)
|
|
1019
|
+
except:
|
|
1020
|
+
sim_ok = False
|
|
1021
|
+
break
|
|
1022
|
+
|
|
1023
|
+
# Mean (kriged) value at x[k]
|
|
1024
|
+
mu_T1_k = mean_T1[x_mean_T1_grid_ind[k]] + (v_T[ind[:j], 0] - mean_T1[x_mean_T1_grid_ind[ind[:j]]]).dot(w)
|
|
1025
|
+
# Standard deviation (of kriging) at x[k]
|
|
1026
|
+
std_T1_k = np.sqrt(np.maximum(0, cov0_T1 - np.dot(w, mat_T1[ind[:j], ind[j]])))
|
|
1027
|
+
# Draw value in N(mu_T1_k, std_T1_k^2)
|
|
1028
|
+
v_T[k, 0] = np.random.normal(loc=mu_T1_k, scale=std_T1_k)
|
|
1029
|
+
else:
|
|
1030
|
+
v_T[k, 0] = mean_T1[x_mean_T1_grid_ind[k]]
|
|
1031
|
+
|
|
1032
|
+
if not sim_ok:
|
|
1033
|
+
if verbose > 2:
|
|
1034
|
+
if logger:
|
|
1035
|
+
logger.info(f'{fname}: ... cannot solve kriging system (for T1, initialization)')
|
|
1036
|
+
else:
|
|
1037
|
+
print(f'{fname}: ... cannot solve kriging system (for T1, initialization)')
|
|
1038
|
+
continue
|
|
1039
|
+
|
|
1040
|
+
# Initialize: unconditional simulation of T2 at x (values in v_T[:,1])
|
|
1041
|
+
ind = np.random.permutation(npt)
|
|
1042
|
+
for j, k in enumerate(ind):
|
|
1043
|
+
if cov_model_T2 is not None:
|
|
1044
|
+
# Simulate value at x[k] (= x[ind[j]]), conditionally to the previous ones
|
|
1045
|
+
# Solve the kriging system (for T2)
|
|
1046
|
+
try:
|
|
1047
|
+
w = np.linalg.solve(
|
|
1048
|
+
mat_T2[ind[:j], :][:, ind[:j]], # kriging matrix
|
|
1049
|
+
mat_T2[ind[:j], ind[j]], # second member
|
|
1050
|
+
)
|
|
1051
|
+
except:
|
|
1052
|
+
sim_ok = False
|
|
1053
|
+
break
|
|
1054
|
+
|
|
1055
|
+
# Mean (kriged) value at x[k]
|
|
1056
|
+
mu_T2_k = mean_T2[x_mean_T2_grid_ind[k]] + (v_T[ind[:j], 1] - mean_T2[x_mean_T2_grid_ind[ind[:j]]]).dot(w)
|
|
1057
|
+
# Standard deviation (of kriging) at x[k]
|
|
1058
|
+
std_T2_k = np.sqrt(np.maximum(0, cov0_T2 - np.dot(w, mat_T2[ind[:j], ind[j]])))
|
|
1059
|
+
# Draw value in N(mu_T2_k, std_T2_k^2)
|
|
1060
|
+
v_T[k, 1] = np.random.normal(loc=mu_T2_k, scale=std_T2_k)
|
|
1061
|
+
else:
|
|
1062
|
+
v_T[k, 1] = mean_T2[x_mean_T2_grid_ind[k]]
|
|
1063
|
+
|
|
1064
|
+
if not sim_ok:
|
|
1065
|
+
if verbose > 2:
|
|
1066
|
+
if logger:
|
|
1067
|
+
logger.info(f'{fname}: ... cannot solve kriging system (for T2, initialization)')
|
|
1068
|
+
else:
|
|
1069
|
+
print(f'{fname}: ... cannot solve kriging system (for T2, initialization)')
|
|
1070
|
+
continue
|
|
1071
|
+
|
|
1072
|
+
# Update simulated values v_T at x using Metropolis-Hasting (MH) algorithm
|
|
1073
|
+
v_T_k_new = np.zeros(2)
|
|
1074
|
+
stop_mh = False
|
|
1075
|
+
for nit in range(mh_iter_max):
|
|
1076
|
+
#hd_ok = np.array([flag_value(v_T[k, 0], v_T[k, 1]) == v[k] for k in range(npt)])
|
|
1077
|
+
hd_ok = flag_value(v_T[:, 0], v_T[:, 1]) == v
|
|
1078
|
+
nhd_ok.append(np.sum(hd_ok))
|
|
1079
|
+
if nit >= mh_iter_min:
|
|
1080
|
+
if nhd_ok[-1] == npt:
|
|
1081
|
+
stop_mh = True
|
|
1082
|
+
break
|
|
1083
|
+
else:
|
|
1084
|
+
# Set acceptation probability for bad case
|
|
1085
|
+
p_accept = accept_init * np.power(1.0 - nit/mh_iter_min, accept_pow)
|
|
1086
|
+
if verbose > 3:
|
|
1087
|
+
if logger:
|
|
1088
|
+
logger.info(f'{fname}: ... sim {ireal+1} of {nreal}: MH iter {nit+1} of {mh_iter_min}, {mh_iter_max}...')
|
|
1089
|
+
else:
|
|
1090
|
+
print(f'{fname}: ... sim {ireal+1} of {nreal}: MH iter {nit+1} of {mh_iter_min}, {mh_iter_max}...')
|
|
1091
|
+
ind = np.random.permutation(npt)
|
|
1092
|
+
for k in ind:
|
|
1093
|
+
if nit >= mh_iter_min and hd_ok[k]:
|
|
1094
|
+
#print('skip')
|
|
1095
|
+
continue
|
|
1096
|
+
#
|
|
1097
|
+
# Sequence of indexes without k
|
|
1098
|
+
indmat = np.hstack((np.arange(k), np.arange(k+1, npt)))
|
|
1099
|
+
# Simulate possible new value v_T_new at x[k], conditionally to all the ohter ones
|
|
1100
|
+
#
|
|
1101
|
+
if cov_model_T1 is not None:
|
|
1102
|
+
# Solve the kriging system for T1
|
|
1103
|
+
try:
|
|
1104
|
+
w = np.linalg.solve(
|
|
1105
|
+
mat_T1[indmat, :][:, indmat], # kriging matrix
|
|
1106
|
+
mat_T1[indmat, k], # second member
|
|
1107
|
+
)
|
|
1108
|
+
except:
|
|
1109
|
+
sim_ok = False
|
|
1110
|
+
if verbose > 2:
|
|
1111
|
+
if logger:
|
|
1112
|
+
logger.info(f'{fname}: ... cannot solve kriging system (for T1)')
|
|
1113
|
+
else:
|
|
1114
|
+
print(f'{fname}: ... cannot solve kriging system (for T1)')
|
|
1115
|
+
break
|
|
1116
|
+
#
|
|
1117
|
+
# Mean (kriged) value at x[k]
|
|
1118
|
+
mu_T1_k = mean_T1[x_mean_T1_grid_ind[k]] + (v_T[indmat, 0] - mean_T1[x_mean_T1_grid_ind[indmat]]).dot(w)
|
|
1119
|
+
# Standard deviation (of kriging) at x[k]
|
|
1120
|
+
std_T1_k = np.sqrt(np.maximum(0, cov0_T1 - np.dot(w, mat_T1[indmat, k])))
|
|
1121
|
+
# Draw value in N(mu, std^2)
|
|
1122
|
+
v_T_k_new[0] = np.random.normal(loc=mu_T1_k, scale=std_T1_k)
|
|
1123
|
+
else:
|
|
1124
|
+
v_T_k_new[0] = mean_T1[x_mean_T1_grid_ind[k]]
|
|
1125
|
+
#
|
|
1126
|
+
# Solve the kriging system for T2
|
|
1127
|
+
if cov_model_T2 is not None:
|
|
1128
|
+
try:
|
|
1129
|
+
w = np.linalg.solve(
|
|
1130
|
+
mat_T2[indmat, :][:, indmat], # kriging matrix
|
|
1131
|
+
mat_T2[indmat, k], # second member
|
|
1132
|
+
)
|
|
1133
|
+
except:
|
|
1134
|
+
sim_ok = False
|
|
1135
|
+
if verbose > 2:
|
|
1136
|
+
if logger:
|
|
1137
|
+
logger.info(f'{fname}: ... cannot solve kriging system (for T2)')
|
|
1138
|
+
else:
|
|
1139
|
+
print(f'{fname}: ... cannot solve kriging system (for T2)')
|
|
1140
|
+
break
|
|
1141
|
+
#
|
|
1142
|
+
# Mean (kriged) value at x[k]
|
|
1143
|
+
mu_T2_k = mean_T2[x_mean_T2_grid_ind[k]] + (v_T[indmat, 1] - mean_T2[x_mean_T2_grid_ind[indmat]]).dot(w)
|
|
1144
|
+
# Standard deviation (of kriging) at x[k]
|
|
1145
|
+
std_T2_k = np.sqrt(np.maximum(0, cov0_T2 - np.dot(w, mat_T2[indmat, k])))
|
|
1146
|
+
# Draw value in N(mu, std^2)
|
|
1147
|
+
v_T_k_new[1] = np.random.normal(loc=mu_T2_k, scale=std_T2_k)
|
|
1148
|
+
else:
|
|
1149
|
+
v_T_k_new[1] = mean_T2[x_mean_T2_grid_ind[k]]
|
|
1150
|
+
#
|
|
1151
|
+
# Accept or not the new candidate
|
|
1152
|
+
if flag_value(v_T_k_new[0], v_T_k_new[1]) == v[k]:
|
|
1153
|
+
# Accept the new candidate
|
|
1154
|
+
v_T[k] = v_T_k_new
|
|
1155
|
+
elif nit < mh_iter_min and np.random.random() < p_accept:
|
|
1156
|
+
# Accept the new candidate
|
|
1157
|
+
v_T[k] = v_T_k_new
|
|
1158
|
+
|
|
1159
|
+
if not sim_ok:
|
|
1160
|
+
break
|
|
1161
|
+
|
|
1162
|
+
if not sim_ok:
|
|
1163
|
+
continue
|
|
1164
|
+
|
|
1165
|
+
if not stop_mh:
|
|
1166
|
+
hd_ok = flag_value(v_T[:, 0], v_T[:, 1]) == v
|
|
1167
|
+
nhd_ok.append(np.sum(hd_ok))
|
|
1168
|
+
if nhd_ok[-1] != npt:
|
|
1169
|
+
# sim_ok kept to True
|
|
1170
|
+
if verbose > 2:
|
|
1171
|
+
if logger:
|
|
1172
|
+
logger.info(f'{fname}: ... conditioning failed')
|
|
1173
|
+
else:
|
|
1174
|
+
print(f'{fname}: ... conditioning failed')
|
|
1175
|
+
|
|
1176
|
+
if ntry < ntry_max - 1 or not retrieve_real_anyway:
|
|
1177
|
+
continue
|
|
1178
|
+
|
|
1179
|
+
# Generate T1 conditional to (x, v_T[:, 0]) (one real)
|
|
1180
|
+
if cov_model_T1 is not None:
|
|
1181
|
+
try:
|
|
1182
|
+
sim_T1 = multiGaussian.multiGaussianRun(
|
|
1183
|
+
cov_model_T1, dimension, spacing, origin, x=x, v=v_T[:, 0],
|
|
1184
|
+
mode='simulation', algo=algo_T1, output_mode='array',
|
|
1185
|
+
**params_T1, nreal=1)
|
|
1186
|
+
except:
|
|
1187
|
+
sim_ok = False
|
|
1188
|
+
if verbose > 2:
|
|
1189
|
+
if logger:
|
|
1190
|
+
logger.info(f'{fname}: ... conditional simulation of T1 failed')
|
|
1191
|
+
else:
|
|
1192
|
+
print(f'{fname}: ... conditional simulation of T1 failed')
|
|
1193
|
+
continue
|
|
1194
|
+
|
|
1195
|
+
else:
|
|
1196
|
+
sim_T1 = params_T1['mean'].reshape(1,*dimension[::-1])
|
|
1197
|
+
# -> sim_T1: nd-array of shape
|
|
1198
|
+
# (1, dimension) (for T1 in 1D)
|
|
1199
|
+
# (1, dimension[1], dimension[0]) (for T1 in 2D)
|
|
1200
|
+
# (1, dimension[2], dimension[1], dimension[0]) (for T1 in 3D)
|
|
1201
|
+
|
|
1202
|
+
# Generate T2 conditional to (x, v_T[:, 1]) (one real)
|
|
1203
|
+
if cov_model_T2 is not None:
|
|
1204
|
+
try:
|
|
1205
|
+
sim_T2 = multiGaussian.multiGaussianRun(
|
|
1206
|
+
cov_model_T2, dimension, spacing, origin, x=x, v=v_T[:, 1],
|
|
1207
|
+
mode='simulation', algo=algo_T2, output_mode='array',
|
|
1208
|
+
**params_T2, nreal=1)
|
|
1209
|
+
except:
|
|
1210
|
+
sim_ok = False
|
|
1211
|
+
if verbose > 2:
|
|
1212
|
+
if logger:
|
|
1213
|
+
logger.info(f'{fname}: ... conditional simulation of T2 failed')
|
|
1214
|
+
else:
|
|
1215
|
+
print(f'{fname}: ... conditional simulation of T2 failed')
|
|
1216
|
+
continue
|
|
1217
|
+
else:
|
|
1218
|
+
sim_T2 = params_T2['mean'].reshape(1,*dimension[::-1])
|
|
1219
|
+
# -> sim_T2: nd-array of shape
|
|
1220
|
+
# (1, dimension) (for T2 in 1D)
|
|
1221
|
+
# (1, dimension[1], dimension[0]) (for T2 in 2D)
|
|
1222
|
+
# (1, dimension[2], dimension[1], dimension[0]) (for T2 in 3D)
|
|
1223
|
+
|
|
1224
|
+
# Generate Z (one real)
|
|
1225
|
+
if sim_ok:
|
|
1226
|
+
if x is not None:
|
|
1227
|
+
if nhd_ok[-1] != npt:
|
|
1228
|
+
if not retrieve_real_anyway:
|
|
1229
|
+
break
|
|
1230
|
+
else:
|
|
1231
|
+
if verbose > 0:
|
|
1232
|
+
if logger:
|
|
1233
|
+
logger.warning(f'{fname}: realization does not honoured all data, but retrieved anyway')
|
|
1234
|
+
else:
|
|
1235
|
+
print(f'{fname}: WARNING: realization does not honoured all data, but retrieved anyway')
|
|
1236
|
+
Z_real = flag_value(sim_T1[0], sim_T2[0])
|
|
1237
|
+
Z.append(Z_real)
|
|
1238
|
+
if full_output:
|
|
1239
|
+
T1.append(sim_T1[0])
|
|
1240
|
+
T2.append(sim_T2[0])
|
|
1241
|
+
n_cond_ok.append(np.asarray(nhd_ok))
|
|
1242
|
+
break
|
|
1243
|
+
|
|
1244
|
+
# Get Z
|
|
1245
|
+
if verbose > 0 and len(Z) < nreal:
|
|
1246
|
+
if logger:
|
|
1247
|
+
logger.warning(f'{fname}: some realization failed (missing)')
|
|
1248
|
+
else:
|
|
1249
|
+
print(f'{fname}: WARNING: some realization failed (missing)')
|
|
1250
|
+
Z = np.asarray(Z).reshape(len(Z), *np.atleast_1d(dimension)[::-1])
|
|
1251
|
+
|
|
1252
|
+
if full_output:
|
|
1253
|
+
T1 = np.asarray(T1).reshape(len(T1), *np.atleast_1d(dimension)[::-1])
|
|
1254
|
+
T2 = np.asarray(T2).reshape(len(T2), *np.atleast_1d(dimension)[::-1])
|
|
1255
|
+
return Z, T1, T2, n_cond_ok
|
|
1256
|
+
else:
|
|
1257
|
+
return Z
|
|
1258
|
+
# ----------------------------------------------------------------------------
|