15#include <fairlogger/Logger.h>
16#include <TCollection.h>
18#include <TGeoMatrix.h>
19#include <TGeoNavigator.h>
21#include <TGeoPhysicalNode.h>
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>
47#include <VecGeom/navigation/BVHLevelLocator.h>
49#include <VecGeom/navigation/VNavigator.h>
50#include <VecGeom/volumes/LogicalVolume.h>
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>
68std::mutex GeometryManager::sTGMutex;
74 if (!gGeoManager || !gGeoManager->IsClosed()) {
75 LOG(error) <<
"No active geometry or geometry not yet closed!";
79 std::lock_guard<std::mutex> guard(sTGMutex);
80 if (!gGeoManager->GetListOfPhysicalNodes()) {
81 LOG(warning) <<
"gGeoManager doesn't contain any aligned nodes!";
83 if (!gGeoManager->cd(symname)) {
84 LOG(error) <<
"Volume path " << symname <<
" not valid!";
87 m = *gGeoManager->GetCurrentMatrix();
92 TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
93 const char*
path =
nullptr;
96 m = *pne->GetGlobalOrig();
99 LOG(warning) <<
"The symbolic volume name " << symname
100 <<
"does not correspond to a physical entry. Using it as a volume path!";
104 return getOriginalMatrixFromPath(
path,
m);
108Bool_t GeometryManager::getOriginalMatrixFromPath(
const char*
path, TGeoHMatrix&
m)
112 if (!gGeoManager || !gGeoManager->IsClosed()) {
113 LOG(error) <<
"Can't get the original global matrix! gGeoManager doesn't exist or it is still opened!";
116 std::lock_guard<std::mutex> guard(sTGMutex);
117 if (!gGeoManager->CheckPath(
path)) {
118 LOG(error) <<
"Volume path " <<
path <<
" not valid!";
122 TIter next(gGeoManager->GetListOfPhysicalNodes());
123 gGeoManager->cd(
path);
125 while (gGeoManager->GetLevel()) {
126 TGeoPhysicalNode* physNode =
nullptr;
128 TGeoNode*
node = gGeoManager->GetCurrentNode();
130 while ((physNode = (TGeoPhysicalNode*)next())) {
131 if (physNode->GetNode() ==
node) {
136 TGeoMatrix* lm =
nullptr;
138 lm = physNode->GetOriginalMatrix();
140 lm =
node->GetMatrix();
143 lm =
node->GetMatrix();
159 if (!gGeoManager || !gGeoManager->IsClosed()) {
160 LOG(error) <<
"Can't get the global matrix! gGeoManager doesn't exist or it is still opened!";
165 TGeoPhysicalNode* pnode = pne->GetPhysicalNode();
167 return pnode->GetMatrix();
171 pne->SetPhysicalNode(
new TGeoPhysicalNode(pne->GetTitle()));
172 return pne->GetPhysicalNode()->GetMatrix();
181 if (!gGeoManager || !gGeoManager->IsClosed()) {
182 LOG(error) <<
"No active geometry or geometry not yet closed!";
186 TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
201 TGeoPNEntry* pne = gGeoManager->GetAlignableEntryByUID(
id);
203 LOG(error) <<
"Failed to find alignable entry with index " <<
id <<
": Det" << detid <<
" Sens.Vol:" << sensid <<
") !";
206 return pne->GetName();
215 TGeoPNEntry* pne = gGeoManager->GetAlignableEntryByUID(
id);
217 LOG(error) <<
"The sens.vol " << sensid <<
" of det " << detid <<
" does not correspond to a physical entry!";
228 static TGeoHMatrix matTmp;
234 TGeoPhysicalNode* pnode = pne->GetPhysicalNode();
236 return pnode->GetMatrix();
239 const char*
path = pne->GetTitle();
240 gGeoManager->PushPath();
241 if (!gGeoManager->cd(
path)) {
242 gGeoManager->PopPath();
243 LOG(error) <<
"Volume path " <<
path <<
" not valid!";
246 matTmp = *gGeoManager->GetCurrentMatrix();
247 gGeoManager->PopPath();
271 for (
auto dv : algPars) {
283 int nvols = algPars.size();
284 std::vector<int> ord(
nvols);
285 std::iota(std::begin(ord), std::end(ord), 0);
286 std::sort(std::begin(ord), std::end(ord), [&algPars](
int a,
int b) {
return algPars[
a].getLevel() < algPars[
b].getLevel(); });
292 LOG(error) <<
"Error applying alignment object for volume" << algPars[ord[
i]].getSymName();
303 double nrm = 1. / step;
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;
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];
354 throw std::runtime_error(
"meanMaterialBudgetExt requires geometry loaded");
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()) {
362 double invlen = 1. /
length;
363 for (
int i = 3;
i--;) {
366 std::lock_guard<std::mutex> guard(sTGMutex);
368 TGeoNode* currentnode = gGeoManager->InitTrack(startD, dir);
370 LOG(error) <<
"start point out of geometry: " <<
x0 <<
':' <<
y0 <<
':' << z0;
375 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
380 gGeoManager->FindNextBoundaryAndStep(
length, kFALSE);
381 Double_t stepTot = 0.0;
382 Double_t step = gGeoManager->GetStep();
384 if (!gGeoManager->IsOnBoundary()) {
390 while (
length > TGeoShape::Tolerance()) {
391 if (step < 2. * TGeoShape::Tolerance()) {
399 const double* curPos = gGeoManager->GetCurrentPoint();
400 LOG(warning) <<
"Cannot cross boundary at (" << curPos[0] <<
',' << curPos[1] <<
',' << curPos[2] <<
')';
417 currentnode = gGeoManager->GetCurrentNode();
422 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
423 gGeoManager->FindNextBoundaryAndStep(
length, kFALSE);
424 step = gGeoManager->GetStep();
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()) {
457 double invlen = 1. /
length;
458 for (
int i = 3;
i--;) {
465 std::unique_lock<std::mutex> guard(sTGMutex, std::defer_lock);
468 nav = gGeoManager->GetCurrentNavigator();
471 TGeoNode* currentnode = nav->InitTrack(startD, dir);
473 LOG(error) <<
"start point out of geometry: " <<
x0 <<
':' <<
y0 <<
':' << z0;
478 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
483 nav->FindNextBoundaryAndStep(
length, kFALSE);
484 Double_t stepTot = 0.0;
485 Double_t step = nav->GetStep();
487 if (!nav->IsOnBoundary()) {
493 while (
length > TGeoShape::Tolerance()) {
494 if (step < 2. * TGeoShape::Tolerance()) {
502 const double* curPos = nav->GetCurrentPoint();
503 LOG(warning) <<
"Cannot cross boundary at (" << curPos[0] <<
',' << curPos[1] <<
',' << curPos[2] <<
')';
505 budTotal.
length = stepTot;
516 currentnode = nav->GetCurrentNode();
521 accountMaterial(currentnode->GetVolume()->GetMedium()->GetMaterial(), budStep);
522 nav->FindNextBoundaryAndStep(
length, kFALSE);
523 step = nav->GetStep();
526 budTotal.
length = stepTot;
535 LOG(fatal) <<
"geometry is not loaded";
537 if (applyMisalignment) {
539 aligner.applyAlignment();
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;
559 if (preferAlignedFile) {
569#ifdef O2_WITH_VECGEOM
576bool usesBvhAcceleration(vecgeom::LogicalVolume
const* vol)
578 return vol->GetDaughtersp()->size() > 2;
584void ensureVecGeomWorldBuilt()
586 GeometryManager::buildVecGeomGeometry(
true);
590void GeometryManager::buildVecGeomGeometry(
bool flattenAssemblies,
int booleanThreshold)
592 static std::once_flag onceFlag;
593 std::call_once(onceFlag, [flattenAssemblies, booleanThreshold]() {
595 LOG(fatal) <<
"Cannot build VecGeom geometry: no TGeo geometry loaded (call GeometryManager::loadGeometry() first)";
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>)
603 LOG(info) <<
"VecGeom conversion: booleanThreshold=" << booleanThreshold;
604 vecgeom::GeoManager::Instance().SetBooleanOptimizationThreshold(booleanThreshold > 0 ? booleanThreshold : 0);
606 if (booleanThreshold > 0) {
607 LOG(warning) <<
"VecGeom without BooleanFactory: Boolean solids are kept as converted";
610 tgeo2vecgeom::RootGeoManager::Instance().LoadRootGeometry();
613#if VECGEOM_VERSION < 0x020000
615 vecgeom::ABBoxManager::Instance().InitABBoxesForCompleteGeometry();
618 vecgeom::BVHManager::Init();
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());
633 vol->SetLevelLocator(vecgeom::SimpleLevelLocator::GetInstance());
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
658 vol->SetLevelLocator(vecgeom::SimpleABBoxLevelLocator::GetInstance());
660 vol->SetNavigator(vecgeom::BVHNavigator<>::Instance());
661 vol->SetLevelLocator(vecgeom::BVHLevelLocator::GetInstance());
673 ensureVecGeomWorldBuilt();
675 using Vector3D = vecgeom::Vector3D<vecgeom::Precision>;
679 if ((
length = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]) < TGeoShape::Tolerance() * TGeoShape::Tolerance()) {
683 double invlen = 1. /
length;
684 for (
int i = 3;
i--;) {
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;
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());
706 thread_local static bool startCacheValid =
false;
709 Vector3D dirr(dir[0], dir[1], dir[2]);
710 constexpr double kPush = 1.E-6;
711 auto world = vecgeom::GeoManager::Instance().GetWorld();
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);
722 currnavstate->Clear();
723 vecgeom::GlobalLocator::LocateGlobalPoint(world, currPoint, *currnavstate,
true);
725 if (currnavstate->IsOutside() || currnavstate->Top() ==
nullptr) {
726 LOG(error) <<
"start point out of geometry: " <<
x0 <<
':' <<
y0 <<
':' << z0;
727 startCacheValid =
false;
730 currnavstate->CopyTo(startCache);
731 startCacheValid =
true;
734 double remainingDist =
length;
736 while (remainingDist > 1.E-10) {
737 auto* lvol = currnavstate->Top()->GetLogicalVolume();
741 accountMaterial(
static_cast<TGeoMaterial*
>(tgeo2vecgeom::RootGeoManager::Instance().GetMaterialPtr(lvol)), budStep);
742#if VECGEOM_VERSION >= 0x020000
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));
748 const double step =
static_cast<double>(lvol->GetNavigator()->ComputeStepAndPropagatedState(currPoint, dirr, remainingDist, *currnavstate, *newnavstate));
757 LOG(warning) <<
"Cannot cross boundary at (" << currPoint[0] <<
',' << currPoint[1] <<
',' << currPoint[2] <<
')';
763 remainingDist -=
step;
767 currPoint = currPoint + (
step + kPush) * dirr;
768 std::swap(currnavstate, newnavstate);
780#ifdef O2_WITH_VECGEOM
781 ensureVecGeomWorldBuilt();
792#ifdef O2_WITH_VECGEOM
793 ensureVecGeomWorldBuilt();
796#if VECGEOM_VERSION >= 0x020000
797 thread_local vecgeom::NavigationState stateStorage;
798 thread_local vecgeom::NavigationState*
state = &stateStorage;
800 thread_local vecgeom::NavigationState*
state =
801 vecgeom::NavigationState::MakeInstance(vecgeom::GeoManager::Instance().getMaxDepth());
804 const vecgeom::Vector3D<vecgeom::Precision> point(
x,
y,
z);
805 if (vecgeom::GlobalLocator::LocateGlobalPoint(vecgeom::GeoManager::Instance().GetWorld(), point, *
state,
true) ==
809 auto const& converter = tgeo2vecgeom::RootGeoManager::Instance();
812 auto const*
node = placed !=
nullptr ? converter.tgeonode(placed) :
nullptr;
813 if (
node ==
nullptr) {
817 chain.push_back(
const_cast<TGeoNode*
>(
node));
819 return !
chain.empty();
Definition of the base alignment parameters class.
Definition of the GeometryManager class.
std::unique_ptr< expressions::Node > node
Definition of the Names Generator class.
static bool isGeometryLoaded()
static const char * getSymbolicName(o2::detectors::DetID detid, int sensid)
static bool ensureVecGeomWorld()
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="")
static std::string getGeomFileName(const std::string_view prefix="")
static constexpr std::string_view CCDBOBJECT
static constexpr std::string_view GEOMOBJECTNAME_FAIR
static const GeometryManagerParam & Instance()
Static class with identifiers, bitmasks and names for ALICE detectors.
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
GLboolean GLboolean GLboolean b
GLuint GLsizei GLsizei * length
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLsizei const GLchar *const * path
GLboolean GLboolean GLboolean GLboolean a
GLuint GLfloat GLfloat y0
GLdouble GLdouble GLdouble z
float float float float z1
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< T >, ROOT::Math::DefaultCoordinateSystemTag > Vector3D
void normalize(double nrm)
float length
length in material
float meanRho
mean density, g/cm^3
float meanX2X0
fraction of radiaton lenght
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"