1 package org.lcsim.geometry.compact.converter.pandora;
2
3 import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_BARREL;
4 import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_ENDCAP;
5 import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_BARREL;
6 import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_ENDCAP;
7 import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_BARREL;
8 import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_ENDCAP;
9 import hep.physics.particle.properties.ParticlePropertyManager;
10 import hep.physics.particle.properties.ParticleType;
11 import hep.physics.vec.BasicHep3Vector;
12 import hep.physics.vec.Hep3Vector;
13
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import java.text.DecimalFormat;
17 import java.util.ArrayList;
18 import java.util.List;
19
20 import javax.swing.filechooser.FileFilter;
21
22 import org.jdom.Document;
23 import org.jdom.Element;
24 import org.jdom.output.Format;
25 import org.jdom.output.XMLOutputter;
26 import org.lcsim.conditions.ConditionsManager;
27 import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
28 import org.lcsim.conditions.ConditionsSet;
29 import org.lcsim.detector.material.BetheBlochCalculator;
30 import org.lcsim.detector.material.IMaterial;
31 import org.lcsim.detector.material.MaterialStore;
32 import org.lcsim.detector.solids.Tube;
33 import org.lcsim.geometry.Calorimeter;
34 import org.lcsim.geometry.Detector;
35 import org.lcsim.geometry.GeometryReader;
36 import org.lcsim.geometry.compact.Subdetector;
37 import org.lcsim.geometry.compact.converter.Converter;
38 import org.lcsim.geometry.field.Solenoid;
39 import org.lcsim.geometry.layer.Layer;
40 import org.lcsim.geometry.layer.LayerSlice;
41 import org.lcsim.geometry.layer.LayerStack;
42 import org.lcsim.geometry.segmentation.AbstractCartesianGrid;
43 import org.lcsim.geometry.subdetector.AbstractPolyhedraCalorimeter;
44 import org.lcsim.geometry.subdetector.MultiLayerTracker;
45 import org.lcsim.geometry.util.BaseIDDecoder;
46 import org.lcsim.geometry.util.IDDescriptor;
47 import org.lcsim.geometry.util.SamplingFractionManager;
48
49
50
51
52
53
54
55
56 public class Main implements Converter
57 {
58 private final static boolean DEBUG = false;
59
60
61 private ConditionsManager conditionsManager = ConditionsManager.defaultInstance();
62
63
64 static final DecimalFormat xlen = new DecimalFormat("#.########");
65 static final DecimalFormat xfrac = new DecimalFormat("#.########");
66 static final DecimalFormat xthick = new DecimalFormat("#.######");
67
68 public void convert(String inputFileName, InputStream in, OutputStream out) throws Exception
69 {
70 GeometryReader reader = new GeometryReader();
71 Detector det = reader.read(in);
72 String detectorName = det.getDetectorName();
73 try
74 {
75 conditionsManager.setDetector(detectorName, 0);
76 }
77 catch (ConditionsNotFoundException x)
78 {
79 throw new RuntimeException("Failed to setup conditions system for detector: " + detectorName, x);
80 }
81 Document doc = convertDetectorToPandora(det);
82 XMLOutputter outputter = new XMLOutputter();
83 if (out != null)
84 {
85 outputter.setFormat(Format.getPrettyFormat());
86 outputter.output(doc, out);
87 out.close();
88 }
89 }
90
91 public Document convertDetectorToPandora(Detector detector)
92 {
93
94 Document outputDoc = new Document();
95 Element root = new Element("pandoraSetup");
96 outputDoc.setRootElement(root);
97 Element calorimeters = new Element("calorimeters");
98 root.addContent(calorimeters);
99
100
101 Element detectorTag = new Element("detector");
102 detectorTag.setAttribute("name", detector.getDetectorName());
103 root.addContent(detectorTag);
104
105
106 ConditionsSet calorimeterCalibration = null;
107 try
108 {
109 calorimeterCalibration = conditionsManager.getConditions("CalorimeterCalibration");
110 }
111 catch (Exception x)
112 {
113 }
114 boolean haveCalCalib = (calorimeterCalibration == null) ? false : true;
115
116
117 for (Subdetector subdetector : detector.getSubdetectors().values())
118 {
119
120
121 if (subdetector instanceof AbstractPolyhedraCalorimeter)
122 {
123 Element calorimeter = new Element("calorimeter");
124 AbstractPolyhedraCalorimeter polycal = (AbstractPolyhedraCalorimeter) subdetector;
125
126
127
128 Calorimeter.CalorimeterType calType = polycal.getCalorimeterType();
129 if (calType.equals(HAD_BARREL) || calType.equals(HAD_ENDCAP) || calType.equals(EM_ENDCAP) || calType.equals(EM_BARREL) || calType.equals(MUON_BARREL) || calType.equals(MUON_ENDCAP))
130 {
131
132 calorimeter.setAttribute("type", Calorimeter.CalorimeterType.toString(calType));
133 calorimeter.setAttribute("innerR", Double.toString(polycal.getInnerRadius()));
134 calorimeter.setAttribute("innerZ", Double.toString(polycal.getInnerZ()));
135 calorimeter.setAttribute("innerPhi", Double.toString(polycal.getSectionPhi()));
136 calorimeter.setAttribute("innerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
137 calorimeter.setAttribute("outerR", Double.toString(polycal.getOuterRadius()));
138 calorimeter.setAttribute("outerZ", Double.toString(polycal.getOuterZ()));
139 calorimeter.setAttribute("outerPhi", Double.toString(polycal.getSectionPhi()));
140 calorimeter.setAttribute("outerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
141 calorimeter.setAttribute("collection", subdetector.getReadout().getName());
142
143
144 List<Double> cellSizes = getCellSizes(subdetector);
145
146
147 if (subdetector.isEndcap())
148 {
149 calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(0)));
150 calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(1)));
151 }
152
153 else if (subdetector.isBarrel())
154 {
155 calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(1)));
156 calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(0)));
157 }
158
159
160 calorimeter.addContent(makeIdentifierDescription(polycal));
161
162
163 calorimeters.addContent(calorimeter);
164
165 LayerStack layers = polycal.getLayering().getLayerStack();
166
167 Element layersElem = new Element("layers");
168 layersElem.setAttribute("nlayers", Integer.toString(layers.getNumberOfLayers()));
169
170 calorimeter.addContent(layersElem);
171
172 double layerD = 0.;
173
174 if (polycal.isBarrel())
175 {
176 layerD = polycal.getInnerRadius();
177 }
178 else if (polycal.isEndcap())
179 {
180 layerD = polycal.getInnerZ();
181 }
182
183 CalorimeterConditions subdetectorCalorimeterConditions = null;
184
185 if (haveCalCalib)
186 {
187 subdetectorCalorimeterConditions = new CalorimeterConditions((Calorimeter) subdetector, calorimeterCalibration);
188 }
189
190
191 if (haveCalCalib)
192 {
193 calorimeter.setAttribute("mipEnergy", xfrac.format(subdetectorCalorimeterConditions.getMipEnergy()));
194 calorimeter.setAttribute("mipSigma", xfrac.format(subdetectorCalorimeterConditions.getMipSigma()));
195 calorimeter.setAttribute("mipCut", xfrac.format(subdetectorCalorimeterConditions.getMipCut()));
196 calorimeter.setAttribute("timeCut", xfrac.format(subdetectorCalorimeterConditions.getTimeCut()));
197 }
198
199
200 else
201 {
202 List<LayerSlice> sensors = subdetector.getLayering().getLayerStack().getLayer(0).getSensors();
203 LayerSlice sensor = sensors.get(0);
204 IMaterial sensorMaterial = MaterialStore.getInstance().get(sensor.getMaterial().getName());
205
206 ParticleType particleType = ParticlePropertyManager.getParticlePropertyProvider().get(13);
207
208 Hep3Vector p = new BasicHep3Vector(-6.8641, -7.2721, 1.2168e-7);
209
210 double emip = BetheBlochCalculator.computeBetheBloch(sensorMaterial, p, particleType.getMass(), particleType.getCharge(), sensor.getThickness());
211
212
213 calorimeter.setAttribute("mipEnergy", xfrac.format(emip));
214
215
216 calorimeter.setAttribute("mipSigma", "0");
217 calorimeter.setAttribute("mipCut", "0");
218 calorimeter.setAttribute("timeCut", xfrac.format(Double.MAX_VALUE));
219 }
220
221 double totalX0 = 0;
222
223 for (int i = 0; i < layers.getNumberOfLayers(); i++)
224 {
225
226 Layer layer = layers.getLayer(i);
227
228 Element layerElem = new Element("layer");
229 layersElem.addContent(layerElem);
230
231
232 double intLen = 0;
233 double radLen = 0;
234 for (int j = 0; j < layer.getNumberOfSlices(); j++)
235 {
236 LayerSlice slice = layer.getSlice(j);
237
238 double x0 = slice.getMaterial().getRadiationLength();
239
240
241 radLen += slice.getThickness() / (x0*10);
242
243
244 double lambda = slice.getMaterial().getNuclearInteractionLength();
245 intLen += slice.getThickness() / (lambda*10);
246 }
247
248
249
250 totalX0 += radLen;
251
252
253
254 layerElem.setAttribute("radLen", xlen.format(radLen));
255 layerElem.setAttribute("intLen", xlen.format(intLen));
256
257
258 double layerD2 = layerD + layer.getThicknessToSensitiveMid();
259 layerElem.setAttribute("distanceToIp", xthick.format(layerD2));
260
261
262 layerElem.setAttribute("cellThickness", xthick.format(layer.getThickness()));
263
264
265
266 if (haveCalCalib)
267 {
268 SamplingLayerRange layerRange = subdetectorCalorimeterConditions.getSamplingLayerRange(i);
269 if (calType == EM_BARREL || calType == EM_ENDCAP)
270 {
271 layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getEMSampling()));
272 }
273 if (calType == HAD_BARREL || calType == HAD_ENDCAP)
274 {
275 layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
276 }
277 if (calType == MUON_BARREL || calType == MUON_ENDCAP)
278 {
279 layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
280 }
281 layerElem.setAttribute("emSamplingFraction", xfrac.format(layerRange.getEMSampling()));
282 layerElem.setAttribute("hadSamplingFraction", xfrac.format(layerRange.getHADSampling()));
283 }
284
285
286
287 else
288 {
289 double samplingFraction = SamplingFractionManager.defaultInstance().getSamplingFraction(subdetector, i);
290 layerElem.setAttribute("emSamplingFraction", xfrac.format(samplingFraction));
291 layerElem.setAttribute("hadSamplingFraction", xfrac.format(samplingFraction));
292 }
293
294
295 layerD += layer.getThickness();
296 }
297
298
299 }
300
301
302 try
303 {
304
305 ConditionsSet conditions = conditionsManager.getConditions("SamplingFractions/" + subdetector.getName());
306 boolean isDigital = conditions.getBoolean("digital");
307 calorimeter.setAttribute("digital", String.valueOf(isDigital));
308 }
309 catch (Exception x)
310 {
311 calorimeter.setAttribute("digital", "false");
312 }
313 }
314 }
315
316
317 double coilRadLen = 0;
318 double coilIntLen = 0;
319 int coilLayers = 0;
320 double coilInnerR = 0;
321 double coilOuterR = 0;
322 double bfield = 0;
323 double coilMaxZ = 0;
324 try
325 {
326 MultiLayerTracker c = (MultiLayerTracker) detector.getSubdetector("SolenoidCoilBarrel");
327 if (c != null)
328 {
329 coilLayers = c.getNumberOfLayers();
330 coilInnerR = c.getInnerR()[0];
331 coilOuterR = c.getInnerR()[coilLayers-1] + c.getLayerThickness(coilLayers-1);
332 for (int layern = 0; layern != c.getNumberOfLayers(); layern++)
333 {
334 for (LayerSlice slice : c.getLayer(layern).getSlices())
335 {
336 double x0 = slice.getMaterial().getRadiationLength();
337 double sliceRadLen = slice.getThickness() / (x0*10);
338 double lambda = slice.getMaterial().getNuclearInteractionLength();
339 double sliceIntLen = slice.getThickness() / (lambda*10);
340
341 coilRadLen += sliceRadLen;
342 coilIntLen += sliceIntLen;
343 }
344 }
345
346 coilRadLen = coilRadLen/(coilOuterR-coilInnerR);
347 coilIntLen = coilIntLen/(coilOuterR-coilInnerR);
348 }
349 }
350 catch (ClassCastException e)
351 {
352 throw new RuntimeException(e);
353 }
354 try
355 {
356 Solenoid s = (Solenoid) detector.getFields().get("GlobalSolenoid");
357 if (s != null)
358 {
359 bfield = s.getField(new BasicHep3Vector(0, 0, 0)).z();
360 coilMaxZ = s.getZMax();
361 }
362 }
363 catch (ClassCastException e)
364 {
365 throw new RuntimeException(e);
366 }
367
368 Element coil = new Element("coil");
369 coil.setAttribute("radLen", xlen.format(coilRadLen));
370 coil.setAttribute("intLen", xlen.format(coilIntLen));
371 coil.setAttribute("innerR", Double.toString(coilInnerR));
372 coil.setAttribute("outerR", Double.toString(coilOuterR));
373 coil.setAttribute("z", Double.toString(coilMaxZ));
374 coil.setAttribute("bfield", Double.toString(bfield));
375 root.addContent(coil);
376
377 Tube tube = (Tube) detector.getTrackingVolume().getLogicalVolume().getSolid();
378 Element tracking = new Element("tracking");
379 tracking.setAttribute("innerR", Double.toString(tube.getInnerRadius()));
380 tracking.setAttribute("outerR", Double.toString(tube.getOuterRadius()));
381 tracking.setAttribute("z", Double.toString(tube.getZHalfLength()));
382 root.addContent(tracking);
383
384 return outputDoc;
385 }
386
387 Element makeIdentifierDescription(Subdetector subdet)
388 {
389 IDDescriptor descr = subdet.getIDDecoder().getIDDescription();
390 Element id = new Element("id");
391 for (int i = 0, j = descr.fieldCount(); i < j; i++)
392 {
393 Element field = new Element("field");
394 field.setAttribute("name", descr.fieldName(i));
395 field.setAttribute("length", Integer.toString(descr.fieldLength(i)));
396 field.setAttribute("start", Integer.toString(descr.fieldStart(i)));
397 field.setAttribute("signed", Boolean.toString(descr.isSigned(i)));
398
399 id.addContent(field);
400 }
401 return id;
402 }
403
404 private List<Double> getCellSizes(Subdetector subdetector)
405 {
406 List<Double> cellSizes = new ArrayList<Double>();
407 BaseIDDecoder dec = (BaseIDDecoder) subdetector.getReadout().getIDDecoder();
408 if (dec instanceof AbstractCartesianGrid)
409 {
410 AbstractCartesianGrid cgrid = (AbstractCartesianGrid) dec;
411 if (cgrid.getGridSizeX() != 0)
412 {
413 cellSizes.add(cgrid.getGridSizeX());
414 }
415 if (cgrid.getGridSizeY() != 0)
416 {
417 cellSizes.add(cgrid.getGridSizeY());
418 }
419 if (cgrid.getGridSizeZ() != 0)
420 {
421 cellSizes.add(cgrid.getGridSizeZ());
422 }
423 }
424 if (cellSizes.size() != 2)
425 throw new RuntimeException("Only 2 cell dimensions are allowed.");
426 return cellSizes;
427 }
428
429 public String getOutputFormat()
430 {
431 return "pandora";
432 }
433
434 public FileFilter getFileFilter()
435 {
436 return new PandoraFileFilter();
437 }
438
439 private static class PandoraFileFilter extends FileFilter
440 {
441
442 public boolean accept(java.io.File file)
443 {
444 return file.getName().endsWith(".xml");
445 }
446
447 public String getDescription()
448 {
449 return "Pandora Geometry file (*.xml)";
450 }
451 }
452 }