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