blob: 0507d791daeeb4f6fed54a396915af742443a904 [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. */
/* */
/*************************************************************************/
/*
* GRAV.C:
*/
EXTERN_ENV
#define global extern
#include "code.h"
/*
* HACKGRAV: evaluate grav field at a given particle.
*/
hackgrav(p,ProcessId)
bodyptr p;
unsigned ProcessId;
{
extern gravsub();
Local[ProcessId].pskip = p;
SETV(Local[ProcessId].pos0, Pos(p));
Local[ProcessId].phi0 = 0.0;
CLRV(Local[ProcessId].acc0);
Local[ProcessId].myn2bterm = 0;
Local[ProcessId].mynbcterm = 0;
Local[ProcessId].skipself = FALSE;
hackwalk(gravsub, ProcessId);
Phi(p) = Local[ProcessId].phi0;
SETV(Acc(p), Local[ProcessId].acc0);
#ifdef QUADPOLE
Cost(p) = Local[ProcessId].myn2bterm + NDIM * Local[ProcessId].mynbcterm;
#else
Cost(p) = Local[ProcessId].myn2bterm + Local[ProcessId].mynbcterm;
#endif
}
/*
* GRAVSUB: compute a single body-body or body-cell interaction.
*/
gravsub(p, ProcessId, level)
register nodeptr p; /* body or cell to interact with */
unsigned ProcessId;
int level;
{
double sqrt();
real drabs, phii, mor3;
vector ai, quaddr;
real dr5inv, phiquad, drquaddr;
if (p != Local[ProcessId].pmem) {
SUBV(Local[ProcessId].dr, Pos(p), Local[ProcessId].pos0);
DOTVP(Local[ProcessId].drsq, Local[ProcessId].dr, Local[ProcessId].dr);
}
Local[ProcessId].drsq += epssq;
drabs = sqrt((double) Local[ProcessId].drsq);
phii = Mass(p) / drabs;
Local[ProcessId].phi0 -= phii;
mor3 = phii / Local[ProcessId].drsq;
MULVS(ai, Local[ProcessId].dr, mor3);
ADDV(Local[ProcessId].acc0, Local[ProcessId].acc0, ai);
if(Type(p) != BODY) { /* a body-cell/leaf interaction? */
Local[ProcessId].mynbcterm++;
#ifdef QUADPOLE
dr5inv = 1.0/(Local[ProcessId].drsq * Local[ProcessId].drsq * drabs);
MULMV(quaddr, Quad(p), Local[ProcessId].dr);
DOTVP(drquaddr, Local[ProcessId].dr, quaddr);
phiquad = -0.5 * dr5inv * drquaddr;
Local[ProcessId].phi0 += phiquad;
phiquad = 5.0 * phiquad / Local[ProcessId].drsq;
MULVS(ai, Local[ProcessId].dr, phiquad);
SUBV(Local[ProcessId].acc0, Local[ProcessId].acc0, ai);
MULVS(quaddr, quaddr, dr5inv);
SUBV(Local[ProcessId].acc0, Local[ProcessId].acc0, quaddr);
#endif
}
else { /* a body-body interaction */
Local[ProcessId].myn2bterm++;
}
}
/*
* HACKWALK: walk the tree opening cells too close to a given point.
*/
local proced hacksub;
hackwalk(sub, ProcessId)
proced sub; /* routine to do calculation */
unsigned ProcessId;
{
walksub(Global->G_root, Global->rsize * Global->rsize, ProcessId);
}
/*
* WALKSUB: recursive routine to do hackwalk operation.
*/
walksub(n, dsq, ProcessId)
nodeptr n; /* pointer into body-tree */
real dsq; /* size of box squared */
unsigned ProcessId;
{
bool subdivp();
nodeptr* nn;
leafptr l;
bodyptr p;
int i;
if (subdivp(n, dsq, ProcessId)) {
if (Type(n) == CELL) {
for (nn = Subp(n); nn < Subp(n) + NSUB; nn++) {
if (*nn != NULL) {
walksub(*nn, dsq / 4.0, ProcessId);
}
}
}
else {
l = (leafptr) n;
for (i = 0; i < l->num_bodies; i++) {
p = Bodyp(l)[i];
if (p != Local[ProcessId].pskip) {
gravsub(p, ProcessId);
}
else {
Local[ProcessId].skipself = TRUE;
}
}
}
}
else {
gravsub(n, ProcessId);
}
}
/*
* SUBDIVP: decide if a node should be opened.
* Side effects: sets pmem,dr, and drsq.
*/
bool subdivp(p, dsq, ProcessId)
register nodeptr p; /* body/cell to be tested */
real dsq; /* size of cell squared */
unsigned ProcessId;
{
SUBV(Local[ProcessId].dr, Pos(p), Local[ProcessId].pos0);
DOTVP(Local[ProcessId].drsq, Local[ProcessId].dr, Local[ProcessId].dr);
Local[ProcessId].pmem = p;
return (tolsq * Local[ProcessId].drsq < dsq);
}