Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:14:19

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