Skip to content

Commit bfb8a5b

Browse files
committed
[CLN] Tidying up GeoModel
1 parent 1133246 commit bfb8a5b

File tree

2 files changed

+100
-93
lines changed

2 files changed

+100
-93
lines changed

gempy/core/data/geo_model.py

Lines changed: 98 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -49,39 +49,19 @@ class GeoModelMeta:
4949
owner: str | None
5050

5151

52-
# @dataclass(init=False)
5352
class GeoModel(BaseModel):
5453
"""
5554
Class representing a geological model.
5655
5756
"""
5857

59-
model_config = ConfigDict(
60-
arbitrary_types_allowed=True,
61-
use_enum_values=False,
62-
json_encoders={
63-
np.ndarray: encode_numpy_array
64-
}
65-
)
66-
6758
meta: GeoModelMeta = Field(exclude=False) #: Meta-information about the geological model, like its name, creation and modification dates, and owner.
6859
structural_frame: StructuralFrame = Field(exclude=False) #: The structural information of the geological model.
6960
grid: Grid = Field(exclude=False, default=None) #: The general grid used in the geological model.
7061

7162
# region GemPy engine data types
7263
_interpolation_options: InterpolationOptions #: The interpolation options provided by the user.
7364

74-
@computed_field(alias="_interpolation_options")
75-
@property
76-
def interpolation_options(self) -> InterpolationOptions:
77-
self._infer_dense_grid_solution()
78-
self._interpolation_options.cache_model_name = self.meta.name
79-
return self._interpolation_options
80-
81-
@interpolation_options.setter
82-
def interpolation_options(self, value):
83-
self._interpolation_options = value
84-
8565
geophysics_input: GeophysicsInput = Field(default=None, exclude=True) #: The geophysics input of the geological model.
8666
input_transform: Transform = Field(default=None, exclude=False) #: The transformation used in the geological model for input points.
8767

@@ -92,78 +72,22 @@ def interpolation_options(self, value):
9272
# endregion
9373
_solutions: Solutions = PrivateAttr(init=False, default=None) #: The computed solutions of the geological model.
9474

95-
@model_validator(mode='wrap')
96-
@classmethod
97-
def deserialize_properties(cls, data: Union["GeoModel", dict], constructor: ModelWrapValidatorHandler["GeoModel"]) -> "GeoModel":
98-
try:
99-
match data:
100-
case GeoModel():
101-
return data
102-
case dict():
103-
instance: GeoModel = constructor(data)
104-
instantiate_if_necessary(
105-
data=data,
106-
key="_interpolation_options",
107-
type=InterpolationOptions
108-
)
109-
instance._interpolation_options = data.get("_interpolation_options")
110-
return instance
111-
case _:
112-
raise ValidationError
113-
except ValidationError:
114-
raise
115-
116-
@classmethod
117-
def from_args(cls, name: str, structural_frame: StructuralFrame, grid: Grid, interpolation_options: InterpolationOptions):
118-
# TODO: Fill the arguments properly
119-
meta = GeoModelMeta(
120-
name=name,
121-
creation_date=datetime.datetime.now().isoformat(),
122-
last_modification_date=None,
123-
owner=None
124-
)
125-
126-
structural_frame = structural_frame # ? This could be Optional
127-
128-
grid = grid
129-
_interpolation_options = interpolation_options
130-
input_transform = Transform.from_input_points(
131-
surface_points=structural_frame.surface_points_copy,
132-
orientations=structural_frame.orientations_copy
133-
)
134-
135-
model = GeoModel(
136-
meta=meta,
137-
structural_frame=structural_frame,
138-
grid=grid,
139-
input_transform=input_transform,
140-
_interpolation_options=_interpolation_options
141-
)
142-
143-
return model
144-
14575
def __repr__(self):
14676
# TODO: Improve this
14777
return pprint.pformat(self.__dict__)
14878

149-
def update_transform(self, auto_anisotropy: GlobalAnisotropy = GlobalAnisotropy.NONE, anisotropy_limit: Optional[np.ndarray] = None):
150-
"""Update the transformation of the geological model.
151-
152-
This function updates the transformation of the geological model using the provided surface points and orientations.
153-
It also applies anisotropy based on the specified type and limit.
154-
155-
Args:
156-
auto_anisotropy (GlobalAnisotropy): The type of anisotropy to apply. Defaults to GlobalAnisotropy.NONE.
157-
anisotropy_limit (Optional[np.ndarray]): Anisotropy limit values. If None, no limit is applied.
158-
159-
"""
79+
# region Properties
16080

161-
self.input_transform = Transform.from_input_points(
162-
surface_points=self.surface_points_copy,
163-
orientations=self.orientations_copy
164-
)
81+
@computed_field(alias="_interpolation_options")
82+
@property
83+
def interpolation_options(self) -> InterpolationOptions:
84+
self._infer_dense_grid_solution()
85+
self._interpolation_options.cache_model_name = self.meta.name
86+
return self._interpolation_options
16587

