26 #include <G4VTouchable.hh>
27 #include <G4LogicalVolume.hh>
28 #include <G4VPhysicalVolume.hh>
34 #include <unordered_map>
40 #ifdef VOLMGR_HAVE_DEBUG_INFO
46 class Geant4GeometryInfo::DebugInfo {
48 typedef std::vector<const G4VPhysicalVolume*> Geant4PlacementPath;
49 std::map<Geant4PlacementPath, Placement>
g4Paths;
71 using VolIDDescriptor = std::pair<VolumeID,std::vector<std::pair<const BitFieldElement*, VolumeID> > >;
83 typedef std::vector<const TGeoNode*> Chain;
85 typedef std::set<VolumeID> Registries;
96 std::unordered_map<TGeoVolume*, bool> m_has_sensitive;
100 : m_detDesc(description), m_geo(g), m_debug(dbg)
102 #ifdef VOLMGR_HAVE_DEBUG_INFO
104 g.
g4DebugInfo =
new Geant4GeometryInfo::DebugInfo();
110 #ifdef VOLMGR_HAVE_DEBUG_INFO
123 for(
const auto& i : children ) {
132 scanPhysicalVolume(pv.
ptr(), ids, sd, chain);
135 printout(WARNING,
"Geant4VolumeManager",
136 "++ Detector element %s of type %s has no placement.",
141 if( pv.second->IsParameterised() )
143 if( pv.second->IsReplicated() )
151 bool hasSensitiveContent(TGeoVolume* vol) {
152 auto [it, inserted] = m_has_sensitive.emplace(vol,
false);
153 if ( !inserted )
return it->second;
154 if (
Volume(vol).isSensitive() )
return it->second =
true;
155 for ( Int_t i = 0, n = vol->GetNdaughters(); i < n; ++i ) {
156 TGeoNode* dau = vol->GetNode(i);
157 if (
PlacedVolume(dau).data() && hasSensitiveContent(dau->GetVolume()) )
158 return it->second =
true;
169 chain.emplace_back(node);
170 const std::size_t ids_save = ids.size();
171 ids.PlacedVolume::VolIDs::Base::insert(ids.end(), pv_ids.begin(), pv_ids.end());
175 add_entry(sd, node, ids, chain);
178 printout(WARNING,
"Geant4VolumeManager",
179 "populate: Strange constellation volume %s is sensitive, but has no readout! sd:%p", pv.
volume().
name(),
183 for( Int_t idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau ) {
184 TGeoNode* daughter = node->GetDaughter(idau);
186 if( placement.
data() && hasSensitiveContent(daughter->GetVolume()) ) {
187 scanPhysicalVolume(daughter, ids, sd, chain);
190 ids.resize(ids_save);
205 Registries::const_iterator i = m_entries.find(code);
207 printout(print_action,
"Geant4VolumeManager",
"+++ Add path:%s vid:%016X",
210 if( i == m_entries.end() ) {
211 path.reserve(nodes.size());
212 for( Chain::const_reverse_iterator k = nodes.rbegin(), kend=nodes.rend(); k != kend; ++k ) {
213 const TGeoNode* node = *(k);
216 G4VPhysicalVolume* phys = g4pit->second;
217 if( phys->IsParameterised() ) {
224 path.emplace_back(phys);
225 printout(print_chain,
"Geant4VolumeManager",
226 "+++ Chain: Node OK: %s [%s]", node->GetName(), phys->GetName().c_str());
229 control.insert(control.begin(),node);
230 vol =
Volume(node->GetVolume());
233 for(
const auto& imp : iVolImp->second ) {
234 const auto& c = imp.first;
235 if ( c.size() <= control.size() && control == c ) {
236 path.emplace_back(imp.second);
237 printout(print_chain,
"Geant4VolumeManager",
"+++ Chain: Node OK: %s %s -> %s",
239 imp.second->GetName().c_str());
246 if ( control.empty() ) {
247 printout(print_res,
"Geant4VolumeManager",
"+++ Encoded Volume IDs:%s",
249 path.erase(path.begin()+path.size()-1);
250 printout(print_res,
"Geant4VolumeManager",
"+++ Map %016X to Geant4 Path:%s",
252 auto hash = detail::hash64(&path[0], path.size()*
sizeof(path[0]));
254 #ifdef VOLMGR_HAVE_DEBUG_INFO
257 if ( missing_real_path != missing_hash_path ) {
260 if ( !nodes.empty() )
264 if ( missing_real_path ) {
272 if ( missing_hash_path ) {
278 std::string idstr = iddesc.
str(code);
279 printout(ALWAYS,
"Geant4VolumeManager",
280 "+++ Decoded Volume IDs: %016llX -> %s", code, idstr.c_str());
282 m_entries.emplace(code);
286 if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) ) {
289 printout(ERROR,
"Geant4VolumeManager",
"populate: Severe error: Duplicated Geant4 path!!!! %s %s",
293 printout(INFO,
"Geant4VolumeManager",
"Control block has still %d entries:%s",
300 if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) ) {
304 printout(ERROR,
"Geant4VolumeManager",
"populate: Severe error: Duplicated Volume entry: 0x%X"
305 " [THIS SHOULD NEVER HAPPEN]", code);
308 if ( i != m_entries.end() )
312 if ( !nodes.empty() ) {
315 std::string node_path;
316 for( std::size_t in=0; in<nodes.size(); ++in ) {
319 node_path += pv.
name();
320 printout( ALWAYS,
"Geant4VolumeManager",
" TGeo Node[%ld]: %s [%p] Volids: '%s'",
321 in, node_path.c_str(), (
void*)nodes[in], pv.
volIDs().
str().c_str() );
325 printout( ERROR,
"Geant4VolumeManager",
" Offend.VolIDs: %s",
detail::tools::toString(iddesc,ids,code).c_str() );
326 throw std::runtime_error(
"Failed to populate Geant4 volume manager!");
335 if( !
info->has_volmgr ) {
337 printout( ALWAYS,
"Geant4VolumeManager",
"+++ Populating Geant4 volume manager.");
338 p.populate(description.
world());
339 printout( ALWAYS,
"Geant4VolumeManager",
340 "+++ Geant4 volume manager populated with %ld sensitive path entries.",
341 info->g4Paths.size() );
345 for(
auto it=
info->g4Paths.begin(); it !=
info->g4Paths.end(); ++it, ++count ) {
346 VolumeID volid = it->second.volumeID;
352 std::string idstr = sens.
idSpec().
str(volid);
353 printout( ALWAYS,
"Geant4VolumeManager",
"%8d: %016X %s -> %s",
354 count, volid, path.c_str(), plac.
name());
355 printout(ALWAYS,
"Geant4VolumeManager",
"%8s %16s %s",
"",
"", idstr.c_str());
358 printout( ERROR,
"Geant4VolumeManager",
359 "Missing volume manager entry: volume ID %016X", volid);
363 info->has_volmgr =
true;
367 except(
"Geant4VolumeManager",
"Attempt populate from invalid Geant4 geometry info [Invalid-Info]");
371 std::vector<const G4VPhysicalVolume*>
380 except(
"Geant4VolumeManager",
"Attempt to use invalid Geant4 volume manager [Invalid-Handle]");
383 except(
"Geant4VolumeManager",
"Attempt to use invalid Geant4 geometry info [Invalid-Info]");
391 auto* p = mgr->
ptr();
393 ::snprintf(text,
sizeof(text),
"==> #path entries: %ld valid: %s has_volmgr: %s",
394 p->g4Paths.size(), yes_no(p->valid), yes_no(p->has_volmgr));
397 return {
"Invalid handle to Geant4GeometryInfo" };
404 std::vector<const G4VPhysicalVolume*> path = handler.
placementPath();
406 printout(INFO,
"Geant4VolumeManager",
"+++ INVALID Geant4VolumeManager handle.");
410 printout(INFO,
"Geant4VolumeManager",
"+++ INVALID Geant4VolumeManager [Not initialized]");
413 else if( path.empty() ) {
414 printout(INFO,
"Geant4VolumeManager",
"+++ EMPTY volume Geant4 Path: %s",
419 uint64_t
hash = detail::hash64(&path[0],
sizeof(path[0])*path.size());
420 auto i =
ptr()->g4Paths.find(
hash);
421 if( i !=
ptr()->g4Paths.end() ) {
422 const auto& e = (*i).second;
428 const auto& paramterised =
ptr()->g4Parameterised;
429 const auto& replicated =
ptr()->g4Replicated;
431 for( std::size_t j=0; j < path.size(); ++j ) {
432 const auto* phys = path[j];
433 if( phys->IsParameterised() ) {
434 int copy_no = touchable->GetCopyNumber(j);
435 const auto it = paramterised.find(phys);
436 if( it != paramterised.end() ) {
439 const auto* field = (*it).second.data()->params->field;
443 except(
"Geant4VolumeManager",
444 "Error Geant4VolumeManager::volumeID(const G4VTouchable* touchable)");
446 else if( phys->IsReplicated() ) {
447 int copy_no = touchable->GetCopyNumber(j);
448 const auto it = replicated.find(phys);
449 if( it != replicated.end() ) {
450 const auto* field = (*it).second.data()->params->field;
454 except(
"Geant4VolumeManager",
455 "Error Geant4VolumeManager::volumeID(const G4VTouchable* touchable)");
461 printout(INFO,
"Geant4VolumeManager",
"+++ Bad Geant4 volume path: \'%s\' [invalid path] %s",
465 else if( !path[0]->GetLogicalVolume()->GetSensitiveDetector() ) {
466 printout(DEBUG,
"Geant4VolumeManager",
"+++ Bad Geant4 volume path: \'%s\' [insensitive] %s",
470 printout(INFO,
"Geant4VolumeManager",
471 "+++ Bad Geant4 volume path: \'%s\' [missing entry] %s",
475 printout(INFO,
"Geant4VolumeManager",
"+++ Bad Geant4 volume path: \'%s\' %s",
484 vol_desc.second.clear();
487 auto hash = detail::hash64(&path[0],
sizeof(path[0])*path.size());
488 auto i =
ptr()->g4Paths.find(
hash);
489 if( i !=
ptr()->g4Paths.end() ) {
490 VolumeID vid = (*i).second.volumeID;
491 G4LogicalVolume* lvol = path[0]->GetLogicalVolume();
492 if( lvol->GetSensitiveDetector() ) {
493 const auto* node = path[0];
494 const auto& pm =
ptr()->g4Placements;
495 for(
const auto& ipm : pm ) {
496 if ( ipm.second == node ) {
500 vol_desc.first = vid;
511 else if( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )