View Javadoc

1   package org.lcsim.recon.tracking.vsegment.geom;
2   
3   import java.lang.ref.SoftReference;
4   import java.util.*;
5   
6   import hep.physics.vec.BasicHep3Vector;
7   import hep.physics.vec.Hep3Vector;
8   import org.lcsim.conditions.ConditionsListener;
9   import org.lcsim.conditions.ConditionsEvent;
10  import org.lcsim.conditions.ConditionsManager;
11  import org.lcsim.conditions.ConditionsManager.ConditionsSetNotFoundException;
12  import org.lcsim.geometry.Detector;
13  import org.lcsim.event.EventHeader;
14  import org.lcsim.event.SimTrackerHit;
15  import org.lcsim.recon.cat.util.NoSuchParameterException;
16  import org.lcsim.util.Driver;
17  
18  import org.lcsim.recon.tracking.vsegment.transform.Rotation3D;
19  
20  /**
21   * This class handles creation, caching and run-time access to {@link Sensor} objects and segmentation information.
22   * <p>
23   * Typically, a <tt>Driver</tt> that controls event reconstruction creates an
24   * instance of this class, supplying {@link Segmenter} object that defines virtual 
25   * segmentation of the detector, and adds it to the event processing chain before any
26   * drivers that need access to {@link Sensor}s. See {@link org.lcsim.contrib.onoprien.tracking.ExampleDriver1}
27   * or {@link org.lcsim.contrib.onoprien.tracking.ExampleDriver2}.
28   * <p>
29   * Other drivers that need access to <tt>SegmentationManager</tt> can fetch it from the
30   * event record by calling <tt>event.get("SegmentationManager")</tt>.
31   * <p>
32   * By default, <tt>Sensor</tt> objects are created as needed (that is, when there are hits
33   * in those sensors), and are kept in cache unless JVM starts running out of memory.
34   * If the user needs <tt>Sensor</tt> objects corresponding to all virtual segments of
35   * the detector to be created before data processing, <tt>SegmentationManager</tt>
36   * can be asked to do so by a call to <tt>set("MAKE_SENSORS_ON_DETECTOR_CHANGE", true)</tt>.
37   * It usually makes sense to do this if the user plans to use {@link #getSensors}
38   * method in the future.
39   *
40   * @author D.Onoprienko
41   * @version $Id: SegmentationManager.java,v 1.1 2008/12/06 21:53:43 onoprien Exp $
42   */
43  public class SegmentationManager extends Driver implements ConditionsListener {
44    
45  // -- Constructors, initialization, and cleanup :  -----------------------------
46  
47    /**
48     * Constructs a new instance of SegmentationManager.
49     *
50     * @param segmenter  Segmenter that defines virtual segmentation of the detector.
51     */
52    public SegmentationManager(Segmenter segmenter) {
53      _segmenter = segmenter;
54      _notInitialized = true;
55      _createSensorsOnDetectorChange = true;
56      _sensorWeakMap = new HashMap<Integer, SoftReference<Sensor>>();
57      _cacheStereoRequests = true;
58      _stereoMap = new HashMap<Sensor, List<Sensor>>();
59      ConditionsManager.defaultInstance().addConditionsListener(this);
60    }
61  
62    /** Called by framework whenever <tt>ConditionsEvent</tt> is dispatched by <tt>ConditionsManager</tt>. */
63    public void conditionsChanged(ConditionsEvent event) {
64      _notInitialized = true;
65    }
66  
67    /**
68     * Detector-dependent initialization.
69     * Clears sensor map, calls <tt>detectorChanged(Detector)</tt> methods of all 
70     * segmenters, then assign prefixes to segmenters.
71     */
72    private void detectorChanged() {
73      ConditionsManager conMan = ConditionsManager.defaultInstance();
74      Detector detector = null;
75      try {
76        detector = conMan.getCachedConditions(Detector.class,"compact.xml").getCachedData();
77      } catch (ConditionsSetNotFoundException x) {}
78      if (detector != null) {
79        if (_createSensorsOnDetectorChange) {
80          _sensorWeakMap = null;
81          _sensorMap = new HashMap<Integer, Sensor>();
82        } else {
83          _sensorWeakMap = new HashMap<Integer, SoftReference<Sensor>>();
84          _sensorMap = null;
85        }
86        if (_cacheStereoRequests) _stereoMap = new HashMap<Sensor, List<Sensor>>();
87        _segmenter.detectorChanged(detector);
88        if (_segmenter instanceof AbstractSegmenter) ((AbstractSegmenter)_segmenter).setPrefix(0);
89        if (_createSensorsOnDetectorChange) {
90          List<Integer> sensorIDs = _segmenter.getSensorIDs();
91          for (int sensorID : sensorIDs) {
92            _sensorMap.put(sensorID, _segmenter.getSensor(sensorID));
93          };
94        }
95        _navigator = new Navigator(detector);
96      } else {
97        throw new RuntimeException("SegmentationManager cannot initialize, no Detector");      
98      }
99    }
100 
101 // -- Setters :  ---------------------------------------------------------------
102 
103   /**
104    * Set any <tt>boolean</tt> parameter. 
105    * The following parameters can be set with this method:
106    * <dl>
107    * <dt>"MAKE_SENSORS_ON_DETECTOR_CHANGE"</dt> <dd>If set to <tt>true</tt>, <tt>Sensor</tt>
108    *            objects corresponding to all virtual segments are created whenever the 
109    *            detector information becomes available (or changes), and are kept in memory
110    *            until the end of the job. 
111    *            Default: <tt>true</tt>.</dd>
112    * <dt>"CACHE_STEREO_REQUESTS"</dt> <dd>If set to <tt>true</tt>, the output of calls to
113    *            {@link #getStereoPartners} will be cached. 
114    *            Default: <tt>true</tt>.</dd></dl>
115    * 
116    * @param name   Name of parameter to be set. Case is ignored.
117    * @param value  Value to be assigned to the parameter.
118    * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
119    *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
120    *         and set their own parameters.
121    */
122   public void set(String name, boolean value) {
123     if (name.equalsIgnoreCase("MAKE_SENSORS_ON_DETECTOR_CHANGE")) {
124       _createSensorsOnDetectorChange = value;
125     } else if (name.equalsIgnoreCase("CACHE_STEREO_REQUESTS")) {
126       _cacheStereoRequests = value;
127     } else {
128       throw new NoSuchParameterException(name, this.getClass());
129     }
130   }
131   
132 // -- Getters :  ---------------------------------------------------------------
133   
134   /** 
135    * Returns <tt>Navigator</tt> that provides various convenience methods for use
136    * with <tt>Sensors</tt> created by this <tt>SegmentationManager</tt>.
137    */
138   public Navigator getNavigator() {
139     return _navigator;
140   }
141   
142 // -- Event processing :  ------------------------------------------------------
143 
144   /** Called by framework to process event. */
145   public void process(EventHeader event) {
146     if (_notInitialized) {
147       detectorChanged();
148       _notInitialized = false;
149     }
150     event.put("SegmentationManager", this);
151     super.process(event);
152   }
153   
154 // -- Sensor and channel lookup, ID conversions :  -----------------------------
155   
156   /**
157    * Returns a collection of <tt>Sensors</tt> corresponding to all virtual segments of the detector.
158    */
159   public Collection<Sensor> getSensors() {
160     if (_createSensorsOnDetectorChange) {
161       return _sensorMap.values();
162     } else {
163       List<Integer> sensorIDs = _segmenter.getSensorIDs();
164       ArrayList<Sensor> sensors = new ArrayList<Sensor>(sensorIDs.size());
165       for (int sensorID : sensorIDs) sensors.add(getSensor(sensorID));
166       return sensors;
167     }
168   }
169 
170   /**
171    * Returns {@link Sensor} object corresponding to the given sensor ID.
172    */
173   public Sensor getSensor(int sensorID) {
174     Sensor sensor = null;
175     if (_createSensorsOnDetectorChange) {
176       sensor = _sensorMap.get(sensorID);
177     } else {
178       SoftReference<Sensor> ref = _sensorWeakMap.get(sensorID);
179       if (ref != null) sensor = ref.get();
180       if (sensor == null) {
181         sensor = _segmenter.getSensor(sensorID);
182         if (sensor != null) _sensorWeakMap.put(sensorID, new SoftReference<Sensor>(sensor));
183       }
184     }
185     return sensor;
186   }
187 
188   /** 
189    * Returns channel ID given sensor and global position.
190    * Returns <tt>-1</tt> if <tt>position</tt> does not belong to this sensor.
191    */
192   public int getChannelID(Sensor sensor, Hep3Vector position) {
193     return sensor.getType().getChannelID(sensor.globalToLocal(position));
194   }
195 
196   /** 
197    * Returns channel ID given sensor and global position extracted from the supplied
198    * {@link SimTrackerHit} object.
199    * Returns <tt>-1</tt> if the position does not belong to this sensor.
200    */
201   public int getChannelID(Sensor sensor, SimTrackerHit hit) {
202     Hep3Vector position = new BasicHep3Vector(hit.getPoint());
203     return getChannelID(sensor, position);
204   }
205 
206   /** 
207    * Returns channel ID given sensor ID and global position.
208    * Returns <tt>-1</tt> if <tt>sensorID</tt> is invalid, or <tt>position<tt>
209    * does not belong to this sensor.
210    */
211   public int getChannelID(int sensorID, Hep3Vector position) {
212     Sensor sensor = getSensor(sensorID);
213     return (sensor == null) ? -1 : getChannelID(sensor, position);
214   }
215   
216   /** 
217    * Converts cell ID and position obtained from {@link SimTrackerHit} object to 
218    * sensor ID, and returns {@link Sensor} object corresponding to this ID.
219    */
220   public Sensor getSensor(SimTrackerHit hit) {
221     int id = getSensorID(hit);
222     return (id == -1) ? null : getSensor(id);
223   }
224 
225   /** 
226    * Converts cell ID and position obtained from {@link SimTrackerHit} object to sensor ID.
227    * FIXME: should be just return _segmenter.getSensorID(hit);
228    * The rest is a workaround for Detector being created twice bug.
229    */
230   public int getSensorID(SimTrackerHit hit) {
231     return _segmenter.getSensorID(hit);
232   }
233 
234 // -- Getting info about Sensors :  --------------------------------------------
235 
236   /**
237    * Returns a list of <tt>Sensors</tt> that might contain hits that should be combined
238    * with hits in the <tt>Sensor</tt> supplied as an argument to form stereo pairs. 
239    * If the <tt>Segmenter</tt> used by this <tt>SegmentationManager</tt> does not support 
240    * stereo partner lookup, an empty list is returned.
241    */  
242   public List<Sensor> getStereoPartners(Sensor sensor) {
243     List<Sensor> partners = null;
244     if (_cacheStereoRequests) partners = _stereoMap.get(sensor);
245     if (partners == null) {
246       List<Integer> partnerIDs = _segmenter.getStereoPartners(sensor.getID());
247       if (partnerIDs == null) return null;
248       partners = new ArrayList<Sensor>(partnerIDs.size());
249       for (int sensorID : partnerIDs) partners.add(getSensor(sensorID));
250     }
251     if (_cacheStereoRequests) _stereoMap.put(sensor, partners);
252     return partners;
253   }
254   
255 // -- Static access to segmentation manager :  ---------------------------------
256   
257   /** Set default segmentation manager. */
258   static public void setDefaultInstance(SegmentationManager segMan) {
259     _defaultSegMan = segMan;
260   }
261   
262   /**
263    * Returns segmentation manager that has been previously set with a call to
264    * {@link #setDefaultInstance(SegmentationManager)} method.
265    */
266   static public SegmentationManager defaultInstance() {
267     return _defaultSegMan;
268   }
269   
270 // -- Private parts :  ---------------------------------------------------------
271   
272   static private SegmentationManager _defaultSegMan;
273   private boolean _notInitialized;
274   
275   private HashMap<Integer, SoftReference<Sensor>> _sensorWeakMap;
276   private HashMap<Integer, Sensor> _sensorMap;
277   
278   private Segmenter _segmenter;
279   private Navigator _navigator;
280   
281   private boolean _createSensorsOnDetectorChange;
282 
283   private boolean _cacheStereoRequests;
284   private HashMap<Sensor, List<Sensor>> _stereoMap;
285 
286 }