/* KDDKDDFREE Changed root to *root to allow NULL from ZOLTAN_FREE to propagate * KDDKDDFREE back to calling routine. */ int Zoltan_Oct_POct_delTree(OCT_Global_Info *OCT_info, pOctant *root) { int i; /* index counter */ pOctant child; /* child of an octant */ if(*root == NULL) return 1; if(Zoltan_Oct_isTerminal(*root)) { if(Zoltan_Oct_nRegions(*root)) Zoltan_Oct_clearRegions(*root); Zoltan_Oct_POct_free(OCT_info, root); } else { for(i=0; i<8; i++) { child = Zoltan_Oct_child(*root, i); if(child != NULL && Zoltan_Oct_POct_local(OCT_info,*root, i)) { Zoltan_Oct_POct_delTree(OCT_info,&child); /* KDDKDDFREE propagate NULL from Zoltan_Oct_POct_delTree to root->child */ (*root)->child[i] = NULL; (*root)->cpid[i] = -1; } /* KDDKDDFREE Added this condition so that tests (in other parts of the * KDDKDDFREE code) for NULL children work */ else if (child != NULL) { (*root)->child[i] = NULL; (*root)->cpid[i] = -1; } /* END KDDKDDFREE */ } Zoltan_Oct_POct_free(OCT_info, root); } return 1; }
/* * Zoltan_Oct_subtree_dref(oct) * * Coarsen octree so that leaf octants do not have less than MINOCTREGIONS * regions. Refinement takes precedence, so coarsening will not take place * unless all subtrees agree on it. */ static int Zoltan_Oct_subtree_dref(ZZ *zz, OCT_Global_Info *OCT_info, pOctant oct) { pOctant child; /* child of an octant */ int coarsen; /* flag to indicate need to coarsen */ int i; /* index counter */ int nregions; /* number of regions */ int total; /* total number of regions */ /* if terminal octant, cannot coarsen on own */ if (Zoltan_Oct_isTerminal(oct)) { nregions=Zoltan_Oct_nRegions(oct); if (nregions > (MAXOCTREGIONS*2) ) { fprintf(stderr, "OCT Zoltan_Oct_subtree_dref: warning: too many (%d) regions " "in oct (id=%d)\n",Zoltan_Oct_nRegions(oct),Zoltan_Oct_id(oct)); return(-1); } else if (nregions < MINOCTREGIONS) return(nregions); else return(-1); } coarsen=1; /* assume to be coarsen */ total=0; /* look at each child, see if they need to be coarsened */ for (i=0; coarsen && i<8; i++) { child = Zoltan_Oct_child(oct,i); /* if child is off processor cannot coarsen */ /* if (!Zoltan_Oct_local(child) ) */ if(!Zoltan_Oct_POct_local(OCT_info, oct, i)) coarsen=0; else { /* get the number of region of the child */ nregions=Zoltan_Oct_subtree_dref(zz, OCT_info,child); if (nregions<0) coarsen=0; else total+=nregions; /* total the region count */ } } /* check if octant can be coarsened */ if (coarsen && total<MAXOCTREGIONS) { Zoltan_Oct_terminal_coarsen(zz, OCT_info,oct); if (total < MINOCTREGIONS) return(total); else return(-1); } return(-1); }
/* * void Zoltan_Oct_costs_free(pOctant octant) * * deletes the cost associated with the octant */ void Zoltan_Oct_costs_free(OCT_Global_Info *OCT_info,pOctant octant) { pOctant children[8]; /* children of the octant */ int i; /* index counter */ Zoltan_Oct_modify_cost(octant, 0); if (!Zoltan_Oct_isTerminal(octant)) { Zoltan_Oct_children(octant,children); for (i=0; i<8; i++) if(Zoltan_Oct_POct_local(OCT_info, octant, i)) Zoltan_Oct_costs_free(OCT_info,children[i]); } }
/* * Zoltan_Oct_terminal_coarsen(oct) * * remove octant's children, accumulating regions * to octant * */ static void Zoltan_Oct_terminal_coarsen(ZZ *zz, OCT_Global_Info *OCT_info, pOctant oct) { pOctant child; /* child of an octant */ pRegion region; /* region associated with an octant */ int i; /* index counter */ pRegion regionlist[8]; /* an array of region lists */ oct_ncoarse++; /* increment coarsening counter */ for(i=0; i<8; i++) { /* get the ith child of an octant */ child = Zoltan_Oct_child(oct,i); /* cannot coarsen if child is off-processor */ /* if(!Zoltan_Oct_POct_local(child)) X */ /* cannot be off-processor */ if(!Zoltan_Oct_POct_local(OCT_info, oct, i)) { fprintf(stderr,"OCT Zoltan_Oct_terminal_coarsen: child not local\n"); abort(); } if(!Zoltan_Oct_isTerminal(child)) { fprintf(stderr,"OCT Zoltan_Oct_terminal_coarsen: child not terminal\n"); abort(); } /* get each child's region list */ regionlist[i] = Zoltan_Oct_regionlist(child); /* delete each child */ /* KDDKDDFREE Change child to &child. */ Zoltan_Oct_POct_free(OCT_info, &child); oct->child[i] = NULL; } oct->numChild = 0; /* * copy contents of each region list into region list * of coarsened parent (which is now a terminal octant) */ for(i=0; i < 8; i++) { region = regionlist[i]; /* go through the regionlist and add to octant */ while(region != NULL) { Zoltan_Oct_addRegion(zz, oct,region); region = region->next; } } }
/* * void Zoltan_Oct_tag_subtree(pOctant octant, int partition_number) * * marks all the octants within the subtree to be in the current partition */ static void Zoltan_Oct_tag_subtree(OCT_Global_Info *OCT_info,pOctant octant, int part) { pOctant children[8]; /* children of octant */ int i; /* index counter */ /* modify NPID so octant know where to migrate to */ Zoltan_Oct_modify_newpid(octant, part); if (Zoltan_Oct_isTerminal(octant)) return; /* if octant has children, have to tag them too */ Zoltan_Oct_children(octant,children); for (i=0; i<8; i++) /* Simple - just visit in order */ /* if (children[i] && Zoltan_Oct_local(OCT_info, children[i])) */ if(children[i] && Zoltan_Oct_POct_local(OCT_info, octant,i)) Zoltan_Oct_tag_subtree(OCT_info,children[i],part); }
/* * Zoltan_Oct_findOctant(oct, coord) * (replaces : PO_findOctant(oct,coord)) * * * find the octant in a subtree containing coord (if coord * is not in the subtree, returns the closest octant in the subtree). * NOTE: return NULL if we hit an off-processor link * */ static pOctant Zoltan_Oct_findOctant(OCT_Global_Info *OCT_info,pOctant oct, COORD coord) { pOctant child; /* child of an octant */ int cnum; /* child number */ /* if octant is terminal, then this is the right octant */ if (Zoltan_Oct_isTerminal(oct)) return(oct); /* find closest child to coord */ cnum = Zoltan_Oct_child_which_wrapper(OCT_info,oct,coord); child = Zoltan_Oct_child(oct, cnum); /* get that child */ /* ATTN: are these local checks necessary? */ /* if ( !Zoltan_Oct_POct_local(child) ) */ if(!Zoltan_Oct_POct_local(OCT_info,oct, cnum)) /* make sure oct is local */ return(NULL); /* recursivly search down the tree */ return(Zoltan_Oct_findOctant(OCT_info,child,coord)); }
/* * float Zoltan_Oct_costs_subtree_compute(pOctant octant, int sequence_number) * * Do a DFS on the octree, calculating the costs for any given subtree. * (Subtree is defined as any octant and all its descendants.) * * Tag every octant visited with a sequence number, automatically * incrementing the sequence number. * * NOTE: must call Zoltan_Oct_costs_init() first */ static float Zoltan_Oct_costs_subtree_compute(OCT_Global_Info *OCT_info,pOctant octant, int *seq) { pOctant children[8]; /* the children of the octant */ float c = 0; /* cost of each subtree */ int i = 0; /* index counter */ /* #ifdef LGG_MIGOCT */ Zoltan_Oct_setID(octant,(*seq)++); /* set new ID for local ordering */ /* #endif */ /* LGG_MIGOCT */ if (!Zoltan_Oct_isTerminal(octant)) { /* get the children of each octant */ Zoltan_Oct_children(octant,children); /* sum the cost for each child to get octant's cost */ for (i=0; i<8; i++) if(children[i] && Zoltan_Oct_POct_local(OCT_info, octant, i)) c += Zoltan_Oct_costs_subtree_compute(OCT_info,children[i], seq); } else /* terminal */ c=Zoltan_Oct_costs_weight(octant); /* set the cost data to the octant */ Zoltan_Oct_modify_cost(octant, c); return(c); }
/* * void Zoltan_Oct_visit(pOctant octant) * * This routine references the following (static) global variables: * * partition - (RW) number of the partition we are currently working on * total - (RW) total cost of all *previous* partitions * pcost - (RW) partition cost for current partition * optcost - (RO) optimal partition cost */ static void Zoltan_Oct_visit(ZZ *zz, pOctant octant, float *part_sizes) { float cost; /* Cost of this octant */ float togo; /* Remaining room in current partition */ float behind; /* How many to make up for from all prev parts */ pOctant children[8]; /* children of the octant */ int i; /* index counter */ COORD origin; /* center of the octant */ double volume; /* volume of the octant */ double prod[3]; /* product of octant origin and its volume */ OCT_Global_Info *OCT_info = (OCT_Global_Info *)(zz->LB.Data_Structure); DFS_Part_Count++; cost = Zoltan_Oct_costs_value(octant); /* get the cost of the octant */ /*behind = partition * optcost - total;*/ /* calcuate how much behind */ behind = (tmpcost*globalcost) - total; /* calcuate how much behind */ if(0) fprintf(stderr,"LGG[%d] pc=%f, c=%f, ps=%f, b=%f\n", partition, pcost, cost, optsize, behind); /* If octant does not overflow the current partition, then use it. */ /*if( cost==0 || (pcost+cost) <= (optcost+behind)) {*/ if(cost==0 || ((pcost+cost) <= (optsize+behind))) { Zoltan_Oct_tag_subtree(OCT_info,octant,partition); /*fprintf(stderr,"LGG[%d] pc=%f, c=%f, ps=%f, b=%f\n", partition, pcost, cost, optsize, behind);*/ pcost+=cost; Zoltan_Oct_origin_volume(octant, origin, &volume); vector_cmult(prod,volume,origin); pmass+=volume; vector_add(pcoord,pcoord,prod); return; } /* * Can't use entire octant because it is too big. If it has suboctants, * visit them. */ if (!Zoltan_Oct_isTerminal(octant)) { Zoltan_Oct_modify_newpid(octant, partition); /* Nonterm */ Zoltan_Oct_children(octant,children); for (i=0; i<8; i++) /* Simple - just visit in order */ if(children[i] && Zoltan_Oct_POct_local(OCT_info, octant,i)) Zoltan_Oct_visit(zz,children[i],part_sizes); return; } /* * No suboctants! * We've hit bottom - have to decide whether to add to * the current partition or start a new one. */ togo = behind + optsize - pcost; /*printf("proc=%d, part=%d, b=%f, pcost=%f, cost=%f, os=%f\n", zz->Proc, partition, behind, pcost, cost, optsize);*/ if ((cost-togo) >= togo) { /*printf("proc=%d, part=%d, togo=%f, pcost=%f, cost=%f, g=%f\n", zz->Proc, partition, togo, pcost, cost, globalcost);*/ /* * End current part and start new one. We are more "over" than "under" */ tmpcost += part_sizes[partition]; partition++; /* Move on to next partition */ while((part_sizes[partition] == 0) && (partition < (zz->Num_Proc - 1))) partition++; optsize = part_sizes[partition]*globalcost; total += pcost; pcost = 0; pmass = 0; vector_set_comp(pcoord,0,0,0); } /*** Add terminal octant to current partition */ Zoltan_Oct_modify_newpid(octant, partition); pcost += cost; Zoltan_Oct_origin_volume(octant, origin, &volume); vector_cmult(prod,volume,origin); pmass += volume; vector_add(pcoord,pcoord,prod); }