1 /** \file   ReorderTool.cpp
2  *  \author Jason Kraftcheck
3  *  \date   2011-05-23
4  */
5 
6 #include "moab/ReorderTool.hpp"
7 #include "moab/Core.hpp"
8 #include "moab/Range.hpp"
9 
10 #include "SequenceManager.hpp"
11 #include "TypeSequenceManager.hpp"
12 #include "EntitySequence.hpp"
13 
14 #include <algorithm>
15 #include <numeric>
16 #include <set>
17 #include <iostream>
18 
19 namespace moab {
20 
21 // no-op function as a convenient spot to set a breakpoint
error(ErrorCode val)22 static inline ErrorCode error(ErrorCode val)
23   { return val; }
24 
25 #define CHKERR \
26   if (MB_SUCCESS != rval) \
27     return error(rval)
28 
29 #define UNRECOVERABLE(ERRCODE) do { if (MB_SUCCESS != (ERRCODE)) { \
30   error((ERRCODE)); \
31   std::cerr << "Unreconverable error during mesh reorder." << std::endl \
32             << "Error Code " << (ERRCODE) << " at " \
33             << __FILE__ << ":" << __LINE__ << std::endl; \
34   std::cerr.flush(); \
35   abort(); \
36 } } while(false)
37 
check_tag_type(Interface * moab,Tag tag,DataType exp_type,int exp_size)38 static ErrorCode check_tag_type( Interface* moab,
39                                  Tag tag,
40                                  DataType exp_type,
41                                  int exp_size )
42 {
43   ErrorCode rval;
44   DataType act_type;
45   int act_size;
46 
47   rval = moab->tag_get_data_type( tag, act_type );
48   CHKERR;
49 
50   rval = moab->tag_get_bytes( tag, act_size );
51   CHKERR;
52 
53   if (act_type != exp_type || act_size != exp_size)
54     return MB_TYPE_OUT_OF_RANGE;
55 
56   return MB_SUCCESS;
57 }
58 
handle_order_from_int_tag(Tag tag,int skip_value,Tag & new_handles)59 ErrorCode ReorderTool::handle_order_from_int_tag( Tag tag,
60                                                   int skip_value,
61                                                   Tag& new_handles )
62 {
63   ErrorCode rval;
64 
65     // check that input tag handles are what we expect
66   rval = check_tag_type( mMB, tag, MB_TYPE_INTEGER, sizeof(int) );
67   CHKERR;
68   EntityHandle zero = 0;
69   rval = mMB->tag_get_handle( 0, 1, MB_TYPE_HANDLE, new_handles,
70                               MB_TAG_DENSE|MB_TAG_CREAT|MB_TAG_EXCL, &zero );
71   CHKERR;
72 
73     // Can only reorder within same type/connectivity (or vertex/num_coords)
74     // groupings.  Call helper function for each such grouping.
75   for (EntityType t = MBVERTEX; t < MBENTITYSET; ++t) {
76       // Get list of all connectivity lengths (or vertex dimensions)
77       // that exist for type t.
78     TypeSequenceManager& seqs = mMB->sequence_manager()->entity_map(t);
79     TypeSequenceManager::iterator i;
80     std::set<int> values;
81     for (i = seqs.begin(); i != seqs.end(); ++i) {
82       EntitySequence* seq = *i;
83         // 0 values per entity implies structured data, which
84         // we cannot reorder.  Skip those.
85       if (t == MBVERTEX || 0 < seq->values_per_entity())
86         values.insert( seq->values_per_entity() );
87     }
88 
89       // Call helper function for each (type,size) tuple.
90     std::set<int>::iterator j;
91     for (j = values.begin(); j != values.end(); ++j) {
92       rval = handle_order_from_int_tag( t, *j, tag, skip_value, new_handles );
93       if (MB_SUCCESS != rval) {
94         mMB->tag_delete( new_handles );
95         return error(rval);
96       }
97     }
98   }
99 
100   return MB_SUCCESS;
101 }
102 
get_entities(EntityType t,int vals_per_ent,Range & entities)103 void ReorderTool::get_entities( EntityType t, int vals_per_ent, Range& entities )
104 {
105   Range::iterator hint = entities.begin();;
106   TypeSequenceManager& seqs = mMB->sequence_manager()->entity_map(t);
107   TypeSequenceManager::iterator s;
108   for (s = seqs.begin(); s != seqs.end(); ++s) {
109     EntitySequence* seq = *s;
110     if (seq->values_per_entity() == vals_per_ent)
111       hint = entities.insert( hint, seq->start_handle(), seq->end_handle() );
112   }
113 }
114 
handle_order_from_int_tag(EntityType t,int vals_per_ent,Tag tag,int skip_value,Tag new_handles)115 ErrorCode ReorderTool::handle_order_from_int_tag( EntityType t,
116                                                   int vals_per_ent,
117                                                   Tag tag,
118                                                   int skip_value,
119                                                   Tag new_handles )
120 {
121   ErrorCode rval;
122 
123     // check that input tag handles are what we expect
124   rval = check_tag_type( mMB, tag, MB_TYPE_INTEGER, sizeof(int) );
125   CHKERR;
126   rval = check_tag_type( mMB, new_handles, MB_TYPE_HANDLE, sizeof(EntityHandle) );
127   CHKERR;
128 
129     // get entities to re-order
130   Range entities;
131   get_entities( t, vals_per_ent, entities );
132 
133     // get entity order values
134   std::vector<int> sortvals(entities.size());
135   rval = mMB->tag_get_data( tag, entities, &sortvals[0] );
136   CHKERR;
137 
138     // remove any entities for which value is skip_value
139   size_t r = 0, w = 0;
140   for (Range::iterator i = entities.begin(); i != entities.end(); ++r) {
141     if (sortvals[r] == skip_value)
142       i = entities.erase(i);
143     else {
144       sortvals[w++] = sortvals[r];
145       ++i;
146     }
147   }
148   sortvals.resize(w);
149 
150     // sort
151   std::sort( sortvals.begin(), sortvals.end() );
152     // Convert to unique list and offsets for each value
153     // When done, sortvals will contain unique, sortvals and
154     // offsets will contain, for each unique value in sortvals,
155     // the number of values that occured in the non-unique list
156     // before the first instance of that value.
157   std::vector<size_t> offsets;
158   offsets.push_back( 0 );
159   offsets.push_back( 1 );
160   for (w = 0, r = 1; r < sortvals.size(); ++r) {
161     if (sortvals[r] == sortvals[w]) {
162       ++offsets.back();
163     }
164     else {
165       ++w;
166       sortvals[w] = sortvals[r];
167       offsets.push_back(offsets.back()+1);
168     }
169   }
170   ++w;
171   assert(w+1 == offsets.size());
172   sortvals.resize(w);
173 
174     // Tag each entity with its new handle
175   for (Range::iterator i = entities.begin(); i != entities.end(); ++i) {
176     int val;
177     rval = mMB->tag_get_data( tag, &*i, 1, &val );
178     CHKERR;
179     w = std::lower_bound( sortvals.begin(), sortvals.end(), val ) - sortvals.begin();
180     assert( w < sortvals.size() );
181     size_t offset = offsets[w];
182     ++offsets[w];
183       // should maybe copy range into array to avoid possibly n^2 behavior here
184     EntityHandle h = *(entities.begin() + offset);
185     rval = mMB->tag_set_data( new_handles, &*i, 1, &h );
186     CHKERR;
187   }
188 
189   return MB_SUCCESS;
190 }
191 
192 
193 
194 
195 ErrorCode
handle_order_from_sets_and_adj(const Range & sets,Tag & handle_tag)196 ReorderTool::handle_order_from_sets_and_adj( const Range& sets,
197                                              Tag& handle_tag )
198 {
199   ErrorCode rval;
200 
201   if (!sets.all_of_type(MBENTITYSET))
202     return MB_TYPE_OUT_OF_RANGE;
203 
204   Tag order_tag;
205   const int negone = -1;
206   rval = mMB->tag_get_handle( 0, 1, MB_TYPE_INTEGER, order_tag,
207                               MB_TAG_DENSE|MB_TAG_CREAT|MB_TAG_EXCL, &negone );
208   if (MB_SUCCESS != rval) {
209     mMB->tag_delete( handle_tag );
210     handle_tag = 0;
211     return error(rval);
212   }
213 
214   std::vector<std::vector<EntityHandle>*> data;
215   rval = int_order_from_sets_and_adj( sets, order_tag, negone, data );
216   for (size_t i = 0; i < data.size(); ++i)
217     delete data[i];
218   if (MB_SUCCESS != rval) {
219     mMB->tag_delete( order_tag );
220     return error(rval);
221   }
222 
223   rval = handle_order_from_int_tag( order_tag, negone, handle_tag );
224   if (MB_SUCCESS != rval) {
225     mMB->tag_delete( order_tag );
226     return error(rval);
227   }
228 
229   rval = mMB->tag_delete( order_tag );
230   if (MB_SUCCESS != rval)
231     return error(rval);
232 
233   return MB_SUCCESS;
234 }
235 
236     // Compare function to use for a map keyed on pointers to sorted vectors
237 struct CompSortedVect {
operator ()moab::CompSortedVect238   bool operator()( const std::vector<EntityHandle>* v1,
239                    const std::vector<EntityHandle>* v2 ) const
240   {
241     std::vector<EntityHandle>::const_iterator i1, i2;
242     for (i1 = v1->begin(), i2 = v2->begin(); i1 != v1->end(); ++i1, ++i2) {
243       if (i2 == v2->end() || *i1 > *i2)
244         return false;
245       else if (*i1 < *i2)
246         return true;
247     }
248     return i2 != v2->end();
249   }
250 };
251 
int_order_from_sets_and_adj(const Range & sets,Tag order_tag,int skip_val,std::vector<std::vector<EntityHandle> * > & revMap)252 ErrorCode ReorderTool::int_order_from_sets_and_adj( const Range& sets,
253                                                     Tag order_tag,
254                                                     int skip_val,
255                   std::vector<std::vector<EntityHandle>*>& revMap )
256 {
257   ErrorCode rval;
258 
259   if (!sets.all_of_type(MBENTITYSET))
260     return MB_TYPE_OUT_OF_RANGE;
261 
262   rval = check_tag_type( mMB, order_tag, MB_TYPE_INTEGER, sizeof(int) );
263   CHKERR;
264 
265     // Compare function to use for a map keyed on pointers to sorted vectors
266   CompSortedVect lessthan;
267     // Map from sorted list of handles to index
268   std::map< std::vector<EntityHandle>*, int, CompSortedVect > forMap;
269   std::map< std::vector<EntityHandle>*, int, CompSortedVect >::iterator fiter, fiter2;
270   std::vector<EntityHandle> sharing; // tmp storage for entity
271 
272     // for each set
273   for (Range::iterator s = sets.begin(); s != sets.end(); ++s) {
274 
275       // gather up all entities and adjacencies
276     Range tmp, ents, adj[4]; // indexed by dimension
277     for (int dim = 0; dim < 4; ++dim) {
278       rval = mMB->get_entities_by_dimension( *s, dim, tmp );
279       CHKERR;
280       for (int ldim = 0; ldim < dim; ++ldim) {
281         rval = mMB->get_adjacencies( tmp, ldim, false, adj[ldim], Interface::UNION );
282         CHKERR;
283       }
284       for (int udim = dim+1; udim <= 3; ++udim) {
285         rval = mMB->get_adjacencies( tmp, udim, false, adj[udim], Interface::UNION );
286         CHKERR;
287       }
288       ents.merge(tmp);
289       tmp.clear();
290     }
291     for (int dim = 0; dim < 4; ++dim) {
292       ents.merge( adj[dim] );
293       adj[dim].clear();
294     }
295 
296       // process each entity
297     for (Range::iterator e = ents.begin(); e != ents.end(); ++e) {
298       int val;
299       rval = mMB->tag_get_data( order_tag, &*e, 1, &val );
300       CHKERR;
301 
302         // If this entity is already in one or more of the sets (either
303         // directly or through adjacency) then get the existing list of
304         // sets and append this set handle (we are iterating over sets
305         // in sorted order, so appending should aways maintain a sorted
306         // list.)
307       sharing.clear();
308       if (val != skip_val) {
309         sharing = *revMap[val];
310         assert( std::lower_bound(sharing.begin(), sharing.end(), *s) == sharing.end() );
311       }
312       sharing.push_back( *s );
313 
314         // Check if new sharing list already exists in forward map
315       fiter = forMap.lower_bound( &sharing );
316       if (fiter == forMap.end() || lessthan(fiter->first,&sharing)) {
317           // Add new sharing list to forward and reverse maps.
318         std::vector<EntityHandle>* newvec = new std::vector<EntityHandle>;
319         newvec->swap(sharing);
320         if ((int)revMap.size() == skip_val)
321           revMap.push_back(0);
322         fiter2 = forMap.insert( fiter, std::pair<std::vector<EntityHandle>*, int>(newvec,revMap.size()) );
323         assert(fiter2 != fiter);
324         fiter = fiter2;
325         revMap.push_back( newvec );
326       }
327 
328         // Update index on entity
329       val = fiter->second;
330       rval = mMB->tag_set_data( order_tag, &*e, 1, &val );
331       CHKERR;
332     }
333   }
334 
335   return MB_SUCCESS;
336 }
337 
338 ErrorCode
get_reordered_handles(Tag tag,const Range & old_handles,std::vector<EntityHandle> & new_handles)339 ReorderTool::get_reordered_handles( Tag tag,
340                                     const Range& old_handles,
341                                     std::vector<EntityHandle>& new_handles )
342 {
343   new_handles.resize( old_handles.size() );
344   ErrorCode rval = mMB->tag_get_data( tag, old_handles, (new_handles.empty())?NULL:&new_handles[0] );
345   CHKERR;
346 
347   Range::const_iterator it1 = old_handles.begin();
348   std::vector<EntityHandle>::iterator it2 = new_handles.begin();
349   for (;it1 != old_handles.end(); ++it1, ++it2)
350     if (0 == *it2)
351       *it2 = *it1;
352 
353   return MB_SUCCESS;
354 }
355 
get_reordered_handles(Tag tag,const std::vector<EntityHandle> & old_handles,std::vector<EntityHandle> & new_handles)356 ErrorCode ReorderTool::get_reordered_handles( Tag tag,
357                         const std::vector<EntityHandle>& old_handles,
358                         std::vector<EntityHandle>& new_handles )
359 {
360   new_handles.resize( old_handles.size() );
361   return get_reordered_handles( tag, &old_handles[0], &new_handles[0], old_handles.size() );
362 }
363 
get_reordered_handles(Tag tag,const EntityHandle * old_handles,EntityHandle * new_handles,size_t num_handles)364 ErrorCode ReorderTool::get_reordered_handles( Tag tag,
365                                         const EntityHandle* old_handles,
366                                         EntityHandle* new_handles,
367                                         size_t num_handles )
368 {
369   ErrorCode rval = mMB->tag_get_data( tag, old_handles, num_handles, new_handles );
370   CHKERR;
371 
372   for (size_t i = 0; i < num_handles; ++i)
373     if (0 == new_handles[i])
374       new_handles[i] = old_handles[i];
375 
376   return MB_SUCCESS;
377 }
378 
get_new_handles(Tag tag,Range & old_handles,std::vector<EntityHandle> & newhandles)379 ErrorCode ReorderTool::get_new_handles( Tag tag,
380                                         Range& old_handles,
381                                         std::vector<EntityHandle>& newhandles )
382 {
383     // get new handles for tagged entities
384   newhandles.resize(old_handles.size());
385   ErrorCode rval = mMB->tag_get_data( tag, old_handles, (newhandles.empty())?NULL:&newhandles[0] );
386   CHKERR;
387 
388     // remove entities that were not reordered
389   Range::iterator i = old_handles.begin();
390   size_t w = 0;
391   for (size_t r = 0; r < newhandles.size(); ++r) {
392     if (0 != newhandles[r]) {
393       newhandles[w] = newhandles[r];
394       ++w;
395       ++i;
396     }
397     else {
398       i = old_handles.erase(i);
399     }
400   }
401   newhandles.resize(w);
402   assert(newhandles.size() == old_handles.size());
403   return MB_SUCCESS;
404 }
405 
reorder_entities(Tag new_handles)406 ErrorCode ReorderTool::reorder_entities( Tag new_handles )
407 {
408   ErrorCode rval;
409 
410   rval = check_tag_type( mMB, new_handles, MB_TYPE_HANDLE, sizeof(EntityHandle) );
411   CHKERR;
412   EntityHandle defval;
413   rval = mMB->tag_get_default_value( new_handles, &defval );
414   CHKERR;
415   if (0 != defval)
416     return error(MB_INDEX_OUT_OF_RANGE);
417 
418     // Can only reorder within same type/connectivity (or vertex/num_coords)
419     // groupings.
420   for (EntityType t = MBVERTEX; t < MBENTITYSET; ++t) {
421       // Get list of all connectivity lengths (or vertex dimensions)
422       // that exist for type t.
423     TypeSequenceManager& seqs = mMB->sequence_manager()->entity_map(t);
424     TypeSequenceManager::iterator i;
425     std::set<int> values;
426     for (i = seqs.begin(); i != seqs.end(); ++i) {
427       EntitySequence* seq = *i;
428         // 0 values per entity implies structured data, which
429         // we cannot reorder.  Skip those.
430       if (t == MBVERTEX || 0 < seq->values_per_entity())
431         values.insert( seq->values_per_entity() );
432     }
433 
434       // reorder primary data for each (type,size) tuple.
435     std::set<int>::iterator j;
436     for (j = values.begin(); j != values.end(); ++j) {
437       Range entities;
438       get_entities( t, *j, entities );
439       std::vector<EntityHandle> handles;
440       rval = get_reordered_handles( new_handles, entities, handles );
441       UNRECOVERABLE(rval);
442 
443       if (t == MBVERTEX) {
444         std::vector<double> coords( entities.size() * 3 );
445         rval = mMB->get_coords( entities, &coords[0] );
446         UNRECOVERABLE(rval);
447         rval = mMB->set_coords( &handles[0], handles.size(), &coords[0] );
448         UNRECOVERABLE(rval);
449       }
450       else {
451         std::vector<EntityHandle> conn;
452         conn.reserve( entities.size() * *j );
453         std::vector<EntityHandle> old_handles;
454         old_handles.resize( entities.size() );
455         std::copy( entities.begin(), entities.end(), old_handles.begin() );
456         rval = mMB->get_connectivity( &old_handles[0], old_handles.size(),
457                                       conn, false );
458         UNRECOVERABLE(rval);
459         old_handles.clear();
460         old_handles = conn;
461         rval = get_reordered_handles( new_handles, old_handles, conn );
462         UNRECOVERABLE(rval);
463         for (unsigned int h = 0; h < handles.size(); ++h) {
464           rval = mMB->set_connectivity( handles[h], &conn[h * *j], *j );
465           UNRECOVERABLE(rval);
466         }
467       }
468     }
469   }
470 
471     // now update tag data
472   std::vector<Tag> tag_handles;
473   mMB->tag_get_tags( tag_handles );
474   for (size_t i = 0; i < tag_handles.size(); ++i) {
475     Tag tag = tag_handles[i];
476     if (tag == new_handles) // don't mess up mapping from old to new handles
477       continue;
478 
479     for (EntityType t = MBVERTEX; t <= MBENTITYSET; ++t) {
480       rval = reorder_tag_data( t, new_handles, tag );
481       UNRECOVERABLE(rval);
482     }
483   }
484 
485   rval = update_set_contents( new_handles );
486   UNRECOVERABLE(rval);
487 
488   return MB_SUCCESS;
489 }
490 
reorder_tag_data(EntityType etype,Tag new_handles,Tag tag)491 ErrorCode ReorderTool::reorder_tag_data( EntityType etype, Tag new_handles, Tag tag )
492 {
493   ErrorCode rval;
494 
495   int tagsize;
496   DataType tagtype;
497   rval = mMB->tag_get_data_type( tag, tagtype );
498   if (MB_SUCCESS != rval)
499     return error(rval);
500   if (MB_TYPE_BIT == tagtype)
501     tagsize = 1;
502   else {
503     rval = mMB->tag_get_bytes( tag, tagsize );
504     if (MB_VARIABLE_DATA_LENGTH == rval)
505       tagsize = -1;
506     else if (MB_SUCCESS != rval)
507       return error(rval);
508   }
509 
510     // we don't re-order set handles, so we don't care about sets
511     // unless the tag contains handles that need to be updated
512   if (MBENTITYSET == etype && MB_TYPE_HANDLE != tagtype)
513     return MB_SUCCESS;
514 
515     // get tagged entities
516   Range old_tagged;
517   rval = mMB->get_entities_by_type_and_tag( 0, etype, &tag, 0, 1, old_tagged );
518   if (MB_SUCCESS != rval && old_tagged.empty())
519     return error(rval);
520 
521     // remove entities that were not reordered, unless the tag
522     // is handle type in which case we need to update the data
523     // for all entities, regardless of reordering.
524   std::vector<EntityHandle> newhandles;
525   if (MB_TYPE_HANDLE == tagtype)
526     rval = get_reordered_handles( new_handles, old_tagged, newhandles );
527   else
528     rval = get_new_handles( new_handles, old_tagged, newhandles );
529   CHKERR;
530 
531   if (old_tagged.empty())
532     return MB_SUCCESS;
533 
534     // get copy of all tag data
535   std::vector<unsigned char> buffer;
536   std::vector<const void*> pointers;
537   std::vector<int> sizes;
538     // if variable-length tag
539   if (-1 == tagsize) {
540     pointers.resize(old_tagged.size());
541     sizes.resize(pointers.size());
542     rval = mMB->tag_get_by_ptr( tag, old_tagged, &pointers[0], &sizes[0] );
543     CHKERR;
544     int total = std::accumulate( sizes.begin(), sizes.end(), 0 );
545     DataType dtype;
546     mMB->tag_get_data_type( tag, dtype );
547     int type_size;
548     switch (dtype) {
549       case MB_TYPE_INTEGER: type_size = sizeof(int);  break;
550       case MB_TYPE_DOUBLE:  type_size = sizeof(double); break;
551       case MB_TYPE_HANDLE:  type_size = sizeof(EntityHandle); break;
552       case MB_TYPE_BIT:     type_size = 1; break;
553       case MB_TYPE_OPAQUE:  type_size = 1; break;
554       default:              return MB_TYPE_OUT_OF_RANGE;
555     }
556     buffer.resize( total*type_size );
557     size_t off = 0;
558     for (size_t j = 0; j < pointers.size(); ++j) {
559       memcpy( &buffer[off], pointers[j], type_size*sizes[j] );
560       pointers[j] = &buffer[off];
561       off += sizes[j] * type_size;
562     }
563   }
564     // if fixed-length tag
565   else {
566     buffer.resize( old_tagged.size() * tagsize );
567     rval = mMB->tag_get_data( tag, old_tagged, &buffer[0] );
568     CHKERR;
569   }
570 
571     // if handle tag, update tag values for reordered handles
572   if (MB_TYPE_HANDLE == tagtype) {
573     assert(!(buffer.size() % sizeof(EntityHandle)));
574     std::vector<unsigned char> buffer2(buffer.size());
575     rval = get_reordered_handles( new_handles,
576                  reinterpret_cast<const EntityHandle*>(&buffer[0]),
577                  reinterpret_cast<EntityHandle*>(&buffer2[0]),
578                  buffer.size() / sizeof(EntityHandle) );
579     CHKERR;
580       // if var-length tag then do not do swap because pointers[] contains pointers
581       // into old buffer
582     if (-1 == tagsize)
583       memcpy( &buffer[0], &buffer2[0], buffer.size() );
584     else
585       buffer.swap(buffer2);
586   }
587 
588     // store re-ordered tag data
589   if (-1 == tagsize) {
590     rval = mMB->tag_set_by_ptr( tag, &newhandles[0], newhandles.size(), &pointers[0], &sizes[0] );
591     pointers.clear();
592     sizes.clear();
593     buffer.clear();
594   }
595   else {
596     rval = mMB->tag_set_data( tag, &newhandles[0], newhandles.size(), &buffer[0] );
597     buffer.clear();
598   }
599   CHKERR;
600 
601     // all permutations should be cyclical, but not all permuted
602     // entities necessarily had tag values, so we might need to delete
603     // tags for some entities
604   std::sort( newhandles.begin(), newhandles.end() );
605   std::vector<EntityHandle>::iterator k = newhandles.begin();
606   Range::iterator i = old_tagged.begin();
607   while (i != old_tagged.end()) {
608     while (k != newhandles.end() && *k < *i)
609       ++k;
610     if (k == newhandles.end())
611       break;
612 
613     if (*i == *k) // what old_tagged -= newhandles
614       i = old_tagged.erase( i );
615     else
616       ++i;
617   }
618 
619   if (!old_tagged.empty()) {
620     rval = mMB->tag_delete_data( tag, old_tagged );
621     CHKERR;
622   }
623 
624   return MB_SUCCESS;
625 }
626 
update_set_contents(Tag nh_tag)627 ErrorCode ReorderTool::update_set_contents( Tag nh_tag )
628 {
629   Range sets;
630   ErrorCode rval = mMB->get_entities_by_type( 0, MBENTITYSET, sets );
631   CHKERR;
632 
633   std::vector<EntityHandle> old_handles, new_handles;
634   for (Range::iterator i = sets.begin(); i != sets.end(); ++i) {
635       // If set is un-ordered...
636     unsigned opts = 0;
637     mMB->get_meshset_options( *i, opts );
638     if (!(opts & MESHSET_ORDERED)) {
639       Range contents;
640       rval = mMB->get_entities_by_handle( *i, contents );
641       CHKERR;
642 
643       rval = get_new_handles( nh_tag, contents, new_handles );
644       CHKERR;
645 
646       Range replace;
647       std::sort( new_handles.begin(), new_handles.end() );
648       Range::iterator hint = replace.begin();
649       for (size_t j = 0; j < new_handles.size(); ++j)
650         hint = replace.insert( hint, new_handles[j] );
651       Range common = intersect(contents,replace);
652       contents -= common;
653       replace -= common;
654       assert(contents.size() == replace.size());
655       if (!contents.empty()) {
656         rval = mMB->remove_entities( *i, contents );
657         CHKERR;
658         rval = mMB->add_entities( *i, replace );
659       }
660     }
661 
662       // If set is ordered...
663     else {
664         // get set contents
665       old_handles.clear();
666       rval = mMB->get_entities_by_handle( *i, old_handles );
667       CHKERR;
668 
669         // get new handles from old contained handles
670       rval = get_reordered_handles( nh_tag, old_handles, new_handles );
671       CHKERR;
672 
673       rval = mMB->clear_meshset( &*i, 1 );
674       CHKERR;
675 
676       rval = mMB->add_entities( *i, &new_handles[0], new_handles.size() );
677       CHKERR;
678     }
679   } // for each set
680 
681   return MB_SUCCESS;
682 }
683 
684 } // namespace moab
685