Optimal TGeo volume tree?

Hi there,

Suppose i wanna build segmented volume contaning subvolumes. I can’t just divide this initial volume due to intersections with subvolumes. So i need to define one segment with subvolume and position it as many times as i need. Here comes 2 questions concerning the optimal way to do it:

  for(Int_t i=0;i<iNpadsX;i++)
    for(Int_t j=0;j<iNpadsY;j++)
      pSector->AddNode(pPad,copy=11000000+1000*(j+1)+i+1,new TGeoTranslation(-dSecX+i*2*dPadX+dPadX,-dSecY+j*2*dPadY+dPadY,0));

or i may do it into 2 steps first a column (or row) then segments in the column:

for(Int_t i=0;i<iNpadsX;i++){
pSector->AddNode(pColumn,copy=11000000+i+1,new TGeoTranslation(-dSecX+i*2*dPadX+dPadX,0,0));

for(Int_t j=0;j<iNpadsY;j++)
pColumn->AddNode(pPad,copy=11000000+1000*(j+1)+i+1,new TGeoTranslation(0,-dSecY+j*2*dPadY+dPadY,0));

What is better?
2. Is there any restriction in choosing copy numbers?
May they be some arbitrary numbers not in sequence
as in example without any penalty in performance?

Hi Kiril,

Either case can be VERY bad for performance, if the number of pads is several thousands, since they all end-up in the same container volume if you do it this way. I see that you position your pads just with translations on X/Y, so normally you should be able to divide some row-container shape. This may not be the case only you have something like a honeycomb structure. If this is the case, you better define a container volume for each row, divide it in equal cells and put your pad in the elementary cell. Then you add all the row-containers overlapping each other (using AddNodeOverlap) with the proper position shifts.

Normally there is no restriction on the copy numbers, you just have to make sure that the same volume placed several times as node in the same container get different numbers.

If you did not understood what I meant, send me a small macro creating your sector geometry and I will have a look.


Hi Andrei

Well initially i did it by TGeoVolume::Divide():

void AliVHMPID::GeomChamber(TGeoVolume *pTic)
// Creates detailed geometry for aerogel study.
// Argument: pTic - pointer to chamber volume, all internal volumes are to be nodes of this master volume 
  Double_t cm=1,mm=0.1*cm;
  Double_t dx,dy,dz,shiftX,shiftY,shiftZ; Int_t copy; //tmp vars for geometry     
  TGeoVolume *pGap=gGeoManager->MakeBox("VhGap",gGeoManager->GetMedium("TicRad"),dx=P()->PadSizeX()*P()->NpadsX()/2, dy=P()->PadSizeY()*P()->NpadsY()/2, dz=4*mm/2);//Gap
  TGeoRotation *pRot=new TGeoRotation("VhGapRot"); pRot->RotateY(90); //rotate 
  pTic->AddNode(pGap,copy=1,new TGeoCombiTrans(shiftX=0*cm,shiftY=0*cm,shiftZ=0*cm,pRot));
  fIdGap=pGap->GetNumber();//needed in StepManager() to check if the track inside gap volume
  Int_t axis,ndiv; Double_t start,step;
  TGeoVolume *pPadX=pGap->Divide("VhPadX",axis=1,ndiv=P()->NpadsX(),start=0,step=0);//divide VhGap along X by NpadsX volumes
              pPadX     ->Divide("VhPadY",axis=2,ndiv=P()->NpadsY(),start=0,step=0);//divide VhPadX along Y by NpadsY volumes

But my problem is that: I need to put some volumes inside the volume i divided. This leads to intersection
which provides problems with G3. According to Rene’s answer this is unavoidable feature of G3.
So i’m forced to do something like that:

void KirTransport::Geom()
Double_t cm=1,m=100cm,mm=0.1cm,mkm=0.001*mm; //default dimentions is cm
Printf(“DEFAULT KirTransport::Geom() invoked”);
Int_t copy;
Double_t dx,dy,dz; //half lengthes in x,y,z for boxes
Double_t rmin,rmax; //for spheres tubes cones

// z
// ^
// |
// | <-Y0-> X <–Y1–> X <–Y1–> X <–Y1–> X <-Y0-> cath wires: r 50mkm, shift Y0=1.05mm, pitch Y1=2.1mm
// | cath wire center to PC 4.45mm
// |
// | <–Y0–> x <-----------Y1-----------> x <–Y0–> anod wires: r 20mkm, shift Y0=2.2mm, pitch Y1=4.0mm material W
// | anod wire center to PC 2.04mm
// |
// | |________________________________________________| pad size y 8.4mm
// |--------------------------------------------------------------------------------------------------------------------> y
Double_t dCathWireR=50mkm , dCathWireY0=1.05mm , dCathWireY1=2.1mm , dPcCathWire=4.45mm; //cath wires layer
Double_t dAnodWireR=20mkm , dAnodWireY0=2.2mm , dAnodWireY1=4.0mm , dPcAnodWire=2.04mm; //anod wires layer

Double_t dPcX =0.58.0mm , dPcY =0.58.4mm , dPcZ=0.550mkm ; //PC
Double_t dPadX =dPcX , dPadY =dPcY , dPadZ=dPcZ+0.5dPcCathWire+dCathWireR ; //Pad 25 mkm is a tolerance
Int_t iNpadsX =80 , iNpadsY =48 ; //80x48
Double_t dSecX =iNpadsX
dPadX , dSecY =iNpadsY*dPadY , dSecZ=dPadZ ; //sector is 80x48 pads plane

TGeoVolume *pSector =MakeBox (“KirSector” ,GetMedium(“CF4”),dx=dSecX , dy=dSecY , dz=dSecZ ); //sector (a pads plane)
TGeoVolume *pPad =MakeBox (“KirPad” ,GetMedium(“CF4”),dx=dPadX , dy=dPadY , dz=dPadZ ); //amplification gap + PC
TGeoVolume *pPc =MakeBox (“KirPc” ,GetMedium(“CsI”),dx=dPadX , dy=dPadY , dz=dPcZ ); //photocathode
TGeoVolume *pAnodWire =MakeTube(“KirAnodWire”,GetMedium(“W”) ,rmin=0 , rmax=dAnodWireR , dz=dPadX ); //anod wire along X
TGeoVolume *pCathWire =MakeTube(“KirCathWire”,GetMedium(“Cu”) ,rmin=0 , rmax=dCathWireR , dz=dPadX ); //cath wire along X

GetTopVolume()->AddNode(pSector,copy=1,new TGeoTranslation(0m,0m,10*cm));

for(Int_t i=0;i<iNpadsX;i++)
for(Int_t j=0;j<iNpadsY;j++)
pSector->AddNode(pPad,copy=11000000+1000*(j+1)+i+1,new TGeoTranslation(-dSecX+i2dPadX+dPadX,-dSecY+j2dPadY+dPadY,0));

// TGeoVolume pColumn =MakeBox (“KirColumn” ,GetMedium(“CF4”),dx=dPadX , dy=dSecY , dz=dPadZ ); //vertical column of pads
// for(Int_t i=0;i<iNpadsX;i++){
// pSector->AddNode(pColumn,copy=11000000+1000+i+1,new TGeoTranslation(-dSecX+i
// for(Int_t j=0;j<iNpadsY;j++)
// pColumn->AddNode(pPad,copy=11000000+1000
(j+1)+i+1,new TGeoTranslation(0,-dSecY+j2dPadY+dPadY,0));
// }

