Zoltan is added as thirdParty package

This commit is contained in:
Hamidreza
2025-05-15 21:58:43 +03:30
parent 83a6e4baa1
commit d7479cf1bd
3392 changed files with 318142 additions and 1 deletions

883
thirdParty/Zoltan/src/hsfc/hsfc.c vendored Normal file
View File

@ -0,0 +1,883 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
/* Andy Bauer's Space Filling Curve (SFC) partitioning modified by Bob Heaphy */
/* This code uses the Inverse Hilbert Space-Filling Curve to map 1-3 dimensional
problems to the unit interval, [0,1]. It then partitions the unit interval
into non-overlapping segments each containing equal weights of computational
objects. For details concerning the algorithm, please read the Developers
Guide. For instructions on using this partitioning algorithm, please read the
Users Guide.
*/
#include "hsfc.h"
#include "hsfc_params.h"
#include "zz_const.h"
#include <float.h>
/****************************************************************************/
static int partition_stats(ZZ *zz, int ndots,
Dots *dots, int *obj_sizes,
float *work_fraction, int *parts, int *new_parts);
/****************************************************************************/
/* Zoltan_HSFC - Main routine, Load Balance: Hilbert Space Filling Curve */
int Zoltan_HSFC(
ZZ *zz,
float *part_sizes, /* Input: Array of size zz->Num_Global_Parts
containing the percentage of work to be
assigned to each partition. */
int *num_import, /* -1 indicates imports not used */
ZOLTAN_ID_PTR *import_gids, /* ignored */
ZOLTAN_ID_PTR *import_lids, /* ignored */
int **import_procs, /* ignored */
int **import_to_part, /* ignored */
int *num_export, /* number of objects to export to lb */
ZOLTAN_ID_PTR *export_gids, /* list of Global IDs of exported objects */
ZOLTAN_ID_PTR *export_lids, /* optional: Local IDs of exported objects */
int **export_procs, /* corresponding processor destinations */
int **export_to_parts /* partition assignments for export */
)
{
/* malloc'd arrays that need to be freed before completion */
Dots *dots = NULL;
ZOLTAN_ID_PTR gids = NULL;
ZOLTAN_ID_PTR lids = NULL;
int *parts = NULL; /* initial partitions for objects */
int *new_proc = NULL; /* new processor assignments for dots */
int *new_part = NULL; /* new partition assignments for dots */
Partition *grand_partition = NULL; /* fine partition of [0,1] */
double *partition = NULL; /* course partition of [0,1] */
double *grand_weight = NULL; /* "binned" weights on grand partition */
double *temp_weight = NULL; /* local binning before MPI_Allreduce */
float *weights = NULL; /* to get original local dots' wt vec */
float *target = NULL; /* desired weight in each partition */
float *work_fraction = NULL; /* % of load in each partition */
double *delta = NULL; /* refinement interval */
double *tsum = NULL;
double *geom_vec = NULL; /* Temporary coordinates array. */
HSFC_Data *d = NULL; /* pointer to persistant data storage */
/* other (non malloc'd) variables */
int ndots; /* number of dots on this machine */
int pcount; /* number of partitions in grand partition */
int new_map; /* flag indicating whether parts were
remapped */
double start_time=0.0L, end_time=0.0L; /* used to time execution */
double start_stat_time=0.0L, total_stat_time=0.0L;
double total_weight = 0.0;
/* temporary variables, loop counters, etc. */
int tmp;
int i, j, k; /* loop counters */
double sum;
int done, out_of_tolerance=0; /* binary flags */
Partition *p = NULL;
int loop = 0;
double actual, desired, correction;
double temp, in[6], out[6];
int err;
int final_output;
int param;
int idummy;
double ddummy;
int dim;
char *yo = "Zoltan_HSFC";
/* begin program with trace, timing, and initializations */
ZOLTAN_TRACE_ENTER (zz, yo);
if (zz->Debug_Level >= ZOLTAN_DEBUG_ATIME) {
MPI_Barrier(zz->Communicator);
start_time = Zoltan_Time(zz->Timer);
}
*num_export = *num_import = -1; /* in case of early error exit */
Zoltan_Bind_Param (HSFC_params, "FINAL_OUTPUT", (void*) &final_output);
Zoltan_Bind_Param (HSFC_params, "KEEP_CUTS", (void*) &param);
Zoltan_Bind_Param (HSFC_params, "REDUCE_DIMENSIONS", (void*) &idummy);
Zoltan_Bind_Param (HSFC_params, "DEGENERATE_RATIO", (void*) &ddummy);
param = idummy = final_output = 0;
ddummy = 0.0;
Zoltan_Assign_Param_Vals (zz->Params, HSFC_params, zz->Debug_Level, zz->Proc,
zz->Debug_Proc);
if (sizeof (int) != 4) {
ZOLTAN_HSFC_ERROR(ZOLTAN_FATAL,
"HSFC implemented only for 32-bit integers");
}
/* allocate persistent storage required by box assign and point assign */
if (zz->LB.Data_Structure == NULL){
zz->LB.Data_Structure = (void*) ZOLTAN_MALLOC (sizeof (HSFC_Data));
if (zz->LB.Data_Structure == NULL){
ZOLTAN_HSFC_ERROR(ZOLTAN_MEMERR, "Error returned by malloc");
}
d = (HSFC_Data*) zz->LB.Data_Structure;
memset ((void*)d, 0, sizeof (HSFC_Data));
Zoltan_Initialize_Transformation(&(d->tran));
}
else{
d = (HSFC_Data*) zz->LB.Data_Structure;
ZOLTAN_FREE (&d->final_partition);
}
/* obtain dot information: gids, lids, weights */
err = Zoltan_Get_Obj_List (zz, &ndots, &gids, &lids, zz->Obj_Weight_Dim,
&weights, &parts);
if (err)
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "Error in Zoltan_Get_Obj_List.");
MPI_Allreduce(&ndots, &i, 1, MPI_INT, MPI_MAX, zz->Communicator);
if (i < 1){
if (zz->Proc == 0)
ZOLTAN_PRINT_WARN(zz->Proc, yo, "No objects to partition")
*num_export = 0;
goto EndReporting;
}
/* allocate storage for dots and their corresponding gids, lids, weights */
if (ndots > 0) {
dots = (Dots*) ZOLTAN_MALLOC (sizeof(Dots) * ndots);
if (dots == NULL)
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Failed to ZOLTAN_MALLOC dots.");
}
/* set dot weights from object weights, if none set to one */
if (zz->Obj_Weight_Dim > 1)
ZOLTAN_PRINT_WARN(zz->Proc, yo,"Only one weight per GID can be processed");
if (zz->Obj_Weight_Dim < 1)
for (i = 0; i < ndots; i++)
dots[i].weight = DEFAULT_WEIGHT;
else
for (i = 0; i < ndots; i++)
dots[i].weight = weights [i * zz->Obj_Weight_Dim]; /* 1 dimension only */
ZOLTAN_FREE (&weights);
/* get dots' coordinates */
err = Zoltan_Get_Coordinates(zz, ndots, gids, lids, &(d->ndimension),
&geom_vec);
if (err != 0)
ZOLTAN_HSFC_ERROR(ZOLTAN_FATAL, "Error in Zoltan_Get_Coordinates.");
if (d->tran.Target_Dim > 0){ /* degenerate geometry */
dim = d->tran.Target_Dim;
}
else{
dim = d->ndimension;
}
for (i = 0, tmp=0; i < ndots; i++, tmp += d->ndimension) {
for (j = 0; j < d->ndimension; j++){
dots[i].x[j] = geom_vec[tmp + j];
}
}
ZOLTAN_FREE(&geom_vec);
ZOLTAN_TRACE_DETAIL (zz, yo, "Obtained dot information");
/* allocate storage for partitions and "binned" weights */
pcount = N * (zz->LB.Num_Global_Parts - 1) + 1;
target =(float*) ZOLTAN_MALLOC(sizeof(float) *zz->LB.Num_Global_Parts);
partition =(double*)ZOLTAN_MALLOC(sizeof(double)*zz->LB.Num_Global_Parts);
delta =(double*)ZOLTAN_MALLOC(sizeof(double)*zz->LB.Num_Global_Parts);
tsum =(double*)ZOLTAN_MALLOC(sizeof(double)*zz->LB.Num_Global_Parts);
grand_weight =(double*)ZOLTAN_MALLOC(sizeof(double) * pcount*3);/*max,min,sum*/
temp_weight =(double*)ZOLTAN_MALLOC(sizeof(double) * pcount*3);/*max,min,sum*/
grand_partition = (Partition*)ZOLTAN_MALLOC (sizeof (Partition) * pcount);
if (target == NULL || partition == NULL || delta == NULL || tsum == NULL
|| grand_weight == NULL || temp_weight == NULL || grand_partition == NULL)
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Malloc error for partitions, targets");
if (zz->Obj_Weight_Dim <= 1)
work_fraction = part_sizes;
else {
work_fraction =(float*)ZOLTAN_MALLOC(sizeof(float)*zz->LB.Num_Global_Parts);
if (work_fraction == NULL)
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Malloc error for work_fraction");
/* HSFC supports only the first weight; select the appropriate part_sizes */
/* entries for the first weight. */
for (i = 0; i < zz->LB.Num_Global_Parts; i++)
work_fraction[i] = part_sizes[i*zz->Obj_Weight_Dim];
}
/* Get bounding box, smallest coordinate aligned box containing all dots */
for (i = 0; i < dim; i++)
out[i] = in[i] = -HUGE_VAL;
for (i = dim; i < 2*dim; i++)
out[i] = in[i] = HUGE_VAL;
for (i = 0; i < ndots; i++) {
for (j = 0; j < dim; j++) {
/* get maximum bound box coordinates: */
if(dots[i].x[j]>in[j]) in[j]=dots[i].x[j];
}
for (j = dim; j < 2*dim; j++) {
/* get minimum bound box coordinates: */
if(dots[i].x[j-dim]<in[j]) in[j]=dots[i].x[j-dim];
}
}
err = MPI_Allreduce(in,out,dim,MPI_DOUBLE,MPI_MAX,zz->Communicator);
err = MPI_Allreduce(in+dim,out+dim,dim,MPI_DOUBLE,MPI_MIN,zz->Communicator);
if (err != MPI_SUCCESS)
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "Bounding box MPI_Allreduce error");
/* Enlarge bounding box to make points on faces become interior (Andy) */
for (i = 0; i < dim; i++) {
temp = (out[i] - out[i+dim]) * HSFC_EPSILON;
d->bbox_hi[i] = out[i] + temp;
d->bbox_lo[i] = out[i+dim] - temp;
d->bbox_extent[i] = d->bbox_hi[i] - d->bbox_lo[i];
if (d->bbox_extent[i] == 0.0)
d->bbox_extent[i] = 1.0; /* degenerate axis, avoid divide by zero */
}
ZOLTAN_TRACE_DETAIL (zz, yo, "Determined problem bounding box");
/* Save appropriate HSFC function for later use below and in point_assign() */
if (dim== 1) d->fhsfc = Zoltan_HSFC_InvHilbert1d;
else if (dim== 2) d->fhsfc = Zoltan_HSFC_InvHilbert2d;
else if (dim== 3) d->fhsfc = Zoltan_HSFC_InvHilbert3d;
/* Scale coordinates to bounding box, compute HSFC */
for (i = 0; i < ndots; i++) {
for (j = 0; j < dim; j++)
out[j] = (dots[i].x[j] - d->bbox_lo[j]) / d->bbox_extent[j];
dots[i].fsfc = d->fhsfc (zz, out); /* Note, this is a function call */
}
/* Initialize grand partition to equally spaced intervals on [0,1] */
for (i = 0; i < pcount; i++) {
grand_partition[i].index = i;
grand_partition[i].r = (i+1) / (double)pcount;
grand_partition[i].l = i / (double)pcount;
}
grand_partition[pcount-1].r += (2.0 * FLT_EPSILON) ;
ZOLTAN_TRACE_DETAIL (zz, yo, "About to enter main loop\n");
/* This loop is the real guts of the partitioning algorithm */
for (loop = 0; loop < MAX_LOOPS; loop++) {
/* initialize bins, DEFAULT_BIN_MAX is less than any possible max,... */
for (i = 0; i < pcount; i++)
grand_weight[i] = temp_weight[i] = 0.0; /* SUM */
for (i = pcount; i < 2*pcount; i++)
grand_weight[i] = temp_weight[i] = DEFAULT_BIN_MAX;
for (i = 2*pcount; i < 3*pcount; i++)
grand_weight[i] = temp_weight[i] = DEFAULT_BIN_MIN;
/* bin weights, max, min for all dots using current grand partition */
for (i = 0; i < ndots; i++) {
if (loop > 0
&& dots[i].fsfc < grand_partition[dots[i].part].r
&& dots[i].fsfc >= grand_partition[dots[i].part].l)
p = &grand_partition[dots[i].part]; /* short cut if unchanged */
else
p = (Partition*) bsearch (&dots[i].fsfc, grand_partition, pcount,
sizeof(Partition), Zoltan_HSFC_compare);
if (p == NULL) /* programming error if NULL */
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "BSEARCH RETURNED ERROR");
dots[i].part = p->index;
temp_weight [p->index] += dots[i].weight; /* local wt sum */
if (dots[i].fsfc > temp_weight[p->index + pcount])
temp_weight [p->index + pcount] = dots[i].fsfc; /*local indx max*/
if (dots[i].fsfc < temp_weight[p->index + 2 * pcount])
temp_weight [p->index + pcount * 2] = dots[i].fsfc;/*local indx min*/
}
err = MPI_Allreduce(temp_weight, grand_weight, pcount,
MPI_DOUBLE, MPI_SUM, zz->Communicator);
err = MPI_Allreduce(temp_weight+pcount, grand_weight+pcount, pcount,
MPI_DOUBLE, MPI_MAX, zz->Communicator);
err = MPI_Allreduce(temp_weight+2*pcount, grand_weight+2*pcount, pcount,
MPI_DOUBLE, MPI_MIN, zz->Communicator);
if (err != MPI_SUCCESS)
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "MPI_Allreduce returned error");
ZOLTAN_TRACE_DETAIL (zz, yo, "Complete main loop MPI_Allreduce");
/* Allocate ideal weights per partition -- once is sufficient */
if (loop == 0) {
total_weight = 0.0;
for (i = 0; i < pcount; i++)
total_weight += grand_weight[i];
for (i = 0; i < zz->LB.Num_Global_Parts; i++)
target[i] = work_fraction[i] * total_weight;
}
/* debug: print target and grand partition values */
if (zz->Debug_Level >= ZOLTAN_DEBUG_ALL && zz->Proc == 0) {
printf ("\n\nTarget %.2f, loop %d\n", target[0], loop);
for (i = 0; i < pcount; i++)
printf ("Grand Partition %3d, weight %3.0f, left = %0.6f, right"
"= %0.6f, delta = %19.14f\n", i, grand_weight[i],
grand_partition[i].l, grand_partition[i].r, grand_weight[i+pcount]
- grand_weight[i+2*pcount]);
}
/* create new partition by summing contiguous bins l to r until target */
for (i = 0; i < pcount; i++) /* since grand weight modified below */
temp_weight[i] = grand_weight[i];
for (k = 0; k < zz->LB.Num_Global_Parts; k++) {
partition[k] = 1.0;
delta[k] = 0.0;
}
done = 1; /* flag, 1 means done is true */
sum = 0.0;
for (k = i = 0; i < pcount && k < zz->LB.Num_Global_Parts - 1; )
if (sum + grand_weight[i] <= target[k])
sum += grand_weight[i++];
else {
/* stop current summing to set new partition coordinate */
partition[k] = grand_partition[i].l;
delta[k] = (grand_partition[i].r - grand_partition[i].l)/(N-1);
/* If a "bin" holds multiple processors worth of dots: */
if (k > 0 && partition[k-1] >= partition[k]) {
partition[k] = 0.5 * (grand_partition[i].r - partition[k-1])
+ partition[k-1];
delta[k] = delta[k-1] = delta[k-1] * 0.5;
}
/* max - min test if current bin is capable of further refinement */
temp = grand_weight[i+pcount] - grand_weight[i+2*pcount];
if (i < pcount && temp > REFINEMENT_LIMIT)
done = 0; /* not done, at least this bin is refinable */
/* get ready for next loop */
grand_weight[i] -= (target[k] - sum); /* prevents systematic bias */
sum = 0.0;
k++;
}
if (done) /* this is the actual loop stopping criterion */
break; /* no bin with "cut" is refinable, time to quit */
/* determine new grand partition by refining new partition boundary */
for (k = i = 0; i < zz->LB.Num_Global_Parts - 1; i++)
for (j = 0; j < N; j++, k++)
grand_partition[k+1].l = grand_partition[k].r
= partition[i] + j * delta[i];
grand_partition[0].l = 0.0;
grand_partition[pcount-1].r = 1.0 + (2.0 * FLT_EPSILON) ;
} /* end of loop */
ZOLTAN_TRACE_DETAIL (zz, yo, "Exited main loop");
Zoltan_Multifree (__FILE__, __LINE__, 3, &grand_weight, &partition, &delta);
if (zz->Obj_Weight_Dim > 1)
ZOLTAN_FREE (&work_fraction);
d->final_partition = (Partition*) ZOLTAN_MALLOC(sizeof(Partition)
* zz->LB.Num_Global_Parts);
if (d->final_partition == NULL)
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Unable to malloc final_partition");
/* initializations required to start loop below */
d->final_partition[0].l = 0.0;
for (k = 0; k < zz->LB.Num_Global_Parts; k++) {
tsum[k] = 0.0;
d->final_partition[k].index = k;
}
actual = desired = total_weight;
i = k = 0;
correction = 1.0;
/* set new partition on [0,1] by summing grand_weights until targets met */
/* k counts partitions and i counts grand partitions */
while (1) {
if (k >= zz->LB.Num_Global_Parts || i >= pcount)
break;
/* case: current partition should remain empty */
if (target[k] == 0.0) {
d->final_partition[k].r = grand_partition[i].l;
k++;
if (k < zz->LB.Num_Global_Parts)
d->final_partition[k].l = grand_partition[i].l;
continue;
}
/* case: current bin weights fit into current partition */
temp = correction * target[k];
if (tsum[k] + temp_weight[i] <= temp) {
tsum[k] += temp_weight[i];
i++;
continue;
}
/* case: current bin weights overfill current partition */
if (temp - tsum[k] > tsum[k] + temp_weight[i] - temp) {
tsum[k] += temp_weight[i];
actual -= tsum[k];
desired -= target[k];
d->final_partition[k].r = grand_partition[i].r;
k++;
if (k < zz->LB.Num_Global_Parts)
d->final_partition[k].l = grand_partition[i].r;
i++;
}
else { /* don't include current bin weight in current partition */
actual -= tsum[k];
desired -= target[k];
d->final_partition[k].r = grand_partition[i].l;
k++;
if (k < zz->LB.Num_Global_Parts)
d->final_partition[k].l = grand_partition[i].l;
}
/* correct target[]s for cumulative partitioning errors (Bruce H.) */
correction = ((desired == 0) ? 1.0 : actual/desired);
}
/* check if we didn't close out last sum, fix right boundary if needed */
if (i == pcount && k < zz->LB.Num_Global_Parts)
{
d->final_partition[k].r = 1.0 + (2.0 * FLT_EPSILON) ;
k++;
}
/* if last partition(s) is empty, loop stops w/o setting final_partition(s) */
for (i = k; i < zz->LB.Num_Global_Parts; i++) {
d->final_partition[i].r = 1.0 + (2.0 * FLT_EPSILON);
d->final_partition[i].l = 1.0 + (2.0 * FLT_EPSILON);
}
out_of_tolerance = 0;
for (k = 0; k < zz->LB.Num_Global_Parts; k++)
if (tsum[k] > target[k] * zz->LB.Imbalance_Tol[0])
out_of_tolerance = 1;
ZOLTAN_TRACE_DETAIL (zz, yo, "Determined final partition");
new_part = (int *) ZOLTAN_MALLOC(2 * ndots * sizeof(int));
if (ndots && !new_part)
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Memory error.");
new_proc = new_part + ndots;
/* Set the final part number for all dots */
for (i = 0; i < ndots; i++) {
j = dots[i].part / N; /* grand_partition is N times final_partition parts*/
if (dots[i].fsfc < d->final_partition[j].r
&& dots[i].fsfc >= d->final_partition[j].l)
p = d->final_partition + j;
else
p = (Partition*) bsearch (&dots[i].fsfc, d->final_partition,
zz->LB.Num_Global_Parts, sizeof(Partition), Zoltan_HSFC_compare);
if (p == NULL)
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "BSEARCH RETURNED ERROR");
dots[i].part = p->index;
new_part[i] = dots[i].part;
new_proc[i] = Zoltan_LB_Part_To_Proc(zz, p->index,
gids + i * zz->Num_GID);
}
/* Remap partitions to reduce data movement. */
if (zz->LB.Remap_Flag) {
err = Zoltan_LB_Remap(zz, &new_map, ndots, new_proc, parts, new_part, 1);
if (err < 0)
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL,"Error returned from Zoltan_LB_Remap");
}
total_stat_time = 0.0;
if (final_output){
int *objSizes = NULL;
if (zz->Debug_Level >= ZOLTAN_DEBUG_ATIME) {
start_stat_time = Zoltan_Time(zz->Timer);
}
if ((ndots > 0) && ((zz->Get_Obj_Size_Multi) || (zz->Get_Obj_Size))){
objSizes = (int *) ZOLTAN_MALLOC(ndots * sizeof(int));
if (!objSizes){
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Failed to ZOLTAN_MALLOC sizes.");
}
if (zz->Get_Obj_Size_Multi) {
zz->Get_Obj_Size_Multi(zz->Get_Obj_Size_Multi_Data,
zz->Num_GID, zz->Num_LID, ndots,
gids, lids, objSizes, &err);
if (err < 0) {
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "Error returned from "
"ZOLTAN_OBJ_SIZE_MULTI function.");
}
}
else if (zz->Get_Obj_Size) {
for (i = 0; i < ndots; i++) {
ZOLTAN_ID_PTR lid = (zz->Num_LID ? &(lids[i*zz->Num_LID]):NULL);
objSizes[i] = zz->Get_Obj_Size(zz->Get_Obj_Size_Data,
zz->Num_GID, zz->Num_LID,
&(gids[i*zz->Num_GID]),
lid, &err);
if (err < 0) {
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "Error returned from "
"ZOLTAN_OBJ_SIZE function.");
}
}
}
}
err = partition_stats(zz, ndots, dots, objSizes, work_fraction,
parts, new_part);
if (err != ZOLTAN_OK){
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "statistics");
}
if (zz->Debug_Level >= ZOLTAN_DEBUG_ATIME) {
total_stat_time = Zoltan_Time(zz->Timer) - start_stat_time;
}
ZOLTAN_FREE(&objSizes);
}
/* free stuff before next required allocations */
Zoltan_Multifree (__FILE__, __LINE__, 3, &temp_weight, &grand_partition,
&target);
/* Count the number of objects to export from this processor */
*num_export = 0;
for (i = 0; i < ndots; i++) {
if (new_part[i] != parts[i] || zz->Proc != new_proc[i])
++(*num_export);
}
EndReporting:
if (!zz->LB.Return_Lists)
*num_export = -1;
else if (zz->LB.Return_Lists == ZOLTAN_LB_CANDIDATE_LISTS) {
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL, "Candidate Lists not supported in HSFC;"
"change RETURN_LISTS parameter");
}
else if (*num_export > 0) {
/* allocate storage for export information and fill in data */
if (!Zoltan_Special_Malloc (zz, (void**) export_gids, *num_export,
ZOLTAN_SPECIAL_MALLOC_GID))
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Failed to malloc global ids");
if (zz->Num_LID > 0) {
if (!Zoltan_Special_Malloc (zz, (void**) export_lids, *num_export,
ZOLTAN_SPECIAL_MALLOC_LID)){
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Failed to malloc local ids");
}
}
if (!Zoltan_Special_Malloc (zz, (void**) export_procs, *num_export,
ZOLTAN_SPECIAL_MALLOC_INT))
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Failed to malloc export proc list");
if (!Zoltan_Special_Malloc (zz, (void**) export_to_parts, *num_export,
ZOLTAN_SPECIAL_MALLOC_INT))
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Failed to malloc export part list");
/* Fill in export arrays */
for (j = i = 0; i < ndots; i++) {
if (new_part[i] != parts[i] || zz->Proc != new_proc[i]) {
*((*export_procs) +j) = new_proc[i];
*((*export_to_parts)+j) = new_part[i];
if (zz->Num_GID > 0)
ZOLTAN_SET_GID(zz, *export_gids+j*zz->Num_GID, gids+i*zz->Num_GID);
if (zz->Num_LID > 0)
ZOLTAN_SET_LID(zz, *export_lids+j*zz->Num_LID, lids+i*zz->Num_LID);
j++;
}
}
}
ZOLTAN_TRACE_DETAIL (zz, yo, "Filled in export information");
/* DEBUG: print useful information */
if (zz->Debug_Level >= ZOLTAN_DEBUG_ALL && zz->Proc == 0)
printf ("<%d> Number of loops = %d\n", zz->Proc, loop + 1);
if (zz->Debug_Level >= ZOLTAN_DEBUG_LIST && zz->Proc == 0)
printf ("<%d> export count %d, ndots %d\n", zz->Proc, *num_export, ndots);
if (zz->Debug_Level >= ZOLTAN_DEBUG_LIST)
for (i = 0; i < ndots; i++) {
printf ("<%d> GID: ", zz->Proc);
ZOLTAN_PRINT_GID (zz, &gids[i*zz->Num_GID]);
if (lids || zz->Num_LID > 0) {
printf (" LID: ");
ZOLTAN_PRINT_LID (zz, &lids[i*zz->Num_LID]);
}
printf (" Part: %d Weight %.1f HSFC %.6f\n", new_part[i],
dots[i].weight, dots[i].fsfc);
printf ("PROC %d DOT " ZOLTAN_ID_SPEC "\n", p->index, gids[i]);
}
ZOLTAN_FREE(&new_part);
/* done, do we keep data structure for box drop and point drop? */
if (!param && /* we don't need partitions */
(d->tran.Target_Dim < 0)){ /* we don't need transformation */
Zoltan_HSFC_Free_Structure (zz);
}
/* really done now, now free dynamic storage and exit with return status */
err = ((out_of_tolerance) ? ZOLTAN_WARN : ZOLTAN_OK);
if (zz->Proc == 0 && err == ZOLTAN_WARN && zz->Debug_Level >ZOLTAN_DEBUG_NONE)
ZOLTAN_PRINT_WARN (zz->Proc, yo, "HSFC: Imbalance exceeds user limit");
End:
if (err != ZOLTAN_OK && err != ZOLTAN_WARN) {
Zoltan_Special_Free(zz, (void **)export_gids, ZOLTAN_SPECIAL_MALLOC_GID);
Zoltan_Special_Free(zz, (void **)export_lids, ZOLTAN_SPECIAL_MALLOC_LID);
Zoltan_Special_Free(zz, (void **)export_procs, ZOLTAN_SPECIAL_MALLOC_INT);
Zoltan_Special_Free(zz, (void **)export_to_parts,
ZOLTAN_SPECIAL_MALLOC_INT);
}
Zoltan_Multifree (__FILE__, __LINE__, 12, &dots, &gids, &lids, &partition,
&grand_partition, &grand_weight, &temp_weight, &weights, &target, &delta,
&parts, &tsum);
if (zz->Obj_Weight_Dim > 1)
ZOLTAN_FREE (&work_fraction);
if (zz->Debug_Level >= ZOLTAN_DEBUG_ATIME) {
MPI_Barrier(zz->Communicator);
end_time = Zoltan_Time(zz->Timer);
if (zz->Debug_Proc == zz->Proc)
printf ("HSFC Processing Time is %.6f seconds\n",
end_time-start_time-total_stat_time);
}
ZOLTAN_TRACE_EXIT (zz, yo);
return err;
}
/* routine for bsearch locating the partition segment holding key */
int Zoltan_HSFC_compare (const void *key, const void *arg)
{
if ( *(double*) key >= ((Partition*) arg)->r) return 1;
if ( *(double*) key < ((Partition*) arg)->l) return -1;
return 0; /* key in arg interval [l,r) */
}
/* free state memory needed by point & box drop routines */
void Zoltan_HSFC_Free_Structure (ZZ *zz)
{
HSFC_Data *data = (HSFC_Data*) zz->LB.Data_Structure;
if (data != NULL)
ZOLTAN_FREE (&data->final_partition);
ZOLTAN_FREE (&zz->LB.Data_Structure);
}
/* Copy an hsfc data structure */
int Zoltan_HSFC_Copy_Structure(ZZ *toZZ, ZZ const *fromZZ)
{
char *yo = "Zoltan_HSFC_Copy_Structure";
int len;
HSFC_Data *to;
HSFC_Data const *from;
Zoltan_HSFC_Free_Structure(toZZ);
from = (HSFC_Data const *)fromZZ->LB.Data_Structure;
if (!from){
return ZOLTAN_OK;
}
to = (HSFC_Data *)ZOLTAN_MALLOC(sizeof(HSFC_Data));
if (!to){
ZOLTAN_PRINT_ERROR(fromZZ->Proc, yo, "Insufficient memory.");
return ZOLTAN_MEMERR;
}
toZZ->LB.Data_Structure = (void *)to;
*to = *from;
if (from->final_partition){
len = sizeof(Partition) * fromZZ->LB.Num_Global_Parts;
to->final_partition = (Partition*) ZOLTAN_MALLOC(len);
if (!to->final_partition){
Zoltan_HSFC_Free_Structure(toZZ);
ZOLTAN_PRINT_ERROR(fromZZ->Proc, yo, "Insufficient memory.");
return ZOLTAN_MEMERR;
}
memcpy(to->final_partition, from->final_partition, len);
}
return ZOLTAN_OK;
}
/* function to read HSFC parameters: */
int Zoltan_HSFC_Set_Param (char *name, char *val)
{
int index;
PARAM_UTYPE result;
return Zoltan_Check_Param (name, val, HSFC_params, &result, &index);
}
/****************************************************************************/
static int partition_stats(ZZ *zz, int ndots,
Dots *dots, int *obj_sizes,
float *work_fraction, int *parts, int *new_parts)
{
int wgtDim = zz->Obj_Weight_Dim;
int proc = zz->Proc;
int i, j, max, numParts;
double move, gmove, bal, max_imbal, ib;
double lwtot, gwtot;
double *lpartWgt = NULL;
double *gpartWgt = NULL;
lwtot = 0.0;
for (i = 0, max=0; i < ndots; i++){
if (new_parts[i] > max) max = new_parts[i];
if (wgtDim){
lwtot += dots[i * wgtDim].weight;
}
else{
lwtot += 1.0;
}
}
MPI_Reduce(&lwtot,&gwtot,1,MPI_DOUBLE, MPI_SUM, 0, zz->Communicator);
MPI_Allreduce(&max,&numParts,1,MPI_INT, MPI_MAX, zz->Communicator);
numParts++;
lpartWgt = (double *)ZOLTAN_CALLOC(numParts, sizeof(double));
gpartWgt = (double *)ZOLTAN_MALLOC(numParts * sizeof(double));
if (numParts && (!lpartWgt || !gpartWgt)){
ZOLTAN_FREE(&lpartWgt);
ZOLTAN_FREE(&gpartWgt);
ZOLTAN_PRINT_ERROR(zz->Proc, "partition_stats", "Insufficient memory.");
return ZOLTAN_MEMERR;
}
for (i = 0, j=0, move=0.0; i < ndots; i++, j += wgtDim){
if (wgtDim)
lpartWgt[new_parts[i]] += (double)dots[j].weight;
else
lpartWgt[new_parts[i]] += 1.0;
if (parts[i] != new_parts[i]){
if (obj_sizes)
move += (double)obj_sizes[i];
else
move += 1;
}
}
MPI_Reduce(lpartWgt, gpartWgt, numParts, MPI_DOUBLE, MPI_SUM,
0, zz->Communicator);
MPI_Reduce(&move, &gmove, 1, MPI_DOUBLE, MPI_SUM, 0, zz->Communicator);
ZOLTAN_FREE(&lpartWgt);
if (proc == 0) {
static int nRuns=0;
static double balsum, balmax, balmin;
static double movesum, movemax, movemin;
char *countType;
max_imbal = 0.0;
if (gwtot) {
for (i = 0; i < numParts; i++){
if (work_fraction[i]) {
ib= (gpartWgt[i]-work_fraction[i]*gwtot)/(work_fraction[i]*gwtot);
if (ib>max_imbal)
max_imbal = ib;
}
}
}
bal = 1.0 + max_imbal;
if (nRuns){
if (gmove > movemax) movemax = gmove;
if (gmove < movemin) movemin = gmove;
if (bal > balmax) balmax = bal;
if (bal < balmin) balmin = bal;
movesum += gmove;
balsum += bal;
}
else{
movemax = movemin = movesum = gmove;
balmax = balmin = balsum = bal;
}
countType = "moveCnt";
if (obj_sizes){
countType = "moveVol";
}
nRuns++;
printf(" STATS Runs %d bal CURRENT %f MAX %f MIN %f AVG %f\n",
nRuns, bal, balmax, balmin, balsum/nRuns);
printf(" STATS Runs %d %s CURRENT %f MAX %f MIN %f AVG %f\n",
nRuns, countType, gmove, movemax, movemin, movesum/nRuns);
}
ZOLTAN_FREE(&gpartWgt);
MPI_Barrier(zz->Communicator);
return ZOLTAN_OK;
}
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif

