Beispiel #1
0
/*
 * pOctant oct_localTree_nextDfs(pOctant oct, void **temp)
 * (previously: pOctant oct_global_nextDfs(pParoct oct, void **temp))
 *
 * do a dfs of the local octree on each processor.
 * subtrees are traversed in the order of the local roots
 * list, and each subtree is done in dfs order.
 *
 * Undefined action will take place if you modify the
 * tree while traversing.
 *
 */
pOctant oct_localTree_nextDfs(pOctant oct, void **temp)
{
  if (*temp==NULL)           /* Start of traversal */
    return(PList_next(OCT_info->OCT_rootlist,temp));


  if (oct=Zoltan_Oct_POct_nextDfs(oct, 0))
    return(oct);

  return(PList_next(OCT_info->OCT_rootlist,temp));
}
Beispiel #2
0
void Zoltan_Oct_Plots(ZZ *zz) {
pRList  RootList;                           /* list of all local roots */
pOctant RootOct;
OCT_Global_Info *OCT_info = (OCT_Global_Info *)(zz->LB.Data_Structure);
FILE *fp;
pRegion tmp;

  Zoltan_Print_Sync_Start(zz->Communicator, 1);

  if (zz->Proc == 0)
    fp = fopen("octants.gnu", "w");
  else
    fp = fopen("octants.gnu", "a");
  
  RootList = Zoltan_Oct_POct_localroots(OCT_info);
  while((RootOct = RL_nextRootOctant(&RootList))) {
    while(RootOct) {
      if(Zoltan_Oct_isTerminal(RootOct)) {

        /* Octant is terminal; surf the region list and print regions. */
        tmp = RootOct->list;
        while (tmp != NULL) {
          printf("%d PLOTREG %f %f\n", zz->Proc, tmp->Coord[0], tmp->Coord[1]);
          tmp = tmp->next;
        }

        /* Print the octant midpoint */
        printf("%d PLOTOCT %f %f\n", zz->Proc, 
               0.5 * (RootOct->min[0] + RootOct->max[0]),
               0.5 * (RootOct->min[1] + RootOct->max[1]));

        /* Print the octant bounding box */
        fprintf(fp, "%f %f\n", RootOct->min[0], RootOct->min[1]);
        fprintf(fp, "%f %f\n", RootOct->max[0], RootOct->min[1]);
        fprintf(fp, "%f %f\n", RootOct->max[0], RootOct->max[1]);
        fprintf(fp, "%f %f\n", RootOct->min[0], RootOct->max[1]);
        fprintf(fp, "%f %f\n\n", RootOct->min[0], RootOct->min[1]);
      }
      RootOct = Zoltan_Oct_POct_nextDfs(OCT_info, RootOct);
    }
  }

  fclose(fp);
  Zoltan_Print_Sync_End(zz->Communicator, 1);
}
Beispiel #3
0
/*
 * oct_global_clear()
 *
 * delete all regions from all octants on the local processor
 *
 */
static void Zoltan_Oct_global_clear(OCT_Global_Info * OCT_info)
{ 
  pRList  RootList;                 /* list of all local roots */
  pOctant Oct;

  /* 
   * iterate through the list of local roots 
   * traverse down the subtree 
   * delete regions associated with octant 
   */
  RootList = Zoltan_Oct_POct_localroots(OCT_info);
  while ((Oct = RL_nextRootOctant(&RootList))) {
    while(Oct) {
      if(Zoltan_Oct_isTerminal(Oct))
	Zoltan_Oct_clearRegions(Oct);
      Oct = Zoltan_Oct_POct_nextDfs(OCT_info, Oct);
    }
  }
}
Beispiel #4
0
/*
 * void Zoltan_Oct_gen_tree_from_input_data()
 *
 * This function will create a root node of on each processor which will
 * then be used to create an octree with regions associated with it. The
 * tree will then be balanced and the output used to balance "mesh regions"
 * on several processors.
 */
