Gempy is an open source Python library for generating complete 3D structural geological models. The library is a complete development for creating geological models from interfaces, faults, and layer orientations, and it also associates the order of geological layers to represent rock intrusions and fault sequences.
Recommendation: Use NSDT Designer to quickly build programmable 3D scenes.
The geological modeling algorithm is based on generalized co-kriging interpolation and supports high-end Python math libraries such as Numpy, PyMC3, and Theano.
Gempy creates a mesh model that can be visualized as a 2D section using Matplotlib, or as a VTK object as a 3D geometric object, allowing representation of geological models on Paraview for custom slicing, filtering, transparency and styling.
This tutorial provides a basic example of a layered geological setup with 5 layers and 1 fault. To make this tutorial fully accessible to most users, we have created a supplemental tutorial on how to install Gempy on Windows using the Anaconda repository distribution.
The input files for this tutorial can be downloaded from this link.
1. Set up the Python environment
In this part, we import the libraries needed for this tutorial. The script requires Gempy as well as Numpy and Matplotlib. We configure Jupyter options after script cells to interactively represent Matplotlib figures (%matplotlib inline).
Note that warnings are just messages that the user must remember when running the script, and do not mean that the code failed. Since this tutorial was conducted on Windows, some supplementary libraries could not be installed, but the overall performance of the geological modeling code is intact.
# Embedding matplotlib figures in the notebooks
%matplotlib inline
# Importing GemPy
import gempy as gp
# Importing auxiliary libraries
import numpy as np
import matplotlib.pyplot as plt
2. Creation of geological model objects and definition of geography
This tutorial creates a 100 column x 100 row x 100 layer grid over a 2km x 2km x 2km extension. Higher resolutions are possible but will take longer to compute. The coordinate system is a local coordinate system, and subsequent tutorials will use UTM coordinates to evaluate Gempy's performance.
Orientations and geological contacts were imported from CSV files and converted to Pandas dataframes. Geological series (faults/strata) and geological stratigraphic sequences are then defined.
It's worth mentioning that faults must be inserted independently, with the youngest being the first entry.
# Importing the data from CSV-files and setting extent and resolution
geo_data = gp.create_data([0,2000,0,2000,0,2000],[100,100,100],
path_o = "../Txt/simple_fault_model_orientations.csv", # importing orientation (foliation) data
path_i = "../Txt/simple_fault_model_points.csv") # importing point-positional interface data
gp.get_data(geo_data).loc[:,['X','Y','Z','formation']].head()
X Y Z formation
interfaces 52 700.0 1000.0 900.0 Main_Fault
53 600.0 1000.0 600.0 Main_Fault
54 500.0 1000.0 300.0 Main_Fault
55 800.0 1000.0 1200.0 Main_Fault
56 900.0 1000.0 1500.0 Main_Fault
# Assigning series to formations as well as their order (timewise)
gp.set_series(geo_data, {"Fault_Series":'Main_Fault',
"Strat_Series": ('Sandstone_2','Siltstone', 'Shale', 'Sandstone_1')},
order_series = ["Fault_Series", 'Strat_Series'],
order_formations=['Main_Fault',
'Sandstone_2','Siltstone', 'Shale', 'Sandstone_1',
], verbose=0)
3. Geological sequence map
Gempy has some useful features for representing defined geological series and stratigraphic sequences.
gp.get_sequential_pile(geo_data)
<gempy.plotting.sequential_pile.StratigraphicPile at 0x107149e8>
4. Review of input data
The different datasets used for geological model building can be accessed through Gempy's ".get_" function.
# Review of the centroid coordinates from the model grid
gp.get_grid(geo_data).values
array([[ 10., 10., 10.],
[ 10., 10., 30.],
[ 10., 10., 50.],
...,
[ 1990., 1990., 1950.],
[ 1990., 1990., 1970.],
[ 1990., 1990., 1990.]], dtype=float32)
# Defined interfases from the input CSV data
gp.get_data(geo_data, 'interfaces').loc[:,['X','Y','Z','formation']].head()
X Y Z formation
52 700.0 1000.0 900.0 Main_Fault
53 600.0 1000.0 600.0 Main_Fault
54 500.0 1000.0 300.0 Main_Fault
55 800.0 1000.0 1200.0 Main_Fault
56 900.0 1000.0 1500.0 Main_Fault
# Defined layer orientations from the input CSV data
gp.get_data(geo_data, 'orientations').loc[:,['X','Y','Z','formation','azimuth']]
X | Y | Z | formation | azimuth |
---|---|---|---|---|
2 | 500 | 1000 | 864.602 | Main_Fault |
1 | 400 | 1000 | 1400.000 | Sandstone_2 |
0 | 1000 | 1000 | 950.000 | Shale |
5. Graphical representation of input data
In this section, 2D and 3D representations are used to present the interface and orientation.
gp.plot_data(geo_data, direction='y')
E:\Software\Anaconda3\lib\site-packages\gempy\gempy_front.py:927: FutureWarning: gempy plotting functionality will be moved in version 1.2, use gempy.plotting module instead
warnings.warn("gempy plotting functionality will be moved in version 1.2, use gempy.plotting module instead", FutureWarning)
gp.plotting.plot_data_3D(geo_data)
6. Geological interpolation
After the input data is ready, we can define the interpolation data and parameters using the InterpolatonData method in the Gempy library.
Geological models are computed under the "compute_model" method. The result of the modeling process is lithology and faults with the same array dimensions as geo_data.
interp_data = gp.InterpolatorData(geo_data, u_grade=[1,1], output='geology', compile_theano=True, theano_optimizer='fast_compile')
Compiling theano function...
Compilation Done!
Level of Optimization: fast_compile
Device: cpu
Precision: float32
Number of faults: 1
interp_data.geo_data_res.formations.as_matrix
<bound method NDFrame.as_matrix of value formation_number
Main_Fault 1 1
Sandstone_2 2 2
Siltstone 3 3
Shale 4 4
Sandstone_1 5 5
basement 6 6>
interp_data.geo_data_res.get_formations()
[Main_Fault, Sandstone_2, Siltstone, Shale, Sandstone_1]
Categories (5, object): [Main_Fault, Sandstone_2, Siltstone, Shale, Sandstone_1]
lith_block, fault_block = gp.compute_model(interp_data)
7. Lithology model exploration
A lithology block has two parts, the first part contains information about the lithology strata and the second part indicates the direction. In this section, the distribution of lithology and fault separation information is presented in the form of a histogram.
lith_block[0]
array([ 6.3131361 , 6.24877167, 6.19397354, ..., 2.00398016,
2.00626612, 2.00983 ], dtype=float32)
plt.hist(lith_block[0],bins=100)
plt.show()
plt.hist(fault_block[0],bins=10)
plt.show()
8. Geological model representation
The resulting lithology blocks can be represented on Matplotlib just like any other Numpy array. However, Gempy has a special way of representing cross sections. Using a Jupyter widget, an interactive representation of a geological cross-section along the Y direction can be performed using the handles to move along the row.
gp.plotting.plot_section(geo_data, lith_block[0], cell_number=50, direction='y', plot_data=False)
import ipywidgets as widgets
def plotCrossSection(cell):
gp.plotting.plot_section(geo_data, lith_block[0], cell_number=cell, direction='y', plot_data=False)
widgets.interact(plotCrossSection,
cell=widgets.IntSlider(min=0,max=99,step=1,value=50) )
gp.plotting.plot_scalar_field(geo_data, lith_block[1], cell_number=50, N=6,
direction='y', plot_data=False)
plt.colorbar()
plt.show()
ver_s, sim_s = gp.get_surfaces(interp_data,lith_block[1],
fault_block[1],
original_scale=True)
gp.plotting.plot_surfaces_3D(geo_data, ver_s, sim_s)
Original link: Gempy 3D structural geological modeling—BimAnt