void add_to_list( ZZ *zz, int include_procs, /* Flag: Compute proc lists. */ int include_parts, /* Flag: Compute part lists. */ int *proc_array, /* Array of size Num_Proc; entry i is incremented if a found partition is on proc i. */ int *parts, /* partitions that box is in */ int *numparts, /* current number of partitions on list */ int add_part /* partition to be added to list */ ) { /* Adds partitions and processors to arrays that for the box */ int last_proc; /* First processor for partition add_part+1. */ int add_proc; /* First processor for partition add_part. */ int i; if (zz->LB.Remap) add_part = zz->LB.Remap[add_part]; if (include_parts) { /* Add partition to partition list */ parts[*numparts] = add_part; (*numparts)++; } if (include_procs) { /* Increment appropriate entry of proc_array for partition add_part. */ add_proc = Zoltan_LB_Part_To_Proc(zz, add_part, NULL); proc_array[add_proc]++; if (!zz->LB.Single_Proc_Per_Part) { /* Partition may be spread across multiple procs. Include them all. */ if (add_part < zz->LB.Num_Global_Parts - 1) last_proc = Zoltan_LB_Part_To_Proc(zz, add_part+1, NULL); else last_proc = zz->Num_Proc; for (i = add_proc+1; i < last_proc; i++) proc_array[i]++; } } }
static int Zoltan_Reftree_Export_Lists(ZZ *zz, ZOLTAN_REFTREE *subroot, int *num_export, ZOLTAN_ID_PTR *export_global_ids, ZOLTAN_ID_PTR *export_local_ids, int **export_to_partition, int **export_procs) { /* * Function to build the export lists */ int i, ierr; /* * if this subtree has no leaves assigned to this processor then there can be * no exports below it */ if (!subroot->assigned_to_me) return(ZOLTAN_OK); if (subroot->num_child == 0) { /* * if this is a leaf, put it on the export lists if it is to be exported */ if (export_it(subroot,zz,&ierr)) { ZOLTAN_SET_GID(zz, &((*export_global_ids)[(*num_export)*zz->Num_GID]), subroot->global_id); ZOLTAN_SET_LID(zz, &((*export_local_ids)[(*num_export)*zz->Num_LID]), subroot->local_id); (*export_to_partition)[*num_export] = subroot->partition; (*export_procs)[*num_export] = Zoltan_LB_Part_To_Proc(zz,subroot->partition,subroot->global_id); *num_export += 1; } if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) return(ierr); } else { /* * if it is not a leaf, traverse the subtree */ for (i=0; i<subroot->num_child; i++) { ierr = Zoltan_Reftree_Export_Lists(zz, &(subroot->children[i]),num_export, export_global_ids,export_local_ids, export_to_partition,export_procs); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) return(ierr); } } return(ZOLTAN_OK); }
static int export_it(ZOLTAN_REFTREE *subroot, ZZ *zz, int *ierr) { /* * Function to determine if an object belongs on the export list. */ int current_part; /* return TRUE if it is currently assigned to this processor and either the new partition is not the old partition or the new partition is not assigned to this processor */ current_part = get_current_part(subroot,zz,ierr); if (*ierr != ZOLTAN_OK && *ierr != ZOLTAN_WARN) return(FALSE); if ((current_part != subroot->partition || Zoltan_LB_Part_To_Proc(zz,subroot->partition,subroot->global_id) != zz->Proc) && subroot->assigned_to_me) return(TRUE); return(FALSE); }
int Zoltan_Random( ZZ *zz, /* The Zoltan structure. */ float *part_sizes, /* Input: Array of size zz->LB.Num_Global_Parts * zz->Obj_Weight_Dim containing the percentage of work to be assigned to each partition. */ int *num_import, /* Return -1. Random uses only export lists. */ ZOLTAN_ID_PTR *import_global_ids, /* Not used. */ ZOLTAN_ID_PTR *import_local_ids, /* Not used. */ int **import_procs, /* Not used. */ int **import_to_part, /* Not used. */ int *num_export, /* Output: Number of objects to export. */ ZOLTAN_ID_PTR *export_global_ids, /* Output: GIDs to export. */ ZOLTAN_ID_PTR *export_local_ids, /* Output: LIDs to export. */ int **export_procs, /* Output: Processsors to export to. */ int **export_to_part /* Output: Partitions to export to. */ ) { int ierr = ZOLTAN_OK; int i, count, num_obj; int max_export; double rand_frac = 1.0; /* Default is to move all objects. */ ZOLTAN_ID_PTR global_ids = NULL; ZOLTAN_ID_PTR local_ids = NULL; int *parts = NULL; float *dummy = NULL; static char *yo = "Zoltan_Random"; static int first_time = 1; ZOLTAN_TRACE_ENTER(zz, yo); /* Synchronize the random number generator. * This synchronization is needed only for sanity in our nightly testing. * If some other operation (eg., Zoltan_LB_Eval) changes the status of * the random number generator, the answers here will change. They won't * be wrong, but they will be different from our accepted answers. */ if (first_time) { Zoltan_Srand(zz->Seed, NULL); Zoltan_Rand(NULL); first_time=0; } /* No import lists computed. */ *num_import = -1; /* Get parameter values. */ Zoltan_Bind_Param(Random_params, "RANDOM_MOVE_FRACTION", (void *) &rand_frac); Zoltan_Assign_Param_Vals(zz->Params, Random_params, zz->Debug_Level, zz->Proc, zz->Debug_Proc); /* Get list of local objects. */ ierr = Zoltan_Get_Obj_List(zz, &num_obj, &global_ids, &local_ids, 0, &dummy, &parts); /* Bound number of objects to export. */ max_export = 1.5*rand_frac*num_obj; /* Allocate export lists. */ *export_global_ids = *export_local_ids = NULL; *export_procs = *export_to_part = NULL; if (max_export > 0) { if (!Zoltan_Special_Malloc(zz, (void **)export_global_ids, max_export, ZOLTAN_SPECIAL_MALLOC_GID) || !Zoltan_Special_Malloc(zz, (void **)export_local_ids, max_export, ZOLTAN_SPECIAL_MALLOC_LID) || !Zoltan_Special_Malloc(zz, (void **)export_procs, max_export, ZOLTAN_SPECIAL_MALLOC_INT) || !Zoltan_Special_Malloc(zz, (void **)export_to_part, max_export, ZOLTAN_SPECIAL_MALLOC_INT)) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Memory error."); ierr = ZOLTAN_MEMERR; goto End; } } /* Randomly assign ids to procs. */ count=0; for (i=0; i<num_obj; i++){ /* Randomly select some objects to move (export) */ if ((count<max_export) && (Zoltan_Rand(NULL)<rand_frac*ZOLTAN_RAND_MAX)){ /* export_global_ids[count] = global_ids[i]; */ ZOLTAN_SET_GID(zz, &((*export_global_ids)[count*zz->Num_GID]), &global_ids[i*zz->Num_GID]); if (local_ids) /* export_local_ids[count] = local_ids[i]; */ ZOLTAN_SET_LID(zz, &((*export_local_ids)[count*zz->Num_LID]), &local_ids[i*zz->Num_LID]); /* Randomly pick new partition number. */ (*export_to_part)[count] = Zoltan_Rand_InRange(NULL, zz->LB.Num_Global_Parts); /* Processor number is derived from partition number. */ (*export_procs)[count] = Zoltan_LB_Part_To_Proc(zz, (*export_to_part)[count], &global_ids[i*zz->Num_GID]); /* printf("Debug: Export gid %u to part %d and proc %d.\n", (*export_global_ids)[count], (*export_to_part)[count], (*export_procs)[count]); */ ++count; } } (*num_export) = count; End: /* Free local memory, but not export lists. */ ZOLTAN_FREE(&global_ids); ZOLTAN_FREE(&local_ids); ZOLTAN_FREE(&parts); ZOLTAN_TRACE_EXIT(zz, yo); return ierr; }
int Zoltan_Divide_Machine( ZZ *zz, /* The Zoltan structure (not used now, will be used for pointer to machine details */ int obj_wgt_dim, /* Number of different weights (loads). */ float *part_sizes, /* Array of partition sizes, containing percentage of work per partition. (length= obj_wgt_dim*num_parts) */ int proc, /* my processor number in global sense */ MPI_Comm comm, /* communicator for part of machine to be divided */ int *set, /* set that proc is in after divide (lowest global numbered processor in set 0) */ int *proclower, /* lowest numbered processor in first set */ int *procmid, /* lowest numbered processor in second set */ int *num_procs, /* on input, # of procs to be divided on exit, # of procs in the set that proc is in */ int *partlower, /* lowest numbered partition in first set */ int *partmid, /* lowest numbered partition in second set */ int *num_parts, /* on input, # of partitions to be divided on exit, # of parts in the set that proc is in */ double *fractionlo /* actual division of machine: % of work to be assigned to first set (length obj_wgt_dim) */ ) { int i, j, k; int np = 0; /* Number of partitions on procmid */ int fpartmid; /* First partition on procmid */ int totalparts; /* Total number of partitions in input set. */ int totalprocs; /* Total number of processors in input set. */ int dim = obj_wgt_dim; double *sum = NULL; /* This routine divides the current machine (defined by the communicator) * into two pieces. * For now, it simply divides the machine in half. In the future, it will * be a more complicated routine taking into account the architecture of * the machine and communication network. * The two resulting sets contain contiguously numbered processors * and partitions. */ if (dim<1) dim = 1; /* In case obj_wgt_dim==0. */ /* The following statement assumes that proclower is being set correctly in the calling routine if Tflops_Special flag is set */ if (!zz->Tflops_Special) MPI_Allreduce(&proc, proclower, 1, MPI_INT, MPI_MIN, comm); totalparts = *partlower + *num_parts; totalprocs = *proclower + *num_procs; /* Compute procmid as roughly half the number of processors. */ /* Then partmid is the lowest-numbered partition on procmid. */ *procmid = *proclower + (*num_procs - 1)/2 + 1; if (*procmid < totalprocs) Zoltan_LB_Proc_To_Part(zz, *procmid, &np, &fpartmid); if (np > 0) *partmid = fpartmid; else { /* No partitions on procmid; find next part number in procs > procmid */ i = *procmid; while (np == 0 && (++i) < totalprocs) { Zoltan_LB_Proc_To_Part(zz, i, &np, &fpartmid); } if (np) *partmid = fpartmid; else *partmid = totalparts; } /* Check special cases */ if (!zz->LB.Single_Proc_Per_Part && *partmid != totalparts) { i = Zoltan_LB_Part_To_Proc(zz, *partmid, NULL); if (i != *procmid) { /* Partition is spread across several processors. Don't allow mid to fall within a partition; reset procmid so that it falls at a partition boundary. */ if (i != *proclower) { /* set procmid to lowest processor containing partmid */ *procmid = i; } else { /* i == *proclower */ /* Move mid to next partition so that procmid != proclower */ (*partmid)++; *procmid = Zoltan_LB_Part_To_Proc(zz, *partmid, NULL); } } } /* Sum up desired partition sizes. */ sum = (double *)ZOLTAN_MALLOC(dim*sizeof(double)); for (k=0; k<dim; k++){ sum[k] = 0.0; fractionlo[k] = 0.0; } for (i = 0; i < *num_parts; i++) { j = *partlower + i; for (k=0; k<dim; k++){ if (j < *partmid) fractionlo[k] += (double) part_sizes[j*dim+k]; sum[k] += (double) part_sizes[j*dim+k]; } } for (k=0; k<dim; k++) if (sum[k] != 0.0) fractionlo[k] /= sum[k]; if (proc < *procmid) { *set = 0; *num_parts = *partmid - *partlower; *num_procs = *procmid - *proclower; } else { *set = 1; *num_parts = totalparts - *partmid; *num_procs = totalprocs - *procmid; } ZOLTAN_FREE(&sum); return ZOLTAN_OK; }
int Zoltan_LB_Remap( ZZ *zz, int *new_map, /* Upon return, flag indicating whether part or proc assignments actually changed due to remapping. */ int nobj, /* # objs the processor knows about after partitioning */ int *proc, /* processors for the objs; if export_list_flag == 1, proc contains new proc assignment else proc contains old proc assignment Upon return, proc contains remapped new proc assignment regardless of export_list_flag's value. */ int *old_part, /* old partition assignments for the objs */ int *new_part, /* new partition assignments for the objs. Upon return, new_part contains remapped new partition assignments */ int export_list_flag /* Flag indicating whether the algorithm computes export lists or import lists. The HG for matching is built differently depending on whether the algorithm knows export or import info. */ ) { char *yo = "Zoltan_LB_Remap"; int ierr = ZOLTAN_OK; int i; int remap_type; /* Type of remapping to be done: Procs, Parts, or None */ int HEcnt = 0; /* Number of local hyperedges */ int *HEinfo = NULL; /* Array of HE info; for each HE, two pins and one edge weight. Stored as a single vector to minimize communication calls. */ *new_map = 0; /* Determine type of remapping that is appropriate */ ierr = set_remap_type(zz, &remap_type); if (remap_type != ZOLTAN_LB_REMAP_NONE) { /* Build local hyperedges */ if (export_list_flag) ierr = local_HEs_from_export_lists(zz, remap_type, nobj, proc, old_part, new_part, &HEcnt, &HEinfo); else ierr = local_HEs_from_import_lists(zz, remap_type, nobj, proc, old_part, new_part, &HEcnt, &HEinfo); if (ierr < 0) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error building local HEs"); goto End; } /* Gather local hyperedges to each processor; build remap vector */ ierr = gather_and_build_remap(zz, new_map, HEcnt, HEinfo); if (ierr < 0) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from gather_and_build_remap."); goto End; } if (*new_map) { /* Update partition and processor information for algorithms */ for (i = 0; i < nobj; i++) { new_part[i] = zz->LB.Remap[new_part[i]]; proc[i] = Zoltan_LB_Part_To_Proc(zz, new_part[i], NULL); } } } End: ZOLTAN_FREE(&HEinfo); return(ierr); }
int Zoltan_Block( ZZ *zz, /* The Zoltan structure. */ float *part_sizes, /* Input: Array of size zz->LB.Num_Global_Parts containing the percentage of work to be assigned to each partition. */ int *num_import, /* Return -1. We use only export lists. */ ZOLTAN_ID_PTR *import_global_ids, /* Not used. */ ZOLTAN_ID_PTR *import_local_ids, /* Not used. */ int **import_procs, /* Not used. */ int **import_to_part, /* Not used. */ int *num_export, /* Output: Number of objects to export. */ ZOLTAN_ID_PTR *export_global_ids, /* Output: GIDs to export. */ ZOLTAN_ID_PTR *export_local_ids, /* Output: LIDs to export. */ int **export_procs, /* Output: Processsors to export to. */ int **export_to_part /* Output: Partitions to export to. */ ) { int ierr = ZOLTAN_OK; int i, count, num_obj; int wtflag = 0; ZOLTAN_ID_PTR global_ids = NULL; ZOLTAN_ID_PTR local_ids = NULL; int *parts = NULL; int *newparts = NULL; float *wgts = NULL; static char *yo = "Zoltan_Block"; ZOLTAN_TRACE_ENTER(zz, yo); /* No import lists computed. */ *num_import = -1; *export_global_ids = *export_local_ids = NULL; *export_procs = *export_to_part = NULL; /* Get list of local objects. */ if (zz->Obj_Weight_Dim > 1) { ierr = ZOLTAN_FATAL; ZOLTAN_PRINT_ERROR(zz->Proc, yo, "OBJ_WEIGHT_DIM > 1 not supported by LB_METHOD BLOCK."); goto End; } wtflag = (zz->Obj_Weight_Dim>0 ? 1 : 0); ierr = Zoltan_Get_Obj_List(zz, &num_obj, &global_ids, &local_ids, wtflag, &wgts, &parts); /* Compute the new partition numbers. */ newparts = (int *) ZOLTAN_MALLOC(num_obj * sizeof(int)); if (num_obj && (!newparts)){ ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Memory error."); ierr = ZOLTAN_MEMERR; goto End; } block_part(zz, num_obj, wtflag, wgts, part_sizes, newparts); /* Check how many partition numbers changed. */ count=0; for (i=0; i<num_obj; i++){ if (newparts[i] != parts[i]) ++count; } (*num_export) = count; /* Allocate export lists. */ if ((*num_export) > 0) { if (!Zoltan_Special_Malloc(zz, (void **)export_global_ids, (*num_export), ZOLTAN_SPECIAL_MALLOC_GID) || !Zoltan_Special_Malloc(zz, (void **)export_local_ids, (*num_export), ZOLTAN_SPECIAL_MALLOC_LID) || !Zoltan_Special_Malloc(zz, (void **)export_procs, (*num_export), ZOLTAN_SPECIAL_MALLOC_INT) || !Zoltan_Special_Malloc(zz, (void **)export_to_part, (*num_export), ZOLTAN_SPECIAL_MALLOC_INT)) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Memory error."); ierr = ZOLTAN_MEMERR; goto End; } } /* Loop over objects and fill export lists. */ count=0; for (i=0; i<num_obj; i++){ if (newparts[i] != parts[i]){ /* export_global_ids[count] = global_ids[i]; */ ZOLTAN_SET_GID(zz, &((*export_global_ids)[count*zz->Num_GID]), &global_ids[i*zz->Num_GID]); if (local_ids) /* export_local_ids[count] = local_ids[i]; */ ZOLTAN_SET_LID(zz, &((*export_local_ids)[count*zz->Num_LID]), &local_ids[i*zz->Num_LID]); /* Set new partition number. */ (*export_to_part)[count] = newparts[i]; /* Processor is derived from partition number. */ (*export_procs)[count] = Zoltan_LB_Part_To_Proc(zz, (*export_to_part)[count], &global_ids[i*zz->Num_GID]); ++count; } } End: /* Free local memory, but not export lists. */ ZOLTAN_FREE(&global_ids); ZOLTAN_FREE(&local_ids); ZOLTAN_FREE(&parts); ZOLTAN_FREE(&newparts); if (wtflag) ZOLTAN_FREE(&wgts); ZOLTAN_TRACE_EXIT(zz, yo); return ierr; }
static int Zoltan_PHG_Return_Lists ( ZZ *zz, ZHG *zhg, int *num_exp, ZOLTAN_ID_PTR *exp_gids, ZOLTAN_ID_PTR *exp_lids, int **exp_procs, int **exp_to_part) { /* Routine to build export lists of ZOLTAN_LB_FN. */ char *yo = "Zoltan_PHG_Return_Lists"; int i, j; int ierr = ZOLTAN_OK; int eproc; int num_gid_entries = zz->Num_GID; int num_lid_entries = zz->Num_LID; int nObj = zhg->nObj; Partition input_parts = zhg->Input_Parts; ZOLTAN_ID_PTR gids = zhg->GIDs; ZOLTAN_ID_PTR lids = zhg->LIDs; int *outparts = zhg->Output_Parts; if (zz->LB.Return_Lists == ZOLTAN_LB_NO_LISTS) goto End; /* Count number of objects with new partitions or new processors. */ *num_exp = 0; for (i = 0; i < nObj; i++) { eproc = Zoltan_LB_Part_To_Proc(zz, outparts[i], &gids[i*num_gid_entries]); if (outparts[i] != input_parts[i] || zz->Proc != eproc) (*num_exp)++; } /* Allocate memory for return lists. */ if (*num_exp > 0) { if (!Zoltan_Special_Malloc(zz, (void**)exp_gids, *num_exp, ZOLTAN_SPECIAL_MALLOC_GID) || !Zoltan_Special_Malloc(zz, (void**)exp_lids, *num_exp, ZOLTAN_SPECIAL_MALLOC_LID) || !Zoltan_Special_Malloc(zz, (void**)exp_procs, *num_exp, ZOLTAN_SPECIAL_MALLOC_INT) || !Zoltan_Special_Malloc(zz, (void**)exp_to_part, *num_exp, ZOLTAN_SPECIAL_MALLOC_INT)) { Zoltan_Special_Free(zz,(void**)exp_gids, ZOLTAN_SPECIAL_MALLOC_GID); Zoltan_Special_Free(zz,(void**)exp_lids, ZOLTAN_SPECIAL_MALLOC_LID); Zoltan_Special_Free(zz,(void**)exp_procs, ZOLTAN_SPECIAL_MALLOC_INT); Zoltan_Special_Free(zz,(void**)exp_to_part,ZOLTAN_SPECIAL_MALLOC_INT); ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Memory error."); ierr = ZOLTAN_MEMERR; goto End; } for (j = 0, i = 0; i < nObj; i++) { eproc = Zoltan_LB_Part_To_Proc(zz, outparts[i], &gids[i*num_gid_entries]); if (outparts[i] != input_parts[i] || eproc != zz->Proc) { ZOLTAN_SET_GID(zz, &((*exp_gids)[j*num_gid_entries]), &(gids[i*num_gid_entries])); if (num_lid_entries > 0) ZOLTAN_SET_LID(zz, &((*exp_lids)[j*num_lid_entries]), &(lids[i*num_lid_entries])); (*exp_procs) [j] = eproc; (*exp_to_part)[j] = outparts[i]; j++; } } } End: return ierr; }
static int Zoltan_PHG_Output_Parts ( ZZ *zz, ZHG *zhg, Partition hg_parts /* Output partitions relative to the 2D distribution of zhg->HG */ ) { /* Function to map the computed partition from the distribution in HGraph * to the input distribution */ static char *yo = "Zoltan_PHG_Output_Parts"; int i; int msg_tag = 31000; int ierr = ZOLTAN_OK; int nObj = zhg->nObj; int *outparts = NULL; int *sendbuf = NULL; HGraph *phg = &(zhg->HG); zhg->Output_Parts = outparts = (int*) ZOLTAN_MALLOC (nObj * sizeof(int)); if (zhg->VtxPlan != NULL) { /* Get the partition information from the 2D decomposition back to the * original owning processor for each GID. */ sendbuf = (int*) ZOLTAN_MALLOC(zhg->nRecv_GNOs * sizeof(int)); for (i = 0; i < zhg->nRecv_GNOs; i++) sendbuf[i] = hg_parts[VTX_GNO_TO_LNO(phg, zhg->Recv_GNOs[i])]; ierr = Zoltan_Comm_Do_Reverse(zhg->VtxPlan, msg_tag, (char*) sendbuf, sizeof(int), NULL, (char *) outparts); if (ierr) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error from Zoltan_Comm_Do_Reverse"); goto End; } ZOLTAN_FREE(&sendbuf); Zoltan_Comm_Destroy(&(zhg->VtxPlan)); } else { for (i = 0; i < zhg->nRecv_GNOs; i++) outparts[i] = hg_parts[zhg->Recv_GNOs[i]]; } if (zz->LB.Remap_Flag) { int new_map; int *newproc = (int *) ZOLTAN_MALLOC(nObj * sizeof(int)); int num_gid_entries = zz->Num_GID; if (nObj && !newproc) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Memory error."); ierr = ZOLTAN_MEMERR; goto End; } for (i = 0; i < nObj; i++){ newproc[i] = Zoltan_LB_Part_To_Proc(zz, outparts[i], &(zhg->GIDs[i*num_gid_entries])); if (newproc[i]<0){ ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Zoltan_LB_Part_To_Proc returned invalid processor number."); ierr = ZOLTAN_FATAL; ZOLTAN_FREE(&newproc); goto End; } } ierr = Zoltan_LB_Remap(zz, &new_map, nObj, newproc, zhg->Input_Parts, outparts, 1); if (ierr < 0) ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from Zoltan_LB_Remap"); ZOLTAN_FREE(&newproc); } End: if (zhg->Recv_GNOs) ZOLTAN_FREE(&(zhg->Recv_GNOs)); zhg->nRecv_GNOs = 0; return ierr; }
static int Zoltan_Postprocess_Partition (ZZ *zz, ZOLTAN_Third_Graph *gr, ZOLTAN_Third_Part *prt, ZOLTAN_Output_Part *part, ZOLTAN_ID_PTR global_ids, ZOLTAN_ID_PTR local_ids) { static char * yo = "Zoltan_Postprocess_Partition"; int ierr = ZOLTAN_OK; int i, j, nsend; int *newproc, *tmp_part, *tmp_input_part; int num_gid_entries = zz->Num_GID; int num_lid_entries = zz->Num_LID; /* Partitioning */ /* Determine new processor and number of objects to export */ newproc = (int *) ZOLTAN_MALLOC(gr->num_obj * sizeof(int)); if (gr->num_obj && !newproc){ /* Not enough memory */ ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory. "); } for (i=0; i<gr->num_obj; i++){ newproc[i] = Zoltan_LB_Part_To_Proc(zz, (int)prt->part[i], &(global_ids[i*num_gid_entries])); if (newproc[i]<0){ ZOLTAN_FREE(&newproc); ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL, "Zoltan_LB_Part_To_Proc returned invalid processor number."); } } if (zz->LB.Remap_Flag) { int new_map; if (sizeof(indextype) == sizeof(int)){ ierr = Zoltan_LB_Remap(zz, &new_map, gr->num_obj, newproc, (int *)prt->input_part, (int *)prt->part, 1); } else{ tmp_part = (int *)ZOLTAN_MALLOC(sizeof(int) * gr->num_obj); tmp_input_part = (int *)ZOLTAN_MALLOC(sizeof(int) * gr->num_obj); if (gr->num_obj && (!tmp_part || !tmp_input_part)){ ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Not enough memory."); } for (i=0; i < gr->num_obj; i++){ tmp_part[i] = (int)prt->part[i]; tmp_input_part[i] = (int)prt->input_part[i]; } ierr = Zoltan_LB_Remap(zz, &new_map, gr->num_obj, newproc, tmp_input_part, tmp_part, 1); for (i=0; i < gr->num_obj; i++){ prt->part[i] = (indextype)tmp_part[i]; prt->input_part[i] = (indextype)tmp_input_part[i]; } ZOLTAN_FREE(&tmp_part); ZOLTAN_FREE(&tmp_input_part); } if (ierr < 0) { ZOLTAN_FREE(&newproc); ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL, "Error returned from Zoltan_LB_Remap"); } } nsend = 0; for (i=0; i<gr->num_obj; i++){ if ((prt->part[i] != prt->input_part[i]) || ((!part->compute_only_part_changes) && (newproc[i] != zz->Proc))) nsend++; if (zz->Debug_Level >= ZOLTAN_DEBUG_ALL) printf("[%1d] DEBUG: local object %1d: old part = " TPL_IDX_SPEC ", new part = " TPL_IDX_SPEC "\n", zz->Proc, i, prt->input_part[i], prt->part[i]); } /* Create export lists */ if (zz->LB.Return_Lists){ if (zz->LB.Return_Lists == ZOLTAN_LB_CANDIDATE_LISTS) { ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL, "Candidate Lists not supported in GRAPH;" "change RETURN_LISTS parameter."); } part->num_exp = nsend; if (nsend > 0) { if (!Zoltan_Special_Malloc(zz,(void **)part->exp_gids,nsend,ZOLTAN_SPECIAL_MALLOC_GID)) { ZOLTAN_FREE(&newproc); ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Not enough memory."); } if (!Zoltan_Special_Malloc(zz,(void **)part->exp_lids,nsend,ZOLTAN_SPECIAL_MALLOC_LID)) { Zoltan_Special_Free(zz,(void **)part->exp_gids,ZOLTAN_SPECIAL_MALLOC_GID); ZOLTAN_FREE(&newproc); ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Not enough memory."); } if (!Zoltan_Special_Malloc(zz,(void **)part->exp_procs,nsend,ZOLTAN_SPECIAL_MALLOC_INT)) { Zoltan_Special_Free(zz,(void **)part->exp_lids,ZOLTAN_SPECIAL_MALLOC_LID); Zoltan_Special_Free(zz,(void **)part->exp_gids,ZOLTAN_SPECIAL_MALLOC_GID); ZOLTAN_FREE(&newproc); ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Not enough memory."); } if (!Zoltan_Special_Malloc(zz,(void **)part->exp_part,nsend,ZOLTAN_SPECIAL_MALLOC_INT)) { Zoltan_Special_Free(zz,(void **)part->exp_lids,ZOLTAN_SPECIAL_MALLOC_LID); Zoltan_Special_Free(zz,(void **)part->exp_gids,ZOLTAN_SPECIAL_MALLOC_GID); Zoltan_Special_Free(zz,(void **)part->exp_procs,ZOLTAN_SPECIAL_MALLOC_INT); ZOLTAN_FREE(&newproc); ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Not enough memory."); } j = 0; for (i=0; i<gr->num_obj; i++){ if ((prt->part[i] != prt->input_part[i]) || ((!part->compute_only_part_changes) && (newproc[i] != zz->Proc))){ /* Object should move to new partition or processor */ ZOLTAN_SET_GID(zz, &((*(part->exp_gids))[j*num_gid_entries]), &(global_ids[i*num_gid_entries])); if (num_lid_entries) ZOLTAN_SET_LID(zz, &((*(part->exp_lids))[j*num_lid_entries]), &(local_ids[i*num_lid_entries])); (*(part->exp_part))[j] = (int)prt->part[i]; (*(part->exp_procs))[j] = newproc[i]; /* printf("[%1d] Debug: Move object %1d to part %1d, proc %1d\n", */ /* zz->Proc, i, prt->part[i], newproc[i]); */ j++; } } } } ZOLTAN_FREE(&newproc); return (ZOLTAN_OK); }
/* Point drop for refinement after above partitioning */ int Zoltan_HSFC_Point_Assign ( ZZ *zz, double *x, int *proc, int *part) { double scaled[3]; double pt[3]; double fsfc; Partition *p; int i; int dim; HSFC_Data *d; int err; char *yo = "Zoltan_HSFC_Point_Assign"; ZOLTAN_TRACE_ENTER (zz, yo); d = (HSFC_Data *) zz->LB.Data_Structure; if (d == NULL) ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "No Decomposition Data available; use KEEP_CUTS parameter."); for (i=0; i<d->ndimension; i++){ pt[i] = x[i]; /* we don't want to change caller's "x" */ } if (d->tran.Target_Dim > 0){ /* degenerate geometry */ dim = d->tran.Target_Dim; Zoltan_Transform_Point(pt, d->tran.Transformation, d->tran.Permutation, d->ndimension, dim, pt); } else{ dim = d->ndimension; } /* Calculate scaled coordinates, calculate HSFC coordinate */ for (i = 0; i < dim; i++) { scaled[i] = (pt[i] - d->bbox_lo[i]) / d->bbox_extent[i]; if (scaled[i] < HSFC_EPSILON) scaled[i] = HSFC_EPSILON; if (scaled[i] > 1.0 - HSFC_EPSILON) scaled[i] = 1.0 - HSFC_EPSILON; } fsfc = d->fhsfc (zz, scaled); /* Note, this is a function call */ /* Find partition containing point and return its number */ p = (Partition *) bsearch (&fsfc, d->final_partition, zz->LB.Num_Global_Parts, sizeof (Partition), Zoltan_HSFC_compare); if (p == NULL) ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "programming error, shouldn't happen"); if (part != NULL) { if (zz->LB.Remap) *part = zz->LB.Remap[p->index]; else *part = p->index; } if (proc != NULL) { if (zz->LB.Remap) *proc = Zoltan_LB_Part_To_Proc(zz, zz->LB.Remap[p->index], NULL); else *proc = Zoltan_LB_Part_To_Proc(zz, p->index, NULL); } err = ZOLTAN_OK; End: ZOLTAN_TRACE_EXIT (zz, yo); return err; }