Commit in lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux on MAIN
analysis/CheatTrackFinderDriver.java+2-31.1 -> 1.2
converters/TrackToITrackConverter.java+2-21.1 -> 1.2
infrastructure/CruxCluster.java+58-61.3 -> 1.4
              /CruxClusterValidator.java+4-31.1.1.1 -> 1.2
              /CruxParticle.java+2-21.3 -> 1.4
itc/ClusterNodeHeprepConverter.java+105added 1.1
   /ClusterNode.java+2-41.1 -> 1.2
   /Node.java+7-11.1 -> 1.2
   /Rosary.java+77-711.1 -> 1.2
   /RosaryClusterer.java+36-221.3 -> 1.4
   /RosaryHeprepConverter.java+20-221.1 -> 1.2
diagnostics/PropagationTest.java+103added 1.1
           /RosarySlicer.java+135added 1.1
+553-136
3 added + 10 modified, total 13 files
Move Hep3Vector implementations to a separate package

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/analysis
CheatTrackFinderDriver.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- CheatTrackFinderDriver.java	3 Mar 2009 21:25:32 -0000	1.1
+++ CheatTrackFinderDriver.java	6 Apr 2009 19:49:24 -0000	1.2
@@ -9,14 +9,13 @@
 import org.lcsim.event.SimTrackerHit;
 
 import org.lcsim.contrib.onoprien.util.NoSuchParameterException;
-import org.lcsim.contrib.onoprien.util.ConstHep3Vector;
-import org.lcsim.contrib.onoprien.util.constants.Particles;
 import org.lcsim.contrib.onoprien.util.job.Driver;
 import org.lcsim.contrib.onoprien.util.job.JobEvent;
 import org.lcsim.contrib.onoprien.util.job.JobEventListener;
 import org.lcsim.contrib.onoprien.util.job.JobManager;
 import org.lcsim.contrib.onoprien.util.swim.BField;
 import org.lcsim.contrib.onoprien.util.swim.Helix;
+import org.lcsim.contrib.onoprien.util.vector.ConstHep3Vector;
 
 import org.lcsim.contrib.onoprien.vsegment.hit.ITrackerHit;
 import org.lcsim.contrib.onoprien.vsegment.mctruth.MCTruthVS;
@@ -28,7 +27,7 @@
  * Driver that uses MC truth info to produce a list of tracks.
  *
  * @author D. Onoprienko
- * @version $Id: CheatTrackFinderDriver.java,v 1.1 2009/03/03 21:25:32 onoprien Exp $
+ * @version $Id: CheatTrackFinderDriver.java,v 1.2 2009/04/06 19:49:24 onoprien Exp $
  */
 public class CheatTrackFinderDriver extends Driver implements JobEventListener {
 

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/converters
TrackToITrackConverter.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- TrackToITrackConverter.java	12 Mar 2009 22:27:12 -0000	1.1
+++ TrackToITrackConverter.java	6 Apr 2009 19:49:24 -0000	1.2
@@ -10,7 +10,7 @@
 import org.lcsim.event.TrackerHit;
 import org.lcsim.fit.helicaltrack.HelicalTrackHit;
 
-import org.lcsim.contrib.onoprien.util.ConstHep3Vector;
+import org.lcsim.contrib.onoprien.util.vector.ConstHep3Vector;
 import org.lcsim.contrib.onoprien.util.WeightedTable;
 import org.lcsim.contrib.onoprien.util.job.Driver;
 import org.lcsim.contrib.onoprien.util.job.JobEvent;
@@ -36,7 +36,7 @@
  * last conversion.
  *
  * @author D. Onoprienko
- * @version $Id: TrackToITrackConverter.java,v 1.1 2009/03/12 22:27:12 onoprien Exp $
+ * @version $Id: TrackToITrackConverter.java,v 1.2 2009/04/06 19:49:24 onoprien Exp $
  */
 public class TrackToITrackConverter extends Driver implements JobEventListener {
 

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/infrastructure
CruxCluster.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- CruxCluster.java	18 Feb 2009 03:29:07 -0000	1.3
+++ CruxCluster.java	6 Apr 2009 19:49:24 -0000	1.4
@@ -3,12 +3,14 @@
 import java.util.*;
 
 import hep.physics.matrix.SymmetricMatrix;
-import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
 import org.lcsim.geometry.Subdetector;
 
 import org.lcsim.contrib.onoprien.util.job.JobManager;
+import org.lcsim.contrib.onoprien.util.vector.BasicHep3Vector;
+import org.lcsim.contrib.onoprien.util.vector.ConstHep3Vector;
 
 import org.lcsim.contrib.onoprien.crux.CruxManager;
 import org.lcsim.contrib.onoprien.crux.geom.CalModule;
@@ -19,7 +21,7 @@
  * Crux package specific implementation of {@link ICluster}.
  *
  * @author D. Onoprienko
- * @version $Id: CruxCluster.java,v 1.3 2009/02/18 03:29:07 onoprien Exp $
+ * @version $Id: CruxCluster.java,v 1.4 2009/04/06 19:49:24 onoprien Exp $
  */
 public class CruxCluster implements ICluster {
   
@@ -33,7 +35,7 @@
     _size = -1;
     _hits = new ArrayList<CalorimeterHit>(0);
     _clusters = new ArrayList<CruxCluster>(0);
-    _validator = CruxManager.defaultInstance().getDefaultClusterValidator();
+    _validator = _defVal;
   }
   
   /** Deep copy constructor. */
@@ -41,7 +43,7 @@
     _type = cluster.getType();
     _energy = cluster.getEnergy();
     double[] temp = cluster.getPosition();
-    _position = (temp == null) ? null : new BasicHep3Vector(temp);
+    _position = (temp == null) ? null : new ConstHep3Vector(temp);
     temp = cluster.getPositionError();
     _positionCov = (temp == null) ? null : new SymmetricMatrix(3, temp, true);
     _iTheta = cluster.getITheta();
@@ -77,7 +79,7 @@
         _hits.removeAll(c.getCalorimeterHits());
       }
       _hits.trimToSize();
-      _validator = CruxManager.defaultInstance().getDefaultClusterValidator();
+      _validator = _defVal;
     }
 
     _size = -1;
@@ -352,10 +354,12 @@
   }
   
 // -- Private parts :  ---------------------------------------------------------
+
+  static protected DefaultValidator _defVal = new DefaultValidator();
   
   protected int _type;
   protected double _energy;
