DD4hep  1.30.0
Detector Description Toolkit for High Energy Physics
DetElementVolumeIDs.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 #ifndef DD4HEP_DETELEMENTVOLUMEIDS_H
14 #define DD4HEP_DETELEMENTVOLUMEIDS_H
15 
16 // Framework include files
17 #include <DD4hep/DetElement.h>
18 #include <DD4hep/Volumes.h>
19 
20 // C/C++ includes
21 
23 namespace dd4hep {
24 
26  class Detector;
27 
29 
37  private:
40 
41  public:
43  std::size_t numberOfNodes { 0 };
45  struct Encoding {
48  };
50  std::map<DetElement, std::vector<Encoding> > entries;
51 
52  private:
53  using PlacementPath = std::vector<PlacedVolume>;
54 
56  std::size_t scanPhysicalVolume(DetElement& parent,
57  DetElement e,
58  PlacedVolume pv,
59  Encoding parent_encoding,
61  PlacementPath& chain);
62  public:
64  DetElementVolumeIDs(const Detector& description);
66  std::size_t populate(DetElement e);
67  };
68 } /* End namespace dd4hep */
69 #endif // DD4HEP_DETELEMENTVOLUMEIDS_H
70 //==========================================================================
71 // AIDA Detector description implementation
72 //--------------------------------------------------------------------------
73 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
74 // All rights reserved.
75 //
76 // For the licensing terms see $DD4hepINSTALL/LICENSE.
77 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
78 //
79 // Author : M.Frank
80 //
81 //==========================================================================
82 
83 // Framework include files
84 #include <DD4hep/Printout.h>
85 #include <DD4hep/Factories.h>
86 #include <DD4hep/Detector.h>
87 #include <DD4hep/DetectorTools.h>
89 
91 using namespace dd4hep;
92 
93 namespace {
94 
96 
103  long assign_de_volumeIDs(Detector& description, int argc, char** argv) {
104  std::string detector = "/world";
105  for(int i = 0; i < argc && argv[i]; ++i) {
106  if ( 0 == ::strncmp("-detector",argv[i],4) )
107  detector = argv[++i];
108  else {
109  std::cout <<
110  "Usage: -plugin DD4hep_DetElementVolumeIDs -arg [-arg] \n\n"
111  " -detector <string> Top level DetElement path. Default: '/world' \n"
112  " -help Print this help output \n"
113  " Arguments given: " << arguments(argc,argv) << std::endl << std::flush;
114  ::exit(EINVAL);
115  }
116  }
117  DetElement element = description.world();
118  if ( detector != "/world" ) {
119  element = detail::tools::findElement(description,detector);
120  if ( !element.isValid() ) {
121  except("DD4hep_DetElementVolumeIDs","+++ Invalid DetElement path: %s",detector.c_str());
122  }
123  }
124  DetElementVolumeIDs mgr(description);
125  auto count = mgr.populate(element);
126  if ( count == 0 ) {
127  except("DD4hep_DetElementVolumeIDs",
128  "+++ NO volume identifiers assigned to DetElement %s. %s",
129  "Something went wrong!",detector.c_str());
130  }
131  return count > 0 ? 1 : 0;
132  }
133 }
134 DECLARE_APPLY(DD4hep_DetElementVolumeIDs,assign_de_volumeIDs)
135 
138 
139 namespace {
140 
142  Encoding update_encoding(const IDDescriptor iddesc, const VolIDs& ids, const Encoding& initial) {
143  VolumeID volume_id = initial.identifier, mask = initial.mask;
144  for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
145  const auto& id = (*i);
146  const BitFieldElement* f = iddesc.field(id.first);
147  VolumeID msk = f->mask();
148  int off = f->offset();
149  VolumeID val = id.second; // Necessary to extend volume IDs > 32 bit
150  volume_id |= ((f->value(val << off) << off)&msk);
151  mask |= msk;
152  }
153  return { volume_id, mask };
154  }
155 }
156 
159  : m_detDesc(description)
160 {
161 }
162 
165  std::size_t count = 0UL;
166  Encoding encoding { 0, 0 };
167  PlacedVolume pv = det.placement();
168 
169  entries.clear();
170  if ( !pv.isValid() ) {
171  except("DetElementVolumeIDs",
172  "+++ Top level DetElement %s has no valid placement. %s",
173  "[Something awfully wrong]", det.path().c_str());
174  }
175  if ( det == m_detDesc.world() ) {
176  for (const auto& i : det.children() ) {
177  DetElement de = i.second;
178  pv = de.placement();
179  if (pv.isValid()) {
180  PlacementPath chain;
181  Encoding coding { 0, 0 };
182  SensitiveDetector sd (0);
183  count += scanPhysicalVolume(de, de, pv, coding, sd, chain);
184  continue;
185  }
186  printout(WARNING, "DetElementVolumeIDs", "++ Detector element %s of type %s has no placement.",
187  de.name(), de.type().c_str());
188  }
189  printout(INFO, "DetElementVolumeIDs", "++ Assigned %ld volume identifiers to DetElements.", count);
190  return count;
191  }
193  if ( !pv.volIDs().empty() && !sd.isValid() ) {
194  except("DetElementVolumeIDs",
195  "+++ No sensitive detector available for top level DetElement %s.",
196  det.path().c_str());
197  }
198  PlacementPath chain;
199  count += scanPhysicalVolume(det, det, pv, encoding, sd, chain);
200  printout(INFO, "DetElementVolumeIDs", "++ Assigned %ld volume identifiers to DetElements.", count);
201  return count;
202 }
203 
205 std::size_t
207  DetElement e,
208  PlacedVolume pv,
209  Encoding parent_encoding,
210  SensitiveDetector& sd,
211  PlacementPath& chain)
212 {
213  TGeoNode* node = pv.ptr();
214  std::size_t count = 0;
215  if (node) {
216  Volume vol = pv.volume();
217  const VolIDs& pv_ids = pv.volIDs();
218  Encoding vol_encoding = parent_encoding;
219  bool is_sensitive = vol.isSensitive();
220  bool have_encoding = pv_ids.empty();
221  bool compound = e.type() == "compound";
222 
223  if ( compound ) {
224  sd = SensitiveDetector(0);
225  vol_encoding = Encoding();
226  }
227  else if ( !sd.isValid() ) {
228  if ( is_sensitive )
229  sd = vol.sensitiveDetector();
230  else if ( (parent->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
231  sd = m_detDesc.sensitiveDetector(parent.name());
232  else if ( (e->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
233  sd = m_detDesc.sensitiveDetector(e.name());
234  }
235  chain.emplace_back(node);
236  if ( sd.isValid() && !pv_ids.empty() ) {
237  Readout ro = sd.readout();
238  if ( ro.isValid() ) {
239  vol_encoding = update_encoding(ro.idSpec(), pv_ids, parent_encoding);
240  have_encoding = true;
241  }
242  else {
243  printout(WARNING, "DetElementVolumeIDs",
244  "%s: Strange constellation volume %s is sensitive, but has no readout! sd:%p",
245  parent.name(), pv.volume().name(), sd.ptr());
246  }
247  }
248  for (int idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
249  TGeoNode* daughter = node->GetDaughter(idau);
250  PlacedVolume place_dau(daughter);
251  if ( place_dau.data() ) {
252  DetElement de_dau;
256  for( const auto& de : e.children() ) {
257  if ( de.second.placement().ptr() == daughter ) {
258  de_dau = de.second;
259  break;
260  }
261  }
262  if ( de_dau.isValid() ) {
263  PlacementPath dau_chain;
264  count += scanPhysicalVolume(parent, de_dau, place_dau, vol_encoding, sd, dau_chain);
265  }
266  else { // there may be several layers of volumes between mother-child of DE
267  count += scanPhysicalVolume(parent, e, place_dau, vol_encoding, sd, chain);
268  }
269  }
270  else {
271  except("DetElementVolumeIDs",
272  "Invalid not instrumented placement: %s %s", daughter->GetName(),
273  " [Internal error -- bad detector constructor]");
274  }
277  if ( compound ) {
278  sd = SensitiveDetector(0);
279  }
280  }
281  if ( sd.isValid() ) {
282  if ( !have_encoding && !compound ) {
283  printout(ERROR, "DetElementVolumeIDs",
284  "Element %s: Missing SD encoding. Volume manager won't work!",
285  e.path().c_str());
286  }
287  if ( is_sensitive || count > 0 ) {
288  // Either this layer is sensitive of a layer below.
289  if ( node == e.placement().ptr() ) {
290  // These here are placement nodes, which at the same time are DetElement placements
291  // 1) We recuperate volumes from lower levels by reusing the subdetector
292  // This only works if there is exactly one sensitive detector per subdetector!
293  // 2) DetElements in the upper hierarchy of the sensitive also get a volume id,
294  // and the volume is registered. (to be discussed)
295  //
296  e.object<DetElement::Object>().volumeID = vol_encoding.identifier;
297  }
298  // Collect all sensitive volumes, which belong to the next DetElement
299  if ( entries.find(e) == entries.end()) {
300  entries[e].emplace_back(vol_encoding);
301  ++numberOfNodes;
302  }
303  ++count;
304  }
305  }
306  chain.pop_back();
307  }
308  return count;
309 }
dd4hep::DetElement::children
const Children & children() const
Access to the list of children.
Definition: DetElement.cpp:207
dd4hep::DetElement::path
const std::string & path() const
Path of the detector element (not necessarily identical to placement path!)
Definition: DetElement.cpp:158
dd4hep::DDSegmentation::BitFieldElement::offset
unsigned offset() const
Definition: BitFieldCoder.h:64
dd4hep::Detector::world
virtual DetElement world() const =0
Return reference to the top-most (world) detector element.
dd4hep::DDSegmentation::BitFieldElement
Helper class for BitFieldCoder that corresponds to one field value.
Definition: BitFieldCoder.h:32
Volumes.h
dd4hep::SensitiveDetector
Handle class to hold the information of a sensitive detector.
Definition: DetElement.h:44
Detector.h
dd4hep::DetElementVolumeIDs
Actor class to assign volume identifiers to DetElements in a subdetector tree.
Definition: DetElementVolumeIDs.cpp:36
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::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
dd4hep::Handle::object
Q & object() const
Access to an unrelated object type.
Definition: Handle.h:165
dd4hep::DetElement::placement
PlacedVolume placement() const
Access to the physical volume of this detector element.
Definition: DetElement.cpp:321
dd4hep::DetElementVolumeIDs::Encoding::mask
VolumeID mask
Definition: DetElementVolumeIDs.cpp:47
dd4hep::IDDescriptor
Class implementing the ID encoding of the detector response.
Definition: IDDescriptor.h:37
dd4hep::DDSegmentation::BitFieldElement::value
FieldID value(CellID bitfield) const
calculate this field's value given an external 64 bit bitmap
Definition: BitFieldCoder.cpp:55
DECLARE_APPLY
#define DECLARE_APPLY(name, func)
Definition: Factories.h:281
dd4hep::Handle::isValid
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:128
DetectorInterna.h
dd4hep::DetElementVolumeIDs::scanPhysicalVolume
std::size_t scanPhysicalVolume(DetElement &parent, DetElement e, PlacedVolume pv, Encoding parent_encoding, SensitiveDetector &sd, PlacementPath &chain)
Scan a single physical volume and look for sensitive elements below.
Definition: DetElementVolumeIDs.cpp:206
dd4hep::Volume::isSensitive
bool isSensitive() const
Accessor if volume is sensitive (ie. is attached to a sensitive detector)
Definition: Volumes.cpp:1322
Factories.h
dd4hep::Handle::name
const char * name() const
Access the object name (or "" if not supported by the object)
dd4hep::DetElementObject
Data class with properties of a detector element.
Definition: DetectorInterna.h:81
dd4hep::detail::tools::findElement
DetElement findElement(const Detector &description, const std::string &path)
Find DetElement as child of the top level volume by its absolute path.
Definition: DetectorTools.cpp:214
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::DetElementVolumeIDs::Encoding
Encoding/mask for sensitive volumes.
Definition: DetElementVolumeIDs.cpp:45
DetectorTools.h
dd4hep::Detector::sensitiveDetector
virtual SensitiveDetector sensitiveDetector(const std::string &name) const =0
Retrieve a sensitive detector by its name from the detector description.
dd4hep::DetElementVolumeIDs::numberOfNodes
std::size_t numberOfNodes
Node counter.
Definition: DetElementVolumeIDs.cpp:43
dd4hep::DetElementVolumeIDs::entries
std::map< DetElement, std::vector< Encoding > > entries
Set of already added entries.
Definition: DetElementVolumeIDs.cpp:50
dd4hep::DetElementVolumeIDs::m_detDesc
const Detector & m_detDesc
Reference to the Detector instance.
Definition: DetElementVolumeIDs.cpp:39
dd4hep::DDSegmentation::BitFieldElement::mask
CellID mask() const
Definition: BitFieldCoder.h:73
VolumeID
dd4hep::DDSegmentation::VolumeID VolumeID
Definition: SegmentationDictionary.h:50
dd4hep::Handle::ptr
T * ptr() const
Access to the held object.
Definition: Handle.h:153
DetElement.h
dd4hep::DetElementVolumeIDs::PlacementPath
std::vector< PlacedVolume > PlacementPath
Definition: DetElementVolumeIDs.cpp:53
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
det
DetElement::Object * det
Definition: AlignmentsCalculator.cpp:66
dd4hep::SensitiveDetector::readout
Readout readout() const
Access readout structure of the sensitive detector.
Definition: DetElement.cpp:420
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::Readout
Handle to the implementation of the readout structure of a subdetector.
Definition: Readout.h:38
Encoding
DetElementVolumeIDs::Encoding Encoding
Definition: DetElementVolumeIDs.cpp:136
dd4hep::Readout::idSpec
IDDescriptor idSpec() const
Access IDDescription structure.
Definition: Readout.cpp:112
dd4hep::DetElementVolumeIDs::populate
std::size_t populate(DetElement e)
Populate the Volume manager.
Definition: DetElementVolumeIDs.cpp:164
dd4hep::PlacedVolume::volIDs
const PlacedVolumeExtension::VolIDs & volIDs() const
Access to the volume IDs.
Definition: Volumes.cpp:496
dd4hep::DetElementObject::HAVE_SENSITIVE_DETECTOR
@ HAVE_SENSITIVE_DETECTOR
Definition: DetectorInterna.h:92
dd4hep::DetElementVolumeIDs::Encoding::identifier
VolumeID identifier
Definition: DetElementVolumeIDs.cpp:46
Printout.h
dd4hep::DetElementVolumeIDs::DetElementVolumeIDs
DetElementVolumeIDs(const Detector &description)
Default constructor.
Definition: DetElementVolumeIDs.cpp:158
dd4hep::Volume::sensitiveDetector
Handle< NamedObject > sensitiveDetector() const
Access to the handle to the sensitive detector.
Definition: Volumes.cpp:1316