|
| 1 | +""" |
| 2 | +Video Tutorial "code-along": Faults |
| 3 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 4 | +""" |
| 5 | + |
| 6 | + |
| 7 | +# %% |
| 8 | +# This tutorial demonstrates step-by-step how to add faults to our geological models created with `gempy`. |
| 9 | +# It follows the Video tutorial series available on the [gempy YouTube channel](https://www.youtube.com/@GemPy3D). |
| 10 | +# Please follow the first part of the tutorial to learn the basics of modeling with gempy before diving into this tutorial. |
| 11 | + |
| 12 | + |
| 13 | +# %% |
| 14 | +# Video tutorial faults: Introduction |
| 15 | +# """""""""""""""""""""""""""""""""""" |
| 16 | +# |
| 17 | +# The first video introduces the concept of modeling faults with GemPy - please view online before starting the tutorial. |
| 18 | +# |
| 19 | +# |
| 20 | + |
| 21 | +# %% |
| 22 | +# .. raw:: html |
| 23 | +# |
| 24 | +# <iframe width="560" height="315" |
| 25 | +# src="https://www.youtube.com/embed/LAaL_2feAiA?si=wyMorsZLts7hXB2S" |
| 26 | +# title="YouTube video player" |
| 27 | +# frameborder="0" |
| 28 | +# allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" |
| 29 | +# allowfullscreen> |
| 30 | +# </iframe> |
| 31 | +# |
| 32 | +# |
| 33 | + |
| 34 | +# %% |
| 35 | + |
| 36 | +# Required imports |
| 37 | +import gempy as gp |
| 38 | +import gempy_viewer as gpv |
| 39 | +import numpy as np |
| 40 | + |
| 41 | + |
| 42 | +# %% |
| 43 | + |
| 44 | +# Path to input data |
| 45 | +data_path = "https://raw.githubusercontent.com/cgre-aachen/gempy_data/master/" |
| 46 | +path_to_data = data_path + "/data/input_data/video_tutorials_v3/" |
| 47 | + |
| 48 | + |
| 49 | +# %% |
| 50 | + |
| 51 | +# Create instance of geomodel |
| 52 | +geo_model = gp.create_geomodel( |
| 53 | + project_name = 'tutorial_model_faults', |
| 54 | + extent=[0,3000,0,1000,0,1000], |
| 55 | + resolution=[90,30,30], |
| 56 | + importer_helper=gp.data.ImporterHelper( |
| 57 | + path_to_orientations=path_to_data + "tutorial_model_faults_1_orientations.csv", |
| 58 | + path_to_surface_points=path_to_data + "tutorial_model_faults_1_surface_points.csv" |
| 59 | + ) |
| 60 | +) |
| 61 | + |
| 62 | + |
| 63 | +# %% |
| 64 | + |
| 65 | + |
| 66 | +# Display a basic cross section of input data |
| 67 | +gpv.plot_2d(geo_model); |
| 68 | + |
| 69 | + |
| 70 | +# %% |
| 71 | + |
| 72 | + |
| 73 | +# Map geological series to surfaces |
| 74 | +gp.map_stack_to_surfaces( |
| 75 | + gempy_model=geo_model, |
| 76 | + mapping_object={ |
| 77 | + "Fault_Series1" : ('fault'), |
| 78 | + "Strat_Series1": ('rock3'), |
| 79 | + "Strat_Series2": ('rock2', 'rock1'), |
| 80 | + } |
| 81 | +) |
| 82 | + |
| 83 | + |
| 84 | +# %% |
| 85 | + |
| 86 | + |
| 87 | +# Define youngest structural group as fault |
| 88 | +gp.set_is_fault(geo_model, ["Fault_Series1"]) |
| 89 | + |
| 90 | + |
| 91 | +# %% |
| 92 | + |
| 93 | + |
| 94 | +# Compute a solution for the model |
| 95 | +gp.compute_model(geo_model) |
| 96 | + |
| 97 | + |
| 98 | +# %% |
| 99 | + |
| 100 | + |
| 101 | +# Display the result in 2d section |
| 102 | +gpv.plot_2d(geo_model, cell_number=20) |
| 103 | +# gpv.plot_3d(geo_model) |
| 104 | + |
| 105 | + |
| 106 | +# %% |
| 107 | + |
| 108 | + |
| 109 | +# Display the scalar field of the fault in 2d section |
| 110 | +gpv.plot_2d(geo_model, show_scalar=True, show_lith=False, series_n=0) |
| 111 | +gpv.plot_2d(geo_model, show_scalar=True, show_lith=False, series_n=1) |
| 112 | +gpv.plot_2d(geo_model, show_scalar=True, show_lith=False, series_n=2) |
| 113 | + |
| 114 | + |
| 115 | +# %% |
| 116 | +# Video tutorial 9: Fault relations |
| 117 | +# """""""""""""""""""""""""""" |
| 118 | + |
| 119 | +# %% |
| 120 | +# .. raw:: html |
| 121 | +# |
| 122 | +# <iframe width="560" height="315" |
| 123 | +# src="https://www.youtube.com/embed/AKpEefP9Ff0?si=7Jeiz5pfHQhXH4jF" |
| 124 | +# title="YouTube video player" |
| 125 | +# frameborder="0" |
| 126 | +# allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" |
| 127 | +# allowfullscreen> |
| 128 | +# </iframe> |
| 129 | +# |
| 130 | +# |
| 131 | + |
| 132 | +# ***Warning***: In the following section we will make several changes to the existing model. This includes adding new elements, groups, surface points and orientation and reordering the structural frame. Executing these cells more than once can lead to errors as things will be added twice. |
| 133 | + |
| 134 | +# %% |
| 135 | + |
| 136 | + |
| 137 | +# Creating a new strucutral element with surface point and orientation data |
| 138 | +new_element = gp.data.StructuralElement( |
| 139 | + name='fault0', |
| 140 | + color=next(geo_model.structural_frame.color_generator), |
| 141 | + surface_points=gp.data.SurfacePointsTable.from_arrays( |
| 142 | + x=np.array([2750, 2750, 2750]), |
| 143 | + y=np.array([0, 500, 1000]), |
| 144 | + z=np.array([400, 400, 400]), |
| 145 | + names=['fault0']*3 |
| 146 | + ), |
| 147 | + orientations=gp.data.OrientationsTable.from_arrays( |
| 148 | + x=np.array([2750]), |
| 149 | + y=np.array([500]), |
| 150 | + z=np.array([400]), |
| 151 | + G_x=np.array([0.8]), |
| 152 | + G_y=np.array([0]), |
| 153 | + G_z=np.array([0.6]), |
| 154 | + names=['fault0'] |
| 155 | + ) |
| 156 | +) |
| 157 | + |
| 158 | +# Creating a new structural group that contains the new element |
| 159 | +group_fault0 = gp.data.StructuralGroup( |
| 160 | + name='Fault_Series0', |
| 161 | + elements=[new_element], |
| 162 | + structural_relation=gp.data.StackRelationType.ERODE, |
| 163 | +) |
| 164 | + |
| 165 | +# Insert the fault group into the structural frame at first position (index 0) |
| 166 | +geo_model.structural_frame.insert_group(index=0, group=group_fault0); |
| 167 | + |
| 168 | + |
| 169 | +# %% |
| 170 | + |
| 171 | + |
| 172 | +# Define youngest structural group as fault |
| 173 | +gp.set_is_fault(geo_model, ["Fault_Series0"]) |
| 174 | + |
| 175 | + |
| 176 | +# %% |
| 177 | + |
| 178 | + |
| 179 | +# Add additional information for exisitng elements on other side of fault |
| 180 | +gp.add_surface_points( |
| 181 | + geo_model=geo_model, |
| 182 | + x=[2950, 2950, 2950], |
| 183 | + y=[0, 500, 1000], |
| 184 | + z=[500, 500, 500], |
| 185 | + elements_names=['rock2']*3 |
| 186 | +); |
| 187 | + |
| 188 | +gp.add_surface_points( |
| 189 | + geo_model=geo_model, |
| 190 | + x=[2950, 2950, 2950], |
| 191 | + y=[0, 500, 1000], |
| 192 | + z=[350, 350, 350], |
| 193 | + elements_names=['rock1']*3 |
| 194 | +); |
| 195 | + |
| 196 | +gp.add_surface_points( |
| 197 | + geo_model=geo_model, |
| 198 | + x=[2950, 2950, 2950], |
| 199 | + y=[0, 500, 1000], |
| 200 | + z=[550, 500, 500], |
| 201 | + elements_names=['rock3']*3 |
| 202 | +); |
| 203 | + |
| 204 | + |
| 205 | +# %% |
| 206 | + |
| 207 | + |
| 208 | +# Display input data with the new fault and the additional input data for the other elements |
| 209 | +gpv.plot_2d(geo_model, show_data=True, show_boundaries=False, show_lith=False) |
| 210 | + |
| 211 | + |
| 212 | +# %% |
| 213 | + |
| 214 | + |
| 215 | +# Recompute the model with the new information |
| 216 | +gp.compute_model(geo_model) |
| 217 | + |
| 218 | + |
| 219 | +# %% |
| 220 | + |
| 221 | + |
| 222 | +# Display the new result |
| 223 | +gpv.plot_2d(geo_model) |
| 224 | + |
| 225 | + |
| 226 | +# %% |
| 227 | + |
| 228 | + |
| 229 | +# Switching the order by adding a new group containing rock3 on top |
| 230 | +gp.add_structural_group( |
| 231 | + model=geo_model, |
| 232 | + group_index=0, |
| 233 | + structural_group_name="Strat_Series0", |
| 234 | + elements=[ |
| 235 | + geo_model.structural_frame.get_element_by_name("rock3") |
| 236 | + ], |
| 237 | + structural_relation=gp.data.StackRelationType.ERODE |
| 238 | +) |
| 239 | + |
| 240 | +# Removing the old group that contained rock3 |
| 241 | +gp.remove_structural_group_by_name(geo_model, group_name="Strat_Series1") |
| 242 | + |
| 243 | + |
| 244 | +# %% |
| 245 | + |
| 246 | + |
| 247 | +# Recompute the model with new order |
| 248 | +gp.compute_model(geo_model) |
| 249 | + |
| 250 | + |
| 251 | +# %% |
| 252 | + |
| 253 | + |
| 254 | +# Display the new result |
| 255 | +gpv.plot_2d(geo_model) |
| 256 | + |
| 257 | + |
| 258 | +# %% |
| 259 | + |
| 260 | + |
| 261 | +# Set fault relations manually |
| 262 | +gp.set_fault_relation( |
| 263 | + frame=geo_model.structural_frame, |
| 264 | + rel_matrix=np.array([ |
| 265 | + [0, 0, 0, 0], |
| 266 | + [0, 0, 0, 0], |
| 267 | + [0, 0, 0, 1], |
| 268 | + [0, 0, 0, 0] |
| 269 | + ] |
| 270 | + ) |
| 271 | +) |
| 272 | + |
| 273 | + |
| 274 | +# %% |
| 275 | + |
| 276 | + |
| 277 | +# Recompute model |
| 278 | +gp.compute_model(geo_model) |
| 279 | + |
| 280 | + |
| 281 | +# %% |
| 282 | + |
| 283 | + |
| 284 | +# Display result |
| 285 | +gpv.plot_2d(geo_model) |
| 286 | + |
| 287 | + |
| 288 | +# %% |
| 289 | +# Video tutorial 10: Fault groups and cross-cutting faults |
| 290 | +# """""""""""""""""""""""""""""""""""" |
| 291 | + |
| 292 | +# %% |
| 293 | +# .. raw:: html |
| 294 | +# |
| 295 | +# <iframe width="560" height="315" |
| 296 | +# src="https://www.youtube.com/embed/PuxoH5EKUrQ?si=P8OhnXEUS8ZWVrGp" |
| 297 | +# title="YouTube video player" |
| 298 | +# frameborder="0" |
| 299 | +# allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" |
| 300 | +# allowfullscreen> |
| 301 | +# </iframe> |
| 302 | +# |
| 303 | +# |
| 304 | + |
| 305 | +# %% |
| 306 | + |
| 307 | + |
| 308 | +# Create instance of new geomodel |
| 309 | +geo_model_cross = gp.create_geomodel( |
| 310 | + project_name = 'tutorial_model_faults_2', |
| 311 | + extent=[0,1000,0,500,0,1000], |
| 312 | + resolution=[50,25,50], |
| 313 | + importer_helper=gp.data.ImporterHelper( |
| 314 | + path_to_orientations=path_to_data + "tutorial_model_faults_2_orientations.csv", |
| 315 | + path_to_surface_points=path_to_data + "tutorial_model_faults_2_surface_points.csv" |
| 316 | + ) |
| 317 | +) |
| 318 | + |
| 319 | + |
| 320 | +# %% |
| 321 | + |
| 322 | + |
| 323 | +# Map geological series to surfaces |
| 324 | +gp.map_stack_to_surfaces( |
| 325 | + gempy_model=geo_model_cross, |
| 326 | + mapping_object={ |
| 327 | + "Fault_Series2" : ('fault3', 'fault2'), |
| 328 | + "Fault_Series1" : ('fault1'), |
| 329 | + "Strat_Series": ('rock3', 'rock2', 'rock1'), |
| 330 | + } |
| 331 | +) |
| 332 | + |
| 333 | +# Define youngest structural group as fault |
| 334 | +gp.set_is_fault(geo_model_cross, ["Fault_Series1", "Fault_Series2"]) |
| 335 | + |
| 336 | +# Change color of basement for better visibility |
| 337 | +geo_model_cross.structural_frame.basement_color="#F7B529" |
| 338 | +geo_model_cross.structural_frame.structural_elements[0].color = '#000000' |
| 339 | +geo_model_cross.structural_frame.structural_elements[1].color = '#36454F' |
| 340 | +geo_model_cross.structural_frame.structural_elements[2].color = '#D3D3D3' |
| 341 | + |
| 342 | + |
| 343 | +# %% |
| 344 | + |
| 345 | + |
| 346 | +geo_model_cross.structural_frame |
| 347 | + |
| 348 | + |
| 349 | +# %% |
| 350 | + |
| 351 | + |
| 352 | +# Set fault relations manually |
| 353 | +gp.set_fault_relation( |
| 354 | + frame=geo_model_cross.structural_frame, |
| 355 | + rel_matrix=np.array([ |
| 356 | + [0, 1, 1], |
| 357 | + [0, 0, 1], |
| 358 | + [0, 0, 0], |
| 359 | + ] |
| 360 | + ) |
| 361 | +) |
| 362 | + |
| 363 | + |
| 364 | +# %% |
| 365 | + |
| 366 | + |
| 367 | +# Display input data on cross section |
| 368 | +gpv.plot_2d(geo_model_cross) |
| 369 | + |
| 370 | + |
| 371 | +# %% |
| 372 | + |
| 373 | + |
| 374 | +# Compute model |
| 375 | +gp.compute_model(geo_model_cross) |
| 376 | + |
| 377 | + |
| 378 | +# %% |
| 379 | + |
| 380 | + |
| 381 | +# Display reusult on cross section |
| 382 | +gpv.plot_2d(geo_model_cross) |
| 383 | + |
| 384 | + |
| 385 | +# sphinx_gallery_thumbnail_number = -1 |
| 386 | + |
0 commit comments