Skip to content

Commit a227afe

Browse files
committed
[DOC] Improve documentation and structure in geology example script
Refactored and enhanced comments and docstrings in the horizontal stratigraphy example script. Improved clarity, added detailed explanations for each step, and ensured consistent formatting across sections.
1 parent 8d11207 commit a227afe

File tree

1 file changed

+125
-43
lines changed

1 file changed

+125
-43
lines changed
Lines changed: 125 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,39 @@
11
"""
2-
Model 1 - Horizontal stratigraphy
3-
==================================
2+
Model 1 - Horizontal Stratigraphy
3+
===================================
44
5-
A simple example with horizontal layers
5+
This example demonstrates how to build a basic geological model with horizontally stacked layers using GemPy,
6+
an open-source Python library for implicit geological modeling. In this script, we will:
67
7-
This script demonstrates how to create a basic model with horizontally stacked layers using GemPy,
8-
a Python-based, open-source library for implicit geological modeling.
9-
"""
8+
- Set up and compute a simple geological model using input data (orientations and surface points).
9+
- Visualize the model in 2D and 3D.
10+
- Export model components (formations, orientations, surface points, and the regular grid) to VTK files.
11+
- Extract mesh vertices and normals, save them to Excel files, and convert the vertex data to an XYZ file.
1012
13+
Each section includes detailed comments to explain its purpose and functionality.
14+
"""
1115

1216
# %%
1317
# Import necessary libraries
1418
import gempy as gp
1519
import gempy_viewer as gpv
16-
20+
import pyvista as pv
21+
import vtk
22+
import pandas as pd
1723

1824
# sphinx_gallery_thumbnail_number = 2
1925

2026
# %%
21-
# Generate the model
22-
# Define the path to data
27+
# Generate the Geological Model
28+
# -----------------------------
29+
# In this section, we define the data source and create a GeoModel instance.
30+
# The model is defined with a specific spatial extent and resolution (refinement).
31+
# Input data (orientations and surface points) are loaded from a remote repository.
32+
33+
# Define the path to the dataset hosted online
2334
data_path = 'https://raw.githubusercontent.com/cgre-aachen/gempy_data/master/'
24-
# Create a GeoModel instance
35+
36+
# Create a GeoModel instance with the given project name, extent, and refinement level.
2537
data = gp.create_geomodel(
2638
project_name='horizontal',
2739
extent=[0, 1000, 0, 1000, 0, 1000],
@@ -31,104 +43,174 @@
3143
path_to_surface_points=data_path + "/data/input_data/jan_models/model1_surface_points.csv"
3244
)
3345
)
34-
# Map geological series to surfaces
46+
47+
# Map a geological series to the corresponding surfaces.
48+
# Here, the "Strat_Series" is associated with two formations ('rock2' and 'rock1'),
49+
# which defines the stacking order of horizontal layers.
3550
gp.map_stack_to_surfaces(
3651
gempy_model=data,
3752
mapping_object={"Strat_Series": ('rock2', 'rock1')}
3853
)
39-
# Compute the geological model
54+
55+
# Compute the geological model using the provided data and mappings.
4056
gp.compute_model(data)
4157
geo_data = data
4258

4359
# %%
44-
# Plot the initial geological model in the y direction without results
60+
# 2D Visualization of the Geological Model
61+
# -----------------------------------------
62+
# The following plots provide 2D views of the model.
63+
# - The first plot shows the initial model without computed results.
64+
# - The subsequent plots display the computed geological data in the x and y directions.
65+
# Note: The boundaries are hidden in the latter plots for a cleaner visualization.
66+
67+
# Plot the initial model in the y direction (without displaying computed results)
4568
gpv.plot_2d(geo_data, direction=['y'], show_results=False)
4669

47-
# Plot the result of the model in the x and y direction with data and without boundaries
70+
# Plot the computed model results in the x and y directions, including data but excluding boundaries
4871
gpv.plot_2d(geo_data, direction=['x'], show_data=True, show_boundaries=False)
4972
gpv.plot_2d(geo_data, direction=['y'], show_data=True, show_boundaries=False)
5073

5174
# %%
52-
# Export to VTK model
53-
p = gpv.plot_3d(geo_data, show_data=True, show_results=True, show_boundaries=True,image=True)
54-
p.surface_poly['rock1'].save('rock1.vtk') # Save the vtk file for formation 1
55-
p.surface_poly['rock2'].save('rock2.vtk') # Save the vtk file for formation 2
56-
p.orientations_mesh.save('orientations.vtk') # Save the vtk file for the orientations
57-
p.surface_points_mesh.save('surface_points.vtk') # Save the vtk file for the surface points
58-
box = p.regular_grid_actor.GetMapper().GetInput() # Get the vtk file for the regular grid
75+
# 3D Visualization and Export to VTK
76+
# ----------------------------------
77+
# Visualize the model in 3D with data, results, and boundaries.
78+
# The generated 3D plot is also used to export various components of the model to VTK files.
79+
p = gpv.plot_3d(geo_data, show_data=True, show_results=True, show_boundaries=True, image=True)
80+
81+
# Export different components of the model to VTK files:
82+
p.surface_poly['rock1'].save('rock1.vtk') # Save formation 'rock1'
83+
p.surface_poly['rock2'].save('rock2.vtk') # Save formation 'rock2'
84+
p.orientations_mesh.save('orientations.vtk') # Save the orientations mesh
85+
p.surface_points_mesh.save('surface_points.vtk') # Save the surface points mesh
86+
87+
# Retrieve and export the regular grid (volume representation) of the model
88+
box = p.regular_grid_actor.GetMapper().GetInput()
5989
box.save('box.vtk')
6090

6191
# %%
62-
import pyvista as pv
92+
# Display the Exported VTK Files with PyVista
93+
# -------------------------------------------
94+
# Load and plot each exported VTK file to verify the export.
6395
pv.read('rock1.vtk').plot(show_edges=False)
6496
pv.read('rock2.vtk').plot(show_edges=False)
6597
pv.read('orientations.vtk').plot(show_edges=False)
6698
pv.read('surface_points.vtk').plot(show_edges=False)
6799
pv.read('box.vtk').plot(show_edges=False)
68100

101+
69102
# %%
70-
# Export vertices of mesh
71-
from builtins import range
72-
import vtk
73-
import pandas as pd
103+
# Extract and Save Mesh Vertices and Normals
104+
# ------------------------------------------
105+
# The following functions extract vertex coordinates and corresponding normal vectors
106+
# from a mesh (vtkPolyData), and then save this data into Excel files for further analysis.
107+
74108
def generate_normals(polydata):
109+
"""
110+
Generate normals for the given polydata if they are not already computed.
111+
112+
Parameters:
113+
polydata (vtk.vtkPolyData): Input polydata for which normals are to be computed.
114+
115+
Returns:
116+
vtk.vtkPolyData: The polydata with computed point normals.
117+
"""
75118
normal_generator = vtk.vtkPolyDataNormals()
76119
normal_generator.SetInputData(polydata)
77120
normal_generator.ComputePointNormalsOn()
78121
normal_generator.ComputeCellNormalsOff()
79122
normal_generator.Update()
80123
return normal_generator.GetOutput()
81124

125+
82126
def get_vertices_and_normals(mesh):
127+
"""
128+
Extract vertices and normals from a mesh.
129+
130+
Parameters:
131+
mesh: The mesh object (typically from a formation) to extract surface vertices and normals.
83132
133+
Returns:
134+
tuple: Two lists containing vertices and normals respectively.
135+
"""
136+
# Extract the surface of the mesh
84137
surface_mesh = mesh.extract_surface()
85138
polydata = surface_mesh
86139

87-
# Generate normals if not present
140+
# Ensure normals are computed for the polydata
88141
polydata_with_normals = generate_normals(polydata)
89142

90-
# Get points (vertices)
143+
# Extract points (vertices)
91144
points = polydata_with_normals.GetPoints()
92-
vertices = []
93-
for i in range(points.GetNumberOfPoints()):
94-
vertices.append(points.GetPoint(i))
145+
vertices = [points.GetPoint(i) for i in range(points.GetNumberOfPoints())]
95146

96-
# Get normals
147+
# Extract normals associated with the points
97148
normals_array = polydata_with_normals.GetPointData().GetNormals()
98-
normals = []
99-
for i in range(normals_array.GetNumberOfTuples()):
100-
normals.append(normals_array.GetTuple(i))
149+
normals = [normals_array.GetTuple(i) for i in range(normals_array.GetNumberOfTuples())]
101150

102151
return vertices, normals
103152

153+
104154
def save_to_excel(vertices, normals, vertices_file, normals_file):
105-
# Create DataFrames
155+
"""
156+
Save the vertices and normals to separate Excel files.
157+
158+
Parameters:
159+
vertices (list): List of vertex coordinates.
160+
normals (list): List of normal vectors.
161+
vertices_file (str): File name for saving vertices.
162+
normals_file (str): File name for saving normals.
163+
"""
164+
# Create DataFrames from the lists
106165
vertices_df = pd.DataFrame(vertices, columns=['X', 'Y', 'Z'])
107166
normals_df = pd.DataFrame(normals, columns=['x', 'y', 'z'])
108167

109-
# Save to Excel files
168+
# Write the DataFrames to Excel files
110169
vertices_df.to_excel(vertices_file, index=False)
111-
normals_df.to_excel
170+
normals_df.to_excel(normals_file, index=False)
171+
172+
173+
# Extract vertices and normals from the mesh of formation 'rock1'
112174
mesh = p.surface_poly['rock1']
113175
vertices, normals = get_vertices_and_normals(mesh)
176+
177+
# Create DataFrames for later processing or verification
114178
vertices_df = pd.DataFrame(vertices, columns=['X', 'Y', 'Z'])
115179
normals_df = pd.DataFrame(normals, columns=['x', 'y', 'z'])
116-
# Save to Excel filesthe
180+
181+
# Define file names for the Excel outputs
117182
vertices_file = "rock1_vertices.xlsx"
118183
normals_file = "rock1_norms.xlsx"
184+
185+
# Save the extracted data to Excel files
119186
save_to_excel(vertices, normals, vertices_file, normals_file)
187+
188+
# Optionally, read back the Excel files to verify their content
120189
pd.read_excel(vertices_file)
121190
pd.read_excel(normals_file)
122191

192+
123193
# %%
124-
# Convert the DataFrame to an XYZ file
194+
# Convert Vertices DataFrame to an XYZ File
195+
# -----------------------------------------
196+
# This function converts a DataFrame containing vertex coordinates to an XYZ format file,
197+
# which is a simple text file with one point per line.
198+
125199
def dataframe_to_xyz(df, filename):
200+
"""
201+
Write vertex coordinates from a DataFrame to an XYZ file.
202+
203+
Parameters:
204+
df (pandas.DataFrame): DataFrame containing 'X', 'Y', and 'Z' columns.
205+
filename (str): Output filename for the XYZ file.
206+
"""
126207
with open(filename, 'w') as f:
127208
for index, row in df.iterrows():
128209
f.write(f"{row['X']} {row['Y']} {row['Z']}\n")
129210

130-
# Specify the filename
211+
212+
# Specify the output file name for the XYZ file
131213
filename = "output.xyz"
132214

133-
# Call the function to write the DataFrame to an XYZ file
134-
dataframe_to_xyz(vertices_df, filename)
215+
# Convert the vertices DataFrame to an XYZ file
216+
dataframe_to_xyz(vertices_df, filename)

0 commit comments

Comments
 (0)