374 lines
9.4 KiB
C
374 lines
9.4 KiB
C
/*************************************************************************/
|
|
/* */
|
|
/* Copyright (c) 1994 Stanford University */
|
|
/* */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* Permission is given to use, copy, and modify this software for any */
|
|
/* non-commercial purpose as long as this copyright notice is not */
|
|
/* removed. All other uses, including redistribution in whole or in */
|
|
/* part, are forbidden without prior written permission. */
|
|
/* */
|
|
/* This software is provided with absolutely no warranty and no */
|
|
/* support. */
|
|
/* */
|
|
/*************************************************************************/
|
|
|
|
#include <math.h>
|
|
#include <limits.h>
|
|
#include "defs.h"
|
|
#include "memory.h"
|
|
#include "particle.h"
|
|
#include "box.h"
|
|
#include "partition_grid.h"
|
|
|
|
#define DIVISOR(x) ((x <= 20) ? 1 : ((x - 20) * 50))
|
|
|
|
typedef struct _Id_Info id_info;
|
|
struct _Id_Info
|
|
{
|
|
long id;
|
|
long num;
|
|
};
|
|
|
|
typedef struct _Cost_Info cost_info;
|
|
struct _Cost_Info
|
|
{
|
|
long cost;
|
|
long num;
|
|
};
|
|
|
|
long CheckBox(long my_id, box *b, long partition_level);
|
|
|
|
void
|
|
InitPartition (long my_id)
|
|
{
|
|
long i;
|
|
|
|
Local[my_id].Childless_Partition = NULL;
|
|
for (i = 0; i < MAX_LEVEL; i++) {
|
|
Local[my_id].Parent_Partition[i] = NULL;
|
|
}
|
|
Local[my_id].Max_Parent_Level = -1;
|
|
}
|
|
|
|
|
|
void
|
|
PartitionIterate (long my_id, partition_function function,
|
|
partition_start position)
|
|
{
|
|
box *b;
|
|
long i;
|
|
|
|
if (position == CHILDREN) {
|
|
b = Local[my_id].Childless_Partition;
|
|
while (b != NULL) {
|
|
(*function)(my_id, b);
|
|
b = b->next;
|
|
}
|
|
}
|
|
else {
|
|
if (position == TOP) {
|
|
for (i = 0; i <= Local[my_id].Max_Parent_Level; i++) {
|
|
b = Local[my_id].Parent_Partition[i];
|
|
while (b != NULL) {
|
|
(*function)(my_id, b);
|
|
b = b->next;
|
|
}
|
|
}
|
|
b = Local[my_id].Childless_Partition;
|
|
while (b != NULL) {
|
|
(*function)(my_id, b);
|
|
b = b->next;
|
|
}
|
|
}
|
|
else {
|
|
b = Local[my_id].Childless_Partition;
|
|
while (b != NULL) {
|
|
(*function)(my_id, b);
|
|
b = b->next;
|
|
}
|
|
for (i = Local[my_id].Max_Parent_Level; i >= 0; i--) {
|
|
b = Local[my_id].Parent_Partition[i];
|
|
while (b != NULL) {
|
|
(*function)(my_id, b);
|
|
b = b->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
InsertBoxInPartition (long my_id, box *b)
|
|
{
|
|
box *level_list;
|
|
|
|
if (b->type == CHILDLESS) {
|
|
b->prev = NULL;
|
|
if (Local[my_id].Childless_Partition != NULL)
|
|
Local[my_id].Childless_Partition->prev = b;
|
|
b->next = Local[my_id].Childless_Partition;
|
|
Local[my_id].Childless_Partition = b;
|
|
}
|
|
else {
|
|
level_list = Local[my_id].Parent_Partition[b->level];
|
|
b->prev = NULL;
|
|
if (level_list != NULL)
|
|
level_list->prev = b;
|
|
b->next = level_list;
|
|
Local[my_id].Parent_Partition[b->level] = b;
|
|
if (b->level > Local[my_id].Max_Parent_Level) {
|
|
Local[my_id].Max_Parent_Level = b->level;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
RemoveBoxFromPartition (long my_id, box *b)
|
|
{
|
|
if (b->type == CHILDLESS) {
|
|
if (b->prev != NULL)
|
|
b->prev->next = b->next;
|
|
else
|
|
Local[my_id].Childless_Partition = b->next;
|
|
if (b->next != NULL)
|
|
b->next->prev = b->prev;
|
|
}
|
|
else {
|
|
if (b->prev != NULL)
|
|
b->prev->next = b->next;
|
|
else
|
|
Local[my_id].Parent_Partition[b->level] = b->next;
|
|
if (b->next != NULL)
|
|
b->next->prev = b->prev;
|
|
if ((b->level == Local[my_id].Max_Parent_Level) &&
|
|
(Local[my_id].Parent_Partition[b->level] == NULL)) {
|
|
while (Local[my_id].Parent_Partition[Local[my_id].Max_Parent_Level]
|
|
== NULL)
|
|
Local[my_id].Max_Parent_Level -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ComputeCostOfBox (box *b)
|
|
{
|
|
long different_costs;
|
|
long i;
|
|
long j;
|
|
long new_cost;
|
|
cost_info cost_list[MAX_PARTICLES_PER_BOX];
|
|
cost_info winner;
|
|
long winner_index;
|
|
long cost_index[MAX_PARTICLES_PER_BOX];
|
|
|
|
if (b->type == PARENT)
|
|
b->cost = ((b->num_v_list * V_LIST_COST(Expansion_Terms))
|
|
/ DIVISOR(Expansion_Terms)) + 1;
|
|
else {
|
|
different_costs = 0;
|
|
for (i = 0; i < b->num_particles; i++) {
|
|
new_cost = b->particles[i]->cost;
|
|
for (j = 0; j < different_costs; j++) {
|
|
if (new_cost == cost_list[j].cost)
|
|
break;
|
|
}
|
|
if (j == different_costs) {
|
|
cost_list[different_costs].cost = new_cost;
|
|
cost_list[different_costs].num = 1;
|
|
different_costs += 1;
|
|
}
|
|
else
|
|
cost_list[j].num += 1;
|
|
}
|
|
|
|
winner.cost = cost_list[0].cost;
|
|
winner.num = 1;
|
|
winner_index = 0;
|
|
cost_index[0] = 0;
|
|
for (i = 1; i < different_costs; i++) {
|
|
if (cost_list[i].num > cost_list[winner_index].num) {
|
|
winner.cost = cost_list[i].cost;
|
|
winner.num = 1;
|
|
winner_index = i;
|
|
cost_index[0] = i;
|
|
}
|
|
else {
|
|
if (cost_list[i].num == cost_list[winner_index].num) {
|
|
cost_index[winner.num] = i;
|
|
winner.num += 1;
|
|
}
|
|
}
|
|
}
|
|
if (winner.num != 1) {
|
|
for (i = 1; i < winner.num; i++)
|
|
winner.cost += cost_list[cost_index[i]].cost;
|
|
winner.cost /= winner.num;
|
|
}
|
|
b->cost = (winner.cost * b->num_particles) / DIVISOR(Expansion_Terms);
|
|
if (b->cost == 0)
|
|
b->cost = 1;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CheckPartition (long my_id)
|
|
{
|
|
long i;
|
|
box *b;
|
|
long NE, NoP, CB, PB;
|
|
long Q1, Q2, Q3, Q4;
|
|
long PC, CC;
|
|
real xpos, ypos;
|
|
|
|
NE = NoP = CB = PB = Q1 = Q2 = Q3 = Q4 = PC = CC = 0;
|
|
for (i = 0; i <= Local[my_id].Max_Parent_Level; i++) {
|
|
b = Local[my_id].Parent_Partition[i];
|
|
while (b != NULL) {
|
|
NE += CheckBox(my_id, b, i);
|
|
PB += 1;
|
|
PC += b->cost;
|
|
b = b->next;
|
|
}
|
|
}
|
|
b = Local[my_id].Childless_Partition;
|
|
while (b != NULL) {
|
|
NE += CheckBox(my_id, b, -1);
|
|
for (i = 0; i < b->num_particles; i++) {
|
|
xpos = b->particles[i]->pos.x;
|
|
ypos = b->particles[i]->pos.y;
|
|
if (xpos > Grid->x_center) {
|
|
if (ypos > Grid->y_center)
|
|
Q1 += 1;
|
|
else
|
|
Q4 += 1;
|
|
}
|
|
else {
|
|
if (ypos > Grid->y_center)
|
|
Q2 += 1;
|
|
else
|
|
Q3 += 1;
|
|
}
|
|
}
|
|
NoP += b->num_particles;
|
|
CB += 1;
|
|
CC += b->cost;
|
|
b = b->next;
|
|
}
|
|
}
|
|
|
|
|
|
long
|
|
CheckBox (long my_id, box *b, long partition_level)
|
|
{
|
|
long num_errors;
|
|
|
|
num_errors = 0;
|
|
if (b->type == CHILDLESS) {
|
|
if (partition_level != -1) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : CHILDLESS box in parent partition (B%f P%ld %ld)\n", b->id, my_id, b->proc);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
if (b->num_children != 0) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : CHILDLESS box has children (B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
if (b->num_particles == 0) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : CHILDLESS box has no particles (B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
if (b->particles[b->num_particles - 1] == NULL) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : CHILDLESS box has fewer particles than expected ");
|
|
printf("(B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
if (b->particles[b->num_particles] != NULL) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : CHILDLESS box has more particles than expected ");
|
|
printf("(B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
}
|
|
else {
|
|
if (partition_level == -1) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : PARENT box in childless partition (B%f P%ld %ld)\n",
|
|
b->id, my_id, b->proc);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
else {
|
|
if (partition_level != b->level) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : PARENT box in wrong partition level ");
|
|
printf("(%ld vs %ld) (B%f P%ld)\n", b->level, partition_level, b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
}
|
|
if (b->num_children == 0) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : PARENT box has no children (B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
if (b->num_particles != 0) {
|
|
LOCK(G_Memory->io_lock);
|
|
printf("ERROR : PARENT box has particles (B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
}
|
|
if (b->parent == NULL) {
|
|
if (b != Grid) {
|
|
LOCK(G_Memory->io_lock);
|
|
if (b->type == CHILDLESS)
|
|
printf("ERROR : Extra CHILDLESS box in partition (B%f P%ld)\n", b->id, my_id);
|
|
else
|
|
printf("ERROR : Extra PARENT box in partition (B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
}
|
|
else {
|
|
if (b->parent->children[b->child_num] != b) {
|
|
LOCK(G_Memory->io_lock);
|
|
if (b->type == CHILDLESS)
|
|
printf("ERROR : Extra CHILDLESS box in partition (B%f P%ld)\n", b->id, my_id);
|
|
else
|
|
printf("ERROR : Extra PARENT box in partition (B%f P%ld)\n", b->id, my_id);
|
|
fflush(stdout);
|
|
UNLOCK(G_Memory->io_lock);
|
|
num_errors += 1;
|
|
}
|
|
}
|
|
return num_errors;
|
|
}
|
|
|
|
|
|
#undef DIVISOR
|