View Javadoc

1   package org.lcsim.detector;
2   
3   import hep.physics.vec.Hep3Vector;
4   
5   import java.util.ArrayList;
6   import java.util.List;
7   
8   import org.lcsim.detector.identifier.IExpandedIdentifier;
9   import org.lcsim.detector.identifier.IIdentifier;
10  import org.lcsim.detector.identifier.IIdentifierHelper;
11  import org.lcsim.detector.identifier.Identifier;
12  import org.lcsim.detector.solids.Inside;
13  
14  /**
15   * Implementation of {@link IDetectorElement}.
16   * 
17   * @author Jeremy McCormick
18   * @version $Id: DetectorElement.java,v 1.48 2011/02/25 03:09:38 jeremy Exp $
19   */
20  public class DetectorElement implements IDetectorElement
21  {
22      private IDetectorElementContainer children;
23      private IGeometryInfo geometry;
24      private IDetectorElement parent;
25      private IIdentifier id;
26      private IIdentifierHelper helper;
27      private IParameters parameters;
28      private IReadout readout;
29      private String name;
30  
31      /**
32       * For subclasses.
33       */
34      protected DetectorElement()
35      {
36      }
37  
38      /**
39       * Creates a DetectorElement with complete arguments, including a parent,
40       * geometry support as a String, and an
41       * {@link org.lcsim.detector.IIdentifier}.
42       * 
43       * @param name The name of this DetectorElement.
44       * @param parent The parent DetectorElement.
45       * @param support The geometry support as a "/" delimited String.
46       * @param id The DetectorElement's identifier.
47       */
48      public DetectorElement(String name, IDetectorElement parent, IPhysicalVolumePath support, IIdentifier id)
49      {
50          setup(name, parent, support, id);
51          register();
52      }
53  
54      /**
55       * Create a DE with a parent and support in the geometry tree.
56       * 
57       * @param name
58       * @param parent
59       * @param support
60       */
61      public DetectorElement(String name, IDetectorElement parent, IPhysicalVolumePath support)
62      {
63          setup(name, parent, support, null);
64          register();
65      }
66  
67      /**
68       * Create a DE with complete arguments, including a parent DE, geometry
69       * support, and an id.
70       * 
71       * @param name
72       * @param parent
73       * @param support
74       */
75      public DetectorElement(String name, IDetectorElement parent, String support)
76      {
77          setup(name, parent, support, id);
78          register();
79      }
80  
81      /**
82       * Create a DE with complete arguments, including a parent DE, string of
83       * path, and an id.
84       * 
85       * @param name
86       * @param parent
87       * @param support
88       */
89      public DetectorElement(String name, IDetectorElement parent, String support, IIdentifier id)
90      {
91          setup(name, parent, support, id);
92          register();
93      }
94  
95      /**
96       * Create a DE with a parent but no support in the geometry, e.g. a ghost
97       * volume.
98       * 
99       * @param name
100      * @param parent
101      */
102     public DetectorElement(String name, IDetectorElement parent)
103     {
104         setup(name, parent, (IPhysicalVolumePath) null, null);
105         register();
106     }
107 
108     /**
109      * Create with a name, parent, and identifier.
110      */
111     public DetectorElement(String name, IDetectorElement parent, IIdentifier id)
112     {
113         setup(name, parent, (IPhysicalVolumePath) null, id);
114         register();
115     }
116 
117     /**
118      * Create a DE with no parent and no support. If this constructor is used,
119      * then an external routine must setup the parent, support, and/or id later.
120      * 
121      * @param name
122      */
123     public DetectorElement(String name)
124     {
125         this.name = name;
126         register();
127     }
128 
129     public String getName()
130     {
131         return name;
132     }
133 
134     /**
135      * Set the parent IDetectorElement. Once this has been set, additional calls
136      * to this method will cause a RuntimeException.
137      * 
138      * @param parent The parent IDetectorElement.
139      * @throws RuntimeException If the parent IDetectorElement is already set.
140      * @throws IllegalArgumentException If @param parent is null.
141      */
142     public void setParent(IDetectorElement parent)
143     {
144         if (this.parent != null)
145         {
146             throw new RuntimeException("The IDetectorElement <" + getName() + "> already has a parent!");
147         }
148 
149         if (parent == null)
150         {
151             throw new IllegalArgumentException("The parent IDetectorElement is null!");
152         }
153 
154         this.parent = parent;
155         ((DetectorElement) parent).addChild(this);
156     }
157 
158     /**
159      * Register this IDetectorElement with the DetectorElementStore.
160      */
161     private void register()
162     {
163         if (!DetectorElementStore.getInstance().contains(this))
164         {
165             DetectorElementStore.getInstance().add(this);
166         }
167     }
168 
169     private void checkName(String name)
170     {
171         if (name == null)
172             throw new IllegalArgumentException("Name argument is null!");
173 
174         if (name.length() == 0)
175             throw new IllegalArgumentException("Name is zero length!");
176 
177         if (name.trim().length() == 0)
178             throw new IllegalArgumentException("Name contains only white space!");
179 
180         if (name.contains("/"))
181             throw new IllegalArgumentException("Name contains a '/', which is not a legal character!");
182     }
183 
184     private void setup(String name, IDetectorElement parent, IPhysicalVolumePath support, IIdentifier id)
185     {
186         this.name = name;
187 
188         checkName(this.name);
189 
190         if (parent != null)
191         {
192             setParent(parent);
193         }
194 
195         if (support != null)
196         {
197             setSupport(support);
198         }
199 
200         if (id != null)
201         {
202             setIdentifier(id);
203         }
204     }
205 
206     private void setup(String name, IDetectorElement parent, String support, IIdentifier id)
207     {
208         this.name = name;
209 
210         checkName(this.name);
211 
212         if (parent != null)
213         {
214             setParent(parent);
215         }
216 
217         if (support != null)
218         {
219             setSupport(support);
220         }
221 
222         if (id != null)
223         {
224             setIdentifier(id);
225         }
226     }
227 
228     public void setSupport(IPhysicalVolumePath support)
229     {
230         createGeometryInfo(support);
231     }
232 
233     public void setSupport(String path)
234     {
235         createGeometryInfo(path);
236     }
237 
238     private void createGeometryInfo(IPhysicalVolumePath path)
239     {
240         geometry = new GeometryInfo(this, path);
241     }
242 
243     private void createGeometryInfo(String path)
244     {
245         IPhysicalVolumeNavigator nav = PhysicalVolumeNavigatorStore.getInstance().getDefaultNavigator();
246         geometry = new GeometryInfo(this, nav.getPath(path));
247     }
248 
249     protected void addChild(IDetectorElement child)
250     {
251         if (children == null)
252         {
253             children = new DetectorElementContainer();
254         }
255         children.add(child);
256     }
257 
258     public IDetectorElementContainer getChildren()
259     {
260         if (children == null)
261         {
262             children = new DetectorElementContainer();
263         }
264         return children;
265     }
266 
267     public boolean hasChildren()
268     {
269         if (children == null)
270         {
271             return false;
272         }
273         return children.size() != 0;
274     }
275 
276     public IGeometryInfo getGeometry()
277     {
278         return geometry;
279     }
280 
281     public IDetectorElement getParent()
282     {
283         return parent;
284     }
285 
286     public IExpandedIdentifier getExpandedIdentifier()
287     {
288         try
289         {
290             return getIdentifierHelper().unpack(id);
291         }
292         catch (Exception x)
293         {
294             throw new RuntimeException(x);
295         }
296     }
297 
298     public IIdentifier getIdentifier()
299     {
300         // FIXME Should return null if no Id.
301         if (id == null)
302         {
303             id = new Identifier();
304         }
305         return id;
306     }
307 
308     public void setIdentifier(IIdentifier id)
309     {
310         this.id = id;
311     }
312 
313     public boolean hasGeometryInfo()
314     {
315         return geometry != null;
316     }
317 
318     public IDetectorElement findDetectorElement(Hep3Vector globalPoint)
319     {
320         IDetectorElement srch = null;
321 
322         if (hasGeometryInfo())
323         {
324             Inside inside = getGeometry().inside(globalPoint);
325             if (inside == Inside.INSIDE)
326             {
327                 srch = this;
328             }
329         }
330 
331         // Look recursively through the children.
332         if (hasChildren())
333         {
334             for (IDetectorElement child : getChildren())
335             {
336                 IDetectorElement childSrch = child.findDetectorElement(globalPoint);
337                 if (childSrch != null)
338                 {
339                     srch = childSrch;
340                 }
341             }
342         }
343 
344         return srch;
345     }
346 
347     public IReadout getReadout()
348     {
349         if (readout == null)
350         {
351             readout = createReadout();
352         }
353         return readout;
354     }
355 
356     public void setReadout(IReadout readout)
357     {
358         this.readout = readout;
359     }
360 
361     public IReadout createReadout()
362     {
363         return new Readout();
364     }
365 
366     public boolean hasReadout()
367     {
368         return this.readout != null;
369     }
370 
371     public IParameters getParameters()
372     {
373         return parameters;
374     }
375 
376     public IDetectorElementContainer getAncestry()
377     {
378         IDetectorElementContainer parents = new DetectorElementContainer();
379 
380         parents.add(this);
381 
382         IDetectorElement par = this.getParent();
383 
384         while (par != null)
385         {
386             parents.add(par);
387             par = par.getParent();
388         }
389 
390         java.util.Collections.reverse(parents);
391 
392         return parents;
393     }
394 
395     public void clearReadouts()
396     {
397         if (hasReadout())
398         {
399             readout.clear();
400         }
401 
402         if (hasChildren())
403         {
404             for (IDetectorElement child : getChildren())
405             {
406                 child.clearReadouts();
407             }
408         }
409     }
410 
411     public boolean isDescendant(IDetectorElement de)
412     {
413         boolean isDesc = false;
414         if (hasChildren())
415         {
416             if (children.contains(de))
417             {
418                 return isDesc = true;
419             }
420             else
421             {
422                 for (IDetectorElement child : children)
423                 {
424                     isDesc = child.isDescendant(de);
425                     if (isDesc)
426                         break;
427                 }
428             }
429         }
430         return isDesc;
431     }
432 
433     /**
434      * Set the {@link IIdentifierHelper} for encoding and decoding identifiers
435      * of this DetectorElement.
436      * 
437      * @param helper The IdentifierHelper to be assigned.
438      */
439     public void setIdentifierHelper(IIdentifierHelper helper)
440     {
441         this.helper = helper;
442     }
443 
444     public IIdentifierHelper getIdentifierHelper()
445     {
446         if (helper == null)
447         {
448             IDetectorElement search = getParent();
449             while (search != null)
450             {
451                 if (search.getIdentifierHelper() != null)
452                     return search.getIdentifierHelper();
453                 search = search.getParent();
454             }
455         }
456 
457         // Might return null if no parent has a helper.
458         return helper;
459     }
460 
461     public void traverseDescendantsPreOrder(IDetectorElementVisitor visitor)
462     {
463         traversePreOrder(this, visitor);
464     }
465 
466     public void traverseDescendantsPostOrder(IDetectorElementVisitor visitor)
467     {
468         traversePostOrder(this, visitor);
469     }
470 
471     private static final void traversePreOrder(IDetectorElement detectorElement, IDetectorElementVisitor visitor)
472     {
473         // Return if done.
474         if (visitor.isDone())
475         {
476             return;
477         }
478 
479         // Visit this node.
480         visitor.visit(detectorElement);
481 
482         // Recursively traverse the daughters.
483         if (detectorElement.hasChildren())
484         {
485             for (IDetectorElement child : detectorElement.getChildren())
486             {
487                 traversePreOrder(child, visitor);
488             }
489         }
490     }
491 
492     private static final void traversePostOrder(IDetectorElement detectorElement, IDetectorElementVisitor visitor)
493     {
494         // Return if done.
495         if (visitor.isDone())
496         {
497             return;
498         }
499 
500         // Recursively traverse the daughters.
501         if (detectorElement.hasChildren())
502         {
503             for (IDetectorElement child : detectorElement.getChildren())
504             {
505                 traversePreOrder(child, visitor);
506             }
507         }
508 
509         // Visit this node.
510         visitor.visit(detectorElement);
511     }
512 
513     public void traverseAncestors(IDetectorElementVisitor visitor)
514     {
515         IDetectorElement detelem = this;
516         while (detelem != null)
517         {
518             visitor.visit(detelem);
519             detelem = detelem.getParent();
520         }
521     }
522 
523     private class TypeSearch<T extends IDetectorElement> implements IDetectorElementVisitor
524     {
525         Class<T> klass;
526         List<T> results = new ArrayList<T>();
527 
528         TypeSearch(Class<T> klass)
529         {
530             this.klass = klass;
531         }
532 
533         public void visit(IDetectorElement detectorElement)
534         {
535             if (klass.isInstance(detectorElement))
536             {
537                 results.add(klass.cast(detectorElement));
538             }
539         }
540 
541         public List<T> getResult()
542         {
543             return results;
544         }
545 
546         public boolean isDone()
547         {
548             return false;
549         }
550     }
551 
552     public <T extends IDetectorElement> List<T> findAncestors(Class<T> klass)
553     {
554         TypeSearch<T> search = new TypeSearch<T>(klass);
555         traverseAncestors(search);
556         return search.getResult();
557     }
558 
559     public <T extends IDetectorElement> List<T> findDescendants(Class<T> klass)
560     {
561         TypeSearch<T> search = new TypeSearch<T>(klass);
562         traverseDescendantsPreOrder(search);
563         return search.getResult();
564     }
565 
566     public boolean isAncestor(IDetectorElement de)
567     {
568         return getAncestry().contains(de);
569     }
570 
571     public void setParameters(IParameters parameters)
572     {
573         if (parameters == null)
574         {
575             throw new IllegalArgumentException("The parameters object is null.");
576         }
577         this.parameters = parameters;
578     }
579 
580     /**
581      * Default implementation of
582      * {@link IDetectorElement#findDetectorElement(IIdentifier)}. Specific types
583      * of {@link IDetectorElement}s can override the default scheme.
584      */
585     public IDetectorElementContainer findDetectorElement(IIdentifier id)
586     {
587         return DetectorElementStore.getInstance().find(id);
588     }
589 
590     public IDetectorElement findDetectorElement(String pathString)
591     {
592         return findDetectorElement(pathString.split("/"));
593     }
594 
595     public IDetectorElement findDetectorElement(String[] path)
596     {
597         IDetectorElement de = this;
598         for (int i = 0; i < path.length; i++)
599         {
600             //System.out.println("looking up path component <" + path[i] + ">");
601 
602             if (!de.hasChildren() && i != path.length)
603                 throw new RuntimeException("Not enough child DetectorElements for path argument.");
604 
605             IDetectorElementContainer children = de.getChildren();
606 
607             IDetectorElementContainer matches = children.find(path[i]);
608             if (matches.size() > 1)
609                 throw new RuntimeException("Found more than one match for path component <" + path[i] + ">.");
610 
611             // Check if no matches were found.
612             // FIXME Should this throw an exception or just return null?
613             if (matches.size() == 0)
614             {
615                 throw new RuntimeException("A DetectorElement for the path component <" + path[i] + "> was not found.");
616             }
617 
618             de = matches.get(0);
619         }
620         return de;
621     }
622 
623     public IDetectorElement getTop()
624     {
625         IDetectorElement top;
626         if (this.getParent() == null)
627             return this;
628         else
629             top = this.getParent();
630 
631         while (true)
632         {
633             if (top.getParent() == null)
634                 break;
635             top = top.getParent();
636         }
637         return top;
638     }
639 
640     public boolean isSensitive()
641     {
642         if (!hasGeometryInfo())
643             return false;
644         IPhysicalVolume pv = getGeometry().getPhysicalVolume();
645         if (pv != null)
646             return pv.isSensitive();
647         else
648             return false;
649     }
650     
651     public void initialize() {
652     }
653 }