132
thirdParty/Zoltan/src/hsfc/hsfc.h vendored Normal file
View File

@ -0,0 +1,132 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifndef ZOLTAN_HSFC_H
#define ZOLTAN_HSFC_H
#include <stdio.h>
#include <math.h>
#include <memory.h>
#include <limits.h>
#include <string.h>
#include <float.h>
#include "zz_const.h"
#include "all_allo_const.h"
#include "params_const.h"
#include "zoltan_util.h"
#include "hsfc_hilbert_const.h"
#include "hsfc_const.h"
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
/* Andy's value * 1.6, points on face of bounding box must become interior */
static const double HSFC_EPSILON = 1.6e-7;
/* limit at which bin can't be divided */
static const double REFINEMENT_LIMIT = 10.0 * DBL_EPSILON;
/* when dots have no weight, use this */
static const double DEFAULT_WEIGHT = 1.0;
/* number of "bins per processor", small positive integer */
static const int N = 8;
/* refinement now hitting limit of double precision */
static const int MAX_LOOPS = 16;
/* The following are used in determining the max/min hsfc coordinates in
a bin, if bin empty */
static const double DEFAULT_BIN_MAX = -2.0;
static const double DEFAULT_BIN_MIN = 2.0;
#define ZOLTAN_HSFC_ERROR(error,str) {err = error; \
ZOLTAN_PRINT_ERROR(zz->Proc, yo, str); goto End;}
typedef struct Partition {
double r; /* rightmost boundary of partition interval */
double l; /* leftmost boundary of partition interval */
int index; /* number of "owner" of data in interval */
} Partition; /* interval is half open, [l,r) */
typedef struct HSFC_Data {
Partition *final_partition;
double bbox_hi[3]; /* smallest bounding box, high point */
double bbox_lo[3]; /* smallest bounding box, low point */
double bbox_extent[3]; /* length of each side of bounding box */
int ndimension; /* number of dimensions in problem (2 or 3) */
double (*fhsfc)(ZZ*, double*); /* space filling curve function */
ZZ_Transform tran; /* transformation for degenerate geometry */
} HSFC_Data; /* data preserved for point & box drop later */
typedef struct Dots {
double fsfc; /* computed normalized SFC coordinate */
double x[3]; /* dots coordinates in problem domain */
float weight; /* scalar computed from weight vector */
int part; /* partition to which dot is assigned */
} Dots; /* represents objects being load-balanced */
extern int Zoltan_HSFC_compare (const void *key, const void *arg);
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif
#endif