static void Zoltan_Oct_gen_tree_from_input_data(ZZ *zz, int oct_wgtflag,
						int *c1, int *c2, int *c3, 
						float *c0, int createpartree) 
{
  char *yo = "Zoltan_Oct_gen_tree_from_input_data";
  pRList  RootList;       /* list of all local roots */
  pOctant RootOct;        /* root octree octant */
  COORD min,              /* min coord bounds of objects */
        max;              /* max coord bounds of objects */
  int num_extra;          /* number of orphaned objects */
  int num_objs;           /* total number of local objects */
  pRegion ptr,            /* pointer to iterate trough region list */
          ptr1;           /* pointer to iterate trough region list */
  pOctant root;           /* root of the partition tree */
  int     i;              /* index counter */
  int     count,          /* count for leaf nodes in partition tree */
          proc,           /* proc leaf node of parition tree belongs to */
          extra,          /* extra leaf node flag, if not evenly divisible */
          remainder;      /* remainder of node, or processors to fill */
  pOctant cursor,         /* cursor to iterate through octant list */
          cursor2,        /* another cursor to iterate through octant list */
          parent;         /* parent of an octant */
  int level,              /* number of levels of refinement */
      n,                  /* index counter */
      part;               /* partition counter */
  Map *array;             /* map of which processors own which octants */
  int hold;               /* used for calculating partition divisions */
  int ierr = 0;

#ifdef KDDKDD_NEW_BOUNDS_GEOM_QUERY_FN
  double bounds[6] = {DBL_MAX,DBL_MAX,DBL_MAX,-DBL_MAX,-DBL_MAX,-DBL_MAX};
  COORD global_min, global_max;
#endif /* KDDKDD_NEW_BOUNDS_GEOM_QUERY_FN */
  int nroots = 0;
  /*test*/
  /* COORD gmin,gmax; */

  OCT_Global_Info *OCT_info = (OCT_Global_Info *) (zz->LB.Data_Structure);

  ZOLTAN_TRACE_ENTER(zz, yo);
  /*
   * If there are no objects on this processor, do not create a root octant.
   * The partitioner will probably assign objects to this processor
   */
  if(zz->Get_Num_Obj == NULL) {
    fprintf(stderr, "OCT %s\n\t%s\n", "Error in octree load balance:",
	    "Must register ZOLTAN_NUM_OBJ_FN function");
    abort();
  }
  *c3 = num_objs = zz->Get_Num_Obj(zz->Get_Num_Obj_Data, &ierr);
  if (ierr) {
    fprintf(stderr, "OCT [%d] %s: Error returned from user defined "
                    "Get_Num_Obj function.\n", zz->Proc, yo);
    exit (-1);
  }
  ptr1 = NULL;

  ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_get_bounds");
  /* Need A Function To Get The Bounds Of The Local Objects */
  Zoltan_Oct_get_bounds(zz, &ptr1, &num_objs, min, max, oct_wgtflag, c0);
  
#ifndef KDDKDD_NEW_BOUNDS_GEOM_QUERY_FN
  /* For now, don't want to add the new query function to Zoltan. */
  /* Zoltan_Oct_get_bounds appears to compute the global min and max from */
  /* the object input. */
  vector_set(OCT_info->OCT_gmin, min);
  vector_set(OCT_info->OCT_gmax, max);
#else
  /*test*/
  /*getMaxBounds(&gmin, &gmax);*/
  if(zz->Get_Bounds_Geom == NULL) {
    fprintf(stderr, "OCT %s\n\t%s\n", "Error in octree load balance:",
	    "Must register Get_Bounds_Geom function");
    abort();
  }
  zz->Get_Bounds_Geom(zz->Get_Bounds_Geom_Data, bounds, &ierr); 
  
  MPI_Allreduce(&(bounds[0]), &(global_min[0]), 3, 
		MPI_DOUBLE, MPI_MIN, zz->Communicator);
  MPI_Allreduce(&(bounds[3]), &(global_max[0]), 3,
		MPI_DOUBLE, MPI_MAX, zz->Communicator);
  vector_set(OCT_info->OCT_gmin, global_min);
  vector_set(OCT_info->OCT_gmax, global_max);
#endif
  /* 
   * the following code segment was added to create a pseudo global octree
   * needed for the partitioner. The basic idea is to regroup all the
   * regions into something close to an octree partitioning and build the
   * tree from that.
   * NOTE: This way of doing things is very costly, especially when calling
   * this for the first time on a mesh not partitioned in an octree style
   * partitioning.
   */

    level = 0;                                    /* initialize level count */

  /* 
   * if more than 1 processor, need to find what level of refinement needed
   * to initially partition bounding box among the processors 
   */

  
    if(zz->Num_Proc > 1) {
      n = zz->Num_Proc;
      if(OCT_info->OCT_dimension == 2)
	hold = 4;
      else
	hold = 8;
      remainder = hold;
      for(; remainder > 0; level++) {
	int pr = (int)POW(hold, level);
	remainder = n - pr;
      }
      level--;
    }
  ZOLTAN_TRACE_DETAIL(zz, yo, "Before createpartree");

  if(createpartree) {
    /* create the global root octant */
    root = Zoltan_Oct_POct_new(OCT_info);
    Zoltan_Oct_setbounds(root, OCT_info->OCT_gmin, OCT_info->OCT_gmax);
    /* Zoltan_Oct_setOrientation(root, 0); */
  
    /* subdivide to as many levels as calculated */
    for(i=0; i<level; i++) {
      cursor = root;
      while(cursor != NULL) {
	if(Zoltan_Oct_isTerminal(cursor)) {
	  cursor2 = Zoltan_Oct_POct_nextDfs(OCT_info, cursor);
	  Zoltan_Oct_terminal_refine(zz, cursor, 0);
	  cursor = cursor2;
	}
	else 
	  cursor = Zoltan_Oct_POct_nextDfs(OCT_info, cursor);
      }
    }
    
#if 0
    if(zz->Proc == 0)
      for(i=0; i<8; i++)
	if(Zoltan_Oct_child(root, i) == NULL)
	  fprintf(stderr,"NULL child pointer\n");
	else
	  fprintf(stderr, "child %d exists\n", i);
#endif

  ZOLTAN_TRACE_DETAIL(zz, yo, "Before create map array");
    /* this part creates the map array */
    if(OCT_info->OCT_dimension == 2) {
      hold = (int)POW(4, level);                 /* ignoring the z+ octants */
      if(hold == 0)
	hold = 1;
    }
    else
      hold = (int)POW(8, level);

    part = hold / zz->Num_Proc;          /* how many octants per partition */
    remainder = hold % zz->Num_Proc; /* extra octants, not evenly divisible */
    extra = zz->Num_Proc - remainder;/* where to start adding extra octants */
    array = (Map *) ZOLTAN_MALLOC(hold * sizeof(Map));   /* alloc map array */
    if(array == NULL) {
      fprintf(stderr, "OCT ERROR on proc %d, could not allocate array map\n",
	      zz->Proc);
      abort();
    }
    /* initialize variables */
    proc = 0;
    count = 0;
    i = 0;
    cursor = root; 
    while(cursor != NULL) {
      cursor2 = Zoltan_Oct_POct_nextDfs(OCT_info, cursor);
      if((Zoltan_Oct_isTerminal(cursor)) && (i < hold)) {
	if(proc == extra) {
	  part++;
	  extra = -1;
	}
	if(count != part) {
	  array[i].npid = proc;
	  array[i].list = RL_initRootList();
	  Zoltan_Oct_bounds(cursor, min, max);
	  vector_set(array[i].min, min);
	  vector_set(array[i].max, max);
	  count++;
	}
	else {
	  count = 1;
	  proc++;
	  array[i].npid = proc;
	  array[i].list = RL_initRootList();
	  Zoltan_Oct_bounds(cursor, min, max);
	  vector_set(array[i].min, min);
	  vector_set(array[i].max, max);
	}
	if(proc == zz->Proc) {
	  array[i].npid = -1;
          /* KDDKDD Added RL_freeList below.  The 
           * KDDKDD implementation from RPI leaked memory because the 
           * KDDKDD test cases for setting array[i].list were not mutually 
           * KDDKDD exclusive.  Freeing the list produces the result we got
           * KDDKDD before, without the memory leak.
           */
	  /* LGG --  it seems to me that this array[i].list assignment is
	   * not really necessary. It looks as though it has already been
	   * assigned with the same information from the prev if-else
	   * commented out RL_freeList(), and RL_initRootList()
	   */
          /*RL_freeList(&(array[i].list));*/
          /* KDDKDD End addition */
	  /*array[i].list = RL_initRootList();*/
	  parent = Zoltan_Oct_parent(cursor);
	  if(parent != NULL)
	    Zoltan_Oct_setchild(parent, cursor->which, NULL);
	  /* octant into local root list */
 	  Zoltan_Oct_POct_setparent(OCT_info, cursor, NULL, -1);
	  Zoltan_Oct_setMapIdx(cursor, i);
	  nroots++;
	  /* Zoltan_Oct_POct_setparent(OCT_info, cursor, NULL, zz->Proc);     
             octant into local root list */
	}
	i++;
      }
      cursor = cursor2;
    } 
    RootList = Zoltan_Oct_POct_localroots(OCT_info); 
    RootOct = RL_nextRootOctant(&RootList);
    if(RootOct != root) {
      /* KDDKDDFREE changed root to &root to allow root to be reset to NULL */
      Zoltan_Oct_POct_delTree(OCT_info,&root);
    }
    
    OCT_info->map = array;
    OCT_info->mapsize = hold;
  }

  /* 
   * attach the regions to the root... Zoltan_Oct_fix will create the octree
   * starting with the root and subdividing as needed 
   */    
  num_extra = Zoltan_Oct_fix(zz, ptr1, num_objs);
 
  ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_migreg_migrate_orphans");
  Zoltan_Oct_migreg_migrate_orphans(zz, ptr1, num_extra, level, OCT_info->map,
				    c1, c2);

  /* ZOLTAN_FREE(&array); */
  while(ptr1 != NULL) {
    ptr = ptr1->next;
    ZOLTAN_FREE(&(ptr1->Global_ID));
    ZOLTAN_FREE(&(ptr1->Local_ID));
    ZOLTAN_FREE(&ptr1);
    ptr1 = ptr;
  }
  ZOLTAN_TRACE_EXIT(zz, yo);
}
Beispiel #5
0
/*
 * void lb_oct_init();
 *
 * initialize the calls needed to start the octree load balancing rounties
 */
