diff --git a/src/g4integration/geometry/AdePTGeometryBridge.cpp b/src/g4integration/geometry/AdePTGeometryBridge.cpp index 5f276a63..f7ad6e23 100644 --- a/src/g4integration/geometry/AdePTGeometryBridge.cpp +++ b/src/g4integration/geometry/AdePTGeometryBridge.cpp @@ -432,6 +432,21 @@ void AdePTGeometryBridge::InitVolAuxData(adeptint::VolAuxData *volAuxData, G4Hep vecgeom::NavigationState rootNavState; visitGeometry(g4world, vecgeomWorld, rootNavState); + // Defensive check for attached SD code: GetSensitiveDetector() is thread local. + // If the GPU geometry is initialized on a thread without SD code attached, issue a warning. + { + const std::size_t nLVs = vecgeom::GeoManager::Instance().GetRegisteredVolumesCount(); + std::size_t nSensitive = 0; + for (std::size_t i = 0; i < nLVs; ++i) { + if (volAuxData[i].fSensIndex >= 0) ++nSensitive; + } + if (nSensitive == 0) { + G4Exception("AdePTGeometryBridge::InitVolAuxData", "NoSensitiveVolumes", JustWarning, + "No logical volume is marked sensitive: AdePT was likely initialized on a thread without attached " + "sensitive detectors; GPU energy deposits will not be scored."); + } + } + auto findRegionName = [](int rid) -> std::string { for (auto *r : *G4RegionStore::GetInstance()) { if (r && r->GetInstanceID() == rid) return r->GetName(); diff --git a/src/g4integration/tracking_managers/AdePTTrackingManager.cc b/src/g4integration/tracking_managers/AdePTTrackingManager.cc index e63f7cf5..87144747 100644 --- a/src/g4integration/tracking_managers/AdePTTrackingManager.cc +++ b/src/g4integration/tracking_managers/AdePTTrackingManager.cc @@ -247,10 +247,13 @@ void AdePTTrackingManager::InitializeAdePT() { auto tid = G4Threading::G4GetThreadId(); - // Master thread cannot initialize AdePT as the number of G4 worker threads may not yet be known in applications. + // Master thread must not initialize AdePT as the number of G4 worker threads may not yet be known in applications. + // Also sensitive detectors are attached per worker thread and may be missed on the master. // In sequential mode, the tid is -2 in most builds, but some sequential Geant4 builds return MASTER_ID (-1). - // Use GetMasterRunManager() to distinguish an actual MT master thread from sequential mode. - if (tid == G4Threading::MASTER_ID && G4MTRunManager::GetMasterRunManager() != nullptr) return; + // G4MTRunManager::GetMasterRunManager() cannot be used to detect an MT master: applications like CMSSW + // drive a G4MTRunManagerKernel directly without ever creating a G4MTRunManager. IsMultithreadedApplication() + // is set by the G4MTRunManagerKernel constructor and therefore covers both cases. + if (tid == G4Threading::MASTER_ID && G4Threading::IsMultithreadedApplication()) return; // a condition variable and a mutex is used for the initialization: // The first G4 worker that reaches the initialization, needs to initialize AdePT.