View File

@ -0,0 +1,614 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
#include "hsfc.h"
#include "zz_const.h"
#include "zz_util_const.h"
#include <math.h>
/* For a detailed description of the following algorithm, please see the
Developers Guide. For instructions on use, please see the Users
Guide. This code assumes a 32 bit integer length!!! For a note on
increasing the precision see the end of this file. */
static double next_query_2d (ZZ*, double *lquerybox, double *hquerybox, double);
static double next_query_3d (ZZ*, double *lquerybox, double *hquerybox, double);
/* returns list of processors and partitions intersecting the user's query box */
int Zoltan_HSFC_Box_Assign (
ZZ *zz, double xlo, double ylo, double zlo, /* low query box vertex */
double xhi, double yhi, double zhi, /* high query box vertex */
int *procs, int *proc_count, int *parts, int *part_count)
{
double xintl[3], xinth[3]; /* low and high bounded query box */
int *part_array = NULL;
int *proc_array = NULL;
HSFC_Data *d; /* HFSC's portion of Zoltan data structure */
int n, i, loop; /* loop counters */
int tmp, dim = 0;
int first_proc, last_proc;
double fsfc, starting;
double lo[3], hi[3];
Partition *p;
const double FUZZY = 1.0e-9; /* to build region about a query point or line */
/* Erik suggested that this value be tied to */
/* the actual precision available (dimension */
/* specific - 2^18 in 3d, 2^27 in 2d. */
int err = ZOLTAN_OK;
int *remap;
char *yo = "Zoltan_HSFC_Box_Assign";
ZOLTAN_TRACE_ENTER (zz, yo);
d = (HSFC_Data *) zz->LB.Data_Structure; /* persistant HSFC data */
if (d == NULL)
ZOLTAN_HSFC_ERROR (ZOLTAN_FATAL,
"No Decomposition Data available; use KEEP_CUTS parameter.");
/* allocate memory to store results */
*part_count = *proc_count = 0;
part_array = (int *) ZOLTAN_MALLOC ((zz->LB.Num_Global_Parts + zz->Num_Proc)
* sizeof (int));
if (part_array == NULL)
ZOLTAN_HSFC_ERROR (ZOLTAN_MEMERR, "Memory allocation error.");
proc_array = part_array + zz->LB.Num_Global_Parts;
memset (part_array, 0, (zz->LB.Num_Global_Parts + zz->Num_Proc)*sizeof (int));
/* One dimensional case is trival, do it and exit */
if (d->ndimension == 1) {
remap = zz->LB.Remap; /* Don't let Point_Assign remap IDs.*/
zz->LB.Remap = NULL; /* We will do this at "fini". */
Zoltan_HSFC_Point_Assign (zz, &xlo, NULL, &n);
Zoltan_HSFC_Point_Assign (zz, &xhi, NULL, &loop);
for (i = n; i <= loop; i++)
part_array[i] = 1;
zz->LB.Remap = remap;
goto fini;
}
if (d->tran.Target_Dim > 0){ /* It must be 1 or 2 */
/*
* Degenerate geometry:
* Transform query box into coordinates that were used for partitioning,
* and place an axis aligned bounding box around it. This box in the new
* coordinates may encompass more "dots" than did the original box, but
* it won't miss any dots.
*/
lo[0] = xlo; lo[1] = ylo; lo[2] = zlo;
hi[0] = xhi; hi[1] = yhi; hi[2] = zhi;
Zoltan_Transform_Box(lo, hi, d->tran.Transformation, d->tran.Permutation,
d->ndimension, d->tran.Target_Dim);
xlo = lo[0]; xhi = hi[0];
ylo = 0.0; yhi = 0.0;
zlo = 0.0; zhi = 0.0;
if (d->tran.Target_Dim == 2){
ylo = lo[1]; yhi = hi[1];
dim = d->tran.Target_Dim;
}
else if (d->tran.Target_Dim == 1){
/*
* Don't let Point_Assign transform coordinates (we already
* did that) or remap partition numbers (we'll do that at "fini").
*/
dim = d->ndimension;
remap = zz->LB.Remap;
d->tran.Target_Dim = 0; /* don't transform coordinates */
d->ndimension = 1; /* partitions were calculated as 1D */
zz->LB.Remap = NULL; /* don't remap partition numbers */
Zoltan_HSFC_Point_Assign (zz, &xlo, NULL, &n);
Zoltan_HSFC_Point_Assign (zz, &xhi, NULL, &loop);
for (i = n; i <= loop; i++) /* loop < n */
part_array[i] = 1;
d->tran.Target_Dim = 1;
d->ndimension = dim;
zz->LB.Remap = remap;
goto fini;
}
}
else{
dim = d->ndimension;
}
/* determine intersection of bounding box and query box */
xintl[0] = (xlo - d->bbox_lo[0]) / d->bbox_extent[0];
if (xintl[0] < FUZZY) xintl[0] = FUZZY;
else if (xintl[0] > 1.0-FUZZY) xintl[0] = 1.0-FUZZY;
xinth[0] = (xhi - d->bbox_lo[0]) / d->bbox_extent[0];
if (xinth[0] < FUZZY) xinth[0] = FUZZY;
else if (xinth[0] > 1.0-FUZZY) xinth[0] = 1.0-FUZZY;
xintl[1] = (ylo - d->bbox_lo[1]) / d->bbox_extent[1];
if (xintl[1] < FUZZY) xintl[1] = FUZZY;
else if (xintl[1] > 1.0-FUZZY) xintl[1] = 1.0-FUZZY;
xinth[1] = (yhi - d->bbox_lo[1]) / d->bbox_extent[1];
if (xinth[1] < FUZZY) xinth[1] = FUZZY;
else if (xinth[1] > 1.0-FUZZY) xinth[1] = 1.0-FUZZY;
/* application programs need to add "dots" even if query box doesn't actually
intersect unit cube. FUZZY forces closest virtual overlap. */
if (xinth[0] - xintl[0] < FUZZY) {
xintl[0] -= (FUZZY/2.0);
xinth[0] += (FUZZY/2.0);
}
if (xinth[1] - xintl[1] < FUZZY) {
xintl[1] -= (FUZZY/2.0);
xinth[1] += (FUZZY/2.0);
}
if (dim == 2)
for (i = 0; i < zz->LB.Num_Global_Parts; i++) {
if (d->final_partition[i].l == d->final_partition[i].r)
continue; /* ignore empty partitions */
/* find next query result in range [0.0, 1.0] */
starting = (d->final_partition[i].l == 0.0)
? 0.0 : (d->final_partition[i].l + FUZZY);
fsfc = next_query_2d (zz, xintl, xinth, starting);
if (fsfc < 0.0)
break; /* done indication, no more partitions to be found */
/* Find next nonempty partition entering or already in query region */
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, can't happen");
if (d->final_partition[p->index].l != d->final_partition[p->index].r)
part_array [p->index] = 1; /* mark non empty partitions */
i = p->index;
}
if (dim == 3) {
/* complete the z axis information, as above */
xintl[2] = (zlo - d->bbox_lo[2]) / d->bbox_extent[2];
if (xintl[2] < 0.0) xintl[2] = FUZZY;
else if (xintl[2] > 1.0) xintl[2] = 1.0-FUZZY;
xinth[2] = (zhi - d->bbox_lo[2]) / d->bbox_extent[2];
if (xinth[2] < 0.0) xinth[2] = FUZZY;
else if (xinth[2] > 1.0) xinth[2] = 1.0-FUZZY;
if (xinth[2] - xintl[2] < FUZZY) {
xintl[2] -= (FUZZY/2.0);
xinth[2] += (FUZZY/2.0);
}
for (i = 0; i < zz->LB.Num_Global_Parts; i++) {
if (d->final_partition[i].l == d->final_partition[i].r)
continue; /* ignore empty partition */
/* find next query result in range [0.0. 1.0] */
starting = (d->final_partition[i].l == 0.0)
? 0.0 : (d->final_partition[i].l + FUZZY);
fsfc = next_query_3d (zz, xintl, xinth, starting);
if (fsfc < 0.0)
break; /* done, no more to be found */
/* 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, can't happen");
if (d->final_partition[p->index].l != d->final_partition[p->index].r)
part_array [p->index] = 1; /* ignore empty partitions */
i = p->index;
}
}
/* move results to user supplied arrays & hope they are big enough */
fini:
*part_count = 0;
if (parts) {
*part_count = 0;
for (i = 0; i < zz->LB.Num_Global_Parts; i++)
if (part_array[i] > 0) {
if (zz->LB.Remap)
parts[(*part_count)++] = zz->LB.Remap[i];
else
parts[(*part_count)++] = i;
}
}
if (procs) {
for (i = 0; i < zz->LB.Num_Global_Parts; i++)
if (part_array[i] > 0) {
tmp = (zz->LB.Remap ? zz->LB.Remap[i] : i);
first_proc = Zoltan_LB_Part_To_Proc(zz, tmp, NULL);
proc_array[first_proc] = 1;
if (!zz->LB.Single_Proc_Per_Part) {
/* Part may be spread across multiple procs. Include them all. */
int j;
if (tmp < zz->LB.Num_Global_Parts - 1)
last_proc = Zoltan_LB_Part_To_Proc (zz, tmp + 1, NULL);
else
last_proc = zz->Num_Proc;
for (j = first_proc + 1; j < last_proc; j++)
proc_array[j] = 1;
}
}
*proc_count = 0;
for (i = 0; i < zz->Num_Proc; i++)
if (proc_array[i] > 0)
procs[(*proc_count)++] = i;
}
End:
ZOLTAN_FREE (&part_array);
ZOLTAN_TRACE_EXIT (zz, yo);
return err;
}
/* returns the first Hilbert coordinate in [s,1] to enter the user's query box */
static double next_query_2d (ZZ *zz, double *lquerybox, double *hquerybox,
double s)
{
int state, newstate=0, savelevel, prune, backtrack;
unsigned int temp, x, y;
unsigned int savestate=0, savequad=0, savenpt=0; /* saved info for backtracking */
unsigned int qlox, qloy, qhix, qhiy; /* query box bounds */
unsigned int nptx, npty, keyx, keyy, newnpt=0;
unsigned int start[2], startbits=0;
unsigned int intersect_hi, intersect_lo;
double t;
unsigned i, level, quadrant; /* loop counters */
static const unsigned int *dk[]
= {data2d, data2d +4, data2d +8, data2d +12};
static const unsigned int *st[]
= {state2d, state2d +4, state2d +8, state2d +12};
static const unsigned int MAXLEVEL = 28; /* only 56 significant bits, 28 per dimension */
/* convert floating normalized, intersected query box corners to integers */
qlox = (unsigned int) (lquerybox[0] * (double) IMAX);
qloy = (unsigned int) (lquerybox[1] * (double) IMAX);
qhix = (unsigned int) (hquerybox[0] * (double) IMAX);
qhiy = (unsigned int) (hquerybox[1] * (double) IMAX);
/* convert floating minimum query hilbert coordinate to integer */
start[1] = (unsigned int) (modf (s * (double) IMAX, &t) * (double) IMAX);
start[0] = (unsigned int) t;
/* initializations before starting main loop */
state = 0;
prune = 1;
backtrack = 1;
savelevel = -1;
nptx = npty = 0;
keyx = keyy = 0;
/* now loop over each level of hilbert curve refinement */
for (level = 0; level < MAXLEVEL; level++) {
if (prune) {
/* get next 2 bits of start for pruning from its shift register */
startbits = start[0] >> 30; /* extract top two bits */
start[0] = (start[0] << 2) | (start[1] >> 30); /* shift hi word */
start[1] = start[1] << 2; /* shift lo word */
}
/* compute current search space intersected with the query region */
temp = IMAX >> level; /* top of range ends in all 1 bits */
x = ((nptx | temp) > qhix) ? qhix : (nptx | temp);
y = ((npty | temp) > qhiy) ? qhiy : (npty | temp);
intersect_hi = (((x >> (30-level)) & 2) | ((y >> (31-level)) & 1));
temp = ~temp; /* bottom of range ends in all 0 bits */
x = ((nptx & temp) < qlox) ? qlox : (nptx & temp);
y = ((npty & temp) < qloy) ? qloy : (npty & temp);
intersect_lo = (((x >> (30-level)) & 2) | ((y >> (31-level)) & 1));
/* loop over subquadrants in hilbert curve order to find lowest numbered
quad that intersects with query region and is larger than start key */
temp = (prune) ? startbits : 0;
for (quadrant = temp; quadrant < 4; quadrant++) {
newnpt = *(dk[state] + quadrant); /* get new 2 bit npt value */
if (!((newnpt ^ intersect_hi) & (newnpt ^ intersect_lo)))
break; /* successfully found intersecting quadrant at this level */
}
if (quadrant < 4) {
newstate = *(st[state] + quadrant);
if (prune && (quadrant > startbits))
prune = 0; /* no more pruning required */
}
/* determine backtracking point, in case backtracking is needed */
if (backtrack)
for (i = quadrant+1; i < 4; i++) {
/* intersect test - subquad intersecting with search/query region */
temp = *(dk[state] + i); /* get new npt */
if (!((temp ^ intersect_hi) & (temp ^ intersect_lo))) {
savelevel = level;
savestate = *(st[state] + i);
savenpt = temp;
savequad = i;
break;
}
}
/* test if this round was successful (quadrant < 4), backtrack if not */
if (quadrant == 4) {
if (savelevel == -1)
return -1.0; /* report that no solution is available */
/* restore all conditions to backtrack point */
level = savelevel;
newstate = savestate;
newnpt = savenpt;
quadrant = savequad;
prune = 0; /* no longer need to prune previous branches */
backtrack = 0; /* only 1 backtrack ever required, now done */
/* discard results below backtrack level */
keyx &= ~(IMAX >> savelevel);
keyy &= ~(IMAX >> savelevel);
nptx &= ~(IMAX >> savelevel);
nptx &= ~(IMAX >> savelevel);
}
/* append current derived key and npoint to cumulative total */
keyx |= ((quadrant & 2) << (30-level));
keyy |= ((quadrant & 1) << (31-level));
nptx |= ((newnpt & 2) << (30-level));
npty |= ((newnpt & 1) << (31-level));
state = newstate;
}
/* now convert final derived key to floating point representation and exit */
start[0] = start[1] = 0;
for (i = 0; i < MAXLEVEL; i++) {
start[0] = (start[0] << 2) | (start[1] >> 30);
start[1] = (start[1] << 2) | ((keyx >> (30-i)) & 2)
| ((keyy >> (31-i)) & 1);
}
return ldexp ((double) start[0], -24) + ldexp((double) start[1], -56);
}
/* returns the first Hilbert coordinate in [s,1] to enter the user's query box */
static double next_query_3d (ZZ *zz, double *lquerybox, double *hquerybox,
double s)
{
int state, newstate = 0, savelevel, prune, backtrack;
unsigned int temp, x, y, z;
unsigned int savestate = 0, savequad = 0, savenpt = 0;
unsigned int qlox, qloy, qloz, qhix, qhiy, qhiz;
unsigned int nptx, npty, nptz, keyx, keyy, keyz, newnpt = 0;
unsigned int start[2], startbits = 0;
unsigned int intersect_hi, intersect_lo;
double t;
unsigned i, quadrant, level;
static const unsigned int *dk[] =
{data3d, data3d +8, data3d +16, data3d +24,
data3d +32, data3d +40, data3d +48, data3d +56,
data3d +64, data3d +72, data3d +80, data3d +88,
data3d +96, data3d +104, data3d +112, data3d +120,
data3d +128, data3d +136, data3d +144, data3d +152,
data3d +160, data3d +168, data3d +176, data3d +184};
static const unsigned int *st[] =
{state3d, state3d +8, state3d +16, state3d +24,
state3d +32, state3d +40, state3d +48, state3d +56,
state3d +64, state3d +72, state3d +80, state3d +88,
state3d +96, state3d +104, state3d +112, state3d +120,
state3d +128, state3d +136, state3d +144, state3d +152,
state3d +160, state3d +168, state3d +176, state3d +184};
static const unsigned int MAXLEVEL = 18; /* only 56 significant bits, 18 per dimension */
/* convert floating query box corners to integers */
qlox = (unsigned int) (lquerybox[0] * (double) IMAX);
qloy = (unsigned int) (lquerybox[1] * (double) IMAX);
qloz = (unsigned int) (lquerybox[2] * (double) IMAX);
qhix = (unsigned int) (hquerybox[0] * (double) IMAX);
qhiy = (unsigned int) (hquerybox[1] * (double) IMAX);
qhiz = (unsigned int) (hquerybox[2] * (double) IMAX);
/* convert floating minimum query hilbert coordinate to integer */
start[1] = (unsigned int) (modf (s * (double) IMAX, &t) * (double) IMAX);
start[0] = (unsigned int) t;
/* initializations before main loop */
state = 0;
prune = 1;
backtrack = 1;
savelevel = -1;
nptx = npty = nptz = 0;
keyx = keyy = keyz = 0;
/* now loop over each level of hilbert curve refinement */
for (level = 0; level < MAXLEVEL; level++) {
if (prune) {
/* get next 3 bits of start for pruning, treat as shift register */
startbits = start[0] >> 29; /* extract top two bits */
start[0] = (start[0] << 3) | (start[1] >> 29); /* shift hi word */
start[1] = start[1] << 3; /* shift lo word */
}
/* compute current search space intersected with the query region */
temp = IMAX >> level; /* top of range ends in all 1 bits */
x = ((nptx | temp) > qhix) ? qhix : (nptx | temp);
y = ((npty | temp) > qhiy) ? qhiy : (npty | temp);
z = ((nptz | temp) > qhiz) ? qhiz : (nptz | temp);
intersect_hi = ((x >> (29-level)) & 4)
| ((y >> (30-level)) & 2)
| ((z >> (31-level)) & 1);
temp = ~temp; /* bottom of range ends in all 0 bits */
x = ((nptx & temp) < qlox) ? qlox : (nptx & temp);
y = ((npty & temp) < qloy) ? qloy : (npty & temp);
z = ((nptz & temp) < qloz) ? qloz : (nptz & temp);
intersect_lo = ((x >> (29-level)) & 4)
| ((y >> (30-level)) & 2)
| ((z >> (31-level)) & 1);
/* loop over subquadrants in hilbert curve order to find lowest numbered
quad that intersects with query region and is larger than start key */
temp = (prune) ? startbits : 0;
for (quadrant = temp; quadrant < 8; quadrant++) {
newnpt = *(dk[state] + quadrant); /* get new 3 bit npt value */
if (!((newnpt ^ intersect_hi) & (newnpt ^ intersect_lo)))
break; /* successfully found intersecting quadrant at this level */
}
if (quadrant < 8) {
newstate = *(st[state] + quadrant);
if (prune && (quadrant > startbits))
prune = 0; /* no more pruning required */
}
/* determine backtracking point, in case backtracking is needed */
if (backtrack)
for (i = quadrant+1; i < 8; i++) {
temp = *(dk[state] + i); /* get new npt */
/* intersect test - subquad intersecting with search/query region */
if (!((temp ^ intersect_hi) & (temp ^ intersect_lo))) {
savelevel = level;
savestate = *(st[state] + i);
savenpt = temp;
savequad = i;
break;
}
}
/* test if this round was successful (quadrant < 8), backtrack if not */
if (quadrant == 8) {
if (savelevel == -1)
return -1.0; /* no solution available, report failure */
/* restore all conditions to backtrack point */
level = savelevel;
newstate = savestate;
newnpt = savenpt;
quadrant = savequad;
prune = 0; /* no longer need to prune previous branches */
backtrack = 0; /* only 1 backtrack ever required, now done */
/* discard results below backtrack level */
keyx &= ~(IMAX >> savelevel);
keyy &= ~(IMAX >> savelevel);
keyz &= ~(IMAX >> savelevel);
nptx &= ~(IMAX >> savelevel);
npty &= ~(IMAX >> savelevel);
nptz &= ~(IMAX >> savelevel);
}
/* append current derived key and npoint to cumulative total */
state = newstate;
keyx |= ((quadrant & 4) << (29-level));
keyy |= ((quadrant & 2) << (30-level));
keyz |= ((quadrant & 1) << (31-level));
nptx |= ((newnpt & 4) << (29-level));
npty |= ((newnpt & 2) << (30-level));
nptz |= ((newnpt & 1) << (31-level));
}
/* now convert final derived key to floating point representation and exit */
start[0] = start[1] = 0;
for (i = 0; i < MAXLEVEL; i++) {
start[0] = (start[0] << 3) | (start[1] >> 29);
start[1] = (start[1] << 3) | ((keyx >> (29-i)) & 4)
| ((keyy >> (30-i)) & 2)
| ((keyz >> (31-i)) & 1);
}
return ldexp ((double) start[0], -22) + ldexp((double) start[1], -54);
}
/* Maintenance Note: Per the review 04.15.03, the following section addresses
increasing the precision of this box assign.
The next_query_xx() routines can be extended to arbitrary precision. Currently
they reflect the precision limitation of using a double for the starting
Hilbert coordinate and the returned value:
static double next_query_3d (ZZ *zz, double *lquerybox, double *hquerybox,
double s)
Change this to:
static int* next_query_3d (ZZ *zz, double *lquerybox, double *hquerybox,
int *start).
Represent the Hilbert coordinate as an array of ints (2 for 2d, 3 for 3d) rather
than the double representation currently used.
Change the declaration:
static const int MAXLEVEL = 18; (3d or 28 in 2d)
to
static const int MAXLEVEL = 32;
Change the return statement:
return ldexp ((double) start[0], -22) + ldexp((double) start[1], -54);
to
return start;
Please see the related remarks in the file hsfc_hilbert.c.
The last change is to replace the criteria for the binary lookup of a hilbert
coordinate to find its partition to use the int arrays rather than double.
This requires a trivial change to hsfc.c to use int arrays for the hilbert
coordinate as well.
*/
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif

