DD4hep - The AIDA detector description toolkit for high energy physics experiments
DD4hep  Rev:Unversioneddirectory
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Geant4VolumeManager.cpp
Go to the documentation of this file.
1 // $Id: $
2 //==========================================================================
3 // AIDA Detector description implementation for LCD
4 //--------------------------------------------------------------------------
5 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
6 // All rights reserved.
7 //
8 // For the licensing terms see $DD4hepINSTALL/LICENSE.
9 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
10 //
11 // Author : M.Frank
12 //
13 //==========================================================================
14 
15 // Framework include files
16 #include "DD4hep/Printout.h"
17 #include "DD4hep/Volumes.h"
18 #include "DD4hep/Detector.h"
19 #include "DD4hep/DetectorTools.h"
22 #include "DDG4/Geant4Mapping.h"
23 
24 // Geant4 include files
25 #include "G4VTouchable.hh"
26 #include "G4LogicalVolume.hh"
27 #include "G4VPhysicalVolume.hh"
28 
29 // C/C++ include files
30 #include <sstream>
31 
32 using namespace DD4hep::Simulation;
33 using namespace DD4hep::Simulation::Geant4GeometryMaps;
34 using namespace DD4hep::Geometry;
35 using namespace DD4hep;
36 using namespace std;
37 
39 
40 namespace {
41 
43  struct Populator {
44  typedef vector<const TGeoNode*> Chain;
48  typedef map<VolumeID,Geant4PlacementPath> Registries;
50  LCDD& m_lcdd;
52  Registries m_entries;
54  Geant4GeometryInfo& m_geo;
55 
57  Populator(LCDD& lcdd, Geant4GeometryInfo& g)
58  : m_lcdd(lcdd), m_geo(g) {
59  }
60 
62  void populate(DetElement e) {
63  const DetElement::Children& c = e.children();
64  for (DetElement::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
65  DetElement de = (*i).second;
66  PlacedVolume pv = de.placement();
67  if (pv.isValid()) {
68  Chain chain;
71  m_entries.clear();
72  chain.push_back(m_lcdd.world().placement().ptr());
73  scanPhysicalVolume(pv.ptr(), ids, sd, chain);
74  continue;
75  }
76  printout(WARNING, "Geant4VolumeManager", "++ Detector element %s of type %s has no placement.", de.name(), de.type().c_str());
77  }
78  }
79 
81  void scanPhysicalVolume(const TGeoNode* node, PlacedVolume::VolIDs ids, SensitiveDetector& sd, Chain& chain) {
82  PlacedVolume pv = Ref_t(node);
83  Volume vol = pv.volume();
84  PlacedVolume::VolIDs pv_ids = pv.volIDs();
85 
86  chain.push_back(node);
87  ids.PlacedVolume::VolIDs::Base::insert(ids.end(), pv_ids.begin(), pv_ids.end());
88  if (vol.isSensitive()) {
89  sd = vol.sensitiveDetector();
90  if (sd.readout().isValid()) {
91  add_entry(sd, node, ids, chain);
92  }
93  else {
94  printout(WARNING, "Geant4VolumeManager",
95  "populate: Strange constellation volume %s is sensitive, but has no readout! sd:%p", pv.volume().name(),
96  sd.ptr());
97  }
98  }
99  for (Int_t idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
100  TGeoNode* daughter = node->GetDaughter(idau);
101  PlacedVolume placement(daughter);
102  if ( placement.data() ) {
103  scanPhysicalVolume(daughter, ids, sd, chain);
104  }
105  }
106  chain.pop_back();
107  }
108 
109  void add_entry(SensitiveDetector sd, const TGeoNode* /* n */, const PlacedVolume::VolIDs& ids, const Chain& nodes) {
110  Chain control;
111  const TGeoNode* node;
112  Volume vol;
113  Geant4PlacementPath path;
114  Readout ro = sd.readout();
115  IDDescriptor iddesc = ro.idSpec();
116  VolumeID code = iddesc.encode(ids);
117  Registries::const_iterator i = m_entries.find(code);
118  PrintLevel print_action = VERBOSE;
119  PrintLevel print_chain = VERBOSE;
120  PrintLevel print_res = VERBOSE;
121 
122  printout(print_action,"Geant4VolumeManager","+++ Add path:%s vid:%016X",
123  DetectorTools::placementPath(nodes,false).c_str(),code);
124 
125  if (i == m_entries.end()) {
126  path.reserve(nodes.size());
127  for (Chain::const_reverse_iterator k = nodes.rbegin(), kend=nodes.rend(); k != kend; ++k) {
128  node = *(k);
129  PlacementMap::const_iterator g4pit = m_geo.g4Placements.find(node);
130  if (g4pit != m_geo.g4Placements.end()) {
131  path.push_back((*g4pit).second);
132  printout(print_chain, "Geant4VolumeManager", "+++ Chain: Node OK: %s [%s]",
133  node->GetName(), (*g4pit).second->GetName().c_str());
134  continue;
135  }
136  control.insert(control.begin(),node);
137  vol = Volume(node->GetVolume());
138  VolumeImprintMap::const_iterator iVolImp = m_geo.g4VolumeImprints.find(vol);
139  if ( iVolImp != m_geo.g4VolumeImprints.end() ) {
140  const Imprints& imprints = (*iVolImp).second;
141  //size_t len = kend-k;
142  for(Imprints::const_iterator iImp=imprints.begin(); iImp != imprints.end(); ++iImp) {
143  const VolumeChain& c = (*iImp).first;
144  if ( c.size() <= control.size() && control == c ) {
145  path.push_back((*iImp).second);
146  printout(print_chain, "Geant4VolumeManager", "+++ Chain: Node OK: %s %s -> %s",
147  node->GetName(), DetectorTools::placementPath(c,false).c_str(),
148  (*iImp).second->GetName().c_str());
149  control.clear();
150  break;
151  }
152  }
153  }
154  }
155  if ( control.empty() ) {
156  printout(print_res, "Geant4VolumeManager", "+++ Volume IDs:%s",
157  DetectorTools::toString(ro.idSpec(),ids,code).c_str());
158  path.erase(path.begin()+path.size()-1);
159  printout(print_res, "Geant4VolumeManager", "+++ Map %016X to Geant4 Path:%s",
160  (void*)code, placementPath(path).c_str());
161  if (m_geo.g4Paths.find(path) == m_geo.g4Paths.end()) {
162  m_geo.g4Paths[path] = code;
163  m_entries.insert(make_pair(code,path));
164  return;
165  }
166  printout(ERROR, "Geant4VolumeManager", "populate: Severe error: Duplicated Geant4 path!!!! %s %s",
167  " [THIS SHOULD NEVER HAPPEN]",placementPath(path).c_str());
168  goto Err;
169  }
170  printout(INFO, "Geant4VolumeManager", "Control block has still %d entries:%s",
171  int(control.size()),DetectorTools::placementPath(control,true).c_str());
172  goto Err;
173  }
174  printout(ERROR, "Geant4VolumeManager", "populate: Severe error: Duplicated Volume entry: %X"
175  " [THIS SHOULD NEVER HAPPEN]", code);
176 
177  Err:
178  if ( i != m_entries.end() )
179  printout(ERROR,"Geant4VolumeManager"," Known G4 path: %s",placementPath((*i).second).c_str());
180  if ( !path.empty() )
181  printout(ERROR,"Geant4VolumeManager"," New G4 path: %s",placementPath(path).c_str());
182  if ( !nodes.empty() )
183  printout(ERROR,"Geant4VolumeManager"," TGeo path: %s",DetectorTools::placementPath(nodes,false).c_str());
184  printout(ERROR,"Geant4VolumeManager", " Offend.VolIDs: %s",DetectorTools::toString(ro.idSpec(),ids,code).c_str());
185  throw runtime_error("Failed to populate Geant4 volume manager!");
186  }
187  };
188 }
189 
192  : Base(info), m_isValid(false) {
193  if (info && info->valid && info->g4Paths.empty()) {
194  Populator p(lcdd, *info);
195  p.populate(lcdd.world());
196  return;
197  }
198  throw runtime_error(format("Geant4VolumeManager", "Attempt populate from invalid Geant4 geometry info [Invalid-Info]"));
199 }
200 
202 Geant4PlacementPath Geant4VolumeManager::placementPath(const G4VTouchable* touchable, bool exception) const {
203  Geant4TouchableHandler handler(touchable);
204  return handler.placementPath(exception);
205 }
206 
209  if (m_isValid) {
210  return true;
211  }
212  else if (!isValid()) {
213  throw runtime_error(format("Geant4VolumeManager", "Attempt to use invalid Geant4 volume manager [Invalid-Handle]"));
214  }
215  else if (!ptr()->valid) {
216  throw runtime_error(format("Geant4VolumeManager", "Attempt to use invalid Geant4 geometry info [Invalid-Info]"));
217  }
218  m_isValid = true;
219  return m_isValid;
220 }
221 
224  if (!path.empty() && checkValidity()) {
225  const Geant4PathMap& m = ptr()->g4Paths;
226  Geant4PathMap::const_iterator i = m.find(path);
227  if (i != m.end())
228  return (*i).second;
229  if (!path[0])
230  return InvalidPath;
231  else if (!path[0]->GetLogicalVolume()->GetSensitiveDetector())
232  return Insensitive;
233  }
234  printout(INFO, "Geant4VolumeManager","+++ Bad volume Geant4 Path: %s",
235  Geant4GeometryMaps::placementPath(path).c_str());
236  return NonExisting;
237 }
238 
240 VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const {
241  Geant4TouchableHandler handler(touchable);
242  return volumeID(handler.placementPath());
243 }
244 
247  vol_desc.second.clear();
248  vol_desc.first = NonExisting;
249  if (!path.empty() && checkValidity()) {
250  const Geant4PathMap& m = ptr()->g4Paths;
251  Geant4PathMap::const_iterator i = m.find(path);
252  if (i != m.end()) {
253  VolumeID vid = (*i).second;
254  G4LogicalVolume* lvol = path[0]->GetLogicalVolume();
255  if (lvol->GetSensitiveDetector()) {
256  const G4VPhysicalVolume* node = path[0];
257  const PlacementMap& pm = ptr()->g4Placements;
258  for (PlacementMap::const_iterator ipm = pm.begin(); ipm != pm.end(); ++ipm) {
259  if ((*ipm).second == node) {
260  PlacedVolume pv = (*ipm).first;
263  vol_desc.first = vid;
264  dsc.decodeFields(vid, vol_desc.second);
265  return;
266  }
267  }
268  }
269  vol_desc.first = Insensitive;
270  return;
271  }
272  if (!path[0])
273  vol_desc.first = InvalidPath;
274  else if (!path[0]->GetLogicalVolume()->GetSensitiveDetector())
275  vol_desc.first = Insensitive;
276  else
277  vol_desc.first = NonExisting;
278  }
279 }
280 
282 void Geant4VolumeManager::volumeDescriptor(const G4VTouchable* touchable, VolIDDescriptor& vol_desc) const {
283  volumeDescriptor(placementPath(touchable), vol_desc);
284 }
285 
Handle class to hold the information of a sensitive detector.
Definition: Detector.h:47
Ref_t sensitiveDetector() const
Access to the handle to the sensitive detector.
Definition: Volumes.cpp:743
bool checkValidity() const
Check the validity of the information before accessing it.
std::vector< const TGeoNode * > VolumeChain
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:135
virtual DetElement world() const =0
Return reference to the top-most (world) detector element.
Volume volume() const
Logical volume of this placement.
Definition: Volumes.cpp:389
const VolIDs & volIDs() const
Access to the volume IDs.
Definition: Volumes.cpp:399
const char * name() const
Access the object name (or "" if not supported by the object)
Definition: Handle.inl:36
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:124
VolumeID volumeID(const PlacementPath &path) const
Access CELLID by placement path.
std::map< Geant4PlacementPath, VolumeID > Geant4PathMap
bool m_isValid
Optimization flag to shortcut object checks.
std::vector< const G4VPhysicalVolume * > Geant4PlacementPath
std::vector< ImprintEntry > Imprints
const Children & children() const
Access to the list of children.
Definition: Detector.cpp:207
std::string type() const
Access detector type (structure, tracker, calorimeter, etc.).
Definition: Detector.cpp:98
return e
Definition: Volumes.cpp:297
void volumeDescriptor(const PlacementPath &path, VolIDDescriptor &volume_desc) const
Accessfully decoded volume fields by placement path.
PrintLevel
Definition: Printout.h:47
Handle to the implementation of the readout structure of a subdetector.
Definition: Readout.h:46
T * ptr() const
Access to the held object.
Definition: Handle.h:149
DD4hep::Geometry::DetElement DetElement
Geant4GeometryMaps::Geant4PlacementPath PlacementPath
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:237
std::map< PlacedVolume, G4VPhysicalVolume * > PlacementMap
std::string format(const std::string &src, const std::string &fmt,...)
Build formatted string.
Definition: Printout.cpp:267
std::string placementPath(DetElement element)
Assemble the placement path from a given detector element to the world volume.
VolumeID encode(const std::vector< VolID > &ids) const
Encode a set of volume identifiers (corresponding to this description of course!) to a volumeID...
Helper class to ease the extraction of information from a G4Touchable object.
IDDescriptor idSpec() const
Access IDDescription structure.
Definition: Readout.cpp:109
std::pair< VolumeID, VolIDFields > VolIDDescriptor
PlacedVolume placement() const
Access to the physical volume of this detector element.
Definition: Detector.cpp:279
Geant4PlacementPath placementPath(bool exception=false) const
Helper: Generate placement path from touchable object.
static const double g
Definition: DD4hepUnits.h:162
Handle< NamedObject > Ref_t
Default Ref_t definition describing named objects.
Definition: Handle.h:176
Handle class describing a detector element.
Definition: Detector.h:172
Readout readout() const
Access readout structure of the sensitive detector.
Definition: Detector.cpp:451
Handle: a templated class like a shared pointer, which allows specialized access to tgeometry objects...
Definition: Handle.h:87
long long int VolumeID
Definition: Primitives.h:35
The main interface to the DD4hep detector description package.
Definition: LCDD.h:82
Concreate class holding the relation information between geant4 objects and dd4hep objects...
PlacementPath placementPath(const G4VTouchable *touchable, bool exception=true) const
Helper: Generate placement path from touchable object.
std::map< std::string, DetElement > Children
Definition: Detector.h:202
void decodeFields(VolumeID vid, VolIDFields &fields)
Decode volume IDs and return filled descriptor with all fields.
int printout(PrintLevel severity, const char *src, const char *fmt,...)
Calls the display action with a given severity level.
Definition: Printout.cpp:111
Geant4GeometryMaps::Geant4PathMap g4Paths
Class implementing the ID encoding of detector response.
Definition: IDDescriptor.h:40
TGeoShape TGeoMedium * m
Definition: Volumes.cpp:294
std::string placementPath(const Geant4PlacementPath &path, bool reverse=true)
Assemble Geant4 volume path.
bool isSensitive() const
Accessor if volume is sensitive (ie. is attached to a sensitive detector)
Definition: Volumes.cpp:749
std::string toString(const PlacedVolume::VolIDs &ids)
Convert VolumeID to string.