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() ) {
140 printout(DEBUG,
"VolumeImport",
141 "+++ Add placement user extension. parent: %s placement: %s.",
142 v->GetName(), pv->GetName() );
145 (*this)(pv->GetVolume());
149 void operator()(TGeoVolume* new_v, TGeoVolume* old_v,
SensitiveDetector sd,
int set_bit) {
150 if ( !new_v || !old_v ) {
151 except(
"dd4hep",
"VolumeImport: ERROR: The refected volume is INVALID!");
153 else if ( !old_v->GetUserExtension() ) {
154 except(
"dd4hep",
"VolumeImport: ERROR: Reflection of non-dd4hep volume %s",new_v->IsA()->GetName());
156 else if ( !new_v->GetUserExtension() ) {
157 TClass* c = new_v->IsA();
163 if ( c == geo_volume_t::Class() ) {
169 else if ( c == geo_assembly_t::Class() ) {
173 new_e->reflected = old_v;
175 else if ( c == TGeoVolumeMulti::Class() ) {
177 TGeoVolumeMulti* new_mv = (TGeoVolumeMulti*)new_v;
178 TGeoVolumeMulti* old_mv = (TGeoVolumeMulti*)old_v;
181 new_e->reflected = old_v;
182 for(
int i=0, n=new_mv->GetNvolumes(); i<n; ++i) {
183 TGeoVolume* vol = new_mv->GetVolume(i);
184 this->setShapeTitle(vol);
185 (*this)(vol, old_mv->GetVolume(i), sd, set_bit);
189 except(
"dd4hep",
"VolumeImport: Unknown TGeoVolume sub-class: %s",new_v->IsA()->GetName());
196 if ( set_bit >= 0 ) new_vol.
setFlagBit(set_bit);
197 for(Int_t i=0; i<new_v->GetNdaughters(); ++i) {
200 if ( !pv->GetUserExtension() ) {
204 (*this)(pv->GetVolume(), ov->GetVolume(), sd, set_bit);
210 TGeoVolume* MakeReflection(TGeoVolume*
v,
const char* newname=0) {
211 static TMap map(100);
212 TGeoVolume* vol = (TGeoVolume*)map.GetValue(
v);
214 if (newname && newname[0])
v->SetName(newname);
217 vol =
v->CloneVolume();
219 printout(ERROR,
"MakeReflection",
"Cannot clone volume %s\n",
v->GetName());
224 if (newname && newname[0]) {
226 vol->SetName(newname);
230 vol->SetName((nam+
"_refl").c_str());
232 delete vol->GetNodes();
233 vol->SetNodes(
nullptr);
234 vol->SetBit(TGeoVolume::kVolumeImportNodes, kFALSE);
235 v->CloneNodesAndConnect(vol);
239 TGeoScale* scale =
new TGeoScale( 1., 1.,-1.);
240 TGeoShape* reflected_shape =
241 TGeoScaledShape::MakeScaledShape((nam+
"_shape_refl").c_str(),
v->GetShape(), scale);
242 vol->SetShape(reflected_shape);
246 Int_t nd = vol->GetNdaughters();
247 if ( !nd )
return vol;
249 if ( !vol->GetFinder() ) {
250 for (Int_t i=0; i < nd; i++) {
251 TGeoNodeMatrix* node = (TGeoNodeMatrix*)vol->GetNode(i);
252 TGeoMatrix* local = node->GetMatrix();
255 Bool_t reflected = local->IsReflection();
256 TGeoMatrix* local_cloned =
new TGeoCombiTrans(*local);
257 local_cloned->RegisterYourself();
258 node->SetMatrix(local_cloned);
262 local_cloned->ReflectZ(kTRUE);
263 local_cloned->ReflectZ(kFALSE);
266 new_vol = MakeReflection(node->GetVolume());
267 node->SetVolume(new_vol);
271 local_cloned->ReflectZ(kTRUE);
275 if ( vol->GetVoxels() ) vol->GetVoxels()->Voxelize();
280 TGeoPatternFinder *new_finder =
v->GetFinder()->MakeCopy(kTRUE);
282 printout(ERROR,
"MakeReflection",
"Could not copy finder for volume %s",
v->GetName());
285 new_finder->SetVolume(vol);
286 vol->SetFinder(new_finder);
287 TGeoNodeOffset *nodeoff;
289 for (Int_t i=0; i<nd; i++) {
290 nodeoff = (TGeoNodeOffset*)vol->GetNode(i);
291 nodeoff->SetFinder(new_finder);
292 new_vol = MakeReflection(nodeoff->GetVolume());
293 nodeoff->SetVolume(new_vol);
298 int get_copy_number(TGeoVolume* par) {
299 TObjArray* a = par ? par->GetNodes() : 0;
300 int copy_nr = (a ? a->GetEntries() : 0);
309 bool print_active = isActivePrintLevel(DEBUG);
311 while ( (node=next()) ) {
312 TGeoMatrix* matrix = node->GetMatrix();
313 if (matrix->IsReflection()) {
314 if ( print_active ) {
315 printout(INFO,
"ReflectionBuilder",
"Reflection matrix:");
318 Volume vol(node->GetVolume());
319 TGeoMatrix* mclone =
new TGeoCombiTrans(*matrix);
320 mclone->RegisterYourself();
323 if ( print_active ) {
324 printout(INFO,
"ReflectionBuilder",
"CLONE matrix:");
327 TGeoNodeMatrix* nodematrix = (TGeoNodeMatrix*)node;
328 nodematrix->SetMatrix(mclone);
329 if ( print_active ) {
330 printout(INFO,
"ReflectionBuilder",
"Reflected volume: %s ", vol.name());
333 node->SetVolume(refl.
ptr());
354 if ( 0 == refCount )
delete this;
367 :
TGeoExtension(c), magic(std::move(c.magic)), refCount(0), volIDs(std::move(c.volIDs)) {
403 else cout <<
"Placement grabbed....." << endl;
412 if ( 0 == ext->
refCount )
delete ext;
416 std::vector<PlacedVolumeExtension::VolID>::const_iterator
418 for (Base::const_iterator i = this->Base::begin(); i != this->Base::end(); ++i)
419 if (name == (*i).first)
425 std::pair<std::vector<PlacedVolumeExtension::VolID>::iterator,
bool>
427 Base::iterator i = this->Base::begin();
428 for (; i != this->Base::end(); ++i)
429 if (name == (*i).first)
432 if (i != this->Base::end()) {
433 return make_pair(i,
false);
435 i = this->Base::emplace(this->Base::end(), name, value);
436 return make_pair(i,
true);
441 std::stringstream str;
443 for(
const auto& i : *
this ) {
444 str << i.first <<
"=" << std::setw(4) << std::right
445 << std::setfill(
'0') << i.second << std::setfill(
' ') <<
" ";
458 return m_element ? m_element->IsA()->GetName() :
"UNKNOWN-PlacedVolume";
463 return m_element ? m_element->GetNumber() : -1;
468 return Material(m_element ? m_element->GetMedium() : 0);
473 return Volume(m_element ? m_element->GetVolume() : 0);
478 return Volume(m_element ? m_element->GetMotherVolume() : 0);
483 return m_element ? m_element->GetNdaughters() : 0;
489 if ( which < (std::size_t)m_element->GetNdaughters() ) {
490 return m_element->GetDaughter(which);
492 except(
"Volume",
"+++ Access daughter %ld of %s [Has only %d daughters]",
493 which, m_element->GetName(), m_element->GetNdaughters());
495 except(
"Volume",
"+++ Cannot access daughters of a non-existing volume!");
501 return _data(*this)->volIDs;
506 auto* o = _data(*
this);
508 o->volIDs.emplace_back(nam, value);
512 except(
"PlacedVolume",
513 "+++ addPhysVolID(%s): parameterised volumes only accept '0' is volID."
514 "These automatically get overwritten with the copy number!",
517 if ( !o->volIDs.empty() ) {
518 except(
"PlacedVolume",
519 "+++ addPhysVolID(%s): parameterised volumes can only host 1 physical volume ID."
520 " vol id '%s' is already defined!", ptr()->
GetName(), o->volIDs[0].first.c_str());
524 p->volIDs.emplace_back(nam, pv->GetNumber());
532 except(
"PlacedVolume",
"+++ matrix: Failed to access invalid PlacedVolume! [Invalid handle]");
534 return *(m_element->GetMatrix());
539 const double* ptr = matrix().GetTranslation();
540 return Position(ptr[0],ptr[1],ptr[2]);
545 std::stringstream str;
546 Object* obj = _data(*
this);
547 str << m_element->GetName() <<
": vol='" << m_element->GetVolume()->GetName()
548 <<
"' mat:'" << m_element->GetMatrix()->GetName()
549 <<
"' volID[" << obj->
volIDs.size() <<
"] ";
550 for (VolIDs::const_iterator i = obj->
volIDs.begin(); i != obj->
volIDs.end(); ++i)
551 str << (*i).first <<
"=" << (*i).second <<
" ";
609 cout <<
"Volume grabbed with valid sensitive detector....." << endl;
611 cout <<
"Volume grabbed....." << endl;
622 cout <<
"Volume deleted....." << endl;
628 cout <<
"VolumeExtension::Release::refCount:" << ext->
refCount << endl;
657 s_verifyCopyNumbers = value;
682 TGeoVolume* vol = MakeReflection(
m_element);
688 except(
"dd4hep",
"Volume: Attempt to reflect an invalid Volume handle.");
699 except(
"dd4hep",
"Volume: Attempt to import an invalid Volume handle.");
709 except(
"Volume",
"+++ Volume flag bit outsize range [0...31]: %d",bit);
715 return (
data()->flags & 1<<bit) != 0;
717 except(
"Volume",
"+++ Volume flag bit outsize range [0...31]: %d",bit);
733 Object* obj = _data(*
this);
741 return _data(*this)->smartLess;
746 double start,
double step,
int numed,
const char* option) {
749 TGeoVolume* mvp = p->Divide(divname.c_str(), iaxis, ndiv, start, step, numed,
option);
761 except(
"dd4hep",
"Volume: Failed to divide volume %s -> %s [Invalid result]",
762 p->GetName(), divname.c_str());
764 except(
"dd4hep",
"Volume: Attempt to divide an invalid logical volume.");
769 TGeoVolume* parent = par;
771 except(
"dd4hep",
"Volume: Attempt to assign daughters to an invalid physical parent volume.");
773 else if ( !daughter ) {
774 except(
"dd4hep",
"Volume: Attempt to assign an invalid physical daughter volume.");
776 else if ( !transform ) {
777 except(
"dd4hep",
"Volume: Attempt to place volume without placement matrix.");
780 std::string nam = std::string(daughter->GetName()) +
"_placement";
781 transform->SetName(nam.c_str());
783 TGeoShape* shape = daughter->GetShape();
785 if ( shape->IsA() == TGeoShapeAssembly::Class() ) {
786 TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
787 as->NeedsBBoxRecompute();
790 const Double_t* r = transform->GetRotationMatrix();
792 Double_t test_rot = r[0] + r[4] + r[8] - 3.0;
793 if ( TMath::Abs(test_rot) < s_rotation_test_limit )
794 transform->ResetBit(TGeoMatrix::kGeoRotation);
796 transform->SetBit(TGeoMatrix::kGeoRotation);
798 if ( transform->IsRotation() ) {
800 r[0]*r[4]*r[8] + r[3]*r[7]*r[2] + r[6]*r[1]*r[5] -
801 r[2]*r[4]*r[6] - r[5]*r[7]*r[0] - r[8]*r[1]*r[3];
804 transform->SetBit(TGeoMatrix::kGeoReflection);
805 printout(DEBUG,
"PlacedVolume",
806 "REFLECTION: (x.Cross(y)).Dot(z): %8.3g Parent: %s [%s] Daughter: %s [%s]",
808 daughter->GetName(), daughter->IsA()->GetName());
813 TString nam_id = TString::Format(
"%s_%d", daughter->GetName(),
id);
814 if ( s_verifyCopyNumbers ) {
815 n =
static_cast<geo_node_t*
>(parent->GetNode(nam_id));
817 printout(ERROR,
"PlacedVolume",
"++ Attempt to place already exiting node %s",(
const char*)nam_id);
820 parent->AddNode(daughter,
id, transform);
822 n =
static_cast<geo_node_t*
>(parent->GetNodes()->Last());
823 if ( nam_id != n->GetName() ) {
824 printout(ERROR,
"PlacedVolume",
"++ FAILED to place node %s",(
const char*)nam_id);
826 if( par->IsA() == TGeoVolumeMulti::Class() ) {
827 printout(DEBUG,
"PlacedVolume",
828 "++ Insert to multi-volume %s. Ensure all daughters %s are instrumented.",
829 par->GetName(), daughter->GetName() );
833 n->geo_node_t::SetUserExtension(extension);
840 rot3D.GetComponents(elements);
841 r.SetMatrix(elements);
842 auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(0,0,0),r);
843 return _addNode(par, daughter, copy_nr, matrix.release());
851 tr.GetRotation(rot3D);
852 tr.GetTranslation(pos3D);
853 rot3D.GetComponents(elements);
854 r.SetMatrix(elements);
855 auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(pos3D.x(), pos3D.y(), pos3D.z()),r);
856 return _addNode(par, daughter, copy_nr, matrix.release());
921 size_t count,
double inc,
double start)
924 0e0, 1e0, 0e0, axis ==
Y_axis ? start : 0e0,
925 0e0, 0e0, 1e0, axis ==
Z_axis ? start : 0e0);
927 0e0, 1e0, 0e0, axis ==
Y_axis ? inc : 0e0,
928 0e0, 0e0, 1e0, axis ==
Z_axis ? inc : 0e0);
960 if ( pv->GetNdaughters() > 1 ) {
961 except(
"Volume",
"paramVolume1D: Mother %s has too many daughters: %ld "
962 "Parameterized volumes may only have one single daughter!",
966 data->params->addref();
968 data->params->start = start;
969 data->params->trafo1D.first = trafo;
970 data->params->trafo1D.second = count;
971 data->params->trafo2D.second = 0;
972 data->params->trafo3D.second = 0;
973 data->params->placements.emplace_back(pv);
974 for(
size_t i=1; i < count; ++i) {
978 data->params->placements.emplace_back(ppv);
979 ppv.
data()->params =
data->params->addref();
1026 if ( pv->GetNdaughters() > 1 ) {
1027 except(
"Volume",
"paramVolume1D: Mother %s has too many daughters: %ld "
1028 "Parameterized volumes may only have one single daughter!",
1032 data->params->addref();
1034 data->params->start = start;
1035 data->params->trafo1D.first = trafo_1;
1036 data->params->trafo1D.second = count_1;
1037 data->params->trafo2D.first = trafo_2;
1038 data->params->trafo2D.second = count_2;
1039 data->params->trafo3D.second = 0;
1040 data->params->placements.emplace_back(pv);
1042 for(
size_t j=0; j < count_2; ++j) {
1044 for(
size_t i = 0; i < count_1; ++i) {
1045 if ( !( i == 0 && j == 0 ) ) {
1048 data->params->placements.emplace_back(ppv);
1049 ppv.
data()->params =
data->params->addref();
1102 if ( pv->GetNdaughters() > 1 ) {
1103 except(
"Volume",
"paramVolume1D: Mother %s has too many daughters: %ld "
1104 "Parameterized volumes may only have one single daughter!",
1108 data->params->addref();
1110 data->params->start = start;
1111 data->params->trafo1D.first = trafo_1;
1112 data->params->trafo1D.second = count_1;
1113 data->params->trafo2D.first = trafo_2;
1114 data->params->trafo2D.second = count_2;
1115 data->params->trafo3D.first = trafo_3;
1116 data->params->trafo3D.second = count_3;
1117 data->params->placements.emplace_back(pv);
1119 for(
size_t k=0; k < count_3; ++k) {
1121 for(
size_t j=0; j < count_2; ++j) {
1123 for(
size_t i = 0; i < count_1; ++i) {
1124 if ( !( i == 0 && j == 0 && k == 0 ) ) {
1127 data->params->placements.emplace_back(ppv);
1128 ppv.
data()->params =
data->params->addref();
1145 throw std::runtime_error(
"dd4hep: Attempt to access invalid handle of type: PlacedVolume");
1156 TGeoMedium* medium = mat.
_ptr<TGeoMedium>();
1161 throw std::runtime_error(
"dd4hep: Volume: Medium " + std::string(mat.
name()) +
" is not registered with geometry manager.");
1163 throw std::runtime_error(
"dd4hep: Volume: Attempt to assign invalid material.");
1175 TColor* col = vis->
color;
1179 int col_num = col->GetNumber();
1180 int col_tr_num = vis->
colortr->GetNumber();
1184 printout(DEBUG,
"setVisAttributes",
1185 "Set color %3d transparent(alpha:%.3f): %3d [%02X,%02X,%02X] DrawingStyle:%9s LineStyle:%6s for volume %s",
1186 col_num, vis->
alpha, col_tr_num,
1187 int(255*col->GetRed()),
1188 int(255*col->GetGreen()),
1189 int(255*col->GetBlue()),
1200 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,0)
1214 printout(DEBUG,
"setVisAttributes",
"Set to wireframe vis:%s",
name());
1227 except(
"Volume",
"setVisAttributes: encountered valid, but badly initialized visattr: %s",attr.
name());
1231 if ( o ) o->
vis = attr;
1256 Object* o = _data(*
this,
false);
1257 if (o)
return o->
vis;
1269 return Solid((*this)->GetShape());
1279 except(
"dd4hep",
"Volume: Cannot access the bounding box of an invalid volume [Invalid Handle]!");
1281 except(
"dd4hep",
"Volume: Cannot access the bounding box an object of type: %s shape: %s",
1296 _data(*this)->
region = obj;
1302 return _data(*this)->region;
1315 _data(*this)->limits = obj;
1321 return _data(*this)->
limits;
1327 _data(*this)->sens_det = obj;
1333 const Object* o = _data(*
this);
1339 return _data(*this)->sens_det.isValid();
1344 return _data(*this)->properties !=
nullptr;
1349 auto* o = _data(*
this);
1350 if ( !o->properties ) {
1351 o->properties =
new TList();
1352 o->properties->SetOwner();
1354 TNamed *prop = (
TNamed*)o->properties->FindObject(nam.c_str());
1356 o->properties->Add(
new TNamed(nam.c_str(), val.c_str()));
1359 except(
"Volume::addProperty",
"Volume: '%s' Property '%s' is already set!",
1365 const auto* o = _data(*
this);
1366 if ( !o->properties ) {
1369 TNamed *prop = (
TNamed*)o->properties->FindObject(nam.c_str());
1370 if ( prop )
return prop->GetTitle();
1376 m_element = _createTGeoVolumeAssembly(nam);
1388 TGeoVolumeMulti* multi = detail::safe_cast<TGeoVolumeMulti>::cast(
m_element);
1401 Volume vol = place->GetVolume();
1402 TGeoMatrix* mat = place->GetMatrix();
1404 std::stringstream os;
1406 double adjust(
double value)
const {
1407 if ( std::abs(value) < TGeoShape::Tolerance() )
1409 return value/dd4hep::cm;
1413 if ( vol->IsA() == TGeoVolumeAssembly::Class() ) {
1414 for(
int i=0; i<vol->GetNdaughters(); ++i) {
1415 os <<
toStringMesh(vol->GetNode(i), prec) << std::endl;
1421 int nvert = 0, nsegs = 0, npols = 0;
1422 sol->GetMeshNumbers(nvert, nsegs, npols);
1423 Double_t* points =
new Double_t[3*nvert];
1424 sol->SetPoints(points);
1426 os << std::setw(16) << std::left << sol->IsA()->GetName()
1427 <<
" " << nvert <<
" Mesh-points:" << std::endl;
1428 os << std::setw(16) << std::left << sol->IsA()->GetName() <<
" " << sol->GetName()
1429 <<
" N(mesh)=" << sol->GetNmeshVertices()
1430 <<
" N(vert)=" << nvert <<
" N(seg)=" << nsegs <<
" N(pols)=" << npols << std::endl;
1432 for(
int i=0; i<nvert; ++i) {
1433 Double_t* p = points + 3*i;
1434 Double_t global[3], local[3] = {p[0], p[1], p[2]};
1435 mat->LocalToMaster(local, global);
1436 os << std::setw(16) << std::left << sol->IsA()->GetName() <<
" " << std::setw(3) << std::left << i
1437 <<
" Local (" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[0])
1438 <<
", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[1])
1439 <<
", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(local[2])
1440 <<
") Global (" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[0])
1441 <<
", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[1])
1442 <<
", " << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(global[2])
1443 <<
")" << std::endl;
1446 const Double_t* org = box->GetOrigin();
1447 os << std::setw(16) << std::left << sol->IsA()->GetName()
1448 <<
" Bounding box: "
1449 <<
" dx=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDX())
1450 <<
" dy=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDY())
1451 <<
" dz=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(box->GetDZ())
1452 <<
" Origin: x=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[0])
1453 <<
" y=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[1])
1454 <<
" z=" << std::setw(7) << std::setprecision(prec) << std::fixed << std::right << _vertex.adjust(org[2])