DD4hep  1.30.0
Detector Description Toolkit for High Energy Physics
Geant4VolumeManager.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // Author : M.Frank
11 //
12 //==========================================================================
13 
14 // Framework include files
15 #include <DD4hep/Printout.h>
16 #include <DD4hep/Volumes.h>
17 #include <DD4hep/DetElement.h>
18 #include <DD4hep/DetectorTools.h>
21 #include <DDG4/Geant4Mapping.h>
22 
23 // Geant4 include files
24 #include <G4VTouchable.hh>
25 #include <G4LogicalVolume.hh>
26 #include <G4VPhysicalVolume.hh>
27 
28 // C/C++ include files
29 #include <sstream>
30 
31 using namespace dd4hep::sim;
32 using namespace dd4hep;
33 
35 using VolIDDescriptor = std::pair<VolumeID,std::vector<std::pair<const BitFieldElement*, VolumeID> > >;
36 
37 namespace {
38 
40  struct Populator {
41 
42  typedef std::vector<const TGeoNode*> Chain;
43  typedef std::map<VolumeID,Geant4GeometryInfo::Geant4PlacementPath> Registries;
44 
46  const Detector& m_detDesc;
48  Registries m_entries;
50  Geant4GeometryInfo& m_geo;
51 
53  Populator(const Detector& description, Geant4GeometryInfo& g)
54  : m_detDesc(description), m_geo(g) {
55  }
56 
58  void populate(DetElement e) {
59  const DetElement::Children& c = e.children();
60  for (const auto& i : c) {
61  DetElement de = i.second;
62  PlacedVolume pv = de.placement();
63  if (pv.isValid()) {
64  Chain chain;
67  m_entries.clear();
68  chain.emplace_back(m_detDesc.world().placement().ptr());
69  scanPhysicalVolume(pv.ptr(), std::move(ids), sd, chain);
70  continue;
71  }
72  printout(WARNING, "Geant4VolumeManager",
73  "++ Detector element %s of type %s has no placement.", de.name(), de.type().c_str());
74  }
76  for( const auto& pv : m_geo.g4Placements ) {
77  if ( pv.second->IsParameterised() )
78  m_geo.g4Parameterised[pv.second] = pv.first;
79  if ( pv.second->IsReplicated() )
80  m_geo.g4Replicated[pv.second] = pv.first;
81  }
82  }
83 
85  void scanPhysicalVolume(const TGeoNode* node, PlacedVolume::VolIDs ids, SensitiveDetector& sd, Chain& chain) {
86  PlacedVolume pv = node;
87  Volume vol = pv.volume();
88  PlacedVolume::VolIDs pv_ids = pv.volIDs();
89 
90  chain.emplace_back(node);
91  ids.PlacedVolume::VolIDs::Base::insert(ids.end(), pv_ids.begin(), pv_ids.end());
92  if (vol.isSensitive()) {
93  sd = vol.sensitiveDetector();
94  if (sd.readout().isValid()) {
95  add_entry(sd, node, ids, chain);
96  }
97  else {
98  printout(WARNING, "Geant4VolumeManager",
99  "populate: Strange constellation volume %s is sensitive, but has no readout! sd:%p", pv.volume().name(),
100  sd.ptr());
101  }
102  }
103  for (Int_t idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
104  TGeoNode* daughter = node->GetDaughter(idau);
105  PlacedVolume placement(daughter);
106  if ( placement.data() ) {
107  scanPhysicalVolume(daughter, ids, sd, chain);
108  }
109  }
110  chain.pop_back();
111  }
112 
113  void add_entry(SensitiveDetector sd, const TGeoNode* n, const PlacedVolume::VolIDs& ids, const Chain& nodes) {
114  Chain control;
115  Volume vol;
116  const TGeoNode* node = nullptr;
117  Readout ro = sd.readout();
118  IDDescriptor iddesc = ro.idSpec();
119  VolumeID code = iddesc.encode(ids);
121  Registries::const_iterator i = m_entries.find(code);
122  PrintLevel print_level = m_geo.printLevel;
123  PrintLevel print_action = print_level;
124  PrintLevel print_chain = print_level;
125  PrintLevel print_res = print_level;
126 
127  printout(print_action,"Geant4VolumeManager","+++ Add path:%s vid:%016X",
128  detail::tools::placementPath(nodes,false).c_str(),code);
129 
130  if( i == m_entries.end() ) {
131  path.reserve(nodes.size());
132  for( Chain::const_reverse_iterator k = nodes.rbegin(), kend=nodes.rend(); k != kend; ++k ) {
133  node = *(k);
134  auto g4pit = m_geo.g4Placements.find(node);
135  if( g4pit != m_geo.g4Placements.end() ) {
136  G4VPhysicalVolume* phys = g4pit->second;
137  if( phys->IsParameterised() ) {
138  PlacedVolume pv(n);
139  PlacedVolumeExtension* ext = pv.data();
140  if( nullptr == ext->params->field ) {
141  ext->params->field = iddesc.field(ext->volIDs.at(0).first);
142  }
143  }
144  path.emplace_back(phys);
145  printout(print_chain, "Geant4VolumeManager", "+++ Chain: Node OK: %s [%s]",
146  node->GetName(), phys->GetName().c_str());
147  continue;
148  }
149  control.insert(control.begin(),node);
150  vol = Volume(node->GetVolume());
151  auto iVolImp = m_geo.g4VolumeImprints.find(vol);
152  if ( iVolImp != m_geo.g4VolumeImprints.end() ) {
153  for(const auto& imp : iVolImp->second ) {
154  const auto& c = imp.first;
155  if ( c.size() <= control.size() && control == c ) {
156  path.emplace_back(imp.second);
157  printout(print_chain, "Geant4VolumeManager", "+++ Chain: Node OK: %s %s -> %s",
158  node->GetName(), detail::tools::placementPath(c,false).c_str(),
159  imp.second->GetName().c_str());
160  control.clear();
161  break;
162  }
163  }
164  }
165  }
166  if ( control.empty() ) {
167  printout(print_res, "Geant4VolumeManager", "+++ Volume IDs:%s",
168  detail::tools::toString(ro.idSpec(),ids,code).c_str());
169  path.erase(path.begin()+path.size()-1);
170  printout(print_res, "Geant4VolumeManager", "+++ Map %016X to Geant4 Path:%s",
171  (void*)code, Geant4GeometryInfo::placementPath(path).c_str());
172  if ( m_geo.g4Paths.find(path) == m_geo.g4Paths.end() ) {
174  for(const auto* phys : path) {
175  opt.flags.path_has_parametrised = phys->IsParameterised() ? 1 : 0;
176  opt.flags.path_has_replicated = phys->IsReplicated() ? 1 : 0;
177  }
178  opt.flags.parametrised = path.front()->IsParameterised() ? 1 : 0;
179  opt.flags.replicated = path.front()->IsReplicated() ? 1 : 0;
180  m_geo.g4Paths[path] = { code, opt.value };
181  m_entries.emplace(code,path);
182  return;
183  }
185  if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) ) {
186  return;
187  }
188  printout(ERROR, "Geant4VolumeManager", "populate: Severe error: Duplicated Geant4 path!!!! %s %s",
189  " [THIS SHOULD NEVER HAPPEN]",Geant4GeometryInfo::placementPath(path).c_str());
190  goto Err;
191  }
192  printout(INFO, "Geant4VolumeManager", "Control block has still %d entries:%s",
193  int(control.size()),detail::tools::placementPath(control,true).c_str());
194  goto Err;
195  }
196  else {
198  if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) ) {
199  return;
200  }
201  }
202  printout(ERROR, "Geant4VolumeManager", "populate: Severe error: Duplicated Volume entry: 0x%X"
203  " [THIS SHOULD NEVER HAPPEN]", code);
204 
205  Err:
206  if ( i != m_entries.end() )
207  printout(ERROR,"Geant4VolumeManager"," Known G4 path: %s",Geant4GeometryInfo::placementPath((*i).second).c_str());
208  if ( !path.empty() )
209  printout(ERROR,"Geant4VolumeManager"," New G4 path: %s",Geant4GeometryInfo::placementPath(path).c_str());
210  if ( !nodes.empty() )
211  printout(ERROR,"Geant4VolumeManager"," TGeo path: %s",detail::tools::placementPath(nodes,false).c_str());
212  printout(ERROR,"Geant4VolumeManager", " Offend.VolIDs: %s",detail::tools::toString(ro.idSpec(),ids,code).c_str());
213  throw std::runtime_error("Failed to populate Geant4 volume manager!");
214  }
215  };
216 }
217 
221  if (info && info->valid && info->g4Paths.empty()) {
222  Populator p(description, *info);
223  p.populate(description.world());
224  return;
225  }
226  except("Geant4VolumeManager", "Attempt populate from invalid Geant4 geometry info [Invalid-Info]");
227 }
228 
230 std::vector<const G4VPhysicalVolume*>
231 Geant4VolumeManager::placementPath(const G4VTouchable* touchable, bool exception) const {
232  Geant4TouchableHandler handler(touchable);
233  return handler.placementPath(exception);
234 }
235 
238  if (!isValid()) {
239  except("Geant4VolumeManager", "Attempt to use invalid Geant4 volume manager [Invalid-Handle]");
240  }
241  else if (!ptr()->valid) {
242  except("Geant4VolumeManager", "Attempt to use invalid Geant4 geometry info [Invalid-Info]");
243  }
244  return true;
245 }
246 
247 #if 0
248 VolumeID Geant4VolumeManager::volumeID(const std::vector<const G4VPhysicalVolume*>& path) const {
250  if (!path.empty() && checkValidity()) {
251  const auto& mapping = ptr()->g4Paths;
252  auto i = mapping.find(path);
253  if ( i != mapping.end() ) {
254  return (*i).second.first;
255  }
256  if (!path[0])
257  return InvalidPath;
258  else if (!path[0]->GetLogicalVolume()->GetSensitiveDetector())
259  return Insensitive;
260  }
261  printout(INFO, "Geant4VolumeManager","+++ Bad volume Geant4 Path: %s",
262  Geant4GeometryInfo::placementPath(path).c_str());
263  return NonExisting;
264 }
265 #endif
266 
268 VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const {
269  Geant4TouchableHandler handler(touchable);
270  std::vector<const G4VPhysicalVolume*> path = handler.placementPath();
271  if( !path.empty() && checkValidity() ) {
272  const auto& mapping = ptr()->g4Paths;
273  auto i = mapping.find(path);
274  if( i != mapping.end() ) {
275  const auto& e = (*i).second;
277  if( e.flags == 0 ) {
278  return e.volumeID;
279  }
280  VolumeID volid = e.volumeID;
281  const auto& paramterised = ptr()->g4Parameterised;
282  const auto& replicated = ptr()->g4Replicated;
284  for( std::size_t j=0; j < path.size(); ++j ) {
285  const auto* phys = path[j];
286  if( phys->IsParameterised() ) {
287  int copy_no = touchable->GetCopyNumber(j);
288  const auto it = paramterised.find(phys);
289  if( it != paramterised.end() ) {
290  //printout(INFO,"Geant4VolumeManager",
291  // "Copy number: %ld <--> %ld", copy_no, long(phys->GetCopyNo()));
292  const auto* field = (*it).second.data()->params->field;
293  volid |= IDDescriptor::encode(field, copy_no);
294  continue;
295  }
296  except("Geant4VolumeManager","Error Geant4VolumeManager::volumeID(const G4VTouchable* touchable)");
297  }
298  else if( phys->IsReplicated() ) {
299  int copy_no = touchable->GetCopyNumber(j);
300  const auto it = replicated.find(phys);
301  if( it != replicated.end() ) {
302  const auto* field = (*it).second.data()->params->field;
303  volid |= IDDescriptor::encode(field, copy_no);
304  continue;
305  }
306  except("Geant4VolumeManager","Error Geant4VolumeManager::volumeID(const G4VTouchable* touchable)");
307  }
308  }
309  return volid;
310  }
311  if( !path[0] )
312  return InvalidPath;
313  else if( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )
314  return Insensitive;
315  }
316  printout(INFO, "Geant4VolumeManager","+++ Bad volume Geant4 Path: %s",
317  Geant4GeometryInfo::placementPath(path).c_str());
318  return NonExisting;
319 }
320 
322 void Geant4VolumeManager::volumeDescriptor(const std::vector<const G4VPhysicalVolume*>& path,
323  VolIDDescriptor& vol_desc) const
324 {
325  vol_desc.second.clear();
326  vol_desc.first = NonExisting;
327  if( !path.empty() && checkValidity() ) {
328  const auto& mapping = ptr()->g4Paths;
329  auto i = mapping.find(path);
330  if( i != mapping.end() ) {
331  VolumeID vid = (*i).second.volumeID;
332  G4LogicalVolume* lvol = path[0]->GetLogicalVolume();
333  if( lvol->GetSensitiveDetector() ) {
334  const auto* node = path[0];
335  const auto& pm = ptr()->g4Placements;
336  for( const auto& ipm : pm ) {
337  if ( ipm.second == node ) {
338  PlacedVolume pv = ipm.first;
340  IDDescriptor dsc = sd.readout().idSpec();
341  vol_desc.first = vid;
342  dsc.decodeFields(vid, vol_desc.second);
343  return;
344  }
345  }
346  }
347  vol_desc.first = Insensitive;
348  return;
349  }
350  if( !path[0] )
351  vol_desc.first = InvalidPath;
352  else if( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )
353  vol_desc.first = Insensitive;
354  else
355  vol_desc.first = NonExisting;
356  }
357 }
358 
360 void Geant4VolumeManager::volumeDescriptor(const G4VTouchable* touchable,
361  VolIDDescriptor& vol_desc) const {
362  volumeDescriptor(placementPath(touchable), vol_desc);
363 }
dd4hep::IDDescriptor::decodeFields
void decodeFields(VolumeID vid, std::vector< std::pair< const BitFieldElement *, VolumeID > > &fields) const
Decode volume IDs and return filled descriptor with all fields.
Definition: IDDescriptor.cpp:164
dd4hep::DetElement::children
const Children & children() const
Access to the list of children.
Definition: DetElement.cpp:207
dd4hep::sim::Geant4VolumeManager::Geant4VolumeManager
Geant4VolumeManager()=default
Default constructor.
dd4hep::sim::Geant4GeometryInfo::placementPath
static std::string placementPath(const Geant4PlacementPath &path, bool reverse=true)
Assemble Geant4 volume path.
Definition: Geant4GeometryInfo.cpp:24
dd4hep::sim::Geant4GeometryInfo::PlacementFlags
Definition: Geant4GeometryInfo.h:99
dd4hep::sim::Geant4TouchableHandler
Helper class to ease the extraction of information from a G4Touchable object.
Definition: Geant4TouchableHandler.h:44
dd4hep::sim::Geant4GeometryInfo::PlacementFlags::_flags::parametrised
unsigned parametrised
Definition: Geant4GeometryInfo.h:102
dd4hep::Detector::world
virtual DetElement world() const =0
Return reference to the top-most (world) detector element.
Volumes.h
Geant4Mapping.h
dd4hep::sim::Geant4TouchableHandler::placementPath
Geant4PlacementPath placementPath(bool exception=false) const
Helper: Generate placement path from touchable object.
Definition: Geant4TouchableHandler.cpp:40
dd4hep::SensitiveDetector
Handle class to hold the information of a sensitive detector.
Definition: DetElement.h:44
dd4hep::PlacedVolumeExtension
Implementation class extending the ROOT placed volume.
Definition: Volumes.h:79
dd4hep::IDDescriptor::field
const BitFieldElement * field(const std::string &field_name) const
Get the field descriptor of one field by name.
Definition: IDDescriptor.cpp:96
dd4hep::info
std::size_t info(const std::string &src, const std::string &msg)
Definition: RootDictionary.h:65
dd4hep::exception
void exception(const std::string &src, const std::string &msg)
Definition: RootDictionary.h:69
dd4hep::DetElement::type
std::string type() const
Access detector type (structure, tracker, calorimeter, etc.).
Definition: DetElement.cpp:97
dd4hep::PlacedVolume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:163
Geant4VolumeManager.h
dd4hep::DetElement::placement
PlacedVolume placement() const
Access to the physical volume of this detector element.
Definition: DetElement.cpp:321
dd4hep::sim::Geant4GeometryInfo::PlacementFlags::flags
struct dd4hep::sim::Geant4GeometryInfo::PlacementFlags::_flags flags
dd4hep::detail::tools::placementPath
std::string placementPath(DetElement element)
Assemble the placement path from a given detector element to the world volume.
Definition: DetectorTools.cpp:276
dd4hep::IDDescriptor
Class implementing the ID encoding of the detector response.
Definition: IDDescriptor.h:37
dd4hep::Handle::isValid
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:128
dd4hep::Handle
Handle: a templated class like a shared pointer, which allows specialized access to tgeometry objects...
Definition: Handle.h:84
dd4hep::PlacedVolumeExtension::volIDs
VolIDs volIDs
ID container.
Definition: Volumes.h:127
dd4hep::Volume::isSensitive
bool isSensitive() const
Accessor if volume is sensitive (ie. is attached to a sensitive detector)
Definition: Volumes.cpp:1322
dd4hep::Handle::name
const char * name() const
Access the object name (or "" if not supported by the object)
dd4hep::sim::Geant4VolumeManager::InvalidPath
static const VolumeID InvalidPath
Definition: Geant4VolumeManager.h:48
dd4hep::sim::Geant4GeometryInfo::printLevel
PrintLevel printLevel
Definition: Geant4GeometryInfo.h:141
dd4hep::sim::Geant4VolumeManager::Insensitive
static const VolumeID Insensitive
Definition: Geant4VolumeManager.h:49
dd4hep::sim::Geant4GeometryInfo::g4Parameterised
Geant4GeometryMaps::G4PlacementMap g4Parameterised
Definition: Geant4GeometryInfo.h:120
dd4hep::sim::Geant4VolumeManager::volumeID
VolumeID volumeID(const G4VTouchable *touchable) const
Access CELLID by placement path.
Definition: Geant4VolumeManager.cpp:268
Geant4AssemblyVolume.h
VolIDDescriptor
std::pair< VolumeID, std::vector< std::pair< const BitFieldElement *, VolumeID > > > VolIDDescriptor
Definition: Geant4VolumeManager.cpp:35
dd4hep::DetElement
Handle class describing a detector element.
Definition: DetElement.h:188
dd4hep::PlacedVolumeExtension::VolIDs
Volume ID container.
Definition: Volumes.h:88
dd4hep::Volume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:370
dd4hep::sim::Geant4VolumeManager::NonExisting
static const VolumeID NonExisting
Definition: Geant4VolumeManager.h:50
dd4hep::sim::Geant4GeometryInfo::PlacementFlags::_flags::path_has_parametrised
unsigned path_has_parametrised
Definition: Geant4GeometryInfo.h:104
dd4hep::sim::Geant4GeometryInfo::g4Placements
Geant4GeometryMaps::PlacementMap g4Placements
Definition: Geant4GeometryInfo.h:117
dd4hep::IDDescriptor::encode
static VolumeID encode(const Field *fld, VolumeID value)
Encode partial volume identifiers to a volumeID.
Definition: IDDescriptor.cpp:148
DetectorTools.h
Geant4TouchableHandler.h
dd4hep::sim::Geant4VolumeManager::placementPath
std::vector< const G4VPhysicalVolume * > placementPath(const G4VTouchable *touchable, bool exception=true) const
Helper: Generate placement path from touchable object.
Definition: Geant4VolumeManager.cpp:231
dd4hep::sim::Geant4GeometryInfo::g4VolumeImprints
Geant4GeometryMaps::VolumeImprintMap g4VolumeImprints
Definition: Geant4GeometryInfo.h:119
dd4hep::sim::IDDescriptor
IDDescriptor IDDescriptor
Definition: LCIOConversions.cpp:69
dd4hep::sim::Geant4GeometryInfo::g4Replicated
Geant4GeometryMaps::G4PlacementMap g4Replicated
Definition: Geant4GeometryInfo.h:121
dd4hep::sim::Geant4GeometryInfo::PlacementFlags::_flags::path_has_replicated
unsigned path_has_replicated
Definition: Geant4GeometryInfo.h:105
VolumeID
dd4hep::DDSegmentation::VolumeID VolumeID
Definition: SegmentationDictionary.h:50
dd4hep::sim::Geant4GeometryInfo::PlacementFlags::_flags::replicated
unsigned replicated
Definition: Geant4GeometryInfo.h:103
dd4hep::sim
Namespace for the Geant4 based simulation part of the AIDA detector description toolkit.
Definition: Geant4Output2EDM4hep.cpp:49
dd4hep::DetElement::Children
std::map< std::string, DetElement > Children
Definition: DetElement.h:206
dd4hep::sim::Geant4GeometryInfo
Concreate class holding the relation information between geant4 objects and dd4hep objects.
Definition: Geant4GeometryInfo.h:93
dd4hep::Handle::ptr
T * ptr() const
Access to the held object.
Definition: Handle.h:153
DetElement.h
dd4hep::sim::Geant4GeometryInfo::g4Paths
std::map< Geant4PlacementPath, Placement > g4Paths
Definition: Geant4GeometryInfo.h:136
dd4hep::sim::Geant4GeometryInfo::Geant4PlacementPath
std::vector< const G4VPhysicalVolume * > Geant4PlacementPath
Definition: Geant4GeometryInfo.h:110
mapping
ConditionsMap & mapping
Definition: AlignmentsCalculator.cpp:82
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::SensitiveDetector::readout
Readout readout() const
Access readout structure of the sensitive detector.
Definition: DetElement.cpp:420
dd4hep::sim::Geant4GeometryInfo::PlacementFlags::value
int value
Definition: Geant4GeometryInfo.h:100
dd4hep::detail::tools::toString
std::string toString(const PlacedVolume::VolIDs &ids)
Convert VolumeID to string.
Definition: DetectorTools.cpp:378
dd4hep::PlacedVolume::volume
Volume volume() const
Logical volume of this placement.
Definition: Volumes.cpp:468
dd4hep::PlacedVolume::data
Object * data() const
Check if placement is properly instrumented.
Definition: Volumes.cpp:447
dd4hep::Detector
The main interface to the dd4hep detector description package.
Definition: Detector.h:90
dd4hep::PlacedVolumeExtension::Parameterisation::field
const detail::BitFieldElement * field
Bitfield from sensitive detector to encode the volume ID on the fly.
Definition: Volumes.h:265
dd4hep::Readout
Handle to the implementation of the readout structure of a subdetector.
Definition: Readout.h:38
dd4hep::Readout::idSpec
IDDescriptor idSpec() const
Access IDDescription structure.
Definition: Readout.cpp:112
dd4hep::PlacedVolume::volIDs
const PlacedVolumeExtension::VolIDs & volIDs() const
Access to the volume IDs.
Definition: Volumes.cpp:496
valid
unsigned char valid
Definition: AlignmentsCalculator.cpp:69
dd4hep::sim::Geant4VolumeManager::volumeDescriptor
void volumeDescriptor(const std::vector< const G4VPhysicalVolume * > &path, std::pair< VolumeID, std::vector< std::pair< const BitFieldElement *, VolumeID > > > &volume_desc) const
Accessfully decoded volume fields by placement path.
dd4hep::PlacedVolumeExtension::params
Parameterisation * params
Reference to the parameterised transformation.
Definition: Volumes.h:125
Printout.h
dd4hep::sim::Geant4VolumeManager::checkValidity
bool checkValidity() const
Check the validity of the information before accessing it.
Definition: Geant4VolumeManager.cpp:237
dd4hep::Volume::sensitiveDetector
Handle< NamedObject > sensitiveDetector() const
Access to the handle to the sensitive detector.
Definition: Volumes.cpp:1316