Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:16:48

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 #ifndef DD4HEP_DDCORE_PANDORACONVERTER_H
0014 #define DD4HEP_DDCORE_PANDORACONVERTER_H
0015 
0016 // Framework include files
0017 #include <DD4hep/Detector.h>
0018 #include <DD4hep/GeoHandler.h>
0019 #include <DD4hep/DetFactoryHelper.h>
0020 
0021 /*
0022  *   dd4hep namespace declaration
0023  */
0024 namespace dd4hep {
0025 
0026   /*
0027    *   XML namespace declaration
0028    */
0029   namespace detail {
0030 
0031     /// Converter to create Pandora structures from dd4hep (NOT IMPLEMENTED)
0032     /** @class PandoraConverter PandoraConverter.h XML/PandoraConverter.h
0033      *
0034      * Geometry converter from dd4hep to Geant 4.
0035      *
0036      * @author  M.Frank
0037      * @version 1.0
0038      */
0039     struct PandoraConverter: public GeoHandler {
0040     protected:
0041       /// Helper class
0042       struct GeometryInfo: public GeoHandler::GeometryInfo {
0043         xml_doc_t doc;
0044         xml_elt_t doc_root, doc_calorimeters, doc_detector, doc_coil, doc_tracking;
0045         /// Helper constructor
0046         GeometryInfo();
0047       };
0048 
0049       /// Reference to detector description
0050       Detector& m_detDesc;
0051       /// Data pointer
0052       GeometryInfo* m_dataPtr;
0053 
0054     public:
0055 
0056       /// Initializing Constructor
0057       PandoraConverter(Detector& description);
0058 
0059       /// Standard destructor
0060       virtual ~PandoraConverter();
0061 
0062       /// Create geometry conversion in Pandora XML format
0063       xml_doc_t create(DetElement top);
0064 
0065     };
0066   }    // End namespace xml
0067 }      // End namespace dd4hep
0068 
0069 #endif /* DD4HEP_DDCORE_PANDORACONVERTER_H   */
0070 
0071 //==========================================================================
0072 //  AIDA Detector description implementation 
0073 //--------------------------------------------------------------------------
0074 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0075 // All rights reserved.
0076 //
0077 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0078 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0079 //
0080 // Author     : M.Frank
0081 //
0082 //==========================================================================
0083 
0084 // Framework includes
0085 #include <DD4hep/Detector.h>
0086 #include <DD4hep/GeoHandler.h>
0087 #include <DD4hep/DetFactoryHelper.h>
0088 #include <XML/DocumentHandler.h>
0089 
0090 // C/C++ include files
0091 #include <stdexcept>
0092 
0093 using namespace dd4hep::detail;
0094 using namespace dd4hep;
0095 using namespace std;
0096 
0097 /// Helper constructor
0098 PandoraConverter::GeometryInfo::GeometryInfo()
0099   : doc(0), doc_root(0), doc_calorimeters(0), doc_detector(0), doc_coil(0), doc_tracking(0) {
0100 }
0101 
0102 /// Initializing Constructor
0103 PandoraConverter::PandoraConverter(Detector& description)
0104   : m_detDesc(description), m_dataPtr(0) {
0105 }
0106 
0107 /// Standard destructor
0108 PandoraConverter::~PandoraConverter() {
0109   if (m_dataPtr)
0110     delete m_dataPtr;
0111   m_dataPtr = 0;
0112 }
0113 
0114 /// Create geometry conversion in Pandora XML format
0115 xml_doc_t PandoraConverter::create(DetElement /* top */) {
0116   const char empty_xml[] = "<?xml version=\"1.0\" encoding=\"UTF-8\">\n"
0117     "<!--                                                               \n"
0118     "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
0119     "      ++++   Linear collider detector description in C++       ++++\n"
0120     "      ++++   dd4hep Detector description generator.            ++++\n"
0121     "      ++++                                                     ++++\n"
0122     "      ++++                              M.Frank CERN/LHCb      ++++\n"
0123     "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
0124     "-->\n"
0125     "<pandoraSetup>\n\0\0";
0126   xml::DocumentHandler docH;
0127   GeometryInfo& geo = *(m_dataPtr = new GeometryInfo);
0128 
0129   xml_elt_t elt(0);
0130   Header hdr = m_detDesc.header();
0131   geo.doc = docH.parse(empty_xml, sizeof(empty_xml));
0132   geo.doc_root = geo.doc.root();
0133   geo.doc_root.append(geo.doc_calorimeters = xml_elt_t(geo.doc, _Unicode(calorimeters)));
0134   geo.doc_root.append(geo.doc_detector = xml_elt_t(geo.doc, _Unicode(detector)));
0135   geo.doc_root.append(geo.doc_coil = xml_elt_t(geo.doc, _Unicode(coil)));
0136   geo.doc_root.append(geo.doc_tracking = xml_elt_t(geo.doc, _Unicode(tracking)));
0137   geo.doc_detector.setAttr(_Unicode(name), hdr.name());
0138   geo.doc_tracking.setAttr(_Unicode(innerR), "");
0139   geo.doc_tracking.setAttr(_Unicode(outerR), "");
0140   geo.doc_tracking.setAttr(_Unicode(z), "");
0141 
0142   return geo.doc;
0143 }
0144 
0145 static long create_description(Detector& /* description */, int /* argc */, char** /* argv */) {
0146   throw runtime_error("The pandora xml conversion plugin is not yet implemented");
0147   return 0;
0148 #if 0
0149 
0150   package org.lcsim.geometry.compact.converter.pandora;
0151 
0152   import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_BARREL;
0153   import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_ENDCAP;
0154   import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_BARREL;
0155   import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_ENDCAP;
0156   import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_BARREL;
0157   import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_ENDCAP;
0158   import hep.physics.particle.properties.ParticlePropertyManager;
0159   import hep.physics.particle.properties.ParticleType;
0160   import hep.physics.vec.BasicHep3Vector;
0161   import hep.physics.vec.Hep3Vector;
0162 
0163   import java.io.InputStream;
0164   import java.io.OutputStream;
0165   import java.text.DecimalFormat;
0166   import java.util.ArrayList;
0167   import java.util.List;
0168   import java.util.StringTokenizer;
0169 
0170   import javax.swing.filechooser.FileFilter;
0171 
0172   import org.jdom.Document;
0173   import org.jdom.Element;
0174   import org.jdom.output.Format;
0175   import org.jdom.output.XMLOutputter;
0176   import org.lcsim.conditions.ConditionsManager;
0177   import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
0178   import org.lcsim.conditions.ConditionsSet;
0179   import org.lcsim.detector.material.BetheBlochCalculator;
0180   import org.lcsim.detector.material.IMaterial;
0181   import org.lcsim.detector.material.MaterialStore;
0182   import org.lcsim.detector.solids.Tube;
0183   import org.lcsim.geometry.Calorimeter;
0184   import org.lcsim.geometry.Calorimeter.CalorimeterType;
0185   import org.lcsim.geometry.Detector;
0186   import org.lcsim.geometry.GeometryReader;
0187   import org.lcsim.geometry.compact.Subdetector;
0188   import org.lcsim.geometry.compact.converter.Converter;
0189   import org.lcsim.geometry.field.Solenoid;
0190   import org.lcsim.geometry.layer.Layer;
0191   import org.lcsim.geometry.layer.LayerSlice;
0192   import org.lcsim.geometry.layer.LayerStack;
0193   import org.lcsim.geometry.segmentation.AbstractCartesianGrid;
0194   import org.lcsim.geometry.subdetector.AbstractPolyhedraCalorimeter;
0195   import org.lcsim.geometry.subdetector.MultiLayerTracker;
0196   import org.lcsim.geometry.util.BaseIDDecoder;
0197   import org.lcsim.geometry.util.IDDescriptor;
0198   import org.lcsim.geometry.util.SamplingFractionManager;
0199 
0200   /**
0201    * This class converts from a compact detector description into slicPandora's
0202    * geometry input format.
0203    *
0204    * @author  Jeremy McCormick <jeremym@slac.stanford.edu>
0205    * @version 1.0
0206    */
0207                                                         public class Main implements Converter
0208                                                         {
0209   private final static boolean DEBUG = false;
0210 
0211   // ConditionsManager instance.
0212                                             private ConditionsManager conditionsManager = ConditionsManager.defaultInstance();
0213 
0214                                             // Numerical formatting.
0215                                             static final DecimalFormat xlen = new DecimalFormat("#.########");
0216                                             static final DecimalFormat xfrac = new DecimalFormat("#.########");
0217                                             static final DecimalFormat xthick = new DecimalFormat("#.######");
0218 
0219                                             /**
0220                                              * A range of layers with associated EM and HAD sampling fractions.
0221                                              *
0222                                              * @author Jeremy McCormick <jeremym@slac.stanford.edu>
0223                                              */
0224                                             static class SamplingLayerRange
0225                                             {
0226                                               int lowerLayer;
0227                                               int upperLayer;
0228                                               double em;
0229                                               double had;
0230 
0231                                               SamplingLayerRange(int lowerLayer, int upperLayer, double em, double had)
0232                                               {
0233                                                 this.lowerLayer = lowerLayer;
0234                                                 this.upperLayer = upperLayer;
0235                                                 this.em = em;
0236                                                 this.had = had;
0237                                               }
0238 
0239     public boolean inRange(int layerNumber)
0240                                               {
0241                                                 return layerNumber >= lowerLayer && layerNumber <= upperLayer;
0242                                               }
0243 
0244     public int getLowerLayer()
0245                                               {
0246                                                 return lowerLayer;
0247                                               }
0248 
0249     public int getUpperLayer()
0250                                               {
0251                                                 return upperLayer;
0252                                               }
0253 
0254     public double getEMSampling()
0255                                               {
0256                                                 return em;
0257                                               }
0258 
0259     public double getHADSampling()
0260                                               {
0261                                                 return had;
0262                                               }
0263                                             }
0264 
0265                                             /**
0266                                              * A list of SamplingLayerRange objects to represent the sampling for a
0267                                              * subdetector.
0268                                              *
0269                                              * @author Jeremy McCormick <jeremym@slac.stanford.edu>
0270                                              *
0271                                              */
0272                                             static class SamplingLayers extends ArrayList<SamplingLayerRange>
0273                                             {
0274     public SamplingLayers()
0275     {
0276     }
0277 
0278     public SamplingLayers(SamplingLayerRange range)
0279     {
0280       this.add(range);
0281     }
0282 
0283     public SamplingLayers(List<SamplingLayerRange> ranges)
0284     {
0285       this.addAll(ranges);
0286     }
0287 
0288     public SamplingLayerRange getSamplingLayerRange(int layern)
0289     {
0290       for (SamplingLayerRange range : this)
0291       {
0292         if (range.inRange(layern))
0293           return range;
0294       }
0295       return null;
0296     }
0297                                             }
0298 
0299                                             /**
0300                                              * Represents CalorimeterConditions for a single subdetector.
0301                                              *
0302                                              * @author Jeremy McCormick <jeremym@slac.stanford.edu>
0303                                              */
0304   private static class CalorimeterConditions
0305   {
0306     SamplingLayers samplingLayers;
0307     String name;
0308     double mipEnergy;
0309     double mipSigma;
0310     double mipCut;
0311     double timeCut;
0312 
0313                   public String toString()
0314     {
0315       StringBuffer buff = new StringBuffer();
0316       buff.append(name + '\n');
0317       for (SamplingLayerRange range : samplingLayers)
0318       {
0319         buff.append("[" + range.getLowerLayer() + " - " + range.getUpperLayer() + "]" + '\n');
0320         buff.append("    em = " + range.getEMSampling() + '\n');
0321         buff.append("    had = " + range.getHADSampling() + '\n');
0322       }
0323 
0324       return buff.toString();
0325     }
0326 
0327     public SamplingLayers getSamplingLayers()
0328     {
0329       return samplingLayers;
0330     }
0331 
0332     /**
0333      * Constructor that parses raw CalorimeterCalibration conditions for a
0334      * single subdetector.
0335      *
0336      * @param calorimeter
0337      * @param conditions
0338      */
0339     protected CalorimeterConditions(Calorimeter calorimeter, ConditionsSet conditions)
0340     {
0341       //System.out.println("conditions: " + calorimeter.getName());
0342       this.name = calorimeter.getName();
0343 
0344       // Figure out which layering conditions to use based on the
0345       // CalorimeterType.
0346       String layeringName = null;
0347       if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
0348       {
0349         layeringName = "ECalLayering";
0350       }
0351       else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
0352       {
0353         layeringName = "HCalLayering";
0354       }
0355       else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
0356       {
0357         layeringName = "MuonLayering";
0358       }
0359       else
0360       {
0361         throw new RuntimeException("Don't know how to handle CalorimeterConditions for " + calorimeter.getName() + ".");
0362       }
0363 
0364       String emName = null;
0365       String hadName = null;
0366       if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL)
0367       {
0368         emName = "EMBarrel_SF";
0369         hadName = "HadBarrel_SF";
0370       }
0371       else if (calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
0372       {
0373         emName = "EMEndcap_SF";
0374         hadName = "HadEndcap_SF";
0375       }
0376 
0377       if (emName == null || hadName == null)
0378       {
0379         throw new RuntimeException("Sampling fractions not found for " + calorimeter.getName() + ".");
0380       }
0381 
0382       String emSampling = conditions.getString(emName);
0383       String hadSampling = conditions.getString(hadName);
0384       List<Double> emSamplingFractions = new ArrayList<Double>();
0385       List<Double> hadSamplingFractions = new ArrayList<Double>();
0386       StringTokenizer tok = new StringTokenizer(emSampling, ",");
0387       while (tok.hasMoreTokens())
0388       {
0389         Double emSamplingFraction = Double.valueOf(tok.nextToken().trim());
0390         emSamplingFractions.add(emSamplingFraction);
0391       }
0392       tok = new StringTokenizer(hadSampling, ",");
0393       while (tok.hasMoreTokens())
0394       {
0395         Double hadSamplingFraction = Double.valueOf(tok.nextToken().trim());
0396         hadSamplingFractions.add(hadSamplingFraction);
0397       }
0398 
0399       String layering = conditions.getString(layeringName);
0400       tok = new StringTokenizer(layering, ",");
0401       List<Integer> layers = new ArrayList<Integer>();
0402       int maxLayer = calorimeter.getLayering().getLayerCount() - 1;
0403       while (tok.hasMoreTokens())
0404       {
0405         String nextToken = tok.nextToken().trim();
0406         int nextLayer = Integer.valueOf(nextToken);
0407         layers.add(nextLayer);
0408       }
0409 
0410       // FIXME Hack to get the correct starting index for the sampling
0411       // fractions. Ideally, the sampling fractions should be separated by subdetector name.
0412       int samplingIndex = 0;
0413       if (calorimeter.getCalorimeterType() == HAD_BARREL || calorimeter.getCalorimeterType() == HAD_ENDCAP)
0414       {
0415         samplingIndex = (new StringTokenizer(conditions.getString("ECalLayering"), ",").countTokens());
0416       }
0417       if (calorimeter.getCalorimeterType() == MUON_BARREL || calorimeter.getCalorimeterType() == MUON_ENDCAP)
0418       {
0419         samplingIndex = (new StringTokenizer(conditions.getString("ECalLayering"), ",").countTokens());
0420         samplingIndex += (new StringTokenizer(conditions.getString("HCalLayering"), ",").countTokens());
0421       }
0422 
0423       // System.out.println("    samplingIndex: " + samplingIndex);
0424 
0425       // Create the SamplingLayerRange list.
0426       samplingLayers = new SamplingLayers();
0427       for (int i = 0; i < layers.size(); i++)
0428       {
0429         // Figure out the layer range.
0430         int lowerLayer = layers.get(i);
0431         int upperLayer = 0;
0432         if (i + 1 > layers.size() - 1)
0433           upperLayer = maxLayer;
0434         else
0435           upperLayer = layers.get(i + 1) - 1;
0436 
0437         // Create the sampling layer range.
0438         double emSamplingFraction = emSamplingFractions.get(samplingIndex);
0439         double hadSamplingFraction = hadSamplingFractions.get(samplingIndex);
0440         SamplingLayerRange samplingLayerRange = new SamplingLayerRange(lowerLayer, upperLayer, emSamplingFraction, hadSamplingFraction);
0441         // System.out.println("    " + lowerLayer + " - " + upperLayer +
0442         // " : " + emSamplingFraction + ", " + hadSamplingFraction);
0443 
0444         samplingLayers.add(samplingLayerRange);
0445 
0446         ++samplingIndex;
0447       }
0448 
0449       // MIP energy.
0450       String mipCondition = null;
0451       String mipSigmaCondition = null;
0452       String mipCutCondition = null;
0453 
0454       // FIXME: Cleanup this ugliness.
0455       if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
0456       {
0457         mipCondition = "ECalMip_MPV";
0458         mipSigmaCondition = "ECalMip_sig";
0459         mipCutCondition = "ECalMip_Cut";
0460       }
0461       else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
0462       {
0463         mipCondition = "HCalMip_MPV";
0464         mipSigmaCondition = "HCalMip_sig";
0465         mipCutCondition = "HCalMip_Cut";
0466       }
0467       else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
0468       {
0469         mipCondition = "MuonMip_MPV";
0470         mipSigmaCondition = "MuonMip_sig";
0471         mipCutCondition = "MuonMip_Cut";
0472       }
0473       mipEnergy = conditions.getDouble(mipCondition);
0474       mipSigma = conditions.getDouble(mipSigmaCondition);
0475       mipCut = conditions.getDouble(mipCutCondition);
0476       timeCut = conditions.getDouble("timeCut");
0477 
0478       /*
0479        * System.out.println("    mipEnergy: " + mipEnergy);
0480        * System.out.println("    mipSigma: " + mipSigma);
0481        * System.out.println("    mipCut: " + mipCut);
0482        * System.out.println("    timeCut: " + timeCut);
0483        */
0484     }
0485 
0486     public SamplingLayerRange getSamplingLayerRange(int layer)
0487     {
0488       for (SamplingLayerRange layers : this.samplingLayers)
0489       {
0490         if (layers.inRange(layer))
0491           return layers;
0492       }
0493       return null;
0494     }
0495 
0496     public double getMipEnergy()
0497     {
0498       return mipEnergy;
0499     }
0500 
0501     public double getMipSigma()
0502     {
0503       return mipSigma;
0504     }
0505 
0506     public double getMipCut()
0507     {
0508       return mipCut;
0509     }
0510 
0511     public double getTimeCut()
0512     {
0513       return timeCut;
0514     }
0515   }
0516 
0517   public void convert(String inputFileName, InputStream in, OutputStream out) throws Exception
0518   {
0519     GeometryReader reader = new GeometryReader();
0520     Detector det = reader.read(in);
0521     String detectorName = det.getDetectorName();
0522     try
0523     {
0524       conditionsManager.setDetector(detectorName, 0);
0525     }
0526     catch (ConditionsNotFoundException x)
0527     {
0528       throw new RuntimeException("Failed to setup conditions system for detector: " + detectorName, x);
0529     }
0530     Document doc = convertDetectorToPandora(det);
0531     XMLOutputter outputter = new XMLOutputter();
0532     if (out != null)
0533     {
0534       outputter.setFormat(Format.getPrettyFormat());
0535       outputter.output(doc, out);
0536       out.close();
0537     }
0538   }
0539 
0540   public Document convertDetectorToPandora(Detector detector)
0541   {
0542     // Setup XML output document.
0543     Document outputDoc = new Document();
0544     Element root = new Element("pandoraSetup");
0545     outputDoc.setRootElement(root);
0546     Element calorimeters = new Element("calorimeters");
0547     root.addContent(calorimeters);
0548 
0549     // Add basic detector data element.
0550     Element detectorTag = new Element("detector");
0551     detectorTag.setAttribute("name", detector.getDetectorName());
0552     root.addContent(detectorTag);
0553 
0554     // Setup CalorimeterCalibration conditions.
0555     ConditionsSet calorimeterCalibration = null;
0556     try
0557     {
0558       calorimeterCalibration = conditionsManager.getConditions("CalorimeterCalibration");
0559     }
0560     catch (Exception x)
0561     {
0562     }
0563     boolean haveCalCalib = (calorimeterCalibration == null) ? false : true;
0564 
0565     // Process the subdetectors.
0566     for (Subdetector subdetector : detector.getSubdetectors().values())
0567     {
0568       //System.out.println(subdetector.getName());
0569       // Only handle calorimeters that are planar.
0570       if (subdetector instanceof AbstractPolyhedraCalorimeter)
0571       {
0572         Element calorimeter = new Element("calorimeter");
0573         AbstractPolyhedraCalorimeter polycal = (AbstractPolyhedraCalorimeter) subdetector;
0574 
0575         // Look for specific calorimeter types in the compact
0576         // description.
0577         Calorimeter.CalorimeterType calType = polycal.getCalorimeterType();
0578         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))
0579         {
0580           // Set basic parameters in pandora calorimeter.
0581           calorimeter.setAttribute("type", Calorimeter.CalorimeterType.toString(calType));
0582           calorimeter.setAttribute("innerR", Double.toString(polycal.getInnerRadius()));
0583           calorimeter.setAttribute("innerZ", Double.toString(polycal.getInnerZ()));
0584           calorimeter.setAttribute("innerPhi", Double.toString(polycal.getSectionPhi()));
0585           calorimeter.setAttribute("innerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
0586           calorimeter.setAttribute("outerR", Double.toString(polycal.getOuterRadius()));
0587           calorimeter.setAttribute("outerZ", Double.toString(polycal.getOuterZ()));
0588           calorimeter.setAttribute("outerPhi", Double.toString(polycal.getSectionPhi()));
0589           calorimeter.setAttribute("outerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
0590           calorimeter.setAttribute("collection", subdetector.getReadout().getName());
0591 
0592           // Get the cell sizes from the segmentation.
0593           List<Double> cellSizes = getCellSizes(subdetector);
0594 
0595           // For endcaps, X is U, and Y is V.
0596           if (subdetector.isEndcap())
0597           {
0598             calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(0)));
0599             calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(1)));
0600           }
0601           // The UV mapping is flipped around for barrel.  X is V, and Y is U.
0602           else if (subdetector.isBarrel())
0603           {
0604             calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(1)));
0605             calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(0)));
0606           }
0607 
0608           // Create identifier description and add to subdet.
0609           calorimeter.addContent(makeIdentifierDescription(polycal));
0610 
0611           // Add the calorimeter.
0612           calorimeters.addContent(calorimeter);
0613 
0614           LayerStack layers = polycal.getLayering().getLayerStack();
0615 
0616           Element layersElem = new Element("layers");
0617           layersElem.setAttribute("nlayers", Integer.toString(layers.getNumberOfLayers()));
0618 
0619           calorimeter.addContent(layersElem);
0620 
0621           double layerD = 0.;
0622 
0623           if (polycal.isBarrel())
0624           {
0625             layerD = polycal.getInnerRadius();
0626           }
0627           else if (polycal.isEndcap())
0628           {
0629             layerD = polycal.getInnerZ();
0630           }
0631 
0632           CalorimeterConditions subdetectorCalorimeterConditions = null;
0633 
0634           if (haveCalCalib)
0635           {
0636             subdetectorCalorimeterConditions = new CalorimeterConditions((Calorimeter) subdetector, calorimeterCalibration);
0637           }
0638 
0639           // Set MIP energy from calibration.
0640           if (haveCalCalib)
0641           {
0642             calorimeter.setAttribute("mipEnergy", xfrac.format(subdetectorCalorimeterConditions.getMipEnergy()));
0643             calorimeter.setAttribute("mipSigma", xfrac.format(subdetectorCalorimeterConditions.getMipSigma()));
0644             calorimeter.setAttribute("mipCut", xfrac.format(subdetectorCalorimeterConditions.getMipCut()));
0645             calorimeter.setAttribute("timeCut", xfrac.format(subdetectorCalorimeterConditions.getTimeCut()));
0646           }
0647           // Set MIP energy from Bethe-Bloche calculation.
0648           // TODO Check accuracy of this algorithm.
0649           else
0650           {
0651             List<LayerSlice> sensors = subdetector.getLayering().getLayerStack().getLayer(0).getSensors();
0652             LayerSlice sensor = sensors.get(0);
0653             IMaterial sensorMaterial = MaterialStore.getInstance().get(sensor.getMaterial().getName());
0654 
0655             ParticleType particleType = ParticlePropertyManager.getParticlePropertyProvider().get(13);
0656 
0657             Hep3Vector p = new BasicHep3Vector(-6.8641, -7.2721, 1.2168e-7);
0658 
0659             double emip = BetheBlochCalculator.computeBetheBloch(sensorMaterial, p, particleType.getMass(), particleType.getCharge(), sensor.getThickness());
0660 
0661             // Set MIP Energy from Bethe Bloche.
0662             calorimeter.setAttribute("mipEnergy", xfrac.format(emip));
0663 
0664             // Set defaults for CalCalib parameters.
0665             calorimeter.setAttribute("mipSigma", "0");
0666             calorimeter.setAttribute("mipCut", "0");
0667             calorimeter.setAttribute("timeCut", xfrac.format(Double.MAX_VALUE));
0668           }
0669 
0670           double totalX0 = 0;
0671 
0672           for (int i = 0; i < layers.getNumberOfLayers(); i++)
0673           {
0674             //System.out.println("  layer " + i);
0675             Layer layer = layers.getLayer(i);
0676 
0677             Element layerElem = new Element("layer");
0678             layersElem.addContent(layerElem);
0679 
0680             // Set radiation and interaction lengths.
0681             double intLen = 0;
0682             double radLen = 0;
0683             for (int j = 0; j < layer.getNumberOfSlices(); j++)
0684             {
0685               LayerSlice slice = layer.getSlice(j);
0686               //System.out.println("    slice " + j + " " + slice.getMaterial().getName());
0687               double x0 = slice.getMaterial().getRadiationLength();
0688               //System.out.println("      x0_mat_D="+x0);
0689               //System.out.println("      x0_mat="+slice.getMaterial().getRadiationLength());
0690               radLen += slice.getThickness() / (x0*10);
0691               //System.out.println("      radLen="+radLen);
0692 
0693               double lambda = slice.getMaterial().getNuclearInteractionLength();
0694               intLen += slice.getThickness() / (lambda*10);
0695             }
0696             //System.out.println("    x0_lyr_tot=" + radLen);
0697 
0698             totalX0 += radLen;
0699 
0700             //System.out.println("    layer " + i + " " + radLen);
0701 
0702             layerElem.setAttribute("radLen", xlen.format(radLen));
0703             layerElem.setAttribute("intLen", xlen.format(intLen));
0704 
0705             // Set distance to IP.
0706             double layerD2 = layerD + layer.getThicknessToSensitiveMid();
0707             layerElem.setAttribute("distanceToIp", xthick.format(layerD2));
0708 
0709             // Set cell thickness.
0710             layerElem.setAttribute("cellThickness", xthick.format(layer.getThickness()));
0711 
0712             // Set EM and HAD sampling fractions from
0713             // CalorimeterCalibration conditions, if present.
0714             if (haveCalCalib)
0715             {
0716               SamplingLayerRange layerRange = subdetectorCalorimeterConditions.getSamplingLayerRange(i);
0717               if (calType == EM_BARREL || calType == EM_ENDCAP)
0718               {
0719                 layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getEMSampling()));
0720               }
0721               if (calType == HAD_BARREL || calType == HAD_ENDCAP)
0722               {
0723                 layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
0724               }
0725               if (calType == MUON_BARREL || calType == MUON_ENDCAP)
0726               {
0727                 layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
0728               }
0729               layerElem.setAttribute("emSamplingFraction", xfrac.format(layerRange.getEMSampling()));
0730               layerElem.setAttribute("hadSamplingFraction", xfrac.format(layerRange.getHADSampling()));
0731             }
0732             // Set from base SamplingFraction conditions. May throw
0733             // an exception if neither CalorimeterCalibration
0734             // or SamplingFractions conditions exists.
0735             else
0736             {
0737               double samplingFraction = SamplingFractionManager.defaultInstance().getSamplingFraction(subdetector, i);
0738               layerElem.setAttribute("emSamplingFraction", xfrac.format(samplingFraction));
0739               layerElem.setAttribute("hadSamplingFraction", xfrac.format(samplingFraction));
0740             }
0741 
0742             // Increment layer distance by thickness of layer.
0743             layerD += layer.getThickness();
0744           }
0745 
0746           //System.out.println("    X0 Sum = " + totalX0);
0747         }
0748 
0749         // Set digital flag.
0750         try
0751         {
0752           // Set digital attribute from conditions, if present.
0753           ConditionsSet conditions = conditionsManager.getConditions("SamplingFractions/" + subdetector.getName());
0754           boolean isDigital = conditions.getBoolean("digital");
0755           calorimeter.setAttribute("digital", String.valueOf(isDigital));
0756         }
0757         catch (Exception x)
0758         {
0759           calorimeter.setAttribute("digital", "false");
0760         }
0761       }
0762     }
0763 
0764     // TODO clean up the hard coded assumptions on coil geometry
0765     double coilRadLen = 0;
0766     double coilIntLen = 0;
0767     int coilLayers = 0;
0768     double coilInnerR = 0;
0769     double coilOuterR = 0;
0770     double bfield = 0;
0771     double coilMaxZ = 0;
0772     try
0773     {
0774       MultiLayerTracker c = (MultiLayerTracker) detector.getSubdetector("SolenoidCoilBarrel");
0775       if (c != null)
0776       {
0777         coilLayers = c.getNumberOfLayers();
0778         coilInnerR = c.getInnerR()[0];
0779         coilOuterR = c.getInnerR()[coilLayers-1] + c.getLayerThickness(coilLayers-1);
0780         for (int layern = 0; layern != c.getNumberOfLayers(); layern++)
0781         {
0782           for (LayerSlice slice : c.getLayer(layern).getSlices())
0783           {
0784             double x0 = slice.getMaterial().getRadiationLength();
0785             double sliceRadLen = slice.getThickness() / (x0*10);
0786             double lambda = slice.getMaterial().getNuclearInteractionLength();
0787             double sliceIntLen = slice.getThickness() / (lambda*10);
0788 
0789             coilRadLen += sliceRadLen;
0790             coilIntLen += sliceIntLen;
0791           }
0792         }
0793         //calculate average interaction/radiation length in coil material
0794         coilRadLen = coilRadLen/(coilOuterR-coilInnerR);
0795         coilIntLen = coilIntLen/(coilOuterR-coilInnerR);
0796       }
0797     }
0798     catch (ClassCastException e)
0799     {
0800       throw new RuntimeException(e);
0801     }
0802     try
0803     {
0804       Solenoid s = (Solenoid) detector.getFields().get("GlobalSolenoid");
0805       if (s != null)
0806       {
0807         bfield = s.getField(new BasicHep3Vector(0, 0, 0)).z();
0808         coilMaxZ = s.getZMax();
0809       }
0810     }
0811     catch (ClassCastException e)
0812     {
0813       throw new RuntimeException(e);
0814     }
0815 
0816     Element coil = new Element("coil");
0817     coil.setAttribute("radLen", xlen.format(coilRadLen));
0818     coil.setAttribute("intLen", xlen.format(coilIntLen));
0819     coil.setAttribute("innerR", Double.toString(coilInnerR));
0820     coil.setAttribute("outerR", Double.toString(coilOuterR));
0821     coil.setAttribute("z", Double.toString(coilMaxZ));
0822     coil.setAttribute("bfield", Double.toString(bfield));
0823     root.addContent(coil);
0824 
0825     Tube tube = (Tube) detector.getTrackingVolume().getLogicalVolume().getSolid();
0826     Element tracking = new Element("tracking");
0827     tracking.setAttribute("innerR", Double.toString(tube.getInnerRadius()));
0828     tracking.setAttribute("outerR", Double.toString(tube.getOuterRadius()));
0829     tracking.setAttribute("z", Double.toString(tube.getZHalfLength()));
0830     root.addContent(tracking);
0831 
0832     return outputDoc;
0833   }
0834 
0835   Element makeIdentifierDescription(Subdetector subdet)
0836   {
0837     IDDescriptor descr = subdet.getIDDecoder().getIDDescription();
0838     Element id = new Element("id");
0839     for (int i = 0, j = descr.fieldCount(); i < j; i++)
0840     {
0841       Element field = new Element("field");
0842       field.setAttribute("name", descr.fieldName(i));
0843       field.setAttribute("length", Integer.toString(descr.fieldLength(i)));
0844       field.setAttribute("start", Integer.toString(descr.fieldStart(i)));
0845       field.setAttribute("signed", Boolean.toString(descr.isSigned(i)));
0846 
0847       id.addContent(field);
0848     }
0849     return id;
0850   }
0851 
0852   private List<Double> getCellSizes(Subdetector subdetector)
0853   {
0854     List<Double> cellSizes = new ArrayList<Double>();
0855     BaseIDDecoder dec = (BaseIDDecoder) subdetector.getReadout().getIDDecoder();
0856     if (dec instanceof AbstractCartesianGrid)
0857     {
0858       AbstractCartesianGrid cgrid = (AbstractCartesianGrid) dec;
0859       if (cgrid.getGridSizeX() != 0)
0860       {
0861         cellSizes.add(cgrid.getGridSizeX());
0862       }
0863       if (cgrid.getGridSizeY() != 0)
0864       {
0865         cellSizes.add(cgrid.getGridSizeY());
0866       }
0867       if (cgrid.getGridSizeZ() != 0)
0868       {
0869         cellSizes.add(cgrid.getGridSizeZ());
0870       }
0871     }
0872     if (cellSizes.size() != 2)
0873       throw new RuntimeException("Only 2 cell dimensions are allowed.");
0874     return cellSizes;
0875   }
0876 
0877   public String getOutputFormat()
0878   {
0879     return "pandora";
0880   }
0881 
0882   public FileFilter getFileFilter()
0883   {
0884     return new PandoraFileFilter();
0885   }
0886 
0887   private static class PandoraFileFilter extends FileFilter
0888   {
0889 
0890     public boolean accept(java.io.File file)
0891     {
0892       return file.getName().endsWith(".xml");
0893     }
0894 
0895     public String getDescription()
0896     {
0897       return "Pandora Geometry file (*.xml)";
0898     }
0899   }
0900                                                         }
0901 #endif
0902 }
0903 DECLARE_APPLY(DD4hepGeometry2PANDORA,create_description)