Skip to content

Commit e6fade1

Browse files
committed
Fixed stratigraphic pile handling in JSON I/O by reverting to working state
1 parent 2a7d8f8 commit e6fade1

File tree

1 file changed

+83
-49
lines changed

1 file changed

+83
-49
lines changed

gempy/modules/json_io/json_operations.py

Lines changed: 83 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
from .schema import SurfacePoint, Orientation, GemPyModelJson
1212
from gempy_engine.core.data.stack_relation_type import StackRelationType
13-
from gempy.core.data.structural_element import StructuralElement
1413

1514

1615
class JsonIO:
@@ -44,8 +43,6 @@ def load_model_from_json(file_path: str):
4443
from gempy.core.data.structural_frame import StructuralFrame
4544
from gempy_engine.core.data import InterpolationOptions
4645
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
4946

5047
with open(file_path, 'r') as f:
5148
data = json.load(f)
@@ -54,30 +51,52 @@ def load_model_from_json(file_path: str):
5451
if not JsonIO._validate_json_schema(data):
5552
raise ValueError("Invalid JSON schema")
5653

57-
# Create a mapping from surface IDs to names
58-
id_to_name = {}
54+
# Get surface names from series data
55+
surface_names = []
5956
for series in data['series']:
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
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
6568
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+
)
6693

67-
# Create GeoModel with default structural frame
94+
# Create GeoModel
6895
model = GeoModel(
6996
name=data['metadata']['name'],
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-
)
97+
structural_frame=structural_frame,
98+
grid=grid,
99+
interpolation_options=interpolation_options
81100
)
82101

83102
# Set the metadata with proper dates
@@ -89,34 +108,15 @@ def load_model_from_json(file_path: str):
89108
)
90109
model.meta = model_meta
91110

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)
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'])
116114

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
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
120120

121121
return model
122122

@@ -131,10 +131,26 @@ def _load_surface_points(surface_points_data: List[SurfacePoint], id_to_name: Op
131131
132132
Returns:
133133
SurfacePointsTable: A new SurfacePointsTable instance
134+
135+
Raises:
136+
ValueError: If the data is invalid or missing required fields
134137
"""
135138
# Import here to avoid circular imports
136139
from gempy.core.data.surface_points import SurfacePointsTable
137140

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+
138154
# Extract coordinates and other data
139155
x = np.array([sp['x'] for sp in surface_points_data])
140156
y = np.array([sp['y'] for sp in surface_points_data])
@@ -168,10 +184,28 @@ def _load_orientations(orientations_data: List[Orientation], id_to_name: Optiona
168184
169185
Returns:
170186
OrientationsTable: A new OrientationsTable instance
187+
188+
Raises:
189+
ValueError: If the data is invalid or missing required fields
171190
"""
172191
# Import here to avoid circular imports
173192
from gempy.core.data.orientations import OrientationsTable
174193

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+
175209
# Extract coordinates and other data
176210
x = np.array([ori['x'] for ori in orientations_data])
177211
y = np.array([ori['y'] for ori in orientations_data])

0 commit comments

Comments
 (0)