166-
self.input_transform.apply_anisotropy(anisotropy_type=auto_anisotropy, anisotropy_limit=anisotropy_limit)
88+
@interpolation_options.setter
89+
def interpolation_options(self, value):
90+
self._interpolation_options = value
16791

16892
@property
16993
def solutions(self) -> Solutions:
@@ -297,10 +221,98 @@ def input_data_descriptor(self) -> InputDataDescriptor:
297221
# TODO: This should have the exact same dirty logic as interpolation_input
298222
return self.structural_frame.input_data_descriptor
299223

224+
# endregion
225+
# region Constructors
226+
@classmethod
227+
def from_args(cls, name: str, structural_frame: StructuralFrame, grid: Grid, interpolation_options: InterpolationOptions):
228+
# TODO: Fill the arguments properly
229+
meta = GeoModelMeta(
230+
name=name,
231+
creation_date=datetime.datetime.now().isoformat(),
232+
last_modification_date=None,
233+
owner=None
234+
)
235+
236+
structural_frame = structural_frame # ? This could be Optional
237+
238+
grid = grid
239+
_interpolation_options = interpolation_options
240+
input_transform = Transform.from_input_points(
241+
surface_points=structural_frame.surface_points_copy,
242+
orientations=structural_frame.orientations_copy
243+
)
244+
245+
model = GeoModel(
246+
meta=meta,
247+
structural_frame=structural_frame,
248+
grid=grid,
249+
input_transform=input_transform,
250+
_interpolation_options=_interpolation_options
251+
)
252+
253+
return model
254+
255+
# endregion
256+
257+
# region Methods
258+
def update_transform(self, auto_anisotropy: GlobalAnisotropy = GlobalAnisotropy.NONE, anisotropy_limit: Optional[np.ndarray] = None):
259+
"""Update the transformation of the geological model.
260+
261+
This function updates the transformation of the geological model using the provided surface points and orientations.
262+
It also applies anisotropy based on the specified type and limit.
263+
264+
Args:
265+
auto_anisotropy (GlobalAnisotropy): The type of anisotropy to apply. Defaults to GlobalAnisotropy.NONE.
266+
anisotropy_limit (Optional[np.ndarray]): Anisotropy limit values. If None, no limit is applied.
267+
268+
"""
269+
270+
self.input_transform = Transform.from_input_points(
271+
surface_points=self.surface_points_copy,
272+
orientations=self.orientations_copy
273+
)
274+
275+
self.input_transform.apply_anisotropy(anisotropy_type=auto_anisotropy, anisotropy_limit=anisotropy_limit)
276+
300277
def add_surface_points(self, X: Sequence[float], Y: Sequence[float], Z: Sequence[float],
301278
surface: Sequence[str], nugget: Optional[Sequence[float]] = None) -> None:
302279
raise NotImplementedError("This method is deprecated. Use `gp.add_surface_points` instead")
303280

281+
# endregion
282+
283+
# region Pydantic serialization
284+
285+
model_config = ConfigDict(
286+
arbitrary_types_allowed=True,
287+
use_enum_values=False,
288+
json_encoders={
289+
np.ndarray: encode_numpy_array
290+
}
291+
)
292+
293+
@model_validator(mode='wrap')
294+
@classmethod
295+
def deserialize_properties(cls, data: Union["GeoModel", dict], constructor: ModelWrapValidatorHandler["GeoModel"]) -> "GeoModel":
296+
try:
297+
match data:
298+
case GeoModel():
299+
return data
300+
case dict():
301+
instance: GeoModel = constructor(data)
302+
instantiate_if_necessary(
303+
data=data,
304+
key="_interpolation_options",
305+
type=InterpolationOptions
306+
)
307+
instance._interpolation_options = data.get("_interpolation_options")
308+
return instance
309+
case _:
310+
raise ValidationError
311+
except ValidationError:
312+
raise
313+
314+
# endregion
315+
304316
def _infer_dense_grid_solution(self):
305317
octrees_set: bool = Grid.GridTypes.OCTREE in self.grid.active_grids
306318
dense_set: bool = Grid.GridTypes.DENSE in self.grid.active_grids

test/test_modules/test_serialize_model.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,8 @@
1010

1111
def test_generate_horizontal_stratigraphic_model():
1212
model: gp.data.GeoModel = gp.generate_example_model(ExampleModel.HORIZONTAL_STRAT, compute_model=False)
13-
1413
model_json = model.model_dump_json(by_alias=True)
1514

16-
# Pretty print JSON
17-
pprint.pp(model_json)
18-
19-
# Ensure the 'verify/' directory exists
20-
os.makedirs("verify", exist_ok=True)
21-
2215
# Write the JSON to disk
2316
file_path = os.path.join("temp", "horizontal_stratigraphic_model.json")
2417
with open(file_path, "w") as f:
@@ -42,6 +35,8 @@ def test_generate_horizontal_stratigraphic_model():
4235

4336
# # Validate json against schema
4437
if False:
38+
# Ensure the 'verify/' directory exists
39+
os.makedirs("verify", exist_ok=True)
4540
verify_json(model_json, name="verify/Horizontal Stratigraphic Model serialization")
4641

4742

0 commit comments

Comments
 (0)