DD4hep  1.30.0
Detector Description Toolkit for High Energy Physics
PandoraConverter.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // Author : M.Frank
11 //
12 //==========================================================================
13 #ifndef DD4HEP_DDCORE_PANDORACONVERTER_H
14 #define DD4HEP_DDCORE_PANDORACONVERTER_H
15 
16 // Framework include files
17 #include <DD4hep/Detector.h>
18 #include <DD4hep/GeoHandler.h>
20 
21 /*
22  * dd4hep namespace declaration
23  */
24 namespace dd4hep {
25 
26  /*
27  * XML namespace declaration
28  */
29  namespace detail {
30 
32 
39  struct PandoraConverter: public GeoHandler {
40  protected:
42  struct GeometryInfo: public GeoHandler::GeometryInfo {
46  GeometryInfo();
47  };
48 
53 
54  public:
55 
57  PandoraConverter(Detector& description);
58 
60  virtual ~PandoraConverter();
61 
64 
65  };
66  } // End namespace xml
67 } // End namespace dd4hep
68 
69 #endif /* DD4HEP_DDCORE_PANDORACONVERTER_H */
70 
71 //==========================================================================
72 // AIDA Detector description implementation
73 //--------------------------------------------------------------------------
74 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
75 // All rights reserved.
76 //
77 // For the licensing terms see $DD4hepINSTALL/LICENSE.
78 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
79 //
80 // Author : M.Frank
81 //
82 //==========================================================================
83 
84 // Framework includes
85 #include <DD4hep/Detector.h>
86 #include <DD4hep/GeoHandler.h>
88 #include <XML/DocumentHandler.h>
89 
90 // C/C++ include files
91 #include <stdexcept>
92 
93 using namespace dd4hep::detail;
94 using namespace dd4hep;
95 using namespace std;
96 
99  : doc(0), doc_root(0), doc_calorimeters(0), doc_detector(0), doc_coil(0), doc_tracking(0) {
100 }
101 
104  : m_detDesc(description), m_dataPtr(0) {
105 }
106 
109  if (m_dataPtr)
110  delete m_dataPtr;
111  m_dataPtr = 0;
112 }
113 
116  const char empty_xml[] = "<?xml version=\"1.0\" encoding=\"UTF-8\">\n"
117  "<!-- \n"
118  " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
119  " ++++ Linear collider detector description in C++ ++++\n"
120  " ++++ dd4hep Detector description generator. ++++\n"
121  " ++++ ++++\n"
122  " ++++ M.Frank CERN/LHCb ++++\n"
123  " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
124  "-->\n"
125  "<pandoraSetup>\n\0\0";
127  GeometryInfo& geo = *(m_dataPtr = new GeometryInfo);
128 
129  xml_elt_t elt(0);
130  Header hdr = m_detDesc.header();
131  geo.doc = docH.parse(empty_xml, sizeof(empty_xml));
132  geo.doc_root = geo.doc.root();
133  geo.doc_root.append(geo.doc_calorimeters = xml_elt_t(geo.doc, _Unicode(calorimeters)));
134  geo.doc_root.append(geo.doc_detector = xml_elt_t(geo.doc, _Unicode(detector)));
135  geo.doc_root.append(geo.doc_coil = xml_elt_t(geo.doc, _Unicode(coil)));
136  geo.doc_root.append(geo.doc_tracking = xml_elt_t(geo.doc, _Unicode(tracking)));
137  geo.doc_detector.setAttr(_Unicode(name), hdr.name());
138  geo.doc_tracking.setAttr(_Unicode(innerR), "");
139  geo.doc_tracking.setAttr(_Unicode(outerR), "");
140  geo.doc_tracking.setAttr(_Unicode(z), "");
141 
142  return geo.doc;
143 }
144 
145 static long create_description(Detector& /* description */, int /* argc */, char** /* argv */) {
146  throw runtime_error("The pandora xml conversion plugin is not yet implemented");
147  return 0;
148 #if 0
149 
150  package org.lcsim.geometry.compact.converter.pandora;
151 
152  import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_BARREL;
153  import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_ENDCAP;
154  import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_BARREL;
155  import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_ENDCAP;
156  import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_BARREL;
157  import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_ENDCAP;
158  import hep.physics.particle.properties.ParticlePropertyManager;
159  import hep.physics.particle.properties.ParticleType;
160  import hep.physics.vec.BasicHep3Vector;
161  import hep.physics.vec.Hep3Vector;
162 
163  import java.io.InputStream;
164  import java.io.OutputStream;
165  import java.text.DecimalFormat;
166  import java.util.ArrayList;
167  import java.util.List;
168  import java.util.StringTokenizer;
169 
170  import javax.swing.filechooser.FileFilter;
171 
172  import org.jdom.Document;
173  import org.jdom.Element;
174  import org.jdom.output.Format;
175  import org.jdom.output.XMLOutputter;
176  import org.lcsim.conditions.ConditionsManager;
177  import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
178  import org.lcsim.conditions.ConditionsSet;
179  import org.lcsim.detector.material.BetheBlochCalculator;
180  import org.lcsim.detector.material.IMaterial;
181  import org.lcsim.detector.material.MaterialStore;
182  import org.lcsim.detector.solids.Tube;
183  import org.lcsim.geometry.Calorimeter;
184  import org.lcsim.geometry.Calorimeter.CalorimeterType;
185  import org.lcsim.geometry.Detector;
186  import org.lcsim.geometry.GeometryReader;
187  import org.lcsim.geometry.compact.Subdetector;
188  import org.lcsim.geometry.compact.converter.Converter;
189  import org.lcsim.geometry.field.Solenoid;
190  import org.lcsim.geometry.layer.Layer;
191  import org.lcsim.geometry.layer.LayerSlice;
192  import org.lcsim.geometry.layer.LayerStack;
193  import org.lcsim.geometry.segmentation.AbstractCartesianGrid;
194  import org.lcsim.geometry.subdetector.AbstractPolyhedraCalorimeter;
195  import org.lcsim.geometry.subdetector.MultiLayerTracker;
196  import org.lcsim.geometry.util.BaseIDDecoder;
197  import org.lcsim.geometry.util.IDDescriptor;
198  import org.lcsim.geometry.util.SamplingFractionManager;
199 
207  public class Main implements Converter
208  {
209  private final static boolean DEBUG = false;
210 
211  // ConditionsManager instance.
212  private ConditionsManager conditionsManager = ConditionsManager.defaultInstance();
213 
214  // Numerical formatting.
215  static final DecimalFormat xlen = new DecimalFormat("#.########");
216  static final DecimalFormat xfrac = new DecimalFormat("#.########");
217  static final DecimalFormat xthick = new DecimalFormat("#.######");
218 
224  static class SamplingLayerRange
225  {
226  int lowerLayer;
227  int upperLayer;
228  double em;
229  double had;
230 
231  SamplingLayerRange(int lowerLayer, int upperLayer, double em, double had)
232  {
233  this.lowerLayer = lowerLayer;
234  this.upperLayer = upperLayer;
235  this.em = em;
236  this.had = had;
237  }
238 
239  public boolean inRange(int layerNumber)
240  {
241  return layerNumber >= lowerLayer && layerNumber <= upperLayer;
242  }
243 
244  public int getLowerLayer()
245  {
246  return lowerLayer;
247  }
248 
249  public int getUpperLayer()
250  {
251  return upperLayer;
252  }
253 
254  public double getEMSampling()
255  {
256  return em;
257  }
258 
259  public double getHADSampling()
260  {
261  return had;
262  }
263  }
264 
272  static class SamplingLayers extends ArrayList<SamplingLayerRange>
273  {
274  public SamplingLayers()
275  {
276  }
277 
278  public SamplingLayers(SamplingLayerRange range)
279  {
280  this.add(range);
281  }
282 
283  public SamplingLayers(List<SamplingLayerRange> ranges)
284  {
285  this.addAll(ranges);
286  }
287 
288  public SamplingLayerRange getSamplingLayerRange(int layern)
289  {
290  for (SamplingLayerRange range : this)
291  {
292  if (range.inRange(layern))
293  return range;
294  }
295  return null;
296  }
297  }
298 
304  private static class CalorimeterConditions
305  {
306  SamplingLayers samplingLayers;
307  String name;
308  double mipEnergy;
309  double mipSigma;
310  double mipCut;
311  double timeCut;
312 
313  public String toString()
314  {
315  StringBuffer buff = new StringBuffer();
316  buff.append(name + '\n');
317  for (SamplingLayerRange range : samplingLayers)
318  {
319  buff.append("[" + range.getLowerLayer() + " - " + range.getUpperLayer() + "]" + '\n');
320  buff.append(" em = " + range.getEMSampling() + '\n');
321  buff.append(" had = " + range.getHADSampling() + '\n');
322  }
323 
324  return buff.toString();
325  }
326 
327  public SamplingLayers getSamplingLayers()
328  {
329  return samplingLayers;
330  }
331 
339  protected CalorimeterConditions(Calorimeter calorimeter, ConditionsSet conditions)
340  {
341  //System.out.println("conditions: " + calorimeter.getName());
342  this.name = calorimeter.getName();
343 
344  // Figure out which layering conditions to use based on the
345  // CalorimeterType.
346  String layeringName = null;
347  if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
348  {
349  layeringName = "ECalLayering";
350  }
351  else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
352  {
353  layeringName = "HCalLayering";
354  }
355  else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
356  {
357  layeringName = "MuonLayering";
358  }
359  else
360  {
361  throw new RuntimeException("Don't know how to handle CalorimeterConditions for " + calorimeter.getName() + ".");
362  }
363 
364  String emName = null;
365  String hadName = null;
366  if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL)
367  {
368  emName = "EMBarrel_SF";
369  hadName = "HadBarrel_SF";
370  }
371  else if (calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
372  {
373  emName = "EMEndcap_SF";
374  hadName = "HadEndcap_SF";
375  }
376 
377  if (emName == null || hadName == null)
378  {
379  throw new RuntimeException("Sampling fractions not found for " + calorimeter.getName() + ".");
380  }
381 
382  String emSampling = conditions.getString(emName);
383  String hadSampling = conditions.getString(hadName);
384  List<Double> emSamplingFractions = new ArrayList<Double>();
385  List<Double> hadSamplingFractions = new ArrayList<Double>();
386  StringTokenizer tok = new StringTokenizer(emSampling, ",");
387  while (tok.hasMoreTokens())
388  {
389  Double emSamplingFraction = Double.valueOf(tok.nextToken().trim());
390  emSamplingFractions.add(emSamplingFraction);
391  }
392  tok = new StringTokenizer(hadSampling, ",");
393  while (tok.hasMoreTokens())
394  {
395  Double hadSamplingFraction = Double.valueOf(tok.nextToken().trim());
396  hadSamplingFractions.add(hadSamplingFraction);
397  }
398 
399  String layering = conditions.getString(layeringName);
400  tok = new StringTokenizer(layering, ",");
401  List<Integer> layers = new ArrayList<Integer>();
402  int maxLayer = calorimeter.getLayering().getLayerCount() - 1;
403  while (tok.hasMoreTokens())
404  {
405  String nextToken = tok.nextToken().trim();
406  int nextLayer = Integer.valueOf(nextToken);
407  layers.add(nextLayer);
408  }
409 
410  // FIXME Hack to get the correct starting index for the sampling
411  // fractions. Ideally, the sampling fractions should be separated by subdetector name.
412  int samplingIndex = 0;
413  if (calorimeter.getCalorimeterType() == HAD_BARREL || calorimeter.getCalorimeterType() == HAD_ENDCAP)
414  {
415  samplingIndex = (new StringTokenizer(conditions.getString("ECalLayering"), ",").countTokens());
416  }
417  if (calorimeter.getCalorimeterType() == MUON_BARREL || calorimeter.getCalorimeterType() == MUON_ENDCAP)
418  {
419  samplingIndex = (new StringTokenizer(conditions.getString("ECalLayering"), ",").countTokens());
420  samplingIndex += (new StringTokenizer(conditions.getString("HCalLayering"), ",").countTokens());
421  }
422 
423  // System.out.println(" samplingIndex: " + samplingIndex);
424 
425  // Create the SamplingLayerRange list.
426  samplingLayers = new SamplingLayers();
427  for (int i = 0; i < layers.size(); i++)
428  {
429  // Figure out the layer range.
430  int lowerLayer = layers.get(i);
431  int upperLayer = 0;
432  if (i + 1 > layers.size() - 1)
433  upperLayer = maxLayer;
434  else
435  upperLayer = layers.get(i + 1) - 1;
436 
437  // Create the sampling layer range.
438  double emSamplingFraction = emSamplingFractions.get(samplingIndex);
439  double hadSamplingFraction = hadSamplingFractions.get(samplingIndex);
440  SamplingLayerRange samplingLayerRange = new SamplingLayerRange(lowerLayer, upperLayer, emSamplingFraction, hadSamplingFraction);
441  // System.out.println(" " + lowerLayer + " - " + upperLayer +
442  // " : " + emSamplingFraction + ", " + hadSamplingFraction);
443 
444  samplingLayers.add(samplingLayerRange);
445 
446  ++samplingIndex;
447  }
448 
449  // MIP energy.
450  String mipCondition = null;
451  String mipSigmaCondition = null;
452  String mipCutCondition = null;
453 
454  // FIXME: Cleanup this ugliness.
455  if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
456  {
457  mipCondition = "ECalMip_MPV";
458  mipSigmaCondition = "ECalMip_sig";
459  mipCutCondition = "ECalMip_Cut";
460  }
461  else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
462  {
463  mipCondition = "HCalMip_MPV";
464  mipSigmaCondition = "HCalMip_sig";
465  mipCutCondition = "HCalMip_Cut";
466  }
467  else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
468  {
469  mipCondition = "MuonMip_MPV";
470  mipSigmaCondition = "MuonMip_sig";
471  mipCutCondition = "MuonMip_Cut";
472  }
473  mipEnergy = conditions.getDouble(mipCondition);
474  mipSigma = conditions.getDouble(mipSigmaCondition);
475  mipCut = conditions.getDouble(mipCutCondition);
476  timeCut = conditions.getDouble("timeCut");
477 
478  /*
479  * System.out.println(" mipEnergy: " + mipEnergy);
480  * System.out.println(" mipSigma: " + mipSigma);
481  * System.out.println(" mipCut: " + mipCut);
482  * System.out.println(" timeCut: " + timeCut);
483  */
484  }
485 
486  public SamplingLayerRange getSamplingLayerRange(int layer)
487  {
488  for (SamplingLayerRange layers : this.samplingLayers)
489  {
490  if (layers.inRange(layer))
491  return layers;
492  }
493  return null;
494  }
495 
496  public double getMipEnergy()
497  {
498  return mipEnergy;
499  }
500 
501  public double getMipSigma()
502  {
503  return mipSigma;
504  }
505 
506  public double getMipCut()
507  {
508  return mipCut;
509  }
510 
511  public double getTimeCut()
512  {
513  return timeCut;
514  }
515  }
516 
517  public void convert(String inputFileName, InputStream in, OutputStream out) throws Exception
518  {
519  GeometryReader reader = new GeometryReader();
520  Detector det = reader.read(in);
521  String detectorName = det.getDetectorName();
522  try
523  {
524  conditionsManager.setDetector(detectorName, 0);
525  }
526  catch (ConditionsNotFoundException x)
527  {
528  throw new RuntimeException("Failed to setup conditions system for detector: " + detectorName, x);
529  }
530  Document doc = convertDetectorToPandora(det);
531  XMLOutputter outputter = new XMLOutputter();
532  if (out != null)
533  {
534  outputter.setFormat(Format.getPrettyFormat());
535  outputter.output(doc, out);
536  out.close();
537  }
538  }
539 
540  public Document convertDetectorToPandora(Detector detector)
541  {
542  // Setup XML output document.
543  Document outputDoc = new Document();
544  Element root = new Element("pandoraSetup");
545  outputDoc.setRootElement(root);
546  Element calorimeters = new Element("calorimeters");
547  root.addContent(calorimeters);
548 
549  // Add basic detector data element.
550  Element detectorTag = new Element("detector");
551  detectorTag.setAttribute("name", detector.getDetectorName());
552  root.addContent(detectorTag);
553 
554  // Setup CalorimeterCalibration conditions.
555  ConditionsSet calorimeterCalibration = null;
556  try
557  {
558  calorimeterCalibration = conditionsManager.getConditions("CalorimeterCalibration");
559  }
560  catch (Exception x)
561  {
562  }
563  boolean haveCalCalib = (calorimeterCalibration == null) ? false : true;
564 
565  // Process the subdetectors.
566  for (Subdetector subdetector : detector.getSubdetectors().values())
567  {
568  //System.out.println(subdetector.getName());
569  // Only handle calorimeters that are planar.
570  if (subdetector instanceof AbstractPolyhedraCalorimeter)
571  {
572  Element calorimeter = new Element("calorimeter");
573  AbstractPolyhedraCalorimeter polycal = (AbstractPolyhedraCalorimeter) subdetector;
574 
575  // Look for specific calorimeter types in the compact
576  // description.
577  Calorimeter.CalorimeterType calType = polycal.getCalorimeterType();
578  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))
579  {
580  // Set basic parameters in pandora calorimeter.
581  calorimeter.setAttribute("type", Calorimeter.CalorimeterType.toString(calType));
582  calorimeter.setAttribute("innerR", Double.toString(polycal.getInnerRadius()));
583  calorimeter.setAttribute("innerZ", Double.toString(polycal.getInnerZ()));
584  calorimeter.setAttribute("innerPhi", Double.toString(polycal.getSectionPhi()));
585  calorimeter.setAttribute("innerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
586  calorimeter.setAttribute("outerR", Double.toString(polycal.getOuterRadius()));
587  calorimeter.setAttribute("outerZ", Double.toString(polycal.getOuterZ()));
588  calorimeter.setAttribute("outerPhi", Double.toString(polycal.getSectionPhi()));
589  calorimeter.setAttribute("outerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
590  calorimeter.setAttribute("collection", subdetector.getReadout().getName());
591 
592  // Get the cell sizes from the segmentation.
593  List<Double> cellSizes = getCellSizes(subdetector);
594 
595  // For endcaps, X is U, and Y is V.
596  if (subdetector.isEndcap())
597  {
598  calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(0)));
599  calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(1)));
600  }
601  // The UV mapping is flipped around for barrel. X is V, and Y is U.
602  else if (subdetector.isBarrel())
603  {
604  calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(1)));
605  calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(0)));
606  }
607 
608  // Create identifier description and add to subdet.
609  calorimeter.addContent(makeIdentifierDescription(polycal));
610 
611  // Add the calorimeter.
612  calorimeters.addContent(calorimeter);
613 
614  LayerStack layers = polycal.getLayering().getLayerStack();
615 
616  Element layersElem = new Element("layers");
617  layersElem.setAttribute("nlayers", Integer.toString(layers.getNumberOfLayers()));
618 
619  calorimeter.addContent(layersElem);
620 
621  double layerD = 0.;
622 
623  if (polycal.isBarrel())
624  {
625  layerD = polycal.getInnerRadius();
626  }
627  else if (polycal.isEndcap())
628  {
629  layerD = polycal.getInnerZ();
630  }
631 
632  CalorimeterConditions subdetectorCalorimeterConditions = null;
633 
634  if (haveCalCalib)
635  {
636  subdetectorCalorimeterConditions = new CalorimeterConditions((Calorimeter) subdetector, calorimeterCalibration);
637  }
638 
639  // Set MIP energy from calibration.
640  if (haveCalCalib)
641  {
642  calorimeter.setAttribute("mipEnergy", xfrac.format(subdetectorCalorimeterConditions.getMipEnergy()));
643  calorimeter.setAttribute("mipSigma", xfrac.format(subdetectorCalorimeterConditions.getMipSigma()));
644  calorimeter.setAttribute("mipCut", xfrac.format(subdetectorCalorimeterConditions.getMipCut()));
645  calorimeter.setAttribute("timeCut", xfrac.format(subdetectorCalorimeterConditions.getTimeCut()));
646  }
647  // Set MIP energy from Bethe-Bloche calculation.
648  // TODO Check accuracy of this algorithm.
649  else
650  {
651  List<LayerSlice> sensors = subdetector.getLayering().getLayerStack().getLayer(0).getSensors();
652  LayerSlice sensor = sensors.get(0);
653  IMaterial sensorMaterial = MaterialStore.getInstance().get(sensor.getMaterial().getName());
654 
655  ParticleType particleType = ParticlePropertyManager.getParticlePropertyProvider().get(13);
656 
657  Hep3Vector p = new BasicHep3Vector(-6.8641, -7.2721, 1.2168e-7);
658 
659  double emip = BetheBlochCalculator.computeBetheBloch(sensorMaterial, p, particleType.getMass(), particleType.getCharge(), sensor.getThickness());
660 
661  // Set MIP Energy from Bethe Bloche.
662  calorimeter.setAttribute("mipEnergy", xfrac.format(emip));
663 
664  // Set defaults for CalCalib parameters.
665  calorimeter.setAttribute("mipSigma", "0");
666  calorimeter.setAttribute("mipCut", "0");
667  calorimeter.setAttribute("timeCut", xfrac.format(Double.MAX_VALUE));
668  }
669 
670  double totalX0 = 0;
671 
672  for (int i = 0; i < layers.getNumberOfLayers(); i++)
673  {
674  //System.out.println(" layer " + i);
675  Layer layer = layers.getLayer(i);
676 
677  Element layerElem = new Element("layer");
678  layersElem.addContent(layerElem);
679 
680  // Set radiation and interaction lengths.
681  double intLen = 0;
682  double radLen = 0;
683  for (int j = 0; j < layer.getNumberOfSlices(); j++)
684  {
685  LayerSlice slice = layer.getSlice(j);
686  //System.out.println(" slice " + j + " " + slice.getMaterial().getName());
687  double x0 = slice.getMaterial().getRadiationLength();
688  //System.out.println(" x0_mat_D="+x0);
689  //System.out.println(" x0_mat="+slice.getMaterial().getRadiationLength());
690  radLen += slice.getThickness() / (x0*10);
691  //System.out.println(" radLen="+radLen);
692 
693  double lambda = slice.getMaterial().getNuclearInteractionLength();
694  intLen += slice.getThickness() / (lambda*10);
695  }
696  //System.out.println(" x0_lyr_tot=" + radLen);
697 
698  totalX0 += radLen;
699 
700  //System.out.println(" layer " + i + " " + radLen);
701 
702  layerElem.setAttribute("radLen", xlen.format(radLen));
703  layerElem.setAttribute("intLen", xlen.format(intLen));
704 
705  // Set distance to IP.
706  double layerD2 = layerD + layer.getThicknessToSensitiveMid();
707  layerElem.setAttribute("distanceToIp", xthick.format(layerD2));
708 
709  // Set cell thickness.
710  layerElem.setAttribute("cellThickness", xthick.format(layer.getThickness()));
711 
712  // Set EM and HAD sampling fractions from
713  // CalorimeterCalibration conditions, if present.
714  if (haveCalCalib)
715  {
716  SamplingLayerRange layerRange = subdetectorCalorimeterConditions.getSamplingLayerRange(i);
717  if (calType == EM_BARREL || calType == EM_ENDCAP)
718  {
719  layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getEMSampling()));
720  }
721  if (calType == HAD_BARREL || calType == HAD_ENDCAP)
722  {
723  layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
724  }
725  if (calType == MUON_BARREL || calType == MUON_ENDCAP)
726  {
727  layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
728  }
729  layerElem.setAttribute("emSamplingFraction", xfrac.format(layerRange.getEMSampling()));
730  layerElem.setAttribute("hadSamplingFraction", xfrac.format(layerRange.getHADSampling()));
731  }
732  // Set from base SamplingFraction conditions. May throw
733  // an exception if neither CalorimeterCalibration
734  // or SamplingFractions conditions exists.
735  else
736  {
737  double samplingFraction = SamplingFractionManager.defaultInstance().getSamplingFraction(subdetector, i);
738  layerElem.setAttribute("emSamplingFraction", xfrac.format(samplingFraction));
739  layerElem.setAttribute("hadSamplingFraction", xfrac.format(samplingFraction));
740  }
741 
742  // Increment layer distance by thickness of layer.
743  layerD += layer.getThickness();
744  }
745 
746  //System.out.println(" X0 Sum = " + totalX0);
747  }
748 
749  // Set digital flag.
750  try
751  {
752  // Set digital attribute from conditions, if present.
753  ConditionsSet conditions = conditionsManager.getConditions("SamplingFractions/" + subdetector.getName());
754  boolean isDigital = conditions.getBoolean("digital");
755  calorimeter.setAttribute("digital", String.valueOf(isDigital));
756  }
757  catch (Exception x)
758  {
759  calorimeter.setAttribute("digital", "false");
760  }
761  }
762  }
763 
764  // TODO clean up the hard coded assumptions on coil geometry
765  double coilRadLen = 0;
766  double coilIntLen = 0;
767  int coilLayers = 0;
768  double coilInnerR = 0;
769  double coilOuterR = 0;
770  double bfield = 0;
771  double coilMaxZ = 0;
772  try
773  {
774  MultiLayerTracker c = (MultiLayerTracker) detector.getSubdetector("SolenoidCoilBarrel");
775  if (c != null)
776  {
777  coilLayers = c.getNumberOfLayers();
778  coilInnerR = c.getInnerR()[0];
779  coilOuterR = c.getInnerR()[coilLayers-1] + c.getLayerThickness(coilLayers-1);
780  for (int layern = 0; layern != c.getNumberOfLayers(); layern++)
781  {
782  for (LayerSlice slice : c.getLayer(layern).getSlices())
783  {
784  double x0 = slice.getMaterial().getRadiationLength();
785  double sliceRadLen = slice.getThickness() / (x0*10);
786  double lambda = slice.getMaterial().getNuclearInteractionLength();
787  double sliceIntLen = slice.getThickness() / (lambda*10);
788 
789  coilRadLen += sliceRadLen;
790  coilIntLen += sliceIntLen;
791  }
792  }
793  //calculate average interaction/radiation length in coil material
794  coilRadLen = coilRadLen/(coilOuterR-coilInnerR);
795  coilIntLen = coilIntLen/(coilOuterR-coilInnerR);
796  }
797  }
798  catch (ClassCastException e)
799  {
800  throw new RuntimeException(e);
801  }
802  try
803  {
804  Solenoid s = (Solenoid) detector.getFields().get("GlobalSolenoid");
805  if (s != null)
806  {
807  bfield = s.getField(new BasicHep3Vector(0, 0, 0)).z();
808  coilMaxZ = s.getZMax();
809  }
810  }
811  catch (ClassCastException e)
812  {
813  throw new RuntimeException(e);
814  }
815 
816  Element coil = new Element("coil");
817  coil.setAttribute("radLen", xlen.format(coilRadLen));
818  coil.setAttribute("intLen", xlen.format(coilIntLen));
819  coil.setAttribute("innerR", Double.toString(coilInnerR));
820  coil.setAttribute("outerR", Double.toString(coilOuterR));
821  coil.setAttribute("z", Double.toString(coilMaxZ));
822  coil.setAttribute("bfield", Double.toString(bfield));
823  root.addContent(coil);
824 
825  Tube tube = (Tube) detector.getTrackingVolume().getLogicalVolume().getSolid();
826  Element tracking = new Element("tracking");
827  tracking.setAttribute("innerR", Double.toString(tube.getInnerRadius()));
828  tracking.setAttribute("outerR", Double.toString(tube.getOuterRadius()));
829  tracking.setAttribute("z", Double.toString(tube.getZHalfLength()));
830  root.addContent(tracking);
831 
832  return outputDoc;
833  }
834 
835  Element makeIdentifierDescription(Subdetector subdet)
836  {
837  IDDescriptor descr = subdet.getIDDecoder().getIDDescription();
838  Element id = new Element("id");
839  for (int i = 0, j = descr.fieldCount(); i < j; i++)
840  {
841  Element field = new Element("field");
842  field.setAttribute("name", descr.fieldName(i));
843  field.setAttribute("length", Integer.toString(descr.fieldLength(i)));
844  field.setAttribute("start", Integer.toString(descr.fieldStart(i)));
845  field.setAttribute("signed", Boolean.toString(descr.isSigned(i)));
846 
847  id.addContent(field);
848  }
849  return id;
850  }
851 
852  private List<Double> getCellSizes(Subdetector subdetector)
853  {
854  List<Double> cellSizes = new ArrayList<Double>();
855  BaseIDDecoder dec = (BaseIDDecoder) subdetector.getReadout().getIDDecoder();
856  if (dec instanceof AbstractCartesianGrid)
857  {
858  AbstractCartesianGrid cgrid = (AbstractCartesianGrid) dec;
859  if (cgrid.getGridSizeX() != 0)
860  {
861  cellSizes.add(cgrid.getGridSizeX());
862  }
863  if (cgrid.getGridSizeY() != 0)
864  {
865  cellSizes.add(cgrid.getGridSizeY());
866  }
867  if (cgrid.getGridSizeZ() != 0)
868  {
869  cellSizes.add(cgrid.getGridSizeZ());
870  }
871  }
872  if (cellSizes.size() != 2)
873  throw new RuntimeException("Only 2 cell dimensions are allowed.");
874  return cellSizes;
875  }
876 
877  public String getOutputFormat()
878  {
879  return "pandora";
880  }
881 
882  public FileFilter getFileFilter()
883  {
884  return new PandoraFileFilter();
885  }
886 
887  private static class PandoraFileFilter extends FileFilter
888  {
889 
890  public boolean accept(java.io.File file)
891  {
892  return file.getName().endsWith(".xml");
893  }
894 
895  public String getDescription()
896  {
897  return "Pandora Geometry file (*.xml)";
898  }
899  }
900  }
901 #endif
902 }
903 DECLARE_APPLY(DD4hepGeometry2PANDORA,create_description)
dd4hep::xml::Element::append
void append(Handle_t handle) const
Append a new element to the existing tree.
Definition: XMLElements.h:839
dd4hep::detail::PandoraConverter::GeometryInfo::doc_calorimeters
xml_elt_t doc_calorimeters
Definition: PandoraConverter.cpp:44
Detector.h
dd4hep::detail::PandoraConverter::GeometryInfo::doc_coil
xml_elt_t doc_coil
Definition: PandoraConverter.cpp:44
dd4hep::LayerStack
Class to describe a layering stack.
Definition: Layering.h:87
dd4hep::IDDescriptor
Class implementing the ID encoding of the detector response.
Definition: IDDescriptor.h:37
DECLARE_APPLY
#define DECLARE_APPLY(name, func)
Definition: Factories.h:281
dd4hep::detail::PandoraConverter::GeometryInfo::doc_tracking
xml_elt_t doc_tracking
Definition: PandoraConverter.cpp:44
dd4hep::Layer
Class to describe one layer in a layering stack.
Definition: Layering.h:56
dd4hep::detail::PandoraConverter::create
xml_doc_t create(DetElement top)
Create geometry conversion in Pandora XML format.
Definition: PandoraConverter.cpp:115
_Unicode
#define _Unicode(a)
Definition: Tags.h:24
dd4hep::Header::name
const std::string name() const
Accessor to object name.
Definition: Objects.cpp:68
DocumentHandler.h
dd4hep::detail::PandoraConverter::m_dataPtr
GeometryInfo * m_dataPtr
Data pointer.
Definition: PandoraConverter.cpp:52
dd4hep::DetElement
Handle class describing a detector element.
Definition: DetElement.h:188
dd4hep::detail::GeoHandler
The base class for all dd4hep geometry crawlers.
Definition: GeoHandler.h:87
dd4hep::detail
DD4hep internal namespace.
Definition: Alignments.h:32
dd4hep::detail::PandoraConverter::GeometryInfo::doc_detector
xml_elt_t doc_detector
Definition: PandoraConverter.cpp:44
dd4hep::detail::PandoraConverter::GeometryInfo
Helper class.
Definition: PandoraConverter.cpp:42
dd4hep::detail::PandoraConverter::GeometryInfo::doc_root
xml_elt_t doc_root
Definition: PandoraConverter.cpp:44
dd4hep::detail::PandoraConverter::~PandoraConverter
virtual ~PandoraConverter()
Standard destructor.
Definition: PandoraConverter.cpp:108
dd4hep::Header
Handle class describing the basic information about geometry objects as it is defined in Detector.
Definition: Objects.h:158
dd4hep::xml::DocumentHandler::parse
virtual Document parse(const char *doc_string, size_t length) const
Parse a standalong XML string into a document.
Definition: DocumentHandler.cpp:656
dd4hep::xml::Document
Class supporting the basic functionality of an XML document.
Definition: XMLElements.h:697
DetFactoryHelper.h
dd4hep::LayerSlice
Class to describe the slice of one layer in a layering stack.
Definition: Layering.h:32
dd4hep::xml::DocumentHandler
Class supporting to read and parse XML documents.
Definition: DocumentHandler.h:39
std
Definition: Plugins.h:30
dd4hep::xml::Element
User abstraction class to manipulate XML elements within a document.
Definition: XMLElements.h:769
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::xml::Element::setAttr
Attribute setAttr(const XmlChar *nam, const T &val) const
Set single attribute.
Definition: XMLElements.h:900
det
DetElement::Object * det
Definition: AlignmentsCalculator.cpp:66
dd4hep::detail::tools::toString
std::string toString(const PlacedVolume::VolIDs &ids)
Convert VolumeID to string.
Definition: DetectorTools.cpp:378
dd4hep::detail::PandoraConverter::m_detDesc
Detector & m_detDesc
Reference to detector description.
Definition: PandoraConverter.cpp:50
dd4hep::Detector
The main interface to the dd4hep detector description package.
Definition: Detector.h:90
dd4hep::detail::PandoraConverter::PandoraConverter
PandoraConverter(Detector &description)
Initializing Constructor.
Definition: PandoraConverter.cpp:103
dd4hep::detail::PandoraConverter::GeometryInfo::doc
xml_doc_t doc
Definition: PandoraConverter.cpp:43
dd4hep::detail::PandoraConverter::GeometryInfo::GeometryInfo
GeometryInfo()
Helper constructor.
Definition: PandoraConverter.cpp:98
dd4hep::Tube
Class describing a tube shape of a section of a tube.
Definition: Shapes.h:628
dd4hep::detail::PandoraConverter
Converter to create Pandora structures from dd4hep (NOT IMPLEMENTED)
Definition: PandoraConverter.cpp:39
dd4hep::Detector::header
virtual Header header() const =0
Accessor to the map of header entries.
GeoHandler.h
dd4hep::xml::Document::root
Handle_t root() const
Access the ROOT eleemnt of the DOM document.
Definition: XMLElements.cpp:1040