Storing TGeoManagers in TTrees - how?

Hi,

I’m trying to move the COMPASS experiment towards usage of the ROOT geometry classes in our reconstruction software. I’m failing at the following point: I want to write the geometry to our detector description tree. I went through the code in TGeoManager::Import and TGeoManager::Export, and the only thing I’m missing appears to be TGeoManager::UpdateElements – a private method which enforces consistency after loading the TGeoManager. Specifically what I’m seeing is the following (file f.root contains a tree t with a single branch which contains the TGeoManager object):

root [0] f = TFile::Open(“f.root”, “READ”)
(class TFile*)0x1c94ba0
root [1] TTree* t
root [2] f->GetObject(“t”, t)
root [3] TGeoManager m = new TGeoManager()
root [4] gGeoManager = 0
(const int)0
root [5] t->SetBranchAddress(“geo”, &m)
root [6] t->GetEntry(0)
Warning in TGeoIdentity::RegisterYourself: cannot register without geometry
Info in TGeoManager::TGeoManager: Geometry Geometry, default geometry created
(Int_t)3619945
root [7] gGeoManager = m
(class TGeoManager
)0x1720270
root [8] if (!gROOT->GetListOfGeometries()->FindObject(gGeoManager)) gROOT->GetListOfGeometries()->Add(gGeoManager);
root [9] if (!gROOT->GetListOfBrowsables()->FindObject(gGeoManager)) gROOT->GetListOfBrowsables()->Add(gGeoManager);
root [10] gGeoManager->Print()
OBJ: TGeoManager detectors detectors.C
root [11] gGeoManager->GetNNodes()
(Int_t)72795
root [12] gGeoManager->UpdateElements()
Error: can not call private or protected function (tmpfile):1:
/software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libGeom.so -1 void TGeoManager::UpdateElements();
Calling : TGeoManager::UpdateElements();
Match rank: file line signature

  •    0 /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libGeom.so  -1 void TGeoManager::UpdateElements();
    

*** Interpreter error recovered ***
root [13] gGeoManager->InitTrack(400, 0, 0, 1, 0, 0)

*** Break *** segmentation violation

I don’t understand the warning message at line 6 (call to GetEntry) but it’s non-fatal. As you can see the goemetry is loaded, I can make some queries but I can’t actually use it.

Any help would be appreciated.

Best regards,

  • Tobias Schlüter

For the sake of completeness, here’s the backtrace, though it’s not very helpful:

There was a crash.
This is the entire stack trace of all threads:

stat_loc=0x7fff772565dc, options=<value optimized out>)
at ../sysdeps/unix/sysv/linux/waitpid.c:32

#0 0x00007f1b264d0f7e in __libc_waitpid (pid=,
stat_loc=0x7fff772565dc, options=)
at …/sysdeps/unix/sysv/linux/waitpid.c:32
#1 0x00007f1b264687e9 in do_system (line=)
at …/sysdeps/posix/system.c:149
#2 0x00007f1b2859dc41 in TUnixSystem::StackTrace() ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libCore.so
#3 0x00007f1b2859d1b3 in TUnixSystem::DispatchSignals(ESignals) ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libCore.so
#4
#5 0x00007f1b24cf91a0 in TGeoNavigator::InitTrack(double, double, double, double, double, double) ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libGeom.so
#6 0x00007f1b24dbd0fd in G__G__Geom1_180_0_162(G__value*, char const*, G__param*, int) ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libGeom.so
#7 0x00007f1b27a121d9 in Cint::G__ExceptionWrapper(int ()(G__value, char const*, G__param*, int), G__value*, char*, G__param*, int) ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libCint.so

I tried creating a TGeoNavigator myself, as suggested by the crash location, but that helped little, the crash moved to another place, namely:

#5 0x00007f6c50ecbed7 in TGeoNavigator::SearchNode(bool, TGeoNode const*) ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libGeom.so
#6 0x00007f6c50eccfa2 in TGeoNavigator::FindNode(bool) ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libGeom.so
#7 0x00007f6c50f910fd in G__G__Geom1_180_0_162(G__value*, char const*, G__param*, int) ()
from /software/cernlib/gcc-4.4/root_v5.28.00-patches-37583/lib/libGeom.so

Hi Tobias,
I really don’t see the point in doing this (why do you need this in a tree?). However, to debug this, try to sent the stack trace while having root compiled in debug mode.

