Tgeo and pixel modelling

I’m relatively new to ROOT and completely new to the ROOT geometry package. Currently I’m trying to model pixel detectors with more generic pixel shapes than simply same sized rectangular ones for the purpose of clustering and hit position determination.

Since usually a lot of the sensor is somewhat periodic I think that using the TGeo is generally a good idea, also because many volumes can be easily described via subdividing larger ones, thus allowing fast navigation. The problem I currently encounter is the connection of pixel coordinate (simply the pixel X,Y “coordinate”) and the actual node representing the pixel.
I.e. I have the information “pixel 4|16 and pixel 4|17 have been hit” and now I want to get the position of the volumes in the node representing these pixels. Is there any good approach to that? I’m dealing with a several 100 000 pixels per detector plane and need to model something in the order of 10 planes.



You just need to have an appropriate indexing scheme. You are likely dividing on both x and y axis each of your 10 planes, something like:

 row = plane_i->Divide("row", 1, nx);
 pixel = row->Divide("pixel", 2, ny);

Doing this, you get a hierarchy of nodes like:
…/plane_(1 to 10)/row_(1 to nx)/pixel_(1 to ny) which you can browse in a TBrowser. To check which of your pixels was hit, you need:

  • a correspondence between (plane_index, row_index, pixel_index) and your internal pixel mapping
  • to find out these indices for the current node, assuming that the current node (as given by TGeoManager::GetCurrentNode) points to it (after some FindNode(x,y,z) query)

The first you need to sort out yourself, for the second you have some simple tools:
node = gGeoManager->GetCurrentNode();

if (node->GetVolume() == pixel_volume) {
   pixel_index = node->GetNumber();
   mother_node = gGeoManager->GetMother(1);
   row_index = mother_node->GetNumber();
   mother_node = gGeoManager->GetMother(2);
   plane_index = mother_node->GetNumber(); // assuming you added your planes as nodes starting with 1

Does this help?

Thanks for your quick and helpful answer, it does help a lot, but I’m still not sure how I can solve the following task:

Given that I have my “correspondence between (plane_index, row_index, pixel_index) and my internal pixel mapping” and now want to go the reverse way: I want to know where my node /plane_P/row_X/pixel_Y is located in my plane.
So I have my information: pixel X|Y in plane P has been hit, now via my correspondence between I can predict which node has been hit. But now I want to find the relative positions of my volumes.
For example I would like to tell my TGeoManager to locate itself at node /plane_P/row_X/pixel_Y and then get its position.


Hi Tobias,

Supposing you know which pixel /plane_P/row_X/pixel_Y has been hit, you can always do:

// now you can convert the coordinates of the local centre of the pixel into raw coordinates:
Double_t pixel_pt[3] = {0,0,0};
Double_t row_pt[3];
gGeoManager->GetCurrentNode()->LocalToMaster(pixel_pt, row_pt);
Double_t plane_pt[3];
gGeoManager->GetMother(1)->LocalToMaster(row_pt, plane_pt);
// Now you have the centre of the pixel in plane coordinates.


Once again, thanks for your help, it helps a lot! Unfortunately I still have some questions:

First of all, I have following code:

//Create the sensitive area for the sensor
TGeoVolume* plane = geom->MakeBox( "sensarea", Si, 10.6, 5.3, 1.01 );
//Divide the regions to create pixels
TGeoVolume* row = plane->Divide("row", 2 , 52 , 0 , 1, 0, "N"); 
TGeoVolume* pixel = row->Divide("pixel", 1 , 46, 0 , 1, 0, "N"); 

Dividing with Divide(“row”, 1, nx) does not work, also I don’t find this type signature in the online documentation, whereas it is the way as described in chapter 18 of the documentation: :confused:
Furthermore, as soon as I increase the division count:

TGeoVolume* row = plane->Divide("row", 2 , 1100 , 0 , 1, 0, "N"); 
TGeoVolume* pixel = row->Divide("pixel", 1 ,500, 0 , 1, 0, "N"); 

I only see the division into rows when I look at the result via Draw() (see attached screenshot). But I can browse the correct structure, also the right amount of nodes in created and navigation works as it should. So I guess this is just a limitation of the drawing? In that case that’s fine for me.

My third and final question concerns the coordinate transformations local <-> global: Your above way works like a charm, but if I’m not mistaken it only works as long as I have a constant depth in my divisions/placement of nodes in other nodes. This determines how often I need to call the ->GetMother(1) and do the next transformation. What if my detector consists of different regions, lets say for example this would be a pixel: /world/plane1/region1_1/subdivision_X as well as /world/plane1/region2_1/subdivision_X/subdivision_Y would be one (just in a different region). I now want to get the coordinates in the local frame of /world/plane1 the same way for any of those pixels, given that I obviously know the path to /world/plane1. Is there any quick way without recursively going up one node and checking if this is /world/plane1?

Cheers and many thanks,

Indeed, what you call is correct, the Divide method that I sent was a shortcut, but a bit too short. The correct version (described also in the reference guide: ( is: plane->Divide("row",1,nx,0,0);

The issue you experience with very high number of divisions is indeed a visualisation limitation, nothing to worry about. For your third question the answer is no - you have to always recursively go up to identify on which plane (mother) the pixel is, assuming that you have a constant relative depth from all pixels to the mother planes OR that you store the pointer to the plane volume and check that GetMother(n)->GetVolume() is the same. However, if you just need to know if the pixel belongs to a specific plane without doing coordinates transformation, you can do: if (gGeoManager->GetMother(3)->GetVolume()->GetNumber()==plane_number) {...}