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