static int lb_oct_init(
  ZZ *zz,                       /* The Zoltan structure with info for
                                   the OCTPART balancer.                    */
  int *num_export,              /* Number of non-local objs assigned to this
                                   processor in the new decomposition.      */
  ZOLTAN_ID_PTR *export_global_ids, /* Returned value: array of global IDs for
                                   non-local objects in this processor's new
                                   decomposition.                           */
  ZOLTAN_ID_PTR *export_local_ids,  /* Returned value:  array of local IDs for
                                   non-local objects in this processor's new
                                   decomposition.                           */
  int **export_procs,           /* Returned value:  array of processor IDs for
                                   processors owning the non-local objects in
                                   this processor's new decomposition.      */
  int **export_to_part,         /* Returned value:  array of partitions to 
                                   which objects are imported.
                                   KDDKDD Assume #parts==#procs.            */
  int oct_dim,                  /* Dimension of method (2D or 3D)           */
  int oct_method,               /* Flag specifying curve to be used.        */
  int oct_maxoctregions,        /* max # of objects in leaves of octree.    */
  int oct_minoctregions,        /* min # of objects in leaves of octree.    */
  int oct_output_level,         /* Flag specifying amount of output.        */
  int oct_wgtflag,              /* Flag specifying use of object weights.   */
  float *part_sizes             /* Array of size zz->Num_Global_Parts
                                   containing the percentage of work to be
                                   assigned to each partition.              */
) 
{
  char *yo = "lb_oct_init";
  OCT_Global_Info *OCT_info;
  int nsentags;                    /* number of tags being sent */
  pRegion export_regs;             /* */
  int nrectags;                    /* number of tags received */
  int kk;
  double time1,time2;              /* timers */
  double timestart,timestop;       /* timers */
  double timers[4];                /* diagnostic timers 
			              0 = start-up time before recursion
				      1 = time before median iterations
				      2 = time in median iterations
				      3 = communication time */
  int    counters[6];              /* diagnostic counts
			              0 = # of median iterations
				      1 = # of objects sent
				      2 = # of objects received
				      3 = most objects this proc ever owns
				      */
  float  c[4];
  int createpartree = 0;
  /*int num_gid_entries = zz->Num_GID;*/
  /*int num_lid_entries = zz->Num_LID;*/
  
  ZOLTAN_TRACE_ENTER(zz, yo);

  MPI_Barrier(zz->Communicator);
  timestart = MPI_Wtime();

  /* initialize timers and counters */
  counters[0] = 0;
  counters[1] = 0;
  counters[2] = 0;
  counters[3] = 0;
  counters[4] = 0;
  counters[5] = 0;
  c[0] = 0;
  c[1] = 0;
  c[2] = 0;
  c[3] = 0;
  timers[1] = 0.0;
  timers[2] = 0.0;
  timers[3] = 0.0;

  nsentags = nrectags = 0;

  if(zz->LB.Data_Structure == NULL) {
    OCT_info = Zoltan_Oct_POct_init(zz, zz->Proc, oct_dim);
    Zoltan_Oct_set_method(OCT_info, oct_method);
    Zoltan_Oct_set_maxregions(oct_maxoctregions);
    Zoltan_Oct_set_minregions(oct_minoctregions);
    createpartree = 1;
  }
  else {
    OCT_info = (OCT_Global_Info *) (zz->LB.Data_Structure);
  }

  /* create the octree structure */
  time1 = MPI_Wtime();

  ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_gen_tree_from_input_data");
  Zoltan_Oct_gen_tree_from_input_data(zz, oct_wgtflag, &counters[1],
				      &counters[2], &counters[3], &c[0], 
				      createpartree);

  time2 = MPI_Wtime();
  timers[0] = time2 - time1;                 /* time took to create octree */
  /* Zoltan_Oct_POct_printResults(OCT_info); */
  /* partition the octree structure */
  time1 = MPI_Wtime();
  ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_dfs_partition");
  /* old call to dfs_paritition: */ 
#if 0
  Zoltan_Oct_dfs_partition(zz, &counters[0], &c[1]);
#else
  /***************************
  if(zz->Proc == 0) {
    int debug_i;
    for(debug_i=0; debug_i<zz->Num_Proc; debug_i++) {
      fprintf(stdout,"Part_size[%d] = %f\n", debug_i, part_sizes[debug_i]);
    }
  }
  ****************************/
  Zoltan_Oct_dfs_partition(zz, &counters[0], &c[1], part_sizes);
#endif
  time2 = MPI_Wtime();
  timers[1] = time2 - time1;              /* time took to partition octree */

  if (oct_output_level > 2) {
    Zoltan_Oct_Plots(zz);
  }

  /* set up tags for migrations */
  time1 = MPI_Wtime();

#if 0  /* KDDKDD -- Count is never used; why is it computed? */
  {
  pRList  RootList;               /* list of all local roots */
  pOctant RootOct;                /* root octree octant */
  int count = 0; 
  RootList = Zoltan_Oct_POct_localroots(OCT_info);
  while((RootOct = RL_nextRootOctant(&RootList))) {
    while(RootOct) {
      if(Zoltan_Oct_isTerminal(RootOct)) {	
	count += Zoltan_Oct_nRegions(RootOct);
      }
      RootOct = Zoltan_Oct_POct_nextDfs(OCT_info, RootOct);
    }
  }
  }
#endif

  ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_dfs_migrate");
  Zoltan_Oct_dfs_migrate(zz, &nsentags, &export_regs, &nrectags, 
	         &c[2], &c[3], &counters[3], &counters[5]);

  ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_fix_tags");
  if (zz->LB.Return_Lists) {
    *num_export = nrectags;
    if (nrectags > 0)
      Zoltan_Oct_fix_tags(zz, export_global_ids, export_local_ids, 
			  export_procs, export_to_part, nrectags,
			  export_regs);
  }

  time2 = MPI_Wtime();
  timers[2] = time2 - time1;               /* time took to setup migration */


#if 0  /* KDDKDD -- Count is never used; why is it computed? */
  {
  /* count the number of objects on this processor */
  pRList  RootList;               /* list of all local roots */
  pOctant RootOct;                /* root octree octant */
  int count = 0; 
  RootList = Zoltan_Oct_POct_localroots(OCT_info);
  while((RootOct = RL_nextRootOctant(&RootList))) {
    while(RootOct) {
      if(Zoltan_Oct_isTerminal(RootOct)) {	
	count += Zoltan_Oct_nRegions(RootOct);
      }
      RootOct = Zoltan_Oct_POct_nextDfs(OCT_info, RootOct);
    }
  }
  }
#endif

  counters[4] = nsentags;
  MPI_Barrier(zz->Communicator);
  timestop = MPI_Wtime();

  if (oct_output_level > 0) {
    ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_print_stats");
    Zoltan_Oct_print_stats(zz, timestop-timestart, timers, counters, c, 
                       oct_output_level);
  }

  for (kk = 0; kk < nrectags; kk++) {
    ZOLTAN_FREE(&(export_regs[kk].Global_ID));
    ZOLTAN_FREE(&(export_regs[kk].Local_ID));
  }
  ZOLTAN_FREE(&export_regs);
  ZOLTAN_TRACE_DETAIL(zz, yo, "Calling Zoltan_Oct_global_clear");
  Zoltan_Oct_global_clear(OCT_info);
  /* KDDKDD Don't understand how re-used octree will work, especially without
   * KDDKDD the Zoltan_Oct_Bounds_Geom function.  For now, we'll delete everything;
   * KDDKDD we can move back to saving some of the tree later.
   */
  Zoltan_Oct_Free_Structure(zz);
  /* KDDKDD END */

  /* Temporary return value until error codes are fully implemented. */
  ZOLTAN_TRACE_EXIT(zz, yo);
  return(ZOLTAN_OK);
}
Beispiel #6
0
/*
 * void Zoltan_Oct_dfs_migrate()
 *
 * sets up information so the migrate octant routines can create the
 * proper export_tags and import_tags arrays
 */
