Source code for pysimfrac.src.analysis.geostats_variogram


import numpy as np
import skgstat as skg
import matplotlib.pylab as plt

from pysimfrac.src.general.helper_functions import print_error, print_warning

## Variogram is computed using scikit-gstat
## https://scikit-gstat.readthedocs.io
## Returns Variogram object
##
## Mirko Mälicke, Egil Möller, Helge David Schneider, & Sebastian Müller. (2021, May 28).
##
## mmaelicke/scikit-gstat: A scipy flavoured geostatistical variogram analysis toolbox (Version v0.6.0). Zenodo. http://doi.org/10.5281/zenodo.4835779
##
## 
[docs] def single_field_variogram(self, surface, num_samples, max_lag, num_lags, model): """ Compute the variogram of a single field using scikit-gstat Parameters -------------------- self : object simFrac Class surface : str Name of desired surface acf to plot. Options are 'aperture', 'top', or 'bottom' num_samples : int Number of random samples used to compute the variogram max_lag : int Maximum lag distance (unitless length). num_lags : int Number of lag bins. Default is 10 model : str See https://scikit-gstat.readthedocs.io for model details. Default is spherical Returns ------------- None Notes ----------------- scikit-gstat variogram object is attached to the simFrac object. Requesting more than 10,000 samples can take a while. """ if num_samples > 10000: print_warning("--> A LOT of samples were requested. We don't recomend more than 10,000. Just to let you know, this might take a while. Why don't you go get a coffee or maybe check your email. Okay?") index_x = np.random.randint(0, self.nx, num_samples) index_y = np.random.randint(0, self.ny, num_samples) indices = np.c_[index_y, index_x] if surface == "aperture": values = np.fromiter( (self.aperture[c[0], c[1]] for c in indices), dtype=float) elif surface == "top": values = np.fromiter((self.top[c[0], c[1]] for c in indices), dtype=float) elif surface == "bottom": values = np.fromiter((self.bottom[c[0], c[1]] for c in indices), dtype=float) else: print_error( f"Error. Unknown surface provided - {surface}. Acceptable surfaces are 'top', 'bottom', or 'aperture''" ) ## Make the variogram using SciKit - gstat self.variogram[surface] = skg.Variogram(indices, values, model = model, maxlag = max_lag, n_lags = num_lags)
[docs] def compute_variogram(self, surface = 'all', num_samples = 500, max_lag = None, num_lags = 10, model = 'spherical',): """ Compute the variogram of the surface using scikit-gstat. Parameters -------------------- self : object simFrac Class surface : str Name of desired surface acf to plot. Options are 'aperture', 'top', 'bottom', or 'all'. Default value is 'all' num_samples : int Number of random samples used to compute the variogram max_lag : int Maximum lag distance (unitless length). num_lags : int Number of lag bins. Default is 10 model : str See https://scikit-gstat.readthedocs.io for model details. Default is spherical Returns ------------- None Notes ----------------- scikit-gstat variogram object is attached to the simFrac object. Reference: Mirko Mälicke, Egil Möller, Helge David Schneider, & Sebastian Müller. (2021, May 28). mmaelicke/scikit-gstat: A scipy flavoured geostatistical variogram analysis toolbox (Version v0.6.0). Zenodo. http://doi.org/10.5281/zenodo.4835779 """ # default is to comput the correlation lengths for all 3 surfaces if surface == 'all': surfaces = ["aperture", "top", "bottom"] for sf in surfaces: print(f"\n--> Computing variogram of {sf} field.") #single_field_variogram(self, surface, num_samples, max_lag, num_lags, model) self.single_field_variogram(sf, num_samples, max_lag, num_lags, model) ## if a single surface is provided, just compute the correlation for that surface else: print(f"\n--> Computing variogram of {surface} field.") self.single_field_variogram(surface, num_samples, max_lag, num_lags, model)
[docs] def plot_variogram(self, surface="all", figname=None, show_lags = False): """ Creates a plot of the autocorrelation function for surfaces. Parameters -------------------- self : object simFrac Class surface : str Name of desired surface acf to plot. Options are 'aperture', 'top', 'bottom', or 'all'. Default value is 'all' figname : str Name of figure to be saved. If figname is None (default), then no figure is saved. show_lags : bool True / False plot variogram as a function of Lag (unitless) or Lag Distance (units of grid resolution) Returns -------------------- None Notes -------------------- None """ if surface == "all": fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(12, 4)) fig.suptitle(f'Variograms of Fracture Surfaces', fontsize=16) # Check for ACF for all surfaces surfaces = ["top", "bottom", "aperture"] for i, sf in enumerate(surfaces): # If the variogram hasn't been computed yet, exit if not self.variogram[sf]: print( f"variogram for {sf} field was not computed yet. Doing that now." ) self.compute_variogram(sf) ## Make subplot for current surface # self.variogram[sf].plot(axes = ax[i], grid = False) # get the parameters _bins = self.variogram[sf].bins _exp = self.variogram[sf].experimental x = np.linspace(0, np.nanmax(_bins), 100) # apply the model y = self.variogram[sf].transform(x) if show_lags: ax[i].plot(_bins, _exp, '.b', label = "Data") ax[i].plot(x, y, '-g', label = f"Model") ax[i].set_xlabel(f"Lag [-]", fontsize=18) else: ax[i].plot(_bins*self.h, _exp, '.b', label = "Data") ax[i].plot(x*self.h, y, '-g', label = f"Model") ax[i].set_xlabel(f"Lag Distance [{self.units}]", fontsize=18) # Set attributes ax[i].set_title(f'{sf}') ax[i].grid(True) if i == 0: ax[i].set_ylabel('Semivariogram', fontsize=18) if i == 2: ax[i].legend(fontsize = 18, loc = 4) else: # Check for variogram for specific surface if not self.variogram[surface]: print( f"variogram for {surface} field was not computed yet. Doing that now." ) self.compute_variogram(surface) fig, ax = plt.subplots(figsize=(10, 6)) fig.suptitle(f'Variogram of {surface} field', fontsize=24) # get the parameters _bins = self.variogram[surface].bins _exp = self.variogram[surface].experimental x = np.linspace(0, np.nanmax(_bins), 100) # apply the model y = self.variogram[surface].transform(x) if show_lags: ax.plot(_bins, _exp, '.b', markersize = 8, label = "Data") ax.plot(x, y, '-g', label = f"Model") ax.set_xlabel(f"Lag [-]", fontsize=18) else: ax.plot(_bins*self.h, _exp, '.b', markersize = 8, label = "Data") ax.plot(x*self.h, y, '-g', label = f"Model") ax.set_xlabel(f"Lag Distance [{self.units}]", fontsize=18) ax.set_ylabel('Semivariogram', fontsize=18) # ax.set_xlabel(f"Lag Distance [{self.units}]", fontsize=18) ax.legend(fontsize = 18, loc = 4) ax.grid(True) plt.xticks(fontsize = 14) plt.yticks(fontsize = 14) # Save figure if the user wants it if figname: print(f"\n--> Saving figure to file {figname}") plt.savefig(figname, dpi=150) return fig, ax