16 added files
lcsim-contrib/src/main/java/org/lcsim/contrib/onoprien/geom/calorimeter
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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