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 throw std::runtime_error(
"dd4hep: Attempt to access invalid handle of type: PlacedVolume");
98 else if (!throw_exception)
100 throw std::runtime_error(
"dd4hep: Attempt to access invalid handle of type: PlacedVolume");
105 void setShapeTitle(TGeoVolume* vol) {
107 TGeoShape* sh = vol->GetShape();
109 sh->SetTitle(tag.c_str());
115 void operator()(TGeoVolume*
v) {
116 TClass* c =
v->IsA();
117 if ( !
v->GetUserExtension() ) {
118 if ( c == geo_volume_t::Class() )
120 else if ( c == geo_assembly_t::Class() )
122 else if ( c == TGeoVolumeMulti::Class() )
125 except(
"dd4hep",
"VolumeImport: Unknown TGeoVolume sub-class: %s",
v->IsA()->GetName());
127 if ( c == TGeoVolumeMulti::Class() ) {
128 TGeoVolumeMulti* mv = (TGeoVolumeMulti*)
v;
129 for(
int i=0, n=mv->GetNvolumes(); i<n; ++i ) {
130 TGeoVolume* vol = mv->GetVolume(i);
131 this->setShapeTitle(vol);
135 for( Int_t i=0; i<
v->GetNdaughters(); ++i ) {
137 if ( !pv->GetUserExtension() )
139 (*this)(pv->GetVolume());
143 void operator()(TGeoVolume* new_v, TGeoVolume* old_v,
SensitiveDetector sd,
int set_bit) {
144 if ( !new_v || !old_v ) {
145 except(
"dd4hep",
"VolumeImport: ERROR: The refected volume is INVALID!");
147 else if ( !old_v->GetUserExtension() ) {
148 except(
"dd4hep",
"VolumeImport: ERROR: Reflection of non-dd4hep volume %s",new_v->IsA()->GetName());
150 else if ( !new_v->GetUserExtension() ) {
151 TClass* c = new_v->IsA();
157 if ( c == geo_volume_t::Class() ) {
163 else if ( c == geo_assembly_t::Class() ) {
167 new_e->reflected = old_v;
169 else if ( c == TGeoVolumeMulti::Class() ) {
171 TGeoVolumeMulti* new_mv = (TGeoVolumeMulti*)new_v;
172 TGeoVolumeMulti* old_mv = (TGeoVolumeMulti*)old_v;
175 new_e->reflected = old_v;
176 for(
int i=0, n=new_mv->GetNvolumes(); i<n; ++i) {
177 TGeoVolume* vol = new_mv->GetVolume(i);
178 this->setShapeTitle(vol);
179 (*this)(vol, old_mv->GetVolume(i), sd, set_bit);
183 except(
"dd4hep",
"VolumeImport: Unknown TGeoVolume sub-class: %s",new_v->IsA()->GetName());
190 if ( set_bit >= 0 ) new_vol.
setFlagBit(set_bit);
191 for(Int_t i=0; i<new_v->GetNdaughters(); ++i) {
194 if ( !pv->GetUserExtension() ) {
198 (*this)(pv->GetVolume(), ov->GetVolume(), sd, set_bit);
204 TGeoVolume* MakeReflection(TGeoVolume*
v,
const char* newname=0) {
205 static TMap map(100);
206 TGeoVolume* vol = (TGeoVolume*)map.GetValue(
v);
208 if (newname && newname[0])
v->SetName(newname);
211 vol =
v->CloneVolume();
213 printout(ERROR,
"MakeReflection",
"Cannot clone volume %s\n",
v->GetName());
218 if (newname && newname[0]) {
220 vol->SetName(newname);
224 vol->SetName((nam+
"_refl").c_str());
226 delete vol->GetNodes();
227 vol->SetNodes(
nullptr);
228 vol->SetBit(TGeoVolume::kVolumeImportNodes, kFALSE);
229 v->CloneNodesAndConnect(vol);
233 TGeoScale* scale =
new TGeoScale( 1., 1.,-1.);
234 TGeoShape* reflected_shape =
235 TGeoScaledShape::MakeScaledShape((nam+
"_shape_refl").c_str(),
v->GetShape(), scale);
236 vol->SetShape(reflected_shape);
240 Int_t nd = vol->GetNdaughters();
241 if ( !nd )
return vol;
243 if ( !vol->GetFinder() ) {
244 for (Int_t i=0; i < nd; i++) {
245 TGeoNodeMatrix* node = (TGeoNodeMatrix*)vol->GetNode(i);
246 TGeoMatrix* local = node->GetMatrix();
249 Bool_t reflected = local->IsReflection();
250 TGeoMatrix* local_cloned =
new TGeoCombiTrans(*local);
251 local_cloned->RegisterYourself();
252 node->SetMatrix(local_cloned);
256 local_cloned->ReflectZ(kTRUE);
257 local_cloned->ReflectZ(kFALSE);
260 new_vol = MakeReflection(node->GetVolume());
261 node->SetVolume(new_vol);
265 local_cloned->ReflectZ(kTRUE);
269 if ( vol->GetVoxels() ) vol->GetVoxels()->Voxelize();
274 TGeoPatternFinder *new_finder =
v->GetFinder()->MakeCopy(kTRUE);
276 printout(ERROR,
"MakeReflection",
"Could not copy finder for volume %s",
v->GetName());
279 new_finder->SetVolume(vol);
280 vol->SetFinder(new_finder);
281 TGeoNodeOffset *nodeoff;
283 for (Int_t i=0; i<nd; i++) {
284 nodeoff = (TGeoNodeOffset*)vol->GetNode(i);
285 nodeoff->SetFinder(new_finder);
286 new_vol = MakeReflection(nodeoff->GetVolume());
287 nodeoff->SetVolume(new_vol);
292 int get_copy_number(TGeoVolume* par) {
293 TObjArray* a = par ? par->GetNodes() : 0;
294 int copy_nr = (a ? a->GetEntries() : 0);
304 bool print_active = isActivePrintLevel(DEBUG);
306 while ( (node=next()) ) {
307 TGeoMatrix* matrix = node->GetMatrix();
308 if (matrix->IsReflection()) {
309 if ( print_active ) {
310 printout(INFO,
"ReflectionBuilder",
"Reflection matrix:");
313 Volume vol(node->GetVolume());
314 TGeoMatrix* mclone =
new TGeoCombiTrans(*matrix);
315 mclone->RegisterYourself();
318 if ( print_active ) {
319 printout(INFO,
"ReflectionBuilder",
"CLONE matrix:");
322 TGeoNodeMatrix* nodematrix = (TGeoNodeMatrix*)node;
323 nodematrix->SetMatrix(mclone);
324 if ( print_active ) {
325 printout(INFO,
"ReflectionBuilder",
"Reflected volume: %s ", vol.name());
328 node->SetVolume(refl.
ptr());
349 if ( 0 == refCount )
delete this;
383 else cout <<
"Placement grabbed....." << endl;
392 if ( 0 == ext->
refCount )
delete ext;
396 std::vector<PlacedVolumeExtension::VolID>::const_iterator
398 for (Base::const_iterator i = this->Base::begin(); i != this->Base::end(); ++i)
399 if (name == (*i).first)
405 std::pair<std::vector<PlacedVolumeExtension::VolID>::iterator,
bool>
407 Base::iterator i = this->Base::begin();
408 for (; i != this->Base::end(); ++i)
409 if (name == (*i).first)
412 if (i != this->Base::end()) {
413 return make_pair(i,
false);
415 i = this->Base::emplace(this->Base::end(), name, value);
416 return make_pair(i,
true);
421 std::stringstream str;
423 for(
const auto& i : *
this ) {
424 str << i.first <<
"=" << std::setw(4) << std::right
425 << std::setfill(
'0') << i.second << std::setfill(
' ') <<
" ";
438 return m_element ? m_element->IsA()->GetName() :
"UNKNOWN-PlacedVolume";
443 return m_element ? m_element->GetNumber() : -1;
448 return Material(m_element ? m_element->GetMedium() : 0);
453 return Volume(m_element ? m_element->GetVolume() : 0);
458 return Volume(m_element ? m_element->GetMotherVolume() : 0);
463 return m_element ? m_element->GetNdaughters() : 0;
469 if ( which < (std::size_t)m_element->GetNdaughters() ) {
470 return m_element->GetDaughter(which);
472 except(
"Volume",
"+++ Access daughter %ld of %s [Has only %d daughters]",
473 which, m_element->GetName(), m_element->GetNdaughters());
475 except(
"Volume",
"+++ Cannot access daughters of a non-existing volume!");
481 return _data(*this)->volIDs;
486 auto* o = _data(*
this);
488 o->volIDs.emplace_back(nam, value);
492 except(
"PlacedVolume",
493 "+++ addPhysVolID(%s): parameterised volumes only accept '0' is volID."
494 "These automatically get overwritten with the copy number!",
497 if ( !o->volIDs.empty() ) {
498 except(
"PlacedVolume",
499 "+++ addPhysVolID(%s): parameterised volumes can only host 1 physical volume ID."
500 " vol id '%s' is already defined!", ptr()->
GetName(), o->volIDs[0].first.c_str());
504 p->volIDs.emplace_back(nam, pv->GetNumber());
512 except(
"PlacedVolume",
"+++ matrix: Failed to access invalid PlacedVolume! [Invalid handle]");
514 return *(m_element->GetMatrix());
519 const double* ptr = matrix().GetTranslation();
520 return Position(ptr[0],ptr[1],ptr[2]);
525 std::stringstream str;
526 Object* obj = _data(*
this);
527 str << m_element->GetName() <<
": vol='" << m_element->GetVolume()->GetName()
528 <<
"' mat:'" << m_element->GetMatrix()->GetName()
529 <<
"' volID[" << obj->
volIDs.size() <<
"] ";
530 for (VolIDs::const_iterator i = obj->
volIDs.begin(); i != obj->
volIDs.end(); ++i)
531 str << (*i).first <<
"=" << (*i).second <<
" ";
589 cout <<
"Volume grabbed with valid sensitive detector....." << endl;
591 cout <<
"Volume grabbed....." << endl;
602 cout <<
"Volume deleted....." << endl;
608 cout <<
"VolumeExtension::Release::refCount:" << ext->
refCount << endl;
637 s_verifyCopyNumbers = value;
662 TGeoVolume* vol = MakeReflection(
m_element);
668 except(
"dd4hep",
"Volume: Attempt to reflect an invalid Volume handle.");
679 except(
"dd4hep",
"Volume: Attempt to import an invalid Volume handle.");
689 except(
"Volume",
"+++ Volume flag bit outsize range [0...31]: %d",bit);
695 return (
data()->flags & 1<<bit) != 0;
697 except(
"Volume",
"+++ Volume flag bit outsize range [0...31]: %d",bit);
713 double start,
double step,
int numed,
const char* option) {
716 TGeoVolume* mvp = p->Divide(divname.c_str(), iaxis, ndiv, start, step, numed,
option);
722 except(
"dd4hep",
"Volume: Failed to divide volume %s -> %s [Invalid result]",
723 p->GetName(), divname.c_str());
725 except(
"dd4hep",
"Volume: Attempt to divide an invalid logical volume.");
730 TGeoVolume* parent = par;
732 except(
"dd4hep",
"Volume: Attempt to assign daughters to an invalid physical parent volume.");
734 else if ( !daughter ) {
735 except(
"dd4hep",
"Volume: Attempt to assign an invalid physical daughter volume.");
737 else if ( !transform ) {
738 except(
"dd4hep",
"Volume: Attempt to place volume without placement matrix.");
741 std::string nam = std::string(daughter->GetName()) +
"_placement";
742 transform->SetName(nam.c_str());
744 TGeoShape* shape = daughter->GetShape();
746 if ( shape->IsA() == TGeoShapeAssembly::Class() ) {
747 TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
748 as->NeedsBBoxRecompute();
751 const Double_t* r = transform->GetRotationMatrix();
753 Double_t test_rot = r[0] + r[4] + r[8] - 3.0;
754 if ( TMath::Abs(test_rot) < s_rotation_test_limit )
755 transform->ResetBit(TGeoMatrix::kGeoRotation);
757 transform->SetBit(TGeoMatrix::kGeoRotation);
759 if ( transform->IsRotation() ) {
761 r[0]*r[4]*r[8] + r[3]*r[7]*r[2] + r[6]*r[1]*r[5] -
762 r[2]*r[4]*r[6] - r[5]*r[7]*r[0] - r[8]*r[1]*r[3];
765 transform->SetBit(TGeoMatrix::kGeoReflection);
766 printout(DEBUG,
"PlacedVolume",
767 "REFLECTION: (x.Cross(y)).Dot(z): %8.3g Parent: %s [%s] Daughter: %s [%s]",
769 daughter->GetName(), daughter->IsA()->GetName());
774 TString nam_id = TString::Format(
"%s_%d", daughter->GetName(),
id);
775 if ( s_verifyCopyNumbers ) {
776 n =
static_cast<geo_node_t*
>(parent->GetNode(nam_id));
778 printout(ERROR,
"PlacedVolume",
"++ Attempt to place already exiting node %s",(
const char*)nam_id);
781 parent->AddNode(daughter,
id, transform);
783 n =
static_cast<geo_node_t*
>(parent->GetNodes()->Last());
784 if ( nam_id != n->GetName() ) {
785 printout(ERROR,
"PlacedVolume",
"++ FAILED to place node %s",(
const char*)nam_id);
788 n->geo_node_t::SetUserExtension(extension);
795 rot3D.GetComponents(elements);
796 r.SetMatrix(elements);
797 auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(0,0,0),r);
798 return _addNode(par, daughter, copy_nr, matrix.release());
806 tr.GetRotation(rot3D);
807 tr.GetTranslation(pos3D);
808 rot3D.GetComponents(elements);
809 r.SetMatrix(elements);
810 auto matrix = std::make_unique<TGeoCombiTrans>(TGeoTranslation(pos3D.x(), pos3D.y(), pos3D.z()),r);
811 return _addNode(par, daughter, copy_nr, matrix.release());
876 size_t count,
double inc,
double start)
879 0e0, 1e0, 0e0, axis ==
Y_axis ? start : 0e0,
880 0e0, 0e0, 1e0, axis ==
Z_axis ? start : 0e0);
882 0e0, 1e0, 0e0, axis ==
Y_axis ? inc : 0e0,
883 0e0, 0e0, 1e0, axis ==
Z_axis ? inc : 0e0);
915 if ( pv->GetNdaughters() > 1 ) {
916 except(
"Volume",
"paramVolume1D: Mother %s has too many daughters: %ld "
917 "Parameterized volumes may only have one single daughter!",
921 data->params->addref();
923 data->params->start = start;
924 data->params->trafo1D.first = trafo;
925 data->params->trafo1D.second = count;
926 data->params->trafo2D.second = 0;
927 data->params->trafo3D.second = 0;
928 data->params->placements.emplace_back(pv);
929 for(
size_t i=1; i < count; ++i) {
933 data->params->placements.emplace_back(ppv);
934 ppv.
data()->params =
data->params->addref();
981 if ( pv->GetNdaughters() > 1 ) {
982 except(
"Volume",
"paramVolume1D: Mother %s has too many daughters: %ld "
983 "Parameterized volumes may only have one single daughter!",
987 data->params->addref();
989 data->params->start = start;
990 data->params->trafo1D.first = trafo_1;
991 data->params->trafo1D.second = count_1;
992 data->params->trafo2D.first = trafo_2;
993 data->params->trafo2D.second = count_2;
994 data->params->trafo3D.second = 0;
995 data->params->placements.emplace_back(pv);
997 for(
size_t j=0; j < count_2; ++j) {
999 for(
size_t i = 0; i < count_1; ++i) {
1000 if ( !( i == 0 && j == 0 ) ) {
1003 data->params->placements.emplace_back(ppv);
1004 ppv.
data()->params =
data->params->addref();
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!",
1063 data->params->addref();
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);
1074 for(
size_t k=0; k < count_3; ++k) {
1076 for(
size_t j=0; j < count_2; ++j) {
1078 for(
size_t i = 0; i < count_1; ++i) {
1079 if ( !( i == 0 && j == 0 && k == 0 ) ) {
1082 data->params->placements.emplace_back(ppv);
1083 ppv.
data()->params =
data->params->addref();
1100 throw std::runtime_error(
"dd4hep: Attempt to access invalid handle of type: PlacedVolume");
1111 TGeoMedium* medium = mat.
_ptr<TGeoMedium>();
1116 throw std::runtime_error(
"dd4hep: Volume: Medium " + std::string(mat.
name()) +
" is not registered with geometry manager.");
1118 throw std::runtime_error(
"dd4hep: Volume: Attempt to assign invalid material.");
1130 TColor* col = vis->
color;
1134 int col_num = col->GetNumber();
1135 int col_tr_num = vis->
colortr->GetNumber();
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()),
1155 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,0)
1169 printout(DEBUG,
"setVisAttributes",
"Set to wireframe vis:%s",
name());
1182 except(
"Volume",
"setVisAttributes: encountered valid, but badly initialized visattr: %s",attr.
name());
1186 if ( o ) o->
vis = attr;
1211 Object* o = _data(*
this,
false);
1212 if (o)
return o->
vis;
1224 return Solid((*this)->GetShape());
1234 except(
"dd4hep",
"Volume: Cannot access the bounding box of an invalid volume [Invalid Handle]!");
1236 except(
"dd4hep",
"Volume: Cannot access the bounding box an object of type: %s shape: %s",
1251 _data(*this)->
region = obj;
1257 return _data(*this)->region;
1270 _data(*this)->limits = obj;
1276 return _data(*this)->
limits;
1282 _data(*this)->sens_det = obj;
1288 const Object* o = _data(*
this);
1294 return _data(*this)->sens_det.isValid();
1299 return _data(*this)->properties !=
nullptr;
1304 auto* o = _data(*
this);
1305 if ( !o->properties ) {
1306 o->properties =
new TList();
1307 o->properties->SetOwner();
1309 TNamed *prop = (
TNamed*)o->properties->FindObject(nam.c_str());
1311 o->properties->Add(
new TNamed(nam.c_str(), val.c_str()));
1314 except(
"Volume::addProperty",
"Volume: '%s' Property '%s' is already set!",
1320 const auto* o = _data(*
this);
1321 if ( !o->properties ) {
1324 TNamed *prop = (
TNamed*)o->properties->FindObject(nam.c_str());
1325 if ( prop )
return prop->GetTitle();
1331 m_element = _createTGeoVolumeAssembly(nam);
1343 TGeoVolumeMulti* multi = detail::safe_cast<TGeoVolumeMulti>::cast(
m_element);
1350 if (
handle.isValid() ) {}
1356 Volume vol = place->GetVolume();
1357 TGeoMatrix* mat = place->GetMatrix();
1359 std::stringstream os;
1361 double adjust(
double value)
const {
1362 if ( std::abs(value) < TGeoShape::Tolerance() )
1364 return value/dd4hep::cm;
1368 if ( vol->IsA() == TGeoVolumeAssembly::Class() ) {
1369 for(
int i=0; i<vol->GetNdaughters(); ++i) {
1370 os <<
toStringMesh(vol->GetNode(i), prec) << std::endl;
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);
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;
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;
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])