1515# from lsdo_function_spaces.core.function_space import FunctionSpace
1616import lsdo_function_spaces as lfs
1717import vedo
18+ from lsdo_function_spaces .utils .internal_utilities import get_projection_squared_distances
1819
1920
2021
@@ -181,7 +182,7 @@ def integrate(self, area, grid_n=10, quadrature_order=2):
181182
182183 # compute areas of the quadrilaterals
183184 grid_values = area .evaluate (parametric_coordinates = parametric_grid .reshape (- 1 ,2 )).reshape ((grid_n , grid_n , - 1 ))
184- output = csdl .Variable (value = np .zeros (( grid_n - 1 , grid_n - 1 ) ))
185+ output = csdl .Variable (value = np .zeros (values . shape ))
185186 for i in csdl .frange (grid_n - 1 ):
186187 for j in csdl .frange (grid_n - 1 ):
187188 area_1 = csdl .norm (csdl .cross (grid_values [i + 1 ,j ]- grid_values [i ,j ], grid_values [i ,j + 1 ]- grid_values [i ,j ]) + 1e-8 )/ 2
@@ -265,7 +266,7 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
265266 max_newton_iterations :int = 100 , newton_tolerance :float = 1e-12 , projection_tolerance :float = None ,
266267 plot :bool = False , force_reproject :bool = False ,
267268 grid_search_evaluation_cutoff :int = None , grid_search_subtraction_cutoff :int = None ,
268- do_pickles = True ) -> csdl .Variable :
269+ do_pickles = True , grid_search_density_cutoff = 50 ) -> csdl .Variable :
269270 '''
270271 Projects a set of points onto the function. The points to project must be provided. If a direction is provided, the projection will find
271272 the points on the function that are closest to the axis defined by the direction. If no direction is provided, the projection will find the
@@ -290,7 +291,8 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
290291 projection_tolerance : float = None
291292 The tolerance for the projection. If None, the projection will not be refined. If not None, the projection will be refined
292293 using a finer grid search density parameter for the points that are not within the tolerance distance.
293- NOTE: This is only for use when the points are within the geometry that they are being projected onto.
294+ NOTE: This is only for use when the points are within the geometry that they are being projected onto, or, if a direction is provided,
295+ the axis defined by the direction intersects the geometry.
294296 plot : bool = False
295297 Whether or not to plot the projection.
296298 force_reproject : bool = False
@@ -303,6 +305,9 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
303305 will be subtracted in sections. If None, no bunching will be done.
304306 do_pickles : bool = True
305307 If True, the projection will be saved to a file. The file will be saved in the stored_files/projections directory.
308+ grid_search_density_cutoff : int = 50
309+ The cutoff for the grid search density during refinement. If the grid search density is greater than this, the refinement will be
310+ terminated and a warning will be printed.
306311 '''
307312 if isinstance (points , csdl .Variable ):
308313 points = points .value
@@ -321,7 +326,7 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
321326 grid_search_density_parameter , max_newton_iterations ,
322327 newton_tolerance , projection_tolerance ,
323328 grid_search_evaluation_cutoff , grid_search_subtraction_cutoff ,
324- do_pickles = do_pickles )
329+ do_pickles = do_pickles , grid_search_density_cutoff = grid_search_density_cutoff )
325330
326331 if plot :
327332 projection_results = self .evaluate (parametric_coordinates ).value
@@ -363,7 +368,7 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
363368 grid_search_values = np .zeros ((num_grid_points , self .coefficients .shape [- 1 ]))
364369 start_index = 0
365370 for i in range (num_sections ):
366- print (i , '/' , num_sections )
371+ # print(i, '/', num_sections)
367372 end_index = start_index + section_size
368373 grid_search_values [start_index :end_index ] = self .evaluate (parametric_coordinates = parametric_grid_search [start_index :end_index ],
369374 coefficients = self .coefficients .value , non_csdl = True )
@@ -386,7 +391,7 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
386391 section_size = int (np .ceil (points .shape [0 ]/ num_sections ))
387392 closest_point_indices = np .zeros ((points .shape [0 ],), dtype = int )
388393 for i in range (num_sections ):
389- print (i , '/' , num_sections )
394+ # print(i, '/', num_sections)
390395 start_index = i * section_size
391396 end_index = min ((i + 1 )* section_size , points .shape [0 ])
392397 points_expanded = np .repeat (points [start_index :end_index ,np .newaxis ,:], grid_search_values .shape [0 ], axis = 1 )
@@ -603,7 +608,7 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
603608 current_guess = self .refine_projection (points , current_guess , direction ,
604609 grid_search_density_parameter , max_newton_iterations ,
605610 newton_tolerance , projection_tolerance = projection_tolerance ,
606- do_pickles = do_pickles )
611+ do_pickles = False )
607612
608613 if plot :
609614 projection_results = self .evaluate (current_guess ).value
@@ -627,12 +632,11 @@ def project(self, points:np.ndarray, direction:np.ndarray=None, grid_search_dens
627632 pickle .dump (current_guess , handle , protocol = pickle .HIGHEST_PROTOCOL )
628633
629634 return current_guess
630-
631635
632636 def refine_projection (self , points :np .ndarray , parametric_coordinates :np .ndarray , direction :np .ndarray , initial_grid_search_density_parameter :int = 1 ,
633637 max_newton_iterations :int = 100 , newton_tolerance :float = 1e-6 , projection_tolerance :float = 1e-6 ,
634638 grid_search_evaluation_cutoff :int = None , grid_search_subtraction_cutoff :int = None ,
635- do_pickles = True ) -> np .ndarray :
639+ do_pickles = True , grid_search_density_cutoff = 50 ) -> np .ndarray :
636640 '''
637641 For projections where the points are in the geometry, this method finds the points that are not within the tolerance distance and reprojects
638642 those points using a finer grid search density parameter.
@@ -641,27 +645,38 @@ def refine_projection(self, points:np.ndarray, parametric_coordinates:np.ndarray
641645 points = points .value
642646 points_flattened = points .reshape ((- 1 ,3 ))
643647 previous_projection_results = self .evaluate (parametric_coordinates = parametric_coordinates , non_csdl = True )
644- distances = np .linalg .norm (points_flattened - previous_projection_results , axis = - 1 )
645- points_to_reproject = np .where (distances > projection_tolerance )[0 ]
648+
649+
650+ squared_distances = get_projection_squared_distances (points_flattened , previous_projection_results , direction )
651+ points_to_reproject = np .where (squared_distances > projection_tolerance ** 2 )[0 ]
652+ distances = np .sqrt (squared_distances [points_to_reproject ])
653+
646654 if len (points_to_reproject ) == 0 :
647655 return parametric_coordinates
648656 else :
649657 counter = 0
650658 grid_search_density_parameter = initial_grid_search_density_parameter * 1.2
651659 while len (points_to_reproject ) > 0 :
652- print ('Total tolerance norm: ' , np .linalg .norm (distances ))
653- print (f'Refining projection on { len (points_to_reproject )} points with grid search density parameter:' , grid_search_density_parameter )
660+ # print('Total tolerance norm: ', np.linalg.norm(distances))
661+ # print(f'Refining projection on {len(points_to_reproject)} points with grid search density parameter:', grid_search_density_parameter)
654662 new_parametric_coordinates = self .project (points_flattened [points_to_reproject ], direction , grid_search_density_parameter = grid_search_density_parameter ,
655663 max_newton_iterations = max_newton_iterations , newton_tolerance = newton_tolerance , force_reproject = False ,
656664 grid_search_evaluation_cutoff = grid_search_evaluation_cutoff ,
657665 grid_search_subtraction_cutoff = grid_search_subtraction_cutoff )
658666 parametric_coordinates [points_to_reproject ] = new_parametric_coordinates
659667 new_projection_results = self .evaluate (parametric_coordinates = new_parametric_coordinates , non_csdl = True )
660- distances = np .linalg .norm (points_flattened [points_to_reproject ] - new_projection_results , axis = 1 )
661- points_to_reproject = points_to_reproject [np .where (distances > projection_tolerance )[0 ]]
668+
669+ # distances = np.linalg.norm(points_flattened[points_to_reproject] - new_projection_results, axis=1)
670+ # points_to_reproject = points_to_reproject[np.where(distances > projection_tolerance)[0]]
671+
672+ squared_distances = get_projection_squared_distances (points_flattened [points_to_reproject ], new_projection_results , direction )
673+ new_points_to_reproject = np .where (squared_distances > projection_tolerance ** 2 )[0 ]
674+ distances = np .sqrt (squared_distances [new_points_to_reproject ])
675+ points_to_reproject = points_to_reproject [new_points_to_reproject ]
676+
662677 grid_search_density_parameter *= 1.5
663678 counter += 1
664- if counter > 10 :
679+ if grid_search_density_parameter > grid_search_density_cutoff :
665680 print ('--' * 50 )
666681 print ("WARNING: Projection refinement stopped because it took more than 10 refinement steps!" )
667682 print ("This is likely because not all of the points are within the function being projected onto." )
0 commit comments