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