From 86988c46bfc227f09d9c3530367e6f8ed42ec684 Mon Sep 17 00:00:00 2001
From: Markus Frank <markus.frank@cern.ch>
Date: Fri, 22 Feb 2013 13:43:14 +0000
Subject: [PATCH] Fix compiler bugs for slc5

---
 DDCore/CMakeLists.txt                        |   2 +-
 DDCore/include/DD4hep/Factories.h            |   6 +-
 DDCore/src/LCDDImp.cpp                       |   6 +-
 DDCore/src/plugins/LCDDConverter.cpp         |  17 +-
 DDCore/src/plugins/LCDDConverter.h           |   7 +-
 DDCore/src/plugins/PandoraConverter.cpp      | 896 +++++++++++++++++++
 DDExamples/UtilityApps/CMakeLists.txt        |   6 +-
 DDExamples/UtilityApps/src/converter.cpp     |  27 +-
 DDExamples/UtilityApps/src/plugin_runner.cpp |  71 ++
 9 files changed, 1012 insertions(+), 26 deletions(-)
 create mode 100644 DDCore/src/plugins/PandoraConverter.cpp
 create mode 100644 DDExamples/UtilityApps/src/plugin_runner.cpp

diff --git a/DDCore/CMakeLists.txt b/DDCore/CMakeLists.txt
index 28083aea4..c84d79c58 100644
--- a/DDCore/CMakeLists.txt
+++ b/DDCore/CMakeLists.txt
@@ -29,7 +29,7 @@ add_library(DD4hepCore SHARED ${sources})
 target_link_libraries(DD4hepCore ${ROOT_LIBRARIES} ${XERCESC_LIBRARIES} Geom Reflex ${libraries})
 
 add_library(DD4hepPlugins SHARED ${plugin_sources})
-target_link_libraries(DD4hepPlugins ${ROOT_LIBRARIES} DD4hepCore Geom Reflex ${libraries})
+target_link_libraries(DD4hepPlugins ${ROOT_LIBRARIES} ${XERCESC_LIBRARIES} DD4hepCore Geom Reflex ${libraries})
 #---Rootmap generation--------------------------------------------------------------
 dd4hep_generate_rootmap(DD4hepPlugins)
 
