Back to home page

EIC code displayed by LXR

 
 

    


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

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