Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-12 08:24:28

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 Markus Frank
0011 //  \date   2015-11-09
0012 //
0013 //==========================================================================
0014 
0015 // Framework include files
0016 #include <DDG4/Geant4DetectorConstruction.h>
0017 
0018 /// Namespace for the AIDA detector description toolkit
0019 namespace dd4hep {
0020 
0021   /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
0022   namespace sim {
0023 
0024     /// Class to create Geant4 detector geometry from TGeo representation in memory
0025     /**
0026      *  On demand (ie. when calling "Construct") the dd4hep geometry is converted
0027      *  to Geant4 with all volumes, assemblies, shapes, materials etc.
0028      *  The actuak work is performed by the Geant4Converter class called by this method.
0029      *
0030      *  \author  M.Frank
0031      *  \version 1.0
0032      *  \ingroup DD4HEP_SIMULATION
0033      */
0034     class Geant4DetectorGeometryConstruction : public Geant4DetectorConstruction   {
0035       /// Property: Dump geometry hierarchy if not NULL. Flags can steer actions. 
0036       unsigned long m_dumpHierarchy {     0 };
0037       /// Property: Flag to debug G4 volume manager population
0038       long m_debugVolManager            { 0 };
0039       /// Property: Flag to instantiate Geant4 volume manager
0040       bool m_haveVolManager         {  true };
0041       /// Property: Flag to debug materials during conversion mechanism
0042       bool m_debugMaterials         { false };
0043       /// Property: Flag to debug elements during conversion mechanism
0044       bool m_debugElements          { false };
0045       /// Property: Flag to debug shapes during conversion mechanism
0046       bool m_debugShapes            { false };
0047       /// Property: Flag to debug volumes during conversion mechanism
0048       bool m_debugVolumes           { false };
0049       /// Property: Flag to debug placements during conversion mechanism
0050       bool m_debugPlacements        { false };
0051       /// Property: Flag to debug reflections during conversion mechanism
0052       bool m_debugReflections       { false };
0053       /// Property: Flag to debug regions during conversion mechanism
0054       bool m_debugRegions           { false };
0055       /// Property: Flag to debug limit sets during conversion mechanism
0056       bool m_debugLimits            { false };
0057       /// Property: Flag to debug regions during conversion mechanism
0058       bool m_debugSurfaces          { false };
0059 
0060       /// Property: Flag to dump all placements after the conversion procedure
0061       bool m_printPlacements        { false };
0062       /// Property: Flag to dump all sensitives after the conversion procedure
0063       bool m_printSensitives        { false };
0064 
0065       /// Property: Printout level of info object
0066       int  m_geoInfoPrintLevel;
0067       /// Property: G4 GDML dump file name (default: empty. If non empty, dump)
0068       std::string m_dumpGDML;
0069 
0070       /// Write GDML file
0071       int writeGDML(const char* gdml_output);
0072       /// Print geant4 volume 
0073       int printVolumeObj(const char* vol_path, PlacedVolume pv, int flg);
0074       /// Print volume tree with attributes
0075       int printVolumeTree(const char* vol_path);
0076       /// Print volume tree WITHOUT attributes
0077       int printVolTree(const char* vol_path);
0078       /// Print geant4 volume tree
0079       int printG4Tree(const char* vol_path);
0080       /// Print geant4 volume
0081       int printVolume(const char* vol_path);
0082       /// Check geant4 volume
0083       int checkVolume(const char* vol_path);
0084       /// Print geant4 material
0085       int printMaterial(const char* mat_name);
0086 
0087       std::pair<std::string, PlacedVolume> resolve_path(const char* vol_path)   const;
0088       void printG4(const std::string& prefix, const G4VPhysicalVolume* g4pv)  const;
0089 
0090     public:
0091       /// Initializing constructor for DDG4
0092       Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const std::string& nam);
0093       /// Default destructor
0094       virtual ~Geant4DetectorGeometryConstruction();
0095       /// Geometry construction callback. Called at "Construct()"
0096       void constructGeo(Geant4DetectorConstructionContext* ctxt)  override;
0097       /// Install command control messenger to write GDML file from command prompt.
0098       virtual void installCommandMessenger()   override;
0099     };
0100   }    // End namespace sim
0101 }      // End namespace dd4hep
0102 
0103 
0104 // Framework include files
0105 #include <DD4hep/InstanceCount.h>
0106 #include <DD4hep/DetectorTools.h>
0107 #include <DD4hep/DD4hepUnits.h>
0108 #include <DD4hep/Printout.h>
0109 #include <DD4hep/Detector.h>
0110 
0111 #include <DDG4/Geant4HierarchyDump.h>
0112 #include <DDG4/Geant4UIMessenger.h>
0113 #include <DDG4/Geant4Converter.h>
0114 #include <DDG4/Geant4Kernel.h>
0115 #include <DDG4/Factories.h>
0116 
0117 #include <TGeoScaledShape.h>
0118 
0119 // Geant4 include files
0120 #include <G4LogicalVolume.hh>
0121 #include <G4PVPlacement.hh>
0122 #include <G4Material.hh>
0123 #include <G4Version.hh>
0124 #include <G4VSolid.hh>
0125 #include <CLHEP/Units/SystemOfUnits.h>
0126 
0127 #ifndef GEANT4_NO_GDML
0128 #include <G4GDMLParser.hh>
0129 #endif
0130 
0131 #include <cmath>
0132 
0133 using namespace dd4hep::sim;
0134 DECLARE_GEANT4ACTION(Geant4DetectorGeometryConstruction)
0135 
0136 /// Initializing constructor for other clients
0137 Geant4DetectorGeometryConstruction::Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const std::string& nam)
0138 : Geant4DetectorConstruction(ctxt,nam)
0139 {
0140   declareProperty("DebugMaterials",    m_debugMaterials);
0141   declareProperty("DebugElements",     m_debugElements);
0142   declareProperty("DebugShapes",       m_debugShapes);
0143   declareProperty("DebugVolumes",      m_debugVolumes);
0144   declareProperty("DebugPlacements",   m_debugPlacements);
0145   declareProperty("DebugReflections",  m_debugReflections);
0146   declareProperty("DebugRegions",      m_debugRegions);
0147   declareProperty("DebugLimits",       m_debugLimits);
0148   declareProperty("DebugSurfaces",     m_debugSurfaces);
0149   declareProperty("DebugVolManager",   m_debugVolManager);
0150   declareProperty("HaveVolManager",    m_haveVolManager);
0151 
0152   declareProperty("PrintPlacements",   m_printPlacements);
0153   declareProperty("PrintSensitives",   m_printSensitives);
0154   declareProperty("GeoInfoPrintLevel", m_geoInfoPrintLevel = DEBUG);
0155 
0156   declareProperty("DumpHierarchy",     m_dumpHierarchy);
0157   declareProperty("DumpGDML",          m_dumpGDML="");
0158   InstanceCount::increment(this);
0159 }
0160 
0161 /// Default destructor
0162 Geant4DetectorGeometryConstruction::~Geant4DetectorGeometryConstruction() {
0163   InstanceCount::decrement(this);
0164 }
0165 
0166 /// Geometry construction callback. Called at "Construct()"
0167 void Geant4DetectorGeometryConstruction::constructGeo(Geant4DetectorConstructionContext* ctxt)   {
0168   Geant4Mapping&  g4map = Geant4Mapping::instance();
0169   DetElement      world = ctxt->description.world();
0170   Geant4Converter conv(ctxt->description, outputLevel());
0171   conv.debugMaterials   = m_debugMaterials;
0172   conv.debugElements    = m_debugElements;
0173   conv.debugShapes      = m_debugShapes;
0174   conv.debugVolumes     = m_debugVolumes;
0175   conv.debugRegions     = m_debugRegions;
0176   conv.debugSurfaces    = m_debugSurfaces;
0177   conv.debugPlacements  = m_debugPlacements;
0178   conv.debugReflections = m_debugReflections;
0179   conv.debugLimits      = m_debugLimits;
0180   conv.printPlacements  = m_printPlacements;
0181   conv.printSensitives  = m_printSensitives;
0182 
0183   ctxt->geometry = conv.create(world).detach();
0184   ctxt->geometry->printLevel = outputLevel();
0185   g4map.attach(ctxt->geometry);
0186   G4VPhysicalVolume* w = ctxt->geometry->world();
0187   // Save away the reference to the world volume
0188   context()->kernel().setWorld(w);
0189   // Create Geant4 volume manager only if not yet available
0190   g4map.debugVolManager = m_debugVolManager;
0191   g4map.haveVolManager  = m_haveVolManager;
0192   if( m_haveVolManager )  {
0193     g4map.volumeManager();
0194   }
0195   if ( m_dumpHierarchy != 0 )   {
0196     Geant4HierarchyDump dmp(ctxt->description, m_dumpHierarchy);
0197     dmp.dump("",w);
0198   }
0199   ctxt->world = w;
0200   if ( !m_dumpGDML.empty() ) writeGDML(m_dumpGDML.c_str());
0201   else if ( ::getenv("DUMP_GDML") ) writeGDML(::getenv("DUMP_GDML"));
0202   enableUI();
0203 }
0204 
0205 std::pair<std::string, dd4hep::PlacedVolume>
0206 Geant4DetectorGeometryConstruction::resolve_path(const char* vol_path)  const {
0207   std::string  p   = vol_path;
0208   Detector&    det = context()->kernel().detectorDescription();
0209   PlacedVolume top = det.world().placement();
0210   PlacedVolume pv  = detail::tools::findNode(top, p);
0211   if ( !pv.isValid() )    {
0212     DetElement de = detail::tools::findElement(det, p);
0213     if ( de.isValid() )  {
0214       pv = de.placement();
0215       p = detail::tools::placementPath(de);
0216     }
0217   }
0218   return make_pair(p,pv);
0219 }
0220 
0221 /// Print geant4 material
0222 int Geant4DetectorGeometryConstruction::printMaterial(const char* mat_name)  {
0223   if ( mat_name )   {
0224     auto& g4map = Geant4Mapping::instance().data().g4Materials;
0225     for ( auto it = g4map.begin(); it != g4map.end(); ++it )  {
0226       const auto* mat = (*it).second;
0227       if ( mat->GetName() == mat_name )   {
0228         std::stringstream output;
0229         const auto* ion = mat->GetIonisation();
0230         printP2("+++  Dump of GEANT4 material: %s", mat_name);
0231         output << mat;
0232         if ( ion )   {
0233           output << "          MEE:  ";
0234           output << std::setprecision(12);
0235           output << ion->GetMeanExcitationEnergy()/CLHEP::eV;
0236           output << " [eV]";
0237         }
0238         else
0239           output << "          MEE: UNKNOWN";
0240         always("+++ printMaterial: \n%s\n", output.str().c_str());
0241         return 1;
0242       }
0243     }
0244     warning("+++ printMaterial: FAILED to find the material %s", mat_name);
0245   }
0246   warning("+++ printMaterial: Property materialName not set!");
0247   return 0;
0248 }
0249 
0250 /// Print geant4 volume
0251 int Geant4DetectorGeometryConstruction::printVolumeObj(const char* vol_path, PlacedVolume pv, int flg)   {
0252   if ( pv.isValid() )   {
0253     const G4LogicalVolume* vol = 0;
0254     auto& g4map = Geant4Mapping::instance().data();
0255     auto pit = g4map.g4Placements.find(pv.ptr());
0256     auto vit = g4map.g4Volumes.find(pv.volume());
0257     warning("+++ printVolume: %s", vol_path);
0258     if ( vit != g4map.g4Volumes.end() )   {
0259       vol = (*vit).second;
0260       auto* sol = vol->GetSolid();
0261       const auto* mat = vol->GetMaterial();
0262       const auto* ion = mat->GetIonisation();
0263       Solid sh  = pv.volume().solid();
0264       if ( flg )  {
0265         printP2("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
0266         printP2("+++  Dump of GEANT4 solid: %s", vol_path);
0267       }
0268       std::stringstream output;
0269       if ( flg )   {
0270         output << mat;
0271         if ( ion )   {
0272           output << "          MEE:  ";
0273           output << std::setprecision(12);
0274           output << ion->GetMeanExcitationEnergy()/CLHEP::eV;
0275           output << " [eV]";
0276         }
0277         else
0278           output << "          MEE: UNKNOWN";
0279       }
0280       if ( flg )   {
0281         output << std::endl << *sol;
0282         printP2("%s", output.str().c_str());
0283         printP2("+++  Dump of ROOT   solid: %s", vol_path);
0284         sh->InspectShape();
0285         if ( sh->IsA() == TGeoScaledShape::Class() )    {
0286           TGeoScaledShape* scaled = (TGeoScaledShape*)sh.ptr();
0287           const Double_t* scale = scaled->GetScale()->GetScale();
0288           double dot = scale[0]*scale[1]*scale[2];
0289           printP2("+++ TGeoScaledShape: %8.3g  %8.3g  %8.3g  [%s]", scale[0], scale[1], scale[2],
0290                   dot > 0e0 ? "RIGHT handed" : "LEFT handed");
0291         }
0292         else if ( pit != g4map.g4Placements.end() )   {
0293           const G4VPhysicalVolume* pl = (*pit).second;
0294           const G4RotationMatrix* rot = pl->GetRotation();
0295           const G4ThreeVector& tr = pl->GetTranslation();
0296           G4Transform3D transform(rot ? *rot : G4RotationMatrix(), tr);
0297           HepGeom::Scale3D  sc;
0298           HepGeom::Rotate3D rr;
0299           G4Translate3D     tt;
0300           transform.getDecomposition(sc,rr,tt);
0301           double dot = sc(0,0)*sc(1,1)*sc(2,2);
0302           printP2("+++ TGeoShape:       %8.3g  %8.3g  %8.3g  [%s]", sc(0,0), sc(1,1), sc(2,2),
0303                   dot > 0e0 ? "RIGHT handed" : "LEFT handed");
0304         }
0305         const TGeoMatrix* matrix = pv->GetMatrix();
0306         printP2("+++ TGeoMatrix:      %s",
0307                 matrix->TestBit(TGeoMatrix::kGeoReflection) ? "LEFT handed" : "RIGHT handed");        
0308         printP2("+++ Shape: %s  cubic volume: %8.3g mm^3  area: %8.3g mm^2",
0309                 sol->GetName().c_str(), sol->GetCubicVolume(), sol->GetSurfaceArea());
0310       }
0311       return 1;
0312     }
0313     else   {
0314       auto ai = g4map.g4AssemblyVolumes.find(pv.ptr());
0315       if ( ai != g4map.g4AssemblyVolumes.end() )   {
0316         Volume v = pv.volume();
0317         warning("+++ printVolume: volume %s is an assembly...need to resolve imprint",vol_path);
0318         for(Int_t i=0; i < v->GetNdaughters(); ++i)   {
0319           TGeoNode*   dau_nod = v->GetNode(i);
0320           std::string p = vol_path + std::string("/") + dau_nod->GetName();
0321           printVolumeObj(p.c_str(), dau_nod, flg);
0322         }
0323         return 0;
0324       }
0325     }
0326     warning("+++ printVolume: FAILED to find the volume %s in geant4 mapping...",vol_path);
0327     return 0;
0328   }
0329   warning("+++ printVolume: FAILED to dump invalid volume",vol_path);
0330   return 0;
0331 }
0332 
0333 /// Print geant4 volume
0334 int Geant4DetectorGeometryConstruction::printVolume(const char* vol_path)  {
0335   if ( vol_path )   {
0336     auto physVol = resolve_path(vol_path);
0337     if ( physVol.second.isValid() )    {
0338       return printVolumeObj(vol_path, physVol.second, ~0x0);
0339     }
0340   }
0341   warning("+++ printVolume: Property VolumePath not set. [Ignored]");
0342   return 0;
0343 }
0344 
0345 /// Print geant4 volume
0346 int Geant4DetectorGeometryConstruction::printVolumeTree(const char* vol_path)  {
0347   if ( vol_path )   {
0348     auto [p, pv] = resolve_path(vol_path);
0349     if ( pv.isValid() )    {
0350       if ( printVolumeObj(p.c_str(), pv, ~0x0) )     {
0351         TGeoVolume* vol = pv->GetVolume();
0352         for(Int_t i=0; i < vol->GetNdaughters(); ++i)   {
0353           PlacedVolume dau_pv(vol->GetNode(i));
0354           std::string path = (p + "/") + dau_pv.name();
0355           if ( printVolumeTree(path.c_str()) )     {
0356           }
0357         }
0358       }
0359       return 1;
0360     }
0361   }
0362   warning("+++ printVolume: Could not access Volume/DetElement '%s'", vol_path ? vol_path : "UNKNOWN");
0363   return 0;
0364 }
0365 
0366 int Geant4DetectorGeometryConstruction::printVolTree(const char* vol_path)  {
0367   if ( vol_path )   {
0368     auto [p, pv] = resolve_path(vol_path);
0369     if ( pv.isValid() )    {
0370       if ( printVolumeObj(p.c_str(), pv, 0) )     {
0371         TGeoVolume* vol = pv->GetVolume();
0372         for(Int_t i=0; i < vol->GetNdaughters(); ++i)   {
0373           PlacedVolume dau_pv(vol->GetNode(i));
0374           std::string path = (p + "/") + dau_pv.name();
0375           if ( printVolTree(path.c_str()) )     {
0376           }
0377         }
0378       }
0379       return 1;
0380     }
0381   }
0382   warning("+++ printVolume: Could not access Volume/DetElement '%s'", vol_path ? vol_path : "UNKNOWN");
0383   return 0;
0384 }
0385 
0386 /// Check geant4 volume
0387 int Geant4DetectorGeometryConstruction::checkVolume(const char* vol_path)  {
0388   if ( vol_path )   {
0389     auto physVol = resolve_path(vol_path);
0390     auto pv = physVol.second;
0391     if ( pv.isValid() )   {
0392       auto& g4map = Geant4Mapping::instance().data().g4Volumes;
0393       auto it = g4map.find(pv.volume());
0394       if ( it != g4map.end() )   {
0395         const G4LogicalVolume* vol = (*it).second;
0396         auto* g4_sol = vol->GetSolid();
0397         Box   rt_sol = pv.volume().solid();
0398         printP2("Geant4 Shape: %s  cubic volume: %8.3g mm^3  area: %8.3g mm^2",
0399                 g4_sol->GetName().c_str(), g4_sol->GetCubicVolume(), g4_sol->GetSurfaceArea());
0400 #if G4VERSION_NUMBER>=1040
0401         G4ThreeVector pMin, pMax;
0402         double conv = (dd4hep::centimeter/CLHEP::centimeter)/2.0;
0403         g4_sol->BoundingLimits(pMin,pMax);
0404         printP2("Geant4 Bounding box extends:    %8.3g  %8.3g %8.3g",
0405                 (pMax.x()-pMin.x())*conv, (pMax.y()-pMin.y())*conv, (pMax.z()-pMin.z())*conv);
0406 #endif
0407         printP2("ROOT   Bounding box dimensions: %8.3g  %8.3g %8.3g",
0408                 rt_sol->GetDX(), rt_sol->GetDY(), rt_sol->GetDZ());
0409         
0410         return 1;
0411       }
0412     }
0413     warning("+++ checkVolume: FAILED to find the volume %s from the top volume",vol_path);
0414   }
0415   warning("+++ checkVolume: Property VolumePath not set. [Ignored]");
0416   return 0;
0417 }
0418 
0419 /// Write GDML file
0420 int Geant4DetectorGeometryConstruction::writeGDML(const char* output)  {
0421 #ifdef GEANT4_NO_GDML
0422   warning("+++ writeGDML: GDML not found in the present Geant4 build! Output: %s not written", output);
0423 #else
0424   G4VPhysicalVolume* w  = context()->world();
0425   if ( output && ::strlen(output) > 0 && output != m_dumpGDML.c_str() )
0426     m_dumpGDML = output;
0427 
0428   if ( !m_dumpGDML.empty() ) {
0429     G4GDMLParser parser;
0430     parser.Write(m_dumpGDML.c_str(), w);
0431     info("+++ writeGDML: Wrote GDML file: %s", m_dumpGDML.c_str());
0432     return 1;
0433   }
0434   else {
0435     const char* gdml_dmp = ::getenv("DUMP_GDML");
0436     if ( gdml_dmp )    {
0437       G4GDMLParser parser;
0438       parser.Write(gdml_dmp, w);
0439       info("+++ writeGDML: Wrote GDML file: %s", gdml_dmp);
0440       return 1;
0441     }
0442   }
0443   warning("+++ writeGDML: Neither property DumpGDML nor environment DUMP_GDML set. No file written!");
0444 #endif
0445   return 0;
0446 }
0447 
0448 void Geant4DetectorGeometryConstruction::printG4(const std::string& prefix, const G4VPhysicalVolume* g4pv)    const   {
0449   std::string path = prefix + "/";
0450   printP2("+++  GEANT4 volume: %s", prefix.c_str());
0451   auto* g4v = g4pv->GetLogicalVolume();
0452   for(size_t i=0, n=g4v->GetNoDaughters(); i<n; ++i)    {
0453     auto* dau = g4v->GetDaughter(i);
0454     printG4(path + dau->GetName(), dau);
0455   }
0456 }
0457 
0458 int Geant4DetectorGeometryConstruction::printG4Tree(const char* vol_path)  {
0459   if ( vol_path )   {
0460     auto [p, pv] = resolve_path(vol_path);
0461     if ( pv.isValid() )    {
0462       auto& g4map = Geant4Mapping::instance().data().g4Placements;
0463       auto it = g4map.find(pv);
0464       if ( it != g4map.end() )   {
0465         printG4(p, (*it).second);
0466       }
0467       return 1;
0468     }
0469   }
0470   warning("+++ printVolume: Could not access Volume/DetElement '%s'", vol_path ? vol_path : "UNKNOWN");
0471   return 0;
0472 }
0473 
0474 /// Install command control messenger to write GDML file from command prompt.
0475 void Geant4DetectorGeometryConstruction::installCommandMessenger()   {
0476   this->Geant4DetectorConstruction::installCommandMessenger();
0477   m_control->addCall("writeGDML", "GDML: write geometry to file: '"+m_dumpGDML+
0478                      "' [uses argument - or - property DumpGDML]",
0479                      Callback(this).make(&Geant4DetectorGeometryConstruction::writeGDML),1);
0480   m_control->addCall("printVolume", "Print Geant4 volume properties [uses argument]",
0481                      Callback(this).make(&Geant4DetectorGeometryConstruction::printVolume),1);
0482   m_control->addCall("printTree",   "Print volume tree WITHOUT properties [uses argument]",
0483                      Callback(this).make(&Geant4DetectorGeometryConstruction::printVolTree),1);
0484   m_control->addCall("printG4Tree",   "Print Geant4 volume tree [uses argument]",
0485                      Callback(this).make(&Geant4DetectorGeometryConstruction::printG4Tree),1);
0486   m_control->addCall("printVolumeTree", "Print volume tree with properties [uses argument]",
0487                      Callback(this).make(&Geant4DetectorGeometryConstruction::printVolumeTree),1);
0488   m_control->addCall("checkVolume", "Check Geant4 volume properties [uses argument]",
0489                      Callback(this).make(&Geant4DetectorGeometryConstruction::checkVolume),1);
0490   m_control->addCall("printMaterial", "Print Geant4 material properties [uses argument]",
0491                      Callback(this).make(&Geant4DetectorGeometryConstruction::printMaterial),1);
0492 }