@@ -311,13 +311,14 @@ def evaluate_displacement(self, points):
311311 d [mask ] = self .faultfunction (gx [mask ] + self .fault_offset , gy [mask ], gz [mask ])
312312 return d * self .displacement
313313
314- def apply_to_points (self , points , reverse = False ):
314+ def apply_to_points (self , points , reverse = False , precomputed_gx = None ):
315315 """
316316 Unfault the array of points
317317
318318 Parameters
319319 ----------
320320 points - numpy array Nx3
321+ precomputed_gx - optional pre-evaluated gx values (same points, avoids duplicate evaluation)
321322
322323 Returns
323324 -------
@@ -328,10 +329,12 @@ def apply_to_points(self, points, reverse=False):
328329 newp = np .copy (points ).astype (float )
329330 # evaluate fault function for all points
330331 # then define mask for only points affected by fault
331- gx = None
332- gy = None
333- gz = None
334- if use_threads :
332+ # gx may be supplied by caller to avoid re-evaluation (precomputed from region check)
333+ if precomputed_gx is not None :
334+ gx = precomputed_gx
335+ gy = self .__getitem__ (1 ).evaluate_value (newp )
336+ gz = self .__getitem__ (2 ).evaluate_value (newp )
337+ elif use_threads :
335338 with ThreadPoolExecutor (max_workers = 8 ) as executor :
336339 # all of these operations should be
337340 # independent so just run as different threads
@@ -361,27 +364,32 @@ def apply_to_points(self, points, reverse=False):
361364 d *= - 1.0
362365 # calculate the fault frame for the evaluation points
363366 for _i in range (steps ):
364- gx = None
365- gy = None
366- gz = None
367367 g = None
368- if use_threads :
368+ if _i == 0 :
369+ # Reuse gx/gy/gz from the initial full-array evaluation above — newp[mask] hasn't
370+ # moved yet on the first iteration, so values are identical.
371+ gx_m = gx [mask ]
372+ gy_m = gy [mask ]
373+ gz_m = gz [mask ]
374+ g = self .__getitem__ (1 ).evaluate_gradient (newp [mask , :], ignore_regions = True )
375+ elif use_threads :
369376 with ThreadPoolExecutor (max_workers = 8 ) as executor :
370377 # all of these operations should be
371378 # independent so just run as different threads
372379 gx_future = executor .submit (self .__getitem__ (0 ).evaluate_value , newp [mask , :])
373380 g_future = executor .submit (self .__getitem__ (1 ).evaluate_gradient , newp [mask , :])
374381 gy_future = executor .submit (self .__getitem__ (1 ).evaluate_value , newp [mask , :])
375382 gz_future = executor .submit (self .__getitem__ (2 ).evaluate_value , newp [mask , :])
376- gx = gx_future .result ()
383+ gx_m = gx_future .result ()
377384 g = g_future .result ()
378- gy = gy_future .result ()
379- gz = gz_future .result ()
385+ gy_m = gy_future .result ()
386+ gz_m = gz_future .result ()
380387 else :
381- gx = self .__getitem__ (0 ).evaluate_value (newp [mask , :])
382- gy = self .__getitem__ (1 ).evaluate_value (newp [mask , :])
383- gz = self .__getitem__ (2 ).evaluate_value (newp [mask , :])
388+ gx_m = self .__getitem__ (0 ).evaluate_value (newp [mask , :])
389+ gy_m = self .__getitem__ (1 ).evaluate_value (newp [mask , :])
390+ gz_m = self .__getitem__ (2 ).evaluate_value (newp [mask , :])
384391 g = self .__getitem__ (1 ).evaluate_gradient (newp [mask , :], ignore_regions = True )
392+ gx , gy , gz = gx_m , gy_m , gz_m # alias for block below
385393 # # get the fault frame val/grad for the points
386394 # determine displacement magnitude, for constant displacement
387395 # hanging wall should be > 0
0 commit comments