1120 lines
30 KiB
C
1120 lines
30 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 <stdio.h>
|
|
#include <float.h>
|
|
#include "defs.h"
|
|
#include "memory.h"
|
|
#include "particle.h"
|
|
#include "box.h"
|
|
#include "partition_grid.h"
|
|
#include "construct_grid.h"
|
|
|
|
#define MY_PARTICLES (Local[my_id].Particles)
|
|
#define MY_NUM_PARTICLES (Local[my_id].Num_Particles)
|
|
#define MY_MAX_PARTICLES (Local[my_id].Max_Particles)
|
|
|
|
void DetermineGridSize(long my_id);
|
|
void DetermineLocalGridSize(long my_id);
|
|
void MergeLocalGridSize(long my_id);
|
|
void ConstructLocalGrid(long my_id);
|
|
box *InitGrid(long my_id);
|
|
void InsertParticlesInTree(long my_id, particle **p_list, long num_of_particles, box *root);
|
|
box *FindHome(long my_id, particle *p, box *current_home);
|
|
box *FindInitialRoot(particle *p, box *current_home);
|
|
box *CreateChild(long my_id, box *pb, long new_child_num);
|
|
void SubdivideBox(long my_id, box *b);
|
|
void MergeLocalGrid(long my_id);
|
|
void MLGHelper(long my_id, box *local_box, box *global_box, box *global_parent);
|
|
void MergeLocalParticles(long my_id, particle **p_array, long num_of_particles, box *pb);
|
|
void SplitParticles(particle **p_array, long length, particle **p_dist, long num_p_dist[NUM_OFFSPRING], box *pb);
|
|
box *CreateLeaf(long my_id, box *pb, long new_child_num, particle **p_array, long length);
|
|
void InsertParticlesInLeaf(long my_id, particle **p_array, long length, box *b);
|
|
long InsertBoxInGrid(long my_id, box *b, box *pb);
|
|
long RemoveBoxFromGrid(box *b, box *pb);
|
|
void InsertSubtreeInPartition(long my_id, box *b);
|
|
void CleanupGrid(long my_id);
|
|
void SetSiblings(box *b);
|
|
void SetColleagues(long my_id, box *b);
|
|
void ConstructGridLists(long my_id, box *b);
|
|
void ConstructInteractionLists(long my_id, box *b);
|
|
void SetVList(long my_id, box *b);
|
|
void SetUList(long my_id, box *b);
|
|
void SetUListHelper(long my_id, box *b, box *pb);
|
|
long AncestorBox(box *b, box *ancestor_box);
|
|
void SetWList(long my_id, box *b);
|
|
void InsertNonAdjChildren(long my_id, box *b, box *pb);
|
|
|
|
|
|
void
|
|
ConstructGrid (long my_id, time_info *local_time, long time_all)
|
|
{
|
|
unsigned long init = 0, start = 0, finish;
|
|
|
|
if (time_all)
|
|
CLOCK(init);
|
|
DetermineGridSize(my_id); /* Finds the four corners of the grid. */
|
|
FreeBoxes(my_id);
|
|
InitPartition(my_id);
|
|
if (time_all)
|
|
CLOCK(start);
|
|
if (MY_NUM_PARTICLES > 0) {
|
|
ConstructLocalGrid(my_id); /* Each processor constructs their own tree
|
|
based on only their particles */
|
|
MergeLocalGrid(my_id); /* The processors combine their trees into one
|
|
global tree. This step contains
|
|
communication between processors. */
|
|
}
|
|
BARRIER(G_Memory->synch, Number_Of_Processors);
|
|
CleanupGrid(my_id);
|
|
if (time_all)
|
|
CLOCK(finish);
|
|
|
|
if (time_all) {
|
|
local_time[MY_TIME_STEP].other_time = start - init;
|
|
local_time[MY_TIME_STEP].construct_time = finish - start;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ConstructLists (long my_id, time_info *local_time, long time_all)
|
|
{
|
|
unsigned long start, finish;
|
|
|
|
if (time_all)
|
|
CLOCK(start);
|
|
PartitionIterate(my_id, ConstructGridLists, TOP);
|
|
BARRIER(G_Memory->synch, Number_Of_Processors);
|
|
PartitionIterate(my_id, ConstructInteractionLists, BOTTOM);
|
|
if (time_all)
|
|
CLOCK(finish);
|
|
|
|
if (time_all) {
|
|
local_time[MY_TIME_STEP].list_time = finish - start;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DestroyGrid (long my_id, time_info *local_time, long time_all)
|
|
{
|
|
box *b_scan, *tb;
|
|
particle *p;
|
|
long i;
|
|
long particle_cost;
|
|
unsigned long start = 0, finish;
|
|
|
|
if (time_all)
|
|
CLOCK(start);
|
|
b_scan = Local[my_id].Childless_Partition;
|
|
MY_NUM_PARTICLES = 0;
|
|
while (b_scan != NULL) {
|
|
tb = b_scan;
|
|
b_scan = b_scan->next;
|
|
particle_cost = tb->cost / tb->num_particles;
|
|
for (i = 0; i < tb->num_particles; i++) {
|
|
if (MY_MAX_PARTICLES <= MY_NUM_PARTICLES) {
|
|
LockedPrint("ERROR (P%d) : Too many particles in local array\n", my_id);
|
|
exit(-1);
|
|
}
|
|
p = tb->particles[i];
|
|
p->cost = particle_cost;
|
|
MY_PARTICLES[MY_NUM_PARTICLES++] = p;
|
|
}
|
|
}
|
|
if (my_id == 0)
|
|
Grid = NULL;
|
|
if (time_all) {
|
|
CLOCK(finish);
|
|
local_time[MY_TIME_STEP].other_time += finish - start;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* PrintGrid (long my_id)
|
|
*
|
|
* Args : none.
|
|
*
|
|
* Returns : nothing.
|
|
*
|
|
* Side Effects : Prints the entire box structure of the grid to stdout.
|
|
*
|
|
*/
|
|
void
|
|
PrintGrid (long my_id)
|
|
{
|
|
if (Grid != NULL) {
|
|
if (my_id == 0) {
|
|
printf("Info for Adaptive Grid :\n");
|
|
printf("Boxes :\n\n");
|
|
}
|
|
fflush(stdout);
|
|
BARRIER(G_Memory->synch, Number_Of_Processors);
|
|
PartitionIterate(my_id, PrintBox, TOP);
|
|
BARRIER(G_Memory->synch, Number_Of_Processors);
|
|
if (my_id == 0) {
|
|
printf("\n");
|
|
}
|
|
fflush(stdout);
|
|
BARRIER(G_Memory->synch, Number_Of_Processors);
|
|
}
|
|
else
|
|
printf("Adaptive grid has not been initialized yet.\n");
|
|
}
|
|
|
|
|
|
void
|
|
DetermineGridSize (long my_id)
|
|
{
|
|
DetermineLocalGridSize(my_id); /* Processor looks at its own particles and
|
|
finds the x and y max and min */
|
|
MergeLocalGridSize(my_id); /* Processors shares info with others and each
|
|
one computes the global max and min */
|
|
}
|
|
|
|
|
|
/* This code is pretty straightforward. A processor scans through its list of
|
|
particles and finds the x_max, x_min, y_max, y_min. The only interesting
|
|
thing is that particles are looked at two at a time, and compared to each
|
|
other before looking at the current best max and min. This speeds up the
|
|
running time of the algorithm from 2n to 3/2n. */
|
|
void
|
|
DetermineLocalGridSize (long my_id)
|
|
{
|
|
real x_pos1, x_pos2, y_pos1, y_pos2;
|
|
real x_max_challenger, x_min_challenger, y_max_challenger, y_min_challenger;
|
|
long i;
|
|
|
|
Local[my_id].Local_X_Max = -MAX_REAL;
|
|
Local[my_id].Local_X_Min = MAX_REAL;
|
|
Local[my_id].Local_Y_Max = -MAX_REAL;
|
|
Local[my_id].Local_Y_Min = MAX_REAL;
|
|
for (i = 0; i < MY_NUM_PARTICLES - 1; i += 2) {
|
|
x_pos1 = MY_PARTICLES[i]->pos.x;
|
|
y_pos1 = MY_PARTICLES[i]->pos.y;
|
|
x_pos2 = MY_PARTICLES[i + 1]->pos.x;
|
|
y_pos2 = MY_PARTICLES[i + 1]->pos.y;
|
|
if (x_pos1 > x_pos2) {
|
|
x_max_challenger = x_pos1;
|
|
x_min_challenger = x_pos2;
|
|
}
|
|
else {
|
|
x_max_challenger = x_pos2;
|
|
x_min_challenger = x_pos1;
|
|
}
|
|
if (y_pos1 > y_pos2) {
|
|
y_max_challenger = y_pos1;
|
|
y_min_challenger = y_pos2;
|
|
}
|
|
else {
|
|
y_max_challenger = y_pos2;
|
|
y_min_challenger = y_pos1;
|
|
}
|
|
if (x_max_challenger > Local[my_id].Local_X_Max)
|
|
Local[my_id].Local_X_Max = x_max_challenger;
|
|
if (x_min_challenger < Local[my_id].Local_X_Min)
|
|
Local[my_id].Local_X_Min = x_min_challenger;
|
|
if (y_max_challenger > Local[my_id].Local_Y_Max)
|
|
Local[my_id].Local_Y_Max = y_max_challenger;
|
|
if (y_min_challenger < Local[my_id].Local_Y_Min)
|
|
Local[my_id].Local_Y_Min = y_min_challenger;
|
|
}
|
|
if (i == (MY_NUM_PARTICLES - 1)) {
|
|
x_max_challenger = MY_PARTICLES[i]->pos.x;
|
|
x_min_challenger = MY_PARTICLES[i]->pos.x;
|
|
y_max_challenger = MY_PARTICLES[i]->pos.y;
|
|
y_min_challenger = MY_PARTICLES[i]->pos.y;
|
|
if (x_max_challenger > Local[my_id].Local_X_Max)
|
|
Local[my_id].Local_X_Max = x_max_challenger;
|
|
if (x_min_challenger < Local[my_id].Local_X_Min)
|
|
Local[my_id].Local_X_Min = x_min_challenger;
|
|
if (y_max_challenger > Local[my_id].Local_Y_Max)
|
|
Local[my_id].Local_Y_Max = y_max_challenger;
|
|
if (y_min_challenger < Local[my_id].Local_Y_Min)
|
|
Local[my_id].Local_Y_Min = y_min_challenger;
|
|
}
|
|
}
|
|
|
|
|
|
/* Each processor writes its best to a global
|
|
array, then they read everyone else's and find the absolute best. */
|
|
void
|
|
MergeLocalGridSize (long my_id)
|
|
{
|
|
real *my_f_array, *their_f_array;
|
|
real x_max_challenger, x_min_challenger, y_max_challenger, y_min_challenger;
|
|
long i;
|
|
|
|
my_f_array = G_Memory->f_array[my_id];
|
|
my_f_array[0] = Local[my_id].Local_X_Max;
|
|
my_f_array[1] = Local[my_id].Local_X_Min;
|
|
my_f_array[2] = Local[my_id].Local_Y_Max;
|
|
my_f_array[3] = Local[my_id].Local_Y_Min;
|
|
BARRIER(G_Memory->synch, Number_Of_Processors);
|
|
|
|
for (i = 0; i < Number_Of_Processors; i++) {
|
|
their_f_array = G_Memory->f_array[i];
|
|
x_max_challenger = their_f_array[0];
|
|
x_min_challenger = their_f_array[1];
|
|
y_max_challenger = their_f_array[2];
|
|
y_min_challenger = their_f_array[3];
|
|
if (x_max_challenger > Local[my_id].Local_X_Max)
|
|
Local[my_id].Local_X_Max = x_max_challenger;
|
|
if (x_min_challenger < Local[my_id].Local_X_Min)
|
|
Local[my_id].Local_X_Min = x_min_challenger;
|
|
if (y_max_challenger > Local[my_id].Local_Y_Max)
|
|
Local[my_id].Local_Y_Max = y_max_challenger;
|
|
if (y_min_challenger < Local[my_id].Local_Y_Min)
|
|
Local[my_id].Local_Y_Min = y_min_challenger;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ConstructLocalGrid (long my_id)
|
|
{
|
|
Local[my_id].Local_Grid = InitGrid(my_id); /* Create the root box */
|
|
InsertParticlesInTree(my_id, MY_PARTICLES, MY_NUM_PARTICLES,
|
|
Local[my_id].Local_Grid);
|
|
/* Put all of your particles into your local tree */
|
|
}
|
|
|
|
|
|
box *
|
|
InitGrid (long my_id)
|
|
{
|
|
real x_length, y_length;
|
|
real grid_length, grid_x_center, grid_y_center;
|
|
long exp;
|
|
box *ret_box;
|
|
|
|
frexp(Local[my_id].Local_X_Max, &exp);
|
|
if (Local[my_id].Local_X_Max > 0)
|
|
Local[my_id].Local_X_Max = ldexp(1.0, exp);
|
|
else {
|
|
if (Local[my_id].Local_X_Max < 0)
|
|
Local[my_id].Local_X_Max = -ldexp(1.0, exp - 1);
|
|
}
|
|
frexp(Local[my_id].Local_X_Min, &exp);
|
|
if (Local[my_id].Local_X_Min < 0)
|
|
Local[my_id].Local_X_Min = -ldexp(1.0, exp);
|
|
else {
|
|
if (Local[my_id].Local_X_Min > 0)
|
|
Local[my_id].Local_X_Min = ldexp(1.0, exp - 1);
|
|
}
|
|
frexp(Local[my_id].Local_Y_Max, &exp);
|
|
if (Local[my_id].Local_Y_Max > 0)
|
|
Local[my_id].Local_Y_Max = ldexp(1.0, exp);
|
|
else {
|
|
if (Local[my_id].Local_Y_Max < 0)
|
|
Local[my_id].Local_Y_Max = -ldexp(1.0, exp - 1);
|
|
}
|
|
frexp(Local[my_id].Local_Y_Min, &exp);
|
|
if (Local[my_id].Local_Y_Min < 0)
|
|
Local[my_id].Local_Y_Min = -ldexp(1.0, exp);
|
|
else {
|
|
if (Local[my_id].Local_Y_Min > 0)
|
|
Local[my_id].Local_Y_Min = ldexp(1.0, exp - 1);
|
|
}
|
|
|
|
x_length = Local[my_id].Local_X_Max - Local[my_id].Local_X_Min;
|
|
y_length = Local[my_id].Local_Y_Max - Local[my_id].Local_Y_Min;
|
|
if (x_length > y_length)
|
|
grid_length = x_length;
|
|
else
|
|
grid_length = y_length;
|
|
grid_x_center = (grid_length / (real) 2.0) + Local[my_id].Local_X_Min;
|
|
grid_y_center = (grid_length / (real) 2.0) + Local[my_id].Local_Y_Min;
|
|
|
|
ret_box = InitBox(my_id, grid_x_center, grid_y_center, grid_length, NULL);
|
|
return ret_box;
|
|
}
|
|
|
|
|
|
/* All this procedure does is put the particles in p_list into the tree pointed
|
|
to by root. For each particle, you find out which childless (ie body) box
|
|
the particle is supposed to go into, and insert it. Because childless boxes
|
|
in this code can have 40 particles in them, instead of one for B-H, I have
|
|
to check that. B-H is the same as having a MAX_PARTICLES_PER_BOX of 1. When
|
|
that value is exceeded, the childless box is subdivided and the particles
|
|
are divided up amongst the children. Note that all the particles may be put
|
|
into one child, in which case that child must be subdivided as well, and so
|
|
on until there is more than one child. */
|
|
void
|
|
InsertParticlesInTree (long my_id, particle **p_list, long num_of_particles, box *root)
|
|
{
|
|
particle *p;
|
|
box *dest_box;
|
|
long i, j;
|
|
|
|
dest_box = root;
|
|
for (i = 0; i < num_of_particles; i++) {
|
|
p = p_list[i];
|
|
dest_box = FindHome(my_id, p, dest_box);
|
|
dest_box->particles[dest_box->num_particles++] = p;
|
|
while (dest_box->num_particles > MAX_PARTICLES_PER_BOX) {
|
|
SubdivideBox(my_id, dest_box);
|
|
if (dest_box->num_children == 1) {
|
|
for (j = 0; dest_box->children[j] == NULL; j++)
|
|
;
|
|
dest_box = dest_box->children[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* This function compares the particles position to the center of the parent
|
|
(or cell) box and chooses the appropriate child to move down to, until
|
|
either a child box or a null pointer is reached. In the first case, the box
|
|
is returned, and in the second, a new child box is created for the parent,
|
|
and that box is returned. */
|
|
box *
|
|
FindHome (long my_id, particle *p, box *current_home)
|
|
{
|
|
box *pb;
|
|
|
|
pb = FindInitialRoot(p, current_home);
|
|
while (pb->type == PARENT) {
|
|
if (p->pos.y > pb->y_center) {
|
|
if (p->pos.x > pb->x_center) {
|
|
if (pb->children[0] == NULL)
|
|
CreateChild(my_id, pb, 0);
|
|
pb = pb->children[0];
|
|
}
|
|
else {
|
|
if (pb->children[1] == NULL)
|
|
CreateChild(my_id, pb, 1);
|
|
pb = pb->children[1];
|
|
}
|
|
}
|
|
else {
|
|
if (p->pos.x > pb->x_center) {
|
|
if (pb->children[3] == NULL)
|
|
CreateChild(my_id, pb, 3);
|
|
pb = pb->children[3];
|
|
}
|
|
else {
|
|
if (pb->children[2] == NULL)
|
|
CreateChild(my_id, pb, 2);
|
|
pb = pb->children[2];
|
|
}
|
|
}
|
|
}
|
|
return pb;
|
|
}
|
|
|
|
|
|
box *
|
|
FindInitialRoot (particle *p, box *current_home)
|
|
{
|
|
long found;
|
|
real x_center_distance, y_center_distance;
|
|
|
|
found = FALSE;
|
|
while (found == FALSE) {
|
|
x_center_distance = p->pos.x - current_home->x_center;
|
|
y_center_distance = p->pos.y - current_home->y_center;
|
|
if (x_center_distance < 0)
|
|
x_center_distance = -x_center_distance;
|
|
if (y_center_distance < 0)
|
|
y_center_distance = -y_center_distance;
|
|
if ((x_center_distance > (current_home->length / 2.0)) ||
|
|
(y_center_distance > (current_home->length / 2.0)))
|
|
current_home = current_home->parent;
|
|
else
|
|
found = TRUE;
|
|
}
|
|
return current_home;
|
|
}
|
|
|
|
|
|
|
|
/* Simply creates a new box and sets the parent and child pointers correctly.
|
|
The child's spot in the parent's children array determines its position.
|
|
So, 0 is upper right, 1 is upper left, 2 is bottom left, and 3 is bottom
|
|
right. That's how I know how to set the location of the child box's center
|
|
just by knowing the child number. */
|
|
box *
|
|
CreateChild (long my_id, box *pb, long new_child_num)
|
|
{
|
|
real child_length, child_offset;
|
|
box *ret_box;
|
|
|
|
child_length = pb->length / (real) NUM_DIMENSIONS;
|
|
child_offset = pb->length / (real) NUM_OFFSPRING;
|
|
if (new_child_num == 0) {
|
|
pb->children[0] = InitBox(my_id, (pb->x_center + child_offset),
|
|
(pb->y_center + child_offset), child_length,
|
|
pb);
|
|
pb->shadow[0] = pb->children[0];
|
|
}
|
|
if (new_child_num == 1) {
|
|
pb->children[1] = InitBox(my_id, (pb->x_center - child_offset),
|
|
(pb->y_center + child_offset), child_length,
|
|
pb);
|
|
pb->shadow[1] = pb->children[1];
|
|
}
|
|
if (new_child_num == 2) {
|
|
pb->children[2] = InitBox(my_id, (pb->x_center - child_offset),
|
|
(pb->y_center - child_offset), child_length,
|
|
pb);
|
|
pb->shadow[2] = pb->children[2];
|
|
}
|
|
if (new_child_num == 3) {
|
|
pb->children[3] = InitBox(my_id, (pb->x_center + child_offset),
|
|
(pb->y_center - child_offset), child_length,
|
|
pb);
|
|
pb->shadow[3] = pb->children[3];
|
|
}
|
|
pb->children[new_child_num]->child_num = new_child_num;
|
|
ret_box = pb->children[new_child_num];
|
|
pb->num_children += 1;
|
|
return ret_box;
|
|
}
|
|
|
|
|
|
/* Looks at all the particles of the parent box and distributes them amongst
|
|
the children. If the child does not exist, one is created. */
|
|
void
|
|
SubdivideBox (long my_id, box *b)
|
|
{
|
|
particle *p;
|
|
box *child;
|
|
long i;
|
|
|
|
for (i = 0; i < b->num_particles; i++) {
|
|
p = b->particles[i];
|
|
if (p->pos.y > b->y_center) {
|
|
if (p->pos.x > b->x_center) {
|
|
child = b->children[0];
|
|
if (child == NULL)
|
|
child = CreateChild(my_id, b, 0);
|
|
}
|
|
else {
|
|
child = b->children[1];
|
|
if (child == NULL)
|
|
child = CreateChild(my_id, b, 1);
|
|
}
|
|
}
|
|
else {
|
|
if (p->pos.x > b->x_center) {
|
|
child = b->children[3];
|
|
if (child == NULL)
|
|
child = CreateChild(my_id, b, 3);
|
|
}
|
|
else {
|
|
child = b->children[2];
|
|
if (child == NULL)
|
|
child = CreateChild(my_id, b, 2);
|
|
}
|
|
}
|
|
child->particles[child->num_particles++] = p;
|
|
b->particles[i] = NULL;
|
|
}
|
|
b->num_particles = 0;
|
|
b->type = PARENT;
|
|
}
|
|
|
|
|
|
/* Each processor keeps track of the boxes that it has inserted into the tree.
|
|
This list is called a partition because when construction is over, every box
|
|
in the global tree will also reside in one and only one of the processors'
|
|
partitions. This is needed for list construction (which you don't have to
|
|
worry about) and cost zone computation (which you will). */
|
|
void
|
|
MergeLocalGrid (long my_id)
|
|
{
|
|
MLGHelper(my_id, Local[my_id].Local_Grid, Grid, NULL);
|
|
}
|
|
|
|
|
|
void
|
|
MLGHelper (long my_id, box *local_box, box *global_box, box *global_parent)
|
|
{
|
|
long success;
|
|
long i;
|
|
|
|
success = FALSE;
|
|
while (success == FALSE) {
|
|
if (local_box->type == PARENT) {
|
|
if (global_box == NULL) {
|
|
success = InsertBoxInGrid(my_id, local_box, global_parent);
|
|
}
|
|
else {
|
|
if (global_box->type == PARENT) {
|
|
success = TRUE;
|
|
for (i = 0; i < NUM_OFFSPRING; i++) {
|
|
if (local_box->children[i] != NULL)
|
|
MLGHelper(my_id, local_box->children[i],
|
|
global_box->children[i], global_box);
|
|
}
|
|
}
|
|
else {
|
|
success = RemoveBoxFromGrid(global_box, global_parent);
|
|
if (success == TRUE) {
|
|
InsertParticlesInTree(my_id, global_box->particles,
|
|
global_box->num_particles, local_box);
|
|
success = InsertBoxInGrid(my_id, local_box, global_parent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (global_box == NULL) {
|
|
success = InsertBoxInGrid(my_id, local_box, global_parent);
|
|
}
|
|
else {
|
|
if (global_box->type == PARENT) {
|
|
MergeLocalParticles(my_id, local_box->particles,
|
|
local_box->num_particles, global_box);
|
|
success = TRUE;
|
|
}
|
|
else {
|
|
success = RemoveBoxFromGrid(global_box, global_parent);
|
|
if (success == TRUE) {
|
|
InsertParticlesInLeaf(my_id, global_box->particles,
|
|
global_box->num_particles, local_box);
|
|
success = InsertBoxInGrid(my_id, local_box, global_parent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (success == FALSE) {
|
|
if (global_parent == NULL)
|
|
global_box = Grid;
|
|
else
|
|
global_box = global_parent->children[local_box->child_num];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
MergeLocalParticles (long my_id, particle **p_array, long num_of_particles, box *pb)
|
|
{
|
|
particle *(p_dist)[NUM_OFFSPRING][MAX_PARTICLES_PER_BOX];
|
|
long num_p_dist[NUM_OFFSPRING];
|
|
box *child;
|
|
long success;
|
|
long i;
|
|
|
|
SplitParticles(p_array, num_of_particles,
|
|
(particle **) p_dist, num_p_dist, pb);
|
|
for (i= 0; i < NUM_OFFSPRING; i++) {
|
|
if (num_p_dist[i] > 0) {
|
|
child = pb->children[i];
|
|
if (child == NULL) {
|
|
child = CreateLeaf(my_id, pb, i, p_dist[i], num_p_dist[i]);
|
|
success = InsertBoxInGrid(my_id, child, pb);
|
|
}
|
|
else {
|
|
if (child->type == PARENT) {
|
|
MergeLocalParticles(my_id, p_dist[i], num_p_dist[i], child);
|
|
success = TRUE;
|
|
}
|
|
else {
|
|
success = RemoveBoxFromGrid(child, pb);
|
|
if (success == TRUE) {
|
|
InsertParticlesInLeaf(my_id, p_dist[i], num_p_dist[i], child);
|
|
success = InsertBoxInGrid(my_id, child, pb);
|
|
}
|
|
else
|
|
child = CreateLeaf(my_id, pb, i, p_dist[i], num_p_dist[i]);
|
|
}
|
|
}
|
|
if (success == FALSE) {
|
|
MLGHelper(my_id, child, pb->children[child->child_num], pb);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
SplitParticles (particle **p_array, long length, particle **p_dist,
|
|
long num_p_dist[NUM_OFFSPRING], box *pb)
|
|
{
|
|
particle *p;
|
|
long i;
|
|
|
|
for (i = 0; i < NUM_OFFSPRING; i++)
|
|
num_p_dist[i] = 0;
|
|
for (i = 0; i < length; i++) {
|
|
p = p_array[i];
|
|
if (p->pos.y > pb->y_center) {
|
|
if (p->pos.x > pb->x_center)
|
|
*(p_dist + num_p_dist[0]++) = p;
|
|
else
|
|
*(p_dist + MAX_PARTICLES_PER_BOX + num_p_dist[1]++) = p;
|
|
}
|
|
else {
|
|
if (p->pos.x > pb->x_center)
|
|
*(p_dist + (3 * MAX_PARTICLES_PER_BOX) + num_p_dist[3]++) = p;
|
|
else
|
|
*(p_dist + (2 * MAX_PARTICLES_PER_BOX) + num_p_dist[2]++) = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
box *
|
|
CreateLeaf (long my_id, box *pb, long new_child_num, particle **p_array, long length)
|
|
{
|
|
real child_length, child_offset;
|
|
box *ret_box = NULL;
|
|
long i;
|
|
|
|
child_length = pb->length / (real) NUM_DIMENSIONS;
|
|
child_offset = pb->length / (real) NUM_OFFSPRING;
|
|
if (new_child_num == 0) {
|
|
ret_box = InitBox(my_id, (pb->x_center + child_offset),
|
|
(pb->y_center + child_offset), child_length,
|
|
pb);
|
|
}
|
|
if (new_child_num == 1) {
|
|
ret_box = InitBox(my_id, (pb->x_center - child_offset),
|
|
(pb->y_center + child_offset), child_length,
|
|
pb);
|
|
}
|
|
if (new_child_num == 2) {
|
|
ret_box = InitBox(my_id, (pb->x_center - child_offset),
|
|
(pb->y_center - child_offset), child_length,
|
|
pb);
|
|
}
|
|
if (new_child_num == 3) {
|
|
ret_box = InitBox(my_id, (pb->x_center + child_offset),
|
|
(pb->y_center - child_offset), child_length,
|
|
pb);
|
|
}
|
|
ret_box->child_num = new_child_num;
|
|
for (i = 0; i < length; i++) {
|
|
ret_box->particles[i] = p_array[i];
|
|
}
|
|
ret_box->num_particles = length;
|
|
return ret_box;
|
|
}
|
|
|
|
|
|
void
|
|
InsertParticlesInLeaf (long my_id, particle **p_array, long length, box *b)
|
|
{
|
|
long i, j;
|
|
long offset;
|
|
|
|
if ((length + b->num_particles) > MAX_PARTICLES_PER_BOX) {
|
|
for (i = b->num_particles, j = length - 1; i < MAX_PARTICLES_PER_BOX;
|
|
i++, j--)
|
|
b->particles[i] = p_array[j];
|
|
b->num_particles = MAX_PARTICLES_PER_BOX;
|
|
length = j + 1;
|
|
InsertParticlesInTree(my_id, p_array, length, b);
|
|
}
|
|
else {
|
|
offset = b->num_particles;
|
|
for (i = 0; i < length; i++)
|
|
b->particles[i + offset] = p_array[i];
|
|
b->num_particles += length;
|
|
}
|
|
}
|
|
|
|
|
|
long
|
|
InsertBoxInGrid (long my_id, box *b, box *pb)
|
|
{
|
|
long success;
|
|
|
|
if (pb == NULL) {
|
|
LOCK(G_Memory->single_lock);
|
|
if (Grid == NULL) {
|
|
Grid = b;
|
|
success = TRUE;
|
|
}
|
|
else
|
|
success = FALSE;
|
|
UNLOCK(G_Memory->single_lock);
|
|
}
|
|
else {
|
|
ALOCK(G_Memory->lock_array, pb->particle_lock_index);
|
|
if (pb->children[b->child_num] == NULL) {
|
|
pb->children[b->child_num] = b;
|
|
pb->num_children += 1;
|
|
b->parent = pb;
|
|
success = TRUE;
|
|
}
|
|
else
|
|
success = FALSE;
|
|
AULOCK(G_Memory->lock_array, pb->particle_lock_index);
|
|
}
|
|
if (success == TRUE)
|
|
InsertSubtreeInPartition(my_id, b);
|
|
return success;
|
|
}
|
|
|
|
|
|
long
|
|
RemoveBoxFromGrid (box *b, box *pb)
|
|
{
|
|
long success;
|
|
|
|
if (pb == NULL) {
|
|
LOCK(G_Memory->single_lock);
|
|
if (Grid == b) {
|
|
Grid = NULL;
|
|
success = TRUE;
|
|
}
|
|
else
|
|
success = FALSE;
|
|
UNLOCK(G_Memory->single_lock);
|
|
}
|
|
else {
|
|
ALOCK(G_Memory->lock_array, pb->particle_lock_index);
|
|
if (pb->children[b->child_num] == b) {
|
|
pb->children[b->child_num] = NULL;
|
|
b->parent = NULL;
|
|
pb->num_children -= 1;
|
|
success = TRUE;
|
|
}
|
|
else
|
|
success = FALSE;
|
|
AULOCK(G_Memory->lock_array, pb->particle_lock_index);
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
void
|
|
InsertSubtreeInPartition (long my_id, box *b)
|
|
{
|
|
long i;
|
|
box *child;
|
|
|
|
if (b->proc == my_id) {
|
|
InsertBoxInPartition(my_id, b);
|
|
}
|
|
if (b->type == PARENT) {
|
|
for (i = 0; i < NUM_OFFSPRING; i++) {
|
|
child = b->children[i];
|
|
if (child == NULL)
|
|
child = b->shadow[i];
|
|
if (child != NULL)
|
|
InsertSubtreeInPartition(my_id, child);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CleanupGrid (long my_id)
|
|
{
|
|
box *b_scan, *tb;
|
|
|
|
b_scan = Local[my_id].Childless_Partition;
|
|
while (b_scan != NULL) {
|
|
if (((b_scan->parent != NULL) || (b_scan == Grid))
|
|
&& (b_scan->type == CHILDLESS))
|
|
b_scan = b_scan->next;
|
|
else {
|
|
tb = b_scan;
|
|
b_scan = b_scan->next;
|
|
if (tb->type == PARENT) {
|
|
tb->type = CHILDLESS;
|
|
RemoveBoxFromPartition(my_id, tb);
|
|
tb->type = PARENT;
|
|
if ((tb->parent != NULL) || (tb == Grid)) {
|
|
InsertBoxInPartition(my_id, tb);
|
|
}
|
|
}
|
|
else
|
|
RemoveBoxFromPartition(my_id, tb);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ConstructGridLists (long my_id, box *b)
|
|
{
|
|
SetSiblings(b);
|
|
SetColleagues(my_id, b);
|
|
}
|
|
|
|
|
|
void
|
|
SetSiblings (box *b)
|
|
{
|
|
box *pb, *sb;
|
|
long i;
|
|
|
|
b->num_siblings = 0;
|
|
pb = b->parent;
|
|
if (pb != NULL) {
|
|
for (i = 0; i < NUM_OFFSPRING; i++) {
|
|
sb = pb->children[i];
|
|
if ((sb != NULL) && (sb != b))
|
|
b->siblings[b->num_siblings++] = sb;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
SetColleagues (long my_id, box *b)
|
|
{
|
|
box *pb, *cb, *cousin;
|
|
long i, j;
|
|
|
|
b->num_colleagues = 0;
|
|
pb = b->parent;
|
|
if (pb != NULL) {
|
|
for (i = 0; i < b->num_siblings; i++)
|
|
b->colleagues[b->num_colleagues++] = b->siblings[i];
|
|
while (b->construct_synch == 0) {
|
|
/* wait */;
|
|
}
|
|
b->construct_synch = 0;
|
|
for (i = 0; i < pb->num_colleagues; i++) {
|
|
cb = pb->colleagues[i];
|
|
for (j = 0; j < NUM_OFFSPRING; j++) {
|
|
cousin = cb->children[j];
|
|
if (cousin != NULL) {
|
|
if (AdjacentBoxes(b, cousin) == TRUE)
|
|
b->colleagues[b->num_colleagues++] = cousin;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (b->type == PARENT) {
|
|
for (i = 0; i < NUM_OFFSPRING; i++) {
|
|
if (b->children[i] != NULL) {
|
|
b->children[i]->construct_synch = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ConstructInteractionLists (long my_id, box *b)
|
|
*
|
|
* Args : a box, b.
|
|
*
|
|
* Returns : nothing.
|
|
*
|
|
* Side Effects : Creates b's colleagues, u_list,
|
|
* v_list, and w_list.
|
|
*
|
|
*/
|
|
void
|
|
ConstructInteractionLists (long my_id, box *b)
|
|
{
|
|
|
|
SetVList(my_id, b);
|
|
if (b->type == CHILDLESS) {
|
|
SetUList(my_id, b);
|
|
SetWList(my_id, b);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void
|
|
SetVList (long my_id, box *b)
|
|
{
|
|
box *pb, *cb, *cousin;
|
|
long i, j;
|
|
|
|
b->num_v_list = 0;
|
|
pb = b->parent;
|
|
if (pb != NULL) {
|
|
for (i = 0; i < pb->num_colleagues; i++) {
|
|
cb = pb->colleagues[i];
|
|
for (j = 0; j < NUM_OFFSPRING; j++) {
|
|
cousin = cb->children[j];
|
|
if (cousin != NULL) {
|
|
if (WellSeparatedBoxes(b, cousin) == TRUE)
|
|
b->v_list[b->num_v_list++] = cousin;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* SetUList (long my_id, box *b)
|
|
*
|
|
* Args : a box, b.
|
|
*
|
|
* Returns : nothing.
|
|
*
|
|
* Side Effects : Sets b's adjacency interaction list.
|
|
*
|
|
* Comments : The helper function is used to enable recursion.
|
|
*
|
|
*/
|
|
void
|
|
SetUList (long my_id, box *b)
|
|
{
|
|
b->num_u_list = 0;
|
|
SetUListHelper(my_id, b, Grid);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* SetUListHelper (long my_id, box *b, box *pb)
|
|
*
|
|
* Args : a box, b, and a parent box, pb.
|
|
*
|
|
* Returns : nothing.
|
|
*
|
|
* Side Effects : Sets b's adjacency interaction list.
|
|
*
|
|
* Comments :
|
|
*
|
|
*/
|
|
void
|
|
SetUListHelper (long my_id, box *b, box *pb)
|
|
{
|
|
box *child;
|
|
long i;
|
|
|
|
for (i = 0; i < NUM_OFFSPRING; i++) {
|
|
child = pb->children[i];
|
|
if (child != NULL) {
|
|
if (AdjacentBoxes(b, child) == TRUE) {
|
|
if (child->type == CHILDLESS)
|
|
b->u_list[b->num_u_list++] = child;
|
|
else
|
|
SetUListHelper(my_id, b, child);
|
|
}
|
|
else {
|
|
if (AncestorBox(b, child) == TRUE)
|
|
SetUListHelper(my_id, b, child);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* AncestorBox (box *b, box *ancestor_box)
|
|
*
|
|
* Args : a box, b, and its possible ancestor box, ancestor_box.
|
|
*
|
|
* Returns : TRUE, if ancestor_box is an ancestor of b, FALSE if not.
|
|
*
|
|
* Side Effects : none.
|
|
*
|
|
* Comments : A box is NOT the ancestor of himself. So, AncestorBox(b,b)
|
|
* always returns FALSE. So, ancestor_box is indeed the ancestor of b
|
|
* if their sizes are not equal and if b's center lies within the boundaries
|
|
* of ancestor_box.
|
|
*
|
|
*/
|
|
long
|
|
AncestorBox (box *b, box *ancestor_box)
|
|
{
|
|
real x_center_distance;
|
|
real y_center_distance;
|
|
long ret_val = TRUE;
|
|
|
|
if (b->length != ancestor_box->length) {
|
|
|
|
x_center_distance = fabs((double)(b->x_center - ancestor_box->x_center));
|
|
y_center_distance = fabs((double)(b->y_center - ancestor_box->y_center));
|
|
if ((x_center_distance > (ancestor_box->length / 2.0)) ||
|
|
(y_center_distance > (ancestor_box->length / 2.0)))
|
|
ret_val = FALSE;
|
|
}
|
|
else
|
|
ret_val = FALSE;
|
|
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* SetWList (long my_id, box *b)
|
|
*
|
|
* Args : a box, b.
|
|
*
|
|
* Returns : nothing.
|
|
*
|
|
* Side Effects : Sets b's w_list.
|
|
*
|
|
* Comments : This list contains all descedants of b's colleagues whose
|
|
* parents are adjacent to b, but who are not adjacent to b themeselves.
|
|
* This list should only be computed for childless boxes.
|
|
*
|
|
*/
|
|
void
|
|
SetWList (long my_id, box *b)
|
|
{
|
|
box *co_search;
|
|
long i;
|
|
|
|
b->num_w_list = 0;
|
|
for (i = 0; i < b->num_colleagues; i++) {
|
|
co_search = b->colleagues[i];
|
|
if (co_search->type == PARENT)
|
|
InsertNonAdjChildren(my_id, b, co_search);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* InsertNonAdjChildren (long my_id, box *b, box *pb)
|
|
*
|
|
* Args : a parent box, pb, and the box with the weak iteraction list, b.
|
|
*
|
|
* Returns : nothing.
|
|
*
|
|
* Side Effects : Inserts all non-adjacent children of adjacent box pb into
|
|
* b's weak interaction list.
|
|
*
|
|
* Comments : This function recursively calls itself on every child that is
|
|
* also adjacent to b and a parent.
|
|
*
|
|
*/
|
|
void
|
|
InsertNonAdjChildren (long my_id, box *b, box *pb)
|
|
{
|
|
long i;
|
|
box *child;
|
|
|
|
for (i = 0; i < pb->num_children; i++) {
|
|
child = pb->children[i];
|
|
if (child != NULL) {
|
|
if (AdjacentBoxes(b, child) == TRUE) {
|
|
if (child->type == PARENT)
|
|
InsertNonAdjChildren(my_id, b, child);
|
|
}
|
|
else
|
|
b->w_list[b->num_w_list++] = child;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|