2 A D implementation of the _bh_ Olden benchmark.
\r
3 The Olden benchmark implements the Barnes-Hut benchmark
\r
6 J. Barnes and P. Hut, "A hierarchical o(N log N) force-calculation algorithm",
\r
7 Nature, 324:446-449, Dec. 1986
\r
9 The original code in the Olden benchmark suite is derived from the
\r
10 ftp://hubble.ifa.hawaii.edu/pub/barnes/treecode
\r
11 source distributed by Barnes.
\r
13 Java code converted to D by leonardo maffi, V.1.0, Dec 25 2009.
\r
15 Removed output unless an option is passed by Leandro Lucarella, 2010-08-04.
\r
16 Downloaded from http://www.fantascienza.net/leonardo/js/
\r
17 http://www.fantascienza.net/leonardo/js/dolden_bh.zip
\r
22 import tango.stdc.stdio: printf, sprintf, fprintf, stderr;
\r
23 import tango.stdc.stdlib: exit, malloc, free;
\r
24 import tango.stdc.time: CLOCKS_PER_SEC, clock;
\r
25 import tango.math.Math: sqrt, floor, PI, pow;
\r
27 import Integer = tango.text.convert.Integer;
\r
28 alias Integer.parse toInt;
\r
30 import std.c.stdio: printf, sprintf, fprintf, stderr;
\r
31 import std.c.stdlib: exit, malloc, free;
\r
32 import std.c.time: CLOCKS_PER_SEC, clock;
\r
33 import std.math: sqrt, floor, PI, pow;
\r
35 version (D_Version2) {
\r
36 import std.conv: to;
\r
37 alias to!(int, char[]) toInt;
\r
39 import std.conv: toInt;
\r
45 return clock() / cast(double)CLOCKS_PER_SEC;
\r
50 Basic uniform random generator: Minimal Standard in Park and
\r
51 Miller (1988): "Random Number Generators: Good Ones Are Hard to
\r
52 Find", Comm. of the ACM, 31, 1192-1201.
\r
53 Parameters: m = 2^31-1, a=48271.
\r
55 Adapted from Pascal code by Jesper Lund:
\r
56 http://www.gnu-pascal.de/crystal/gpc/en/mail1390.html
\r
59 const int m = int.max;
\r
60 const int a = 48_271;
\r
61 const int q = m / a;
\r
62 const int r = m % a;
\r
65 public double uniform(double min, double max) {
\r
67 seed = a * (seed - k * q) - r * k;
\r
70 double r = cast(double)seed / m;
\r
71 return r * (max - min) + min;
\r
76 interface Enumeration {
\r
77 bool hasMoreElements();
\r
78 Object nextElement();
\r
83 A class representing a three dimensional vector that implements
\r
84 several math operations. To improve speed we implement the
\r
85 vector as an array of doubles rather than use the exising
\r
86 code in the java.util.Vec3 class.
\r
89 /// The number of dimensions in the vector
\r
90 // Can't be changed because of crossProduct()
\r
93 /// An array containing the values in the vector.
\r
94 private double data[];
\r
96 /// Construct an empty 3 dimensional vector for use in Barnes-Hut algorithm.
\r
102 /// Create a copy of the vector. Return a clone of the math vector
\r
103 public Vec3 clone() {
\r
105 v.data.length = NDIM;
\r
106 v.data[] = this.data[];
\r
111 Return the value at the i'th index of the vector.
\r
112 @param i the vector index
\r
113 @return the value at the i'th index of the vector.
\r
115 final double value(int i) {
\r
120 Set the value of the i'th index of the vector.
\r
121 @param i the vector index
\r
122 @param v the value to store
\r
124 final void value(int i, double v) {
\r
129 Set one of the dimensions of the vector to 1.0
\r
130 param j the dimension to set.
\r
132 final void unit(int j) {
\r
133 for (int i = 0; i < NDIM; i++)
\r
134 data[i] = (i == j) ? 1.0 : 0.0;
\r
138 Add two vectors and the result is placed in this vector.
\r
139 @param u the other operand of the addition
\r
141 final void addition(Vec3 u) {
\r
142 for (int i = 0; i < NDIM; i++)
\r
143 data[i] += u.data[i];
\r
147 * Subtract two vectors and the result is placed in this vector.
\r
148 * This vector contain the first operand.
\r
149 * @param u the other operand of the subtraction.
\r
151 final void subtraction(Vec3 u) {
\r
152 for (int i = 0; i < NDIM; i++)
\r
153 data[i] -= u.data[i];
\r
157 Subtract two vectors and the result is placed in this vector.
\r
158 @param u the first operand of the subtraction.
\r
159 @param v the second opernd of the subtraction
\r
161 final void subtraction(Vec3 u, Vec3 v) {
\r
162 for (int i = 0; i < NDIM; i++)
\r
163 data[i] = u.data[i] - v.data[i];
\r
167 Multiply the vector times a scalar.
\r
168 @param s the scalar value
\r
170 final void multScalar(double s) {
\r
171 for (int i = 0; i < NDIM; i++)
\r
176 * Multiply the vector times a scalar and place the result in this vector.
\r
177 * @param u the vector
\r
178 * @param s the scalar value
\r
180 final void multScalar(Vec3 u, double s) {
\r
181 for (int i = 0; i < NDIM; i++)
\r
182 data[i] = u.data[i] * s;
\r
186 * Divide each element of the vector by a scalar value.
\r
187 * @param s the scalar value.
\r
189 final void divScalar(double s) {
\r
190 for (int i = 0; i < NDIM; i++)
\r
195 * Return the dot product of a vector.
\r
196 * @return the dot product of a vector.
\r
198 final double dotProduct() {
\r
200 for (int i = 0; i < NDIM; i++)
\r
201 s += data[i] * data[i];
\r
205 final double absolute() {
\r
207 for (int i = 0; i < NDIM; i++)
\r
208 tmp += data[i] * data[i];
\r
212 final double distance(Vec3 v) {
\r
214 for (int i = 0; i < NDIM; i++)
\r
215 tmp += ((data[i] - v.data[i]) * (data[i] - v.data[i]));
\r
219 final void crossProduct(Vec3 u, Vec3 w) {
\r
220 data[0] = u.data[1] * w.data[2] - u.data[2] * w.data[1];
\r
221 data[1] = u.data[2] * w.data[0] - u.data[0] * w.data[2];
\r
222 data[2] = u.data[0] * w.data[1] - u.data[1] * w.data[0];
\r
225 final void incrementalAdd(Vec3 u) {
\r
226 for (int i = 0; i < NDIM; i++)
\r
227 data[i] += u.data[i];
\r
230 final void incrementalSub(Vec3 u) {
\r
231 for (int i = 0; i < NDIM; i++)
\r
232 data[i] -= u.data[i];
\r
235 final void incrementalMultScalar(double s) {
\r
236 for (int i = 0; i < NDIM; i++)
\r
240 final void incrementalDivScalar(double s) {
\r
241 for (int i = 0; i < NDIM; i++)
\r
245 final void addScalar(Vec3 u, double s) {
\r
246 for (int i = 0; i < NDIM; i++)
\r
247 data[i] = u.data[i] + s;
\r
250 public char* toCString() {
\r
251 // this is not generic code at all
\r
252 char* result = cast(char*)malloc(100);
\r
253 if (result == null) exit(1);
\r
254 sprintf(result, "%.17f %.17f %.17f ", data[0], data[1], data[2]);
\r
260 /// A class that represents the common fields of a cell or body data structure.
\r
261 abstract class Node {
\r
262 // mass of the node
\r
265 // Position of the node
\r
268 // highest bit of int coord
\r
269 const int IMAX = 1073741824;
\r
271 // potential softening parameter
\r
272 const double EPS = 0.05;
\r
274 /// Construct an empty node
\r
280 abstract Node loadTree(Body p, Vec3 xpic, int l, Tree root);
\r
282 abstract double hackcofm();
\r
284 abstract HG walkSubTree(double dsq, HG hg);
\r
286 static final int oldSubindex(Vec3 ic, int l) {
\r
288 for (int k = 0; k < Vec3.NDIM; k++)
\r
289 if ((cast(int)ic.value(k) & l) != 0)
\r
290 i += Cell.NSUB >> (k + 1);
\r
294 public char* toCString() {
\r
295 char* result = cast(char*)malloc(130);
\r
296 if (result == null) exit(1);
\r
297 char* pos_str = pos.toCString();
\r
298 sprintf(result, "%f : %s", mass, pos_str);
\r
303 /// Compute a single body-body or body-cell interaction
\r
304 final HG gravSub(HG hg) {
\r
305 Vec3 dr = new Vec3();
\r
306 dr.subtraction(pos, hg.pos0);
\r
308 double drsq = dr.dotProduct() + (EPS * EPS);
\r
309 double drabs = sqrt(drsq);
\r
311 double phii = mass / drabs;
\r
313 double mor3 = phii / drsq;
\r
314 dr.multScalar(mor3);
\r
315 hg.acc0.addition(dr);
\r
320 * A sub class which is used to compute and save information during the
\r
321 * gravity computation phase.
\r
323 static protected final class HG {
\r
324 /// Body to skip in force evaluation
\r
327 /// Point at which to evaluate field
\r
330 /// Computed potential at pos0
\r
334 /// computed acceleration at pos0
\r
338 * Create a HG object.
\r
339 * @param b the body object
\r
340 * @param p a vector that represents the body
\r
342 this(Body b, Vec3 p) {
\r
352 /// A class used to representing particles in the N-body simulation.
\r
353 final class Body : Node {
\r
354 Vec3 vel, acc, newAcc;
\r
356 private Body next, procNext;
\r
358 /// Create an empty body.
\r
362 newAcc = new Vec3();
\r
366 * Set the next body in the list.
\r
367 * @param n the body
\r
369 final void setNext(Body n) {
\r
374 * Get the next body in the list.
\r
375 * @return the next body
\r
377 final Body getNext() {
\r
382 * Set the next body in the list.
\r
383 * @param n the body
\r
385 final void setProcNext(Body n) {
\r
390 * Get the next body in the list.
\r
391 * @return the next body
\r
393 final Body getProcNext() {
\r
398 * Enlarge cubical "box", salvaging existing tree structure.
\r
399 * @param tree the root of the tree.
\r
400 * @param nsteps the current time step
\r
402 final void expandBox(Tree tree, int nsteps) {
\r
403 Vec3 rmid = new Vec3();
\r
405 bool inbox = icTest(tree);
\r
407 double rsize = tree.rsize;
\r
408 rmid.addScalar(tree.rmin, 0.5 * rsize);
\r
410 for (int k = 0; k < Vec3.NDIM; k++)
\r
411 if (pos.value(k) < rmid.value(k)) {
\r
412 double rmin = tree.rmin.value(k);
\r
413 tree.rmin.value(k, rmin - rsize);
\r
416 tree.rsize = 2.0 * rsize;
\r
417 if (tree.root !is null) {
\r
418 Vec3 ic = tree.intcoord(rmid);
\r
420 throw new Exception("Value is out of bounds");
\r
421 int k = oldSubindex(ic, IMAX >> 1);
\r
422 Cell newt = new Cell();
\r
423 newt.subp[k] = tree.root;
\r
425 inbox = icTest(tree);
\r
431 * Check the bounds of the body and return true if it isn't in the
\r
434 final bool icTest(Tree tree) {
\r
435 double pos0 = pos.value(0);
\r
436 double pos1 = pos.value(1);
\r
437 double pos2 = pos.value(2);
\r
439 // by default, it is in bounds
\r
440 bool result = true;
\r
442 double xsc = (pos0 - tree.rmin.value(0)) / tree.rsize;
\r
443 if (!(0.0 < xsc && xsc < 1.0))
\r
446 xsc = (pos1 - tree.rmin.value(1)) / tree.rsize;
\r
447 if (!(0.0 < xsc && xsc < 1.0))
\r
450 xsc = (pos2 - tree.rmin.value(2)) / tree.rsize;
\r
451 if (!(0.0 < xsc && xsc < 1.0))
\r
458 * Descend Tree and insert particle. We're at a body so we need to
\r
459 * create a cell and attach this body to the cell.
\r
460 * @param p the body to insert
\r
463 * @param tree the root of the data structure
\r
464 * @return the subtree with the new body inserted
\r
466 final Node loadTree(Body p, Vec3 xpic, int l, Tree tree) {
\r
468 Cell retval = new Cell();
\r
469 int si = subindex(tree, l);
\r
470 // attach this Body node to the cell
\r
471 retval.subp[si] = this;
\r
473 // move down one level
\r
474 si = oldSubindex(xpic, l);
\r
475 Node rt = retval.subp[si];
\r
477 retval.subp[si] = rt.loadTree(p, xpic, l >> 1, tree);
\r
479 retval.subp[si] = p;
\r
484 * Descend tree finding center of mass coordinates
\r
485 * @return the mass of this node
\r
487 final double hackcofm() {
\r
491 /// iteration of the bodies
\r
492 int opApply(int delegate(ref Body) dg) {
\r
494 Body current = this;
\r
495 while (current !is null) {
\r
496 result = dg(current);
\r
497 current = current.next;
\r
504 /// inverse iteration of the bodies
\r
505 int opApplyReverse(int delegate(ref Body) dg) {
\r
507 Body current = this;
\r
508 while (current !is null) {
\r
509 result = dg(current);
\r
510 current = current.procNext;
\r
519 * Return an enumeration of the bodies
\r
520 * @return an enumeration of the bodies
\r
522 final Enumeration elements() {
\r
523 // a local class that implements the enumerator
\r
524 static final class Enumerate : Enumeration {
\r
525 private Body current;
\r
526 public this(Body outer) {
\r
527 //this.current = Body.this;
\r
528 this.current = outer;
\r
530 public bool hasMoreElements() {
\r
531 return current !is null;
\r
533 public Object nextElement() {
\r
534 Object retval = current;
\r
535 current = current.next;
\r
540 return new Enumerate(this);
\r
543 final Enumeration elementsRev() {
\r
544 // a local class that implements the enumerator
\r
545 static class Enumerate : Enumeration {
\r
546 private Body current;
\r
547 public this(Body outer) {
\r
548 //this.current = Body.this;
\r
549 this.current = outer;
\r
551 public bool hasMoreElements() {
\r
552 return current !is null;
\r
554 public Object nextElement() {
\r
555 Object retval = current;
\r
556 current = current.procNext;
\r
561 return new Enumerate(this);
\r
565 * Determine which subcell to select.
\r
566 * Combination of intcoord and oldSubindex.
\r
567 * @param t the root of the tree
\r
569 final int subindex(Tree tree, int l) {
\r
570 Vec3 xp = new Vec3();
\r
572 double xsc = (pos.value(0) - tree.rmin.value(0)) / tree.rsize;
\r
573 xp.value(0, floor(IMAX * xsc));
\r
575 xsc = (pos.value(1) - tree.rmin.value(1)) / tree.rsize;
\r
576 xp.value(1, floor(IMAX * xsc));
\r
578 xsc = (pos.value(2) - tree.rmin.value(2)) / tree.rsize;
\r
579 xp.value(2, floor(IMAX * xsc));
\r
582 for (int k = 0; k < Vec3.NDIM; k++)
\r
583 if ((cast(int)xp.value(k) & l) != 0)
\r
584 i += Cell.NSUB >> (k + 1);
\r
589 * Evaluate gravitational field on the body.
\r
590 * The original olden version calls a routine named "walkscan",
\r
591 * but we use the same name that is in the Barnes code.
\r
593 final void hackGravity(double rsize, Node root) {
\r
594 Vec3 pos0 = pos.clone();
\r
595 HG hg = new HG(this, pos);
\r
596 hg = root.walkSubTree(rsize * rsize, hg);
\r
601 /// Recursively walk the tree to do hackwalk calculation
\r
602 final HG walkSubTree(double dsq, HG hg) {
\r
603 if (this != hg.pskip)
\r
609 * Return a string represenation of a body.
\r
610 * @return a string represenation of a body.
\r
612 public char* toCString() {
\r
613 char* result = cast(char*)malloc(140);
\r
614 if (result == null) exit(1);
\r
615 char* super_str = super.toCString();
\r
616 sprintf(result, "Body %s", super_str);
\r
624 /// A class used to represent internal nodes in the tree
\r
625 final class Cell : Node {
\r
626 // subcells per cell
\r
627 const int NSUB = 1 << Vec3.NDIM;
\r
630 * The children of this cell node. Each entry may contain either
\r
631 * another cell or a body.
\r
637 subp.length = NSUB;
\r
641 * Descend Tree and insert particle. We're at a cell so
\r
642 * we need to move down the tree.
\r
643 * @param p the body to insert into the tree
\r
646 * @param tree the root of the tree
\r
647 * @return the subtree with the new body inserted
\r
649 Node loadTree(Body p, Vec3 xpic, int l, Tree tree) {
\r
650 // move down one level
\r
651 int si = oldSubindex(xpic, l);
\r
652 Node rt = subp[si];
\r
654 subp[si] = rt.loadTree(p, xpic, l >> 1, tree);
\r
661 * Descend tree finding center of mass coordinates
\r
662 * @return the mass of this node
\r
664 double hackcofm() {
\r
666 Vec3 tmpPos = new Vec3();
\r
667 Vec3 tmpv = new Vec3();
\r
668 for (int i = 0; i < NSUB; i++) {
\r
671 double mr = r.hackcofm();
\r
673 tmpv.multScalar(r.pos, mr);
\r
674 tmpPos.addition(tmpv);
\r
679 pos.divScalar(mass);
\r
684 /// Recursively walk the tree to do hackwalk calculation
\r
685 HG walkSubTree(double dsq, HG hg) {
\r
686 if (subdivp(dsq, hg)) {
\r
687 for (int k = 0; k < Cell.NSUB; k++) {
\r
690 hg = r.walkSubTree(dsq / 4.0, hg);
\r
699 * Decide if the cell is too close to accept as a single term.
\r
700 * @return true if the cell is too close.
\r
702 bool subdivp(double dsq, HG hg) {
\r
703 Vec3 dr = new Vec3();
\r
704 dr.subtraction(pos, hg.pos0);
\r
705 double drsq = dr.dotProduct();
\r
707 // in the original olden version drsp is multiplied by 1.0
\r
712 * Return a string represenation of a cell.
\r
713 * @return a string represenation of a cell.
\r
715 public char* toCString() {
\r
716 char* result = cast(char*)malloc(140);
\r
717 if (result == null) exit(1);
\r
718 char* super_str = super.toCString();
\r
719 sprintf(result, "Cell %s", super_str);
\r
727 * A class that represents the root of the data structure used
\r
728 * to represent the N-bodies in the Barnes-Hut algorithm.
\r
734 /// A reference to the root node.
\r
737 /// The complete list of bodies that have been created.
\r
738 private Body bodyTab;
\r
740 /// The complete list of bodies that have been created - in reverse.
\r
741 private Body bodyTabRev;
\r
743 /// Construct the root of the data structure that represents the N-bodies.
\r
746 rsize = -2.0 * -2.0;
\r
750 rmin.value(0, -2.0);
\r
751 rmin.value(1, -2.0);
\r
752 rmin.value(2, -2.0);
\r
756 * Return an enumeration of the bodies.
\r
757 * @return an enumeration of the bodies.
\r
759 final Enumeration bodies() {
\r
760 return bodyTab.elements();
\r
764 * Return an enumeration of the bodies - in reverse.
\r
765 * @return an enumeration of the bodies - in reverse.
\r
767 final Enumeration bodiesRev() {
\r
768 return bodyTabRev.elementsRev();
\r
772 * Create the testdata used in the benchmark.
\r
773 * @param nbody the number of bodies to create
\r
775 final void createTestData(int nbody) {
\r
776 Vec3 cmr = new Vec3();
\r
777 Vec3 cmv = new Vec3();
\r
778 Body head = new Body();
\r
781 double rsc = 3.0 * PI / 16.0;
\r
782 double vsc = sqrt(1.0 / rsc);
\r
784 Random rnd = Random(seed);
\r
786 for (int i = 0; i < nbody; i++) {
\r
787 Body p = new Body();
\r
791 p.mass = 1.0 / cast(double)nbody;
\r
793 double t1 = rnd.uniform(0.0, 0.999);
\r
794 t1 = pow(t1, (-2.0 / 3.0)) - 1.0;
\r
795 double r = 1.0 / sqrt(t1);
\r
797 double coeff = 4.0;
\r
798 for (int k = 0; k < Vec3.NDIM; k++) {
\r
799 r = rnd.uniform(0.0, 0.999);
\r
800 p.pos.value(k, coeff * r);
\r
803 cmr.addition(p.pos);
\r
807 x = rnd.uniform(0.0, 1.0);
\r
808 y = rnd.uniform(0.0, 0.1);
\r
809 } while (y > (x * x * pow(1.0 - x * x, 3.5)));
\r
811 double v = sqrt(2.0) * x / pow(1 + r * r, 0.25);
\r
813 double rad = vsc * v;
\r
816 for (int k = 0; k < Vec3.NDIM; k++)
\r
817 p.vel.value(k, rnd.uniform(-1.0, 1.0));
\r
818 rsq = p.vel.dotProduct();
\r
819 } while (rsq > 1.0);
\r
820 double rsc1 = rad / sqrt(rsq);
\r
821 p.vel.multScalar(rsc1);
\r
822 cmv.addition(p.vel);
\r
825 // mark end of list
\r
826 prev.setNext(null);
\r
828 // toss the dummy node at the beginning and set a reference to the first element
\r
829 bodyTab = head.getNext();
\r
831 cmr.divScalar(cast(double)nbody);
\r
832 cmv.divScalar(cast(double)nbody);
\r
836 for (Enumeration e = bodyTab.elements(); e.hasMoreElements();) {
\r
837 Body b = cast(Body)e.nextElement();
\r
838 b.pos.subtraction(cmr);
\r
839 b.vel.subtraction(cmv);
\r
840 b.setProcNext(prev);
\r
844 // set the reference to the last element
\r
850 * Advance the N-body system one time-step.
\r
851 * @param nstep the current time step
\r
853 void stepSystem(int nstep) {
\r
859 // compute the gravity for all the particles
\r
860 for (Enumeration e = bodyTabRev.elementsRev(); e.hasMoreElements();) {
\r
861 Body b = cast(Body)e.nextElement();
\r
862 b.hackGravity(rsize, root);
\r
864 vp(bodyTabRev, nstep);
\r
868 * Initialize the tree structure for hack force calculation.
\r
869 * @param nsteps the current time step
\r
871 private void makeTree(int nstep) {
\r
872 for (Enumeration e = bodiesRev(); e.hasMoreElements();) {
\r
873 Body q = cast(Body)e.nextElement();
\r
874 if (q.mass != 0.0) {
\r
875 q.expandBox(this, nstep);
\r
876 Vec3 xqic = intcoord(q.pos);
\r
877 if (root is null) {
\r
880 root = root.loadTree(q, xqic, Node.IMAX >> 1, this);
\r
888 * Compute integerized coordinates.
\r
889 * @return the coordinates or null if rp is out of bounds
\r
891 final Vec3 intcoord(Vec3 vp) {
\r
892 Vec3 xp = new Vec3();
\r
894 double xsc = (vp.value(0) - rmin.value(0)) / rsize;
\r
895 if (0.0 <= xsc && xsc < 1.0)
\r
896 xp.value(0, floor(Node.IMAX * xsc));
\r
900 xsc = (vp.value(1) - rmin.value(1)) / rsize;
\r
901 if (0.0 <= xsc && xsc < 1.0)
\r
902 xp.value(1, floor(Node.IMAX * xsc));
\r
906 xsc = (vp.value(2) - rmin.value(2)) / rsize;
\r
907 if (0.0 <= xsc && xsc < 1.0)
\r
908 xp.value(2, floor(Node.IMAX * xsc));
\r
915 static final private void vp(Body p, int nstep) {
\r
916 Vec3 dacc = new Vec3();
\r
917 Vec3 dvel = new Vec3();
\r
918 double dthf = 0.5 * BH.DTIME;
\r
920 for (Enumeration e = p.elementsRev(); e.hasMoreElements();) {
\r
921 Body b = cast(Body)e.nextElement();
\r
922 Vec3 acc1 = b.newAcc.clone();
\r
924 dacc.subtraction(acc1, b.acc);
\r
925 dvel.multScalar(dacc, dthf);
\r
926 dvel.addition(b.vel);
\r
927 b.vel = dvel.clone();
\r
930 b.acc = acc1.clone();
\r
931 dvel.multScalar(b.acc, dthf);
\r
933 Vec3 vel1 = b.vel.clone();
\r
934 vel1.addition(dvel);
\r
935 Vec3 dpos = vel1.clone();
\r
936 dpos.multScalar(BH.DTIME);
\r
937 dpos.addition(b.pos);
\r
938 b.pos = dpos.clone();
\r
939 vel1.addition(dvel);
\r
940 b.vel = vel1.clone();
\r
947 /// The user specified number of bodies to create.
\r
948 private static int nbody = 0;
\r
950 /// The maximum number of time steps to take in the simulation
\r
951 private static int nsteps = 10;
\r
953 /// Should we print information messsages
\r
954 private static bool printMsgs = false;
\r
956 /// Should we print detailed results
\r
957 private static bool printResults = false;
\r
959 const double DTIME = 0.0125;
\r
960 private const double TSTOP = 2.0;
\r
962 public static final void main(char[][] args) {
\r
963 parseCmdLine(args);
\r
966 printf("nbody = %d\n", nbody);
\r
968 auto start0 = myclock();
\r
969 Tree root = new Tree();
\r
970 root.createTestData(nbody);
\r
971 auto end0 = myclock();
\r
973 printf("Bodies created\n");
\r
975 auto start1 = myclock();
\r
978 while ((tnow < TSTOP + 0.1 * DTIME) && (i < nsteps)) {
\r
979 root.stepSystem(i++);
\r
982 auto end1 = myclock();
\r
984 if (printResults) {
\r
986 for (Enumeration e = root.bodies(); e.hasMoreElements();) {
\r
987 Body b = cast(Body)e.nextElement();
\r
988 char* str_ptr = b.pos.toCString();
\r
989 printf("body %d: %s\n", j++, str_ptr);
\r
995 printf("Build time %.2f\n", end0 - start0);
\r
996 printf("Compute Time %.2f\n", end1 - start1);
\r
997 printf("Total Time %.2f\n", end1 - start0);
\r
1002 private static final void parseCmdLine(char[][] args) {
\r
1004 while (i < args.length && args[i][0] == '-') {
\r
1005 char[] arg = args[i++];
\r
1007 // check for options that require arguments
\r
1008 if (arg == "-b") {
\r
1009 if (i < args.length)
\r
1010 nbody = toInt(args[i++]);
\r
1012 throw new Exception("-l requires the number of levels");
\r
1013 } else if (arg == "-s") {
\r
1014 if (i < args.length)
\r
1015 nsteps = toInt(args[i++]);
\r
1017 throw new Exception("-l requires the number of levels");
\r
1018 } else if (arg == "-m") {
\r
1020 } else if (arg == "-p") {
\r
1021 printResults = true;
\r
1022 } else if (arg == "-h") {
\r
1031 /// The usage routine which describes the program options.
\r
1032 private static final void usage() {
\r
1033 fprintf(stderr, "usage: BH -b <size> [-s <steps>] [-p] [-m] [-h]\n");
\r
1034 fprintf(stderr, " -b the number of bodies\n");
\r
1035 fprintf(stderr, " -s the max. number of time steps (default=10)\n");
\r
1036 fprintf(stderr, " -p (print detailed results)\n");
\r
1037 fprintf(stderr, " -m (print information messages\n");
\r
1043 void main(char[][] args) {
\r