Regards,
Andrei

Well, it’s not my decision to make, and the guy responsible for the software prefers having it in a tree, it certainly allows for easier merging of files. TGeoManager::Import and Export also interfere with our usual procedure (geometry information stored alongside the produced data, which is also logical in our case, as our detector information is more than just geometry), as I’d have to memorize that I wanted to store the geometry and then add it to the produced file after it’s been closed. This becomes especially obnoxious when the file has to be split due to large size, as I’d then have to add all the referenced geometries to all parts of the file (we can have several runs in one so-called mini-DST file, and therefore several geometries).

I’ll see if I can produce a debug backtrace. Not that I think that it will help much – UpdateElements certainly isn’t available to me if I’m using a tree.

Anyway, I take it from your answer that TGeoManager is unusual for a ROOT class in that it shouldn’t be stored in a tree.

BTW: Andrei,
after you gave your talk at COMPASS I asked you to estimate how long it would take COMPASS to move to the VMC given your previous experience. That’s still in the stars, but I can tell you that I ported our reconstruction software to the ROOT geometry during another talk at that same meeting: where our still-current interface for handing geometry information from MC to reconstruction was discussed – I found this interface so insane that I felt the immediate urge to replace it with something better. I replaced a few hundred lines of code with the ~20 lines of code that are required to use the ROOT geometry. I’m saying this to let you know that I’m happy with the software :slight_smile:

Tobias, if you need to bind geometry with data in the same file (which is not the smartest thing to do due to geometry size and the fact that it does not change for every file !!!) you can put it anyway in the user info of the tree, not as a branch (!). Note that changing geometries in memory is a thing that should be carefully managed (gGeoManager global pointer and navigators)

A better approach is to have a DB of geometry versions and to separately retrieve the geometry you need according to a run range. You can do this even if you mix runs in your miniDST - you just detect the run change then switch to the appropriate geometry.

Just my two cents, but I would try to convince my software coordinators…
Cheers,

I’ll see if I can find out wht the Tree user-info is. Thanks for the pointer.

As for the rationale: our current approach allows me to work on my laptop even when I’m offline. A situation that admittedly gets rarer and rarer, but still something I profit from occassionally. The geometry comes in at about 200k (compressed), which is irrelevant compared to the 2 GB datafiles that we’re usually handling.

OK, your choice. Look at TTree::Set/GetUserInfo() where you can put a list of geometries if needed. While loading the tree, you will have to implement the mechanism to switch the active geometry.

Cheers,

Thanks, I’ll see if I can get somewhere with that.

[quote=“agheata”]Look at TTree::Set/GetUserInfo() where you can put a list of geometries if needed. While loading the tree, you will have to implement the mechanism to switch the active geometry[/quote]Seems to work for a single geometry (note that it ‘activates’ the geometry the moment I load the Tree):
root [0] f = TFile::Open(“f.root”, “READ”)
(class TFile*)0x1c3b430
root [1] TTree* t
root [2] f->GetObject(“t”, t)
Info in TGeoManager::CloseGeometry: Geometry loaded from file…
Info in TGeoManager::SetTopVolume: Top volume is HALL. Master volume is HALL
Info in TGeoManager::Voxelize: Voxelizing…
Info in TGeoNavigator::BuildCache: — Maximum geometry depth set to 100
Info in TGeoManager::CloseGeometry: 72795 nodes/ 1530 volume UID’s in detectors.C
Info in TGeoManager::CloseGeometry: ----------------modeler ready----------------
root [3] gGeoManager->Print()
OBJ: TGeoManager detectors detectors.C
root [4] gGeoManager->GetNNodes()
(Int_t)72795
root [5] gROOT->GetListOfGeometries()->FindObject(gGeoManager)
(const class TObject*)0x1fa0ff0
root [6] gROOT->GetListOfBrowsables()->FindObject(gGeoManager)
(const class TObject*)0x1fa0ff0
root [7] gGeoManager->InitTrack(400, 0, 0, 1, 0, 0)
(class TGeoNode*)0x2184e20
root [8]

Now I only need to figure out a way to deal with multiple geometries.

A colleague of mine came up with an elegant and simple solution: the geometry is handled as a .C file. Just put the contents of this file as text into the tree. This seems to address all my problems.

OK Tobias,
I am not sure this is the most elegant approach, but for small geometries it should do the trick.

Best,