View Javadoc

1   package org.lcsim.geometry.compact;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.io.InputStream;
6   import java.net.MalformedURLException;
7   import java.net.URL;
8   import java.util.ArrayList;
9   import java.util.HashMap;
10  import java.util.Iterator;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.Map.Entry;
14  import java.util.Scanner;
15  
16  import org.jdom.Document;
17  import org.jdom.Element;
18  import org.jdom.JDOMException;
19  import org.jdom.input.SAXBuilder;
20  import org.lcsim.geometry.util.BaseIDDecoder;
21  import org.lcsim.material.XMLMaterialManager;
22  import org.lcsim.units.clhep.Constants;
23  import org.lcsim.util.xml.ClasspathEntityResolver;
24  import org.lcsim.util.xml.ElementFactory;
25  import org.lcsim.util.xml.ElementFactory.ElementCreationException;
26  import org.lcsim.util.xml.JDOMExpressionFactory;
27  
28  import Jama.Matrix;
29  
30  /**
31   * A tool for reading xml files containing compact detector descriptions.
32   * 
33   * This class does not create subclass objects. For example, CylindricalBarrelCalorimeter is inserted into
34   * Detector as a generic Subdetector. To get subclasses, use the org.lcsim.geometry.GeometryReader class,
35   * which extends this.
36   * 
37   * @author tonyj
38   * @version $Id: CompactReader.java,v 1.49 2013/04/24 02:00:35 jeremy Exp $
39   * 
40   */
41  public class CompactReader {
42      private ElementFactory factory;
43      private JDOMExpressionFactory expr;
44      private Document doc;
45      private XMLMaterialManager xmat;
46  
47      /**
48       * Create a CompactReader using a DefaultElementFactory.
49       */
50      public CompactReader() {
51          this(new CompactElementFactory());
52      }
53  
54      /**
55       * Create a CompactReader using the specified ElementFactory.
56       * 
57       * @param factory The ElementFactory to be used for creating elements as the file is parsed.
58       */
59      public CompactReader(ElementFactory factory) {
60          this.factory = factory;
61      }
62  
63      /**
64       * Read a compact geometry XML file.
65       * 
66       * @param in The input stream to read.
67       * @throws java.io.IOException If an IO error occurs while reading the stream.
68       * @throws org.jdom.JDOMException If invalid XML is found while reading the file.
69       * @throws org.lcsim.geometry.compact.ElementFactory.ElementCreationException If the ElementFactory throws
70       *             an ElementCreationException.
71       * @return The parsed detector description.
72       */
73      public Detector read(InputStream in) throws IOException, JDOMException, ElementCreationException {
74          expr = new JDOMExpressionFactory();
75  
76          // Setup CLHEP units in the expression evaluator.
77          registerCLHEPConstants(expr);
78  
79          SAXBuilder builder = new SAXBuilder();
80          builder.setFactory(expr);
81  
82          // Enable schema validation
83          builder.setValidation(true);
84          builder.setFeature("http://apache.org/xml/features/validation/schema", true);
85  
86          // Use a classpath entity resolver to get the schemas from the jar file.
87          builder.setEntityResolver(new ClasspathEntityResolver());
88  
89          doc = builder.build(in);
90  
91          Element compact = doc.getRootElement();
92          Detector det = factory.createElement(Detector.class, compact, null);
93  
94          readHeader(compact, det);
95          readConstants(compact, det);
96          readMatrices(compact, det);
97          readRegions(compact, det);
98          readLimits(compact, det);
99          readMaterials(compact, det);
100         Map<String, Readout> readoutMap = readReadouts(compact, det);
101         readVisAttributes(compact, det);
102         readSubdetectors(compact, det, readoutMap);
103         readFields(compact, det);
104         readIncludes(compact, det);
105 
106         return det;
107     }
108 
109     private void readConstants(Element lccdd, Detector det) throws JDOMException, ElementCreationException {
110         Element define = lccdd.getChild("define");
111         for (Iterator i = define.getChildren("constant").iterator(); i.hasNext();) {
112             Element constant = (Element) i.next();
113             Constant c = factory.createElement(Constant.class, constant, null);
114             expr.addConstant(c.getName(), c.getValue());
115             det.addConstant(c);
116         }
117     }
118     
119     private void readMatrices(Element compact, Detector det) {
120         Element define = compact.getChild("define");
121         for (Iterator iterator = define.getChildren("matrix").iterator(); iterator.hasNext();) {
122             Element element = (Element)iterator.next();
123             String name = element.getAttributeValue("name");
124             int coldim = Integer.parseInt(element.getAttributeValue("coldim"));
125             String rawValues = element.getAttributeValue("values");
126             Scanner scanner = new Scanner(rawValues);
127             List<double[]> rows = new ArrayList<double[]>();
128             while (scanner.hasNextDouble()) {
129                 double[] row = new double[coldim];
130                 for (int i=0; i<coldim; i++) {
131                     double value = scanner.nextDouble();
132                     row[i] = value;
133                 }
134                 rows.add(row);
135             }
136             double[][] array = new double[rows.size()][coldim];
137             for (int i=0, n=rows.size(); i<n; i++) {
138                 array[i] = rows.get(i);
139             }
140             Matrix matrix = new Matrix(array);
141             det.addMatrix(name, matrix);            
142         }
143     }
144 
145     private void readHeader(Element lccdd, Detector det) throws JDOMException, ElementCreationException {
146         Element info = lccdd.getChild("info");
147         det.setHeader(factory.createElement(Header.class, info, null));
148     }
149 
150     private void readRegions(Element lccdd, Detector det) throws JDOMException, ElementCreationException {
151         Element regions = lccdd.getChild("regions");
152         if (regions != null) {
153             for (Iterator i = regions.getChildren("region").iterator(); i.hasNext();) {
154                 Element region = (Element) i.next();
155                 Region r = factory.createElement(Region.class, region, null);
156                 det.addRegion(r);
157             }
158         }
159     }
160 
161     private void readLimits(Element lccdd, Detector det) throws JDOMException, ElementCreationException {
162         Element limits = lccdd.getChild("limits");
163         if (limits != null) {
164             for (Iterator i = limits.getChildren("limitset").iterator(); i.hasNext();) {
165                 Element limitset = (Element) i.next();
166                 LimitSet ls = factory.createElement(LimitSet.class, limitset, null);
167                 det.addLimitSet(ls);
168             }
169         }
170     }
171 
172     private Map<String, Readout> readReadouts(Element lccdd, Detector det) throws JDOMException, ElementCreationException {
173         Map<String, Readout> readoutMap = new HashMap<String, Readout>();
174         Element readouts = lccdd.getChild("readouts");
175         for (Iterator i = readouts.getChildren("readout").iterator(); i.hasNext();) {
176             Element readout = (Element) i.next();
177 
178             Readout r = null;
179             try {
180                 r = createReadout(readout);
181             } catch (Exception e) {
182                 throw new RuntimeException(e);
183             }
184 
185             readoutMap.put(r.getName(), r);
186             det.addReadout(r);
187         }
188         return readoutMap;
189     }
190 
191     private Readout createReadout(Element readoutElement) throws Exception {
192         Readout readout = factory.createElement(Readout.class, readoutElement, null);
193         Element segmentation = readoutElement.getChild("segmentation");
194 
195         // Setup an IDDecoder with segmentation for a calorimeter.
196         if (segmentation != null) {
197             String type = segmentation.getAttributeValue("type");
198             Segmentation seg = factory.createElement(Segmentation.class, segmentation, type);
199             readout.setSegmentation(seg);
200         }
201         // Use a generic IDDecoder.
202         else {
203             readout.setIDDecoder(new BaseIDDecoder());
204         }
205 
206         return readout;
207     }
208 
209     private void readSubdetectors(Element lccdd, Detector det, Map<String, Readout> readoutMap) throws JDOMException, ElementCreationException {
210         Element detectors = lccdd.getChild("detectors");
211         for (Iterator i = detectors.getChildren("detector").iterator(); i.hasNext();) {
212             Element detector = (Element) i.next();
213             String type = detector.getAttributeValue("type");
214 
215             Subdetector sub = factory.createElement(Subdetector.class, detector, type);
216             String readout = detector.getAttributeValue("readout");
217             if (readout != null) {
218                 Readout r = readoutMap.get(readout);
219                 if (r == null)
220                     throw new JDOMException("Unknown readout " + readout);
221                 sub.setReadout(r);
222             }
223 
224             String visref = detector.getAttributeValue("vis");
225             if (visref != null) {
226                 VisAttributes vis = det.getVisAttributes().get(visref);
227                 if (vis == null)
228                     throw new JDOMException("Unknown vis " + visref + " for subdetector " + sub.getName() + " in compact description.");
229                 sub.setVisAttributes(vis);
230             }
231 
232             det.addSubdetector(sub);
233         }
234     }
235 
236     private void readFields(Element lccdd, Detector det) throws JDOMException, ElementCreationException {
237         Element fields = lccdd.getChild("fields");
238         if (fields != null) {
239             for (Iterator i = fields.getChildren("field").iterator(); i.hasNext();) {
240                 Element f = (Element) i.next();
241                 String type = f.getAttributeValue("type");
242 
243                 Field field = factory.createElement(Field.class, f, type);
244                 det.addField(field);
245             }
246         }
247     }
248 
249     private void readMaterials(org.jdom.Element compact, Detector det) {
250         // Setup XMLMatMgr's default data. This needs to be called before
251         // the compact materials are loaded in order to resolve references.
252         XMLMaterialManager.setup();
253 
254         // Create XMLMatMgr for this detector's materials.
255         if (compact.getChild("materials") != null) {
256             xmat = new XMLMaterialManager(compact.getChild("materials"));
257 
258             // FIXME Need to call this here???
259             // matmgr.addReferencesFromCompact(lccdd);
260         }
261 
262         // Set the detector's XMLMaterialManager, so it is accessible to
263         // clients such as the LCDD converter.
264         det.setXMLMaterialManager(xmat);
265     }
266 
267     /**
268      * Create the VisAttributes objects from vis elements in the display block.
269      * 
270      * @param lccdd
271      * @param det
272      * @throws JDOMException
273      * @throws ElementCreationException
274      */
275     private void readVisAttributes(Element lccdd, Detector det) throws JDOMException, ElementCreationException {
276 
277         Element display = lccdd.getChild("display");
278         if (display != null) {
279             for (Iterator i = display.getChildren("vis").iterator(); i.hasNext();) {
280                 Element vis = (Element) i.next();
281                 assert (vis != null);
282                 VisAttributes v = factory.createElement(VisAttributes.class, vis, null);
283                 det.addVisAttributes(v);
284             }
285 
286             // Add an invisible vis settings that shows daughters.
287             VisAttributes invisible = new VisAttributes("InvisibleWithDaughters");
288             invisible.setVisible(false);
289             invisible.setShowDaughters(true);
290             det.addVisAttributes(invisible);
291 
292             // Add an invisible vis settings that shows daughters.
293             VisAttributes invisibleNoDau = new VisAttributes("InvisibleNoDaughters");
294             invisibleNoDau.setVisible(false);
295             invisibleNoDau.setShowDaughters(false);
296             det.addVisAttributes(invisibleNoDau);
297         }
298     }
299 
300     // TODO: Should be protected or private but need to fix some external code first.
301     public static void registerCLHEPConstants(JDOMExpressionFactory f) {
302         Constants constants = Constants.getInstance();
303         for (Entry<String, Double> unit : constants.entrySet()) {
304             // System.out.println("adding constant " + unit.getKey() + "=" +unit.getValue());
305             f.addConstant(unit.getKey(), unit.getValue());
306         }
307     }
308 
309     protected void resetDocument() {
310         doc = null;
311     }
312 
313     public Document getDocument() {
314         return doc;
315     }
316 
317     void readIncludes(Element lccdd, Detector det) {
318         Element includes = lccdd.getChild("includes");
319 
320         if (includes == null)
321             return;
322 
323         for (Object o : includes.getChildren("gdmlFile")) {
324             Element gdmlFile = (Element) o;
325 
326             if (gdmlFile.getAttribute("ref") != null) {
327 
328                 String ref = gdmlFile.getAttributeValue("ref");
329 
330                 // System.out.println("merging in " + ref);
331 
332                 try {
333                     det.addGDMLReference(new URL(ref));
334                 } catch (Exception x) {
335                     throw new RuntimeException(x);
336                 }
337             } else if (gdmlFile.getAttribute("file") != null) {
338                 File file = new File(gdmlFile.getAttributeValue("file"));
339                 try {
340                     URL url = new URL(file.toURI().toURL().toString());
341                     det.addGDMLReference(url);
342                 } catch (MalformedURLException e) {
343                     throw new RuntimeException(e);
344                 }
345             } else {
346                 throw new RuntimeException("Missing ref or file attribute on gdmlFile element.");
347             }
348         }
349     }
350 }