diff --git a/DDCore/include/DD4hep/Factories.h b/DDCore/include/DD4hep/Factories.h
index b71420ee2..aab050570 100644
--- a/DDCore/include/DD4hep/Factories.h
+++ b/DDCore/include/DD4hep/Factories.h
@@ -198,27 +198,31 @@ namespace {
 #define DECLARE_APPLY(name,func) \
   namespace DD4hep { namespace Geometry { namespace { struct name {}; }            \
   template <> long ApplyFactory<name>::create(DD4hep::Geometry::LCDD& l,int n,char** a) {return func(l,n,a);} }} \
+  using DD4hep::Geometry::name;\
   DECLARE_NAMED_APPLY_FACTORY(DD4hep::Geometry,name)
 
 #define DECLARE_TRANSLATION(name,func)                                                  \
   namespace DD4hep { namespace Geometry { namespace { struct name {}; }                 \
   template <> DD4hep::Geometry::Ref_t TranslationFactory<name>::create(DD4hep::Geometry::LCDD& l) {return func(l);} }} \
+  using DD4hep::Geometry::name;\
   DECLARE_NAMED_TRANSLATION_FACTORY(DD4hep::Geometry,name)
 
 #define DECLARE_XMLELEMENT(name,func) \
   namespace DD4hep { namespace Geometry { namespace { struct xml_element_##name {}; }   \
   template <> DD4hep::Geometry::Ref_t XMLElementFactory<DD4hep::Geometry::xml_element_##name>::create(DD4hep::Geometry::LCDD& l,DD4hep::XML::Handle_t e) {return func(l,e);} }}\
+  using DD4hep::Geometry::xml_element_##name;\
   PLUGINSVC_FACTORY_WITH_ID(xml_element_##name,std::string(#name),TNamed*(DD4hep::Geometry::LCDD*,DD4hep::XML::Handle_t*))
 
 #define DECLARE_XML_DOC_READER(name,func) \
   namespace DD4hep { namespace Geometry { namespace { struct xml_document_##name {}; }  \
   template <> long XMLDocumentReaderFactory<DD4hep::Geometry::xml_document_##name>::create(DD4hep::Geometry::LCDD& l,DD4hep::XML::Handle_t e) {return func(l,e);} }}\
+  using DD4hep::Geometry::xml_document_##name;\
   PLUGINSVC_FACTORY_WITH_ID(xml_document_##name,std::string(#name "_XML_reader"),long(DD4hep::Geometry::LCDD*,DD4hep::XML::Handle_t*))
 
 #define DECLARE_XML_PROCESSOR(name,func) \
   namespace DD4hep { namespace Geometry { struct det_element_##name {};	\
   template <> DD4hep::Geometry::Ref_t DetElementFactory< DD4hep::Geometry::det_element_##name >::create(DD4hep::Geometry::LCDD& l,DD4hep::XML::Handle_t e,DD4hep::Geometry::Ref_t h){return func(l,e,h);}}} \
-  typedef DD4hep::Geometry::det_element_##name det_element_##name;\
+  using DD4hep::Geometry::det_element_##name;\
   PLUGINSVC_FACTORY_WITH_ID(det_element_##name,std::string(#name),TNamed*(DD4hep::Geometry::LCDD*,DD4hep::XML::Handle_t*,DD4hep::Geometry::Ref_t*))
 
 #define DECLARE_SUBDETECTOR(name,func) DECLARE_XML_PROCESSOR(name,func)
diff --git a/DDCore/src/LCDDImp.cpp b/DDCore/src/LCDDImp.cpp
index 377fcdf45..6037358e4 100644
--- a/DDCore/src/LCDDImp.cpp
+++ b/DDCore/src/LCDDImp.cpp
@@ -252,11 +252,11 @@ void LCDDImp::fromXML(const string& xmlfile, LCDDBuildType build_type) {
   }
   catch(const exception& e)  {
     cout << "Exception:" << e.what() << endl;
-    throw runtime_error("Exception:"+string(e.what())+" while parsing "+xmlfile);
+    throw runtime_error("Exception:\""+string(e.what())+"\" while parsing "+xmlfile);
   }
   catch(const XML::XmlException& e)  {
     cout << "XML-DOM Exception:" << XML::_toString(e.msg) << endl;
-    throw runtime_error("XML-DOM Exception:"+XML::_toString(e.msg)+" while parsing "+xmlfile);
+    throw runtime_error("XML-DOM Exception:\""+XML::_toString(e.msg)+"\" while parsing "+xmlfile);
   } 
   catch(...)  {
     cout << "UNKNOWN Exception" << endl;
@@ -287,7 +287,7 @@ void LCDDImp::apply(const char* factory_type, int argc, char** argv)   {
   }
   catch(const exception& e)  {
     cout << "Exception:" << e.what() << endl;
-    throw runtime_error("Exception:"+string(e.what())+" while applying plugin:"+fac);
+    throw runtime_error("Exception:\""+string(e.what())+"\" while applying plugin:"+fac);
   }
   catch(...)  {
     cout << "UNKNOWN Exception" << endl;
diff --git a/DDCore/src/plugins/LCDDConverter.cpp b/DDCore/src/plugins/LCDDConverter.cpp
index 591d22554..81fd0549b 100644
--- a/DDCore/src/plugins/LCDDConverter.cpp
+++ b/DDCore/src/plugins/LCDDConverter.cpp
@@ -68,10 +68,15 @@ void LCDDConverter::GeometryInfo::check(const string& name, const TNamed* n,map<
 }
 
 /// Initializing Constructor
-LCDDConverter::LCDDConverter( LCDD& lcdd ) : m_lcdd(lcdd) {
+LCDDConverter::LCDDConverter( LCDD& lcdd ) : m_lcdd(lcdd), m_dataPtr(0) {
   m_checkOverlaps = true;
 }
 
+LCDDConverter::~LCDDConverter()   {
+  if ( m_dataPtr ) delete m_dataPtr;
+  m_dataPtr = 0;
+}
+
 /// Dump element in GDML format to output stream
 xml_h LCDDConverter::handleElement(const string& name, const TGeoElement* element) const {
   GeometryInfo& geo = data();
@@ -839,7 +844,7 @@ xml_doc_t LCDDConverter::createGDML(DetElement top) {
   collect(top,geo);
   m_checkOverlaps = false;
 
-  const char empty_lcdd[] =
+  const char empty_gdml[] =
     "<?xml version=\"1.0\" encoding=\"UTF-8\">\n"
     "<!--                                                               \n"
     "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
@@ -856,7 +861,7 @@ xml_doc_t LCDDConverter::createGDML(DetElement top) {
 
   XML::DocumentHandler docH;
   xml_elt_t elt(0);
-  geo.doc = docH.parse(empty_lcdd,sizeof(empty_lcdd));
+  geo.doc = docH.parse(empty_gdml,sizeof(empty_gdml));
   geo.doc_root = geo.doc.root();
   geo.doc_root.append(geo.doc_define    = xml_elt_t(geo.doc,_X(define)));
   geo.doc_root.append(geo.doc_materials = xml_elt_t(geo.doc,_X(materials)));
@@ -999,9 +1004,11 @@ xml_doc_t LCDDConverter::createLCDD(DetElement top) {
   return geo.doc;
 }
 
+/// Helper constructor
 LCDDConverter::GeometryInfo::GeometryInfo()
-  : doc(0), doc_root(0), doc_header(0), doc_idDict(0), doc_detectors(0), doc_limits(0), doc_regions(0),
-    doc_display(0), doc_gdml(0), doc_fields(0), doc_define(0), doc_materials(0),
+  : doc(0), doc_root(0), doc_header(0), doc_idDict(0), doc_detectors(0), 
+    doc_limits(0), doc_regions(0), doc_display(0), doc_gdml(0), 
+    doc_fields(0), doc_define(0), doc_materials(0),
     doc_solids(0), doc_structure(0),doc_setup(0)
 {
 }
diff --git a/DDCore/src/plugins/LCDDConverter.h b/DDCore/src/plugins/LCDDConverter.h
index 780069f89..1bd708e5a 100644
--- a/DDCore/src/plugins/LCDDConverter.h
+++ b/DDCore/src/plugins/LCDDConverter.h
@@ -93,8 +93,9 @@ namespace DD4hep {
 	  doc_display, doc_gdml, doc_fields, doc_define, doc_materials, doc_solids, doc_structure, doc_setup;
 	GeometryInfo();
       };
-
+      /// Reference to detector description
       LCDD&           m_lcdd;
+      /// Processing flag
       bool            m_checkOverlaps;
 
       typedef std::set<std::string> NameSet;
@@ -103,7 +104,7 @@ namespace DD4hep {
       GeometryInfo* m_dataPtr;
       GeometryInfo& data() const { return *m_dataPtr; }
 
-
+      /// Data integrity checker
       void checkVolumes(const std::string& name, const TGeoVolume* volume) const;
 
       
@@ -111,7 +112,7 @@ namespace DD4hep {
       LCDDConverter( LCDD& lcdd );
 
       /// Standard destructor
-      virtual ~LCDDConverter() {}
+      virtual ~LCDDConverter();
 
       /// Create geometry conversion in GDML format
       xml_doc_t createGDML(DetElement top);
diff --git a/DDCore/src/plugins/PandoraConverter.cpp b/DDCore/src/plugins/PandoraConverter.cpp
new file mode 100644
index 000000000..65d3a56ea
--- /dev/null
+++ b/DDCore/src/plugins/PandoraConverter.cpp
@@ -0,0 +1,896 @@
+//====================================================================
+//  AIDA Detector description implementation
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+// $Id:$
+#ifndef DD4HEP_GEOMETRY_PANDORACONVERTER_H
+#define DD4HEP_GEOMETRY_PANDORACONVERTER_H
+
+// Framework include files
+#include "DD4hep/LCDD.h"
+#include "DD4hep/GeoHandler.h"
+#include "DD4hep/DetFactoryHelper.h"
+
+/*
+ *   DD4hep namespace declaration
+ */
+namespace DD4hep {
+
+  /*
+   *   XML namespace declaration
+   */
+  namespace Geometry   {
+
+    /** @class PandoraConverter PandoraConverter.h XML/PandoraConverter.h
+     * 
+     * Geometry converter from DD4hep to Geant 4.
+     *
+     * @author  M.Frank
+     * @version 1.0
+     */
+    struct PandoraConverter : public GeoHandler  {
+    protected:
+      struct GeometryInfo : public GeoHandler::GeometryInfo {
+	xml_doc_t           doc;
+	xml_elt_t           doc_root, doc_calorimeters, doc_detector, doc_coil, doc_tracking;
+	/// Helper constructor
+	GeometryInfo();
+      };
+
+      /// Reference to detector description
+      LCDD&           m_lcdd;
+      /// Data pointer
+      GeometryInfo*   m_dataPtr;
+
+    public:
+      
+      /// Initializing Constructor
+      PandoraConverter( LCDD& lcdd );
+
+      /// Standard destructor
+      virtual ~PandoraConverter();
+
+      /// Create geometry conversion in Pandora XML format
+      xml_doc_t create(DetElement top);
+
+    };
+  }    // End namespace XML
+}      // End namespace DD4hep
+
+#endif // DD4HEP_GEOMETRY_PANDORACONVERTER_H
+
+//====================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+// $Id:$
+
+// Framework includes
+#include "DD4hep/LCDD.h"
+#include "DD4hep/GeoHandler.h"
+#include "DD4hep/DetFactoryHelper.h"
+#include "XML/DocumentHandler.h"
+
+// C/C++ include files
+#include <stdexcept>
+
+using namespace DD4hep::Geometry;
+using namespace DD4hep;
+using namespace std;
+
+/// Helper constructor
+PandoraConverter::GeometryInfo::GeometryInfo()
+  : doc(0), doc_root(0), doc_calorimeters(0), doc_detector(0), doc_coil(0), doc_tracking(0)
+{
+}
+
+/// Initializing Constructor
+PandoraConverter::PandoraConverter( LCDD& lcdd ) 
+ : m_lcdd(lcdd), m_dataPtr(0)
+{
+}
+
+/// Standard destructor
+PandoraConverter::~PandoraConverter() {
+  if ( m_dataPtr ) delete m_dataPtr;
+  m_dataPtr = 0;
+}
+
+/// Create geometry conversion in Pandora XML format
+xml_doc_t PandoraConverter::create(DetElement top) {
+  const char empty_xml[] =
+    "<?xml version=\"1.0\" encoding=\"UTF-8\">\n"
+    "<!--                                                               \n"
+    "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
+    "      ++++   Linear collider detector description in C++       ++++\n"
+    "      ++++   DD4hep Detector description generator.            ++++\n"
+    "      ++++                                                     ++++\n"
+    "      ++++                              M.Frank CERN/LHCb      ++++\n"
+    "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
+    "-->\n"
+    "<pandoraSetup>\n\0\0";
+  XML::DocumentHandler docH;
+  GeometryInfo& geo = *(m_dataPtr=new GeometryInfo);
+
+  xml_elt_t elt(0);
+  Header hdr = m_lcdd.header();
+  geo.doc = docH.parse(empty_xml,sizeof(empty_xml));
+  geo.doc_root = geo.doc.root();
+  geo.doc_root.append(geo.doc_calorimeters = xml_elt_t(geo.doc,_U(calorimeters)));
+  geo.doc_root.append(geo.doc_detector     = xml_elt_t(geo.doc,_U(detector)));
+  geo.doc_root.append(geo.doc_coil         = xml_elt_t(geo.doc,_U(coil)));
+  geo.doc_root.append(geo.doc_tracking     = xml_elt_t(geo.doc,_U(tracking)));
+  geo.doc_detector.setAttr(_U(name),hdr.name());
+  geo.doc_tracking.setAttr(_U(innerR),"");
+  geo.doc_tracking.setAttr(_U(outerR),"");
+  geo.doc_tracking.setAttr(_U(z),"");
+  
+  return geo.doc;
+}
+
+static long create_lcdd(LCDD& lcdd, int argc, char** argv)   {
+  throw runtime_error("The pandora xml conversion plugin is not yet implemented");
+  return 0;
+#if 0
+
+package org.lcsim.geometry.compact.converter.pandora;
+
+import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_BARREL;
+import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_ENDCAP;
+import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_BARREL;
+import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_ENDCAP;
+import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_BARREL;
+import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_ENDCAP;
+import hep.physics.particle.properties.ParticlePropertyManager;
+import hep.physics.particle.properties.ParticleType;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.swing.filechooser.FileFilter;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+import org.lcsim.conditions.ConditionsManager;
+import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
+import org.lcsim.conditions.ConditionsSet;
+import org.lcsim.detector.material.BetheBlochCalculator;
+import org.lcsim.detector.material.IMaterial;
+import org.lcsim.detector.material.MaterialStore;
+import org.lcsim.detector.solids.Tube;
+import org.lcsim.geometry.Calorimeter;
+import org.lcsim.geometry.Calorimeter.CalorimeterType;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.GeometryReader;
+import org.lcsim.geometry.compact.Subdetector;
+import org.lcsim.geometry.compact.converter.Converter;
+import org.lcsim.geometry.field.Solenoid;
+import org.lcsim.geometry.layer.Layer;
+import org.lcsim.geometry.layer.LayerSlice;
+import org.lcsim.geometry.layer.LayerStack;
+import org.lcsim.geometry.segmentation.AbstractCartesianGrid;
+import org.lcsim.geometry.subdetector.AbstractPolyhedraCalorimeter;
+import org.lcsim.geometry.subdetector.MultiLayerTracker;
+import org.lcsim.geometry.util.BaseIDDecoder;
+import org.lcsim.geometry.util.IDDescriptor;
+import org.lcsim.geometry.util.SamplingFractionManager;
+
+/**
+ * This class converts from a compact detector description into slicPandora's
+ * geometry input format.
+ * 
+ * @author Jeremy McCormick <jeremym@slac.stanford.edu>
+ * @version $Id: Main.java,v 1.33 2011/03/17 22:06:36 jeremy Exp $
+ */
+public class Main implements Converter
+{
+    private final static boolean DEBUG = false;
+    
+    // ConditionsManager instance.
+    private ConditionsManager conditionsManager = ConditionsManager.defaultInstance();
+    
+    // Numerical formatting.
+    static final DecimalFormat xlen = new DecimalFormat("#.########");
+    static final DecimalFormat xfrac = new DecimalFormat("#.########");
+    static final DecimalFormat xthick = new DecimalFormat("#.######");
+
+    /**
+     * A range of layers with associated EM and HAD sampling fractions.
+     * 
+     * @author Jeremy McCormick <jeremym@slac.stanford.edu>
+     */
+    static class SamplingLayerRange
+    {
+        int lowerLayer;
+        int upperLayer;
+        double em;
+        double had;
+
+        SamplingLayerRange(int lowerLayer, int upperLayer, double em, double had)
+        {
+            this.lowerLayer = lowerLayer;
+            this.upperLayer = upperLayer;
+            this.em = em;
+            this.had = had;
+        }
+
+        public boolean inRange(int layerNumber)
+        {
+            return layerNumber >= lowerLayer && layerNumber <= upperLayer;
+        }
+
+        public int getLowerLayer()
+        {
+            return lowerLayer;
+        }
+
+        public int getUpperLayer()
+        {
+            return upperLayer;
+        }
+
+        public double getEMSampling()
+        {
+            return em;
+        }
+
+        public double getHADSampling()
+        {
+            return had;
+        }
+    }
+
+    /**
+     * A list of SamplingLayerRange objects to represent the sampling for a
+     * subdetector.
+     * 
+     * @author Jeremy McCormick <jeremym@slac.stanford.edu>
+     * 
+     */
+    static class SamplingLayers extends ArrayList<SamplingLayerRange>
+    {
+        public SamplingLayers()
+        {
+        }
+
+        public SamplingLayers(SamplingLayerRange range)
+        {
+            this.add(range);
+        }
+
+        public SamplingLayers(List<SamplingLayerRange> ranges)
+        {
+            this.addAll(ranges);
+        }
+
+        public SamplingLayerRange getSamplingLayerRange(int layern)
+        {
+            for (SamplingLayerRange range : this)
+		{
+		    if (range.inRange(layern))
+			return range;
+		}
+            return null;
+        }
+    }
+
+    /**
+     * Represents CalorimeterConditions for a single subdetector.
+     * 
+     * @author Jeremy McCormick <jeremym@slac.stanford.edu>
+     */
+    private static class CalorimeterConditions
+    {
+        SamplingLayers samplingLayers;
+        String name;
+        double mipEnergy;
+        double mipSigma;
+        double mipCut;
+        double timeCut;
+
+        public String toString()
+        {
+            StringBuffer buff = new StringBuffer();
+            buff.append(name + '\n');
+            for (SamplingLayerRange range : samplingLayers)
+		{
+		    buff.append("[" + range.getLowerLayer() + " - " + range.getUpperLayer() + "]" + '\n');
+		    buff.append("    em = " + range.getEMSampling() + '\n');
+		    buff.append("    had = " + range.getHADSampling() + '\n');
+		}
+
+            return buff.toString();
+        }
+
+        public SamplingLayers getSamplingLayers()
+        {
+            return samplingLayers;
+        }
+
+        /**
+         * Constructor that parses raw CalorimeterCalibration conditions for a
+         * single subdetector.
+         * 
+         * @param calorimeter
+         * @param conditions
+         */
+        protected CalorimeterConditions(Calorimeter calorimeter, ConditionsSet conditions)
+        {
+            //System.out.println("conditions: " + calorimeter.getName());
+            this.name = calorimeter.getName();
+
+            // Figure out which layering conditions to use based on the
+            // CalorimeterType.
+            String layeringName = null;
+            if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
+		{
+		    layeringName = "ECalLayering";
+		}
+            else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
+		{
+		    layeringName = "HCalLayering";
+		}
+            else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
+		{
+		    layeringName = "MuonLayering";
+		}
+            else
+		{
+		    throw new RuntimeException("Don't know how to handle CalorimeterConditions for " + calorimeter.getName() + ".");
+		}
+
+            String emName = null;
+            String hadName = null;
+            if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL)
+		{
+		    emName = "EMBarrel_SF";
+		    hadName = "HadBarrel_SF";
+		}
+            else if (calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
+		{
+		    emName = "EMEndcap_SF";
+		    hadName = "HadEndcap_SF";
+		}
+
+            if (emName == null || hadName == null)
+		{
+		    throw new RuntimeException("Sampling fractions not found for " + calorimeter.getName() + ".");
+		}
+
+            String emSampling = conditions.getString(emName);
+            String hadSampling = conditions.getString(hadName);
+            List<Double> emSamplingFractions = new ArrayList<Double>();
+            List<Double> hadSamplingFractions = new ArrayList<Double>();
+            StringTokenizer tok = new StringTokenizer(emSampling, ",");
+            while (tok.hasMoreTokens())
+		{
+		    Double emSamplingFraction = Double.valueOf(tok.nextToken().trim());
+		    emSamplingFractions.add(emSamplingFraction);
+		}
+            tok = new StringTokenizer(hadSampling, ",");
+            while (tok.hasMoreTokens())
+		{
+		    Double hadSamplingFraction = Double.valueOf(tok.nextToken().trim());
+		    hadSamplingFractions.add(hadSamplingFraction);
+		}
+
+            String layering = conditions.getString(layeringName);
+            tok = new StringTokenizer(layering, ",");
+            List<Integer> layers = new ArrayList<Integer>();
+            int maxLayer = calorimeter.getLayering().getLayerCount() - 1;
+            while (tok.hasMoreTokens())
+		{
+		    String nextToken = tok.nextToken().trim();
+		    int nextLayer = Integer.valueOf(nextToken);
+		    layers.add(nextLayer);
+		}
+
+            // FIXME Hack to get the correct starting index for the sampling
+            // fractions. Ideally, the sampling fractions should be separated by subdetector name.
+            int samplingIndex = 0;
+            if (calorimeter.getCalorimeterType() == HAD_BARREL || calorimeter.getCalorimeterType() == HAD_ENDCAP)
+		{
+		    samplingIndex = (new StringTokenizer(conditions.getString("ECalLayering"), ",").countTokens());
+		}
+            if (calorimeter.getCalorimeterType() == MUON_BARREL || calorimeter.getCalorimeterType() == MUON_ENDCAP)
+		{
+		    samplingIndex = (new StringTokenizer(conditions.getString("ECalLayering"), ",").countTokens());
+		    samplingIndex += (new StringTokenizer(conditions.getString("HCalLayering"), ",").countTokens());
+		}
+
+            // System.out.println("    samplingIndex: " + samplingIndex);
+
+            // Create the SamplingLayerRange list.
+            samplingLayers = new SamplingLayers();
+            for (int i = 0; i < layers.size(); i++)
+		{
+		    // Figure out the layer range.
+		    int lowerLayer = layers.get(i);
+		    int upperLayer = 0;
+		    if (i + 1 > layers.size() - 1)
+			upperLayer = maxLayer;
+		    else
+			upperLayer = layers.get(i + 1) - 1;
+
+		    // Create the sampling layer range.
+		    double emSamplingFraction = emSamplingFractions.get(samplingIndex);
+		    double hadSamplingFraction = hadSamplingFractions.get(samplingIndex);
+		    SamplingLayerRange samplingLayerRange = new SamplingLayerRange(lowerLayer, upperLayer, emSamplingFraction, hadSamplingFraction);
+		    // System.out.println("    " + lowerLayer + " - " + upperLayer +
+		    // " : " + emSamplingFraction + ", " + hadSamplingFraction);
+
+		    samplingLayers.add(samplingLayerRange);
+
+		    ++samplingIndex;
+		}
+
+            // MIP energy.
+            String mipCondition = null;
+            String mipSigmaCondition = null;
+            String mipCutCondition = null;
+            
+            // FIXME: Cleanup this ugliness.
+            if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
+		{
+		    mipCondition = "ECalMip_MPV";
+		    mipSigmaCondition = "ECalMip_sig";
+		    mipCutCondition = "ECalMip_Cut";
+		}
+            else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
+		{
+		    mipCondition = "HCalMip_MPV";
+		    mipSigmaCondition = "HCalMip_sig";
+		    mipCutCondition = "HCalMip_Cut";
+		}
+            else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
+		{
+		    mipCondition = "MuonMip_MPV";
+		    mipSigmaCondition = "MuonMip_sig";
+		    mipCutCondition = "MuonMip_Cut";
+		}
+            mipEnergy = conditions.getDouble(mipCondition);
+            mipSigma = conditions.getDouble(mipSigmaCondition);
+            mipCut = conditions.getDouble(mipCutCondition);
+            timeCut = conditions.getDouble("timeCut");
+
+            /*
+             * System.out.println("    mipEnergy: " + mipEnergy);
+             * System.out.println("    mipSigma: " + mipSigma);
+             * System.out.println("    mipCut: " + mipCut);
+             * System.out.println("    timeCut: " + timeCut);
+             */
+        }
+
+        public SamplingLayerRange getSamplingLayerRange(int layer)
+        {
+            for (SamplingLayerRange layers : this.samplingLayers)
+		{
+		    if (layers.inRange(layer))
+			return layers;
+		}
+            return null;
+        }
+
+        public double getMipEnergy()
+        {
+            return mipEnergy;
+        }
+
+        public double getMipSigma()
+        {
+            return mipSigma;
+        }
+
+        public double getMipCut()
+        {
+            return mipCut;
+        }
+
+        public double getTimeCut()
+        {
+            return timeCut;
+        }
+    }
+
+    public void convert(String inputFileName, InputStream in, OutputStream out) throws Exception
+    {
+        GeometryReader reader = new GeometryReader();
+        Detector det = reader.read(in);
+        String detectorName = det.getDetectorName();
+        try
+	    {
+		conditionsManager.setDetector(detectorName, 0);
+	    }
+        catch (ConditionsNotFoundException x)
+	    {
+		throw new RuntimeException("Failed to setup conditions system for detector: " + detectorName, x);
+	    }
+        Document doc = convertDetectorToPandora(det);
+        XMLOutputter outputter = new XMLOutputter();
+        if (out != null)
+	    {
+		outputter.setFormat(Format.getPrettyFormat());
+		outputter.output(doc, out);
+		out.close();
+	    }
+    }
+
+    public Document convertDetectorToPandora(Detector detector)
+    {
+        // Setup XML output document.
+        Document outputDoc = new Document();
+        Element root = new Element("pandoraSetup");
+        outputDoc.setRootElement(root);
+        Element calorimeters = new Element("calorimeters");
+        root.addContent(calorimeters);
+        
+        // Add basic detector data element.
+        Element detectorTag = new Element("detector");
+        detectorTag.setAttribute("name", detector.getDetectorName());
+        root.addContent(detectorTag);
+
+        // Setup CalorimeterCalibration conditions.
+        ConditionsSet calorimeterCalibration = null;
+        try
+	    {
+		calorimeterCalibration = conditionsManager.getConditions("CalorimeterCalibration");
+	    }
+        catch (Exception x)
+	    {
+	    }
+        boolean haveCalCalib = (calorimeterCalibration == null) ? false : true;
+
+        // Process the subdetectors.
+        for (Subdetector subdetector : detector.getSubdetectors().values())
+	    {
+		//System.out.println(subdetector.getName());
+		// Only handle calorimeters that are planar.
+		if (subdetector instanceof AbstractPolyhedraCalorimeter)
+		    {
+			Element calorimeter = new Element("calorimeter");
+			AbstractPolyhedraCalorimeter polycal = (AbstractPolyhedraCalorimeter) subdetector;
+
+			// Look for specific calorimeter types in the compact
+			// description.
+			Calorimeter.CalorimeterType calType = polycal.getCalorimeterType();
+			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))
+			    {
+				// Set basic parameters in pandora calorimeter.
+				calorimeter.setAttribute("type", Calorimeter.CalorimeterType.toString(calType));
+				calorimeter.setAttribute("innerR", Double.toString(polycal.getInnerRadius()));
+				calorimeter.setAttribute("innerZ", Double.toString(polycal.getInnerZ()));
+				calorimeter.setAttribute("innerPhi", Double.toString(polycal.getSectionPhi()));
+				calorimeter.setAttribute("innerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
+				calorimeter.setAttribute("outerR", Double.toString(polycal.getOuterRadius()));
+				calorimeter.setAttribute("outerZ", Double.toString(polycal.getOuterZ()));
+				calorimeter.setAttribute("outerPhi", Double.toString(polycal.getSectionPhi()));
+				calorimeter.setAttribute("outerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
+				calorimeter.setAttribute("collection", subdetector.getReadout().getName());
+
+				// Get the cell sizes from the segmentation.
+				List<Double> cellSizes = getCellSizes(subdetector);
+                    
+				// For endcaps, X is U, and Y is V.
+				if (subdetector.isEndcap())
+				    {
+					calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(0)));
+					calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(1)));
+				    }
+				// The UV mapping is flipped around for barrel.  X is V, and Y is U.
+				else if (subdetector.isBarrel())
+				    {
+					calorimeter.setAttribute("cellSizeU", Double.toString(cellSizes.get(1)));
+					calorimeter.setAttribute("cellSizeV", Double.toString(cellSizes.get(0)));
+				    }
+
+				// Create identifier description and add to subdet.
+				calorimeter.addContent(makeIdentifierDescription(polycal));
+
+				// Add the calorimeter.
+				calorimeters.addContent(calorimeter);
+
+				LayerStack layers = polycal.getLayering().getLayerStack();
+
+				Element layersElem = new Element("layers");
+				layersElem.setAttribute("nlayers", Integer.toString(layers.getNumberOfLayers()));
+
+				calorimeter.addContent(layersElem);
+
+				double layerD = 0.;
+
+				if (polycal.isBarrel())
+				    {
+					layerD = polycal.getInnerRadius();
+				    }
+				else if (polycal.isEndcap())
+				    {
+					layerD = polycal.getInnerZ();
+				    }
+
+				CalorimeterConditions subdetectorCalorimeterConditions = null;
+
+				if (haveCalCalib)
+				    {
+					subdetectorCalorimeterConditions = new CalorimeterConditions((Calorimeter) subdetector, calorimeterCalibration);
+				    }
+
+				// Set MIP energy from calibration.
+				if (haveCalCalib)
+				    {
+					calorimeter.setAttribute("mipEnergy", xfrac.format(subdetectorCalorimeterConditions.getMipEnergy()));
+					calorimeter.setAttribute("mipSigma", xfrac.format(subdetectorCalorimeterConditions.getMipSigma()));
+					calorimeter.setAttribute("mipCut", xfrac.format(subdetectorCalorimeterConditions.getMipCut()));
+					calorimeter.setAttribute("timeCut", xfrac.format(subdetectorCalorimeterConditions.getTimeCut()));
+				    } 
+				// Set MIP energy from Bethe-Bloche calculation.
+				// TODO Check accuracy of this algorithm.
+				else
+				    {
+					List<LayerSlice> sensors = subdetector.getLayering().getLayerStack().getLayer(0).getSensors();
+					LayerSlice sensor = sensors.get(0);
+					IMaterial sensorMaterial = MaterialStore.getInstance().get(sensor.getMaterial().getName());
+
+					ParticleType particleType = ParticlePropertyManager.getParticlePropertyProvider().get(13);
+
+					Hep3Vector p = new BasicHep3Vector(-6.8641, -7.2721, 1.2168e-7);
+
+					double emip = BetheBlochCalculator.computeBetheBloch(sensorMaterial, p, particleType.getMass(), particleType.getCharge(), sensor.getThickness());
+
+					// Set MIP Energy from Bethe Bloche.
+					calorimeter.setAttribute("mipEnergy", xfrac.format(emip));
+
+					// Set defaults for CalCalib parameters.
+					calorimeter.setAttribute("mipSigma", "0");
+					calorimeter.setAttribute("mipCut", "0");
+					calorimeter.setAttribute("timeCut", xfrac.format(Double.MAX_VALUE));
+				    }
+                    
+				double totalX0 = 0;
+
+				for (int i = 0; i < layers.getNumberOfLayers(); i++)
+				    {
+					//System.out.println("  layer " + i);
+					Layer layer = layers.getLayer(i);
+
+					Element layerElem = new Element("layer");
+					layersElem.addContent(layerElem);
+
+					// Set radiation and interaction lengths.
+					double intLen = 0;
+					double radLen = 0;
+					for (int j = 0; j < layer.getNumberOfSlices(); j++)
+					    {
+						LayerSlice slice = layer.getSlice(j);
+						//System.out.println("    slice " + j + " " + slice.getMaterial().getName());                            
+						double x0 = slice.getMaterial().getRadiationLength();
+						//System.out.println("      x0_mat_D="+x0);
+						//System.out.println("      x0_mat="+slice.getMaterial().getRadiationLength());
+						radLen += slice.getThickness() / (x0*10);
+						//System.out.println("      radLen="+radLen);
+                            
+						double lambda = slice.getMaterial().getNuclearInteractionLength();
+						intLen += slice.getThickness() / (lambda*10);
+					    }
+					//System.out.println("    x0_lyr_tot=" + radLen);
+                        
+                        
+					totalX0 += radLen;
+                        
+					//System.out.println("    layer " + i + " " + radLen);
+                        
+					layerElem.setAttribute("radLen", xlen.format(radLen));
+					layerElem.setAttribute("intLen", xlen.format(intLen));
+
+					// Set distance to IP.
+					double layerD2 = layerD + layer.getThicknessToSensitiveMid();
+					layerElem.setAttribute("distanceToIp", xthick.format(layerD2));
+
+					// Set cell thickness.
+					layerElem.setAttribute("cellThickness", xthick.format(layer.getThickness()));
+
+					// Set EM and HAD sampling fractions from
+					// CalorimeterCalibration conditions, if present.
+					if (haveCalCalib)
+					    {
+						SamplingLayerRange layerRange = subdetectorCalorimeterConditions.getSamplingLayerRange(i);
+						if (calType == EM_BARREL || calType == EM_ENDCAP)
+						    {
+							layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getEMSampling()));
+						    }
+						if (calType == HAD_BARREL || calType == HAD_ENDCAP)
+						    {
+							layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
+						    }
+						if (calType == MUON_BARREL || calType == MUON_ENDCAP)
+						    {
+							layerElem.setAttribute("samplingFraction", xfrac.format(layerRange.getHADSampling()));
+						    }
+						layerElem.setAttribute("emSamplingFraction", xfrac.format(layerRange.getEMSampling()));
+						layerElem.setAttribute("hadSamplingFraction", xfrac.format(layerRange.getHADSampling()));
+					    }
+					// Set from base SamplingFraction conditions. May throw
+					// an exception if neither CalorimeterCalibration
+					// or SamplingFractions conditions exists.
+					else
+					    {
+						double samplingFraction = SamplingFractionManager.defaultInstance().getSamplingFraction(subdetector, i);
+						layerElem.setAttribute("emSamplingFraction", xfrac.format(samplingFraction));
+						layerElem.setAttribute("hadSamplingFraction", xfrac.format(samplingFraction));
+					    }
+
+					// Increment layer distance by thickness of layer.
+					layerD += layer.getThickness();
+				    }
+                    
+				//System.out.println("    X0 Sum = " + totalX0);
+			    }
+
+			// Set digital flag.
+			try
+			    {
+				// Set digital attribute from conditions, if present.
+				ConditionsSet conditions = conditionsManager.getConditions("SamplingFractions/" + subdetector.getName());
+				boolean isDigital = conditions.getBoolean("digital");
+				calorimeter.setAttribute("digital", String.valueOf(isDigital));
+			    }
+			catch (Exception x)
+			    {
+				calorimeter.setAttribute("digital", "false");
+			    }                
+		    }                        
+	    }
+                     
+        // TODO clean up the hard coded assumptions on coil geometry
+        double coilRadLen = 0;
+        double coilIntLen = 0;
+        int coilLayers = 0;
+        double coilInnerR = 0;
+        double coilOuterR = 0;
+        double bfield = 0;
+        double coilMaxZ = 0;
+        try 
+	    {
+        	MultiLayerTracker c = (MultiLayerTracker) detector.getSubdetector("SolenoidCoilBarrel");
+        	if (c != null) 
+		    {
+        		coilLayers = c.getNumberOfLayers();
+        		coilInnerR = c.getInnerR()[0];
+        		coilOuterR = c.getInnerR()[coilLayers-1] + c.getLayerThickness(coilLayers-1);
+        		for (int layern = 0; layern != c.getNumberOfLayers(); layern++) 
+			    {
+				for (LayerSlice slice : c.getLayer(layern).getSlices())
+				    {
+					double x0 = slice.getMaterial().getRadiationLength();
+					double sliceRadLen = slice.getThickness() / (x0*10);                   
+					double lambda = slice.getMaterial().getNuclearInteractionLength();
+					double sliceIntLen = slice.getThickness() / (lambda*10);
+        		        
+					coilRadLen += sliceRadLen;
+					coilIntLen += sliceIntLen; 
+				    }
+			    }
+        		//calculate average interaction/radiation length in coil material
+        		coilRadLen = coilRadLen/(coilOuterR-coilInnerR);
+        		coilIntLen = coilIntLen/(coilOuterR-coilInnerR);
+		    }        
+	    } 
+        catch (ClassCastException e) 
+	    {        
+		throw new RuntimeException(e);
+	    }
+        try 
+	    {
+        	Solenoid s = (Solenoid) detector.getFields().get("GlobalSolenoid");
+        	if (s != null) 
+		    {
+        		bfield = s.getField(new BasicHep3Vector(0, 0, 0)).z();
+        		coilMaxZ = s.getZMax();
+		    }
+	    } 
+        catch (ClassCastException e) 
+	    {
+		throw new RuntimeException(e);
+	    }
+        
+        Element coil = new Element("coil");
+        coil.setAttribute("radLen", xlen.format(coilRadLen));
+        coil.setAttribute("intLen", xlen.format(coilIntLen));
+        coil.setAttribute("innerR", Double.toString(coilInnerR));
+        coil.setAttribute("outerR", Double.toString(coilOuterR));
+        coil.setAttribute("z", Double.toString(coilMaxZ));
+        coil.setAttribute("bfield", Double.toString(bfield));
+        root.addContent(coil);        
+
+        Tube tube = (Tube) detector.getTrackingVolume().getLogicalVolume().getSolid();
+        Element tracking = new Element("tracking");
+        tracking.setAttribute("innerR", Double.toString(tube.getInnerRadius()));
+        tracking.setAttribute("outerR", Double.toString(tube.getOuterRadius()));
+        tracking.setAttribute("z", Double.toString(tube.getZHalfLength()));
+        root.addContent(tracking);
+
+        return outputDoc;
+    }
+
+    Element makeIdentifierDescription(Subdetector subdet)
+    {
+        IDDescriptor descr = subdet.getIDDecoder().getIDDescription();
+        Element id = new Element("id");
+        for (int i = 0, j = descr.fieldCount(); i < j; i++)
+	    {
+		Element field = new Element("field");
+		field.setAttribute("name", descr.fieldName(i));
+		field.setAttribute("length", Integer.toString(descr.fieldLength(i)));
+		field.setAttribute("start", Integer.toString(descr.fieldStart(i)));
+		field.setAttribute("signed", Boolean.toString(descr.isSigned(i)));
+
+		id.addContent(field);
+	    }
+        return id;
+    }
+
+    private List<Double> getCellSizes(Subdetector subdetector)
+    {
+        List<Double> cellSizes = new ArrayList<Double>();
+        BaseIDDecoder dec = (BaseIDDecoder) subdetector.getReadout().getIDDecoder();
+        if (dec instanceof AbstractCartesianGrid)
+	    {
+		AbstractCartesianGrid cgrid = (AbstractCartesianGrid) dec;
+		if (cgrid.getGridSizeX() != 0)
+		    {
+			cellSizes.add(cgrid.getGridSizeX());
+		    }
+		if (cgrid.getGridSizeY() != 0)
+		    {
+			cellSizes.add(cgrid.getGridSizeY());
+		    }
+		if (cgrid.getGridSizeZ() != 0)
+		    {
+			cellSizes.add(cgrid.getGridSizeZ());
+		    }
+	    }
+        if (cellSizes.size() != 2)
+            throw new RuntimeException("Only 2 cell dimensions are allowed.");
+        return cellSizes;
+    }
+
+    public String getOutputFormat()
+    {
+        return "pandora";
+    }
+
+    public FileFilter getFileFilter()
+    {
+        return new PandoraFileFilter();
+    }
+
+    private static class PandoraFileFilter extends FileFilter
+    {
+
+        public boolean accept(java.io.File file)
+        {
+            return file.getName().endsWith(".xml");
+        }
+
+        public String getDescription()
+        {
+            return "Pandora Geometry file (*.xml)";
+        }
+    }
+}
+#endif
+}
+DECLARE_APPLY(DD4hepGeometry2PANDORA,create_lcdd);
diff --git a/DDExamples/UtilityApps/CMakeLists.txt b/DDExamples/UtilityApps/CMakeLists.txt
index 197e6710d..c93f580b2 100644
--- a/DDExamples/UtilityApps/CMakeLists.txt
+++ b/DDExamples/UtilityApps/CMakeLists.txt
@@ -3,8 +3,12 @@ cmake_minimum_required(VERSION 2.8.3 FATAL_ERROR)
 include_directories( ${CMAKE_SOURCE_DIR}/DDCore/include 
                      ${ROOT_INCLUDE_DIR})
 
+#-----------------------------------------------------------------------------------
 add_executable(geoDisplay src/display.cpp)
 target_link_libraries(geoDisplay DD4hepCore)
-
+#-----------------------------------------------------------------------------------
 add_executable(geoConverter src/converter.cpp)
 target_link_libraries(geoConverter DD4hepCore)
+#-----------------------------------------------------------------------------------
+add_executable(geoPluginRun src/plugin_runner.cpp)
+target_link_libraries(geoPluginRun DD4hepCore)
diff --git a/DDExamples/UtilityApps/src/converter.cpp b/DDExamples/UtilityApps/src/converter.cpp
index e8895491f..86fec7003 100644
--- a/DDExamples/UtilityApps/src/converter.cpp
+++ b/DDExamples/UtilityApps/src/converter.cpp
@@ -26,10 +26,11 @@ using namespace DD4hep::Geometry;
 namespace {
   void usage() {
     cout << "geoConverter -opt [-opt]                                                \n"
-      "        Action flags:               Usage is exclusive!                       \n"
+      "        Action flags:               Usage is exclusive, 1 required!           \n"
       "        -compact2lcdd               Convert compact xml geometry to lcdd.     \n"
-      "        -compact2gdml               Convert compact xml geometry to gdml.   \n\n"
-      "        -input <file>   [REQUIRED]  Specify input file.                       \n"
+      "        -compact2gdml               Convert compact xml geometry to gdml.     \n"
+      "        -compact2pandora            Convert compact xml to pandora xml      \n\n"
+      "        -input  <file>  [REQUIRED]  Specify input file.                       \n"
       "        -output <file>  [OPTIONAL]  Specify output file.                      \n"
       "                                    if no output file is specified, the output\n"
       "                                    device is stdout.                         \n"
@@ -42,14 +43,17 @@ namespace {
 int main(int argc,char** argv)  {
   bool compact2lcdd = false;
   bool compact2gdml = false;
+  bool compact2pand = false;
   int output = 0;
   vector<char*> geo_files;
   for(int i=1; i<argc;++i) {
     if ( argv[i][0]=='-' ) {
       if ( strncmp(argv[i],"-compact2lcdd",12)==0 )
 	compact2lcdd = true;
-      if ( strncmp(argv[i],"-compact2gdml",12)==0 )
+      else if ( strncmp(argv[i],"-compact2gdml",12)==0 )
 	compact2gdml = true;
+      else if ( strncmp(argv[i],"-compact2pandora",12)==0 )
+	compact2pand = true;
       else if ( strncmp(argv[i],"-input",2)==0 )
 	geo_files.push_back(argv[++i]);
       else if ( strncmp(argv[i],"-output",2)==0 )
@@ -61,24 +65,23 @@ int main(int argc,char** argv)  {
       usage();
     }
   }
-  if ( geo_files.empty() || (!compact2lcdd && !compact2gdml))
+  if ( geo_files.empty() || (!compact2lcdd && !compact2gdml && !compact2pand))
     usage();
 
   try {
-    pair<int, char**> args(0,0);
     LCDD& lcdd = LCDD::getInstance();  
-    // Load all compact files
+    // Load compact files
     lcdd.apply("DD4hepCompactLoader",int(geo_files.size()),&geo_files[0]);
-    if ( compact2lcdd ) {
+    if ( compact2lcdd )
       lcdd.apply("DD4hepGeometry2LCDD",output,&argv[output]);
-    }
-    else if ( compact2gdml ) {
+    else if ( compact2gdml )
       lcdd.apply("DD4hepGeometry2GDML",output,&argv[output]);
-    }    
+    else if ( compact2pand )
+      lcdd.apply("DD4hepGeometry2PANDORA",output,&argv[output]);
     return 0;
   }
   catch(const exception& e)  {
-    cout << "Exception:" << e.what() << endl;
+    cout << e.what() << endl;
   }
   catch(...)  {
     cout << "UNKNOWN Exception" << endl;
diff --git a/DDExamples/UtilityApps/src/plugin_runner.cpp b/DDExamples/UtilityApps/src/plugin_runner.cpp
new file mode 100644
index 000000000..6ee7d868f
--- /dev/null
+++ b/DDExamples/UtilityApps/src/plugin_runner.cpp
@@ -0,0 +1,71 @@
+// $Id:$
+//====================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------
+//
+//  Generic ROOT based geometry display program
+// 
+//  Author     : M.Frank
+//
+//====================================================================
+
+// Framework include files
+#include "DD4hep/LCDD.h"
+
+// C/C++ include files
+#include <iostream>
+#include <cstdlib>
+#include <vector>
+#include <cerrno>
+#include <string>
+
+using namespace std;
+using namespace DD4hep::Geometry;
+
+//______________________________________________________________________________
+namespace {
+  void usage() {
+    cout << "geoPlugin -opt [-opt]                                                   \n"
+      "        -plugin <name>  [REQUIRED]  Plugin to be executed and applied.        \n"
+      "        -input  <file>  [REQUIRED]  Specify input file.                       \n"
+	 << endl;
+    exit(EINVAL);
+  }
+}
+
+//______________________________________________________________________________
+int main(int argc,char** argv)  {
+  string plugin;
+  vector<char*> geo_files;
+  for(int i=1; i<argc;++i) {
+    if ( argv[i][0]=='-' ) {
+      if ( strncmp(argv[i],"-input",2)==0 )
+	geo_files.push_back(argv[++i]);
+      else if ( strncmp(argv[i],"-plugin",2)==0 )
+        plugin = argv[++i];
+      else
+	usage();
+    }
+    else {
+      usage();
+    }
+  }
+  if ( geo_files.empty() || plugin.empty() )
+    usage();
+
+  try {
+    LCDD& lcdd = LCDD::getInstance();  
+    // Load compact files
+    lcdd.apply("DD4hepCompactLoader",int(geo_files.size()),&geo_files[0]);
+    // Execute plugin
+    lcdd.apply(plugin.c_str(),0,0);
+    return 0;
+  }
+  catch(const exception& e)  {
+    cout << "Exception:" << e.what() << endl;
+  }
+  catch(...)  {
+    cout << "UNKNOWN Exception" << endl;
+  }
+  return EINVAL;
+}
-- 
GitLab