void Zoltan_Oct_dfs_migrate(ZZ *zz, int *nsentags,
		    pRegion *import_regs, int *nrectags, 
		    float *c2, float *c3, int *counter3, int *counter4) 
{
  pRList RootList;                           /* list of the local roots */
  pOctant oct;                               /* octree octant */
  pOctant *docts = NULL;                     /* array of octants being sent */
  int *dpids = NULL;                         /* array of octant pids */
  int dcount;                                /* count of octants being sent */
  int pid;                                   /* processor id */
  int nrecocts;
  OCT_Global_Info *OCT_info = (OCT_Global_Info *)(zz->LB.Data_Structure);
  char *yo = "Zoltan_Oct_dfs_migrate";

  if(Zoltan_Oct_nOctants()) {  /* allocate space for octants being migrated */
    docts = (pOctant *)ZOLTAN_MALLOC(Zoltan_Oct_nOctants() * sizeof(pOctant));
    if(!docts) {
      ZOLTAN_PRINT_ERROR(zz->Proc, yo, "cannot allocate arrays.");
      abort();
    }
    dpids = (int *) ZOLTAN_MALLOC(Zoltan_Oct_nOctants() * sizeof(int));
    if(!dpids) {
      ZOLTAN_PRINT_ERROR(zz->Proc, yo, "cannot allocate arrays.");
      ZOLTAN_FREE(&docts);
      abort();
    }
  }

  dcount=0;

  /* go through the local octants and make sure each has a valid npid */
  RootList = Zoltan_Oct_POct_localroots(OCT_info);  

  while((oct = RL_nextRootOctant(&RootList))) 
    while(oct) {
      pid = Zoltan_Oct_data_newpid(oct);
      if (pid<0 || pid>=zz->Num_Proc) {
	fprintf(stderr,"%d Zoltan_Oct_dfs_migrate: bad dest pid %d\n", zz->Proc, pid);
	abort();
      }
      if (dcount<Zoltan_Oct_nOctants()) {   
	docts[dcount]=oct;
	dpids[dcount]=pid;
      }
      oct=Zoltan_Oct_POct_nextDfs(OCT_info, oct);
      dcount++;
    }

  if (dcount!=Zoltan_Oct_nOctants()) {
    fprintf(stderr, "ERROR: in Zoltan_Oct_dfs_migrate, octant count mismatch (I counted %d but there should be %d)\n",dcount, Zoltan_Oct_nOctants());
 /*    dcount=Zoltan_Oct_nOctants();  */
 /*    abort(); */
  }

  /* setup the import_regs */
  Zoltan_Oct_migrate_objects(zz, docts, dpids, dcount, nsentags,
                     import_regs, nrectags, c2, c3, counter3, counter4);
  Zoltan_Oct_migrate_octants(zz, dpids, docts, dcount, &nrecocts);

  ZOLTAN_FREE(&docts);
  ZOLTAN_FREE(&dpids);
}