-  protected BasicHep3Vector _position;
+  protected ConstHep3Vector _position;
   protected SymmetricMatrix _positionCov;
   protected double _iTheta;
   protected double _iPhi;
@@ -369,11 +373,59 @@
   ArrayList<CalModule> _modules;
   
   protected CruxClusterValidator _validator;
+
+// -- Comparator :  ------------------------------------------------------------
   
   static private Comparator<Subdetector> _sdComparator = new Comparator<Subdetector>() {
     public int compare(Subdetector sd1, Subdetector sd2) {
       return sd1.getSystemID() - sd2.getSystemID();
     }
   };
+
+// -- Default validator class :  -----------------------------------------------
+
+  static protected class DefaultValidator extends CruxClusterValidator {
+
+    public double getEnergy(CruxCluster cluster) {
+      throw new UnsupportedOperationException();
+    }
+
+    public ConstHep3Vector getPosition(CruxCluster cluster) {
+      BasicHep3Vector pos = new BasicHep3Vector();
+      double weight = 0.;
+      for (CruxCluster cl : cluster._clusters) {
+        double w = cl.getEnergy();
+        pos.add(cl._position, w);
+        weight += w;
+      }
+      for (CalorimeterHit hit : cluster._hits) {
+        double w = hit.getCorrectedEnergy();
+        pos.add(hit.getPositionVec(), w);
+        weight += w;
+      }
+      if (weight == 0.) return ConstHep3Vector.V000;
+      return new ConstHep3Vector(pos.scale(1./weight));
+    }
+
+    public SymmetricMatrix getPositionError(CruxCluster cluster) {
+      throw new UnsupportedOperationException();
+    }
+
+    public double getITheta(CruxCluster cluster) {
+      throw new UnsupportedOperationException();
+    }
+
+    public double getIPhi(CruxCluster cluster) {
+      throw new UnsupportedOperationException();
+    }
+
+    public double[] getDirectionError(CruxCluster cluster) {
+      throw new UnsupportedOperationException();
+    }
+
+    public double[] getShape(CruxCluster cluster) {
+      throw new UnsupportedOperationException();
+    }
+  }
   
 }

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/infrastructure
CruxClusterValidator.java 1.1.1.1 -> 1.2
diff -u -r1.1.1.1 -r1.2
--- CruxClusterValidator.java	10 Dec 2008 22:03:06 -0000	1.1.1.1
+++ CruxClusterValidator.java	6 Apr 2009 19:49:24 -0000	1.2
@@ -1,7 +1,8 @@
 package org.lcsim.contrib.onoprien.crux.infrastructure;
 
 import hep.physics.matrix.SymmetricMatrix;
