blob: 7ada1f5dd121d39eaf170e692eb69de26c51d89b [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. */
/* */
/*************************************************************************/
EXTERN_ENV
#define global extern
#include "code.h"
#include "defs.h"
bool intcoord();
cellptr makecell(unsigned int ProcessId);
leafptr makeleaf(unsigned int ProcessId);
cellptr SubdivideLeaf(leafptr le, cellptr parent, unsigned int l,
unsigned int ProcessId);
cellptr InitCell(cellptr parent, unsigned int ProcessId);
leafptr InitLeaf(cellptr parent, unsigned int ProcessId);
nodeptr loadtree(bodyptr p, cellptr root, unsigned int ProcessId);
/*
* MAKETREE: initialize tree structure for hack force calculation.
*/
maketree(ProcessId)
unsigned ProcessId;
{
bodyptr p, *pp;
Local[ProcessId].myncell = 0;
Local[ProcessId].mynleaf = 0;
if (ProcessId == 0) {
Local[ProcessId].mycelltab[Local[ProcessId].myncell++] = Global->G_root;
}
Local[ProcessId].Current_Root = (nodeptr) Global->G_root;
for (pp = Local[ProcessId].mybodytab;
pp < Local[ProcessId].mybodytab+Local[ProcessId].mynbody; pp++) {
p = *pp;
if (Mass(p) != 0.0) {
Local[ProcessId].Current_Root
= (nodeptr) loadtree(p, (cellptr) Local[ProcessId].Current_Root,
ProcessId);
}
else {
LOCK(Global->io_lock);
fprintf(stderr, "Process %d found body %d to have zero mass\n",
ProcessId, (int) p);
UNLOCK(Global->io_lock);
}
}
BARRIER(Global->Bartree,NPROC);
hackcofm( 0, ProcessId );
BARRIER(Global->Barcom,NPROC);
}
cellptr InitCell(parent, ProcessId)
cellptr parent;
unsigned ProcessId;
{
cellptr c;
int i, Mycell;
c = makecell(ProcessId);
c->processor = ProcessId;
c->next = NULL;
c->prev = NULL;
if (parent == NULL)
Level(c) = IMAX >> 1;
else
Level(c) = Level(parent) >> 1;
Parent(c) = (nodeptr) parent;
ChildNum(c) = 0;
return (c);
}
leafptr InitLeaf(parent, ProcessId)
cellptr parent;
unsigned ProcessId;
{
leafptr l;
int i, Mycell;
l = makeleaf(ProcessId);
l->processor = ProcessId;
l->next = NULL;
l->prev = NULL;
if (parent==NULL)
Level(l) = IMAX >> 1;
else
Level(l) = Level(parent) >> 1;
Parent(l) = (nodeptr) parent;
ChildNum(l) = 0;
return (l);
}
printtree (n)
nodeptr n;
{
int k;
cellptr c;
leafptr l;
bodyptr p;
nodeptr tmp;
unsigned long nseq;
int xp[NDIM];
switch (Type(n)) {
case CELL:
c = (cellptr) n;
nseq = c->seqnum;
printf("Cell : Cost = %d, ", Cost(c));
PRTV("Pos", Pos(n));
printf("\n");
for (k = 0; k < NSUB; k++) {
printf("Child #%d: ", k);
if (Subp(c)[k] == NULL) {
printf("NONE");
}
else {
if (Type(Subp(c)[k]) == CELL) {
nseq = ((cellptr) Subp(c)[k])->seqnum;
printf("C: Cost = %d, ", Cost(Subp(c)[k]));
}
else {
nseq = ((leafptr) Subp(c)[k])->seqnum;
printf("L: # Bodies = %2d, Cost = %d, ",
((leafptr) Subp(c)[k])->num_bodies, Cost(Subp(c)[k]));
}
tmp = Subp(c)[k];
PRTV("Pos", Pos(tmp));
}
printf("\n");
}
for (k=0;k<NSUB;k++) {
if (Subp(c)[k] != NULL) {
printtree(Subp(c)[k]);
}
}
break;
case LEAF:
l = (leafptr) n;
nseq = l->seqnum;
printf("Leaf : # Bodies = %2d, Cost = %d, ", l->num_bodies, Cost(l));
PRTV("Pos", Pos(n));
printf("\n");
for (k = 0; k < l->num_bodies; k++) {
p = Bodyp(l)[k];
printf("Body #%2d: Num = %2d, Level = %o, ",
p - bodytab, k, Level(p));
PRTV("Pos",Pos(p));
printf("\n");
}
break;
default:
fprintf(stderr, "Bad type\n");
exit(-1);
break;
}
fflush(stdout);
}
/*
* LOADTREE: descend tree and insert particle.
*/
nodeptr
loadtree(p, root, ProcessId)
bodyptr p; /* body to load into tree */
cellptr root;
unsigned ProcessId;
{
int l, xq[NDIM], xp[NDIM], xor[NDIM], subindex(), flag;
int i, j, root_level;
bool valid_root;
int kidIndex;
volatile nodeptr *volatile qptr, mynode;
cellptr c;
leafptr le;
intcoord(xp, Pos(p));
valid_root = TRUE;
for (i = 0; i < NDIM; i++) {
xor[i] = xp[i] ^ Local[ProcessId].Root_Coords[i];
}
for (i = IMAX >> 1; i > Level(root); i >>= 1) {
for (j = 0; j < NDIM; j++) {
if (xor[j] & i) {
valid_root = FALSE;
break;
}
}
if (!valid_root) {
break;
}
}
if (!valid_root) {
if (root != Global->G_root) {
root_level = Level(root);
for (j = i; j > root_level; j >>= 1) {
root = (cellptr) Parent(root);
}
valid_root = TRUE;
for (i = IMAX >> 1; i > Level(root); i >>= 1) {
for (j = 0; j < NDIM; j++) {
if (xor[j] & i) {
valid_root = FALSE;
break;
}
}
if (!valid_root) {
printf("P%d body %d\n", ProcessId, p - bodytab);
root = Global->G_root;
}
}
}
}
root = Global->G_root;
mynode = (nodeptr) root;
kidIndex = subindex(xp, Level(mynode));
qptr = &Subp(mynode)[kidIndex];
l = Level(mynode) >> 1;
flag = TRUE;
while (flag) { /* loop descending tree */
if (l == 0) {
error("not enough levels in tree\n");
}
if (*qptr == NULL) {
/* lock the parent cell */
ALOCK(CellLock->CL, ((cellptr) mynode)->seqnum % MAXLOCK);
if (*qptr == NULL) {
le = InitLeaf((cellptr) mynode, ProcessId);
Parent(p) = (nodeptr) le;
Level(p) = l;
ChildNum(p) = le->num_bodies;
ChildNum(le) = kidIndex;
Bodyp(le)[le->num_bodies++] = p;
*qptr = (nodeptr) le;
flag = FALSE;
}
AULOCK(CellLock->CL, ((cellptr) mynode)->seqnum % MAXLOCK);
/* unlock the parent cell */
}
if (flag && *qptr && (Type(*qptr) == LEAF)) {
/* reached a "leaf"? */
ALOCK(CellLock->CL, ((cellptr) mynode)->seqnum % MAXLOCK);
/* lock the parent cell */
if (Type(*qptr) == LEAF) { /* still a "leaf"? */
le = (leafptr) *qptr;
if (le->num_bodies == MAX_BODIES_PER_LEAF) {
*qptr = (nodeptr) SubdivideLeaf(le, (cellptr) mynode, l,
ProcessId);
}
else {
Parent(p) = (nodeptr) le;
Level(p) = l;
ChildNum(p) = le->num_bodies;
Bodyp(le)[le->num_bodies++] = p;
flag = FALSE;
}
}
AULOCK(CellLock->CL, ((cellptr) mynode)->seqnum % MAXLOCK);
/* unlock the node */
}
if (flag) {
mynode = *qptr;
kidIndex = subindex(xp, l);
qptr = &Subp(*qptr)[kidIndex]; /* move down one level */
l = l >> 1; /* and test next bit */
}
}
SETV(Local[ProcessId].Root_Coords, xp);
return Parent((leafptr) *qptr);
}
/* * INTCOORD: compute integerized coordinates. * Returns: TRUE
unless rp was out of bounds. */
bool intcoord(xp, rp)
int xp[NDIM]; /* integerized coordinate vector [0,IMAX) */
vector rp; /* real coordinate vector (system coords) */
{
int k;
bool inb;
double xsc, floor();
inb = TRUE;
for (k = 0; k < NDIM; k++) {
xsc = (rp[k] - Global->rmin[k]) / Global->rsize;
if (0.0 <= xsc && xsc < 1.0) {
xp[k] = floor(IMAX * xsc);
}
else {
inb = FALSE;
}
}
return (inb);
}
/*
* SUBINDEX: determine which subcell to select.
*/
int subindex(x, l)
int x[NDIM]; /* integerized coordinates of particle */
int l; /* current level of tree */
{
int i, k;
int yes;
i = 0;
yes = FALSE;
if (x[0] & l) {
i += NSUB >> 1;
yes = TRUE;
}
for (k = 1; k < NDIM; k++) {
if (((x[k] & l) && !yes) || (!(x[k] & l) && yes)) {
i += NSUB >> (k + 1);
yes = TRUE;
}
else yes = FALSE;
}
return (i);
}
/*
* HACKCOFM: descend tree finding center-of-mass coordinates.
*/
hackcofm(nc, ProcessId)
int nc;
unsigned ProcessId;
{
int i,Myindex;
nodeptr r;
leafptr l;
leafptr* ll;
bodyptr p;
cellptr q;
cellptr *cc;
vector tmpv, dr;
real drsq;
matrix drdr, Idrsq, tmpm;
/* get a cell using get*sub. Cells are got in reverse of the order in */
/* the cell array; i.e. reverse of the order in which they were created */
/* this way, we look at child cells before parents */
for (ll = Local[ProcessId].myleaftab + Local[ProcessId].mynleaf - 1;
ll >= Local[ProcessId].myleaftab; ll--) {
l = *ll;
Mass(l) = 0.0;
Cost(l) = 0;
CLRV(Pos(l));
for (i = 0; i < l->num_bodies; i++) {
p = Bodyp(l)[i];
Mass(l) += Mass(p);
Cost(l) += Cost(p);
MULVS(tmpv, Pos(p), Mass(p));
ADDV(Pos(l), Pos(l), tmpv);
}
DIVVS(Pos(l), Pos(l), Mass(l));
#ifdef QUADPOLE
CLRM(Quad(l));
for (i = 0; i < l->num_bodies; i++) {
p = Bodyp(l)[i];
SUBV(dr, Pos(p), Pos(l));
OUTVP(drdr, dr, dr);
DOTVP(drsq, dr, dr);
SETMI(Idrsq);
MULMS(Idrsq, Idrsq, drsq);
MULMS(tmpm, drdr, 3.0);
SUBM(tmpm, tmpm, Idrsq);
MULMS(tmpm, tmpm, Mass(p));
ADDM(Quad(l), Quad(l), tmpm);
}
#endif
Done(l)=TRUE;
}
for (cc = Local[ProcessId].mycelltab+Local[ProcessId].myncell-1;
cc >= Local[ProcessId].mycelltab; cc--) {
q = *cc;
Mass(q) = 0.0;
Cost(q) = 0;
CLRV(Pos(q));
for (i = 0; i < NSUB; i++) {
r = Subp(q)[i];
if (r != NULL) {
while(!Done(r)) {
/* wait */
}
Mass(q) += Mass(r);
Cost(q) += Cost(r);
MULVS(tmpv, Pos(r), Mass(r));
ADDV(Pos(q), Pos(q), tmpv);
Done(r) = FALSE;
}
}
DIVVS(Pos(q), Pos(q), Mass(q));
#ifdef QUADPOLE
CLRM(Quad(q));
for (i = 0; i < NSUB; i++) {
r = Subp(q)[i];
if (r != NULL) {
SUBV(dr, Pos(r), Pos(q));
OUTVP(drdr, dr, dr);
DOTVP(drsq, dr, dr);
SETMI(Idrsq);
MULMS(Idrsq, Idrsq, drsq);
MULMS(tmpm, drdr, 3.0);
SUBM(tmpm, tmpm, Idrsq);
MULMS(tmpm, tmpm, Mass(r));
ADDM(tmpm, tmpm, Quad(r));
ADDM(Quad(q), Quad(q), tmpm);
}
}
#endif
Done(q)=TRUE;
}
}
cellptr
SubdivideLeaf (le, parent, l, ProcessId)
leafptr le;
cellptr parent;
unsigned int l;
unsigned int ProcessId;
{
cellptr c;
int i, index;
int xp[NDIM];
bodyptr bodies[MAX_BODIES_PER_LEAF];
int num_bodies;
bodyptr p;
/* first copy leaf's bodies to temp array, so we can reuse the leaf */
num_bodies = le->num_bodies;
for (i = 0; i < num_bodies; i++) {
bodies[i] = Bodyp(le)[i];
Bodyp(le)[i] = NULL;
}
le->num_bodies = 0;
/* create the parent cell for this subtree */
c = InitCell(parent, ProcessId);
ChildNum(c) = ChildNum(le);
/* do first particle separately, so we can reuse le */
p = bodies[0];
intcoord(xp, Pos(p));
index = subindex(xp, l);
Subp(c)[index] = (nodeptr) le;
ChildNum(le) = index;
Parent(le) = (nodeptr) c;
Level(le) = l >> 1;
/* set stuff for body */
Parent(p) = (nodeptr) le;
ChildNum(p) = le->num_bodies;
Level(p) = l >> 1;
/* insert the body */
Bodyp(le)[le->num_bodies++] = p;
/* now handle the rest */
for (i = 1; i < num_bodies; i++) {
p = bodies[i];
intcoord(xp, Pos(p));
index = subindex(xp, l);
if (!Subp(c)[index]) {
le = InitLeaf(c, ProcessId);
ChildNum(le) = index;
Subp(c)[index] = (nodeptr) le;
}
else {
le = (leafptr) Subp(c)[index];
}
Parent(p) = (nodeptr) le;
ChildNum(p) = le->num_bodies;
Level(p) = l >> 1;
Bodyp(le)[le->num_bodies++] = p;
}
return c;
}
/*
* MAKECELL: allocation routine for cells.
*/
cellptr makecell(ProcessId)
unsigned ProcessId;
{
cellptr c;
int i, Mycell;
if (Local[ProcessId].mynumcell == maxmycell) {
error("makecell: Proc %d needs more than %d cells; increase fcells\n",
ProcessId,maxmycell);
}
Mycell = Local[ProcessId].mynumcell++;
c = Local[ProcessId].ctab + Mycell;
c->seqnum = ProcessId*maxmycell+Mycell;
Type(c) = CELL;
Done(c) = FALSE;
Mass(c) = 0.0;
for (i = 0; i < NSUB; i++) {
Subp(c)[i] = NULL;
}
Local[ProcessId].mycelltab[Local[ProcessId].myncell++] = c;
return (c);
}
/*
* MAKELEAF: allocation routine for leaves.
*/
leafptr makeleaf(ProcessId)
unsigned ProcessId;
{
leafptr le;
int i, Myleaf;
if (Local[ProcessId].mynumleaf == maxmyleaf) {
error("makeleaf: Proc %d needs more than %d leaves; increase fleaves\n",
ProcessId,maxmyleaf);
}
Myleaf = Local[ProcessId].mynumleaf++;
le = Local[ProcessId].ltab + Myleaf;
le->seqnum = ProcessId * maxmyleaf + Myleaf;
Type(le) = LEAF;
Done(le) = FALSE;
Mass(le) = 0.0;
le->num_bodies = 0;
for (i = 0; i < MAX_BODIES_PER_LEAF; i++) {
Bodyp(le)[i] = NULL;
}
Local[ProcessId].myleaftab[Local[ProcessId].mynleaf++] = le;
return (le);
}