View Javadoc

1   package org.lcsim.recon.tracking.vsegment.digitization;
2   
3   import java.util.*;
4   
5   import org.lcsim.detector.DetectorElementStore;
6   import org.lcsim.detector.IDetectorElementContainer;
7   import org.lcsim.detector.identifier.IIdentifier;
8   import org.lcsim.detector.identifier.Identifier;
9   import org.lcsim.event.EventHeader;
10  import org.lcsim.event.SimTrackerHit;
11  import org.lcsim.recon.cat.util.NoSuchParameterException;
12  import org.lcsim.units.clhep.SystemOfUnits;
13  import org.lcsim.util.Driver;
14  
15  import org.lcsim.recon.tracking.vsegment.geom.SegmentationManager;
16  import org.lcsim.recon.tracking.vsegment.geom.Sensor;
17  import org.lcsim.recon.tracking.vsegment.hit.DigiTrackerHit;
18  import org.lcsim.recon.tracking.vsegment.hit.base.DigiTrackerHitComposite;
19  import org.lcsim.recon.tracking.vsegment.mctruth.MCTruth;
20  
21  /**
22   * Driver that handles conversion of {@link SimTrackerHit} objects collections
23   * found in a simulated event into a collection of {@link DigiTrackerHit} objects. 
24   * <p>
25   * The actual conversion of a group of <tt>SimTrackerHits</tt> produced by a particle
26   * crossing sensitive detector into a group <tt>DigiTrackerHits</tt> is done by the
27   * {@link SimToDigiConverter} object supplied in the constructor. The driver handles reading and
28   * writing collections, dividing <tt>SimTrackerHits</tt> into groups corresponding to 
29   * single particle-sensor crossings, passing those groups to the <tt>SimToDigiConverter</tt>,
30   * and combining <tt>DigiTrackerHits</tt> corresponding to the same channel.
31   * <p>
32   * On input, lists of <tt>SimTrackerHits</tt> with names added through calls to 
33   * <tt>set("ADD_INPUT_LIST_NAME", name)</tt> will be processed. If no input list names have 
34   * been added, all <tt>SimTrackerHit</tt> lists found in the event will be processed.
35   * <p>
36   * On output, a map of {@link Sensor} objects to lists of created <tt>DigiTrackerHits</tt>
37   * is added to the event, with a name supplied through a call to <tt>set("OUTPUT_MAP_NAME", name)</tt>
38   * (type <tt>HashMap&lt;Sensor, ArrayList&lt;DigiTrackerHit&gt;&gt;</tt>).
39   * 
40   * 
41   * 
42   * @author D.Onoprienko
43   * @version $Id: SimToDigiDriver.java,v 1.1 2008/12/06 21:53:43 onoprien Exp $
44   */
45  public class SimToDigiDriver extends Driver {
46    
47  // -- Constructors :  ----------------------------------------------------------
48    
49    /**
50     * Create digitization driver with the given <tt>SimToDigiConverter</tt> and the default
51     * distance cut of 200 microns.
52     */
53    public SimToDigiDriver(SimToDigiConverter converter) {
54      _converter = converter;
55      set("DISTANCE_CUT", 200.*SystemOfUnits.micrometer);
56    }
57    
58  // -- Getters :  ---------------------------------------------------------------
59    
60    /** Returns <tt>SimToDigiConverter</tt> object used by this driver. */
61    public SimToDigiConverter getConverter() {return _converter;}
62    
63  // -- Setters :  ---------------------------------------------------------------
64    
65    /** Set <tt>SimToDigiConverter</tt> to be used by this driver. */
66    public void setConverter(SimToDigiConverter converter) {_converter = converter;}
67    
68    /**
69     * Set any <tt>double</tt> parameter.
70     * The following parameters can be set with this method:
71     * <p><dl>
72     * <dt>"DISTANCE_CUT"</dt> <dd>Put <tt>SimTrackerHit</tt>s that are less than this
73     *                           distance apart and produced by the same <tt>MCParticle</tt>
74     *                           into a group supplied in a single call to <tt>SimToDigiConverter</tt>.
75     *                           Default: 200 microns.</dd></dl>
76     * 
77     * 
78     * @param name   Name of parameter to be set (case is ignored).
79     * @param value  Value to be assigned to the parameter.
80     * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
81     *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
82     *         and set their own parameters.
83     */
84    public void set(String name, double value) {
85      if (name.equalsIgnoreCase("DISTANCE_CUT")) {
86        _distCut2 = value*value;
87      } else {
88        throw new NoSuchParameterException(name, this.getClass());
89      }
90    }
91    
92    /** 
93     * Set any <tt>String</tt> parameter. 
94     * The following parameters can be set with this method:
95     * <p><dl>
96     * <dt>"ADD_INPUT_LIST_NAME"</dt> <dd>Add a name of input list of simulated hits
97     *                 (type <tt>List<SimTrackerHit></tt>). 
98     *                 Default: <tt>null</tt> (all lists will be processed).<dd>
99     * <dt>"OUTPUT_MAP_NAME"</dt> <dd>Name of ouitput collection of hist
100    *             (type <tt>HashMap<Sensor, ArrayList<DigiTrackerHit>></tt>). 
101    *             Default: "DigiHits".<dd></dl>
102    *
103    * @param name   Name of parameter to be set. Case is ignored.
104    * @param value  Value to be assigned to the parameter.
105    * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
106    *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
107    *         and set their own parameters.
108    */
109   public void set(String name, String value) {
110     if (name.equalsIgnoreCase("ADD_INPUT_LIST_NAME")) {
111       if (_inListNames == null) _inListNames = new ArrayList<String>(5);
112       _inListNames.add(value);
113     } else if (name.equalsIgnoreCase("OUTPUT_MAP_NAME")) {
114       _outMapName = value;
115     } else {
116       throw new NoSuchParameterException(name, this.getClass());
117     }
118   }
119   
120 // -- Processing event :  ------------------------------------------------------ 
121 
122   public void process(EventHeader event) {
123     
124     // Process children if any
125     
126     super.process(event);
127     
128     // Fetch MCTruth object if present in the event:
129     
130     MCTruth mcTruth = null;
131     try {
132       mcTruth = (MCTruth) event.get("MCTruth");
133     } catch (IllegalArgumentException x) {}
134     
135     // Fetch Segmentation manager:
136     
137     SegmentationManager segMan = (SegmentationManager) event.get("SegmentationManager");
138     _converter.setSegmentationManager(segMan);
139  
140     // Make a list of SimTrackerHit collections to process :
141     
142     List<List<SimTrackerHit>> collections;
143 
144     if (_inListNames == null) {
145       collections = event.get(SimTrackerHit.class);
146     } else {
147       collections = new ArrayList<List<SimTrackerHit>>(_inListNames.size());
148       for (String name : _inListNames) {
149         try {
150           collections.add(event.get(SimTrackerHit.class, name));
151         } catch (IllegalArgumentException x) {}
152       }
153     }
154     
155     // Create output map :
156     
157     HashMap<Sensor, ArrayList<DigiTrackerHit>> outMap = new HashMap<Sensor, ArrayList<DigiTrackerHit>>();
158 
159     // Loop over input collections :
160     
161     for (List<SimTrackerHit> hitList : collections) {
162       
163       // Split hit lists into groups produced by a single particle-sensor crossing
164       
165       LinkedList<LinkedList<SimTrackerHit>> groupList = new LinkedList<LinkedList<SimTrackerHit>>();
166       for (SimTrackerHit hit : hitList) {
167         
168         // associate DetectorElements with SimTrackerHits
169         if (hit.getDetectorElement() == null) {
170           IIdentifier hitId = new Identifier(hit.getCellID());
171           IDetectorElementContainer deHit = DetectorElementStore.getInstance().find(hitId);
172           if (deHit.size() == 0) {
173             throw new RuntimeException("No DetectorElement found for id <"+hitId.toString()+">.");
174           }
175           hit.setDetectorElement( deHit.get(0) );
176         }
177 
178         boolean found = false;
179         for (LinkedList<SimTrackerHit> group : groupList) {
180           SimTrackerHit lastHit = group.getLast();
181           if (hit.getMCParticle() == lastHit.getMCParticle() && hit.getLayer() == lastHit.getLayer()) {
182             double[] p1 = lastHit.getPoint();
183             double[] p2 = hit.getPoint();
184             if ((p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1]) + (p1[2]-p2[2])*(p1[2]-p2[2]) < _distCut2) {
185               found = true;
186               group.addLast(hit);
187               break;
188             }
189           }
190         }
191         if (! found) {
192           LinkedList<SimTrackerHit> newGroup = new LinkedList<SimTrackerHit>();
193           newGroup.add(hit);
194           groupList.addFirst(newGroup);
195         }
196       }
197       
198       // Call SimToDigiConverter for each group, add resulting digis to the output map
199       
200       for (LinkedList<SimTrackerHit> group : groupList) {
201         
202         List<DigiTrackerHit> digiGroup = _converter.convert(group);
203         if (mcTruth != null) mcTruth.addSimGroup(group, digiGroup);
204         
205         Sensor prevSensor = null;
206         ArrayList<DigiTrackerHit> digiList = null;
207         for (DigiTrackerHit digi : digiGroup) {
208           Sensor sensor = digi.getSensor();
209           if (sensor != prevSensor) {
210             prevSensor = sensor;
211             digiList = outMap.get(sensor);
212           }
213           if (digiList == null) {
214             digiList = new ArrayList<DigiTrackerHit>();
215             outMap.put(sensor, digiList);
216           }
217           digiList.add(digi);
218         }
219       }
220 
221     } // end of loop over input collections
222     
223     // Combine and sort DigiTrackerHits in each list
224     
225     for (ArrayList<DigiTrackerHit> dList : outMap.values()) {
226       Collections.sort(dList);
227       DigiTrackerHit[] copy = dList.toArray(new DigiTrackerHit[dList.size()+1]);
228       dList.clear();
229       int previousChannel = -1;
230       DigiTrackerHit previousHit = null;
231       DigiTrackerHitComposite compHit = null;
232       for (DigiTrackerHit hit : copy) {
233         if (hit == null) {
234           if (compHit == null) {
235             if (previousHit != null) dList.add(previousHit);
236           } else {
237             compHit.trimToSize();
238             dList.add(compHit);
239           }
240           break;
241         }
242         int channelID = hit.getChannel();
243         if (channelID == previousChannel) {
244           if (compHit == null) {
245             compHit = new DigiTrackerHitComposite();
246             compHit.addHit(previousHit);
247           }
248           compHit.addHit(hit);
249         } else {
250           if (compHit == null) {
251             if (previousHit != null) dList.add(previousHit);
252           } else {
253             compHit.trimToSize();
254             dList.add(compHit);
255             compHit = null;
256           }
257         }
258         previousHit = hit;
259         previousChannel = channelID;
260       }
261       dList.trimToSize();
262     }
263     
264     // Put the map back into the event
265     
266     event.put(_outMapName, outMap);
267     
268   }
269   
270 // -- Private parts :  ---------------------------------------------------------
271   
272   protected SimToDigiConverter _converter;
273   
274   protected ArrayList<String> _inListNames;
275   protected String _outMapName;
276   
277   protected double _distCut2;
278 }