Project
Loading...
Searching...
No Matches
GeometryManager.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
15#include <fairlogger/Logger.h> // for LOG
16#include <TCollection.h> // for TIter
17#include <TFile.h>
18#include <TGeoMatrix.h> // for TGeoHMatrix
19#include <TGeoNavigator.h> // for TGeoNavigator
20#include <TGeoNode.h> // for TGeoNode
21#include <TGeoPhysicalNode.h> // for TGeoPhysicalNode, TGeoPNEntry
22#include <string>
23#include <cassert>
24#include <cstddef> // for NULL
25#include <numeric>
26
32
33#ifdef O2_WITH_VECGEOM
34#include "TGeo2VecGeom/RootGeoManager.h"
35#include <VecGeom/base/Version.h>
36#include <VecGeom/management/GeoManager.h>
37#include <VecGeom/management/ABBoxManager.h>
38#include <VecGeom/management/BVHManager.h>
39#include <VecGeom/navigation/GlobalLocator.h>
40#include <VecGeom/navigation/NavigationState.h>
41#include <VecGeom/navigation/NewSimpleNavigator.h>
42#include <VecGeom/navigation/BVHNavigator.h>
43#include <VecGeom/navigation/SimpleLevelLocator.h>
44#if VECGEOM_VERSION >= 0x020000
45#include <VecGeom/navigation/SimpleABBoxLevelLocator.h>
46#else
47#include <VecGeom/navigation/BVHLevelLocator.h>
48#endif
49#include <VecGeom/navigation/VNavigator.h>
50#include <VecGeom/volumes/LogicalVolume.h>
51#include <mutex>
52// The BVH navigator of the VNavigator family, which Geant4 navigation needs on every volume.
53#if __has_include(<VecGeom/navigation/BVHNavigatorV.h>)
54#define O2_VECGEOM_HAS_BVH_VNAVIGATOR
55#include <VecGeom/navigation/BVHNavigatorV.h>
56#include <VecGeom/navigation/BVHLevelLocator.h>
57#include <VecGeom/navigation/BVHSafetyEstimator.h>
58#include <VecGeom/navigation/SimpleSafetyEstimator.h>
59#endif
60#endif
61
62using namespace o2::detectors;
63using namespace o2::base;
64
68std::mutex GeometryManager::sTGMutex;
69
70//______________________________________________________________________
71Bool_t GeometryManager::getOriginalMatrix(const char* symname, TGeoHMatrix& m)
72{
73 m.Clear();
74 if (!gGeoManager || !gGeoManager->IsClosed()) {
75 LOG(error) << "No active geometry or geometry not yet closed!";
76 ;
77 return kFALSE;
78 }
79 std::lock_guard<std::mutex> guard(sTGMutex);
80 if (!gGeoManager->GetListOfPhysicalNodes()) {
81 LOG(warning) << "gGeoManager doesn't contain any aligned nodes!";
82
83 if (!gGeoManager->cd(symname)) {
84 LOG(error) << "Volume path " << symname << " not valid!";
85 return kFALSE;
86 } else {
87 m = *gGeoManager->GetCurrentMatrix();
88 return kTRUE;
89 }
90 }
91
92 TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
93 const char* path = nullptr;
94
95 if (pne) {
96 m = *pne->GetGlobalOrig();
97 return kTRUE;
98 } else {
99 LOG(warning) << "The symbolic volume name " << symname
100 << "does not correspond to a physical entry. Using it as a volume path!";
101 path = symname;
102 }
103
104 return getOriginalMatrixFromPath(path, m);
105}
106
107//______________________________________________________________________
108Bool_t GeometryManager::getOriginalMatrixFromPath(const char* path, TGeoHMatrix& m)
109{
110 m.Clear();
111
112 if (!gGeoManager || !gGeoManager->IsClosed()) {
113 LOG(error) << "Can't get the original global matrix! gGeoManager doesn't exist or it is still opened!";
114 return kFALSE;
115 }
116 std::lock_guard<std::mutex> guard(sTGMutex);
117 if (!gGeoManager->CheckPath(path)) {
118 LOG(error) << "Volume path " << path << " not valid!";
119 return kFALSE;
120 }
121
122 TIter next(gGeoManager->GetListOfPhysicalNodes());
123 gGeoManager->cd(path);
124
125 while (gGeoManager->GetLevel()) {
126 TGeoPhysicalNode* physNode = nullptr;
127 next.Reset();
128 TGeoNode* node = gGeoManager->GetCurrentNode();
129
130 while ((physNode = (TGeoPhysicalNode*)next())) {
131 if (physNode->GetNode() == node) {
132 break;
133 }
134 }
135
136 TGeoMatrix* lm = nullptr;
137 if (physNode) {
138 lm = physNode->GetOriginalMatrix();
139 if (!lm) {
140 lm = node->GetMatrix();
141 }
142 } else {
143 lm = node->GetMatrix();
144 }
145
146 m.MultiplyLeft(lm);
147
148 gGeoManager->CdUp();
149 }
150 return kTRUE;
151}
152
153//______________________________________________________________________
154TGeoHMatrix* GeometryManager::getMatrix(TGeoPNEntry* pne)
155{
156 // Get the global transformation matrix for a given PNEntry
157 // by quering the TGeoManager
158
159 if (!gGeoManager || !gGeoManager->IsClosed()) {
160 LOG(error) << "Can't get the global matrix! gGeoManager doesn't exist or it is still opened!";
161 return nullptr;
162 }
163
164 // if matrix already known --> return it
165 TGeoPhysicalNode* pnode = pne->GetPhysicalNode();
166 if (pnode) {
167 return pnode->GetMatrix();
168 }
169
170 // otherwise calculate it from title and attach via TGeoPhysicalNode
171 pne->SetPhysicalNode(new TGeoPhysicalNode(pne->GetTitle()));
172 return pne->GetPhysicalNode()->GetMatrix();
173}
174
175//______________________________________________________________________
176TGeoHMatrix* GeometryManager::getMatrix(const char* symname)
177{
178 // Get the global transformation matrix for a given alignable volume
179 // identified by its symbolic name 'symname' by quering the TGeoManager
180
181 if (!gGeoManager || !gGeoManager->IsClosed()) {
182 LOG(error) << "No active geometry or geometry not yet closed!";
183 return nullptr;
184 }
185
186 TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
187 if (!pne) {
188 return nullptr;
189 }
190
191 return getMatrix(pne);
192}
193
194//______________________________________________________________________
195const char* GeometryManager::getSymbolicName(DetID detid, int sensid)
196{
200 int id = getSensID(detid, sensid);
201 TGeoPNEntry* pne = gGeoManager->GetAlignableEntryByUID(id);
202 if (!pne) {
203 LOG(error) << "Failed to find alignable entry with index " << id << ": Det" << detid << " Sens.Vol:" << sensid << ") !";
204 return nullptr;
205 }
206 return pne->GetName();
207}
208
209TGeoPNEntry* GeometryManager::getPNEntry(DetID detid, Int_t sensid)
210{
214 int id = getSensID(detid, sensid);
215 TGeoPNEntry* pne = gGeoManager->GetAlignableEntryByUID(id);
216 if (!pne) {
217 LOG(error) << "The sens.vol " << sensid << " of det " << detid << " does not correspond to a physical entry!";
218 }
219 return pne;
220}
221
222//______________________________________________________________________
223TGeoHMatrix* GeometryManager::getMatrix(DetID detid, Int_t sensid)
224{
228 static TGeoHMatrix matTmp;
229 TGeoPNEntry* pne = getPNEntry(detid, sensid);
230 if (!pne) {
231 return nullptr;
232 }
233
234 TGeoPhysicalNode* pnode = pne->GetPhysicalNode();
235 if (pnode) {
236 return pnode->GetMatrix();
237 }
238
239 const char* path = pne->GetTitle();
240 gGeoManager->PushPath(); // Preserve the modeler state.
241 if (!gGeoManager->cd(path)) {
242 gGeoManager->PopPath();
243 LOG(error) << "Volume path " << path << " not valid!";
244 return nullptr;
245 }
246 matTmp = *gGeoManager->GetCurrentMatrix();
247 gGeoManager->PopPath();
248 return &matTmp;
249}
250
251//______________________________________________________________________
252Bool_t GeometryManager::getOriginalMatrix(DetID detid, int sensid, TGeoHMatrix& m)
253{
257 m.Clear();
258
259 const char* symname = getSymbolicName(detid, sensid);
260 if (!symname) {
261 return kFALSE;
262 }
263
264 return getOriginalMatrix(symname, m);
265}
266
267//______________________________________________________________________
268bool GeometryManager::applyAlignment(const std::vector<const std::vector<o2::detectors::AlignParam>*> algPars)
269{
271 for (auto dv : algPars) {
272 if (dv && !applyAlignment(*dv)) {
273 return false;
274 }
275 }
276 return true;
277}
278
279//______________________________________________________________________
280bool GeometryManager::applyAlignment(const std::vector<o2::detectors::AlignParam>& algPars)
281{
283 int nvols = algPars.size();
284 std::vector<int> ord(nvols);
285 std::iota(std::begin(ord), std::end(ord), 0); // sort to apply alignment in correct hierarchy
286 std::sort(std::begin(ord), std::end(ord), [&algPars](int a, int b) { return algPars[a].getLevel() < algPars[b].getLevel(); });
287
288 bool res = true;
289 for (int i = 0; i < nvols; i++) {
290 if (!algPars[ord[i]].applyToGeometry(GeometryManagerParam::Instance().printLevel)) {
291 res = false;
292 LOG(error) << "Error applying alignment object for volume" << algPars[ord[i]].getSymName();
293 }
294 }
295 return res;
296}
297
298// ================= methods for nested MatBudgetExt class ================
299
300//______________________________________________________________________
302{
303 double nrm = 1. / step;
304 meanRho *= nrm;
305 meanA *= nrm;
306 meanZ *= nrm;
307 meanZ2A *= nrm;
308 if (nrm > 0.) {
309 length = step;
310 }
311}
312
313//______________________________________________________________________
314void GeometryManager::accountMaterial(const TGeoMaterial* material, GeometryManager::MatBudgetExt& bd)
315{
316 bd.meanRho = material->GetDensity();
317 bd.meanX2X0 = material->GetRadLen();
318 bd.meanA = material->GetA();
319 bd.meanZ = material->GetZ();
320 if (material->IsMixture()) {
321 TGeoMixture* mixture = (TGeoMixture*)material;
322 Double_t norm = 0.;
323 bd.meanZ2A = 0.;
324 for (Int_t iel = 0; iel < mixture->GetNelements(); iel++) {
325 norm += mixture->GetWmixt()[iel];
326 bd.meanZ2A += mixture->GetZmixt()[iel] * mixture->GetWmixt()[iel] / mixture->GetAmixt()[iel];
327 }
328 bd.meanZ2A /= norm;
329 } else {
330 bd.meanZ2A = bd.meanZ / bd.meanA;
331 }
332}
333
334//_____________________________________________________________________________________
335GeometryManager::MatBudgetExt GeometryManager::meanMaterialBudgetExt(float x0, float y0, float z0, float x1, float y1, float z1)
336{
337 //
338 // TODO? It seems there is no real nead for extended material budget, consider eliminating it
339 //
340 // Calculate mean material budget and material properties (extended version) between
341 // the points "0" and "1".
342 //
343 // see MatBudgetExt data members for provided information
344 //
345 // Origin: Marian Ivanov, Marian.Ivanov@cern.ch
346 //
347 // Corrections and improvements by
348 // Andrea Dainese, Andrea.Dainese@lnl.infn.it,
349 // Andrei Gheata, Andrei.Gheata@cern.ch
350 //
351 // Ported to O2: ruben.shahoyan@cern.ch
352 //
353 if (!gGeoManager) {
354 throw std::runtime_error("meanMaterialBudgetExt requires geometry loaded");
355 }
356 double length, startD[3] = {x0, y0, z0};
357 double dir[3] = {x1 - x0, y1 - y0, z1 - z0};
358 if ((length = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]) < TGeoShape::Tolerance() * TGeoShape::Tolerance()) {
359 return MatBudgetExt(); // return empty struct
360 }
361 length = TMath::Sqrt(length);
362 double invlen = 1. / length;
363 for (int i = 3; i--;) {
364 dir[i] *= invlen;
365 }
366 std::lock_guard<std::mutex> guard(sTGMutex);
367 // Initialize start point and direction
368 TGeoNode* currentnode = gGeoManager->InitTrack(startD, dir);
369 if (!currentnode) {
370 LOG(error) << "start point out of geometry: " << x0 << ':' << y0 << ':' << z0;
371 return MatBudgetExt(); // return empty struct
372 }
373
374 MatBudgetExt budTotal, budStep;
375 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
376 budStep.length = length;
377
378 // Locate next boundary within length without computing safety.
379 // Propagate either with length (if no boundary found) or just cross boundary
380 gGeoManager->FindNextBoundaryAndStep(length, kFALSE);
381 Double_t stepTot = 0.0; // Step made
382 Double_t step = gGeoManager->GetStep();
383 // If no boundary within proposed length, return current step data
384 if (!gGeoManager->IsOnBoundary()) {
385 budStep.meanX2X0 = budStep.length / budStep.meanX2X0;
386 return MatBudgetExt(budStep);
387 }
388 // Try to cross the boundary and see what is next
389 Int_t nzero = 0;
390 while (length > TGeoShape::Tolerance()) {
391 if (step < 2. * TGeoShape::Tolerance()) {
392 nzero++;
393 } else {
394 nzero = 0;
395 }
396 if (nzero > 3) {
397 // This means navigation has problems on one boundary
398 // Try to cross by making a small step
399 const double* curPos = gGeoManager->GetCurrentPoint();
400 LOG(warning) << "Cannot cross boundary at (" << curPos[0] << ',' << curPos[1] << ',' << curPos[2] << ')';
401 budTotal.normalize(stepTot);
402 budTotal.nCross = -1; // flag failed navigation
403 return MatBudgetExt(budTotal);
404 }
405 stepTot += step;
406
407 budTotal.meanRho += step * budStep.meanRho;
408 budTotal.meanX2X0 += step / budStep.meanX2X0;
409 budTotal.meanA += step * budStep.meanA;
410 budTotal.meanZ += step * budStep.meanZ;
411 budTotal.meanZ2A += step * budStep.meanZ2A;
412 budTotal.nCross++;
413
414 if (step >= length) {
415 break;
416 }
417 currentnode = gGeoManager->GetCurrentNode();
418 if (!currentnode) {
419 break;
420 }
421 length -= step;
422 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
423 gGeoManager->FindNextBoundaryAndStep(length, kFALSE);
424 step = gGeoManager->GetStep();
425 }
426 budTotal.normalize(stepTot);
427 return MatBudgetExt(budTotal);
428}
429
430//_____________________________________________________________________________________
431o2::base::MatBudget GeometryManager::meanMaterialBudget(float x0, float y0, float z0, float x1, float y1, float z1,
432 TGeoNavigator* nav)
433{
434 //
435 // Calculate mean material budget and material properties between
436 // the points "0" and "1".
437 //
438 // see MatBudget data members for provided information
439 //
440 // Origin: Marian Ivanov, Marian.Ivanov@cern.ch
441 //
442 // Corrections and improvements by
443 // Andrea Dainese, Andrea.Dainese@lnl.infn.it,
444 // Andrei Gheata, Andrei.Gheata@cern.ch
445 //
446 // Ported to O2: ruben.shahoyan@cern.ch
447 //
448 // Multi-threaded execution: pass a navigator owned by the calling thread.
449 //
450
451 double length, startD[3] = {x0, y0, z0};
452 double dir[3] = {x1 - x0, y1 - y0, z1 - z0};
453 if ((length = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]) < TGeoShape::Tolerance() * TGeoShape::Tolerance()) {
454 return o2::base::MatBudget(); // return empty struct
455 }
456 length = TMath::Sqrt(length);
457 double invlen = 1. / length;
458 for (int i = 3; i--;) {
459 dir[i] *= invlen;
460 }
461 // A caller that passes its own navigator owns it exclusively, so no locking is needed. A caller
462 // that passes none shares gGeoManager's current navigator and must still serialize. Deciding
463 // this from the argument keeps the choice local: it does not depend on -- and cannot be broken
464 // by -- process-global state such as TGeoManager::GetMaxThreads().
465 std::unique_lock<std::mutex> guard(sTGMutex, std::defer_lock);
466 if (!nav) {
467 guard.lock();
468 nav = gGeoManager->GetCurrentNavigator();
469 }
470 // Initialize start point and direction
471 TGeoNode* currentnode = nav->InitTrack(startD, dir);
472 if (!currentnode) {
473 LOG(error) << "start point out of geometry: " << x0 << ':' << y0 << ':' << z0;
474 return o2::base::MatBudget(); // return empty struct
475 }
476
477 o2::base::MatBudget budTotal, budStep;
478 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
479 budStep.length = length;
480
481 // Locate next boundary within length without computing safety.
482 // Propagate either with length (if no boundary found) or just cross boundary
483 nav->FindNextBoundaryAndStep(length, kFALSE);
484 Double_t stepTot = 0.0; // Step made
485 Double_t step = nav->GetStep();
486 // If no boundary within proposed length, return current step data
487 if (!nav->IsOnBoundary()) {
488 budStep.meanX2X0 = budStep.length / budStep.meanX2X0;
489 return o2::base::MatBudget(budStep);
490 }
491 // Try to cross the boundary and see what is next
492 Int_t nzero = 0;
493 while (length > TGeoShape::Tolerance()) {
494 if (step < 2. * TGeoShape::Tolerance()) {
495 nzero++;
496 } else {
497 nzero = 0;
498 }
499 if (nzero > 3) {
500 // This means navigation has problems on one boundary
501 // Try to cross by making a small step
502 const double* curPos = nav->GetCurrentPoint();
503 LOG(warning) << "Cannot cross boundary at (" << curPos[0] << ',' << curPos[1] << ',' << curPos[2] << ')';
504 budTotal.meanRho /= stepTot;
505 budTotal.length = stepTot;
506 return o2::base::MatBudget(budTotal);
507 }
508 stepTot += step;
509
510 budTotal.meanRho += step * budStep.meanRho;
511 budTotal.meanX2X0 += step / budStep.meanX2X0;
512
513 if (step >= length) {
514 break;
515 }
516 currentnode = nav->GetCurrentNode();
517 if (!currentnode) {
518 break;
519 }
520 length -= step;
521 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
522 nav->FindNextBoundaryAndStep(length, kFALSE);
523 step = nav->GetStep();
524 }
525 budTotal.meanRho /= stepTot;
526 budTotal.length = stepTot;
527 return o2::base::MatBudget(budTotal);
528}
529
530//_________________________________
531void GeometryManager::applyMisalignent(bool applyMisalignment)
532{
534 if (!isGeometryLoaded()) {
535 LOG(fatal) << "geometry is not loaded";
536 }
537 if (applyMisalignment) {
538 auto& aligner = Aligner::Instance();
539 aligner.applyAlignment();
540 }
541}
542
543//_________________________________
544void GeometryManager::loadGeometry(std::string_view simPrefix, bool applyMisalignment, bool preferAlignedFile)
545{
546 auto loadGeom = [](const std::string_view fname) {
547 LOG(info) << "Loading geometry from " << fname;
548 TFile flGeom(fname.data());
549 if (flGeom.IsZombie()) {
550 LOG(fatal) << "Failed to open file " << fname;
551 }
552 // try under the standard CCDB name
553 if (!flGeom.Get(std::string(o2::base::NameConf::CCDBOBJECT).c_str()) &&
554 !flGeom.Get(std::string(o2::base::NameConf::GEOMOBJECTNAME_FAIR).c_str())) {
555 LOG(fatal) << "Did not find geometry named " << o2::base::NameConf::CCDBOBJECT << " or " << o2::base::NameConf::GEOMOBJECTNAME_FAIR;
556 }
557 };
558
559 if (preferAlignedFile) {
562 } else {
564 loadGeom(o2::base::NameConf::getGeomFileName(simPrefix));
565 applyMisalignent(applyMisalignment);
566 }
567}
568
569#ifdef O2_WITH_VECGEOM
570
571namespace
572{
576bool usesBvhAcceleration(vecgeom::LogicalVolume const* vol)
577{
578 return vol->GetDaughtersp()->size() > 2;
579}
580
584void ensureVecGeomWorldBuilt()
585{
586 GeometryManager::buildVecGeomGeometry(true);
587}
588} // namespace
589
590void GeometryManager::buildVecGeomGeometry(bool flattenAssemblies, int booleanThreshold)
591{
592 static std::once_flag onceFlag;
593 std::call_once(onceFlag, [flattenAssemblies, booleanThreshold]() {
594 if (!gGeoManager) {
595 LOG(fatal) << "Cannot build VecGeom geometry: no TGeo geometry loaded (call GeometryManager::loadGeometry() first)";
596 }
597 // Translate geometry and material pointers, then build acceleration structures.
598 tgeo2vecgeom::RootGeoManager::Instance().SetMaterialConversionHook([](TGeoMaterial const* m) { return (void*)m; });
599 LOG(info) << "VecGeom conversion: flattenAssemblies=" << flattenAssemblies;
600 tgeo2vecgeom::RootGeoManager::Instance().SetFlattenAssemblies(flattenAssemblies);
601#if __has_include(<VecGeom/management/BooleanFactory.h>)
602 // Applied when the conversion closes the geometry.
603 LOG(info) << "VecGeom conversion: booleanThreshold=" << booleanThreshold;
604 vecgeom::GeoManager::Instance().SetBooleanOptimizationThreshold(booleanThreshold > 0 ? booleanThreshold : 0);
605#else
606 if (booleanThreshold > 0) {
607 LOG(warning) << "VecGeom without BooleanFactory: Boolean solids are kept as converted";
608 }
609#endif
610 tgeo2vecgeom::RootGeoManager::Instance().LoadRootGeometry();
611
612 // Acceleration structures must be built before the navigators/locators reference them.
613#if VECGEOM_VERSION < 0x020000
614 // VecGeom 2 has no ABBoxManager: the BVH below is built directly.
615 vecgeom::ABBoxManager::Instance().InitABBoxesForCompleteGeometry();
616#endif
617 // Builds a BVH per logical volume.
618 vecgeom::BVHManager::Init();
619
620 // For each logical volume, set a navigator (used for ComputeStep), a matched level locator
621 // (used for point relocation after a boundary crossing via GlobalLocator) and, where the
622 // VNavigator family is complete, the safety estimator LogicalVolume::GetSafetyEstimator()
623 // hands out, which is separate from the one a navigator uses internally.
624 for (auto& lvol : vecgeom::GeoManager::Instance().GetLogicalVolumesMap()) {
625 auto* vol = lvol.second;
626 if (!usesBvhAcceleration(vol)) {
627 vol->SetNavigator(vecgeom::NewSimpleNavigator<>::Instance());
628#ifdef O2_VECGEOM_HAS_BVH_VNAVIGATOR
629 vol->SetLevelLocator(vol->ContainsAssembly() ? vecgeom::SimpleAssemblyLevelLocator::GetInstance()
630 : vecgeom::SimpleLevelLocator::GetInstance());
631 vol->SetSafetyEstimator(vecgeom::SimpleSafetyEstimator::Instance());
632#else
633 vol->SetLevelLocator(vecgeom::SimpleLevelLocator::GetInstance());
634#endif
635 } else {
636#if defined(O2_VECGEOM_HAS_BVH_VNAVIGATOR)
637 vol->SetNavigator(vecgeom::BVHNavigatorV<>::Instance());
638 vol->SetLevelLocator(vol->ContainsAssembly() ? vecgeom::BVHAssemblyAwareLevelLocator::GetInstance()
639 : vecgeom::BVHLevelLocator::GetInstance());
640 vol->SetSafetyEstimator(vecgeom::BVHSafetyEstimator::Instance());
641#elif VECGEOM_VERSION >= 0x020000
642 // VecGeom 2 turned BVHNavigator into a plain class with static entry points instead of a
643 // VNavigator singleton, so there is nothing to attach: vecGeomMaterialBudget() calls it
644 // directly.
645 //
646 // The locator changes too, and not by choice. BVHLevelLocator does not compile in 2.1.0 or
647 // 2.1.1 -- the header is byte-identical in both -- because its four LevelLocate() calls
648 // have no match among the single templated BVH::LevelLocate(int exclude_item_id, ...) that
649 // v2 ships. It survived two releases because nothing in VecGeom includes that header
650 // except itself, so upstream CI never compiles it; O2 appears to be its only consumer.
651 //
652 // SimpleABBoxLevelLocator is the accelerated stand-in, using the ABBoxes built just above.
653 // Three of the four methods could be rebuilt on the templated API (the idiom is in
654 // BVHNavigator itself: bvh->LevelInside<BVHNavigator>(exclude_id, point, id, dlp)), but
655 // the direction-aware LevelLocateExclVol has no v2 counterpart at all, so this stays a
656 // fallback rather than a reimplementation. Revert to BVHLevelLocator once upstream fixes
657 // or removes it, and measure: whether ABBox location costs anything real here is unknown.
658 vol->SetLevelLocator(vecgeom::SimpleABBoxLevelLocator::GetInstance());
659#else
660 vol->SetNavigator(vecgeom::BVHNavigator<>::Instance());
661 vol->SetLevelLocator(vecgeom::BVHLevelLocator::GetInstance());
662#endif
663 }
664 }
665 });
666}
667
668//_____________________________________________________________________________________
669o2::base::MatBudget GeometryManager::vecGeomMaterialBudget(float x0, float y0, float z0, float x1, float y1, float z1)
670{
671 // Mean material budget between "0" and "1" via VecGeom's BVH-accelerated ray/boundary
672 // intersection, instead of TGeo.
673 ensureVecGeomWorldBuilt();
674
675 using Vector3D = vecgeom::Vector3D<vecgeom::Precision>;
676
677 double length, start[3] = {x0, y0, z0};
678 double dir[3] = {x1 - x0, y1 - y0, z1 - z0};
679 if ((length = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]) < TGeoShape::Tolerance() * TGeoShape::Tolerance()) {
680 return o2::base::MatBudget(); // return empty struct
681 }
682 length = std::sqrt(length);
683 double invlen = 1. / length;
684 for (int i = 3; i--;) {
685 dir[i] *= invlen;
686 }
687
688 // Only the allocation differs between VecGeom versions; everything below works on pointers in
689 // both, which also keeps the std::swap() at the end of the loop a pointer swap rather than a
690 // copy of the state itself.
691 //
692 // VecGeom 1 builds NavigationState as NavStatePath, a variable-size object that must be told the
693 // maximum depth at construction and can only be made through MakeInstance(). VecGeom 2 dropped
694 // NavStatePath and MakeInstance with it: NavigationState is NavStateIndex or NavStateTuple, both
695 // fixed-size value types, so a thread_local object is the direct equivalent.
696#if VECGEOM_VERSION >= 0x020000
697 thread_local static vecgeom::NavigationState newnavstateStorage, currnavstateStorage, startCacheStorage;
698 thread_local static vecgeom::NavigationState* newnavstate = &newnavstateStorage;
699 thread_local static vecgeom::NavigationState* currnavstate = &currnavstateStorage;
700 thread_local static vecgeom::NavigationState* startCache = &startCacheStorage;
701#else
702 thread_local static vecgeom::NavigationState* newnavstate = vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth());
703 thread_local static vecgeom::NavigationState* currnavstate = vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth());
704 thread_local static vecgeom::NavigationState* startCache = vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth());
705#endif
706 thread_local static bool startCacheValid = false;
707
708 Vector3D currPoint(x0, y0, z0);
709 Vector3D dirr(dir[0], dir[1], dir[2]);
710 constexpr double kPush = 1.E-6; // mimick the nudging of TGeo's FindNextBoundaryAndStep
711 auto world = vecgeom::GeoManager::Instance().GetWorld();
712 o2::base::MatBudget budTot, budStep;
713 budStep.length = length;
714
715 // Locate the starting volume, reusing the path from the previous call when still valid.
716 if (startCacheValid && !startCache->IsOutside()) {
717 startCache->CopyTo(currnavstate);
718 vecgeom::Transformation3D m;
719 currnavstate->TopMatrix(m);
720 vecgeom::GlobalLocator::RelocatePointFromPath(m.Transform(currPoint), *currnavstate);
721 } else {
722 currnavstate->Clear();
723 vecgeom::GlobalLocator::LocateGlobalPoint(world, currPoint, *currnavstate, true);
724 }
725 if (currnavstate->IsOutside() || currnavstate->Top() == nullptr) {
726 LOG(error) << "start point out of geometry: " << x0 << ':' << y0 << ':' << z0;
727 startCacheValid = false;
728 return o2::base::MatBudget();
729 }
730 currnavstate->CopyTo(startCache);
731 startCacheValid = true;
732
733 double stepTot = 0.;
734 double remainingDist = length;
735 Int_t nzero = 0;
736 while (remainingDist > 1.E-10) {
737 auto* lvol = currnavstate->Top()->GetLogicalVolume();
738 // Not LogicalVolume::GetMaterialPtr(): VecGeom 2 dropped the material slot from the logical
739 // volume. TGeo2VecGeom keeps what its conversion hook returned, indexed by logical volume id,
740 // and serves it for both VecGeom versions.
741 accountMaterial(static_cast<TGeoMaterial*>(tgeo2vecgeom::RootGeoManager::Instance().GetMaterialPtr(lvol)), budStep);
742#if VECGEOM_VERSION >= 0x020000
743 const double step =
744 usesBvhAcceleration(lvol)
745 ? static_cast<double>(vecgeom::BVHNavigator::ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate))
746 : static_cast<double>(lvol->GetNavigator()->ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate));
747#else
748 const double step = static_cast<double>(lvol->GetNavigator()->ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate));
749#endif
750 if (step < 2.E-10) {
751 nzero++;
752 } else {
753 nzero = 0;
754 }
755 if (nzero > 3) {
756 // This means navigation has problems on one boundary
757 LOG(warning) << "Cannot cross boundary at (" << currPoint[0] << ',' << currPoint[1] << ',' << currPoint[2] << ')';
758 budTot.meanRho /= stepTot;
759 budTot.length = stepTot;
760 return o2::base::MatBudget(budTot);
761 }
762
763 remainingDist -= step;
764 stepTot += step;
765 budTot.meanRho += step * budStep.meanRho;
766 budTot.meanX2X0 += step / budStep.meanX2X0;
767 currPoint = currPoint + (step + kPush) * dirr;
768 std::swap(currnavstate, newnavstate);
769 }
770 budTot.meanRho /= stepTot;
771 budTot.length = stepTot;
772 return o2::base::MatBudget(budTot);
773}
774
775#endif // O2_WITH_VECGEOM
776
777//_____________________________________________________________________________________
779{
780#ifdef O2_WITH_VECGEOM
781 ensureVecGeomWorldBuilt();
782 return true;
783#else
784 return false;
785#endif
786}
787
788//_____________________________________________________________________________________
789bool GeometryManager::vecGeomLocate(double x, double y, double z, std::vector<TGeoNode*>& chain)
790{
791 chain.clear();
792#ifdef O2_WITH_VECGEOM
793 ensureVecGeomWorldBuilt();
794 // One state per thread, as for the material budget above, and allocated the
795 // same way: see the comment there on NavStatePath vs NavStateIndex.
796#if VECGEOM_VERSION >= 0x020000
797 thread_local vecgeom::NavigationState stateStorage;
798 thread_local vecgeom::NavigationState* state = &stateStorage;
799#else
800 thread_local vecgeom::NavigationState* state =
801 vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth());
802#endif
803 state->Clear();
804 const vecgeom::Vector3D<vecgeom::Precision> point(x, y, z);
805 if (vecgeom::GlobalLocator::LocateGlobalPoint(vecgeom::GeoManager::Instance().GetWorld(), point, *state, true) ==
806 nullptr) {
807 return false;
808 }
809 auto const& converter = tgeo2vecgeom::RootGeoManager::Instance();
810 for (int level = 0; level < (int)state->GetCurrentLevel(); ++level) {
811 auto const* placed = state->At(level);
812 auto const* node = placed != nullptr ? converter.tgeonode(placed) : nullptr;
813 if (node == nullptr) {
814 chain.clear();
815 return false;
816 }
817 chain.push_back(const_cast<TGeoNode*>(node));
818 }
819 return !chain.empty();
820#else
821 (void)x;
822 (void)y;
823 (void)z;
824 return false;
825#endif
826}
Definition of the base alignment parameters class.
Definition of the GeometryManager class.
std::unique_ptr< expressions::Node > node
int32_t i
GPUChain * chain
SurfaceTrackState state
Definition of the Names Generator class.
uint32_t res
Definition RawData.h:0
static const char * getSymbolicName(o2::detectors::DetID detid, int sensid)
static Bool_t getOriginalMatrix(o2::detectors::DetID detid, int sensid, TGeoHMatrix &m)
static void loadGeometry(std::string_view geomFilePath="", bool applyMisalignment=false, bool preferAlignedFile=true)
static bool applyAlignment(const std::vector< o2::detectors::AlignParam > &algPars)
misalign geometry with alignment objects from the array, optionaly check overlaps
static o2::base::MatBudget meanMaterialBudget(float x0, float y0, float z0, float x1, float y1, float z1, TGeoNavigator *nav=nullptr)
static MatBudgetExt meanMaterialBudgetExt(float x0, float y0, float z0, float x1, float y1, float z1)
static int getSensID(o2::detectors::DetID detid, int sensid)
static bool vecGeomLocate(double x, double y, double z, std::vector< TGeoNode * > &chain)
static TGeoHMatrix * getMatrix(const char *symname)
static TGeoPNEntry * getPNEntry(o2::detectors::DetID detid, Int_t sensid)
static void applyMisalignent(bool applyMisalignment=true)
static std::string getAlignedGeomFileName(const std::string_view prefix="")
Definition NameConf.cxx:47
static std::string getGeomFileName(const std::string_view prefix="")
Definition NameConf.cxx:41
static constexpr std::string_view CCDBOBJECT
Definition NameConf.h:66
static constexpr std::string_view GEOMOBJECTNAME_FAIR
Definition NameConf.h:83
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:60
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition glcorearb.h:5034
GLuint GLfloat GLfloat GLfloat x1
Definition glcorearb.h:5034
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint y
Definition glcorearb.h:270
GLuint GLsizei GLsizei * length
Definition glcorearb.h:790
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint GLfloat x0
Definition glcorearb.h:5034
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLint level
Definition glcorearb.h:275
GLuint start
Definition glcorearb.h:469
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint GLfloat GLfloat y0
Definition glcorearb.h:5034
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
float float float float z1
Definition MathUtils.h:82
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< T >, ROOT::Math::DefaultCoordinateSystemTag > Vector3D
value_T step
Definition TrackUtils.h:42
float length
length in material
Definition MatCell.h:55
float meanRho
mean density, g/cm^3
Definition MatCell.h:30
float meanX2X0
fraction of radiaton lenght
Definition MatCell.h:31
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"