TGeoRotation *pWireRot=new TGeoRotation(“KirWireRot”); pWireRot->RotateY(90); //rotate wires around Y to be along X (initially along Z)

pPad->AddNode(pPc ,copy=1,new TGeoTranslation(0, 0 , -dPadZ + dPcZ ));

pPad->AddNode(pAnodWire,copy=1,new TGeoCombiTrans (0, -dPadY+dAnodWireY0 , -dPadZ+dPcAnodWire+2dPcZ , pWireRot));
pPad->AddNode(pAnodWire,copy=2,new TGeoCombiTrans (0, dPadY-dAnodWireY0 , -dPadZ+dPcAnodWire+2
dPcZ , pWireRot));

pPad->AddNode(pCathWire,copy=1,new TGeoCombiTrans (0, -dPadY+dCathWireY0 , -dPadZ+dPcCathWire+2dPcZ , pWireRot));
pPad->AddNode(pCathWire,copy=2,new TGeoCombiTrans (0, -dPadY+dCathWireY0+dCathWireY1 , -dPadZ+dPcCathWire+2
dPcZ , pWireRot));
pPad->AddNode(pCathWire,copy=3,new TGeoCombiTrans (0, dPadY-dCathWireY0-dCathWireY1 , -dPadZ+dPcCathWire+2dPcZ , pWireRot));
pPad->AddNode(pCathWire,copy=4,new TGeoCombiTrans (0, dPadY-dCathWireY0 , -dPadZ+dPcCathWire+2
dPcZ , pWireRot));


Kirill, I really do not see the overlaping problem. Even in the second case, you have a unique volume pPad that is a box and of course that the volumes you put inside it should not overlap each other or extrude the box. Why do you think you cannot put this content in a division cell ?

Send me a macro that I can run, with real numbers instead of parameters and maybe I can help.