DD4hep  1.38.0
Detector Description Toolkit for High Energy Physics
Volumes.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/Detector.h>
16 #include <DD4hep/Printout.h>
17 #include <DD4hep/InstanceCount.h>
18 #include <DD4hep/MatrixHelpers.h>
20 
21 // ROOT include files
22 #include <TROOT.h>
23 #include <TClass.h>
24 #include <TColor.h>
25 #include <TGeoShape.h>
26 #include <TGeoVolume.h>
27 #include <TGeoNode.h>
28 #include <TGeoMatrix.h>
29 #include <TGeoMedium.h>
30 
31 #include <TGeoVoxelFinder.h>
32 #include <TGeoShapeAssembly.h>
33 #include <TGeoScaledShape.h>
34 #include <TMap.h>
35 
36 // C/C++ include files
37 #include <climits>
38 #include <iostream>
39 #include <stdexcept>
40 #include <sstream>
41 #include <iomanip>
42 
43 using namespace dd4hep;
44 
45 /*
46  * The section below uses the new ROOT features using user extensions to volumes
47  * and placements. Once this is common, the above mechanism should be thrown away....
48  *
49  * M.Frank
50  */
51 
52 typedef TGeoNode geo_node_t;
53 typedef TGeoVolume geo_volume_t;
54 typedef TGeoVolumeAssembly geo_assembly_t;
55 
60 
61 namespace {
62 
63  static constexpr double s_rotation_test_limit = 1e-12;
64  static bool s_verifyCopyNumbers = true;
65 
66  template <typename T> typename T::Object* _userExtension(const T& v) {
67  typedef typename T::Object O;
68  O* o = (O*)(v.ptr()->GetUserExtension());
69  return o;
70  }
71 
72  TGeoVolume* _createTGeoVolume(const std::string& name, TGeoShape* s, TGeoMedium* m) {
73  geo_volume_t* e = new geo_volume_t(name.c_str(),s,m);
74  e->SetUserExtension(new Volume::Object());
75  return e;
76  }
77  TGeoVolume* _createTGeoVolumeAssembly(const std::string& name) {
78  geo_assembly_t* e = new geo_assembly_t(name.c_str()); // It is important to use the correct constructor!!
79  e->SetUserExtension(new Assembly::Object());
80  return e;
81  }
82  TGeoVolumeMulti* _createTGeoVolumeMulti(const std::string& name, TGeoMedium* medium) {
83  TGeoVolumeMulti* e = new TGeoVolumeMulti(name.c_str(), medium);
84  e->SetUserExtension(new VolumeMulti::Object());
85  return e;
86  }
87  PlacedVolume::Object* _data(const PlacedVolume& v) {
88  PlacedVolume::Object* o = _userExtension(v);
89  if (o) return o;
90  except("PlacedVolume::_data", "+++ Attempt to access invalid handle of type: PlacedVolume");
91  return nullptr;
92  }
94  Volume::Object* _data(const Volume& v, bool throw_exception = true) {
95  //if ( v.ptr() && v.ptr()->IsA() == TGeoVolume::Class() ) return v.data<Volume::Object>();
96  Volume::Object* o = _userExtension(v);
97  if (o)
98  return o;
99  else if (!throw_exception)
100  return nullptr;
101  except("Volume::_data", "+++ Attempt to access invalid handle of type: Volume");
102  return nullptr;
103  }
104 
105  class VolumeImport {
106  public:
107  void setShapeTitle(TGeoVolume* vol) {
108  if ( vol ) {
109  TGeoShape* sh = vol->GetShape();
110  std::string tag = get_shape_tag(sh);
111  sh->SetTitle(tag.c_str());
112  }
113  }
114 
115  public:
117  void operator()(TGeoVolume* v) {
118  TClass* c = v->IsA();
119  if( !v->GetUserExtension() ) {
120  if( c == geo_volume_t::Class() )
121  v->SetUserExtension(new Volume::Object());
122  else if( c == geo_assembly_t::Class() )
123  v->SetUserExtension(new Assembly::Object());
124  else if( c == TGeoVolumeMulti::Class() )
125  v->SetUserExtension(new VolumeMulti::Object());
126  else
127  except("dd4hep","VolumeImport: Unknown TGeoVolume sub-class: %s",v->IsA()->GetName());
128  }
129  if( c == TGeoVolumeMulti::Class() ) {
130  TGeoVolumeMulti* mv = (TGeoVolumeMulti*)v;
131  for( int i=0, n=mv->GetNvolumes(); i<n; ++i ) {
132  TGeoVolume* vol = mv->GetVolume(i);
133  this->setShapeTitle(vol);
134  (*this)(vol);
135  }
136  }
137  for( Int_t i=0; i<v->GetNdaughters(); ++i ) {
138  geo_node_t* pv = v->GetNode(i);
139  if( !pv->GetUserExtension() ) {
140  printout(DEBUG, "VolumeImport",
141  "+++ Add placement user extension. parent: %s placement: %s.",
142  v->GetName(), pv->GetName() );
143  pv->geo_node_t::SetUserExtension(new PlacedVolume::Object());
144  }
145  (*this)(pv->GetVolume());
146  }
147  }
149  void operator()(TGeoVolume* new_v, TGeoVolume* old_v, SensitiveDetector sd, int set_bit) {
150  if ( !new_v || !old_v ) {
151  except("dd4hep","VolumeImport: ERROR: The refected volume is INVALID!");
152  }
153  else if ( !old_v->GetUserExtension() ) {
154  except("dd4hep","VolumeImport: ERROR: Reflection of non-dd4hep volume %s",new_v->IsA()->GetName());
155  }
156  else if ( !new_v->GetUserExtension() ) {
157  TClass* c = new_v->IsA();
158  Volume old_vol(old_v);
159  Volume new_vol(new_v);
160  if ( sd.isValid() && old_vol.isSensitive() ) {
161  new_vol.setSensitiveDetector(sd);
162  }
163  if ( c == geo_volume_t::Class() ) {
164  Volume::Object *new_e, *old_e = (Volume::Object*)_data(old_vol);
165  old_e->reflected = new_v;
166  new_v->SetUserExtension(new_e = new Volume::Object(*old_e));
167  new_e->reflected = old_v;
168  }
169  else if ( c == geo_assembly_t::Class() ) {
170  Assembly::Object *new_e, *old_e = (Assembly::Object*)_data(old_vol);
171  old_e->reflected = new_v;
172  new_v->SetUserExtension(new_e = new Assembly::Object(*old_e));
173  new_e->reflected = old_v;
174  }
175  else if ( c == TGeoVolumeMulti::Class() ) {
176  VolumeMulti::Object *new_e, *old_e = (VolumeMulti::Object*)_data(old_vol);
177  TGeoVolumeMulti* new_mv = (TGeoVolumeMulti*)new_v;
178  TGeoVolumeMulti* old_mv = (TGeoVolumeMulti*)old_v;
179  new_v->SetUserExtension(new_e = new VolumeMulti::Object(*old_e));
180  old_e->reflected = new_v;
181  new_e->reflected = old_v;
182  for(int i=0, n=new_mv->GetNvolumes(); i<n; ++i) {
183  TGeoVolume* vol = new_mv->GetVolume(i);
184  this->setShapeTitle(vol);
185  (*this)(vol, old_mv->GetVolume(i), sd, set_bit);
186  }
187  }
188  else
189  except("dd4hep","VolumeImport: Unknown TGeoVolume sub-class: %s",new_v->IsA()->GetName());
190 
191  new_vol.setSensitiveDetector(old_vol.sensitiveDetector());
192  new_vol.setVisAttributes(old_vol.visAttributes());
193  new_vol.setLimitSet(old_vol.limitSet());
194  new_vol.setRegion(old_vol.region());
195 
196  if ( set_bit >= 0 ) new_vol.setFlagBit(set_bit);
197  for(Int_t i=0; i<new_v->GetNdaughters(); ++i) {
198  geo_node_t* pv = new_v->GetNode(i);
199  geo_node_t* ov = old_v->GetNode(i);
200  if ( !pv->GetUserExtension() ) {
201  auto* e = (PlacedVolume::Object*)ov->geo_node_t::GetUserExtension();
202  pv->geo_node_t::SetUserExtension(new PlacedVolume::Object(*e));
203  }
204  (*this)(pv->GetVolume(), ov->GetVolume(), sd, set_bit);
205  }
206  }
207  }
208  };
209 
210  TGeoVolume* MakeReflection(TGeoVolume* v, const char* newname=0) {
211  static TMap map(100);
212  TGeoVolume* vol = (TGeoVolume*)map.GetValue(v);
213  if ( vol ) {
214  if (newname && newname[0]) v->SetName(newname);
215  return vol;
216  }
217  vol = v->CloneVolume();
218  if (!vol) {
219  printout(ERROR,"MakeReflection", "Cannot clone volume %s\n", v->GetName());
220  return nullptr;
221  }
222  map.Add(v, vol);
223  std::string nam;
224  if (newname && newname[0]) {
225  nam = newname;
226  vol->SetName(newname);
227  }
228  else {
229  nam = v->GetName();
230  vol->SetName((nam+"_refl").c_str());
231  }
232  delete vol->GetNodes();
233  vol->SetNodes(nullptr);
234  vol->SetBit(TGeoVolume::kVolumeImportNodes, kFALSE);
235  v->CloneNodesAndConnect(vol);
236  // The volume is now properly cloned, but with the same shape.
237  // Reflect the shape (if any) and connect it.
238  if (v->GetShape()) {
239  TGeoScale* scale = new TGeoScale( 1., 1.,-1.);
240  TGeoShape* reflected_shape =
241  TGeoScaledShape::MakeScaledShape((nam+"_shape_refl").c_str(), v->GetShape(), scale);
242  vol->SetShape(reflected_shape);
243  //vol->SetShape(v->GetShape());
244  }
245  // Reflect the daughters.
246  Int_t nd = vol->GetNdaughters();
247  if ( !nd ) return vol;
248  TGeoVolume *new_vol;
249  if ( !vol->GetFinder() ) {
250  for (Int_t i=0; i < nd; i++) {
251  TGeoNodeMatrix* node = (TGeoNodeMatrix*)vol->GetNode(i);
252  TGeoMatrix* local = node->GetMatrix();
253  // printf("%s before\n", node->GetName());
254  // local->Print();
255  Bool_t reflected = local->IsReflection();
256  TGeoMatrix* local_cloned = new TGeoCombiTrans(*local);
257  local_cloned->RegisterYourself();
258  node->SetMatrix(local_cloned);
259  if (!reflected) {
260  // We need to reflect only the translation and propagate to daughters.
261  // H' = Sz * H * Sz
262  local_cloned->ReflectZ(kTRUE);
263  local_cloned->ReflectZ(kFALSE);
264  // printf("%s after\n", node->GetName());
265  // node->GetMatrix()->Print();
266  new_vol = MakeReflection(node->GetVolume());
267  node->SetVolume(new_vol);
268  continue;
269  }
270  // The next daughter is already reflected, so reflect on Z everything and stop
271  local_cloned->ReflectZ(kTRUE); // rot + tr
272  // printf("%s already reflected... After:\n", node->GetName());
273  // node->GetMatrix()->Print();
274  }
275  if ( vol->GetVoxels() ) vol->GetVoxels()->Voxelize();
276  return vol;
277  }
278  // Volume is divided, so we have to reflect the division.
279  // printf(" ... divided %s\n", fFinder->ClassName());
280  TGeoPatternFinder *new_finder = v->GetFinder()->MakeCopy(kTRUE);
281  if (!new_finder) {
282  printout(ERROR,"MakeReflection", "Could not copy finder for volume %s", v->GetName());
283  return nullptr;
284  }
285  new_finder->SetVolume(vol);
286  vol->SetFinder(new_finder);
287  TGeoNodeOffset *nodeoff;
288  new_vol = 0;
289  for (Int_t i=0; i<nd; i++) {
290  nodeoff = (TGeoNodeOffset*)vol->GetNode(i);
291  nodeoff->SetFinder(new_finder);
292  new_vol = MakeReflection(nodeoff->GetVolume());
293  nodeoff->SetVolume(new_vol);
294  }
295  return vol;
296  }
297 
298  int get_copy_number(TGeoVolume* par) {
299  TObjArray* a = par ? par->GetNodes() : 0;
300  int copy_nr = (a ? a->GetEntries() : 0);
301  return copy_nr;
302  }
303 
304 }
305 
307 void ReflectionBuilder::execute() const {
308  TGeoIterator next(detector.manager().GetTopVolume());
309  bool print_active = isActivePrintLevel(DEBUG);
310  TGeoNode *node;
311  while ( (node=next()) ) {
312  TGeoMatrix* matrix = node->GetMatrix();
313  if (matrix->IsReflection()) {
314  if ( print_active ) {
315  printout(INFO,"ReflectionBuilder","Reflection matrix:");
316  matrix->Print();
317  }
318  Volume vol(node->GetVolume());
319  TGeoMatrix* mclone = new TGeoCombiTrans(*matrix);
320  mclone->RegisterYourself();
321  // Reflect just the rotation component
322  //mclone->ReflectZ(kFALSE, kTRUE);
323  if ( print_active ) {
324  printout(INFO,"ReflectionBuilder","CLONE matrix:");
325  mclone->Print();
326  }
327  TGeoNodeMatrix* nodematrix = (TGeoNodeMatrix*)node;
328  nodematrix->SetMatrix(mclone);
329  if ( print_active ) {
330  printout(INFO,"ReflectionBuilder","Reflected volume: %s ", vol.name());
331  }
332  Volume refl = vol.reflect(vol.sensitiveDetector());
333  node->SetVolume(refl.ptr());
334  }
335  }
336 }
337 
340 }
341 
344 }
345 
348  ++refCount;
349  return this;
350 }
353  --refCount;
354  if ( 0 == refCount ) delete this;
355 }
356 
359  : TGeoExtension(), volIDs()
360 {
361  magic = magic_word();
363 }
364 
367  : TGeoExtension(c), magic(std::move(c.magic)), refCount(0), volIDs(std::move(c.volIDs)) {
369 }
370 
373  : TGeoExtension(), magic(c.magic), refCount(0), volIDs() {
375  volIDs = c.volIDs;
376 }
377 
380  if ( this->params ) this->params->release();
382 }
383 
386  magic = std::move(copy.magic);
387  params = std::move(copy.params);
388  volIDs = std::move(copy.volIDs);
389  return *this;
390 }
393  magic = copy.magic;
394  params = copy.params;
395  volIDs = copy.volIDs;
396  return *this;
397 }
398 
401  ++this->refCount;
402 #ifdef ___print_vols
403  else cout << "Placement grabbed....." << endl;
404 #endif
405  return this;
406 }
407 
410  PlacedVolumeExtension* ext = const_cast<PlacedVolumeExtension*>(this);
411  --ext->refCount;
412  if ( 0 == ext->refCount ) delete ext;
413 }
414 
416 std::vector<PlacedVolumeExtension::VolID>::const_iterator
417 PlacedVolumeExtension::VolIDs::find(const std::string& name) const {
418  for (Base::const_iterator i = this->Base::begin(); i != this->Base::end(); ++i)
419  if (name == (*i).first)
420  return i;
421  return this->end();
422 }
423 
425 std::pair<std::vector<PlacedVolumeExtension::VolID>::iterator, bool>
426 PlacedVolumeExtension::VolIDs::insert(const std::string& name, int value) {
427  Base::iterator i = this->Base::begin();
428  for (; i != this->Base::end(); ++i)
429  if (name == (*i).first)
430  break;
431  //
432  if (i != this->Base::end()) {
433  return make_pair(i, false);
434  }
435  i = this->Base::emplace(this->Base::end(), name, value);
436  return make_pair(i, true);
437 }
438 
441  std::stringstream str;
442  str << std::hex;
443  for(const auto& i : *this ) {
444  str << i.first << "=" << std::setw(4) << std::right
445  << std::setfill('0') << i.second << std::setfill(' ') << " ";
446  }
447  return str.str();
448 }
449 
452  PlacedVolume::Object* o = _userExtension(*this);
453  return o;
454 }
455 
457 const char* PlacedVolume::type() const {
458  return m_element ? m_element->IsA()->GetName() : "UNKNOWN-PlacedVolume";
459 }
460 
463  return m_element ? m_element->GetNumber() : -1;
464 }
465 
468  return Material(m_element ? m_element->GetMedium() : 0);
469 }
470 
473  return Volume(m_element ? m_element->GetVolume() : 0);
474 }
475 
478  return Volume(m_element ? m_element->GetMotherVolume() : 0);
479 }
480 
482 std::size_t PlacedVolume::num_daughters() const {
483  return m_element ? m_element->GetNdaughters() : 0;
484 }
485 
487 PlacedVolume PlacedVolume::daughter(std::size_t which) const {
488  if ( m_element ) {
489  if ( which < (std::size_t)m_element->GetNdaughters() ) {
490  return m_element->GetDaughter(which);
491  }
492  except("Volume","+++ Access daughter %ld of %s [Has only %d daughters]",
493  which, m_element->GetName(), m_element->GetNdaughters());
494  }
495  except("Volume","+++ Cannot access daughters of a non-existing volume!");
496  return nullptr;
497 }
498 
501  return _data(*this)->volIDs;
502 }
503 
505 PlacedVolume& PlacedVolume::addPhysVolID(const std::string& nam, int value) {
506  auto* o = _data(*this);
507  if ( !o->params ) {
508  o->volIDs.emplace_back(nam, value);
509  return *this;
510  }
511  if ( value > 0 ) {
512  except("PlacedVolume",
513  "+++ addPhysVolID(%s): parameterised volumes only accept '0' is volID."
514  "These automatically get overwritten with the copy number!",
515  ptr()->GetName());
516  }
517  if ( !o->volIDs.empty() ) {
518  except("PlacedVolume",
519  "+++ addPhysVolID(%s): parameterised volumes can only host 1 physical volume ID."
520  " vol id '%s' is already defined!", ptr()->GetName(), o->volIDs[0].first.c_str());
521  }
522  for(PlacedVolume pv : o->params->placements) {
523  auto* p = _data(pv);
524  p->volIDs.emplace_back(nam, pv->GetNumber());
525  }
526  return *this;
527 }
528 
530 const TGeoMatrix& PlacedVolume::matrix() const {
531  if ( !isValid() ) {
532  except("PlacedVolume","+++ matrix: Failed to access invalid PlacedVolume! [Invalid handle]");
533  }
534  return *(m_element->GetMatrix());
535 }
536 
539  const double* ptr = matrix().GetTranslation();
540  return Position(ptr[0],ptr[1],ptr[2]);
541 }
542 
544 std::string PlacedVolume::toString() const {
545  std::stringstream str;
546  Object* obj = _data(*this);
547  str << m_element->GetName() << ": vol='" << m_element->GetVolume()->GetName()
548  << "' mat:'" << m_element->GetMatrix()->GetName()
549  << "' volID[" << obj->volIDs.size() << "] ";
550  for (VolIDs::const_iterator i = obj->volIDs.begin(); i != obj->volIDs.end(); ++i)
551  str << (*i).first << "=" << (*i).second << " ";
552  str << std::ends;
553  return str.str();
554 }
555 
558 : TGeoExtension(), region(), limits(), vis(), sens_det() {
560 }
561 
564  detail::deletePtr(properties);
565  region.clear();
566  limits.clear();
567  vis.clear();
568  sens_det.clear();
570 }
571 
574  this->copy(c);
575 }
576 
579  this->copy(c);
580  return *this;
581 }
582 
585  if ( this != &c ) {
586  magic = c.magic;
587  region = c.region;
588  limits = c.limits;
589  vis = c.vis;
590  sens_det = c.sens_det;
592  detail::deletePtr(properties);
593  if ( c.properties ) {
594  properties = new TList();
595  properties->SetOwner();
596  TIter next(properties);
597  TNamed *property;
598  while ((property = (TNamed*)next())) properties->Add(new TNamed(*property));
599  }
600  }
601 }
602 
605  VolumeExtension* ext = const_cast<VolumeExtension*>(this);
606  ++ext->refCount;
607 #ifdef ___print_vols
608  if ( ext->sens_det.isValid() )
609  cout << "Volume grabbed with valid sensitive detector....." << endl;
610  else
611  cout << "Volume grabbed....." << endl;
612 #endif
613  return ext;
614 }
615 
618  VolumeExtension* ext = const_cast<VolumeExtension*>(this);
619  --ext->refCount;
620  if ( 0 == ext->refCount ) {
621 #ifdef ___print_vols
622  cout << "Volume deleted....." << endl;
623 #endif
624  delete ext;
625  }
626  else {
627 #ifdef ___print_vols
628  cout << "VolumeExtension::Release::refCount:" << ext->refCount << endl;
629 #endif
630  }
631 }
632 
634 Volume::Volume(const std::string& nam) {
635  m_element = _createTGeoVolume(nam,0,0);
636 }
637 
639 Volume::Volume(const std::string& nam, const std::string& title) {
640  m_element = _createTGeoVolume(nam,0,0);
641  m_element->SetTitle(title.c_str());
642 }
643 
645 Volume::Volume(const std::string& nam, const Solid& sol, const Material& mat) {
646  m_element = _createTGeoVolume(nam, sol.ptr(), mat.ptr());
647 }
648 
650 Volume::Volume(const std::string& nam, const std::string& title, const Solid& sol, const Material& mat) {
651  m_element = _createTGeoVolume(nam, sol.ptr(), mat.ptr());
652  m_element->SetTitle(title.c_str());
653 }
654 
657  s_verifyCopyNumbers = value;
658 }
659 
662  Volume::Object* o = _userExtension(*this);
663  return o;
664 }
665 
667 const char* Volume::type() const {
668  return m_element ? m_element->IsA()->GetName() : "UNKNOWN-Volume";
669 }
670 
673  return this->reflect(this->sensitiveDetector());
674 }
675 
678  if ( m_element ) {
679  VolumeImport imp;
680  Object* o = data();
681  if ( !o->reflected.isValid() ) {
682  TGeoVolume* vol = MakeReflection(m_element);
683  imp(vol, m_element, sd, Volume::REFLECTED);
684  o->reflected = vol;
685  }
686  return o->reflected;
687  }
688  except("dd4hep","Volume: Attempt to reflect an invalid Volume handle.");
689  return *this;
690 }
691 
694  if ( m_element ) {
695  VolumeImport imp;
696  imp(m_element);
697  return *this;
698  }
699  except("dd4hep","Volume: Attempt to import an invalid Volume handle.");
700  return *this;
701 }
702 
704 void Volume::setFlagBit(unsigned int bit) {
705  if ( bit <= 31 ) {
706  data()->flags |= 1<<bit;
707  return;
708  }
709  except("Volume","+++ Volume flag bit outsize range [0...31]: %d",bit);
710 }
711 
713 bool Volume::testFlagBit(unsigned int bit) const {
714  if ( bit <= 31 ) {
715  return (data()->flags & 1<<bit) != 0;
716  }
717  except("Volume","+++ Volume flag bit outsize range [0...31]: %d",bit);
718  return false; // Anyhow never called. Only to satisfy the compiler.
719 }
720 
722 bool Volume::isReflected() const {
723  return testFlagBit(REFLECTED);
724 }
725 
727 bool Volume::isAssembly() const {
728  return m_element ? m_element->IsAssembly() : false;
729 }
730 
732 double Volume::setSmartlessValue(double new_value) {
733  Object* obj = _data(*this);
734  double tmp = obj->smartLess;
735  obj->smartLess = new_value;
736  return tmp;
737 }
738 
740 double Volume::smartlessValue() const {
741  return _data(*this)->smartLess;
742 }
743 
745 Volume Volume::divide(const std::string& divname, int iaxis, int ndiv,
746  double start, double step, int numed, const char* option) {
747  TGeoVolume* p = m_element;
748  if ( p ) {
749  TGeoVolume* mvp = p->Divide(divname.c_str(), iaxis, ndiv, start, step, numed, option);
750  if ( mvp ) {
751  Volume(p).import();
752  Volume(mvp).import();
753 #if 0
754  VolumeImport imp;
755  imp(mvp);
756  imp(p);
757  return VolumeMulti(mvp);
758 #endif
759  return { mvp };
760  }
761  except("dd4hep","Volume: Failed to divide volume %s -> %s [Invalid result]",
762  p->GetName(), divname.c_str());
763  }
764  except("dd4hep","Volume: Attempt to divide an invalid logical volume.");
765  return nullptr;
766 }
767 
768 PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* transform) {
769  TGeoVolume* parent = par;
770  if ( !parent ) {
771  except("dd4hep","Volume: Attempt to assign daughters to an invalid physical parent volume.");
772  }
773  else if ( !daughter ) {
774  except("dd4hep","Volume: Attempt to assign an invalid physical daughter volume.");
775  }
776  else if ( !transform ) {
777  except("dd4hep","Volume: Attempt to place volume without placement matrix.");
778  }
779  if ( transform != detail::matrix::_identity() ) {
780  std::string nam = std::string(daughter->GetName()) + "_placement";
781  transform->SetName(nam.c_str());
782  }
783  TGeoShape* shape = daughter->GetShape();
784  // Need to fix the daughter's BBox of assemblies, if the BBox was not calculated....
785  if ( shape->IsA() == TGeoShapeAssembly::Class() ) {
786  TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
787  as->NeedsBBoxRecompute();
788  as->ComputeBBox();
789  }
790  const Double_t* r = transform->GetRotationMatrix();
791  if ( r ) {
792  Double_t test_rot = r[0] + r[4] + r[8] - 3.0;
793  if ( TMath::Abs(test_rot) < s_rotation_test_limit )
794  transform->ResetBit(TGeoMatrix::kGeoRotation);
795  else
796  transform->SetBit(TGeoMatrix::kGeoRotation);
797 
798  if ( transform->IsRotation() ) {
799  Double_t det =
800  r[0]*r[4]*r[8] + r[3]*r[7]*r[2] + r[6]*r[1]*r[5] -
801  r[2]*r[4]*r[6] - r[5]*r[7]*r[0] - r[8]*r[1]*r[3];
803  if ( det < 0e0 ) {
804  transform->SetBit(TGeoMatrix::kGeoReflection);
805  printout(DEBUG, "PlacedVolume",
806  "REFLECTION: (x.Cross(y)).Dot(z): %8.3g Parent: %s [%s] Daughter: %s [%s]",
807  det, par->GetName(), par->IsA()->GetName(),
808  daughter->GetName(), daughter->IsA()->GetName());
809  }
810  }
811  }
812  geo_node_t* n {nullptr};
813  TString nam_id = TString::Format("%s_%d", daughter->GetName(), id);
814  if ( s_verifyCopyNumbers ) {
815  n = static_cast<geo_node_t*>(parent->GetNode(nam_id));
816  if ( n != 0 ) {
817  printout(ERROR,"PlacedVolume","++ Attempt to place already exiting node %s",(const char*)nam_id);
818  }
819  }
820  /* n = */ parent->AddNode(daughter, id, transform);
821  //n = static_cast<geo_node_t*>(parent->GetNode(nam_id));
822  n = static_cast<geo_node_t*>(parent->GetNodes()->Last());
823  if ( nam_id != n->GetName() ) {
824  printout(ERROR,"PlacedVolume","++ FAILED to place node %s",(const char*)nam_id);
825  }
826  if( par->IsA() == TGeoVolumeMulti::Class() ) { // Make sure that all daughters of a division are instrumented
827  printout(DEBUG, "PlacedVolume",
828  "++ Insert to multi-volume %s. Ensure all daughters %s are instrumented.",
829  par->GetName(), daughter->GetName() );
830  Volume(par).import();
831  }
832  PlacedVolume::Object* extension = new PlacedVolume::Object();
833  n->geo_node_t::SetUserExtension(extension);
834  return PlacedVolume(n);
835 }
836 
837 PlacedVolume _addNode(TGeoVolume* par, Volume daughter, int copy_nr, const Rotation3D& rot3D) {
838  TGeoRotation r;
839  double elements[9];
840  rot3D.GetComponents(elements);
841  r.SetMatrix(elements);
842  auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(0,0,0),r);
843  return _addNode(par, daughter, copy_nr, matrix.release());
844 }
845 
846 PlacedVolume _addNode(TGeoVolume* par, Volume daughter, int copy_nr, const Transform3D& tr) {
847  TGeoRotation r;
848  double elements[9];
849  Position pos3D;
850  Rotation3D rot3D;
851  tr.GetRotation(rot3D);
852  tr.GetTranslation(pos3D);
853  rot3D.GetComponents(elements);
854  r.SetMatrix(elements);
855  auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(pos3D.x(), pos3D.y(), pos3D.z()),r);
856  return _addNode(par, daughter, copy_nr, matrix.release());
857 }
858 
860 PlacedVolume Volume::placeVolume(const Volume& volume, TGeoMatrix* tr) const {
861  return _addNode(m_element, volume, get_copy_number(m_element), tr);
862 }
863 
865 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_nr, TGeoMatrix* tr) const {
866  return _addNode(m_element, volume, copy_nr, tr);
867 }
868 
870 PlacedVolume Volume::placeVolume(const Volume& volume, const Transform3D& trans) const {
871  return _addNode(m_element, volume, get_copy_number(m_element), trans);
872 }
873 
876  return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_identity());
877 }
878 
880 PlacedVolume Volume::placeVolume(const Volume& volume, const Position& pos) const {
881  return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_translation(pos));
882 }
883 
885 PlacedVolume Volume::placeVolume(const Volume& volume, const RotationZYX& rot) const {
886  return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_rotationZYX(rot));
887 }
888 
890 PlacedVolume Volume::placeVolume(const Volume& volume, const Rotation3D& rot) const {
891  return _addNode(m_element, volume, get_copy_number(m_element), rot);
892 }
893 
895 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Transform3D& trans) const {
896  return _addNode(m_element, volume, copy_no, trans);
897 }
898 
900 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no) const {
901  return _addNode(m_element, volume, copy_no, detail::matrix::_identity());
902 }
903 
905 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Position& pos) const {
906  return _addNode(m_element, volume, copy_no, detail::matrix::_translation(pos));
907 }
908 
910 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const RotationZYX& rot) const {
911  return _addNode(m_element, volume, copy_no, detail::matrix::_rotationZYX(rot));
912 }
913 
915 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Rotation3D& rot) const {
916  return _addNode(m_element, volume, copy_no, rot);
917 }
918 
921  size_t count, double inc, double start)
922 {
923  Transform3D offset(1e0, 0e0, 0e0, axis == X_axis ? start : 0e0,
924  0e0, 1e0, 0e0, axis == Y_axis ? start : 0e0,
925  0e0, 0e0, 1e0, axis == Z_axis ? start : 0e0);
926  Transform3D tr(1e0, 0e0, 0e0, axis == X_axis ? inc : 0e0,
927  0e0, 1e0, 0e0, axis == Y_axis ? inc : 0e0,
928  0e0, 0e0, 1e0, axis == Z_axis ? inc : 0e0);
929  PlacedVolume pv = paramVolume1D(offset, entity, count, tr);
930  auto* data = pv.data();
931  data->params->flags = axis | REPLICATED;
932  return pv;
933 }
934 
936 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const Position& inc) {
937  return paramVolume1D(Transform3D(), entity, count, Transform3D(inc));
938 }
939 
941 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const RotationZYX& inc) {
942  return paramVolume1D(Transform3D(), entity, count, Transform3D(inc));
943 }
944 
946 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const Transform3D& inc) {
947  return paramVolume1D(Transform3D(), entity, count, inc);
948 }
949 
952  Volume entity,
953  size_t count,
954  const Transform3D& trafo)
955 {
956  Transform3D tr(start);
957  PlacedVolume pv =
958  _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr));
959  auto* data = pv.data();
960  if ( pv->GetNdaughters() > 1 ) {
961  except("Volume","paramVolume1D: Mother %s has too many daughters: %ld "
962  "Parameterized volumes may only have one single daughter!",
963  ptr()->GetName(), pv.volume()->GetNdaughters());
964  }
966  data->params->addref();
967  data->params->flags = PARAMETERIZED;
968  data->params->start = start;
969  data->params->trafo1D.first = trafo;
970  data->params->trafo1D.second = count;
971  data->params->trafo2D.second = 0;
972  data->params->trafo3D.second = 0;
973  data->params->placements.emplace_back(pv);
974  for(size_t i=1; i < count; ++i) {
975  tr *= trafo;
976  PlacedVolume ppv =
977  _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr));
978  data->params->placements.emplace_back(ppv);
979  ppv.data()->params = data->params->addref();
980  }
981  return pv;
982 }
983 
986  size_t count_1,
987  const Transform3D& trafo_1,
988  size_t count_2,
989  const Transform3D& trafo_2)
990 {
991  return paramVolume2D(Transform3D(), entity, count_1, trafo_1, count_2, trafo_2);
992 }
993 
996  Volume entity,
997  size_t count_1,
998  const Position& pos_1,
999  size_t count_2,
1000  const Position& pos_2)
1001 {
1002  return paramVolume2D(start, entity, count_1, Transform3D(pos_1), count_2, Transform3D(pos_2));
1003 }
1004 
1007  size_t count_1,
1008  const Position& pos_1,
1009  size_t count_2,
1010  const Position& pos_2)
1011 {
1012  return paramVolume2D(Transform3D(), entity, count_1, Transform3D(pos_1), count_2, Transform3D(pos_2));
1013 }
1014 
1017  Volume entity,
1018  size_t count_1,
1019  const Transform3D& trafo_1,
1020  size_t count_2,
1021  const Transform3D& trafo_2)
1022 {
1023  PlacedVolume pv =
1024  _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(start));
1025  auto* data = pv.data();
1026  if ( pv->GetNdaughters() > 1 ) {
1027  except("Volume","paramVolume1D: Mother %s has too many daughters: %ld "
1028  "Parameterized volumes may only have one single daughter!",
1029  ptr()->GetName(), pv.volume()->GetNdaughters());
1030  }
1032  data->params->addref();
1033  data->params->flags = PARAMETERIZED;
1034  data->params->start = start;
1035  data->params->trafo1D.first = trafo_1;
1036  data->params->trafo1D.second = count_1;
1037  data->params->trafo2D.first = trafo_2;
1038  data->params->trafo2D.second = count_2;
1039  data->params->trafo3D.second = 0;
1040  data->params->placements.emplace_back(pv);
1041  Transform3D tr2(start);
1042  for(size_t j=0; j < count_2; ++j) {
1043  Transform3D tr1 = tr2;
1044  for(size_t i = 0; i < count_1; ++i) {
1045  if ( !( i == 0 && j == 0 ) ) {
1046  PlacedVolume ppv =
1047  _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr1));
1048  data->params->placements.emplace_back(ppv);
1049  ppv.data()->params = data->params->addref();
1050  }
1051  tr1 *= trafo_1;
1052  }
1053  tr2 *= trafo_2;
1054  }
1055  return pv;
1056 }
1057 
1060  Volume entity,
1061  size_t count_1,
1062  const Position& pos_1,
1063  size_t count_2,
1064  const Position& pos_2,
1065  size_t count_3,
1066  const Position& pos_3)
1067 {
1068  return paramVolume3D(start, entity,
1069  count_1, Transform3D(pos_1),
1070  count_2, Transform3D(pos_2),
1071  count_3, Transform3D(pos_3));
1072 }
1073 
1076  size_t count_1,
1077  const Position& pos_1,
1078  size_t count_2,
1079  const Position& pos_2,
1080  size_t count_3,
1081  const Position& pos_3)
1082 {
1083  return paramVolume3D(Transform3D(), entity,
1084  count_1, Transform3D(pos_1),
1085  count_2, Transform3D(pos_2),
1086  count_3, Transform3D(pos_3));
1087 }
1088 
1091  Volume entity,
1092  size_t count_1,
1093  const Transform3D& trafo_1,
1094  size_t count_2,
1095  const Transform3D& trafo_2,
1096  size_t count_3,
1097  const Transform3D& trafo_3)
1098 {
1099  PlacedVolume pv =
1100  _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(start));
1101  auto* data = pv.data();
1102  if ( pv->GetNdaughters() > 1 ) {
1103  except("Volume","paramVolume1D: Mother %s has too many daughters: %ld "
1104  "Parameterized volumes may only have one single daughter!",
1105  ptr()->GetName(), pv.volume()->GetNdaughters());
1106  }
1108  data->params->addref();
1109  data->params->flags = PARAMETERIZED;
1110  data->params->start = start;
1111  data->params->trafo1D.first = trafo_1;
1112  data->params->trafo1D.second = count_1;
1113  data->params->trafo2D.first = trafo_2;
1114  data->params->trafo2D.second = count_2;
1115  data->params->trafo3D.first = trafo_3;
1116  data->params->trafo3D.second = count_3;
1117  data->params->placements.emplace_back(pv);
1118  Transform3D tr3(start);
1119  for(size_t k=0; k < count_3; ++k) {
1120  Transform3D tr2 = tr3;
1121  for(size_t j=0; j < count_2; ++j) {
1122  Transform3D tr1 = tr2;
1123  for(size_t i = 0; i < count_1; ++i) {
1124  if ( !( i == 0 && j == 0 && k == 0 ) ) {
1125  PlacedVolume ppv =
1126  _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr1));
1127  data->params->placements.emplace_back(ppv);
1128  ppv.data()->params = data->params->addref();
1129  }
1130  tr1 *= trafo_1;
1131  }
1132  tr2 *= trafo_2;
1133  }
1134  tr3 *= trafo_3;
1135  }
1136  return pv;
1137 }
1138 
1140 const Volume& Volume::setOption(const std::string& opt) const {
1141  if ( isValid() ) {
1142  m_element->SetOption(opt.c_str());
1143  return *this;
1144  }
1145  throw std::runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume");
1146 }
1147 
1149 std::string Volume::option() const {
1150  return m_element->GetOption();
1151 }
1152 
1154 const Volume& Volume::setMaterial(const Material& mat) const {
1155  if (mat.isValid()) {
1156  TGeoMedium* medium = mat._ptr<TGeoMedium>();
1157  if (medium) {
1158  m_element->SetMedium(medium);
1159  return *this;
1160  }
1161  throw std::runtime_error("dd4hep: Volume: Medium " + std::string(mat.name()) + " is not registered with geometry manager.");
1162  }
1163  throw std::runtime_error("dd4hep: Volume: Attempt to assign invalid material.");
1164 }
1165 
1168  return Material(m_element->GetMedium());
1169 }
1170 
1172 const Volume& Volume::setVisAttributes(const VisAttr& attr) const {
1173  if ( attr.isValid() ) {
1174  VisAttr::Object* vis = attr.data<VisAttr::Object>();
1175  TColor* col = vis->color;
1176  if ( col ) {
1177  int draw_style = vis->drawingStyle;
1178  int line_style = vis->lineStyle;
1179  int col_num = col->GetNumber();
1180  int col_tr_num = vis->colortr->GetNumber();
1181  m_element->SetVisibility(vis->visible ? kTRUE : kFALSE);
1182  m_element->SetVisContainers(kTRUE);
1183  m_element->SetVisDaughters(vis->showDaughters ? kTRUE : kFALSE);
1184  printout(DEBUG,"setVisAttributes",
1185  "Set color %3d transparent(alpha:%.3f): %3d [%02X,%02X,%02X] DrawingStyle:%9s LineStyle:%6s for volume %s",
1186  col_num, vis->alpha, col_tr_num,
1187  int(255*col->GetRed()),
1188  int(255*col->GetGreen()),
1189  int(255*col->GetBlue()),
1190  draw_style == VisAttr::SOLID ? "Solid" : "Wireframe",
1191  line_style == VisAttr::SOLID ? "Solid" : "Dashed",
1192  name()
1193  );
1194  m_element->SetLineWidth(10);
1195  m_element->SetLineColor(col_num);
1196  m_element->SetFillColor(col_tr_num);
1197  if (draw_style == VisAttr::SOLID) {
1198  m_element->SetFillStyle(1001); // Root: solid
1199 
1200 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,0)
1201  // Set directly transparency to the volume, NOT to the material as for ROOT < 6.29
1202  m_element->ResetTransparency(Char_t((1.0-vis->alpha)*100));
1203 #else
1204  // As suggested by Valentin Volkl https://sft.its.cern.ch/jira/browse/DDFORHEP-20
1205  //
1206  // According to https://root.cern.ch/phpBB3/viewtopic.php?t=2309#p66013
1207  // a transparency>50 will make a volume invisible in the normal pad.
1208  // Hence: possibly restrict transparency to a maximum of 50.
1209  // but let's see first how this behaves.
1210  m_element->SetTransparency(Char_t((1.0-vis->alpha)*100));
1211 #endif
1212  }
1213  else {
1214  printout(DEBUG,"setVisAttributes","Set to wireframe vis:%s",name());
1215  m_element->SetLineColor(kBlack);
1216  m_element->SetFillColor(0);
1217  m_element->SetFillStyle(0); // Root: hollow
1218  }
1219  if (line_style == VisAttr::SOLID) // Root line style: 1=solid, 2=dash, 3=dot, 4=dash-dot.
1220  m_element->SetLineStyle(1);
1221  else if (line_style == VisAttr::DASHED)
1222  m_element->SetLineStyle(2);
1223  else
1224  m_element->SetLineStyle(line_style);
1225  }
1226  else {
1227  except("Volume","setVisAttributes: encountered valid, but badly initialized visattr: %s",attr.name());
1228  }
1229  }
1230  Volume::Object* o = _userExtension(*this);
1231  if ( o ) o->vis = attr;
1232  return *this;
1233 }
1234 
1236 const Volume& Volume::setVisAttributes(const Detector& description, const std::string& nam) const {
1237  if (!nam.empty()) {
1238  VisAttr attr = description.visAttributes(nam);
1239  setVisAttributes(attr);
1240  }
1241  return *this;
1242 }
1243 
1245 const Volume& Volume::setAttributes(const Detector& description, const std::string& rg, const std::string& ls, const std::string& vis) const {
1246  if (!rg.empty())
1247  setRegion(description.region(rg));
1248  if (!ls.empty())
1249  setLimitSet(description.limitSet(ls));
1250  setVisAttributes(description, vis);
1251  return *this;
1252 }
1253 
1256  Object* o = _data(*this, false);
1257  if (o) return o->vis;
1258  return VisAttr();
1259 }
1260 
1262 const Volume& Volume::setSolid(const Solid& sol) const {
1263  m_element->SetShape(sol);
1264  return *this;
1265 }
1266 
1269  return Solid((*this)->GetShape());
1270 }
1271 
1274  Box box = this->solid();
1275  if ( box.isValid() ) {
1276  return box;
1277  }
1278  else if ( !isValid() ) {
1279  except("dd4hep","Volume: Cannot access the bounding box of an invalid volume [Invalid Handle]!");
1280  }
1281  except("dd4hep","Volume: Cannot access the bounding box an object of type: %s shape: %s",
1282  this->ptr()->IsA()->GetName(), this->ptr()->GetShape()->IsA()->GetName());
1283  return box;
1284 }
1285 
1287 const Volume& Volume::setRegion(const Detector& description, const std::string& nam) const {
1288  if (!nam.empty()) {
1289  return setRegion(description.region(nam));
1290  }
1291  return *this;
1292 }
1293 
1295 const Volume& Volume::setRegion(const Region& obj) const {
1296  _data(*this)->region = obj;
1297  return *this;
1298 }
1299 
1302  return _data(*this)->region;
1303 }
1304 
1306 const Volume& Volume::setLimitSet(const Detector& description, const std::string& nam) const {
1307  if (!nam.empty()) {
1308  return setLimitSet(description.limitSet(nam));
1309  }
1310  return *this;
1311 }
1312 
1314 const Volume& Volume::setLimitSet(const LimitSet& obj) const {
1315  _data(*this)->limits = obj;
1316  return *this;
1317 }
1318 
1321  return _data(*this)->limits;
1322 }
1323 
1326  //cout << "Setting sensitive detector '" << obj.name() << "' to volume:" << ptr() << " " << name() << endl;
1327  _data(*this)->sens_det = obj;
1328  return *this;
1329 }
1330 
1333  const Object* o = _data(*this);
1334  return o->sens_det;
1335 }
1336 
1338 bool Volume::isSensitive() const {
1339  return _data(*this)->sens_det.isValid();
1340 }
1341 
1344  return _data(*this)->properties != nullptr;
1345 }
1346 
1348 void Volume::addProperty(const std::string& nam, const std::string& val) const {
1349  auto* o = _data(*this);
1350  if ( !o->properties ) {
1351  o->properties = new TList();
1352  o->properties->SetOwner();
1353  }
1354  TNamed *prop = (TNamed*)o->properties->FindObject(nam.c_str());
1355  if ( !prop ) {
1356  o->properties->Add(new TNamed(nam.c_str(), val.c_str()));
1357  return;
1358  }
1359  except("Volume::addProperty", "Volume: '%s' Property '%s' is already set!",
1360  ptr()->GetName(), nam.c_str());
1361 }
1362 
1364 std::string Volume::getProperty(const std::string& nam, const std::string& default_val) const {
1365  const auto* o = _data(*this);
1366  if ( !o->properties ) {
1367  return default_val;
1368  }
1369  TNamed *prop = (TNamed*)o->properties->FindObject(nam.c_str());
1370  if ( prop ) return prop->GetTitle();
1371  return default_val;
1372 }
1373 
1375 Assembly::Assembly(const std::string& nam) {
1376  m_element = _createTGeoVolumeAssembly(nam);
1377 }
1378 
1380 VolumeMulti::VolumeMulti(const std::string& nam, Material mat) {
1381  m_element = _createTGeoVolumeMulti(nam, mat.ptr());
1382 }
1383 
1386  if ( m_element ) {
1387  // This will lead to an exception if the type is not TGeoVolumeMulti
1388  TGeoVolumeMulti* multi = detail::safe_cast<TGeoVolumeMulti>::cast(m_element);
1389  if ( multi ) {
1390  import();
1391  return;
1392  }
1393  // Force a bad cast exception
1395  if ( handle.isValid() ) {}
1396  }
1397 }
1398 
1400 std::string dd4hep::toStringMesh(PlacedVolume place, int prec) {
1401  Volume vol = place->GetVolume();
1402  TGeoMatrix* mat = place->GetMatrix();
1403  Solid sol = vol.solid();
1404  std::stringstream os;
1405  struct _numbering {
1406  double adjust(double value) const {
1407  if ( std::abs(value) < TGeoShape::Tolerance() )
1408  return 0.0;
1409  return value/dd4hep::cm;
1410  }
1411  } _vertex;
1412 
1413  if ( vol->IsA() == TGeoVolumeAssembly::Class() ) {
1414  for(int i=0; i<vol->GetNdaughters(); ++i) {
1415  os << toStringMesh(vol->GetNode(i), prec) << std::endl;
1416  }
1417  return os.str();
1418  }
1419 
1420  // Prints shape parameters
1421  int nvert = 0, nsegs = 0, npols = 0;
1422  sol->GetMeshNumbers(nvert, nsegs, npols);
1423  Double_t* points = new Double_t[3*nvert];
1424  sol->SetPoints(points);
1425 
1426  os << std::setw(16) << std::left << sol->IsA()->GetName()
1427  << " " << nvert << " Mesh-points:" << std::endl;
1428  os << std::setw(16) << std::left << sol->IsA()->GetName() << " " << sol->GetName()
1429  << " N(mesh)=" << sol->GetNmeshVertices()
1430  << " N(vert)=" << nvert << " N(seg)=" << nsegs << " N(pols)=" << npols << std::endl;
1431 
1432  for(int i=0; i<nvert; ++i) {
1433  Double_t* p = points + 3*i;
1434  Double_t global[3], local[3] = {p[0], p[1], p[2]};
1435  mat->LocalToMaster(local, global);
1436  os << std::setw(16) << std::left << sol->IsA()->GetName() << " " << std::setw(3) << std::left << i
1437  << " Local (" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[0])
1438  << ", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[1])
1439  << ", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[2])
1440  << ") Global (" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[0])
1441  << ", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[1])
1442  << ", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[2])
1443  << ")" << std::endl;
1444  }
1445  Box box = sol;
1446  const Double_t* org = box->GetOrigin();
1447  os << std::setw(16) << std::left << sol->IsA()->GetName()
1448  << " Bounding box: "
1449  << " dx=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDX())
1450  << " dy=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDY())
1451  << " dz=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDZ())
1452  << " Origin: x=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[0])
1453  << " y=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[1])
1454  << " z=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[2])
1455  << std::endl;
1456 
1458  delete [] points;
1459  return os.str();
1460 }
1461 
dd4hep::detail::matrix::_translation
TGeoTranslation * _translation(const Position &pos)
Convert a Position object to a TGeoTranslation.
Definition: MatrixHelpers.cpp:55
dd4hep::Detector::manager
virtual TGeoManager & manager() const =0
Access the geometry manager of this instance.
dd4hep::VolumeMulti
Implementation class extending the ROOT mulit-volumes (TGeoVolumeMulti)
Definition: Volumes.h:728
dd4hep::Volume::Z_axis
@ Z_axis
Definition: Volumes.h:387
dd4hep::VolumeExtension::Release
virtual void Release() const override
TGeoExtension overload: Method called always when the pointer to the extension is not needed anymore.
Definition: Volumes.cpp:617
dd4hep::Volume::setLimitSet
const Volume & setLimitSet(const Detector &description, const std::string &name) const
Set the limits to the volume. Note: If the name string is empty, the action is ignored.
Definition: Volumes.cpp:1306
dd4hep::Volume::isAssembly
bool isAssembly() const
Test if this volume is an assembly structure.
Definition: Volumes.cpp:727
dd4hep::VolumeExtension
Implementation class extending the ROOT volume (TGeoVolume)
Definition: Volumes.h:301
dd4hep::VisAttrObject::colortr
TColor * colortr
Definition: ObjectsInterna.h:92
dd4hep::Volume::enableCopyNumberCheck
static void enableCopyNumberCheck(bool value)
Set flag to enable copy number checks when inserting new nodes.
Definition: Volumes.cpp:656
dd4hep::Volume::hasProperties
bool hasProperties() const
Check for existence of properties.
Definition: Volumes.cpp:1343
dd4hep::Assembly::Assembly
Assembly()=default
Default constructor.
dd4hep::Volume::ReplicationAxis
ReplicationAxis
Definition: Volumes.h:381
dd4hep::VolumeExtension::region
Region region
Region reference.
Definition: Volumes.h:312
v
View * v
Definition: MultiView.cpp:28
dd4hep::SensitiveDetector
Handle class to hold the information of a sensitive detector.
Definition: DetElement.h:43
dd4hep::Volume::setSmartlessValue
double setSmartlessValue(double value)
Set the smartless option for G4 voxelization. Returns previous value.
Definition: Volumes.cpp:732
dd4hep::detail::matrix::_rotationZYX
TGeoRotation * _rotationZYX(const RotationZYX &rot)
Convert a RotationZYX object to a newly created TGeoRotation.
Definition: MatrixHelpers.cpp:59
MatrixHelpers.h
Detector.h
dd4hep::PlacedVolumeExtension
Implementation class extending the ROOT placed volume.
Definition: Volumes.h:80
dd4hep::PlacedVolumeExtension::~PlacedVolumeExtension
virtual ~PlacedVolumeExtension()
Default destructor.
Definition: Volumes.cpp:379
dd4hep::VolumeMulti::VolumeMulti
VolumeMulti()=default
Default constructor.
dd4hep::PlacedVolumeExtension::Release
virtual void Release() const override
TGeoExtension overload: Method called always when the pointer to the extension is not needed anymore.
Definition: Volumes.cpp:409
dd4hep::VolumeExtension::reflected
Handle< TGeoVolume > reflected
Reference to the reflected volume (or to the original volume for reflections)
Definition: Volumes.h:320
dd4hep::PlacedVolume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:164
dd4hep::VisAttr
Handle class describing visualization attributes.
Definition: Objects.h:331
dd4hep::Volume::paramVolume2D
PlacedVolume paramVolume2D(Volume entity, size_t count_1, const Transform3D &inc_1, size_t count_2, const Transform3D &inc_2)
2D Parameterised volume implementation
Definition: Volumes.cpp:985
geo_volume_t
TGeoVolume geo_volume_t
Definition: Volumes.cpp:53
dd4hep::Volume::smartlessValue
double smartlessValue() const
access the smartless option for G4 voxelization
Definition: Volumes.cpp:740
dd4hep::NamedObject::GetName
const char * GetName() const
Access name.
Definition: NamedObject.h:58
dd4hep::LimitSet::limits
const std::set< Limit > & limits() const
Accessor to limits container.
Definition: Objects.cpp:496
dd4hep::PlacedVolume::addPhysVolID
PlacedVolume & addPhysVolID(const std::string &name, int value)
Add identifier.
Definition: Volumes.cpp:505
dd4hep::detail::matrix::_identity
TGeoIdentity * _identity()
Access the TGeo identity transformation.
Definition: MatrixHelpers.cpp:27
dd4hep::Volume::setOption
const Volume & setOption(const std::string &opt) const
Set the volume's option value.
Definition: Volumes.cpp:1140
dd4hep::Volume::solid
Solid solid() const
Access to Solid (Shape)
Definition: Volumes.cpp:1268
dd4hep::Handle::isValid
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:126
dd4hep::Handle< NamedObject >
dd4hep::Detector::region
virtual Region region(const std::string &name) const =0
Retrieve a region object by its name from the detector description.
dd4hep::detail::matrix::_transform
TGeoHMatrix * _transform(const Transform3D &trans)
Convert a Transform3D object to a newly created TGeoHMatrix.
Definition: MatrixHelpers.cpp:140
dd4hep::Volume::setRegion
const Volume & setRegion(const Detector &description, const std::string &name) const
Set the regional attributes to the volume. Note: If the name string is empty, the action is ignored.
Definition: Volumes.cpp:1287
dd4hep::PlacedVolume::Object
PlacedVolumeExtension Object
Definition: Volumes.h:166
dd4hep::Rotation3D
ROOT::Math::Rotation3D Rotation3D
Definition: Objects.h:112
dd4hep::PlacedVolumeExtension::volIDs
VolIDs volIDs
ID container.
Definition: Volumes.h:128
dd4hep::magic_word
unsigned long long int magic_word()
Access to the magic word, which is protecting some objects against memory corruptions.
Definition: Handle.h:51
dd4hep::Solid_type< TGeoShape >
dd4hep::Volume::paramVolume1D
PlacedVolume paramVolume1D(const Transform3D &start, Volume entity, size_t count, const Transform3D &inc)
1D Parameterised volume implementation
Definition: Volumes.cpp:951
dd4hep::Volume::isSensitive
bool isSensitive() const
Accessor if volume is sensitive (ie. is attached to a sensitive detector)
Definition: Volumes.cpp:1338
dd4hep::VolumeExtension::magic
unsigned long magic
Magic word to detect memory corruptions.
Definition: Volumes.h:304
dd4hep::Handle::name
const char * name() const
Access the object name (or "" if not supported by the object)
dd4hep::VolumeExtension::vis
VisAttr vis
Reference to visualization attributes.
Definition: Volumes.h:316
dd4hep::Volume::placeVolume
PlacedVolume placeVolume(const Volume &volume) const
Place daughter volume. The position and rotation are the identity.
Definition: Volumes.cpp:875
dd4hep::PlacedVolumeExtension::Parameterisation::addref
Parameterisation * addref()
Increase ref count.
Definition: Volumes.cpp:347
dd4hep::Handle::clear
Handle< T > & clear()
Release the object held by the handle.
Definition: Handle.h:134
dd4hep::VolumeExtension::refCount
long refCount
Reference count on object (used to implement Grab/Release)
Definition: Volumes.h:306
dd4hep::Volume::material
Material material() const
Access to the Volume material.
Definition: Volumes.cpp:1167
dd4hep::PlacedVolumeExtension::Parameterisation::release
void release()
Decrease ref count.
Definition: Volumes.cpp:352
dd4hep::Material
Handle class describing a material.
Definition: Objects.h:271
dd4hep::Volume::option
std::string option() const
Access the volume's option value.
Definition: Volumes.cpp:1149
dd4hep::PlacedVolume::daughter
PlacedVolume daughter(std::size_t which) const
Access the daughter by index.
Definition: Volumes.cpp:487
dd4hep::Volume::PARAMETERIZED
@ PARAMETERIZED
Definition: Volumes.h:383
dd4hep::PlacedVolume::Processor::Processor
Processor()
Default constructor.
dd4hep::PlacedVolumeExtension::VolIDs
Volume ID container.
Definition: Volumes.h:89
dd4hep::Utilities::GetName
const char * GetName(T *p)
Definition: Utilities.h:45
dd4hep::Volume::REPLICATED
@ REPLICATED
Definition: Volumes.h:382
dd4hep::Volume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:371
dd4hep::Volume::Y_axis
@ Y_axis
Definition: Volumes.h:386
dd4hep::VisAttrObject::showDaughters
unsigned char showDaughters
Definition: ObjectsInterna.h:96
dd4hep::Volume::setSensitiveDetector
const Volume & setSensitiveDetector(const SensitiveDetector &obj) const
Assign the sensitive detector structure.
Definition: Volumes.cpp:1325
dd4hep::VisAttrObject::lineStyle
unsigned char lineStyle
Definition: ObjectsInterna.h:95
dd4hep::Volume::setSolid
const Volume & setSolid(const Solid &s) const
Set the volume's solid shape.
Definition: Volumes.cpp:1262
dd4hep::VolumeExtension::copy
void copy(const VolumeExtension &c)
Copy the object.
Definition: Volumes.cpp:584
dd4hep::Handle::data
Q * data() const
Access to an unrelated object type.
Definition: Handle.h:159
dd4hep::LimitSet
Handle class describing a set of limits as they are used for simulation.
Definition: Objects.h:432
dd4hep::Volume::REFLECTED
@ REFLECTED
Definition: Volumes.h:379
dd4hep::PlacedVolume::material
Material material() const
Volume material.
Definition: Volumes.cpp:467
dd4hep::Volume::limitSet
LimitSet limitSet() const
Access to the limit set.
Definition: Volumes.cpp:1320
dd4hep::Volume::replicate
PlacedVolume replicate(const Volume entity, ReplicationAxis axis, size_t count, double inc, double start=0e0)
1D volume replication implementation
Definition: Volumes.cpp:920
dd4hep::VisAttr::DASHED
@ DASHED
Definition: Objects.h:334
dd4hep::Volume::region
Region region() const
Access to the handle to the region structure.
Definition: Volumes.cpp:1301
dd4hep::VolumeExtension::sens_det
Handle< NamedObject > sens_det
Reference to the sensitive detector.
Definition: Volumes.h:318
_addNode
PlacedVolume _addNode(TGeoVolume *par, TGeoVolume *daughter, int id, TGeoMatrix *transform)
Definition: Volumes.cpp:768
dd4hep::VisAttrObject::color
TColor * color
Definition: ObjectsInterna.h:91
dd4hep::VolumeExtension::flags
int flags
Bit field to determine the usage. Bit 0...15 reserverd for system usage. 16...31 user space.
Definition: Volumes.h:310
dd4hep::Volume::addProperty
void addProperty(const std::string &nam, const std::string &val) const
Add Volume property (name-value pair)
Definition: Volumes.cpp:1348
dd4hep::Volume::setMaterial
const Volume & setMaterial(const Material &m) const
Set the volume's material.
Definition: Volumes.cpp:1154
dd4hep::VisAttrObject::drawingStyle
unsigned char drawingStyle
Definition: ObjectsInterna.h:94
TNamed
Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html.
Definition: ROOTClasses.h:37
dd4hep::Volume::paramVolume3D
PlacedVolume paramVolume3D(Volume entity, size_t count_1, const Transform3D &inc_1, size_t count_2, const Transform3D &inc_2, size_t count_3, const Transform3D &inc_3)
3D Parameterised volume implementation
dd4hep::Volume::testFlagBit
bool testFlagBit(unsigned int bit) const
Test the user flag bit.
Definition: Volumes.cpp:713
geo_assembly_t
TGeoVolumeAssembly geo_assembly_t
Definition: Volumes.cpp:54
dd4hep::Region
Handle class describing a region as used in simulation.
Definition: Objects.h:469
dd4hep::Handle< TGeoVolume >::m_element
TGeoVolume * m_element
Single and only data member: Reference to the actual element.
Definition: Handle.h:91
dd4hep::Handle::_ptr
Q * _ptr() const
Access to an unrelated object type.
Definition: Handle.h:155
dd4hep::Detector::limitSet
virtual LimitSet limitSet(const std::string &name) const =0
Retrieve a limitset by its name from the detector description.
dd4hep::PlacedVolume::matrix
const TGeoMatrix & matrix() const
Access the full transformation matrix to the parent volume.
Definition: Volumes.cpp:530
dd4hep::VolumeExtension::Grab
virtual TGeoExtension * Grab() override
TGeoExtension overload: Method called whenever requiring a pointer to the extension.
Definition: Volumes.cpp:604
dd4hep::ReflectionBuilder::execute
void execute() const
Perform scan.
dd4hep::PlacedVolume::motherVol
Volume motherVol() const
Parent volume (envelope)
Definition: Volumes.cpp:477
dd4hep::PlacedVolume::toString
std::string toString() const
String dump.
Definition: Volumes.cpp:544
dd4hep::PlacedVolumeExtension::PlacedVolumeExtension
PlacedVolumeExtension()
Default constructor.
Definition: Volumes.cpp:358
dd4hep::Volume::Volume
Volume()=default
Default constructor.
dd4hep::Detector::visAttributes
virtual const HandleMap & visAttributes() const =0
Accessor to the map of visualisation attributes.
dd4hep::Transform3D
ROOT::Math::Transform3D Transform3D
Definition: Objects.h:116
dd4hep::PlacedVolume::num_daughters
std::size_t num_daughters() const
Number of daughters placed in this volume.
Definition: Volumes.cpp:482
DECREMENT_COUNTER
#define DECREMENT_COUNTER
Definition: config.h:39
dd4hep::Volume::divide
Volume divide(const std::string &divname, int iaxis, int ndiv, double start, double step, int numed=0, const char *option="")
Divide volume into subsections (See the ROOT manual for details)
Definition: Volumes.cpp:745
dd4hep::Position
ROOT::Math::XYZVector Position
Definition: Objects.h:80
dd4hep::VolumeExtension::VolumeExtension
VolumeExtension()
Default constructor.
Definition: Volumes.cpp:557
dd4hep::PlacedVolumeExtension::magic
unsigned long magic
Magic word to detect memory corruptions.
Definition: Volumes.h:122
dd4hep::Volume::isReflected
bool isReflected() const
Test if this volume was reflected.
Definition: Volumes.cpp:722
dd4hep::PlacedVolume::type
const char * type() const
Access the object type from the class information.
Definition: Volumes.cpp:457
dd4hep::Box
Class describing a box shape.
Definition: Shapes.h:295
dd4hep::VisAttr::SOLID
@ SOLID
Definition: Objects.h:334
dd4hep::PlacedVolumeExtension::Grab
virtual TGeoExtension * Grab() override
TGeoExtension overload: Method called whenever requiring a pointer to the extension.
Definition: Volumes.cpp:400
dd4hep::Handle::ptr
T * ptr() const
Access to the held object.
Definition: Handle.h:151
ObjectsInterna.h
dd4hep::Volume::type
const char * type() const
Access the object type from the class information.
Definition: Volumes.cpp:667
dd4hep::ReflectionBuilder::detector
Detector & detector
Definition: Volumes.h:61
dd4hep::Volume::boundingBox
Box boundingBox() const
Access the bounding box of the volume (if available)
Definition: Volumes.cpp:1273
dd4hep::VolumeExtension::operator=
VolumeExtension & operator=(VolumeExtension &&copy)=delete
No move assignment.
geo_node_t
TGeoNode geo_node_t
Definition: Volumes.cpp:52
dd4hep::VolumeMulti::verifyVolumeMulti
void verifyVolumeMulti()
Import volume from pointer as a result of Solid->Divide()
Definition: Volumes.cpp:1385
dd4hep::Volume::setVisAttributes
const Volume & setVisAttributes(const VisAttr &obj) const
Set Visualization attributes to the volume.
Definition: Volumes.cpp:1172
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::PlacedVolumeExtension::VolIDs::str
std::string str() const
String representation for debugging.
Definition: Volumes.cpp:440
dd4hep::VolumeExtension::smartLess
double smartLess
Geant4 optimization flag: Smartless.
Definition: Volumes.h:324
dd4hep::Solid
Solid_type< TGeoShape > Solid
Definition: Shapes.h:198
det
DetElement::Object * det
Definition: AlignmentsCalculator.cpp:66
dd4hep::PlacedVolume::copyNumber
int copyNumber() const
Access the copy number of this placement within its mother.
Definition: Volumes.cpp:462
dd4hep::PlacedVolume::Processor::~Processor
virtual ~Processor()
Default destructor.
Definition: Volumes.cpp:343
dd4hep::PlacedVolume::volume
Volume volume() const
Logical volume of this placement.
Definition: Volumes.cpp:472
dd4hep::PlacedVolumeExtension::VolIDs::insert
std::pair< std::vector< VolID >::iterator, bool > insert(const std::string &name, int value)
Insert new entry.
Definition: Volumes.cpp:426
dd4hep::PlacedVolume::data
Object * data() const
Check if placement is properly instrumented.
Definition: Volumes.cpp:451
dd4hep::Detector
The main interface to the dd4hep detector description package.
Definition: Detector.h:89
dd4hep::Volume::getProperty
std::string getProperty(const std::string &nam, const std::string &default_val="") const
Access property value. Returns default_value if the property is not present.
Definition: Volumes.cpp:1364
INCREMENT_COUNTER
#define INCREMENT_COUNTER
Definition: config.h:38
dd4hep::Volume::reflect
Volume reflect() const
Create a reflected volume tree. The reflected volume has left-handed coordinates.
Definition: Volumes.cpp:672
dd4hep::VolumeExtension::~VolumeExtension
virtual ~VolumeExtension()
Default destructor.
Definition: Volumes.cpp:563
dd4hep::Volume::setFlagBit
void setFlagBit(unsigned int bit)
Set user flags in bit-field.
Definition: Volumes.cpp:704
TGeoExtension
Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html.
Definition: ROOTClasses.h:25
dd4hep::detail::tools::copy
void copy(Alignment from, Alignment to)
Copy alignment object from source object.
Definition: AlignmentTools.cpp:43
dd4hep::PlacedVolumeExtension::refCount
long refCount
Reference count on object (used to implement Grab/Release)
Definition: Volumes.h:124
dd4hep::PlacedVolume::volIDs
const PlacedVolumeExtension::VolIDs & volIDs() const
Access to the volume IDs.
Definition: Volumes.cpp:500
dd4hep::RotationZYX
ROOT::Math::RotationZYX RotationZYX
Definition: Objects.h:104
InstanceCount.h
dd4hep::Volume::setAttributes
const Volume & setAttributes(const Detector &description, const std::string &region, const std::string &limits, const std::string &vis) const
Attach attributes to the volume.
Definition: Volumes.cpp:1245
dd4hep::VolumeExtension::properties
TList * properties
Reference to properties.
Definition: Volumes.h:322
dd4hep::VisAttrObject::alpha
float alpha
Definition: ObjectsInterna.h:93
dd4hep::Volume::visAttributes
VisAttr visAttributes() const
Access the visualisation attributes.
Definition: Volumes.cpp:1255
dd4hep::Volume::Object
VolumeExtension Object
Definition: Volumes.h:373
ClassImp
ClassImp(VolumeExtension) ClassImp(PlacedVolumeExtension) ClassImp(PlacedVolumeExtension
Enable ROOT persistency.
Definition: Volumes.cpp:57
dd4hep::PlacedVolumeExtension::params
Parameterisation * params
Reference to the parameterised transformation.
Definition: Volumes.h:126
dd4hep::PlacedVolume::position
Position position() const
Access the translation vector to the parent volume.
Definition: Volumes.cpp:538
dd4hep::get_shape_tag
std::string get_shape_tag(const TGeoShape *shape)
Retrieve tag name from shape type.
Definition: ShapeUtilities.cpp:185
Printout.h
dd4hep::Volume::X_axis
@ X_axis
Definition: Volumes.h:385
dd4hep::PlacedVolumeExtension::Parameterisation
Optional parameters to implement special features such as parametrization.
Definition: Volumes.h:247
dd4hep::Volume::import
Volume & import()
If we import volumes from external sources, we have to attach the extensions to the tree.
Definition: Volumes.cpp:693
dd4hep::PlacedVolumeExtension::VolIDs::find
std::vector< VolID >::const_iterator find(const std::string &name) const
Find entry.
Definition: Volumes.cpp:417
dd4hep::toStringMesh
std::string toStringMesh(const TGeoShape *shape, int precision=2)
Output mesh vertices to string.
Definition: ShapeUtilities.cpp:1295
dd4hep::VolumeExtension::referenced
int referenced
Definition: Volumes.h:308
dd4hep::Volume::data
Object * data() const
Check if placement is properly instrumented.
Definition: Volumes.cpp:661
dd4hep::PlacedVolumeExtension::operator=
PlacedVolumeExtension & operator=(PlacedVolumeExtension &&copy)
Move assignment.
Definition: Volumes.cpp:385
dd4hep::Volume::sensitiveDetector
Handle< NamedObject > sensitiveDetector() const
Access to the handle to the sensitive detector.
Definition: Volumes.cpp:1332
dd4hep::VolumeExtension::limits
LimitSet limits
Limit sets used for simulation.
Definition: Volumes.h:314
dd4hep::VisAttrObject::visible
unsigned char visible
Definition: ObjectsInterna.h:97
dd4hep::VisAttrObject
Concrete object implementation of the VisAttr Handle.
Definition: ObjectsInterna.h:88