7
7
"""
8
8
9
9
import warnings
10
+ from typing import Optional , Sequence
11
+
12
+ import gempy as gp
13
+
14
+ from gempy_engine .core .data .raw_arrays_solution import RawArraysSolution
15
+
10
16
try :
11
17
from scipy .spatial .distance import cdist
12
18
except ImportError :
13
19
warnings .warn ('scipy.spatial package is not installed.' )
14
20
15
21
import numpy as np
16
22
import pandas as pd
17
- from gempy_viewer import _plot
18
- from gempy_viewer import helpers , _visualization_2d
19
23
import matplotlib .cm as cm
20
24
import matplotlib .pyplot as plt
21
25
from copy import deepcopy
22
26
23
- class domain (object ):
24
27
25
- def __init__ (self , model , domain = None , data = None , set_mean = None ):
28
+ class Domain :
29
+ def __init__ (self , model_solutions : gp .data .Solutions , domain : Optional [Sequence ] = None , data = None , set_mean = None ):
26
30
27
31
# set model from a gempy solution
28
32
# TODO: Check if I actually need all this or if its easier to just get grid and lith of the solution
29
- self .sol = model
33
+ self .sol : RawArraysSolution = model_solutions . raw_arrays
30
34
31
35
# set kriging surfaces, basically in which lithologies to do all this, default is everything
32
36
# TODO: Maybe also allow to pass a gempy regular grid object
33
37
if domain is None :
34
38
domain = np .unique (self .sol .lith_block )
35
- self .set_domain (domain )
39
+ self .set_domain (
40
+ domain = domain ,
41
+ grid_values = model_solutions .octrees_output [- 1 ].grid_centers .regular_grid .original_values
42
+ )
36
43
37
44
# set data, default is None
38
45
# TODO: need to figure out a way to then set mean and variance for the SGS and SK
@@ -49,7 +56,7 @@ def __init__(self, model, domain=None, data=None, set_mean=None):
49
56
self .inp_var = np .var (data [:, 3 ])
50
57
self .inp_std = np .sqrt (self .inp_var )
51
58
52
- def set_domain (self , domain ):
59
+ def set_domain (self , domain : np . ndarray , grid_values : np . ndarray ):
53
60
"""
54
61
Method to cut domain by array of surfaces. Simply masking the lith_block with array of input lithologies
55
62
applying mask to grid.
@@ -63,11 +70,12 @@ def set_domain(self, domain):
63
70
self .domain = domain
64
71
65
72
# mask by array of input surfaces (by id, can be from different series)
73
+
66
74
self .mask = np .isin (self .sol .lith_block , self .domain )
67
75
68
76
# Apply mask to lith_block and grid
69
77
self .krig_lith = self .sol .lith_block [self .mask ]
70
- self .krig_grid = self . sol . grid . values [self .mask ]
78
+ self .krig_grid = grid_values [self .mask ]
71
79
72
80
def set_data (self , data ):
73
81
"""
@@ -86,7 +94,7 @@ def set_data(self, data):
86
94
self .data_df = pd .DataFrame (data = d )
87
95
88
96
89
- class variogram_model (object ):
97
+ class VariogramModel (object ):
90
98
91
99
# class containing all the variogram functionality
92
100
@@ -182,36 +190,35 @@ def plot(self, type_='variogram', show_parameters=True):
182
190
183
191
if show_parameters == True :
184
192
plt .axhline (self .sill , color = 'black' , lw = 1 )
185
- plt .text (self .range_ * 2 , self .sill , 'sill' , fontsize = 12 , va = 'center' , ha = 'center' , backgroundcolor = 'w' )
193
+ plt .text (self .range_ * 2 , self .sill , 'sill' , fontsize = 12 , va = 'center' , ha = 'center' , backgroundcolor = 'w' )
186
194
plt .axvline (self .range_ , color = 'black' , lw = 1 )
187
- plt .text (self .range_ , self .sill / 2 , 'range' , fontsize = 12 , va = 'center' , ha = 'center' , backgroundcolor = 'w' )
195
+ plt .text (self .range_ , self .sill / 2 , 'range' , fontsize = 12 , va = 'center' , ha = 'center' , backgroundcolor = 'w' )
188
196
189
197
if type_ == 'variogram' :
190
- d = np .arange (0 , self .range_ * 4 , self .range_ / 1000 )
198
+ d = np .arange (0 , self .range_ * 4 , self .range_ / 1000 )
191
199
plt .plot (d , self .calculate_semivariance (d ), label = self .theoretical_model + " variogram model" )
192
200
plt .ylabel ('semivariance' )
193
201
plt .title ('Variogram model' )
194
202
plt .legend ()
195
203
196
204
if type_ == 'covariance' :
197
- d = np .arange (0 , self .range_ * 4 , self .range_ / 1000 )
205
+ d = np .arange (0 , self .range_ * 4 , self .range_ / 1000 )
198
206
plt .plot (d , self .calculate_covariance (d ), label = self .theoretical_model + " covariance model" )
199
207
plt .ylabel ('covariance' )
200
208
plt .title ('Covariance model' )
201
209
plt .legend ()
202
210
203
211
if type_ == 'both' :
204
- d = np .arange (0 , self .range_ * 4 , self .range_ / 1000 )
212
+ d = np .arange (0 , self .range_ * 4 , self .range_ / 1000 )
205
213
plt .plot (d , self .calculate_semivariance (d ), label = self .theoretical_model + " variogram model" )
206
214
plt .plot (d , self .calculate_covariance (d ), label = self .theoretical_model + " covariance model" )
207
215
plt .ylabel ('semivariance/covariance' )
208
216
plt .title ('Models of spatial correlation' )
209
217
plt .legend ()
210
218
211
219
plt .xlabel ('lag distance' )
212
- plt .ylim (0 - self .sill / 20 , self .sill + self .sill / 20 )
213
- plt .xlim (0 , self .range_ * 4 )
214
-
220
+ plt .ylim (0 - self .sill / 20 , self .sill + self .sill / 20 )
221
+ plt .xlim (0 , self .range_ * 4 )
215
222
216
223
217
224
class field_solution (object ):
@@ -240,7 +247,7 @@ def plot_results(self, geo_data, prop='val', direction='y', result='interpolatio
240
247
Returns:
241
248
242
249
"""
243
- a = np .full_like (self .domain .mask , np .nan , dtype = np .double ) # array like lith_block but with nan if outside domain
250
+ a = np .full_like (self .domain .mask , np .nan , dtype = np .double ) # array like lith_block but with nan if outside domain
244
251
245
252
est_vals = self .results_df ['estimated value' ].values
246
253
est_var = self .results_df ['estimation variance' ].values
@@ -257,13 +264,13 @@ def plot_results(self, geo_data, prop='val', direction='y', result='interpolatio
257
264
else :
258
265
print ('prop must be val var or both' )
259
266
260
- #create plot object
267
+ # create plot object
261
268
p = _visualization_2d .PlotSolution (geo_data )
262
269
_a , _b , _c , extent_val , x , y = p ._slice (direction , cell_number )[:- 2 ]
263
270
264
- #colors
271
+ # colors
265
272
cmap = cm .get_cmap (cmap )
266
- cmap .set_bad (color = 'w' , alpha = alpha ) # define color and alpha for nan values
273
+ cmap .set_bad (color = 'w' , alpha = alpha ) # define color and alpha for nan values
267
274
268
275
# plot
269
276
if prop is not 'both' :
@@ -299,6 +306,7 @@ def plot_results(self, geo_data, prop='val', direction='y', result='interpolatio
299
306
helpers .add_colorbar (im2 , label = 'variance[]' )
300
307
plt .tight_layout ()
301
308
309
+
302
310
# TODO: check with new ordianry kriging and nugget effect
303
311
def simple_kriging (a , b , prop , var_mod , inp_mean ):
304
312
'''
@@ -320,11 +328,11 @@ def simple_kriging(a, b, prop, var_mod, inp_mean):
320
328
w = np .zeros ((shape ))
321
329
322
330
# Filling matrices with covariances based on calculated distances
323
- C [:shape , :shape ] = var_mod .calculate_covariance (b ) # ? cov or semiv
324
- c [:shape ] = var_mod .calculate_covariance (a ) # ? cov or semiv
331
+ C [:shape , :shape ] = var_mod .calculate_covariance (b ) # ? cov or semiv
332
+ c [:shape ] = var_mod .calculate_covariance (a ) # ? cov or semiv
325
333
326
334
# nugget effect for simple kriging - dont remember why i set this actively, should be the same
327
- #np.fill_diagonal(C, self.sill)
335
+ # np.fill_diagonal(C, self.sill)
328
336
329
337
# TODO: find way to check quality of matrix and solutions for instability
330
338
# Solve Kriging equations
@@ -337,6 +345,7 @@ def simple_kriging(a, b, prop, var_mod, inp_mean):
337
345
338
346
return result , pred_var
339
347
348
+
340
349
def ordinary_kriging (a , b , prop , var_mod ):
341
350
'''
342
351
Method for ordinary kriging calculation.
@@ -381,6 +390,7 @@ def ordinary_kriging(a, b, prop, var_mod):
381
390
382
391
return result , pred_var
383
392
393
+
384
394
def create_kriged_field (domain , variogram_model , distance_type = 'euclidian' ,
385
395
moving_neighbourhood = 'all' , kriging_type = 'OK' , n_closest_points = 20 ):
386
396
'''
@@ -449,14 +459,15 @@ def create_kriged_field(domain, variogram_model, distance_type='euclidian',
449
459
450
460
# create dataframe of results data for calling
451
461
d = {'X' : domain .krig_grid [:, 0 ], 'Y' : domain .krig_grid [:, 1 ], 'Z' : domain .krig_grid [:, 2 ],
452
- 'estimated value' : kriging_result_vals , 'estimation variance' : kriging_result_vars }
462
+ 'estimated value' : kriging_result_vals , 'estimation variance' : kriging_result_vars }
453
463
454
464
results_df = pd .DataFrame (data = d )
455
465
456
466
return field_solution (domain , variogram_model , results_df , field_type = 'interpolation' )
457
467
468
+
458
469
def create_gaussian_field (domain , variogram_model , distance_type = 'euclidian' ,
459
- moving_neighbourhood = 'all' , kriging_type = 'OK' , n_closest_points = 20 ):
470
+ moving_neighbourhood = 'all' , kriging_type = 'OK' , n_closest_points = 20 ):
460
471
'''
461
472
Method to create a kriged field over the defined grid of the gempy solution depending on the defined
462
473
input data (conditioning).
@@ -472,9 +483,9 @@ def create_gaussian_field(domain, variogram_model, distance_type='euclidian',
472
483
np .random .shuffle (shuffled_grid )
473
484
474
485
# append shuffled grid to input locations
475
- sgs_locations = np .vstack ((domain .data [:,:3 ],shuffled_grid ))
486
+ sgs_locations = np .vstack ((domain .data [:, :3 ], shuffled_grid ))
476
487
# create array for input properties
477
- sgs_prop_updating = domain .data [:,3 ] # use this and then always stack new ant end
488
+ sgs_prop_updating = domain .data [:, 3 ] # use this and then always stack new ant end
478
489
479
490
# container for estimation variances
480
491
estimation_var = np .zeros (len (shuffled_grid ))
@@ -493,9 +504,9 @@ def create_gaussian_field(domain, variogram_model, distance_type='euclidian',
493
504
for i in range (len (domain .krig_grid )):
494
505
# STEP 1: cut update distance matrix to correct size
495
506
# HAVE TO CHECK IF THIS IS REALLY CORRECT
496
- active_distance_matrix = dist_all_to_all [:active_data ,:active_data ]
497
- active_distance_vector = dist_all_to_all [:,active_data ] # basically next point to be simulated
498
- active_distance_vector = active_distance_vector [:active_data ] # cut to left or diagonal
507
+ active_distance_matrix = dist_all_to_all [:active_data , :active_data ]
508
+ active_distance_vector = dist_all_to_all [:, active_data ] # basically next point to be simulated
509
+ active_distance_vector = active_distance_vector [:active_data ] # cut to left or diagonal
499
510
500
511
# TODO: NEED PART FOR ZERO INPUT OR NO POINTS IN RANGE OR LESS THAN N POINTS
501
512
@@ -512,7 +523,7 @@ def create_gaussian_field(domain, variogram_model, distance_type='euclidian',
512
523
# This seems to work
513
524
if len (sgs_prop_updating ) <= n_closest_points :
514
525
a = active_distance_vector [:active_data ]
515
- b = active_distance_matrix [:active_data ,:active_data ]
526
+ b = active_distance_matrix [:active_data , :active_data ]
516
527
prop = sgs_prop_updating
517
528
518
529
# this does not # DAMN THIS STILL HAS ITSELF RIGHT? PROBLEM!
@@ -552,22 +563,19 @@ def create_gaussian_field(domain, variogram_model, distance_type='euclidian',
552
563
553
564
# append to prop:
554
565
sgs_prop_updating = np .append (sgs_prop_updating , estimate )
555
- estimation_var [i ]= var
566
+ estimation_var [i ] = var
556
567
557
568
# at end of loop: include simulated point for next step
558
569
active_data += 1
559
570
560
571
# delete original input data from results
561
- simulated_prop = sgs_prop_updating [len (domain .data [:,3 ]):] # check if this works like intended
572
+ simulated_prop = sgs_prop_updating [len (domain .data [:, 3 ]):] # check if this works like intended
562
573
563
574
# create dataframe of results data for calling
564
575
d = {'X' : shuffled_grid [:, 0 ], 'Y' : shuffled_grid [:, 1 ], 'Z' : shuffled_grid [:, 2 ],
565
576
'estimated value' : simulated_prop , 'estimation variance' : estimation_var }
566
577
567
578
results_df = pd .DataFrame (data = d )
568
- results_df = results_df .sort_values (['X' ,'Y' ,'Z' ])
579
+ results_df = results_df .sort_values (['X' , 'Y' , 'Z' ])
569
580
570
581
return field_solution (domain , variogram_model , results_df , field_type = 'simulation' )
571
-
572
-
573
-
0 commit comments