CArl
Code Arlequin / C++ implementation
intersection_search.cpp
Go to the documentation of this file.
1 /*
2  * intersection_search.cpp
3  *
4  * Created on: Apr 14, 2016
5  * Author: Thiago Milanetto Schlittler
6  */
7 
8 #include "intersection_search.h"
9 
10 namespace carl
11 {
12  libMesh::Mesh & Intersection_Search::mesh_A()
13  {
14  return m_Mesh_A;
15  }
16 
17  libMesh::Mesh & Intersection_Search::mesh_B()
18  {
19  return m_Mesh_B;
20  }
21 
23  {
24  return m_Mesh_Coupling;
25  }
26 
27  /*
28  * Build both patches associated to the query element
29  */
30  void Intersection_Search::BuildCoupledPatches(const libMesh::Elem * Query_elem, int patch_counter)
31  {
32  // Unbreakable Patches!
34 
35  // Trusty Patches!
37 
38  if(m_bPrintDebug)
39  {
40  std::string filename = "meshes/3D/tests/output/patch_mesh_A_" + std::to_string(patch_counter) + "_" + std::to_string(m_rank);
42  filename = "meshes/3D/tests/output/patch_mesh_B_" + std::to_string(patch_counter) + "_" + std::to_string(m_rank);
44  }
45  }
46 
47  /*
48  * Find all the intersections between the patches, using a brute force
49  * method (all elements from a patch are tested against all the elements
50  * from the other patch).
51  */
52  void Intersection_Search::FindPatchIntersections_Brute(const libMesh::Elem * Query_elem)
53  {
54  m_perf_log.push("Preamble","Brute force algorithm");
55 
56  // Code for the brute force intersection tests
58 
59  // Intersection_Tools
61 
62  // Boolean: do they intersect?
63  bool bDoIntersect = false;
64 
65  std::unordered_set<unsigned int> & Patch_Set_A = m_Patch_Constructor_A.elem_indexes();
66  std::unordered_set<unsigned int> & Patch_Set_B = m_Patch_Constructor_B.elem_indexes();
67 
68  std::unordered_set<unsigned int>::iterator it_patch_A;
69  std::unordered_set<unsigned int>::iterator it_patch_B;
70 
71  // Debug vars
72  int nbOfTests = 0;
73  int nbOfPositiveTests = 0;
74 
75  m_perf_log.pop("Preamble","Brute force algorithm");
76 
77  for( it_patch_A = Patch_Set_A.begin();
78  it_patch_A != Patch_Set_A.end();
79  ++it_patch_A)
80  {
81  const libMesh::Elem * elem_A = m_Mesh_A.elem(*it_patch_A);
82 
83  for( it_patch_B = Patch_Set_B.begin();
84  it_patch_B != Patch_Set_B.end();
85  ++it_patch_B)
86  {
87  m_perf_log.push("Find intersection","Brute force algorithm");
88  ++nbOfTests;
89  const libMesh::Elem * elem_B = m_Mesh_B.elem(*it_patch_B);
90 
91  bDoIntersect = m_Intersection_test.libMesh_exact_do_intersect(elem_A,elem_B);
92  m_perf_log.pop("Find intersection","Brute force algorithm");
93 
94  if(bDoIntersect)
95  {
97  {
98  m_Intersection_Pairs_multimap.insert(std::pair<unsigned int, unsigned int>(*it_patch_A,*it_patch_B));
99  }
100  ++nbOfPositiveTests;
101  }
102  }
103  }
104 
105  // Partitioning vars
106  unsigned int query_idx = Query_elem->id();
107  m_Nb_Of_Intersections_Elem_C[query_idx] = nbOfPositiveTests;
108 
109  if(m_bPrintDebug)
110  {
111  std::cout << " DEBUG: brute force search results" << std::endl;
112  std::cout << " -> Positives / tests : " << nbOfPositiveTests << " / " << nbOfTests
113  << " (" << 100.*nbOfPositiveTests/nbOfTests << "%)" << std::endl << std::endl;
114  }
115  }
116 
117  /*
118  * Find the first intersecting pair from a patch. Do so by :
119  *
120  * a) locating the elements from the guide patch that contain the
121  * vertices of an element from the probed patch.
122  * b) for each one of these guide elements, find the one that
123  * intersects the probed element inside the coupling.
124  * c) if this fails, use a brute force search method.
125  */
127  Patch_construction * Patch_probed,
128  std::pair<unsigned int,unsigned int> & First_intersection)
129  {
130  // Set up some references for a simpler code
131  libMesh::ReplicatedMesh& Mesh_patch_guide = Patch_guide->patch_mesh();
132  libMesh::ReplicatedMesh& Mesh_patch_probed = Patch_probed->patch_mesh();
133 
134  // Set up locator for the first intersecting pair
135  std::unique_ptr<libMesh::PointLocatorBase> Patch_guide_Locator = Mesh_patch_guide.sub_point_locator();
136 
137  // Instruction needed to avoid the code from crashing if a query is
138  // outside the mesh
139  Patch_guide_Locator->enable_out_of_mesh_mode();
140 
141  // Find the first pair
142  libMesh::Elem * Patch_probed_first_elem = NULL;
143  unsigned int Patch_probed_first_elem_id = 0;
144 
145  // Set of intersecting terms:
146  std::set<unsigned int> Intersecting_guide_elems;
147  bool bFoundIntersection = false;
148  for(libMesh::ReplicatedMesh::element_iterator element_probed_it = Mesh_patch_probed.elements_begin();
149  element_probed_it != Mesh_patch_probed.elements_end();
150  ++element_probed_it)
151  {
152  Patch_probed_first_elem = * element_probed_it;
153  Patch_probed_first_elem_id = Patch_probed->convert_patch_to_parent_elem_id(Patch_probed_first_elem->id());
154  bFoundIntersection = m_Intersection_test.FindAllIntersection(Patch_probed_first_elem,Patch_guide_Locator,Intersecting_guide_elems);
155  if(bFoundIntersection)
156  {
157  break;
158  }
159  }
160 
161  // Search for one intersecting term inside the guide patch
162  libMesh::Elem * Patch_guide_first_elem = NULL;
163  unsigned int Patch_guide_first_elem_id;
164  bool bFoundFirstInter = false;
165 
166  for(std::set<unsigned int>::iterator it_inter = Intersecting_guide_elems.begin();
167  it_inter != Intersecting_guide_elems.end();
168  ++it_inter)
169  {
170  Patch_guide_first_elem = Mesh_patch_guide.elem(*it_inter);
171  Patch_guide_first_elem_id = Patch_guide->convert_patch_to_parent_elem_id(*it_inter);
172 
173  // Must test if the intersection is inside the coupling region
174  bFoundFirstInter = m_Intersection_test_neighbors.libMesh_exact_do_intersect_inside_coupling(Patch_probed_first_elem,Patch_guide_first_elem);
175 
176  if(bFoundFirstInter)
177  {
178  First_intersection.first = Patch_guide_first_elem_id;
179  First_intersection.second = Patch_probed_first_elem_id;
180  break;
181  }
182  }
183 
184  if(!bFoundFirstInter)
185  {
186  // Couldn't find the first intersection using a point search ...
187  // Will have to do the things the hard way ...
188  BruteForce_FindFirstPair(Patch_guide,Patch_probed,First_intersection);
189  }
190  };
191 
192  /*
193  * Find the first intersecting pair from a patch, doing a full scan of
194  * the patches (essentially, a brute force algorithm set to stop after the
195  * first positive test).
196  */
198  Patch_construction * Patch_probed,
199  std::pair<unsigned int,unsigned int> & First_intersection)
200  {
201  bool bFoundFirstInter = false;
202  std::unordered_set<unsigned int> & Patch_Set_Guide = Patch_guide->elem_indexes();
203  std::unordered_set<unsigned int> & Patch_Set_Probed = Patch_probed->elem_indexes();
204 
205  libMesh::ReplicatedMesh& Mesh_patch_guide = Patch_guide->patch_mesh();
206  libMesh::ReplicatedMesh& Mesh_patch_probed = Patch_probed->patch_mesh();
207 
208  std::unordered_set<unsigned int>::iterator it_patch_Guide;
209  std::unordered_set<unsigned int>::iterator it_patch_Probed;
210 
211  for( it_patch_Guide = Patch_Set_Guide.begin();
212  it_patch_Guide != Patch_Set_Guide.end();
213  ++it_patch_Guide)
214  {
215  const libMesh::Elem * elem_Guide = Mesh_patch_guide.elem(*it_patch_Guide);
216 
217  for( it_patch_Probed = Patch_Set_Probed.begin();
218  it_patch_Probed != Patch_Set_Probed.end();
219  ++it_patch_Probed)
220  {
221  const libMesh::Elem * elem_Probed = Mesh_patch_probed.elem(*it_patch_Probed);
222 
223  bFoundFirstInter = m_Intersection_test.libMesh_exact_do_intersect_inside_coupling(elem_Guide,elem_Probed);
224 
225  if(bFoundFirstInter)
226  {
227  First_intersection.first = *it_patch_Guide;
228  First_intersection.second = *it_patch_Probed;
229  return;
230  }
231  }
232  }
233 
234  homemade_assert_msg(bFoundFirstInter,"Could't find a first intersecting pair. Are you sure that the patches do intersect?\n");
235  }
236 
237  /*
238  * Find all the intersections between the patches, using an advancing
239  * front method.
240  */
241  void Intersection_Search::FindPatchIntersections_Front(const libMesh::Elem * Query_elem)
242  {
243  m_perf_log.push("Preamble","Advancing front algorithm");
244  // Code for the front intersection tests
246 
247  // Intersection_Tools
250 
251  // --- Set up variables needed by Gander's algorithm
252 
253  // First, determinate which patch will be the guide, and which will be
254  // the probed
255  Patch_construction * Patch_guide = &m_Patch_Constructor_A;
256  Patch_construction * Patch_probed = &m_Patch_Constructor_B;
257 
258  // Exchange them if the guide is smaller
259  bool bGuidedByB = Patch_guide->size() > Patch_probed->size();
260  if(bGuidedByB)
261  {
262  if(m_bPrintDebug)
263  {
264  std::cout << " DEBUG: Probe: A | Guide: B" << std::endl;
265  }
266  Patch_guide = &m_Patch_Constructor_B;
267  Patch_probed = &m_Patch_Constructor_A;
268  }
269  else
270  {
271  if(m_bPrintDebug)
272  {
273  std::cout << " DEBUG: Probe: B | Guide: A" << std::endl;
274  }
275  }
276 
277  // Ids of the working elements
278  unsigned int Guide_working_elem_id;
279  unsigned int Probed_working_elem_id;
280 
281  // Find the first pair, (guide, probed)
282  std::pair<unsigned int,unsigned int> First_intersection;
283  BruteForce_FindFirstPair(Patch_guide,Patch_probed,First_intersection);
284 
285  // Index and iterators guide neighbor elements to be tested
286  unsigned int guide_neighbor_index = 0;
287  std::unordered_set<unsigned int>::iterator it_neigh, it_neigh_end;
288 
289  // Boolean saying if two elements intersect (exactly)
290  bool bDoIntersect = false;
291 
292  // Boolean saying if a neighbor element intersects (exactly)
293  bool bDoNeighborIntersect = false;
294 
295  // Boolean used to short-circuit the neighbor search test if all
296  // the concerned elements already have neighbours.
297  bool bDoTestGuideNeighbours = true;
298 
299  // --- Preamble - initializations
300  // Insert the first elements in the queues
301  Patch_guide->FrontSearch_initialize();
302  Patch_probed->FrontSearch_initialize();
303 
304  Patch_guide->intersection_queue_push_back(First_intersection.first);
305  Patch_probed->intersection_queue_push_back(First_intersection.second);
306  Patch_guide->set_elem_as_inside_queue(First_intersection.first);
307 
308  // Debug vars
309  int nbOfGuideElemsTested = 0;
310  int nbOfTests = 0;
311  int nbOfPositiveTests = 0;
312 
313  bool bCreateNewNefForGuideNeigh = true;
314 
315  m_perf_log.pop("Preamble","Advancing front algorithm");
316 
317  while(!Patch_guide->intersection_queue_empty())
318  {
319  m_perf_log.push("Set up new guide element","Advancing front algorithm");
320 
321  // Pop out the first element from the guide intersection queue
322  Guide_working_elem_id = Patch_guide->intersection_queue_extract_front_elem();
323  Patch_guide->set_elem_as_treated(Guide_working_elem_id);
324 
325  // Get its pointer
326  const libMesh::Elem * elem_guide = Patch_guide->current_elem_pointer();
327 
328  ++nbOfGuideElemsTested;
329 
330  // Set up the neighbor test short-circuits
331  bDoTestGuideNeighbours = Patch_guide->set_neighbors_to_search_next_pairs();
332 
333  // Clear and initialize the probed patch lists
334  Patch_probed->FrontSearch_reset();
335 
336  // Pop out the first element from the probed intersection queue, and
337  // insert it inside the test queue
338  Patch_probed->FrontSearch_prepare_for_probed_test();
339 
340  m_perf_log.pop("Set up new guide element","Advancing front algorithm");
341 
342  while(!Patch_probed->test_queue_empty())
343  {
344  m_perf_log.push("Find intersection","Advancing front algorithm");
345  // Pop out the first elem to be tested
346  Probed_working_elem_id = Patch_probed->test_queue_extract_front_elem();
347  Patch_probed->set_elem_as_treated(Probed_working_elem_id);
348 
349  const libMesh::Elem * elem_probed = Patch_probed->current_elem_pointer();
350 
351  // Test the intersection
352  bDoIntersect = m_Intersection_test.libMesh_exact_do_intersect(elem_guide,elem_probed);
353  ++nbOfTests;
354  m_perf_log.pop("Find intersection","Advancing front algorithm");
355 
356  // If they do intersect, we have to ...
357  if(bDoIntersect)
358  {
359  // 1) add elements to intersection multimap, watching out
360  // for the element order
361  if(m_bSaveInterData)
362  {
363  if(bGuidedByB)
364  {
365  m_Intersection_Pairs_multimap.insert(std::pair<unsigned int, unsigned int>(Probed_working_elem_id,Guide_working_elem_id));
366  }
367  else
368  {
369  m_Intersection_Pairs_multimap.insert(std::pair<unsigned int, unsigned int>(Guide_working_elem_id,Probed_working_elem_id));
370  }
371  }
372  ++nbOfPositiveTests;
373 
374  m_perf_log.push("Update test queue","Advancing front algorithm");
375  // 2) add elem_probed's neighbors, if not treated yet
376  Patch_probed->add_neighbors_to_test_list();
377  m_perf_log.pop("Update test queue","Advancing front algorithm");
378 
379  m_perf_log.push("Update intersection queue","Advancing front algorithm");
380  // 3) determinate if any of the guide neighbors are good
381  // candidates with the probed element.
382  if(bDoTestGuideNeighbours)
383  {
384  it_neigh = Patch_guide->neighbors_to_search_next_pair().begin();
385  it_neigh_end = Patch_guide->neighbors_to_search_next_pair().end();
386 
387  bCreateNewNefForGuideNeigh = true;
388 
389  for( ; it_neigh != it_neigh_end; ++it_neigh )
390  {
391  // This element doesn't have an intersecting pair
392  // yet. Test it, but only save it if it is inside
393  // the coupling region
394  guide_neighbor_index = *it_neigh;
395  const libMesh::Elem * elem_neigh = Patch_guide->elem(guide_neighbor_index);
396  bDoNeighborIntersect = m_Intersection_test_neighbors.libMesh_exact_do_intersect_inside_coupling(elem_probed,elem_neigh,bCreateNewNefForGuideNeigh);
397 
398  if(bDoNeighborIntersect)
399  {
400  bCreateNewNefForGuideNeigh = false;
401  }
402 
403  if(bDoNeighborIntersect)
404  {
405  // Now it has an intersecting pair!
406  Patch_guide->intersection_queue_push_back(guide_neighbor_index);
407  Patch_probed->intersection_queue_push_back(Probed_working_elem_id);
408 
409  // Set the guide elements as "already inside the queue"
410  Patch_guide->set_elem_as_inside_queue(guide_neighbor_index);
411  }
412  }
413 
414  bDoTestGuideNeighbours = Patch_guide->set_neighbors_to_search_next_pairs();
415  }
416  m_perf_log.pop("Update intersection queue","Advancing front algorithm");
417  }
418  }
419  }
420 
421  // Partitioning vars
422  unsigned int query_idx = Query_elem->id();
423  m_Nb_Of_Intersections_Elem_C[query_idx] = nbOfPositiveTests;
424 
425  if(m_bPrintDebug)
426  {
427  std::cout << " DEBUG: advancing front search results" << std::endl;
428  std::cout << " -> Guide elements tested / all : " << nbOfGuideElemsTested << " / " << Patch_guide->size() << std::endl;
429  std::cout << " -> Positives / tests : " << nbOfPositiveTests << " / " << nbOfTests
430  << " (" << 100.*nbOfPositiveTests/nbOfTests << "%)" << std::endl << std::endl;
431  }
432  }
433 
434  /*
435  * For each coupling element, build the patches and find their
436  * intersections, using the brute force method.
437  */
439  {
440  // Prepare iterators
441  libMesh::Mesh::const_element_iterator it_coupl = m_Mesh_Coupling.local_elements_begin();
442  libMesh::Mesh::const_element_iterator it_coupl_end = m_Mesh_Coupling.local_elements_end();
443 
444  int patch_counter = 0;
445  double real_volume = 0;
446 
448 
449  for( ; it_coupl != it_coupl_end; ++it_coupl)
450  {
451  const libMesh::Elem * Query_elem = * it_coupl;
452 
453  m_perf_log.push("Build patches","Brute force");
454  BuildCoupledPatches(Query_elem,patch_counter);
455  m_perf_log.pop("Build patches","Brute force");
456 
457  ++patch_counter;
458 
459  if(m_bPrintDebug)
460  {
461  real_volume += Query_elem->volume();
462  }
463 
464  m_perf_log.push("Find intersections","Brute force");
465  FindPatchIntersections_Brute(Query_elem);
466  m_perf_log.pop("Find intersections","Brute force");
468  {
469  m_perf_log.push("Build intersections","Brute force");
470  UpdateCouplingIntersection(Query_elem);
471  m_perf_log.pop("Build intersections","Brute force");
472  }
473  };
474 
476  {
477  m_perf_log.push("Prepare mesh","Brute force");
479  m_perf_log.pop("Prepare mesh","Brute force");
480  }
481 
483  {
484  std::vector<double> timing_find_intersections(m_nodes,0);
485  std::vector<double> timing_build_intersections(m_nodes,0);
486 
487  libMesh::PerfData performance_data = m_perf_log.get_perf_data("Find intersections","Brute force");
488  timing_find_intersections[m_rank] = performance_data.tot_time_incl_sub;
489  performance_data = m_perf_log.get_perf_data("Build intersections","Brute force");
490  timing_build_intersections[m_rank] = performance_data.tot_time_incl_sub;
491 
492  m_comm.sum(timing_find_intersections);
493  m_comm.sum(timing_build_intersections);
494 
495  if(m_rank == 0)
496  {
497  print_stats_to_file(timing_find_intersections,m_timing_data_file_base + "_search_brute.dat");
499  {
500  print_stats_to_file(timing_build_intersections,m_timing_data_file_base + "_build_brute.dat");
501  }
502  }
503  }
504 
506  {
507  m_perf_log.push("Calculate volume","Brute force");
508  double total_volume = m_Mesh_Intersection.get_total_volume();
509  m_perf_log.push("Calculate volume","Brute force");
510 
511  std::cout << " DEBUG volume on proc. " << m_rank << "(BRUTE)" << std::endl;
512  std::cout << " -> Mesh elems, nodes : " << m_Mesh_Intersection.mesh().n_elem() << " , " << m_Mesh_Intersection.mesh().n_nodes() << std::endl;
513  std::cout << " -> Intersection volume / real : " << total_volume << " / " << real_volume << std::endl << std::endl;
514  }
515  }
516 
518  {
519  // Prepare iterators
520  libMesh::Mesh::const_element_iterator it_coupl = m_Mesh_Coupling.local_elements_begin();
521  libMesh::Mesh::const_element_iterator it_coupl_end = m_Mesh_Coupling.local_elements_end();
522 
523  int patch_counter = 0;
524 
525  for( ; it_coupl != it_coupl_end; ++it_coupl)
526  {
527  const libMesh::Elem * Query_elem = * it_coupl;
528 
529  m_perf_log.push("Build patches","Brute force (preamble run)");
530  BuildCoupledPatches(Query_elem,patch_counter);
531  m_perf_log.pop("Build patches","Brute force (preamble run)");
532 
533  ++patch_counter;
534 
535  m_perf_log.push("Find intersections","Brute force (preamble run)");
536  FindPatchIntersections_Brute(Query_elem);
537  m_perf_log.pop("Find intersections","Brute force (preamble run)");
538  };
539  }
540 
541  /*
542  * For each coupling element, build the patches and find their
543  * intersections, using the advancing front method.
544  */
546  {
547  // Prepare iterators
548  libMesh::Mesh::const_element_iterator it_coupl = m_Mesh_Coupling.local_elements_begin();
549  libMesh::Mesh::const_element_iterator it_coupl_end = m_Mesh_Coupling.local_elements_end();
550 
551  int patch_counter = 0;
552  double real_volume = 0;
553 
555 
556  for( ; it_coupl != it_coupl_end; ++it_coupl)
557  {
558  const libMesh::Elem * Query_elem = * it_coupl;
559 
560  m_perf_log.push("Build patches","Advancing front");
561  BuildCoupledPatches(Query_elem,patch_counter);
562  m_perf_log.pop("Build patches","Advancing front");
563 
564  ++patch_counter;
565 
566  if(m_bPrintDebug)
567  {
568  real_volume += Query_elem->volume();
569  }
570  m_perf_log.push("Find intersections","Advancing front");
571  FindPatchIntersections_Front(Query_elem);
572  m_perf_log.pop("Find intersections","Advancing front");
574  {
575  m_perf_log.push("Build intersections","Advancing front");
576  UpdateCouplingIntersection(Query_elem);
577  m_perf_log.pop("Build intersections","Advancing front");
578  }
579  };
580 
582  {
583  m_perf_log.push("Prepare mesh","Advancing front");
585  m_perf_log.pop("Prepare mesh","Advancing front");
586  }
587 
589  {
590  std::vector<double> timing_find_intersections(m_nodes,0);
591  std::vector<double> timing_build_intersections(m_nodes,0);
592 
593  libMesh::PerfData performance_data = m_perf_log.get_perf_data("Find intersections","Advancing front");
594  timing_find_intersections[m_rank] = performance_data.tot_time_incl_sub;
595  performance_data = m_perf_log.get_perf_data("Build intersections","Advancing front");
596  timing_build_intersections[m_rank] = performance_data.tot_time_incl_sub;
597 
598  m_comm.sum(timing_find_intersections);
599  m_comm.sum(timing_build_intersections);
600 
601  if(m_rank == 0)
602  {
603  print_stats_to_file(timing_find_intersections,m_timing_data_file_base + "_search_advancing.dat");
605  {
606  print_stats_to_file(timing_build_intersections,m_timing_data_file_base + "_build_advancing.dat");
607  }
608  }
609  }
610 
612  {
613  m_perf_log.push("Calculate volume","Advancing front");
614  double total_volume = m_Mesh_Intersection.get_total_volume();
615  m_perf_log.push("Calculate volume","Advancing front");
616 
617  std::cout << " DEBUG volume on proc. " << m_rank << "(FRONT)" << std::endl;
618  std::cout << " -> Mesh elems, nodes : " << m_Mesh_Intersection.mesh().n_elem() << " , " << m_Mesh_Intersection.mesh().n_nodes() << std::endl;
619  std::cout << " -> Intersection volume / real : " << total_volume << " / " << real_volume << std::endl << std::endl;
620  }
621  }
622 
624  {
625  // Prepare iterators
626  libMesh::Mesh::const_element_iterator it_coupl = m_Mesh_Coupling.local_elements_begin();
627  libMesh::Mesh::const_element_iterator it_coupl_end = m_Mesh_Coupling.local_elements_end();
628 
629  int patch_counter = 0;
630 
631  for( ; it_coupl != it_coupl_end; ++it_coupl)
632  {
633  const libMesh::Elem * Query_elem = * it_coupl;
634 
635  m_perf_log.push("Build patches (preamble)","Advancing front (preamble run)");
636  BuildCoupledPatches(Query_elem,patch_counter);
637  m_perf_log.pop("Build patches","Advancing front (preamble run)");
638 
639  ++patch_counter;
640 
641  m_perf_log.push("Find intersections","Advancing front (preamble run)");
642  FindPatchIntersections_Front(Query_elem);
643  m_perf_log.pop("Find intersections","Advancing front (preamble run)");
644  };
645  }
646 
647  /*
648  * Preallocate run. It essentially does the intersection run, but
649  * without saving the data or building the intersections themselves.
650  *
651  */
653  {
654  m_bSaveInterData = false;
655  switch (search_type)
656  {
658  break;
659 
661  break;
662 
665  break;
666  }
667 
669 
671  }
672 
674  {
676  {
677  // Redo the partitioning
679 
680  for(unsigned int iii = 0; iii < m_Nb_Of_Intersections_Elem_C.size(); ++iii)
681  {
683  }
684 
686  {
687  libMesh::Partitioner * dummy_partitioner = m_Mesh_Coupling.partitioner().get();
688  dummy_partitioner->attach_weights(&m_coupling_weights);
689  m_Mesh_Coupling.partition(m_nodes);
690  }
691 
692  // Allocate the intersection maps ...
693  std::vector<unsigned int> nb_of_inters_per_rank(m_nodes,0);
694  unsigned int dummy_nb_of_inters = 0;
695  libMesh::Mesh::const_element_iterator it_local = m_Mesh_Coupling.local_elements_begin();
696  libMesh::Mesh::const_element_iterator it_local_end = m_Mesh_Coupling.local_elements_end();
697  for( ; it_local != it_local_end; ++ it_local)
698  {
699  const libMesh::Elem * dummy_elem = * it_local;
700  nb_of_inters_per_rank[m_rank] += m_coupling_weights[dummy_elem->id()];
701  }
702  m_comm.sum(nb_of_inters_per_rank);
703  m_Intersection_Pairs_multimap.reserve(2*dummy_nb_of_inters);
704 
705  // ... and the intersection grid
706  m_Mesh_Intersection.preallocate_grid(192*dummy_nb_of_inters);
707  m_bHavePreallocData = true;
708 
710  {
711  if(m_rank == 0)
712  {
713  std::string intersection_statistics_filename;
715  {
716  intersection_statistics_filename = m_timing_data_file_base + "_inters_per_partition__new_partitioning.dat";
717  }
718  else
719  {
720  intersection_statistics_filename = m_timing_data_file_base + "_inters_per_partition__original.dat";
721  }
722 
723  libMesh::StatisticsVector<int> intersection_statistics(m_nodes,0);
724  for(unsigned int iii = 0; iii < m_nodes; ++iii)
725  {
726  intersection_statistics[iii] = nb_of_inters_per_rank[iii];
727  }
728 
729  std::ofstream inter_statistics_output(intersection_statistics_filename,std::ofstream::app);
730 
731  inter_statistics_output << intersection_statistics.minimum() << " "
732  << intersection_statistics.maximum() << " "
733  << intersection_statistics.mean() << " "
734  << intersection_statistics.median() << " "
735  << intersection_statistics.stddev() << std::endl;
736 
737  inter_statistics_output.close();
738  }
739 
740  }
741  }
742  }
743 
744  /*
745  * Interface for the user to build the intersections. By default, it
746  * uses the brute force algorithm, but the argument can be changed to
747  * carl::FRONT to use the advancing front method, of to carl::BOTH to use
748  * both methods (useful for benchmarking).
749  */
751  {
753  {
754  // Must do an preeeety expensive preallocation. Ouch ...
755  m_Intersection_Pairs_multimap.reserve(m_Mesh_A.n_elem()*m_Mesh_B.n_elem());
756  }
757 
758  m_bSaveInterData = true;
759  m_bIntersectionsBuilt = false;
760 
761  switch (search_type)
762  {
764  break;
765 
767  break;
768 
771  break;
772  }
773 
775  {
777  m_bIntersectionsBuilt = true;
778  }
779  }
780 
781  /*
782  * Calculate the volume over all the processors
783  */
785  {
786  // Use a barrier to guarantee that all procs are in the same position
787  m_comm.barrier();
788 
789  // Calculate the volume of the intersection on each processor
790  double global_volume = m_Mesh_Intersection.get_total_volume();
791 
792  // Add it!
793  m_comm.sum(global_volume);
794 
795  // Calculate the volume of the coupling region on each processor
796  libMesh::Mesh::const_element_iterator it_coupl = m_Mesh_Coupling.local_elements_begin();
797  libMesh::Mesh::const_element_iterator it_coupl_end = m_Mesh_Coupling.local_elements_end();
798  double real_volume = 0;
799 
800  for( ; it_coupl != it_coupl_end; ++it_coupl)
801  {
802  const libMesh::Elem * Query_elem = * it_coupl;
803  real_volume += Query_elem->volume();
804  }
805 
806  // Add it!
807  m_comm.sum(real_volume);
808 
809  std::cout << " TOTAL volume, proc. " << m_rank << std::endl;
810  std::cout << " -> Intersection volume / real : " << global_volume << " / " << real_volume << std::endl << std::endl;
811 
812  }
813  /*
814  * Legacy function, used to calculate the volume of the intersections
815  * without updating the intersection mesh.
816  */
817  void Intersection_Search::CalculateIntersectionVolume(const libMesh::Elem * Query_elem)
818  {
819  std::unordered_set<unsigned int> & Patch_Set_A = m_Patch_Constructor_A.elem_indexes();
820 
821  std::unordered_set<unsigned int>::iterator it_patch_A;
822 
823  bool bDoIntersect = true;
824  bool bCreateNewNefForA = true;
825 
827 
828  std::set<libMesh::Point> points_out;
829  double total_volume = 0;
830 
831  // Debug vars
832  int nbOfTests = 0;
833  int nbOfPositiveTests = 0;
834  for( it_patch_A = Patch_Set_A.begin();
835  it_patch_A != Patch_Set_A.end();
836  ++it_patch_A)
837  {
838  auto iterator_pair = m_Intersection_Pairs_multimap.equal_range(*it_patch_A);
839 
840  const libMesh::Elem * elem_A = m_Mesh_A.elem(*it_patch_A);
841  bCreateNewNefForA = true;
842 
843  for(auto it_patch_B = iterator_pair.first ;
844  it_patch_B != iterator_pair.second ;
845  ++it_patch_B )
846  {
847  const libMesh::Elem * elem_B = m_Mesh_B.elem(it_patch_B->second);
848  points_out.clear();
849 
850  m_perf_log.push("Build intersection polyhedron","Build intersections");
851  bDoIntersect = m_Intersection_test.libMesh_exact_intersection_inside_coupling(elem_A,elem_B,points_out,bCreateNewNefForA,true,false);
852  m_perf_log.pop("Build intersection polyhedron","Build intersections");
853  ++nbOfTests;
854 
855  if(bDoIntersect)
856  {
857  bCreateNewNefForA = false;
858  m_perf_log.push("Calculate volume","Build intersections");
859  total_volume += m_Mesh_Intersection.get_intersection_volume(points_out);
860  m_perf_log.pop("Calculate volume","Build intersections");
861  ++nbOfPositiveTests;
862  }
863  }
864  }
865 
866  if(m_bPrintDebug)
867  {
868  std::cout << " DEBUG: calculate the volume" << std::endl;
869  std::cout << " -> Intersection volume / real : " << total_volume << " / " << Query_elem->volume() << std::endl << std::endl;
870  std::cout << " -> Positives / tests : " << nbOfPositiveTests << " / " << nbOfTests
871  << " (" << 100.*nbOfPositiveTests/nbOfTests << "%)" << std::endl << std::endl;
872  }
873  }
874 
875  /*
876  * Take the intersection tables info and update the intersection mesh.
877  */
878  void Intersection_Search::UpdateCouplingIntersection(const libMesh::Elem * Query_elem)
879  {
880  // Preamble
881  std::unordered_set<unsigned int> & Patch_Set_A = m_Patch_Constructor_A.elem_indexes();
882  std::unordered_set<unsigned int>::iterator it_patch_A;
883 
884  bool bDoIntersect = true;
885  bool bCreateNewNefForA = true;
887 
888  std::set<libMesh::Point> points_out;
889 
890  // Debug vars
891  int nbOfTests = 0;
892  int nbOfPositiveTests = 0;
893 
894  // For each element inside patch A ...
895  for( it_patch_A = Patch_Set_A.begin();
896  it_patch_A != Patch_Set_A.end();
897  ++it_patch_A)
898  {
899  auto iterator_pair = m_Intersection_Pairs_multimap.equal_range(*it_patch_A);
900 
901  const libMesh::Elem * elem_A = m_Mesh_A.elem(*it_patch_A);
902  bCreateNewNefForA = true;
903 
904  // ... get the intersections with patch B ...
905  for(auto it_patch_B = iterator_pair.first ;
906  it_patch_B != iterator_pair.second ;
907  ++it_patch_B )
908  {
909  const libMesh::Elem * elem_B = m_Mesh_B.elem(it_patch_B->second);
910  points_out.clear();
911 
912  // ... test if they intersect inside the coupling region ...
913  m_perf_log.push("Build intersection polyhedron","Build intersections");
914  bDoIntersect = m_Intersection_test.libMesh_exact_intersection_inside_coupling(elem_A,elem_B,points_out,bCreateNewNefForA,true,false);
915  m_perf_log.pop("Build intersection polyhedron","Build intersections");
916  ++nbOfTests;
917 
918  if(bDoIntersect)
919  {
920  // ... and, if they do, update the intersection mesh!
921  bCreateNewNefForA = false;
922  m_perf_log.push("Update intersection","Build intersections");
923  m_Mesh_Intersection.increase_intersection_mesh(points_out,*it_patch_A,it_patch_B->second,Query_elem->id());
924  m_perf_log.pop("Update intersection","Build intersections");
925  ++nbOfPositiveTests;
926  }
927  }
928  }
929 
930  if(m_bPrintDebug)
931  {
932  std::cout << " DEBUG: update intersection mesh" << std::endl;
933  std::cout << " -> Positives / tests : " << nbOfPositiveTests << " / " << nbOfTests
934  << " (" << 100.*nbOfPositiveTests/nbOfTests << "%)" << std::endl << std::endl;
935  }
936  }
937 
938  void Intersection_Search::SetScalingFiles(const std::string& timing_data_file_base)
939  {
940  m_bPrintTimingData = true;
942  m_timing_data_file_base = timing_data_file_base;
943  }
944 }
945 
946 
bool m_bDidPreliminarySearch
Boolean flag determining if we did a preliminary intersection search, used for the coupling mesh repa...
std::string m_timing_data_file_base
Output filenames base for the timing data.
bool m_bIntersectionsBuilt
Boolean flag indicating if the intersections were built. (A bit useless right now ...
double get_total_volume()
Calculate the intersection mesh's total volume.
SearchMethod
Definition: common_enums.h:54
bool m_bSkipIntersectionConstruction
Boolean indicating if we should skip the intersection construction. Default: false.
void FindAndBuildIntersections_Front()
Find and build all the intersections, using the advancing front method.
void FindIntersections_Front()
Find all the intersections, using the advancing front method.
void FindIntersections_Brute()
Find all the intersections, using the brute force method.
void set_elem_as_inside_queue(unsigned int elem_id)
[ADV. FRONT] Mark element as already inside the deque of elements to be treated.
const libMesh::ReplicatedMesh & mesh()
Returns the address of the intersection mesh.
Class used to build a mesh patch from a parent mesh and an coupling mesh element. ...
std::string m_Output_filename_base
Output filenames base.
void export_patch_mesh(std::string &filename_base)
Export the patch mesh to a file.
bool m_bPrintIntersectionsPerPartData
Print intersections per partition. Default: false.
void FindPatchIntersections_Brute(const libMesh::Elem *Query_elem)
Find all the intersections between the patches associated to the Query_elem, using a brute force meth...
libMesh::Mesh & m_Mesh_Coupling
Mesh representing the coupling region.
const libMesh::Parallel::Communicator & m_comm
Global communicator.
const libMesh::Elem * current_elem_pointer()
unsigned int intersection_queue_extract_front_elem()
[ADV. FRONT] Pop and returns the first element to be treated.
void increase_intersection_mesh(const std::set< libMesh::Point > &input_points, unsigned int elem_idx_A, unsigned int elem_idx_B, unsigned int elem_idx_C)
Increase the intersection mesh with the current polyhedron mesh and update its data structures...
void export_intersection_data(const std::string &filename_base, const std::string &mesh_format=std::string(".e"))
Export both the intersection mesh its data structures.
const unsigned int m_nodes
Number of MPI processors.
void BuildCoupledPatches(const libMesh::Elem *Query_elem, int patch_counter=0)
Build both patches associated a given query element from the coupling region mesh.
void libmesh_set_coupling_nef_polyhedron(const libMesh::Elem *elem_C)
Set the Nef polyhedron for the coupling mesh element.
unsigned int FrontSearch_prepare_for_probed_test()
[ADV. FRONT] Reset the advancing front search data structures, with the exception of list of elements...
void BruteForce_FindFirstPair(Patch_construction *Patch_guide, Patch_construction *Patch_probed, std::pair< unsigned int, unsigned int > &First_intersection)
Find the first intersecting pair from a patch, doing a full scan of the patches.
bool intersection_queue_empty()
[ADV. FRONT] Check if deque of elements to be treated is empty.
void PreparePreallocationAndLoad(SearchMethod search_type=BRUTE)
Do a preliminary search, to optimize the intersection search and construction.
void PreallocateAndPartitionCoupling()
Preallocate Intersection_Search::m_Intersection_Pairs_multimap and repartition the coupling mesh...
bool m_bSkipIntersectionPartitioning
Boolean indicating if we should skip the intersection repartitioning. Default: false.
Patch_construction m_Patch_Constructor_B
Patch_construction object for mesh B.
void print_stats_to_file(std::vector< double > &vec_data, const std::string filename)
bool test_queue_empty()
[ADV. FRONT] Check if deque of elements to be tested is empty.
bool FindAllIntersection(const libMesh::Elem *Query_elem, std::unique_ptr< libMesh::PointLocatorBase > &point_locator, std::set< unsigned int > &Intersecting_elems)
Find all elements from the mesh intersecting Query_elem, using the mesh's libMesh::PointLocatorBase.
void UpdateCouplingIntersection(const libMesh::Elem *Query_elem)
Build the intersections associated to the Query_elem and update the intersection mesh.
std::unordered_set< unsigned int > & elem_indexes()
Returns the set of elements inside the patch.
libMesh::ReplicatedMesh & patch_mesh()
Returns the patch mesh.
libMesh::PerfLog m_perf_log
libMesh::PerfLog object.
const libMesh::Elem * elem(unsigned int idx)
Patch_construction m_Patch_Constructor_A
Patch_construction object for mesh A.
std::unordered_multimap< unsigned int, unsigned int > m_Intersection_Pairs_multimap
Multimap containing the intersection pairs.
std::vector< unsigned int > m_Nb_Of_Intersections_Elem_C
Vector containing the number of intersections found inside each of the coupling mesh elements...
bool m_bHavePreallocData
Boolean flag determining if we have the data for a proper preallocation of m_Intersection_Pairs_multi...
void FindFirstPair(Patch_construction *Patch_guide, Patch_construction *Patch_probed, std::pair< unsigned int, unsigned int > &First_intersection)
Find the first intersecting pair from a patch.
Mesh_Intersection m_Mesh_Intersection
Object containing the intersection mesh.
unsigned int convert_patch_to_parent_elem_id(unsigned int input)
Convert an element index from the patch mesh to the parent mesh.
libMesh::ErrorVector m_coupling_weights
libMesh::ErrorVector used to repartition the coupling mesh.
void BuildPatch(const libMesh::Elem *Query_elem)
Build the patch mesh covering a given "Query_elem".
Intersection_Tools m_Intersection_test
Intersection operations for the main intersection tests.
bool m_bPrintDebug
Print debug data. Default: false.
bool set_neighbors_to_search_next_pairs()
[ADV. FRONT] Set the list of neighbors of the current element that must be tested yet...
void CalculateGlobalVolume()
Calculate the total intersection volume over all the processors.
libMesh::Mesh & mesh_A()
Reference to the mesh A.
void set_elem_as_treated(unsigned int elem_id)
[ADV. FRONT] Mark element as already treated.
void initialize()
Initialize the data structures.
void SetScalingFiles(const std::string &timing_data_file_base)
Set up timing output file.
libMesh::Mesh & mesh_Coupling()
Reference to the coupling mesh.
void add_neighbors_to_test_list()
[ADV. FRONT] Adds element to test list.
double get_intersection_volume(std::set< libMesh::Point > &input_points)
Calculate the volume of an polyhedron defined by the point set.
bool libMesh_exact_do_intersect_inside_coupling(const libMesh::Elem *elem_A, const libMesh::Elem *elem_B, bool bCreateNewNefForA=true)
Determinate if two elements intersect inside the coupling region.
void FindPatchIntersections_Front(const libMesh::Elem *Query_elem)
Find all the intersections between the patches associated to the Query_elem, using an advancing front...
unsigned int test_queue_extract_front_elem()
[ADV. FRONT] Pop and returns the first element to be tested.
void preallocate_grid(int map_preallocation)
Preallocate the discrete points grid.
bool libMesh_exact_do_intersect(const libMesh::Elem *elem_A, const libMesh::Elem *elem_B)
Determinate if two elements intersect.
void FrontSearch_reset()
[ADV. FRONT] Reset the advancing front search data structures, with the exception of list of elements...
#define homemade_assert_msg(asserted, msg)
Definition: common_header.h:63
unsigned int size()
Returns the number of elements inside the patch.
void intersection_queue_push_back(unsigned int elem_id)
[ADV. FRONT] Push back element to the deque containing the elements to be treated.
void prepare_for_use()
Prepare the intersection mesh for use.
bool libMesh_exact_intersection_inside_coupling(const libMesh::Elem *elem_A, const libMesh::Elem *elem_B, std::set< libMesh::Point > &points_out, bool bCreateNewNefForA=true, bool bConvertPoints=true, bool bTestNeeded=false)
Build the intersection between two elements intersect inside the coupling region. ...
bool m_bSaveInterData
Boolean flag determining if we should save the intersection data or not. Default: true...
void CalculateIntersectionVolume(const libMesh::Elem *Query_elem)
Calculate the volume of the intersections associated to Query_elem without updating the intersection ...
Intersection_Tools m_Intersection_test_neighbors
Intersection operations for the neighbor intersection tests. (why do we need both?)
void FindAndBuildIntersections_Brute()
Find and build all the intersections, using the brute force method.
const unsigned int m_rank
This processor's rank (or ID in the communicator)
void BuildIntersections(SearchMethod search_type=BRUTE)
Find and build all the intersections.
libMesh::Mesh & mesh_B()
Reference to the mesh B.
bool m_bPrintTimingData
Print timing data. Default: false.
void FrontSearch_initialize()
[ADV. FRONT] Initialize the advancing front search data structures.
std::unordered_set< unsigned int > & neighbors_to_search_next_pair()
[ADV. FRONT] Returns the current element's neighbors that must be tested yet.