ROOT logo
#include "TGeoManager.h"
#include "TGeoVolume.h"
#include "TGeoNode.h"
#include "TGeoBBox.h"
#include "TRandom3.h"
#include "TMath.h"
#include "TH1.h"
#include "TH2.h"
#include "TCanvas.h"
#include "TStopwatch.h"
#include "TFile.h"

TStopwatch *timer = 0;

Int_t propagate_in_geom(Double_t *, Double_t *);
void score(TGeoVolume *, Int_t, Double_t);
Double_t timing_per_volume(TGeoVolume *);
Double_t *val1 = 0;
Double_t *val2 = 0;
Bool_t   *flags = 0;

void checkgeom()
{
   TGeoManager::Import("geometry.root");
   Int_t nvol = gGeoManager->GetListOfVolumes()->GetEntries();
   Int_t nuid = gGeoManager->GetListOfUVolumes()->GetEntries();
   timer = new TStopwatch();
   Int_t i;
   Double_t value;
   flags = new Bool_t[nuid];
   val1 = new Double_t[nuid];
   val2 = new Double_t[nuid];
   memset(flags, 0, nuid*sizeof(Bool_t));
   memset(val1, 0, nuid*sizeof(Double_t));
   memset(val2, 0, nuid*sizeof(Double_t));
   TGeoVolume *vol;

// STAGE 1: Overlap checking by sampling per volume

   printf("====================================================================\n");
   printf("STAGE 1: Overlap checking by sampling per volume\n");
   printf("====================================================================\n");
   for (i=0; i<nvol; i++) {
      vol = (TGeoVolume*)gGeoManager->GetListOfVolumes()->At(i);
      Int_t uid = vol->GetNumber();
      if (flags[uid]) continue;
      flags[uid] = kTRUE;
      if (!vol->GetNdaughters()) continue;
      vol->CheckOverlaps(0.01, "s"); 
   }

// STAGE 2: Global overlap checking
   printf("====================================================================\n");
   printf("STAGE 2: Global overlap checking\n");
   printf("====================================================================\n");
   gGeoManager->CheckOverlaps(0.01);
   
// STAGE 3: How many crossings per volume in a realistic case ?
   // Ignore volumes with no daughters

   // Generate rays from vertex in phi=[0,2*pi] theta=[0,pi]
   Int_t ntracks = 1000000;
   printf("====================================================================\n");
   printf("STAGE 3: Propagating %i tracks starting from vertex\n and conting number of boundary crossings...\n", ntracks);
   printf("====================================================================\n");
   Int_t nbound = 0;
   Double_t theta, phi;
   Double_t point[3], dir[3];
   new TRandom3();

   timer->Start();
   for (i=0; i<ntracks; i++) {
      phi = 2.*TMath::Pi()*gRandom->Rndm();
      theta= TMath::ACos(1.-2.*gRandom->Rndm());
      point[0] = point[1] = point[2] = 0;
      dir[0]=TMath::Sin(theta)*TMath::Cos(phi);
      dir[1]=TMath::Sin(theta)*TMath::Sin(phi);
      dir[2]=TMath::Cos(theta);
      if ((i%1000)==0) printf("... remaining tracks %i\n", ntracks-i);
      nbound += propagate_in_geom(point,dir);
   }
   Double_t time1 = timer->CpuTime() *1.E6;
   Double_t time2 = time1/ntracks;
   Double_t time3 = time1/nbound;
   printf("Time for crossing %i boundaries: %g [ms]\n", nbound, time1);
   printf("Time per track for full geometry traversal: %g [ms], per crossing: %g [ms]\n", time2, time3);

// STAGE 4: How much time per volume:
   
   printf("====================================================================\n");
   printf("STAGE 4: How much navigation time per volume per next+safety call\n");
   printf("====================================================================\n");
   TGeoIterator next(gGeoManager->GetTopVolume());
   TGeoNode*current;
   TString path;
   vol = gGeoManager->GetTopVolume();
   memset(flags, 0, nuid*sizeof(Bool_t));
   score(vol, 1, timing_per_volume(vol)); 
   while ((current=next())) {
      vol = current->GetVolume();
      Int_t uid = vol->GetNumber();
      if (flags[uid]) continue;
      flags[uid] = kTRUE;
      next.GetPath(path);
      gGeoManager->cd(path.Data());
      score(vol,1,timing_per_volume(vol));
   }   

   // Draw some histos
   Double_t time_tot_pertrack = 0.;
   TCanvas *c1 = new TCanvas("c2","ncrossings",10,10,900,500);
   c1->SetGrid();
   c1->SetTopMargin(0.15);
   TFile *f = new TFile("histos.root", "RECREATE");
   TH1F *h = new TH1F("h","number of boundary crossings per volume",3,0,3);
   h->SetStats(0);
   h->SetFillColor(38);
   h->SetBit(TH1::kCanRebin);
   
   memset(flags, 0, nuid*sizeof(Bool_t));
   for (i=0; i<nuid; i++) {
      vol = gGeoManager->GetVolume(i);
      if (!vol->GetNdaughters()) continue;
      time_tot_pertrack += val1[i]*val2[i];
      h->Fill(vol->GetName(), (Int_t)val1[i]);
   }
   time_tot_pertrack /= ntracks;
   h->LabelsDeflate();
   h->LabelsOption(">","X");
   h->Draw();   


   TCanvas *c2 = new TCanvas("c3","time spent per volume in navigation",10,10,900,500);
   c2->SetGrid();
   c2->SetTopMargin(0.15);
   TH2F *h2 = new TH2F("h2", "time per FNB call vs. ndaughters", 100, 0,100,100,0,15);
   h2->SetStats(0);
   h2->SetMarkerStyle(2);
   TH1F *h1 = new TH1F("h1","percent of time spent per volume",3,0,3);
   h1->SetStats(0);
   h1->SetFillColor(38);
   h1->SetBit(TH1::kCanRebin);
   for (i=0; i<nuid; i++) {
      vol = gGeoManager->GetVolume(i);
      if (!vol->GetNdaughters()) continue;
      value = val1[i]*val2[i]/ntracks/time_tot_pertrack;
      h1->Fill(vol->GetName(), value);
      h2->Fill(vol->GetNdaughters(), val2[i]);
   }     
   h1->LabelsDeflate();
   h1->LabelsOption(">","X");
   h1->Draw();
   TCanvas *c3 = new TCanvas("c4","timing vs. ndaughters",10,10,900,500);
   c3->SetGrid();
   c3->SetTopMargin(0.15);
   h2->Draw();   
   f->Write();
   delete [] flags;
   delete [] val1;
   delete [] val2;
}

