import DPJRuntime.Framework.*;
import DPJRuntime.Framework.DisjointTree.*;
import DPJRuntime.Framework.TreeOps.*;
import DPJRuntime.Framework.ArrayOps.*;
import java.util.concurrent.atomic.*;
import java.util.Vector;
import java.util.ArrayList;
/**
* @author vadve
*
* <p>Simplified 2D version of the center-of-mass computation from the
* Barnes-Hut n-body algorithm.</p>
**/
public class BarnesHutCofMTree {
final static int NBODIES = 3;
final static int LEFT = 0, RIGHT = 1;
final static double HORIZON = 7.0; // right end of space; left end is 0.0
final static boolean DEBUG = true;
public static class Body<region R> {
public double[]<R> pic in R;
public double mass in R;
public double cofm in R;
public double phi in R;
// Constructor for 2-dimensional space tree (binary tree)
public Body(int x, double mass, double phi) {
pic = new double[1]<R>;
pic[0] = (double) x;
this.mass = mass;
this.phi = phi;
}
public void print() reads R {
System.out.println(": Mass = " + this.mass +
";\tPosition = " + this.pic[0] +
";\tCofM = " + this.cofm);
}
}
public static class Cell<region R>
extends Body<R> // Superclass represents the CofM
{
public double left in R; // Left end of bounding box
public double right in R; // Right end of bounding box
public Cell(double left, double right) {
super(0, 0.0, 0.0); // CofM params are set later
this.left = left;
this.right = right;
}
public double midpoint() reads R {
return (left + right) / 2;
}
public void print() reads R {
System.out.println(": left = " + this.left +
";\tright = " + this.right +
";\tCofM = " + this.cofm);
}
}
public static class Expander<region R>
implements NodeExpander<Body<R>, reads R> {
public int slotToExpand(/* final int level, */
final Body<R> curValue,
final Body<R> parentValue,
final Body<R> valueToInsert)
reads R {
assert(valueToInsert != null); // else nothing to insert!
assert(valueToInsert.pic != null); // else no data there!
assert(curValue != null); // else no node to insert at!
if (DEBUG) {
System.out.print("slotToExpand: curValue = ");
curValue.print();
System.out.print("slotToExpand: valueToInsert = ");
valueToInsert.print();
}
int returnValue;
if (curValue instanceof Cell) {
Cell<R> curCell = (Cell<R>) curValue;
returnValue = (curCell.midpoint() > valueToInsert.pic[0])? LEFT : RIGHT;
}
else {
assert(false);
assert(curValue instanceof Body);
returnValue = LEFT;
}
if (DEBUG) {
System.out.println("slotToExpand: returning slot = " + returnValue);
}
return returnValue;
}
public <region NR> Body<NR>
nodeFactory(/* final int level, */
final Body<R> curValue,
final Body<R> parentValue,
final int indexOfCurNodeInParent,
final Body<R> valueToInsert)
reads R {
if (DEBUG) {
System.out.print("\n*** nodeFactory: curValue = ");
curValue.print();
System.out.print( " nodeFactory: parentValue = ");
if (parentValue != null) {
parentValue.print(); System.out.println("");
}
else
System.out.println("---NULL---\n");
}
if (parentValue == null || ! (parentValue instanceof Cell))
return new Cell<NR>(0.0, HORIZON);
assert (parentValue instanceof Cell); // other case handled earlier
assert(indexOfCurNodeInParent <= 1); // binary tree!
Cell<R> parentCell = (Cell<R>) parentValue;
// newCell gets left half if left child; right half otherwise
Cell<NR> newCell = (indexOfCurNodeInParent == LEFT)?
new Cell<NR>(parentCell.left, parentCell.midpoint()) :
new Cell<NR>(parentCell.midpoint(), parentCell.right);
return newCell;
}
}
public static final class BodyGenerator<region R>
implements DisjointIntAndObjectToObject<Body<R>, Body<R>, pure> {
// range of body masses is 0..MAXMASS
final double MAXMASS = 1000.0; // arbitrary units
// Random number generator for values in the range [0.0..1.0].
// The mass is random*MAXMASS.
final java.util.Random rstream =
new java.util.Random(0); // don't care seed
// Operation to generate each new body.
public <region R>Body<R> op(int i, final Body<R> /*unused*/obj) pure {
assert(obj == null); // should only construct the array once
double mass = MAXMASS * rstream.nextDouble();
return new Body<R>(2*i, mass, 0.0);
}
}
public static class CofMVisitor<region BHTree>
implements SubtreeVisitorPostOrder<Body<BHTree>,
Vector<Double>, reads BHTree>
{
public <region TR2, region VR2> Vector<Double>
visit(final Body<TR2> curBody,
final ArrayList<Vector<Double>> childValues)
reads BHTree writes TR2 {
Vector<Double> result = new Vector<Double>(2);
if (childValues == null || childValues.size() == 0) { // leaf node
curBody.cofm = curBody.pic[0];
result.add(curBody.mass);
result.add(curBody.pic[0]);
return result;
}
// Binary tree! Do first child.
final Vector<Double> masspos0 = childValues.get(0);
double totCofm = curBody.mass * curBody.pic[0] +
masspos0.get(0) * masspos0.get(1);
double totMass = curBody.mass * masspos0.get(0);
// Do second child, if any.
assert(childValues.size() <= 2); // binary tree!
if (childValues.size() == 2) {
final Vector<Double> masspos1 = childValues.get(1);
totCofm += masspos1.get(0) * masspos1.get(1);
totMass += masspos1.get(0);
}
curBody.cofm = totCofm / totMass;
assert(result.size() == 0);
result.add(totMass);
result.add(totCofm);
if (DEBUG) {
curBody.print();
}
return result;
}
}
public static void main(String[] args) {
region BodyRegion, TreeRegion;
// First, build a linear array of bodies.
DisjointArray.Creator creator = new DisjointArray.Creator();
DisjointArray<Body<BodyRegion>, TreeRegion> bodies =
creator.create(NBODIES, Body.class);
bodies = bodies.<Body<BodyRegion>, pure>
withIndexedMapping(new BodyGenerator<BodyRegion>());
// Now insert them into a new tree
DisjointTree<Body<BodyRegion>, TreeRegion> bhTree =
new DisjointTree<Body<BodyRegion>, TreeRegion>();
bhTree.<reads BodyRegion>buildTree(bodies, /*arity=*/2,
new Expander<BodyRegion>());
// Walk the tree, computing and printing out the CofM
DisjointTree.PostOrderTraversal<Body<BodyRegion>,
Vector<Double>,TreeRegion> walker =
new DisjointTree.PostOrderTraversal<Body<BodyRegion>,
Vector<Double>,TreeRegion>();
walker.<reads BodyRegion>parallelPostorder(bhTree.getRoot(),
new CofMVisitor<BodyRegion>());
}
}