Advice on structuring Eve application

Hello,

I have a detector with some sensitive components I’ve modeled using the TGeoManager etc. I’d like to incorporate this into an event display using Eve. One role of the model in the event display is to perform tracking between hit locations and check if this track intersects another detector component.

Each component will have its own associated data, and then groups of components will have group-level data. So the design I have in mind is that each sensitive component is represented by an object, which is linked to its physical node location by the TGeoManager (perhaps I give each object the unique node id), and I can use this to do my interpolation or whatever other geometrical calculations I desire.

What I’m not sure of is the most sensible way to incorporate this into the TEve object hierarchy. Right now my geometry gets loaded into eve by giving it the top node and asking it to recursively descend. But all this accomplishes really is making a picture from the geometry; the TEveElements that are so created aren’t linked to any of my behind-the-scenes classes.

I see two different alternatives here (if they are not so different, or if there are other better ones, please enlighten me):

  1. Inherit the representations of my components from TEveElement, then iterate over my detector geometry, create instances of my objects using the shapes and translations of the nodes, then add them to an element list If I do it this way, then I can also give my component representation objects information about where they are (or give them the information about which node they belong to). Does inheriting these objects from TEveElement give me other nifty abilities later on (e.g. for highlighting/hiding detector components, making DigitSet collections, …?) Besides the interpolation I’d like to have other sets of plots which Eve seems very well suited for making and organizing so I’d like to have Eve ‘know’ as much about these objects and their member data as possible.

