10
10
11
11
from .schema import SurfacePoint , Orientation , GemPyModelJson
12
12
from gempy_engine .core .data .stack_relation_type import StackRelationType
13
+ from gempy .core .data .structural_element import StructuralElement
13
14
14
15
15
16
class JsonIO :
@@ -43,6 +44,8 @@ def load_model_from_json(file_path: str):
43
44
from gempy .core .data .structural_frame import StructuralFrame
44
45
from gempy_engine .core .data import InterpolationOptions
45
46
from gempy .API .map_stack_to_surfaces_API import map_stack_to_surfaces
47
+ from gempy_engine .core .data .stack_relation_type import StackRelationType
48
+ from gempy .core .data .structural_group import StructuralGroup
46
49
47
50
with open (file_path , 'r' ) as f :
48
51
data = json .load (f )
@@ -51,52 +54,30 @@ def load_model_from_json(file_path: str):
51
54
if not JsonIO ._validate_json_schema (data ):
52
55
raise ValueError ("Invalid JSON schema" )
53
56
54
- # Get surface names from series data
55
- surface_names = []
57
+ # Create a mapping from surface IDs to names
58
+ id_to_name = {}
56
59
for series in data ['series' ]:
57
- surface_names .extend (series ['surfaces' ])
58
-
59
- # Create a mapping from surface points to their names
60
- surface_point_names = {}
61
- for sp in data ['surface_points' ]:
62
- # Find the surface name that corresponds to this ID
63
- surface_name = None
64
- for series in data ['series' ]:
65
- for i , name in enumerate (series ['surfaces' ]):
66
- if i == sp ['id' ]: # Match the ID with the index in the series
67
- surface_name = name
60
+ for surface_name in series ['surfaces' ]:
61
+ # Find the ID for this surface name from surface points
62
+ for sp in data ['surface_points' ]:
63
+ if sp ['id' ] not in id_to_name :
64
+ id_to_name [sp ['id' ]] = surface_name
68
65
break
69
- if surface_name is not None :
70
- break
71
- surface_point_names [sp ['id' ]] = surface_name if surface_name is not None else f"surface_{ sp ['id' ]} "
72
-
73
- # Load surface points and orientations
74
- surface_points = JsonIO ._load_surface_points (data ['surface_points' ], surface_point_names )
75
- orientations = JsonIO ._load_orientations (data ['orientations' ], surface_point_names )
76
-
77
- # Create structural frame
78
- structural_frame = StructuralFrame .from_data_tables (surface_points , orientations )
79
-
80
- # Create grid
81
- grid = Grid (
82
- extent = data ['grid_settings' ]['regular_grid_extent' ],
83
- resolution = data ['grid_settings' ]['regular_grid_resolution' ]
84
- )
85
-
86
- # Create interpolation options with kernel options
87
- interpolation_options = InterpolationOptions (
88
- range = data ['interpolation_options' ].get ('kernel_options' , {}).get ('range' , 1.7 ),
89
- c_o = data ['interpolation_options' ].get ('kernel_options' , {}).get ('c_o' , 10 ),
90
- mesh_extraction = data ['interpolation_options' ].get ('mesh_extraction' , True ),
91
- number_octree_levels = data ['interpolation_options' ].get ('number_octree_levels' , 1 )
92
- )
93
66
94
- # Create GeoModel
67
+ # Create GeoModel with default structural frame
95
68
model = GeoModel (
96
69
name = data ['metadata' ]['name' ],
97
- structural_frame = structural_frame ,
98
- grid = grid ,
99
- interpolation_options = interpolation_options
70
+ structural_frame = StructuralFrame .initialize_default_structure (),
71
+ grid = Grid (
72
+ extent = data ['grid_settings' ]['regular_grid_extent' ],
73
+ resolution = data ['grid_settings' ]['regular_grid_resolution' ]
74
+ ),
75
+ interpolation_options = InterpolationOptions (
76
+ range = data ['interpolation_options' ].get ('kernel_options' , {}).get ('range' , 1.7 ),
77
+ c_o = data ['interpolation_options' ].get ('kernel_options' , {}).get ('c_o' , 10 ),
78
+ mesh_extraction = data ['interpolation_options' ].get ('mesh_extraction' , True ),
79
+ number_octree_levels = data ['interpolation_options' ].get ('number_octree_levels' , 1 )
80
+ )
100
81
)
101
82
102
83
# Set the metadata with proper dates
@@ -108,15 +89,34 @@ def load_model_from_json(file_path: str):
108
89
)
109
90
model .meta = model_meta
110
91
111
- # Map series to surfaces with structural relations
112
- mapping_object = {series ['name' ]: series ['surfaces' ] for series in data ['series' ]}
113
- map_stack_to_surfaces (model , mapping_object , series_data = data ['series' ])
92
+ # Load surface points and orientations with the ID to name mapping
93
+ surface_points = JsonIO ._load_surface_points (data ['surface_points' ], id_to_name )
94
+ orientations = JsonIO ._load_orientations (data ['orientations' ], id_to_name )
95
+
96
+ # Create structural groups based on series data
97
+ model .structural_frame .structural_groups = []
98
+ for i , series in enumerate (data ['series' ]):
99
+ group = StructuralGroup (
100
+ name = series ['name' ],
101
+ elements = [],
102
+ structural_relation = StackRelationType [series .get ('structural_relation' , 'ERODE' )]
103
+ )
104
+ model .structural_frame .structural_groups .append (group )
105
+
106
+ # Add elements to the group
107
+ for surface_name in series ['surfaces' ]:
108
+ element = StructuralElement (
109
+ name = surface_name ,
110
+ id = len (group .elements ),
111
+ surface_points = surface_points .get_surface_points_by_name (surface_name ),
112
+ orientations = orientations .get_orientations_by_name (surface_name ),
113
+ color = next (model .structural_frame .color_generator )
114
+ )
115
+ group .append_element (element )
114
116
115
- # Set fault relations after structural groups are set up
116
- if 'fault_relations' in data and data ['fault_relations' ] is not None :
117
- fault_relations = np .array (data ['fault_relations' ])
118
- if fault_relations .shape == (len (model .structural_frame .structural_groups ), len (model .structural_frame .structural_groups )):
119
- model .structural_frame .fault_relations = fault_relations
117
+ # Ensure the last group has the correct structural relation for the basement
118
+ if model .structural_frame .structural_groups :
119
+ model .structural_frame .structural_groups [- 1 ].structural_relation = StackRelationType .BASEMENT
120
120
121
121
return model
122
122
@@ -131,26 +131,10 @@ def _load_surface_points(surface_points_data: List[SurfacePoint], id_to_name: Op
131
131
132
132
Returns:
133
133
SurfacePointsTable: A new SurfacePointsTable instance
134
-
135
- Raises:
136
- ValueError: If the data is invalid or missing required fields
137
134
"""
138
135
# Import here to avoid circular imports
139
136
from gempy .core .data .surface_points import SurfacePointsTable
140
137
141
- # Validate data structure
142
- required_fields = {'x' , 'y' , 'z' , 'nugget' , 'id' }
143
- for i , sp in enumerate (surface_points_data ):
144
- missing_fields = required_fields - set (sp .keys ())
145
- if missing_fields :
146
- raise ValueError (f"Missing required fields in surface point { i } : { missing_fields } " )
147
-
148
- # Validate data types
149
- if not all (isinstance (sp [field ], (int , float )) for field in ['x' , 'y' , 'z' , 'nugget' ]):
150
- raise ValueError (f"Invalid data type in surface point { i } . All coordinates and nugget must be numeric." )
151
- if not isinstance (sp ['id' ], int ):
152
- raise ValueError (f"Invalid data type in surface point { i } . ID must be an integer." )
153
-
154
138
# Extract coordinates and other data
155
139
x = np .array ([sp ['x' ] for sp in surface_points_data ])
156
140
y = np .array ([sp ['y' ] for sp in surface_points_data ])
@@ -184,28 +168,10 @@ def _load_orientations(orientations_data: List[Orientation], id_to_name: Optiona
184
168
185
169
Returns:
186
170
OrientationsTable: A new OrientationsTable instance
187
-
188
- Raises:
189
- ValueError: If the data is invalid or missing required fields
190
171
"""
191
172
# Import here to avoid circular imports
192
173
from gempy .core .data .orientations import OrientationsTable
193
174
194
- # Validate data structure
195
- required_fields = {'x' , 'y' , 'z' , 'G_x' , 'G_y' , 'G_z' , 'nugget' , 'polarity' , 'id' }
196
- for i , ori in enumerate (orientations_data ):
197
- missing_fields = required_fields - set (ori .keys ())
198
- if missing_fields :
199
- raise ValueError (f"Missing required fields in orientation { i } : { missing_fields } " )
200
-
201
- # Validate data types
202
- if not all (isinstance (ori [field ], (int , float )) for field in ['x' , 'y' , 'z' , 'G_x' , 'G_y' , 'G_z' , 'nugget' ]):
203
- raise ValueError (f"Invalid data type in orientation { i } . All coordinates, gradients, and nugget must be numeric." )
204
- if not isinstance (ori .get ('polarity' , 1 ), int ) or ori .get ('polarity' , 1 ) not in {- 1 , 1 }:
205
- raise ValueError (f"Invalid polarity in orientation { i } . Must be 1 (normal) or -1 (reverse)." )
206
- if not isinstance (ori ['id' ], int ):
207
- raise ValueError (f"Invalid data type in orientation { i } . ID must be an integer." )
208
-
209
175
# Extract coordinates and other data
210
176
x = np .array ([ori ['x' ] for ori in orientations_data ])
211
177
y = np .array ([ori ['y' ] for ori in orientations_data ])
0 commit comments