File indexing completed on 2026-09-12 08:24:28
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <DDG4/Geant4DetectorConstruction.h>
0017
0018
0019 namespace dd4hep {
0020
0021
0022 namespace sim {
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 class Geant4DetectorGeometryConstruction : public Geant4DetectorConstruction {
0035
0036 unsigned long m_dumpHierarchy { 0 };
0037
0038 long m_debugVolManager { 0 };
0039
0040 bool m_haveVolManager { true };
0041
0042 bool m_debugMaterials { false };
0043
0044 bool m_debugElements { false };
0045
0046 bool m_debugShapes { false };
0047
0048 bool m_debugVolumes { false };
0049
0050 bool m_debugPlacements { false };
0051
0052 bool m_debugReflections { false };
0053
0054 bool m_debugRegions { false };
0055
0056 bool m_debugLimits { false };
0057
0058 bool m_debugSurfaces { false };
0059
0060
0061 bool m_printPlacements { false };
0062
0063 bool m_printSensitives { false };
0064
0065
0066 int m_geoInfoPrintLevel;
0067
0068 std::string m_dumpGDML;
0069
0070
0071 int writeGDML(const char* gdml_output);
0072
0073 int printVolumeObj(const char* vol_path, PlacedVolume pv, int flg);
0074
0075 int printVolumeTree(const char* vol_path);
0076
0077 int printVolTree(const char* vol_path);
0078
0079 int printG4Tree(const char* vol_path);
0080
0081 int printVolume(const char* vol_path);
0082
0083 int checkVolume(const char* vol_path);
0084
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
0092 Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const std::string& nam);
0093
0094 virtual ~Geant4DetectorGeometryConstruction();
0095
0096 void constructGeo(Geant4DetectorConstructionContext* ctxt) override;
0097
0098 virtual void installCommandMessenger() override;
0099 };
0100 }
0101 }
0102
0103
0104
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
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
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
0162 Geant4DetectorGeometryConstruction::~Geant4DetectorGeometryConstruction() {
0163 InstanceCount::decrement(this);
0164 }
0165
0166
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
0188 context()->kernel().setWorld(w);
0189
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
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
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
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
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
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
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
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 }