View Javadoc

1   package org.lcsim.detector.converter.compact;
2   
3   import java.io.IOException;
4   import java.lang.reflect.Modifier;
5   import java.util.HashMap;
6   import java.util.Map;
7   import java.util.Set;
8   
9   import org.jdom.Document;
10  import org.jdom.Element;
11  import org.jdom.JDOMException;
12  import org.lcsim.detector.DetectorElement;
13  import org.lcsim.detector.DetectorIdentifierHelper.SystemMap;
14  import org.lcsim.detector.DetectorStore;
15  import org.lcsim.detector.IDetectorElement;
16  import org.lcsim.detector.ILogicalVolume;
17  import org.lcsim.detector.IPhysicalVolume;
18  import org.lcsim.detector.LogicalVolume;
19  import org.lcsim.detector.ParametersStore;
20  import org.lcsim.detector.PhysicalVolume;
21  import org.lcsim.detector.PhysicalVolumeNavigatorStore;
22  import org.lcsim.detector.converter.lcdd.MaterialElementConverter;
23  import org.lcsim.detector.converter.lcdd.MaterialMixtureConverter;
24  import org.lcsim.detector.converter.lcdd.MaterialsConverter;
25  import org.lcsim.detector.identifier.IIdentifierHelper;
26  import org.lcsim.detector.material.IMaterial;
27  import org.lcsim.detector.material.MaterialStore;
28  import org.lcsim.detector.solids.Box;
29  import org.lcsim.detector.solids.Tube;
30  import org.lcsim.geometry.Detector;
31  import org.lcsim.geometry.compact.Constant;
32  import org.lcsim.geometry.compact.Subdetector;
33  import org.lcsim.geometry.subdetector.PolyconeSupport;
34  import org.reflections.Reflections;
35  
36  public class DetectorConverter implements IDetectorConverter {
37      // Map of class to converter.
38      Map<Class, ISubdetectorConverter> subdetectorConverters = new HashMap<Class, ISubdetectorConverter>();
39  
40      // The parameters converter.
41      ParametersConverter paramCnv = new ParametersConverter();
42  
43      // Materials converters.
44      MaterialsConverter materialCnv = new MaterialsConverter();
45      MaterialElementConverter elemCnv = new MaterialElementConverter();
46      MaterialMixtureConverter matCnv = new MaterialMixtureConverter();
47  
48      // The SystemMap for setting up the IdentifierHelpers.
49      SystemMap sysMap;
50  
51      public IPhysicalVolume convert(Detector detector, Document doc) throws JDOMException, IOException {
52          // Clear out old DetectorStore store before building new detector.
53          DetectorStore.getInstance().clear();
54  
55          // Convert materials.
56          convertMaterials("/org/lcsim/material/elements.xml");
57          convertMaterials("/org/lcsim/material/materials.xml");
58          convertMaterials(doc);
59  
60          // Construct the world volume.
61          IPhysicalVolume pvWorld = buildWorldVolume(detector);
62  
63          // Make the default navigator.
64          PhysicalVolumeNavigatorStore.getInstance().reset();
65          PhysicalVolumeNavigatorStore.getInstance().createDefault(pvWorld);
66  
67          // Set the Detector's DetectorElement.
68          IDetectorElement deDet = new DeDetector(detector);
69          detector.setDetectorElement(deDet);
70  
71          // Construct the tracking volume.
72          buildTrackingVolume(pvWorld.getLogicalVolume(), detector);
73  
74          // Set the world volume.
75          detector.setWorldVolume(pvWorld);
76  
77          // Make the SystemMap.
78          sysMap = makeSystemMap(detector);
79  
80          // Convert Subdetectors including creation of IdentifierHelpers.
81          convertSubdetectors(detector);
82  
83          // Return the world volume.
84          return pvWorld;
85      }
86  
87      public DetectorConverter() {
88      }
89  
90      public void registerSubdetectorConverters() {
91          Reflections reflect = new Reflections("org.lcsim.detector.converter.compact");
92          Set<Class<? extends AbstractSubdetectorConverter>> converters = reflect
93                  .getSubTypesOf(AbstractSubdetectorConverter.class);
94  
95          if (converters.size() == 0) {
96              throw new RuntimeException("No subdetector converter classes were found.");
97          }
98  
99          for (Class<? extends AbstractSubdetectorConverter> converter : converters) {
100             try {
101                 if (!Modifier.isAbstract(converter.getModifiers())) {
102                     this.addSubdetectorConverter(converter.newInstance());
103                 }
104             } catch (InstantiationException | IllegalAccessException e) {
105                 throw new RuntimeException(e);
106             }
107         }
108     }
109 
110     private void addSubdetectorConverter(ISubdetectorConverter s) {
111         // if (subdetectorConverters.get(s.getSubdetectorType()) != null) {
112         // throw new IllegalArgumentException("Already have converter for <"
113         // + s.getSubdetectorType().getCanonicalName() + "> !");
114         // }
115         subdetectorConverters.put(s.getSubdetectorType(), s);
116     }
117 
118     private ISubdetectorConverter getSubdetectorConverter(Class klass) {
119         return subdetectorConverters.get(klass);
120     }
121 
122     public IPhysicalVolume convert(Detector detector, String resource) throws JDOMException, IOException {
123         return convert(detector, CompactDocumentBuilder.build(resource));
124     }
125 
126     private void convertMaterials(Document doc) throws JDOMException {
127         materialCnv.convert(doc);
128     }
129 
130     private void convertMaterials(String resource) throws JDOMException, IOException {
131         Document doc = CompactDocumentBuilder.build(resource);
132 
133         for (Object obj : doc.getRootElement().getChildren()) {
134             Element e = (Element) obj;
135             if (e.getName().equals("element")) {
136                 elemCnv.convert(e);
137             } else if (e.getName().equals("material")) {
138                 matCnv.convert(e);
139             }
140         }
141     }
142 
143     private void convertSubdetectors(Detector detector) {
144         // Process all Subdetectors in the Detector.
145         for (Subdetector subdetector : detector.getSubdetectors().values()) {
146 
147             // Find a converter for this type.
148             ISubdetectorConverter cnv = getSubdetectorConverter(subdetector.getClass());
149 
150             if (cnv != null) {
151 
152                 // cnv.getSubdetectorType().getCanonicalName());
153                 DetectorElement subdetectorDE = (DetectorElement) cnv.makeSubdetectorDetectorElement(detector, subdetector);
154 
155                 // Make the IdentifierHelper for this Subdetector.
156                 IIdentifierHelper helper = cnv.makeIdentifierHelper(subdetector, sysMap);
157 
158                 // Convert the parameters.
159                 try {
160                     paramCnv.convert(subdetector.getNode());
161                 } catch (JDOMException x) {
162                     throw new RuntimeException(x);
163                 }
164 
165                 if (subdetectorDE != null) {
166                     subdetectorDE.setIdentifierHelper(helper);
167                 }
168 
169                 // Build the Subdetector's geometry and associated
170                 // DetectorElement(s).
171                 cnv.convert(subdetector, detector);
172 
173                 // Get the top level Subdetector node back.
174                 DetectorElement subdetDE = (DetectorElement) subdetector.getDetectorElement();
175 
176                 // Check if a DetectorElement was created. Some compact
177                 // "detector" objects
178                 // are not really detectors but dead material so this check is
179                 // necessary
180                 // to avoid errors.
181                 if (subdetDE != null) {
182                     // Make the Parameters from the compact detector element
183                     // and assign to the Subdetector's DetectorElement.
184                     subdetDE.setParameters(ParametersStore.getInstance().get(subdetector.getName()));
185 
186                     // Make the Subdetector IdentifierHelper from the IDDecoder
187                     // and assign to the Subdetector's DetectorElement.
188                     if (helper != null && subdetectorDE.getIdentifierHelper() == null) {
189                         subdetDE.setIdentifierHelper(helper);
190                     }
191 
192                     // Make the identifiers for this Subdetector.
193                     cnv.makeIdentifiers(subdetector);
194                 }
195                 
196                 // Initialize the subdetector detector element (no op for most classes).
197                 subdetectorDE.initialize();
198             }
199         }
200     }
201 
202     private void buildTrackingVolume(ILogicalVolume world, Detector detector) {
203         Map<String, Constant> constants = detector.getConstants();
204 
205         if (constants.get("tracking_region_zmax") == null || constants.get("tracking_region_radius") == null) {
206             throw new RuntimeException("Missing parameters for defining tracking region!");
207         }
208 
209         double zmax = constants.get("tracking_region_zmax").getValue();
210         double radius = constants.get("tracking_region_radius").getValue();
211 
212         Tube trackingTube = new Tube("tracking_region_tube", 0, radius, zmax);
213 
214         LogicalVolume trackingLV = new LogicalVolume("tracking_region", trackingTube, MaterialStore.getInstance().get(
215                 "Air"));
216 
217         new PhysicalVolume(null, "tracking_region", trackingLV, world, 0);
218     }
219 
220     private IPhysicalVolume buildWorldVolume(Detector detector) {
221         Map<String, Constant> constants = detector.getConstants();
222 
223         if (constants.get("world_x") == null || constants.get("world_y") == null || constants.get("world_z") == null) {
224             throw new RuntimeException("Missing world_x, world_y, or world_z!");
225         }
226 
227         double x = constants.get("world_x").getValue();
228         double y = constants.get("world_y").getValue();
229         double z = constants.get("world_z").getValue();
230 
231         IMaterial air = MaterialStore.getInstance().get("Air");
232 
233         Box boxWorld = new Box("world_box", x, y, z);
234 
235         LogicalVolume lvWorld = new LogicalVolume("world", boxWorld, air);
236 
237         PhysicalVolume pvWorld = new PhysicalVolume(null, "world", lvWorld, null, 0);
238 
239         return pvWorld;
240     }
241 
242     // Converts the subdetectors in a detector to a map of subsystems to system
243     // id.
244     // TODO: Must be a better way to setup these associations in the
245     // DetectorIdentifierHelper.
246     public static final SystemMap makeSystemMap(Detector d) {
247         SystemMap m = new SystemMap();
248 
249         for (Subdetector subdet : d.getSubdetectors().values()) {
250             String name = subdet.getName();
251 
252             int sys = subdet.getSystemID();
253 
254             // Based on naming conventions from sid01 and sid02.
255             if (!name.contains("Support") && !(subdet instanceof PolyconeSupport)) {
256                 if (name.contains("VertexBarrel")) {
257                     m.put("vtxBarrel", sys);
258                 } else if (name.contains("VertexEndcap")) {
259                     m.put("vtxEndcap", sys);
260                 } else if (name.contains("TrackerBarrel")) {
261                     m.put("sitBarrel", sys);
262                 } else if (name.contains("TrackerEndcap")) {
263                     m.put("sitEndcap", sys);
264                 } else if (name.contains("TrackerForward")) {
265                     m.put("sitForward", sys);
266                 } else if (name.contains("TPC")) {
267                     m.put("tpc", sys);
268                 } else if (name.contains("EMBarrel")) {
269                     m.put("ecalBarrel", sys);
270                 } else if (name.contains("EMEndcap") && !name.contains("Forward")) {
271                     m.put("ecalEndcap", sys);
272                 } else if (name.contains("HADBarrel")) {
273                     m.put("hcalBarrel", sys);
274                 } else if (name.contains("HADEndcap")) {
275                     m.put("hcalEndcap", sys);
276                 } else if (name.contains("MuonBarrel")) {
277                     m.put("muonBarrel", sys);
278                 } else if (name.contains("MuonEndcap")) {
279                     m.put("muonEndcap", sys);
280                 } else if (name.contains("LuminosityMonitor") || name.contains("LumiCal")) {
281                     m.put("lumi", sys);
282                 } else if (name.contains("ForwardEMEndcap")) {
283                     m.put("ecalForward", sys);
284                 }
285             }
286         }
287 
288         return m;
289     }
290 }