View Javadoc

1   package org.lcsim.geometry.compact.converter.lcdd.util;
2   
3   import java.io.InputStream;
4   import java.util.HashMap;
5   import java.util.Iterator;
6   import java.util.List;
7   import java.util.Map;
8   
9   import org.jdom.Attribute;
10  import org.jdom.Document;
11  import org.jdom.Element;
12  import org.jdom.JDOMException;
13  import org.jdom.Namespace;
14  import org.jdom.input.SAXBuilder;
15  import org.lcsim.geometry.compact.converter.lcdd.LCDDSubdetector;
16  import org.lcsim.material.XMLMaterialManager;
17  
18  /**
19   * 
20   * @author tonyj
21   */
22  public class LCDD extends Element {
23      private Map materials = new HashMap();
24      Volume worldVolume = null;
25      Volume trackingVolume = null;
26      LCDDMaterialHelper matHelper = new LCDDMaterialHelper(XMLMaterialManager.getDefaultMaterialManager());
27  
28      public LCDD() {
29          super("lcdd");
30  
31          build();
32      }
33  
34      private void build() {
35          addNamespaceDeclaration(Namespace.getNamespace("lcdd", "http://www.lcsim.org/schemas/lcdd/1.0"));
36  
37          setAttribute("noNamespaceSchemaLocation", "http://www.lcsim.org/schemas/lcdd/1.0/lcdd.xsd", Namespace.getNamespace("xs", "http://www.w3.org/2001/XMLSchema-instance"));
38  
39          Header header = new Header();
40          addContent(header);
41  
42          Element iddict = new Element("iddict");
43          addContent(iddict);
44  
45          Element sensitiveDetectors = new Element("sensitive_detectors");
46          addContent(sensitiveDetectors);
47  
48          Element limits = new Element("limits");
49          addContent(limits);
50  
51          Element regions = new Element("regions");
52          addContent(regions);
53  
54          Element display = new Element("display");
55          addContent(display);
56  
57          // Add an invisible vis settings that shows daughters.
58          // VisAttributes invisible = new VisAttributes("InvisibleWithDaughters");
59          // invisible.setVisible(false);
60          // invisible.setShowDaughters(true);
61          // this.add(invisible);
62  
63          // Add an invisible vis settings that shows daughters.
64          // VisAttributes invisibleNoDau = new VisAttributes("InvisibleNoDaughters");
65          // invisibleNoDau.setVisible(false);
66          // invisibleNoDau.setShowDaughters(false);
67          // this.add(invisibleNoDau);
68  
69          Element gdml = new Element("gdml");
70          addContent(gdml);
71  
72          gdml.addContent(new Define());
73  
74          gdml.addContent(new Element("materials"));
75  
76          Solids solids = new Solids();
77          gdml.addContent(solids);
78  
79          Structure structure = new Structure();
80          gdml.addContent(structure);
81  
82          Box worldSolid = new Box("world_box");
83          worldSolid.setAttribute("x", "world_x");
84          worldSolid.setAttribute("y", "world_y");
85          worldSolid.setAttribute("z", "world_z");
86          solids.addSolid(worldSolid);
87  
88          this.worldVolume = new Volume("world_volume");
89          worldVolume.setSolid(worldSolid);
90          structure.setWorldVolume(worldVolume);
91  
92          Tube trackingSolid = new Tube("tracking_cylinder");
93          trackingSolid.setAttribute("rmax", "tracking_region_radius");
94          trackingSolid.setAttribute("z", "2*tracking_region_zmax");
95          trackingSolid.setAttribute("deltaphi", String.valueOf(2 * Math.PI));
96          solids.addSolid(trackingSolid);
97  
98          this.trackingVolume = new Volume("tracking_volume");
99          trackingVolume.setSolid(trackingSolid);
100         structure.setTrackingVolume(trackingVolume);
101         worldVolume.addPhysVol(new PhysVol(trackingVolume));
102 
103         Element setup = new Element("setup");
104         setup.setAttribute("name", "Default");
105         setup.setAttribute("version", "1.0");
106         Element world = new Element("world");
107         world.setAttribute("ref", worldVolume.getRefName());
108         setup.addContent(world);
109         gdml.addContent(setup);
110 
111         Element fields = new Element("fields");
112         addContent(fields);
113     }
114 
115     private final Material getWorldMaterial() {
116         Material m = null;
117         try {
118             // User-specified fill material.
119             m = this.getMaterial("WorldMaterial");
120         } catch (JDOMException x) {
121             try {
122                 // Default fill material of air.
123                 m = this.getMaterial("Air");
124             } catch (JDOMException x2) {
125                 // This should not happen!
126                 throw new RuntimeException(x);
127             }
128         }
129         return m;
130     }
131 
132     private final Material getTrackingMaterial() {
133         Material m = null;
134         try {
135             // User-specified fill material.
136             m = this.getMaterial("TrackingMaterial");
137         } catch (JDOMException x) {
138             try {
139                 // Default fill material of air.
140                 m = this.getMaterial("Air");
141             } catch (JDOMException x2) {
142                 // This should not happen!
143                 throw new RuntimeException(x);
144             }
145         }
146         return m;
147     }
148 
149     public void cleanUp() throws JDOMException {
150         Structure structure = getStructure();
151         Volume trackingVolume = structure.getTrackingVolume();
152         trackingVolume.setMaterial(getTrackingMaterial());
153 
154         // Move to end
155         structure.removeContent(trackingVolume);
156         structure.addContent(trackingVolume);
157 
158         Region trackingRegion = new Region("TrackingRegion");
159         trackingRegion.setThreshold(1);
160         trackingRegion.setStoreSecondaries(true);
161         addRegion(trackingRegion);
162         trackingVolume.setRegion(trackingRegion);
163 
164         Volume worldVolume = structure.getWorldVolume();
165         worldVolume.setMaterial(getWorldMaterial());
166 
167         // Move to end
168         structure.removeContent(worldVolume);
169         structure.addContent(worldVolume);
170 
171         // Set the world volume to invisible.
172         VisAttributes worldVis = new VisAttributes("WorldVis");
173         worldVis.setVisible(false);
174         this.getWorldVolume().setVisAttributes(worldVis);
175         this.add(worldVis);
176 
177         // Set the tracking volume to invisible.
178         VisAttributes trackingVis = new VisAttributes("TrackingVis");
179         trackingVis.setVisible(false);
180         this.getTrackingVolume().setVisAttributes(trackingVis);
181         this.add(trackingVis);
182     }
183 
184     public Solids getSolids() {
185         return (Solids) getChild("gdml").getChild("solids");
186     }
187 
188     public Solid getSolid(String name) {
189         Solid solid = null;
190         for (Object object : getSolids().getChildren()) {
191             solid = (Solid) object;
192             if (solid != null) {
193                 if (solid.getAttributeValue("name").compareTo(name) == 0) {
194                     return solid;
195                 }
196             }
197         }
198         return null;
199     }
200 
201     public void add(Constant constant) {
202         getDefine().addConstant(constant);
203     }
204     
205     public void add(Matrix matrix) {
206         getDefine().addMatrix(matrix);
207     }
208 
209     public void add(Position position) {
210         getDefine().addPosition(position);
211     }
212 
213     public void add(Rotation rotation) {
214         getDefine().addRotation(rotation);
215     }
216 
217     public void add(Solid solid) {
218         getSolids().addSolid(solid);
219     }
220 
221     public void add(Volume volume) {
222         getStructure().addVolume(volume);
223     }
224 
225     public void add(Region region) {
226         getChild("regions").addContent(region);
227     }
228 
229     public void add(IDSpec spec) {
230         getChild("iddict").addContent(spec);
231     }
232 
233     public void add(LimitSet limitset) {
234         getChild("limits").addContent(limitset);
235     }
236 
237     public void add(VisAttributes vis) {
238         getChild("display").addContent(vis);
239     }
240 
241     public VisAttributes getVisAttributes(String name) {
242         VisAttributes vis = null;
243         for (Iterator i = getChild("display").getChildren("vis").iterator(); i.hasNext();) {
244             VisAttributes thisvis = (VisAttributes) i.next();
245             if (thisvis.getRefName().compareTo(name) == 0) {
246                 vis = thisvis;
247                 break;
248             }
249         }
250         return vis;
251     }
252 
253     public Structure getStructure() {
254         return (Structure) getChild("gdml").getChild("structure");
255     }
256 
257     // FIXME Weird stuff going on with this method.
258     public Material getMaterial(String name) throws JDOMException {
259         // System.out.println("LCDD.getMaterial - " + name);
260 
261         Material mat = (Material) materials.get(name);
262 
263         // System.out.println("found material - " + name);
264 
265         /**
266          * This may be a material that was not defined in the materials block. Attempt to look it up using the
267          * global materials manager.
268          * 
269          * If this fails, the material reference is probably invalid/undefined.
270          * 
271          */
272         if (mat == null) {
273             // System.out.println("resolving mat ref - " + name);
274 
275             // This call will push material XML references into the LCDD object. (???)
276             matHelper.resolveLCDDMaterialReference(name, this);
277         }
278 
279         // Retry the materials lookup as above call should have added it if found.
280         mat = (Material) materials.get(name);
281 
282         if (mat == null) {
283             // Material lookup failed!
284             throw new JDOMException("Material " + name + " was not found.");
285         }
286 
287         return mat;
288     }
289 
290     public Define getDefine() {
291         return (Define) getChild("gdml").getChild("define");
292     }
293 
294     public Header getHeader() {
295         return (Header) getChild("header");
296     }
297 
298     public void addMaterial(Material material) {
299         if (materials.get(material.getRefName()) == null) {
300             getChild("gdml").getChild("materials").addContent(material);
301             materials.put(material.getRefName(), material);
302         }
303     }
304 
305     public void addElement(Element element) {
306         if (getElement(element.getAttributeValue("name")) == null) {
307             getChild("gdml").getChild("materials").addContent(element);
308         }
309     }
310 
311     public Element getElement(String elemName) {
312         Element e = null;
313         for (Object o : getChild("gdml").getChild("materials").getChildren("element")) {
314             Element ee = (Element) o;
315             if (ee.getAttributeValue("name").contentEquals(elemName)) {
316                 e = ee;
317                 break;
318             }
319         }
320         return e;
321     }
322 
323     public void addIDSpec(IDSpec spec) {
324         getChild("iddict").addContent(spec);
325     }
326 
327     public void addSensitiveDetector(SensitiveDetector det) {
328         getChild("sensitive_detectors").addContent(det);
329     }
330 
331     public void add(Field field) {
332         getChild("fields").addContent(field);
333     }
334 
335     public void setGlobalField(Field field) {
336         Element fields = getChild("fields");
337         fields.addContent(field);
338 
339         Element fieldRef = new Element("fieldref");
340         fieldRef.setAttribute("ref", field.getRefName());
341 
342         Element globalField = new Element("global_field");
343         globalField.addContent(fieldRef);
344         fields.addContent(globalField);
345     }
346 
347     public void addRegion(Region region) {
348         getChild("regions").addContent(region);
349     }
350 
351     public Element getRegions() {
352         return getChild("regions");
353     }
354 
355     public Region getRegion(String name) {
356         Region region = null;
357         for (Iterator i = getChild("regions").getChildren("region").iterator(); i.hasNext();) {
358             Region thisregion = (Region) i.next();
359             if (thisregion.getRefName().compareTo(name) == 0) {
360                 region = thisregion;
361                 break;
362             }
363         }
364         return region;
365     }
366 
367     /**
368      * Pick the world or tracking volume for a subdetector's mother volume, depending on the value of the
369      * insideTrackingVolume attribute.
370      * 
371      * If insideTrackingVolume is not set, trackers go into the tracking volume and calorimeters go into the
372      * world volume.
373      * 
374      * @param subdet LCDD subdetector
375      */
376     public Volume pickMotherVolume(LCDDSubdetector subdet) {
377         Attribute insideAttrib = subdet.getElement().getAttribute("insideTrackingVolume");
378         boolean inside = false;
379 
380         try {
381             if (insideAttrib == null) {
382                 if (subdet.isTracker()) {
383                     inside = true;
384                 } else {
385                     inside = false;
386                 }
387             } else {
388                 inside = insideAttrib.getBooleanValue();
389             }
390         } catch (org.jdom.DataConversionException dce) {
391             throw new RuntimeException("Error converting insideTrackingVolume attribute.", dce);
392         }
393 
394         Volume motherVolume = (inside ? getStructure().getTrackingVolume() : getStructure().getWorldVolume());
395 
396         if (motherVolume == null) {
397             throw new RuntimeException("Picked a null mother volume.");
398         }
399 
400         // System.out.println("subdet " + subdet.getElement().getAttributeValue("name") + " -> "
401         // + motherVolume.getAttributeValue("name") + "; insideTrackingVolume=" + inside);
402 
403         return motherVolume;
404     }
405 
406     public void addLimitSet(LimitSet limitset) {
407         getChild("limits").addContent(limitset);
408     }
409 
410     public LimitSet getLimitSet(String name) {
411         LimitSet limitset = null;
412         for (Iterator i = getChild("limits").getChildren("limitset").iterator(); i.hasNext();) {
413             LimitSet thislimitset = (LimitSet) i.next();
414             if (thislimitset.getRefName().compareTo(name) == 0) {
415                 limitset = thislimitset;
416                 break;
417             }
418         }
419         return limitset;
420     }
421 
422     public Volume getWorldVolume() {
423         return this.worldVolume;
424     }
425 
426     public Volume getTrackingVolume() {
427         return this.trackingVolume;
428     }
429 
430     public Volume getVolume(String name) {
431         for (Iterator i = getChild("structure").getChildren("volume").iterator(); i.hasNext();) {
432             Volume vol = (Volume) i.next();
433             if (vol.getRefName().compareTo(name) == 0) {
434                 return vol;
435             }
436         }
437         return null;
438     }
439 
440     /**
441      * Merge an existing GDML file into this LCDD document.
442      * 
443      * @param in InputStream from a GDML data source.
444      */
445     public void mergeGDML(InputStream in) {
446         
447         // Build the GDML input document.
448         SAXBuilder builder = new SAXBuilder();
449         Document doc = null;
450         try {
451             doc = builder.build(in);
452         } catch (Exception x) {
453             throw new RuntimeException(x);
454         }
455 
456         Element root = doc.getRootElement();
457 
458         if (!root.getName().equals("gdml")) {
459             throw new RuntimeException("Document is not a valid GDML file.");
460         }
461 
462         Element gdml = getChild("gdml");
463 
464         // Find the world and tracking volumes in the target document.
465 
466         Element targetWorld = null;
467         Element targetTracking = null;
468         for (Object o : gdml.getChild("structure").getChildren()) {
469             Element e = (Element) o;
470             if (e.getAttributeValue("name").equals("world_volume")) {
471                 targetWorld = e;
472             } else if (e.getAttributeValue("name").equals("tracking_volume")) {
473                 targetTracking = e;
474             }
475         }
476 
477         // Process top level sections in the source GDML document.
478         for (Object o1 : root.getChildren()) {
479             Element section = (Element) o1;
480 
481             // System.out.println("merging in section " + section.getName());
482 
483             // Ignore the setup section of the source document.
484             if (!section.getName().equals("setup")) {
485                 Element target = gdml.getChild(section.getName());
486 
487                 // Process children in this section.
488                 for (Object o2 : section.getChildren()) {
489                     Element element = (Element) o2;
490 
491                     // Check if physvols need to be merged into the target tracking or world volumes.
492                     if (element.getName().equals("volume") && (element.getAttributeValue("name").equals("world_volume") || element.getAttributeValue("name").equals("tracking_volume"))) {
493                         Element targetVol = null;
494 
495                         if (element.getAttributeValue("name").equals("world_volume")) {
496                             targetVol = targetWorld;
497                         } else if (element.getAttributeValue("name").equals("tracking_volume")) {
498                             targetVol = targetTracking;
499                         }
500 
501                         for (Object o : element.getChildren("physvol")) {
502                             Element physvol = (Element) o;
503                             boolean skip = false;
504                             if (targetTracking != null && physvol.getChild("volumeref").getAttributeValue("ref").equals("tracking_volume"))
505                                 skip = true;
506                             if (!skip)
507                                 targetVol.addContent((Element) physvol.clone());
508                         }
509                     }
510                     // Generic merge-in of this element into target section, checking for duplicates.
511                     else {
512                         // Check for dup names in target section.
513                         List targetElements = target.getChildren(element.getName());
514                         boolean dup = false;
515                         for (Object o : targetElements) {
516                             Element targetElement = (Element) o;
517                             if (targetElement.getAttributeValue("name").equals(element.getAttributeValue("name"))) {
518                                 dup = true;
519                                 break;
520                             }
521                         }
522 
523                         if (!dup)
524                             target.addContent((Element) element.clone());
525                     }
526                 }
527             }
528         }
529     }
530 }