25 #include <TGeoShape.h>
26 #include <TGeoVolume.h>
28 #include <TGeoMatrix.h>
29 #include <TGeoMedium.h>
31 #include <TGeoVoxelFinder.h>
32 #include <TGeoShapeAssembly.h>
33 #include <TGeoScaledShape.h>
63 static constexpr
double s_rotation_test_limit = 1e-12;
64 static bool s_verifyCopyNumbers =
true;
66 template <
typename T>
typename T::Object* _userExtension(
const T&
v) {
67 typedef typename T::Object O;
68 O* o = (O*)(
v.ptr()->GetUserExtension());
72 TGeoVolume* _createTGeoVolume(
const std::string& name, TGeoShape* s, TGeoMedium* m) {
77 TGeoVolume* _createTGeoVolumeAssembly(
const std::string& name) {
82 TGeoVolumeMulti* _createTGeoVolumeMulti(
const std::string& name, TGeoMedium* medium) {
83 TGeoVolumeMulti* e =
new TGeoVolumeMulti(name.c_str(), medium);
90 except(
"PlacedVolume::_data",
"+++ Attempt to access invalid handle of type: PlacedVolume");
99 else if (!throw_exception)
101 except(
"Volume::_data",
"+++ Attempt to access invalid handle of type: Volume");
107 void setShapeTitle(TGeoVolume* vol) {
109 TGeoShape* sh = vol->GetShape();
111 sh->SetTitle(tag.c_str());
117 void operator()(TGeoVolume*
v) {
118 TClass* c =
v->IsA();
119 if ( !
v->GetUserExtension() ) {
120 if ( c == geo_volume_t::Class() )
122 else if ( c == geo_assembly_t::Class() )
124 else if ( c == TGeoVolumeMulti::Class() )
127 except(
"dd4hep",
"VolumeImport: Unknown TGeoVolume sub-class: %s",
v->IsA()->GetName());
129 if ( c == TGeoVolumeMulti::Class() ) {
130 TGeoVolumeMulti* mv = (TGeoVolumeMulti*)
v;
131 for(
int i=0, n=mv->GetNvolumes(); i<n; ++i ) {
132 TGeoVolume* vol = mv->GetVolume(i);
133 this->setShapeTitle(vol);
137 for( Int_t i=0; i<
v->GetNdaughters(); ++i ) {
139 if ( !pv->GetUserExtension() )
141 (*this)(pv->GetVolume());
145 void operator()(TGeoVolume* new_v, TGeoVolume* old_v,
SensitiveDetector sd,
int set_bit) {
146 if ( !new_v || !old_v ) {
147 except(
"dd4hep",
"VolumeImport: ERROR: The refected volume is INVALID!");
149 else if ( !old_v->GetUserExtension() ) {
150 except(
"dd4hep",
"VolumeImport: ERROR: Reflection of non-dd4hep volume %s",new_v->IsA()->GetName());
152 else if ( !new_v->GetUserExtension() ) {
153 TClass* c = new_v->IsA();
159 if ( c == geo_volume_t::Class() ) {
165 else if ( c == geo_assembly_t::Class() ) {
169 new_e->reflected = old_v;
171 else if ( c == TGeoVolumeMulti::Class() ) {
173 TGeoVolumeMulti* new_mv = (TGeoVolumeMulti*)new_v;
174 TGeoVolumeMulti* old_mv = (TGeoVolumeMulti*)old_v;
177 new_e->reflected = old_v;
178 for(
int i=0, n=new_mv->GetNvolumes(); i<n; ++i) {
179 TGeoVolume* vol = new_mv->GetVolume(i);
180 this->setShapeTitle(vol);
181 (*this)(vol, old_mv->GetVolume(i), sd, set_bit);
185 except(
"dd4hep",
"VolumeImport: Unknown TGeoVolume sub-class: %s",new_v->IsA()->GetName());
192 if ( set_bit >= 0 ) new_vol.
setFlagBit(set_bit);
193 for(Int_t i=0; i<new_v->GetNdaughters(); ++i) {
196 if ( !pv->GetUserExtension() ) {
200 (*this)(pv->GetVolume(), ov->GetVolume(), sd, set_bit);
206 TGeoVolume* MakeReflection(TGeoVolume*
v,
const char* newname=0) {
207 static TMap map(100);
208 TGeoVolume* vol = (TGeoVolume*)map.GetValue(
v);
210 if (newname && newname[0])
v->SetName(newname);
213 vol =
v->CloneVolume();
215 printout(ERROR,
"MakeReflection",
"Cannot clone volume %s\n",
v->GetName());
220 if (newname && newname[0]) {
222 vol->SetName(newname);
226 vol->SetName((nam+
"_refl").c_str());
228 delete vol->GetNodes();
229 vol->SetNodes(
nullptr);
230 vol->SetBit(TGeoVolume::kVolumeImportNodes, kFALSE);
231 v->CloneNodesAndConnect(vol);
235 TGeoScale* scale =
new TGeoScale( 1., 1.,-1.);
236 TGeoShape* reflected_shape =
237 TGeoScaledShape::MakeScaledShape((nam+
"_shape_refl").c_str(),
v->GetShape(), scale);
238 vol->SetShape(reflected_shape);
242 Int_t nd = vol->GetNdaughters();
243 if ( !nd )
return vol;
245 if ( !vol->GetFinder() ) {
246 for (Int_t i=0; i < nd; i++) {
247 TGeoNodeMatrix* node = (TGeoNodeMatrix*)vol->GetNode(i);
248 TGeoMatrix* local = node->GetMatrix();
251 Bool_t reflected = local->IsReflection();
252 TGeoMatrix* local_cloned =
new TGeoCombiTrans(*local);
253 local_cloned->RegisterYourself();
254 node->SetMatrix(local_cloned);
258 local_cloned->ReflectZ(kTRUE);
259 local_cloned->ReflectZ(kFALSE);
262 new_vol = MakeReflection(node->GetVolume());
263 node->SetVolume(new_vol);
267 local_cloned->ReflectZ(kTRUE);
271 if ( vol->GetVoxels() ) vol->GetVoxels()->Voxelize();
276 TGeoPatternFinder *new_finder =
v->GetFinder()->MakeCopy(kTRUE);
278 printout(ERROR,
"MakeReflection",
"Could not copy finder for volume %s",
v->GetName());
281 new_finder->SetVolume(vol);
282 vol->SetFinder(new_finder);
283 TGeoNodeOffset *nodeoff;
285 for (Int_t i=0; i<nd; i++) {
286 nodeoff = (TGeoNodeOffset*)vol->GetNode(i);
287 nodeoff->SetFinder(new_finder);
288 new_vol = MakeReflection(nodeoff->GetVolume());
289 nodeoff->SetVolume(new_vol);
294 int get_copy_number(TGeoVolume* par) {
295 TObjArray* a = par ? par->GetNodes() : 0;
296 int copy_nr = (a ? a->GetEntries() : 0);
305 bool print_active = isActivePrintLevel(DEBUG);
307 while ( (node=next()) ) {
308 TGeoMatrix* matrix = node->GetMatrix();
309 if (matrix->IsReflection()) {
310 if ( print_active ) {
311 printout(INFO,
"ReflectionBuilder",
"Reflection matrix:");
314 Volume vol(node->GetVolume());
315 TGeoMatrix* mclone =
new TGeoCombiTrans(*matrix);
316 mclone->RegisterYourself();
319 if ( print_active ) {
320 printout(INFO,
"ReflectionBuilder",
"CLONE matrix:");
323 TGeoNodeMatrix* nodematrix = (TGeoNodeMatrix*)node;
324 nodematrix->SetMatrix(mclone);
325 if ( print_active ) {
326 printout(INFO,
"ReflectionBuilder",
"Reflected volume: %s ", vol.name());
329 node->SetVolume(refl.
ptr());
350 if ( 0 == refCount )
delete this;
399 else cout <<
"Placement grabbed....." << endl;
408 if ( 0 == ext->
refCount )
delete ext;
412 std::vector<PlacedVolumeExtension::VolID>::const_iterator
414 for (Base::const_iterator i = this->Base::begin(); i != this->Base::end(); ++i)
415 if (name == (*i).first)
421 std::pair<std::vector<PlacedVolumeExtension::VolID>::iterator,
bool>
423 Base::iterator i = this->Base::begin();
424 for (; i != this->Base::end(); ++i)
425 if (name == (*i).first)
428 if (i != this->Base::end()) {
429 return make_pair(i,
false);
431 i = this->Base::emplace(this->Base::end(), name, value);
432 return make_pair(i,
true);
437 std::stringstream str;
439 for(
const auto& i : *
this ) {
440 str << i.first <<
"=" << std::setw(4) << std::right
441 << std::setfill(
'0') << i.second << std::setfill(
' ') <<
" ";
454 return m_element ? m_element->IsA()->GetName() :
"UNKNOWN-PlacedVolume";
459 return m_element ? m_element->GetNumber() : -1;
464 return Material(m_element ? m_element->GetMedium() : 0);
469 return Volume(m_element ? m_element->GetVolume() : 0);
474 return Volume(m_element ? m_element->GetMotherVolume() : 0);
479 return m_element ? m_element->GetNdaughters() : 0;
485 if ( which < (std::size_t)m_element->GetNdaughters() ) {
486 return m_element->GetDaughter(which);
488 except(
"Volume",
"+++ Access daughter %ld of %s [Has only %d daughters]",
489 which, m_element->GetName(), m_element->GetNdaughters());
491 except(
"Volume",
"+++ Cannot access daughters of a non-existing volume!");
497 return _data(*this)->volIDs;
502 auto* o = _data(*
this);
504 o->volIDs.emplace_back(nam, value);
508 except(
"PlacedVolume",
509 "+++ addPhysVolID(%s): parameterised volumes only accept '0' is volID."
510 "These automatically get overwritten with the copy number!",
513 if ( !o->volIDs.empty() ) {
514 except(
"PlacedVolume",
515 "+++ addPhysVolID(%s): parameterised volumes can only host 1 physical volume ID."
516 " vol id '%s' is already defined!", ptr()->
GetName(), o->volIDs[0].first.c_str());
520 p->volIDs.emplace_back(nam, pv->GetNumber());
528 except(
"PlacedVolume",
"+++ matrix: Failed to access invalid PlacedVolume! [Invalid handle]");
530 return *(m_element->GetMatrix());
535 const double* ptr = matrix().GetTranslation();
536 return Position(ptr[0],ptr[1],ptr[2]);
541 std::stringstream str;
542 Object* obj = _data(*
this);
543 str << m_element->GetName() <<
": vol='" << m_element->GetVolume()->GetName()
544 <<
"' mat:'" << m_element->GetMatrix()->GetName()
545 <<
"' volID[" << obj->
volIDs.size() <<
"] ";
546 for (VolIDs::const_iterator i = obj->
volIDs.begin(); i != obj->
volIDs.end(); ++i)
547 str << (*i).first <<
"=" << (*i).second <<
" ";
605 cout <<
"Volume grabbed with valid sensitive detector....." << endl;
607 cout <<
"Volume grabbed....." << endl;
618 cout <<
"Volume deleted....." << endl;
624 cout <<
"VolumeExtension::Release::refCount:" << ext->
refCount << endl;
653 s_verifyCopyNumbers = value;
678 TGeoVolume* vol = MakeReflection(
m_element);
684 except(
"dd4hep",
"Volume: Attempt to reflect an invalid Volume handle.");
695 except(
"dd4hep",
"Volume: Attempt to import an invalid Volume handle.");
705 except(
"Volume",
"+++ Volume flag bit outsize range [0...31]: %d",bit);
711 return (
data()->flags & 1<<bit) != 0;
713 except(
"Volume",
"+++ Volume flag bit outsize range [0...31]: %d",bit);
729 Object* obj = _data(*
this);
737 return _data(*this)->smartLess;
742 double start,
double step,
int numed,
const char* option) {
745 TGeoVolume* mvp = p->Divide(divname.c_str(), iaxis, ndiv, start, step, numed,
option);
751 except(
"dd4hep",
"Volume: Failed to divide volume %s -> %s [Invalid result]",
752 p->GetName(), divname.c_str());
754 except(
"dd4hep",
"Volume: Attempt to divide an invalid logical volume.");
759 TGeoVolume* parent = par;
761 except(
"dd4hep",
"Volume: Attempt to assign daughters to an invalid physical parent volume.");
763 else if ( !daughter ) {
764 except(
"dd4hep",
"Volume: Attempt to assign an invalid physical daughter volume.");
766 else if ( !transform ) {
767 except(
"dd4hep",
"Volume: Attempt to place volume without placement matrix.");
770 std::string nam = std::string(daughter->GetName()) +
"_placement";
771 transform->SetName(nam.c_str());
773 TGeoShape* shape = daughter->GetShape();
775 if ( shape->IsA() == TGeoShapeAssembly::Class() ) {
776 TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
777 as->NeedsBBoxRecompute();
780 const Double_t* r = transform->GetRotationMatrix();
782 Double_t test_rot = r[0] + r[4] + r[8] - 3.0;
783 if ( TMath::Abs(test_rot) < s_rotation_test_limit )
784 transform->ResetBit(TGeoMatrix::kGeoRotation);
786 transform->SetBit(TGeoMatrix::kGeoRotation);
788 if ( transform->IsRotation() ) {
790 r[0]*r[4]*r[8] + r[3]*r[7]*r[2] + r[6]*r[1]*r[5] -
791 r[2]*r[4]*r[6] - r[5]*r[7]*r[0] - r[8]*r[1]*r[3];
794 transform->SetBit(TGeoMatrix::kGeoReflection);
795 printout(DEBUG,
"PlacedVolume",
796 "REFLECTION: (x.Cross(y)).Dot(z): %8.3g Parent: %s [%s] Daughter: %s [%s]",
798 daughter->GetName(), daughter->IsA()->GetName());
803 TString nam_id = TString::Format(
"%s_%d", daughter->GetName(),
id);
804 if ( s_verifyCopyNumbers ) {
805 n =
static_cast<geo_node_t*
>(parent->GetNode(nam_id));
807 printout(ERROR,
"PlacedVolume",
"++ Attempt to place already exiting node %s",(
const char*)nam_id);
810 parent->AddNode(daughter,
id, transform);
812 n =
static_cast<geo_node_t*
>(parent->GetNodes()->Last());
813 if ( nam_id != n->GetName() ) {
814 printout(ERROR,
"PlacedVolume",
"++ FAILED to place node %s",(
const char*)nam_id);
817 n->geo_node_t::SetUserExtension(extension);
824 rot3D.GetComponents(elements);
825 r.SetMatrix(elements);
826 auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(0,0,0),r);
827 return _addNode(par, daughter, copy_nr, matrix.release());
835 tr.GetRotation(rot3D);
836 tr.GetTranslation(pos3D);
837 rot3D.GetComponents(elements);
838 r.SetMatrix(elements);
839 auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(pos3D.x(), pos3D.y(), pos3D.z()),r);
840 return _addNode(par, daughter, copy_nr, matrix.release());
905 size_t count,
double inc,
double start)
908 0e0, 1e0, 0e0, axis ==
Y_axis ? start : 0e0,
909 0e0, 0e0, 1e0, axis ==
Z_axis ? start : 0e0);
911 0e0, 1e0, 0e0, axis ==
Y_axis ? inc : 0e0,
912 0e0, 0e0, 1e0, axis ==
Z_axis ? inc : 0e0);
944 if ( pv->GetNdaughters() > 1 ) {
945 except(
"Volume",
"paramVolume1D: Mother %s has too many daughters: %ld "
946 "Parameterized volumes may only have one single daughter!",
950 data->params->addref();
952 data->params->start = start;
953 data->params->trafo1D.first = trafo;
954 data->params->trafo1D.second = count;
955 data->params->trafo2D.second = 0;
956 data->params->trafo3D.second = 0;
957 data->params->placements.emplace_back(pv);
958 for(
size_t i=1; i < count; ++i) {
962 data->params->placements.emplace_back(ppv);
963 ppv.
data()->params =
data->params->addref();
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!",
1016 data->params->addref();
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);
1026 for(
size_t j=0; j < count_2; ++j) {
1028 for(
size_t i = 0; i < count_1; ++i) {
1029 if ( !( i == 0 && j == 0 ) ) {
1032 data->params->placements.emplace_back(ppv);
1033 ppv.
data()->params =
data->params->addref();
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!",
1092 data->params->addref();
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);
1103 for(
size_t k=0; k < count_3; ++k) {
1105 for(
size_t j=0; j < count_2; ++j) {
1107 for(
size_t i = 0; i < count_1; ++i) {
1108 if ( !( i == 0 && j == 0 && k == 0 ) ) {
1111 data->params->placements.emplace_back(ppv);
1112 ppv.
data()->params =
data->params->addref();
1129 throw std::runtime_error(
"dd4hep: Attempt to access invalid handle of type: PlacedVolume");
1140 TGeoMedium* medium = mat.
_ptr<TGeoMedium>();
1145 throw std::runtime_error(
"dd4hep: Volume: Medium " + std::string(mat.
name()) +
" is not registered with geometry manager.");
1147 throw std::runtime_error(
"dd4hep: Volume: Attempt to assign invalid material.");
1159 TColor* col = vis->
color;
1163 int col_num = col->GetNumber();
1164 int col_tr_num = vis->
colortr->GetNumber();
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()),
1184 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,0)
1198 printout(DEBUG,
"setVisAttributes",
"Set to wireframe vis:%s",
name());
1211 except(
"Volume",
"setVisAttributes: encountered valid, but badly initialized visattr: %s",attr.
name());
1215 if ( o ) o->
vis = attr;
1240 Object* o = _data(*
this,
false);
1241 if (o)
return o->
vis;
1253 return Solid((*this)->GetShape());
1263 except(
"dd4hep",
"Volume: Cannot access the bounding box of an invalid volume [Invalid Handle]!");
1265 except(
"dd4hep",
"Volume: Cannot access the bounding box an object of type: %s shape: %s",
1280 _data(*this)->
region = obj;
1286 return _data(*this)->region;
1299 _data(*this)->limits = obj;
1305 return _data(*this)->
limits;
1311 _data(*this)->sens_det = obj;
1317 const Object* o = _data(*
this);
1323 return _data(*this)->sens_det.isValid();
1328 return _data(*this)->properties !=
nullptr;
1333 auto* o = _data(*
this);
1334 if ( !o->properties ) {
1335 o->properties =
new TList();
1336 o->properties->SetOwner();
1338 TNamed *prop = (
TNamed*)o->properties->FindObject(nam.c_str());
1340 o->properties->Add(
new TNamed(nam.c_str(), val.c_str()));
1343 except(
"Volume::addProperty",
"Volume: '%s' Property '%s' is already set!",
1349 const auto* o = _data(*
this);
1350 if ( !o->properties ) {
1353 TNamed *prop = (
TNamed*)o->properties->FindObject(nam.c_str());
1354 if ( prop )
return prop->GetTitle();
1360 m_element = _createTGeoVolumeAssembly(nam);
1372 TGeoVolumeMulti* multi = detail::safe_cast<TGeoVolumeMulti>::cast(
m_element);
1379 if (
handle.isValid() ) {}
1385 Volume vol = place->GetVolume();
1386 TGeoMatrix* mat = place->GetMatrix();
1388 std::stringstream os;
1390 double adjust(
double value)
const {
1391 if ( std::abs(value) < TGeoShape::Tolerance() )
1393 return value/dd4hep::cm;
1397 if ( vol->IsA() == TGeoVolumeAssembly::Class() ) {
1398 for(
int i=0; i<vol->GetNdaughters(); ++i) {
1399 os <<
toStringMesh(vol->GetNode(i), prec) << std::endl;
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);
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;
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;
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])