-import hep.physics.vec.BasicHep3Vector;
+
+import org.lcsim.contrib.onoprien.util.vector.ConstHep3Vector;
 
 /**
  * Base class for coding algorithms that assign parameters to clusters of calorimeter hits.
@@ -12,13 +13,13 @@
  * Objects returned by overridden methods should not be owned by any other objects.
  *
  * @author D. Onoprienko
- * @version $Id: CruxClusterValidator.java,v 1.1.1.1 2008/12/10 22:03:06 jeremy Exp $
+ * @version $Id: CruxClusterValidator.java,v 1.2 2009/04/06 19:49:24 onoprien Exp $
  */
 public class CruxClusterValidator {
   
   public double getEnergy(CruxCluster cluster) {throw new UnsupportedOperationException();}
   
-  public BasicHep3Vector getPosition(CruxCluster cluster) {throw new UnsupportedOperationException();}
+  public ConstHep3Vector getPosition(CruxCluster cluster) {throw new UnsupportedOperationException();}
   
   public SymmetricMatrix getPositionError(CruxCluster cluster) {throw new UnsupportedOperationException();}
   

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/infrastructure
CruxParticle.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- CruxParticle.java	4 Mar 2009 03:29:58 -0000	1.3
+++ CruxParticle.java	6 Apr 2009 19:49:24 -0000	1.4
@@ -12,13 +12,13 @@
 import org.lcsim.event.ReconstructedParticle;
 import org.lcsim.event.Track;
 
-import org.lcsim.contrib.onoprien.util.ConstHep3Vector;
+import org.lcsim.contrib.onoprien.util.vector.ConstHep3Vector;
 
 /**
  * Class to represent a reconstructed particle produced by PFA.
  *
  * @author D. Onoprienko
- * @version $Id: CruxParticle.java,v 1.3 2009/03/04 03:29:58 onoprien Exp $
+ * @version $Id: CruxParticle.java,v 1.4 2009/04/06 19:49:24 onoprien Exp $
  */
 public class CruxParticle implements ReconstructedParticle {
   

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/itc
ClusterNodeHeprepConverter.java added at 1.1
diff -N ClusterNodeHeprepConverter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ClusterNodeHeprepConverter.java	6 Apr 2009 19:49:24 -0000	1.1
@@ -0,0 +1,105 @@
+package org.lcsim.contrib.onoprien.crux.itc;
+
+import java.awt.Color;
+import java.util.*;
+
+import hep.graphics.heprep.HepRepFactory;
+import hep.graphics.heprep.HepRepInstance;
+import hep.graphics.heprep.HepRepPoint;
+import hep.graphics.heprep.HepRepType;
+import hep.graphics.heprep.HepRepTypeTree;
+import hep.graphics.heprep.HepRepInstanceTree;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.util.heprep.ColorMap;
+import org.lcsim.util.heprep.HepRepCollectionConverter;
+import org.lcsim.util.heprep.LCSimHepRepConverter;
+import org.lcsim.util.heprep.RainbowColorMap;
+
+/**
+ *
+ * @author tonyj
+ * @version $Id: ClusterNodeHeprepConverter.java,v 1.1 2009/04/06 19:49:24 onoprien Exp $
+ */
+class ClusterNodeHeprepConverter implements HepRepCollectionConverter {
+
+  private Color[] colors;
+    
+  ClusterNodeHeprepConverter() {
+    ColorMap cm = new RainbowColorMap();
+    colors = new Color[20];
+    for (int i = 0; i < colors.length; i++) {
+      colors[i] = cm.getColor(((double) i) / colors.length, 1);
+    }
+    // Shuffle the elements in the array
+    Collections.shuffle(Arrays.asList(colors));
+  }
+
+  public boolean canHandle(Class k) {
+    return ClusterNode.class.isAssignableFrom(k);
+  }
+
+  public void convert(EventHeader event, List collection, HepRepFactory factory, HepRepTypeTree typeTree, HepRepInstanceTree instanceTree) {
+
+    LCMetaData meta = event.getMetaData(collection);
+    String name = meta.getName();
+    int flags = meta.getFlags();
+
+    HepRepType typeX = factory.createHepRepType(typeTree, name);
+    typeX.addAttValue("layer", LCSimHepRepConverter.HITS_LAYER);
+    typeX.addAttValue("drawAs", "Point");
+    typeX.addAttValue("color", Color.RED);
+    typeX.addAttValue("fill", true);
+    typeX.addAttValue("fillColor", Color.RED);
+    typeX.addAttValue("MarkName", "Box");
+    typeX.addAttDef("hits", "Number of hits", "physics", "");
+
+    int i = 0;
+
+    for (ClusterNode node : (List<ClusterNode>) collection) {
+
+      Color clusterColor = colors[i];
+      i = (i + 1) % colors.length;
+      double[] pos;// = rosary.getTrajectory().getPosition().v();
+      HepRepInstance instanceC = factory.createHepRepInstance(instanceTree, typeX);
+      //HepRepPoint cp = factory.createHepRepPoint(instanceC, pos[0], pos[1], pos[2]);
+
+      instanceC.addAttValue("drawAs", "Ellipsoid");
+      
+      instanceC.addAttValue("Radius", 1);
+      instanceC.addAttValue("Radius2", 1);
+      instanceC.addAttValue("Radius3", 1);
+      
+      instanceC.addAttValue("hits", node.getHits().size());
+
+      instanceC.addAttValue("MarkName", "Star");
+      instanceC.addAttValue("color", clusterColor);
+      instanceC.addAttValue("MarkSize", 10);
+
+      List<CalorimeterHit> hits = node.getHits();
+      for (CalorimeterHit hit : hits) {
+        // FixMe: What if hit doesn't have position?
+        double hitpos[] = null;
+        try {
+          hitpos = hit.getPosition();
+        } catch (Exception x) {
+        }
+
+        if (hitpos != null) {
+          pos = hit.getPosition();
+          HepRepInstance instanceX = factory.createHepRepInstance(instanceC, typeX);
+          instanceX.addAttValue("energy", hit.getRawEnergy());
+          instanceX.addAttValue("MarkSize", 5);
+          instanceX.addAttValue("color", (node.getType() == Node.Type.DOT) ? Color.RED : Color.BLUE);
+          instanceX.addAttValue("showparentattributes", true);
+          instanceX.addAttValue("pickparent", true);
+          HepRepPoint pp = factory.createHepRepPoint(instanceX, pos[0], pos[1], pos[2]);
+        }
+      }
+
+    }
+
+  }
+
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/itc
ClusterNode.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- ClusterNode.java	29 Mar 2009 23:44:19 -0000	1.1
+++ ClusterNode.java	6 Apr 2009 19:49:24 -0000	1.2
@@ -7,15 +7,13 @@
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
 
-import org.lcsim.contrib.onoprien.util.ConstHep3Vector;
-
-import org.lcsim.contrib.onoprien.crux.infrastructure.ITrack;
+import org.lcsim.contrib.onoprien.util.vector.ConstHep3Vector;
 
 /**
  * Class that represents a rosary node that contains calorimeter hits - either {@link Dot} or {@link Bead}.
  *
  * @author D. Onoprienko
- * @version $Id: ClusterNode.java,v 1.1 2009/03/29 23:44:19 onoprien Exp $
+ * @version $Id: ClusterNode.java,v 1.2 2009/04/06 19:49:24 onoprien Exp $
  */
 abstract public class ClusterNode extends Node {
 

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/itc
Node.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- Node.java	29 Mar 2009 23:44:19 -0000	1.1
+++ Node.java	6 Apr 2009 19:49:24 -0000	1.2
@@ -12,7 +12,7 @@
  * attached to a {@link Rosary} in a particular layer.
  *
  * @author D. Onoprienko
- * @version $Id: Node.java,v 1.1 2009/03/29 23:44:19 onoprien Exp $
+ * @version $Id: Node.java,v 1.2 2009/04/06 19:49:24 onoprien Exp $
  */
 abstract public class Node {
 
@@ -77,4 +77,10 @@
    * Returns <tt>true</tt> if this node is attached to at least one <tt>Rosary</tt>.
    */
   public boolean isAttached() {return ! _rosaries.isEmpty();}
+
+// -- Overriding Object :  -----------------------------------------------------
+
+  public String toString() {
+    return getType() + " at layer "+ getLayer();
+  }
 }

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/itc
Rosary.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- Rosary.java	29 Mar 2009 23:44:19 -0000	1.1
+++ Rosary.java	6 Apr 2009 19:49:24 -0000	1.2
@@ -3,25 +3,28 @@
 import java.util.*;
 
 import hep.physics.vec.Hep3Vector;
-import org.lcsim.contrib.onoprien.util.swim.Trajectory;
 
-import org.lcsim.contrib.onoprien.crux.infrastructure.CruxCluster;
-import org.lcsim.contrib.onoprien.crux.infrastructure.CruxParticle;
-import org.lcsim.contrib.onoprien.crux.infrastructure.ITrack;
+import org.lcsim.contrib.onoprien.util.swim.Trajectory;
 
 import static org.lcsim.contrib.onoprien.crux.itc.Node.Type.*;
 
 /**
  * Class that represents a rosary cluster.
  * <p>
- * <tt>Rosary</tt> is a list of {@link Node}, indexed from head to tail. The reconstructed
- * particle is assumed to propagate from head to tail of a <tt>Rosary</tt>. 
- * 
+ * <tt>Rosary</tt> is a list of {@link Node}, indexed from tail to head.
+ * <p>
+ * When the <tt>Rosary</tt> is being threaded, new nodes are added to the head. The
+ * hypothetic reconstructed particle propagation direction is assumed to be from
+ * tail to head if the threading direction is <tt>FORWARD</tt> (as returned by
+ * {@link #getThreadingDirection()}), and from head to tail if the threading direction
+ * is <tt>BACK</tt>. In a finished <tt>Rosary</tt> (threading direction is <tt>THREADED</tt>,
+ * the reconstructed particle is assumed to propagate from tail to head.
  *
  * @author D. Onoprienko
- * @version $Id: Rosary.java,v 1.1 2009/03/29 23:44:19 onoprien Exp $
+ * @version $Id: Rosary.java,v 1.2 2009/04/06 19:49:24 onoprien Exp $
  */
-public class Rosary extends CruxCluster {
+public class Rosary {
+//public class Rosary extends CruxCluster {
   
   public enum ThreadDirection {FORWARD, BACK, THREADED}
 
@@ -63,32 +66,45 @@
 
 // -- Getters :  ---------------------------------------------------------------
   
-  /** Returns the node at the specified position in this <tt>Rosary</tt>. */
+  /**
+   * Returns the node at the specified position in this <tt>Rosary</tt>.
+   * The <tt>Rosary</tt> is indexed from head to tail.
+   */
   public Node getNode(int index) {
     return _nodes.get(index);
   }
 
-  /** 
-   * Returns the first node in this <tt>Rosary</tt>.
-   * Returns <tt>null</tt> if this <tt>Rosary</tt> does not have any nodes.
+  /**
+   * Returns a list of nodes in this <tt>Rosary</tt> that belong to one of the specified types.
+   * The ordering is the same as in the Rosary (from tail to head).
+   * If no types are specified, all types of nodes are included.
    */
-  public Node getHeadNode() {
-    return (_nodes.isEmpty()) ? null : _nodes.get(0);
+  public List<Node> getNodes(Node.Type... types) {
+    if (types.length == 0) {
+      return Collections.unmodifiableList(_nodes);
+    } else {
+      EnumSet<Node.Type> set = EnumSet.copyOf(Arrays.asList(types));
+      ArrayList<Node> out = new ArrayList<Node>(_nodes.size());
+      for (Node node : _nodes) {
+        if (set.contains(node.getType())) {
+          out.add(node);
+        }
+      }
+      return out;
+    }
   }
-  
+
   /** 
-   * Returns the first node in this <tt>Rosary</tt> that belongs to one of the specified types.
-   * Returns <tt>null</tt> if this <tt>Rosary</tt> does not have nodes of these types.
+   * Returns the node closest to the tail of this <tt>Rosary</tt> that belongs to one of the specified types.
+   * Returns <tt>null</tt> if this <tt>Rosary</tt> does not have nodes of these types. If no types are
+   * specified, returns the node at the tail of this <tt>Rosary</tt>, regardless of its type.
    */
-  public Node getHeadNode(Node.Type type, Node.Type... types) {
-    ListIterator<Node> it = _nodes.listIterator();
+  public Node getTailNode(Node.Type... types) {
     if (types.length == 0) {
-      while (it.hasNext()) {
-        Node node = it.next();
-        if (node.getType() == type) return node;
-      }
+      return (_nodes.isEmpty()) ? null : _nodes.get(0);
     } else {
-      EnumSet<Node.Type> set = EnumSet.of(type, types);
+      ListIterator<Node> it = _nodes.listIterator();
+      EnumSet<Node.Type> set = EnumSet.copyOf(Arrays.asList(types));
       while (it.hasNext()) {
         Node node = it.next();
         if (set.contains(node.getType())) return node;
@@ -98,10 +114,11 @@
   }
 
   /**
-   * Returns fist <tt>numberOfNodes</tt> Nodes of one of the specified types, starting from the head of
-   * the Rosary. The ordering is the same as in the Rosary. If no types are specified, all types of nodes are included.
+   * Returns the first <tt>numberOfNodes</tt> nodes of one of the specified types, starting from
+   * the tail of this <tt>Rosary</tt>. The ordering is the same as in the <tt>Rosary</tt> (from tail to head).
+   * If no types are specified, all types of nodes are included.
    */
-  public ArrayList<Node> getHeadNodes(int numberOfNodes, Node.Type... types) {
+  public ArrayList<Node> getTailNodes(int numberOfNodes, Node.Type... types) {
     ArrayList<Node> out = new ArrayList<Node>(numberOfNodes);
     ListIterator<Node> it = _nodes.listIterator();
     if (types.length == 0) {
@@ -109,7 +126,7 @@
         out.add(it.next());
       }
     } else {
-      EnumSet<Node.Type> set = EnumSet.of(types[0], types);
+      EnumSet<Node.Type> set = EnumSet.copyOf(Arrays.asList(types));
       while (it.hasNext() && out.size() < numberOfNodes) {
         Node node = it.next();
         if (set.contains(node.getType())) out.add(node);
@@ -118,27 +135,18 @@
     return out;
   }
 
-  /** 
-   * Returns the last node in this <tt>Rosary</tt>.
-   * Returns <tt>null</tt> if this <tt>Rosary</tt> does not have any nodes.
-   */
-  public Node getTailNode() {
-    return (_nodes.isEmpty()) ? null : _nodes.get(_nodes.size()-1);
-  }
-  
-  /** 
-   * Returns the last node of one of the specified types in this <tt>Rosary</tt>.
-   * Returns <tt>null</tt> if this <tt>Rosary</tt> does not have nodes of the given types.
+  /**
+   * Returns the node closest to the head of this <tt>Rosary</tt> that belongs to one of the specified types.
+   * Returns <tt>null</tt> if this <tt>Rosary</tt> does not have nodes of these types. If no types are
+   * specified, returns the node at the head of this <tt>Rosary</tt> (last added, unless the
+   * threading direction has just been reversed), regardless of its type.
    */
-  public Node getTailNode(Node.Type type, Node.Type... types) {
-    ListIterator<Node> it = _nodes.listIterator(_nodes.size());
+  public Node getHeadNode(Node.Type... types) {
     if (types.length == 0) {
-      while (it.hasPrevious()) {
-        Node node = it.previous();
-        if (node.getType() == type) return node;
-      }
+      return (_nodes.isEmpty()) ? null : _nodes.get(_nodes.size()-1);
     } else {
-      EnumSet<Node.Type> set = EnumSet.of(type, types);
+      EnumSet<Node.Type> set = EnumSet.copyOf(Arrays.asList(types));
+      ListIterator<Node> it = _nodes.listIterator(_nodes.size());
       while (it.hasPrevious()) {
         Node node = it.previous();
         if (set.contains(node.getType())) return node;
@@ -148,19 +156,20 @@
   }
 
   /**
-   * Returns fist <tt>numberOfNodes</tt> Nodes of one of the specified types, starting from the tail of
-   * the Rosary. The ordering is the same as in the Rosary. If no types are specified, all types of nodes are included.
+   * Returns the first <tt>numberOfNodes</tt> nodes of one of the specified types, starting from
+   * the head of this <tt>Rosary</tt>. The ordering is the same as in the <tt>Rosary</tt> (from tail to head).
+   * If no types are specified, all types of nodes are included.
    */
-  public ArrayList<Node> getTailNodes(int numberOfNodes, Node.Type... types) {
+  public ArrayList<Node> getHeadNodes(int numberOfNodes, Node.Type... types) {
     ArrayList<Node> out = new ArrayList<Node>(numberOfNodes);
     ListIterator<Node> it = _nodes.listIterator(_nodes.size());
     if (types.length == 0) {
-      while (it.hasPrevious()) {
+      while (it.hasPrevious() && out.size() < numberOfNodes) {
         out.add(it.previous());
       }
     } else {
-      EnumSet<Node.Type> set = EnumSet.of(types[0], types);
-      while (it.hasPrevious()) {
+      EnumSet<Node.Type> set = EnumSet.copyOf(Arrays.asList(types));
+      while (it.hasPrevious() && out.size() < numberOfNodes) {
         Node node = it.previous();
         if (set.contains(node.getType())) out.add(node);
       }
@@ -196,28 +205,23 @@
     return iTail - iHead ;
   }
   
-  /** Returns the total number of nodes in this <tt>Rosary</tt>. */
-  public int getNodeCount() {
-    return _nodes.size();
-  }
-  
-  /** Returns the number of nodes that belong to one of the specified types in this <tt>Rosary</tt>. */
-  public int getNodeCount(Node.Type type, Node.Type... types) {
-    int out = 0;
-    ListIterator<Node> it = _nodes.listIterator();
+  /**
+   * Returns the number of nodes in this <tt>Rosary</tt> that belong to one of the specified types.
+   * If no types are specified, all nodes are counted.
+   */
+  public int getNodeCount(Node.Type... types) {
     if (types.length == 0) {
-      while (it.hasNext()) {
-        Node node = it.next();
-        if (node.getType() == type) out++ ;
-      }
+      return _nodes.size();
     } else {
-      EnumSet<Node.Type> set = EnumSet.of(type, types);
+      EnumSet<Node.Type> set = EnumSet.copyOf(Arrays.asList(types));
+      int out = 0;
+      ListIterator<Node> it = _nodes.listIterator();
       while (it.hasNext()) {
         Node node = it.next();
         if (set.contains(node.getType())) out++ ;
       }
+      return out;
     }
-    return out;
   }
   
   /** Returns the number of {@link Crack} objects at the tail of this <tt>Rosary</tt>. */
@@ -235,7 +239,7 @@
   
 // -- Modifiers :  -------------------------------------------------------------
 
-  /** Sets threading direction property. */
+  /** Sets threading direction flag. */
   public void setThreadingDirection(ThreadDirection direction) {
     _threadDir = direction;
   }
@@ -246,14 +250,16 @@
   }
   
   /**
-   * Reverses propagation direction associated with this <tt>Rosary</tt>.
+   * Reverses hypothetic reconstructed particle propagation direction associated with
+   * this <tt>Rosary</tt>. The head of the rosary becomes its tail. The threading direction
+   * flag is not changed.
    */
   public void reverseDirection() {
     Collections.reverse(_nodes);
     _trajectory = null;
   }
   
-  /** Adds the node to the tail of this <tt>Rosary</tt>. */
+  /** Adds the node to the head of this <tt>Rosary</tt>. */
   public void addNode(Node node) {
     _nodes.add(node);
     node.getRosaries().add(this);

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/itc
RosaryClusterer.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- RosaryClusterer.java	31 Mar 2009 03:55:35 -0000	1.3
+++ RosaryClusterer.java	6 Apr 2009 19:49:24 -0000	1.4
@@ -15,6 +15,7 @@
 import org.lcsim.contrib.onoprien.util.job.JobManager;
 import org.lcsim.contrib.onoprien.util.swim.Trajectory;
 
+import org.lcsim.contrib.onoprien.crux.diagnostics.RosarySlicer;
 import org.lcsim.contrib.onoprien.crux.geom.CalLayer;
 import org.lcsim.contrib.onoprien.crux.geom.CalGeometry;
 import org.lcsim.contrib.onoprien.crux.infrastructure.CruxCluster;
@@ -63,9 +64,10 @@
  * </dl>
  *
  * @author D. Onoprienko
- * @version $Id: RosaryClusterer.java,v 1.3 2009/03/31 03:55:35 onoprien Exp $
+ * @version $Id: RosaryClusterer.java,v 1.4 2009/04/06 19:49:24 onoprien Exp $
  */
-public class RosaryClusterer extends Driver implements Clusterer, JobEventListener {
+public class RosaryClusterer extends Driver implements JobEventListener {
+//public class RosaryClusterer extends Driver implements Clusterer, JobEventListener {
 
 // -- Private parts :  ---------------------------------------------------------
 
@@ -98,6 +100,9 @@
   protected ComputeTrajectory _computeTrajectory;
   protected FindDotsAndBeads _findDotsAndBeads;
 
+  public HashMap<Rosary, ArrayList<Hep3Vector>> display = new HashMap<Rosary, ArrayList<Hep3Vector>>();
+  public RosarySlicer slicer = new RosarySlicer();
+
 
 // -- Constructors and initialization :  ---------------------------------------
   
@@ -106,6 +111,8 @@
     JobManager jobMan = JobManager.defaultInstance();
     _geom = jobMan.get(CalGeometry.class);
     jobMan.addListener(this, _geom);
+    jobMan.registerHepRepConverter(new RosaryHeprepConverter());
+    jobMan.registerHepRepConverter(new ClusterNodeHeprepConverter());
   }
   
   public void detectorChanged(JobEvent jEvent) {
@@ -246,7 +253,7 @@
       hitMap = new CruxHitMap((Collection<CalorimeterHit>)o);
     }
 
-    List<Cluster> rosaries = createClusters(hitMap);
+    List<Rosary> rosaries = createClusters(hitMap);
     
     _inTracks = null;
     event.put(_outRosName, rosaries, Rosary.class, 0);
@@ -256,21 +263,21 @@
   
 // -- Implementing Clusterer :  ------------------------------------------------
   
-  public List<Cluster> createClusters(List<CalorimeterHit> hits) {
+  public List<Rosary> createClusters(List<CalorimeterHit> hits) {
     return createClusters((hits instanceof CruxHitMap) ? (CruxHitMap)hits : new CruxHitMap(hits));
   }
   
-  public List<Cluster> createClusters(Map<Long,CalorimeterHit> map) {
+  public List<Rosary> createClusters(Map<Long,CalorimeterHit> map) {
     return createClusters(new CruxHitMap(map));
   }
 
-  public List<Cluster> createClusters(Collection<CalorimeterHit> hits) {
+  public List<Rosary> createClusters(Collection<CalorimeterHit> hits) {
     return createClusters((hits instanceof CruxHitMap) ? (CruxHitMap)hits : new CruxHitMap(hits));
   }
 
 // -- Actual clustering algorithm :  -------------------------------------------
 
-  public List<Cluster> createClusters(CruxHitMap hitMap) {
+  public List<Rosary> createClusters(CruxHitMap hitMap) {
 
     if (_inParticles != null) {
       for (CruxParticle p : _inParticles) {
@@ -285,23 +292,17 @@
     _findDotsAndBeads.findDotsAndBeads(hitMap);
     _layerDB.initialize();
 
+    slicer.fillDotsBeads(_layerDB);
+
     if (_saveDotsBeads && _event != null) {
-      ArrayList<Cluster> dots = new ArrayList<Cluster>();
-      ArrayList<Cluster> beads = new ArrayList<Cluster>();
+      ArrayList<ClusterNode> dots = new ArrayList<ClusterNode>();
+      ArrayList<ClusterNode> beads = new ArrayList<ClusterNode>();
       for (LayerData layerData : _layerDB) {
-        for (Dot dot : layerData.dots) {
-          CruxCluster cluster = new CruxCluster();
-          dots.add(cluster);
-          cluster.addHits(dot.getHits());
-        }
-        for (Bead bead : layerData.beads) {
-          CruxCluster cluster = new CruxCluster();
-          beads.add(cluster);
-          cluster.addHits(bead.getHits());
-        }
+        dots.addAll(layerData.dots);
+        beads.addAll(layerData.beads);
       }
-      _event.put("Dots", dots, Cluster.class, 0);
-      _event.put("Beads", beads, Cluster.class, 0);
+      _event.put("Dots", dots, ClusterNode.class, 0);
+      _event.put("Beads", beads, ClusterNode.class, 0);
     }
 
     // Create Rosaries from tracks :
@@ -312,6 +313,8 @@
         seedRosaries.add(_seedFromTrack.seedFromTrack(track));
       }
     }
+
+    log("Created "+ seedRosaries.size() +" from tracks");
     
     // Thread Rosaries seeded from tracks :
 
@@ -321,6 +324,8 @@
     // Loop over seed layers, seeding new Rosaries and threading them
 
     List<CalLayer> seedLayers = _chooseSeedLayers.chooseSeedLayers();
+
+    log("Using "+ seedLayers.size() +" seed layers");
     
     for (CalLayer layer : seedLayers) {
       LayerData layerData = _layerDB.get(layer);
@@ -335,10 +340,12 @@
     // Clean up
     
     _layerDB = null;
+
+    slicer.saveToAida();
     
     // Return final list of Rosaries
     
-    return new ArrayList<Cluster>(threadedRosaries);
+    return new ArrayList<Rosary>(threadedRosaries);
   }
 
   /**
@@ -347,8 +354,11 @@
   protected void thread(Queue<Rosary> seeds, List<Rosary> threaded) {
     while (! seeds.isEmpty()) {
       Rosary rosary = seeds.remove();
+      log("--- Threading Rosary "+ rosary);
+      display.put(rosary,new ArrayList<Hep3Vector>());
       while (_step.step(rosary, seeds)) {}
       if (_acceptThreadedRosary.acceptThreadedRosary(rosary)) threaded.add(rosary);
+      _event.put(rosary.toString(), display.get(rosary));
     }
   }
 
@@ -370,6 +380,10 @@
     return _layerDB;
   }
 
+  final public EventHeader getEvent() {
+    return _event;
+  }
+
   final public DistanceToPointNodeComparator getDistanceToPointNodeComparator(Hep3Vector point) {
     return new DistanceToPointNodeComparator(point);
   }

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/itc
RosaryHeprepConverter.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- RosaryHeprepConverter.java	29 Mar 2009 23:44:19 -0000	1.1
+++ RosaryHeprepConverter.java	6 Apr 2009 19:49:24 -0000	1.2
@@ -10,7 +10,6 @@
 import hep.graphics.heprep.HepRepTypeTree;
 import hep.graphics.heprep.HepRepInstanceTree;
 import org.lcsim.event.CalorimeterHit;
-import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.EventHeader.LCMetaData;
 import org.lcsim.spacegeom.CartesianPoint;
@@ -23,7 +22,7 @@
 /**
  *
  * @author tonyj
- * @version $Id: RosaryHeprepConverter.java,v 1.1 2009/03/29 23:44:19 onoprien Exp $
+ * @version $Id: RosaryHeprepConverter.java,v 1.2 2009/04/06 19:49:24 onoprien Exp $
  */
 class RosaryHeprepConverter implements HepRepCollectionConverter {
 
@@ -56,8 +55,8 @@
     typeX.addAttValue("fill", true);
     typeX.addAttValue("fillColor", Color.RED);
     typeX.addAttValue("MarkName", "Box");
-    typeX.addAttDef("energy", "Hit Energy", "physics", "");
-    typeX.addAttDef("cluster", "Cluster Energy", "physics", "");
+    typeX.addAttDef("dots", "Number of Dots", "physics", "");
+    typeX.addAttDef("beads", "Number of Beads", "physics", "");
 
     int i = 0;
 
@@ -65,49 +64,48 @@
 
       Color clusterColor = colors[i];
       i = (i + 1) % colors.length;
-      double[] pos = rosary.getPosition();
+      double[] pos;// = rosary.getTrajectory().getPosition().v();
       HepRepInstance instanceC = factory.createHepRepInstance(instanceTree, typeX);
-      HepRepPoint cp = factory.createHepRepPoint(instanceC, pos[0], pos[1], pos[2]);
+      //HepRepPoint cp = factory.createHepRepPoint(instanceC, pos[0], pos[1], pos[2]);
 
-      SpacePoint point = new CartesianPoint(pos);
       instanceC.addAttValue("drawAs", "Ellipsoid");
-      // TODO Change from fixed size to reflect true cluster dimensions.
-      instanceC.addAttValue("Radius", 5);
-      instanceC.addAttValue("Radius2", 5);
-      instanceC.addAttValue("Radius3", 20);
-      //TODO Change to use cluster direction instead of connecting origin to centroid.
-      double theta = point.theta();
-      double phi = point.phi();
-      instanceC.addAttValue("Phi", phi);
-      instanceC.addAttValue("Theta", theta);
+      
+      instanceC.addAttValue("Radius", 1);
+      instanceC.addAttValue("Radius2", 1);
+      instanceC.addAttValue("Radius3", 1);
+      
+      instanceC.addAttValue("dots", rosary.getNodeCount(Node.Type.DOT));
+      instanceC.addAttValue("beads", rosary.getNodeCount(Node.Type.BEAD));
 
       instanceC.addAttValue("MarkName", "Star");
-      instanceC.addAttValue("cluster", rosary.getEnergy());
       instanceC.addAttValue("color", clusterColor);
       instanceC.addAttValue("MarkSize", 10);
 
-      List<CalorimeterHit> hits = rosary.getCalorimeterHits();
-      if (hits != null) {
+      for (Node node : rosary.getNodes(Node.Type.DOT, Node.Type.BEAD)) {
+        List<CalorimeterHit> hits = node.getHits();
         for (CalorimeterHit hit : hits) {
           // FixMe: What if hit doesn't have position?
           double hitpos[] = null;
           try {
             hitpos = hit.getPosition();
-          } catch (Exception x) {}
+          } catch (Exception x) {
+          }
 
           if (hitpos != null) {
             pos = hit.getPosition();
             HepRepInstance instanceX = factory.createHepRepInstance(instanceC, typeX);
             instanceX.addAttValue("energy", hit.getRawEnergy());
             instanceX.addAttValue("MarkSize", 5);
-            //instanceX.addAttValue("cluster",cluster.getEnergy());
-            instanceX.addAttValue("color", clusterColor);
+            instanceX.addAttValue("color", (node.getType() == Node.Type.DOT) ? Color.RED : Color.BLUE);
             instanceX.addAttValue("showparentattributes", true);
             instanceX.addAttValue("pickparent", true);
             HepRepPoint pp = factory.createHepRepPoint(instanceX, pos[0], pos[1], pos[2]);
           }
         }
       }
+
     }
+
   }
+
 }

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/diagnostics
PropagationTest.java added at 1.1
diff -N PropagationTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ PropagationTest.java	6 Apr 2009 19:49:24 -0000	1.1
@@ -0,0 +1,103 @@
+package org.lcsim.contrib.onoprien.crux.diagnostics;
+
+import java.util.*;
+
+import hep.physics.vec.Hep3Vector;
+import org.lcsim.event.EventHeader;
+
+import org.lcsim.contrib.onoprien.util.constants.Units;
+import org.lcsim.contrib.onoprien.util.job.Driver;
+import org.lcsim.contrib.onoprien.util.job.JobEvent;
+import org.lcsim.contrib.onoprien.util.job.JobEventListener;
+import org.lcsim.contrib.onoprien.util.job.JobManager;
+import org.lcsim.contrib.onoprien.util.swim.Trajectory;
+
+import org.lcsim.contrib.onoprien.crux.SiD02Geometry;
+import org.lcsim.contrib.onoprien.crux.analysis.CheatTrackFinderDriver;
+import org.lcsim.contrib.onoprien.crux.analysis.DefinitionCrux;
+import org.lcsim.contrib.onoprien.crux.analysis.RecType;
+import org.lcsim.contrib.onoprien.crux.geom.CalGeometry;
+import org.lcsim.contrib.onoprien.crux.geom.CalLayer;
+import org.lcsim.contrib.onoprien.crux.infrastructure.ITrack;
+import org.lcsim.contrib.onoprien.crux.mctruth.MCTruthDriverCrux;
+import org.lcsim.contrib.onoprien.crux.recon.CalorimeterDriver;
+
+/**
+ *
+ *
+ * @author D. Onoprienko
+ * @version $Id: PropagationTest.java,v 1.1 2009/04/06 19:49:24 onoprien Exp $
+ */
+public class PropagationTest extends Driver implements JobEventListener {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  CalGeometry _geom;
+
+// -- Constructors and initialization :  ---------------------------------------
+
+  public PropagationTest() {
+
+    _geom = new SiD02Geometry();
+    JobManager.defaultInstance().addListener(this, _geom);
+
+    MCTruthDriverCrux mcTruthDriver = new MCTruthDriverCrux();
+    mcTruthDriver.set("CALORIMETER_HITS", "CruxCalorimeterHits");
+    add(mcTruthDriver);
+
+    // Tracker hits processing --> "VSTrackerClusters" :
+
+    add(new org.lcsim.contrib.onoprien.vsegment.ExampleDriverSiD02());
+
+    // Calorimeter hits processing --> "CruxCalorimeterHits" :
+
+    CalorimeterDriver calDriver = new CalorimeterDriver();
+    calDriver.set("INPUT_HITS", "EcalBarrDigiHits","EcalEndcapDigiHits","HcalBarrDigiHits","HcalEndcapDigiHits");
+    calDriver.set("OUTPUT_HITS", "CruxCalorimeterHits");
+    calDriver.set("GEOMETRY", _geom);
+    add(calDriver);
+
+    // Track finder (cheater) --> "Tracks" :
+
+    CheatTrackFinderDriver trackFinder = new CheatTrackFinderDriver();
+    trackFinder.set("HIT_COLLECTIONS", "VSTrackerClusters");
+    trackFinder.set("TRACK_LIST", "Tracks");
+
+    DefinitionCrux def = new DefinitionCrux("std");
+    //def.setCut(RecType.TRACK, "CHARGED", true);
+    def.setCut(RecType.TRACK, "PT", .2*Units.GeV);
+    //def.setCut(RecType.TRACK, "MIN_TRACK_HIT_LAYERS", 3);
+    trackFinder.set("DEFINITION", def);
+
+    add(trackFinder);
+  }
+  
+  public  void detectorChanged(JobEvent jEvent) {
+  }
+
+// -- Event processing :  ------------------------------------------------------
+
+  public void process(EventHeader event) {
+
+    super.process(event);
+
+    int iTrack = 0;
+
+    List<ITrack> tracks = event.get(ITrack.class, "Tracks");
+    for (ITrack track : tracks) {
+      ArrayList<Hep3Vector> points = new ArrayList<Hep3Vector>();
+      String name = iTrack++ + track.getMCParticle().getType().getName();
+      log("Track "+ name);
+      Trajectory traj = track.getTrajectory(ITrack.Point.START);
+      CalLayer layer = _geom.propagateFromTracker(traj);
+      while (layer != null) {
+        log(" New layer "+ layer);
+        points.add(traj.getPosition());
+        layer = _geom.propagateToNextLayer(layer, traj);
+      }
+      event.put(name, points, Hep3Vector.class, 0);
+    }
+    
+  }
+
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/crux/diagnostics
RosarySlicer.java added at 1.1
diff -N RosarySlicer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ RosarySlicer.java	6 Apr 2009 19:49:24 -0000	1.1
@@ -0,0 +1,135 @@
+package org.lcsim.contrib.onoprien.crux.diagnostics;
+
+import java.util.*;
+
+import hep.aida.*;
+import hep.physics.vec.Hep3Vector;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.util.aida.AIDA;
+
+import org.lcsim.contrib.onoprien.util.job.JobManager;
+
+import org.lcsim.contrib.onoprien.crux.geom.CalLayer;
+import org.lcsim.contrib.onoprien.crux.itc.Bead;
+import org.lcsim.contrib.onoprien.crux.itc.Dot;
+import org.lcsim.contrib.onoprien.crux.itc.LayerData;
+import org.lcsim.contrib.onoprien.crux.itc.LayerDataBase;
+
+/**
+ *
+ *
+ * @author D. Onoprienko
+ * @version $Id: RosarySlicer.java,v 1.1 2009/04/06 19:49:24 onoprien Exp $
+ */
+public class RosarySlicer {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  private HashMap<CalLayer, Slice> _map;
+
+// -- Constructors and initialization :  ---------------------------------------
+
+// -- Fill vector lists :  -----------------------------------------------------
+
+  public void fillDotsBeads(LayerDataBase db) {
+    JobManager.defaultInstance().getAIDA().clearAll();
+    _map = new HashMap<CalLayer, Slice>();
+    for (LayerData data : db) {
+      Slice slice = new Slice(data.cruxLayer);
+      _map.put(data.cruxLayer, slice);
+      for (Dot dot : data.dots) {
+        for (CalorimeterHit hit : dot.getHits()) {
+          slice.dots.add(hit.getPositionVec());
+        }
+      }
+      for (Bead bead : data.beads) {
+        for (CalorimeterHit hit : bead.getHits()) {
+          slice.beads.add(hit.getPositionVec());
+        }
+      }
+      slice.decoder = data.decoder;
+    }
+  }
+
+  public void fillTrajectory(Hep3Vector pos, CalLayer layer, boolean findCell) {
+    Slice slice = _map.get(layer);
+    slice.tPoints.add(pos);
+    if (findCell) {
+      long cellID = slice.decoder.findCellContainingXYZ(pos);
+      slice.decoder.setID(cellID);
+      slice.tCells.add(slice.decoder.getPositionVector());
+    }
+  }
+
+
+// -- Dumping data into AIDA :  ------------------------------------------------
+
+  public void saveToAida() {
+
+    AIDA aida = JobManager.defaultInstance().getAIDA();
+    IAnalysisFactory af = aida.analysisFactory();
+    ITree tree = aida.tree();
+    IDataPointSetFactory dpsf   = af.createDataPointSetFactory(tree);
+
+    for (Slice slice : _map.values()) {
+
+      boolean isBarrel = slice.decoder.getBarrelEndcapFlag().isBarrel();
+
+      IDataPointSet dps = dpsf.create(slice.layer.toString()+" Dots", 2);
+      for (Hep3Vector pos : slice.dots) {
+        double x = (isBarrel) ? Math.atan2(Math.hypot(pos.x(), pos.y()), pos.z()) : pos.x() ;
+        double y = (isBarrel) ? Math.atan2(pos.y(), pos.x()) : pos.y() ;
+        IDataPoint point = dps.addPoint();
+        point.coordinate(0).setValue(x);
+        point.coordinate(1).setValue(y);
+      }
+
+      dps = dpsf.create(slice.layer.toString()+" Beads", 2);
+      for (Hep3Vector pos : slice.beads) {
+        double x = (isBarrel) ? Math.atan2(Math.hypot(pos.x(), pos.y()), pos.z()) : pos.x() ;
+        double y = (isBarrel) ? Math.atan2(pos.y(), pos.x()) : pos.y() ;
+        IDataPoint point = dps.addPoint();
+        point.coordinate(0).setValue(x);
+        point.coordinate(1).setValue(y);
+      }
+
+      dps = dpsf.create(slice.layer.toString()+" Trajectory", 2);
+      for (Hep3Vector pos : slice.tPoints) {
+        double x = (isBarrel) ? Math.atan2(Math.hypot(pos.x(), pos.y()), pos.z()) : pos.x() ;
+        double y = (isBarrel) ? Math.atan2(pos.y(), pos.x()) : pos.y() ;
+        IDataPoint point = dps.addPoint();
+        point.coordinate(0).setValue(x);
+        point.coordinate(1).setValue(y);
+      }
+
+      dps = dpsf.create(slice.layer.toString()+" TrajCells", 2);
+      for (Hep3Vector pos : slice.tCells) {
+        double x = (isBarrel) ? Math.atan2(Math.hypot(pos.x(), pos.y()), pos.z()) : pos.x() ;
+        double y = (isBarrel) ? Math.atan2(pos.y(), pos.x()) : pos.y() ;
+        IDataPoint point = dps.addPoint();
+        point.coordinate(0).setValue(x);
+        point.coordinate(1).setValue(y);
+      }
+
+    }
+
+    _map = null;
+  }
+
+// -- Per layer data :  --------------------------------------------------------
+
+  private class Slice {
+
+    Slice(CalLayer layer) {this.layer = layer;}
+
+    CalLayer layer;
+    IDDecoder decoder;
+
+    ArrayList<Hep3Vector> hits = new ArrayList<Hep3Vector>();
+    ArrayList<Hep3Vector> dots = new ArrayList<Hep3Vector>();
+    ArrayList<Hep3Vector> beads = new ArrayList<Hep3Vector>();
+    ArrayList<Hep3Vector> tPoints = new ArrayList<Hep3Vector>();
+    ArrayList<Hep3Vector> tCells = new ArrayList<Hep3Vector>();
+  }
+}
CVSspam 0.2.8