Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:17:06

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
0015 #include <DD4hep/Detector.h>
0016 #include <DD4hep/Printout.h>
0017 #include <DD4hep/InstanceCount.h>
0018 #include <DD4hep/MatrixHelpers.h>
0019 #include <DD4hep/detail/ObjectsInterna.h>
0020 
0021 // ROOT include files
0022 #include <TROOT.h>
0023 #include <TClass.h>
0024 #include <TColor.h>
0025 #include <TGeoShape.h>
0026 #include <TGeoVolume.h>
0027 #include <TGeoNode.h>
0028 #include <TGeoMatrix.h>
0029 #include <TGeoMedium.h>
0030 
0031 #include <TGeoVoxelFinder.h>
0032 #include <TGeoShapeAssembly.h>
0033 #include <TGeoScaledShape.h>
0034 #include <TMap.h>
0035 
0036 // C/C++ include files
0037 #include <climits>
0038 #include <iostream>
0039 #include <stdexcept>
0040 #include <sstream>
0041 #include <iomanip>
0042 
0043 using namespace dd4hep;
0044 
0045 /*
0046  *  The section below uses the new ROOT features using user extensions to volumes
0047  *  and placements. Once this is common, the above mechanism should be thrown away....
0048  *
0049  *  M.Frank
0050  */
0051 
0052 typedef TGeoNode                geo_node_t;
0053 typedef TGeoVolume              geo_volume_t;
0054 typedef TGeoVolumeAssembly      geo_assembly_t;
0055 
0056 /// Enable ROOT persistency
0057 ClassImp(VolumeExtension)
0058 ClassImp(PlacedVolumeExtension)
0059 ClassImp(PlacedVolumeExtension::Parameterisation)
0060 
0061 namespace {
0062 
0063   static constexpr double s_rotation_test_limit = 1e-12;
0064   static bool s_verifyCopyNumbers = true;
0065 
0066   template <typename T> typename T::Object* _userExtension(const T& v)  {
0067     typedef typename T::Object O;
0068     O* o = (O*)(v.ptr()->GetUserExtension());
0069     return o;
0070   }
0071 
0072   TGeoVolume* _createTGeoVolume(const std::string& name, TGeoShape* s, TGeoMedium* m)  {
0073     geo_volume_t* e = new geo_volume_t(name.c_str(),s,m);
0074     e->SetUserExtension(new Volume::Object());
0075     return e;
0076   }
0077   TGeoVolume* _createTGeoVolumeAssembly(const std::string& name)  {
0078     geo_assembly_t* e = new geo_assembly_t(name.c_str()); // It is important to use the correct constructor!!
0079     e->SetUserExtension(new Assembly::Object());
0080     return e;
0081   }
0082   TGeoVolumeMulti* _createTGeoVolumeMulti(const std::string& name, TGeoMedium* medium)  {
0083     TGeoVolumeMulti* e = new TGeoVolumeMulti(name.c_str(), medium);
0084     e->SetUserExtension(new VolumeMulti::Object());
0085     return e;
0086   }
0087   PlacedVolume::Object* _data(const PlacedVolume& v) {
0088     PlacedVolume::Object* o = _userExtension(v);
0089     if (o) return o;
0090     throw std::runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume");
0091   }
0092   /// Accessor to the data part of the Volume
0093   Volume::Object* _data(const Volume& v, bool throw_exception = true) {
0094     //if ( v.ptr() && v.ptr()->IsA() == TGeoVolume::Class() ) return v.data<Volume::Object>();
0095     Volume::Object* o = _userExtension(v);
0096     if (o)
0097       return o;
0098     else if (!throw_exception)
0099       return nullptr;
0100     throw std::runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume");
0101   }
0102 
0103   class VolumeImport   {
0104   public:
0105     void setShapeTitle(TGeoVolume* vol)   {
0106       if ( vol )   {
0107         TGeoShape* sh = vol->GetShape();
0108         std::string tag = get_shape_tag(sh);
0109         sh->SetTitle(tag.c_str());
0110       }
0111     }
0112 
0113   public:
0114     /// Callback for simple imports. Simple add a user extension
0115     void operator()(TGeoVolume* v)   {
0116       TClass* c = v->IsA();
0117       if ( !v->GetUserExtension() )   {
0118         if ( c == geo_volume_t::Class() )
0119           v->SetUserExtension(new Volume::Object());
0120         else if  ( c == geo_assembly_t::Class() )
0121           v->SetUserExtension(new Assembly::Object());
0122         else if  ( c == TGeoVolumeMulti::Class() )
0123           v->SetUserExtension(new VolumeMulti::Object());
0124         else
0125           except("dd4hep","VolumeImport: Unknown TGeoVolume sub-class: %s",v->IsA()->GetName());
0126       }
0127       if  ( c == TGeoVolumeMulti::Class() )  {
0128         TGeoVolumeMulti* mv = (TGeoVolumeMulti*)v;
0129         for( int i=0, n=mv->GetNvolumes(); i<n; ++i )   {
0130           TGeoVolume* vol = mv->GetVolume(i);
0131           this->setShapeTitle(vol);
0132           (*this)(vol);
0133         }
0134       }
0135       for( Int_t i=0; i<v->GetNdaughters(); ++i )  {
0136         geo_node_t* pv = v->GetNode(i);
0137         if ( !pv->GetUserExtension() )
0138           pv->geo_node_t::SetUserExtension(new PlacedVolume::Object());
0139         (*this)(pv->GetVolume());
0140       }
0141     }
0142     /// Callback for clone imports, where the user extension should be copied
0143     void operator()(TGeoVolume* new_v, TGeoVolume* old_v, SensitiveDetector sd, int set_bit)   {
0144       if ( !new_v || !old_v )  {
0145         except("dd4hep","VolumeImport: ERROR: The refected volume is INVALID!");        
0146       }
0147       else if ( !old_v->GetUserExtension() )   {
0148         except("dd4hep","VolumeImport: ERROR: Reflection of non-dd4hep volume %s",new_v->IsA()->GetName());
0149       }
0150       else if ( !new_v->GetUserExtension() )   {
0151         TClass* c = new_v->IsA();
0152         Volume old_vol(old_v);
0153         Volume new_vol(new_v);
0154         if ( sd.isValid() && old_vol.isSensitive() )   {
0155           new_vol.setSensitiveDetector(sd);
0156         }
0157         if ( c == geo_volume_t::Class() )  {
0158           Volume::Object *new_e, *old_e = (Volume::Object*)_data(old_vol);
0159           old_e->reflected = new_v;
0160           new_v->SetUserExtension(new_e = new Volume::Object(*old_e)); 
0161           new_e->reflected = old_v;
0162         }
0163         else if  ( c == geo_assembly_t::Class() )  {
0164           Assembly::Object *new_e, *old_e = (Assembly::Object*)_data(old_vol);
0165           old_e->reflected = new_v;
0166           new_v->SetUserExtension(new_e = new Assembly::Object(*old_e));
0167           new_e->reflected = old_v;
0168         }
0169         else if  ( c == TGeoVolumeMulti::Class() )   {
0170           VolumeMulti::Object *new_e, *old_e = (VolumeMulti::Object*)_data(old_vol);
0171           TGeoVolumeMulti* new_mv = (TGeoVolumeMulti*)new_v;
0172           TGeoVolumeMulti* old_mv = (TGeoVolumeMulti*)old_v;
0173           new_v->SetUserExtension(new_e = new VolumeMulti::Object(*old_e));
0174           old_e->reflected = new_v;
0175           new_e->reflected = old_v;
0176           for(int i=0, n=new_mv->GetNvolumes(); i<n; ++i)  {
0177             TGeoVolume* vol = new_mv->GetVolume(i);
0178             this->setShapeTitle(vol);
0179             (*this)(vol, old_mv->GetVolume(i), sd, set_bit);
0180           }
0181         }
0182         else
0183           except("dd4hep","VolumeImport: Unknown TGeoVolume sub-class: %s",new_v->IsA()->GetName());
0184 
0185         new_vol.setSensitiveDetector(old_vol.sensitiveDetector());
0186         new_vol.setVisAttributes(old_vol.visAttributes());
0187         new_vol.setLimitSet(old_vol.limitSet());
0188         new_vol.setRegion(old_vol.region());
0189 
0190         if ( set_bit >= 0 ) new_vol.setFlagBit(set_bit);
0191         for(Int_t i=0; i<new_v->GetNdaughters(); ++i)  {
0192           geo_node_t* pv = new_v->GetNode(i);
0193           geo_node_t* ov = old_v->GetNode(i);
0194           if ( !pv->GetUserExtension() )   {
0195             auto* e = (PlacedVolume::Object*)ov->geo_node_t::GetUserExtension();
0196             pv->geo_node_t::SetUserExtension(new PlacedVolume::Object(*e));
0197           }
0198           (*this)(pv->GetVolume(), ov->GetVolume(), sd, set_bit);
0199         }
0200       }
0201     }
0202   };
0203 
0204   TGeoVolume* MakeReflection(TGeoVolume* v, const char* newname=0)  {
0205     static TMap map(100);
0206     TGeoVolume* vol = (TGeoVolume*)map.GetValue(v);
0207     if ( vol ) {
0208       if (newname && newname[0]) v->SetName(newname);
0209       return vol;
0210     }
0211     vol = v->CloneVolume();
0212     if (!vol) {
0213       printout(ERROR,"MakeReflection", "Cannot clone volume %s\n", v->GetName());
0214       return nullptr;
0215     }
0216     map.Add(v, vol);
0217     std::string nam;
0218     if (newname && newname[0])  {
0219       nam = newname;
0220       vol->SetName(newname);
0221     }
0222     else   {
0223       nam = v->GetName();
0224       vol->SetName((nam+"_refl").c_str());
0225     }
0226     delete vol->GetNodes();
0227     vol->SetNodes(nullptr);
0228     vol->SetBit(TGeoVolume::kVolumeImportNodes, kFALSE);
0229     v->CloneNodesAndConnect(vol);
0230     // The volume is now properly cloned, but with the same shape.
0231     // Reflect the shape (if any) and connect it.
0232     if (v->GetShape())   {
0233       TGeoScale* scale = new TGeoScale( 1., 1.,-1.);
0234       TGeoShape* reflected_shape =
0235         TGeoScaledShape::MakeScaledShape((nam+"_shape_refl").c_str(), v->GetShape(), scale);
0236       vol->SetShape(reflected_shape);
0237       //vol->SetShape(v->GetShape());
0238     }
0239     // Reflect the daughters.
0240     Int_t nd = vol->GetNdaughters();
0241     if ( !nd ) return vol;
0242     TGeoVolume *new_vol;
0243     if ( !vol->GetFinder() ) {
0244       for (Int_t i=0; i < nd; i++) {
0245         TGeoNodeMatrix* node  = (TGeoNodeMatrix*)vol->GetNode(i);
0246         TGeoMatrix*     local = node->GetMatrix();
0247         //         printf("%s before\n", node->GetName());
0248         //         local->Print();
0249         Bool_t      reflected = local->IsReflection();
0250         TGeoMatrix* local_cloned = new TGeoCombiTrans(*local);
0251         local_cloned->RegisterYourself();
0252         node->SetMatrix(local_cloned);
0253         if (!reflected) {
0254           // We need to reflect only the translation and propagate to daughters.
0255           // H' = Sz * H * Sz
0256           local_cloned->ReflectZ(kTRUE);
0257           local_cloned->ReflectZ(kFALSE);
0258           //            printf("%s after\n", node->GetName());
0259           //            node->GetMatrix()->Print();
0260           new_vol = MakeReflection(node->GetVolume());
0261           node->SetVolume(new_vol);
0262           continue;
0263         }
0264         // The next daughter is already reflected, so reflect on Z everything and stop
0265         local_cloned->ReflectZ(kTRUE); // rot + tr
0266         //         printf("%s already reflected... After:\n", node->GetName());
0267         //         node->GetMatrix()->Print();
0268       }
0269       if ( vol->GetVoxels() ) vol->GetVoxels()->Voxelize();
0270       return vol;
0271     }
0272     // Volume is divided, so we have to reflect the division.
0273     //   printf("   ... divided %s\n", fFinder->ClassName());
0274     TGeoPatternFinder *new_finder = v->GetFinder()->MakeCopy(kTRUE);
0275     if (!new_finder) {
0276       printout(ERROR,"MakeReflection", "Could not copy finder for volume %s", v->GetName());
0277       return nullptr;
0278     }
0279     new_finder->SetVolume(vol);
0280     vol->SetFinder(new_finder);
0281     TGeoNodeOffset *nodeoff;
0282     new_vol = 0;
0283     for (Int_t i=0; i<nd; i++) {
0284       nodeoff = (TGeoNodeOffset*)vol->GetNode(i);
0285       nodeoff->SetFinder(new_finder);
0286       new_vol = MakeReflection(nodeoff->GetVolume());
0287       nodeoff->SetVolume(new_vol);
0288     }
0289     return vol;
0290   }
0291 
0292   int get_copy_number(TGeoVolume* par)    {
0293     TObjArray* a = par ? par->GetNodes() : 0;
0294     int copy_nr = (a ? a->GetEntries() : 0);
0295     return copy_nr;
0296   }
0297 
0298 }
0299 
0300 
0301 /// Perform scan
0302 void ReflectionBuilder::execute()  const   {
0303   TGeoIterator next(detector.manager().GetTopVolume());
0304   bool print_active = isActivePrintLevel(DEBUG);
0305   TGeoNode *node;
0306   while ( (node=next()) ) {
0307     TGeoMatrix* matrix = node->GetMatrix();
0308     if (matrix->IsReflection()) {
0309       if ( print_active )  {
0310         printout(INFO,"ReflectionBuilder","Reflection matrix:");
0311         matrix->Print();
0312       }
0313       Volume vol(node->GetVolume());
0314       TGeoMatrix* mclone = new TGeoCombiTrans(*matrix);
0315       mclone->RegisterYourself();
0316       // Reflect just the rotation component
0317       //mclone->ReflectZ(kFALSE, kTRUE);
0318       if ( print_active )  {
0319         printout(INFO,"ReflectionBuilder","CLONE matrix:");
0320         mclone->Print();
0321       }
0322       TGeoNodeMatrix* nodematrix = (TGeoNodeMatrix*)node;
0323       nodematrix->SetMatrix(mclone);
0324       if ( print_active )  {
0325         printout(INFO,"ReflectionBuilder","Reflected volume: %s ", vol.name());
0326       }
0327       Volume refl = vol.reflect(vol.sensitiveDetector());
0328       node->SetVolume(refl.ptr());
0329     }
0330   }
0331 }
0332 
0333 /// Default constructor
0334 PlacedVolume::Processor::Processor()   {
0335 }
0336 
0337 /// Default destructor
0338 PlacedVolume::Processor::~Processor()   {
0339 }
0340 
0341 /// Increase ref count
0342 PlacedVolumeExtension::Parameterisation* PlacedVolumeExtension::Parameterisation::addref()  {
0343   ++refCount;
0344   return this;
0345 }
0346 /// Decrease ref count
0347 void PlacedVolumeExtension::Parameterisation::release()  {
0348   --refCount;
0349   if ( 0 == refCount ) delete this;
0350 }
0351 
0352 /// Default constructor
0353 PlacedVolumeExtension::PlacedVolumeExtension()
0354   : TGeoExtension(), volIDs()
0355 {
0356   magic = magic_word();
0357   INCREMENT_COUNTER;
0358 }
0359 
0360 /// Default move
0361 PlacedVolumeExtension::PlacedVolumeExtension(PlacedVolumeExtension&& c)
0362   : TGeoExtension(c), magic(std::move(c.magic)), refCount(0), volIDs(std::move(c.volIDs)) {
0363   INCREMENT_COUNTER;
0364 }
0365 
0366 /// Copy constructor
0367 PlacedVolumeExtension::PlacedVolumeExtension(const PlacedVolumeExtension& c)
0368   : TGeoExtension(), magic(c.magic), refCount(0), volIDs() {
0369   INCREMENT_COUNTER;
0370   volIDs = c.volIDs;
0371 }
0372 
0373 /// Default destructor
0374 PlacedVolumeExtension::~PlacedVolumeExtension() {
0375   if ( this->params ) this->params->release();
0376   DECREMENT_COUNTER;
0377 }
0378 
0379 /// TGeoExtension overload: Method called whenever requiring a pointer to the extension
0380 TGeoExtension* PlacedVolumeExtension::Grab()   {
0381   ++this->refCount;
0382 #ifdef ___print_vols
0383   else  cout << "Placement grabbed....." << endl;
0384 #endif
0385   return this;
0386 }
0387 
0388 /// TGeoExtension overload: Method called always when the pointer to the extension is not needed anymore
0389 void PlacedVolumeExtension::Release() const  {
0390   PlacedVolumeExtension* ext = const_cast<PlacedVolumeExtension*>(this);
0391   --ext->refCount;
0392   if ( 0 == ext->refCount ) delete ext;
0393 }
0394 
0395 /// Lookup volume ID
0396 std::vector<PlacedVolumeExtension::VolID>::const_iterator
0397 PlacedVolumeExtension::VolIDs::find(const std::string& name) const {
0398   for (Base::const_iterator i = this->Base::begin(); i != this->Base::end(); ++i)
0399     if (name == (*i).first)
0400       return i;
0401   return this->end();
0402 }
0403 
0404 /// Insert a new value into the volume ID container
0405 std::pair<std::vector<PlacedVolumeExtension::VolID>::iterator, bool>
0406 PlacedVolumeExtension::VolIDs::insert(const std::string& name, int value) {
0407   Base::iterator i = this->Base::begin();
0408   for (; i != this->Base::end(); ++i)
0409     if (name == (*i).first)
0410       break;
0411   //
0412   if (i != this->Base::end()) {
0413     return make_pair(i, false);
0414   }
0415   i = this->Base::emplace(this->Base::end(), name, value);
0416   return make_pair(i, true);
0417 }
0418 
0419 /// String representation for debugging
0420 std::string PlacedVolumeExtension::VolIDs::str()  const   {
0421   std::stringstream str;
0422   str << std::hex;
0423   for(const auto& i : *this )   {
0424     str << i.first << "=" << std::setw(4) << std::right
0425         << std::setfill('0') << i.second << std::setfill(' ') << " ";
0426   }
0427   return str.str();
0428 }
0429 
0430 /// Check if placement is properly instrumented
0431 PlacedVolume::Object* PlacedVolume::data() const   {
0432   PlacedVolume::Object* o = _userExtension(*this);
0433   return o;
0434 }
0435 
0436 /// Access the object type from the class information
0437 const char* PlacedVolume::type() const   {
0438   return m_element ? m_element->IsA()->GetName() : "UNKNOWN-PlacedVolume";
0439 }
0440 
0441 /// Access the copy number of this placement within its mother
0442 int PlacedVolume::copyNumber() const   {
0443   return m_element ? m_element->GetNumber() : -1;
0444 }
0445 
0446 /// Volume material
0447 Material PlacedVolume::material() const {
0448   return Material(m_element ? m_element->GetMedium() : 0);
0449 }
0450 
0451 /// Logical volume of this placement
0452 Volume PlacedVolume::volume() const {
0453   return Volume(m_element ? m_element->GetVolume() : 0);
0454 }
0455 
0456 /// Parent volume (envelope)
0457 Volume PlacedVolume::motherVol() const {
0458   return Volume(m_element ? m_element->GetMotherVolume() : 0);
0459 }
0460 
0461 /// Number of daughters placed in this volume
0462 std::size_t PlacedVolume::num_daughters()  const   {
0463   return m_element ? m_element->GetNdaughters() : 0;
0464 }
0465 
0466 /// Access the daughter by index
0467 PlacedVolume PlacedVolume::daughter(std::size_t which)  const   {
0468   if ( m_element )  {
0469     if ( which < (std::size_t)m_element->GetNdaughters() )   {
0470       return m_element->GetDaughter(which);
0471     }
0472     except("Volume","+++ Access daughter %ld of %s [Has only %d daughters]",
0473        which, m_element->GetName(), m_element->GetNdaughters());
0474   }
0475   except("Volume","+++ Cannot access daughters of a non-existing volume!");
0476   return nullptr;
0477 }
0478 
0479 /// Access to the volume IDs
0480 const PlacedVolume::VolIDs& PlacedVolume::volIDs() const {
0481   return _data(*this)->volIDs;
0482 }
0483 
0484 /// Add identifier
0485 PlacedVolume& PlacedVolume::addPhysVolID(const std::string& nam, int value) {
0486   auto* o = _data(*this);
0487   if ( !o->params )   {
0488     o->volIDs.emplace_back(nam, value);
0489     return *this;
0490   }
0491   if ( value > 0 )    {
0492     except("PlacedVolume",
0493        "+++ addPhysVolID(%s): parameterised volumes only accept '0' is volID."
0494        "These automatically get overwritten with the copy number!",
0495        ptr()->GetName());
0496   }
0497   if ( !o->volIDs.empty() )    {
0498     except("PlacedVolume",
0499        "+++ addPhysVolID(%s): parameterised volumes can only host 1 physical volume ID."
0500        " vol id '%s' is already defined!", ptr()->GetName(), o->volIDs[0].first.c_str());
0501   }
0502   for(PlacedVolume pv : o->params->placements)  {
0503     auto* p = _data(pv);
0504     p->volIDs.emplace_back(nam, pv->GetNumber());
0505   }
0506   return *this;
0507 }
0508 
0509 /// Translation vector within parent volume
0510 const TGeoMatrix& PlacedVolume::matrix()  const    {
0511   if ( !isValid() )  {
0512     except("PlacedVolume","+++ matrix: Failed to access invalid PlacedVolume! [Invalid handle]");
0513   }
0514   return *(m_element->GetMatrix());  
0515 }
0516 
0517 /// Translation vector within parent volume
0518 Position PlacedVolume::position()  const    {
0519   const double* ptr = matrix().GetTranslation();
0520   return Position(ptr[0],ptr[1],ptr[2]);
0521 }
0522 
0523 /// String dump
0524 std::string PlacedVolume::toString() const {
0525   std::stringstream str;
0526   Object* obj = _data(*this);
0527   str << m_element->GetName() << ":  vol='" << m_element->GetVolume()->GetName()
0528       << "' mat:'" << m_element->GetMatrix()->GetName()
0529       << "' volID[" << obj->volIDs.size() << "] ";
0530   for (VolIDs::const_iterator i = obj->volIDs.begin(); i != obj->volIDs.end(); ++i)
0531     str << (*i).first << "=" << (*i).second << "  ";
0532   str << std::ends;
0533   return str.str();
0534 }
0535 
0536 /// Default constructor
0537 VolumeExtension::VolumeExtension()
0538 : TGeoExtension(), region(), limits(), vis(), sens_det()   {
0539   INCREMENT_COUNTER;
0540 }
0541 
0542 /// Default destructor
0543 VolumeExtension::~VolumeExtension() {
0544   detail::deletePtr(properties);
0545   region.clear();
0546   limits.clear();
0547   vis.clear();
0548   sens_det.clear();
0549   DECREMENT_COUNTER;
0550 }
0551 
0552 /// Copy constructor
0553 VolumeExtension::VolumeExtension(const VolumeExtension& c)   {
0554   this->copy(c);
0555 }
0556 
0557 /// Copy assignment
0558 VolumeExtension& VolumeExtension::operator=(const VolumeExtension& c)   {
0559   this->copy(c);
0560   return *this;
0561 }
0562 
0563 /// Copy the object
0564 void VolumeExtension::copy(const VolumeExtension& c) {
0565   if ( this != &c )   {
0566     magic      = c.magic;
0567     region     = c.region;
0568     limits     = c.limits;
0569     vis        = c.vis;
0570     sens_det   = c.sens_det;
0571     referenced = c.referenced;
0572     detail::deletePtr(properties);
0573     if ( c.properties )    {
0574       properties = new TList();
0575       properties->SetOwner();
0576       TIter next(properties);
0577       TNamed *property;
0578       while ((property = (TNamed*)next())) properties->Add(new TNamed(*property));
0579     }
0580   }
0581 }
0582 
0583 /// TGeoExtension overload: Method called whenever requiring a pointer to the extension
0584 TGeoExtension* VolumeExtension::Grab()  {
0585   VolumeExtension* ext = const_cast<VolumeExtension*>(this);
0586   ++ext->refCount;
0587 #ifdef ___print_vols
0588   if ( ext->sens_det.isValid() )
0589     cout << "Volume grabbed with valid sensitive detector....." << endl;
0590   else
0591     cout << "Volume grabbed....." << endl;
0592 #endif
0593   return ext;
0594 }
0595 
0596 /// TGeoExtension overload: Method called always when the pointer to the extension is not needed anymore
0597 void VolumeExtension::Release() const  {
0598   VolumeExtension* ext = const_cast<VolumeExtension*>(this);
0599   --ext->refCount;
0600   if ( 0 == ext->refCount )   {
0601 #ifdef ___print_vols
0602     cout << "Volume deleted....." << endl;
0603 #endif
0604     delete ext;
0605   }
0606   else  {
0607 #ifdef ___print_vols
0608     cout << "VolumeExtension::Release::refCount:" << ext->refCount << endl;
0609 #endif
0610   }
0611 }
0612 
0613 /// Constructor to be used when creating a new geometry tree.
0614 Volume::Volume(const std::string& nam) {
0615   m_element = _createTGeoVolume(nam,0,0);
0616 }
0617 
0618 /// Constructor to be used when creating a new geometry tree.
0619 Volume::Volume(const std::string& nam, const std::string& title) {
0620   m_element = _createTGeoVolume(nam,0,0);
0621   m_element->SetTitle(title.c_str());
0622 }
0623 
0624 /// Constructor to be used when creating a new geometry tree. Also sets materuial and solid attributes
0625 Volume::Volume(const std::string& nam, const Solid& sol, const Material& mat) {
0626   m_element = _createTGeoVolume(nam, sol.ptr(), mat.ptr());
0627 }
0628 
0629 /// Constructor to be used when creating a new geometry tree. Also sets materuial and solid attributes
0630 Volume::Volume(const std::string& nam, const std::string& title, const Solid& sol, const Material& mat) {
0631   m_element = _createTGeoVolume(nam, sol.ptr(), mat.ptr());
0632   m_element->SetTitle(title.c_str());
0633 }
0634 
0635 /// Set flag to enable copy number checks when inserting new nodes
0636 void Volume::enableCopyNumberCheck(bool value)    {
0637   s_verifyCopyNumbers = value;
0638 }
0639 
0640 /// Check if placement is properly instrumented
0641 Volume::Object* Volume::data() const   {
0642   Volume::Object* o = _userExtension(*this);
0643   return o;
0644 }
0645 
0646 /// Access the object type from the class information
0647 const char* Volume::type() const   {
0648   return m_element ? m_element->IsA()->GetName() : "UNKNOWN-Volume";
0649 }
0650 
0651 /// Create a reflected volume tree. The reflected volume has left-handed coordinates
0652 Volume Volume::reflect()  const   {
0653   return this->reflect(this->sensitiveDetector());
0654 }
0655     
0656 /// Create a reflected volume tree. The reflected volume has left-handed coordinates
0657 Volume Volume::reflect(SensitiveDetector sd)  const   {
0658   if ( m_element )   {
0659     VolumeImport imp;
0660     Object* o = data();
0661     if ( !o->reflected.isValid() )  {
0662       TGeoVolume* vol = MakeReflection(m_element);
0663       imp(vol, m_element, sd, Volume::REFLECTED);
0664       o->reflected = vol;
0665     }
0666     return o->reflected;
0667   }
0668   except("dd4hep","Volume: Attempt to reflect an invalid Volume handle.");
0669   return *this;
0670 }
0671 
0672 /// If we import volumes from external sources, we have to attach the extensions to the tree
0673 Volume& Volume::import()    {
0674   if ( m_element )   {
0675     VolumeImport imp;
0676     imp(m_element);
0677     return *this;
0678   }
0679   except("dd4hep","Volume: Attempt to import an invalid Volume handle.");
0680   return *this;
0681 }
0682 
0683 /// Set user flags in bit-field
0684 void Volume::setFlagBit(unsigned int bit)   {
0685   if ( bit <= 31 )   {
0686     data()->flags |= 1<<bit;
0687     return;
0688   }
0689   except("Volume","+++ Volume flag bit outsize range [0...31]: %d",bit);
0690 }
0691 
0692 /// Test the user flag bit
0693 bool Volume::testFlagBit(unsigned int bit)   const    {
0694   if ( bit <= 31 )   {
0695     return (data()->flags & 1<<bit) != 0;
0696   }
0697   except("Volume","+++ Volume flag bit outsize range [0...31]: %d",bit);
0698   return false; // Anyhow never called. Only to satisfy the compiler.
0699 }    
0700 
0701 /// Test if this volume was reflected
0702 bool Volume::isReflected()   const    {
0703   return testFlagBit(REFLECTED);
0704 }
0705 
0706 /// Test if this volume is an assembly structure
0707 bool Volume::isAssembly()   const   {
0708   return m_element ? m_element->IsAssembly() : false;
0709 }    
0710 
0711 /// Divide volume into subsections (See the ROOT manuloa for details)
0712 Volume Volume::divide(const std::string& divname, int iaxis, int ndiv,
0713                       double start, double step, int numed, const char* option)   {
0714   TGeoVolume* p = m_element;
0715   if ( p )  {
0716     TGeoVolume* mvp = p->Divide(divname.c_str(), iaxis, ndiv, start, step, numed, option);
0717     if ( mvp )   {
0718       VolumeImport imp;
0719       imp(mvp);
0720       return VolumeMulti(mvp);
0721     }
0722     except("dd4hep","Volume: Failed to divide volume %s -> %s [Invalid result]",
0723            p->GetName(), divname.c_str());
0724   }
0725   except("dd4hep","Volume: Attempt to divide an invalid logical volume.");
0726   return nullptr;
0727 }
0728 
0729 PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* transform) {
0730   TGeoVolume* parent = par;
0731   if ( !parent )   {
0732     except("dd4hep","Volume: Attempt to assign daughters to an invalid physical parent volume.");
0733   }
0734   else if ( !daughter )   {
0735     except("dd4hep","Volume: Attempt to assign an invalid physical daughter volume.");
0736   }
0737   else if ( !transform )   {
0738     except("dd4hep","Volume: Attempt to place volume without placement matrix.");
0739   }
0740   if ( transform != detail::matrix::_identity() ) {
0741     std::string nam = std::string(daughter->GetName()) + "_placement";
0742     transform->SetName(nam.c_str());
0743   }
0744   TGeoShape* shape = daughter->GetShape();
0745   // Need to fix the daughter's BBox of assemblies, if the BBox was not calculated....
0746   if ( shape->IsA() == TGeoShapeAssembly::Class() )  {
0747     TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
0748     as->NeedsBBoxRecompute();
0749     as->ComputeBBox();
0750   }
0751   const Double_t* r = transform->GetRotationMatrix();
0752   if ( r )   {
0753     Double_t test_rot = r[0] + r[4] + r[8] - 3.0;
0754     if ( TMath::Abs(test_rot) < s_rotation_test_limit )
0755       transform->ResetBit(TGeoMatrix::kGeoRotation);
0756     else
0757       transform->SetBit(TGeoMatrix::kGeoRotation);
0758 
0759     if ( transform->IsRotation() )   {
0760       Double_t det =
0761         r[0]*r[4]*r[8] + r[3]*r[7]*r[2] + r[6]*r[1]*r[5] -
0762         r[2]*r[4]*r[6] - r[5]*r[7]*r[0] - r[8]*r[1]*r[3];
0763       /// We have a left handed matrix (determinant < 0). This is a reflection!
0764       if ( det < 0e0 )   {
0765         transform->SetBit(TGeoMatrix::kGeoReflection);
0766         printout(DEBUG, "PlacedVolume",
0767                  "REFLECTION: (x.Cross(y)).Dot(z): %8.3g Parent: %s [%s] Daughter: %s [%s]",
0768                  det, par->GetName(), par->IsA()->GetName(),
0769                  daughter->GetName(), daughter->IsA()->GetName());
0770       }
0771     }
0772   }
0773   geo_node_t* n {nullptr};
0774   TString nam_id = TString::Format("%s_%d", daughter->GetName(), id);
0775   if ( s_verifyCopyNumbers )   {
0776     n = static_cast<geo_node_t*>(parent->GetNode(nam_id));
0777     if ( n != 0 )  {
0778       printout(ERROR,"PlacedVolume","++ Attempt to place already exiting node %s",(const char*)nam_id);
0779     }
0780   }
0781   /* n = */ parent->AddNode(daughter, id, transform);
0782   //n = static_cast<geo_node_t*>(parent->GetNode(nam_id));
0783   n = static_cast<geo_node_t*>(parent->GetNodes()->Last());
0784   if ( nam_id != n->GetName() )   {
0785     printout(ERROR,"PlacedVolume","++ FAILED to place node %s",(const char*)nam_id);
0786   }
0787   PlacedVolume::Object* extension = new PlacedVolume::Object();
0788   n->geo_node_t::SetUserExtension(extension);
0789   return PlacedVolume(n);
0790 }
0791 
0792 PlacedVolume _addNode(TGeoVolume* par, Volume daughter, int copy_nr, const Rotation3D& rot3D)   {
0793   TGeoRotation r;
0794   double elements[9];
0795   rot3D.GetComponents(elements);
0796   r.SetMatrix(elements);
0797   auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(0,0,0),r);
0798   return _addNode(par, daughter, copy_nr, matrix.release());
0799 }
0800 
0801 PlacedVolume _addNode(TGeoVolume* par, Volume daughter, int copy_nr, const Transform3D& tr)   {
0802   TGeoRotation r;
0803   double elements[9];
0804   Position   pos3D;
0805   Rotation3D rot3D;
0806   tr.GetRotation(rot3D);
0807   tr.GetTranslation(pos3D);
0808   rot3D.GetComponents(elements);
0809   r.SetMatrix(elements);
0810   auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(pos3D.x(), pos3D.y(), pos3D.z()),r);
0811   return _addNode(par, daughter, copy_nr, matrix.release());
0812 }
0813 
0814 /// Place daughter volume with generic TGeo matrix
0815 PlacedVolume Volume::placeVolume(const Volume& volume, TGeoMatrix* tr) const    {
0816   return _addNode(m_element, volume, get_copy_number(m_element), tr);
0817 }
0818 
0819 /// Place daughter volume with generic TGeo matrix
0820 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_nr, TGeoMatrix* tr) const    {
0821   return _addNode(m_element, volume, copy_nr, tr);
0822 }
0823 
0824 /// Place daughter volume according to generic Transform3D
0825 PlacedVolume Volume::placeVolume(const Volume& volume, const Transform3D& trans) const {
0826   return _addNode(m_element, volume, get_copy_number(m_element), trans);
0827 }
0828 
0829 /// Place daughter volume. The position and rotation are the identity
0830 PlacedVolume Volume::placeVolume(const Volume& volume) const {
0831   return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_identity());
0832 }
0833 
0834 /// Place un-rotated daughter volume at the given position.
0835 PlacedVolume Volume::placeVolume(const Volume& volume, const Position& pos) const {
0836   return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_translation(pos));
0837 }
0838 
0839 /// Place rotated daughter volume. The position is automatically the identity position
0840 PlacedVolume Volume::placeVolume(const Volume& volume, const RotationZYX& rot) const {
0841   return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_rotationZYX(rot));
0842 }
0843 
0844 /// Place rotated daughter volume. The position is automatically the identity position
0845 PlacedVolume Volume::placeVolume(const Volume& volume, const Rotation3D& rot) const {
0846   return _addNode(m_element, volume, get_copy_number(m_element), rot);
0847 }
0848 
0849 /// Place daughter volume according to generic Transform3D
0850 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Transform3D& trans) const {
0851   return _addNode(m_element, volume, copy_no, trans);
0852 }
0853 
0854 /// Place daughter volume. The position and rotation are the identity
0855 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no) const {
0856   return _addNode(m_element, volume, copy_no, detail::matrix::_identity());
0857 }
0858 
0859 /// Place un-rotated daughter volume at the given position.
0860 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Position& pos) const {
0861   return _addNode(m_element, volume, copy_no, detail::matrix::_translation(pos));
0862 }
0863 
0864 /// Place rotated daughter volume. The position is automatically the identity position
0865 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const RotationZYX& rot) const {
0866   return _addNode(m_element, volume, copy_no, detail::matrix::_rotationZYX(rot));
0867 }
0868 
0869 /// Place rotated daughter volume. The position is automatically the identity position
0870 PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Rotation3D& rot) const {
0871   return _addNode(m_element, volume, copy_no, rot);
0872 }
0873 
0874 /// 1D volume replication implementation
0875 PlacedVolume Volume::replicate(const Volume entity, ReplicationAxis axis,
0876                    size_t count, double inc, double start)
0877 {
0878   Transform3D offset(1e0,  0e0,  0e0,  axis == X_axis ? start : 0e0,
0879              0e0,  1e0,  0e0,  axis == Y_axis ? start : 0e0,
0880              0e0,  0e0,  1e0,  axis == Z_axis ? start : 0e0);
0881   Transform3D tr(1e0,  0e0,  0e0,  axis == X_axis ? inc : 0e0,
0882          0e0,  1e0,  0e0,  axis == Y_axis ? inc : 0e0,
0883          0e0,  0e0,  1e0,  axis == Z_axis ? inc : 0e0);
0884   PlacedVolume pv = paramVolume1D(offset, entity, count, tr);
0885   auto* data = pv.data();
0886   data->params->flags = axis | REPLICATED;
0887   return pv;
0888 }
0889 
0890 /// Constructor to be used when creating a new parameterised volume object
0891 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const Position& inc)   {
0892   return paramVolume1D(Transform3D(), entity, count, Transform3D(inc));
0893 }
0894 
0895 /// Constructor to be used when creating a new parameterised volume object
0896 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const RotationZYX& inc)  {
0897   return paramVolume1D(Transform3D(), entity, count, Transform3D(inc));
0898 }
0899 
0900 /// Constructor to be used when creating a new parameterised volume object
0901 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const Transform3D& inc)   {
0902   return paramVolume1D(Transform3D(), entity, count, inc);
0903 }
0904 
0905 /// Constructor to be used when creating a new parameterised volume object
0906 PlacedVolume Volume::paramVolume1D(const Transform3D& start,
0907                    Volume entity,
0908                    size_t count,
0909                    const Transform3D& trafo)
0910 {
0911   Transform3D tr(start);
0912   PlacedVolume pv =
0913     _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr));
0914   auto* data = pv.data();
0915   if ( pv->GetNdaughters() > 1 )   {
0916     except("Volume","paramVolume1D: Mother %s has too many daughters: %ld "
0917        "Parameterized volumes may only have one single daughter!",
0918        ptr()->GetName(), pv.volume()->GetNdaughters());
0919   }
0920   data->params = new PlacedVolumeExtension::Parameterisation();
0921   data->params->addref();
0922   data->params->flags = PARAMETERIZED;
0923   data->params->start = start;
0924   data->params->trafo1D.first  = trafo;
0925   data->params->trafo1D.second = count;
0926   data->params->trafo2D.second = 0;
0927   data->params->trafo3D.second = 0;
0928   data->params->placements.emplace_back(pv);
0929   for(size_t i=1; i < count; ++i)    {
0930     tr *= trafo;
0931     PlacedVolume ppv =
0932       _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr));
0933     data->params->placements.emplace_back(ppv);
0934     ppv.data()->params = data->params->addref();
0935   }
0936   return pv;
0937 }
0938 
0939 /// Constructor to be used when creating a new parameterised volume object
0940 PlacedVolume Volume::paramVolume2D(Volume entity,
0941                    size_t count_1,
0942                    const Transform3D& trafo_1,
0943                    size_t count_2,
0944                    const Transform3D& trafo_2)
0945 {
0946   return paramVolume2D(Transform3D(), entity, count_1, trafo_1, count_2, trafo_2);
0947 }
0948 
0949 /// Constructor to be used when creating a new parameterised volume object
0950 PlacedVolume Volume::paramVolume2D(const Transform3D& start,
0951                    Volume entity,
0952                    size_t count_1,
0953                    const Position& pos_1,
0954                    size_t count_2,
0955                    const Position& pos_2)
0956 {
0957   return paramVolume2D(start, entity, count_1, Transform3D(pos_1), count_2, Transform3D(pos_2));
0958 }
0959 
0960 /// Constructor to be used when creating a new parameterised volume object
0961 PlacedVolume Volume::paramVolume2D(Volume entity,
0962                    size_t count_1,
0963                    const Position& pos_1,
0964                    size_t count_2,
0965                    const Position& pos_2)
0966 {
0967   return paramVolume2D(Transform3D(), entity, count_1, Transform3D(pos_1), count_2, Transform3D(pos_2));
0968 }
0969 
0970 /// Constructor to be used when creating a new parameterised volume object
0971 PlacedVolume Volume::paramVolume2D(const Transform3D& start,
0972                    Volume entity,
0973                    size_t count_1,
0974                    const Transform3D& trafo_1,
0975                    size_t count_2,
0976                    const Transform3D& trafo_2)
0977 {
0978   PlacedVolume pv =
0979     _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(start));
0980   auto* data = pv.data();
0981   if ( pv->GetNdaughters() > 1 )   {
0982     except("Volume","paramVolume1D: Mother %s has too many daughters: %ld "
0983        "Parameterized volumes may only have one single daughter!",
0984        ptr()->GetName(), pv.volume()->GetNdaughters());
0985   }
0986   data->params = new PlacedVolumeExtension::Parameterisation();
0987   data->params->addref();
0988   data->params->flags = PARAMETERIZED;
0989   data->params->start = start;
0990   data->params->trafo1D.first  = trafo_1;
0991   data->params->trafo1D.second = count_1;
0992   data->params->trafo2D.first  = trafo_2;
0993   data->params->trafo2D.second = count_2;
0994   data->params->trafo3D.second = 0;
0995   data->params->placements.emplace_back(pv);
0996   Transform3D tr2(start);
0997   for(size_t j=0; j < count_2; ++j)    {
0998     Transform3D tr1 = tr2;
0999     for(size_t i = 0; i < count_1; ++i)    {
1000       if ( !( i == 0 && j == 0 ) )   {
1001     PlacedVolume ppv =
1002       _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr1));
1003     data->params->placements.emplace_back(ppv);
1004     ppv.data()->params = data->params->addref();
1005       }
1006       tr1 *= trafo_1;
1007     }
1008     tr2 *= trafo_2;
1009   }
1010   return pv;
1011 }
1012 
1013 /// Constructor to be used when creating a new parameterised volume object
1014 PlacedVolume Volume::paramVolume3D(const Transform3D& start,
1015                    Volume entity,
1016                    size_t count_1,
1017                    const Position& pos_1,
1018                    size_t count_2,
1019                    const Position& pos_2,
1020                    size_t count_3,
1021                    const Position& pos_3)
1022 {
1023   return paramVolume3D(start, entity, 
1024                count_1, Transform3D(pos_1),
1025                count_2, Transform3D(pos_2),
1026                count_3, Transform3D(pos_3));
1027 }
1028 
1029 /// Constructor to be used when creating a new parameterised volume object
1030 PlacedVolume Volume::paramVolume3D(Volume entity,
1031                    size_t count_1,
1032                    const Position& pos_1,
1033                    size_t count_2,
1034                    const Position& pos_2,
1035                    size_t count_3,
1036                    const Position& pos_3)
1037 {
1038   return paramVolume3D(Transform3D(), entity,
1039                count_1, Transform3D(pos_1),
1040                count_2, Transform3D(pos_2),
1041                count_3, Transform3D(pos_3));
1042 }
1043 
1044 /// Constructor to be used when creating a new parameterised volume object
1045 PlacedVolume Volume::paramVolume3D(const Transform3D& start,
1046                    Volume entity,
1047                    size_t count_1,
1048                    const Transform3D& trafo_1,
1049                    size_t count_2,
1050                    const Transform3D& trafo_2,
1051                    size_t count_3,
1052                    const Transform3D& trafo_3)
1053 {
1054   PlacedVolume pv =
1055     _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(start));
1056   auto* data = pv.data();
1057   if ( pv->GetNdaughters() > 1 )   {
1058     except("Volume","paramVolume1D: Mother %s has too many daughters: %ld "
1059        "Parameterized volumes may only have one single daughter!",
1060        ptr()->GetName(), pv.volume()->GetNdaughters());
1061   }
1062   data->params = new PlacedVolumeExtension::Parameterisation();
1063   data->params->addref();
1064   data->params->flags = PARAMETERIZED;
1065   data->params->start = start;
1066   data->params->trafo1D.first  = trafo_1;
1067   data->params->trafo1D.second = count_1;
1068   data->params->trafo2D.first  = trafo_2;
1069   data->params->trafo2D.second = count_2;
1070   data->params->trafo3D.first  = trafo_3;
1071   data->params->trafo3D.second = count_3;
1072   data->params->placements.emplace_back(pv);
1073   Transform3D tr3(start);
1074   for(size_t k=0; k < count_3; ++k)    {
1075     Transform3D tr2 = tr3;
1076     for(size_t j=0; j < count_2; ++j)    {
1077       Transform3D tr1 = tr2;
1078       for(size_t i = 0; i < count_1; ++i)    {
1079     if ( !( i == 0 && j == 0 && k == 0 ) )   {
1080       PlacedVolume ppv =
1081         _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(tr1));
1082       data->params->placements.emplace_back(ppv);
1083       ppv.data()->params = data->params->addref();
1084     }
1085     tr1 *= trafo_1;
1086       }
1087       tr2 *= trafo_2;
1088     }
1089     tr3 *= trafo_3;
1090   }
1091   return pv;
1092 }
1093 
1094 /// Set the volume's option value
1095 const Volume& Volume::setOption(const std::string& opt) const {
1096   if ( isValid() )   {
1097     m_element->SetOption(opt.c_str());
1098     return *this;
1099   }
1100   throw std::runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume");
1101 }
1102 
1103 /// Access the volume's option value
1104 std::string Volume::option() const {
1105   return m_element->GetOption();
1106 }
1107 
1108 /// Set the volume's material
1109 const Volume& Volume::setMaterial(const Material& mat) const {
1110   if (mat.isValid()) {
1111     TGeoMedium* medium = mat._ptr<TGeoMedium>();
1112     if (medium) {
1113       m_element->SetMedium(medium);
1114       return *this;
1115     }
1116     throw std::runtime_error("dd4hep: Volume: Medium " + std::string(mat.name()) + " is not registered with geometry manager.");
1117   }
1118   throw std::runtime_error("dd4hep: Volume: Attempt to assign invalid material.");
1119 }
1120 
1121 /// Access to the Volume material
1122 Material Volume::material() const {
1123   return Material(m_element->GetMedium());
1124 }
1125 
1126 /// Set Visualization attributes to the volume
1127 const Volume& Volume::setVisAttributes(const VisAttr& attr) const {
1128   if ( attr.isValid() ) {
1129     VisAttr::Object* vis = attr.data<VisAttr::Object>();
1130     TColor* col = vis->color;
1131     if ( col )   {
1132       int draw_style = vis->drawingStyle;
1133       int line_style = vis->lineStyle;
1134       int col_num    = col->GetNumber();
1135       int col_tr_num = vis->colortr->GetNumber();
1136       m_element->SetVisibility(vis->visible ? kTRUE : kFALSE);
1137       m_element->SetVisContainers(kTRUE);
1138       m_element->SetVisDaughters(vis->showDaughters ? kTRUE : kFALSE);
1139       printout(DEBUG,"setVisAttributes",
1140                "Set color %3d transparent(alpha:%.3f): %3d [%02X,%02X,%02X] DrawingStyle:%9s LineStyle:%6s for volume %s",
1141                col_num, vis->alpha, col_tr_num,
1142                int(255*col->GetRed()),
1143                int(255*col->GetGreen()),
1144                int(255*col->GetBlue()),
1145                draw_style == VisAttr::SOLID ? "Solid" : "Wireframe",
1146                line_style == VisAttr::SOLID ? "Solid" : "Dashed",
1147                name()
1148                );
1149       m_element->SetLineWidth(10);
1150       m_element->SetLineColor(col_num);
1151       m_element->SetFillColor(col_tr_num);
1152       if (draw_style == VisAttr::SOLID) {
1153         m_element->SetFillStyle(1001);   // Root: solid
1154 
1155 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,0)
1156         // Set directly transparency to the volume, NOT to the material as for ROOT < 6.29
1157         m_element->ResetTransparency(Char_t((1.0-vis->alpha)*100));
1158 #else
1159         // As suggested by Valentin Volkl https://sft.its.cern.ch/jira/browse/DDFORHEP-20
1160         //
1161         // According to https://root.cern.ch/phpBB3/viewtopic.php?t=2309#p66013
1162         // a transparency>50 will make a volume invisible in the normal pad.
1163         // Hence: possibly restrict transparency to a maximum of 50.
1164         //        but let's see first how this behaves.
1165         m_element->SetTransparency(Char_t((1.0-vis->alpha)*100));
1166 #endif
1167       }
1168       else {
1169         printout(DEBUG,"setVisAttributes","Set to wireframe vis:%s",name());
1170         m_element->SetLineColor(kBlack);
1171         m_element->SetFillColor(0);
1172         m_element->SetFillStyle(0);      // Root: hollow
1173       }
1174       if (line_style == VisAttr::SOLID)  // Root line style: 1=solid, 2=dash, 3=dot, 4=dash-dot.
1175         m_element->SetLineStyle(1);
1176       else if (line_style == VisAttr::DASHED)
1177         m_element->SetLineStyle(2);
1178       else
1179         m_element->SetLineStyle(line_style);
1180     }
1181     else   {
1182       except("Volume","setVisAttributes: encountered valid, but badly initialized visattr: %s",attr.name());
1183     }
1184   }
1185   Volume::Object* o = _userExtension(*this);
1186   if ( o ) o->vis = attr;
1187   return *this;
1188 }
1189 
1190 /// Set Visualization attributes to the volume
1191 const Volume& Volume::setVisAttributes(const Detector& description, const std::string& nam) const {
1192   if (!nam.empty()) {
1193     VisAttr attr = description.visAttributes(nam);
1194     setVisAttributes(attr);
1195   }
1196   return *this;
1197 }
1198 
1199 /// Attach attributes to the volume
1200 const Volume& Volume::setAttributes(const Detector& description, const std::string& rg, const std::string& ls, const std::string& vis) const {
1201   if (!rg.empty())
1202     setRegion(description.region(rg));
1203   if (!ls.empty())
1204     setLimitSet(description.limitSet(ls));
1205   setVisAttributes(description, vis);
1206   return *this;
1207 }
1208 
1209 /// Access the visualisation attributes
1210 VisAttr Volume::visAttributes() const {
1211   Object* o = _data(*this, false);
1212   if (o) return o->vis;
1213   return VisAttr();
1214 }
1215 
1216 /// Set the volume's solid shape
1217 const Volume& Volume::setSolid(const Solid& sol) const {
1218   m_element->SetShape(sol);
1219   return *this;
1220 }
1221 
1222 /// Access to Solid (Shape)
1223 Solid Volume::solid() const {
1224   return Solid((*this)->GetShape());
1225 }
1226 
1227 /// Access the bounding box of the volume (if available)
1228 Box Volume::boundingBox() const {
1229   Box box = this->solid();
1230   if ( box.isValid() )   {
1231     return box;
1232   }
1233   else if ( !isValid() )   {
1234     except("dd4hep","Volume: Cannot access the bounding box of an invalid volume [Invalid Handle]!");
1235   }
1236   except("dd4hep","Volume: Cannot access the bounding box an object of type: %s shape: %s",
1237          this->ptr()->IsA()->GetName(), this->ptr()->GetShape()->IsA()->GetName());
1238   return box;
1239 }
1240 
1241 /// Set the regional attributes to the volume
1242 const Volume& Volume::setRegion(const Detector& description, const std::string& nam) const {
1243   if (!nam.empty()) {
1244     return setRegion(description.region(nam));
1245   }
1246   return *this;
1247 }
1248 
1249 /// Set the regional attributes to the volume
1250 const Volume& Volume::setRegion(const Region& obj) const {
1251   _data(*this)->region = obj;
1252   return *this;
1253 }
1254 
1255 /// Access to the handle to the region structure
1256 Region Volume::region() const {
1257   return _data(*this)->region;
1258 }
1259 
1260 /// Set the limits to the volume
1261 const Volume& Volume::setLimitSet(const Detector& description, const std::string& nam) const {
1262   if (!nam.empty()) {
1263     return setLimitSet(description.limitSet(nam));
1264   }
1265   return *this;
1266 }
1267 
1268 /// Set the limits to the volume
1269 const Volume& Volume::setLimitSet(const LimitSet& obj) const {
1270   _data(*this)->limits = obj;
1271   return *this;
1272 }
1273 
1274 /// Access to the limit set
1275 LimitSet Volume::limitSet() const {
1276   return _data(*this)->limits;
1277 }
1278 
1279 /// Assign the sensitive detector structure
1280 const Volume& Volume::setSensitiveDetector(const SensitiveDetector& obj) const {
1281   //cout << "Setting sensitive detector '" << obj.name() << "' to volume:" << ptr() << " " << name() << endl;
1282   _data(*this)->sens_det = obj;
1283   return *this;
1284 }
1285 
1286 /// Access to the handle to the sensitive detector
1287 Ref_t Volume::sensitiveDetector() const {
1288   const Object* o = _data(*this);
1289   return o->sens_det;
1290 }
1291 
1292 /// Accessor if volume is sensitive (ie. is attached to a sensitive detector)
1293 bool Volume::isSensitive() const {
1294   return _data(*this)->sens_det.isValid();
1295 }
1296 
1297 /// Check for existence of properties
1298 bool Volume::hasProperties()  const   {
1299   return _data(*this)->properties != nullptr;
1300 }
1301 
1302 /// Add Volume property (name-value pair)
1303 void Volume::addProperty(const std::string& nam, const std::string& val) const  {
1304   auto* o = _data(*this);
1305   if ( !o->properties )   {
1306     o->properties = new TList();
1307     o->properties->SetOwner();
1308   }
1309   TNamed *prop = (TNamed*)o->properties->FindObject(nam.c_str());
1310   if ( !prop )   {
1311     o->properties->Add(new TNamed(nam.c_str(), val.c_str()));
1312     return;
1313   }
1314   except("Volume::addProperty", "Volume: '%s' Property '%s' is already set!",
1315      ptr()->GetName(), nam.c_str());
1316 }
1317 
1318 /// Access property value. Returns default_value if the property is not present
1319 std::string Volume::getProperty(const std::string& nam, const std::string& default_val)   const {
1320   const auto* o = _data(*this);
1321   if ( !o->properties )   {
1322     return default_val;
1323   }
1324   TNamed *prop = (TNamed*)o->properties->FindObject(nam.c_str());
1325   if ( prop ) return prop->GetTitle();
1326   return default_val;
1327 }
1328 
1329 /// Constructor to be used when creating a new assembly object
1330 Assembly::Assembly(const std::string& nam) {
1331   m_element = _createTGeoVolumeAssembly(nam);
1332 }
1333 
1334 /// Constructor to be used when creating a new multi-volume object
1335 VolumeMulti::VolumeMulti(const std::string& nam, Material mat) {
1336   m_element = _createTGeoVolumeMulti(nam, mat.ptr());
1337 }
1338 
1339 /// Import volume from pointer as a result of Solid->Divide()
1340 void VolumeMulti::verifyVolumeMulti()   {
1341   if ( m_element )  {
1342     // This will lead to an exception if the type is not TGeoVolumeMulti
1343     TGeoVolumeMulti* multi = detail::safe_cast<TGeoVolumeMulti>::cast(m_element);
1344     if ( multi )  {
1345       import();
1346       return;
1347     }
1348     // Force a bad cast exception
1349     Handle<TGeoVolumeMulti> handle(m_element);
1350     if ( handle.isValid() )  {}
1351   }
1352 }
1353 
1354 /// Output mesh vertices to string
1355 std::string dd4hep::toStringMesh(PlacedVolume place, int prec)   {
1356   Volume       vol   = place->GetVolume();
1357   TGeoMatrix*  mat   = place->GetMatrix();
1358   Solid        sol   = vol.solid();
1359   std::stringstream os;
1360   struct _numbering {
1361     double adjust(double value)  const   {
1362       if ( std::abs(value) < TGeoShape::Tolerance() )
1363         return 0.0;
1364       return value/dd4hep::cm;
1365     }
1366   } _vertex;
1367 
1368   if ( vol->IsA() == TGeoVolumeAssembly::Class() )    {
1369     for(int i=0; i<vol->GetNdaughters(); ++i)  {
1370       os << toStringMesh(vol->GetNode(i), prec) << std::endl;
1371     }
1372     return os.str();
1373   }
1374 
1375   // Prints shape parameters
1376   int nvert = 0, nsegs = 0, npols = 0;
1377   sol->GetMeshNumbers(nvert, nsegs, npols);
1378   Double_t* points = new Double_t[3*nvert];
1379   sol->SetPoints(points);
1380 
1381   os << std::setw(16) << std::left << sol->IsA()->GetName()
1382      << " " << nvert << " Mesh-points:" << std::endl;
1383   os << std::setw(16) << std::left << sol->IsA()->GetName() << " " << sol->GetName()
1384      << " N(mesh)=" << sol->GetNmeshVertices()
1385      << "  N(vert)=" << nvert << "  N(seg)=" << nsegs << "  N(pols)=" << npols << std::endl;
1386     
1387   for(int i=0; i<nvert; ++i)   {
1388     Double_t* p = points + 3*i;
1389     Double_t global[3], local[3] = {p[0], p[1], p[2]};
1390     mat->LocalToMaster(local, global);
1391     os << std::setw(16) << std::left << sol->IsA()->GetName() << " " << std::setw(3) << std::left << i
1392        << " Local  ("  << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[0])
1393        << ", "         << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[1])
1394        << ", "         << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[2])
1395        << ") Global (" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[0])
1396        << ", "         << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[1])
1397        << ", "         << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[2])
1398        << ")" << std::endl;
1399   }
1400   Box box = sol;
1401   const Double_t* org = box->GetOrigin();
1402   os << std::setw(16) << std::left << sol->IsA()->GetName()
1403      << " Bounding box: "
1404      << " dx="        << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDX())
1405      << " dy="        << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDY())
1406      << " dz="        << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDZ())
1407      << " Origin: x=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[0])
1408      << " y="         << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[1])
1409      << " z="         << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[2])
1410      << std::endl;
1411   
1412   /// -------------------- DONE --------------------
1413   delete [] points;
1414   return os.str();
1415 }
1416