View Javadoc

1   package org.lcsim.geometry.compact.converter.lcdd;
2   
3   import java.io.FileInputStream;
4   import java.io.FileNotFoundException;
5   import java.io.IOException;
6   import java.io.OutputStream;
7   import java.net.URL;
8   import java.util.HashMap;
9   import java.util.Iterator;
10  import java.util.Map;
11  import java.util.zip.CRC32;
12  import java.util.zip.CheckedOutputStream;
13  
14  import org.jdom.Document;
15  import org.jdom.Element;
16  import org.jdom.JDOMException;
17  import org.jdom.filter.ContentFilter;
18  import org.jdom.output.Format;
19  import org.jdom.output.XMLOutputter;
20  import org.lcsim.geometry.compact.Field;
21  import org.lcsim.geometry.compact.Readout;
22  import org.lcsim.geometry.compact.Subdetector;
23  import org.lcsim.geometry.compact.converter.lcdd.util.Author;
24  import org.lcsim.geometry.compact.converter.lcdd.util.Calorimeter;
25  import org.lcsim.geometry.compact.converter.lcdd.util.Constant;
26  import org.lcsim.geometry.compact.converter.lcdd.util.Define;
27  import org.lcsim.geometry.compact.converter.lcdd.util.Detector;
28  import org.lcsim.geometry.compact.converter.lcdd.util.Generator;
29  import org.lcsim.geometry.compact.converter.lcdd.util.HitProcessor;
30  import org.lcsim.geometry.compact.converter.lcdd.util.HitsCollection;
31  import org.lcsim.geometry.compact.converter.lcdd.util.IDField;
32  import org.lcsim.geometry.compact.converter.lcdd.util.IDSpec;
33  import org.lcsim.geometry.compact.converter.lcdd.util.LCDD;
34  import org.lcsim.geometry.compact.converter.lcdd.util.LCDDMaterialHelper;
35  import org.lcsim.geometry.compact.converter.lcdd.util.Limit;
36  import org.lcsim.geometry.compact.converter.lcdd.util.LimitSet;
37  import org.lcsim.geometry.compact.converter.lcdd.util.Position;
38  import org.lcsim.geometry.compact.converter.lcdd.util.Region;
39  import org.lcsim.geometry.compact.converter.lcdd.util.Rotation;
40  import org.lcsim.geometry.compact.converter.lcdd.util.SensitiveDetector;
41  import org.lcsim.geometry.compact.converter.lcdd.util.Tracker;
42  import org.lcsim.geometry.compact.converter.lcdd.util.UnsegmentedCalorimeter;
43  import org.lcsim.geometry.compact.converter.lcdd.util.VisAttributes;
44  import org.lcsim.geometry.util.IDDescriptor;
45  import org.lcsim.util.cache.FileCache;
46  
47  import Jama.Matrix;
48  
49  /**
50   * 
51   * @author tonyj
52   */
53  class LCDDDetector extends org.lcsim.geometry.compact.Detector {
54      
55      // Reference to compact doc.
56      private Element compact;
57  
58      // Checksum of LCDD file.
59      private long checksum;
60  
61      LCDDDetector(Element node) {
62          super(node);
63          this.compact = node;
64      }
65  
66      Document writeLCDD(String filename) throws IOException, JDOMException {
67          LCDD lcdd = new LCDD();
68  
69          checksum = calculateChecksum(compact);
70  
71          Detector detector = lcdd.getHeader().getDetector();
72          detector.setTitle(getHeader().getDetectorName());
73          lcdd.getHeader().setComment(getHeader().getComment());
74  
75          Generator generator = lcdd.getHeader().getGenerator();
76          generator.setTitle(getName());
77          generator.setVersion(getVersion());
78          generator.setFile(filename);
79          generator.setChecksum(getChecksum());
80  
81          Author author = lcdd.getHeader().getAuthor();
82          author.setAuthorName(getHeader().getAuthor());
83  
84          /* standard defines */
85          Define define = lcdd.getDefine();
86          Rotation rotation = new Rotation("identity_rot");
87          define.addRotation(rotation);
88  
89          Rotation reflect = new Rotation("reflect_rot");
90          reflect.setX(Math.PI);
91          define.addRotation(reflect);
92  
93          Position position = new Position("identity_pos");
94          define.addPosition(position);
95  
96          /* constants */
97          for (org.lcsim.geometry.compact.Constant c : getConstants().values()) {
98              define.addConstant(new Constant(c.getName(), String.valueOf(c.getValue())));
99          }
100         
101         /* Write out the matrices associated with this detector, e.g. for material properties. */
102         writeMatrices(lcdd);
103 
104         /* Setup materials. */
105         setupMaterials(lcdd);
106 
107         // Readouts.
108         Map<Readout, IDSpec> idMap = writeReadouts(lcdd);
109 
110         // Regions.
111         writeRegions(lcdd);
112 
113         // Limits.
114         writeLimits(lcdd);
115 
116         // Vis attributes.
117         writeVisAttribs(lcdd);
118 
119         // Subdetectors.
120         writeSubdetectors(lcdd, idMap);
121 
122         // Fields.
123         writeFields(lcdd);
124 
125         // GDML references.
126         writeGDMLRefs(lcdd);
127 
128         lcdd.cleanUp();
129 
130         // Make LCDD document.
131         Document doc = new Document();
132         doc.setRootElement(lcdd);
133 
134         return doc;
135     }
136 
137     private void writeGDMLRefs(LCDD lcdd) throws IOException, FileNotFoundException {
138         FileCache cache = new FileCache();
139         for (URL gdmlFile : getGDMLReferences()) {
140             lcdd.mergeGDML(new FileInputStream(cache.getCachedFile(gdmlFile)));
141         }
142     }
143 
144     private void writeFields(LCDD lcdd) throws JDOMException {
145         for (Field field : getFields().values()) {
146             ((LCDDField) field).addToLCDD(lcdd);
147         }
148     }
149 
150     private void writeSubdetectors(LCDD lcdd, Map<Readout, IDSpec> idMap) throws JDOMException {
151         for (Subdetector sub : getSubdetectors().values()) {
152             SensitiveDetector sensitiveDetector = null;
153             Readout readout = sub.getReadout();
154             if (readout != null) {
155                 if (sub.isTracker()) {
156                     sensitiveDetector = new Tracker(sub.getName());
157                 } else if (sub.isCalorimeter()) {
158                     if (readout.getSegmentation() != null && readout.getSegmentation().useForHitPosition()) {
159                         // Standard segmented calorimeter.
160                         sensitiveDetector = new Calorimeter(sub.getName());
161                     } else {
162                         // Unsegmented calorimeter for detailed readout studies.
163                         // May still have Segmentation but it is not used for the hit positions.
164                         sensitiveDetector = new UnsegmentedCalorimeter(sub.getName());
165                     }
166                 }
167                 
168                 if (sensitiveDetector != null) {
169                     sensitiveDetector.setIDSpec(idMap.get(readout));
170                     sensitiveDetector.setHitsCollection(readout.getName());
171                     lcdd.addSensitiveDetector(sensitiveDetector);
172                 }
173 
174                 
175                 /* Add the hit_processor elements. */
176                 for (String processorName : readout.getProcessorNames()) {
177                     sensitiveDetector.addContent(new HitProcessor(processorName));
178                 }
179                 
180                 /* Add the hits_collection elements. */
181                 for (String collectionName : readout.getCollectionNames()) {
182                     sensitiveDetector.addContent(new HitsCollection(collectionName));
183                 }
184                 
185                 if (sub.isCalorimeter()) {
186                     try {
187                         if (readout.getSegmentation() != null) {
188                             LCDDSegmentation seg = (LCDDSegmentation) readout.getSegmentation();
189                             seg.setSegmentation((Calorimeter) sensitiveDetector);
190                         }
191                     } catch (Throwable x) {
192                         throw new RuntimeException("Readout " + readout.getName() + " is not a valid Segmentation object.", x);
193                     }
194                 }
195 
196             }
197 
198             // System.out.println("class:" + sub.getClass().getCanonicalName());
199 
200             if (sub instanceof LCDDSubdetector) {
201                 ((LCDDSubdetector) sub).addToLCDD(lcdd, sensitiveDetector);
202             } else {
203                 throw new RuntimeException("Subdetector is not an instanceof LCDDSubdetector.");
204             }
205         }
206     }
207 
208     private void writeVisAttribs(LCDD lcdd) {
209         // Visualization attributes.
210         for (org.lcsim.geometry.compact.VisAttributes vis : getVisAttributes().values()) {
211             VisAttributes lcddvis = new VisAttributes(vis.getName());
212 
213             float rgba[] = vis.getRGBA();
214             lcddvis.setColor(rgba[0], rgba[1], rgba[2], rgba[3]);
215             lcddvis.setDrawingStyle(vis.getDrawingStyle());
216             lcddvis.setLineStyle(vis.getLineStyle());
217             lcddvis.setVisible(vis.getVisible());
218             lcddvis.setShowDaughters(vis.getShowDaughters());
219 
220             lcdd.add(lcddvis);
221         }
222     }
223 
224     private void writeLimits(LCDD lcdd) {
225         for (org.lcsim.geometry.compact.LimitSet limitset : getLimits().values()) {
226             LimitSet lcddLimitSet = new LimitSet(limitset.getName());
227             for (org.lcsim.geometry.compact.Limit limit : limitset.getLimits().values()) {
228                 Limit lcddLimit = new Limit(limit.getName());
229 
230                 lcddLimit.setParticles(limit.getParticles());
231                 lcddLimit.setUnit(limit.getUnit());
232                 lcddLimit.setValue(limit.getValue());
233 
234                 lcddLimitSet.addLimit(lcddLimit);
235             }
236             lcdd.addLimitSet(lcddLimitSet);
237         }
238     }
239 
240     private void writeRegions(LCDD lcdd) {
241         for (org.lcsim.geometry.compact.Region region : getRegions().values()) {
242             Region lcddRegion = new Region(region.getName());
243             lcddRegion.setStoreSecondaries(region.getStoreSecondaries());
244             lcddRegion.setKillTracks(region.getKillTracks());
245             lcddRegion.setThreshold(region.getEnergyThreshold());
246             lcddRegion.setEnergyUnit(region.getEnergyUnit());
247             lcddRegion.setLengthUnit(region.getLengthUnit());
248             lcddRegion.setCut(region.getRangeCut());
249             lcdd.addRegion(lcddRegion);
250         }
251     }
252     
253     private void writeMatrices(LCDD lcdd) {
254         for (String name : this.getMatrices().keySet()) {
255              Matrix matrix = this.getMatrix(name);
256              int coldim = matrix.getColumnDimension();             
257              org.lcsim.geometry.compact.converter.lcdd.util.Matrix lcddMatrix = 
258                      new org.lcsim.geometry.compact.converter.lcdd.util.Matrix(name, coldim);                         
259              String values = "";
260              for (int i=0, n=matrix.getRowDimension(); i<n; i++) {
261                  String row = "";
262                  for (int j=0; j<coldim; j++) {
263                      row += matrix.get(i, j) + " ";
264                  }
265                  values += row.trim() + '\n';
266              }
267              values = values.trim();
268              lcddMatrix.setValues(values);
269              lcdd.add(lcddMatrix);
270         }
271     }
272 
273     private Map<Readout, IDSpec> writeReadouts(LCDD lcdd) {
274         // Loop over the readouts
275         Map<Readout, IDSpec> idMap = new HashMap<Readout, IDSpec>();
276         for (Readout readout : getReadouts().values()) {            
277             /* Setup the IdSpec for this readout. */
278             setupIdSpec(lcdd, idMap, readout);            
279         }
280         return idMap;
281     }
282 
283     private void setupIdSpec(LCDD lcdd, Map<Readout, IDSpec> idMap, Readout readout) {
284         IDDescriptor id = readout.getIDDescriptor();
285         IDSpec idspec = new IDSpec(readout.getName());
286         idspec.setLength(id.getMaxBit());
287 
288         for (int i = 0; i < id.fieldCount(); i++) {
289             IDField field = new IDField();
290             field.setLabel(id.fieldName(i));
291             field.setLength(id.fieldLength(i));
292             field.setStart(id.fieldStart(i));
293             field.setSigned(id.isSigned(i));
294             idspec.addIDField(field);
295         }
296         lcdd.addIDSpec(idspec);
297         idMap.put(readout, idspec);
298     }
299 
300     private void setupMaterials(LCDD lcdd) throws JDOMException {
301         LCDDMaterialHelper helper = new LCDDMaterialHelper(getXMLMaterialManager());
302         helper.copyToLCDD(compact, lcdd);
303     }
304 
305     public String getName() {
306         return "GeomConverter";
307     }
308 
309     private String getVersion() {
310         return "1.0";
311     }
312 
313     private long getChecksum() {
314         return checksum;
315     }
316 
317     private long calculateChecksum(Element top) throws IOException {
318         // Write out in canonical format to calculate checksum
319         // ignoring comments and whitespace
320         Iterator iter = top.getDescendants(new ContentFilter(ContentFilter.COMMENT));
321         while (iter.hasNext()) {
322             iter.next();
323             iter.remove();
324         }
325 
326         CRC32 check = new CRC32();
327         OutputStream out = new CheckedOutputStream(new NullOutputStream(), check);
328 
329         XMLOutputter outputter = new XMLOutputter();
330         outputter.setFormat(Format.getCompactFormat());
331         outputter.output(top, out);
332         out.close();
333         return check.getValue();
334     }
335 
336     private static class NullOutputStream extends OutputStream {
337         public void write(byte[] b, int off, int len) throws IOException {
338         }
339 
340         public void write(byte[] b) throws IOException {
341         }
342 
343         public void write(int b) throws IOException {
344         }
345     }
346 }