CArl
Code Arlequin / C++ implementation
patch_construction.cpp
Go to the documentation of this file.
1 /*
2  * patch_construction.cpp
3  *
4  * Created on: Apr 14, 2016
5  * Author: Thiago Milanetto Schlittler
6  */
7 
8 #include "patch_construction.h"
9 
10 namespace carl
11 {
12 // Getters
13 libMesh::ReplicatedMesh & Patch_construction::parent_mesh()
14 {
15  return m_Mesh_parent;
16 }
17 
18 libMesh::ReplicatedMesh & Patch_construction::patch_mesh()
19 {
20  return m_Mesh_patch;
21 }
22 
23 std::unordered_set<unsigned int> & Patch_construction::elem_indexes()
24 {
25  return m_Patch_Elem_indexes;
26 };
27 
28 std::unordered_set<unsigned int> & Patch_construction::node_indexes()
29 {
30  return m_Patch_Node_indexes;
31 };
32 
34 {
35  return m_Patch_Elem_indexes.size();
36 }
37 
38 const libMesh::Elem * Patch_construction::elem(unsigned int idx)
39 {
40  return m_Mesh_parent.elem(idx);
41 }
42 
43 std::unordered_map<unsigned int,std::unordered_set<unsigned int> > & Patch_construction::patch_elem_neighbours()
44 {
46 }
47 
48 void Patch_construction::insert_patch_element(const libMesh::Elem * Patch_elem)
49 {
50  m_Patch_Elem_indexes.insert(Patch_elem->id());
51  for(unsigned int iii = 0; iii < Patch_elem->n_nodes(); ++iii)
52  {
53  m_Patch_Node_indexes.insert(Patch_elem->node(iii));
54  }
55 }
56 
57 void Patch_construction::BuildPatch(const libMesh::Elem * Query_elem)
58 {
59  bool bDoIntersect = false;
60 
61  std::set<unsigned int> Intersecting_elems;
62  m_Intersection_Test.FindAllIntersection(Query_elem,m_Parent_Point_Locator,Intersecting_elems);
63 
64  m_Patch_Elem_indexes.clear();
65  m_Patch_Node_indexes.clear();
67 
68  // Deque containing the indices of the elements to test
69  std::deque<int> Patch_Test_Queue;
70 
71  // Unordered set, used to avoid double testing elements
72  std::unordered_set<int> Treated_From_Mesh(m_Mesh_parent.n_elem());
73 
74  // Index and pointer to element being tested right now
75  unsigned int Tested_idx;
76 
77  // Candidate index
78  unsigned int Candidate_idx;
79 
80  // First element is ok!
81  libMesh::Elem * First_Patch_elems = NULL;
82  libMesh::Elem * elem_candidate = NULL;
83  std::set<unsigned int>::iterator it_set_start = Intersecting_elems.begin();
84  for( ; it_set_start != Intersecting_elems.end(); ++it_set_start)
85  {
86  Treated_From_Mesh.insert(*it_set_start);
87  First_Patch_elems = m_Mesh_parent.elem(*it_set_start);
88  insert_patch_element(First_Patch_elems);
89 
90  for(unsigned int iii = 0; iii < First_Patch_elems->n_neighbors(); ++iii)
91  {
92  elem_candidate = First_Patch_elems->neighbor(iii);
93  if(elem_candidate != NULL)
94  {
95  Patch_Test_Queue.push_back(elem_candidate->id());
96  Treated_From_Mesh.insert(elem_candidate->id());
97  }
98  }
99  }
100 
101  // Debug vars
102  int nbOfTests = 1;
103  int nbOfPositiveTests = 1;
104 
105  while(!Patch_Test_Queue.empty())
106  {
107  // Extract element from the list
108  Tested_idx = Patch_Test_Queue[0];
109  Patch_Test_Queue.pop_front();
110  const libMesh::Elem * Tested_elem = m_Mesh_parent.elem(Tested_idx);
111 
112  // Test it
113  bDoIntersect = m_Intersection_Test.libMesh_exact_do_intersect(Query_elem,Tested_elem);
114  ++nbOfTests;
115 
116  // If it does intersect ...
117  if(bDoIntersect)
118  {
119  ++nbOfPositiveTests;
120 
121  // Add it to the output list ...
122  insert_patch_element(Tested_elem);
123 
124  // ... And add its neighbours (if they weren't tested yet)
125  for(unsigned int iii = 0; iii < Tested_elem->n_neighbors(); ++iii)
126  {
127  elem_candidate = Tested_elem->neighbor(iii);
128  if(elem_candidate != NULL)
129  {
130  Candidate_idx = elem_candidate->id();
131  if(Treated_From_Mesh.find(Candidate_idx)==Treated_From_Mesh.end())
132  {
133  Patch_Test_Queue.push_back(Candidate_idx);
134  Treated_From_Mesh.insert(Candidate_idx);
135  }
136  }
137  }
138  }
139  }
140 
141  // Now, let us build the patch's neighbour table
142  std::unordered_set<unsigned int> dummy_neighbour_set(12);
143 
144  std::unordered_set<unsigned int>::iterator it_set = m_Patch_Elem_indexes.begin();
145  std::unordered_set<unsigned int>::iterator it_set_end = m_Patch_Elem_indexes.end();
147 
148  libMesh::Elem * elem_neighbour;
149  unsigned int elem_neighbour_id;
150 
151  for( ; it_set != it_set_end; ++it_set)
152  {
153  const libMesh::Elem * elem = m_Mesh_parent.elem(*it_set);
154  dummy_neighbour_set.clear();
155 
156  for(unsigned int iii = 0; iii < elem->n_neighbors(); ++iii)
157  {
158  elem_neighbour = elem->neighbor(iii);
159 
160  if(elem_neighbour != NULL)
161  {
162  // Then test if it is inside the patch
163  elem_neighbour_id = elem_neighbour->id();
164  if(m_Patch_Elem_indexes.find(elem_neighbour_id) != m_Patch_Elem_indexes.end())
165  {
166  // Then the neighbor is inside the patch, insert it
167  dummy_neighbour_set.insert(elem_neighbour->id());
168  }
169  }
170  }
171  m_Patch_Elem_Neighbours.insert(std::pair<unsigned int,std::unordered_set<unsigned int> >(*it_set,dummy_neighbour_set));
172  }
173 
174  // Build the patch mesh
175  this->build_patch_mesh();
176 
177  if(m_bPrintDebug)
178  {
179  std::cout << " DEBUG: patch search results" << std::endl;
180  std::cout << " -> Nb. of intersections found : " << m_Patch_Elem_indexes.size() << std::endl << std::endl;
181 
182  std::cout << " -> Nb. of mesh elements : " << m_Mesh_parent.n_elem() << std::endl;
183  std::cout << " -> Nb. of patch elements : " << m_Patch_Elem_indexes.size() << std::endl;
184  std::cout << " -> Patch elem % : " << 100.*m_Patch_Elem_indexes.size()/m_Mesh_parent.n_elem() << " %" << std::endl << std::endl;
185 
186  std::cout << " -> Nb. of mesh nodes : " << m_Mesh_parent.n_nodes() << std::endl;
187  std::cout << " -> Nb. of patch nodes : " << m_Patch_Node_indexes.size() << std::endl;
188  std::cout << " -> Patch node % : " << 100.*m_Patch_Node_indexes.size()/m_Mesh_parent.n_nodes() << " %" << std::endl << std::endl;
189 
190  std::cout << " -> Nb. of tests : " << nbOfTests << std::endl;
191  std::cout << " -> Nb. of positive tests : " << nbOfPositiveTests << std::endl;
192  std::cout << " -> Positive % : " << 100.*nbOfPositiveTests/nbOfTests << " %" << std::endl << std::endl;
193  }
194 }
195 
196 /*
197  *
198  * Methods and getters associated to the advancing front search method.
199  *
200  */
201 
202 /*
203  * Getters, setters and extractors
204  */
206 {
207  m_element_intersection_queue.push_back(elem_id);
208 }
209 
210 void Patch_construction::set_elem_as_treated(unsigned int elem_id)
211 {
212  m_element_already_treated[elem_id] = 1;
213 }
214 
216 {
218 }
219 
221 {
222  return m_element_intersection_queue.empty();
223 }
224 
226 {
227  return m_element_test_queue.empty();
228 }
229 
231 {
233  m_element_intersection_queue.pop_front();
234  return m_working_element_id;
235 }
236 
238 {
240  m_element_test_queue.pop_front();
241  return m_working_element_id;
242 };
243 
245 {
246  return m_working_element_id;
247 };
248 
250 {
251  return m_elem_map_Parent_to_Patch[input];
252 }
253 
255 {
256  return m_elem_map_Patch_to_Parent[input];
257 }
258 
260 {
261  return m_Mesh_parent.elem(m_working_element_id);
262 }
263 
264 std::unordered_set<unsigned int> & Patch_construction::neighbors_to_search_next_pair()
265 {
267 }
268 
269 // Determinate which neighbors need to be tested
271 {
273 
274  // Iterator over all the neighbors
275  std::unordered_set<unsigned int>::iterator it_neigh, it_neigh_end;
276 
277  it_neigh = m_Patch_Elem_Neighbours[m_working_element_id].begin();
278  it_neigh_end = m_Patch_Elem_Neighbours[m_working_element_id].end();
279 
280  // Clear the "to test" set
282 
283  // And fill it, if needed
284  for( ; it_neigh != it_neigh_end; ++ it_neigh)
285  {
286  if( m_element_inside_intersection_queue[*it_neigh] == 0 )
287  {
288  // This element does not have an initial intersection pair,
289  // add it to the list
290  m_element_neighbours_to_search.insert(*it_neigh);
291  }
292  }
293 
295  {
296  // Then do not do the intersection test!
297  m_bTestNeighsForNewPairs = false;
298  }
299 
301 }
302 
304 {
305  std::unordered_set<unsigned int>::iterator it_neigh, it_neigh_end;
306 
307  it_neigh = m_Patch_Elem_Neighbours[m_working_element_id].begin();
308  it_neigh_end = m_Patch_Elem_Neighbours[m_working_element_id].end();
309 
310  for( ; it_neigh != it_neigh_end; ++ it_neigh)
311  {
312  if( m_element_already_treated[*it_neigh] == 0 )
313  {
314  // New element!
315  m_element_test_queue.push_back(*it_neigh);
316  m_element_already_treated[*it_neigh] = 1;
317  }
318  }
319 };
320 
321 /*
322  * Initialize the deques, vectors and sets
323  */
325 {
326  homemade_assert_msg(!m_Patch_Elem_indexes.empty() || !m_Patch_Node_indexes.empty(),"Patch is empty!");
327 
329  m_element_test_queue.clear();
330 
333 
336 
338  m_element_neighbours_to_search.reserve(12);
339 
340  std::unordered_set<unsigned int>::iterator it_idx, it_idx_end;
341  it_idx = m_Patch_Elem_indexes.begin();
342  it_idx_end = m_Patch_Elem_indexes.end();
343 
344  for( ; it_idx != it_idx_end; ++it_idx)
345  {
346  m_element_already_treated[*it_idx] = 0;
348  }
349 
351 }
352 
353 /*
354  * Reset everything, with the exception of the intersection queue
355  */
357 {
358  homemade_assert_msg(!m_Patch_Elem_indexes.empty() || !m_Patch_Node_indexes.empty(),"Patch is empty!");
359 
360  m_element_test_queue.clear();
361 
362  std::unordered_set<unsigned int>::iterator it_idx, it_idx_end;
363  it_idx = m_Patch_Elem_indexes.begin();
364  it_idx_end = m_Patch_Elem_indexes.end();
365 
366  for( ; it_idx != it_idx_end; ++it_idx)
367  {
368  m_element_already_treated[*it_idx] = 0;
370  }
371 
373 }
374 
375 /*
376  * Prepare the patch for a new round of tests
377  */
379 {
380  // Extract the intersection queue's first element
382 
383  // Add it to the test queue
384  m_element_test_queue.clear();
386 
387  return m_working_element_id;
388 }
389 
390 /*
391  * Build a patch mesh
392  */
394 {
395  // Test if the patch is empty
396  homemade_assert_msg(!m_Patch_Elem_indexes.empty() || !m_Patch_Node_indexes.empty(),"Patch is empty!");
397 
398  // Clear the input mesh
399  m_Mesh_patch.clear();
400 
401  m_Mesh_patch.reserve_elem(m_Patch_Elem_indexes.size());
402  m_Mesh_patch.reserve_nodes(m_Patch_Node_indexes.size());
403 
408 
409  // Insert the nodes
410  std::unordered_set<unsigned int>::iterator it_set = m_Patch_Node_indexes.begin();
411  std::unordered_set<unsigned int>::iterator it_set_end = m_Patch_Node_indexes.end();
412  libMesh::Node * dummyNode = NULL;
413  unsigned int counter = 0;
414  for( ; it_set != it_set_end ; ++it_set)
415  {
416  dummyNode = m_Mesh_parent.node_ptr(*it_set);
417  m_Mesh_patch.add_point(*dummyNode, counter, m_Mesh_parent.processor_id());
418  m_node_map_Parent_to_Patch[*it_set] = counter;
419  m_node_map_Patch_to_Parent[counter] = *it_set;
420  ++counter;
421  }
422 
423  // Insert the elements
424  it_set = m_Patch_Elem_indexes.begin();
425  it_set_end = m_Patch_Elem_indexes.end();
426  libMesh::Elem * originalElem = NULL;
427  libMesh::Elem * dummyElem = NULL;
428  counter = 0;
429 
430  unsigned int originalNode = 0;
431  unsigned int outputNode = 0;
432  for( ; it_set != it_set_end ; ++it_set)
433  {
434  originalElem = m_Mesh_parent.elem(*it_set);
435 
436  if(originalElem->type() == libMesh::TET4)
437  {
438  dummyElem = m_Mesh_patch.add_elem(new libMesh::Tet4 );
439  }
440  else if(originalElem->type() == libMesh::HEX8)
441  {
442  dummyElem = m_Mesh_patch.add_elem(new libMesh::Hex8 );
443  }
444  else
445  {
446  homemade_error_msg("Invalid element type!\n");
447  }
448 
449  for(unsigned int iii = 0; iii < originalElem->n_nodes(); ++iii)
450  {
451  originalNode = originalElem->node(iii);
452  outputNode = m_node_map_Parent_to_Patch[originalNode];
453  dummyElem->set_node(iii) = m_Mesh_patch.node_ptr(outputNode);
454  }
455 
456  m_elem_map_Parent_to_Patch[*it_set] = counter;
457  m_elem_map_Patch_to_Parent[counter] = *it_set;
458  ++counter;
459  }
460 
461  m_Mesh_patch.allow_renumbering(false);
462  m_Mesh_patch.prepare_for_use();
463 }
464 
465 void Patch_construction::export_patch_mesh(std::string & filename_base)
466 {
467  std::string filename_mesh = filename_base + ".msh";
468  m_Mesh_patch.write(filename_mesh);
469 
470  std::string filename_elements = filename_base + "_elements__global_to_patch.dat";
471  std::string filename_nodes = filename_base + "_nodes__global_to_patch.dat";
472 
473  std::ofstream elems_out(filename_elements);
474  std::ofstream nodes_out(filename_nodes);
475 
476  elems_out << m_elem_map_Patch_to_Parent.size() << std::endl;
477  for(unsigned int iii = 0; iii < m_elem_map_Patch_to_Parent.size(); ++iii)
478  {
479  elems_out << m_elem_map_Patch_to_Parent[iii] << " " << iii << std::endl;
480  }
481 
482  elems_out.close();
483 
484  nodes_out << m_node_map_Patch_to_Parent.size() << std::endl;
485  for(unsigned int iii = 0; iii < m_node_map_Patch_to_Parent.size(); ++iii)
486  {
487  nodes_out << m_node_map_Patch_to_Parent[iii] << " " << iii << std::endl;
488  }
489 
490  nodes_out.close();
491 }
492 }
libMesh::ReplicatedMesh m_Mesh_patch
Patch mesh.
std::unordered_map< unsigned int, int > m_node_map_Patch_to_Parent
Mapping between the patch and parent mesh nodes, using the former as keys.
std::unordered_set< unsigned int > & node_indexes()
Returns the set of nodes inside the patch.
std::unordered_set< unsigned int > m_Patch_Elem_indexes
Set of elements inside the patch.
#define homemade_error_msg(msg)
Definition: common_header.h:73
std::unordered_map< unsigned int, int > m_element_already_treated
[ADV. FRONT] Marks if an element was already treated or not
void set_elem_as_inside_queue(unsigned int elem_id)
[ADV. FRONT] Mark element as already inside the deque of elements to be treated.
std::unordered_map< unsigned int, int > m_node_map_Parent_to_Patch
Mapping between the parent and patch mesh nodes, using the former as keys.
void export_patch_mesh(std::string &filename_base)
Export the patch mesh to a file.
void insert_patch_element(const libMesh::Elem *Patch_elem)
Insert an parent mesh element inside the patch, updating the data structures.
const libMesh::Elem * current_elem_pointer()
unsigned int intersection_queue_extract_front_elem()
[ADV. FRONT] Pop and returns the first element to be treated.
libMesh::ReplicatedMesh & parent_mesh()
Returns the parent mesh.
unsigned int FrontSearch_prepare_for_probed_test()
[ADV. FRONT] Reset the advancing front search data structures, with the exception of list of elements...
std::unordered_map< unsigned int, std::unordered_set< unsigned int > > & patch_elem_neighbours()
Returns the patch mesh element neighbour table.
bool intersection_queue_empty()
[ADV. FRONT] Check if deque of elements to be treated is empty.
Intersection_Tools m_Intersection_Test
Intersection search and construction tools.
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.
std::unordered_set< unsigned int > & elem_indexes()
Returns the set of elements inside the patch.
libMesh::ReplicatedMesh & patch_mesh()
Returns the patch mesh.
libMesh::ReplicatedMesh & m_Mesh_parent
Parent mesh.
const libMesh::Elem * elem(unsigned int idx)
std::unordered_map< unsigned int, std::unordered_set< unsigned int > > m_Patch_Elem_Neighbours
Element neighbour table for the patch.
std::unordered_map< unsigned int, int > m_element_inside_intersection_queue
[ADV. FRONT] Marks if an element is already inside "m_element_intersection_queue" ...
unsigned int convert_patch_to_parent_elem_id(unsigned int input)
Convert an element index from the patch mesh to the parent mesh.
std::unordered_set< unsigned int > m_Patch_Node_indexes
Set of nodes inside the patch.
void BuildPatch(const libMesh::Elem *Query_elem)
Build the patch mesh covering a given "Query_elem".
bool set_neighbors_to_search_next_pairs()
[ADV. FRONT] Set the list of neighbors of the current element that must be tested yet...
void set_elem_as_treated(unsigned int elem_id)
[ADV. FRONT] Mark element as already treated.
void add_neighbors_to_test_list()
[ADV. FRONT] Adds element to test list.
std::unique_ptr< libMesh::PointLocatorBase > m_Parent_Point_Locator
Parent mesh point locator.
unsigned int test_queue_extract_front_elem()
[ADV. FRONT] Pop and returns the first element to be tested.
std::deque< int > m_element_intersection_queue
[ADV. FRONT] Deque containing the elements to be treated.
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.
unsigned int m_working_element_id
[ADV. FRONT] Index of the patch element currently being tested
std::deque< int > m_element_test_queue
[ADV. FRONT] Deque containing the elements to be tested
bool m_bPrintDebug
Print debug information? Default: false.
void intersection_queue_push_back(unsigned int elem_id)
[ADV. FRONT] Push back element to the deque containing the elements to be treated.
std::unordered_set< unsigned int > m_element_neighbours_to_search
[ADV. FRONT] Set containing the current element's neighbors that must be tested yet.
void build_patch_mesh()
Build a patch mesh from the patch data structures.
std::unordered_map< unsigned int, int > m_elem_map_Patch_to_Parent
Mapping between the patch and parent mesh elements, using the former as keys.
unsigned int convert_parent_to_patch_elem_id(unsigned int input)
Convert an element index from the parent mesh to the patch mesh.
std::unordered_map< unsigned int, int > m_elem_map_Parent_to_Patch
Mapping between the parent and patch mesh elements, using the former as keys.
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.