Int_t propagate_in_geom(Double_t *start, Double_t *dir)
{
// Propagate from START along DIR from boundary to boundary until exiting 
// geometry. Fill array of hits.
   gGeoManager->InitTrack(start, dir);
   TGeoNode *current = 0;
   Int_t nzero = 0;
   Int_t nhits = 0;
   while (!gGeoManager->IsOutside()) {
      current = gGeoManager->FindNextBoundaryAndStep(TGeoShape::Big(), kFALSE);
      if (!current || gGeoManager->IsOutside()) return nhits;
      Double_t step = gGeoManager->GetStep();
      if (step<2.*TGeoShape::Tolerance()) {
         nzero++;
         continue;
      } 
      else nzero = 0;
      if (nzero>3) {
      // Problems in trying to cross a boundary
         printf("Error in trying to cross boundary of %s\n", current->GetName());
         return nhits;
      }
      // Generate the hit
      nhits++;
      TGeoVolume *vol = current->GetVolume();
      score(vol,0,1.);
      Int_t iup = 1;
      TGeoNode *mother = gGeoManager->GetMother(iup++);
      while (mother && mother->GetVolume()->IsAssembly()) {
         score(mother->GetVolume(), 0, 1.);
         mother = gGeoManager->GetMother(iup++);
      }   
   }
   return nhits;
}      

void score(TGeoVolume *vol, Int_t ifield, Double_t value)
{
// Score something for VOL
   Int_t uid = vol->GetNumber();
   switch (ifield) {
      case 0:
         val1[uid] += value;
         break;
      case 1:
         val2[uid] += value;
   }
}   

