Print

Print


Commit in lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom on MAIN
calorimeter/CalGeometry.java+278added 1.1
           /CalLayer.java+94added 1.1
           /CalModule.java+145added 1.1
           /package-info.java+4added 1.1
calorimeter/lib/SiD02Geometry.java+254added 1.1
               /package-info.java+11added 1.1
tracker/AbstractSegmenter.java+123added 1.1
       /Direction.java+26added 1.1
       /ForwardingSegmenter.java+179added 1.1
       /RegionSegmenter.java+154added 1.1
       /SegmentationManager.java+260added 1.1
       /Segmenter.java+51added 1.1
       /Sensor.java+178added 1.1
       /SensorConverter.java+81added 1.1
       /SensorType.java+74added 1.1
       /package-info.java+4added 1.1
+1916
16 added files
New MC Truth access package to support CAT analysis.
Cleanup and refactoring (in progress). 
Streamlined/flexible geometry access.
Skeleton CAT drivers (testing).
Miscelaneous additions/fixes.

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/calorimeter
CalGeometry.java added at 1.1
diff -N CalGeometry.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CalGeometry.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,278 @@
+package org.lcsim.contrib.onoprien.geom.calorimeter;
+
+import java.util.*;
+
+import hep.physics.vec.Hep3Vector;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IGeometryInfo;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Tube;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.Detector;
+
+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.Intersection;
+import org.lcsim.contrib.onoprien.util.swim.Trajectory;
+import org.lcsim.contrib.onoprien.util.swim.Surface;
+import org.lcsim.contrib.onoprien.util.swim.ZCylinder;
+import org.lcsim.contrib.onoprien.util.swim.ZDisk;
+
+/**
+ * Provides various calorimeter geometry related services to other classes.
+ * Singleton of this class is available at run time through {@link JobManager} by
+ * calling <tt>JobManager.defaultInstance().get(CalGeometry.class)</tt>.
+ * <p>
+ * An object of a concrete extension of this class must be instantiated and registered with the
+ * {@link JobManager}. Usually, this is done by passing the <tt>CalGeometry</tt> instance to
+ * {@link org.lcsim.contrib.onoprien.crux.recon.CalorimeterDriver}.
+ * <p>
+ * The extending class must implement abstract methods {@link #getModules()},
+ * {@link #nextLayers(Trajectory) nextLayers(Trajectory)}, and
+ * {@link #nextLayers(CalLayer, Trajectory) nextLayers(CalLayer, Trajectory)}, dividing
+ * the calorimeter into modules and defining neighbor relations between them. If a subclass
+ * overrides {@link #detectorChanged(JobEvent) detectorChanged(JobEvent)}, it should call
+ * <tt>super.detectorChanged(JobEvent)</tt> after its own initialization. 
+ * <p>
+ * Simple generic implementation capable of handling SiD-like geometries with cylindrical
+ * calorimeters is available - see {@link SiD02Geometry}.
+ * 
+ * @author D. Onoprienko
+ * @version $Id: CalGeometry.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+abstract public class CalGeometry implements JobEventListener {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  private Detector _detector;
+  private HashMap<IDetectorElement, CalLayer> _de2cl;
+  
+// -- Constructors and initialization :  ---------------------------------------
+  
+  public CalGeometry() {
+    JobManager.defaultInstance().addListener(this);
+  }
+
+  public void detectorChanged(JobEvent jEvent) {
+    _detector = jEvent.getDetector();
+    _de2cl = new HashMap<IDetectorElement, CalLayer>();
+    for (CalModule module : getModules()) {
+      for (CalLayer layer : module.getLayers()) {
+        _de2cl.put(layer.getDetectorElement(), layer);
+      }
+    }
+    //printModules();
+  }
+
+
+// -- Abstract methods :  ------------------------------------------------------
+  
+  /** Returns an unmodifiable list of calorimeter modules, ordered by module ID. */
+  abstract public List<CalModule> getModules();
+
+  /**
+   * Returns the next layer the specified trajectory is most likely to cross after coming out of the
+   * specified layer. The origin of the trajectory should belong to the specified layer - no checking is done.
+   */
+  abstract public CalLayer nextLayer(CalLayer layer, Trajectory trajectory);
+
+  /**
+   * Returns the next layer the specified trajectory is most likely to cross.
+   */
+  abstract public CalLayer nextLayer(Trajectory trajectory);
+
+  /**
+   * Returns a list of layers the specified trajectory might cross after coming out of the
+   * given layer - more likely first (but excluding the most likely one that would be returned
+   * by <tt>nextLayer</tt>). The origin of the trajectory should belong to the
+   * specified layer - no checking is done.
+   */
+  abstract public List<CalLayer> nextLayers(CalLayer layer, Trajectory trajectory);
+
+  /**
+   * Returns a list of layers the specified trajectory might cross next - more likely first
+   * (but excluding the most likely one that would be returned by <tt>nextLayer</tt>).
+   */
+  abstract public List<CalLayer> nextLayers(Trajectory trajectory);
+
+
+// -- Getters :  ---------------------------------------------------------------
+
+  /** Returns currently used <tt>Detector</tt> object. */
+  public Detector getDetector() {
+    return _detector;
+  }
+  
+  /** Returns calorimeter module the given hit belongs to. */
+  public CalModule getModule(CalorimeterHit hit) {
+    return getLayer(hit).getModule();
+  }
+
+  /** Returns calorimeter layer the specified hit belongs to. */
+  public CalLayer getLayer(CalorimeterHit hit) {
+    return getLayer(hit.getDetectorElement());
+  }
+
+  
+// -- Trajectory propagation :  ------------------------------------------------
+
+  /**
+   * Propagates the given trajectory to the given calorimeter layer.
+   * Returns the point where the trajectory intersects the layer's reference surface.
+   * Origin of the supplied <tt>Trajectory</tt> is set to that point.
+   * If the trajectory does not cross the specified layer, <tt>null</tt> is returned
+   * and the trajectory is not changed.
+   */
+  public Hep3Vector propagateToLayer(Trajectory trajectory, CalLayer layer) {
+    Surface refSurface = layer.getReferenceSurface();
+    Intersection inter = refSurface.intersect(trajectory);
+    if (inter.hasNext()) {
+      trajectory.swim(inter.getPathLength());
+      return trajectory.getPosition();
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Propagates the given trajectory from the specified layer to the next calorimeter layer it crosses.
+   * <tt>CalLayer</tt> object associated with that layer is returned, and
+   * the origin of the supplied <tt>Trajectory</tt> is set to a point where it
+   * crosses that layer's reference surface. If the trajectory leaves the calorimeter,
+   * <tt>null</tt> is returned and the trajectory is not changed.
+   */
+  public CalLayer propagateToNextLayer(CalLayer currentLayer, Trajectory trajectory) {
+
+    // Try immediate neighbor
+
+    CalLayer immediateNeighbor = (currentLayer == null) ? nextLayer(trajectory) : nextLayer(currentLayer, trajectory);
+    if (immediateNeighbor != null) {
+      Hep3Vector pos = propagateToLayer(trajectory, immediateNeighbor);
+      if (pos != null) return immediateNeighbor;
+    }
+
+    // Try others
+
+    List<CalLayer> nextLayers = (currentLayer == null) ? nextLayers(trajectory) : nextLayers(currentLayer, trajectory);
+    double sNext = Double.MAX_VALUE;
+    CalLayer nextLayer = null;
+    for (CalLayer layer : nextLayers) {
+      Intersection inter = trajectory.intersect(layer.getReferenceSurface());
+      if (inter.hasNext()) {
+        double s = inter.getPathLength();
+        if (s < sNext) {
+          sNext = s;
+          nextLayer = layer;
+        }
+      }
+    }
+    if (nextLayer == null) {
+      return null;
+    } else {
+      trajectory.swim(sNext);
+      return nextLayer;
+    }
+
+  }
+
+  /**
+   * Propagates the given trajectory from outside the calorimeter to its entry layer.
+   * <tt>CalLayer</tt> object associated with that layer is returned, and
+   * the origin of the supplied <tt>Trajectory</tt> is set to a point where it
+   * crosses that layer's reference surface. The origin of the specified trajectory
+   * is assumed to be inside the tracker volume, no checking is done. If the trajectory
+   * does not enter calorimeter, <tt>null</tt> is returned and the trajectory is not changed.
+   */
+  public CalLayer propagateFromTracker(Trajectory trajectory) {
+    double sNext = Double.MAX_VALUE;
+    CalLayer nextLayer = null;
+    for (CalModule module : getModules()) {
+      if (module.isEntry()) {
+        CalLayer layer = module.firstLayer();
+        Intersection inter = trajectory.intersect(layer.getReferenceSurface());
+        if (inter.hasNext()) {
+          double s = inter.getPathLength();
+          if (s < sNext) {
+            sNext = s;
+            nextLayer = layer;
+          }
+        }
+      }
+    }
+    if (nextLayer == null) {
+      return null;
+    } else {
+      trajectory.swim(sNext);
+      return nextLayer;
+    }
+  }
+
+  /**
+   * Propagates the given trajectory to the next calorimeter layer it crosses.
+   * <tt>CalLayer</tt> object associated with that layer is returned, and
+   * the origin of the supplied <tt>Trajectory</tt> is set to a point where it
+   * crosses that layer's reference surface. If the trajectory does not cross any
+   * calorimeter layers, <tt>null</tt> is returned and the trajectory is not changed.
+   */
+  public CalLayer propagateToNextLayer(Trajectory trajectory) {
+    return propagateToNextLayer(null, trajectory);
+  }
+  
+// -- Point to layer projection :  ---------------------------------------------
+  
+  public Hep3Vector getClosestPointOnLayer(Hep3Vector point, CalLayer layer) {
+    return layer.getReferenceSurface().project(point);
+  }
+
+
+// -- Protected helper methods :  ----------------------------------------------
+
+  protected CalLayer getLayer(IDetectorElement de) {
+    return _de2cl.get(de);
+  }
+
+  /**
+   * Creates and returns reference surface object corresponding to the specified detector element.
+   */
+  protected Surface createReferenceSurface(IDetectorElement detEl) {
+    IGeometryInfo gInfo = detEl.getGeometry();
+    ISolid solid = gInfo.getLogicalVolume().getSolid();
+    if (solid instanceof Tube) {
+      Tube tube = (Tube) solid;
+      double rMin = tube.getInnerRadius();
+      double rMax = tube.getOuterRadius();
+      double zHalf = tube.getZHalfLength();
+      Hep3Vector pos = gInfo.getPosition();
+      double z = pos.z();
+      if (pos.x() > 0.001 || pos.y() > 0.001) {
+        throw new IllegalArgumentException("Cannot create reference surface for Tube at position "+ pos);
+      }
+      if (Math.abs(z)  < zHalf) { // barrel cylinder
+        return new ZCylinder((rMin+rMax)/2., zHalf);
+      } else { // endcap disk
+        return new ZDisk(z, rMin, rMax);
+      }
+    } else {
+      throw new IllegalArgumentException("Creating reference surfaces for solids other than Tube is not implemented");
+    }
+  }
+
+// -- Diagnostics :  -----------------------------------------------------------
+
+  private void printModules() {
+    System.out.println("");
+    System.out.println("Modules");
+    for (CalModule module : getModules()) {
+      System.out.println("");
+      System.out.println("Module "+ module.getName() +
+              " subd "+ module.getSubdetector().getName() +" att "+ module.getAttributes());
+      System.out.println("");
+      for (CalLayer layer : module.getLayers()) {
+        System.out.println("Layer "+ layer.getLayerID() +" ordinal "+ layer.getLayerOrdinal() +
+                " decoded "+ layer.getLayerDecoded() +" de "+ layer.getDetectorElement().getName());
+      }
+    }
+  }
+
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/calorimeter
CalLayer.java added at 1.1
diff -N CalLayer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CalLayer.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,94 @@
+package org.lcsim.contrib.onoprien.geom.calorimeter;
+
+import org.lcsim.detector.IDetectorElement;
+
+import org.lcsim.contrib.onoprien.util.job.JobManager;
+import org.lcsim.contrib.onoprien.util.swim.Surface;
+
+/**
+ * Class that represents a layer inside a calorimeter module.
+ * 
+ * @author D. Onoprienko
+ * @version $Id: CalLayer.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public class CalLayer implements Comparable<CalLayer> {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  private CalModule _module;
+  private int _decoded;
+  private int _id;
+  private int _ordinal;
+  private IDetectorElement _detEl;
+  private Surface _refSurf;
+
+
+// -- Constructors :  ----------------------------------------------------------
+  
+  public CalLayer(CalModule module, IDetectorElement detectorElement, int layerOrdinal, int layerID, int layerDecoded) {
+    _module = module;
+    _ordinal = layerOrdinal;
+    _detEl = detectorElement;
+    _decoded = layerDecoded;
+    _id = layerID;
+    _refSurf = JobManager.defaultInstance().get(CalGeometry.class).createReferenceSurface(detectorElement);
+  }
+
+
+// -- Getters :  ---------------------------------------------------------------
+  
+  /** Returns calorimeter module this layer belongs to. */
+  public CalModule getModule() {
+    return _module;
+  }
+  
+  /** Returns reference surface of this layer. */
+  public Surface getReferenceSurface() {
+    return _refSurf;
+  }
+  
+  /** 
+   * Returns layer number as reported by {@link IDDecoder} for hits in this layer.
+   * Note that layers in a module are not necessarily numbered starting from zero.
+   */
+  public int getLayerDecoded() {
+    return _decoded;
+  }
+  
+  /** 
+   * Returns global layer ID (unique within the detector).
+   * IDs for all <tt>CruxCalLayers</tt> in the detector form a continuous sequence 
+   * starting with 0, in the increasing module ID order (increasing layer number inside
+   * modules).
+   */
+  public int getLayerID() {
+    return _id;
+  }
+  
+  /**
+   * Returns layer position in a module, numbered from inside to outside, starting from zero.
+   */
+  public int getLayerOrdinal() {
+    return _ordinal;
+  }
+  
+  /** Returns <tt>DetectorElement</tt> associated with this layer. */
+  public IDetectorElement getDetectorElement() {
+    return _detEl;
+  }
+  
+  
+// -- Ordering :  --------------------------------------------------------------
+  
+  /** Defines natural ordering of layers (increasing ID order). */
+  public int compareTo(CalLayer layer) {
+    return _id - layer._id;
+  }
+
+
+// -- Overriding Object :  -----------------------------------------------------
+
+  public String toString() {
+    return "CalLayer:" + _detEl.getName();
+  }
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/calorimeter
CalModule.java added at 1.1
diff -N CalModule.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CalModule.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,145 @@
+package org.lcsim.contrib.onoprien.geom.calorimeter;
+
+import java.util.*;
+
+import org.lcsim.geometry.Subdetector;
+
+/**
+ * Class to represent a part of the calorimeter.
+ * 
+ * @author D. Onoprienko
+ * @version $Id: CalModule.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public class CalModule {
+  
+  public enum Attribute {ECAL, HCAL, BARREL, ENDCAP, SOUTH, NORTH, ENTRY, EXIT}
+  
+// -- Constructors and initialization :  ---------------------------------------
+  
+  public CalModule(String name, EnumSet<Attribute> attributes, String subdetectorName) {
+    _name = name;
+    _attributes = attributes;
+    _sdName = subdetectorName;
+  }
+
+  public void initialize(int moduleID, Subdetector subDet, List<CalLayer> layers) {
+    _id = moduleID;
+    _sd = subDet;
+    _layers = new ArrayList<CalLayer>(layers);
+  }
+  
+// -- Getters :  ---------------------------------------------------------------
+  
+  /** Returns module ID - unique within the detector. */
+  public int getID() {
+    return _id;
+  }
+  
+  /** Returns module name - unique within the detector. */
+  public String getName() {
+    return _name;
+  }
+  
+  /**  Returns set of attributes associated with this module. */
+  public EnumSet<Attribute> getAttributes() {
+    return _attributes;
+  }
+  
+  public boolean isECal() {
+    return _attributes.contains(Attribute.ECAL);
+  }
+  
+  public boolean isHCal() {
+    return _attributes.contains(Attribute.HCAL);
+  }
+  
+  public boolean isBarrel() {
+    return _attributes.contains(Attribute.BARREL);
+  }
+  
+  public boolean isEndcap() {
+    return _attributes.contains(Attribute.ENDCAP);
+  }
+  
+  public boolean isSouth() {
+    return _attributes.contains(Attribute.SOUTH);
+  }
+  
+  public boolean isNorth() {
+    return _attributes.contains(Attribute.NORTH);
+  }
+
+  public boolean isEntry() {
+    return _attributes.contains(Attribute.ENTRY);
+  }
+
+  public boolean isExit() {
+    return _attributes.contains(Attribute.EXIT);
+  }
+  
+  public Subdetector getSubdetector() {
+    return _sd;
+  }
+  
+  public String getSubdetectorName() {
+    return _sdName;
+  }
+  
+  /** Returns an unmodifiable list of layer objects in this module. */
+  public List<CalLayer> getLayers() {
+    return Collections.unmodifiableList(_layers);
+  }
+  
+
+  /**
+   * Look up layer object in this module by its ordinal number.
+   * Layers in a module are numbered from 0, from inside to outside.
+   * Throws <tt>IndexOutOfBoundsException</tt> if the specified layer ordinal is out of bounds.
+   */
+  public CalLayer getLayerByOrdinal(int ordinal) {
+    return _layers.get(ordinal);
+  }
+  
+  /**
+   * Look up layer object in this module by its layer number as reported by {@link IDDecoder}.
+   * Throws <tt>IndexOutOfBoundsException</tt> if there is no layer with the specified
+   * number in this module.
+   */
+  public CalLayer getLayerByDecoded(int layerNumber) {
+    int ordinal = layerNumber - _layers.get(0).getLayerDecoded();
+    return getLayerByOrdinal(ordinal);
+  }
+  
+  /**
+   * Look up layer object in this module by its layer ID.
+   * Throws <tt>IndexOutOfBoundsException</tt> if the layer with the specified ID
+   * does not belong to this module.
+   */
+  public CalLayer getLayerByID(int layerID) {
+    int ordinal = layerID - _layers.get(0).getLayerID();
+    return getLayerByOrdinal(ordinal);
+  }
+
+  /**
+   * Returns the first (innermost) layer in this module.
+   */
+  public CalLayer firstLayer() {
+    return _layers.get(0);
+  }
+
+  /**
+   * Returns the last (outermost) layer in this module.
+   */
+  public CalLayer lastLayer() {
+    return _layers.get(_layers.size()-1);
+  }
+  
+// -- Private parts :  ---------------------------------------------------------
+  
+  private int _id;
+  private String _name;
+  private EnumSet<Attribute> _attributes;
+  private String _sdName;
+  private Subdetector _sd;
+  private ArrayList<CalLayer> _layers;
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/calorimeter
package-info.java added at 1.1
diff -N package-info.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ package-info.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,4 @@
+/**
+ * Classes used in describing calorimeter geometry and providing various geometry-related services.
+ */
+package org.lcsim.contrib.onoprien.geom.calorimeter;

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/calorimeter/lib
SiD02Geometry.java added at 1.1
diff -N SiD02Geometry.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SiD02Geometry.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,254 @@
+package org.lcsim.contrib.onoprien.geom.calorimeter.lib;
+import java.util.*;
+
+import hep.physics.vec.Hep3Vector;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IDetectorElementVisitor;
+import org.lcsim.detector.IGeometryInfo;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.Subdetector;
+
+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.geom.calorimeter.CalGeometry;
+import org.lcsim.contrib.onoprien.geom.calorimeter.CalLayer;
+import org.lcsim.contrib.onoprien.geom.calorimeter.CalModule;
+
+import static org.lcsim.contrib.onoprien.geom.calorimeter.CalModule.Attribute.*;
+
+/**
+ * Generic {@link CalGeometry} implementation suitable for SiD cylindrical calorimeter.
+ * Optimized implementations can be written for particular detectors to improve performance.
+ * <p>
+ * 6 modules are created, one for each endcap and one for the barrel, both for ECAL and HCAL.
+ *
+ * @author D. Onoprienko
+ * @version $Id: SiD02Geometry.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public class SiD02Geometry extends CalGeometry implements JobEventListener {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  private List<CalModule> _modules;
+  private CalModule _eBar, _hBar, _eSouthEnd, _eNorthEnd, _hSouthEnd, _hNorthEnd;
+
+
+// -- Constructors and initialization :  ---------------------------------------
+  
+  public SiD02Geometry() {
+    JobManager.defaultInstance().addListener(this);
+  }
+  
+  public void detectorChanged(JobEvent jEvent) {
+
+    // create modules
+
+    _eBar = new CalModule("ECAL_BARREL", EnumSet.of(ECAL, BARREL, ENTRY), "EMBarrel");
+    _hBar = new CalModule("HCAL_BARREL", EnumSet.of(HCAL, BARREL, EXIT), "HADBarrel");
+    _eSouthEnd = new CalModule("ECAL_ENDCAP_SOUTH", EnumSet.of(ECAL, ENDCAP, SOUTH, ENTRY), "EMEndcap");
+    _eNorthEnd = new CalModule("ECAL_ENDCAP_NORTH", EnumSet.of(ECAL, ENDCAP, NORTH, ENTRY), "EMEndcap");
+    _hSouthEnd = new CalModule("HCAL_ENDCAP_SOUTH", EnumSet.of(HCAL, ENDCAP, SOUTH, EXIT), "HADEndcap");
+    _hNorthEnd = new CalModule("HCAL_ENDCAP_NORTH", EnumSet.of(HCAL, ENDCAP, NORTH, EXIT), "HADEndcap");
+
+    _modules = new ArrayList<CalModule>(6);
+    Collections.addAll(_modules, _eBar, _hBar, _eSouthEnd, _eNorthEnd, _hSouthEnd, _hNorthEnd);
+    _modules = Collections.unmodifiableList(_modules);
+
+    // create layers
+
+    Detector det = jEvent.getDetector();
+    int idOffset = 0;
+    int moduleID = 0;
+    for (final CalModule module : _modules) {
+      Subdetector sd = det.getSubdetector(module.getSubdetectorName());
+      final List<IDetectorElement> deList = new ArrayList<IDetectorElement>(50);
+      sd.getDetectorElement().traverseDescendantsPreOrder(new IDetectorElementVisitor() {
+        public void visit(IDetectorElement de) {
+          if (de.isSensitive())  {
+            if (module.isBarrel()) {
+              deList.add(de);
+            } else {
+              IGeometryInfo gInfo = de.getGeometry();
+              double z = gInfo.getPosition().z();
+              if ((z > 0. && module.isNorth()) || (z < 0. && module.isSouth())) {
+                deList.add(de);
+              }
+            }
+          }
+        }
+        public boolean isDone() {return false;}
+      });
+      TreeMap<Integer, IDetectorElement> deMap = new TreeMap<Integer, IDetectorElement>();
+      for (IDetectorElement de : deList) {
+
+        int idLayerIndex = de.getIdentifierHelper().getFieldIndex("layer");
+        int layer = de.getExpandedIdentifier().getValue(idLayerIndex);
+
+        //String name = de.getName();
+        //name = name.replaceFirst(".*layer","");
+        //name = name.replaceFirst("_.*","");
+        //int layer = Integer.parseInt(name);
+
+        IDetectorElement duplicate = deMap.put(layer, de);
+        if (duplicate != null) throw new RuntimeException("More than 1 DetectorElement in the same layer");
+      }
+      ArrayList<CalLayer> layerList = new ArrayList<CalLayer>(deMap.size());
+      int ordinal = 0;
+      for (Map.Entry<Integer, IDetectorElement> entry : deMap.entrySet()) {
+        int layer = entry.getKey();
+        int id = idOffset + layer;
+        layerList.add(new CalLayer(module, entry.getValue(), ordinal, id, layer));
+        ordinal++;
+      }
+      module.initialize(moduleID++, sd, layerList);
+      idOffset += layerList.size();
+    }
+
+    // CalGeometry initialization
+
+    super.detectorChanged(jEvent);
+  }
+
+
+// -- Implementing CalGeometry :  ----------------------------------------------
+
+  /** Returns an unmodifiable list of calorimeter modules, ordered by module ID. */
+  public List<CalModule> getModules() {
+    return _modules;
+  }
+
+  /**
+   * Returns the next layer the specified trajectory is most likely to cross after coming out of the
+   * specified layer. The origin of the trajectory should belong to the specified layer - no checking is done.
+   */
+  public CalLayer nextLayer(CalLayer layer, Trajectory trajectory) {
+    boolean pointingOut;
+    CalModule module = layer.getModule();
+    Hep3Vector dir = trajectory.getDirection();
+    if (module.isBarrel()) {
+      Hep3Vector pos = trajectory.getPosition();
+      pointingOut = dir.x()*pos.x() + dir.y()*pos.y() > 0. ;
+    } else if (module.isNorth()) {
+      pointingOut = dir.z() > 0.;
+    } else {
+      pointingOut = dir.z() < 0.;
+    }
+    int nextOrdinal = layer.getLayerOrdinal() + ( (pointingOut) ? 1 : -1 );
+    try {
+      return module.getLayerByOrdinal(nextOrdinal);
+    } catch (IndexOutOfBoundsException x) {
+      if (module == _eBar) {
+        if (nextOrdinal == 0) {
+          return null;
+        } else {
+          return _hBar.firstLayer();
+        }
+      } else if (module == _hBar) {
+        if (nextOrdinal == 0) {
+          return _eBar.lastLayer();
+        } else {
+          return null;
+        }
+      } else if (module == _eNorthEnd) {
+        if (nextOrdinal == 0) {
+          return null;
+        } else {
+          return _hNorthEnd.firstLayer();
+        }
+      } else if (module == _eSouthEnd) {
+        if (nextOrdinal == 0) {
+          return null;
+        } else {
+          return _hSouthEnd.firstLayer();
+        }
+      } else if (module == _hNorthEnd) {
+        if (nextOrdinal == 0) {
+          return _eNorthEnd.lastLayer();
+        } else {
+          return null;
+        }
+      } else if (module == _hSouthEnd) {
+        if (nextOrdinal == 0) {
+          return _eSouthEnd.lastLayer();
+        } else {
+          return null;
+        }
+      } else {
+        throw new RuntimeException();
+      }
+    }
+  }
+
+  /**
+   * Returns a list of layers the specified trajectory might cross after coming out of the
+   * given layer - more likely first (but excluding the most likely one that would be returned
+   * by <tt>nextLayer</tt>). The origin of the trajectory should belong to the
+   * specified layer - no checking is done.
+   */
+  public List<CalLayer> nextLayers(CalLayer layer, Trajectory trajectory) {
+    Hep3Vector dir = trajectory.getDirection();
+    Hep3Vector pos = trajectory.getPosition();
+    CalModule module = layer.getModule();
+    boolean isFirstLayer = module.firstLayer() == layer;
+    boolean isLastLayer = module.lastLayer() == layer;
+    double dz = dir.z();
+    //double dirR = pos.x()*dir.x() + pos.y()*dir.y();
+    double dirZ = dz*pos.z();
+    if (module == _eBar) {
+      if (isFirstLayer) {
+        return Collections.emptyList();  // FIXME: loosing trajectories going into ECAL endcap (few, on reverse only)
+      } else {
+        if (dz > 0.) {
+          return Collections.singletonList(_hNorthEnd.firstLayer());
+        } else {
+          return Collections.singletonList(_hSouthEnd.firstLayer());
+        }
+      }
+    } else if (module == _hBar) {
+      if (isFirstLayer) {
+        if (dz > 0.) {
+          return _hNorthEnd.getLayers();
+        } else {
+          return _hSouthEnd.getLayers();
+        }
+      } else {
+        return Collections.emptyList();
+      }
+    } else if (module == _eNorthEnd || module == _eSouthEnd) {
+      if (isFirstLayer || isLastLayer) {
+        return Collections.emptyList();
+      } else {
+        return Collections.singletonList(_eBar.firstLayer());
+      }
+    } else if (module == _hNorthEnd || module == _hSouthEnd) {
+      if (isLastLayer) {
+        return Collections.emptyList();
+      } else if (isFirstLayer && dirZ < 0.) {
+        return _eBar.getLayers();
+      } else {
+        return Collections.singletonList(_hBar.firstLayer());
+      }
+    } else {
+      throw new RuntimeException();
+    }
+  }
+
+  /**
+   * Returns a list of layers the specified trajectory might cross next - more likely first.
+   */
+  public CalLayer nextLayer(Trajectory trajectory) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * Returns a list of layers the specified trajectory might cross next - more likely first
+   * (but excluding the most likely one that would be returned by <tt>nextLayer</tt>).
+   */
+  public List<CalLayer> nextLayers(Trajectory trajectory){
+    throw new UnsupportedOperationException();
+  }
+
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/calorimeter/lib
package-info.java added at 1.1
diff -N package-info.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ package-info.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,11 @@
+/**
+ * Library of classes implementing 
+ * {@link org.lcsim.contrib.onoprien.geom.calorimeter.CalGeometry}
+ * for particular detector versions.
+ * <p>
+ * If your detector is not here, use one these as an example.
+ *
+ * @author D. Onoprienko
+ */
+package org.lcsim.contrib.onoprien.geom.calorimeter.lib;
+

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
AbstractSegmenter.java added at 1.1
diff -N AbstractSegmenter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ AbstractSegmenter.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,123 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.util.*;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IGeometryInfo;
+import org.lcsim.detector.IPhysicalVolume;
+
+/**
+ * Base class for {@link ForwardingSegmenter}s and {@link RegionSegmenter}s that 
+ * can be chained together to describe virtual segmentation of the entire detector.
+ * <p>
+ * A <tt>ForwardingSegmenter</tt> can have any number of daughter segmenters, each 
+ * handling a particular part of the detector. Each daughter is either another 
+ * <tt>ForwardingSegmenter</tt>, or a <tt>RegionSegmenter</tt> that does the actual
+ * {@link Sensor} object creation, and assigns an integer ID (<tt>postfix</tt>) to
+ * each <tt>Sensor</tt> within the region it is responsible for. The result is a tree
+ * of segmenters, with <tt>ForwardingSegmenter</tt>s at its top and intermediate nodes,
+ * and <tt>RegionSegmenter</tt>s as its leaves. {@link SegmentationManager} automatically
+ * assigns prefixes to all <tt>RegionSegmenter</tt>s, making sure that <tt>SensorID</tt>
+ * they assign to <tt>Sensors</tt> are unique within the whole detector. 
+ * <p>
+ * See top level segmenters in the {@link org.lcsim.contrib.onoprien.geom.tracker.lib}
+ * package for an example of chaining several different segmenters.
+ *
+ * @author D. Onoprienko
+ * @version $Id: AbstractSegmenter.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+abstract public class AbstractSegmenter implements Segmenter {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  protected int _prefix;
+  protected int _postfixLength;
+  protected int _postfixMask;
+  protected int _prefixTemplate;
+
+
+// -- Constructors :  ----------------------------------------------------------
+  
+  AbstractSegmenter() {
+  }
+
+
+// -- Handling of prefixes and postfixes :  ------------------------------------
+  
+  /** 
+   * Set <tt>prefix</tt> for this <tt>Segmenter</tt>.
+   * The number of bits reserved for <tt>postfix</tt> will be calculated automatically.
+   * For the top level <tt>Segmenter</tt>, this method will be called by
+   * <tt>SegmentationManager</tt> with <tt>prefix</tt> equal to zero.
+   */
+  void setPrefix(int prefix) {
+    setPrefix(prefix, getNativePostfixLength());
+  }
+  
+  /**
+   * Set <tt>pretfix</tt> value and <tt>postfix</tt> length for this <tt>Segmenter</tt>.
+   */
+  void setPrefix(int prefix, int postfixLength) {
+    _prefix = prefix;
+    _postfixLength = postfixLength;
+    _postfixMask = 0;
+    for (int i=0; i<postfixLength; i++) _postfixMask = (_postfixMask << 1) | 1;
+    _prefixTemplate = prefix << _postfixLength;
+  }
+  
+  
+  /**
+   * Returns minimum number of bits required to hold any postfix that can be used
+   * by this <tt>Segmenter</tt>.
+   */
+  abstract protected int getNativePostfixLength();
+  
+  /**
+   * Get <tt>prefix</tt> used by this <tt>OldSegmenter</tt>.
+   */
+  final protected int getPrefix() {
+    return _prefix;
+  }
+  
+  /** Convert <tt>postfix</tt> to full <tt>SensorID</tt>. */
+  final protected int postfixToID(int postfix) {
+    return (postfix == -1) ? -1 : (_prefixTemplate | postfix);
+  }
+
+  /** Extract <tt>postfix</tt> from full <tt>SensorID</tt>. */
+  final protected int idToPostfix(int sensorID) {
+    return sensorID & _postfixMask;
+  }
+
+
+// -- Static utility methods :  ------------------------------------------------
+  
+  /**
+   * Returns the number of bits required to hold an integer between <tt>0</tt> and <tt>maxID</tt>.
+   */
+  static int getIdSize(int maxID) {
+    return (int) Math.ceil(Math.log(maxID+0.8)/Math.log(2.));
+  }
+  
+  /**
+   * Returns a list of sensitive lowest-level decendents of the diven detector element.
+   * FIXME: This should be a DetectorElement method !
+   */
+  static public List<IDetectorElement> getLeaves(IDetectorElement del) {
+    ArrayList<IDetectorElement> out = new ArrayList<IDetectorElement>();
+    if (del.hasChildren()) {
+      for (IDetectorElement child : del.getChildren()) {
+        out.addAll(getLeaves(child));
+      }
+    } else {
+      IGeometryInfo gInfo = del.getGeometry();
+      if (gInfo != null) {
+        IPhysicalVolume pVol = gInfo.getPhysicalVolume();
+        if (pVol != null) out.add(del);
+//        if (pVol != null && pVol.isSensitive()) out.add(del); Returns false for every volume - why ?
+      }
+    }
+    return out;
+  }
+  
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
Direction.java added at 1.1
diff -N Direction.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Direction.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,26 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+/**
+ * Direction along the track - {@link #OUT} means from the center of the detector to the 
+ * periphery (for most tracks, this is the direction the particle moves in), {@link #IN}
+ * means from outside into the detector.
+ *
+ * @author D.Onoprienko
+ * @version $Id: Direction.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public enum Direction {
+
+  /** Outside-to-inside direction. */
+  IN(-1), 
+  
+  /** Inside-to-outside direction. */
+  OUT(1);
+  
+  /**
+   * Integer coefficient associated with the direction: <tt>-1</tt> for {@link #IN}, <tt>1</tt> for {@link #OUT}.
+   */
+  public final int k;
+  
+  Direction(int k) {this.k = k;}
+  
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
ForwardingSegmenter.java added at 1.1
diff -N ForwardingSegmenter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ForwardingSegmenter.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,179 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.util.*;
+
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.geometry.Detector;
+
+/**
+ * Base class for implementing {@link Segmenter}s that forward ID or {@link Sensor}
+ * creation calls to their daughter segmenters. See {@link AbstractSegmenter} for
+ * details on how to chain segmenters.
+ * <p>
+ * Subclasses should implement {@link #chooseSegmenter(SimTrackerHit)} method to select
+ * a daughter segmenter that will handle a particular simulated hit. Daughter segmenters
+ * should be added to the parent segmenter through calls to 
+ * {@link #addDaughterSegmenter(AbstractSegmenter)}.
+ *
+ * @author D. Onoprienko
+ * @version $Id: ForwardingSegmenter.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+abstract public class ForwardingSegmenter extends AbstractSegmenter {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  private ArrayList<AbstractSegmenter> _daughters;
+
+  protected int _daughterPostfixLength;
+  protected int _daughterIdMask;
+
+
+// -- Constructors :  ----------------------------------------------------------
+  
+  /** Default constructor. */
+  protected ForwardingSegmenter() {
+    _daughters = new ArrayList<AbstractSegmenter>();
+  }
+
+
+// -- Choosing daughter segmenter :  -------------------------------------------
+  
+  /**
+   * Subclasses should implement this method to choose daughter <tt>Segmenter</tt>
+   * that can handle the given hit.
+   */
+  abstract public AbstractSegmenter chooseSegmenter(SimTrackerHit hit);
+
+
+// -- Implementing Segmenter :  ------------------------------------------------
+  
+  /**
+   * Returns a list of <tt>SensorsID</tt> corresponding to all virtual segments
+   * in the part of the detector handled by this <tt>Segmenter</tt>.
+   */
+  public List<Integer> getSensorIDs() {
+    List<Integer> sensorIDs = null;
+    for (AbstractSegmenter daughter : _daughters) {
+      if (sensorIDs == null) {
+        sensorIDs = daughter.getSensorIDs();
+      } else {
+        sensorIDs.addAll(daughter.getSensorIDs());
+      }
+    }
+    //System.out.println("Segmenter "+this+" returning "+sensorIDs.size()+" IDs");
+    return sensorIDs;
+  }
+
+  /**
+   * Returns integer <tt>SensorID</tt> uniquely identifying a {@link Sensor} object
+   * within the whole detector, given the simulated hit.
+   */
+  public List<Integer> getSensorID(SimTrackerHit hit) {
+    AbstractSegmenter daughter = chooseSegmenter(hit);
+    return (daughter == null) ? Collections.<Integer>emptyList() : daughter.getSensorID(hit);
+  }
+  
+  /**
+   * Creates a new {@link Sensor} object given full <tt>SensorID</tt>.
+   * Caution: for the sake of speed, no checking is done to veryfy that the 
+   * supplied <tt>SensorID</tt> is valid and should be handled by this <tt>Segmenter</tt>.
+   * Giving this method an invalid <tt>SensorID</tt> may produce unpredictable results.
+   */
+  public Sensor getSensor(int sensorID) {
+    return _daughters.get(idToDaughterIndex(sensorID)).getSensor(sensorID);
+  }
+  
+  /**
+   * Returns a list of <tt>Sensors</tt> that might contain hits that should be combined
+   * with hits in the <tt>Sensor</tt> whose <tt>sensorID</tt> is supplied as an argument
+   * to form stereo pairs. 
+   * Default implementation forwards the call to the appropriate daughter segmenter. 
+   * Subclasses may override.
+   */
+  public List<Integer> getStereoPartners(int sensorID) {
+    return _daughters.get(idToDaughterIndex(sensorID)).getStereoPartners(sensorID);
+  }
+
+
+// -- Initialization :  --------------------------------------------------------
+  
+  /**
+   * Detector dependent initialization.
+   * Subclasses should override this method if they need to perform any detector
+   * dependent initialization, but they should call {@link #updateDaughterSegmenters(Detector)}
+   * from this method to have their daughter <tt>Segmenter</tt>s initialized as well.
+   */
+  public void detectorChanged(Detector detector) {
+//    System.out.println(" ");
+//    System.out.println("Updating " + this + " with " + detector.getName());
+    updateDaughterSegmenters(detector);
+  }
+  
+  /** 
+   * Calls {@link #detectorChanged(Detector)} methods of daughter <tt>Segmenter</tt>s.
+   * If subclasses override {@link #detectorChanged(Detector)} method, they should
+   * call this method to have daughter <tt>Segmenter</tt>s initialized.
+   */
+  protected void updateDaughterSegmenters(Detector detector) {
+    for (AbstractSegmenter daughter : _daughters) daughter.detectorChanged(detector);
+  }
+
+
+// -- Handling of prefixes and postfixes :  ------------------------------------
+  
+  /**
+   * Set <tt>pretfix</tt> value and <tt>postfix</tt> length for this <tt>Segmenter</tt>.
+   */
+  public void setPrefix(int prefix, int postfixLength) {
+    //System.out.println("Setting prefix for "+this+" prefix "+prefix+" length "+postfixLength);
+    super.setPrefix(prefix, postfixLength);
+    _daughters.trimToSize();
+    int daughterIdLdength = getIdSize(_daughters.size()-1);
+    _daughterPostfixLength = postfixLength - daughterIdLdength;
+    _daughterIdMask = 0;
+    for (int i=0; i<daughterIdLdength; i++) _daughterIdMask = (_daughterIdMask << 1) | 1;
+    _daughterIdMask = _daughterIdMask << _daughterPostfixLength;
+    for (int daughterIndex=0; daughterIndex < _daughters.size(); daughterIndex++) {
+      _daughters.get(daughterIndex).setPrefix((prefix << daughterIdLdength) | daughterIndex , _daughterPostfixLength);
+    }
+  }
+  
+  /**
+   * Extract daughter <tt>Segmenter</tt> index from full <tt>SensorID</tt>.
+   */
+  protected int idToDaughterIndex(int sensorID) {
+    return (_daughterIdMask & sensorID) >> _daughterPostfixLength;
+  }
+  
+  /**
+   * Returns minimum <tt>postfix</tt> length required by this <tt>Segmenter</tt>
+   * to accomodate all its daughters and their <tt>postfix</tt>es.
+   */
+  protected int getNativePostfixLength() {
+    int daughterIdLdength = getIdSize(_daughters.size()-1);
+    int maxDaughterPostfixLength = 0;
+    for (AbstractSegmenter daughter : _daughters) {
+      maxDaughterPostfixLength = Math.max(daughter.getNativePostfixLength(), maxDaughterPostfixLength);
+    }
+    return daughterIdLdength + maxDaughterPostfixLength;
+  }
+
+
+// -- Adding / Removing daughters :  -------------------------------------------
+
+  /** Add daughter <tt>Segmenter</tt>. */
+  public void addDaughterSegmenter(AbstractSegmenter daughter) {
+    _daughters.add(daughter);
+  }
+  
+  /** Remove daughter <tt>Segmenter</tt>. */
+  public void removeDaughterSegmenter(AbstractSegmenter daughter) {
+    _daughters.remove(daughter);
+  }
+  
+  /** Remove all daughter <tt>Segmenter</tt>s. */
+  public void removeAllDaughterSegmenters() {
+    _daughters.clear();
+  }
+
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
RegionSegmenter.java added at 1.1
diff -N RegionSegmenter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ RegionSegmenter.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,154 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.util.*;
+
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.geometry.Detector;
+
+/**
+ * Base class for implementing {@link Segmenter}s that describe virtual segmentation 
+ * of a certain part of the detector.
+ * <p>
+ * Within that part, each <tt>Sensor</tt> is identified by a unique integer <tt>postfix</tt>.
+ * Each <tt>RegionSegmenter</tt> can be assigned an integer <tt>prefix</tt>. After that,
+ * <tt>SensorID</tt> values returned by <tt>getSensorID(SimTrackerHit)</tt> method and assigned to
+ * <tt>Sensor</tt> objects created by this segmenter will be composed of bits
+ * containing the <tt>prefix</tt> and bits containing the <tt>postfix</tt>.
+ * <p>
+ * Objects of this class are intended to be used either as top level segmenters
+ * describing segmentation of the whole detector and provided directly to 
+ * {@link SegmentationManager} in its constructor, or as bottom level segmenters
+ * in a tree of <tt>AbstractSegmenters</tt>. In the latter case, they should be added as 
+ * daughters to <tt>ForwardingSegmenters</tt>, and their prefixes will be set automatically.
+ * See {@link AbstractSegmenter} for details on how to chain <tt>Segmenters</tt>.
+ * <p>
+ * Subclasses should implement {@link #makePostfix(SimTrackerHit)}, {@link #makeSensor(int)},
+ * {@link #getMaxPostfix()}, and {@link #isPostfixValid(int)} methods. In addition, 
+ * {@link #detectorChanged(Detector)} method can be overridden if any detector 
+ * dependent initialization is required.
+ *
+ * @author D. Onoprienko
+ * @version $Id: RegionSegmenter.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+abstract public class RegionSegmenter extends AbstractSegmenter {
+  
+// -- Constructors :  ----------------------------------------------------------
+  
+  /** Default constructor. */
+  protected RegionSegmenter() {
+  }
+  
+// -- To be implemented by subclusses :  ---------------------------------------
+  
+  /**
+   * Subclasses should implement this method to return an array of sensor <tt>postfix</tt> 
+   * values corresponding to the position of the specified simulated hit. 
+   */
+  abstract protected int[] makePostfix(SimTrackerHit hit);
+
+  /**
+   * Subclasses should implement this method to create a new {@link Sensor} object given
+   * the <tt>postfix</tt>. If the postfix is invalid, <tt>null</tt> should be returned.
+   */
+  abstract protected Sensor makeSensor(int postfix);
+  
+  /**
+   * Subclasses should implement this method to return maximum postfix value that can be
+   * returned by {@link #makePostfix(SimTrackerHit)} method of this <tt>Segmenter</tt> object.
+   */
+  abstract protected int getMaxPostfix();
+  
+  /**
+   * Subclasses should override this method to return <tt>true</tt> if the given 
+   * <tt>postfix</tt> corresponds to a valid <tt>Sensor</tt> object that can be created
+   * by this <tt>RegionSegmenter</tt>. Default implementation is provided, returning
+   * <tt>true</tt> if the value of <tt>postfix</tt> is between zero and the value
+   * returned by {@link #getMaxPostfix()}.
+   */
+  protected boolean isPostfixValid(int postfix) {
+    return postfix >= 0 && postfix <= getMaxPostfix();
+  }
+  
+// -- Implementing Segmenter :  ------------------------------------------------
+  
+  /**
+   * Returns a collection of <tt>Sensors</tt> corresponding to all virtual segments
+   * in the part of the detector handled by this <tt>Segmenter</tt>.
+   */
+  public List<Integer> getSensorIDs() {
+    int nSensors = getMaxPostfix() + 1;
+    ArrayList<Integer> sensorIDs = new ArrayList<Integer>(nSensors);
+    for (int postfix=0; postfix < nSensors; postfix++) {
+      if (isPostfixValid(postfix)) sensorIDs.add(postfixToID(postfix));
+    }
+    //System.out.println("Segmenter "+this+" returning "+sensorIDs.size()+" IDs");
+    return sensorIDs;
+  }
+  
+  /**
+   * Returns integer <tt>SensorID</tt> uniquely identifying a {@link Sensor} object
+   * within the whole detector, given the simulated hit.
+   */
+  public List<Integer> getSensorID(SimTrackerHit hit) {
+    int[] postfix = makePostfix(hit);
+    if (postfix.length == 0) {
+      return Collections.emptyList();
+    } else {
+      List<Integer> pfList = new ArrayList(postfix.length);
+      for (int pf : postfix) pfList.add(postfixToID(pf));
+      return pfList;
+    }
+  }
+  
+  /**
+   * Creates a new {@link Sensor} object given full <tt>SensorID</tt>.
+   * For the sake of speed, no checking is done to verify that the supplied 
+   * <tt>SensorID</tt> belongs to the part of the detector that should be handled 
+   * by this <tt>OldSegmenter</tt> - be careful.
+   */
+  public Sensor getSensor(int sensorID) {
+    return makeSensor(idToPostfix(sensorID));
+  }
+
+  /** 
+   * Called by the framework whenever detector geometry changes.
+   * Subclasses can override this method if they need to perform any 
+   * detector-dependent initialization.
+   */
+  public void detectorChanged(Detector detector) {
+  }
+  
+  /**
+   * Returns a list of <tt>Sensors</tt> that might contain hits that should be combined
+   * with hits in the <tt>Sensor</tt> whose <tt>sensorID</tt> is supplied as an argument
+   * to form stereo pairs.
+   * Default implementation returns an empty list. Subclasses may override.
+   */
+  public List<Integer> getStereoPartners(int sensorID) {
+    return Collections.emptyList();
+  }
+  
+// -- Handling prefixes and postfixes :  ---------------------------------------
+  
+  /**
+   * Set <tt>pretfix</tt> value and <tt>postfix</tt> length for this <tt>Segmenter</tt>.
+   */
+  public void setPrefix(int prefix, int postfixLength) {
+//    System.out.println("Setting prefix for "+this+" prefix "+prefix+" length "+postfixLength);
+    super.setPrefix(prefix, postfixLength);
+    if (getIdSize(prefix) + postfixLength > 32) {
+      throw new IllegalArgumentException("Combined prefix and postfix length cannot be more than 32");
+    } else if (postfixLength < getNativePostfixLength()) {
+      throw new IllegalArgumentException("Attempt to set insufficient postfix length");
+    }
+  }
+  
+  /**
+   * Returns minimum number of bits required to hold any postfix that can be returned by
+   * {@link #makePostfix(SimTrackerHit)} method of this <tt>Segmenter</tt>.
+   */
+  public int getNativePostfixLength() {
+    return getIdSize(getMaxPostfix());
+  }
+  
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
SegmentationManager.java added at 1.1
diff -N SegmentationManager.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SegmentationManager.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,260 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.lang.ref.SoftReference;
+import java.util.*;
+
+import org.lcsim.detector.identifier.IExpandedIdentifier;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.identifier.IIdentifierHelper;
+import org.lcsim.detector.identifier.Identifiable;
+import org.lcsim.geometry.Detector;
+import org.lcsim.event.SimTrackerHit;
+
+import org.lcsim.contrib.onoprien.data.heprep.ITrackerHitConverter;
+import org.lcsim.contrib.onoprien.util.job.NoSuchParameterException;
+import org.lcsim.contrib.onoprien.util.job.JobEvent;
+import org.lcsim.contrib.onoprien.util.job.Driver;
+import org.lcsim.contrib.onoprien.util.job.JobEventListener;
+import org.lcsim.contrib.onoprien.util.job.JobManager;
+
+/**
+ * This class handles creation, caching and run-time access to {@link Sensor} objects and segmentation information.
+ * <p>
+ * Typically, the driver that controls event reconstruction obtains an
+ * instance of this class from the {@link JobManager}, and sets the {@link Segmenter} object that defines virtual
+ * segmentation of the detector. See {@link org.lcsim.contrib.onoprien.geom.tracker.lib.ExampleDriver1}
+ * or {@link org.lcsim.contrib.onoprien.geom.tracker.lib.ExampleDriver2}.
+ * <p>
+ * At run time, <tt>SegmentationManager</tt> can be accessed through the {@link JobManager}
+ * by calling <tt>JobManager.defaultInstance().get(SegmentationManager.class)</tt>.
+ * <p>
+ * By default, <tt>Sensor</tt> objects are created as needed (that is, when there are hits
+ * in those sensors), and are kept in cache unless JVM starts running out of memory.
+ * If the user needs <tt>Sensor</tt> objects corresponding to all virtual segments of
+ * the detector to be created before data processing, <tt>SegmentationManager</tt>
+ * can be asked to do so by a call to <tt>set("MAKE_SENSORS_ON_DETECTOR_CHANGE", true)</tt>.
+ * It usually makes sense to do this if the user plans to use {@link #getSensors}
+ * method in the future.
+ *
+ * @author D.Onoprienko
+ * @version $Id: SegmentationManager.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public class SegmentationManager implements JobEventListener {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  private HashMap<Integer, SoftReference<Sensor>> _sensorWeakMap;
+  private HashMap<Integer, Sensor> _sensorMap;
+
+  private Segmenter _segmenter;
+
+  private boolean _createSensorsOnDetectorChange;
+
+  private boolean _cacheStereoRequests;
+  private HashMap<Sensor, List<Sensor>> _stereoMap;
+
+  
+// -- Constructors, initialization, and cleanup :  -----------------------------
+
+  /**
+   * Constructs a new instance of SegmentationManager.
+   */
+  private SegmentationManager() {
+
+    _createSensorsOnDetectorChange = true;
+    _sensorWeakMap = new HashMap<Integer, SoftReference<Sensor>>();
+    _cacheStereoRequests = true;
+    _stereoMap = new HashMap<Sensor, List<Sensor>>();
+
+    JobManager jobMan = JobManager.defaultInstance();
+
+    jobMan.registerHepRepConverter(new SensorConverter());
+    jobMan.registerHepRepConverter(new ITrackerHitConverter());
+
+    jobMan.addListener(this);
+  }
+
+  /**
+   * Detector-dependent initialization.
+   * Clears sensor map, calls <tt>detectorChanged(Detector)</tt> methods of all 
+   * segmenters, then assign prefixes to segmenters.
+   */
+  public void detectorChanged(JobEvent jEvent) {
+    if (_segmenter == null) throw new IllegalStateException("Segmenter has not been set");
+    Detector detector = jEvent.getDetector();
+    if (_createSensorsOnDetectorChange) {
+      _sensorWeakMap = null;
+      _sensorMap = new HashMap<Integer, Sensor>();
+    } else {
+      _sensorWeakMap = new HashMap<Integer, SoftReference<Sensor>>();
+      _sensorMap = null;
+    }
+    if (_cacheStereoRequests) {
+      _stereoMap = new HashMap<Sensor, List<Sensor>>();
+    }
+    _segmenter.detectorChanged(detector);
+    if (_segmenter instanceof AbstractSegmenter) {
+      ((AbstractSegmenter) _segmenter).setPrefix(0);
+    }
+    if (_createSensorsOnDetectorChange) {
+      List<Integer> sensorIDs = _segmenter.getSensorIDs();
+      for (int sensorID : sensorIDs) {
+        _sensorMap.put(sensorID, _segmenter.getSensor(sensorID));
+      }
+    }
+  }
+
+  /**
+   * Called by the framework to create a new instance of <tt>SegmentationManager</tt>
+   * - should not be called by user's code.
+   */
+  public static SegmentationManager defaultInstance() {
+    return new SegmentationManager();
+  }
+
+
+// -- Setters :  ---------------------------------------------------------------
+
+  /**
+   * Set any <tt>boolean</tt> parameter. 
+   * The following parameters can be set with this method:
+   * <dl>
+   * <dt>"SEGMENTER"</dt> <dd>{@link Segmenter} describing virtual segmentation to be used by
+   *            this <tt>SegmentationManager</tt>.<br>
+   *            No default - Segmenter must be set before this <tt>SegmentationManager</tt> can be used.</dd>
+   * <dt>"MAKE_SENSORS_ON_DETECTOR_CHANGE"</dt> <dd>If set to <tt>true</tt>, <tt>Sensor</tt>
+   *            objects corresponding to all virtual segments are created whenever the 
+   *            detector information becomes available (or changes), and are kept in memory
+   *            until the end of the job.<br>
+   *            Default: <tt>true</tt>.</dd>
+   * <dt>"CACHE_STEREO_REQUESTS"</dt> <dd>If set to <tt>true</tt>, the output of calls to
+   *            {@link #getStereoPartners} will be cached.<br>
+   *            Default: <tt>true</tt>.</dd>
+   * </dl>
+   * 
+   * @param name   Name of parameter to be set. Case is ignored.
+   * @param value  Value to be assigned to the parameter.
+   * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
+   *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
+   *         and set their own parameters.
+   */
+  public void set(String name, Object... values) {
+    try {
+      if (name.equalsIgnoreCase("SEGMENTER")) {
+        _segmenter = (Segmenter) values[0];
+      } else if (name.equalsIgnoreCase("MAKE_SENSORS_ON_DETECTOR_CHANGE")) {
+        _createSensorsOnDetectorChange = (Boolean) values[0];
+      } else if (name.equalsIgnoreCase("CACHE_STEREO_REQUESTS")) {
+        _cacheStereoRequests = (Boolean) values[0];
+      } else {
+        throw new NoSuchParameterException(name);
+      }
+    } catch (ClassCastException x) {
+      throw new IllegalArgumentException(Driver.ERR_VIT, x);
+    } catch (IndexOutOfBoundsException x) {
+      throw new IllegalArgumentException(Driver.ERR_INV, x);
+    }
+  }
+
+
+// -- Sensor and channel lookup, ID conversions :  -----------------------------
+  
+  /**
+   * Returns a collection of <tt>Sensors</tt> corresponding to all virtual segments of the detector.
+   */
+  public Collection<Sensor> getSensors() {
+    if (_createSensorsOnDetectorChange) {
+      return _sensorMap.values();
+    } else {
+      List<Integer> sensorIDs = _segmenter.getSensorIDs();
+      ArrayList<Sensor> sensors = new ArrayList<Sensor>(sensorIDs.size());
+      for (int sensorID : sensorIDs) sensors.add(getSensor(sensorID));
+      return sensors;
+    }
+  }
+
+  /**
+   * Returns {@link Sensor} object corresponding to the given sensor ID.
+   */
+  public Sensor getSensor(int sensorID) {
+    Sensor sensor = null;
+    if (_createSensorsOnDetectorChange) {
+      sensor = _sensorMap.get(sensorID);
+    } else {
+      SoftReference<Sensor> ref = _sensorWeakMap.get(sensorID);
+      if (ref != null) sensor = ref.get();
+      if (sensor == null) {
+        sensor = _segmenter.getSensor(sensorID);
+        if (sensor != null) _sensorWeakMap.put(sensorID, new SoftReference<Sensor>(sensor));
+      }
+    }
+    return sensor;
+  }
+  
+  /** 
+   * Returns a list of sensors the specified simulated hit belongs to.
+   */
+  public List<Sensor> getSensor(SimTrackerHit hit) {
+    List<Integer> idList = getSensorID(hit);
+    ArrayList<Sensor> sensors = new ArrayList<Sensor>(idList.size());
+    for (int id : idList) {
+      sensors.add(getSensor(id));
+    }
+    return sensors;
+  }
+
+  /** 
+   * Converts cell ID and position obtained from {@link SimTrackerHit} object to sensor ID.
+   */
+  public List<Integer> getSensorID(SimTrackerHit hit) {
+    return _segmenter.getSensorID(hit);
+  }
+
+// -- Getting info about Sensors :  --------------------------------------------
+
+  /**
+   * Returns a list of <tt>Sensors</tt> that might contain hits that should be combined
+   * with hits in the specified <tt>Sensor</tt> to form stereo pairs. Returns an empty
+   * list in the specified <tt>Sensor</tt> is not a part of a stereo layer.
+   * If the <tt>Segmenter</tt> used by this <tt>SegmentationManager</tt> does not support 
+   * stereo partner lookup, <tt>null</tt> may be returned.
+   */  
+  public List<Sensor> getStereoPartners(Sensor sensor) {
+    List<Sensor> partners = null;
+    if (_cacheStereoRequests) partners = _stereoMap.get(sensor);
+    if (partners == null) {
+      List<Integer> partnerIDs = _segmenter.getStereoPartners(sensor.getID());
+      if (partnerIDs == null) return null;
+      if (partnerIDs.isEmpty()) {
+        partners =  Collections.emptyList();
+      } else {
+        partners = new ArrayList<Sensor>(partnerIDs.size());
+        for (int sensorID : partnerIDs) partners.add(getSensor(sensorID));
+      }
+    }
+    if (_cacheStereoRequests) _stereoMap.put(sensor, partners);
+    return partners;
+  }
+  
+  /** 
+   * Packs Sensor ID and Channel ID into a single <tt>long</tt> Cell ID.
+   */
+  private long encodeCellID(int sensorID, int channelID) {
+    return (((long) sensorID) << 32) & (0xffffffffL | channelID);
+  }
+  
+  /**
+   * Unpacks <tt>long</tt> Cell ID, retrieving Sensor ID and Channel ID.
+   * @return Array that contains two <tt>int</tt> values: {SensorID, ChannelID}.
+   */
+  private int[] decodeCellID(long cellID) {
+    int sensorID = (int) (cellID >> 32);
+    int channelID = (int) cellID;
+    return new int[] {sensorID, channelID};
+  }
+  
+  public IIdentifierHelper getIdentifierHelper() {
+    return null; // FIXME
+  }
+
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
Segmenter.java added at 1.1
diff -N Segmenter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Segmenter.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,51 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.util.*;
+
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.geometry.Detector;
+
+/**
+ * Any class that implement this interface defines virtual segmentation of either
+ * entire detector or some part of it.
+ * <p>
+ * Additional machinery is provided for chaining <tt>Segmenters</tt> - see
+ * {@link AbstractSegmenter} for details.
+ *
+ * @author D. Onoprienko
+ * @version $Id: Segmenter.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public interface Segmenter {
+  
+  /**
+   * Returns a list of <tt>SensorsIDs</tt> corresponding to all virtual segments
+   * in the part of the detector handled by this <tt>Segmenter</tt>.
+   */
+  public List<Integer> getSensorIDs();
+  
+  /**
+   * Returns a list of integer <tt>SensorIDs</tt> uniquely identifying each of the 
+   * {@link Sensor} objects the specified simulated hit belongs to.
+   * The hit may belong to more than one sensor to simulate overlaps, double sided
+   * sensors, etc. The hit may belong to no sensors to simulate gaps.
+   */
+  public List<Integer> getSensorID(SimTrackerHit hit);
+  
+  /**
+   * Creates a new {@link Sensor} object given full <tt>SensorID</tt>.
+   */
+  public Sensor getSensor(int sensorID);
+  
+  /**
+   * Detector dependent initialization.
+   */
+  public void detectorChanged(Detector detector);
+  
+  /**
+   * Returns a list of <tt>Sensors</tt> that might contain hits that should be combined
+   * with hits in the <tt>Sensor</tt> with the specified <tt>sensorID</tt> to form stereo pairs.
+   * If the <tt>Sensor</tt> is not part of a stereo layer, an empty list should be returned.
+   */
+  public List<Integer> getStereoPartners(int sensorID);
+  
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
Sensor.java added at 1.1
diff -N Sensor.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Sensor.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,178 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.util.*;
+
+import hep.physics.vec.Hep3Vector;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.identifier.IExpandedIdentifier;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.identifier.IIdentifierHelper;
+import org.lcsim.geometry.Subdetector;
+import org.lcsim.geometry.subdetector.BarrelEndcapFlag;
+
+import org.lcsim.contrib.onoprien.util.job.JobManager;
+import org.lcsim.contrib.onoprien.util.transform.IRefFrame;
+
+/**
+ * Representation of a silicon sensor that can be further divided 
+ * into strips or pixels. Each sensor has a local reference frame associated with it, 
+ * and knows how to transform coordinates between local and global frames. 
+ *
+ * @author D.Onoprienko
+ * @version $Id: Sensor.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public class Sensor {
+
+// -- Private parts :  ---------------------------------------------------------
+
+  private IDetectorElement _de;
+  private SensorType _type;
+  private int _id;
+  private IIdentifier _identifier;
+  private IRefFrame _sf;
+  private IRefFrame _lf;
+
+  private int _layer;
+  private int _superLayer;
+  private Subdetector _sd;
+
+
+// -- Constructors :  ----------------------------------------------------------
+
+  /**
+   * Constructor with automatic layer number calculation.
+   * Layer is obtained from <tt>DetectorElement</tt>, superlayer is assigned based
+   * on existence of stereo partners.
+   */
+  public Sensor(Subdetector subDetector, IDetectorElement de, int id, SensorType type, IRefFrame referenceFrame) {
+    this(subDetector, de, id, type, referenceFrame, de.getIdentifierHelper().getValue(de.getIdentifier(), "layer"));
+  }
+
+  /**
+   * Constructor with automatic superlayer number calculation.
+   * Layer is provided to the constructor, superlayer is assigned based on existence of stereo partners.
+   */
+  public Sensor(Subdetector subDetector, IDetectorElement de, int id, SensorType type, IRefFrame referenceFrame, int layer) {
+    this(subDetector, de, id, type, referenceFrame, layer, 0);
+    SegmentationManager segMan = JobManager.defaultInstance().get(SegmentationManager.class);
+    List<Sensor> stereoPartners = segMan.getStereoPartners(this);
+    if (stereoPartners == null || stereoPartners.isEmpty()) {
+      _superLayer = _layer;
+    } else {
+      _superLayer = _layer / 2;
+    }
+  }
+
+  /**
+   * Full constructor
+   */
+  public Sensor(Subdetector subDetector, IDetectorElement de, int id, SensorType type, IRefFrame referenceFrame,
+                int layer, int superLayer) {
+    _sd = subDetector;
+    _de = de;
+    _id = id;
+    _type = type;
+    _sf = referenceFrame;
+    _layer = layer;
+    _superLayer = superLayer;
+  }
+
+
+// -- Implementing ITrackerObject :  -------------------------------------------
+
+  public Sensor getSensor() {
+    return this;
+  }
+   
+   /**
+    * Get the {@link IIdentifier} associated with this object.
+    */
+   public IIdentifier getIdentifier() {
+     return _identifier;
+   }
+   
+   /**
+    * Get the {@link IExpandedIdentifier} associated with this object.
+    */
+   public IExpandedIdentifier getExpandedIdentifier() {
+     return getIdentifierHelper().unpack(_identifier);
+   }
+   
+   /**
+    * Get the {@link IIdentifierHelper} associated with this object.
+    */
+   public IIdentifierHelper getIdentifierHelper() {
+     return JobManager.defaultInstance().get(SegmentationManager.class).getIdentifierHelper();
+   }
+
+  /**
+   * Returns tracker layer this object belongs to.
+   */
+  public int getLayer() {
+    return _layer;
+  }
+  
+  /**
+   * Returns stereo layer this object belongs to. 
+   * Layers that form stereo pairs belong to the same stereo layer.
+   */
+  public int getSuperLayer() {
+    return _superLayer;
+  }
+  
+  /**
+   * Returns <tt>BarrelEndcapFlag</tt> describing this object.
+   */
+  public BarrelEndcapFlag getBarrelEndcapFlag() {
+    if (_sd.isBarrel()) {
+      return BarrelEndcapFlag.BARREL;
+    } else {
+      double z = _de.getGeometry().getPosition().z();
+      if (z > Double.MIN_VALUE) {
+        return BarrelEndcapFlag.ENDCAP_NORTH;
+      } else {
+        return BarrelEndcapFlag.ENDCAP_SOUTH;
+      }
+    }
+  }
+
+  /**
+   * Returns <tt></tt> this object belongs to.
+   */
+  public Subdetector getSubdetector() {
+    return _sd;
+  }
+
+  
+// -- Getters :  ---------------------------------------------------------------
+  
+  /**
+   * Returns {@link IDetectorElement} object this sensor belongs to.
+   */
+  public IDetectorElement getDetectorElement() {return _de;}
+  
+  /**
+   * Returns {@link SensorType} object representing the geometry of this sensor.
+   */
+  public SensorType getType() {return _type;}
+  
+  /**
+   * Returns a unique integer ID associated with this sensor.
+   */
+  public int getID() {return _id;}
+  
+  /** 
+   * Returns reference frame associated with this sensor.
+   */
+  public IRefFrame getRefFrame() {return _sf;}
+  
+  /** 
+   * Returns cartesian reference frame associated with the specified position on this sensor.
+   * Usually, if the reference frame of this sensor is itself cartesian, it is returned by this
+   * method, independent of the specified position.
+   */
+  public IRefFrame getLocalFrame(Hep3Vector position) {
+    return (_lf == null) ? _type.getLocalFrame(_sf, position) : _lf ;
+  }
+
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
SensorConverter.java added at 1.1
diff -N SensorConverter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SensorConverter.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,81 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.util.*;
+
+import hep.graphics.heprep.HepRepFactory;
+import hep.graphics.heprep.HepRepInstance;
+import hep.graphics.heprep.HepRepInstanceTree;
+import hep.graphics.heprep.HepRepType;
+import hep.graphics.heprep.HepRepTypeTree;
+import hep.physics.vec.Hep3Vector;
+import java.awt.Color;
+import org.lcsim.detector.DetectorElementStore;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IDetectorElementContainer;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.identifier.Identifier;
+import org.lcsim.detector.solids.IPolyhedron;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Point3D;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.geometry.Subdetector;
+import org.lcsim.geometry.subdetector.SiTrackerBarrel;
+import org.lcsim.geometry.subdetector.SiTrackerEndcap;
+import org.lcsim.util.heprep.HepRepCollectionConverter;
+import org.lcsim.util.heprep.LCSimHepRepConverter;
+import org.lcsim.contrib.onoprien.geom.tracker.lib.sensortype.WedgeSideParallel;
+import org.lcsim.contrib.onoprien.util.transform.IRefFrame;
+
+/**
+ * HepRep converter for {@link Sensor}.
+ *
+ * @author D. Onoprienko
+ * @version $Id: SensorConverter.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public class SensorConverter implements HepRepCollectionConverter{
+  
+  /**
+   * Creates a new instance of SensorConverter
+   */
+  public SensorConverter() {
+  }
+  
+  
+  public boolean canHandle(Class k) {
+    return (Sensor.class.isAssignableFrom(k));
+  }
+  
+  public void convert(EventHeader event, List collection, HepRepFactory factory, HepRepTypeTree typeTree, HepRepInstanceTree instanceTree) {
+    
+    LCMetaData data = event.getMetaData(collection);
+    String collection_name = data.getName();
+    
+    HepRepType typeS = factory.createHepRepType(typeTree,collection_name);
+    typeS.addAttValue("layer",LCSimHepRepConverter.HITS_LAYER);
+    typeS.addAttValue("drawAs","prism");
+    typeS.addAttValue("color",Color.LIGHT_GRAY);
+    
+    for (Sensor sensor : (List<Sensor>) collection) {
+      
+      SensorType sType = sensor.getType();
+      if (!(sType instanceof WedgeSideParallel)) continue;
+      IRefFrame sensorFrame = sensor.getRefFrame();
+      
+      List<Hep3Vector> corners = sType.getCorners();
+      
+      //change order for HepRep
+      Collections.swap(corners, 2, 3);
+      
+      HepRepInstance instance = factory.createHepRepInstance(instanceTree, typeS);
+      
+      for (Hep3Vector corner : corners) {
+        Hep3Vector p = sensorFrame.transformFrom(corner);
+        factory.createHepRepPoint(instance,p.x(),p.y(),p.z());
+      }
+
+    }
+  }
+  
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
SensorType.java added at 1.1
diff -N SensorType.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SensorType.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,74 @@
+package org.lcsim.contrib.onoprien.geom.tracker;
+
+import java.util.List;
+
+import hep.physics.vec.Hep3Vector;
+
+import org.lcsim.contrib.onoprien.data.ITrackerHit;
+import org.lcsim.contrib.onoprien.util.transform.IRefFrame;
+
+/**
+ * Any class that implements this interface defines a particular shape of a sensor 
+ * and its segmentation into channels (strips or pixels in case of silicon sensors).
+ *
+ * @author D.Onoprienko
+ * @version $Id: SensorType.java,v 1.1 2009/07/08 15:59:38 onoprien Exp $
+ */
+public interface SensorType {
+
+  /**
+   * Converts a point in local sensor coordinates to channel ID.
+   * Returns -1 if the point is outside of sensor sensitive area.
+   */
+  int getChannelID(Hep3Vector point);
+  
+  /** Returns maximum channel ID on this sensor. */
+  int getMaxChannelID();
+  
+  /** Returns <tt>true</tt> if channel with this ID exists on this sensor. */
+  boolean isValidChannelID(int channelID);
+  
+  /**
+   * Returns position of the center of a given channel, in local sensor coordinates.
+   */
+  Hep3Vector getChannelPosition(int channelID);
+  
+  /** Returns dimensions of a given channel along U, V, W. */
+  Hep3Vector getChannelDimensions(int channelID);
+  
+  /**
+   * Returns the type of hits produced by this type of sensor.
+   */
+  ITrackerHit.Type getHitType();
+  
+  /**
+   * Returns local cartesian reference frame at the specified position in local sensor coordinates.
+   */
+  IRefFrame getLocalFrame(IRefFrame sensorFrame, Hep3Vector position);
+  
+  /**
+   * Returns ID of a channel obtained by shifting the given channel by the given
+   * number of channels in the given direction along the local reference frame axis. 
+   * Returns <tt>-1</tt> if shifting puts the point outside of the sensor boundaries.
+   * Throws <tt>IllegalArgumentException</tt> if this type of sensor does not have a
+   * concept of a neighbor in the given direction. 
+   *
+   * @param channelID  ID of the original channel
+   * @param shiftV     move in <tt>U</tt> direction by <tt>shiftU</tt> channels
+   * @param shiftU     move in <tt>V</tt> direction by <tt>shiftV</tt> channels
+   * @param shiftW     move in <tt>W</tt> direction by <tt>shiftW</tt> channels
+   */
+  int getNeighbor(int channelID, int shiftU, int shiftV, int shiftW);
+  
+  /**
+   * Returns a list of IDs of all immediate neighbor channels.
+   */
+  List<Integer> getNeighbors(int channelID);
+  
+  /**
+   * Returns a list of vectors that correspond to corners of the sensor, in sensor reference frame.
+   * Useful for drawing sensors and event display.
+   */
+  List<Hep3Vector> getCorners();
+  
+}

lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/tracker
package-info.java added at 1.1
diff -N package-info.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ package-info.java	8 Jul 2009 15:59:38 -0000	1.1
@@ -0,0 +1,4 @@
+/**
+ * Classes that handle virtual segmentation of the tracker.
+ */
+package org.lcsim.contrib.onoprien.geom.tracker;
CVSspam 0.2.8