Or, is it better to let Eve do the geometry importing automatically, then after the fact give each TEveElement in the hierarchy a reference to my objects? This is less work, but then it appears that Eve doesn’t have the geometrical information (for example if I ask for the main translation belonging to each TEveElement using RefMainTrans, the matrix is the 0 matrix - it didn’t import the matrix used to place the TGeoNode? Then to get the geometry information into the objects referenced by the TEveElements would I have to iterate separately over the TGeoManager hierarchy?

Or is there a way to go directly to the TGeoNode used to place this TEveElement? It seems like there are now two separate hierarchies with very similar information (TGeoManager’s list of nodes and TEveManager’s list of TEveElements). Do I want to use them both simultaneously or try to only use the TEveElement hierarchy?

I feel like I’m going in circles between the many possibilities and perhaps those of you who have thought about this before might have some advice. Thanks for reading,

Joe

Not sure if anyone is interested in how I proceeded or not, but I thought I’d outline it for posterity.

I created a descendant of TEveGeoShape (call it MyDetectorComponent) which acts as a base class for the various detector elements. I create the eve geometry scene by recursively iterating over my geometry hierarchy, and creating MyDetectorComponents for each TGeoVolume and TGeoVolumeAssembly. At each volume I can decide which subclass of MyDetectorComponent to use based on the string path for each volume. (This might be expensive in terms of having a separate volume for every component, but I haven’t noticed any issues yet with about 1200 components - most of them are the same physical shape, however).

This way I can extract the TGeoShape and TGeoMatrix from the geometry nodes and give them to the TEveGeoShape member variables - so now I have all the geometric information contained in my classes, which can also be members of TEveElementList’s (since they inherit from TEveGeoShape). And now I can do interesting things like selecting MyDetectorComponents (because they are Pickable TEveElement’s) and displaying MyDetectorComponentEditor in the lower left pane.

Overall quite happy with the Eve framework, perhaps when it’s finished I’ll put it in the apps section.

Thanks,

Joe

Hi Joe,

Sorry I’m getting back to you so late … things are quite crazy for me these days.

I was going to propose the TEveGeoShape solution to you … we use this in CMS to display reconstruction geometry, too, allowing us to also color it according to hit information and to provide picking from the graphics views. We go up to a couple 10k shapes and it works ok.

I guess you learned all about TEveGeo(Top)Nodes the hard way … that it is just a view and sort of a GUI into a TGeo geometry and not an independent representation.

Another thing we did recently for CMS is an independent table-view representation of simulation geometry. We have about 2M volumes and it turns out we can load them into ~16MB large vector, holding pointers to TGeoNode, hierarchy information and graphical properties. This allows as to do extremely fast selection by shape or material and assign colors / transparency / visibility to volume selection.

Out of curiosity, what experiment are you doing this for?

Best,
Matevz

Hi Matevz,

Thanks for getting back to me on this!

This is for the CREST experiment - Cosmic Ray Electron Synchrotron Telescope. It’s a balloon-borne high energy cosmic ray lepton detector. We’re launching our mission from Antarctica in a couple months.

Well, I’m happy I chose a path that makes sense to at least one other person (and in this case apparently a large group of people). And you partially addressed another design choice I am making, which is whether to display hits by changing detector element visualization properties, or to paste a boxset or arrowset onto the model. Our detector is composed of a segmented crystal array (1024 disks in a plane) surrounded by a rectangular charged particle veto (see attached picture). For crystal hits, I can use a pointset or a boxset (or just color the discs), but veto hits are only interesting when both ends of a veto paddle register a hit, in which case what we really have is a distribution of where we think the hit occurred along the paddle (the spatial spread coming from our timing resolution - we have to measure the delay in light signals from either end of the paddle to reconstruct the position). So representing our paddle hits in a useful way becomes an exercise in artistry, in my opinion.

The way I decided to quickly map from the signal source (for us, a phototube number) to MyDetectorClass (which inherits from TEveGeoShape) was just a std::map<Int_t, MyDetectorClass*>. Then for an input event (a list of hits), I can iterate over the hits and modify/highlight the referenced component. From looking at the classes, it looks like you intended for things like this to be handled by TEveDigitSet, but I’m not sure how to proceed in that direction.

The other question I have to think about is how best to reconstruct charged particle tracks going through the veto paddles and connect them to candidate crystal hits. Charged particles -protons mostly- are a large background to our signal (synchrotron photons from cosmic ray leptons). The proton energy depositions in the crystals are useful as a calibration tool. (Having this diagnostic during flight is actually the reason I’m trying to make this 3D model in the first place!)

So I’d want to guess at particle tracks based on veto events, then determine the distance of a crystal from this track. Any advice on doing this more easily then moving along the line and calculating 1024 distances at every step? Perhaps involving TEveTrack? Are there any methods that perform something like: [find point of closest approach of a TEveTrack to a TEveGeoShape]?

Also a more general question - you mention for example doing selection by material to avoid I presume having to iterate over every TGeoShape - could you show me an example of this in action? It would apply easily in my case as well (veto material vs crystal material).

Thanks very much for your thoughts and assistance,

Joe


Hi Joe,

TEveQuadSet / TEveBoxSet (TEveDigitSet subclasses) might work for you in some cases. We used quad-sets for silicon detectors (pixel, strip and SDDs) in ALICE, with each module being one quad-set. The good thing here is that you can share a signal-color mapping (TEveRGBAPalette) between all instances – and then set thresholds etc in one place.

For CMS we developed TEveCalo classes … this gets rather complicated, see tutorial calorimeters.C. The main complications come from projected views and summing-up of energies in phi and eta … and then providing reasonable selection capabilities.

I guess what I’m saying is, use what’s there if it works for you, otherwise roll your own … as you already did.

About searching for closest point of approach … distance from a line to a point is quadratic in parametrization along the line … so you can find minimum for, say, the center of the disk, which should get you really close to the actual minimum. Or you meant something different? TEveTrack is really mostly container for (position, momentum) pairs as input and set of points on output. TEveTrackPropagator provides propagation in arbitrary magnetic field … and I guess all you have are straight lines so you don’t need anything like that.

Oh yes, if you can, use vector<MyDetectorClass*> instead of a map.

About material selection … we still iterate over all instances … the material selection just allows us to see all silicon / aluminium / gold / … in the detector. There are more than 1000 different materials used in CMS geometry and people often know what they are looking for by material and not by name. Full iteration over 2M volumes takes 0.1s … my point was that by not being shy and expanding the whole geometry into a vector one can do things very efficiently with, according to modern standards, very little memory consumption.

Best,
Matevz

Hi Matevz,

Thanks for the advice- makes a lot of sense.

I have copied the structure of the MultiView.C class in the eve tutorials section to make a tabbed window with a projected geometry scene of only the crystal detector elements. I iterate over a vector of detector components as you suggest:

vector<CRESTComponent*>::iterator compit; for (compit=fComponentVector.begin();compit < fComponentVector.end();compit++) { TString title = (*compit)->GetElementTitle(); if(title.Contains("XTAL")) { //then add to the crystal geometry cout << "Got XTAL element with name " << title << endl; fMultiview->ImportGeomCrystal(*compit); } }
the ImportGeomCrystal function is:

void CRESTMultiView::ImportGeomCrystal(TEveElement* el) { fCrystalMgr->ImportElements(el, fCrystalGeomScene); }
fCrystalMgr is a projection manager just ilke fRPhiMgr in MultiView.C, fCrystalGeomScene is analogous to fRPhiGeomScene, etc.

The spawned window successfully draws the projection; however, this causes a crash when I highlight a crystal in either the default gl viewer or the projected subwindow when another crystal is already highlighted:

[code]The lines below might hint at the cause of the crash.
If they do not help you then please submit a bug report at
http://root.cern.ch/bugs. Please post the ENTIRE stack trace
from above as an attachment in addition to anything else
that might help us fixing this issue.

#5 0x0000000113c93844 in gldReadPixels ()
#6 0x0000000113c8580a in gldUpdateDispatch ()
#7 0x0000000113c934b4 in gldReadPixels ()
#8 0x0000000113c7ec6a in gldUpdateDispatch ()
#9 0x0000000113c84c07 in gldUpdateDispatch ()
#10 0x0000000113c92fb5 in gldReadPixels ()
#11 0x0000000113c7bea9 in gldUpdateDispatch ()
#12 0x0000000113a3d8d9 in gleDoDrawDispatchCore ()
#13 0x000000011398b0a7 in gleSetupAndDrawArraysOrElementsOutOfLine_ListExec ()
#14 0x000000011398908e in gleCallList ()
#15 0x000000010fbd2174 in TGLPhysicalShape::Draw ()
#16 0x000000010fbe4409 in TGLScene::RenderElements ()
#17 0x000000010fbe4012 in TGLScene::RenderAllPasses ()
#18 0x000000010fc10f4f in TGLViewerBase::SubRenderScenes ()
#19 0x000000010fc10fe8 in TGLViewerBase::RenderNonSelected ()
#20 0x000000010fc0d14a in TGLViewer::DoDrawMono ()
#21 0x000000010fc0c726 in TGLViewer::DoDraw ()
#22 0x000000010ed66c0d in TEveViewerList::RepaintChangedViewers ()
#23 0x000000010ed1ed31 in TEveManager::DoRedraw3D ()

Root > Error in TGLLockable::TakeLock: ‘TGLSceneBase Crystal Geometry’ unable to take ModifyLock, already DrawLock
Error in TGLLockable::ReleaseLock: ‘TGLSceneBase Crystal Geometry’ unable to release ModifyLock, is DrawLock[/code]

Any ideas? The same code with the same version of root (trunk) does not crash on a different machine. I can search through glxinfo for something in particular if you think it will help. I’m not sure if it’s a gl issue or not, because I can run the eve tutorials without any crashes, including alice_esd.C from whence I copied the MultiView class.

Edit: If I add the gEve->GetGlobalScene() instead of fCrystalGeomScene, I get no crashes. Is there something wrong with the way I’m importing elements into fCrystalGeomScene? Or perhaps the order of adding the scene to a view vs. importing elements?

Working machine: macbook pro running Lion 10.7
non working: macbook running os x 10.5.8

Hi Joe,

Hmmh, no clue on the crash. It does have some strange GL function names … I’d guess this is on 10.7 :slight_smile:

Can you make me a tarball so that I can try myself?

Cheers,
Matevz

Yes - it’s compiled into a repository with some other collaboration libraries you don’t have so give me a minute to make an isolated version with a working makefile.

And right - it’s only on 10.7 that it has this behavior. What can you do; buying a new machine is just never a good idea. :unamused:

Joe

Here’s a tarball - it should compile with just make. The relevant lines are 98 and 99 of CRESTMultiView.cpp; right now it’s in the ‘working’ state (no crash) where the global geometry is added, you can get the crash by compiling with only the fCrystalGeom added.

Thanks for looking at it! Any other thing you happen to notice that could be improved feel free to let me know. #-o

Joe
CM.zip (1020 KB)

One thing I forgot to modify: upon creation of CRESTNavHandler, for testing I gave it a hard location of a root file to input - obviously you don’t have this file, so please comment line 67 of CRESTViewer.cpp - the one saying init_input().

Hi Joe,

I uncommented the two lines … it seems happy on my desktop (fedora 15). I have another of those 10.7s at home so will give it a try there later on (and no, getting a new computer is never a bad idea … it’s often a bad idea to reinstall an old one, though).

I also tried running with valgrind but get no errors.

Soon,
Matevz

Ok - thanks for checking it out. Also, by transitioning to compiled mode I’ve caused a series of errors to be printed out upon exiting via Control-q from the eve browser; I assume that’s because I create the eve classes inside of the CRESTViewer class but I’m not properly handling cleaning things up (especially fMultiview). Any quick tips on how to fix that up?

If you want a really quick one, call gSystem->Exit(0) on control-q :slight_smile:

Otherwise there’s static TEveManager::Terminate() that cleans up most of eve stuff. But destroying object forests is always harder than creating them :wink:

What crash do you get? It seems ok here (ctrl-q & menu).

Matevz

Well yes, I suppose that’s true :astonished:

Here’s what it spits out (this happens on os x 10.5.8 and 10.7):

root [0] Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorFailure: Set a breakpoint @ CGErrorBreakpoint() to catch errors as they are logged. Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b Oct 19 00:08:25 Josephs-MacBook-Pro.local CrestViewer[676] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0x11b

So I think I found a way to avoid the crash - apparently calling Scene->AddElements repeatedly is the issue. The workaround is to create a list of the elements to add first, then calling Scene->AddElement only once at the end.

So in CRESTViewer.cpp, I now have (specifically see the comment on line 150 and the addition of line 155:

144 TEveElementList* crystal_elements = new TEveElementList(); 145 vector<CRESTComponent*>::iterator compit; 146 for (compit=fComponentVector.begin();compit < fComponentVector.end();compit++) { 147 TString title = (*compit)->GetElementTitle(); 148 if(title.Contains("XTAL")) { //then add to the crystal geometry 149 cout << "Got XTAL element with name " << (*compit)->GetElementName() << endl; 150 //fMultiview->ImportGeomCrystal(*compit); 151 crystal_elements->AddElement(*compit); 152 } 153 } 154 155 fMultiview->ImportGeomCrystal(crystal_elements);

This results in no crash (yet!). So, was this an example of how not to add elements to a geometry scene, or should it have worked? Either way good to know this way does work.

Thanks,

Joe

Hi Joe,

I reproduced both issues (crash + errors on exit) yesterday but was too tired to look further.

I was suspecting there might be some kind of double addition of elements, or somehow getting selection/highlight select an element with 0 reference count (which causes it to get deleted on selection exit, as selection and highlight are implemented as eve lists and thus change reference count on objects) … I’ve seen crashes like this before :slight_smile:

If you want me to, I can try and go through your code in detail. With projections things get rather complex very soon – and I haven’t done this in a while. You probably saw that there are two projection-manager::import functions – one that puts products into the top level storage and the other one that puts them into a provided container (I think I saw you already use the second one, which is right, as you can choose which scene the products will go to).

Best,
Matevz

Hi Matevz,

I think it’s ok to leave it here - it’s working and while there may be some underlying issue in importing, it’s probably just some slightly subtle thing I should or should not have done differently in the compiled vs. interpreted code, or perhaps how I inherited my objects from TEveGeoShape. Perhaps when both of us have nothing to do we’d come back to this :cry: (never!)

Thanks so much for your help thus far - when the viewer is more developed, or when I run into a new, more terrible problem, I’ll update.

Cheers!

Joe

Hi Joe,

OK, deal! When / if you decide to move things further on, you’re welcome to visit UCSD so we can work on it together.

Cheers,
Matevz