Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:23:02

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 
0014 // Framework include files
0015 #define DD4HEP_MUST_USE_DETECTORIMP_H
0016 #include <DD4hep/Detector.h>
0017 #include <DD4hep/DetectorImp.h>
0018 #include <DD4hep/Memory.h>
0019 #include <DD4hep/DD4hepUI.h>
0020 #include <DD4hep/Factories.h>
0021 #include <DD4hep/Printout.h>
0022 #include <DD4hep/DD4hepUnits.h>
0023 #include <DD4hep/DetectorTools.h>
0024 #include <DD4hep/PluginCreators.h>
0025 #include <DD4hep/VolumeProcessor.h>
0026 #include <DD4hep/DetectorProcessor.h>
0027 #include <DD4hep/DD4hepRootPersistency.h>
0028 #include <XML/DocumentHandler.h>
0029 #include <XML/XMLElements.h>
0030 #include <XML/XMLTags.h>
0031 
0032 // ROOT includes
0033 #include <TInterpreter.h>
0034 #include <TGeoElement.h>
0035 #include <TGeoManager.h>
0036 #include <TGeoVolume.h>
0037 #include <TSystem.h>
0038 #include <TClass.h>
0039 #include <TRint.h>
0040 #include <TGDMLMatrix.h>
0041 
0042 // C/C++ include files
0043 #include <cerrno>
0044 #include <cstdlib>
0045 #include <sstream>
0046 
0047 using namespace dd4hep;
0048 using namespace dd4hep::detail;
0049 
0050 namespace  {
0051 
0052   struct ProcessorArgs   {
0053     bool use = false;
0054     int  start = 0, end = 0, argc = 0, count=0;
0055     std::vector<char*> argv;
0056     ProcessorArgs(int ac, char** av)    {
0057       for(int i=0; i<ac; ++i)  {
0058         if ( 0 == ::strncmp(av[i],"-processor",6) )   {
0059           use = true;
0060           start = i;
0061         }
0062         if ( use )   {
0063           ++argc; ++count; end = i;
0064           if ( 0 == ::strncmp(av[i],"-end-processor",6) )  {
0065             argv.emplace_back(av[i]);
0066             return;
0067           }
0068           else if ( 0 == ::strncmp(av[i],"-end-plugin",4) )  { // End of current plugin
0069             argv.emplace_back((char*)"-end-processor");
0070             return;
0071           }
0072           else if ( 0 == ::strncmp(av[i],"-plugin",4) )  {     // Start of next plugin
0073             argv.emplace_back((char*)"-end-processor");
0074             return;
0075           }
0076           argv.emplace_back(av[i]);
0077         }
0078       }
0079     }
0080   };
0081 }
0082 
0083 /// Dummy plugin to be able to invoke the plugin runner and e.g. only test the geometry
0084 /**
0085  *  Factory: DD4hep_DummyPlugin
0086  *
0087  *  \author  M.Frank
0088  *  \version 1.0
0089  *  \date    01/04/2014
0090  */
0091 static long dummy_plugin(Detector& , int, char**) {
0092   return 1;
0093 }
0094 DECLARE_APPLY(DD4hep_DummyPlugin,dummy_plugin)
0095 
0096 /// Basic entry point to create/access the Detector instance
0097 /**
0098  *  Factory: Detector_constructor
0099  *
0100  *  \author  M.Frank
0101  *  \version 1.0
0102  *  \date    01/04/2014
0103  */
0104 static void* create_description_instance(const char* /* name */) {
0105   return &Detector::getInstance();
0106 }
0107 DECLARE_CONSTRUCTOR(Detector_constructor,create_description_instance)
0108 
0109 /// Basic entry point to display the currently loaded geometry using the ROOT OpenGL viewer
0110 /** Invoke the ROOT geometry display using the factory mechanism.
0111  *
0112  *  Factory: DD4hep_GeometryDisplay
0113  *
0114  *  \author  M.Frank
0115  *  \version 1.0
0116  *  \date    01/04/2014
0117  */
0118 static long display(Detector& description, int argc, char** argv) {
0119   TGeoManager& mgr = description.manager();
0120   int vislevel = 6, visopt = 1;
0121   std::string detector = "/world";
0122   const char* opt = "ogl";
0123   for( int i = 0; i < argc && argv[i]; ++i )  {
0124     if ( 0 == ::strncmp("-option",argv[i],4) )
0125       opt = argv[++i];
0126     else if ( 0 == ::strncmp("-level",argv[i],4) )
0127       vislevel = ::atol(argv[++i]);
0128     else if ( 0 == ::strncmp("-visopt",argv[i],4) )
0129       visopt = ::atol(argv[++i]);
0130     else if ( 0 == ::strncmp("-detector",argv[i],4) )
0131       detector = argv[++i];
0132     else  {
0133       std::cout <<
0134         "Usage: -plugin DD4hep_GeometryDisplay  -arg [-arg]                                \n\n"
0135         "     Invoke the ROOT geometry display using the factory mechanism.                \n\n"
0136         "     -detector <string> Top level DetElement path. Default: '/world'                \n"
0137         "     -option   <string> ROOT Draw option.    Default: 'ogl'                         \n"
0138         "     -level    <number> Visualization level  [TGeoManager::SetVisLevel]  Default: 4 \n"
0139         "     -visopt   <number> Visualization option [TGeoManager::SetVisOption] Default: 1\n"       
0140         "     -load              Only load the geometry. Do not invoke the display          \n"
0141         "     -help              Print this help output  \n"       
0142         "     Arguments given: " << arguments(argc,argv) << std::endl << std::flush;
0143       ::exit(EINVAL);
0144     }
0145   }
0146   mgr.SetVisLevel(vislevel);
0147   mgr.SetVisOption(visopt);
0148   TGeoVolume* vol = mgr.GetTopVolume();
0149   if ( detector != "/world" )   {
0150     DetElement elt = detail::tools::findElement(description,detector);
0151     if ( !elt.isValid() )  {
0152       except("DD4hep_GeometryDisplay","+++ Invalid DetElement path: %s",detector.c_str());
0153     }
0154     if ( !elt.placement().isValid() )   {
0155       except("DD4hep_GeometryDisplay","+++ Invalid DetElement placement: %s",detector.c_str());
0156     }
0157     vol = elt.placement().volume();
0158   }
0159   if ( vol )   {
0160     vol->Draw(opt);
0161     return 1;
0162   }
0163   return 0;
0164 }
0165 DECLARE_APPLY(DD4hep_GeometryDisplay,display)
0166 
0167 /// Basic entry point to execute a public function from a library
0168 /**
0169  *  Factory: DD4hep_Function
0170  *
0171  *  \author  M.Frank
0172  *  \version 1.0
0173  *  \date    01/04/2014
0174  */
0175 static long run_function(Detector&, int argc, char** argv) {
0176   std::string lib, func;
0177   std::vector<char*> args;
0178   for(int i = 0; i < argc && argv[i]; ++i)  {
0179     if ( 0 == ::strncmp("-library",argv[i],4) )
0180       lib = argv[++i];
0181     else if ( 0 == ::strncmp("-function",argv[i],4) )
0182       func = argv[++i];
0183     else
0184       args.emplace_back(argv[i]);
0185   }
0186   if ( lib.empty() || func.empty() )  {
0187     std::cout <<
0188       "Usage: -plugin DD4hep_Function -arg [-arg]                        \n\n"
0189       "       Execute a function without arguments inside a library.     \n\n"
0190       "     -library   <string>    Library to be loaded                    \n"
0191       "     -function  <string>    name of the entry point to be executed. \n"
0192       "\tArguments given: " << arguments(argc,argv) << std::endl << std::flush;
0193     ::exit(EINVAL);
0194   }
0195   Func_t f = gSystem->DynFindSymbol("*",func.c_str());
0196   int ret;
0197   if ( !f )  {
0198     ret = gSystem->Load(lib.c_str());
0199     if ( ret != 0 )  {
0200       except("DD4hep_Function","+++ Failed to load library: %s",lib.c_str());
0201     }
0202     f = gSystem->DynFindSymbol("*",func.c_str());
0203     if ( !f )  {
0204       except("DD4hep_Function","+++ Failed to find function %s in library: %s",
0205              func.c_str(),lib.c_str());
0206     }
0207   }
0208   typedef int (*call_t)(int, char**);
0209   call_t ff  = (call_t)f;
0210   ret = (*ff)(args.size(),&args[0]);
0211   return ret;
0212 }
0213 DECLARE_APPLY(DD4hep_Function,run_function)
0214 
0215 /// Basic entry point to start the ROOT interpreter.
0216 /**
0217  *  Factory: DD4hep_Rint
0218  *
0219  *  \author  M.Frank
0220  *  \version 1.0
0221  *  \date    01/04/2014
0222  */
0223 static long run_interpreter(Detector& /* description */, int argc, char** argv) {
0224   if ( 0 == gApplication )  {
0225     std::pair<int, char**> a(argc,argv);
0226     gApplication = new TRint("DD4hepRint", &a.first, a.second);
0227     printout(INFO,"DD4hepRint","++ Created ROOT interpreter instance for DD4hepUI.");
0228   }
0229   for(int i=0; i<argc; ++i)   {
0230     printout(INFO,"DD4hepRint","Excecute[%d]: %s", i, argv[i]);
0231     gInterpreter->ProcessLine(argv[i]);
0232   }
0233   if ( !gApplication->IsRunning() )  {
0234     gApplication->Run();
0235   }
0236   return 1;
0237 }
0238 DECLARE_APPLY(DD4hep_Rint,run_interpreter)
0239 
0240 /// Basic entry point to start the ROOT UI
0241 /**
0242  *  The UI will show up in the ROOT prompt and is accessible
0243  *  in the interpreter with the global variable 
0244  *  dd4hep::DD4hepUI* gdd4hepUI;
0245  *
0246  *  Factory: DD4hep_InteractiveUI
0247  *
0248  *  \author  M.Frank
0249  *  \version 1.0
0250  *  \date    01/04/2014
0251  */
0252 static long root_ui(Detector& description, int /* argc */, char** /* argv */) {
0253   char cmd[256];
0254   std::snprintf(cmd, sizeof(cmd),
0255                 "dd4hep::detail::DD4hepUI* gDD4hepUI = new "
0256                 "dd4hep::detail::DD4hepUI(*(dd4hep::Detector*)%p);",
0257                 (void*)&description);
0258   gInterpreter->ProcessLine(cmd);
0259   printout(ALWAYS,"DD4hepUI",
0260            "Use the ROOT interpreter variable gDD4hepUI "
0261            "to interact with the detector description.");
0262   return 1;
0263 }
0264 DECLARE_APPLY(DD4hep_InteractiveUI,root_ui)
0265 
0266 /// Basic entry point to dump all known GDML tables
0267 /**
0268  *
0269  *  Factory: DD4hep_Dump_GDMLTables
0270  *
0271  *  \author  M.Frank
0272  *  \version 1.0
0273  *  \date    01/04/2014
0274  */
0275 static long root_dump_gdml_tables(Detector& description, int /* argc */, char** /* argv */) {
0276   size_t num_tables = 0;
0277   size_t num_elements = 0;
0278   const TObjArray* c = description.manager().GetListOfGDMLMatrices();
0279   TObjArrayIter arr(c);
0280   printout(INFO,"Dump_GDMLTables","+++ Dumping known GDML tables from TGeoManager.");
0281   for(TObject* i = arr.Next(); i; i=arr.Next())   {
0282     TGDMLMatrix* gdmlMat = (TGDMLMatrix*)i;
0283     num_elements += (gdmlMat->GetRows()*gdmlMat->GetCols());
0284     ++num_tables;
0285     gdmlMat->Print();
0286   }
0287   printout(INFO,"Dump_GDMLTables",
0288            "+++ Successfully dumped %ld GDML tables with %ld elements.",
0289            num_tables, num_elements);
0290   return 1;
0291 }
0292 DECLARE_APPLY(DD4hep_Dump_GDMLTables,root_dump_gdml_tables)
0293 
0294 /// Basic entry point to dump all known optical surfaces
0295 /**
0296  *
0297  *  Factory: DD4hep_Dump_OpticalSurfaces
0298  *
0299  *  \author  M.Frank
0300  *  \version 1.0
0301  *  \date    01/04/2014
0302  */
0303 static long root_dump_optical_surfaces(Detector& description, int /* argc */, char** /* argv */) {
0304   size_t num_surfaces = 0;
0305   printout(ALWAYS,"","");
0306   const TObjArray* c = description.manager().GetListOfOpticalSurfaces();
0307   TObjArrayIter arr(c);
0308   printout(ALWAYS,"Dump_OpticalSurfaces","+++ Dumping known Optical Surfaces from TGeoManager.");
0309   for(TObject* i = arr.Next(); i; i=arr.Next())   {
0310     TGeoOpticalSurface* optSurt = (TGeoOpticalSurface*)i;
0311     ++num_surfaces;
0312     optSurt->Print();
0313   }
0314   printout(ALWAYS,"Dump_OpticalSurfaces",
0315            "+++ Successfully dumped %ld Optical surfaces.",num_surfaces);
0316   return 1;
0317 }
0318 DECLARE_APPLY(DD4hep_Dump_OpticalSurfaces,root_dump_optical_surfaces)
0319 
0320 /// Basic entry point to dump all known skin surfaces
0321 /**
0322  *
0323  *  Factory: DD4hep_Dump_SkinSurfaces
0324  *
0325  *  \author  M.Frank
0326  *  \version 1.0
0327  *  \date    01/04/2014
0328  */
0329 static long root_dump_skin_surfaces(Detector& description, int /* argc */, char** /* argv */) {
0330   size_t num_surfaces = 0;
0331   printout(ALWAYS,"","");
0332   const TObjArray* c = description.manager().GetListOfSkinSurfaces();
0333   TObjArrayIter arr(c);
0334   printout(ALWAYS,"Dump_SkinSurfaces","+++ Dumping known Skin Surfaces from TGeoManager.");
0335   for(TObject* i = arr.Next(); i; i=arr.Next())   {
0336     TGeoSkinSurface* skinSurf = (TGeoSkinSurface*)i;
0337     ++num_surfaces;
0338     skinSurf->Print();
0339   }
0340   printout(ALWAYS,"Dump_SkinSurfaces",
0341            "+++ Successfully dumped %ld Skin surfaces.",num_surfaces);
0342   return 1;
0343 }
0344 DECLARE_APPLY(DD4hep_Dump_SkinSurfaces,root_dump_skin_surfaces)
0345 
0346 /// Basic entry point to dump all known border surfaces
0347 /**
0348  *
0349  *  Factory: DD4hep_Dump_BorderSurfaces
0350  *
0351  *  \author  M.Frank
0352  *  \version 1.0
0353  *  \date    01/04/2014
0354  */
0355 static long root_dump_border_surfaces(Detector& description, int /* argc */, char** /* argv */) {
0356   size_t num_surfaces = 0;
0357   printout(ALWAYS,"","");
0358   const TObjArray* c = description.manager().GetListOfBorderSurfaces();
0359   TObjArrayIter arr(c);
0360   printout(ALWAYS,"Dump_BorderSurfaces","+++ Dumping known Border Surfaces from TGeoManager.");
0361   for(TObject* i = arr.Next(); i; i=arr.Next())   {
0362     TGeoBorderSurface* bordSurt = (TGeoBorderSurface*)i;
0363     ++num_surfaces;
0364     bordSurt->Print();
0365   }
0366   printout(ALWAYS,"Dump_BorderSurfaces",
0367            "+++ Successfully dumped %ld Border surfaces.",num_surfaces);
0368   return 1;
0369 }
0370 DECLARE_APPLY(DD4hep_Dump_BorderSurfaces,root_dump_border_surfaces)
0371 
0372 /// Basic entry point to dump the ROOT TGeoElementTable object
0373 /**
0374  *  Dump the elment table to stdout or file.
0375  *
0376  *  Factory: DD4hep_ElementTable -format xml/text(default) -output <file-name>
0377  *
0378  *  \author  M.Frank
0379  *  \version 1.0
0380  *  \date    01/04/2014
0381  */
0382 static long root_elements(Detector& description, int argc, char** argv) {
0383   using elt_h = xml::Element;
0384 
0385   /// Generic printer object. Calls the print method of TObject
0386   /**
0387    *  \author  M.Frank
0388    *  \version 1.0
0389    *  \date    01/04/2014
0390    */
0391   struct ElementPrint {
0392     /// Default constructor
0393     ElementPrint() = default;
0394     /// Default destructor
0395     virtual ~ElementPrint() = default;
0396     /// Element writer
0397     virtual void operator()(TGeoElement* elt)  {   elt->Print();    }
0398     /// Isotope writer
0399     virtual void operator()(TGeoIsotope* iso)  {   iso->Print();    }
0400   };
0401 
0402   /// XML printer to produce XML output
0403   /**
0404    *  \author  M.Frank
0405    *  \version 1.0
0406    *  \date    01/04/2014
0407    */
0408   struct ElementPrintXML : public ElementPrint  {
0409     /// Root XML element
0410     elt_h root;
0411     /// Initializing constructor
0412     ElementPrintXML(elt_h r) : root(r) {}
0413     /// Default destructor
0414     virtual ~ElementPrintXML() {}
0415     /// Element writer
0416     virtual void operator()(TGeoElement* element)  {
0417       elt_h elt = root.addChild(_U(element));
0418       elt.setAttr(_U(Z),element->Z());
0419       elt.setAttr(_U(N),element->N());
0420       elt.setAttr(_U(formula),element->GetName());
0421       elt.setAttr(_U(name),element->GetName());
0422       elt_h atom = elt.addChild(_U(atom));
0423       atom.setAttr(_U(type),"A");
0424       atom.setAttr(_U(unit),"g/mole");
0425       atom.setAttr(_U(value),element->A());
0426     }
0427     /// Isotope writer
0428     virtual void operator()(TGeoIsotope* isotope)  {
0429       elt_h iso = root.addChild(_U(isotope));
0430       iso.setAttr(_U(Z),isotope->GetZ());
0431       iso.setAttr(_U(N),isotope->GetN());
0432       iso.setAttr(_U(formula),isotope->GetName());
0433       iso.setAttr(_U(name),isotope->GetName());
0434       elt_h atom = iso.addChild(_U(atom));
0435       atom.setAttr(_U(type),"A");
0436       atom.setAttr(_U(unit),"g/mole");
0437       atom.setAttr(_U(value),isotope->GetA());
0438     }
0439   };
0440 
0441   std::string type = "text", output = "";
0442   for(int i=0; i<argc; ++i)  {
0443     if ( argv[i][0] == '-' )  {
0444       char c = ::tolower(argv[i][1]);
0445       if ( c == 't' && i+1<argc ) type = argv[++i];
0446       else if ( c == 'o' && i+1<argc ) output = argv[++i];
0447       else  {
0448         ::printf("DD4hep_ElementTable -opt [-opt]                        \n"
0449                  "  -type   <string>    Output format: text or xml       \n"
0450                  "  -output <file-name> Output file specifier (xml only) \n"
0451                  "\n");
0452         exit(EINVAL);
0453       }
0454     }
0455   }
0456 
0457   xml::Document        doc(0);
0458   xml::DocumentHandler docH;
0459   xml::Element         element(0);
0460   if ( type == "xml" )  {
0461     const char comment[] = "\n"
0462       "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
0463       "      ++++   Generic detector description in C++               ++++\n"
0464       "      ++++   dd4hep Detector description generator.            ++++\n"
0465       "      ++++                                                     ++++\n"
0466       "      ++++   Parser:"
0467       XML_IMPLEMENTATION_TYPE
0468       "                ++++\n"
0469       "      ++++                                                     ++++\n"
0470       "      ++++   Table of elements as defined in ROOT: " ROOT_RELEASE  "     ++++\n"
0471       "      ++++                                                     ++++\n"
0472       "      ++++                              M.Frank CERN/LHCb      ++++\n"
0473       "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n  ";
0474     doc = docH.create("materials", comment);
0475     element = doc.root();
0476   }
0477   dd4hep_ptr<ElementPrint> printer(element
0478                                    ? new ElementPrintXML(element)
0479                                    : new ElementPrint());
0480   TGeoElementTable* table = description.manager().GetElementTable();
0481   for(Int_t i=0, n=table->GetNelements(); i < n; ++i)
0482     (*printer)(table->GetElement(i));
0483 
0484   for(Int_t i=0, n=table->GetNelements(); i < n; ++i)  {
0485     TGeoElement* elt = table->GetElement(i);
0486     Int_t niso = elt->GetNisotopes();
0487     if ( niso > 0 )  {
0488       for(Int_t j=0; j < niso; ++j)
0489         (*printer)(elt->GetIsotope(j));
0490     }
0491   }
0492   if ( element )   {
0493     xml::DocumentHandler dH;
0494     dH.output(doc, output);
0495   }
0496   return 1;
0497 }
0498 DECLARE_APPLY(DD4hep_ElementTable,root_elements)
0499 
0500 /// Basic entry point to dump the ROOT TGeoElementTable object
0501 /**
0502  *  Dump the elment table to stdout or file.
0503  *
0504  *  Factory: DD4hepElementTable -format xml/text(default) -output <file-name>
0505  *
0506  *  \author  M.Frank
0507  *  \version 1.0
0508  *  \date    01/04/2014
0509  */
0510 static long root_materials(Detector& description, int argc, char** argv) {
0511 
0512   using elt_h = xml::Element;
0513 
0514   /// Material printer object
0515   /**
0516    *  \author  M.Frank
0517    *  \version 1.0
0518    *  \date    01/04/2014
0519    */
0520   struct MaterialPrint {
0521   public:
0522     /// Reference to the detector description
0523     Detector& description;
0524 
0525   public:
0526     /// Initializing constructor
0527     MaterialPrint(Detector& desc) : description(desc) {}
0528     /// Default destructor
0529     virtual ~MaterialPrint() = default;
0530     /// Print single material
0531     virtual elt_h print(TGeoMaterial* mat)  {
0532       const char* st = "Undefined";
0533       switch( mat->GetState() )   {
0534       case TGeoMaterial::kMatStateSolid:     st = "solid";     break;
0535       case TGeoMaterial::kMatStateLiquid:    st = "liquid";    break;
0536       case TGeoMaterial::kMatStateGas:       st = "gas";       break;
0537       case TGeoMaterial::kMatStateUndefined:
0538       default:                               st = "Undefined"; break;
0539       }
0540       ::printf("%-32s %-8s\n", mat->GetName(), mat->IsMixture() ? "Mixture" : "Material");
0541       ::printf("         Aeff=%7.3f Zeff=%7.4f rho=%8.3f [g/mole] radlen=%8.3g [cm] intlen=%8.3g [cm] index=%3d\n",
0542                mat->GetA(), mat->GetZ(), mat->GetDensity(),
0543                mat->GetRadLen(), mat->GetIntLen(), mat->GetIndex());
0544       ::printf("         Temp=%.3g [Kelvin] Pressure=%.5g [hPa] state=%s\n",
0545                mat->GetTemperature(), mat->GetPressure()/dd4hep::pascal/100.0, st);
0546       return elt_h(0);
0547     }
0548     /// Print element entry
0549     virtual void print(elt_h, TGeoElement* elt, double frac)   {
0550       ::printf("  %-6s Fraction: %7.3f Z=%3d A=%6.2f N=%3d Neff=%6.2f\n",
0551                elt->GetName(), frac, elt->Z(), elt->A(), elt->N(), elt->Neff());
0552     }
0553     /// Print material property
0554     virtual void printProperty(elt_h, TNamed* prop, TGDMLMatrix* matrix)   {
0555       if ( matrix )
0556         ::printf("  Property: %-20s [%ld x %ld] --> %s\n",
0557                  prop->GetName(), long(matrix->GetRows()), long(matrix->GetCols()), prop->GetTitle());
0558       else
0559         ::printf("  Property: %-20s [ERROR: NO TABLE!] --> %s\n",
0560                  prop->GetName(), prop->GetTitle());
0561     }
0562     virtual void operator()(TGeoMaterial* mat)  {
0563       Double_t* mix = mat->IsMixture() ? ((TGeoMixture*)mat)->GetWmixt() : 0;
0564       elt_h     mh  = print(mat);
0565       for( int n=mat->GetNelements(), i=0; i<n; ++i )   {
0566         TGeoElement* elt = mat->GetElement(i);
0567         print(mh, elt, mix ? mix[i] : 1);
0568       }
0569       TListIter mat_iter(&mat->GetProperties());
0570       for( TObject* i = mat_iter.Next(); i; i=mat_iter.Next() )   {
0571         printProperty(mh, (TNamed*)i, description.manager().GetGDMLMatrix(i->GetTitle()));
0572       }
0573     }
0574   };
0575   /// XML printer to produce XML output
0576   /**
0577    *  \author  M.Frank
0578    *  \version 1.0
0579    *  \date    01/04/2014
0580    */
0581   struct MaterialPrintXML : public MaterialPrint  {
0582     elt_h root;
0583     MaterialPrintXML(elt_h elt, Detector& desc) : MaterialPrint(desc), root(elt) {}
0584     virtual ~MaterialPrintXML() {}
0585     virtual elt_h print(TGeoMaterial* mat)  {
0586       elt_h elt = root.addChild(_U(material));
0587       elt.setAttr(_U(name),mat->GetName());
0588       if ( ::strlen(mat->GetTitle())>0 )   {
0589         elt.setAttr(_U(formula),mat->GetTitle());
0590       }
0591       else if ( mat->GetNelements() == 1 )   {
0592         elt.setAttr(_U(formula),mat->GetElement(0)->GetName());
0593 #if 0
0594         // We do not need this. It shall be computed by TGeo using the Geant4 formula.
0595         elt_h RL = elt.addChild(_U(RL));
0596         RL.setAttr(_U(type),  "X0");
0597         RL.setAttr(_U(value), mat->GetRadLen());
0598         RL.setAttr(_U(unit),  "cm");
0599         elt_h NIL = elt.addChild(_U(NIL));
0600         NIL.setAttr(_U(type),  "lambda");
0601         NIL.setAttr(_U(value), mat->GetIntLen());
0602         NIL.setAttr(_U(unit),  "cm");
0603 #endif
0604       }
0605       elt_h D = elt.addChild(_U(D));
0606       D.setAttr(_U(type),  "density");
0607       D.setAttr(_U(value), mat->GetDensity());
0608       D.setAttr(_U(unit),  "g/cm3");
0609       if ( mat->GetTemperature() != description.stdConditions().temperature )  {
0610         elt_h T = elt.addChild(_U(T));
0611         T.setAttr(_U(type), "temperature");
0612         T.setAttr(_U(value), mat->GetTemperature());
0613         T.setAttr(_U(unit), "kelvin");
0614       }
0615       if ( mat->GetPressure() != description.stdConditions().pressure )  {
0616         elt_h P = elt.addChild(_U(P));
0617         P.setAttr(_U(type),  "pressure");
0618         P.setAttr(_U(value), mat->GetPressure());
0619         P.setAttr(_U(unit),  "pascal");
0620       }
0621       return elt;
0622     }
0623     virtual void print(elt_h mat, TGeoElement* element, double frac)  {
0624       elt_h elt = mat.addChild(_U(composite));
0625       elt.setAttr(_U(n),frac);
0626       elt.setAttr(_U(ref),element->GetName());
0627     }
0628     virtual void printProperty(elt_h mat, TNamed* prop, TGDMLMatrix* /* matrix */)   {
0629       elt_h elt = mat.addChild(_U(property));
0630       elt.setAttr(_U(name),prop->GetName());
0631       elt.setAttr(_U(ref), prop->GetTitle());
0632     }
0633   };
0634 
0635   std::string type = "text", output = "", name = "";
0636   for(int i=0; i<argc; ++i)  {
0637     if ( argv[i][0] == '-' )  {
0638       char c = ::tolower(argv[i][1]);
0639       if ( c == 't' && i+1<argc ) type = argv[++i];
0640       else if ( c == 'n' && i+1<argc ) name   = argv[++i];
0641       else if ( c == 'o' && i+1<argc ) output = argv[++i];
0642       else  {
0643         ::printf("DD4hep_MaterialTable -opt [-opt]                       \n"
0644                  "  -type   <string>    Output format: text or xml       \n"
0645                  "  -output <file-name> Output file specifier (xml only) \n"
0646                  "\n");
0647         exit(EINVAL);
0648       }
0649     }
0650   }
0651 
0652   xml::Document        doc(0);
0653   xml::DocumentHandler docH;
0654   xml::Element         element(0);
0655   if ( type == "xml" )  {
0656     const char comment[] = "\n"
0657       "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
0658       "      ++++   Generic detector description in C++               ++++\n"
0659       "      ++++   dd4hep Detector description generator.            ++++\n"
0660       "      ++++                                                     ++++\n"
0661       "      ++++   Parser:"
0662       XML_IMPLEMENTATION_TYPE
0663       "                ++++\n"
0664       "      ++++                                                     ++++\n"
0665       "      ++++   Table of elements as defined in ROOT: " ROOT_RELEASE "     ++++\n"
0666       "      ++++                                                     ++++\n"
0667       "      ++++                              M.Frank CERN/LHCb      ++++\n"
0668       "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n  ";
0669     doc = docH.create("materials", comment);
0670     element = doc.root();
0671   }
0672   dd4hep_ptr<MaterialPrint> printer(element
0673                                     ? new MaterialPrintXML(element, description)
0674                                     : new MaterialPrint(description));
0675   TObject* obj = 0;
0676   TList*   mats = description.manager().GetListOfMaterials();
0677   dd4hep_ptr<TIterator> iter(mats->MakeIterator());
0678   while( (obj=iter->Next()) != 0 )  {
0679     TGeoMaterial* mat = (TGeoMaterial*)obj;
0680     if ( name.empty() || name == mat->GetName() )
0681       (*printer)(mat);
0682   }
0683   if ( element )   {
0684     xml::DocumentHandler dH;
0685     dH.output(doc, output);
0686   }
0687   return 1;
0688 }
0689 DECLARE_APPLY(DD4hep_MaterialTable,root_materials)
0690 
0691 /// Basic entry point to interprete an XML document
0692 /**
0693  *  - The file URI to be opened 
0694  *    is passed as first argument to the call.
0695  *  - The processing hint (build type) is passed as optional 
0696  *    second argument.
0697  *
0698  *  Factory: DD4hep_CompactLoader
0699  *
0700  *  \author  M.Frank
0701  *  \version 1.0
0702  *  \date    01/04/2014
0703  */
0704 static long load_compact(Detector& description, int argc, char** argv) {
0705   if ( argc > 0 )   {
0706     DetectorBuildType type = BUILD_DEFAULT;
0707     std::string input = argv[0];
0708     if ( argc > 1 )  {
0709       type = buildType(argv[1]);
0710       printout(INFO,"CompactLoader","+++ Processing compact file: %s with flag %s",
0711                input.c_str(), argv[1]);
0712       description.fromCompact(input,type);
0713       return 1;
0714     }
0715     printout(INFO,"CompactLoader","+++ Processing compact file: %s",input.c_str());
0716     description.fromCompact(input);
0717     return 1;
0718   }
0719   return 0;
0720 }
0721 DECLARE_APPLY(DD4hep_CompactLoader,load_compact)
0722 
0723 /// Basic entry point to process any XML document.
0724 /**
0725  *  - The file URI to be opened 
0726  *    is passed as first argument to the call.
0727  *  - The processing hint (build type) is passed as optional 
0728  *    second argument.
0729  *
0730  *  The root tag defines the plugin to interprete it.
0731  *
0732  *  Factory: DD4hep_XMLLoader
0733  *
0734  *  \author  M.Frank
0735  *  \version 1.0
0736  *  \date    01/04/2014
0737  */
0738 static long load_xml(Detector& description, int argc, char** argv) {
0739   if ( argc > 0 )   {
0740     DetectorBuildType type = BUILD_DEFAULT;
0741     std::string input = argv[0];
0742     if ( argc > 1 )  {
0743       type = buildType(argv[1]);
0744       printout(INFO,"XMLLoader","+++ Processing XML file: %s with flag %s",
0745                input.c_str(), argv[1]);
0746       description.fromXML(input, type);
0747       return 1;
0748     }
0749     printout(INFO,"XMLLoader","+++ Processing XML file: %s",input.c_str());
0750     description.fromXML(input, description.buildType());
0751     return 1;
0752   }
0753   return 0;
0754 }
0755 DECLARE_APPLY(DD4hep_XMLLoader,load_xml)
0756 
0757 /// Basic entry point to process any pre-parsed XML document.
0758 /**
0759  *  - The handle to the XML element (XercesC DOMNode) 
0760  *    is passed as first argument to the call.
0761  *  - The processing hint (build type) is passed as optional 
0762  *    second argument.
0763  *
0764  *  The root tag defines the plugin to interprete it.
0765  *
0766  *  Factory: DD4hep_XMLProcessor
0767  *
0768  *  \author  M.Frank
0769  *  \version 1.0
0770  *  \date    01/04/2014
0771  */
0772 static long process_xml_doc(Detector& description, int argc, char** argv) {
0773   if ( argc > 0 )   {
0774     DetectorBuildType type = BUILD_DEFAULT;
0775     DetectorImp* imp = dynamic_cast<DetectorImp*>(&description);
0776     if ( imp )  {
0777       xml::XmlElement* h = (xml::XmlElement*)argv[0];
0778       xml::Handle_t    input(h);
0779       if ( input.ptr() )   {
0780         if ( argc > 1 )  {
0781           type = buildType(argv[1]);
0782           printout(INFO,"XMLLoader","+++ Processing XML element: %s with flag %s",
0783                    input.tag().c_str(), argv[1]);
0784         }
0785         imp->processXMLElement(input, type);
0786         return 1;
0787       }
0788       except("DD4hepXMLProcessor",
0789              "++ The passed reference to the parsed XML document is invalid.");
0790     }
0791   }
0792   return 0;
0793 }
0794 DECLARE_APPLY(DD4hep_XMLProcessor,process_xml_doc)
0795 
0796 /// Basic entry point to load the volume manager object
0797 /**
0798  *  Factory: DD4hep_VolumeManager
0799  *
0800  *  \author  M.Frank
0801  *  \version 1.0
0802  *  \date    01/04/2014
0803  */
0804 static long load_volmgr(Detector& description, int, char**) {
0805   printout(INFO,"DD4hepVolumeManager","**** running plugin DD4hepVolumeManager ! " );
0806   try {
0807     DetectorImp* imp = dynamic_cast<DetectorImp*>(&description);
0808     if ( imp )  {
0809       imp->imp_loadVolumeManager();
0810       printout(INFO,"VolumeManager","+++ Volume manager populated and loaded.");
0811       return 1;
0812     }
0813   }
0814   catch (const std::exception& e) {
0815     except("DD4hep_VolumeManager", "Exception: %s\n     %s", e.what(),
0816            "dd4hep: while programming VolumeManager. Are your volIDs correct?");
0817   }
0818   catch (...) {
0819     except("DD4hep_VolumeManager",
0820            "UNKNOWN exception while programming VolumeManager. Are your volIDs correct?");
0821   }
0822   return 0;
0823 }
0824 DECLARE_APPLY(DD4hep_VolumeManager,load_volmgr)
0825 DECLARE_APPLY(DD4hepVolumeManager,load_volmgr)
0826 
0827 /// Basic entry point to dump a dd4hep geometry to a ROOT file
0828 /**
0829  *  Factory: DD4hep_Geometry2ROOT
0830  *
0831  *  \author  M.Frank
0832  *  \version 1.0
0833  *  \date    01/04/2014
0834  */
0835 static long dump_geometry2root(Detector& description, int argc, char** argv) {
0836   if ( argc > 0 )   {
0837     std::string output;
0838     for(int i = 0; i < argc && argv[i]; ++i)  {
0839       if ( 0 == ::strncmp("-output",argv[i],4) )
0840         output = argv[++i];
0841     }
0842     if ( output.empty() )   {
0843       std::cout <<
0844         "Usage: -plugin DD4hep_Geometry2ROOT -arg [-arg]                             \n\n"
0845         "     Output DD4hep detector description object to a ROOT file.              \n\n"
0846         "     -output <string>         Output file name.                               \n"
0847         "\tArguments given: " << arguments(argc,argv) << std::endl << std::flush;
0848       ::exit(EINVAL);
0849     }
0850     printout(INFO,"Geometry2ROOT","+++ Dump geometry to root file:%s",output.c_str());
0851     //description.manager().Export(output.c_str()+1);
0852     if ( DD4hepRootPersistency::save(description,output.c_str(),"Geometry") > 1 )  {
0853       return 1;
0854     }
0855   }
0856   printout(ERROR,"Geometry2ROOT","+++ No output file name given.");
0857   return 0;
0858 }
0859 DECLARE_APPLY(DD4hep_Geometry2ROOT,dump_geometry2root)
0860 
0861 /// Basic entry point to load a dd4hep geometry directly from the ROOT file
0862 /**
0863  *  Factory: DD4hep_RootLoader
0864  *
0865  *  \author  M.Frank
0866  *  \version 1.0
0867  *  \date    01/04/2014
0868  */
0869 static long load_geometryFromroot(Detector& description, int argc, char** argv) {
0870   if ( argc > 0 )   {
0871     std::string input = argv[0];  // <-- for backwards compatibility
0872     for(int i = 0; i < argc && argv[i]; ++i)  {
0873       if ( 0 == ::strncmp("-input",argv[i],4) )
0874         input = argv[++i];
0875     }
0876     if ( input.empty() )   {
0877       std::cout <<
0878         "Usage: DD4hep_RootLoader -arg [-arg]                                        \n\n"
0879         "     Load DD4hep detector description from ROOT file to memory.             \n\n"
0880         "     -input  <string>         Input file name.                                \n"
0881         "\tArguments given: " << arguments(argc,argv) << std::endl << std::flush;
0882       ::exit(EINVAL);
0883     }
0884     printout(INFO,"DD4hepRootLoader","+++ Read geometry from root file:%s",input.c_str());
0885     if ( 1 == DD4hepRootPersistency::load(description,input.c_str(),"Geometry") )  {
0886       return 1;
0887     }
0888   }
0889   printout(ERROR,"DD4hep_RootLoader","+++ No input file name given.");
0890   return 0;
0891 }
0892 DECLARE_APPLY(DD4hep_RootLoader,load_geometryFromroot)
0893 
0894 /// Basic entry point to dump a dd4hep geometry as TGeo to a ROOT file
0895 /**
0896  *  Factory: DD4hep_Geometry2TGeo
0897  *
0898  *  \author  W.Deconinck
0899  *  \version 1.0
0900  *  \date    14/09/2022
0901  */
0902 static long dump_geometry2tgeo(Detector& description, int argc, char** argv) {
0903   if ( argc > 0 )   {
0904     std::string output( argc == 1 ? argv[0] : "" );
0905     printout(INFO,"Geometry2TGeo","+++ output: %d %s", argc, output.c_str());
0906     for(int i = 0; i < argc && argv[i]; ++i)  {
0907       if ( 0 == ::strncmp("-output",argv[i],4) )
0908         output = argv[++i];
0909     }
0910     if ( output.empty() )   {
0911       std::cout <<
0912         "Usage: -plugin <name> -arg [-arg]                                             \n"
0913         "     Output TGeo information to a ROOT file.                                \n\n"
0914         "     name:   factory name     DD4hepGeometry2TGeo                             \n"
0915         "     -output <string>         Output file name.                               \n"
0916         "\tArguments given: " << arguments(argc,argv) << std::endl << std::flush;
0917       ::exit(EINVAL);
0918     }
0919     printout(INFO,"Geometry2TGeo","+++ Dump geometry to root file:%s",output.c_str());
0920     if ( description.manager().Export(output.c_str()) > 1 ) {
0921       return 1;
0922     }
0923   }
0924   printout(ERROR,"Geometry2TGeo","+++ No output file name given.");
0925   return 0;
0926 }
0927 DECLARE_APPLY(DD4hep_Geometry2TGeo,dump_geometry2tgeo)
0928 DECLARE_APPLY(DD4hepGeometry2TGeo,dump_geometry2tgeo)
0929 
0930 /// Basic entry point to check sensitive detector strictures
0931 /**
0932  *  Factory: DD4hep_CheckDetectors
0933  *
0934  *  \author  M.Frank
0935  *  \version 1.0
0936  *  \date    01/04/2014
0937  */
0938 static long check_detectors(Detector& description, int /* argc */, char** /* argv */) {
0939   DD4hepRootCheck check(&description);
0940   auto ret = check.checkDetectors();
0941   return ret.first > 0 && ret.second == 0 ? 1 : 0;
0942 }
0943 DECLARE_APPLY(DD4hep_CheckDetectors,check_detectors)
0944 
0945 /// Basic entry point to check sensitive detector strictures
0946 /**
0947  *  Factory: DD4hepCheckSensitives
0948  *
0949  *  \author  M.Frank
0950  *  \version 1.0
0951  *  \date    01/04/2014
0952  */
0953 static long check_sensitives(Detector& description, int /* argc */, char** /* argv */) {
0954   DD4hepRootCheck check(&description);
0955   auto ret = check.checkSensitives();
0956   return ret.first > 0 && ret.second == 0 ? 1 : 0;
0957 }
0958 DECLARE_APPLY(DD4hep_CheckSensitives,check_sensitives)
0959 
0960 /// Basic entry point to check sensitive detector strictures
0961 /**
0962  *  Factory: DD4hep_CheckSegmentations
0963  *
0964  *  \author  M.Frank
0965  *  \version 1.0
0966  *  \date    01/04/2014
0967  */
0968 static long check_segmentations(Detector& description, int /* argc */, char** /* argv */) {
0969   DD4hepRootCheck check(&description);
0970   auto ret = check.checkSegmentations();
0971   return ret.first > 0 && ret.second == 0 ? 1 : 0;
0972 }
0973 DECLARE_APPLY(DD4hep_CheckSegmentations,check_segmentations)
0974 
0975 /// Basic entry point to check sensitive detector strictures
0976 /**
0977  *  Factory: DD4hep_CheckReadouts
0978  *
0979  *  \author  M.Frank
0980  *  \version 1.0
0981  *  \date    01/04/2014
0982  */
0983 static long check_readouts(Detector& description, int /* argc */, char** /* argv */) {
0984   DD4hepRootCheck check(&description);
0985   auto ret = check.checkReadouts();
0986   return ret.first > 0 && ret.second == 0 ? 1 : 0;
0987 }
0988 DECLARE_APPLY(DD4hep_CheckReadouts,check_readouts)
0989 
0990 /// Basic entry point to check IDDescriptors of the detector object
0991 /**
0992  *  Factory: DD4hep_CheckIdspecs
0993  *
0994  *  \author  M.Frank
0995  *  \version 1.0
0996  *  \date    01/04/2014
0997  */
0998 static long check_idspecs(Detector& description, int /* argc */, char** /* argv */) {
0999   DD4hepRootCheck check(&description);
1000   auto ret = check.checkIdSpecs();
1001   return ret.first > 0 && ret.second == 0 ? 1 : 0;
1002 }
1003 DECLARE_APPLY(DD4hep_CheckIdspecs,check_idspecs)
1004 
1005 /// Basic entry point to check IDDescriptors of the detector object
1006 /**
1007  *  Factory: DD4hep_CheckVolumeManager
1008  *
1009  *  \author  M.Frank
1010  *  \version 1.0
1011  *  \date    01/04/2014
1012  */
1013 static long check_volumemanager(Detector& description, int /* argc */, char** /* argv */) {
1014   DD4hepRootCheck check(&description);
1015   auto ret = check.checkVolManager();
1016   return ret.first > 0 && ret.second == 0 ? 1 : 0;
1017 }
1018 DECLARE_APPLY(DD4hep_CheckVolumeManager,check_volumemanager)
1019 
1020 /// Basic entry point to check IDDescriptors of the detector object
1021 /**
1022  *  Factory: DD4hep_CheckNominals
1023  *
1024  *  \author  M.Frank
1025  *  \version 1.0
1026  *  \date    01/04/2014
1027  */
1028 static long check_nominals(Detector& description, int /* argc */, char** /* argv */) {
1029   DD4hepRootCheck check(&description);
1030   auto ret = check.checkNominals();
1031   return ret.first > 0 && ret.second == 0 ? 1 : 0;
1032 }
1033 DECLARE_APPLY(DD4hep_CheckNominals,check_nominals)
1034 
1035 /// Basic entry point to print out the volume hierarchy
1036 /**
1037  *  Factory: DD4hep_VolumeDump
1038  *
1039  *  \author  M.Frank
1040  *  \version 1.0
1041  *  \date    01/04/2014
1042  */
1043 static long dump_volume_tree(Detector& description, int argc, char** argv) {
1044   struct Actor {
1045     Detector&        description;
1046     bool             m_printPathes         = false;
1047     bool             m_printVolIDs         = false;
1048     bool             m_printShapes         = false;
1049     bool             m_printPointers       = false;
1050     bool             m_printPositions      = false;
1051     bool             m_printVis            = false;
1052     bool             m_printMaterials      = false;
1053     bool             m_printSensitivesOnly = false;
1054     long             m_printMaxLevel       = 999999;
1055     long             m_numNodes            = 0;
1056     long             m_numShapes           = 0;
1057     long             m_numSensitive        = 0;
1058     long             m_numMaterial         = 0;
1059     long             m_numMaterialERR      = 0;
1060     bool             m_topStat             = false;
1061     std::string      m_detector;
1062     std::string                currTop;
1063     std::map<std::string,long> top_counts;
1064     
1065     Actor(Detector& desc, int ac, char** av) : description(desc)  {
1066       m_detector = "/world";
1067       for(int i=0; i<ac; ++i)  {
1068         char c = ::tolower(av[i][0]);
1069         char* p = av[i];
1070         if ( c == '-' ) { ++p; c = ::tolower(av[i][1]); }
1071         if ( c == '-' ) { ++p; c = ::tolower(av[i][1]); }
1072         if      ( ::strncmp(p,"volume_ids",3) == 0  ) m_printVolIDs         = true;
1073         else if ( ::strncmp(p,"level",3)      == 0  ) m_printMaxLevel       = ::atol(av[++i]);
1074         else if ( ::strncmp(p,"materials",3)  == 0  ) m_printMaterials      = true;
1075         else if ( ::strncmp(p,"pathes",3)     == 0  ) m_printPathes         = true;
1076         else if ( ::strncmp(p,"positions",3)  == 0  ) m_printPositions      = true;
1077         else if ( ::strncmp(p,"pointers",3)   == 0  ) m_printPointers       = true;
1078         else if ( ::strncmp(p,"shapes",3)     == 0  ) m_printShapes         = true;
1079         else if ( ::strncmp(p,"sensitive",3)  == 0  ) m_printSensitivesOnly = true;
1080         else if ( ::strncmp(p,"topstats",3)   == 0  ) m_topStat             = true;
1081         else if ( ::strncmp(p,"vis",3)        == 0  ) m_printVis            = true;
1082         else if ( ::strncmp(p,"detector",3)   == 0  ) m_detector            = av[++i];
1083         else if ( ::strncmp(p,"help",3)       == 0  )   {
1084           std::cout <<
1085             "Usage: -plugin <name> -arg [-arg]                                                   \n"
1086             "     -detector <string> Top level DetElement path. Default: '/world'                \n"
1087             "     -pathes            Print DetElement pathes                                     \n"
1088             "     -level    <number> Maximal depth to be explored by the scan                    \n"
1089             "     -positions         Print placement positions                                   \n"
1090             "     -volume_ids        Print placement volume IDs                                  \n"
1091             "     -materials         Print volume materials                                      \n"       
1092             "     -pointers          Debug: Print pointer values                                 \n"       
1093             "     -shapes            Print shape information                                     \n"
1094             "     -vis               Print visualisation attribute name(s) if present            \n"
1095             "     -sensitive         Only print information for sensitive volumes                \n"
1096             "     -topstats          Print statistics about top level node                       \n"       
1097             "\tArguments given: " << arguments(ac,av) << std::endl << std::flush;
1098           _exit(0);
1099         }
1100       }
1101       if ( m_printMaxLevel < 999999 )
1102         printout(ALWAYS,"VolumeDump","+++ Maximal print level:   %ld",m_printMaxLevel);
1103       if ( !m_detector.empty() )
1104         printout(ALWAYS,"VolumeDump","+++ Subdetector path:      %s",m_detector.c_str());
1105       printout(ALWAYS,"VolumeDump","+++ Printing positions:    %s",yes_no(m_printPositions));
1106       printout(ALWAYS,"VolumeDump","+++ Printing shapes:       %s",yes_no(m_printShapes));
1107       printout(ALWAYS,"VolumeDump","+++ Printing materials:    %s",yes_no(m_printMaterials));
1108       printout(ALWAYS,"VolumeDump","+++ Printing volume ids:   %s",yes_no(m_printVolIDs));
1109       printout(ALWAYS,"VolumeDump","+++ Printing visattrs:     %s",yes_no(m_printVis));
1110       printout(ALWAYS,"VolumeDump","+++ Print only sensitives: %s",yes_no(m_printSensitivesOnly));
1111     }
1112     ~Actor()  {
1113       printout(ALWAYS,"VolumeDump",
1114                "+++ Checked %ld physical volume placements.     %3ld are sensitive.",
1115                m_numNodes, m_numSensitive);
1116       if ( m_printMaterials )  {
1117         printout(ALWAYS,"VolumeDump",
1118                  "+++ Checked %ld materials in volume placements. %3ld are BAD.",
1119                  m_numMaterial, m_numMaterialERR);
1120       }
1121       if ( m_printShapes )   {
1122         printout(ALWAYS,"VolumeDump","+++ Checked %ld shapes.", m_numShapes);
1123       }
1124       if ( m_topStat )  {
1125         for(const auto& t : top_counts)  {
1126           if ( t.second > 1 )
1127             printout(ALWAYS,"VolumeDump",
1128                      "+++     Top node: %-32s     %8ld placements.",t.first.c_str(),t.second);
1129         }
1130       }
1131     }
1132 
1133     long dump(std::string prefix, TGeoNode* ideal, TGeoNode* aligned, int level, PlacedVolume::VolIDs volids)  {
1134       char fmt[128];
1135       std::stringstream log;
1136       PlacedVolume pv(ideal);
1137       bool sensitive = false;
1138       std::string opt_info, pref = std::move(prefix);
1139 
1140       if ( level >= m_printMaxLevel )    {
1141         return 1;
1142       }
1143       ++m_numNodes;
1144       if ( level == 0 )
1145         currTop = "";
1146       else if ( level == 1 )   {
1147         currTop = ideal->GetVolume()->GetName();
1148         ++top_counts[currTop];
1149       }
1150       else if ( level > 1 )   {
1151         ++top_counts[currTop];
1152       }
1153 
1154       if ( m_printPathes )   {
1155         pref += "/";
1156         pref += aligned->GetName();
1157       }
1158       /// 
1159       TGeoVolume* mother = ideal ? ideal->GetMotherVolume() : nullptr;
1160       if ( m_printPositions || m_printVolIDs )  {
1161         if ( m_printPointers )    {
1162           if ( ideal != aligned )
1163             std::snprintf(fmt,sizeof(fmt),"Ideal:%p Aligned:%p ",
1164                           (void*)ideal,(void*)aligned);
1165           else
1166             std::snprintf(fmt,sizeof(fmt),"Ideal:%p MotherVol:%p",
1167                           (void*)ideal, (void*)mother);
1168           log << fmt;
1169         }
1170         // Top level volume! have no volume ids
1171         if ( m_printVolIDs && ideal && ideal->GetMotherVolume() )  {
1172           PlacedVolume::VolIDs vid = pv.volIDs();
1173           if ( !vid.empty() )  {
1174             sensitive = true;
1175             log << " VolID: ";
1176             volids.insert(volids.end(),vid.begin(),vid.end());
1177             for( const auto& i : volids )  {
1178               std::snprintf(fmt, sizeof(fmt), "%s:%2d ",i.first.c_str(),i.second);
1179               log << fmt;
1180             }
1181             if ( !vid.empty() || pv.volume().isSensitive() )  {
1182               SensitiveDetector sd = pv.volume().sensitiveDetector();
1183               if ( sd.isValid() )  {
1184                 IDDescriptor dsc = sd.readout().idSpec();
1185                 if ( dsc.isValid() )  {
1186                   log << std::hex << " (0x" << std::setfill('0') << std::setw(8)
1187                       << dsc.encode(volids)
1188                       << std::setfill(' ') << std::dec << ") ";
1189                 }
1190               }
1191             }
1192           }
1193         }
1194         opt_info = log.str();
1195         log.str("");
1196       }
1197       ///  
1198       if ( m_printVis && pv.volume().visAttributes().isValid() )   {
1199         log << " Vis:" << pv.volume().visAttributes().name();
1200         opt_info += log.str();
1201         log.str("");
1202       }
1203       TGeoVolume* volume = ideal ? ideal->GetVolume() : 0;
1204       if ( !m_printSensitivesOnly || (m_printSensitivesOnly && sensitive) )  {
1205         Volume vol = pv.volume();
1206         char  sens = vol.isSensitive() ? 'S' : ' ';
1207         if ( m_printPointers )    {
1208           if ( ideal == aligned )  {
1209             std::snprintf(fmt,sizeof(fmt),"%03d %%s [Ideal:%p Vol:%p MotherVol:%p] %%-%ds %%-16s Vol:%%s shape:%%s \t %c %%s",
1210                           level+1,(void*)ideal,(void*)vol, (void*)mother, 2*level+1, sens);
1211           }
1212           else  {
1213             std::snprintf(fmt,sizeof(fmt),"%03d %%s Ideal:%p Aligned:%p %%-%ds %%-16s Vol:%%s shape:%%s %c %%s",
1214                           level+1,(void*)ideal,(void*)aligned,2*level+1,sens);
1215           }
1216         }
1217         else  {
1218           if ( ideal == aligned )  {
1219             std::snprintf(fmt,sizeof(fmt),"%03d %%s %%-%ds %%-16s Vol:%%s shape:%%s \t %c %%s",
1220                           level+1,2*level+1,sens);
1221           }
1222           else  {
1223             std::snprintf(fmt,sizeof(fmt),"%03d %%s Ideal:%p Aligned:%p %%-%ds %%-16s Vol:%%s shape:%%s %c %%s",
1224                           level+1,(void*)ideal,(void*)aligned,2*level+1,sens);
1225           }
1226         }
1227         const auto* sh = volume ? volume->GetShape() : nullptr;
1228         printout(INFO,"VolumeDump",fmt,pref.c_str(),"",
1229                  aligned->GetName(),
1230                  vol.name(),
1231                  sh ? sh->IsA()->GetName() : "[Invalid Shape]",
1232                  opt_info.c_str());
1233         if ( sens == 'S' ) ++m_numSensitive;
1234       }
1235       if ( m_printMaterials )   {
1236         Volume   vol = pv.volume();
1237         Material mat = vol.material();
1238         TGeoMaterial* mptr = mat->GetMaterial();
1239         bool ok = mat.A() == mptr->GetA() && mat.Z() == mptr->GetZ();
1240         std::snprintf(fmt,sizeof(fmt),"%03d %%s %%-%ds Material: %%-16s A:%%6.2f %%6.2f  Z:%%6.2f %%6.2f",
1241                       level+1,2*level+1);
1242         ++m_numMaterial;
1243         if ( !ok ) ++m_numMaterialERR;
1244         printout(ok ? INFO : ERROR, "VolumeDump", fmt,
1245                  "  ->", "", mat.name(), mat.A(), mptr->GetA(), mat.Z(), mptr->GetZ());
1246       }
1247       log.str("");
1248       if ( m_printShapes )   {
1249         log << "Shape: " << toStringSolid(pv.volume().solid()) << " \t";
1250       }
1251       if ( m_printPositions )  {
1252         if ( ideal )  {
1253           const double* trans = ideal->GetMatrix()->GetTranslation();
1254           std::snprintf(fmt, sizeof(fmt), "Pos: (%f,%f,%f) ",trans[0],trans[1],trans[2]);
1255         }
1256         else  {
1257           std::snprintf(fmt, sizeof(fmt), " <ERROR: INVALID Translation matrix> ");
1258         }
1259         log << fmt << " \t";
1260       }
1261       if ( !log.str().empty() )  {
1262         std::snprintf(fmt,sizeof(fmt),"%03d %%s %%-%ds %%s",level+1,2*level+1);
1263         printout(INFO, "VolumeDump", fmt, "  ->", "", log.str().c_str());
1264       }
1265       for (Int_t idau = 0, ndau = aligned->GetNdaughters(); idau < ndau; ++idau)  {
1266         if ( ideal )   {
1267           TGeoNode*   ideal_daughter   = ideal->GetDaughter(idau);
1268           const char* daughter_name    = ideal_daughter->GetName();
1269           TGeoNode*   aligned_daughter = volume->GetNode(daughter_name);
1270           dump(pref, ideal_daughter, aligned_daughter, level+1, volids);
1271         }
1272         else  {
1273           printout(ERROR,"VolumeDump"," <ERROR: INVALID IDEAL Translation matrix>: %s",aligned->GetName());
1274         }
1275       }
1276       return 1;
1277     }
1278     ///
1279     int operator()()   {
1280       PlacedVolume pv;
1281       DetElement   top = description.world();
1282       detail::tools::PlacementPath path;
1283 
1284       if ( m_detector != "/world" )   {
1285         top = detail::tools::findElement(description,m_detector);
1286         if ( !top.isValid() )  {
1287           except("VolumeDump","+++ Invalid DetElement path: %s",m_detector.c_str());
1288         }
1289       }
1290       if ( !top.placement().isValid() )   {
1291         except("VolumeDump","+++ Invalid DetElement placement: %s",m_detector.c_str());
1292       }
1293       std::string place = top.placementPath();
1294       detail::tools::placementPath(top, path);
1295       pv = detail::tools::findNode(description.world().placement(),place);
1296       if ( !pv.isValid() )   {
1297         except("VolumeDump","+++ Invalid placement verification for placement:%s",place.c_str());
1298       }
1299       return this->dump("", top.placement().ptr(), pv.ptr(), 0, PlacedVolume::VolIDs());
1300     }
1301   };
1302   Actor actor(description, argc, argv);
1303   return actor();
1304 }
1305 DECLARE_APPLY(DD4hep_VolumeDump,dump_volume_tree)
1306 
1307 // ======================================================================================
1308 /// Plugin function: Apply arbitrary functor callback on the tree of detector elements
1309 /**
1310  *  Factory: dd4hep_DetElementProcessor
1311  *
1312  *  Invokation: -plugin dd4hep_DetElementProcessor 
1313  *                      -detector /path/to/detElement (default: /world)
1314  *                      -processor <factory-name> <processor-args>
1315  *
1316  *  \author  M.Frank
1317  *  \version 1.0
1318  *  \date    18/11/2016
1319  */
1320 static int detelement_processor(Detector& description, int argc, char** argv)   {
1321   bool          recursive = true;
1322   ProcessorArgs args(argc, argv);
1323   DetElement    det = description.world();
1324   std::unique_ptr<DetectorProcessor>
1325     proc(dd4hep::createProcessor<DetectorProcessor>(description, args.argc, &args.argv[0]));
1326 
1327   for(int i=0; i<argc; ++i)  {
1328     if ( i >= args.start && i <= args.end )
1329       continue;
1330     else if ( 0 == ::strncmp(argv[i],"-recursive",4) )
1331       recursive = true;
1332     else if ( 0 == ::strncmp(argv[i],"-no-recursive",7) )
1333       recursive = false;
1334     else if ( 0 == ::strncmp(argv[i],"-detector",4) )  {
1335       std::string path = argv[++i];
1336       det = detail::tools::findElement(description, path);
1337       if ( det.isValid() )   {
1338         continue;
1339       }
1340       except("DetElementProcessor",
1341              "++ The detector element path:%s is not part of this description!",
1342              path.c_str());
1343     }
1344     else  {
1345       except("DetElementProcessor","++ Unknown plugin argument: %s",argv[i]);
1346     }
1347   }
1348   return DetectorScanner().scan(*proc, det, 0, recursive) > 0 ? 1 : 0;
1349 }
1350 DECLARE_APPLY(DD4hep_DetElementProcessor,detelement_processor)
1351 
1352 // ======================================================================================
1353 /// Plugin function: Apply arbitrary functor callback on the tree of detector elements
1354 /**
1355  *  Factory: DD4hep_DetElementProcessor
1356  *
1357  *  Invokation: -plugin DD4hep_DetElementProcessor 
1358  *                      -detector /path/to/detElement (default: /world)
1359  *                      -processor <factory-name> <processor-args>
1360  *
1361  *  \author  M.Frank
1362  *  \version 1.0
1363  *  \date    18/11/2016
1364  */
1365 static int placed_volume_processor(Detector& description, int argc, char** argv)   {
1366   bool         recursive = true;
1367   PlacedVolume pv = description.world().placement();
1368   ProcessorArgs args(argc, argv);
1369   std::unique_ptr<PlacedVolumeProcessor>
1370     proc(dd4hep::createProcessor<PlacedVolumeProcessor>(description, args.argc, &args.argv[0]));
1371 
1372   std::string path = "/world";
1373   for(int i=0; i<argc; ++i)  {
1374     if ( i >= args.start && i <= args.end )
1375       continue;
1376     else if ( 0 == ::strncmp(argv[i],"-recursive",4) )
1377       recursive = true;
1378     else if ( 0 == ::strncmp(argv[i],"--recursive",5) )
1379       recursive = true;
1380     else if ( 0 == ::strncmp(argv[i],"-no-recursive",7) )
1381       recursive = false;
1382     else if ( 0 == ::strncmp(argv[i],"--no-recursive",8) )
1383       recursive = false;
1384     else if ( 0 == ::strncmp(argv[i],"-detector",4) )
1385       path = argv[++i];
1386     else if ( 0 == ::strncmp(argv[i],"--detector",5) )
1387       path = argv[++i];
1388     else
1389       except("PlacedVolumeProcessor","++ Unknown plugin argument: %s",argv[i]);
1390   }
1391   DetElement det  = detail::tools::findElement(description, path);
1392   if ( det.isValid() )  {
1393     pv = det.placement();
1394     if ( pv.isValid() )  {
1395       return PlacedVolumeScanner().scanPlacements(*proc, pv, 0, recursive) > 0 ? 1 : 0;
1396     }
1397     except("PlacedVolumeProcessor",
1398            "++ The detector element with path:%s has no valid placement!",
1399            path.c_str());
1400   }
1401   except("PlacedVolumeProcessor",
1402          "++ The detector element path:%s is not part of this description!",
1403          path.c_str());
1404   return 0;
1405 }
1406 DECLARE_APPLY(DD4hep_PlacedVolumeProcessor,placed_volume_processor)
1407 
1408 /// Basic entry point to print out the detector element hierarchy
1409 /**
1410  *  Factory: DD4hep_DetectorDump, DD4hep_DetectorVolumeDump
1411  *
1412  *  \author  M.Frank
1413  *  \version 1.0
1414  *  \date    01/04/2014
1415  */
1416 template <int flag> long dump_detelement_tree(Detector& description, int argc, char** argv) {
1417   using VolIDs = PlacedVolume::VolIDs;
1418   /// Local helper class
1419   struct Actor {
1420     Detector& descr;
1421     std::string path     { };
1422     DetElement det_world { };
1423     long count          = 0;
1424     int  have_match     = -1;
1425     int  analysis_level = 999999;
1426     bool dump_materials = false;
1427     bool dump_shapes    = false;
1428     bool dump_positions = false;
1429     bool dump_volids    = false;
1430     bool sensitive_only = false;
1431 
1432     /// Initializing constructor
1433     Actor(Detector& det) : descr(det) {
1434       det_world = descr.world();
1435     }
1436     /// Default destructor
1437     ~Actor() {
1438       printout(ALWAYS,"DetectorDump", "+++ Scanned a total of %ld elements.",count);
1439     }
1440     void parse_args(int ac, char** av)   {
1441       for(int i=0; i<ac; ++i)  {
1442         if      ( ::strncmp(av[i],"--sensitive",     5)==0 ) { sensitive_only = true;  }
1443         else if ( ::strncmp(av[i], "-sensitive",     5)==0 ) { sensitive_only = true;  }
1444         else if ( ::strncmp(av[i], "--no-sensitive", 8)==0 ) { sensitive_only = false; }
1445         else if ( ::strncmp(av[i], "-materials",     4)==0 ) { dump_materials = true;  }
1446         else if ( ::strncmp(av[i], "--materials",    5)==0 ) { dump_materials = true;  }
1447         else if ( ::strncmp(av[i], "-shapes",        4)==0 ) { dump_shapes    = true;  }
1448         else if ( ::strncmp(av[i], "--shapes",       5)==0 ) { dump_shapes    = true;  }
1449         else if ( ::strncmp(av[i], "-positions",     4)==0 ) { dump_positions = true;  }
1450         else if ( ::strncmp(av[i], "--positions",    5)==0 ) { dump_positions = true;  }
1451         else if ( ::strncmp(av[i], "-no-sensitive",  7)==0 ) { sensitive_only = false; }
1452         else if ( ::strncmp(av[i], "--volids",       5)==0 ) { dump_volids    = true;  }
1453         else if ( ::strncmp(av[i], "-volids",        5)==0 ) { dump_volids    = true;  }
1454         else if ( ::strncmp(av[i], "--detector",     5)==0 ) { path = av[++i];       }
1455         else if ( ::strncmp(av[i], "-detector",      5)==0 ) { path = av[++i];       }
1456         else if ( ::strncmp(av[i], "--level",        5)==0 ) { analysis_level = ::atol(av[++i]); }
1457         else if ( ::strncmp(av[i], "-level",         5)==0 ) { analysis_level = ::atol(av[++i]); }
1458         else   {
1459           std::cout << "  "
1460                     << (flag==0 ? "DD4hep_DetectorDump" : "DD4hep_DetectorVolumeDump") << " -arg [-arg]   \n\n"
1461                     << "         Dump " << (flag==0 ? "DetElement" : "Detector volume") << " tree.          \n"
1462                     << "         Configure produced output information using the following options:       \n\n"
1463             "   --sensitive             Process only sensitive volumes.                                \n"
1464             "    -sensitive             dto.                                                           \n"
1465             "   --no-sensitive          Invert sensitive only flag.                                    \n"
1466             "    -no-sensitive          dto.                                                           \n"
1467             "   --shapes                Print shape information.                                       \n"
1468             "    -shapes                dto.                                                           \n"
1469             "   --positions             Print position information.                                    \n"
1470             "    -positions             dto.                                                           \n"
1471             "   --materials             Print material information.                                    \n"
1472             "    -materials             dto.                                                           \n"
1473             "   --detector    <path>    Process elements only if <path> is part of the DetElement path.\n"
1474             "    -detector    <path>    dto.                                                           \n"
1475             "    -level       <number>  Maximal depth to be explored by the scan                       \n"
1476             "   --level       <number>  dto.                                                           \n"
1477             "    -volids                Print volume identifiers of placements.                        \n"
1478             "   --volids                dto.                                                           \n"
1479             "\tArguments given: " << arguments(ac,av) << std::endl << std::flush;        
1480           ::exit(EINVAL);
1481         }
1482       }
1483     }
1484     IDDescriptor get_id_descriptor(PlacedVolume pv)   {
1485       if ( pv.isValid() )  {
1486         Volume v = pv.volume();
1487         SensitiveDetector sd = v.sensitiveDetector();
1488         if ( sd.isValid() )   {
1489           IDDescriptor dsc = sd.readout().idSpec();
1490           if ( dsc.isValid() ) return dsc;
1491         }
1492         for (Int_t idau = 0, ndau = v->GetNdaughters(); idau < ndau; ++idau)  {
1493           IDDescriptor dsc = get_id_descriptor(v->GetNode(idau));
1494           if ( dsc.isValid() ) return dsc;
1495         }
1496       }
1497       return IDDescriptor();
1498     }
1499     void validate_id_descriptor(DetElement de, IDDescriptor& desc)   {
1500       desc = (!de.parent() || de.parent() == det_world)
1501         ? IDDescriptor() : get_id_descriptor(de.placement());
1502     }
1503 
1504     long dump(DetElement de, int level, IDDescriptor& id_desc, VolIDs chain)   {
1505       char fmt[256];
1506       PlacedVolume place = de.placement();
1507       const DetElement::Children& children = de.children();
1508       bool use_elt = path.empty() || de.path().find(path) != std::string::npos;
1509 
1510       if ( have_match < 0 && use_elt )  {
1511         have_match = level;
1512       }
1513 
1514       use_elt &= ((level-have_match) <= analysis_level);
1515       if ( !place.isValid() )    {
1516         std::snprintf(fmt,sizeof(fmt),"%03d %%-%ds %%s DetElement with INVALID PLACEMENT!", level+1, 2*level+1);
1517         printout(ERROR,"DetectorDump", fmt, "", de.path().c_str());
1518         use_elt = false;
1519       }
1520 
1521       if ( place.isValid() && de != det_world )    {
1522         chain.insert(chain.end(), place.volIDs().begin(), place.volIDs().end());
1523       }
1524       if ( use_elt )   {
1525         if ( !sensitive_only || 0 != de.volumeID() )  {
1526           char sens = place.isValid() && place.volume().isSensitive() ? 'S' : ' ';
1527           switch( flag )  {
1528           case 0:
1529             ++count;
1530             if ( de.placement() == de.idealPlacement() )  {
1531               std::snprintf(fmt, sizeof(fmt), "%03d %%-%ds %%s NumDau:%%d VolID:%%08X Place:%%p  %%c", level+1, 2*level+1);
1532               printout(INFO, "DetectorDump", fmt, "", de.path().c_str(), int(children.size()),
1533                        (unsigned long)de.volumeID(), (void*)place.ptr(), sens);
1534               break;
1535             }
1536             std::snprintf(fmt, sizeof(fmt), "%03d %%-%ds %%s NumDau:%%d VolID:%%08X Place:%%p [ideal:%%p aligned:%%p]  %%c",
1537                           level+1, 2*level+1);
1538             printout(INFO, "DetectorDump", fmt, "", de.path().c_str(), int(children.size()),
1539                      (unsigned long)de.volumeID(), (void*)de.idealPlacement().ptr(),
1540                      (void*)place.ptr(), sens);
1541             break;
1542           case 1:
1543             ++count;
1544             std::snprintf(fmt, sizeof(fmt), "%03d %%-%ds Detector: %%s NumDau:%%d VolID:%%p", level+1, 2*level+1);
1545             printout(INFO, "DetectorDump", fmt, "", de.path().c_str(), int(children.size()), (void*)de.volumeID());
1546             if ( de.placement() == de.idealPlacement() )  {
1547               std::snprintf(fmt, sizeof(fmt), "%03d %%-%ds Placement: %%s  %%c", level+1, 2*level+3);
1548               printout(INFO,"DetectorDump",fmt,"", de.placementPath().c_str(), sens);
1549               break;
1550             }
1551             std::snprintf(fmt,sizeof(fmt), "%03d %%-%ds Placement: %%s  [ideal:%%p aligned:%%p] %%c",
1552                           level+1,2*level+3);
1553             printout(INFO,"DetectorDump",fmt,"", de.placementPath().c_str(),
1554                      (void*)de.idealPlacement().ptr(), (void*)place.ptr(), sens);          
1555             break;
1556           default:
1557             break;
1558           }
1559           if ( (dump_materials || dump_shapes) && place.isValid() )  {
1560             Volume vol = place.volume();
1561             Material mat = vol.material();
1562             std::snprintf(fmt,sizeof(fmt), "%03d %%-%ds Material: %%-12s Shape: %%s", level+1,2*level+3);
1563             printout(INFO,"DetectorDump",fmt,"", mat.name(), toStringSolid(vol->GetShape()).c_str());
1564           }
1565           if ( dump_positions && place.isValid() )  {
1566             Position pos = place.position();
1567             Box      box = place.volume().solid();
1568             double   loc[3] = {0,0,0}, world[3] = {0,0,0};
1569             TGeoHMatrix   tr = de.nominal().worldTransformation();
1570             tr.LocalToMaster(loc, world);
1571             std::snprintf(fmt,sizeof(fmt), "%03d %%-%ds BBox:     (%%9.4f,%%9.4f,%%9.4f) [cm]", level+1,2*level+3);
1572             printout(INFO,"DetectorDump",fmt,"", box.x(), box.y(), box.z());
1573             std::snprintf(fmt,sizeof(fmt), "%03d %%-%ds Position: (%%9.4f,%%9.4f,%%9.4f) [cm] w/r to mother", level+1,2*level+3);
1574             printout(INFO,"DetectorDump",fmt,"", pos.X(), pos.Y(), pos.Z());
1575             std::snprintf(fmt,sizeof(fmt), "%03d %%-%ds Position: (%%9.4f,%%9.4f,%%9.4f) [cm] w/r to world",  level+1,2*level+3);
1576             printout(INFO,"DetectorDump",fmt,"", world[0], world[1], world[2]);
1577           }
1578           if ( dump_volids && !place.volIDs().empty() )    {
1579             std::stringstream log;
1580             log << " VID:";
1581             for( const auto& i : chain )
1582               log << " " << i.first << ':' << std::dec << std::setw(2) << i.second;
1583             if ( id_desc.isValid() )  {
1584               log << " (encoded:0x" << std::setfill('0') << std::setw(8) << std::hex
1585                   << id_desc.encode(chain)
1586                   << std::setfill(' ') << std::dec << ") ";
1587             }
1588             std::snprintf(fmt,sizeof(fmt),"%03d %%-%ds %%s", level+1, 2*level+1);
1589             printout(INFO,"DetectorDump", fmt, "", log.str().c_str());
1590           }
1591         }
1592       }
1593       for ( const auto& c : children )   {
1594         validate_id_descriptor(c.second, id_desc);
1595         dump(c.second, level+1, id_desc, chain);
1596       }
1597       return 1;
1598     }
1599   };
1600   VolIDs       chain;
1601   IDDescriptor id_descriptor;
1602   Actor        actor(description);
1603   actor.parse_args(argc, argv);
1604   return actor.dump(description.world(), 0, id_descriptor, std::move(chain));
1605 }
1606 DECLARE_APPLY(DD4hep_DetectorDump,dump_detelement_tree<0>)
1607 DECLARE_APPLY(DD4hep_DetectorVolumeDump,dump_detelement_tree<1>)
1608 
1609 /// Basic entry point to print out the volume hierarchy
1610 /**
1611  *  Factory: DD4hep_DetElementCache
1612  *
1613  *  \author  M.Frank
1614  *  \version 1.0
1615  *  \date    01/04/2014
1616  */
1617 static long detelement_cache(Detector& description, int argc, char** argv) {
1618   struct Actor {
1619     long cache(DetElement de) {
1620       const DetElement::Children& c = de.children();
1621       de.nominal().worldTransformation();
1622       de.nominal().detectorTransformation();
1623       de.placementPath();
1624       de.path();
1625       for( const auto& i : c ) cache(i.second);
1626       return 1;
1627     }
1628   } actor;
1629   std::string detector = "/world";
1630   for(int i = 0; i < argc && argv[i]; ++i)  {
1631     if ( 0 == ::strncmp("-detector",argv[i],4) )
1632       detector = argv[++i];
1633     else if ( 0 == ::strncmp("--detector",argv[i],5) )
1634       detector = argv[++i];
1635     else  {
1636       std::cout <<
1637         "Usage: -plugin DD4hep_DetElementCache  -arg [-arg]                 \n\n"
1638         "     Fill cache with transformation information in DetElements.    \n\n"
1639         "     -detector <string>  Top level DetElement path. Default: '/world'\n"
1640         "     --detector <string> dto.                                        \n"
1641         "     -help              Print this help.                             \n"
1642         "     Arguments given: " << arguments(argc,argv) << std::endl << std::flush;
1643       ::exit(EINVAL);
1644     }
1645   }
1646   DetElement element = description.world();
1647   if ( detector != "/world" )   {
1648     element = detail::tools::findElement(description, detector);
1649     if ( !element.isValid() )  {
1650       except("VolumeDump","+++ Invalid DetElement path: %s", detector.c_str());
1651     }
1652   }
1653   return actor.cache(element);
1654 }
1655 DECLARE_APPLY(DD4hep_DetElementCache,detelement_cache)
1656 
1657 /// Basic entry point to dump the geometry tree of the description instance
1658 /**
1659  *  Factory: DD4hep_GeometryTreeDump
1660  *
1661  *  \author  M.Frank
1662  *  \version 1.0
1663  *  \date    01/04/2014
1664  */
1665 #include "../GeometryTreeDump.h"
1666 static long exec_GeometryTreeDump(Detector& description, int, char** ) {
1667   GeometryTreeDump dmp;
1668   dmp.create(description.world());
1669   return 1;
1670 }
1671 DECLARE_APPLY(DD4hep_GeometryTreeDump,exec_GeometryTreeDump)
1672 
1673 /// Basic entry point to print out detector type map
1674 /**
1675  *  Factory: DD4hep_DetectorTypes
1676  *
1677  *  \author  M.Frank
1678  *  \version 1.0
1679  *  \date    01/04/2014
1680  */
1681 static long detectortype_cache(Detector& description, int argc, char** argv)  {
1682   std::vector<std::string> types;
1683   for(int i = 0; i < argc && argv[i]; ++i)  {
1684     if ( 0 == ::strncmp("-type",argv[i],4) )
1685       types.push_back(argv[++i]);
1686     else if ( 0 == ::strncmp("--type",argv[i],4) )
1687       types.push_back(argv[++i]);
1688     else   {
1689       std::cout <<
1690         "Usage: DD4hep_DetectorTypes -type <type> -arg [-arg]                          \n"
1691         "     Dump detector types from detector description.                         \n\n"
1692         "     -type   <string>         Add new type to be listed. Multiple possible.   \n"
1693         "\tArguments given: " << arguments(argc,argv) << std::endl << std::flush;
1694       ::exit(EINVAL);
1695     }
1696   }
1697   if ( types.empty() )   {
1698     types = description.detectorTypes();
1699   }
1700   printout(INFO,"DetectorTypes","Detector type dump:  %ld types:", long(types.size()));
1701   for( const auto& type : types )   {
1702     const std::vector<DetElement>& detectors = description.detectors(type);
1703     printout(INFO,"DetectorTypes","\t --> %ld %s detectors:",long(detectors.size()), type.c_str());
1704     for( const auto& d : detectors )   {
1705       printout(INFO,"DetectorTypes","\t\t %-16s --> %s  [%s]",type.c_str(),d.name(),d.type().c_str());
1706     }
1707   }
1708   return 1;
1709 }
1710 DECLARE_APPLY(DD4hep_DetectorTypes,detectortype_cache)
1711 
1712 /// Basic entry point to print out detector type map
1713 /**
1714  *  Factory: TestSurfaces
1715  *
1716  *  \author  M.Frank
1717  *  \version 1.0
1718  *  \date    01/04/2014
1719  */
1720 #include <DD4hep/SurfaceInstaller.h>
1721 typedef SurfaceInstaller TestSurfacesPlugin;
1722 DECLARE_SURFACE_INSTALLER(TestSurfaces,TestSurfacesPlugin)
1723 
1724 /// Basic entry point to print out detector type map
1725 /**
1726  *  Factory: DD4hep_PluginTester
1727  *
1728  *  \author  M.Frank
1729  *  \version 1.0
1730  *  \date    01/04/2014
1731  */
1732 #include <DD4hep/PluginTester.h>
1733 static long install_plugin_tester(Detector& description, int , char** ) {
1734   PluginTester* test = description.extension<PluginTester>(false);
1735   if ( !test )  {
1736     description.addExtension<PluginTester>(new PluginTester());
1737     printout(INFO,"PluginTester",
1738              "+++ Successfully installed PluginTester instance to Detector.");
1739   }
1740   return 1;
1741 }
1742 DECLARE_APPLY(DD4hep_PluginTester,install_plugin_tester)
1743