64
thirdParty/Zoltan/src/hsfc/hsfc_const.h vendored Normal file
View File

@ -0,0 +1,64 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifndef ZOLTAN_HSFC_CONST_H
#define ZOLTAN_HSFC_CONST_H
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
/* function prototypes */
int Zoltan_HSFC_Set_Param (char *name, char *val) ;
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif
#endif

View File

@ -0,0 +1,332 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include "hsfc_hilbert_const.h" /* contains state tables and documentation */
#include "hsfc.h"
#include "zz_const.h"
/* see maintenance note at the end of this file for information about extending
the precision of these routines. */
/* Given a 1-d coordinate in [0,1], returns it as the Hilbert key) */
double Zoltan_HSFC_InvHilbert1d (ZZ *zz, double *coord)
{
char *yo = "Zoltan_HSFC_InvHilbert1d";
/* sanity check for input arguments */
if (coord[0] < 0.0)
ZOLTAN_PRINT_ERROR (zz->Proc, yo, "Spatial Coordinates out of range.");
return *coord;
}
/* Given x,y coordinates in [0,1]x[0,1], returns the Hilbert key [0,1] */
double Zoltan_HSFC_InvHilbert2d (ZZ *zz, double *coord)
{
static const unsigned *d[]={idata2d, idata2d +4, idata2d +8, idata2d +12};
static const unsigned *s[]={istate2d, istate2d +4, istate2d +8, istate2d +12};
int level;
unsigned int key[2], c[2], temp, state;
const int MAXLEVEL = 28; /* 56 bits of significance, 28 per dimension */
char *yo = "Zoltan_HSFC_InvHilbert2d";
/* sanity check for input arguments */
if ((coord[0] < 0.0) || (coord[0] > 1.0) || (coord[1] < 0.0)
|| (coord[1] > 1.0))
ZOLTAN_PRINT_ERROR (zz->Proc, yo, "Spatial Coordinates out of range.");
/* convert x,y coordinates to integers in range [0, IMAX] */
c[0] = (unsigned int) (coord[0] * (double) IMAX); /* x */
c[1] = (unsigned int) (coord[1] * (double) IMAX); /* y */
/* use state tables to convert nested quadrant's coordinates level by level */
key[0] = key[1] = 0;
state = 0;
for (level = 0; level < MAXLEVEL; level++) {
temp = ((c[0] >> (30-level)) & 2) /* extract 2 bits at current level */
| ((c[1] >> (31-level)) & 1);
/* treat key[] as long shift register, shift in converted coordinate */
key[0] = (key[0] << 2) | (key[1] >> 30);
key[1] = (key[1] << 2) | *(d[state] + temp);
state = *(s[state] + temp);
}
/* convert 2 part Hilbert key to double and return */
return ldexp ((double) key[0], -24) + ldexp ((double) key[1], -56);
}
/* Given x,y,z coordinates in [0,1]x[0,1]x[0,1], returns Hilbert key in [0,1] */
double Zoltan_HSFC_InvHilbert3d (ZZ *zz, double *coord)
{
static const unsigned int *d[] =
{idata3d, idata3d +8, idata3d +16, idata3d +24,
idata3d +32, idata3d +40, idata3d +48, idata3d +56,
idata3d +64, idata3d +72, idata3d +80, idata3d +88,
idata3d +96, idata3d +104, idata3d +112, idata3d +120,
idata3d +128, idata3d +136, idata3d +144, idata3d +152,
idata3d +160, idata3d +168, idata3d +176, idata3d +184};
static const unsigned int *s[] =
{istate3d, istate3d +8, istate3d +16, istate3d +24,
istate3d +32, istate3d +40, istate3d +48, istate3d +56,
istate3d +64, istate3d +72, istate3d +80, istate3d +88,
istate3d +96, istate3d +104, istate3d +112, istate3d +120,
istate3d +128, istate3d +136, istate3d +144, istate3d +152,
istate3d +160, istate3d +168, istate3d +176, istate3d +184};
int level;
unsigned int key[2], c[3], temp, state;
const int MAXLEVEL = 19; /* 56 bits of significance, 18+ per dimension */
char *yo = "Zoltan_HSFC_InvHilbert3d";
/* sanity check for input arguments */
if ((coord[0] < 0.0) || (coord[0] > 1.0) || (coord[1] < 0.0)
|| (coord[1] > 1.0) || (coord[2] < 0.0) || (coord[2] > 1.0))
ZOLTAN_PRINT_ERROR (zz->Proc, yo, "Spatial Coordinates out of range.");
/* convert x,y,z coordinates to integers in range [0,IMAX] */
c[0] = (unsigned int) (coord[0] * (double) IMAX); /* x */
c[1] = (unsigned int) (coord[1] * (double) IMAX); /* y */
c[2] = (unsigned int) (coord[2] * (double) IMAX); /* z */
/* use state tables to convert nested quadrant's coordinates level by level */
key[0] = key[1] = 0;
state = 0;
for (level = 0; level < MAXLEVEL; level++) {
temp = ((c[0] >> (29-level)) & 4) /* extract 3 bits at current level */
| ((c[1] >> (30-level)) & 2)
| ((c[2] >> (31-level)) & 1);
/* treat key[] as long shift register, shift in converted coordinate */
key[0] = (key[0] << 3) | (key[1] >> 29);
key[1] = (key[1] << 3) | *(d[state] + temp);
state = *(s[state] + temp);
}
/* convert 2 part Hilbert key to double and return */
return ldexp ((double) key[0], -25) + ldexp ((double) key[1], -57);
}
/* Note: the following code has been tested and is fine. It was necessary
during the testing for the new box assign algorithm. Since it is potentially
useful, I am leaving this code intact, but ifdef'ing it out because of the
SQA coverage requirement. */
#ifdef RTHRTH
/* Given the Hilbert key, returns it as the coordinate in [0,1] */
void Zoltan_HSFC_Hilbert1d (ZZ *zz, double *coord, double key)
{
char *yo = "Zoltan_HSFC_Hilbert1d";
/* sanity check for input argument */
if ((key < 0.0) || (key > 1.0))
ZOLTAN_PRINT_ERROR (zz->Proc, yo, "Hilbert coordinate out of range.");
*coord = key;
}
/* Given the Hilbert key, returns the 2-d coordinates in [0,1]x[0,1] */
void Zoltan_HSFC_Hilbert2d (ZZ *zz, double *coord, double key)
{
static const unsigned *d[] = {data2d, data2d +4, data2d +8, data2d +12};
static const unsigned *s[] = {state2d, state2d +4, state2d +8, state2d +12};
int level, state;
unsigned int c[2], ikey[2], temp;
double t;
static const int MAXLEVEL = 28; /* only 56 significant bits, 28 per dimension */
char *yo = "Zoltan_HSFC_Hilbert2d";
/* sanity check for input argument */
if ((key < 0.0) || (key > 1.0))
ZOLTAN_PRINT_ERROR (zz->Proc, yo, "Hilbert coordinate out of range.");
ikey[1] = (unsigned int) (modf (key * (double) IMAX, &t) * (double) IMAX);
ikey[0] = (unsigned int) t;
/* use state tables to convert nested quadrant's coordinates level by level */
c[0] = c[1] = 0;
state = 0;
for (level = 0; level < MAXLEVEL; level++) {
temp = *(d[state] + (ikey[0] >> 30)); /* 2 bits: xy */
state = *(s[state] + (ikey[0] >> 30));
c[0] |= ((temp & 2) << (30-level)); /* insert x bit */
c[1] |= ((temp & 1) << (31-level)); /* insert y bit */
/* treating ikey[] as shift register, shift next 2 bits in place */
ikey[0] = (ikey[0] << 2) | (ikey[1] >> 30);
ikey[1] = ikey[1] << 2;
}
/* convert integer coordinates to doubles */
coord[0] = (double) c[0] / (double) IMAX; /* x in [0,1] */
coord[1] = (double) c[1] / (double) IMAX; /* y in [0,1] */
}
/* Given the Hilbert key, returns the 3-d coordinates in [0,1]x[0,1]x[0,1] */
void Zoltan_HSFC_Hilbert3d (ZZ *zz, double *coord, double key)
{
static const unsigned int *d[] =
{data3d, data3d +8, data3d +16, data3d +24,
data3d +32, data3d +40, data3d +48, data3d +56,
data3d +64, data3d +72, data3d +80, data3d +88,
data3d +96, data3d +104, data3d +112, data3d +120,
data3d +128, data3d +136, data3d +144, data3d +152,
data3d +160, data3d +168, data3d +176, data3d +184};
static const unsigned int *s[] =
{state3d, state3d +8, state3d +16, state3d +24,
state3d +32, state3d +40, state3d +48, state3d +56,
state3d +64, state3d +72, state3d +80, state3d +88,
state3d +96, state3d +104, state3d +112, state3d +120,
state3d +128, state3d +136, state3d +144, state3d +152,
state3d +160, state3d +168, state3d +176, state3d +184};
int level, state;
unsigned int c[3], ikey[2], temp;
double t;
static const int MAXLEVEL = 19; /* 56 significant bits, 18+ per dimension */
char *yo = "Zoltan_HSFC_Hilbert3d";
/* sanity check for input argument */
if ((key < 0.0) || (key > 1.0))
ZOLTAN_PRINT_ERROR (zz->Proc, yo, "Hilbert coordinate out of range.");
ikey[1] = (unsigned int) (modf (key * (double) IMAX, &t) * (double) IMAX);
ikey[0] = (unsigned int) t;
/* use state tables to convert nested quadrant's coordinates level by level */
c[0] = c[1] = c[2] = 0;
state = 0;
for (level = 0; level < MAXLEVEL; level++) {
temp = *(d[state] + (ikey[0] >> 29)); /* get next 3 bits: xyz */
state = *(s[state] + (ikey[0] >> 29));
c[0] |= ((temp & 4) << (29-level)); /* insert x bit */
c[1] |= ((temp & 2) << (30-level)); /* insert y bit */
c[2] |= ((temp & 1) << (31-level)); /* insert z bit */
/* treating ikey[] as shift register, shift next 3 bits in place */
ikey[0] = (ikey[0] << 3) | (ikey[1] >> 29);
ikey[1] = ikey[1] << 3;
}
/* convert coordinates to doubles */
coord[0] = (double) c[0] / (double) IMAX; /* x in [0,1] */
coord[1] = (double) c[1] / (double) IMAX; /* y in [0,1] */
coord[2] = (double) c[2] / (double) IMAX; /* z in [0,1] */
}
#endif
/* MAINTENANCE NOTE: Per the design review 04/15/03, this section discusses
how to increase the precision of the routines in this file. The table driven
logic can be extended to arbitrary precision. Currently, these routines only
take or return the precision of a double.
First, consider how to extend the Zoltan_HSFC_InvHilbertxx() routines to return
the full precision for the 2 or 3 dimensional input:
The statement
c[0] = (unsigned int) (coord[0] * (double) IMAX); (etc. for each dimension)
returns about 32 bits of usable information per dimension.
Change the declaration:
const int MAXLEVEL = 28;
to
const int MAXLEVEL = 32;
Then the key array contains 64 bits in 2d or 96 bits in 3d. Change its
declaration to either 2 or 3 ints as appropriate.
The easiest thing is to modify the routine to return the key array itself to
preserve the maximum precision. This requires changing the function definition:
double Zoltan_HSFC_InvHilbert2d (ZZ *zz, double *coord)
to
int *Zoltan_HSFC_InvHilbert2d (ZZ *zz, double *coord).
and changing the return statement:
return ldexp ((double) key[0], -24) + ldexp ((double) key[1], -56);
to
return key;
Second, consider how to extend the Zoltan_HSFC_Hilbertxx() routines. If the key
array is used as the return argument above, then these Hilbertxx routines should
be modified to accept the key array as the Hilbert coordinate rather than the
current double. This requires changing the function definition:
void Zoltan_HSFC_Hilbert2d (ZZ *zz, double *coord, double key)
to
void Zoltan_HSFC_Hilbert2d (ZZ *zz, double *coord, int* ikey)
Change the declaration
static const int MAXLEVEL = 28; (2d or 19 in 3d)
to
static const int MAXLEVEL = 32;
Eliminate the lines that convert the orginal double arguement of key to ikey.
*/
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif

