3D Structural Geological Modeling in Python with Gempy - Tutorial

3DStructuralGeologicalModelinginPythonwithGempy.png

Gempy is as open source Python library for generating full 3D structural geological models. The library is a complete development to create geological models from interfases, faults, and layer orientations, it also relates the sequence of geological layers to represent rock intrusions and faults order.

Algorithm for geological modeling is based on universal cokriging interpolation with the support of high-end Python mathematical libraries as Numpy, PyMC3 and Theano.

Gempy creates a grid model that can be visualized as 2D sections with Matplotlib or as 3D geometrical objects as VTK objects that allow the representation of the geologic models on Paraview for custom slicing, filtering, transparencies, and styling.

This tutorial is a basic example of a stratified geological setup with 5 layers and one fault. In order to make the tutorial fully accessible to the majority of users, we have created a complementary tutorial about how to install Gempy on Windows with a repository distribution of Anaconda.

Tutorial

The tutorial has two parts:

Part 1: Instalation of Gempy in Windows

Part 2: Geological modeling example with Gempy

Python code

This is the script for the tutorial:

Setting up the Python enviroment

In this part we import the required libraries for the tutorial. The script requires Gempy as well as Numpy and Matplotlib. We configure a Jupyter option for the interactive representation of Matplotlib graphics after the script cells (%matplotlib inline).
Notice the that warnings are only messages that the user have to take in mind when running the script, they do not mean a failure of the code. Since this tutorial is on Windows some complementary libraries were unable to install but the overall performance of the geological modeling code is complete.

# 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

Creation of the geological model object and statigraphy definition

The tutorial creates a grid of 100 col x 100 rows x 100 layers over a extension of 2km x 2km x 2km. Higher resolutions are posible but the computational time will be higher. The coordinate system is of local coordinates, comming tutorial will evaluate the performace of Gempy with UTM coordinates.
The orientation and geological contacts are imported from CSV files and converted into a Pandas dataframe. Then the geological series (faults / formations) are defined as well as the geological formation sequence.
Its important to mentions that faults have to be inserted independently, where the youngest is 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)

Geological sequence plot

Gempy has some useful features to represent the defined geological series and formation sequences.

gp.get_sequential_pile(geo_data)
<gempy.plotting.sequential_pile.StratigraphicPile at 0x107149e8>
output_7_1.png

Review of the input data

The different datasets for the geological model construction can be accessed though the ".get_" functions of Gempy.

# 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 270
1 400 1000 1400.000 Sandstone_2 90
0 1000 1000 950.000 Shale 90

Graphical representation of input data

In this part 2D and 3D representations were done to present the interfases and orientations.

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)
output_13_1.png
gp.plotting.plot_data_3D(geo_data)
output_27_1.PNG

Geological interpolation

Once the input data is ready, we can define the data and parameters for the interpolation with the InterpolatonData method from the Gempy library.
The geological model is calculated under the "compute_model" method. Results from the model process are the lithology and faults on the same array dimensions as the 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)

Lithologic model exploration

The lithology block has two parts, the first one has information about the lithological formation, while the second represents the orientation. In this part the distribution of lithology and fault-separated information are represented as histograms.

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()
output_22_0.png
plt.hist(fault_block[0],bins=10)
plt.show()
output_23_0.png

Geological model representation

As any other Numpy array, the resulting lithological blocks can be represented on Matplotlib. However, Gempy have special methods for cross section representation. With the use of Jupyter widgets an interactive representation of the geological cross sections along the Y direction is performed with a handelbar to shift along rows.

gp.plotting.plot_section(geo_data, lith_block[0], cell_number=50,  direction='y', plot_data=False)
output_25_0.png
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) )
output_24_0.PNG
gp.plotting.plot_scalar_field(geo_data, lith_block[1], cell_number=50, N=6,
                        direction='y', plot_data=False)
plt.colorbar()
plt.show()
output_27_0.png
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)
output_27_2.PNG

Input files

You can download the input files for this tutorial on this link.






1 Comment

Saul Montoya

Saul Montoya es Ingeniero Civil graduado de la Pontificia Universidad Católica del Perú en Lima con estudios de postgrado en Manejo e Ingeniería de Recursos Hídricos (Programa WAREM) de la Universidad de Stuttgart con mención en Ingeniería de Aguas Subterráneas y Hidroinformática.

Smiley face

Subscribe to our free e-newsletter for tutorials, articles, webminars, courses and more.