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
VolumeManager.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation for LCD
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/LCDD.h"
16 #include "DD4hep/Printout.h"
19 
20 // C/C++ includes
21 #include <set>
22 #include <cmath>
23 #include <sstream>
24 #include <iomanip>
25 
26 using namespace std;
27 using namespace DD4hep;
28 using namespace DD4hep::Geometry;
29 
30 namespace {
31 
32  struct Populator {
33  typedef PlacedVolume::VolIDs VolIDs;
34  typedef vector<TGeoNode*> Chain;
35  typedef pair<VolumeID, VolumeID> Encoding;
37  LCDD& m_lcdd;
39  VolumeManager m_volManager;
41  set<VolumeID> m_entries;
43  Populator(LCDD& lcdd, VolumeManager vm)
44  : m_lcdd(lcdd), m_volManager(vm) {
45  }
46 
48  void populate(DetElement e) {
49  //const char* typ = 0;//::getenv("VOLMGR_NEW");
50  const DetElement::Children& c = e.children();
51  SensitiveDetector parent_sd;
52  if ( e->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR ) {
53  parent_sd = m_lcdd.sensitiveDetector(e.name());
54  }
55  //printout(INFO, "VolumeManager", "++ Executing %s plugin manager version",typ ? "***NEW***" : "***OLD***");
56  for (DetElement::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
57  DetElement de = (*i).second;
58  PlacedVolume pv = de.placement();
59  if (pv.isValid()) {
60  Chain chain;
61  SensitiveDetector sd = parent_sd;
62  m_entries.clear();
63 #if 0
64  if ( typ ) {
65  Encoding coding(0, 0);
66  scanPhysicalVolume(de, de, pv, coding, sd, chain);
67  continue;
68  }
69  VolIDs ids;
70  scanPhysicalVolume(de, de, pv, ids, sd, chain);
71 #else
72  Encoding coding(0, 0);
73  scanPhysicalVolume(de, de, pv, coding, sd, chain);
74 #endif
75  continue;
76  }
77  printout(WARNING, "VolumeManager", "++ Detector element %s of type %s has no placement.",
78  de.name(), de.type().c_str());
79  }
80  }
82  DetElement findElt(DetElement e, PlacedVolume pv) {
83  const DetElement::Children& c = e.children();
84  if (e.placement().ptr() == pv.ptr())
85  return e;
86  for (DetElement::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
87  DetElement de = (*i).second;
88  if (de.placement().ptr() == pv.ptr())
89  return de;
90  }
91  for (DetElement::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
92  DetElement de = findElt((*i).second, pv);
93  if (de.isValid())
94  return de;
95  }
96  return DetElement();
97  }
99  size_t scanPhysicalVolume(DetElement& parent, DetElement e, PlacedVolume pv,
100  Encoding parent_encoding,
101  SensitiveDetector& sd, Chain& chain)
102  {
103  TGeoNode* node = pv.ptr();
104  size_t count = 0;
105  if (node) {
106  Volume vol = pv.volume();
107  const VolIDs& pv_ids = pv.volIDs();
108  Encoding vol_encoding = parent_encoding;
109  bool is_sensitive = vol.isSensitive();
110  bool have_encoding = pv_ids.empty();
111  bool compound = e.type() == "compound";
112 
113  if ( compound ) {
114  sd = SensitiveDetector(0);
115  vol_encoding = Encoding();
116  }
117  else if ( !sd.isValid() ) {
118  if ( is_sensitive )
119  sd = vol.sensitiveDetector();
120  else if ( (parent->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
121  sd = m_lcdd.sensitiveDetector(parent.name());
122  else if ( (e->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
123  sd = m_lcdd.sensitiveDetector(e.name());
124  }
125  chain.push_back(node);
126  if ( sd.isValid() && !pv_ids.empty() ) {
127  Readout ro = sd.readout();
128  if ( ro.isValid() ) {
129  vol_encoding = update_encoding(ro.idSpec(), pv_ids, parent_encoding);
130  have_encoding = true;
131  }
132  else {
133  printout(WARNING, "VolumeManager",
134  "%s: Strange constellation volume %s is sensitive, but has no readout! sd:%p",
135  parent.name(), pv.volume().name(), sd.ptr());
136  }
137  }
138  for (Int_t idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
139  TGeoNode* daughter = node->GetDaughter(idau);
140  PlacedVolume placement(daughter);
141  if ( placement.data() ) {
142  PlacedVolume pv_dau(daughter);
143  DetElement de_dau = findElt(e, daughter);
144  if ( de_dau.isValid() ) {
145  Chain dau_chain;
146  count += scanPhysicalVolume(parent, de_dau, pv_dau, vol_encoding, sd, dau_chain);
147  }
148  else {
149  count += scanPhysicalVolume(parent, e, pv_dau, vol_encoding, sd, chain);
150  }
151  }
152  else {
153  except("VolumeManager",
154  "Invalid not instrumented placement:"+string(daughter->GetName())+
155  " [Internal error -- bad detector constructor]");
156  }
157  if ( compound ) {
158  sd = SensitiveDetector(0);
159  }
160  }
161  if ( e.path().find("/world/EcalBarrel") == 0 ) {
162  printout(DEBUG, "VolumeManager","");
163  }
164  if ( sd.isValid() ) {
165  if ( !have_encoding ) {
166  printout(ERROR, "VolumeManager","%s: Missing SD encoding. Volume manager won't work!",
167  e.path().c_str());
168  }
169  bool add_det_vol_id = (is_sensitive || count > 0) && node == e.placement().ptr();
170  if ( add_det_vol_id ) {
171  // 1) We recuperate volumes from lower levels by reusing the subdetector
172  // This only works if there is exactly one sensitive detector per subdetector!
173  // 2) DetElements in the upper hierarchy of the sensitive also get al volume id,
174  // and the volume is registered. (to be discussed)
175  //
176  // I hate this, but I could not talk Frank out of this! M.F.
177  //
178  printout(VERBOSE,"VolumeManager","++++ %-11s SD:%s VolID=%p Mask=%p",e.path().c_str(),
179  have_encoding ? "RECUPERATED" : "REGULAR", sd.name(),
180  (void*)vol_encoding.first, (void*)vol_encoding.second);
181  e.object<DetElement::Object>().volumeID = vol_encoding.first;
182  }
183  if ( is_sensitive || add_det_vol_id ) {
184  add_entry(sd, parent, e, node, vol_encoding, chain);
185  ++count;
186  }
187  }
188  chain.pop_back();
189  }
190  return count;
191  }
193  size_t scanPhysicalVolume(DetElement& parent, DetElement e, PlacedVolume pv,
194  VolIDs ids, SensitiveDetector& sd, Chain& chain)
195  {
196  TGeoNode* node = pv.ptr();
197  size_t count = 0;
198  if (node) {
199  Volume vol = pv.volume();
200  chain.push_back(node);
201  VolIDs pv_ids = pv.volIDs();
202  ids.VolIDs::Base::insert(ids.end(), pv_ids.begin(), pv_ids.end());
203  bool got_readout = false;
204  if ( vol.isSensitive() ) {
205  sd = vol.sensitiveDetector();
206  Readout ro = sd.readout();
207  if ( sd.isValid() && ro.isValid() ) {
208  got_readout = true;
209  add_entry(sd, parent, e, node, ids, chain);
210  ++count;
211  }
212  else {
213  printout(WARNING, "VolumeManager",
214  "%s: Strange constellation volume %s is sensitive, but has no readout! sd:%p",
215  parent.name(), pv.volume().name(), sd.ptr());
216  }
217  }
218  for (Int_t idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
219  TGeoNode* daughter = node->GetDaughter(idau);
220  PlacedVolume placement(daughter);
221  if ( placement.data() ) {
222  size_t cnt;
223  PlacedVolume pv_dau = Ref_t(daughter);
224  DetElement de_dau = findElt(e, daughter);
225  if ( de_dau.isValid() ) {
226  Chain dau_chain;
227  cnt = scanPhysicalVolume(parent, de_dau, pv_dau, ids, sd, dau_chain);
228  }
229  else {
230  cnt = scanPhysicalVolume(parent, e, pv_dau, ids, sd, chain);
231  }
232  // There was a sensitive daughter volume, also add the parent entry.
233  if ( count == 0 && cnt > 0 && sd.isValid() && !pv_ids.empty()) {
234  add_entry(sd, parent, e, node, ids, chain);
235  }
236  count += cnt;
237  }
238  else {
239  throw runtime_error("Invalid not instrumented placement:"+string(daughter->GetName())+
240  " [Internal error -- bad detector constructor]");
241  }
242  }
243  if ( count == 0 ) {
244  sd = SensitiveDetector(0);
245  }
246  else if ( count > 0 && sd.isValid() ) {
247  // We recuperate volumes from lower levels by reusing the subdetector
248  // This only works if there is exactly one sensitive detector per subdetector!
249  // I hate this, but I could not talk Frank out of this! M.F.
250  Readout ro = sd.readout();
251  if ( ro.isValid() ) {
252  IDDescriptor iddesc = ro.idSpec();
253  Encoding det_encoding = encoding(iddesc,ids);
254  printout(VERBOSE,"VolumeManager","++++ %-11s SD:%s VolID=%p Mask=%p",e.path().c_str(),
255  got_readout ? "RECUPERATED" : "REGULAR", sd.name(),
256  (void*)det_encoding.first, (void*)det_encoding.second);
257  e.object<DetElement::Object>().volumeID = det_encoding.first;
258  }
259  }
260  chain.pop_back();
261  }
262  return count;
263  }
264 
266  static Encoding update_encoding(const IDDescriptor iddesc, const VolIDs& ids, const Encoding& initial) {
267  VolumeID volume_id = initial.first, mask = initial.second;
268  for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
269  const PlacedVolume::VolID& id = (*i);
270  IDDescriptor::Field f = iddesc.field(id.first);
271  VolumeID msk = f->mask();
272  int offset = f->offset();
273  volume_id |= ((f->value(id.second << offset) << offset)&msk);
274  mask |= msk;
275  }
276  return make_pair(volume_id, mask);
277  }
279  static Encoding encoding(const IDDescriptor iddesc, const VolIDs& ids) {
280  VolumeID volume_id = 0, mask = 0;
281  for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
282  const PlacedVolume::VolID& id = (*i);
283  IDDescriptor::Field f = iddesc.field(id.first);
284  VolumeID msk = f->mask();
285  int off = f->offset();
286  volume_id |= ((f->value(id.second<<off)<<off)&msk);
287  mask |= msk;
288  }
289  return make_pair(volume_id, mask);
290  }
291 
292  void add_entry(SensitiveDetector sd, DetElement parent, DetElement e,
293  const TGeoNode* n, const Encoding& code, Chain& nodes)
294  {
295  if ( sd.isValid() ) {
296  if (m_entries.find(code.first) == m_entries.end()) {
297  Readout ro = sd.readout();
298  string sd_name = sd.name();
299  DetElement sub_detector = m_lcdd.detector(sd_name);
300  VolumeManager section = m_volManager.addSubdetector(sub_detector, ro);
301  // This is the block, we effectively have to save for each physical volume with a VolID
303  context->identifier = code.first;
304  context->mask = code.second;
305  context->detector = parent;
306  context->placement = PlacedVolume(n);
307  context->element = e;
308  //context->volID = ids;
309  context->path = nodes;
310  for (size_t i = nodes.size(); i > 1; --i) { // Omit the placement of the parent DetElement
311  TGeoMatrix* m = nodes[i - 1]->GetMatrix();
312  context->toWorld.MultiplyLeft(m);
313  }
314  context->toDetector = context->toWorld;
315  context->toDetector.MultiplyLeft(nodes[0]->GetMatrix());
316  context->toWorld.MultiplyLeft(&parent.worldTransformation());
317  if (!section.adoptPlacement(context)) {
318  print_node(sd, parent, e, n, code, nodes);
319  }
320  m_entries.insert(code.first);
321  }
322  }
323  }
324 
325  void add_entry(SensitiveDetector sd, DetElement parent, DetElement e,
326  const TGeoNode* n, const VolIDs& ids, Chain& nodes)
327  {
328  if ( sd.isValid() ) {
329  Readout ro = sd.readout();
330  IDDescriptor iddesc = ro.idSpec();
331  Encoding code = encoding(iddesc, ids);
332 
333  if (m_entries.find(code.first) == m_entries.end()) {
334  string sd_name = sd.name();
335  DetElement sub_detector = m_lcdd.detector(sd_name);
336  VolumeManager section = m_volManager.addSubdetector(sub_detector, ro);
337  // This is the block, we effectively have to save for each physical volume with a VolID
339  context->identifier = code.first;
340  context->mask = code.second;
341  context->detector = parent;
342  context->placement = PlacedVolume(n);
343  context->element = e;
344  context->volID = ids;
345  context->path = nodes;
346  for (size_t i = nodes.size(); i > 1; --i) { // Omit the placement of the parent DetElement
347  TGeoMatrix* m = nodes[i - 1]->GetMatrix();
348  context->toWorld.MultiplyLeft(m);
349  }
350  context->toDetector = context->toWorld;
351  context->toDetector.MultiplyLeft(nodes[0]->GetMatrix());
352  context->toWorld.MultiplyLeft(&parent.worldTransformation());
353  if (!section.adoptPlacement(context)) {
354  print_node(sd, parent, e, n, ids, nodes);
355  }
356  m_entries.insert(code.first);
357  }
358  }
359  }
360 
361  void print_node(SensitiveDetector sd, DetElement parent, DetElement e,
362  const TGeoNode* n, const VolIDs& ids, const Chain& /* nodes */) const
363  {
364  static int s_count = 0;
365  Readout ro = sd.readout();
366  const IDDescriptor& en = ro.idSpec();
367  PlacedVolume pv = Ref_t(n);
368  bool sensitive = pv.volume().isSensitive();
369  Encoding code = encoding(en, ids);
370  VolumeID volume_id = code.first;
371 
372  //if ( !sensitive ) return;
373  ++s_count;
374  stringstream log;
375  log << s_count << ": " << parent.name() << ": " << e.name()
376  << " ro:" << ro.ptr() << " pv:" << n->GetName() << " id:"
377  << (void*) volume_id << " : ";
378  for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
379  const PlacedVolume::VolID& id = (*i);
380  IDDescriptor::Field f = ro.idSpec().field(id.first);
381  VolumeID value = f->value(volume_id);
382  log << id.first << "=" << id.second << "," << value
383  << " [" << f->offset() << "," << f->width() << "] ";
384  }
385  log << " Sensitive:" << yes_no(sensitive);
386  printout(DEBUG, "VolumeManager", log.str().c_str());
387 #if 0
388  log.str("");
389  log << s_count << ": " << e.name() << " Detector GeoNodes:";
390  for(vector<const TGeoNode*>::const_iterator j=nodes.begin(); j!=nodes.end();++j)
391  log << (void*)(*j) << " ";
392  printout(DEBUG,"VolumeManager",log.str().c_str());
393 #endif
394  }
395  void print_node(SensitiveDetector sd, DetElement parent, DetElement e,
396  const TGeoNode* n, const Encoding& code, const Chain& /* nodes */) const
397  {
398  static int s_count = 0;
399  Readout ro = sd.readout();
400  PlacedVolume pv = Ref_t(n);
401  bool sensitive = pv.volume().isSensitive();
402  VolumeID volume_id = code.first;
403 
404  //if ( !sensitive ) return;
405  ++s_count;
406  stringstream log;
407  log << s_count << ": " << parent.name() << ": " << e.name()
408  << " ro:" << ro.ptr() << " pv:" << n->GetName() << " id:"
409  << (void*) volume_id << " Sensitive:" << yes_no(sensitive);
410  printout(DEBUG, "VolumeManager", log.str().c_str());
411 #if 0
412  log.str("");
413  log << s_count << ": " << e.name() << " Detector GeoNodes:";
414  for(vector<const TGeoNode*>::const_iterator j=nodes.begin(); j!=nodes.end();++j)
415  log << (void*)(*j) << " ";
416  printout(DEBUG,"VolumeManager",log.str().c_str());
417 #endif
418  }
419  };
420 }
421 
423 VolumeManager::VolumeManager(LCDD& lcdd, const string& nam, DetElement elt, Readout ro, int flags) {
424  printout(INFO, "VolumeManager", " - populating volume ids - be patient ..." );
425  Object* obj_ptr = new Object();
426  assign(obj_ptr, nam, "VolumeManager");
427  if (elt.isValid()) {
428  Populator p(lcdd, *this);
429  obj_ptr->detector = elt;
430  obj_ptr->id = ro.isValid() ? ro.idSpec() : IDDescriptor();
431  obj_ptr->top = obj_ptr;
432  obj_ptr->flags = flags;
433  p.populate(elt);
434  }
435  printout(INFO, "VolumeManager", " - populating volume ids - done" );
436 }
437 
439 VolumeManager::VolumeManager(DetElement sub_detector, Readout ro) {
440  Object* obj_ptr = new Object();
441  obj_ptr->detector = sub_detector;
442  obj_ptr->id = ro.isValid() ? ro.idSpec() : IDDescriptor();
443  assign(obj_ptr, sub_detector.name(), "VolumeManager");
444 }
445 
447 VolumeManager VolumeManager::addSubdetector(DetElement det, Readout ro) {
448  if (isValid()) {
449  Object& o = _data();
450  if (!det.isValid()) {
451  throw runtime_error("DD4hep: VolumeManager::addSubdetector: Only valid subdetectors "
452  "are allowed. [Invalid DetElement]");
453  }
454  Detectors::const_iterator i = o.subdetectors.find(det);
455  if (i == o.subdetectors.end()) {
456  string det_name = det.name();
457  // First check all pre-conditions
458  if (!ro.isValid()) {
459  throw runtime_error("DD4hep: VolumeManager::addSubdetector: Only subdetectors with a "
460  "valid readout descriptor are allowed. [Invalid DetElement:" + det_name + "]");
461  }
462  PlacedVolume pv = det.placement();
463  if (!pv.isValid()) {
464  throw runtime_error("DD4hep: VolumeManager::addSubdetector: Only subdetectors with a "
465  "valid placement are allowed. [Invalid DetElement:" + det_name + "]");
466  }
467  VolIDs::Base::const_iterator vit = pv.volIDs().find("system");
468  if (vit == pv.volIDs().end()) {
469  throw runtime_error("DD4hep: VolumeManager::addSubdetector: Only subdetectors with "
470  "valid placement VolIDs are allowed. [Invalid DetElement:" + det_name + "]");
471  }
472 
473  i = o.subdetectors.insert(make_pair(det, VolumeManager(det,ro))).first;
474  const PlacedVolume::VolID& id = (*vit);
475  VolumeManager m = (*i).second;
476  IDDescriptor::Field field = ro.idSpec().field(id.first);
477  if (!field) {
478  throw runtime_error("DD4hep: VolumeManager::addSubdetector: IdDescriptor of " +
479  string(det.name()) + " has no field " + id.first);
480  }
481  Object& mo = m._data();
482  mo.top = o.top;
483  mo.flags = o.flags;
484  mo.system = field;
485  mo.sysID = id.second;
486  mo.detMask = mo.sysID;
487  o.managers[mo.sysID] = m;
488  det.callAtUpdate(DetElement::PLACEMENT_CHANGED|DetElement::PLACEMENT_DETECTOR,
489  &mo,&Object::update);
490  }
491  return (*i).second;
492  }
493  throw runtime_error("DD4hep: VolumeManager::addSubdetector: "
494  "Failed to add subdetector section. [Invalid Manager Handle]");
495 }
496 
498 VolumeManager VolumeManager::subdetector(VolumeID id) const {
499  if (isValid()) {
500  const Object& o = _data();
502  for (Detectors::const_iterator j = o.subdetectors.begin(); j != o.subdetectors.end(); ++j) {
503  const Object& mo = (*j).second._data();
504  //VolumeID sys_id = mo.system.decode(id);
505  VolumeID sys_id = mo.system->value(id << mo.system->offset());
506  if (sys_id == mo.sysID)
507  return (*j).second;
508  }
509  throw runtime_error("DD4hep: VolumeManager::subdetector(VolID): "
510  "Attempt to access unknown subdetector section.");
511  }
512  throw runtime_error("DD4hep: VolumeManager::subdetector(VolID): "
513  "Cannot assign ID descriptor [Invalid Manager Handle]");
514 }
515 
517 DetElement VolumeManager::detector() const {
518  if (isValid()) {
519  return _data().detector;
520  }
521  throw runtime_error("DD4hep: VolumeManager::detector: Cannot access DetElement [Invalid Handle]");
522 }
523 
525 IDDescriptor VolumeManager::idSpec() const {
526  return _data().id;
527 }
528 
530 bool VolumeManager::adoptPlacement(VolumeID /* sys_id */, Context* context) {
531  stringstream err;
532  Object& o = _data();
533  VolumeID vid = context->identifier;
534  PlacedVolume pv = context->placement;
535  Volumes::iterator i = o.volumes.find(vid);
536 #if 0
537  if ( (context->identifier&context->mask) != context->identifier ) {
538  err << "Bad context mask:" << (void*)context->mask << " id:" << (void*)context->identifier
539  << " pv:" << pv.name() << " Sensitive:"
540  << yes_no(pv.volume().isSensitive()) << endl;
541  goto Fail;
542  }
543 #endif
544  if (i == o.volumes.end()) {
545  o.volumes[vid] = context;
546  o.detMask |= context->mask;
547  err << "Inserted new volume:" << setw(6) << left << o.volumes.size() << " Ptr:" << (void*) pv.ptr() << " ["
548  << pv.name() << "]" << " ID:" << (void*) context->identifier << " Mask:" << (void*) context->mask;
549  printout(VERBOSE, "VolumeManager", err.str().c_str());
550  return true;
551  }
552  err << "+++ Attempt to register duplicate volID " << (void*) context->identifier
553  << " Mask:" << (void*) context->mask
554  << " to detector " << o.detector.name()
555  << " ptr:" << (void*) pv.ptr()
556  << " Name:" << pv.name()
557  << " Sensitive:" << yes_no(pv.volume().isSensitive()) << endl;
558  printout(ERROR, "VolumeManager", "%s", err.str().c_str());
559  err.str("");
560  err << " !!!!! ++++ VolIDS ";
561  const VolIDs::Base& id_vector = context->volID;
562  for (VolIDs::Base::const_iterator vit = id_vector.begin(); vit != id_vector.end(); ++vit)
563  err << (*vit).first << "=" << (*vit).second << "; ";
564  printout(ERROR, "VolumeManager", "%s", err.str().c_str());
565  err.str("");
566  context = (*i).second;
567  pv = context->placement;
568  err << " !!!!! +++ Clashing volID " << (void*) context->identifier
569  << " Mask:" << (void*) context->mask
570  << " to detector " << o.detector.name()
571  << " ptr:" << (void*) pv.ptr()
572  << " Name:" << pv.name()
573  << " Sensitive:" << yes_no(pv.volume().isSensitive()) << endl;
574  printout(ERROR, "VolumeManager", "%s", err.str().c_str());
575  err.str("");
576 
577  goto Fail;
578  Fail: {
579  err << " !!!!! ++++ VolIDS ";
580  const VolIDs::Base& ids = context->volID;
581  for (VolIDs::Base::const_iterator vit = ids.begin(); vit != ids.end(); ++vit)
582  err << (*vit).first << "=" << (*vit).second << "; ";
583  }
584  printout(ERROR, "VolumeManager", "%s", err.str().c_str());
585  // throw runtime_error(err.str());
586  return false;
587 }
588 
590 bool VolumeManager::adoptPlacement(Context* context) {
591  stringstream err;
592  if (isValid()) {
593  Object& o = _data();
594  if (context) {
595  if ((o.flags & ONE) == ONE) {
596  VolumeManager top(Ref_t(o.top));
597  return top.adoptPlacement(context);
598  }
599  if ((o.flags & TREE) == TREE) {
600  bool isTop = ptr() == o.top;
601  if (!isTop) {
602  VolumeID sys_id = o.system->value(context->identifier);
603  if (sys_id == o.sysID) {
604  return adoptPlacement(sys_id, context);
605  }
606  VolumeManager top(Ref_t(o.top));
607  return top.adoptPlacement(context);
608  }
609  for (Managers::iterator j = o.managers.begin(); j != o.managers.end(); ++j) {
610  Object& m = (*j).second._data();
611  VolumeID sid = m.system->value(context->identifier);
612  if ((*j).first == sid) {
613  return (*j).second.adoptPlacement(sid, context);
614  }
615  }
616  }
617  return false;
618  }
619  err << "Failed to add new physical volume to detector:" << o.detector.name() << " [Invalid Context]";
620  goto Fail;
621  }
622  err << "Failed to add new physical volume [Invalid Manager Handle]";
623  goto Fail;
624  Fail: throw runtime_error("DD4hep: " + err.str());
625  return false;
626 }
627 
629 VolumeManager::Context* VolumeManager::lookupContext(VolumeID volume_id) const {
630  if (isValid()) {
631  Context* c = 0;
632  const Object& o = _data();
633  bool is_top = o.top == ptr();
634  bool one_tree = (o.flags & ONE) == ONE;
635  if (!is_top && one_tree) {
636  return VolumeManager(Ref_t(o.top)).lookupContext(volume_id);
637  }
638  VolumeID id = volume_id;
640  c = o.search(id);
641  if (c)
642  return c;
644  if (!one_tree) {
645  for (Detectors::const_iterator j = o.subdetectors.begin(); j != o.subdetectors.end(); ++j) {
646  if ((c = (*j).second._data().search(id)) != 0)
647  return c;
648  }
649  }
650  stringstream err;
651  err << "VolumeManager::lookupContext: Failed to search Volume context [Unknown identifier]"
652  << (void*) volume_id;
653  throw runtime_error("DD4hep: " + err.str());
654  }
655  throw runtime_error("DD4hep: VolumeManager::lookupContext: "
656  "Failed to search Volume context [Invalid Manager Handle]");
657 }
658 
660 PlacedVolume VolumeManager::lookupPlacement(VolumeID volume_id) const {
661  Context* c = lookupContext(volume_id);
662  return c->placement;
663 }
664 
666 DetElement VolumeManager::lookupDetector(VolumeID volume_id) const {
667  Context* c = lookupContext(volume_id);
668  return c->detector;
669 }
670 
672 DetElement VolumeManager::lookupDetElement(VolumeID volume_id) const {
673  Context* c = lookupContext(volume_id);
674  return c->element;
675 }
676 
678 const TGeoMatrix& VolumeManager::worldTransformation(VolumeID volume_id) const {
679  Context* c = lookupContext(volume_id);
680  return c->toWorld;
681 }
682 
684 std::ostream& DD4hep::Geometry::operator<<(std::ostream& os, const VolumeManager& m) {
686  VolumeManager::Object* top = dynamic_cast<VolumeManager::Object*>(o.top);
687  bool isTop = top == &o;
688  //bool hasTop = (o.flags & VolumeManager::ONE) == VolumeManager::ONE;
689  //bool isSdet = (o.flags & VolumeManager::TREE) == VolumeManager::TREE && top != &o;
690  string prefix(isTop ? "" : "++ ");
691  os << prefix << (isTop ? "TOP Level " : "Secondary ") << "Volume manager:"
692  << &o << " " << o.detector.name() << " IDD:"
693  << o.id.toString() << " SysID:" << (void*) o.sysID << " "
694  << o.managers.size() << " subsections " << o.volumes.size()
695  << " placements ";
696  if (!(o.managers.empty() && o.volumes.empty()))
697  os << endl;
698  for (VolumeManager::Volumes::const_iterator i = o.volumes.begin(); i != o.volumes.end(); ++i) {
699  const VolumeManager::Context* c = (*i).second;
700  PlacedVolume pv = c->placement;
701  os << prefix << "PV:" << setw(32) << left << pv.name()
702  << " id:" << setw(18) << left << (void*) c->identifier << " mask:"
703  << setw(18) << left << (void*) c->mask << endl;
704  }
705  for (VolumeManager::Managers::const_iterator i = o.managers.begin(); i != o.managers.end(); ++i)
706  os << prefix << (*i).second << endl;
707  return os;
708 }
709 
710 // #if 0
711 
712 // It was wishful thinking, the implementation of the reverse lookups would be as simple.
713 // Hence the folling calls are removed for the time being.
714 
715 // Markus Frank
716 
717 // /** This set of functions is required when reading/analyzing
718 // * already created hits which have a VolumeID attached.
719 // */
720 // /// Lookup the context, which belongs to a registered physical volume.
721 // Context* lookupContext(PlacedVolume vol) const throw();
722 // /// Access the physical volume identifier from the placed volume
723 // VolumeID lookupID(PlacedVolume vol) const;
724 // /// Lookup a top level subdetector detector element according to a contained 64 bit hit ID
725 // DetElement lookupDetector(PlacedVolume vol) const;
726 // /// Lookup the closest subdetector detector element in the hierarchy according to a contained 64 bit hit ID
727 // DetElement lookupDetElement(PlacedVolume vol) const;
728 // /// Access the transformation of a physical volume to the world coordinate system
729 // const TGeoMatrix& worldTransformation(PlacedVolume vol) const;
730 
731 // /// Lookup the context, which belongs to a registered physical volume.
732 // VolumeManager::Context* VolumeManager::lookupContext(PlacedVolume pv) const throw() {
733 // if ( isValid() ) {
734 // Context* c = 0;
735 // const Object& o = _data();
736 // if ( o.top != ptr() && (o.flags&ONE) == ONE ) {
737 // return VolumeManager(Ref_t(o.top)).lookupContext(pv);
738 // }
739 // /// First look in our own volume cache if the entry is found.
740 // c = o.search(pv);
741 // if ( c ) return c;
742 // /// Second: look in the subdetector volume cache if the entry is found.
743 // for(Detectors::const_iterator j=o.subdetectors.begin(); j != o.subdetectors.end(); ++j) {
744 // if ( (c=(*j).second._data().search(pv)) != 0 )
745 // return c;
746 // }
747 // throw runtime_error("VolumeManager::lookupContext: Failed to search Volume context [Unknown identifier]");
748 // }
749 // throw runtime_error("VolumeManager::lookupContext: Failed to search Volume context [Invalid Manager Handle]");
750 // }
751 
752 // /// Access the physical volume identifier from the placed volume
753 // VolumeManager::VolumeID VolumeManager::lookupID(PlacedVolume vol) const {
754 // Context* c = lookupContext(vol);
755 // return c->identifier;
756 // }
757 
758 // /// Lookup a top level subdetector detector element according to a contained 64 bit hit ID
759 // DetElement VolumeManager::lookupDetector(PlacedVolume vol) const {
760 // Context* c = lookupContext(vol);
761 // return c->detector;
762 // }
763 
764 // /// Lookup the closest subdetector detector element in the hierarchy according to a contained 64 bit hit ID
765 // DetElement VolumeManager::lookupDetElement(PlacedVolume vol) const {
766 // Context* c = lookupContext(vol);
767 // return c->element;
768 // }
769 
770 // /// Access the transformation of a physical volume to the world coordinate system
771 // const TGeoMatrix& VolumeManager::worldTransformation(PlacedVolume vol) const {
772 // Context* c = lookupContext(vol);
773 // return c->toWorld;
774 // }
775 
776 // #endif
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
VolumeManager addSubdetector(DetElement detector, Readout ro)
Add a new Volume manager section according to a new subdetector.
bool adoptPlacement(Context *context)
Register physical volume with the manager (normally: section manager)
VolIDs volID
Volume IDS corresponding to this element.
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:135
Volume volume() const
Logical volume of this placement.
Definition: Volumes.cpp:389
Detectors subdetectors
The container of subdetector elements.
const VolIDs & volIDs() const
Access to the volume IDs.
Definition: Volumes.cpp:399
TGeoHMatrix toDetector
The transformation of space-points to the corrdinate system of the closests detector element...
DetElement element
Handle to the closest Detector element.
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
Volumes volumes
The container of placements managed by this instance.
Handle< T > & clear()
Release the object held by the handle.
Definition: Handle.h:132
std::string toString() const
Access string representation.
Q * data() const
Access to an unrelated object type.
Definition: Handle.h:157
VolumeManagerObject * top
The reference to the TOP level VolumeManager.
const char * yes_no(bool value)
Helper function to print booleans in format YES/NO.
Definition: Printout.h:295
Object & _data() const
Additional data accessor.
Definition: VolumeManager.h:94
TGeoHMatrix toWorld
The transformation of space-points to the world corrdinate system.
VolumeID mask
Ignore mask of the placement identifier.
void callAtUpdate(unsigned int typ, Q *pointer, void(T::*pmf)(unsigned long typ, DetElement &det, void *opt_par)) const
Extend the detector element with an arbitrary callback.
Definition: Detector.h:307
This structure describes the cached data for one placement held by the volume manager.
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
DetElement detector
The Detector element handle managed by this instance.
int except(const std::string &src, const std::string &fmt,...)
Calls the display action with ERROR and throws an std::runtime_error exception.
Definition: Printout.cpp:217
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
std::ostream & operator<<(std::ostream &os, const VolumeManager &m)
Enable printouts for debugging.
DD4hep::Geometry::DetElement DetElement
Field system
The system field descriptor.
Context * search(const VolumeID &id) const
Search the locally cached volumes for a matching ID.
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:237
Volume::Object * _data(const Volume &v, bool throw_exception=true)
Accessor to the data part of the Volume.
Definition: Volumes.cpp:464
This structure describes the internal data of the volume manager object.
Field field(const std::string &field_name) const
Get the field descriptor of one field by name.
VolumeID identifier
Placement identifier.
IDDescriptor idSpec() const
Access IDDescription structure.
Definition: Readout.cpp:109
Q & object() const
Access to an unrelated object type.
Definition: Handle.h:161
DD4hep::Geometry::SensitiveDetector SensitiveDetector
const std::string & path() const
Path of the detector element (not necessarily identical to placement path!)
Definition: Detector.cpp:160
PlacedVolume placement() const
Access to the physical volume of this detector element.
Definition: Detector.cpp:279
Handle< NamedObject > Ref_t
Default Ref_t definition describing named objects.
Definition: Handle.h:176
Context * lookupContext(VolumeID volume_id) const
Lookup the context, which belongs to a registered physical volume.
Handle class describing a detector element.
Definition: Detector.h:172
Class to support the retrieval of detector elements and volumes given a valid identifier.
Definition: VolumeManager.h:70
#define DEBUG
std::vector< VolID >::const_iterator find(const std::string &name) const
Find entry.
Definition: Volumes.cpp:341
Path path
Path of placements to this sensitive volume.
Readout readout() const
Access readout structure of the sensitive detector.
Definition: Detector.cpp:451
DetElement detector
Handle to the subdetector element handle.
long long int VolumeID
Definition: Primitives.h:35
The main interface to the DD4hep detector description package.
Definition: LCDD.h:82
static const double second
Definition: DD4hepUnits.h:112
std::map< std::string, DetElement > Children
Definition: Detector.h:202
Data class with properties of a detector element.
int printout(PrintLevel severity, const char *src, const char *fmt,...)
Calls the display action with a given severity level.
Definition: Printout.cpp:111
Managers managers
The volume managers for the individual subdetector elements.
IDDescriptor id
The ID descriptor object.
Class implementing the ID encoding of detector response.
Definition: IDDescriptor.h:40
const TGeoHMatrix & worldTransformation() const
Set detector element for reference transformations. Will delete existing reference trafo...
Definition: Detector.cpp:375
TGeoShape TGeoMedium * m
Definition: Volumes.cpp:294
Geometry::IDDescriptor IDDescriptor
bool isSensitive() const
Accessor if volume is sensitive (ie. is attached to a sensitive detector)
Definition: Volumes.cpp:749