Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
MergeMesh.cpp
Go to the documentation of this file.
1 #include "moab/MergeMesh.hpp"
2 
3 #include "moab/Skinner.hpp"
5 #include "moab/Range.hpp"
6 #include "moab/CartVect.hpp"
7 
8 #include "Internals.hpp"
9 #include <vector>
10 #include <algorithm>
11 #include <string>
12 #include <vector>
13 #include <cassert>
14 #include <iostream>
15 #include <iomanip>
16 
17 #include <cstdlib>
18 
19 namespace moab
20 {
21 
22 MergeMesh::MergeMesh( Interface* impl, bool printErrorIn )
23  : mbImpl( impl ), mbMergeTag( 0 ), mergeTol( 0.001 ), mergeTolSq( 0.000001 ), printError( printErrorIn )
24 {
25 }
26 
28 {
30  mbMergeTag = NULL;
31 }
32 
34  int elems_size,
35  const double merge_tol,
36  const int do_merge,
37  const int update_sets,
38  Tag merge_tag,
39  bool do_higher_dim )
40 {
41  mergeTol = merge_tol;
42  mergeTolSq = merge_tol * merge_tol;
43  Range tmp_elems;
44  tmp_elems.insert( elems, elems + elems_size );
45  ErrorCode result = merge_entities( tmp_elems, merge_tol, do_merge, update_sets, (Tag)merge_tag, do_higher_dim );
46 
47  return result;
48 }
49 
50 /* This function appears to be not necessary after MOAB conversion
51 
52  void MergeMesh::perform_merge(Tag merge_tag)
53  {
54  // put into a range
55  ErrorCode result = perform_merge(merge_tag);
56  if (result != MB_SUCCESS)
57  throw std::runtime_error("Merge operation failed");
58  }*/
59 
61  const double merge_tol,
62  const int do_merge,
63  const int,
64  Tag merge_tag,
65  bool merge_higher_dim )
66 {
67  // If merge_higher_dim is true, do_merge must also be true
68  if( merge_higher_dim && !do_merge )
69  {
70  return MB_FAILURE;
71  }
72 
73  mergeTol = merge_tol;
74  mergeTolSq = merge_tol * merge_tol;
75 
76  // get the skin of the entities
77  Skinner skinner( mbImpl );
78  Range skin_range;
79  ErrorCode result = skinner.find_skin( 0, elems, 0, skin_range, false, false );
80  if( MB_SUCCESS != result ) return result;
81 
82  // create a tag to mark merged-to entity; reuse tree_root
83  EntityHandle tree_root = 0;
84  if( 0 == merge_tag )
85  {
86  result = mbImpl->tag_get_handle( "__merge_tag", 1, MB_TYPE_HANDLE, mbMergeTag, MB_TAG_DENSE | MB_TAG_EXCL,
87  &tree_root );
88  if( MB_SUCCESS != result ) return result;
89  }
90  else
91  mbMergeTag = merge_tag;
92 
93  // build a kd tree with the vertices
94  AdaptiveKDTree kd( mbImpl );
95  result = kd.build_tree( skin_range, &tree_root );
96  if( MB_SUCCESS != result ) return result;
97 
98  // find matching vertices, mark them
99  result = find_merged_to( tree_root, kd, mbMergeTag );
100  if( MB_SUCCESS != result ) return result;
101 
102  // merge them if requested
103  if( do_merge )
104  {
105  result = perform_merge( mbMergeTag );
106  if( MB_SUCCESS != result ) return result;
107  }
108 
109  if( merge_higher_dim && deadEnts.size() != 0 )
110  {
111  result = merge_higher_dimensions( elems );
112  if( MB_SUCCESS != result ) return result;
113  }
114 
115  return MB_SUCCESS;
116 }
117 
118 ErrorCode MergeMesh::merge_all( EntityHandle meshset, const double merge_tol )
119 {
120  if( 0 == mbMergeTag )
121  {
122  EntityHandle def_val = 0;
124  &def_val ) );
125  }
126  // get all entities;
127  // get all vertices connected
128  // build a kdtree
129  // find merged to
130  mergeTol = merge_tol;
131  mergeTolSq = merge_tol * merge_tol;
132 
133  // get all vertices
134  Range entities;
135  MB_CHK_ERR( mbImpl->get_entities_by_handle( meshset, entities, /*recursive*/ true ) );
136  Range sets = entities.subset_by_type( MBENTITYSET );
137  entities = subtract( entities, sets );
138  Range verts;
139  MB_CHK_ERR( mbImpl->get_connectivity( entities, verts ) );
140 
141  // build a kd tree with the vertices
142  AdaptiveKDTree kd( mbImpl );
143  EntityHandle tree_root;
144  MB_CHK_ERR( kd.build_tree( verts, &tree_root ) );
145  // find matching vertices, mark them
146  MB_CHK_ERR( find_merged_to( tree_root, kd, mbMergeTag ) );
147 
149 
150  if( deadEnts.size() != 0 )
151  {
152  MB_CHK_ERR( merge_higher_dimensions( entities ) );
153  }
154  return MB_SUCCESS;
155 }
157 {
158  // we start with an empty range of vertices that are "merged to"
159  // they are used (eventually) for higher dim entities
160  mergedToVertices.clear();
161  ErrorCode result;
162  if( deadEnts.size() == 0 )
163  {
164  if( printError ) std::cout << "\nWarning: Geometries don't have a common face; Nothing to merge" << std::endl;
165  return MB_SUCCESS; // nothing to merge carry on with the program
166  }
167  if( mbImpl->type_from_handle( *deadEnts.begin() ) != MBVERTEX ) return MB_FAILURE;
168  std::vector< EntityHandle > merge_tag_val( deadEnts.size() );
169  Range deadEntsRange;
170  std::copy( deadEnts.rbegin(), deadEnts.rend(), range_inserter( deadEntsRange ) );
171  result = mbImpl->tag_get_data( merge_tag, deadEntsRange, &merge_tag_val[0] );
172  if( MB_SUCCESS != result ) return result;
173 
174  std::set< EntityHandle >::iterator rit;
175  unsigned int i;
176  for( rit = deadEnts.begin(), i = 0; rit != deadEnts.end(); ++rit, i++ )
177  {
178  assert( merge_tag_val[i] );
179  if( MBVERTEX == TYPE_FROM_HANDLE( merge_tag_val[i] ) ) mergedToVertices.insert( merge_tag_val[i] );
180  result = mbImpl->merge_entities( merge_tag_val[i], *rit, false, false );
181  if( MB_SUCCESS != result )
182  {
183  return result;
184  }
185  }
186  result = mbImpl->delete_entities( deadEntsRange );
187  return result;
188 }
189 // merge vertices according to an input tag
190 // merge them if the tags are equal
191 struct handle_id
192 {
194  int val;
195 };
196 
197 // handle structure comparison function for qsort
198 // if the id is the same , compare the handle.
199 int compare_handle_id( const void* a, const void* b )
200 {
201 
202  handle_id* ia = (handle_id*)a;
203  handle_id* ib = (handle_id*)b;
204  if( ia->val == ib->val )
205  {
206  return ( ia->eh < ib->eh ) ? -1 : 1;
207  }
208  else
209  {
210  return ( ia->val - ib->val );
211  }
212 }
213 
215 {
216  ErrorCode rval;
217  DataType tag_type;
218  rval = mbImpl->tag_get_data_type( user_tag, tag_type );
219  if( rval != MB_SUCCESS || tag_type != MB_TYPE_INTEGER ) return MB_FAILURE;
220 
221  std::vector< int > vals( verts.size() );
222  rval = mbImpl->tag_get_data( user_tag, verts, &vals[0] );
223  if( rval != MB_SUCCESS ) return rval;
224 
225  if( 0 == merge_tag )
226  {
227  EntityHandle def_val = 0;
229  &def_val );
230  if( MB_SUCCESS != rval ) return rval;
231  }
232  else
233  mbMergeTag = merge_tag;
234 
235  std::vector< handle_id > handles( verts.size() );
236  int i = 0;
237  for( Range::iterator vit = verts.begin(); vit != verts.end(); ++vit )
238  {
239  handles[i].eh = *vit;
240  handles[i].val = vals[i];
241  i++;
242  }
243  // std::sort(handles.begin(), handles.end(), compare_handle_id);
244  qsort( &handles[0], handles.size(), sizeof( handle_id ), compare_handle_id );
245  i = 0;
246  while( i < (int)verts.size() - 1 )
247  {
248  handle_id first = handles[i];
249  int j = i + 1;
250  while( j < (int)verts.size() && handles[j].val == first.val )
251  {
252  rval = mbImpl->tag_set_data( mbMergeTag, &( handles[j].eh ), 1, &( first.eh ) );
253  if( rval != MB_SUCCESS ) return rval;
254  deadEnts.insert( handles[j].eh );
255  j++;
256  }
257  i = j;
258  }
259 
260  rval = perform_merge( mbMergeTag );
261 
262  return rval;
263 }
265 {
266  AdaptiveKDTreeIter iter;
267 
268  // evaluate vertices in this leaf
269  Range leaf_range, leaf_range2;
270  std::vector< EntityHandle > sorted_leaves;
271  std::vector< double > coords;
272  std::vector< EntityHandle > merge_tag_val, leaves_out;
273 
274  ErrorCode result = tree.get_tree_iterator( tree_root, iter );
275  if( MB_SUCCESS != result ) return result;
276  while( result == MB_SUCCESS )
277  {
278  sorted_leaves.push_back( iter.handle() );
279  result = iter.step();
280  }
281  if( result != MB_ENTITY_NOT_FOUND ) return result;
282  std::sort( sorted_leaves.begin(), sorted_leaves.end() );
283 
284  std::vector< EntityHandle >::iterator it;
285  for( it = sorted_leaves.begin(); it != sorted_leaves.end(); ++it )
286  {
287 
288  leaf_range.clear();
289  result = mbImpl->get_entities_by_handle( *it, leaf_range );
290  if( MB_SUCCESS != result ) return result;
291  coords.resize( 3 * leaf_range.size() );
292  merge_tag_val.resize( leaf_range.size() );
293  result = mbImpl->get_coords( leaf_range, &coords[0] );
294  if( MB_SUCCESS != result ) return result;
295  result = mbImpl->tag_get_data( merge_tag, leaf_range, &merge_tag_val[0] );
296  if( MB_SUCCESS != result ) return result;
297  Range::iterator rit;
298  unsigned int i;
299  bool inleaf_merged, outleaf_merged = false;
300  unsigned int lr_size = leaf_range.size();
301 
302  for( i = 0, rit = leaf_range.begin(); i != lr_size; ++rit, i++ )
303  {
304  if( 0 != merge_tag_val[i] ) continue;
305  CartVect from( &coords[3 * i] );
306  inleaf_merged = false;
307 
308  // check close-by leaves too
309  leaves_out.clear();
310  result =
311  tree.distance_search( from.array(), mergeTol, leaves_out, mergeTol, 1.0e-6, NULL, NULL, &tree_root );
312  leaf_range2.clear();
313  for( std::vector< EntityHandle >::iterator vit = leaves_out.begin(); vit != leaves_out.end(); ++vit )
314  {
315  if( *vit > *it )
316  { // if we haven't visited this leaf yet in the outer loop
317  result = mbImpl->get_entities_by_handle( *vit, leaf_range2, Interface::UNION );
318  if( MB_SUCCESS != result ) return result;
319  }
320  }
321  if( !leaf_range2.empty() )
322  {
323  coords.resize( 3 * ( lr_size + leaf_range2.size() ) );
324  merge_tag_val.resize( lr_size + leaf_range2.size() );
325  result = mbImpl->get_coords( leaf_range2, &coords[3 * lr_size] );
326  if( MB_SUCCESS != result ) return result;
327  result = mbImpl->tag_get_data( merge_tag, leaf_range2, &merge_tag_val[lr_size] );
328  if( MB_SUCCESS != result ) return result;
329  outleaf_merged = false;
330  }
331 
332  // check other verts in this leaf
333  for( unsigned int j = i + 1; j < merge_tag_val.size(); j++ )
334  {
335  EntityHandle to_ent = j >= lr_size ? leaf_range2[j - lr_size] : leaf_range[j];
336 
337  if( *rit == to_ent ) continue;
338 
339  if( ( from - CartVect( &coords[3 * j] ) ).length_squared() < mergeTolSq )
340  {
341  merge_tag_val[j] = *rit;
342  if( j < lr_size )
343  {
344  inleaf_merged = true;
345  }
346  else
347  {
348  outleaf_merged = true;
349  }
350  deadEnts.insert( to_ent );
351  }
352  }
353  if( outleaf_merged )
354  {
355  result = mbImpl->tag_set_data( merge_tag, leaf_range2, &merge_tag_val[leaf_range.size()] );
356  if( MB_SUCCESS != result ) return result;
357  outleaf_merged = false;
358  }
359  if( inleaf_merged )
360  {
361  result = mbImpl->tag_set_data( merge_tag, leaf_range, &merge_tag_val[0] );
362  if( MB_SUCCESS != result ) return result;
363  }
364  }
365  }
366  return MB_SUCCESS;
367 }
368 
369 // Determine which higher dimensional entities should be merged
371 {
372  // apply a different strategy
373  // look at the vertices that were merged to, earlier, and find all entities adjacent to them
374  // elems (input) are used just for initial connectivity
375  ErrorCode result;
376  Range verts;
377  result = mbImpl->get_connectivity( elems, verts );
378  if( MB_SUCCESS != result ) return result;
379 
380  // all higher dim entities that will be merged will be connected to the vertices that were
381  // merged earlier; we will look at these vertices only
382  Range mergedToVertsRange;
383  std::copy( mergedToVertices.rbegin(), mergedToVertices.rend(), range_inserter( mergedToVertsRange ) );
384  Range vertsOfInterest = intersect( mergedToVertsRange, verts );
385  // Go through each dimension
386  Range possibleEntsToMerge, conn, matches, moreDeadEnts;
387 
388  for( int dim = 1; dim < 3; dim++ )
389  {
390  moreDeadEnts.clear();
391  possibleEntsToMerge.clear();
392  result = mbImpl->get_adjacencies( vertsOfInterest, dim, false, possibleEntsToMerge, Interface::UNION );
393  if( MB_SUCCESS != result ) return result;
394  // Go through each possible entity and see if it shares vertices with another entity of same
395  // dimension
396  for( Range::iterator pit = possibleEntsToMerge.begin(); pit != possibleEntsToMerge.end(); ++pit )
397  {
398  EntityHandle eh = *pit; // possible entity to be matched
399  conn.clear();
400  // Get the vertices connected to it in a range
401 
402  result = mbImpl->get_connectivity( &eh, 1, conn );
403  if( MB_SUCCESS != result ) return result;
404  matches.clear();
405  // now retrieve all entities connected to all conn vertices
406  result = mbImpl->get_adjacencies( conn, dim, false, matches, Interface::INTERSECT );
407  if( MB_SUCCESS != result ) return result;
408  if( matches.size() > 1 )
409  {
410  for( Range::iterator matchIt = matches.begin(); matchIt != matches.end(); ++matchIt )
411  {
412  EntityHandle to_remove = *matchIt;
413  if( to_remove != eh )
414  {
415  moreDeadEnts.insert( to_remove );
416  result = mbImpl->merge_entities( eh, to_remove, false, false );
417  if( result != MB_SUCCESS ) return result;
418  possibleEntsToMerge.erase( to_remove );
419  }
420  }
421  }
422  }
423  // Delete the entities of dimension dim
424  result = mbImpl->delete_entities( moreDeadEnts );
425  if( result != MB_SUCCESS ) return result;
426  }
427  return MB_SUCCESS;
428 #if 0
429  Range skinEnts, adj, matches, moreDeadEnts;
430  ErrorCode result;
431  Skinner skinner(mbImpl);
432  //Go through each dimension
433  for (int dim = 1; dim < 3; dim++)
434  {
435  skinEnts.clear();
436  moreDeadEnts.clear();
437  result = skinner.find_skin(0, elems, dim, skinEnts, false, false);
438  //Go through each skin entity and see if it shares adjacancies with another entity
439  for (Range::iterator skinIt = skinEnts.begin();
440  skinIt != skinEnts.end(); ++skinIt)
441  {
442  adj.clear();
443  //Get the adjacencies 1 dimension lower
444  result = mbImpl->get_adjacencies(&(*skinIt), 1, dim - 1, false, adj);
445  if (result != MB_SUCCESS)
446  return result;
447  //See what other entities share these adjacencies
448  matches.clear();
449  result = mbImpl->get_adjacencies(adj, dim, false, matches,
451  if (result != MB_SUCCESS)
452  return result;
453  //If there is more than one entity, then we have some to merge and erase
454  if (matches.size() > 1)
455  {
456  for (Range::iterator matchIt = matches.begin();
457  matchIt != matches.end(); ++matchIt)
458  {
459  if (*matchIt != *skinIt)
460  {
461  moreDeadEnts.insert(*matchIt);
462  result = mbImpl->merge_entities(*skinIt, *matchIt, false, false);
463  if (result != MB_SUCCESS)
464  return result;
465  skinEnts.erase(*matchIt);
466  }
467  }
468  }
469  }
470  //Delete the entities
471  result = mbImpl->delete_entities(moreDeadEnts);
472  if (result != MB_SUCCESS)
473  return result;
474  }
475  return MB_SUCCESS;
476 #endif
477 }
478 
479 } // End namespace moab