COSTA: COSt and Termination Analyzer for Java Bytecode
    
    package memory.jolden.bh;

import java.util.Enumeration;

/**
 * A class that represents the root of the data structure used
 * to represent the N-bodies in the Barnes-Hut algorithm.
 **/
class Tree
{
  MathVector rmin;
  double     rsize;
  /**
   * A reference to the root node.
   **/
  Node       root;
  /**
   * The complete list of bodies that have been created.
   **/
   Body       bodyTab;
  /**
   * The complete list of bodies that have been created - in reverse.
   **/
   Body       bodyTabRev;
  
  /**
   * Construct the root of the data structure that represents the N-bodies.
   **/
  Tree()
  {
    rmin       = new MathVector();
    rsize      = -2.0 * -2.0;
    root       = null;
    bodyTab    = null;
    bodyTabRev = null;

    rmin.value(0, -2.0);
    rmin.value(1, -2.0);
    rmin.value(2, -2.0);
  }
  
  /**
   * Return an enumeration of the bodies.
   * @return an enumeration of the bodies.
   **/
  final Enumeration bodies()
  {
    return bodyTab.elements();
  }

  /**
   * Return an enumeration of the bodies - in reverse.
   * @return an enumeration of the bodies - in reverse.
   **/
  final Enumeration bodiesRev()
  {
    return bodyTabRev.elementsRev();
  }

  /**
   * Create the testdata used in the benchmark.
   * @param nbody the number of bodies to create
   **/
  final void createTestData(int nbody)
  {
    MathVector cmr = new MathVector();
    MathVector cmv = new MathVector();

    Body head = new Body();
    Body prev = head;

    double rsc  = 3.0 * Math.PI / 16.0;
    double vsc  = Math.sqrt(1.0 / rsc);
    double seed = 123.0;

    for (int i = 0; i < nbody; i++) {
      Body p = new Body();

      prev.setNext(p);
      prev = p;
      p.mass = 1.0/(double)nbody;
      
      seed      = BH.myRand(seed);
      double t1 = BH.xRand(0.0, 0.999, seed);
      t1        = Math.pow(t1, (-2.0/3.0)) - 1.0;
      double r  = 1.0 / Math.sqrt(t1);

      double coeff = 4.0;
      for (int k = 0; k < MathVector.NDIM; k++) {
	seed = BH.myRand(seed);
	r = BH.xRand(0.0, 0.999, seed);
	p.pos.value(k, coeff*r);
      }
      
      cmr.addition(p.pos);

      double x, y;
      do {
      	seed = BH.myRand(seed);
      	x    = BH.xRand(0.0, 1.0, seed);
      	seed = BH.myRand(seed);
      	y    = BH.xRand(0.0, 0.1, seed);
      } while (y > x*x * Math.pow(1.0 - x*x, 3.5));

      double v = Math.sqrt(2.0) * x / Math.pow(1 + r*r, 0.25);

      double rad = vsc * v;
      double rsq=0;
      do {
      	for (int k = 0; k < MathVector.NDIM; k++) {
      	  seed     = BH.myRand(seed);
      	  p.vel.value(k, BH.xRand(-1.0, 1.0, seed));
      	}
      	rsq = p.vel.dotProduct();
      } while (rsq > 1.0);
      double rsc1 = rad / Math.sqrt(rsq);
      p.vel.multScalar(rsc1);
      cmv.addition(p.vel);
    }

    // mark end of list
    prev.setNext(null);
    // toss the dummy node at the beginning and set a reference to the first element
    bodyTab = head.getNext();

    cmr.divScalar((double)nbody);
    cmv.divScalar((double)nbody);

    prev = null;
    
    Body b = bodyTab;

    while ( b != null ) {
	b.pos.subtraction(cmr);
	b.vel.subtraction(cmv);
	b.setProcNext(prev);
	prev = b;
	b=b.next;
    }
    /*
    for (Enumeration e = bodyTab.elements(); e.hasMoreElements(); ) {
      Body b = (Body)e.nextElement();
      b.pos.subtraction(cmr);
      b.vel.subtraction(cmv);
      b.setProcNext(prev);
      prev = b;
    }
    */
    // set the reference to the last element
    bodyTabRev = prev;
  }


  /**
   * Advance the N-body system one time-step.
   * @param nstep the current time step
   **/
  void stepSystem(int nstep)
  {
    // free the tree
    //root = null;

    //makeTree(nstep);

    // compute the gravity for all the particles
    Body b=bodyTabRev;
    while ( b != null) {
      b.hackGravity(rsize, root);
      b=b.procNext;
    }
    /*
    for (Enumeration e = bodyTabRev.elementsRev(); e.hasMoreElements(); ) {
      Body b = (Body)e.nextElement();
      b.hackGravity(rsize, root);
    }
    */
    vp(bodyTabRev, nstep);

  }

