1
+ """
2
+ Tutorial: Loading a Model with Multiple Series and Faults using JSON I/O
3
+ =====================================================================
4
+
5
+ This tutorial demonstrates how to load a geological model with multiple series and faults using GemPy's JSON I/O functionality.
6
+ The model consists of two layers (rock1, rock2) and a fault that offsets them.
7
+ """
8
+
9
+ # %%
10
+ # Import necessary libraries
11
+ import matplotlib
12
+ matplotlib .use ('Agg' ) # Use non-interactive backend
13
+ import gempy as gp
14
+ import gempy_viewer as gpv
15
+ import numpy as np
16
+ import json
17
+ from pathlib import Path
18
+ import matplotlib .pyplot as plt
19
+ from gempy_engine .core .data .stack_relation_type import StackRelationType
20
+ from gempy .modules .json_io .json_operations import JsonIO # Updated import path
21
+
22
+ # %%
23
+ # Define the model data
24
+ model_data = {
25
+ "metadata" : {
26
+ "name" : "multiple_series_faults" ,
27
+ "creation_date" : "2024-03-19" ,
28
+ "last_modification_date" : "2024-03-19" ,
29
+ "owner" : "tutorial"
30
+ },
31
+ "surface_points" : [
32
+ # fault surface points (previously rock1 points)
33
+ {"x" : 0.0 , "y" : 200.0 , "z" : 600.0 , "id" : 2 , "nugget" : 0.00002 },
34
+ {"x" : 0.0 , "y" : 500.0 , "z" : 600.0 , "id" : 2 , "nugget" : 0.00002 },
35
+ {"x" : 0.0 , "y" : 800.0 , "z" : 600.0 , "id" : 2 , "nugget" : 0.00002 },
36
+ {"x" : 200.0 , "y" : 200.0 , "z" : 600.0 , "id" : 2 , "nugget" : 0.00002 },
37
+ {"x" : 200.0 , "y" : 500.0 , "z" : 600.0 , "id" : 2 , "nugget" : 0.00002 },
38
+ {"x" : 200.0 , "y" : 800.0 , "z" : 600.0 , "id" : 2 , "nugget" : 0.00002 },
39
+ {"x" : 800.0 , "y" : 200.0 , "z" : 200.0 , "id" : 2 , "nugget" : 0.00002 },
40
+ {"x" : 800.0 , "y" : 500.0 , "z" : 200.0 , "id" : 2 , "nugget" : 0.00002 },
41
+ {"x" : 800.0 , "y" : 800.0 , "z" : 200.0 , "id" : 2 , "nugget" : 0.00002 },
42
+ {"x" : 1000.0 , "y" : 200.0 , "z" : 200.0 , "id" : 2 , "nugget" : 0.00002 },
43
+ {"x" : 1000.0 , "y" : 500.0 , "z" : 200.0 , "id" : 2 , "nugget" : 0.00002 },
44
+ {"x" : 1000.0 , "y" : 800.0 , "z" : 200.0 , "id" : 2 , "nugget" : 0.00002 },
45
+ # rock2 surface points
46
+ {"x" : 0.0 , "y" : 200.0 , "z" : 800.0 , "id" : 1 , "nugget" : 0.00002 },
47
+ {"x" : 0.0 , "y" : 800.0 , "z" : 800.0 , "id" : 1 , "nugget" : 0.00002 },
48
+ {"x" : 200.0 , "y" : 200.0 , "z" : 800.0 , "id" : 1 , "nugget" : 0.00002 },
49
+ {"x" : 200.0 , "y" : 800.0 , "z" : 800.0 , "id" : 1 , "nugget" : 0.00002 },
50
+ {"x" : 800.0 , "y" : 200.0 , "z" : 400.0 , "id" : 1 , "nugget" : 0.00002 },
51
+ {"x" : 800.0 , "y" : 800.0 , "z" : 400.0 , "id" : 1 , "nugget" : 0.00002 },
52
+ {"x" : 1000.0 , "y" : 200.0 , "z" : 400.0 , "id" : 1 , "nugget" : 0.00002 },
53
+ {"x" : 1000.0 , "y" : 800.0 , "z" : 400.0 , "id" : 1 , "nugget" : 0.00002 },
54
+ # rock1 surface points (previously fault points)
55
+ {"x" : 500.0 , "y" : 500.0 , "z" : 500.0 , "id" : 0 , "nugget" : 0.00002 },
56
+ {"x" : 450.0 , "y" : 500.0 , "z" : 600.0 , "id" : 0 , "nugget" : 0.00002 },
57
+ {"x" : 500.0 , "y" : 200.0 , "z" : 500.0 , "id" : 0 , "nugget" : 0.00002 },
58
+ {"x" : 450.0 , "y" : 200.0 , "z" : 600.0 , "id" : 0 , "nugget" : 0.00002 },
59
+ {"x" : 500.0 , "y" : 800.0 , "z" : 500.0 , "id" : 0 , "nugget" : 0.00002 },
60
+ {"x" : 450.0 , "y" : 800.0 , "z" : 600.0 , "id" : 0 , "nugget" : 0.00002 },
61
+ ],
62
+ "orientations" : [
63
+ # rock2 orientation (upper layer at x=100)
64
+ {"x" : 100.0 , "y" : 500.0 , "z" : 800.0 , "G_x" : 0.0 , "G_y" : 0.0 , "G_z" : 1.0 , "id" : 1 , "nugget" : 0.01 , "polarity" : 1 },
65
+ # rock1 orientation (lower layer at x=100)
66
+ {"x" : 100.0 , "y" : 500.0 , "z" : 600.0 , "G_x" : 0.0 , "G_y" : 0.0 , "G_z" : 1.0 , "id" : 2 , "nugget" : 0.01 , "polarity" : 1 },
67
+ # fault orientation (at x=500)
68
+ {"x" : 500.0 , "y" : 500.0 , "z" : 500.0 , "G_x" : 0.8 , "G_y" : 0.0 , "G_z" : 0.6 , "id" : 0 , "nugget" : 0.01 , "polarity" : 1 },
69
+ # rock2 orientation (upper layer at x=900)
70
+ {"x" : 900.0 , "y" : 500.0 , "z" : 400.0 , "G_x" : 0.0 , "G_y" : 0.0 , "G_z" : 1.0 , "id" : 1 , "nugget" : 0.01 , "polarity" : 1 },
71
+ # rock1 orientation (lower layer at x=900)
72
+ {"x" : 900.0 , "y" : 500.0 , "z" : 200.0 , "G_x" : 0.0 , "G_y" : 0.0 , "G_z" : 1.0 , "id" : 2 , "nugget" : 0.01 , "polarity" : 1 },
73
+ ],
74
+ "series" : [
75
+ {
76
+ "name" : "Fault_Series" ,
77
+ "surfaces" : ["fault" ],
78
+ "structural_relation" : "FAULT" ,
79
+ "color" : "#015482" # Blue color for fault
80
+ },
81
+ {
82
+ "name" : "Strat_Series" ,
83
+ "surfaces" : ["rock2" , "rock1" ],
84
+ "structural_relation" : "ERODE" ,
85
+ "colors" : ["#ffbe00" , "#9f0052" ] # Yellow for rock2, Pink for rock1
86
+ }
87
+ ],
88
+ "grid_settings" : {
89
+ "regular_grid_resolution" : [90 , 30 , 30 ], # Increased resolution for better visualization
90
+ "regular_grid_extent" : [0 , 1000 , 0 , 1000 , 0 , 1000 ],
91
+ "octree_levels" : None
92
+ },
93
+ "interpolation_options" : {}
94
+ }
95
+
96
+ # %%
97
+ # Save the model data to a JSON file
98
+ tutorial_dir = Path (__file__ ).parent
99
+ json_file = tutorial_dir / "multiple_series_faults.json"
100
+ with open (json_file , "w" ) as f :
101
+ json .dump (model_data , f , indent = 4 )
102
+
103
+ # %%
104
+ # Load the model from JSON
105
+ model = JsonIO .load_model_from_json (str (json_file ))
106
+
107
+ # Print structural groups
108
+ print ("\n Structural Groups:" )
109
+ print (model .structural_frame .structural_groups )
110
+
111
+ # %%
112
+ # Set fault relations
113
+ # Create a 2x2 matrix for fault relations (2 series: Fault_Series, Strat_Series)
114
+ # 1 means the fault affects the series, 0 means it doesn't
115
+ model .structural_frame .fault_relations = np .array ([
116
+ [0 , 1 ], # Fault_Series affects Strat_Series
117
+ [0 , 0 ] # Strat_Series doesn't affect any series
118
+ ])
119
+
120
+ # Explicitly set the structural relation for the fault series
121
+ model .structural_frame .structural_groups [0 ].structural_relation = StackRelationType .FAULT
122
+
123
+ # Set the fault series as a fault
124
+ gp .set_is_fault (
125
+ frame = model ,
126
+ fault_groups = ['Fault_Series' ]
127
+ )
128
+
129
+ # %%
130
+ # Compute the geological model
131
+ gp .compute_model (model )
132
+
133
+ # %%
134
+ # Plot the model
135
+ # Plot the initial geological model in the y direction without results
136
+ fig , ax = plt .subplots (figsize = (10 , 6 ))
137
+ gpv .plot_2d (model , direction = ['y' ], show_results = False , ax = ax )
138
+ plt .title ("Initial Geological Model (y direction)" )
139
+ plt .savefig ('initial_model_y.png' )
140
+ plt .close ()
141
+
142
+ # Plot the result of the model in the x and y direction with data and without boundaries
143
+ fig , (ax1 , ax2 ) = plt .subplots (1 , 2 , figsize = (15 , 6 ))
144
+ gpv .plot_2d (model , direction = ['x' ], show_data = True , show_boundaries = False , ax = ax1 )
145
+ ax1 .set_title ("Model with Data (x direction)" )
146
+ gpv .plot_2d (model , direction = ['y' ], show_data = True , show_boundaries = False , ax = ax2 )
147
+ ax2 .set_title ("Model with Data (y direction)" )
148
+ plt .tight_layout ()
149
+ plt .savefig ('model_with_data.png' )
150
+ plt .close ()
151
+
152
+ # Plot the scalar field of the fault
153
+ fig , ax = plt .subplots (figsize = (10 , 6 ))
154
+ gpv .plot_2d (model , show_scalar = True , show_lith = False , series_n = 0 , ax = ax )
155
+ plt .title ("Fault Scalar Field" )
156
+ plt .savefig ('fault_scalar_field.png' )
157
+ plt .close ()
0 commit comments