|
8 | 8 | # geomodeling and demonstrating how you can leverage these to create your own geological models. We will guide you through building a
|
9 | 9 | # model from scratch, based on a conceptual 2D cross-section with boreholes. This simple example will highlight key workflow steps
|
10 | 10 | # and structural features that GemPy can model.
|
| 11 | + |
11 | 12 | # Installation
|
12 | 13 | # """"""""""""
|
13 | 14 | #
|
|
78 | 79 | # relevant data in a representative space. For this example, we align the extent with the cross-section we imported:
|
79 | 80 | # - **X** is parallel to the section.
|
80 | 81 | # - **Y** is perpendicular. Since we have no data along y, a narrow extent makes sense. We choose an extent of 400, defining it as
|
81 |
| -# -200 to 200, placing the cross-section at y=0 (in the middle). |
| 82 | +# -200 to 200, placing the cross-section at y=0 (in the middle). |
82 | 83 | # - **Z**, representing depth, takes a negative value since we are modeling the subsurface.
|
83 | 84 | # 3. **Initialize Structural Framework**: Set up a default structural framework.
|
84 | 85 | # 4. **Define either resolution or refinement**: In GemPy 3, you can use either regular grids or octrees.
|
85 | 86 | # - **Regular grids**: Define a resolution (and refinement=None). A medium resolution of 50x50x50, for example, results in 125,000 voxels.
|
86 | 87 | # Model voxels are prisms, not cubes, so resolution can differ from extent. Avoid exceeding 100 cells in each direction (1,000,000 voxels)
|
87 | 88 | # to prevent high computational costs.
|
88 | 89 | # - **Octrees**: Define a level of refinement (and resolution=None). Higher refinement levels increase computational costs.
|
89 |
| -# |
90 |
| -# > **Note on choice of modeling grids:** Which type of grid is used depends on the use case. Note that as of the current version of GemPy 3, |
91 |
| -# the rendering of surfaces uses dual-contouring, which is based on octrees. So even if you choose regular grids, octree-based computing will |
92 |
| -# be executed additionally in order to render the surfaces in 3D. |
| 90 | + |
| 91 | +# .. admonition:: Note on choice of modeling grids |
| 92 | +# Which type of grid is used depends on the use case. Note that as of the current version of GemPy 3, |
| 93 | +# the rendering of surfaces uses dual-contouring, which is based on octrees. So even if you choose regular grids, octree-based computing will |
| 94 | +# be executed additionally in order to render the surfaces in 3D. |
93 | 95 |
|
94 | 96 | # %%
|
95 | 97 | geo_model = gp.create_geomodel(
|
|
106 | 108 | # such as the parameters defined above,
|
107 | 109 | # and the input data we will introduce further below. You can access different types of information by accessing the attributes. For instance, you
|
108 | 110 | # can retrieve the coordinates of our modeling grid as follows:
|
| 111 | + |
109 | 112 | # %%
|
110 | 113 | geo_model.grid
|
| 114 | + |
111 | 115 | # %% md
|
112 | 116 | # The `geo_model` object also contains the structural frame of our model, i.e., information about our main structural groups (also referred to as
|
113 | 117 | # series or stacks in our model), and their sequential and geological relationships with one another. Each group can contain several elements,
|
|
230 | 234 | # """"""""""""""""""""""""""""""""""
|
231 | 235 | # Ok, good! Now we have added the position of the bottom of this top layer for each borehole. But is this enough to compute our first layer?
|
232 | 236 | # Well, no. GemPy's approach is based on an implicit interpolation method that requires the following minimum data:
|
233 |
| -# - **Two surface points** for at least one surface in a structural group/series |
234 |
| -# - **One orientation** per structural group/series |
| 237 | +# |
| 238 | +# - **Two surface points** for at least one surface in a structural group/series |
| 239 | +# - **One orientation** per structural group/series |
235 | 240 | #
|
236 | 241 | # Thanks to GemPy's global interpolation approach, once you have one surface defined by two surface points and an orientation in a structural
|
237 | 242 | # group, you can add more surfaces (in the same group) with the minimum of one surface point, as it will now take its orientation information
|
|
336 | 341 | plt.show()
|
337 | 342 |
|
338 | 343 | # %% md
|
339 |
| -# ## Adding a Second Lithological Unit |
340 |
| -# |
| 344 | +# Adding a Second Lithological Unit |
| 345 | +# """"""""""""""""""""""""""""""""" |
341 | 346 | # To add another unit to our model, we can define it as another structural element and then append it to our `geo_model` object. We do this
|
342 | 347 | # for the second unit in the following steps. See how we can already give it a name (let's assume this is a siltstone now), a color corresponding
|
343 | 348 | # to the dot colors in the cross-section, as well as define surface points and orientations. By appending it to `structural_groups[0]`, we are
|
|
527 | 532 | # defines how a younger (upper) structural group will relate to the older (lower) structural groups and possibly affect their scalar field.
|
528 | 533 | #
|
529 | 534 | # The parameter `StackRelationType` can take the following values:
|
| 535 | +# |
530 | 536 | # - `BASEMENT`: Treats all lower groups as the basement.
|
531 | 537 | # - `ERODE`: Defines erosive contact/unconformity.
|
532 | 538 | # - `ONLAP`: Defines the younger group to be onlapping onto the older groups.
|
|
535 | 541 | # We will now take a look at each of these relation types except for the basement type.
|
536 | 542 |
|
537 | 543 | # %% md
|
538 |
| -# ### Erosive Contact |
539 |
| -# |
| 544 | +# Erosive Contact |
| 545 | +# """"""""""""""" |
540 | 546 | # For this, we don't have to change anything now, as we already set the `StackRelationType` to be `ERODE`. If we now plot it, we will see
|
541 | 547 | # how this younger structural group erodes all older elements and basically "cuts them out" in our model.
|
542 | 548 |
|
|
562 | 568 | # We can see how all units of the depositional series stop at the contact with the new discontinuity group. However, this doesn't look
|
563 | 569 | # quite right, and it in particular doesn't fit the surface point that was observed in the third borehole. So let's try another relation type.
|
564 | 570 | #
|
565 |
| -# ## Onlapping |
566 |
| -# |
| 571 | +# Onlapping |
| 572 | +# """"""""" |
567 | 573 | # Let's change the relation type from `ERODE` to `ONLAP` to achieve a different type of discontinuity and then plot it.
|
568 | 574 |
|
569 | 575 | # %%
|
|
594 | 600 | # Now the unit defined as part of the discontinuity group is onlapping onto the uppermost surface of the default group and ends there.
|
595 | 601 | # This also doesn't really make sense considering the data given, so let's try the last relation type.
|
596 | 602 | #
|
597 |
| -# ## Faults |
598 |
| -# |
| 603 | +# Faults |
| 604 | +# """""" |
599 | 605 | # Let's change the relation type to `FAULT` and plot the results. For a fault, we also need to make use of the function `set_is_fault`.
|
600 | 606 |
|
601 | 607 | # %%
|
|
652 | 658 | plt.show()
|
653 | 659 |
|
654 | 660 | # %% md
|
655 |
| -# ## Topography and Geological Maps |
656 |
| -# |
| 661 | +# Topography and Geological Maps |
| 662 | +# """""""""""""""""""""""""""""" |
657 | 663 | # In GemPy, we can add more grid types for different purposes, such as to add topography to our model. In this following section,
|
658 | 664 | # we will exemplify this by creating a random topography grid which allows us to intersect the surfaces as well as compute a high-resolution
|
659 | 665 | # geological map. GemPy has a built-in function to generate random topography. After executing it, a topography grid will be added to the
|
|
697 | 703 | # `set_topography_from_file` and `set_topography_from_arrays`.
|
698 | 704 |
|
699 | 705 | # %% md
|
700 |
| -# ## Extracting Model Solutions |
701 |
| -# |
| 706 | +# Extracting Model Solutions |
| 707 | +# """""""""""""""""""""""""" |
702 | 708 | # Once you have built a model, you might not only want to visualize it, but also further analyze it or export it for further utilization.
|
703 | 709 | # For this, it is good to know that the solutions from modeling are stored in `geo_model.solutions` and can be returned from there. This
|
704 | 710 | # includes the following outputs in particular:
|
705 | 711 | # - `geo_model.solutions.dc_meshes`: A list of the surface meshes in the model with the location of vertices and edges for each.
|
706 | 712 | # - `geo_model.solutions.raw_arrays`: An object containing numerous arrays that define various parts of the model. Of particular importance
|
707 | 713 | # are the lithology block (`lith_block`), the fault block (`fault_block`), and the scalar field matrix (`scalar_field_matrix`).
|
708 | 714 | #
|
709 |
| -# ### Mesh Solutions |
710 |
| -# |
| 715 | +# Mesh Solutions |
| 716 | +# """""""""""""" |
711 | 717 | # Let's take a quick look at how we can return some key information from `geo_model.solutions`. Starting with meshes, we can see that the list
|
712 | 718 | # `dc_meshes` can be indexed to return specific meshes and their respective vertices or edges. Please note that the order will be the same as
|
713 | 719 | # in our `structural_frame`, i.e., the index `[0]` will return the first and top surface, in our case, the discontinuity surface.
|
|
726 | 732 | geo_model.input_transform.apply_inverse(vertices_0)
|
727 | 733 |
|
728 | 734 | # %% md
|
729 |
| -# ### Lithology Block |
730 |
| -# |
| 735 | +# Lithology Block |
| 736 | +# """"""""""""""" |
731 | 737 | # The lithology block is an array that, for a given model realization/solution, returns the ID of the lithology for each voxel. Note below
|
732 | 738 | # that the `lith_block` first returns all values in the shape of one row. You might need to reshape it as shown below. For a regular grid,
|
733 | 739 | # you can reshape it using the resolution used in `geo_model`.
|
|
742 | 748 | print(lith_block.shape, lith_block)
|
743 | 749 |
|
744 | 750 | # %% md
|
745 |
| -# ### Grid Values |
746 |
| -# |
| 751 | +# Grid Values |
| 752 | +# """"""""""" |
747 | 753 | # Apart from these solutions, you might also need to return grid values. You can access the values for each grid in your `geo_model`
|
748 | 754 | # object via `geo_model.grid` as shown below.
|
749 | 755 | # %%
|
|
0 commit comments