  /**
   * Initialize the tree structure for hack force calculation.
   * @param nsteps the current time step
   **/
  private void makeTree(int nstep)
  {
      Body q=bodyTabRev;
    while ( q != null ) {
      if (q.mass != 0.0) {
	  	  	  q.expandBox(this, nstep);
	  MathVector xqic = intcoord(q.pos);
	if (root == null) {
	  root = q;
	} else {
	    root = root.loadTree(q, xqic, Node.IMAX >> 1, this);
	}
      }
      q=q.procNext;
    }
    /*
    for (Enumeration e = bodiesRev(); e.hasMoreElements(); ) {
      Body q = (Body)e.nextElement();
      if (q.mass != 0.0) {
	  q.expandBox(this, nstep);
	  MathVector xqic = intcoord(q.pos);
	if (root == null) {
	  root = q;
	} else {
	    root = root.loadTree(nstep,q, xqic, Node.IMAX >> 1, this);
	}
      }
    }
    */
      root.hackcofm();
  }

  /**
   * Compute integerized coordinates.
   * @return the coordinates or null if rp is out of bounds
   **/
  final MathVector intcoord(MathVector vp)
  {
    MathVector xp = new MathVector();
    
    double xsc = (vp.value(0) - rmin.value(0)) / rsize;
    if (0.0 <= xsc && xsc < 1.0) {
      xp.value(0, Math.floor(Node.IMAX * xsc));
    } else {
      return null;
    }

    xsc = (vp.value(1) - rmin.value(1)) / rsize;
    if (0.0 <= xsc && xsc < 1.0) {
      xp.value(1, Math.floor(Node.IMAX * xsc));
    } else {
      return null;
    }

    xsc = (vp.value(2) - rmin.value(2)) / rsize;
    if (0.0 <= xsc && xsc < 1.0) {
      xp.value(2, Math.floor(Node.IMAX * xsc));
    } else {
      return null;
    }
    return xp;
  }

  static final private void vp(Body p, int nstep)
  {
    MathVector dacc = new MathVector();
    MathVector dvel = new MathVector();
    double dthf = 0.5 * BH.DTIME;
    Body b=p;

    while ( b != null ) {
      System.out.println("Entering loop");
      MathVector acc1 = (MathVector)b.newAcc.clone();
      if (nstep > 0) {
	  dacc.subtraction(acc1, b.acc);
	  dvel.multScalar(dacc, dthf);
	  dvel.addition(b.vel);
	  b.vel = null;
	  b.vel = (MathVector)dvel.clone();	 
      }      
      b.acc = (MathVector)acc1.clone();
      acc1 = null;
      dvel.multScalar(b.acc, dthf);
      b.acc = null;
      MathVector vel1 = (MathVector)b.vel.clone();
      b.vel = null;
      vel1.addition(dvel);
      MathVector dpos = (MathVector)vel1.clone();
      dpos.multScalar(BH.DTIME);
      dpos.addition(b.pos);
      b.pos = null;
      b.pos = (MathVector)dpos.clone();
      b.pos = null;
      dpos = null;
      vel1.addition(dvel);
      b.vel = (MathVector)vel1.clone();
      b.vel = null;
      vel1 = null;
      b=b.procNext;
    }

    /*
    for (Enumeration e = p.elementsRev(); e.hasMoreElements(); ) {
      Body b = (Body)e.nextElement();
      MathVector acc1 = (MathVector)b.newAcc.clone();
      if (nstep > 0) {
	dacc.subtraction(acc1, b.acc);
	dvel.multScalar(dacc, dthf);
	dvel.addition(b.vel);
	b.vel = (MathVector)dvel.clone();
      }
      b.acc = (MathVector)acc1.clone();
      dvel.multScalar(b.acc, dthf);

      MathVector vel1 = (MathVector)b.vel.clone();
      vel1.addition(dvel);
      MathVector dpos = (MathVector)vel1.clone();
      dpos.multScalar(BH.DTIME);
      dpos.addition(b.pos);
      b.pos = (MathVector)dpos.clone();
      vel1.addition(dvel);
      b.vel = (MathVector)vel1.clone();
    }
    */
  }

    /** main method to test real consumption of cTD **/
    public static void main2(String[] args){
	Tree root = new Tree();
	root.createTestData(8);
    }

    /** main method to test real consumption of eB **/
    public static void main(String[] args){
	Tree root = new Tree();
	root.createTestData(5);
	root.vp(root.bodyTabRev,1);
	//root.root = null;
	//Body q = root.bodyTabRev;
	//q.expandBox(root,5);
    }
}