root/MOAB/trunk/parallel/MBParallelComm.cpp @ 2809

Revision 2809, 166.0 KB (checked in by kraftche, 8 months ago)

fix buffer overflow

Line 
1#include "MBInterface.hpp"
2#include "MBParallelComm.hpp"
3#include "MBWriteUtilIface.hpp"
4#include "MBReadUtilIface.hpp"
5#include "SequenceManager.hpp"
6#include "EntitySequence.hpp"
7#include "TagServer.hpp"
8#include "MBTagConventions.hpp"
9#include "MBSkinner.hpp"
10#include "MBParallelConventions.h"
11#include "MBCore.hpp"
12#include "MBError.hpp"
13#include "ElementSequence.hpp"
14#include "MBCN.hpp"
15#include "RangeMap.hpp"
16
17#include <iostream>
18#include <algorithm>
19#include <numeric>
20
21#define MIN(a,b) (a < b ? a : b)
22#define MAX(a,b) (a > b ? a : b)
23const bool debug = false;
24const bool debug_packing = false;
25
26#include <math.h>
27#include <assert.h>
28
29
30extern "C" 
31{
32#include "minmax.h"
33#include "gs.h"
34#include "errmem.h"
35#include "types.h"
36#include "sort.h"
37#include "tuple_list.h"
38}
39
40#ifdef USE_MPI
41#include "mpi.h"
42#endif
43
44#define INITIAL_BUFF_SIZE 1024
45
46//#define DEBUG_PACKING 1
47#ifdef DEBUG_PACKING
48unsigned int __PACK_num = 0, __UNPACK_num = 0, __PACK_count = 0, __UNPACK_count = 0;
49std::string __PACK_string, __UNPACK_string;
50
51#define PC(n, m) {\
52          if (__PACK_num == (unsigned int)n && __PACK_string == m) __PACK_count++;\
53          else {\
54            if (__PACK_count > 1) std::cerr << " (" << __PACK_count << "x)";\
55            __PACK_count = 1; __PACK_string = m; __PACK_num = n;\
56            std::cerr << std::endl << "PACK: " << n << m;\
57          }}
58#define UPC(n, m) {\
59          if (__UNPACK_num == (unsigned int)n && __UNPACK_string == m) __UNPACK_count++;\
60          else {\
61            if (__UNPACK_count > 1) std::cerr << "(" << __UNPACK_count << "x)";\
62            __UNPACK_count = 1; __UNPACK_string = m; __UNPACK_num = n;\
63            std::cerr << std::endl << "UNPACK: " << n << m;\
64          }}
65#else
66#define PC(n, m)
67#define UPC(n, m)
68#endif
69
70#define PACK_INT(buff, int_val) {int tmp_val = int_val; PACK_INTS(buff, &tmp_val, 1);}
71
72#define PACK_INTS(buff, int_val, num) {memcpy(buff, int_val, (num)*sizeof(int)); buff += (num)*sizeof(int); PC(num, " ints");}
73
74#define PACK_DBL(buff, dbl_val, num) {memcpy(buff, dbl_val, (num)*sizeof(double)); buff += (num)*sizeof(double); PC(num, " doubles");}
75
76#define PACK_EH(buff, eh_val, num) {memcpy(buff, eh_val, (num)*sizeof(MBEntityHandle)); buff += (num)*sizeof(MBEntityHandle); PC(num, " handles");}
77
78#define PACK_CHAR_64(buff, char_val) {strcpy((char*)buff, char_val); buff += 64; PC(64, " chars");}
79
80#define PACK_VOID(buff, val, num) {memcpy(buff, val, num); buff += num; PC(num, " void");}
81
82#define PACK_BYTES(buff, val, num) PACK_INT(buff, num) PACK_VOID(buff, val, num)
83
84#define PACK_RANGE(buff, rng) {int num_subs = num_subranges(rng); PACK_INTS(buff, &num_subs, 1); PC(num_subs, "-subranged range"); \
85          for (MBRange::const_pair_iterator cit = rng.const_pair_begin(); cit != rng.const_pair_end(); cit++) { \
86            MBEntityHandle eh = (*cit).first; PACK_EH(buff, &eh, 1); \
87            eh = (*cit).second; PACK_EH(buff, &eh, 1);}; }
88
89#define UNPACK_INT(buff, int_val) {UNPACK_INTS(buff, &int_val, 1);}
90
91#define UNPACK_INTS(buff, int_val, num) {memcpy(int_val, buff, (num)*sizeof(int)); buff += (num)*sizeof(int); UPC(num, " ints");}
92
93#define UNPACK_DBL(buff, dbl_val, num) {memcpy(dbl_val, buff, (num)*sizeof(double)); buff += (num)*sizeof(double); UPC(num, " doubles");}
94
95#define UNPACK_EH(buff, eh_val, num) {memcpy(eh_val, buff, (num)*sizeof(MBEntityHandle)); buff += (num)*sizeof(MBEntityHandle); UPC(num, " handles");}
96
97#define UNPACK_CHAR_64(buff, char_val) {strcpy(char_val, (char*)buff); buff += 64; UPC(64, " chars");}
98
99#define UNPACK_VOID(buff, val, num) {memcpy(val, buff, num); buff += num; UPC(num, " void");}
100
101#define UNPACK_RANGE(buff, rng) {int num_subs; UNPACK_INTS(buff, &num_subs, 1); UPC(num_subs, "-subranged range"); MBEntityHandle _eh[2]; \
102          for (int i = 0; i < num_subs; i++) { UNPACK_EH(buff, _eh, 2); rng.insert(_eh[0], _eh[1]);}}
103
104#define RR(a) if (MB_SUCCESS != result) {\
105          dynamic_cast<MBCore*>(mbImpl)->get_error_handler()->set_last_error(a);\
106          return result;}
107
108#define RRA(a) if (MB_SUCCESS != result) {\
109      std::string tmp_str; mbImpl->get_last_error(tmp_str);\
110      tmp_str.append("\n"); tmp_str.append(a);\
111      dynamic_cast<MBCore*>(mbImpl)->get_error_handler()->set_last_error(tmp_str.c_str()); \
112      return result;}
113
114/** Name of tag used to store MBParallelComm Index on mesh paritioning sets */
115const char* PARTITIONING_PCOMM_TAG_NAME = "__PRTN_PCOMM";
116 
117/** \brief Tag storing parallel communication objects
118 *
119 * This tag stores pointers to MBParallelComm communication
120 * objects; one of these is allocated for each different
121 * communicator used to read mesh.  MBParallelComm stores
122 * partition and interface sets corresponding to its parallel mesh.
123 * By default, a parallel read uses the first MBParallelComm object
124 * on the interface instance; if instantiated with one, ReadParallel
125 * adds this object to the interface instance too.
126 *
127 * Tag type: opaque
128 * Tag size: MAX_SHARING_PROCS*sizeof(MBParallelComm*)
129 */
130#define PARALLEL_COMM_TAG_NAME "__PARALLEL_COMM"
131
132
133enum MBMessageTag {MB_MESG_ANY=MPI_ANY_TAG, 
134                   MB_MESG_SIZE,
135                   MB_MESG_ENTS,
136                   MB_MESG_REMOTE_HANDLES_RANGE,
137                   MB_MESG_REMOTE_HANDLES_VECTOR,
138                   MB_MESG_TAGS };
139   
140MBParallelComm::MBParallelComm(MBInterface *impl, MPI_Comm comm, int* id ) 
141    : mbImpl(impl), procConfig(comm), sharedpTag(0), sharedpsTag(0),
142      sharedhTag(0), sharedhsTag(0), pstatusTag(0), ifaceSetsTag(0),
143      partitionTag(0), globalPartCount(-1), partitioningSet(0)
144{
145  myBuffer.resize(INITIAL_BUFF_SIZE);
146
147  tagServer = dynamic_cast<MBCore*>(mbImpl)->tag_server();
148  sequenceManager = dynamic_cast<MBCore*>(mbImpl)->sequence_manager();
149
150  int flag = 1;
151  int retval = MPI_Initialized(&flag);
152  if (MPI_SUCCESS != retval || !flag) {
153    int argc = 0;
154    char **argv = NULL;
155   
156      // mpi not initialized yet - initialize here
157    retval = MPI_Init(&argc, &argv);
158  }
159
160  pcommID = add_pcomm(this);
161  if (id)
162    *id = pcommID;
163}
164
165MBParallelComm::MBParallelComm(MBInterface *impl,
166                               std::vector<unsigned char> &tmp_buff, 
167                               MPI_Comm comm,
168                               int* id) 
169    : mbImpl(impl), procConfig(comm), sharedpTag(0), sharedpsTag(0),
170      sharedhTag(0), sharedhsTag(0), pstatusTag(0), ifaceSetsTag(0),
171      partitionTag(0), globalPartCount(-1), partitioningSet(0)
172{
173  myBuffer.swap(tmp_buff);
174  int flag = 1;
175  int retval = MPI_Initialized(&flag);
176  if (MPI_SUCCESS != retval || !flag) {
177    int argc = 0;
178    char **argv = NULL;
179   
180      // mpi not initialized yet - initialize here
181    retval = MPI_Init(&argc, &argv);
182  }
183
184  pcommID = add_pcomm(this);
185  if (id)
186    *id = pcommID;
187}
188
189MBParallelComm::~MBParallelComm() 
190{
191  remove_pcomm(this);
192}
193
194int MBParallelComm::add_pcomm(MBParallelComm *pc) 
195{
196    // add this pcomm to instance tag
197  std::vector<MBParallelComm *> pc_array(MAX_SHARING_PROCS, 
198                                         (MBParallelComm*)NULL);
199  MBTag pc_tag = pcomm_tag(mbImpl, true);
200  assert(0 != pc_tag);
201 
202  MBErrorCode result = mbImpl->tag_get_data(pc_tag, 0, 0, (void*)&pc_array[0]);
203  if (MB_SUCCESS != result && MB_TAG_NOT_FOUND != result) 
204    return -1;
205  int index = 0;
206  while (index < MAX_SHARING_PROCS && pc_array[index]) index++;
207  if (index == MAX_SHARING_PROCS) {
208    index = -1;
209    assert(false);
210  }
211  else {
212    pc_array[index] = pc;
213    mbImpl->tag_set_data(pc_tag, 0, 0, (void*)&pc_array[0]);
214  }
215  return index;
216}
217
218void MBParallelComm::remove_pcomm(MBParallelComm *pc) 
219{
220    // remove this pcomm from instance tag
221  std::vector<MBParallelComm *> pc_array(MAX_SHARING_PROCS);
222  MBTag pc_tag = pcomm_tag(mbImpl, true);
223 
224  MBErrorCode result = mbImpl->tag_get_data(pc_tag, 0, 0, (void*)&pc_array[0]);
225  std::vector<MBParallelComm*>::iterator pc_it = 
226    std::find(pc_array.begin(), pc_array.end(), pc);
227  assert(MB_SUCCESS == result && 
228         pc_it != pc_array.end());
229  *pc_it = NULL;
230  mbImpl->tag_set_data(pc_tag, 0, 0, (void*)&pc_array[0]);
231}
232
233//! assign a global id space, for largest-dimension or all entities (and
234//! in either case for vertices too)
235MBErrorCode MBParallelComm::assign_global_ids(MBEntityHandle this_set,
236                                              const int dimension, 
237                                              const int start_id,
238                                              const bool largest_dim_only,
239                                              const bool parallel) 
240{
241  MBRange entities[4];
242  int local_num_elements[4];
243  MBErrorCode result;
244  std::vector<unsigned char> pstatus;
245  for (int dim = 0; dim <= dimension; dim++) {
246    if (dim == 0 || !largest_dim_only || dim == dimension) {
247      result = mbImpl->get_entities_by_dimension(this_set, dim, entities[dim]); 
248      RRA("Failed to get vertices in assign_global_ids.");
249    }
250
251      // need to filter out non-locally-owned entities!!!
252    pstatus.resize(entities[dim].size());
253    result = mbImpl->tag_get_data(pstatus_tag(), entities[dim], &pstatus[0]);
254    RRA("Failed to get pstatus in assign_global_ids.");
255   
256    MBRange dum_range;
257    MBRange::iterator rit;
258    unsigned int i;
259    for (rit = entities[dim].begin(), i = 0; rit != entities[dim].end(); rit++, i++)
260      if (pstatus[i] & PSTATUS_NOT_OWNED)
261        dum_range.insert(*rit);
262    entities[dim] = entities[dim].subtract(dum_range);
263   
264    local_num_elements[dim] = entities[dim].size();
265  }
266 
267    // communicate numbers
268  std::vector<int> num_elements(procConfig.proc_size()*4);
269#ifdef USE_MPI
270  if (procConfig.proc_size() > 1 && parallel) {
271    int retval = MPI_Alltoall(local_num_elements, 4, MPI_INT,
272                              &num_elements[0], procConfig.proc_size()*4, 
273                              MPI_INT, procConfig.proc_comm());
274    if (0 != retval) return MB_FAILURE;
275  }
276  else
277#endif
278    for (int dim = 0; dim < 4; dim++) num_elements[dim] = local_num_elements[dim];
279 
280    // my entities start at one greater than total_elems[d]
281  int total_elems[4] = {start_id, start_id, start_id, start_id};
282 
283  for (unsigned int proc = 0; proc < procConfig.proc_rank(); proc++) {
284    for (int dim = 0; dim < 4; dim++) total_elems[dim] += num_elements[4*proc + dim];
285  }
286 
287    //assign global ids now
288  MBTag gid_tag;
289  int zero = 0;
290  result = mbImpl->tag_create(GLOBAL_ID_TAG_NAME, sizeof(int), 
291                              MB_TAG_DENSE, MB_TYPE_INTEGER, gid_tag,
292                              &zero, true);
293  if (MB_SUCCESS != result && MB_ALREADY_ALLOCATED != result) return result;
294 
295  for (int dim = 0; dim < 4; dim++) {
296    if (entities[dim].empty()) continue;
297    num_elements.resize(entities[dim].size());
298    int i = 0;
299    for (MBRange::iterator rit = entities[dim].begin(); rit != entities[dim].end(); rit++)
300      num_elements[i++] = total_elems[dim]++;
301   
302    result = mbImpl->tag_set_data(gid_tag, entities[dim], &num_elements[0]); 
303    RRA("Failed to set global id tag in assign_global_ids.");
304  }
305 
306  return MB_SUCCESS;
307}
308
309MBErrorCode MBParallelComm::send_entities(const int to_proc,
310                                          MBRange &orig_ents,
311                                          const bool adjs,
312                                          const bool tags,
313                                          const bool store_remote_handles,
314                                          MBRange &final_ents,
315                                          bool wait_all) 
316{
317
318    // find a spot in the proc buffers vector
319  int index = get_buffers(to_proc);
320 
321    // pack/send the entities to the destination
322  MPI_Request req_vec[2] = {MPI_REQUEST_NULL,  // send req (ownerSBuff)
323                             MPI_REQUEST_NULL}; // recv req (remote handles)
324  MBErrorCode result = pack_send_entities(to_proc, orig_ents, 
325                                          adjs, tags, store_remote_handles, false,
326                                          ownerSBuffs[index], ownerRBuffs[index],
327                                          req_vec[0], req_vec[1], final_ents);
328  RRA("Failed to pack-send entities.");
329
330  MPI_Status statuses[2];
331
332    // if we're storing remote handles, process the return message
333  if (store_remote_handles) {
334    assert(MPI_REQUEST_NULL != req_vec[1]);
335    MPI_Wait(&req_vec[1], &statuses[1]);
336    MBRange remote_range;
337    unsigned char *buff_ptr = &ownerRBuffs[index][0];
338    UNPACK_RANGE(buff_ptr, remote_range);
339    result = set_remote_data(final_ents, remote_range, to_proc);
340    RRA("Trouble setting remote data range on sent entities.");
341  }
342
343  if (wait_all) {
344      // wait for all to finish
345    int success = MPI_Waitall(2, req_vec, statuses);
346    if (success != MPI_SUCCESS) {
347      result = MB_FAILURE;
348      RRA("Failed in waitall in send_entities.");
349    }
350  }
351 
352  return MB_SUCCESS;
353}
354
355MBErrorCode MBParallelComm::recv_entities(const int from_proc,
356                                          const bool store_remote_handles,
357                                          MBRange &final_ents,
358                                          bool wait_all) 
359{
360  MBErrorCode result;
361 
362    // find a spot in the proc buffers vector
363  int index = get_buffers(from_proc);
364 
365    // recv/unpack entities from the sender
366  MPI_Request req = MPI_REQUEST_NULL;
367  MPI_Status status;
368  int success = MPI_Recv(&ghostRBuffs[index][0], ghostRBuffs[index].size(), 
369                         MPI_UNSIGNED_CHAR, from_proc, 
370                         MB_MESG_ANY, procConfig.proc_comm(), 
371                         &status);
372  if (MPI_SUCCESS != success) {
373    result = MB_FAILURE;
374    RRA("Recv failed in recv_ents.");
375  }
376
377    // check type, and if it's just the size, resize buffer and re-call recv
378  if (MB_MESG_SIZE == status.MPI_TAG) {
379    result = recv_size_buff(from_proc,
380                            ghostRBuffs[index],
381                            req, MB_MESG_ANY);
382    RRA("Failed to resize recv buffer.");
383    MPI_Wait(&req, &status);
384  }
385 
386    // ok, got the actual entities, now unpack
387  result = recv_unpack_entities(from_proc, store_remote_handles, false,
388                                ghostRBuffs[index], ghostSBuffs[index], 
389                                req, final_ents);
390  RRA("Failed to recv-unpack message.");
391
392  if (wait_all) {
393      // wait for last message to finish
394    int success = MPI_Wait(&req, &status);
395    if (success != MPI_SUCCESS) {
396      result = MB_FAILURE;
397      RRA("Failed in wait in recv_entities.");
398    }
399  }
400
401  return result;
402}
403
404int MBParallelComm::get_buffers(int to_proc) 
405{
406  int ind = -1;
407  std::vector<int>::iterator vit = 
408    std::find(buffProcs.begin(), buffProcs.end(), to_proc);
409  if (vit == buffProcs.end()) {
410    ind = buffProcs.size();
411    buffProcs.push_back(to_proc);
412    ownerSBuffs[ind].resize(INITIAL_BUFF_SIZE);
413    ghostRBuffs[ind].resize(INITIAL_BUFF_SIZE);
414      // allocate these other buffs in case we're storing remote handles
415    ownerRBuffs[ind].resize(INITIAL_BUFF_SIZE);
416    ghostSBuffs[ind].resize(INITIAL_BUFF_SIZE);
417     
418  }
419  else ind = vit - buffProcs.begin();
420  assert(ind < MAX_SHARING_PROCS);
421  return ind;
422}
423
424MBErrorCode MBParallelComm::pack_send_entities(const int to_proc,
425                                               MBRange &orig_ents,
426                                               const bool adjacencies,
427                                               const bool tags,
428                                               const bool store_remote_handles,
429                                               const bool iface_layer,
430                                               std::vector<unsigned char> &send_buff,
431                                               std::vector<unsigned char> &recv_buff,
432                                               MPI_Request &send_req,
433                                               MPI_Request &recv_req,
434                                               MBRange &final_ents) 
435{
436#ifndef USE_MPI
437  return MB_FAILURE;
438#else
439
440  MBErrorCode result = MB_SUCCESS;
441  MBRange whole_range;
442  int buff_size;
443   
444  result = pack_buffer(orig_ents, adjacencies, tags, 
445                       store_remote_handles, iface_layer, to_proc,
446                       final_ents, send_buff, buff_size); 
447  RRA("Failed to pack buffer in pack_send.");
448
449    // now that we know how many entities, post a receive for the
450    // remote range, if requested
451  int success;
452  if (store_remote_handles && iface_layer) {
453    recv_buff.resize(final_ents.size()*sizeof(MBEntityHandle) + sizeof(int));
454   
455    success = MPI_Irecv(&recv_buff[0], recv_buff.size(), MPI_UNSIGNED_CHAR, to_proc, 
456                        MB_MESG_REMOTE_HANDLES_VECTOR, procConfig.proc_comm(), 
457                        &recv_req);
458    if (success != MPI_SUCCESS) return MB_FAILURE;
459  }
460  else if (store_remote_handles && !iface_layer) {
461    recv_buff.resize(2*num_subranges(final_ents)*sizeof(MBEntityHandle) + sizeof(int));
462   
463    success = MPI_Irecv(&recv_buff[0], recv_buff.size(), MPI_UNSIGNED_CHAR, to_proc, 
464                        MB_MESG_REMOTE_HANDLES_RANGE, procConfig.proc_comm(), 
465                        &recv_req);
466    if (success != MPI_SUCCESS) return MB_FAILURE;
467  }
468
469    // if the message is large, send a first message to tell how large
470  if (INITIAL_BUFF_SIZE < buff_size) {
471    int tmp_buff_size = -buff_size;
472    int success = MPI_Send(&tmp_buff_size, sizeof(int), MPI_UNSIGNED_CHAR, 
473                           to_proc, MB_MESG_SIZE, procConfig.proc_comm());
474    if (success != MPI_SUCCESS) return MB_FAILURE;
475  }
476   
477    // send the buffer
478  success = MPI_Isend(&send_buff[0], buff_size, MPI_UNSIGNED_CHAR, to_proc, 
479                      MB_MESG_ENTS, procConfig.proc_comm(), &send_req);
480  if (success != MPI_SUCCESS) return MB_FAILURE;
481
482  return result;
483#endif
484}
485
486MBErrorCode MBParallelComm::recv_size_buff(const int from_proc,
487                                           std::vector<unsigned char> &recv_buff,
488                                           MPI_Request &recv_req,
489                                           int mesg_tag) 
490{
491    // use the received size to resize buffer, then post another irecv
492  recv_buff.resize(-(*((int*)&recv_buff[0])));
493  int success = MPI_Irecv(&recv_buff[0], recv_buff.size(), MPI_UNSIGNED_CHAR, from_proc, 
494                          mesg_tag, procConfig.proc_comm(), &recv_req);
495  if (MPI_SUCCESS != success) {
496    MBErrorCode result = MB_FAILURE;
497    RRA("Failed call to Irecv in recv_size_buff.");
498  }
499 
500  return MB_SUCCESS;
501}
502 
503MBErrorCode MBParallelComm::recv_unpack_entities(const int from_proc,
504                                                 const bool store_remote_handles,
505                                                 const bool iface_layer,
506                                                 std::vector<unsigned char> &recv_buff,
507                                                 std::vector<unsigned char> &send_buff,
508                                                 MPI_Request &send_req,
509                                                 MBRange &recd_ents)
510{
511#ifndef USE_MPI
512  return MB_FAILURE;
513#else
514
515  MBErrorCode result = MB_SUCCESS;
516 
517    // unpack the buffer
518  if (iface_layer) {
519    std::vector<MBEntityHandle> recd_ents_tmp;
520    unsigned char *buff_ptr = &recv_buff[0];
521    result = unpack_iface_entities(buff_ptr, from_proc, recd_ents_tmp);
522    RRA("Failed to unpack buffer in recv_unpack.");
523    if (store_remote_handles) {
524      int recd_size = recd_ents_tmp.size()*sizeof(MBEntityHandle) +
525          sizeof(int);
526      send_buff.resize(recd_size);
527      unsigned char *buff_ptr = &send_buff[0];
528      PACK_INT(buff_ptr, recd_ents_tmp.size());
529      PACK_EH(buff_ptr, &recd_ents_tmp[0], recd_ents_tmp.size());
530      int success = MPI_Isend(&send_buff[0], recd_size, MPI_UNSIGNED_CHAR, from_proc, 
531                              MB_MESG_REMOTE_HANDLES_VECTOR, procConfig.proc_comm(), &send_req);
532      if (success != MPI_SUCCESS) {
533        result = MB_FAILURE;
534        RRA("Failed to send handles in recv_unpack.");
535      }
536    }
537    std::copy(recd_ents_tmp.begin(), recd_ents_tmp.end(), mb_range_inserter(recd_ents));
538  }
539  else {
540    result = unpack_buffer(&recv_buff[0], store_remote_handles, from_proc, recd_ents); 
541    RRA("Failed to unpack buffer in recv_unpack.");
542    if (store_remote_handles) {
543      int recd_size = 2*num_subranges(recd_ents)*sizeof(MBEntityHandle) + sizeof(int);
544      send_buff.resize(recd_size);
545      unsigned char *buff_ptr = &send_buff[0];
546      PACK_RANGE(buff_ptr, recd_ents);
547      int success = MPI_Isend(&send_buff[0], recd_size, MPI_UNSIGNED_CHAR, from_proc, 
548                          MB_MESG_REMOTE_HANDLES_RANGE, procConfig.proc_comm(), &send_req);
549      if (success != MPI_SUCCESS) {
550        result = MB_FAILURE;
551        RRA("Failed to send handles in recv_unpack.");
552      }
553    }
554  }
555
556  return result;
557#endif
558}
559
560MBErrorCode MBParallelComm::broadcast_entities( const int from_proc,
561                                                MBRange &entities,
562                                                const bool adjacencies,
563                                                const bool tags) 
564{
565#ifndef USE_MPI
566  return MB_FAILURE;
567#else
568 
569  MBErrorCode result = MB_SUCCESS;
570  int success;
571  MBRange whole_range;
572  int buff_size;
573 
574  std::vector<unsigned char> buff;
575  if ((int)procConfig.proc_rank() == from_proc) {
576    result = pack_buffer( entities, adjacencies, tags, 
577                          false, false, -1,
578                          whole_range, buff, buff_size); 
579    RRA("Failed to compute buffer size in broadcast_entities.");
580  }
581
582  success = MPI_Bcast( &buff_size, 1, MPI_INT, from_proc, procConfig.proc_comm() );
583  if (MPI_SUCCESS != success) {
584    result = MB_FAILURE;
585    RRA("MPI_Bcast of buffer size failed.");
586  }
587 
588  if (!buff_size) // no data
589    return MB_SUCCESS;
590
591  if ((int)procConfig.proc_rank() != from_proc) 
592    buff.resize(buff_size);
593
594  success = MPI_Bcast( &buff[0], buff_size, MPI_UNSIGNED_CHAR, from_proc, procConfig.proc_comm() );
595  if (MPI_SUCCESS != success) {
596    result = MB_FAILURE;
597    RRA("MPI_Bcast of buffer failed.");
598  }
599
600  if ((int)procConfig.proc_rank() != from_proc) {
601    result = unpack_buffer(&buff[0], false, from_proc, entities);
602    RRA("Failed to unpack buffer in broadcast_entities.");
603  }
604
605  return MB_SUCCESS;
606#endif
607}
608
609MBErrorCode MBParallelComm::pack_buffer(MBRange &orig_ents, 
610                                        const bool adjacencies,
611                                        const bool tags,
612                                        const bool store_remote_handles,
613                                        const bool iface_layer,
614                                        const int to_proc,
615                                        MBRange &final_ents,
616                                        std::vector<unsigned char> &buff,
617                                        int &buff_size) 
618{
619    // pack the buffer with the entity ranges, adjacencies, and tags sections
620    //
621    // Note: new entities used in subsequent connectivity lists, sets, or tags,
622    //   are referred to as (MBMAXTYPE + index), where index is into vector
623    //   of new entities, 0-based
624    //
625    // DATA LAYOUT IN BUFFER:
626    // . w/ handles ? (0-no, 1-yes, range, 2-yes, vector)
627    // ENTITIES:
628    // . for all types:
629    //   - ent_type -- end of data indicated by ent_type == MBMAXTYPE
630    //   - range(ent type) -- #ents = range.size()
631    //   - if (ent_type == MBVERTEX) xxx[#ents], yyy[#ents], zzz[#ents]
632    //   - else {
633    //     . nodes_per_ent
634    //     . connect[#ents * nodes_per_ent]
635    //   - }
636    //   - if (handles) range/vector of remote handles
637    // SETS:
638    // . range of set handles -- (#sets = range.size())
639    // . options[#sets] (unsigned int)
640    // . if (unordered) set range
641    // . else if ordered
642    //   - #ents in set
643    //   - handles[#ents]
644    // . #parents
645    // . if (#parents) handles[#parents]
646    // . #children
647    // . if (#children) handles[#children]
648    // ADJACENCIES:
649    // (no adjs for now)
650    // TAGS:
651    // . #tags
652    // . for each tag
653    //   - tag size
654    //   - tag type
655    //   - data type
656    //   - if (default value)
657    //     . 1
658    //     . default value
659    //   - else
660    //     . 0
661    //   - name (null-terminated string, in char[64])
662    //   - range (size = #ents)
663    //   - tag_vals[#ents]
664
665  MBErrorCode result;
666
667  std::vector<MBEntityType> ent_types;
668  std::vector<MBRange> all_ranges;
669  std::vector<int> verts_per_entity;
670  MBRange set_range;
671  std::vector<MBRange> set_ranges;
672  std::vector<MBTag> all_tags;
673  std::vector<MBRange> tag_ranges;
674  std::vector<int> set_sizes;
675  std::vector<unsigned int> options_vec;
676
677  buff_size = 0;
678  MBRange::const_iterator rit;
679 
680    //=================
681    // count first...
682    //=================
683
684  unsigned char *buff_ptr = NULL;
685 
686    // entities
687  result = pack_entities(orig_ents, rit, final_ents, buff_ptr,
688                         buff_size, true, store_remote_handles, 
689                         iface_layer, to_proc, ent_types, all_ranges, 
690                         verts_per_entity); 
691  RRA("Packing entities (count) failed.");
692 
693    // sets
694  result = pack_sets(orig_ents, rit, final_ents, buff_ptr, buff_size, true,
695                     store_remote_handles, to_proc, set_range, set_ranges,
696                     set_sizes, options_vec); 
697  RRA("Packing sets (count) failed.");
698 
699    // adjacencies
700  if (adjacencies) {
701    result = pack_adjacencies(orig_ents, rit, final_ents, buff_ptr, 
702                              buff_size, true,
703                              store_remote_handles, to_proc);
704    RRA("Packing adjs (count) failed.");
705  }
706   
707    // tags
708  if (tags) {
709    result = get_tag_send_list( final_ents, all_tags, tag_ranges );
710    RRA("Failed to get tagged entities.")
711    result = pack_tags(orig_ents, rit, final_ents, buff_ptr, 
712                       buff_size, true, store_remote_handles, to_proc, 
713                       all_tags, tag_ranges);
714    RRA("Packing tags (count) failed.");
715  }
716
717    //=================
718    // now do the real packing
719    //=================
720
721  assert(0 <= buff_size);
722  buff.resize(buff_size);
723  int orig_buff_size = buff_size;
724  buff_size = 0;
725  buff_ptr = &buff[0];
726 
727    // entities
728  result = pack_entities(orig_ents, rit, final_ents, buff_ptr,
729                         buff_size, false, store_remote_handles, 
730                         iface_layer, to_proc, ent_types, 
731                         all_ranges, verts_per_entity); 
732  RRA("Packing entities (real) failed.");
733#ifdef DEBUG_PACKING
734  std::cerr << "pack_entities buffer space: " << buff_ptr - &buff[0] << " bytes." << std::endl;
735  unsigned char *tmp_buff = buff_ptr;
736#endif 
737 
738    // sets
739  result = pack_sets(orig_ents, rit, final_ents, buff_ptr, buff_size, false,
740                     store_remote_handles, to_proc, set_range, set_ranges,
741                     set_sizes, options_vec); 
742  RRA("Packing sets (real) failed.");
743#ifdef DEBUG_PACKING
744  std::cerr << "pack_sets buffer space: " << buff_ptr - tmp_buff << " bytes." << std::endl;
745  tmp_buff = buff_ptr;
746#endif 
747 
748    // adjacencies
749  if (adjacencies) {
750    result = pack_adjacencies(orig_ents, rit, final_ents, buff_ptr, 
751                              buff_size, false,
752                              store_remote_handles, to_proc);
753    RRA("Packing adjs (real) failed.");
754  }
755   
756    // tags
757  if (tags) {
758    result = pack_tags(orig_ents, rit, final_ents, buff_ptr, 
759                       buff_size, false, store_remote_handles, to_proc, all_tags,
760                       tag_ranges);
761    RRA("Packing tags (real) failed.");
762#ifdef DEBUG_PACKING
763    std::cerr << "pack_tags buffer space: " << buff_ptr - tmp_buff << " bytes." << std::endl;
764    tmp_buff = buff_ptr;
765#endif 
766  }
767
768    // original buffer size might be larger, because some
769    // ranges of local handles pack into more compact ranges of
770    // remote handles (because they're expressed using MBMAXTYPE plus
771    // index in new entity range, and that list of entities is likely
772    // to be compact)
773  assert(orig_buff_size >= buff_size);
774
775  return result;
776}
777 
778MBErrorCode MBParallelComm::unpack_buffer(unsigned char *buff_ptr,
779                                          const bool store_remote_handles,
780                                          int from_proc,
781                                          MBRange &final_ents)
782{
783  if (myBuffer.capacity() == 0) return MB_FAILURE;
784 
785#ifdef DEBUG_PACKING
786    unsigned char *tmp_buff = buff_ptr;
787#endif 
788  MBErrorCode result = unpack_entities(buff_ptr, store_remote_handles,
789                                       from_proc, final_ents);
790  RRA("Unpacking entities failed.");
791#ifdef DEBUG_PACKING
792    std::cerr << "unpack_entities buffer space: " << buff_ptr - tmp_buff << " bytes." << std::endl;
793    tmp_buff = buff_ptr;
794#endif 
795  result = unpack_sets(buff_ptr, final_ents, store_remote_handles, 
796                       from_proc);
797  RRA("Unpacking sets failed.");
798#ifdef DEBUG_PACKING
799    std::cerr << "unpack_sets buffer space: " << buff_ptr - tmp_buff << " bytes." << std::endl;
800    tmp_buff = buff_ptr;
801#endif 
802  result = unpack_tags(buff_ptr, final_ents, store_remote_handles,
803                       from_proc);
804  RRA("Unpacking tags failed.");
805#ifdef DEBUG_PACKING
806    std::cerr << "unpack_tags buffer space: " << buff_ptr - tmp_buff << " bytes." << std::endl;
807    tmp_buff = buff_ptr;
808#endif 
809
810#ifdef DEBUG_PACKING
811  std::cerr << std::endl;
812#endif
813 
814  return MB_SUCCESS;
815}
816
817int MBParallelComm::num_subranges(const MBRange &this_range)
818{
819    // ok, have all the ranges we'll pack; count the subranges
820  int num_sub_ranges = 0;
821  for (MBRange::const_pair_iterator pit = this_range.const_pair_begin(); 
822       pit != this_range.const_pair_end(); pit++)
823    num_sub_ranges++;
824
825  return num_sub_ranges;
826}
827
828MBErrorCode MBParallelComm::pack_entities(MBRange &entities,
829                                          MBRange::const_iterator &start_rit,
830                                          MBRange &whole_range,
831                                          unsigned char *&buff_ptr,
832                                          int &count,
833                                          const bool just_count,
834                                          const bool store_remote_handles,
835                                          const bool iface_layer,
836                                          const int to_proc,
837                                          std::vector<MBEntityType> &ent_types, 
838                                          std::vector<MBRange> &all_ranges, 
839                                          std::vector<int> &verts_per_entity) 
840{
841    // (. w/ handles ? (0-no, 1-yes, range, 2-yes, vector))
842    // ENTITIES:
843    // . for all types:
844    //   - ent_type -- end of data indicated by ent_type == MBMAXTYPE
845    //   - #ents
846    //   - if (ent_type == MBVERTEX) xxx[#ents], yyy[#ents], zzz[#ents]
847    //   - else {
848    //     . nodes_per_ent
849    //     . connect[#ents * nodes_per_ent]
850    //   - }
851    //   - if (handles) range/vector of remote handles
852
853  unsigned char *orig_buff_ptr = buff_ptr;
854  MBErrorCode result;
855  MBWriteUtilIface *wu = NULL;
856  if (!just_count) {
857    result = mbImpl->query_interface(std::string("MBWriteUtilIface"), 
858                                     reinterpret_cast<void**>(&wu));
859    RRA("Couldn't get MBWriteUtilIface.");
860
861  }
862 
863    // pack vertices
864  if (just_count) {
865      // don't count size of verts until after all entities are included
866    ent_types.push_back(MBVERTEX);
867    verts_per_entity.push_back(1);
868    all_ranges.push_back(entities.subset_by_type(MBVERTEX));
869  }
870  else {
871    if (!all_ranges[0].empty()) {
872      PACK_INT(buff_ptr, ((int) MBVERTEX));
873      PACK_INT(buff_ptr, ((int) all_ranges[0].size()));
874      int num_verts = all_ranges[0].size();
875      std::vector<double*> coords(3);
876      for (int i = 0; i < 3; i++)
877        coords[i] = reinterpret_cast<double*>(buff_ptr + i * num_verts * sizeof(double));
878
879      assert(NULL != wu);
880   
881      result = wu->get_node_arrays(3, num_verts, all_ranges[0], 0, 0, coords);
882      RRA("Couldn't allocate node space.");
883      PC(3*num_verts, " doubles");
884
885      buff_ptr += 3 * num_verts * sizeof(double);
886
887      if (store_remote_handles)
888        PACK_RANGE(buff_ptr, all_ranges[0]);
889
890#ifdef DEBUG_PACKING
891      std::cerr << "Packed " << all_ranges[0].size() << " vertices." << std::endl;
892#endif     
893    }
894  }
895
896    // place an iterator at the first non-vertex entity
897  if (!all_ranges[0].empty()) {
898    start_rit = entities.find(*all_ranges[0].rbegin());
899    start_rit++;
900  }
901  else {
902    start_rit = entities.begin();
903  }
904 
905  MBRange::const_iterator end_rit = start_rit;
906  std::vector<MBRange>::iterator allr_it = all_ranges.begin();
907 
908    // pack entities
909  if (just_count) {   
910
911      // get all ranges of entities that have different #'s of vertices or different types
912    while (end_rit != entities.end() && TYPE_FROM_HANDLE(*start_rit) != MBENTITYSET) {
913
914        // get the sequence holding this entity
915      EntitySequence *seq;
916      ElementSequence *eseq;
917      result = sequenceManager->find(*start_rit, seq);
918      RRA("Couldn't find entity sequence.");
919
920      if (NULL == seq) return MB_FAILURE;
921      eseq = dynamic_cast<ElementSequence*>(seq);
922
923        // if type and nodes per element change, start a new range
924      if (eseq->type() != *ent_types.rbegin() || 
925          (int) eseq->nodes_per_element() != *verts_per_entity.rbegin()) {
926        ent_types.push_back(eseq->type());
927        verts_per_entity.push_back(eseq->nodes_per_element());
928        all_ranges.push_back(MBRange());
929        allr_it++;
930      }
931   
932        // get position in entities list one past end of this sequence
933      end_rit = entities.lower_bound(start_rit, entities.end(), eseq->end_handle()+1);
934
935        // put these entities in the last range
936      std::copy(start_rit, end_rit, mb_range_inserter(*all_ranges.rbegin()));
937
938        // remove any which are already shared
939      if (store_remote_handles && !iface_layer) {
940        result = remove_nonowned_shared(*all_ranges.rbegin(), to_proc, false);
941        RRA("Failed nonowned_shared test.");
942      }
943
944      whole_range.merge(*all_ranges.rbegin());
945     
946        // now start where we last left off
947      start_rit = end_rit;
948    }
949
950      // update vertex range to cover vertices included in other entities
951      // and remove entities already there
952    result = mbImpl->get_adjacencies(whole_range, 0, false, all_ranges[0], 
953                                     MBInterface::UNION);
954    RRA("Failed get_adjacencies.");
955
956    if (store_remote_handles) {
957      whole_range = whole_range.subtract(all_ranges[0]);
958      result = remove_nonowned_shared(all_ranges[0], to_proc, false);
959      RRA("Failed nonowned_shared test.");
960    }
961   
962      // count those data, now that we know which
963      // entities get communicated
964    whole_range.merge(all_ranges[0]);
965    count += 3 * sizeof(double) * all_ranges[0].size();
966   
967      // space for the ranges
968    std::vector<MBRange>::iterator vit = all_ranges.begin();
969    std::vector<int>::iterator iit = verts_per_entity.begin();
970    std::vector<MBEntityType>::iterator eit = ent_types.begin();
971    for (; vit != all_ranges.end(); vit++, iit++, eit++) {
972        // entity type of this range, but passed as int
973      count += sizeof(int);
974     
975        // number of entities
976      count += sizeof(int);
977
978        // nodes per entity
979      if (iit != verts_per_entity.begin()) count += sizeof(int);
980
981        // connectivity of subrange
982      if (iit != verts_per_entity.begin()) {
983        count += *iit * sizeof(MBEntityHandle)*(*vit).size();
984      }
985     
986        // remote handles, if desired
987      if (store_remote_handles)
988        count += sizeof(int) + 2*sizeof(MBEntityHandle)*num_subranges(*vit);
989    }
990
991      // extra entity type at end, passed as int
992    count += sizeof(int);
993  }
994  else {
995      // for each range beyond the first
996    allr_it++;
997    std::vector<int>::iterator nv_it = verts_per_entity.begin();
998    std::vector<MBEntityType>::iterator et_it = ent_types.begin();
999    std::vector<MBEntityHandle> dum_connect;
1000    nv_it++; et_it++;
1001   
1002    for (; allr_it != all_ranges.end(); allr_it++, nv_it++, et_it++) {
1003        // pack the entity type
1004      PACK_INT(buff_ptr, ((int)*et_it));
1005
1006        // pack # ents
1007      PACK_INT(buff_ptr, (*allr_it).size());
1008     
1009        // pack the nodes per entity
1010      PACK_INT(buff_ptr, *nv_it);
1011     
1012        // pack the connectivity
1013      const MBEntityHandle *connect;
1014      int num_connect;
1015      MBEntityHandle *start_vec = (MBEntityHandle*)buff_ptr;
1016      for (MBRange::const_iterator rit = allr_it->begin(); rit != allr_it->end(); rit++) {
1017        result = mbImpl->get_connectivity(*rit, connect, num_connect, false,
1018                                          &dum_connect);
1019        RRA("Failed to get connectivity.");
1020        assert(num_connect == *nv_it);
1021        PACK_EH(buff_ptr, &connect[0], num_connect);
1022      }
1023
1024        // substitute destination handles
1025      result = get_remote_handles(store_remote_handles, start_vec, start_vec,
1026                                  *nv_it*(*allr_it).size(), to_proc,
1027                                  whole_range);
1028      RRA("Trouble getting remote handles when packing entities.");
1029
1030        // pack the handles
1031      if (store_remote_handles)
1032        PACK_RANGE(buff_ptr, (*allr_it));
1033
1034#ifdef DEBUG_PACKING
1035      std::cerr << "Packed " << (*allr_it).size() << " ents of type " 
1036                << MBCN::EntityTypeName(TYPE_FROM_HANDLE(*(allr_it->begin()))) << std::endl;
1037#endif     
1038     
1039    }
1040
1041      // pack MBMAXTYPE to indicate end of ranges
1042    PACK_INT(buff_ptr, ((int)MBMAXTYPE));
1043
1044    count += buff_ptr - orig_buff_ptr;
1045  }
1046
1047  if (debug_packing) std::cerr << std::endl << "Done packing entities." << std::endl;
1048
1049  return MB_SUCCESS;
1050}
1051
1052MBErrorCode MBParallelComm::get_remote_handles(const bool store_remote_handles,
1053                                               MBEntityHandle *from_vec, 
1054                                               MBEntityHandle *to_vec_tmp,
1055                                               int num_ents, int to_proc,
1056                                               const MBRange &new_ents) 
1057{
1058    // NOTE: THIS IMPLEMENTATION IS JUST LIKE THE RANGE-BASED VERSION, NO REUSE
1059    // AT THIS TIME, SO IF YOU FIX A BUG IN THIS VERSION, IT MAY BE IN THE
1060    // OTHER VERSION TOO!!!
1061  if (0 == num_ents) return MB_SUCCESS;
1062 
1063    // use a local destination ptr in case we're doing an in-place copy
1064  std::vector<MBEntityHandle> tmp_vector;
1065  MBEntityHandle *to_vec = to_vec_tmp;
1066  if (to_vec == from_vec) {
1067    tmp_vector.resize(num_ents);
1068    to_vec = &tmp_vector[0];
1069  }
1070
1071  if (!store_remote_handles) {
1072    int err;
1073      // in this case, substitute position in new_ents list
1074    for (int i = 0; i < num_ents; i++) {
1075      int ind = new_ents.index(from_vec[i]);
1076      to_vec[i] = CREATE_HANDLE(MBMAXTYPE, ind, err);
1077      assert(to_vec[i] != 0 && !err && -1 != ind);
1078    }
1079  }
1080  else {
1081    MBTag sharedp_tag, sharedps_tag, sharedh_tag, sharedhs_tag, pstatus_tag;
1082    MBErrorCode result = get_shared_proc_tags(sharedp_tag, sharedps_tag, 
1083                                              sharedh_tag, sharedhs_tag, pstatus_tag);
1084 
1085      // get single-proc destination handles and shared procs
1086    std::vector<int> sharing_procs(num_ents);
1087    result = mbImpl->tag_get_data(sharedh_tag, from_vec, num_ents,
1088                                  to_vec);
1089    RRA("Failed to get shared handle tag for remote_handles.");
1090    result = mbImpl->tag_get_data(sharedp_tag, from_vec, num_ents, &sharing_procs[0]);
1091    RRA("Failed to get sharing proc tag in remote_handles.");
1092    for (int j = 0; j < num_ents; j++) {
1093      if (to_vec[j] && sharing_procs[j] != to_proc)
1094        to_vec[j] = 0;
1095    }
1096   
1097    MBEntityHandle tmp_handles[MAX_SHARING_PROCS];
1098    int tmp_procs[MAX_SHARING_PROCS];
1099    int i;
1100      // go through results, and for 0-valued ones, look for multiple shared proc
1101    MBEntityHandle *tmp_eh;
1102    for (tmp_eh = to_vec, i = 0; i < num_ents; i++) {
1103      if (!to_vec[i]) {
1104        result = mbImpl->tag_get_data(sharedps_tag, from_vec+i, 1, tmp_procs);
1105        if (MB_SUCCESS == result) {
1106          for (int j = 0; j < MAX_SHARING_PROCS; j++) {
1107            if (-1 == tmp_procs[j]) break;
1108            else if (tmp_procs[j] == to_proc) {
1109              result = mbImpl->tag_get_data(sharedhs_tag, from_vec+i, 1, tmp_handles);
1110              RRA("Trouble getting sharedhs tag.");
1111              to_vec[i] = tmp_handles[j];
1112              assert(to_vec[i]);
1113              break;
1114            }
1115          }
1116        }
1117        if (!to_vec[i]) {
1118          int j = new_ents.index(from_vec[i]);
1119          if (-1 == j) {
1120            result = MB_FAILURE;
1121            RRA("Failed to find new entity in send list.");
1122          }
1123          int err;
1124          to_vec[i] = CREATE_HANDLE(MBMAXTYPE, j, err);
1125          if (err) {
1126            result = MB_FAILURE;
1127            RRA("Failed to create handle in remote_handles.");
1128          }
1129        }
1130      }
1131    }
1132  }
1133 
1134    // memcpy over results if from_vec and to_vec are the same
1135  if (to_vec_tmp == from_vec) 
1136    memcpy(from_vec, to_vec, num_ents * sizeof(MBEntityHandle));
1137 
1138  return MB_SUCCESS;
1139}
1140
1141MBErrorCode MBParallelComm::get_remote_handles(const bool store_remote_handles,
1142                                               const MBRange &from_range, 
1143                                               MBEntityHandle *to_vec,
1144                                               int to_proc,
1145                                               const MBRange &new_ents) 
1146{
1147    // NOTE: THIS IMPLEMENTATION IS JUST LIKE THE VECTOR-BASED VERSION, NO REUSE
1148    // AT THIS TIME, SO IF YOU FIX A BUG IN THIS VERSION, IT MAY BE IN THE
1149    // OTHER VERSION TOO!!!
1150  if (from_range.empty()) return MB_SUCCESS;
1151 
1152  if (!store_remote_handles) {
1153    int err;
1154      // in this case, substitute position in new_ents list
1155    MBRange::iterator rit;
1156    unsigned int i;
1157    for (rit = from_range.begin(), i = 0; rit != from_range.end(); rit++, i++) {
1158      int ind = new_ents.index(*rit);
1159      to_vec[i] = CREATE_HANDLE(MBMAXTYPE, ind, err);
1160      assert(to_vec[i] != 0 && !err && -1 != ind);
1161    }
1162  }
1163  else {
1164    MBTag sharedp_tag, sharedps_tag, sharedh_tag, sharedhs_tag, pstatus_tag;
1165    MBErrorCode result = get_shared_proc_tags(sharedp_tag, sharedps_tag, 
1166                                              sharedh_tag, sharedhs_tag, pstatus_tag);
1167 
1168      // get single-proc destination handles and shared procs
1169    std::vector<int> sharing_procs(from_range.size());
1170    result = mbImpl->tag_get_data(sharedh_tag, from_range, to_vec);
1171    RRA("Failed to get shared handle tag for remote_handles.");
1172    result = mbImpl->tag_get_data(sharedp_tag, from_range, &sharing_procs[0]);
1173    RRA("Failed to get sharing proc tag in remote_handles.");
1174    for (unsigned int j = 0; j < from_range.size(); j++) {
1175      if (to_vec[j] && sharing_procs[j] != to_proc)
1176        to_vec[j] = 0;
1177    }
1178   
1179    MBEntityHandle tmp_handles[MAX_SHARING_PROCS];
1180    int tmp_procs[MAX_SHARING_PROCS];
1181      // go through results, and for 0-valued ones, look for multiple shared proc
1182    MBRange::iterator rit;
1183    unsigned int i;
1184    for (rit = from_range.begin(), i = 0; rit != from_range.end(); rit++, i++) {
1185      if (!to_vec[i]) {
1186        result = mbImpl->tag_get_data(sharedhs_tag, &(*rit), 1, tmp_handles);
1187        if (MB_SUCCESS == result) {
1188          result = mbImpl->tag_get_data(sharedps_tag, &(*rit), 1, tmp_procs);
1189          RRA("Trouble getting sharedps tag.");
1190          for (int j = 0; j < MAX_SHARING_PROCS; j++)
1191            if (tmp_procs[j] == to_proc) {
1192              to_vec[i] = tmp_handles[j];
1193              break;
1194            }
1195        }
1196     
1197        if (!to_vec[i]) {
1198          int j = new_ents.index(*rit);
1199          if (-1 == j) {
1200            result = MB_FAILURE;
1201            RRA("Failed to find new entity in send list.");
1202          }
1203          int err;
1204          to_vec[i] = CREATE_HANDLE(MBMAXTYPE, j, err);
1205          if (err) {
1206            result = MB_FAILURE;
1207            RRA("Failed to create handle in remote_handles.");
1208          }
1209        }
1210      }
1211    }
1212  }
1213 
1214  return MB_SUCCESS;
1215}
1216
1217MBErrorCode MBParallelComm::get_remote_handles(const bool store_remote_handles,
1218                                               const MBRange &from_range, 
1219                                               MBRange &to_range,
1220                                               int to_proc,
1221                                               const MBRange &new_ents) 
1222{
1223  std::vector<MBEntityHandle> to_vector(from_range.size());
1224
1225  MBErrorCode result =
1226    get_remote_handles(store_remote_handles, from_range, &to_vector[0],
1227                       to_proc, new_ents);
1228  RRA("Trouble getting remote handles.");
1229  std::copy(to_vector.begin(), to_vector.end(), mb_range_inserter(to_range));
1230  return result;
1231}
1232
1233MBErrorCode MBParallelComm::unpack_entities(unsigned char *&buff_ptr,
1234                                            const bool store_remote_handles,
1235                                            const int from_proc,
1236                                            MBRange &entities) 
1237{
1238  MBErrorCode result;
1239  bool done = false;
1240  MBReadUtilIface *ru = NULL;
1241  result = mbImpl->query_interface(std::string("MBReadUtilIface"), 
1242                                   reinterpret_cast<void**>(&ru));
1243  RRA("Failed to get MBReadUtilIface.");
1244 
1245 
1246  while (!done) {
1247    MBEntityType this_type;
1248    MBEntityHandle actual_start;
1249    UNPACK_INT(buff_ptr, this_type);
1250    assert(this_type >= MBVERTEX && 
1251           (this_type == MBMAXTYPE || this_type < MBENTITYSET));
1252
1253      // MBMAXTYPE signifies end of entities data
1254    if (MBMAXTYPE == this_type) break;
1255   
1256      // get the number of ents
1257    int num_ents;
1258    UNPACK_INT(buff_ptr, num_ents);
1259   
1260    if (MBVERTEX == this_type) {
1261        // unpack coords
1262      if (num_ents) {
1263        std::vector<double*> coords(3);
1264        result = ru->get_node_arrays(3, num_ents, 0, 
1265                                     actual_start, coords);
1266        RRA("Failed to allocate node arrays.");
1267
1268        entities.insert(actual_start, actual_start+num_ents-1);
1269     
1270          // unpack the buffer data directly into coords
1271        for (int i = 0; i < 3; i++) 
1272          memcpy(coords[i], buff_ptr+i*num_ents*sizeof(double), 
1273                 num_ents*sizeof(double));
1274        buff_ptr += 3*num_ents * sizeof(double);
1275        UPC(3*num_ents, " doubles");
1276
1277          // unpack source handles
1278        if (store_remote_handles) {
1279          MBRange this_range;
1280          this_range.insert(actual_start, actual_start+num_ents-1);
1281          MBRange dum_range;
1282          UNPACK_RANGE(buff_ptr, dum_range);
1283          result = set_remote_data(this_range, dum_range, from_proc);
1284          RRA("Couldn't set sharing data");
1285        }
1286      }
1287    }
1288
1289    else {
1290      int verts_per_entity;
1291     
1292        // unpack the nodes per entity
1293      UNPACK_INT(buff_ptr, verts_per_entity);
1294     
1295      MBEntityHandle *connect;
1296      result = ru->get_element_array(num_ents, verts_per_entity, this_type,
1297                                     0, actual_start,
1298                                     connect);
1299      RRA("Failed to allocate element arrays.");
1300
1301        // unpack the connectivity
1302      UNPACK_EH(buff_ptr, connect, (num_ents*verts_per_entity));
1303      entities.insert(actual_start, actual_start+num_ents-1);
1304
1305        // convert to local handles
1306      result = get_local_handles(connect, num_ents*verts_per_entity,
1307                                 entities);
1308      RRA("Couldn't get local handles.");
1309
1310      if (store_remote_handles) {
1311          // unpack source handles
1312        MBRange this_range;
1313        this_range.insert(actual_start, actual_start+num_ents-1);
1314        MBRange dum_range;
1315        UNPACK_RANGE(buff_ptr, dum_range);
1316        result = set_remote_data(this_range, dum_range, from_proc);
1317        RRA("Couldn't set sharing data");
1318      }
1319
1320        // update adjacencies
1321      result = ru->update_adjacencies(actual_start, num_ents, 
1322                                      verts_per_entity, connect);
1323      RRA("Failed to update adjacencies.");
1324    }
1325
1326#ifdef DEBUG_PACKING
1327      std::cerr << "Unpacked " << num_ents << " ents of type " 
1328                << MBCN::EntityTypeName(TYPE_FROM_HANDLE(actual_start)) << std::endl;
1329#endif     
1330
1331  }
1332 
1333 
1334  if (debug_packing) std::cerr << std::endl << "Done unpacking entities." << std::endl;
1335
1336  return MB_SUCCESS;
1337}
1338
1339MBErrorCode MBParallelComm::unpack_iface_entities(unsigned char *&buff_ptr,
1340                                                  const int from_proc, 
1341                                                  std::vector<MBEntityHandle> &recd_ents) 
1342{
1343    // for all the entities in the received buffer; for each, save
1344    // entities in this instance which match connectivity, or zero if none found
1345  MBErrorCode result;
1346  bool done = false;
1347  std::vector<MBEntityHandle> connect;
1348 
1349  while (!done) {
1350    MBEntityType this_type;
1351    UNPACK_INT(buff_ptr, this_type);
1352    assert(this_type > MBVERTEX && 
1353           (this_type == MBMAXTYPE || this_type < MBENTITYSET));
1354
1355      // MBMAXTYPE signifies end of entities data
1356    if (MBMAXTYPE == this_type) break;
1357   
1358      // get the number of ents
1359    int num_ents;
1360    UNPACK_INT(buff_ptr, num_ents);
1361   
1362    int verts_per_entity;
1363     
1364      // unpack the verts per entity
1365    UNPACK_INT(buff_ptr, verts_per_entity);
1366
1367    connect.resize(verts_per_entity * num_ents);
1368   
1369      // unpack the connectivity
1370    UNPACK_EH(buff_ptr, &connect[0], (num_ents*verts_per_entity));
1371
1372      // unpack source handles
1373    MBRange source_range, tmp_range;
1374    UNPACK_RANGE(buff_ptr, source_range);
1375
1376      // save matching local entities, or 0 if none found
1377    for (int i = 0; i < num_ents; i++) {
1378        // test for existing entity
1379      result = mbImpl->get_adjacencies(&connect[0]+i*verts_per_entity, verts_per_entity, 
1380                                       MBCN::Dimension(this_type), false, tmp_range);
1381      if (MB_MULTIPLE_ENTITIES_FOUND == result) {
1382        RRA("Multiple entities found.");
1383      }
1384      if (!tmp_range.empty()) {
1385          // found a corresponding entity - save target
1386        assert(1 == tmp_range.size());
1387        recd_ents.push_back(*tmp_range.begin());
1388        tmp_range.clear();
1389      }
1390      else
1391        recd_ents.push_back(0);
1392    }
1393
1394#ifdef DEBUG_PACKING
1395    std::cerr << "Unpacked " << num_ents << " ents of type " 
1396              << MBCN::EntityTypeName(TYPE_FROM_HANDLE(actual_start)) << std::endl;
1397#endif     
1398
1399  }
1400 
1401 
1402  if (debug_packing) std::cerr << std::endl << "Done unpacking iface entities." << std::endl;
1403
1404  return MB_SUCCESS;
1405}
1406
1407MBErrorCode MBParallelComm::get_local_handles(const MBRange &remote_handles,
1408                                              MBRange &local_handles,
1409                                              const MBRange &new_ents) 
1410{
1411  std::vector<MBEntityHandle> rh_vec;
1412  rh_vec.reserve(remote_handles.size());
1413  std::copy(remote_handles.begin(), remote_handles.end(), std::back_inserter(rh_vec));
1414  MBErrorCode result = get_local_handles(&rh_vec[0], remote_handles.size(), new_ents);
1415  std::copy(rh_vec.begin(), rh_vec.end(), mb_range_inserter(local_handles));
1416  return result;
1417}
1418 
1419MBErrorCode MBParallelComm::get_local_handles(MBEntityHandle *from_vec, 
1420                                              int num_ents,
1421                                              const MBRange &new_ents) 
1422{
1423  for (int i = 0; i < num_ents; i++) {
1424    if (TYPE_FROM_HANDLE(from_vec[i]) == MBMAXTYPE) {
1425      assert(ID_FROM_HANDLE(from_vec[i]) < (int) new_ents.size());
1426      from_vec[i] = new_ents[ID_FROM_HANDLE(from_vec[i])];
1427    }
1428  }
1429 
1430  return MB_SUCCESS;
1431}
1432
1433MBErrorCode MBParallelComm::set_remote_data(MBRange &local_range,
1434                                            MBRange &remote_range,
1435                                            int other_proc) 
1436{
1437    // NOTE: THIS IMPLEMENTATION IS JUST LIKE THE VECTOR-BASED VERSION, NO REUSE
1438    // AT THIS TIME, SO IF YOU FIX A BUG IN THIS VERSION, IT MAY BE IN THE
1439    // OTHER VERSION TOO!!!
1440
1441  MBTag sharedp_tag, sharedps_tag, sharedh_tag, sharedhs_tag, pstatus_tag;
1442  MBErrorCode result = get_shared_proc_tags(sharedp_tag, sharedps_tag, 
1443                                            sharedh_tag, sharedhs_tag, pstatus_tag);
1444
1445    // get remote procs tag, if any
1446  MBRange tmp_range, tmp_local_range = local_range;
1447  std::vector<int> remote_proc(local_range.size());
1448  std::vector<int> remote_procs(MAX_SHARING_PROCS);
1449  std::vector<MBEntityHandle> remote_handle(local_range.size());
1450  std::vector<MBEntityHandle> remote_handles(MAX_SHARING_PROCS);
1451  std::fill(remote_procs.begin(), remote_procs.end(), -1);
1452  std::fill(remote_handles.begin(), remote_handles.end(), 0);
1453  result = mbImpl->tag_get_data(sharedp_tag, local_range,
1454                                &remote_proc[0]);
1455  RRA("Couldn't get sharedp tag (range).");
1456  result = mbImpl->tag_get_data(sharedh_tag, local_range,
1457                                &remote_handle[0]);
1458  RRA("Couldn't get sharedh tag (range).");
1459  MBRange::iterator rit, rit2;
1460  int i = 0;
1461
1462    // for each pair of local/remote handles:
1463  for (rit = tmp_local_range.begin(), rit2 = remote_range.begin(); 
1464       rit != tmp_local_range.end(); rit++, rit2++, i++) {
1465
1466      // get existing remote proc(s), handle(s) for this local handle
1467    remote_procs[0] = remote_proc[i];
1468    if (-1 != remote_procs[0]) remote_handles[0] = remote_handle[i];
1469    else {
1470      result = mbImpl->tag_get_data(sharedps_tag, &(*rit), 1,
1471                                    &remote_procs[0]);
1472      if (MB_SUCCESS == result) {
1473        result = mbImpl->tag_get_data(sharedhs_tag, &(*rit), 1,
1474                                      &remote_handles[0]);
1475        RRA("Couldn't get sharedhs tag (range).");
1476      }
1477    }
1478
1479      // now insert other_proc, handle into these, and set the tags
1480    if (-1 == remote_procs[0]) {
1481      remote_procs[0] = other_proc;
1482      remote_handles[0] = *rit2;
1483      result = mbImpl->tag_set_data(sharedp_tag, &(*rit), 1, &remote_procs[0]);
1484      RRA("Couldn't set sharedp tag (range)");
1485      result = mbImpl->tag_set_data(sharedh_tag, &(*rit), 1, &remote_handles[0]);
1486      RRA("Couldn't set sharedh tag (range)");
1487      remote_procs[0] = -1;
1488      remote_handles[0] = 0;
1489    }
1490    else {
1491      std::vector<int>::iterator vit = remote_procs.begin();
1492      std::vector<MBEntityHandle>::iterator vit2 = remote_handles.begin();
1493      while (-1 != *vit && vit != remote_procs.end() && other_proc > *vit) {
1494        vit++; vit2++;
1495      }
1496      assert(*vit != other_proc);
1497      remote_procs.insert(vit, other_proc);
1498      remote_handles.insert(vit2, *rit2);
1499        // need to pop 'cuz we're using an insert above
1500      remote_procs.pop_back();
1501      remote_handles.pop_back();
1502      result = mbImpl->tag_set_data(sharedps_tag, &(*rit), 1, &remote_procs[0]);
1503      RRA("Couldn't set sharedps tag (range)");
1504      result = mbImpl->tag_set_data(sharedhs_tag, &(*rit), 1, &remote_handles[0]);
1505      RRA("Couldn't set sharedhs tag (range)");
1506      std::fill(remote_procs.begin(), remote_procs.end(), -1);
1507      std::fill(remote_handles.begin(), remote_handles.end(), 0);
1508        // need to clear sharedp_tag and sharedh_tag if prev
1509        // data came from there
1510      if (-1 != remote_proc[i]) {
1511        remote_proc[i] = -1;
1512        remote_handle[i] = 0;
1513        result = mbImpl->tag_set_data(sharedp_tag, &*rit, 1, &remote_proc[i] );
1514        RRA("Couldn't set sharedp tag");
1515        result = mbImpl->tag_set_data(sharedh_tag, &*rit, 1, &remote_handle[i] );
1516        RRA("Couldn't set sharedp tag");
1517      }
1518    }
1519  }
1520
1521    // also update shared flag for these ents
1522  unsigned char *shared_flags = (unsigned char*) &remote_proc[0];
1523  result = mbImpl->tag_get_data(pstatus_tag, local_range, shared_flags);
1524  RRA("Couldn't get pstatus tag (range)");
1525  for (unsigned int i = 0; i < local_range.size(); i++)
1526    shared_flags[i] |= PSTATUS_SHARED;
1527  result = mbImpl->tag_set_data(pstatus_tag, local_range, shared_flags);
1528  RRA("Couldn't set pstatus tag (range)");
1529 
1530 
1531  return MB_SUCCESS;
1532}
1533 
1534MBErrorCode MBParallelComm::set_remote_data(MBEntityHandle *local_ents,
1535                                            MBEntityHandle *remote_ents,
1536                                            int num_ents,
1537                                            int other_proc) 
1538{
1539  if (0 == num_ents)
1540    return MB_SUCCESS;
1541
1542    // NOTE: THIS IMPLEMENTATION IS JUST LIKE THE RANGE-BASED VERSION, NO REUSE
1543    // AT THIS TIME, SO IF YOU FIX A BUG IN THIS VERSION, IT MAY BE IN THE
1544    // OTHER VERSION TOO!!!
1545  MBTag sharedp_tag, sharedps_tag, sharedh_tag, sharedhs_tag, pstatus_tag;
1546  MBErrorCode result = get_shared_proc_tags(sharedp_tag, sharedps_tag, 
1547                                            sharedh_tag, sharedhs_tag, pstatus_tag);
1548
1549    // get remote procs tag, if any
1550  MBRange tmp_range;
1551  std::vector<int> remote_proc(num_ents);
1552  int remote_procs[MAX_SHARING_PROCS];
1553  std::vector<MBEntityHandle> remote_handle(num_ents);
1554  MBEntityHandle remote_handles[MAX_SHARING_PROCS];
1555  std::vector<unsigned char> pstatus_vals(num_ents);
1556  result = mbImpl->tag_get_data(sharedp_tag, local_ents, num_ents,
1557                                &remote_proc[0]);
1558  RRA("Couldn't get sharedp tag (vector)");
1559  result = mbImpl->tag_get_data(sharedh_tag, local_ents, num_ents,
1560                                &remote_handle[0]);
1561  RRA("Couldn't get sharedh tag (vector)");
1562  result = mbImpl->tag_get_data(pstatus_tag, local_ents, num_ents,
1563                                &pstatus_vals[0]);
1564  RRA("Couldn't get sharedh tag (vector)");
1565
1566    // for each local/remote handle pair
1567  for (int i = 0; i != num_ents; i++) {
1568
1569      // get existing remote proc(s), handle(s) for this local handle
1570    if (-1 != remote_proc[i]) {
1571      remote_procs[0] = remote_proc[i];
1572      remote_handles[0] = remote_handle[i];
1573      std::fill(remote_procs+1, remote_procs+MAX_SHARING_PROCS, -1);
1574      std::fill(remote_handles+1, remote_handles+MAX_SHARING_PROCS, 0);
1575    }
1576    else {
1577      result = mbImpl->tag_get_data(sharedps_tag, local_ents+i, 1,
1578                                    remote_procs);
1579      RRA("Couldn't get sharedps tag (vector)");
1580     
1581      result = mbImpl->tag_get_data(sharedhs_tag, local_ents+i, 1,
1582                                    remote_handles);
1583      RRA("Couldn't get sharedhs tag (vector)");
1584    }
1585
1586      // now either insert other_proc, handle into these, or remove if
1587      // remote handle is 0
1588    if (0 == remote_ents[i]) {
1589      result = rmv_remote_proc(local_ents[i], remote_procs, remote_handles,
1590                               other_proc);
1591      RRA(" ");
1592    }
1593    else {
1594      result = add_remote_proc(local_ents[i], remote_procs, remote_handles,
1595                               other_proc, remote_ents[i]);
1596      RRA(" ");
1597    }
1598  }
1599
1600  return MB_SUCCESS;
1601}
1602
1603MBErrorCode MBParallelComm::rmv_remote_proc(MBEntityHandle ent,
1604                                            int *remote_procs,
1605                                            MBEntityHandle *remote_hs,
1606                                            int remote_proc) 
1607{
1608  int i = std::find(remote_procs, remote_procs+MAX_SHARING_PROCS, -1) - remote_procs;
1609  int j = std::find(remote_procs, remote_procs+i, remote_proc) - remote_procs;
1610  MBErrorCode result;
1611
1612    // remote_proc must be in this list
1613  assert(j != i);
1614 
1615  for (; j != i; j++) {
1616    remote_procs[j] = remote_procs[j+1];
1617    remote_hs[j] = remote_hs[j+1];
1618  }
1619
1620  if (i == 1) {
1621      // only had one proc, and now have none; have to set the values,
1622      // since they're sparse tags
1623    result = mbImpl->tag_set_data(sharedp_tag(), &ent, 1, remote_procs);
1624    result = mbImpl->tag_set_data(sharedh_tag(), &ent, 1, remote_hs);
1625      // if it's not shared, it's also not a ghost, interface, or !owned entity
1626    unsigned char not_shared = 0;
1627    result = mbImpl->tag_set_data(pstatus_tag(), &ent, 1, &not_shared);
1628  }
1629  else if (i == 2) {
1630      // went from 2 to 1, need to unset 1 and set the other
1631    result = mbImpl->tag_set_data(sharedp_tag(), &ent, 1, remote_procs);
1632    RRA("Couldn't set sharedp tag");
1633    result = mbImpl->tag_set_data(sharedh_tag(), &ent, 1, remote_hs);
1634    RRA("Couldn't set sharedh tag");
1635    result = mbImpl->tag_delete_data(sharedps_tag(), &ent, 1);
1636    RRA("Couldn't remove sharedps tag");
1637    result = mbImpl->tag_delete_data(sharedhs_tag(), &ent, 1);
1638    RRA("Couldn't remove sharedhs tag");
1639  }
1640  else {
1641    result = mbImpl->tag_set_data(sharedps_tag(), &ent, 1, remote_procs);
1642    RRA("Couldn't set sharedps tag");
1643    result = mbImpl->tag_set_data(sharedhs_tag(), &ent, 1, remote_hs);
1644    RRA("Couldn't set sharedhs tag");
1645  }
1646 
1647  return MB_SUCCESS;
1648}
1649
1650template <typename T> void
1651insert_in_array( T* array, size_t array_size, size_t location, T value )
1652{
1653  assert( location+1 < array_size );
1654  for (size_t i = array_size-1; i > location; --i)
1655    array[i] = array[i-1];
1656  array[location] = value;
1657}
1658
1659MBErrorCode MBParallelComm::add_remote_proc(MBEntityHandle ent,
1660                                            int *remote_procs,
1661                                            MBEntityHandle *remote_hs,
1662                                            int remote_proc,
1663                                            MBEntityHandle remote_handle) 
1664{
1665  int* ptr = std::find( remote_procs, remote_procs+MAX_SHARING_PROCS, -1 );
1666  const size_t n = ptr - remote_procs;
1667  ptr = std::lower_bound( remote_procs, remote_procs+n, remote_proc );
1668  const size_t i = ptr - remote_procs;
1669 
1670  MBErrorCode result;
1671  const int invalid_proc = -1;
1672  const MBEntityHandle invalid_handle = 0;
1673  if (i == n || remote_procs[i] != remote_proc) {
1674    insert_in_array( remote_procs, MAX_SHARING_PROCS, i, remote_proc );
1675    insert_in_array( remote_hs, MAX_SHARING_PROCS, i, remote_handle );
1676   
1677    switch (n) {
1678      case 0:
1679        result = mbImpl->tag_set_data( sharedp_tag(), &ent, 1, remote_procs );
1680        RRA("Couldn't set sharedp tag");
1681        result = mbImpl->tag_set_data( sharedh_tag(), &ent, 1, remote_hs );
1682        RRA("Couldn't set sharedh tag");
1683        break;
1684      case 1:
1685          // going from 1 -> many, so clear single-value tag
1686        result = mbImpl->tag_set_data(  sharedp_tag(), &ent, 1, &invalid_proc );
1687        RRA("Couldn't set sharedp tag");
1688        result = mbImpl->tag_set_data( sharedh_tag(), &ent, 1, &invalid_handle );
1689        RRA("Couldn't set sharedh tag");
1690          // NO BREAK: fall through to next block to set many-valued tags
1691      default:
1692        result = mbImpl->tag_set_data(  sharedps_tag(), &ent, 1, remote_procs );
1693        RRA("Couldn't set sharedps tag");
1694        result = mbImpl->tag_set_data( sharedhs_tag(), &ent, 1, remote_hs );
1695        RRA("Couldn't set sharedhs tag");
1696        break;
1697    }
1698  }
1699  else if (remote_hs[i] != remote_handle) {
1700    assert(remote_hs[i] == invalid_handle);
1701    remote_hs[i] = remote_handle;
1702    if (n == 1) {
1703      result = mbImpl->tag_set_data( sharedh_tag(), &ent, 1, remote_hs );
1704      RRA("Couldn't set sharedh tag");
1705    }
1706    else {
1707      result = mbImpl->tag_set_data( sharedhs_tag(), &ent, 1, remote_hs );
1708      RRA("Couldn't set sharedhs tag");
1709    }
1710  }
1711 
1712  return MB_SUCCESS;
1713}
1714
1715MBErrorCode MBParallelComm::pack_range_map(MBRange &key_range, MBEntityHandle val_start,
1716                                           HandleMap &handle_map) 
1717{
1718  for (MBRange::const_pair_iterator key_it = key_range.const_pair_begin(); 
1719       key_it != key_range.const_pair_end(); key_it++) {
1720    int tmp_num = (*key_it).second - (*key_it).first + 1;
1721    handle_map.insert((*key_it).first, val_start, tmp_num);
1722    val_start += tmp_num;
1723  }
1724
1725  return MB_SUCCESS;
1726}
1727
1728MBErrorCode MBParallelComm::pack_sets(MBRange &entities,
1729                                      MBRange::const_iterator &start_rit,
1730                                      MBRange &whole_range,
1731                                      unsigned char *&buff_ptr,
1732                                      int &count,
1733                                      const bool just_count,
1734                                      const bool store_remote_handles,
1735                                      const int to_proc,
1736                                      MBRange &set_range,
1737                                      std::vector<MBRange> &set_ranges,
1738                                      std::vector<int> &set_sizes,
1739                                      std::vector<unsigned int> &options_vec)
1740{
1741    // SETS:
1742    // . #sets
1743    // . for each set:
1744    //   - options[#sets] (unsigned int)
1745    //   - if (unordered) set range
1746    //   - else if ordered
1747    //     . #ents in set
1748    //     . handles[#ents]
1749    //   - #parents
1750    //   - if (#parents) handles[#parents]
1751    //   - #children
1752    //   - if (#children) handles[#children]
1753 
1754    // now the sets; assume any sets the application wants to pass are in the entities list
1755  unsigned char *orig_buff_ptr = buff_ptr;
1756  MBErrorCode result;
1757
1758  if (just_count) {
1759    int ranges_size = 0, vecs_size = 0, tot_parch = 0;
1760   
1761    for (; start_rit != entities.end(); start_rit++) {
1762      set_range.insert(*start_rit);
1763   
1764      unsigned int options;
1765      result = mbImpl->get_meshset_options(*start_rit, options);
1766      RRA("Failed to get meshset options.");
1767      options_vec.push_back(options);
1768
1769      if (options & MESHSET_SET) {
1770          // range-based set; count the subranges
1771        set_ranges.push_back(MBRange());
1772        result = mbImpl->get_entities_by_handle(*start_rit, *set_ranges.rbegin());
1773        RRA("Failed to get set entities.");
1774
1775          // set range
1776        ranges_size += 2 * sizeof(MBEntityHandle) * num_subranges(*set_ranges.rbegin()) + 
1777          sizeof(int);
1778      }
1779      else if (options & MESHSET_ORDERED) {
1780          // just get the number of entities in the set
1781        int num_ents;
1782        result = mbImpl->get_number_entities_by_handle(*start_rit, num_ents);
1783        RRA("Failed to get number entities in ordered set.");
1784        set_sizes.push_back(num_ents);
1785
1786          // set vec
1787        vecs_size += sizeof(MBEntityHandle) * num_ents + sizeof(int);
1788      }
1789
1790        // get numbers of parents/children
1791      int num_par, num_ch;
1792      result = mbImpl->num_child_meshsets(*start_rit, &num_ch);
1793      RRA("Failed to get num children.");
1794
1795      result = mbImpl->num_parent_meshsets(*start_rit, &num_par);
1796      RRA("Failed to get num parents.");
1797
1798      tot_parch += num_ch + num_par;
1799     
1800    }
1801
1802      // num of sets
1803    count += sizeof(int);
1804   
1805      // options
1806    count += set_range.size() * sizeof(unsigned int);
1807
1808      // range, vector sizes
1809    count += ranges_size + vecs_size;
1810   
1811      // set children, parents
1812    count += 2 * set_range.size() * sizeof(int) + tot_parch * sizeof(MBEntityHandle);
1813
1814        // set handles
1815    if (!set_range.empty() && store_remote_handles)
1816      count += sizeof(int) + 2*sizeof(MBEntityHandle)*num_subranges(set_range);
1817
1818    whole_range.merge(set_range);
1819  }
1820  else {
1821   
1822      // set handle range
1823    PACK_INT(buff_ptr, set_range.size());
1824
1825      // option values
1826    if (!set_range.empty())
1827      PACK_VOID(buff_ptr, &options_vec[0], set_range.size()*sizeof(unsigned int));
1828
1829    std::vector<unsigned int>::const_iterator opt_it = options_vec.begin();
1830    std::vector<MBRange>::const_iterator rit = set_ranges.begin();
1831    std::vector<int>::const_iterator mem_it = set_sizes.begin();
1832    static std::vector<MBEntityHandle> members;
1833
1834    for (MBRange::const_iterator set_it = set_range.begin(); set_it != set_range.end(); 
1835         set_it++, opt_it++) {
1836      if ((*opt_it) & MESHSET_SET) {
1837          // pack entities as a range
1838        MBRange dum_range;
1839        result = get_remote_handles(store_remote_handles,
1840                                    (*rit), dum_range, to_proc,
1841                                    whole_range);
1842        RRA("Trouble getting remote handles for unordered set contents.");
1843        PACK_RANGE(buff_ptr, dum_range);
1844        rit++;
1845      }
1846      else if ((*opt_it) & MESHSET_ORDERED) {
1847          // pack entities as vector, with length
1848        PACK_INT(buff_ptr, *mem_it);
1849        members.clear();
1850        result = mbImpl->get_entities_by_handle(*set_it, members);
1851        RRA("Failed to get set entities.");
1852        result = get_remote_handles(store_remote_handles,
1853                                    &members[0], &members[0], 
1854                                    members.size(), to_proc,
1855                                    whole_range);
1856        RRA("Trouble getting remote handles for ordered set contents.");
1857        PACK_EH(buff_ptr, &members[0], *mem_it);
1858        mem_it++;
1859      }
1860    }
1861   
1862      // pack numbers of parents/children
1863    unsigned int tot_pch = 0;
1864    for (MBRange::const_iterator set_it = set_range.begin(); set_it != set_range.end(); 
1865         set_it++) {
1866        // pack parents
1867      int num_pch;
1868      result = mbImpl->num_parent_meshsets(*set_it, &num_pch);
1869      RRA("Failed to get num parents.");
1870      PACK_INT(buff_ptr, num_pch);
1871      tot_pch += num_pch;
1872      result = mbImpl->num_child_meshsets(*set_it, &num_pch);
1873      RRA("Failed to get num children.");
1874      PACK_INT(buff_ptr, num_pch);
1875      tot_pch += num_pch;
1876    }
1877
1878      // now pack actual parents/children
1879    members.clear();
1880    members.reserve(tot_pch);
1881    std::vector<MBEntityHandle> tmp_pch;
1882    for (MBRange::const_iterator set_it = set_range.begin(); set_it != set_range.end(); 
1883         set_it++) {
1884      result = mbImpl->get_parent_meshsets(*set_it, tmp_pch);
1885      RRA("Failed to get parents.");
1886      std::copy(tmp_pch.begin(), tmp_pch.end(), std::back_inserter(members));
1887      tmp_pch.clear();
1888      result = mbImpl->get_child_meshsets(*set_it, tmp_pch);
1889      RRA("Failed to get children.");
1890      std::copy(tmp_pch.begin(), tmp_pch.end(), std::back_inserter(members));
1891      tmp_pch.clear();
1892    }
1893    assert(members.size() == tot_pch);
1894    if (!members.empty()) {
1895      result = get_remote_handles(store_remote_handles,
1896                                  &members[0], &members[0], 
1897                                  members.size(), to_proc,
1898                                  whole_range);
1899      RRA("Trouble getting remote handles for set parent/child sets.");
1900#ifndef NDEBUG
1901        // check that all handles are either sets or maxtype
1902      for (unsigned int __j = 0; __j < members.size(); __j++)
1903        assert((TYPE_FROM_HANDLE(members[__j]) == MBMAXTYPE &&
1904                ID_FROM_HANDLE(members[__j]) < (int)whole_range.size()) ||
1905               TYPE_FROM_HANDLE(members[__j]) == MBENTITYSET);
1906#endif       
1907      PACK_EH(buff_ptr, &members[0], members.size());
1908    }
1909   
1910    // pack the handles
1911    if (store_remote_handles && !set_range.empty())
1912      PACK_RANGE(buff_ptr, set_range);
1913
1914    count += buff_ptr - orig_buff_ptr;
1915  }
1916
1917  if (debug_packing) std::cerr << std::endl << "Done packing sets." << std::endl;
1918
1919  return MB_SUCCESS;
1920}
1921
1922MBErrorCode MBParallelComm::unpack_sets(unsigned char *&buff_ptr,
1923                                        MBRange &entities,
1924                                        const bool store_remote_handles,
1925                                        const int from_proc)
1926{
1927 
1928    // now the sets; assume any sets the application wants to pass are in the entities list
1929  MBErrorCode result;
1930
1931  MBRange new_sets;
1932  int num_sets;
1933  UNPACK_INT(buff_ptr, num_sets);
1934
1935  if (!num_sets) return MB_SUCCESS;
1936         
1937  std::vector<MBEntityHandle> members;
1938  int num_ents;
1939  std::vector<unsigned int> options_vec(num_sets);
1940      // option value
1941  if (num_sets)
1942    UNPACK_VOID(buff_ptr, &options_vec[0], num_sets*sizeof(unsigned int));
1943
1944    // create sets
1945  int i;
1946  MBRange::const_iterator rit;
1947  for (i = 0; i < num_sets; i++) {
1948   
1949      // create the set
1950    MBEntityHandle set_handle;
1951    result = mbImpl->create_meshset(options_vec[i], set_handle);
1952    RRA("Failed to create set in unpack.");
1953
1954    // make sure new sets handles are monotonically increasing
1955    assert(set_handle > *new_sets.rbegin());
1956
1957    new_sets.insert(set_handle);
1958  }
1959
1960  entities.merge(new_sets);
1961 
1962  for (rit = new_sets.begin(), i = 0; rit != new_sets.end(); rit++, i++) {
1963    if (options_vec[i] & MESHSET_SET) {
1964        // unpack entities as a range
1965      MBRange set_range, tmp_range;
1966      UNPACK_RANGE(buff_ptr, tmp_range);
1967      result = get_local_handles(tmp_range, set_range, entities);     
1968      RRA("Failed to get local handles for unordered set contents.");
1969      result = mbImpl->add_entities(*rit, set_range);
1970      RRA("Failed to add ents to unordered set in unpack.");
1971    }
1972    else if (options_vec[i] & MESHSET_ORDERED) {
1973        // unpack entities as vector, with length
1974      UNPACK_INT(buff_ptr, num_ents);
1975      members.resize(num_ents);
1976      if (num_ents) UNPACK_EH(buff_ptr, &members[0], num_ents);
1977      result = get_local_handles(&members[0], num_ents, entities);
1978      RRA("Failed to get local handles for ordered set contents.");
1979      result = mbImpl->add_entities(*rit, &members[0], num_ents);
1980      RRA("Failed to add ents to ordered set in unpack.");
1981    }
1982  }
1983
1984  std::vector<int> num_pch(2*new_sets.size());
1985  std::vector<int>::iterator vit;
1986  int tot_pch = 0;
1987  for (vit = num_pch.begin(); vit != num_pch.end(); vit++) {
1988    UNPACK_INT(buff_ptr, *vit);
1989    tot_pch += *vit;
1990  }
1991 
1992  members.resize(tot_pch);
1993  UNPACK_EH(buff_ptr, &members[0], tot_pch);
1994  result = get_local_handles(&members[0], tot_pch, entities);
1995  RRA("Couldn't get local handle for parent/child sets.");
1996
1997  int num = 0;
1998  MBEntityHandle *mem_ptr = &members[0];
1999  for (rit = new_sets.begin(); rit != new_sets.end(); rit++) {
2000      // unpack parents/children
2001    int num_par = num_pch[num++], num_child = num_pch[num++];
2002    if (num_par+num_child) {
2003      for (i = 0; i < num_par; i++) {
2004        assert(0 != mem_ptr[i]);
2005        result = mbImpl->add_parent_meshset(*rit, mem_ptr[i]);
2006        RRA("Failed to add parent to set in unpack.");
2007      }
2008      mem_ptr += num_par;
2009      for (i = 0; i < num_child; i++) {
2010        assert(0 != mem_ptr[i]);
2011        result = mbImpl->add_child_meshset(*rit, mem_ptr[i]);
2012        RRA("Failed to add child to set in unpack.");
2013      }
2014      mem_ptr += num_child;
2015    }
2016  }
2017
2018    // unpack source handles
2019  MBRange dum_range;
2020  if (store_remote_handles && !new_sets.empty()) {
2021    UNPACK_RANGE(buff_ptr, dum_range);
2022    result = set_remote_data(new_sets, dum_range, from_proc);
2023    RRA("Couldn't set sharing data for sets");
2024  }
2025
2026  if (debug_packing) std::cerr << std::endl << "Done unpacking sets." << std::endl;
2027
2028  return MB_SUCCESS;
2029}
2030
2031MBErrorCode MBParallelComm::pack_adjacencies(MBRange &entities,
2032                                             MBRange::const_iterator &start_rit,
2033                                             MBRange &whole_range,
2034                                             unsigned char *&buff_ptr,
2035                                             int &count,
2036                                             const bool just_count,
2037                                             const bool store_handles,
2038                                             const int to_proc)
2039{
2040  return MB_FAILURE;
2041}
2042
2043MBErrorCode MBParallelComm::unpack_adjacencies(unsigned char *&buff_ptr,
2044                                               MBRange &entities,
2045                                               const bool store_handles,
2046                                               const int from_proc)
2047{
2048  return MB_FAILURE;
2049}
2050
2051MBErrorCode MBParallelComm::pack_tags(MBRange &entities,
2052                                      MBRange::const_iterator &start_rit,
2053                                      const MBRange &whole_range,
2054                                      unsigned char *&buff_ptr,
2055                                      int &count,
2056                                      const bool just_count,
2057                                      const bool store_remote_handles,
2058                                      const int to_proc,
2059                                      const std::vector<MBTag> &all_tags,
2060                                      const std::vector<MBRange> &tag_ranges)
2061{
2062    // get all the tags
2063
2064  MBErrorCode result;
2065  std::vector<MBTag>::const_iterator tag_it;
2066  std::vector<MBRange>::const_iterator rit;
2067
2068  if (just_count) {
2069   
2070    for (tag_it = all_tags.begin(), rit = tag_ranges.begin(); 
2071         tag_it != all_tags.end(); tag_it++, rit++) {
2072
2073      result = packed_tag_size( *tag_it, *rit, count );
2074      if (MB_SUCCESS != result)
2075        return result;
2076    }
2077   
2078      // number of tags
2079    count += sizeof(int);
2080  }
2081
2082  else {
2083
2084    PACK_INT(buff_ptr, all_tags.size());
2085    count += sizeof(int);
2086   
2087    for (tag_it = all_tags.begin(), rit = tag_ranges.begin(); 
2088         tag_it != all_tags.end(); tag_it++, rit++) {
2089         
2090   
2091      result = pack_tag( *tag_it, *tag_it, *rit, whole_range, buff_ptr, 
2092                         count, store_remote_handles, to_proc );
2093      if (MB_SUCCESS != result)
2094        return result;
2095    }
2096  }
2097 
2098  if (debug_packing) std::cerr << std::endl << "Done packing tags." << std::endl;
2099
2100  return MB_SUCCESS;
2101}
2102         
2103
2104MBErrorCode MBParallelComm::packed_tag_size( MBTag tag,
2105                                             const MBRange &tagged_entities,
2106                                             int &count )
2107{
2108    // for dense tags, compute size assuming all entities have that tag
2109    // for sparse tags, get number of entities w/ that tag to compute size
2110
2111  std::vector<int> var_len_sizes;
2112  std::vector<const void*> var_len_values;
2113   
2114  const TagInfo *tinfo = tagServer->get_tag_info(tag);
2115    // default value
2116  count += sizeof(int);
2117  if (NULL != tinfo->default_value()) 
2118    count += tinfo->default_value_size();
2119
2120    // size, type, data type
2121  count += 3*sizeof(int);
2122
2123    // name
2124  count += sizeof(int);
2125  count += tinfo->get_name().size();
2126
2127    // range of tag
2128  count += sizeof(int) + tagged_entities.size() * sizeof(MBEntityHandle);
2129
2130  if (tinfo->get_size() == MB_VARIABLE_LENGTH) {
2131    const int num_ent = tagged_entities.size();
2132      // send a tag size for each entity
2133    count += num_ent * sizeof(int);
2134      // send tag data for each entity
2135    var_len_sizes.resize( num_ent );
2136    var_len_values.resize( num_ent );
2137    MBErrorCode result = tagServer->get_data( tag,
2138                                              tagged_entities, 
2139                                              &var_len_values[0], 
2140                                              &var_len_sizes[0] );
2141    RRA("Failed to get lenghts of variable-length tag values.");
2142    count += std::accumulate( var_len_sizes.begin(), var_len_sizes.end(), 0 );
2143  }
2144  else {
2145      // tag data values for range or vector
2146    count += tagged_entities.size() * tinfo->get_size();
2147  }
2148 
2149  return MB_SUCCESS;
2150}
2151
2152
2153MBErrorCode MBParallelComm::pack_tag( MBTag src_tag,
2154                                      MBTag dst_tag,
2155                                      const MBRange &tagged_entites,
2156                                      const MBRange &whole_range,
2157                                      unsigned char *&buff_ptr,
2158                                      int &count,
2159                                      const bool store_remote_handles,
2160                                      const int to_proc )
2161{
2162  unsigned char *orig_buff_ptr = buff_ptr;
2163  MBErrorCode result;
2164  std::vector<int> var_len_sizes;
2165  std::vector<const void*> var_len_values;
2166
2167  const TagInfo* tinfo = tagServer->get_tag_info(src_tag);
2168  if (!tinfo)
2169    return MB_TAG_NOT_FOUND;
2170   
2171  const TagInfo* dst_tinfo;
2172  if (src_tag == dst_tag) {
2173    dst_tinfo = tinfo;
2174  }
2175  else {
2176    dst_tinfo = tagServer->get_tag_info(dst_tag);
2177    if (!dst_tinfo)
2178      return MB_TAG_NOT_FOUND;
2179    if (dst_tinfo->get_size() != tinfo->get_size())
2180      return MB_TYPE_OUT_OF_RANGE;
2181    if (dst_tinfo->get_data_type() != tinfo->get_data_type() && 
2182        dst_tinfo->get_data_type() != MB_TYPE_OPAQUE &&
2183            tinfo->get_data_type() != MB_TYPE_OPAQUE)
2184      return MB_TYPE_OUT_OF_RANGE;
2185  }
2186   
2187   
2188
2189    // size, type, data type
2190  PACK_INT(buff_ptr, tinfo->get_size());
2191  MBTagType this_type;
2192  result = mbImpl->tag_get_type(dst_tag, this_type);
2193  PACK_INT(buff_ptr, (int)this_type);
2194  PACK_INT(buff_ptr, (int)(tinfo->get_data_type()));
2195
2196    // default value
2197  if (NULL == tinfo->default_value()) {
2198    PACK_INT(buff_ptr, 0);
2199  }
2200  else {
2201    PACK_BYTES(buff_ptr, tinfo->default_value(), tinfo->default_value_size());
2202  }
2203
2204    // name
2205  PACK_BYTES(buff_ptr, dst_tinfo->get_name().c_str(), dst_tinfo->get_name().size());
2206
2207#ifdef DEBUG_PACKING
2208std::cerr << "Packing tag \"" << tinfo->get_name() << "\"";
2209if (tinfo != dst_tinfo)
2210  std::cerr << " (as tag \"" << dst_tinfo->get_name() << "\")";
2211std::cerr << std::endl;
2212#endif   
2213    // pack entities
2214  PACK_INT(buff_ptr, tagged_entites.size());
2215  result = get_remote_handles(store_remote_handles,
2216                              tagged_entites, (MBEntityHandle*)buff_ptr, to_proc,
2217                              whole_range);
2218#ifdef DEBUG_PACKING
2219  if (MB_SUCCESS != result) {
2220    std::cerr << "Trouble getting remote handles for tagged entities:" << std::endl;
2221    tagged_entites.print("  ");
2222  }
2223#else
2224  RRA("Trouble getting remote handles for tagged entities.");
2225#endif
2226
2227  buff_ptr += tagged_entites.size() * sizeof(MBEntityHandle);
2228
2229  const size_t num_ent = tagged_entites.size();
2230  if (tinfo->get_size() == MB_VARIABLE_LENGTH) {
2231    var_len_sizes.resize( num_ent, 0 );
2232    var_len_values.resize( num_ent, 0 );
2233    result = mbImpl->tag_get_data(src_tag, tagged_entites, &var_len_values[0], 
2234                                  &var_len_sizes[0] );
2235    RRA("Failed to get variable-length tag data in pack_tags.");
2236    PACK_INTS(buff_ptr, &var_len_sizes[0], num_ent);
2237    for (unsigned int i = 0; i < num_ent; ++i)
2238      PACK_VOID(buff_ptr, var_len_values[i], var_len_sizes[i]);
2239  }
2240  else {
2241    result = mbImpl->tag_get_data(src_tag, tagged_entites, buff_ptr);
2242    RRA("Failed to get tag data in pack_tags.");
2243    buff_ptr += num_ent * tinfo->get_size();
2244    PC(num_ent*tinfo->get_size(), " void");
2245  }
2246
2247  count += buff_ptr - orig_buff_ptr;
2248
2249  return MB_SUCCESS;
2250}
2251
2252MBErrorCode MBParallelComm::get_tag_send_list( const MBRange& whole_range,
2253                                               std::vector<MBTag>& all_tags,
2254                                               std::vector<MBRange>& tag_ranges )
2255{
2256  std::vector<MBTag> tmp_tags;
2257  MBErrorCode result = tagServer->get_tags(tmp_tags);
2258  RRA("Failed to get tags in pack_tags.");
2259
2260  std::vector<MBTag>::iterator tag_it;
2261  for (tag_it = tmp_tags.begin(); tag_it != tmp_tags.end(); tag_it++) {
2262    std::string tag_name;
2263    result = mbImpl->tag_get_name(*tag_it, tag_name);
2264    if (tag_name.c_str()[0] == '_' && tag_name.c_str()[1] == '_')
2265      continue;
2266
2267    MBRange tmp_range;
2268    result = tagServer->get_entities(*tag_it, tmp_range);
2269    RRA("Failed to get entities for tag in pack_tags.");
2270    tmp_range = tmp_range.intersect(whole_range);
2271
2272    if (tmp_range.empty()) continue;
2273       
2274      // ok, we'll be sending this tag
2275    all_tags.push_back( *tag_it );
2276    tag_ranges.push_back( MBRange() );
2277    tag_ranges.back().swap( tmp_range );
2278  }
2279 
2280  return MB_SUCCESS;
2281}
2282
2283
2284
2285MBErrorCode MBParallelComm::unpack_tags(unsigned char *&buff_ptr,
2286                                        MBRange &entities,
2287                                        const bool store_remote_handles,
2288                                        const int from_proc)
2289{
2290    // tags
2291    // get all the tags
2292    // for dense tags, compute size assuming all entities have that tag
2293    // for sparse tags, get number of entities w/ that tag to compute size
2294
2295  MBErrorCode result;
2296 
2297  int num_tags;
2298  UNPACK_INT(buff_ptr, num_tags);
2299  std::vector<MBEntityHandle> tag_ents;
2300  std::vector<const void*> var_len_vals;
2301  std::vector<int> var_lengths;
2302
2303  for (int i = 0; i < num_tags; i++) {
2304   
2305        // tag handle
2306    MBTag tag_handle;
2307
2308      // size, data type
2309    int tag_size, tag_data_type, tag_type;
2310    UNPACK_INT(buff_ptr, tag_size);
2311    UNPACK_INT(buff_ptr, tag_type);
2312    UNPACK_INT(buff_ptr, tag_data_type);
2313     
2314      // default value
2315    int def_val_size;
2316    UNPACK_INT(buff_ptr, def_val_size);
2317    void *def_val_ptr = NULL;
2318    if (def_val_size) {
2319      def_val_ptr = buff_ptr;
2320      buff_ptr += def_val_size;
2321      UPC(tag_size, " void");
2322    }
2323   
2324      // name
2325    int name_len;
2326    UNPACK_INT(buff_ptr, name_len);
2327    std::string tag_name( reinterpret_cast<char*>(buff_ptr), name_len );
2328    buff_ptr += name_len;
2329    UPC(64, " chars");
2330#ifdef DEBUG_PACKING
2331    std::cerr << "Unpacking tag " << tag_name << std::endl;
2332#endif   
2333
2334      // create the tag
2335    if (tag_size == MB_VARIABLE_LENGTH) 
2336      result = mbImpl->tag_create_variable_length( tag_name.c_str(), (MBTagType)tag_type,
2337                                                   (MBDataType)tag_data_type, tag_handle,
2338                                                   def_val_ptr, def_val_size );
2339    else
2340      result = mbImpl->tag_create(tag_name.c_str(), tag_size, (MBTagType) tag_type, 
2341                                  (MBDataType) tag_data_type, tag_handle,
2342                                  def_val_ptr);
2343    if (MB_ALREADY_ALLOCATED == result) {
2344        // already allocated tag, check to make sure it's the same size, type, etc.
2345      const TagInfo *tag_info = tagServer->get_tag_info(tag_name.c_str());
2346      MBTagType this_type;
2347      result = mbImpl->tag_get_type(tag_handle, this_type);
2348      if (tag_size != tag_info->get_size() ||
2349          tag_type != this_type ||
2350          tag_data_type != tag_info->get_data_type() ||
2351          (def_val_ptr && !tag_info->default_value()) ||
2352          (!def_val_ptr && tag_info->default_value())) {
2353        RRA("Didn't get correct tag info when unpacking tag.");
2354      }
2355    }
2356    else if (MB_SUCCESS != result) return result;
2357
2358      // go through handle vec (in buffer) and convert to local handles in-place
2359    int num_ents;
2360    UNPACK_INT(buff_ptr, num_ents);
2361    MBEntityHandle *handle_vec = (MBEntityHandle*)buff_ptr;
2362    result = get_local_handles(handle_vec, num_ents, entities);
2363    RRA("Failed to get local handles for tagged entities.");
2364    buff_ptr += num_ents * sizeof(MBEntityHandle);
2365
2366      // if it's a handle type, also convert tag vals in-place in buffer
2367    if (MB_TYPE_HANDLE == tag_type) {
2368      MBEntityHandle *val_vec = (MBEntityHandle*)buff_ptr;
2369      result = get_local_handles(val_vec, num_ents, entities);
2370      RRA("Failed to get local handles for tag vals.");
2371    }
2372
2373    if (tag_size == MB_VARIABLE_LENGTH) {
2374        // Be careful of alignment here.  If the integers are aligned
2375        // in the buffer, we can use them directly.  Otherwise we must
2376        // copy them.
2377      const int* size_arr;
2378      if (((size_t)buff_ptr)%4) {
2379        var_lengths.resize( num_ents );
2380        memcpy( &var_lengths[0], buff_ptr, num_ents*sizeof(int) );
2381        size_arr = &var_lengths[0];
2382      }
2383      else {
2384        size_arr = reinterpret_cast<const int*>(buff_ptr);
2385      }
2386      buff_ptr += sizeof(int) * num_ents;
2387      UPC(sizeof(int) * num_ents, " void");
2388     
2389        // get pointers into buffer for each tag value
2390      var_len_vals.resize(num_ents);
2391      for (std::vector<MBEntityHandle>::size_type i = 0; 
2392           i < (std::vector<MBEntityHandle>::size_type) num_ents; ++i) {
2393        var_len_vals[i] = buff_ptr;
2394        buff_ptr += size_arr[i];
2395        UPC(size_arr[i], " void");
2396      }
2397      result = mbImpl->tag_set_data( tag_handle, handle_vec, num_ents,
2398                                     &var_len_vals[0], size_arr );
2399      RRA("Trouble setting tag data when unpacking variable-length tag.");
2400    }
2401    else {
2402      result = mbImpl->tag_set_data(tag_handle, handle_vec,
2403                                    num_ents, buff_ptr);
2404      RRA("Trouble setting range-based tag data when unpacking tag.");
2405      buff_ptr += num_ents * tag_size;
2406      UPC(num_ents * tag_size, " void");
2407    }
2408  }
2409 
2410  if (debug_packing) std::cerr << std::endl << "Done unpacking tags." << std::endl;
2411
2412  return MB_SUCCESS;
2413}
2414
2415MBErrorCode MBParallelComm::resolve_shared_ents(MBEntityHandle this_set,
2416                                                int resolve_dim,
2417                                                int shared_dim) 
2418{
2419  MBErrorCode result;
2420  MBRange proc_ents;
2421      // get the entities in the partition sets
2422  for (MBRange::iterator rit = partitionSets.begin(); rit != partitionSets.end(); rit++) {
2423    MBRange tmp_ents;
2424    result = mbImpl->get_entities_by_handle(*rit, tmp_ents, true);
2425    if (MB_SUCCESS != result) return result;
2426    proc_ents.merge(tmp_ents);
2427  }
2428
2429    // resolve dim is maximal dim of entities in proc_ents
2430  if (-1 == resolve_dim) {
2431    resolve_dim = mbImpl->dimension_from_handle(*proc_ents.rbegin()); 
2432    RRA("Couldn't get dimension.");
2433   
2434  }
2435
2436    // proc_ents should all be of same dimension
2437  if (resolve_dim > shared_dim &&
2438      mbImpl->dimension_from_handle(*proc_ents.rbegin()) !=
2439      mbImpl->dimension_from_handle(*proc_ents.begin())) {
2440    MBRange::iterator lower = proc_ents.lower_bound(MBCN::TypeDimensionMap[0].first),
2441      upper = proc_ents.upper_bound(MBCN::TypeDimensionMap[resolve_dim-1].second);
2442    proc_ents.erase(lower, upper);
2443  }
2444 
2445    // must call even if we don't have any entities, to make sure
2446    // collective comm'n works
2447  return resolve_shared_ents(this_set, proc_ents, resolve_dim, shared_dim);
2448}
2449 
2450MBErrorCode MBParallelComm::resolve_shared_ents(MBEntityHandle this_set,
2451                                                MBRange &proc_ents,
2452                                                int resolve_dim,
2453                                                int shared_dim) 
2454{
2455  MBErrorCode result;
2456  if (debug) std::cerr << "Resolving shared entities." << std::endl;
2457
2458  if (-1 == shared_dim) {
2459    if (0 == resolve_dim) {
2460      result = mbImpl->get_dimension(shared_dim); 
2461      RRA("Couldn't get dimension.");
2462    }
2463    else shared_dim = mbImpl->dimension_from_handle(*proc_ents.begin())-1;
2464  }
2465  assert(shared_dim >= 0 && resolve_dim >= 0);
2466 
2467    // get the skin entities by dimension
2468  MBRange skin_ents[4];
2469  std::vector<int> gid_data;
2470  std::vector<MBEntityHandle> handle_vec;
2471  int skin_dim;
2472
2473    // get the entities to be skinned
2474  if (resolve_dim < shared_dim) {
2475      // for vertex-based partition, it's the elements adj to the vertices
2476    result = mbImpl->get_adjacencies(proc_ents, shared_dim,
2477                                     false, skin_ents[resolve_dim],
2478                                     MBInterface::UNION);
2479    RRA("Failed getting skinned entities.");
2480    skin_dim = shared_dim-1;
2481  }
2482  else {
2483      // for element-based partition, it's just the elements
2484    skin_ents[resolve_dim] = proc_ents;
2485    skin_dim = resolve_dim-1;
2486  }
2487
2488    // find the skin
2489  MBSkinner skinner(mbImpl);
2490  result = skinner.find_skin(skin_ents[skin_dim+1], skin_ents[skin_dim],
2491                             skin_ents[skin_dim], true);
2492  RRA("Failed to find skin.");
2493  if (debug) std::cerr << "Found skin, now resolving." << std::endl;
2494
2495    // get entities adjacent to skin ents from shared_dim down to
2496    // zero; don't create them if they don't exist already
2497  for (int this_dim = skin_dim-1; this_dim >= 0; this_dim--) {
2498    result = mbImpl->get_adjacencies(skin_ents[skin_dim], this_dim,
2499                                     false, skin_ents[this_dim],
2500                                     MBInterface::UNION);
2501    RRA("Failed getting skin adjacencies.");
2502  }
2503
2504    // resolve shared vertices first
2505
2506    // global id tag
2507  MBTag gid_tag; int def_val = -1;
2508  result = mbImpl->tag_create(GLOBAL_ID_TAG_NAME, sizeof(int),
2509                              MB_TAG_DENSE, MB_TYPE_INTEGER, gid_tag,
2510                              &def_val, true);
2511  if (MB_FAILURE == result) return result;
2512
2513  else if (MB_ALREADY_ALLOCATED != result) {
2514      // just created it, so we need global ids
2515    result = assign_global_ids(0, skin_dim+1);
2516    RRA("Failed assigning global ids.");
2517  }
2518
2519    // store index in temp tag; reuse gid_data
2520  gid_data.resize(2*skin_ents[0].size());
2521  int idx = 0;
2522  for (MBRange::iterator rit = skin_ents[0].begin(); 
2523       rit != skin_ents[0].end(); rit++) 
2524    gid_data[idx] = idx, idx++;
2525  MBTag idx_tag;
2526  result = mbImpl->tag_create("__idx_tag", sizeof(int), MB_TAG_DENSE,
2527                              MB_TYPE_INTEGER, idx_tag, &def_val, true);
2528  if (MB_SUCCESS != result && MB_ALREADY_ALLOCATED != result) return result;
2529  result = mbImpl->tag_set_data(idx_tag, skin_ents[0], &gid_data[0]);
2530  RRA("Couldn't assign index tag.");
2531
2532    // get gids for skin ents in a vector, to pass to gs
2533  result = mbImpl->tag_get_data(gid_tag, skin_ents[0], &gid_data[0]);
2534  RRA("Couldn't get gid tag for skin vertices.");
2535
2536    // put handles in vector for passing to gs setup
2537  std::copy(skin_ents[0].begin(), skin_ents[0].end(), 
2538            std::back_inserter(handle_vec));
2539 
2540    // get a crystal router
2541  crystal_data *cd = procConfig.crystal_router();
2542 
2543    // get total number of entities; will overshoot highest global id, but
2544    // that's ok
2545  int num_total = 0, num_local;
2546  result = mbImpl->get_number_entities_by_dimension(0, 0, num_local);
2547  if (MB_SUCCESS != result) return result;
2548  int failure = MPI_Allreduce(&num_local, &num_total, 1,
2549                              MPI_INT, MPI_SUM, procConfig.proc_comm());
2550  if (failure) {
2551    result = MB_FAILURE;
2552    RRA("Allreduce for total number of shared ents failed.");
2553  }
2554 
2555    // call gather-scatter to get shared ids & procs
2556  gs_data *gsd;
2557  assert(sizeof(ulong_) == sizeof(MBEntityHandle));
2558  if (sizeof(int) != sizeof(ulong_)) {
2559    std::vector<long> lgid_data(gid_data.size());
2560    std::copy(gid_data.begin(), gid_data.end(), lgid_data.begin());
2561    gsd = gs_data_setup(skin_ents[0].size(), &lgid_data[0], 
2562                        (ulong_*)&handle_vec[0], 2, 1, 1, cd);
2563  }
2564  else {
2565    gsd = gs_data_setup(skin_ents[0].size(), (long*)&gid_data[0], 
2566                        (ulong_*)&handle_vec[0], 2, 1, 1, cd);
2567  }
2568 
2569  if (NULL == gsd) {
2570    result = MB_FAILURE;
2571    RRA("Couldn't create gs data.");
2572  }
2573
2574    // get shared proc tags
2575  MBTag sharedp_tag, sharedps_tag, sharedh_tag, sharedhs_tag, pstatus_tag;
2576  result = get_shared_proc_tags(sharedp_tag, sharedps_tag, 
2577                                sharedh_tag, sharedhs_tag, pstatus_tag);
2578  RRA("Couldn't get shared proc tags.");
2579 
2580    // load shared verts into a tuple, then sort by index
2581  tuple_list shared_verts;
2582  tuple_list_init_max(&shared_verts, 2, 0, 1, 0, 
2583                      skin_ents[0].size()*(MAX_SHARING_PROCS+1));
2584  unsigned int i = 0, j = 0;
2585  for (unsigned int p = 0; p < gsd->nlinfo->np; p++) 
2586    for (unsigned int np = 0; np < gsd->nlinfo->nshared[p]; np++) {
2587      shared_verts.vi[i++] = gsd->nlinfo->sh_ind[j];
2588      shared_verts.vi[i++] = gsd->nlinfo->target[p];
2589      shared_verts.vul[j] = gsd->nlinfo->ulabels[j];
2590      j++;
2591      shared_verts.n++;
2592    }
2593 
2594  int max_size = skin_ents[0].size()*(MAX_SHARING_PROCS+1);
2595  std::vector<int> sort_buffer(max_size);
2596  tuple_list_sort(&shared_verts, 0,(buffer*)&sort_buffer[0]);
2597
2598    // set sharing procs and handles tags on skin ents
2599  int maxp = -1;
2600  std::vector<int> sharing_procs(MAX_SHARING_PROCS);
2601  std::fill(sharing_procs.begin(), sharing_procs.end(), maxp);
2602  j = 0; i = 0;
2603
2604    // get ents shared by 1 or n procs
2605  std::map<std::vector<int>, MBRange> proc_nranges;
2606  MBRange proc_verts;
2607  result = mbImpl->get_adjacencies(proc_ents, 0, false, proc_verts,
2608                                   MBInterface::UNION);
2609  RRA("Couldn't get proc_verts.");
2610 
2611  result = tag_shared_verts(shared_verts, skin_ents,
2612                            proc_nranges, proc_verts);
2613  RRA("Trouble tagging shared verts.");
2614
2615    // get entities shared by 1 or n procs
2616  result = tag_shared_ents(resolve_dim, shared_dim, shared_verts, skin_ents,
2617                           proc_nranges);
2618  RRA("Trouble tagging shared entities.");
2619
2620  if (debug) {
2621    for (std::map<std::vector<int>, MBRange>::const_iterator mit = proc_nranges.begin();
2622         mit != proc_nranges.end(); mit++) {
2623      std::cout << "Iface: ";
2624      for (std::vector<int>::const_iterator vit = (mit->first).begin();
2625           vit != (mit->first).end(); vit++) std::cout << " " << *vit;
2626      std::cout << std::endl;
2627    }
2628  }
2629 
2630    // create the sets for each interface; store them as tags on
2631    // the interface instance
2632  MBRange iface_sets;
2633  result = create_interface_sets(proc_nranges, this_set, resolve_dim, shared_dim);
2634  RRA("Trouble creating iface sets.");
2635
2636    // resolve shared entity remote handles; implemented in ghost cell exchange
2637    // code because it's so similar
2638  result = exchange_ghost_cells(-1, -1, 0, true, true);
2639  RRA("Trouble resolving shared entity remote handles.");
2640
2641    // now set the shared/interface tag on non-vertex entities on interface
2642  result = tag_iface_entities();
2643  RRA("Failed to tag iface entities.");
2644
2645    // now build parent/child links for interface sets
2646  result = create_iface_pc_links();
2647  RRA("Trouble creating interface parent/child links.");
2648 
2649    // done
2650  return result;
2651}
2652
2653MBErrorCode MBParallelComm::tag_iface_entities() 
2654{
2655  MBRange all_ents, if_ents;
2656  MBErrorCode result;
2657  for (MBRange::iterator if_it = interfaceSets.begin(); if_it != interfaceSets.end(); if_it++) {
2658      // get all ents
2659    result = mbImpl->get_entities_by_handle(*if_it, if_ents);
2660    RRA("Trouble getting iface entities.");
2661  }
2662  std::vector<unsigned char> tvals(if_ents.size());
2663  result = mbImpl->tag_get_data(pstatus_tag(), if_ents, &tvals[0]);
2664  RRA("Failed to get pstatus tag values.");
2665 
2666  for (unsigned int i = 0; i < tvals.size(); i++)
2667    tvals[i] |= PSTATUS_INTERFACE;
2668 
2669  result = mbImpl->tag_set_data(pstatus_tag(), if_ents, &tvals[0]);
2670  RRA("Failed to set pstatus tag values.");
2671 
2672  return MB_SUCCESS;
2673}
2674
2675MBErrorCode MBParallelComm::set_pstatus_entities(MBRange &pstatus_ents,
2676                                                 unsigned char pstatus_val,
2677                                                 bool lower_dim_ents,
2678                                                 bool verts_too,
2679                                                 int operation) 
2680{
2681  std::vector<unsigned char> pstatus_vals(pstatus_ents.size());
2682  MBRange all_ents, *range_ptr = &pstatus_ents;
2683  MBErrorCode result;
2684  if (lower_dim_ents || verts_too) {
2685    all_ents = pstatus_ents;
2686    range_ptr = &all_ents;
2687    int start_dim = (lower_dim_ents ? mbImpl->dimension_from_handle(*pstatus_ents.rbegin())-1 : 0);
2688    for (; start_dim >= 0; start_dim--) {
2689      result = mbImpl->get_adjacencies(all_ents, start_dim, true, all_ents,
2690                                       MBInterface::UNION);
2691      RRA(" ");
2692    }
2693  }
2694  if (MBInterface::UNION == operation) {
2695    result = mbImpl->tag_get_data(pstatus_tag(), *range_ptr, &pstatus_vals[0]);
2696    RRA("Couldn't get pstatus tag value.");
2697    for (unsigned int i = pstatus_ents.size()-1; i >= 0; i--)
2698      pstatus_vals[i] |= pstatus_val;
2699  }
2700  else {
2701    for (unsigned int i = pstatus_ents.size()-1; i >= 0; i--)
2702      pstatus_vals[i] = pstatus_val;
2703  }
2704  result = mbImpl->tag_set_data(pstatus_tag(), *range_ptr, &pstatus_vals[0]);
2705  RRA("Couldn't set pstatus tag value.");
2706 
2707  return MB_SUCCESS;
2708}
2709 
2710MBErrorCode MBParallelComm::create_interface_sets(std::map<std::vector<int>, MBRange> &proc_nranges,
2711                                                  MBEntityHandle this_set,
2712                                                  int resolve_dim, int shared_dim) 
2713{
2714  if (proc_nranges.empty()) return MB_SUCCESS;
2715 
2716  int proc_ids[MAX_SHARING_PROCS];
2717  MBTag sharedp_tag, sharedps_tag, sharedh_tag, sharedhs_tag, pstatus_tag;
2718  MBErrorCode result = get_shared_proc_tags(sharedp_tag, sharedps_tag, 
2719                                            sharedh_tag, sharedhs_tag,
2720                                            pstatus_tag);
2721  RRA("Trouble getting shared proc tags in create_interface_sets.");
2722  MBRange::iterator rit;
2723
2724    // create interface sets, tag them, and tag their contents with iface set tag
2725  std::vector<MBEntityHandle> tag_vals;
2726  std::vector<unsigned char> pstatus;
2727  for (std::map<std::vector<int>,MBRange>::iterator mit = proc_nranges.begin();
2728       mit != proc_nranges.end(); mit++) {
2729      // create the set
2730    MBEntityHandle new_set;
2731    result = mbImpl->create_meshset(MESHSET_SET, new_set); 
2732    RRA("Failed to create interface set.");
2733    interfaceSets.insert(new_set);
2734
2735      // add entities
2736    result = mbImpl->add_entities(new_set, mit->second); 
2737    RRA("Failed to add entities to interface set.");
2738      // tag set with the proc rank(s)
2739    if (mit->first.size() == 1)
2740      result = mbImpl->tag_set_data(sharedp_tag, &new_set, 1, 
2741                                    &(mit->first)[0]); 
2742    else {
2743      // pad tag data out to MAX_SHARING_PROCS with -1
2744      assert( mit->first.size() <= MAX_SHARING_PROCS );
2745      std::copy( mit->first.begin(), mit->first.end(), proc_ids );
2746      std::fill( proc_ids + mit->first.size(), proc_ids + MAX_SHARING_PROCS, -1 );
2747      result = mbImpl->tag_set_data(sharedps_tag, &new_set, 1, proc_ids );
2748    }
2749    RRA("Failed to tag interface set with procs.");
2750   
2751      // get the owning proc, then set the pstatus tag on iface set
2752    int min_proc = (mit->first)[0];
2753    unsigned char pval = (PSTATUS_SHARED | PSTATUS_INTERFACE);
2754    if (min_proc < (int) procConfig.proc_rank()) pval |= PSTATUS_NOT_OWNED;
2755    result = mbImpl->tag_set_data(pstatus_tag, &new_set, 1, &pval); 
2756    RRA("Failed to tag interface set with pstatus.");
2757
2758      // tag the entities with the same thing
2759    pstatus.clear();
2760    pstatus.resize(mit->second.size(), pval);
2761    result = mbImpl->tag_set_data(pstatus_tag, mit->second, &pstatus[0]); 
2762    RRA("Failed to tag interface set entities with pstatus.");
2763  }
2764
2765  return MB_SUCCESS;
2766}
2767
2768MBErrorCode MBParallelComm::create_iface_pc_links() 
2769{
2770    // now that we've resolved the entities in the iface sets,
2771    // set parent/child links between the iface sets
2772
2773    // first tag all entities in the iface sets
2774  MBTag tmp_iface_tag;
2775  MBEntityHandle tmp_iface_set = 0;
2776  MBErrorCode result = mbImpl->tag_create("__tmp_iface", sizeof(MBEntityHandle),
2777                                          MB_TAG_DENSE, MB_TYPE_HANDLE,
2778                                          tmp_iface_tag, &tmp_iface_set);
2779  if (MB_ALREADY_ALLOCATED != result && MB_SUCCESS != result) 
2780    RRA("Failed to create temporary iface set tag.");
2781
2782  MBRange iface_ents;
2783  std::vector<MBEntityHandle> tag_vals;
2784  MBRange::iterator rit;
2785 
2786  for (rit = interfaceSets.begin(); rit != interfaceSets.end(); rit++) {
2787      // tag entities with interface set
2788    iface_ents.clear();
2789    result = mbImpl->get_entities_by_handle(*rit, iface_ents);
2790    RRA("Couldn't get entities in iface set.");
2791   
2792    if (iface_ents.empty()) continue;
2793   
2794    tag_vals.resize(iface_ents.size());
2795    std::fill(tag_vals.begin(), tag_vals.end(), *rit);
2796    result = mbImpl->tag_set_data(tmp_iface_tag, iface_ents, &tag_vals[0]); 
2797    RRA("Failed to tag iface entities with interface set.");
2798  }
2799 
2800    // now go back through interface sets and add parent/child links
2801  MBRange tmp_ents2;
2802  for (int d = 2; d >= 0; d--) {
2803    for (rit = interfaceSets.begin(); rit != interfaceSets.end(); rit++) {
2804        // get entities on this interface
2805      iface_ents.clear();
2806      result = mbImpl->get_entities_by_handle(*rit, iface_ents, true);
2807      RRA("Couldn't get entities by dimension.");
2808      if (iface_ents.empty() ||
2809          mbImpl->dimension_from_handle(*iface_ents.rbegin()) != d) continue;
2810
2811        // get higher-dimensional entities and their interface sets
2812      result = mbImpl->get_adjacencies(&(*iface_ents.begin()), 1, d+1,
2813                                       false, tmp_ents2);
2814      RRA("Couldn't get adjacencies for interface sets.");
2815      tag_vals.resize(tmp_ents2.size());
2816      result = mbImpl->tag_get_data(tmp_iface_tag, tmp_ents2, &tag_vals[0]);
2817      RRA("Couldn't get iface set tag for interface sets.");
2818     
2819        // go through and for any on interface make it a parent
2820      MBEntityHandle last_set = 0;
2821      for (unsigned int i = 0; i < tag_vals.size(); i++) {
2822        if (tag_vals[i] && tag_vals[i] != last_set) {
2823          result = mbImpl->add_parent_child(tag_vals[i], *rit);
2824          RRA("Couldn't add parent/child link for interface set.");
2825          last_set = tag_vals[i];
2826        }
2827      }
2828    }
2829  }
2830 
2831    // delete the temporary tag
2832  result = mbImpl->tag_delete(tmp_iface_tag);
2833  RRA("Couldn't delete tmp iface tag.");
2834
2835  return MB_SUCCESS;
2836}
2837
2838MBErrorCode MBParallelComm::tag_shared_ents(int resolve_dim,
2839                                            int shared_dim,
2840                                            tuple_list &shared_verts,
2841                                            MBRange *skin_ents,
2842                                            std::map<std::vector<int>, MBRange> &proc_nranges) 
2843{
2844    // set sharing procs tags on other skin ents
2845  MBTag sharedp_tag, sharedps_tag, sharedh_tag, sharedhs_tag