CArl
Code Arlequin / C++ implementation
stitch_meshes.cpp
Go to the documentation of this file.
1 /*
2  * stitch_meshes.cpp
3  *
4  * Created on: Jun 2, 2016
5  * Author: Thiago Milanetto Schlittler
6  */
7 
8 #include "stitch_meshes.h"
9 
10 namespace carl
11 {
12 const libMesh::ReplicatedMesh & Stitch_Meshes::mesh()
13 {
14  return m_Stitched_mesh;
15 }
16 
17 void Stitch_Meshes::set_base_filenames(std::vector<std::string> & mesh_filenames, std::vector<std::string> & table_filenames)
18 {
19  homemade_assert_msg(mesh_filenames.size() == table_filenames.size(), "File lists have different sizes!\n");
20 
21  m_nb_files = table_filenames.size();
22 
23  // Resize the string vectors
24  m_mesh_filenames.resize(m_nb_files);
25  m_table_filenames.resize(m_nb_files);
26 
27  for(unsigned int iii = 0; iii < m_nb_files; ++iii)
28  {
29  m_mesh_filenames[iii] = mesh_filenames[iii];
30  m_table_filenames[iii] = table_filenames[iii];
31  }
32 
33  m_bFilenamesSet = true;
34 }
35 
36 void Stitch_Meshes::set_base_filenames(const std::string & filename_base, const std::string & mesh_format, unsigned int nb_of_files )
37 {
38  // Set the number of files
39  if(nb_of_files == 0)
40  {
42  }
43  else
44  {
45  m_nb_files = nb_of_files;
46  }
47 
48  // Resize the string vectors
51 
52  for(unsigned int iii = 0; iii < m_nb_files; ++iii)
53  {
54  m_mesh_filenames[iii] = filename_base + "_r_" + std::to_string(iii) + "_n_" + std::to_string(m_nb_files) + mesh_format;
55  m_table_filenames[iii] = filename_base + "_r_" + std::to_string(iii) + "_n_" + std::to_string(m_nb_files) + "_inter_table.dat";
56  }
57 
59  m_table_output= m_base_output + "_inter_pairs.dat";
60 
61  m_bFilenamesSet = true;
62 }
63 
64 void Stitch_Meshes::preallocate_grid(int map_preallocation)
65 {
66  m_discrete_vertices.reserve(map_preallocation);
67 // m_Grid_to_mesh_vertex_idx.reserve(map_preallocation);
68  m_bGridPreallocated = true;
69 }
70 
71 void Stitch_Meshes::set_grid_constraints(const libMesh::Mesh & mesh_A, const libMesh::Mesh & mesh_B, double vol_tol )
72 {
73  libMesh::MeshTools::BoundingBox bbox_A = libMesh::MeshTools::bounding_box(mesh_A);
74  libMesh::MeshTools::BoundingBox bbox_B = libMesh::MeshTools::bounding_box(mesh_B);
75 
76  // Just to be sure, test if the bboxes intersect!
77  homemade_assert_msg(bbox_A.intersect(bbox_B),"Meshes' bounding boxes do not intersect!\n");
78 
79  // Set the (future) intersection bbox corners
80  std::vector<double> eps_candidates(3,0);
81  for(unsigned int iii = 0; iii < 3; ++iii)
82  {
83  m_Grid_MinPoint(iii) = std::max(bbox_A.min()(iii),bbox_B.min()(iii));
84  m_Grid_MaxPoint(iii) = std::min(bbox_A.max()(iii),bbox_B.max()(iii));
85  eps_candidates[iii] = (m_Grid_MaxPoint(iii) - m_Grid_MinPoint(iii))/m_GridN_min;
86  }
87 
88  m_eps = *std::min_element(eps_candidates.begin(),eps_candidates.end());
89 
90  for(unsigned int iii = 0; iii < 3; ++iii)
91  {
92  m_Grid_MinPoint(iii) -= 2*m_eps;
93  m_Grid_MaxPoint(iii) += 2*m_eps;
94  }
95 
96  for(unsigned int iii = 0; iii < 3; ++iii)
97  {
98  m_GridN[iii] = (m_Grid_MaxPoint(iii) - m_Grid_MinPoint(iii)) / m_eps + 1;
99  }
100 
101  if( vol_tol < 0 )
102  {
103  // Grossily estimate the volume of A's and B's elements using the bbox
104  double grid_volume = (m_Grid_MaxPoint(0) - m_Grid_MinPoint(0)) *
105  (m_Grid_MaxPoint(1) - m_Grid_MinPoint(1)) *
107 
108 
109  double fraction_vol_A = (bbox_A.max()(0) - bbox_A.min()(0)) *
110  (bbox_A.max()(1) - bbox_A.min()(1)) *
111  (bbox_A.max()(2) - bbox_A.min()(2)) /
112  grid_volume;
113 
114  double fraction_vol_B = (bbox_B.max()(0) - bbox_B.min()(0)) *
115  (bbox_B.max()(1) - bbox_B.min()(1)) *
116  (bbox_B.max()(2) - bbox_B.min()(2)) /
117  grid_volume;
118 
119  unsigned int est_elem = std::max(fraction_vol_A * mesh_A.n_elem(),fraction_vol_B * mesh_B.n_elem());
120 
121  m_vol_tol = 1E-6 * grid_volume / est_elem;
122  }
123  else
124  {
125  m_vol_tol = vol_tol;
126  }
127 
128  // Mark grid as ready to use
129  m_bGridDefined = true;
130 
131  if(m_bPrintDebug)
132  {
133  std::cout << " DEBUG: discrete grid" << std::endl;
134  std::cout << " -> eps : " << m_eps << std::endl;
135  std::cout << " -> volume : " << m_vol_tol << std::endl;
136  std::cout << " -> Grid dimensions : " << m_GridN[0] << " " << m_GridN[1] << " " << m_GridN[2] << " " << std::endl << std::endl;
137  }
138 }
139 
141 {
142  // Copy everything from the argument
143  m_Grid_MinPoint = mesh_inter_obj.min_point();
144  m_Grid_MaxPoint = mesh_inter_obj.max_point();
145  m_eps = mesh_inter_obj.eps();
146  m_vol_tol = mesh_inter_obj.min_vol();
147  m_GridN = mesh_inter_obj.grid_sizes();
148  m_GridN_min = mesh_inter_obj.grid_min_size();
149 
150  // Mark grid as ready to use
151  m_bGridDefined = true;
152 
153  if(m_bPrintDebug)
154  {
155  std::cout << " DEBUG: discrete grid" << std::endl;
156  std::cout << " -> eps : " << m_eps << std::endl;
157  std::cout << " -> volume : " << m_vol_tol << std::endl;
158  std::cout << " -> Grid dimensions : " << m_GridN[0] << " " << m_GridN[1] << " " << m_GridN[2] << " " << std::endl << std::endl;
159  }
160 }
161 
163 {
164  // Check if the grids and files were set, and if the grid was preallocated
165  homemade_assert_msg(m_bGridDefined,"Grid not set!\n");
166  homemade_assert_msg(m_bFilenamesSet,"Filenames not set!\n");
167 
168  // -> First, read the intersection tables files, to get the grid hash
169  // function preallocation.
170 
171  std::ifstream table_file;
173  m_nb_of_elements = 0;
175 
176  unsigned int temp_nb_of_intersections = 0;
177  unsigned int temp_nb_of_elements = 0;
178  unsigned int temp_nb_of_nodes = 0;
179 
180  for(unsigned int iii = 0; iii < m_nb_files; ++iii)
181  {
182  table_file.open(m_table_filenames[iii]);
183  table_file >> temp_nb_of_intersections;
184  table_file >> temp_nb_of_elements;
185  table_file >> temp_nb_of_nodes;
186 
187  table_file.close();
188 
189  m_nb_of_intersections += temp_nb_of_intersections;
190  m_nb_of_elements += temp_nb_of_elements;
191  m_maximum_nb_of_nodes += temp_nb_of_nodes;
192  }
193 
194  // -> Preallocate the data structures
196 
197  m_Stitched_mesh.reserve_elem(m_nb_of_elements);
198  m_Stitched_mesh.reserve_nodes(m_maximum_nb_of_nodes);
199 
204 
205  // -> Second, read the data that will be used to reconstruct the
206  // intersection tables in the end: intersection pairs, and number of
207  // elements per intersection.
208  unsigned int intersection_idx = 0;
209  unsigned int dummy_uint = 0;
210  unsigned int nb_of_elems = 0;
211  for(unsigned int iii = 0; iii < m_nb_files; ++iii)
212  {
213  table_file.open(m_table_filenames[iii]);
214  table_file >> temp_nb_of_intersections;
215  table_file >> temp_nb_of_elements;
216  table_file >> temp_nb_of_nodes;
217 
218  for(unsigned int jjj = 0; jjj < temp_nb_of_intersections; ++jjj)
219  {
220  table_file >> dummy_uint;
221  table_file >> m_intersection_pairs[intersection_idx].first
222  >> m_intersection_pairs[intersection_idx].second;
223  table_file >> m_intersection_nb_of_elements[intersection_idx];
224  carl::jump_lines(table_file);
225 
226  // Prepare data for the restriction mesh
227  nb_of_elems += m_intersection_nb_of_elements[intersection_idx];
228  m_restriction_set_first.insert(m_intersection_pairs[intersection_idx].first);
229  m_restriction_set_second.insert(m_intersection_pairs[intersection_idx].second);
230  ++intersection_idx;
231  }
232 
233  table_file.close();
234  }
235 
236  // -> Fourth, re-build the intersection tables
237  unsigned int intersection_elem_idx = 0;
238 
239  std::ofstream joined_tables_file(m_table_output);
240  joined_tables_file << m_nb_of_intersections << " "
241  << nb_of_elems << std::endl;
242 
243  for(unsigned int iii = 0; iii < m_nb_of_intersections; ++iii)
244  {
245  joined_tables_file << m_intersection_pairs[iii].first << " "
246  << m_intersection_pairs[iii].second << std::endl;
247  // joined_tables_file << iii << " "
248  // << m_intersection_pairs[iii].first << " "
249  // << m_intersection_pairs[iii].second << " "
250  // << m_intersection_nb_of_elements[iii] << " ";
251  // for(unsigned jjj = 0; jjj < m_intersection_nb_of_elements[iii]; ++jjj)
252  // {
253  // joined_tables_file << intersection_elem_idx << " ";
254  // ++intersection_elem_idx;
255  // }
256  // joined_tables_file << std::endl;
257  }
258  joined_tables_file.close();
259 }
260 
262 {
263  homemade_assert_msg(m_bGridPreallocated,"Grid not preallocated!\n");
264 
265  // -> Third, stitch the meshes
266  libMesh::ReplicatedMesh temp_mesh(m_world_comm,3);
267  temp_mesh.allow_renumbering(false);
268 
269  unsigned int full_mesh_nb_elems = 0;
270  unsigned int full_mesh_nb_nodes = 0;
271 
272  libMesh::Elem * copy_elem = NULL;
273  libMesh::Elem * mesh_elem = NULL;
274  libMesh::Node * mesh_node = NULL;
275 
276  double dummy_volume = 0;
277 
278  // -> Stitch!
279  for(unsigned int iii = 0; iii < m_nb_files; ++iii)
280  {
281  // -> Open mesh file
282  temp_mesh.read(m_mesh_filenames[iii]);
283 
284  // -> Insert nodes
285  libMesh::ReplicatedMesh::element_iterator it_mesh = temp_mesh.elements_begin();
286 
287  for( ; it_mesh != temp_mesh.elements_end(); ++it_mesh)
288  {
289  copy_elem = * it_mesh;
290 
291  // -> Each element is unique, so no tests for insertion
292  mesh_elem = libMesh::Elem::build(libMesh::TET4).release();
293  mesh_elem->set_id(full_mesh_nb_elems);
294  mesh_elem->processor_id(0);
295 
296  // -> First, add the nodes
297  for(unsigned int jjj = 0; jjj < 4; ++jjj)
298  {
299  convert_to_discrete(copy_elem->point(jjj),m_dummy_discrete_point);
301  {
302  // New vertex! Add it to the mesh
303  m_discrete_vertices[m_dummy_discrete_point] = full_mesh_nb_nodes;
304  mesh_node = m_Stitched_mesh.add_point(copy_elem->point(jjj),full_mesh_nb_nodes,0);
305  ++full_mesh_nb_nodes;
306  }
307  else
308  {
310  }
311 
312  // Associate vertex to the new element
313  mesh_elem->set_node(jjj) = mesh_node;
314 
315  }
316 
317  m_Stitched_mesh.add_elem(mesh_elem);
318  dummy_volume += mesh_elem->volume();
319 
320  ++full_mesh_nb_elems;
321  }
322  }
323 
324  // Print information about the number of collisions
325  if(m_bPrintDebug)
326  {
327  size_t collisions = 0;
328  for (size_t bucket = 0; bucket != m_discrete_vertices.bucket_count(); ++bucket)
329  {
330  if (m_discrete_vertices.bucket_size(bucket) > 1)
331  {
332  collisions += m_discrete_vertices.bucket_size(bucket) - 1;
333  }
334  }
335 
336  std::cout << " DEBUG: discrete grid hash collisions" << std::endl;
337  std::cout << " -> Nb. of collisions / size : " << collisions << " / " << m_discrete_vertices.size()
338  << " (" << 100.*collisions/m_discrete_vertices.size() << "%)" << std::endl << std::endl;
339  }
340  m_Stitched_mesh.prepare_for_use();
341 
342  // Print mesh
343  libMesh::NameBasedIO output_mesh(m_Stitched_mesh);
344  output_mesh.write(m_mesh_output);
345 
346  if(m_bPrintDebug)
347  {
348  std::cout << " DEBUG: stitched mesh" << std::endl;
349  std::cout << " -> Volume : " << dummy_volume << std::endl << std::endl;
350  }
351 
352  int wrong_volume = 0;
353  libMesh::ReplicatedMesh::element_iterator elem_begin = m_Stitched_mesh.local_elements_begin();
354  libMesh::ReplicatedMesh::element_iterator elem_end = m_Stitched_mesh.local_elements_end();
355 
356  for( ; elem_begin != elem_end; ++elem_begin)
357  {
358  libMesh::Elem * dummy_elem = * elem_begin;
359  if(std::abs(dummy_elem->volume()) < m_vol_tol)
360  {
361  ++wrong_volume;
362  }
363  }
364 
365  std::cout << " -> bad volumes : " << wrong_volume << " ( " << m_vol_tol << " ) " << std::endl;
366 };
367 
368 void Stitch_Meshes::convert_to_discrete(const libMesh::Point& iPoint, std::vector<long>& oPoint)
369 {
370  oPoint[0] = lround( (iPoint(0) - m_Grid_MinPoint(0) )/m_eps);
371  oPoint[1] = lround( (iPoint(1) - m_Grid_MinPoint(1) )/m_eps);
372  oPoint[2] = lround( (iPoint(2) - m_Grid_MinPoint(2) )/m_eps);
373 }
374 
375 const std::unordered_set<unsigned int>* Stitch_Meshes::get_restricted_set_pointer_first()
376 {
377  return &m_restriction_set_first;
378 };
379 
380 const std::unordered_set<unsigned int>* Stitch_Meshes::get_restricted_set_pointer_second()
381 {
382  return &m_restriction_set_second;
383 };
384 
385 }
386 
387 
388 
389 
std::vector< long > m_GridN
Dimensions of the discrete point grid.
Definition: stitch_meshes.h:81
long m_GridN_min
Minimal number of integers over each dimension of the discrete grid.
Definition: stitch_meshes.h:96
libMesh::Point & min_point()
Returns the minimal point of the discrete grid.
const unsigned int m_nodes
Number of processors.
Definition: stitch_meshes.h:40
unsigned int m_nb_files
Number of files.
Definition: stitch_meshes.h:53
std::vector< std::pair< unsigned int, unsigned int > > m_intersection_pairs
Vector containing all the intersection pairs.
Definition: stitch_meshes.h:61
bool m_bGridDefined
Is the grid defined?
libMesh::Point & max_point()
Returns the maximum point of the discrete grid.
std::string m_table_output
Intersection table output filename.
Definition: stitch_meshes.h:58
double m_eps
Precision of the discrete point grid.
Definition: stitch_meshes.h:75
unsigned int m_nb_of_elements
Final mesh's number of elements.
long grid_min_size()
Returns the minimum discrete grid size.
std::unordered_set< unsigned int > m_restriction_set_second
Set of elements used for the restriction of the second mesh.
Definition: stitch_meshes.h:66
bool m_bGridPreallocated
Is the grid preallocated?
bool m_bFilenamesSet
Have the filenames been set?
std::vector< unsigned int > m_intersection_nb_of_elements
Nmber of elements inside each intersection.
Definition: stitch_meshes.h:69
void preallocate_grid(int map_preallocation)
Preallocate the discrete points grid.
unsigned int m_nb_of_intersections
Final mesh's number of intersections.
Definition: stitch_meshes.h:99
std::string m_base_output
Base output filename.
Definition: stitch_meshes.h:56
void set_base_filenames(std::vector< std::string > &mesh_filenames, std::vector< std::string > &table_filenames)
Set by hand the filenames used to build the stitched mesh.
double eps()
Returns the discrete grid step.
std::unordered_set< unsigned int > m_restriction_set_first
Set of elements used for the restriction of the first mesh.
Definition: stitch_meshes.h:65
std::vector< long > m_dummy_discrete_point
Definition: stitch_meshes.h:83
void stitch_meshes()
Stitch the meshes.
libMesh::ReplicatedMesh & m_Stitched_mesh
Final, stitched mesh.
Definition: stitch_meshes.h:44
void set_grid_constraints(const libMesh::Mesh &mesh_A, const libMesh::Mesh &mesh_B, double vol_tol=-1)
Set the boundaries of the discrete points grid, using the intersected meshes as a base...
void join_tables()
Join the intersection tables.
std::unordered_map< std::vector< long >, unsigned int, PointHash_3D, PointHash_3D_Equal > m_discrete_vertices
Unordered map (or hash) for the discrete points (key).
Definition: stitch_meshes.h:93
void convert_to_discrete(const libMesh::Point &iPoint, std::vector< long > &oPoint)
Convert a real valued point to a discrete point.
double min_vol()
Returns the minimal polyhedron volume.
libMesh::Point m_Grid_MinPoint
Minimal point of the discrete grid.
Definition: stitch_meshes.h:86
std::vector< long > & grid_sizes()
Returns the discrete grid sizes.
double m_vol_tol
Grid minimum volume.
Definition: stitch_meshes.h:78
const std::unordered_set< unsigned int > * get_restricted_set_pointer_second()
Returns the pointer to the set with the elements used to form the second restricted mesh...
Class used to construct the intersection meshes.
std::string m_mesh_output
Mesh output filename.
Definition: stitch_meshes.h:57
bool m_bPrintDebug
Print debug information? Default: false.
#define homemade_assert_msg(asserted, msg)
Definition: common_header.h:63
const libMesh::Parallel::Communicator & m_world_comm
MPI Communicator.
Definition: stitch_meshes.h:39
libMesh::Point m_Grid_MaxPoint
Maximum point of the discrete grid.
Definition: stitch_meshes.h:89
const std::unordered_set< unsigned int > * get_restricted_set_pointer_first()
Returns the pointer to the set with the elements used to form the first restricted mesh...
unsigned int m_maximum_nb_of_nodes
Upper limit for the final mesh's number of nodes.
std::vector< std::string > m_mesh_filenames
File names of the meshes to be stitched.
Definition: stitch_meshes.h:47
void jump_lines(T &filestream, unsigned int numberOfLines=1)
const libMesh::ReplicatedMesh & mesh()
Returns the stitched mesh.
std::vector< std::string > m_table_filenames
File names of intersection tables to joined.
Definition: stitch_meshes.h:50