blob: ab8b43d753f2bc1806dd7d0c4424874b0194863d [file] [log] [blame]
/*************************************************************************/
/* */
/* 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