Double_t timing_per_volume(TGeoVolume *vol)
{
// Compute timing per "FindNextBoundary" + "Safety" call. Volume must be
// in the current path.
   timer->Reset();
   const TGeoShape *shape = vol->GetShape();
   TGeoBBox *box = (TGeoBBox *)shape;
   Double_t dx = box->GetDX();
   Double_t dy = box->GetDY();
   Double_t dz = box->GetDZ();
   Double_t ox = (box->GetOrigin())[0];
   Double_t oy = (box->GetOrigin())[1];
   Double_t oz = (box->GetOrigin())[2];
   Double_t point[3], dir[3], lpt[3], ldir[3];
   Double_t pstep = 0.;
   pstep = TMath::Max(pstep,dz);
   Double_t theta, phi;
   Int_t idaughter;
   timer->Start();
   Double_t dist;
   Bool_t inside;
   for (Int_t i=0; i<1000000; i++) {
      lpt[0] = ox-dx+2*dx*gRandom->Rndm();
      lpt[1] = oy-dy+2*dy*gRandom->Rndm();
      lpt[2] = oz-dz+2*dz*gRandom->Rndm();
      gGeoManager->GetCurrentMatrix()->LocalToMaster(lpt,point);
      gGeoManager->SetCurrentPoint(point[0],point[1],point[2]);
      phi = 2*TMath::Pi()*gRandom->Rndm();
      theta= TMath::ACos(1.-2.*gRandom->Rndm());
      ldir[0]=TMath::Sin(theta)*TMath::Cos(phi);
      ldir[1]=TMath::Sin(theta)*TMath::Sin(phi);
      ldir[2]=TMath::Cos(theta);
      gGeoManager->GetCurrentMatrix()->LocalToMasterVect(ldir,dir);
      gGeoManager->SetCurrentDirection(dir);
      gGeoManager->SetStep(pstep);
      gGeoManager->ResetState();
      inside = kTRUE;
      dist = TGeoShape::Big();
      if (!vol->IsAssembly()) {
         inside = vol->Contains(lpt);
         if (!inside) {
            dist = vol->GetShape()->DistFromOutside(lpt,ldir,3,pstep); 
//            if (dist>=pstep) continue;
         } else {   
            vol->GetShape()->DistFromInside(lpt,ldir,3,pstep);
         }   
            
         if (!vol->GetNdaughters()) vol->GetShape()->Safety(lpt, inside);
      }   
      if (vol->GetNdaughters()) {
         gGeoManager->Safety();
         gGeoManager->FindNextDaughterBoundary(point,dir,idaughter,kFALSE);
      }   
   }
   timer->Stop();
   Double_t time_per_track = timer->CpuTime();
   Int_t uid = vol->GetNumber();
   Int_t ncrossings = (Int_t)val1[uid];
   if (!vol->GetNdaughters())
      printf("Time for volume %s (shape=%s): %g [ms] ndaughters=%d ncross=%d\n", vol->GetName(), vol->GetShape()->GetName(), time_per_track, vol->GetNdaughters(), ncrossings);
   else
      printf("Time for volume %s (assemb=%d): %g [ms] ndaughters=%d ncross=%d\n", vol->GetName(), vol->IsAssembly(), time_per_track, vol->GetNdaughters(), ncrossings);
   return time_per_track;
}
   
 checkgeom.C:1
 checkgeom.C:2
 checkgeom.C:3
 checkgeom.C:4
 checkgeom.C:5
 checkgeom.C:6
 checkgeom.C:7
 checkgeom.C:8
 checkgeom.C:9
 checkgeom.C:10
 checkgeom.C:11
 checkgeom.C:12
 checkgeom.C:13
 checkgeom.C:14
 checkgeom.C:15
 checkgeom.C:16
 checkgeom.C:17
 checkgeom.C:18
 checkgeom.C:19
 checkgeom.C:20
 checkgeom.C:21
 checkgeom.C:22
 checkgeom.C:23
 checkgeom.C:24
 checkgeom.C:25
 checkgeom.C:26
 checkgeom.C:27
 checkgeom.C:28
 checkgeom.C:29
 checkgeom.C:30
 checkgeom.C:31
 checkgeom.C:32
 checkgeom.C:33
 checkgeom.C:34
 checkgeom.C:35
 checkgeom.C:36
 checkgeom.C:37
 checkgeom.C:38
 checkgeom.C:39
 checkgeom.C:40
 checkgeom.C:41
 checkgeom.C:42
 checkgeom.C:43
 checkgeom.C:44
 checkgeom.C:45
 checkgeom.C:46
 checkgeom.C:47
 checkgeom.C:48
 checkgeom.C:49
 checkgeom.C:50
 checkgeom.C:51
 checkgeom.C:52
 checkgeom.C:53
 checkgeom.C:54
 checkgeom.C:55
 checkgeom.C:56
 checkgeom.C:57
 checkgeom.C:58
 checkgeom.C:59
 checkgeom.C:60
 checkgeom.C:61
 checkgeom.C:62
 checkgeom.C:63
 checkgeom.C:64
 checkgeom.C:65
 checkgeom.C:66
 checkgeom.C:67
 checkgeom.C:68
 checkgeom.C:69
 checkgeom.C:70
 checkgeom.C:71
 checkgeom.C:72
 checkgeom.C:73
 checkgeom.C:74
 checkgeom.C:75
 checkgeom.C:76
 checkgeom.C:77
 checkgeom.C:78
 checkgeom.C:79
 checkgeom.C:80
 checkgeom.C:81
 checkgeom.C:82
 checkgeom.C:83
 checkgeom.C:84
 checkgeom.C:85
 checkgeom.C:86
 checkgeom.C:87
 checkgeom.C:88
 checkgeom.C:89
 checkgeom.C:90
 checkgeom.C:91
 checkgeom.C:92
 checkgeom.C:93
 checkgeom.C:94
 checkgeom.C:95
 checkgeom.C:96
 checkgeom.C:97
 checkgeom.C:98
 checkgeom.C:99
 checkgeom.C:100
 checkgeom.C:101
 checkgeom.C:102
 checkgeom.C:103
 checkgeom.C:104
 checkgeom.C:105
 checkgeom.C:106
 checkgeom.C:107
 checkgeom.C:108
 checkgeom.C:109
 checkgeom.C:110
 checkgeom.C:111
 checkgeom.C:112
 checkgeom.C:113
 checkgeom.C:114
 checkgeom.C:115
 checkgeom.C:116
 checkgeom.C:117
 checkgeom.C:118
 checkgeom.C:119
 checkgeom.C:120
 checkgeom.C:121
 checkgeom.C:122
 checkgeom.C:123
 checkgeom.C:124
 checkgeom.C:125
 checkgeom.C:126
 checkgeom.C:127
 checkgeom.C:128
 checkgeom.C:129
 checkgeom.C:130
 checkgeom.C:131
 checkgeom.C:132
 checkgeom.C:133
 checkgeom.C:134
 checkgeom.C:135
 checkgeom.C:136
 checkgeom.C:137
 checkgeom.C:138
 checkgeom.C:139
 checkgeom.C:140
 checkgeom.C:141
 checkgeom.C:142
 checkgeom.C:143
 checkgeom.C:144
 checkgeom.C:145
 checkgeom.C:146
 checkgeom.C:147
 checkgeom.C:148
 checkgeom.C:149
 checkgeom.C:150
 checkgeom.C:151
 checkgeom.C:152
 checkgeom.C:153
 checkgeom.C:154
 checkgeom.C:155
 checkgeom.C:156
 checkgeom.C:157
 checkgeom.C:158
 checkgeom.C:159
 checkgeom.C:160
 checkgeom.C:161
 checkgeom.C:162
 checkgeom.C:163
 checkgeom.C:164
 checkgeom.C:165
 checkgeom.C:166
 checkgeom.C:167
 checkgeom.C:168
 checkgeom.C:169
 checkgeom.C:170
 checkgeom.C:171
 checkgeom.C:172
 checkgeom.C:173
 checkgeom.C:174
 checkgeom.C:175
 checkgeom.C:176
 checkgeom.C:177
 checkgeom.C:178
 checkgeom.C:179
 checkgeom.C:180
 checkgeom.C:181
 checkgeom.C:182
 checkgeom.C:183
 checkgeom.C:184
 checkgeom.C:185
 checkgeom.C:186
 checkgeom.C:187
 checkgeom.C:188
 checkgeom.C:189
 checkgeom.C:190
 checkgeom.C:191
 checkgeom.C:192
 checkgeom.C:193
 checkgeom.C:194
 checkgeom.C:195
 checkgeom.C:196
 checkgeom.C:197
 checkgeom.C:198
 checkgeom.C:199
 checkgeom.C:200
 checkgeom.C:201
 checkgeom.C:202
 checkgeom.C:203
 checkgeom.C:204
 checkgeom.C:205
 checkgeom.C:206
 checkgeom.C:207
 checkgeom.C:208
 checkgeom.C:209
 checkgeom.C:210
 checkgeom.C:211
 checkgeom.C:212
 checkgeom.C:213
 checkgeom.C:214
 checkgeom.C:215
 checkgeom.C:216
 checkgeom.C:217
 checkgeom.C:218
 checkgeom.C:219
 checkgeom.C:220
 checkgeom.C:221
 checkgeom.C:222
 checkgeom.C:223
 checkgeom.C:224
 checkgeom.C:225
 checkgeom.C:226
 checkgeom.C:227
 checkgeom.C:228
 checkgeom.C:229
 checkgeom.C:230
 checkgeom.C:231
 checkgeom.C:232
 checkgeom.C:233
 checkgeom.C:234
 checkgeom.C:235
 checkgeom.C:236
 checkgeom.C:237
 checkgeom.C:238
 checkgeom.C:239
 checkgeom.C:240
 checkgeom.C:241
 checkgeom.C:242
 checkgeom.C:243
 checkgeom.C:244
 checkgeom.C:245
 checkgeom.C:246
 checkgeom.C:247
 checkgeom.C:248
 checkgeom.C:249
 checkgeom.C:250
 checkgeom.C:251
 checkgeom.C:252
 checkgeom.C:253
 checkgeom.C:254
 checkgeom.C:255
 checkgeom.C:256
 checkgeom.C:257
 checkgeom.C:258
 checkgeom.C:259
 checkgeom.C:260
 checkgeom.C:261
 checkgeom.C:262
 checkgeom.C:263
 checkgeom.C:264
 checkgeom.C:265
 checkgeom.C:266
 checkgeom.C:267
 checkgeom.C:268
 checkgeom.C:269
 checkgeom.C:270
 checkgeom.C:271
 checkgeom.C:272
 checkgeom.C:273
 checkgeom.C:274
 checkgeom.C:275
 checkgeom.C:276
 checkgeom.C:277