11from typing import Union
2+
3+ from LoopStructural .utils .maths import rotation
24from ._structural_frame_builder import StructuralFrameBuilder
35from .. import AnalyticalGeologicalFeature
46from LoopStructural .utils import get_vectors
@@ -135,9 +137,9 @@ def create_data_from_geometry(
135137 )
136138
137139 if len (vector_data ) == 0 :
138- logger .error (
139- "You cannot model a fault without defining the orientation of the fault\n \
140- Defaulting to a vertical fault"
140+ logger .warning (
141+ f"No orientation data for fault\n \
142+ Defaulting to a dip of { fault_dip } vertical fault"
141143 )
142144 if fault_frame_data .loc [trace_mask , :].shape [0 ] > 3 :
143145
@@ -149,20 +151,22 @@ def create_data_from_geometry(
149151 slope , intercept = coefficients
150152
151153 # Create a direction vector using the slope
152- direction_vector = np .array ([1 , slope ])
154+ direction_vector = np .array ([1 , slope , 0 ])
153155 direction_vector /= np .linalg .norm (direction_vector )
154- print ( f"Fault dip: { fault_dip } " )
156+ rotation_matrix = rotation ( direction_vector [ None , :], [ 90 - fault_dip ] )
155157 vector_data = np .array (
156158 [
157159 [
158160 direction_vector [1 ],
159161 - direction_vector [0 ],
160- np . sin ( np . deg2rad ( fault_dip )) ,
162+ 0 ,
161163 ]
162164 ]
163165 )
164- vector_data /= np .linalg .norm (vector_data , axis = 1 )[:, None ]
166+ vector_data /= np .linalg .norm (vector_data , axis = 1 )
167+ vector_data = np .einsum ("ijk,ik->ij" , rotation_matrix , vector_data )
165168
169+ vector_data /= np .linalg .norm (vector_data , axis = 1 )
166170 fault_normal_vector = np .mean (vector_data , axis = 0 )
167171
168172 logger .info (f"Fault normal vector: { fault_normal_vector } " )
@@ -221,11 +225,11 @@ def create_data_from_geometry(
221225 self .fault_minor_axis = minor_axis
222226 self .fault_major_axis = major_axis
223227 self .fault_intermediate_axis = intermediate_axis
224- fault_normal_vector /= np .linalg .norm (fault_normal_vector )
228+ self . fault_normal_vector /= np .linalg .norm (self . fault_normal_vector )
225229 fault_slip_vector /= np .linalg .norm (fault_slip_vector )
226230 # check if slip vector is inside fault plane, if not project onto fault plane
227231 # if not np.isclose(normal_vector @ slip_vector, 0):
228- strike_vector = np .cross (fault_normal_vector , fault_slip_vector )
232+ strike_vector = np .cross (self . fault_normal_vector , fault_slip_vector )
229233 self .fault_strike_vector = strike_vector
230234
231235 fault_edges = np .zeros ((2 , 3 ))
@@ -252,8 +256,8 @@ def create_data_from_geometry(
252256 )
253257 if fault_center is not None :
254258 if minor_axis is not None :
255- fault_edges [0 , :] = fault_center [:3 ] + fault_normal_vector * minor_axis
256- fault_edges [1 , :] = fault_center [:3 ] - fault_normal_vector * minor_axis
259+ fault_edges [0 , :] = fault_center [:3 ] + self . fault_normal_vector * minor_axis
260+ fault_edges [1 , :] = fault_center [:3 ] - self . fault_normal_vector * minor_axis
257261 self .update_geometry (fault_edges )
258262
259263 # choose whether to add points -1,1 to constrain fault frame or a scaled
@@ -342,9 +346,9 @@ def create_data_from_geometry(
342346 fault_center [1 ],
343347 fault_center [2 ],
344348 self .name ,
345- fault_normal_vector [0 ] / minor_axis * 0.5 ,
346- fault_normal_vector [1 ] / minor_axis * 0.5 ,
347- fault_normal_vector [2 ] / minor_axis * 0.5 ,
349+ self . fault_normal_vector [0 ] / minor_axis * 0.5 ,
350+ self . fault_normal_vector [1 ] / minor_axis * 0.5 ,
351+ self . fault_normal_vector [2 ] / minor_axis * 0.5 ,
348352 np .nan ,
349353 0 ,
350354 w ,
@@ -439,9 +443,9 @@ def create_data_from_geometry(
439443
440444 self .add_data_from_data_frame (fault_frame_data )
441445 if fault_trace_anisotropy > 0 :
442- self .add_fault_trace_anisotropy (fault_trace_anisotropy )
446+ self .add_fault_trace_anisotropy (w = fault_trace_anisotropy )
443447 if fault_dip_anisotropy > 0 :
444- self .add_fault_dip_anisotropy (fault_dip_anisotropy )
448+ self .add_fault_dip_anisotropy (w = fault_dip_anisotropy )
445449 if force_mesh_geometry :
446450 self .set_mesh_geometry (fault_buffer , None )
447451 self .update_geometry (fault_frame_data [["X" , "Y" , "Z" ]].to_numpy ())
@@ -501,29 +505,24 @@ def add_fault_trace_anisotropy(self, w: float = 1.0):
501505 w : float, optional
502506 _description_, by default 1.0
503507 """
504- trace_data = self .builders [0 ].data .loc [self .builders [0 ].data ["val" ] == 0 , :]
505- if trace_data .shape [0 ] < 2 :
506- logger .warning (
507- f"Only { trace_data .shape [0 ]} point on fault trace, cannot add fault trace anisotropy. Need at least 3 points"
508+ if w > 0 :
509+
510+ plane = np .array ([0 , 0 , 1 ])
511+ strike_vector = (
512+ self .fault_normal_vector - np .dot (self .fault_normal_vector , plane ) * plane
513+ )
514+ strike_vector /= np .linalg .norm (strike_vector )
515+ strike_vector = np .array ([strike_vector [1 ], - strike_vector [0 ], 0 ])
516+
517+ anisotropy_feature = AnalyticalGeologicalFeature (
518+ vector = strike_vector , origin = [0 , 0 , 0 ], name = "fault_trace_anisotropy"
519+ )
520+ print ('adding fault trace anisotropy' )
521+ self .builders [0 ].add_orthogonal_feature (
522+ anisotropy_feature , w = w , region = None , step = 1 , B = 0
508523 )
509- return
510- coefficients = np .polyfit (
511- trace_data ["X" ],
512- trace_data ["Y" ],
513- 1 ,
514- )
515- slope , intercept = coefficients
516-
517- # Create a direction vector using the slope
518- direction_vector = np .array ([1 , slope ])
519- direction_vector /= np .linalg .norm (direction_vector )
520- vector_data = np .array ([[direction_vector [1 ], - direction_vector [0 ], 0 ]])
521- anisotropy_feature = AnalyticalGeologicalFeature (
522- vector = vector_data , origin = [0 , 0 , 0 ], name = "fault_trace_anisotropy"
523- )
524- self .builders [0 ].add_orthogonal_feature (anisotropy_feature , w = w , region = None , step = 1 , B = 0 )
525524
526- def add_fault_dip_anisotropy (self , dip : np . ndarray , w : float = 1.0 ):
525+ def add_fault_dip_anisotropy (self , w : float = 1.0 ):
527526 """_summary_
528527
529528 Parameters
@@ -533,32 +532,23 @@ def add_fault_dip_anisotropy(self, dip: np.ndarray, w: float = 1.0):
533532 w : float, optional
534533 _description_, by default 1.0
535534 """
536-
537- trace_data = self .builders [0 ].data .loc [self .builders [0 ].data ["val" ] == 0 , :]
538- if trace_data .shape [0 ] < 2 :
539- logger .warning (
540- f'Only { trace_data .shape [0 ]} point on fault trace, cannot add fault trace anisotropy. Need at least 3 points'
535+ if w > 0 :
536+ plane = np .array ([0 , 0 , 1 ])
537+ strike_vector = (
538+ self .fault_normal_vector - np .dot (self .fault_normal_vector , plane ) * plane
541539 )
542- return
543- coefficients = np .polyfit (
544- trace_data ["X" ],
545- trace_data ["Y" ],
546- 1 ,
547- )
548- slope , intercept = coefficients
540+ strike_vector /= np .linalg .norm (strike_vector )
541+ strike_vector = np .array ([strike_vector [1 ], - strike_vector [0 ], 0 ])
549542
550- # Create a direction vector using the slope
551- direction_vector = np .array ([1 , slope ])
552- direction_vector /= np .linalg .norm (direction_vector )
553- vector_data = np .array ([[direction_vector [0 ], direction_vector [1 ], 0 ]])
543+ dip_vector = np .cross (strike_vector , self .fault_normal_vector )
554544
555- vector_data = np . array (
556- [[ direction_vector [ 1 ], - direction_vector [ 0 ], np . sin ( np . deg2rad ( dip ))]]
557- )
558- anisotropy_feature = AnalyticalGeologicalFeature (
559- vector = vector_data , origin = [ 0 , 0 , 0 ], name = "fault_dip_anisotropy"
560- )
561- self . builders [ 0 ]. add_orthogonal_feature ( anisotropy_feature , w = w , region = None , step = 1 , B = 0 )
545+ anisotropy_feature = AnalyticalGeologicalFeature (
546+ vector = dip_vector , origin = [ 0 , 0 , 0 ], name = "fault_dip_anisotropy"
547+ )
548+ print ( f'adding fault dip anisotropy { anisotropy_feature . name } ' )
549+ self . builders [ 0 ]. add_orthogonal_feature (
550+ anisotropy_feature , w = w , region = None , step = 1 , B = 0
551+ )
562552
563553 def update (self ):
564554 for i in range (3 ):
0 commit comments