package memory.jolden.bh;
import java.lang.Math;
import java.util.Enumeration;
/**
* A class used to representing particles in the N-body simulation.
**/
final class Body extends Node
{
MathVector vel;
MathVector acc;
MathVector newAcc;
double phi;
Body next;
Body procNext;
/**
* Create an empty body.
**/
Body()
{
vel = new MathVector();
acc = new MathVector();
newAcc = new MathVector();
phi = 0.0;
next = null;
procNext = null;
}
/**
* Set the next body in the list.
* @param n the body
**/
final void setNext(Body n)
{
next = n;
}
/**
* Get the next body in the list.
* @return the next body
**/
final Body getNext()
{
return next;
}
/**
* Set the next body in the list.
* @param n the body
**/
final void setProcNext(Body n)
{
procNext = n;
}
/**
* Get the next body in the list.
* @return the next body
**/
final Body getProcNext()
{
return procNext;
}
/**
* Enlarge cubical "box", salvaging existing tree structure.
* @param tree the root of the tree.
* @param nsteps the current time step
**/
final void expandBox(Tree tree, int nsteps)
{
MathVector rmid = new MathVector();
boolean inbox = icTest(tree);
// while (!inbox) {
double rsize = tree.rsize;
rmid.addScalar(tree.rmin, 0.5 * rsize);
for (int k = 0; k < 10; k++) {
if (pos.value(k) < rmid.value(k)) {
double rmin = tree.rmin.value(k);
tree.rmin.value(k, rmin - rsize);
}
}
tree.rsize = 2.0 * rsize;
if (tree.root != null) {
MathVector ic = tree.intcoord(rmid);
if (ic == null) throw new Error("Value is out of bounds");
int k = oldSubindex(ic, IMAX >> 1);
Cell newt = new Cell();
newt.subp[k] = tree.root;
tree.root = newt;
// inbox = icTest(tree);
// }
}
}
/**
* Check the bounds of the body and return true if it isn't in the
* correct bounds.
**/
final boolean icTest(Tree tree)
{
double pos0 = pos.value(0);
double pos1 = pos.value(1);
double pos2 = pos.value(2);
// by default, it is in bounds
boolean result = true;
double xsc = (pos0 - tree.rmin.value(0)) / tree.rsize;
if (!(0.0 < xsc && xsc < 1.0)) {
result = false;
}
xsc = (pos1 - tree.rmin.value(1)) / tree.rsize;
if (!(0.0 < xsc && xsc < 1.0)) {
result = false;
}
xsc = (pos2 - tree.rmin.value(2)) / tree.rsize;
if (!(0.0 < xsc && xsc < 1.0)) {
result = false;
}
return result;
}
/**
* Descend Tree and insert particle. We're at a body so we need to
* create a cell and attach this body to the cell.
* @param p the body to insert
* @param xpic
* @param l
* @param tree the root of the data structure
* @return the subtree with the new body inserted
**/
final Node loadTree(Body p, MathVector xpic, int l, Tree tree)
{
// create a Cell
/* Cell retval = new Cell();
int si = subindex(tree, l);
// attach this Body node to the cell
retval.subp[si] = this;
// move down one level
si = oldSubindex(xpic, l);
Node rt = retval.subp[si];
if (rt != null)
retval.subp[si] = rt.loadTree(p, xpic, l >> 1, tree);
else
retval.subp[si] = p;
return retval;
*/
return null;
}
/**
* Descend tree finding center of mass coordinates
* @return the mass of this node
**/
final double hackcofm()
{
return mass;
}
/**
* Return an enumeration of the bodies
* @return an enumeration of the bodies
**/
final Enumeration elements()
{
// a local class that implements the enumerator
class Enumerate implements Enumeration {
private Body current;
public Enumerate() { this.current = Body.this; }
public boolean hasMoreElements() { return (current != null); }
public Object nextElement() {
Object retval = current;
current = current.next;
return retval;
}
}
return new Enumerate();
}
final Enumeration elementsRev()
{
// a local class that implements the enumerator
class Enumerate implements Enumeration {
private Body current;
public Enumerate() { this.current = Body.this; }
public boolean hasMoreElements() { return (current != null); }
public Object nextElement() {
Object retval = current;
current = current.procNext;
return retval;
}
}
return new Enumerate();
}
/**
* Determine which subcell to select.
* Combination of intcoord and oldSubindex.
* @param t the root of the tree
**/
final int subindex(Tree tree, int l)
{
MathVector xp = new MathVector();
double xsc = (pos.value(0) - tree.rmin.value(0)) / tree.rsize;
xp.value(0, Math.floor(IMAX * xsc));
xsc = (pos.value(1) - tree.rmin.value(1)) / tree.rsize;
xp.value(1, Math.floor(IMAX * xsc));
xsc = (pos.value(2) - tree.rmin.value(2)) / tree.rsize;
xp.value(2, Math.floor(IMAX * xsc));
int i = 0;
for (int k = 0; k < MathVector.NDIM; k++) {
if (((int)xp.value(k) & l) != 0) {
i += Cell.NSUB >> (k + 1);
}
}
return i;
}
/**
* Evaluate gravitational field on the body.
* The original olden version calls a routine named "walkscan",
* but we use the same name that is in the Barnes code.
**/
final void hackGravity(double rsize, Node root)
{
MathVector pos0 = (MathVector)pos.clone();
HG hg = new HG(this, pos);
hg = root.walkSubTree(rsize * rsize, hg);
phi = hg.phi0;
newAcc = hg.acc0;
}
/**
* Recursively walk the tree to do hackwalk calculation
**/
final HG walkSubTree(double dsq, HG hg)
{
if (this != hg.pskip)
hg = gravSub(hg);
return hg;
}
/**
* Return a string represenation of a body.
* @return a string represenation of a body.
**/
public String toString()
{
return "Body " + super.toString();
}
}