File indexing completed on 2025-01-30 09:17:06
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 throw std::runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume");
0091 }
0092
0093 Volume::Object* _data(const Volume& v, bool throw_exception = true) {
0094
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
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
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
0231
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
0238 }
0239
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
0248
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
0255
0256 local_cloned->ReflectZ(kTRUE);
0257 local_cloned->ReflectZ(kFALSE);
0258
0259
0260 new_vol = MakeReflection(node->GetVolume());
0261 node->SetVolume(new_vol);
0262 continue;
0263 }
0264
0265 local_cloned->ReflectZ(kTRUE);
0266
0267
0268 }
0269 if ( vol->GetVoxels() ) vol->GetVoxels()->Voxelize();
0270 return vol;
0271 }
0272
0273
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
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
0317
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
0334 PlacedVolume::Processor::Processor() {
0335 }
0336
0337
0338 PlacedVolume::Processor::~Processor() {
0339 }
0340
0341
0342 PlacedVolumeExtension::Parameterisation* PlacedVolumeExtension::Parameterisation::addref() {
0343 ++refCount;
0344 return this;
0345 }
0346
0347 void PlacedVolumeExtension::Parameterisation::release() {
0348 --refCount;
0349 if ( 0 == refCount ) delete this;
0350 }
0351
0352
0353 PlacedVolumeExtension::PlacedVolumeExtension()
0354 : TGeoExtension(), volIDs()
0355 {
0356 magic = magic_word();
0357 INCREMENT_COUNTER;
0358 }
0359
0360
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
0367 PlacedVolumeExtension::PlacedVolumeExtension(const PlacedVolumeExtension& c)
0368 : TGeoExtension(), magic(c.magic), refCount(0), volIDs() {
0369 INCREMENT_COUNTER;
0370 volIDs = c.volIDs;
0371 }
0372
0373
0374 PlacedVolumeExtension::~PlacedVolumeExtension() {
0375 if ( this->params ) this->params->release();
0376 DECREMENT_COUNTER;
0377 }
0378
0379
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
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
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
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
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
0431 PlacedVolume::Object* PlacedVolume::data() const {
0432 PlacedVolume::Object* o = _userExtension(*this);
0433 return o;
0434 }
0435
0436
0437 const char* PlacedVolume::type() const {
0438 return m_element ? m_element->IsA()->GetName() : "UNKNOWN-PlacedVolume";
0439 }
0440
0441
0442 int PlacedVolume::copyNumber() const {
0443 return m_element ? m_element->GetNumber() : -1;
0444 }
0445
0446
0447 Material PlacedVolume::material() const {
0448 return Material(m_element ? m_element->GetMedium() : 0);
0449 }
0450
0451
0452 Volume PlacedVolume::volume() const {
0453 return Volume(m_element ? m_element->GetVolume() : 0);
0454 }
0455
0456
0457 Volume PlacedVolume::motherVol() const {
0458 return Volume(m_element ? m_element->GetMotherVolume() : 0);
0459 }
0460
0461
0462 std::size_t PlacedVolume::num_daughters() const {
0463 return m_element ? m_element->GetNdaughters() : 0;
0464 }
0465
0466
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
0480 const PlacedVolume::VolIDs& PlacedVolume::volIDs() const {
0481 return _data(*this)->volIDs;
0482 }
0483
0484
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
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
0518 Position PlacedVolume::position() const {
0519 const double* ptr = matrix().GetTranslation();
0520 return Position(ptr[0],ptr[1],ptr[2]);
0521 }
0522
0523
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
0537 VolumeExtension::VolumeExtension()
0538 : TGeoExtension(), region(), limits(), vis(), sens_det() {
0539 INCREMENT_COUNTER;
0540 }
0541
0542
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
0553 VolumeExtension::VolumeExtension(const VolumeExtension& c) {
0554 this->copy(c);
0555 }
0556
0557
0558 VolumeExtension& VolumeExtension::operator=(const VolumeExtension& c) {
0559 this->copy(c);
0560 return *this;
0561 }
0562
0563
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
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
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
0614 Volume::Volume(const std::string& nam) {
0615 m_element = _createTGeoVolume(nam,0,0);
0616 }
0617
0618
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
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
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
0636 void Volume::enableCopyNumberCheck(bool value) {
0637 s_verifyCopyNumbers = value;
0638 }
0639
0640
0641 Volume::Object* Volume::data() const {
0642 Volume::Object* o = _userExtension(*this);
0643 return o;
0644 }
0645
0646
0647 const char* Volume::type() const {
0648 return m_element ? m_element->IsA()->GetName() : "UNKNOWN-Volume";
0649 }
0650
0651
0652 Volume Volume::reflect() const {
0653 return this->reflect(this->sensitiveDetector());
0654 }
0655
0656
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
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
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
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;
0699 }
0700
0701
0702 bool Volume::isReflected() const {
0703 return testFlagBit(REFLECTED);
0704 }
0705
0706
0707 bool Volume::isAssembly() const {
0708 return m_element ? m_element->IsAssembly() : false;
0709 }
0710
0711
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
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
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 parent->AddNode(daughter, id, transform);
0782
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
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
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
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
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
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
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
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
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
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
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
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
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
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
0891 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const Position& inc) {
0892 return paramVolume1D(Transform3D(), entity, count, Transform3D(inc));
0893 }
0894
0895
0896 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const RotationZYX& inc) {
0897 return paramVolume1D(Transform3D(), entity, count, Transform3D(inc));
0898 }
0899
0900
0901 PlacedVolume Volume::paramVolume1D(Volume entity, size_t count, const Transform3D& inc) {
0902 return paramVolume1D(Transform3D(), entity, count, inc);
0903 }
0904
0905
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
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
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
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
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
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
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
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
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
1104 std::string Volume::option() const {
1105 return m_element->GetOption();
1106 }
1107
1108
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
1122 Material Volume::material() const {
1123 return Material(m_element->GetMedium());
1124 }
1125
1126
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);
1154
1155 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,0)
1156
1157 m_element->ResetTransparency(Char_t((1.0-vis->alpha)*100));
1158 #else
1159
1160
1161
1162
1163
1164
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);
1173 }
1174 if (line_style == VisAttr::SOLID)
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
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
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
1210 VisAttr Volume::visAttributes() const {
1211 Object* o = _data(*this, false);
1212 if (o) return o->vis;
1213 return VisAttr();
1214 }
1215
1216
1217 const Volume& Volume::setSolid(const Solid& sol) const {
1218 m_element->SetShape(sol);
1219 return *this;
1220 }
1221
1222
1223 Solid Volume::solid() const {
1224 return Solid((*this)->GetShape());
1225 }
1226
1227
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
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
1250 const Volume& Volume::setRegion(const Region& obj) const {
1251 _data(*this)->region = obj;
1252 return *this;
1253 }
1254
1255
1256 Region Volume::region() const {
1257 return _data(*this)->region;
1258 }
1259
1260
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
1269 const Volume& Volume::setLimitSet(const LimitSet& obj) const {
1270 _data(*this)->limits = obj;
1271 return *this;
1272 }
1273
1274
1275 LimitSet Volume::limitSet() const {
1276 return _data(*this)->limits;
1277 }
1278
1279
1280 const Volume& Volume::setSensitiveDetector(const SensitiveDetector& obj) const {
1281
1282 _data(*this)->sens_det = obj;
1283 return *this;
1284 }
1285
1286
1287 Ref_t Volume::sensitiveDetector() const {
1288 const Object* o = _data(*this);
1289 return o->sens_det;
1290 }
1291
1292
1293 bool Volume::isSensitive() const {
1294 return _data(*this)->sens_det.isValid();
1295 }
1296
1297
1298 bool Volume::hasProperties() const {
1299 return _data(*this)->properties != nullptr;
1300 }
1301
1302
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
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
1330 Assembly::Assembly(const std::string& nam) {
1331 m_element = _createTGeoVolumeAssembly(nam);
1332 }
1333
1334
1335 VolumeMulti::VolumeMulti(const std::string& nam, Material mat) {
1336 m_element = _createTGeoVolumeMulti(nam, mat.ptr());
1337 }
1338
1339
1340 void VolumeMulti::verifyVolumeMulti() {
1341 if ( m_element ) {
1342
1343 TGeoVolumeMulti* multi = detail::safe_cast<TGeoVolumeMulti>::cast(m_element);
1344 if ( multi ) {
1345 import();
1346 return;
1347 }
1348
1349 Handle<TGeoVolumeMulti> handle(m_element);
1350 if ( handle.isValid() ) {}
1351 }
1352 }
1353
1354
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
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
1413 delete [] points;
1414 return os.str();
1415 }
1416