View File

@ -0,0 +1,244 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifndef __HSFC_HILBERT_CONST_H
#define __HSFC_HILBERT_CONST_H
#include "zz_const.h"
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
/***************************************************************************
* The modules and data arrays in hsfc_hilbert.c and hsfc_box_assign.c are
* influenced by a series of papers:
* "Load balancing for the parallel adaptive solution of partial differential
* equations", 1994, deCougny, Devine, Flaherty, Loy, Ozturan, Shephard
* "Adaptive Local Refinement with Octree Load-Balancing for the parallel
* solution of three-dimensional conservation laws", 1998, Loy, (Ph.D.)
* "The Performance of an Octree Load Balancer for Parallel Adaptive Finite
* Element Computation", 2001, Campbell
* "Using State Diagrams for Hilbert Curve Mappings", Lawder, 2000
* "Querying Multi-demensional Data Indexed Using the Hilbert Space-Filling
* Curve", Lawder, King, 2000
* "Calculation of Mappings between One and n-dimensional Values Using the
* Hilbert Space-filling Curve", Lawder, 2000
* "Using Space-filling Curves for Multi-dimensional Indexing", Lawder, King,
* 2000
*
* A useful reference discussing the Hilbert curve for spatial data indexing,
* data queries, etc. is "Fundamentals of Spatial Information Systems, 1992,
* Laurini, Thompson.
*
* Useful code examples for the generation of Hilbert and Inverse Hilbert
* coordinates came from Octree (in above papers) also using state tables,
* H. Carter Edwards (1997), (Ph.D. dissertation, code copyrighted 1997),
* Doug Moore, Rice University (copyrighted 1998-2000) whose code also
* includes an implimenation of a query search for box like regions in the
* Hilbert space as well as other database oriented functions.
*
* This code is closest in spirit to Lawder, but with significant differences:
* octree state tables modified to match existing HSFC direction
* (Note, Lawder tables are incorrect!),
* no binary search, greatly simplifing the test for intersection,
* backtracking does not explicitly work backwards up the tree,
* query region and search region intersection calculated fresh at each level,
* partitioning rather than database application.
* (Note, no code examples were available in Lawder's publications, so this
* is an original adaptation.)
*
****************************************************************************/
static unsigned const int IMAX = ~(0U);
static unsigned const int idata2d[] = /* 2 dimension to nkey conversion */
{0, 3, 1, 2,
0, 1, 3, 2,
2, 3, 1, 0,
2, 1, 3, 0};
static unsigned const int istate2d[] = /* 2 dimension to nkey state transitions */
{1, 2, 0, 0,
0, 1, 3, 1,
2, 0, 2, 3,
3, 3, 1, 2};
static unsigned const int data2d[] = /* nkey to 2 dimension conversion */
{0, 2, 3, 1,
0, 1, 3, 2,
3, 2, 0, 1,
3, 1, 0, 2};
static unsigned const int state2d[] = /* nkey to 2 dimension state transitions */
{1, 0, 0, 2,
0, 1, 1, 3,
3, 2, 2, 0,
2, 3, 3, 1};
static unsigned const data3d [] = { /* nkey to 3 dimension conversion */
0, 4, 6, 2, 3, 7, 5, 1,
0, 1, 3, 2, 6, 7, 5, 4,
0, 4, 5, 1, 3, 7, 6, 2,
5, 4, 0, 1, 3, 2, 6, 7,
6, 7, 3, 2, 0, 1, 5, 4,
3, 7, 6, 2, 0, 4, 5, 1,
5, 4, 6, 7, 3, 2, 0, 1,
0, 1, 5, 4, 6, 7, 3, 2,
5, 1, 0, 4, 6, 2, 3, 7,
5, 1, 3, 7, 6, 2, 0, 4,
0, 2, 6, 4, 5, 7, 3, 1,
3, 1, 0, 2, 6, 4, 5, 7,
5, 7, 6, 4, 0, 2, 3, 1,
6, 7, 5, 4, 0, 1, 3, 2,
3, 1, 5, 7, 6, 4, 0, 2,
0, 2, 3, 1, 5, 7, 6, 4,
3, 2, 0, 1, 5, 4, 6, 7,
3, 2, 6, 7, 5, 4, 0, 1,
6, 2, 0, 4, 5, 1, 3, 7,
3, 7, 5, 1, 0, 4, 6, 2,
5, 7, 3, 1, 0, 2, 6, 4,
6, 2, 3, 7, 5, 1, 0, 4,
6, 4, 0, 2, 3, 1, 5, 7,
6, 4, 5, 7, 3, 1, 0, 2};
static unsigned const state3d [] = { /* nkey to 3 dimension state transitions */
1, 2, 0, 3, 4, 0, 5, 6,
0, 7, 1, 8, 5, 1, 4, 9,
15, 0, 2, 22, 20, 2, 19, 23,
20, 6, 3, 23, 15, 3, 16, 22,
22, 13, 4, 12, 11, 4, 1, 20,
11, 19, 5, 20, 22, 5, 0, 12,
9, 3, 6, 2, 21, 6, 17, 0,
10, 1, 7, 11, 12, 7, 13, 14,
12, 9, 8, 14, 10, 8, 18, 11,
6, 8, 9, 7, 17, 9, 21, 1,
7, 15, 10, 16, 13, 10, 12, 17,
5, 14, 11, 9, 0, 11, 22, 8,
8, 20, 12, 19, 18, 12, 10, 5,
18, 4, 13, 5, 8, 13, 7, 19,
17, 11, 14, 1, 6, 14, 23, 7,
2, 10, 15, 18, 19, 15, 20, 21,
19, 17, 16, 21, 2, 16, 3, 18,
14, 16, 17, 15, 23, 17, 6, 10,
13, 21, 18, 17, 7, 18, 8, 16,
16, 5, 19, 4, 3, 19, 2, 13,
3, 12, 20, 13, 16, 20, 15, 4,
23, 18, 21, 10, 14, 21, 9, 15,
4, 23, 22, 6, 1, 22, 11, 3,
21, 22, 23, 0, 9, 23, 14, 2};
static unsigned const idata3d [] = { /* 3 dimension to nkey conversion */
0, 7, 3, 4, 1, 6, 2, 5,
0, 1, 3, 2, 7, 6, 4, 5,
0, 3, 7, 4, 1, 2, 6, 5,
2, 3, 5, 4, 1, 0, 6, 7,
4, 5, 3, 2, 7, 6, 0, 1,
4, 7, 3, 0, 5, 6, 2, 1,
6, 7, 5, 4, 1, 0, 2, 3,
0, 1, 7, 6, 3, 2, 4, 5,
2, 1, 5, 6, 3, 0, 4, 7,
6, 1, 5, 2, 7, 0, 4, 3,
0, 7, 1, 6, 3, 4, 2, 5,
2, 1, 3, 0, 5, 6, 4, 7,
4, 7, 5, 6, 3, 0, 2, 1,
4, 5, 7, 6, 3, 2, 0, 1,
6, 1, 7, 0, 5, 2, 4, 3,
0, 3, 1, 2, 7, 4, 6, 5,
2, 3, 1, 0, 5, 4, 6, 7,
6, 7, 1, 0, 5, 4, 2, 3,
2, 5, 1, 6, 3, 4, 0, 7,
4, 3, 7, 0, 5, 2, 6, 1,
4, 3, 5, 2, 7, 0, 6, 1,
6, 5, 1, 2, 7, 4, 0, 3,
2, 5, 3, 4, 1, 6, 0, 7,
6, 5, 7, 4, 1, 2, 0, 3};
static unsigned const istate3d [] ={ /* 3 dimension to nkey state transitions */
1, 6, 3, 4, 2, 5, 0, 0,
0, 7, 8, 1, 9, 4, 5, 1,
15, 22, 23, 20, 0, 2, 19, 2,
3, 23, 3, 15, 6, 20, 16, 22,
11, 4, 12, 4, 20, 1, 22, 13,
22, 12, 20, 11, 5, 0, 5, 19,
17, 0, 6, 21, 3, 9, 6, 2,
10, 1, 14, 13, 11, 7, 12, 7,
8, 9, 8, 18, 14, 12, 10, 11,
21, 8, 9, 9, 1, 6, 17, 7,
7, 17, 15, 12, 16, 13, 10, 10,
11, 14, 9, 5, 11, 22, 0, 8,
18, 5, 12, 10, 19, 8, 12, 20,
8, 13, 19, 7, 5, 13, 18, 4,
23, 11, 7, 17, 14, 14, 6, 1,
2, 18, 10, 15, 21, 19, 20, 15,
16, 21, 17, 19, 16, 2, 3, 18,
6, 10, 16, 14, 17, 23, 17, 15,
18, 18, 21, 8, 17, 7, 13, 16,
3, 4, 13, 16, 19, 19, 2, 5,
16, 13, 20, 20, 4, 3, 15, 12,
9, 21, 18, 21, 15, 14, 23, 10,
22, 22, 6, 1, 23, 11, 4, 3,
14, 23, 2, 9, 22, 23, 21, 0};
double Zoltan_HSFC_InvHilbert1d (ZZ*, double *coord);
double Zoltan_HSFC_InvHilbert2d (ZZ*, double *coord);
double Zoltan_HSFC_InvHilbert3d (ZZ*, double *coord);
void Zoltan_HSFC_Hilbert1d (ZZ*, double *coord, double key);
void Zoltan_HSFC_Hilbert2d (ZZ*, double *coord, double key);
void Zoltan_HSFC_Hilbert3d (ZZ*, double *coord, double key);
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif
#endif

View File

@ -0,0 +1,70 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifndef __HSFC_PARAMS_H
#define __HSFC_PARAMS_H
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
#include "zz_const.h"
/* This structure is the Zoltan convention for user settable parameters */
static PARAM_VARS HSFC_params[] =
{{"KEEP_CUTS", NULL, "INT", 0},
{ "REDUCE_DIMENSIONS", NULL, "INT", 0 },
{ "DEGENERATE_RATIO", NULL, "DOUBLE", 0 },
{"FINAL_OUTPUT", NULL, "INT", 0},
{NULL, NULL, NULL, 0}};
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif
#endif

View File

@ -0,0 +1,133 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif
#include "hsfc.h"
#include "zz_const.h"
#include "zz_util_const.h"
/* For a detailed explaination of this module, please see the Developers
Guide. For instructions on its use, please see the Users Guide. */
/* 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;
}
#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif