@@ -34,144 +34,12 @@ class StructuralFrame:
34
34
# ? Should I create some sort of structural options class? For example, the masking descriptor and faults relations pointer
35
35
is_dirty : bool = True
36
36
37
- @model_validator (mode = "wrap" )
38
- @classmethod
39
- def deserialize_binary (cls , data : Union ["StructuralFrame" , dict ], constructor : ModelWrapValidatorHandler ["StructuralFrame" ]) -> "StructuralFrame" :
40
- match data :
41
- case StructuralFrame ():
42
- return data
43
- case dict ():
44
- instance : StructuralFrame = constructor (data )
45
- metadata = data .get ('binary_meta_data' , {})
46
-
47
- context = loading_model_context .get ()
48
-
49
- if 'binary_body' not in context :
50
- return instance
51
-
52
- binary_array = context ['binary_body' ]
53
-
54
- sp_binary = binary_array [:metadata ["sp_binary_length" ]]
55
- ori_binary = binary_array [metadata ["sp_binary_length" ]:]
56
-
57
- # Reconstruct arrays
58
- sp_data : np .ndarray = np .frombuffer (sp_binary , dtype = SurfacePointsTable .dt )
59
- ori_data : np .ndarray = np .frombuffer (ori_binary , dtype = OrientationsTable .dt )
60
-
61
- instance .surface_points = SurfacePointsTable (
62
- data = sp_data ,
63
- name_id_map = instance .surface_points_copy .name_id_map
64
- )
65
-
66
- instance .orientations = OrientationsTable (
67
- data = ori_data ,
68
- name_id_map = instance .orientations_copy .name_id_map
69
- )
70
-
71
- return instance
72
- case _:
73
- raise ValidationError (f"Invalid data type for StructuralFrame: { type (data )} " )
74
-
75
- # Access the context variable to get injected data
76
-
77
- @model_validator (mode = "after" )
78
- def deserialize_surface_points (self : "StructuralFrame" ):
79
- # Access the context variable to get injected data
80
- context = loading_model_context .get ()
81
-
82
- if 'surface_points_binary' not in context :
83
- return self
84
-
85
- # Check if we have a binary payload to digest
86
- binary_array = context ['surface_points_binary' ]
87
- if not isinstance (binary_array , np .ndarray ):
88
- return self
89
- if binary_array .shape [0 ] < 1 :
90
- return self
91
-
92
- self .surface_points = SurfacePointsTable (
93
- data = binary_array ,
94
- name_id_map = self .surface_points_copy .name_id_map
95
- )
96
-
97
- return self
98
-
99
- @model_validator (mode = "after" )
100
- def deserialize_orientations (self : "StructuralFrame" ):
101
- # TODO: Check here the binary size of surface_points_binary
102
-
103
- # Access the context variable to get injected data
104
- context = loading_model_context .get ()
105
- if 'orientations_binary' not in context :
106
- return self
107
-
108
- # Check if we have a binary payload to digest
109
- binary_array = context ['orientations_binary' ]
110
- if not isinstance (binary_array , np .ndarray ):
111
- return self
112
-
113
- self .orientations = OrientationsTable (
114
- data = binary_array ,
115
- name_id_map = self .orientations_copy .name_id_map
116
- )
117
-
118
- return self
119
-
120
- @computed_field
121
- def binary_meta_data (self ) -> dict :
122
- sp_data = self .surface_points_copy .data
123
- ori_data = self .orientations_copy .data
124
- return {
125
- 'sp_shape' : sp_data .shape ,
126
- 'sp_dtype' : str (sp_data .dtype ),
127
- 'sp_binary_length' : len (sp_data .tobytes ()),
128
- 'ori_shape' : ori_data .shape ,
129
- 'ori_dtype' : str (ori_data .dtype ),
130
- 'ori_binary_length' : len (ori_data .tobytes ())
131
- }
132
-
133
- @computed_field
134
- @property
135
- def serialize_sp (self ) -> int :
136
- return int (hashlib .md5 (self .surface_points_copy .data .tobytes ()).hexdigest ()[:8 ], 16 )
137
-
138
- @computed_field
139
- @property
140
- def serialize_orientations (self ) -> int :
141
- return int (hashlib .md5 (self .orientations_copy .data .tobytes ()).hexdigest ()[:8 ], 16 )
37
+ # region Constructor
142
38
143
39
def __init__ (self , structural_groups : list [StructuralGroup ], color_gen : ColorsGenerator ):
144
40
self .structural_groups = structural_groups # ? This maybe could be optional
145
41
self .color_generator = color_gen
146
42
147
- def get_element_by_name (self , element_name : str ) -> StructuralElement :
148
- elements : Generator = (group .get_element_by_name (element_name ) for group in self .structural_groups )
149
- valid_elements : Generator = (element for element in elements if element is not None )
150
- element = next (valid_elements , None )
151
- if element is None :
152
- raise ValueError (f"Element with name { element_name } not found in the structural frame." )
153
- return element
154
-
155
- def get_group_by_name (self , group_name : str ) -> StructuralGroup :
156
- groups : Generator = (group for group in self .structural_groups if group .name == group_name )
157
- group = next (groups , None )
158
- if group is None :
159
- raise ValueError (f"Group with name { group_name } not found in the structural frame." )
160
- return group
161
-
162
- def get_group_by_element (self , element : StructuralElement ) -> StructuralGroup :
163
- groups : Generator = (group for group in self .structural_groups if element in group .elements )
164
- group = next (groups , None )
165
- if group is None :
166
- raise ValueError (f"Element { element .name } not found in any group in the structural frame." )
167
- return group
168
-
169
- def append_group (self , group : StructuralGroup ):
170
- self .structural_groups .append (group )
171
-
172
- def insert_group (self , index : int , group : StructuralGroup ):
173
- self .structural_groups .insert (index , group )
174
-
175
43
@classmethod
176
44
def from_data_tables (cls , surface_points : SurfacePointsTable , orientations : OrientationsTable ):
177
45
surface_points_groups : list [SurfacePointsTable ] = surface_points .get_surface_points_by_id_groups ()
@@ -245,6 +113,37 @@ def initialize_default_structure(cls) -> 'StructuralFrame':
245
113
246
114
return structural_frame
247
115
116
+ # endregion
117
+
118
+ # region Methods
119
+ def get_element_by_name (self , element_name : str ) -> StructuralElement :
120
+ elements : Generator = (group .get_element_by_name (element_name ) for group in self .structural_groups )
121
+ valid_elements : Generator = (element for element in elements if element is not None )
122
+ element = next (valid_elements , None )
123
+ if element is None :
124
+ raise ValueError (f"Element with name { element_name } not found in the structural frame." )
125
+ return element
126
+
127
+ def get_group_by_name (self , group_name : str ) -> StructuralGroup :
128
+ groups : Generator = (group for group in self .structural_groups if group .name == group_name )
129
+ group = next (groups , None )
130
+ if group is None :
131
+ raise ValueError (f"Group with name { group_name } not found in the structural frame." )
132
+ return group
133
+
134
+ def get_group_by_element (self , element : StructuralElement ) -> StructuralGroup :
135
+ groups : Generator = (group for group in self .structural_groups if element in group .elements )
136
+ group = next (groups , None )
137
+ if group is None :
138
+ raise ValueError (f"Element { element .name } not found in any group in the structural frame." )
139
+ return group
140
+
141
+ def append_group (self , group : StructuralGroup ):
142
+ self .structural_groups .append (group )
143
+
144
+ def insert_group (self , index : int , group : StructuralGroup ):
145
+ self .structural_groups .insert (index , group )
146
+
248
147
def __repr__ (self ):
249
148
structural_groups_repr = ',\n ' .join ([repr (g ) for g in self .structural_groups ])
250
149
fault_relations_str = np .array2string (self .fault_relations , precision = 2 , separator = ', ' , suppress_small = True ) if self .fault_relations is not None else 'None'
@@ -285,6 +184,9 @@ def _repr_html_(self):
285
184
"""
286
185
return html
287
186
187
+ # endregion
188
+
189
+ # region Properties
288
190
@property
289
191
def structural_elements (self ) -> list [StructuralElement ]:
290
192
"""Returns a list of all structural elements across the structural groups."""
@@ -555,6 +457,117 @@ def surfaces_df(self) -> 'pd.DataFrame':
555
457
556
458
# endregion
557
459
460
+ # endregion
461
+ # region Pydantic
462
+
463
+ @model_validator (mode = "wrap" )
464
+ @classmethod
465
+ def deserialize_binary (cls , data : Union ["StructuralFrame" , dict ], constructor : ModelWrapValidatorHandler ["StructuralFrame" ]) -> "StructuralFrame" :
466
+ match data :
467
+ case StructuralFrame ():
468
+ return data
469
+ case dict ():
470
+ instance : StructuralFrame = constructor (data )
471
+ metadata = data .get ('binary_meta_data' , {})
472
+
473
+ context = loading_model_context .get ()
474
+
475
+ if 'binary_body' not in context :
476
+ return instance
477
+
478
+ binary_array = context ['binary_body' ]
479
+
480
+ sp_binary = binary_array [:metadata ["sp_binary_length" ]]
481
+ ori_binary = binary_array [metadata ["sp_binary_length" ]:]
482
+
483
+ # Reconstruct arrays
484
+ sp_data : np .ndarray = np .frombuffer (sp_binary , dtype = SurfacePointsTable .dt )
485
+ ori_data : np .ndarray = np .frombuffer (ori_binary , dtype = OrientationsTable .dt )
486
+
487
+ instance .surface_points = SurfacePointsTable (
488
+ data = sp_data ,
489
+ name_id_map = instance .surface_points_copy .name_id_map
490
+ )
491
+
492
+ instance .orientations = OrientationsTable (
493
+ data = ori_data ,
494
+ name_id_map = instance .orientations_copy .name_id_map
495
+ )
496
+
497
+ return instance
498
+ case _:
499
+ raise ValidationError (f"Invalid data type for StructuralFrame: { type (data )} " )
500
+
501
+ # Access the context variable to get injected data
502
+
503
+ @model_validator (mode = "after" )
504
+ def deserialize_surface_points (self : "StructuralFrame" ):
505
+ # Access the context variable to get injected data
506
+ context = loading_model_context .get ()
507
+
508
+ if 'surface_points_binary' not in context :
509
+ return self
510
+
511
+ # Check if we have a binary payload to digest
512
+ binary_array = context ['surface_points_binary' ]
513
+ if not isinstance (binary_array , np .ndarray ):
514
+ return self
515
+ if binary_array .shape [0 ] < 1 :
516
+ return self
517
+
518
+ self .surface_points = SurfacePointsTable (
519
+ data = binary_array ,
520
+ name_id_map = self .surface_points_copy .name_id_map
521
+ )
522
+
523
+ return self
524
+
525
+ @model_validator (mode = "after" )
526
+ def deserialize_orientations (self : "StructuralFrame" ):
527
+ # TODO: Check here the binary size of surface_points_binary
528
+
529
+ # Access the context variable to get injected data
530
+ context = loading_model_context .get ()
531
+ if 'orientations_binary' not in context :
532
+ return self
533
+
534
+ # Check if we have a binary payload to digest
535
+ binary_array = context ['orientations_binary' ]
536
+ if not isinstance (binary_array , np .ndarray ):
537
+ return self
538
+
539
+ self .orientations = OrientationsTable (
540
+ data = binary_array ,
541
+ name_id_map = self .orientations_copy .name_id_map
542
+ )
543
+
544
+ return self
545
+
546
+ @computed_field
547
+ def binary_meta_data (self ) -> dict :
548
+ sp_data = self .surface_points_copy .data
549
+ ori_data = self .orientations_copy .data
550
+ return {
551
+ 'sp_shape' : sp_data .shape ,
552
+ 'sp_dtype' : str (sp_data .dtype ),
553
+ 'sp_binary_length' : len (sp_data .tobytes ()),
554
+ 'ori_shape' : ori_data .shape ,
555
+ 'ori_dtype' : str (ori_data .dtype ),
556
+ 'ori_binary_length' : len (ori_data .tobytes ())
557
+ }
558
+
559
+ @computed_field
560
+ @property
561
+ def serialize_sp (self ) -> int :
562
+ return int (hashlib .md5 (self .surface_points_copy .data .tobytes ()).hexdigest ()[:8 ], 16 )
563
+
564
+ @computed_field
565
+ @property
566
+ def serialize_orientations (self ) -> int :
567
+ return int (hashlib .md5 (self .orientations_copy .data .tobytes ()).hexdigest ()[:8 ], 16 )
568
+
569
+ # endregion
570
+
558
571
def _validate_faults_relations (self ):
559
572
"""Check that if there are any StackRelationType.FAULT in the structural groups the fault relation matrix is
560
573
given and shape is the right one, i.e. a square matrix of size equals to len(groups)"""
0 commit comments